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, NULL, NULL); 58 59 static int 60 nvme_ahci_probe (device_t device) 61 { 62 return (0); 63 } 64 65 static int 66 nvme_ahci_attach(device_t dev) 67 { 68 struct nvme_controller*ctrlr = DEVICE2SOFTC(dev); 69 int ret; 70 71 /* Map MMIO registers */ 72 ctrlr->resource_id = 0; 73 74 ctrlr->resource = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 75 &ctrlr->resource_id, RF_ACTIVE); 76 77 if(ctrlr->resource == NULL) { 78 nvme_printf(ctrlr, "unable to allocate mem resource\n"); 79 ret = ENOMEM; 80 goto bad; 81 } 82 ctrlr->bus_tag = rman_get_bustag(ctrlr->resource); 83 ctrlr->bus_handle = rman_get_bushandle(ctrlr->resource); 84 ctrlr->regs = (struct nvme_registers *)ctrlr->bus_handle; 85 86 /* Allocate and setup IRQ */ 87 ctrlr->rid = 0; 88 ctrlr->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 89 &ctrlr->rid, RF_SHAREABLE | RF_ACTIVE); 90 if (ctrlr->res == NULL) { 91 nvme_printf(ctrlr, "unable to allocate shared interrupt\n"); 92 ret = ENOMEM; 93 goto bad; 94 } 95 96 ctrlr->msi_count = 0; 97 ctrlr->num_io_queues = 1; 98 if (bus_setup_intr(dev, ctrlr->res, 99 INTR_TYPE_MISC | INTR_MPSAFE, NULL, nvme_ctrlr_shared_handler, 100 ctrlr, &ctrlr->tag) != 0) { 101 nvme_printf(ctrlr, "unable to setup shared interrupt\n"); 102 ret = ENOMEM; 103 goto bad; 104 } 105 ctrlr->tag = (void *)0x1; 106 107 /* 108 * We're attached via this funky mechanism. Flag the controller so that 109 * it avoids things that can't work when we do that, like asking for 110 * PCI config space entries. 111 */ 112 ctrlr->quirks |= QUIRK_AHCI; 113 114 return (nvme_attach(dev)); /* Note: failure frees resources */ 115 bad: 116 if (ctrlr->resource != NULL) { 117 bus_release_resource(dev, SYS_RES_MEMORY, 118 ctrlr->resource_id, ctrlr->resource); 119 } 120 if (ctrlr->res) 121 bus_release_resource(ctrlr->dev, SYS_RES_IRQ, 122 rman_get_rid(ctrlr->res), ctrlr->res); 123 return (ret); 124 } 125 126 static int 127 nvme_ahci_detach(device_t dev) 128 { 129 130 return (nvme_detach(dev)); 131 } 132