1 /* 2 ** File: 3c501.c Jan. 14, 1997 3 ** 4 ** Author: Giovanni Falzoni <gfalzoni@inwind.it> 5 ** 6 ** This file contains specific implementation of the ethernet 7 ** device driver for 3Com Etherlink (3c501) boards. This is a 8 ** very old board and its performances are very poor for today 9 ** network environments. 10 */ 11 12 #include <minix/drivers.h> 13 #include <minix/netdriver.h> 14 #include "dp.h" 15 16 #if (ENABLE_3C501 == 1) 17 18 #include "3c501.h" 19 20 static unsigned char StationAddress[SA_ADDR_LEN] = {0, 0, 0, 0, 0, 0,}; 21 static buff_t *TxBuff = NULL; 22 23 /* 24 ** Name: el1_getstats 25 ** Function: Reads statistics counters from board. 26 **/ 27 static void el1_getstats(dpeth_t * dep) 28 { 29 30 /* Nothing to do */ 31 } 32 33 /* 34 ** Name: el1_reset 35 ** Function: Reset function specific for Etherlink hardware. 36 */ 37 static void el1_reset(dpeth_t * dep) 38 { 39 unsigned int ix; 40 41 for (ix = 0; ix < 8; ix += 1) /* Resets the board */ 42 outb_el1(dep, EL1_CSR, ECSR_RESET); 43 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); 44 45 /* Set Ethernet Address on controller */ 46 outb_el1(dep, EL1_CSR, ECSR_LOOP); /* Loopback mode */ 47 for (ix = EL1_ADDRESS; ix < SA_ADDR_LEN; ix += 1) 48 outb_el1(dep, ix, StationAddress[ix]); 49 50 /* Enable DMA/Interrupt, gain control of Buffer */ 51 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); 52 /* Clear RX packet area */ 53 outw_el1(dep, EL1_RECVPTR, 0); 54 /* Enable transmit/receive configuration and flush pending interrupts */ 55 outb_el1(dep, EL1_XMIT, EXSR_IDLE | EXSR_16JAM | EXSR_JAM | EXSR_UNDER); 56 outb_el1(dep, EL1_RECV, dep->de_recv_mode); 57 inb_el1(dep, EL1_RECV); 58 inb_el1(dep, EL1_XMIT); 59 dep->de_flags &= NOT(DEF_XMIT_BUSY); 60 } 61 62 /* 63 ** Name: el1_dumpstats 64 ** Function: Dumps counter on screen (support for console display). 65 */ 66 static void el1_dumpstats(dpeth_t * UNUSED(dep)) 67 { 68 69 } 70 71 /* 72 ** Name: el1_mode_init 73 ** Function: Initializes receicer mode 74 */ 75 static void el1_mode_init(dpeth_t * dep) 76 { 77 78 if (dep->de_flags & DEF_BROAD) { 79 dep->de_recv_mode = ERSR_BROAD | ERSR_RMASK; 80 81 } else if (dep->de_flags & DEF_PROMISC) { 82 dep->de_recv_mode = ERSR_ALL | ERSR_RMASK; 83 84 } else if (dep->de_flags & DEF_MULTI) { 85 dep->de_recv_mode = ERSR_MULTI | ERSR_RMASK; 86 87 } else { 88 dep->de_recv_mode = ERSR_NONE | ERSR_RMASK; 89 } 90 outb_el1(dep, EL1_RECV, dep->de_recv_mode); 91 inb_el1(dep, EL1_RECV); 92 } 93 94 /* 95 ** Name: el1_recv 96 ** Function: Receive function. Called from interrupt handler to 97 ** unload recv. buffer or from main (packet to client) 98 */ 99 static ssize_t el1_recv(dpeth_t *dep, struct netdriver_data *data, size_t max) 100 { 101 buff_t *rxptr; 102 size_t size; 103 104 if ((rxptr = dep->de_recvq_head) == NULL) 105 return SUSPEND; 106 107 /* Remove buffer from queue and free buffer */ 108 if (dep->de_recvq_tail == dep->de_recvq_head) 109 dep->de_recvq_head = dep->de_recvq_tail = NULL; 110 else 111 dep->de_recvq_head = rxptr->next; 112 113 /* Copy buffer to user area */ 114 size = MIN((size_t)rxptr->size, max); 115 116 netdriver_copyout(data, 0, rxptr->buffer, size); 117 118 /* Return buffer to the idle pool */ 119 free_buff(dep, rxptr); 120 121 return size; 122 } 123 124 /* 125 ** Name: el1_send 126 ** Function: Send function. 127 */ 128 static int el1_send(dpeth_t *dep, struct netdriver_data *data, size_t size) 129 { 130 buff_t *txbuff; 131 clock_t now; 132 133 if (dep->de_flags & DEF_XMIT_BUSY) { 134 now = getticks(); 135 if ((now - dep->de_xmit_start) > 4) { 136 /* Transmitter timed out */ 137 DEBUG(printf("3c501: transmitter timed out ... \n")); 138 netdriver_stat_oerror(1); 139 dep->de_flags &= NOT(DEF_XMIT_BUSY); 140 /* Try sending anyway. */ 141 } else 142 return SUSPEND; 143 } 144 145 /* Since we may have to retransmit, we need a local copy. */ 146 if ((txbuff = alloc_buff(dep, size + sizeof(buff_t))) == NULL) 147 panic("out of memory"); 148 149 /* Fill transmit buffer from user area */ 150 txbuff->next = NULL; 151 txbuff->size = size; 152 153 netdriver_copyin(data, 0, txbuff->buffer, size); 154 155 /* Save for retransmission */ 156 TxBuff = txbuff; 157 dep->de_flags |= DEF_XMIT_BUSY; 158 159 /* Setup board for packet loading */ 160 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); 161 inb_el1(dep, EL1_RECV); /* Clears any spurious interrupt */ 162 inb_el1(dep, EL1_XMIT); 163 outw_el1(dep, EL1_RECVPTR, 0); /* Clears RX packet area */ 164 165 /* Loads packet */ 166 outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size)); 167 outsb(dep->de_data_port, txbuff->buffer, size); 168 /* Starts transmitter */ 169 outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - size)); 170 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); /* There it goes... */ 171 172 dep->de_xmit_start = getticks(); 173 174 return OK; 175 } 176 177 /* 178 ** Name: el1_stop 179 ** Function: Stops board and disable interrupts. 180 */ 181 static void el1_stop(dpeth_t * dep) 182 { 183 int ix; 184 185 DEBUG(printf("%s: stopping Etherlink ....\n", netdriver_name())); 186 for (ix = 0; ix < 8; ix += 1) /* Reset board */ 187 outb_el1(dep, EL1_CSR, ECSR_RESET); 188 outb_el1(dep, EL1_CSR, ECSR_SYS); 189 sys_irqdisable(&dep->de_hook); /* Disable interrupt */ 190 } 191 192 /* 193 ** Name: el1_interrupt 194 ** Function: Interrupt handler. Acknwledges transmit interrupts 195 ** or unloads receive buffer to memory queue. 196 */ 197 static void el1_interrupt(dpeth_t * dep) 198 { 199 u16_t csr, isr; 200 int pktsize; 201 buff_t *rxptr; 202 203 csr = inb_el1(dep, EL1_CSR); 204 if ((csr & ECSR_XMIT) && (dep->de_flags & DEF_XMIT_BUSY)) { 205 206 /* Got a transmit interrupt */ 207 isr = inb_el1(dep, EL1_XMIT); 208 if ((isr & (EXSR_16JAM | EXSR_UNDER | EXSR_JAM)) || !(isr & EXSR_IDLE)) { 209 DEBUG(printf("3c501: got xmit interrupt (ASR=0x%02X XSR=0x%02X)\n", csr, isr)); 210 if (isr & EXSR_JAM) { 211 /* Sending, packet got a collision */ 212 netdriver_stat_coll(1); 213 /* Put pointer back to beginning of packet */ 214 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); 215 outw_el1(dep, EL1_XMITPTR, (EL1_BFRSIZ - TxBuff->size)); 216 /* And retrigger transmission */ 217 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_XMIT); 218 return; 219 220 } else if ((isr & EXSR_16JAM) || !(isr & EXSR_IDLE)) { 221 netdriver_stat_oerror(1); 222 } else if (isr & EXSR_UNDER) { 223 netdriver_stat_oerror(1); 224 } 225 DEBUG(printf("3c501: got xmit interrupt (0x%02X)\n", isr)); 226 el1_reset(dep); 227 } else { 228 /** if (inw_el1(dep, EL1_XMITPTR) == EL1_BFRSIZ) **/ 229 /* Packet transmitted successfully */ 230 dep->bytes_Tx += (long) (TxBuff->size); 231 free_buff(dep, TxBuff); 232 dep->de_flags &= NOT(DEF_XMIT_BUSY); 233 netdriver_send(); 234 if (dep->de_flags & DEF_XMIT_BUSY) 235 return; 236 } 237 238 } else if ((csr & (ECSR_RECV | ECSR_XMTBSY)) == (ECSR_RECV | ECSR_XMTBSY)) { 239 240 /* Got a receive interrupt */ 241 isr = inb_el1(dep, EL1_RECV); 242 pktsize = inw_el1(dep, EL1_RECVPTR); 243 if ((isr & ERSR_RERROR) || (isr & ERSR_STALE)) { 244 DEBUG(printf("Rx0 (ASR=0x%02X RSR=0x%02X size=%d)\n", 245 csr, isr, pktsize)); 246 netdriver_stat_ierror(1); 247 248 } else if (pktsize < NDEV_ETH_PACKET_MIN || 249 pktsize > NDEV_ETH_PACKET_MAX) { 250 DEBUG(printf("Rx1 (ASR=0x%02X RSR=0x%02X size=%d)\n", 251 csr, isr, pktsize)); 252 netdriver_stat_ierror(1); 253 254 } else if ((rxptr = alloc_buff(dep, pktsize + sizeof(buff_t))) == NULL) { 255 /* Memory not available. Drop packet */ 256 netdriver_stat_ierror(1); 257 258 } else if (isr & (ERSR_GOOD | ERSR_ANY)) { 259 /* Got a good packet. Read it from buffer */ 260 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_SYS); 261 outw_el1(dep, EL1_XMITPTR, 0); 262 insb(dep->de_data_port, rxptr->buffer, pktsize); 263 rxptr->next = NULL; 264 rxptr->size = pktsize; 265 dep->bytes_Rx += (long) pktsize; 266 /* Queue packet to receive queue */ 267 if (dep->de_recvq_head == NULL) 268 dep->de_recvq_head = rxptr; 269 else 270 dep->de_recvq_tail->next = rxptr; 271 dep->de_recvq_tail = rxptr; 272 273 /* Reply to pending Receive requests, if any */ 274 netdriver_recv(); 275 } 276 } else { /* Nasty condition, should never happen */ 277 DEBUG( 278 printf("3c501: got interrupt with status 0x%02X\n" 279 " de_flags=0x%04X XSR=0x%02X RSR=0x%02X \n" 280 " xmit buffer = 0x%4X recv buffer = 0x%4X\n", 281 csr, dep->de_flags, 282 inb_el1(dep, EL1_RECV), 283 inb_el1(dep, EL1_XMIT), 284 inw_el1(dep, EL1_XMITPTR), 285 inw_el1(dep, EL1_RECVPTR)) 286 ); 287 el1_reset(dep); 288 } 289 290 /* Move into receive mode */ 291 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV); 292 outw_el1(dep, EL1_RECVPTR, 0); 293 /* Be sure that interrupts are cleared */ 294 inb_el1(dep, EL1_RECV); 295 inb_el1(dep, EL1_XMIT); 296 } 297 298 /* 299 ** Name: el1_init 300 ** Function: Initalizes board hardware and driver data structures. 301 */ 302 static void el1_init(dpeth_t * dep) 303 { 304 unsigned int ix; 305 306 dep->de_irq &= NOT(DEI_DEFAULT); /* Strip the default flag. */ 307 dep->de_offset_page = 0; 308 dep->de_data_port = dep->de_base_port + EL1_DATAPORT; 309 310 el1_reset(dep); /* Reset and initialize board */ 311 312 /* Start receiver (default mode) */ 313 outw_el1(dep, EL1_RECVPTR, 0); 314 outb_el1(dep, EL1_CSR, ECSR_RIDE | ECSR_RECV); 315 316 /* Initializes buffer pool */ 317 init_buff(dep, NULL); 318 el1_mode_init(dep); 319 320 printf("%s: Etherlink (%s) at %X:%d - ", 321 netdriver_name(), "3c501", dep->de_base_port, dep->de_irq); 322 for (ix = 0; ix < SA_ADDR_LEN; ix += 1) 323 printf("%02X%c", (dep->de_address.na_addr[ix] = StationAddress[ix]), 324 ix < SA_ADDR_LEN - 1 ? ':' : '\n'); 325 326 /* Device specific functions */ 327 dep->de_recvf = el1_recv; 328 dep->de_sendf = el1_send; 329 dep->de_flagsf = el1_mode_init; 330 dep->de_resetf = el1_reset; 331 dep->de_getstatsf = el1_getstats; 332 dep->de_dumpstatsf = el1_dumpstats; 333 dep->de_interruptf = el1_interrupt; 334 } 335 336 /* 337 ** Name: el1_probe 338 ** Function: Checks for presence of the board. 339 */ 340 int el1_probe(dpeth_t * dep) 341 { 342 unsigned int ix; 343 344 for (ix = 0; ix < 8; ix += 1) /* Reset the board */ 345 outb_el1(dep, EL1_CSR, ECSR_RESET); 346 outb_el1(dep, EL1_CSR, ECSR_SYS); /* Leaves buffer to system */ 347 348 /* Check station address */ 349 for (ix = 0; ix < SA_ADDR_LEN; ix += 1) { 350 outw_el1(dep, EL1_XMITPTR, ix); 351 StationAddress[ix] = inb_el1(dep, EL1_SAPROM); 352 } 353 if (StationAddress[0] != 0x02 || /* Etherlink Station address */ 354 StationAddress[1] != 0x60 || /* MUST be 02:60:8c:xx:xx:xx */ 355 StationAddress[2] != 0x8C) 356 return FALSE; /* No Etherlink board at this address */ 357 358 dep->de_ramsize = 0; /* RAM size is meaningless */ 359 dep->de_linmem = 0L; /* Access is via I/O port */ 360 361 /* Device specific functions */ 362 dep->de_initf = el1_init; 363 dep->de_stopf = el1_stop; 364 365 return TRUE; /* Etherlink board found */ 366 } 367 368 #endif /* ENABLE_3C501 */ 369 370 /** 3c501.c **/ 371