Module Name:    src
Committed By:   knakahara
Date:           Tue Jul 21 03:10:42 UTC 2015

Modified Files:
        src/sys/arch/x86/include: pci_machdep_common.h
        src/sys/arch/x86/pci: pci_intr_machdep.c

Log Message:
add pci_intr_alloc() API


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/sys/arch/x86/include/pci_machdep_common.h
cvs rdiff -u -r1.33 -r1.34 src/sys/arch/x86/pci/pci_intr_machdep.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/include/pci_machdep_common.h
diff -u src/sys/arch/x86/include/pci_machdep_common.h:1.18 src/sys/arch/x86/include/pci_machdep_common.h:1.19
--- src/sys/arch/x86/include/pci_machdep_common.h:1.18	Fri May 15 08:36:41 2015
+++ src/sys/arch/x86/include/pci_machdep_common.h	Tue Jul 21 03:10:42 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_machdep_common.h,v 1.18 2015/05/15 08:36:41 knakahara Exp $	*/
+/*	$NetBSD: pci_machdep_common.h,v 1.19 2015/07/21 03:10:42 knakahara Exp $	*/
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
@@ -120,6 +120,15 @@ void		*pci_intr_establish(pci_chipset_ta
 void		pci_intr_disestablish(pci_chipset_tag_t, void *);
 int		pci_intr_distribute(void *, const kcpuset_t *, kcpuset_t *);
 
+typedef enum {
+	PCI_INTR_TYPE_INTX = 0,
+	PCI_INTR_TYPE_MSI,
+	PCI_INTR_TYPE_MSIX,
+	PCI_INTR_TYPE_SIZE,
+} pci_intr_type_t;
+
+pci_intr_type_t	pci_intr_type(pci_intr_handle_t);
+
 /*
  * If device drivers use MSI/MSI-X, they should use these API for INTx
  * instead of pci_intr_map(), because of conforming the pci_intr_handle
@@ -128,6 +137,13 @@ int		pci_intr_distribute(void *, const k
 int		pci_intx_alloc(const struct pci_attach_args *,
 		    pci_intr_handle_t **);
 
+/*
+ * Wrapper function for generally unitied allocation to fallback MSI-X/MSI/INTx
+ * automatically.
+ */
+int		pci_intr_alloc(const struct pci_attach_args *,
+		    pci_intr_handle_t **, int *, pci_intr_type_t);
+
 /* experimental MSI support */
 int		pci_msi_count(const struct pci_attach_args *);
 int		pci_msi_alloc(const struct pci_attach_args *,

Index: src/sys/arch/x86/pci/pci_intr_machdep.c
diff -u src/sys/arch/x86/pci/pci_intr_machdep.c:1.33 src/sys/arch/x86/pci/pci_intr_machdep.c:1.34
--- src/sys/arch/x86/pci/pci_intr_machdep.c:1.33	Fri May 15 08:36:41 2015
+++ src/sys/arch/x86/pci/pci_intr_machdep.c	Tue Jul 21 03:10:42 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci_intr_machdep.c,v 1.33 2015/05/15 08:36:41 knakahara Exp $	*/
+/*	$NetBSD: pci_intr_machdep.c,v 1.34 2015/07/21 03:10:42 knakahara Exp $	*/
 
 /*-
  * Copyright (c) 1997, 1998, 2009 The NetBSD Foundation, Inc.
@@ -73,7 +73,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.33 2015/05/15 08:36:41 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci_intr_machdep.c,v 1.34 2015/07/21 03:10:42 knakahara Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -350,6 +350,20 @@ pci_intr_distribute(void *cookie, const 
 }
 
 #if NIOAPIC > 0
+pci_intr_type_t
+pci_intr_type(pci_intr_handle_t ih)
+{
+
+	if (INT_VIA_MSI(ih)) {
+		if (MSI_INT_IS_MSIX(ih))
+			return PCI_INTR_TYPE_MSIX;
+		else
+			return PCI_INTR_TYPE_MSI;
+	} else {
+		return PCI_INTR_TYPE_INTX;
+	}
+}
+
 static void
 x86_pci_intx_release(pci_chipset_tag_t pc, pci_intr_handle_t *pih)
 {
@@ -404,6 +418,112 @@ error:
 	return error;
 }
 
+/*
+ * Interrupt handler allocation utility. This function calls each allocation
+ * function as specified by arguments.
+ * Currently callee functions are pci_intx_alloc(), pci_msi_alloc_exact(),
+ * and pci_msix_alloc_exact().
+ * pa       : pci_attach_args
+ * ihps     : interrupt handlers
+ * counts   : The array of number of required interrupt handlers.
+ *            It is overwritten by allocated the number of handlers.
+ *            CAUTION: The size of counts[] must be PCI_INTR_TYPE_SIZE.
+ * max_type : "max" type of using interrupts. See below.
+ *     e.g.
+ *         If you want to use 5 MSI-X, 1 MSI, or INTx, you use "counts" as
+ *             int counts[PCI_INTR_TYPE_SIZE];
+ *             counts[PCI_INTR_TYPE_MSIX] = 5;
+ *             counts[PCI_INTR_TYPE_MSI] = 1;
+ *             counts[PCI_INTR_TYPE_INTX] = 1;
+ *             error = pci_intr_alloc(pa, ihps, counts, PCI_INTR_TYPE_MSIX);
+ *
+ *         If you want to use hardware max number MSI-X or 1 MSI,
+ *         and not to use INTx, you use "counts" as
+ *             int counts[PCI_INTR_TYPE_SIZE];
+ *             counts[PCI_INTR_TYPE_MSIX] = -1;
+ *             counts[PCI_INTR_TYPE_MSI] = 1;
+ *             counts[PCI_INTR_TYPE_INTX] = 0;
+ *             error = pci_intr_alloc(pa, ihps, counts, PCI_INTR_TYPE_MSIX);
+ *
+ *         If you want to use 3 MSI or INTx, you can use "counts" as
+ *             int counts[PCI_INTR_TYPE_SIZE];
+ *             counts[PCI_INTR_TYPE_MSI] = 3;
+ *             counts[PCI_INTR_TYPE_INTX] = 1;
+ *             error = pci_intr_alloc(pa, ihps, counts, PCI_INTR_TYPE_MSI);
+ *
+ *         If you want to use 1 MSI or INTx (probably most general usage),
+ *         you can simply use this API like
+ *         below
+ *             error = pci_intr_alloc(pa, ihps, NULL, 0);
+ *                                                    ^ ignored
+ */
+int
+pci_intr_alloc(const struct pci_attach_args *pa, pci_intr_handle_t **ihps,
+    int *counts, pci_intr_type_t max_type)
+{
+	int error;
+	int intx_count, msi_count, msix_count;
+
+	intx_count = msi_count = msix_count = 0;
+	if (counts == NULL) { /* simple pattern */
+		msi_count = 1;
+		intx_count = 1;
+	} else {
+		switch(max_type) {
+		case PCI_INTR_TYPE_MSIX:
+			msix_count = counts[PCI_INTR_TYPE_MSIX];
+			/* FALLTHROUGH */
+		case PCI_INTR_TYPE_MSI:
+			msi_count = counts[PCI_INTR_TYPE_MSI];
+			/* FALLTHROUGH */
+		case PCI_INTR_TYPE_INTX:
+			intx_count = counts[PCI_INTR_TYPE_INTX];
+			break;
+		default:
+			return EINVAL;
+		}
+	}
+
+	memset(counts, 0, sizeof(counts[0]) * PCI_INTR_TYPE_SIZE);
+	error = EINVAL;
+
+	/* try MSI-X */
+	if (msix_count == -1) /* use hardware max */
+		msix_count = pci_msix_count(pa);
+	if (msix_count > 0) {
+		error = pci_msix_alloc_exact(pa, ihps, msix_count);
+		if (error == 0) {
+			counts[PCI_INTR_TYPE_MSIX] = msix_count;
+			goto out;
+		}
+	}
+
+	/* try MSI */
+	if (msi_count == -1) /* use hardware max */
+		msi_count = pci_msi_count(pa);
+	if (msi_count > 0) {
+		error = pci_msi_alloc_exact(pa, ihps, msi_count);
+		if (error == 0) {
+			if (counts != NULL) {
+				counts[PCI_INTR_TYPE_MSI] = msi_count;
+				goto out;
+			}
+		}
+	}
+
+	/* try INTx */
+	if (intx_count != 0) { /* The number of INTx is always 1. */
+		error = pci_intx_alloc(pa, ihps);
+		if (error == 0) {
+			if (counts != NULL)
+				counts[PCI_INTR_TYPE_INTX] = 1;
+		}
+	}
+
+ out:
+	return error;
+}
+
 void
 pci_intr_release(pci_chipset_tag_t pc, pci_intr_handle_t *pih, int count)
 {

Reply via email to