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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/conf.h> 317c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 327c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 337c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 347c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 357c478bd9Sstevel@tonic-gate #include <sys/pci.h> 367c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 377c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 387c478bd9Sstevel@tonic-gate #include <sys/errno.h> 397c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 407c478bd9Sstevel@tonic-gate #include <sys/debug.h> 417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 427c478bd9Sstevel@tonic-gate #include <sys/ebus.h> 437c478bd9Sstevel@tonic-gate #include <sys/open.h> 447c478bd9Sstevel@tonic-gate #include <sys/stat.h> 457c478bd9Sstevel@tonic-gate #include <sys/file.h> 467c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #ifdef DEBUG 497c478bd9Sstevel@tonic-gate uint64_t ebus_debug_flags = 0; 507c478bd9Sstevel@tonic-gate #endif 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * The values of the following variables are used to initialize 547c478bd9Sstevel@tonic-gate * the cache line size and latency timer registers in the ebus 557c478bd9Sstevel@tonic-gate * configuration header. Variables are used instead of constants 567c478bd9Sstevel@tonic-gate * to allow tuning from the /etc/system file. 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate static uint8_t ebus_cache_line_size = 0x10; /* 64 bytes */ 597c478bd9Sstevel@tonic-gate static uint8_t ebus_latency_timer = 0x40; /* 64 PCI cycles */ 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * function prototypes for bus ops routines: 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate static int 657c478bd9Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 667c478bd9Sstevel@tonic-gate off_t offset, off_t len, caddr_t *addrp); 677c478bd9Sstevel@tonic-gate static int 687c478bd9Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip, 697c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result); 707c478bd9Sstevel@tonic-gate static int 717c478bd9Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 727c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result); 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate /* 757c478bd9Sstevel@tonic-gate * function prototypes for dev ops routines: 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate static int ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 787c478bd9Sstevel@tonic-gate static int ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 797c478bd9Sstevel@tonic-gate static int ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 807c478bd9Sstevel@tonic-gate void *arg, void **result); 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * general function prototypes: 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate static int ebus_config(ebus_devstate_t *ebus_p); 867c478bd9Sstevel@tonic-gate static int ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 877c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp, pci_regspec_t *rp); 887c478bd9Sstevel@tonic-gate static int febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 897c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp, struct regspec *rp); 907c478bd9Sstevel@tonic-gate int get_ranges_prop(ebus_devstate_t *ebus_p); 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate #define getprop(dip, name, addr, intp) \ 93*a3282898Scth ddi_getlongprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 947c478bd9Sstevel@tonic-gate (name), (caddr_t)(addr), (intp)) 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate static int ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp); 977c478bd9Sstevel@tonic-gate static int ebus_close(dev_t dev, int flags, int otyp, cred_t *credp); 987c478bd9Sstevel@tonic-gate static int ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 997c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp); 1007c478bd9Sstevel@tonic-gate struct cb_ops ebus_cb_ops = { 1017c478bd9Sstevel@tonic-gate ebus_open, /* open */ 1027c478bd9Sstevel@tonic-gate ebus_close, /* close */ 1037c478bd9Sstevel@tonic-gate nodev, /* strategy */ 1047c478bd9Sstevel@tonic-gate nodev, /* print */ 1057c478bd9Sstevel@tonic-gate nodev, /* dump */ 1067c478bd9Sstevel@tonic-gate nodev, /* read */ 1077c478bd9Sstevel@tonic-gate nodev, /* write */ 1087c478bd9Sstevel@tonic-gate ebus_ioctl, /* ioctl */ 1097c478bd9Sstevel@tonic-gate nodev, /* devmap */ 1107c478bd9Sstevel@tonic-gate nodev, /* mmap */ 1117c478bd9Sstevel@tonic-gate nodev, /* segmap */ 1127c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 1137c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1147c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 1157c478bd9Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 1167c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 1177c478bd9Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 1187c478bd9Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 1197c478bd9Sstevel@tonic-gate }; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate /* 1227c478bd9Sstevel@tonic-gate * bus ops and dev ops structures: 1237c478bd9Sstevel@tonic-gate */ 1247c478bd9Sstevel@tonic-gate static struct bus_ops ebus_bus_ops = { 1257c478bd9Sstevel@tonic-gate BUSO_REV, 1267c478bd9Sstevel@tonic-gate ebus_map, 1277c478bd9Sstevel@tonic-gate NULL, 1287c478bd9Sstevel@tonic-gate NULL, 1297c478bd9Sstevel@tonic-gate NULL, 1307c478bd9Sstevel@tonic-gate i_ddi_map_fault, 1317c478bd9Sstevel@tonic-gate ddi_dma_map, 1327c478bd9Sstevel@tonic-gate ddi_dma_allochdl, 1337c478bd9Sstevel@tonic-gate ddi_dma_freehdl, 1347c478bd9Sstevel@tonic-gate ddi_dma_bindhdl, 1357c478bd9Sstevel@tonic-gate ddi_dma_unbindhdl, 1367c478bd9Sstevel@tonic-gate ddi_dma_flush, 1377c478bd9Sstevel@tonic-gate ddi_dma_win, 1387c478bd9Sstevel@tonic-gate ddi_dma_mctl, 1397c478bd9Sstevel@tonic-gate ebus_ctlops, 1407c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 1417c478bd9Sstevel@tonic-gate ndi_busop_get_eventcookie, 1427c478bd9Sstevel@tonic-gate ndi_busop_add_eventcall, 1437c478bd9Sstevel@tonic-gate ndi_busop_remove_eventcall, 1447c478bd9Sstevel@tonic-gate ndi_post_event, 1457c478bd9Sstevel@tonic-gate 0, 1467c478bd9Sstevel@tonic-gate 0, 1477c478bd9Sstevel@tonic-gate 0, 1487c478bd9Sstevel@tonic-gate 0, 1497c478bd9Sstevel@tonic-gate 0, 1507c478bd9Sstevel@tonic-gate 0, 1517c478bd9Sstevel@tonic-gate 0, 1527c478bd9Sstevel@tonic-gate 0, 1537c478bd9Sstevel@tonic-gate ebus_intr_ops 1547c478bd9Sstevel@tonic-gate }; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate static struct dev_ops ebus_ops = { 1577c478bd9Sstevel@tonic-gate DEVO_REV, 1587c478bd9Sstevel@tonic-gate 0, 1597c478bd9Sstevel@tonic-gate ebus_info, 1607c478bd9Sstevel@tonic-gate nulldev, 1617c478bd9Sstevel@tonic-gate nulldev, 1627c478bd9Sstevel@tonic-gate ebus_attach, 1637c478bd9Sstevel@tonic-gate ebus_detach, 1647c478bd9Sstevel@tonic-gate nodev, 1657c478bd9Sstevel@tonic-gate &ebus_cb_ops, 1667c478bd9Sstevel@tonic-gate &ebus_bus_ops 1677c478bd9Sstevel@tonic-gate }; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate /* 1707c478bd9Sstevel@tonic-gate * module definitions: 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 1737c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1767c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 1777c478bd9Sstevel@tonic-gate "ebus nexus driver %I%", /* Name of module. */ 1787c478bd9Sstevel@tonic-gate &ebus_ops, /* driver ops */ 1797c478bd9Sstevel@tonic-gate }; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1827c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 1837c478bd9Sstevel@tonic-gate }; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* 1867c478bd9Sstevel@tonic-gate * driver global data: 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate static void *per_ebus_state; /* per-ebus soft state pointer */ 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate int 1927c478bd9Sstevel@tonic-gate _init(void) 1937c478bd9Sstevel@tonic-gate { 1947c478bd9Sstevel@tonic-gate int e; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * Initialize per-ebus soft state pointer. 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate e = ddi_soft_state_init(&per_ebus_state, sizeof (ebus_devstate_t), 1); 2007c478bd9Sstevel@tonic-gate if (e != 0) 2017c478bd9Sstevel@tonic-gate return (e); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* 2047c478bd9Sstevel@tonic-gate * Install the module. 2057c478bd9Sstevel@tonic-gate */ 2067c478bd9Sstevel@tonic-gate e = mod_install(&modlinkage); 2077c478bd9Sstevel@tonic-gate if (e != 0) 2087c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_ebus_state); 2097c478bd9Sstevel@tonic-gate return (e); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate int 2137c478bd9Sstevel@tonic-gate _fini(void) 2147c478bd9Sstevel@tonic-gate { 2157c478bd9Sstevel@tonic-gate int e; 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate /* 2187c478bd9Sstevel@tonic-gate * Remove the module. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate e = mod_remove(&modlinkage); 2217c478bd9Sstevel@tonic-gate if (e != 0) 2227c478bd9Sstevel@tonic-gate return (e); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * Free the soft state info. 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_ebus_state); 2287c478bd9Sstevel@tonic-gate return (e); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate int 2327c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2337c478bd9Sstevel@tonic-gate { 2347c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* device driver entry points */ 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2407c478bd9Sstevel@tonic-gate static int 2417c478bd9Sstevel@tonic-gate ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2427c478bd9Sstevel@tonic-gate { 2437c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p; /* per ebus state pointer */ 2447c478bd9Sstevel@tonic-gate int instance; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate instance = getminor((dev_t)arg); 2477c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(instance); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate switch (infocmd) { 2507c478bd9Sstevel@tonic-gate default: 2517c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2547c478bd9Sstevel@tonic-gate *result = (void *)instance; 2557c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2587c478bd9Sstevel@tonic-gate if (ebus_p == NULL) 2597c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2607c478bd9Sstevel@tonic-gate *result = (void *)ebus_p->dip; 2617c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * attach entry point: 2677c478bd9Sstevel@tonic-gate * 2687c478bd9Sstevel@tonic-gate * normal attach: 2697c478bd9Sstevel@tonic-gate * 2707c478bd9Sstevel@tonic-gate * create soft state structure (dip, reg, nreg and state fields) 2717c478bd9Sstevel@tonic-gate * map in configuration header 2727c478bd9Sstevel@tonic-gate * make sure device is properly configured 2737c478bd9Sstevel@tonic-gate * report device 2747c478bd9Sstevel@tonic-gate */ 2757c478bd9Sstevel@tonic-gate static int 2767c478bd9Sstevel@tonic-gate ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2777c478bd9Sstevel@tonic-gate { 2787c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p; /* per ebus state pointer */ 2797c478bd9Sstevel@tonic-gate int instance; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate DBG1(D_ATTACH, NULL, "dip=%p\n", dip); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate switch (cmd) { 2847c478bd9Sstevel@tonic-gate case DDI_ATTACH: 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate /* 2877c478bd9Sstevel@tonic-gate * Allocate soft state for this instance. 2887c478bd9Sstevel@tonic-gate */ 2897c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 2907c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(per_ebus_state, instance) 2917c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 2927c478bd9Sstevel@tonic-gate DBG(D_ATTACH, NULL, "failed to alloc soft state\n"); 2937c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(instance); 2967c478bd9Sstevel@tonic-gate ebus_p->dip = dip; 2977c478bd9Sstevel@tonic-gate mutex_init(&ebus_p->ebus_mutex, NULL, MUTEX_DRIVER, NULL); 2987c478bd9Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate /* Set ebus type field based on ddi name info */ 3017c478bd9Sstevel@tonic-gate if (strcmp(ddi_get_name(dip), "jbus-ebus") == 0) { 3027c478bd9Sstevel@tonic-gate ebus_p->type = FEBUS_TYPE; 3037c478bd9Sstevel@tonic-gate } else { 3047c478bd9Sstevel@tonic-gate ebus_p->type = EBUS_TYPE; 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 3087c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, "no-dma-interrupt-sync", NULL, 0); 3097c478bd9Sstevel@tonic-gate /* Get our ranges property for mapping child registers. */ 3107c478bd9Sstevel@tonic-gate if (get_ranges_prop(ebus_p) != DDI_SUCCESS) { 3117c478bd9Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 3127c478bd9Sstevel@tonic-gate free_ebus_soft_state(instance); 3137c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * create minor node for devctl interfaces 3187c478bd9Sstevel@tonic-gate */ 3197c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance, 3207c478bd9Sstevel@tonic-gate DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 3217c478bd9Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 3227c478bd9Sstevel@tonic-gate free_ebus_soft_state(instance); 3237c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * Make sure the master enable and memory access enable 3277c478bd9Sstevel@tonic-gate * bits are set in the config command register. 3287c478bd9Sstevel@tonic-gate */ 3297c478bd9Sstevel@tonic-gate if (ebus_p->type == EBUS_TYPE) { 3307c478bd9Sstevel@tonic-gate if (!ebus_config(ebus_p)) { 3317c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, "devctl"); 3327c478bd9Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 3337c478bd9Sstevel@tonic-gate free_ebus_soft_state(instance); 3347c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate * Make the pci_report_pmcap() call only for RIO 3407c478bd9Sstevel@tonic-gate * implementations. 3417c478bd9Sstevel@tonic-gate */ 3427c478bd9Sstevel@tonic-gate if (IS_RIO(dip)) { 3437c478bd9Sstevel@tonic-gate (void) pci_report_pmcap(dip, PCI_PM_IDLESPEED, 3447c478bd9Sstevel@tonic-gate (void *)EBUS_4MHZ); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 3487c478bd9Sstevel@tonic-gate * Make the state as attached and report the device. 3497c478bd9Sstevel@tonic-gate */ 3507c478bd9Sstevel@tonic-gate ebus_p->state = ATTACHED; 3517c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 3527c478bd9Sstevel@tonic-gate DBG(D_ATTACH, ebus_p, "returning\n"); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate case DDI_RESUME: 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 3597c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(instance); 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate * Make sure the master enable and memory access enable 3637c478bd9Sstevel@tonic-gate * bits are set in the config command register. 3647c478bd9Sstevel@tonic-gate */ 3657c478bd9Sstevel@tonic-gate if (ebus_p->type == EBUS_TYPE) { 3667c478bd9Sstevel@tonic-gate if (!ebus_config(ebus_p)) { 3677c478bd9Sstevel@tonic-gate free_ebus_soft_state(instance); 3687c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate ebus_p->state = RESUMED; 3737c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* 3797c478bd9Sstevel@tonic-gate * detach entry point: 3807c478bd9Sstevel@tonic-gate */ 3817c478bd9Sstevel@tonic-gate static int 3827c478bd9Sstevel@tonic-gate ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3837c478bd9Sstevel@tonic-gate { 3847c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 3857c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(instance); 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate switch (cmd) { 3887c478bd9Sstevel@tonic-gate case DDI_DETACH: 3897c478bd9Sstevel@tonic-gate DBG1(D_DETACH, ebus_p, "DDI_DETACH dip=%p\n", dip); 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate switch (ebus_p->type) { 3927c478bd9Sstevel@tonic-gate case EBUS_TYPE: 3937c478bd9Sstevel@tonic-gate kmem_free(ebus_p->rangespec.rangep, ebus_p->range_cnt * 3947c478bd9Sstevel@tonic-gate sizeof (struct ebus_pci_rangespec)); 3957c478bd9Sstevel@tonic-gate break; 3967c478bd9Sstevel@tonic-gate case FEBUS_TYPE: 3977c478bd9Sstevel@tonic-gate kmem_free(ebus_p->rangespec.ferangep, 3987c478bd9Sstevel@tonic-gate ebus_p->range_cnt * 3997c478bd9Sstevel@tonic-gate sizeof (struct febus_rangespec)); 4007c478bd9Sstevel@tonic-gate break; 4017c478bd9Sstevel@tonic-gate default: 4027c478bd9Sstevel@tonic-gate DBG(D_ATTACH, NULL, "failed to recognize ebus type\n"); 4037c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, "devctl"); 4077c478bd9Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 4087c478bd9Sstevel@tonic-gate free_ebus_soft_state(instance); 4097c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 4127c478bd9Sstevel@tonic-gate DBG1(D_DETACH, ebus_p, "DDI_SUSPEND dip=%p\n", dip); 4137c478bd9Sstevel@tonic-gate ebus_p->state = SUSPENDED; 4147c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate DBG(D_ATTACH, NULL, "failed to recognize ebus detach command\n"); 4177c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate int 4227c478bd9Sstevel@tonic-gate get_ranges_prop(ebus_devstate_t *ebus_p) 4237c478bd9Sstevel@tonic-gate { 4247c478bd9Sstevel@tonic-gate int nrange, range_len; 4257c478bd9Sstevel@tonic-gate struct ebus_pci_rangespec *rangep; 4267c478bd9Sstevel@tonic-gate struct febus_rangespec *ferangep; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate switch (ebus_p->type) { 4297c478bd9Sstevel@tonic-gate case EBUS_TYPE: 4307c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, 4317c478bd9Sstevel@tonic-gate ebus_p->dip, DDI_PROP_DONTPASS, 4327c478bd9Sstevel@tonic-gate "ranges", (caddr_t)&rangep, 4337c478bd9Sstevel@tonic-gate &range_len) != DDI_SUCCESS) { 4347c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Can't get %s ranges property", 4357c478bd9Sstevel@tonic-gate ddi_get_name(ebus_p->dip)); 4367c478bd9Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate nrange = range_len / sizeof (struct ebus_pci_rangespec); 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate if (nrange == 0) { 4427c478bd9Sstevel@tonic-gate kmem_free(rangep, range_len); 4437c478bd9Sstevel@tonic-gate DBG(D_ATTACH, NULL, "range is equal to zero\n"); 4447c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate #ifdef DEBUG 4487c478bd9Sstevel@tonic-gate { 4497c478bd9Sstevel@tonic-gate int i; 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate for (i = 0; i < nrange; i++) { 4527c478bd9Sstevel@tonic-gate DBG5(D_MAP, ebus_p, 4537c478bd9Sstevel@tonic-gate "ebus range addr 0x%x.0x%x PCI range " 4547c478bd9Sstevel@tonic-gate "addr 0x%x.0x%x.0x%x ", 4557c478bd9Sstevel@tonic-gate rangep[i].ebus_phys_hi, 4567c478bd9Sstevel@tonic-gate rangep[i].ebus_phys_low, 4577c478bd9Sstevel@tonic-gate rangep[i].pci_phys_hi, 4587c478bd9Sstevel@tonic-gate rangep[i].pci_phys_mid, 4597c478bd9Sstevel@tonic-gate rangep[i].pci_phys_low); 4607c478bd9Sstevel@tonic-gate DBG1(D_MAP, ebus_p, 4617c478bd9Sstevel@tonic-gate "Size 0x%x\n", rangep[i].rng_size); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate ebus_p->rangespec.rangep = rangep; 4677c478bd9Sstevel@tonic-gate ebus_p->range_cnt = nrange; 4687c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate case FEBUS_TYPE: 4717c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, ebus_p->dip, 4727c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "ranges", 4737c478bd9Sstevel@tonic-gate (caddr_t)&ferangep, &range_len) != DDI_SUCCESS) { 4747c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Can't get %s ranges property", 4757c478bd9Sstevel@tonic-gate ddi_get_name(ebus_p->dip)); 4767c478bd9Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate nrange = range_len / sizeof (struct febus_rangespec); 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate if (nrange == 0) { 4827c478bd9Sstevel@tonic-gate kmem_free(ferangep, range_len); 4837c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate #ifdef DEBUG 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate int i; 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate for (i = 0; i < nrange; i++) { 4917c478bd9Sstevel@tonic-gate DBG4(D_MAP, ebus_p, 4927c478bd9Sstevel@tonic-gate "ebus range addr 0x%x.0x%x" 4937c478bd9Sstevel@tonic-gate " Parent range " 4947c478bd9Sstevel@tonic-gate "addr 0x%x.0x%x ", 4957c478bd9Sstevel@tonic-gate ferangep[i].febus_phys_hi, 4967c478bd9Sstevel@tonic-gate ferangep[i].febus_phys_low, 4977c478bd9Sstevel@tonic-gate ferangep[i].parent_phys_hi, 4987c478bd9Sstevel@tonic-gate ferangep[i].parent_phys_low); 4997c478bd9Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "Size 0x%x\n", 5007c478bd9Sstevel@tonic-gate ferangep[i].rng_size); 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 5047c478bd9Sstevel@tonic-gate ebus_p->rangespec.ferangep = ferangep; 5057c478bd9Sstevel@tonic-gate ebus_p->range_cnt = nrange; 5067c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate default: 5097c478bd9Sstevel@tonic-gate DBG(D_MAP, NULL, "failed to recognize ebus type\n"); 5107c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* bus driver entry points */ 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate /* 5177c478bd9Sstevel@tonic-gate * bus map entry point: 5187c478bd9Sstevel@tonic-gate * 5197c478bd9Sstevel@tonic-gate * if map request is for an rnumber 5207c478bd9Sstevel@tonic-gate * get the corresponding regspec from device node 5217c478bd9Sstevel@tonic-gate * build a new regspec in our parent's format 5227c478bd9Sstevel@tonic-gate * build a new map_req with the new regspec 5237c478bd9Sstevel@tonic-gate * call up the tree to complete the mapping 5247c478bd9Sstevel@tonic-gate */ 5257c478bd9Sstevel@tonic-gate static int 5267c478bd9Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 5277c478bd9Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip)); 5307c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp, *ebus_regs; 5317c478bd9Sstevel@tonic-gate struct regspec reg; 5327c478bd9Sstevel@tonic-gate pci_regspec_t pci_reg; 5337c478bd9Sstevel@tonic-gate ddi_map_req_t p_map_request; 5347c478bd9Sstevel@tonic-gate int rnumber, i, n; 5357c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate /* 5387c478bd9Sstevel@tonic-gate * Handle the mapping according to its type. 5397c478bd9Sstevel@tonic-gate */ 5407c478bd9Sstevel@tonic-gate DBG4(D_MAP, ebus_p, "rdip=%s%d: off=%x len=%x\n", 5417c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), off, len); 5427c478bd9Sstevel@tonic-gate switch (mp->map_type) { 5437c478bd9Sstevel@tonic-gate case DDI_MT_REGSPEC: 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate /* 5467c478bd9Sstevel@tonic-gate * We assume the register specification is in ebus format. 5477c478bd9Sstevel@tonic-gate * We must convert it into a PCI format regspec and pass 5487c478bd9Sstevel@tonic-gate * the request to our parent. 5497c478bd9Sstevel@tonic-gate */ 5507c478bd9Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "rdip=%s%d: REGSPEC - handlep=%p\n", 5517c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 5527c478bd9Sstevel@tonic-gate mp->map_handlep); 5537c478bd9Sstevel@tonic-gate ebus_rp = (ebus_regspec_t *)mp->map_obj.rp; 5547c478bd9Sstevel@tonic-gate break; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate case DDI_MT_RNUMBER: 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate /* 5597c478bd9Sstevel@tonic-gate * Get the "reg" property from the device node and convert 5607c478bd9Sstevel@tonic-gate * it to our parent's format. 5617c478bd9Sstevel@tonic-gate */ 5627c478bd9Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 5637c478bd9Sstevel@tonic-gate DBG4(D_MAP, ebus_p, "rdip=%s%d: rnumber=%x handlep=%p\n", 5647c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 5657c478bd9Sstevel@tonic-gate rnumber, mp->map_handlep); 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate if (getprop(rdip, "reg", &ebus_regs, &i) != DDI_SUCCESS) { 5687c478bd9Sstevel@tonic-gate DBG(D_MAP, ebus_p, "can't get reg property\n"); 5697c478bd9Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate n = i / sizeof (ebus_regspec_t); 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate if (rnumber < 0 || rnumber >= n) { 5747c478bd9Sstevel@tonic-gate DBG(D_MAP, ebus_p, "rnumber out of range\n"); 5757c478bd9Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate ebus_rp = &ebus_regs[rnumber]; 5787c478bd9Sstevel@tonic-gate break; 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate default: 5817c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate /* Adjust our reg property with offset and length */ 5867c478bd9Sstevel@tonic-gate ebus_rp->addr_low += off; 5877c478bd9Sstevel@tonic-gate if (len) 5887c478bd9Sstevel@tonic-gate ebus_rp->size = len; 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * Now we have a copy the "reg" entry we're attempting to map. 5927c478bd9Sstevel@tonic-gate * Translate this into our parents PCI address using the ranges 5937c478bd9Sstevel@tonic-gate * property. 5947c478bd9Sstevel@tonic-gate */ 5957c478bd9Sstevel@tonic-gate switch (ebus_p->type) { 5967c478bd9Sstevel@tonic-gate case EBUS_TYPE: 5977c478bd9Sstevel@tonic-gate rval = ebus_apply_range(ebus_p, rdip, ebus_rp, &pci_reg); 5987c478bd9Sstevel@tonic-gate break; 5997c478bd9Sstevel@tonic-gate case FEBUS_TYPE: 6007c478bd9Sstevel@tonic-gate rval = febus_apply_range(ebus_p, rdip, ebus_rp, ®); 6017c478bd9Sstevel@tonic-gate break; 6027c478bd9Sstevel@tonic-gate default: 6037c478bd9Sstevel@tonic-gate DBG(D_MAP, NULL, "failed to recognize ebus type\n"); 6047c478bd9Sstevel@tonic-gate rval = DDI_FAILURE; 6057c478bd9Sstevel@tonic-gate } 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate if (mp->map_type == DDI_MT_RNUMBER) 6087c478bd9Sstevel@tonic-gate kmem_free(ebus_regs, i); 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) 6117c478bd9Sstevel@tonic-gate return (rval); 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate #ifdef DEBUG 6147c478bd9Sstevel@tonic-gate switch (ebus_p->type) { 6157c478bd9Sstevel@tonic-gate case EBUS_TYPE: 6167c478bd9Sstevel@tonic-gate DBG5(D_MAP, ebus_p, "(%x,%x,%x)(%x,%x)\n", 6177c478bd9Sstevel@tonic-gate pci_reg.pci_phys_hi, 6187c478bd9Sstevel@tonic-gate pci_reg.pci_phys_mid, 6197c478bd9Sstevel@tonic-gate pci_reg.pci_phys_low, 6207c478bd9Sstevel@tonic-gate pci_reg.pci_size_hi, 6217c478bd9Sstevel@tonic-gate pci_reg.pci_size_low); 6227c478bd9Sstevel@tonic-gate break; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate case FEBUS_TYPE: 6257c478bd9Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "%x,%x,%x\n", 6267c478bd9Sstevel@tonic-gate reg.regspec_bustype, 6277c478bd9Sstevel@tonic-gate reg.regspec_addr, 6287c478bd9Sstevel@tonic-gate reg.regspec_size); 6297c478bd9Sstevel@tonic-gate break; 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate #endif 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate p_map_request = *mp; 6347c478bd9Sstevel@tonic-gate p_map_request.map_type = DDI_MT_REGSPEC; 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate switch (ebus_p->type) { 6377c478bd9Sstevel@tonic-gate case EBUS_TYPE: 6387c478bd9Sstevel@tonic-gate p_map_request.map_obj.rp = (struct regspec *)&pci_reg; 6397c478bd9Sstevel@tonic-gate break; 6407c478bd9Sstevel@tonic-gate case FEBUS_TYPE: 6417c478bd9Sstevel@tonic-gate p_map_request.map_obj.rp = ® 6427c478bd9Sstevel@tonic-gate break; 6437c478bd9Sstevel@tonic-gate default: 6447c478bd9Sstevel@tonic-gate DBG(D_MAP, NULL, "failed to recognize ebus type\n"); 6457c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate rval = ddi_map(dip, &p_map_request, 0, 0, addrp); 6497c478bd9Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "parent returned %x\n", rval); 6507c478bd9Sstevel@tonic-gate return (rval); 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate static int 6557c478bd9Sstevel@tonic-gate ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 6567c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp, pci_regspec_t *rp) 6577c478bd9Sstevel@tonic-gate { 6587c478bd9Sstevel@tonic-gate int b; 6597c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 6607c478bd9Sstevel@tonic-gate struct ebus_pci_rangespec *rangep = ebus_p->rangespec.rangep; 6617c478bd9Sstevel@tonic-gate int nrange = ebus_p->range_cnt; 6627c478bd9Sstevel@tonic-gate static char out_of_range[] = 6637c478bd9Sstevel@tonic-gate "Out of range register specification from device node <%s>"; 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n", 6667c478bd9Sstevel@tonic-gate ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate for (b = 0; b < nrange; ++b, ++rangep) { 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate /* Check for the correct space */ 6717c478bd9Sstevel@tonic-gate if (ebus_rp->addr_hi == rangep->ebus_phys_hi) 6727c478bd9Sstevel@tonic-gate /* See if we fit in this range */ 6737c478bd9Sstevel@tonic-gate if ((ebus_rp->addr_low >= 6747c478bd9Sstevel@tonic-gate rangep->ebus_phys_low) && 6757c478bd9Sstevel@tonic-gate ((ebus_rp->addr_low + ebus_rp->size - 1) 6767c478bd9Sstevel@tonic-gate <= (rangep->ebus_phys_low + 6777c478bd9Sstevel@tonic-gate rangep->rng_size - 1))) { 6787c478bd9Sstevel@tonic-gate uint_t addr_offset = ebus_rp->addr_low - 6797c478bd9Sstevel@tonic-gate rangep->ebus_phys_low; 6807c478bd9Sstevel@tonic-gate /* 6817c478bd9Sstevel@tonic-gate * Use the range entry to translate 6827c478bd9Sstevel@tonic-gate * the EBUS physical address into the 6837c478bd9Sstevel@tonic-gate * parents PCI space. 6847c478bd9Sstevel@tonic-gate */ 6857c478bd9Sstevel@tonic-gate rp->pci_phys_hi = 6867c478bd9Sstevel@tonic-gate rangep->pci_phys_hi; 6877c478bd9Sstevel@tonic-gate rp->pci_phys_mid = rangep->pci_phys_mid; 6887c478bd9Sstevel@tonic-gate rp->pci_phys_low = 6897c478bd9Sstevel@tonic-gate rangep->pci_phys_low + addr_offset; 6907c478bd9Sstevel@tonic-gate rp->pci_size_hi = 0; 6917c478bd9Sstevel@tonic-gate rp->pci_size_low = 6927c478bd9Sstevel@tonic-gate min(ebus_rp->size, (rangep->rng_size - 6937c478bd9Sstevel@tonic-gate addr_offset)); 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ", 6967c478bd9Sstevel@tonic-gate rangep->ebus_phys_hi, 6977c478bd9Sstevel@tonic-gate rangep->ebus_phys_low); 6987c478bd9Sstevel@tonic-gate DBG4(D_MAP, ebus_p, "Parent hi0x%x " 6997c478bd9Sstevel@tonic-gate "mid0x%x lo0x%x size 0x%x\n", 7007c478bd9Sstevel@tonic-gate rangep->pci_phys_hi, 7017c478bd9Sstevel@tonic-gate rangep->pci_phys_mid, 7027c478bd9Sstevel@tonic-gate rangep->pci_phys_low, 7037c478bd9Sstevel@tonic-gate rangep->rng_size); 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate break; 7067c478bd9Sstevel@tonic-gate } 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate if (b == nrange) { 7107c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip)); 7117c478bd9Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate return (rval); 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate static int 7187c478bd9Sstevel@tonic-gate febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 7197c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp, struct regspec *rp) { 7207c478bd9Sstevel@tonic-gate int b; 7217c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 7227c478bd9Sstevel@tonic-gate struct febus_rangespec *rangep = ebus_p->rangespec.ferangep; 7237c478bd9Sstevel@tonic-gate int nrange = ebus_p->range_cnt; 7247c478bd9Sstevel@tonic-gate static char out_of_range[] = 7257c478bd9Sstevel@tonic-gate "Out of range register specification from device node <%s>"; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n", 7287c478bd9Sstevel@tonic-gate ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size); 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate for (b = 0; b < nrange; ++b, ++rangep) { 7317c478bd9Sstevel@tonic-gate /* Check for the correct space */ 7327c478bd9Sstevel@tonic-gate if (ebus_rp->addr_hi == rangep->febus_phys_hi) 7337c478bd9Sstevel@tonic-gate /* See if we fit in this range */ 7347c478bd9Sstevel@tonic-gate if ((ebus_rp->addr_low >= 7357c478bd9Sstevel@tonic-gate rangep->febus_phys_low) && 7367c478bd9Sstevel@tonic-gate ((ebus_rp->addr_low + ebus_rp->size - 1) 7377c478bd9Sstevel@tonic-gate <= (rangep->febus_phys_low + 7387c478bd9Sstevel@tonic-gate rangep->rng_size - 1))) { 7397c478bd9Sstevel@tonic-gate uint_t addr_offset = ebus_rp->addr_low - 7407c478bd9Sstevel@tonic-gate rangep->febus_phys_low; 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate /* 7437c478bd9Sstevel@tonic-gate * Use the range entry to translate 7447c478bd9Sstevel@tonic-gate * the FEBUS physical address into the 7457c478bd9Sstevel@tonic-gate * parents space. 7467c478bd9Sstevel@tonic-gate */ 7477c478bd9Sstevel@tonic-gate rp->regspec_bustype = 7487c478bd9Sstevel@tonic-gate rangep->parent_phys_hi; 7497c478bd9Sstevel@tonic-gate rp->regspec_addr = 7507c478bd9Sstevel@tonic-gate rangep->parent_phys_low + addr_offset; 7517c478bd9Sstevel@tonic-gate rp->regspec_size = 7527c478bd9Sstevel@tonic-gate min(ebus_rp->size, (rangep->rng_size - 7537c478bd9Sstevel@tonic-gate addr_offset)); 7547c478bd9Sstevel@tonic-gate 7557c478bd9Sstevel@tonic-gate DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ", 7567c478bd9Sstevel@tonic-gate rangep->febus_phys_hi, 7577c478bd9Sstevel@tonic-gate rangep->febus_phys_low); 7587c478bd9Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "Parent hi0x%x " 7597c478bd9Sstevel@tonic-gate "lo0x%x size 0x%x\n", 7607c478bd9Sstevel@tonic-gate rangep->parent_phys_hi, 7617c478bd9Sstevel@tonic-gate rangep->parent_phys_low, 7627c478bd9Sstevel@tonic-gate rangep->rng_size); 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate break; 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate if (b == nrange) { 7697c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip)); 7707c478bd9Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate return (rval); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate static int 7787c478bd9Sstevel@tonic-gate ebus_name_child(dev_info_t *child, char *name, int namelen) 7797c478bd9Sstevel@tonic-gate { 7807c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp; 7817c478bd9Sstevel@tonic-gate int reglen; 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* 7847c478bd9Sstevel@tonic-gate * Get the address portion of the node name based on the 7857c478bd9Sstevel@tonic-gate * address/offset. 7867c478bd9Sstevel@tonic-gate */ 787*a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 7887c478bd9Sstevel@tonic-gate "reg", (caddr_t)&ebus_rp, ®len) != DDI_SUCCESS) { 7897c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", ebus_rp->addr_hi, 7937c478bd9Sstevel@tonic-gate ebus_rp->addr_low); 7947c478bd9Sstevel@tonic-gate kmem_free(ebus_rp, reglen); 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate /* 8007c478bd9Sstevel@tonic-gate * control ops entry point: 8017c478bd9Sstevel@tonic-gate * 8027c478bd9Sstevel@tonic-gate * Requests handled completely: 8037c478bd9Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD 8047c478bd9Sstevel@tonic-gate * DDI_CTLOPS_UNINITCHILD 8057c478bd9Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV 8067c478bd9Sstevel@tonic-gate * DDI_CTLOPS_REGSIZE 8077c478bd9Sstevel@tonic-gate * DDI_CTLOPS_NREGS 8087c478bd9Sstevel@tonic-gate * 8097c478bd9Sstevel@tonic-gate * All others passed to parent. 8107c478bd9Sstevel@tonic-gate */ 8117c478bd9Sstevel@tonic-gate static int 8127c478bd9Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip, 8137c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result) 8147c478bd9Sstevel@tonic-gate { 8157c478bd9Sstevel@tonic-gate #ifdef DEBUG 8167c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip)); 8177c478bd9Sstevel@tonic-gate #endif 8187c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp; 8197c478bd9Sstevel@tonic-gate int i, n; 8207c478bd9Sstevel@tonic-gate char name[10]; 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate switch (op) { 8237c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: { 8247c478bd9Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg; 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * Set the address portion of the node name based on the 8277c478bd9Sstevel@tonic-gate * address/offset. 8287c478bd9Sstevel@tonic-gate */ 8297c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n", 8307c478bd9Sstevel@tonic-gate ddi_get_name(child), ddi_get_instance(child)); 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate if (ebus_name_child(child, name, 10) != DDI_SUCCESS) { 8337c478bd9Sstevel@tonic-gate DBG(D_CTLOPS, ebus_p, "can't name child\n"); 8347c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 8387c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 8397c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 8437c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n", 8447c478bd9Sstevel@tonic-gate ddi_get_name((dev_info_t *)arg), 8457c478bd9Sstevel@tonic-gate ddi_get_instance((dev_info_t *)arg)); 8467c478bd9Sstevel@tonic-gate ddi_set_name_addr((dev_info_t *)arg, NULL); 8477c478bd9Sstevel@tonic-gate ddi_remove_minor_node((dev_info_t *)arg, NULL); 8487c478bd9Sstevel@tonic-gate impl_rem_dev_props((dev_info_t *)arg); 8497c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n", 8547c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8557c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n", 8567c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), 8577c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 8587c478bd9Sstevel@tonic-gate ddi_get_name_addr(rdip)); 8597c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n", 8647c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8657c478bd9Sstevel@tonic-gate if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) { 8667c478bd9Sstevel@tonic-gate DBG(D_CTLOPS, ebus_p, "can't get reg property\n"); 8677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate n = i / sizeof (ebus_regspec_t); 8707c478bd9Sstevel@tonic-gate if (*(int *)arg < 0 || *(int *)arg >= n) { 8717c478bd9Sstevel@tonic-gate DBG(D_MAP, ebus_p, "rnumber out of range\n"); 8727c478bd9Sstevel@tonic-gate kmem_free(ebus_rp, i); 8737c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate *((off_t *)result) = ebus_rp[*(int *)arg].size; 8767c478bd9Sstevel@tonic-gate kmem_free(ebus_rp, i); 8777c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_NREGS: rdip=%s%d\n", 8827c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8837c478bd9Sstevel@tonic-gate if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) { 8847c478bd9Sstevel@tonic-gate DBG(D_CTLOPS, ebus_p, "can't get reg property\n"); 8857c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate *((uint_t *)result) = i / sizeof (ebus_regspec_t); 8887c478bd9Sstevel@tonic-gate kmem_free(ebus_rp, i); 8897c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* 8937c478bd9Sstevel@tonic-gate * Now pass the request up to our parent. 8947c478bd9Sstevel@tonic-gate */ 8957c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "passing request to parent: rdip=%s%d\n", 8967c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8977c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate struct ebus_string_to_pil { 9017c478bd9Sstevel@tonic-gate int8_t *string; 9027c478bd9Sstevel@tonic-gate uint32_t pil; 9037c478bd9Sstevel@tonic-gate }; 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate static struct ebus_string_to_pil ebus_name_to_pil[] = {{"SUNW,CS4231", 9}, 9067c478bd9Sstevel@tonic-gate {"audio", 9}, 9077c478bd9Sstevel@tonic-gate {"fdthree", 8}, 9087c478bd9Sstevel@tonic-gate {"floppy", 8}, 9097c478bd9Sstevel@tonic-gate {"ecpp", 3}, 9107c478bd9Sstevel@tonic-gate {"parallel", 3}, 9117c478bd9Sstevel@tonic-gate {"su", 12}, 9127c478bd9Sstevel@tonic-gate {"se", 12}, 9137c478bd9Sstevel@tonic-gate {"serial", 12}, 9147c478bd9Sstevel@tonic-gate {"power", 14}}; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate static struct ebus_string_to_pil ebus_device_type_to_pil[] = {{"serial", 12}, 9177c478bd9Sstevel@tonic-gate {"block", 8}}; 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate static int 9207c478bd9Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 9217c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 9227c478bd9Sstevel@tonic-gate { 9237c478bd9Sstevel@tonic-gate #ifdef DEBUG 9247c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip)); 9257c478bd9Sstevel@tonic-gate #endif 9267c478bd9Sstevel@tonic-gate ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private; 9277c478bd9Sstevel@tonic-gate int32_t i, max_children, max_device_types, len; 9287c478bd9Sstevel@tonic-gate char *name_p, *device_type_p; 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate DBG1(D_INTR, ebus_p, "ip 0x%p\n", ip); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate /* 9337c478bd9Sstevel@tonic-gate * NOTE: These ops below will never be supported in this nexus 9347c478bd9Sstevel@tonic-gate * driver, hence they always return immediately. 9357c478bd9Sstevel@tonic-gate */ 9367c478bd9Sstevel@tonic-gate switch (intr_op) { 9377c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 9387c478bd9Sstevel@tonic-gate *(int *)result = 0; 9397c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9407c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 9417c478bd9Sstevel@tonic-gate case DDI_INTROP_SETMASK: 9427c478bd9Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 9437c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 9447c478bd9Sstevel@tonic-gate return (DDI_ENOTSUP); 9457c478bd9Sstevel@tonic-gate default: 9467c478bd9Sstevel@tonic-gate break; 9477c478bd9Sstevel@tonic-gate } 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) || ip->is_pil) 9507c478bd9Sstevel@tonic-gate goto done; 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate /* 9537c478bd9Sstevel@tonic-gate * This is a hack to set the PIL for the devices under ebus. 9547c478bd9Sstevel@tonic-gate * We first look up a device by it's specific name, if we can't 9557c478bd9Sstevel@tonic-gate * match the name, we try and match it's device_type property. 9567c478bd9Sstevel@tonic-gate * Lastly we default a PIL level of 1. 9577c478bd9Sstevel@tonic-gate */ 9587c478bd9Sstevel@tonic-gate name_p = ddi_node_name(rdip); 9597c478bd9Sstevel@tonic-gate max_children = sizeof (ebus_name_to_pil) / 9607c478bd9Sstevel@tonic-gate sizeof (struct ebus_string_to_pil); 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate for (i = 0; i < max_children; i++) { 9637c478bd9Sstevel@tonic-gate if (strcmp(ebus_name_to_pil[i].string, name_p) == 0) { 9647c478bd9Sstevel@tonic-gate DBG2(D_INTR, ebus_p, "child name %s; match PIL %d\n", 9657c478bd9Sstevel@tonic-gate ebus_name_to_pil[i].string, 9667c478bd9Sstevel@tonic-gate ebus_name_to_pil[i].pil); 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate ip->is_pil = ebus_name_to_pil[i].pil; 9697c478bd9Sstevel@tonic-gate goto done; 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate 973*a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 9747c478bd9Sstevel@tonic-gate "device_type", (caddr_t)&device_type_p, &len) == DDI_SUCCESS) { 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate max_device_types = sizeof (ebus_device_type_to_pil) / 9777c478bd9Sstevel@tonic-gate sizeof (struct ebus_string_to_pil); 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate for (i = 0; i < max_device_types; i++) { 9807c478bd9Sstevel@tonic-gate if (strcmp(ebus_device_type_to_pil[i].string, 9817c478bd9Sstevel@tonic-gate device_type_p) == 0) { 9827c478bd9Sstevel@tonic-gate DBG2(D_INTR, ebus_p, "Device type %s; match " 9837c478bd9Sstevel@tonic-gate "PIL %d\n", ebus_device_type_to_pil[i]. 9847c478bd9Sstevel@tonic-gate string, ebus_device_type_to_pil[i].pil); 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate ip->is_pil = ebus_device_type_to_pil[i].pil; 9877c478bd9Sstevel@tonic-gate break; 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate kmem_free(device_type_p, len); 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate /* 9957c478bd9Sstevel@tonic-gate * If we get here, we need to set a default value 9967c478bd9Sstevel@tonic-gate * for the PIL. 9977c478bd9Sstevel@tonic-gate */ 9987c478bd9Sstevel@tonic-gate if (ip->is_pil == 0) { 9997c478bd9Sstevel@tonic-gate ip->is_pil = 1; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d assigning default interrupt level %d " 10027c478bd9Sstevel@tonic-gate "for device %s%d", ddi_get_name(dip), ddi_get_instance(dip), 10037c478bd9Sstevel@tonic-gate ip->is_pil, ddi_get_name(rdip), ddi_get_instance(rdip)); 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate done: 10077c478bd9Sstevel@tonic-gate /* Pass up the request to our parent. */ 10087c478bd9Sstevel@tonic-gate return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result)); 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate static int 10137c478bd9Sstevel@tonic-gate ebus_config(ebus_devstate_t *ebus_p) 10147c478bd9Sstevel@tonic-gate { 10157c478bd9Sstevel@tonic-gate ddi_acc_handle_t conf_handle; 10167c478bd9Sstevel@tonic-gate uint16_t comm; 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate /* 10197c478bd9Sstevel@tonic-gate * Make sure the master enable and memory access enable 10207c478bd9Sstevel@tonic-gate * bits are set in the config command register. 10217c478bd9Sstevel@tonic-gate */ 10227c478bd9Sstevel@tonic-gate if (pci_config_setup(ebus_p->dip, &conf_handle) != DDI_SUCCESS) 10237c478bd9Sstevel@tonic-gate return (0); 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate comm = pci_config_get16(conf_handle, PCI_CONF_COMM), 10267c478bd9Sstevel@tonic-gate #ifdef DEBUG 10277c478bd9Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "command register was 0x%x\n", comm); 10287c478bd9Sstevel@tonic-gate #endif 10297c478bd9Sstevel@tonic-gate comm |= (PCI_COMM_ME|PCI_COMM_MAE|PCI_COMM_SERR_ENABLE| 10307c478bd9Sstevel@tonic-gate PCI_COMM_PARITY_DETECT); 10317c478bd9Sstevel@tonic-gate pci_config_put16(conf_handle, PCI_CONF_COMM, comm), 10327c478bd9Sstevel@tonic-gate #ifdef DEBUG 10337c478bd9Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "command register is now 0x%x\n", comm); 10347c478bd9Sstevel@tonic-gate #endif 10357c478bd9Sstevel@tonic-gate pci_config_put8(conf_handle, PCI_CONF_CACHE_LINESZ, 10367c478bd9Sstevel@tonic-gate (uchar_t)ebus_cache_line_size); 10377c478bd9Sstevel@tonic-gate pci_config_put8(conf_handle, PCI_CONF_LATENCY_TIMER, 10387c478bd9Sstevel@tonic-gate (uchar_t)ebus_latency_timer); 10397c478bd9Sstevel@tonic-gate pci_config_teardown(&conf_handle); 10407c478bd9Sstevel@tonic-gate return (1); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate #ifdef DEBUG 10447c478bd9Sstevel@tonic-gate extern void prom_printf(const char *, ...); 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate static void 10477c478bd9Sstevel@tonic-gate ebus_debug(uint_t flag, ebus_devstate_t *ebus_p, char *fmt, 10487c478bd9Sstevel@tonic-gate uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5) 10497c478bd9Sstevel@tonic-gate { 10507c478bd9Sstevel@tonic-gate char *s; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate if (ebus_debug_flags & flag) { 10537c478bd9Sstevel@tonic-gate switch (flag) { 10547c478bd9Sstevel@tonic-gate case D_ATTACH: 10557c478bd9Sstevel@tonic-gate s = "attach"; break; 10567c478bd9Sstevel@tonic-gate case D_DETACH: 10577c478bd9Sstevel@tonic-gate s = "detach"; break; 10587c478bd9Sstevel@tonic-gate case D_MAP: 10597c478bd9Sstevel@tonic-gate s = "map"; break; 10607c478bd9Sstevel@tonic-gate case D_CTLOPS: 10617c478bd9Sstevel@tonic-gate s = "ctlops"; break; 10627c478bd9Sstevel@tonic-gate case D_INTR: 10637c478bd9Sstevel@tonic-gate s = "intr"; break; 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate if (ebus_p) 10667c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: %s: ", 10677c478bd9Sstevel@tonic-gate ddi_get_name(ebus_p->dip), 10687c478bd9Sstevel@tonic-gate ddi_get_instance(ebus_p->dip), s); 10697c478bd9Sstevel@tonic-gate else 10707c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "ebus: "); 10717c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5); 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate #endif 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate /* ARGSUSED3 */ 10777c478bd9Sstevel@tonic-gate static int 10787c478bd9Sstevel@tonic-gate ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp) 10797c478bd9Sstevel@tonic-gate { 10807c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p; 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate /* 10837c478bd9Sstevel@tonic-gate * Make sure the open is for the right file type. 10847c478bd9Sstevel@tonic-gate */ 10857c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 10867c478bd9Sstevel@tonic-gate return (EINVAL); 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate /* 10897c478bd9Sstevel@tonic-gate * Get the soft state structure for the device. 10907c478bd9Sstevel@tonic-gate */ 10917c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(getminor(*devp)); 10927c478bd9Sstevel@tonic-gate if (ebus_p == NULL) 10937c478bd9Sstevel@tonic-gate return (ENXIO); 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate /* 10967c478bd9Sstevel@tonic-gate * Handle the open by tracking the device state. 10977c478bd9Sstevel@tonic-gate */ 10987c478bd9Sstevel@tonic-gate mutex_enter(&ebus_p->ebus_mutex); 10997c478bd9Sstevel@tonic-gate if (flags & FEXCL) { 11007c478bd9Sstevel@tonic-gate if (ebus_p->ebus_soft_state != EBUS_SOFT_STATE_CLOSED) { 11017c478bd9Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 11027c478bd9Sstevel@tonic-gate return (EBUSY); 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN_EXCL; 11057c478bd9Sstevel@tonic-gate } else { 11067c478bd9Sstevel@tonic-gate if (ebus_p->ebus_soft_state == EBUS_SOFT_STATE_OPEN_EXCL) { 11077c478bd9Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 11087c478bd9Sstevel@tonic-gate return (EBUSY); 11097c478bd9Sstevel@tonic-gate } 11107c478bd9Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN; 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 11137c478bd9Sstevel@tonic-gate return (0); 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate /* ARGSUSED */ 11187c478bd9Sstevel@tonic-gate static int 11197c478bd9Sstevel@tonic-gate ebus_close(dev_t dev, int flags, int otyp, cred_t *credp) 11207c478bd9Sstevel@tonic-gate { 11217c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p; 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 11247c478bd9Sstevel@tonic-gate return (EINVAL); 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(getminor(dev)); 11277c478bd9Sstevel@tonic-gate if (ebus_p == NULL) 11287c478bd9Sstevel@tonic-gate return (ENXIO); 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate mutex_enter(&ebus_p->ebus_mutex); 11317c478bd9Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED; 11327c478bd9Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 11337c478bd9Sstevel@tonic-gate return (0); 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate /* 11387c478bd9Sstevel@tonic-gate * ebus_ioctl: devctl hotplug controls 11397c478bd9Sstevel@tonic-gate */ 11407c478bd9Sstevel@tonic-gate /* ARGSUSED */ 11417c478bd9Sstevel@tonic-gate static int 11427c478bd9Sstevel@tonic-gate ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 11437c478bd9Sstevel@tonic-gate int *rvalp) 11447c478bd9Sstevel@tonic-gate { 11457c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p; 11467c478bd9Sstevel@tonic-gate dev_info_t *self; 11477c478bd9Sstevel@tonic-gate struct devctl_iocdata *dcp; 11487c478bd9Sstevel@tonic-gate uint_t bus_state; 11497c478bd9Sstevel@tonic-gate int rv = 0; 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(getminor(dev)); 11527c478bd9Sstevel@tonic-gate if (ebus_p == NULL) 11537c478bd9Sstevel@tonic-gate return (ENXIO); 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate self = ebus_p->dip; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate /* 11587c478bd9Sstevel@tonic-gate * We can use the generic implementation for these ioctls 11597c478bd9Sstevel@tonic-gate */ 11607c478bd9Sstevel@tonic-gate switch (cmd) { 11617c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_GETSTATE: 11627c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_ONLINE: 11637c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_OFFLINE: 11647c478bd9Sstevel@tonic-gate case DEVCTL_BUS_GETSTATE: 11657c478bd9Sstevel@tonic-gate return (ndi_devctl_ioctl(self, cmd, arg, mode, 0)); 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate /* 11697c478bd9Sstevel@tonic-gate * read devctl ioctl data 11707c478bd9Sstevel@tonic-gate */ 11717c478bd9Sstevel@tonic-gate if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 11727c478bd9Sstevel@tonic-gate return (EFAULT); 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate switch (cmd) { 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_RESET: 11777c478bd9Sstevel@tonic-gate rv = ENOTSUP; 11787c478bd9Sstevel@tonic-gate break; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate case DEVCTL_BUS_QUIESCE: 11817c478bd9Sstevel@tonic-gate if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 11827c478bd9Sstevel@tonic-gate if (bus_state == BUS_QUIESCED) 11837c478bd9Sstevel@tonic-gate break; 11847c478bd9Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_QUIESCED); 11857c478bd9Sstevel@tonic-gate break; 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate case DEVCTL_BUS_UNQUIESCE: 11887c478bd9Sstevel@tonic-gate if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 11897c478bd9Sstevel@tonic-gate if (bus_state == BUS_ACTIVE) 11907c478bd9Sstevel@tonic-gate break; 11917c478bd9Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_ACTIVE); 11927c478bd9Sstevel@tonic-gate break; 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate case DEVCTL_BUS_RESET: 11957c478bd9Sstevel@tonic-gate rv = ENOTSUP; 11967c478bd9Sstevel@tonic-gate break; 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate case DEVCTL_BUS_RESETALL: 11997c478bd9Sstevel@tonic-gate rv = ENOTSUP; 12007c478bd9Sstevel@tonic-gate break; 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate default: 12037c478bd9Sstevel@tonic-gate rv = ENOTTY; 12047c478bd9Sstevel@tonic-gate } 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate ndi_dc_freehdl(dcp); 12077c478bd9Sstevel@tonic-gate return (rv); 12087c478bd9Sstevel@tonic-gate } 1209