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
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00052 #include <assert.h>
00053 #include <byteorder.h>
00054 #include <errno.h>
00055 #include <stdio.h>
00056 #include <libarch/ddi.h>
00057 #include <net/packet.h>
00058 #include <packet_client.h>
00059 #include "dp8390.h"
00060
00062 #define DP_PAGE 256
00063
00065 #define SQ_PAGES 6
00066
00067
00068
00070 #define NE2K_DATA 0x0010
00071
00073 #define NE2K_RESET 0x001f
00074
00076 #define NE2K_START 0x4000
00077
00079 #define NE2K_SIZE 0x4000
00080
00082 #define NE2K_RETRY 0x1000
00083
00085 #define NE2K_ERL 10
00086
00088 #define ETH_MIN_PACK_SIZE 60
00089
00091 #define ETH_MAX_PACK_SIZE_TAGGED 1518
00092
00096 typedef struct {
00098 uint8_t status;
00099
00101 uint8_t next;
00102
00104 uint8_t rbcl;
00105
00107 uint8_t rbch;
00108 } recv_header_t;
00109
00117 static void pio_read_buf_16(void *port, void *buf, size_t size)
00118 {
00119 size_t i;
00120
00121 for (i = 0; (i << 1) < size; i++)
00122 *((uint16_t *) buf + i) = pio_read_16((ioport16_t *) (port));
00123 }
00124
00132 static void pio_write_buf_16(void *port, void *buf, size_t size)
00133 {
00134 size_t i;
00135
00136 for (i = 0; (i << 1) < size; i++)
00137 pio_write_16((ioport16_t *) port, *((uint16_t *) buf + i));
00138 }
00139
00140 static void ne2k_download(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
00141 {
00142 size_t esize = size & ~1;
00143
00144 pio_write_8(ne2k->port + DP_RBCR0, esize & 0xff);
00145 pio_write_8(ne2k->port + DP_RBCR1, (esize >> 8) & 0xff);
00146 pio_write_8(ne2k->port + DP_RSAR0, addr & 0xff);
00147 pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
00148 pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
00149
00150 if (esize != 0) {
00151 pio_read_buf_16(ne2k->data_port, buf, esize);
00152 size -= esize;
00153 buf += esize;
00154 }
00155
00156 if (size) {
00157 assert(size == 1);
00158
00159 uint16_t word = pio_read_16(ne2k->data_port);
00160 memcpy(buf, &word, 1);
00161 }
00162 }
00163
00164 static void ne2k_upload(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
00165 {
00166 size_t esize = size & ~1;
00167
00168 pio_write_8(ne2k->port + DP_RBCR0, esize & 0xff);
00169 pio_write_8(ne2k->port + DP_RBCR1, (esize >> 8) & 0xff);
00170 pio_write_8(ne2k->port + DP_RSAR0, addr & 0xff);
00171 pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
00172 pio_write_8(ne2k->port + DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
00173
00174 if (esize != 0) {
00175 pio_write_buf_16(ne2k->data_port, buf, esize);
00176 size -= esize;
00177 buf += esize;
00178 }
00179
00180 if (size) {
00181 assert(size == 1);
00182
00183 uint16_t word = 0;
00184
00185 memcpy(&word, buf, 1);
00186 pio_write_16(ne2k->data_port, word);
00187 }
00188 }
00189
00190 static void ne2k_init(ne2k_t *ne2k)
00191 {
00192 unsigned int i;
00193
00194
00195 uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
00196 usleep(2000);
00197 pio_write_8(ne2k->port + NE2K_RESET, val);
00198 usleep(2000);
00199
00200
00201 pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
00202 for (i = 0; i < NE2K_RETRY; i++) {
00203 if (pio_read_8(ne2k->port + DP_ISR) != 0)
00204 break;
00205 }
00206 }
00207
00218 int ne2k_probe(ne2k_t *ne2k, void *port, int irq)
00219 {
00220 unsigned int i;
00221
00222
00223 ne2k->port = port;
00224 ne2k->data_port = ne2k->port + NE2K_DATA;
00225 ne2k->irq = irq;
00226 ne2k->probed = false;
00227 ne2k->up = false;
00228
00229 ne2k_init(ne2k);
00230
00231
00232 uint8_t val = pio_read_8(ne2k->port + DP_CR);
00233 if ((val & (CR_STP | CR_DM_ABORT)) != (CR_STP | CR_DM_ABORT))
00234 return EXDEV;
00235
00236
00237 pio_write_8(ne2k->port + DP_RCR, RCR_MON);
00238 pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
00239 pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
00240
00241
00242 pio_write_8(ne2k->port + DP_RBCR0, ETH_ADDR << 1);
00243 pio_write_8(ne2k->port + DP_RBCR1, 0);
00244 pio_write_8(ne2k->port + DP_RSAR0, 0);
00245 pio_write_8(ne2k->port + DP_RSAR1, 0);
00246 pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
00247
00248 for (i = 0; i < ETH_ADDR; i++)
00249 ne2k->mac[i] = pio_read_16(ne2k->data_port);
00250
00251 ne2k->probed = true;
00252 return EOK;
00253 }
00254
00263 int ne2k_up(ne2k_t *ne2k)
00264 {
00265 if (!ne2k->probed)
00266 return EXDEV;
00267
00268 ne2k_init(ne2k);
00269
00270
00271
00272
00273
00274
00275 ne2k->sq.dirty = false;
00276 ne2k->sq.page = NE2K_START / DP_PAGE;
00277 fibril_mutex_initialize(&ne2k->sq_mutex);
00278 fibril_condvar_initialize(&ne2k->sq_cv);
00279
00280
00281
00282
00283
00284
00285
00286 ne2k->start_page = ne2k->sq.page + SQ_PAGES;
00287 ne2k->stop_page = ne2k->sq.page + NE2K_SIZE / DP_PAGE;
00288
00289
00290
00291
00292
00293
00294
00295
00296 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
00297
00298
00299 pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
00300
00301
00302 pio_write_8(ne2k->port + DP_RBCR0, 0);
00303 pio_write_8(ne2k->port + DP_RBCR1, 0);
00304
00305
00306 pio_write_8(ne2k->port + DP_RCR, RCR_AB);
00307
00308
00309 pio_write_8(ne2k->port + DP_TCR, TCR_INTERNAL);
00310
00311
00312 pio_write_8(ne2k->port + DP_BNRY, ne2k->start_page);
00313 pio_write_8(ne2k->port + DP_PSTART, ne2k->start_page);
00314 pio_write_8(ne2k->port + DP_PSTOP, ne2k->stop_page);
00315
00316
00317 pio_write_8(ne2k->port + DP_ISR, 0xff);
00318
00319
00320 pio_write_8(ne2k->port + DP_IMR,
00321 IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
00322
00323
00324 pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
00325
00326 pio_write_8(ne2k->port + DP_PAR0, ne2k->mac[0]);
00327 pio_write_8(ne2k->port + DP_PAR1, ne2k->mac[1]);
00328 pio_write_8(ne2k->port + DP_PAR2, ne2k->mac[2]);
00329 pio_write_8(ne2k->port + DP_PAR3, ne2k->mac[3]);
00330 pio_write_8(ne2k->port + DP_PAR4, ne2k->mac[4]);
00331 pio_write_8(ne2k->port + DP_PAR5, ne2k->mac[5]);
00332
00333 pio_write_8(ne2k->port + DP_MAR0, 0xff);
00334 pio_write_8(ne2k->port + DP_MAR1, 0xff);
00335 pio_write_8(ne2k->port + DP_MAR2, 0xff);
00336 pio_write_8(ne2k->port + DP_MAR3, 0xff);
00337 pio_write_8(ne2k->port + DP_MAR4, 0xff);
00338 pio_write_8(ne2k->port + DP_MAR5, 0xff);
00339 pio_write_8(ne2k->port + DP_MAR6, 0xff);
00340 pio_write_8(ne2k->port + DP_MAR7, 0xff);
00341
00342 pio_write_8(ne2k->port + DP_CURR, ne2k->start_page + 1);
00343
00344
00345 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_DM_ABORT | CR_STA);
00346
00347
00348 pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
00349
00350
00351 pio_read_8(ne2k->port + DP_CNTR0);
00352 pio_read_8(ne2k->port + DP_CNTR1);
00353 pio_read_8(ne2k->port + DP_CNTR2);
00354
00355
00356 ne2k->up = true;
00357 return EOK;
00358 }
00359
00365 void ne2k_down(ne2k_t *ne2k)
00366 {
00367 if ((ne2k->probed) && (ne2k->up)) {
00368 pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
00369 ne2k_init(ne2k);
00370 ne2k->up = false;
00371 }
00372 }
00373
00380 void ne2k_send(ne2k_t *ne2k, packet_t *packet)
00381 {
00382 assert(ne2k->probed);
00383 assert(ne2k->up);
00384
00385 fibril_mutex_lock(&ne2k->sq_mutex);
00386
00387 while (ne2k->sq.dirty)
00388 fibril_condvar_wait(&ne2k->sq_cv, &ne2k->sq_mutex);
00389
00390 void *buf = packet_get_data(packet);
00391 size_t size = packet_get_data_length(packet);
00392
00393 if ((size < ETH_MIN_PACK_SIZE) || (size > ETH_MAX_PACK_SIZE_TAGGED)) {
00394 fibril_mutex_unlock(&ne2k->sq_mutex);
00395 fprintf(stderr, "%s: Frame dropped (invalid size %zu bytes)\n",
00396 NAME, size);
00397 return;
00398 }
00399
00400
00401 ne2k_upload(ne2k, buf, ne2k->sq.page * DP_PAGE, size);
00402 ne2k->sq.dirty = true;
00403 ne2k->sq.size = size;
00404
00405
00406 pio_write_8(ne2k->port + DP_TPSR, ne2k->sq.page);
00407 pio_write_8(ne2k->port + DP_TBCR0, size & 0xff);
00408 pio_write_8(ne2k->port + DP_TBCR1, (size >> 8) & 0xff);
00409 pio_write_8(ne2k->port + DP_CR, CR_TXP | CR_STA);
00410
00411 fibril_mutex_unlock(&ne2k->sq_mutex);
00412 }
00413
00414 static void ne2k_reset(ne2k_t *ne2k)
00415 {
00416 unsigned int i;
00417
00418
00419 pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
00420 pio_write_8(ne2k->port + DP_RBCR0, 0);
00421 pio_write_8(ne2k->port + DP_RBCR1, 0);
00422
00423 for (i = 0; i < NE2K_RETRY; i++) {
00424 if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RST) != 0)
00425 break;
00426 }
00427
00428 pio_write_8(ne2k->port + DP_TCR, TCR_1EXTERNAL | TCR_OFST);
00429 pio_write_8(ne2k->port + DP_CR, CR_STA | CR_DM_ABORT);
00430 pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
00431
00432
00433 for (i = 0; i < NE2K_RETRY; i++) {
00434 if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RDC) != 0)
00435 break;
00436 }
00437
00438 uint8_t val = pio_read_8(ne2k->port + DP_ISR);
00439 pio_write_8(ne2k->port + DP_ISR, val & ~ISR_RDC);
00440
00441
00442
00443
00444
00445
00446 fibril_mutex_lock(&ne2k->sq_mutex);
00447 ne2k->sq.dirty = false;
00448 fibril_mutex_unlock(&ne2k->sq_mutex);
00449 }
00450
00451 static frame_t *ne2k_receive_frame(ne2k_t *ne2k, uint8_t page, size_t length)
00452 {
00453 frame_t *frame = (frame_t *) malloc(sizeof(frame_t));
00454 if (frame == NULL)
00455 return NULL;
00456
00457 link_initialize(&frame->link);
00458
00459 frame->packet = netif_packet_get_1(length);
00460 if (frame->packet == NULL) {
00461 free(frame);
00462 return NULL;
00463 }
00464
00465 void *buf = packet_suffix(frame->packet, length);
00466 bzero(buf, length);
00467 uint8_t last = page + length / DP_PAGE;
00468
00469 if (last >= ne2k->stop_page) {
00470 size_t left = (ne2k->stop_page - page) * DP_PAGE
00471 - sizeof(recv_header_t);
00472
00473 ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
00474 left);
00475 ne2k_download(ne2k, buf + left, ne2k->start_page * DP_PAGE,
00476 length - left);
00477 } else
00478 ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
00479 length);
00480
00481 ne2k->stats.receive_packets++;
00482 return frame;
00483 }
00484
00485 static link_t *ne2k_receive(ne2k_t *ne2k)
00486 {
00487
00488
00489
00490
00491
00492 link_t *frames = (link_t *) malloc(sizeof(link_t));
00493 if (frames != NULL)
00494 list_initialize(frames);
00495
00496 while (true) {
00497 uint8_t boundary = pio_read_8(ne2k->port + DP_BNRY) + 1;
00498
00499 if (boundary == ne2k->stop_page)
00500 boundary = ne2k->start_page;
00501
00502 pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_STA);
00503 uint8_t current = pio_read_8(ne2k->port + DP_CURR);
00504 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STA);
00505
00506 if (current == boundary)
00507
00508 break;
00509
00510 recv_header_t header;
00511 size_t size = sizeof(header);
00512 size_t offset = boundary * DP_PAGE;
00513
00514
00515 pio_write_8(ne2k->port + DP_RBCR0, size & 0xff);
00516 pio_write_8(ne2k->port + DP_RBCR1, (size >> 8) & 0xff);
00517 pio_write_8(ne2k->port + DP_RSAR0, offset & 0xff);
00518 pio_write_8(ne2k->port + DP_RSAR1, (offset >> 8) & 0xff);
00519 pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
00520
00521 pio_read_buf_16(ne2k->data_port, (void *) &header, size);
00522
00523 size_t length =
00524 (((size_t) header.rbcl) | (((size_t) header.rbch) << 8)) - size;
00525 uint8_t next = header.next;
00526
00527 if ((length < ETH_MIN_PACK_SIZE)
00528 || (length > ETH_MAX_PACK_SIZE_TAGGED)) {
00529 fprintf(stderr, "%s: Rant frame (%zu bytes)\n", NAME, length);
00530 next = current;
00531 } else if ((header.next < ne2k->start_page)
00532 || (header.next > ne2k->stop_page)) {
00533 fprintf(stderr, "%s: Malformed next frame %u\n", NAME,
00534 header.next);
00535 next = current;
00536 } else if (header.status & RSR_FO) {
00537
00538
00539
00540
00541 fprintf(stderr, "%s: FIFO overrun\n", NAME);
00542 ne2k->overruns++;
00543 next = current;
00544 } else if ((header.status & RSR_PRX) && (ne2k->up)) {
00545 if (frames != NULL) {
00546 frame_t *frame = ne2k_receive_frame(ne2k, boundary, length);
00547 if (frame != NULL)
00548 list_append(&frame->link, frames);
00549 }
00550 }
00551
00552
00553
00554
00555
00556
00557
00558 if (next == ne2k->start_page)
00559 next = ne2k->stop_page - 1;
00560 else
00561 next--;
00562
00563 pio_write_8(ne2k->port + DP_BNRY, next);
00564 }
00565
00566 return frames;
00567 }
00568
00569 link_t *ne2k_interrupt(ne2k_t *ne2k, uint8_t isr, uint8_t tsr)
00570 {
00571
00572 link_t *frames = NULL;
00573
00574 if (isr & (ISR_PTX | ISR_TXE)) {
00575 if (isr & ISR_TXE)
00576 ne2k->stats.send_errors++;
00577 else {
00578 if (tsr & TSR_PTX)
00579 ne2k->stats.send_packets++;
00580
00581 if (tsr & TSR_COL)
00582 ne2k->stats.collisions++;
00583
00584 if (tsr & TSR_ABT)
00585 ne2k->stats.send_aborted_errors++;
00586
00587 if (tsr & TSR_CRS)
00588 ne2k->stats.send_carrier_errors++;
00589
00590 if (tsr & TSR_FU) {
00591 ne2k->underruns++;
00592 if (ne2k->underruns < NE2K_ERL)
00593 fprintf(stderr, "%s: FIFO underrun\n", NAME);
00594 }
00595
00596 if (tsr & TSR_CDH) {
00597 ne2k->stats.send_heartbeat_errors++;
00598 if (ne2k->stats.send_heartbeat_errors < NE2K_ERL)
00599 fprintf(stderr, "%s: CD heartbeat failure\n", NAME);
00600 }
00601
00602 if (tsr & TSR_OWC)
00603 ne2k->stats.send_window_errors++;
00604 }
00605
00606 fibril_mutex_lock(&ne2k->sq_mutex);
00607
00608 if (ne2k->sq.dirty) {
00609
00610 ne2k->sq.dirty = false;
00611 ne2k->sq.size = 0;
00612
00613
00614 fibril_condvar_broadcast(&ne2k->sq_cv);
00615 } else {
00616 ne2k->misses++;
00617 if (ne2k->misses < NE2K_ERL)
00618 fprintf(stderr, "%s: Spurious PTX interrupt\n", NAME);
00619 }
00620
00621 fibril_mutex_unlock(&ne2k->sq_mutex);
00622 }
00623
00624 if (isr & ISR_RXE)
00625 ne2k->stats.receive_errors++;
00626
00627 if (isr & ISR_CNT) {
00628 ne2k->stats.receive_crc_errors +=
00629 pio_read_8(ne2k->port + DP_CNTR0);
00630 ne2k->stats.receive_frame_errors +=
00631 pio_read_8(ne2k->port + DP_CNTR1);
00632 ne2k->stats.receive_missed_errors +=
00633 pio_read_8(ne2k->port + DP_CNTR2);
00634 }
00635
00636 if (isr & ISR_PRX)
00637 frames = ne2k_receive(ne2k);
00638
00639 if (isr & ISR_RST) {
00640
00641
00642
00643
00644 ne2k_reset(ne2k);
00645 }
00646
00647
00648 pio_write_8(ne2k->port + DP_IMR,
00649 IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
00650
00651 return frames;
00652 }
00653