source: mainline/uspace/srv/hw/netif/dp8390/dp8390.c@ 774e6d1a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 774e6d1a was 3c106e88, checked in by martin@…>, 14 years ago

complete rewrite of the NE2000 network interface driver

  • remove almost all stuff which was not directly related to NE2000 ISA to improve readability (optional support for NE1000, already defunct host DMA support, etc.)
  • correct input and output buffering and correct synchronization w.r.t. fibrils (the only remaining fibril-related question is whether multiple overlaping IRQ notifications can cause any troubles)

this implementation finally provides solid foundations for the next lowest networking layers (ARP, IP) and provide a way to debug UDP and TCP

  • Property mode set to 100644
File size: 16.9 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * Copyright (c) 2011 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * This code is based upon the NE2000 driver for MINIX,
32 * distributed according to a BSD-style license.
33 *
34 * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
35 * Copyright (c) 1992, 1994 Philip Homburg
36 * Copyright (c) 1996 G. Falzoni
37 *
38 */
39
40/** @addtogroup ne2000
41 * @{
42 */
43
44/** @file
45 *
46 * NE2000 (based on DP8390) network interface core implementation.
47 * Only the basic NE2000 PIO (ISA) interface is supported, remote
48 * DMA is completely absent from this code for simplicity.
49 *
50 */
51
52#include <assert.h>
53#include <byteorder.h>
54#include <errno.h>
55#include <libarch/ddi.h>
56#include <netif_skel.h>
57#include <net/packet.h>
58#include <nil_interface.h>
59#include <packet_client.h>
60#include "dp8390.h"
61
62/** Page size */
63#define DP_PAGE 256
64
65/** 6 * DP_PAGE >= 1514 bytes */
66#define SQ_PAGES 6
67
68/* NE2000 implementation. */
69
70/** NE2000 Data Register */
71#define NE2K_DATA 0x0010
72
73/** NE2000 Reset register */
74#define NE2K_RESET 0x001f
75
76/** NE2000 data start */
77#define NE2K_START 0x4000
78
79/** NE2000 data size */
80#define NE2K_SIZE 0x4000
81
82/** NE2000 retry count */
83#define NE2K_RETRY 100
84
85/** NE2000 error messages rate limiting */
86#define NE2K_ERL 10
87
88/** Minimum Ethernet packet size in bytes */
89#define ETH_MIN_PACK_SIZE 60
90
91/** Maximum Ethernet packet size in bytes */
92#define ETH_MAX_PACK_SIZE_TAGGED 1518
93
94/** Type definition of the receive header
95 *
96 */
97typedef struct {
98 /** Copy of RSR */
99 uint8_t status;
100
101 /** Pointer to next packet */
102 uint8_t next;
103
104 /** Receive Byte Count Low */
105 uint8_t rbcl;
106
107 /** Receive Byte Count High */
108 uint8_t rbch;
109} recv_header_t;
110
111/** Read a memory block word by word.
112 *
113 * @param[in] port Source address.
114 * @param[out] buf Destination buffer.
115 * @param[in] size Memory block size in bytes.
116 *
117 */
118static void pio_read_buf_16(void *port, void *buf, size_t size)
119{
120 size_t i;
121
122 for (i = 0; (i << 1) < size; i++)
123 *((uint16_t *) buf + i) = pio_read_16((ioport16_t *) (port));
124}
125
126/** Write a memory block word by word.
127 *
128 * @param[in] port Destination address.
129 * @param[in] buf Source buffer.
130 * @param[in] size Memory block size in bytes.
131 *
132 */
133static void pio_write_buf_16(void *port, void *buf, size_t size)
134{
135 size_t i;
136
137 for (i = 0; (i << 1) < size; i++)
138 pio_write_16((ioport16_t *) port, *((uint16_t *) buf + i));
139}
140
141static void ne2k_download(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
142{
143 size_t esize = size & ~1;
144
145 pio_write_8(ne2k->port + DP_RBCR0, esize & 0xff);
146 pio_write_8(ne2k->port + DP_RBCR1, (esize >> 8) & 0xff);
147 pio_write_8(ne2k->port + DP_RSAR0, addr & 0xff);
148 pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
149 pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
150
151 if (esize != 0) {
152 pio_read_buf_16(ne2k->data_port, buf, esize);
153 size -= esize;
154 buf += esize;
155 }
156
157 if (size) {
158 assert(size == 1);
159
160 uint16_t word = pio_read_16(ne2k->data_port);
161 memcpy(buf, &word, 1);
162 }
163}
164
165static void ne2k_upload(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
166{
167 size_t esize = size & ~1;
168
169 pio_write_8(ne2k->port + DP_RBCR0, esize & 0xff);
170 pio_write_8(ne2k->port + DP_RBCR1, (esize >> 8) & 0xff);
171 pio_write_8(ne2k->port + DP_RSAR0, addr & 0xff);
172 pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
173 pio_write_8(ne2k->port + DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
174
175 if (esize != 0) {
176 pio_write_buf_16(ne2k->data_port, buf, esize);
177 size -= esize;
178 buf += esize;
179 }
180
181 if (size) {
182 assert(size == 1);
183
184 uint16_t word = 0;
185
186 memcpy(&word, buf, 1);
187 pio_write_16(ne2k->data_port, word);
188 }
189}
190
191/** Probe and initialize the network interface.
192 *
193 * @param[in,out] ne2k Network interface structure.
194 * @param[in] port Device address.
195 * @param[in] irq Device interrupt vector.
196 *
197 * @return EOK on success.
198 * @return EXDEV if the network interface was not recognized.
199 *
200 */
201int ne2k_probe(ne2k_t *ne2k, void *port, int irq)
202{
203 unsigned int i;
204
205 /* General initialization */
206 ne2k->port = port;
207 ne2k->data_port = ne2k->port + NE2K_DATA;
208 ne2k->irq = irq;
209 ne2k->probed = false;
210 ne2k->up = false;
211
212 /* Reset the ethernet card */
213 uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
214 usleep(2000);
215 pio_write_8(ne2k->port + NE2K_RESET, val);
216 usleep(2000);
217
218 /* Reset the DP8390 */
219 pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
220 for (i = 0; i < 0x1000; i++) {
221 if (pio_read_8(ne2k->port + DP_ISR) != 0)
222 break;
223 }
224
225 /* Check if the DP8390 is really there */
226 val = pio_read_8(ne2k->port + DP_CR);
227 if ((val & (CR_STP | CR_DM_ABORT)) != (CR_STP | CR_DM_ABORT))
228 return EXDEV;
229
230 /* Disable the receiver and init TCR and DCR */
231 pio_write_8(ne2k->port + DP_RCR, RCR_MON);
232 pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
233 pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
234
235 /* Setup a transfer to get the MAC address */
236 pio_write_8(ne2k->port + DP_RBCR0, ETH_ADDR << 1);
237 pio_write_8(ne2k->port + DP_RBCR1, 0);
238 pio_write_8(ne2k->port + DP_RSAR0, 0);
239 pio_write_8(ne2k->port + DP_RSAR1, 0);
240 pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
241
242 for (i = 0; i < ETH_ADDR; i++)
243 ne2k->mac[i] = pio_read_16(ne2k->data_port);
244
245 /*
246 * Setup send queue. Use the first
247 * SQ_PAGES of NE2000 memory for the send
248 * buffer.
249 */
250 ne2k->sq.dirty = false;
251 ne2k->sq.page = NE2K_START / DP_PAGE;
252 fibril_mutex_initialize(&ne2k->sq_mutex);
253 fibril_condvar_initialize(&ne2k->sq_cv);
254
255 /*
256 * Setup receive ring buffer. Use all the rest
257 * of the NE2000 memory (except the first SQ_PAGES
258 * reserved for the send buffer) for the receive
259 * ring buffer.
260 */
261 ne2k->start_page = ne2k->sq.page + SQ_PAGES;
262 ne2k->stop_page = ne2k->sq.page + NE2K_SIZE / DP_PAGE;
263
264 /*
265 * Initialization of the DP8390 following the mandatory procedure
266 * in reference manual ("DP8390D/NS32490D NIC Network Interface
267 * Controller", National Semiconductor, July 1995, Page 29).
268 */
269
270 /* Step 1: */
271 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
272
273 /* Step 2: */
274 pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
275
276 /* Step 3: */
277 pio_write_8(ne2k->port + DP_RBCR0, 0);
278 pio_write_8(ne2k->port + DP_RBCR1, 0);
279
280 /* Step 4: */
281 pio_write_8(ne2k->port + DP_RCR, RCR_AB);
282
283 /* Step 5: */
284 pio_write_8(ne2k->port + DP_TCR, TCR_INTERNAL);
285
286 /* Step 6: */
287 pio_write_8(ne2k->port + DP_BNRY, ne2k->start_page);
288 pio_write_8(ne2k->port + DP_PSTART, ne2k->start_page);
289 pio_write_8(ne2k->port + DP_PSTOP, ne2k->stop_page);
290
291 /* Step 7: */
292 pio_write_8(ne2k->port + DP_ISR, 0xff);
293
294 /* Step 8: */
295 pio_write_8(ne2k->port + DP_IMR,
296 IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
297
298 /* Step 9: */
299 pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
300
301 pio_write_8(ne2k->port + DP_PAR0, ne2k->mac[0]);
302 pio_write_8(ne2k->port + DP_PAR1, ne2k->mac[1]);
303 pio_write_8(ne2k->port + DP_PAR2, ne2k->mac[2]);
304 pio_write_8(ne2k->port + DP_PAR3, ne2k->mac[3]);
305 pio_write_8(ne2k->port + DP_PAR4, ne2k->mac[4]);
306 pio_write_8(ne2k->port + DP_PAR5, ne2k->mac[5]);
307
308 pio_write_8(ne2k->port + DP_MAR0, 0xff);
309 pio_write_8(ne2k->port + DP_MAR1, 0xff);
310 pio_write_8(ne2k->port + DP_MAR2, 0xff);
311 pio_write_8(ne2k->port + DP_MAR3, 0xff);
312 pio_write_8(ne2k->port + DP_MAR4, 0xff);
313 pio_write_8(ne2k->port + DP_MAR5, 0xff);
314 pio_write_8(ne2k->port + DP_MAR6, 0xff);
315 pio_write_8(ne2k->port + DP_MAR7, 0xff);
316
317 pio_write_8(ne2k->port + DP_CURR, ne2k->start_page + 1);
318
319 /* Step 10: */
320 pio_write_8(ne2k->port + DP_CR, CR_DM_ABORT | CR_STA);
321
322 /* Step 11: */
323 pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
324
325 /* Reset counters by reading */
326 pio_read_8(ne2k->port + DP_CNTR0);
327 pio_read_8(ne2k->port + DP_CNTR1);
328 pio_read_8(ne2k->port + DP_CNTR2);
329
330 /* Finish the initialization */
331 ne2k->probed = true;
332 return EOK;
333}
334
335/** Start the network interface.
336 *
337 * @param[in,out] ne2k Network interface structure.
338 *
339 * @return EOK on success.
340 * @return EXDEV if the network interface is disabled.
341 *
342 */
343int ne2k_up(ne2k_t *ne2k)
344{
345 if (!ne2k->probed)
346 return EXDEV;
347
348 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STA);
349 pio_write_8(ne2k->port + DP_RCR, RCR_AB);
350
351 ne2k->up = true;
352 return EOK;
353}
354
355/** Stop the network interface.
356 *
357 * @param[in,out] ne2k Network interface structure.
358 *
359 */
360void ne2k_down(ne2k_t *ne2k)
361{
362 if ((ne2k->probed) && (ne2k->up)) {
363 pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
364
365 /* Reset the ethernet card */
366 uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
367 usleep(2000);
368 pio_write_8(ne2k->port + NE2K_RESET, val);
369
370 ne2k->up = false;
371 }
372}
373
374/** Send a frame.
375 *
376 * @param[in,out] ne2k Network interface structure.
377 * @param[in] packet Frame to be sent.
378 *
379 */
380void ne2k_send(ne2k_t *ne2k, packet_t *packet)
381{
382 assert(ne2k->probed);
383 assert(ne2k->up);
384
385 fibril_mutex_lock(&ne2k->sq_mutex);
386
387 while (ne2k->sq.dirty)
388 fibril_condvar_wait(&ne2k->sq_cv, &ne2k->sq_mutex);
389
390 void *buf = packet_get_data(packet);
391 size_t size = packet_get_data_length(packet);
392
393 if ((size < ETH_MIN_PACK_SIZE) || (size > ETH_MAX_PACK_SIZE_TAGGED)) {
394 fprintf(stderr, "%s: Frame dropped (invalid size %zu bytes)\n",
395 NAME, size);
396 return;
397 }
398
399 /* Upload the frame to the ethernet card */
400 ne2k_upload(ne2k, buf, ne2k->sq.page * DP_PAGE, size);
401 ne2k->sq.dirty = true;
402 ne2k->sq.size = size;
403
404 /* Initialize the transfer */
405 pio_write_8(ne2k->port + DP_TPSR, ne2k->sq.page);
406 pio_write_8(ne2k->port + DP_TBCR0, size & 0xff);
407 pio_write_8(ne2k->port + DP_TBCR1, (size >> 8) & 0xff);
408 pio_write_8(ne2k->port + DP_CR, CR_TXP | CR_STA);
409
410 fibril_mutex_unlock(&ne2k->sq_mutex);
411}
412
413static void ne2k_reset(ne2k_t *ne2k)
414{
415 unsigned int i;
416
417 /* Stop the chip */
418 pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
419 pio_write_8(ne2k->port + DP_RBCR0, 0);
420 pio_write_8(ne2k->port + DP_RBCR1, 0);
421
422 for (i = 0; i < 0x1000; i++) {
423 if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RST) != 0)
424 break;
425 }
426
427 pio_write_8(ne2k->port + DP_TCR, TCR_1EXTERNAL | TCR_OFST);
428 pio_write_8(ne2k->port + DP_CR, CR_STA | CR_DM_ABORT);
429 pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
430
431 /* Acknowledge the ISR_RDC (remote DMA) interrupt */
432 for (i = 0; i < 0x1000; i++) {
433 if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RDC) != 0)
434 break;
435 }
436
437 uint8_t val = pio_read_8(ne2k->port + DP_ISR);
438 pio_write_8(ne2k->port + DP_ISR, val & ~ISR_RDC);
439
440 /*
441 * Reset the transmit ring. If we were transmitting a frame,
442 * we pretend that the packet is processed. Higher layers will
443 * retransmit if the packet wasn't actually sent.
444 */
445 fibril_mutex_lock(&ne2k->sq_mutex);
446 ne2k->sq.dirty = false;
447 fibril_mutex_unlock(&ne2k->sq_mutex);
448}
449
450static uint8_t ne2k_isr_ack(ne2k_t *ne2k)
451{
452 uint8_t isr = pio_read_8(ne2k->port + DP_ISR);
453 if (isr != 0)
454 pio_write_8(ne2k->port + DP_ISR, isr);
455
456 return isr;
457}
458
459static void ne2k_receive_frame(ne2k_t *ne2k, uint8_t page, size_t length,
460 int nil_phone, device_id_t device_id)
461{
462 packet_t *packet = netif_packet_get_1(length);
463 if (!packet)
464 return;
465
466 void *buf = packet_suffix(packet, length);
467 bzero(buf, length);
468 uint8_t last = page + length / DP_PAGE;
469
470 if (last >= ne2k->stop_page) {
471 size_t left = (ne2k->stop_page - page) * DP_PAGE
472 - sizeof(recv_header_t);
473
474 ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
475 left);
476 ne2k_download(ne2k, buf + left, ne2k->start_page * DP_PAGE,
477 length - left);
478 } else
479 ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
480 length);
481
482 ne2k->stats.receive_packets++;
483 nil_received_msg(nil_phone, device_id, packet, SERVICE_NONE);
484}
485
486static void ne2k_receive(ne2k_t *ne2k, int nil_phone, device_id_t device_id)
487{
488 while (true) {
489 uint8_t boundary = pio_read_8(ne2k->port + DP_BNRY) + 1;
490
491 if (boundary == ne2k->stop_page)
492 boundary = ne2k->start_page;
493
494 pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_STA);
495 uint8_t current = pio_read_8(ne2k->port + DP_CURR);
496 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STA);
497
498 if (current == boundary)
499 /* No more frames to process */
500 break;
501
502 recv_header_t header;
503 size_t size = sizeof(header);
504 size_t offset = boundary * DP_PAGE;
505
506 /* Get the frame header */
507 pio_write_8(ne2k->port + DP_RBCR0, size & 0xff);
508 pio_write_8(ne2k->port + DP_RBCR1, (size >> 8) & 0xff);
509 pio_write_8(ne2k->port + DP_RSAR0, offset & 0xff);
510 pio_write_8(ne2k->port + DP_RSAR1, (offset >> 8) & 0xff);
511 pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
512
513 pio_read_buf_16(ne2k->data_port, (void *) &header, size);
514
515 size_t length =
516 (((size_t) header.rbcl) | (((size_t) header.rbch) << 8)) - size;
517 uint8_t next = header.next;
518
519 if ((length < ETH_MIN_PACK_SIZE)
520 || (length > ETH_MAX_PACK_SIZE_TAGGED)) {
521 fprintf(stderr, "%s: Rant frame (%zu bytes)\n", NAME, length);
522 next = current;
523 } else if ((header.next < ne2k->start_page)
524 || (header.next > ne2k->stop_page)) {
525 fprintf(stderr, "%s: Malformed next frame %u\n", NAME,
526 header.next);
527 next = current;
528 } else if (header.status & RSR_FO) {
529 /*
530 * This is very serious, so we issue a warning and
531 * reset the buffers.
532 */
533 fprintf(stderr, "%s: FIFO overrun\n", NAME);
534 ne2k->overruns++;
535 next = current;
536 } else if ((header.status & RSR_PRX) && (ne2k->up))
537 ne2k_receive_frame(ne2k, boundary, length, nil_phone, device_id);
538
539 /*
540 * Update the boundary pointer
541 * to the value of the page
542 * prior to the next packet to
543 * be processed.
544 */
545 if (next == ne2k->start_page)
546 next = ne2k->stop_page - 1;
547 else
548 next--;
549
550 pio_write_8(ne2k->port + DP_BNRY, next);
551 }
552}
553
554void ne2k_interrupt(ne2k_t *ne2k, uint8_t isr, int nil_phone, device_id_t device_id)
555{
556 bool signal = false;
557 bool stopped = false;
558
559 for (; (isr & 0x7f) != 0; isr = ne2k_isr_ack(ne2k)) {
560 if (isr & (ISR_PTX | ISR_TXE)) {
561 if (isr & ISR_TXE)
562 ne2k->stats.send_errors++;
563 else {
564 uint8_t tsr = pio_read_8(ne2k->port + DP_TSR);
565
566 if (tsr & TSR_PTX)
567 ne2k->stats.send_packets++;
568
569 if (tsr & TSR_COL)
570 ne2k->stats.collisions++;
571
572 if (tsr & TSR_ABT)
573 ne2k->stats.send_aborted_errors++;
574
575 if (tsr & TSR_CRS)
576 ne2k->stats.send_carrier_errors++;
577
578 if (tsr & TSR_FU) {
579 ne2k->underruns++;
580 if (ne2k->underruns < NE2K_ERL)
581 fprintf(stderr, "%s: FIFO underrun\n", NAME);
582 }
583
584 if (tsr & TSR_CDH) {
585 ne2k->stats.send_heartbeat_errors++;
586 if (ne2k->stats.send_heartbeat_errors < NE2K_ERL)
587 fprintf(stderr, "%s: CD heartbeat failure\n", NAME);
588 }
589
590 if (tsr & TSR_OWC)
591 ne2k->stats.send_window_errors++;
592 }
593
594 fibril_mutex_lock(&ne2k->sq_mutex);
595
596 if (ne2k->sq.dirty) {
597 /* Prepare the buffer for next packet */
598 ne2k->sq.dirty = false;
599 ne2k->sq.size = 0;
600 signal = true;
601 } else {
602 ne2k->misses++;
603 if (ne2k->misses < NE2K_ERL)
604 fprintf(stderr, "%s: Spurious PTX interrupt\n", NAME);
605 }
606
607 fibril_mutex_unlock(&ne2k->sq_mutex);
608 }
609
610 if (isr & ISR_PRX)
611 ne2k_receive(ne2k, nil_phone, device_id);
612
613 if (isr & ISR_RXE)
614 ne2k->stats.receive_errors++;
615
616 if (isr & ISR_CNT) {
617 ne2k->stats.receive_crc_errors +=
618 pio_read_8(ne2k->port + DP_CNTR0);
619 ne2k->stats.receive_frame_errors +=
620 pio_read_8(ne2k->port + DP_CNTR1);
621 ne2k->stats.receive_missed_errors +=
622 pio_read_8(ne2k->port + DP_CNTR2);
623 }
624
625 if (isr & ISR_RST) {
626 /*
627 * This means we got an interrupt but the ethernet
628 * chip is shutdown. We set the flag 'stopped'
629 * and continue processing arrived packets. When the
630 * receive buffer is empty, we reset the DP8390.
631 */
632 stopped = true;
633 }
634 }
635
636 if (stopped) {
637 /*
638 * The chip is stopped, and all arrived
639 * frames are delivered.
640 */
641 ne2k_reset(ne2k);
642 }
643
644 /* Signal a next frame to be sent */
645 if (signal)
646 fibril_condvar_broadcast(&ne2k->sq_cv);
647}
648
649/** @}
650 */
Note: See TracBrowser for help on using the repository browser.