110187SKrishna.Elango@Sun.COM /*
210187SKrishna.Elango@Sun.COM * CDDL HEADER START
310187SKrishna.Elango@Sun.COM *
410187SKrishna.Elango@Sun.COM * The contents of this file are subject to the terms of the
510187SKrishna.Elango@Sun.COM * Common Development and Distribution License (the "License").
610187SKrishna.Elango@Sun.COM * You may not use this file except in compliance with the License.
710187SKrishna.Elango@Sun.COM *
810187SKrishna.Elango@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910187SKrishna.Elango@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010187SKrishna.Elango@Sun.COM * See the License for the specific language governing permissions
1110187SKrishna.Elango@Sun.COM * and limitations under the License.
1210187SKrishna.Elango@Sun.COM *
1310187SKrishna.Elango@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410187SKrishna.Elango@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510187SKrishna.Elango@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610187SKrishna.Elango@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710187SKrishna.Elango@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810187SKrishna.Elango@Sun.COM *
1910187SKrishna.Elango@Sun.COM * CDDL HEADER END
2010187SKrishna.Elango@Sun.COM */
2112059SAlan.Adamson@Sun.COM
2210187SKrishna.Elango@Sun.COM /*
2312330SDaniel.Ice@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2410187SKrishna.Elango@Sun.COM */
2510187SKrishna.Elango@Sun.COM
2610187SKrishna.Elango@Sun.COM #include <sys/sysmacros.h>
2710187SKrishna.Elango@Sun.COM #include <sys/types.h>
2810187SKrishna.Elango@Sun.COM #include <sys/kmem.h>
2910187SKrishna.Elango@Sun.COM #include <sys/modctl.h>
3010187SKrishna.Elango@Sun.COM #include <sys/ddi.h>
3110187SKrishna.Elango@Sun.COM #include <sys/sunddi.h>
3210187SKrishna.Elango@Sun.COM #include <sys/sunndi.h>
3310187SKrishna.Elango@Sun.COM #include <sys/fm/protocol.h>
3410187SKrishna.Elango@Sun.COM #include <sys/fm/util.h>
3510187SKrishna.Elango@Sun.COM #include <sys/promif.h>
3610187SKrishna.Elango@Sun.COM #include <sys/disp.h>
3710923SEvan.Yan@Sun.COM #include <sys/stat.h>
3810923SEvan.Yan@Sun.COM #include <sys/file.h>
3910187SKrishna.Elango@Sun.COM #include <sys/pci_cap.h>
4010923SEvan.Yan@Sun.COM #include <sys/pci_impl.h>
4110187SKrishna.Elango@Sun.COM #include <sys/pcie_impl.h>
4210923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcie_hp.h>
4311445SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pciehpc.h>
4411445SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcishpc.h>
4510923SEvan.Yan@Sun.COM #include <sys/hotplug/pci/pcicfg.h>
4611245SZhijun.Fu@Sun.COM #include <sys/pci_cfgacc.h>
4710187SKrishna.Elango@Sun.COM
4810923SEvan.Yan@Sun.COM /* Local functions prototypes */
4910187SKrishna.Elango@Sun.COM static void pcie_init_pfd(dev_info_t *);
5010187SKrishna.Elango@Sun.COM static void pcie_fini_pfd(dev_info_t *);
5110187SKrishna.Elango@Sun.COM
5210187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64)
5310187SKrishna.Elango@Sun.COM static void pcie_check_io_mem_range(ddi_acc_handle_t, boolean_t *, boolean_t *);
5410187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */
5510187SKrishna.Elango@Sun.COM
5610187SKrishna.Elango@Sun.COM #ifdef DEBUG
5710187SKrishna.Elango@Sun.COM uint_t pcie_debug_flags = 0;
5810187SKrishna.Elango@Sun.COM static void pcie_print_bus(pcie_bus_t *bus_p);
5910923SEvan.Yan@Sun.COM void pcie_dbg(char *fmt, ...);
6010187SKrishna.Elango@Sun.COM #endif /* DEBUG */
6110187SKrishna.Elango@Sun.COM
6210187SKrishna.Elango@Sun.COM /* Variable to control default PCI-Express config settings */
6310187SKrishna.Elango@Sun.COM ushort_t pcie_command_default =
6410187SKrishna.Elango@Sun.COM PCI_COMM_SERR_ENABLE |
6510187SKrishna.Elango@Sun.COM PCI_COMM_WAIT_CYC_ENAB |
6610187SKrishna.Elango@Sun.COM PCI_COMM_PARITY_DETECT |
6710187SKrishna.Elango@Sun.COM PCI_COMM_ME |
6810187SKrishna.Elango@Sun.COM PCI_COMM_MAE |
6910187SKrishna.Elango@Sun.COM PCI_COMM_IO;
7010187SKrishna.Elango@Sun.COM
7110187SKrishna.Elango@Sun.COM /* xxx_fw are bits that are controlled by FW and should not be modified */
7210187SKrishna.Elango@Sun.COM ushort_t pcie_command_default_fw =
7310187SKrishna.Elango@Sun.COM PCI_COMM_SPEC_CYC |
7410187SKrishna.Elango@Sun.COM PCI_COMM_MEMWR_INVAL |
7510187SKrishna.Elango@Sun.COM PCI_COMM_PALETTE_SNOOP |
7610187SKrishna.Elango@Sun.COM PCI_COMM_WAIT_CYC_ENAB |
7710187SKrishna.Elango@Sun.COM 0xF800; /* Reserved Bits */
7810187SKrishna.Elango@Sun.COM
7910187SKrishna.Elango@Sun.COM ushort_t pcie_bdg_command_default_fw =
8010187SKrishna.Elango@Sun.COM PCI_BCNF_BCNTRL_ISA_ENABLE |
8110187SKrishna.Elango@Sun.COM PCI_BCNF_BCNTRL_VGA_ENABLE |
8210187SKrishna.Elango@Sun.COM 0xF000; /* Reserved Bits */
8310187SKrishna.Elango@Sun.COM
8410187SKrishna.Elango@Sun.COM /* PCI-Express Base error defaults */
8510187SKrishna.Elango@Sun.COM ushort_t pcie_base_err_default =
8610187SKrishna.Elango@Sun.COM PCIE_DEVCTL_CE_REPORTING_EN |
8710187SKrishna.Elango@Sun.COM PCIE_DEVCTL_NFE_REPORTING_EN |
8810187SKrishna.Elango@Sun.COM PCIE_DEVCTL_FE_REPORTING_EN |
8910187SKrishna.Elango@Sun.COM PCIE_DEVCTL_UR_REPORTING_EN;
9010187SKrishna.Elango@Sun.COM
9110187SKrishna.Elango@Sun.COM /* PCI-Express Device Control Register */
9210187SKrishna.Elango@Sun.COM uint16_t pcie_devctl_default = PCIE_DEVCTL_RO_EN |
9310187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_READ_REQ_512;
9410187SKrishna.Elango@Sun.COM
9510187SKrishna.Elango@Sun.COM /* PCI-Express AER Root Control Register */
9610187SKrishna.Elango@Sun.COM #define PCIE_ROOT_SYS_ERR (PCIE_ROOTCTL_SYS_ERR_ON_CE_EN | \
9710187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN | \
9810187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_FE_EN)
9910187SKrishna.Elango@Sun.COM
10010187SKrishna.Elango@Sun.COM ushort_t pcie_root_ctrl_default =
10110187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_CE_EN |
10210187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_NFE_EN |
10310187SKrishna.Elango@Sun.COM PCIE_ROOTCTL_SYS_ERR_ON_FE_EN;
10410187SKrishna.Elango@Sun.COM
10510187SKrishna.Elango@Sun.COM /* PCI-Express Root Error Command Register */
10610187SKrishna.Elango@Sun.COM ushort_t pcie_root_error_cmd_default =
10710187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_CE_REP_EN |
10810187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_NFE_REP_EN |
10910187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD_FE_REP_EN;
11010187SKrishna.Elango@Sun.COM
11110187SKrishna.Elango@Sun.COM /* ECRC settings in the PCIe AER Control Register */
11210187SKrishna.Elango@Sun.COM uint32_t pcie_ecrc_value =
11310187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_GEN_ENA |
11410187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_CHECK_ENA;
11510187SKrishna.Elango@Sun.COM
11610187SKrishna.Elango@Sun.COM /*
11710187SKrishna.Elango@Sun.COM * If a particular platform wants to disable certain errors such as UR/MA,
11810187SKrishna.Elango@Sun.COM * instead of using #defines have the platform's PCIe Root Complex driver set
11910187SKrishna.Elango@Sun.COM * these masks using the pcie_get_XXX_mask and pcie_set_XXX_mask functions. For
12010923SEvan.Yan@Sun.COM * x86 the closest thing to a PCIe root complex driver is NPE. For SPARC the
12110187SKrishna.Elango@Sun.COM * closest PCIe root complex driver is PX.
12210187SKrishna.Elango@Sun.COM *
12310187SKrishna.Elango@Sun.COM * pcie_serr_disable_flag : disable SERR only (in RCR and command reg) x86
12410187SKrishna.Elango@Sun.COM * systems may want to disable SERR in general. For root ports, enabling SERR
12510187SKrishna.Elango@Sun.COM * causes NMIs which are not handled and results in a watchdog timeout error.
12610187SKrishna.Elango@Sun.COM */
12710187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_mask = 0; /* AER UE Mask */
12810187SKrishna.Elango@Sun.COM uint32_t pcie_aer_ce_mask = 0; /* AER CE Mask */
12910187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_mask = 0; /* AER Secondary UE Mask */
13010187SKrishna.Elango@Sun.COM uint32_t pcie_serr_disable_flag = 0; /* Disable SERR */
13110187SKrishna.Elango@Sun.COM
13210187SKrishna.Elango@Sun.COM /* Default severities needed for eversholt. Error handling doesn't care */
13310187SKrishna.Elango@Sun.COM uint32_t pcie_aer_uce_severity = PCIE_AER_UCE_MTLP | PCIE_AER_UCE_RO | \
13410187SKrishna.Elango@Sun.COM PCIE_AER_UCE_FCP | PCIE_AER_UCE_SD | PCIE_AER_UCE_DLP | \
13510187SKrishna.Elango@Sun.COM PCIE_AER_UCE_TRAINING;
13610187SKrishna.Elango@Sun.COM uint32_t pcie_aer_suce_severity = PCIE_AER_SUCE_SERR_ASSERT | \
13710187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_UC_ADDR_ERR | PCIE_AER_SUCE_UC_ATTR_ERR | \
13810187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_USC_MSG_DATA_ERR;
13910187SKrishna.Elango@Sun.COM
14010187SKrishna.Elango@Sun.COM int pcie_max_mps = PCIE_DEVCTL_MAX_PAYLOAD_4096 >> 5;
14110923SEvan.Yan@Sun.COM int pcie_disable_ari = 0;
14210187SKrishna.Elango@Sun.COM
14310187SKrishna.Elango@Sun.COM static void pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip,
14410187SKrishna.Elango@Sun.COM int *max_supported);
14510187SKrishna.Elango@Sun.COM static int pcie_get_max_supported(dev_info_t *dip, void *arg);
14610187SKrishna.Elango@Sun.COM static int pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
14710187SKrishna.Elango@Sun.COM caddr_t *addrp, ddi_acc_handle_t *handlep);
14810923SEvan.Yan@Sun.COM static void pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph);
14910187SKrishna.Elango@Sun.COM
15011245SZhijun.Fu@Sun.COM dev_info_t *pcie_get_rc_dip(dev_info_t *dip);
15111245SZhijun.Fu@Sun.COM
15210187SKrishna.Elango@Sun.COM /*
15310187SKrishna.Elango@Sun.COM * modload support
15410187SKrishna.Elango@Sun.COM */
15510187SKrishna.Elango@Sun.COM
15610187SKrishna.Elango@Sun.COM static struct modlmisc modlmisc = {
15710187SKrishna.Elango@Sun.COM &mod_miscops, /* Type of module */
15810923SEvan.Yan@Sun.COM "PCI Express Framework Module"
15910187SKrishna.Elango@Sun.COM };
16010187SKrishna.Elango@Sun.COM
16110187SKrishna.Elango@Sun.COM static struct modlinkage modlinkage = {
16210187SKrishna.Elango@Sun.COM MODREV_1,
16310187SKrishna.Elango@Sun.COM (void *)&modlmisc,
16410187SKrishna.Elango@Sun.COM NULL
16510187SKrishna.Elango@Sun.COM };
16610187SKrishna.Elango@Sun.COM
16710187SKrishna.Elango@Sun.COM /*
16810187SKrishna.Elango@Sun.COM * Global Variables needed for a non-atomic version of ddi_fm_ereport_post.
16910187SKrishna.Elango@Sun.COM * Currently used to send the pci.fabric ereports whose payload depends on the
17010187SKrishna.Elango@Sun.COM * type of PCI device it is being sent for.
17110187SKrishna.Elango@Sun.COM */
17210187SKrishna.Elango@Sun.COM char *pcie_nv_buf;
17310187SKrishna.Elango@Sun.COM nv_alloc_t *pcie_nvap;
17410187SKrishna.Elango@Sun.COM nvlist_t *pcie_nvl;
17510187SKrishna.Elango@Sun.COM
17610187SKrishna.Elango@Sun.COM int
_init(void)17710187SKrishna.Elango@Sun.COM _init(void)
17810187SKrishna.Elango@Sun.COM {
17910187SKrishna.Elango@Sun.COM int rval;
18010187SKrishna.Elango@Sun.COM
18110187SKrishna.Elango@Sun.COM pcie_nv_buf = kmem_alloc(ERPT_DATA_SZ, KM_SLEEP);
18210187SKrishna.Elango@Sun.COM pcie_nvap = fm_nva_xcreate(pcie_nv_buf, ERPT_DATA_SZ);
18310187SKrishna.Elango@Sun.COM pcie_nvl = fm_nvlist_create(pcie_nvap);
18410187SKrishna.Elango@Sun.COM
185*12751SAn.Bui@Sun.COM if ((rval = mod_install(&modlinkage)) != 0) {
186*12751SAn.Bui@Sun.COM fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
187*12751SAn.Bui@Sun.COM fm_nva_xdestroy(pcie_nvap);
188*12751SAn.Bui@Sun.COM kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
189*12751SAn.Bui@Sun.COM }
19010187SKrishna.Elango@Sun.COM return (rval);
19110187SKrishna.Elango@Sun.COM }
19210187SKrishna.Elango@Sun.COM
19310187SKrishna.Elango@Sun.COM int
_fini()19410187SKrishna.Elango@Sun.COM _fini()
19510187SKrishna.Elango@Sun.COM {
19610187SKrishna.Elango@Sun.COM int rval;
19710187SKrishna.Elango@Sun.COM
198*12751SAn.Bui@Sun.COM if ((rval = mod_remove(&modlinkage)) == 0) {
199*12751SAn.Bui@Sun.COM fm_nvlist_destroy(pcie_nvl, FM_NVA_RETAIN);
200*12751SAn.Bui@Sun.COM fm_nva_xdestroy(pcie_nvap);
201*12751SAn.Bui@Sun.COM kmem_free(pcie_nv_buf, ERPT_DATA_SZ);
202*12751SAn.Bui@Sun.COM }
20310187SKrishna.Elango@Sun.COM return (rval);
20410187SKrishna.Elango@Sun.COM }
20510187SKrishna.Elango@Sun.COM
20610187SKrishna.Elango@Sun.COM int
_info(struct modinfo * modinfop)20710187SKrishna.Elango@Sun.COM _info(struct modinfo *modinfop)
20810187SKrishna.Elango@Sun.COM {
20910187SKrishna.Elango@Sun.COM return (mod_info(&modlinkage, modinfop));
21010187SKrishna.Elango@Sun.COM }
21110187SKrishna.Elango@Sun.COM
21210923SEvan.Yan@Sun.COM /* ARGSUSED */
21310923SEvan.Yan@Sun.COM int
pcie_init(dev_info_t * dip,caddr_t arg)21410923SEvan.Yan@Sun.COM pcie_init(dev_info_t *dip, caddr_t arg)
21510923SEvan.Yan@Sun.COM {
21610923SEvan.Yan@Sun.COM int ret = DDI_SUCCESS;
21710923SEvan.Yan@Sun.COM
21810923SEvan.Yan@Sun.COM /*
21910923SEvan.Yan@Sun.COM * Create a "devctl" minor node to support DEVCTL_DEVICE_*
22010923SEvan.Yan@Sun.COM * and DEVCTL_BUS_* ioctls to this bus.
22110923SEvan.Yan@Sun.COM */
22210923SEvan.Yan@Sun.COM if ((ret = ddi_create_minor_node(dip, "devctl", S_IFCHR,
22310923SEvan.Yan@Sun.COM PCI_MINOR_NUM(ddi_get_instance(dip), PCI_DEVCTL_MINOR),
22410923SEvan.Yan@Sun.COM DDI_NT_NEXUS, 0)) != DDI_SUCCESS) {
22510923SEvan.Yan@Sun.COM PCIE_DBG("Failed to create devctl minor node for %s%d\n",
22610923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip));
22710923SEvan.Yan@Sun.COM
22810923SEvan.Yan@Sun.COM return (ret);
22910923SEvan.Yan@Sun.COM }
23010923SEvan.Yan@Sun.COM
23110923SEvan.Yan@Sun.COM if ((ret = pcie_hp_init(dip, arg)) != DDI_SUCCESS) {
23210923SEvan.Yan@Sun.COM /*
23311366SColin.Zou@Sun.COM * On some x86 platforms, we observed unexpected hotplug
23411366SColin.Zou@Sun.COM * initialization failures in recent years. The known cause
23511366SColin.Zou@Sun.COM * is a hardware issue: while the problem PCI bridges have
23611366SColin.Zou@Sun.COM * the Hotplug Capable registers set, the machine actually
23711366SColin.Zou@Sun.COM * does not implement the expected ACPI object.
23811366SColin.Zou@Sun.COM *
23911366SColin.Zou@Sun.COM * We don't want to stop PCI driver attach and system boot
24011366SColin.Zou@Sun.COM * just because of this hotplug initialization failure.
24111366SColin.Zou@Sun.COM * Continue with a debug message printed.
24210923SEvan.Yan@Sun.COM */
24311366SColin.Zou@Sun.COM PCIE_DBG("%s%d: Failed setting hotplug framework\n",
24410923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip));
24510923SEvan.Yan@Sun.COM
24610923SEvan.Yan@Sun.COM #if defined(__sparc)
24710923SEvan.Yan@Sun.COM ddi_remove_minor_node(dip, "devctl");
24810923SEvan.Yan@Sun.COM
24910923SEvan.Yan@Sun.COM return (ret);
25010923SEvan.Yan@Sun.COM #endif /* defined(__sparc) */
25110923SEvan.Yan@Sun.COM }
25210923SEvan.Yan@Sun.COM
25310923SEvan.Yan@Sun.COM return (DDI_SUCCESS);
25410923SEvan.Yan@Sun.COM }
25510923SEvan.Yan@Sun.COM
25610923SEvan.Yan@Sun.COM /* ARGSUSED */
25710923SEvan.Yan@Sun.COM int
pcie_uninit(dev_info_t * dip)25810923SEvan.Yan@Sun.COM pcie_uninit(dev_info_t *dip)
25910923SEvan.Yan@Sun.COM {
26010923SEvan.Yan@Sun.COM int ret = DDI_SUCCESS;
26110923SEvan.Yan@Sun.COM
26210923SEvan.Yan@Sun.COM if (pcie_ari_is_enabled(dip) == PCIE_ARI_FORW_ENABLED)
26310923SEvan.Yan@Sun.COM (void) pcie_ari_disable(dip);
26410923SEvan.Yan@Sun.COM
26510923SEvan.Yan@Sun.COM if ((ret = pcie_hp_uninit(dip)) != DDI_SUCCESS) {
26610923SEvan.Yan@Sun.COM PCIE_DBG("Failed to uninitialize hotplug for %s%d\n",
26710923SEvan.Yan@Sun.COM ddi_driver_name(dip), ddi_get_instance(dip));
26810923SEvan.Yan@Sun.COM
26910923SEvan.Yan@Sun.COM return (ret);
27010923SEvan.Yan@Sun.COM }
27110923SEvan.Yan@Sun.COM
27210923SEvan.Yan@Sun.COM ddi_remove_minor_node(dip, "devctl");
27310923SEvan.Yan@Sun.COM
27410923SEvan.Yan@Sun.COM return (ret);
27510923SEvan.Yan@Sun.COM }
27610923SEvan.Yan@Sun.COM
27711445SEvan.Yan@Sun.COM /*
27811445SEvan.Yan@Sun.COM * PCIe module interface for enabling hotplug interrupt.
27911445SEvan.Yan@Sun.COM *
28011445SEvan.Yan@Sun.COM * It should be called after pcie_init() is done and bus driver's
28111445SEvan.Yan@Sun.COM * interrupt handlers have being attached.
28211445SEvan.Yan@Sun.COM */
28311445SEvan.Yan@Sun.COM int
pcie_hpintr_enable(dev_info_t * dip)28411445SEvan.Yan@Sun.COM pcie_hpintr_enable(dev_info_t *dip)
28511445SEvan.Yan@Sun.COM {
28611445SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
28711445SEvan.Yan@Sun.COM pcie_hp_ctrl_t *ctrl_p = PCIE_GET_HP_CTRL(dip);
28811445SEvan.Yan@Sun.COM
28911445SEvan.Yan@Sun.COM if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
29011445SEvan.Yan@Sun.COM (void) (ctrl_p->hc_ops.enable_hpc_intr)(ctrl_p);
29111445SEvan.Yan@Sun.COM } else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
29211445SEvan.Yan@Sun.COM (void) pcishpc_enable_irqs(ctrl_p);
29311445SEvan.Yan@Sun.COM }
29411445SEvan.Yan@Sun.COM return (DDI_SUCCESS);
29511445SEvan.Yan@Sun.COM }
29611445SEvan.Yan@Sun.COM
29711445SEvan.Yan@Sun.COM /*
29811445SEvan.Yan@Sun.COM * PCIe module interface for disabling hotplug interrupt.
29911445SEvan.Yan@Sun.COM *
30011445SEvan.Yan@Sun.COM * It should be called before pcie_uninit() is called and bus driver's
30111445SEvan.Yan@Sun.COM * interrupt handlers is dettached.
30211445SEvan.Yan@Sun.COM */
30311445SEvan.Yan@Sun.COM int
pcie_hpintr_disable(dev_info_t * dip)30411445SEvan.Yan@Sun.COM pcie_hpintr_disable(dev_info_t *dip)
30511445SEvan.Yan@Sun.COM {
30611445SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
30711445SEvan.Yan@Sun.COM pcie_hp_ctrl_t *ctrl_p = PCIE_GET_HP_CTRL(dip);
30811445SEvan.Yan@Sun.COM
30911445SEvan.Yan@Sun.COM if (PCIE_IS_PCIE_HOTPLUG_ENABLED(bus_p)) {
31011445SEvan.Yan@Sun.COM (void) (ctrl_p->hc_ops.disable_hpc_intr)(ctrl_p);
31111445SEvan.Yan@Sun.COM } else if (PCIE_IS_PCI_HOTPLUG_ENABLED(bus_p)) {
31211445SEvan.Yan@Sun.COM (void) pcishpc_disable_irqs(ctrl_p);
31311445SEvan.Yan@Sun.COM }
31411445SEvan.Yan@Sun.COM return (DDI_SUCCESS);
31511445SEvan.Yan@Sun.COM }
31611445SEvan.Yan@Sun.COM
31710923SEvan.Yan@Sun.COM /* ARGSUSED */
31810923SEvan.Yan@Sun.COM int
pcie_intr(dev_info_t * dip)31910923SEvan.Yan@Sun.COM pcie_intr(dev_info_t *dip)
32010923SEvan.Yan@Sun.COM {
32110923SEvan.Yan@Sun.COM return (pcie_hp_intr(dip));
32210923SEvan.Yan@Sun.COM }
32310923SEvan.Yan@Sun.COM
32410923SEvan.Yan@Sun.COM /* ARGSUSED */
32510923SEvan.Yan@Sun.COM int
pcie_open(dev_info_t * dip,dev_t * devp,int flags,int otyp,cred_t * credp)32610923SEvan.Yan@Sun.COM pcie_open(dev_info_t *dip, dev_t *devp, int flags, int otyp, cred_t *credp)
32710923SEvan.Yan@Sun.COM {
32810923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
32910923SEvan.Yan@Sun.COM
33010923SEvan.Yan@Sun.COM /*
33110923SEvan.Yan@Sun.COM * Make sure the open is for the right file type.
33210923SEvan.Yan@Sun.COM */
33310923SEvan.Yan@Sun.COM if (otyp != OTYP_CHR)
33410923SEvan.Yan@Sun.COM return (EINVAL);
33510923SEvan.Yan@Sun.COM
33610923SEvan.Yan@Sun.COM /*
33710923SEvan.Yan@Sun.COM * Handle the open by tracking the device state.
33810923SEvan.Yan@Sun.COM */
33910923SEvan.Yan@Sun.COM if ((bus_p->bus_soft_state == PCI_SOFT_STATE_OPEN_EXCL) ||
34010923SEvan.Yan@Sun.COM ((flags & FEXCL) &&
34110923SEvan.Yan@Sun.COM (bus_p->bus_soft_state != PCI_SOFT_STATE_CLOSED))) {
34210923SEvan.Yan@Sun.COM return (EBUSY);
34310923SEvan.Yan@Sun.COM }
34410923SEvan.Yan@Sun.COM
34510923SEvan.Yan@Sun.COM if (flags & FEXCL)
34610923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
34710923SEvan.Yan@Sun.COM else
34810923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_OPEN;
34910923SEvan.Yan@Sun.COM
35010923SEvan.Yan@Sun.COM return (0);
35110923SEvan.Yan@Sun.COM }
35210923SEvan.Yan@Sun.COM
35310923SEvan.Yan@Sun.COM /* ARGSUSED */
35410923SEvan.Yan@Sun.COM int
pcie_close(dev_info_t * dip,dev_t dev,int flags,int otyp,cred_t * credp)35510923SEvan.Yan@Sun.COM pcie_close(dev_info_t *dip, dev_t dev, int flags, int otyp, cred_t *credp)
35610923SEvan.Yan@Sun.COM {
35710923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
35810923SEvan.Yan@Sun.COM
35910923SEvan.Yan@Sun.COM if (otyp != OTYP_CHR)
36010923SEvan.Yan@Sun.COM return (EINVAL);
36110923SEvan.Yan@Sun.COM
36210923SEvan.Yan@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
36310923SEvan.Yan@Sun.COM
36410923SEvan.Yan@Sun.COM return (0);
36510923SEvan.Yan@Sun.COM }
36610923SEvan.Yan@Sun.COM
36710923SEvan.Yan@Sun.COM /* ARGSUSED */
36810923SEvan.Yan@Sun.COM int
pcie_ioctl(dev_info_t * dip,dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)36910923SEvan.Yan@Sun.COM pcie_ioctl(dev_info_t *dip, dev_t dev, int cmd, intptr_t arg, int mode,
37010923SEvan.Yan@Sun.COM cred_t *credp, int *rvalp)
37110923SEvan.Yan@Sun.COM {
37210923SEvan.Yan@Sun.COM struct devctl_iocdata *dcp;
37310923SEvan.Yan@Sun.COM uint_t bus_state;
37410923SEvan.Yan@Sun.COM int rv = DDI_SUCCESS;
37510923SEvan.Yan@Sun.COM
37610923SEvan.Yan@Sun.COM /*
37710923SEvan.Yan@Sun.COM * We can use the generic implementation for devctl ioctl
37810923SEvan.Yan@Sun.COM */
37910923SEvan.Yan@Sun.COM switch (cmd) {
38010923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_GETSTATE:
38110923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_ONLINE:
38210923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_OFFLINE:
38310923SEvan.Yan@Sun.COM case DEVCTL_BUS_GETSTATE:
38410923SEvan.Yan@Sun.COM return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
38510923SEvan.Yan@Sun.COM default:
38610923SEvan.Yan@Sun.COM break;
38710923SEvan.Yan@Sun.COM }
38810923SEvan.Yan@Sun.COM
38910923SEvan.Yan@Sun.COM /*
39010923SEvan.Yan@Sun.COM * read devctl ioctl data
39110923SEvan.Yan@Sun.COM */
39210923SEvan.Yan@Sun.COM if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
39310923SEvan.Yan@Sun.COM return (EFAULT);
39410923SEvan.Yan@Sun.COM
39510923SEvan.Yan@Sun.COM switch (cmd) {
39610923SEvan.Yan@Sun.COM case DEVCTL_BUS_QUIESCE:
39710923SEvan.Yan@Sun.COM if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
39810923SEvan.Yan@Sun.COM if (bus_state == BUS_QUIESCED)
39910923SEvan.Yan@Sun.COM break;
40010923SEvan.Yan@Sun.COM (void) ndi_set_bus_state(dip, BUS_QUIESCED);
40110923SEvan.Yan@Sun.COM break;
40210923SEvan.Yan@Sun.COM case DEVCTL_BUS_UNQUIESCE:
40310923SEvan.Yan@Sun.COM if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
40410923SEvan.Yan@Sun.COM if (bus_state == BUS_ACTIVE)
40510923SEvan.Yan@Sun.COM break;
40610923SEvan.Yan@Sun.COM (void) ndi_set_bus_state(dip, BUS_ACTIVE);
40710923SEvan.Yan@Sun.COM break;
40810923SEvan.Yan@Sun.COM case DEVCTL_BUS_RESET:
40910923SEvan.Yan@Sun.COM case DEVCTL_BUS_RESETALL:
41010923SEvan.Yan@Sun.COM case DEVCTL_DEVICE_RESET:
41110923SEvan.Yan@Sun.COM rv = ENOTSUP;
41210923SEvan.Yan@Sun.COM break;
41310923SEvan.Yan@Sun.COM default:
41410923SEvan.Yan@Sun.COM rv = ENOTTY;
41510923SEvan.Yan@Sun.COM }
41610923SEvan.Yan@Sun.COM
41710923SEvan.Yan@Sun.COM ndi_dc_freehdl(dcp);
41810923SEvan.Yan@Sun.COM return (rv);
41910923SEvan.Yan@Sun.COM }
42010923SEvan.Yan@Sun.COM
42110923SEvan.Yan@Sun.COM /* ARGSUSED */
42210923SEvan.Yan@Sun.COM int
pcie_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int flags,char * name,caddr_t valuep,int * lengthp)42310923SEvan.Yan@Sun.COM pcie_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
42410923SEvan.Yan@Sun.COM int flags, char *name, caddr_t valuep, int *lengthp)
42510923SEvan.Yan@Sun.COM {
42610923SEvan.Yan@Sun.COM if (dev == DDI_DEV_T_ANY)
42710923SEvan.Yan@Sun.COM goto skip;
42810923SEvan.Yan@Sun.COM
42910923SEvan.Yan@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(dip) &&
43010923SEvan.Yan@Sun.COM strcmp(name, "pci-occupant") == 0) {
43110923SEvan.Yan@Sun.COM int pci_dev = PCI_MINOR_NUM_TO_PCI_DEVNUM(getminor(dev));
43210923SEvan.Yan@Sun.COM
43310923SEvan.Yan@Sun.COM pcie_hp_create_occupant_props(dip, dev, pci_dev);
43410923SEvan.Yan@Sun.COM }
43510923SEvan.Yan@Sun.COM
43610923SEvan.Yan@Sun.COM skip:
43710923SEvan.Yan@Sun.COM return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
43810923SEvan.Yan@Sun.COM }
43910923SEvan.Yan@Sun.COM
44011245SZhijun.Fu@Sun.COM int
pcie_init_cfghdl(dev_info_t * cdip)44111245SZhijun.Fu@Sun.COM pcie_init_cfghdl(dev_info_t *cdip)
44211245SZhijun.Fu@Sun.COM {
44311245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p;
44411245SZhijun.Fu@Sun.COM ddi_acc_handle_t eh = NULL;
44511245SZhijun.Fu@Sun.COM
44611245SZhijun.Fu@Sun.COM bus_p = PCIE_DIP2BUS(cdip);
44711245SZhijun.Fu@Sun.COM if (bus_p == NULL)
44811245SZhijun.Fu@Sun.COM return (DDI_FAILURE);
44911245SZhijun.Fu@Sun.COM
45011245SZhijun.Fu@Sun.COM /* Create an config access special to error handling */
45111245SZhijun.Fu@Sun.COM if (pci_config_setup(cdip, &eh) != DDI_SUCCESS) {
45211245SZhijun.Fu@Sun.COM cmn_err(CE_WARN, "Cannot setup config access"
45311245SZhijun.Fu@Sun.COM " for BDF 0x%x\n", bus_p->bus_bdf);
45411245SZhijun.Fu@Sun.COM return (DDI_FAILURE);
45511245SZhijun.Fu@Sun.COM }
45611245SZhijun.Fu@Sun.COM
45711245SZhijun.Fu@Sun.COM bus_p->bus_cfg_hdl = eh;
45811245SZhijun.Fu@Sun.COM return (DDI_SUCCESS);
45911245SZhijun.Fu@Sun.COM }
46011245SZhijun.Fu@Sun.COM
46111245SZhijun.Fu@Sun.COM void
pcie_fini_cfghdl(dev_info_t * cdip)46211245SZhijun.Fu@Sun.COM pcie_fini_cfghdl(dev_info_t *cdip)
46311245SZhijun.Fu@Sun.COM {
46411245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip);
46511245SZhijun.Fu@Sun.COM
46611245SZhijun.Fu@Sun.COM pci_config_teardown(&bus_p->bus_cfg_hdl);
46711245SZhijun.Fu@Sun.COM }
46811245SZhijun.Fu@Sun.COM
46910187SKrishna.Elango@Sun.COM /*
47010187SKrishna.Elango@Sun.COM * PCI-Express child device initialization.
47110187SKrishna.Elango@Sun.COM * This function enables generic pci-express interrupts and error
47210187SKrishna.Elango@Sun.COM * handling.
47310187SKrishna.Elango@Sun.COM *
47410187SKrishna.Elango@Sun.COM * @param pdip root dip (root nexus's dip)
47510187SKrishna.Elango@Sun.COM * @param cdip child's dip (device's dip)
47610187SKrishna.Elango@Sun.COM * @return DDI_SUCCESS or DDI_FAILURE
47710187SKrishna.Elango@Sun.COM */
47810187SKrishna.Elango@Sun.COM /* ARGSUSED */
47910187SKrishna.Elango@Sun.COM int
pcie_initchild(dev_info_t * cdip)48010187SKrishna.Elango@Sun.COM pcie_initchild(dev_info_t *cdip)
48110187SKrishna.Elango@Sun.COM {
48210187SKrishna.Elango@Sun.COM uint16_t tmp16, reg16;
48310187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p;
48411596SJason.Beloro@Sun.COM uint32_t devid, venid;
48510187SKrishna.Elango@Sun.COM
48610187SKrishna.Elango@Sun.COM bus_p = PCIE_DIP2BUS(cdip);
48710187SKrishna.Elango@Sun.COM if (bus_p == NULL) {
48810187SKrishna.Elango@Sun.COM PCIE_DBG("%s: BUS not found.\n",
48910187SKrishna.Elango@Sun.COM ddi_driver_name(cdip));
49010187SKrishna.Elango@Sun.COM
49110187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
49210187SKrishna.Elango@Sun.COM }
49310187SKrishna.Elango@Sun.COM
49411245SZhijun.Fu@Sun.COM if (pcie_init_cfghdl(cdip) != DDI_SUCCESS)
49511245SZhijun.Fu@Sun.COM return (DDI_FAILURE);
49611245SZhijun.Fu@Sun.COM
49711596SJason.Beloro@Sun.COM /*
49811596SJason.Beloro@Sun.COM * Update pcie_bus_t with real Vendor Id Device Id.
49911596SJason.Beloro@Sun.COM *
50011596SJason.Beloro@Sun.COM * For assigned devices in IOV environment, the OBP will return
50111596SJason.Beloro@Sun.COM * faked device id/vendor id on configration read and for both
50211596SJason.Beloro@Sun.COM * properties in root domain. translate_devid() function will
50311596SJason.Beloro@Sun.COM * update the properties with real device-id/vendor-id on such
50411596SJason.Beloro@Sun.COM * platforms, so that we can utilize the properties here to get
50511596SJason.Beloro@Sun.COM * real device-id/vendor-id and overwrite the faked ids.
50611596SJason.Beloro@Sun.COM *
50711596SJason.Beloro@Sun.COM * For unassigned devices or devices in non-IOV environment, the
50811596SJason.Beloro@Sun.COM * operation below won't make a difference.
50911596SJason.Beloro@Sun.COM *
51011596SJason.Beloro@Sun.COM * The IOV implementation only supports assignment of PCIE
51111596SJason.Beloro@Sun.COM * endpoint devices. Devices under pci-pci bridges don't need
51211596SJason.Beloro@Sun.COM * operation like this.
51311596SJason.Beloro@Sun.COM */
51411596SJason.Beloro@Sun.COM devid = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
51511596SJason.Beloro@Sun.COM "device-id", -1);
51611596SJason.Beloro@Sun.COM venid = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
51711596SJason.Beloro@Sun.COM "vendor-id", -1);
51811596SJason.Beloro@Sun.COM bus_p->bus_dev_ven_id = (devid << 16) | (venid & 0xffff);
51911596SJason.Beloro@Sun.COM
52010187SKrishna.Elango@Sun.COM /* Clear the device's status register */
52110187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_CONF_STAT);
52210187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_CONF_STAT, reg16);
52310187SKrishna.Elango@Sun.COM
52410187SKrishna.Elango@Sun.COM /* Setup the device's command register */
52510187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_CONF_COMM);
52610187SKrishna.Elango@Sun.COM tmp16 = (reg16 & pcie_command_default_fw) | pcie_command_default;
52710187SKrishna.Elango@Sun.COM
52810187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64)
52910187SKrishna.Elango@Sun.COM boolean_t empty_io_range = B_FALSE;
53010187SKrishna.Elango@Sun.COM boolean_t empty_mem_range = B_FALSE;
53110187SKrishna.Elango@Sun.COM /*
53210187SKrishna.Elango@Sun.COM * Check for empty IO and Mem ranges on bridges. If so disable IO/Mem
53310187SKrishna.Elango@Sun.COM * access as it can cause a hang if enabled.
53410187SKrishna.Elango@Sun.COM */
53510187SKrishna.Elango@Sun.COM pcie_check_io_mem_range(bus_p->bus_cfg_hdl, &empty_io_range,
53610187SKrishna.Elango@Sun.COM &empty_mem_range);
53710187SKrishna.Elango@Sun.COM if ((empty_io_range == B_TRUE) &&
53810187SKrishna.Elango@Sun.COM (pcie_command_default & PCI_COMM_IO)) {
53910187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_IO;
54010187SKrishna.Elango@Sun.COM PCIE_DBG("No I/O range found for %s, bdf 0x%x\n",
54110187SKrishna.Elango@Sun.COM ddi_driver_name(cdip), bus_p->bus_bdf);
54210187SKrishna.Elango@Sun.COM }
54310187SKrishna.Elango@Sun.COM if ((empty_mem_range == B_TRUE) &&
54410187SKrishna.Elango@Sun.COM (pcie_command_default & PCI_COMM_MAE)) {
54510187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_MAE;
54610187SKrishna.Elango@Sun.COM PCIE_DBG("No Mem range found for %s, bdf 0x%x\n",
54710187SKrishna.Elango@Sun.COM ddi_driver_name(cdip), bus_p->bus_bdf);
54810187SKrishna.Elango@Sun.COM }
54910187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */
55010187SKrishna.Elango@Sun.COM
55110187SKrishna.Elango@Sun.COM if (pcie_serr_disable_flag && PCIE_IS_PCIE(bus_p))
55210187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_COMM_SERR_ENABLE;
55310187SKrishna.Elango@Sun.COM
55410187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_CONF_COMM, tmp16);
55510187SKrishna.Elango@Sun.COM PCIE_DBG_CFG(cdip, bus_p, "COMMAND", 16, PCI_CONF_COMM, reg16);
55610187SKrishna.Elango@Sun.COM
55710187SKrishna.Elango@Sun.COM /*
55810187SKrishna.Elango@Sun.COM * If the device has a bus control register then program it
55910187SKrishna.Elango@Sun.COM * based on the settings in the command register.
56010187SKrishna.Elango@Sun.COM */
56110187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) {
56210187SKrishna.Elango@Sun.COM /* Clear the device's secondary status register */
56310187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_BCNF_SEC_STATUS);
56410187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_BCNF_SEC_STATUS, reg16);
56510187SKrishna.Elango@Sun.COM
56610187SKrishna.Elango@Sun.COM /* Setup the device's secondary command register */
56710187SKrishna.Elango@Sun.COM reg16 = PCIE_GET(16, bus_p, PCI_BCNF_BCNTRL);
56810187SKrishna.Elango@Sun.COM tmp16 = (reg16 & pcie_bdg_command_default_fw);
56910187SKrishna.Elango@Sun.COM
57010187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_SERR_ENABLE;
57110187SKrishna.Elango@Sun.COM /*
57210187SKrishna.Elango@Sun.COM * Workaround for this Nvidia bridge. Don't enable the SERR
57310187SKrishna.Elango@Sun.COM * enable bit in the bridge control register as it could lead to
57410187SKrishna.Elango@Sun.COM * bogus NMIs.
57510187SKrishna.Elango@Sun.COM */
57610187SKrishna.Elango@Sun.COM if (bus_p->bus_dev_ven_id == 0x037010DE)
57710187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_BCNF_BCNTRL_SERR_ENABLE;
57810187SKrishna.Elango@Sun.COM
57910187SKrishna.Elango@Sun.COM if (pcie_command_default & PCI_COMM_PARITY_DETECT)
58010187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
58110187SKrishna.Elango@Sun.COM
58210187SKrishna.Elango@Sun.COM /*
58310187SKrishna.Elango@Sun.COM * Enable Master Abort Mode only if URs have not been masked.
58410187SKrishna.Elango@Sun.COM * For PCI and PCIe-PCI bridges, enabling this bit causes a
58510187SKrishna.Elango@Sun.COM * Master Aborts/UR to be forwarded as a UR/TA or SERR. If this
58610187SKrishna.Elango@Sun.COM * bit is masked, posted requests are dropped and non-posted
58710187SKrishna.Elango@Sun.COM * requests are returned with -1.
58810187SKrishna.Elango@Sun.COM */
58910187SKrishna.Elango@Sun.COM if (pcie_aer_uce_mask & PCIE_AER_UCE_UR)
59010187SKrishna.Elango@Sun.COM tmp16 &= ~PCI_BCNF_BCNTRL_MAST_AB_MODE;
59110187SKrishna.Elango@Sun.COM else
59210187SKrishna.Elango@Sun.COM tmp16 |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
59310187SKrishna.Elango@Sun.COM PCIE_PUT(16, bus_p, PCI_BCNF_BCNTRL, tmp16);
59410187SKrishna.Elango@Sun.COM PCIE_DBG_CFG(cdip, bus_p, "SEC CMD", 16, PCI_BCNF_BCNTRL,
59510187SKrishna.Elango@Sun.COM reg16);
59610187SKrishna.Elango@Sun.COM }
59710187SKrishna.Elango@Sun.COM
59810187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) {
59910187SKrishna.Elango@Sun.COM /* Setup PCIe device control register */
60010187SKrishna.Elango@Sun.COM reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
60112330SDaniel.Ice@Sun.COM /* note: MPS/MRRS are initialized in pcie_initchild_mps() */
60212330SDaniel.Ice@Sun.COM tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK |
60312330SDaniel.Ice@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
60412330SDaniel.Ice@Sun.COM (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
60512330SDaniel.Ice@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK));
60610187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
60710187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(cdip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
60810187SKrishna.Elango@Sun.COM
60910187SKrishna.Elango@Sun.COM /* Enable PCIe errors */
61010187SKrishna.Elango@Sun.COM pcie_enable_errors(cdip);
61110187SKrishna.Elango@Sun.COM }
61210187SKrishna.Elango@Sun.COM
61310923SEvan.Yan@Sun.COM bus_p->bus_ari = B_FALSE;
61410923SEvan.Yan@Sun.COM if ((pcie_ari_is_enabled(ddi_get_parent(cdip))
61510923SEvan.Yan@Sun.COM == PCIE_ARI_FORW_ENABLED) && (pcie_ari_device(cdip)
61610923SEvan.Yan@Sun.COM == PCIE_ARI_DEVICE)) {
61710923SEvan.Yan@Sun.COM bus_p->bus_ari = B_TRUE;
61810923SEvan.Yan@Sun.COM }
61910923SEvan.Yan@Sun.COM
62011245SZhijun.Fu@Sun.COM if (pcie_initchild_mps(cdip) == DDI_FAILURE) {
62111245SZhijun.Fu@Sun.COM pcie_fini_cfghdl(cdip);
62210187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
62311245SZhijun.Fu@Sun.COM }
62410187SKrishna.Elango@Sun.COM
62510187SKrishna.Elango@Sun.COM return (DDI_SUCCESS);
62610187SKrishna.Elango@Sun.COM }
62710187SKrishna.Elango@Sun.COM
62810187SKrishna.Elango@Sun.COM static void
pcie_init_pfd(dev_info_t * dip)62910187SKrishna.Elango@Sun.COM pcie_init_pfd(dev_info_t *dip)
63010187SKrishna.Elango@Sun.COM {
63110187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_ZALLOC(pf_data_t);
63210187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
63310187SKrishna.Elango@Sun.COM
63410187SKrishna.Elango@Sun.COM PCIE_DIP2PFD(dip) = pfd_p;
63510187SKrishna.Elango@Sun.COM
63610187SKrishna.Elango@Sun.COM pfd_p->pe_bus_p = bus_p;
63710187SKrishna.Elango@Sun.COM pfd_p->pe_severity_flags = 0;
63811596SJason.Beloro@Sun.COM pfd_p->pe_orig_severity_flags = 0;
63910187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_FALSE;
64010187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_FALSE;
64110187SKrishna.Elango@Sun.COM
64210187SKrishna.Elango@Sun.COM /* Allocate the root fault struct for both RC and RP */
64310187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p)) {
64410187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
64510187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
64611596SJason.Beloro@Sun.COM PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t);
64710187SKrishna.Elango@Sun.COM }
64810187SKrishna.Elango@Sun.COM
64910187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
65011596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t);
65111596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
65210187SKrishna.Elango@Sun.COM
65310187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p))
65410187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
65510187SKrishna.Elango@Sun.COM
65610187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) {
65710187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
65810187SKrishna.Elango@Sun.COM
65910187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p))
66010187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p) =
66110187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
66210187SKrishna.Elango@Sun.COM
66310187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
66410187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_tgt_bdf = PCIE_INVALID_BDF;
66510187SKrishna.Elango@Sun.COM
66610187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) {
66710187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p) =
66810187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
66910187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id =
67010187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF;
67110187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id =
67210187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF;
67310187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIE_BDG(bus_p)) {
67410187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p) =
67510187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcie_adv_bdg_err_regs_t);
67610187SKrishna.Elango@Sun.COM PCIE_ADV_BDG_REG(pfd_p)->pcie_sue_tgt_bdf =
67710187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF;
67810187SKrishna.Elango@Sun.COM }
67910187SKrishna.Elango@Sun.COM
68010187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
68110187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p) =
68210187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
68310187SKrishna.Elango@Sun.COM
68410187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
68510187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 0) =
68610187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t);
68710187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 1) =
68810187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t);
68910187SKrishna.Elango@Sun.COM }
69010187SKrishna.Elango@Sun.COM }
69110187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIX(bus_p)) {
69210187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) {
69310187SKrishna.Elango@Sun.COM PCIX_BDG_ERR_REG(pfd_p) =
69410187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_bdg_err_regs_t);
69510187SKrishna.Elango@Sun.COM
69610187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
69710187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 0) =
69810187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t);
69910187SKrishna.Elango@Sun.COM PCIX_BDG_ECC_REG(pfd_p, 1) =
70010187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t);
70110187SKrishna.Elango@Sun.COM }
70210187SKrishna.Elango@Sun.COM } else {
70310187SKrishna.Elango@Sun.COM PCIX_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcix_err_regs_t);
70410187SKrishna.Elango@Sun.COM
70510187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p))
70610187SKrishna.Elango@Sun.COM PCIX_ECC_REG(pfd_p) =
70710187SKrishna.Elango@Sun.COM PCIE_ZALLOC(pf_pcix_ecc_regs_t);
70810187SKrishna.Elango@Sun.COM }
70910187SKrishna.Elango@Sun.COM }
71010187SKrishna.Elango@Sun.COM }
71110187SKrishna.Elango@Sun.COM
71210187SKrishna.Elango@Sun.COM static void
pcie_fini_pfd(dev_info_t * dip)71310187SKrishna.Elango@Sun.COM pcie_fini_pfd(dev_info_t *dip)
71410187SKrishna.Elango@Sun.COM {
71510187SKrishna.Elango@Sun.COM pf_data_t *pfd_p = PCIE_DIP2PFD(dip);
71610187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
71710187SKrishna.Elango@Sun.COM
71810187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) {
71910187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE_BDG(bus_p) && PCIE_IS_PCIX(bus_p)) {
72010187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
72110187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
72210187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t));
72310187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
72410187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t));
72510187SKrishna.Elango@Sun.COM }
72610187SKrishna.Elango@Sun.COM
72710187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ERR_REG(pfd_p),
72810187SKrishna.Elango@Sun.COM sizeof (pf_pcix_bdg_err_regs_t));
72910187SKrishna.Elango@Sun.COM }
73010187SKrishna.Elango@Sun.COM
73110187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p))
73210187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_RP_REG(pfd_p),
73310187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_rp_err_regs_t));
73410187SKrishna.Elango@Sun.COM else if (PCIE_IS_PCIE_BDG(bus_p))
73510187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_BDG_REG(pfd_p),
73610187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_bdg_err_regs_t));
73710187SKrishna.Elango@Sun.COM
73810187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_REG(pfd_p),
73910187SKrishna.Elango@Sun.COM sizeof (pf_pcie_adv_err_regs_t));
74010187SKrishna.Elango@Sun.COM
74110187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p))
74210187SKrishna.Elango@Sun.COM kmem_free(PCIE_RP_REG(pfd_p),
74310187SKrishna.Elango@Sun.COM sizeof (pf_pcie_rp_err_regs_t));
74410187SKrishna.Elango@Sun.COM
74510187SKrishna.Elango@Sun.COM kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
74610187SKrishna.Elango@Sun.COM } else if (PCIE_IS_PCIX(bus_p)) {
74710187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p)) {
74810187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p)) {
74910187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 0),
75010187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t));
75110187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ECC_REG(pfd_p, 1),
75210187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t));
75310187SKrishna.Elango@Sun.COM }
75410187SKrishna.Elango@Sun.COM
75510187SKrishna.Elango@Sun.COM kmem_free(PCIX_BDG_ERR_REG(pfd_p),
75610187SKrishna.Elango@Sun.COM sizeof (pf_pcix_bdg_err_regs_t));
75710187SKrishna.Elango@Sun.COM } else {
75810187SKrishna.Elango@Sun.COM if (PCIX_ECC_VERSION_CHECK(bus_p))
75910187SKrishna.Elango@Sun.COM kmem_free(PCIX_ECC_REG(pfd_p),
76010187SKrishna.Elango@Sun.COM sizeof (pf_pcix_ecc_regs_t));
76110187SKrishna.Elango@Sun.COM
76210187SKrishna.Elango@Sun.COM kmem_free(PCIX_ERR_REG(pfd_p),
76310187SKrishna.Elango@Sun.COM sizeof (pf_pcix_err_regs_t));
76410187SKrishna.Elango@Sun.COM }
76510187SKrishna.Elango@Sun.COM }
76610187SKrishna.Elango@Sun.COM
76710187SKrishna.Elango@Sun.COM if (PCIE_IS_BDG(bus_p))
76810187SKrishna.Elango@Sun.COM kmem_free(PCI_BDG_ERR_REG(pfd_p),
76910187SKrishna.Elango@Sun.COM sizeof (pf_pci_bdg_err_regs_t));
77010187SKrishna.Elango@Sun.COM
77111596SJason.Beloro@Sun.COM kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t));
77210187SKrishna.Elango@Sun.COM kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
77310187SKrishna.Elango@Sun.COM
77411596SJason.Beloro@Sun.COM if (PCIE_IS_ROOT(bus_p)) {
77510187SKrishna.Elango@Sun.COM kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
77611596SJason.Beloro@Sun.COM kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t));
77711596SJason.Beloro@Sun.COM }
77810187SKrishna.Elango@Sun.COM
77910187SKrishna.Elango@Sun.COM kmem_free(PCIE_DIP2PFD(dip), sizeof (pf_data_t));
78010187SKrishna.Elango@Sun.COM
78110187SKrishna.Elango@Sun.COM PCIE_DIP2PFD(dip) = NULL;
78210187SKrishna.Elango@Sun.COM }
78310187SKrishna.Elango@Sun.COM
78410187SKrishna.Elango@Sun.COM
78510187SKrishna.Elango@Sun.COM /*
78610187SKrishna.Elango@Sun.COM * Special functions to allocate pf_data_t's for PCIe root complexes.
78710187SKrishna.Elango@Sun.COM * Note: Root Complex not Root Port
78810187SKrishna.Elango@Sun.COM */
78910187SKrishna.Elango@Sun.COM void
pcie_rc_init_pfd(dev_info_t * dip,pf_data_t * pfd_p)79010187SKrishna.Elango@Sun.COM pcie_rc_init_pfd(dev_info_t *dip, pf_data_t *pfd_p)
79110187SKrishna.Elango@Sun.COM {
79210187SKrishna.Elango@Sun.COM pfd_p->pe_bus_p = PCIE_DIP2DOWNBUS(dip);
79310187SKrishna.Elango@Sun.COM pfd_p->pe_severity_flags = 0;
79411596SJason.Beloro@Sun.COM pfd_p->pe_orig_severity_flags = 0;
79510187SKrishna.Elango@Sun.COM pfd_p->pe_lock = B_FALSE;
79610187SKrishna.Elango@Sun.COM pfd_p->pe_valid = B_FALSE;
79710187SKrishna.Elango@Sun.COM
79810187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p) = PCIE_ZALLOC(pf_root_fault_t);
79910187SKrishna.Elango@Sun.COM PCIE_ROOT_FAULT(pfd_p)->scan_bdf = PCIE_INVALID_BDF;
80011596SJason.Beloro@Sun.COM PCIE_ROOT_EH_SRC(pfd_p) = PCIE_ZALLOC(pf_root_eh_src_t);
80110187SKrishna.Elango@Sun.COM PCI_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_err_regs_t);
80211596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p) = PCIE_ZALLOC(pf_affected_dev_t);
80311596SJason.Beloro@Sun.COM PFD_AFFECTED_DEV(pfd_p)->pe_affected_bdf = PCIE_INVALID_BDF;
80410187SKrishna.Elango@Sun.COM PCI_BDG_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pci_bdg_err_regs_t);
80510187SKrishna.Elango@Sun.COM PCIE_ERR_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_err_regs_t);
80610187SKrishna.Elango@Sun.COM PCIE_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_rp_err_regs_t);
80710187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_err_regs_t);
80810187SKrishna.Elango@Sun.COM PCIE_ADV_RP_REG(pfd_p) = PCIE_ZALLOC(pf_pcie_adv_rp_err_regs_t);
80911596SJason.Beloro@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ce_src_id = PCIE_INVALID_BDF;
81011596SJason.Beloro@Sun.COM PCIE_ADV_RP_REG(pfd_p)->pcie_rp_ue_src_id = PCIE_INVALID_BDF;
81110187SKrishna.Elango@Sun.COM
81210187SKrishna.Elango@Sun.COM PCIE_ADV_REG(pfd_p)->pcie_ue_sev = pcie_aer_uce_severity;
81310187SKrishna.Elango@Sun.COM }
81410187SKrishna.Elango@Sun.COM
81510187SKrishna.Elango@Sun.COM void
pcie_rc_fini_pfd(pf_data_t * pfd_p)81610187SKrishna.Elango@Sun.COM pcie_rc_fini_pfd(pf_data_t *pfd_p)
81710187SKrishna.Elango@Sun.COM {
81810187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_RP_REG(pfd_p), sizeof (pf_pcie_adv_rp_err_regs_t));
81910187SKrishna.Elango@Sun.COM kmem_free(PCIE_ADV_REG(pfd_p), sizeof (pf_pcie_adv_err_regs_t));
82010187SKrishna.Elango@Sun.COM kmem_free(PCIE_RP_REG(pfd_p), sizeof (pf_pcie_rp_err_regs_t));
82110187SKrishna.Elango@Sun.COM kmem_free(PCIE_ERR_REG(pfd_p), sizeof (pf_pcie_err_regs_t));
82210187SKrishna.Elango@Sun.COM kmem_free(PCI_BDG_ERR_REG(pfd_p), sizeof (pf_pci_bdg_err_regs_t));
82311596SJason.Beloro@Sun.COM kmem_free(PFD_AFFECTED_DEV(pfd_p), sizeof (pf_affected_dev_t));
82410187SKrishna.Elango@Sun.COM kmem_free(PCI_ERR_REG(pfd_p), sizeof (pf_pci_err_regs_t));
82510187SKrishna.Elango@Sun.COM kmem_free(PCIE_ROOT_FAULT(pfd_p), sizeof (pf_root_fault_t));
82611596SJason.Beloro@Sun.COM kmem_free(PCIE_ROOT_EH_SRC(pfd_p), sizeof (pf_root_eh_src_t));
82710187SKrishna.Elango@Sun.COM }
82810187SKrishna.Elango@Sun.COM
82911245SZhijun.Fu@Sun.COM /*
83011245SZhijun.Fu@Sun.COM * init pcie_bus_t for root complex
83111245SZhijun.Fu@Sun.COM *
83211245SZhijun.Fu@Sun.COM * Only a few of the fields in bus_t is valid for root complex.
83311245SZhijun.Fu@Sun.COM * The fields that are bracketed are initialized in this routine:
83411245SZhijun.Fu@Sun.COM *
83511245SZhijun.Fu@Sun.COM * dev_info_t * <bus_dip>
83611245SZhijun.Fu@Sun.COM * dev_info_t * bus_rp_dip
83711245SZhijun.Fu@Sun.COM * ddi_acc_handle_t bus_cfg_hdl
83811245SZhijun.Fu@Sun.COM * uint_t <bus_fm_flags>
83911245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_bdf
84011245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_rp_bdf
84111245SZhijun.Fu@Sun.COM * uint32_t bus_dev_ven_id
84211245SZhijun.Fu@Sun.COM * uint8_t bus_rev_id
84311245SZhijun.Fu@Sun.COM * uint8_t <bus_hdr_type>
84411245SZhijun.Fu@Sun.COM * uint16_t <bus_dev_type>
84511245SZhijun.Fu@Sun.COM * uint8_t bus_bdg_secbus
84611245SZhijun.Fu@Sun.COM * uint16_t bus_pcie_off
84711245SZhijun.Fu@Sun.COM * uint16_t <bus_aer_off>
84811245SZhijun.Fu@Sun.COM * uint16_t bus_pcix_off
84911245SZhijun.Fu@Sun.COM * uint16_t bus_ecc_ver
85011245SZhijun.Fu@Sun.COM * pci_bus_range_t bus_bus_range
85111245SZhijun.Fu@Sun.COM * ppb_ranges_t * bus_addr_ranges
85211245SZhijun.Fu@Sun.COM * int bus_addr_entries
85311245SZhijun.Fu@Sun.COM * pci_regspec_t * bus_assigned_addr
85411245SZhijun.Fu@Sun.COM * int bus_assigned_entries
85511245SZhijun.Fu@Sun.COM * pf_data_t * bus_pfd
85611596SJason.Beloro@Sun.COM * pcie_domain_t * <bus_dom>
85711245SZhijun.Fu@Sun.COM * int bus_mps
85811245SZhijun.Fu@Sun.COM * uint64_t bus_cfgacc_base
85911245SZhijun.Fu@Sun.COM * void * bus_plat_private
86011245SZhijun.Fu@Sun.COM */
86110187SKrishna.Elango@Sun.COM void
pcie_rc_init_bus(dev_info_t * dip)86210187SKrishna.Elango@Sun.COM pcie_rc_init_bus(dev_info_t *dip)
86310187SKrishna.Elango@Sun.COM {
86410187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p;
86510187SKrishna.Elango@Sun.COM
86610187SKrishna.Elango@Sun.COM bus_p = (pcie_bus_t *)kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
86710187SKrishna.Elango@Sun.COM bus_p->bus_dip = dip;
86810187SKrishna.Elango@Sun.COM bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_RC_PSEUDO;
86910187SKrishna.Elango@Sun.COM bus_p->bus_hdr_type = PCI_HEADER_ONE;
87010187SKrishna.Elango@Sun.COM
87110187SKrishna.Elango@Sun.COM /* Fake that there are AER logs */
87210187SKrishna.Elango@Sun.COM bus_p->bus_aer_off = (uint16_t)-1;
87310187SKrishna.Elango@Sun.COM
87410187SKrishna.Elango@Sun.COM /* Needed only for handle lookup */
87510187SKrishna.Elango@Sun.COM bus_p->bus_fm_flags |= PF_FM_READY;
87610187SKrishna.Elango@Sun.COM
87710187SKrishna.Elango@Sun.COM ndi_set_bus_private(dip, B_FALSE, DEVI_PORT_TYPE_PCI, bus_p);
87811596SJason.Beloro@Sun.COM
87911596SJason.Beloro@Sun.COM PCIE_BUS2DOM(bus_p) = PCIE_ZALLOC(pcie_domain_t);
88010187SKrishna.Elango@Sun.COM }
88110187SKrishna.Elango@Sun.COM
88210187SKrishna.Elango@Sun.COM void
pcie_rc_fini_bus(dev_info_t * dip)88310187SKrishna.Elango@Sun.COM pcie_rc_fini_bus(dev_info_t *dip)
88410187SKrishna.Elango@Sun.COM {
88511245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2DOWNBUS(dip);
88610187SKrishna.Elango@Sun.COM ndi_set_bus_private(dip, B_FALSE, NULL, NULL);
88711596SJason.Beloro@Sun.COM kmem_free(PCIE_BUS2DOM(bus_p), sizeof (pcie_domain_t));
88810187SKrishna.Elango@Sun.COM kmem_free(bus_p, sizeof (pcie_bus_t));
88910187SKrishna.Elango@Sun.COM }
89010187SKrishna.Elango@Sun.COM
89110187SKrishna.Elango@Sun.COM /*
89211245SZhijun.Fu@Sun.COM * partially init pcie_bus_t for device (dip,bdf) for accessing pci
89311245SZhijun.Fu@Sun.COM * config space
89411245SZhijun.Fu@Sun.COM *
89511245SZhijun.Fu@Sun.COM * This routine is invoked during boot, either after creating a devinfo node
89611245SZhijun.Fu@Sun.COM * (x86 case) or during px driver attach (sparc case); it is also invoked
89711245SZhijun.Fu@Sun.COM * in hotplug context after a devinfo node is created.
89811245SZhijun.Fu@Sun.COM *
89911245SZhijun.Fu@Sun.COM * The fields that are bracketed are initialized if flag PCIE_BUS_INITIAL
90011245SZhijun.Fu@Sun.COM * is set:
90110187SKrishna.Elango@Sun.COM *
90211245SZhijun.Fu@Sun.COM * dev_info_t * <bus_dip>
90311245SZhijun.Fu@Sun.COM * dev_info_t * <bus_rp_dip>
90411245SZhijun.Fu@Sun.COM * ddi_acc_handle_t bus_cfg_hdl
90511245SZhijun.Fu@Sun.COM * uint_t bus_fm_flags
90611245SZhijun.Fu@Sun.COM * pcie_req_id_t <bus_bdf>
90711245SZhijun.Fu@Sun.COM * pcie_req_id_t <bus_rp_bdf>
90811245SZhijun.Fu@Sun.COM * uint32_t <bus_dev_ven_id>
90911245SZhijun.Fu@Sun.COM * uint8_t <bus_rev_id>
91011245SZhijun.Fu@Sun.COM * uint8_t <bus_hdr_type>
91111245SZhijun.Fu@Sun.COM * uint16_t <bus_dev_type>
91211245SZhijun.Fu@Sun.COM * uint8_t <bus_bdg_secbus
91311245SZhijun.Fu@Sun.COM * uint16_t <bus_pcie_off>
91411245SZhijun.Fu@Sun.COM * uint16_t <bus_aer_off>
91511245SZhijun.Fu@Sun.COM * uint16_t <bus_pcix_off>
91611245SZhijun.Fu@Sun.COM * uint16_t <bus_ecc_ver>
91711245SZhijun.Fu@Sun.COM * pci_bus_range_t bus_bus_range
91811245SZhijun.Fu@Sun.COM * ppb_ranges_t * bus_addr_ranges
91911245SZhijun.Fu@Sun.COM * int bus_addr_entries
92011245SZhijun.Fu@Sun.COM * pci_regspec_t * bus_assigned_addr
92111245SZhijun.Fu@Sun.COM * int bus_assigned_entries
92211245SZhijun.Fu@Sun.COM * pf_data_t * bus_pfd
92311596SJason.Beloro@Sun.COM * pcie_domain_t * bus_dom
92411245SZhijun.Fu@Sun.COM * int bus_mps
92511245SZhijun.Fu@Sun.COM * uint64_t bus_cfgacc_base
92611245SZhijun.Fu@Sun.COM * void * bus_plat_private
92711245SZhijun.Fu@Sun.COM *
92811245SZhijun.Fu@Sun.COM * The fields that are bracketed are initialized if flag PCIE_BUS_FINAL
92911245SZhijun.Fu@Sun.COM * is set:
93011245SZhijun.Fu@Sun.COM *
93111245SZhijun.Fu@Sun.COM * dev_info_t * bus_dip
93211245SZhijun.Fu@Sun.COM * dev_info_t * bus_rp_dip
93311245SZhijun.Fu@Sun.COM * ddi_acc_handle_t bus_cfg_hdl
93411245SZhijun.Fu@Sun.COM * uint_t bus_fm_flags
93511245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_bdf
93611245SZhijun.Fu@Sun.COM * pcie_req_id_t bus_rp_bdf
93711245SZhijun.Fu@Sun.COM * uint32_t bus_dev_ven_id
93811245SZhijun.Fu@Sun.COM * uint8_t bus_rev_id
93911245SZhijun.Fu@Sun.COM * uint8_t bus_hdr_type
94011245SZhijun.Fu@Sun.COM * uint16_t bus_dev_type
94111245SZhijun.Fu@Sun.COM * uint8_t <bus_bdg_secbus>
94211245SZhijun.Fu@Sun.COM * uint16_t bus_pcie_off
94311245SZhijun.Fu@Sun.COM * uint16_t bus_aer_off
94411245SZhijun.Fu@Sun.COM * uint16_t bus_pcix_off
94511245SZhijun.Fu@Sun.COM * uint16_t bus_ecc_ver
94611245SZhijun.Fu@Sun.COM * pci_bus_range_t <bus_bus_range>
94711245SZhijun.Fu@Sun.COM * ppb_ranges_t * <bus_addr_ranges>
94811245SZhijun.Fu@Sun.COM * int <bus_addr_entries>
94911245SZhijun.Fu@Sun.COM * pci_regspec_t * <bus_assigned_addr>
95011245SZhijun.Fu@Sun.COM * int <bus_assigned_entries>
95111245SZhijun.Fu@Sun.COM * pf_data_t * <bus_pfd>
95211596SJason.Beloro@Sun.COM * pcie_domain_t * bus_dom
95311245SZhijun.Fu@Sun.COM * int bus_mps
95411245SZhijun.Fu@Sun.COM * uint64_t bus_cfgacc_base
95511245SZhijun.Fu@Sun.COM * void * <bus_plat_private>
95610187SKrishna.Elango@Sun.COM */
95711245SZhijun.Fu@Sun.COM
95810187SKrishna.Elango@Sun.COM pcie_bus_t *
pcie_init_bus(dev_info_t * dip,pcie_req_id_t bdf,uint8_t flags)95911245SZhijun.Fu@Sun.COM pcie_init_bus(dev_info_t *dip, pcie_req_id_t bdf, uint8_t flags)
96010187SKrishna.Elango@Sun.COM {
96111245SZhijun.Fu@Sun.COM uint16_t status, base, baseptr, num_cap;
96211245SZhijun.Fu@Sun.COM uint32_t capid;
96311245SZhijun.Fu@Sun.COM int range_size;
96411245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p;
96511245SZhijun.Fu@Sun.COM dev_info_t *rcdip;
96611245SZhijun.Fu@Sun.COM dev_info_t *pdip;
96711245SZhijun.Fu@Sun.COM const char *errstr = NULL;
96810187SKrishna.Elango@Sun.COM
96911245SZhijun.Fu@Sun.COM if (!(flags & PCIE_BUS_INITIAL))
97011245SZhijun.Fu@Sun.COM goto initial_done;
97110187SKrishna.Elango@Sun.COM
97210187SKrishna.Elango@Sun.COM bus_p = kmem_zalloc(sizeof (pcie_bus_t), KM_SLEEP);
97310187SKrishna.Elango@Sun.COM
97411245SZhijun.Fu@Sun.COM bus_p->bus_dip = dip;
97511245SZhijun.Fu@Sun.COM bus_p->bus_bdf = bdf;
97610187SKrishna.Elango@Sun.COM
97711245SZhijun.Fu@Sun.COM rcdip = pcie_get_rc_dip(dip);
97811245SZhijun.Fu@Sun.COM ASSERT(rcdip != NULL);
97910187SKrishna.Elango@Sun.COM
98011245SZhijun.Fu@Sun.COM /* Save the Vendor ID, Device ID and revision ID */
98111245SZhijun.Fu@Sun.COM bus_p->bus_dev_ven_id = pci_cfgacc_get32(rcdip, bdf, PCI_CONF_VENID);
98211245SZhijun.Fu@Sun.COM bus_p->bus_rev_id = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_REVID);
98310187SKrishna.Elango@Sun.COM /* Save the Header Type */
98411245SZhijun.Fu@Sun.COM bus_p->bus_hdr_type = pci_cfgacc_get8(rcdip, bdf, PCI_CONF_HEADER);
98510187SKrishna.Elango@Sun.COM bus_p->bus_hdr_type &= PCI_HEADER_TYPE_M;
98610187SKrishna.Elango@Sun.COM
98711245SZhijun.Fu@Sun.COM /*
98811245SZhijun.Fu@Sun.COM * Figure out the device type and all the relavant capability offsets
98911245SZhijun.Fu@Sun.COM */
99011245SZhijun.Fu@Sun.COM /* set default value */
99111245SZhijun.Fu@Sun.COM bus_p->bus_dev_type = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
99210187SKrishna.Elango@Sun.COM
99311245SZhijun.Fu@Sun.COM status = pci_cfgacc_get16(rcdip, bdf, PCI_CONF_STAT);
99411245SZhijun.Fu@Sun.COM if (status == PCI_CAP_EINVAL16 || !(status & PCI_STAT_CAP))
99511245SZhijun.Fu@Sun.COM goto caps_done; /* capability not supported */
99611245SZhijun.Fu@Sun.COM
99711245SZhijun.Fu@Sun.COM /* Relevant conventional capabilities first */
99811245SZhijun.Fu@Sun.COM
99911245SZhijun.Fu@Sun.COM /* Conventional caps: PCI_CAP_ID_PCI_E, PCI_CAP_ID_PCIX */
100011245SZhijun.Fu@Sun.COM num_cap = 2;
100110923SEvan.Yan@Sun.COM
100211245SZhijun.Fu@Sun.COM switch (bus_p->bus_hdr_type) {
100311245SZhijun.Fu@Sun.COM case PCI_HEADER_ZERO:
100411245SZhijun.Fu@Sun.COM baseptr = PCI_CONF_CAP_PTR;
100511245SZhijun.Fu@Sun.COM break;
100611245SZhijun.Fu@Sun.COM case PCI_HEADER_PPB:
100711245SZhijun.Fu@Sun.COM baseptr = PCI_BCNF_CAP_PTR;
100811245SZhijun.Fu@Sun.COM break;
100911245SZhijun.Fu@Sun.COM case PCI_HEADER_CARDBUS:
101011245SZhijun.Fu@Sun.COM baseptr = PCI_CBUS_CAP_PTR;
101111245SZhijun.Fu@Sun.COM break;
101211245SZhijun.Fu@Sun.COM default:
101311245SZhijun.Fu@Sun.COM cmn_err(CE_WARN, "%s: unexpected pci header type:%x",
101411245SZhijun.Fu@Sun.COM __func__, bus_p->bus_hdr_type);
101511245SZhijun.Fu@Sun.COM goto caps_done;
101610187SKrishna.Elango@Sun.COM }
101710187SKrishna.Elango@Sun.COM
101811245SZhijun.Fu@Sun.COM base = baseptr;
101911245SZhijun.Fu@Sun.COM for (base = pci_cfgacc_get8(rcdip, bdf, base); base && num_cap;
102011245SZhijun.Fu@Sun.COM base = pci_cfgacc_get8(rcdip, bdf, base + PCI_CAP_NEXT_PTR)) {
102111245SZhijun.Fu@Sun.COM capid = pci_cfgacc_get8(rcdip, bdf, base);
102211245SZhijun.Fu@Sun.COM switch (capid) {
102311245SZhijun.Fu@Sun.COM case PCI_CAP_ID_PCI_E:
102411245SZhijun.Fu@Sun.COM bus_p->bus_pcie_off = base;
102511245SZhijun.Fu@Sun.COM bus_p->bus_dev_type = pci_cfgacc_get16(rcdip, bdf,
102611245SZhijun.Fu@Sun.COM base + PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
102711245SZhijun.Fu@Sun.COM
102811245SZhijun.Fu@Sun.COM /* Check and save PCIe hotplug capability information */
102911245SZhijun.Fu@Sun.COM if ((PCIE_IS_RP(bus_p) || PCIE_IS_SWD(bus_p)) &&
103011245SZhijun.Fu@Sun.COM (pci_cfgacc_get16(rcdip, bdf, base + PCIE_PCIECAP)
103111245SZhijun.Fu@Sun.COM & PCIE_PCIECAP_SLOT_IMPL) &&
103211245SZhijun.Fu@Sun.COM (pci_cfgacc_get32(rcdip, bdf, base + PCIE_SLOTCAP)
103311245SZhijun.Fu@Sun.COM & PCIE_SLOTCAP_HP_CAPABLE))
103411245SZhijun.Fu@Sun.COM bus_p->bus_hp_sup_modes |= PCIE_NATIVE_HP_MODE;
103510923SEvan.Yan@Sun.COM
103611245SZhijun.Fu@Sun.COM num_cap--;
103711245SZhijun.Fu@Sun.COM break;
103811245SZhijun.Fu@Sun.COM case PCI_CAP_ID_PCIX:
103911245SZhijun.Fu@Sun.COM bus_p->bus_pcix_off = base;
104011245SZhijun.Fu@Sun.COM if (PCIE_IS_BDG(bus_p))
104111245SZhijun.Fu@Sun.COM bus_p->bus_ecc_ver =
104211245SZhijun.Fu@Sun.COM pci_cfgacc_get16(rcdip, bdf, base +
104311245SZhijun.Fu@Sun.COM PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
104411245SZhijun.Fu@Sun.COM else
104511245SZhijun.Fu@Sun.COM bus_p->bus_ecc_ver =
104611245SZhijun.Fu@Sun.COM pci_cfgacc_get16(rcdip, bdf, base +
104711245SZhijun.Fu@Sun.COM PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
104811245SZhijun.Fu@Sun.COM num_cap--;
104911245SZhijun.Fu@Sun.COM break;
105011245SZhijun.Fu@Sun.COM default:
105111245SZhijun.Fu@Sun.COM break;
105210187SKrishna.Elango@Sun.COM }
105310187SKrishna.Elango@Sun.COM }
105410187SKrishna.Elango@Sun.COM
105511245SZhijun.Fu@Sun.COM /* Check and save PCI hotplug (SHPC) capability information */
105611245SZhijun.Fu@Sun.COM if (PCIE_IS_BDG(bus_p)) {
105711245SZhijun.Fu@Sun.COM base = baseptr;
105811245SZhijun.Fu@Sun.COM for (base = pci_cfgacc_get8(rcdip, bdf, base);
105911245SZhijun.Fu@Sun.COM base; base = pci_cfgacc_get8(rcdip, bdf,
106011245SZhijun.Fu@Sun.COM base + PCI_CAP_NEXT_PTR)) {
106111245SZhijun.Fu@Sun.COM capid = pci_cfgacc_get8(rcdip, bdf, base);
106211245SZhijun.Fu@Sun.COM if (capid == PCI_CAP_ID_PCI_HOTPLUG) {
106311245SZhijun.Fu@Sun.COM bus_p->bus_pci_hp_off = base;
106411245SZhijun.Fu@Sun.COM bus_p->bus_hp_sup_modes |= PCIE_PCI_HP_MODE;
106511245SZhijun.Fu@Sun.COM break;
106611245SZhijun.Fu@Sun.COM }
106711245SZhijun.Fu@Sun.COM }
106811245SZhijun.Fu@Sun.COM }
106911245SZhijun.Fu@Sun.COM
107011245SZhijun.Fu@Sun.COM /* Then, relevant extended capabilities */
107110187SKrishna.Elango@Sun.COM
107211245SZhijun.Fu@Sun.COM if (!PCIE_IS_PCIE(bus_p))
107311245SZhijun.Fu@Sun.COM goto caps_done;
107411245SZhijun.Fu@Sun.COM
107511245SZhijun.Fu@Sun.COM /* Extended caps: PCIE_EXT_CAP_ID_AER */
107611245SZhijun.Fu@Sun.COM for (base = PCIE_EXT_CAP; base; base = (capid >>
107711245SZhijun.Fu@Sun.COM PCIE_EXT_CAP_NEXT_PTR_SHIFT) & PCIE_EXT_CAP_NEXT_PTR_MASK) {
107811245SZhijun.Fu@Sun.COM capid = pci_cfgacc_get32(rcdip, bdf, base);
107911245SZhijun.Fu@Sun.COM if (capid == PCI_CAP_EINVAL32)
108011245SZhijun.Fu@Sun.COM break;
108111245SZhijun.Fu@Sun.COM if (((capid >> PCIE_EXT_CAP_ID_SHIFT) & PCIE_EXT_CAP_ID_MASK)
108211245SZhijun.Fu@Sun.COM == PCIE_EXT_CAP_ID_AER) {
108311245SZhijun.Fu@Sun.COM bus_p->bus_aer_off = base;
108411245SZhijun.Fu@Sun.COM break;
108511245SZhijun.Fu@Sun.COM }
108611245SZhijun.Fu@Sun.COM }
108711245SZhijun.Fu@Sun.COM
108811245SZhijun.Fu@Sun.COM caps_done:
108910187SKrishna.Elango@Sun.COM /* save RP dip and RP bdf */
109010187SKrishna.Elango@Sun.COM if (PCIE_IS_RP(bus_p)) {
109111245SZhijun.Fu@Sun.COM bus_p->bus_rp_dip = dip;
109210187SKrishna.Elango@Sun.COM bus_p->bus_rp_bdf = bus_p->bus_bdf;
109310187SKrishna.Elango@Sun.COM } else {
109411245SZhijun.Fu@Sun.COM for (pdip = ddi_get_parent(dip); pdip;
109510187SKrishna.Elango@Sun.COM pdip = ddi_get_parent(pdip)) {
109610187SKrishna.Elango@Sun.COM pcie_bus_t *parent_bus_p = PCIE_DIP2BUS(pdip);
109710187SKrishna.Elango@Sun.COM
109810187SKrishna.Elango@Sun.COM /*
109911245SZhijun.Fu@Sun.COM * If RP dip and RP bdf in parent's bus_t have
110011245SZhijun.Fu@Sun.COM * been initialized, simply use these instead of
110111245SZhijun.Fu@Sun.COM * continuing up to the RC.
110211245SZhijun.Fu@Sun.COM */
110311245SZhijun.Fu@Sun.COM if (parent_bus_p->bus_rp_dip != NULL) {
110411245SZhijun.Fu@Sun.COM bus_p->bus_rp_dip = parent_bus_p->bus_rp_dip;
110511245SZhijun.Fu@Sun.COM bus_p->bus_rp_bdf = parent_bus_p->bus_rp_bdf;
110611245SZhijun.Fu@Sun.COM break;
110711245SZhijun.Fu@Sun.COM }
110811245SZhijun.Fu@Sun.COM
110911245SZhijun.Fu@Sun.COM /*
111010187SKrishna.Elango@Sun.COM * When debugging be aware that some NVIDIA x86
111110187SKrishna.Elango@Sun.COM * architectures have 2 nodes for each RP, One at Bus
111210187SKrishna.Elango@Sun.COM * 0x0 and one at Bus 0x80. The requester is from Bus
111310187SKrishna.Elango@Sun.COM * 0x80
111410187SKrishna.Elango@Sun.COM */
111510187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(parent_bus_p)) {
111610187SKrishna.Elango@Sun.COM bus_p->bus_rp_dip = pdip;
111710187SKrishna.Elango@Sun.COM bus_p->bus_rp_bdf = parent_bus_p->bus_bdf;
111810187SKrishna.Elango@Sun.COM break;
111910187SKrishna.Elango@Sun.COM }
112010187SKrishna.Elango@Sun.COM }
112110187SKrishna.Elango@Sun.COM }
112210187SKrishna.Elango@Sun.COM
112311245SZhijun.Fu@Sun.COM bus_p->bus_soft_state = PCI_SOFT_STATE_CLOSED;
112411245SZhijun.Fu@Sun.COM bus_p->bus_fm_flags = 0;
112511245SZhijun.Fu@Sun.COM bus_p->bus_mps = 0;
112610187SKrishna.Elango@Sun.COM
112711245SZhijun.Fu@Sun.COM ndi_set_bus_private(dip, B_TRUE, DEVI_PORT_TYPE_PCI, (void *)bus_p);
112811245SZhijun.Fu@Sun.COM
112911245SZhijun.Fu@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(dip))
113011245SZhijun.Fu@Sun.COM (void) ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
113110923SEvan.Yan@Sun.COM "hotplug-capable");
113210923SEvan.Yan@Sun.COM
113311245SZhijun.Fu@Sun.COM initial_done:
113411245SZhijun.Fu@Sun.COM if (!(flags & PCIE_BUS_FINAL))
113511245SZhijun.Fu@Sun.COM goto final_done;
113611245SZhijun.Fu@Sun.COM
113711245SZhijun.Fu@Sun.COM /* already initialized? */
113811245SZhijun.Fu@Sun.COM bus_p = PCIE_DIP2BUS(dip);
113911245SZhijun.Fu@Sun.COM
114011245SZhijun.Fu@Sun.COM /* Save the Range information if device is a switch/bridge */
114111245SZhijun.Fu@Sun.COM if (PCIE_IS_BDG(bus_p)) {
114211245SZhijun.Fu@Sun.COM /* get "bus_range" property */
114311245SZhijun.Fu@Sun.COM range_size = sizeof (pci_bus_range_t);
114411245SZhijun.Fu@Sun.COM if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
114511245SZhijun.Fu@Sun.COM "bus-range", (caddr_t)&bus_p->bus_bus_range, &range_size)
114611245SZhijun.Fu@Sun.COM != DDI_PROP_SUCCESS) {
114711245SZhijun.Fu@Sun.COM errstr = "Cannot find \"bus-range\" property";
114811245SZhijun.Fu@Sun.COM cmn_err(CE_WARN,
114911245SZhijun.Fu@Sun.COM "PCIE init err info failed BDF 0x%x:%s\n",
115011245SZhijun.Fu@Sun.COM bus_p->bus_bdf, errstr);
115111245SZhijun.Fu@Sun.COM }
115211245SZhijun.Fu@Sun.COM
115311245SZhijun.Fu@Sun.COM /* get secondary bus number */
115411245SZhijun.Fu@Sun.COM rcdip = pcie_get_rc_dip(dip);
115511245SZhijun.Fu@Sun.COM ASSERT(rcdip != NULL);
115610187SKrishna.Elango@Sun.COM
115711245SZhijun.Fu@Sun.COM bus_p->bus_bdg_secbus = pci_cfgacc_get8(rcdip,
115811245SZhijun.Fu@Sun.COM bus_p->bus_bdf, PCI_BCNF_SECBUS);
115911245SZhijun.Fu@Sun.COM
116011245SZhijun.Fu@Sun.COM /* Get "ranges" property */
116111245SZhijun.Fu@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
116211245SZhijun.Fu@Sun.COM "ranges", (caddr_t)&bus_p->bus_addr_ranges,
116311245SZhijun.Fu@Sun.COM &bus_p->bus_addr_entries) != DDI_PROP_SUCCESS)
116411245SZhijun.Fu@Sun.COM bus_p->bus_addr_entries = 0;
116511245SZhijun.Fu@Sun.COM bus_p->bus_addr_entries /= sizeof (ppb_ranges_t);
116611245SZhijun.Fu@Sun.COM }
116710187SKrishna.Elango@Sun.COM
116811245SZhijun.Fu@Sun.COM /* save "assigned-addresses" property array, ignore failues */
116911245SZhijun.Fu@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
117011245SZhijun.Fu@Sun.COM "assigned-addresses", (caddr_t)&bus_p->bus_assigned_addr,
117111245SZhijun.Fu@Sun.COM &bus_p->bus_assigned_entries) == DDI_PROP_SUCCESS)
117211245SZhijun.Fu@Sun.COM bus_p->bus_assigned_entries /= sizeof (pci_regspec_t);
117311245SZhijun.Fu@Sun.COM else
117411245SZhijun.Fu@Sun.COM bus_p->bus_assigned_entries = 0;
117511245SZhijun.Fu@Sun.COM
117611245SZhijun.Fu@Sun.COM pcie_init_pfd(dip);
117711245SZhijun.Fu@Sun.COM
117811245SZhijun.Fu@Sun.COM pcie_init_plat(dip);
117911245SZhijun.Fu@Sun.COM
118011245SZhijun.Fu@Sun.COM final_done:
118110187SKrishna.Elango@Sun.COM
118210187SKrishna.Elango@Sun.COM PCIE_DBG("Add %s(dip 0x%p, bdf 0x%x, secbus 0x%x)\n",
118311245SZhijun.Fu@Sun.COM ddi_driver_name(dip), (void *)dip, bus_p->bus_bdf,
118410187SKrishna.Elango@Sun.COM bus_p->bus_bdg_secbus);
118510187SKrishna.Elango@Sun.COM #ifdef DEBUG
118610187SKrishna.Elango@Sun.COM pcie_print_bus(bus_p);
118710187SKrishna.Elango@Sun.COM #endif
118810187SKrishna.Elango@Sun.COM
118910187SKrishna.Elango@Sun.COM return (bus_p);
119011245SZhijun.Fu@Sun.COM }
119111245SZhijun.Fu@Sun.COM
119211245SZhijun.Fu@Sun.COM /*
119311245SZhijun.Fu@Sun.COM * Invoked before destroying devinfo node, mostly during hotplug
119411245SZhijun.Fu@Sun.COM * operation to free pcie_bus_t data structure
119511245SZhijun.Fu@Sun.COM */
119611245SZhijun.Fu@Sun.COM /* ARGSUSED */
119711245SZhijun.Fu@Sun.COM void
pcie_fini_bus(dev_info_t * dip,uint8_t flags)119811245SZhijun.Fu@Sun.COM pcie_fini_bus(dev_info_t *dip, uint8_t flags)
119911245SZhijun.Fu@Sun.COM {
120011245SZhijun.Fu@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
120111245SZhijun.Fu@Sun.COM ASSERT(bus_p);
120211245SZhijun.Fu@Sun.COM
120311245SZhijun.Fu@Sun.COM if (flags & PCIE_BUS_INITIAL) {
120411245SZhijun.Fu@Sun.COM pcie_fini_plat(dip);
120511245SZhijun.Fu@Sun.COM pcie_fini_pfd(dip);
120611245SZhijun.Fu@Sun.COM
120711245SZhijun.Fu@Sun.COM kmem_free(bus_p->bus_assigned_addr,
120811245SZhijun.Fu@Sun.COM (sizeof (pci_regspec_t) * bus_p->bus_assigned_entries));
120911245SZhijun.Fu@Sun.COM kmem_free(bus_p->bus_addr_ranges,
121011245SZhijun.Fu@Sun.COM (sizeof (ppb_ranges_t) * bus_p->bus_addr_entries));
121111245SZhijun.Fu@Sun.COM /* zero out the fields that have been destroyed */
121211245SZhijun.Fu@Sun.COM bus_p->bus_assigned_addr = NULL;
121311245SZhijun.Fu@Sun.COM bus_p->bus_addr_ranges = NULL;
121411245SZhijun.Fu@Sun.COM bus_p->bus_assigned_entries = 0;
121511245SZhijun.Fu@Sun.COM bus_p->bus_addr_entries = 0;
121611245SZhijun.Fu@Sun.COM }
121711245SZhijun.Fu@Sun.COM
121811245SZhijun.Fu@Sun.COM if (flags & PCIE_BUS_FINAL) {
121911245SZhijun.Fu@Sun.COM if (PCIE_IS_HOTPLUG_CAPABLE(dip)) {
122011245SZhijun.Fu@Sun.COM (void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
122111245SZhijun.Fu@Sun.COM "hotplug-capable");
122211245SZhijun.Fu@Sun.COM }
122311245SZhijun.Fu@Sun.COM
122411245SZhijun.Fu@Sun.COM ndi_set_bus_private(dip, B_TRUE, NULL, NULL);
122511245SZhijun.Fu@Sun.COM kmem_free(bus_p, sizeof (pcie_bus_t));
122611245SZhijun.Fu@Sun.COM }
122710187SKrishna.Elango@Sun.COM }
122810187SKrishna.Elango@Sun.COM
122910187SKrishna.Elango@Sun.COM int
pcie_postattach_child(dev_info_t * cdip)123010187SKrishna.Elango@Sun.COM pcie_postattach_child(dev_info_t *cdip)
123110187SKrishna.Elango@Sun.COM {
123210187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(cdip);
123310187SKrishna.Elango@Sun.COM
123410187SKrishna.Elango@Sun.COM if (!bus_p)
123510187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
123610187SKrishna.Elango@Sun.COM
123710187SKrishna.Elango@Sun.COM return (pcie_enable_ce(cdip));
123810187SKrishna.Elango@Sun.COM }
123910187SKrishna.Elango@Sun.COM
124010187SKrishna.Elango@Sun.COM /*
124110187SKrishna.Elango@Sun.COM * PCI-Express child device de-initialization.
124210187SKrishna.Elango@Sun.COM * This function disables generic pci-express interrupts and error
124310187SKrishna.Elango@Sun.COM * handling.
124410187SKrishna.Elango@Sun.COM */
124510187SKrishna.Elango@Sun.COM void
pcie_uninitchild(dev_info_t * cdip)124610187SKrishna.Elango@Sun.COM pcie_uninitchild(dev_info_t *cdip)
124710187SKrishna.Elango@Sun.COM {
124810187SKrishna.Elango@Sun.COM pcie_disable_errors(cdip);
124911245SZhijun.Fu@Sun.COM pcie_fini_cfghdl(cdip);
125011596SJason.Beloro@Sun.COM pcie_fini_dom(cdip);
125111245SZhijun.Fu@Sun.COM }
125211245SZhijun.Fu@Sun.COM
125311245SZhijun.Fu@Sun.COM /*
125411245SZhijun.Fu@Sun.COM * find the root complex dip
125511245SZhijun.Fu@Sun.COM */
125611245SZhijun.Fu@Sun.COM dev_info_t *
pcie_get_rc_dip(dev_info_t * dip)125711245SZhijun.Fu@Sun.COM pcie_get_rc_dip(dev_info_t *dip)
125811245SZhijun.Fu@Sun.COM {
125911245SZhijun.Fu@Sun.COM dev_info_t *rcdip;
126011245SZhijun.Fu@Sun.COM pcie_bus_t *rc_bus_p;
126111245SZhijun.Fu@Sun.COM
126211245SZhijun.Fu@Sun.COM for (rcdip = ddi_get_parent(dip); rcdip;
126311245SZhijun.Fu@Sun.COM rcdip = ddi_get_parent(rcdip)) {
126411245SZhijun.Fu@Sun.COM rc_bus_p = PCIE_DIP2BUS(rcdip);
126511245SZhijun.Fu@Sun.COM if (rc_bus_p && PCIE_IS_RC(rc_bus_p))
126611245SZhijun.Fu@Sun.COM break;
126711245SZhijun.Fu@Sun.COM }
126811245SZhijun.Fu@Sun.COM
126911245SZhijun.Fu@Sun.COM return (rcdip);
127011245SZhijun.Fu@Sun.COM }
127111245SZhijun.Fu@Sun.COM
127211245SZhijun.Fu@Sun.COM static boolean_t
pcie_is_pci_device(dev_info_t * dip)127311245SZhijun.Fu@Sun.COM pcie_is_pci_device(dev_info_t *dip)
127411245SZhijun.Fu@Sun.COM {
127511245SZhijun.Fu@Sun.COM dev_info_t *pdip;
127611245SZhijun.Fu@Sun.COM char *device_type;
127711245SZhijun.Fu@Sun.COM
127811245SZhijun.Fu@Sun.COM pdip = ddi_get_parent(dip);
127911245SZhijun.Fu@Sun.COM ASSERT(pdip);
128011245SZhijun.Fu@Sun.COM
128111245SZhijun.Fu@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
128211245SZhijun.Fu@Sun.COM "device_type", &device_type) != DDI_PROP_SUCCESS)
128311245SZhijun.Fu@Sun.COM return (B_FALSE);
128411245SZhijun.Fu@Sun.COM
128511245SZhijun.Fu@Sun.COM if (strcmp(device_type, "pciex") != 0 &&
128611245SZhijun.Fu@Sun.COM strcmp(device_type, "pci") != 0) {
128711245SZhijun.Fu@Sun.COM ddi_prop_free(device_type);
128811245SZhijun.Fu@Sun.COM return (B_FALSE);
128911245SZhijun.Fu@Sun.COM }
129011245SZhijun.Fu@Sun.COM
129111245SZhijun.Fu@Sun.COM ddi_prop_free(device_type);
129211245SZhijun.Fu@Sun.COM return (B_TRUE);
129311245SZhijun.Fu@Sun.COM }
129411245SZhijun.Fu@Sun.COM
129511245SZhijun.Fu@Sun.COM typedef struct {
129611245SZhijun.Fu@Sun.COM boolean_t init;
129711245SZhijun.Fu@Sun.COM uint8_t flags;
129811245SZhijun.Fu@Sun.COM } pcie_bus_arg_t;
129911245SZhijun.Fu@Sun.COM
130011245SZhijun.Fu@Sun.COM /*ARGSUSED*/
130111245SZhijun.Fu@Sun.COM static int
pcie_fab_do_init_fini(dev_info_t * dip,void * arg)130211245SZhijun.Fu@Sun.COM pcie_fab_do_init_fini(dev_info_t *dip, void *arg)
130311245SZhijun.Fu@Sun.COM {
130411245SZhijun.Fu@Sun.COM pcie_req_id_t bdf;
130511245SZhijun.Fu@Sun.COM pcie_bus_arg_t *bus_arg = (pcie_bus_arg_t *)arg;
130611245SZhijun.Fu@Sun.COM
130711245SZhijun.Fu@Sun.COM if (!pcie_is_pci_device(dip))
130811245SZhijun.Fu@Sun.COM goto out;
130911245SZhijun.Fu@Sun.COM
131011245SZhijun.Fu@Sun.COM if (bus_arg->init) {
131111245SZhijun.Fu@Sun.COM if (pcie_get_bdf_from_dip(dip, &bdf) != DDI_SUCCESS)
131211245SZhijun.Fu@Sun.COM goto out;
131311245SZhijun.Fu@Sun.COM
131411245SZhijun.Fu@Sun.COM (void) pcie_init_bus(dip, bdf, bus_arg->flags);
131511245SZhijun.Fu@Sun.COM } else {
131611245SZhijun.Fu@Sun.COM (void) pcie_fini_bus(dip, bus_arg->flags);
131711245SZhijun.Fu@Sun.COM }
131811245SZhijun.Fu@Sun.COM
131911245SZhijun.Fu@Sun.COM return (DDI_WALK_CONTINUE);
132011245SZhijun.Fu@Sun.COM
132111245SZhijun.Fu@Sun.COM out:
132211245SZhijun.Fu@Sun.COM return (DDI_WALK_PRUNECHILD);
132310187SKrishna.Elango@Sun.COM }
132410187SKrishna.Elango@Sun.COM
132510187SKrishna.Elango@Sun.COM void
pcie_fab_init_bus(dev_info_t * rcdip,uint8_t flags)132611245SZhijun.Fu@Sun.COM pcie_fab_init_bus(dev_info_t *rcdip, uint8_t flags)
132710187SKrishna.Elango@Sun.COM {
132811245SZhijun.Fu@Sun.COM int circular_count;
132911245SZhijun.Fu@Sun.COM dev_info_t *dip = ddi_get_child(rcdip);
133011245SZhijun.Fu@Sun.COM pcie_bus_arg_t arg;
133110187SKrishna.Elango@Sun.COM
133211245SZhijun.Fu@Sun.COM arg.init = B_TRUE;
133311245SZhijun.Fu@Sun.COM arg.flags = flags;
133410187SKrishna.Elango@Sun.COM
133511245SZhijun.Fu@Sun.COM ndi_devi_enter(rcdip, &circular_count);
133611245SZhijun.Fu@Sun.COM ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
133711245SZhijun.Fu@Sun.COM ndi_devi_exit(rcdip, circular_count);
133811245SZhijun.Fu@Sun.COM }
133910923SEvan.Yan@Sun.COM
134011245SZhijun.Fu@Sun.COM void
pcie_fab_fini_bus(dev_info_t * rcdip,uint8_t flags)134111245SZhijun.Fu@Sun.COM pcie_fab_fini_bus(dev_info_t *rcdip, uint8_t flags)
134211245SZhijun.Fu@Sun.COM {
134311245SZhijun.Fu@Sun.COM int circular_count;
134411245SZhijun.Fu@Sun.COM dev_info_t *dip = ddi_get_child(rcdip);
134511245SZhijun.Fu@Sun.COM pcie_bus_arg_t arg;
134610923SEvan.Yan@Sun.COM
134711245SZhijun.Fu@Sun.COM arg.init = B_FALSE;
134811245SZhijun.Fu@Sun.COM arg.flags = flags;
134910187SKrishna.Elango@Sun.COM
135011245SZhijun.Fu@Sun.COM ndi_devi_enter(rcdip, &circular_count);
135111245SZhijun.Fu@Sun.COM ddi_walk_devs(dip, pcie_fab_do_init_fini, &arg);
135211245SZhijun.Fu@Sun.COM ndi_devi_exit(rcdip, circular_count);
135310187SKrishna.Elango@Sun.COM }
135410187SKrishna.Elango@Sun.COM
135510187SKrishna.Elango@Sun.COM void
pcie_enable_errors(dev_info_t * dip)135610187SKrishna.Elango@Sun.COM pcie_enable_errors(dev_info_t *dip)
135710187SKrishna.Elango@Sun.COM {
135810187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
135910187SKrishna.Elango@Sun.COM uint16_t reg16, tmp16;
136010187SKrishna.Elango@Sun.COM uint32_t reg32, tmp32;
136110187SKrishna.Elango@Sun.COM
136210187SKrishna.Elango@Sun.COM ASSERT(bus_p);
136310187SKrishna.Elango@Sun.COM
136410187SKrishna.Elango@Sun.COM /*
136510187SKrishna.Elango@Sun.COM * Clear any pending errors
136610187SKrishna.Elango@Sun.COM */
136710187SKrishna.Elango@Sun.COM pcie_clear_errors(dip);
136810187SKrishna.Elango@Sun.COM
136910187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p))
137010187SKrishna.Elango@Sun.COM return;
137110187SKrishna.Elango@Sun.COM
137210187SKrishna.Elango@Sun.COM /*
137310187SKrishna.Elango@Sun.COM * Enable Baseline Error Handling but leave CE reporting off (poweron
137410187SKrishna.Elango@Sun.COM * default).
137510187SKrishna.Elango@Sun.COM */
137610187SKrishna.Elango@Sun.COM if ((reg16 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL)) !=
137710187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) {
137810187SKrishna.Elango@Sun.COM tmp16 = (reg16 & (PCIE_DEVCTL_MAX_READ_REQ_MASK |
137910187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
138010187SKrishna.Elango@Sun.COM (pcie_devctl_default & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
138110187SKrishna.Elango@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
138210187SKrishna.Elango@Sun.COM (pcie_base_err_default & (~PCIE_DEVCTL_CE_REPORTING_EN));
138310187SKrishna.Elango@Sun.COM
138410187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, tmp16);
138510187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, reg16);
138610187SKrishna.Elango@Sun.COM }
138710187SKrishna.Elango@Sun.COM
138810187SKrishna.Elango@Sun.COM /* Enable Root Port Baseline Error Receiving */
138910187SKrishna.Elango@Sun.COM if (PCIE_IS_ROOT(bus_p) &&
139010187SKrishna.Elango@Sun.COM (reg16 = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL)) !=
139110187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) {
139210187SKrishna.Elango@Sun.COM
139310187SKrishna.Elango@Sun.COM tmp16 = pcie_serr_disable_flag ?
139410187SKrishna.Elango@Sun.COM (pcie_root_ctrl_default & ~PCIE_ROOT_SYS_ERR) :
139510187SKrishna.Elango@Sun.COM pcie_root_ctrl_default;
139610187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, tmp16);
139710187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "ROOT DEVCTL", 16, PCIE_ROOTCTL,
139810187SKrishna.Elango@Sun.COM reg16);
139910187SKrishna.Elango@Sun.COM }
140010187SKrishna.Elango@Sun.COM
140110187SKrishna.Elango@Sun.COM /*
140210187SKrishna.Elango@Sun.COM * Enable PCI-Express Advanced Error Handling if Exists
140310187SKrishna.Elango@Sun.COM */
140410187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p))
140510187SKrishna.Elango@Sun.COM return;
140610187SKrishna.Elango@Sun.COM
140710187SKrishna.Elango@Sun.COM /* Set Uncorrectable Severity */
140810187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_SERV)) !=
140910187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) {
141010187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_uce_severity;
141110187SKrishna.Elango@Sun.COM
141210187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_SERV, tmp32);
141310187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER UCE SEV", 32, PCIE_AER_UCE_SERV,
141410187SKrishna.Elango@Sun.COM reg32);
141510187SKrishna.Elango@Sun.COM }
141610187SKrishna.Elango@Sun.COM
141710187SKrishna.Elango@Sun.COM /* Enable Uncorrectable errors */
141810187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_UCE_MASK)) !=
141910187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) {
142010187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_uce_mask;
142110187SKrishna.Elango@Sun.COM
142210187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, tmp32);
142310187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER UCE MASK", 32, PCIE_AER_UCE_MASK,
142410187SKrishna.Elango@Sun.COM reg32);
142510187SKrishna.Elango@Sun.COM }
142610187SKrishna.Elango@Sun.COM
142710187SKrishna.Elango@Sun.COM /* Enable ECRC generation and checking */
142810187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
142910187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) {
143010187SKrishna.Elango@Sun.COM tmp32 = reg32 | pcie_ecrc_value;
143110187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, tmp32);
143210187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER CTL", 32, PCIE_AER_CTL, reg32);
143310187SKrishna.Elango@Sun.COM }
143410187SKrishna.Elango@Sun.COM
143510187SKrishna.Elango@Sun.COM /* Enable Secondary Uncorrectable errors if this is a bridge */
143610187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p))
143710187SKrishna.Elango@Sun.COM goto root;
143810187SKrishna.Elango@Sun.COM
143910187SKrishna.Elango@Sun.COM /* Set Uncorrectable Severity */
144010187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_SERV)) !=
144110187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) {
144210187SKrishna.Elango@Sun.COM tmp32 = pcie_aer_suce_severity;
144310187SKrishna.Elango@Sun.COM
144410187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_SERV, tmp32);
144510187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER SUCE SEV", 32, PCIE_AER_SUCE_SERV,
144610187SKrishna.Elango@Sun.COM reg32);
144710187SKrishna.Elango@Sun.COM }
144810187SKrishna.Elango@Sun.COM
144910187SKrishna.Elango@Sun.COM if ((reg32 = PCIE_AER_GET(32, bus_p, PCIE_AER_SUCE_MASK)) !=
145010187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) {
145110187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, pcie_aer_suce_mask);
145210187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER SUCE MASK", 32,
145310187SKrishna.Elango@Sun.COM PCIE_AER_SUCE_MASK, reg32);
145410187SKrishna.Elango@Sun.COM }
145510187SKrishna.Elango@Sun.COM
145610187SKrishna.Elango@Sun.COM root:
145710187SKrishna.Elango@Sun.COM /*
145810187SKrishna.Elango@Sun.COM * Enable Root Control this is a Root device
145910187SKrishna.Elango@Sun.COM */
146010187SKrishna.Elango@Sun.COM if (!PCIE_IS_ROOT(bus_p))
146110187SKrishna.Elango@Sun.COM return;
146210187SKrishna.Elango@Sun.COM
146310187SKrishna.Elango@Sun.COM if ((reg16 = PCIE_AER_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
146410187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) {
146510187SKrishna.Elango@Sun.COM PCIE_AER_PUT(16, bus_p, PCIE_AER_RE_CMD,
146610187SKrishna.Elango@Sun.COM pcie_root_error_cmd_default);
146710187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER Root Err Cmd", 16,
146810187SKrishna.Elango@Sun.COM PCIE_AER_RE_CMD, reg16);
146910187SKrishna.Elango@Sun.COM }
147010187SKrishna.Elango@Sun.COM }
147110187SKrishna.Elango@Sun.COM
147210187SKrishna.Elango@Sun.COM /*
147310187SKrishna.Elango@Sun.COM * This function is used for enabling CE reporting and setting the AER CE mask.
147410187SKrishna.Elango@Sun.COM * When called from outside the pcie module it should always be preceded by
147510187SKrishna.Elango@Sun.COM * a call to pcie_enable_errors.
147610187SKrishna.Elango@Sun.COM */
147710187SKrishna.Elango@Sun.COM int
pcie_enable_ce(dev_info_t * dip)147810187SKrishna.Elango@Sun.COM pcie_enable_ce(dev_info_t *dip)
147910187SKrishna.Elango@Sun.COM {
148010187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
148110187SKrishna.Elango@Sun.COM uint16_t device_sts, device_ctl;
148210187SKrishna.Elango@Sun.COM uint32_t tmp_pcie_aer_ce_mask;
148310187SKrishna.Elango@Sun.COM
148410187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p))
148510187SKrishna.Elango@Sun.COM return (DDI_SUCCESS);
148610187SKrishna.Elango@Sun.COM
148710187SKrishna.Elango@Sun.COM /*
148810187SKrishna.Elango@Sun.COM * The "pcie_ce_mask" property is used to control both the CE reporting
148910187SKrishna.Elango@Sun.COM * enable field in the device control register and the AER CE mask. We
149010187SKrishna.Elango@Sun.COM * leave CE reporting disabled if pcie_ce_mask is set to -1.
149110187SKrishna.Elango@Sun.COM */
149210187SKrishna.Elango@Sun.COM
149310187SKrishna.Elango@Sun.COM tmp_pcie_aer_ce_mask = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
149410187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "pcie_ce_mask", pcie_aer_ce_mask);
149510187SKrishna.Elango@Sun.COM
149610187SKrishna.Elango@Sun.COM if (tmp_pcie_aer_ce_mask == (uint32_t)-1) {
149710187SKrishna.Elango@Sun.COM /*
149810187SKrishna.Elango@Sun.COM * Nothing to do since CE reporting has already been disabled.
149910187SKrishna.Elango@Sun.COM */
150010187SKrishna.Elango@Sun.COM return (DDI_SUCCESS);
150110187SKrishna.Elango@Sun.COM }
150210187SKrishna.Elango@Sun.COM
150310187SKrishna.Elango@Sun.COM if (PCIE_HAS_AER(bus_p)) {
150410187SKrishna.Elango@Sun.COM /* Enable AER CE */
150510187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, tmp_pcie_aer_ce_mask);
150610187SKrishna.Elango@Sun.COM PCIE_DBG_AER(dip, bus_p, "AER CE MASK", 32, PCIE_AER_CE_MASK,
150710187SKrishna.Elango@Sun.COM 0);
150810187SKrishna.Elango@Sun.COM
150910187SKrishna.Elango@Sun.COM /* Clear any pending AER CE errors */
151010187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_STS, -1);
151110187SKrishna.Elango@Sun.COM }
151210187SKrishna.Elango@Sun.COM
151310187SKrishna.Elango@Sun.COM /* clear any pending CE errors */
151410187SKrishna.Elango@Sun.COM if ((device_sts = PCIE_CAP_GET(16, bus_p, PCIE_DEVSTS)) !=
151510187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16)
151610187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVSTS,
151710187SKrishna.Elango@Sun.COM device_sts & (~PCIE_DEVSTS_CE_DETECTED));
151810187SKrishna.Elango@Sun.COM
151910187SKrishna.Elango@Sun.COM /* Enable CE reporting */
152010187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
152110187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL,
152210187SKrishna.Elango@Sun.COM (device_ctl & (~PCIE_DEVCTL_ERR_MASK)) | pcie_base_err_default);
152310187SKrishna.Elango@Sun.COM PCIE_DBG_CAP(dip, bus_p, "DEVCTL", 16, PCIE_DEVCTL, device_ctl);
152410187SKrishna.Elango@Sun.COM
152510187SKrishna.Elango@Sun.COM return (DDI_SUCCESS);
152610187SKrishna.Elango@Sun.COM }
152710187SKrishna.Elango@Sun.COM
152810187SKrishna.Elango@Sun.COM /* ARGSUSED */
152910187SKrishna.Elango@Sun.COM void
pcie_disable_errors(dev_info_t * dip)153010187SKrishna.Elango@Sun.COM pcie_disable_errors(dev_info_t *dip)
153110187SKrishna.Elango@Sun.COM {
153210187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
153310187SKrishna.Elango@Sun.COM uint16_t device_ctl;
153410187SKrishna.Elango@Sun.COM uint32_t aer_reg;
153510187SKrishna.Elango@Sun.COM
153610187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE(bus_p))
153710187SKrishna.Elango@Sun.COM return;
153810187SKrishna.Elango@Sun.COM
153910187SKrishna.Elango@Sun.COM /*
154010187SKrishna.Elango@Sun.COM * Disable PCI-Express Baseline Error Handling
154110187SKrishna.Elango@Sun.COM */
154210187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
154310187SKrishna.Elango@Sun.COM device_ctl &= ~PCIE_DEVCTL_ERR_MASK;
154410187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, device_ctl);
154510187SKrishna.Elango@Sun.COM
154610187SKrishna.Elango@Sun.COM /*
154710187SKrishna.Elango@Sun.COM * Disable PCI-Express Advanced Error Handling if Exists
154810187SKrishna.Elango@Sun.COM */
154910187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p))
155010187SKrishna.Elango@Sun.COM goto root;
155110187SKrishna.Elango@Sun.COM
155210187SKrishna.Elango@Sun.COM /* Disable Uncorrectable errors */
155310187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_UCE_MASK, PCIE_AER_UCE_BITS);
155410187SKrishna.Elango@Sun.COM
155510187SKrishna.Elango@Sun.COM /* Disable Correctable errors */
155610187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CE_MASK, PCIE_AER_CE_BITS);
155710187SKrishna.Elango@Sun.COM
155810187SKrishna.Elango@Sun.COM /* Disable ECRC generation and checking */
155910187SKrishna.Elango@Sun.COM if ((aer_reg = PCIE_AER_GET(32, bus_p, PCIE_AER_CTL)) !=
156010187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL32) {
156110187SKrishna.Elango@Sun.COM aer_reg &= ~(PCIE_AER_CTL_ECRC_GEN_ENA |
156210187SKrishna.Elango@Sun.COM PCIE_AER_CTL_ECRC_CHECK_ENA);
156310187SKrishna.Elango@Sun.COM
156410187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_CTL, aer_reg);
156510187SKrishna.Elango@Sun.COM }
156610187SKrishna.Elango@Sun.COM /*
156710187SKrishna.Elango@Sun.COM * Disable Secondary Uncorrectable errors if this is a bridge
156810187SKrishna.Elango@Sun.COM */
156910187SKrishna.Elango@Sun.COM if (!PCIE_IS_PCIE_BDG(bus_p))
157010187SKrishna.Elango@Sun.COM goto root;
157110187SKrishna.Elango@Sun.COM
157210187SKrishna.Elango@Sun.COM PCIE_AER_PUT(32, bus_p, PCIE_AER_SUCE_MASK, PCIE_AER_SUCE_BITS);
157310187SKrishna.Elango@Sun.COM
157410187SKrishna.Elango@Sun.COM root:
157510187SKrishna.Elango@Sun.COM /*
157610187SKrishna.Elango@Sun.COM * disable Root Control this is a Root device
157710187SKrishna.Elango@Sun.COM */
157810187SKrishna.Elango@Sun.COM if (!PCIE_IS_ROOT(bus_p))
157910187SKrishna.Elango@Sun.COM return;
158010187SKrishna.Elango@Sun.COM
158110187SKrishna.Elango@Sun.COM if (!pcie_serr_disable_flag) {
158210187SKrishna.Elango@Sun.COM device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_ROOTCTL);
158310187SKrishna.Elango@Sun.COM device_ctl &= ~PCIE_ROOT_SYS_ERR;
158410187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_ROOTCTL, device_ctl);
158510187SKrishna.Elango@Sun.COM }
158610187SKrishna.Elango@Sun.COM
158710187SKrishna.Elango@Sun.COM if (!PCIE_HAS_AER(bus_p))
158810187SKrishna.Elango@Sun.COM return;
158910187SKrishna.Elango@Sun.COM
159010187SKrishna.Elango@Sun.COM if ((device_ctl = PCIE_CAP_GET(16, bus_p, PCIE_AER_RE_CMD)) !=
159110187SKrishna.Elango@Sun.COM PCI_CAP_EINVAL16) {
159210187SKrishna.Elango@Sun.COM device_ctl &= ~pcie_root_error_cmd_default;
159310187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_AER_RE_CMD, device_ctl);
159410187SKrishna.Elango@Sun.COM }
159510187SKrishna.Elango@Sun.COM }
159610187SKrishna.Elango@Sun.COM
159710187SKrishna.Elango@Sun.COM /*
159810187SKrishna.Elango@Sun.COM * Extract bdf from "reg" property.
159910187SKrishna.Elango@Sun.COM */
160010187SKrishna.Elango@Sun.COM int
pcie_get_bdf_from_dip(dev_info_t * dip,pcie_req_id_t * bdf)160110187SKrishna.Elango@Sun.COM pcie_get_bdf_from_dip(dev_info_t *dip, pcie_req_id_t *bdf)
160210187SKrishna.Elango@Sun.COM {
160310187SKrishna.Elango@Sun.COM pci_regspec_t *regspec;
160410187SKrishna.Elango@Sun.COM int reglen;
160510187SKrishna.Elango@Sun.COM
160610187SKrishna.Elango@Sun.COM if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
160710187SKrishna.Elango@Sun.COM "reg", (int **)®spec, (uint_t *)®len) != DDI_SUCCESS)
160810187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
160910187SKrishna.Elango@Sun.COM
161010187SKrishna.Elango@Sun.COM if (reglen < (sizeof (pci_regspec_t) / sizeof (int))) {
161110187SKrishna.Elango@Sun.COM ddi_prop_free(regspec);
161210187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
161310187SKrishna.Elango@Sun.COM }
161410187SKrishna.Elango@Sun.COM
161510187SKrishna.Elango@Sun.COM /* Get phys_hi from first element. All have same bdf. */
161610187SKrishna.Elango@Sun.COM *bdf = (regspec->pci_phys_hi & (PCI_REG_BDFR_M ^ PCI_REG_REG_M)) >> 8;
161710187SKrishna.Elango@Sun.COM
161810187SKrishna.Elango@Sun.COM ddi_prop_free(regspec);
161910187SKrishna.Elango@Sun.COM return (DDI_SUCCESS);
162010187SKrishna.Elango@Sun.COM }
162110187SKrishna.Elango@Sun.COM
162210187SKrishna.Elango@Sun.COM dev_info_t *
pcie_get_my_childs_dip(dev_info_t * dip,dev_info_t * rdip)162310187SKrishna.Elango@Sun.COM pcie_get_my_childs_dip(dev_info_t *dip, dev_info_t *rdip)
162410187SKrishna.Elango@Sun.COM {
162510187SKrishna.Elango@Sun.COM dev_info_t *cdip = rdip;
162610187SKrishna.Elango@Sun.COM
162710187SKrishna.Elango@Sun.COM for (; ddi_get_parent(cdip) != dip; cdip = ddi_get_parent(cdip))
162810187SKrishna.Elango@Sun.COM ;
162910187SKrishna.Elango@Sun.COM
163010187SKrishna.Elango@Sun.COM return (cdip);
163110187SKrishna.Elango@Sun.COM }
163210187SKrishna.Elango@Sun.COM
163310187SKrishna.Elango@Sun.COM uint32_t
pcie_get_bdf_for_dma_xfer(dev_info_t * dip,dev_info_t * rdip)163410187SKrishna.Elango@Sun.COM pcie_get_bdf_for_dma_xfer(dev_info_t *dip, dev_info_t *rdip)
163510187SKrishna.Elango@Sun.COM {
163610187SKrishna.Elango@Sun.COM dev_info_t *cdip;
163710187SKrishna.Elango@Sun.COM
163810187SKrishna.Elango@Sun.COM /*
163910187SKrishna.Elango@Sun.COM * As part of the probing, the PCI fcode interpreter may setup a DMA
164010187SKrishna.Elango@Sun.COM * request if a given card has a fcode on it using dip and rdip of the
164110923SEvan.Yan@Sun.COM * hotplug connector i.e, dip and rdip of px/pcieb driver. In this
164210187SKrishna.Elango@Sun.COM * case, return a invalid value for the bdf since we cannot get to the
164310187SKrishna.Elango@Sun.COM * bdf value of the actual device which will be initiating this DMA.
164410187SKrishna.Elango@Sun.COM */
164510187SKrishna.Elango@Sun.COM if (rdip == dip)
164610187SKrishna.Elango@Sun.COM return (PCIE_INVALID_BDF);
164710187SKrishna.Elango@Sun.COM
164810187SKrishna.Elango@Sun.COM cdip = pcie_get_my_childs_dip(dip, rdip);
164910187SKrishna.Elango@Sun.COM
165010187SKrishna.Elango@Sun.COM /*
165110187SKrishna.Elango@Sun.COM * For a given rdip, return the bdf value of dip's (px or pcieb)
165210187SKrishna.Elango@Sun.COM * immediate child or secondary bus-id if dip is a PCIe2PCI bridge.
165310187SKrishna.Elango@Sun.COM *
165410187SKrishna.Elango@Sun.COM * XXX - For now, return a invalid bdf value for all PCI and PCI-X
165510187SKrishna.Elango@Sun.COM * devices since this needs more work.
165610187SKrishna.Elango@Sun.COM */
165710187SKrishna.Elango@Sun.COM return (PCI_GET_PCIE2PCI_SECBUS(cdip) ?
165810187SKrishna.Elango@Sun.COM PCIE_INVALID_BDF : PCI_GET_BDF(cdip));
165910187SKrishna.Elango@Sun.COM }
166010187SKrishna.Elango@Sun.COM
166110187SKrishna.Elango@Sun.COM uint32_t
pcie_get_aer_uce_mask()166210187SKrishna.Elango@Sun.COM pcie_get_aer_uce_mask() {
166310187SKrishna.Elango@Sun.COM return (pcie_aer_uce_mask);
166410187SKrishna.Elango@Sun.COM }
166510187SKrishna.Elango@Sun.COM uint32_t
pcie_get_aer_ce_mask()166610187SKrishna.Elango@Sun.COM pcie_get_aer_ce_mask() {
166710187SKrishna.Elango@Sun.COM return (pcie_aer_ce_mask);
166810187SKrishna.Elango@Sun.COM }
166910187SKrishna.Elango@Sun.COM uint32_t
pcie_get_aer_suce_mask()167010187SKrishna.Elango@Sun.COM pcie_get_aer_suce_mask() {
167110187SKrishna.Elango@Sun.COM return (pcie_aer_suce_mask);
167210187SKrishna.Elango@Sun.COM }
167310187SKrishna.Elango@Sun.COM uint32_t
pcie_get_serr_mask()167410187SKrishna.Elango@Sun.COM pcie_get_serr_mask() {
167510187SKrishna.Elango@Sun.COM return (pcie_serr_disable_flag);
167610187SKrishna.Elango@Sun.COM }
167710187SKrishna.Elango@Sun.COM
167810187SKrishna.Elango@Sun.COM void
pcie_set_aer_uce_mask(uint32_t mask)167910187SKrishna.Elango@Sun.COM pcie_set_aer_uce_mask(uint32_t mask) {
168010187SKrishna.Elango@Sun.COM pcie_aer_uce_mask = mask;
168110187SKrishna.Elango@Sun.COM if (mask & PCIE_AER_UCE_UR)
168210187SKrishna.Elango@Sun.COM pcie_base_err_default &= ~PCIE_DEVCTL_UR_REPORTING_EN;
168310187SKrishna.Elango@Sun.COM else
168410187SKrishna.Elango@Sun.COM pcie_base_err_default |= PCIE_DEVCTL_UR_REPORTING_EN;
168510187SKrishna.Elango@Sun.COM
168610187SKrishna.Elango@Sun.COM if (mask & PCIE_AER_UCE_ECRC)
168710187SKrishna.Elango@Sun.COM pcie_ecrc_value = 0;
168810187SKrishna.Elango@Sun.COM }
168910187SKrishna.Elango@Sun.COM
169010187SKrishna.Elango@Sun.COM void
pcie_set_aer_ce_mask(uint32_t mask)169110187SKrishna.Elango@Sun.COM pcie_set_aer_ce_mask(uint32_t mask) {
169210187SKrishna.Elango@Sun.COM pcie_aer_ce_mask = mask;
169310187SKrishna.Elango@Sun.COM }
169410187SKrishna.Elango@Sun.COM void
pcie_set_aer_suce_mask(uint32_t mask)169510187SKrishna.Elango@Sun.COM pcie_set_aer_suce_mask(uint32_t mask) {
169610187SKrishna.Elango@Sun.COM pcie_aer_suce_mask = mask;
169710187SKrishna.Elango@Sun.COM }
169810187SKrishna.Elango@Sun.COM void
pcie_set_serr_mask(uint32_t mask)169910187SKrishna.Elango@Sun.COM pcie_set_serr_mask(uint32_t mask) {
170010187SKrishna.Elango@Sun.COM pcie_serr_disable_flag = mask;
170110187SKrishna.Elango@Sun.COM }
170210187SKrishna.Elango@Sun.COM
170310187SKrishna.Elango@Sun.COM /*
170410187SKrishna.Elango@Sun.COM * Is the rdip a child of dip. Used for checking certain CTLOPS from bubbling
170510187SKrishna.Elango@Sun.COM * up erronously. Ex. ISA ctlops to a PCI-PCI Bridge.
170610187SKrishna.Elango@Sun.COM */
170710187SKrishna.Elango@Sun.COM boolean_t
pcie_is_child(dev_info_t * dip,dev_info_t * rdip)170810187SKrishna.Elango@Sun.COM pcie_is_child(dev_info_t *dip, dev_info_t *rdip)
170910187SKrishna.Elango@Sun.COM {
171010187SKrishna.Elango@Sun.COM dev_info_t *cdip = ddi_get_child(dip);
171110187SKrishna.Elango@Sun.COM for (; cdip; cdip = ddi_get_next_sibling(cdip))
171210187SKrishna.Elango@Sun.COM if (cdip == rdip)
171310187SKrishna.Elango@Sun.COM break;
171410187SKrishna.Elango@Sun.COM return (cdip != NULL);
171510187SKrishna.Elango@Sun.COM }
171610187SKrishna.Elango@Sun.COM
171710187SKrishna.Elango@Sun.COM boolean_t
pcie_is_link_disabled(dev_info_t * dip)171810187SKrishna.Elango@Sun.COM pcie_is_link_disabled(dev_info_t *dip)
171910187SKrishna.Elango@Sun.COM {
172010187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
172110187SKrishna.Elango@Sun.COM
172210187SKrishna.Elango@Sun.COM if (PCIE_IS_PCIE(bus_p)) {
172310187SKrishna.Elango@Sun.COM if (PCIE_CAP_GET(16, bus_p, PCIE_LINKCTL) &
172410187SKrishna.Elango@Sun.COM PCIE_LINKCTL_LINK_DISABLE)
172510187SKrishna.Elango@Sun.COM return (B_TRUE);
172610187SKrishna.Elango@Sun.COM }
172710187SKrishna.Elango@Sun.COM return (B_FALSE);
172810187SKrishna.Elango@Sun.COM }
172910187SKrishna.Elango@Sun.COM
173010187SKrishna.Elango@Sun.COM /*
173110187SKrishna.Elango@Sun.COM * Initialize the MPS for a root port.
173210187SKrishna.Elango@Sun.COM *
173310187SKrishna.Elango@Sun.COM * dip - dip of root port device.
173410187SKrishna.Elango@Sun.COM */
173510187SKrishna.Elango@Sun.COM void
pcie_init_root_port_mps(dev_info_t * dip)173610187SKrishna.Elango@Sun.COM pcie_init_root_port_mps(dev_info_t *dip)
173710187SKrishna.Elango@Sun.COM {
173810187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
173910187SKrishna.Elango@Sun.COM int rp_cap, max_supported = pcie_max_mps;
174010187SKrishna.Elango@Sun.COM
174110187SKrishna.Elango@Sun.COM (void) pcie_get_fabric_mps(ddi_get_parent(dip),
174210187SKrishna.Elango@Sun.COM ddi_get_child(dip), &max_supported);
174310187SKrishna.Elango@Sun.COM
174410187SKrishna.Elango@Sun.COM rp_cap = PCI_CAP_GET16(bus_p->bus_cfg_hdl, NULL,
174510187SKrishna.Elango@Sun.COM bus_p->bus_pcie_off, PCIE_DEVCAP) &
174610187SKrishna.Elango@Sun.COM PCIE_DEVCAP_MAX_PAYLOAD_MASK;
174710187SKrishna.Elango@Sun.COM
174810187SKrishna.Elango@Sun.COM if (rp_cap < max_supported)
174910187SKrishna.Elango@Sun.COM max_supported = rp_cap;
175010187SKrishna.Elango@Sun.COM
175110187SKrishna.Elango@Sun.COM bus_p->bus_mps = max_supported;
175210187SKrishna.Elango@Sun.COM (void) pcie_initchild_mps(dip);
175310187SKrishna.Elango@Sun.COM }
175410187SKrishna.Elango@Sun.COM
175510187SKrishna.Elango@Sun.COM /*
175610187SKrishna.Elango@Sun.COM * Initialize the Maximum Payload Size of a device.
175710187SKrishna.Elango@Sun.COM *
175810187SKrishna.Elango@Sun.COM * cdip - dip of device.
175910187SKrishna.Elango@Sun.COM *
176010187SKrishna.Elango@Sun.COM * returns - DDI_SUCCESS or DDI_FAILURE
176110187SKrishna.Elango@Sun.COM */
176210187SKrishna.Elango@Sun.COM int
pcie_initchild_mps(dev_info_t * cdip)176310187SKrishna.Elango@Sun.COM pcie_initchild_mps(dev_info_t *cdip)
176410187SKrishna.Elango@Sun.COM {
176510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p;
176610187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(cdip);
176710923SEvan.Yan@Sun.COM uint8_t dev_type;
176810187SKrishna.Elango@Sun.COM
176910187SKrishna.Elango@Sun.COM bus_p = PCIE_DIP2BUS(cdip);
177010187SKrishna.Elango@Sun.COM if (bus_p == NULL) {
177110187SKrishna.Elango@Sun.COM PCIE_DBG("%s: BUS not found.\n",
177210187SKrishna.Elango@Sun.COM ddi_driver_name(cdip));
177310187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
177410187SKrishna.Elango@Sun.COM }
177510187SKrishna.Elango@Sun.COM
177610923SEvan.Yan@Sun.COM dev_type = bus_p->bus_dev_type;
177710923SEvan.Yan@Sun.COM
177810923SEvan.Yan@Sun.COM /*
177910923SEvan.Yan@Sun.COM * For ARI Devices, only function zero's MPS needs to be set.
178010923SEvan.Yan@Sun.COM */
178110923SEvan.Yan@Sun.COM if ((dev_type == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
178210923SEvan.Yan@Sun.COM (pcie_ari_is_enabled(pdip) == PCIE_ARI_FORW_ENABLED)) {
178310923SEvan.Yan@Sun.COM pcie_req_id_t child_bdf;
178410923SEvan.Yan@Sun.COM
178510923SEvan.Yan@Sun.COM if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
178610923SEvan.Yan@Sun.COM return (DDI_FAILURE);
178710923SEvan.Yan@Sun.COM if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) != 0)
178810923SEvan.Yan@Sun.COM return (DDI_SUCCESS);
178910923SEvan.Yan@Sun.COM }
179010923SEvan.Yan@Sun.COM
179112059SAlan.Adamson@Sun.COM if (PCIE_IS_PCIE(bus_p)) {
179212059SAlan.Adamson@Sun.COM int suggested_mrrs, fabric_mps;
179312059SAlan.Adamson@Sun.COM uint16_t device_mps, device_mps_cap, device_mrrs, dev_ctrl;
179410187SKrishna.Elango@Sun.COM
179512330SDaniel.Ice@Sun.COM dev_ctrl = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL);
179612059SAlan.Adamson@Sun.COM if ((fabric_mps = (PCIE_IS_RP(bus_p) ? bus_p :
179712330SDaniel.Ice@Sun.COM PCIE_DIP2BUS(pdip))->bus_mps) < 0) {
179812330SDaniel.Ice@Sun.COM dev_ctrl = (dev_ctrl & ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
179912330SDaniel.Ice@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK)) |
180012330SDaniel.Ice@Sun.COM (pcie_devctl_default &
180112330SDaniel.Ice@Sun.COM (PCIE_DEVCTL_MAX_READ_REQ_MASK |
180212330SDaniel.Ice@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK));
180312330SDaniel.Ice@Sun.COM
180412330SDaniel.Ice@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl);
180512059SAlan.Adamson@Sun.COM return (DDI_SUCCESS);
180612330SDaniel.Ice@Sun.COM }
180712059SAlan.Adamson@Sun.COM
180812059SAlan.Adamson@Sun.COM device_mps_cap = PCIE_CAP_GET(16, bus_p, PCIE_DEVCAP) &
180910187SKrishna.Elango@Sun.COM PCIE_DEVCAP_MAX_PAYLOAD_MASK;
181010187SKrishna.Elango@Sun.COM
181112059SAlan.Adamson@Sun.COM device_mrrs = (dev_ctrl & PCIE_DEVCTL_MAX_READ_REQ_MASK) >>
181212059SAlan.Adamson@Sun.COM PCIE_DEVCTL_MAX_READ_REQ_SHIFT;
181312059SAlan.Adamson@Sun.COM
181412059SAlan.Adamson@Sun.COM if (device_mps_cap < fabric_mps)
181512059SAlan.Adamson@Sun.COM device_mrrs = device_mps = device_mps_cap;
181612059SAlan.Adamson@Sun.COM else
181712059SAlan.Adamson@Sun.COM device_mps = (uint16_t)fabric_mps;
181812059SAlan.Adamson@Sun.COM
181912059SAlan.Adamson@Sun.COM suggested_mrrs = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY,
182012059SAlan.Adamson@Sun.COM cdip, DDI_PROP_DONTPASS, "suggested-mrrs", device_mrrs);
182112059SAlan.Adamson@Sun.COM
182212059SAlan.Adamson@Sun.COM if ((device_mps == fabric_mps) ||
182312059SAlan.Adamson@Sun.COM (suggested_mrrs < device_mrrs))
182412059SAlan.Adamson@Sun.COM device_mrrs = (uint16_t)suggested_mrrs;
182510187SKrishna.Elango@Sun.COM
182610187SKrishna.Elango@Sun.COM /*
182712059SAlan.Adamson@Sun.COM * Replace MPS and MRRS settings.
182810187SKrishna.Elango@Sun.COM */
182912059SAlan.Adamson@Sun.COM dev_ctrl &= ~(PCIE_DEVCTL_MAX_READ_REQ_MASK |
183012059SAlan.Adamson@Sun.COM PCIE_DEVCTL_MAX_PAYLOAD_MASK);
183110187SKrishna.Elango@Sun.COM
183212059SAlan.Adamson@Sun.COM dev_ctrl |= ((device_mrrs << PCIE_DEVCTL_MAX_READ_REQ_SHIFT) |
183312059SAlan.Adamson@Sun.COM device_mps << PCIE_DEVCTL_MAX_PAYLOAD_SHIFT);
183410187SKrishna.Elango@Sun.COM
183510187SKrishna.Elango@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL, dev_ctrl);
183610187SKrishna.Elango@Sun.COM
183712059SAlan.Adamson@Sun.COM bus_p->bus_mps = device_mps;
183810187SKrishna.Elango@Sun.COM }
183910923SEvan.Yan@Sun.COM
184010187SKrishna.Elango@Sun.COM return (DDI_SUCCESS);
184110187SKrishna.Elango@Sun.COM }
184210187SKrishna.Elango@Sun.COM
184310187SKrishna.Elango@Sun.COM /*
184410187SKrishna.Elango@Sun.COM * Scans a device tree/branch for a maximum payload size capabilities.
184510187SKrishna.Elango@Sun.COM *
184610187SKrishna.Elango@Sun.COM * rc_dip - dip of Root Complex.
184710187SKrishna.Elango@Sun.COM * dip - dip of device where scan will begin.
184810187SKrishna.Elango@Sun.COM * max_supported (IN) - maximum allowable MPS.
184910187SKrishna.Elango@Sun.COM * max_supported (OUT) - maximum payload size capability of fabric.
185010187SKrishna.Elango@Sun.COM */
185110187SKrishna.Elango@Sun.COM void
pcie_get_fabric_mps(dev_info_t * rc_dip,dev_info_t * dip,int * max_supported)185210187SKrishna.Elango@Sun.COM pcie_get_fabric_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported)
185310187SKrishna.Elango@Sun.COM {
185410187SKrishna.Elango@Sun.COM if (dip == NULL)
185510187SKrishna.Elango@Sun.COM return;
185610187SKrishna.Elango@Sun.COM
185710187SKrishna.Elango@Sun.COM /*
185810187SKrishna.Elango@Sun.COM * Perform a fabric scan to obtain Maximum Payload Capabilities
185910187SKrishna.Elango@Sun.COM */
186010187SKrishna.Elango@Sun.COM (void) pcie_scan_mps(rc_dip, dip, max_supported);
186110187SKrishna.Elango@Sun.COM
186210187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: Highest Common MPS= %x\n", max_supported);
186310187SKrishna.Elango@Sun.COM }
186410187SKrishna.Elango@Sun.COM
186510187SKrishna.Elango@Sun.COM /*
186610187SKrishna.Elango@Sun.COM * Scans fabric and determines Maximum Payload Size based on
186710187SKrishna.Elango@Sun.COM * highest common denominator alogorithm
186810187SKrishna.Elango@Sun.COM */
186910187SKrishna.Elango@Sun.COM static void
pcie_scan_mps(dev_info_t * rc_dip,dev_info_t * dip,int * max_supported)187010187SKrishna.Elango@Sun.COM pcie_scan_mps(dev_info_t *rc_dip, dev_info_t *dip, int *max_supported)
187110187SKrishna.Elango@Sun.COM {
187210187SKrishna.Elango@Sun.COM int circular_count;
187310187SKrishna.Elango@Sun.COM pcie_max_supported_t max_pay_load_supported;
187410187SKrishna.Elango@Sun.COM
187510187SKrishna.Elango@Sun.COM max_pay_load_supported.dip = rc_dip;
187610187SKrishna.Elango@Sun.COM max_pay_load_supported.highest_common_mps = *max_supported;
187710187SKrishna.Elango@Sun.COM
187810187SKrishna.Elango@Sun.COM ndi_devi_enter(ddi_get_parent(dip), &circular_count);
187910187SKrishna.Elango@Sun.COM ddi_walk_devs(dip, pcie_get_max_supported,
188010187SKrishna.Elango@Sun.COM (void *)&max_pay_load_supported);
188110187SKrishna.Elango@Sun.COM ndi_devi_exit(ddi_get_parent(dip), circular_count);
188210923SEvan.Yan@Sun.COM
188310187SKrishna.Elango@Sun.COM *max_supported = max_pay_load_supported.highest_common_mps;
188410187SKrishna.Elango@Sun.COM }
188510187SKrishna.Elango@Sun.COM
188610187SKrishna.Elango@Sun.COM /*
188710187SKrishna.Elango@Sun.COM * Called as part of the Maximum Payload Size scan.
188810187SKrishna.Elango@Sun.COM */
188910187SKrishna.Elango@Sun.COM static int
pcie_get_max_supported(dev_info_t * dip,void * arg)189010187SKrishna.Elango@Sun.COM pcie_get_max_supported(dev_info_t *dip, void *arg)
189110187SKrishna.Elango@Sun.COM {
189210187SKrishna.Elango@Sun.COM uint32_t max_supported;
189310187SKrishna.Elango@Sun.COM uint16_t cap_ptr;
189410187SKrishna.Elango@Sun.COM pcie_max_supported_t *current = (pcie_max_supported_t *)arg;
189510187SKrishna.Elango@Sun.COM pci_regspec_t *reg;
189610187SKrishna.Elango@Sun.COM int rlen;
189710187SKrishna.Elango@Sun.COM caddr_t virt;
189810187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle;
189910187SKrishna.Elango@Sun.COM
190010187SKrishna.Elango@Sun.COM if (ddi_get_child(current->dip) == NULL) {
190110187SKrishna.Elango@Sun.COM goto fail1;
190210187SKrishna.Elango@Sun.COM }
190310187SKrishna.Elango@Sun.COM
190410187SKrishna.Elango@Sun.COM if (pcie_dev(dip) == DDI_FAILURE) {
190510187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: "
190610187SKrishna.Elango@Sun.COM "Not a PCIe dev\n", ddi_driver_name(dip));
190710187SKrishna.Elango@Sun.COM goto fail1;
190810187SKrishna.Elango@Sun.COM }
190910187SKrishna.Elango@Sun.COM
191012059SAlan.Adamson@Sun.COM /*
191112059SAlan.Adamson@Sun.COM * If the suggested-mrrs property exists, then don't include this
191212059SAlan.Adamson@Sun.COM * device in the MPS capabilities scan.
191312059SAlan.Adamson@Sun.COM */
191412059SAlan.Adamson@Sun.COM if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
191512059SAlan.Adamson@Sun.COM "suggested-mrrs") != 0)
191612059SAlan.Adamson@Sun.COM goto fail1;
191712059SAlan.Adamson@Sun.COM
191810187SKrishna.Elango@Sun.COM if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
191910187SKrishna.Elango@Sun.COM (caddr_t)®, &rlen) != DDI_PROP_SUCCESS) {
192010187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: "
192110187SKrishna.Elango@Sun.COM "Can not read reg\n", ddi_driver_name(dip));
192210187SKrishna.Elango@Sun.COM goto fail1;
192310187SKrishna.Elango@Sun.COM }
192410187SKrishna.Elango@Sun.COM
192510187SKrishna.Elango@Sun.COM if (pcie_map_phys(ddi_get_child(current->dip), reg, &virt,
192610187SKrishna.Elango@Sun.COM &config_handle) != DDI_SUCCESS) {
192710187SKrishna.Elango@Sun.COM PCIE_DBG("MPS: pcie_get_max_supported: %s: pcie_map_phys "
192810187SKrishna.Elango@Sun.COM "failed\n", ddi_driver_name(dip));
192910187SKrishna.Elango@Sun.COM goto fail2;
193010187SKrishna.Elango@Sun.COM }
193110187SKrishna.Elango@Sun.COM
193210187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E, &cap_ptr)) ==
193310187SKrishna.Elango@Sun.COM DDI_FAILURE) {
193410187SKrishna.Elango@Sun.COM goto fail3;
193510187SKrishna.Elango@Sun.COM }
193610187SKrishna.Elango@Sun.COM
193710187SKrishna.Elango@Sun.COM max_supported = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
193810187SKrishna.Elango@Sun.COM PCIE_DEVCAP) & PCIE_DEVCAP_MAX_PAYLOAD_MASK;
193910187SKrishna.Elango@Sun.COM
194010187SKrishna.Elango@Sun.COM PCIE_DBG("PCIE MPS: %s: MPS Capabilities %x\n", ddi_driver_name(dip),
194110187SKrishna.Elango@Sun.COM max_supported);
194210187SKrishna.Elango@Sun.COM
194310187SKrishna.Elango@Sun.COM if (max_supported < current->highest_common_mps)
194410187SKrishna.Elango@Sun.COM current->highest_common_mps = max_supported;
194510187SKrishna.Elango@Sun.COM
194610187SKrishna.Elango@Sun.COM fail3:
194710187SKrishna.Elango@Sun.COM pcie_unmap_phys(&config_handle, reg);
194810187SKrishna.Elango@Sun.COM fail2:
194910187SKrishna.Elango@Sun.COM kmem_free(reg, rlen);
195010187SKrishna.Elango@Sun.COM fail1:
195110187SKrishna.Elango@Sun.COM return (DDI_WALK_CONTINUE);
195210187SKrishna.Elango@Sun.COM }
195310187SKrishna.Elango@Sun.COM
195410187SKrishna.Elango@Sun.COM /*
195510187SKrishna.Elango@Sun.COM * Determines if there are any root ports attached to a root complex.
195610187SKrishna.Elango@Sun.COM *
195710187SKrishna.Elango@Sun.COM * dip - dip of root complex
195810187SKrishna.Elango@Sun.COM *
195910187SKrishna.Elango@Sun.COM * Returns - DDI_SUCCESS if there is at least one root port otherwise
196010923SEvan.Yan@Sun.COM * DDI_FAILURE.
196110187SKrishna.Elango@Sun.COM */
196210187SKrishna.Elango@Sun.COM int
pcie_root_port(dev_info_t * dip)196310187SKrishna.Elango@Sun.COM pcie_root_port(dev_info_t *dip)
196410187SKrishna.Elango@Sun.COM {
196510187SKrishna.Elango@Sun.COM int port_type;
196610187SKrishna.Elango@Sun.COM uint16_t cap_ptr;
196710187SKrishna.Elango@Sun.COM ddi_acc_handle_t config_handle;
196810187SKrishna.Elango@Sun.COM dev_info_t *cdip = ddi_get_child(dip);
196910187SKrishna.Elango@Sun.COM
197010187SKrishna.Elango@Sun.COM /*
197110187SKrishna.Elango@Sun.COM * Determine if any of the children of the passed in dip
197210187SKrishna.Elango@Sun.COM * are root ports.
197310187SKrishna.Elango@Sun.COM */
197410187SKrishna.Elango@Sun.COM for (; cdip; cdip = ddi_get_next_sibling(cdip)) {
197510187SKrishna.Elango@Sun.COM
197610187SKrishna.Elango@Sun.COM if (pci_config_setup(cdip, &config_handle) != DDI_SUCCESS)
197710187SKrishna.Elango@Sun.COM continue;
197810187SKrishna.Elango@Sun.COM
197910187SKrishna.Elango@Sun.COM if ((PCI_CAP_LOCATE(config_handle, PCI_CAP_ID_PCI_E,
198010187SKrishna.Elango@Sun.COM &cap_ptr)) == DDI_FAILURE) {
198110187SKrishna.Elango@Sun.COM pci_config_teardown(&config_handle);
198210187SKrishna.Elango@Sun.COM continue;
198310187SKrishna.Elango@Sun.COM }
198410187SKrishna.Elango@Sun.COM
198510187SKrishna.Elango@Sun.COM port_type = PCI_CAP_GET16(config_handle, NULL, cap_ptr,
198610187SKrishna.Elango@Sun.COM PCIE_PCIECAP) & PCIE_PCIECAP_DEV_TYPE_MASK;
198710187SKrishna.Elango@Sun.COM
198810187SKrishna.Elango@Sun.COM pci_config_teardown(&config_handle);
198910187SKrishna.Elango@Sun.COM
199010187SKrishna.Elango@Sun.COM if (port_type == PCIE_PCIECAP_DEV_TYPE_ROOT)
199110187SKrishna.Elango@Sun.COM return (DDI_SUCCESS);
199210187SKrishna.Elango@Sun.COM }
199310187SKrishna.Elango@Sun.COM
199410187SKrishna.Elango@Sun.COM /* No root ports were found */
199510187SKrishna.Elango@Sun.COM
199610187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
199710187SKrishna.Elango@Sun.COM }
199810187SKrishna.Elango@Sun.COM
199910187SKrishna.Elango@Sun.COM /*
200010187SKrishna.Elango@Sun.COM * Function that determines if a device a PCIe device.
200110187SKrishna.Elango@Sun.COM *
200210187SKrishna.Elango@Sun.COM * dip - dip of device.
200310187SKrishna.Elango@Sun.COM *
200410187SKrishna.Elango@Sun.COM * returns - DDI_SUCCESS if device is a PCIe device, otherwise DDI_FAILURE.
200510187SKrishna.Elango@Sun.COM */
200610187SKrishna.Elango@Sun.COM int
pcie_dev(dev_info_t * dip)200710187SKrishna.Elango@Sun.COM pcie_dev(dev_info_t *dip)
200810187SKrishna.Elango@Sun.COM {
200910187SKrishna.Elango@Sun.COM /* get parent device's device_type property */
201010187SKrishna.Elango@Sun.COM char *device_type;
201110187SKrishna.Elango@Sun.COM int rc = DDI_FAILURE;
201210187SKrishna.Elango@Sun.COM dev_info_t *pdip = ddi_get_parent(dip);
201310187SKrishna.Elango@Sun.COM
201410187SKrishna.Elango@Sun.COM if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
201510187SKrishna.Elango@Sun.COM DDI_PROP_DONTPASS, "device_type", &device_type)
201610187SKrishna.Elango@Sun.COM != DDI_PROP_SUCCESS) {
201710187SKrishna.Elango@Sun.COM return (DDI_FAILURE);
201810187SKrishna.Elango@Sun.COM }
201910187SKrishna.Elango@Sun.COM
202010187SKrishna.Elango@Sun.COM if (strcmp(device_type, "pciex") == 0)
202110187SKrishna.Elango@Sun.COM rc = DDI_SUCCESS;
202210187SKrishna.Elango@Sun.COM else
202310187SKrishna.Elango@Sun.COM rc = DDI_FAILURE;
202410187SKrishna.Elango@Sun.COM
202510187SKrishna.Elango@Sun.COM ddi_prop_free(device_type);
202610187SKrishna.Elango@Sun.COM return (rc);
202710187SKrishna.Elango@Sun.COM }
202810187SKrishna.Elango@Sun.COM
202910187SKrishna.Elango@Sun.COM /*
203010187SKrishna.Elango@Sun.COM * Function to map in a device's memory space.
203110187SKrishna.Elango@Sun.COM */
203210187SKrishna.Elango@Sun.COM static int
pcie_map_phys(dev_info_t * dip,pci_regspec_t * phys_spec,caddr_t * addrp,ddi_acc_handle_t * handlep)203310187SKrishna.Elango@Sun.COM pcie_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
203410187SKrishna.Elango@Sun.COM caddr_t *addrp, ddi_acc_handle_t *handlep)
203510187SKrishna.Elango@Sun.COM {
203610187SKrishna.Elango@Sun.COM ddi_map_req_t mr;
203710187SKrishna.Elango@Sun.COM ddi_acc_hdl_t *hp;
203810187SKrishna.Elango@Sun.COM int result;
203910187SKrishna.Elango@Sun.COM ddi_device_acc_attr_t attr;
204010187SKrishna.Elango@Sun.COM
204110187SKrishna.Elango@Sun.COM attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
204210187SKrishna.Elango@Sun.COM attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
204310187SKrishna.Elango@Sun.COM attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
204410187SKrishna.Elango@Sun.COM attr.devacc_attr_access = DDI_CAUTIOUS_ACC;
204510187SKrishna.Elango@Sun.COM
204610187SKrishna.Elango@Sun.COM *handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
204710187SKrishna.Elango@Sun.COM hp = impl_acc_hdl_get(*handlep);
204810187SKrishna.Elango@Sun.COM hp->ah_vers = VERS_ACCHDL;
204910187SKrishna.Elango@Sun.COM hp->ah_dip = dip;
205010187SKrishna.Elango@Sun.COM hp->ah_rnumber = 0;
205110187SKrishna.Elango@Sun.COM hp->ah_offset = 0;
205210187SKrishna.Elango@Sun.COM hp->ah_len = 0;
205310187SKrishna.Elango@Sun.COM hp->ah_acc = attr;
205410187SKrishna.Elango@Sun.COM
205510187SKrishna.Elango@Sun.COM mr.map_op = DDI_MO_MAP_LOCKED;
205610187SKrishna.Elango@Sun.COM mr.map_type = DDI_MT_REGSPEC;
205710187SKrishna.Elango@Sun.COM mr.map_obj.rp = (struct regspec *)phys_spec;
205810187SKrishna.Elango@Sun.COM mr.map_prot = PROT_READ | PROT_WRITE;
205910187SKrishna.Elango@Sun.COM mr.map_flags = DDI_MF_KERNEL_MAPPING;
206010187SKrishna.Elango@Sun.COM mr.map_handlep = hp;
206110187SKrishna.Elango@Sun.COM mr.map_vers = DDI_MAP_VERSION;
206210187SKrishna.Elango@Sun.COM
206310187SKrishna.Elango@Sun.COM result = ddi_map(dip, &mr, 0, 0, addrp);
206410187SKrishna.Elango@Sun.COM
206510187SKrishna.Elango@Sun.COM if (result != DDI_SUCCESS) {
206610187SKrishna.Elango@Sun.COM impl_acc_hdl_free(*handlep);
206710187SKrishna.Elango@Sun.COM *handlep = (ddi_acc_handle_t)NULL;
206810187SKrishna.Elango@Sun.COM } else {
206910187SKrishna.Elango@Sun.COM hp->ah_addr = *addrp;
207010187SKrishna.Elango@Sun.COM }
207110187SKrishna.Elango@Sun.COM
207210187SKrishna.Elango@Sun.COM return (result);
207310187SKrishna.Elango@Sun.COM }
207410187SKrishna.Elango@Sun.COM
207510187SKrishna.Elango@Sun.COM /*
207610187SKrishna.Elango@Sun.COM * Map out memory that was mapped in with pcie_map_phys();
207710187SKrishna.Elango@Sun.COM */
207810187SKrishna.Elango@Sun.COM static void
pcie_unmap_phys(ddi_acc_handle_t * handlep,pci_regspec_t * ph)207910187SKrishna.Elango@Sun.COM pcie_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph)
208010187SKrishna.Elango@Sun.COM {
208110187SKrishna.Elango@Sun.COM ddi_map_req_t mr;
208210187SKrishna.Elango@Sun.COM ddi_acc_hdl_t *hp;
208310187SKrishna.Elango@Sun.COM
208410187SKrishna.Elango@Sun.COM hp = impl_acc_hdl_get(*handlep);
208510187SKrishna.Elango@Sun.COM ASSERT(hp);
208610187SKrishna.Elango@Sun.COM
208710187SKrishna.Elango@Sun.COM mr.map_op = DDI_MO_UNMAP;
208810187SKrishna.Elango@Sun.COM mr.map_type = DDI_MT_REGSPEC;
208910187SKrishna.Elango@Sun.COM mr.map_obj.rp = (struct regspec *)ph;
209010187SKrishna.Elango@Sun.COM mr.map_prot = PROT_READ | PROT_WRITE;
209110187SKrishna.Elango@Sun.COM mr.map_flags = DDI_MF_KERNEL_MAPPING;
209210187SKrishna.Elango@Sun.COM mr.map_handlep = hp;
209310187SKrishna.Elango@Sun.COM mr.map_vers = DDI_MAP_VERSION;
209410187SKrishna.Elango@Sun.COM
209510187SKrishna.Elango@Sun.COM (void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
209610187SKrishna.Elango@Sun.COM hp->ah_len, &hp->ah_addr);
209710187SKrishna.Elango@Sun.COM
209810187SKrishna.Elango@Sun.COM impl_acc_hdl_free(*handlep);
209910187SKrishna.Elango@Sun.COM *handlep = (ddi_acc_handle_t)NULL;
210010187SKrishna.Elango@Sun.COM }
210110187SKrishna.Elango@Sun.COM
210210187SKrishna.Elango@Sun.COM void
pcie_set_rber_fatal(dev_info_t * dip,boolean_t val)210310187SKrishna.Elango@Sun.COM pcie_set_rber_fatal(dev_info_t *dip, boolean_t val)
210410187SKrishna.Elango@Sun.COM {
210510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
210610187SKrishna.Elango@Sun.COM bus_p->bus_pfd->pe_rber_fatal = val;
210710187SKrishna.Elango@Sun.COM }
210810187SKrishna.Elango@Sun.COM
210910187SKrishna.Elango@Sun.COM /*
211010187SKrishna.Elango@Sun.COM * Return parent Root Port's pe_rber_fatal value.
211110187SKrishna.Elango@Sun.COM */
211210187SKrishna.Elango@Sun.COM boolean_t
pcie_get_rber_fatal(dev_info_t * dip)211310187SKrishna.Elango@Sun.COM pcie_get_rber_fatal(dev_info_t *dip)
211410187SKrishna.Elango@Sun.COM {
211510187SKrishna.Elango@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2UPBUS(dip);
211610187SKrishna.Elango@Sun.COM pcie_bus_t *rp_bus_p = PCIE_DIP2UPBUS(bus_p->bus_rp_dip);
211710187SKrishna.Elango@Sun.COM return (rp_bus_p->bus_pfd->pe_rber_fatal);
211810187SKrishna.Elango@Sun.COM }
211910187SKrishna.Elango@Sun.COM
212010923SEvan.Yan@Sun.COM int
pcie_ari_supported(dev_info_t * dip)212110923SEvan.Yan@Sun.COM pcie_ari_supported(dev_info_t *dip)
212210923SEvan.Yan@Sun.COM {
212310923SEvan.Yan@Sun.COM uint32_t devcap2;
212410923SEvan.Yan@Sun.COM uint16_t pciecap;
212510923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
212610923SEvan.Yan@Sun.COM uint8_t dev_type;
212710923SEvan.Yan@Sun.COM
212810923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p\n", dip);
212910923SEvan.Yan@Sun.COM
213010923SEvan.Yan@Sun.COM if (bus_p == NULL)
213110923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED);
213210923SEvan.Yan@Sun.COM
213310923SEvan.Yan@Sun.COM dev_type = bus_p->bus_dev_type;
213410923SEvan.Yan@Sun.COM
213510923SEvan.Yan@Sun.COM if ((dev_type != PCIE_PCIECAP_DEV_TYPE_DOWN) &&
213610923SEvan.Yan@Sun.COM (dev_type != PCIE_PCIECAP_DEV_TYPE_ROOT))
213710923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED);
213810923SEvan.Yan@Sun.COM
213910923SEvan.Yan@Sun.COM if (pcie_disable_ari) {
214010923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: ARI Disabled\n", dip);
214110923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED);
214210923SEvan.Yan@Sun.COM }
214310923SEvan.Yan@Sun.COM
214410923SEvan.Yan@Sun.COM pciecap = PCIE_CAP_GET(16, bus_p, PCIE_PCIECAP);
214510923SEvan.Yan@Sun.COM
214610923SEvan.Yan@Sun.COM if ((pciecap & PCIE_PCIECAP_VER_MASK) < PCIE_PCIECAP_VER_2_0) {
214710923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: Not 2.0\n", dip);
214810923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED);
214910923SEvan.Yan@Sun.COM }
215010923SEvan.Yan@Sun.COM
215110923SEvan.Yan@Sun.COM devcap2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCAP2);
215210923SEvan.Yan@Sun.COM
215310923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: dip=%p: DevCap2=0x%x\n",
215410923SEvan.Yan@Sun.COM dip, devcap2);
215510923SEvan.Yan@Sun.COM
215610923SEvan.Yan@Sun.COM if (devcap2 & PCIE_DEVCAP2_ARI_FORWARD) {
215710923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_supported: "
215810923SEvan.Yan@Sun.COM "dip=%p: ARI Forwarding is supported\n", dip);
215910923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_SUPPORTED);
216010923SEvan.Yan@Sun.COM }
216110923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_NOT_SUPPORTED);
216210923SEvan.Yan@Sun.COM }
216310923SEvan.Yan@Sun.COM
216410923SEvan.Yan@Sun.COM int
pcie_ari_enable(dev_info_t * dip)216510923SEvan.Yan@Sun.COM pcie_ari_enable(dev_info_t *dip)
216610923SEvan.Yan@Sun.COM {
216710923SEvan.Yan@Sun.COM uint16_t devctl2;
216810923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
216910923SEvan.Yan@Sun.COM
217010923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_enable: dip=%p\n", dip);
217110923SEvan.Yan@Sun.COM
217210923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
217310923SEvan.Yan@Sun.COM return (DDI_FAILURE);
217410923SEvan.Yan@Sun.COM
217510923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
217610923SEvan.Yan@Sun.COM devctl2 |= PCIE_DEVCTL2_ARI_FORWARD_EN;
217710923SEvan.Yan@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
217810923SEvan.Yan@Sun.COM
217910923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_enable: dip=%p: writing 0x%x to DevCtl2\n",
218010923SEvan.Yan@Sun.COM dip, devctl2);
218110923SEvan.Yan@Sun.COM
218210923SEvan.Yan@Sun.COM return (DDI_SUCCESS);
218310923SEvan.Yan@Sun.COM }
218410923SEvan.Yan@Sun.COM
218510923SEvan.Yan@Sun.COM int
pcie_ari_disable(dev_info_t * dip)218610923SEvan.Yan@Sun.COM pcie_ari_disable(dev_info_t *dip)
218710923SEvan.Yan@Sun.COM {
218810923SEvan.Yan@Sun.COM uint16_t devctl2;
218910923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
219010923SEvan.Yan@Sun.COM
219110923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_disable: dip=%p\n", dip);
219210923SEvan.Yan@Sun.COM
219310923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
219410923SEvan.Yan@Sun.COM return (DDI_FAILURE);
219510923SEvan.Yan@Sun.COM
219610923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(16, bus_p, PCIE_DEVCTL2);
219710923SEvan.Yan@Sun.COM devctl2 &= ~PCIE_DEVCTL2_ARI_FORWARD_EN;
219810923SEvan.Yan@Sun.COM PCIE_CAP_PUT(16, bus_p, PCIE_DEVCTL2, devctl2);
219910923SEvan.Yan@Sun.COM
220010923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_disable: dip=%p: writing 0x%x to DevCtl2\n",
220110923SEvan.Yan@Sun.COM dip, devctl2);
220210923SEvan.Yan@Sun.COM
220310923SEvan.Yan@Sun.COM return (DDI_SUCCESS);
220410923SEvan.Yan@Sun.COM }
220510923SEvan.Yan@Sun.COM
220610923SEvan.Yan@Sun.COM int
pcie_ari_is_enabled(dev_info_t * dip)220710923SEvan.Yan@Sun.COM pcie_ari_is_enabled(dev_info_t *dip)
220810923SEvan.Yan@Sun.COM {
220910923SEvan.Yan@Sun.COM uint16_t devctl2;
221010923SEvan.Yan@Sun.COM pcie_bus_t *bus_p = PCIE_DIP2BUS(dip);
221110923SEvan.Yan@Sun.COM
221210923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: dip=%p\n", dip);
221310923SEvan.Yan@Sun.COM
221410923SEvan.Yan@Sun.COM if (pcie_ari_supported(dip) == PCIE_ARI_FORW_NOT_SUPPORTED)
221510923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_DISABLED);
221610923SEvan.Yan@Sun.COM
221710923SEvan.Yan@Sun.COM devctl2 = PCIE_CAP_GET(32, bus_p, PCIE_DEVCTL2);
221810923SEvan.Yan@Sun.COM
221910923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: dip=%p: DevCtl2=0x%x\n",
222010923SEvan.Yan@Sun.COM dip, devctl2);
222110923SEvan.Yan@Sun.COM
222210923SEvan.Yan@Sun.COM if (devctl2 & PCIE_DEVCTL2_ARI_FORWARD_EN) {
222310923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_is_enabled: "
222410923SEvan.Yan@Sun.COM "dip=%p: ARI Forwarding is enabled\n", dip);
222510923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_ENABLED);
222610923SEvan.Yan@Sun.COM }
222710923SEvan.Yan@Sun.COM
222810923SEvan.Yan@Sun.COM return (PCIE_ARI_FORW_DISABLED);
222910923SEvan.Yan@Sun.COM }
223010923SEvan.Yan@Sun.COM
223110923SEvan.Yan@Sun.COM int
pcie_ari_device(dev_info_t * dip)223210923SEvan.Yan@Sun.COM pcie_ari_device(dev_info_t *dip)
223310923SEvan.Yan@Sun.COM {
223410923SEvan.Yan@Sun.COM ddi_acc_handle_t handle;
223510923SEvan.Yan@Sun.COM uint16_t cap_ptr;
223610923SEvan.Yan@Sun.COM
223710923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_device: dip=%p\n", dip);
223810923SEvan.Yan@Sun.COM
223910923SEvan.Yan@Sun.COM /*
224010923SEvan.Yan@Sun.COM * XXX - This function may be called before the bus_p structure
224110923SEvan.Yan@Sun.COM * has been populated. This code can be changed to remove
224210923SEvan.Yan@Sun.COM * pci_config_setup()/pci_config_teardown() when the RFE
224310923SEvan.Yan@Sun.COM * to populate the bus_p structures early in boot is putback.
224410923SEvan.Yan@Sun.COM */
224510923SEvan.Yan@Sun.COM
224610923SEvan.Yan@Sun.COM /* First make sure it is a PCIe device */
224710923SEvan.Yan@Sun.COM
224810923SEvan.Yan@Sun.COM if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
224910923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE);
225010923SEvan.Yan@Sun.COM
225110923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_ID_PCI_E, &cap_ptr))
225210923SEvan.Yan@Sun.COM != DDI_SUCCESS) {
225310923SEvan.Yan@Sun.COM pci_config_teardown(&handle);
225410923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE);
225510923SEvan.Yan@Sun.COM }
225610923SEvan.Yan@Sun.COM
225710923SEvan.Yan@Sun.COM /* Locate the ARI Capability */
225810923SEvan.Yan@Sun.COM
225910923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle, PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI),
226010923SEvan.Yan@Sun.COM &cap_ptr)) == DDI_FAILURE) {
226110923SEvan.Yan@Sun.COM pci_config_teardown(&handle);
226210923SEvan.Yan@Sun.COM return (PCIE_NOT_ARI_DEVICE);
226310923SEvan.Yan@Sun.COM }
226410923SEvan.Yan@Sun.COM
226510923SEvan.Yan@Sun.COM /* ARI Capability was found so it must be a ARI device */
226610923SEvan.Yan@Sun.COM PCIE_DBG("pcie_ari_device: ARI Device dip=%p\n", dip);
226710923SEvan.Yan@Sun.COM
226810923SEvan.Yan@Sun.COM pci_config_teardown(&handle);
226910923SEvan.Yan@Sun.COM return (PCIE_ARI_DEVICE);
227010923SEvan.Yan@Sun.COM }
227110923SEvan.Yan@Sun.COM
227210923SEvan.Yan@Sun.COM int
pcie_ari_get_next_function(dev_info_t * dip,int * func)227310923SEvan.Yan@Sun.COM pcie_ari_get_next_function(dev_info_t *dip, int *func)
227410923SEvan.Yan@Sun.COM {
227510923SEvan.Yan@Sun.COM uint32_t val;
227610923SEvan.Yan@Sun.COM uint16_t cap_ptr, next_function;
227710923SEvan.Yan@Sun.COM ddi_acc_handle_t handle;
227810923SEvan.Yan@Sun.COM
227910923SEvan.Yan@Sun.COM /*
228010923SEvan.Yan@Sun.COM * XXX - This function may be called before the bus_p structure
228110923SEvan.Yan@Sun.COM * has been populated. This code can be changed to remove
228210923SEvan.Yan@Sun.COM * pci_config_setup()/pci_config_teardown() when the RFE
228310923SEvan.Yan@Sun.COM * to populate the bus_p structures early in boot is putback.
228410923SEvan.Yan@Sun.COM */
228510923SEvan.Yan@Sun.COM
228610923SEvan.Yan@Sun.COM if (pci_config_setup(dip, &handle) != DDI_SUCCESS)
228710923SEvan.Yan@Sun.COM return (DDI_FAILURE);
228810923SEvan.Yan@Sun.COM
228910923SEvan.Yan@Sun.COM if ((PCI_CAP_LOCATE(handle,
229010923SEvan.Yan@Sun.COM PCI_CAP_XCFG_SPC(PCIE_EXT_CAP_ID_ARI), &cap_ptr)) == DDI_FAILURE) {
229110923SEvan.Yan@Sun.COM pci_config_teardown(&handle);
229210923SEvan.Yan@Sun.COM return (DDI_FAILURE);
229310923SEvan.Yan@Sun.COM }
229410923SEvan.Yan@Sun.COM
229510923SEvan.Yan@Sun.COM val = PCI_CAP_GET32(handle, NULL, cap_ptr, PCIE_ARI_CAP);
229610923SEvan.Yan@Sun.COM
229710923SEvan.Yan@Sun.COM next_function = (val >> PCIE_ARI_CAP_NEXT_FUNC_SHIFT) &
229810923SEvan.Yan@Sun.COM PCIE_ARI_CAP_NEXT_FUNC_MASK;
229910923SEvan.Yan@Sun.COM
230010923SEvan.Yan@Sun.COM pci_config_teardown(&handle);
230110923SEvan.Yan@Sun.COM
230210923SEvan.Yan@Sun.COM *func = next_function;
230310923SEvan.Yan@Sun.COM
230410923SEvan.Yan@Sun.COM return (DDI_SUCCESS);
230510923SEvan.Yan@Sun.COM }
230610923SEvan.Yan@Sun.COM
230710923SEvan.Yan@Sun.COM dev_info_t *
pcie_func_to_dip(dev_info_t * dip,pcie_req_id_t function)230810923SEvan.Yan@Sun.COM pcie_func_to_dip(dev_info_t *dip, pcie_req_id_t function)
230910923SEvan.Yan@Sun.COM {
231010923SEvan.Yan@Sun.COM pcie_req_id_t child_bdf;
231110923SEvan.Yan@Sun.COM dev_info_t *cdip;
231210923SEvan.Yan@Sun.COM
231310923SEvan.Yan@Sun.COM for (cdip = ddi_get_child(dip); cdip;
231410923SEvan.Yan@Sun.COM cdip = ddi_get_next_sibling(cdip)) {
231510923SEvan.Yan@Sun.COM
231610923SEvan.Yan@Sun.COM if (pcie_get_bdf_from_dip(cdip, &child_bdf) == DDI_FAILURE)
231710923SEvan.Yan@Sun.COM return (NULL);
231810923SEvan.Yan@Sun.COM
231910923SEvan.Yan@Sun.COM if ((child_bdf & PCIE_REQ_ID_ARI_FUNC_MASK) == function)
232010923SEvan.Yan@Sun.COM return (cdip);
232110923SEvan.Yan@Sun.COM }
232210923SEvan.Yan@Sun.COM return (NULL);
232310923SEvan.Yan@Sun.COM }
232410923SEvan.Yan@Sun.COM
232510187SKrishna.Elango@Sun.COM #ifdef DEBUG
232610187SKrishna.Elango@Sun.COM
232710187SKrishna.Elango@Sun.COM static void
pcie_print_bus(pcie_bus_t * bus_p)232810187SKrishna.Elango@Sun.COM pcie_print_bus(pcie_bus_t *bus_p)
232910187SKrishna.Elango@Sun.COM {
233010187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dip = 0x%p\n", bus_p->bus_dip);
233110187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_fm_flags = 0x%x\n", bus_p->bus_fm_flags);
233210187SKrishna.Elango@Sun.COM
233310187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_bdf = 0x%x\n", bus_p->bus_bdf);
233410187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dev_ven_id = 0x%x\n", bus_p->bus_dev_ven_id);
233510187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_rev_id = 0x%x\n", bus_p->bus_rev_id);
233610187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_hdr_type = 0x%x\n", bus_p->bus_hdr_type);
233710187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_dev_type = 0x%x\n", bus_p->bus_dev_type);
233810187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_bdg_secbus = 0x%x\n", bus_p->bus_bdg_secbus);
233910187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_pcie_off = 0x%x\n", bus_p->bus_pcie_off);
234010187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_aer_off = 0x%x\n", bus_p->bus_aer_off);
234110187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_pcix_off = 0x%x\n", bus_p->bus_pcix_off);
234210187SKrishna.Elango@Sun.COM pcie_dbg("\tbus_ecc_ver = 0x%x\n", bus_p->bus_ecc_ver);
234310187SKrishna.Elango@Sun.COM }
234410187SKrishna.Elango@Sun.COM
234510187SKrishna.Elango@Sun.COM /*
234610187SKrishna.Elango@Sun.COM * For debugging purposes set pcie_dbg_print != 0 to see printf messages
234710187SKrishna.Elango@Sun.COM * during interrupt.
234810187SKrishna.Elango@Sun.COM *
234910187SKrishna.Elango@Sun.COM * When a proper solution is in place this code will disappear.
235010187SKrishna.Elango@Sun.COM * Potential solutions are:
235110187SKrishna.Elango@Sun.COM * o circular buffers
235210187SKrishna.Elango@Sun.COM * o taskq to print at lower pil
235310187SKrishna.Elango@Sun.COM */
235410187SKrishna.Elango@Sun.COM int pcie_dbg_print = 0;
235510187SKrishna.Elango@Sun.COM void
pcie_dbg(char * fmt,...)235610187SKrishna.Elango@Sun.COM pcie_dbg(char *fmt, ...)
235710187SKrishna.Elango@Sun.COM {
235810187SKrishna.Elango@Sun.COM va_list ap;
235910187SKrishna.Elango@Sun.COM
236010187SKrishna.Elango@Sun.COM if (!pcie_debug_flags) {
236110187SKrishna.Elango@Sun.COM return;
236210187SKrishna.Elango@Sun.COM }
236310187SKrishna.Elango@Sun.COM va_start(ap, fmt);
236410187SKrishna.Elango@Sun.COM if (servicing_interrupt()) {
236510187SKrishna.Elango@Sun.COM if (pcie_dbg_print) {
236610187SKrishna.Elango@Sun.COM prom_vprintf(fmt, ap);
236710187SKrishna.Elango@Sun.COM }
236810187SKrishna.Elango@Sun.COM } else {
236910187SKrishna.Elango@Sun.COM prom_vprintf(fmt, ap);
237010187SKrishna.Elango@Sun.COM }
237110187SKrishna.Elango@Sun.COM va_end(ap);
237210187SKrishna.Elango@Sun.COM }
237310187SKrishna.Elango@Sun.COM #endif /* DEBUG */
237410187SKrishna.Elango@Sun.COM
237510187SKrishna.Elango@Sun.COM #if defined(__i386) || defined(__amd64)
237610187SKrishna.Elango@Sun.COM static void
pcie_check_io_mem_range(ddi_acc_handle_t cfg_hdl,boolean_t * empty_io_range,boolean_t * empty_mem_range)237710187SKrishna.Elango@Sun.COM pcie_check_io_mem_range(ddi_acc_handle_t cfg_hdl, boolean_t *empty_io_range,
237810187SKrishna.Elango@Sun.COM boolean_t *empty_mem_range)
237910187SKrishna.Elango@Sun.COM {
238010187SKrishna.Elango@Sun.COM uint8_t class, subclass;
238110187SKrishna.Elango@Sun.COM uint_t val;
238210187SKrishna.Elango@Sun.COM
238310187SKrishna.Elango@Sun.COM class = pci_config_get8(cfg_hdl, PCI_CONF_BASCLASS);
238410187SKrishna.Elango@Sun.COM subclass = pci_config_get8(cfg_hdl, PCI_CONF_SUBCLASS);
238510187SKrishna.Elango@Sun.COM
238610187SKrishna.Elango@Sun.COM if ((class == PCI_CLASS_BRIDGE) && (subclass == PCI_BRIDGE_PCI)) {
238710187SKrishna.Elango@Sun.COM val = (((uint_t)pci_config_get8(cfg_hdl, PCI_BCNF_IO_BASE_LOW) &
238810187SKrishna.Elango@Sun.COM PCI_BCNF_IO_MASK) << 8);
238910187SKrishna.Elango@Sun.COM /*
239010187SKrishna.Elango@Sun.COM * Assuming that a zero based io_range[0] implies an
239110187SKrishna.Elango@Sun.COM * invalid I/O range. Likewise for mem_range[0].
239210187SKrishna.Elango@Sun.COM */
239310187SKrishna.Elango@Sun.COM if (val == 0)
239410187SKrishna.Elango@Sun.COM *empty_io_range = B_TRUE;
239510187SKrishna.Elango@Sun.COM val = (((uint_t)pci_config_get16(cfg_hdl, PCI_BCNF_MEM_BASE) &
239610187SKrishna.Elango@Sun.COM PCI_BCNF_MEM_MASK) << 16);
239710187SKrishna.Elango@Sun.COM if (val == 0)
239810187SKrishna.Elango@Sun.COM *empty_mem_range = B_TRUE;
239910187SKrishna.Elango@Sun.COM }
240010187SKrishna.Elango@Sun.COM }
240111245SZhijun.Fu@Sun.COM
240210187SKrishna.Elango@Sun.COM #endif /* defined(__i386) || defined(__amd64) */
2403