1d4bc0535SKrishna Elango /* 2d4bc0535SKrishna Elango * CDDL HEADER START 3d4bc0535SKrishna Elango * 4d4bc0535SKrishna Elango * The contents of this file are subject to the terms of the 5d4bc0535SKrishna Elango * Common Development and Distribution License (the "License"). 6d4bc0535SKrishna Elango * You may not use this file except in compliance with the License. 7d4bc0535SKrishna Elango * 8d4bc0535SKrishna Elango * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d4bc0535SKrishna Elango * or http://www.opensolaris.org/os/licensing. 10d4bc0535SKrishna Elango * See the License for the specific language governing permissions 11d4bc0535SKrishna Elango * and limitations under the License. 12d4bc0535SKrishna Elango * 13d4bc0535SKrishna Elango * When distributing Covered Code, include this CDDL HEADER in each 14d4bc0535SKrishna Elango * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d4bc0535SKrishna Elango * If applicable, add the following below this CDDL HEADER, with the 16d4bc0535SKrishna Elango * fields enclosed by brackets "[]" replaced with your own identifying 17d4bc0535SKrishna Elango * information: Portions Copyright [yyyy] [name of copyright owner] 18d4bc0535SKrishna Elango * 19d4bc0535SKrishna Elango * CDDL HEADER END 20d4bc0535SKrishna Elango */ 21d4bc0535SKrishna Elango /* 222e98bdabSvitezslav batrla - Sun Microsystems - Prague Czech Republic * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23d4bc0535SKrishna Elango */ 24*cd21e7c5SGarrett D'Amore /* 25*cd21e7c5SGarrett D'Amore * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. 26*cd21e7c5SGarrett D'Amore */ 27d4bc0535SKrishna Elango 28d4bc0535SKrishna Elango /* 29d4bc0535SKrishna Elango * Common x86 and SPARC PCI-E to PCI bus bridge nexus driver 30d4bc0535SKrishna Elango */ 31d4bc0535SKrishna Elango 32d4bc0535SKrishna Elango #include <sys/sysmacros.h> 33d4bc0535SKrishna Elango #include <sys/conf.h> 34d4bc0535SKrishna Elango #include <sys/kmem.h> 35d4bc0535SKrishna Elango #include <sys/debug.h> 36d4bc0535SKrishna Elango #include <sys/modctl.h> 37d4bc0535SKrishna Elango #include <sys/autoconf.h> 38d4bc0535SKrishna Elango #include <sys/ddi_impldefs.h> 39d4bc0535SKrishna Elango #include <sys/pci.h> 40d4bc0535SKrishna Elango #include <sys/ddi.h> 41d4bc0535SKrishna Elango #include <sys/sunddi.h> 42d4bc0535SKrishna Elango #include <sys/sunndi.h> 43d4bc0535SKrishna Elango #include <sys/fm/util.h> 44d4bc0535SKrishna Elango #include <sys/pci_cap.h> 4526947304SEvan Yan #include <sys/pci_impl.h> 46d4bc0535SKrishna Elango #include <sys/pcie_impl.h> 47d4bc0535SKrishna Elango #include <sys/open.h> 48d4bc0535SKrishna Elango #include <sys/stat.h> 49d4bc0535SKrishna Elango #include <sys/file.h> 50d4bc0535SKrishna Elango #include <sys/promif.h> /* prom_printf */ 51d4bc0535SKrishna Elango #include <sys/disp.h> 52d4bc0535SKrishna Elango #include <sys/pcie_pwr.h> 5326947304SEvan Yan #include <sys/hotplug/pci/pcie_hp.h> 54d4bc0535SKrishna Elango #include "pcieb.h" 55d4bc0535SKrishna Elango #ifdef PX_PLX 56d4bc0535SKrishna Elango #include <io/pciex/pcieb_plx.h> 57d4bc0535SKrishna Elango #endif /* PX_PLX */ 58d4bc0535SKrishna Elango 59d4bc0535SKrishna Elango /*LINTLIBRARY*/ 60d4bc0535SKrishna Elango 61d4bc0535SKrishna Elango /* panic flag */ 62d4bc0535SKrishna Elango int pcieb_die = PF_ERR_FATAL_FLAGS; 6383e6495bSDaniel Ice int pcieb_disable_41210_wkarnd = 0; 64d4bc0535SKrishna Elango 65d4bc0535SKrishna Elango /* flag to turn on MSI support */ 6686a9c507SGuoli Shu int pcieb_enable_msi = 1; 67d4bc0535SKrishna Elango 68d4bc0535SKrishna Elango #if defined(DEBUG) 69d4bc0535SKrishna Elango uint_t pcieb_dbg_print = 0; 70d4bc0535SKrishna Elango 71d4bc0535SKrishna Elango static char *pcieb_debug_sym [] = { /* same sequence as pcieb_debug_bit */ 72d4bc0535SKrishna Elango /* 0 */ "attach", 73d4bc0535SKrishna Elango /* 1 */ "pwr", 74d4bc0535SKrishna Elango /* 2 */ "intr" 75d4bc0535SKrishna Elango }; 76d4bc0535SKrishna Elango #endif /* DEBUG */ 77d4bc0535SKrishna Elango 78d4bc0535SKrishna Elango static int pcieb_bus_map(dev_info_t *, dev_info_t *, ddi_map_req_t *, off_t, 79d4bc0535SKrishna Elango off_t, caddr_t *); 80d4bc0535SKrishna Elango static int pcieb_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, 81d4bc0535SKrishna Elango void *); 82d4bc0535SKrishna Elango static int pcieb_fm_init(pcieb_devstate_t *pcieb_p); 83d4bc0535SKrishna Elango static void pcieb_fm_fini(pcieb_devstate_t *pcieb_p); 84d4bc0535SKrishna Elango static int pcieb_fm_init_child(dev_info_t *dip, dev_info_t *cdip, int cap, 85d4bc0535SKrishna Elango ddi_iblock_cookie_t *ibc_p); 86d4bc0535SKrishna Elango static int pcieb_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 87d4bc0535SKrishna Elango ddi_dma_attr_t *attr_p, int (*waitfp)(caddr_t), caddr_t arg, 88d4bc0535SKrishna Elango ddi_dma_handle_t *handlep); 89d4bc0535SKrishna Elango static int pcieb_dma_mctl(dev_info_t *dip, dev_info_t *rdip, 90d4bc0535SKrishna Elango ddi_dma_handle_t handle, enum ddi_dma_ctlops cmd, off_t *offp, 91d4bc0535SKrishna Elango size_t *lenp, caddr_t *objp, uint_t cache_flags); 92d4bc0535SKrishna Elango static int pcieb_intr_ops(dev_info_t *dip, dev_info_t *rdip, 93d4bc0535SKrishna Elango ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result); 94d4bc0535SKrishna Elango 95d4bc0535SKrishna Elango static struct bus_ops pcieb_bus_ops = { 96d4bc0535SKrishna Elango BUSO_REV, 97d4bc0535SKrishna Elango pcieb_bus_map, 98d4bc0535SKrishna Elango 0, 99d4bc0535SKrishna Elango 0, 100d4bc0535SKrishna Elango 0, 101d4bc0535SKrishna Elango i_ddi_map_fault, 102*cd21e7c5SGarrett D'Amore 0, 103d4bc0535SKrishna Elango pcieb_dma_allochdl, 104d4bc0535SKrishna Elango ddi_dma_freehdl, 105d4bc0535SKrishna Elango ddi_dma_bindhdl, 106d4bc0535SKrishna Elango ddi_dma_unbindhdl, 107d4bc0535SKrishna Elango ddi_dma_flush, 108d4bc0535SKrishna Elango ddi_dma_win, 109d4bc0535SKrishna Elango pcieb_dma_mctl, 110d4bc0535SKrishna Elango pcieb_ctlops, 111d4bc0535SKrishna Elango ddi_bus_prop_op, 112d4bc0535SKrishna Elango ndi_busop_get_eventcookie, /* (*bus_get_eventcookie)(); */ 113d4bc0535SKrishna Elango ndi_busop_add_eventcall, /* (*bus_add_eventcall)(); */ 114d4bc0535SKrishna Elango ndi_busop_remove_eventcall, /* (*bus_remove_eventcall)(); */ 115d4bc0535SKrishna Elango ndi_post_event, /* (*bus_post_event)(); */ 116d4bc0535SKrishna Elango NULL, /* (*bus_intr_ctl)(); */ 117d4bc0535SKrishna Elango NULL, /* (*bus_config)(); */ 118d4bc0535SKrishna Elango NULL, /* (*bus_unconfig)(); */ 119d4bc0535SKrishna Elango pcieb_fm_init_child, /* (*bus_fm_init)(); */ 120d4bc0535SKrishna Elango NULL, /* (*bus_fm_fini)(); */ 121d4bc0535SKrishna Elango i_ndi_busop_access_enter, /* (*bus_fm_access_enter)(); */ 122d4bc0535SKrishna Elango i_ndi_busop_access_exit, /* (*bus_fm_access_exit)(); */ 123d4bc0535SKrishna Elango pcie_bus_power, /* (*bus_power)(); */ 12426947304SEvan Yan pcieb_intr_ops, /* (*bus_intr_op)(); */ 12526947304SEvan Yan pcie_hp_common_ops /* (*bus_hp_op)(); */ 126d4bc0535SKrishna Elango }; 127d4bc0535SKrishna Elango 128d4bc0535SKrishna Elango static int pcieb_open(dev_t *, int, int, cred_t *); 129d4bc0535SKrishna Elango static int pcieb_close(dev_t, int, int, cred_t *); 130d4bc0535SKrishna Elango static int pcieb_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 131d4bc0535SKrishna Elango static int pcieb_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 132d4bc0535SKrishna Elango static uint_t pcieb_intr_handler(caddr_t arg1, caddr_t arg2); 133d4bc0535SKrishna Elango 134d4bc0535SKrishna Elango /* PM related functions */ 135d4bc0535SKrishna Elango static int pcieb_pwr_setup(dev_info_t *dip); 136d4bc0535SKrishna Elango static int pcieb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p); 137d4bc0535SKrishna Elango static void pcieb_pwr_teardown(dev_info_t *dip); 138d4bc0535SKrishna Elango static int pcieb_pwr_disable(dev_info_t *dip); 139d4bc0535SKrishna Elango 140d4bc0535SKrishna Elango /* Hotplug related functions */ 141d4bc0535SKrishna Elango static void pcieb_id_props(pcieb_devstate_t *pcieb); 142d4bc0535SKrishna Elango 143d4bc0535SKrishna Elango /* 144d4bc0535SKrishna Elango * soft state pointer 145d4bc0535SKrishna Elango */ 146d4bc0535SKrishna Elango void *pcieb_state; 147d4bc0535SKrishna Elango 148d4bc0535SKrishna Elango static struct cb_ops pcieb_cb_ops = { 149d4bc0535SKrishna Elango pcieb_open, /* open */ 150d4bc0535SKrishna Elango pcieb_close, /* close */ 151d4bc0535SKrishna Elango nodev, /* strategy */ 152d4bc0535SKrishna Elango nodev, /* print */ 153d4bc0535SKrishna Elango nodev, /* dump */ 154d4bc0535SKrishna Elango nodev, /* read */ 155d4bc0535SKrishna Elango nodev, /* write */ 156d4bc0535SKrishna Elango pcieb_ioctl, /* ioctl */ 157d4bc0535SKrishna Elango nodev, /* devmap */ 158d4bc0535SKrishna Elango nodev, /* mmap */ 159d4bc0535SKrishna Elango nodev, /* segmap */ 160d4bc0535SKrishna Elango nochpoll, /* poll */ 16126947304SEvan Yan pcie_prop_op, /* cb_prop_op */ 162d4bc0535SKrishna Elango NULL, /* streamtab */ 163d4bc0535SKrishna Elango D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */ 164d4bc0535SKrishna Elango CB_REV, /* rev */ 165d4bc0535SKrishna Elango nodev, /* int (*cb_aread)() */ 166d4bc0535SKrishna Elango nodev /* int (*cb_awrite)() */ 167d4bc0535SKrishna Elango }; 168d4bc0535SKrishna Elango 169d4bc0535SKrishna Elango static int pcieb_probe(dev_info_t *); 170d4bc0535SKrishna Elango static int pcieb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 171d4bc0535SKrishna Elango static int pcieb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 172d4bc0535SKrishna Elango 173d4bc0535SKrishna Elango static struct dev_ops pcieb_ops = { 174d4bc0535SKrishna Elango DEVO_REV, /* devo_rev */ 175d4bc0535SKrishna Elango 0, /* refcnt */ 176d4bc0535SKrishna Elango pcieb_info, /* info */ 177d4bc0535SKrishna Elango nulldev, /* identify */ 178d4bc0535SKrishna Elango pcieb_probe, /* probe */ 179d4bc0535SKrishna Elango pcieb_attach, /* attach */ 180d4bc0535SKrishna Elango pcieb_detach, /* detach */ 181d4bc0535SKrishna Elango nulldev, /* reset */ 182d4bc0535SKrishna Elango &pcieb_cb_ops, /* driver operations */ 183d4bc0535SKrishna Elango &pcieb_bus_ops, /* bus operations */ 184d4bc0535SKrishna Elango pcie_power, /* power */ 185d4bc0535SKrishna Elango ddi_quiesce_not_needed, /* quiesce */ 186d4bc0535SKrishna Elango }; 187d4bc0535SKrishna Elango 188d4bc0535SKrishna Elango /* 189d4bc0535SKrishna Elango * Module linkage information for the kernel. 190d4bc0535SKrishna Elango */ 191d4bc0535SKrishna Elango 192d4bc0535SKrishna Elango static struct modldrv modldrv = { 193d4bc0535SKrishna Elango &mod_driverops, /* Type of module */ 19426947304SEvan Yan "PCIe bridge/switch driver", 195d4bc0535SKrishna Elango &pcieb_ops, /* driver ops */ 196d4bc0535SKrishna Elango }; 197d4bc0535SKrishna Elango 198d4bc0535SKrishna Elango static struct modlinkage modlinkage = { 199d4bc0535SKrishna Elango MODREV_1, 200d4bc0535SKrishna Elango (void *)&modldrv, 201d4bc0535SKrishna Elango NULL 202d4bc0535SKrishna Elango }; 203d4bc0535SKrishna Elango 204d4bc0535SKrishna Elango /* 205d4bc0535SKrishna Elango * forward function declarations: 206d4bc0535SKrishna Elango */ 207d4bc0535SKrishna Elango static void pcieb_uninitchild(dev_info_t *); 208d4bc0535SKrishna Elango static int pcieb_initchild(dev_info_t *child); 209d4bc0535SKrishna Elango static void pcieb_create_ranges_prop(dev_info_t *, ddi_acc_handle_t); 210d4bc0535SKrishna Elango static boolean_t pcieb_is_pcie_device_type(dev_info_t *dip); 211d4bc0535SKrishna Elango 212d4bc0535SKrishna Elango /* interrupt related declarations */ 213d4bc0535SKrishna Elango static int pcieb_msi_supported(dev_info_t *); 214d4bc0535SKrishna Elango static int pcieb_intr_attach(pcieb_devstate_t *pcieb); 215d4bc0535SKrishna Elango static int pcieb_intr_init(pcieb_devstate_t *pcieb_p, int intr_type); 216d4bc0535SKrishna Elango static void pcieb_intr_fini(pcieb_devstate_t *pcieb_p); 217d4bc0535SKrishna Elango 218d4bc0535SKrishna Elango int 219d4bc0535SKrishna Elango _init(void) 220d4bc0535SKrishna Elango { 221d4bc0535SKrishna Elango int e; 222d4bc0535SKrishna Elango 223d4bc0535SKrishna Elango if ((e = ddi_soft_state_init(&pcieb_state, sizeof (pcieb_devstate_t), 224d4bc0535SKrishna Elango 1)) == 0 && (e = mod_install(&modlinkage)) != 0) 225d4bc0535SKrishna Elango ddi_soft_state_fini(&pcieb_state); 226d4bc0535SKrishna Elango return (e); 227d4bc0535SKrishna Elango } 228d4bc0535SKrishna Elango 229d4bc0535SKrishna Elango int 230d4bc0535SKrishna Elango _fini(void) 231d4bc0535SKrishna Elango { 232d4bc0535SKrishna Elango int e; 233d4bc0535SKrishna Elango 234d4bc0535SKrishna Elango if ((e = mod_remove(&modlinkage)) == 0) { 235d4bc0535SKrishna Elango ddi_soft_state_fini(&pcieb_state); 236d4bc0535SKrishna Elango } 237d4bc0535SKrishna Elango return (e); 238d4bc0535SKrishna Elango } 239d4bc0535SKrishna Elango 240d4bc0535SKrishna Elango int 241d4bc0535SKrishna Elango _info(struct modinfo *modinfop) 242d4bc0535SKrishna Elango { 243d4bc0535SKrishna Elango return (mod_info(&modlinkage, modinfop)); 244d4bc0535SKrishna Elango } 245d4bc0535SKrishna Elango 246d4bc0535SKrishna Elango /* ARGSUSED */ 247d4bc0535SKrishna Elango static int 24826947304SEvan Yan pcieb_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 24926947304SEvan Yan { 25026947304SEvan Yan minor_t minor = getminor((dev_t)arg); 25126947304SEvan Yan int instance = PCI_MINOR_NUM_TO_INSTANCE(minor); 25226947304SEvan Yan pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, instance); 25326947304SEvan Yan int ret = DDI_SUCCESS; 25426947304SEvan Yan 25526947304SEvan Yan switch (infocmd) { 25626947304SEvan Yan case DDI_INFO_DEVT2INSTANCE: 25726947304SEvan Yan *result = (void *)(intptr_t)instance; 25826947304SEvan Yan break; 25926947304SEvan Yan case DDI_INFO_DEVT2DEVINFO: 26026947304SEvan Yan if (pcieb == NULL) { 26126947304SEvan Yan ret = DDI_FAILURE; 26226947304SEvan Yan break; 26326947304SEvan Yan } 26426947304SEvan Yan 26526947304SEvan Yan *result = (void *)pcieb->pcieb_dip; 26626947304SEvan Yan break; 26726947304SEvan Yan default: 26826947304SEvan Yan ret = DDI_FAILURE; 26926947304SEvan Yan break; 27026947304SEvan Yan } 27126947304SEvan Yan 27226947304SEvan Yan return (ret); 27326947304SEvan Yan } 27426947304SEvan Yan 27526947304SEvan Yan 27626947304SEvan Yan /*ARGSUSED*/ 27726947304SEvan Yan static int 278d4bc0535SKrishna Elango pcieb_probe(dev_info_t *devi) 279d4bc0535SKrishna Elango { 280d4bc0535SKrishna Elango return (DDI_PROBE_SUCCESS); 281d4bc0535SKrishna Elango } 282d4bc0535SKrishna Elango 28383e6495bSDaniel Ice /* 28483e6495bSDaniel Ice * This is a workaround for an undocumented HW erratum with the 28583e6495bSDaniel Ice * multi-function, F0 and F2, Intel 41210 PCIe-to-PCI bridge. When 28683e6495bSDaniel Ice * Fn (cdip) attaches, this workaround is called to initialize Fn's 28783e6495bSDaniel Ice * sibling (sdip) with MPS/MRRS if it isn't already configured. 28883e6495bSDaniel Ice * Doing so prevents a malformed TLP panic. 28983e6495bSDaniel Ice */ 29083e6495bSDaniel Ice static void 29183e6495bSDaniel Ice pcieb_41210_mps_wkrnd(dev_info_t *cdip) 29283e6495bSDaniel Ice { 29383e6495bSDaniel Ice dev_info_t *sdip; 29483e6495bSDaniel Ice ddi_acc_handle_t cfg_hdl; 29583e6495bSDaniel Ice uint16_t cdip_dev_ctrl, cdip_mrrs_mps; 29683e6495bSDaniel Ice pcie_bus_t *cdip_bus_p = PCIE_DIP2BUS(cdip); 29783e6495bSDaniel Ice 29883e6495bSDaniel Ice /* Get cdip's MPS/MRRS already setup by pcie_initchild_mps() */ 29983e6495bSDaniel Ice ASSERT(cdip_bus_p); 30083e6495bSDaniel Ice cdip_dev_ctrl = PCIE_CAP_GET(16, cdip_bus_p, PCIE_DEVCTL); 30183e6495bSDaniel Ice cdip_mrrs_mps = cdip_dev_ctrl & 30283e6495bSDaniel Ice (PCIE_DEVCTL_MAX_READ_REQ_MASK | PCIE_DEVCTL_MAX_PAYLOAD_MASK); 30383e6495bSDaniel Ice 30483e6495bSDaniel Ice /* Locate sdip and set its MPS/MRRS when applicable */ 30583e6495bSDaniel Ice for (sdip = ddi_get_child(ddi_get_parent(cdip)); sdip; 30683e6495bSDaniel Ice sdip = ddi_get_next_sibling(sdip)) { 30783e6495bSDaniel Ice uint16_t sdip_dev_ctrl, sdip_mrrs_mps, cap_ptr; 30883e6495bSDaniel Ice uint32_t bus_dev_ven_id; 30983e6495bSDaniel Ice 31083e6495bSDaniel Ice if (sdip == cdip || pci_config_setup(sdip, &cfg_hdl) 31183e6495bSDaniel Ice != DDI_SUCCESS) 31283e6495bSDaniel Ice continue; 31383e6495bSDaniel Ice 31483e6495bSDaniel Ice /* must be an Intel 41210 bridge */ 31583e6495bSDaniel Ice bus_dev_ven_id = pci_config_get32(cfg_hdl, PCI_CONF_VENID); 31683e6495bSDaniel Ice if (!PCIEB_IS_41210_BRIDGE(bus_dev_ven_id)) { 31783e6495bSDaniel Ice pci_config_teardown(&cfg_hdl); 31883e6495bSDaniel Ice continue; 31983e6495bSDaniel Ice } 32083e6495bSDaniel Ice 32183e6495bSDaniel Ice if (PCI_CAP_LOCATE(cfg_hdl, PCI_CAP_ID_PCI_E, &cap_ptr) 32283e6495bSDaniel Ice != DDI_SUCCESS) { 32383e6495bSDaniel Ice pci_config_teardown(&cfg_hdl); 32483e6495bSDaniel Ice continue; 32583e6495bSDaniel Ice } 32683e6495bSDaniel Ice 32783e6495bSDaniel Ice /* get sdip's MPS/MRRS to compare to cdip's */ 32883e6495bSDaniel Ice sdip_dev_ctrl = PCI_CAP_GET16(cfg_hdl, NULL, cap_ptr, 32983e6495bSDaniel Ice PCIE_DEVCTL); 33083e6495bSDaniel Ice sdip_mrrs_mps = sdip_dev_ctrl & 33183e6495bSDaniel Ice (PCIE_DEVCTL_MAX_READ_REQ_MASK | 33283e6495bSDaniel Ice PCIE_DEVCTL_MAX_PAYLOAD_MASK); 33383e6495bSDaniel Ice 33483e6495bSDaniel Ice /* if sdip already attached then its MPS/MRRS is configured */ 33583e6495bSDaniel Ice if (i_ddi_devi_attached(sdip)) { 33683e6495bSDaniel Ice ASSERT(sdip_mrrs_mps == cdip_mrrs_mps); 33783e6495bSDaniel Ice pci_config_teardown(&cfg_hdl); 33883e6495bSDaniel Ice continue; 33983e6495bSDaniel Ice } 34083e6495bSDaniel Ice 34183e6495bSDaniel Ice /* otherwise, update sdip's MPS/MRRS if different from cdip's */ 34283e6495bSDaniel Ice if (sdip_mrrs_mps != cdip_mrrs_mps) { 34383e6495bSDaniel Ice sdip_dev_ctrl = (sdip_dev_ctrl & 34483e6495bSDaniel Ice ~(PCIE_DEVCTL_MAX_READ_REQ_MASK | 34583e6495bSDaniel Ice PCIE_DEVCTL_MAX_PAYLOAD_MASK)) | cdip_mrrs_mps; 34683e6495bSDaniel Ice 34783e6495bSDaniel Ice PCI_CAP_PUT16(cfg_hdl, NULL, cap_ptr, PCIE_DEVCTL, 34883e6495bSDaniel Ice sdip_dev_ctrl); 34983e6495bSDaniel Ice } 35083e6495bSDaniel Ice 35183e6495bSDaniel Ice /* 35283e6495bSDaniel Ice * note: sdip's bus_mps will be updated by 35383e6495bSDaniel Ice * pcie_initchild_mps() 35483e6495bSDaniel Ice */ 35583e6495bSDaniel Ice 35683e6495bSDaniel Ice pci_config_teardown(&cfg_hdl); 35783e6495bSDaniel Ice 35883e6495bSDaniel Ice break; 35983e6495bSDaniel Ice } 36083e6495bSDaniel Ice } 36183e6495bSDaniel Ice 362d4bc0535SKrishna Elango static int 363d4bc0535SKrishna Elango pcieb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 364d4bc0535SKrishna Elango { 365d4bc0535SKrishna Elango int instance; 366d4bc0535SKrishna Elango char device_type[8]; 367d4bc0535SKrishna Elango pcieb_devstate_t *pcieb; 368d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2UPBUS(devi); 369d4bc0535SKrishna Elango ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl; 370d4bc0535SKrishna Elango 371d4bc0535SKrishna Elango switch (cmd) { 372d4bc0535SKrishna Elango case DDI_RESUME: 373d4bc0535SKrishna Elango (void) pcie_pwr_resume(devi); 374d4bc0535SKrishna Elango return (DDI_SUCCESS); 375d4bc0535SKrishna Elango 376d4bc0535SKrishna Elango default: 377d4bc0535SKrishna Elango return (DDI_FAILURE); 378d4bc0535SKrishna Elango 379d4bc0535SKrishna Elango case DDI_ATTACH: 380d4bc0535SKrishna Elango break; 381d4bc0535SKrishna Elango } 382d4bc0535SKrishna Elango 383d4bc0535SKrishna Elango if (!(PCIE_IS_BDG(bus_p))) { 384d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, devi, "This is not a switch or" 385d4bc0535SKrishna Elango " bridge\n"); 386d4bc0535SKrishna Elango return (DDI_FAILURE); 387d4bc0535SKrishna Elango } 388d4bc0535SKrishna Elango 389d4bc0535SKrishna Elango /* 390d4bc0535SKrishna Elango * If PCIE_LINKCTL_LINK_DISABLE bit in the PCIe Config 391d4bc0535SKrishna Elango * Space (PCIe Capability Link Control Register) is set, 392d4bc0535SKrishna Elango * then do not bind the driver. 393d4bc0535SKrishna Elango */ 394d4bc0535SKrishna Elango if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) & PCIE_LINKCTL_LINK_DISABLE) 395d4bc0535SKrishna Elango return (DDI_FAILURE); 396d4bc0535SKrishna Elango 397d4bc0535SKrishna Elango /* 398d4bc0535SKrishna Elango * Allocate and get soft state structure. 399d4bc0535SKrishna Elango */ 400d4bc0535SKrishna Elango instance = ddi_get_instance(devi); 401d4bc0535SKrishna Elango if (ddi_soft_state_zalloc(pcieb_state, instance) != DDI_SUCCESS) 402d4bc0535SKrishna Elango return (DDI_FAILURE); 403d4bc0535SKrishna Elango pcieb = ddi_get_soft_state(pcieb_state, instance); 404d4bc0535SKrishna Elango pcieb->pcieb_dip = devi; 405d4bc0535SKrishna Elango 406d4bc0535SKrishna Elango if ((pcieb_fm_init(pcieb)) != DDI_SUCCESS) { 407d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, devi, "Failed in pcieb_fm_init\n"); 408d4bc0535SKrishna Elango goto fail; 409d4bc0535SKrishna Elango } 410d4bc0535SKrishna Elango pcieb->pcieb_init_flags |= PCIEB_INIT_FM; 411d4bc0535SKrishna Elango 412d4bc0535SKrishna Elango mutex_init(&pcieb->pcieb_mutex, NULL, MUTEX_DRIVER, NULL); 413d4bc0535SKrishna Elango mutex_init(&pcieb->pcieb_err_mutex, NULL, MUTEX_DRIVER, 414d4bc0535SKrishna Elango (void *)pcieb->pcieb_fm_ibc); 415d4bc0535SKrishna Elango mutex_init(&pcieb->pcieb_peek_poke_mutex, NULL, MUTEX_DRIVER, 416d4bc0535SKrishna Elango (void *)pcieb->pcieb_fm_ibc); 417d4bc0535SKrishna Elango 418d4bc0535SKrishna Elango /* create special properties for device identification */ 419d4bc0535SKrishna Elango pcieb_id_props(pcieb); 420d4bc0535SKrishna Elango 421d4bc0535SKrishna Elango /* 422d4bc0535SKrishna Elango * Power management setup. This also makes sure that switch/bridge 423d4bc0535SKrishna Elango * is at D0 during attach. 424d4bc0535SKrishna Elango */ 425d4bc0535SKrishna Elango if (pwr_common_setup(devi) != DDI_SUCCESS) { 426d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, devi, "pwr_common_setup failed\n"); 427d4bc0535SKrishna Elango goto fail; 428d4bc0535SKrishna Elango } 429d4bc0535SKrishna Elango 430d4bc0535SKrishna Elango if (pcieb_pwr_setup(devi) != DDI_SUCCESS) { 431d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, devi, "pxb_pwr_setup failed \n"); 432d4bc0535SKrishna Elango goto fail; 433d4bc0535SKrishna Elango } 434d4bc0535SKrishna Elango 435d4bc0535SKrishna Elango /* 436d4bc0535SKrishna Elango * Make sure the "device_type" property exists. 437d4bc0535SKrishna Elango */ 438d4bc0535SKrishna Elango if (pcieb_is_pcie_device_type(devi)) 439d4bc0535SKrishna Elango (void) strcpy(device_type, "pciex"); 440d4bc0535SKrishna Elango else 441d4bc0535SKrishna Elango (void) strcpy(device_type, "pci"); 442d4bc0535SKrishna Elango 443d4bc0535SKrishna Elango (void) ddi_prop_update_string(DDI_DEV_T_NONE, devi, 444d4bc0535SKrishna Elango "device_type", device_type); 445d4bc0535SKrishna Elango 446d4bc0535SKrishna Elango /* 447d4bc0535SKrishna Elango * Check whether the "ranges" property is present. 448d4bc0535SKrishna Elango * Otherwise create the ranges property by reading 449d4bc0535SKrishna Elango * the configuration registers 450d4bc0535SKrishna Elango */ 451d4bc0535SKrishna Elango if (ddi_prop_exists(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 452d4bc0535SKrishna Elango "ranges") == 0) { 453d4bc0535SKrishna Elango pcieb_create_ranges_prop(devi, config_handle); 454d4bc0535SKrishna Elango } 455d4bc0535SKrishna Elango 456d4bc0535SKrishna Elango if (PCIE_IS_PCI_BDG(bus_p)) 457d4bc0535SKrishna Elango pcieb_set_pci_perf_parameters(devi, config_handle); 458d4bc0535SKrishna Elango 459d4bc0535SKrishna Elango #ifdef PX_PLX 460d4bc0535SKrishna Elango pcieb_attach_plx_workarounds(pcieb); 461d4bc0535SKrishna Elango #endif /* PX_PLX */ 462d4bc0535SKrishna Elango 46326947304SEvan Yan if (pcie_init(devi, NULL) != DDI_SUCCESS) 46426947304SEvan Yan goto fail; 465d4bc0535SKrishna Elango 46683e6495bSDaniel Ice /* Intel PCIe-to-PCI 41210 bridge workaround -- if applicable */ 46783e6495bSDaniel Ice if (pcieb_disable_41210_wkarnd == 0 && 46883e6495bSDaniel Ice PCIEB_IS_41210_BRIDGE(bus_p->bus_dev_ven_id)) 46983e6495bSDaniel Ice pcieb_41210_mps_wkrnd(devi); 47083e6495bSDaniel Ice 471d4bc0535SKrishna Elango /* 472d4bc0535SKrishna Elango * Initialize interrupt handlers. Ignore return value. 473d4bc0535SKrishna Elango */ 474d4bc0535SKrishna Elango (void) pcieb_intr_attach(pcieb); 475d4bc0535SKrishna Elango 47670f83219SEvan Yan (void) pcie_hpintr_enable(devi); 47770f83219SEvan Yan 478d4bc0535SKrishna Elango /* Do any platform specific workarounds needed at this time */ 479d4bc0535SKrishna Elango pcieb_plat_attach_workaround(devi); 480d4bc0535SKrishna Elango 481d4bc0535SKrishna Elango /* 482d4bc0535SKrishna Elango * If this is a root port, determine and set the max payload size. 483d4bc0535SKrishna Elango * Since this will involve scanning the fabric, all error enabling 484d4bc0535SKrishna Elango * and sw workarounds should be in place before doing this. 485d4bc0535SKrishna Elango */ 486d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p)) 487d4bc0535SKrishna Elango pcie_init_root_port_mps(devi); 488d4bc0535SKrishna Elango 489d4bc0535SKrishna Elango ddi_report_dev(devi); 490d4bc0535SKrishna Elango return (DDI_SUCCESS); 491d4bc0535SKrishna Elango 492d4bc0535SKrishna Elango fail: 493d4bc0535SKrishna Elango (void) pcieb_detach(devi, DDI_DETACH); 494d4bc0535SKrishna Elango return (DDI_FAILURE); 495d4bc0535SKrishna Elango } 496d4bc0535SKrishna Elango 497d4bc0535SKrishna Elango static int 498d4bc0535SKrishna Elango pcieb_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 499d4bc0535SKrishna Elango { 500d4bc0535SKrishna Elango pcieb_devstate_t *pcieb; 501d4bc0535SKrishna Elango int error = DDI_SUCCESS; 502d4bc0535SKrishna Elango 503d4bc0535SKrishna Elango switch (cmd) { 504d4bc0535SKrishna Elango case DDI_SUSPEND: 505d4bc0535SKrishna Elango error = pcie_pwr_suspend(devi); 506d4bc0535SKrishna Elango return (error); 507d4bc0535SKrishna Elango 508d4bc0535SKrishna Elango case DDI_DETACH: 509d4bc0535SKrishna Elango break; 510d4bc0535SKrishna Elango 511d4bc0535SKrishna Elango default: 512d4bc0535SKrishna Elango return (DDI_FAILURE); 513d4bc0535SKrishna Elango } 514d4bc0535SKrishna Elango 515d4bc0535SKrishna Elango pcieb = ddi_get_soft_state(pcieb_state, ddi_get_instance(devi)); 516d4bc0535SKrishna Elango 51770f83219SEvan Yan /* disable hotplug interrupt */ 51870f83219SEvan Yan (void) pcie_hpintr_disable(devi); 51970f83219SEvan Yan 520d4bc0535SKrishna Elango /* remove interrupt handlers */ 521d4bc0535SKrishna Elango pcieb_intr_fini(pcieb); 522d4bc0535SKrishna Elango 52326947304SEvan Yan /* uninitialize inband PCI-E HPC if present */ 52426947304SEvan Yan (void) pcie_uninit(devi); 525d4bc0535SKrishna Elango 526d4bc0535SKrishna Elango (void) ddi_prop_remove(DDI_DEV_T_NONE, devi, "device_type"); 527d4bc0535SKrishna Elango 528d4bc0535SKrishna Elango (void) ndi_prop_remove(DDI_DEV_T_NONE, pcieb->pcieb_dip, 529d4bc0535SKrishna Elango "pcie_ce_mask"); 530d4bc0535SKrishna Elango 531d4bc0535SKrishna Elango if (pcieb->pcieb_init_flags & PCIEB_INIT_FM) 532d4bc0535SKrishna Elango pcieb_fm_fini(pcieb); 533d4bc0535SKrishna Elango 534d4bc0535SKrishna Elango pcieb_pwr_teardown(devi); 535d4bc0535SKrishna Elango pwr_common_teardown(devi); 536d4bc0535SKrishna Elango 537d4bc0535SKrishna Elango mutex_destroy(&pcieb->pcieb_peek_poke_mutex); 538d4bc0535SKrishna Elango mutex_destroy(&pcieb->pcieb_err_mutex); 539d4bc0535SKrishna Elango mutex_destroy(&pcieb->pcieb_mutex); 540d4bc0535SKrishna Elango 541d4bc0535SKrishna Elango /* 542d4bc0535SKrishna Elango * And finally free the per-pci soft state. 543d4bc0535SKrishna Elango */ 544d4bc0535SKrishna Elango ddi_soft_state_free(pcieb_state, ddi_get_instance(devi)); 545d4bc0535SKrishna Elango 546d4bc0535SKrishna Elango return (DDI_SUCCESS); 547d4bc0535SKrishna Elango } 548d4bc0535SKrishna Elango 549d4bc0535SKrishna Elango static int 550d4bc0535SKrishna Elango pcieb_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 551d4bc0535SKrishna Elango off_t offset, off_t len, caddr_t *vaddrp) 552d4bc0535SKrishna Elango { 553d4bc0535SKrishna Elango dev_info_t *pdip; 554d4bc0535SKrishna Elango 5559757e35cSStephen Hanson if (PCIE_IS_RP(PCIE_DIP2BUS(dip)) && mp->map_handlep != NULL) { 556837c1ac4SStephen Hanson ddi_acc_impl_t *hdlp = 557837c1ac4SStephen Hanson (ddi_acc_impl_t *)(mp->map_handlep)->ah_platform_private; 558837c1ac4SStephen Hanson 559837c1ac4SStephen Hanson pcieb_set_prot_scan(dip, hdlp); 560837c1ac4SStephen Hanson } 561d4bc0535SKrishna Elango pdip = (dev_info_t *)DEVI(dip)->devi_parent; 562d4bc0535SKrishna Elango return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip, rdip, mp, 563d4bc0535SKrishna Elango offset, len, vaddrp)); 564d4bc0535SKrishna Elango } 565d4bc0535SKrishna Elango 566d4bc0535SKrishna Elango static int 567d4bc0535SKrishna Elango pcieb_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 568d4bc0535SKrishna Elango void *arg, void *result) 569d4bc0535SKrishna Elango { 570d4bc0535SKrishna Elango pci_regspec_t *drv_regp; 571d4bc0535SKrishna Elango int reglen; 572d4bc0535SKrishna Elango int rn; 573d4bc0535SKrishna Elango int totreg; 574d4bc0535SKrishna Elango pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, 575d4bc0535SKrishna Elango ddi_get_instance(dip)); 576d4bc0535SKrishna Elango struct detachspec *ds; 577d4bc0535SKrishna Elango struct attachspec *as; 578d4bc0535SKrishna Elango 579d4bc0535SKrishna Elango switch (ctlop) { 580d4bc0535SKrishna Elango case DDI_CTLOPS_REPORTDEV: 581d4bc0535SKrishna Elango if (rdip == (dev_info_t *)0) 582d4bc0535SKrishna Elango return (DDI_FAILURE); 583fc256490SJason Beloro 584fc256490SJason Beloro if (ddi_get_parent(rdip) == dip) { 585d4bc0535SKrishna Elango cmn_err(CE_CONT, "?PCIE-device: %s@%s, %s%d\n", 586d4bc0535SKrishna Elango ddi_node_name(rdip), ddi_get_name_addr(rdip), 587fc256490SJason Beloro ddi_driver_name(rdip), ddi_get_instance(rdip)); 588fc256490SJason Beloro } 589fc256490SJason Beloro 590fc256490SJason Beloro /* Pass it up for fabric sync */ 591fc256490SJason Beloro (void) ddi_ctlops(dip, rdip, ctlop, arg, result); 592d4bc0535SKrishna Elango return (DDI_SUCCESS); 593d4bc0535SKrishna Elango 594d4bc0535SKrishna Elango case DDI_CTLOPS_INITCHILD: 595d4bc0535SKrishna Elango return (pcieb_initchild((dev_info_t *)arg)); 596d4bc0535SKrishna Elango 597d4bc0535SKrishna Elango case DDI_CTLOPS_UNINITCHILD: 598d4bc0535SKrishna Elango pcieb_uninitchild((dev_info_t *)arg); 599d4bc0535SKrishna Elango return (DDI_SUCCESS); 600d4bc0535SKrishna Elango 601d4bc0535SKrishna Elango case DDI_CTLOPS_SIDDEV: 602d4bc0535SKrishna Elango return (DDI_SUCCESS); 603d4bc0535SKrishna Elango 604d4bc0535SKrishna Elango case DDI_CTLOPS_REGSIZE: 605d4bc0535SKrishna Elango case DDI_CTLOPS_NREGS: 606d4bc0535SKrishna Elango if (rdip == (dev_info_t *)0) 607d4bc0535SKrishna Elango return (DDI_FAILURE); 608d4bc0535SKrishna Elango break; 609d4bc0535SKrishna Elango 610d4bc0535SKrishna Elango case DDI_CTLOPS_PEEK: 611d4bc0535SKrishna Elango case DDI_CTLOPS_POKE: 612d4bc0535SKrishna Elango return (pcieb_plat_peekpoke(dip, rdip, ctlop, arg, result)); 613d4bc0535SKrishna Elango case DDI_CTLOPS_ATTACH: 614d4bc0535SKrishna Elango if (!pcie_is_child(dip, rdip)) 615d4bc0535SKrishna Elango return (DDI_SUCCESS); 616d4bc0535SKrishna Elango 617d4bc0535SKrishna Elango as = (struct attachspec *)arg; 618d4bc0535SKrishna Elango switch (as->when) { 619d4bc0535SKrishna Elango case DDI_PRE: 620d4bc0535SKrishna Elango if (as->cmd == DDI_RESUME) { 621d4bc0535SKrishna Elango pcie_clear_errors(rdip); 622d4bc0535SKrishna Elango if (pcieb_plat_ctlops(rdip, ctlop, arg) != 623d4bc0535SKrishna Elango DDI_SUCCESS) 624d4bc0535SKrishna Elango return (DDI_FAILURE); 625d4bc0535SKrishna Elango } 626d4bc0535SKrishna Elango 627d4bc0535SKrishna Elango if (as->cmd == DDI_ATTACH) 628d4bc0535SKrishna Elango return (pcie_pm_hold(dip)); 629d4bc0535SKrishna Elango 630d4bc0535SKrishna Elango return (DDI_SUCCESS); 631d4bc0535SKrishna Elango 632d4bc0535SKrishna Elango case DDI_POST: 633c2cc6e07SRamesh Chitrothu if (as->cmd == DDI_ATTACH && 634c2cc6e07SRamesh Chitrothu as->result != DDI_SUCCESS) { 635c2cc6e07SRamesh Chitrothu /* 636c2cc6e07SRamesh Chitrothu * Attach failed for the child device. The child 637c2cc6e07SRamesh Chitrothu * driver may have made PM calls before the 638c2cc6e07SRamesh Chitrothu * attach failed. pcie_pm_remove_child() should 639c2cc6e07SRamesh Chitrothu * cleanup PM state and holds (if any) 640c2cc6e07SRamesh Chitrothu * associated with the child device. 641c2cc6e07SRamesh Chitrothu */ 642c2cc6e07SRamesh Chitrothu return (pcie_pm_remove_child(dip, rdip)); 643c2cc6e07SRamesh Chitrothu } 644d4bc0535SKrishna Elango 645d4bc0535SKrishna Elango if (as->result == DDI_SUCCESS) { 646d4bc0535SKrishna Elango pf_init(rdip, (void *)pcieb->pcieb_fm_ibc, 647d4bc0535SKrishna Elango as->cmd); 648d4bc0535SKrishna Elango 649d4bc0535SKrishna Elango (void) pcieb_plat_ctlops(rdip, ctlop, arg); 650d4bc0535SKrishna Elango } 651d4bc0535SKrishna Elango 652d4bc0535SKrishna Elango /* 653d4bc0535SKrishna Elango * For empty hotplug-capable slots, we should explicitly 654d4bc0535SKrishna Elango * disable the errors, so that we won't panic upon 655d4bc0535SKrishna Elango * unsupported hotplug messages. 656d4bc0535SKrishna Elango */ 657d4bc0535SKrishna Elango if ((!ddi_prop_exists(DDI_DEV_T_ANY, rdip, 658d4bc0535SKrishna Elango DDI_PROP_DONTPASS, "hotplug-capable")) || 659d4bc0535SKrishna Elango ddi_get_child(rdip)) { 660d4bc0535SKrishna Elango (void) pcie_postattach_child(rdip); 661d4bc0535SKrishna Elango return (DDI_SUCCESS); 662d4bc0535SKrishna Elango } 663d4bc0535SKrishna Elango 664d4bc0535SKrishna Elango pcie_disable_errors(rdip); 665d4bc0535SKrishna Elango 666d4bc0535SKrishna Elango return (DDI_SUCCESS); 667d4bc0535SKrishna Elango default: 668d4bc0535SKrishna Elango break; 669d4bc0535SKrishna Elango } 670d4bc0535SKrishna Elango return (DDI_SUCCESS); 671d4bc0535SKrishna Elango 672d4bc0535SKrishna Elango case DDI_CTLOPS_DETACH: 673d4bc0535SKrishna Elango if (!pcie_is_child(dip, rdip)) 674d4bc0535SKrishna Elango return (DDI_SUCCESS); 675d4bc0535SKrishna Elango 676d4bc0535SKrishna Elango ds = (struct detachspec *)arg; 677d4bc0535SKrishna Elango switch (ds->when) { 678d4bc0535SKrishna Elango case DDI_PRE: 679d4bc0535SKrishna Elango pf_fini(rdip, ds->cmd); 680d4bc0535SKrishna Elango return (DDI_SUCCESS); 681d4bc0535SKrishna Elango 682d4bc0535SKrishna Elango case DDI_POST: 683d4bc0535SKrishna Elango if (pcieb_plat_ctlops(rdip, ctlop, arg) != DDI_SUCCESS) 684d4bc0535SKrishna Elango return (DDI_FAILURE); 685d4bc0535SKrishna Elango if (ds->cmd == DDI_DETACH && 686d4bc0535SKrishna Elango ds->result == DDI_SUCCESS) { 687d4bc0535SKrishna Elango return (pcie_pm_remove_child(dip, rdip)); 688d4bc0535SKrishna Elango } 689d4bc0535SKrishna Elango return (DDI_SUCCESS); 690d4bc0535SKrishna Elango default: 691d4bc0535SKrishna Elango break; 692d4bc0535SKrishna Elango } 693d4bc0535SKrishna Elango return (DDI_SUCCESS); 694d4bc0535SKrishna Elango default: 695d4bc0535SKrishna Elango return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 696d4bc0535SKrishna Elango } 697d4bc0535SKrishna Elango 698d4bc0535SKrishna Elango *(int *)result = 0; 699d4bc0535SKrishna Elango if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, 700d4bc0535SKrishna Elango DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", (caddr_t)&drv_regp, 701d4bc0535SKrishna Elango ®len) != DDI_SUCCESS) 702d4bc0535SKrishna Elango return (DDI_FAILURE); 703d4bc0535SKrishna Elango 704d4bc0535SKrishna Elango totreg = reglen / sizeof (pci_regspec_t); 705d4bc0535SKrishna Elango if (ctlop == DDI_CTLOPS_NREGS) 706d4bc0535SKrishna Elango *(int *)result = totreg; 707d4bc0535SKrishna Elango else if (ctlop == DDI_CTLOPS_REGSIZE) { 708d4bc0535SKrishna Elango rn = *(int *)arg; 709d4bc0535SKrishna Elango if (rn >= totreg) { 710d4bc0535SKrishna Elango kmem_free(drv_regp, reglen); 711d4bc0535SKrishna Elango return (DDI_FAILURE); 712d4bc0535SKrishna Elango } 713d4bc0535SKrishna Elango 714d4bc0535SKrishna Elango *(off_t *)result = drv_regp[rn].pci_size_low | 715d4bc0535SKrishna Elango ((uint64_t)drv_regp[rn].pci_size_hi << 32); 716d4bc0535SKrishna Elango } 717d4bc0535SKrishna Elango 718d4bc0535SKrishna Elango kmem_free(drv_regp, reglen); 719d4bc0535SKrishna Elango return (DDI_SUCCESS); 720d4bc0535SKrishna Elango } 721d4bc0535SKrishna Elango 722d4bc0535SKrishna Elango /* 723d4bc0535SKrishna Elango * name_child 724d4bc0535SKrishna Elango * 725d4bc0535SKrishna Elango * This function is called from init_child to name a node. It is 726d4bc0535SKrishna Elango * also passed as a callback for node merging functions. 727d4bc0535SKrishna Elango * 728d4bc0535SKrishna Elango * return value: DDI_SUCCESS, DDI_FAILURE 729d4bc0535SKrishna Elango */ 730d4bc0535SKrishna Elango static int 731d4bc0535SKrishna Elango pcieb_name_child(dev_info_t *child, char *name, int namelen) 732d4bc0535SKrishna Elango { 733d4bc0535SKrishna Elango pci_regspec_t *pci_rp; 73426947304SEvan Yan uint_t device, func; 735d4bc0535SKrishna Elango char **unit_addr; 736d4bc0535SKrishna Elango uint_t n; 737d4bc0535SKrishna Elango 738d4bc0535SKrishna Elango /* 739d4bc0535SKrishna Elango * For .conf nodes, use unit-address property as name 740d4bc0535SKrishna Elango */ 741d4bc0535SKrishna Elango if (ndi_dev_is_persistent_node(child) == 0) { 742d4bc0535SKrishna Elango if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, 743d4bc0535SKrishna Elango DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != 744d4bc0535SKrishna Elango DDI_PROP_SUCCESS) { 745d4bc0535SKrishna Elango cmn_err(CE_WARN, 746d4bc0535SKrishna Elango "cannot find unit-address in %s.conf", 747d4bc0535SKrishna Elango ddi_driver_name(child)); 748d4bc0535SKrishna Elango return (DDI_FAILURE); 749d4bc0535SKrishna Elango } 750d4bc0535SKrishna Elango if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { 751d4bc0535SKrishna Elango cmn_err(CE_WARN, "unit-address property in %s.conf" 752d4bc0535SKrishna Elango " not well-formed", ddi_driver_name(child)); 753d4bc0535SKrishna Elango ddi_prop_free(unit_addr); 754d4bc0535SKrishna Elango return (DDI_FAILURE); 755d4bc0535SKrishna Elango } 756d4bc0535SKrishna Elango (void) snprintf(name, namelen, "%s", *unit_addr); 757d4bc0535SKrishna Elango ddi_prop_free(unit_addr); 758d4bc0535SKrishna Elango return (DDI_SUCCESS); 759d4bc0535SKrishna Elango } 760d4bc0535SKrishna Elango 761d4bc0535SKrishna Elango /* 762d4bc0535SKrishna Elango * Get the address portion of the node name based on 763d4bc0535SKrishna Elango * the function and device number. 764d4bc0535SKrishna Elango */ 765d4bc0535SKrishna Elango if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 766d4bc0535SKrishna Elango DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) { 767d4bc0535SKrishna Elango return (DDI_FAILURE); 768d4bc0535SKrishna Elango } 769d4bc0535SKrishna Elango 770d4bc0535SKrishna Elango /* copy the device identifications */ 77126947304SEvan Yan device = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi); 772d4bc0535SKrishna Elango func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi); 773d4bc0535SKrishna Elango 77426947304SEvan Yan if (pcie_ari_is_enabled(ddi_get_parent(child)) 77526947304SEvan Yan == PCIE_ARI_FORW_ENABLED) { 77626947304SEvan Yan func = (device << 3) | func; 77726947304SEvan Yan device = 0; 77826947304SEvan Yan } 77926947304SEvan Yan 780d4bc0535SKrishna Elango if (func != 0) 78126947304SEvan Yan (void) snprintf(name, namelen, "%x,%x", device, func); 782d4bc0535SKrishna Elango else 78326947304SEvan Yan (void) snprintf(name, namelen, "%x", device); 784d4bc0535SKrishna Elango 785d4bc0535SKrishna Elango ddi_prop_free(pci_rp); 786d4bc0535SKrishna Elango return (DDI_SUCCESS); 787d4bc0535SKrishna Elango } 788d4bc0535SKrishna Elango 789d4bc0535SKrishna Elango static int 790d4bc0535SKrishna Elango pcieb_initchild(dev_info_t *child) 791d4bc0535SKrishna Elango { 792d4bc0535SKrishna Elango char name[MAXNAMELEN]; 793d4bc0535SKrishna Elango int result = DDI_FAILURE; 794d4bc0535SKrishna Elango pcieb_devstate_t *pcieb = 795d4bc0535SKrishna Elango (pcieb_devstate_t *)ddi_get_soft_state(pcieb_state, 796d4bc0535SKrishna Elango ddi_get_instance(ddi_get_parent(child))); 797d4bc0535SKrishna Elango 798d4bc0535SKrishna Elango /* 799d4bc0535SKrishna Elango * Name the child 800d4bc0535SKrishna Elango */ 801d4bc0535SKrishna Elango if (pcieb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS) { 802d4bc0535SKrishna Elango result = DDI_FAILURE; 803d4bc0535SKrishna Elango goto done; 804d4bc0535SKrishna Elango } 805d4bc0535SKrishna Elango ddi_set_name_addr(child, name); 806d4bc0535SKrishna Elango 807d4bc0535SKrishna Elango /* 808d4bc0535SKrishna Elango * Pseudo nodes indicate a prototype node with per-instance 809d4bc0535SKrishna Elango * properties to be merged into the real h/w device node. 810d4bc0535SKrishna Elango * The interpretation of the unit-address is DD[,F] 811d4bc0535SKrishna Elango * where DD is the device id and F is the function. 812d4bc0535SKrishna Elango */ 813d4bc0535SKrishna Elango if (ndi_dev_is_persistent_node(child) == 0) { 814d4bc0535SKrishna Elango extern int pci_allow_pseudo_children; 815d4bc0535SKrishna Elango 816d4bc0535SKrishna Elango /* 817d4bc0535SKrishna Elango * Try to merge the properties from this prototype 818d4bc0535SKrishna Elango * node into real h/w nodes. 819d4bc0535SKrishna Elango */ 8202e98bdabSvitezslav batrla - Sun Microsystems - Prague Czech Republic if (ndi_merge_node(child, pcieb_name_child) == DDI_SUCCESS) { 821d4bc0535SKrishna Elango /* 822d4bc0535SKrishna Elango * Merged ok - return failure to remove the node. 823d4bc0535SKrishna Elango */ 824d4bc0535SKrishna Elango ddi_set_name_addr(child, NULL); 825d4bc0535SKrishna Elango result = DDI_FAILURE; 826d4bc0535SKrishna Elango goto done; 827d4bc0535SKrishna Elango } 828d4bc0535SKrishna Elango 829d4bc0535SKrishna Elango /* workaround for ddivs to run under PCI-E */ 830d4bc0535SKrishna Elango if (pci_allow_pseudo_children) { 831d4bc0535SKrishna Elango result = DDI_SUCCESS; 832d4bc0535SKrishna Elango goto done; 833d4bc0535SKrishna Elango } 834d4bc0535SKrishna Elango 835d4bc0535SKrishna Elango /* 836d4bc0535SKrishna Elango * The child was not merged into a h/w node, 837d4bc0535SKrishna Elango * but there's not much we can do with it other 838d4bc0535SKrishna Elango * than return failure to cause the node to be removed. 839d4bc0535SKrishna Elango */ 840d4bc0535SKrishna Elango cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged", 841d4bc0535SKrishna Elango ddi_driver_name(child), ddi_get_name_addr(child), 842d4bc0535SKrishna Elango ddi_driver_name(child)); 843d4bc0535SKrishna Elango ddi_set_name_addr(child, NULL); 844d4bc0535SKrishna Elango result = DDI_NOT_WELL_FORMED; 845d4bc0535SKrishna Elango goto done; 846d4bc0535SKrishna Elango } 847d4bc0535SKrishna Elango 848d4bc0535SKrishna Elango /* platform specific initchild */ 849d4bc0535SKrishna Elango pcieb_plat_initchild(child); 850d4bc0535SKrishna Elango 851d4bc0535SKrishna Elango if (pcie_pm_hold(pcieb->pcieb_dip) != DDI_SUCCESS) { 852d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, pcieb->pcieb_dip, 853d4bc0535SKrishna Elango "INITCHILD: px_pm_hold failed\n"); 854d4bc0535SKrishna Elango result = DDI_FAILURE; 855d4bc0535SKrishna Elango goto done; 856d4bc0535SKrishna Elango } 857d4bc0535SKrishna Elango /* Any return from here must call pcie_pm_release */ 858d4bc0535SKrishna Elango 859d4bc0535SKrishna Elango /* 860d4bc0535SKrishna Elango * If configuration registers were previously saved by 861d4bc0535SKrishna Elango * child (before it entered D3), then let the child do the 862d4bc0535SKrishna Elango * restore to set up the config regs as it'll first need to 863d4bc0535SKrishna Elango * power the device out of D3. 864d4bc0535SKrishna Elango */ 865d4bc0535SKrishna Elango if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 866d4bc0535SKrishna Elango "config-regs-saved-by-child") == 1) { 867d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, ddi_get_parent(child), 868d4bc0535SKrishna Elango "INITCHILD: config regs to be restored by child" 869d4bc0535SKrishna Elango " for %s@%s\n", ddi_node_name(child), 870d4bc0535SKrishna Elango ddi_get_name_addr(child)); 871d4bc0535SKrishna Elango 872d4bc0535SKrishna Elango result = DDI_SUCCESS; 873d4bc0535SKrishna Elango goto cleanup; 874d4bc0535SKrishna Elango } 875d4bc0535SKrishna Elango 876d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, ddi_get_parent(child), 877d4bc0535SKrishna Elango "INITCHILD: config regs setup for %s@%s\n", 878d4bc0535SKrishna Elango ddi_node_name(child), ddi_get_name_addr(child)); 879d4bc0535SKrishna Elango 880fc256490SJason Beloro pcie_init_dom(child); 881fc256490SJason Beloro 882c0da6274SZhi-Jun Robin Fu if (pcie_initchild(child) != DDI_SUCCESS) { 883d4bc0535SKrishna Elango result = DDI_FAILURE; 884fc256490SJason Beloro pcie_fini_dom(child); 885d4bc0535SKrishna Elango goto cleanup; 886d4bc0535SKrishna Elango } 887d4bc0535SKrishna Elango 888d4bc0535SKrishna Elango #ifdef PX_PLX 889d4bc0535SKrishna Elango if (pcieb_init_plx_workarounds(pcieb, child) == DDI_FAILURE) { 890d4bc0535SKrishna Elango result = DDI_FAILURE; 891fc256490SJason Beloro pcie_fini_dom(child); 892d4bc0535SKrishna Elango goto cleanup; 893d4bc0535SKrishna Elango } 894d4bc0535SKrishna Elango #endif /* PX_PLX */ 895d4bc0535SKrishna Elango 896d4bc0535SKrishna Elango result = DDI_SUCCESS; 897d4bc0535SKrishna Elango cleanup: 898d4bc0535SKrishna Elango pcie_pm_release(pcieb->pcieb_dip); 899d4bc0535SKrishna Elango done: 900d4bc0535SKrishna Elango return (result); 901d4bc0535SKrishna Elango } 902d4bc0535SKrishna Elango 903d4bc0535SKrishna Elango static void 904d4bc0535SKrishna Elango pcieb_uninitchild(dev_info_t *dip) 905d4bc0535SKrishna Elango { 906d4bc0535SKrishna Elango 907d4bc0535SKrishna Elango pcie_uninitchild(dip); 908d4bc0535SKrishna Elango 909d4bc0535SKrishna Elango pcieb_plat_uninitchild(dip); 910d4bc0535SKrishna Elango 911d4bc0535SKrishna Elango ddi_set_name_addr(dip, NULL); 912d4bc0535SKrishna Elango 913d4bc0535SKrishna Elango /* 914d4bc0535SKrishna Elango * Strip the node to properly convert it back to prototype form 915d4bc0535SKrishna Elango */ 916d4bc0535SKrishna Elango ddi_remove_minor_node(dip, NULL); 917d4bc0535SKrishna Elango 918d4bc0535SKrishna Elango ddi_prop_remove_all(dip); 919d4bc0535SKrishna Elango } 920d4bc0535SKrishna Elango 921d4bc0535SKrishna Elango static boolean_t 922d4bc0535SKrishna Elango pcieb_is_pcie_device_type(dev_info_t *dip) 923d4bc0535SKrishna Elango { 924d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(dip); 925d4bc0535SKrishna Elango 926d4bc0535SKrishna Elango if (PCIE_IS_SW(bus_p) || PCIE_IS_RP(bus_p) || PCIE_IS_PCI2PCIE(bus_p)) 927d4bc0535SKrishna Elango return (B_TRUE); 928d4bc0535SKrishna Elango 929d4bc0535SKrishna Elango return (B_FALSE); 930d4bc0535SKrishna Elango } 931d4bc0535SKrishna Elango 932d4bc0535SKrishna Elango static int 933d4bc0535SKrishna Elango pcieb_intr_attach(pcieb_devstate_t *pcieb) 934d4bc0535SKrishna Elango { 935d4bc0535SKrishna Elango int intr_types; 936d4bc0535SKrishna Elango dev_info_t *dip = pcieb->pcieb_dip; 937d4bc0535SKrishna Elango 938d4bc0535SKrishna Elango /* Allow platform specific code to do any initialization first */ 939d4bc0535SKrishna Elango pcieb_plat_intr_attach(pcieb); 940d4bc0535SKrishna Elango 941d4bc0535SKrishna Elango /* 942d4bc0535SKrishna Elango * Initialize interrupt handlers. 943d4bc0535SKrishna Elango * If both MSI and FIXED are supported, try to attach MSI first. 944d4bc0535SKrishna Elango * If MSI fails for any reason, then try FIXED, but only allow one 945d4bc0535SKrishna Elango * type to be attached. 946d4bc0535SKrishna Elango */ 947d4bc0535SKrishna Elango if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) { 948d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_supported_types" 949d4bc0535SKrishna Elango " failed\n"); 950d4bc0535SKrishna Elango goto FAIL; 951d4bc0535SKrishna Elango } 952d4bc0535SKrishna Elango 953d4bc0535SKrishna Elango if ((intr_types & DDI_INTR_TYPE_MSI) && 954d4bc0535SKrishna Elango (pcieb_msi_supported(dip) == DDI_SUCCESS)) { 955d4bc0535SKrishna Elango if (pcieb_intr_init(pcieb, DDI_INTR_TYPE_MSI) == DDI_SUCCESS) 956d4bc0535SKrishna Elango intr_types = DDI_INTR_TYPE_MSI; 957d4bc0535SKrishna Elango else { 958d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "Unable to attach MSI" 959d4bc0535SKrishna Elango " handler\n"); 960d4bc0535SKrishna Elango } 961d4bc0535SKrishna Elango } 962d4bc0535SKrishna Elango 963d4bc0535SKrishna Elango if (intr_types != DDI_INTR_TYPE_MSI) { 964d4bc0535SKrishna Elango /* 965d4bc0535SKrishna Elango * MSIs are not supported or MSI initialization failed. For Root 966d4bc0535SKrishna Elango * Ports mark this so error handling might try to fallback to 967d4bc0535SKrishna Elango * some other mechanism if available (machinecheck etc.). 968d4bc0535SKrishna Elango */ 969d4bc0535SKrishna Elango if (PCIE_IS_RP(PCIE_DIP2UPBUS(dip))) 970d4bc0535SKrishna Elango pcieb->pcieb_no_aer_msi = B_TRUE; 971d4bc0535SKrishna Elango } 972d4bc0535SKrishna Elango 973d4bc0535SKrishna Elango if (intr_types & DDI_INTR_TYPE_FIXED) { 974d4bc0535SKrishna Elango if (pcieb_intr_init(pcieb, DDI_INTR_TYPE_FIXED) != 975d4bc0535SKrishna Elango DDI_SUCCESS) { 976d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, 977d4bc0535SKrishna Elango "Unable to attach INTx handler\n"); 978d4bc0535SKrishna Elango goto FAIL; 979d4bc0535SKrishna Elango } 980d4bc0535SKrishna Elango } 981d4bc0535SKrishna Elango return (DDI_SUCCESS); 982d4bc0535SKrishna Elango 983d4bc0535SKrishna Elango FAIL: 984d4bc0535SKrishna Elango return (DDI_FAILURE); 985d4bc0535SKrishna Elango } 986d4bc0535SKrishna Elango 987d4bc0535SKrishna Elango /* 988d4bc0535SKrishna Elango * This function initializes internally generated interrupts only. 989d4bc0535SKrishna Elango * It does not affect any interrupts generated by downstream devices 990d4bc0535SKrishna Elango * or the forwarding of them. 991d4bc0535SKrishna Elango * 992d4bc0535SKrishna Elango * Enable Device Specific Interrupts or Hotplug features here. 993d4bc0535SKrishna Elango * Enabling features may change how many interrupts are requested 994d4bc0535SKrishna Elango * by the device. If features are not enabled first, the 995d4bc0535SKrishna Elango * device might not ask for any interrupts. 996d4bc0535SKrishna Elango */ 9970ff3af34SShesha Sreenivasamurthy 998d4bc0535SKrishna Elango static int 999d4bc0535SKrishna Elango pcieb_intr_init(pcieb_devstate_t *pcieb, int intr_type) 1000d4bc0535SKrishna Elango { 1001d4bc0535SKrishna Elango dev_info_t *dip = pcieb->pcieb_dip; 1002d4bc0535SKrishna Elango int nintrs, request, count, x; 1003d4bc0535SKrishna Elango int intr_cap = 0; 1004d4bc0535SKrishna Elango int inum = 0; 1005d4bc0535SKrishna Elango int ret, hp_msi_off; 1006d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip); 1007d4bc0535SKrishna Elango uint16_t vendorid = bus_p->bus_dev_ven_id & 0xFFFF; 1008d4bc0535SKrishna Elango boolean_t is_hp = B_FALSE; 1009d4bc0535SKrishna Elango boolean_t is_pme = B_FALSE; 1010d4bc0535SKrishna Elango 1011d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "pcieb_intr_init: Attaching %s handler\n", 1012d4bc0535SKrishna Elango (intr_type == DDI_INTR_TYPE_MSI) ? "MSI" : "INTx"); 1013d4bc0535SKrishna Elango 1014d4bc0535SKrishna Elango request = 0; 101526947304SEvan Yan if (PCIE_IS_HOTPLUG_ENABLED(dip)) { 1016d4bc0535SKrishna Elango request++; 1017d4bc0535SKrishna Elango is_hp = B_TRUE; 1018d4bc0535SKrishna Elango } 1019d4bc0535SKrishna Elango 1020d4bc0535SKrishna Elango /* 1021d4bc0535SKrishna Elango * Hotplug and PME share the same MSI vector. If hotplug is not 1022d4bc0535SKrishna Elango * supported check if MSI is needed for PME. 1023d4bc0535SKrishna Elango */ 1024d4bc0535SKrishna Elango if ((intr_type == DDI_INTR_TYPE_MSI) && PCIE_IS_RP(bus_p) && 1025d4bc0535SKrishna Elango (vendorid == NVIDIA_VENDOR_ID)) { 1026d4bc0535SKrishna Elango is_pme = B_TRUE; 1027d4bc0535SKrishna Elango if (!is_hp) 1028d4bc0535SKrishna Elango request++; 1029d4bc0535SKrishna Elango } 1030d4bc0535SKrishna Elango 1031d4bc0535SKrishna Elango /* 1032d4bc0535SKrishna Elango * Setup MSI if this device is a Rootport and has AER. Currently no 1033d4bc0535SKrishna Elango * SPARC Root Port supports fabric errors being reported through it. 1034d4bc0535SKrishna Elango */ 1035d4bc0535SKrishna Elango if (intr_type == DDI_INTR_TYPE_MSI) { 1036d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p) && PCIE_HAS_AER(bus_p)) 1037d4bc0535SKrishna Elango request++; 1038d4bc0535SKrishna Elango } 1039d4bc0535SKrishna Elango 1040d4bc0535SKrishna Elango if (request == 0) 1041d4bc0535SKrishna Elango return (DDI_SUCCESS); 1042d4bc0535SKrishna Elango 1043d4bc0535SKrishna Elango /* 1044d4bc0535SKrishna Elango * Get number of supported interrupts. 1045d4bc0535SKrishna Elango * 1046d4bc0535SKrishna Elango * Several Bridges/Switches will not have this property set, resulting 1047d4bc0535SKrishna Elango * in a FAILURE, if the device is not configured in a way that 1048d4bc0535SKrishna Elango * interrupts are needed. (eg. hotplugging) 1049d4bc0535SKrishna Elango */ 1050d4bc0535SKrishna Elango ret = ddi_intr_get_nintrs(dip, intr_type, &nintrs); 1051d4bc0535SKrishna Elango if ((ret != DDI_SUCCESS) || (nintrs == 0)) { 1052d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_nintrs ret:%d" 1053d4bc0535SKrishna Elango " req:%d\n", ret, nintrs); 1054d4bc0535SKrishna Elango return (DDI_FAILURE); 1055d4bc0535SKrishna Elango } 1056d4bc0535SKrishna Elango 1057d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "bdf 0x%x: ddi_intr_get_nintrs: nintrs %d", 1058d4bc0535SKrishna Elango " request %d\n", bus_p->bus_bdf, nintrs, request); 1059d4bc0535SKrishna Elango 1060d4bc0535SKrishna Elango if (request > nintrs) 1061d4bc0535SKrishna Elango request = nintrs; 1062d4bc0535SKrishna Elango 1063d4bc0535SKrishna Elango /* Allocate an array of interrupt handlers */ 1064d4bc0535SKrishna Elango pcieb->pcieb_htable_size = sizeof (ddi_intr_handle_t) * request; 1065d4bc0535SKrishna Elango pcieb->pcieb_htable = kmem_zalloc(pcieb->pcieb_htable_size, 1066d4bc0535SKrishna Elango KM_SLEEP); 1067d4bc0535SKrishna Elango pcieb->pcieb_init_flags |= PCIEB_INIT_HTABLE; 1068d4bc0535SKrishna Elango 1069d4bc0535SKrishna Elango ret = ddi_intr_alloc(dip, pcieb->pcieb_htable, intr_type, inum, 1070d4bc0535SKrishna Elango request, &count, DDI_INTR_ALLOC_NORMAL); 1071d4bc0535SKrishna Elango if ((ret != DDI_SUCCESS) || (count == 0)) { 1072d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_alloc() ret: %d ask: %d" 1073d4bc0535SKrishna Elango " actual: %d\n", ret, request, count); 1074d4bc0535SKrishna Elango goto FAIL; 1075d4bc0535SKrishna Elango } 1076d4bc0535SKrishna Elango pcieb->pcieb_init_flags |= PCIEB_INIT_ALLOC; 1077d4bc0535SKrishna Elango 1078d4bc0535SKrishna Elango /* Save the actual number of interrupts allocated */ 1079d4bc0535SKrishna Elango pcieb->pcieb_intr_count = count; 1080d4bc0535SKrishna Elango if (count < request) { 1081d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "bdf 0%x: Requested Intr: %d" 1082d4bc0535SKrishna Elango " Received: %d\n", bus_p->bus_bdf, request, count); 1083d4bc0535SKrishna Elango } 1084d4bc0535SKrishna Elango 1085d4bc0535SKrishna Elango /* 1086d4bc0535SKrishna Elango * NVidia (MCP55 and other) chipsets have a errata that if the number 1087d4bc0535SKrishna Elango * of requested MSI intrs is not allocated we have to fall back to INTx. 1088d4bc0535SKrishna Elango */ 1089d4bc0535SKrishna Elango if (intr_type == DDI_INTR_TYPE_MSI) { 1090d4bc0535SKrishna Elango if (PCIE_IS_RP(bus_p) && (vendorid == NVIDIA_VENDOR_ID)) { 1091d4bc0535SKrishna Elango if (request != count) 1092d4bc0535SKrishna Elango goto FAIL; 1093d4bc0535SKrishna Elango } 1094d4bc0535SKrishna Elango } 1095d4bc0535SKrishna Elango 1096d4bc0535SKrishna Elango /* Get interrupt priority */ 1097d4bc0535SKrishna Elango ret = ddi_intr_get_pri(pcieb->pcieb_htable[0], 1098d4bc0535SKrishna Elango &pcieb->pcieb_intr_priority); 1099d4bc0535SKrishna Elango if (ret != DDI_SUCCESS) { 1100d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_get_pri() ret: %d\n", 1101d4bc0535SKrishna Elango ret); 1102d4bc0535SKrishna Elango goto FAIL; 1103d4bc0535SKrishna Elango } 1104d4bc0535SKrishna Elango 1105d4bc0535SKrishna Elango if (pcieb->pcieb_intr_priority >= LOCK_LEVEL) { 1106d4bc0535SKrishna Elango pcieb->pcieb_intr_priority = LOCK_LEVEL - 1; 1107d4bc0535SKrishna Elango ret = ddi_intr_set_pri(pcieb->pcieb_htable[0], 1108d4bc0535SKrishna Elango pcieb->pcieb_intr_priority); 1109d4bc0535SKrishna Elango if (ret != DDI_SUCCESS) { 1110d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "ddi_intr_set_pri() ret:" 1111d4bc0535SKrishna Elango " %d\n", ret); 1112d4bc0535SKrishna Elango 1113d4bc0535SKrishna Elango goto FAIL; 1114d4bc0535SKrishna Elango } 1115d4bc0535SKrishna Elango } 1116d4bc0535SKrishna Elango 1117d4bc0535SKrishna Elango mutex_init(&pcieb->pcieb_intr_mutex, NULL, MUTEX_DRIVER, NULL); 1118d4bc0535SKrishna Elango 1119d4bc0535SKrishna Elango pcieb->pcieb_init_flags |= PCIEB_INIT_MUTEX; 1120d4bc0535SKrishna Elango 1121d4bc0535SKrishna Elango for (count = 0; count < pcieb->pcieb_intr_count; count++) { 1122d4bc0535SKrishna Elango ret = ddi_intr_add_handler(pcieb->pcieb_htable[count], 1123d4bc0535SKrishna Elango pcieb_intr_handler, (caddr_t)pcieb, 1124d4bc0535SKrishna Elango (caddr_t)(uintptr_t)(inum + count)); 1125d4bc0535SKrishna Elango 1126d4bc0535SKrishna Elango if (ret != DDI_SUCCESS) { 1127d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "Cannot add " 1128d4bc0535SKrishna Elango "interrupt(%d)\n", ret); 1129d4bc0535SKrishna Elango break; 1130d4bc0535SKrishna Elango } 1131d4bc0535SKrishna Elango } 1132d4bc0535SKrishna Elango 1133d4bc0535SKrishna Elango /* If unsucessful, remove the added handlers */ 1134d4bc0535SKrishna Elango if (ret != DDI_SUCCESS) { 1135d4bc0535SKrishna Elango for (x = 0; x < count; x++) { 1136d4bc0535SKrishna Elango (void) ddi_intr_remove_handler(pcieb->pcieb_htable[x]); 1137d4bc0535SKrishna Elango } 1138d4bc0535SKrishna Elango goto FAIL; 1139d4bc0535SKrishna Elango } 1140d4bc0535SKrishna Elango 1141d4bc0535SKrishna Elango pcieb->pcieb_init_flags |= PCIEB_INIT_HANDLER; 1142d4bc0535SKrishna Elango 1143d4bc0535SKrishna Elango (void) ddi_intr_get_cap(pcieb->pcieb_htable[0], &intr_cap); 1144d4bc0535SKrishna Elango 1145d4bc0535SKrishna Elango /* 1146d4bc0535SKrishna Elango * Get this intr lock because we are not quite ready to handle 1147d4bc0535SKrishna Elango * interrupts immediately after enabling it. The MSI multi register 1148d4bc0535SKrishna Elango * gets programmed in ddi_intr_enable after which we need to get the 1149d4bc0535SKrishna Elango * MSI offsets for Hotplug/AER. 1150d4bc0535SKrishna Elango */ 1151d4bc0535SKrishna Elango mutex_enter(&pcieb->pcieb_intr_mutex); 1152d4bc0535SKrishna Elango 1153d4bc0535SKrishna Elango if (intr_cap & DDI_INTR_FLAG_BLOCK) { 1154d4bc0535SKrishna Elango (void) ddi_intr_block_enable(pcieb->pcieb_htable, 1155d4bc0535SKrishna Elango pcieb->pcieb_intr_count); 1156d4bc0535SKrishna Elango pcieb->pcieb_init_flags |= PCIEB_INIT_BLOCK; 1157d4bc0535SKrishna Elango } else { 1158d4bc0535SKrishna Elango for (count = 0; count < pcieb->pcieb_intr_count; count++) { 1159d4bc0535SKrishna Elango (void) ddi_intr_enable(pcieb->pcieb_htable[count]); 1160d4bc0535SKrishna Elango } 1161d4bc0535SKrishna Elango } 1162d4bc0535SKrishna Elango pcieb->pcieb_init_flags |= PCIEB_INIT_ENABLE; 1163d4bc0535SKrishna Elango 1164d4bc0535SKrishna Elango /* Save the interrupt type */ 1165d4bc0535SKrishna Elango pcieb->pcieb_intr_type = intr_type; 1166d4bc0535SKrishna Elango 1167d4bc0535SKrishna Elango /* Get the MSI offset for hotplug/PME from the PCIe cap reg */ 1168d4bc0535SKrishna Elango if (intr_type == DDI_INTR_TYPE_MSI) { 1169d4bc0535SKrishna Elango hp_msi_off = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL, 1170d4bc0535SKrishna Elango bus_p->bus_pcie_off, PCIE_PCIECAP) & 1171d4bc0535SKrishna Elango PCIE_PCIECAP_INT_MSG_NUM; 1172d4bc0535SKrishna Elango 1173d4bc0535SKrishna Elango if (hp_msi_off >= count) { 1174d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "MSI number %d in PCIe " 1175d4bc0535SKrishna Elango "cap > max allocated %d\n", hp_msi_off, count); 1176d4bc0535SKrishna Elango mutex_exit(&pcieb->pcieb_intr_mutex); 1177d4bc0535SKrishna Elango goto FAIL; 1178d4bc0535SKrishna Elango } 1179d4bc0535SKrishna Elango 1180d4bc0535SKrishna Elango if (is_hp) 1181d4bc0535SKrishna Elango pcieb->pcieb_isr_tab[hp_msi_off] |= PCIEB_INTR_SRC_HP; 1182d4bc0535SKrishna Elango 1183d4bc0535SKrishna Elango if (is_pme) 1184d4bc0535SKrishna Elango pcieb->pcieb_isr_tab[hp_msi_off] |= PCIEB_INTR_SRC_PME; 1185d4bc0535SKrishna Elango } else { 1186d4bc0535SKrishna Elango /* INTx handles only Hotplug interrupts */ 1187d4bc0535SKrishna Elango if (is_hp) 1188d4bc0535SKrishna Elango pcieb->pcieb_isr_tab[0] |= PCIEB_INTR_SRC_HP; 1189d4bc0535SKrishna Elango } 1190d4bc0535SKrishna Elango 1191d4bc0535SKrishna Elango 1192d4bc0535SKrishna Elango /* 1193d4bc0535SKrishna Elango * Get the MSI offset for errors from the AER Root Error status 1194d4bc0535SKrishna Elango * register. 1195d4bc0535SKrishna Elango */ 1196d4bc0535SKrishna Elango if ((intr_type == DDI_INTR_TYPE_MSI) && PCIE_IS_RP(bus_p)) { 1197d4bc0535SKrishna Elango if (PCIE_HAS_AER(bus_p)) { 1198d4bc0535SKrishna Elango int aer_msi_off; 1199d4bc0535SKrishna Elango aer_msi_off = (PCI_XCAP_GET32(bus_p->bus_cfg_hdl, NULL, 1200d4bc0535SKrishna Elango bus_p->bus_aer_off, PCIE_AER_RE_STS) >> 1201d4bc0535SKrishna Elango PCIE_AER_RE_STS_MSG_NUM_SHIFT) & 1202d4bc0535SKrishna Elango PCIE_AER_RE_STS_MSG_NUM_MASK; 1203d4bc0535SKrishna Elango 1204d4bc0535SKrishna Elango if (aer_msi_off >= count) { 1205d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_ATTACH, dip, "MSI number %d in" 1206d4bc0535SKrishna Elango " AER cap > max allocated %d\n", 1207d4bc0535SKrishna Elango aer_msi_off, count); 1208d4bc0535SKrishna Elango mutex_exit(&pcieb->pcieb_intr_mutex); 1209d4bc0535SKrishna Elango goto FAIL; 1210d4bc0535SKrishna Elango } 1211d4bc0535SKrishna Elango pcieb->pcieb_isr_tab[aer_msi_off] |= PCIEB_INTR_SRC_AER; 1212d4bc0535SKrishna Elango } else { 1213d4bc0535SKrishna Elango /* 1214d4bc0535SKrishna Elango * This RP does not have AER. Fallback to the 1215d4bc0535SKrishna Elango * SERR+Machinecheck approach if available. 1216d4bc0535SKrishna Elango */ 1217d4bc0535SKrishna Elango pcieb->pcieb_no_aer_msi = B_TRUE; 1218d4bc0535SKrishna Elango } 1219d4bc0535SKrishna Elango } 1220d4bc0535SKrishna Elango 1221d4bc0535SKrishna Elango mutex_exit(&pcieb->pcieb_intr_mutex); 1222d4bc0535SKrishna Elango return (DDI_SUCCESS); 1223d4bc0535SKrishna Elango 1224d4bc0535SKrishna Elango FAIL: 12250ff3af34SShesha Sreenivasamurthy pcieb_intr_fini(pcieb); 1226d4bc0535SKrishna Elango return (DDI_FAILURE); 1227d4bc0535SKrishna Elango } 1228d4bc0535SKrishna Elango 1229d4bc0535SKrishna Elango static void 1230d4bc0535SKrishna Elango pcieb_intr_fini(pcieb_devstate_t *pcieb) 1231d4bc0535SKrishna Elango { 1232d4bc0535SKrishna Elango int x; 1233d4bc0535SKrishna Elango int count = pcieb->pcieb_intr_count; 1234d4bc0535SKrishna Elango int flags = pcieb->pcieb_init_flags; 1235d4bc0535SKrishna Elango 1236d4bc0535SKrishna Elango if ((flags & PCIEB_INIT_ENABLE) && 1237d4bc0535SKrishna Elango (flags & PCIEB_INIT_BLOCK)) { 1238d4bc0535SKrishna Elango (void) ddi_intr_block_disable(pcieb->pcieb_htable, count); 1239d4bc0535SKrishna Elango flags &= ~(PCIEB_INIT_ENABLE | 1240d4bc0535SKrishna Elango PCIEB_INIT_BLOCK); 1241d4bc0535SKrishna Elango } 1242d4bc0535SKrishna Elango 1243d4bc0535SKrishna Elango if (flags & PCIEB_INIT_MUTEX) 1244d4bc0535SKrishna Elango mutex_destroy(&pcieb->pcieb_intr_mutex); 1245d4bc0535SKrishna Elango 1246d4bc0535SKrishna Elango for (x = 0; x < count; x++) { 1247d4bc0535SKrishna Elango if (flags & PCIEB_INIT_ENABLE) 1248d4bc0535SKrishna Elango (void) ddi_intr_disable(pcieb->pcieb_htable[x]); 1249d4bc0535SKrishna Elango 1250d4bc0535SKrishna Elango if (flags & PCIEB_INIT_HANDLER) 1251d4bc0535SKrishna Elango (void) ddi_intr_remove_handler(pcieb->pcieb_htable[x]); 1252d4bc0535SKrishna Elango 1253d4bc0535SKrishna Elango if (flags & PCIEB_INIT_ALLOC) 1254d4bc0535SKrishna Elango (void) ddi_intr_free(pcieb->pcieb_htable[x]); 1255d4bc0535SKrishna Elango } 1256d4bc0535SKrishna Elango 1257d4bc0535SKrishna Elango flags &= ~(PCIEB_INIT_ENABLE | PCIEB_INIT_HANDLER | PCIEB_INIT_ALLOC | 1258d4bc0535SKrishna Elango PCIEB_INIT_MUTEX); 1259d4bc0535SKrishna Elango 1260d4bc0535SKrishna Elango if (flags & PCIEB_INIT_HTABLE) 1261d4bc0535SKrishna Elango kmem_free(pcieb->pcieb_htable, pcieb->pcieb_htable_size); 1262d4bc0535SKrishna Elango 1263d4bc0535SKrishna Elango flags &= ~PCIEB_INIT_HTABLE; 1264d4bc0535SKrishna Elango 1265d4bc0535SKrishna Elango pcieb->pcieb_init_flags &= flags; 1266d4bc0535SKrishna Elango } 1267d4bc0535SKrishna Elango 1268d4bc0535SKrishna Elango /* 1269d4bc0535SKrishna Elango * Checks if this device needs MSIs enabled or not. 1270d4bc0535SKrishna Elango */ 1271d4bc0535SKrishna Elango /*ARGSUSED*/ 1272d4bc0535SKrishna Elango static int 1273d4bc0535SKrishna Elango pcieb_msi_supported(dev_info_t *dip) 1274d4bc0535SKrishna Elango { 1275d4bc0535SKrishna Elango return ((pcieb_enable_msi && pcieb_plat_msi_supported(dip)) ? 1276d4bc0535SKrishna Elango DDI_SUCCESS: DDI_FAILURE); 1277d4bc0535SKrishna Elango } 1278d4bc0535SKrishna Elango 1279d4bc0535SKrishna Elango /*ARGSUSED*/ 12800ff3af34SShesha Sreenivasamurthy static int 1281d4bc0535SKrishna Elango pcieb_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap, 1282d4bc0535SKrishna Elango ddi_iblock_cookie_t *ibc) 1283d4bc0535SKrishna Elango { 1284d4bc0535SKrishna Elango pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, 1285d4bc0535SKrishna Elango ddi_get_instance(dip)); 1286d4bc0535SKrishna Elango 1287d4bc0535SKrishna Elango ASSERT(ibc != NULL); 1288d4bc0535SKrishna Elango *ibc = pcieb->pcieb_fm_ibc; 1289d4bc0535SKrishna Elango 1290d4bc0535SKrishna Elango return (DEVI(dip)->devi_fmhdl->fh_cap | DDI_FM_ACCCHK_CAPABLE | 1291d4bc0535SKrishna Elango DDI_FM_DMACHK_CAPABLE); 1292d4bc0535SKrishna Elango } 1293d4bc0535SKrishna Elango 1294d4bc0535SKrishna Elango static int 1295d4bc0535SKrishna Elango pcieb_fm_init(pcieb_devstate_t *pcieb_p) 1296d4bc0535SKrishna Elango { 1297d4bc0535SKrishna Elango dev_info_t *dip = pcieb_p->pcieb_dip; 1298d4bc0535SKrishna Elango int fm_cap = DDI_FM_EREPORT_CAPABLE; 1299d4bc0535SKrishna Elango 1300d4bc0535SKrishna Elango /* 1301d4bc0535SKrishna Elango * Request our capability level and get our parents capability 1302d4bc0535SKrishna Elango * and ibc. 1303d4bc0535SKrishna Elango */ 1304d4bc0535SKrishna Elango ddi_fm_init(dip, &fm_cap, &pcieb_p->pcieb_fm_ibc); 1305d4bc0535SKrishna Elango 1306d4bc0535SKrishna Elango return (DDI_SUCCESS); 1307d4bc0535SKrishna Elango } 1308d4bc0535SKrishna Elango 1309d4bc0535SKrishna Elango /* 1310d4bc0535SKrishna Elango * Breakdown our FMA resources 1311d4bc0535SKrishna Elango */ 1312d4bc0535SKrishna Elango static void 1313d4bc0535SKrishna Elango pcieb_fm_fini(pcieb_devstate_t *pcieb_p) 1314d4bc0535SKrishna Elango { 1315d4bc0535SKrishna Elango /* 1316d4bc0535SKrishna Elango * Clean up allocated fm structures 1317d4bc0535SKrishna Elango */ 1318d4bc0535SKrishna Elango ddi_fm_fini(pcieb_p->pcieb_dip); 1319d4bc0535SKrishna Elango } 1320d4bc0535SKrishna Elango 1321d4bc0535SKrishna Elango static int 1322d4bc0535SKrishna Elango pcieb_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1323d4bc0535SKrishna Elango { 132426947304SEvan Yan int inst = PCI_MINOR_NUM_TO_INSTANCE(getminor(*devp)); 132526947304SEvan Yan pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, inst); 132626947304SEvan Yan int rv; 1327d4bc0535SKrishna Elango 132826947304SEvan Yan if (pcieb == NULL) 1329d4bc0535SKrishna Elango return (ENXIO); 1330d4bc0535SKrishna Elango 133126947304SEvan Yan mutex_enter(&pcieb->pcieb_mutex); 133226947304SEvan Yan rv = pcie_open(pcieb->pcieb_dip, devp, flags, otyp, credp); 133326947304SEvan Yan mutex_exit(&pcieb->pcieb_mutex); 1334d4bc0535SKrishna Elango 133526947304SEvan Yan return (rv); 1336d4bc0535SKrishna Elango } 1337d4bc0535SKrishna Elango 1338d4bc0535SKrishna Elango static int 1339d4bc0535SKrishna Elango pcieb_close(dev_t dev, int flags, int otyp, cred_t *credp) 1340d4bc0535SKrishna Elango { 134126947304SEvan Yan int inst = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev)); 134226947304SEvan Yan pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, inst); 134326947304SEvan Yan int rv; 1344d4bc0535SKrishna Elango 134526947304SEvan Yan if (pcieb == NULL) 1346d4bc0535SKrishna Elango return (ENXIO); 1347d4bc0535SKrishna Elango 134826947304SEvan Yan mutex_enter(&pcieb->pcieb_mutex); 134926947304SEvan Yan rv = pcie_close(pcieb->pcieb_dip, dev, flags, otyp, credp); 135026947304SEvan Yan mutex_exit(&pcieb->pcieb_mutex); 1351d4bc0535SKrishna Elango 135226947304SEvan Yan return (rv); 1353d4bc0535SKrishna Elango } 1354d4bc0535SKrishna Elango 1355d4bc0535SKrishna Elango static int 1356d4bc0535SKrishna Elango pcieb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1357d4bc0535SKrishna Elango int *rvalp) 1358d4bc0535SKrishna Elango { 135926947304SEvan Yan int inst = PCI_MINOR_NUM_TO_INSTANCE(getminor(dev)); 136026947304SEvan Yan pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, inst); 136126947304SEvan Yan int rv; 1362d4bc0535SKrishna Elango 136326947304SEvan Yan if (pcieb == NULL) 1364d4bc0535SKrishna Elango return (ENXIO); 1365d4bc0535SKrishna Elango 136626947304SEvan Yan /* To handle devctl and hotplug related ioctls */ 136726947304SEvan Yan rv = pcie_ioctl(pcieb->pcieb_dip, dev, cmd, arg, mode, credp, rvalp); 1368d4bc0535SKrishna Elango 1369d4bc0535SKrishna Elango return (rv); 1370d4bc0535SKrishna Elango } 1371d4bc0535SKrishna Elango 1372d4bc0535SKrishna Elango /* 1373d4bc0535SKrishna Elango * Common interrupt handler for hotplug, PME and errors. 1374d4bc0535SKrishna Elango */ 1375d4bc0535SKrishna Elango static uint_t 1376d4bc0535SKrishna Elango pcieb_intr_handler(caddr_t arg1, caddr_t arg2) 1377d4bc0535SKrishna Elango { 1378d4bc0535SKrishna Elango pcieb_devstate_t *pcieb_p = (pcieb_devstate_t *)arg1; 1379d4bc0535SKrishna Elango dev_info_t *dip = pcieb_p->pcieb_dip; 1380d4bc0535SKrishna Elango ddi_fm_error_t derr; 1381d4bc0535SKrishna Elango int sts = 0; 1382d4bc0535SKrishna Elango int ret = DDI_INTR_UNCLAIMED; 1383d4bc0535SKrishna Elango int isrc; 1384d4bc0535SKrishna Elango 1385d4bc0535SKrishna Elango if (!(pcieb_p->pcieb_init_flags & PCIEB_INIT_ENABLE)) 1386d4bc0535SKrishna Elango goto FAIL; 1387d4bc0535SKrishna Elango 1388d4bc0535SKrishna Elango mutex_enter(&pcieb_p->pcieb_intr_mutex); 1389d4bc0535SKrishna Elango isrc = pcieb_p->pcieb_isr_tab[(int)(uintptr_t)arg2]; 1390d4bc0535SKrishna Elango mutex_exit(&pcieb_p->pcieb_intr_mutex); 1391d4bc0535SKrishna Elango 1392d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_INTR, dip, "Received intr number %d\n", 1393d4bc0535SKrishna Elango (int)(uintptr_t)arg2); 1394d4bc0535SKrishna Elango 1395d4bc0535SKrishna Elango if (isrc == PCIEB_INTR_SRC_UNKNOWN) 1396d4bc0535SKrishna Elango goto FAIL; 1397d4bc0535SKrishna Elango 139826947304SEvan Yan if (isrc & PCIEB_INTR_SRC_HP) 139926947304SEvan Yan ret = pcie_intr(dip); 1400d4bc0535SKrishna Elango 1401d4bc0535SKrishna Elango if (isrc & PCIEB_INTR_SRC_PME) 1402d4bc0535SKrishna Elango ret = DDI_INTR_CLAIMED; 1403d4bc0535SKrishna Elango 1404d4bc0535SKrishna Elango /* AER Error */ 1405d4bc0535SKrishna Elango if (isrc & PCIEB_INTR_SRC_AER) { 1406d4bc0535SKrishna Elango /* 1407d4bc0535SKrishna Elango * If MSI is shared with PME/hotplug then check Root Error 1408d4bc0535SKrishna Elango * Status Reg before claiming it. For now it's ok since 1409d4bc0535SKrishna Elango * we know we get 2 MSIs. 1410d4bc0535SKrishna Elango */ 1411d4bc0535SKrishna Elango ret = DDI_INTR_CLAIMED; 1412d4bc0535SKrishna Elango bzero(&derr, sizeof (ddi_fm_error_t)); 1413d4bc0535SKrishna Elango derr.fme_version = DDI_FME_VERSION; 1414d4bc0535SKrishna Elango mutex_enter(&pcieb_p->pcieb_peek_poke_mutex); 1415d4bc0535SKrishna Elango mutex_enter(&pcieb_p->pcieb_err_mutex); 1416d4bc0535SKrishna Elango 1417fc256490SJason Beloro pf_eh_enter(PCIE_DIP2BUS(dip)); 1418fc256490SJason Beloro PCIE_ROOT_EH_SRC(PCIE_DIP2PFD(dip))->intr_type = 1419fc256490SJason Beloro PF_INTR_TYPE_AER; 1420fc256490SJason Beloro 1421d4bc0535SKrishna Elango if ((DEVI(dip)->devi_fmhdl->fh_cap) & DDI_FM_EREPORT_CAPABLE) 1422d4bc0535SKrishna Elango sts = pf_scan_fabric(dip, &derr, NULL); 1423fc256490SJason Beloro pf_eh_exit(PCIE_DIP2BUS(dip)); 1424d4bc0535SKrishna Elango 1425d4bc0535SKrishna Elango mutex_exit(&pcieb_p->pcieb_err_mutex); 1426d4bc0535SKrishna Elango mutex_exit(&pcieb_p->pcieb_peek_poke_mutex); 1427d4bc0535SKrishna Elango if (pcieb_die & sts) 1428d4bc0535SKrishna Elango fm_panic("%s-%d: PCI(-X) Express Fatal Error. (0x%x)", 1429d4bc0535SKrishna Elango ddi_driver_name(dip), ddi_get_instance(dip), sts); 1430d4bc0535SKrishna Elango } 1431d4bc0535SKrishna Elango FAIL: 1432d4bc0535SKrishna Elango return (ret); 1433d4bc0535SKrishna Elango } 1434d4bc0535SKrishna Elango 1435d4bc0535SKrishna Elango /* 1436d4bc0535SKrishna Elango * Some PCI-X to PCI-E bridges do not support full 64-bit addressing on the 1437d4bc0535SKrishna Elango * PCI-X side of the bridge. We build a special version of this driver for 1438d4bc0535SKrishna Elango * those bridges, which uses PCIEB_ADDR_LIMIT_LO and/or PCIEB_ADDR_LIMIT_HI 1439d4bc0535SKrishna Elango * to define the range of values which the chip can handle. The code below 1440d4bc0535SKrishna Elango * then clamps the DMA address range supplied by the driver, preventing the 1441d4bc0535SKrishna Elango * PCI-E nexus driver from allocating any memory the bridge can't deal 1442d4bc0535SKrishna Elango * with. 1443d4bc0535SKrishna Elango */ 1444d4bc0535SKrishna Elango static int 1445d4bc0535SKrishna Elango pcieb_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, 1446d4bc0535SKrishna Elango ddi_dma_attr_t *attr_p, int (*waitfp)(caddr_t), caddr_t arg, 1447d4bc0535SKrishna Elango ddi_dma_handle_t *handlep) 1448d4bc0535SKrishna Elango { 1449d4bc0535SKrishna Elango int ret; 1450af334d37SColin Zou - Sun Microsystems - Beijing China #ifdef PCIEB_BCM 1451d4bc0535SKrishna Elango uint64_t lim; 1452d4bc0535SKrishna Elango 1453d4bc0535SKrishna Elango /* 1454d4bc0535SKrishna Elango * If the leaf device's limits are outside than what the Broadcom 1455d4bc0535SKrishna Elango * bridge can handle, we need to clip the values passed up the chain. 1456d4bc0535SKrishna Elango */ 1457d4bc0535SKrishna Elango lim = attr_p->dma_attr_addr_lo; 1458d4bc0535SKrishna Elango attr_p->dma_attr_addr_lo = MAX(lim, PCIEB_ADDR_LIMIT_LO); 1459d4bc0535SKrishna Elango 1460d4bc0535SKrishna Elango lim = attr_p->dma_attr_addr_hi; 1461d4bc0535SKrishna Elango attr_p->dma_attr_addr_hi = MIN(lim, PCIEB_ADDR_LIMIT_HI); 1462d4bc0535SKrishna Elango 1463af334d37SColin Zou - Sun Microsystems - Beijing China #endif /* PCIEB_BCM */ 1464d4bc0535SKrishna Elango 1465d4bc0535SKrishna Elango /* 1466d4bc0535SKrishna Elango * This is a software workaround to fix the Broadcom 5714/5715 PCIe-PCI 1467d4bc0535SKrishna Elango * bridge prefetch bug. Intercept the DMA alloc handle request and set 1468d4bc0535SKrishna Elango * PX_DMAI_FLAGS_MAP_BUFZONE flag in the handle. If this flag is set, 1469d4bc0535SKrishna Elango * the px nexus driver will allocate an extra page & make it valid one, 1470d4bc0535SKrishna Elango * for any DVMA request that comes from any of the Broadcom bridge child 1471d4bc0535SKrishna Elango * devices. 1472d4bc0535SKrishna Elango */ 1473d4bc0535SKrishna Elango if ((ret = ddi_dma_allochdl(dip, rdip, attr_p, waitfp, arg, 1474d4bc0535SKrishna Elango handlep)) == DDI_SUCCESS) { 1475d4bc0535SKrishna Elango ddi_dma_impl_t *mp = (ddi_dma_impl_t *)*handlep; 1476af334d37SColin Zou - Sun Microsystems - Beijing China #ifdef PCIEB_BCM 1477d4bc0535SKrishna Elango mp->dmai_inuse |= PX_DMAI_FLAGS_MAP_BUFZONE; 1478af334d37SColin Zou - Sun Microsystems - Beijing China #endif /* PCIEB_BCM */ 1479d4bc0535SKrishna Elango /* 1480d4bc0535SKrishna Elango * For a given rdip, update mp->dmai_bdf with the bdf value 1481d4bc0535SKrishna Elango * of pcieb's immediate child or secondary bus-id of the 1482d4bc0535SKrishna Elango * PCIe2PCI bridge. 1483d4bc0535SKrishna Elango */ 1484d4bc0535SKrishna Elango mp->dmai_minxfer = pcie_get_bdf_for_dma_xfer(dip, rdip); 1485d4bc0535SKrishna Elango } 1486d4bc0535SKrishna Elango 1487d4bc0535SKrishna Elango return (ret); 1488d4bc0535SKrishna Elango } 1489d4bc0535SKrishna Elango 1490d4bc0535SKrishna Elango /* 1491d4bc0535SKrishna Elango * FDVMA feature is not supported for any child device of Broadcom 5714/5715 1492d4bc0535SKrishna Elango * PCIe-PCI bridge due to prefetch bug. Return failure immediately, so that 1493d4bc0535SKrishna Elango * these drivers will switch to regular DVMA path. 1494d4bc0535SKrishna Elango */ 1495d4bc0535SKrishna Elango /*ARGSUSED*/ 1496d4bc0535SKrishna Elango static int 1497d4bc0535SKrishna Elango pcieb_dma_mctl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handle, 1498d4bc0535SKrishna Elango enum ddi_dma_ctlops cmd, off_t *offp, size_t *lenp, caddr_t *objp, 1499d4bc0535SKrishna Elango uint_t cache_flags) 1500d4bc0535SKrishna Elango { 1501d4bc0535SKrishna Elango int ret; 1502d4bc0535SKrishna Elango 1503af334d37SColin Zou - Sun Microsystems - Beijing China #ifdef PCIEB_BCM 1504d4bc0535SKrishna Elango if (cmd == DDI_DMA_RESERVE) 1505d4bc0535SKrishna Elango return (DDI_FAILURE); 1506af334d37SColin Zou - Sun Microsystems - Beijing China #endif /* PCIEB_BCM */ 1507d4bc0535SKrishna Elango 1508d4bc0535SKrishna Elango if (((ret = ddi_dma_mctl(dip, rdip, handle, cmd, offp, lenp, objp, 1509d4bc0535SKrishna Elango cache_flags)) == DDI_SUCCESS) && (cmd == DDI_DMA_RESERVE)) { 1510d4bc0535SKrishna Elango ddi_dma_impl_t *mp = (ddi_dma_impl_t *)*objp; 1511d4bc0535SKrishna Elango 1512d4bc0535SKrishna Elango /* 1513d4bc0535SKrishna Elango * For a given rdip, update mp->dmai_bdf with the bdf value 1514d4bc0535SKrishna Elango * of pcieb's immediate child or secondary bus-id of the 1515d4bc0535SKrishna Elango * PCIe2PCI bridge. 1516d4bc0535SKrishna Elango */ 1517d4bc0535SKrishna Elango mp->dmai_minxfer = pcie_get_bdf_for_dma_xfer(dip, rdip); 1518d4bc0535SKrishna Elango } 1519d4bc0535SKrishna Elango 1520d4bc0535SKrishna Elango return (ret); 1521d4bc0535SKrishna Elango } 1522d4bc0535SKrishna Elango 1523d4bc0535SKrishna Elango static int 1524d4bc0535SKrishna Elango pcieb_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 1525d4bc0535SKrishna Elango ddi_intr_handle_impl_t *hdlp, void *result) 1526d4bc0535SKrishna Elango { 1527d4bc0535SKrishna Elango return (pcieb_plat_intr_ops(dip, rdip, intr_op, hdlp, result)); 1528d4bc0535SKrishna Elango 1529d4bc0535SKrishna Elango } 1530d4bc0535SKrishna Elango 1531d4bc0535SKrishna Elango /* 1532d4bc0535SKrishna Elango * Power management related initialization specific to pcieb. 1533d4bc0535SKrishna Elango * Called by pcieb_attach() 1534d4bc0535SKrishna Elango */ 1535d4bc0535SKrishna Elango static int 1536d4bc0535SKrishna Elango pcieb_pwr_setup(dev_info_t *dip) 1537d4bc0535SKrishna Elango { 1538d4bc0535SKrishna Elango char *comp_array[5]; 1539d4bc0535SKrishna Elango int i; 1540d4bc0535SKrishna Elango ddi_acc_handle_t conf_hdl; 1541d4bc0535SKrishna Elango uint16_t pmcap, cap_ptr; 1542d4bc0535SKrishna Elango pcie_pwr_t *pwr_p; 1543d4bc0535SKrishna Elango 1544d4bc0535SKrishna Elango /* Some platforms/devices may choose to disable PM */ 1545d4bc0535SKrishna Elango if (pcieb_plat_pwr_disable(dip)) { 1546d4bc0535SKrishna Elango (void) pcieb_pwr_disable(dip); 1547d4bc0535SKrishna Elango return (DDI_SUCCESS); 1548d4bc0535SKrishna Elango } 1549d4bc0535SKrishna Elango 1550d4bc0535SKrishna Elango ASSERT(PCIE_PMINFO(dip)); 1551d4bc0535SKrishna Elango pwr_p = PCIE_NEXUS_PMINFO(dip); 1552d4bc0535SKrishna Elango ASSERT(pwr_p); 1553d4bc0535SKrishna Elango 1554d4bc0535SKrishna Elango /* Code taken from pci_pci driver */ 1555d4bc0535SKrishna Elango if (pci_config_setup(dip, &pwr_p->pwr_conf_hdl) != DDI_SUCCESS) { 1556d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_setup: pci_config_setup " 1557d4bc0535SKrishna Elango "failed\n"); 1558d4bc0535SKrishna Elango return (DDI_FAILURE); 1559d4bc0535SKrishna Elango } 1560d4bc0535SKrishna Elango conf_hdl = pwr_p->pwr_conf_hdl; 1561d4bc0535SKrishna Elango 1562d4bc0535SKrishna Elango /* 1563d4bc0535SKrishna Elango * Walk the capabilities searching for a PM entry. 1564d4bc0535SKrishna Elango */ 1565d4bc0535SKrishna Elango if ((PCI_CAP_LOCATE(conf_hdl, PCI_CAP_ID_PM, &cap_ptr)) == 1566d4bc0535SKrishna Elango DDI_FAILURE) { 1567d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, dip, "switch/bridge does not support PM. " 1568d4bc0535SKrishna Elango " PCI PM data structure not found in config header\n"); 1569d4bc0535SKrishna Elango pci_config_teardown(&conf_hdl); 1570d4bc0535SKrishna Elango return (DDI_SUCCESS); 1571d4bc0535SKrishna Elango } 1572d4bc0535SKrishna Elango /* 1573d4bc0535SKrishna Elango * Save offset to pmcsr for future references. 1574d4bc0535SKrishna Elango */ 1575d4bc0535SKrishna Elango pwr_p->pwr_pmcsr_offset = cap_ptr + PCI_PMCSR; 1576d4bc0535SKrishna Elango pmcap = PCI_CAP_GET16(conf_hdl, NULL, cap_ptr, PCI_PMCAP); 1577d4bc0535SKrishna Elango if (pmcap & PCI_PMCAP_D1) { 1578d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, dip, "D1 state supported\n"); 1579d4bc0535SKrishna Elango pwr_p->pwr_pmcaps |= PCIE_SUPPORTS_D1; 1580d4bc0535SKrishna Elango } 1581d4bc0535SKrishna Elango if (pmcap & PCI_PMCAP_D2) { 1582d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, dip, "D2 state supported\n"); 1583d4bc0535SKrishna Elango pwr_p->pwr_pmcaps |= PCIE_SUPPORTS_D2; 1584d4bc0535SKrishna Elango } 1585d4bc0535SKrishna Elango 1586d4bc0535SKrishna Elango i = 0; 1587d4bc0535SKrishna Elango comp_array[i++] = "NAME=PCIe switch/bridge PM"; 1588d4bc0535SKrishna Elango comp_array[i++] = "0=Power Off (D3)"; 1589d4bc0535SKrishna Elango if (pwr_p->pwr_pmcaps & PCIE_SUPPORTS_D2) 1590d4bc0535SKrishna Elango comp_array[i++] = "1=D2"; 1591d4bc0535SKrishna Elango if (pwr_p->pwr_pmcaps & PCIE_SUPPORTS_D1) 1592d4bc0535SKrishna Elango comp_array[i++] = "2=D1"; 1593d4bc0535SKrishna Elango comp_array[i++] = "3=Full Power D0"; 1594d4bc0535SKrishna Elango 1595d4bc0535SKrishna Elango /* 1596d4bc0535SKrishna Elango * Create pm-components property, if it does not exist already. 1597d4bc0535SKrishna Elango */ 1598d4bc0535SKrishna Elango if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 1599d4bc0535SKrishna Elango "pm-components", comp_array, i) != DDI_PROP_SUCCESS) { 1600d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, dip, "could not create pm-components " 1601d4bc0535SKrishna Elango " prop\n"); 1602d4bc0535SKrishna Elango pci_config_teardown(&conf_hdl); 1603d4bc0535SKrishna Elango return (DDI_FAILURE); 1604d4bc0535SKrishna Elango } 1605d4bc0535SKrishna Elango return (pcieb_pwr_init_and_raise(dip, pwr_p)); 1606d4bc0535SKrishna Elango } 1607d4bc0535SKrishna Elango 1608d4bc0535SKrishna Elango /* 1609d4bc0535SKrishna Elango * undo whatever is done in pcieb_pwr_setup. called by pcieb_detach() 1610d4bc0535SKrishna Elango */ 1611d4bc0535SKrishna Elango static void 1612d4bc0535SKrishna Elango pcieb_pwr_teardown(dev_info_t *dip) 1613d4bc0535SKrishna Elango { 1614d4bc0535SKrishna Elango pcie_pwr_t *pwr_p; 1615d4bc0535SKrishna Elango 1616d4bc0535SKrishna Elango if (!PCIE_PMINFO(dip) || !(pwr_p = PCIE_NEXUS_PMINFO(dip))) 1617d4bc0535SKrishna Elango return; 1618d4bc0535SKrishna Elango 1619d4bc0535SKrishna Elango (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "pm-components"); 1620d4bc0535SKrishna Elango if (pwr_p->pwr_conf_hdl) 1621d4bc0535SKrishna Elango pci_config_teardown(&pwr_p->pwr_conf_hdl); 1622d4bc0535SKrishna Elango } 1623d4bc0535SKrishna Elango 1624d4bc0535SKrishna Elango /* 1625d4bc0535SKrishna Elango * Initializes the power level and raise the power to D0, if it is 1626d4bc0535SKrishna Elango * not at D0. 1627d4bc0535SKrishna Elango */ 1628d4bc0535SKrishna Elango static int 1629d4bc0535SKrishna Elango pcieb_pwr_init_and_raise(dev_info_t *dip, pcie_pwr_t *pwr_p) 1630d4bc0535SKrishna Elango { 1631d4bc0535SKrishna Elango uint16_t pmcsr; 1632d4bc0535SKrishna Elango int ret = DDI_SUCCESS; 1633d4bc0535SKrishna Elango 1634d4bc0535SKrishna Elango /* 1635d4bc0535SKrishna Elango * Intialize our power level from PMCSR. The common code initializes 1636d4bc0535SKrishna Elango * this to UNKNOWN. There is no guarantee that we will be at full 1637d4bc0535SKrishna Elango * power at attach. If we are not at D0, raise the power. 1638d4bc0535SKrishna Elango */ 1639d4bc0535SKrishna Elango pmcsr = pci_config_get16(pwr_p->pwr_conf_hdl, pwr_p->pwr_pmcsr_offset); 1640d4bc0535SKrishna Elango pmcsr &= PCI_PMCSR_STATE_MASK; 1641d4bc0535SKrishna Elango switch (pmcsr) { 1642d4bc0535SKrishna Elango case PCI_PMCSR_D0: 1643d4bc0535SKrishna Elango pwr_p->pwr_func_lvl = PM_LEVEL_D0; 1644d4bc0535SKrishna Elango break; 1645d4bc0535SKrishna Elango 1646d4bc0535SKrishna Elango case PCI_PMCSR_D1: 1647d4bc0535SKrishna Elango pwr_p->pwr_func_lvl = PM_LEVEL_D1; 1648d4bc0535SKrishna Elango break; 1649d4bc0535SKrishna Elango 1650d4bc0535SKrishna Elango case PCI_PMCSR_D2: 1651d4bc0535SKrishna Elango pwr_p->pwr_func_lvl = PM_LEVEL_D2; 1652d4bc0535SKrishna Elango break; 1653d4bc0535SKrishna Elango 1654d4bc0535SKrishna Elango case PCI_PMCSR_D3HOT: 1655d4bc0535SKrishna Elango pwr_p->pwr_func_lvl = PM_LEVEL_D3; 1656d4bc0535SKrishna Elango break; 1657d4bc0535SKrishna Elango 1658d4bc0535SKrishna Elango default: 1659d4bc0535SKrishna Elango break; 1660d4bc0535SKrishna Elango } 1661d4bc0535SKrishna Elango 1662d4bc0535SKrishna Elango /* Raise the power to D0. */ 1663d4bc0535SKrishna Elango if (pwr_p->pwr_func_lvl != PM_LEVEL_D0 && 1664d4bc0535SKrishna Elango ((ret = pm_raise_power(dip, 0, PM_LEVEL_D0)) != DDI_SUCCESS)) { 1665d4bc0535SKrishna Elango /* 1666d4bc0535SKrishna Elango * Read PMCSR again. If it is at D0, ignore the return 1667d4bc0535SKrishna Elango * value from pm_raise_power. 1668d4bc0535SKrishna Elango */ 1669d4bc0535SKrishna Elango pmcsr = pci_config_get16(pwr_p->pwr_conf_hdl, 1670d4bc0535SKrishna Elango pwr_p->pwr_pmcsr_offset); 1671d4bc0535SKrishna Elango if ((pmcsr & PCI_PMCSR_STATE_MASK) == PCI_PMCSR_D0) 1672d4bc0535SKrishna Elango ret = DDI_SUCCESS; 1673d4bc0535SKrishna Elango else { 1674d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_setup: could not " 1675d4bc0535SKrishna Elango "raise power to D0 \n"); 1676d4bc0535SKrishna Elango } 1677d4bc0535SKrishna Elango } 1678d4bc0535SKrishna Elango if (ret == DDI_SUCCESS) 1679d4bc0535SKrishna Elango pwr_p->pwr_func_lvl = PM_LEVEL_D0; 1680d4bc0535SKrishna Elango return (ret); 1681d4bc0535SKrishna Elango } 1682d4bc0535SKrishna Elango 1683d4bc0535SKrishna Elango /* 1684d4bc0535SKrishna Elango * Disable PM for x86 and PLX 8532 switch. 1685d4bc0535SKrishna Elango * For PLX Transitioning one port on this switch to low power causes links 1686d4bc0535SKrishna Elango * on other ports on the same station to die. Due to PLX erratum #34, we 1687d4bc0535SKrishna Elango * can't allow the downstream device go to non-D0 state. 1688d4bc0535SKrishna Elango */ 1689d4bc0535SKrishna Elango static int 1690d4bc0535SKrishna Elango pcieb_pwr_disable(dev_info_t *dip) 1691d4bc0535SKrishna Elango { 1692d4bc0535SKrishna Elango pcie_pwr_t *pwr_p; 1693d4bc0535SKrishna Elango 1694d4bc0535SKrishna Elango ASSERT(PCIE_PMINFO(dip)); 1695d4bc0535SKrishna Elango pwr_p = PCIE_NEXUS_PMINFO(dip); 1696d4bc0535SKrishna Elango ASSERT(pwr_p); 1697d4bc0535SKrishna Elango PCIEB_DEBUG(DBG_PWR, dip, "pcieb_pwr_disable: disabling PM\n"); 1698d4bc0535SKrishna Elango pwr_p->pwr_func_lvl = PM_LEVEL_D0; 1699d4bc0535SKrishna Elango pwr_p->pwr_flags = PCIE_NO_CHILD_PM; 1700d4bc0535SKrishna Elango return (DDI_SUCCESS); 1701d4bc0535SKrishna Elango } 1702d4bc0535SKrishna Elango 1703d4bc0535SKrishna Elango #ifdef DEBUG 1704d4bc0535SKrishna Elango int pcieb_dbg_intr_print = 0; 1705d4bc0535SKrishna Elango void 1706d4bc0535SKrishna Elango pcieb_dbg(uint_t bit, dev_info_t *dip, char *fmt, ...) 1707d4bc0535SKrishna Elango { 1708d4bc0535SKrishna Elango va_list ap; 1709d4bc0535SKrishna Elango 1710d4bc0535SKrishna Elango if (!pcieb_dbg_print) 1711d4bc0535SKrishna Elango return; 1712d4bc0535SKrishna Elango 1713d4bc0535SKrishna Elango if (dip) 1714d4bc0535SKrishna Elango prom_printf("%s(%d): %s", ddi_driver_name(dip), 1715d4bc0535SKrishna Elango ddi_get_instance(dip), pcieb_debug_sym[bit]); 1716d4bc0535SKrishna Elango 1717d4bc0535SKrishna Elango va_start(ap, fmt); 1718d4bc0535SKrishna Elango if (servicing_interrupt()) { 1719d4bc0535SKrishna Elango if (pcieb_dbg_intr_print) 1720d4bc0535SKrishna Elango prom_vprintf(fmt, ap); 1721d4bc0535SKrishna Elango } else { 1722d4bc0535SKrishna Elango prom_vprintf(fmt, ap); 1723d4bc0535SKrishna Elango } 1724d4bc0535SKrishna Elango 1725d4bc0535SKrishna Elango va_end(ap); 1726d4bc0535SKrishna Elango } 1727d4bc0535SKrishna Elango #endif 1728d4bc0535SKrishna Elango 1729d4bc0535SKrishna Elango static void 1730d4bc0535SKrishna Elango pcieb_id_props(pcieb_devstate_t *pcieb) 1731d4bc0535SKrishna Elango { 1732d4bc0535SKrishna Elango uint64_t serialid = 0; /* 40b field of EUI-64 serial no. register */ 1733d4bc0535SKrishna Elango uint16_t cap_ptr; 1734d4bc0535SKrishna Elango uint8_t fic = 0; /* 1 = first in chassis device */ 1735d4bc0535SKrishna Elango pcie_bus_t *bus_p = PCIE_DIP2BUS(pcieb->pcieb_dip); 1736d4bc0535SKrishna Elango ddi_acc_handle_t config_handle = bus_p->bus_cfg_hdl; 1737d4bc0535SKrishna Elango 1738d4bc0535SKrishna Elango /* 1739d4bc0535SKrishna Elango * Identify first in chassis. In the special case of a Sun branded 1740d4bc0535SKrishna Elango * PLX device, it obviously is first in chassis. Otherwise, in the 1741d4bc0535SKrishna Elango * general case, look for an Expansion Slot Register and check its 1742d4bc0535SKrishna Elango * first-in-chassis bit. 1743d4bc0535SKrishna Elango */ 1744d4bc0535SKrishna Elango #ifdef PX_PLX 1745d4bc0535SKrishna Elango uint16_t vendor_id = bus_p->bus_dev_ven_id & 0xFFFF; 1746d4bc0535SKrishna Elango uint16_t device_id = bus_p->bus_dev_ven_id >> 16; 1747d4bc0535SKrishna Elango if ((vendor_id == PXB_VENDOR_SUN) && 1748d4bc0535SKrishna Elango ((device_id == PXB_DEVICE_PLX_PCIX) || 1749d4bc0535SKrishna Elango (device_id == PXB_DEVICE_PLX_PCIE))) { 1750d4bc0535SKrishna Elango fic = 1; 1751d4bc0535SKrishna Elango } 1752d4bc0535SKrishna Elango #endif /* PX_PLX */ 1753d4bc0535SKrishna Elango if ((fic == 0) && ((PCI_CAP_LOCATE(config_handle, 1754d4bc0535SKrishna Elango PCI_CAP_ID_SLOT_ID, &cap_ptr)) != DDI_FAILURE)) { 1755d4bc0535SKrishna Elango uint8_t esr = PCI_CAP_GET8(config_handle, NULL, 1756d4bc0535SKrishna Elango cap_ptr, PCI_CAP_ID_REGS_OFF); 1757d4bc0535SKrishna Elango if (PCI_CAPSLOT_FIC(esr)) 1758d4bc0535SKrishna Elango fic = 1; 1759d4bc0535SKrishna Elango } 1760d4bc0535SKrishna Elango 1761d4bc0535SKrishna Elango if ((PCI_CAP_LOCATE(config_handle, 1762d4bc0535SKrishna Elango PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_SER), &cap_ptr)) != DDI_FAILURE) { 1763d4bc0535SKrishna Elango /* Serialid can be 0 thru a full 40b number */ 1764d4bc0535SKrishna Elango serialid = PCI_XCAP_GET32(config_handle, NULL, 1765d4bc0535SKrishna Elango cap_ptr, PCIE_SER_SID_UPPER_DW); 1766d4bc0535SKrishna Elango serialid <<= 32; 1767d4bc0535SKrishna Elango serialid |= PCI_XCAP_GET32(config_handle, NULL, 1768d4bc0535SKrishna Elango cap_ptr, PCIE_SER_SID_LOWER_DW); 1769d4bc0535SKrishna Elango } 1770d4bc0535SKrishna Elango 1771d4bc0535SKrishna Elango if (fic) 1772d4bc0535SKrishna Elango (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, pcieb->pcieb_dip, 1773d4bc0535SKrishna Elango "first-in-chassis"); 1774d4bc0535SKrishna Elango if (serialid) 1775d4bc0535SKrishna Elango (void) ddi_prop_update_int64(DDI_DEV_T_NONE, pcieb->pcieb_dip, 1776d4bc0535SKrishna Elango "serialid#", serialid); 1777d4bc0535SKrishna Elango } 1778d4bc0535SKrishna Elango 1779d4bc0535SKrishna Elango static void 1780d4bc0535SKrishna Elango pcieb_create_ranges_prop(dev_info_t *dip, 1781d4bc0535SKrishna Elango ddi_acc_handle_t config_handle) 1782d4bc0535SKrishna Elango { 1783d4bc0535SKrishna Elango uint32_t base, limit; 178426947304SEvan Yan ppb_ranges_t ranges[PCIEB_RANGE_LEN]; 1785d4bc0535SKrishna Elango uint8_t io_base_lo, io_limit_lo; 1786d4bc0535SKrishna Elango uint16_t io_base_hi, io_limit_hi, mem_base, mem_limit; 178726947304SEvan Yan int i = 0, rangelen = sizeof (ppb_ranges_t)/sizeof (int); 1788d4bc0535SKrishna Elango 1789d4bc0535SKrishna Elango io_base_lo = pci_config_get8(config_handle, PCI_BCNF_IO_BASE_LOW); 1790d4bc0535SKrishna Elango io_limit_lo = pci_config_get8(config_handle, PCI_BCNF_IO_LIMIT_LOW); 1791d4bc0535SKrishna Elango io_base_hi = pci_config_get16(config_handle, PCI_BCNF_IO_BASE_HI); 1792d4bc0535SKrishna Elango io_limit_hi = pci_config_get16(config_handle, PCI_BCNF_IO_LIMIT_HI); 1793d4bc0535SKrishna Elango mem_base = pci_config_get16(config_handle, PCI_BCNF_MEM_BASE); 1794d4bc0535SKrishna Elango mem_limit = pci_config_get16(config_handle, PCI_BCNF_MEM_LIMIT); 1795d4bc0535SKrishna Elango 1796d4bc0535SKrishna Elango /* 1797d4bc0535SKrishna Elango * Create ranges for IO space 1798d4bc0535SKrishna Elango */ 1799d4bc0535SKrishna Elango ranges[i].size_low = ranges[i].size_high = 0; 1800d4bc0535SKrishna Elango ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0; 1801d4bc0535SKrishna Elango ranges[i].child_high = ranges[i].parent_high |= 1802d4bc0535SKrishna Elango (PCI_REG_REL_M | PCI_ADDR_IO); 1803d4bc0535SKrishna Elango base = PCIEB_16bit_IOADDR(io_base_lo); 1804d4bc0535SKrishna Elango limit = PCIEB_16bit_IOADDR(io_limit_lo); 1805d4bc0535SKrishna Elango 1806d4bc0535SKrishna Elango if ((io_base_lo & 0xf) == PCIEB_32BIT_IO) { 1807d4bc0535SKrishna Elango base = PCIEB_LADDR(base, io_base_hi); 1808d4bc0535SKrishna Elango } 1809d4bc0535SKrishna Elango if ((io_limit_lo & 0xf) == PCIEB_32BIT_IO) { 1810d4bc0535SKrishna Elango limit = PCIEB_LADDR(limit, io_limit_hi); 1811d4bc0535SKrishna Elango } 1812d4bc0535SKrishna Elango 1813d4bc0535SKrishna Elango if ((io_base_lo & PCIEB_32BIT_IO) && (io_limit_hi > 0)) { 1814d4bc0535SKrishna Elango base = PCIEB_LADDR(base, io_base_hi); 1815d4bc0535SKrishna Elango limit = PCIEB_LADDR(limit, io_limit_hi); 1816d4bc0535SKrishna Elango } 1817d4bc0535SKrishna Elango 1818d4bc0535SKrishna Elango /* 1819d4bc0535SKrishna Elango * Create ranges for 32bit memory space 1820d4bc0535SKrishna Elango */ 1821d4bc0535SKrishna Elango base = PCIEB_32bit_MEMADDR(mem_base); 1822d4bc0535SKrishna Elango limit = PCIEB_32bit_MEMADDR(mem_limit); 1823d4bc0535SKrishna Elango ranges[i].size_low = ranges[i].size_high = 0; 1824d4bc0535SKrishna Elango ranges[i].parent_mid = ranges[i].child_mid = ranges[i].parent_high = 0; 1825d4bc0535SKrishna Elango ranges[i].child_high = ranges[i].parent_high |= 1826d4bc0535SKrishna Elango (PCI_REG_REL_M | PCI_ADDR_MEM32); 1827d4bc0535SKrishna Elango ranges[i].child_low = ranges[i].parent_low = base; 1828d4bc0535SKrishna Elango if (limit >= base) { 1829d4bc0535SKrishna Elango ranges[i].size_low = limit - base + PCIEB_MEMGRAIN; 1830d4bc0535SKrishna Elango i++; 1831d4bc0535SKrishna Elango } 1832d4bc0535SKrishna Elango 1833d4bc0535SKrishna Elango if (i) { 1834d4bc0535SKrishna Elango (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges", 1835d4bc0535SKrishna Elango (int *)ranges, i * rangelen); 1836d4bc0535SKrishna Elango } 1837d4bc0535SKrishna Elango } 1838d4bc0535SKrishna Elango 1839d4bc0535SKrishna Elango /* 1840d4bc0535SKrishna Elango * For PCI and PCI-X devices including PCIe2PCI bridge, initialize 1841d4bc0535SKrishna Elango * cache-line-size and latency timer configuration registers. 1842d4bc0535SKrishna Elango */ 1843d4bc0535SKrishna Elango void 1844d4bc0535SKrishna Elango pcieb_set_pci_perf_parameters(dev_info_t *dip, ddi_acc_handle_t cfg_hdl) 1845d4bc0535SKrishna Elango { 1846d4bc0535SKrishna Elango uint_t n; 1847d4bc0535SKrishna Elango 1848d4bc0535SKrishna Elango /* Initialize cache-line-size configuration register if needed */ 1849d4bc0535SKrishna Elango if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1850d4bc0535SKrishna Elango "cache-line-size", 0) == 0) { 1851d4bc0535SKrishna Elango pci_config_put8(cfg_hdl, PCI_CONF_CACHE_LINESZ, 1852d4bc0535SKrishna Elango PCIEB_CACHE_LINE_SIZE); 1853d4bc0535SKrishna Elango n = pci_config_get8(cfg_hdl, PCI_CONF_CACHE_LINESZ); 1854d4bc0535SKrishna Elango if (n != 0) { 1855d4bc0535SKrishna Elango (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 1856d4bc0535SKrishna Elango "cache-line-size", n); 1857d4bc0535SKrishna Elango } 1858d4bc0535SKrishna Elango } 1859d4bc0535SKrishna Elango 1860d4bc0535SKrishna Elango /* Initialize latency timer configuration registers if needed */ 1861d4bc0535SKrishna Elango if (ddi_getprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1862d4bc0535SKrishna Elango "latency-timer", 0) == 0) { 1863d4bc0535SKrishna Elango uchar_t min_gnt, latency_timer; 1864d4bc0535SKrishna Elango uchar_t header_type; 1865d4bc0535SKrishna Elango 1866d4bc0535SKrishna Elango /* Determine the configuration header type */ 1867d4bc0535SKrishna Elango header_type = pci_config_get8(cfg_hdl, PCI_CONF_HEADER); 1868d4bc0535SKrishna Elango 1869d4bc0535SKrishna Elango if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) { 1870d4bc0535SKrishna Elango latency_timer = PCIEB_LATENCY_TIMER; 1871d4bc0535SKrishna Elango pci_config_put8(cfg_hdl, PCI_BCNF_LATENCY_TIMER, 1872d4bc0535SKrishna Elango latency_timer); 1873d4bc0535SKrishna Elango } else { 1874d4bc0535SKrishna Elango min_gnt = pci_config_get8(cfg_hdl, PCI_CONF_MIN_G); 1875d4bc0535SKrishna Elango latency_timer = min_gnt * 8; 1876d4bc0535SKrishna Elango } 1877d4bc0535SKrishna Elango 1878d4bc0535SKrishna Elango pci_config_put8(cfg_hdl, PCI_CONF_LATENCY_TIMER, 1879d4bc0535SKrishna Elango latency_timer); 1880d4bc0535SKrishna Elango n = pci_config_get8(cfg_hdl, PCI_CONF_LATENCY_TIMER); 1881d4bc0535SKrishna Elango if (n != 0) { 1882d4bc0535SKrishna Elango (void) ndi_prop_update_int(DDI_DEV_T_NONE, dip, 1883d4bc0535SKrishna Elango "latency-timer", n); 1884d4bc0535SKrishna Elango } 1885d4bc0535SKrishna Elango } 1886d4bc0535SKrishna Elango } 1887