diff options
Diffstat (limited to 'usr/src/uts/i86pc/io')
-rw-r--r-- | usr/src/uts/i86pc/io/pci/pci.c | 9 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/pciex/npe.c | 139 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/pciex/npe_misc.c | 29 |
3 files changed, 142 insertions, 35 deletions
diff --git a/usr/src/uts/i86pc/io/pci/pci.c b/usr/src/uts/i86pc/io/pci/pci.c index 7cd0b38d4e..4c34aa4db2 100644 --- a/usr/src/uts/i86pc/io/pci/pci.c +++ b/usr/src/uts/i86pc/io/pci/pci.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -102,6 +102,7 @@ static int pci_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); static int pci_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *, caddr_t, int *); static int pci_info(dev_info_t *, ddi_info_cmd_t, void *, void **); +static void pci_peekpoke_cb(dev_info_t *, ddi_fm_error_t *); struct cb_ops pci_cb_ops = { pci_open, /* open */ @@ -594,7 +595,7 @@ pci_ctlops(dev_info_t *dip, dev_info_t *rdip, pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip)); return (pci_peekpoke_check(dip, rdip, ctlop, arg, result, pci_common_peekpoke, &pcip->pci_err_mutex, - &pcip->pci_peek_poke_mutex)); + &pcip->pci_peek_poke_mutex, pci_peekpoke_cb)); /* for now only X86 systems support PME wakeup from suspended state */ case DDI_CTLOPS_ATTACH: @@ -792,6 +793,10 @@ pci_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) return (pcihp_info(dip, cmd, arg, result)); } +void pci_peekpoke_cb(dev_info_t *dip, ddi_fm_error_t *derr) { + (void) pci_ereport_post(dip, derr, NULL); +} + /*ARGSUSED*/ static int pci_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap, diff --git a/usr/src/uts/i86pc/io/pciex/npe.c b/usr/src/uts/i86pc/io/pciex/npe.c index fde4276cc7..3ca09deb31 100644 --- a/usr/src/uts/i86pc/io/pciex/npe.c +++ b/usr/src/uts/i86pc/io/pciex/npe.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,8 +32,8 @@ #include <sys/conf.h> #include <sys/modctl.h> -#include <sys/pcie.h> #include <sys/pci_impl.h> +#include <sys/pcie_impl.h> #include <sys/sysmacros.h> #include <sys/ddi_intr.h> #include <sys/sunndi.h> @@ -42,9 +42,9 @@ #include <sys/ndifm.h> #include <sys/fm/util.h> #include <sys/hotplug/pci/pcihp.h> -#include <io/pci/pci_common.h> #include <io/pci/pci_tools_ext.h> -#include <io/pciex/pcie_error.h> +#include <io/pci/pci_common.h> +#include <io/pciex/pcie_nvidia.h> /* * Bus Operation functions @@ -60,6 +60,16 @@ static int npe_fm_init(dev_info_t *, dev_info_t *, int, static int npe_fm_callback(dev_info_t *, ddi_fm_error_t *, const void *); +/* + * Disable URs and Received MA for all PCIe devices. Until x86 SW is changed so + * that random drivers do not do PIO accesses on devices that it does not own, + * these error bits must be disabled. SERR must also be disabled if URs have + * been masked. + */ +uint32_t npe_aer_uce_mask = PCIE_AER_UCE_UR; +uint32_t npe_aer_ce_mask = 0; +uint32_t npe_aer_suce_mask = PCIE_AER_SUCE_RCVD_MA; + struct bus_ops npe_bus_ops = { BUSO_REV, npe_bus_map, @@ -158,6 +168,7 @@ static int npe_initchild(dev_info_t *child); extern void npe_query_acpi_mcfg(dev_info_t *dip); extern void npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl); extern int npe_disable_empty_bridges_workaround(dev_info_t *child); +extern void npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl); /* * Module linkage information for the kernel. @@ -177,7 +188,6 @@ static struct modlinkage modlinkage = { /* Save minimal state. */ void *npe_statep; - int _init(void) { @@ -244,6 +254,8 @@ npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) pcip->pci_dip = devi; + pcie_rc_init_bus(devi); + /* * Initialize hotplug support on this bus. At minimum * (for non hotplug bus) this would create ":devctl" minor @@ -262,12 +274,17 @@ npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) ddi_soft_state_free(npe_statep, instance); return (DDI_FAILURE); } + pcip->pci_fmcap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE | DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE; ddi_fm_init(devi, &pcip->pci_fmcap, &pcip->pci_fm_ibc); - if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) + if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) { ddi_fm_handler_register(devi, npe_fm_callback, NULL); + } + + PCIE_DIP2PFD(devi) = kmem_zalloc(sizeof (pf_data_t), KM_SLEEP); + pcie_rc_init_pfd(devi, PCIE_DIP2PFD(devi)); npe_query_acpi_mcfg(devi); ddi_report_dev(devi); @@ -275,7 +292,6 @@ npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) } - /*ARGSUSED*/ static int npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) @@ -299,6 +315,10 @@ npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) ddi_fm_handler_unregister(devi); + pcie_rc_fini_bus(devi); + pcie_rc_fini_pfd(PCIE_DIP2PFD(devi)); + kmem_free(PCIE_DIP2PFD(devi), sizeof (pf_data_t)); + ddi_fm_fini(devi); ddi_soft_state_free(npe_statep, instance); return (DDI_SUCCESS); @@ -610,7 +630,10 @@ npe_ctlops(dev_info_t *dip, dev_info_t *rdip, int totreg; uint_t reglen; pci_regspec_t *drv_regp; - struct attachspec *asp; + struct attachspec *asp; + struct detachspec *dsp; + pci_state_t *pci_p = ddi_get_soft_state(npe_statep, + ddi_get_instance(dip)); switch (ctlop) { case DDI_CTLOPS_REPORTDEV: @@ -677,7 +700,15 @@ npe_ctlops(dev_info_t *dip, dev_info_t *rdip, /* X86 systems support PME wakeup from suspended state */ case DDI_CTLOPS_ATTACH: + if (!pcie_is_child(dip, rdip)) + return (DDI_SUCCESS); + asp = (struct attachspec *)arg; + if ((asp->when == DDI_POST) && (asp->result == DDI_SUCCESS)) { + pf_init(rdip, (void *)pci_p->pci_fm_ibc, asp->cmd); + (void) pcie_postattach_child(rdip); + } + /* only do this for immediate children */ if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE && ddi_get_parent(rdip) == dip) @@ -688,16 +719,25 @@ npe_ctlops(dev_info_t *dip, dev_info_t *rdip, (void *) dip); /* NOTREACHED */ } - return (ddi_ctlops(dip, rdip, ctlop, arg, result)); + + return (DDI_SUCCESS); case DDI_CTLOPS_DETACH: - asp = (struct attachspec *)arg; + if (!pcie_is_child(dip, rdip)) + return (DDI_SUCCESS); + + dsp = (struct detachspec *)arg; + + if (dsp->when == DDI_PRE) + pf_fini(rdip, dsp->cmd); + /* only do this for immediate children */ - if (asp->cmd == DDI_SUSPEND && asp->when == DDI_POST && + if (dsp->cmd == DDI_SUSPEND && dsp->when == DDI_POST && ddi_get_parent(rdip) == dip) if (pci_post_suspend(rdip) != DDI_SUCCESS) return (DDI_FAILURE); - return (ddi_ctlops(dip, rdip, ctlop, arg, result)); + + return (DDI_SUCCESS); default: break; @@ -722,7 +762,9 @@ npe_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, static int npe_initchild(dev_info_t *child) { - char name[80]; + char name[80]; + pcie_bus_t *bus_p; + uint32_t regs; ddi_acc_handle_t cfg_hdl; /* @@ -797,15 +839,55 @@ npe_initchild(dev_info_t *child) else ddi_set_parent_data(child, NULL); + /* Disable certain errors on PCIe drivers for x86 platforms */ + regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask; + pcie_set_aer_uce_mask(regs); + regs = pcie_get_aer_ce_mask() | npe_aer_ce_mask; + pcie_set_aer_ce_mask(regs); + regs = pcie_get_aer_suce_mask() | npe_aer_suce_mask; + pcie_set_aer_suce_mask(regs); + /* - * Enable AER next pointer being displayed and PCIe Error initilization + * If URs are disabled, mask SERRs as well, otherwise the system will + * still be notified of URs */ + if (npe_aer_uce_mask & PCIE_AER_UCE_UR) + pcie_set_serr_mask(1); + if (pci_config_setup(child, &cfg_hdl) == DDI_SUCCESS) { npe_ck804_fix_aer_ptr(cfg_hdl); - (void) pcie_error_enable(child, cfg_hdl); + npe_nvidia_error_mask(cfg_hdl); pci_config_teardown(&cfg_hdl); } + bus_p = pcie_init_bus(child); + if (bus_p) { + uint16_t device_id = (uint16_t)(bus_p->bus_dev_ven_id >> 16); + uint16_t vendor_id = (uint16_t)(bus_p->bus_dev_ven_id & 0xFFFF); + uint16_t rev_id = bus_p->bus_rev_id; + + /* Disable AER for certain NVIDIA Chipsets */ + if ((vendor_id == NVIDIA_VENDOR_ID) && + (device_id == NVIDIA_CK804_DEVICE_ID) && + (rev_id < NVIDIA_CK804_AER_VALID_REVID)) + bus_p->bus_aer_off = 0; + + (void) pcie_initchild(child); + + /* If device is an NVIDIA RC do device specific error setup */ + if ((vendor_id == NVIDIA_VENDOR_ID) && + NVIDIA_PCIE_RC_DEV_ID(device_id)) { + ddi_acc_handle_t cfg_hdl = bus_p->bus_cfg_hdl; + uint16_t rc_ctl; + + rc_ctl = pci_config_get16(cfg_hdl, NVIDIA_INTR_BCR_OFF + + 0x2); + pci_config_put16(cfg_hdl, NVIDIA_INTR_BCR_OFF + 0x2, + rc_ctl | NVIDIA_INTR_BCR_SERR_FORWARD_BIT); + } + + } + return (DDI_SUCCESS); } @@ -813,22 +895,8 @@ npe_initchild(dev_info_t *child) static int npe_removechild(dev_info_t *dip) { - ddi_acc_handle_t cfg_hdl; - struct ddi_parent_private_data *pdptr; + pcie_uninitchild(dip); - /* - * Do it way early. - * Otherwise ddi_map() call form pcie_error_fini crashes - */ - if (pci_config_setup(dip, &cfg_hdl) == DDI_SUCCESS) { - pcie_error_disable(dip, cfg_hdl); - pci_config_teardown(&cfg_hdl); - } - - if ((pdptr = ddi_get_parent_data(dip)) != NULL) { - kmem_free(pdptr, (sizeof (*pdptr) + sizeof (struct intrspec))); - ddi_set_parent_data(dip, NULL); - } ddi_set_name_addr(dip, NULL); /* @@ -872,6 +940,7 @@ npe_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) return (ENXIO); dip = pci_p->pci_dip; + return (pci_common_ioctl(dip, dev, cmd, arg, mode, credp, rvalp)); } @@ -907,5 +976,13 @@ npe_fm_init(dev_info_t *dip, dev_info_t *tdip, int cap, static int npe_fm_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *no_used) { - return (ndi_fm_handler_dispatch(dip, NULL, derr)); + /* + * On current x86 systems, npe's callback does not get called for failed + * loads. If in the future this feature is used, the fault PA should be + * logged in the derr->fme_bus_specific field. The appropriate PCIe + * error handling code should be called and needs to be coordinated with + * safe access handling. + */ + + return (DDI_FM_OK); } diff --git a/usr/src/uts/i86pc/io/pciex/npe_misc.c b/usr/src/uts/i86pc/io/pciex/npe_misc.c index 892bfbb09e..24e6096f7d 100644 --- a/usr/src/uts/i86pc/io/pciex/npe_misc.c +++ b/usr/src/uts/i86pc/io/pciex/npe_misc.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -36,6 +36,8 @@ #include <sys/acpi/acpi.h> #include <sys/acpi/acpi_pci.h> #include <sys/acpica.h> +#include <sys/pci_cap.h> +#include <sys/pcie_impl.h> #include <io/pciex/pcie_nvidia.h> /* @@ -44,12 +46,16 @@ void npe_query_acpi_mcfg(dev_info_t *dip); void npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl); int npe_disable_empty_bridges_workaround(dev_info_t *child); +void npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl); /* * Default ecfga base address */ int64_t npe_default_ecfga_base = 0xE0000000; +extern uint32_t npe_aer_uce_mask; +extern boolean_t pcie_full_scan; + /* * Query the MCFG table using ACPI. If MCFG is found, setup the * 'ecfga-base-address' (Enhanced Configuration Access base address) @@ -118,7 +124,6 @@ npe_ck804_fix_aer_ptr(ddi_acc_handle_t cfg_hdl) } } - /* * If the bridge is empty, disable it */ @@ -137,3 +142,23 @@ npe_disable_empty_bridges_workaround(dev_info_t *child) return (0); } + +void +npe_nvidia_error_mask(ddi_acc_handle_t cfg_hdl) { + uint32_t regs; + uint16_t vendor_id = pci_config_get16(cfg_hdl, PCI_CONF_VENID); + uint16_t dev_id = pci_config_get16(cfg_hdl, PCI_CONF_DEVID); + + if ((vendor_id == NVIDIA_VENDOR_ID) && NVIDIA_PCIE_RC_DEV_ID(dev_id)) { + /* Disable ECRC for all devices */ + regs = pcie_get_aer_uce_mask() | npe_aer_uce_mask | + PCIE_AER_UCE_ECRC; + pcie_set_aer_uce_mask(regs); + + /* + * Turn full scan on since the Error Source ID register may not + * have the correct ID. + */ + pcie_full_scan = B_TRUE; + } +} |