xref: /openbsd-src/sys/dev/pci/nvme_pci.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: nvme_pci.c,v 1.8 2019/06/27 17:55:42 kettenis 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 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 	if (pci_matchbyid(pa, nvme_msi_blacklist, nitems(nvme_msi_blacklist)))
99 		CLR(pa->pa_flags, PCI_FLAGS_MSI_ENABLED);
100 
101 	maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, NVME_PCI_BAR);
102 	if (pci_mapreg_map(pa, NVME_PCI_BAR, maptype, 0,
103 	    &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) {
104 		printf(": unable to map registers\n");
105 		return;
106 	}
107 
108 	if (pci_intr_map_msix(pa, 0, &ih) != 0 &&
109 	    pci_intr_map_msi(pa, &ih) != 0) {
110 		if (pci_intr_map(pa, &ih) != 0) {
111 			printf(": unable to map interrupt\n");
112 			goto unmap;
113 		}
114 		msi = 0;
115 	}
116 
117 	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
118 	    msi ? nvme_intr : nvme_intr_intx, sc, DEVNAME(sc));
119 	if (sc->sc_ih == NULL) {
120 		printf(": unable to establish interrupt\n");
121 		goto unmap;
122 	}
123 
124 	printf(": %s", pci_intr_string(pa->pa_pc, ih));
125 	if (nvme_attach(sc) != 0) {
126 		/* error printed by nvme_attach() */
127 		goto disestablish;
128 	}
129 
130 	return;
131 
132 disestablish:
133 	pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
134 	sc->sc_ih = NULL;
135 
136 unmap:
137 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
138 	sc->sc_ios = 0;
139 }
140 
141 int
142 nvme_pci_detach(struct device *self, int flags)
143 {
144 	return (0);
145 }
146 
147 int
148 nvme_pci_activate(struct device *self, int act)
149 {
150 	struct nvme_pci_softc *psc = (struct nvme_pci_softc *)self;
151 
152 	return (nvme_activate(&psc->psc_nvme, act));
153 }
154