10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/types.h> 300Sstevel@tonic-gate #include <sys/conf.h> 310Sstevel@tonic-gate #include <sys/ddi.h> 320Sstevel@tonic-gate #include <sys/sunddi.h> 330Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 340Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 350Sstevel@tonic-gate #include <sys/pci.h> 360Sstevel@tonic-gate #include <sys/autoconf.h> 370Sstevel@tonic-gate #include <sys/cmn_err.h> 380Sstevel@tonic-gate #include <sys/errno.h> 390Sstevel@tonic-gate #include <sys/kmem.h> 400Sstevel@tonic-gate #include <sys/debug.h> 410Sstevel@tonic-gate #include <sys/sysmacros.h> 420Sstevel@tonic-gate #include <sys/ebus.h> 430Sstevel@tonic-gate #include <sys/open.h> 440Sstevel@tonic-gate #include <sys/stat.h> 450Sstevel@tonic-gate #include <sys/file.h> 460Sstevel@tonic-gate #include <sys/sunndi.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gate #ifdef DEBUG 490Sstevel@tonic-gate uint64_t ebus_debug_flags = 0; 500Sstevel@tonic-gate #endif 510Sstevel@tonic-gate 520Sstevel@tonic-gate /* 530Sstevel@tonic-gate * The values of the following variables are used to initialize 540Sstevel@tonic-gate * the cache line size and latency timer registers in the ebus 550Sstevel@tonic-gate * configuration header. Variables are used instead of constants 560Sstevel@tonic-gate * to allow tuning from the /etc/system file. 570Sstevel@tonic-gate */ 580Sstevel@tonic-gate static uint8_t ebus_cache_line_size = 0x10; /* 64 bytes */ 590Sstevel@tonic-gate static uint8_t ebus_latency_timer = 0x40; /* 64 PCI cycles */ 600Sstevel@tonic-gate 610Sstevel@tonic-gate /* 620Sstevel@tonic-gate * function prototypes for bus ops routines: 630Sstevel@tonic-gate */ 640Sstevel@tonic-gate static int 650Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 660Sstevel@tonic-gate off_t offset, off_t len, caddr_t *addrp); 670Sstevel@tonic-gate static int 680Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip, 690Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result); 700Sstevel@tonic-gate static int 710Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 720Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result); 730Sstevel@tonic-gate 740Sstevel@tonic-gate /* 750Sstevel@tonic-gate * function prototypes for dev ops routines: 760Sstevel@tonic-gate */ 770Sstevel@tonic-gate static int ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 780Sstevel@tonic-gate static int ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 790Sstevel@tonic-gate static int ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 800Sstevel@tonic-gate void *arg, void **result); 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* 830Sstevel@tonic-gate * general function prototypes: 840Sstevel@tonic-gate */ 850Sstevel@tonic-gate static int ebus_config(ebus_devstate_t *ebus_p); 860Sstevel@tonic-gate static int ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 870Sstevel@tonic-gate ebus_regspec_t *ebus_rp, pci_regspec_t *rp); 880Sstevel@tonic-gate static int febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 890Sstevel@tonic-gate ebus_regspec_t *ebus_rp, struct regspec *rp); 900Sstevel@tonic-gate int get_ranges_prop(ebus_devstate_t *ebus_p); 910Sstevel@tonic-gate 920Sstevel@tonic-gate #define getprop(dip, name, addr, intp) \ 93*506Scth ddi_getlongprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 940Sstevel@tonic-gate (name), (caddr_t)(addr), (intp)) 950Sstevel@tonic-gate 960Sstevel@tonic-gate static int ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp); 970Sstevel@tonic-gate static int ebus_close(dev_t dev, int flags, int otyp, cred_t *credp); 980Sstevel@tonic-gate static int ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 990Sstevel@tonic-gate cred_t *credp, int *rvalp); 1000Sstevel@tonic-gate struct cb_ops ebus_cb_ops = { 1010Sstevel@tonic-gate ebus_open, /* open */ 1020Sstevel@tonic-gate ebus_close, /* close */ 1030Sstevel@tonic-gate nodev, /* strategy */ 1040Sstevel@tonic-gate nodev, /* print */ 1050Sstevel@tonic-gate nodev, /* dump */ 1060Sstevel@tonic-gate nodev, /* read */ 1070Sstevel@tonic-gate nodev, /* write */ 1080Sstevel@tonic-gate ebus_ioctl, /* ioctl */ 1090Sstevel@tonic-gate nodev, /* devmap */ 1100Sstevel@tonic-gate nodev, /* mmap */ 1110Sstevel@tonic-gate nodev, /* segmap */ 1120Sstevel@tonic-gate nochpoll, /* poll */ 1130Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 1140Sstevel@tonic-gate NULL, /* streamtab */ 1150Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 1160Sstevel@tonic-gate CB_REV, /* rev */ 1170Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 1180Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 1190Sstevel@tonic-gate }; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * bus ops and dev ops structures: 1230Sstevel@tonic-gate */ 1240Sstevel@tonic-gate static struct bus_ops ebus_bus_ops = { 1250Sstevel@tonic-gate BUSO_REV, 1260Sstevel@tonic-gate ebus_map, 1270Sstevel@tonic-gate NULL, 1280Sstevel@tonic-gate NULL, 1290Sstevel@tonic-gate NULL, 1300Sstevel@tonic-gate i_ddi_map_fault, 1310Sstevel@tonic-gate ddi_dma_map, 1320Sstevel@tonic-gate ddi_dma_allochdl, 1330Sstevel@tonic-gate ddi_dma_freehdl, 1340Sstevel@tonic-gate ddi_dma_bindhdl, 1350Sstevel@tonic-gate ddi_dma_unbindhdl, 1360Sstevel@tonic-gate ddi_dma_flush, 1370Sstevel@tonic-gate ddi_dma_win, 1380Sstevel@tonic-gate ddi_dma_mctl, 1390Sstevel@tonic-gate ebus_ctlops, 1400Sstevel@tonic-gate ddi_bus_prop_op, 1410Sstevel@tonic-gate ndi_busop_get_eventcookie, 1420Sstevel@tonic-gate ndi_busop_add_eventcall, 1430Sstevel@tonic-gate ndi_busop_remove_eventcall, 1440Sstevel@tonic-gate ndi_post_event, 1450Sstevel@tonic-gate 0, 1460Sstevel@tonic-gate 0, 1470Sstevel@tonic-gate 0, 1480Sstevel@tonic-gate 0, 1490Sstevel@tonic-gate 0, 1500Sstevel@tonic-gate 0, 1510Sstevel@tonic-gate 0, 1520Sstevel@tonic-gate 0, 1530Sstevel@tonic-gate ebus_intr_ops 1540Sstevel@tonic-gate }; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate static struct dev_ops ebus_ops = { 1570Sstevel@tonic-gate DEVO_REV, 1580Sstevel@tonic-gate 0, 1590Sstevel@tonic-gate ebus_info, 1600Sstevel@tonic-gate nulldev, 1610Sstevel@tonic-gate nulldev, 1620Sstevel@tonic-gate ebus_attach, 1630Sstevel@tonic-gate ebus_detach, 1640Sstevel@tonic-gate nodev, 1650Sstevel@tonic-gate &ebus_cb_ops, 1660Sstevel@tonic-gate &ebus_bus_ops 1670Sstevel@tonic-gate }; 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate /* 1700Sstevel@tonic-gate * module definitions: 1710Sstevel@tonic-gate */ 1720Sstevel@tonic-gate #include <sys/modctl.h> 1730Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate static struct modldrv modldrv = { 1760Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 1770Sstevel@tonic-gate "ebus nexus driver %I%", /* Name of module. */ 1780Sstevel@tonic-gate &ebus_ops, /* driver ops */ 1790Sstevel@tonic-gate }; 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate static struct modlinkage modlinkage = { 1820Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 1830Sstevel@tonic-gate }; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate * driver global data: 1870Sstevel@tonic-gate */ 1880Sstevel@tonic-gate static void *per_ebus_state; /* per-ebus soft state pointer */ 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate int 1920Sstevel@tonic-gate _init(void) 1930Sstevel@tonic-gate { 1940Sstevel@tonic-gate int e; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate /* 1970Sstevel@tonic-gate * Initialize per-ebus soft state pointer. 1980Sstevel@tonic-gate */ 1990Sstevel@tonic-gate e = ddi_soft_state_init(&per_ebus_state, sizeof (ebus_devstate_t), 1); 2000Sstevel@tonic-gate if (e != 0) 2010Sstevel@tonic-gate return (e); 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate /* 2040Sstevel@tonic-gate * Install the module. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate e = mod_install(&modlinkage); 2070Sstevel@tonic-gate if (e != 0) 2080Sstevel@tonic-gate ddi_soft_state_fini(&per_ebus_state); 2090Sstevel@tonic-gate return (e); 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate int 2130Sstevel@tonic-gate _fini(void) 2140Sstevel@tonic-gate { 2150Sstevel@tonic-gate int e; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate /* 2180Sstevel@tonic-gate * Remove the module. 2190Sstevel@tonic-gate */ 2200Sstevel@tonic-gate e = mod_remove(&modlinkage); 2210Sstevel@tonic-gate if (e != 0) 2220Sstevel@tonic-gate return (e); 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* 2250Sstevel@tonic-gate * Free the soft state info. 2260Sstevel@tonic-gate */ 2270Sstevel@tonic-gate ddi_soft_state_fini(&per_ebus_state); 2280Sstevel@tonic-gate return (e); 2290Sstevel@tonic-gate } 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate int 2320Sstevel@tonic-gate _info(struct modinfo *modinfop) 2330Sstevel@tonic-gate { 2340Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate /* device driver entry points */ 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate /*ARGSUSED*/ 2400Sstevel@tonic-gate static int 2410Sstevel@tonic-gate ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2420Sstevel@tonic-gate { 2430Sstevel@tonic-gate ebus_devstate_t *ebus_p; /* per ebus state pointer */ 2440Sstevel@tonic-gate int instance; 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate instance = getminor((dev_t)arg); 2470Sstevel@tonic-gate ebus_p = get_ebus_soft_state(instance); 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate switch (infocmd) { 2500Sstevel@tonic-gate default: 2510Sstevel@tonic-gate return (DDI_FAILURE); 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 2540Sstevel@tonic-gate *result = (void *)instance; 2550Sstevel@tonic-gate return (DDI_SUCCESS); 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 2580Sstevel@tonic-gate if (ebus_p == NULL) 2590Sstevel@tonic-gate return (DDI_FAILURE); 2600Sstevel@tonic-gate *result = (void *)ebus_p->dip; 2610Sstevel@tonic-gate return (DDI_SUCCESS); 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * attach entry point: 2670Sstevel@tonic-gate * 2680Sstevel@tonic-gate * normal attach: 2690Sstevel@tonic-gate * 2700Sstevel@tonic-gate * create soft state structure (dip, reg, nreg and state fields) 2710Sstevel@tonic-gate * map in configuration header 2720Sstevel@tonic-gate * make sure device is properly configured 2730Sstevel@tonic-gate * report device 2740Sstevel@tonic-gate */ 2750Sstevel@tonic-gate static int 2760Sstevel@tonic-gate ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2770Sstevel@tonic-gate { 2780Sstevel@tonic-gate ebus_devstate_t *ebus_p; /* per ebus state pointer */ 2790Sstevel@tonic-gate int instance; 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate DBG1(D_ATTACH, NULL, "dip=%p\n", dip); 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate switch (cmd) { 2840Sstevel@tonic-gate case DDI_ATTACH: 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate /* 2870Sstevel@tonic-gate * Allocate soft state for this instance. 2880Sstevel@tonic-gate */ 2890Sstevel@tonic-gate instance = ddi_get_instance(dip); 2900Sstevel@tonic-gate if (ddi_soft_state_zalloc(per_ebus_state, instance) 2910Sstevel@tonic-gate != DDI_SUCCESS) { 2920Sstevel@tonic-gate DBG(D_ATTACH, NULL, "failed to alloc soft state\n"); 2930Sstevel@tonic-gate return (DDI_FAILURE); 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate ebus_p = get_ebus_soft_state(instance); 2960Sstevel@tonic-gate ebus_p->dip = dip; 2970Sstevel@tonic-gate mutex_init(&ebus_p->ebus_mutex, NULL, MUTEX_DRIVER, NULL); 2980Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED; 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* Set ebus type field based on ddi name info */ 3010Sstevel@tonic-gate if (strcmp(ddi_get_name(dip), "jbus-ebus") == 0) { 3020Sstevel@tonic-gate ebus_p->type = FEBUS_TYPE; 3030Sstevel@tonic-gate } else { 3040Sstevel@tonic-gate ebus_p->type = EBUS_TYPE; 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 3080Sstevel@tonic-gate DDI_PROP_CANSLEEP, "no-dma-interrupt-sync", NULL, 0); 3090Sstevel@tonic-gate /* Get our ranges property for mapping child registers. */ 3100Sstevel@tonic-gate if (get_ranges_prop(ebus_p) != DDI_SUCCESS) { 3110Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 3120Sstevel@tonic-gate free_ebus_soft_state(instance); 3130Sstevel@tonic-gate return (DDI_FAILURE); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate /* 3170Sstevel@tonic-gate * create minor node for devctl interfaces 3180Sstevel@tonic-gate */ 3190Sstevel@tonic-gate if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance, 3200Sstevel@tonic-gate DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 3210Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 3220Sstevel@tonic-gate free_ebus_soft_state(instance); 3230Sstevel@tonic-gate return (DDI_FAILURE); 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate /* 3260Sstevel@tonic-gate * Make sure the master enable and memory access enable 3270Sstevel@tonic-gate * bits are set in the config command register. 3280Sstevel@tonic-gate */ 3290Sstevel@tonic-gate if (ebus_p->type == EBUS_TYPE) { 3300Sstevel@tonic-gate if (!ebus_config(ebus_p)) { 3310Sstevel@tonic-gate ddi_remove_minor_node(dip, "devctl"); 3320Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 3330Sstevel@tonic-gate free_ebus_soft_state(instance); 3340Sstevel@tonic-gate return (DDI_FAILURE); 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * Make the pci_report_pmcap() call only for RIO 3400Sstevel@tonic-gate * implementations. 3410Sstevel@tonic-gate */ 3420Sstevel@tonic-gate if (IS_RIO(dip)) { 3430Sstevel@tonic-gate (void) pci_report_pmcap(dip, PCI_PM_IDLESPEED, 3440Sstevel@tonic-gate (void *)EBUS_4MHZ); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate /* 3480Sstevel@tonic-gate * Make the state as attached and report the device. 3490Sstevel@tonic-gate */ 3500Sstevel@tonic-gate ebus_p->state = ATTACHED; 3510Sstevel@tonic-gate ddi_report_dev(dip); 3520Sstevel@tonic-gate DBG(D_ATTACH, ebus_p, "returning\n"); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate return (DDI_SUCCESS); 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate case DDI_RESUME: 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate instance = ddi_get_instance(dip); 3590Sstevel@tonic-gate ebus_p = get_ebus_soft_state(instance); 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate /* 3620Sstevel@tonic-gate * Make sure the master enable and memory access enable 3630Sstevel@tonic-gate * bits are set in the config command register. 3640Sstevel@tonic-gate */ 3650Sstevel@tonic-gate if (ebus_p->type == EBUS_TYPE) { 3660Sstevel@tonic-gate if (!ebus_config(ebus_p)) { 3670Sstevel@tonic-gate free_ebus_soft_state(instance); 3680Sstevel@tonic-gate return (DDI_FAILURE); 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate ebus_p->state = RESUMED; 3730Sstevel@tonic-gate return (DDI_SUCCESS); 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate return (DDI_FAILURE); 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate /* 3790Sstevel@tonic-gate * detach entry point: 3800Sstevel@tonic-gate */ 3810Sstevel@tonic-gate static int 3820Sstevel@tonic-gate ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3830Sstevel@tonic-gate { 3840Sstevel@tonic-gate int instance = ddi_get_instance(dip); 3850Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(instance); 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate switch (cmd) { 3880Sstevel@tonic-gate case DDI_DETACH: 3890Sstevel@tonic-gate DBG1(D_DETACH, ebus_p, "DDI_DETACH dip=%p\n", dip); 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate switch (ebus_p->type) { 3920Sstevel@tonic-gate case EBUS_TYPE: 3930Sstevel@tonic-gate kmem_free(ebus_p->rangespec.rangep, ebus_p->range_cnt * 3940Sstevel@tonic-gate sizeof (struct ebus_pci_rangespec)); 3950Sstevel@tonic-gate break; 3960Sstevel@tonic-gate case FEBUS_TYPE: 3970Sstevel@tonic-gate kmem_free(ebus_p->rangespec.ferangep, 3980Sstevel@tonic-gate ebus_p->range_cnt * 3990Sstevel@tonic-gate sizeof (struct febus_rangespec)); 4000Sstevel@tonic-gate break; 4010Sstevel@tonic-gate default: 4020Sstevel@tonic-gate DBG(D_ATTACH, NULL, "failed to recognize ebus type\n"); 4030Sstevel@tonic-gate return (DDI_FAILURE); 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate ddi_remove_minor_node(dip, "devctl"); 4070Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 4080Sstevel@tonic-gate free_ebus_soft_state(instance); 4090Sstevel@tonic-gate return (DDI_SUCCESS); 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate case DDI_SUSPEND: 4120Sstevel@tonic-gate DBG1(D_DETACH, ebus_p, "DDI_SUSPEND dip=%p\n", dip); 4130Sstevel@tonic-gate ebus_p->state = SUSPENDED; 4140Sstevel@tonic-gate return (DDI_SUCCESS); 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate DBG(D_ATTACH, NULL, "failed to recognize ebus detach command\n"); 4170Sstevel@tonic-gate return (DDI_FAILURE); 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate int 4220Sstevel@tonic-gate get_ranges_prop(ebus_devstate_t *ebus_p) 4230Sstevel@tonic-gate { 4240Sstevel@tonic-gate int nrange, range_len; 4250Sstevel@tonic-gate struct ebus_pci_rangespec *rangep; 4260Sstevel@tonic-gate struct febus_rangespec *ferangep; 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate switch (ebus_p->type) { 4290Sstevel@tonic-gate case EBUS_TYPE: 4300Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, 4310Sstevel@tonic-gate ebus_p->dip, DDI_PROP_DONTPASS, 4320Sstevel@tonic-gate "ranges", (caddr_t)&rangep, 4330Sstevel@tonic-gate &range_len) != DDI_SUCCESS) { 4340Sstevel@tonic-gate cmn_err(CE_WARN, "Can't get %s ranges property", 4350Sstevel@tonic-gate ddi_get_name(ebus_p->dip)); 4360Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate nrange = range_len / sizeof (struct ebus_pci_rangespec); 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate if (nrange == 0) { 4420Sstevel@tonic-gate kmem_free(rangep, range_len); 4430Sstevel@tonic-gate DBG(D_ATTACH, NULL, "range is equal to zero\n"); 4440Sstevel@tonic-gate return (DDI_FAILURE); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate #ifdef DEBUG 4480Sstevel@tonic-gate { 4490Sstevel@tonic-gate int i; 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate for (i = 0; i < nrange; i++) { 4520Sstevel@tonic-gate DBG5(D_MAP, ebus_p, 4530Sstevel@tonic-gate "ebus range addr 0x%x.0x%x PCI range " 4540Sstevel@tonic-gate "addr 0x%x.0x%x.0x%x ", 4550Sstevel@tonic-gate rangep[i].ebus_phys_hi, 4560Sstevel@tonic-gate rangep[i].ebus_phys_low, 4570Sstevel@tonic-gate rangep[i].pci_phys_hi, 4580Sstevel@tonic-gate rangep[i].pci_phys_mid, 4590Sstevel@tonic-gate rangep[i].pci_phys_low); 4600Sstevel@tonic-gate DBG1(D_MAP, ebus_p, 4610Sstevel@tonic-gate "Size 0x%x\n", rangep[i].rng_size); 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate #endif /* DEBUG */ 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate ebus_p->rangespec.rangep = rangep; 4670Sstevel@tonic-gate ebus_p->range_cnt = nrange; 4680Sstevel@tonic-gate return (DDI_SUCCESS); 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate case FEBUS_TYPE: 4710Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, ebus_p->dip, 4720Sstevel@tonic-gate DDI_PROP_DONTPASS, "ranges", 4730Sstevel@tonic-gate (caddr_t)&ferangep, &range_len) != DDI_SUCCESS) { 4740Sstevel@tonic-gate cmn_err(CE_WARN, "Can't get %s ranges property", 4750Sstevel@tonic-gate ddi_get_name(ebus_p->dip)); 4760Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate nrange = range_len / sizeof (struct febus_rangespec); 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate if (nrange == 0) { 4820Sstevel@tonic-gate kmem_free(ferangep, range_len); 4830Sstevel@tonic-gate return (DDI_FAILURE); 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate #ifdef DEBUG 4870Sstevel@tonic-gate { 4880Sstevel@tonic-gate int i; 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate for (i = 0; i < nrange; i++) { 4910Sstevel@tonic-gate DBG4(D_MAP, ebus_p, 4920Sstevel@tonic-gate "ebus range addr 0x%x.0x%x" 4930Sstevel@tonic-gate " Parent range " 4940Sstevel@tonic-gate "addr 0x%x.0x%x ", 4950Sstevel@tonic-gate ferangep[i].febus_phys_hi, 4960Sstevel@tonic-gate ferangep[i].febus_phys_low, 4970Sstevel@tonic-gate ferangep[i].parent_phys_hi, 4980Sstevel@tonic-gate ferangep[i].parent_phys_low); 4990Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "Size 0x%x\n", 5000Sstevel@tonic-gate ferangep[i].rng_size); 5010Sstevel@tonic-gate } 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate #endif /* DEBUG */ 5040Sstevel@tonic-gate ebus_p->rangespec.ferangep = ferangep; 5050Sstevel@tonic-gate ebus_p->range_cnt = nrange; 5060Sstevel@tonic-gate return (DDI_SUCCESS); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate default: 5090Sstevel@tonic-gate DBG(D_MAP, NULL, "failed to recognize ebus type\n"); 5100Sstevel@tonic-gate return (DDI_FAILURE); 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate /* bus driver entry points */ 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate /* 5170Sstevel@tonic-gate * bus map entry point: 5180Sstevel@tonic-gate * 5190Sstevel@tonic-gate * if map request is for an rnumber 5200Sstevel@tonic-gate * get the corresponding regspec from device node 5210Sstevel@tonic-gate * build a new regspec in our parent's format 5220Sstevel@tonic-gate * build a new map_req with the new regspec 5230Sstevel@tonic-gate * call up the tree to complete the mapping 5240Sstevel@tonic-gate */ 5250Sstevel@tonic-gate static int 5260Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 5270Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp) 5280Sstevel@tonic-gate { 5290Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip)); 5300Sstevel@tonic-gate ebus_regspec_t *ebus_rp, *ebus_regs; 5310Sstevel@tonic-gate struct regspec reg; 5320Sstevel@tonic-gate pci_regspec_t pci_reg; 5330Sstevel@tonic-gate ddi_map_req_t p_map_request; 5340Sstevel@tonic-gate int rnumber, i, n; 5350Sstevel@tonic-gate int rval = DDI_SUCCESS; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate /* 5380Sstevel@tonic-gate * Handle the mapping according to its type. 5390Sstevel@tonic-gate */ 5400Sstevel@tonic-gate DBG4(D_MAP, ebus_p, "rdip=%s%d: off=%x len=%x\n", 5410Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), off, len); 5420Sstevel@tonic-gate switch (mp->map_type) { 5430Sstevel@tonic-gate case DDI_MT_REGSPEC: 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate /* 5460Sstevel@tonic-gate * We assume the register specification is in ebus format. 5470Sstevel@tonic-gate * We must convert it into a PCI format regspec and pass 5480Sstevel@tonic-gate * the request to our parent. 5490Sstevel@tonic-gate */ 5500Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "rdip=%s%d: REGSPEC - handlep=%p\n", 5510Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 5520Sstevel@tonic-gate mp->map_handlep); 5530Sstevel@tonic-gate ebus_rp = (ebus_regspec_t *)mp->map_obj.rp; 5540Sstevel@tonic-gate break; 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate case DDI_MT_RNUMBER: 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate /* 5590Sstevel@tonic-gate * Get the "reg" property from the device node and convert 5600Sstevel@tonic-gate * it to our parent's format. 5610Sstevel@tonic-gate */ 5620Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 5630Sstevel@tonic-gate DBG4(D_MAP, ebus_p, "rdip=%s%d: rnumber=%x handlep=%p\n", 5640Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 5650Sstevel@tonic-gate rnumber, mp->map_handlep); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate if (getprop(rdip, "reg", &ebus_regs, &i) != DDI_SUCCESS) { 5680Sstevel@tonic-gate DBG(D_MAP, ebus_p, "can't get reg property\n"); 5690Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate n = i / sizeof (ebus_regspec_t); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate if (rnumber < 0 || rnumber >= n) { 5740Sstevel@tonic-gate DBG(D_MAP, ebus_p, "rnumber out of range\n"); 5750Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate ebus_rp = &ebus_regs[rnumber]; 5780Sstevel@tonic-gate break; 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate default: 5810Sstevel@tonic-gate return (DDI_ME_INVAL); 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate /* Adjust our reg property with offset and length */ 5860Sstevel@tonic-gate ebus_rp->addr_low += off; 5870Sstevel@tonic-gate if (len) 5880Sstevel@tonic-gate ebus_rp->size = len; 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate /* 5910Sstevel@tonic-gate * Now we have a copy the "reg" entry we're attempting to map. 5920Sstevel@tonic-gate * Translate this into our parents PCI address using the ranges 5930Sstevel@tonic-gate * property. 5940Sstevel@tonic-gate */ 5950Sstevel@tonic-gate switch (ebus_p->type) { 5960Sstevel@tonic-gate case EBUS_TYPE: 5970Sstevel@tonic-gate rval = ebus_apply_range(ebus_p, rdip, ebus_rp, &pci_reg); 5980Sstevel@tonic-gate break; 5990Sstevel@tonic-gate case FEBUS_TYPE: 6000Sstevel@tonic-gate rval = febus_apply_range(ebus_p, rdip, ebus_rp, ®); 6010Sstevel@tonic-gate break; 6020Sstevel@tonic-gate default: 6030Sstevel@tonic-gate DBG(D_MAP, NULL, "failed to recognize ebus type\n"); 6040Sstevel@tonic-gate rval = DDI_FAILURE; 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate if (mp->map_type == DDI_MT_RNUMBER) 6080Sstevel@tonic-gate kmem_free(ebus_regs, i); 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate if (rval != DDI_SUCCESS) 6110Sstevel@tonic-gate return (rval); 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate #ifdef DEBUG 6140Sstevel@tonic-gate switch (ebus_p->type) { 6150Sstevel@tonic-gate case EBUS_TYPE: 6160Sstevel@tonic-gate DBG5(D_MAP, ebus_p, "(%x,%x,%x)(%x,%x)\n", 6170Sstevel@tonic-gate pci_reg.pci_phys_hi, 6180Sstevel@tonic-gate pci_reg.pci_phys_mid, 6190Sstevel@tonic-gate pci_reg.pci_phys_low, 6200Sstevel@tonic-gate pci_reg.pci_size_hi, 6210Sstevel@tonic-gate pci_reg.pci_size_low); 6220Sstevel@tonic-gate break; 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate case FEBUS_TYPE: 6250Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "%x,%x,%x\n", 6260Sstevel@tonic-gate reg.regspec_bustype, 6270Sstevel@tonic-gate reg.regspec_addr, 6280Sstevel@tonic-gate reg.regspec_size); 6290Sstevel@tonic-gate break; 6300Sstevel@tonic-gate } 6310Sstevel@tonic-gate #endif 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate p_map_request = *mp; 6340Sstevel@tonic-gate p_map_request.map_type = DDI_MT_REGSPEC; 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate switch (ebus_p->type) { 6370Sstevel@tonic-gate case EBUS_TYPE: 6380Sstevel@tonic-gate p_map_request.map_obj.rp = (struct regspec *)&pci_reg; 6390Sstevel@tonic-gate break; 6400Sstevel@tonic-gate case FEBUS_TYPE: 6410Sstevel@tonic-gate p_map_request.map_obj.rp = ® 6420Sstevel@tonic-gate break; 6430Sstevel@tonic-gate default: 6440Sstevel@tonic-gate DBG(D_MAP, NULL, "failed to recognize ebus type\n"); 6450Sstevel@tonic-gate return (DDI_FAILURE); 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate rval = ddi_map(dip, &p_map_request, 0, 0, addrp); 6490Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "parent returned %x\n", rval); 6500Sstevel@tonic-gate return (rval); 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate static int 6550Sstevel@tonic-gate ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 6560Sstevel@tonic-gate ebus_regspec_t *ebus_rp, pci_regspec_t *rp) 6570Sstevel@tonic-gate { 6580Sstevel@tonic-gate int b; 6590Sstevel@tonic-gate int rval = DDI_SUCCESS; 6600Sstevel@tonic-gate struct ebus_pci_rangespec *rangep = ebus_p->rangespec.rangep; 6610Sstevel@tonic-gate int nrange = ebus_p->range_cnt; 6620Sstevel@tonic-gate static char out_of_range[] = 6630Sstevel@tonic-gate "Out of range register specification from device node <%s>"; 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n", 6660Sstevel@tonic-gate ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size); 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate for (b = 0; b < nrange; ++b, ++rangep) { 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* Check for the correct space */ 6710Sstevel@tonic-gate if (ebus_rp->addr_hi == rangep->ebus_phys_hi) 6720Sstevel@tonic-gate /* See if we fit in this range */ 6730Sstevel@tonic-gate if ((ebus_rp->addr_low >= 6740Sstevel@tonic-gate rangep->ebus_phys_low) && 6750Sstevel@tonic-gate ((ebus_rp->addr_low + ebus_rp->size - 1) 6760Sstevel@tonic-gate <= (rangep->ebus_phys_low + 6770Sstevel@tonic-gate rangep->rng_size - 1))) { 6780Sstevel@tonic-gate uint_t addr_offset = ebus_rp->addr_low - 6790Sstevel@tonic-gate rangep->ebus_phys_low; 6800Sstevel@tonic-gate /* 6810Sstevel@tonic-gate * Use the range entry to translate 6820Sstevel@tonic-gate * the EBUS physical address into the 6830Sstevel@tonic-gate * parents PCI space. 6840Sstevel@tonic-gate */ 6850Sstevel@tonic-gate rp->pci_phys_hi = 6860Sstevel@tonic-gate rangep->pci_phys_hi; 6870Sstevel@tonic-gate rp->pci_phys_mid = rangep->pci_phys_mid; 6880Sstevel@tonic-gate rp->pci_phys_low = 6890Sstevel@tonic-gate rangep->pci_phys_low + addr_offset; 6900Sstevel@tonic-gate rp->pci_size_hi = 0; 6910Sstevel@tonic-gate rp->pci_size_low = 6920Sstevel@tonic-gate min(ebus_rp->size, (rangep->rng_size - 6930Sstevel@tonic-gate addr_offset)); 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ", 6960Sstevel@tonic-gate rangep->ebus_phys_hi, 6970Sstevel@tonic-gate rangep->ebus_phys_low); 6980Sstevel@tonic-gate DBG4(D_MAP, ebus_p, "Parent hi0x%x " 6990Sstevel@tonic-gate "mid0x%x lo0x%x size 0x%x\n", 7000Sstevel@tonic-gate rangep->pci_phys_hi, 7010Sstevel@tonic-gate rangep->pci_phys_mid, 7020Sstevel@tonic-gate rangep->pci_phys_low, 7030Sstevel@tonic-gate rangep->rng_size); 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate break; 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate if (b == nrange) { 7100Sstevel@tonic-gate cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip)); 7110Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate return (rval); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate static int 7180Sstevel@tonic-gate febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 7190Sstevel@tonic-gate ebus_regspec_t *ebus_rp, struct regspec *rp) { 7200Sstevel@tonic-gate int b; 7210Sstevel@tonic-gate int rval = DDI_SUCCESS; 7220Sstevel@tonic-gate struct febus_rangespec *rangep = ebus_p->rangespec.ferangep; 7230Sstevel@tonic-gate int nrange = ebus_p->range_cnt; 7240Sstevel@tonic-gate static char out_of_range[] = 7250Sstevel@tonic-gate "Out of range register specification from device node <%s>"; 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n", 7280Sstevel@tonic-gate ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size); 7290Sstevel@tonic-gate 7300Sstevel@tonic-gate for (b = 0; b < nrange; ++b, ++rangep) { 7310Sstevel@tonic-gate /* Check for the correct space */ 7320Sstevel@tonic-gate if (ebus_rp->addr_hi == rangep->febus_phys_hi) 7330Sstevel@tonic-gate /* See if we fit in this range */ 7340Sstevel@tonic-gate if ((ebus_rp->addr_low >= 7350Sstevel@tonic-gate rangep->febus_phys_low) && 7360Sstevel@tonic-gate ((ebus_rp->addr_low + ebus_rp->size - 1) 7370Sstevel@tonic-gate <= (rangep->febus_phys_low + 7380Sstevel@tonic-gate rangep->rng_size - 1))) { 7390Sstevel@tonic-gate uint_t addr_offset = ebus_rp->addr_low - 7400Sstevel@tonic-gate rangep->febus_phys_low; 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate /* 7430Sstevel@tonic-gate * Use the range entry to translate 7440Sstevel@tonic-gate * the FEBUS physical address into the 7450Sstevel@tonic-gate * parents space. 7460Sstevel@tonic-gate */ 7470Sstevel@tonic-gate rp->regspec_bustype = 7480Sstevel@tonic-gate rangep->parent_phys_hi; 7490Sstevel@tonic-gate rp->regspec_addr = 7500Sstevel@tonic-gate rangep->parent_phys_low + addr_offset; 7510Sstevel@tonic-gate rp->regspec_size = 7520Sstevel@tonic-gate min(ebus_rp->size, (rangep->rng_size - 7530Sstevel@tonic-gate addr_offset)); 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ", 7560Sstevel@tonic-gate rangep->febus_phys_hi, 7570Sstevel@tonic-gate rangep->febus_phys_low); 7580Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "Parent hi0x%x " 7590Sstevel@tonic-gate "lo0x%x size 0x%x\n", 7600Sstevel@tonic-gate rangep->parent_phys_hi, 7610Sstevel@tonic-gate rangep->parent_phys_low, 7620Sstevel@tonic-gate rangep->rng_size); 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate break; 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate if (b == nrange) { 7690Sstevel@tonic-gate cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip)); 7700Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate return (rval); 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate static int 7780Sstevel@tonic-gate ebus_name_child(dev_info_t *child, char *name, int namelen) 7790Sstevel@tonic-gate { 7800Sstevel@tonic-gate ebus_regspec_t *ebus_rp; 7810Sstevel@tonic-gate int reglen; 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate /* 7840Sstevel@tonic-gate * Get the address portion of the node name based on the 7850Sstevel@tonic-gate * address/offset. 7860Sstevel@tonic-gate */ 787*506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 7880Sstevel@tonic-gate "reg", (caddr_t)&ebus_rp, ®len) != DDI_SUCCESS) { 7890Sstevel@tonic-gate return (DDI_FAILURE); 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", ebus_rp->addr_hi, 7930Sstevel@tonic-gate ebus_rp->addr_low); 7940Sstevel@tonic-gate kmem_free(ebus_rp, reglen); 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate return (DDI_SUCCESS); 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate /* 8000Sstevel@tonic-gate * control ops entry point: 8010Sstevel@tonic-gate * 8020Sstevel@tonic-gate * Requests handled completely: 8030Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD 8040Sstevel@tonic-gate * DDI_CTLOPS_UNINITCHILD 8050Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV 8060Sstevel@tonic-gate * DDI_CTLOPS_REGSIZE 8070Sstevel@tonic-gate * DDI_CTLOPS_NREGS 8080Sstevel@tonic-gate * 8090Sstevel@tonic-gate * All others passed to parent. 8100Sstevel@tonic-gate */ 8110Sstevel@tonic-gate static int 8120Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip, 8130Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result) 8140Sstevel@tonic-gate { 8150Sstevel@tonic-gate #ifdef DEBUG 8160Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip)); 8170Sstevel@tonic-gate #endif 8180Sstevel@tonic-gate ebus_regspec_t *ebus_rp; 8190Sstevel@tonic-gate int i, n; 8200Sstevel@tonic-gate char name[10]; 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate switch (op) { 8230Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: { 8240Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg; 8250Sstevel@tonic-gate /* 8260Sstevel@tonic-gate * Set the address portion of the node name based on the 8270Sstevel@tonic-gate * address/offset. 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n", 8300Sstevel@tonic-gate ddi_get_name(child), ddi_get_instance(child)); 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate if (ebus_name_child(child, name, 10) != DDI_SUCCESS) { 8330Sstevel@tonic-gate DBG(D_CTLOPS, ebus_p, "can't name child\n"); 8340Sstevel@tonic-gate return (DDI_FAILURE); 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate ddi_set_name_addr(child, name); 8380Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 8390Sstevel@tonic-gate return (DDI_SUCCESS); 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 8430Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n", 8440Sstevel@tonic-gate ddi_get_name((dev_info_t *)arg), 8450Sstevel@tonic-gate ddi_get_instance((dev_info_t *)arg)); 8460Sstevel@tonic-gate ddi_set_name_addr((dev_info_t *)arg, NULL); 8470Sstevel@tonic-gate ddi_remove_minor_node((dev_info_t *)arg, NULL); 8480Sstevel@tonic-gate impl_rem_dev_props((dev_info_t *)arg); 8490Sstevel@tonic-gate return (DDI_SUCCESS); 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n", 8540Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8550Sstevel@tonic-gate cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n", 8560Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), 8570Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 8580Sstevel@tonic-gate ddi_get_name_addr(rdip)); 8590Sstevel@tonic-gate return (DDI_SUCCESS); 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n", 8640Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8650Sstevel@tonic-gate if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) { 8660Sstevel@tonic-gate DBG(D_CTLOPS, ebus_p, "can't get reg property\n"); 8670Sstevel@tonic-gate return (DDI_FAILURE); 8680Sstevel@tonic-gate } 8690Sstevel@tonic-gate n = i / sizeof (ebus_regspec_t); 8700Sstevel@tonic-gate if (*(int *)arg < 0 || *(int *)arg >= n) { 8710Sstevel@tonic-gate DBG(D_MAP, ebus_p, "rnumber out of range\n"); 8720Sstevel@tonic-gate kmem_free(ebus_rp, i); 8730Sstevel@tonic-gate return (DDI_FAILURE); 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate *((off_t *)result) = ebus_rp[*(int *)arg].size; 8760Sstevel@tonic-gate kmem_free(ebus_rp, i); 8770Sstevel@tonic-gate return (DDI_SUCCESS); 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_NREGS: rdip=%s%d\n", 8820Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8830Sstevel@tonic-gate if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) { 8840Sstevel@tonic-gate DBG(D_CTLOPS, ebus_p, "can't get reg property\n"); 8850Sstevel@tonic-gate return (DDI_FAILURE); 8860Sstevel@tonic-gate } 8870Sstevel@tonic-gate *((uint_t *)result) = i / sizeof (ebus_regspec_t); 8880Sstevel@tonic-gate kmem_free(ebus_rp, i); 8890Sstevel@tonic-gate return (DDI_SUCCESS); 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate /* 8930Sstevel@tonic-gate * Now pass the request up to our parent. 8940Sstevel@tonic-gate */ 8950Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "passing request to parent: rdip=%s%d\n", 8960Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 8970Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate struct ebus_string_to_pil { 9010Sstevel@tonic-gate int8_t *string; 9020Sstevel@tonic-gate uint32_t pil; 9030Sstevel@tonic-gate }; 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate static struct ebus_string_to_pil ebus_name_to_pil[] = {{"SUNW,CS4231", 9}, 9060Sstevel@tonic-gate {"audio", 9}, 9070Sstevel@tonic-gate {"fdthree", 8}, 9080Sstevel@tonic-gate {"floppy", 8}, 9090Sstevel@tonic-gate {"ecpp", 3}, 9100Sstevel@tonic-gate {"parallel", 3}, 9110Sstevel@tonic-gate {"su", 12}, 9120Sstevel@tonic-gate {"se", 12}, 9130Sstevel@tonic-gate {"serial", 12}, 9140Sstevel@tonic-gate {"power", 14}}; 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate static struct ebus_string_to_pil ebus_device_type_to_pil[] = {{"serial", 12}, 9170Sstevel@tonic-gate {"block", 8}}; 9180Sstevel@tonic-gate 9190Sstevel@tonic-gate static int 9200Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 9210Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 9220Sstevel@tonic-gate { 9230Sstevel@tonic-gate #ifdef DEBUG 9240Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip)); 9250Sstevel@tonic-gate #endif 9260Sstevel@tonic-gate ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private; 9270Sstevel@tonic-gate int32_t i, max_children, max_device_types, len; 9280Sstevel@tonic-gate char *name_p, *device_type_p; 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate DBG1(D_INTR, ebus_p, "ip 0x%p\n", ip); 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate /* 9330Sstevel@tonic-gate * NOTE: These ops below will never be supported in this nexus 9340Sstevel@tonic-gate * driver, hence they always return immediately. 9350Sstevel@tonic-gate */ 9360Sstevel@tonic-gate switch (intr_op) { 9370Sstevel@tonic-gate case DDI_INTROP_GETCAP: 9380Sstevel@tonic-gate *(int *)result = 0; 9390Sstevel@tonic-gate return (DDI_SUCCESS); 9400Sstevel@tonic-gate case DDI_INTROP_SETCAP: 9410Sstevel@tonic-gate case DDI_INTROP_SETMASK: 9420Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 9430Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 9440Sstevel@tonic-gate return (DDI_ENOTSUP); 9450Sstevel@tonic-gate default: 9460Sstevel@tonic-gate break; 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) || ip->is_pil) 9500Sstevel@tonic-gate goto done; 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate /* 9530Sstevel@tonic-gate * This is a hack to set the PIL for the devices under ebus. 9540Sstevel@tonic-gate * We first look up a device by it's specific name, if we can't 9550Sstevel@tonic-gate * match the name, we try and match it's device_type property. 9560Sstevel@tonic-gate * Lastly we default a PIL level of 1. 9570Sstevel@tonic-gate */ 9580Sstevel@tonic-gate name_p = ddi_node_name(rdip); 9590Sstevel@tonic-gate max_children = sizeof (ebus_name_to_pil) / 9600Sstevel@tonic-gate sizeof (struct ebus_string_to_pil); 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate for (i = 0; i < max_children; i++) { 9630Sstevel@tonic-gate if (strcmp(ebus_name_to_pil[i].string, name_p) == 0) { 9640Sstevel@tonic-gate DBG2(D_INTR, ebus_p, "child name %s; match PIL %d\n", 9650Sstevel@tonic-gate ebus_name_to_pil[i].string, 9660Sstevel@tonic-gate ebus_name_to_pil[i].pil); 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate ip->is_pil = ebus_name_to_pil[i].pil; 9690Sstevel@tonic-gate goto done; 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 973*506Scth if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 9740Sstevel@tonic-gate "device_type", (caddr_t)&device_type_p, &len) == DDI_SUCCESS) { 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate max_device_types = sizeof (ebus_device_type_to_pil) / 9770Sstevel@tonic-gate sizeof (struct ebus_string_to_pil); 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate for (i = 0; i < max_device_types; i++) { 9800Sstevel@tonic-gate if (strcmp(ebus_device_type_to_pil[i].string, 9810Sstevel@tonic-gate device_type_p) == 0) { 9820Sstevel@tonic-gate DBG2(D_INTR, ebus_p, "Device type %s; match " 9830Sstevel@tonic-gate "PIL %d\n", ebus_device_type_to_pil[i]. 9840Sstevel@tonic-gate string, ebus_device_type_to_pil[i].pil); 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate ip->is_pil = ebus_device_type_to_pil[i].pil; 9870Sstevel@tonic-gate break; 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate kmem_free(device_type_p, len); 9920Sstevel@tonic-gate } 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate /* 9950Sstevel@tonic-gate * If we get here, we need to set a default value 9960Sstevel@tonic-gate * for the PIL. 9970Sstevel@tonic-gate */ 9980Sstevel@tonic-gate if (ip->is_pil == 0) { 9990Sstevel@tonic-gate ip->is_pil = 1; 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d assigning default interrupt level %d " 10020Sstevel@tonic-gate "for device %s%d", ddi_get_name(dip), ddi_get_instance(dip), 10030Sstevel@tonic-gate ip->is_pil, ddi_get_name(rdip), ddi_get_instance(rdip)); 10040Sstevel@tonic-gate } 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate done: 10070Sstevel@tonic-gate /* Pass up the request to our parent. */ 10080Sstevel@tonic-gate return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result)); 10090Sstevel@tonic-gate } 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate static int 10130Sstevel@tonic-gate ebus_config(ebus_devstate_t *ebus_p) 10140Sstevel@tonic-gate { 10150Sstevel@tonic-gate ddi_acc_handle_t conf_handle; 10160Sstevel@tonic-gate uint16_t comm; 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate /* 10190Sstevel@tonic-gate * Make sure the master enable and memory access enable 10200Sstevel@tonic-gate * bits are set in the config command register. 10210Sstevel@tonic-gate */ 10220Sstevel@tonic-gate if (pci_config_setup(ebus_p->dip, &conf_handle) != DDI_SUCCESS) 10230Sstevel@tonic-gate return (0); 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate comm = pci_config_get16(conf_handle, PCI_CONF_COMM), 10260Sstevel@tonic-gate #ifdef DEBUG 10270Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "command register was 0x%x\n", comm); 10280Sstevel@tonic-gate #endif 10290Sstevel@tonic-gate comm |= (PCI_COMM_ME|PCI_COMM_MAE|PCI_COMM_SERR_ENABLE| 10300Sstevel@tonic-gate PCI_COMM_PARITY_DETECT); 10310Sstevel@tonic-gate pci_config_put16(conf_handle, PCI_CONF_COMM, comm), 10320Sstevel@tonic-gate #ifdef DEBUG 10330Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "command register is now 0x%x\n", comm); 10340Sstevel@tonic-gate #endif 10350Sstevel@tonic-gate pci_config_put8(conf_handle, PCI_CONF_CACHE_LINESZ, 10360Sstevel@tonic-gate (uchar_t)ebus_cache_line_size); 10370Sstevel@tonic-gate pci_config_put8(conf_handle, PCI_CONF_LATENCY_TIMER, 10380Sstevel@tonic-gate (uchar_t)ebus_latency_timer); 10390Sstevel@tonic-gate pci_config_teardown(&conf_handle); 10400Sstevel@tonic-gate return (1); 10410Sstevel@tonic-gate } 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate #ifdef DEBUG 10440Sstevel@tonic-gate extern void prom_printf(const char *, ...); 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate static void 10470Sstevel@tonic-gate ebus_debug(uint_t flag, ebus_devstate_t *ebus_p, char *fmt, 10480Sstevel@tonic-gate uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5) 10490Sstevel@tonic-gate { 10500Sstevel@tonic-gate char *s; 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate if (ebus_debug_flags & flag) { 10530Sstevel@tonic-gate switch (flag) { 10540Sstevel@tonic-gate case D_ATTACH: 10550Sstevel@tonic-gate s = "attach"; break; 10560Sstevel@tonic-gate case D_DETACH: 10570Sstevel@tonic-gate s = "detach"; break; 10580Sstevel@tonic-gate case D_MAP: 10590Sstevel@tonic-gate s = "map"; break; 10600Sstevel@tonic-gate case D_CTLOPS: 10610Sstevel@tonic-gate s = "ctlops"; break; 10620Sstevel@tonic-gate case D_INTR: 10630Sstevel@tonic-gate s = "intr"; break; 10640Sstevel@tonic-gate } 10650Sstevel@tonic-gate if (ebus_p) 10660Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: %s: ", 10670Sstevel@tonic-gate ddi_get_name(ebus_p->dip), 10680Sstevel@tonic-gate ddi_get_instance(ebus_p->dip), s); 10690Sstevel@tonic-gate else 10700Sstevel@tonic-gate cmn_err(CE_CONT, "ebus: "); 10710Sstevel@tonic-gate cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5); 10720Sstevel@tonic-gate } 10730Sstevel@tonic-gate } 10740Sstevel@tonic-gate #endif 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate /* ARGSUSED3 */ 10770Sstevel@tonic-gate static int 10780Sstevel@tonic-gate ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp) 10790Sstevel@tonic-gate { 10800Sstevel@tonic-gate ebus_devstate_t *ebus_p; 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate /* 10830Sstevel@tonic-gate * Make sure the open is for the right file type. 10840Sstevel@tonic-gate */ 10850Sstevel@tonic-gate if (otyp != OTYP_CHR) 10860Sstevel@tonic-gate return (EINVAL); 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate /* 10890Sstevel@tonic-gate * Get the soft state structure for the device. 10900Sstevel@tonic-gate */ 10910Sstevel@tonic-gate ebus_p = get_ebus_soft_state(getminor(*devp)); 10920Sstevel@tonic-gate if (ebus_p == NULL) 10930Sstevel@tonic-gate return (ENXIO); 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate /* 10960Sstevel@tonic-gate * Handle the open by tracking the device state. 10970Sstevel@tonic-gate */ 10980Sstevel@tonic-gate mutex_enter(&ebus_p->ebus_mutex); 10990Sstevel@tonic-gate if (flags & FEXCL) { 11000Sstevel@tonic-gate if (ebus_p->ebus_soft_state != EBUS_SOFT_STATE_CLOSED) { 11010Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 11020Sstevel@tonic-gate return (EBUSY); 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN_EXCL; 11050Sstevel@tonic-gate } else { 11060Sstevel@tonic-gate if (ebus_p->ebus_soft_state == EBUS_SOFT_STATE_OPEN_EXCL) { 11070Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 11080Sstevel@tonic-gate return (EBUSY); 11090Sstevel@tonic-gate } 11100Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN; 11110Sstevel@tonic-gate } 11120Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 11130Sstevel@tonic-gate return (0); 11140Sstevel@tonic-gate } 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate /* ARGSUSED */ 11180Sstevel@tonic-gate static int 11190Sstevel@tonic-gate ebus_close(dev_t dev, int flags, int otyp, cred_t *credp) 11200Sstevel@tonic-gate { 11210Sstevel@tonic-gate ebus_devstate_t *ebus_p; 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate if (otyp != OTYP_CHR) 11240Sstevel@tonic-gate return (EINVAL); 11250Sstevel@tonic-gate 11260Sstevel@tonic-gate ebus_p = get_ebus_soft_state(getminor(dev)); 11270Sstevel@tonic-gate if (ebus_p == NULL) 11280Sstevel@tonic-gate return (ENXIO); 11290Sstevel@tonic-gate 11300Sstevel@tonic-gate mutex_enter(&ebus_p->ebus_mutex); 11310Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED; 11320Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 11330Sstevel@tonic-gate return (0); 11340Sstevel@tonic-gate } 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate /* 11380Sstevel@tonic-gate * ebus_ioctl: devctl hotplug controls 11390Sstevel@tonic-gate */ 11400Sstevel@tonic-gate /* ARGSUSED */ 11410Sstevel@tonic-gate static int 11420Sstevel@tonic-gate ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 11430Sstevel@tonic-gate int *rvalp) 11440Sstevel@tonic-gate { 11450Sstevel@tonic-gate ebus_devstate_t *ebus_p; 11460Sstevel@tonic-gate dev_info_t *self; 11470Sstevel@tonic-gate struct devctl_iocdata *dcp; 11480Sstevel@tonic-gate uint_t bus_state; 11490Sstevel@tonic-gate int rv = 0; 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate ebus_p = get_ebus_soft_state(getminor(dev)); 11520Sstevel@tonic-gate if (ebus_p == NULL) 11530Sstevel@tonic-gate return (ENXIO); 11540Sstevel@tonic-gate 11550Sstevel@tonic-gate self = ebus_p->dip; 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate /* 11580Sstevel@tonic-gate * We can use the generic implementation for these ioctls 11590Sstevel@tonic-gate */ 11600Sstevel@tonic-gate switch (cmd) { 11610Sstevel@tonic-gate case DEVCTL_DEVICE_GETSTATE: 11620Sstevel@tonic-gate case DEVCTL_DEVICE_ONLINE: 11630Sstevel@tonic-gate case DEVCTL_DEVICE_OFFLINE: 11640Sstevel@tonic-gate case DEVCTL_BUS_GETSTATE: 11650Sstevel@tonic-gate return (ndi_devctl_ioctl(self, cmd, arg, mode, 0)); 11660Sstevel@tonic-gate } 11670Sstevel@tonic-gate 11680Sstevel@tonic-gate /* 11690Sstevel@tonic-gate * read devctl ioctl data 11700Sstevel@tonic-gate */ 11710Sstevel@tonic-gate if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 11720Sstevel@tonic-gate return (EFAULT); 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate switch (cmd) { 11750Sstevel@tonic-gate 11760Sstevel@tonic-gate case DEVCTL_DEVICE_RESET: 11770Sstevel@tonic-gate rv = ENOTSUP; 11780Sstevel@tonic-gate break; 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate case DEVCTL_BUS_QUIESCE: 11810Sstevel@tonic-gate if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 11820Sstevel@tonic-gate if (bus_state == BUS_QUIESCED) 11830Sstevel@tonic-gate break; 11840Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_QUIESCED); 11850Sstevel@tonic-gate break; 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate case DEVCTL_BUS_UNQUIESCE: 11880Sstevel@tonic-gate if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 11890Sstevel@tonic-gate if (bus_state == BUS_ACTIVE) 11900Sstevel@tonic-gate break; 11910Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_ACTIVE); 11920Sstevel@tonic-gate break; 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate case DEVCTL_BUS_RESET: 11950Sstevel@tonic-gate rv = ENOTSUP; 11960Sstevel@tonic-gate break; 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate case DEVCTL_BUS_RESETALL: 11990Sstevel@tonic-gate rv = ENOTSUP; 12000Sstevel@tonic-gate break; 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate default: 12030Sstevel@tonic-gate rv = ENOTTY; 12040Sstevel@tonic-gate } 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate ndi_dc_freehdl(dcp); 12070Sstevel@tonic-gate return (rv); 12080Sstevel@tonic-gate } 1209