125cf1a30Sjl139090 /* 225cf1a30Sjl139090 * CDDL HEADER START 325cf1a30Sjl139090 * 425cf1a30Sjl139090 * The contents of this file are subject to the terms of the 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * You may not use this file except in compliance with the License. 725cf1a30Sjl139090 * 825cf1a30Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 925cf1a30Sjl139090 * or http://www.opensolaris.org/os/licensing. 1025cf1a30Sjl139090 * See the License for the specific language governing permissions 1125cf1a30Sjl139090 * and limitations under the License. 1225cf1a30Sjl139090 * 1325cf1a30Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each 1425cf1a30Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1525cf1a30Sjl139090 * If applicable, add the following below this CDDL HEADER, with the 1625cf1a30Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying 1725cf1a30Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner] 1825cf1a30Sjl139090 * 1925cf1a30Sjl139090 * CDDL HEADER END 2025cf1a30Sjl139090 */ 2125cf1a30Sjl139090 /* 22*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2325cf1a30Sjl139090 * Use is subject to license terms. 2425cf1a30Sjl139090 */ 2525cf1a30Sjl139090 2625cf1a30Sjl139090 2725cf1a30Sjl139090 /* 2825cf1a30Sjl139090 * OPL CMU-CH PCI nexus driver. 2925cf1a30Sjl139090 * 3025cf1a30Sjl139090 */ 3125cf1a30Sjl139090 3225cf1a30Sjl139090 #include <sys/types.h> 3325cf1a30Sjl139090 #include <sys/sysmacros.h> 3425cf1a30Sjl139090 #include <sys/systm.h> 3525cf1a30Sjl139090 #include <sys/intreg.h> 3625cf1a30Sjl139090 #include <sys/intr.h> 3725cf1a30Sjl139090 #include <sys/machsystm.h> 3825cf1a30Sjl139090 #include <sys/conf.h> 3925cf1a30Sjl139090 #include <sys/stat.h> 4025cf1a30Sjl139090 #include <sys/kmem.h> 4125cf1a30Sjl139090 #include <sys/async.h> 4225cf1a30Sjl139090 #include <sys/ivintr.h> 4325cf1a30Sjl139090 #include <sys/sunddi.h> 4425cf1a30Sjl139090 #include <sys/sunndi.h> 4525cf1a30Sjl139090 #include <sys/ndifm.h> 4625cf1a30Sjl139090 #include <sys/ontrap.h> 4725cf1a30Sjl139090 #include <sys/ddi_impldefs.h> 4825cf1a30Sjl139090 #include <sys/ddi_subrdefs.h> 4925cf1a30Sjl139090 #include <sys/epm.h> 5025cf1a30Sjl139090 #include <sys/spl.h> 5125cf1a30Sjl139090 #include <sys/fm/util.h> 5225cf1a30Sjl139090 #include <sys/fm/util.h> 5325cf1a30Sjl139090 #include <sys/fm/protocol.h> 5425cf1a30Sjl139090 #include <sys/fm/io/pci.h> 5525cf1a30Sjl139090 #include <sys/fm/io/sun4upci.h> 5625cf1a30Sjl139090 #include <sys/pcicmu/pcicmu.h> 5725cf1a30Sjl139090 5825cf1a30Sjl139090 #include <sys/cmn_err.h> 5925cf1a30Sjl139090 #include <sys/time.h> 6025cf1a30Sjl139090 #include <sys/pci.h> 6125cf1a30Sjl139090 #include <sys/modctl.h> 6225cf1a30Sjl139090 #include <sys/open.h> 6325cf1a30Sjl139090 #include <sys/errno.h> 6425cf1a30Sjl139090 #include <sys/file.h> 6525cf1a30Sjl139090 6625cf1a30Sjl139090 6725cf1a30Sjl139090 uint32_t pcmu_spurintr_duration = 60000000; /* One minute */ 6825cf1a30Sjl139090 6925cf1a30Sjl139090 /* 7025cf1a30Sjl139090 * The variable controls the default setting of the command register 7125cf1a30Sjl139090 * for pci devices. See pcmu_init_child() for details. 7225cf1a30Sjl139090 * 7325cf1a30Sjl139090 * This flags also controls the setting of bits in the bridge control 7425cf1a30Sjl139090 * register pci to pci bridges. See pcmu_init_child() for details. 7525cf1a30Sjl139090 */ 7625cf1a30Sjl139090 ushort_t pcmu_command_default = PCI_COMM_SERR_ENABLE | 7725cf1a30Sjl139090 PCI_COMM_WAIT_CYC_ENAB | 7825cf1a30Sjl139090 PCI_COMM_PARITY_DETECT | 7925cf1a30Sjl139090 PCI_COMM_ME | 8025cf1a30Sjl139090 PCI_COMM_MAE | 8125cf1a30Sjl139090 PCI_COMM_IO; 8225cf1a30Sjl139090 /* 8325cf1a30Sjl139090 * The following driver parameters are defined as variables to allow 8425cf1a30Sjl139090 * patching for debugging and tuning. Flags that can be set on a per 8525cf1a30Sjl139090 * PBM basis are bit fields where the PBM device instance number maps 8625cf1a30Sjl139090 * to the bit position. 8725cf1a30Sjl139090 */ 8825cf1a30Sjl139090 #ifdef DEBUG 8925cf1a30Sjl139090 uint64_t pcmu_debug_flags = 0; 9025cf1a30Sjl139090 #endif 9125cf1a30Sjl139090 uint_t ecc_error_intr_enable = 1; 9225cf1a30Sjl139090 9325cf1a30Sjl139090 uint_t pcmu_ecc_afsr_retries = 100; /* XXX - what's a good value? */ 9425cf1a30Sjl139090 9525cf1a30Sjl139090 uint_t pcmu_intr_retry_intv = 5; /* for interrupt retry reg */ 9625cf1a30Sjl139090 uint_t pcmu_panic_on_fatal_errors = 1; /* should be 1 at beta */ 9725cf1a30Sjl139090 9825cf1a30Sjl139090 hrtime_t pcmu_intrpend_timeout = 5ll * NANOSEC; /* 5 seconds in nanoseconds */ 9925cf1a30Sjl139090 10025cf1a30Sjl139090 uint64_t pcmu_errtrig_pa = 0x0; 10125cf1a30Sjl139090 10225cf1a30Sjl139090 10325cf1a30Sjl139090 /* 10425cf1a30Sjl139090 * The following value is the number of consecutive unclaimed interrupts that 10525cf1a30Sjl139090 * will be tolerated for a particular ino_p before the interrupt is deemed to 10625cf1a30Sjl139090 * be jabbering and is blocked. 10725cf1a30Sjl139090 */ 10825cf1a30Sjl139090 uint_t pcmu_unclaimed_intr_max = 20; 10925cf1a30Sjl139090 11025cf1a30Sjl139090 /* 11125cf1a30Sjl139090 * function prototypes for dev ops routines: 11225cf1a30Sjl139090 */ 11325cf1a30Sjl139090 static int pcmu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 11425cf1a30Sjl139090 static int pcmu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 11525cf1a30Sjl139090 static int pcmu_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 11625cf1a30Sjl139090 void *arg, void **result); 11725cf1a30Sjl139090 static int pcmu_open(dev_t *devp, int flags, int otyp, cred_t *credp); 11825cf1a30Sjl139090 static int pcmu_close(dev_t dev, int flags, int otyp, cred_t *credp); 11925cf1a30Sjl139090 static int pcmu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 12025cf1a30Sjl139090 cred_t *credp, int *rvalp); 12125cf1a30Sjl139090 static int pcmu_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 12225cf1a30Sjl139090 int flags, char *name, caddr_t valuep, int *lengthp); 12325cf1a30Sjl139090 static int pcmu_ctlops_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args); 12425cf1a30Sjl139090 static int pcmu_ctlops_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args, 12525cf1a30Sjl139090 void *result); 12625cf1a30Sjl139090 12725cf1a30Sjl139090 static int map_pcmu_registers(pcmu_t *, dev_info_t *); 12825cf1a30Sjl139090 static void unmap_pcmu_registers(pcmu_t *); 12925cf1a30Sjl139090 static void pcmu_pbm_clear_error(pcmu_pbm_t *); 13025cf1a30Sjl139090 13125cf1a30Sjl139090 static int pcmu_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, 13225cf1a30Sjl139090 void *, void *); 13325cf1a30Sjl139090 static int pcmu_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, 13425cf1a30Sjl139090 off_t, off_t, caddr_t *); 13525cf1a30Sjl139090 static int pcmu_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t, 13625cf1a30Sjl139090 ddi_intr_handle_impl_t *, void *); 13725cf1a30Sjl139090 13825cf1a30Sjl139090 static uint32_t pcmu_identity_init(pcmu_t *pcmu_p); 13925cf1a30Sjl139090 static int pcmu_intr_setup(pcmu_t *pcmu_p); 14025cf1a30Sjl139090 static void pcmu_pbm_errstate_get(pcmu_t *pcmu_p, 14125cf1a30Sjl139090 pcmu_pbm_errstate_t *pbm_err_p); 14225cf1a30Sjl139090 static int pcmu_obj_setup(pcmu_t *pcmu_p); 14325cf1a30Sjl139090 static void pcmu_obj_destroy(pcmu_t *pcmu_p); 14425cf1a30Sjl139090 static void pcmu_obj_resume(pcmu_t *pcmu_p); 14525cf1a30Sjl139090 static void pcmu_obj_suspend(pcmu_t *pcmu_p); 14625cf1a30Sjl139090 14725cf1a30Sjl139090 static void u2u_ittrans_init(pcmu_t *, u2u_ittrans_data_t **); 14825cf1a30Sjl139090 static void u2u_ittrans_resume(u2u_ittrans_data_t **); 14925cf1a30Sjl139090 static void u2u_ittrans_uninit(u2u_ittrans_data_t *); 15025cf1a30Sjl139090 15125cf1a30Sjl139090 static pcmu_ksinfo_t *pcmu_name_kstat; 15225cf1a30Sjl139090 15325cf1a30Sjl139090 /* 15425cf1a30Sjl139090 * bus ops and dev ops structures: 15525cf1a30Sjl139090 */ 15625cf1a30Sjl139090 static struct bus_ops pcmu_bus_ops = { 15725cf1a30Sjl139090 BUSO_REV, 15825cf1a30Sjl139090 pcmu_map, 15925cf1a30Sjl139090 0, 16025cf1a30Sjl139090 0, 16125cf1a30Sjl139090 0, 16225cf1a30Sjl139090 i_ddi_map_fault, 16325cf1a30Sjl139090 0, 16425cf1a30Sjl139090 0, 16525cf1a30Sjl139090 0, 16625cf1a30Sjl139090 0, 16725cf1a30Sjl139090 0, 16825cf1a30Sjl139090 0, 16925cf1a30Sjl139090 0, 17025cf1a30Sjl139090 0, 17125cf1a30Sjl139090 pcmu_ctlops, 17225cf1a30Sjl139090 ddi_bus_prop_op, 17325cf1a30Sjl139090 ndi_busop_get_eventcookie, /* (*bus_get_eventcookie)(); */ 17425cf1a30Sjl139090 ndi_busop_add_eventcall, /* (*bus_add_eventcall)(); */ 17525cf1a30Sjl139090 ndi_busop_remove_eventcall, /* (*bus_remove_eventcall)(); */ 17625cf1a30Sjl139090 ndi_post_event, /* (*bus_post_event)(); */ 17725cf1a30Sjl139090 NULL, /* (*bus_intr_ctl)(); */ 17825cf1a30Sjl139090 NULL, /* (*bus_config)(); */ 17925cf1a30Sjl139090 NULL, /* (*bus_unconfig)(); */ 18025cf1a30Sjl139090 NULL, /* (*bus_fm_init)(); */ 18125cf1a30Sjl139090 NULL, /* (*bus_fm_fini)(); */ 18225cf1a30Sjl139090 NULL, /* (*bus_fm_access_enter)(); */ 18325cf1a30Sjl139090 NULL, /* (*bus_fm_access_fini)(); */ 18425cf1a30Sjl139090 NULL, /* (*bus_power)(); */ 18525cf1a30Sjl139090 pcmu_intr_ops /* (*bus_intr_op)(); */ 18625cf1a30Sjl139090 }; 18725cf1a30Sjl139090 18825cf1a30Sjl139090 struct cb_ops pcmu_cb_ops = { 18925cf1a30Sjl139090 pcmu_open, /* open */ 19025cf1a30Sjl139090 pcmu_close, /* close */ 19125cf1a30Sjl139090 nodev, /* strategy */ 19225cf1a30Sjl139090 nodev, /* print */ 19325cf1a30Sjl139090 nodev, /* dump */ 19425cf1a30Sjl139090 nodev, /* read */ 19525cf1a30Sjl139090 nodev, /* write */ 19625cf1a30Sjl139090 pcmu_ioctl, /* ioctl */ 19725cf1a30Sjl139090 nodev, /* devmap */ 19825cf1a30Sjl139090 nodev, /* mmap */ 19925cf1a30Sjl139090 nodev, /* segmap */ 20025cf1a30Sjl139090 nochpoll, /* poll */ 20125cf1a30Sjl139090 pcmu_prop_op, /* cb_prop_op */ 20225cf1a30Sjl139090 NULL, /* streamtab */ 20325cf1a30Sjl139090 D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 20425cf1a30Sjl139090 CB_REV, /* rev */ 20525cf1a30Sjl139090 nodev, /* int (*cb_aread)() */ 20625cf1a30Sjl139090 nodev /* int (*cb_awrite)() */ 20725cf1a30Sjl139090 }; 20825cf1a30Sjl139090 20925cf1a30Sjl139090 static struct dev_ops pcmu_ops = { 21025cf1a30Sjl139090 DEVO_REV, 21125cf1a30Sjl139090 0, 21225cf1a30Sjl139090 pcmu_info, 21325cf1a30Sjl139090 nulldev, 21425cf1a30Sjl139090 0, 21525cf1a30Sjl139090 pcmu_attach, 21625cf1a30Sjl139090 pcmu_detach, 21725cf1a30Sjl139090 nodev, 21825cf1a30Sjl139090 &pcmu_cb_ops, 21925cf1a30Sjl139090 &pcmu_bus_ops, 220*19397407SSherry Moore 0, 221*19397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 222*19397407SSherry Moore 22325cf1a30Sjl139090 }; 22425cf1a30Sjl139090 22525cf1a30Sjl139090 /* 22625cf1a30Sjl139090 * module definitions: 22725cf1a30Sjl139090 */ 22825cf1a30Sjl139090 extern struct mod_ops mod_driverops; 22925cf1a30Sjl139090 23025cf1a30Sjl139090 static struct modldrv modldrv = { 23125cf1a30Sjl139090 &mod_driverops, /* Type of module - driver */ 232*19397407SSherry Moore "OPL CMU-CH PCI Nexus driver", /* Name of module. */ 23325cf1a30Sjl139090 &pcmu_ops, /* driver ops */ 23425cf1a30Sjl139090 }; 23525cf1a30Sjl139090 23625cf1a30Sjl139090 static struct modlinkage modlinkage = { 23725cf1a30Sjl139090 MODREV_1, (void *)&modldrv, NULL 23825cf1a30Sjl139090 }; 23925cf1a30Sjl139090 24025cf1a30Sjl139090 /* 24125cf1a30Sjl139090 * driver global data: 24225cf1a30Sjl139090 */ 24325cf1a30Sjl139090 void *per_pcmu_state; /* per-pbm soft state pointer */ 24425cf1a30Sjl139090 kmutex_t pcmu_global_mutex; /* attach/detach common struct lock */ 24525cf1a30Sjl139090 errorq_t *pcmu_ecc_queue = NULL; /* per-system ecc handling queue */ 24625cf1a30Sjl139090 24725cf1a30Sjl139090 extern void pcmu_child_cfg_save(dev_info_t *dip); 24825cf1a30Sjl139090 extern void pcmu_child_cfg_restore(dev_info_t *dip); 24925cf1a30Sjl139090 25025cf1a30Sjl139090 int 25125cf1a30Sjl139090 _init(void) 25225cf1a30Sjl139090 { 25325cf1a30Sjl139090 int e; 25425cf1a30Sjl139090 25525cf1a30Sjl139090 /* 25625cf1a30Sjl139090 * Initialize per-pci bus soft state pointer. 25725cf1a30Sjl139090 */ 25825cf1a30Sjl139090 e = ddi_soft_state_init(&per_pcmu_state, sizeof (pcmu_t), 1); 25925cf1a30Sjl139090 if (e != 0) 26025cf1a30Sjl139090 return (e); 26125cf1a30Sjl139090 26225cf1a30Sjl139090 /* 26325cf1a30Sjl139090 * Initialize global mutexes. 26425cf1a30Sjl139090 */ 26525cf1a30Sjl139090 mutex_init(&pcmu_global_mutex, NULL, MUTEX_DRIVER, NULL); 26625cf1a30Sjl139090 26725cf1a30Sjl139090 /* 26825cf1a30Sjl139090 * Create the performance kstats. 26925cf1a30Sjl139090 */ 27025cf1a30Sjl139090 pcmu_kstat_init(); 27125cf1a30Sjl139090 27225cf1a30Sjl139090 /* 27325cf1a30Sjl139090 * Install the module. 27425cf1a30Sjl139090 */ 27525cf1a30Sjl139090 e = mod_install(&modlinkage); 27625cf1a30Sjl139090 if (e != 0) { 27725cf1a30Sjl139090 ddi_soft_state_fini(&per_pcmu_state); 27825cf1a30Sjl139090 mutex_destroy(&pcmu_global_mutex); 27925cf1a30Sjl139090 } 28025cf1a30Sjl139090 return (e); 28125cf1a30Sjl139090 } 28225cf1a30Sjl139090 28325cf1a30Sjl139090 int 28425cf1a30Sjl139090 _fini(void) 28525cf1a30Sjl139090 { 28625cf1a30Sjl139090 int e; 28725cf1a30Sjl139090 28825cf1a30Sjl139090 /* 28925cf1a30Sjl139090 * Remove the module. 29025cf1a30Sjl139090 */ 29125cf1a30Sjl139090 e = mod_remove(&modlinkage); 29225cf1a30Sjl139090 if (e != 0) { 29325cf1a30Sjl139090 return (e); 29425cf1a30Sjl139090 } 29525cf1a30Sjl139090 29625cf1a30Sjl139090 /* 29725cf1a30Sjl139090 * Destroy pcmu_ecc_queue, and set it to NULL. 29825cf1a30Sjl139090 */ 29925cf1a30Sjl139090 if (pcmu_ecc_queue) { 30025cf1a30Sjl139090 errorq_destroy(pcmu_ecc_queue); 30125cf1a30Sjl139090 pcmu_ecc_queue = NULL; 30225cf1a30Sjl139090 } 30325cf1a30Sjl139090 30425cf1a30Sjl139090 /* 30525cf1a30Sjl139090 * Destroy the performance kstats. 30625cf1a30Sjl139090 */ 30725cf1a30Sjl139090 pcmu_kstat_fini(); 30825cf1a30Sjl139090 30925cf1a30Sjl139090 /* 31025cf1a30Sjl139090 * Free the per-pci and per-CMU-CH soft state info and destroy 31125cf1a30Sjl139090 * mutex for per-CMU-CH soft state. 31225cf1a30Sjl139090 */ 31325cf1a30Sjl139090 ddi_soft_state_fini(&per_pcmu_state); 31425cf1a30Sjl139090 mutex_destroy(&pcmu_global_mutex); 31525cf1a30Sjl139090 return (e); 31625cf1a30Sjl139090 } 31725cf1a30Sjl139090 31825cf1a30Sjl139090 int 31925cf1a30Sjl139090 _info(struct modinfo *modinfop) 32025cf1a30Sjl139090 { 32125cf1a30Sjl139090 return (mod_info(&modlinkage, modinfop)); 32225cf1a30Sjl139090 } 32325cf1a30Sjl139090 32425cf1a30Sjl139090 /*ARGSUSED*/ 32525cf1a30Sjl139090 static int 32625cf1a30Sjl139090 pcmu_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 32725cf1a30Sjl139090 { 32825cf1a30Sjl139090 int instance = getminor((dev_t)arg) >> 8; 32925cf1a30Sjl139090 pcmu_t *pcmu_p = get_pcmu_soft_state(instance); 33025cf1a30Sjl139090 33125cf1a30Sjl139090 switch (infocmd) { 33225cf1a30Sjl139090 case DDI_INFO_DEVT2INSTANCE: 33325cf1a30Sjl139090 *result = (void *)(uintptr_t)instance; 33425cf1a30Sjl139090 return (DDI_SUCCESS); 33525cf1a30Sjl139090 33625cf1a30Sjl139090 case DDI_INFO_DEVT2DEVINFO: 33725cf1a30Sjl139090 if (pcmu_p == NULL) 33825cf1a30Sjl139090 return (DDI_FAILURE); 33925cf1a30Sjl139090 *result = (void *)pcmu_p->pcmu_dip; 34025cf1a30Sjl139090 return (DDI_SUCCESS); 34125cf1a30Sjl139090 34225cf1a30Sjl139090 default: 34325cf1a30Sjl139090 return (DDI_FAILURE); 34425cf1a30Sjl139090 } 34525cf1a30Sjl139090 } 34625cf1a30Sjl139090 34725cf1a30Sjl139090 34825cf1a30Sjl139090 /* device driver entry points */ 34925cf1a30Sjl139090 /* 35025cf1a30Sjl139090 * attach entry point: 35125cf1a30Sjl139090 */ 35225cf1a30Sjl139090 static int 35325cf1a30Sjl139090 pcmu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 35425cf1a30Sjl139090 { 35525cf1a30Sjl139090 pcmu_t *pcmu_p; 35625cf1a30Sjl139090 int instance = ddi_get_instance(dip); 35725cf1a30Sjl139090 35825cf1a30Sjl139090 switch (cmd) { 35925cf1a30Sjl139090 case DDI_ATTACH: 36025cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_ATTACH, dip, "DDI_ATTACH\n"); 36125cf1a30Sjl139090 36225cf1a30Sjl139090 /* 36325cf1a30Sjl139090 * Allocate and get the per-pci soft state structure. 36425cf1a30Sjl139090 */ 36525cf1a30Sjl139090 if (alloc_pcmu_soft_state(instance) != DDI_SUCCESS) { 36625cf1a30Sjl139090 cmn_err(CE_WARN, "%s%d: can't allocate pci state", 36725cf1a30Sjl139090 ddi_driver_name(dip), instance); 36825cf1a30Sjl139090 goto err_bad_pcmu_softstate; 36925cf1a30Sjl139090 } 37025cf1a30Sjl139090 pcmu_p = get_pcmu_soft_state(instance); 37125cf1a30Sjl139090 pcmu_p->pcmu_dip = dip; 37225cf1a30Sjl139090 mutex_init(&pcmu_p->pcmu_mutex, NULL, MUTEX_DRIVER, NULL); 37325cf1a30Sjl139090 pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_CLOSED; 37425cf1a30Sjl139090 pcmu_p->pcmu_open_count = 0; 37525cf1a30Sjl139090 37625cf1a30Sjl139090 /* 37725cf1a30Sjl139090 * Get key properties of the pci bridge node. 37825cf1a30Sjl139090 */ 37925cf1a30Sjl139090 if (get_pcmu_properties(pcmu_p, dip) == DDI_FAILURE) { 38025cf1a30Sjl139090 goto err_bad_pcmu_prop; 38125cf1a30Sjl139090 } 38225cf1a30Sjl139090 38325cf1a30Sjl139090 /* 38425cf1a30Sjl139090 * Map in the registers. 38525cf1a30Sjl139090 */ 38625cf1a30Sjl139090 if (map_pcmu_registers(pcmu_p, dip) == DDI_FAILURE) { 38725cf1a30Sjl139090 goto err_bad_reg_prop; 38825cf1a30Sjl139090 } 38925cf1a30Sjl139090 if (pcmu_obj_setup(pcmu_p) != DDI_SUCCESS) { 39025cf1a30Sjl139090 goto err_bad_objs; 39125cf1a30Sjl139090 } 39225cf1a30Sjl139090 39325cf1a30Sjl139090 if (ddi_create_minor_node(dip, "devctl", S_IFCHR, 39425cf1a30Sjl139090 (uint_t)instance<<8 | 0xff, 39525cf1a30Sjl139090 DDI_NT_NEXUS, 0) != DDI_SUCCESS) { 39625cf1a30Sjl139090 goto err_bad_devctl_node; 39725cf1a30Sjl139090 } 39825cf1a30Sjl139090 39925cf1a30Sjl139090 /* 40025cf1a30Sjl139090 * Due to unresolved hardware issues, disable PCIPM until 40125cf1a30Sjl139090 * the problem is fully understood. 40225cf1a30Sjl139090 * 40325cf1a30Sjl139090 * pcmu_pwr_setup(pcmu_p, dip); 40425cf1a30Sjl139090 */ 40525cf1a30Sjl139090 40625cf1a30Sjl139090 ddi_report_dev(dip); 40725cf1a30Sjl139090 40825cf1a30Sjl139090 pcmu_p->pcmu_state = PCMU_ATTACHED; 40925cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_ATTACH, dip, "attach success\n"); 41025cf1a30Sjl139090 break; 41125cf1a30Sjl139090 41225cf1a30Sjl139090 err_bad_objs: 41325cf1a30Sjl139090 ddi_remove_minor_node(dip, "devctl"); 41425cf1a30Sjl139090 err_bad_devctl_node: 41525cf1a30Sjl139090 unmap_pcmu_registers(pcmu_p); 41625cf1a30Sjl139090 err_bad_reg_prop: 41725cf1a30Sjl139090 free_pcmu_properties(pcmu_p); 41825cf1a30Sjl139090 err_bad_pcmu_prop: 41925cf1a30Sjl139090 mutex_destroy(&pcmu_p->pcmu_mutex); 42025cf1a30Sjl139090 free_pcmu_soft_state(instance); 42125cf1a30Sjl139090 err_bad_pcmu_softstate: 42225cf1a30Sjl139090 return (DDI_FAILURE); 42325cf1a30Sjl139090 42425cf1a30Sjl139090 case DDI_RESUME: 42525cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_ATTACH, dip, "DDI_RESUME\n"); 42625cf1a30Sjl139090 42725cf1a30Sjl139090 /* 42825cf1a30Sjl139090 * Make sure the CMU-CH control registers 42925cf1a30Sjl139090 * are configured properly. 43025cf1a30Sjl139090 */ 43125cf1a30Sjl139090 pcmu_p = get_pcmu_soft_state(instance); 43225cf1a30Sjl139090 mutex_enter(&pcmu_p->pcmu_mutex); 43325cf1a30Sjl139090 43425cf1a30Sjl139090 /* 43525cf1a30Sjl139090 * Make sure this instance has been suspended. 43625cf1a30Sjl139090 */ 43725cf1a30Sjl139090 if (pcmu_p->pcmu_state != PCMU_SUSPENDED) { 43825cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_ATTACH, dip, 43925cf1a30Sjl139090 "instance NOT suspended\n"); 44025cf1a30Sjl139090 mutex_exit(&pcmu_p->pcmu_mutex); 44125cf1a30Sjl139090 return (DDI_FAILURE); 44225cf1a30Sjl139090 } 44325cf1a30Sjl139090 pcmu_obj_resume(pcmu_p); 44425cf1a30Sjl139090 pcmu_p->pcmu_state = PCMU_ATTACHED; 44525cf1a30Sjl139090 44625cf1a30Sjl139090 pcmu_child_cfg_restore(dip); 44725cf1a30Sjl139090 44825cf1a30Sjl139090 mutex_exit(&pcmu_p->pcmu_mutex); 44925cf1a30Sjl139090 break; 45025cf1a30Sjl139090 45125cf1a30Sjl139090 default: 45225cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_ATTACH, dip, "unsupported attach op\n"); 45325cf1a30Sjl139090 return (DDI_FAILURE); 45425cf1a30Sjl139090 } 45525cf1a30Sjl139090 45625cf1a30Sjl139090 return (DDI_SUCCESS); 45725cf1a30Sjl139090 } 45825cf1a30Sjl139090 45925cf1a30Sjl139090 /* 46025cf1a30Sjl139090 * detach entry point: 46125cf1a30Sjl139090 */ 46225cf1a30Sjl139090 static int 46325cf1a30Sjl139090 pcmu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 46425cf1a30Sjl139090 { 46525cf1a30Sjl139090 int instance = ddi_get_instance(dip); 46625cf1a30Sjl139090 pcmu_t *pcmu_p = get_pcmu_soft_state(instance); 46725cf1a30Sjl139090 int len; 46825cf1a30Sjl139090 46925cf1a30Sjl139090 /* 47025cf1a30Sjl139090 * Make sure we are currently attached 47125cf1a30Sjl139090 */ 47225cf1a30Sjl139090 if (pcmu_p->pcmu_state != PCMU_ATTACHED) { 47325cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_ATTACH, dip, 47425cf1a30Sjl139090 "failed - instance not attached\n"); 47525cf1a30Sjl139090 return (DDI_FAILURE); 47625cf1a30Sjl139090 } 47725cf1a30Sjl139090 47825cf1a30Sjl139090 mutex_enter(&pcmu_p->pcmu_mutex); 47925cf1a30Sjl139090 48025cf1a30Sjl139090 switch (cmd) { 48125cf1a30Sjl139090 case DDI_DETACH: 48225cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_DETACH, dip, "DDI_DETACH\n"); 48325cf1a30Sjl139090 pcmu_obj_destroy(pcmu_p); 48425cf1a30Sjl139090 48525cf1a30Sjl139090 /* 48625cf1a30Sjl139090 * Free the pci soft state structure and the rest of the 48725cf1a30Sjl139090 * resources it's using. 48825cf1a30Sjl139090 */ 48925cf1a30Sjl139090 free_pcmu_properties(pcmu_p); 49025cf1a30Sjl139090 unmap_pcmu_registers(pcmu_p); 49125cf1a30Sjl139090 mutex_exit(&pcmu_p->pcmu_mutex); 49225cf1a30Sjl139090 mutex_destroy(&pcmu_p->pcmu_mutex); 49325cf1a30Sjl139090 free_pcmu_soft_state(instance); 49425cf1a30Sjl139090 49525cf1a30Sjl139090 /* Free the interrupt-priorities prop if we created it. */ 49625cf1a30Sjl139090 if (ddi_getproplen(DDI_DEV_T_ANY, dip, 49725cf1a30Sjl139090 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 49825cf1a30Sjl139090 "interrupt-priorities", &len) == DDI_PROP_SUCCESS) { 49925cf1a30Sjl139090 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, 50025cf1a30Sjl139090 "interrupt-priorities"); 50125cf1a30Sjl139090 } 50225cf1a30Sjl139090 return (DDI_SUCCESS); 50325cf1a30Sjl139090 50425cf1a30Sjl139090 case DDI_SUSPEND: 50525cf1a30Sjl139090 pcmu_child_cfg_save(dip); 50625cf1a30Sjl139090 pcmu_obj_suspend(pcmu_p); 50725cf1a30Sjl139090 pcmu_p->pcmu_state = PCMU_SUSPENDED; 50825cf1a30Sjl139090 50925cf1a30Sjl139090 mutex_exit(&pcmu_p->pcmu_mutex); 51025cf1a30Sjl139090 return (DDI_SUCCESS); 51125cf1a30Sjl139090 51225cf1a30Sjl139090 default: 51325cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_DETACH, dip, "unsupported detach op\n"); 51425cf1a30Sjl139090 mutex_exit(&pcmu_p->pcmu_mutex); 51525cf1a30Sjl139090 return (DDI_FAILURE); 51625cf1a30Sjl139090 } 51725cf1a30Sjl139090 } 51825cf1a30Sjl139090 51925cf1a30Sjl139090 /* ARGSUSED3 */ 52025cf1a30Sjl139090 static int 52125cf1a30Sjl139090 pcmu_open(dev_t *devp, int flags, int otyp, cred_t *credp) 52225cf1a30Sjl139090 { 52325cf1a30Sjl139090 pcmu_t *pcmu_p; 52425cf1a30Sjl139090 52525cf1a30Sjl139090 if (otyp != OTYP_CHR) { 52625cf1a30Sjl139090 return (EINVAL); 52725cf1a30Sjl139090 } 52825cf1a30Sjl139090 52925cf1a30Sjl139090 /* 53025cf1a30Sjl139090 * Get the soft state structure for the device. 53125cf1a30Sjl139090 */ 53225cf1a30Sjl139090 pcmu_p = DEV_TO_SOFTSTATE(*devp); 53325cf1a30Sjl139090 if (pcmu_p == NULL) { 53425cf1a30Sjl139090 return (ENXIO); 53525cf1a30Sjl139090 } 53625cf1a30Sjl139090 53725cf1a30Sjl139090 /* 53825cf1a30Sjl139090 * Handle the open by tracking the device state. 53925cf1a30Sjl139090 */ 54025cf1a30Sjl139090 PCMU_DBG2(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, 54125cf1a30Sjl139090 "devp=%x: flags=%x\n", devp, flags); 54225cf1a30Sjl139090 mutex_enter(&pcmu_p->pcmu_mutex); 54325cf1a30Sjl139090 if (flags & FEXCL) { 54425cf1a30Sjl139090 if (pcmu_p->pcmu_soft_state != PCMU_SOFT_STATE_CLOSED) { 54525cf1a30Sjl139090 mutex_exit(&pcmu_p->pcmu_mutex); 54625cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, "busy\n"); 54725cf1a30Sjl139090 return (EBUSY); 54825cf1a30Sjl139090 } 54925cf1a30Sjl139090 pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_OPEN_EXCL; 55025cf1a30Sjl139090 } else { 55125cf1a30Sjl139090 if (pcmu_p->pcmu_soft_state == PCMU_SOFT_STATE_OPEN_EXCL) { 55225cf1a30Sjl139090 mutex_exit(&pcmu_p->pcmu_mutex); 55325cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_OPEN, pcmu_p->pcmu_dip, "busy\n"); 55425cf1a30Sjl139090 return (EBUSY); 55525cf1a30Sjl139090 } 55625cf1a30Sjl139090 pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_OPEN; 55725cf1a30Sjl139090 } 55825cf1a30Sjl139090 pcmu_p->pcmu_open_count++; 55925cf1a30Sjl139090 mutex_exit(&pcmu_p->pcmu_mutex); 56025cf1a30Sjl139090 return (0); 56125cf1a30Sjl139090 } 56225cf1a30Sjl139090 56325cf1a30Sjl139090 56425cf1a30Sjl139090 /* ARGSUSED */ 56525cf1a30Sjl139090 static int 56625cf1a30Sjl139090 pcmu_close(dev_t dev, int flags, int otyp, cred_t *credp) 56725cf1a30Sjl139090 { 56825cf1a30Sjl139090 pcmu_t *pcmu_p; 56925cf1a30Sjl139090 57025cf1a30Sjl139090 if (otyp != OTYP_CHR) { 57125cf1a30Sjl139090 return (EINVAL); 57225cf1a30Sjl139090 } 57325cf1a30Sjl139090 57425cf1a30Sjl139090 pcmu_p = DEV_TO_SOFTSTATE(dev); 57525cf1a30Sjl139090 if (pcmu_p == NULL) { 57625cf1a30Sjl139090 return (ENXIO); 57725cf1a30Sjl139090 } 57825cf1a30Sjl139090 57925cf1a30Sjl139090 PCMU_DBG2(PCMU_DBG_CLOSE, pcmu_p->pcmu_dip, 58025cf1a30Sjl139090 "dev=%x: flags=%x\n", dev, flags); 58125cf1a30Sjl139090 mutex_enter(&pcmu_p->pcmu_mutex); 58225cf1a30Sjl139090 pcmu_p->pcmu_soft_state = PCMU_SOFT_STATE_CLOSED; 58325cf1a30Sjl139090 pcmu_p->pcmu_open_count = 0; 58425cf1a30Sjl139090 mutex_exit(&pcmu_p->pcmu_mutex); 58525cf1a30Sjl139090 return (0); 58625cf1a30Sjl139090 } 58725cf1a30Sjl139090 58825cf1a30Sjl139090 /* ARGSUSED */ 58925cf1a30Sjl139090 static int 59025cf1a30Sjl139090 pcmu_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 59125cf1a30Sjl139090 cred_t *credp, int *rvalp) 59225cf1a30Sjl139090 { 59325cf1a30Sjl139090 pcmu_t *pcmu_p; 59425cf1a30Sjl139090 dev_info_t *dip; 59525cf1a30Sjl139090 struct devctl_iocdata *dcp; 59625cf1a30Sjl139090 uint_t bus_state; 59725cf1a30Sjl139090 int rv = 0; 59825cf1a30Sjl139090 59925cf1a30Sjl139090 pcmu_p = DEV_TO_SOFTSTATE(dev); 60025cf1a30Sjl139090 if (pcmu_p == NULL) { 60125cf1a30Sjl139090 return (ENXIO); 60225cf1a30Sjl139090 } 60325cf1a30Sjl139090 60425cf1a30Sjl139090 dip = pcmu_p->pcmu_dip; 60525cf1a30Sjl139090 PCMU_DBG2(PCMU_DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd); 60625cf1a30Sjl139090 60725cf1a30Sjl139090 /* 60825cf1a30Sjl139090 * We can use the generic implementation for these ioctls 60925cf1a30Sjl139090 */ 61025cf1a30Sjl139090 switch (cmd) { 61125cf1a30Sjl139090 case DEVCTL_DEVICE_GETSTATE: 61225cf1a30Sjl139090 case DEVCTL_DEVICE_ONLINE: 61325cf1a30Sjl139090 case DEVCTL_DEVICE_OFFLINE: 61425cf1a30Sjl139090 case DEVCTL_BUS_GETSTATE: 61525cf1a30Sjl139090 return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0)); 61625cf1a30Sjl139090 } 61725cf1a30Sjl139090 61825cf1a30Sjl139090 /* 61925cf1a30Sjl139090 * read devctl ioctl data 62025cf1a30Sjl139090 */ 62125cf1a30Sjl139090 if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 62225cf1a30Sjl139090 return (EFAULT); 62325cf1a30Sjl139090 62425cf1a30Sjl139090 switch (cmd) { 62525cf1a30Sjl139090 62625cf1a30Sjl139090 case DEVCTL_DEVICE_RESET: 62725cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_DEVICE_RESET\n"); 62825cf1a30Sjl139090 rv = ENOTSUP; 62925cf1a30Sjl139090 break; 63025cf1a30Sjl139090 63125cf1a30Sjl139090 63225cf1a30Sjl139090 case DEVCTL_BUS_QUIESCE: 63325cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_QUIESCE\n"); 63425cf1a30Sjl139090 if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) { 63525cf1a30Sjl139090 if (bus_state == BUS_QUIESCED) { 63625cf1a30Sjl139090 break; 63725cf1a30Sjl139090 } 63825cf1a30Sjl139090 } 63925cf1a30Sjl139090 (void) ndi_set_bus_state(dip, BUS_QUIESCED); 64025cf1a30Sjl139090 break; 64125cf1a30Sjl139090 64225cf1a30Sjl139090 case DEVCTL_BUS_UNQUIESCE: 64325cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_UNQUIESCE\n"); 64425cf1a30Sjl139090 if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS) { 64525cf1a30Sjl139090 if (bus_state == BUS_ACTIVE) { 64625cf1a30Sjl139090 break; 64725cf1a30Sjl139090 } 64825cf1a30Sjl139090 } 64925cf1a30Sjl139090 (void) ndi_set_bus_state(dip, BUS_ACTIVE); 65025cf1a30Sjl139090 break; 65125cf1a30Sjl139090 65225cf1a30Sjl139090 case DEVCTL_BUS_RESET: 65325cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_RESET\n"); 65425cf1a30Sjl139090 rv = ENOTSUP; 65525cf1a30Sjl139090 break; 65625cf1a30Sjl139090 65725cf1a30Sjl139090 case DEVCTL_BUS_RESETALL: 65825cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_IOCTL, dip, "DEVCTL_BUS_RESETALL\n"); 65925cf1a30Sjl139090 rv = ENOTSUP; 66025cf1a30Sjl139090 break; 66125cf1a30Sjl139090 66225cf1a30Sjl139090 default: 66325cf1a30Sjl139090 rv = ENOTTY; 66425cf1a30Sjl139090 } 66525cf1a30Sjl139090 66625cf1a30Sjl139090 ndi_dc_freehdl(dcp); 66725cf1a30Sjl139090 return (rv); 66825cf1a30Sjl139090 } 66925cf1a30Sjl139090 67025cf1a30Sjl139090 static int pcmu_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 67125cf1a30Sjl139090 int flags, char *name, caddr_t valuep, int *lengthp) 67225cf1a30Sjl139090 { 67325cf1a30Sjl139090 return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); 67425cf1a30Sjl139090 } 67525cf1a30Sjl139090 /* bus driver entry points */ 67625cf1a30Sjl139090 67725cf1a30Sjl139090 /* 67825cf1a30Sjl139090 * bus map entry point: 67925cf1a30Sjl139090 * 68025cf1a30Sjl139090 * if map request is for an rnumber 68125cf1a30Sjl139090 * get the corresponding regspec from device node 68225cf1a30Sjl139090 * build a new regspec in our parent's format 68325cf1a30Sjl139090 * build a new map_req with the new regspec 68425cf1a30Sjl139090 * call up the tree to complete the mapping 68525cf1a30Sjl139090 */ 68625cf1a30Sjl139090 static int 68725cf1a30Sjl139090 pcmu_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 68825cf1a30Sjl139090 off_t off, off_t len, caddr_t *addrp) 68925cf1a30Sjl139090 { 69025cf1a30Sjl139090 pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); 69125cf1a30Sjl139090 struct regspec p_regspec; 69225cf1a30Sjl139090 ddi_map_req_t p_mapreq; 69325cf1a30Sjl139090 int reglen, rval, r_no; 69425cf1a30Sjl139090 pci_regspec_t reloc_reg, *rp = &reloc_reg; 69525cf1a30Sjl139090 69625cf1a30Sjl139090 PCMU_DBG2(PCMU_DBG_MAP, dip, "rdip=%s%d:", 69725cf1a30Sjl139090 ddi_driver_name(rdip), ddi_get_instance(rdip)); 69825cf1a30Sjl139090 69925cf1a30Sjl139090 if (mp->map_flags & DDI_MF_USER_MAPPING) { 70025cf1a30Sjl139090 return (DDI_ME_UNIMPLEMENTED); 70125cf1a30Sjl139090 } 70225cf1a30Sjl139090 70325cf1a30Sjl139090 switch (mp->map_type) { 70425cf1a30Sjl139090 case DDI_MT_REGSPEC: 70525cf1a30Sjl139090 reloc_reg = *(pci_regspec_t *)mp->map_obj.rp; /* dup whole */ 70625cf1a30Sjl139090 break; 70725cf1a30Sjl139090 70825cf1a30Sjl139090 case DDI_MT_RNUMBER: 70925cf1a30Sjl139090 r_no = mp->map_obj.rnumber; 71025cf1a30Sjl139090 PCMU_DBG1(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, " r#=%x", r_no); 71125cf1a30Sjl139090 71225cf1a30Sjl139090 if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS, 71325cf1a30Sjl139090 "reg", (caddr_t)&rp, ®len) != DDI_SUCCESS) { 71425cf1a30Sjl139090 return (DDI_ME_RNUMBER_RANGE); 71525cf1a30Sjl139090 } 71625cf1a30Sjl139090 71725cf1a30Sjl139090 if (r_no < 0 || r_no >= reglen / sizeof (pci_regspec_t)) { 71825cf1a30Sjl139090 kmem_free(rp, reglen); 71925cf1a30Sjl139090 return (DDI_ME_RNUMBER_RANGE); 72025cf1a30Sjl139090 } 72125cf1a30Sjl139090 rp += r_no; 72225cf1a30Sjl139090 break; 72325cf1a30Sjl139090 72425cf1a30Sjl139090 default: 72525cf1a30Sjl139090 return (DDI_ME_INVAL); 72625cf1a30Sjl139090 } 72725cf1a30Sjl139090 PCMU_DBG0(PCMU_DBG_MAP | PCMU_DBG_CONT, dip, "\n"); 72825cf1a30Sjl139090 72925cf1a30Sjl139090 /* use "assigned-addresses" to relocate regspec within pci space */ 73025cf1a30Sjl139090 if (rval = pcmu_reloc_reg(dip, rdip, pcmu_p, rp)) { 73125cf1a30Sjl139090 goto done; 73225cf1a30Sjl139090 } 73325cf1a30Sjl139090 73425cf1a30Sjl139090 /* adjust regspec according to mapping request */ 73525cf1a30Sjl139090 if (len) { 73625cf1a30Sjl139090 rp->pci_size_low = (uint_t)len; 73725cf1a30Sjl139090 } 73825cf1a30Sjl139090 rp->pci_phys_low += off; 73925cf1a30Sjl139090 74025cf1a30Sjl139090 /* use "ranges" to translate relocated pci regspec into parent space */ 74125cf1a30Sjl139090 if (rval = pcmu_xlate_reg(pcmu_p, rp, &p_regspec)) { 74225cf1a30Sjl139090 goto done; 74325cf1a30Sjl139090 } 74425cf1a30Sjl139090 74525cf1a30Sjl139090 p_mapreq = *mp; /* dup the whole structure */ 74625cf1a30Sjl139090 p_mapreq.map_type = DDI_MT_REGSPEC; 74725cf1a30Sjl139090 p_mapreq.map_obj.rp = &p_regspec; 74825cf1a30Sjl139090 rval = ddi_map(dip, &p_mapreq, 0, 0, addrp); 74925cf1a30Sjl139090 75025cf1a30Sjl139090 done: 75125cf1a30Sjl139090 if (mp->map_type == DDI_MT_RNUMBER) { 75225cf1a30Sjl139090 kmem_free(rp - r_no, reglen); 75325cf1a30Sjl139090 } 75425cf1a30Sjl139090 return (rval); 75525cf1a30Sjl139090 } 75625cf1a30Sjl139090 75725cf1a30Sjl139090 #ifdef DEBUG 75825cf1a30Sjl139090 int pcmu_peekfault_cnt = 0; 75925cf1a30Sjl139090 int pcmu_pokefault_cnt = 0; 76025cf1a30Sjl139090 #endif /* DEBUG */ 76125cf1a30Sjl139090 76225cf1a30Sjl139090 static int 76325cf1a30Sjl139090 pcmu_do_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args) 76425cf1a30Sjl139090 { 76525cf1a30Sjl139090 pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 76625cf1a30Sjl139090 int err = DDI_SUCCESS; 76725cf1a30Sjl139090 on_trap_data_t otd; 76825cf1a30Sjl139090 76925cf1a30Sjl139090 mutex_enter(&pcbm_p->pcbm_pokeflt_mutex); 77025cf1a30Sjl139090 pcbm_p->pcbm_ontrap_data = &otd; 77125cf1a30Sjl139090 77225cf1a30Sjl139090 /* Set up protected environment. */ 77325cf1a30Sjl139090 if (!on_trap(&otd, OT_DATA_ACCESS)) { 77425cf1a30Sjl139090 uintptr_t tramp = otd.ot_trampoline; 77525cf1a30Sjl139090 77625cf1a30Sjl139090 otd.ot_trampoline = (uintptr_t)&poke_fault; 77725cf1a30Sjl139090 err = do_poke(in_args->size, (void *)in_args->dev_addr, 77825cf1a30Sjl139090 (void *)in_args->host_addr); 77925cf1a30Sjl139090 otd.ot_trampoline = tramp; 78025cf1a30Sjl139090 } else { 78125cf1a30Sjl139090 err = DDI_FAILURE; 78225cf1a30Sjl139090 } 78325cf1a30Sjl139090 78425cf1a30Sjl139090 /* 78525cf1a30Sjl139090 * Read the async fault register for the PBM to see it sees 78625cf1a30Sjl139090 * a master-abort. 78725cf1a30Sjl139090 */ 78825cf1a30Sjl139090 pcmu_pbm_clear_error(pcbm_p); 78925cf1a30Sjl139090 79025cf1a30Sjl139090 if (otd.ot_trap & OT_DATA_ACCESS) { 79125cf1a30Sjl139090 err = DDI_FAILURE; 79225cf1a30Sjl139090 } 79325cf1a30Sjl139090 79425cf1a30Sjl139090 /* Take down protected environment. */ 79525cf1a30Sjl139090 no_trap(); 79625cf1a30Sjl139090 79725cf1a30Sjl139090 pcbm_p->pcbm_ontrap_data = NULL; 79825cf1a30Sjl139090 mutex_exit(&pcbm_p->pcbm_pokeflt_mutex); 79925cf1a30Sjl139090 80025cf1a30Sjl139090 #ifdef DEBUG 80125cf1a30Sjl139090 if (err == DDI_FAILURE) 80225cf1a30Sjl139090 pcmu_pokefault_cnt++; 80325cf1a30Sjl139090 #endif 80425cf1a30Sjl139090 return (err); 80525cf1a30Sjl139090 } 80625cf1a30Sjl139090 80725cf1a30Sjl139090 80825cf1a30Sjl139090 static int 80925cf1a30Sjl139090 pcmu_ctlops_poke(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args) 81025cf1a30Sjl139090 { 81125cf1a30Sjl139090 return (pcmu_do_poke(pcmu_p, in_args)); 81225cf1a30Sjl139090 } 81325cf1a30Sjl139090 81425cf1a30Sjl139090 /* ARGSUSED */ 81525cf1a30Sjl139090 static int 81625cf1a30Sjl139090 pcmu_do_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args) 81725cf1a30Sjl139090 { 81825cf1a30Sjl139090 int err = DDI_SUCCESS; 81925cf1a30Sjl139090 on_trap_data_t otd; 82025cf1a30Sjl139090 82125cf1a30Sjl139090 if (!on_trap(&otd, OT_DATA_ACCESS)) { 82225cf1a30Sjl139090 uintptr_t tramp = otd.ot_trampoline; 82325cf1a30Sjl139090 82425cf1a30Sjl139090 otd.ot_trampoline = (uintptr_t)&peek_fault; 82525cf1a30Sjl139090 err = do_peek(in_args->size, (void *)in_args->dev_addr, 82625cf1a30Sjl139090 (void *)in_args->host_addr); 82725cf1a30Sjl139090 otd.ot_trampoline = tramp; 82825cf1a30Sjl139090 } else 82925cf1a30Sjl139090 err = DDI_FAILURE; 83025cf1a30Sjl139090 83125cf1a30Sjl139090 no_trap(); 83225cf1a30Sjl139090 83325cf1a30Sjl139090 #ifdef DEBUG 83425cf1a30Sjl139090 if (err == DDI_FAILURE) 83525cf1a30Sjl139090 pcmu_peekfault_cnt++; 83625cf1a30Sjl139090 #endif 83725cf1a30Sjl139090 return (err); 83825cf1a30Sjl139090 } 83925cf1a30Sjl139090 84025cf1a30Sjl139090 84125cf1a30Sjl139090 static int 84225cf1a30Sjl139090 pcmu_ctlops_peek(pcmu_t *pcmu_p, peekpoke_ctlops_t *in_args, void *result) 84325cf1a30Sjl139090 { 84425cf1a30Sjl139090 result = (void *)in_args->host_addr; 84525cf1a30Sjl139090 return (pcmu_do_peek(pcmu_p, in_args)); 84625cf1a30Sjl139090 } 84725cf1a30Sjl139090 84825cf1a30Sjl139090 /* 84925cf1a30Sjl139090 * control ops entry point: 85025cf1a30Sjl139090 * 85125cf1a30Sjl139090 * Requests handled completely: 85225cf1a30Sjl139090 * DDI_CTLOPS_INITCHILD see pcmu_init_child() for details 85325cf1a30Sjl139090 * DDI_CTLOPS_UNINITCHILD 85425cf1a30Sjl139090 * DDI_CTLOPS_REPORTDEV see report_dev() for details 85525cf1a30Sjl139090 * DDI_CTLOPS_XLATE_INTRS nothing to do 85625cf1a30Sjl139090 * DDI_CTLOPS_IOMIN cache line size if streaming otherwise 1 85725cf1a30Sjl139090 * DDI_CTLOPS_REGSIZE 85825cf1a30Sjl139090 * DDI_CTLOPS_NREGS 85925cf1a30Sjl139090 * DDI_CTLOPS_NINTRS 86025cf1a30Sjl139090 * DDI_CTLOPS_DVMAPAGESIZE 86125cf1a30Sjl139090 * DDI_CTLOPS_POKE 86225cf1a30Sjl139090 * DDI_CTLOPS_PEEK 86325cf1a30Sjl139090 * DDI_CTLOPS_QUIESCE 86425cf1a30Sjl139090 * DDI_CTLOPS_UNQUIESCE 86525cf1a30Sjl139090 * 86625cf1a30Sjl139090 * All others passed to parent. 86725cf1a30Sjl139090 */ 86825cf1a30Sjl139090 static int 86925cf1a30Sjl139090 pcmu_ctlops(dev_info_t *dip, dev_info_t *rdip, 87025cf1a30Sjl139090 ddi_ctl_enum_t op, void *arg, void *result) 87125cf1a30Sjl139090 { 87225cf1a30Sjl139090 pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); 87325cf1a30Sjl139090 87425cf1a30Sjl139090 switch (op) { 87525cf1a30Sjl139090 case DDI_CTLOPS_INITCHILD: 87625cf1a30Sjl139090 return (pcmu_init_child(pcmu_p, (dev_info_t *)arg)); 87725cf1a30Sjl139090 87825cf1a30Sjl139090 case DDI_CTLOPS_UNINITCHILD: 87925cf1a30Sjl139090 return (pcmu_uninit_child(pcmu_p, (dev_info_t *)arg)); 88025cf1a30Sjl139090 88125cf1a30Sjl139090 case DDI_CTLOPS_REPORTDEV: 88225cf1a30Sjl139090 return (pcmu_report_dev(rdip)); 88325cf1a30Sjl139090 88425cf1a30Sjl139090 case DDI_CTLOPS_IOMIN: 88525cf1a30Sjl139090 /* 88625cf1a30Sjl139090 * If we are using the streaming cache, align at 88725cf1a30Sjl139090 * least on a cache line boundary. Otherwise use 88825cf1a30Sjl139090 * whatever alignment is passed in. 88925cf1a30Sjl139090 */ 89025cf1a30Sjl139090 return (DDI_SUCCESS); 89125cf1a30Sjl139090 89225cf1a30Sjl139090 case DDI_CTLOPS_REGSIZE: 89325cf1a30Sjl139090 *((off_t *)result) = pcmu_get_reg_set_size(rdip, *((int *)arg)); 89425cf1a30Sjl139090 return (DDI_SUCCESS); 89525cf1a30Sjl139090 89625cf1a30Sjl139090 case DDI_CTLOPS_NREGS: 89725cf1a30Sjl139090 *((uint_t *)result) = pcmu_get_nreg_set(rdip); 89825cf1a30Sjl139090 return (DDI_SUCCESS); 89925cf1a30Sjl139090 90025cf1a30Sjl139090 case DDI_CTLOPS_DVMAPAGESIZE: 90125cf1a30Sjl139090 *((ulong_t *)result) = 0; 90225cf1a30Sjl139090 return (DDI_SUCCESS); 90325cf1a30Sjl139090 90425cf1a30Sjl139090 case DDI_CTLOPS_POKE: 90525cf1a30Sjl139090 return (pcmu_ctlops_poke(pcmu_p, (peekpoke_ctlops_t *)arg)); 90625cf1a30Sjl139090 90725cf1a30Sjl139090 case DDI_CTLOPS_PEEK: 90825cf1a30Sjl139090 return (pcmu_ctlops_peek(pcmu_p, (peekpoke_ctlops_t *)arg, 90925cf1a30Sjl139090 result)); 91025cf1a30Sjl139090 91125cf1a30Sjl139090 case DDI_CTLOPS_AFFINITY: 91225cf1a30Sjl139090 break; 91325cf1a30Sjl139090 91425cf1a30Sjl139090 case DDI_CTLOPS_QUIESCE: 91525cf1a30Sjl139090 return (DDI_FAILURE); 91625cf1a30Sjl139090 91725cf1a30Sjl139090 case DDI_CTLOPS_UNQUIESCE: 91825cf1a30Sjl139090 return (DDI_FAILURE); 91925cf1a30Sjl139090 92025cf1a30Sjl139090 default: 92125cf1a30Sjl139090 break; 92225cf1a30Sjl139090 } 92325cf1a30Sjl139090 92425cf1a30Sjl139090 /* 92525cf1a30Sjl139090 * Now pass the request up to our parent. 92625cf1a30Sjl139090 */ 92725cf1a30Sjl139090 PCMU_DBG2(PCMU_DBG_CTLOPS, dip, 92825cf1a30Sjl139090 "passing request to parent: rdip=%s%d\n", 92925cf1a30Sjl139090 ddi_driver_name(rdip), ddi_get_instance(rdip)); 93025cf1a30Sjl139090 return (ddi_ctlops(dip, rdip, op, arg, result)); 93125cf1a30Sjl139090 } 93225cf1a30Sjl139090 93325cf1a30Sjl139090 93425cf1a30Sjl139090 /* ARGSUSED */ 93525cf1a30Sjl139090 static int 93625cf1a30Sjl139090 pcmu_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 93725cf1a30Sjl139090 ddi_intr_handle_impl_t *hdlp, void *result) 93825cf1a30Sjl139090 { 93925cf1a30Sjl139090 pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip)); 94025cf1a30Sjl139090 int ret = DDI_SUCCESS; 94125cf1a30Sjl139090 94225cf1a30Sjl139090 switch (intr_op) { 94325cf1a30Sjl139090 case DDI_INTROP_GETCAP: 94425cf1a30Sjl139090 /* GetCap will always fail for all non PCI devices */ 94525cf1a30Sjl139090 (void) pci_intx_get_cap(rdip, (int *)result); 94625cf1a30Sjl139090 break; 94725cf1a30Sjl139090 case DDI_INTROP_SETCAP: 94825cf1a30Sjl139090 ret = DDI_ENOTSUP; 94925cf1a30Sjl139090 break; 95025cf1a30Sjl139090 case DDI_INTROP_ALLOC: 95125cf1a30Sjl139090 *(int *)result = hdlp->ih_scratch1; 95225cf1a30Sjl139090 break; 95325cf1a30Sjl139090 case DDI_INTROP_FREE: 95425cf1a30Sjl139090 break; 95525cf1a30Sjl139090 case DDI_INTROP_GETPRI: 95625cf1a30Sjl139090 *(int *)result = hdlp->ih_pri ? hdlp->ih_pri : 0; 95725cf1a30Sjl139090 break; 95825cf1a30Sjl139090 case DDI_INTROP_SETPRI: 95925cf1a30Sjl139090 break; 96025cf1a30Sjl139090 case DDI_INTROP_ADDISR: 96125cf1a30Sjl139090 ret = pcmu_add_intr(dip, rdip, hdlp); 96225cf1a30Sjl139090 break; 96325cf1a30Sjl139090 case DDI_INTROP_REMISR: 96425cf1a30Sjl139090 ret = pcmu_remove_intr(dip, rdip, hdlp); 96525cf1a30Sjl139090 break; 96625cf1a30Sjl139090 case DDI_INTROP_ENABLE: 96725cf1a30Sjl139090 ret = pcmu_ib_update_intr_state(pcmu_p, rdip, hdlp, 96825cf1a30Sjl139090 PCMU_INTR_STATE_ENABLE); 96925cf1a30Sjl139090 break; 97025cf1a30Sjl139090 case DDI_INTROP_DISABLE: 97125cf1a30Sjl139090 ret = pcmu_ib_update_intr_state(pcmu_p, rdip, hdlp, 97225cf1a30Sjl139090 PCMU_INTR_STATE_DISABLE); 97325cf1a30Sjl139090 break; 97425cf1a30Sjl139090 case DDI_INTROP_SETMASK: 97525cf1a30Sjl139090 ret = pci_intx_set_mask(rdip); 97625cf1a30Sjl139090 break; 97725cf1a30Sjl139090 case DDI_INTROP_CLRMASK: 97825cf1a30Sjl139090 ret = pci_intx_clr_mask(rdip); 97925cf1a30Sjl139090 break; 98025cf1a30Sjl139090 case DDI_INTROP_GETPENDING: 98125cf1a30Sjl139090 ret = pci_intx_get_pending(rdip, (int *)result); 98225cf1a30Sjl139090 break; 98325cf1a30Sjl139090 case DDI_INTROP_NINTRS: 98425cf1a30Sjl139090 case DDI_INTROP_NAVAIL: 985a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip); 98625cf1a30Sjl139090 break; 98725cf1a30Sjl139090 case DDI_INTROP_SUPPORTED_TYPES: 98825cf1a30Sjl139090 /* PCI nexus driver supports only fixed interrupts */ 989a54f81fbSanish *(int *)result = i_ddi_get_intx_nintrs(rdip) ? 99025cf1a30Sjl139090 DDI_INTR_TYPE_FIXED : 0; 99125cf1a30Sjl139090 break; 99225cf1a30Sjl139090 default: 99325cf1a30Sjl139090 ret = DDI_ENOTSUP; 99425cf1a30Sjl139090 break; 99525cf1a30Sjl139090 } 99625cf1a30Sjl139090 99725cf1a30Sjl139090 return (ret); 99825cf1a30Sjl139090 } 99925cf1a30Sjl139090 100025cf1a30Sjl139090 /* 100125cf1a30Sjl139090 * CMU-CH specifics implementation: 100225cf1a30Sjl139090 * interrupt mapping register 100325cf1a30Sjl139090 * PBM configuration 100425cf1a30Sjl139090 * ECC and PBM error handling 100525cf1a30Sjl139090 */ 100625cf1a30Sjl139090 100725cf1a30Sjl139090 /* called by pcmu_attach() DDI_ATTACH to initialize pci objects */ 100825cf1a30Sjl139090 static int 100925cf1a30Sjl139090 pcmu_obj_setup(pcmu_t *pcmu_p) 101025cf1a30Sjl139090 { 101125cf1a30Sjl139090 int ret; 101225cf1a30Sjl139090 101325cf1a30Sjl139090 mutex_enter(&pcmu_global_mutex); 101425cf1a30Sjl139090 pcmu_p->pcmu_rev = ddi_prop_get_int(DDI_DEV_T_ANY, pcmu_p->pcmu_dip, 101525cf1a30Sjl139090 DDI_PROP_DONTPASS, "module-revision#", 0); 101625cf1a30Sjl139090 101725cf1a30Sjl139090 pcmu_ib_create(pcmu_p); 101825cf1a30Sjl139090 pcmu_cb_create(pcmu_p); 101925cf1a30Sjl139090 pcmu_ecc_create(pcmu_p); 102025cf1a30Sjl139090 pcmu_pbm_create(pcmu_p); 102125cf1a30Sjl139090 pcmu_err_create(pcmu_p); 102225cf1a30Sjl139090 if ((ret = pcmu_intr_setup(pcmu_p)) != DDI_SUCCESS) 102325cf1a30Sjl139090 goto done; 102425cf1a30Sjl139090 1025c9b6d37cSfherard /* 1026c9b6d37cSfherard * Due to a hardware bug, do not create kstat for DC systems 1027c9b6d37cSfherard * with PCI hw revision less than 5. 1028c9b6d37cSfherard */ 1029c9b6d37cSfherard if ((strncmp(ddi_binding_name(pcmu_p->pcmu_dip), 1030c9b6d37cSfherard PCICMU_OPL_DC_BINDING_NAME, strlen(PCICMU_OPL_DC_BINDING_NAME)) 1031c9b6d37cSfherard != 0) || (pcmu_p->pcmu_rev > 4)) { 103225cf1a30Sjl139090 pcmu_kstat_create(pcmu_p); 1033c9b6d37cSfherard } 103425cf1a30Sjl139090 done: 103525cf1a30Sjl139090 mutex_exit(&pcmu_global_mutex); 103625cf1a30Sjl139090 if (ret != DDI_SUCCESS) { 103725cf1a30Sjl139090 cmn_err(CE_NOTE, "Interrupt register failure, returning 0x%x\n", 103825cf1a30Sjl139090 ret); 103925cf1a30Sjl139090 } 104025cf1a30Sjl139090 return (ret); 104125cf1a30Sjl139090 } 104225cf1a30Sjl139090 104325cf1a30Sjl139090 /* called by pcmu_detach() DDI_DETACH to destroy pci objects */ 104425cf1a30Sjl139090 static void 104525cf1a30Sjl139090 pcmu_obj_destroy(pcmu_t *pcmu_p) 104625cf1a30Sjl139090 { 104725cf1a30Sjl139090 mutex_enter(&pcmu_global_mutex); 104825cf1a30Sjl139090 104925cf1a30Sjl139090 pcmu_kstat_destroy(pcmu_p); 105025cf1a30Sjl139090 pcmu_pbm_destroy(pcmu_p); 105125cf1a30Sjl139090 pcmu_err_destroy(pcmu_p); 105225cf1a30Sjl139090 pcmu_ecc_destroy(pcmu_p); 105325cf1a30Sjl139090 pcmu_cb_destroy(pcmu_p); 105425cf1a30Sjl139090 pcmu_ib_destroy(pcmu_p); 105525cf1a30Sjl139090 pcmu_intr_teardown(pcmu_p); 105625cf1a30Sjl139090 105725cf1a30Sjl139090 mutex_exit(&pcmu_global_mutex); 105825cf1a30Sjl139090 } 105925cf1a30Sjl139090 106025cf1a30Sjl139090 /* called by pcmu_attach() DDI_RESUME to (re)initialize pci objects */ 106125cf1a30Sjl139090 static void 106225cf1a30Sjl139090 pcmu_obj_resume(pcmu_t *pcmu_p) 106325cf1a30Sjl139090 { 106425cf1a30Sjl139090 mutex_enter(&pcmu_global_mutex); 106525cf1a30Sjl139090 106625cf1a30Sjl139090 pcmu_ib_configure(pcmu_p->pcmu_ib_p); 106725cf1a30Sjl139090 pcmu_ecc_configure(pcmu_p); 106825cf1a30Sjl139090 pcmu_ib_resume(pcmu_p->pcmu_ib_p); 106925cf1a30Sjl139090 u2u_ittrans_resume((u2u_ittrans_data_t **) 107025cf1a30Sjl139090 &(pcmu_p->pcmu_cb_p->pcb_ittrans_cookie)); 107125cf1a30Sjl139090 107225cf1a30Sjl139090 pcmu_pbm_configure(pcmu_p->pcmu_pcbm_p); 107325cf1a30Sjl139090 107425cf1a30Sjl139090 pcmu_cb_resume(pcmu_p->pcmu_cb_p); 107525cf1a30Sjl139090 107625cf1a30Sjl139090 pcmu_pbm_resume(pcmu_p->pcmu_pcbm_p); 107725cf1a30Sjl139090 107825cf1a30Sjl139090 mutex_exit(&pcmu_global_mutex); 107925cf1a30Sjl139090 } 108025cf1a30Sjl139090 108125cf1a30Sjl139090 /* called by pcmu_detach() DDI_SUSPEND to suspend pci objects */ 108225cf1a30Sjl139090 static void 108325cf1a30Sjl139090 pcmu_obj_suspend(pcmu_t *pcmu_p) 108425cf1a30Sjl139090 { 108525cf1a30Sjl139090 mutex_enter(&pcmu_global_mutex); 108625cf1a30Sjl139090 108725cf1a30Sjl139090 pcmu_pbm_suspend(pcmu_p->pcmu_pcbm_p); 108825cf1a30Sjl139090 pcmu_ib_suspend(pcmu_p->pcmu_ib_p); 108925cf1a30Sjl139090 pcmu_cb_suspend(pcmu_p->pcmu_cb_p); 109025cf1a30Sjl139090 109125cf1a30Sjl139090 mutex_exit(&pcmu_global_mutex); 109225cf1a30Sjl139090 } 109325cf1a30Sjl139090 109425cf1a30Sjl139090 static int 109525cf1a30Sjl139090 pcmu_intr_setup(pcmu_t *pcmu_p) 109625cf1a30Sjl139090 { 109725cf1a30Sjl139090 dev_info_t *dip = pcmu_p->pcmu_dip; 109825cf1a30Sjl139090 pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 109925cf1a30Sjl139090 pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; 110025cf1a30Sjl139090 int i, no_of_intrs; 110125cf1a30Sjl139090 110225cf1a30Sjl139090 /* 110325cf1a30Sjl139090 * Get the interrupts property. 110425cf1a30Sjl139090 */ 110525cf1a30Sjl139090 if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 110625cf1a30Sjl139090 "interrupts", (caddr_t)&pcmu_p->pcmu_inos, 110725cf1a30Sjl139090 &pcmu_p->pcmu_inos_len) != DDI_SUCCESS) { 110825cf1a30Sjl139090 cmn_err(CE_PANIC, "%s%d: no interrupts property\n", 110925cf1a30Sjl139090 ddi_driver_name(dip), ddi_get_instance(dip)); 111025cf1a30Sjl139090 } 111125cf1a30Sjl139090 111225cf1a30Sjl139090 /* 111325cf1a30Sjl139090 * figure out number of interrupts in the "interrupts" property 111425cf1a30Sjl139090 * and convert them all into ino. 111525cf1a30Sjl139090 */ 111625cf1a30Sjl139090 i = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "#interrupt-cells", 1); 111725cf1a30Sjl139090 i = CELLS_1275_TO_BYTES(i); 111825cf1a30Sjl139090 no_of_intrs = pcmu_p->pcmu_inos_len / i; 111925cf1a30Sjl139090 for (i = 0; i < no_of_intrs; i++) { 112025cf1a30Sjl139090 pcmu_p->pcmu_inos[i] = 112125cf1a30Sjl139090 PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[i]); 112225cf1a30Sjl139090 } 112325cf1a30Sjl139090 112425cf1a30Sjl139090 pcb_p->pcb_no_of_inos = no_of_intrs; 112525cf1a30Sjl139090 if (i = pcmu_ecc_register_intr(pcmu_p)) { 112625cf1a30Sjl139090 goto teardown; 112725cf1a30Sjl139090 } 112825cf1a30Sjl139090 112925cf1a30Sjl139090 intr_dist_add(pcmu_cb_intr_dist, pcb_p); 113025cf1a30Sjl139090 pcmu_ecc_enable_intr(pcmu_p); 113125cf1a30Sjl139090 113225cf1a30Sjl139090 if (i = pcmu_pbm_register_intr(pcbm_p)) { 113325cf1a30Sjl139090 intr_dist_rem(pcmu_cb_intr_dist, pcb_p); 113425cf1a30Sjl139090 goto teardown; 113525cf1a30Sjl139090 } 113625cf1a30Sjl139090 intr_dist_add(pcmu_pbm_intr_dist, pcbm_p); 113725cf1a30Sjl139090 pcmu_ib_intr_enable(pcmu_p, pcmu_p->pcmu_inos[CBNINTR_PBM]); 113825cf1a30Sjl139090 113925cf1a30Sjl139090 intr_dist_add_weighted(pcmu_ib_intr_dist_all, pcmu_p->pcmu_ib_p); 114025cf1a30Sjl139090 return (DDI_SUCCESS); 114125cf1a30Sjl139090 teardown: 114225cf1a30Sjl139090 pcmu_intr_teardown(pcmu_p); 114325cf1a30Sjl139090 return (i); 114425cf1a30Sjl139090 } 114525cf1a30Sjl139090 114625cf1a30Sjl139090 /* 114725cf1a30Sjl139090 * pcmu_fix_ranges - fixes the config space entry of the "ranges" 114825cf1a30Sjl139090 * property on CMU-CH platforms 114925cf1a30Sjl139090 */ 115025cf1a30Sjl139090 void 115125cf1a30Sjl139090 pcmu_fix_ranges(pcmu_ranges_t *rng_p, int rng_entries) 115225cf1a30Sjl139090 { 115325cf1a30Sjl139090 int i; 115425cf1a30Sjl139090 for (i = 0; i < rng_entries; i++, rng_p++) { 115525cf1a30Sjl139090 if ((rng_p->child_high & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) 115625cf1a30Sjl139090 rng_p->parent_low |= rng_p->child_high; 115725cf1a30Sjl139090 } 115825cf1a30Sjl139090 } 115925cf1a30Sjl139090 116025cf1a30Sjl139090 /* 116125cf1a30Sjl139090 * map_pcmu_registers 116225cf1a30Sjl139090 * 116325cf1a30Sjl139090 * This function is called from the attach routine to map the registers 116425cf1a30Sjl139090 * accessed by this driver. 116525cf1a30Sjl139090 * 116625cf1a30Sjl139090 * used by: pcmu_attach() 116725cf1a30Sjl139090 * 116825cf1a30Sjl139090 * return value: DDI_FAILURE on failure 116925cf1a30Sjl139090 */ 117025cf1a30Sjl139090 static int 117125cf1a30Sjl139090 map_pcmu_registers(pcmu_t *pcmu_p, dev_info_t *dip) 117225cf1a30Sjl139090 { 117325cf1a30Sjl139090 ddi_device_acc_attr_t attr; 117425cf1a30Sjl139090 117525cf1a30Sjl139090 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 117625cf1a30Sjl139090 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 117725cf1a30Sjl139090 117825cf1a30Sjl139090 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 117925cf1a30Sjl139090 if (ddi_regs_map_setup(dip, 0, &pcmu_p->pcmu_address[0], 0, 0, 118025cf1a30Sjl139090 &attr, &pcmu_p->pcmu_ac[0]) != DDI_SUCCESS) { 118125cf1a30Sjl139090 cmn_err(CE_WARN, "%s%d: unable to map reg entry 0\n", 118225cf1a30Sjl139090 ddi_driver_name(dip), ddi_get_instance(dip)); 118325cf1a30Sjl139090 return (DDI_FAILURE); 118425cf1a30Sjl139090 } 118525cf1a30Sjl139090 118625cf1a30Sjl139090 /* 118725cf1a30Sjl139090 * We still use pcmu_address[2] 118825cf1a30Sjl139090 */ 118925cf1a30Sjl139090 if (ddi_regs_map_setup(dip, 2, &pcmu_p->pcmu_address[2], 0, 0, 119025cf1a30Sjl139090 &attr, &pcmu_p->pcmu_ac[2]) != DDI_SUCCESS) { 119125cf1a30Sjl139090 cmn_err(CE_WARN, "%s%d: unable to map reg entry 2\n", 119225cf1a30Sjl139090 ddi_driver_name(dip), ddi_get_instance(dip)); 119325cf1a30Sjl139090 ddi_regs_map_free(&pcmu_p->pcmu_ac[0]); 119425cf1a30Sjl139090 return (DDI_FAILURE); 119525cf1a30Sjl139090 } 119625cf1a30Sjl139090 119725cf1a30Sjl139090 /* 119825cf1a30Sjl139090 * The second register set contains the bridge's configuration 119925cf1a30Sjl139090 * header. This header is at the very beginning of the bridge's 120025cf1a30Sjl139090 * configuration space. This space has litte-endian byte order. 120125cf1a30Sjl139090 */ 120225cf1a30Sjl139090 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 120325cf1a30Sjl139090 if (ddi_regs_map_setup(dip, 1, &pcmu_p->pcmu_address[1], 0, 120425cf1a30Sjl139090 PCI_CONF_HDR_SIZE, &attr, &pcmu_p->pcmu_ac[1]) != DDI_SUCCESS) { 120525cf1a30Sjl139090 120625cf1a30Sjl139090 cmn_err(CE_WARN, "%s%d: unable to map reg entry 1\n", 120725cf1a30Sjl139090 ddi_driver_name(dip), ddi_get_instance(dip)); 120825cf1a30Sjl139090 ddi_regs_map_free(&pcmu_p->pcmu_ac[0]); 120925cf1a30Sjl139090 return (DDI_FAILURE); 121025cf1a30Sjl139090 } 121125cf1a30Sjl139090 PCMU_DBG2(PCMU_DBG_ATTACH, dip, "address (%p,%p)\n", 121225cf1a30Sjl139090 pcmu_p->pcmu_address[0], pcmu_p->pcmu_address[1]); 121325cf1a30Sjl139090 return (DDI_SUCCESS); 121425cf1a30Sjl139090 } 121525cf1a30Sjl139090 121625cf1a30Sjl139090 /* 121725cf1a30Sjl139090 * unmap_pcmu_registers: 121825cf1a30Sjl139090 * 121925cf1a30Sjl139090 * This routine unmap the registers mapped by map_pcmu_registers. 122025cf1a30Sjl139090 * 122125cf1a30Sjl139090 * used by: pcmu_detach() 122225cf1a30Sjl139090 * 122325cf1a30Sjl139090 * return value: none 122425cf1a30Sjl139090 */ 122525cf1a30Sjl139090 static void 122625cf1a30Sjl139090 unmap_pcmu_registers(pcmu_t *pcmu_p) 122725cf1a30Sjl139090 { 122825cf1a30Sjl139090 ddi_regs_map_free(&pcmu_p->pcmu_ac[0]); 122925cf1a30Sjl139090 ddi_regs_map_free(&pcmu_p->pcmu_ac[1]); 123025cf1a30Sjl139090 ddi_regs_map_free(&pcmu_p->pcmu_ac[2]); 123125cf1a30Sjl139090 } 123225cf1a30Sjl139090 123325cf1a30Sjl139090 /* 123425cf1a30Sjl139090 * These convenience wrappers relies on map_pcmu_registers() to setup 123525cf1a30Sjl139090 * pcmu_address[0-2] correctly at first. 123625cf1a30Sjl139090 */ 123725cf1a30Sjl139090 static uintptr_t 123825cf1a30Sjl139090 get_reg_base(pcmu_t *pcmu_p) 123925cf1a30Sjl139090 { 124025cf1a30Sjl139090 return ((uintptr_t)pcmu_p->pcmu_address[2]); 124125cf1a30Sjl139090 } 124225cf1a30Sjl139090 124325cf1a30Sjl139090 /* The CMU-CH config reg base is always the 2nd reg entry */ 124425cf1a30Sjl139090 static uintptr_t 124525cf1a30Sjl139090 get_config_reg_base(pcmu_t *pcmu_p) 124625cf1a30Sjl139090 { 124725cf1a30Sjl139090 return ((uintptr_t)(pcmu_p->pcmu_address[1])); 124825cf1a30Sjl139090 } 124925cf1a30Sjl139090 125025cf1a30Sjl139090 uint64_t 125125cf1a30Sjl139090 ib_get_map_reg(pcmu_ib_mondo_t mondo, uint32_t cpu_id) 125225cf1a30Sjl139090 { 125325cf1a30Sjl139090 return ((mondo) | (cpu_id << PCMU_INTR_MAP_REG_TID_SHIFT) | 125425cf1a30Sjl139090 PCMU_INTR_MAP_REG_VALID); 125525cf1a30Sjl139090 125625cf1a30Sjl139090 } 125725cf1a30Sjl139090 125825cf1a30Sjl139090 uint32_t 125925cf1a30Sjl139090 ib_map_reg_get_cpu(volatile uint64_t reg) 126025cf1a30Sjl139090 { 126125cf1a30Sjl139090 return ((reg & PCMU_INTR_MAP_REG_TID) >> 126225cf1a30Sjl139090 PCMU_INTR_MAP_REG_TID_SHIFT); 126325cf1a30Sjl139090 } 126425cf1a30Sjl139090 126525cf1a30Sjl139090 uint64_t * 126625cf1a30Sjl139090 ib_intr_map_reg_addr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino) 126725cf1a30Sjl139090 { 126825cf1a30Sjl139090 uint64_t *addr; 126925cf1a30Sjl139090 127025cf1a30Sjl139090 ASSERT(ino & 0x20); 127125cf1a30Sjl139090 addr = (uint64_t *)(pib_p->pib_obio_intr_map_regs + 127225cf1a30Sjl139090 (((uint_t)ino & 0x1f) << 3)); 127325cf1a30Sjl139090 return (addr); 127425cf1a30Sjl139090 } 127525cf1a30Sjl139090 127625cf1a30Sjl139090 uint64_t * 127725cf1a30Sjl139090 ib_clear_intr_reg_addr(pcmu_ib_t *pib_p, pcmu_ib_ino_t ino) 127825cf1a30Sjl139090 { 127925cf1a30Sjl139090 uint64_t *addr; 128025cf1a30Sjl139090 128125cf1a30Sjl139090 ASSERT(ino & 0x20); 128225cf1a30Sjl139090 addr = (uint64_t *)(pib_p->pib_obio_clear_intr_regs + 128325cf1a30Sjl139090 (((uint_t)ino & 0x1f) << 3)); 128425cf1a30Sjl139090 return (addr); 128525cf1a30Sjl139090 } 128625cf1a30Sjl139090 128725cf1a30Sjl139090 uintptr_t 128825cf1a30Sjl139090 pcmu_ib_setup(pcmu_ib_t *pib_p) 128925cf1a30Sjl139090 { 129025cf1a30Sjl139090 pcmu_t *pcmu_p = pib_p->pib_pcmu_p; 129125cf1a30Sjl139090 uintptr_t a = get_reg_base(pcmu_p); 129225cf1a30Sjl139090 129325cf1a30Sjl139090 pib_p->pib_ign = PCMU_ID_TO_IGN(pcmu_p->pcmu_id); 129425cf1a30Sjl139090 pib_p->pib_max_ino = PCMU_MAX_INO; 129525cf1a30Sjl139090 pib_p->pib_obio_intr_map_regs = a + PCMU_IB_OBIO_INTR_MAP_REG_OFFSET; 129625cf1a30Sjl139090 pib_p->pib_obio_clear_intr_regs = 129725cf1a30Sjl139090 a + PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET; 129825cf1a30Sjl139090 return (a); 129925cf1a30Sjl139090 } 130025cf1a30Sjl139090 130125cf1a30Sjl139090 /* 130225cf1a30Sjl139090 * Return the cpuid to to be used for an ino. 130325cf1a30Sjl139090 * 130425cf1a30Sjl139090 * On multi-function pci devices, functions have separate devinfo nodes and 130525cf1a30Sjl139090 * interrupts. 130625cf1a30Sjl139090 * 130725cf1a30Sjl139090 * This function determines if there is already an established slot-oriented 130825cf1a30Sjl139090 * interrupt-to-cpu binding established, if there is then it returns that 130925cf1a30Sjl139090 * cpu. Otherwise a new cpu is selected by intr_dist_cpuid(). 131025cf1a30Sjl139090 * 131125cf1a30Sjl139090 * The devinfo node we are trying to associate a cpu with is 131225cf1a30Sjl139090 * ino_p->pino_ih_head->ih_dip. 131325cf1a30Sjl139090 */ 131425cf1a30Sjl139090 uint32_t 131525cf1a30Sjl139090 pcmu_intr_dist_cpuid(pcmu_ib_t *pib_p, pcmu_ib_ino_info_t *ino_p) 131625cf1a30Sjl139090 { 131725cf1a30Sjl139090 dev_info_t *rdip = ino_p->pino_ih_head->ih_dip; 131825cf1a30Sjl139090 dev_info_t *prdip = ddi_get_parent(rdip); 131925cf1a30Sjl139090 pcmu_ib_ino_info_t *sino_p; 132025cf1a30Sjl139090 dev_info_t *sdip; 132125cf1a30Sjl139090 dev_info_t *psdip; 132225cf1a30Sjl139090 char *buf1 = NULL, *buf2 = NULL; 132325cf1a30Sjl139090 char *s1, *s2, *s3; 132425cf1a30Sjl139090 int l2; 132525cf1a30Sjl139090 int cpu_id; 132625cf1a30Sjl139090 132725cf1a30Sjl139090 /* must be CMU-CH driver parent (not ebus) */ 132825cf1a30Sjl139090 if (strcmp(ddi_driver_name(prdip), "pcicmu") != 0) 132925cf1a30Sjl139090 goto newcpu; 133025cf1a30Sjl139090 133125cf1a30Sjl139090 /* 133225cf1a30Sjl139090 * From PCI 1275 binding: 2.2.1.3 Unit Address representation: 133325cf1a30Sjl139090 * Since the "unit-number" is the address that appears in on Open 133425cf1a30Sjl139090 * Firmware 'device path', it follows that only the DD and DD,FF 133525cf1a30Sjl139090 * forms of the text representation can appear in a 'device path'. 133625cf1a30Sjl139090 * 133725cf1a30Sjl139090 * The rdip unit address is of the form "DD[,FF]". Define two 133825cf1a30Sjl139090 * unit address strings that represent same-slot use: "DD" and "DD,". 133925cf1a30Sjl139090 * The first compare uses strcmp, the second uses strncmp. 134025cf1a30Sjl139090 */ 134125cf1a30Sjl139090 s1 = ddi_get_name_addr(rdip); 134225cf1a30Sjl139090 if (s1 == NULL) { 134325cf1a30Sjl139090 goto newcpu; 134425cf1a30Sjl139090 } 134525cf1a30Sjl139090 134625cf1a30Sjl139090 buf1 = kmem_alloc(MAXNAMELEN, KM_SLEEP); /* strcmp */ 134725cf1a30Sjl139090 buf2 = kmem_alloc(MAXNAMELEN, KM_SLEEP); /* strncmp */ 134825cf1a30Sjl139090 s1 = strcpy(buf1, s1); 134925cf1a30Sjl139090 s2 = strcpy(buf2, s1); 135025cf1a30Sjl139090 135125cf1a30Sjl139090 s1 = strrchr(s1, ','); 135225cf1a30Sjl139090 if (s1) { 135325cf1a30Sjl139090 *s1 = '\0'; /* have "DD,FF" */ 135425cf1a30Sjl139090 s1 = buf1; /* search via strcmp "DD" */ 135525cf1a30Sjl139090 135625cf1a30Sjl139090 s2 = strrchr(s2, ','); 135725cf1a30Sjl139090 *(s2 + 1) = '\0'; 135825cf1a30Sjl139090 s2 = buf2; 135925cf1a30Sjl139090 l2 = strlen(s2); /* search via strncmp "DD," */ 136025cf1a30Sjl139090 } else { 136125cf1a30Sjl139090 (void) strcat(s2, ","); /* have "DD" */ 136225cf1a30Sjl139090 l2 = strlen(s2); /* search via strncmp "DD," */ 136325cf1a30Sjl139090 } 136425cf1a30Sjl139090 136525cf1a30Sjl139090 /* 136625cf1a30Sjl139090 * Search the established ino list for devinfo nodes bound 136725cf1a30Sjl139090 * to an ino that matches one of the slot use strings. 136825cf1a30Sjl139090 */ 136925cf1a30Sjl139090 ASSERT(MUTEX_HELD(&pib_p->pib_ino_lst_mutex)); 137025cf1a30Sjl139090 for (sino_p = pib_p->pib_ino_lst; sino_p; sino_p = sino_p->pino_next) { 137125cf1a30Sjl139090 /* skip self and non-established */ 137225cf1a30Sjl139090 if ((sino_p == ino_p) || (sino_p->pino_established == 0)) 137325cf1a30Sjl139090 continue; 137425cf1a30Sjl139090 137525cf1a30Sjl139090 /* skip non-siblings */ 137625cf1a30Sjl139090 sdip = sino_p->pino_ih_head->ih_dip; 137725cf1a30Sjl139090 psdip = ddi_get_parent(sdip); 137825cf1a30Sjl139090 if (psdip != prdip) 137925cf1a30Sjl139090 continue; 138025cf1a30Sjl139090 138125cf1a30Sjl139090 /* must be CMU-CH driver parent (not ebus) */ 138225cf1a30Sjl139090 if (strcmp(ddi_driver_name(psdip), "pcicmu") != 0) 138325cf1a30Sjl139090 continue; 138425cf1a30Sjl139090 138525cf1a30Sjl139090 s3 = ddi_get_name_addr(sdip); 138625cf1a30Sjl139090 if ((s1 && (strcmp(s1, s3) == 0)) || 138725cf1a30Sjl139090 (strncmp(s2, s3, l2) == 0)) { 138825cf1a30Sjl139090 extern int intr_dist_debug; 138925cf1a30Sjl139090 139025cf1a30Sjl139090 if (intr_dist_debug) { 139125cf1a30Sjl139090 cmn_err(CE_CONT, "intr_dist: " 139225cf1a30Sjl139090 "pcicmu`pcmu_intr_dist_cpuid " 139325cf1a30Sjl139090 "%s#%d %s: cpu %d established " 139425cf1a30Sjl139090 "by %s#%d %s\n", ddi_driver_name(rdip), 139525cf1a30Sjl139090 ddi_get_instance(rdip), 139625cf1a30Sjl139090 ddi_deviname(rdip, buf1), 139725cf1a30Sjl139090 sino_p->pino_cpuid, 139825cf1a30Sjl139090 ddi_driver_name(sdip), 139925cf1a30Sjl139090 ddi_get_instance(sdip), 140025cf1a30Sjl139090 ddi_deviname(sdip, buf2)); 140125cf1a30Sjl139090 } 140225cf1a30Sjl139090 break; 140325cf1a30Sjl139090 } 140425cf1a30Sjl139090 } 140525cf1a30Sjl139090 140625cf1a30Sjl139090 /* If a slot use match is found then use established cpu */ 140725cf1a30Sjl139090 if (sino_p) { 140825cf1a30Sjl139090 cpu_id = sino_p->pino_cpuid; /* target established cpu */ 140925cf1a30Sjl139090 goto out; 141025cf1a30Sjl139090 } 141125cf1a30Sjl139090 141225cf1a30Sjl139090 newcpu: cpu_id = intr_dist_cpuid(); /* target new cpu */ 141325cf1a30Sjl139090 141425cf1a30Sjl139090 out: if (buf1) 141525cf1a30Sjl139090 kmem_free(buf1, MAXNAMELEN); 141625cf1a30Sjl139090 if (buf2) 141725cf1a30Sjl139090 kmem_free(buf2, MAXNAMELEN); 141825cf1a30Sjl139090 return (cpu_id); 141925cf1a30Sjl139090 } 142025cf1a30Sjl139090 142125cf1a30Sjl139090 void 142225cf1a30Sjl139090 pcmu_cb_teardown(pcmu_t *pcmu_p) 142325cf1a30Sjl139090 { 142425cf1a30Sjl139090 pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; 142525cf1a30Sjl139090 142625cf1a30Sjl139090 u2u_ittrans_uninit((u2u_ittrans_data_t *)pcb_p->pcb_ittrans_cookie); 142725cf1a30Sjl139090 } 142825cf1a30Sjl139090 142925cf1a30Sjl139090 int 143025cf1a30Sjl139090 pcmu_ecc_add_intr(pcmu_t *pcmu_p, int inum, pcmu_ecc_intr_info_t *eii_p) 143125cf1a30Sjl139090 { 143225cf1a30Sjl139090 uint32_t mondo; 143325cf1a30Sjl139090 143425cf1a30Sjl139090 mondo = ((pcmu_p->pcmu_cb_p->pcb_ign << PCMU_INO_BITS) | 143525cf1a30Sjl139090 pcmu_p->pcmu_inos[inum]); 143625cf1a30Sjl139090 1437b0fc0e77Sgovinda VERIFY(add_ivintr(mondo, pcmu_pil[inum], (intrfunc)pcmu_ecc_intr, 1438b0fc0e77Sgovinda (caddr_t)eii_p, NULL, NULL) == 0); 1439b0fc0e77Sgovinda 144025cf1a30Sjl139090 return (PCMU_ATTACH_RETCODE(PCMU_ECC_OBJ, 144125cf1a30Sjl139090 PCMU_OBJ_INTR_ADD, DDI_SUCCESS)); 144225cf1a30Sjl139090 } 144325cf1a30Sjl139090 144425cf1a30Sjl139090 /* ARGSUSED */ 144525cf1a30Sjl139090 void 144625cf1a30Sjl139090 pcmu_ecc_rem_intr(pcmu_t *pcmu_p, int inum, pcmu_ecc_intr_info_t *eii_p) 144725cf1a30Sjl139090 { 144825cf1a30Sjl139090 uint32_t mondo; 144925cf1a30Sjl139090 145025cf1a30Sjl139090 mondo = ((pcmu_p->pcmu_cb_p->pcb_ign << PCMU_INO_BITS) | 145125cf1a30Sjl139090 pcmu_p->pcmu_inos[inum]); 1452b0fc0e77Sgovinda 1453b0fc0e77Sgovinda VERIFY(rem_ivintr(mondo, pcmu_pil[inum]) == 0); 145425cf1a30Sjl139090 } 145525cf1a30Sjl139090 145625cf1a30Sjl139090 void 145725cf1a30Sjl139090 pcmu_pbm_configure(pcmu_pbm_t *pcbm_p) 145825cf1a30Sjl139090 { 145925cf1a30Sjl139090 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 146025cf1a30Sjl139090 dev_info_t *dip = pcmu_p->pcmu_dip; 146125cf1a30Sjl139090 146225cf1a30Sjl139090 #define pbm_err ((PCMU_PCI_AFSR_E_MASK << PCMU_PCI_AFSR_PE_SHIFT) | \ 146325cf1a30Sjl139090 (PCMU_PCI_AFSR_E_MASK << PCMU_PCI_AFSR_SE_SHIFT)) 146425cf1a30Sjl139090 #define csr_err (PCI_STAT_PERROR | PCI_STAT_S_PERROR | \ 146525cf1a30Sjl139090 PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB | \ 146625cf1a30Sjl139090 PCI_STAT_S_TARG_AB | PCI_STAT_S_PERROR) 146725cf1a30Sjl139090 146825cf1a30Sjl139090 /* 146925cf1a30Sjl139090 * Clear any PBM errors. 147025cf1a30Sjl139090 */ 147125cf1a30Sjl139090 *pcbm_p->pcbm_async_flt_status_reg = pbm_err; 147225cf1a30Sjl139090 147325cf1a30Sjl139090 /* 147425cf1a30Sjl139090 * Clear error bits in configuration status register. 147525cf1a30Sjl139090 */ 147625cf1a30Sjl139090 PCMU_DBG1(PCMU_DBG_ATTACH, dip, 147725cf1a30Sjl139090 "pcmu_pbm_configure: conf status reg=%x\n", csr_err); 147825cf1a30Sjl139090 147925cf1a30Sjl139090 pcbm_p->pcbm_config_header->ch_status_reg = csr_err; 148025cf1a30Sjl139090 148125cf1a30Sjl139090 PCMU_DBG1(PCMU_DBG_ATTACH, dip, 148225cf1a30Sjl139090 "pcmu_pbm_configure: conf status reg==%x\n", 148325cf1a30Sjl139090 pcbm_p->pcbm_config_header->ch_status_reg); 148425cf1a30Sjl139090 148525cf1a30Sjl139090 (void) ndi_prop_update_int(DDI_DEV_T_ANY, dip, "latency-timer", 148625cf1a30Sjl139090 (int)pcbm_p->pcbm_config_header->ch_latency_timer_reg); 148725cf1a30Sjl139090 #undef pbm_err 148825cf1a30Sjl139090 #undef csr_err 148925cf1a30Sjl139090 } 149025cf1a30Sjl139090 149125cf1a30Sjl139090 uint_t 149225cf1a30Sjl139090 pcmu_pbm_disable_errors(pcmu_pbm_t *pcbm_p) 149325cf1a30Sjl139090 { 149425cf1a30Sjl139090 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 149525cf1a30Sjl139090 pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p; 149625cf1a30Sjl139090 149725cf1a30Sjl139090 /* 149825cf1a30Sjl139090 * Disable error and streaming byte hole interrupts via the 149925cf1a30Sjl139090 * PBM control register. 150025cf1a30Sjl139090 */ 150125cf1a30Sjl139090 *pcbm_p->pcbm_ctrl_reg &= ~PCMU_PCI_CTRL_ERR_INT_EN; 150225cf1a30Sjl139090 150325cf1a30Sjl139090 /* 150425cf1a30Sjl139090 * Disable error interrupts via the interrupt mapping register. 150525cf1a30Sjl139090 */ 150625cf1a30Sjl139090 pcmu_ib_intr_disable(pib_p, 150725cf1a30Sjl139090 pcmu_p->pcmu_inos[CBNINTR_PBM], PCMU_IB_INTR_NOWAIT); 150825cf1a30Sjl139090 return (BF_NONE); 150925cf1a30Sjl139090 } 151025cf1a30Sjl139090 151125cf1a30Sjl139090 void 151225cf1a30Sjl139090 pcmu_cb_setup(pcmu_t *pcmu_p) 151325cf1a30Sjl139090 { 151425cf1a30Sjl139090 uint64_t csr, csr_pa, pa; 151525cf1a30Sjl139090 pcmu_cb_t *pcb_p = pcmu_p->pcmu_cb_p; 151625cf1a30Sjl139090 151725cf1a30Sjl139090 pcb_p->pcb_ign = PCMU_ID_TO_IGN(pcmu_p->pcmu_id); 151825cf1a30Sjl139090 pa = (uint64_t)hat_getpfnum(kas.a_hat, pcmu_p->pcmu_address[0]); 151925cf1a30Sjl139090 pcb_p->pcb_base_pa = pa = pa >> (32 - MMU_PAGESHIFT) << 32; 152025cf1a30Sjl139090 pcb_p->pcb_map_pa = pa + PCMU_IB_OBIO_INTR_MAP_REG_OFFSET; 152125cf1a30Sjl139090 pcb_p->pcb_clr_pa = pa + PCMU_IB_OBIO_CLEAR_INTR_REG_OFFSET; 152225cf1a30Sjl139090 pcb_p->pcb_obsta_pa = pa + PCMU_IB_OBIO_INTR_STATE_DIAG_REG; 152325cf1a30Sjl139090 152425cf1a30Sjl139090 csr_pa = pa + PCMU_CB_CONTROL_STATUS_REG_OFFSET; 152525cf1a30Sjl139090 csr = lddphysio(csr_pa); 152625cf1a30Sjl139090 152725cf1a30Sjl139090 /* 152825cf1a30Sjl139090 * Clear any pending address parity errors. 152925cf1a30Sjl139090 */ 153025cf1a30Sjl139090 if (csr & PCMU_CB_CONTROL_STATUS_APERR) { 153125cf1a30Sjl139090 csr |= PCMU_CB_CONTROL_STATUS_APERR; 153225cf1a30Sjl139090 cmn_err(CE_WARN, "clearing UPA address parity error\n"); 153325cf1a30Sjl139090 } 153425cf1a30Sjl139090 csr |= PCMU_CB_CONTROL_STATUS_APCKEN; 153525cf1a30Sjl139090 csr &= ~PCMU_CB_CONTROL_STATUS_IAP; 153625cf1a30Sjl139090 stdphysio(csr_pa, csr); 153725cf1a30Sjl139090 153825cf1a30Sjl139090 u2u_ittrans_init(pcmu_p, 153925cf1a30Sjl139090 (u2u_ittrans_data_t **)&pcb_p->pcb_ittrans_cookie); 154025cf1a30Sjl139090 } 154125cf1a30Sjl139090 154225cf1a30Sjl139090 void 154325cf1a30Sjl139090 pcmu_ecc_setup(pcmu_ecc_t *pecc_p) 154425cf1a30Sjl139090 { 154525cf1a30Sjl139090 pecc_p->pecc_ue.pecc_errpndg_mask = 0; 154625cf1a30Sjl139090 pecc_p->pecc_ue.pecc_offset_mask = PCMU_ECC_UE_AFSR_DW_OFFSET; 154725cf1a30Sjl139090 pecc_p->pecc_ue.pecc_offset_shift = PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT; 154825cf1a30Sjl139090 pecc_p->pecc_ue.pecc_size_log2 = 3; 154925cf1a30Sjl139090 } 155025cf1a30Sjl139090 155125cf1a30Sjl139090 static uintptr_t 155225cf1a30Sjl139090 get_pbm_reg_base(pcmu_t *pcmu_p) 155325cf1a30Sjl139090 { 155425cf1a30Sjl139090 return ((uintptr_t)(pcmu_p->pcmu_address[0])); 155525cf1a30Sjl139090 } 155625cf1a30Sjl139090 155725cf1a30Sjl139090 void 155825cf1a30Sjl139090 pcmu_pbm_setup(pcmu_pbm_t *pcbm_p) 155925cf1a30Sjl139090 { 156025cf1a30Sjl139090 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p; 156125cf1a30Sjl139090 156225cf1a30Sjl139090 /* 156325cf1a30Sjl139090 * Get the base virtual address for the PBM control block. 156425cf1a30Sjl139090 */ 156525cf1a30Sjl139090 uintptr_t a = get_pbm_reg_base(pcmu_p); 156625cf1a30Sjl139090 156725cf1a30Sjl139090 /* 156825cf1a30Sjl139090 * Get the virtual address of the PCI configuration header. 156925cf1a30Sjl139090 * This should be mapped little-endian. 157025cf1a30Sjl139090 */ 157125cf1a30Sjl139090 pcbm_p->pcbm_config_header = 157225cf1a30Sjl139090 (config_header_t *)get_config_reg_base(pcmu_p); 157325cf1a30Sjl139090 157425cf1a30Sjl139090 /* 157525cf1a30Sjl139090 * Get the virtual addresses for control, error and diag 157625cf1a30Sjl139090 * registers. 157725cf1a30Sjl139090 */ 157825cf1a30Sjl139090 pcbm_p->pcbm_ctrl_reg = (uint64_t *)(a + PCMU_PCI_CTRL_REG_OFFSET); 157925cf1a30Sjl139090 pcbm_p->pcbm_diag_reg = (uint64_t *)(a + PCMU_PCI_DIAG_REG_OFFSET); 158025cf1a30Sjl139090 pcbm_p->pcbm_async_flt_status_reg = 158125cf1a30Sjl139090 (uint64_t *)(a + PCMU_PCI_ASYNC_FLT_STATUS_REG_OFFSET); 158225cf1a30Sjl139090 pcbm_p->pcbm_async_flt_addr_reg = 158325cf1a30Sjl139090 (uint64_t *)(a + PCMU_PCI_ASYNC_FLT_ADDR_REG_OFFSET); 158425cf1a30Sjl139090 } 158525cf1a30Sjl139090 158625cf1a30Sjl139090 /*ARGSUSED*/ 158725cf1a30Sjl139090 void 158825cf1a30Sjl139090 pcmu_pbm_teardown(pcmu_pbm_t *pcbm_p) 158925cf1a30Sjl139090 { 159025cf1a30Sjl139090 } 159125cf1a30Sjl139090 159225cf1a30Sjl139090 int 159325cf1a30Sjl139090 pcmu_get_numproxy(dev_info_t *dip) 159425cf1a30Sjl139090 { 159525cf1a30Sjl139090 return (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 159625cf1a30Sjl139090 "#upa-interrupt-proxies", 1)); 159725cf1a30Sjl139090 } 159825cf1a30Sjl139090 159925cf1a30Sjl139090 int 160025cf1a30Sjl139090 pcmu_get_portid(dev_info_t *dip) 160125cf1a30Sjl139090 { 160225cf1a30Sjl139090 return (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 160325cf1a30Sjl139090 "portid", -1)); 160425cf1a30Sjl139090 } 160525cf1a30Sjl139090 160625cf1a30Sjl139090 /* 160725cf1a30Sjl139090 * CMU-CH Performance Events. 160825cf1a30Sjl139090 */ 160925cf1a30Sjl139090 static pcmu_kev_mask_t 161025cf1a30Sjl139090 pcicmu_pcmu_events[] = { 161125cf1a30Sjl139090 {"pio_cycles_b", 0xf}, {"interrupts", 0x11}, 161225cf1a30Sjl139090 {"upa_inter_nack", 0x12}, {"pio_reads", 0x13}, 161325cf1a30Sjl139090 {"pio_writes", 0x14}, 161425cf1a30Sjl139090 {"clear_pic", 0x1f} 161525cf1a30Sjl139090 }; 161625cf1a30Sjl139090 161725cf1a30Sjl139090 /* 161825cf1a30Sjl139090 * Create the picN kstat's. 161925cf1a30Sjl139090 */ 162025cf1a30Sjl139090 void 162125cf1a30Sjl139090 pcmu_kstat_init() 162225cf1a30Sjl139090 { 162325cf1a30Sjl139090 pcmu_name_kstat = (pcmu_ksinfo_t *)kmem_alloc(sizeof (pcmu_ksinfo_t), 162425cf1a30Sjl139090 KM_NOSLEEP); 162525cf1a30Sjl139090 162625cf1a30Sjl139090 if (pcmu_name_kstat == NULL) { 162725cf1a30Sjl139090 cmn_err(CE_WARN, "pcicmu : no space for kstat\n"); 162825cf1a30Sjl139090 } else { 162925cf1a30Sjl139090 pcmu_name_kstat->pic_no_evs = 163025cf1a30Sjl139090 sizeof (pcicmu_pcmu_events) / sizeof (pcmu_kev_mask_t); 163125cf1a30Sjl139090 pcmu_name_kstat->pic_shift[0] = PCMU_SHIFT_PIC0; 163225cf1a30Sjl139090 pcmu_name_kstat->pic_shift[1] = PCMU_SHIFT_PIC1; 163325cf1a30Sjl139090 pcmu_create_name_kstat("pcmup", 163425cf1a30Sjl139090 pcmu_name_kstat, pcicmu_pcmu_events); 163525cf1a30Sjl139090 } 163625cf1a30Sjl139090 } 163725cf1a30Sjl139090 163825cf1a30Sjl139090 /* 163925cf1a30Sjl139090 * Called from _fini() 164025cf1a30Sjl139090 */ 164125cf1a30Sjl139090 void 164225cf1a30Sjl139090 pcmu_kstat_fini() 164325cf1a30Sjl139090 { 164425cf1a30Sjl139090 if (pcmu_name_kstat != NULL) { 164525cf1a30Sjl139090 pcmu_delete_name_kstat(pcmu_name_kstat); 164625cf1a30Sjl139090 kmem_free(pcmu_name_kstat, sizeof (pcmu_ksinfo_t)); 164725cf1a30Sjl139090 pcmu_name_kstat = NULL; 164825cf1a30Sjl139090 } 164925cf1a30Sjl139090 } 165025cf1a30Sjl139090 165125cf1a30Sjl139090 /* 165225cf1a30Sjl139090 * Create the performance 'counters' kstat. 165325cf1a30Sjl139090 */ 165425cf1a30Sjl139090 void 165525cf1a30Sjl139090 pcmu_add_upstream_kstat(pcmu_t *pcmu_p) 165625cf1a30Sjl139090 { 165725cf1a30Sjl139090 pcmu_cntr_pa_t *cntr_pa_p = &pcmu_p->pcmu_uks_pa; 165825cf1a30Sjl139090 uint64_t regbase = va_to_pa((void *)get_reg_base(pcmu_p)); 165925cf1a30Sjl139090 166025cf1a30Sjl139090 cntr_pa_p->pcr_pa = regbase + PCMU_PERF_PCR_OFFSET; 166125cf1a30Sjl139090 cntr_pa_p->pic_pa = regbase + PCMU_PERF_PIC_OFFSET; 166225cf1a30Sjl139090 pcmu_p->pcmu_uksp = pcmu_create_cntr_kstat(pcmu_p, "pcmup", 166325cf1a30Sjl139090 NUM_OF_PICS, pcmu_cntr_kstat_pa_update, cntr_pa_p); 166425cf1a30Sjl139090 } 166525cf1a30Sjl139090 166625cf1a30Sjl139090 /* 166725cf1a30Sjl139090 * u2u_ittrans_init() is caled from in pci.c's pcmu_cb_setup() per CMU. 166825cf1a30Sjl139090 * Second argument "ittrans_cookie" is address of pcb_ittrans_cookie in 166925cf1a30Sjl139090 * pcb_p member. allocated interrupt block is returned in it. 167025cf1a30Sjl139090 */ 167125cf1a30Sjl139090 static void 167225cf1a30Sjl139090 u2u_ittrans_init(pcmu_t *pcmu_p, u2u_ittrans_data_t **ittrans_cookie) 167325cf1a30Sjl139090 { 167425cf1a30Sjl139090 167525cf1a30Sjl139090 u2u_ittrans_data_t *u2u_trans_p; 167625cf1a30Sjl139090 ddi_device_acc_attr_t attr; 167725cf1a30Sjl139090 int ret; 167825cf1a30Sjl139090 int board; 167925cf1a30Sjl139090 168025cf1a30Sjl139090 /* 168125cf1a30Sjl139090 * Allocate the data structure to support U2U's 168225cf1a30Sjl139090 * interrupt target translations. 168325cf1a30Sjl139090 */ 168425cf1a30Sjl139090 u2u_trans_p = (u2u_ittrans_data_t *) 168525cf1a30Sjl139090 kmem_zalloc(sizeof (u2u_ittrans_data_t), KM_SLEEP); 168625cf1a30Sjl139090 168725cf1a30Sjl139090 /* 168825cf1a30Sjl139090 * Get other properties, "board#" 168925cf1a30Sjl139090 */ 169025cf1a30Sjl139090 board = ddi_getprop(DDI_DEV_T_ANY, pcmu_p->pcmu_dip, 169125cf1a30Sjl139090 DDI_PROP_DONTPASS, "board#", -1); 169225cf1a30Sjl139090 169325cf1a30Sjl139090 u2u_trans_p->u2u_board = board; 169425cf1a30Sjl139090 169525cf1a30Sjl139090 if (board == -1) { 169625cf1a30Sjl139090 /* this cannot happen on production systems */ 169725cf1a30Sjl139090 cmn_err(CE_PANIC, "u2u:Invalid property;board = %d", board); 169825cf1a30Sjl139090 } 169925cf1a30Sjl139090 170025cf1a30Sjl139090 /* 170125cf1a30Sjl139090 * Initialize interrupt target translations mutex. 170225cf1a30Sjl139090 */ 170325cf1a30Sjl139090 mutex_init(&(u2u_trans_p->u2u_ittrans_lock), "u2u_ittrans_lock", 170425cf1a30Sjl139090 MUTEX_DEFAULT, NULL); 170525cf1a30Sjl139090 170625cf1a30Sjl139090 /* 170725cf1a30Sjl139090 * Get U2U's registers space by ddi_regs_map_setup(9F) 170825cf1a30Sjl139090 */ 170925cf1a30Sjl139090 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 171025cf1a30Sjl139090 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 171125cf1a30Sjl139090 attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 171225cf1a30Sjl139090 171325cf1a30Sjl139090 ret = ddi_regs_map_setup(pcmu_p->pcmu_dip, 171425cf1a30Sjl139090 REGS_INDEX_OF_U2U, (caddr_t *)(&(u2u_trans_p->u2u_regs_base)), 171525cf1a30Sjl139090 0, 0, &attr, &(u2u_trans_p->u2u_acc)); 171625cf1a30Sjl139090 171725cf1a30Sjl139090 /* 171825cf1a30Sjl139090 * check result of ddi_regs_map_setup(). 171925cf1a30Sjl139090 */ 172025cf1a30Sjl139090 if (ret != DDI_SUCCESS) { 172125cf1a30Sjl139090 cmn_err(CE_PANIC, "u2u%d: registers map setup failed", board); 172225cf1a30Sjl139090 } 172325cf1a30Sjl139090 172425cf1a30Sjl139090 /* 172525cf1a30Sjl139090 * Read Port-id(1 byte) in u2u 172625cf1a30Sjl139090 */ 172725cf1a30Sjl139090 u2u_trans_p->u2u_port_id = *(volatile int32_t *) 172825cf1a30Sjl139090 (u2u_trans_p->u2u_regs_base + U2U_PID_REGISTER_OFFSET); 172925cf1a30Sjl139090 173025cf1a30Sjl139090 if (pcmu_p->pcmu_id != u2u_trans_p->u2u_port_id) { 173125cf1a30Sjl139090 cmn_err(CE_PANIC, "u2u%d: Invalid Port-ID", board); 173225cf1a30Sjl139090 } 173325cf1a30Sjl139090 173425cf1a30Sjl139090 *ittrans_cookie = u2u_trans_p; 173525cf1a30Sjl139090 } 173625cf1a30Sjl139090 173725cf1a30Sjl139090 /* 173825cf1a30Sjl139090 * u2u_ittras_resume() is called from pcmu_obj_resume() at DDI_RESUME entry. 173925cf1a30Sjl139090 */ 174025cf1a30Sjl139090 static void 174125cf1a30Sjl139090 u2u_ittrans_resume(u2u_ittrans_data_t **ittrans_cookie) 174225cf1a30Sjl139090 { 174325cf1a30Sjl139090 174425cf1a30Sjl139090 u2u_ittrans_data_t *u2u_trans_p; 174525cf1a30Sjl139090 u2u_ittrans_id_t *ittrans_id_p; 174625cf1a30Sjl139090 uintptr_t data_reg_addr; 174725cf1a30Sjl139090 int ix; 174825cf1a30Sjl139090 174925cf1a30Sjl139090 u2u_trans_p = *ittrans_cookie; 175025cf1a30Sjl139090 175125cf1a30Sjl139090 /* 175225cf1a30Sjl139090 * Set U2U Data Register 175325cf1a30Sjl139090 */ 175425cf1a30Sjl139090 for (ix = 0; ix < U2U_DATA_NUM; ix++) { 175525cf1a30Sjl139090 ittrans_id_p = &(u2u_trans_p->u2u_ittrans_id[ix]); 175625cf1a30Sjl139090 data_reg_addr = u2u_trans_p->u2u_regs_base + 175725cf1a30Sjl139090 U2U_DATA_REGISTER_OFFSET + (ix * sizeof (uint64_t)); 175825cf1a30Sjl139090 if (ittrans_id_p->u2u_ino_map_reg == NULL) { 175925cf1a30Sjl139090 /* This index was not set */ 176025cf1a30Sjl139090 continue; 176125cf1a30Sjl139090 } 176225cf1a30Sjl139090 *(volatile uint32_t *) (data_reg_addr) = 176325cf1a30Sjl139090 (uint32_t)ittrans_id_p->u2u_tgt_cpu_id; 176425cf1a30Sjl139090 176525cf1a30Sjl139090 } 176625cf1a30Sjl139090 } 176725cf1a30Sjl139090 176825cf1a30Sjl139090 /* 176925cf1a30Sjl139090 * u2u_ittras_uninit() is called from ib_destroy() at detach, 177025cf1a30Sjl139090 * or occuring error in attach. 177125cf1a30Sjl139090 */ 177225cf1a30Sjl139090 static void 177325cf1a30Sjl139090 u2u_ittrans_uninit(u2u_ittrans_data_t *ittrans_cookie) 177425cf1a30Sjl139090 { 177525cf1a30Sjl139090 177625cf1a30Sjl139090 if (ittrans_cookie == NULL) { 177725cf1a30Sjl139090 return; /* not support */ 177825cf1a30Sjl139090 } 177925cf1a30Sjl139090 178025cf1a30Sjl139090 if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) { 178125cf1a30Sjl139090 return; /* illeagal case */ 178225cf1a30Sjl139090 } 178325cf1a30Sjl139090 178425cf1a30Sjl139090 ddi_regs_map_free(&(ittrans_cookie->u2u_acc)); 178525cf1a30Sjl139090 mutex_destroy(&(ittrans_cookie->u2u_ittrans_lock)); 178625cf1a30Sjl139090 kmem_free((void *)ittrans_cookie, sizeof (u2u_ittrans_data_t)); 178725cf1a30Sjl139090 } 178825cf1a30Sjl139090 178925cf1a30Sjl139090 /* 179025cf1a30Sjl139090 * This routine,u2u_translate_tgtid(, , cpu_id, pino_map_reg), 179125cf1a30Sjl139090 * searches index having same value of pino_map_reg, or empty. 179225cf1a30Sjl139090 * Then, stores cpu_id in a U2U Data Register as this index, 179325cf1a30Sjl139090 * and return this index. 179425cf1a30Sjl139090 */ 179525cf1a30Sjl139090 int 179625cf1a30Sjl139090 u2u_translate_tgtid(pcmu_t *pcmu_p, uint_t cpu_id, 179725cf1a30Sjl139090 volatile uint64_t *pino_map_reg) 179825cf1a30Sjl139090 { 179925cf1a30Sjl139090 180025cf1a30Sjl139090 int index = -1; 180125cf1a30Sjl139090 int ix; 180225cf1a30Sjl139090 int err_level; /* severity level for cmn_err */ 180325cf1a30Sjl139090 u2u_ittrans_id_t *ittrans_id_p; 180425cf1a30Sjl139090 uintptr_t data_reg_addr; 180525cf1a30Sjl139090 u2u_ittrans_data_t *ittrans_cookie; 180625cf1a30Sjl139090 180725cf1a30Sjl139090 ittrans_cookie = 180825cf1a30Sjl139090 (u2u_ittrans_data_t *)(pcmu_p->pcmu_cb_p->pcb_ittrans_cookie); 180925cf1a30Sjl139090 181025cf1a30Sjl139090 if (ittrans_cookie == NULL) { 181125cf1a30Sjl139090 return (cpu_id); 181225cf1a30Sjl139090 } 181325cf1a30Sjl139090 181425cf1a30Sjl139090 if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) { 181525cf1a30Sjl139090 return (-1); /* illeagal case */ 181625cf1a30Sjl139090 } 181725cf1a30Sjl139090 181825cf1a30Sjl139090 mutex_enter(&(ittrans_cookie->u2u_ittrans_lock)); 181925cf1a30Sjl139090 182025cf1a30Sjl139090 /* 182125cf1a30Sjl139090 * Decide index No. of U2U Data registers in either 182225cf1a30Sjl139090 * already used by same pino_map_reg, or empty. 182325cf1a30Sjl139090 */ 182425cf1a30Sjl139090 for (ix = 0; ix < U2U_DATA_NUM; ix++) { 182525cf1a30Sjl139090 ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[ix]); 182625cf1a30Sjl139090 if (ittrans_id_p->u2u_ino_map_reg == pino_map_reg) { 182725cf1a30Sjl139090 /* already used this pino_map_reg */ 182825cf1a30Sjl139090 index = ix; 182925cf1a30Sjl139090 break; 183025cf1a30Sjl139090 } 183125cf1a30Sjl139090 if (index == -1 && 183225cf1a30Sjl139090 ittrans_id_p->u2u_ino_map_reg == NULL) { 183325cf1a30Sjl139090 index = ix; 183425cf1a30Sjl139090 } 183525cf1a30Sjl139090 } 183625cf1a30Sjl139090 183725cf1a30Sjl139090 if (index == -1) { 183825cf1a30Sjl139090 if (panicstr) { 183925cf1a30Sjl139090 err_level = CE_WARN; 184025cf1a30Sjl139090 } else { 184125cf1a30Sjl139090 err_level = CE_PANIC; 184225cf1a30Sjl139090 } 184325cf1a30Sjl139090 cmn_err(err_level, "u2u%d:No more U2U-Data regs!!", 184425cf1a30Sjl139090 ittrans_cookie->u2u_board); 184525cf1a30Sjl139090 return (cpu_id); 184625cf1a30Sjl139090 } 184725cf1a30Sjl139090 184825cf1a30Sjl139090 /* 184925cf1a30Sjl139090 * For U2U 185025cf1a30Sjl139090 * set cpu_id into u2u_data_reg by index. 185125cf1a30Sjl139090 * ((uint64_t)(u2u_regs_base 185225cf1a30Sjl139090 * + U2U_DATA_REGISTER_OFFSET))[index] = cpu_id; 185325cf1a30Sjl139090 */ 185425cf1a30Sjl139090 185525cf1a30Sjl139090 data_reg_addr = ittrans_cookie->u2u_regs_base 185625cf1a30Sjl139090 + U2U_DATA_REGISTER_OFFSET 185725cf1a30Sjl139090 + (index * sizeof (uint64_t)); 185825cf1a30Sjl139090 185925cf1a30Sjl139090 /* 186025cf1a30Sjl139090 * Set cpu_id into U2U Data register[index] 186125cf1a30Sjl139090 */ 186225cf1a30Sjl139090 *(volatile uint32_t *) (data_reg_addr) = (uint32_t)cpu_id; 186325cf1a30Sjl139090 186425cf1a30Sjl139090 /* 186525cf1a30Sjl139090 * Setup for software, excepting at panicing. 186625cf1a30Sjl139090 * and rebooting, etc...? 186725cf1a30Sjl139090 */ 186825cf1a30Sjl139090 if (!panicstr) { 186925cf1a30Sjl139090 ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[index]); 187025cf1a30Sjl139090 ittrans_id_p->u2u_tgt_cpu_id = cpu_id; 187125cf1a30Sjl139090 ittrans_id_p->u2u_ino_map_reg = pino_map_reg; 187225cf1a30Sjl139090 } 187325cf1a30Sjl139090 187425cf1a30Sjl139090 mutex_exit(&(ittrans_cookie->u2u_ittrans_lock)); 187525cf1a30Sjl139090 187625cf1a30Sjl139090 return (index); 187725cf1a30Sjl139090 } 187825cf1a30Sjl139090 187925cf1a30Sjl139090 /* 188025cf1a30Sjl139090 * u2u_ittrans_cleanup() is called from common_pcmu_ib_intr_disable() 188125cf1a30Sjl139090 * after called intr_rem_cpu(mondo). 188225cf1a30Sjl139090 */ 188325cf1a30Sjl139090 void 188425cf1a30Sjl139090 u2u_ittrans_cleanup(u2u_ittrans_data_t *ittrans_cookie, 188525cf1a30Sjl139090 volatile uint64_t *pino_map_reg) 188625cf1a30Sjl139090 { 188725cf1a30Sjl139090 188825cf1a30Sjl139090 int ix; 188925cf1a30Sjl139090 u2u_ittrans_id_t *ittrans_id_p; 189025cf1a30Sjl139090 189125cf1a30Sjl139090 if (ittrans_cookie == NULL) { 189225cf1a30Sjl139090 return; 189325cf1a30Sjl139090 } 189425cf1a30Sjl139090 189525cf1a30Sjl139090 if (ittrans_cookie == (u2u_ittrans_data_t *)(-1)) { 189625cf1a30Sjl139090 return; /* illeagal case */ 189725cf1a30Sjl139090 } 189825cf1a30Sjl139090 189925cf1a30Sjl139090 mutex_enter(&(ittrans_cookie->u2u_ittrans_lock)); 190025cf1a30Sjl139090 190125cf1a30Sjl139090 for (ix = 0; ix < U2U_DATA_NUM; ix++) { 190225cf1a30Sjl139090 ittrans_id_p = &(ittrans_cookie->u2u_ittrans_id[ix]); 190325cf1a30Sjl139090 if (ittrans_id_p->u2u_ino_map_reg == pino_map_reg) { 190425cf1a30Sjl139090 ittrans_id_p->u2u_ino_map_reg = NULL; 190525cf1a30Sjl139090 break; 190625cf1a30Sjl139090 } 190725cf1a30Sjl139090 } 190825cf1a30Sjl139090 190925cf1a30Sjl139090 mutex_exit(&(ittrans_cookie->u2u_ittrans_lock)); 191025cf1a30Sjl139090 } 191125cf1a30Sjl139090 191225cf1a30Sjl139090 /* 191325cf1a30Sjl139090 * pcmu_ecc_classify, called by ecc_handler to classify ecc errors 191425cf1a30Sjl139090 * and determine if we should panic or not. 191525cf1a30Sjl139090 */ 191625cf1a30Sjl139090 void 191725cf1a30Sjl139090 pcmu_ecc_classify(uint64_t err, pcmu_ecc_errstate_t *ecc_err_p) 191825cf1a30Sjl139090 { 191925cf1a30Sjl139090 struct async_flt *ecc = &ecc_err_p->ecc_aflt; 192025cf1a30Sjl139090 /* LINTED */ 192125cf1a30Sjl139090 pcmu_t *pcmu_p = ecc_err_p->ecc_ii_p.pecc_p->pecc_pcmu_p; 192225cf1a30Sjl139090 192325cf1a30Sjl139090 ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 192425cf1a30Sjl139090 192525cf1a30Sjl139090 ecc_err_p->ecc_bridge_type = PCI_OPLCMU; /* RAGS */ 192625cf1a30Sjl139090 /* 192725cf1a30Sjl139090 * Get the parent bus id that caused the error. 192825cf1a30Sjl139090 */ 192925cf1a30Sjl139090 ecc_err_p->ecc_dev_id = (ecc_err_p->ecc_afsr & PCMU_ECC_UE_AFSR_ID) 193025cf1a30Sjl139090 >> PCMU_ECC_UE_AFSR_ID_SHIFT; 193125cf1a30Sjl139090 /* 193225cf1a30Sjl139090 * Determine the doubleword offset of the error. 193325cf1a30Sjl139090 */ 193425cf1a30Sjl139090 ecc_err_p->ecc_dw_offset = (ecc_err_p->ecc_afsr & 193525cf1a30Sjl139090 PCMU_ECC_UE_AFSR_DW_OFFSET) >> PCMU_ECC_UE_AFSR_DW_OFFSET_SHIFT; 193625cf1a30Sjl139090 /* 193725cf1a30Sjl139090 * Determine the primary error type. 193825cf1a30Sjl139090 */ 193925cf1a30Sjl139090 switch (err) { 194025cf1a30Sjl139090 case PCMU_ECC_UE_AFSR_E_PIO: 194125cf1a30Sjl139090 if (ecc_err_p->pecc_pri) { 194225cf1a30Sjl139090 ecc->flt_erpt_class = PCI_ECC_PIO_UE; 194325cf1a30Sjl139090 } else { 194425cf1a30Sjl139090 ecc->flt_erpt_class = PCI_ECC_SEC_PIO_UE; 194525cf1a30Sjl139090 } 194625cf1a30Sjl139090 /* For CMU-CH, a UE is always fatal. */ 194725cf1a30Sjl139090 ecc->flt_panic = 1; 194825cf1a30Sjl139090 break; 194925cf1a30Sjl139090 195025cf1a30Sjl139090 default: 195125cf1a30Sjl139090 return; 195225cf1a30Sjl139090 } 195325cf1a30Sjl139090 } 195425cf1a30Sjl139090 195525cf1a30Sjl139090 /* 195625cf1a30Sjl139090 * pcmu_pbm_classify, called by pcmu_pbm_afsr_report to classify piow afsr. 195725cf1a30Sjl139090 */ 195825cf1a30Sjl139090 int 195925cf1a30Sjl139090 pcmu_pbm_classify(pcmu_pbm_errstate_t *pbm_err_p) 196025cf1a30Sjl139090 { 196125cf1a30Sjl139090 uint32_t e; 196225cf1a30Sjl139090 int nerr = 0; 196325cf1a30Sjl139090 char **tmp_class; 196425cf1a30Sjl139090 196525cf1a30Sjl139090 if (pbm_err_p->pcbm_pri) { 196625cf1a30Sjl139090 tmp_class = &pbm_err_p->pcbm_pci.pcmu_err_class; 196725cf1a30Sjl139090 e = PBM_AFSR_TO_PRIERR(pbm_err_p->pbm_afsr); 196825cf1a30Sjl139090 pbm_err_p->pbm_log = FM_LOG_PCI; 196925cf1a30Sjl139090 } else { 197025cf1a30Sjl139090 tmp_class = &pbm_err_p->pbm_err_class; 197125cf1a30Sjl139090 e = PBM_AFSR_TO_SECERR(pbm_err_p->pbm_afsr); 197225cf1a30Sjl139090 pbm_err_p->pbm_log = FM_LOG_PBM; 197325cf1a30Sjl139090 } 197425cf1a30Sjl139090 197525cf1a30Sjl139090 if (e & PCMU_PCI_AFSR_E_MA) { 197625cf1a30Sjl139090 *tmp_class = pbm_err_p->pcbm_pri ? PCI_MA : PCI_SEC_MA; 197725cf1a30Sjl139090 nerr++; 197825cf1a30Sjl139090 } 197925cf1a30Sjl139090 return (nerr); 198025cf1a30Sjl139090 } 198125cf1a30Sjl139090 198225cf1a30Sjl139090 /* 198325cf1a30Sjl139090 * Function used to clear PBM/PCI/IOMMU error state after error handling 198425cf1a30Sjl139090 * is complete. Only clearing error bits which have been logged. Called by 198525cf1a30Sjl139090 * pcmu_pbm_err_handler and pcmu_bus_exit. 198625cf1a30Sjl139090 */ 198725cf1a30Sjl139090 static void 198825cf1a30Sjl139090 pcmu_clear_error(pcmu_t *pcmu_p, pcmu_pbm_errstate_t *pbm_err_p) 198925cf1a30Sjl139090 { 199025cf1a30Sjl139090 pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 199125cf1a30Sjl139090 199225cf1a30Sjl139090 ASSERT(MUTEX_HELD(&pcbm_p->pcbm_pcmu_p->pcmu_err_mutex)); 199325cf1a30Sjl139090 199425cf1a30Sjl139090 *pcbm_p->pcbm_ctrl_reg = pbm_err_p->pbm_ctl_stat; 199525cf1a30Sjl139090 *pcbm_p->pcbm_async_flt_status_reg = pbm_err_p->pbm_afsr; 199625cf1a30Sjl139090 pcbm_p->pcbm_config_header->ch_status_reg = 199725cf1a30Sjl139090 pbm_err_p->pcbm_pci.pcmu_cfg_stat; 199825cf1a30Sjl139090 } 199925cf1a30Sjl139090 200025cf1a30Sjl139090 /*ARGSUSED*/ 200125cf1a30Sjl139090 int 200225cf1a30Sjl139090 pcmu_pbm_err_handler(dev_info_t *dip, ddi_fm_error_t *derr, 200325cf1a30Sjl139090 const void *impl_data, int caller) 200425cf1a30Sjl139090 { 200525cf1a30Sjl139090 int fatal = 0; 200625cf1a30Sjl139090 int nonfatal = 0; 200725cf1a30Sjl139090 int unknown = 0; 200825cf1a30Sjl139090 uint32_t prierr, secerr; 200925cf1a30Sjl139090 pcmu_pbm_errstate_t pbm_err; 201025cf1a30Sjl139090 pcmu_t *pcmu_p = (pcmu_t *)impl_data; 201125cf1a30Sjl139090 int ret = 0; 201225cf1a30Sjl139090 201325cf1a30Sjl139090 ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 201425cf1a30Sjl139090 pcmu_pbm_errstate_get(pcmu_p, &pbm_err); 201525cf1a30Sjl139090 201625cf1a30Sjl139090 derr->fme_ena = derr->fme_ena ? derr->fme_ena : 201725cf1a30Sjl139090 fm_ena_generate(0, FM_ENA_FMT1); 201825cf1a30Sjl139090 201925cf1a30Sjl139090 prierr = PBM_AFSR_TO_PRIERR(pbm_err.pbm_afsr); 202025cf1a30Sjl139090 secerr = PBM_AFSR_TO_SECERR(pbm_err.pbm_afsr); 202125cf1a30Sjl139090 202225cf1a30Sjl139090 if (derr->fme_flag == DDI_FM_ERR_PEEK) { 202325cf1a30Sjl139090 /* 202425cf1a30Sjl139090 * For ddi_peek treat all events as nonfatal. We only 202525cf1a30Sjl139090 * really call this function so that pcmu_clear_error() 202625cf1a30Sjl139090 * and ndi_fm_handler_dispatch() will get called. 202725cf1a30Sjl139090 */ 202825cf1a30Sjl139090 nonfatal++; 202925cf1a30Sjl139090 goto done; 203025cf1a30Sjl139090 } else if (derr->fme_flag == DDI_FM_ERR_POKE) { 203125cf1a30Sjl139090 /* 203225cf1a30Sjl139090 * For ddi_poke we can treat as nonfatal if the 203325cf1a30Sjl139090 * following conditions are met : 203425cf1a30Sjl139090 * 1. Make sure only primary error is MA/TA 203525cf1a30Sjl139090 * 2. Make sure no secondary error 203625cf1a30Sjl139090 * 3. check pci config header stat reg to see MA/TA is 203725cf1a30Sjl139090 * logged. We cannot verify only MA/TA is recorded 203825cf1a30Sjl139090 * since it gets much more complicated when a 203925cf1a30Sjl139090 * PCI-to-PCI bridge is present. 204025cf1a30Sjl139090 */ 204125cf1a30Sjl139090 if ((prierr == PCMU_PCI_AFSR_E_MA) && !secerr && 204225cf1a30Sjl139090 (pbm_err.pcbm_pci.pcmu_cfg_stat & PCI_STAT_R_MAST_AB)) { 204325cf1a30Sjl139090 nonfatal++; 204425cf1a30Sjl139090 goto done; 204525cf1a30Sjl139090 } 204625cf1a30Sjl139090 } 204725cf1a30Sjl139090 204825cf1a30Sjl139090 if (prierr || secerr) { 204925cf1a30Sjl139090 ret = pcmu_pbm_afsr_report(dip, derr->fme_ena, &pbm_err); 205025cf1a30Sjl139090 if (ret == DDI_FM_FATAL) { 205125cf1a30Sjl139090 fatal++; 205225cf1a30Sjl139090 } else { 205325cf1a30Sjl139090 nonfatal++; 205425cf1a30Sjl139090 } 205525cf1a30Sjl139090 } 205625cf1a30Sjl139090 205725cf1a30Sjl139090 ret = pcmu_cfg_report(dip, derr, &pbm_err.pcbm_pci, caller, prierr); 205825cf1a30Sjl139090 if (ret == DDI_FM_FATAL) { 205925cf1a30Sjl139090 fatal++; 206025cf1a30Sjl139090 } else if (ret == DDI_FM_NONFATAL) { 206125cf1a30Sjl139090 nonfatal++; 206225cf1a30Sjl139090 } 206325cf1a30Sjl139090 206425cf1a30Sjl139090 done: 206525cf1a30Sjl139090 if (ret == DDI_FM_FATAL) { 206625cf1a30Sjl139090 fatal++; 206725cf1a30Sjl139090 } else if (ret == DDI_FM_NONFATAL) { 206825cf1a30Sjl139090 nonfatal++; 206925cf1a30Sjl139090 } else if (ret == DDI_FM_UNKNOWN) { 207025cf1a30Sjl139090 unknown++; 207125cf1a30Sjl139090 } 207225cf1a30Sjl139090 207325cf1a30Sjl139090 /* Cleanup and reset error bits */ 207425cf1a30Sjl139090 pcmu_clear_error(pcmu_p, &pbm_err); 207525cf1a30Sjl139090 207625cf1a30Sjl139090 return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 207725cf1a30Sjl139090 (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 207825cf1a30Sjl139090 } 207925cf1a30Sjl139090 208025cf1a30Sjl139090 int 208125cf1a30Sjl139090 pcmu_check_error(pcmu_t *pcmu_p) 208225cf1a30Sjl139090 { 208325cf1a30Sjl139090 pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 208425cf1a30Sjl139090 uint16_t pcmu_cfg_stat; 208525cf1a30Sjl139090 uint64_t pbm_afsr; 208625cf1a30Sjl139090 208725cf1a30Sjl139090 ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 208825cf1a30Sjl139090 208925cf1a30Sjl139090 pcmu_cfg_stat = pcbm_p->pcbm_config_header->ch_status_reg; 209025cf1a30Sjl139090 pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; 209125cf1a30Sjl139090 209225cf1a30Sjl139090 if ((pcmu_cfg_stat & (PCI_STAT_S_PERROR | PCI_STAT_S_TARG_AB | 209325cf1a30Sjl139090 PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | 209425cf1a30Sjl139090 PCI_STAT_S_SYSERR | PCI_STAT_PERROR)) || 209525cf1a30Sjl139090 (PBM_AFSR_TO_PRIERR(pbm_afsr))) { 209625cf1a30Sjl139090 return (1); 209725cf1a30Sjl139090 } 209825cf1a30Sjl139090 return (0); 209925cf1a30Sjl139090 210025cf1a30Sjl139090 } 210125cf1a30Sjl139090 210225cf1a30Sjl139090 /* 210325cf1a30Sjl139090 * Function used to gather PBM/PCI error state for the 210425cf1a30Sjl139090 * pcmu_pbm_err_handler. This function must be called while pcmu_err_mutex 210525cf1a30Sjl139090 * is held. 210625cf1a30Sjl139090 */ 210725cf1a30Sjl139090 static void 210825cf1a30Sjl139090 pcmu_pbm_errstate_get(pcmu_t *pcmu_p, pcmu_pbm_errstate_t *pbm_err_p) 210925cf1a30Sjl139090 { 211025cf1a30Sjl139090 pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p; 211125cf1a30Sjl139090 211225cf1a30Sjl139090 ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex)); 211325cf1a30Sjl139090 bzero(pbm_err_p, sizeof (pcmu_pbm_errstate_t)); 211425cf1a30Sjl139090 211525cf1a30Sjl139090 /* 211625cf1a30Sjl139090 * Capture all pbm error state for later logging 211725cf1a30Sjl139090 */ 211825cf1a30Sjl139090 pbm_err_p->pbm_bridge_type = PCI_OPLCMU; /* RAGS */ 211925cf1a30Sjl139090 pbm_err_p->pcbm_pci.pcmu_cfg_stat = 212025cf1a30Sjl139090 pcbm_p->pcbm_config_header->ch_status_reg; 212125cf1a30Sjl139090 pbm_err_p->pbm_ctl_stat = *pcbm_p->pcbm_ctrl_reg; 212225cf1a30Sjl139090 pbm_err_p->pcbm_pci.pcmu_cfg_comm = 212325cf1a30Sjl139090 pcbm_p->pcbm_config_header->ch_command_reg; 212425cf1a30Sjl139090 pbm_err_p->pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; 212525cf1a30Sjl139090 pbm_err_p->pbm_afar = *pcbm_p->pcbm_async_flt_addr_reg; 212625cf1a30Sjl139090 pbm_err_p->pcbm_pci.pcmu_pa = *pcbm_p->pcbm_async_flt_addr_reg; 212725cf1a30Sjl139090 } 212825cf1a30Sjl139090 212925cf1a30Sjl139090 static void 213025cf1a30Sjl139090 pcmu_pbm_clear_error(pcmu_pbm_t *pcbm_p) 213125cf1a30Sjl139090 { 213225cf1a30Sjl139090 uint64_t pbm_afsr; 213325cf1a30Sjl139090 213425cf1a30Sjl139090 /* 213525cf1a30Sjl139090 * for poke() support - called from POKE_FLUSH. Spin waiting 213625cf1a30Sjl139090 * for MA, TA or SERR to be cleared by a pcmu_pbm_error_intr(). 213725cf1a30Sjl139090 * We have to wait for SERR too in case the device is beyond 213825cf1a30Sjl139090 * a pci-pci bridge. 213925cf1a30Sjl139090 */ 214025cf1a30Sjl139090 pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; 214125cf1a30Sjl139090 while (((pbm_afsr >> PCMU_PCI_AFSR_PE_SHIFT) & 214225cf1a30Sjl139090 (PCMU_PCI_AFSR_E_MA | PCMU_PCI_AFSR_E_TA))) { 214325cf1a30Sjl139090 pbm_afsr = *pcbm_p->pcbm_async_flt_status_reg; 214425cf1a30Sjl139090 } 214525cf1a30Sjl139090 } 214625cf1a30Sjl139090 214725cf1a30Sjl139090 void 214825cf1a30Sjl139090 pcmu_err_create(pcmu_t *pcmu_p) 214925cf1a30Sjl139090 { 215025cf1a30Sjl139090 /* 215125cf1a30Sjl139090 * PCI detected ECC errorq, to schedule async handling 215225cf1a30Sjl139090 * of ECC errors and logging. 215325cf1a30Sjl139090 * The errorq is created here but destroyed when _fini is called 215425cf1a30Sjl139090 * for the pci module. 215525cf1a30Sjl139090 */ 215625cf1a30Sjl139090 if (pcmu_ecc_queue == NULL) { 215725cf1a30Sjl139090 pcmu_ecc_queue = errorq_create("pcmu_ecc_queue", 215825cf1a30Sjl139090 (errorq_func_t)pcmu_ecc_err_drain, 215925cf1a30Sjl139090 (void *)NULL, 216025cf1a30Sjl139090 ECC_MAX_ERRS, sizeof (pcmu_ecc_errstate_t), 216125cf1a30Sjl139090 PIL_2, ERRORQ_VITAL); 216225cf1a30Sjl139090 if (pcmu_ecc_queue == NULL) 216325cf1a30Sjl139090 panic("failed to create required system error queue"); 216425cf1a30Sjl139090 } 216525cf1a30Sjl139090 216625cf1a30Sjl139090 /* 216725cf1a30Sjl139090 * Initialize error handling mutex. 216825cf1a30Sjl139090 */ 216925cf1a30Sjl139090 mutex_init(&pcmu_p->pcmu_err_mutex, NULL, MUTEX_DRIVER, 217025cf1a30Sjl139090 (void *)pcmu_p->pcmu_fm_ibc); 217125cf1a30Sjl139090 } 217225cf1a30Sjl139090 217325cf1a30Sjl139090 void 217425cf1a30Sjl139090 pcmu_err_destroy(pcmu_t *pcmu_p) 217525cf1a30Sjl139090 { 217625cf1a30Sjl139090 mutex_destroy(&pcmu_p->pcmu_err_mutex); 217725cf1a30Sjl139090 } 217825cf1a30Sjl139090 217925cf1a30Sjl139090 /* 218025cf1a30Sjl139090 * Function used to post PCI block module specific ereports. 218125cf1a30Sjl139090 */ 218225cf1a30Sjl139090 void 218325cf1a30Sjl139090 pcmu_pbm_ereport_post(dev_info_t *dip, uint64_t ena, 218425cf1a30Sjl139090 pcmu_pbm_errstate_t *pbm_err) 218525cf1a30Sjl139090 { 218625cf1a30Sjl139090 char *aux_msg; 218725cf1a30Sjl139090 uint32_t prierr, secerr; 218825cf1a30Sjl139090 pcmu_t *pcmu_p; 218925cf1a30Sjl139090 int instance = ddi_get_instance(dip); 219025cf1a30Sjl139090 219125cf1a30Sjl139090 ena = ena ? ena : fm_ena_generate(0, FM_ENA_FMT1); 219225cf1a30Sjl139090 219325cf1a30Sjl139090 pcmu_p = get_pcmu_soft_state(instance); 219425cf1a30Sjl139090 prierr = PBM_AFSR_TO_PRIERR(pbm_err->pbm_afsr); 219525cf1a30Sjl139090 secerr = PBM_AFSR_TO_SECERR(pbm_err->pbm_afsr); 219625cf1a30Sjl139090 if (prierr) 219725cf1a30Sjl139090 aux_msg = "PCI primary error: Master Abort"; 219825cf1a30Sjl139090 else if (secerr) 219925cf1a30Sjl139090 aux_msg = "PCI secondary error: Master Abort"; 220025cf1a30Sjl139090 else 220125cf1a30Sjl139090 aux_msg = ""; 220225cf1a30Sjl139090 cmn_err(CE_WARN, "%s %s: %s %s=0x%lx, %s=0x%lx, %s=0x%lx %s=0x%x", 220325cf1a30Sjl139090 (pcmu_p->pcmu_pcbm_p)->pcbm_nameinst_str, 220425cf1a30Sjl139090 (pcmu_p->pcmu_pcbm_p)->pcbm_nameaddr_str, 220525cf1a30Sjl139090 aux_msg, 220625cf1a30Sjl139090 PCI_PBM_AFAR, pbm_err->pbm_afar, 220725cf1a30Sjl139090 PCI_PBM_AFSR, pbm_err->pbm_afsr, 220825cf1a30Sjl139090 PCI_PBM_CSR, pbm_err->pbm_ctl_stat, 220925cf1a30Sjl139090 "portid", pcmu_p->pcmu_id); 221025cf1a30Sjl139090 } 2211