1 /* $NetBSD: if_ai.c,v 1.31 2009/05/12 08:44:19 cegger Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: if_ai.c,v 1.31 2009/05/12 08:44:19 cegger Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
38 #include <sys/errno.h>
39 #include <sys/device.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
44 #include <net/if_dl.h>
45 #include <net/if_types.h>
46 #include <net/if_media.h>
47 #include <net/if_ether.h>
53 #include <dev/isa/isareg.h>
54 #include <dev/isa/isavar.h>
56 #include <dev/ic/i82586reg.h>
57 #include <dev/ic/i82586var.h>
58 #include <dev/isa/if_aireg.h>
61 #define DPRINTF(x) printf x
67 struct ie_softc sc_ie
;
69 bus_space_tag_t sc_regt
; /* space tag for registers */
70 bus_space_handle_t sc_regh
; /* space handle for registers */
75 void *sc_ih
; /* interrupt handle */
78 const char *ai_names
[] = {
84 /* Functions required by the i82586 MI driver */
85 static void ai_reset(struct ie_softc
*, int);
86 static void ai_atten(struct ie_softc
*, int);
88 static void ai_copyin(struct ie_softc
*, void *, int, size_t);
89 static void ai_copyout(struct ie_softc
*, const void *, int, size_t);
91 static u_int16_t
ai_read_16(struct ie_softc
*, int);
92 static void ai_write_16(struct ie_softc
*, int, u_int16_t
);
93 static void ai_write_24(struct ie_softc
*, int, int);
95 /* Local support functions */
96 static int check_ie_present(struct ie_softc
*, bus_space_tag_t
,
97 bus_space_handle_t
, bus_size_t
);
98 static int ai_find_mem_size(struct ai_softc
*, bus_space_tag_t
,
101 int ai_match(device_t
, cfdata_t
, void *);
102 void ai_attach(device_t
, device_t
, void *);
105 * AT&T StarLan support routines
108 ai_reset(struct ie_softc
*sc
, int why
)
110 struct ai_softc
* asc
= (struct ai_softc
*) sc
;
114 /* reset to chip to see if it responds */
115 bus_space_write_1(asc
->sc_regt
, asc
->sc_regh
, AI_RESET
, 0);
121 * this takes around 10sec, and we can get
122 * by quite well w/out it...
129 ai_atten(struct ie_softc
*sc
, int why
)
131 struct ai_softc
* asc
= (struct ai_softc
*) sc
;
132 bus_space_write_1(asc
->sc_regt
, asc
->sc_regh
, AI_ATTN
, 0);
136 ai_copyin (struct ie_softc
*sc
, void *dst
, int offset
, size_t size
)
139 u_int8_t
* bptr
= dst
;
141 bus_space_barrier(sc
->bt
, sc
->bh
, offset
, size
,
142 BUS_SPACE_BARRIER_READ
);
145 *bptr
= bus_space_read_1(sc
->bt
, sc
->bh
, offset
);
146 offset
++; bptr
++; size
--;
150 bus_space_read_region_2(sc
->bt
, sc
->bh
, offset
, (u_int16_t
*) bptr
,
156 *bptr
= bus_space_read_1(sc
->bt
, sc
->bh
, offset
);
161 ai_copyout (struct ie_softc
*sc
, const void *src
, int offset
, size_t size
)
165 int ooffset
= offset
;
166 const u_int8_t
* bptr
= src
;
169 bus_space_write_1(sc
->bt
, sc
->bh
, offset
, *bptr
);
170 offset
++; bptr
++; size
--;
174 bus_space_write_region_2(sc
->bt
, sc
->bh
, offset
,
175 (const u_int16_t
*)bptr
, size
>> 1);
179 bus_space_write_1(sc
->bt
, sc
->bh
, offset
, *bptr
);
182 bus_space_barrier(sc
->bt
, sc
->bh
, ooffset
, osize
,
183 BUS_SPACE_BARRIER_WRITE
);
187 ai_read_16 (struct ie_softc
*sc
, int offset
)
189 bus_space_barrier(sc
->bt
, sc
->bh
, offset
, 2, BUS_SPACE_BARRIER_READ
);
190 return bus_space_read_2(sc
->bt
, sc
->bh
, offset
);
194 ai_write_16 (struct ie_softc
*sc
, int offset
, u_int16_t value
)
196 bus_space_write_2(sc
->bt
, sc
->bh
, offset
, value
);
197 bus_space_barrier(sc
->bt
, sc
->bh
, offset
, 2, BUS_SPACE_BARRIER_WRITE
);
201 ai_write_24 (struct ie_softc
*sc
, int offset
, int addr
)
203 bus_space_write_4(sc
->bt
, sc
->bh
, offset
, addr
+
204 (u_long
) sc
->sc_maddr
- (u_long
) sc
->sc_iobase
);
205 bus_space_barrier(sc
->bt
, sc
->bh
, offset
, 4, BUS_SPACE_BARRIER_WRITE
);
209 ai_match(device_t parent
, cfdata_t cf
, void *aux
)
215 bus_space_handle_t ioh
;
216 struct isa_attach_args
* const ia
= aux
;
221 if (ia
->ia_niomem
< 1)
226 if (ISA_DIRECT_CONFIG(ia
))
229 /* Punt if wildcarded port, IRQ or memory address */
230 if (ia
->ia_io
[0].ir_addr
== ISA_UNKNOWN_PORT
||
231 ia
->ia_iomem
[0].ir_addr
== ISA_UNKNOWN_IOMEM
||
232 ia
->ia_irq
[0].ir_irq
== ISA_UNKNOWN_IRQ
) {
234 "ai_match: wildcarded IRQ, IOAddr, or memAddr, skipping\n"));
241 * This probe is horribly bad, but I have no info on this card other
242 * than the former driver, and it was just as bad!
244 if (bus_space_map(iot
, ia
->ia_io
[0].ir_addr
,
245 AI_IOSIZE
, 0, &ioh
) != 0) {
247 DPRINTF(("ai_match: cannot map %d IO ports @ 0x%x\n",
248 AI_IOSIZE
, ia
->ia_iobase
));
252 val
= bus_space_read_1(iot
, ioh
, AI_REVISION
);
254 type
= SL_BOARD(val
);
255 if (type
!= SL10_BOARD
&& type
!= EN100_BOARD
&&
256 type
!= SLFIBER_BOARD
) {
257 DPRINTF(("ai_match: unknown board code 0x%02x @ 0x%x\n",
258 type
, ia
->ia_iobase
));
263 * Fill in just about enough of our local `ai_softc' for
264 * ai_find_mem_size() to do its job.
266 memset(&asc
, 0, sizeof asc
);
270 if ((memsize
= ai_find_mem_size(&asc
, ia
->ia_memt
,
271 ia
->ia_iomem
[0].ir_addr
)) == 0) {
272 DPRINTF(("ai_match: cannot size memory of board @ 0x%x\n",
273 ia
->ia_io
[0].ir_addr
));
277 if (ia
->ia_iomem
[0].ir_size
!= 0 &&
278 ia
->ia_iomem
[0].ir_size
!= memsize
) {
280 "ai_match: memsize of board @ 0x%x doesn't match config\n",
288 ia
->ia_io
[0].ir_size
= AI_IOSIZE
;
291 ia
->ia_iomem
[0].ir_size
= memsize
;
297 DPRINTF(("ai_match: found board @ 0x%x\n", ia
->ia_iobase
));
300 bus_space_unmap(iot
, ioh
, AI_IOSIZE
);
305 ai_attach(device_t parent
, device_t self
, void *aux
)
307 struct ai_softc
*asc
= (void *)self
;
308 struct ie_softc
*sc
= &asc
->sc_ie
;
309 struct isa_attach_args
*ia
= aux
;
312 bus_space_handle_t ioh
, memh
;
313 u_int8_t ethaddr
[ETHER_ADDR_LEN
];
316 if (bus_space_map(ia
->ia_iot
, ia
->ia_io
[0].ir_addr
,
317 ia
->ia_io
[0].ir_size
, 0, &ioh
) != 0) {
318 DPRINTF(("\n%s: can't map i/o space 0x%x-0x%x\n",
319 device_xname(&sc
->sc_dev
),
320 ia
->ia_io
[0].ir_addr
, ia
->ia_io
[0].ir_addr
+
321 ia
->ia_io
[0].ir_size
- 1));
325 if (bus_space_map(ia
->ia_memt
, ia
->ia_iomem
[0].ir_addr
,
326 ia
->ia_iomem
[0].ir_size
, 0, &memh
) != 0) {
327 DPRINTF(("\n%s: can't map iomem space 0x%x-0x%x\n",
328 device_xname(&sc
->sc_dev
),
329 ia
->ia_iomem
[0].ir_addr
, ia
->ia_iomem
[0].ir_addr
+
330 ia
->ia_iomem
[0].ir_size
- 1));
331 bus_space_unmap(ia
->ia_iot
, ioh
, ia
->ia_io
[0].ir_size
);
335 asc
->sc_regt
= ia
->ia_iot
;
340 sc
->hwreset
= ai_reset
;
341 sc
->chan_attn
= ai_atten
;
343 sc
->ie_bus_barrier
= NULL
;
345 sc
->memcopyin
= ai_copyin
;
346 sc
->memcopyout
= ai_copyout
;
347 sc
->ie_bus_read16
= ai_read_16
;
348 sc
->ie_bus_write16
= ai_write_16
;
349 sc
->ie_bus_write24
= ai_write_24
;
351 sc
->do_xmitnopchain
= 0;
353 sc
->sc_mediachange
= NULL
;
354 sc
->sc_mediastatus
= NULL
;
356 sc
->bt
= ia
->ia_memt
;
360 sc
->sc_msize
= ia
->ia_iomem
[0].ir_size
;
361 sc
->sc_maddr
= (void *)memh
;
362 sc
->sc_iobase
= (char *)sc
->sc_maddr
+ sc
->sc_msize
- (1 << 24);
364 /* set up pointers to important on-card control structures */
366 sc
->scb
= IE_ISCP_SZ
;
367 sc
->scp
= sc
->sc_msize
+ IE_SCP_ADDR
- (1 << 24);
369 sc
->buf_area
= sc
->scb
+ IE_SCB_SZ
;
370 sc
->buf_area_sz
= sc
->sc_msize
- IE_ISCP_SZ
- IE_SCB_SZ
- IE_SCP_SZ
;
372 /* zero card memory */
373 bus_space_set_region_1(sc
->bt
, sc
->bh
, 0, 0, sc
->sc_msize
);
375 /* set card to 16-bit bus mode */
376 bus_space_write_1(sc
->bt
, sc
->bh
, IE_SCP_BUS_USE((u_long
)sc
->scp
),
379 /* set up pointers to key structures */
380 ai_write_24(sc
, IE_SCP_ISCP((u_long
)sc
->scp
), (u_long
) sc
->iscp
);
381 ai_write_16(sc
, IE_ISCP_SCB((u_long
)sc
->iscp
), (u_long
) sc
->scb
);
382 ai_write_24(sc
, IE_ISCP_BASE((u_long
)sc
->iscp
), (u_long
) sc
->iscp
);
384 /* flush setup of pointers, check if chip answers */
385 bus_space_barrier(sc
->bt
, sc
->bh
, 0, sc
->sc_msize
,
386 BUS_SPACE_BARRIER_WRITE
);
387 if (!i82586_proberam(sc
)) {
388 DPRINTF(("\n%s: can't talk to i82586!\n",
389 device_xname(&sc
->sc_dev
)));
390 bus_space_unmap(ia
->ia_iot
, ioh
, ia
->ia_io
[0].ir_size
);
391 bus_space_unmap(ia
->ia_memt
, memh
, ia
->ia_iomem
[0].ir_size
);
395 val
= bus_space_read_1(asc
->sc_regt
, asc
->sc_regh
, AI_REVISION
);
396 asc
->card_rev
= SL_REV(val
);
397 asc
->card_type
= SL_BOARD(val
) - 1;
398 snprintf(name
, sizeof(name
), "%s, rev. %d",
399 ai_names
[asc
->card_type
], asc
->card_rev
);
401 i82586_attach(sc
, name
, ethaddr
, NULL
, 0, 0);
403 asc
->sc_ih
= isa_intr_establish(ia
->ia_ic
, ia
->ia_irq
[0].ir_irq
,
404 IST_EDGE
, IPL_NET
, i82586_intr
, sc
);
405 if (asc
->sc_ih
== NULL
) {
406 DPRINTF(("\n%s: can't establish interrupt\n",
407 device_xname(&sc
->sc_dev
)));
412 * Divine the memory size of this board.
413 * Better hope there's nothing important hiding just below the card...
416 ai_find_mem_size(struct ai_softc
* asc
, bus_space_tag_t memt
, bus_size_t maddr
)
419 bus_space_handle_t memh
;
420 struct ie_softc
* sc
= &asc
->sc_ie
;
422 for (size
= 65536; size
>= 16384; size
-= 16384) {
423 if (bus_space_map(memt
, maddr
, size
, 0, &memh
) == 0) {
424 size
= check_ie_present(sc
, memt
, maddr
, size
);
425 bus_space_unmap(memt
, memh
, size
);
436 * Check to see if there's an 82586 out there.
439 check_ie_present(struct ie_softc
* sc
, bus_space_tag_t memt
, bus_space_handle_t memh
, bus_size_t size
)
441 sc
->hwreset
= ai_reset
;
442 sc
->chan_attn
= ai_atten
;
443 sc
->ie_bus_read16
= ai_read_16
;
444 sc
->ie_bus_write16
= ai_write_16
;
448 sc
->sc_iobase
= (char *)memh
+ size
- (1 << 24);
450 sc
->scp
= size
+ IE_SCP_ADDR
- (1 << 24);
451 bus_space_set_region_1(memt
, memh
, (u_long
) sc
->scp
, 0, IE_SCP_SZ
);
454 bus_space_set_region_1(memt
, memh
, (u_long
) sc
->iscp
, 0, IE_ISCP_SZ
);
456 sc
->scb
= IE_ISCP_SZ
;
457 bus_space_set_region_1(memt
, memh
, sc
->scb
, 0, IE_SCB_SZ
);
459 /* set card to 16-bit bus mode */
460 bus_space_write_1(sc
->bt
, sc
->bh
, IE_SCP_BUS_USE((u_long
)sc
->scp
),
463 /* set up pointers to key structures */
464 ai_write_24(sc
, IE_SCP_ISCP((u_long
)sc
->scp
), (u_long
) sc
->iscp
);
465 ai_write_16(sc
, IE_ISCP_SCB((u_long
)sc
->iscp
), (u_long
) sc
->scb
);
466 ai_write_24(sc
, IE_ISCP_BASE((u_long
)sc
->iscp
), (u_long
) sc
->iscp
);
468 /* flush setup of pointers, check if chip answers */
469 bus_space_barrier(sc
->bt
, sc
->bh
, 0, sc
->sc_msize
,
470 BUS_SPACE_BARRIER_WRITE
);
472 if (!i82586_proberam(sc
))
478 CFATTACH_DECL(ai
, sizeof(struct ai_softc
),
479 ai_match
, ai_attach
, NULL
, NULL
);