Line data Source code
1 : /* $OpenBSD: nvme_pci.c,v 1.7 2018/01/10 15:45:46 jcs 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 0 : nvme_pci_match(struct device *parent, void *match, void *aux)
65 : {
66 0 : struct pci_attach_args *pa = aux;
67 :
68 0 : if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
69 0 : PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_NVM &&
70 0 : PCI_INTERFACE(pa->pa_class) == NVME_PCI_INTERFACE)
71 0 : return (1);
72 :
73 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE &&
74 0 : (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_NVME1 ||
75 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_NVME2))
76 0 : return (1);
77 :
78 0 : return (0);
79 0 : }
80 :
81 : static const struct pci_matchid nvme_msi_blacklist[] = {
82 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_OPTANE },
83 : };
84 :
85 : void
86 0 : nvme_pci_attach(struct device *parent, struct device *self, void *aux)
87 : {
88 0 : struct nvme_pci_softc *psc = (struct nvme_pci_softc *)self;
89 0 : struct nvme_softc *sc = &psc->psc_nvme;
90 0 : struct pci_attach_args *pa = aux;
91 : pcireg_t maptype;
92 0 : pci_intr_handle_t ih;
93 : int msi = 1;
94 :
95 0 : psc->psc_pc = pa->pa_pc;
96 0 : sc->sc_dmat = pa->pa_dmat;
97 :
98 0 : if (pci_matchbyid(pa, nvme_msi_blacklist, nitems(nvme_msi_blacklist)))
99 0 : CLR(pa->pa_flags, PCI_FLAGS_MSI_ENABLED);
100 :
101 0 : maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, NVME_PCI_BAR);
102 0 : if (pci_mapreg_map(pa, NVME_PCI_BAR, maptype, 0,
103 0 : &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios, 0) != 0) {
104 0 : printf(": unable to map registers\n");
105 0 : return;
106 : }
107 :
108 0 : if (pci_intr_map_msi(pa, &ih) != 0) {
109 0 : if (pci_intr_map(pa, &ih) != 0) {
110 0 : printf(": unable to map interrupt\n");
111 0 : goto unmap;
112 : }
113 : msi = 0;
114 0 : }
115 :
116 0 : sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
117 0 : msi ? nvme_intr : nvme_intr_intx, sc, DEVNAME(sc));
118 0 : if (sc->sc_ih == NULL) {
119 0 : printf(": unable to establish interrupt\n");
120 0 : goto unmap;
121 : }
122 :
123 0 : printf(": %s", pci_intr_string(pa->pa_pc, ih));
124 0 : if (nvme_attach(sc) != 0) {
125 : /* error printed by nvme_attach() */
126 : goto disestablish;
127 : }
128 :
129 0 : return;
130 :
131 : disestablish:
132 0 : pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
133 0 : sc->sc_ih = NULL;
134 :
135 : unmap:
136 0 : bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
137 0 : sc->sc_ios = 0;
138 0 : }
139 :
140 : int
141 0 : nvme_pci_detach(struct device *self, int flags)
142 : {
143 0 : return (0);
144 : }
145 :
146 : int
147 0 : nvme_pci_activate(struct device *self, int act)
148 : {
149 0 : struct nvme_pci_softc *psc = (struct nvme_pci_softc *)self;
150 :
151 0 : return (nvme_activate(&psc->psc_nvme, act));
152 : }
|