diff options
author | jveta <none@none> | 2007-05-03 15:11:37 -0700 |
---|---|---|
committer | jveta <none@none> | 2007-05-03 15:11:37 -0700 |
commit | 600d77457b335b6f448f13d5f33bf7e70dfbb39d (patch) | |
tree | ecafb22dd1ae6888750a00fe1bbe74c142eade40 /usr/src | |
parent | c8cefa24739f75292de004b06d90e5b1290911ae (diff) | |
download | illumos-gate-600d77457b335b6f448f13d5f33bf7e70dfbb39d.tar.gz |
6505891 MSIs not handled correctly for devices with dynamic MSI capability
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/i86pc/io/pci/pci_common.c | 125 | ||||
-rw-r--r-- | usr/src/uts/i86pc/io/pcplusmp/apic_introp.c | 8 | ||||
-rw-r--r-- | usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c | 11 | ||||
-rw-r--r-- | usr/src/uts/intel/io/pciex/pcie_nvidia.c | 12 |
4 files changed, 106 insertions, 50 deletions
diff --git a/usr/src/uts/i86pc/io/pci/pci_common.c b/usr/src/uts/i86pc/io/pci/pci_common.c index f432b85130..cacc0ae123 100644 --- a/usr/src/uts/i86pc/io/pci/pci_common.c +++ b/usr/src/uts/i86pc/io/pci/pci_common.c @@ -52,6 +52,7 @@ #include <io/pci/pci_common.h> #include <sys/pci_cfgspace.h> #include <sys/pci_impl.h> +#include <sys/pci_cap.h> /* * Function prototypes @@ -199,8 +200,11 @@ pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, int types = 0; int pciepci = 0; int i, j, count; + int rv; int behavior; int cap_ptr; + uint16_t msi_cap_base, msix_cap_base, cap_ctrl; + char *prop; ddi_intrspec_t isp; struct intrspec *ispec; ddi_intr_handle_impl_t tmp_hdl; @@ -216,27 +220,86 @@ pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, /* Process the request */ switch (intr_op) { case DDI_INTROP_SUPPORTED_TYPES: + /* + * First we determine the interrupt types supported by the + * device itself, then we filter them through what the OS + * and system supports. We determine system-level + * interrupt type support for anything other than fixed intrs + * through the psm_intr_ops vector + */ + rv = DDI_FAILURE; + /* Fixed supported by default */ - *(int *)result = DDI_INTR_TYPE_FIXED; + types = DDI_INTR_TYPE_FIXED; - /* Figure out if MSI or MSI-X is supported? */ - if (pci_msi_get_supported_type(rdip, &types) != DDI_SUCCESS) + if (psm_intr_ops == NULL) { + *(int *)result = types; return (DDI_SUCCESS); + } + if (pci_config_setup(rdip, &handle) != DDI_SUCCESS) + return (DDI_FAILURE); - if (psm_intr_ops != NULL) { - /* - * Only support MSI for now, OR it in - */ - *(int *)result |= (types & DDI_INTR_TYPE_MSI); + /* Sanity test cap control values if found */ - tmp_hdl.ih_type = *(int *)result; - (void) (*psm_intr_ops)(rdip, &tmp_hdl, - PSM_INTR_OP_CHECK_MSI, result); - DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " - "rdip: 0x%p supported types: 0x%x\n", (void *)rdip, - *(int *)result)); + if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI, &msi_cap_base) == + DDI_SUCCESS) { + cap_ctrl = PCI_CAP_GET16(handle, 0, msi_cap_base, + PCI_MSI_CTRL); + if (cap_ctrl == PCI_CAP_EINVAL16) + goto SUPPORTED_TYPES_OUT; + + types |= DDI_INTR_TYPE_MSI; } - break; + + if (PCI_CAP_LOCATE(handle, PCI_CAP_ID_MSI_X, &msix_cap_base) == + DDI_SUCCESS) { + cap_ctrl = PCI_CAP_GET16(handle, 0, msix_cap_base, + PCI_MSIX_CTRL); + if (cap_ctrl == PCI_CAP_EINVAL16) + goto SUPPORTED_TYPES_OUT; + + types |= DDI_INTR_TYPE_MSIX; + } + + /* + * Filter device-level types through system-level support + */ + + /* No official MSI-X support for now */ + types &= ~DDI_INTR_TYPE_MSIX; + + tmp_hdl.ih_type = types; + if ((*psm_intr_ops)(rdip, &tmp_hdl, PSM_INTR_OP_CHECK_MSI, + &types) != PSM_SUCCESS) + goto SUPPORTED_TYPES_OUT; + + DDI_INTR_NEXDBG((CE_CONT, "pci_common_intr_ops: " + "rdip: 0x%p supported types: 0x%x\n", (void *)rdip, + *(int *)result)); + + /* + * Export any MSI/MSI-X cap locations via properties + */ + if (types & DDI_INTR_TYPE_MSI) { + if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, + "pci-msi-capid-pointer", (int)msi_cap_base) != + DDI_PROP_SUCCESS) + goto SUPPORTED_TYPES_OUT; + } + if (types & DDI_INTR_TYPE_MSIX) { + if (ndi_prop_update_int(DDI_DEV_T_NONE, rdip, + "pci-msix-capid-pointer", (int)msix_cap_base) != + DDI_PROP_SUCCESS) + goto SUPPORTED_TYPES_OUT; + } + + rv = DDI_SUCCESS; + +SUPPORTED_TYPES_OUT: + *(int *)result = types; + pci_config_teardown(&handle); + return (rv); + case DDI_INTROP_NAVAIL: case DDI_INTROP_NINTRS: if (DDI_INTR_IS_MSI_OR_MSIX(hdlp->ih_type)) { @@ -280,19 +343,33 @@ pci_common_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op, i_ddi_set_pci_config_handle(rdip, handle); } - if (i_ddi_get_msi_msix_cap_ptr(rdip) == 0) { - char *prop = - (hdlp->ih_type == DDI_INTR_TYPE_MSI) ? - "pci-msi-capid-pointer" : - "pci-msix-capid-pointer"; + prop = NULL; + cap_ptr = 0; + if (hdlp->ih_type == DDI_INTR_TYPE_MSI) + prop = "pci-msi-capid-pointer"; + else if (hdlp->ih_type == DDI_INTR_TYPE_MSIX) + prop = "pci-msix-capid-pointer"; + /* + * Enforce the calling of DDI_INTROP_SUPPORTED_TYPES + * for MSI(X) before allocation + */ + if (prop != NULL) { cap_ptr = ddi_prop_get_int(DDI_DEV_T_ANY, rdip, - DDI_PROP_DONTPASS, prop, - PCI_CAP_NEXT_PTR_NULL); - i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr); + DDI_PROP_DONTPASS, prop, 0); + if (cap_ptr == 0) { + DDI_INTR_NEXDBG((CE_CONT, + "pci_common_intr_ops: rdip: 0x%p " + "attempted MSI(X) alloc without " + "cap property\n", (void *)rdip)); + return (DDI_FAILURE); + } } + i_ddi_set_msi_msix_cap_ptr(rdip, cap_ptr); - + /* + * Allocate interrupt vectors + */ (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_ALLOC_VECTORS, result); diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c b/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c index 02617ae071..324c8cb54d 100644 --- a/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c +++ b/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c @@ -89,7 +89,7 @@ apic_pci_msi_enable_vector(dev_info_t *dip, int type, int inum, int vector, "\tdriver = %s, inum=0x%x vector=0x%x apicid=0x%x\n", (void *)dip, ddi_driver_name(dip), inum, vector, target_apic_id)); - if (handle == NULL) + if (handle == NULL || cap_ptr == 0) return (PSM_FAILURE); /* MSI Address */ @@ -553,7 +553,7 @@ apic_pci_msi_unconfigure(dev_info_t *rdip, int type, int inum) int cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip); ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(rdip); - if (handle == NULL) + if (handle == NULL || cap_ptr == 0) return (PSM_FAILURE); if (type == DDI_INTR_TYPE_MSI) { @@ -600,7 +600,7 @@ apic_pci_msi_enable_mode(dev_info_t *rdip, int type, int inum) int cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip); ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(rdip); - if (handle == NULL) + if (handle == NULL || cap_ptr == 0) return (PSM_FAILURE); if (type == DDI_INTR_TYPE_MSI) { @@ -644,7 +644,7 @@ apic_pci_msi_disable_mode(dev_info_t *rdip, int type, int inum) int cap_ptr = i_ddi_get_msi_msix_cap_ptr(rdip); ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(rdip); - if (handle == NULL) + if (handle == NULL || cap_ptr == 0) return (PSM_FAILURE); if (type == DDI_INTR_TYPE_MSI) { diff --git a/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c b/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c index 1ca88880c4..6081d9a8b7 100644 --- a/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c +++ b/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c @@ -2969,17 +2969,6 @@ pcicfg_set_standard_props(dev_info_t *dip, ddi_acc_handle_t config_handle, return (ret); } } - if ((cap_id_loc = pcicfg_get_cap(config_handle, PCI_CAP_ID_MSI)) > 0) { - if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, - "pci-msi-capid-pointer", cap_id_loc)) != DDI_SUCCESS) - return (ret); - } - if ((cap_id_loc = pcicfg_get_cap(config_handle, PCI_CAP_ID_MSI_X)) > - 0) { - if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, - "pci-msix-capid-pointer", cap_id_loc)) != DDI_SUCCESS) - return (ret); - } if ((cap_id_loc = pcicfg_get_cap(config_handle, PCI_CAP_ID_PCIX)) > 0) { /* create the pcix-capid-pointer property */ if ((ret = ndi_prop_update_int(DDI_DEV_T_NONE, dip, diff --git a/usr/src/uts/intel/io/pciex/pcie_nvidia.c b/usr/src/uts/intel/io/pciex/pcie_nvidia.c index aec3a31580..23f3993b9f 100644 --- a/usr/src/uts/intel/io/pciex/pcie_nvidia.c +++ b/usr/src/uts/intel/io/pciex/pcie_nvidia.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -71,16 +71,6 @@ check_if_device_is_pciex(dev_info_t *cdip, uchar_t bus, uchar_t dev, (void) ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "pcix-capid-pointer", capsp); - if (cap == PCI_CAP_ID_MSI && cdip) { - (void) ndi_prop_update_int(DDI_DEV_T_NONE, cdip, - "pci-msi-capid-pointer", capsp); - } - - if (cap == PCI_CAP_ID_MSI_X && cdip) { - (void) ndi_prop_update_int(DDI_DEV_T_NONE, cdip, - "pci-msix-capid-pointer", capsp); - } - if (cap == PCI_CAP_ID_PCI_E) { #ifdef DEBUG if (pci_boot_debug) |