iPXE
3c5x9.c
Go to the documentation of this file.
1 /**************************************************************************
2 ETHERBOOT - BOOTP/TFTP Bootstrap Program
3 
4 Author: Martin Renters.
5  Date: Mar 22 1995
6 
7  This code is based heavily on David Greenman's if_ed.c driver and
8  Andres Vega Garcia's if_ep.c driver.
9 
10  Copyright (C) 1993-1994, David Greenman, Martin Renters.
11  Copyright (C) 1993-1995, Andres Vega Garcia.
12  Copyright (C) 1995, Serge Babkin.
13  This software may be used, modified, copied, distributed, and sold, in
14  both source and binary form provided that the above copyright and these
15  terms are retained. Under no circumstances are the authors responsible for
16  the proper functioning of this software, nor do the authors assume any
17  responsibility for damages incurred with its use.
18 
19 3c509 support added by Serge Babkin (babkin@hq.icb.chel.su)
20 
21 $Id$
22 
23 ***************************************************************************/
24 
25 FILE_LICENCE ( BSD2 );
26 
27 /* #define EDEBUG */
28 
29 #include <ipxe/ethernet.h>
30 #include "etherboot.h"
31 #include "nic.h"
32 #include <ipxe/isa.h>
33 #include "3c509.h"
34 
35 static enum { none, bnc, utp } connector = none; /* for 3C509 */
36 
37 /**************************************************************************
38 ETH_RESET - Reset adapter
39 ***************************************************************************/
40 void t5x9_disable ( struct nic *nic ) {
41  /* stop card */
45  ;
48  udelay(1000);
55 
56  /*
57  * wait for reset to complete
58  */
60  ;
61 
62  GO_WINDOW(nic->ioaddr,0);
63 
64  /* Disable the card */
66 
67  /* Configure IRQ to none */
69 }
70 
71 static void t509_enable ( struct nic *nic ) {
72  int i;
73 
74  /* Enable the card */
75  GO_WINDOW(nic->ioaddr,0);
77 
78  GO_WINDOW(nic->ioaddr,2);
79 
80  /* Reload the ether_addr. */
81  for (i = 0; i < ETH_ALEN; i++)
82  outb(nic->node_addr[i], nic->ioaddr + EP_W2_ADDR_0 + i);
83 
86 
87  /* Window 1 is operating window */
88  GO_WINDOW(nic->ioaddr,1);
89  for (i = 0; i < 31; i++)
91 
92  /* get rid of stray intr's */
93  outw(ACK_INTR | 0xff, nic->ioaddr + EP_COMMAND);
94 
96 
98 
100  nic->ioaddr + EP_COMMAND);
101 
102  /* configure BNC */
103  if (connector == bnc) {
105  udelay(1000);
106  }
107  /* configure UTP */
108  else if (connector == utp) {
109  GO_WINDOW(nic->ioaddr,4);
111  mdelay(2000); /* Give time for media to negotiate */
112  GO_WINDOW(nic->ioaddr,1);
113  }
114 
115  /* start transceiver and receiver */
118 
119  /* set early threshold for minimal packet length */
122 }
123 
124 static void t509_reset ( struct nic *nic ) {
125  t5x9_disable ( nic );
126  t509_enable ( nic );
127 }
128 
129 /**************************************************************************
130 ETH_TRANSMIT - Transmit a frame
131 ***************************************************************************/
132 static char padmap[] = {
133  0, 3, 2, 1};
134 
135 static void t509_transmit(
136 struct nic *nic,
137 const char *d, /* Destination */
138 unsigned int t, /* Type */
139 unsigned int s, /* size */
140 const char *p) /* Packet */
141 {
142  register unsigned int len;
143  int pad;
144  int status;
145 
146 #ifdef EDEBUG
147  printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
148 #endif
149 
150  /* swap bytes of type */
151  t= htons(t);
152 
153  len=s+ETH_HLEN; /* actual length of packet */
154  pad = padmap[len & 3];
155 
156  /*
157  * The 3c509 automatically pads short packets to minimum ethernet length,
158  * but we drop packets that are too large. Perhaps we should truncate
159  * them instead?
160  */
161  if (len + pad > ETH_FRAME_LEN) {
162  return;
163  }
164 
165  /* drop acknowledgements */
166  while ((status=inb(nic->ioaddr + EP_W1_TX_STATUS)) & TXS_COMPLETE ) {
170  }
171  outb(0x0, nic->ioaddr + EP_W1_TX_STATUS);
172  }
173 
174  while (inw(nic->ioaddr + EP_W1_FREE_TX) < (unsigned short)len + pad + 4)
175  ; /* no room in FIFO */
176 
178  outw(0x0, nic->ioaddr + EP_W1_TX_PIO_WR_1); /* Second dword meaningless */
179 
180  /* write packet */
184  outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, p, s / 2);
185  if (s & 1)
186  outb(*(p+s - 1), nic->ioaddr + EP_W1_TX_PIO_WR_1);
187 
188  while (pad--)
189  outb(0, nic->ioaddr + EP_W1_TX_PIO_WR_1); /* Padding */
190 
191  /* wait for Tx complete */
192  while((inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
193  ;
194 }
195 
196 /**************************************************************************
197 ETH_POLL - Wait for a frame
198 ***************************************************************************/
199 static int t509_poll(struct nic *nic, int retrieve)
200 {
201  /* common variables */
202  /* variables for 3C509 */
203  short status, cst;
204  register short rx_fifo;
205 
206  cst=inw(nic->ioaddr + EP_STATUS);
207 
208 #ifdef EDEBUG
209  if(cst & 0x1FFF)
210  printf("-%hX-",cst);
211 #endif
212 
213  if( (cst & S_RX_COMPLETE)==0 ) {
214  /* acknowledge everything */
215  outw(ACK_INTR| (cst & S_5_INTS), nic->ioaddr + EP_COMMAND);
217 
218  return 0;
219  }
220 
222 #ifdef EDEBUG
223  printf("*%hX*",status);
224 #endif
225 
226  if (status & ERR_RX) {
228  return 0;
229  }
230 
231  rx_fifo = status & RX_BYTES_MASK;
232  if (rx_fifo==0)
233  return 0;
234 
235  if ( ! retrieve ) return 1;
236 
237  /* read packet */
238 #ifdef EDEBUG
239  printf("[l=%d",rx_fifo);
240 #endif
241  insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
242  if(rx_fifo & 1)
243  nic->packet[rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
244  nic->packetlen=rx_fifo;
245 
246  while(1) {
248 #ifdef EDEBUG
249  printf("*%hX*",status);
250 #endif
251  rx_fifo = status & RX_BYTES_MASK;
252  if(rx_fifo>0) {
253  insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
254  if(rx_fifo & 1)
256  nic->packetlen+=rx_fifo;
257 #ifdef EDEBUG
258  printf("+%d",rx_fifo);
259 #endif
260  }
261  if(( status & RX_INCOMPLETE )==0) {
262 #ifdef EDEBUG
263  printf("=%d",nic->packetlen);
264 #endif
265  break;
266  }
267  udelay(1000); /* if incomplete wait 1 ms */
268  }
269  /* acknowledge reception of packet */
272  ;
273 #ifdef EDEBUG
274 {
275  unsigned short type = 0; /* used by EDEBUG */
276  type = (nic->packet[12]<<8) | nic->packet[13];
277  if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
278  nic->packet[5] == 0xFF*ETH_ALEN)
279  printf(",t=%hX,b]",type);
280  else
281  printf(",t=%hX]",type);
282 }
283 #endif
284  return (1);
285 }
286 
287 /**************************************************************************
288 ETH_IRQ - interrupt handling
289 ***************************************************************************/
290 static void t509_irq(struct nic *nic __unused, irq_action_t action __unused)
291 {
292  switch ( action ) {
293  case DISABLE :
294  break;
295  case ENABLE :
296  break;
297  case FORCE :
298  break;
299  }
300 }
301 
302 /*************************************************************************
303  3Com 509 - specific routines
304 **************************************************************************/
305 
306 static int eeprom_rdy ( uint16_t ioaddr ) {
307  int i;
308 
309  for (i = 0; is_eeprom_busy(ioaddr) && i < MAX_EEPROMBUSY; i++);
310  if (i >= MAX_EEPROMBUSY) {
311  /* printf("3c509: eeprom failed to come ready.\n"); */
312  /* memory in EPROM is tight */
313  /* printf("3c509: eeprom busy.\n"); */
314  return (0);
315  }
316  return (1);
317 }
318 
319 /*
320  * get_e: gets a 16 bits word from the EEPROM.
321  */
322 static int get_e ( uint16_t ioaddr, int offset ) {
323  GO_WINDOW(ioaddr,0);
324  if (!eeprom_rdy(ioaddr))
325  return (0xffff);
327  if (!eeprom_rdy(ioaddr))
328  return (0xffff);
329  return (inw(ioaddr + EP_W0_EEPROM_DATA));
330 }
331 
334  .poll = t509_poll,
335  .transmit = t509_transmit,
336  .irq = t509_irq,
337 };
338 
339 /**************************************************************************
340 ETH_PROBE - Look for an adapter
341 ***************************************************************************/
342 int t5x9_probe ( struct nic *nic,
343  uint16_t prod_id_check, uint16_t prod_id_mask ) {
344  uint16_t prod_id;
345  int i,j;
346  unsigned short *p;
347 
348  /* Check product ID */
349  prod_id = get_e ( nic->ioaddr, EEPROM_PROD_ID );
350  if ( ( prod_id & prod_id_mask ) != prod_id_check ) {
351  printf ( "EEPROM Product ID is incorrect (%hx & %hx != %hx)\n",
352  prod_id, prod_id_mask, prod_id_check );
353  return 0;
354  }
355 
356  /* test for presence of connectors */
357  GO_WINDOW(nic->ioaddr,0);
359  j = (inw(nic->ioaddr + EP_W0_ADDRESS_CFG) >> 14) & 0x3;
360 
361  switch(j) {
362  case 0:
363  if (i & IS_UTP) {
364  printf("10baseT\n");
365  connector = utp;
366  } else {
367  printf("10baseT not present\n");
368  return 0;
369  }
370  break;
371  case 1:
372  if (i & IS_AUI) {
373  printf("10base5\n");
374  } else {
375  printf("10base5 not present\n");
376  return 0;
377  }
378  break;
379  case 3:
380  if (i & IS_BNC) {
381  printf("10base2\n");
382  connector = bnc;
383  } else {
384  printf("10base2 not present\n");
385  return 0;
386  }
387  break;
388  default:
389  printf("unknown connector\n");
390  return 0;
391  }
392 
393  /*
394  * Read the station address from the eeprom
395  */
396  p = (unsigned short *) nic->node_addr;
397  for (i = 0; i < ETH_ALEN / 2; i++) {
398  p[i] = htons(get_e(nic->ioaddr,i));
399  GO_WINDOW(nic->ioaddr,2);
400  outw(ntohs(p[i]), nic->ioaddr + EP_W2_ADDR_0 + (i * 2));
401  }
402 
403  DBG ( "Ethernet Address: %s\n", eth_ntoa ( nic->node_addr ) );
404 
405  t509_reset(nic);
406 
408  return 1;
409 
410 }
411 
412 /*
413  * Local variables:
414  * c-basic-offset: 8
415  * End:
416  */
Definition: nic.h:35
#define TXS_UNDERRUN
Definition: 3c509.h:334
FILE_LICENCE(BSD2)
unsigned short uint16_t
Definition: stdint.h:11
#define RX_DISCARD_TOP_PACK
Definition: 3c509.h:225
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition: vsprintf.c:464
uint16_t inw(volatile uint16_t *io_addr)
Read 16-bit word from I/O-mapped device.
#define SET_TX_START_THRESH
Definition: 3c509.h:239
#define EEPROM_PROD_ID
Definition: 3c509.h:90
#define ENABLE_UTP
Definition: 3c509.h:354
#define RX_DISABLE
Definition: 3c509.h:221
#define EP_W1_TX_PIO_WR_1
Definition: 3c509.h:133
#define outw(data, io_addr)
Definition: io.h:319
#define RX_RESET
Definition: 3c509.h:224
#define FIL_GROUP
Definition: 3c509.h:234
#define EP_STATUS
Definition: 3c509.h:111
#define RX_BYTES_MASK
Definition: 3c509.h:381
static void t509_enable(struct nic *nic)
Definition: 3c5x9.c:71
uint8_t type
Type.
Definition: ena.h:16
Definition: 3c5x9.c:35
void outsw(volatile uint16_t *io_addr, const uint16_t *data, unsigned int count)
Write 16-bit words to I/O-mapped device.
#define EP_W1_RX_PIO_RD_1
Definition: 3c509.h:140
#define S_COMMAND_IN_PROGRESS
Definition: 3c509.h:285
#define ERR_RX
Definition: 3c509.h:305
#define EP_W0_EEPROM_COMMAND
Definition: 3c509.h:120
#define is_eeprom_busy(b)
Definition: 3c509.h:74
#define TX_RESET
Definition: 3c509.h:228
static void t509_reset(struct nic *nic)
Definition: 3c5x9.c:124
Definition: 3c5x9.c:35
#define ntohs(value)
Definition: byteswap.h:136
u32 pad[9]
Padding.
Definition: ar9003_mac.h:90
#define EP_W0_RESOURCE_CFG
Definition: 3c509.h:121
static struct nic_operations t509_operations
Definition: 3c5x9.c:332
#define TXS_STATUS_OVERFLOW
Definition: 3c509.h:336
int dummy_connect(struct nic *nic __unused)
Definition: legacy.c:151
#define S_RX_COMPLETE
Definition: 3c509.h:279
#define IS_AUI
Definition: 3c509.h:343
#define EP_W1_FREE_TX
Definition: 3c509.h:135
#define EP_W1_RX_STATUS
Definition: 3c509.h:138
#define IS_BNC
Definition: 3c509.h:344
uint8_t status
Status.
Definition: ena.h:16
#define ACK_INTR
Definition: 3c509.h:247
Definition: 3c5x9.c:35
#define TXS_MAX_COLLISION
Definition: 3c509.h:335
#define TXS_COMPLETE
Definition: 3c509.h:331
static unsigned long ioaddr
Definition: davicom.c:129
unsigned int ioaddr
Definition: nic.h:55
#define EP_W0_ADDRESS_CFG
Definition: 3c509.h:122
#define TX_DISABLE
Definition: 3c509.h:227
#define ETH_HLEN
Definition: if_ether.h:9
Ethernet protocol.
#define ETH_FRAME_LEN
Definition: if_ether.h:11
void udelay(unsigned long usecs)
Delay for a fixed number of microseconds.
Definition: timer.c:60
void t5x9_disable(struct nic *nic)
Definition: 3c5x9.c:40
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
#define SET_RD_0_MASK
Definition: 3c509.h:231
irq_action_t
Definition: nic.h:34
#define START_TRANSCEIVER
Definition: 3c509.h:215
unsigned int packetlen
Definition: nic.h:54
#define SET_RX_FILTER
Definition: 3c509.h:232
int t5x9_probe(struct nic *nic, uint16_t prod_id_check, uint16_t prod_id_mask)
Definition: 3c5x9.c:342
#define SET_INTR_MASK
Definition: 3c509.h:230
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
Definition: ethernet.c:175
#define C_INTR_LATCH
Definition: 3c509.h:248
#define ENABLE_DRQ_IRQ
Definition: 3c509.h:347
#define SET_IRQ(i)
Definition: 3c509.h:361
#define SET_RX_EARLY_THRESH
Definition: 3c509.h:237
static int eeprom_rdy(uint16_t ioaddr)
Definition: 3c5x9.c:306
static int get_e(uint16_t ioaddr, int offset)
Definition: 3c5x9.c:322
#define EP_W0_CONFIG_CTRL
Definition: 3c509.h:123
#define EP_W2_ADDR_0
Definition: 3c509.h:151
void insw(volatile uint16_t *io_addr, uint16_t *data, unsigned int count)
Read 16-bit words from I/O-mapped device.
#define EP_W1_TX_STATUS
Definition: 3c509.h:136
uint8_t inb(volatile uint8_t *io_addr)
Read byte from I/O-mapped device.
#define ETH_ALEN
Definition: if_ether.h:8
#define ETH_ZLEN
Definition: if_ether.h:10
Definition: nic.h:37
Definition: nic.h:49
static char padmap[]
Definition: 3c5x9.c:132
static int t509_poll(struct nic *nic, int retrieve)
Definition: 3c5x9.c:199
#define TX_ENABLE
Definition: 3c509.h:226
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
#define S_5_INTS
Definition: 3c509.h:283
Definition: nic.h:36
unsigned char * packet
Definition: nic.h:53
static enum @7 connector
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:78
unsigned char * node_addr
Definition: nic.h:52
#define FIL_INDIVIDUAL
Definition: 3c509.h:233
#define outb(data, io_addr)
Definition: io.h:309
#define RX_ENABLE
Definition: 3c509.h:223
#define GO_WINDOW(b, x)
Definition: 3c509.h:75
uint32_t len
Length.
Definition: ena.h:14
#define EEPROM_CMD_RD
Definition: 3c509.h:63
static void t509_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p)
Definition: 3c5x9.c:135
#define MAX_EEPROMBUSY
Definition: 3c509.h:53
#define EP_W4_MEDIA_TYPE
Definition: 3c509.h:164
#define FIL_BRDCST
Definition: 3c509.h:235
static void t509_irq(struct nic *nic __unused, irq_action_t action __unused)
Definition: 3c5x9.c:290
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
struct nic_operations * nic_op
Definition: nic.h:50
#define EP_COMMAND
Definition: 3c509.h:109
int(* connect)(struct nic *)
Definition: nic.h:63
#define EP_W0_EEPROM_DATA
Definition: 3c509.h:119
#define htons(value)
Definition: byteswap.h:135
#define STOP_TRANSCEIVER
Definition: 3c509.h:242
#define IS_UTP
Definition: 3c509.h:345
#define RX_INCOMPLETE
Definition: 3c509.h:369