Annotation of sys/arch/sparc64/dev/pci_machdep.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pci_machdep.c,v 1.30 2007/08/04 16:39:15 kettenis Exp $ */
2: /* $NetBSD: pci_machdep.c,v 1.22 2001/07/20 00:07:13 eeh Exp $ */
3:
4: /*
5: * Copyright (c) 1999, 2000 Matthew R. Green
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. The name of the author may not be used to endorse or promote products
17: * derived from this software without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: /*
33: * functions expected by the MI PCI code.
34: */
35:
36: #ifdef DEBUG
37: #define SPDB_CONF 0x01
38: #define SPDB_INTR 0x04
39: #define SPDB_INTMAP 0x08
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) do { } while (0)
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: #include <dev/pci/pcivar.h>
60: #include <dev/pci/pcireg.h>
61:
62: #include <dev/ofw/ofw_pci.h>
63:
64: #include <sparc64/dev/iommureg.h>
65: #include <sparc64/dev/iommuvar.h>
66: #include <sparc64/dev/psychoreg.h>
67: #include <sparc64/dev/psychovar.h>
68: #include <sparc64/sparc64/cache.h>
69:
70: /* this is a base to be copied */
71: struct sparc_pci_chipset _sparc_pci_chipset = {
72: NULL,
73: };
74:
75: static int pci_bus_frequency(int node);
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 anything */
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: pcitag_t
100: pci_make_tag(pc, b, d, f)
101: pci_chipset_tag_t pc;
102: int b;
103: int d;
104: int f;
105: {
106: struct ofw_pci_register reg;
107: pcitag_t tag;
108: int busrange[2];
109: int node, len;
110: #ifdef DEBUG
111: char name[80];
112: bzero(name, sizeof(name));
113: #endif
114:
115: /*
116: * Hunt for the node that corresponds to this device
117: *
118: * We could cache this info in an array in the parent
119: * device... except then we have problems with devices
120: * attached below pci-pci bridges, and we would need to
121: * add special code to the pci-pci bridge to cache this
122: * info.
123: */
124:
125: tag = PCITAG_CREATE(-1, b, d, f);
126: node = pc->rootnode;
127: /*
128: * First make sure we're on the right bus. If our parent
129: * has a bus-range property and we're not in the range,
130: * then we're obviously on the wrong bus. So go up one
131: * level.
132: */
133: #ifdef DEBUG
134: if (sparc_pci_debug & SPDB_PROBE) {
135: OF_getprop(node, "name", &name, sizeof(name));
136: printf("curnode %x %s\n", node, name);
137: }
138: #endif
139: #if 0
140: while ((OF_getprop(OF_parent(node), "bus-range", (void *)&busrange,
141: sizeof(busrange)) == sizeof(busrange)) &&
142: (b < busrange[0] || b > busrange[1])) {
143: /* Out of range, go up one */
144: node = OF_parent(node);
145: #ifdef DEBUG
146: if (sparc_pci_debug & SPDB_PROBE) {
147: OF_getprop(node, "name", &name, sizeof(name));
148: printf("going up to node %x %s\n", node, name);
149: }
150: #endif
151: }
152: #endif
153: /*
154: * Now traverse all peers until we find the node or we find
155: * the right bridge.
156: *
157: * XXX We go up one and down one to make sure nobody's missed.
158: * but this should not be necessary.
159: */
160: for (node = ((node)); node; node = OF_peer(node)) {
161:
162: #ifdef DEBUG
163: if (sparc_pci_debug & SPDB_PROBE) {
164: OF_getprop(node, "name", &name, sizeof(name));
165: printf("checking node %x %s\n", node, name);
166: }
167: #endif
168:
169: #if 1
170: /*
171: * Check for PCI-PCI bridges. If the device we want is
172: * in the bus-range for that bridge, work our way down.
173: */
174: while ((OF_getprop(node, "bus-range", (void *)&busrange,
175: sizeof(busrange)) == sizeof(busrange)) &&
176: (b >= busrange[0] && b <= busrange[1])) {
177: /* Go down 1 level */
178: node = OF_child(node);
179: #ifdef DEBUG
180: if (sparc_pci_debug & SPDB_PROBE) {
181: OF_getprop(node, "name", &name, sizeof(name));
182: printf("going down to node %x %s\n",
183: node, name);
184: }
185: #endif
186: }
187: #endif
188: /*
189: * We only really need the first `reg' property.
190: *
191: * For simplicity, we'll query the `reg' when we
192: * need it. Otherwise we could malloc() it, but
193: * that gets more complicated.
194: */
195: len = OF_getproplen(node, "reg");
196: if (len < sizeof(reg))
197: continue;
198: if (OF_getprop(node, "reg", (void *)®, sizeof(reg)) != len)
199: panic("pci_probe_bus: OF_getprop len botch");
200:
201: if (b != OFW_PCI_PHYS_HI_BUS(reg.phys_hi))
202: continue;
203: if (d != OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi))
204: continue;
205: if (f != OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi))
206: continue;
207:
208: /* Got a match */
209: tag = PCITAG_CREATE(node, b, d, f);
210:
211: return (tag);
212: }
213: /* No device found -- return a dead tag */
214: return (tag);
215: }
216:
217: void
218: pci_decompose_tag(pc, tag, bp, dp, fp)
219: pci_chipset_tag_t pc;
220: pcitag_t tag;
221: int *bp, *dp, *fp;
222: {
223:
224: if (bp != NULL)
225: *bp = PCITAG_BUS(tag);
226: if (dp != NULL)
227: *dp = PCITAG_DEV(tag);
228: if (fp != NULL)
229: *fp = PCITAG_FUN(tag);
230: }
231:
232: static int
233: pci_bus_frequency(int node)
234: {
235: int len, bus_frequency;
236:
237: len = OF_getproplen(node, "clock-frequency");
238: if (len < sizeof(bus_frequency)) {
239: DPRINTF(SPDB_PROBE,
240: ("pci_bus_frequency: clock-frequency len %d too small\n",
241: len));
242: return 33;
243: }
244: if (OF_getprop(node, "clock-frequency", &bus_frequency,
245: sizeof(bus_frequency)) != len) {
246: DPRINTF(SPDB_PROBE,
247: ("pci_bus_frequency: could not read clock-frequency\n"));
248: return 33;
249: }
250: return bus_frequency / 1000000;
251: }
252:
253: int
254: sparc64_pci_enumerate_bus(struct pci_softc *sc,
255: int (*match)(struct pci_attach_args *), struct pci_attach_args *pap)
256: {
257: struct ofw_pci_register reg;
258: pci_chipset_tag_t pc = sc->sc_pc;
259: pcitag_t tag;
260: pcireg_t class, csr, bhlc, ic;
261: int node, b, d, f, ret;
262: int bus_frequency, lt, cl, cacheline;
263: char name[30];
264:
265: if (sc->sc_bridgetag)
266: node = PCITAG_NODE(*sc->sc_bridgetag);
267: else
268: node = pc->rootnode;
269:
270: bus_frequency = pci_bus_frequency(node);
271:
272: /*
273: * Make sure the cache line size is at least as big as the
274: * ecache line and the streaming cache (64 byte).
275: */
276: cacheline = max(cacheinfo.ec_linesize, 64);
277: KASSERT((cacheline/64)*64 == cacheline &&
278: (cacheline/cacheinfo.ec_linesize)*cacheinfo.ec_linesize == cacheline &&
279: (cacheline/4)*4 == cacheline);
280:
281: for (node = OF_child(node); node != 0 && node != -1;
282: node = OF_peer(node)) {
283: name[0] = name[29] = 0;
284: OF_getprop(node, "name", name, sizeof(name));
285:
286: if (OF_getprop(node, "class-code", &class, sizeof(class)) !=
287: sizeof(class))
288: continue;
289: if (OF_getprop(node, "reg", ®, sizeof(reg)) < sizeof(reg))
290: panic("pci_enumerate_bus: \"%s\" regs too small", name);
291:
292: b = OFW_PCI_PHYS_HI_BUS(reg.phys_hi);
293: d = OFW_PCI_PHYS_HI_DEVICE(reg.phys_hi);
294: f = OFW_PCI_PHYS_HI_FUNCTION(reg.phys_hi);
295:
296: if (sc->sc_bus != b) {
297: printf("%s: WARNING: incorrect bus # for \"%s\" "
298: "(%d/%d/%d)\n", sc->sc_dev.dv_xname, name, b, d, f);
299: continue;
300: }
301:
302: tag = PCITAG_CREATE(node, b, d, f);
303:
304: /*
305: * Turn on parity and fast-back-to-back for the device.
306: */
307: csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
308: if (csr & PCI_STATUS_BACKTOBACK_SUPPORT)
309: csr |= PCI_COMMAND_BACKTOBACK_ENABLE;
310: csr |= PCI_COMMAND_PARITY_ENABLE;
311: pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
312:
313: /*
314: * Initialize the latency timer register for busmaster
315: * devices to work properly.
316: * latency-timer = min-grant * bus-freq / 4 (from FreeBSD)
317: * Also initialize the cache line size register.
318: * Solaris anytime sets this register to the value 0x10.
319: */
320: bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG);
321: ic = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
322:
323: lt = min(PCI_MIN_GNT(ic) * bus_frequency / 4, 255);
324: if (lt == 0 || lt < PCI_LATTIMER(bhlc))
325: lt = PCI_LATTIMER(bhlc);
326:
327: cl = PCI_CACHELINE(bhlc);
328: if (cl == 0)
329: cl = cacheline;
330:
331: bhlc &= ~((PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT) |
332: (PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT));
333: bhlc |= (lt << PCI_LATTIMER_SHIFT) |
334: (cl << PCI_CACHELINE_SHIFT);
335: pci_conf_write(pc, tag, PCI_BHLC_REG, bhlc);
336:
337: ret = pci_probe_device(sc, tag, match, pap);
338: if (match != NULL && ret != 0)
339: return (ret);
340: }
341:
342: return (0);
343: }
344:
345: /* assume we are mapped little-endian/side-effect */
346: pcireg_t
347: pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
348: {
349: pcireg_t val = (pcireg_t)~0;
350:
351: DPRINTF(SPDB_CONF, ("pci_conf_read: tag %lx reg %x ",
352: (long)PCITAG_OFFSET(tag), reg));
353: if (PCITAG_NODE(tag) != -1) {
354: val = bus_space_read_4(pc->bustag, pc->bushandle,
355: (PCITAG_OFFSET(tag) << pc->tagshift) + reg);
356: } else
357: DPRINTF(SPDB_CONF, ("pci_conf_read: bogus pcitag %x\n",
358: (int)PCITAG_OFFSET(tag)));
359: DPRINTF(SPDB_CONF, (" returning %08x\n", (u_int)val));
360:
361: return (val);
362: }
363:
364: void
365: pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
366: {
367: DPRINTF(SPDB_CONF, ("pci_conf_write: tag %lx; reg %x; data %x; ",
368: (long)PCITAG_OFFSET(tag), reg, (int)data));
369:
370: /* If we don't know it, just punt. */
371: if (PCITAG_NODE(tag) == -1) {
372: DPRINTF(SPDB_CONF, ("pci_config_write: bad addr"));
373: return;
374: }
375:
376: bus_space_write_4(pc->bustag, pc->bushandle,
377: (PCITAG_OFFSET(tag) << pc->tagshift) + 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 < 0 || 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: interrupts = -1;
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:
423: if (pa->pa_pc->intr_map)
424: return ((*pa->pa_pc->intr_map)(pa, ihp));
425: else
426: return (0);
427: }
428:
429: int
430: pci_intr_line(pci_intr_handle_t ih)
431: {
432: return (ih);
433: }
434:
435: const char *
436: pci_intr_string(pc, ih)
437: pci_chipset_tag_t pc;
438: pci_intr_handle_t ih;
439: {
440: static char str[16];
441:
442: DPRINTF(SPDB_INTR, ("pci_intr_string: ih %u", ih));
443: snprintf(str, sizeof str, "ivec 0x%x", INTVEC(ih));
444: DPRINTF(SPDB_INTR, ("; returning %s\n", str));
445:
446: return (str);
447: }
448:
449: void *
450: pci_intr_establish(pc, ih, level, func, arg, what)
451: pci_chipset_tag_t pc;
452: pci_intr_handle_t ih;
453: int level;
454: int (*func)(void *);
455: void *arg;
456: char *what;
457: {
458: void *cookie;
459: struct psycho_pbm *pp = (struct psycho_pbm *)pc->cookie;
460:
461: DPRINTF(SPDB_INTR, ("pci_intr_establish: ih %lu; level %d",
462: (u_long)ih, level));
463: cookie = bus_intr_establish(pp->pp_memt, ih, level, 0, func, arg, what);
464:
465: DPRINTF(SPDB_INTR, ("; returning handle %p\n", cookie));
466: return (cookie);
467: }
468:
469: void
470: pci_intr_disestablish(pc, cookie)
471: pci_chipset_tag_t pc;
472: void *cookie;
473: {
474:
475: DPRINTF(SPDB_INTR, ("pci_intr_disestablish: cookie %p\n", cookie));
476:
477: /* XXX */
478: printf("can't disestablish PCI interrupts yet\n");
479: }
CVSweb