xref: /netbsd-src/sys/dev/isa/if_ai.c (revision 7c7c171d130af9949261bc7dce2150a03c3d239c)
1 /*	$NetBSD: if_ai.c,v 1.4 1998/04/15 01:45:43 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Rafal K. Boni.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/mbuf.h>
42 #include <sys/errno.h>
43 #include <sys/device.h>
44 #include <sys/protosw.h>
45 #include <sys/socket.h>
46 
47 #include <net/if.h>
48 #include <net/if_dl.h>
49 #include <net/if_types.h>
50 #include <net/if_media.h>
51 #include <net/if_ether.h>
52 
53 #include <vm/vm.h>
54 
55 #include <machine/cpu.h>
56 #include <machine/bus.h>
57 #include <machine/intr.h>
58 
59 #include <dev/isa/isareg.h>
60 #include <dev/isa/isavar.h>
61 
62 #include <dev/ic/i82586reg.h>
63 #include <dev/ic/i82586var.h>
64 #include <dev/isa/if_aireg.h>
65 
66 #ifdef AI_DEBUG
67 #define DPRINTF(x)	printf x
68 #else
69 #define DPRINTF(x)
70 #endif
71 
72 struct ai_softc {
73 	struct ie_softc sc_ie;
74 
75 	bus_space_tag_t sc_regt;	/* space tag for registers */
76 	bus_space_handle_t sc_regh;	/* space handle for registers */
77 
78 	u_int8_t	card_rev;
79 	u_int8_t	card_type;
80 
81 	void		*sc_ih;		/* interrupt handle */
82 };
83 
84 const char *ai_names[] = {
85         "StarLAN 10",
86         "EN100",
87         "StarLAN Fiber",
88 };
89 
90 /* Functions required by the i82586 MI driver */
91 static void 	ai_reset __P((struct ie_softc *, int));
92 static void 	ai_atten __P((struct ie_softc *));
93 
94 static void	ai_copyin __P((struct ie_softc *, void *, int, size_t));
95 static void	ai_copyout __P((struct ie_softc *, const void *, int, size_t));
96 
97 static u_int16_t ai_read_16 __P((struct ie_softc *, int));
98 static void	ai_write_16 __P((struct ie_softc *, int, u_int16_t));
99 static void	ai_write_24 __P((struct ie_softc *, int, int));
100 
101 /* Local support functions */
102 static int 	check_ie_present __P((struct ie_softc*, bus_space_tag_t,
103 					bus_space_handle_t, bus_size_t));
104 static int	ai_find_mem_size __P((struct ai_softc*, bus_space_tag_t,
105 					bus_size_t));
106 
107 #ifdef __BROKEN_INDIRECT_CONFIG
108 int ai_match __P((struct device *, void*, void *));
109 #else
110 int ai_match __P((struct device *, struct cfdata *, void *));
111 #endif
112 void ai_attach __P((struct device *, struct device *, void *));
113 
114 /*
115  * AT&T StarLan support routines
116  */
117 static void
118 ai_reset(sc, why)
119 	struct ie_softc *sc;
120 	int why;
121 {
122 	struct ai_softc* asc = (struct ai_softc *) sc;
123 
124 	switch (why) {
125 	case CHIP_PROBE:
126 		/* reset to chip to see if it responds */
127 		bus_space_write_1(asc->sc_regt, asc->sc_regh, AI_RESET, 0);
128 		DELAY(100);
129 		break;
130 
131 	case CARD_RESET:
132 		/*
133 		 * this takes around 10sec, and we can get
134 		 * by quite well w/out it...
135 		 */
136 		break;
137 	}
138 }
139 
140 static void
141 ai_atten(sc)
142 	struct ie_softc *sc;
143 {
144     struct ai_softc* asc = (struct ai_softc *) sc;
145     bus_space_write_1(asc->sc_regt, asc->sc_regh, AI_ATTN, 0);
146 }
147 
148 static void
149 ai_copyin (sc, dst, offset, size)
150         struct ie_softc *sc;
151         void *dst;
152         int offset;
153         size_t size;
154 {
155 	int dribble;
156 	u_int8_t* bptr = dst;
157 
158 	bus_space_barrier(sc->bt, sc->bh, offset, size,
159 			  BUS_SPACE_BARRIER_READ);
160 
161 	if (offset % 2) {
162 		*bptr = bus_space_read_1(sc->bt, sc->bh, offset);
163 		offset++; bptr++; size--;
164 	}
165 
166 	dribble = size % 2;
167 	bus_space_read_region_2(sc->bt, sc->bh, offset, (u_int16_t *) bptr,
168 				size >> 1);
169 
170 	if (dribble) {
171 		bptr += size - 1;
172 		offset += size - 1;
173 		*bptr = bus_space_read_1(sc->bt, sc->bh, offset);
174 	}
175 }
176 
177 static void
178 ai_copyout (sc, src, offset, size)
179         struct ie_softc *sc;
180         const void *src;
181         int offset;
182         size_t size;
183 {
184 	int dribble;
185 	int osize = size;
186 	int ooffset = offset;
187 	const u_int8_t* bptr = src;
188 
189 	if (offset % 2) {
190 		bus_space_write_1(sc->bt, sc->bh, offset, *bptr);
191 		offset++; bptr++; size--;
192 	}
193 
194 	dribble = size % 2;
195 	bus_space_write_region_2(sc->bt, sc->bh, offset, (u_int16_t *)bptr,
196 				 size >> 1);
197 	if (dribble) {
198 		bptr += size - 1;
199 		offset += size - 1;
200 		bus_space_write_1(sc->bt, sc->bh, offset, *bptr);
201 	}
202 
203 	bus_space_barrier(sc->bt, sc->bh, ooffset, osize,
204 			  BUS_SPACE_BARRIER_WRITE);
205 }
206 
207 static u_int16_t
208 ai_read_16 (sc, offset)
209         struct ie_softc *sc;
210         int offset;
211 {
212 	bus_space_barrier(sc->bt, sc->bh, offset, 2, BUS_SPACE_BARRIER_READ);
213         return bus_space_read_2(sc->bt, sc->bh, offset);
214 }
215 
216 static void
217 ai_write_16 (sc, offset, value)
218         struct ie_softc *sc;
219         int offset;
220         u_int16_t value;
221 {
222         bus_space_write_2(sc->bt, sc->bh, offset, value);
223 	bus_space_barrier(sc->bt, sc->bh, offset, 2, BUS_SPACE_BARRIER_WRITE);
224 }
225 
226 static void
227 ai_write_24 (sc, offset, addr)
228         struct ie_softc *sc;
229         int offset, addr;
230 {
231         bus_space_write_4(sc->bt, sc->bh, offset, addr +
232                                 (u_long) sc->sc_maddr - (u_long) sc->sc_iobase);
233 	bus_space_barrier(sc->bt, sc->bh, offset, 4, BUS_SPACE_BARRIER_WRITE);
234 }
235 
236 int
237 ai_match(parent, cf, aux)
238 	struct device *parent;
239 #ifdef __BROKEN_INDIRECT_CONFIG
240         void *cf;
241 #else
242 	struct cfdata *cf;
243 #endif
244 	void *aux;
245 {
246 	int rv = 0;
247 	u_int8_t val, type;
248 	bus_size_t memsize;
249 	bus_space_tag_t iot;
250 	bus_space_handle_t ioh;
251 	struct isa_attach_args * const ia = aux;
252 	struct ai_softc asc;
253 
254 
255 	/* Punt if wildcarded port, IRQ or memory address */
256 	if (ia->ia_irq == ISACF_IRQ_DEFAULT ||
257 	    ia->ia_maddr == ISACF_IOMEM_DEFAULT  ||
258             ia->ia_iobase == ISACF_PORT_DEFAULT) {
259 		DPRINTF((
260 		 "ai_match: wildcarded IRQ, IOAddr, or memAddr, skipping\n"));
261 		return (0);
262 	}
263 
264 	iot = ia->ia_iot;
265 
266 	/*
267 	 * This probe is horribly bad, but I have no info on this card other
268 	 * than the former driver, and it was just as bad!
269 	 */
270 	if (bus_space_map(iot, ia->ia_iobase,
271 			  AI_IOSIZE, 0, &ioh) != 0) {
272 
273 		DPRINTF(("ai_match: cannot map %d IO ports @ 0x%x\n",
274 			 AI_IOSIZE, ia->ia_iobase));
275 		return (0);
276 	}
277 
278 	val = bus_space_read_1(iot, ioh, AI_REVISION);
279 
280 	type = SL_BOARD(val);
281 	if (type != SL10_BOARD || type != EN100_BOARD ||
282 	    type != SLFIBER_BOARD) {
283 		DPRINTF(("ai_match: unknown board code 0x%02x @ 0x%x\n",
284 			 type, ia->ia_iobase));
285 		goto out;
286 	}
287 
288 	/*
289 	 * Fill in just about enough of our local `ai_softc' for
290 	 * ai_find_mem_size() to do its job.
291 	 */
292 	bzero(&asc, sizeof asc);
293 	asc.sc_regt = iot;
294 	asc.sc_regh = ioh;
295 
296 	if ((memsize = ai_find_mem_size(&asc,ia->ia_memt,ia->ia_maddr)) == 0) {
297 		DPRINTF(("ai_match: cannot size memory of board @ 0x%x\n",
298 			 ia->ia_iobase));
299 		goto out;
300 	}
301 
302 	if (!ia->ia_msize)
303 		ia->ia_msize = memsize;
304 	else if (ia->ia_msize != memsize) {
305 		DPRINTF((
306 		   "ai_match: memsize of board @ 0x%x doesn't match config\n",
307 		   ia->ia_iobase));
308 		goto out;
309 	}
310 
311 	rv = 1;
312 	ia->ia_msize = memsize;
313 	ia->ia_iosize = AI_IOSIZE;
314 	DPRINTF(("ai_match: found board @ 0x%x\n", ia->ia_iobase));
315 
316 out:
317 	bus_space_unmap(iot, ioh, AI_IOSIZE);
318 	return rv;
319 }
320 
321 void
322 ai_attach(parent, self, aux)
323 	struct device *parent;
324 	struct device *self;
325 	void   *aux;
326 {
327 	struct ai_softc *asc = (void *)self;
328 	struct ie_softc *sc = &asc->sc_ie;
329 	struct isa_attach_args *ia = aux;
330 
331 	u_int8_t val = 0;
332 	bus_space_handle_t ioh, memh;
333 	u_int8_t ethaddr[ETHER_ADDR_LEN];
334 
335 	if (bus_space_map(ia->ia_iot, ia->ia_iobase,
336 			  ia->ia_iosize, 0, &ioh) != 0) {
337 		DPRINTF(("\n%s: can't map i/o space 0x%x-0x%x\n",
338 			 sc->sc_dev.dv_xname,
339 		         ia->ia_iobase, ia->ia_iobase + ia->ia_iosize - 1));
340 		return;
341 	}
342 
343 	if (bus_space_map(ia->ia_memt, ia->ia_maddr,
344 			  ia->ia_msize, 0, &memh) != 0) {
345 		DPRINTF(("\n%s: can't map iomem space 0x%x-0x%x\n",
346 			 sc->sc_dev.dv_xname,
347 			 ia->ia_maddr, ia->ia_maddr + ia->ia_msize - 1));
348 		bus_space_unmap(ia->ia_iot, ioh, ia->ia_iosize);
349 		return;
350 	}
351 
352 	asc->sc_regt = ia->ia_iot;
353 	asc->sc_regh = ioh;
354 
355 	sc->hwinit = NULL;
356 	sc->intrhook = NULL;
357 	sc->hwreset = ai_reset;
358 	sc->chan_attn = ai_atten;
359 
360 	sc->memcopyin = ai_copyin;
361 	sc->memcopyout = ai_copyout;
362 	sc->ie_bus_read16 = ai_read_16;
363 	sc->ie_bus_write16 = ai_write_16;
364 	sc->ie_bus_write24 = ai_write_24;
365 
366 	sc->do_xmitnopchain = 0;
367 
368 	sc->sc_mediachange = NULL;
369 	sc->sc_mediastatus = NULL;
370 
371 	sc->bt = ia->ia_memt;
372 	sc->bh = memh;
373 
374 	/* Map i/o space. */
375 	sc->sc_msize = ia->ia_msize;
376 	sc->sc_maddr = (void *) memh;
377 	sc->sc_iobase = sc->sc_maddr + sc->sc_msize - (1 << 24);
378 
379 	/* set up pointers to important on-card control structures */
380 	sc->iscp = 0;
381 	sc->scb = IE_ISCP_SZ;
382 	sc->scp = sc->sc_msize + IE_SCP_ADDR - (1 << 24);
383 
384 	sc->buf_area = sc->scb + IE_SCB_SZ;
385 	sc->buf_area_sz = sc->sc_msize - IE_ISCP_SZ - IE_SCB_SZ - IE_SCP_SZ;
386 
387 	/* zero card memory */
388 	bus_space_set_region_1(sc->bt, sc->bh, 0, 0, sc->sc_msize);
389 
390 	/* set card to 16-bit bus mode */
391 	bus_space_write_1(sc->bt, sc->bh, IE_SCP_BUS_USE((u_long)sc->scp), 0);
392 
393 	/* set up pointers to key structures */
394 	ai_write_24(sc, IE_SCP_ISCP((u_long)sc->scp), (u_long) sc->iscp);
395 	ai_write_16(sc, IE_ISCP_SCB((u_long)sc->iscp), (u_long) sc->scb);
396 	ai_write_24(sc, IE_ISCP_BASE((u_long)sc->iscp), (u_long) sc->iscp);
397 
398 	/* flush setup of pointers, check if chip answers */
399 	bus_space_barrier(sc->bt, sc->bh, 0, sc->sc_msize,
400 			  BUS_SPACE_BARRIER_WRITE);
401 	if (!i82586_proberam(sc)) {
402 		DPRINTF(("\n%s: can't talk to i82586!\n",
403 			sc->sc_dev.dv_xname));
404 		bus_space_unmap(ia->ia_iot, ioh, ia->ia_iosize);
405 		bus_space_unmap(ia->ia_memt, memh, ia->ia_msize);
406 		return;
407 	}
408 
409 	val = bus_space_read_1(asc->sc_regt, asc->sc_regh, AI_REVISION);
410 	asc->card_rev = SL_REV(val);
411 	asc->card_type = SL_BOARD(val) - 1;
412 	sprintf(version, "%s, rev. %d",
413 		ai_names[asc->card_type], asc->card_rev);
414 
415 	i82586_attach(sc, version, ethaddr, NULL, 0, 0);
416 
417 	asc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
418 					IPL_NET, i82586_intr, sc);
419 	if (asc->sc_ih == NULL) {
420 		DPRINTF(("\n%s: can't establish interrupt\n",
421 			sc->sc_dev.dv_xname));
422 	}
423 }
424 
425 /*
426  * Divine the memory size of this board.
427  * Better hope there's nothing important hiding just below the card...
428  */
429 static int
430 ai_find_mem_size(asc, memt, maddr)
431 	struct ai_softc* asc;
432 	bus_space_tag_t memt;
433 	bus_size_t maddr;
434 {
435 	int size;
436 	bus_space_handle_t memh;
437 	struct ie_softc* sc = &asc->sc_ie;
438 
439 	for (size = 65536; size >= 16384; size -= 16384) {
440 		if (bus_space_map(memt, maddr, size, 0, &memh) == 0) {
441 			size = check_ie_present(sc, memt, maddr, size);
442 			bus_space_unmap(memt, memh, size);
443 
444 			if (size != 0)
445 				return size;
446 		}
447 	}
448 
449 	return (0);
450 }
451 
452 /*
453  * Check to see if there's an 82586 out there.
454  */
455 static int
456 check_ie_present(sc, memt, memh, size)
457 	struct ie_softc* sc;
458 	bus_space_tag_t memt;
459 	bus_space_handle_t memh;
460 	bus_size_t size;
461 {
462 	sc->hwreset = ai_reset;
463 	sc->chan_attn = ai_atten;
464 	sc->ie_bus_read16 = ai_read_16;
465 	sc->ie_bus_write16 = ai_write_16;
466 
467 	sc->bt = memt;
468 	sc->bh = memh;
469 	sc->sc_iobase = (void *) memh + size - (1 << 24);
470 
471 	sc->scp = size + IE_SCP_ADDR - (1 << 24);
472 	bus_space_set_region_1(memt, memh, (u_long) sc->scp, 0, IE_SCP_SZ);
473 
474 	sc->iscp = 0;
475 	bus_space_set_region_1(memt, memh, (u_long) sc->iscp, 0, IE_ISCP_SZ);
476 
477 	sc->scb = IE_ISCP_SZ;
478 	bus_space_set_region_1(memt, memh, sc->scb, 0, IE_SCB_SZ);
479 
480 	/* set card to 16-bit bus mode */
481 	bus_space_write_1(sc->bt, sc->bh, IE_SCP_BUS_USE((u_long)sc->scp), 0);
482 
483 	/* set up pointers to key structures */
484 	ai_write_24(sc, IE_SCP_ISCP((u_long)sc->scp), (u_long) sc->iscp);
485 	ai_write_16(sc, IE_ISCP_SCB((u_long)sc->iscp), (u_long) sc->scb);
486 	ai_write_24(sc, IE_ISCP_BASE((u_long)sc->iscp), (u_long) sc->iscp);
487 
488 	/* flush setup of pointers, check if chip answers */
489 	bus_space_barrier(sc->bt, sc->bh, 0, sc->sc_msize,
490 			  BUS_SPACE_BARRIER_WRITE);
491 
492 	if (!i82586_proberam(sc))
493 		return (0);
494 
495 	return (size);
496 }
497 
498 struct cfattach ai_ca = {
499 	sizeof(struct ai_softc), ai_match, ai_attach
500 };
501