2
* 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot
4
* Copyright (C) 2000 Shusuke Nisiyama <shu@athena.qe.eng.hokudai.ac.jp>
8
* This software may be used, modified, copied, distributed, and sold, in
9
* both source and binary form provided that the above copyright and these
10
* terms are retained. Under no circumstances are the authors responsible for
11
* the proper functioning of this software, nor do the authors assume any
12
* responsibility for damages incurred with its use.
14
* This code is based on Martin Renters' etherboot-4.4.3 3c509.c and
15
* Herb Peyerl's FreeBSD 3.4-RELEASE if_vx.c driver.
17
* Copyright (C) 1993-1994, David Greenman, Martin Renters.
18
* Copyright (C) 1993-1995, Andres Vega Garcia.
19
* Copyright (C) 1995, Serge Babkin.
21
* Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
27
#include "etherboot.h"
33
static unsigned short eth_nic_base, eth_asic_base;
34
static unsigned short vx_connector, vx_connectors;
36
static struct connector_entry {
39
} conn_tab[VX_CONNECTORS] = {
40
#define CONNECTOR_UTP 0
42
#define CONNECTOR_AUI 1
46
#define CONNECTOR_BNC 3
48
#define CONNECTOR_TX 4
50
#define CONNECTOR_FX 5
52
#define CONNECTOR_MII 6
57
static void vxgetlink(void);
58
static void vxsetlink(void);
60
#define udelay(n) waiton_timer2(((n)*TICKS_PER_MS)/1000)
62
/**************************************************************************
63
ETH_RESET - Reset adapter
64
***************************************************************************/
65
static void t595_reset(struct nic *nic)
69
/***********************************************************
71
*************************************************************/
74
outw(RX_DISABLE, BASE + VX_COMMAND);
75
outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
77
outw(TX_DISABLE, BASE + VX_COMMAND);
78
outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
80
outw(RX_RESET, BASE + VX_COMMAND);
82
outw(TX_RESET, BASE + VX_COMMAND);
84
outw(C_INTR_LATCH, BASE + VX_COMMAND);
85
outw(SET_RD_0_MASK, BASE + VX_COMMAND);
86
outw(SET_INTR_MASK, BASE + VX_COMMAND);
87
outw(SET_RX_FILTER, BASE + VX_COMMAND);
96
/* Disable the card */
97
/* outw(0, BASE + VX_W0_CONFIG_CTRL); */
99
/* Configure IRQ to none */
100
/* outw(SET_IRQ(0), BASE + VX_W0_RESOURCE_CFG); */
102
/* Enable the card */
103
/* outw(ENABLE_DRQ_IRQ, BASE + VX_W0_CONFIG_CTRL); */
107
/* Reload the ether_addr. */
108
for (i = 0; i < ETH_ALEN; i++)
109
outb(nic->node_addr[i], BASE + VX_W2_ADDR_0 + i);
111
outw(RX_RESET, BASE + VX_COMMAND);
113
outw(TX_RESET, BASE + VX_COMMAND);
116
/* Window 1 is operating window */
118
for (i = 0; i < 31; i++)
119
inb(BASE + VX_W1_TX_STATUS);
121
outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
122
S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
123
outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
124
S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
127
* Attempt to get rid of any stray interrupts that occured during
128
* configuration. On the i386 this isn't possible because one may
129
* already be queued. However, a single stray interrupt is
133
outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
135
outw(SET_RX_FILTER | FIL_INDIVIDUAL |
136
FIL_BRDCST, BASE + VX_COMMAND);
143
j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
144
outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
146
outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
150
/* start tranciever and receiver */
151
outw(RX_ENABLE, BASE + VX_COMMAND);
152
outw(TX_ENABLE, BASE + VX_COMMAND);
156
/**************************************************************************
157
ETH_TRANSMIT - Transmit a frame
158
***************************************************************************/
159
static char padmap[] = {
162
static void t595_transmit(
164
const char *d, /* Destination */
165
unsigned int t, /* Type */
166
unsigned int s, /* size */
167
const char *p) /* Packet */
174
printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
177
/* swap bytes of type */
180
len=s+ETH_HLEN; /* actual length of packet */
181
pad = padmap[len & 3];
184
* The 3c595 automatically pads short packets to minimum ethernet length,
185
* but we drop packets that are too large. Perhaps we should truncate
188
if (len + pad > ETH_FRAME_LEN) {
192
/* drop acknowledgements */
193
while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
194
if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
195
outw(TX_RESET, BASE + VX_COMMAND);
196
outw(TX_ENABLE, BASE + VX_COMMAND);
199
outb(0x0, BASE + VX_W1_TX_STATUS);
202
while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
203
/* no room in FIFO */
206
outw(len, BASE + VX_W1_TX_PIO_WR_1);
207
outw(0x0, BASE + VX_W1_TX_PIO_WR_1); /* Second dword meaningless */
210
outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
211
outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
212
outw(t, BASE + VX_W1_TX_PIO_WR_1);
213
outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2);
215
outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1);
218
outb(0, BASE + VX_W1_TX_PIO_WR_1); /* Padding */
220
/* wait for Tx complete */
221
while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
225
/**************************************************************************
226
ETH_POLL - Wait for a frame
227
***************************************************************************/
228
static int t595_poll(struct nic *nic)
230
/* common variables */
231
unsigned short type = 0; /* used by EDEBUG */
232
/* variables for 3C595 */
234
register short rx_fifo;
236
cst=inw(BASE + VX_STATUS);
243
if( (cst & S_RX_COMPLETE)==0 ) {
244
/* acknowledge everything */
245
outw(ACK_INTR | cst, BASE + VX_COMMAND);
246
outw(C_INTR_LATCH, BASE + VX_COMMAND);
251
status = inw(BASE + VX_W1_RX_STATUS);
253
printf("*%hX*",status);
256
if (status & ERR_RX) {
257
outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
261
rx_fifo = status & RX_BYTES_MASK;
267
printf("[l=%d",rx_fifo);
269
insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
271
nic->packet[rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
272
nic->packetlen=rx_fifo;
275
status = inw(BASE + VX_W1_RX_STATUS);
277
printf("*%hX*",status);
279
rx_fifo = status & RX_BYTES_MASK;
282
insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
284
nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
285
nic->packetlen+=rx_fifo;
287
printf("+%d",rx_fifo);
290
if(( status & RX_INCOMPLETE )==0) {
292
printf("=%d",nic->packetlen);
299
/* acknowledge reception of packet */
300
outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
301
while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS);
303
type = (nic->packet[12]<<8) | nic->packet[13];
304
if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
305
nic->packet[5] == 0xFF*ETH_ALEN)
306
printf(",t=%hX,b]",type);
308
printf(",t=%hX]",type);
314
/*************************************************************************
315
3Com 595 - specific routines
316
**************************************************************************/
323
for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++)
325
if (i >= MAX_EEPROMBUSY) {
326
/* printf("3c595: eeprom failed to come ready.\n"); */
327
printf("3c595: eeprom is busy.\n"); /* memory in EPROM is tight */
334
* get_e: gets a 16 bits word from the EEPROM. we must have set the window
343
outw(EEPROM_CMD_RD | offset, BASE + VX_W0_EEPROM_COMMAND);
346
return (inw(BASE + VX_W0_EEPROM_DATA));
355
vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
356
for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
357
if (vx_connectors & conn_tab[k].bit) {
361
printf(conn_tab[k].name);
365
if (vx_connectors == 0) {
366
printf("no connectors!");
370
vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG)
371
& INTERNAL_CONNECTOR_MASK)
372
>> INTERNAL_CONNECTOR_BITS;
373
if (vx_connector & 0x10) {
374
vx_connector &= 0x0f;
375
printf("[*%s*]", conn_tab[vx_connector].name);
376
printf(": disable 'auto select' with DOS util!");
378
printf("[*%s*]", conn_tab[vx_connector].name);
386
char *reason, *warning;
387
static short prev_flags;
388
static char prev_conn = -1;
390
if (prev_conn == -1) {
391
prev_conn = vx_connector;
394
i = vx_connector; /* default in EEPROM */
398
if ((vx_connectors & conn_tab[vx_connector].bit) == 0) {
399
warning = "strange connector type in EEPROM.";
405
printf("warning: %s\n", warning);
407
printf("selected %s. (%s)\n", conn_tab[i].name, reason);
409
/* Set the selected connector. */
411
j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
412
outl(j | (i <<INTERNAL_CONNECTOR_BITS), BASE + VX_W3_INTERNAL_CFG);
414
/* First, disable all. */
415
outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
418
outw(0, BASE + VX_W4_MEDIA_TYPE);
420
/* Second, enable the selected one. */
424
outw(ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
427
outw(START_TRANSCEIVER,BASE + VX_COMMAND);
433
outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
435
default: /* AUI and MII fall here */
441
static void t595_disable(struct nic *nic)
443
outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
446
outw(0, BASE + VX_W4_MEDIA_TYPE);
450
/**************************************************************************
451
ETH_PROBE - Look for an adapter
452
***************************************************************************/
453
struct nic *t595_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci)
458
if (probeaddrs == 0 || probeaddrs[0] == 0)
460
/* eth_nic_base = probeaddrs[0] & ~3; */
461
eth_nic_base = pci->ioaddr;
464
outw(GLOBAL_RESET, BASE + VX_COMMAND);
471
for (i = 0; i < (EEPROMSIZE/2); i++) {
472
printf("%hX:", get_e(i));
477
* Read the station address from the eeprom
479
p = (unsigned short *) nic->node_addr;
480
for (i = 0; i < 3; i++) {
482
p[i] = htons(get_e(EEPROM_OEM_ADDR_0 + i));
484
outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2));
487
printf("Ethernet address: %!\n", nic->node_addr);
490
nic->reset = t595_reset;
491
nic->poll = t595_poll;
492
nic->transmit = t595_transmit;
493
nic->disable = t595_disable;