xref: /netbsd-src/sys/dev/pci/cac_pci.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: cac_pci.c,v 1.4 2000/06/13 13:36:52 ad Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * PCI front-end for cac(4) driver.
41  */
42 
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: cac_pci.c,v 1.4 2000/06/13 13:36:52 ad Exp $");
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/device.h>
50 #include <sys/queue.h>
51 #include <sys/proc.h>
52 #include <sys/buf.h>
53 
54 #include <machine/endian.h>
55 #include <machine/bus.h>
56 
57 #include <dev/pci/pcidevs.h>
58 #include <dev/pci/pcivar.h>
59 
60 #include <dev/ic/cacreg.h>
61 #include <dev/ic/cacvar.h>
62 
63 #define	PCI_CBIO	0x10	/* Configuration base I/O address */
64 #define	PCI_CBMA	0x14	/* Configuration base memory address */
65 
66 static int	cac_pci_match __P((struct device *, struct cfdata *, void *));
67 static void	cac_pci_attach __P((struct device *, struct device *, void *));
68 
69 static void	cac_pci_l0_submit __P((struct cac_softc *, paddr_t));
70 static paddr_t	cac_pci_l0_completed __P((struct cac_softc *));
71 static int	cac_pci_l0_intr_pending __P((struct cac_softc *));
72 static void	cac_pci_l0_intr_enable __P((struct cac_softc *, int));
73 static int	cac_pci_l0_fifo_full __P((struct cac_softc *));
74 
75 static void	cac_pci_l1_submit __P((struct cac_softc *, paddr_t));
76 static paddr_t	cac_pci_l1_completed __P((struct cac_softc *));
77 static int	cac_pci_l1_intr_pending __P((struct cac_softc *));
78 static void	cac_pci_l1_intr_enable __P((struct cac_softc *, int));
79 static int	cac_pci_l1_fifo_full __P((struct cac_softc *));
80 
81 struct cfattach cac_pci_ca = {
82 	sizeof(struct cac_softc), cac_pci_match, cac_pci_attach
83 };
84 
85 static struct cac_linkage cac_pci_l0 = {
86 	cac_pci_l0_submit,
87 	cac_pci_l0_completed,
88 	cac_pci_l0_intr_pending,
89 	cac_pci_l0_intr_enable,
90 	cac_pci_l0_fifo_full
91 };
92 
93 static struct cac_linkage cac_pci_l1 = {
94 	cac_pci_l1_submit,
95 	cac_pci_l1_completed,
96 	cac_pci_l1_intr_pending,
97 	cac_pci_l1_intr_enable,
98 	cac_pci_l1_fifo_full
99 };
100 
101 /* This block of code inspired by Compaq's Linux driver. */
102 struct cac_type {
103 	int	ct_subsysid;			/* PCI subsystem ID */
104 	int	ct_mmreg;			/* Memory mapped registers */
105 	struct	cac_linkage *ct_linkage;	/* Command interface */
106 	char	*ct_typestr;			/* Textual description */
107 } static cac_type[] = {
108 #ifdef notdef
109 	{ 0x0040110e, 0, &cac_pci_lX, "IDA" },
110 	{ 0x0140110e, 0, &cac_pci_lX, "IDA 2" },
111 	{ 0x1040110e, 0, &cac_pci_lX, "IAES" },
112 	{ 0x2040110e, 0, &cac_pci_lX, "SMART" },
113 #endif
114 	{ 0x3040110e, 0, &cac_pci_l0, "SMART-2/E" },
115 	{ 0x40300e11, 1, &cac_pci_l0, "SMART-2/P" },
116 	{ 0x40310e11, 1, &cac_pci_l0, "SMART-2SL" },
117 	{ 0x40320e11, 1, &cac_pci_l0, "Smart Array 3200" },
118 	{ 0x40330e11, 1, &cac_pci_l0, "Smart Array 3100ES" },
119 	{ 0x40340e11, 1, &cac_pci_l0, "Smart Array 221" },
120 	{ 0x40400e11, 1, &cac_pci_l1, "Integrated Array" },
121 	{ 0x40500e11, 1, &cac_pci_l1, "Smart Array 4200" },
122 	{ 0x40510e11, 1, &cac_pci_l1, "Smart Array 4200ES" },
123 	{ -1, 1, &cac_pci_l0, "array controller (unknown type)" },
124 };
125 
126 static int
127 cac_pci_match(parent, match, aux)
128 	struct device *parent;
129 	struct cfdata *match;
130 	void *aux;
131 {
132 	struct pci_attach_args *pa;
133 
134 	pa = (struct pci_attach_args *)aux;
135 
136 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_COMPAQ &&
137 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_COMPAQ_SMART2P)
138 		return (1);
139 
140 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_DEC &&
141 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_DEC_CPQ42XX)
142 		return (1);
143 
144 	return (0);
145 }
146 
147 static void
148 cac_pci_attach(parent, self, aux)
149 	struct device *parent;
150 	struct device *self;
151 	void *aux;
152 {
153 	struct pci_attach_args *pa;
154 	struct cac_type *ct;
155 	struct cac_softc *sc;
156 	pci_chipset_tag_t pc;
157 	pci_intr_handle_t ih;
158 	const char *intrstr;
159 	pcireg_t csr, subsysid;
160 	int mmreg;
161 
162 	sc = (struct cac_softc *)self;
163 	pa = (struct pci_attach_args *)aux;
164 	pc = pa->pa_pc;
165 	mmreg = 0;
166 
167 	printf(": ");
168 
169 	subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
170 
171 	for (ct = cac_type; ct->ct_subsysid != -1; ct++)
172 		if (subsysid == ct->ct_subsysid)
173 			break;
174 
175 	if ((mmreg = ct->ct_mmreg) != 0)
176 		if (pci_mapreg_map(pa, PCI_CBMA, PCI_MAPREG_TYPE_MEM, 0,
177 		    &sc->sc_iot, &sc->sc_ioh, NULL, NULL))
178 		    	mmreg = 0;
179 
180 	if (mmreg == 0)
181 		if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
182 		    &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) {
183 			printf("can't map i/o space\n");
184 			return;
185 		}
186 
187 	sc->sc_dmat = pa->pa_dmat;
188 
189 	/* Enable the device. */
190 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
191 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
192 		       csr | PCI_COMMAND_MASTER_ENABLE);
193 
194 	/* Map and establish the interrupt. */
195 	if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
196 	    pa->pa_intrline, &ih)) {
197 		printf("can't map interrupt\n");
198 		return;
199 	}
200 	intrstr = pci_intr_string(pc, ih);
201 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, cac_intr, sc);
202 	if (sc->sc_ih == NULL) {
203 		printf("can't establish interrupt");
204 		if (intrstr != NULL)
205 			printf(" at %s", intrstr);
206 		printf("\n");
207 		return;
208 	}
209 
210 	/* Now attach to the bus-independent code */
211 	sc->sc_typestr = ct->ct_typestr;
212 	sc->sc_cl = ct->ct_linkage;
213 	cac_init(sc, intrstr);
214 }
215 
216 static void
217 cac_pci_l0_submit(sc, addr)
218 	struct cac_softc *sc;
219 	paddr_t addr;
220 {
221 
222 	cac_outl(sc, CAC_REG_CMD_FIFO, addr);
223 }
224 
225 static paddr_t
226 cac_pci_l0_completed(sc)
227 	struct cac_softc *sc;
228 {
229 
230 	return (cac_inl(sc, CAC_REG_DONE_FIFO));
231 }
232 
233 static int
234 cac_pci_l0_intr_pending(sc)
235 	struct cac_softc *sc;
236 {
237 
238 	return (cac_inl(sc, CAC_REG_INT_PENDING));
239 }
240 
241 static void
242 cac_pci_l0_intr_enable(sc, state)
243 	struct cac_softc *sc;
244 	int state;
245 {
246 
247 	cac_outl(sc, CAC_REG_INT_MASK, state);
248 }
249 
250 static int
251 cac_pci_l0_fifo_full(sc)
252 	struct cac_softc *sc;
253 {
254 
255 	return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
256 }
257 
258 static void
259 cac_pci_l1_submit(sc, addr)
260 	struct cac_softc *sc;
261 	paddr_t addr;
262 {
263 
264 	cac_outl(sc, CAC_42REG_CMD_FIFO, addr);
265 }
266 
267 static paddr_t
268 cac_pci_l1_completed(sc)
269 	struct cac_softc *sc;
270 {
271 	int32_t val;
272 
273 	if ((val = cac_inl(sc, CAC_42REG_DONE_FIFO)) == -1)
274 		return (0);
275 
276 	cac_outl(sc, CAC_42REG_DONE_FIFO, 0);
277 	return ((paddr_t)val);
278 }
279 
280 static int
281 cac_pci_l1_intr_pending(sc)
282 	struct cac_softc *sc;
283 {
284 
285 	return (cac_inl(sc, CAC_42REG_INT_PENDING) &
286 	    cac_inl(sc, CAC_42REG_STATUS));
287 }
288 
289 static void
290 cac_pci_l1_intr_enable(sc, state)
291 	struct cac_softc *sc;
292 	int state;
293 {
294 
295 	cac_outl(sc, CAC_REG_INT_MASK, (state ? 0 : 8));	/* XXX */
296 }
297 
298 static int
299 cac_pci_l1_fifo_full(sc)
300 	struct cac_softc *sc;
301 {
302 
303 	return (~cac_inl(sc, CAC_42REG_CMD_FIFO));
304 }
305