1 /* $NetBSD: we.c,v 1.14 2008/03/12 14:31:11 cube Exp $ */
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
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.
34 * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
37 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
39 * Copyright (C) 1993, David Greenman. This software may be used, modified,
40 * copied, distributed, and sold, in both source and binary form provided that
41 * the above copyright and these terms are retained. Under no circumstances is
42 * the author responsible for the proper functioning of this software, nor does
43 * the author assume any responsibility for damages incurred with its use.
47 * Device driver for the Western Digital/SMC 8003 and 8013 series,
48 * and the SMC Elite Ultra (8216).
51 #include <sys/cdefs.h>
52 __KERNEL_RCSID(0, "$NetBSD: we.c,v 1.14 2008/03/12 14:31:11 cube Exp $");
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/device.h>
57 #include <sys/socket.h>
59 #include <sys/syslog.h>
62 #include <net/if_dl.h>
63 #include <net/if_types.h>
64 #include <net/if_media.h>
66 #include <net/if_ether.h>
69 #include <sys/bswap.h>
72 #include <dev/isa/isareg.h>
73 #include <dev/isa/isavar.h>
75 #include <dev/ic/dp8390reg.h>
76 #include <dev/ic/dp8390var.h>
77 #include <dev/ic/wereg.h>
78 #include <dev/ic/wevar.h>
80 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
81 #define bus_space_read_region_stream_2 bus_space_read_region_2
82 #define bus_space_write_stream_2 bus_space_write_2
83 #define bus_space_write_region_stream_2 bus_space_write_region_2
86 static void we_set_media(struct we_softc
*, int);
88 static void we_media_init(struct dp8390_softc
*);
90 static int we_mediachange(struct dp8390_softc
*);
91 static void we_mediastatus(struct dp8390_softc
*, struct ifmediareq
*);
93 static void we_recv_int(struct dp8390_softc
*);
94 static void we_init_card(struct dp8390_softc
*);
95 static int we_write_mbuf(struct dp8390_softc
*, struct mbuf
*, int);
96 static int we_ring_copy(struct dp8390_softc
*, int, void *, u_short
);
97 static void we_read_hdr(struct dp8390_softc
*, int, struct dp8390_ring
*);
98 static int we_test_mem(struct dp8390_softc
*);
100 static inline void we_readmem(struct we_softc
*, int, u_int8_t
*, int);
103 * Delay needed when switching 16-bit access to shared memory.
105 #define WE_DELAY(wsc) delay(3)
108 * Enable card RAM, and 16-bit access.
110 #define WE_MEM_ENABLE(wsc) \
111 if (((wsc)->sc_flags & WE_16BIT_NOTOGGLE) == 0) { \
112 if ((wsc)->sc_flags & WE_16BIT_ENABLE) \
113 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
114 WE_LAAR, (wsc)->sc_laar_proto | WE_LAAR_M16EN); \
115 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
116 WE_MSR, wsc->sc_msr_proto | WE_MSR_MENB); \
121 * Disable card RAM, and 16-bit access.
123 #define WE_MEM_DISABLE(wsc) \
124 if (((wsc)->sc_flags & WE_16BIT_NOTOGGLE) == 0) { \
125 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
126 WE_MSR, (wsc)->sc_msr_proto); \
127 if ((wsc)->sc_flags & WE_16BIT_ENABLE) \
128 bus_space_write_1((wsc)->sc_asict, (wsc)->sc_asich, \
129 WE_LAAR, (wsc)->sc_laar_proto); \
134 we_config(device_t self
, struct we_softc
*wsc
, const char *typestr
)
136 struct dp8390_softc
*sc
= &wsc
->sc_dp8390
;
138 int i
, forced_16bit
= 0;
141 * Allow user to override 16-bit mode. 8-bit takes precedence.
143 if (device_cfdata(self
)->cf_flags
& DP8390_FORCE_16BIT_MODE
) {
144 wsc
->sc_flags
|= WE_16BIT_ENABLE
;
147 if (device_cfdata(self
)->cf_flags
& DP8390_FORCE_8BIT_MODE
)
148 wsc
->sc_flags
&= ~WE_16BIT_ENABLE
;
150 /* Registers are linear. */
151 for (i
= 0; i
< 16; i
++)
152 sc
->sc_reg_map
[i
] = i
;
154 /* Now we can use the NIC_{GET,PUT}() macros. */
156 aprint_normal_dev(self
, "%s Ethernet (%s-bit)\n",
157 typestr
, wsc
->sc_flags
& WE_16BIT_ENABLE
? "16" : "8");
159 /* Get station address from EEPROM. */
160 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
161 sc
->sc_enaddr
[i
] = bus_space_read_1(wsc
->sc_asict
,
162 wsc
->sc_asich
, WE_PROM
+ i
);
165 * Set upper address bits and 8/16 bit access to shared memory.
169 bus_space_read_1(wsc
->sc_asict
, wsc
->sc_asich
, WE_LAAR
) &
171 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
, WE_LAAR
,
172 wsc
->sc_laar_proto
| (wsc
->sc_flags
& WE_16BIT_ENABLE
? WE_LAAR_M16EN
: 0));
173 } else if ((wsc
->sc_type
& WE_SOFTCONFIG
) ||
175 (wsc
->sc_type
== WE_TYPE_TOSHIBA1
) ||
176 (wsc
->sc_type
== WE_TYPE_TOSHIBA4
) ||
179 (wsc
->sc_type
== WE_TYPE_WD8013EBT
)) {
180 wsc
->sc_laar_proto
= (wsc
->sc_maddr
>> 19) & WE_LAAR_ADDRHI
;
181 if (wsc
->sc_flags
& WE_16BIT_ENABLE
)
182 wsc
->sc_laar_proto
|= WE_LAAR_L16EN
;
183 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
, WE_LAAR
,
184 wsc
->sc_laar_proto
| (wsc
->sc_flags
& WE_16BIT_ENABLE
? WE_LAAR_M16EN
: 0));
188 * Set address and enable interface shared memory.
191 /* XXX MAGIC CONSTANTS XXX */
192 x
= bus_space_read_1(wsc
->sc_asict
, wsc
->sc_asich
, 0x04);
193 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
, 0x04, x
| 0x80);
194 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
, 0x0b,
195 ((wsc
->sc_maddr
>> 13) & 0x0f) |
196 ((wsc
->sc_maddr
>> 11) & 0x40) |
197 (bus_space_read_1(wsc
->sc_asict
, wsc
->sc_asich
, 0x0b) & 0xb0));
198 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
, 0x04, x
);
199 wsc
->sc_msr_proto
= 0x00;
203 if (wsc
->sc_type
== WE_TYPE_TOSHIBA1
||
204 wsc
->sc_type
== WE_TYPE_TOSHIBA4
) {
205 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
,
207 ((wsc
->sc_maddr
>> 8) & 0xe0) | 0x04);
208 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
,
210 ((wsc
->sc_maddr
>> 16) & 0x0f));
211 wsc
->sc_msr_proto
= WE_MSR_POW
;
214 wsc
->sc_msr_proto
= (wsc
->sc_maddr
>> 13) &
217 sc
->cr_proto
= ED_CR_RD2
;
220 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
, WE_MSR
,
221 wsc
->sc_msr_proto
| WE_MSR_MENB
);
227 * FIFO threshold to 8, No auto-init Remote DMA,
230 * 16-bit cards also get word-wide DMA transfers.
232 sc
->dcr_reg
= ED_DCR_FT1
| ED_DCR_LS
|
233 (wsc
->sc_flags
& WE_16BIT_ENABLE
? ED_DCR_WTS
: 0);
235 sc
->test_mem
= we_test_mem
;
236 sc
->ring_copy
= we_ring_copy
;
237 sc
->write_mbuf
= we_write_mbuf
;
238 sc
->read_hdr
= we_read_hdr
;
239 sc
->recv_int
= we_recv_int
;
240 sc
->init_card
= we_init_card
;
242 sc
->sc_mediachange
= we_mediachange
;
243 sc
->sc_mediastatus
= we_mediastatus
;
246 /* sc->mem_size has to be set by frontend */
248 sc
->sc_flags
= device_cfdata(self
)->cf_flags
;
250 /* Do generic parts of attach. */
251 if (wsc
->sc_type
& WE_SOFTCONFIG
)
252 sc
->sc_media_init
= we_media_init
;
254 sc
->sc_media_init
= dp8390_media_init
;
255 if (dp8390_config(sc
)) {
256 aprint_error_dev(self
, "configuration failed\n");
261 * Disable 16-bit access to shared memory - we leave it disabled
264 * (1) machines reboot properly when the board is set to
265 * 16-bit mode and there are conflicting 8-bit devices
266 * within the same 128k address space as this board's
269 * (2) so that other 8-bit devices with shared memory
270 * in this same 128k address space will work.
278 we_test_mem(struct dp8390_softc
*sc
)
280 struct we_softc
*wsc
= (struct we_softc
*)sc
;
281 bus_space_tag_t memt
= sc
->sc_buft
;
282 bus_space_handle_t memh
= sc
->sc_bufh
;
283 bus_size_t memsize
= sc
->mem_size
;
286 if (wsc
->sc_flags
& WE_16BIT_ENABLE
)
287 bus_space_set_region_2(memt
, memh
, 0, 0, memsize
>> 1);
289 bus_space_set_region_1(memt
, memh
, 0, 0, memsize
);
291 if (wsc
->sc_flags
& WE_16BIT_ENABLE
) {
292 for (i
= 0; i
< memsize
; i
+= 2) {
293 if (bus_space_read_2(memt
, memh
, i
) != 0)
297 for (i
= 0; i
< memsize
; i
++) {
298 if (bus_space_read_1(memt
, memh
, i
) != 0)
306 aprint_error_dev(sc
->sc_dev
,
307 "failed to clear shared memory at offset 0x%x\n", i
);
313 * Given a NIC memory source address and a host memory destination address,
314 * copy 'len' from NIC to host using shared memory. The 'len' is rounded
315 * up to a word - ok as long as mbufs are word-sized.
318 we_readmem(struct we_softc
*wsc
, int from
, u_int8_t
*to
, int len
)
320 bus_space_tag_t memt
= wsc
->sc_dp8390
.sc_buft
;
321 bus_space_handle_t memh
= wsc
->sc_dp8390
.sc_bufh
;
326 if (wsc
->sc_flags
& WE_16BIT_ENABLE
)
327 bus_space_read_region_stream_2(memt
, memh
, from
,
328 (u_int16_t
*)to
, len
>> 1);
330 bus_space_read_region_1(memt
, memh
, from
,
335 we_write_mbuf(struct dp8390_softc
*sc
, struct mbuf
*m
, int buf
)
337 struct we_softc
*wsc
= (struct we_softc
*)sc
;
338 bus_space_tag_t memt
= wsc
->sc_dp8390
.sc_buft
;
339 bus_space_handle_t memh
= wsc
->sc_dp8390
.sc_bufh
;
340 u_int8_t
*data
, savebyte
[2];
341 int savelen
, len
, leftover
;
346 savelen
= m
->m_pkthdr
.len
;
351 * 8-bit boards are simple; no alignment tricks are necessary.
353 if ((wsc
->sc_flags
& WE_16BIT_ENABLE
) == 0) {
354 for (; m
!= NULL
; buf
+= m
->m_len
, m
= m
->m_next
)
355 bus_space_write_region_1(memt
, memh
,
356 buf
, mtod(m
, u_int8_t
*), m
->m_len
);
357 if (savelen
< ETHER_MIN_LEN
- ETHER_CRC_LEN
) {
358 bus_space_set_region_1(memt
, memh
,
359 buf
, 0, ETHER_MIN_LEN
- ETHER_CRC_LEN
- savelen
);
360 savelen
= ETHER_MIN_LEN
- ETHER_CRC_LEN
;
365 /* Start out with no leftover data. */
367 savebyte
[0] = savebyte
[1] = 0;
369 for (; m
!= NULL
; m
= m
->m_next
) {
373 data
= mtod(m
, u_int8_t
*);
380 * Data left over (from mbuf or realignment).
381 * Buffer the next byte, and write it and
382 * the leftover data out.
384 savebyte
[1] = *data
++;
386 bus_space_write_stream_2(memt
, memh
, buf
,
387 *(u_int16_t
*)savebyte
);
390 } else if (BUS_SPACE_ALIGNED_POINTER(data
, u_int16_t
)
393 * Unaligned dta; buffer the next byte.
395 savebyte
[0] = *data
++;
400 * Aligned data; output contiguous words as
401 * much as we can, then buffer the remaining
406 bus_space_write_region_stream_2(memt
, memh
,
407 buf
, (u_int16_t
*)data
, len
>> 1);
411 savebyte
[0] = *data
++;
416 panic("we_write_mbuf: negative len");
419 panic("we_write_mbuf: data != lim");
424 bus_space_write_stream_2(memt
, memh
, buf
,
425 *(u_int16_t
*)savebyte
);
428 if (savelen
< ETHER_MIN_LEN
- ETHER_CRC_LEN
) {
429 bus_space_set_region_2(memt
, memh
,
430 buf
, 0, (ETHER_MIN_LEN
- ETHER_CRC_LEN
- savelen
) >> 1);
431 savelen
= ETHER_MIN_LEN
- ETHER_CRC_LEN
;
441 we_ring_copy(struct dp8390_softc
*sc
, int src
, void *dstv
, u_short amount
)
444 struct we_softc
*wsc
= (struct we_softc
*)sc
;
447 /* Does copy wrap to lower addr in ring buffer? */
448 if (src
+ amount
> sc
->mem_end
) {
449 tmp_amount
= sc
->mem_end
- src
;
451 /* Copy amount up to end of NIC memory. */
452 we_readmem(wsc
, src
, dst
, tmp_amount
);
454 amount
-= tmp_amount
;
459 we_readmem(wsc
, src
, dst
, amount
);
461 return (src
+ amount
);
465 we_read_hdr(struct dp8390_softc
*sc
, int packet_ptr
,
466 struct dp8390_ring
*packet_hdrp
)
468 struct we_softc
*wsc
= (struct we_softc
*)sc
;
470 we_readmem(wsc
, packet_ptr
, (u_int8_t
*)packet_hdrp
,
471 sizeof(struct dp8390_ring
));
472 #if BYTE_ORDER == BIG_ENDIAN
473 packet_hdrp
->count
= bswap16(packet_hdrp
->count
);
478 we_recv_int(struct dp8390_softc
*sc
)
480 struct we_softc
*wsc
= (struct we_softc
*)sc
;
488 we_media_init(struct dp8390_softc
*sc
)
490 struct we_softc
*wsc
= (void *) sc
;
491 int defmedia
= IFM_ETHER
;
495 x
= bus_space_read_1(wsc
->sc_asict
, wsc
->sc_asich
, WE790_HWR
);
496 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
, WE790_HWR
,
498 if (bus_space_read_1(wsc
->sc_asict
, wsc
->sc_asich
, WE790_GCR
) &
500 defmedia
|= IFM_10_2
;
502 defmedia
|= IFM_10_5
;
503 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
, WE790_HWR
,
506 x
= bus_space_read_1(wsc
->sc_asict
, wsc
->sc_asich
, WE_IRR
);
508 defmedia
|= IFM_10_2
;
510 defmedia
|= IFM_10_5
;
513 ifmedia_init(&sc
->sc_media
, 0, dp8390_mediachange
, dp8390_mediastatus
);
514 ifmedia_add(&sc
->sc_media
, IFM_ETHER
|IFM_10_2
, 0, NULL
);
515 ifmedia_add(&sc
->sc_media
, IFM_ETHER
|IFM_10_5
, 0, NULL
);
516 ifmedia_set(&sc
->sc_media
, defmedia
);
520 we_mediachange(struct dp8390_softc
*sc
)
524 * Current media is already set up. Just reset the interface
525 * to let the new value take hold. The new media will be
526 * set up in we_init_card() called via dp8390_init().
533 we_mediastatus(struct dp8390_softc
*sc
, struct ifmediareq
*ifmr
)
535 struct ifmedia
*ifm
= &sc
->sc_media
;
538 * The currently selected media is always the active media.
540 ifmr
->ifm_active
= ifm
->ifm_cur
->ifm_media
;
544 we_init_card(struct dp8390_softc
*sc
)
546 struct we_softc
*wsc
= (struct we_softc
*)sc
;
547 struct ifmedia
*ifm
= &sc
->sc_media
;
549 if (wsc
->sc_init_hook
)
550 (*wsc
->sc_init_hook
)(wsc
);
552 we_set_media(wsc
, ifm
->ifm_cur
->ifm_media
);
556 we_set_media(struct we_softc
*wsc
, int media
)
558 struct dp8390_softc
*sc
= &wsc
->sc_dp8390
;
559 bus_space_tag_t asict
= wsc
->sc_asict
;
560 bus_space_handle_t asich
= wsc
->sc_asich
;
561 u_int8_t hwr
, gcr
, irr
;
564 hwr
= bus_space_read_1(asict
, asich
, WE790_HWR
);
565 bus_space_write_1(asict
, asich
, WE790_HWR
,
566 hwr
| WE790_HWR_SWH
);
567 gcr
= bus_space_read_1(asict
, asich
, WE790_GCR
);
568 if (IFM_SUBTYPE(media
) == IFM_10_2
)
569 gcr
|= WE790_GCR_GPOUT
;
571 gcr
&= ~WE790_GCR_GPOUT
;
572 bus_space_write_1(asict
, asich
, WE790_GCR
,
573 gcr
| WE790_GCR_LIT
);
574 bus_space_write_1(asict
, asich
, WE790_HWR
,
575 hwr
& ~WE790_HWR_SWH
);
579 irr
= bus_space_read_1(wsc
->sc_asict
, wsc
->sc_asich
, WE_IRR
);
580 if (IFM_SUBTYPE(media
) == IFM_10_2
)
584 bus_space_write_1(wsc
->sc_asict
, wsc
->sc_asich
, WE_IRR
, irr
);