Annotation of sys/dev/sbus/qec.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: qec.c,v 1.10 2006/06/02 20:00:56 miod Exp $ */
2: /* $NetBSD: qec.c,v 1.12 2000/12/04 20:12:55 fvdl Exp $ */
3:
4: /*-
5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Paul Kranenburg.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: #include <sys/types.h>
41: #include <sys/param.h>
42: #include <sys/systm.h>
43: #include <sys/kernel.h>
44: #include <sys/errno.h>
45: #include <sys/device.h>
46: #include <sys/malloc.h>
47:
48: #include <machine/bus.h>
49: #include <machine/intr.h>
50: #include <machine/autoconf.h>
51:
52: #include <dev/sbus/sbusvar.h>
53: #include <dev/sbus/qecreg.h>
54: #include <dev/sbus/qecvar.h>
55:
56: int qecprint(void *, const char *);
57: int qecmatch(struct device *, void *, void *);
58: void qecattach(struct device *, struct device *, void *);
59: void qec_init(struct qec_softc *);
60:
61: int qec_bus_map(
62: bus_space_tag_t,
63: bus_space_tag_t,
64: bus_addr_t, /*offset*/
65: bus_size_t, /*size*/
66: int, /*flags*/
67: bus_space_handle_t *);
68: void * qec_intr_establish(
69: bus_space_tag_t,
70: bus_space_tag_t,
71: int, /*bus interrupt priority*/
72: int, /*`device class' interrupt level*/
73: int, /*flags*/
74: int (*)(void *), /*handler*/
75: void *, /*arg*/
76: const char *); /*what*/
77:
78: struct cfattach qec_ca = {
79: sizeof(struct qec_softc), qecmatch, qecattach
80: };
81:
82: struct cfdriver qec_cd = {
83: NULL, "qec", DV_DULL
84: };
85:
86: int
87: qecprint(aux, busname)
88: void *aux;
89: const char *busname;
90: {
91: struct sbus_attach_args *sa = aux;
92: bus_space_tag_t t = sa->sa_bustag;
93: struct qec_softc *sc = t->cookie;
94:
95: sa->sa_bustag = sc->sc_bustag; /* XXX */
96: sbus_print(aux, busname); /* XXX */
97: sa->sa_bustag = t; /* XXX */
98: return (UNCONF);
99: }
100:
101: int
102: qecmatch(parent, vcf, aux)
103: struct device *parent;
104: void *vcf;
105: void *aux;
106: {
107: struct cfdata *cf = vcf;
108: struct sbus_attach_args *sa = aux;
109:
110: return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
111: }
112:
113: /*
114: * Attach all the sub-devices we can find
115: */
116: void
117: qecattach(parent, self, aux)
118: struct device *parent, *self;
119: void *aux;
120: {
121: struct sbus_attach_args *sa = aux;
122: struct qec_softc *sc = (void *)self;
123: int node;
124: int sbusburst;
125: struct sparc_bus_space_tag *sbt;
126: bus_space_handle_t bh;
127: int error;
128:
129: sc->sc_bustag = sa->sa_bustag;
130: sc->sc_dmatag = sa->sa_dmatag;
131: node = sa->sa_node;
132:
133: if (sa->sa_nreg < 2) {
134: printf("%s: only %d register sets\n",
135: self->dv_xname, sa->sa_nreg);
136: return;
137: }
138:
139: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
140: sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size,
141: 0, 0, &sc->sc_regs) != 0) {
142: printf("%s: attach: cannot map registers\n", self->dv_xname);
143: return;
144: }
145:
146: /*
147: * This device's "register space 1" is just a buffer where the
148: * Lance ring-buffers can be stored. Note the buffer's location
149: * and size, so the child driver can pick them up.
150: */
151: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[1].sbr_slot,
152: sa->sa_reg[1].sbr_offset, sa->sa_reg[1].sbr_size, 0, 0, &bh) != 0) {
153: printf("%s: attach: cannot map registers\n", self->dv_xname);
154: return;
155: }
156: sc->sc_buffer = (caddr_t)bus_space_vaddr(sc->sc_bustag, bh);
157: sc->sc_bufsiz = (bus_size_t)sa->sa_reg[1].sbr_size;
158:
159: /* Get number of on-board channels */
160: sc->sc_nchannels = getpropint(node, "#channels", -1);
161: if (sc->sc_nchannels == -1) {
162: printf(": no channels\n");
163: return;
164: }
165:
166: /*
167: * Get transfer burst size from PROM
168: */
169: sbusburst = ((struct sbus_softc *)parent)->sc_burst;
170: if (sbusburst == 0)
171: sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
172:
173: sc->sc_burst = getpropint(node, "burst-sizes", -1);
174: if (sc->sc_burst == -1)
175: /* take SBus burst sizes */
176: sc->sc_burst = sbusburst;
177:
178: /* Clamp at parent's burst sizes */
179: sc->sc_burst &= sbusburst;
180:
181: /*
182: * Collect address translations from the OBP.
183: */
184: error = getprop(node, "ranges", sizeof(struct sbus_range),
185: &sc->sc_nrange, (void **)&sc->sc_range);
186: switch (error) {
187: case 0:
188: break;
189: case ENOENT:
190: default:
191: panic("%s: error getting ranges property", self->dv_xname);
192: }
193:
194: /* Allocate a bus tag */
195: sbt = malloc(sizeof(*sbt), M_DEVBUF, M_NOWAIT);
196: if (sbt == NULL) {
197: printf("%s: attach: out of memory\n", self->dv_xname);
198: return;
199: }
200:
201: bzero(sbt, sizeof *sbt);
202: strlcpy(sbt->name, sc->sc_dev.dv_xname, sizeof(sbt->name));
203: sbt->cookie = sc;
204: sbt->parent = sc->sc_bustag;
205: sbt->asi = sbt->parent->asi;
206: sbt->sasi = sbt->parent->sasi;
207: sbt->sparc_bus_map = qec_bus_map;
208: sbt->sparc_intr_establish = qec_intr_establish;
209:
210: /*
211: * Save interrupt information for use in our qec_intr_establish()
212: * function below. Apparently, the intr level for the quad
213: * ethernet board (qe) is stored in the QEC node rather than
214: * separately in each of the QE nodes.
215: *
216: * XXX - qe.c should call bus_intr_establish() with `level = 0'..
217: * XXX - maybe we should have our own attach args for all that.
218: */
219: sc->sc_intr = sa->sa_intr;
220:
221: printf(": %dK memory\n", sc->sc_bufsiz / 1024);
222:
223: qec_init(sc);
224:
225: /* search through children */
226: for (node = firstchild(node); node; node = nextsibling(node)) {
227: struct sbus_attach_args sa;
228:
229: sbus_setup_attach_args((struct sbus_softc *)parent,
230: sbt, sc->sc_dmatag, node, &sa);
231: (void)config_found(&sc->sc_dev, (void *)&sa, qecprint);
232: sbus_destroy_attach_args(&sa);
233: }
234: }
235:
236: int
237: qec_bus_map(t, t0, addr, size, flags, hp)
238: bus_space_tag_t t;
239: bus_space_tag_t t0;
240: bus_addr_t addr;
241: bus_size_t size;
242: int flags;
243: bus_space_handle_t *hp;
244: {
245: struct qec_softc *sc = t->cookie;
246: int slot = BUS_ADDR_IOSPACE(addr);
247: bus_addr_t offset = BUS_ADDR_PADDR(addr);
248: int i;
249:
250: for (t = t->parent; t; t = t->parent) {
251: if (t->sparc_bus_map != NULL)
252: break;
253: }
254:
255: if (t == NULL) {
256: printf("\nqec_bus_map: invalid parent");
257: return (EINVAL);
258: }
259:
260: if (flags & BUS_SPACE_MAP_PROMADDRESS) {
261: return ((*t->sparc_bus_map)
262: (t, t0, offset, size, flags, hp));
263: }
264:
265: for (i = 0; i < sc->sc_nrange; i++) {
266: bus_addr_t paddr;
267: int iospace;
268:
269: if (sc->sc_range[i].cspace != slot)
270: continue;
271:
272: /* We've found the connection to the parent bus */
273: paddr = sc->sc_range[i].poffset + offset;
274: iospace = sc->sc_range[i].pspace;
275: return ((*t->sparc_bus_map)
276: (t, t0, BUS_ADDR(iospace, paddr), size, flags, hp));
277: }
278:
279: return (EINVAL);
280: }
281:
282: void *
283: qec_intr_establish(t, t0, pri, level, flags, handler, arg, what)
284: bus_space_tag_t t;
285: bus_space_tag_t t0;
286: int pri;
287: int level;
288: int flags;
289: int (*handler)(void *);
290: void *arg;
291: const char *what;
292: {
293: struct qec_softc *sc = t->cookie;
294:
295: if (pri == 0) {
296: /*
297: * qe.c calls bus_intr_establish() with `pri == 0'
298: * XXX - see also comment in qec_attach().
299: */
300: if (sc->sc_intr == NULL) {
301: printf("%s: warning: no interrupts\n",
302: sc->sc_dev.dv_xname);
303: return (NULL);
304: }
305: pri = sc->sc_intr->sbi_pri;
306: }
307:
308: for (t = t->parent; t; t = t->parent) {
309: if (t->sparc_intr_establish != NULL)
310: return ((*t->sparc_intr_establish)
311: (t, t0, pri, level, flags, handler, arg, what));
312: }
313:
314: panic("qec_intr_extablish): no handler found");
315:
316: return (NULL);
317: }
318:
319: void
320: qec_init(sc)
321: struct qec_softc *sc;
322: {
323: bus_space_tag_t t = sc->sc_bustag;
324: bus_space_handle_t qr = sc->sc_regs;
325: u_int32_t v, burst = 0, psize;
326: int i;
327:
328: /* First, reset the controller */
329: bus_space_write_4(t, qr, QEC_QRI_CTRL, QEC_CTRL_RESET);
330: for (i = 0; i < 1000; i++) {
331: DELAY(100);
332: v = bus_space_read_4(t, qr, QEC_QRI_CTRL);
333: if ((v & QEC_CTRL_RESET) == 0)
334: break;
335: }
336:
337: /*
338: * Cut available buffer size into receive and transmit buffers.
339: * XXX - should probably be done in be & qe driver...
340: */
341: v = sc->sc_msize = sc->sc_bufsiz / sc->sc_nchannels;
342: bus_space_write_4(t, qr, QEC_QRI_MSIZE, v);
343:
344: v = sc->sc_rsize = sc->sc_bufsiz / (sc->sc_nchannels * 2);
345: bus_space_write_4(t, qr, QEC_QRI_RSIZE, v);
346: bus_space_write_4(t, qr, QEC_QRI_TSIZE, v);
347:
348: psize = sc->sc_nchannels == 1 ? QEC_PSIZE_2048 : 0;
349: bus_space_write_4(t, qr, QEC_QRI_PSIZE, psize);
350:
351: if (sc->sc_burst & SBUS_BURST_64)
352: burst = QEC_CTRL_B64;
353: else if (sc->sc_burst & SBUS_BURST_32)
354: burst = QEC_CTRL_B32;
355: else
356: burst = QEC_CTRL_B16;
357:
358: v = bus_space_read_4(t, qr, QEC_QRI_CTRL);
359: v = (v & QEC_CTRL_MODEMASK) | burst;
360: bus_space_write_4(t, qr, QEC_QRI_CTRL, v);
361: }
362:
363: /*
364: * Common routine to initialize the QEC packet ring buffer.
365: * Called from be & qe drivers.
366: */
367: void
368: qec_meminit(qr, pktbufsz)
369: struct qec_ring *qr;
370: unsigned int pktbufsz;
371: {
372: bus_addr_t txbufdma, rxbufdma;
373: bus_addr_t dma;
374: caddr_t p;
375: unsigned int ntbuf, nrbuf, i;
376:
377: p = qr->rb_membase;
378: dma = qr->rb_dmabase;
379:
380: ntbuf = qr->rb_ntbuf;
381: nrbuf = qr->rb_nrbuf;
382:
383: /*
384: * Allocate transmit descriptors
385: */
386: qr->rb_txd = (struct qec_xd *)p;
387: qr->rb_txddma = dma;
388: p += QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd);
389: dma += QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd);
390:
391: /*
392: * Allocate receive descriptors
393: */
394: qr->rb_rxd = (struct qec_xd *)p;
395: qr->rb_rxddma = dma;
396: p += QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd);
397: dma += QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd);
398:
399:
400: /*
401: * Allocate transmit buffers
402: */
403: qr->rb_txbuf = p;
404: txbufdma = dma;
405: p += ntbuf * pktbufsz;
406: dma += ntbuf * pktbufsz;
407:
408: /*
409: * Allocate receive buffers
410: */
411: qr->rb_rxbuf = p;
412: rxbufdma = dma;
413: p += nrbuf * pktbufsz;
414: dma += nrbuf * pktbufsz;
415:
416: /*
417: * Initialize transmit buffer descriptors
418: */
419: for (i = 0; i < QEC_XD_RING_MAXSIZE; i++) {
420: qr->rb_txd[i].xd_addr = (u_int32_t)
421: (txbufdma + (i % ntbuf) * pktbufsz);
422: qr->rb_txd[i].xd_flags = 0;
423: }
424:
425: /*
426: * Initialize receive buffer descriptors
427: */
428: for (i = 0; i < QEC_XD_RING_MAXSIZE; i++) {
429: qr->rb_rxd[i].xd_addr = (u_int32_t)
430: (rxbufdma + (i % nrbuf) * pktbufsz);
431: qr->rb_rxd[i].xd_flags = (i < nrbuf)
432: ? QEC_XD_OWN | (pktbufsz & QEC_XD_LENGTH)
433: : 0;
434: }
435:
436: qr->rb_tdhead = qr->rb_tdtail = 0;
437: qr->rb_td_nbusy = 0;
438: qr->rb_rdtail = 0;
439: }
CVSweb