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