1 /*- 2 * Copyright (C) 2017 Olivier Houchard 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/buf.h> 31 #include <sys/bus.h> 32 #include <sys/conf.h> 33 #include <sys/proc.h> 34 #include <sys/smp.h> 35 36 #include "nvme_private.h" 37 38 static int nvme_ahci_probe(device_t dev); 39 static int nvme_ahci_attach(device_t dev); 40 static int nvme_ahci_detach(device_t dev); 41 42 static device_method_t nvme_ahci_methods[] = { 43 /* Device interface */ 44 DEVMETHOD(device_probe, nvme_ahci_probe), 45 DEVMETHOD(device_attach, nvme_ahci_attach), 46 DEVMETHOD(device_detach, nvme_ahci_detach), 47 DEVMETHOD(device_shutdown, nvme_shutdown), 48 { 0, 0 } 49 }; 50 51 static driver_t nvme_ahci_driver = { 52 "nvme", 53 nvme_ahci_methods, 54 sizeof(struct nvme_controller), 55 }; 56 57 DRIVER_MODULE(nvme, ahci, nvme_ahci_driver, nvme_devclass, NULL, 0); 58 MODULE_VERSION(nvme, 1); 59 MODULE_DEPEND(nvme, cam, 1, 1, 1); 60 61 static int 62 nvme_ahci_probe (device_t device) 63 { 64 return (0); 65 } 66 67 static int 68 nvme_ahci_attach(device_t dev) 69 { 70 struct nvme_controller*ctrlr = DEVICE2SOFTC(dev); 71 int ret; 72 73 /* Map MMIO registers */ 74 ctrlr->resource_id = 0; 75 76 ctrlr->resource = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 77 &ctrlr->resource_id, RF_ACTIVE); 78 79 if(ctrlr->resource == NULL) { 80 nvme_printf(ctrlr, "unable to allocate mem resource\n"); 81 ret = ENOMEM; 82 goto bad; 83 } 84 ctrlr->bus_tag = rman_get_bustag(ctrlr->resource); 85 ctrlr->bus_handle = rman_get_bushandle(ctrlr->resource); 86 ctrlr->regs = (struct nvme_registers *)ctrlr->bus_handle; 87 88 /* Allocate and setup IRQ */ 89 ctrlr->rid = 0; 90 ctrlr->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 91 &ctrlr->rid, RF_SHAREABLE | RF_ACTIVE); 92 93 if (ctrlr->res == NULL) { 94 nvme_printf(ctrlr, "unable to allocate shared IRQ\n"); 95 ret = ENOMEM; 96 goto bad; 97 } 98 99 ctrlr->msix_enabled = 0; 100 ctrlr->num_io_queues = 1; 101 ctrlr->num_cpus_per_ioq = mp_ncpus; 102 if (bus_setup_intr(dev, ctrlr->res, 103 INTR_TYPE_MISC | INTR_MPSAFE, NULL, nvme_ctrlr_intx_handler, 104 ctrlr, &ctrlr->tag) != 0) { 105 nvme_printf(ctrlr, "unable to setup intx handler\n"); 106 ret = ENOMEM; 107 goto bad; 108 } 109 ctrlr->tag = (void *)0x1; 110 111 return nvme_attach(dev); 112 bad: 113 if (ctrlr->resource != NULL) { 114 bus_release_resource(dev, SYS_RES_MEMORY, 115 ctrlr->resource_id, ctrlr->resource); 116 } 117 if (ctrlr->res) 118 bus_release_resource(ctrlr->dev, SYS_RES_IRQ, 119 rman_get_rid(ctrlr->res), ctrlr->res); 120 return (ret); 121 } 122 123 static int 124 nvme_ahci_detach(device_t dev) 125 { 126 127 return (nvme_detach(dev)); 128 } 129