1 /* $NetBSD: 3c90xb.c,v 1.14 2008/12/14 18:46:33 christos Exp $ */
5 * Matthias Drochner. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/types.h>
30 #include <machine/pio.h>
32 struct mbuf
; /* XXX */
33 typedef int bus_dmamap_t
; /* XXX */
34 #include <dev/ic/elink3reg.h>
35 #include <dev/ic/elinkxlreg.h>
37 #include <lib/libsa/stand.h>
42 #if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
43 #include <lib/libkern/libkern.h>
49 #define RECVBUF_SIZE 1600 /* struct ex_upd + packet */
53 static pcihdl_t mytag
;
54 static char recvbuf
[RECVBUF_SIZE
];
55 #define RECVBUF_PHYS vtophys(recvbuf)
56 #define RECVBUF_VIRT ((void *)recvbuf)
57 static struct ex_dpd sndbuf
;
58 #define SNDBUF_PHYS vtophys(&sndbuf)
59 #define SNDBUF_VIRT ((void *)&sndbuf)
61 #else /* !standalone, userspace testing environment */
63 #define PCI_MODE1_ENABLE 0x80000000UL
66 static pcihdl_t mytag
= PCI_MODE1_ENABLE
| (PCIBUSNO
<< 16) | (PCIDEVNO
<< 11);
68 extern void *mapmem(int, int);
69 void *dmamem
; /* virtual */
70 #define DMABASE 0x3ffd800
72 #define RECVBUF_PHYS DMABASE
73 #define RECVBUF_VIRT dmamem
74 #define SNDBUF_PHYS (DMABASE + RECVBUF_SIZE)
75 #define SNDBUF_VIRT ((void *)(((char *)dmamem) + RECVBUF_SIZE))
77 #endif /* _STANDALONE */
80 #define CSR_READ_1(reg) inb(iobase + (reg))
81 #define CSR_READ_2(reg) inw(iobase + (reg))
82 #define CSR_READ_4(reg) inl(iobase + (reg))
83 #define CSR_WRITE_1(reg, val) outb(iobase + (reg), val)
84 #define CSR_WRITE_2(reg, val) outw(iobase + (reg), val)
85 #define CSR_WRITE_4(reg, val) outl(iobase + (reg), val)
88 #define GO_WINDOW(x) CSR_WRITE_2(ELINK_COMMAND, WINDOW_SELECT | x)
91 static u_char myethaddr
[6];
92 unsigned ether_medium
;
98 {0x9005, 0}, /* 3c900b Combo */
99 {0x9055, 1}, /* 3c905b TP */
100 {0x9058, 0}, /* 3c905b Combo */
104 static struct mtabentry
{
105 int address_cfg
; /* configured connector */
106 int config_bit
; /* connector present */
108 } mediatab
[] = { /* indexed by media type - etherdrv.h */
109 {ELINKMEDIA_10BASE_2
, ELINK_PCI_BNC
, "BNC"},
110 {ELINKMEDIA_10BASE_T
, ELINK_PCI_10BASE_T
, "UTP"},
111 {ELINKMEDIA_AUI
, ELINK_PCI_AUI
, "AUI"},
112 {ELINKMEDIA_MII
, ELINK_PCI_100BASE_MII
, "MII"},
113 {ELINKMEDIA_100BASE_TX
, ELINK_PCI_100BASE_TX
, "100TX"},
116 #if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
117 static struct btinfo_netif bi_netif
;
120 #define ex_waitcmd() \
122 while (CSR_READ_2(ELINK_STATUS) & COMMAND_IN_PROGRESS) \
127 uint16_t ex_read_eeprom(int);
128 static int ex_eeprom_busy(void);
130 void ex_set_media(void);
135 CSR_WRITE_2(ELINK_COMMAND
, GLOBAL_RESET
);
142 * XXX what to do if EEPROM doesn't unbusy?
145 ex_read_eeprom(int offset
)
150 if (ex_eeprom_busy())
152 CSR_WRITE_1(ELINK_W0_EEPROM_COMMAND
, READ_EEPROM
| (offset
& 0x3f));
153 if (ex_eeprom_busy())
155 data
= CSR_READ_2(ELINK_W0_EEPROM_DATA
);
166 if (!(CSR_READ_2(ELINK_W0_EEPROM_COMMAND
) & EEPROM_BUSY
))
170 printf("\nex: eeprom stays busy.\n");
186 * Set the station address and clear the station mask. The latter
187 * is needed for 90x cards, 0 is the default for 90xB cards.
190 for (i
= 0; i
< 6; i
++) {
191 CSR_WRITE_1(ELINK_W2_ADDR_0
+ i
,
193 CSR_WRITE_1(ELINK_W2_RECVMASK_0
+ i
, 0);
198 CSR_WRITE_2(ELINK_COMMAND
, RX_RESET
);
200 CSR_WRITE_2(ELINK_COMMAND
, TX_RESET
);
203 CSR_WRITE_2(ELINK_COMMAND
, SET_INTR_MASK
| 0); /* disable */
204 CSR_WRITE_2(ELINK_COMMAND
, ACK_INTR
| 0xff);
208 CSR_WRITE_2(ELINK_COMMAND
, SET_RX_FILTER
| FIL_INDIVIDUAL
| FIL_BRDCST
);
210 CSR_WRITE_4(ELINK_DNLISTPTR
, 0);
211 CSR_WRITE_2(ELINK_COMMAND
, TX_ENABLE
);
213 CSR_WRITE_4(ELINK_UPLISTPTR
, RECVBUF_PHYS
);
214 CSR_WRITE_2(ELINK_COMMAND
, RX_ENABLE
);
215 CSR_WRITE_2(ELINK_COMMAND
, ELINK_UPUNSTALL
);
223 int config0
, config1
;
225 CSR_WRITE_2(ELINK_W3_MAC_CONTROL
, 0);
227 if (ether_medium
== ETHERMEDIUM_MII
)
231 CSR_WRITE_2(ELINK_W4_MEDIA_TYPE
, 0);
232 CSR_WRITE_2(ELINK_COMMAND
, STOP_TRANSCEIVER
);
235 switch (ether_medium
) {
236 case ETHERMEDIUM_UTP
:
237 CSR_WRITE_2(ELINK_W4_MEDIA_TYPE
,
238 JABBER_GUARD_ENABLE
| LINKBEAT_ENABLE
);
240 case ETHERMEDIUM_BNC
:
241 CSR_WRITE_2(ELINK_COMMAND
, START_TRANSCEIVER
);
244 case ETHERMEDIUM_AUI
:
245 CSR_WRITE_2(ELINK_W4_MEDIA_TYPE
, SQE_ENABLE
);
248 case ETHERMEDIUM_100TX
:
249 CSR_WRITE_2(ELINK_W4_MEDIA_TYPE
, LINKBEAT_ENABLE
);
256 config0
= CSR_READ_2(ELINK_W3_INTERNAL_CONFIG
);
257 config1
= CSR_READ_2(ELINK_W3_INTERNAL_CONFIG
+ 2);
259 config1
= config1
& ~CONFIG_MEDIAMASK
;
260 config1
|= (mediatab
[ether_medium
].address_cfg
261 << CONFIG_MEDIAMASK_SHIFT
);
263 CSR_WRITE_2(ELINK_W3_INTERNAL_CONFIG
, config0
);
264 CSR_WRITE_2(ELINK_W3_INTERNAL_CONFIG
+ 2, config1
);
273 /* test for presence of connectors */
275 i
= CSR_READ_1(ELINK_W3_RESET_OPTIONS
);
276 j
= (CSR_READ_2(ELINK_W3_INTERNAL_CONFIG
+ 2) & CONFIG_MEDIAMASK
)
277 >> CONFIG_MEDIAMASK_SHIFT
;
280 for (ether_medium
= 0, m
= mediatab
;
281 ether_medium
< sizeof(mediatab
) / sizeof(mediatab
[0]);
282 ether_medium
++, m
++) {
283 if (j
== m
->address_cfg
) {
284 if (!(i
& m
->config_bit
)) {
285 printf("%s not present\n", m
->name
);
288 printf("using %s\n", m
->name
);
292 printf("unknown connector\n");
298 EtherInit(unsigned char *myadr
)
302 volatile struct ex_upd
*upd
;
308 printf("pcicheck failed\n");
312 pcicfgread(&mytag
, 0, &id
);
314 for (excard
= &excards
[0]; excard
->did
!= -1; excard
++) {
316 if (pcifinddev(0x10b7, excard
->did
, &mytag
) == 0)
319 if (id
== (0x10b7 | (excard
->did
<< 16)))
327 pcicfgread(&mytag
, 0x10, &iobase
);
331 dmamem
= mapmem(DMABASE
, DMASIZE
);
336 /* enable bus mastering in PCI command register */
337 if (pcicfgread(&mytag
, 0x04, (int *)&pcicsr
)
338 || pcicfgwrite(&mytag
, 0x04, pcicsr
| 4)) {
339 printf("cannot enable DMA\n");
346 ether_medium
= ETHERMEDIUM_MII
;
349 if (ether_medium
< 0)
353 val
= ex_read_eeprom(EEPROM_OEM_ADDR0
);
354 myethaddr
[0] = val
>> 8;
355 myethaddr
[1] = val
& 0xff;
356 val
= ex_read_eeprom(EEPROM_OEM_ADDR1
);
357 myethaddr
[2] = val
>> 8;
358 myethaddr
[3] = val
& 0xff;
359 val
= ex_read_eeprom(EEPROM_OEM_ADDR2
);
360 myethaddr
[4] = val
>> 8;
361 myethaddr
[5] = val
& 0xff;
362 memcpy(myadr
, myethaddr
, 6);
365 upd
->upd_nextptr
= RECVBUF_PHYS
;
366 upd
->upd_pktstatus
= 1500;
367 upd
->upd_frags
[0].fr_addr
= RECVBUF_PHYS
+ 100;
368 upd
->upd_frags
[0].fr_len
= 1500 | EX_FR_LAST
;
372 #if defined(_STANDALONE) && !defined(SUPPORT_NO_NETBSD)
373 strncpy(bi_netif
.ifname
, "ex", sizeof(bi_netif
.ifname
));
374 bi_netif
.bus
= BI_BUS_PCI
;
375 bi_netif
.addr
.tag
= mytag
;
377 BI_ADD(&bi_netif
, BTINFO_NETIF
, sizeof(bi_netif
));
387 * Issue software reset
389 CSR_WRITE_2(ELINK_COMMAND
, RX_DISABLE
);
390 CSR_WRITE_2(ELINK_COMMAND
, TX_DISABLE
);
391 CSR_WRITE_2(ELINK_COMMAND
, STOP_TRANSCEIVER
);
392 CSR_WRITE_2(ELINK_COMMAND
, INTR_LATCH
);
396 EtherSend(char *pkt
, int len
)
398 volatile struct ex_dpd
*dpd
;
403 dpd
->dpd_nextptr
= 0;
406 dpd
->dpd_frags
[0].fr_addr
= vtophys(pkt
);
408 memcpy(SNDBUF_VIRT
+ 100, pkt
, len
);
409 dpd
->dpd_frags
[0].fr_addr
= SNDBUF_PHYS
+ 100;
411 dpd
->dpd_frags
[0].fr_len
= len
| EX_FR_LAST
;
413 CSR_WRITE_4(ELINK_DNLISTPTR
, SNDBUF_PHYS
);
414 CSR_WRITE_2(ELINK_COMMAND
, ELINK_DNUNSTALL
);
417 while (!(dpd
->dpd_fsh
& 0x00010000)) {
419 printf("3c90xb: send timeout\n");
429 EtherReceive(char *pkt
, int maxlen
)
431 volatile struct ex_upd
*upd
;
436 if (!(upd
->upd_pktstatus
& ~EX_UPD_PKTLENMASK
))
439 len
= upd
->upd_pktstatus
& EX_UPD_PKTLENMASK
;
443 memcpy(pkt
, RECVBUF_VIRT
+ 100, len
);
445 upd
->upd_pktstatus
= 1500;
446 CSR_WRITE_2(ELINK_COMMAND
, ELINK_UPUNSTALL
);