Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 31 Aug 2011 13:34:10 -0400
From:      John Baldwin <jhb@freebsd.org>
To:        stable@freebsd.org
Subject:   mfi(4) patch to add MSI-X support, possibly address command timeouts
Message-ID:  <201108311334.10804.jhb@freebsd.org>

next in thread | raw e-mail | index | archive | help
I'd like some folks to test a patch to the mfi(4) driver that may help to 
address issues several folks have reported.  The patch does two things, first 
it adds some dummy reads of PCI registers when checking device status in the 
interrupt handler to "flush" the writes to ACK interrupts.  The Linux 
megaraid-sas driver uses this approach and some folks have tested a patch from 
Scott Long which had a somewhat similar effect.  Second, it enables the use of 
MSI-X interrupts for many newer devices.

The patch is available below and at www.freebsd.org/~jhb/patches/mfi.patch

Index: mfi_pci.c
===================================================================
--- mfi_pci.c	(revision 224613)
+++ mfi_pci.c	(working copy)
@@ -169,7 +169,7 @@
 	struct mfi_softc *sc;
 	struct mfi_ident *m;
 	uint32_t command;
-	int error;
+	int count, error;
 
 	sc = device_get_softc(dev);
 	bzero(sc, sizeof(*sc));
@@ -226,6 +226,29 @@
 		goto out;
 	}
 
+	/* Allocate IRQ resource. */
+	sc->mfi_irq_rid = 0;
+	switch (pci_get_device(sc->mfi_dev)) {
+	case 0x0060:	/* SAS1078R */
+	case 0x007c:	/* SAS1078DE */
+	case 0x0413:	/* Verde ZCR */
+		/* Do not use MSI-X for these systems. */
+		break;
+	default:
+		count = 1;
+		if (pci_alloc_msix(sc->mfi_dev, &count) == 0) {
+			device_printf(sc->mfi_dev, "Using MSI-X\n");
+			sc->mfi_irq_rid = 1;
+		}
+		break;
+	}
+	if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ,
+	    &sc->mfi_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+		device_printf(sc->mfi_dev, "Cannot allocate interrupt\n");
+		error = EINVAL;
+		goto out;
+	}
+
 	error = mfi_attach(sc);
 out:
 	if (error) {
@@ -280,6 +303,8 @@
 		bus_release_resource(sc->mfi_dev, SYS_RES_MEMORY,
 		    sc->mfi_regs_rid, sc->mfi_regs_resource);
 	}
+	if (sc->mfi_irq_rid != 0)
+		pci_release_msi(sc->mfi_dev);
 
 	return;
 }
Index: mfi.c
===================================================================
--- mfi.c	(revision 224613)
+++ mfi.c	(working copy)
@@ -157,6 +157,9 @@
 mfi_enable_intr_xscale(struct mfi_softc *sc)
 {
 	MFI_WRITE4(sc, MFI_OMSK, 0x01);
+
+	/* Dummy read to force PCI flush. */
+	(void)MFI_READ4(sc, MFI_OMSK);
 }
 
 static void
@@ -168,6 +171,9 @@
 	} else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
 		MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
 	}
+
+	/* Dummy read to force PCI flush. */
+	(void)MFI_READ4(sc, MFI_OMSK);
 }
 
 static int32_t
@@ -192,6 +198,9 @@
 		return 1;
 
 	MFI_WRITE4(sc, MFI_OSTS, status);
+
+	/* Dummy read to force PCI flush. */
+	(void)MFI_READ4(sc, MFI_OSTS);
 	return 0;
 }
 
@@ -212,6 +221,9 @@
 	}
 
 	MFI_WRITE4(sc, MFI_ODCR0, status);
+
+	/* Dummy read to force PCI flush. */
+	(void)MFI_READ4(sc, MFI_OSTS);
 	return 0;
 }
 
@@ -484,15 +496,8 @@
 	mtx_unlock(&sc->mfi_io_lock);
 
 	/*
-	 * Set up the interrupt handler.  XXX This should happen in
-	 * mfi_pci.c
+	 * Set up the interrupt handler.
 	 */
-	sc->mfi_irq_rid = 0;
-	if ((sc->mfi_irq = bus_alloc_resource_any(sc->mfi_dev, SYS_RES_IRQ,
-	    &sc->mfi_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
-		device_printf(sc->mfi_dev, "Cannot allocate interrupt\n");
-		return (EINVAL);
-	}
 	if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE|INTR_TYPE_BIO,
 	    NULL, mfi_intr, sc, &sc->mfi_intr)) {
 		device_printf(sc->mfi_dev, "Cannot set up interrupt\n");

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201108311334.10804.jhb>