1 /* $NetBSD: if_le_ledma.c,v 1.33 2009/09/08 18:31:36 tsutsui Exp $ */
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace
9 * Simulation Facility, NASA Ames Research Center; Paul Kranenburg.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: if_le_ledma.c,v 1.33 2009/09/08 18:31:36 tsutsui Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
42 #include <sys/syslog.h>
43 #include <sys/socket.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
48 #include <net/if_ether.h>
49 #include <net/if_media.h>
52 #include <netinet/in.h>
53 #include <netinet/if_inarp.h>
58 #include <machine/autoconf.h>
60 #include <dev/sbus/sbusvar.h>
62 #include <dev/ic/lsi64854reg.h>
63 #include <dev/ic/lsi64854var.h>
65 #include <dev/ic/lancereg.h>
66 #include <dev/ic/lancevar.h>
67 #include <dev/ic/am7990reg.h>
68 #include <dev/ic/am7990var.h>
75 #define LEREG1_RDP 0 /* Register Data port */
76 #define LEREG1_RAP 2 /* Register Address port */
79 struct am7990_softc sc_am7990
; /* glue to MI code */
80 bus_space_tag_t sc_bustag
;
81 bus_dmamap_t sc_dmamap
;
82 bus_space_handle_t sc_reg
; /* LANCE registers */
83 struct lsi64854_softc
*sc_dma
; /* pointer to my dma */
84 u_int sc_laddr
; /* LANCE DMA address */
86 #define LE_LOSTTHRESH 5 /* lost carrior count to switch media */
89 #define MEMSIZE (16*1024) /* LANCE memory size */
90 #define LEDMA_BOUNDARY (16*1024*1024) /* must not cross 16MB boundary */
92 int lematch_ledma(device_t
, cfdata_t
, void *);
93 void leattach_ledma(device_t
, device_t
, void *);
96 * Media types supported by the Sun4m.
98 static int lemedia
[] = {
103 #define NLEMEDIA __arraycount(lemedia)
105 void lesetutp(struct lance_softc
*);
106 void lesetaui(struct lance_softc
*);
108 int lemediachange(struct lance_softc
*);
109 void lemediastatus(struct lance_softc
*, struct ifmediareq
*);
111 CFATTACH_DECL_NEW(le_ledma
, sizeof(struct le_softc
),
112 lematch_ledma
, leattach_ledma
, NULL
, NULL
);
114 #if defined(_KERNEL_OPT)
118 static void lewrcsr(struct lance_softc
*, uint16_t, uint16_t);
119 static uint16_t lerdcsr(struct lance_softc
*, uint16_t);
120 static void lehwreset(struct lance_softc
*);
121 static void lehwinit(struct lance_softc
*);
122 static void lenocarrier(struct lance_softc
*);
125 lewrcsr(struct lance_softc
*sc
, uint16_t port
, uint16_t val
)
127 struct le_softc
*lesc
= (struct le_softc
*)sc
;
128 bus_space_tag_t t
= lesc
->sc_bustag
;
129 bus_space_handle_t h
= lesc
->sc_reg
;
131 bus_space_write_2(t
, h
, LEREG1_RAP
, port
);
132 bus_space_write_2(t
, h
, LEREG1_RDP
, val
);
136 * We need to flush the Sbus->Mbus write buffers. This can most
137 * easily be accomplished by reading back the register that we
138 * just wrote (thanks to Chris Torek for this solution).
140 (void)bus_space_read_2(t
, h
, LEREG1_RDP
);
145 lerdcsr(struct lance_softc
*sc
, uint16_t port
)
147 struct le_softc
*lesc
= (struct le_softc
*)sc
;
148 bus_space_tag_t t
= lesc
->sc_bustag
;
149 bus_space_handle_t h
= lesc
->sc_reg
;
151 bus_space_write_2(t
, h
, LEREG1_RAP
, port
);
152 return (bus_space_read_2(t
, h
, LEREG1_RDP
));
156 lesetutp(struct lance_softc
*sc
)
158 struct lsi64854_softc
*dma
= ((struct le_softc
*)sc
)->sc_dma
;
161 csr
= L64854_GCSR(dma
);
163 L64854_SCSR(dma
, csr
);
164 delay(20000); /* must not touch le for 20ms */
168 lesetaui(struct lance_softc
*sc
)
170 struct lsi64854_softc
*dma
= ((struct le_softc
*)sc
)->sc_dma
;
173 csr
= L64854_GCSR(dma
);
175 L64854_SCSR(dma
, csr
);
176 delay(20000); /* must not touch le for 20ms */
180 lemediachange(struct lance_softc
*sc
)
182 struct ifmedia
*ifm
= &sc
->sc_media
;
184 if (IFM_TYPE(ifm
->ifm_media
) != IFM_ETHER
)
188 * Switch to the selected media. If autoselect is
189 * set, we don't really have to do anything. We'll
190 * switch to the other media when we detect loss of
193 switch (IFM_SUBTYPE(ifm
->ifm_media
)) {
213 lemediastatus(struct lance_softc
*sc
, struct ifmediareq
*ifmr
)
215 struct lsi64854_softc
*dma
= ((struct le_softc
*)sc
)->sc_dma
;
218 * Notify the world which media we're currently using.
220 if (L64854_GCSR(dma
) & E_TP_AUI
)
221 ifmr
->ifm_active
= IFM_ETHER
|IFM_10_T
;
223 ifmr
->ifm_active
= IFM_ETHER
|IFM_10_5
;
227 lehwreset(struct lance_softc
*sc
)
229 struct le_softc
*lesc
= (struct le_softc
*)sc
;
230 struct lsi64854_softc
*dma
= lesc
->sc_dma
;
237 csr
= L64854_GCSR(dma
);
238 aui_bit
= csr
& E_TP_AUI
;
241 /* Write bits 24-31 of Lance address */
242 bus_space_write_4(dma
->sc_bustag
, dma
->sc_regs
, L64854_REG_ENBAR
,
243 lesc
->sc_laddr
& 0xff000000);
248 * Disable E-cache invalidates on chip writes.
249 * Retain previous cable selection bit.
251 csr
= L64854_GCSR(dma
);
252 csr
|= (E_DSBL_WR_INVAL
| aui_bit
);
253 L64854_SCSR(dma
, csr
);
254 delay(20000); /* must not touch le for 20ms */
258 lehwinit(struct lance_softc
*sc
)
262 * Make sure we're using the currently-enabled media type.
263 * XXX Actually, this is probably unnecessary, now.
265 switch (IFM_SUBTYPE(sc
->sc_media
.ifm_cur
->ifm_media
)) {
277 lenocarrier(struct lance_softc
*sc
)
279 struct le_softc
*lesc
= (struct le_softc
*)sc
;
281 /* it may take a while for modern switches to set 10baseT media */
282 if (lesc
->sc_lostcount
++ < LE_LOSTTHRESH
)
285 lesc
->sc_lostcount
= 0;
288 * Check if the user has requested a certain cable type, and
289 * if so, honor that request.
291 printf("%s: lost carrier on ", device_xname(sc
->sc_dev
));
293 if (L64854_GCSR(lesc
->sc_dma
) & E_TP_AUI
) {
295 switch (IFM_SUBTYPE(sc
->sc_media
.ifm_media
)) {
298 printf(", switching to AUI port");
303 switch (IFM_SUBTYPE(sc
->sc_media
.ifm_media
)) {
306 printf(", switching to UTP port");
314 lematch_ledma(device_t parent
, cfdata_t cf
, void *aux
)
316 struct sbus_attach_args
*sa
= aux
;
318 return (strcmp(cf
->cf_name
, sa
->sa_name
) == 0);
323 leattach_ledma(device_t parent
, device_t self
, void *aux
)
325 struct le_softc
*lesc
= device_private(self
);
326 struct lance_softc
*sc
= &lesc
->sc_am7990
.lsc
;
327 struct lsi64854_softc
*lsi
= device_private(parent
);
328 struct sbus_attach_args
*sa
= aux
;
329 bus_dma_tag_t dmatag
= sa
->sa_dmatag
;
330 bus_dma_segment_t seg
;
334 lesc
->sc_bustag
= sa
->sa_bustag
;
336 /* Establish link to `ledma' device */
338 lesc
->sc_dma
->sc_client
= lesc
;
340 /* Map device registers */
341 if (sbus_bus_map(sa
->sa_bustag
,
345 0, &lesc
->sc_reg
) != 0) {
346 aprint_error(": cannot map registers\n");
350 /* Allocate buffer memory */
351 sc
->sc_memsize
= MEMSIZE
;
353 /* Get a DMA handle */
354 if ((error
= bus_dmamap_create(dmatag
, MEMSIZE
, 1, MEMSIZE
,
355 LEDMA_BOUNDARY
, BUS_DMA_NOWAIT
,
356 &lesc
->sc_dmamap
)) != 0) {
357 aprint_error(": DMA map create error %d\n", error
);
361 /* Allocate DMA buffer */
362 if ((error
= bus_dmamem_alloc(dmatag
, MEMSIZE
, 0, LEDMA_BOUNDARY
,
363 &seg
, 1, &rseg
, BUS_DMA_NOWAIT
)) != 0) {
364 aprint_error(": DMA buffer alloc error %d\n",error
);
368 /* Map DMA buffer into kernel space */
369 if ((error
= bus_dmamem_map(dmatag
, &seg
, rseg
, MEMSIZE
,
370 (void **)&sc
->sc_mem
,
371 BUS_DMA_NOWAIT
|BUS_DMA_COHERENT
)) != 0) {
372 aprint_error(": DMA buffer map error %d\n", error
);
373 bus_dmamem_free(dmatag
, &seg
, rseg
);
377 /* Load DMA buffer */
378 if ((error
= bus_dmamap_load(dmatag
, lesc
->sc_dmamap
, sc
->sc_mem
,
379 MEMSIZE
, NULL
, BUS_DMA_NOWAIT
|BUS_DMA_COHERENT
)) != 0) {
380 aprint_error(": DMA buffer map load error %d\n", error
);
381 bus_dmamem_free(dmatag
, &seg
, rseg
);
382 bus_dmamem_unmap(dmatag
, sc
->sc_mem
, MEMSIZE
);
386 lesc
->sc_laddr
= lesc
->sc_dmamap
->dm_segs
[0].ds_addr
;
387 sc
->sc_addr
= lesc
->sc_laddr
& 0xffffff;
388 sc
->sc_conf3
= LE_C3_BSWP
| LE_C3_ACON
| LE_C3_BCON
;
389 lesc
->sc_lostcount
= 0;
391 sc
->sc_mediachange
= lemediachange
;
392 sc
->sc_mediastatus
= lemediastatus
;
393 sc
->sc_supmedia
= lemedia
;
394 sc
->sc_nsupmedia
= NLEMEDIA
;
395 sc
->sc_defaultmedia
= IFM_ETHER
|IFM_AUTO
;
397 prom_getether(sa
->sa_node
, sc
->sc_enaddr
);
399 sc
->sc_copytodesc
= lance_copytobuf_contig
;
400 sc
->sc_copyfromdesc
= lance_copyfrombuf_contig
;
401 sc
->sc_copytobuf
= lance_copytobuf_contig
;
402 sc
->sc_copyfrombuf
= lance_copyfrombuf_contig
;
403 sc
->sc_zerobuf
= lance_zerobuf_contig
;
405 sc
->sc_rdcsr
= lerdcsr
;
406 sc
->sc_wrcsr
= lewrcsr
;
407 sc
->sc_hwinit
= lehwinit
;
408 sc
->sc_nocarrier
= lenocarrier
;
409 sc
->sc_hwreset
= lehwreset
;
411 /* Establish interrupt handler */
412 if (sa
->sa_nintr
!= 0)
413 (void)bus_intr_establish(sa
->sa_bustag
, sa
->sa_pri
, IPL_NET
,
416 am7990_config(&lesc
->sc_am7990
);
418 /* now initialize DMA */