1 /* $OpenBSD: sili_pci.c,v 1.16 2024/05/24 06:02:58 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2007 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/device.h>
22 #include <sys/timeout.h>
23
24 #include <machine/bus.h>
25
26 #include <dev/pci/pcireg.h>
27 #include <dev/pci/pcivar.h>
28 #include <dev/pci/pcidevs.h>
29
30 #include <dev/ata/atascsi.h>
31
32 #include <dev/ic/silireg.h>
33 #include <dev/ic/silivar.h>
34
35 int sili_pci_match(struct device *, void *, void *);
36 void sili_pci_attach(struct device *, struct device *, void *);
37 int sili_pci_detach(struct device *, int);
38 int sili_pci_activate(struct device *, int);
39
40 struct sili_pci_softc {
41 struct sili_softc psc_sili;
42
43 pci_chipset_tag_t psc_pc;
44 pcitag_t psc_tag;
45
46 void *psc_ih;
47 };
48
49 const struct cfattach sili_pci_ca = {
50 sizeof(struct sili_pci_softc),
51 sili_pci_match,
52 sili_pci_attach,
53 sili_pci_detach,
54 sili_pci_activate
55 };
56
57 struct sili_device {
58 pci_vendor_id_t sd_vendor;
59 pci_product_id_t sd_product;
60 u_int sd_nports;
61 };
62
63 const struct sili_device *sili_lookup(struct pci_attach_args *);
64
65 static const struct sili_device sili_devices[] = {
66 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3124, 4 },
67 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3131, 1 },
68 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3132, 2 },
69 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_3531, 1 },
70 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_AAR_1220SA, 2 },
71 { PCI_VENDOR_CMDTECH, PCI_PRODUCT_CMDTECH_AAR_1225SA, 2 },
72 { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3124, 4 }
73 };
74
75 const struct sili_device *
sili_lookup(struct pci_attach_args * pa)76 sili_lookup(struct pci_attach_args *pa)
77 {
78 int i;
79 const struct sili_device *sd;
80
81 for (i = 0; i < nitems(sili_devices); i++) {
82 sd = &sili_devices[i];
83 if (sd->sd_vendor == PCI_VENDOR(pa->pa_id) &&
84 sd->sd_product == PCI_PRODUCT(pa->pa_id))
85 return (sd);
86 }
87
88 return (NULL);
89 }
90
91 int
sili_pci_match(struct device * parent,void * match,void * aux)92 sili_pci_match(struct device *parent, void *match, void *aux)
93 {
94 return (sili_lookup((struct pci_attach_args *)aux) != NULL);
95 }
96
97 void
sili_pci_attach(struct device * parent,struct device * self,void * aux)98 sili_pci_attach(struct device *parent, struct device *self, void *aux)
99 {
100 struct sili_pci_softc *psc = (void *)self;
101 struct sili_softc *sc = &psc->psc_sili;
102 struct pci_attach_args *pa = aux;
103 const struct sili_device *sd;
104 pcireg_t memtype;
105 pci_intr_handle_t ih;
106 const char *intrstr;
107
108 sd = sili_lookup(pa);
109
110 psc->psc_pc = pa->pa_pc;
111 psc->psc_tag = pa->pa_tag;
112 psc->psc_ih = NULL;
113 sc->sc_dmat = pa->pa_dmat;
114 sc->sc_ios_global = 0;
115 sc->sc_ios_port = 0;
116 sc->sc_nports = sd->sd_nports;
117
118 memtype = pci_mapreg_type(psc->psc_pc, psc->psc_tag,
119 SILI_PCI_BAR_GLOBAL);
120 if (pci_mapreg_map(pa, SILI_PCI_BAR_GLOBAL, memtype, 0,
121 &sc->sc_iot_global, &sc->sc_ioh_global,
122 NULL, &sc->sc_ios_global, 0) != 0) {
123 printf(": unable to map global registers\n");
124 return;
125 }
126
127 memtype = pci_mapreg_type(psc->psc_pc, psc->psc_tag,
128 SILI_PCI_BAR_PORT);
129 if (pci_mapreg_map(pa, SILI_PCI_BAR_PORT, memtype, 0,
130 &sc->sc_iot_port, &sc->sc_ioh_port,
131 NULL, &sc->sc_ios_port, 0) != 0) {
132 printf(": unable to map port registers\n");
133 goto unmap_global;
134 }
135
136 /* hook up the interrupt */
137 if (pci_intr_map(pa, &ih)) {
138 printf(": unable to map interrupt\n");
139 goto unmap_port;
140 }
141 intrstr = pci_intr_string(psc->psc_pc, ih);
142 psc->psc_ih = pci_intr_establish(psc->psc_pc, ih, IPL_BIO,
143 sili_intr, sc, sc->sc_dev.dv_xname);
144 if (psc->psc_ih == NULL) {
145 printf(": unable to map interrupt%s%s\n",
146 intrstr == NULL ? "" : " at ",
147 intrstr == NULL ? "" : intrstr);
148 goto unmap_port;
149 }
150 printf(": %s", intrstr);
151
152 if (sili_attach(sc) != 0) {
153 /* error printed by sili_attach */
154 goto deintr;
155 }
156
157 return;
158
159 deintr:
160 pci_intr_disestablish(psc->psc_pc, psc->psc_ih);
161 psc->psc_ih = NULL;
162 unmap_port:
163 bus_space_unmap(sc->sc_iot_port, sc->sc_ioh_port, sc->sc_ios_port);
164 sc->sc_ios_port = 0;
165 unmap_global:
166 bus_space_unmap(sc->sc_iot_global, sc->sc_ioh_global,
167 sc->sc_ios_global);
168 sc->sc_ios_global = 0;
169 }
170
171 int
sili_pci_detach(struct device * self,int flags)172 sili_pci_detach(struct device *self, int flags)
173 {
174 struct sili_pci_softc *psc = (struct sili_pci_softc *)self;
175 struct sili_softc *sc = &psc->psc_sili;
176 int rv;
177
178 rv = sili_detach(sc, flags);
179 if (rv != 0)
180 return (rv);
181
182 if (psc->psc_ih != NULL) {
183 pci_intr_disestablish(psc->psc_pc, psc->psc_ih);
184 psc->psc_ih = NULL;
185 }
186 if (sc->sc_ios_port != 0) {
187 bus_space_unmap(sc->sc_iot_port, sc->sc_ioh_port,
188 sc->sc_ios_port);
189 sc->sc_ios_port = 0;
190 }
191 if (sc->sc_ios_global != 0) {
192 bus_space_unmap(sc->sc_iot_global, sc->sc_ioh_global,
193 sc->sc_ios_global);
194 sc->sc_ios_global = 0;
195 }
196
197 return (0);
198 }
199
200 int
sili_pci_activate(struct device * self,int act)201 sili_pci_activate(struct device *self, int act)
202 {
203 struct sili_softc *sc = (struct sili_softc *)self;
204 int rv = 0;
205
206 switch (act) {
207 case DVACT_RESUME:
208 sili_resume(sc);
209 rv = config_activate_children(self, act);
210 break;
211 default:
212 rv = config_activate_children(self, act);
213 break;
214 }
215 return (rv);
216 }
217