1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/pci.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/ebus.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/open.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 49*7c478bd9Sstevel@tonic-gate uint64_t ebus_debug_flags = 0; 50*7c478bd9Sstevel@tonic-gate #endif 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate /* 53*7c478bd9Sstevel@tonic-gate * The values of the following variables are used to initialize 54*7c478bd9Sstevel@tonic-gate * the cache line size and latency timer registers in the ebus 55*7c478bd9Sstevel@tonic-gate * configuration header. Variables are used instead of constants 56*7c478bd9Sstevel@tonic-gate * to allow tuning from the /etc/system file. 57*7c478bd9Sstevel@tonic-gate */ 58*7c478bd9Sstevel@tonic-gate static uint8_t ebus_cache_line_size = 0x10; /* 64 bytes */ 59*7c478bd9Sstevel@tonic-gate static uint8_t ebus_latency_timer = 0x40; /* 64 PCI cycles */ 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate /* 62*7c478bd9Sstevel@tonic-gate * function prototypes for bus ops routines: 63*7c478bd9Sstevel@tonic-gate */ 64*7c478bd9Sstevel@tonic-gate static int 65*7c478bd9Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 66*7c478bd9Sstevel@tonic-gate off_t offset, off_t len, caddr_t *addrp); 67*7c478bd9Sstevel@tonic-gate static int 68*7c478bd9Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip, 69*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result); 70*7c478bd9Sstevel@tonic-gate static int 71*7c478bd9Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 72*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result); 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* 75*7c478bd9Sstevel@tonic-gate * function prototypes for dev ops routines: 76*7c478bd9Sstevel@tonic-gate */ 77*7c478bd9Sstevel@tonic-gate static int ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 78*7c478bd9Sstevel@tonic-gate static int ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 79*7c478bd9Sstevel@tonic-gate static int ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 80*7c478bd9Sstevel@tonic-gate void *arg, void **result); 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate /* 83*7c478bd9Sstevel@tonic-gate * general function prototypes: 84*7c478bd9Sstevel@tonic-gate */ 85*7c478bd9Sstevel@tonic-gate static int ebus_config(ebus_devstate_t *ebus_p); 86*7c478bd9Sstevel@tonic-gate static int ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 87*7c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp, pci_regspec_t *rp); 88*7c478bd9Sstevel@tonic-gate static int febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 89*7c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp, struct regspec *rp); 90*7c478bd9Sstevel@tonic-gate int get_ranges_prop(ebus_devstate_t *ebus_p); 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate #define getprop(dip, name, addr, intp) \ 93*7c478bd9Sstevel@tonic-gate ddi_getlongprop(DDI_DEV_T_NONE, (dip), DDI_PROP_DONTPASS, \ 94*7c478bd9Sstevel@tonic-gate (name), (caddr_t)(addr), (intp)) 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate static int ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp); 97*7c478bd9Sstevel@tonic-gate static int ebus_close(dev_t dev, int flags, int otyp, cred_t *credp); 98*7c478bd9Sstevel@tonic-gate static int ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 99*7c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp); 100*7c478bd9Sstevel@tonic-gate struct cb_ops ebus_cb_ops = { 101*7c478bd9Sstevel@tonic-gate ebus_open, /* open */ 102*7c478bd9Sstevel@tonic-gate ebus_close, /* close */ 103*7c478bd9Sstevel@tonic-gate nodev, /* strategy */ 104*7c478bd9Sstevel@tonic-gate nodev, /* print */ 105*7c478bd9Sstevel@tonic-gate nodev, /* dump */ 106*7c478bd9Sstevel@tonic-gate nodev, /* read */ 107*7c478bd9Sstevel@tonic-gate nodev, /* write */ 108*7c478bd9Sstevel@tonic-gate ebus_ioctl, /* ioctl */ 109*7c478bd9Sstevel@tonic-gate nodev, /* devmap */ 110*7c478bd9Sstevel@tonic-gate nodev, /* mmap */ 111*7c478bd9Sstevel@tonic-gate nodev, /* segmap */ 112*7c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 113*7c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 114*7c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 115*7c478bd9Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 116*7c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 117*7c478bd9Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 118*7c478bd9Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 119*7c478bd9Sstevel@tonic-gate }; 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate /* 122*7c478bd9Sstevel@tonic-gate * bus ops and dev ops structures: 123*7c478bd9Sstevel@tonic-gate */ 124*7c478bd9Sstevel@tonic-gate static struct bus_ops ebus_bus_ops = { 125*7c478bd9Sstevel@tonic-gate BUSO_REV, 126*7c478bd9Sstevel@tonic-gate ebus_map, 127*7c478bd9Sstevel@tonic-gate NULL, 128*7c478bd9Sstevel@tonic-gate NULL, 129*7c478bd9Sstevel@tonic-gate NULL, 130*7c478bd9Sstevel@tonic-gate i_ddi_map_fault, 131*7c478bd9Sstevel@tonic-gate ddi_dma_map, 132*7c478bd9Sstevel@tonic-gate ddi_dma_allochdl, 133*7c478bd9Sstevel@tonic-gate ddi_dma_freehdl, 134*7c478bd9Sstevel@tonic-gate ddi_dma_bindhdl, 135*7c478bd9Sstevel@tonic-gate ddi_dma_unbindhdl, 136*7c478bd9Sstevel@tonic-gate ddi_dma_flush, 137*7c478bd9Sstevel@tonic-gate ddi_dma_win, 138*7c478bd9Sstevel@tonic-gate ddi_dma_mctl, 139*7c478bd9Sstevel@tonic-gate ebus_ctlops, 140*7c478bd9Sstevel@tonic-gate ddi_bus_prop_op, 141*7c478bd9Sstevel@tonic-gate ndi_busop_get_eventcookie, 142*7c478bd9Sstevel@tonic-gate ndi_busop_add_eventcall, 143*7c478bd9Sstevel@tonic-gate ndi_busop_remove_eventcall, 144*7c478bd9Sstevel@tonic-gate ndi_post_event, 145*7c478bd9Sstevel@tonic-gate 0, 146*7c478bd9Sstevel@tonic-gate 0, 147*7c478bd9Sstevel@tonic-gate 0, 148*7c478bd9Sstevel@tonic-gate 0, 149*7c478bd9Sstevel@tonic-gate 0, 150*7c478bd9Sstevel@tonic-gate 0, 151*7c478bd9Sstevel@tonic-gate 0, 152*7c478bd9Sstevel@tonic-gate 0, 153*7c478bd9Sstevel@tonic-gate ebus_intr_ops 154*7c478bd9Sstevel@tonic-gate }; 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate static struct dev_ops ebus_ops = { 157*7c478bd9Sstevel@tonic-gate DEVO_REV, 158*7c478bd9Sstevel@tonic-gate 0, 159*7c478bd9Sstevel@tonic-gate ebus_info, 160*7c478bd9Sstevel@tonic-gate nulldev, 161*7c478bd9Sstevel@tonic-gate nulldev, 162*7c478bd9Sstevel@tonic-gate ebus_attach, 163*7c478bd9Sstevel@tonic-gate ebus_detach, 164*7c478bd9Sstevel@tonic-gate nodev, 165*7c478bd9Sstevel@tonic-gate &ebus_cb_ops, 166*7c478bd9Sstevel@tonic-gate &ebus_bus_ops 167*7c478bd9Sstevel@tonic-gate }; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate /* 170*7c478bd9Sstevel@tonic-gate * module definitions: 171*7c478bd9Sstevel@tonic-gate */ 172*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 173*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 176*7c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 177*7c478bd9Sstevel@tonic-gate "ebus nexus driver %I%", /* Name of module. */ 178*7c478bd9Sstevel@tonic-gate &ebus_ops, /* driver ops */ 179*7c478bd9Sstevel@tonic-gate }; 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 182*7c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 183*7c478bd9Sstevel@tonic-gate }; 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate /* 186*7c478bd9Sstevel@tonic-gate * driver global data: 187*7c478bd9Sstevel@tonic-gate */ 188*7c478bd9Sstevel@tonic-gate static void *per_ebus_state; /* per-ebus soft state pointer */ 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate int 192*7c478bd9Sstevel@tonic-gate _init(void) 193*7c478bd9Sstevel@tonic-gate { 194*7c478bd9Sstevel@tonic-gate int e; 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* 197*7c478bd9Sstevel@tonic-gate * Initialize per-ebus soft state pointer. 198*7c478bd9Sstevel@tonic-gate */ 199*7c478bd9Sstevel@tonic-gate e = ddi_soft_state_init(&per_ebus_state, sizeof (ebus_devstate_t), 1); 200*7c478bd9Sstevel@tonic-gate if (e != 0) 201*7c478bd9Sstevel@tonic-gate return (e); 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * Install the module. 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate e = mod_install(&modlinkage); 207*7c478bd9Sstevel@tonic-gate if (e != 0) 208*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_ebus_state); 209*7c478bd9Sstevel@tonic-gate return (e); 210*7c478bd9Sstevel@tonic-gate } 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate int 213*7c478bd9Sstevel@tonic-gate _fini(void) 214*7c478bd9Sstevel@tonic-gate { 215*7c478bd9Sstevel@tonic-gate int e; 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* 218*7c478bd9Sstevel@tonic-gate * Remove the module. 219*7c478bd9Sstevel@tonic-gate */ 220*7c478bd9Sstevel@tonic-gate e = mod_remove(&modlinkage); 221*7c478bd9Sstevel@tonic-gate if (e != 0) 222*7c478bd9Sstevel@tonic-gate return (e); 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate /* 225*7c478bd9Sstevel@tonic-gate * Free the soft state info. 226*7c478bd9Sstevel@tonic-gate */ 227*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&per_ebus_state); 228*7c478bd9Sstevel@tonic-gate return (e); 229*7c478bd9Sstevel@tonic-gate } 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate int 232*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 233*7c478bd9Sstevel@tonic-gate { 234*7c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* device driver entry points */ 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 240*7c478bd9Sstevel@tonic-gate static int 241*7c478bd9Sstevel@tonic-gate ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 242*7c478bd9Sstevel@tonic-gate { 243*7c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p; /* per ebus state pointer */ 244*7c478bd9Sstevel@tonic-gate int instance; 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate instance = getminor((dev_t)arg); 247*7c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(instance); 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate switch (infocmd) { 250*7c478bd9Sstevel@tonic-gate default: 251*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 254*7c478bd9Sstevel@tonic-gate *result = (void *)instance; 255*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 258*7c478bd9Sstevel@tonic-gate if (ebus_p == NULL) 259*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 260*7c478bd9Sstevel@tonic-gate *result = (void *)ebus_p->dip; 261*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate /* 266*7c478bd9Sstevel@tonic-gate * attach entry point: 267*7c478bd9Sstevel@tonic-gate * 268*7c478bd9Sstevel@tonic-gate * normal attach: 269*7c478bd9Sstevel@tonic-gate * 270*7c478bd9Sstevel@tonic-gate * create soft state structure (dip, reg, nreg and state fields) 271*7c478bd9Sstevel@tonic-gate * map in configuration header 272*7c478bd9Sstevel@tonic-gate * make sure device is properly configured 273*7c478bd9Sstevel@tonic-gate * report device 274*7c478bd9Sstevel@tonic-gate */ 275*7c478bd9Sstevel@tonic-gate static int 276*7c478bd9Sstevel@tonic-gate ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 277*7c478bd9Sstevel@tonic-gate { 278*7c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p; /* per ebus state pointer */ 279*7c478bd9Sstevel@tonic-gate int instance; 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate DBG1(D_ATTACH, NULL, "dip=%p\n", dip); 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate switch (cmd) { 284*7c478bd9Sstevel@tonic-gate case DDI_ATTACH: 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate /* 287*7c478bd9Sstevel@tonic-gate * Allocate soft state for this instance. 288*7c478bd9Sstevel@tonic-gate */ 289*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 290*7c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(per_ebus_state, instance) 291*7c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 292*7c478bd9Sstevel@tonic-gate DBG(D_ATTACH, NULL, "failed to alloc soft state\n"); 293*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(instance); 296*7c478bd9Sstevel@tonic-gate ebus_p->dip = dip; 297*7c478bd9Sstevel@tonic-gate mutex_init(&ebus_p->ebus_mutex, NULL, MUTEX_DRIVER, NULL); 298*7c478bd9Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED; 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate /* Set ebus type field based on ddi name info */ 301*7c478bd9Sstevel@tonic-gate if (strcmp(ddi_get_name(dip), "jbus-ebus") == 0) { 302*7c478bd9Sstevel@tonic-gate ebus_p->type = FEBUS_TYPE; 303*7c478bd9Sstevel@tonic-gate } else { 304*7c478bd9Sstevel@tonic-gate ebus_p->type = EBUS_TYPE; 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 308*7c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, "no-dma-interrupt-sync", NULL, 0); 309*7c478bd9Sstevel@tonic-gate /* Get our ranges property for mapping child registers. */ 310*7c478bd9Sstevel@tonic-gate if (get_ranges_prop(ebus_p) != DDI_SUCCESS) { 311*7c478bd9Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 312*7c478bd9Sstevel@tonic-gate free_ebus_soft_state(instance); 313*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 314*7c478bd9Sstevel@tonic-gate } 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate /* 317*7c478bd9Sstevel@tonic-gate * create minor node for devctl interfaces 318*7c478bd9Sstevel@tonic-gate */ 319*7c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance, 320*7c478bd9Sstevel@tonic-gate DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 321*7c478bd9Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 322*7c478bd9Sstevel@tonic-gate free_ebus_soft_state(instance); 323*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate /* 326*7c478bd9Sstevel@tonic-gate * Make sure the master enable and memory access enable 327*7c478bd9Sstevel@tonic-gate * bits are set in the config command register. 328*7c478bd9Sstevel@tonic-gate */ 329*7c478bd9Sstevel@tonic-gate if (ebus_p->type == EBUS_TYPE) { 330*7c478bd9Sstevel@tonic-gate if (!ebus_config(ebus_p)) { 331*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, "devctl"); 332*7c478bd9Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 333*7c478bd9Sstevel@tonic-gate free_ebus_soft_state(instance); 334*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 335*7c478bd9Sstevel@tonic-gate } 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate /* 339*7c478bd9Sstevel@tonic-gate * Make the pci_report_pmcap() call only for RIO 340*7c478bd9Sstevel@tonic-gate * implementations. 341*7c478bd9Sstevel@tonic-gate */ 342*7c478bd9Sstevel@tonic-gate if (IS_RIO(dip)) { 343*7c478bd9Sstevel@tonic-gate (void) pci_report_pmcap(dip, PCI_PM_IDLESPEED, 344*7c478bd9Sstevel@tonic-gate (void *)EBUS_4MHZ); 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate /* 348*7c478bd9Sstevel@tonic-gate * Make the state as attached and report the device. 349*7c478bd9Sstevel@tonic-gate */ 350*7c478bd9Sstevel@tonic-gate ebus_p->state = ATTACHED; 351*7c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 352*7c478bd9Sstevel@tonic-gate DBG(D_ATTACH, ebus_p, "returning\n"); 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate case DDI_RESUME: 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 359*7c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(instance); 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate /* 362*7c478bd9Sstevel@tonic-gate * Make sure the master enable and memory access enable 363*7c478bd9Sstevel@tonic-gate * bits are set in the config command register. 364*7c478bd9Sstevel@tonic-gate */ 365*7c478bd9Sstevel@tonic-gate if (ebus_p->type == EBUS_TYPE) { 366*7c478bd9Sstevel@tonic-gate if (!ebus_config(ebus_p)) { 367*7c478bd9Sstevel@tonic-gate free_ebus_soft_state(instance); 368*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate ebus_p->state = RESUMED; 373*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 376*7c478bd9Sstevel@tonic-gate } 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate /* 379*7c478bd9Sstevel@tonic-gate * detach entry point: 380*7c478bd9Sstevel@tonic-gate */ 381*7c478bd9Sstevel@tonic-gate static int 382*7c478bd9Sstevel@tonic-gate ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 383*7c478bd9Sstevel@tonic-gate { 384*7c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 385*7c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(instance); 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate switch (cmd) { 388*7c478bd9Sstevel@tonic-gate case DDI_DETACH: 389*7c478bd9Sstevel@tonic-gate DBG1(D_DETACH, ebus_p, "DDI_DETACH dip=%p\n", dip); 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate switch (ebus_p->type) { 392*7c478bd9Sstevel@tonic-gate case EBUS_TYPE: 393*7c478bd9Sstevel@tonic-gate kmem_free(ebus_p->rangespec.rangep, ebus_p->range_cnt * 394*7c478bd9Sstevel@tonic-gate sizeof (struct ebus_pci_rangespec)); 395*7c478bd9Sstevel@tonic-gate break; 396*7c478bd9Sstevel@tonic-gate case FEBUS_TYPE: 397*7c478bd9Sstevel@tonic-gate kmem_free(ebus_p->rangespec.ferangep, 398*7c478bd9Sstevel@tonic-gate ebus_p->range_cnt * 399*7c478bd9Sstevel@tonic-gate sizeof (struct febus_rangespec)); 400*7c478bd9Sstevel@tonic-gate break; 401*7c478bd9Sstevel@tonic-gate default: 402*7c478bd9Sstevel@tonic-gate DBG(D_ATTACH, NULL, "failed to recognize ebus type\n"); 403*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, "devctl"); 407*7c478bd9Sstevel@tonic-gate mutex_destroy(&ebus_p->ebus_mutex); 408*7c478bd9Sstevel@tonic-gate free_ebus_soft_state(instance); 409*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 412*7c478bd9Sstevel@tonic-gate DBG1(D_DETACH, ebus_p, "DDI_SUSPEND dip=%p\n", dip); 413*7c478bd9Sstevel@tonic-gate ebus_p->state = SUSPENDED; 414*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 415*7c478bd9Sstevel@tonic-gate } 416*7c478bd9Sstevel@tonic-gate DBG(D_ATTACH, NULL, "failed to recognize ebus detach command\n"); 417*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 418*7c478bd9Sstevel@tonic-gate } 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate int 422*7c478bd9Sstevel@tonic-gate get_ranges_prop(ebus_devstate_t *ebus_p) 423*7c478bd9Sstevel@tonic-gate { 424*7c478bd9Sstevel@tonic-gate int nrange, range_len; 425*7c478bd9Sstevel@tonic-gate struct ebus_pci_rangespec *rangep; 426*7c478bd9Sstevel@tonic-gate struct febus_rangespec *ferangep; 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate switch (ebus_p->type) { 429*7c478bd9Sstevel@tonic-gate case EBUS_TYPE: 430*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, 431*7c478bd9Sstevel@tonic-gate ebus_p->dip, DDI_PROP_DONTPASS, 432*7c478bd9Sstevel@tonic-gate "ranges", (caddr_t)&rangep, 433*7c478bd9Sstevel@tonic-gate &range_len) != DDI_SUCCESS) { 434*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Can't get %s ranges property", 435*7c478bd9Sstevel@tonic-gate ddi_get_name(ebus_p->dip)); 436*7c478bd9Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate nrange = range_len / sizeof (struct ebus_pci_rangespec); 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate if (nrange == 0) { 442*7c478bd9Sstevel@tonic-gate kmem_free(rangep, range_len); 443*7c478bd9Sstevel@tonic-gate DBG(D_ATTACH, NULL, "range is equal to zero\n"); 444*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 448*7c478bd9Sstevel@tonic-gate { 449*7c478bd9Sstevel@tonic-gate int i; 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate for (i = 0; i < nrange; i++) { 452*7c478bd9Sstevel@tonic-gate DBG5(D_MAP, ebus_p, 453*7c478bd9Sstevel@tonic-gate "ebus range addr 0x%x.0x%x PCI range " 454*7c478bd9Sstevel@tonic-gate "addr 0x%x.0x%x.0x%x ", 455*7c478bd9Sstevel@tonic-gate rangep[i].ebus_phys_hi, 456*7c478bd9Sstevel@tonic-gate rangep[i].ebus_phys_low, 457*7c478bd9Sstevel@tonic-gate rangep[i].pci_phys_hi, 458*7c478bd9Sstevel@tonic-gate rangep[i].pci_phys_mid, 459*7c478bd9Sstevel@tonic-gate rangep[i].pci_phys_low); 460*7c478bd9Sstevel@tonic-gate DBG1(D_MAP, ebus_p, 461*7c478bd9Sstevel@tonic-gate "Size 0x%x\n", rangep[i].rng_size); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate ebus_p->rangespec.rangep = rangep; 467*7c478bd9Sstevel@tonic-gate ebus_p->range_cnt = nrange; 468*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate case FEBUS_TYPE: 471*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, ebus_p->dip, 472*7c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "ranges", 473*7c478bd9Sstevel@tonic-gate (caddr_t)&ferangep, &range_len) != DDI_SUCCESS) { 474*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Can't get %s ranges property", 475*7c478bd9Sstevel@tonic-gate ddi_get_name(ebus_p->dip)); 476*7c478bd9Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 477*7c478bd9Sstevel@tonic-gate } 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate nrange = range_len / sizeof (struct febus_rangespec); 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate if (nrange == 0) { 482*7c478bd9Sstevel@tonic-gate kmem_free(ferangep, range_len); 483*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 487*7c478bd9Sstevel@tonic-gate { 488*7c478bd9Sstevel@tonic-gate int i; 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate for (i = 0; i < nrange; i++) { 491*7c478bd9Sstevel@tonic-gate DBG4(D_MAP, ebus_p, 492*7c478bd9Sstevel@tonic-gate "ebus range addr 0x%x.0x%x" 493*7c478bd9Sstevel@tonic-gate " Parent range " 494*7c478bd9Sstevel@tonic-gate "addr 0x%x.0x%x ", 495*7c478bd9Sstevel@tonic-gate ferangep[i].febus_phys_hi, 496*7c478bd9Sstevel@tonic-gate ferangep[i].febus_phys_low, 497*7c478bd9Sstevel@tonic-gate ferangep[i].parent_phys_hi, 498*7c478bd9Sstevel@tonic-gate ferangep[i].parent_phys_low); 499*7c478bd9Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "Size 0x%x\n", 500*7c478bd9Sstevel@tonic-gate ferangep[i].rng_size); 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate } 503*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 504*7c478bd9Sstevel@tonic-gate ebus_p->rangespec.ferangep = ferangep; 505*7c478bd9Sstevel@tonic-gate ebus_p->range_cnt = nrange; 506*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate default: 509*7c478bd9Sstevel@tonic-gate DBG(D_MAP, NULL, "failed to recognize ebus type\n"); 510*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate /* bus driver entry points */ 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate /* 517*7c478bd9Sstevel@tonic-gate * bus map entry point: 518*7c478bd9Sstevel@tonic-gate * 519*7c478bd9Sstevel@tonic-gate * if map request is for an rnumber 520*7c478bd9Sstevel@tonic-gate * get the corresponding regspec from device node 521*7c478bd9Sstevel@tonic-gate * build a new regspec in our parent's format 522*7c478bd9Sstevel@tonic-gate * build a new map_req with the new regspec 523*7c478bd9Sstevel@tonic-gate * call up the tree to complete the mapping 524*7c478bd9Sstevel@tonic-gate */ 525*7c478bd9Sstevel@tonic-gate static int 526*7c478bd9Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 527*7c478bd9Sstevel@tonic-gate off_t off, off_t len, caddr_t *addrp) 528*7c478bd9Sstevel@tonic-gate { 529*7c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip)); 530*7c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp, *ebus_regs; 531*7c478bd9Sstevel@tonic-gate struct regspec reg; 532*7c478bd9Sstevel@tonic-gate pci_regspec_t pci_reg; 533*7c478bd9Sstevel@tonic-gate ddi_map_req_t p_map_request; 534*7c478bd9Sstevel@tonic-gate int rnumber, i, n; 535*7c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate /* 538*7c478bd9Sstevel@tonic-gate * Handle the mapping according to its type. 539*7c478bd9Sstevel@tonic-gate */ 540*7c478bd9Sstevel@tonic-gate DBG4(D_MAP, ebus_p, "rdip=%s%d: off=%x len=%x\n", 541*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), off, len); 542*7c478bd9Sstevel@tonic-gate switch (mp->map_type) { 543*7c478bd9Sstevel@tonic-gate case DDI_MT_REGSPEC: 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate * We assume the register specification is in ebus format. 547*7c478bd9Sstevel@tonic-gate * We must convert it into a PCI format regspec and pass 548*7c478bd9Sstevel@tonic-gate * the request to our parent. 549*7c478bd9Sstevel@tonic-gate */ 550*7c478bd9Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "rdip=%s%d: REGSPEC - handlep=%p\n", 551*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 552*7c478bd9Sstevel@tonic-gate mp->map_handlep); 553*7c478bd9Sstevel@tonic-gate ebus_rp = (ebus_regspec_t *)mp->map_obj.rp; 554*7c478bd9Sstevel@tonic-gate break; 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate case DDI_MT_RNUMBER: 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate /* 559*7c478bd9Sstevel@tonic-gate * Get the "reg" property from the device node and convert 560*7c478bd9Sstevel@tonic-gate * it to our parent's format. 561*7c478bd9Sstevel@tonic-gate */ 562*7c478bd9Sstevel@tonic-gate rnumber = mp->map_obj.rnumber; 563*7c478bd9Sstevel@tonic-gate DBG4(D_MAP, ebus_p, "rdip=%s%d: rnumber=%x handlep=%p\n", 564*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip), 565*7c478bd9Sstevel@tonic-gate rnumber, mp->map_handlep); 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate if (getprop(rdip, "reg", &ebus_regs, &i) != DDI_SUCCESS) { 568*7c478bd9Sstevel@tonic-gate DBG(D_MAP, ebus_p, "can't get reg property\n"); 569*7c478bd9Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 570*7c478bd9Sstevel@tonic-gate } 571*7c478bd9Sstevel@tonic-gate n = i / sizeof (ebus_regspec_t); 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate if (rnumber < 0 || rnumber >= n) { 574*7c478bd9Sstevel@tonic-gate DBG(D_MAP, ebus_p, "rnumber out of range\n"); 575*7c478bd9Sstevel@tonic-gate return (DDI_ME_RNUMBER_RANGE); 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate ebus_rp = &ebus_regs[rnumber]; 578*7c478bd9Sstevel@tonic-gate break; 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate default: 581*7c478bd9Sstevel@tonic-gate return (DDI_ME_INVAL); 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate /* Adjust our reg property with offset and length */ 586*7c478bd9Sstevel@tonic-gate ebus_rp->addr_low += off; 587*7c478bd9Sstevel@tonic-gate if (len) 588*7c478bd9Sstevel@tonic-gate ebus_rp->size = len; 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate /* 591*7c478bd9Sstevel@tonic-gate * Now we have a copy the "reg" entry we're attempting to map. 592*7c478bd9Sstevel@tonic-gate * Translate this into our parents PCI address using the ranges 593*7c478bd9Sstevel@tonic-gate * property. 594*7c478bd9Sstevel@tonic-gate */ 595*7c478bd9Sstevel@tonic-gate switch (ebus_p->type) { 596*7c478bd9Sstevel@tonic-gate case EBUS_TYPE: 597*7c478bd9Sstevel@tonic-gate rval = ebus_apply_range(ebus_p, rdip, ebus_rp, &pci_reg); 598*7c478bd9Sstevel@tonic-gate break; 599*7c478bd9Sstevel@tonic-gate case FEBUS_TYPE: 600*7c478bd9Sstevel@tonic-gate rval = febus_apply_range(ebus_p, rdip, ebus_rp, ®); 601*7c478bd9Sstevel@tonic-gate break; 602*7c478bd9Sstevel@tonic-gate default: 603*7c478bd9Sstevel@tonic-gate DBG(D_MAP, NULL, "failed to recognize ebus type\n"); 604*7c478bd9Sstevel@tonic-gate rval = DDI_FAILURE; 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate if (mp->map_type == DDI_MT_RNUMBER) 608*7c478bd9Sstevel@tonic-gate kmem_free(ebus_regs, i); 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) 611*7c478bd9Sstevel@tonic-gate return (rval); 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 614*7c478bd9Sstevel@tonic-gate switch (ebus_p->type) { 615*7c478bd9Sstevel@tonic-gate case EBUS_TYPE: 616*7c478bd9Sstevel@tonic-gate DBG5(D_MAP, ebus_p, "(%x,%x,%x)(%x,%x)\n", 617*7c478bd9Sstevel@tonic-gate pci_reg.pci_phys_hi, 618*7c478bd9Sstevel@tonic-gate pci_reg.pci_phys_mid, 619*7c478bd9Sstevel@tonic-gate pci_reg.pci_phys_low, 620*7c478bd9Sstevel@tonic-gate pci_reg.pci_size_hi, 621*7c478bd9Sstevel@tonic-gate pci_reg.pci_size_low); 622*7c478bd9Sstevel@tonic-gate break; 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate case FEBUS_TYPE: 625*7c478bd9Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "%x,%x,%x\n", 626*7c478bd9Sstevel@tonic-gate reg.regspec_bustype, 627*7c478bd9Sstevel@tonic-gate reg.regspec_addr, 628*7c478bd9Sstevel@tonic-gate reg.regspec_size); 629*7c478bd9Sstevel@tonic-gate break; 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate #endif 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate p_map_request = *mp; 634*7c478bd9Sstevel@tonic-gate p_map_request.map_type = DDI_MT_REGSPEC; 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate switch (ebus_p->type) { 637*7c478bd9Sstevel@tonic-gate case EBUS_TYPE: 638*7c478bd9Sstevel@tonic-gate p_map_request.map_obj.rp = (struct regspec *)&pci_reg; 639*7c478bd9Sstevel@tonic-gate break; 640*7c478bd9Sstevel@tonic-gate case FEBUS_TYPE: 641*7c478bd9Sstevel@tonic-gate p_map_request.map_obj.rp = ® 642*7c478bd9Sstevel@tonic-gate break; 643*7c478bd9Sstevel@tonic-gate default: 644*7c478bd9Sstevel@tonic-gate DBG(D_MAP, NULL, "failed to recognize ebus type\n"); 645*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate rval = ddi_map(dip, &p_map_request, 0, 0, addrp); 649*7c478bd9Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "parent returned %x\n", rval); 650*7c478bd9Sstevel@tonic-gate return (rval); 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate 654*7c478bd9Sstevel@tonic-gate static int 655*7c478bd9Sstevel@tonic-gate ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 656*7c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp, pci_regspec_t *rp) 657*7c478bd9Sstevel@tonic-gate { 658*7c478bd9Sstevel@tonic-gate int b; 659*7c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 660*7c478bd9Sstevel@tonic-gate struct ebus_pci_rangespec *rangep = ebus_p->rangespec.rangep; 661*7c478bd9Sstevel@tonic-gate int nrange = ebus_p->range_cnt; 662*7c478bd9Sstevel@tonic-gate static char out_of_range[] = 663*7c478bd9Sstevel@tonic-gate "Out of range register specification from device node <%s>"; 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n", 666*7c478bd9Sstevel@tonic-gate ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size); 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate for (b = 0; b < nrange; ++b, ++rangep) { 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate /* Check for the correct space */ 671*7c478bd9Sstevel@tonic-gate if (ebus_rp->addr_hi == rangep->ebus_phys_hi) 672*7c478bd9Sstevel@tonic-gate /* See if we fit in this range */ 673*7c478bd9Sstevel@tonic-gate if ((ebus_rp->addr_low >= 674*7c478bd9Sstevel@tonic-gate rangep->ebus_phys_low) && 675*7c478bd9Sstevel@tonic-gate ((ebus_rp->addr_low + ebus_rp->size - 1) 676*7c478bd9Sstevel@tonic-gate <= (rangep->ebus_phys_low + 677*7c478bd9Sstevel@tonic-gate rangep->rng_size - 1))) { 678*7c478bd9Sstevel@tonic-gate uint_t addr_offset = ebus_rp->addr_low - 679*7c478bd9Sstevel@tonic-gate rangep->ebus_phys_low; 680*7c478bd9Sstevel@tonic-gate /* 681*7c478bd9Sstevel@tonic-gate * Use the range entry to translate 682*7c478bd9Sstevel@tonic-gate * the EBUS physical address into the 683*7c478bd9Sstevel@tonic-gate * parents PCI space. 684*7c478bd9Sstevel@tonic-gate */ 685*7c478bd9Sstevel@tonic-gate rp->pci_phys_hi = 686*7c478bd9Sstevel@tonic-gate rangep->pci_phys_hi; 687*7c478bd9Sstevel@tonic-gate rp->pci_phys_mid = rangep->pci_phys_mid; 688*7c478bd9Sstevel@tonic-gate rp->pci_phys_low = 689*7c478bd9Sstevel@tonic-gate rangep->pci_phys_low + addr_offset; 690*7c478bd9Sstevel@tonic-gate rp->pci_size_hi = 0; 691*7c478bd9Sstevel@tonic-gate rp->pci_size_low = 692*7c478bd9Sstevel@tonic-gate min(ebus_rp->size, (rangep->rng_size - 693*7c478bd9Sstevel@tonic-gate addr_offset)); 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ", 696*7c478bd9Sstevel@tonic-gate rangep->ebus_phys_hi, 697*7c478bd9Sstevel@tonic-gate rangep->ebus_phys_low); 698*7c478bd9Sstevel@tonic-gate DBG4(D_MAP, ebus_p, "Parent hi0x%x " 699*7c478bd9Sstevel@tonic-gate "mid0x%x lo0x%x size 0x%x\n", 700*7c478bd9Sstevel@tonic-gate rangep->pci_phys_hi, 701*7c478bd9Sstevel@tonic-gate rangep->pci_phys_mid, 702*7c478bd9Sstevel@tonic-gate rangep->pci_phys_low, 703*7c478bd9Sstevel@tonic-gate rangep->rng_size); 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate break; 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate } 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate if (b == nrange) { 710*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip)); 711*7c478bd9Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate return (rval); 715*7c478bd9Sstevel@tonic-gate } 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate static int 718*7c478bd9Sstevel@tonic-gate febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip, 719*7c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp, struct regspec *rp) { 720*7c478bd9Sstevel@tonic-gate int b; 721*7c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 722*7c478bd9Sstevel@tonic-gate struct febus_rangespec *rangep = ebus_p->rangespec.ferangep; 723*7c478bd9Sstevel@tonic-gate int nrange = ebus_p->range_cnt; 724*7c478bd9Sstevel@tonic-gate static char out_of_range[] = 725*7c478bd9Sstevel@tonic-gate "Out of range register specification from device node <%s>"; 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n", 728*7c478bd9Sstevel@tonic-gate ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate for (b = 0; b < nrange; ++b, ++rangep) { 731*7c478bd9Sstevel@tonic-gate /* Check for the correct space */ 732*7c478bd9Sstevel@tonic-gate if (ebus_rp->addr_hi == rangep->febus_phys_hi) 733*7c478bd9Sstevel@tonic-gate /* See if we fit in this range */ 734*7c478bd9Sstevel@tonic-gate if ((ebus_rp->addr_low >= 735*7c478bd9Sstevel@tonic-gate rangep->febus_phys_low) && 736*7c478bd9Sstevel@tonic-gate ((ebus_rp->addr_low + ebus_rp->size - 1) 737*7c478bd9Sstevel@tonic-gate <= (rangep->febus_phys_low + 738*7c478bd9Sstevel@tonic-gate rangep->rng_size - 1))) { 739*7c478bd9Sstevel@tonic-gate uint_t addr_offset = ebus_rp->addr_low - 740*7c478bd9Sstevel@tonic-gate rangep->febus_phys_low; 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate /* 743*7c478bd9Sstevel@tonic-gate * Use the range entry to translate 744*7c478bd9Sstevel@tonic-gate * the FEBUS physical address into the 745*7c478bd9Sstevel@tonic-gate * parents space. 746*7c478bd9Sstevel@tonic-gate */ 747*7c478bd9Sstevel@tonic-gate rp->regspec_bustype = 748*7c478bd9Sstevel@tonic-gate rangep->parent_phys_hi; 749*7c478bd9Sstevel@tonic-gate rp->regspec_addr = 750*7c478bd9Sstevel@tonic-gate rangep->parent_phys_low + addr_offset; 751*7c478bd9Sstevel@tonic-gate rp->regspec_size = 752*7c478bd9Sstevel@tonic-gate min(ebus_rp->size, (rangep->rng_size - 753*7c478bd9Sstevel@tonic-gate addr_offset)); 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ", 756*7c478bd9Sstevel@tonic-gate rangep->febus_phys_hi, 757*7c478bd9Sstevel@tonic-gate rangep->febus_phys_low); 758*7c478bd9Sstevel@tonic-gate DBG3(D_MAP, ebus_p, "Parent hi0x%x " 759*7c478bd9Sstevel@tonic-gate "lo0x%x size 0x%x\n", 760*7c478bd9Sstevel@tonic-gate rangep->parent_phys_hi, 761*7c478bd9Sstevel@tonic-gate rangep->parent_phys_low, 762*7c478bd9Sstevel@tonic-gate rangep->rng_size); 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate break; 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate } 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate if (b == nrange) { 769*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip)); 770*7c478bd9Sstevel@tonic-gate return (DDI_ME_REGSPEC_RANGE); 771*7c478bd9Sstevel@tonic-gate } 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate return (rval); 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate 776*7c478bd9Sstevel@tonic-gate 777*7c478bd9Sstevel@tonic-gate static int 778*7c478bd9Sstevel@tonic-gate ebus_name_child(dev_info_t *child, char *name, int namelen) 779*7c478bd9Sstevel@tonic-gate { 780*7c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp; 781*7c478bd9Sstevel@tonic-gate int reglen; 782*7c478bd9Sstevel@tonic-gate 783*7c478bd9Sstevel@tonic-gate /* 784*7c478bd9Sstevel@tonic-gate * Get the address portion of the node name based on the 785*7c478bd9Sstevel@tonic-gate * address/offset. 786*7c478bd9Sstevel@tonic-gate */ 787*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS, 788*7c478bd9Sstevel@tonic-gate "reg", (caddr_t)&ebus_rp, ®len) != DDI_SUCCESS) { 789*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 790*7c478bd9Sstevel@tonic-gate } 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", ebus_rp->addr_hi, 793*7c478bd9Sstevel@tonic-gate ebus_rp->addr_low); 794*7c478bd9Sstevel@tonic-gate kmem_free(ebus_rp, reglen); 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 797*7c478bd9Sstevel@tonic-gate } 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate /* 800*7c478bd9Sstevel@tonic-gate * control ops entry point: 801*7c478bd9Sstevel@tonic-gate * 802*7c478bd9Sstevel@tonic-gate * Requests handled completely: 803*7c478bd9Sstevel@tonic-gate * DDI_CTLOPS_INITCHILD 804*7c478bd9Sstevel@tonic-gate * DDI_CTLOPS_UNINITCHILD 805*7c478bd9Sstevel@tonic-gate * DDI_CTLOPS_REPORTDEV 806*7c478bd9Sstevel@tonic-gate * DDI_CTLOPS_REGSIZE 807*7c478bd9Sstevel@tonic-gate * DDI_CTLOPS_NREGS 808*7c478bd9Sstevel@tonic-gate * 809*7c478bd9Sstevel@tonic-gate * All others passed to parent. 810*7c478bd9Sstevel@tonic-gate */ 811*7c478bd9Sstevel@tonic-gate static int 812*7c478bd9Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip, 813*7c478bd9Sstevel@tonic-gate ddi_ctl_enum_t op, void *arg, void *result) 814*7c478bd9Sstevel@tonic-gate { 815*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 816*7c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip)); 817*7c478bd9Sstevel@tonic-gate #endif 818*7c478bd9Sstevel@tonic-gate ebus_regspec_t *ebus_rp; 819*7c478bd9Sstevel@tonic-gate int i, n; 820*7c478bd9Sstevel@tonic-gate char name[10]; 821*7c478bd9Sstevel@tonic-gate 822*7c478bd9Sstevel@tonic-gate switch (op) { 823*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: { 824*7c478bd9Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg; 825*7c478bd9Sstevel@tonic-gate /* 826*7c478bd9Sstevel@tonic-gate * Set the address portion of the node name based on the 827*7c478bd9Sstevel@tonic-gate * address/offset. 828*7c478bd9Sstevel@tonic-gate */ 829*7c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n", 830*7c478bd9Sstevel@tonic-gate ddi_get_name(child), ddi_get_instance(child)); 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate if (ebus_name_child(child, name, 10) != DDI_SUCCESS) { 833*7c478bd9Sstevel@tonic-gate DBG(D_CTLOPS, ebus_p, "can't name child\n"); 834*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, name); 838*7c478bd9Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 839*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 843*7c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n", 844*7c478bd9Sstevel@tonic-gate ddi_get_name((dev_info_t *)arg), 845*7c478bd9Sstevel@tonic-gate ddi_get_instance((dev_info_t *)arg)); 846*7c478bd9Sstevel@tonic-gate ddi_set_name_addr((dev_info_t *)arg, NULL); 847*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node((dev_info_t *)arg, NULL); 848*7c478bd9Sstevel@tonic-gate impl_rem_dev_props((dev_info_t *)arg); 849*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n", 854*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 855*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n", 856*7c478bd9Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), 857*7c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), 858*7c478bd9Sstevel@tonic-gate ddi_get_name_addr(rdip)); 859*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n", 864*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 865*7c478bd9Sstevel@tonic-gate if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) { 866*7c478bd9Sstevel@tonic-gate DBG(D_CTLOPS, ebus_p, "can't get reg property\n"); 867*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 868*7c478bd9Sstevel@tonic-gate } 869*7c478bd9Sstevel@tonic-gate n = i / sizeof (ebus_regspec_t); 870*7c478bd9Sstevel@tonic-gate if (*(int *)arg < 0 || *(int *)arg >= n) { 871*7c478bd9Sstevel@tonic-gate DBG(D_MAP, ebus_p, "rnumber out of range\n"); 872*7c478bd9Sstevel@tonic-gate kmem_free(ebus_rp, i); 873*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 874*7c478bd9Sstevel@tonic-gate } 875*7c478bd9Sstevel@tonic-gate *((off_t *)result) = ebus_rp[*(int *)arg].size; 876*7c478bd9Sstevel@tonic-gate kmem_free(ebus_rp, i); 877*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 880*7c478bd9Sstevel@tonic-gate 881*7c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_NREGS: rdip=%s%d\n", 882*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 883*7c478bd9Sstevel@tonic-gate if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) { 884*7c478bd9Sstevel@tonic-gate DBG(D_CTLOPS, ebus_p, "can't get reg property\n"); 885*7c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 886*7c478bd9Sstevel@tonic-gate } 887*7c478bd9Sstevel@tonic-gate *((uint_t *)result) = i / sizeof (ebus_regspec_t); 888*7c478bd9Sstevel@tonic-gate kmem_free(ebus_rp, i); 889*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 890*7c478bd9Sstevel@tonic-gate } 891*7c478bd9Sstevel@tonic-gate 892*7c478bd9Sstevel@tonic-gate /* 893*7c478bd9Sstevel@tonic-gate * Now pass the request up to our parent. 894*7c478bd9Sstevel@tonic-gate */ 895*7c478bd9Sstevel@tonic-gate DBG2(D_CTLOPS, ebus_p, "passing request to parent: rdip=%s%d\n", 896*7c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 897*7c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, op, arg, result)); 898*7c478bd9Sstevel@tonic-gate } 899*7c478bd9Sstevel@tonic-gate 900*7c478bd9Sstevel@tonic-gate struct ebus_string_to_pil { 901*7c478bd9Sstevel@tonic-gate int8_t *string; 902*7c478bd9Sstevel@tonic-gate uint32_t pil; 903*7c478bd9Sstevel@tonic-gate }; 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate static struct ebus_string_to_pil ebus_name_to_pil[] = {{"SUNW,CS4231", 9}, 906*7c478bd9Sstevel@tonic-gate {"audio", 9}, 907*7c478bd9Sstevel@tonic-gate {"fdthree", 8}, 908*7c478bd9Sstevel@tonic-gate {"floppy", 8}, 909*7c478bd9Sstevel@tonic-gate {"ecpp", 3}, 910*7c478bd9Sstevel@tonic-gate {"parallel", 3}, 911*7c478bd9Sstevel@tonic-gate {"su", 12}, 912*7c478bd9Sstevel@tonic-gate {"se", 12}, 913*7c478bd9Sstevel@tonic-gate {"serial", 12}, 914*7c478bd9Sstevel@tonic-gate {"power", 14}}; 915*7c478bd9Sstevel@tonic-gate 916*7c478bd9Sstevel@tonic-gate static struct ebus_string_to_pil ebus_device_type_to_pil[] = {{"serial", 12}, 917*7c478bd9Sstevel@tonic-gate {"block", 8}}; 918*7c478bd9Sstevel@tonic-gate 919*7c478bd9Sstevel@tonic-gate static int 920*7c478bd9Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 921*7c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 922*7c478bd9Sstevel@tonic-gate { 923*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 924*7c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip)); 925*7c478bd9Sstevel@tonic-gate #endif 926*7c478bd9Sstevel@tonic-gate ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private; 927*7c478bd9Sstevel@tonic-gate int32_t i, max_children, max_device_types, len; 928*7c478bd9Sstevel@tonic-gate char *name_p, *device_type_p; 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate DBG1(D_INTR, ebus_p, "ip 0x%p\n", ip); 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate /* 933*7c478bd9Sstevel@tonic-gate * NOTE: These ops below will never be supported in this nexus 934*7c478bd9Sstevel@tonic-gate * driver, hence they always return immediately. 935*7c478bd9Sstevel@tonic-gate */ 936*7c478bd9Sstevel@tonic-gate switch (intr_op) { 937*7c478bd9Sstevel@tonic-gate case DDI_INTROP_GETCAP: 938*7c478bd9Sstevel@tonic-gate *(int *)result = 0; 939*7c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 940*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SETCAP: 941*7c478bd9Sstevel@tonic-gate case DDI_INTROP_SETMASK: 942*7c478bd9Sstevel@tonic-gate case DDI_INTROP_CLRMASK: 943*7c478bd9Sstevel@tonic-gate case DDI_INTROP_GETPENDING: 944*7c478bd9Sstevel@tonic-gate return (DDI_ENOTSUP); 945*7c478bd9Sstevel@tonic-gate default: 946*7c478bd9Sstevel@tonic-gate break; 947*7c478bd9Sstevel@tonic-gate } 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) || ip->is_pil) 950*7c478bd9Sstevel@tonic-gate goto done; 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate /* 953*7c478bd9Sstevel@tonic-gate * This is a hack to set the PIL for the devices under ebus. 954*7c478bd9Sstevel@tonic-gate * We first look up a device by it's specific name, if we can't 955*7c478bd9Sstevel@tonic-gate * match the name, we try and match it's device_type property. 956*7c478bd9Sstevel@tonic-gate * Lastly we default a PIL level of 1. 957*7c478bd9Sstevel@tonic-gate */ 958*7c478bd9Sstevel@tonic-gate name_p = ddi_node_name(rdip); 959*7c478bd9Sstevel@tonic-gate max_children = sizeof (ebus_name_to_pil) / 960*7c478bd9Sstevel@tonic-gate sizeof (struct ebus_string_to_pil); 961*7c478bd9Sstevel@tonic-gate 962*7c478bd9Sstevel@tonic-gate for (i = 0; i < max_children; i++) { 963*7c478bd9Sstevel@tonic-gate if (strcmp(ebus_name_to_pil[i].string, name_p) == 0) { 964*7c478bd9Sstevel@tonic-gate DBG2(D_INTR, ebus_p, "child name %s; match PIL %d\n", 965*7c478bd9Sstevel@tonic-gate ebus_name_to_pil[i].string, 966*7c478bd9Sstevel@tonic-gate ebus_name_to_pil[i].pil); 967*7c478bd9Sstevel@tonic-gate 968*7c478bd9Sstevel@tonic-gate ip->is_pil = ebus_name_to_pil[i].pil; 969*7c478bd9Sstevel@tonic-gate goto done; 970*7c478bd9Sstevel@tonic-gate } 971*7c478bd9Sstevel@tonic-gate } 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS, 974*7c478bd9Sstevel@tonic-gate "device_type", (caddr_t)&device_type_p, &len) == DDI_SUCCESS) { 975*7c478bd9Sstevel@tonic-gate 976*7c478bd9Sstevel@tonic-gate max_device_types = sizeof (ebus_device_type_to_pil) / 977*7c478bd9Sstevel@tonic-gate sizeof (struct ebus_string_to_pil); 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate for (i = 0; i < max_device_types; i++) { 980*7c478bd9Sstevel@tonic-gate if (strcmp(ebus_device_type_to_pil[i].string, 981*7c478bd9Sstevel@tonic-gate device_type_p) == 0) { 982*7c478bd9Sstevel@tonic-gate DBG2(D_INTR, ebus_p, "Device type %s; match " 983*7c478bd9Sstevel@tonic-gate "PIL %d\n", ebus_device_type_to_pil[i]. 984*7c478bd9Sstevel@tonic-gate string, ebus_device_type_to_pil[i].pil); 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate ip->is_pil = ebus_device_type_to_pil[i].pil; 987*7c478bd9Sstevel@tonic-gate break; 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate } 990*7c478bd9Sstevel@tonic-gate 991*7c478bd9Sstevel@tonic-gate kmem_free(device_type_p, len); 992*7c478bd9Sstevel@tonic-gate } 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate /* 995*7c478bd9Sstevel@tonic-gate * If we get here, we need to set a default value 996*7c478bd9Sstevel@tonic-gate * for the PIL. 997*7c478bd9Sstevel@tonic-gate */ 998*7c478bd9Sstevel@tonic-gate if (ip->is_pil == 0) { 999*7c478bd9Sstevel@tonic-gate ip->is_pil = 1; 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d assigning default interrupt level %d " 1002*7c478bd9Sstevel@tonic-gate "for device %s%d", ddi_get_name(dip), ddi_get_instance(dip), 1003*7c478bd9Sstevel@tonic-gate ip->is_pil, ddi_get_name(rdip), ddi_get_instance(rdip)); 1004*7c478bd9Sstevel@tonic-gate } 1005*7c478bd9Sstevel@tonic-gate 1006*7c478bd9Sstevel@tonic-gate done: 1007*7c478bd9Sstevel@tonic-gate /* Pass up the request to our parent. */ 1008*7c478bd9Sstevel@tonic-gate return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result)); 1009*7c478bd9Sstevel@tonic-gate } 1010*7c478bd9Sstevel@tonic-gate 1011*7c478bd9Sstevel@tonic-gate 1012*7c478bd9Sstevel@tonic-gate static int 1013*7c478bd9Sstevel@tonic-gate ebus_config(ebus_devstate_t *ebus_p) 1014*7c478bd9Sstevel@tonic-gate { 1015*7c478bd9Sstevel@tonic-gate ddi_acc_handle_t conf_handle; 1016*7c478bd9Sstevel@tonic-gate uint16_t comm; 1017*7c478bd9Sstevel@tonic-gate 1018*7c478bd9Sstevel@tonic-gate /* 1019*7c478bd9Sstevel@tonic-gate * Make sure the master enable and memory access enable 1020*7c478bd9Sstevel@tonic-gate * bits are set in the config command register. 1021*7c478bd9Sstevel@tonic-gate */ 1022*7c478bd9Sstevel@tonic-gate if (pci_config_setup(ebus_p->dip, &conf_handle) != DDI_SUCCESS) 1023*7c478bd9Sstevel@tonic-gate return (0); 1024*7c478bd9Sstevel@tonic-gate 1025*7c478bd9Sstevel@tonic-gate comm = pci_config_get16(conf_handle, PCI_CONF_COMM), 1026*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1027*7c478bd9Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "command register was 0x%x\n", comm); 1028*7c478bd9Sstevel@tonic-gate #endif 1029*7c478bd9Sstevel@tonic-gate comm |= (PCI_COMM_ME|PCI_COMM_MAE|PCI_COMM_SERR_ENABLE| 1030*7c478bd9Sstevel@tonic-gate PCI_COMM_PARITY_DETECT); 1031*7c478bd9Sstevel@tonic-gate pci_config_put16(conf_handle, PCI_CONF_COMM, comm), 1032*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1033*7c478bd9Sstevel@tonic-gate DBG1(D_MAP, ebus_p, "command register is now 0x%x\n", comm); 1034*7c478bd9Sstevel@tonic-gate #endif 1035*7c478bd9Sstevel@tonic-gate pci_config_put8(conf_handle, PCI_CONF_CACHE_LINESZ, 1036*7c478bd9Sstevel@tonic-gate (uchar_t)ebus_cache_line_size); 1037*7c478bd9Sstevel@tonic-gate pci_config_put8(conf_handle, PCI_CONF_LATENCY_TIMER, 1038*7c478bd9Sstevel@tonic-gate (uchar_t)ebus_latency_timer); 1039*7c478bd9Sstevel@tonic-gate pci_config_teardown(&conf_handle); 1040*7c478bd9Sstevel@tonic-gate return (1); 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1044*7c478bd9Sstevel@tonic-gate extern void prom_printf(const char *, ...); 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate static void 1047*7c478bd9Sstevel@tonic-gate ebus_debug(uint_t flag, ebus_devstate_t *ebus_p, char *fmt, 1048*7c478bd9Sstevel@tonic-gate uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5) 1049*7c478bd9Sstevel@tonic-gate { 1050*7c478bd9Sstevel@tonic-gate char *s; 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate if (ebus_debug_flags & flag) { 1053*7c478bd9Sstevel@tonic-gate switch (flag) { 1054*7c478bd9Sstevel@tonic-gate case D_ATTACH: 1055*7c478bd9Sstevel@tonic-gate s = "attach"; break; 1056*7c478bd9Sstevel@tonic-gate case D_DETACH: 1057*7c478bd9Sstevel@tonic-gate s = "detach"; break; 1058*7c478bd9Sstevel@tonic-gate case D_MAP: 1059*7c478bd9Sstevel@tonic-gate s = "map"; break; 1060*7c478bd9Sstevel@tonic-gate case D_CTLOPS: 1061*7c478bd9Sstevel@tonic-gate s = "ctlops"; break; 1062*7c478bd9Sstevel@tonic-gate case D_INTR: 1063*7c478bd9Sstevel@tonic-gate s = "intr"; break; 1064*7c478bd9Sstevel@tonic-gate } 1065*7c478bd9Sstevel@tonic-gate if (ebus_p) 1066*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: %s: ", 1067*7c478bd9Sstevel@tonic-gate ddi_get_name(ebus_p->dip), 1068*7c478bd9Sstevel@tonic-gate ddi_get_instance(ebus_p->dip), s); 1069*7c478bd9Sstevel@tonic-gate else 1070*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "ebus: "); 1071*7c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5); 1072*7c478bd9Sstevel@tonic-gate } 1073*7c478bd9Sstevel@tonic-gate } 1074*7c478bd9Sstevel@tonic-gate #endif 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate /* ARGSUSED3 */ 1077*7c478bd9Sstevel@tonic-gate static int 1078*7c478bd9Sstevel@tonic-gate ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1079*7c478bd9Sstevel@tonic-gate { 1080*7c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p; 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate /* 1083*7c478bd9Sstevel@tonic-gate * Make sure the open is for the right file type. 1084*7c478bd9Sstevel@tonic-gate */ 1085*7c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 1086*7c478bd9Sstevel@tonic-gate return (EINVAL); 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate /* 1089*7c478bd9Sstevel@tonic-gate * Get the soft state structure for the device. 1090*7c478bd9Sstevel@tonic-gate */ 1091*7c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(getminor(*devp)); 1092*7c478bd9Sstevel@tonic-gate if (ebus_p == NULL) 1093*7c478bd9Sstevel@tonic-gate return (ENXIO); 1094*7c478bd9Sstevel@tonic-gate 1095*7c478bd9Sstevel@tonic-gate /* 1096*7c478bd9Sstevel@tonic-gate * Handle the open by tracking the device state. 1097*7c478bd9Sstevel@tonic-gate */ 1098*7c478bd9Sstevel@tonic-gate mutex_enter(&ebus_p->ebus_mutex); 1099*7c478bd9Sstevel@tonic-gate if (flags & FEXCL) { 1100*7c478bd9Sstevel@tonic-gate if (ebus_p->ebus_soft_state != EBUS_SOFT_STATE_CLOSED) { 1101*7c478bd9Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 1102*7c478bd9Sstevel@tonic-gate return (EBUSY); 1103*7c478bd9Sstevel@tonic-gate } 1104*7c478bd9Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN_EXCL; 1105*7c478bd9Sstevel@tonic-gate } else { 1106*7c478bd9Sstevel@tonic-gate if (ebus_p->ebus_soft_state == EBUS_SOFT_STATE_OPEN_EXCL) { 1107*7c478bd9Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 1108*7c478bd9Sstevel@tonic-gate return (EBUSY); 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN; 1111*7c478bd9Sstevel@tonic-gate } 1112*7c478bd9Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 1113*7c478bd9Sstevel@tonic-gate return (0); 1114*7c478bd9Sstevel@tonic-gate } 1115*7c478bd9Sstevel@tonic-gate 1116*7c478bd9Sstevel@tonic-gate 1117*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1118*7c478bd9Sstevel@tonic-gate static int 1119*7c478bd9Sstevel@tonic-gate ebus_close(dev_t dev, int flags, int otyp, cred_t *credp) 1120*7c478bd9Sstevel@tonic-gate { 1121*7c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p; 1122*7c478bd9Sstevel@tonic-gate 1123*7c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 1124*7c478bd9Sstevel@tonic-gate return (EINVAL); 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(getminor(dev)); 1127*7c478bd9Sstevel@tonic-gate if (ebus_p == NULL) 1128*7c478bd9Sstevel@tonic-gate return (ENXIO); 1129*7c478bd9Sstevel@tonic-gate 1130*7c478bd9Sstevel@tonic-gate mutex_enter(&ebus_p->ebus_mutex); 1131*7c478bd9Sstevel@tonic-gate ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED; 1132*7c478bd9Sstevel@tonic-gate mutex_exit(&ebus_p->ebus_mutex); 1133*7c478bd9Sstevel@tonic-gate return (0); 1134*7c478bd9Sstevel@tonic-gate } 1135*7c478bd9Sstevel@tonic-gate 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate /* 1138*7c478bd9Sstevel@tonic-gate * ebus_ioctl: devctl hotplug controls 1139*7c478bd9Sstevel@tonic-gate */ 1140*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1141*7c478bd9Sstevel@tonic-gate static int 1142*7c478bd9Sstevel@tonic-gate ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1143*7c478bd9Sstevel@tonic-gate int *rvalp) 1144*7c478bd9Sstevel@tonic-gate { 1145*7c478bd9Sstevel@tonic-gate ebus_devstate_t *ebus_p; 1146*7c478bd9Sstevel@tonic-gate dev_info_t *self; 1147*7c478bd9Sstevel@tonic-gate struct devctl_iocdata *dcp; 1148*7c478bd9Sstevel@tonic-gate uint_t bus_state; 1149*7c478bd9Sstevel@tonic-gate int rv = 0; 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate ebus_p = get_ebus_soft_state(getminor(dev)); 1152*7c478bd9Sstevel@tonic-gate if (ebus_p == NULL) 1153*7c478bd9Sstevel@tonic-gate return (ENXIO); 1154*7c478bd9Sstevel@tonic-gate 1155*7c478bd9Sstevel@tonic-gate self = ebus_p->dip; 1156*7c478bd9Sstevel@tonic-gate 1157*7c478bd9Sstevel@tonic-gate /* 1158*7c478bd9Sstevel@tonic-gate * We can use the generic implementation for these ioctls 1159*7c478bd9Sstevel@tonic-gate */ 1160*7c478bd9Sstevel@tonic-gate switch (cmd) { 1161*7c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_GETSTATE: 1162*7c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_ONLINE: 1163*7c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_OFFLINE: 1164*7c478bd9Sstevel@tonic-gate case DEVCTL_BUS_GETSTATE: 1165*7c478bd9Sstevel@tonic-gate return (ndi_devctl_ioctl(self, cmd, arg, mode, 0)); 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate /* 1169*7c478bd9Sstevel@tonic-gate * read devctl ioctl data 1170*7c478bd9Sstevel@tonic-gate */ 1171*7c478bd9Sstevel@tonic-gate if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 1172*7c478bd9Sstevel@tonic-gate return (EFAULT); 1173*7c478bd9Sstevel@tonic-gate 1174*7c478bd9Sstevel@tonic-gate switch (cmd) { 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_RESET: 1177*7c478bd9Sstevel@tonic-gate rv = ENOTSUP; 1178*7c478bd9Sstevel@tonic-gate break; 1179*7c478bd9Sstevel@tonic-gate 1180*7c478bd9Sstevel@tonic-gate case DEVCTL_BUS_QUIESCE: 1181*7c478bd9Sstevel@tonic-gate if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 1182*7c478bd9Sstevel@tonic-gate if (bus_state == BUS_QUIESCED) 1183*7c478bd9Sstevel@tonic-gate break; 1184*7c478bd9Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_QUIESCED); 1185*7c478bd9Sstevel@tonic-gate break; 1186*7c478bd9Sstevel@tonic-gate 1187*7c478bd9Sstevel@tonic-gate case DEVCTL_BUS_UNQUIESCE: 1188*7c478bd9Sstevel@tonic-gate if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 1189*7c478bd9Sstevel@tonic-gate if (bus_state == BUS_ACTIVE) 1190*7c478bd9Sstevel@tonic-gate break; 1191*7c478bd9Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_ACTIVE); 1192*7c478bd9Sstevel@tonic-gate break; 1193*7c478bd9Sstevel@tonic-gate 1194*7c478bd9Sstevel@tonic-gate case DEVCTL_BUS_RESET: 1195*7c478bd9Sstevel@tonic-gate rv = ENOTSUP; 1196*7c478bd9Sstevel@tonic-gate break; 1197*7c478bd9Sstevel@tonic-gate 1198*7c478bd9Sstevel@tonic-gate case DEVCTL_BUS_RESETALL: 1199*7c478bd9Sstevel@tonic-gate rv = ENOTSUP; 1200*7c478bd9Sstevel@tonic-gate break; 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate default: 1203*7c478bd9Sstevel@tonic-gate rv = ENOTTY; 1204*7c478bd9Sstevel@tonic-gate } 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate ndi_dc_freehdl(dcp); 1207*7c478bd9Sstevel@tonic-gate return (rv); 1208*7c478bd9Sstevel@tonic-gate } 1209