Annotation of sys/arch/sparc/dev/qec.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: qec.c,v 1.17 2006/06/02 20:00:54 miod Exp $ */
2:
3: /*
4: * Copyright (c) 1998 Theo de Raadt and Jason L. Wright.
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: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19: * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26: */
27:
28: #include <sys/types.h>
29: #include <sys/param.h>
30: #include <sys/systm.h>
31: #include <sys/kernel.h>
32: #include <sys/errno.h>
33: #include <sys/ioctl.h>
34: #include <sys/device.h>
35: #include <sys/malloc.h>
36: #include <sys/buf.h>
37: #include <sys/proc.h>
38: #include <sys/user.h>
39: #include <sys/mbuf.h>
40: #include <sys/socket.h>
41:
42: #include <net/if.h>
43: #include <net/if_dl.h>
44: #include <net/if_types.h>
45: #include <net/netisr.h>
46: #include <net/if_media.h>
47:
48: #ifdef INET
49: #include <netinet/in.h>
50: #include <netinet/in_systm.h>
51: #include <netinet/in_var.h>
52: #include <netinet/ip.h>
53: #include <netinet/if_ether.h>
54: #endif
55:
56: #include <sparc/autoconf.h>
57: #include <sparc/cpu.h>
58:
59: #include <sparc/dev/sbusvar.h>
60: #include <sparc/dev/dmareg.h>
61: #include <sparc/dev/qecreg.h>
62: #include <sparc/dev/qecvar.h>
63:
64: int qecprint(void *, const char *);
65: int qecmatch(struct device *, void *, void *);
66: void qecattach(struct device *, struct device *, void *);
67: void qec_fix_range(struct qec_softc *, struct sbus_softc *);
68: void qec_translate(struct qec_softc *, struct confargs *);
69:
70: struct cfattach qec_ca = {
71: sizeof(struct qec_softc), qecmatch, qecattach
72: };
73:
74: struct cfdriver qec_cd = {
75: NULL, "qec", DV_DULL
76: };
77:
78: int
79: qecprint(aux, name)
80: void *aux;
81: const char *name;
82: {
83: register struct confargs *ca = aux;
84:
85: if (name)
86: printf("%s at %s", ca->ca_ra.ra_name, name);
87: printf(" offset 0x%x", ca->ca_offset);
88: return (UNCONF);
89: }
90:
91: /*
92: * match a QEC device in a slot capable of DMA
93: */
94: int
95: qecmatch(parent, vcf, aux)
96: struct device *parent;
97: void *vcf, *aux;
98: {
99: struct cfdata *cf = vcf;
100: struct confargs *ca = aux;
101: struct romaux *ra = &ca->ca_ra;
102:
103: if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
104: return (0);
105:
106: if (!sbus_testdma((struct sbus_softc *)parent, ca))
107: return (0);
108:
109: return (1);
110: }
111:
112: /*
113: * Attach all the sub-devices we can find
114: */
115: void
116: qecattach(parent, self, aux)
117: struct device *parent, *self;
118: void *aux;
119: {
120: register struct confargs *ca = aux;
121: struct qec_softc *sc = (void *)self;
122: int node;
123: struct confargs oca;
124: char *name;
125: int sbusburst;
126:
127: /*
128: * The first i/o space is the qec global registers, and
129: * the second is a buffer used by the qec channels internally.
130: * (It's not necessary to map the second i/o space, but knowing
131: * its size is necessary).
132: */
133: sc->sc_regs = mapiodev(&ca->ca_ra.ra_reg[0], 0,
134: sizeof(struct qecregs));
135: sc->sc_bufsiz = ca->ca_ra.ra_reg[1].rr_len;
136: sc->sc_paddr = ca->ca_ra.ra_reg[0].rr_paddr;
137:
138: /*
139: * On qec+qe, the qec has the interrupt priority, but we
140: * need to pass that down so that the qe's can handle them.
141: */
142: if (ca->ca_ra.ra_nintr == 1)
143: sc->sc_pri = ca->ca_ra.ra_intr[0].int_pri;
144:
145: node = sc->sc_node = ca->ca_ra.ra_node;
146:
147: qec_fix_range(sc, (struct sbus_softc *)parent);
148:
149: /*
150: * Get transfer burst size from PROM
151: */
152: sbusburst = ((struct sbus_softc *)parent)->sc_burst;
153: if (sbusburst == 0)
154: sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
155:
156: sc->sc_nchannels = getpropint(ca->ca_ra.ra_node, "#channels", -1);
157: if (sc->sc_nchannels == -1) {
158: printf(": no channels\n");
159: return;
160: }
161: else if (sc->sc_nchannels < 1 || sc->sc_nchannels > 4) {
162: printf(": invalid number of channels: %d\n", sc->sc_nchannels);
163: return;
164: }
165:
166: sc->sc_burst = getpropint(ca->ca_ra.ra_node, "burst-sizes", -1);
167: if (sc->sc_burst == -1)
168: /* take SBus burst sizes */
169: sc->sc_burst = sbusburst;
170:
171: /* Clamp at parent's burst sizes */
172: sc->sc_burst &= sbusburst;
173:
174: printf(": %dK memory %d channel%s",
175: sc->sc_bufsiz / 1024, sc->sc_nchannels,
176: (sc->sc_nchannels == 1) ? "" : "s");
177:
178: node = sc->sc_node = ca->ca_ra.ra_node;
179:
180: /* Propagate bootpath */
181: if (ca->ca_ra.ra_bp != NULL)
182: oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1;
183: else
184: oca.ca_ra.ra_bp = NULL;
185:
186: printf("\n");
187:
188: qec_reset(sc);
189:
190: /* search through children */
191: for (node = firstchild(node); node; node = nextsibling(node)) {
192: name = getpropstring(node, "name");
193: if (!romprop(&oca.ca_ra, name, node))
194: continue;
195:
196: qec_translate(sc, &oca);
197: oca.ca_bustype = BUS_SBUS;
198: (void) config_found(&sc->sc_dev, (void *)&oca, qecprint);
199: }
200: }
201:
202: void
203: qec_fix_range(sc, sbp)
204: struct qec_softc *sc;
205: struct sbus_softc *sbp;
206: {
207: int rlen, i, j;
208:
209: rlen = getproplen(sc->sc_node, "ranges");
210: sc->sc_range =
211: (struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT);
212: if (sc->sc_range == NULL) {
213: printf("%s: PROM ranges too large: %d\n",
214: sc->sc_dev.dv_xname, rlen);
215: return;
216: }
217: sc->sc_nrange = rlen / sizeof(struct rom_range);
218: (void)getprop(sc->sc_node, "ranges", sc->sc_range, rlen);
219:
220: for (i = 0; i < sc->sc_nrange; i++) {
221: for (j = 0; j < sbp->sc_nrange; j++) {
222: if (sc->sc_range[i].pspace == sbp->sc_range[j].cspace) {
223: sc->sc_range[i].poffset +=
224: sbp->sc_range[j].poffset;
225: sc->sc_range[i].pspace =
226: sbp->sc_range[j].pspace;
227: break;
228: }
229: }
230: }
231: }
232:
233: /*
234: * Translate the register addresses of our children
235: */
236: void
237: qec_translate(sc, ca)
238: struct qec_softc *sc;
239: struct confargs *ca;
240: {
241: register int i;
242:
243: ca->ca_slot = ca->ca_ra.ra_iospace;
244: ca->ca_offset = sc->sc_range[ca->ca_slot].poffset - (long)sc->sc_paddr;
245:
246: /* Translate into parent address spaces */
247: for (i = 0; i < ca->ca_ra.ra_nreg; i++) {
248: int j, cspace = ca->ca_ra.ra_reg[i].rr_iospace;
249:
250: for (j = 0; j < sc->sc_nrange; j++) {
251: if (sc->sc_range[j].cspace == cspace) {
252: (int)ca->ca_ra.ra_reg[i].rr_paddr +=
253: sc->sc_range[j].poffset;
254: (int)ca->ca_ra.ra_reg[i].rr_iospace =
255: sc->sc_range[j].pspace;
256: break;
257: }
258: }
259: }
260: }
261:
262: /*
263: * Reset the QEC and initialize its global registers.
264: */
265: void
266: qec_reset(sc)
267: struct qec_softc *sc;
268: {
269: struct qecregs *qr = sc->sc_regs;
270: int i = 200;
271:
272: qr->ctrl = QEC_CTRL_RESET;
273: while (--i) {
274: if ((qr->ctrl & QEC_CTRL_RESET) == 0)
275: break;
276: DELAY(20);
277: }
278: if (i == 0) {
279: printf("%s: reset failed.\n", sc->sc_dev.dv_xname);
280: return;
281: }
282:
283: qr->msize = sc->sc_bufsiz / sc->sc_nchannels;
284: sc->sc_msize = qr->msize;
285:
286: qr->rsize = sc->sc_bufsiz / (sc->sc_nchannels * 2);
287: sc->sc_rsize = qr->rsize;
288:
289: qr->tsize = sc->sc_bufsiz / (sc->sc_nchannels * 2);
290:
291: qr->psize = QEC_PSIZE_2048;
292:
293: if (sc->sc_burst & SBUS_BURST_64)
294: i = QEC_CTRL_B64;
295: else if (sc->sc_burst & SBUS_BURST_32)
296: i = QEC_CTRL_B32;
297: else
298: i = QEC_CTRL_B16;
299:
300: qr->ctrl = (qr->ctrl & QEC_CTRL_MODEMASK) | i;
301: }
302:
303: /*
304: * Routine to copy from mbuf chain to transmit buffer in
305: * network buffer memory.
306: */
307: int
308: qec_put(buf, m0)
309: u_int8_t *buf;
310: struct mbuf *m0;
311: {
312: struct mbuf *m;
313: int len, tlen = 0;
314:
315: for (m = m0; m != NULL; m = m->m_next) {
316: len = m->m_len;
317: bcopy(mtod(m, caddr_t), buf, len);
318: buf += len;
319: tlen += len;
320: }
321: m_freem(m0);
322: return (tlen);
323: }
324:
325: /*
326: * Pull data off an interface.
327: * Len is the length of data, with local net header stripped.
328: * We copy the data into mbufs. When full cluster sized units are present,
329: * we copy into clusters.
330: */
331: struct mbuf *
332: qec_get(ifp, buf, totlen)
333: struct ifnet *ifp;
334: u_int8_t *buf;
335: int totlen;
336: {
337: struct mbuf *m, *top, **mp;
338: int len, pad;
339:
340: MGETHDR(m, M_DONTWAIT, MT_DATA);
341: if (m == NULL)
342: return (NULL);
343: m->m_pkthdr.rcvif = ifp;
344: m->m_pkthdr.len = totlen;
345: pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
346: len = MHLEN;
347: if (totlen >= MINCLSIZE) {
348: MCLGET(m, M_DONTWAIT);
349: if (m->m_flags & M_EXT)
350: len = MCLBYTES;
351: }
352: m->m_data += pad;
353: len -= pad;
354: top = NULL;
355: mp = ⊤
356:
357: while (totlen > 0) {
358: if (top) {
359: MGET(m, M_DONTWAIT, MT_DATA);
360: if (m == NULL) {
361: m_freem(top);
362: return NULL;
363: }
364: len = MLEN;
365: }
366: if (top && totlen >= MINCLSIZE) {
367: MCLGET(m, M_DONTWAIT);
368: if (m->m_flags & M_EXT)
369: len = MCLBYTES;
370: }
371: m->m_len = len = min(totlen, len);
372: bcopy(buf, mtod(m, caddr_t), len);
373: buf += len;
374: totlen -= len;
375: *mp = m;
376: mp = &m->m_next;
377: }
378:
379: return (top);
380: }
CVSweb