Annotation of sys/arch/sgi/pci/macepcibridge.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: macepcibridge.c,v 1.12 2007/06/21 20:17:12 miod Exp $ */
2:
3: /*
4: * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se)
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: *
27: */
28:
29: /*
30: * Machine dependent PCI BUS Bridge driver on Mace (O2).
31: */
32:
33: #include <sys/param.h>
34: #include <sys/systm.h>
35: #include <sys/kernel.h>
36: #include <sys/malloc.h>
37: #include <sys/device.h>
38: #include <sys/proc.h>
39: #include <sys/ioctl.h>
40: #include <sys/extent.h>
41: #include <uvm/uvm.h>
42:
43: #include <machine/autoconf.h>
44: #include <machine/pte.h>
45: #include <machine/cpu.h>
46: #include <machine/vmparam.h>
47:
48: #include <dev/pci/pcireg.h>
49: #include <dev/pci/pcivar.h>
50:
51: #include <mips64/archtype.h>
52: #include <sgi/localbus/crimebus.h>
53: #include <sgi/localbus/macebus.h>
54: #include <sgi/pci/macepcibrvar.h>
55:
56: extern void *macebus_intr_establish(void *, u_long, int, int,
57: int (*)(void *), void *, char *);
58: extern void macebus_intr_disestablish(void *, void *);
59: extern void pciaddr_remap(pci_chipset_tag_t);
60:
61: /**/
62: int mace_pcibrmatch(struct device *, void *, void *);
63: void mace_pcibrattach(struct device *, struct device *, void *);
64: void mace_pcibr_attach_hook(struct device *, struct device *,
65: struct pcibus_attach_args *);
66: int mace_pcibr_errintr(void *);
67:
68: pcitag_t mace_pcibr_make_tag(void *, int, int, int);
69: void mace_pcibr_decompose_tag(void *, pcitag_t, int *, int *, int *);
70:
71: int mace_pcibr_bus_maxdevs(void *, int);
72: pcireg_t mace_pcibr_conf_read(void *, pcitag_t, int);
73: void mace_pcibr_conf_write(void *, pcitag_t, int, pcireg_t);
74:
75: int mace_pcibr_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
76: const char *mace_pcibr_intr_string(void *, pci_intr_handle_t);
77: void *mace_pcibr_intr_establish(void *, pci_intr_handle_t,
78: int, int (*func)(void *), void *, char *);
79: void mace_pcibr_intr_disestablish(void *, void *);
80:
81: bus_addr_t mace_pcibr_pa_to_device(paddr_t);
82: paddr_t mace_pcibr_device_to_pa(bus_addr_t);
83:
84: struct cfattach macepcibr_ca = {
85: sizeof(struct mace_pcibr_softc), mace_pcibrmatch, mace_pcibrattach,
86: };
87:
88: struct cfdriver macepcibr_cd = {
89: NULL, "macepcibr", DV_DULL,
90: };
91:
92: long pci_io_ext_storage[EXTENT_FIXED_STORAGE_SIZE(8) / sizeof (long)];
93: long pci_mem_ext_storage[EXTENT_FIXED_STORAGE_SIZE(8) / sizeof (long)];
94:
95: bus_space_t mace_pcibbus_mem_tag = {
96: NULL,
97: (bus_addr_t)MACE_PCI_MEM_BASE,
98: NULL,
99: 0,
100: mace_pcib_read_1, mace_pcib_write_1,
101: mace_pcib_read_2, mace_pcib_write_2,
102: mace_pcib_read_4, mace_pcib_write_4,
103: mace_pcib_read_8, mace_pcib_write_8,
104: mace_pcib_space_map, mace_pcib_space_unmap, mace_pcib_space_region,
105: };
106:
107: bus_space_t mace_pcibbus_io_tag = {
108: NULL,
109: (bus_addr_t)MACE_PCI_IO_BASE,
110: NULL,
111: 0,
112: mace_pcib_read_1, mace_pcib_write_1,
113: mace_pcib_read_2, mace_pcib_write_2,
114: mace_pcib_read_4, mace_pcib_write_4,
115: mace_pcib_read_8, mace_pcib_write_8,
116: mace_pcib_space_map, mace_pcib_space_unmap, mace_pcib_space_region,
117: };
118:
119: /*
120: * PCI doesn't have any special needs; just use the generic versions
121: * of these functions.
122: */
123: struct machine_bus_dma_tag pci_bus_dma_tag = {
124: NULL, /* _cookie */
125: _dmamap_create,
126: _dmamap_destroy,
127: _dmamap_load,
128: _dmamap_load_mbuf,
129: _dmamap_load_uio,
130: _dmamap_load_raw,
131: _dmamap_unload,
132: _dmamap_sync,
133: _dmamem_alloc,
134: _dmamem_free,
135: _dmamem_map,
136: _dmamem_unmap,
137: _dmamem_mmap,
138: mace_pcibr_pa_to_device,
139: mace_pcibr_device_to_pa,
140: CRIME_MEMORY_MASK
141: };
142:
143: struct _perr_map {
144: pcireg_t mask;
145: pcireg_t flag;
146: char *text;
147: } perr_map[] = {
148: { PERR_MASTER_ABORT, PERR_MASTER_ABORT_ADDR_VALID, "master abort" },
149: { PERR_TARGET_ABORT, PERR_TARGET_ABORT_ADDR_VALID, "target abort" },
150: { PERR_DATA_PARITY_ERR,PERR_DATA_PARITY_ADDR_VALID, "data parity error" },
151: { PERR_RETRY_ERR, PERR_RETRY_ADDR_VALID, "retry error" },
152: { PERR_ILLEGAL_CMD, 0, "illegal command" },
153: { PERR_SYSTEM_ERR, 0, "system error" },
154: { PERR_INTERRUPT_TEST,0, "interrupt test" },
155: { PERR_PARITY_ERR, 0, "parity error" },
156: { PERR_OVERRUN, 0, "overrun error" },
157: { PERR_RSVD, 0, "reserved ??" },
158: { PERR_MEMORY_ADDR, 0, "memory address" },
159: { PERR_CONFIG_ADDR, 0, "config address" },
160: { 0, 0 }
161: };
162:
163:
164: static int mace_pcibrprint(void *, const char *pnp);
165:
166:
167: int
168: mace_pcibrmatch(struct device *parent, void *match, void *aux)
169: {
170: switch(sys_config.system_type) {
171: case SGI_O2:
172: return 1;
173: }
174: return (0);
175: }
176:
177: void
178: mace_pcibrattach(struct device *parent, struct device *self, void *aux)
179: {
180: struct mace_pcibr_softc *sc = (struct mace_pcibr_softc *)self;
181: struct pcibus_attach_args pba;
182: struct confargs *ca = aux;
183: pcireg_t pcireg;
184:
185: /*
186: * Common to all bridge chips.
187: */
188: sc->sc_pc.pc_conf_v = sc;
189: sc->sc_pc.pc_attach_hook = mace_pcibr_attach_hook;
190: sc->sc_pc.pc_make_tag = mace_pcibr_make_tag;
191: sc->sc_pc.pc_decompose_tag = mace_pcibr_decompose_tag;
192: sc->sc_pc.pc_sync_cache = sys_config._IOSyncDCache;
193:
194: /* Create extents for PCI mappings */
195: mace_pcibbus_io_tag.bus_extent = extent_create("pci_io",
196: MACE_PCI_IO_BASE, MACE_PCI_IO_BASE + MACE_PCI_IO_SIZE - 1,
197: M_DEVBUF, (caddr_t)pci_io_ext_storage,
198: sizeof(pci_io_ext_storage), EX_NOCOALESCE|EX_NOWAIT);
199:
200: mace_pcibbus_mem_tag.bus_extent = extent_create("pci_mem",
201: MACE_PCI_MEM_BASE, MACE_PCI_MEM_BASE + MACE_PCI_MEM_SIZE - 1,
202: M_DEVBUF, (caddr_t)pci_mem_ext_storage,
203: sizeof(pci_mem_ext_storage), EX_NOCOALESCE|EX_NOWAIT);
204:
205: /* local -> PCI MEM mapping offset */
206: sc->sc_mem_bus_space = &mace_pcibbus_mem_tag;
207:
208: /* local -> PCI IO mapping offset */
209: sc->sc_io_bus_space = &mace_pcibbus_io_tag;
210:
211: /* Map in PCI control registers */
212: sc->sc_memt = ca->ca_memt;
213: if (bus_space_map(sc->sc_memt, MACE_PCI_OFFS, 4096, 0, &sc->sc_memh)) {
214: printf("UH-OH! Can't map PCI control registers!\n");
215: return;
216: }
217: pcireg = bus_space_read_4(sc->sc_memt, sc->sc_memh, MACE_PCI_REVISION);
218:
219: printf(": mace rev %d, host system O2\n", pcireg);
220:
221: /* Register the PCI ERROR interrupt handler */
222: BUS_INTR_ESTABLISH(ca, NULL, 8, IST_LEVEL, IPL_HIGH,
223: mace_pcibr_errintr, (void *)sc, sc->sc_dev.dv_xname);
224:
225: sc->sc_pc.pc_bus_maxdevs = mace_pcibr_bus_maxdevs;
226: sc->sc_pc.pc_conf_read = mace_pcibr_conf_read;
227: sc->sc_pc.pc_conf_write = mace_pcibr_conf_write;
228:
229: sc->sc_pc.pc_intr_v = NULL;
230: sc->sc_pc.pc_intr_map = mace_pcibr_intr_map;
231: sc->sc_pc.pc_intr_string = mace_pcibr_intr_string;
232: sc->sc_pc.pc_intr_establish = mace_pcibr_intr_establish;
233: sc->sc_pc.pc_intr_disestablish = mace_pcibr_intr_disestablish;
234:
235: /*
236: * Firmware sucks. Remap PCI BAR registers. (sigh)
237: */
238: pciaddr_remap(&sc->sc_pc);
239:
240: /*
241: * Configure our PCI devices.
242: */
243: pba.pba_busname = "pci";
244: pba.pba_iot = sc->sc_io_bus_space;
245: pba.pba_memt = sc->sc_mem_bus_space;
246: pba.pba_dmat = malloc(sizeof(pci_bus_dma_tag), M_DEVBUF, M_NOWAIT);
247: *pba.pba_dmat = pci_bus_dma_tag;
248: pba.pba_pc = &sc->sc_pc;
249: pba.pba_domain = pci_ndomains++;
250: pba.pba_bus = sc->sc_dev.dv_unit;
251: pba.pba_bridgetag = NULL;
252: config_found(self, &pba, mace_pcibrprint);
253:
254: /* Clear PCI errors and set up error interrupt */
255: bus_space_write_4(sc->sc_memt, sc->sc_memh, MACE_PCI_ERROR_FLAGS, 0);
256: pcireg = bus_space_read_4(sc->sc_memt, sc->sc_memh, MACE_PCI_CONTROL);
257: pcireg |= MACE_PCI_INTCTRL;
258: bus_space_write_4(sc->sc_memt, sc->sc_memh, MACE_PCI_CONTROL, pcireg);
259: }
260:
261: static int
262: mace_pcibrprint(aux, pnp)
263: void *aux;
264: const char *pnp;
265: {
266: struct pcibus_attach_args *pba = aux;
267:
268: if (pnp)
269: printf("%s at %s", pba->pba_busname, pnp);
270: printf(" bus %d", pba->pba_bus);
271: return(UNCONF);
272: }
273:
274: void
275: mace_pcibr_attach_hook(parent, self, pba)
276: struct device *parent, *self;
277: struct pcibus_attach_args *pba;
278: {
279: }
280:
281: int
282: mace_pcibr_errintr(void *v)
283: {
284: struct mace_pcibr_softc *sc = v;
285: bus_space_tag_t memt = sc->sc_memt;
286: bus_space_handle_t memh = sc->sc_memh;
287: struct _perr_map *emap = perr_map;
288: pcireg_t stat, erraddr;
289:
290: /* Check and clear any PCI error, report found */
291: stat = bus_space_read_4(memt, memh, MACE_PCI_ERROR_FLAGS);
292: erraddr = bus_space_read_4(memt, memh, MACE_PCI_ERROR_ADDRESS);
293: while (emap->mask) {
294: if (stat & emap->mask) {
295: printf("mace: pci err %s", emap->text);
296: if (emap->flag && stat & emap->flag)
297: printf(" at address %p", erraddr);
298: printf("\n");
299: }
300: emap++;
301: }
302: bus_space_write_4(memt, memh, MACE_PCI_ERROR_FLAGS, 0);
303: return 1;
304: }
305:
306: /*
307: * PCI access drivers
308: */
309:
310: pcitag_t
311: mace_pcibr_make_tag(cpv, bus, dev, fnc)
312: void *cpv;
313: int bus, dev, fnc;
314: {
315: return (bus << 16) | (dev << 11) | (fnc << 8);
316: }
317:
318: void
319: mace_pcibr_decompose_tag(cpv, tag, busp, devp, fncp)
320: void *cpv;
321: pcitag_t tag;
322: int *busp, *devp, *fncp;
323: {
324: if (busp != NULL)
325: *busp = (tag >> 16) & 0x7;
326: if (devp != NULL)
327: *devp = (tag >> 11) & 0x1f;
328: if (fncp != NULL)
329: *fncp = (tag >> 8) & 0x7;
330: }
331:
332: int
333: mace_pcibr_bus_maxdevs(cpv, busno)
334: void *cpv;
335: int busno;
336: {
337: return(16);
338: }
339:
340: pcireg_t
341: mace_pcibr_conf_read(cpv, tag, offset)
342: void *cpv;
343: pcitag_t tag;
344: int offset;
345: {
346: struct mace_pcibr_softc *sc = cpv;
347: bus_space_tag_t memt = sc->sc_memt;
348: bus_space_handle_t memh = sc->sc_memh;
349: pcireg_t data, stat;
350: int s;
351:
352: s = splhigh();
353:
354: bus_space_write_4(memt, memh, MACE_PCI_ERROR_FLAGS, 0);
355: data = tag | offset;
356: bus_space_write_4(memt, memh, MACE_PCI_CFGADDR, data);
357: data = bus_space_read_4(memt, memh, MACE_PCI_CFGDATA);
358: bus_space_write_4(memt, memh, MACE_PCI_CFGADDR, 0);
359:
360: /* Check and clear any PCI error, returns -1 if error is found */
361: stat = bus_space_read_4(memt, memh, MACE_PCI_ERROR_FLAGS);
362: bus_space_write_4(memt, memh, MACE_PCI_ERROR_FLAGS, 0);
363: if (stat & (PERR_MASTER_ABORT | PERR_TARGET_ABORT |
364: PERR_DATA_PARITY_ERR | PERR_RETRY_ERR)) {
365: data = -1;
366: }
367:
368: splx(s);
369: return(data);
370: }
371:
372: void
373: mace_pcibr_conf_write(cpv, tag, offset, data)
374: void *cpv;
375: pcitag_t tag;
376: int offset;
377: pcireg_t data;
378: {
379: struct mace_pcibr_softc *sc = cpv;
380: pcireg_t addr;
381: int s;
382:
383: s = splhigh();
384:
385: addr = tag | offset;
386: bus_space_write_4(sc->sc_memt, sc->sc_memh, MACE_PCI_CFGADDR, addr);
387: bus_space_write_4(sc->sc_memt, sc->sc_memh, MACE_PCI_CFGDATA, data);
388: bus_space_write_4(sc->sc_memt, sc->sc_memh, MACE_PCI_CFGADDR, 0);
389:
390: splx(s);
391: }
392:
393: int
394: mace_pcibr_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
395: {
396: int bus, device, pirq;
397:
398: *ihp = -1;
399:
400: if (pa->pa_intrpin == 0) {
401: /* No IRQ used. */
402: return 1;
403: }
404: if (pa->pa_intrpin > 4) {
405: printf("mace_pcibr_intr_map: bad interrupt pin %d\n", pa->pa_intrpin);
406: return 1;
407: }
408:
409: mace_pcibr_decompose_tag((void *)NULL, pa->pa_tag, &bus, &device, NULL);
410:
411: if (sys_config.system_type == SGI_O2) {
412: pirq = -1;
413: switch (device) {
414: case 1:
415: pirq = 9;
416: break;
417: case 2:
418: pirq = 10;
419: break;
420: case 3:
421: pirq = 11;
422: break;
423: }
424: }
425:
426: *ihp = pirq;
427: return 0;
428: }
429:
430: const char *
431: mace_pcibr_intr_string(lcv, ih)
432: void *lcv;
433: pci_intr_handle_t ih;
434: {
435: static char str[16];
436:
437: snprintf(str, sizeof(str), "irq %d", ih);
438: return(str);
439: }
440:
441: void *
442: mace_pcibr_intr_establish(lcv, ih, level, func, arg, name)
443: void *lcv;
444: pci_intr_handle_t ih;
445: int level;
446: int (*func)(void *);
447: void *arg;
448: char *name;
449: {
450: return macebus_intr_establish(NULL, ih, IST_LEVEL, level, func, arg, name);
451: }
452:
453: void
454: mace_pcibr_intr_disestablish(lcv, cookie)
455: void *lcv, *cookie;
456: {
457: macebus_intr_disestablish(lcv, cookie);
458: }
459:
460: /*
461: * Bus access primitives
462: * XXX 64 bit access not clean in lp32 mode.
463: */
464:
465: u_int8_t
466: mace_pcib_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
467: {
468: return *(volatile u_int8_t *)(h + (o | 3) - (o & 3));
469: }
470:
471: u_int16_t
472: mace_pcib_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
473: {
474: return *(volatile u_int16_t *)(h + (o | 2) - (o & 3));
475: }
476:
477: u_int32_t
478: mace_pcib_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
479: {
480: return *(volatile u_int32_t *)(h + o);
481: }
482:
483: u_int64_t
484: mace_pcib_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
485: {
486: return *(volatile u_int64_t *)(h + o);
487: }
488:
489: void
490: mace_pcib_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int8_t v)
491: {
492: *(volatile u_int8_t *)(h + (o | 3) - (o & 3)) = v;
493: }
494:
495: void
496: mace_pcib_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int16_t v)
497: {
498: *(volatile u_int16_t *)(h + (o | 2) - (o & 3)) = v;
499: }
500:
501: void
502: mace_pcib_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int32_t v)
503: {
504: *(volatile u_int32_t *)(h + o) = v;
505: }
506:
507: void
508: mace_pcib_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int64_t v)
509: {
510: *(volatile u_int64_t *)(h + o) = v;
511: }
512:
513: extern int extent_malloc_flags;
514:
515: int
516: mace_pcib_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size,
517: int cacheable, bus_space_handle_t *bshp)
518: {
519: bus_addr_t bpa;
520: int error;
521: bpa = t->bus_base + (offs & 0x01ffffff);
522:
523: if ((error = extent_alloc_region(t->bus_extent, bpa, size,
524: EX_NOWAIT | extent_malloc_flags))) {
525: return error;
526: }
527:
528: if ((error = bus_mem_add_mapping(bpa, size, cacheable, bshp))) {
529: if (extent_free(t->bus_extent, bpa, size,
530: EX_NOWAIT | extent_malloc_flags)) {
531: printf("bus_space_map: pa %p, size %p\n", bpa, size);
532: printf("bus_space_map: can't free region\n");
533: }
534: }
535:
536: return (error);
537: }
538:
539: void
540: mace_pcib_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
541: {
542: bus_addr_t sva;
543: bus_size_t off, len;
544: bus_addr_t paddr;
545:
546: /* should this verify that the proper size is freed? */
547: sva = trunc_page(bsh);
548: off = bsh - sva;
549: len = size+off;
550:
551: if (pmap_extract(pmap_kernel(), bsh, (void *)&paddr) == 0) {
552: printf("bus_space_unmap: no pa for va %p\n", bsh);
553: return;
554: }
555:
556: if (extent_free(t->bus_extent, paddr, size,
557: EX_NOWAIT | extent_malloc_flags)) {
558: printf("bus_space_map: pa %p, size %p\n", paddr, size);
559: printf("bus_space_map: can't free region\n");
560: }
561: }
562:
563: int
564: mace_pcib_space_region(bus_space_tag_t t, bus_space_handle_t bsh,
565: bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
566: {
567: *nbshp = bsh + offset;
568: return (0);
569: }
570:
571: /*
572: * Mace PCI bus_dma helpers.
573: * The PCI bus accesses memory contiguously at 0x00000000 onwards.
574: */
575:
576: bus_addr_t
577: mace_pcibr_pa_to_device(paddr_t pa)
578: {
579: return (pa & CRIME_MEMORY_MASK);
580: }
581:
582: paddr_t
583: mace_pcibr_device_to_pa(bus_addr_t addr)
584: {
585: paddr_t pa = (paddr_t)addr & CRIME_MEMORY_MASK;
586:
587: if (pa >= 256 * 1024 * 1024)
588: pa |= CRIME_MEMORY_OFFSET;
589:
590: return (pa);
591: }
CVSweb