pci_machdep.c revision 1.29 1 /* $NetBSD: pci_machdep.c,v 1.29 2002/05/15 18:37:55 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1999, 2000 Matthew R. Green
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /*
32 * functions expected by the MI PCI code.
33 */
34
35 #ifdef DEBUG
36 #define SPDB_CONF 0x01
37 #define SPDB_INTR 0x04
38 #define SPDB_INTMAP 0x08
39 #define SPDB_INTFIX 0x10
40 #define SPDB_PROBE 0x20
41 int sparc_pci_debug = 0x0;
42 #define DPRINTF(l, s) do { if (sparc_pci_debug & l) printf s; } while (0)
43 #else
44 #define DPRINTF(l, s)
45 #endif
46
47 #include <sys/types.h>
48 #include <sys/param.h>
49 #include <sys/time.h>
50 #include <sys/systm.h>
51 #include <sys/errno.h>
52 #include <sys/device.h>
53 #include <sys/malloc.h>
54
55 #define _SPARC_BUS_DMA_PRIVATE
56 #include <machine/bus.h>
57 #include <machine/autoconf.h>
58 #include <machine/openfirm.h>
59
60 #include <dev/pci/pcivar.h>
61 #include <dev/pci/pcireg.h>
62
63 #include <dev/ofw/ofw_pci.h>
64
65 #include <sparc64/dev/ofpcivar.h>
66
67 #include <sparc64/dev/iommureg.h>
68 #include <sparc64/dev/iommuvar.h>
69 #include <sparc64/dev/psychoreg.h>
70 #include <sparc64/dev/psychovar.h>
71
72 /* this is a base to be copied */
73 struct sparc_pci_chipset _sparc_pci_chipset = {
74 NULL,
75 };
76
77 /*
78 * functions provided to the MI code.
79 */
80
81 void
82 pci_attach_hook(parent, self, pba)
83 struct device *parent;
84 struct device *self;
85 struct pcibus_attach_args *pba;
86 {
87 /* Don't do nothing */
88 }
89
90 int
91 pci_bus_maxdevs(pc, busno)
92 pci_chipset_tag_t pc;
93 int busno;
94 {
95
96 return 32;
97 }
98
99 #ifdef __PCI_BUS_DEVORDER
100 int
101 pci_bus_devorder(pc, busno, devs)
102 pci_chipset_tag_t pc;
103 int busno;
104 char *devs;
105 {
106 struct ofw_pci_register reg;
107 int node, len, device, i = 0;
108 u_int32_t done = 0;
109 #ifdef DEBUG
110 char name[80];
111 #endif
112
113 node = pc->curnode;
114 #ifdef DEBUG
115 if (sparc_pci_debug & SPDB_PROBE) {
116 OF_getprop(node, "name", &name, sizeof(name));
117 printf("pci_bus_devorder: curnode %x %s\n", node, name);
118 }
119 #endif
120 /*
121 * Initially, curnode is the root of the pci tree. As we
122 * attach bridges, curnode should be set to that of the bridge.
123 */
124 for (node = OF_child(node); node; node = OF_peer(node)) {
125 len = OF_getproplen(node, "reg");
126 if (len < sizeof(reg))
127 continue;
128 if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len)
129 panic("pci_probe_bus: OF_getprop len botch");
130
131 device = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi);
132
133 if (done & (1 << device))
134 continue;
135
136 devs[i++] = device;
137 done |= 1 << device;
138 #ifdef DEBUG
139 if (sparc_pci_debug & SPDB_PROBE) {
140 OF_getprop(node, "name", &name, sizeof(name));
141 printf("pci_bus_devorder: adding %x %s\n", node, name);
142 }
143 #endif
144 if (i == 32)
145 break;
146 }
147 if (i < 32)
148 devs[i] = -1;
149
150 return i;
151 }
152 #endif
153
154 pcitag_t
155 pci_make_tag(pc, b, d, f)
156 pci_chipset_tag_t pc;
157 int b;
158 int d;
159 int f;
160 {
161 struct ofw_pci_register reg;
162 pcitag_t tag;
163 int busrange[2];
164 int node, len;
165 #ifdef DEBUG
166 char name[80];
167 bzero(name, sizeof(name));
168 #endif
169
170 /*
171 * Hunt for the node that corresponds to this device
172 *
173 * We could cache this info in an array in the parent
174 * device... except then we have problems with devices
175 * attached below pci-pci bridges, and we would need to
176 * add special code to the pci-pci bridge to cache this
177 * info.
178 */
179
180 tag = PCITAG_CREATE(-1, b, d, f);
181 node = pc->rootnode;
182 /*
183 * First make sure we're on the right bus. If our parent
184 * has a bus-range property and we're not in the range,
185 * then we're obviously on the wrong bus. So go up one
186 * level.
187 */
188 #ifdef DEBUG
189 if (sparc_pci_debug & SPDB_PROBE) {
190 OF_getprop(node, "name", &name, sizeof(name));
191 printf("curnode %x %s\n", node, name);
192 }
193 #endif
194 #if 0
195 while ((OF_getprop(OF_parent(node), "bus-range", (void *)&busrange,
196 sizeof(busrange)) == sizeof(busrange)) &&
197 (b < busrange[0] || b > busrange[1])) {
198 /* Out of range, go up one */
199 node = OF_parent(node);
200 #ifdef DEBUG
201 if (sparc_pci_debug & SPDB_PROBE) {
202 OF_getprop(node, "name", &name, sizeof(name));
203 printf("going up to node %x %s\n", node, name);
204 }
205 #endif
206 }
207 #endif
208 /*
209 * Now traverse all peers until we find the node or we find
210 * the right bridge.
211 *
212 * XXX We go up one and down one to make sure nobody's missed.
213 * but this should not be necessary.
214 */
215 for (node = ((node)); node; node = OF_peer(node)) {
216
217 #ifdef DEBUG
218 if (sparc_pci_debug & SPDB_PROBE) {
219 OF_getprop(node, "name", &name, sizeof(name));
220 printf("checking node %x %s\n", node, name);
221 }
222 #endif
223
224 #if 1
225 /*
226 * Check for PCI-PCI bridges. If the device we want is
227 * in the bus-range for that bridge, work our way down.
228 */
229 while ((OF_getprop(node, "bus-range", (void *)&busrange,
230 sizeof(busrange)) == sizeof(busrange)) &&
231 (b >= busrange[0] && b <= busrange[1])) {
232 /* Go down 1 level */
233 node = OF_child(node);
234 #ifdef DEBUG
235 if (sparc_pci_debug & SPDB_PROBE) {
236 OF_getprop(node, "name", &name, sizeof(name));
237 printf("going down to node %x %s\n",
238 node, name);
239 }
240 #endif
241 }
242 #endif
243 /*
244 * We only really need the first `reg' property.
245 *
246 * For simplicity, we'll query the `reg' when we
247 * need it. Otherwise we could malloc() it, but
248 * that gets more complicated.
249 */
250 len = OF_getproplen(node, "reg");
251 if (len < sizeof(reg))
252 continue;
253 if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len)
254 panic("pci_probe_bus: OF_getprop len botch");
255
256 if (b != OFW_PCI_PHYS_HI_BUS(reg.phys_hi))
257 continue;
258 if (d != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi))
259 continue;
260 if (f != OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi))
261 continue;
262
263 /* Got a match */
264 tag = ofpci_make_tag(pc, node, b, d, f);
265
266 /*
267 * Record the node. This has two effects:
268 *
269 * 1) We don't have to search as far.
270 * 2) pci_bus_devorder will scan the right bus.
271 */
272 pc->curnode = node;
273 return (tag);
274 }
275 /* No device found -- return a dead tag */
276 return (tag);
277 }
278
279 void
280 pci_decompose_tag(pc, tag, bp, dp, fp)
281 pci_chipset_tag_t pc;
282 pcitag_t tag;
283 int *bp, *dp, *fp;
284 {
285
286 if (bp != NULL)
287 *bp = PCITAG_BUS(tag);
288 if (dp != NULL)
289 *dp = PCITAG_DEV(tag);
290 if (fp != NULL)
291 *fp = PCITAG_FUN(tag);
292 }
293
294 pcitag_t
295 ofpci_make_tag(pc, node, b, d, f)
296 pci_chipset_tag_t pc;
297 int node;
298 int b;
299 int d;
300 int f;
301 {
302 pcitag_t tag;
303
304 tag = PCITAG_CREATE(node, b, d, f);
305
306 /*
307 * Record the node. This has two effects:
308 *
309 * 1) We don't have to search as far.
310 * 2) pci_bus_devorder will scan the right bus.
311 */
312 pc->curnode = node;
313
314 /* Enable all the different spaces for this device */
315 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG,
316 PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_MASTER_ENABLE|
317 PCI_COMMAND_IO_ENABLE);
318 return (tag);
319 }
320
321 /* assume we are mapped little-endian/side-effect */
322 pcireg_t
323 pci_conf_read(pc, tag, reg)
324 pci_chipset_tag_t pc;
325 pcitag_t tag;
326 int reg;
327 {
328 struct psycho_pbm *pp = pc->cookie;
329 struct psycho_softc *sc = pp->pp_sc;
330 pcireg_t val = (pcireg_t)~0;
331
332 DPRINTF(SPDB_CONF, ("pci_conf_read: tag %lx reg %x ",
333 (long)tag, reg));
334 if (PCITAG_NODE(tag) != -1) {
335 DPRINTF(SPDB_CONF, ("asi=%x addr=%qx (offset=%x) ...",
336 sc->sc_configaddr._asi,
337 (long long)(sc->sc_configaddr._ptr +
338 PCITAG_OFFSET(tag) + reg),
339 (int)PCITAG_OFFSET(tag) + reg));
340
341 val = bus_space_read_4(sc->sc_configtag, sc->sc_configaddr,
342 PCITAG_OFFSET(tag) + reg);
343 }
344 #ifdef DEBUG
345 else DPRINTF(SPDB_CONF, ("pci_conf_read: bogus pcitag %x\n",
346 (int)PCITAG_OFFSET(tag)));
347 #endif
348 DPRINTF(SPDB_CONF, (" returning %08x\n", (u_int)val));
349
350 return (val);
351 }
352
353 void
354 pci_conf_write(pc, tag, reg, data)
355 pci_chipset_tag_t pc;
356 pcitag_t tag;
357 int reg;
358 pcireg_t data;
359 {
360 struct psycho_pbm *pp = pc->cookie;
361 struct psycho_softc *sc = pp->pp_sc;
362
363 DPRINTF(SPDB_CONF, ("pci_conf_write: tag %lx; reg %x; data %x; ",
364 (long)PCITAG_OFFSET(tag), reg, (int)data));
365 DPRINTF(SPDB_CONF, ("asi = %x; readaddr = %qx (offset = %x)\n",
366 sc->sc_configaddr._asi,
367 (long long)(sc->sc_configaddr._ptr + PCITAG_OFFSET(tag) + reg),
368 (int)PCITAG_OFFSET(tag) + reg));
369
370 /* If we don't know it, just punt it. */
371 if (PCITAG_NODE(tag) == -1) {
372 DPRINTF(SPDB_CONF, ("pci_conf_write: bad addr"));
373 return;
374 }
375
376 bus_space_write_4(sc->sc_configtag, sc->sc_configaddr,
377 PCITAG_OFFSET(tag) + reg, data);
378 }
379
380 /*
381 * interrupt mapping foo.
382 * XXX: how does this deal with multiple interrupts for a device?
383 */
384 int
385 pci_intr_map(pa, ihp)
386 struct pci_attach_args *pa;
387 pci_intr_handle_t *ihp;
388 {
389 pcitag_t tag = pa->pa_tag;
390 int interrupts;
391 int len, node = PCITAG_NODE(tag);
392 char devtype[30];
393
394 len = OF_getproplen(node, "interrupts");
395 if (len < sizeof(interrupts)) {
396 DPRINTF(SPDB_INTMAP,
397 ("pci_intr_map: interrupts len %d too small\n", len));
398 return (ENODEV);
399 }
400 if (OF_getprop(node, "interrupts", (void *)&interrupts,
401 sizeof(interrupts)) != len) {
402 DPRINTF(SPDB_INTMAP,
403 ("pci_intr_map: could not read interrupts\n"));
404 return (ENODEV);
405 }
406
407 if (OF_mapintr(node, &interrupts, sizeof(interrupts),
408 sizeof(interrupts)) < 0) {
409 printf("OF_mapintr failed\n");
410 }
411 /* Try to find an IPL for this type of device. */
412 if (OF_getprop(node, "device_type", &devtype, sizeof(devtype)) > 0) {
413 for (len = 0; intrmap[len].in_class; len++)
414 if (strcmp(intrmap[len].in_class, devtype) == 0) {
415 interrupts |= INTLEVENCODE(intrmap[len].in_lev);
416 break;
417 }
418 }
419
420 /* XXXX -- we use the ino. What if there is a valid IGN? */
421 *ihp = interrupts;
422 return (0);
423 }
424
425 const char *
426 pci_intr_string(pc, ih)
427 pci_chipset_tag_t pc;
428 pci_intr_handle_t ih;
429 {
430 static char str[16];
431
432 DPRINTF(SPDB_INTR, ("pci_intr_string: ih %u", ih));
433 sprintf(str, "ivec %x", ih);
434 DPRINTF(SPDB_INTR, ("; returning %s\n", str));
435
436 return (str);
437 }
438
439 const struct evcnt *
440 pci_intr_evcnt(pc, ih)
441 pci_chipset_tag_t pc;
442 pci_intr_handle_t ih;
443 {
444
445 /* XXX for now, no evcnt parent reported */
446 return NULL;
447 }
448
449 void *
450 pci_intr_establish(pc, ih, level, func, arg)
451 pci_chipset_tag_t pc;
452 pci_intr_handle_t ih;
453 int level;
454 int (*func) __P((void *));
455 void *arg;
456 {
457 void *cookie;
458 struct psycho_pbm *pp = (struct psycho_pbm *)pc->cookie;
459
460 DPRINTF(SPDB_INTR, ("pci_intr_establish: ih %lu; level %d", (u_long)ih, level));
461 cookie = bus_intr_establish(pp->pp_memt, ih, level, 0, func, arg);
462
463 DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie));
464 return (cookie);
465 }
466
467 void
468 pci_intr_disestablish(pc, cookie)
469 pci_chipset_tag_t pc;
470 void *cookie;
471 {
472
473 DPRINTF(SPDB_INTR, ("pci_intr_disestablish: cookie %p\n", cookie));
474
475 /* XXX */
476 panic("can't disestablish PCI interrupts yet");
477 }
478