17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5a1ca9cb8Sarutz * Common Development and Distribution License (the "License"). 6a1ca9cb8Sarutz * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*39470729Skd93003 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Psycho+ specifics implementation: 307c478bd9Sstevel@tonic-gate * interrupt mapping register 317c478bd9Sstevel@tonic-gate * PBM configuration 327c478bd9Sstevel@tonic-gate * ECC and PBM error handling 337c478bd9Sstevel@tonic-gate * Iommu mapping handling 347c478bd9Sstevel@tonic-gate * Streaming Cache flushing 357c478bd9Sstevel@tonic-gate */ 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <sys/types.h> 387c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 397c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 407c478bd9Sstevel@tonic-gate #include <sys/async.h> 417c478bd9Sstevel@tonic-gate #include <sys/systm.h> 427c478bd9Sstevel@tonic-gate #include <sys/intreg.h> /* UPAID_TO_IGN() */ 43b0fc0e77Sgovinda #include <sys/ivintr.h> 447c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 457c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 467c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 477c478bd9Sstevel@tonic-gate #include <sys/fm/util.h> 487c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 497c478bd9Sstevel@tonic-gate #include <sys/iommutsb.h> 507c478bd9Sstevel@tonic-gate #include <sys/spl.h> 517c478bd9Sstevel@tonic-gate #include <sys/fm/util.h> 527c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h> 537c478bd9Sstevel@tonic-gate #include <sys/fm/io/pci.h> 547c478bd9Sstevel@tonic-gate #include <sys/fm/io/sun4upci.h> 557c478bd9Sstevel@tonic-gate #include <sys/pci/pci_obj.h> 567c478bd9Sstevel@tonic-gate #include <sys/pci/pcipsy.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 597c478bd9Sstevel@tonic-gate #include <sys/starfire.h> 607c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate static uint32_t pci_identity_init(pci_t *pci_p); 637c478bd9Sstevel@tonic-gate static int pci_intr_setup(pci_t *pci_p); 647c478bd9Sstevel@tonic-gate static void pci_pbm_errstate_get(pci_t *pci_p, pbm_errstate_t *pbm_err_p); 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate static pci_ksinfo_t *pci_name_kstat; 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 697c478bd9Sstevel@tonic-gate /* called by pci_attach() DDI_ATTACH to initialize pci objects */ 707c478bd9Sstevel@tonic-gate int 717c478bd9Sstevel@tonic-gate pci_obj_setup(pci_t *pci_p) 727c478bd9Sstevel@tonic-gate { 737c478bd9Sstevel@tonic-gate pci_common_t *cmn_p; 747c478bd9Sstevel@tonic-gate int ret; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate mutex_enter(&pci_global_mutex); 777c478bd9Sstevel@tonic-gate cmn_p = get_pci_common_soft_state(pci_p->pci_id); 787c478bd9Sstevel@tonic-gate if (cmn_p == NULL) { 797c478bd9Sstevel@tonic-gate uint_t id = pci_p->pci_id; 807c478bd9Sstevel@tonic-gate if (alloc_pci_common_soft_state(id) != DDI_SUCCESS) { 817c478bd9Sstevel@tonic-gate mutex_exit(&pci_global_mutex); 827c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate cmn_p = get_pci_common_soft_state(id); 857c478bd9Sstevel@tonic-gate cmn_p->pci_common_id = id; 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate ASSERT((pci_p->pci_side == 0) || (pci_p->pci_side == 1)); 897c478bd9Sstevel@tonic-gate if (cmn_p->pci_p[pci_p->pci_side]) { 907c478bd9Sstevel@tonic-gate /* second side attach */ 917c478bd9Sstevel@tonic-gate pci_p->pci_side = PCI_OTHER_SIDE(pci_p->pci_side); 927c478bd9Sstevel@tonic-gate ASSERT(cmn_p->pci_p[pci_p->pci_side] == NULL); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate cmn_p->pci_p[pci_p->pci_side] = pci_p; 967c478bd9Sstevel@tonic-gate pci_p->pci_common_p = cmn_p; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate if (cmn_p->pci_common_refcnt == 0) { 997c478bd9Sstevel@tonic-gate /* Perform allocation first to avoid delicate unwinding. */ 1007c478bd9Sstevel@tonic-gate if (pci_alloc_tsb(pci_p) != DDI_SUCCESS) { 1017c478bd9Sstevel@tonic-gate cmn_p->pci_p[pci_p->pci_side] = NULL; 1027c478bd9Sstevel@tonic-gate pci_p->pci_common_p = NULL; 1037c478bd9Sstevel@tonic-gate free_pci_common_soft_state(cmn_p->pci_common_id); 1047c478bd9Sstevel@tonic-gate mutex_exit(&pci_global_mutex); 1057c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate cmn_p->pci_common_tsb_cookie = pci_p->pci_tsb_cookie; 1087c478bd9Sstevel@tonic-gate cmn_p->pci_chip_id = pci_identity_init(pci_p); 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate ib_create(pci_p); 1117c478bd9Sstevel@tonic-gate cmn_p->pci_common_ib_p = pci_p->pci_ib_p; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate cb_create(pci_p); 1147c478bd9Sstevel@tonic-gate cmn_p->pci_common_cb_p = pci_p->pci_cb_p; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate iommu_create(pci_p); 1177c478bd9Sstevel@tonic-gate cmn_p->pci_common_iommu_p = pci_p->pci_iommu_p; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate ecc_create(pci_p); 1207c478bd9Sstevel@tonic-gate cmn_p->pci_common_ecc_p = pci_p->pci_ecc_p; 1217c478bd9Sstevel@tonic-gate } else { 1227c478bd9Sstevel@tonic-gate ASSERT(cmn_p->pci_common_refcnt == 1); 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate pci_p->pci_tsb_cookie = cmn_p->pci_common_tsb_cookie; 1257c478bd9Sstevel@tonic-gate pci_p->pci_ib_p = cmn_p->pci_common_ib_p; 1267c478bd9Sstevel@tonic-gate pci_p->pci_cb_p = cmn_p->pci_common_cb_p; 1277c478bd9Sstevel@tonic-gate pci_p->pci_iommu_p = cmn_p->pci_common_iommu_p; 1287c478bd9Sstevel@tonic-gate pci_p->pci_ecc_p = cmn_p->pci_common_ecc_p; 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate pbm_create(pci_p); 1327c478bd9Sstevel@tonic-gate sc_create(pci_p); 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate pci_fm_create(pci_p); 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate if ((ret = pci_intr_setup(pci_p)) != DDI_SUCCESS) 1377c478bd9Sstevel@tonic-gate goto done; 1387c478bd9Sstevel@tonic-gate if (CHIP_TYPE(pci_p) == PCI_CHIP_PSYCHO) 1397c478bd9Sstevel@tonic-gate pci_kstat_create(pci_p); 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate cmn_p->pci_common_attachcnt++; 1427c478bd9Sstevel@tonic-gate cmn_p->pci_common_refcnt++; 1437c478bd9Sstevel@tonic-gate done: 1447c478bd9Sstevel@tonic-gate mutex_exit(&pci_global_mutex); 1457c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) 1467c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "Interrupt register failure, returning 0x%x\n", 1477c478bd9Sstevel@tonic-gate ret); 1487c478bd9Sstevel@tonic-gate return (ret); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* called by pci_detach() DDI_DETACH to destroy pci objects */ 1527c478bd9Sstevel@tonic-gate void 1537c478bd9Sstevel@tonic-gate pci_obj_destroy(pci_t *pci_p) 1547c478bd9Sstevel@tonic-gate { 1557c478bd9Sstevel@tonic-gate pci_common_t *cmn_p; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate mutex_enter(&pci_global_mutex); 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate cmn_p = pci_p->pci_common_p; 1607c478bd9Sstevel@tonic-gate cmn_p->pci_common_refcnt--; 1617c478bd9Sstevel@tonic-gate cmn_p->pci_common_attachcnt--; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate pci_kstat_destroy(pci_p); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate sc_destroy(pci_p); 1667c478bd9Sstevel@tonic-gate pbm_destroy(pci_p); 1677c478bd9Sstevel@tonic-gate pci_fm_destroy(pci_p); 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate if (cmn_p->pci_common_refcnt != 0) { 1707c478bd9Sstevel@tonic-gate cmn_p->pci_p[pci_p->pci_side] = NULL; 1717c478bd9Sstevel@tonic-gate mutex_exit(&pci_global_mutex); 1727c478bd9Sstevel@tonic-gate return; 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate ecc_destroy(pci_p); 1767c478bd9Sstevel@tonic-gate iommu_destroy(pci_p); 1777c478bd9Sstevel@tonic-gate cb_destroy(pci_p); 1787c478bd9Sstevel@tonic-gate ib_destroy(pci_p); 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate free_pci_common_soft_state(cmn_p->pci_common_id); 1817c478bd9Sstevel@tonic-gate pci_intr_teardown(pci_p); 1827c478bd9Sstevel@tonic-gate mutex_exit(&pci_global_mutex); 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* called by pci_attach() DDI_RESUME to (re)initialize pci objects */ 1867c478bd9Sstevel@tonic-gate void 1877c478bd9Sstevel@tonic-gate pci_obj_resume(pci_t *pci_p) 1887c478bd9Sstevel@tonic-gate { 1897c478bd9Sstevel@tonic-gate pci_common_t *cmn_p = pci_p->pci_common_p; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate mutex_enter(&pci_global_mutex); 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate if (cmn_p->pci_common_attachcnt == 0) { 1947c478bd9Sstevel@tonic-gate ib_configure(pci_p->pci_ib_p); 1957c478bd9Sstevel@tonic-gate iommu_configure(pci_p->pci_iommu_p); 1967c478bd9Sstevel@tonic-gate ecc_configure(pci_p); 1977c478bd9Sstevel@tonic-gate ib_resume(pci_p->pci_ib_p); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate pbm_configure(pci_p->pci_pbm_p); 2017c478bd9Sstevel@tonic-gate sc_configure(pci_p->pci_sc_p); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if (cmn_p->pci_common_attachcnt == 0) 2047c478bd9Sstevel@tonic-gate cb_resume(pci_p->pci_cb_p); 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate pbm_resume(pci_p->pci_pbm_p); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate cmn_p->pci_common_attachcnt++; 2097c478bd9Sstevel@tonic-gate mutex_exit(&pci_global_mutex); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* called by pci_detach() DDI_SUSPEND to suspend pci objects */ 2137c478bd9Sstevel@tonic-gate void 2147c478bd9Sstevel@tonic-gate pci_obj_suspend(pci_t *pci_p) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate mutex_enter(&pci_global_mutex); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate pbm_suspend(pci_p->pci_pbm_p); 2197c478bd9Sstevel@tonic-gate if (!--pci_p->pci_common_p->pci_common_attachcnt) { 2207c478bd9Sstevel@tonic-gate ib_suspend(pci_p->pci_ib_p); 2217c478bd9Sstevel@tonic-gate cb_suspend(pci_p->pci_cb_p); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate mutex_exit(&pci_global_mutex); 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate static uint32_t javelin_prom_fix[] = {0xfff800, 0, 0, 0x3f}; 2287c478bd9Sstevel@tonic-gate static int 2297c478bd9Sstevel@tonic-gate pci_intr_setup(pci_t *pci_p) 2307c478bd9Sstevel@tonic-gate { 2317c478bd9Sstevel@tonic-gate extern char *platform; 2327c478bd9Sstevel@tonic-gate dev_info_t *dip = pci_p->pci_dip; 2337c478bd9Sstevel@tonic-gate pbm_t *pbm_p = pci_p->pci_pbm_p; 2347c478bd9Sstevel@tonic-gate cb_t *cb_p = pci_p->pci_cb_p; 2357c478bd9Sstevel@tonic-gate int i, no_of_intrs; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * This is a hack to fix a broken imap entry in the javelin PROM. 2397c478bd9Sstevel@tonic-gate * see bugid 4226603 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate if (strcmp((const char *)&platform, "SUNW,Ultra-250") == 0) 2427c478bd9Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 2437c478bd9Sstevel@tonic-gate "interrupt-map-mask", (caddr_t)javelin_prom_fix, 2447c478bd9Sstevel@tonic-gate sizeof (javelin_prom_fix)); 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* 2477c478bd9Sstevel@tonic-gate * Get the interrupts property. 2487c478bd9Sstevel@tonic-gate */ 249a3282898Scth if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2507c478bd9Sstevel@tonic-gate "interrupts", (caddr_t)&pci_p->pci_inos, 2517c478bd9Sstevel@tonic-gate &pci_p->pci_inos_len) != DDI_SUCCESS) 2527c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "%s%d: no interrupts property\n", 2537c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* 2567c478bd9Sstevel@tonic-gate * figure out number of interrupts in the "interrupts" property 2577c478bd9Sstevel@tonic-gate * and convert them all into ino. 2587c478bd9Sstevel@tonic-gate */ 2597c478bd9Sstevel@tonic-gate i = ddi_getprop(DDI_DEV_T_ANY, dip, 0, "#interrupt-cells", 1); 2607c478bd9Sstevel@tonic-gate i = CELLS_1275_TO_BYTES(i); 2617c478bd9Sstevel@tonic-gate no_of_intrs = pci_p->pci_inos_len / i; 2627c478bd9Sstevel@tonic-gate for (i = 0; i < no_of_intrs; i++) 2637c478bd9Sstevel@tonic-gate pci_p->pci_inos[i] = IB_MONDO_TO_INO(pci_p->pci_inos[i]); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate if (pci_p->pci_common_p->pci_common_refcnt == 0) { 2667c478bd9Sstevel@tonic-gate cb_p->cb_no_of_inos = no_of_intrs; 2677c478bd9Sstevel@tonic-gate if (i = cb_register_intr(pci_p)) 2687c478bd9Sstevel@tonic-gate goto teardown; 2697c478bd9Sstevel@tonic-gate if (i = ecc_register_intr(pci_p)) 2707c478bd9Sstevel@tonic-gate goto teardown; 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate intr_dist_add(cb_intr_dist, cb_p); 2737c478bd9Sstevel@tonic-gate cb_enable_intr(pci_p); 2747c478bd9Sstevel@tonic-gate ecc_enable_intr(pci_p); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if (i = pbm_register_intr(pbm_p)) { 2787c478bd9Sstevel@tonic-gate if (pci_p->pci_common_p->pci_common_refcnt == 0) 2797c478bd9Sstevel@tonic-gate intr_dist_rem(cb_intr_dist, cb_p); 2807c478bd9Sstevel@tonic-gate goto teardown; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate intr_dist_add(pbm_intr_dist, pbm_p); 2837c478bd9Sstevel@tonic-gate ib_intr_enable(pci_p, pci_p->pci_inos[CBNINTR_PBM]); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate if (pci_p->pci_common_p->pci_common_refcnt == 0) 2867c478bd9Sstevel@tonic-gate intr_dist_add_weighted(ib_intr_dist_all, pci_p->pci_ib_p); 2877c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2887c478bd9Sstevel@tonic-gate teardown: 2897c478bd9Sstevel@tonic-gate pci_intr_teardown(pci_p); 2907c478bd9Sstevel@tonic-gate return (i); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * pci_fix_ranges - fixes the config space entry of the "ranges" 2957c478bd9Sstevel@tonic-gate * property on psycho+ platforms 2967c478bd9Sstevel@tonic-gate */ 2977c478bd9Sstevel@tonic-gate void 2987c478bd9Sstevel@tonic-gate pci_fix_ranges(pci_ranges_t *rng_p, int rng_entries) 2997c478bd9Sstevel@tonic-gate { 3007c478bd9Sstevel@tonic-gate int i; 3017c478bd9Sstevel@tonic-gate for (i = 0; i < rng_entries; i++, rng_p++) 3027c478bd9Sstevel@tonic-gate if ((rng_p->child_high & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) 3037c478bd9Sstevel@tonic-gate rng_p->parent_low |= rng_p->child_high; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * map_pci_registers 3087c478bd9Sstevel@tonic-gate * 3097c478bd9Sstevel@tonic-gate * This function is called from the attach routine to map the registers 3107c478bd9Sstevel@tonic-gate * accessed by this driver. 3117c478bd9Sstevel@tonic-gate * 3127c478bd9Sstevel@tonic-gate * used by: pci_attach() 3137c478bd9Sstevel@tonic-gate * 3147c478bd9Sstevel@tonic-gate * return value: DDI_FAILURE on failure 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate int 3177c478bd9Sstevel@tonic-gate map_pci_registers(pci_t *pci_p, dev_info_t *dip) 3187c478bd9Sstevel@tonic-gate { 3197c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t attr; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 3227c478bd9Sstevel@tonic-gate attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 3257c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 0, &pci_p->pci_address[0], 0, 0, 3267c478bd9Sstevel@tonic-gate &attr, &pci_p->pci_ac[0]) != DDI_SUCCESS) { 3277c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: unable to map reg entry 0\n", 3287c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 3297c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate /* 3327c478bd9Sstevel@tonic-gate * if we don't have streaming buffer, then we don't have 3337c478bd9Sstevel@tonic-gate * pci_address[2]. 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate if (pci_stream_buf_exists && 3367c478bd9Sstevel@tonic-gate ddi_regs_map_setup(dip, 2, &pci_p->pci_address[2], 0, 0, 3377c478bd9Sstevel@tonic-gate &attr, &pci_p->pci_ac[2]) != DDI_SUCCESS) { 3387c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: unable to map reg entry 2\n", 3397c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 3407c478bd9Sstevel@tonic-gate ddi_regs_map_free(&pci_p->pci_ac[0]); 3417c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate /* 3457c478bd9Sstevel@tonic-gate * The second register set contains the bridge's configuration 3467c478bd9Sstevel@tonic-gate * header. This header is at the very beginning of the bridge's 3477c478bd9Sstevel@tonic-gate * configuration space. This space has litte-endian byte order. 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 3507c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, 1, &pci_p->pci_address[1], 0, 3517c478bd9Sstevel@tonic-gate PCI_CONF_HDR_SIZE, &attr, &pci_p->pci_ac[1]) != DDI_SUCCESS) { 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: unable to map reg entry 1\n", 3547c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 3557c478bd9Sstevel@tonic-gate ddi_regs_map_free(&pci_p->pci_ac[0]); 3567c478bd9Sstevel@tonic-gate if (pci_stream_buf_exists) 3577c478bd9Sstevel@tonic-gate ddi_regs_map_free(&pci_p->pci_ac[2]); 3587c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate DEBUG3(DBG_ATTACH, dip, "address (%p,%p,%p)\n", 3617c478bd9Sstevel@tonic-gate pci_p->pci_address[0], pci_p->pci_address[1], 3627c478bd9Sstevel@tonic-gate pci_p->pci_address[2]); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * unmap_pci_registers: 3697c478bd9Sstevel@tonic-gate * 3707c478bd9Sstevel@tonic-gate * This routine unmap the registers mapped by map_pci_registers. 3717c478bd9Sstevel@tonic-gate * 3727c478bd9Sstevel@tonic-gate * used by: pci_detach() 3737c478bd9Sstevel@tonic-gate * 3747c478bd9Sstevel@tonic-gate * return value: none 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate void 3777c478bd9Sstevel@tonic-gate unmap_pci_registers(pci_t *pci_p) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate ddi_regs_map_free(&pci_p->pci_ac[0]); 3807c478bd9Sstevel@tonic-gate ddi_regs_map_free(&pci_p->pci_ac[1]); 3817c478bd9Sstevel@tonic-gate if (pci_stream_buf_exists) 3827c478bd9Sstevel@tonic-gate ddi_regs_map_free(&pci_p->pci_ac[2]); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * These convenience wrappers relies on map_pci_registers() to setup 3877c478bd9Sstevel@tonic-gate * pci_address[0-2] correctly at first. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate /* The psycho+ reg base is at 1fe.0000.0000 */ 3907c478bd9Sstevel@tonic-gate static uintptr_t 3917c478bd9Sstevel@tonic-gate get_reg_base(pci_t *pci_p) 3927c478bd9Sstevel@tonic-gate { 3937c478bd9Sstevel@tonic-gate return ((uintptr_t)pci_p->pci_address[pci_stream_buf_exists ? 2 : 0]); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* The psycho+ config reg base is always the 2nd reg entry */ 3977c478bd9Sstevel@tonic-gate static uintptr_t 3987c478bd9Sstevel@tonic-gate get_config_reg_base(pci_t *pci_p) 3997c478bd9Sstevel@tonic-gate { 4007c478bd9Sstevel@tonic-gate return ((uintptr_t)(pci_p->pci_address[1])); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate uint64_t 4047c478bd9Sstevel@tonic-gate ib_get_map_reg(ib_mondo_t mondo, uint32_t cpu_id) 4057c478bd9Sstevel@tonic-gate { 4067c478bd9Sstevel@tonic-gate return ((mondo) | (cpu_id << COMMON_INTR_MAP_REG_TID_SHIFT) | 4077c478bd9Sstevel@tonic-gate COMMON_INTR_MAP_REG_VALID); 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate uint32_t 4127c478bd9Sstevel@tonic-gate ib_map_reg_get_cpu(volatile uint64_t reg) 4137c478bd9Sstevel@tonic-gate { 4147c478bd9Sstevel@tonic-gate return ((reg & COMMON_INTR_MAP_REG_TID) >> 4157c478bd9Sstevel@tonic-gate COMMON_INTR_MAP_REG_TID_SHIFT); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate uint64_t * 4197c478bd9Sstevel@tonic-gate ib_intr_map_reg_addr(ib_t *ib_p, ib_ino_t ino) 4207c478bd9Sstevel@tonic-gate { 4217c478bd9Sstevel@tonic-gate uint64_t *addr; 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate if (ino & 0x20) 4247c478bd9Sstevel@tonic-gate addr = (uint64_t *)(ib_p->ib_obio_intr_map_regs + 4257c478bd9Sstevel@tonic-gate (((uint_t)ino & 0x1f) << 3)); 4267c478bd9Sstevel@tonic-gate else 4277c478bd9Sstevel@tonic-gate addr = (uint64_t *)(ib_p->ib_slot_intr_map_regs + 4287c478bd9Sstevel@tonic-gate (((uint_t)ino & 0x3c) << 1)); 4297c478bd9Sstevel@tonic-gate return (addr); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate uint64_t * 4337c478bd9Sstevel@tonic-gate ib_clear_intr_reg_addr(ib_t *ib_p, ib_ino_t ino) 4347c478bd9Sstevel@tonic-gate { 4357c478bd9Sstevel@tonic-gate uint64_t *addr; 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate if (ino & 0x20) 4387c478bd9Sstevel@tonic-gate addr = (uint64_t *)(ib_p->ib_obio_clear_intr_regs + 4397c478bd9Sstevel@tonic-gate (((uint_t)ino & 0x1f) << 3)); 4407c478bd9Sstevel@tonic-gate else 4417c478bd9Sstevel@tonic-gate addr = (uint64_t *)(ib_p->ib_slot_clear_intr_regs + 4427c478bd9Sstevel@tonic-gate (((uint_t)ino & 0x1f) << 3)); 4437c478bd9Sstevel@tonic-gate return (addr); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * psycho have one mapping register per slot 4487c478bd9Sstevel@tonic-gate */ 4497c478bd9Sstevel@tonic-gate void 4507c478bd9Sstevel@tonic-gate ib_ino_map_reg_share(ib_t *ib_p, ib_ino_t ino, ib_ino_info_t *ino_p) 4517c478bd9Sstevel@tonic-gate { 4527c478bd9Sstevel@tonic-gate if (!IB_IS_OBIO_INO(ino)) { 4537c478bd9Sstevel@tonic-gate ASSERT(ino_p->ino_slot_no < 8); 4547c478bd9Sstevel@tonic-gate ib_p->ib_map_reg_counters[ino_p->ino_slot_no]++; 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate /* 4597c478bd9Sstevel@tonic-gate * return true if the ino shares mapping register with other interrupts 4607c478bd9Sstevel@tonic-gate * of the same slot, or is still shared by other On-board devices. 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate int 4637c478bd9Sstevel@tonic-gate ib_ino_map_reg_unshare(ib_t *ib_p, ib_ino_t ino, ib_ino_info_t *ino_p) 4647c478bd9Sstevel@tonic-gate { 4657c478bd9Sstevel@tonic-gate ASSERT(IB_IS_OBIO_INO(ino) || ino_p->ino_slot_no < 8); 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (IB_IS_OBIO_INO(ino)) 468b0fc0e77Sgovinda return (ino_p->ino_ipil_size); 4697c478bd9Sstevel@tonic-gate else 4707c478bd9Sstevel@tonic-gate return (--ib_p->ib_map_reg_counters[ino_p->ino_slot_no]); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4747c478bd9Sstevel@tonic-gate void 4757c478bd9Sstevel@tonic-gate pci_pbm_intr_dist(pbm_t *pbm_p) 4767c478bd9Sstevel@tonic-gate { 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate uintptr_t 4807c478bd9Sstevel@tonic-gate pci_ib_setup(ib_t *ib_p) 4817c478bd9Sstevel@tonic-gate { 4827c478bd9Sstevel@tonic-gate pci_t *pci_p = ib_p->ib_pci_p; 4837c478bd9Sstevel@tonic-gate uintptr_t a = get_reg_base(pci_p); 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate ib_p->ib_ign = PCI_ID_TO_IGN(pci_p->pci_id); 4867c478bd9Sstevel@tonic-gate ib_p->ib_max_ino = PSYCHO_MAX_INO; 4877c478bd9Sstevel@tonic-gate ib_p->ib_slot_intr_map_regs = a + PSYCHO_IB_SLOT_INTR_MAP_REG_OFFSET; 4887c478bd9Sstevel@tonic-gate ib_p->ib_obio_intr_map_regs = a + PSYCHO_IB_OBIO_INTR_MAP_REG_OFFSET; 4897c478bd9Sstevel@tonic-gate ib_p->ib_obio_clear_intr_regs = 4907c478bd9Sstevel@tonic-gate a + PSYCHO_IB_OBIO_CLEAR_INTR_REG_OFFSET; 4917c478bd9Sstevel@tonic-gate return (a); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate uint32_t 4957c478bd9Sstevel@tonic-gate pci_xlate_intr(dev_info_t *dip, dev_info_t *rdip, ib_t *ib_p, uint32_t intr) 4967c478bd9Sstevel@tonic-gate { 4977c478bd9Sstevel@tonic-gate int32_t len; 4987c478bd9Sstevel@tonic-gate dev_info_t *cdip; 4997c478bd9Sstevel@tonic-gate pci_regspec_t *pci_rp; 5007c478bd9Sstevel@tonic-gate uint32_t bus, dev, phys_hi; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate if ((intr > PCI_INTD) || (intr < PCI_INTA)) 5037c478bd9Sstevel@tonic-gate goto done; 5047c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, rdip, NULL, "interrupt-map")) 5057c478bd9Sstevel@tonic-gate goto done; 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * Hack for pre 1275 imap machines e.g. quark & tazmo 5087c478bd9Sstevel@tonic-gate * We need to turn any PCI interrupts into ino interrupts. machines 5097c478bd9Sstevel@tonic-gate * supporting imap will have this done in the map. 5107c478bd9Sstevel@tonic-gate */ 5117c478bd9Sstevel@tonic-gate cdip = get_my_childs_dip(dip, rdip); 5127c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "reg", 5137c478bd9Sstevel@tonic-gate (caddr_t)&pci_rp, &len) != DDI_SUCCESS) 5147c478bd9Sstevel@tonic-gate return (0); 5157c478bd9Sstevel@tonic-gate phys_hi = pci_rp->pci_phys_hi; 5167c478bd9Sstevel@tonic-gate kmem_free(pci_rp, len); 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate bus = PCI_REG_BUS_G(phys_hi); 5197c478bd9Sstevel@tonic-gate dev = PCI_REG_DEV_G(phys_hi); 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * The ino for a given device id is derived as 0BSSNN where 5237c478bd9Sstevel@tonic-gate * 5247c478bd9Sstevel@tonic-gate * B = 0 for bus A, 1 for bus B 5257c478bd9Sstevel@tonic-gate * SS = dev - 1 for bus A, dev - 2 for bus B 5267c478bd9Sstevel@tonic-gate * NN = 00 for INTA#, 01 for INTB#, 10 for INTC#, 11 for INTD# 5277c478bd9Sstevel@tonic-gate * 5287c478bd9Sstevel@tonic-gate * if pci bus number > 0x80, then devices are located on the A side(66) 5297c478bd9Sstevel@tonic-gate */ 5307c478bd9Sstevel@tonic-gate DEBUG3(DBG_IB, dip, "pci_xlate_intr: bus=%x, dev=%x, intr=%x\n", 5317c478bd9Sstevel@tonic-gate bus, dev, intr); 5327c478bd9Sstevel@tonic-gate intr--; 5337c478bd9Sstevel@tonic-gate intr |= (bus & 0x80) ? ((dev - 1) << 2) : (0x10 | ((dev - 2) << 2)); 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate DEBUG1(DBG_IB, dip, "pci_xlate_intr: done ino=%x\n", intr); 5367c478bd9Sstevel@tonic-gate done: 5377c478bd9Sstevel@tonic-gate return (IB_INO_TO_MONDO(ib_p, intr)); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* 5417c478bd9Sstevel@tonic-gate * Return the cpuid to to be used for an ino. Psycho has special slot-cpu 5427c478bd9Sstevel@tonic-gate * constraints on cpu assignment: 5437c478bd9Sstevel@tonic-gate * 5447c478bd9Sstevel@tonic-gate * On multi-function pci cards, functions have separate devinfo nodes and 5457c478bd9Sstevel@tonic-gate * interrupts. Some pci support hardware, such as the psycho/pcipsy chip, 5467c478bd9Sstevel@tonic-gate * control interrupt-to-cpu binding on a per pci-slot basis instead of per 5477c478bd9Sstevel@tonic-gate * function. For hardware like this, if an interrupt for one function has 5487c478bd9Sstevel@tonic-gate * already been directed to a particular cpu, we can't choose a different 5497c478bd9Sstevel@tonic-gate * cpu for another function implemented in the same pci-slot - if we did 5507c478bd9Sstevel@tonic-gate * we would be redirecting the first function too (which causes problems 5517c478bd9Sstevel@tonic-gate * for consistent interrupt distribution). 5527c478bd9Sstevel@tonic-gate * 5537c478bd9Sstevel@tonic-gate * This function determines if there is already an established slot-oriented 5547c478bd9Sstevel@tonic-gate * interrupt-to-cpu binding established, if there is then it returns that 5557c478bd9Sstevel@tonic-gate * cpu. Otherwise a new cpu is selected by intr_dist_cpuid(). 5567c478bd9Sstevel@tonic-gate * 5577c478bd9Sstevel@tonic-gate * The devinfo node we are trying to associate a cpu with is 558b0fc0e77Sgovinda * ino_p->ino_ipil_p->ipil_ih_head->ih_dip. 5597c478bd9Sstevel@tonic-gate */ 5607c478bd9Sstevel@tonic-gate uint32_t 5617c478bd9Sstevel@tonic-gate pci_intr_dist_cpuid(ib_t *ib_p, ib_ino_info_t *ino_p) 5627c478bd9Sstevel@tonic-gate { 563b0fc0e77Sgovinda dev_info_t *rdip = ino_p->ino_ipil_p->ipil_ih_head->ih_dip; 5647c478bd9Sstevel@tonic-gate dev_info_t *prdip = ddi_get_parent(rdip); 5657c478bd9Sstevel@tonic-gate ib_ino_info_t *sino_p; 5667c478bd9Sstevel@tonic-gate dev_info_t *sdip; 5677c478bd9Sstevel@tonic-gate dev_info_t *psdip; 5687c478bd9Sstevel@tonic-gate char *buf1 = NULL, *buf2 = NULL; 5697c478bd9Sstevel@tonic-gate char *s1, *s2, *s3; 5707c478bd9Sstevel@tonic-gate int l2; 5717c478bd9Sstevel@tonic-gate int cpu_id; 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* must be psycho driver parent (not ebus) */ 5747c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(prdip), "pcipsy") != 0) 5757c478bd9Sstevel@tonic-gate goto newcpu; 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate /* 5787c478bd9Sstevel@tonic-gate * From PCI 1275 binding: 2.2.1.3 Unit Address representation: 5797c478bd9Sstevel@tonic-gate * Since the "unit-number" is the address that appears in on Open 5807c478bd9Sstevel@tonic-gate * Firmware 'device path', it follows that only the DD and DD,FF 5817c478bd9Sstevel@tonic-gate * forms of the text representation can appear in a 'device path'. 5827c478bd9Sstevel@tonic-gate * 5837c478bd9Sstevel@tonic-gate * The rdip unit address is of the form "DD[,FF]". Define two 5847c478bd9Sstevel@tonic-gate * unit address strings that represent same-slot use: "DD" and "DD,". 5857c478bd9Sstevel@tonic-gate * The first compare uses strcmp, the second uses strncmp. 5867c478bd9Sstevel@tonic-gate */ 5877c478bd9Sstevel@tonic-gate s1 = ddi_get_name_addr(rdip); 5887c478bd9Sstevel@tonic-gate if (s1 == NULL) 5897c478bd9Sstevel@tonic-gate goto newcpu; 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate buf1 = kmem_alloc(MAXNAMELEN, KM_SLEEP); /* strcmp */ 5927c478bd9Sstevel@tonic-gate buf2 = kmem_alloc(MAXNAMELEN, KM_SLEEP); /* strncmp */ 5937c478bd9Sstevel@tonic-gate s1 = strcpy(buf1, s1); 5947c478bd9Sstevel@tonic-gate s2 = strcpy(buf2, s1); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate s1 = strrchr(s1, ','); 5977c478bd9Sstevel@tonic-gate if (s1) { 5987c478bd9Sstevel@tonic-gate *s1 = '\0'; /* have "DD,FF" */ 5997c478bd9Sstevel@tonic-gate s1 = buf1; /* search via strcmp "DD" */ 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate s2 = strrchr(s2, ','); 6027c478bd9Sstevel@tonic-gate *(s2 + 1) = '\0'; 6037c478bd9Sstevel@tonic-gate s2 = buf2; 6047c478bd9Sstevel@tonic-gate l2 = strlen(s2); /* search via strncmp "DD," */ 6057c478bd9Sstevel@tonic-gate } else { 6067c478bd9Sstevel@tonic-gate (void) strcat(s2, ","); /* have "DD" */ 6077c478bd9Sstevel@tonic-gate l2 = strlen(s2); /* search via strncmp "DD," */ 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* 6117c478bd9Sstevel@tonic-gate * Search the established ino list for devinfo nodes bound 6127c478bd9Sstevel@tonic-gate * to an ino that matches one of the slot use strings. 6137c478bd9Sstevel@tonic-gate */ 6147c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ib_p->ib_ino_lst_mutex)); 615b0fc0e77Sgovinda for (sino_p = ib_p->ib_ino_lst; sino_p; sino_p = sino_p->ino_next_p) { 6167c478bd9Sstevel@tonic-gate /* skip self and non-established */ 6177c478bd9Sstevel@tonic-gate if ((sino_p == ino_p) || (sino_p->ino_established == 0)) 6187c478bd9Sstevel@tonic-gate continue; 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate /* skip non-siblings */ 621b0fc0e77Sgovinda sdip = sino_p->ino_ipil_p->ipil_ih_head->ih_dip; 6227c478bd9Sstevel@tonic-gate psdip = ddi_get_parent(sdip); 6237c478bd9Sstevel@tonic-gate if (psdip != prdip) 6247c478bd9Sstevel@tonic-gate continue; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* must be psycho driver parent (not ebus) */ 6277c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(psdip), "pcipsy") != 0) 6287c478bd9Sstevel@tonic-gate continue; 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate s3 = ddi_get_name_addr(sdip); 6317c478bd9Sstevel@tonic-gate if ((s1 && (strcmp(s1, s3) == 0)) || 6327c478bd9Sstevel@tonic-gate (strncmp(s2, s3, l2) == 0)) { 6337c478bd9Sstevel@tonic-gate extern int intr_dist_debug; 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate if (intr_dist_debug) 6367c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "intr_dist: " 6377c478bd9Sstevel@tonic-gate "pcipsy`pci_intr_dist_cpuid " 6387c478bd9Sstevel@tonic-gate "%s#%d %s: cpu %d established " 6397c478bd9Sstevel@tonic-gate "by %s#%d %s\n", ddi_driver_name(rdip), 6407c478bd9Sstevel@tonic-gate ddi_get_instance(rdip), 6417c478bd9Sstevel@tonic-gate ddi_deviname(rdip, buf1), sino_p->ino_cpuid, 6427c478bd9Sstevel@tonic-gate ddi_driver_name(sdip), 6437c478bd9Sstevel@tonic-gate ddi_get_instance(sdip), 6447c478bd9Sstevel@tonic-gate ddi_deviname(sdip, buf2)); 6457c478bd9Sstevel@tonic-gate break; 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* If a slot use match is found then use established cpu */ 6507c478bd9Sstevel@tonic-gate if (sino_p) { 6517c478bd9Sstevel@tonic-gate cpu_id = sino_p->ino_cpuid; /* target established cpu */ 6527c478bd9Sstevel@tonic-gate goto out; 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate newcpu: cpu_id = intr_dist_cpuid(); /* target new cpu */ 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate out: if (buf1) 6587c478bd9Sstevel@tonic-gate kmem_free(buf1, MAXNAMELEN); 6597c478bd9Sstevel@tonic-gate if (buf2) 6607c478bd9Sstevel@tonic-gate kmem_free(buf2, MAXNAMELEN); 6617c478bd9Sstevel@tonic-gate return (cpu_id); 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6669129170aSarutz static void 6679129170aSarutz cb_thermal_timeout(void *arg) 6687c478bd9Sstevel@tonic-gate { 6697c478bd9Sstevel@tonic-gate do_shutdown(); 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate /* 6727c478bd9Sstevel@tonic-gate * In case do_shutdown() fails to halt the system. 6737c478bd9Sstevel@tonic-gate */ 6747c478bd9Sstevel@tonic-gate (void) timeout((void(*)(void *))power_down, NULL, 6757c478bd9Sstevel@tonic-gate thermal_powerdown_delay * hz); 6767c478bd9Sstevel@tonic-gate } 6779129170aSarutz 6789129170aSarutz /* 6799129170aSarutz * High-level handler for psycho's CBNINTR_THERMAL interrupt. 6809129170aSarutz * 6819129170aSarutz * Use timeout(9f) to implement the core functionality so that the 6829129170aSarutz * timeout(9f) function can sleep, if needed. 6839129170aSarutz */ 6849129170aSarutz /*ARGSUSED*/ 6859129170aSarutz uint_t 6869129170aSarutz cb_thermal_intr(caddr_t a) 6879129170aSarutz { 6889129170aSarutz cmn_err(CE_WARN, "pci: Thermal warning detected!\n"); 6899129170aSarutz if (pci_thermal_intr_fatal) { 6909129170aSarutz (void) timeout(cb_thermal_timeout, NULL, 0); 6919129170aSarutz } 6927c478bd9Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate void 6967c478bd9Sstevel@tonic-gate pci_cb_teardown(pci_t *pci_p) 6977c478bd9Sstevel@tonic-gate { 6987c478bd9Sstevel@tonic-gate cb_t *cb_p = pci_p->pci_cb_p; 6997c478bd9Sstevel@tonic-gate uint32_t mondo; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate if (pci_p->pci_thermal_interrupt != -1) { 7027c478bd9Sstevel@tonic-gate mondo = ((pci_p->pci_cb_p->cb_ign << PCI_INO_BITS) | 7037c478bd9Sstevel@tonic-gate pci_p->pci_inos[CBNINTR_THERMAL]); 7047c478bd9Sstevel@tonic-gate mondo = CB_MONDO_TO_XMONDO(pci_p->pci_cb_p, mondo); 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate cb_disable_nintr(cb_p, CBNINTR_THERMAL, IB_INTR_WAIT); 707b0fc0e77Sgovinda VERIFY(rem_ivintr(mondo, pci_pil[CBNINTR_THERMAL]) == 0); 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 7107c478bd9Sstevel@tonic-gate pc_ittrans_uninit(cb_p->cb_ittrans_cookie); 7117c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate int 7157c478bd9Sstevel@tonic-gate cb_register_intr(pci_t *pci_p) 7167c478bd9Sstevel@tonic-gate { 7177c478bd9Sstevel@tonic-gate uint32_t mondo; 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate if (pci_p->pci_thermal_interrupt == -1) 7207c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate mondo = ((pci_p->pci_cb_p->cb_ign << PCI_INO_BITS) | 7237c478bd9Sstevel@tonic-gate pci_p->pci_inos[CBNINTR_THERMAL]); 7247c478bd9Sstevel@tonic-gate mondo = CB_MONDO_TO_XMONDO(pci_p->pci_cb_p, mondo); 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate VERIFY(add_ivintr(mondo, pci_pil[CBNINTR_THERMAL], 727b0fc0e77Sgovinda (intrfunc)cb_thermal_intr, (caddr_t)pci_p->pci_cb_p, 728b0fc0e77Sgovinda NULL, NULL) == 0); 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate return (PCI_ATTACH_RETCODE(PCI_CB_OBJ, PCI_OBJ_INTR_ADD, DDI_SUCCESS)); 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate void 7347c478bd9Sstevel@tonic-gate cb_enable_intr(pci_t *pci_p) 7357c478bd9Sstevel@tonic-gate { 7367c478bd9Sstevel@tonic-gate if (pci_p->pci_thermal_interrupt != -1) 7377c478bd9Sstevel@tonic-gate cb_enable_nintr(pci_p, CBNINTR_THERMAL); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate uint64_t 7417c478bd9Sstevel@tonic-gate cb_ino_to_map_pa(cb_t *cb_p, ib_ino_t ino) 7427c478bd9Sstevel@tonic-gate { 7437c478bd9Sstevel@tonic-gate return (cb_p->cb_map_pa + ((ino & 0x1f) << 3)); 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate uint64_t 7477c478bd9Sstevel@tonic-gate cb_ino_to_clr_pa(cb_t *cb_p, ib_ino_t ino) 7487c478bd9Sstevel@tonic-gate { 7497c478bd9Sstevel@tonic-gate return (cb_p->cb_clr_pa + ((ino & 0x1f) << 3)); 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* 7537c478bd9Sstevel@tonic-gate * allow removal of exported/shared thermal interrupt 7547c478bd9Sstevel@tonic-gate */ 7557c478bd9Sstevel@tonic-gate int 7567c478bd9Sstevel@tonic-gate cb_remove_xintr(pci_t *pci_p, dev_info_t *dip, dev_info_t *rdip, 7577c478bd9Sstevel@tonic-gate ib_ino_t ino, ib_mondo_t mondo) 7587c478bd9Sstevel@tonic-gate { 7597c478bd9Sstevel@tonic-gate if (ino != pci_p->pci_inos[CBNINTR_THERMAL]) 7607c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate cb_disable_nintr(pci_p->pci_cb_p, CBNINTR_THERMAL, IB_INTR_WAIT); 763b0fc0e77Sgovinda VERIFY(rem_ivintr(mondo, pci_pil[CBNINTR_THERMAL]) == 0); 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate DEBUG1(DBG_R_INTX, dip, "remove xintr %x\n", ino); 7667c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate int 7707c478bd9Sstevel@tonic-gate pci_ecc_add_intr(pci_t *pci_p, int inum, ecc_intr_info_t *eii_p) 7717c478bd9Sstevel@tonic-gate { 7727c478bd9Sstevel@tonic-gate uint32_t mondo; 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate mondo = ((pci_p->pci_cb_p->cb_ign << PCI_INO_BITS) | 7757c478bd9Sstevel@tonic-gate pci_p->pci_inos[inum]); 7767c478bd9Sstevel@tonic-gate mondo = CB_MONDO_TO_XMONDO(pci_p->pci_cb_p, mondo); 7777c478bd9Sstevel@tonic-gate 778b0fc0e77Sgovinda VERIFY(add_ivintr(mondo, pci_pil[inum], (intrfunc)ecc_intr, 779b0fc0e77Sgovinda (caddr_t)eii_p, NULL, NULL) == 0); 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate return (PCI_ATTACH_RETCODE(PCI_ECC_OBJ, PCI_OBJ_INTR_ADD, DDI_SUCCESS)); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate void 7857c478bd9Sstevel@tonic-gate pci_ecc_rem_intr(pci_t *pci_p, int inum, ecc_intr_info_t *eii_p) 7867c478bd9Sstevel@tonic-gate { 7877c478bd9Sstevel@tonic-gate uint32_t mondo; 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate mondo = ((pci_p->pci_cb_p->cb_ign << PCI_INO_BITS) | 7907c478bd9Sstevel@tonic-gate pci_p->pci_inos[inum]); 7917c478bd9Sstevel@tonic-gate mondo = CB_MONDO_TO_XMONDO(pci_p->pci_cb_p, mondo); 7927c478bd9Sstevel@tonic-gate 793b0fc0e77Sgovinda VERIFY(rem_ivintr(mondo, pci_pil[inum]) == 0); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate static int pbm_has_pass_1_cheerio(pci_t *pci_p); 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate void 7997c478bd9Sstevel@tonic-gate pbm_configure(pbm_t *pbm_p) 8007c478bd9Sstevel@tonic-gate { 8017c478bd9Sstevel@tonic-gate pci_t *pci_p = pbm_p->pbm_pci_p; 8027c478bd9Sstevel@tonic-gate cb_t *cb_p = pci_p->pci_cb_p; 8037c478bd9Sstevel@tonic-gate dev_info_t *dip = pci_p->pci_dip; 8047c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 8057c478bd9Sstevel@tonic-gate uint32_t mask = 1 << instance; 8067c478bd9Sstevel@tonic-gate uint64_t l; 8077c478bd9Sstevel@tonic-gate uint16_t s = 0; 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /* 8107c478bd9Sstevel@tonic-gate * Workarounds for hardware bugs: 8117c478bd9Sstevel@tonic-gate * 8127c478bd9Sstevel@tonic-gate * bus parking 8137c478bd9Sstevel@tonic-gate * 8147c478bd9Sstevel@tonic-gate * Pass 2 psycho parts have a bug that requires bus 8157c478bd9Sstevel@tonic-gate * parking to be disabled. 8167c478bd9Sstevel@tonic-gate * 8177c478bd9Sstevel@tonic-gate * Pass 1 cheerio parts have a bug which prevents them 8187c478bd9Sstevel@tonic-gate * from working on a PBM with bus parking enabled. 8197c478bd9Sstevel@tonic-gate * 8207c478bd9Sstevel@tonic-gate * rerun disable 8217c478bd9Sstevel@tonic-gate * 8227c478bd9Sstevel@tonic-gate * Pass 1 and 2 psycho's require that the rerun's be 8237c478bd9Sstevel@tonic-gate * enabled. 8247c478bd9Sstevel@tonic-gate * 8257c478bd9Sstevel@tonic-gate * retry limit 8267c478bd9Sstevel@tonic-gate * 8277c478bd9Sstevel@tonic-gate * For pass 1 and pass 2 psycho parts we disable the 8287c478bd9Sstevel@tonic-gate * retry limit. This is because the limit of 16 seems 8297c478bd9Sstevel@tonic-gate * too restrictive for devices that are children of pci 8307c478bd9Sstevel@tonic-gate * to pci bridges. For pass 3 this limit will be 64. 8317c478bd9Sstevel@tonic-gate * 8327c478bd9Sstevel@tonic-gate * DMA write/PIO read sync 8337c478bd9Sstevel@tonic-gate * 8347c478bd9Sstevel@tonic-gate * For pass 2 psycho, the disable this feature. 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate l = lddphysio(cb_p->cb_base_pa + PSYCHO_CB_CONTROL_STATUS_REG_OFFSET); 8377c478bd9Sstevel@tonic-gate l &= PSYCHO_CB_CONTROL_STATUS_VER; 8387c478bd9Sstevel@tonic-gate l >>= PSYCHO_CB_CONTROL_STATUS_VER_SHIFT; 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate DEBUG2(DBG_ATTACH, dip, "cb_create: ver=%d, mask=%x\n", l, mask); 8417c478bd9Sstevel@tonic-gate pci_rerun_disable = (uint32_t)-1; 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate switch (l) { 8447c478bd9Sstevel@tonic-gate case 0: 8457c478bd9Sstevel@tonic-gate DEBUG0(DBG_ATTACH, dip, "cb_create: psycho pass 1\n"); 8467c478bd9Sstevel@tonic-gate if (!pci_disable_pass1_workarounds) { 8477c478bd9Sstevel@tonic-gate if (pbm_has_pass_1_cheerio(pci_p)) 8487c478bd9Sstevel@tonic-gate pci_bus_parking_enable &= ~mask; 8497c478bd9Sstevel@tonic-gate pci_rerun_disable &= ~mask; 8507c478bd9Sstevel@tonic-gate pci_retry_disable |= mask; 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate break; 8537c478bd9Sstevel@tonic-gate case 1: 8547c478bd9Sstevel@tonic-gate if (!pci_disable_pass2_workarounds) { 8557c478bd9Sstevel@tonic-gate pci_bus_parking_enable &= ~mask; 8567c478bd9Sstevel@tonic-gate pci_rerun_disable &= ~mask; 8577c478bd9Sstevel@tonic-gate pci_retry_disable |= mask; 8587c478bd9Sstevel@tonic-gate pci_dwsync_disable |= mask; 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate break; 8617c478bd9Sstevel@tonic-gate case 2: 8627c478bd9Sstevel@tonic-gate if (!pci_disable_pass3_workarounds) { 8637c478bd9Sstevel@tonic-gate pci_dwsync_disable |= mask; 8647c478bd9Sstevel@tonic-gate if (pbm_has_pass_1_cheerio(pci_p)) 8657c478bd9Sstevel@tonic-gate pci_bus_parking_enable &= ~mask; 8667c478bd9Sstevel@tonic-gate } 8677c478bd9Sstevel@tonic-gate break; 8687c478bd9Sstevel@tonic-gate case 3: 8697c478bd9Sstevel@tonic-gate if (!pci_disable_plus_workarounds) { 8707c478bd9Sstevel@tonic-gate pci_dwsync_disable |= mask; 8717c478bd9Sstevel@tonic-gate if (pbm_has_pass_1_cheerio(pci_p)) 8727c478bd9Sstevel@tonic-gate pci_bus_parking_enable &= ~mask; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate break; 8757c478bd9Sstevel@tonic-gate default: 8767c478bd9Sstevel@tonic-gate if (!pci_disable_default_workarounds) { 8777c478bd9Sstevel@tonic-gate pci_dwsync_disable |= mask; 8787c478bd9Sstevel@tonic-gate if (pbm_has_pass_1_cheerio(pci_p)) 8797c478bd9Sstevel@tonic-gate pci_bus_parking_enable &= ~mask; 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate break; 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate /* 8857c478bd9Sstevel@tonic-gate * Clear any PBM errors. 8867c478bd9Sstevel@tonic-gate */ 8877c478bd9Sstevel@tonic-gate l = (PSYCHO_PCI_AFSR_E_MASK << PSYCHO_PCI_AFSR_PE_SHIFT) | 8887c478bd9Sstevel@tonic-gate (PSYCHO_PCI_AFSR_E_MASK << PSYCHO_PCI_AFSR_SE_SHIFT); 8897c478bd9Sstevel@tonic-gate *pbm_p->pbm_async_flt_status_reg = l; 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate /* 8927c478bd9Sstevel@tonic-gate * Clear error bits in configuration status register. 8937c478bd9Sstevel@tonic-gate */ 8947c478bd9Sstevel@tonic-gate s = PCI_STAT_PERROR | PCI_STAT_S_PERROR | 8957c478bd9Sstevel@tonic-gate PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB | 8967c478bd9Sstevel@tonic-gate PCI_STAT_S_TARG_AB | PCI_STAT_S_PERROR; 8977c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "pbm_configure: conf status reg=%x\n", s); 8987c478bd9Sstevel@tonic-gate pbm_p->pbm_config_header->ch_status_reg = s; 8997c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "pbm_configure: conf status reg==%x\n", 9007c478bd9Sstevel@tonic-gate pbm_p->pbm_config_header->ch_status_reg); 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate l = *pbm_p->pbm_ctrl_reg; /* save control register state */ 9037c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "pbm_configure: ctrl reg==%llx\n", l); 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate /* 9067c478bd9Sstevel@tonic-gate * See if any SERR# signals are asserted. We'll clear them later. 9077c478bd9Sstevel@tonic-gate */ 9087c478bd9Sstevel@tonic-gate if (l & COMMON_PCI_CTRL_SERR) 9097c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: SERR asserted on pci bus\n", 9107c478bd9Sstevel@tonic-gate ddi_driver_name(dip), instance); 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate /* 9137c478bd9Sstevel@tonic-gate * Determine if PCI bus is running at 33 or 66 mhz. 9147c478bd9Sstevel@tonic-gate */ 9157c478bd9Sstevel@tonic-gate if (l & COMMON_PCI_CTRL_SPEED) 9167c478bd9Sstevel@tonic-gate pbm_p->pbm_speed = PBM_SPEED_66MHZ; 9177c478bd9Sstevel@tonic-gate else 9187c478bd9Sstevel@tonic-gate pbm_p->pbm_speed = PBM_SPEED_33MHZ; 9197c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "pbm_configure: %d mhz\n", 9207c478bd9Sstevel@tonic-gate pbm_p->pbm_speed == PBM_SPEED_66MHZ ? 66 : 33); 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate /* 9237c478bd9Sstevel@tonic-gate * Enable error interrupts. 9247c478bd9Sstevel@tonic-gate */ 9257c478bd9Sstevel@tonic-gate if (pci_error_intr_enable & mask) 9267c478bd9Sstevel@tonic-gate l |= PSYCHO_PCI_CTRL_ERR_INT_EN; 9277c478bd9Sstevel@tonic-gate else 9287c478bd9Sstevel@tonic-gate l &= ~PSYCHO_PCI_CTRL_ERR_INT_EN; 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate /* 9317c478bd9Sstevel@tonic-gate * Disable pci streaming byte errors and error interrupts. 9327c478bd9Sstevel@tonic-gate */ 9337c478bd9Sstevel@tonic-gate pci_sbh_error_intr_enable &= ~mask; 9347c478bd9Sstevel@tonic-gate l &= ~PSYCHO_PCI_CTRL_SBH_INT_EN; 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate /* 9377c478bd9Sstevel@tonic-gate * Enable/disable bus parking. 9387c478bd9Sstevel@tonic-gate */ 9397c478bd9Sstevel@tonic-gate if ((pci_bus_parking_enable & mask) && 9407c478bd9Sstevel@tonic-gate !ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 9417c478bd9Sstevel@tonic-gate "no-bus-parking")) 9427c478bd9Sstevel@tonic-gate l |= PSYCHO_PCI_CTRL_ARB_PARK; 9437c478bd9Sstevel@tonic-gate else 9447c478bd9Sstevel@tonic-gate l &= ~PSYCHO_PCI_CTRL_ARB_PARK; 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate /* 9477c478bd9Sstevel@tonic-gate * Enable arbitration. 9487c478bd9Sstevel@tonic-gate */ 9497c478bd9Sstevel@tonic-gate if (pci_p->pci_side == B) 9507c478bd9Sstevel@tonic-gate l = (l & ~PSYCHO_PCI_CTRL_ARB_EN_MASK) | pci_b_arb_enable; 9517c478bd9Sstevel@tonic-gate else 9527c478bd9Sstevel@tonic-gate l = (l & ~PSYCHO_PCI_CTRL_ARB_EN_MASK) | pci_a_arb_enable; 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * Make sure SERR is clear 9567c478bd9Sstevel@tonic-gate */ 9577c478bd9Sstevel@tonic-gate l |= COMMON_PCI_CTRL_SERR; 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate /* 9607c478bd9Sstevel@tonic-gate * Make sure power management interrupt is disabled. 9617c478bd9Sstevel@tonic-gate */ 9627c478bd9Sstevel@tonic-gate l &= ~PSYCHO_PCI_CTRL_WAKEUP_EN; 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 9657c478bd9Sstevel@tonic-gate /* 9667c478bd9Sstevel@tonic-gate * Hack to determine whether we do Starfire special handling 9677c478bd9Sstevel@tonic-gate * For starfire, we simply program a constant odd-value 9687c478bd9Sstevel@tonic-gate * (0x1D) in the MID field. 9697c478bd9Sstevel@tonic-gate * 9707c478bd9Sstevel@tonic-gate * Zero out the MID field before ORing. We leave the LSB of 9717c478bd9Sstevel@tonic-gate * the MID field intact since we cannot have a zero (even) 9727c478bd9Sstevel@tonic-gate * MID value. 9737c478bd9Sstevel@tonic-gate */ 9747c478bd9Sstevel@tonic-gate l &= 0xFF0FFFFFFFFFFFFFULL; 9757c478bd9Sstevel@tonic-gate l |= 0x1DULL << 51; 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate /* 9787c478bd9Sstevel@tonic-gate * Program in the Interrupt Group Number. Here we have to 9797c478bd9Sstevel@tonic-gate * convert the starfire 7bit upaid into a 5bit value. 9807c478bd9Sstevel@tonic-gate */ 9817c478bd9Sstevel@tonic-gate l |= (uint64_t)STARFIRE_UPAID2HWIGN(pbm_p->pbm_pci_p->pci_id) 9827c478bd9Sstevel@tonic-gate << COMMON_CB_CONTROL_STATUS_IGN_SHIFT; 9837c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate /* 9867c478bd9Sstevel@tonic-gate * Now finally write the control register with the appropriate value. 9877c478bd9Sstevel@tonic-gate */ 9887c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "pbm_configure: ctrl reg=%llx\n", l); 9897c478bd9Sstevel@tonic-gate *pbm_p->pbm_ctrl_reg = l; 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate /* 9927c478bd9Sstevel@tonic-gate * Allow the diag register to be set based upon variable that 9937c478bd9Sstevel@tonic-gate * can be configured via /etc/system. 9947c478bd9Sstevel@tonic-gate */ 9957c478bd9Sstevel@tonic-gate l = *pbm_p->pbm_diag_reg; 9967c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "pbm_configure: PCI diag reg==%llx\n", l); 9977c478bd9Sstevel@tonic-gate if (pci_retry_disable & mask) 9987c478bd9Sstevel@tonic-gate l |= COMMON_PCI_DIAG_DIS_RETRY; 9997c478bd9Sstevel@tonic-gate if (pci_retry_enable & mask) 10007c478bd9Sstevel@tonic-gate l &= ~COMMON_PCI_DIAG_DIS_RETRY; 10017c478bd9Sstevel@tonic-gate if (pci_intsync_disable & mask) 10027c478bd9Sstevel@tonic-gate l |= COMMON_PCI_DIAG_DIS_INTSYNC; 10037c478bd9Sstevel@tonic-gate else 10047c478bd9Sstevel@tonic-gate l &= ~COMMON_PCI_DIAG_DIS_INTSYNC; 10057c478bd9Sstevel@tonic-gate if (pci_dwsync_disable & mask) 10067c478bd9Sstevel@tonic-gate l |= PSYCHO_PCI_DIAG_DIS_DWSYNC; 10077c478bd9Sstevel@tonic-gate else 10087c478bd9Sstevel@tonic-gate l &= ~PSYCHO_PCI_DIAG_DIS_DWSYNC; 10097c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "pbm_configure: PCI diag reg=%llx\n", l); 10107c478bd9Sstevel@tonic-gate *pbm_p->pbm_diag_reg = l; 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate /* 10137c478bd9Sstevel@tonic-gate * Enable SERR# and parity reporting via command register. 10147c478bd9Sstevel@tonic-gate */ 10157c478bd9Sstevel@tonic-gate s = pci_perr_enable & mask ? PCI_COMM_PARITY_DETECT : 0; 10167c478bd9Sstevel@tonic-gate s |= pci_serr_enable & mask ? PCI_COMM_SERR_ENABLE : 0; 10177c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "pbm_configure: conf command reg=%x\n", s); 10187c478bd9Sstevel@tonic-gate pbm_p->pbm_config_header->ch_command_reg = s; 10197c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, "pbm_configure: conf command reg==%x\n", 10207c478bd9Sstevel@tonic-gate pbm_p->pbm_config_header->ch_command_reg); 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * The current versions of the obp are suppose to set the latency 10247c478bd9Sstevel@tonic-gate * timer register but do not. Bug 1234181 is open against this 10257c478bd9Sstevel@tonic-gate * problem. Until this bug is fixed we check to see if the obp 10267c478bd9Sstevel@tonic-gate * has attempted to set the latency timer register by checking 10277c478bd9Sstevel@tonic-gate * for the existence of a "latency-timer" property. 10287c478bd9Sstevel@tonic-gate */ 10297c478bd9Sstevel@tonic-gate if (pci_set_latency_timer_register) { 10307c478bd9Sstevel@tonic-gate DEBUG1(DBG_ATTACH, dip, 10317c478bd9Sstevel@tonic-gate "pbm_configure: set psycho latency timer to %x\n", 10327c478bd9Sstevel@tonic-gate pci_latency_timer); 10337c478bd9Sstevel@tonic-gate pbm_p->pbm_config_header->ch_latency_timer_reg = 10347c478bd9Sstevel@tonic-gate pci_latency_timer; 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_ANY, dip, "latency-timer", 10387c478bd9Sstevel@tonic-gate (int)pbm_p->pbm_config_header->ch_latency_timer_reg); 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate uint_t 10427c478bd9Sstevel@tonic-gate pbm_disable_pci_errors(pbm_t *pbm_p) 10437c478bd9Sstevel@tonic-gate { 10447c478bd9Sstevel@tonic-gate pci_t *pci_p = pbm_p->pbm_pci_p; 10457c478bd9Sstevel@tonic-gate ib_t *ib_p = pci_p->pci_ib_p; 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate /* 10487c478bd9Sstevel@tonic-gate * Disable error and streaming byte hole interrupts via the 10497c478bd9Sstevel@tonic-gate * PBM control register. 10507c478bd9Sstevel@tonic-gate */ 10517c478bd9Sstevel@tonic-gate *pbm_p->pbm_ctrl_reg &= 10527c478bd9Sstevel@tonic-gate ~(PSYCHO_PCI_CTRL_ERR_INT_EN | PSYCHO_PCI_CTRL_SBH_INT_EN); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate /* 10557c478bd9Sstevel@tonic-gate * Disable error interrupts via the interrupt mapping register. 10567c478bd9Sstevel@tonic-gate */ 10577c478bd9Sstevel@tonic-gate ib_intr_disable(ib_p, pci_p->pci_inos[CBNINTR_PBM], IB_INTR_NOWAIT); 10587c478bd9Sstevel@tonic-gate return (BF_NONE); 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10627c478bd9Sstevel@tonic-gate uint64_t 10637c478bd9Sstevel@tonic-gate pci_sc_configure(pci_t *pci_p) 10647c478bd9Sstevel@tonic-gate { 10657c478bd9Sstevel@tonic-gate return (0); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10697c478bd9Sstevel@tonic-gate void 10707c478bd9Sstevel@tonic-gate pci_pbm_dma_sync(pbm_t *pbm_p, ib_ino_t ino) 10717c478bd9Sstevel@tonic-gate { 10727c478bd9Sstevel@tonic-gate uint64_t pa = pbm_p->pbm_sync_reg_pa; 10737c478bd9Sstevel@tonic-gate if (pa) 10747c478bd9Sstevel@tonic-gate (void) lddphysio(pa); /* Load from Sync Register */ 10757c478bd9Sstevel@tonic-gate } 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10787c478bd9Sstevel@tonic-gate dvma_context_t 10797c478bd9Sstevel@tonic-gate pci_iommu_get_dvma_context(iommu_t *iommu_p, dvma_addr_t dvma_pg_index) 10807c478bd9Sstevel@tonic-gate { 10817c478bd9Sstevel@tonic-gate ASSERT(0); 10827c478bd9Sstevel@tonic-gate return (0); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10867c478bd9Sstevel@tonic-gate void 10877c478bd9Sstevel@tonic-gate pci_iommu_free_dvma_context(iommu_t *iommu_p, dvma_context_t ctx) 10887c478bd9Sstevel@tonic-gate { 10897c478bd9Sstevel@tonic-gate ASSERT(0); 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate void 10937c478bd9Sstevel@tonic-gate pci_iommu_config(iommu_t *iommu_p, uint64_t iommu_ctl, uint64_t cfgpa) 10947c478bd9Sstevel@tonic-gate { 10957c478bd9Sstevel@tonic-gate volatile uint64_t *pbm_csr_p = (volatile uint64_t *) 10967c478bd9Sstevel@tonic-gate get_pbm_reg_base(iommu_p->iommu_pci_p); 10977c478bd9Sstevel@tonic-gate volatile uint64_t pbm_ctl = *pbm_csr_p; 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate volatile uint64_t *iommu_ctl_p = iommu_p->iommu_ctrl_reg; 11007c478bd9Sstevel@tonic-gate volatile uint64_t tsb_bar_val = iommu_p->iommu_tsb_paddr; 11017c478bd9Sstevel@tonic-gate volatile uint64_t *tsb_bar_p = iommu_p->iommu_tsb_base_addr_reg; 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate DEBUG2(DBG_ATTACH, iommu_p->iommu_pci_p->pci_dip, 11047c478bd9Sstevel@tonic-gate "\npci_iommu_config: pbm_csr_p=%016llx pbm_ctl=%016llx", 11057c478bd9Sstevel@tonic-gate pbm_csr_p, pbm_ctl); 11067c478bd9Sstevel@tonic-gate DEBUG2(DBG_ATTACH|DBG_CONT, iommu_p->iommu_pci_p->pci_dip, 11077c478bd9Sstevel@tonic-gate "\n\tiommu_ctl_p=%016llx iommu_ctl=%016llx", 11087c478bd9Sstevel@tonic-gate iommu_ctl_p, iommu_ctl); 11097c478bd9Sstevel@tonic-gate DEBUG2(DBG_ATTACH|DBG_CONT, iommu_p->iommu_pci_p->pci_dip, 11107c478bd9Sstevel@tonic-gate "\n\tcfgpa=%016llx tsb_bar_val=%016llx", cfgpa, tsb_bar_val); 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate if (!cfgpa) 11137c478bd9Sstevel@tonic-gate goto reprog; 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate /* disable PBM arbiters - turn off bits 0-7 */ 11167c478bd9Sstevel@tonic-gate *pbm_csr_p = (pbm_ctl >> 8) << 8; 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate /* make sure we own the bus by reading any child device config space */ 11197c478bd9Sstevel@tonic-gate (void) ldphysio(cfgpa); /* also flushes the prev write */ 11207c478bd9Sstevel@tonic-gate reprog: 11217c478bd9Sstevel@tonic-gate *tsb_bar_p = tsb_bar_val; 11227c478bd9Sstevel@tonic-gate *iommu_ctl_p = iommu_ctl; 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate *pbm_csr_p = pbm_ctl; /* re-enable bus arbitration */ 11257c478bd9Sstevel@tonic-gate pbm_ctl = *pbm_csr_p; /* flush all prev writes */ 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate int 11297c478bd9Sstevel@tonic-gate pci_sc_ctx_inv(dev_info_t *dip, sc_t *sc_p, ddi_dma_impl_t *mp) 11307c478bd9Sstevel@tonic-gate { 11317c478bd9Sstevel@tonic-gate ASSERT(0); 11327c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11337c478bd9Sstevel@tonic-gate } 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate void 11367c478bd9Sstevel@tonic-gate pci_cb_setup(pci_t *pci_p) 11377c478bd9Sstevel@tonic-gate { 11387c478bd9Sstevel@tonic-gate uint64_t csr, csr_pa, pa; 11397c478bd9Sstevel@tonic-gate cb_t *cb_p = pci_p->pci_cb_p; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate /* cb_p->cb_node_id = 0; */ 11427c478bd9Sstevel@tonic-gate cb_p->cb_ign = PCI_ID_TO_IGN(pci_p->pci_id); 11437c478bd9Sstevel@tonic-gate pa = (uint64_t)hat_getpfnum(kas.a_hat, pci_p->pci_address[0]); 11447c478bd9Sstevel@tonic-gate cb_p->cb_base_pa = pa = pa >> (32 - MMU_PAGESHIFT) << 32; 11457c478bd9Sstevel@tonic-gate cb_p->cb_map_pa = pa + PSYCHO_IB_OBIO_INTR_MAP_REG_OFFSET; 11467c478bd9Sstevel@tonic-gate cb_p->cb_clr_pa = pa + PSYCHO_IB_OBIO_CLEAR_INTR_REG_OFFSET; 11477c478bd9Sstevel@tonic-gate cb_p->cb_obsta_pa = pa + COMMON_IB_OBIO_INTR_STATE_DIAG_REG; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate csr_pa = pa + PSYCHO_CB_CONTROL_STATUS_REG_OFFSET; 11507c478bd9Sstevel@tonic-gate csr = lddphysio(csr_pa); 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate /* 11537c478bd9Sstevel@tonic-gate * Clear any pending address parity errors. 11547c478bd9Sstevel@tonic-gate */ 11557c478bd9Sstevel@tonic-gate if (csr & COMMON_CB_CONTROL_STATUS_APERR) { 11567c478bd9Sstevel@tonic-gate csr |= COMMON_CB_CONTROL_STATUS_APERR; 11577c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "clearing UPA address parity error\n"); 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate csr |= COMMON_CB_CONTROL_STATUS_APCKEN; 11607c478bd9Sstevel@tonic-gate csr &= ~COMMON_CB_CONTROL_STATUS_IAP; 11617c478bd9Sstevel@tonic-gate stdphysio(csr_pa, csr); 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate #ifdef _STARFIRE 11647c478bd9Sstevel@tonic-gate /* Setup Starfire interrupt target translation */ 11657c478bd9Sstevel@tonic-gate pc_ittrans_init(pci_p->pci_id, &cb_p->cb_ittrans_cookie); 11667c478bd9Sstevel@tonic-gate #endif /* _STARFIRE */ 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate void 11717c478bd9Sstevel@tonic-gate pci_ecc_setup(ecc_t *ecc_p) 11727c478bd9Sstevel@tonic-gate { 11737c478bd9Sstevel@tonic-gate ecc_p->ecc_ue.ecc_errpndg_mask = 0; 11747c478bd9Sstevel@tonic-gate ecc_p->ecc_ue.ecc_offset_mask = PSYCHO_ECC_UE_AFSR_DW_OFFSET; 11757c478bd9Sstevel@tonic-gate ecc_p->ecc_ue.ecc_offset_shift = PSYCHO_ECC_UE_AFSR_DW_OFFSET_SHIFT; 11767c478bd9Sstevel@tonic-gate ecc_p->ecc_ue.ecc_size_log2 = 3; 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate ecc_p->ecc_ce.ecc_errpndg_mask = 0; 11797c478bd9Sstevel@tonic-gate ecc_p->ecc_ce.ecc_offset_mask = PSYCHO_ECC_CE_AFSR_DW_OFFSET; 11807c478bd9Sstevel@tonic-gate ecc_p->ecc_ce.ecc_offset_shift = PSYCHO_ECC_CE_AFSR_DW_OFFSET_SHIFT; 11817c478bd9Sstevel@tonic-gate ecc_p->ecc_ce.ecc_size_log2 = 3; 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate /* 11857c478bd9Sstevel@tonic-gate * overwrite dvma end address (only on virtual-dma systems) 11867c478bd9Sstevel@tonic-gate * initialize tsb size 11877c478bd9Sstevel@tonic-gate * reset context bits 11887c478bd9Sstevel@tonic-gate * return: IOMMU CSR bank base address (VA) 11897c478bd9Sstevel@tonic-gate */ 11907c478bd9Sstevel@tonic-gate uintptr_t 11917c478bd9Sstevel@tonic-gate pci_iommu_setup(iommu_t *iommu_p) 11927c478bd9Sstevel@tonic-gate { 11937c478bd9Sstevel@tonic-gate pci_dvma_range_prop_t *dvma_prop; 11947c478bd9Sstevel@tonic-gate int dvma_prop_len; 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate pci_t *pci_p = iommu_p->iommu_pci_p; 11977c478bd9Sstevel@tonic-gate dev_info_t *dip = pci_p->pci_dip; 11987c478bd9Sstevel@tonic-gate uint_t tsb_size = iommu_tsb_cookie_to_size(pci_p->pci_tsb_cookie); 11997c478bd9Sstevel@tonic-gate uint_t tsb_size_prop; 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 12027c478bd9Sstevel@tonic-gate "virtual-dma", (caddr_t)&dvma_prop, &dvma_prop_len) != 12037c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) 12047c478bd9Sstevel@tonic-gate goto tsb_done; 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate if (dvma_prop_len != sizeof (pci_dvma_range_prop_t)) { 12077c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: invalid virtual-dma property", 12087c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 12097c478bd9Sstevel@tonic-gate goto tsb_end; 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate iommu_p->iommu_dvma_end = dvma_prop->dvma_base + 12127c478bd9Sstevel@tonic-gate (dvma_prop->dvma_len - 1); 12137c478bd9Sstevel@tonic-gate tsb_size_prop = IOMMU_BTOP(dvma_prop->dvma_len) * sizeof (uint64_t); 12147c478bd9Sstevel@tonic-gate tsb_size = MIN(tsb_size_prop, tsb_size); 12157c478bd9Sstevel@tonic-gate tsb_end: 12167c478bd9Sstevel@tonic-gate kmem_free(dvma_prop, dvma_prop_len); 12177c478bd9Sstevel@tonic-gate tsb_done: 12187c478bd9Sstevel@tonic-gate iommu_p->iommu_tsb_size = iommu_tsb_size_encode(tsb_size); 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate if (CHIP_TYPE(pci_p) != PCI_CHIP_HUMMINGBIRD) 12217c478bd9Sstevel@tonic-gate pci_preserve_iommu_tsb = 0; 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate /* 12247c478bd9Sstevel@tonic-gate * Psycho has no context support. 12257c478bd9Sstevel@tonic-gate */ 12267c478bd9Sstevel@tonic-gate iommu_p->iommu_ctx_bitmap = NULL; 12277c478bd9Sstevel@tonic-gate iommu_p->iommu_flush_ctx_reg = NULL; 12287c478bd9Sstevel@tonic-gate pci_use_contexts = 0; 12297c478bd9Sstevel@tonic-gate pci_sc_use_contexts = 0; 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate /* 12327c478bd9Sstevel@tonic-gate * Determine the virtual address of the register block 12337c478bd9Sstevel@tonic-gate * containing the iommu control registers. 12347c478bd9Sstevel@tonic-gate */ 12357c478bd9Sstevel@tonic-gate return (get_reg_base(pci_p)); 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12397c478bd9Sstevel@tonic-gate void 12407c478bd9Sstevel@tonic-gate pci_iommu_teardown(iommu_t *iommu_p) 12417c478bd9Sstevel@tonic-gate { 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate /* The psycho+ PBM reg base is at 1fe.0000.2000 */ 12457c478bd9Sstevel@tonic-gate uintptr_t 12467c478bd9Sstevel@tonic-gate get_pbm_reg_base(pci_t *pci_p) 12477c478bd9Sstevel@tonic-gate { 12487c478bd9Sstevel@tonic-gate return ((uintptr_t)(pci_p->pci_address[0] + 12497c478bd9Sstevel@tonic-gate (pci_stream_buf_exists ? 0 : PSYCHO_PCI_PBM_REG_BASE))); 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate void 12537c478bd9Sstevel@tonic-gate pci_post_uninit_child(pci_t *pci_p) 12547c478bd9Sstevel@tonic-gate { 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate void 12587c478bd9Sstevel@tonic-gate pci_pbm_setup(pbm_t *pbm_p) 12597c478bd9Sstevel@tonic-gate { 12607c478bd9Sstevel@tonic-gate pci_t *pci_p = pbm_p->pbm_pci_p; 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate /* 12637c478bd9Sstevel@tonic-gate * Get the base virtual address for the PBM control block. 12647c478bd9Sstevel@tonic-gate */ 12657c478bd9Sstevel@tonic-gate uintptr_t a = get_pbm_reg_base(pci_p); 12667c478bd9Sstevel@tonic-gate 12677c478bd9Sstevel@tonic-gate /* 12687c478bd9Sstevel@tonic-gate * Get the virtual address of the PCI configuration header. 12697c478bd9Sstevel@tonic-gate * This should be mapped little-endian. 12707c478bd9Sstevel@tonic-gate */ 12717c478bd9Sstevel@tonic-gate pbm_p->pbm_config_header = 12727c478bd9Sstevel@tonic-gate (config_header_t *)get_config_reg_base(pci_p); 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate /* 12757c478bd9Sstevel@tonic-gate * Get the virtual addresses for control, error and diag 12767c478bd9Sstevel@tonic-gate * registers. 12777c478bd9Sstevel@tonic-gate */ 12787c478bd9Sstevel@tonic-gate pbm_p->pbm_ctrl_reg = (uint64_t *)(a + PSYCHO_PCI_CTRL_REG_OFFSET); 12797c478bd9Sstevel@tonic-gate pbm_p->pbm_diag_reg = (uint64_t *)(a + PSYCHO_PCI_DIAG_REG_OFFSET); 12807c478bd9Sstevel@tonic-gate pbm_p->pbm_async_flt_status_reg = 12817c478bd9Sstevel@tonic-gate (uint64_t *)(a + PSYCHO_PCI_ASYNC_FLT_STATUS_REG_OFFSET); 12827c478bd9Sstevel@tonic-gate pbm_p->pbm_async_flt_addr_reg = 12837c478bd9Sstevel@tonic-gate (uint64_t *)(a + PSYCHO_PCI_ASYNC_FLT_ADDR_REG_OFFSET); 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate if (CHIP_TYPE(pci_p) >= PCI_CHIP_SABRE) 12867c478bd9Sstevel@tonic-gate pbm_p->pbm_sync_reg_pa = 12877c478bd9Sstevel@tonic-gate pci_p->pci_cb_p->cb_base_pa + DMA_WRITE_SYNC_REG; 12887c478bd9Sstevel@tonic-gate } 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12917c478bd9Sstevel@tonic-gate void 12927c478bd9Sstevel@tonic-gate pci_pbm_teardown(pbm_t *pbm_p) 12937c478bd9Sstevel@tonic-gate { 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate void 12977c478bd9Sstevel@tonic-gate pci_sc_setup(sc_t *sc_p) 12987c478bd9Sstevel@tonic-gate { 12997c478bd9Sstevel@tonic-gate pci_t *pci_p = sc_p->sc_pci_p; 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate /* 13027c478bd9Sstevel@tonic-gate * Determine the virtual addresses of the streaming cache 13037c478bd9Sstevel@tonic-gate * control/status and flush registers. 13047c478bd9Sstevel@tonic-gate */ 13057c478bd9Sstevel@tonic-gate uintptr_t a = get_pbm_reg_base(pci_p); 13067c478bd9Sstevel@tonic-gate sc_p->sc_ctrl_reg = (uint64_t *)(a + PSYCHO_SC_CTRL_REG_OFFSET); 13077c478bd9Sstevel@tonic-gate sc_p->sc_invl_reg = (uint64_t *)(a + PSYCHO_SC_INVL_REG_OFFSET); 13087c478bd9Sstevel@tonic-gate sc_p->sc_sync_reg = (uint64_t *)(a + PSYCHO_SC_SYNC_REG_OFFSET); 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate /* 13117c478bd9Sstevel@tonic-gate * Determine the virtual addresses of the streaming cache 13127c478bd9Sstevel@tonic-gate * diagnostic access registers. 13137c478bd9Sstevel@tonic-gate */ 13147c478bd9Sstevel@tonic-gate a = get_reg_base(pci_p); 13157c478bd9Sstevel@tonic-gate if (pci_p->pci_bus_range.lo != 0) { 13167c478bd9Sstevel@tonic-gate sc_p->sc_data_diag_acc = (uint64_t *) 13177c478bd9Sstevel@tonic-gate (a + PSYCHO_SC_A_DATA_DIAG_OFFSET); 13187c478bd9Sstevel@tonic-gate sc_p->sc_tag_diag_acc = (uint64_t *) 13197c478bd9Sstevel@tonic-gate (a + PSYCHO_SC_A_TAG_DIAG_OFFSET); 13207c478bd9Sstevel@tonic-gate sc_p->sc_ltag_diag_acc = (uint64_t *) 13217c478bd9Sstevel@tonic-gate (a + PSYCHO_SC_A_LTAG_DIAG_OFFSET); 13227c478bd9Sstevel@tonic-gate } else { 13237c478bd9Sstevel@tonic-gate sc_p->sc_data_diag_acc = (uint64_t *) 13247c478bd9Sstevel@tonic-gate (a + PSYCHO_SC_B_DATA_DIAG_OFFSET); 13257c478bd9Sstevel@tonic-gate sc_p->sc_tag_diag_acc = (uint64_t *) 13267c478bd9Sstevel@tonic-gate (a + PSYCHO_SC_B_TAG_DIAG_OFFSET); 13277c478bd9Sstevel@tonic-gate sc_p->sc_ltag_diag_acc = (uint64_t *) 13287c478bd9Sstevel@tonic-gate (a + PSYCHO_SC_B_LTAG_DIAG_OFFSET); 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate int 13337c478bd9Sstevel@tonic-gate pci_get_numproxy(dev_info_t *dip) 13347c478bd9Sstevel@tonic-gate { 13357c478bd9Sstevel@tonic-gate return (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 13367c478bd9Sstevel@tonic-gate "#upa-interrupt-proxies", 1)); 13377c478bd9Sstevel@tonic-gate } 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate int 13407c478bd9Sstevel@tonic-gate pci_get_portid(dev_info_t *dip) 13417c478bd9Sstevel@tonic-gate { 13427c478bd9Sstevel@tonic-gate return (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 13437c478bd9Sstevel@tonic-gate "upa-portid", -1)); 13447c478bd9Sstevel@tonic-gate } 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate /* 13477c478bd9Sstevel@tonic-gate * pbm_has_pass_1_cheerio 13487c478bd9Sstevel@tonic-gate * 13497c478bd9Sstevel@tonic-gate * 13507c478bd9Sstevel@tonic-gate * Given a PBM soft state pointer, this routine scans it child nodes 13517c478bd9Sstevel@tonic-gate * to see if one is a pass 1 cheerio. 13527c478bd9Sstevel@tonic-gate * 13537c478bd9Sstevel@tonic-gate * return value: 1 if pass 1 cheerio is found, 0 otherwise 13547c478bd9Sstevel@tonic-gate */ 13557c478bd9Sstevel@tonic-gate static int 13567c478bd9Sstevel@tonic-gate pbm_has_pass_1_cheerio(pci_t *pci_p) 13577c478bd9Sstevel@tonic-gate { 13587c478bd9Sstevel@tonic-gate dev_info_t *cdip; 13597c478bd9Sstevel@tonic-gate int found = 0; 13607c478bd9Sstevel@tonic-gate char *s; 13617c478bd9Sstevel@tonic-gate int rev; 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate cdip = ddi_get_child(pci_p->pci_dip); 13647c478bd9Sstevel@tonic-gate while (cdip != NULL && found == 0) { 13657c478bd9Sstevel@tonic-gate s = ddi_get_name(cdip); 13667c478bd9Sstevel@tonic-gate if (strcmp(s, "ebus") == 0 || strcmp(s, "pci108e,1000") == 0) { 13677c478bd9Sstevel@tonic-gate rev = 13687c478bd9Sstevel@tonic-gate ddi_getprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 13697c478bd9Sstevel@tonic-gate "revision-id", 0); 13707c478bd9Sstevel@tonic-gate if (rev == 0) 13717c478bd9Sstevel@tonic-gate found = 1; 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate cdip = ddi_get_next_sibling(cdip); 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate return (found); 13767c478bd9Sstevel@tonic-gate } 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate /* 13797c478bd9Sstevel@tonic-gate * Psycho Performance Events. 13807c478bd9Sstevel@tonic-gate */ 13817c478bd9Sstevel@tonic-gate pci_kev_mask_t 13827c478bd9Sstevel@tonic-gate psycho_pci_events[] = { 13837c478bd9Sstevel@tonic-gate {"dvma_stream_rd_a", 0x0}, {"dvma_stream_wr_a", 0x1}, 13847c478bd9Sstevel@tonic-gate {"dvma_const_rd_a", 0x2}, {"dvma_const_wr_a", 0x3}, 13857c478bd9Sstevel@tonic-gate {"dvma_stream_buf_mis_a", 0x4}, {"dvma_cycles_a", 0x5}, 13867c478bd9Sstevel@tonic-gate {"dvma_wd_xfr_a", 0x6}, {"pio_cycles_a", 0x7}, 13877c478bd9Sstevel@tonic-gate {"dvma_stream_rd_b", 0x8}, {"dvma_stream_wr_b", 0x9}, 13887c478bd9Sstevel@tonic-gate {"dvma_const_rd_b", 0xa}, {"dvma_const_wr_b", 0xb}, 13897c478bd9Sstevel@tonic-gate {"dvma_stream_buf_mis_b", 0xc}, {"dvma_cycles_b", 0xd}, 13907c478bd9Sstevel@tonic-gate {"dvma_wd_xfr_b", 0xe}, {"pio_cycles_b", 0xf}, 13917c478bd9Sstevel@tonic-gate {"dvma_tlb_misses", 0x10}, {"interrupts", 0x11}, 13927c478bd9Sstevel@tonic-gate {"upa_inter_nack", 0x12}, {"pio_reads", 0x13}, 13937c478bd9Sstevel@tonic-gate {"pio_writes", 0x14}, {"merge_buffer", 0x15}, 13947c478bd9Sstevel@tonic-gate {"dma_tbwalk_a", 0x16}, {"dma_stc_a", 0x17}, 13957c478bd9Sstevel@tonic-gate {"dma_tbwalk_b", 0x18}, {"dma_stc_b", 0x19}, 13967c478bd9Sstevel@tonic-gate {"clear_pic", 0x1f} 13977c478bd9Sstevel@tonic-gate }; 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate /* 14007c478bd9Sstevel@tonic-gate * Create the picN kstat's. 14017c478bd9Sstevel@tonic-gate */ 14027c478bd9Sstevel@tonic-gate void 14037c478bd9Sstevel@tonic-gate pci_kstat_init() 14047c478bd9Sstevel@tonic-gate { 14057c478bd9Sstevel@tonic-gate pci_name_kstat = (pci_ksinfo_t *)kmem_alloc(sizeof (pci_ksinfo_t), 14067c478bd9Sstevel@tonic-gate KM_NOSLEEP); 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate if (pci_name_kstat == NULL) { 14097c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pcipsy : no space for kstat\n"); 14107c478bd9Sstevel@tonic-gate } else { 14117c478bd9Sstevel@tonic-gate pci_name_kstat->pic_no_evs = 14127c478bd9Sstevel@tonic-gate sizeof (psycho_pci_events) / sizeof (pci_kev_mask_t); 14137c478bd9Sstevel@tonic-gate pci_name_kstat->pic_shift[0] = PSYCHO_SHIFT_PIC0; 14147c478bd9Sstevel@tonic-gate pci_name_kstat->pic_shift[1] = PSYCHO_SHIFT_PIC1; 14157c478bd9Sstevel@tonic-gate pci_create_name_kstat("pcip", 14167c478bd9Sstevel@tonic-gate pci_name_kstat, psycho_pci_events); 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate } 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate /* 14217c478bd9Sstevel@tonic-gate * Called from _fini() 14227c478bd9Sstevel@tonic-gate */ 14237c478bd9Sstevel@tonic-gate void 14247c478bd9Sstevel@tonic-gate pci_kstat_fini() 14257c478bd9Sstevel@tonic-gate { 14267c478bd9Sstevel@tonic-gate if (pci_name_kstat != NULL) { 14277c478bd9Sstevel@tonic-gate pci_delete_name_kstat(pci_name_kstat); 14287c478bd9Sstevel@tonic-gate kmem_free(pci_name_kstat, sizeof (pci_ksinfo_t)); 14297c478bd9Sstevel@tonic-gate pci_name_kstat = NULL; 14307c478bd9Sstevel@tonic-gate } 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14347c478bd9Sstevel@tonic-gate void 14357c478bd9Sstevel@tonic-gate pci_add_pci_kstat(pci_t *pci_p) 14367c478bd9Sstevel@tonic-gate { 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate /* ARGSUSED */ 14407c478bd9Sstevel@tonic-gate void 14417c478bd9Sstevel@tonic-gate pci_rem_pci_kstat(pci_t *pci_p) 14427c478bd9Sstevel@tonic-gate { 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate /* 14467c478bd9Sstevel@tonic-gate * Create the performance 'counters' kstat. 14477c478bd9Sstevel@tonic-gate */ 14487c478bd9Sstevel@tonic-gate void 14497c478bd9Sstevel@tonic-gate pci_add_upstream_kstat(pci_t *pci_p) 14507c478bd9Sstevel@tonic-gate { 14517c478bd9Sstevel@tonic-gate pci_common_t *cmn_p = pci_p->pci_common_p; 14527c478bd9Sstevel@tonic-gate pci_cntr_pa_t *cntr_pa_p = &cmn_p->pci_cmn_uks_pa; 14537c478bd9Sstevel@tonic-gate uint64_t regbase = va_to_pa((void *)get_reg_base(pci_p)); 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate cntr_pa_p->pcr_pa = regbase + PSYCHO_PERF_PCR_OFFSET; 14567c478bd9Sstevel@tonic-gate cntr_pa_p->pic_pa = regbase + PSYCHO_PERF_PIC_OFFSET; 14577c478bd9Sstevel@tonic-gate cmn_p->pci_common_uksp = pci_create_cntr_kstat(pci_p, "pcip", 14587c478bd9Sstevel@tonic-gate NUM_OF_PICS, pci_cntr_kstat_pa_update, cntr_pa_p); 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate /* 14627c478bd9Sstevel@tonic-gate * Extract the drivers binding name to identify which chip 14637c478bd9Sstevel@tonic-gate * we're binding to. Whenever a new bus bridge is created, the driver alias 14647c478bd9Sstevel@tonic-gate * entry should be added here to identify the device if needed. If a device 14657c478bd9Sstevel@tonic-gate * isn't added, the identity defaults to PCI_CHIP_UNIDENTIFIED. 14667c478bd9Sstevel@tonic-gate */ 14677c478bd9Sstevel@tonic-gate static uint32_t 14687c478bd9Sstevel@tonic-gate pci_identity_init(pci_t *pci_p) 14697c478bd9Sstevel@tonic-gate { 14707c478bd9Sstevel@tonic-gate dev_info_t *dip = pci_p->pci_dip; 14717c478bd9Sstevel@tonic-gate char *name = ddi_binding_name(dip); 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate if (strcmp(name, "pci108e,8000") == 0) 14747c478bd9Sstevel@tonic-gate return (CHIP_ID(PCI_CHIP_PSYCHO, 0x00, 0x00)); 14757c478bd9Sstevel@tonic-gate if (strcmp(name, "pci108e,a000") == 0) 14767c478bd9Sstevel@tonic-gate return (CHIP_ID(PCI_CHIP_SABRE, 0x00, 0x00)); 14777c478bd9Sstevel@tonic-gate if (strcmp(name, "pci108e,a001") == 0) 14787c478bd9Sstevel@tonic-gate return (CHIP_ID(PCI_CHIP_HUMMINGBIRD, 0x00, 0x00)); 14797c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?%s%d:using default chip identity\n", 14807c478bd9Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 14817c478bd9Sstevel@tonic-gate return (CHIP_ID(PCI_CHIP_PSYCHO, 0x00, 0x00)); 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14857c478bd9Sstevel@tonic-gate void 14867c478bd9Sstevel@tonic-gate pci_post_init_child(pci_t *pci_p, dev_info_t *child) 14877c478bd9Sstevel@tonic-gate { 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14917c478bd9Sstevel@tonic-gate int 14927c478bd9Sstevel@tonic-gate pci_pbm_add_intr(pci_t *pci_p) 14937c478bd9Sstevel@tonic-gate { 14947c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14957c478bd9Sstevel@tonic-gate } 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 14987c478bd9Sstevel@tonic-gate void 14997c478bd9Sstevel@tonic-gate pci_pbm_rem_intr(pci_t *pci_p) 15007c478bd9Sstevel@tonic-gate { 15017c478bd9Sstevel@tonic-gate } 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15047c478bd9Sstevel@tonic-gate void 15057c478bd9Sstevel@tonic-gate pci_pbm_suspend(pci_t *pci_p) 15067c478bd9Sstevel@tonic-gate { 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate 15097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15107c478bd9Sstevel@tonic-gate void 15117c478bd9Sstevel@tonic-gate pci_pbm_resume(pci_t *pci_p) 15127c478bd9Sstevel@tonic-gate { 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate /* 15167c478bd9Sstevel@tonic-gate * pcipsy error handling 101: 15177c478bd9Sstevel@tonic-gate * 15187c478bd9Sstevel@tonic-gate * The various functions below are responsible for error handling. Given 15197c478bd9Sstevel@tonic-gate * a particular error, they must gather the appropriate state, report all 15207c478bd9Sstevel@tonic-gate * errors with correct payload, and attempt recovery where ever possible. 15217c478bd9Sstevel@tonic-gate * 15227c478bd9Sstevel@tonic-gate * Recovery in the context of this driver is being able notify a leaf device 15237c478bd9Sstevel@tonic-gate * of the failed transaction. This leaf device may either be the master or 15247c478bd9Sstevel@tonic-gate * target for this transaction and may have already received an error 15257c478bd9Sstevel@tonic-gate * notification via a PCI interrupt. Notification is done via DMA and access 15267c478bd9Sstevel@tonic-gate * handles. If we capture an address for the transaction then we can map it 15277c478bd9Sstevel@tonic-gate * to a handle(if the leaf device is fma-compliant) and fault the handle as 15287c478bd9Sstevel@tonic-gate * well as call the device driver registered callback. 15297c478bd9Sstevel@tonic-gate * 15307c478bd9Sstevel@tonic-gate * The hardware can either interrupt or trap upon detection of an error, in 15317c478bd9Sstevel@tonic-gate * some rare cases it also causes a fatal reset. 15327c478bd9Sstevel@tonic-gate * 15337c478bd9Sstevel@tonic-gate * pbm_error_intr() and ecc_intr() are responsible for PCI Block Module 15347c478bd9Sstevel@tonic-gate * errors(generic PCI + bridge specific) and ECC errors, respectively. They 15357c478bd9Sstevel@tonic-gate * are common between pcisch and pcipsy and therefore exist in pci_pbm.c and 15367c478bd9Sstevel@tonic-gate * pci_ecc.c. To support error handling certain chip specific handlers 15377c478bd9Sstevel@tonic-gate * must exist and they are defined below. 15387c478bd9Sstevel@tonic-gate * 15397c478bd9Sstevel@tonic-gate * cpu_deferred_error() and cpu_async_error(), handle the traps that may 15407c478bd9Sstevel@tonic-gate * have originated from IO space. They call into the registered IO callbacks 15417c478bd9Sstevel@tonic-gate * to report and handle errors that may have caused the trap. 15427c478bd9Sstevel@tonic-gate * 15437c478bd9Sstevel@tonic-gate * pci_pbm_err_handler() is called by pbm_error_intr() or pci_err_callback() 15447c478bd9Sstevel@tonic-gate * (generic fma callback for pcipsy/pcisch, pci_fm.c). pci_err_callback() is 15457c478bd9Sstevel@tonic-gate * called when the CPU has trapped because of a possible IO error(TO/BERR/UE). 15467c478bd9Sstevel@tonic-gate * It will call pci_pbm_err_handler() to report and handle all PCI/PBM/IOMMU 15477c478bd9Sstevel@tonic-gate * related errors which are detected by the chip. 15487c478bd9Sstevel@tonic-gate * 15497c478bd9Sstevel@tonic-gate * pci_pbm_err_handler() calls a generic interface pbm_afsr_report()(pci_pbm.c) 15507c478bd9Sstevel@tonic-gate * to report the pbm specific errors and attempt to map the failed address 15517c478bd9Sstevel@tonic-gate * (if captured) to a device instance. pbm_afsr_report() calls a chip specific 15527c478bd9Sstevel@tonic-gate * interface to interpret the afsr bits pci_pbm_classify()(pcisch.c/pcipsy.c). 15537c478bd9Sstevel@tonic-gate * 15547c478bd9Sstevel@tonic-gate * ecc_err_handler()(pci_ecc.c) also calls a chip specific interface to 15557c478bd9Sstevel@tonic-gate * interpret the afsr, pci_ecc_classify(). ecc_err_handler() also calls 15567c478bd9Sstevel@tonic-gate * pci_pbm_err_handler() and ndi_fm_handler_dispatch() to log any related 15577c478bd9Sstevel@tonic-gate * errors. 15587c478bd9Sstevel@tonic-gate * 15597c478bd9Sstevel@tonic-gate * To make sure that the trap code and the interrupt code are not going 15607c478bd9Sstevel@tonic-gate * to step on each others toes we have a per chip pci_fm_mutex. This also 15617c478bd9Sstevel@tonic-gate * makes it necessary for us to be cautious while we are at a high PIL, so 15627c478bd9Sstevel@tonic-gate * that we do not cause a subsequent trap that causes us to hang. 15637c478bd9Sstevel@tonic-gate * 15647c478bd9Sstevel@tonic-gate * The attempt to commonize code was meant to keep in line with the current 15657c478bd9Sstevel@tonic-gate * pci driver implementation and it was not meant to confuse. If you are 15667c478bd9Sstevel@tonic-gate * confused then don't worry, I was too. 15677c478bd9Sstevel@tonic-gate */ 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate /* 15707c478bd9Sstevel@tonic-gate * For Psycho, a UE is always fatal, except if it is a translation error on a 15717c478bd9Sstevel@tonic-gate * Darwin platform. We ignore these because they do not cause data corruption. 15727c478bd9Sstevel@tonic-gate */ 15737c478bd9Sstevel@tonic-gate int 15747c478bd9Sstevel@tonic-gate ecc_ue_is_fatal(struct async_flt *ecc) 15757c478bd9Sstevel@tonic-gate { 15767c478bd9Sstevel@tonic-gate return (((uint_t)(ecc->flt_stat >> SABRE_UE_AFSR_PDTE_SHIFT) & 15777c478bd9Sstevel@tonic-gate SABRE_UE_AFSR_E_PDTE) == 0); 15787c478bd9Sstevel@tonic-gate } 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate /* 15817c478bd9Sstevel@tonic-gate * pci_ecc_classify, called by ecc_handler to classify ecc errors 15827c478bd9Sstevel@tonic-gate * and determine if we should panic or not. 1583a1ca9cb8Sarutz * 1584a1ca9cb8Sarutz * Note that it is possible yet extremely rare for more than one 1585a1ca9cb8Sarutz * primary error bit to be set. We classify the ecc error based 1586a1ca9cb8Sarutz * on the first set bit that is found. 15877c478bd9Sstevel@tonic-gate */ 15887c478bd9Sstevel@tonic-gate void 15897c478bd9Sstevel@tonic-gate pci_ecc_classify(uint64_t err, ecc_errstate_t *ecc_err_p) 15907c478bd9Sstevel@tonic-gate { 15917c478bd9Sstevel@tonic-gate struct async_flt *ecc = &ecc_err_p->ecc_aflt; 15927c478bd9Sstevel@tonic-gate pci_common_t *cmn_p = ecc_err_p->ecc_ii_p.ecc_p->ecc_pci_cmn_p; 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cmn_p->pci_fm_mutex)); 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate ecc_err_p->ecc_bridge_type = PCI_BRIDGE_TYPE(cmn_p); 15977c478bd9Sstevel@tonic-gate /* 15987c478bd9Sstevel@tonic-gate * Get the parent bus id that caused the error. 15997c478bd9Sstevel@tonic-gate */ 16007c478bd9Sstevel@tonic-gate ecc_err_p->ecc_dev_id = (ecc_err_p->ecc_afsr & PSYCHO_ECC_UE_AFSR_ID) 16017c478bd9Sstevel@tonic-gate >> PSYCHO_ECC_UE_AFSR_ID_SHIFT; 16027c478bd9Sstevel@tonic-gate /* 16037c478bd9Sstevel@tonic-gate * Determine the doubleword offset of the error. 16047c478bd9Sstevel@tonic-gate */ 16057c478bd9Sstevel@tonic-gate ecc_err_p->ecc_dw_offset = (ecc_err_p->ecc_afsr & 16067c478bd9Sstevel@tonic-gate PSYCHO_ECC_UE_AFSR_DW_OFFSET) 16077c478bd9Sstevel@tonic-gate >> PSYCHO_ECC_UE_AFSR_DW_OFFSET_SHIFT; 16087c478bd9Sstevel@tonic-gate /* 16097c478bd9Sstevel@tonic-gate * Determine the primary error type. 16107c478bd9Sstevel@tonic-gate */ 1611*39470729Skd93003 if (err & COMMON_ECC_AFSR_E_PIO) { 16127c478bd9Sstevel@tonic-gate if (ecc_err_p->ecc_ii_p.ecc_type == CBNINTR_UE) { 16137c478bd9Sstevel@tonic-gate if (ecc_err_p->ecc_pri) { 16147c478bd9Sstevel@tonic-gate ecc->flt_erpt_class = PCI_ECC_PIO_UE; 16157c478bd9Sstevel@tonic-gate } else { 16167c478bd9Sstevel@tonic-gate ecc->flt_erpt_class = PCI_ECC_SEC_PIO_UE; 16177c478bd9Sstevel@tonic-gate } 16187c478bd9Sstevel@tonic-gate ecc->flt_panic = ecc_ue_is_fatal(&ecc_err_p->ecc_aflt); 16197c478bd9Sstevel@tonic-gate } else { 16207c478bd9Sstevel@tonic-gate ecc->flt_erpt_class = ecc_err_p->ecc_pri ? 16217c478bd9Sstevel@tonic-gate PCI_ECC_PIO_CE : PCI_ECC_SEC_PIO_CE; 16227c478bd9Sstevel@tonic-gate return; 16237c478bd9Sstevel@tonic-gate } 1624*39470729Skd93003 } else if (err & COMMON_ECC_AFSR_E_DRD) { 16257c478bd9Sstevel@tonic-gate if (ecc_err_p->ecc_ii_p.ecc_type == CBNINTR_UE) { 16267c478bd9Sstevel@tonic-gate if (ecc_err_p->ecc_pri) { 16277c478bd9Sstevel@tonic-gate ecc->flt_erpt_class = PCI_ECC_DRD_UE; 16287c478bd9Sstevel@tonic-gate } else { 16297c478bd9Sstevel@tonic-gate ecc->flt_erpt_class = PCI_ECC_SEC_DRD_UE; 16307c478bd9Sstevel@tonic-gate } 16317c478bd9Sstevel@tonic-gate ecc->flt_panic = ecc_ue_is_fatal(&ecc_err_p->ecc_aflt); 16327c478bd9Sstevel@tonic-gate } else { 16337c478bd9Sstevel@tonic-gate ecc->flt_erpt_class = ecc_err_p->ecc_pri ? 16347c478bd9Sstevel@tonic-gate PCI_ECC_DRD_CE : PCI_ECC_SEC_DRD_CE; 16357c478bd9Sstevel@tonic-gate return; 16367c478bd9Sstevel@tonic-gate } 1637*39470729Skd93003 } else if (err & COMMON_ECC_AFSR_E_DWR) { 16387c478bd9Sstevel@tonic-gate if (ecc_err_p->ecc_ii_p.ecc_type == CBNINTR_UE) { 16397c478bd9Sstevel@tonic-gate if (ecc_err_p->ecc_pri) { 16407c478bd9Sstevel@tonic-gate ecc->flt_erpt_class = PCI_ECC_DWR_UE; 16417c478bd9Sstevel@tonic-gate } else { 16427c478bd9Sstevel@tonic-gate ecc->flt_erpt_class = PCI_ECC_SEC_DWR_UE; 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate ecc->flt_panic = ecc_ue_is_fatal(&ecc_err_p->ecc_aflt); 16457c478bd9Sstevel@tonic-gate } else { 16467c478bd9Sstevel@tonic-gate ecc->flt_erpt_class = ecc_err_p->ecc_pri ? 16477c478bd9Sstevel@tonic-gate PCI_ECC_DWR_CE : PCI_ECC_SEC_DWR_CE; 16487c478bd9Sstevel@tonic-gate return; 16497c478bd9Sstevel@tonic-gate } 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate } 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate ushort_t 16547c478bd9Sstevel@tonic-gate pci_ecc_get_synd(uint64_t afsr) 16557c478bd9Sstevel@tonic-gate { 16567c478bd9Sstevel@tonic-gate return ((ushort_t)((afsr & PSYCHO_ECC_CE_AFSR_SYND) 16577c478bd9Sstevel@tonic-gate >> PSYCHO_ECC_CE_AFSR_SYND_SHIFT)); 16587c478bd9Sstevel@tonic-gate } 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate /* 16617c478bd9Sstevel@tonic-gate * pci_pbm_classify, called by pbm_afsr_report to classify piow afsr. 16627c478bd9Sstevel@tonic-gate */ 16637c478bd9Sstevel@tonic-gate int 16647c478bd9Sstevel@tonic-gate pci_pbm_classify(pbm_errstate_t *pbm_err_p) 16657c478bd9Sstevel@tonic-gate { 16667c478bd9Sstevel@tonic-gate uint32_t e; 16677c478bd9Sstevel@tonic-gate int nerr = 0; 16687c478bd9Sstevel@tonic-gate char **tmp_class; 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate if (pbm_err_p->pbm_pri) { 16717c478bd9Sstevel@tonic-gate tmp_class = &pbm_err_p->pbm_pci.pci_err_class; 16727c478bd9Sstevel@tonic-gate e = PBM_AFSR_TO_PRIERR(pbm_err_p->pbm_afsr); 16737c478bd9Sstevel@tonic-gate pbm_err_p->pbm_log = FM_LOG_PCI; 16747c478bd9Sstevel@tonic-gate } else { 16757c478bd9Sstevel@tonic-gate tmp_class = &pbm_err_p->pbm_err_class; 16767c478bd9Sstevel@tonic-gate e = PBM_AFSR_TO_SECERR(pbm_err_p->pbm_afsr); 16777c478bd9Sstevel@tonic-gate pbm_err_p->pbm_log = FM_LOG_PBM; 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate if (e & PSYCHO_PCI_AFSR_E_MA) { 16817c478bd9Sstevel@tonic-gate *tmp_class = pbm_err_p->pbm_pri ? PCI_MA : PCI_SEC_MA; 16827c478bd9Sstevel@tonic-gate nerr++; 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate if (e & PSYCHO_PCI_AFSR_E_TA) { 16857c478bd9Sstevel@tonic-gate *tmp_class = pbm_err_p->pbm_pri ? PCI_REC_TA : PCI_SEC_REC_TA; 16867c478bd9Sstevel@tonic-gate nerr++; 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate if (e & PSYCHO_PCI_AFSR_E_RTRY) { 16897c478bd9Sstevel@tonic-gate pbm_err_p->pbm_err_class = pbm_err_p->pbm_pri ? 16907c478bd9Sstevel@tonic-gate PCI_PBM_RETRY : PCI_SEC_PBM_RETRY; 16917c478bd9Sstevel@tonic-gate pbm_err_p->pbm_log = FM_LOG_PBM; 16927c478bd9Sstevel@tonic-gate nerr++; 16937c478bd9Sstevel@tonic-gate } 16947c478bd9Sstevel@tonic-gate if (e & PSYCHO_PCI_AFSR_E_PERR) { 16957c478bd9Sstevel@tonic-gate *tmp_class = pbm_err_p->pbm_pri ? PCI_MDPE : PCI_SEC_MDPE; 16967c478bd9Sstevel@tonic-gate nerr++; 16977c478bd9Sstevel@tonic-gate } 16987c478bd9Sstevel@tonic-gate return (nerr); 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate 17017c478bd9Sstevel@tonic-gate /* 17027c478bd9Sstevel@tonic-gate * Function used to clear PBM/PCI/IOMMU error state after error handling 17037c478bd9Sstevel@tonic-gate * is complete. Only clearing error bits which have been logged. Called by 17047c478bd9Sstevel@tonic-gate * pci_pbm_err_handler and pci_bus_exit. 17057c478bd9Sstevel@tonic-gate */ 17067c478bd9Sstevel@tonic-gate static void 17077c478bd9Sstevel@tonic-gate pci_clear_error(pci_t *pci_p, pbm_errstate_t *pbm_err_p) 17087c478bd9Sstevel@tonic-gate { 17097c478bd9Sstevel@tonic-gate pbm_t *pbm_p = pci_p->pci_pbm_p; 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pbm_p->pbm_pci_p->pci_common_p->pci_fm_mutex)); 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate *pbm_p->pbm_ctrl_reg = pbm_err_p->pbm_ctl_stat; 17147c478bd9Sstevel@tonic-gate *pbm_p->pbm_async_flt_status_reg = pbm_err_p->pbm_afsr; 17157c478bd9Sstevel@tonic-gate pbm_p->pbm_config_header->ch_status_reg = 17167c478bd9Sstevel@tonic-gate pbm_err_p->pbm_pci.pci_cfg_stat; 17177c478bd9Sstevel@tonic-gate } 17187c478bd9Sstevel@tonic-gate 17197c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17207c478bd9Sstevel@tonic-gate int 17217c478bd9Sstevel@tonic-gate pci_pbm_err_handler(dev_info_t *dip, ddi_fm_error_t *derr, 17227c478bd9Sstevel@tonic-gate const void *impl_data, int caller) 17237c478bd9Sstevel@tonic-gate { 17247c478bd9Sstevel@tonic-gate int fatal = 0; 17257c478bd9Sstevel@tonic-gate int nonfatal = 0; 17267c478bd9Sstevel@tonic-gate int unknown = 0; 17277c478bd9Sstevel@tonic-gate uint32_t prierr, secerr; 17287c478bd9Sstevel@tonic-gate pbm_errstate_t pbm_err; 17297c478bd9Sstevel@tonic-gate char buf[FM_MAX_CLASS]; 17307c478bd9Sstevel@tonic-gate pci_t *pci_p = (pci_t *)impl_data; 17317c478bd9Sstevel@tonic-gate pbm_t *pbm_p = pci_p->pci_pbm_p; 17327c478bd9Sstevel@tonic-gate int ret = 0; 17337c478bd9Sstevel@tonic-gate uint64_t pbm_ctl_stat; 17347c478bd9Sstevel@tonic-gate uint16_t pci_cfg_stat; 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pci_p->pci_common_p->pci_fm_mutex)); 17377c478bd9Sstevel@tonic-gate pci_pbm_errstate_get(pci_p, &pbm_err); 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate derr->fme_ena = derr->fme_ena ? derr->fme_ena : 17407c478bd9Sstevel@tonic-gate fm_ena_generate(0, FM_ENA_FMT1); 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate prierr = PBM_AFSR_TO_PRIERR(pbm_err.pbm_afsr); 17437c478bd9Sstevel@tonic-gate secerr = PBM_AFSR_TO_SECERR(pbm_err.pbm_afsr); 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate if (derr->fme_flag == DDI_FM_ERR_EXPECTED) { 17467c478bd9Sstevel@tonic-gate if (caller == PCI_TRAP_CALL) { 17477c478bd9Sstevel@tonic-gate /* 17487c478bd9Sstevel@tonic-gate * For ddi_caut_get treat all events as 17497c478bd9Sstevel@tonic-gate * nonfatal. The trampoline will set 17507c478bd9Sstevel@tonic-gate * err_ena = 0, err_status = NONFATAL. We only 17517c478bd9Sstevel@tonic-gate * really call this function so that pci_clear_error() 17527c478bd9Sstevel@tonic-gate * and ndi_fm_handler_dispatch() will get called. 17537c478bd9Sstevel@tonic-gate */ 17547c478bd9Sstevel@tonic-gate derr->fme_status = DDI_FM_NONFATAL; 17557c478bd9Sstevel@tonic-gate nonfatal++; 17567c478bd9Sstevel@tonic-gate goto done; 17577c478bd9Sstevel@tonic-gate } else { 17587c478bd9Sstevel@tonic-gate /* 17597c478bd9Sstevel@tonic-gate * For ddi_caut_put treat all events as nonfatal. Here 17607c478bd9Sstevel@tonic-gate * we have the handle and can call ndi_fm_acc_err_set(). 17617c478bd9Sstevel@tonic-gate */ 17627c478bd9Sstevel@tonic-gate derr->fme_status = DDI_FM_NONFATAL; 17637c478bd9Sstevel@tonic-gate ndi_fm_acc_err_set(pbm_p->pbm_excl_handle, derr); 17647c478bd9Sstevel@tonic-gate nonfatal++; 17657c478bd9Sstevel@tonic-gate goto done; 17667c478bd9Sstevel@tonic-gate } 17677c478bd9Sstevel@tonic-gate } else if (derr->fme_flag == DDI_FM_ERR_PEEK) { 17687c478bd9Sstevel@tonic-gate /* 17697c478bd9Sstevel@tonic-gate * For ddi_peek treat all events as nonfatal. We only 17707c478bd9Sstevel@tonic-gate * really call this function so that pci_clear_error() 17717c478bd9Sstevel@tonic-gate * and ndi_fm_handler_dispatch() will get called. 17727c478bd9Sstevel@tonic-gate */ 17737c478bd9Sstevel@tonic-gate nonfatal++; 17747c478bd9Sstevel@tonic-gate goto done; 17757c478bd9Sstevel@tonic-gate } else if (derr->fme_flag == DDI_FM_ERR_POKE) { 17767c478bd9Sstevel@tonic-gate /* 17777c478bd9Sstevel@tonic-gate * For ddi_poke we can treat as nonfatal if the 17787c478bd9Sstevel@tonic-gate * following conditions are met : 17797c478bd9Sstevel@tonic-gate * 1. Make sure only primary error is MA/TA 17807c478bd9Sstevel@tonic-gate * 2. Make sure no secondary error 17817c478bd9Sstevel@tonic-gate * 3. check pci config header stat reg to see MA/TA is 17827c478bd9Sstevel@tonic-gate * logged. We cannot verify only MA/TA is recorded 17837c478bd9Sstevel@tonic-gate * since it gets much more complicated when a 17847c478bd9Sstevel@tonic-gate * PCI-to-PCI bridge is present. 17857c478bd9Sstevel@tonic-gate */ 17867c478bd9Sstevel@tonic-gate if ((prierr == PSYCHO_PCI_AFSR_E_MA) && !secerr && 17877c478bd9Sstevel@tonic-gate (pbm_err.pbm_pci.pci_cfg_stat & PCI_STAT_R_MAST_AB)) { 17887c478bd9Sstevel@tonic-gate nonfatal++; 17897c478bd9Sstevel@tonic-gate goto done; 17907c478bd9Sstevel@tonic-gate } 17917c478bd9Sstevel@tonic-gate if ((prierr == PSYCHO_PCI_AFSR_E_TA) && !secerr && 17927c478bd9Sstevel@tonic-gate (pbm_err.pbm_pci.pci_cfg_stat & PCI_STAT_R_TARG_AB)) { 17937c478bd9Sstevel@tonic-gate nonfatal++; 17947c478bd9Sstevel@tonic-gate goto done; 17957c478bd9Sstevel@tonic-gate } 17967c478bd9Sstevel@tonic-gate } 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate if (prierr || secerr) { 17997c478bd9Sstevel@tonic-gate ret = pbm_afsr_report(dip, derr->fme_ena, &pbm_err); 18007c478bd9Sstevel@tonic-gate if (ret == DDI_FM_FATAL) 18017c478bd9Sstevel@tonic-gate fatal++; 18027c478bd9Sstevel@tonic-gate else 18037c478bd9Sstevel@tonic-gate nonfatal++; 18047c478bd9Sstevel@tonic-gate } 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate ret = pci_cfg_report(dip, derr, &pbm_err.pbm_pci, caller, prierr); 18077c478bd9Sstevel@tonic-gate if (ret == DDI_FM_FATAL) 18087c478bd9Sstevel@tonic-gate fatal++; 18097c478bd9Sstevel@tonic-gate else if (ret == DDI_FM_NONFATAL) 18107c478bd9Sstevel@tonic-gate nonfatal++; 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate pbm_ctl_stat = pbm_err.pbm_ctl_stat; 18137c478bd9Sstevel@tonic-gate pci_cfg_stat = pbm_err.pbm_pci.pci_cfg_stat; 18147c478bd9Sstevel@tonic-gate 18157c478bd9Sstevel@tonic-gate /* 18167c478bd9Sstevel@tonic-gate * PBM Received System Error - During any transaction, or 18177c478bd9Sstevel@tonic-gate * at any point on the bus, some device may detect a critical 18187c478bd9Sstevel@tonic-gate * error and signal a system error to the system. 18197c478bd9Sstevel@tonic-gate */ 18207c478bd9Sstevel@tonic-gate if (pbm_ctl_stat & COMMON_PCI_CTRL_SERR) { 18217c478bd9Sstevel@tonic-gate /* 18227c478bd9Sstevel@tonic-gate * may be expected (master abort from pci-pci bridge during 18237c478bd9Sstevel@tonic-gate * poke will generate SERR) 18247c478bd9Sstevel@tonic-gate */ 18257c478bd9Sstevel@tonic-gate if (derr->fme_flag != DDI_FM_ERR_POKE) { 18267c478bd9Sstevel@tonic-gate pbm_err.pbm_pci.pci_err_class = PCI_REC_SERR; 18277c478bd9Sstevel@tonic-gate (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", 18287c478bd9Sstevel@tonic-gate PCI_ERROR_SUBCLASS, pbm_err.pbm_pci.pci_err_class); 18297c478bd9Sstevel@tonic-gate ddi_fm_ereport_post(dip, buf, derr->fme_ena, 18307c478bd9Sstevel@tonic-gate DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, 18317c478bd9Sstevel@tonic-gate PCI_CONFIG_STATUS, DATA_TYPE_UINT16, pci_cfg_stat, 18327c478bd9Sstevel@tonic-gate PCI_CONFIG_COMMAND, DATA_TYPE_UINT16, 18337c478bd9Sstevel@tonic-gate pbm_err.pbm_pci.pci_cfg_comm, PCI_PA, 18347c478bd9Sstevel@tonic-gate DATA_TYPE_UINT64, (uint64_t)0, NULL); 18357c478bd9Sstevel@tonic-gate } 183600d0963fSdilpreet unknown++; 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate 18397c478bd9Sstevel@tonic-gate /* Streaming Byte Hole Error */ 18407c478bd9Sstevel@tonic-gate if (pbm_ctl_stat & COMMON_PCI_CTRL_SBH_ERR) { 18417c478bd9Sstevel@tonic-gate if (pci_panic_on_sbh_errors) 18427c478bd9Sstevel@tonic-gate fatal++; 18437c478bd9Sstevel@tonic-gate else 18447c478bd9Sstevel@tonic-gate nonfatal++; 18457c478bd9Sstevel@tonic-gate pbm_err.pbm_err_class = PCI_PSY_SBH; 18467c478bd9Sstevel@tonic-gate pbm_ereport_post(dip, derr->fme_ena, &pbm_err); 18477c478bd9Sstevel@tonic-gate } 18487c478bd9Sstevel@tonic-gate done: 18497c478bd9Sstevel@tonic-gate ret = ndi_fm_handler_dispatch(dip, NULL, derr); 18507c478bd9Sstevel@tonic-gate if (ret == DDI_FM_FATAL) { 18517c478bd9Sstevel@tonic-gate fatal++; 18527c478bd9Sstevel@tonic-gate } else if (ret == DDI_FM_NONFATAL) { 18537c478bd9Sstevel@tonic-gate nonfatal++; 18547c478bd9Sstevel@tonic-gate } else if (ret == DDI_FM_UNKNOWN) { 18557c478bd9Sstevel@tonic-gate unknown++; 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate /* 18597c478bd9Sstevel@tonic-gate * rserr not claimed as nonfatal by a child is treated as fatal 18607c478bd9Sstevel@tonic-gate */ 186100d0963fSdilpreet if (unknown && !nonfatal && !fatal) 18627c478bd9Sstevel@tonic-gate fatal++; 18637c478bd9Sstevel@tonic-gate 18647c478bd9Sstevel@tonic-gate /* Cleanup and reset error bits */ 18657c478bd9Sstevel@tonic-gate pci_clear_error(pci_p, &pbm_err); 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL : 18687c478bd9Sstevel@tonic-gate (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK))); 18697c478bd9Sstevel@tonic-gate } 18707c478bd9Sstevel@tonic-gate 18717c478bd9Sstevel@tonic-gate int 18727c478bd9Sstevel@tonic-gate pci_check_error(pci_t *pci_p) 18737c478bd9Sstevel@tonic-gate { 18747c478bd9Sstevel@tonic-gate pbm_t *pbm_p = pci_p->pci_pbm_p; 18757c478bd9Sstevel@tonic-gate uint16_t pci_cfg_stat; 18767c478bd9Sstevel@tonic-gate uint64_t pbm_ctl_stat, pbm_afsr; 18777c478bd9Sstevel@tonic-gate 18787c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pci_p->pci_common_p->pci_fm_mutex)); 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate pci_cfg_stat = pbm_p->pbm_config_header->ch_status_reg; 18817c478bd9Sstevel@tonic-gate pbm_ctl_stat = *pbm_p->pbm_ctrl_reg; 18827c478bd9Sstevel@tonic-gate pbm_afsr = *pbm_p->pbm_async_flt_status_reg; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate if ((pci_cfg_stat & (PCI_STAT_S_PERROR | PCI_STAT_S_TARG_AB | 18857c478bd9Sstevel@tonic-gate PCI_STAT_R_TARG_AB | PCI_STAT_R_MAST_AB | 18867c478bd9Sstevel@tonic-gate PCI_STAT_S_SYSERR | PCI_STAT_PERROR)) || 18877c478bd9Sstevel@tonic-gate (pbm_ctl_stat & (COMMON_PCI_CTRL_SBH_ERR | 18887c478bd9Sstevel@tonic-gate COMMON_PCI_CTRL_SERR)) || 18897c478bd9Sstevel@tonic-gate (PBM_AFSR_TO_PRIERR(pbm_afsr))) 18907c478bd9Sstevel@tonic-gate return (1); 18917c478bd9Sstevel@tonic-gate 18927c478bd9Sstevel@tonic-gate return (0); 18937c478bd9Sstevel@tonic-gate 18947c478bd9Sstevel@tonic-gate } 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate /* 18977c478bd9Sstevel@tonic-gate * Function used to gather PBM/PCI error state for the 18987c478bd9Sstevel@tonic-gate * pci_pbm_err_handler. This function must be called while pci_fm_mutex 18997c478bd9Sstevel@tonic-gate * is held. 19007c478bd9Sstevel@tonic-gate */ 19017c478bd9Sstevel@tonic-gate static void 19027c478bd9Sstevel@tonic-gate pci_pbm_errstate_get(pci_t *pci_p, pbm_errstate_t *pbm_err_p) 19037c478bd9Sstevel@tonic-gate { 19047c478bd9Sstevel@tonic-gate pbm_t *pbm_p = pci_p->pci_pbm_p; 19057c478bd9Sstevel@tonic-gate 19067c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pci_p->pci_common_p->pci_fm_mutex)); 19077c478bd9Sstevel@tonic-gate bzero(pbm_err_p, sizeof (pbm_errstate_t)); 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate /* 19107c478bd9Sstevel@tonic-gate * Capture all pbm error state for later logging 19117c478bd9Sstevel@tonic-gate */ 19127c478bd9Sstevel@tonic-gate pbm_err_p->pbm_bridge_type = PCI_BRIDGE_TYPE(pci_p->pci_common_p); 19137c478bd9Sstevel@tonic-gate pbm_err_p->pbm_pci.pci_cfg_stat = 19147c478bd9Sstevel@tonic-gate pbm_p->pbm_config_header->ch_status_reg; 19157c478bd9Sstevel@tonic-gate pbm_err_p->pbm_ctl_stat = *pbm_p->pbm_ctrl_reg; 19167c478bd9Sstevel@tonic-gate pbm_err_p->pbm_pci.pci_cfg_comm = 19177c478bd9Sstevel@tonic-gate pbm_p->pbm_config_header->ch_command_reg; 19187c478bd9Sstevel@tonic-gate pbm_err_p->pbm_afsr = *pbm_p->pbm_async_flt_status_reg; 19197c478bd9Sstevel@tonic-gate pbm_err_p->pbm_afar = *pbm_p->pbm_async_flt_addr_reg; 19207c478bd9Sstevel@tonic-gate pbm_err_p->pbm_pci.pci_pa = *pbm_p->pbm_async_flt_addr_reg; 19217c478bd9Sstevel@tonic-gate } 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate void 19247c478bd9Sstevel@tonic-gate pbm_clear_error(pbm_t *pbm_p) 19257c478bd9Sstevel@tonic-gate { 19267c478bd9Sstevel@tonic-gate uint64_t pbm_afsr, pbm_ctl_stat; 19277c478bd9Sstevel@tonic-gate 19287c478bd9Sstevel@tonic-gate /* 19297c478bd9Sstevel@tonic-gate * for poke() support - called from POKE_FLUSH. Spin waiting 19307c478bd9Sstevel@tonic-gate * for MA, TA or SERR to be cleared by a pbm_error_intr(). 19317c478bd9Sstevel@tonic-gate * We have to wait for SERR too in case the device is beyond 19327c478bd9Sstevel@tonic-gate * a pci-pci bridge. 19337c478bd9Sstevel@tonic-gate */ 19347c478bd9Sstevel@tonic-gate pbm_ctl_stat = *pbm_p->pbm_ctrl_reg; 19357c478bd9Sstevel@tonic-gate pbm_afsr = *pbm_p->pbm_async_flt_status_reg; 19367c478bd9Sstevel@tonic-gate while (((pbm_afsr >> PSYCHO_PCI_AFSR_PE_SHIFT) & 19377c478bd9Sstevel@tonic-gate (PSYCHO_PCI_AFSR_E_MA | PSYCHO_PCI_AFSR_E_TA)) || 19387c478bd9Sstevel@tonic-gate (pbm_ctl_stat & COMMON_PCI_CTRL_SERR)) { 19397c478bd9Sstevel@tonic-gate pbm_ctl_stat = *pbm_p->pbm_ctrl_reg; 19407c478bd9Sstevel@tonic-gate pbm_afsr = *pbm_p->pbm_async_flt_status_reg; 19417c478bd9Sstevel@tonic-gate } 19427c478bd9Sstevel@tonic-gate } 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19457c478bd9Sstevel@tonic-gate void 19467c478bd9Sstevel@tonic-gate pci_format_addr(dev_info_t *dip, uint64_t *afar, uint64_t afsr) 19477c478bd9Sstevel@tonic-gate { 19487c478bd9Sstevel@tonic-gate /* 19497c478bd9Sstevel@tonic-gate * For Psycho the full address is stored in hardware. So 19507c478bd9Sstevel@tonic-gate * there is no need to format it. 19517c478bd9Sstevel@tonic-gate */ 19527c478bd9Sstevel@tonic-gate } 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19557c478bd9Sstevel@tonic-gate int 19567c478bd9Sstevel@tonic-gate pci_bus_quiesce(pci_t *pci_p, dev_info_t *dip, void *result) 19577c478bd9Sstevel@tonic-gate { 19587c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 19597c478bd9Sstevel@tonic-gate } 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19627c478bd9Sstevel@tonic-gate int 19637c478bd9Sstevel@tonic-gate pci_bus_unquiesce(pci_t *pci_p, dev_info_t *dip, void *result) 19647c478bd9Sstevel@tonic-gate { 19657c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate 1968d0662dbfSelowe int 1969d0662dbfSelowe pci_reloc_getkey(void) 1970d0662dbfSelowe { 1971d0662dbfSelowe return (0x100); 1972d0662dbfSelowe } 1973d0662dbfSelowe 19747c478bd9Sstevel@tonic-gate void 19757c478bd9Sstevel@tonic-gate pci_vmem_free(iommu_t *iommu_p, ddi_dma_impl_t *mp, void *dvma_addr, 19767c478bd9Sstevel@tonic-gate size_t npages) 19777c478bd9Sstevel@tonic-gate { 19787c478bd9Sstevel@tonic-gate pci_vmem_do_free(iommu_p, dvma_addr, npages, 19797c478bd9Sstevel@tonic-gate (mp->dmai_flags & DMAI_FLAGS_VMEMCACHE)); 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate /* 19847c478bd9Sstevel@tonic-gate * NOTE: This call is only used by legacy systems (eg. E250 and E450) that 19857c478bd9Sstevel@tonic-gate * require unregistering the pci driver's thermal intrerrupt handler before 19867c478bd9Sstevel@tonic-gate * they can register their own. 19877c478bd9Sstevel@tonic-gate */ 19887c478bd9Sstevel@tonic-gate void 19897c478bd9Sstevel@tonic-gate pci_thermal_rem_intr(dev_info_t *rdip, uint_t inum) 19907c478bd9Sstevel@tonic-gate { 19917c478bd9Sstevel@tonic-gate pci_t *pci_p; 19927c478bd9Sstevel@tonic-gate dev_info_t *pdip; 19937c478bd9Sstevel@tonic-gate uint32_t dev_mondo, pci_mondo; 19947c478bd9Sstevel@tonic-gate int instance; 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate for (pdip = ddi_get_parent(rdip); pdip; pdip = ddi_get_parent(pdip)) { 19977c478bd9Sstevel@tonic-gate if (strcmp(ddi_driver_name(pdip), "pcipsy") == 0) 19987c478bd9Sstevel@tonic-gate break; 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate 20017c478bd9Sstevel@tonic-gate if (!pdip) { 20027c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pci_thermal_rem_intr() no pcipsy parent\n"); 20037c478bd9Sstevel@tonic-gate return; 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate instance = ddi_get_instance(pdip); 20077c478bd9Sstevel@tonic-gate pci_p = get_pci_soft_state(instance); 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate /* Calculate the requesting device's mondo */ 20107c478bd9Sstevel@tonic-gate dev_mondo = pci_xlate_intr(pci_p->pci_dip, rdip, pci_p->pci_ib_p, 2011a195726fSgovinda IB_MONDO_TO_INO(i_ddi_get_inum(rdip, inum))); 20127c478bd9Sstevel@tonic-gate 20137c478bd9Sstevel@tonic-gate /* get pci's thermal mondo */ 20147c478bd9Sstevel@tonic-gate pci_mondo = ((pci_p->pci_cb_p->cb_ign << PCI_INO_BITS) | 20157c478bd9Sstevel@tonic-gate pci_p->pci_inos[CBNINTR_THERMAL]); 20167c478bd9Sstevel@tonic-gate pci_mondo = CB_MONDO_TO_XMONDO(pci_p->pci_cb_p, pci_mondo); 20177c478bd9Sstevel@tonic-gate 20187c478bd9Sstevel@tonic-gate if (pci_mondo == dev_mondo) { 20197c478bd9Sstevel@tonic-gate DEBUG2(DBG_ATTACH, rdip, "pci_thermal_rem_intr unregistered " 20207c478bd9Sstevel@tonic-gate "for dip=%s%d:", ddi_driver_name(rdip), 20217c478bd9Sstevel@tonic-gate ddi_get_instance(rdip)); 2022b0fc0e77Sgovinda VERIFY(rem_ivintr(pci_mondo, pci_pil[CBNINTR_THERMAL]) == 0); 20237c478bd9Sstevel@tonic-gate } 20247c478bd9Sstevel@tonic-gate } 202549f91442Ssuha 202649f91442Ssuha /* 202749f91442Ssuha * pci_iommu_bypass_end_configure 202849f91442Ssuha * 202949f91442Ssuha * Support for 40-bit bus width to UPA in DVMA and iommu bypass transfers: 203049f91442Ssuha */ 203149f91442Ssuha 203249f91442Ssuha dma_bypass_addr_t 203349f91442Ssuha pci_iommu_bypass_end_configure(void) 203449f91442Ssuha { 203549f91442Ssuha 203649f91442Ssuha return ((dma_bypass_addr_t)UPA_IOMMU_BYPASS_END); 203749f91442Ssuha } 2038