changeset 4160:c23579e36e7c

6505891 MSIs not handled correctly for devices with dynamic MSI capability
author jveta
date Thu, 03 May 2007 15:11:37 -0700
parents 61358aef9ab3
children ca2dbbf9df8a
files usr/src/uts/i86pc/io/pci/pci_common.c usr/src/uts/i86pc/io/pcplusmp/apic_introp.c usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c usr/src/uts/intel/io/pciex/pcie_nvidia.c
diffstat 4 files changed, 107 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/i86pc/io/pci/pci_common.c	Thu May 03 14:25:49 2007 -0700
+++ b/usr/src/uts/i86pc/io/pci/pci_common.c	Thu May 03 15:11:37 2007 -0700
@@ -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 @@
 	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 @@
 	/* 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;
+
+		if (psm_intr_ops == NULL) {
+			*(int *)result = types;
+			return (DDI_SUCCESS);
+		}
+		if (pci_config_setup(rdip, &handle) != DDI_SUCCESS)
+			return (DDI_FAILURE);
 
-		/* Figure out if MSI or MSI-X is supported? */
-		if (pci_msi_get_supported_type(rdip, &types) != DDI_SUCCESS)
-			return (DDI_SUCCESS);
+		/* Sanity test cap control values if found */
+
+		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;
+		}
+
+		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;
 
-		if (psm_intr_ops != NULL) {
-			/*
-			 * Only support MSI for now, OR it in
-			 */
-			*(int *)result |= (types & DDI_INTR_TYPE_MSI);
+			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));
 
-			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));
+		/*
+		 * 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;
 		}
-		break;
+		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 @@
 				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);
 
--- a/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c	Thu May 03 14:25:49 2007 -0700
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c	Thu May 03 15:11:37 2007 -0700
@@ -89,7 +89,7 @@
 	    "\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 @@
 	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 @@
 	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 @@
 	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) {
--- a/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c	Thu May 03 14:25:49 2007 -0700
+++ b/usr/src/uts/intel/io/hotplug/pcicfg/pcicfg.c	Thu May 03 15:11:37 2007 -0700
@@ -2969,17 +2969,6 @@
 			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,
--- a/usr/src/uts/intel/io/pciex/pcie_nvidia.c	Thu May 03 14:25:49 2007 -0700
+++ b/usr/src/uts/intel/io/pciex/pcie_nvidia.c	Thu May 03 15:11:37 2007 -0700
@@ -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 @@
 			(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)