Annotation of sys/arch/sparc64/dev/pyro.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: pyro.c,v 1.7 2007/04/03 19:59:01 kettenis Exp $ */
2:
3: /*
4: * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5: * Copyright (c) 2003 Henric Jungheim
6: * Copyright (c) 2007 Mark Kettenis
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
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
20: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28: * POSSIBILITY OF SUCH DAMAGE.
29: */
30:
31: #include <sys/param.h>
32: #include <sys/device.h>
33: #include <sys/errno.h>
34: #include <sys/malloc.h>
35: #include <sys/systm.h>
36:
37: #define _SPARC_BUS_DMA_PRIVATE
38: #include <machine/bus.h>
39: #include <machine/autoconf.h>
40:
41: #include <dev/pci/pcivar.h>
42: #include <dev/pci/pcireg.h>
43:
44: #include <sparc64/dev/iommureg.h>
45: #include <sparc64/dev/iommuvar.h>
46: #include <sparc64/dev/pyrovar.h>
47:
48: #ifdef DEBUG
49: #define PDB_PROM 0x01
50: #define PDB_BUSMAP 0x02
51: #define PDB_INTR 0x04
52: #define PDB_CONF 0x08
53: int pyro_debug = ~0;
54: #define DPRINTF(l, s) do { if (pyro_debug & l) printf s; } while (0)
55: #else
56: #define DPRINTF(l, s)
57: #endif
58:
59: extern struct sparc_pci_chipset _sparc_pci_chipset;
60:
61: int pyro_match(struct device *, void *, void *);
62: void pyro_attach(struct device *, struct device *, void *);
63: void pyro_init(struct pyro_softc *, int);
64: void pyro_init_iommu(struct pyro_softc *, struct pyro_pbm *);
65: int pyro_print(void *, const char *);
66:
67: pci_chipset_tag_t pyro_alloc_chipset(struct pyro_pbm *, int,
68: pci_chipset_tag_t);
69: bus_space_tag_t pyro_alloc_mem_tag(struct pyro_pbm *);
70: bus_space_tag_t pyro_alloc_io_tag(struct pyro_pbm *);
71: bus_space_tag_t pyro_alloc_config_tag(struct pyro_pbm *);
72: bus_space_tag_t _pyro_alloc_bus_tag(struct pyro_pbm *, const char *,
73: int, int, int);
74: bus_dma_tag_t pyro_alloc_dma_tag(struct pyro_pbm *);
75:
76: int pyro_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
77: int _pyro_bus_map(bus_space_tag_t, bus_space_tag_t, bus_addr_t,
78: bus_size_t, int, bus_space_handle_t *);
79: paddr_t _pyro_bus_mmap(bus_space_tag_t, bus_space_tag_t, bus_addr_t, off_t,
80: int, int);
81: void *_pyro_intr_establish(bus_space_tag_t, bus_space_tag_t, int, int, int,
82: int (*)(void *), void *, const char *);
83:
84: int pyro_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, bus_size_t, int,
85: bus_size_t, bus_size_t, int, bus_dmamap_t *);
86:
87: int
88: pyro_match(struct device *parent, void *match, void *aux)
89: {
90: struct mainbus_attach_args *ma = aux;
91: char *str;
92:
93: if (strcmp(ma->ma_name, "pci") != 0)
94: return (0);
95:
96: str = getpropstring(ma->ma_node, "compatible");
97: if (strcmp(str, "pciex108e,80f0") == 0)
98: return (1);
99:
100: return (0);
101: }
102:
103: void
104: pyro_attach(struct device *parent, struct device *self, void *aux)
105: {
106: struct pyro_softc *sc = (struct pyro_softc *)self;
107: struct mainbus_attach_args *ma = aux;
108: int busa;
109:
110: sc->sc_node = ma->ma_node;
111: sc->sc_dmat = ma->ma_dmatag;
112: sc->sc_bust = ma->ma_bustag;
113: sc->sc_csr = ma->ma_reg[0].ur_paddr;
114: sc->sc_xbc = ma->ma_reg[1].ur_paddr;
115: sc->sc_ign = INTIGN(ma->ma_upaid << INTMAP_IGN_SHIFT);
116:
117: if ((ma->ma_reg[0].ur_paddr & 0x00700000) == 0x00600000)
118: busa = 1;
119: else
120: busa = 0;
121:
122: if (bus_space_map(sc->sc_bust, sc->sc_csr,
123: ma->ma_reg[0].ur_len, 0, &sc->sc_csrh)) {
124: printf(": failed to map csr registers\n");
125: return;
126: }
127:
128: if (bus_space_map(sc->sc_bust, sc->sc_xbc,
129: ma->ma_reg[1].ur_len, 0, &sc->sc_xbch)) {
130: printf(": failed to map xbc registers\n");
131: return;
132: }
133:
134: pyro_init(sc, busa);
135: }
136:
137: void
138: pyro_init(struct pyro_softc *sc, int busa)
139: {
140: struct pyro_pbm *pbm;
141: struct pcibus_attach_args pba;
142: int *busranges = NULL, nranges;
143:
144: pbm = (struct pyro_pbm *)malloc(sizeof(*pbm), M_DEVBUF, M_NOWAIT);
145: if (pbm == NULL)
146: panic("pyro: can't alloc pyro pbm");
147: bzero(pbm, sizeof(*pbm));
148:
149: pbm->pp_sc = sc;
150: pbm->pp_bus_a = busa;
151:
152: if (getprop(sc->sc_node, "ranges", sizeof(struct pyro_range),
153: &pbm->pp_nrange, (void **)&pbm->pp_range))
154: panic("pyro: can't get ranges");
155:
156: if (getprop(sc->sc_node, "bus-range", sizeof(int), &nranges,
157: (void **)&busranges))
158: panic("pyro: can't get bus-range");
159:
160: printf(": \"%s\", rev %d, ign %x, bus %c %d to %d\n",
161: sc->sc_oberon ? "Oberon" : "Fire",
162: getpropint(sc->sc_node, "module-revision#", 0), sc->sc_ign,
163: busa ? 'A' : 'B', busranges[0], busranges[1]);
164:
165: printf("%s: ", sc->sc_dv.dv_xname);
166: pyro_init_iommu(sc, pbm);
167:
168: pbm->pp_memt = pyro_alloc_mem_tag(pbm);
169: pbm->pp_iot = pyro_alloc_io_tag(pbm);
170: pbm->pp_cfgt = pyro_alloc_config_tag(pbm);
171: pbm->pp_dmat = pyro_alloc_dma_tag(pbm);
172:
173: if (bus_space_map(pbm->pp_cfgt, 0, 0x10000000, 0, &pbm->pp_cfgh))
174: panic("pyro: could not map config space");
175:
176: pbm->pp_pc = pyro_alloc_chipset(pbm, sc->sc_node, &_sparc_pci_chipset);
177:
178: pbm->pp_pc->bustag = pbm->pp_cfgt;
179: pbm->pp_pc->bushandle = pbm->pp_cfgh;
180:
181: pba.pba_busname = "pci";
182: pba.pba_domain = pci_ndomains++;
183: pba.pba_bus = busranges[0];
184: pba.pba_bridgetag = NULL;
185: pba.pba_pc = pbm->pp_pc;
186: #if 0
187: pba.pba_flags = pbm->pp_flags;
188: #endif
189: pba.pba_dmat = pbm->pp_dmat;
190: pba.pba_memt = pbm->pp_memt;
191: pba.pba_iot = pbm->pp_iot;
192: pba.pba_pc->intr_map = pyro_intr_map;
193:
194: free(busranges, M_DEVBUF);
195:
196: config_found(&sc->sc_dv, &pba, pyro_print);
197: }
198:
199: void
200: pyro_init_iommu(struct pyro_softc *sc, struct pyro_pbm *pbm)
201: {
202: struct iommu_state *is = &pbm->pp_is;
203: int tsbsize = 7;
204: u_int32_t iobase = -1;
205: char *name;
206:
207: is->is_bustag = sc->sc_bust;
208:
209: if (bus_space_subregion(is->is_bustag, sc->sc_csrh,
210: 0x40000, 0x100, &is->is_iommu)) {
211: panic("pyro: unable to create iommu handle");
212: }
213:
214: is->is_sb[0] = &pbm->pp_sb;
215: is->is_sb[0]->sb_bustag = is->is_bustag;
216:
217: name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
218: if (name == NULL)
219: panic("couldn't malloc iommu name");
220: snprintf(name, 32, "%s dvma", sc->sc_dv.dv_xname);
221:
222: iommu_init(name, is, tsbsize, iobase);
223: }
224:
225: int
226: pyro_print(void *aux, const char *p)
227: {
228: if (p == NULL)
229: return (UNCONF);
230: return (QUIET);
231: }
232:
233: /*
234: * Bus-specific interrupt mapping
235: */
236: int
237: pyro_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
238: {
239: struct pyro_pbm *pp = pa->pa_pc->cookie;
240: struct pyro_softc *sc = pp->pp_sc;
241: u_int dev;
242:
243: if (*ihp != (pci_intr_handle_t)-1) {
244: *ihp |= sc->sc_ign;
245: return (0);
246: }
247:
248: /*
249: * We didn't find a PROM mapping for this interrupt. Try to
250: * construct one ourselves based on the swizzled interrupt pin
251: * and the interrupt mapping for PCI slots documented in the
252: * UltraSPARC-IIi User's Manual.
253: */
254:
255: if (pa->pa_intrpin == 0)
256: return (-1);
257:
258: /*
259: * This deserves some documentation. Should anyone
260: * have anything official looking, please speak up.
261: */
262: dev = pa->pa_device - 1;
263:
264: *ihp = (pa->pa_intrpin - 1) & INTMAP_PCIINT;
265: *ihp |= (dev << 2) & INTMAP_PCISLOT;
266: *ihp |= sc->sc_ign;
267:
268: return (0);
269: }
270:
271: bus_space_tag_t
272: pyro_alloc_mem_tag(struct pyro_pbm *pp)
273: {
274: return (_pyro_alloc_bus_tag(pp, "mem",
275: 0x02, /* 32-bit mem space (where's the #define???) */
276: ASI_PRIMARY, ASI_PRIMARY_LITTLE));
277: }
278:
279: bus_space_tag_t
280: pyro_alloc_io_tag(struct pyro_pbm *pp)
281: {
282: return (_pyro_alloc_bus_tag(pp, "io",
283: 0x01, /* IO space (where's the #define???) */
284: ASI_PHYS_NON_CACHED_LITTLE, ASI_PHYS_NON_CACHED));
285: }
286:
287: bus_space_tag_t
288: pyro_alloc_config_tag(struct pyro_pbm *pp)
289: {
290: return (_pyro_alloc_bus_tag(pp, "cfg",
291: 0x00, /* Config space (where's the #define???) */
292: ASI_PHYS_NON_CACHED_LITTLE, ASI_PHYS_NON_CACHED));
293: }
294:
295: bus_space_tag_t
296: _pyro_alloc_bus_tag(struct pyro_pbm *pbm, const char *name, int ss,
297: int asi, int sasi)
298: {
299: struct pyro_softc *sc = pbm->pp_sc;
300: struct sparc_bus_space_tag *bt;
301:
302: bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT);
303: if (bt == NULL)
304: panic("pyro: could not allocate bus tag");
305:
306: bzero(bt, sizeof *bt);
307: snprintf(bt->name, sizeof(bt->name), "%s-pbm_%s(%d/%2.2x)",
308: sc->sc_dv.dv_xname, name, ss, asi);
309:
310: bt->cookie = pbm;
311: bt->parent = sc->sc_bust;
312: bt->default_type = ss;
313: bt->asi = asi;
314: bt->sasi = sasi;
315: bt->sparc_bus_map = _pyro_bus_map;
316: bt->sparc_bus_mmap = _pyro_bus_mmap;
317: bt->sparc_intr_establish = _pyro_intr_establish;
318: return (bt);
319: }
320:
321: bus_dma_tag_t
322: pyro_alloc_dma_tag(struct pyro_pbm *pbm)
323: {
324: struct pyro_softc *sc = pbm->pp_sc;
325: bus_dma_tag_t dt, pdt = sc->sc_dmat;
326:
327: dt = (bus_dma_tag_t)malloc(sizeof(struct sparc_bus_dma_tag),
328: M_DEVBUF, M_NOWAIT);
329: if (dt == NULL)
330: panic("pyro: could not alloc dma tag");
331:
332: bzero(dt, sizeof(*dt));
333: dt->_cookie = pbm;
334: dt->_parent = pdt;
335: dt->_dmamap_create = pyro_dmamap_create;
336: dt->_dmamap_destroy = iommu_dvmamap_destroy;
337: dt->_dmamap_load = iommu_dvmamap_load;
338: dt->_dmamap_load_raw = iommu_dvmamap_load_raw;
339: dt->_dmamap_unload = iommu_dvmamap_unload;
340: dt->_dmamap_sync = iommu_dvmamap_sync;
341: dt->_dmamem_alloc = iommu_dvmamem_alloc;
342: dt->_dmamem_free = iommu_dvmamem_free;
343: dt->_dmamem_map = iommu_dvmamem_map;
344: dt->_dmamem_unmap = iommu_dvmamem_unmap;
345: return (dt);
346: }
347:
348: pci_chipset_tag_t
349: pyro_alloc_chipset(struct pyro_pbm *pbm, int node, pci_chipset_tag_t pc)
350: {
351: pci_chipset_tag_t npc;
352:
353: npc = malloc(sizeof *npc, M_DEVBUF, M_NOWAIT);
354: if (npc == NULL)
355: panic("pyro: could not allocate pci_chipset_tag_t");
356: memcpy(npc, pc, sizeof *pc);
357: npc->cookie = pbm;
358: npc->rootnode = node;
359: npc->tagshift = 4; /* PCIe has a larger config space */
360: return (npc);
361: }
362:
363: int
364: pyro_dmamap_create(bus_dma_tag_t t, bus_dma_tag_t t0, bus_size_t size,
365: int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags,
366: bus_dmamap_t *dmamp)
367: {
368: struct pyro_pbm *pp = t->_cookie;
369:
370: return (iommu_dvmamap_create(t, t0, &pp->pp_sb, size, nsegments,
371: maxsegsz, boundary, flags, dmamp));
372: }
373:
374: int
375: _pyro_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
376: bus_size_t size, int flags, bus_space_handle_t *hp)
377: {
378: struct pyro_pbm *pbm = t->cookie;
379: int i, ss;
380:
381: DPRINTF(PDB_BUSMAP, ("_pyro_bus_map: type %d off %qx sz %qx flags %d",
382: t->default_type,
383: (unsigned long long)offset,
384: (unsigned long long)size,
385: flags));
386:
387: ss = t->default_type;
388: DPRINTF(PDB_BUSMAP, (" cspace %d", ss));
389:
390: if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
391: printf("\n_pyro_bus_map: invalid parent");
392: return (EINVAL);
393: }
394:
395: if (flags & BUS_SPACE_MAP_PROMADDRESS) {
396: return ((*t->parent->sparc_bus_map)
397: (t, t0, offset, size, flags, hp));
398: }
399:
400: for (i = 0; i < pbm->pp_nrange; i++) {
401: bus_addr_t paddr;
402:
403: if (((pbm->pp_range[i].cspace >> 24) & 0x03) != ss)
404: continue;
405:
406: paddr = pbm->pp_range[i].phys_lo + offset;
407: paddr |= ((bus_addr_t)pbm->pp_range[i].phys_hi) << 32;
408: return ((*t->parent->sparc_bus_map)
409: (t, t0, paddr, size, flags, hp));
410: }
411:
412: return (EINVAL);
413: }
414:
415: paddr_t
416: _pyro_bus_mmap(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t paddr,
417: off_t off, int prot, int flags)
418: {
419: bus_addr_t offset = paddr;
420: struct pyro_pbm *pbm = t->cookie;
421: int i, ss;
422:
423: ss = t->default_type;
424:
425: DPRINTF(PDB_BUSMAP, ("_pyro_bus_mmap: prot %d flags %d pa %qx\n",
426: prot, flags, (unsigned long long)paddr));
427:
428: if (t->parent == 0 || t->parent->sparc_bus_mmap == 0) {
429: printf("\n_pyro_bus_mmap: invalid parent");
430: return (-1);
431: }
432:
433: for (i = 0; i < pbm->pp_nrange; i++) {
434: bus_addr_t paddr;
435:
436: if (((pbm->pp_range[i].cspace >> 24) & 0x03) != ss)
437: continue;
438:
439: paddr = pbm->pp_range[i].phys_lo + offset;
440: paddr |= ((bus_addr_t)pbm->pp_range[i].phys_hi<<32);
441: return ((*t->parent->sparc_bus_mmap)
442: (t, t0, paddr, off, prot, flags));
443: }
444:
445: return (-1);
446: }
447:
448: void *
449: _pyro_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
450: int level, int flags, int (*handler)(void *), void *arg, const char *what)
451: {
452: struct pyro_pbm *pbm = t->cookie;
453: struct pyro_softc *sc = pbm->pp_sc;
454: struct intrhand *ih = NULL;
455: volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
456: int ino;
457:
458: ino = INTINO(ihandle);
459:
460: if (level == IPL_NONE)
461: level = INTLEV(ihandle);
462: if (level == IPL_NONE) {
463: printf(": no IPL, setting IPL 2.\n");
464: level = 2;
465: }
466:
467: if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
468: u_int64_t *imap, *iclr;
469:
470: imap = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1000;
471: iclr = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1400;
472: intrmapptr = &imap[ino];
473: intrclrptr = &iclr[ino];
474: ino |= INTVEC(ihandle);
475: }
476:
477: ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr,
478: intrclrptr, what);
479: if (ih == NULL)
480: return (NULL);
481:
482: intr_establish(ih->ih_pil, ih);
483:
484: if (intrmapptr != NULL) {
485: u_int64_t intrmap;
486:
487: intrmap = *intrmapptr;
488: intrmap |= (1LL << 6);
489: intrmap |= INTMAP_V;
490: *intrmapptr = intrmap;
491: intrmap = *intrmapptr;
492: ih->ih_number |= intrmap & INTMAP_INR;
493: }
494:
495: return (ih);
496: }
497:
498: const struct cfattach pyro_ca = {
499: sizeof(struct pyro_softc), pyro_match, pyro_attach
500: };
501:
502: struct cfdriver pyro_cd = {
503: NULL, "pyro", DV_DULL
504: };
CVSweb