|
|
1.1 root 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 ([email protected])
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 */
42: outw(RX_DISABLE, nic->ioaddr + EP_COMMAND);
43: outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
44: while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
45: ;
46: outw(TX_DISABLE, nic->ioaddr + EP_COMMAND);
47: outw(STOP_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
48: udelay(1000);
49: outw(RX_RESET, nic->ioaddr + EP_COMMAND);
50: outw(TX_RESET, nic->ioaddr + EP_COMMAND);
51: outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
52: outw(SET_RD_0_MASK, nic->ioaddr + EP_COMMAND);
53: outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
54: outw(SET_RX_FILTER, nic->ioaddr + EP_COMMAND);
55:
56: /*
57: * wait for reset to complete
58: */
59: while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
60: ;
61:
62: GO_WINDOW(nic->ioaddr,0);
63:
64: /* Disable the card */
65: outw(0, nic->ioaddr + EP_W0_CONFIG_CTRL);
66:
67: /* Configure IRQ to none */
68: outw(SET_IRQ(0), nic->ioaddr + EP_W0_RESOURCE_CFG);
69: }
70:
71: static void t509_enable ( struct nic *nic ) {
72: int i;
73:
74: /* Enable the card */
75: GO_WINDOW(nic->ioaddr,0);
76: outw(ENABLE_DRQ_IRQ, nic->ioaddr + EP_W0_CONFIG_CTRL);
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:
84: outw(RX_RESET, nic->ioaddr + EP_COMMAND);
85: outw(TX_RESET, nic->ioaddr + EP_COMMAND);
86:
87: /* Window 1 is operating window */
88: GO_WINDOW(nic->ioaddr,1);
89: for (i = 0; i < 31; i++)
90: inb(nic->ioaddr + EP_W1_TX_STATUS);
91:
92: /* get rid of stray intr's */
93: outw(ACK_INTR | 0xff, nic->ioaddr + EP_COMMAND);
94:
95: outw(SET_RD_0_MASK | S_5_INTS, nic->ioaddr + EP_COMMAND);
96:
97: outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
98:
99: outw(SET_RX_FILTER | FIL_GROUP | FIL_INDIVIDUAL | FIL_BRDCST,
100: nic->ioaddr + EP_COMMAND);
101:
102: /* configure BNC */
103: if (connector == bnc) {
104: outw(START_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
105: udelay(1000);
106: }
107: /* configure UTP */
108: else if (connector == utp) {
109: GO_WINDOW(nic->ioaddr,4);
110: outw(ENABLE_UTP, nic->ioaddr + EP_W4_MEDIA_TYPE);
111: sleep(2); /* Give time for media to negotiate */
112: GO_WINDOW(nic->ioaddr,1);
113: }
114:
115: /* start transceiver and receiver */
116: outw(RX_ENABLE, nic->ioaddr + EP_COMMAND);
117: outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
118:
119: /* set early threshold for minimal packet length */
120: outw(SET_RX_EARLY_THRESH | ETH_ZLEN, nic->ioaddr + EP_COMMAND);
121: outw(SET_TX_START_THRESH | 16, nic->ioaddr + EP_COMMAND);
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 ) {
167: if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
168: outw(TX_RESET, nic->ioaddr + EP_COMMAND);
169: outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
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:
177: outw(len, nic->ioaddr + EP_W1_TX_PIO_WR_1);
178: outw(0x0, nic->ioaddr + EP_W1_TX_PIO_WR_1); /* Second dword meaningless */
179:
180: /* write packet */
181: outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
182: outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
183: outw(t, nic->ioaddr + EP_W1_TX_PIO_WR_1);
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);
216: outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
217:
218: return 0;
219: }
220:
221: status = inw(nic->ioaddr + EP_W1_RX_STATUS);
222: #ifdef EDEBUG
223: printf("*%hX*",status);
224: #endif
225:
226: if (status & ERR_RX) {
227: outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
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) {
247: status = inw(nic->ioaddr + EP_W1_RX_STATUS);
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)
255: nic->packet[nic->packetlen+rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_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 */
270: outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
271: while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
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);
326: outw(EEPROM_CMD_RD | offset, ioaddr + EP_W0_EEPROM_COMMAND);
327: if (!eeprom_rdy(ioaddr))
328: return (0xffff);
329: return (inw(ioaddr + EP_W0_EEPROM_DATA));
330: }
331:
332: static struct nic_operations t509_operations = {
333: .connect = dummy_connect,
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);
358: i = inw(nic->ioaddr + EP_W0_CONFIG_CTRL);
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:
407: nic->nic_op = &t509_operations;
408: return 1;
409:
410: }
411:
412: /*
413: * Local variables:
414: * c-basic-offset: 8
415: * End:
416: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.