svn commit: r351904 - in stable/12/sys: conf dev/ahci dev/nvme modules/nvme

Warner Losh imp at FreeBSD.org
Thu Sep 5 23:02:10 UTC 2019


Author: imp
Date: Thu Sep  5 23:02:08 2019
New Revision: 351904
URL: https://svnweb.freebsd.org/changeset/base/351904

Log:
  MFC r351356:
  
    Create a AHCI attachment for nvme.

Added:
  stable/12/sys/dev/nvme/nvme_ahci.c
     - copied unchanged from r351356, head/sys/dev/nvme/nvme_ahci.c
Modified:
  stable/12/sys/conf/files
  stable/12/sys/dev/ahci/ahci.c
  stable/12/sys/dev/ahci/ahci.h
  stable/12/sys/dev/ahci/ahci_pci.c
  stable/12/sys/modules/nvme/Makefile
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/conf/files
==============================================================================
--- stable/12/sys/conf/files	Thu Sep  5 23:01:12 2019	(r351903)
+++ stable/12/sys/conf/files	Thu Sep  5 23:02:08 2019	(r351904)
@@ -2574,6 +2574,7 @@ dev/nsp/nsp_pccard.c		optional nsp pccard
 dev/null/null.c			standard
 dev/nvd/nvd.c			optional nvd nvme
 dev/nvme/nvme.c			optional nvme
+dev/nvme/nvme_ahci.c		optional nvme ahci
 dev/nvme/nvme_ctrlr.c		optional nvme
 dev/nvme/nvme_ctrlr_cmd.c	optional nvme
 dev/nvme/nvme_ns.c		optional nvme

Modified: stable/12/sys/dev/ahci/ahci.c
==============================================================================
--- stable/12/sys/dev/ahci/ahci.c	Thu Sep  5 23:01:12 2019	(r351903)
+++ stable/12/sys/dev/ahci/ahci.c	Thu Sep  5 23:02:08 2019	(r351904)
@@ -347,6 +347,16 @@ ahci_attach(device_t dev)
 		if ((ctlr->ichannels & (1 << unit)) == 0)
 			device_disable(child);
 	}
+	/* Attach any remapped NVME device */
+	for (; unit < ctlr->channels + ctlr->remapped_devices; unit++) {
+		child = device_add_child(dev, "nvme", -1);
+		if (child == NULL) {
+			device_printf(dev, "failed to add remapped NVMe device");
+			    continue;
+		}
+		device_set_ivars(child, (void *)(intptr_t)(unit | AHCI_REMAPPED_UNIT));
+	}
+
 	if (ctlr->caps & AHCI_CAP_EMS) {
 		child = device_add_child(dev, "ahciem", -1);
 		if (child == NULL)
@@ -497,6 +507,12 @@ ahci_intr(void *data)
 				ctlr->interrupt[unit].function(arg);
 		}
 	}
+	for (; unit < ctlr->channels + ctlr->remapped_devices; unit++) {
+		if ((arg = ctlr->interrupt[unit].argument)) {
+			ctlr->interrupt[unit].function(arg);
+		}
+	}
+
 	/* AHCI declares level triggered IS. */
 	if (!(ctlr->quirks & AHCI_Q_EDGEIS))
 		ATA_OUTL(ctlr->r_mem, AHCI_IS, is);
@@ -546,12 +562,23 @@ ahci_alloc_resource(device_t dev, device_t child, int 
 	struct resource *res;
 	rman_res_t st;
 	int offset, size, unit;
+	bool is_remapped;
 
 	unit = (intptr_t)device_get_ivars(child);
+	if (unit & AHCI_REMAPPED_UNIT) {
+		unit &= ~AHCI_REMAPPED_UNIT;
+		unit -= ctlr->channels;
+		is_remapped = true;
+	} else
+		is_remapped = false;
 	res = NULL;
 	switch (type) {
 	case SYS_RES_MEMORY:
-		if (unit >= 0) {
+		if (is_remapped) {
+			offset = ctlr->remap_offset + unit * ctlr->remap_size;
+			size = ctlr->remap_size;
+		}
+		else if (unit >= 0) {
 			offset = AHCI_OFFSET + (unit << 7);
 			size = 128;
 		} else if (*rid == 0) {
@@ -612,7 +639,7 @@ ahci_setup_intr(device_t dev, device_t child, struct r
     void *argument, void **cookiep)
 {
 	struct ahci_controller *ctlr = device_get_softc(dev);
-	int unit = (intptr_t)device_get_ivars(child);
+	int unit = (intptr_t)device_get_ivars(child) & ~AHCI_REMAPPED_UNIT;
 
 	if (filter != NULL) {
 		printf("ahci.c: we cannot use a filter here\n");
@@ -628,7 +655,7 @@ ahci_teardown_intr(device_t dev, device_t child, struc
     void *cookie)
 {
 	struct ahci_controller *ctlr = device_get_softc(dev);
-	int unit = (intptr_t)device_get_ivars(child);
+	int unit = (intptr_t)device_get_ivars(child) & ~AHCI_REMAPPED_UNIT;
 
 	ctlr->interrupt[unit].function = NULL;
 	ctlr->interrupt[unit].argument = NULL;
@@ -641,7 +668,7 @@ ahci_print_child(device_t dev, device_t child)
 	int retval, channel;
 
 	retval = bus_print_child_header(dev, child);
-	channel = (int)(intptr_t)device_get_ivars(child);
+	channel = (int)(intptr_t)device_get_ivars(child) & ~AHCI_REMAPPED_UNIT;
 	if (channel >= 0)
 		retval += printf(" at channel %d", channel);
 	retval += bus_print_child_footer(dev, child);
@@ -654,7 +681,7 @@ ahci_child_location_str(device_t dev, device_t child, 
 {
 	int channel;
 
-	channel = (int)(intptr_t)device_get_ivars(child);
+	channel = (int)(intptr_t)device_get_ivars(child) & ~AHCI_REMAPPED_UNIT;
 	if (channel >= 0)
 		snprintf(buf, buflen, "channel=%d", channel);
 	return (0);

Modified: stable/12/sys/dev/ahci/ahci.h
==============================================================================
--- stable/12/sys/dev/ahci/ahci.h	Thu Sep  5 23:01:12 2019	(r351903)
+++ stable/12/sys/dev/ahci/ahci.h	Thu Sep  5 23:02:08 2019	(r351904)
@@ -214,6 +214,7 @@
 #define		AHCI_CAP2_SADM	0x00000010
 #define		AHCI_CAP2_DESO	0x00000020
 
+#define AHCI_VSCAP                  0xa4
 #define AHCI_OFFSET                 0x100
 #define AHCI_STEP                   0x80
 
@@ -318,6 +319,10 @@
 /* Total main work area. */
 #define AHCI_WORK_SIZE              (AHCI_CT_OFFSET + AHCI_CT_SIZE * ch->numslots)
 
+
+/* NVMe remapped device */
+#define AHCI_REMAPPED_UNIT	(1 << 31)
+
 struct ahci_dma_prd {
     u_int64_t                   dba;
     u_int32_t                   reserved;
@@ -518,6 +523,9 @@ struct ahci_controller {
 	int			cccv;		/* CCC vector */
 	int			direct;		/* Direct command completion */
 	int			msi;		/* MSI interupts */
+	int			remapped_devices; /* Remapped NVMe devices */
+	uint32_t		remap_offset;
+	uint32_t		remap_size;
 	struct {
 		void			(*function)(void *);
 		void			*argument;

Modified: stable/12/sys/dev/ahci/ahci_pci.c
==============================================================================
--- stable/12/sys/dev/ahci/ahci_pci.c	Thu Sep  5 23:01:12 2019	(r351903)
+++ stable/12/sys/dev/ahci/ahci_pci.c	Thu Sep  5 23:02:08 2019	(r351904)
@@ -495,6 +495,48 @@ ahci_pci_attach(device_t dev)
 	    &ctlr->r_rid, RF_ACTIVE)))
 		return ENXIO;
 
+	/*
+	 * Intel RAID hardware can remap NVMe devices inside its BAR.
+	 * Try to detect this. Either we have to add the device
+	 * here, or the user has to change the mode in the BIOS
+	 * from RST to AHCI.
+	 */
+	if (pci_get_vendor(dev) == 0x8086) {
+		uint32_t vscap;
+
+		vscap = ATA_INL(ctlr->r_mem, AHCI_VSCAP);
+		if (vscap & 1) {
+			uint32_t cap = ATA_INL(ctlr->r_mem, 0x800); /* Intel's REMAP CAP */
+			int i;
+
+			ctlr->remap_offset = 0x4000;
+			ctlr->remap_size = 0x4000;
+
+			/*
+			 * Check each of the devices that might be remapped to
+			 * make sure they are an nvme device. At the present,
+			 * nvme are the only known devices remapped.
+			 */
+			for (i = 0; i < 3; i++) {
+				if (cap & (1 << i) &&
+				    (ATA_INL(ctlr->r_mem, 0x880 + i * 0x80) ==
+				     ((PCIC_STORAGE << 16) |
+				      (PCIS_STORAGE_NVM << 8) |
+				      PCIP_STORAGE_NVM_ENTERPRISE_NVMHCI_1_0))) {
+					ctlr->remapped_devices++;
+				}
+			}
+
+			/* If we have any remapped device, disable MSI */
+			if (ctlr->remapped_devices > 0) {
+				device_printf(dev, "Detected %d nvme remapped devices\n",
+				    ctlr->remapped_devices);
+				ctlr->quirks |= (AHCI_Q_NOMSIX | AHCI_Q_NOMSI);
+			}
+		}
+	}
+
+
 	if (ctlr->quirks & AHCI_Q_NOMSIX)
 		msix_count = 0;
 

Copied: stable/12/sys/dev/nvme/nvme_ahci.c (from r351356, head/sys/dev/nvme/nvme_ahci.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/12/sys/dev/nvme/nvme_ahci.c	Thu Sep  5 23:02:08 2019	(r351904, copy of r351356, head/sys/dev/nvme/nvme_ahci.c)
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (C) 2017 Olivier Houchard
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/smp.h>
+
+#include "nvme_private.h"
+
+static int    nvme_ahci_probe(device_t dev);
+static int    nvme_ahci_attach(device_t dev);
+static int    nvme_ahci_detach(device_t dev);
+
+static device_method_t nvme_ahci_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,     nvme_ahci_probe),
+	DEVMETHOD(device_attach,    nvme_ahci_attach),
+	DEVMETHOD(device_detach,    nvme_ahci_detach),
+	DEVMETHOD(device_shutdown,  nvme_shutdown),
+	{ 0, 0 }
+};
+
+static driver_t nvme_ahci_driver = {
+	"nvme",
+	nvme_ahci_methods,
+	sizeof(struct nvme_controller),
+};
+
+DRIVER_MODULE(nvme, ahci, nvme_ahci_driver, nvme_devclass, NULL, 0);
+MODULE_VERSION(nvme_ahci, 1);
+
+static int
+nvme_ahci_probe (device_t device)
+{
+	return (0);
+}
+
+static int
+nvme_ahci_attach(device_t dev)
+{
+	struct nvme_controller*ctrlr = DEVICE2SOFTC(dev);
+	int ret;
+
+	/* Map MMIO registers */
+	ctrlr->resource_id = 0;
+
+	ctrlr->resource = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+	    &ctrlr->resource_id, RF_ACTIVE);
+
+	if(ctrlr->resource == NULL) {
+		nvme_printf(ctrlr, "unable to allocate mem resource\n");
+		ret = ENOMEM;
+		goto bad;
+	}
+	ctrlr->bus_tag = rman_get_bustag(ctrlr->resource);
+	ctrlr->bus_handle = rman_get_bushandle(ctrlr->resource);
+	ctrlr->regs = (struct nvme_registers *)ctrlr->bus_handle;
+
+	/* Allocate and setup IRQ */
+	ctrlr->rid = 0;
+	ctrlr->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+	    &ctrlr->rid, RF_SHAREABLE | RF_ACTIVE);
+
+	if (ctrlr->res == NULL) {
+		nvme_printf(ctrlr, "unable to allocate shared IRQ\n");
+		ret = ENOMEM;
+		goto bad;
+	}
+
+	ctrlr->msix_enabled = 0;
+	ctrlr->num_io_queues = 1;
+	ctrlr->num_cpus_per_ioq = mp_ncpus;
+	if (bus_setup_intr(dev, ctrlr->res,
+	    INTR_TYPE_MISC | INTR_MPSAFE, NULL, nvme_ctrlr_intx_handler,
+	    ctrlr, &ctrlr->tag) != 0) {
+		nvme_printf(ctrlr, "unable to setup intx handler\n");
+		ret = ENOMEM;
+		goto bad;
+	}
+	ctrlr->tag = (void *)0x1;
+
+	return nvme_attach(dev);
+bad:
+	if (ctrlr->resource != NULL) {
+		bus_release_resource(dev, SYS_RES_MEMORY,
+		    ctrlr->resource_id, ctrlr->resource);
+	}
+	if (ctrlr->res)
+		bus_release_resource(ctrlr->dev, SYS_RES_IRQ,
+		    rman_get_rid(ctrlr->res), ctrlr->res);
+	return (ret);
+}
+
+static int
+nvme_ahci_detach(device_t dev)
+{
+
+	return (nvme_detach(dev));
+}

Modified: stable/12/sys/modules/nvme/Makefile
==============================================================================
--- stable/12/sys/modules/nvme/Makefile	Thu Sep  5 23:01:12 2019	(r351903)
+++ stable/12/sys/modules/nvme/Makefile	Thu Sep  5 23:02:08 2019	(r351904)
@@ -5,6 +5,7 @@
 KMOD = nvme
 
 SRCS =	nvme.c			\
+	nvme_ahci.c		\
 	nvme_ctrlr.c		\
 	nvme_ctrlr_cmd.c	\
 	nvme_ns.c		\


More information about the svn-src-all mailing list