11772Sjl139090 /*
21772Sjl139090 * CDDL HEADER START
31772Sjl139090 *
41772Sjl139090 * The contents of this file are subject to the terms of the
51772Sjl139090 * Common Development and Distribution License (the "License").
61772Sjl139090 * You may not use this file except in compliance with the License.
71772Sjl139090 *
81772Sjl139090 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91772Sjl139090 * or http://www.opensolaris.org/os/licensing.
101772Sjl139090 * See the License for the specific language governing permissions
111772Sjl139090 * and limitations under the License.
121772Sjl139090 *
131772Sjl139090 * When distributing Covered Code, include this CDDL HEADER in each
141772Sjl139090 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151772Sjl139090 * If applicable, add the following below this CDDL HEADER, with the
161772Sjl139090 * fields enclosed by brackets "[]" replaced with your own identifying
171772Sjl139090 * information: Portions Copyright [yyyy] [name of copyright owner]
181772Sjl139090 *
191772Sjl139090 * CDDL HEADER END
201772Sjl139090 */
211772Sjl139090 /*
221772Sjl139090 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
231772Sjl139090 * Use is subject to license terms.
241772Sjl139090 */
251772Sjl139090
261772Sjl139090 #pragma ident "%Z%%M% %I% %E% SMI"
271772Sjl139090
281772Sjl139090 /*
291772Sjl139090 * CMU-CH PBM implementation:
301772Sjl139090 * initialization
311772Sjl139090 * Bus error interrupt handler
321772Sjl139090 */
331772Sjl139090
341772Sjl139090 #include <sys/types.h>
351772Sjl139090 #include <sys/kmem.h>
361772Sjl139090 #include <sys/spl.h>
371772Sjl139090 #include <sys/sysmacros.h>
381772Sjl139090 #include <sys/sunddi.h>
391772Sjl139090 #include <sys/fm/protocol.h>
401772Sjl139090 #include <sys/fm/util.h>
411772Sjl139090 #include <sys/machsystm.h>
421772Sjl139090 #include <sys/async.h>
431772Sjl139090 #include <sys/ddi_impldefs.h>
441772Sjl139090 #include <sys/ontrap.h>
451772Sjl139090 #include <sys/pcicmu/pcicmu.h>
461772Sjl139090 #include <sys/membar.h>
471772Sjl139090 #include <sys/ivintr.h>
481772Sjl139090
491772Sjl139090 static uint_t pcmu_pbm_error_intr(caddr_t a);
501772Sjl139090
511772Sjl139090 /* The nexus interrupt priority values */
521772Sjl139090 int pcmu_pil[] = {14, 14, 14, 14, 14, 14};
531772Sjl139090
541772Sjl139090 void
pcmu_pbm_create(pcmu_t * pcmu_p)551772Sjl139090 pcmu_pbm_create(pcmu_t *pcmu_p)
561772Sjl139090 {
571772Sjl139090 pcmu_pbm_t *pcbm_p;
581772Sjl139090 int len;
591772Sjl139090 dev_info_t *dip = pcmu_p->pcmu_dip;
601772Sjl139090
611772Sjl139090 /*
621772Sjl139090 * Allocate a state structure for the PBM and cross-link it
631772Sjl139090 * to its per pci node state structure.
641772Sjl139090 */
651772Sjl139090 pcbm_p = (pcmu_pbm_t *)kmem_zalloc(sizeof (pcmu_pbm_t), KM_SLEEP);
661772Sjl139090 pcmu_p->pcmu_pcbm_p = pcbm_p;
671772Sjl139090 pcbm_p->pcbm_pcmu_p = pcmu_p;
681772Sjl139090
691772Sjl139090 len = snprintf(pcbm_p->pcbm_nameinst_str,
701772Sjl139090 sizeof (pcbm_p->pcbm_nameinst_str), "%s%d", NAMEINST(dip));
711772Sjl139090 pcbm_p->pcbm_nameaddr_str = pcbm_p->pcbm_nameinst_str + ++len;
721772Sjl139090 (void) snprintf(pcbm_p->pcbm_nameaddr_str,
731772Sjl139090 sizeof (pcbm_p->pcbm_nameinst_str) - len, "%s@%s", NAMEADDR(dip));
741772Sjl139090
751772Sjl139090 pcmu_pbm_setup(pcbm_p);
761772Sjl139090
771772Sjl139090 PCMU_DBG4(PCMU_DBG_ATTACH, dip,
781772Sjl139090 "pcmu_pbm_create: ctrl=%x, afsr=%x, afar=%x, diag=%x\n",
791772Sjl139090 pcbm_p->pcbm_ctrl_reg, pcbm_p->pcbm_async_flt_status_reg,
801772Sjl139090 pcbm_p->pcbm_async_flt_addr_reg, pcbm_p->pcbm_diag_reg);
811772Sjl139090 PCMU_DBG1(PCMU_DBG_ATTACH, dip, "pcmu_pbm_create: conf=%x\n",
821772Sjl139090 pcbm_p->pcbm_config_header);
831772Sjl139090
841772Sjl139090 /*
851772Sjl139090 * Register a function to disable pbm error interrupts during a panic.
861772Sjl139090 */
871772Sjl139090 bus_func_register(BF_TYPE_ERRDIS,
881772Sjl139090 (busfunc_t)pcmu_pbm_disable_errors, pcbm_p);
891772Sjl139090
901772Sjl139090 /*
911772Sjl139090 * create the interrupt-priorities property if it doesn't
921772Sjl139090 * already exist to provide a hint as to the PIL level for
931772Sjl139090 * our interrupt.
941772Sjl139090 */
951772Sjl139090 if (ddi_getproplen(DDI_DEV_T_ANY, dip,
961772Sjl139090 DDI_PROP_DONTPASS, "interrupt-priorities",
971772Sjl139090 &len) != DDI_PROP_SUCCESS) {
981772Sjl139090 /* Create the interrupt-priorities property. */
991772Sjl139090 (void) ddi_prop_create(DDI_DEV_T_NONE, dip,
1001772Sjl139090 DDI_PROP_CANSLEEP, "interrupt-priorities",
1011772Sjl139090 (caddr_t)pcmu_pil, sizeof (pcmu_pil));
1021772Sjl139090 }
1031772Sjl139090 pcmu_pbm_configure(pcbm_p);
1041772Sjl139090 }
1051772Sjl139090
1061772Sjl139090 int
pcmu_pbm_register_intr(pcmu_pbm_t * pcbm_p)1071772Sjl139090 pcmu_pbm_register_intr(pcmu_pbm_t *pcbm_p)
1081772Sjl139090 {
1091772Sjl139090 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p;
1101772Sjl139090 uint32_t mondo;
1111772Sjl139090 int r = DDI_SUCCESS;
1121772Sjl139090
1131772Sjl139090 pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, pcmu_p->pcmu_inos[CBNINTR_PBM]);
1141772Sjl139090
1151772Sjl139090 /*
1161772Sjl139090 * Install the PCI error interrupt handler.
1171772Sjl139090 */
1181772Sjl139090 mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p,
1191772Sjl139090 pcmu_p->pcmu_inos[CBNINTR_PBM]);
1201772Sjl139090
121*2973Sgovinda VERIFY(add_ivintr(mondo, pcmu_pil[CBNINTR_PBM],
122*2973Sgovinda (intrfunc)pcmu_pbm_error_intr, (caddr_t)pcmu_p, NULL, NULL) == 0);
1231772Sjl139090
1241772Sjl139090 pcbm_p->pcbm_iblock_cookie = (void *)(uintptr_t)pcmu_pil[CBNINTR_PBM];
1251772Sjl139090
1261772Sjl139090 /*
1271772Sjl139090 * Create the pokefault mutex at the PIL below the error interrupt.
1281772Sjl139090 */
1291772Sjl139090
1301772Sjl139090 mutex_init(&pcbm_p->pcbm_pokeflt_mutex, NULL, MUTEX_DRIVER,
1311772Sjl139090 (void *)(uintptr_t)ipltospl(spltoipl(
1321772Sjl139090 (int)(uintptr_t)pcbm_p->pcbm_iblock_cookie) - 1));
1331772Sjl139090
1341772Sjl139090 return (PCMU_ATTACH_RETCODE(PCMU_PBM_OBJ, PCMU_OBJ_INTR_ADD, r));
1351772Sjl139090 }
1361772Sjl139090
1371772Sjl139090 void
pcmu_pbm_destroy(pcmu_t * pcmu_p)1381772Sjl139090 pcmu_pbm_destroy(pcmu_t *pcmu_p)
1391772Sjl139090 {
1401772Sjl139090 pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
1411772Sjl139090 pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p;
1421772Sjl139090 uint32_t mondo;
1431772Sjl139090
1441772Sjl139090 PCMU_DBG0(PCMU_DBG_DETACH, pcmu_p->pcmu_dip, "pcmu_pbm_destroy:\n");
1451772Sjl139090
1461772Sjl139090 mondo = PCMU_IB_INO_TO_MONDO(pcmu_p->pcmu_ib_p,
1471772Sjl139090 pcmu_p->pcmu_inos[CBNINTR_PBM]);
1481772Sjl139090
1491772Sjl139090 /*
1501772Sjl139090 * Free the pokefault mutex.
1511772Sjl139090 */
1521772Sjl139090 mutex_destroy(&pcbm_p->pcbm_pokeflt_mutex);
1531772Sjl139090
1541772Sjl139090 /*
1551772Sjl139090 * Remove the error interrupt.
1561772Sjl139090 */
1571772Sjl139090 intr_dist_rem(pcmu_pbm_intr_dist, pcbm_p);
1581772Sjl139090 pcmu_ib_intr_disable(pib_p,
1591772Sjl139090 pcmu_p->pcmu_inos[CBNINTR_PBM], PCMU_IB_INTR_WAIT);
160*2973Sgovinda
161*2973Sgovinda VERIFY(rem_ivintr(mondo, pcmu_pil[CBNINTR_PBM]) == 0);
1621772Sjl139090
1631772Sjl139090 /*
1641772Sjl139090 * Remove the error disable function.
1651772Sjl139090 */
1661772Sjl139090 bus_func_unregister(BF_TYPE_ERRDIS,
1671772Sjl139090 (busfunc_t)pcmu_pbm_disable_errors, pcbm_p);
1681772Sjl139090
1691772Sjl139090 pcmu_pbm_teardown(pcbm_p);
1701772Sjl139090
1711772Sjl139090 /*
1721772Sjl139090 * Free the pbm state structure.
1731772Sjl139090 */
1741772Sjl139090 kmem_free(pcbm_p, sizeof (pcmu_pbm_t));
1751772Sjl139090 pcmu_p->pcmu_pcbm_p = NULL;
1761772Sjl139090 }
1771772Sjl139090
1781772Sjl139090 static uint_t
pcmu_pbm_error_intr(caddr_t a)1791772Sjl139090 pcmu_pbm_error_intr(caddr_t a)
1801772Sjl139090 {
1811772Sjl139090 pcmu_t *pcmu_p = (pcmu_t *)a;
1821772Sjl139090 pcmu_pbm_t *pcbm_p = pcmu_p->pcmu_pcbm_p;
1831772Sjl139090 ddi_fm_error_t derr;
1841772Sjl139090 int err = DDI_FM_OK;
1851772Sjl139090 on_trap_data_t *otp = pcbm_p->pcbm_ontrap_data;
1861772Sjl139090
1871772Sjl139090 bzero(&derr, sizeof (ddi_fm_error_t));
1881772Sjl139090 derr.fme_version = DDI_FME_VERSION;
1891772Sjl139090 mutex_enter(&pcmu_p->pcmu_err_mutex);
1901772Sjl139090 if ((otp != NULL) && (otp->ot_prot & OT_DATA_ACCESS)) {
1911772Sjl139090 /*
1921772Sjl139090 * ddi_poke protection, check nexus and children for
1931772Sjl139090 * expected errors.
1941772Sjl139090 */
1951772Sjl139090 otp->ot_trap |= OT_DATA_ACCESS;
1961772Sjl139090 membar_sync();
1971772Sjl139090 derr.fme_flag = DDI_FM_ERR_POKE;
1981772Sjl139090 err = pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr,
1991772Sjl139090 (void *)pcmu_p, PCI_INTR_CALL);
2001772Sjl139090 } else if (pcmu_check_error(pcmu_p) != 0) {
2011772Sjl139090 /*
2021772Sjl139090 * unprotected error, check for all errors.
2031772Sjl139090 */
2041772Sjl139090 if (pcmu_errtrig_pa) {
2051772Sjl139090 (void) ldphysio(pcmu_errtrig_pa);
2061772Sjl139090 }
2071772Sjl139090 derr.fme_flag = DDI_FM_ERR_UNEXPECTED;
2081772Sjl139090 err = pcmu_pbm_err_handler(pcmu_p->pcmu_dip, &derr,
2091772Sjl139090 (void *)pcmu_p, PCI_INTR_CALL);
2101772Sjl139090 }
2111772Sjl139090
2121772Sjl139090 if (err == DDI_FM_FATAL) {
2131772Sjl139090 if (pcmu_panic_on_fatal_errors) {
2141772Sjl139090 mutex_exit(&pcmu_p->pcmu_err_mutex);
2151772Sjl139090 cmn_err(CE_PANIC, "%s-%d: Fatal PCI bus error(s)\n",
2161772Sjl139090 ddi_driver_name(pcmu_p->pcmu_dip),
2171772Sjl139090 ddi_get_instance(pcmu_p->pcmu_dip));
2181772Sjl139090 }
2191772Sjl139090 }
2201772Sjl139090
2211772Sjl139090 mutex_exit(&pcmu_p->pcmu_err_mutex);
2221772Sjl139090 pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, pcmu_p->pcmu_inos[CBNINTR_PBM]);
2231772Sjl139090 return (DDI_INTR_CLAIMED);
2241772Sjl139090 }
2251772Sjl139090
2261772Sjl139090 void
pcmu_pbm_suspend(pcmu_pbm_t * pcbm_p)2271772Sjl139090 pcmu_pbm_suspend(pcmu_pbm_t *pcbm_p)
2281772Sjl139090 {
2291772Sjl139090 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p;
2301772Sjl139090 pcmu_ib_ino_t ino = pcmu_p->pcmu_inos[CBNINTR_PBM];
2311772Sjl139090 pcbm_p->pcbm_imr_save = *ib_intr_map_reg_addr(pcmu_p->pcmu_ib_p, ino);
2321772Sjl139090 }
2331772Sjl139090
2341772Sjl139090 void
pcmu_pbm_resume(pcmu_pbm_t * pcbm_p)2351772Sjl139090 pcmu_pbm_resume(pcmu_pbm_t *pcbm_p)
2361772Sjl139090 {
2371772Sjl139090 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p;
2381772Sjl139090 pcmu_ib_ino_t ino = pcmu_p->pcmu_inos[CBNINTR_PBM];
2391772Sjl139090
2401772Sjl139090 pcmu_ib_nintr_clear(pcmu_p->pcmu_ib_p, ino);
2411772Sjl139090 *ib_intr_map_reg_addr(pcmu_p->pcmu_ib_p, ino) = pcbm_p->pcbm_imr_save;
2421772Sjl139090 }
2431772Sjl139090
2441772Sjl139090 void
pcmu_pbm_intr_dist(void * arg)2451772Sjl139090 pcmu_pbm_intr_dist(void *arg)
2461772Sjl139090 {
2471772Sjl139090 pcmu_pbm_t *pcbm_p = (pcmu_pbm_t *)arg;
2481772Sjl139090 pcmu_t *pcmu_p = pcbm_p->pcbm_pcmu_p;
2491772Sjl139090 pcmu_ib_t *pib_p = pcmu_p->pcmu_ib_p;
2501772Sjl139090 pcmu_ib_ino_t ino =
2511772Sjl139090 PCMU_IB_MONDO_TO_INO(pcmu_p->pcmu_inos[CBNINTR_PBM]);
2521772Sjl139090 mutex_enter(&pib_p->pib_intr_lock);
2531772Sjl139090 pcmu_ib_intr_dist_nintr(pib_p, ino, ib_intr_map_reg_addr(pib_p, ino));
2541772Sjl139090 mutex_exit(&pib_p->pib_intr_lock);
2551772Sjl139090 }
2561772Sjl139090
2571772Sjl139090 /*
2581772Sjl139090 * Function used to log PBM AFSR register bits and to lookup and fault
2591772Sjl139090 * handle associated with PBM AFAR register. Called by
2601772Sjl139090 * pcmu_pbm_err_handler with pcmu_err_mutex held.
2611772Sjl139090 */
2621772Sjl139090 int
pcmu_pbm_afsr_report(dev_info_t * dip,uint64_t fme_ena,pcmu_pbm_errstate_t * pbm_err_p)2631772Sjl139090 pcmu_pbm_afsr_report(dev_info_t *dip, uint64_t fme_ena,
2641772Sjl139090 pcmu_pbm_errstate_t *pbm_err_p)
2651772Sjl139090 {
2661772Sjl139090 int fatal = 0;
2671772Sjl139090 /* LINTED variable */
2681772Sjl139090 pcmu_t *pcmu_p = get_pcmu_soft_state(ddi_get_instance(dip));
2691772Sjl139090
2701772Sjl139090 ASSERT(MUTEX_HELD(&pcmu_p->pcmu_err_mutex));
2711772Sjl139090
2721772Sjl139090 pbm_err_p->pcbm_pri = PBM_PRIMARY;
2731772Sjl139090 (void) pcmu_pbm_classify(pbm_err_p);
2741772Sjl139090
2751772Sjl139090 /*
2761772Sjl139090 * We are currently not dealing with the multiple error
2771772Sjl139090 * case, for any secondary errors we will panic.
2781772Sjl139090 */
2791772Sjl139090 pbm_err_p->pcbm_pri = PBM_SECONDARY;
2801772Sjl139090 if (pcmu_pbm_classify(pbm_err_p)) {
2811772Sjl139090 fatal++;
2821772Sjl139090 pcmu_pbm_ereport_post(dip, fme_ena, pbm_err_p);
2831772Sjl139090 }
2841772Sjl139090
2851772Sjl139090 if (fatal) {
2861772Sjl139090 return (DDI_FM_FATAL);
2871772Sjl139090 }
2881772Sjl139090 return (DDI_FM_NONFATAL);
2891772Sjl139090 }
290