1 /*	$OpenBSD: qec.c,v 1.16 2003/06/02 15:54:22 deraadt 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
qecprint(aux,name)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
qecmatch(parent,vcf,aux)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
qecattach(parent,self,aux)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 	if (ca->ca_bustype == BUS_SBUS)
181 		sbus_establish(&sc->sc_sd, &sc->sc_dev);
182 
183 	/* Propagate bootpath */
184 	if (ca->ca_ra.ra_bp != NULL)
185 		oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1;
186 	else
187 		oca.ca_ra.ra_bp = NULL;
188 
189 	printf("\n");
190 
191 	qec_reset(sc);
192 
193 	/* search through children */
194 	for (node = firstchild(node); node; node = nextsibling(node)) {
195 		name = getpropstring(node, "name");
196 		if (!romprop(&oca.ca_ra, name, node))
197 			continue;
198 
199 		qec_translate(sc, &oca);
200 		oca.ca_bustype = BUS_SBUS;
201 		(void) config_found(&sc->sc_dev, (void *)&oca, qecprint);
202 	}
203 }
204 
205 void
qec_fix_range(sc,sbp)206 qec_fix_range(sc, sbp)
207 	struct qec_softc *sc;
208 	struct sbus_softc *sbp;
209 {
210 	int rlen, i, j;
211 
212 	rlen = getproplen(sc->sc_node, "ranges");
213 	sc->sc_range =
214 		(struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT);
215 	if (sc->sc_range == NULL) {
216 		printf("%s: PROM ranges too large: %d\n",
217 				sc->sc_dev.dv_xname, rlen);
218 		return;
219 	}
220 	sc->sc_nrange = rlen / sizeof(struct rom_range);
221 	(void)getprop(sc->sc_node, "ranges", sc->sc_range, rlen);
222 
223 	for (i = 0; i < sc->sc_nrange; i++) {
224 		for (j = 0; j < sbp->sc_nrange; j++) {
225 			if (sc->sc_range[i].pspace == sbp->sc_range[j].cspace) {
226 				sc->sc_range[i].poffset +=
227 				    sbp->sc_range[j].poffset;
228 				sc->sc_range[i].pspace =
229 				    sbp->sc_range[j].pspace;
230 				break;
231 			}
232 		}
233 	}
234 }
235 
236 /*
237  * Translate the register addresses of our children
238  */
239 void
qec_translate(sc,ca)240 qec_translate(sc, ca)
241 	struct qec_softc *sc;
242 	struct confargs *ca;
243 {
244 	register int i;
245 
246 	ca->ca_slot = ca->ca_ra.ra_iospace;
247 	ca->ca_offset = sc->sc_range[ca->ca_slot].poffset - (long)sc->sc_paddr;
248 
249 	/* Translate into parent address spaces */
250 	for (i = 0; i < ca->ca_ra.ra_nreg; i++) {
251 		int j, cspace = ca->ca_ra.ra_reg[i].rr_iospace;
252 
253 		for (j = 0; j < sc->sc_nrange; j++) {
254 			if (sc->sc_range[j].cspace == cspace) {
255 				int tmp = (int)ca->ca_ra.ra_reg[i].rr_paddr;
256 				tmp += sc->sc_range[j].poffset;
257 				ca->ca_ra.ra_reg[i].rr_paddr = (void *)tmp;
258 				ca->ca_ra.ra_reg[i].rr_iospace =
259 				    (int)sc->sc_range[j].pspace;
260 				break;
261 			}
262 		}
263 	}
264 }
265 
266 /*
267  * Reset the QEC and initialize its global registers.
268  */
269 void
qec_reset(sc)270 qec_reset(sc)
271 	struct qec_softc *sc;
272 {
273 	struct qecregs *qr = sc->sc_regs;
274 	int i = 200;
275 
276 	qr->ctrl = QEC_CTRL_RESET;
277 	while (--i) {
278 		if ((qr->ctrl & QEC_CTRL_RESET) == 0)
279 			break;
280 		DELAY(20);
281 	}
282 	if (i == 0) {
283 		printf("%s: reset failed.\n", sc->sc_dev.dv_xname);
284 		return;
285 	}
286 
287 	qr->msize = sc->sc_bufsiz / sc->sc_nchannels;
288 	sc->sc_msize = qr->msize;
289 
290 	qr->rsize = sc->sc_bufsiz / (sc->sc_nchannels * 2);
291 	sc->sc_rsize = qr->rsize;
292 
293 	qr->tsize = sc->sc_bufsiz / (sc->sc_nchannels * 2);
294 
295 	qr->psize = QEC_PSIZE_2048;
296 
297         if (sc->sc_burst & SBUS_BURST_64)
298 		i = QEC_CTRL_B64;
299 	else if (sc->sc_burst & SBUS_BURST_32)
300 		i = QEC_CTRL_B32;
301 	else
302 		i = QEC_CTRL_B16;
303 
304 	qr->ctrl = (qr->ctrl & QEC_CTRL_MODEMASK) | i;
305 }
306 
307 /*
308  * Routine to copy from mbuf chain to transmit buffer in
309  * network buffer memory.
310  */
311 int
qec_put(buf,m0)312 qec_put(buf, m0)
313 	u_int8_t *buf;
314 	struct mbuf *m0;
315 {
316 	struct mbuf *m;
317 	int len, tlen = 0;
318 
319 	for (m = m0; m != NULL; m = m->m_next) {
320 		len = m->m_len;
321 		bcopy(mtod(m, caddr_t), buf, len);
322 		buf += len;
323 		tlen += len;
324 	}
325 	m_freem(m0);
326 	return (tlen);
327 }
328 
329 /*
330  * Pull data off an interface.
331  * Len is the length of data, with local net header stripped.
332  * We copy the data into mbufs.  When full cluster sized units are present,
333  * we copy into clusters.
334  */
335 struct mbuf *
qec_get(ifp,buf,totlen)336 qec_get(ifp, buf, totlen)
337 	struct ifnet *ifp;
338 	u_int8_t *buf;
339 	int totlen;
340 {
341 	struct mbuf *m, *top, **mp;
342 	int len, pad;
343 
344 	MGETHDR(m, M_DONTWAIT, MT_DATA);
345 	if (m == NULL)
346 		return (NULL);
347 	m->m_pkthdr.rcvif = ifp;
348 	m->m_pkthdr.len = totlen;
349 	pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
350 	len = MHLEN;
351 	if (totlen >= MINCLSIZE) {
352 		MCLGET(m, M_DONTWAIT);
353 		if (m->m_flags & M_EXT)
354 			len = MCLBYTES;
355 	}
356 	m->m_data += pad;
357 	len -= pad;
358 	top = NULL;
359 	mp = &top;
360 
361 	while (totlen > 0) {
362 		if (top) {
363 			MGET(m, M_DONTWAIT, MT_DATA);
364 			if (m == NULL) {
365 				m_freem(top);
366 				return NULL;
367 			}
368 			len = MLEN;
369 		}
370 		if (top && totlen >= MINCLSIZE) {
371 			MCLGET(m, M_DONTWAIT);
372 			if (m->m_flags & M_EXT)
373 				len = MCLBYTES;
374 		}
375 		m->m_len = len = min(totlen, len);
376 		bcopy(buf, mtod(m, caddr_t), len);
377 		buf += len;
378 		totlen -= len;
379 		*mp = m;
380 		mp = &m->m_next;
381 	}
382 
383 	return (top);
384 }
385