1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Sun4u PCI to PCI bus bridge nexus driver 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/conf.h> 34*0Sstevel@tonic-gate #include <sys/kmem.h> 35*0Sstevel@tonic-gate #include <sys/debug.h> 36*0Sstevel@tonic-gate #include <sys/modctl.h> 37*0Sstevel@tonic-gate #include <sys/autoconf.h> 38*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 39*0Sstevel@tonic-gate #include <sys/ddi_subrdefs.h> 40*0Sstevel@tonic-gate #include <sys/pci.h> 41*0Sstevel@tonic-gate #include <sys/pci/pci_nexus.h> 42*0Sstevel@tonic-gate #include <sys/pci/pci_regs.h> 43*0Sstevel@tonic-gate #include <sys/ddi.h> 44*0Sstevel@tonic-gate #include <sys/sunndi.h> 45*0Sstevel@tonic-gate #include <sys/sunddi.h> 46*0Sstevel@tonic-gate #include <sys/fm/protocol.h> 47*0Sstevel@tonic-gate #include <sys/ddifm.h> 48*0Sstevel@tonic-gate #include <sys/pci/pci_pwr.h> 49*0Sstevel@tonic-gate #include <sys/pci/pci_debug.h> 50*0Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h> 51*0Sstevel@tonic-gate #include <sys/open.h> 52*0Sstevel@tonic-gate #include <sys/stat.h> 53*0Sstevel@tonic-gate #include <sys/file.h> 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate #define NUM_LOGICAL_SLOTS 32 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate #define PPB_RANGE_LEN 2 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate #define PPB_32BIT_IO 1 60*0Sstevel@tonic-gate #define PPB_32bit_MEM 1 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate #define PPB_MEMGRAIN 0x100000 63*0Sstevel@tonic-gate #define PPB_IOGRAIN 0x1000 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate #define PPB_16bit_IOADDR(addr) ((uint16_t)(((uint8_t)(addr) & 0xF0) << 8)) 66*0Sstevel@tonic-gate #define PPB_LADDR(lo, hi) (((uint16_t)(hi) << 16) | (uint16_t)(lo)) 67*0Sstevel@tonic-gate #define PPB_32bit_MEMADDR(addr) (PPB_LADDR(0, ((uint16_t)(addr) & 0xFFF0))) 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate typedef struct slot_table { 70*0Sstevel@tonic-gate uchar_t bus_id[128]; 71*0Sstevel@tonic-gate uchar_t slot_name[32]; 72*0Sstevel@tonic-gate uint8_t device_no; 73*0Sstevel@tonic-gate uint8_t phys_slot_num; 74*0Sstevel@tonic-gate } slot_table_t; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* 77*0Sstevel@tonic-gate * The following typedef is used to represent an entry in the "ranges" 78*0Sstevel@tonic-gate * property of a device node. 79*0Sstevel@tonic-gate */ 80*0Sstevel@tonic-gate typedef struct { 81*0Sstevel@tonic-gate uint32_t child_high; 82*0Sstevel@tonic-gate uint32_t child_mid; 83*0Sstevel@tonic-gate uint32_t child_low; 84*0Sstevel@tonic-gate uint32_t parent_high; 85*0Sstevel@tonic-gate uint32_t parent_mid; 86*0Sstevel@tonic-gate uint32_t parent_low; 87*0Sstevel@tonic-gate uint32_t size_high; 88*0Sstevel@tonic-gate uint32_t size_low; 89*0Sstevel@tonic-gate } ppb_ranges_t; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate /* 92*0Sstevel@tonic-gate * The variable controls the default setting of the command register 93*0Sstevel@tonic-gate * for pci devices. See ppb_initchild() for details. 94*0Sstevel@tonic-gate */ 95*0Sstevel@tonic-gate static ushort_t ppb_command_default = PCI_COMM_SERR_ENABLE | 96*0Sstevel@tonic-gate PCI_COMM_WAIT_CYC_ENAB | 97*0Sstevel@tonic-gate PCI_COMM_PARITY_DETECT | 98*0Sstevel@tonic-gate PCI_COMM_ME | 99*0Sstevel@tonic-gate PCI_COMM_MAE | 100*0Sstevel@tonic-gate PCI_COMM_IO; 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate static int ppb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 103*0Sstevel@tonic-gate off_t, off_t, caddr_t *); 104*0Sstevel@tonic-gate static int ppb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 105*0Sstevel@tonic-gate void *, void *); 106*0Sstevel@tonic-gate static int ppb_intr_ops(dev_info_t *dip, dev_info_t *rdip, 107*0Sstevel@tonic-gate ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result); 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate /* 110*0Sstevel@tonic-gate * fm_init busop to initialize our children 111*0Sstevel@tonic-gate */ 112*0Sstevel@tonic-gate static int ppb_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap, 113*0Sstevel@tonic-gate ddi_iblock_cookie_t *ibc); 114*0Sstevel@tonic-gate static void ppb_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle); 115*0Sstevel@tonic-gate static void ppb_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle); 116*0Sstevel@tonic-gate static int ppb_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op, 117*0Sstevel@tonic-gate void *arg, void *result); 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate struct bus_ops ppb_bus_ops = { 120*0Sstevel@tonic-gate BUSO_REV, 121*0Sstevel@tonic-gate ppb_bus_map, 122*0Sstevel@tonic-gate 0, 123*0Sstevel@tonic-gate 0, 124*0Sstevel@tonic-gate 0, 125*0Sstevel@tonic-gate i_ddi_map_fault, 126*0Sstevel@tonic-gate ddi_dma_map, 127*0Sstevel@tonic-gate ddi_dma_allochdl, 128*0Sstevel@tonic-gate ddi_dma_freehdl, 129*0Sstevel@tonic-gate ddi_dma_bindhdl, 130*0Sstevel@tonic-gate ddi_dma_unbindhdl, 131*0Sstevel@tonic-gate ddi_dma_flush, 132*0Sstevel@tonic-gate ddi_dma_win, 133*0Sstevel@tonic-gate ddi_dma_mctl, 134*0Sstevel@tonic-gate ppb_ctlops, 135*0Sstevel@tonic-gate ddi_bus_prop_op, 136*0Sstevel@tonic-gate ndi_busop_get_eventcookie, /* (*bus_get_eventcookie)(); */ 137*0Sstevel@tonic-gate ndi_busop_add_eventcall, /* (*bus_add_eventcall)(); */ 138*0Sstevel@tonic-gate ndi_busop_remove_eventcall, /* (*bus_remove_eventcall)(); */ 139*0Sstevel@tonic-gate ndi_post_event, /* (*bus_post_event)(); */ 140*0Sstevel@tonic-gate 0, /* (*bus_intr_ctl)(); */ 141*0Sstevel@tonic-gate 0, /* (*bus_config)(); */ 142*0Sstevel@tonic-gate 0, /* (*bus_unconfig)(); */ 143*0Sstevel@tonic-gate ppb_fm_init_child, /* (*bus_fm_init)(); */ 144*0Sstevel@tonic-gate NULL, /* (*bus_fm_fini)(); */ 145*0Sstevel@tonic-gate ppb_bus_enter, /* (*bus_enter)() */ 146*0Sstevel@tonic-gate ppb_bus_exit, /* (*bus_exit)() */ 147*0Sstevel@tonic-gate ppb_bus_power, /* (*bus_power)() */ 148*0Sstevel@tonic-gate ppb_intr_ops /* (*bus_intr_op)(); */ 149*0Sstevel@tonic-gate }; 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate static int ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp); 152*0Sstevel@tonic-gate static int ppb_close(dev_t dev, int flags, int otyp, cred_t *credp); 153*0Sstevel@tonic-gate static int ppb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 154*0Sstevel@tonic-gate cred_t *credp, int *rvalp); 155*0Sstevel@tonic-gate static int ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 156*0Sstevel@tonic-gate int flags, char *name, caddr_t valuep, int *lengthp); 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate static struct cb_ops ppb_cb_ops = { 159*0Sstevel@tonic-gate ppb_open, /* open */ 160*0Sstevel@tonic-gate ppb_close, /* close */ 161*0Sstevel@tonic-gate nulldev, /* strategy */ 162*0Sstevel@tonic-gate nulldev, /* print */ 163*0Sstevel@tonic-gate nulldev, /* dump */ 164*0Sstevel@tonic-gate nulldev, /* read */ 165*0Sstevel@tonic-gate nulldev, /* write */ 166*0Sstevel@tonic-gate ppb_ioctl, /* ioctl */ 167*0Sstevel@tonic-gate nodev, /* devmap */ 168*0Sstevel@tonic-gate nodev, /* mmap */ 169*0Sstevel@tonic-gate nodev, /* segmap */ 170*0Sstevel@tonic-gate nochpoll, /* poll */ 171*0Sstevel@tonic-gate ppb_prop_op, /* cb_prop_op */ 172*0Sstevel@tonic-gate NULL, /* streamtab */ 173*0Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 174*0Sstevel@tonic-gate CB_REV, /* rev */ 175*0Sstevel@tonic-gate nodev, /* int (*cb_aread)() */ 176*0Sstevel@tonic-gate nodev /* int (*cb_awrite)() */ 177*0Sstevel@tonic-gate }; 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate static int ppb_probe(dev_info_t *); 180*0Sstevel@tonic-gate static int ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 181*0Sstevel@tonic-gate static int ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 182*0Sstevel@tonic-gate static int ppb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 183*0Sstevel@tonic-gate void *arg, void **result); 184*0Sstevel@tonic-gate static int ppb_pwr(dev_info_t *dip, int component, int level); 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate struct dev_ops ppb_ops = { 187*0Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 188*0Sstevel@tonic-gate 0, /* refcnt */ 189*0Sstevel@tonic-gate ppb_info, /* info */ 190*0Sstevel@tonic-gate nulldev, /* identify */ 191*0Sstevel@tonic-gate ppb_probe, /* probe */ 192*0Sstevel@tonic-gate ppb_attach, /* attach */ 193*0Sstevel@tonic-gate ppb_detach, /* detach */ 194*0Sstevel@tonic-gate nulldev, /* reset */ 195*0Sstevel@tonic-gate &ppb_cb_ops, /* driver operations */ 196*0Sstevel@tonic-gate &ppb_bus_ops, /* bus operations */ 197*0Sstevel@tonic-gate ppb_pwr 198*0Sstevel@tonic-gate }; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate /* 201*0Sstevel@tonic-gate * Module linkage information for the kernel. 202*0Sstevel@tonic-gate */ 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate static struct modldrv modldrv = { 205*0Sstevel@tonic-gate &mod_driverops, /* Type of module */ 206*0Sstevel@tonic-gate "Standard PCI to PCI bridge nexus driver 1.74", 207*0Sstevel@tonic-gate &ppb_ops, /* driver ops */ 208*0Sstevel@tonic-gate }; 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 211*0Sstevel@tonic-gate MODREV_1, 212*0Sstevel@tonic-gate (void *)&modldrv, 213*0Sstevel@tonic-gate NULL 214*0Sstevel@tonic-gate }; 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /* 217*0Sstevel@tonic-gate * soft state pointer and structure template: 218*0Sstevel@tonic-gate */ 219*0Sstevel@tonic-gate static void *ppb_state; 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate static struct ppb_cfg_state { 222*0Sstevel@tonic-gate dev_info_t *dip; 223*0Sstevel@tonic-gate ushort_t command; 224*0Sstevel@tonic-gate uchar_t cache_line_size; 225*0Sstevel@tonic-gate uchar_t latency_timer; 226*0Sstevel@tonic-gate uchar_t header_type; 227*0Sstevel@tonic-gate uchar_t sec_latency_timer; 228*0Sstevel@tonic-gate ushort_t bridge_control; 229*0Sstevel@tonic-gate }; 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate typedef struct { 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate dev_info_t *dip; 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate /* 236*0Sstevel@tonic-gate * configuration register state for the bus: 237*0Sstevel@tonic-gate */ 238*0Sstevel@tonic-gate uchar_t ppb_cache_line_size; 239*0Sstevel@tonic-gate uchar_t ppb_latency_timer; 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate /* 242*0Sstevel@tonic-gate * PM support 243*0Sstevel@tonic-gate */ 244*0Sstevel@tonic-gate ddi_acc_handle_t ppb_conf_hdl; 245*0Sstevel@tonic-gate uint8_t ppb_pmcsr_offset; 246*0Sstevel@tonic-gate pci_pwr_t *ppb_pwr_p; 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate /* 249*0Sstevel@tonic-gate * HP support 250*0Sstevel@tonic-gate */ 251*0Sstevel@tonic-gate boolean_t hotplug_capable; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate kmutex_t ppb_mutex; 254*0Sstevel@tonic-gate uint_t ppb_soft_state; 255*0Sstevel@tonic-gate #define PPB_SOFT_STATE_CLOSED 0x00 256*0Sstevel@tonic-gate #define PPB_SOFT_STATE_OPEN 0x01 257*0Sstevel@tonic-gate #define PPB_SOFT_STATE_OPEN_EXCL 0x02 258*0Sstevel@tonic-gate int fm_cap; 259*0Sstevel@tonic-gate ddi_iblock_cookie_t fm_ibc; 260*0Sstevel@tonic-gate } ppb_devstate_t; 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate /* 263*0Sstevel@tonic-gate * The following variable enables a workaround for the following obp bug: 264*0Sstevel@tonic-gate * 265*0Sstevel@tonic-gate * 1234181 - obp should set latency timer registers in pci 266*0Sstevel@tonic-gate * configuration header 267*0Sstevel@tonic-gate * 268*0Sstevel@tonic-gate * Until this bug gets fixed in the obp, the following workaround should 269*0Sstevel@tonic-gate * be enabled. 270*0Sstevel@tonic-gate */ 271*0Sstevel@tonic-gate static uint_t ppb_set_latency_timer_register = 1; 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate /* 274*0Sstevel@tonic-gate * The following variable enables a workaround for an obp bug to be 275*0Sstevel@tonic-gate * submitted. A bug requesting a workaround fof this problem has 276*0Sstevel@tonic-gate * been filed: 277*0Sstevel@tonic-gate * 278*0Sstevel@tonic-gate * 1235094 - need workarounds on positron nexus drivers to set cache 279*0Sstevel@tonic-gate * line size registers 280*0Sstevel@tonic-gate * 281*0Sstevel@tonic-gate * Until this bug gets fixed in the obp, the following workaround should 282*0Sstevel@tonic-gate * be enabled. 283*0Sstevel@tonic-gate */ 284*0Sstevel@tonic-gate static uint_t ppb_set_cache_line_size_register = 1; 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate /* 287*0Sstevel@tonic-gate * forward function declarations: 288*0Sstevel@tonic-gate */ 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate /* 291*0Sstevel@tonic-gate * FMA error callback 292*0Sstevel@tonic-gate * Register error handling callback with our parent. We will just call 293*0Sstevel@tonic-gate * our children's error callbacks and return their status. 294*0Sstevel@tonic-gate */ 295*0Sstevel@tonic-gate static int ppb_err_callback(dev_info_t *dip, ddi_fm_error_t *derr, 296*0Sstevel@tonic-gate const void *impl_data); 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* 299*0Sstevel@tonic-gate * init/fini routines to alloc/dealloc fm structures and 300*0Sstevel@tonic-gate * register/unregister our callback. 301*0Sstevel@tonic-gate */ 302*0Sstevel@tonic-gate static void ppb_fm_init(ppb_devstate_t *ppb_p); 303*0Sstevel@tonic-gate static void ppb_fm_fini(ppb_devstate_t *ppb_p); 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate static void ppb_removechild(dev_info_t *); 306*0Sstevel@tonic-gate static int ppb_initchild(dev_info_t *child); 307*0Sstevel@tonic-gate static dev_info_t *get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip); 308*0Sstevel@tonic-gate static void ppb_pwr_setup(ppb_devstate_t *ppb, dev_info_t *dip); 309*0Sstevel@tonic-gate static void ppb_pwr_teardown(ppb_devstate_t *ppb, dev_info_t *dip); 310*0Sstevel@tonic-gate static void ppb_init_hotplug(ppb_devstate_t *ppb); 311*0Sstevel@tonic-gate static void ppb_create_ranges_prop(dev_info_t *, ddi_acc_handle_t); 312*0Sstevel@tonic-gate extern uint64_t pci_debug_flags = 0; 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate int 315*0Sstevel@tonic-gate _init(void) 316*0Sstevel@tonic-gate { 317*0Sstevel@tonic-gate int e; 318*0Sstevel@tonic-gate if ((e = ddi_soft_state_init(&ppb_state, sizeof (ppb_devstate_t), 319*0Sstevel@tonic-gate 1)) == 0 && (e = mod_install(&modlinkage)) != 0) 320*0Sstevel@tonic-gate ddi_soft_state_fini(&ppb_state); 321*0Sstevel@tonic-gate return (e); 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate int 325*0Sstevel@tonic-gate _fini(void) 326*0Sstevel@tonic-gate { 327*0Sstevel@tonic-gate int e; 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) == 0) 330*0Sstevel@tonic-gate ddi_soft_state_fini(&ppb_state); 331*0Sstevel@tonic-gate return (e); 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate int 335*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 336*0Sstevel@tonic-gate { 337*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate /*ARGSUSED*/ 341*0Sstevel@tonic-gate static int 342*0Sstevel@tonic-gate ppb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 343*0Sstevel@tonic-gate { 344*0Sstevel@tonic-gate ppb_devstate_t *ppb_p; /* per ppb state pointer */ 345*0Sstevel@tonic-gate minor_t minor = getminor((dev_t)arg); 346*0Sstevel@tonic-gate int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 349*0Sstevel@tonic-gate instance); 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate switch (infocmd) { 352*0Sstevel@tonic-gate default: 353*0Sstevel@tonic-gate return (DDI_FAILURE); 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 356*0Sstevel@tonic-gate *result = (void *)instance; 357*0Sstevel@tonic-gate return (DDI_SUCCESS); 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 360*0Sstevel@tonic-gate if (ppb_p == NULL) 361*0Sstevel@tonic-gate return (DDI_FAILURE); 362*0Sstevel@tonic-gate *result = (void *)ppb_p->dip; 363*0Sstevel@tonic-gate return (DDI_SUCCESS); 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate /*ARGSUSED*/ 368*0Sstevel@tonic-gate static int 369*0Sstevel@tonic-gate ppb_probe(register dev_info_t *devi) 370*0Sstevel@tonic-gate { 371*0Sstevel@tonic-gate return (DDI_PROBE_SUCCESS); 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate /*ARGSUSED*/ 375*0Sstevel@tonic-gate static int 376*0Sstevel@tonic-gate ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 377*0Sstevel@tonic-gate { 378*0Sstevel@tonic-gate int instance; 379*0Sstevel@tonic-gate ppb_devstate_t *ppb; 380*0Sstevel@tonic-gate ddi_acc_handle_t config_handle; 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate switch (cmd) { 383*0Sstevel@tonic-gate case DDI_ATTACH: 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate /* 386*0Sstevel@tonic-gate * Make sure the "device_type" property exists. 387*0Sstevel@tonic-gate */ 388*0Sstevel@tonic-gate (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, 389*0Sstevel@tonic-gate "device_type", "pci"); 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate /* 392*0Sstevel@tonic-gate * Allocate and get soft state structure. 393*0Sstevel@tonic-gate */ 394*0Sstevel@tonic-gate instance = ddi_get_instance(devi); 395*0Sstevel@tonic-gate if (ddi_soft_state_zalloc(ppb_state, instance) != DDI_SUCCESS) 396*0Sstevel@tonic-gate return (DDI_FAILURE); 397*0Sstevel@tonic-gate ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, instance); 398*0Sstevel@tonic-gate ppb->dip = devi; 399*0Sstevel@tonic-gate mutex_init(&ppb->ppb_mutex, NULL, MUTEX_DRIVER, NULL); 400*0Sstevel@tonic-gate ppb->ppb_soft_state = PPB_SOFT_STATE_CLOSED; 401*0Sstevel@tonic-gate if (pci_config_setup(devi, &config_handle) != DDI_SUCCESS) { 402*0Sstevel@tonic-gate mutex_destroy(&ppb->ppb_mutex); 403*0Sstevel@tonic-gate ddi_soft_state_free(ppb_state, instance); 404*0Sstevel@tonic-gate return (DDI_FAILURE); 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate ppb_pwr_setup(ppb, devi); 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate if (PM_CAPABLE(ppb->ppb_pwr_p)) { 409*0Sstevel@tonic-gate mutex_enter(&ppb->ppb_pwr_p->pwr_mutex); 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate /* 412*0Sstevel@tonic-gate * Before reading config registers, make sure power is 413*0Sstevel@tonic-gate * on, and remains on. 414*0Sstevel@tonic-gate */ 415*0Sstevel@tonic-gate ppb->ppb_pwr_p->pwr_fp++; 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate pci_pwr_change(ppb->ppb_pwr_p, 418*0Sstevel@tonic-gate ppb->ppb_pwr_p->current_lvl, 419*0Sstevel@tonic-gate pci_pwr_new_lvl(ppb->ppb_pwr_p)); 420*0Sstevel@tonic-gate } 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate ppb->ppb_cache_line_size = 423*0Sstevel@tonic-gate pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ); 424*0Sstevel@tonic-gate ppb->ppb_latency_timer = 425*0Sstevel@tonic-gate pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER); 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate /* 428*0Sstevel@tonic-gate * Check whether the "ranges" property is present. 429*0Sstevel@tonic-gate * Otherwise create the ranges property by reading 430*0Sstevel@tonic-gate * the configuration registers 431*0Sstevel@tonic-gate */ 432*0Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 433*0Sstevel@tonic-gate "ranges") == 0) { 434*0Sstevel@tonic-gate ppb_create_ranges_prop(devi, config_handle); 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate pci_config_teardown(&config_handle); 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate if (PM_CAPABLE(ppb->ppb_pwr_p)) { 440*0Sstevel@tonic-gate ppb->ppb_pwr_p->pwr_fp--; 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate pci_pwr_change(ppb->ppb_pwr_p, 443*0Sstevel@tonic-gate ppb->ppb_pwr_p->current_lvl, 444*0Sstevel@tonic-gate pci_pwr_new_lvl(ppb->ppb_pwr_p)); 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate mutex_exit(&ppb->ppb_pwr_p->pwr_mutex); 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate /* 450*0Sstevel@tonic-gate * Initialize hotplug support on this bus. At minimum 451*0Sstevel@tonic-gate * (for non hotplug bus) this would create ":devctl" minor 452*0Sstevel@tonic-gate * node to support DEVCTL_DEVICE_* and DEVCTL_BUS_* ioctls 453*0Sstevel@tonic-gate * to this bus. This all takes place if this nexus has hot-plug 454*0Sstevel@tonic-gate * slots and successfully initializes Hot Plug Framework. 455*0Sstevel@tonic-gate */ 456*0Sstevel@tonic-gate ppb->hotplug_capable = B_FALSE; 457*0Sstevel@tonic-gate ppb_init_hotplug(ppb); 458*0Sstevel@tonic-gate if (ppb->hotplug_capable == B_FALSE) { 459*0Sstevel@tonic-gate /* 460*0Sstevel@tonic-gate * create minor node for devctl interfaces 461*0Sstevel@tonic-gate */ 462*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, "devctl", S_IFCHR, 463*0Sstevel@tonic-gate PCIHP_AP_MINOR_NUM(instance, PCIHP_DEVCTL_MINOR), 464*0Sstevel@tonic-gate DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 465*0Sstevel@tonic-gate if (ppb->ppb_pwr_p != NULL) { 466*0Sstevel@tonic-gate ppb_pwr_teardown(ppb, devi); 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate mutex_destroy(&ppb->ppb_mutex); 469*0Sstevel@tonic-gate ddi_soft_state_free(ppb_state, instance); 470*0Sstevel@tonic-gate return (DDI_FAILURE); 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate DEBUG1(DBG_ATTACH, devi, 475*0Sstevel@tonic-gate "ppb_attach(): this nexus %s hotplug slots\n", 476*0Sstevel@tonic-gate ppb->hotplug_capable == B_TRUE ? "has":"has no"); 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate ppb_fm_init(ppb); 479*0Sstevel@tonic-gate ddi_report_dev(devi); 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate return (DDI_SUCCESS); 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate case DDI_RESUME: 484*0Sstevel@tonic-gate /* 485*0Sstevel@tonic-gate * Get the soft state structure for the bridge. 486*0Sstevel@tonic-gate */ 487*0Sstevel@tonic-gate ppb = (ppb_devstate_t *) 488*0Sstevel@tonic-gate ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate pci_pwr_resume(devi, ppb->ppb_pwr_p); 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate return (DDI_SUCCESS); 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate return (DDI_FAILURE); 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate /*ARGSUSED*/ 498*0Sstevel@tonic-gate static int 499*0Sstevel@tonic-gate ppb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 500*0Sstevel@tonic-gate { 501*0Sstevel@tonic-gate ppb_devstate_t *ppb; 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate switch (cmd) { 504*0Sstevel@tonic-gate case DDI_DETACH: 505*0Sstevel@tonic-gate /* 506*0Sstevel@tonic-gate * And finally free the per-pci soft state after 507*0Sstevel@tonic-gate * uninitializing hotplug support for this bus. 508*0Sstevel@tonic-gate */ 509*0Sstevel@tonic-gate ppb = (ppb_devstate_t *) 510*0Sstevel@tonic-gate ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate ppb_fm_fini(ppb); 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate if (ppb->hotplug_capable == B_TRUE) 515*0Sstevel@tonic-gate if (pcihp_uninit(devi) == DDI_FAILURE) 516*0Sstevel@tonic-gate return (DDI_FAILURE); 517*0Sstevel@tonic-gate else 518*0Sstevel@tonic-gate ddi_remove_minor_node(devi, "devctl"); 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type"); 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate if (ppb->ppb_pwr_p != NULL) { 523*0Sstevel@tonic-gate ppb_pwr_teardown(ppb, devi); 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate mutex_destroy(&ppb->ppb_mutex); 526*0Sstevel@tonic-gate ddi_soft_state_free(ppb_state, ddi_get_instance(devi)); 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate return (DDI_SUCCESS); 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate case DDI_SUSPEND: 531*0Sstevel@tonic-gate ppb = (ppb_devstate_t *) 532*0Sstevel@tonic-gate ddi_get_soft_state(ppb_state, ddi_get_instance(devi)); 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate pci_pwr_suspend(devi, ppb->ppb_pwr_p); 535*0Sstevel@tonic-gate 536*0Sstevel@tonic-gate return (DDI_SUCCESS); 537*0Sstevel@tonic-gate } 538*0Sstevel@tonic-gate return (DDI_FAILURE); 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate /*ARGSUSED*/ 542*0Sstevel@tonic-gate static int 543*0Sstevel@tonic-gate ppb_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 544*0Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 545*0Sstevel@tonic-gate { 546*0Sstevel@tonic-gate register dev_info_t *pdip; 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate pdip = (dev_info_t *)DEVI(dip)->devi_parent; 549*0Sstevel@tonic-gate return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map) 550*0Sstevel@tonic-gate (pdip, rdip, mp, offset, len, vaddrp)); 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate /*ARGSUSED*/ 554*0Sstevel@tonic-gate static int 555*0Sstevel@tonic-gate ppb_ctlops(dev_info_t *dip, dev_info_t *rdip, 556*0Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 557*0Sstevel@tonic-gate { 558*0Sstevel@tonic-gate pci_regspec_t *drv_regp; 559*0Sstevel@tonic-gate int reglen; 560*0Sstevel@tonic-gate int rn; 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate int totreg; 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate switch (ctlop) { 565*0Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 566*0Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 567*0Sstevel@tonic-gate return (DDI_FAILURE); 568*0Sstevel@tonic-gate cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", 569*0Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_name_addr(rdip), 570*0Sstevel@tonic-gate ddi_driver_name(rdip), 571*0Sstevel@tonic-gate ddi_get_instance(rdip)); 572*0Sstevel@tonic-gate return (DDI_SUCCESS); 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 575*0Sstevel@tonic-gate return (ppb_initchild((dev_info_t *)arg)); 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 578*0Sstevel@tonic-gate ppb_removechild((dev_info_t *)arg); 579*0Sstevel@tonic-gate return (DDI_SUCCESS); 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 582*0Sstevel@tonic-gate return (DDI_SUCCESS); 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 585*0Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 586*0Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 587*0Sstevel@tonic-gate return (DDI_FAILURE); 588*0Sstevel@tonic-gate break; 589*0Sstevel@tonic-gate default: 590*0Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate *(int *)result = 0; 594*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, 595*0Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", 596*0Sstevel@tonic-gate (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) 597*0Sstevel@tonic-gate return (DDI_FAILURE); 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate totreg = reglen / sizeof (pci_regspec_t); 600*0Sstevel@tonic-gate if (ctlop == DDI_CTLOPS_NREGS) 601*0Sstevel@tonic-gate *(int *)result = totreg; 602*0Sstevel@tonic-gate else if (ctlop == DDI_CTLOPS_REGSIZE) { 603*0Sstevel@tonic-gate rn = *(int *)arg; 604*0Sstevel@tonic-gate if (rn >= totreg) { 605*0Sstevel@tonic-gate kmem_free(drv_regp, reglen); 606*0Sstevel@tonic-gate return (DDI_FAILURE); 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate *(off_t *)result = drv_regp[rn].pci_size_low | 609*0Sstevel@tonic-gate ((uint64_t)drv_regp[rn].pci_size_hi << 32); 610*0Sstevel@tonic-gate } 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate kmem_free(drv_regp, reglen); 613*0Sstevel@tonic-gate return (DDI_SUCCESS); 614*0Sstevel@tonic-gate } 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate static dev_info_t * 618*0Sstevel@tonic-gate get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip) 619*0Sstevel@tonic-gate { 620*0Sstevel@tonic-gate dev_info_t *cdip = rdip; 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip)) 623*0Sstevel@tonic-gate ; 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate return (cdip); 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate static int 630*0Sstevel@tonic-gate ppb_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 631*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 632*0Sstevel@tonic-gate { 633*0Sstevel@tonic-gate ddi_ispec_t *ip = (ddi_ispec_t *)hdlp->ih_private; 634*0Sstevel@tonic-gate dev_info_t *cdip = rdip; 635*0Sstevel@tonic-gate pci_regspec_t *pci_rp; 636*0Sstevel@tonic-gate int reglen, len; 637*0Sstevel@tonic-gate uint32_t d, intr; 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate if (hdlp->ih_type != DDI_INTR_TYPE_FIXED) 640*0Sstevel@tonic-gate goto done; 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate /* 643*0Sstevel@tonic-gate * If the interrupt-map property is defined at this 644*0Sstevel@tonic-gate * node, it will have performed the interrupt 645*0Sstevel@tonic-gate * translation as part of the property, so no 646*0Sstevel@tonic-gate * rotation needs to be done. 647*0Sstevel@tonic-gate */ 648*0Sstevel@tonic-gate if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 649*0Sstevel@tonic-gate "interrupt-map", &len) == DDI_PROP_SUCCESS) 650*0Sstevel@tonic-gate goto done; 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate cdip = get_my_childs_dip(dip, rdip); 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate /* 655*0Sstevel@tonic-gate * Use the devices reg property to determine its 656*0Sstevel@tonic-gate * PCI bus number and device number. 657*0Sstevel@tonic-gate */ 658*0Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_NONE, cdip, DDI_PROP_DONTPASS, 659*0Sstevel@tonic-gate "reg", (caddr_t)&pci_rp, ®len) != DDI_SUCCESS) 660*0Sstevel@tonic-gate return (DDI_FAILURE); 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate intr = *ip->is_intr; 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate /* Spin the interrupt */ 665*0Sstevel@tonic-gate d = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi); 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate if ((intr >= PCI_INTA) && (intr <= PCI_INTD)) 668*0Sstevel@tonic-gate *ip->is_intr = ((intr - 1 + (d % 4)) % 4 + 1); 669*0Sstevel@tonic-gate else 670*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: %s: PCI intr=%x out of range", 671*0Sstevel@tonic-gate ddi_driver_name(rdip), ddi_get_instance(rdip), 672*0Sstevel@tonic-gate ddi_driver_name(dip), intr); 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate kmem_free(pci_rp, reglen); 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate done: 677*0Sstevel@tonic-gate /* Pass up the request to our parent. */ 678*0Sstevel@tonic-gate return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result)); 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate static int 682*0Sstevel@tonic-gate ppb_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op, 683*0Sstevel@tonic-gate void *arg, void *result) 684*0Sstevel@tonic-gate { 685*0Sstevel@tonic-gate ppb_devstate_t *ppb; 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 688*0Sstevel@tonic-gate ddi_get_instance(dip)); 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate return (pci_pwr_ops(ppb->ppb_pwr_p, dip, impl_arg, op, arg, result)); 691*0Sstevel@tonic-gate } 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate /* 695*0Sstevel@tonic-gate * name_child 696*0Sstevel@tonic-gate * 697*0Sstevel@tonic-gate * This function is called from init_child to name a node. It is 698*0Sstevel@tonic-gate * also passed as a callback for node merging functions. 699*0Sstevel@tonic-gate * 700*0Sstevel@tonic-gate * return value: DDI_SUCCESS, DDI_FAILURE 701*0Sstevel@tonic-gate */ 702*0Sstevel@tonic-gate static int 703*0Sstevel@tonic-gate ppb_name_child(dev_info_t *child, char *name, int namelen) 704*0Sstevel@tonic-gate { 705*0Sstevel@tonic-gate pci_regspec_t *pci_rp; 706*0Sstevel@tonic-gate uint_t slot, func; 707*0Sstevel@tonic-gate char **unit_addr; 708*0Sstevel@tonic-gate uint_t n; 709*0Sstevel@tonic-gate 710*0Sstevel@tonic-gate /* 711*0Sstevel@tonic-gate * Pseudo nodes indicate a prototype node with per-instance 712*0Sstevel@tonic-gate * properties to be merged into the real h/w device node. 713*0Sstevel@tonic-gate * The interpretation of the unit-address is DD[,F] 714*0Sstevel@tonic-gate * where DD is the device id and F is the function. 715*0Sstevel@tonic-gate */ 716*0Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 717*0Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 718*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 719*0Sstevel@tonic-gate DDI_PROP_SUCCESS) { 720*0Sstevel@tonic-gate cmn_err(CE_WARN, "cannot name node from %s.conf", 721*0Sstevel@tonic-gate ddi_driver_name(child)); 722*0Sstevel@tonic-gate return (DDI_FAILURE); 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 725*0Sstevel@tonic-gate cmn_err(CE_WARN, "unit-address property in %s.conf" 726*0Sstevel@tonic-gate " not well-formed", ddi_driver_name(child)); 727*0Sstevel@tonic-gate ddi_prop_free(unit_addr); 728*0Sstevel@tonic-gate return (DDI_FAILURE); 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%s", *unit_addr); 731*0Sstevel@tonic-gate ddi_prop_free(unit_addr); 732*0Sstevel@tonic-gate return (DDI_SUCCESS); 733*0Sstevel@tonic-gate } 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate /* 736*0Sstevel@tonic-gate * Get the address portion of the node name based on 737*0Sstevel@tonic-gate * the function and device number. 738*0Sstevel@tonic-gate */ 739*0Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 740*0Sstevel@tonic-gate "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) { 741*0Sstevel@tonic-gate return (DDI_FAILURE); 742*0Sstevel@tonic-gate } 743*0Sstevel@tonic-gate 744*0Sstevel@tonic-gate slot = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi); 745*0Sstevel@tonic-gate func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi); 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate if (func != 0) 748*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%x,%x", slot, func); 749*0Sstevel@tonic-gate else 750*0Sstevel@tonic-gate (void) snprintf(name, namelen, "%x", slot); 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate ddi_prop_free(pci_rp); 753*0Sstevel@tonic-gate return (DDI_SUCCESS); 754*0Sstevel@tonic-gate } 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate static int 757*0Sstevel@tonic-gate ppb_initchild(dev_info_t *child) 758*0Sstevel@tonic-gate { 759*0Sstevel@tonic-gate char name[MAXNAMELEN]; 760*0Sstevel@tonic-gate ddi_acc_handle_t config_handle; 761*0Sstevel@tonic-gate ushort_t command_preserve, command; 762*0Sstevel@tonic-gate uint_t n; 763*0Sstevel@tonic-gate ushort_t bcr; 764*0Sstevel@tonic-gate uchar_t header_type; 765*0Sstevel@tonic-gate uchar_t min_gnt, latency_timer; 766*0Sstevel@tonic-gate ppb_devstate_t *ppb; 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate /* 769*0Sstevel@tonic-gate * Name the child 770*0Sstevel@tonic-gate */ 771*0Sstevel@tonic-gate if (ppb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) 772*0Sstevel@tonic-gate return (DDI_FAILURE); 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate ddi_set_name_addr(child, name); 775*0Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate /* 778*0Sstevel@tonic-gate * Pseudo nodes indicate a prototype node with per-instance 779*0Sstevel@tonic-gate * properties to be merged into the real h/w device node. 780*0Sstevel@tonic-gate * The interpretation of the unit-address is DD[,F] 781*0Sstevel@tonic-gate * where DD is the device id and F is the function. 782*0Sstevel@tonic-gate */ 783*0Sstevel@tonic-gate if (ndi_dev_is_persistent_node(child) == 0) { 784*0Sstevel@tonic-gate extern int pci_allow_pseudo_children; 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate /* 787*0Sstevel@tonic-gate * Try to merge the properties from this prototype 788*0Sstevel@tonic-gate * node into real h/w nodes. 789*0Sstevel@tonic-gate */ 790*0Sstevel@tonic-gate if (ndi_merge_node(child, ppb_name_child) == DDI_SUCCESS) { 791*0Sstevel@tonic-gate /* 792*0Sstevel@tonic-gate * Merged ok - return failure to remove the node. 793*0Sstevel@tonic-gate */ 794*0Sstevel@tonic-gate ppb_removechild(child); 795*0Sstevel@tonic-gate return (DDI_FAILURE); 796*0Sstevel@tonic-gate } 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate /* workaround for ddivs to run under PCI */ 799*0Sstevel@tonic-gate if (pci_allow_pseudo_children) 800*0Sstevel@tonic-gate return (DDI_SUCCESS); 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate /* 803*0Sstevel@tonic-gate * The child was not merged into a h/w node, 804*0Sstevel@tonic-gate * but there's not much we can do with it other 805*0Sstevel@tonic-gate * than return failure to cause the node to be removed. 806*0Sstevel@tonic-gate */ 807*0Sstevel@tonic-gate cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 808*0Sstevel@tonic-gate ddi_driver_name(child), ddi_get_name_addr(child), 809*0Sstevel@tonic-gate ddi_driver_name(child)); 810*0Sstevel@tonic-gate ppb_removechild(child); 811*0Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 812*0Sstevel@tonic-gate } 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate ddi_set_parent_data(child, NULL); 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 817*0Sstevel@tonic-gate ddi_get_instance(ddi_get_parent(child))); 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate /* 820*0Sstevel@tonic-gate * If hardware is PM capable, set up the power info structure. 821*0Sstevel@tonic-gate * This also ensures the the bus will not be off (0MHz) otherwise 822*0Sstevel@tonic-gate * system panics during a bus access. 823*0Sstevel@tonic-gate */ 824*0Sstevel@tonic-gate if (PM_CAPABLE(ppb->ppb_pwr_p)) { 825*0Sstevel@tonic-gate /* 826*0Sstevel@tonic-gate * Create a pwr_info struct for child. Bus will be 827*0Sstevel@tonic-gate * at full speed after creating info. 828*0Sstevel@tonic-gate */ 829*0Sstevel@tonic-gate pci_pwr_create_info(ppb->ppb_pwr_p, child); 830*0Sstevel@tonic-gate #ifdef DEBUG 831*0Sstevel@tonic-gate ASSERT(ppb->ppb_pwr_p->current_lvl == PM_LEVEL_B0); 832*0Sstevel@tonic-gate #endif 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate /* 836*0Sstevel@tonic-gate * If configuration registers were previously saved by 837*0Sstevel@tonic-gate * child (before it entered D3), then let the child do the 838*0Sstevel@tonic-gate * restore to set up the config regs as it'll first need to 839*0Sstevel@tonic-gate * power the device out of D3. 840*0Sstevel@tonic-gate */ 841*0Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 842*0Sstevel@tonic-gate "config-regs-saved-by-child") == 1) { 843*0Sstevel@tonic-gate DEBUG2(DBG_PWR, ddi_get_parent(child), 844*0Sstevel@tonic-gate "INITCHILD: config regs to be restored by child" 845*0Sstevel@tonic-gate " for %s@%s\n", ddi_node_name(child), 846*0Sstevel@tonic-gate ddi_get_name_addr(child)); 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate return (DDI_SUCCESS); 849*0Sstevel@tonic-gate } 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate DEBUG2(DBG_PWR, ddi_get_parent(child), 852*0Sstevel@tonic-gate "INITCHILD: config regs setup for %s@%s\n", 853*0Sstevel@tonic-gate ddi_node_name(child), ddi_get_name_addr(child)); 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) { 856*0Sstevel@tonic-gate if (PM_CAPABLE(ppb->ppb_pwr_p)) { 857*0Sstevel@tonic-gate pci_pwr_rm_info(ppb->ppb_pwr_p, child); 858*0Sstevel@tonic-gate } 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate return (DDI_FAILURE); 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate /* 864*0Sstevel@tonic-gate * Determine the configuration header type. 865*0Sstevel@tonic-gate */ 866*0Sstevel@tonic-gate header_type = pci_config_get8(config_handle, PCI_CONF_HEADER); 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate /* 869*0Sstevel@tonic-gate * Support for the "command-preserve" property. 870*0Sstevel@tonic-gate */ 871*0Sstevel@tonic-gate command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child, 872*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "command-preserve", 0); 873*0Sstevel@tonic-gate command = pci_config_get16(config_handle, PCI_CONF_COMM); 874*0Sstevel@tonic-gate command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB); 875*0Sstevel@tonic-gate command |= (ppb_command_default & ~command_preserve); 876*0Sstevel@tonic-gate pci_config_put16(config_handle, PCI_CONF_COMM, command); 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate /* 879*0Sstevel@tonic-gate * If the device has a bus control register then program it 880*0Sstevel@tonic-gate * based on the settings in the command register. 881*0Sstevel@tonic-gate */ 882*0Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 883*0Sstevel@tonic-gate bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL); 884*0Sstevel@tonic-gate if (ppb_command_default & PCI_COMM_PARITY_DETECT) 885*0Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE; 886*0Sstevel@tonic-gate if (ppb_command_default & PCI_COMM_SERR_ENABLE) 887*0Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE; 888*0Sstevel@tonic-gate bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE; 889*0Sstevel@tonic-gate pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr); 890*0Sstevel@tonic-gate } 891*0Sstevel@tonic-gate 892*0Sstevel@tonic-gate /* 893*0Sstevel@tonic-gate * Initialize cache-line-size configuration register if needed. 894*0Sstevel@tonic-gate */ 895*0Sstevel@tonic-gate if (ppb_set_cache_line_size_register && 896*0Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 897*0Sstevel@tonic-gate "cache-line-size", 0) == 0) { 898*0Sstevel@tonic-gate pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ, 899*0Sstevel@tonic-gate ppb->ppb_cache_line_size); 900*0Sstevel@tonic-gate n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ); 901*0Sstevel@tonic-gate if (n != 0) { 902*0Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, child, 903*0Sstevel@tonic-gate "cache-line-size", n); 904*0Sstevel@tonic-gate } 905*0Sstevel@tonic-gate } 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate /* 908*0Sstevel@tonic-gate * Initialize latency timer configuration registers if needed. 909*0Sstevel@tonic-gate */ 910*0Sstevel@tonic-gate if (ppb_set_latency_timer_register && 911*0Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 912*0Sstevel@tonic-gate "latency-timer", 0) == 0) { 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 915*0Sstevel@tonic-gate latency_timer = ppb->ppb_latency_timer; 916*0Sstevel@tonic-gate pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER, 917*0Sstevel@tonic-gate ppb->ppb_latency_timer); 918*0Sstevel@tonic-gate } else { 919*0Sstevel@tonic-gate min_gnt = pci_config_get8(config_handle, 920*0Sstevel@tonic-gate PCI_CONF_MIN_G); 921*0Sstevel@tonic-gate latency_timer = min_gnt * 8; 922*0Sstevel@tonic-gate } 923*0Sstevel@tonic-gate pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER, 924*0Sstevel@tonic-gate latency_timer); 925*0Sstevel@tonic-gate n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER); 926*0Sstevel@tonic-gate if (n != 0) { 927*0Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, child, 928*0Sstevel@tonic-gate "latency-timer", n); 929*0Sstevel@tonic-gate } 930*0Sstevel@tonic-gate } 931*0Sstevel@tonic-gate 932*0Sstevel@tonic-gate /* 933*0Sstevel@tonic-gate * Check to see if the XMITS/PCI-X workaround applies. 934*0Sstevel@tonic-gate */ 935*0Sstevel@tonic-gate n = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_NOTPROM, 936*0Sstevel@tonic-gate "pcix-update-cmd-reg", -1); 937*0Sstevel@tonic-gate 938*0Sstevel@tonic-gate if (n != -1) { 939*0Sstevel@tonic-gate extern void pcix_set_cmd_reg(dev_info_t *child, uint16_t value); 940*0Sstevel@tonic-gate DEBUG1(DBG_INIT_CLD, child, "Turning on XMITS NCPQ " 941*0Sstevel@tonic-gate "Workaround: value = %x\n", n); 942*0Sstevel@tonic-gate pcix_set_cmd_reg(child, n); 943*0Sstevel@tonic-gate } 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate pci_config_teardown(&config_handle); 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate return (DDI_SUCCESS); 948*0Sstevel@tonic-gate } 949*0Sstevel@tonic-gate 950*0Sstevel@tonic-gate static void 951*0Sstevel@tonic-gate ppb_removechild(dev_info_t *dip) 952*0Sstevel@tonic-gate { 953*0Sstevel@tonic-gate ppb_devstate_t *ppb; 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 956*0Sstevel@tonic-gate ddi_get_instance(ddi_get_parent(dip))); 957*0Sstevel@tonic-gate 958*0Sstevel@tonic-gate if (PM_CAPABLE(ppb->ppb_pwr_p)) { 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate DEBUG2(DBG_PWR, ddi_get_parent(dip), 961*0Sstevel@tonic-gate "UNINITCHILD: removing pwr_info for %s@%s\n", 962*0Sstevel@tonic-gate ddi_node_name(dip), ddi_get_name_addr(dip)); 963*0Sstevel@tonic-gate pci_pwr_rm_info(ppb->ppb_pwr_p, dip); 964*0Sstevel@tonic-gate } 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate ddi_set_name_addr(dip, NULL); 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate /* 969*0Sstevel@tonic-gate * Strip the node to properly convert it back to prototype form 970*0Sstevel@tonic-gate */ 971*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate impl_rem_dev_props(dip); 974*0Sstevel@tonic-gate } 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate /* 977*0Sstevel@tonic-gate * If bridge is PM capable, set up PM state for nexus. 978*0Sstevel@tonic-gate */ 979*0Sstevel@tonic-gate static void 980*0Sstevel@tonic-gate ppb_pwr_setup(ppb_devstate_t *ppb, dev_info_t *pdip) 981*0Sstevel@tonic-gate { 982*0Sstevel@tonic-gate char *comp_array[5]; 983*0Sstevel@tonic-gate int i; 984*0Sstevel@tonic-gate ddi_acc_handle_t conf_hdl; 985*0Sstevel@tonic-gate uint8_t cap_ptr; 986*0Sstevel@tonic-gate uint8_t cap_id; 987*0Sstevel@tonic-gate uint8_t pmcsr_bse; 988*0Sstevel@tonic-gate uint16_t pmcap; 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate /* 991*0Sstevel@tonic-gate * Determine if bridge is PM capable. If not, leave ppb_pwr_p NULL 992*0Sstevel@tonic-gate * and return. 993*0Sstevel@tonic-gate */ 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate if (pci_config_setup(pdip, &ppb->ppb_conf_hdl) != DDI_SUCCESS) { 996*0Sstevel@tonic-gate 997*0Sstevel@tonic-gate return; 998*0Sstevel@tonic-gate } 999*0Sstevel@tonic-gate 1000*0Sstevel@tonic-gate conf_hdl = ppb->ppb_conf_hdl; 1001*0Sstevel@tonic-gate 1002*0Sstevel@tonic-gate cap_ptr = pci_config_get8(conf_hdl, PCI_BCNF_CAP_PTR); 1003*0Sstevel@tonic-gate 1004*0Sstevel@tonic-gate /* 1005*0Sstevel@tonic-gate * Walk the capabilities searching for a PM entry. 1006*0Sstevel@tonic-gate */ 1007*0Sstevel@tonic-gate while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 1008*0Sstevel@tonic-gate cap_id = pci_config_get8(conf_hdl, 1009*0Sstevel@tonic-gate cap_ptr + PCI_CAP_ID); 1010*0Sstevel@tonic-gate if (cap_id == PCI_CAP_ID_PM) { 1011*0Sstevel@tonic-gate break; 1012*0Sstevel@tonic-gate } 1013*0Sstevel@tonic-gate cap_ptr = pci_config_get8(conf_hdl, 1014*0Sstevel@tonic-gate cap_ptr + PCI_CAP_NEXT_PTR); 1015*0Sstevel@tonic-gate } 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate if (cap_ptr == 0) { 1018*0Sstevel@tonic-gate DEBUG0(DBG_PWR, pdip, "bridge does not support PM. PCI" 1019*0Sstevel@tonic-gate " PM data structure not found in config header\n"); 1020*0Sstevel@tonic-gate pci_config_teardown(&conf_hdl); 1021*0Sstevel@tonic-gate 1022*0Sstevel@tonic-gate return; 1023*0Sstevel@tonic-gate } 1024*0Sstevel@tonic-gate 1025*0Sstevel@tonic-gate /* 1026*0Sstevel@tonic-gate * Allocate PM state structure for ppb. 1027*0Sstevel@tonic-gate */ 1028*0Sstevel@tonic-gate ppb->ppb_pwr_p = (pci_pwr_t *) 1029*0Sstevel@tonic-gate kmem_zalloc(sizeof (pci_pwr_t), KM_SLEEP); 1030*0Sstevel@tonic-gate ppb->ppb_pwr_p->pwr_fp = 0; 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate /* 1033*0Sstevel@tonic-gate * Save offset to pmcsr for future references. 1034*0Sstevel@tonic-gate */ 1035*0Sstevel@tonic-gate ppb->ppb_pmcsr_offset = cap_ptr + PCI_PMCSR; 1036*0Sstevel@tonic-gate 1037*0Sstevel@tonic-gate pmcsr_bse = pci_config_get8(conf_hdl, cap_ptr + PCI_PMCSR_BSE); 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate pmcap = pci_config_get16(conf_hdl, cap_ptr + PCI_PMCAP); 1040*0Sstevel@tonic-gate 1041*0Sstevel@tonic-gate if (pmcap & PCI_PMCAP_D1) { 1042*0Sstevel@tonic-gate DEBUG0(DBG_PWR, pdip, "setup: B1 state supported\n"); 1043*0Sstevel@tonic-gate ppb->ppb_pwr_p->pwr_flags |= PCI_PWR_B1_CAPABLE; 1044*0Sstevel@tonic-gate } else { 1045*0Sstevel@tonic-gate DEBUG0(DBG_PWR, pdip, "setup: B1 state NOT supported\n"); 1046*0Sstevel@tonic-gate } 1047*0Sstevel@tonic-gate if (pmcap & PCI_PMCAP_D2) { 1048*0Sstevel@tonic-gate DEBUG0(DBG_PWR, pdip, "setup: B2 state supported\n"); 1049*0Sstevel@tonic-gate ppb->ppb_pwr_p->pwr_flags |= PCI_PWR_B2_CAPABLE; 1050*0Sstevel@tonic-gate } else { 1051*0Sstevel@tonic-gate DEBUG0(DBG_PWR, pdip, "setup: B2 via D2 NOT supported\n"); 1052*0Sstevel@tonic-gate } 1053*0Sstevel@tonic-gate 1054*0Sstevel@tonic-gate if (pmcsr_bse & PCI_PMCSR_BSE_BPCC_EN) { 1055*0Sstevel@tonic-gate DEBUG0(DBG_PWR, pdip, 1056*0Sstevel@tonic-gate "setup: bridge power/clock control enable\n"); 1057*0Sstevel@tonic-gate } else { 1058*0Sstevel@tonic-gate DEBUG0(DBG_PWR, pdip, 1059*0Sstevel@tonic-gate "setup: bridge power/clock control disabled\n"); 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate kmem_free(ppb->ppb_pwr_p, sizeof (pci_pwr_t)); 1062*0Sstevel@tonic-gate ppb->ppb_pwr_p = NULL; 1063*0Sstevel@tonic-gate pci_config_teardown(&conf_hdl); 1064*0Sstevel@tonic-gate 1065*0Sstevel@tonic-gate return; 1066*0Sstevel@tonic-gate } 1067*0Sstevel@tonic-gate 1068*0Sstevel@tonic-gate /* 1069*0Sstevel@tonic-gate * PCI states D0 and D3 always are supported for normal PCI 1070*0Sstevel@tonic-gate * devices. D1 and D2 are optional which are checked for above. 1071*0Sstevel@tonic-gate * Bridge function states D0-D3 correspond to secondary bus states 1072*0Sstevel@tonic-gate * B0-B3, EXCEPT if PCI_PMCSR_BSE_B2_B3 is set. In this case, setting 1073*0Sstevel@tonic-gate * the bridge function to D3 will set the bridge bus to state B2 instead 1074*0Sstevel@tonic-gate * of B3. D2 will not correspond to B2 (and in fact, probably 1075*0Sstevel@tonic-gate * won't be D2 capable). Implicitly, this means that if 1076*0Sstevel@tonic-gate * PCI_PMCSR_BSE_B2_B3 is set, the bus will not be B3 capable. 1077*0Sstevel@tonic-gate */ 1078*0Sstevel@tonic-gate if (pmcsr_bse & PCI_PMCSR_BSE_B2_B3) { 1079*0Sstevel@tonic-gate ppb->ppb_pwr_p->pwr_flags |= PCI_PWR_B2_CAPABLE; 1080*0Sstevel@tonic-gate DEBUG0(DBG_PWR, pdip, "B2 supported via D3\n"); 1081*0Sstevel@tonic-gate } else { 1082*0Sstevel@tonic-gate ppb->ppb_pwr_p->pwr_flags |= PCI_PWR_B3_CAPABLE; 1083*0Sstevel@tonic-gate DEBUG0(DBG_PWR, pdip, "B3 supported via D3\n"); 1084*0Sstevel@tonic-gate } 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate ppb->ppb_pwr_p->pwr_dip = pdip; 1087*0Sstevel@tonic-gate mutex_init(&ppb->ppb_pwr_p->pwr_mutex, NULL, MUTEX_DRIVER, NULL); 1088*0Sstevel@tonic-gate 1089*0Sstevel@tonic-gate i = 0; 1090*0Sstevel@tonic-gate comp_array[i++] = "NAME=PCI bridge PM"; 1091*0Sstevel@tonic-gate if (ppb->ppb_pwr_p->pwr_flags & PCI_PWR_B3_CAPABLE) { 1092*0Sstevel@tonic-gate comp_array[i++] = "0=Clock/Power Off (B3)"; 1093*0Sstevel@tonic-gate } 1094*0Sstevel@tonic-gate if (ppb->ppb_pwr_p->pwr_flags & PCI_PWR_B2_CAPABLE) { 1095*0Sstevel@tonic-gate comp_array[i++] = "1=Clock Off (B2)"; 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate if (ppb->ppb_pwr_p->pwr_flags & PCI_PWR_B1_CAPABLE) { 1098*0Sstevel@tonic-gate comp_array[i++] = "2=Bus Inactive (B1)"; 1099*0Sstevel@tonic-gate } 1100*0Sstevel@tonic-gate comp_array[i++] = "3=Full Power (B0)"; 1101*0Sstevel@tonic-gate 1102*0Sstevel@tonic-gate /* 1103*0Sstevel@tonic-gate * Create pm-components property. It does not already exist. 1104*0Sstevel@tonic-gate */ 1105*0Sstevel@tonic-gate if (ddi_prop_update_string_array(DDI_DEV_T_NONE, pdip, 1106*0Sstevel@tonic-gate "pm-components", comp_array, i) != DDI_PROP_SUCCESS) { 1107*0Sstevel@tonic-gate cmn_err(CE_WARN, 1108*0Sstevel@tonic-gate "%s%d pm-components prop update failed", 1109*0Sstevel@tonic-gate ddi_driver_name(pdip), ddi_get_instance(pdip)); 1110*0Sstevel@tonic-gate pci_config_teardown(&conf_hdl); 1111*0Sstevel@tonic-gate mutex_destroy(&ppb->ppb_pwr_p->pwr_mutex); 1112*0Sstevel@tonic-gate kmem_free(ppb->ppb_pwr_p, sizeof (pci_pwr_t)); 1113*0Sstevel@tonic-gate ppb->ppb_pwr_p = NULL; 1114*0Sstevel@tonic-gate 1115*0Sstevel@tonic-gate return; 1116*0Sstevel@tonic-gate } 1117*0Sstevel@tonic-gate 1118*0Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, pdip, DDI_PROP_CANSLEEP, 1119*0Sstevel@tonic-gate "pm-want-child-notification?", NULL, NULL) != DDI_PROP_SUCCESS) { 1120*0Sstevel@tonic-gate cmn_err(CE_WARN, 1121*0Sstevel@tonic-gate "%s%d fail to create pm-want-child-notification? prop", 1122*0Sstevel@tonic-gate ddi_driver_name(pdip), ddi_get_instance(pdip)); 1123*0Sstevel@tonic-gate 1124*0Sstevel@tonic-gate (void) ddi_prop_remove(DDI_DEV_T_NONE, pdip, "pm-components"); 1125*0Sstevel@tonic-gate pci_config_teardown(&conf_hdl); 1126*0Sstevel@tonic-gate mutex_destroy(&ppb->ppb_pwr_p->pwr_mutex); 1127*0Sstevel@tonic-gate kmem_free(ppb->ppb_pwr_p, sizeof (pci_pwr_t)); 1128*0Sstevel@tonic-gate ppb->ppb_pwr_p = NULL; 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate return; 1131*0Sstevel@tonic-gate } 1132*0Sstevel@tonic-gate 1133*0Sstevel@tonic-gate ppb->ppb_pwr_p->current_lvl = 1134*0Sstevel@tonic-gate pci_pwr_current_lvl(ppb->ppb_pwr_p); 1135*0Sstevel@tonic-gate } 1136*0Sstevel@tonic-gate 1137*0Sstevel@tonic-gate /* 1138*0Sstevel@tonic-gate * Remove PM state for nexus. 1139*0Sstevel@tonic-gate */ 1140*0Sstevel@tonic-gate static void 1141*0Sstevel@tonic-gate ppb_pwr_teardown(ppb_devstate_t *ppb, dev_info_t *dip) 1142*0Sstevel@tonic-gate { 1143*0Sstevel@tonic-gate int low_lvl; 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate /* 1146*0Sstevel@tonic-gate * Determine the lowest power level supported. 1147*0Sstevel@tonic-gate */ 1148*0Sstevel@tonic-gate if (ppb->ppb_pwr_p->pwr_flags & PCI_PWR_B3_CAPABLE) { 1149*0Sstevel@tonic-gate low_lvl = PM_LEVEL_B3; 1150*0Sstevel@tonic-gate } else { 1151*0Sstevel@tonic-gate low_lvl = PM_LEVEL_B2; 1152*0Sstevel@tonic-gate } 1153*0Sstevel@tonic-gate 1154*0Sstevel@tonic-gate if (pm_lower_power(dip, PCI_PM_COMP_0, low_lvl) != DDI_SUCCESS) { 1155*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d failed to lower power", 1156*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1157*0Sstevel@tonic-gate } 1158*0Sstevel@tonic-gate 1159*0Sstevel@tonic-gate pci_config_teardown(&ppb->ppb_conf_hdl); 1160*0Sstevel@tonic-gate mutex_destroy(&ppb->ppb_pwr_p->pwr_mutex); 1161*0Sstevel@tonic-gate kmem_free(ppb->ppb_pwr_p, sizeof (pci_pwr_t)); 1162*0Sstevel@tonic-gate 1163*0Sstevel@tonic-gate if (ddi_prop_remove(DDI_DEV_T_NONE, dip, "pm-components") != 1164*0Sstevel@tonic-gate DDI_PROP_SUCCESS) { 1165*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d unable to remove prop pm-components", 1166*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1167*0Sstevel@tonic-gate } 1168*0Sstevel@tonic-gate 1169*0Sstevel@tonic-gate if (ddi_prop_remove(DDI_DEV_T_NONE, dip, 1170*0Sstevel@tonic-gate "pm-want-child-notification?") != DDI_PROP_SUCCESS) { 1171*0Sstevel@tonic-gate cmn_err(CE_WARN, 1172*0Sstevel@tonic-gate "%s%d unable to remove prop pm-want_child_notification?", 1173*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1174*0Sstevel@tonic-gate } 1175*0Sstevel@tonic-gate } 1176*0Sstevel@tonic-gate 1177*0Sstevel@tonic-gate /* 1178*0Sstevel@tonic-gate * Examine the pmcsr register and return the software defined 1179*0Sstevel@tonic-gate * state (the difference being whether D3 means B2 or B3). 1180*0Sstevel@tonic-gate */ 1181*0Sstevel@tonic-gate int 1182*0Sstevel@tonic-gate pci_pwr_current_lvl(pci_pwr_t *pwr_p) 1183*0Sstevel@tonic-gate { 1184*0Sstevel@tonic-gate ppb_devstate_t *ppb; 1185*0Sstevel@tonic-gate uint16_t pmcsr; 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate /* 1188*0Sstevel@tonic-gate * Find out current power level 1189*0Sstevel@tonic-gate */ 1190*0Sstevel@tonic-gate ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 1191*0Sstevel@tonic-gate ddi_get_instance(pwr_p->pwr_dip)); 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate pmcsr = pci_config_get16(ppb->ppb_conf_hdl, 1194*0Sstevel@tonic-gate ppb->ppb_pmcsr_offset); 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate switch (pmcsr & PCI_PMCSR_STATE_MASK) { 1197*0Sstevel@tonic-gate case PCI_PMCSR_D0: 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate return (PM_LEVEL_B0); 1200*0Sstevel@tonic-gate case PCI_PMCSR_D1: 1201*0Sstevel@tonic-gate 1202*0Sstevel@tonic-gate return (PM_LEVEL_B1); 1203*0Sstevel@tonic-gate case PCI_PMCSR_D2: 1204*0Sstevel@tonic-gate 1205*0Sstevel@tonic-gate return (PM_LEVEL_B2); 1206*0Sstevel@tonic-gate case PCI_PMCSR_D3HOT: 1207*0Sstevel@tonic-gate if ((ppb->ppb_pwr_p->pwr_flags & PCI_PWR_B3_CAPABLE) == 0) { 1208*0Sstevel@tonic-gate 1209*0Sstevel@tonic-gate return (PM_LEVEL_B2); 1210*0Sstevel@tonic-gate } else { 1211*0Sstevel@tonic-gate 1212*0Sstevel@tonic-gate return (PM_LEVEL_B3); 1213*0Sstevel@tonic-gate } 1214*0Sstevel@tonic-gate } 1215*0Sstevel@tonic-gate /*NOTREACHED*/ 1216*0Sstevel@tonic-gate } 1217*0Sstevel@tonic-gate 1218*0Sstevel@tonic-gate /* 1219*0Sstevel@tonic-gate * Power entry point. Called by the PM framework to change the 1220*0Sstevel@tonic-gate * current power state of the bus. This function must first verify that 1221*0Sstevel@tonic-gate * the requested power change is still valid. 1222*0Sstevel@tonic-gate */ 1223*0Sstevel@tonic-gate /*ARGSUSED*/ 1224*0Sstevel@tonic-gate static int 1225*0Sstevel@tonic-gate ppb_pwr(dev_info_t *dip, int component, int lvl) 1226*0Sstevel@tonic-gate { 1227*0Sstevel@tonic-gate ppb_devstate_t *ppb; 1228*0Sstevel@tonic-gate uint16_t pmcsr; 1229*0Sstevel@tonic-gate char *str; 1230*0Sstevel@tonic-gate int lowest_lvl; 1231*0Sstevel@tonic-gate int old_lvl; 1232*0Sstevel@tonic-gate int new_lvl; 1233*0Sstevel@tonic-gate 1234*0Sstevel@tonic-gate ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 1235*0Sstevel@tonic-gate ddi_get_instance(dip)); 1236*0Sstevel@tonic-gate if (ppb == NULL) { 1237*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d ppb_pwr: can't get soft state", 1238*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate return (DDI_FAILURE); 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate 1243*0Sstevel@tonic-gate DEBUG1(DBG_PWR, dip, "ppb_pwr(): ENTER level = %d\n", lvl); 1244*0Sstevel@tonic-gate 1245*0Sstevel@tonic-gate mutex_enter(&ppb->ppb_pwr_p->pwr_mutex); 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate /* 1248*0Sstevel@tonic-gate * Find out if the power setting is possible. If it is not, 1249*0Sstevel@tonic-gate * set component busy and return failure. If it is possible, 1250*0Sstevel@tonic-gate * and it is the lowest pwr setting possible, set component 1251*0Sstevel@tonic-gate * busy so that the framework does not try to lower any further. 1252*0Sstevel@tonic-gate */ 1253*0Sstevel@tonic-gate lowest_lvl = pci_pwr_new_lvl(ppb->ppb_pwr_p); 1254*0Sstevel@tonic-gate if (lowest_lvl > lvl) { 1255*0Sstevel@tonic-gate pci_pwr_component_busy(ppb->ppb_pwr_p); 1256*0Sstevel@tonic-gate DEBUG2(DBG_PWR, dip, "ppb_pwr: failing power request " 1257*0Sstevel@tonic-gate "lowest allowed is %d requested is %d\n", 1258*0Sstevel@tonic-gate lowest_lvl, lvl); 1259*0Sstevel@tonic-gate mutex_exit(&ppb->ppb_pwr_p->pwr_mutex); 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate return (DDI_FAILURE); 1262*0Sstevel@tonic-gate } else if (lowest_lvl == lvl) { 1263*0Sstevel@tonic-gate pci_pwr_component_busy(ppb->ppb_pwr_p); 1264*0Sstevel@tonic-gate } else { 1265*0Sstevel@tonic-gate pci_pwr_component_idle(ppb->ppb_pwr_p); 1266*0Sstevel@tonic-gate } 1267*0Sstevel@tonic-gate 1268*0Sstevel@tonic-gate pmcsr = pci_config_get16(ppb->ppb_conf_hdl, ppb->ppb_pmcsr_offset); 1269*0Sstevel@tonic-gate 1270*0Sstevel@tonic-gate /* 1271*0Sstevel@tonic-gate * Save the current power level. This is the actual function level, 1272*0Sstevel@tonic-gate * not the translated bridge level stored in pwr_p->current_lvl 1273*0Sstevel@tonic-gate */ 1274*0Sstevel@tonic-gate old_lvl = pmcsr & PCI_PMCSR_STATE_MASK; 1275*0Sstevel@tonic-gate 1276*0Sstevel@tonic-gate pmcsr &= ~PCI_PMCSR_STATE_MASK; 1277*0Sstevel@tonic-gate switch (lvl) { 1278*0Sstevel@tonic-gate case PM_LEVEL_B0: 1279*0Sstevel@tonic-gate str = "PM_LEVEL_B0 (full speed)"; 1280*0Sstevel@tonic-gate pmcsr |= PCI_PMCSR_D0; 1281*0Sstevel@tonic-gate break; 1282*0Sstevel@tonic-gate case PM_LEVEL_B1: 1283*0Sstevel@tonic-gate str = "PM_LEVEL_B1 (light sleep. No bus traffic allowed)"; 1284*0Sstevel@tonic-gate if ((ppb->ppb_pwr_p->pwr_flags & PCI_PWR_B1_CAPABLE) == 0) { 1285*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d PCI PM state B1 not supported", 1286*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1287*0Sstevel@tonic-gate 1288*0Sstevel@tonic-gate mutex_exit(&ppb->ppb_pwr_p->pwr_mutex); 1289*0Sstevel@tonic-gate return (DDI_FAILURE); 1290*0Sstevel@tonic-gate } 1291*0Sstevel@tonic-gate pmcsr |= PCI_PMCSR_D1; 1292*0Sstevel@tonic-gate break; 1293*0Sstevel@tonic-gate case PM_LEVEL_B2: 1294*0Sstevel@tonic-gate str = "PM_LEVEL_B2 (clock off)"; 1295*0Sstevel@tonic-gate if ((ppb->ppb_pwr_p->pwr_flags & PCI_PWR_B2_CAPABLE) == 0) { 1296*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d PM state B2 not supported...", 1297*0Sstevel@tonic-gate ddi_driver_name(dip), 1298*0Sstevel@tonic-gate ddi_get_instance(dip)); 1299*0Sstevel@tonic-gate mutex_exit(&ppb->ppb_pwr_p->pwr_mutex); 1300*0Sstevel@tonic-gate 1301*0Sstevel@tonic-gate return (DDI_FAILURE); 1302*0Sstevel@tonic-gate } 1303*0Sstevel@tonic-gate 1304*0Sstevel@tonic-gate if ((ppb->ppb_pwr_p->pwr_flags & PCI_PWR_B3_CAPABLE) == 0) { 1305*0Sstevel@tonic-gate /* 1306*0Sstevel@tonic-gate * If B3 isn't supported, use D3 for B2 to avoid the 1307*0Sstevel@tonic-gate * possible case that D2 for B2 isn't supported. 1308*0Sstevel@tonic-gate * Saves and extra check and state flag.. 1309*0Sstevel@tonic-gate */ 1310*0Sstevel@tonic-gate pmcsr |= PCI_PMCSR_D3HOT; 1311*0Sstevel@tonic-gate } else { 1312*0Sstevel@tonic-gate pmcsr |= PCI_PMCSR_D2; 1313*0Sstevel@tonic-gate } 1314*0Sstevel@tonic-gate break; 1315*0Sstevel@tonic-gate case PM_LEVEL_B3: 1316*0Sstevel@tonic-gate str = "PM_LEVEL_B30 (clock and power off)"; 1317*0Sstevel@tonic-gate if ((ppb->ppb_pwr_p->pwr_flags & PCI_PWR_B3_CAPABLE) == 0) { 1318*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d PM state B3 not supported...", 1319*0Sstevel@tonic-gate ddi_driver_name(dip), 1320*0Sstevel@tonic-gate ddi_get_instance(dip)); 1321*0Sstevel@tonic-gate mutex_exit(&ppb->ppb_pwr_p->pwr_mutex); 1322*0Sstevel@tonic-gate 1323*0Sstevel@tonic-gate return (DDI_FAILURE); 1324*0Sstevel@tonic-gate } 1325*0Sstevel@tonic-gate pmcsr |= PCI_PMCSR_D3HOT; 1326*0Sstevel@tonic-gate 1327*0Sstevel@tonic-gate break; 1328*0Sstevel@tonic-gate 1329*0Sstevel@tonic-gate default: 1330*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d Unknown PM state %d", 1331*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip), lvl); 1332*0Sstevel@tonic-gate mutex_exit(&ppb->ppb_pwr_p->pwr_mutex); 1333*0Sstevel@tonic-gate 1334*0Sstevel@tonic-gate return (DDI_FAILURE); 1335*0Sstevel@tonic-gate } 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate new_lvl = pmcsr & PCI_PMCSR_STATE_MASK; 1338*0Sstevel@tonic-gate 1339*0Sstevel@tonic-gate /* 1340*0Sstevel@tonic-gate * Save config regs if going into HW state D3 (B2 or B3) 1341*0Sstevel@tonic-gate */ 1342*0Sstevel@tonic-gate if ((old_lvl != PCI_PMCSR_D3HOT) && (new_lvl == PCI_PMCSR_D3HOT)) { 1343*0Sstevel@tonic-gate DEBUG0(DBG_PWR, dip, "ppb_pwr(): SAVING CONFIG REGS\n"); 1344*0Sstevel@tonic-gate if (pci_save_config_regs(dip) != DDI_SUCCESS) { 1345*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d Save config regs failed", 1346*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1347*0Sstevel@tonic-gate mutex_exit(&ppb->ppb_pwr_p->pwr_mutex); 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate return (DDI_FAILURE); 1350*0Sstevel@tonic-gate } 1351*0Sstevel@tonic-gate } 1352*0Sstevel@tonic-gate 1353*0Sstevel@tonic-gate pci_config_put16(ppb->ppb_conf_hdl, ppb->ppb_pmcsr_offset, pmcsr); 1354*0Sstevel@tonic-gate 1355*0Sstevel@tonic-gate /* 1356*0Sstevel@tonic-gate * No bus transactions should occur without waiting for 1357*0Sstevel@tonic-gate * settle time specified in PCI PM spec rev 2.1 sec 5.6.1 1358*0Sstevel@tonic-gate * To make things simple, just use the max time specified for 1359*0Sstevel@tonic-gate * all state transitions. 1360*0Sstevel@tonic-gate */ 1361*0Sstevel@tonic-gate delay(drv_usectohz(PCI_CLK_SETTLE_TIME)); 1362*0Sstevel@tonic-gate 1363*0Sstevel@tonic-gate /* 1364*0Sstevel@tonic-gate * Restore configuration registers if coming out of HW state D3 1365*0Sstevel@tonic-gate */ 1366*0Sstevel@tonic-gate if ((old_lvl == PCI_PMCSR_D3HOT) && (new_lvl != PCI_PMCSR_D3HOT)) { 1367*0Sstevel@tonic-gate DEBUG0(DBG_PWR, dip, "ppb_pwr(): RESTORING CONFIG REGS\n"); 1368*0Sstevel@tonic-gate if (pci_restore_config_regs(dip) != DDI_SUCCESS) { 1369*0Sstevel@tonic-gate panic("%s%d restore config regs failed", 1370*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 1371*0Sstevel@tonic-gate } 1372*0Sstevel@tonic-gate /*NOTREACHED*/ 1373*0Sstevel@tonic-gate } 1374*0Sstevel@tonic-gate 1375*0Sstevel@tonic-gate ppb->ppb_pwr_p->current_lvl = lvl; 1376*0Sstevel@tonic-gate 1377*0Sstevel@tonic-gate mutex_exit(&ppb->ppb_pwr_p->pwr_mutex); 1378*0Sstevel@tonic-gate 1379*0Sstevel@tonic-gate DEBUG1(DBG_PWR, dip, "ppb_set_pwr: set PM state to %s\n\n", str); 1380*0Sstevel@tonic-gate 1381*0Sstevel@tonic-gate return (DDI_SUCCESS); 1382*0Sstevel@tonic-gate } 1383*0Sstevel@tonic-gate 1384*0Sstevel@tonic-gate /* 1385*0Sstevel@tonic-gate * Initialize hotplug framework if we are hotpluggable. 1386*0Sstevel@tonic-gate * Sets flag in the soft state if Hot Plug is supported and initialized 1387*0Sstevel@tonic-gate * properly. 1388*0Sstevel@tonic-gate */ 1389*0Sstevel@tonic-gate /*ARGSUSED*/ 1390*0Sstevel@tonic-gate static void 1391*0Sstevel@tonic-gate ppb_init_hotplug(ppb_devstate_t *ppb) 1392*0Sstevel@tonic-gate { 1393*0Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, ppb->dip, DDI_PROP_DONTPASS, 1394*0Sstevel@tonic-gate "hotplug-capable")) { 1395*0Sstevel@tonic-gate (void) modload("misc", "pcihp"); 1396*0Sstevel@tonic-gate 1397*0Sstevel@tonic-gate if (pcihp_init(ppb->dip) != DDI_SUCCESS) { 1398*0Sstevel@tonic-gate cmn_err(CE_WARN, 1399*0Sstevel@tonic-gate "%s #%d: Failed setting hotplug framework", 1400*0Sstevel@tonic-gate ddi_driver_name(ppb->dip), 1401*0Sstevel@tonic-gate ddi_get_instance(ppb->dip)); 1402*0Sstevel@tonic-gate } else 1403*0Sstevel@tonic-gate ppb->hotplug_capable = B_TRUE; 1404*0Sstevel@tonic-gate } 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate } 1407*0Sstevel@tonic-gate 1408*0Sstevel@tonic-gate static void 1409*0Sstevel@tonic-gate ppb_create_ranges_prop(dev_info_t *dip, 1410*0Sstevel@tonic-gate ddi_acc_handle_t config_handle) 1411*0Sstevel@tonic-gate { 1412*0Sstevel@tonic-gate uint32_t base, limit; 1413*0Sstevel@tonic-gate ppb_ranges_t ranges[PPB_RANGE_LEN]; 1414*0Sstevel@tonic-gate uint8_t io_base_lo, io_limit_lo; 1415*0Sstevel@tonic-gate uint16_t io_base_hi, io_limit_hi, mem_base, mem_limit; 1416*0Sstevel@tonic-gate int i = 0, rangelen = sizeof (ppb_ranges_t)/sizeof (int); 1417*0Sstevel@tonic-gate 1418*0Sstevel@tonic-gate io_base_lo = pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW); 1419*0Sstevel@tonic-gate io_limit_lo = pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW); 1420*0Sstevel@tonic-gate io_base_hi = pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI); 1421*0Sstevel@tonic-gate io_limit_hi = pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI); 1422*0Sstevel@tonic-gate mem_base = pci_config_get16(config_handle, PCI_BCNF_MEM_BASE); 1423*0Sstevel@tonic-gate mem_limit = pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT); 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate /* 1426*0Sstevel@tonic-gate * Create ranges for IO space 1427*0Sstevel@tonic-gate */ 1428*0Sstevel@tonic-gate ranges[i].size_low = ranges[i].size_high = 0; 1429*0Sstevel@tonic-gate ranges[i].parent_mid = ranges[i].child_mid = 1430*0Sstevel@tonic-gate ranges[i].parent_high = 0; 1431*0Sstevel@tonic-gate ranges[i].child_high = ranges[i].parent_high |= 1432*0Sstevel@tonic-gate (PCI_REG_REL_M | PCI_ADDR_IO); 1433*0Sstevel@tonic-gate base = PPB_16bit_IOADDR(io_base_lo); 1434*0Sstevel@tonic-gate limit = PPB_16bit_IOADDR(io_limit_lo); 1435*0Sstevel@tonic-gate 1436*0Sstevel@tonic-gate if ((io_base_lo & 0xf) == PPB_32BIT_IO) { 1437*0Sstevel@tonic-gate base = PPB_LADDR(base, io_base_hi); 1438*0Sstevel@tonic-gate } 1439*0Sstevel@tonic-gate if ((io_limit_lo & 0xf) == PPB_32BIT_IO) { 1440*0Sstevel@tonic-gate limit = PPB_LADDR(limit, io_limit_hi); 1441*0Sstevel@tonic-gate } 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate if ((io_base_lo & PPB_32BIT_IO) && (io_limit_hi > 0)) { 1444*0Sstevel@tonic-gate base = PPB_LADDR(base, io_base_hi); 1445*0Sstevel@tonic-gate limit = PPB_LADDR(limit, io_limit_hi); 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate /* 1449*0Sstevel@tonic-gate * Create ranges for 32bit memory space 1450*0Sstevel@tonic-gate */ 1451*0Sstevel@tonic-gate base = PPB_32bit_MEMADDR(mem_base); 1452*0Sstevel@tonic-gate limit = PPB_32bit_MEMADDR(mem_limit); 1453*0Sstevel@tonic-gate ranges[i].size_low = ranges[i].size_high = 0; 1454*0Sstevel@tonic-gate ranges[i].parent_mid = ranges[i].child_mid = 1455*0Sstevel@tonic-gate ranges[i].parent_high = 0; 1456*0Sstevel@tonic-gate ranges[i].child_high = ranges[i].parent_high |= 1457*0Sstevel@tonic-gate (PCI_REG_REL_M | PCI_ADDR_MEM32); 1458*0Sstevel@tonic-gate ranges[i].child_low = ranges[i].parent_low = base; 1459*0Sstevel@tonic-gate if (limit >= base) { 1460*0Sstevel@tonic-gate ranges[i].size_low = limit - base + PPB_MEMGRAIN; 1461*0Sstevel@tonic-gate i++; 1462*0Sstevel@tonic-gate } 1463*0Sstevel@tonic-gate 1464*0Sstevel@tonic-gate if (i) { 1465*0Sstevel@tonic-gate (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges", 1466*0Sstevel@tonic-gate (int *)ranges, i * rangelen); 1467*0Sstevel@tonic-gate } 1468*0Sstevel@tonic-gate } 1469*0Sstevel@tonic-gate 1470*0Sstevel@tonic-gate /* ARGSUSED */ 1471*0Sstevel@tonic-gate static int 1472*0Sstevel@tonic-gate ppb_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1473*0Sstevel@tonic-gate { 1474*0Sstevel@tonic-gate ppb_devstate_t *ppb_p; 1475*0Sstevel@tonic-gate minor_t minor = getminor(*devp); 1476*0Sstevel@tonic-gate int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 1477*0Sstevel@tonic-gate 1478*0Sstevel@tonic-gate /* 1479*0Sstevel@tonic-gate * Make sure the open is for the right file type. 1480*0Sstevel@tonic-gate */ 1481*0Sstevel@tonic-gate if (otyp != OTYP_CHR) 1482*0Sstevel@tonic-gate return (EINVAL); 1483*0Sstevel@tonic-gate 1484*0Sstevel@tonic-gate /* 1485*0Sstevel@tonic-gate * Get the soft state structure for the device. 1486*0Sstevel@tonic-gate */ 1487*0Sstevel@tonic-gate ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 1488*0Sstevel@tonic-gate instance); 1489*0Sstevel@tonic-gate 1490*0Sstevel@tonic-gate if (ppb_p == NULL) 1491*0Sstevel@tonic-gate return (ENXIO); 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate if (ppb_p->hotplug_capable == B_TRUE) 1494*0Sstevel@tonic-gate return ((pcihp_get_cb_ops())->cb_open(devp, flags, 1495*0Sstevel@tonic-gate otyp, credp)); 1496*0Sstevel@tonic-gate 1497*0Sstevel@tonic-gate /* 1498*0Sstevel@tonic-gate * Handle the open by tracking the device state. 1499*0Sstevel@tonic-gate */ 1500*0Sstevel@tonic-gate mutex_enter(&ppb_p->ppb_mutex); 1501*0Sstevel@tonic-gate if (flags & FEXCL) { 1502*0Sstevel@tonic-gate if (ppb_p->ppb_soft_state != PPB_SOFT_STATE_CLOSED) { 1503*0Sstevel@tonic-gate mutex_exit(&ppb_p->ppb_mutex); 1504*0Sstevel@tonic-gate return (EBUSY); 1505*0Sstevel@tonic-gate } 1506*0Sstevel@tonic-gate ppb_p->ppb_soft_state = PPB_SOFT_STATE_OPEN_EXCL; 1507*0Sstevel@tonic-gate } else { 1508*0Sstevel@tonic-gate if (ppb_p->ppb_soft_state == PPB_SOFT_STATE_OPEN_EXCL) { 1509*0Sstevel@tonic-gate mutex_exit(&ppb_p->ppb_mutex); 1510*0Sstevel@tonic-gate return (EBUSY); 1511*0Sstevel@tonic-gate } 1512*0Sstevel@tonic-gate ppb_p->ppb_soft_state = PPB_SOFT_STATE_OPEN; 1513*0Sstevel@tonic-gate } 1514*0Sstevel@tonic-gate mutex_exit(&ppb_p->ppb_mutex); 1515*0Sstevel@tonic-gate return (0); 1516*0Sstevel@tonic-gate } 1517*0Sstevel@tonic-gate 1518*0Sstevel@tonic-gate 1519*0Sstevel@tonic-gate /* ARGSUSED */ 1520*0Sstevel@tonic-gate static int 1521*0Sstevel@tonic-gate ppb_close(dev_t dev, int flags, int otyp, cred_t *credp) 1522*0Sstevel@tonic-gate { 1523*0Sstevel@tonic-gate ppb_devstate_t *ppb_p; 1524*0Sstevel@tonic-gate minor_t minor = getminor(dev); 1525*0Sstevel@tonic-gate int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 1526*0Sstevel@tonic-gate 1527*0Sstevel@tonic-gate if (otyp != OTYP_CHR) 1528*0Sstevel@tonic-gate return (EINVAL); 1529*0Sstevel@tonic-gate 1530*0Sstevel@tonic-gate ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 1531*0Sstevel@tonic-gate instance); 1532*0Sstevel@tonic-gate 1533*0Sstevel@tonic-gate if (ppb_p == NULL) 1534*0Sstevel@tonic-gate return (ENXIO); 1535*0Sstevel@tonic-gate 1536*0Sstevel@tonic-gate if (ppb_p->hotplug_capable == B_TRUE) 1537*0Sstevel@tonic-gate return ((pcihp_get_cb_ops())->cb_close(dev, flags, 1538*0Sstevel@tonic-gate otyp, credp)); 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate mutex_enter(&ppb_p->ppb_mutex); 1541*0Sstevel@tonic-gate ppb_p->ppb_soft_state = PPB_SOFT_STATE_CLOSED; 1542*0Sstevel@tonic-gate mutex_exit(&ppb_p->ppb_mutex); 1543*0Sstevel@tonic-gate return (0); 1544*0Sstevel@tonic-gate } 1545*0Sstevel@tonic-gate 1546*0Sstevel@tonic-gate 1547*0Sstevel@tonic-gate /* 1548*0Sstevel@tonic-gate * ppb_ioctl: devctl hotplug controls 1549*0Sstevel@tonic-gate */ 1550*0Sstevel@tonic-gate /* ARGSUSED */ 1551*0Sstevel@tonic-gate static int 1552*0Sstevel@tonic-gate ppb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1553*0Sstevel@tonic-gate int *rvalp) 1554*0Sstevel@tonic-gate { 1555*0Sstevel@tonic-gate ppb_devstate_t *ppb_p; 1556*0Sstevel@tonic-gate dev_info_t *self; 1557*0Sstevel@tonic-gate struct devctl_iocdata *dcp; 1558*0Sstevel@tonic-gate uint_t bus_state; 1559*0Sstevel@tonic-gate int rv = 0; 1560*0Sstevel@tonic-gate minor_t minor = getminor(dev); 1561*0Sstevel@tonic-gate int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 1562*0Sstevel@tonic-gate 1563*0Sstevel@tonic-gate ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 1564*0Sstevel@tonic-gate instance); 1565*0Sstevel@tonic-gate 1566*0Sstevel@tonic-gate if (ppb_p == NULL) 1567*0Sstevel@tonic-gate return (ENXIO); 1568*0Sstevel@tonic-gate 1569*0Sstevel@tonic-gate if (ppb_p->hotplug_capable == B_TRUE) 1570*0Sstevel@tonic-gate return ((pcihp_get_cb_ops())->cb_ioctl(dev, cmd, 1571*0Sstevel@tonic-gate arg, mode, credp, rvalp)); 1572*0Sstevel@tonic-gate 1573*0Sstevel@tonic-gate self = ppb_p->dip; 1574*0Sstevel@tonic-gate 1575*0Sstevel@tonic-gate /* 1576*0Sstevel@tonic-gate * We can use the generic implementation for these ioctls 1577*0Sstevel@tonic-gate */ 1578*0Sstevel@tonic-gate switch (cmd) { 1579*0Sstevel@tonic-gate case DEVCTL_DEVICE_GETSTATE: 1580*0Sstevel@tonic-gate case DEVCTL_DEVICE_ONLINE: 1581*0Sstevel@tonic-gate case DEVCTL_DEVICE_OFFLINE: 1582*0Sstevel@tonic-gate case DEVCTL_BUS_GETSTATE: 1583*0Sstevel@tonic-gate return (ndi_devctl_ioctl(self, cmd, arg, mode, 0)); 1584*0Sstevel@tonic-gate } 1585*0Sstevel@tonic-gate 1586*0Sstevel@tonic-gate /* 1587*0Sstevel@tonic-gate * read devctl ioctl data 1588*0Sstevel@tonic-gate */ 1589*0Sstevel@tonic-gate if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 1590*0Sstevel@tonic-gate return (EFAULT); 1591*0Sstevel@tonic-gate 1592*0Sstevel@tonic-gate switch (cmd) { 1593*0Sstevel@tonic-gate 1594*0Sstevel@tonic-gate case DEVCTL_DEVICE_RESET: 1595*0Sstevel@tonic-gate rv = ENOTSUP; 1596*0Sstevel@tonic-gate break; 1597*0Sstevel@tonic-gate 1598*0Sstevel@tonic-gate case DEVCTL_BUS_QUIESCE: 1599*0Sstevel@tonic-gate if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 1600*0Sstevel@tonic-gate if (bus_state == BUS_QUIESCED) 1601*0Sstevel@tonic-gate break; 1602*0Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_QUIESCED); 1603*0Sstevel@tonic-gate break; 1604*0Sstevel@tonic-gate 1605*0Sstevel@tonic-gate case DEVCTL_BUS_UNQUIESCE: 1606*0Sstevel@tonic-gate if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS) 1607*0Sstevel@tonic-gate if (bus_state == BUS_ACTIVE) 1608*0Sstevel@tonic-gate break; 1609*0Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_ACTIVE); 1610*0Sstevel@tonic-gate break; 1611*0Sstevel@tonic-gate 1612*0Sstevel@tonic-gate case DEVCTL_BUS_RESET: 1613*0Sstevel@tonic-gate rv = ENOTSUP; 1614*0Sstevel@tonic-gate break; 1615*0Sstevel@tonic-gate 1616*0Sstevel@tonic-gate case DEVCTL_BUS_RESETALL: 1617*0Sstevel@tonic-gate rv = ENOTSUP; 1618*0Sstevel@tonic-gate break; 1619*0Sstevel@tonic-gate 1620*0Sstevel@tonic-gate default: 1621*0Sstevel@tonic-gate rv = ENOTTY; 1622*0Sstevel@tonic-gate } 1623*0Sstevel@tonic-gate 1624*0Sstevel@tonic-gate ndi_dc_freehdl(dcp); 1625*0Sstevel@tonic-gate return (rv); 1626*0Sstevel@tonic-gate } 1627*0Sstevel@tonic-gate 1628*0Sstevel@tonic-gate static int ppb_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 1629*0Sstevel@tonic-gate int flags, char *name, caddr_t valuep, int *lengthp) 1630*0Sstevel@tonic-gate { 1631*0Sstevel@tonic-gate ppb_devstate_t *ppb_p; 1632*0Sstevel@tonic-gate minor_t minor = getminor(dev); 1633*0Sstevel@tonic-gate int instance = PCIHP_AP_MINOR_NUM_TO_INSTANCE(minor); 1634*0Sstevel@tonic-gate 1635*0Sstevel@tonic-gate ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 1636*0Sstevel@tonic-gate instance); 1637*0Sstevel@tonic-gate 1638*0Sstevel@tonic-gate if (ppb_p == NULL) 1639*0Sstevel@tonic-gate return (ENXIO); 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate if (ppb_p->hotplug_capable == B_TRUE) 1642*0Sstevel@tonic-gate return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip, prop_op, 1643*0Sstevel@tonic-gate flags, name, valuep, lengthp)); 1644*0Sstevel@tonic-gate 1645*0Sstevel@tonic-gate return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); 1646*0Sstevel@tonic-gate } 1647*0Sstevel@tonic-gate 1648*0Sstevel@tonic-gate /* 1649*0Sstevel@tonic-gate * Initialize our FMA resources 1650*0Sstevel@tonic-gate */ 1651*0Sstevel@tonic-gate static void 1652*0Sstevel@tonic-gate ppb_fm_init(ppb_devstate_t *ppb_p) 1653*0Sstevel@tonic-gate { 1654*0Sstevel@tonic-gate ddi_fm_error_t derr; 1655*0Sstevel@tonic-gate 1656*0Sstevel@tonic-gate ppb_p->fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE | 1657*0Sstevel@tonic-gate DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; 1658*0Sstevel@tonic-gate 1659*0Sstevel@tonic-gate /* 1660*0Sstevel@tonic-gate * Request our capability level and get our parents capability 1661*0Sstevel@tonic-gate * and ibc. 1662*0Sstevel@tonic-gate */ 1663*0Sstevel@tonic-gate ddi_fm_init(ppb_p->dip, &ppb_p->fm_cap, &ppb_p->fm_ibc); 1664*0Sstevel@tonic-gate ASSERT((ppb_p->fm_cap & DDI_FM_EREPORT_CAPABLE) && 1665*0Sstevel@tonic-gate (ppb_p->fm_cap & DDI_FM_ERRCB_CAPABLE)); 1666*0Sstevel@tonic-gate 1667*0Sstevel@tonic-gate pci_ereport_setup(ppb_p->dip); 1668*0Sstevel@tonic-gate 1669*0Sstevel@tonic-gate /* 1670*0Sstevel@tonic-gate * clear any outstanding error bits 1671*0Sstevel@tonic-gate */ 1672*0Sstevel@tonic-gate bzero(&derr, sizeof (ddi_fm_error_t)); 1673*0Sstevel@tonic-gate derr.fme_version = DDI_FME_VERSION; 1674*0Sstevel@tonic-gate derr.fme_flag = DDI_FM_ERR_EXPECTED; 1675*0Sstevel@tonic-gate pci_ereport_post(ppb_p->dip, &derr, NULL); 1676*0Sstevel@tonic-gate pci_bdg_ereport_post(ppb_p->dip, &derr, NULL); 1677*0Sstevel@tonic-gate 1678*0Sstevel@tonic-gate /* 1679*0Sstevel@tonic-gate * Register error callback with our parent. 1680*0Sstevel@tonic-gate */ 1681*0Sstevel@tonic-gate ddi_fm_handler_register(ppb_p->dip, ppb_err_callback, NULL); 1682*0Sstevel@tonic-gate } 1683*0Sstevel@tonic-gate 1684*0Sstevel@tonic-gate /* 1685*0Sstevel@tonic-gate * Breakdown our FMA resources 1686*0Sstevel@tonic-gate */ 1687*0Sstevel@tonic-gate static void 1688*0Sstevel@tonic-gate ppb_fm_fini(ppb_devstate_t *ppb_p) 1689*0Sstevel@tonic-gate { 1690*0Sstevel@tonic-gate /* 1691*0Sstevel@tonic-gate * Clean up allocated fm structures 1692*0Sstevel@tonic-gate */ 1693*0Sstevel@tonic-gate ddi_fm_handler_unregister(ppb_p->dip); 1694*0Sstevel@tonic-gate pci_ereport_teardown(ppb_p->dip); 1695*0Sstevel@tonic-gate ddi_fm_fini(ppb_p->dip); 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate 1698*0Sstevel@tonic-gate /* 1699*0Sstevel@tonic-gate * Initialize FMA resources for children devices. Called when 1700*0Sstevel@tonic-gate * child calls ddi_fm_init(). 1701*0Sstevel@tonic-gate */ 1702*0Sstevel@tonic-gate /*ARGSUSED*/ 1703*0Sstevel@tonic-gate static int 1704*0Sstevel@tonic-gate ppb_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap, 1705*0Sstevel@tonic-gate ddi_iblock_cookie_t *ibc) 1706*0Sstevel@tonic-gate { 1707*0Sstevel@tonic-gate ppb_devstate_t *ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, 1708*0Sstevel@tonic-gate ddi_get_instance(dip)); 1709*0Sstevel@tonic-gate *ibc = ppb_p->fm_ibc; 1710*0Sstevel@tonic-gate return (ppb_p->fm_cap); 1711*0Sstevel@tonic-gate } 1712*0Sstevel@tonic-gate 1713*0Sstevel@tonic-gate /* 1714*0Sstevel@tonic-gate * FMA registered error callback 1715*0Sstevel@tonic-gate */ 1716*0Sstevel@tonic-gate static int 1717*0Sstevel@tonic-gate ppb_err_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data) 1718*0Sstevel@tonic-gate { 1719*0Sstevel@tonic-gate uint16_t pci_cfg_stat, pci_cfg_sec_stat; 1720*0Sstevel@tonic-gate 1721*0Sstevel@tonic-gate ASSERT(impl_data == NULL); 1722*0Sstevel@tonic-gate pci_ereport_post(dip, derr, &pci_cfg_stat); 1723*0Sstevel@tonic-gate pci_bdg_ereport_post(dip, derr, &pci_cfg_sec_stat); 1724*0Sstevel@tonic-gate return (pci_bdg_check_status(dip, derr, pci_cfg_stat, 1725*0Sstevel@tonic-gate pci_cfg_sec_stat)); 1726*0Sstevel@tonic-gate } 1727*0Sstevel@tonic-gate 1728*0Sstevel@tonic-gate static void 1729*0Sstevel@tonic-gate ppb_bus_enter(dev_info_t *dip, ddi_acc_handle_t handle) 1730*0Sstevel@tonic-gate { 1731*0Sstevel@tonic-gate i_ndi_busop_access_enter(dip, handle); 1732*0Sstevel@tonic-gate } 1733*0Sstevel@tonic-gate 1734*0Sstevel@tonic-gate /* ARGSUSED */ 1735*0Sstevel@tonic-gate static void 1736*0Sstevel@tonic-gate ppb_bus_exit(dev_info_t *dip, ddi_acc_handle_t handle) 1737*0Sstevel@tonic-gate { 1738*0Sstevel@tonic-gate i_ndi_busop_access_exit(dip, handle); 1739*0Sstevel@tonic-gate } 1740