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 #include <sys/param.h> 28 #include <sys/systm.h> 29 #include <sys/buf.h> 30 #include <sys/bus.h> 31 #include <sys/conf.h> 32 #include <sys/proc.h> 33 #include <sys/smp.h> 34 35 #include "nvme_private.h" 36 37 static int nvme_ahci_probe(device_t dev); 38 static int nvme_ahci_attach(device_t dev); 39 static int nvme_ahci_detach(device_t dev); 40 41 static device_method_t nvme_ahci_methods[] = { 42 /* Device interface */ 43 DEVMETHOD(device_probe, nvme_ahci_probe), 44 DEVMETHOD(device_attach, nvme_ahci_attach), 45 DEVMETHOD(device_detach, nvme_ahci_detach), 46 DEVMETHOD(device_shutdown, nvme_shutdown), 47 { 0, 0 } 48 }; 49 50 static driver_t nvme_ahci_driver = { 51 "nvme", 52 nvme_ahci_methods, 53 sizeof(struct nvme_controller), 54 }; 55 56 DRIVER_MODULE(nvme, ahci, nvme_ahci_driver, NULL, NULL); 57 58 static int 59 nvme_ahci_probe (device_t device) 60 { 61 return (0); 62 } 63 64 static int 65 nvme_ahci_attach(device_t dev) 66 { 67 struct nvme_controller*ctrlr = DEVICE2SOFTC(dev); 68 int ret; 69 70 /* Map MMIO registers */ 71 ctrlr->resource_id = 0; 72 73 ctrlr->resource = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 74 &ctrlr->resource_id, RF_ACTIVE); 75 76 if(ctrlr->resource == NULL) { 77 nvme_printf(ctrlr, "unable to allocate mem resource\n"); 78 ret = ENOMEM; 79 goto bad; 80 } 81 ctrlr->bus_tag = rman_get_bustag(ctrlr->resource); 82 ctrlr->bus_handle = rman_get_bushandle(ctrlr->resource); 83 ctrlr->regs = (struct nvme_registers *)ctrlr->bus_handle; 84 85 /* Allocate and setup IRQ */ 86 ctrlr->rid = 0; 87 ctrlr->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 88 &ctrlr->rid, RF_SHAREABLE | RF_ACTIVE); 89 if (ctrlr->res == NULL) { 90 nvme_printf(ctrlr, "unable to allocate shared interrupt\n"); 91 ret = ENOMEM; 92 goto bad; 93 } 94 95 ctrlr->msi_count = 0; 96 ctrlr->num_io_queues = 1; 97 if (bus_setup_intr(dev, ctrlr->res, 98 INTR_TYPE_MISC | INTR_MPSAFE, NULL, nvme_ctrlr_shared_handler, 99 ctrlr, &ctrlr->tag) != 0) { 100 nvme_printf(ctrlr, "unable to setup shared interrupt\n"); 101 ret = ENOMEM; 102 goto bad; 103 } 104 ctrlr->tag = (void *)0x1; 105 106 /* 107 * We're attached via this funky mechanism. Flag the controller so that 108 * it avoids things that can't work when we do that, like asking for 109 * PCI config space entries. 110 */ 111 ctrlr->quirks |= QUIRK_AHCI; 112 113 return (nvme_attach(dev)); /* Note: failure frees resources */ 114 bad: 115 if (ctrlr->resource != NULL) { 116 bus_release_resource(dev, SYS_RES_MEMORY, 117 ctrlr->resource_id, ctrlr->resource); 118 } 119 if (ctrlr->res) 120 bus_release_resource(ctrlr->dev, SYS_RES_IRQ, 121 rman_get_rid(ctrlr->res), ctrlr->res); 122 return (ret); 123 } 124 125 static int 126 nvme_ahci_detach(device_t dev) 127 { 128 129 return (nvme_detach(dev)); 130 } 131