1*25cf1a30Sjl /* 2*25cf1a30Sjl * CDDL HEADER START 3*25cf1a30Sjl * 4*25cf1a30Sjl * The contents of this file are subject to the terms of the 5*25cf1a30Sjl * Common Development and Distribution License (the "License"). 6*25cf1a30Sjl * You may not use this file except in compliance with the License. 7*25cf1a30Sjl * 8*25cf1a30Sjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*25cf1a30Sjl * or http://www.opensolaris.org/os/licensing. 10*25cf1a30Sjl * See the License for the specific language governing permissions 11*25cf1a30Sjl * and limitations under the License. 12*25cf1a30Sjl * 13*25cf1a30Sjl * When distributing Covered Code, include this CDDL HEADER in each 14*25cf1a30Sjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*25cf1a30Sjl * If applicable, add the following below this CDDL HEADER, with the 16*25cf1a30Sjl * fields enclosed by brackets "[]" replaced with your own identifying 17*25cf1a30Sjl * information: Portions Copyright [yyyy] [name of copyright owner] 18*25cf1a30Sjl * 19*25cf1a30Sjl * CDDL HEADER END 20*25cf1a30Sjl */ 21*25cf1a30Sjl /* 22*25cf1a30Sjl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*25cf1a30Sjl * Use is subject to license terms. 24*25cf1a30Sjl */ 25*25cf1a30Sjl 26*25cf1a30Sjl #pragma ident "%Z%%M% %I% %E% SMI" 27*25cf1a30Sjl 28*25cf1a30Sjl /* 29*25cf1a30Sjl * OPL CMU-CH PCI nexus driver. 30*25cf1a30Sjl * 31*25cf1a30Sjl */ 32*25cf1a30Sjl 33*25cf1a30Sjl #include <sys/types.h> 34*25cf1a30Sjl #include <sys/sysmacros.h> 35*25cf1a30Sjl #include <sys/systm.h> 36*25cf1a30Sjl #include <sys/intreg.h> 37*25cf1a30Sjl #include <sys/intr.h> 38*25cf1a30Sjl #include <sys/machsystm.h> 39*25cf1a30Sjl #include <sys/conf.h> 40*25cf1a30Sjl #include <sys/stat.h> 41*25cf1a30Sjl #include <sys/kmem.h> 42*25cf1a30Sjl #include <sys/async.h> 43*25cf1a30Sjl #include <sys/ivintr.h> 44*25cf1a30Sjl #include <sys/sunddi.h> 45*25cf1a30Sjl #include <sys/sunndi.h> 46*25cf1a30Sjl #include <sys/ndifm.h> 47*25cf1a30Sjl #include <sys/ontrap.h> 48*25cf1a30Sjl #include <sys/ddi_impldefs.h> 49*25cf1a30Sjl #include <sys/ddi_subrdefs.h> 50*25cf1a30Sjl #include <sys/epm.h> 51*25cf1a30Sjl #include <sys/spl.h> 52*25cf1a30Sjl #include <sys/fm/util.h> 53*25cf1a30Sjl #include <sys/fm/util.h> 54*25cf1a30Sjl #include <sys/fm/protocol.h> 55*25cf1a30Sjl #include <sys/fm/io/pci.h> 56*25cf1a30Sjl #include <sys/fm/io/sun4upci.h> 57*25cf1a30Sjl #include <sys/pcicmu/pcicmu.h> 58*25cf1a30Sjl 59*25cf1a30Sjl #include <sys/cmn_err.h> 60*25cf1a30Sjl #include <sys/time.h> 61*25cf1a30Sjl #include <sys/pci.h> 62*25cf1a30Sjl #include <sys/modctl.h> 63*25cf1a30Sjl #include <sys/open.h> 64*25cf1a30Sjl #include <sys/errno.h> 65*25cf1a30Sjl #include <sys/file.h> 66*25cf1a30Sjl 67*25cf1a30Sjl 68*25cf1a30Sjl uint32_t pcmu_spurintr_duration = 60000000; /* One minute */ 69*25cf1a30Sjl 70*25cf1a30Sjl /* 71*25cf1a30Sjl * The variable controls the default setting of the command register 72*25cf1a30Sjl * for pci devices. See pcmu_init_child() for details. 73*25cf1a30Sjl * 74*25cf1a30Sjl * This flags also controls the setting of bits in the bridge control 75*25cf1a30Sjl * register pci to pci bridges. See pcmu_init_child() for details. 76*25cf1a30Sjl */ 77*25cf1a30Sjl ushort_t pcmu_command_default = PCI_COMM_SERR_ENABLE | 78*25cf1a30Sjl PCI_COMM_WAIT_CYC_ENAB | 79*25cf1a30Sjl PCI_COMM_PARITY_DETECT | 80*25cf1a30Sjl PCI_COMM_ME | 81*25cf1a30Sjl PCI_COMM_MAE | 82*25cf1a30Sjl PCI_COMM_IO; 83*25cf1a30Sjl /* 84*25cf1a30Sjl * The following driver parameters are defined as variables to allow 85*25cf1a30Sjl * patching for debugging and tuning. Flags that can be set on a per 86*25cf1a30Sjl * PBM basis are bit fields where the PBM device instance number maps 87*25cf1a30Sjl * to the bit position. 88*25cf1a30Sjl */ 89*25cf1a30Sjl #ifdef DEBUG 90*25cf1a30Sjl uint64_t pcmu_debug_flags = 0; 91*25cf1a30Sjl #endif 92*25cf1a30Sjl uint_t ecc_error_intr_enable = 1; 93*25cf1a30Sjl 94*25cf1a30Sjl uint_t pcmu_ecc_afsr_retries = 100; /* XXX - what's a good value? */ 95*25cf1a30Sjl 96*25cf1a30Sjl uint_t pcmu_intr_retry_intv = 5; /* for interrupt retry reg */ 97*25cf1a30Sjl uint_t pcmu_panic_on_fatal_errors = 1; /* should be 1 at beta */ 98*25cf1a30Sjl 99*25cf1a30Sjl hrtime_t pcmu_intrpend_timeout = 5ll * NANOSEC; /* 5 seconds in nanoseconds */ 100*25cf1a30Sjl 101*25cf1a30Sjl uint64_t pcmu_errtrig_pa = 0x0; 102*25cf1a30Sjl 103*25cf1a30Sjl 104*25cf1a30Sjl /* 105*25cf1a30Sjl * The following value is the number of consecutive unclaimed interrupts that 106*25cf1a30Sjl * will be tolerated for a particular ino_p before the interrupt is deemed to 107*25cf1a30Sjl * be jabbering and is blocked. 108*25cf1a30Sjl */ 109*25cf1a30Sjl uint_t pcmu_unclaimed_intr_max = 20; 110*25cf1a30Sjl 111*25cf1a30Sjl /* 112*25cf1a30Sjl * function prototypes for dev ops routines: 113*25cf1a30Sjl */ 114*25cf1a30Sjl static int pcmu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 115*25cf1a30Sjl static int pcmu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 116*25cf1a30Sjl static int pcmu_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 117*25cf1a30Sjl void *arg, void **result); 118*25cf1a30Sjl static int pcmu_open(dev_t *devp, int flags, int otyp, cred_t *credp); 119*25cf1a30Sjl static int pcmu_close(dev_t dev, int flags, int otyp, cred_t *credp); 120*25cf1a30Sjl static int pcmu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 121*25cf1a30Sjl cred_t *credp, int *rvalp); 122*25cf1a30Sjl static int pcmu_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 123*25cf1a30Sjl int flags, char *name, caddr_t valuep, int *lengthp); 124*25cf1a30Sjl static int pcmu_ctlops_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args); 125*25cf1a30Sjl static int pcmu_ctlops_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args, 126*25cf1a30Sjl void *result); 127*25cf1a30Sjl 128*25cf1a30Sjl static int map_pcmu_registers(pcmu_t *, dev_info_t *); 129*25cf1a30Sjl static void unmap_pcmu_registers(pcmu_t *); 130*25cf1a30Sjl static void pcmu_pbm_clear_error(pcmu_pbm_t *); 131*25cf1a30Sjl 132*25cf1a30Sjl static int pcmu_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 133*25cf1a30Sjl void *, void *); 134*25cf1a30Sjl static int pcmu_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 135*25cf1a30Sjl off_t, off_t, caddr_t *); 136*25cf1a30Sjl static int pcmu_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 137*25cf1a30Sjl ddi_intr_handle_impl_t *, void *); 138*25cf1a30Sjl 139*25cf1a30Sjl static uint32_t pcmu_identity_init(pcmu_t *pcmu_p); 140*25cf1a30Sjl static int pcmu_intr_setup(pcmu_t *pcmu_p); 141*25cf1a30Sjl static void pcmu_pbm_errstate_get(pcmu_t *pcmu_p, 142*25cf1a30Sjl pcmu_pbm_errstate_t *pbm_err_p); 143*25cf1a30Sjl static int pcmu_obj_setup(pcmu_t *pcmu_p); 144*25cf1a30Sjl static void pcmu_obj_destroy(pcmu_t *pcmu_p); 145*25cf1a30Sjl static void pcmu_obj_resume(pcmu_t *pcmu_p); 146*25cf1a30Sjl static void pcmu_obj_suspend(pcmu_t *pcmu_p); 147*25cf1a30Sjl 148*25cf1a30Sjl static void u2u_ittrans_init(pcmu_t *, u2u_ittrans_data_t **); 149*25cf1a30Sjl static void u2u_ittrans_resume(u2u_ittrans_data_t **); 150*25cf1a30Sjl static void u2u_ittrans_uninit(u2u_ittrans_data_t *); 151*25cf1a30Sjl 152*25cf1a30Sjl static pcmu_ksinfo_t *pcmu_name_kstat; 153*25cf1a30Sjl 154*25cf1a30Sjl /* 155*25cf1a30Sjl * bus ops and dev ops structures: 156*25cf1a30Sjl */ 157*25cf1a30Sjl static struct bus_ops pcmu_bus_ops = { 158*25cf1a30Sjl BUSO_REV, 159*25cf1a30Sjl pcmu_map, 160*25cf1a30Sjl 0, 161*25cf1a30Sjl 0, 162*25cf1a30Sjl 0, 163*25cf1a30Sjl i_ddi_map_fault, 164*25cf1a30Sjl 0, 165*25cf1a30Sjl 0, 166*25cf1a30Sjl 0, 167*25cf1a30Sjl 0, 168*25cf1a30Sjl 0, 169*25cf1a30Sjl 0, 170*25cf1a30Sjl 0, 171*25cf1a30Sjl 0, 172*25cf1a30Sjl pcmu_ctlops, 173*25cf1a30Sjl ddi_bus_prop_op, 174*25cf1a30Sjl ndi_busop_get_eventcookie, /* (*bus_get_eventcookie)(); */ 175*25cf1a30Sjl ndi_busop_add_eventcall, /* (*bus_add_eventcall)(); */ 176*25cf1a30Sjl ndi_busop_remove_eventcall, /* (*bus_remove_eventcall)(); */ 177*25cf1a30Sjl ndi_post_event, /* (*bus_post_event)(); */ 178*25cf1a30Sjl NULL, /* (*bus_intr_ctl)(); */ 179*25cf1a30Sjl NULL, /* (*bus_config)(); */ 180*25cf1a30Sjl NULL, /* (*bus_unconfig)(); */ 181*25cf1a30Sjl NULL, /* (*bus_fm_init)(); */ 182*25cf1a30Sjl NULL, /* (*bus_fm_fini)(); */ 183*25cf1a30Sjl NULL, /* (*bus_fm_access_enter)(); */ 184*25cf1a30Sjl NULL, /* (*bus_fm_access_fini)(); */ 185*25cf1a30Sjl NULL, /* (*bus_power)(); */ 186*25cf1a30Sjl pcmu_intr_ops /* (*bus_intr_op)(); */ 187*25cf1a30Sjl }; 188*25cf1a30Sjl 189*25cf1a30Sjl struct cb_ops pcmu_cb_ops = { 190*25cf1a30Sjl pcmu_open, /* open */ 191*25cf1a30Sjl pcmu_close, /* close */ 192*25cf1a30Sjl nodev, /* strategy */ 193*25cf1a30Sjl nodev, /* print */ 194*25cf1a30Sjl nodev, /* dump */ 195*25cf1a30Sjl nodev, /* read */ 196*25cf1a30Sjl nodev, /* write */ 197*25cf1a30Sjl pcmu_ioctl, /* ioctl */ 198*25cf1a30Sjl nodev, /* devmap */ 199*25cf1a30Sjl nodev, /* mmap */ 200*25cf1a30Sjl nodev, /* segmap */ 201*25cf1a30Sjl nochpoll, /* poll */ 202*25cf1a30Sjl pcmu_prop_op, /* cb_prop_op */ 203*25cf1a30Sjl NULL, /* streamtab */ 204*25cf1a30Sjl D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 205*25cf1a30Sjl CB_REV, /* rev */ 206*25cf1a30Sjl nodev, /* int (*cb_aread)() */ 207*25cf1a30Sjl nodev /* int (*cb_awrite)() */ 208*25cf1a30Sjl }; 209*25cf1a30Sjl 210*25cf1a30Sjl static struct dev_ops pcmu_ops = { 211*25cf1a30Sjl DEVO_REV, 212*25cf1a30Sjl 0, 213*25cf1a30Sjl pcmu_info, 214*25cf1a30Sjl nulldev, 215*25cf1a30Sjl 0, 216*25cf1a30Sjl pcmu_attach, 217*25cf1a30Sjl pcmu_detach, 218*25cf1a30Sjl nodev, 219*25cf1a30Sjl &pcmu_cb_ops, 220*25cf1a30Sjl &pcmu_bus_ops, 221*25cf1a30Sjl 0 222*25cf1a30Sjl }; 223*25cf1a30Sjl 224*25cf1a30Sjl /* 225*25cf1a30Sjl * module definitions: 226*25cf1a30Sjl */ 227*25cf1a30Sjl extern struct mod_ops mod_driverops; 228*25cf1a30Sjl 229*25cf1a30Sjl static struct modldrv modldrv = { 230*25cf1a30Sjl &mod_driverops, /* Type of module - driver */ 231*25cf1a30Sjl "OPL CMU-CH PCI Nexus driver %I%", /* Name of module. */ 232*25cf1a30Sjl &pcmu_ops, /* driver ops */ 233*25cf1a30Sjl }; 234*25cf1a30Sjl 235*25cf1a30Sjl static struct modlinkage modlinkage = { 236*25cf1a30Sjl MODREV_1, (void *)&modldrv, NULL 237*25cf1a30Sjl }; 238*25cf1a30Sjl 239*25cf1a30Sjl /* 240*25cf1a30Sjl * driver global data: 241*25cf1a30Sjl */ 242*25cf1a30Sjl void *per_pcmu_state; /* per-pbm soft state pointer */ 243*25cf1a30Sjl kmutex_t pcmu_global_mutex; /* attach/detach common struct lock */ 244*25cf1a30Sjl errorq_t *pcmu_ecc_queue = NULL; /* per-system ecc handling queue */ 245*25cf1a30Sjl 246*25cf1a30Sjl extern void pcmu_child_cfg_save(dev_info_t *dip); 247*25cf1a30Sjl extern void pcmu_child_cfg_restore(dev_info_t *dip); 248*25cf1a30Sjl 249*25cf1a30Sjl int 250*25cf1a30Sjl _init(void) 251*25cf1a30Sjl { 252*25cf1a30Sjl int e; 253*25cf1a30Sjl 254*25cf1a30Sjl /* 255*25cf1a30Sjl * Initialize per-pci bus soft state pointer. 256*25cf1a30Sjl */ 257*25cf1a30Sjl e = ddi_soft_state_init(&per_pcmu_state, sizeof (pcmu_t), 1); 258*25cf1a30Sjl if (e != 0) 259*25cf1a30Sjl return (e); 260*25cf1a30Sjl 261*25cf1a30Sjl /* 262*25cf1a30Sjl * Initialize global mutexes. 263*25cf1a30Sjl */ 264*25cf1a30Sjl mutex_init(&pcmu_global_mutex, NULL, MUTEX_DRIVER, NULL); 265*25cf1a30Sjl 266*25cf1a30Sjl /* 267*25cf1a30Sjl * Create the performance kstats. 268*25cf1a30Sjl */ 269*25cf1a30Sjl pcmu_kstat_init(); 270*25cf1a30Sjl 271*25cf1a30Sjl /* 272*25cf1a30Sjl * Install the module. 273*25cf1a30Sjl */ 274*25cf1a30Sjl e = mod_install(&modlinkage); 275*25cf1a30Sjl if (e != 0) { 276*25cf1a30Sjl ddi_soft_state_fini(&per_pcmu_state); 277*25cf1a30Sjl mutex_destroy(&pcmu_global_mutex); 278*25cf1a30Sjl } 279*25cf1a30Sjl return (e); 280*25cf1a30Sjl } 281*25cf1a30Sjl 282*25cf1a30Sjl int 283*25cf1a30Sjl _fini(void) 284*25cf1a30Sjl { 285*25cf1a30Sjl int e; 286*25cf1a30Sjl 287*25cf1a30Sjl /* 288*25cf1a30Sjl * Remove the module. 289*25cf1a30Sjl */ 290*25cf1a30Sjl e = mod_remove(&modlinkage); 291*25cf1a30Sjl if (e != 0) { 292*25cf1a30Sjl return (e); 293*25cf1a30Sjl } 294*25cf1a30Sjl 295*25cf1a30Sjl /* 296*25cf1a30Sjl * Destroy pcmu_ecc_queue, and set it to NULL. 297*25cf1a30Sjl */ 298*25cf1a30Sjl if (pcmu_ecc_queue) { 299*25cf1a30Sjl errorq_destroy(pcmu_ecc_queue); 300*25cf1a30Sjl pcmu_ecc_queue = NULL; 301*25cf1a30Sjl } 302*25cf1a30Sjl 303*25cf1a30Sjl /* 304*25cf1a30Sjl * Destroy the performance kstats. 305*25cf1a30Sjl */ 306*25cf1a30Sjl pcmu_kstat_fini(); 307*25cf1a30Sjl 308*25cf1a30Sjl /* 309*25cf1a30Sjl * Free the per-pci and per-CMU-CH soft state info and destroy 310*25cf1a30Sjl * mutex for per-CMU-CH soft state. 311*25cf1a30Sjl */ 312*25cf1a30Sjl ddi_soft_state_fini(&per_pcmu_state); 313*25cf1a30Sjl mutex_destroy(&pcmu_global_mutex); 314*25cf1a30Sjl return (e); 315*25cf1a30Sjl } 316*25cf1a30Sjl 317*25cf1a30Sjl int 318*25cf1a30Sjl _info(struct modinfo *modinfop) 319*25cf1a30Sjl { 320*25cf1a30Sjl return (mod_info(&modlinkage, modinfop)); 321*25cf1a30Sjl } 322*25cf1a30Sjl 323*25cf1a30Sjl /*ARGSUSED*/ 324*25cf1a30Sjl static int 325*25cf1a30Sjl pcmu_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 326*25cf1a30Sjl { 327*25cf1a30Sjl int instance = getminor((dev_t)arg) >> 8; 328*25cf1a30Sjl pcmu_t *pcmu_p = get_pcmu_soft_state(instance); 329*25cf1a30Sjl 330*25cf1a30Sjl switch (infocmd) { 331*25cf1a30Sjl case DDI_INFO_DEVT2INSTANCE: 332*25cf1a30Sjl *result = (void *)(uintptr_t)instance; 333*25cf1a30Sjl return (DDI_SUCCESS); 334*25cf1a30Sjl 335*25cf1a30Sjl case DDI_INFO_DEVT2DEVINFO: 336*25cf1a30Sjl if (pcmu_p == NULL) 337*25cf1a30Sjl return (DDI_FAILURE); 338*25cf1a30Sjl *result = (void *)pcmu_p->pcmu_dip; 339*25cf1a30Sjl return (DDI_SUCCESS); 340*25cf1a30Sjl 341*25cf1a30Sjl default: 342*25cf1a30Sjl return (DDI_FAILURE); 343*25cf1a30Sjl } 344*25cf1a30Sjl } 345*25cf1a30Sjl 346*25cf1a30Sjl 347*25cf1a30Sjl /* device driver entry points */ 348*25cf1a30Sjl /* 349*25cf1a30Sjl * attach entry point: 350*25cf1a30Sjl */ 351*25cf1a30Sjl static int 352*25cf1a30Sjl pcmu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 353*25cf1a30Sjl { 354*25cf1a30Sjl pcmu_t *pcmu_p; 355*25cf1a30Sjl int instance = ddi_get_instance(dip); 356*25cf1a30Sjl 357*25cf1a30Sjl switch (cmd) { 358*25cf1a30Sjl case DDI_ATTACH: 359*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_ATTACH, dip, "DDI_ATTACH\n"); 360*25cf1a30Sjl 361*25cf1a30Sjl /* 362*25cf1a30Sjl * Allocate and get the per-pci soft state structure. 363*25cf1a30Sjl */ 364*25cf1a30Sjl if (alloc_pcmu_soft_state(instance) != DDI_SUCCESS) { 365*25cf1a30Sjl cmn_err(CE_WARN, "%s%d: can't allocate pci state", 366*25cf1a30Sjl ddi_driver_name(dip), instance); 367*25cf1a30Sjl goto err_bad_pcmu_softstate; 368*25cf1a30Sjl } 369*25cf1a30Sjl pcmu_p = get_pcmu_soft_state(instance); 370*25cf1a30Sjl pcmu_p->pcmu_dip = dip; 371*25cf1a30Sjl mutex_init(&pcmu_p->pcmu_mutex, NULL, MUTEX_DRIVER, NULL); 372*25cf1a30Sjl pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_CLOSED; 373*25cf1a30Sjl pcmu_p->pcmu_open_count = 0; 374*25cf1a30Sjl 375*25cf1a30Sjl /* 376*25cf1a30Sjl * Get key properties of the pci bridge node. 377*25cf1a30Sjl */ 378*25cf1a30Sjl if (get_pcmu_properties(pcmu_p, dip) == DDI_FAILURE) { 379*25cf1a30Sjl goto err_bad_pcmu_prop; 380*25cf1a30Sjl } 381*25cf1a30Sjl 382*25cf1a30Sjl /* 383*25cf1a30Sjl * Map in the registers. 384*25cf1a30Sjl */ 385*25cf1a30Sjl if (map_pcmu_registers(pcmu_p, dip) == DDI_FAILURE) { 386*25cf1a30Sjl goto err_bad_reg_prop; 387*25cf1a30Sjl } 388*25cf1a30Sjl if (pcmu_obj_setup(pcmu_p) != DDI_SUCCESS) { 389*25cf1a30Sjl goto err_bad_objs; 390*25cf1a30Sjl } 391*25cf1a30Sjl 392*25cf1a30Sjl if (ddi_create_minor_node(dip, "devctl", S_IFCHR, 393*25cf1a30Sjl (uint_t)instance<<8 | 0xff, 394*25cf1a30Sjl DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 395*25cf1a30Sjl goto err_bad_devctl_node; 396*25cf1a30Sjl } 397*25cf1a30Sjl 398*25cf1a30Sjl /* 399*25cf1a30Sjl * Due to unresolved hardware issues, disable PCIPM until 400*25cf1a30Sjl * the problem is fully understood. 401*25cf1a30Sjl * 402*25cf1a30Sjl * pcmu_pwr_setup(pcmu_p, dip); 403*25cf1a30Sjl */ 404*25cf1a30Sjl 405*25cf1a30Sjl ddi_report_dev(dip); 406*25cf1a30Sjl 407*25cf1a30Sjl pcmu_p->pcmu_state = PCMU_ATTACHED; 408*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_ATTACH, dip, "attach success\n"); 409*25cf1a30Sjl break; 410*25cf1a30Sjl 411*25cf1a30Sjl err_bad_objs: 412*25cf1a30Sjl ddi_remove_minor_node(dip, "devctl"); 413*25cf1a30Sjl err_bad_devctl_node: 414*25cf1a30Sjl unmap_pcmu_registers(pcmu_p); 415*25cf1a30Sjl err_bad_reg_prop: 416*25cf1a30Sjl free_pcmu_properties(pcmu_p); 417*25cf1a30Sjl err_bad_pcmu_prop: 418*25cf1a30Sjl mutex_destroy(&pcmu_p->pcmu_mutex); 419*25cf1a30Sjl free_pcmu_soft_state(instance); 420*25cf1a30Sjl err_bad_pcmu_softstate: 421*25cf1a30Sjl return (DDI_FAILURE); 422*25cf1a30Sjl 423*25cf1a30Sjl case DDI_RESUME: 424*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_ATTACH, dip, "DDI_RESUME\n"); 425*25cf1a30Sjl 426*25cf1a30Sjl /* 427*25cf1a30Sjl * Make sure the CMU-CH control registers 428*25cf1a30Sjl * are configured properly. 429*25cf1a30Sjl */ 430*25cf1a30Sjl pcmu_p = get_pcmu_soft_state(instance); 431*25cf1a30Sjl mutex_enter(&pcmu_p->pcmu_mutex); 432*25cf1a30Sjl 433*25cf1a30Sjl /* 434*25cf1a30Sjl * Make sure this instance has been suspended. 435*25cf1a30Sjl */ 436*25cf1a30Sjl if (pcmu_p->pcmu_state != PCMU_SUSPENDED) { 437*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_ATTACH, dip, 438*25cf1a30Sjl "instance NOT suspended\n"); 439*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_mutex); 440*25cf1a30Sjl return (DDI_FAILURE); 441*25cf1a30Sjl } 442*25cf1a30Sjl pcmu_obj_resume(pcmu_p); 443*25cf1a30Sjl pcmu_p->pcmu_state = PCMU_ATTACHED; 444*25cf1a30Sjl 445*25cf1a30Sjl pcmu_child_cfg_restore(dip); 446*25cf1a30Sjl 447*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_mutex); 448*25cf1a30Sjl break; 449*25cf1a30Sjl 450*25cf1a30Sjl default: 451*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_ATTACH, dip, "unsupported attach op\n"); 452*25cf1a30Sjl return (DDI_FAILURE); 453*25cf1a30Sjl } 454*25cf1a30Sjl 455*25cf1a30Sjl return (DDI_SUCCESS); 456*25cf1a30Sjl } 457*25cf1a30Sjl 458*25cf1a30Sjl /* 459*25cf1a30Sjl * detach entry point: 460*25cf1a30Sjl */ 461*25cf1a30Sjl static int 462*25cf1a30Sjl pcmu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 463*25cf1a30Sjl { 464*25cf1a30Sjl int instance = ddi_get_instance(dip); 465*25cf1a30Sjl pcmu_t *pcmu_p = get_pcmu_soft_state(instance); 466*25cf1a30Sjl int len; 467*25cf1a30Sjl 468*25cf1a30Sjl /* 469*25cf1a30Sjl * Make sure we are currently attached 470*25cf1a30Sjl */ 471*25cf1a30Sjl if (pcmu_p->pcmu_state != PCMU_ATTACHED) { 472*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_ATTACH, dip, 473*25cf1a30Sjl "failed - instance not attached\n"); 474*25cf1a30Sjl return (DDI_FAILURE); 475*25cf1a30Sjl } 476*25cf1a30Sjl 477*25cf1a30Sjl mutex_enter(&pcmu_p->pcmu_mutex); 478*25cf1a30Sjl 479*25cf1a30Sjl switch (cmd) { 480*25cf1a30Sjl case DDI_DETACH: 481*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_DETACH, dip, "DDI_DETACH\n"); 482*25cf1a30Sjl pcmu_obj_destroy(pcmu_p); 483*25cf1a30Sjl 484*25cf1a30Sjl /* 485*25cf1a30Sjl * Free the pci soft state structure and the rest of the 486*25cf1a30Sjl * resources it's using. 487*25cf1a30Sjl */ 488*25cf1a30Sjl free_pcmu_properties(pcmu_p); 489*25cf1a30Sjl unmap_pcmu_registers(pcmu_p); 490*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_mutex); 491*25cf1a30Sjl mutex_destroy(&pcmu_p->pcmu_mutex); 492*25cf1a30Sjl free_pcmu_soft_state(instance); 493*25cf1a30Sjl 494*25cf1a30Sjl /* Free the interrupt-priorities prop if we created it. */ 495*25cf1a30Sjl if (ddi_getproplen(DDI_DEV_T_ANY, dip, 496*25cf1a30Sjl DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 497*25cf1a30Sjl "interrupt-priorities", &len) == DDI_PROP_SUCCESS) { 498*25cf1a30Sjl (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 499*25cf1a30Sjl "interrupt-priorities"); 500*25cf1a30Sjl } 501*25cf1a30Sjl return (DDI_SUCCESS); 502*25cf1a30Sjl 503*25cf1a30Sjl case DDI_SUSPEND: 504*25cf1a30Sjl pcmu_child_cfg_save(dip); 505*25cf1a30Sjl pcmu_obj_suspend(pcmu_p); 506*25cf1a30Sjl pcmu_p->pcmu_state = PCMU_SUSPENDED; 507*25cf1a30Sjl 508*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_mutex); 509*25cf1a30Sjl return (DDI_SUCCESS); 510*25cf1a30Sjl 511*25cf1a30Sjl default: 512*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_DETACH, dip, "unsupported detach op\n"); 513*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_mutex); 514*25cf1a30Sjl return (DDI_FAILURE); 515*25cf1a30Sjl } 516*25cf1a30Sjl } 517*25cf1a30Sjl 518*25cf1a30Sjl 519*25cf1a30Sjl /*LINTLIBRARY*/ 520*25cf1a30Sjl 521*25cf1a30Sjl /* ARGSUSED3 */ 522*25cf1a30Sjl static int 523*25cf1a30Sjl pcmu_open(dev_t *devp, int flags, int otyp, cred_t *credp) 524*25cf1a30Sjl { 525*25cf1a30Sjl pcmu_t *pcmu_p; 526*25cf1a30Sjl 527*25cf1a30Sjl if (otyp != OTYP_CHR) { 528*25cf1a30Sjl return (EINVAL); 529*25cf1a30Sjl } 530*25cf1a30Sjl 531*25cf1a30Sjl /* 532*25cf1a30Sjl * Get the soft state structure for the device. 533*25cf1a30Sjl */ 534*25cf1a30Sjl pcmu_p = DEV_TO_SOFTSTATE(*devp); 535*25cf1a30Sjl if (pcmu_p == NULL) { 536*25cf1a30Sjl return (ENXIO); 537*25cf1a30Sjl } 538*25cf1a30Sjl 539*25cf1a30Sjl /* 540*25cf1a30Sjl * Handle the open by tracking the device state. 541*25cf1a30Sjl */ 542*25cf1a30Sjl PCMU_DBG2(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, 543*25cf1a30Sjl "devp=%x: flags=%x\n", devp, flags); 544*25cf1a30Sjl mutex_enter(&pcmu_p->pcmu_mutex); 545*25cf1a30Sjl if (flags & FEXCL) { 546*25cf1a30Sjl if (pcmu_p->pcmu_soft_state != PCMU_SOFT_STATE_CLOSED) { 547*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_mutex); 548*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, "busy\n"); 549*25cf1a30Sjl return (EBUSY); 550*25cf1a30Sjl } 551*25cf1a30Sjl pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_OPEN_EXCL; 552*25cf1a30Sjl } else { 553*25cf1a30Sjl if (pcmu_p->pcmu_soft_state == PCMU_SOFT_STATE_OPEN_EXCL) { 554*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_mutex); 555*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, "busy\n"); 556*25cf1a30Sjl return (EBUSY); 557*25cf1a30Sjl } 558*25cf1a30Sjl pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_OPEN; 559*25cf1a30Sjl } 560*25cf1a30Sjl pcmu_p->pcmu_open_count++; 561*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_mutex); 562*25cf1a30Sjl return (0); 563*25cf1a30Sjl } 564*25cf1a30Sjl 565*25cf1a30Sjl 566*25cf1a30Sjl /* ARGSUSED */ 567*25cf1a30Sjl static int 568*25cf1a30Sjl pcmu_close(dev_t dev, int flags, int otyp, cred_t *credp) 569*25cf1a30Sjl { 570*25cf1a30Sjl pcmu_t *pcmu_p; 571*25cf1a30Sjl 572*25cf1a30Sjl if (otyp != OTYP_CHR) { 573*25cf1a30Sjl return (EINVAL); 574*25cf1a30Sjl } 575*25cf1a30Sjl 576*25cf1a30Sjl pcmu_p = DEV_TO_SOFTSTATE(dev); 577*25cf1a30Sjl if (pcmu_p == NULL) { 578*25cf1a30Sjl return (ENXIO); 579*25cf1a30Sjl } 580*25cf1a30Sjl 581*25cf1a30Sjl PCMU_DBG2(PCMU_DBG_CLOSE, pcmu_p->pcmu_dip, 582*25cf1a30Sjl "dev=%x: flags=%x\n", dev, flags); 583*25cf1a30Sjl mutex_enter(&pcmu_p->pcmu_mutex); 584*25cf1a30Sjl pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_CLOSED; 585*25cf1a30Sjl pcmu_p->pcmu_open_count = 0; 586*25cf1a30Sjl mutex_exit(&pcmu_p->pcmu_mutex); 587*25cf1a30Sjl return (0); 588*25cf1a30Sjl } 589*25cf1a30Sjl 590*25cf1a30Sjl /* ARGSUSED */ 591*25cf1a30Sjl static int 592*25cf1a30Sjl pcmu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 593*25cf1a30Sjl cred_t *credp, int *rvalp) 594*25cf1a30Sjl { 595*25cf1a30Sjl pcmu_t *pcmu_p; 596*25cf1a30Sjl dev_info_t *dip; 597*25cf1a30Sjl struct devctl_iocdata *dcp; 598*25cf1a30Sjl uint_t bus_state; 599*25cf1a30Sjl int rv = 0; 600*25cf1a30Sjl 601*25cf1a30Sjl pcmu_p = DEV_TO_SOFTSTATE(dev); 602*25cf1a30Sjl if (pcmu_p == NULL) { 603*25cf1a30Sjl return (ENXIO); 604*25cf1a30Sjl } 605*25cf1a30Sjl 606*25cf1a30Sjl dip = pcmu_p->pcmu_dip; 607*25cf1a30Sjl PCMU_DBG2(PCMU_DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd); 608*25cf1a30Sjl 609*25cf1a30Sjl /* 610*25cf1a30Sjl * We can use the generic implementation for these ioctls 611*25cf1a30Sjl */ 612*25cf1a30Sjl switch (cmd) { 613*25cf1a30Sjl case DEVCTL_DEVICE_GETSTATE: 614*25cf1a30Sjl case DEVCTL_DEVICE_ONLINE: 615*25cf1a30Sjl case DEVCTL_DEVICE_OFFLINE: 616*25cf1a30Sjl case DEVCTL_BUS_GETSTATE: 617*25cf1a30Sjl return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0)); 618*25cf1a30Sjl } 619*25cf1a30Sjl 620*25cf1a30Sjl /* 621*25cf1a30Sjl * read devctl ioctl data 622*25cf1a30Sjl */ 623*25cf1a30Sjl if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 624*25cf1a30Sjl return (EFAULT); 625*25cf1a30Sjl 626*25cf1a30Sjl switch (cmd) { 627*25cf1a30Sjl 628*25cf1a30Sjl case DEVCTL_DEVICE_RESET: 629*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_DEVICE_RESET\n"); 630*25cf1a30Sjl rv = ENOTSUP; 631*25cf1a30Sjl break; 632*25cf1a30Sjl 633*25cf1a30Sjl 634*25cf1a30Sjl case DEVCTL_BUS_QUIESCE: 635*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_QUIESCE\n"); 636*25cf1a30Sjl if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) { 637*25cf1a30Sjl if (bus_state == BUS_QUIESCED) { 638*25cf1a30Sjl break; 639*25cf1a30Sjl } 640*25cf1a30Sjl } 641*25cf1a30Sjl (void) ndi_set_bus_state(dip, BUS_QUIESCED); 642*25cf1a30Sjl break; 643*25cf1a30Sjl 644*25cf1a30Sjl case DEVCTL_BUS_UNQUIESCE: 645*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_UNQUIESCE\n"); 646*25cf1a30Sjl if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) { 647*25cf1a30Sjl if (bus_state == BUS_ACTIVE) { 648*25cf1a30Sjl break; 649*25cf1a30Sjl } 650*25cf1a30Sjl } 651*25cf1a30Sjl (void) ndi_set_bus_state(dip, BUS_ACTIVE); 652*25cf1a30Sjl break; 653*25cf1a30Sjl 654*25cf1a30Sjl case DEVCTL_BUS_RESET: 655*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_RESET\n"); 656*25cf1a30Sjl rv = ENOTSUP; 657*25cf1a30Sjl break; 658*25cf1a30Sjl 659*25cf1a30Sjl case DEVCTL_BUS_RESETALL: 660*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_RESETALL\n"); 661*25cf1a30Sjl rv = ENOTSUP; 662*25cf1a30Sjl break; 663*25cf1a30Sjl 664*25cf1a30Sjl default: 665*25cf1a30Sjl rv = ENOTTY; 666*25cf1a30Sjl } 667*25cf1a30Sjl 668*25cf1a30Sjl ndi_dc_freehdl(dcp); 669*25cf1a30Sjl return (rv); 670*25cf1a30Sjl } 671*25cf1a30Sjl 672*25cf1a30Sjl static int pcmu_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 673*25cf1a30Sjl int flags, char *name, caddr_t valuep, int *lengthp) 674*25cf1a30Sjl { 675*25cf1a30Sjl return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); 676*25cf1a30Sjl } 677*25cf1a30Sjl /* bus driver entry points */ 678*25cf1a30Sjl 679*25cf1a30Sjl /* 680*25cf1a30Sjl * bus map entry point: 681*25cf1a30Sjl * 682*25cf1a30Sjl * if map request is for an rnumber 683*25cf1a30Sjl * get the corresponding regspec from device node 684*25cf1a30Sjl * build a new regspec in our parent's format 685*25cf1a30Sjl * build a new map_req with the new regspec 686*25cf1a30Sjl * call up the tree to complete the mapping 687*25cf1a30Sjl */ 688*25cf1a30Sjl static int 689*25cf1a30Sjl pcmu_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 690*25cf1a30Sjl off_t off, off_t len, caddr_t *addrp) 691*25cf1a30Sjl { 692*25cf1a30Sjl pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); 693*25cf1a30Sjl struct regspec p_regspec; 694*25cf1a30Sjl ddi_map_req_t p_mapreq; 695*25cf1a30Sjl int reglen, rval, r_no; 696*25cf1a30Sjl pci_regspec_t reloc_reg, *rp = &reloc_reg; 697*25cf1a30Sjl 698*25cf1a30Sjl PCMU_DBG2(PCMU_DBG_MAP, dip, "rdip=%s%d:", 699*25cf1a30Sjl ddi_driver_name(rdip), ddi_get_instance(rdip)); 700*25cf1a30Sjl 701*25cf1a30Sjl if (mp->map_flags & DDI_MF_USER_MAPPING) { 702*25cf1a30Sjl return (DDI_ME_UNIMPLEMENTED); 703*25cf1a30Sjl } 704*25cf1a30Sjl 705*25cf1a30Sjl switch (mp->map_type) { 706*25cf1a30Sjl case DDI_MT_REGSPEC: 707*25cf1a30Sjl reloc_reg = *(pci_regspec_t *)mp->map_obj.rp; /* dup whole */ 708*25cf1a30Sjl break; 709*25cf1a30Sjl 710*25cf1a30Sjl case DDI_MT_RNUMBER: 711*25cf1a30Sjl r_no = mp->map_obj.rnumber; 712*25cf1a30Sjl PCMU_DBG1(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, " r#=%x", r_no); 713*25cf1a30Sjl 714*25cf1a30Sjl if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS, 715*25cf1a30Sjl "reg", (caddr_t)&rp, ®len) != DDI_SUCCESS) { 716*25cf1a30Sjl return (DDI_ME_RNUMBER_RANGE); 717*25cf1a30Sjl } 718*25cf1a30Sjl 719*25cf1a30Sjl if (r_no < 0 || r_no >= reglen / sizeof (pci_regspec_t)) { 720*25cf1a30Sjl kmem_free(rp, reglen); 721*25cf1a30Sjl return (DDI_ME_RNUMBER_RANGE); 722*25cf1a30Sjl } 723*25cf1a30Sjl rp += r_no; 724*25cf1a30Sjl break; 725*25cf1a30Sjl 726*25cf1a30Sjl default: 727*25cf1a30Sjl return (DDI_ME_INVAL); 728*25cf1a30Sjl } 729*25cf1a30Sjl PCMU_DBG0(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, "\n"); 730*25cf1a30Sjl 731*25cf1a30Sjl /* use "assigned-addresses" to relocate regspec within pci space */ 732*25cf1a30Sjl if (rval = pcmu_reloc_reg(dip, rdip, pcmu_p, rp)) { 733*25cf1a30Sjl goto done; 734*25cf1a30Sjl } 735*25cf1a30Sjl 736*25cf1a30Sjl /* adjust regspec according to mapping request */ 737*25cf1a30Sjl if (len) { 738*25cf1a30Sjl rp->pci_size_low = (uint_t)len; 739*25cf1a30Sjl } 740*25cf1a30Sjl rp->pci_phys_low += off; 741*25cf1a30Sjl 742*25cf1a30Sjl /* use "ranges" to translate relocated pci regspec into parent space */ 743*25cf1a30Sjl if (rval = pcmu_xlate_reg(pcmu_p, rp, &p_regspec)) { 744*25cf1a30Sjl goto done; 745*25cf1a30Sjl } 746*25cf1a30Sjl 747*25cf1a30Sjl p_mapreq = *mp; /* dup the whole structure */ 748*25cf1a30Sjl p_mapreq.map_type = DDI_MT_REGSPEC; 749*25cf1a30Sjl p_mapreq.map_obj.rp = &p_regspec; 750*25cf1a30Sjl rval = ddi_map(dip, &p_mapreq, 0, 0, addrp); 751*25cf1a30Sjl 752*25cf1a30Sjl done: 753*25cf1a30Sjl if (mp->map_type == DDI_MT_RNUMBER) { 754*25cf1a30Sjl kmem_free(rp - r_no, reglen); 755*25cf1a30Sjl } 756*25cf1a30Sjl return (rval); 757*25cf1a30Sjl } 758*25cf1a30Sjl 759*25cf1a30Sjl #ifdef DEBUG 760*25cf1a30Sjl int pcmu_peekfault_cnt = 0; 761*25cf1a30Sjl int pcmu_pokefault_cnt = 0; 762*25cf1a30Sjl #endif /* DEBUG */ 763*25cf1a30Sjl 764*25cf1a30Sjl static int 765*25cf1a30Sjl pcmu_do_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args) 766*25cf1a30Sjl { 767*25cf1a30Sjl pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 768*25cf1a30Sjl int err = DDI_SUCCESS; 769*25cf1a30Sjl on_trap_data_t otd; 770*25cf1a30Sjl 771*25cf1a30Sjl mutex_enter(&pcbm_p->pcbm_pokeflt_mutex); 772*25cf1a30Sjl pcbm_p->pcbm_ontrap_data = &otd; 773*25cf1a30Sjl 774*25cf1a30Sjl /* Set up protected environment. */ 775*25cf1a30Sjl if (!on_trap(&otd, OT_DATA_ACCESS)) { 776*25cf1a30Sjl uintptr_t tramp = otd.ot_trampoline; 777*25cf1a30Sjl 778*25cf1a30Sjl otd.ot_trampoline = (uintptr_t)&poke_fault; 779*25cf1a30Sjl err = do_poke(in_args->size, (void *)in_args->dev_addr, 780*25cf1a30Sjl (void *)in_args->host_addr); 781*25cf1a30Sjl otd.ot_trampoline = tramp; 782*25cf1a30Sjl } else { 783*25cf1a30Sjl err = DDI_FAILURE; 784*25cf1a30Sjl } 785*25cf1a30Sjl 786*25cf1a30Sjl /* 787*25cf1a30Sjl * Read the async fault register for the PBM to see it sees 788*25cf1a30Sjl * a master-abort. 789*25cf1a30Sjl */ 790*25cf1a30Sjl pcmu_pbm_clear_error(pcbm_p); 791*25cf1a30Sjl 792*25cf1a30Sjl if (otd.ot_trap & OT_DATA_ACCESS) { 793*25cf1a30Sjl err = DDI_FAILURE; 794*25cf1a30Sjl } 795*25cf1a30Sjl 796*25cf1a30Sjl /* Take down protected environment. */ 797*25cf1a30Sjl no_trap(); 798*25cf1a30Sjl 799*25cf1a30Sjl pcbm_p->pcbm_ontrap_data = NULL; 800*25cf1a30Sjl mutex_exit(&pcbm_p->pcbm_pokeflt_mutex); 801*25cf1a30Sjl 802*25cf1a30Sjl #ifdef DEBUG 803*25cf1a30Sjl if (err == DDI_FAILURE) 804*25cf1a30Sjl pcmu_pokefault_cnt++; 805*25cf1a30Sjl #endif 806*25cf1a30Sjl return (err); 807*25cf1a30Sjl } 808*25cf1a30Sjl 809*25cf1a30Sjl 810*25cf1a30Sjl static int 811*25cf1a30Sjl pcmu_ctlops_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args) 812*25cf1a30Sjl { 813*25cf1a30Sjl return (pcmu_do_poke(pcmu_p, in_args)); 814*25cf1a30Sjl } 815*25cf1a30Sjl 816*25cf1a30Sjl /* ARGSUSED */ 817*25cf1a30Sjl static int 818*25cf1a30Sjl pcmu_do_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args) 819*25cf1a30Sjl { 820*25cf1a30Sjl int err = DDI_SUCCESS; 821*25cf1a30Sjl on_trap_data_t otd; 822*25cf1a30Sjl 823*25cf1a30Sjl if (!on_trap(&otd, OT_DATA_ACCESS)) { 824*25cf1a30Sjl uintptr_t tramp = otd.ot_trampoline; 825*25cf1a30Sjl 826*25cf1a30Sjl otd.ot_trampoline = (uintptr_t)&peek_fault; 827*25cf1a30Sjl err = do_peek(in_args->size, (void *)in_args->dev_addr, 828*25cf1a30Sjl (void *)in_args->host_addr); 829*25cf1a30Sjl otd.ot_trampoline = tramp; 830*25cf1a30Sjl } else 831*25cf1a30Sjl err = DDI_FAILURE; 832*25cf1a30Sjl 833*25cf1a30Sjl no_trap(); 834*25cf1a30Sjl 835*25cf1a30Sjl #ifdef DEBUG 836*25cf1a30Sjl if (err == DDI_FAILURE) 837*25cf1a30Sjl pcmu_peekfault_cnt++; 838*25cf1a30Sjl #endif 839*25cf1a30Sjl return (err); 840*25cf1a30Sjl } 841*25cf1a30Sjl 842*25cf1a30Sjl 843*25cf1a30Sjl static int 844*25cf1a30Sjl pcmu_ctlops_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args, void *result) 845*25cf1a30Sjl { 846*25cf1a30Sjl result = (void *)in_args->host_addr; 847*25cf1a30Sjl return (pcmu_do_peek(pcmu_p, in_args)); 848*25cf1a30Sjl } 849*25cf1a30Sjl 850*25cf1a30Sjl /* 851*25cf1a30Sjl * control ops entry point: 852*25cf1a30Sjl * 853*25cf1a30Sjl * Requests handled completely: 854*25cf1a30Sjl * DDI_CTLOPS_INITCHILD see pcmu_init_child() for details 855*25cf1a30Sjl * DDI_CTLOPS_UNINITCHILD 856*25cf1a30Sjl * DDI_CTLOPS_REPORTDEV see report_dev() for details 857*25cf1a30Sjl * DDI_CTLOPS_XLATE_INTRS nothing to do 858*25cf1a30Sjl * DDI_CTLOPS_IOMIN cache line size if streaming otherwise 1 859*25cf1a30Sjl * DDI_CTLOPS_REGSIZE 860*25cf1a30Sjl * DDI_CTLOPS_NREGS 861*25cf1a30Sjl * DDI_CTLOPS_NINTRS 862*25cf1a30Sjl * DDI_CTLOPS_DVMAPAGESIZE 863*25cf1a30Sjl * DDI_CTLOPS_POKE 864*25cf1a30Sjl * DDI_CTLOPS_PEEK 865*25cf1a30Sjl * DDI_CTLOPS_QUIESCE 866*25cf1a30Sjl * DDI_CTLOPS_UNQUIESCE 867*25cf1a30Sjl * 868*25cf1a30Sjl * All others passed to parent. 869*25cf1a30Sjl */ 870*25cf1a30Sjl static int 871*25cf1a30Sjl pcmu_ctlops(dev_info_t *dip, dev_info_t *rdip, 872*25cf1a30Sjl ddi_ctl_enum_t op, void *arg, void *result) 873*25cf1a30Sjl { 874*25cf1a30Sjl pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); 875*25cf1a30Sjl 876*25cf1a30Sjl switch (op) { 877*25cf1a30Sjl case DDI_CTLOPS_INITCHILD: 878*25cf1a30Sjl return (pcmu_init_child(pcmu_p, (dev_info_t *)arg)); 879*25cf1a30Sjl 880*25cf1a30Sjl case DDI_CTLOPS_UNINITCHILD: 881*25cf1a30Sjl return (pcmu_uninit_child(pcmu_p, (dev_info_t *)arg)); 882*25cf1a30Sjl 883*25cf1a30Sjl case DDI_CTLOPS_REPORTDEV: 884*25cf1a30Sjl return (pcmu_report_dev(rdip)); 885*25cf1a30Sjl 886*25cf1a30Sjl case DDI_CTLOPS_IOMIN: 887*25cf1a30Sjl /* 888*25cf1a30Sjl * If we are using the streaming cache, align at 889*25cf1a30Sjl * least on a cache line boundary. Otherwise use 890*25cf1a30Sjl * whatever alignment is passed in. 891*25cf1a30Sjl */ 892*25cf1a30Sjl return (DDI_SUCCESS); 893*25cf1a30Sjl 894*25cf1a30Sjl case DDI_CTLOPS_REGSIZE: 895*25cf1a30Sjl *((off_t *)result) = pcmu_get_reg_set_size(rdip, *((int *)arg)); 896*25cf1a30Sjl return (DDI_SUCCESS); 897*25cf1a30Sjl 898*25cf1a30Sjl case DDI_CTLOPS_NREGS: 899*25cf1a30Sjl *((uint_t *)result) = pcmu_get_nreg_set(rdip); 900*25cf1a30Sjl return (DDI_SUCCESS); 901*25cf1a30Sjl 902*25cf1a30Sjl case DDI_CTLOPS_DVMAPAGESIZE: 903*25cf1a30Sjl *((ulong_t *)result) = 0; 904*25cf1a30Sjl return (DDI_SUCCESS); 905*25cf1a30Sjl 906*25cf1a30Sjl case DDI_CTLOPS_POKE: 907*25cf1a30Sjl return (pcmu_ctlops_poke(pcmu_p, (peekpoke_ctlops_t *)arg)); 908*25cf1a30Sjl 909*25cf1a30Sjl case DDI_CTLOPS_PEEK: 910*25cf1a30Sjl return (pcmu_ctlops_peek(pcmu_p, (peekpoke_ctlops_t *)arg, 911*25cf1a30Sjl result)); 912*25cf1a30Sjl 913*25cf1a30Sjl case DDI_CTLOPS_AFFINITY: 914*25cf1a30Sjl break; 915*25cf1a30Sjl 916*25cf1a30Sjl case DDI_CTLOPS_QUIESCE: 917*25cf1a30Sjl return (DDI_FAILURE); 918*25cf1a30Sjl 919*25cf1a30Sjl case DDI_CTLOPS_UNQUIESCE: 920*25cf1a30Sjl return (DDI_FAILURE); 921*25cf1a30Sjl 922*25cf1a30Sjl default: 923*25cf1a30Sjl break; 924*25cf1a30Sjl } 925*25cf1a30Sjl 926*25cf1a30Sjl /* 927*25cf1a30Sjl * Now pass the request up to our parent. 928*25cf1a30Sjl */ 929*25cf1a30Sjl PCMU_DBG2(PCMU_DBG_CTLOPS, dip, 930*25cf1a30Sjl "passing request to parent: rdip=%s%d\n", 931*25cf1a30Sjl ddi_driver_name(rdip), ddi_get_instance(rdip)); 932*25cf1a30Sjl return (ddi_ctlops(dip, rdip, op, arg, result)); 933*25cf1a30Sjl } 934*25cf1a30Sjl 935*25cf1a30Sjl 936*25cf1a30Sjl /* ARGSUSED */ 937*25cf1a30Sjl static int 938*25cf1a30Sjl pcmu_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 939*25cf1a30Sjl ddi_intr_handle_impl_t *hdlp, void *result) 940*25cf1a30Sjl { 941*25cf1a30Sjl pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); 942*25cf1a30Sjl int ret = DDI_SUCCESS; 943*25cf1a30Sjl 944*25cf1a30Sjl switch (intr_op) { 945*25cf1a30Sjl case DDI_INTROP_GETCAP: 946*25cf1a30Sjl /* GetCap will always fail for all non PCI devices */ 947*25cf1a30Sjl (void) pci_intx_get_cap(rdip, (int *)result); 948*25cf1a30Sjl break; 949*25cf1a30Sjl case DDI_INTROP_SETCAP: 950*25cf1a30Sjl ret = DDI_ENOTSUP; 951*25cf1a30Sjl break; 952*25cf1a30Sjl case DDI_INTROP_ALLOC: 953*25cf1a30Sjl *(int *)result = hdlp->ih_scratch1; 954*25cf1a30Sjl break; 955*25cf1a30Sjl case DDI_INTROP_FREE: 956*25cf1a30Sjl break; 957*25cf1a30Sjl case DDI_INTROP_GETPRI: 958*25cf1a30Sjl *(int *)result = hdlp->ih_pri ? hdlp->ih_pri : 0; 959*25cf1a30Sjl break; 960*25cf1a30Sjl case DDI_INTROP_SETPRI: 961*25cf1a30Sjl break; 962*25cf1a30Sjl case DDI_INTROP_ADDISR: 963*25cf1a30Sjl ret = pcmu_add_intr(dip, rdip, hdlp); 964*25cf1a30Sjl break; 965*25cf1a30Sjl case DDI_INTROP_REMISR: 966*25cf1a30Sjl ret = pcmu_remove_intr(dip, rdip, hdlp); 967*25cf1a30Sjl break; 968*25cf1a30Sjl case DDI_INTROP_ENABLE: 969*25cf1a30Sjl ret = pcmu_ib_update_intr_state(pcmu_p, rdip, hdlp, 970*25cf1a30Sjl PCMU_INTR_STATE_ENABLE); 971*25cf1a30Sjl break; 972*25cf1a30Sjl case DDI_INTROP_DISABLE: 973*25cf1a30Sjl ret = pcmu_ib_update_intr_state(pcmu_p, rdip, hdlp, 974*25cf1a30Sjl PCMU_INTR_STATE_DISABLE); 975*25cf1a30Sjl break; 976*25cf1a30Sjl case DDI_INTROP_SETMASK: 977*25cf1a30Sjl ret = pci_intx_set_mask(rdip); 978*25cf1a30Sjl break; 979*25cf1a30Sjl case DDI_INTROP_CLRMASK: 980*25cf1a30Sjl ret = pci_intx_clr_mask(rdip); 981*25cf1a30Sjl break; 982*25cf1a30Sjl case DDI_INTROP_GETPENDING: 983*25cf1a30Sjl ret = pci_intx_get_pending(rdip, (int *)result); 984*25cf1a30Sjl break; 985*25cf1a30Sjl case DDI_INTROP_NINTRS: 986*25cf1a30Sjl case DDI_INTROP_NAVAIL: 987*25cf1a30Sjl *(int *)result = i_ddi_get_nintrs(rdip); 988*25cf1a30Sjl break; 989*25cf1a30Sjl case DDI_INTROP_SUPPORTED_TYPES: 990*25cf1a30Sjl /* PCI nexus driver supports only fixed interrupts */ 991*25cf1a30Sjl *(int *)result = i_ddi_get_nintrs(rdip) ? 992*25cf1a30Sjl DDI_INTR_TYPE_FIXED : 0; 993*25cf1a30Sjl break; 994*25cf1a30Sjl default: 995*25cf1a30Sjl ret = DDI_ENOTSUP; 996*25cf1a30Sjl break; 997*25cf1a30Sjl } 998*25cf1a30Sjl 999*25cf1a30Sjl return (ret); 1000*25cf1a30Sjl } 1001*25cf1a30Sjl 1002*25cf1a30Sjl /* 1003*25cf1a30Sjl * CMU-CH specifics implementation: 1004*25cf1a30Sjl * interrupt mapping register 1005*25cf1a30Sjl * PBM configuration 1006*25cf1a30Sjl * ECC and PBM error handling 1007*25cf1a30Sjl */ 1008*25cf1a30Sjl 1009*25cf1a30Sjl /* called by pcmu_attach() DDI_ATTACH to initialize pci objects */ 1010*25cf1a30Sjl static int 1011*25cf1a30Sjl pcmu_obj_setup(pcmu_t *pcmu_p) 1012*25cf1a30Sjl { 1013*25cf1a30Sjl int ret; 1014*25cf1a30Sjl 1015*25cf1a30Sjl mutex_enter(&pcmu_global_mutex); 1016*25cf1a30Sjl pcmu_p->pcmu_rev = ddi_prop_get_int(DDI_DEV_T_ANY, pcmu_p->pcmu_dip, 1017*25cf1a30Sjl DDI_PROP_DONTPASS, "module-revision#", 0); 1018*25cf1a30Sjl 1019*25cf1a30Sjl pcmu_ib_create(pcmu_p); 1020*25cf1a30Sjl pcmu_cb_create(pcmu_p); 1021*25cf1a30Sjl pcmu_ecc_create(pcmu_p); 1022*25cf1a30Sjl pcmu_pbm_create(pcmu_p); 1023*25cf1a30Sjl pcmu_err_create(pcmu_p); 1024*25cf1a30Sjl if ((ret = pcmu_intr_setup(pcmu_p)) != DDI_SUCCESS) 1025*25cf1a30Sjl goto done; 1026*25cf1a30Sjl 1027*25cf1a30Sjl pcmu_kstat_create(pcmu_p); 1028*25cf1a30Sjl done: 1029*25cf1a30Sjl mutex_exit(&pcmu_global_mutex); 1030*25cf1a30Sjl if (ret != DDI_SUCCESS) { 1031*25cf1a30Sjl cmn_err(CE_NOTE, "Interrupt register failure, returning 0x%x\n", 1032*25cf1a30Sjl ret); 1033*25cf1a30Sjl } 1034*25cf1a30Sjl return (ret); 1035*25cf1a30Sjl } 1036*25cf1a30Sjl 1037*25cf1a30Sjl /* called by pcmu_detach() DDI_DETACH to destroy pci objects */ 1038*25cf1a30Sjl static void 1039*25cf1a30Sjl pcmu_obj_destroy(pcmu_t *pcmu_p) 1040*25cf1a30Sjl { 1041*25cf1a30Sjl mutex_enter(&pcmu_global_mutex); 1042*25cf1a30Sjl 1043*25cf1a30Sjl pcmu_kstat_destroy(pcmu_p); 1044*25cf1a30Sjl pcmu_pbm_destroy(pcmu_p); 1045*25cf1a30Sjl pcmu_err_destroy(pcmu_p); 1046*25cf1a30Sjl pcmu_ecc_destroy(pcmu_p); 1047*25cf1a30Sjl pcmu_cb_destroy(pcmu_p); 1048*25cf1a30Sjl pcmu_ib_destroy(pcmu_p); 1049*25cf1a30Sjl pcmu_intr_teardown(pcmu_p); 1050*25cf1a30Sjl 1051*25cf1a30Sjl mutex_exit(&pcmu_global_mutex); 1052*25cf1a30Sjl } 1053*25cf1a30Sjl 1054*25cf1a30Sjl /* called by pcmu_attach() DDI_RESUME to (re)initialize pci objects */ 1055*25cf1a30Sjl static void 1056*25cf1a30Sjl pcmu_obj_resume(pcmu_t *pcmu_p) 1057*25cf1a30Sjl { 1058*25cf1a30Sjl mutex_enter(&pcmu_global_mutex); 1059*25cf1a30Sjl 1060*25cf1a30Sjl pcmu_ib_configure(pcmu_p->pcmu_ib_p); 1061*25cf1a30Sjl pcmu_ecc_configure(pcmu_p); 1062*25cf1a30Sjl pcmu_ib_resume(pcmu_p->pcmu_ib_p); 1063*25cf1a30Sjl u2u_ittrans_resume((u2u_ittrans_data_t **) 1064*25cf1a30Sjl &(pcmu_p->pcmu_cb_p->pcb_ittrans_cookie)); 1065*25cf1a30Sjl 1066*25cf1a30Sjl pcmu_pbm_configure(pcmu_p->pcmu_pcbm_p); 1067*25cf1a30Sjl 1068*25cf1a30Sjl pcmu_cb_resume(pcmu_p->pcmu_cb_p); 1069*25cf1a30Sjl 1070*25cf1a30Sjl pcmu_pbm_resume(pcmu_p->pcmu_pcbm_p); 1071*25cf1a30Sjl 1072*25cf1a30Sjl mutex_exit(&pcmu_global_mutex); 1073*25cf1a30Sjl } 1074*25cf1a30Sjl 1075*25cf1a30Sjl /* called by pcmu_detach() DDI_SUSPEND to suspend pci objects */ 1076*25cf1a30Sjl static void 1077*25cf1a30Sjl pcmu_obj_suspend(pcmu_t *pcmu_p) 1078*25cf1a30Sjl { 1079*25cf1a30Sjl mutex_enter(&pcmu_global_mutex); 1080*25cf1a30Sjl 1081*25cf1a30Sjl pcmu_pbm_suspend(pcmu_p->pcmu_pcbm_p); 1082*25cf1a30Sjl pcmu_ib_suspend(pcmu_p->pcmu_ib_p); 1083*25cf1a30Sjl pcmu_cb_suspend(pcmu_p->pcmu_cb_p); 1084*25cf1a30Sjl 1085*25cf1a30Sjl mutex_exit(&pcmu_global_mutex); 1086*25cf1a30Sjl } 1087*25cf1a30Sjl 1088*25cf1a30Sjl static int 1089*25cf1a30Sjl pcmu_intr_setup(pcmu_t *pcmu_p) 1090*25cf1a30Sjl { 1091*25cf1a30Sjl dev_info_t *dip = pcmu_p->pcmu_dip; 1092*25cf1a30Sjl pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 1093*25cf1a30Sjl pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; 1094*25cf1a30Sjl int i, no_of_intrs; 1095*25cf1a30Sjl 1096*25cf1a30Sjl /* 1097*25cf1a30Sjl * Get the interrupts property. 1098*25cf1a30Sjl */ 1099*25cf1a30Sjl if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 1100*25cf1a30Sjl "interrupts", (caddr_t)&pcmu_p->pcmu_inos, 1101*25cf1a30Sjl &pcmu_p->pcmu_inos_len) != DDI_SUCCESS) { 1102*25cf1a30Sjl cmn_err(CE_PANIC, "%s%d: no interrupts property\n", 1103*25cf1a30Sjl ddi_driver_name(dip), ddi_get_instance(dip)); 1104*25cf1a30Sjl } 1105*25cf1a30Sjl 1106*25cf1a30Sjl /* 1107*25cf1a30Sjl * figure out number of interrupts in the "interrupts" property 1108*25cf1a30Sjl * and convert them all into ino. 1109*25cf1a30Sjl */ 1110*25cf1a30Sjl i = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "#interrupt-cells", 1); 1111*25cf1a30Sjl i = CELLS_1275_TO_BYTES(i); 1112*25cf1a30Sjl no_of_intrs = pcmu_p->pcmu_inos_len / i; 1113*25cf1a30Sjl for (i = 0; i < no_of_intrs; i++) { 1114*25cf1a30Sjl pcmu_p->pcmu_inos[i] = 1115*25cf1a30Sjl PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[i]); 1116*25cf1a30Sjl } 1117*25cf1a30Sjl 1118*25cf1a30Sjl pcb_p->pcb_no_of_inos = no_of_intrs; 1119*25cf1a30Sjl if (i = pcmu_ecc_register_intr(pcmu_p)) { 1120*25cf1a30Sjl goto teardown; 1121*25cf1a30Sjl } 1122*25cf1a30Sjl 1123*25cf1a30Sjl intr_dist_add(pcmu_cb_intr_dist, pcb_p); 1124*25cf1a30Sjl pcmu_ecc_enable_intr(pcmu_p); 1125*25cf1a30Sjl 1126*25cf1a30Sjl if (i = pcmu_pbm_register_intr(pcbm_p)) { 1127*25cf1a30Sjl intr_dist_rem(pcmu_cb_intr_dist, pcb_p); 1128*25cf1a30Sjl goto teardown; 1129*25cf1a30Sjl } 1130*25cf1a30Sjl intr_dist_add(pcmu_pbm_intr_dist, pcbm_p); 1131*25cf1a30Sjl pcmu_ib_intr_enable(pcmu_p, pcmu_p->pcmu_inos[CBNINTR_PBM]); 1132*25cf1a30Sjl 1133*25cf1a30Sjl intr_dist_add_weighted(pcmu_ib_intr_dist_all, pcmu_p->pcmu_ib_p); 1134*25cf1a30Sjl return (DDI_SUCCESS); 1135*25cf1a30Sjl teardown: 1136*25cf1a30Sjl pcmu_intr_teardown(pcmu_p); 1137*25cf1a30Sjl return (i); 1138*25cf1a30Sjl } 1139*25cf1a30Sjl 1140*25cf1a30Sjl /* 1141*25cf1a30Sjl * pcmu_fix_ranges - fixes the config space entry of the "ranges" 1142*25cf1a30Sjl * property on CMU-CH platforms 1143*25cf1a30Sjl */ 1144*25cf1a30Sjl void 1145*25cf1a30Sjl pcmu_fix_ranges(pcmu_ranges_t *rng_p, int rng_entries) 1146*25cf1a30Sjl { 1147*25cf1a30Sjl int i; 1148*25cf1a30Sjl for (i = 0; i < rng_entries; i++, rng_p++) { 1149*25cf1a30Sjl if ((rng_p->child_high & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) 1150*25cf1a30Sjl rng_p->parent_low |= rng_p->child_high; 1151*25cf1a30Sjl } 1152*25cf1a30Sjl } 1153*25cf1a30Sjl 1154*25cf1a30Sjl /* 1155*25cf1a30Sjl * map_pcmu_registers 1156*25cf1a30Sjl * 1157*25cf1a30Sjl * This function is called from the attach routine to map the registers 1158*25cf1a30Sjl * accessed by this driver. 1159*25cf1a30Sjl * 1160*25cf1a30Sjl * used by: pcmu_attach() 1161*25cf1a30Sjl * 1162*25cf1a30Sjl * return value: DDI_FAILURE on failure 1163*25cf1a30Sjl */ 1164*25cf1a30Sjl static int 1165*25cf1a30Sjl map_pcmu_registers(pcmu_t *pcmu_p, dev_info_t *dip) 1166*25cf1a30Sjl { 1167*25cf1a30Sjl ddi_device_acc_attr_t attr; 1168*25cf1a30Sjl 1169*25cf1a30Sjl attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1170*25cf1a30Sjl attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1171*25cf1a30Sjl 1172*25cf1a30Sjl attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 1173*25cf1a30Sjl if (ddi_regs_map_setup(dip, 0, &pcmu_p->pcmu_address[0], 0, 0, 1174*25cf1a30Sjl &attr, &pcmu_p->pcmu_ac[0]) != DDI_SUCCESS) { 1175*25cf1a30Sjl cmn_err(CE_WARN, "%s%d: unable to map reg entry 0\n", 1176*25cf1a30Sjl ddi_driver_name(dip), ddi_get_instance(dip)); 1177*25cf1a30Sjl return (DDI_FAILURE); 1178*25cf1a30Sjl } 1179*25cf1a30Sjl 1180*25cf1a30Sjl /* 1181*25cf1a30Sjl * We still use pcmu_address[2] 1182*25cf1a30Sjl */ 1183*25cf1a30Sjl if (ddi_regs_map_setup(dip, 2, &pcmu_p->pcmu_address[2], 0, 0, 1184*25cf1a30Sjl &attr, &pcmu_p->pcmu_ac[2]) != DDI_SUCCESS) { 1185*25cf1a30Sjl cmn_err(CE_WARN, "%s%d: unable to map reg entry 2\n", 1186*25cf1a30Sjl ddi_driver_name(dip), ddi_get_instance(dip)); 1187*25cf1a30Sjl ddi_regs_map_free(&pcmu_p->pcmu_ac[0]); 1188*25cf1a30Sjl return (DDI_FAILURE); 1189*25cf1a30Sjl } 1190*25cf1a30Sjl 1191*25cf1a30Sjl /* 1192*25cf1a30Sjl * The second register set contains the bridge's configuration 1193*25cf1a30Sjl * header. This header is at the very beginning of the bridge's 1194*25cf1a30Sjl * configuration space. This space has litte-endian byte order. 1195*25cf1a30Sjl */ 1196*25cf1a30Sjl attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 1197*25cf1a30Sjl if (ddi_regs_map_setup(dip, 1, &pcmu_p->pcmu_address[1], 0, 1198*25cf1a30Sjl PCI_CONF_HDR_SIZE, &attr, &pcmu_p->pcmu_ac[1]) != DDI_SUCCESS) { 1199*25cf1a30Sjl 1200*25cf1a30Sjl cmn_err(CE_WARN, "%s%d: unable to map reg entry 1\n", 1201*25cf1a30Sjl ddi_driver_name(dip), ddi_get_instance(dip)); 1202*25cf1a30Sjl ddi_regs_map_free(&pcmu_p->pcmu_ac[0]); 1203*25cf1a30Sjl return (DDI_FAILURE); 1204*25cf1a30Sjl } 1205*25cf1a30Sjl PCMU_DBG2(PCMU_DBG_ATTACH, dip, "address (%p,%p)\n", 1206*25cf1a30Sjl pcmu_p->pcmu_address[0], pcmu_p->pcmu_address[1]); 1207*25cf1a30Sjl return (DDI_SUCCESS); 1208*25cf1a30Sjl } 1209*25cf1a30Sjl 1210*25cf1a30Sjl /* 1211*25cf1a30Sjl * unmap_pcmu_registers: 1212*25cf1a30Sjl * 1213*25cf1a30Sjl * This routine unmap the registers mapped by map_pcmu_registers. 1214*25cf1a30Sjl * 1215*25cf1a30Sjl * used by: pcmu_detach() 1216*25cf1a30Sjl * 1217*25cf1a30Sjl * return value: none 1218*25cf1a30Sjl */ 1219*25cf1a30Sjl static void 1220*25cf1a30Sjl unmap_pcmu_registers(pcmu_t *pcmu_p) 1221*25cf1a30Sjl { 1222*25cf1a30Sjl ddi_regs_map_free(&pcmu_p->pcmu_ac[0]); 1223*25cf1a30Sjl ddi_regs_map_free(&pcmu_p->pcmu_ac[1]); 1224*25cf1a30Sjl ddi_regs_map_free(&pcmu_p->pcmu_ac[2]); 1225*25cf1a30Sjl } 1226*25cf1a30Sjl 1227*25cf1a30Sjl /* 1228*25cf1a30Sjl * These convenience wrappers relies on map_pcmu_registers() to setup 1229*25cf1a30Sjl * pcmu_address[0-2] correctly at first. 1230*25cf1a30Sjl */ 1231*25cf1a30Sjl static uintptr_t 1232*25cf1a30Sjl get_reg_base(pcmu_t *pcmu_p) 1233*25cf1a30Sjl { 1234*25cf1a30Sjl return ((uintptr_t)pcmu_p->pcmu_address[2]); 1235*25cf1a30Sjl } 1236*25cf1a30Sjl 1237*25cf1a30Sjl /* The CMU-CH config reg base is always the 2nd reg entry */ 1238*25cf1a30Sjl static uintptr_t 1239*25cf1a30Sjl get_config_reg_base(pcmu_t *pcmu_p) 1240*25cf1a30Sjl { 1241*25cf1a30Sjl return ((uintptr_t)(pcmu_p->pcmu_address[1])); 1242*25cf1a30Sjl } 1243*25cf1a30Sjl 1244*25cf1a30Sjl uint64_t 1245*25cf1a30Sjl ib_get_map_reg(pcmu_ib_mondo_t mondo, uint32_t cpu_id) 1246*25cf1a30Sjl { 1247*25cf1a30Sjl return ((mondo) | (cpu_id << PCMU_INTR_MAP_REG_TID_SHIFT) | 1248*25cf1a30Sjl PCMU_INTR_MAP_REG_VALID); 1249*25cf1a30Sjl 1250*25cf1a30Sjl } 1251*25cf1a30Sjl 1252*25cf1a30Sjl uint32_t 1253*25cf1a30Sjl ib_map_reg_get_cpu(volatile uint64_t reg) 1254*25cf1a30Sjl { 1255*25cf1a30Sjl return ((reg & PCMU_INTR_MAP_REG_TID) >> 1256*25cf1a30Sjl PCMU_INTR_MAP_REG_TID_SHIFT); 1257*25cf1a30Sjl } 1258*25cf1a30Sjl 1259*25cf1a30Sjl uint64_t * 1260*25cf1a30Sjl ib_intr_map_reg_addr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino) 1261*25cf1a30Sjl { 1262*25cf1a30Sjl uint64_t *addr; 1263*25cf1a30Sjl 1264*25cf1a30Sjl ASSERT(ino & 0x20); 1265*25cf1a30Sjl addr = (uint64_t *)(pib_p->pib_obio_intr_map_regs + 1266*25cf1a30Sjl (((uint_t)ino & 0x1f) << 3)); 1267*25cf1a30Sjl return (addr); 1268*25cf1a30Sjl } 1269*25cf1a30Sjl 1270*25cf1a30Sjl uint64_t * 1271*25cf1a30Sjl ib_clear_intr_reg_addr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino) 1272*25cf1a30Sjl { 1273*25cf1a30Sjl uint64_t *addr; 1274*25cf1a30Sjl 1275*25cf1a30Sjl ASSERT(ino & 0x20); 1276*25cf1a30Sjl addr = (uint64_t *)(pib_p->pib_obio_clear_intr_regs + 1277*25cf1a30Sjl (((uint_t)ino & 0x1f) << 3)); 1278*25cf1a30Sjl return (addr); 1279*25cf1a30Sjl } 1280*25cf1a30Sjl 1281*25cf1a30Sjl uintptr_t 1282*25cf1a30Sjl pcmu_ib_setup(pcmu_ib_t *pib_p) 1283*25cf1a30Sjl { 1284*25cf1a30Sjl pcmu_t *pcmu_p = pib_p->pib_pcmu_p; 1285*25cf1a30Sjl uintptr_t a = get_reg_base(pcmu_p); 1286*25cf1a30Sjl 1287*25cf1a30Sjl pib_p->pib_ign = PCMU_ID_TO_IGN(pcmu_p->pcmu_id); 1288*25cf1a30Sjl pib_p->pib_max_ino = PCMU_MAX_INO; 1289*25cf1a30Sjl pib_p->pib_obio_intr_map_regs = a + PCMU_IB_OBIO_INTR_MAP_REG_OFFSET; 1290*25cf1a30Sjl pib_p->pib_obio_clear_intr_regs = 1291*25cf1a30Sjl a + PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET; 1292*25cf1a30Sjl return (a); 1293*25cf1a30Sjl } 1294*25cf1a30Sjl 1295*25cf1a30Sjl /* 1296*25cf1a30Sjl * Return the cpuid to to be used for an ino. 1297*25cf1a30Sjl * 1298*25cf1a30Sjl * On multi-function pci devices, functions have separate devinfo nodes and 1299*25cf1a30Sjl * interrupts. 1300*25cf1a30Sjl * 1301*25cf1a30Sjl * This function determines if there is already an established slot-oriented 1302*25cf1a30Sjl * interrupt-to-cpu binding established, if there is then it returns that 1303*25cf1a30Sjl * cpu. Otherwise a new cpu is selected by intr_dist_cpuid(). 1304*25cf1a30Sjl * 1305*25cf1a30Sjl * The devinfo node we are trying to associate a cpu with is 1306*25cf1a30Sjl * ino_p->pino_ih_head->ih_dip. 1307*25cf1a30Sjl */ 1308*25cf1a30Sjl uint32_t 1309*25cf1a30Sjl pcmu_intr_dist_cpuid(pcmu_ib_t *pib_p, pcmu_ib_ino_info_t *ino_p) 1310*25cf1a30Sjl { 1311*25cf1a30Sjl dev_info_t *rdip = ino_p->pino_ih_head->ih_dip; 1312*25cf1a30Sjl dev_info_t *prdip = ddi_get_parent(rdip); 1313*25cf1a30Sjl pcmu_ib_ino_info_t *sino_p; 1314*25cf1a30Sjl dev_info_t *sdip; 1315*25cf1a30Sjl dev_info_t *psdip; 1316*25cf1a30Sjl char *buf1 = NULL, *buf2 = NULL; 1317*25cf1a30Sjl char *s1, *s2, *s3; 1318*25cf1a30Sjl int l2; 1319*25cf1a30Sjl int cpu_id; 1320*25cf1a30Sjl 1321*25cf1a30Sjl /* must be CMU-CH driver parent (not ebus) */ 1322*25cf1a30Sjl if (strcmp(ddi_driver_name(prdip), "pcicmu") != 0) 1323*25cf1a30Sjl goto newcpu; 1324*25cf1a30Sjl 1325*25cf1a30Sjl /* 1326*25cf1a30Sjl * From PCI 1275 binding: 2.2.1.3 Unit Address representation: 1327*25cf1a30Sjl * Since the "unit-number" is the address that appears in on Open 1328*25cf1a30Sjl * Firmware 'device path', it follows that only the DD and DD,FF 1329*25cf1a30Sjl * forms of the text representation can appear in a 'device path'. 1330*25cf1a30Sjl * 1331*25cf1a30Sjl * The rdip unit address is of the form "DD[,FF]". Define two 1332*25cf1a30Sjl * unit address strings that represent same-slot use: "DD" and "DD,". 1333*25cf1a30Sjl * The first compare uses strcmp, the second uses strncmp. 1334*25cf1a30Sjl */ 1335*25cf1a30Sjl s1 = ddi_get_name_addr(rdip); 1336*25cf1a30Sjl if (s1 == NULL) { 1337*25cf1a30Sjl goto newcpu; 1338*25cf1a30Sjl } 1339*25cf1a30Sjl 1340*25cf1a30Sjl buf1 = kmem_alloc(MAXNAMELEN, KM_SLEEP); /* strcmp */ 1341*25cf1a30Sjl buf2 = kmem_alloc(MAXNAMELEN, KM_SLEEP); /* strncmp */ 1342*25cf1a30Sjl s1 = strcpy(buf1, s1); 1343*25cf1a30Sjl s2 = strcpy(buf2, s1); 1344*25cf1a30Sjl 1345*25cf1a30Sjl s1 = strrchr(s1, ','); 1346*25cf1a30Sjl if (s1) { 1347*25cf1a30Sjl *s1 = '\0'; /* have "DD,FF" */ 1348*25cf1a30Sjl s1 = buf1; /* search via strcmp "DD" */ 1349*25cf1a30Sjl 1350*25cf1a30Sjl s2 = strrchr(s2, ','); 1351*25cf1a30Sjl *(s2 + 1) = '\0'; 1352*25cf1a30Sjl s2 = buf2; 1353*25cf1a30Sjl l2 = strlen(s2); /* search via strncmp "DD," */ 1354*25cf1a30Sjl } else { 1355*25cf1a30Sjl (void) strcat(s2, ","); /* have "DD" */ 1356*25cf1a30Sjl l2 = strlen(s2); /* search via strncmp "DD," */ 1357*25cf1a30Sjl } 1358*25cf1a30Sjl 1359*25cf1a30Sjl /* 1360*25cf1a30Sjl * Search the established ino list for devinfo nodes bound 1361*25cf1a30Sjl * to an ino that matches one of the slot use strings. 1362*25cf1a30Sjl */ 1363*25cf1a30Sjl ASSERT(MUTEX_HELD(&pib_p->pib_ino_lst_mutex)); 1364*25cf1a30Sjl for (sino_p = pib_p->pib_ino_lst; sino_p; sino_p = sino_p->pino_next) { 1365*25cf1a30Sjl /* skip self and non-established */ 1366*25cf1a30Sjl if ((sino_p == ino_p) || (sino_p->pino_established == 0)) 1367*25cf1a30Sjl continue; 1368*25cf1a30Sjl 1369*25cf1a30Sjl /* skip non-siblings */ 1370*25cf1a30Sjl sdip = sino_p->pino_ih_head->ih_dip; 1371*25cf1a30Sjl psdip = ddi_get_parent(sdip); 1372*25cf1a30Sjl if (psdip != prdip) 1373*25cf1a30Sjl continue; 1374*25cf1a30Sjl 1375*25cf1a30Sjl /* must be CMU-CH driver parent (not ebus) */ 1376*25cf1a30Sjl if (strcmp(ddi_driver_name(psdip), "pcicmu") != 0) 1377*25cf1a30Sjl continue; 1378*25cf1a30Sjl 1379*25cf1a30Sjl s3 = ddi_get_name_addr(sdip); 1380*25cf1a30Sjl if ((s1 && (strcmp(s1, s3) == 0)) || 1381*25cf1a30Sjl (strncmp(s2, s3, l2) == 0)) { 1382*25cf1a30Sjl extern int intr_dist_debug; 1383*25cf1a30Sjl 1384*25cf1a30Sjl if (intr_dist_debug) { 1385*25cf1a30Sjl cmn_err(CE_CONT, "intr_dist: " 1386*25cf1a30Sjl "pcicmu`pcmu_intr_dist_cpuid " 1387*25cf1a30Sjl "%s#%d %s: cpu %d established " 1388*25cf1a30Sjl "by %s#%d %s\n", ddi_driver_name(rdip), 1389*25cf1a30Sjl ddi_get_instance(rdip), 1390*25cf1a30Sjl ddi_deviname(rdip, buf1), 1391*25cf1a30Sjl sino_p->pino_cpuid, 1392*25cf1a30Sjl ddi_driver_name(sdip), 1393*25cf1a30Sjl ddi_get_instance(sdip), 1394*25cf1a30Sjl ddi_deviname(sdip, buf2)); 1395*25cf1a30Sjl } 1396*25cf1a30Sjl break; 1397*25cf1a30Sjl } 1398*25cf1a30Sjl } 1399*25cf1a30Sjl 1400*25cf1a30Sjl /* If a slot use match is found then use established cpu */ 1401*25cf1a30Sjl if (sino_p) { 1402*25cf1a30Sjl cpu_id = sino_p->pino_cpuid; /* target established cpu */ 1403*25cf1a30Sjl goto out; 1404*25cf1a30Sjl } 1405*25cf1a30Sjl 1406*25cf1a30Sjl newcpu: cpu_id = intr_dist_cpuid(); /* target new cpu */ 1407*25cf1a30Sjl 1408*25cf1a30Sjl out: if (buf1) 1409*25cf1a30Sjl kmem_free(buf1, MAXNAMELEN); 1410*25cf1a30Sjl if (buf2) 1411*25cf1a30Sjl kmem_free(buf2, MAXNAMELEN); 1412*25cf1a30Sjl return (cpu_id); 1413*25cf1a30Sjl } 1414*25cf1a30Sjl 1415*25cf1a30Sjl void 1416*25cf1a30Sjl pcmu_cb_teardown(pcmu_t *pcmu_p) 1417*25cf1a30Sjl { 1418*25cf1a30Sjl pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; 1419*25cf1a30Sjl 1420*25cf1a30Sjl u2u_ittrans_uninit((u2u_ittrans_data_t *)pcb_p->pcb_ittrans_cookie); 1421*25cf1a30Sjl } 1422*25cf1a30Sjl 1423*25cf1a30Sjl int 1424*25cf1a30Sjl pcmu_ecc_add_intr(pcmu_t *pcmu_p, int inum, pcmu_ecc_intr_info_t *eii_p) 1425*25cf1a30Sjl { 1426*25cf1a30Sjl uint32_t mondo; 1427*25cf1a30Sjl 1428*25cf1a30Sjl mondo = ((pcmu_p->pcmu_cb_p->pcb_ign << PCMU_INO_BITS) | 1429*25cf1a30Sjl pcmu_p->pcmu_inos[inum]); 1430*25cf1a30Sjl 1431*25cf1a30Sjl VERIFY(add_ivintr(mondo, pcmu_pil[inum], pcmu_ecc_intr, 1432*25cf1a30Sjl (caddr_t)eii_p, NULL) == 0); 1433*25cf1a30Sjl return (PCMU_ATTACH_RETCODE(PCMU_ECC_OBJ, 1434*25cf1a30Sjl PCMU_OBJ_INTR_ADD, DDI_SUCCESS)); 1435*25cf1a30Sjl } 1436*25cf1a30Sjl 1437*25cf1a30Sjl /* ARGSUSED */ 1438*25cf1a30Sjl void 1439*25cf1a30Sjl pcmu_ecc_rem_intr(pcmu_t *pcmu_p, int inum, pcmu_ecc_intr_info_t *eii_p) 1440*25cf1a30Sjl { 1441*25cf1a30Sjl uint32_t mondo; 1442*25cf1a30Sjl 1443*25cf1a30Sjl mondo = ((pcmu_p->pcmu_cb_p->pcb_ign << PCMU_INO_BITS) | 1444*25cf1a30Sjl pcmu_p->pcmu_inos[inum]); 1445*25cf1a30Sjl rem_ivintr(mondo, NULL); 1446*25cf1a30Sjl } 1447*25cf1a30Sjl 1448*25cf1a30Sjl void 1449*25cf1a30Sjl pcmu_pbm_configure(pcmu_pbm_t *pcbm_p) 1450*25cf1a30Sjl { 1451*25cf1a30Sjl pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 1452*25cf1a30Sjl dev_info_t *dip = pcmu_p->pcmu_dip; 1453*25cf1a30Sjl 1454*25cf1a30Sjl #define pbm_err ((PCMU_PCI_AFSR_E_MASK << PCMU_PCI_AFSR_PE_SHIFT) | \ 1455*25cf1a30Sjl (PCMU_PCI_AFSR_E_MASK << PCMU_PCI_AFSR_SE_SHIFT)) 1456*25cf1a30Sjl #define csr_err (PCI_STAT_PERROR | PCI_STAT_S_PERROR | \ 1457*25cf1a30Sjl PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB | \ 1458*25cf1a30Sjl PCI_STAT_S_TARG_AB | PCI_STAT_S_PERROR) 1459*25cf1a30Sjl 1460*25cf1a30Sjl /* 1461*25cf1a30Sjl * Clear any PBM errors. 1462*25cf1a30Sjl */ 1463*25cf1a30Sjl *pcbm_p->pcbm_async_flt_status_reg = pbm_err; 1464*25cf1a30Sjl 1465*25cf1a30Sjl /* 1466*25cf1a30Sjl * Clear error bits in configuration status register. 1467*25cf1a30Sjl */ 1468*25cf1a30Sjl PCMU_DBG1(PCMU_DBG_ATTACH, dip, 1469*25cf1a30Sjl "pcmu_pbm_configure: conf status reg=%x\n", csr_err); 1470*25cf1a30Sjl 1471*25cf1a30Sjl pcbm_p->pcbm_config_header->ch_status_reg = csr_err; 1472*25cf1a30Sjl 1473*25cf1a30Sjl PCMU_DBG1(PCMU_DBG_ATTACH, dip, 1474*25cf1a30Sjl "pcmu_pbm_configure: conf status reg==%x\n", 1475*25cf1a30Sjl pcbm_p->pcbm_config_header->ch_status_reg); 1476*25cf1a30Sjl 1477*25cf1a30Sjl (void) ndi_prop_update_int(DDI_DEV_T_ANY, dip, "latency-timer", 1478*25cf1a30Sjl (int)pcbm_p->pcbm_config_header->ch_latency_timer_reg); 1479*25cf1a30Sjl #undef pbm_err 1480*25cf1a30Sjl #undef csr_err 1481*25cf1a30Sjl } 1482*25cf1a30Sjl 1483*25cf1a30Sjl uint_t 1484*25cf1a30Sjl pcmu_pbm_disable_errors(pcmu_pbm_t *pcbm_p) 1485*25cf1a30Sjl { 1486*25cf1a30Sjl pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 1487*25cf1a30Sjl pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; 1488*25cf1a30Sjl 1489*25cf1a30Sjl /* 1490*25cf1a30Sjl * Disable error and streaming byte hole interrupts via the 1491*25cf1a30Sjl * PBM control register. 1492*25cf1a30Sjl */ 1493*25cf1a30Sjl *pcbm_p->pcbm_ctrl_reg &= ~PCMU_PCI_CTRL_ERR_INT_EN; 1494*25cf1a30Sjl 1495*25cf1a30Sjl /* 1496*25cf1a30Sjl * Disable error interrupts via the interrupt mapping register. 1497*25cf1a30Sjl */ 1498*25cf1a30Sjl pcmu_ib_intr_disable(pib_p, 1499*25cf1a30Sjl pcmu_p->pcmu_inos[CBNINTR_PBM], PCMU_IB_INTR_NOWAIT); 1500*25cf1a30Sjl return (BF_NONE); 1501*25cf1a30Sjl } 1502*25cf1a30Sjl 1503*25cf1a30Sjl void 1504*25cf1a30Sjl pcmu_cb_setup(pcmu_t *pcmu_p) 1505*25cf1a30Sjl { 1506*25cf1a30Sjl uint64_t csr, csr_pa, pa; 1507*25cf1a30Sjl pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; 1508*25cf1a30Sjl 1509*25cf1a30Sjl pcb_p->pcb_ign = PCMU_ID_TO_IGN(pcmu_p->pcmu_id); 1510*25cf1a30Sjl pa = (uint64_t)hat_getpfnum(kas.a_hat, pcmu_p->pcmu_address[0]); 1511*25cf1a30Sjl pcb_p->pcb_base_pa = pa = pa >> (32 - MMU_PAGESHIFT) << 32; 1512*25cf1a30Sjl pcb_p->pcb_map_pa = pa + PCMU_IB_OBIO_INTR_MAP_REG_OFFSET; 1513*25cf1a30Sjl pcb_p->pcb_clr_pa = pa + PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET; 1514*25cf1a30Sjl pcb_p->pcb_obsta_pa = pa + PCMU_IB_OBIO_INTR_STATE_DIAG_REG; 1515*25cf1a30Sjl 1516*25cf1a30Sjl csr_pa = pa + PCMU_CB_CONTROL_STATUS_REG_OFFSET; 1517*25cf1a30Sjl csr = lddphysio(csr_pa); 1518*25cf1a30Sjl 1519*25cf1a30Sjl /* 1520*25cf1a30Sjl * Clear any pending address parity errors. 1521*25cf1a30Sjl */ 1522*25cf1a30Sjl if (csr & PCMU_CB_CONTROL_STATUS_APERR) { 1523*25cf1a30Sjl csr |= PCMU_CB_CONTROL_STATUS_APERR; 1524*25cf1a30Sjl cmn_err(CE_WARN, "clearing UPA address parity error\n"); 1525*25cf1a30Sjl } 1526*25cf1a30Sjl csr |= PCMU_CB_CONTROL_STATUS_APCKEN; 1527*25cf1a30Sjl csr &= ~PCMU_CB_CONTROL_STATUS_IAP; 1528*25cf1a30Sjl stdphysio(csr_pa, csr); 1529*25cf1a30Sjl 1530*25cf1a30Sjl u2u_ittrans_init(pcmu_p, 1531*25cf1a30Sjl (u2u_ittrans_data_t **)&pcb_p->pcb_ittrans_cookie); 1532*25cf1a30Sjl } 1533*25cf1a30Sjl 1534*25cf1a30Sjl void 1535*25cf1a30Sjl pcmu_ecc_setup(pcmu_ecc_t *pecc_p) 1536*25cf1a30Sjl { 1537*25cf1a30Sjl pecc_p->pecc_ue.pecc_errpndg_mask = 0; 1538*25cf1a30Sjl pecc_p->pecc_ue.pecc_offset_mask = PCMU_ECC_UE_AFSR_DW_OFFSET; 1539*25cf1a30Sjl pecc_p->pecc_ue.pecc_offset_shift = PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT; 1540*25cf1a30Sjl pecc_p->pecc_ue.pecc_size_log2 = 3; 1541*25cf1a30Sjl } 1542*25cf1a30Sjl 1543*25cf1a30Sjl static uintptr_t 1544*25cf1a30Sjl get_pbm_reg_base(pcmu_t *pcmu_p) 1545*25cf1a30Sjl { 1546*25cf1a30Sjl return ((uintptr_t)(pcmu_p->pcmu_address[0])); 1547*25cf1a30Sjl } 1548*25cf1a30Sjl 1549*25cf1a30Sjl void 1550*25cf1a30Sjl pcmu_pbm_setup(pcmu_pbm_t *pcbm_p) 1551*25cf1a30Sjl { 1552*25cf1a30Sjl pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 1553*25cf1a30Sjl 1554*25cf1a30Sjl /* 1555*25cf1a30Sjl * Get the base virtual address for the PBM control block. 1556*25cf1a30Sjl */ 1557*25cf1a30Sjl uintptr_t a = get_pbm_reg_base(pcmu_p); 1558*25cf1a30Sjl 1559*25cf1a30Sjl /* 1560*25cf1a30Sjl * Get the virtual address of the PCI configuration header. 1561*25cf1a30Sjl * This should be mapped little-endian. 1562*25cf1a30Sjl */ 1563*25cf1a30Sjl pcbm_p->pcbm_config_header = 1564*25cf1a30Sjl (config_header_t *)get_config_reg_base(pcmu_p); 1565*25cf1a30Sjl 1566*25cf1a30Sjl /* 1567*25cf1a30Sjl * Get the virtual addresses for control, error and diag 1568*25cf1a30Sjl * registers. 1569*25cf1a30Sjl */ 1570*25cf1a30Sjl pcbm_p->pcbm_ctrl_reg = (uint64_t *)(a + PCMU_PCI_CTRL_REG_OFFSET); 1571*25cf1a30Sjl pcbm_p->pcbm_diag_reg = (uint64_t *)(a + PCMU_PCI_DIAG_REG_OFFSET); 1572*25cf1a30Sjl pcbm_p->pcbm_async_flt_status_reg = 1573*25cf1a30Sjl (uint64_t *)(a + PCMU_PCI_ASYNC_FLT_STATUS_REG_OFFSET); 1574*25cf1a30Sjl pcbm_p->pcbm_async_flt_addr_reg = 1575*25cf1a30Sjl (uint64_t *)(a + PCMU_PCI_ASYNC_FLT_ADDR_REG_OFFSET); 1576*25cf1a30Sjl } 1577*25cf1a30Sjl 1578*25cf1a30Sjl /*ARGSUSED*/ 1579*25cf1a30Sjl void 1580*25cf1a30Sjl pcmu_pbm_teardown(pcmu_pbm_t *pcbm_p) 1581*25cf1a30Sjl { 1582*25cf1a30Sjl } 1583*25cf1a30Sjl 1584*25cf1a30Sjl int 1585*25cf1a30Sjl pcmu_get_numproxy(dev_info_t *dip) 1586*25cf1a30Sjl { 1587*25cf1a30Sjl return (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1588*25cf1a30Sjl "#upa-interrupt-proxies", 1)); 1589*25cf1a30Sjl } 1590*25cf1a30Sjl 1591*25cf1a30Sjl int 1592*25cf1a30Sjl pcmu_get_portid(dev_info_t *dip) 1593*25cf1a30Sjl { 1594*25cf1a30Sjl return (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1595*25cf1a30Sjl "portid", -1)); 1596*25cf1a30Sjl } 1597*25cf1a30Sjl 1598*25cf1a30Sjl /* 1599*25cf1a30Sjl * CMU-CH Performance Events. 1600*25cf1a30Sjl */ 1601*25cf1a30Sjl static pcmu_kev_mask_t 1602*25cf1a30Sjl pcicmu_pcmu_events[] = { 1603*25cf1a30Sjl {"pio_cycles_b", 0xf}, {"interrupts", 0x11}, 1604*25cf1a30Sjl {"upa_inter_nack", 0x12}, {"pio_reads", 0x13}, 1605*25cf1a30Sjl {"pio_writes", 0x14}, 1606*25cf1a30Sjl {"clear_pic", 0x1f} 1607*25cf1a30Sjl }; 1608*25cf1a30Sjl 1609*25cf1a30Sjl /* 1610*25cf1a30Sjl * Create the picN kstat's. 1611*25cf1a30Sjl */ 1612*25cf1a30Sjl void 1613*25cf1a30Sjl pcmu_kstat_init() 1614*25cf1a30Sjl { 1615*25cf1a30Sjl pcmu_name_kstat = (pcmu_ksinfo_t *)kmem_alloc(sizeof (pcmu_ksinfo_t), 1616*25cf1a30Sjl KM_NOSLEEP); 1617*25cf1a30Sjl 1618*25cf1a30Sjl if (pcmu_name_kstat == NULL) { 1619*25cf1a30Sjl cmn_err(CE_WARN, "pcicmu : no space for kstat\n"); 1620*25cf1a30Sjl } else { 1621*25cf1a30Sjl pcmu_name_kstat->pic_no_evs = 1622*25cf1a30Sjl sizeof (pcicmu_pcmu_events) / sizeof (pcmu_kev_mask_t); 1623*25cf1a30Sjl pcmu_name_kstat->pic_shift[0] = PCMU_SHIFT_PIC0; 1624*25cf1a30Sjl pcmu_name_kstat->pic_shift[1] = PCMU_SHIFT_PIC1; 1625*25cf1a30Sjl pcmu_create_name_kstat("pcmup", 1626*25cf1a30Sjl pcmu_name_kstat, pcicmu_pcmu_events); 1627*25cf1a30Sjl } 1628*25cf1a30Sjl } 1629*25cf1a30Sjl 1630*25cf1a30Sjl /* 1631*25cf1a30Sjl * Called from _fini() 1632*25cf1a30Sjl */ 1633*25cf1a30Sjl void 1634*25cf1a30Sjl pcmu_kstat_fini() 1635*25cf1a30Sjl { 1636*25cf1a30Sjl if (pcmu_name_kstat != NULL) { 1637*25cf1a30Sjl pcmu_delete_name_kstat(pcmu_name_kstat); 1638*25cf1a30Sjl kmem_free(pcmu_name_kstat, sizeof (pcmu_ksinfo_t)); 1639*25cf1a30Sjl pcmu_name_kstat = NULL; 1640*25cf1a30Sjl } 1641*25cf1a30Sjl } 1642*25cf1a30Sjl 1643*25cf1a30Sjl /* 1644*25cf1a30Sjl * Create the performance 'counters' kstat. 1645*25cf1a30Sjl */ 1646*25cf1a30Sjl void 1647*25cf1a30Sjl pcmu_add_upstream_kstat(pcmu_t *pcmu_p) 1648*25cf1a30Sjl { 1649*25cf1a30Sjl pcmu_cntr_pa_t *cntr_pa_p = &pcmu_p->pcmu_uks_pa; 1650*25cf1a30Sjl uint64_t regbase = va_to_pa((void *)get_reg_base(pcmu_p)); 1651*25cf1a30Sjl 1652*25cf1a30Sjl cntr_pa_p->pcr_pa = regbase + PCMU_PERF_PCR_OFFSET; 1653*25cf1a30Sjl cntr_pa_p->pic_pa = regbase + PCMU_PERF_PIC_OFFSET; 1654*25cf1a30Sjl pcmu_p->pcmu_uksp = pcmu_create_cntr_kstat(pcmu_p, "pcmup", 1655*25cf1a30Sjl NUM_OF_PICS, pcmu_cntr_kstat_pa_update, cntr_pa_p); 1656*25cf1a30Sjl } 1657*25cf1a30Sjl 1658*25cf1a30Sjl /* 1659*25cf1a30Sjl * u2u_ittrans_init() is caled from in pci.c's pcmu_cb_setup() per CMU. 1660*25cf1a30Sjl * Second argument "ittrans_cookie" is address of pcb_ittrans_cookie in 1661*25cf1a30Sjl * pcb_p member. allocated interrupt block is returned in it. 1662*25cf1a30Sjl */ 1663*25cf1a30Sjl static void 1664*25cf1a30Sjl u2u_ittrans_init(pcmu_t *pcmu_p, u2u_ittrans_data_t **ittrans_cookie) 1665*25cf1a30Sjl { 1666*25cf1a30Sjl 1667*25cf1a30Sjl u2u_ittrans_data_t *u2u_trans_p; 1668*25cf1a30Sjl ddi_device_acc_attr_t attr; 1669*25cf1a30Sjl int ret; 1670*25cf1a30Sjl int board; 1671*25cf1a30Sjl 1672*25cf1a30Sjl /* 1673*25cf1a30Sjl * Allocate the data structure to support U2U's 1674*25cf1a30Sjl * interrupt target translations. 1675*25cf1a30Sjl */ 1676*25cf1a30Sjl u2u_trans_p = (u2u_ittrans_data_t *) 1677*25cf1a30Sjl kmem_zalloc(sizeof (u2u_ittrans_data_t), KM_SLEEP); 1678*25cf1a30Sjl 1679*25cf1a30Sjl /* 1680*25cf1a30Sjl * Get other properties, "board#" 1681*25cf1a30Sjl */ 1682*25cf1a30Sjl board = ddi_getprop(DDI_DEV_T_ANY, pcmu_p->pcmu_dip, 1683*25cf1a30Sjl DDI_PROP_DONTPASS, "board#", -1); 1684*25cf1a30Sjl 1685*25cf1a30Sjl u2u_trans_p->u2u_board = board; 1686*25cf1a30Sjl 1687*25cf1a30Sjl if (board == -1) { 1688*25cf1a30Sjl /* this cannot happen on production systems */ 1689*25cf1a30Sjl cmn_err(CE_PANIC, "u2u:Invalid property;board = %d", board); 1690*25cf1a30Sjl } 1691*25cf1a30Sjl 1692*25cf1a30Sjl /* 1693*25cf1a30Sjl * Initialize interrupt target translations mutex. 1694*25cf1a30Sjl */ 1695*25cf1a30Sjl mutex_init(&(u2u_trans_p->u2u_ittrans_lock), "u2u_ittrans_lock", 1696*25cf1a30Sjl MUTEX_DEFAULT, NULL); 1697*25cf1a30Sjl 1698*25cf1a30Sjl /* 1699*25cf1a30Sjl * Get U2U's registers space by ddi_regs_map_setup(9F) 1700*25cf1a30Sjl */ 1701*25cf1a30Sjl attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 1702*25cf1a30Sjl attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 1703*25cf1a30Sjl attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 1704*25cf1a30Sjl 1705*25cf1a30Sjl ret = ddi_regs_map_setup(pcmu_p->pcmu_dip, 1706*25cf1a30Sjl REGS_INDEX_OF_U2U, (caddr_t *)(&(u2u_trans_p->u2u_regs_base)), 1707*25cf1a30Sjl 0, 0, &attr, &(u2u_trans_p->u2u_acc)); 1708*25cf1a30Sjl 1709*25cf1a30Sjl /* 1710*25cf1a30Sjl * check result of ddi_regs_map_setup(). 1711*25cf1a30Sjl */ 1712*25cf1a30Sjl if (ret != DDI_SUCCESS) { 1713*25cf1a30Sjl cmn_err(CE_PANIC, "u2u%d: registers map setup failed", board); 1714*25cf1a30Sjl } 1715*25cf1a30Sjl 1716*25cf1a30Sjl /* 1717*25cf1a30Sjl * Read Port-id(1 byte) in u2u 1718*25cf1a30Sjl */ 1719*25cf1a30Sjl u2u_trans_p->u2u_port_id = *(volatile int32_t *) 1720*25cf1a30Sjl (u2u_trans_p->u2u_regs_base + U2U_PID_REGISTER_OFFSET); 1721*25cf1a30Sjl 1722*25cf1a30Sjl if (pcmu_p->pcmu_id != u2u_trans_p->u2u_port_id) { 1723*25cf1a30Sjl cmn_err(CE_PANIC, "u2u%d: Invalid Port-ID", board); 1724*25cf1a30Sjl } 1725*25cf1a30Sjl 1726*25cf1a30Sjl *ittrans_cookie = u2u_trans_p; 1727*25cf1a30Sjl } 1728*25cf1a30Sjl 1729*25cf1a30Sjl /* 1730*25cf1a30Sjl * u2u_ittras_resume() is called from pcmu_obj_resume() at DDI_RESUME entry. 1731*25cf1a30Sjl */ 1732*25cf1a30Sjl static void 1733*25cf1a30Sjl u2u_ittrans_resume(u2u_ittrans_data_t **ittrans_cookie) 1734*25cf1a30Sjl { 1735*25cf1a30Sjl 1736*25cf1a30Sjl u2u_ittrans_data_t *u2u_trans_p; 1737*25cf1a30Sjl u2u_ittrans_id_t *ittrans_id_p; 1738*25cf1a30Sjl uintptr_t data_reg_addr; 1739*25cf1a30Sjl int ix; 1740*25cf1a30Sjl 1741*25cf1a30Sjl u2u_trans_p = *ittrans_cookie; 1742*25cf1a30Sjl 1743*25cf1a30Sjl /* 1744*25cf1a30Sjl * Set U2U Data Register 1745*25cf1a30Sjl */ 1746*25cf1a30Sjl for (ix = 0; ix < U2U_DATA_NUM; ix++) { 1747*25cf1a30Sjl ittrans_id_p = &(u2u_trans_p->u2u_ittrans_id[ix]); 1748*25cf1a30Sjl data_reg_addr = u2u_trans_p->u2u_regs_base + 1749*25cf1a30Sjl U2U_DATA_REGISTER_OFFSET + (ix * sizeof (uint64_t)); 1750*25cf1a30Sjl if (ittrans_id_p->u2u_ino_map_reg == NULL) { 1751*25cf1a30Sjl /* This index was not set */ 1752*25cf1a30Sjl continue; 1753*25cf1a30Sjl } 1754*25cf1a30Sjl *(volatile uint32_t *) (data_reg_addr) = 1755*25cf1a30Sjl (uint32_t)ittrans_id_p->u2u_tgt_cpu_id; 1756*25cf1a30Sjl 1757*25cf1a30Sjl } 1758*25cf1a30Sjl } 1759*25cf1a30Sjl 1760*25cf1a30Sjl /* 1761*25cf1a30Sjl * u2u_ittras_uninit() is called from ib_destroy() at detach, 1762*25cf1a30Sjl * or occuring error in attach. 1763*25cf1a30Sjl */ 1764*25cf1a30Sjl static void 1765*25cf1a30Sjl u2u_ittrans_uninit(u2u_ittrans_data_t *ittrans_cookie) 1766*25cf1a30Sjl { 1767*25cf1a30Sjl 1768*25cf1a30Sjl if (ittrans_cookie == NULL) { 1769*25cf1a30Sjl return; /* not support */ 1770*25cf1a30Sjl } 1771*25cf1a30Sjl 1772*25cf1a30Sjl if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) { 1773*25cf1a30Sjl return; /* illeagal case */ 1774*25cf1a30Sjl } 1775*25cf1a30Sjl 1776*25cf1a30Sjl ddi_regs_map_free(&(ittrans_cookie->u2u_acc)); 1777*25cf1a30Sjl mutex_destroy(&(ittrans_cookie->u2u_ittrans_lock)); 1778*25cf1a30Sjl kmem_free((void *)ittrans_cookie, sizeof (u2u_ittrans_data_t)); 1779*25cf1a30Sjl } 1780*25cf1a30Sjl 1781*25cf1a30Sjl /* 1782*25cf1a30Sjl * This routine,u2u_translate_tgtid(, , cpu_id, pino_map_reg), 1783*25cf1a30Sjl * searches index having same value of pino_map_reg, or empty. 1784*25cf1a30Sjl * Then, stores cpu_id in a U2U Data Register as this index, 1785*25cf1a30Sjl * and return this index. 1786*25cf1a30Sjl */ 1787*25cf1a30Sjl int 1788*25cf1a30Sjl u2u_translate_tgtid(pcmu_t *pcmu_p, uint_t cpu_id, 1789*25cf1a30Sjl volatile uint64_t *pino_map_reg) 1790*25cf1a30Sjl { 1791*25cf1a30Sjl 1792*25cf1a30Sjl int index = -1; 1793*25cf1a30Sjl int ix; 1794*25cf1a30Sjl int err_level; /* severity level for cmn_err */ 1795*25cf1a30Sjl u2u_ittrans_id_t *ittrans_id_p; 1796*25cf1a30Sjl uintptr_t data_reg_addr; 1797*25cf1a30Sjl u2u_ittrans_data_t *ittrans_cookie; 1798*25cf1a30Sjl 1799*25cf1a30Sjl ittrans_cookie = 1800*25cf1a30Sjl (u2u_ittrans_data_t *)(pcmu_p->pcmu_cb_p->pcb_ittrans_cookie); 1801*25cf1a30Sjl 1802*25cf1a30Sjl if (ittrans_cookie == NULL) { 1803*25cf1a30Sjl return (cpu_id); 1804*25cf1a30Sjl } 1805*25cf1a30Sjl 1806*25cf1a30Sjl if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) { 1807*25cf1a30Sjl return (-1); /* illeagal case */ 1808*25cf1a30Sjl } 1809*25cf1a30Sjl 1810*25cf1a30Sjl mutex_enter(&(ittrans_cookie->u2u_ittrans_lock)); 1811*25cf1a30Sjl 1812*25cf1a30Sjl /* 1813*25cf1a30Sjl * Decide index No. of U2U Data registers in either 1814*25cf1a30Sjl * already used by same pino_map_reg, or empty. 1815*25cf1a30Sjl */ 1816*25cf1a30Sjl for (ix = 0; ix < U2U_DATA_NUM; ix++) { 1817*25cf1a30Sjl ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[ix]); 1818*25cf1a30Sjl if (ittrans_id_p->u2u_ino_map_reg == pino_map_reg) { 1819*25cf1a30Sjl /* already used this pino_map_reg */ 1820*25cf1a30Sjl index = ix; 1821*25cf1a30Sjl break; 1822*25cf1a30Sjl } 1823*25cf1a30Sjl if (index == -1 && 1824*25cf1a30Sjl ittrans_id_p->u2u_ino_map_reg == NULL) { 1825*25cf1a30Sjl index = ix; 1826*25cf1a30Sjl } 1827*25cf1a30Sjl } 1828*25cf1a30Sjl 1829*25cf1a30Sjl if (index == -1) { 1830*25cf1a30Sjl if (panicstr) { 1831*25cf1a30Sjl err_level = CE_WARN; 1832*25cf1a30Sjl } else { 1833*25cf1a30Sjl err_level = CE_PANIC; 1834*25cf1a30Sjl } 1835*25cf1a30Sjl cmn_err(err_level, "u2u%d:No more U2U-Data regs!!", 1836*25cf1a30Sjl ittrans_cookie->u2u_board); 1837*25cf1a30Sjl return (cpu_id); 1838*25cf1a30Sjl } 1839*25cf1a30Sjl 1840*25cf1a30Sjl /* 1841*25cf1a30Sjl * For U2U 1842*25cf1a30Sjl * set cpu_id into u2u_data_reg by index. 1843*25cf1a30Sjl * ((uint64_t)(u2u_regs_base 1844*25cf1a30Sjl * + U2U_DATA_REGISTER_OFFSET))[index] = cpu_id; 1845*25cf1a30Sjl */ 1846*25cf1a30Sjl 1847*25cf1a30Sjl data_reg_addr = ittrans_cookie->u2u_regs_base 1848*25cf1a30Sjl + U2U_DATA_REGISTER_OFFSET 1849*25cf1a30Sjl + (index * sizeof (uint64_t)); 1850*25cf1a30Sjl 1851*25cf1a30Sjl /* 1852*25cf1a30Sjl * Set cpu_id into U2U Data register[index] 1853*25cf1a30Sjl */ 1854*25cf1a30Sjl *(volatile uint32_t *) (data_reg_addr) = (uint32_t)cpu_id; 1855*25cf1a30Sjl 1856*25cf1a30Sjl /* 1857*25cf1a30Sjl * Setup for software, excepting at panicing. 1858*25cf1a30Sjl * and rebooting, etc...? 1859*25cf1a30Sjl */ 1860*25cf1a30Sjl if (!panicstr) { 1861*25cf1a30Sjl ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[index]); 1862*25cf1a30Sjl ittrans_id_p->u2u_tgt_cpu_id = cpu_id; 1863*25cf1a30Sjl ittrans_id_p->u2u_ino_map_reg = pino_map_reg; 1864*25cf1a30Sjl } 1865*25cf1a30Sjl 1866*25cf1a30Sjl mutex_exit(&(ittrans_cookie->u2u_ittrans_lock)); 1867*25cf1a30Sjl 1868*25cf1a30Sjl return (index); 1869*25cf1a30Sjl } 1870*25cf1a30Sjl 1871*25cf1a30Sjl /* 1872*25cf1a30Sjl * u2u_ittrans_cleanup() is called from common_pcmu_ib_intr_disable() 1873*25cf1a30Sjl * after called intr_rem_cpu(mondo). 1874*25cf1a30Sjl */ 1875*25cf1a30Sjl void 1876*25cf1a30Sjl u2u_ittrans_cleanup(u2u_ittrans_data_t *ittrans_cookie, 1877*25cf1a30Sjl volatile uint64_t *pino_map_reg) 1878*25cf1a30Sjl { 1879*25cf1a30Sjl 1880*25cf1a30Sjl int ix; 1881*25cf1a30Sjl u2u_ittrans_id_t *ittrans_id_p; 1882*25cf1a30Sjl 1883*25cf1a30Sjl if (ittrans_cookie == NULL) { 1884*25cf1a30Sjl return; 1885*25cf1a30Sjl } 1886*25cf1a30Sjl 1887*25cf1a30Sjl if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) { 1888*25cf1a30Sjl return; /* illeagal case */ 1889*25cf1a30Sjl } 1890*25cf1a30Sjl 1891*25cf1a30Sjl mutex_enter(&(ittrans_cookie->u2u_ittrans_lock)); 1892*25cf1a30Sjl 1893*25cf1a30Sjl for (ix = 0; ix < U2U_DATA_NUM; ix++) { 1894*25cf1a30Sjl ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[ix]); 1895*25cf1a30Sjl if (ittrans_id_p->u2u_ino_map_reg == pino_map_reg) { 1896*25cf1a30Sjl ittrans_id_p->u2u_ino_map_reg = NULL; 1897*25cf1a30Sjl break; 1898*25cf1a30Sjl } 1899*25cf1a30Sjl } 1900*25cf1a30Sjl 1901*25cf1a30Sjl mutex_exit(&(ittrans_cookie->u2u_ittrans_lock)); 1902*25cf1a30Sjl } 1903*25cf1a30Sjl 1904*25cf1a30Sjl /* 1905*25cf1a30Sjl * pcmu_ecc_classify, called by ecc_handler to classify ecc errors 1906*25cf1a30Sjl * and determine if we should panic or not. 1907*25cf1a30Sjl */ 1908*25cf1a30Sjl void 1909*25cf1a30Sjl pcmu_ecc_classify(uint64_t err, pcmu_ecc_errstate_t *ecc_err_p) 1910*25cf1a30Sjl { 1911*25cf1a30Sjl struct async_flt *ecc = &ecc_err_p->ecc_aflt; 1912*25cf1a30Sjl /* LINTED */ 1913*25cf1a30Sjl pcmu_t *pcmu_p = ecc_err_p->ecc_ii_p.pecc_p->pecc_pcmu_p; 1914*25cf1a30Sjl 1915*25cf1a30Sjl ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 1916*25cf1a30Sjl 1917*25cf1a30Sjl ecc_err_p->ecc_bridge_type = PCI_OPLCMU; /* RAGS */ 1918*25cf1a30Sjl /* 1919*25cf1a30Sjl * Get the parent bus id that caused the error. 1920*25cf1a30Sjl */ 1921*25cf1a30Sjl ecc_err_p->ecc_dev_id = (ecc_err_p->ecc_afsr & PCMU_ECC_UE_AFSR_ID) 1922*25cf1a30Sjl >> PCMU_ECC_UE_AFSR_ID_SHIFT; 1923*25cf1a30Sjl /* 1924*25cf1a30Sjl * Determine the doubleword offset of the error. 1925*25cf1a30Sjl */ 1926*25cf1a30Sjl ecc_err_p->ecc_dw_offset = (ecc_err_p->ecc_afsr & 1927*25cf1a30Sjl PCMU_ECC_UE_AFSR_DW_OFFSET) >> PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT; 1928*25cf1a30Sjl /* 1929*25cf1a30Sjl * Determine the primary error type. 1930*25cf1a30Sjl */ 1931*25cf1a30Sjl switch (err) { 1932*25cf1a30Sjl case PCMU_ECC_UE_AFSR_E_PIO: 1933*25cf1a30Sjl if (ecc_err_p->pecc_pri) { 1934*25cf1a30Sjl ecc->flt_erpt_class = PCI_ECC_PIO_UE; 1935*25cf1a30Sjl } else { 1936*25cf1a30Sjl ecc->flt_erpt_class = PCI_ECC_SEC_PIO_UE; 1937*25cf1a30Sjl } 1938*25cf1a30Sjl /* For CMU-CH, a UE is always fatal. */ 1939*25cf1a30Sjl ecc->flt_panic = 1; 1940*25cf1a30Sjl break; 1941*25cf1a30Sjl 1942*25cf1a30Sjl default: 1943*25cf1a30Sjl return; 1944*25cf1a30Sjl } 1945*25cf1a30Sjl } 1946*25cf1a30Sjl 1947*25cf1a30Sjl /* 1948*25cf1a30Sjl * pcmu_pbm_classify, called by pcmu_pbm_afsr_report to classify piow afsr. 1949*25cf1a30Sjl */ 1950*25cf1a30Sjl int 1951*25cf1a30Sjl pcmu_pbm_classify(pcmu_pbm_errstate_t *pbm_err_p) 1952*25cf1a30Sjl { 1953*25cf1a30Sjl uint32_t e; 1954*25cf1a30Sjl int nerr = 0; 1955*25cf1a30Sjl char **tmp_class; 1956*25cf1a30Sjl 1957*25cf1a30Sjl if (pbm_err_p->pcbm_pri) { 1958*25cf1a30Sjl tmp_class = &pbm_err_p->pcbm_pci.pcmu_err_class; 1959*25cf1a30Sjl e = PBM_AFSR_TO_PRIERR(pbm_err_p->pbm_afsr); 1960*25cf1a30Sjl pbm_err_p->pbm_log = FM_LOG_PCI; 1961*25cf1a30Sjl } else { 1962*25cf1a30Sjl tmp_class = &pbm_err_p->pbm_err_class; 1963*25cf1a30Sjl e = PBM_AFSR_TO_SECERR(pbm_err_p->pbm_afsr); 1964*25cf1a30Sjl pbm_err_p->pbm_log = FM_LOG_PBM; 1965*25cf1a30Sjl } 1966*25cf1a30Sjl 1967*25cf1a30Sjl if (e & PCMU_PCI_AFSR_E_MA) { 1968*25cf1a30Sjl *tmp_class = pbm_err_p->pcbm_pri ? PCI_MA : PCI_SEC_MA; 1969*25cf1a30Sjl nerr++; 1970*25cf1a30Sjl } 1971*25cf1a30Sjl return (nerr); 1972*25cf1a30Sjl } 1973*25cf1a30Sjl 1974*25cf1a30Sjl /* 1975*25cf1a30Sjl * Function used to clear PBM/PCI/IOMMU error state after error handling 1976*25cf1a30Sjl * is complete. Only clearing error bits which have been logged. Called by 1977*25cf1a30Sjl * pcmu_pbm_err_handler and pcmu_bus_exit. 1978*25cf1a30Sjl */ 1979*25cf1a30Sjl static void 1980*25cf1a30Sjl pcmu_clear_error(pcmu_t *pcmu_p, pcmu_pbm_errstate_t *pbm_err_p) 1981*25cf1a30Sjl { 1982*25cf1a30Sjl pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 1983*25cf1a30Sjl 1984*25cf1a30Sjl ASSERT(MUTEX_HELD(&pcbm_p->pcbm_pcmu_p->pcmu_err_mutex)); 1985*25cf1a30Sjl 1986*25cf1a30Sjl *pcbm_p->pcbm_ctrl_reg = pbm_err_p->pbm_ctl_stat; 1987*25cf1a30Sjl *pcbm_p->pcbm_async_flt_status_reg = pbm_err_p->pbm_afsr; 1988*25cf1a30Sjl pcbm_p->pcbm_config_header->ch_status_reg = 1989*25cf1a30Sjl pbm_err_p->pcbm_pci.pcmu_cfg_stat; 1990*25cf1a30Sjl } 1991*25cf1a30Sjl 1992*25cf1a30Sjl /*ARGSUSED*/ 1993*25cf1a30Sjl int 1994*25cf1a30Sjl pcmu_pbm_err_handler(dev_info_t *dip, ddi_fm_error_t *derr, 1995*25cf1a30Sjl const void *impl_data, int caller) 1996*25cf1a30Sjl { 1997*25cf1a30Sjl int fatal = 0; 1998*25cf1a30Sjl int nonfatal = 0; 1999*25cf1a30Sjl int unknown = 0; 2000*25cf1a30Sjl uint32_t prierr, secerr; 2001*25cf1a30Sjl pcmu_pbm_errstate_t pbm_err; 2002*25cf1a30Sjl pcmu_t *pcmu_p = (pcmu_t *)impl_data; 2003*25cf1a30Sjl int ret = 0; 2004*25cf1a30Sjl 2005*25cf1a30Sjl ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 2006*25cf1a30Sjl pcmu_pbm_errstate_get(pcmu_p, &pbm_err); 2007*25cf1a30Sjl 2008*25cf1a30Sjl derr->fme_ena = derr->fme_ena ? derr->fme_ena : 2009*25cf1a30Sjl fm_ena_generate(0, FM_ENA_FMT1); 2010*25cf1a30Sjl 2011*25cf1a30Sjl prierr = PBM_AFSR_TO_PRIERR(pbm_err.pbm_afsr); 2012*25cf1a30Sjl secerr = PBM_AFSR_TO_SECERR(pbm_err.pbm_afsr); 2013*25cf1a30Sjl 2014*25cf1a30Sjl if (derr->fme_flag == DDI_FM_ERR_PEEK) { 2015*25cf1a30Sjl /* 2016*25cf1a30Sjl * For ddi_peek treat all events as nonfatal. We only 2017*25cf1a30Sjl * really call this function so that pcmu_clear_error() 2018*25cf1a30Sjl * and ndi_fm_handler_dispatch() will get called. 2019*25cf1a30Sjl */ 2020*25cf1a30Sjl nonfatal++; 2021*25cf1a30Sjl goto done; 2022*25cf1a30Sjl } else if (derr->fme_flag == DDI_FM_ERR_POKE) { 2023*25cf1a30Sjl /* 2024*25cf1a30Sjl * For ddi_poke we can treat as nonfatal if the 2025*25cf1a30Sjl * following conditions are met : 2026*25cf1a30Sjl * 1. Make sure only primary error is MA/TA 2027*25cf1a30Sjl * 2. Make sure no secondary error 2028*25cf1a30Sjl * 3. check pci config header stat reg to see MA/TA is 2029*25cf1a30Sjl * logged. We cannot verify only MA/TA is recorded 2030*25cf1a30Sjl * since it gets much more complicated when a 2031*25cf1a30Sjl * PCI-to-PCI bridge is present. 2032*25cf1a30Sjl */ 2033*25cf1a30Sjl if ((prierr == PCMU_PCI_AFSR_E_MA) && !secerr && 2034*25cf1a30Sjl (pbm_err.pcbm_pci.pcmu_cfg_stat & PCI_STAT_R_MAST_AB)) { 2035*25cf1a30Sjl nonfatal++; 2036*25cf1a30Sjl goto done; 2037*25cf1a30Sjl } 2038*25cf1a30Sjl } 2039*25cf1a30Sjl 2040*25cf1a30Sjl if (prierr || secerr) { 2041*25cf1a30Sjl ret = pcmu_pbm_afsr_report(dip, derr->fme_ena, &pbm_err); 2042*25cf1a30Sjl if (ret == DDI_FM_FATAL) { 2043*25cf1a30Sjl fatal++; 2044*25cf1a30Sjl } else { 2045*25cf1a30Sjl nonfatal++; 2046*25cf1a30Sjl } 2047*25cf1a30Sjl } 2048*25cf1a30Sjl 2049*25cf1a30Sjl ret = pcmu_cfg_report(dip, derr, &pbm_err.pcbm_pci, caller, prierr); 2050*25cf1a30Sjl if (ret == DDI_FM_FATAL) { 2051*25cf1a30Sjl fatal++; 2052*25cf1a30Sjl } else if (ret == DDI_FM_NONFATAL) { 2053*25cf1a30Sjl nonfatal++; 2054*25cf1a30Sjl } 2055*25cf1a30Sjl 2056*25cf1a30Sjl done: 2057*25cf1a30Sjl if (ret == DDI_FM_FATAL) { 2058*25cf1a30Sjl fatal++; 2059*25cf1a30Sjl } else if (ret == DDI_FM_NONFATAL) { 2060*25cf1a30Sjl nonfatal++; 2061*25cf1a30Sjl } else if (ret == DDI_FM_UNKNOWN) { 2062*25cf1a30Sjl unknown++; 2063*25cf1a30Sjl } 2064*25cf1a30Sjl 2065*25cf1a30Sjl /* Cleanup and reset error bits */ 2066*25cf1a30Sjl pcmu_clear_error(pcmu_p, &pbm_err); 2067*25cf1a30Sjl 2068*25cf1a30Sjl return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 2069*25cf1a30Sjl (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 2070*25cf1a30Sjl } 2071*25cf1a30Sjl 2072*25cf1a30Sjl int 2073*25cf1a30Sjl pcmu_check_error(pcmu_t *pcmu_p) 2074*25cf1a30Sjl { 2075*25cf1a30Sjl pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 2076*25cf1a30Sjl uint16_t pcmu_cfg_stat; 2077*25cf1a30Sjl uint64_t pbm_afsr; 2078*25cf1a30Sjl 2079*25cf1a30Sjl ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 2080*25cf1a30Sjl 2081*25cf1a30Sjl pcmu_cfg_stat = pcbm_p->pcbm_config_header->ch_status_reg; 2082*25cf1a30Sjl pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; 2083*25cf1a30Sjl 2084*25cf1a30Sjl if ((pcmu_cfg_stat & (PCI_STAT_S_PERROR | PCI_STAT_S_TARG_AB | 2085*25cf1a30Sjl PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | 2086*25cf1a30Sjl PCI_STAT_S_SYSERR | PCI_STAT_PERROR)) || 2087*25cf1a30Sjl (PBM_AFSR_TO_PRIERR(pbm_afsr))) { 2088*25cf1a30Sjl return (1); 2089*25cf1a30Sjl } 2090*25cf1a30Sjl return (0); 2091*25cf1a30Sjl 2092*25cf1a30Sjl } 2093*25cf1a30Sjl 2094*25cf1a30Sjl /* 2095*25cf1a30Sjl * Function used to gather PBM/PCI error state for the 2096*25cf1a30Sjl * pcmu_pbm_err_handler. This function must be called while pcmu_err_mutex 2097*25cf1a30Sjl * is held. 2098*25cf1a30Sjl */ 2099*25cf1a30Sjl static void 2100*25cf1a30Sjl pcmu_pbm_errstate_get(pcmu_t *pcmu_p, pcmu_pbm_errstate_t *pbm_err_p) 2101*25cf1a30Sjl { 2102*25cf1a30Sjl pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 2103*25cf1a30Sjl 2104*25cf1a30Sjl ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 2105*25cf1a30Sjl bzero(pbm_err_p, sizeof (pcmu_pbm_errstate_t)); 2106*25cf1a30Sjl 2107*25cf1a30Sjl /* 2108*25cf1a30Sjl * Capture all pbm error state for later logging 2109*25cf1a30Sjl */ 2110*25cf1a30Sjl pbm_err_p->pbm_bridge_type = PCI_OPLCMU; /* RAGS */ 2111*25cf1a30Sjl pbm_err_p->pcbm_pci.pcmu_cfg_stat = 2112*25cf1a30Sjl pcbm_p->pcbm_config_header->ch_status_reg; 2113*25cf1a30Sjl pbm_err_p->pbm_ctl_stat = *pcbm_p->pcbm_ctrl_reg; 2114*25cf1a30Sjl pbm_err_p->pcbm_pci.pcmu_cfg_comm = 2115*25cf1a30Sjl pcbm_p->pcbm_config_header->ch_command_reg; 2116*25cf1a30Sjl pbm_err_p->pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; 2117*25cf1a30Sjl pbm_err_p->pbm_afar = *pcbm_p->pcbm_async_flt_addr_reg; 2118*25cf1a30Sjl pbm_err_p->pcbm_pci.pcmu_pa = *pcbm_p->pcbm_async_flt_addr_reg; 2119*25cf1a30Sjl } 2120*25cf1a30Sjl 2121*25cf1a30Sjl static void 2122*25cf1a30Sjl pcmu_pbm_clear_error(pcmu_pbm_t *pcbm_p) 2123*25cf1a30Sjl { 2124*25cf1a30Sjl uint64_t pbm_afsr; 2125*25cf1a30Sjl 2126*25cf1a30Sjl /* 2127*25cf1a30Sjl * for poke() support - called from POKE_FLUSH. Spin waiting 2128*25cf1a30Sjl * for MA, TA or SERR to be cleared by a pcmu_pbm_error_intr(). 2129*25cf1a30Sjl * We have to wait for SERR too in case the device is beyond 2130*25cf1a30Sjl * a pci-pci bridge. 2131*25cf1a30Sjl */ 2132*25cf1a30Sjl pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; 2133*25cf1a30Sjl while (((pbm_afsr >> PCMU_PCI_AFSR_PE_SHIFT) & 2134*25cf1a30Sjl (PCMU_PCI_AFSR_E_MA | PCMU_PCI_AFSR_E_TA))) { 2135*25cf1a30Sjl pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; 2136*25cf1a30Sjl } 2137*25cf1a30Sjl } 2138*25cf1a30Sjl 2139*25cf1a30Sjl void 2140*25cf1a30Sjl pcmu_err_create(pcmu_t *pcmu_p) 2141*25cf1a30Sjl { 2142*25cf1a30Sjl /* 2143*25cf1a30Sjl * PCI detected ECC errorq, to schedule async handling 2144*25cf1a30Sjl * of ECC errors and logging. 2145*25cf1a30Sjl * The errorq is created here but destroyed when _fini is called 2146*25cf1a30Sjl * for the pci module. 2147*25cf1a30Sjl */ 2148*25cf1a30Sjl if (pcmu_ecc_queue == NULL) { 2149*25cf1a30Sjl pcmu_ecc_queue = errorq_create("pcmu_ecc_queue", 2150*25cf1a30Sjl (errorq_func_t)pcmu_ecc_err_drain, 2151*25cf1a30Sjl (void *)NULL, 2152*25cf1a30Sjl ECC_MAX_ERRS, sizeof (pcmu_ecc_errstate_t), 2153*25cf1a30Sjl PIL_2, ERRORQ_VITAL); 2154*25cf1a30Sjl if (pcmu_ecc_queue == NULL) 2155*25cf1a30Sjl panic("failed to create required system error queue"); 2156*25cf1a30Sjl } 2157*25cf1a30Sjl 2158*25cf1a30Sjl /* 2159*25cf1a30Sjl * Initialize error handling mutex. 2160*25cf1a30Sjl */ 2161*25cf1a30Sjl mutex_init(&pcmu_p->pcmu_err_mutex, NULL, MUTEX_DRIVER, 2162*25cf1a30Sjl (void *)pcmu_p->pcmu_fm_ibc); 2163*25cf1a30Sjl } 2164*25cf1a30Sjl 2165*25cf1a30Sjl void 2166*25cf1a30Sjl pcmu_err_destroy(pcmu_t *pcmu_p) 2167*25cf1a30Sjl { 2168*25cf1a30Sjl mutex_destroy(&pcmu_p->pcmu_err_mutex); 2169*25cf1a30Sjl } 2170*25cf1a30Sjl 2171*25cf1a30Sjl /* 2172*25cf1a30Sjl * Function used to post PCI block module specific ereports. 2173*25cf1a30Sjl */ 2174*25cf1a30Sjl void 2175*25cf1a30Sjl pcmu_pbm_ereport_post(dev_info_t *dip, uint64_t ena, 2176*25cf1a30Sjl pcmu_pbm_errstate_t *pbm_err) 2177*25cf1a30Sjl { 2178*25cf1a30Sjl char *aux_msg; 2179*25cf1a30Sjl uint32_t prierr, secerr; 2180*25cf1a30Sjl pcmu_t *pcmu_p; 2181*25cf1a30Sjl int instance = ddi_get_instance(dip); 2182*25cf1a30Sjl 2183*25cf1a30Sjl ena = ena ? ena : fm_ena_generate(0, FM_ENA_FMT1); 2184*25cf1a30Sjl 2185*25cf1a30Sjl pcmu_p = get_pcmu_soft_state(instance); 2186*25cf1a30Sjl prierr = PBM_AFSR_TO_PRIERR(pbm_err->pbm_afsr); 2187*25cf1a30Sjl secerr = PBM_AFSR_TO_SECERR(pbm_err->pbm_afsr); 2188*25cf1a30Sjl if (prierr) 2189*25cf1a30Sjl aux_msg = "PCI primary error: Master Abort"; 2190*25cf1a30Sjl else if (secerr) 2191*25cf1a30Sjl aux_msg = "PCI secondary error: Master Abort"; 2192*25cf1a30Sjl else 2193*25cf1a30Sjl aux_msg = ""; 2194*25cf1a30Sjl cmn_err(CE_WARN, "%s %s: %s %s=0x%lx, %s=0x%lx, %s=0x%lx %s=0x%x", 2195*25cf1a30Sjl (pcmu_p->pcmu_pcbm_p)->pcbm_nameinst_str, 2196*25cf1a30Sjl (pcmu_p->pcmu_pcbm_p)->pcbm_nameaddr_str, 2197*25cf1a30Sjl aux_msg, 2198*25cf1a30Sjl PCI_PBM_AFAR, pbm_err->pbm_afar, 2199*25cf1a30Sjl PCI_PBM_AFSR, pbm_err->pbm_afsr, 2200*25cf1a30Sjl PCI_PBM_CSR, pbm_err->pbm_ctl_stat, 2201*25cf1a30Sjl "portid", pcmu_p->pcmu_id); 2202*25cf1a30Sjl } 2203