1 /* $OpenBSD: nvme_pci.c,v 1.10 2022/03/11 18:00:51 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2014 David Gwynne <dlg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/buf.h> 22 #include <sys/kernel.h> 23 #include <sys/malloc.h> 24 #include <sys/device.h> 25 #include <sys/timeout.h> 26 #include <sys/queue.h> 27 #include <sys/mutex.h> 28 #include <sys/pool.h> 29 30 #include <machine/bus.h> 31 32 #include <dev/pci/pcireg.h> 33 #include <dev/pci/pcivar.h> 34 #include <dev/pci/pcidevs.h> 35 36 #include <scsi/scsi_all.h> 37 #include <scsi/scsiconf.h> 38 39 #include <dev/ic/nvmereg.h> 40 #include <dev/ic/nvmevar.h> 41 42 #define NVME_PCI_BAR 0x10 43 #define NVME_PCI_INTERFACE 0x02 44 45 struct nvme_pci_softc { 46 struct nvme_softc psc_nvme; 47 pci_chipset_tag_t psc_pc; 48 }; 49 50 int nvme_pci_match(struct device *, void *, void *); 51 void nvme_pci_attach(struct device *, struct device *, void *); 52 int nvme_pci_detach(struct device *, int); 53 int nvme_pci_activate(struct device *, int); 54 55 const struct cfattach nvme_pci_ca = { 56 sizeof(struct nvme_pci_softc), 57 nvme_pci_match, 58 nvme_pci_attach, 59 nvme_pci_detach, 60 nvme_pci_activate 61 }; 62 63 int 64 nvme_pci_match(struct device *parent, void *match, void *aux) 65 { 66 struct pci_attach_args *pa = aux; 67 68 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE && 69 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_NVM && 70 PCI_INTERFACE(pa->pa_class) == NVME_PCI_INTERFACE) 71 return (1); 72 73 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE && 74 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_NVME1 || 75 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_NVME2)) 76 return (1); 77 78 return (0); 79 } 80 81 static const struct pci_matchid nvme_msi_blacklist[] = { 82 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_OPTANE }, 83 }; 84 85 void 86 nvme_pci_attach(struct device *parent, struct device *self, void *aux) 87 { 88 struct nvme_pci_softc *psc = (struct nvme_pci_softc *)self; 89 struct nvme_softc *sc = &psc->psc_nvme; 90 struct pci_attach_args *pa = aux; 91 pcireg_t maptype; 92 pci_intr_handle_t ih; 93 int msi = 1; 94 95 psc->psc_pc = pa->pa_pc; 96 sc->sc_dmat = pa->pa_dmat; 97 98 printf(": "); 99 100 if (pci_matchbyid(pa, nvme_msi_blacklist, nitems(nvme_msi_blacklist))) 101 CLR(pa->pa_flags, PCI_FLAGS_MSI_ENABLED); 102 103 maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, NVME_PCI_BAR); 104 if (pci_mapreg_map(pa, NVME_PCI_BAR, maptype, 0, 105 &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) { 106 printf("unable to map registers\n"); 107 return; 108 } 109 110 if (pci_intr_map_msix(pa, 0, &ih) != 0 && 111 pci_intr_map_msi(pa, &ih) != 0) { 112 if (pci_intr_map(pa, &ih) != 0) { 113 printf("unable to map interrupt\n"); 114 goto unmap; 115 } 116 msi = 0; 117 } 118 119 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, 120 msi ? nvme_intr : nvme_intr_intx, sc, DEVNAME(sc)); 121 if (sc->sc_ih == NULL) { 122 printf("unable to establish interrupt\n"); 123 goto unmap; 124 } 125 126 printf("%s, ", pci_intr_string(pa->pa_pc, ih)); 127 if (nvme_attach(sc) != 0) { 128 /* error printed by nvme_attach() */ 129 goto disestablish; 130 } 131 132 return; 133 134 disestablish: 135 pci_intr_disestablish(pa->pa_pc, sc->sc_ih); 136 sc->sc_ih = NULL; 137 138 unmap: 139 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); 140 sc->sc_ios = 0; 141 } 142 143 int 144 nvme_pci_detach(struct device *self, int flags) 145 { 146 return (0); 147 } 148 149 int 150 nvme_pci_activate(struct device *self, int act) 151 { 152 struct nvme_pci_softc *psc = (struct nvme_pci_softc *)self; 153 154 return (nvme_activate(&psc->psc_nvme, act)); 155 } 156