00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 FILE_LICENCE ( BSD2 );
00026
00027
00028
00029 #include <gpxe/ethernet.h>
00030 #include "etherboot.h"
00031 #include "nic.h"
00032 #include <gpxe/isa.h>
00033 #include "3c509.h"
00034
00035 static enum { none, bnc, utp } connector = none;
00036
00037
00038
00039
00040 void t5x9_disable ( struct nic *nic ) {
00041
00042 outw(RX_DISABLE, nic->ioaddr + EP_COMMAND);
00043 outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
00044 while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
00045 ;
00046 outw(TX_DISABLE, nic->ioaddr + EP_COMMAND);
00047 outw(STOP_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
00048 udelay(1000);
00049 outw(RX_RESET, nic->ioaddr + EP_COMMAND);
00050 outw(TX_RESET, nic->ioaddr + EP_COMMAND);
00051 outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
00052 outw(SET_RD_0_MASK, nic->ioaddr + EP_COMMAND);
00053 outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
00054 outw(SET_RX_FILTER, nic->ioaddr + EP_COMMAND);
00055
00056
00057
00058
00059 while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
00060 ;
00061
00062 GO_WINDOW(nic->ioaddr,0);
00063
00064
00065 outw(0, nic->ioaddr + EP_W0_CONFIG_CTRL);
00066
00067
00068 outw(SET_IRQ(0), nic->ioaddr + EP_W0_RESOURCE_CFG);
00069 }
00070
00071 static void t509_enable ( struct nic *nic ) {
00072 int i;
00073
00074
00075 GO_WINDOW(nic->ioaddr,0);
00076 outw(ENABLE_DRQ_IRQ, nic->ioaddr + EP_W0_CONFIG_CTRL);
00077
00078 GO_WINDOW(nic->ioaddr,2);
00079
00080
00081 for (i = 0; i < ETH_ALEN; i++)
00082 outb(nic->node_addr[i], nic->ioaddr + EP_W2_ADDR_0 + i);
00083
00084 outw(RX_RESET, nic->ioaddr + EP_COMMAND);
00085 outw(TX_RESET, nic->ioaddr + EP_COMMAND);
00086
00087
00088 GO_WINDOW(nic->ioaddr,1);
00089 for (i = 0; i < 31; i++)
00090 inb(nic->ioaddr + EP_W1_TX_STATUS);
00091
00092
00093 outw(ACK_INTR | 0xff, nic->ioaddr + EP_COMMAND);
00094
00095 outw(SET_RD_0_MASK | S_5_INTS, nic->ioaddr + EP_COMMAND);
00096
00097 outw(SET_INTR_MASK, nic->ioaddr + EP_COMMAND);
00098
00099 outw(SET_RX_FILTER | FIL_GROUP | FIL_INDIVIDUAL | FIL_BRDCST,
00100 nic->ioaddr + EP_COMMAND);
00101
00102
00103 if (connector == bnc) {
00104 outw(START_TRANSCEIVER, nic->ioaddr + EP_COMMAND);
00105 udelay(1000);
00106 }
00107
00108 else if (connector == utp) {
00109 GO_WINDOW(nic->ioaddr,4);
00110 outw(ENABLE_UTP, nic->ioaddr + EP_W4_MEDIA_TYPE);
00111 sleep(2);
00112 GO_WINDOW(nic->ioaddr,1);
00113 }
00114
00115
00116 outw(RX_ENABLE, nic->ioaddr + EP_COMMAND);
00117 outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
00118
00119
00120 outw(SET_RX_EARLY_THRESH | ETH_ZLEN, nic->ioaddr + EP_COMMAND);
00121 outw(SET_TX_START_THRESH | 16, nic->ioaddr + EP_COMMAND);
00122 }
00123
00124 static void t509_reset ( struct nic *nic ) {
00125 t5x9_disable ( nic );
00126 t509_enable ( nic );
00127 }
00128
00129
00130
00131
00132 static char padmap[] = {
00133 0, 3, 2, 1};
00134
00135 static void t509_transmit(
00136 struct nic *nic,
00137 const char *d,
00138 unsigned int t,
00139 unsigned int s,
00140 const char *p)
00141 {
00142 register unsigned int len;
00143 int pad;
00144 int status;
00145
00146 #ifdef EDEBUG
00147 printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
00148 #endif
00149
00150
00151 t= htons(t);
00152
00153 len=s+ETH_HLEN;
00154 pad = padmap[len & 3];
00155
00156
00157
00158
00159
00160
00161 if (len + pad > ETH_FRAME_LEN) {
00162 return;
00163 }
00164
00165
00166 while ((status=inb(nic->ioaddr + EP_W1_TX_STATUS)) & TXS_COMPLETE ) {
00167 if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
00168 outw(TX_RESET, nic->ioaddr + EP_COMMAND);
00169 outw(TX_ENABLE, nic->ioaddr + EP_COMMAND);
00170 }
00171 outb(0x0, nic->ioaddr + EP_W1_TX_STATUS);
00172 }
00173
00174 while (inw(nic->ioaddr + EP_W1_FREE_TX) < (unsigned short)len + pad + 4)
00175 ;
00176
00177 outw(len, nic->ioaddr + EP_W1_TX_PIO_WR_1);
00178 outw(0x0, nic->ioaddr + EP_W1_TX_PIO_WR_1);
00179
00180
00181 outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
00182 outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
00183 outw(t, nic->ioaddr + EP_W1_TX_PIO_WR_1);
00184 outsw(nic->ioaddr + EP_W1_TX_PIO_WR_1, p, s / 2);
00185 if (s & 1)
00186 outb(*(p+s - 1), nic->ioaddr + EP_W1_TX_PIO_WR_1);
00187
00188 while (pad--)
00189 outb(0, nic->ioaddr + EP_W1_TX_PIO_WR_1);
00190
00191
00192 while((inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
00193 ;
00194 }
00195
00196
00197
00198
00199 static int t509_poll(struct nic *nic, int retrieve)
00200 {
00201
00202
00203 short status, cst;
00204 register short rx_fifo;
00205
00206 cst=inw(nic->ioaddr + EP_STATUS);
00207
00208 #ifdef EDEBUG
00209 if(cst & 0x1FFF)
00210 printf("-%hX-",cst);
00211 #endif
00212
00213 if( (cst & S_RX_COMPLETE)==0 ) {
00214
00215 outw(ACK_INTR| (cst & S_5_INTS), nic->ioaddr + EP_COMMAND);
00216 outw(C_INTR_LATCH, nic->ioaddr + EP_COMMAND);
00217
00218 return 0;
00219 }
00220
00221 status = inw(nic->ioaddr + EP_W1_RX_STATUS);
00222 #ifdef EDEBUG
00223 printf("*%hX*",status);
00224 #endif
00225
00226 if (status & ERR_RX) {
00227 outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
00228 return 0;
00229 }
00230
00231 rx_fifo = status & RX_BYTES_MASK;
00232 if (rx_fifo==0)
00233 return 0;
00234
00235 if ( ! retrieve ) return 1;
00236
00237
00238 #ifdef EDEBUG
00239 printf("[l=%d",rx_fifo);
00240 #endif
00241 insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
00242 if(rx_fifo & 1)
00243 nic->packet[rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
00244 nic->packetlen=rx_fifo;
00245
00246 while(1) {
00247 status = inw(nic->ioaddr + EP_W1_RX_STATUS);
00248 #ifdef EDEBUG
00249 printf("*%hX*",status);
00250 #endif
00251 rx_fifo = status & RX_BYTES_MASK;
00252 if(rx_fifo>0) {
00253 insw(nic->ioaddr + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
00254 if(rx_fifo & 1)
00255 nic->packet[nic->packetlen+rx_fifo-1]=inb(nic->ioaddr + EP_W1_RX_PIO_RD_1);
00256 nic->packetlen+=rx_fifo;
00257 #ifdef EDEBUG
00258 printf("+%d",rx_fifo);
00259 #endif
00260 }
00261 if(( status & RX_INCOMPLETE )==0) {
00262 #ifdef EDEBUG
00263 printf("=%d",nic->packetlen);
00264 #endif
00265 break;
00266 }
00267 udelay(1000);
00268 }
00269
00270 outw(RX_DISCARD_TOP_PACK, nic->ioaddr + EP_COMMAND);
00271 while (inw(nic->ioaddr + EP_STATUS) & S_COMMAND_IN_PROGRESS)
00272 ;
00273 #ifdef EDEBUG
00274 {
00275 unsigned short type = 0;
00276 type = (nic->packet[12]<<8) | nic->packet[13];
00277 if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
00278 nic->packet[5] == 0xFF*ETH_ALEN)
00279 printf(",t=%hX,b]",type);
00280 else
00281 printf(",t=%hX]",type);
00282 }
00283 #endif
00284 return (1);
00285 }
00286
00287
00288
00289
00290 static void t509_irq(struct nic *nic __unused, irq_action_t action __unused)
00291 {
00292 switch ( action ) {
00293 case DISABLE :
00294 break;
00295 case ENABLE :
00296 break;
00297 case FORCE :
00298 break;
00299 }
00300 }
00301
00302
00303
00304
00305
00306 static int eeprom_rdy ( uint16_t ioaddr ) {
00307 int i;
00308
00309 for (i = 0; is_eeprom_busy(ioaddr) && i < MAX_EEPROMBUSY; i++);
00310 if (i >= MAX_EEPROMBUSY) {
00311
00312
00313
00314 return (0);
00315 }
00316 return (1);
00317 }
00318
00319
00320
00321
00322 static int get_e ( uint16_t ioaddr, int offset ) {
00323 GO_WINDOW(ioaddr,0);
00324 if (!eeprom_rdy(ioaddr))
00325 return (0xffff);
00326 outw(EEPROM_CMD_RD | offset, ioaddr + EP_W0_EEPROM_COMMAND);
00327 if (!eeprom_rdy(ioaddr))
00328 return (0xffff);
00329 return (inw(ioaddr + EP_W0_EEPROM_DATA));
00330 }
00331
00332 static struct nic_operations t509_operations = {
00333 .connect = dummy_connect,
00334 .poll = t509_poll,
00335 .transmit = t509_transmit,
00336 .irq = t509_irq,
00337 };
00338
00339
00340
00341
00342 int t5x9_probe ( struct nic *nic,
00343 uint16_t prod_id_check, uint16_t prod_id_mask ) {
00344 uint16_t prod_id;
00345 int i,j;
00346 unsigned short *p;
00347
00348
00349 prod_id = get_e ( nic->ioaddr, EEPROM_PROD_ID );
00350 if ( ( prod_id & prod_id_mask ) != prod_id_check ) {
00351 printf ( "EEPROM Product ID is incorrect (%hx & %hx != %hx)\n",
00352 prod_id, prod_id_mask, prod_id_check );
00353 return 0;
00354 }
00355
00356
00357 GO_WINDOW(nic->ioaddr,0);
00358 i = inw(nic->ioaddr + EP_W0_CONFIG_CTRL);
00359 j = (inw(nic->ioaddr + EP_W0_ADDRESS_CFG) >> 14) & 0x3;
00360
00361 switch(j) {
00362 case 0:
00363 if (i & IS_UTP) {
00364 printf("10baseT\n");
00365 connector = utp;
00366 } else {
00367 printf("10baseT not present\n");
00368 return 0;
00369 }
00370 break;
00371 case 1:
00372 if (i & IS_AUI) {
00373 printf("10base5\n");
00374 } else {
00375 printf("10base5 not present\n");
00376 return 0;
00377 }
00378 break;
00379 case 3:
00380 if (i & IS_BNC) {
00381 printf("10base2\n");
00382 connector = bnc;
00383 } else {
00384 printf("10base2 not present\n");
00385 return 0;
00386 }
00387 break;
00388 default:
00389 printf("unknown connector\n");
00390 return 0;
00391 }
00392
00393
00394
00395
00396 p = (unsigned short *) nic->node_addr;
00397 for (i = 0; i < ETH_ALEN / 2; i++) {
00398 p[i] = htons(get_e(nic->ioaddr,i));
00399 GO_WINDOW(nic->ioaddr,2);
00400 outw(ntohs(p[i]), nic->ioaddr + EP_W2_ADDR_0 + (i * 2));
00401 }
00402
00403 DBG ( "Ethernet Address: %s\n", eth_ntoa ( nic->node_addr ) );
00404
00405 t509_reset(nic);
00406
00407 nic->nic_op = &t509_operations;
00408 return 1;
00409
00410 }
00411
00412
00413
00414
00415
00416