1 /* $NetBSD: if_le_isa.c,v 1.41 2005/12/24 20:27:41 perry Exp $ */
2 /* $FreeBSD: src/sys/dev/le/if_le_isa.c,v 1.1 2006/05/17 21:25:22 marius Exp $ */
3 /* $DragonFly: src/sys/dev/netif/lnc/if_lnc_isa.c,v 1.11 2008/05/14 11:59:20 sephe Exp $ */
6 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
11 * Simulation Facility, NASA Ames Research Center.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the NetBSD
24 * Foundation, Inc. and its contributors.
25 * 4. Neither the name of The NetBSD Foundation nor the names of its
26 * contributors may be used to endorse or promote products derived
27 * from this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
43 * Copyright (c) 1992, 1993
44 * The Regents of the University of California. All rights reserved.
46 * This code is derived from software contributed to Berkeley by
47 * Ralph Campbell and Rick Macklem.
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions
52 * 1. Redistributions of source code must retain the above copyright
53 * notice, this list of conditions and the following disclaimer.
54 * 2. Redistributions in binary form must reproduce the above copyright
55 * notice, this list of conditions and the following disclaimer in the
56 * documentation and/or other materials provided with the distribution.
57 * 3. Neither the name of the University nor the names of its contributors
58 * may be used to endorse or promote products derived from this software
59 * without specific prior written permission.
61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
76 #include <sys/param.h>
77 #include <sys/systm.h>
79 #include <sys/endian.h>
80 #include <sys/kernel.h>
81 #include <sys/interrupt.h>
83 #include <sys/module.h>
84 #include <sys/resource.h>
86 #include <sys/socket.h>
88 #include <net/ethernet.h>
90 #include <net/if_media.h>
91 #include <net/if_arp.h>
93 #include <bus/isa/isavar.h>
95 #include <dev/netif/lnc/lancereg.h>
96 #include <dev/netif/lnc/lancevar.h>
97 #include <dev/netif/lnc/am7990var.h>
99 #define LE_ISA_MEMSIZE (16*1024)
100 #define PCNET_RDP 0x10
101 #define PCNET_RAP 0x12
103 struct le_isa_softc
{
104 struct am7990_softc sc_am7990
; /* glue to MI code */
106 bus_size_t sc_rap
; /* offsets to LANCE... */
107 bus_size_t sc_rdp
; /* ...registers */
110 struct resource
*sc_rres
;
111 bus_space_tag_t sc_regt
;
112 bus_space_handle_t sc_regh
;
115 struct resource
*sc_dres
;
118 struct resource
*sc_ires
;
121 bus_dma_tag_t sc_pdmat
;
122 bus_dma_tag_t sc_dmat
;
123 bus_dmamap_t sc_dmam
;
126 static device_probe_t le_isa_probe
;
127 static device_attach_t le_isa_attach
;
128 static device_detach_t le_isa_detach
;
129 static device_resume_t le_isa_resume
;
130 static device_suspend_t le_isa_suspend
;
132 static device_method_t le_isa_methods
[] = {
133 /* Device interface */
134 DEVMETHOD(device_probe
, le_isa_probe
),
135 DEVMETHOD(device_attach
, le_isa_attach
),
136 DEVMETHOD(device_detach
, le_isa_detach
),
137 /* We can just use the suspend method here. */
138 DEVMETHOD(device_shutdown
, le_isa_suspend
),
139 DEVMETHOD(device_suspend
, le_isa_suspend
),
140 DEVMETHOD(device_resume
, le_isa_resume
),
145 DEFINE_CLASS_0(lnc
, le_isa_driver
, le_isa_methods
, sizeof(struct le_isa_softc
));
146 DRIVER_MODULE(lnc
, isa
, le_isa_driver
, le_devclass
, 0, 0);
147 MODULE_DEPEND(lnc
, ether
, 1, 1, 1);
149 struct le_isa_param
{
156 } static const le_isa_params
[] = {
157 { "BICC Isolan", 24, 0xe, 0xc, 0, 2 },
158 { "Novell NE2100", 16, 0x12, 0x10, 0, 1 }
161 static struct isa_pnp_id le_isa_ids
[] = {
162 { 0x0322690e, "Cabletron E2200 Single Chip" }, /* CSI2203 */
163 { 0x0110490a, "Boca LANCard Combo" }, /* BRI1001 */
164 { 0x0100a60a, "Melco Inc. LGY-IV" }, /* BUF0001 */
165 { 0xd880d041, "Novell NE2100" }, /* PNP80D8 */
166 { 0x0082d041, "Cabletron E2100 Series DNI" }, /* PNP8200 */
167 { 0x3182d041, "AMD AM1500T/AM2100" }, /* PNP8231 */
168 { 0x8c82d041, "AMD PCnet-ISA" }, /* PNP828C */
169 { 0x8d82d041, "AMD PCnet-32" }, /* PNP828D */
170 { 0xcefaedfe, "Racal InterLan EtherBlaster" }, /* _WMFACE */
174 static void le_isa_wrcsr(struct lance_softc
*, uint16_t, uint16_t);
175 static uint16_t le_isa_rdcsr(struct lance_softc
*, uint16_t);
176 static bus_dmamap_callback_t le_isa_dma_callback
;
177 static int le_isa_probe_legacy(device_t
, const struct le_isa_param
*);
180 le_isa_wrcsr(struct lance_softc
*sc
, uint16_t port
, uint16_t val
)
182 struct le_isa_softc
*lesc
= (struct le_isa_softc
*)sc
;
184 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, lesc
->sc_rap
, port
);
185 bus_space_barrier(lesc
->sc_regt
, lesc
->sc_regh
, lesc
->sc_rap
, 2,
186 BUS_SPACE_BARRIER_WRITE
);
187 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, lesc
->sc_rdp
, val
);
191 le_isa_rdcsr(struct lance_softc
*sc
, uint16_t port
)
193 struct le_isa_softc
*lesc
= (struct le_isa_softc
*)sc
;
195 bus_space_write_2(lesc
->sc_regt
, lesc
->sc_regh
, lesc
->sc_rap
, port
);
196 bus_space_barrier(lesc
->sc_regt
, lesc
->sc_regh
, lesc
->sc_rap
, 2,
197 BUS_SPACE_BARRIER_WRITE
);
198 return (bus_space_read_2(lesc
->sc_regt
, lesc
->sc_regh
, lesc
->sc_rdp
));
202 le_isa_dma_callback(void *xsc
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
204 struct lance_softc
*sc
= (struct lance_softc
*)xsc
;
208 KASSERT(nsegs
== 1, ("%s: bad DMA segment count", __func__
));
209 sc
->sc_addr
= segs
[0].ds_addr
;
213 le_isa_probe_legacy(device_t dev
, const struct le_isa_param
*leip
)
215 struct le_isa_softc
*lesc
;
216 struct lance_softc
*sc
;
219 lesc
= device_get_softc(dev
);
220 sc
= &lesc
->sc_am7990
.lsc
;
223 lesc
->sc_rres
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &lesc
->sc_rrid
,
224 0, ~0, leip
->iosize
, RF_ACTIVE
);
225 if (lesc
->sc_rres
== NULL
)
227 lesc
->sc_regt
= rman_get_bustag(lesc
->sc_rres
);
228 lesc
->sc_regh
= rman_get_bushandle(lesc
->sc_rres
);
229 lesc
->sc_rap
= leip
->rap
;
230 lesc
->sc_rdp
= leip
->rdp
;
232 /* Stop the chip and put it in a known state. */
233 le_isa_wrcsr(sc
, LE_CSR0
, LE_C0_STOP
);
235 if (le_isa_rdcsr(sc
, LE_CSR0
) != LE_C0_STOP
) {
239 le_isa_wrcsr(sc
, LE_CSR3
, 0);
243 bus_release_resource(dev
, SYS_RES_IOPORT
, lesc
->sc_rrid
, lesc
->sc_rres
);
248 le_isa_probe(device_t dev
)
252 switch (ISA_PNP_PROBE(device_get_parent(dev
), dev
, le_isa_ids
)) {
256 for (i
= 0; i
< sizeof(le_isa_params
) /
257 sizeof(le_isa_params
[0]); i
++) {
258 if (le_isa_probe_legacy(dev
, &le_isa_params
[i
]) == 0) {
259 device_set_desc(dev
, le_isa_params
[i
].name
);
271 le_isa_attach(device_t dev
)
273 struct le_isa_softc
*lesc
;
274 struct lance_softc
*sc
;
275 bus_size_t macstart
, rap
, rdp
;
276 int error
, i
, macstride
;
278 lesc
= device_get_softc(dev
);
279 sc
= &lesc
->sc_am7990
.lsc
;
282 switch (ISA_PNP_PROBE(device_get_parent(dev
), dev
, le_isa_ids
)) {
284 lesc
->sc_rres
= bus_alloc_resource_any(dev
, SYS_RES_IOPORT
,
285 &lesc
->sc_rrid
, RF_ACTIVE
);
292 for (i
= 0; i
< sizeof(le_isa_params
) /
293 sizeof(le_isa_params
[0]); i
++) {
294 if (le_isa_probe_legacy(dev
, &le_isa_params
[i
]) == 0) {
295 lesc
->sc_rres
= bus_alloc_resource(dev
,
296 SYS_RES_IOPORT
, &lesc
->sc_rrid
, 0, ~0,
297 le_isa_params
[i
].iosize
, RF_ACTIVE
);
298 rap
= le_isa_params
[i
].rap
;
299 rdp
= le_isa_params
[i
].rdp
;
300 macstart
= le_isa_params
[i
].macstart
;
301 macstride
= le_isa_params
[i
].macstride
;
308 device_printf(dev
, "cannot determine chip\n");
314 if (lesc
->sc_rres
== NULL
) {
315 device_printf(dev
, "cannot allocate registers\n");
319 lesc
->sc_regt
= rman_get_bustag(lesc
->sc_rres
);
320 lesc
->sc_regh
= rman_get_bushandle(lesc
->sc_rres
);
325 if ((lesc
->sc_dres
= bus_alloc_resource_any(dev
, SYS_RES_DRQ
,
326 &lesc
->sc_drid
, RF_ACTIVE
)) == NULL
) {
327 device_printf(dev
, "cannot allocate DMA channel\n");
333 if ((lesc
->sc_ires
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
,
334 &lesc
->sc_irid
, RF_SHAREABLE
| RF_ACTIVE
)) == NULL
) {
335 device_printf(dev
, "cannot allocate interrupt\n");
340 error
= bus_dma_tag_create(
342 1, 0, /* alignment, boundary */
343 BUS_SPACE_MAXADDR_24BIT
, /* lowaddr */
344 BUS_SPACE_MAXADDR
, /* highaddr */
345 NULL
, NULL
, /* filter, filterarg */
346 BUS_SPACE_MAXSIZE_32BIT
, /* maxsize */
348 BUS_SPACE_MAXSIZE_32BIT
, /* maxsegsize */
349 BUS_DMA_WAITOK
, /* flags */
352 device_printf(dev
, "cannot allocate parent DMA tag\n");
356 sc
->sc_memsize
= LE_ISA_MEMSIZE
;
358 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
359 * aligned and the ring descriptors must be 8-byte aligned.
361 error
= bus_dma_tag_create(
362 lesc
->sc_pdmat
, /* parent */
363 8, 0, /* alignment, boundary */
364 BUS_SPACE_MAXADDR_24BIT
, /* lowaddr */
365 BUS_SPACE_MAXADDR
, /* highaddr */
366 NULL
, NULL
, /* filter, filterarg */
367 sc
->sc_memsize
, /* maxsize */
369 sc
->sc_memsize
, /* maxsegsize */
370 BUS_DMA_WAITOK
, /* flags */
373 device_printf(dev
, "cannot allocate buffer DMA tag\n");
377 error
= bus_dmamem_alloc(lesc
->sc_dmat
, (void **)&sc
->sc_mem
,
378 BUS_DMA_WAITOK
| BUS_DMA_COHERENT
, &lesc
->sc_dmam
);
380 device_printf(dev
, "cannot allocate DMA buffer memory\n");
385 error
= bus_dmamap_load(lesc
->sc_dmat
, lesc
->sc_dmam
, sc
->sc_mem
,
386 sc
->sc_memsize
, le_isa_dma_callback
, sc
, 0);
387 if (error
!= 0 || sc
->sc_addr
== 0) {
388 device_printf(dev
, "cannot load DMA buffer map\n");
392 isa_dmacascade(rman_get_start(lesc
->sc_dres
));
398 * Extract the physical MAC address from the ROM.
400 for (i
= 0; i
< sizeof(sc
->sc_enaddr
); i
++)
401 sc
->sc_enaddr
[i
] = bus_space_read_1(lesc
->sc_regt
,
402 lesc
->sc_regh
, macstart
+ i
* macstride
);
404 sc
->sc_copytodesc
= lance_copytobuf_contig
;
405 sc
->sc_copyfromdesc
= lance_copyfrombuf_contig
;
406 sc
->sc_copytobuf
= lance_copytobuf_contig
;
407 sc
->sc_copyfrombuf
= lance_copyfrombuf_contig
;
408 sc
->sc_zerobuf
= lance_zerobuf_contig
;
410 sc
->sc_rdcsr
= le_isa_rdcsr
;
411 sc
->sc_wrcsr
= le_isa_wrcsr
;
412 sc
->sc_hwreset
= NULL
;
413 sc
->sc_hwinit
= NULL
;
414 sc
->sc_hwintr
= NULL
;
415 sc
->sc_nocarrier
= NULL
;
416 sc
->sc_mediachange
= NULL
;
417 sc
->sc_mediastatus
= NULL
;
418 sc
->sc_supmedia
= NULL
;
420 error
= am7990_config(&lesc
->sc_am7990
, device_get_name(dev
),
421 device_get_unit(dev
));
423 device_printf(dev
, "cannot attach Am7990\n");
427 error
= bus_setup_intr(dev
, lesc
->sc_ires
, INTR_NETSAFE
| INTR_MPSAFE
,
428 am7990_intr
, sc
, &lesc
->sc_ih
, sc
->ifp
->if_serializer
);
430 device_printf(dev
, "cannot set up interrupt\n");
434 sc
->ifp
->if_cpuid
= ithread_cpuid(rman_get_start(lesc
->sc_ires
));
435 KKASSERT(sc
->ifp
->if_cpuid
>= 0 && sc
->ifp
->if_cpuid
< ncpus
);
440 am7990_detach(&lesc
->sc_am7990
);
442 bus_dmamap_unload(lesc
->sc_dmat
, lesc
->sc_dmam
);
444 bus_dmamem_free(lesc
->sc_dmat
, sc
->sc_mem
, lesc
->sc_dmam
);
446 bus_dma_tag_destroy(lesc
->sc_dmat
);
448 bus_dma_tag_destroy(lesc
->sc_pdmat
);
450 bus_release_resource(dev
, SYS_RES_IRQ
, lesc
->sc_irid
, lesc
->sc_ires
);
452 bus_release_resource(dev
, SYS_RES_DRQ
, lesc
->sc_drid
, lesc
->sc_dres
);
454 bus_release_resource(dev
, SYS_RES_IOPORT
, lesc
->sc_rrid
, lesc
->sc_rres
);
460 le_isa_detach(device_t dev
)
462 struct le_isa_softc
*lesc
;
463 struct lance_softc
*sc
;
465 lesc
= device_get_softc(dev
);
466 sc
= &lesc
->sc_am7990
.lsc
;
468 if (device_is_attached(dev
)) {
469 lwkt_serialize_enter(sc
->ifp
->if_serializer
);
471 bus_teardown_intr(dev
, lesc
->sc_ires
, lesc
->sc_ih
);
472 lwkt_serialize_exit(sc
->ifp
->if_serializer
);
474 am7990_detach(&lesc
->sc_am7990
);
478 bus_release_resource(dev
, SYS_RES_IRQ
, lesc
->sc_irid
, lesc
->sc_ires
);
480 bus_release_resource(dev
, SYS_RES_DRQ
, lesc
->sc_drid
, lesc
->sc_dres
);
482 bus_release_resource(dev
, SYS_RES_IOPORT
, lesc
->sc_rrid
, lesc
->sc_rres
);
484 bus_dmamap_unload(lesc
->sc_dmat
, lesc
->sc_dmam
);
485 bus_dmamem_free(lesc
->sc_dmat
, sc
->sc_mem
, lesc
->sc_dmam
);
488 bus_dma_tag_destroy(lesc
->sc_dmat
);
490 bus_dma_tag_destroy(lesc
->sc_pdmat
);
496 le_isa_suspend(device_t dev
)
498 struct le_isa_softc
*lesc
;
500 lesc
= device_get_softc(dev
);
502 lance_suspend(&lesc
->sc_am7990
.lsc
);
508 le_isa_resume(device_t dev
)
510 struct le_isa_softc
*lesc
;
512 lesc
= device_get_softc(dev
);
514 lance_resume(&lesc
->sc_am7990
.lsc
);