source: mainline/uspace/srv/hw/netif/dp8390/dp8390.c@ 3c106e88

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3c106e88 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
RevLine 
[e0854e3]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
[3c106e88]40/** @addtogroup ne2000
[21580dd]41 * @{
42 */
43
44/** @file
[3c106e88]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 *
[21580dd]50 */
51
52#include <assert.h>
[2687bdb]53#include <byteorder.h>
[21580dd]54#include <errno.h>
[3c106e88]55#include <libarch/ddi.h>
56#include <netif_skel.h>
[c69d327]57#include <net/packet.h>
[39d70ec]58#include <nil_interface.h>
[0a866eeb]59#include <packet_client.h>
[21580dd]60#include "dp8390.h"
61
[3c106e88]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
[39d70ec]95 *
[21580dd]96 */
[3c106e88]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;
[21580dd]110
[39d70ec]111/** Read a memory block word by word.
112 *
[3c106e88]113 * @param[in] port Source address.
114 * @param[out] buf Destination buffer.
115 * @param[in] size Memory block size in bytes.
[39d70ec]116 *
[21580dd]117 */
[3c106e88]118static void pio_read_buf_16(void *port, void *buf, size_t size)
[95ff5c4]119{
[3c106e88]120 size_t i;
[95ff5c4]121
[3c106e88]122 for (i = 0; (i << 1) < size; i++)
123 *((uint16_t *) buf + i) = pio_read_16((ioport16_t *) (port));
[21580dd]124}
125
[3c106e88]126/** Write a memory block word by word.
[66b628a]127 *
[3c106e88]128 * @param[in] port Destination address.
129 * @param[in] buf Source buffer.
130 * @param[in] size Memory block size in bytes.
[66b628a]131 *
132 */
[3c106e88]133static void pio_write_buf_16(void *port, void *buf, size_t size)
[95ff5c4]134{
[3c106e88]135 size_t i;
[95ff5c4]136
[3c106e88]137 for (i = 0; (i << 1) < size; i++)
138 pio_write_16((ioport16_t *) port, *((uint16_t *) buf + i));
[21580dd]139}
140
[3c106e88]141static void ne2k_download(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
[95ff5c4]142{
[3c106e88]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);
[7922dea]159
[3c106e88]160 uint16_t word = pio_read_16(ne2k->data_port);
161 memcpy(buf, &word, 1);
[21580dd]162 }
163}
164
[3c106e88]165static void ne2k_upload(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
[7922dea]166{
[3c106e88]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;
[7922dea]179 }
180
[3c106e88]181 if (size) {
182 assert(size == 1);
[7922dea]183
[3c106e88]184 uint16_t word = 0;
[7922dea]185
[3c106e88]186 memcpy(&word, buf, 1);
187 pio_write_16(ne2k->data_port, word);
[7922dea]188 }
189}
190
[3c106e88]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)
[21580dd]202{
[3c106e88]203 unsigned int i;
[95ff5c4]204
[3c106e88]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;
[21580dd]223 }
[95ff5c4]224
[3c106e88]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;
[39d70ec]229
[3c106e88]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);
[39d70ec]234
[3c106e88]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);
[95ff5c4]241
[3c106e88]242 for (i = 0; i < ETH_ADDR; i++)
243 ne2k->mac[i] = pio_read_16(ne2k->data_port);
[95ff5c4]244
[3c106e88]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);
[95ff5c4]254
[3c106e88]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;
[d3c9b60]263
264 /*
[3c106e88]265 * Initialization of the DP8390 following the mandatory procedure
[21580dd]266 * in reference manual ("DP8390D/NS32490D NIC Network Interface
267 * Controller", National Semiconductor, July 1995, Page 29).
268 */
[d3c9b60]269
[21580dd]270 /* Step 1: */
[3c106e88]271 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
[d3c9b60]272
[21580dd]273 /* Step 2: */
[3c106e88]274 pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
[d3c9b60]275
[21580dd]276 /* Step 3: */
[3c106e88]277 pio_write_8(ne2k->port + DP_RBCR0, 0);
278 pio_write_8(ne2k->port + DP_RBCR1, 0);
[d3c9b60]279
[21580dd]280 /* Step 4: */
[3c106e88]281 pio_write_8(ne2k->port + DP_RCR, RCR_AB);
[d3c9b60]282
[21580dd]283 /* Step 5: */
[3c106e88]284 pio_write_8(ne2k->port + DP_TCR, TCR_INTERNAL);
[d3c9b60]285
[21580dd]286 /* Step 6: */
[3c106e88]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);
[d3c9b60]290
[21580dd]291 /* Step 7: */
[3c106e88]292 pio_write_8(ne2k->port + DP_ISR, 0xff);
[d3c9b60]293
[21580dd]294 /* Step 8: */
[3c106e88]295 pio_write_8(ne2k->port + DP_IMR,
296 IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
[d3c9b60]297
[21580dd]298 /* Step 9: */
[3c106e88]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);
[d3c9b60]318
[21580dd]319 /* Step 10: */
[3c106e88]320 pio_write_8(ne2k->port + DP_CR, CR_DM_ABORT | CR_STA);
[d3c9b60]321
[21580dd]322 /* Step 11: */
[3c106e88]323 pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
[d3c9b60]324
[3c106e88]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;
[d3c9b60]347
[3c106e88]348 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STA);
349 pio_write_8(ne2k->port + DP_RCR, RCR_AB);
[d3c9b60]350
[3c106e88]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 }
[21580dd]372}
373
[3c106e88]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)
[21580dd]381{
[3c106e88]382 assert(ne2k->probed);
383 assert(ne2k->up);
384
385 fibril_mutex_lock(&ne2k->sq_mutex);
[b590c21]386
[3c106e88]387 while (ne2k->sq.dirty)
388 fibril_condvar_wait(&ne2k->sq_cv, &ne2k->sq_mutex);
[b590c21]389
[3c106e88]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 }
[b590c21]398
[3c106e88]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);
[21580dd]411}
412
[3c106e88]413static void ne2k_reset(ne2k_t *ne2k)
[21580dd]414{
[3c106e88]415 unsigned int i;
[b590c21]416
[3c106e88]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);
[b590c21]421
[3c106e88]422 for (i = 0; i < 0x1000; i++) {
423 if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RST) != 0)
424 break;
425 }
[b590c21]426
[3c106e88]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);
[b590c21]430
[3c106e88]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 }
[b590c21]436
[3c106e88]437 uint8_t val = pio_read_8(ne2k->port + DP_ISR);
438 pio_write_8(ne2k->port + DP_ISR, val & ~ISR_RDC);
[b590c21]439
440 /*
[3c106e88]441 * Reset the transmit ring. If we were transmitting a frame,
442 * we pretend that the packet is processed. Higher layers will
[21580dd]443 * retransmit if the packet wasn't actually sent.
444 */
[3c106e88]445 fibril_mutex_lock(&ne2k->sq_mutex);
446 ne2k->sq.dirty = false;
447 fibril_mutex_unlock(&ne2k->sq_mutex);
[21580dd]448}
449
[3c106e88]450static uint8_t ne2k_isr_ack(ne2k_t *ne2k)
[d8d8bbd]451{
[3c106e88]452 uint8_t isr = pio_read_8(ne2k->port + DP_ISR);
[d8d8bbd]453 if (isr != 0)
[3c106e88]454 pio_write_8(ne2k->port + DP_ISR, isr);
[d8d8bbd]455
456 return isr;
457}
458
[3c106e88]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)
[21580dd]487{
[3c106e88]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;
[0777f4c5]558
[3c106e88]559 for (; (isr & 0x7f) != 0; isr = ne2k_isr_ack(ne2k)) {
[0777f4c5]560 if (isr & (ISR_PTX | ISR_TXE)) {
561 if (isr & ISR_TXE)
[3c106e88]562 ne2k->stats.send_errors++;
[0777f4c5]563 else {
[3c106e88]564 uint8_t tsr = pio_read_8(ne2k->port + DP_TSR);
[0777f4c5]565
566 if (tsr & TSR_PTX)
[3c106e88]567 ne2k->stats.send_packets++;
[0777f4c5]568
569 if (tsr & TSR_COL)
[3c106e88]570 ne2k->stats.collisions++;
[0777f4c5]571
572 if (tsr & TSR_ABT)
[3c106e88]573 ne2k->stats.send_aborted_errors++;
[0777f4c5]574
575 if (tsr & TSR_CRS)
[3c106e88]576 ne2k->stats.send_carrier_errors++;
[0777f4c5]577
[3c106e88]578 if (tsr & TSR_FU) {
579 ne2k->underruns++;
580 if (ne2k->underruns < NE2K_ERL)
581 fprintf(stderr, "%s: FIFO underrun\n", NAME);
582 }
[0777f4c5]583
[3c106e88]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 }
[0777f4c5]589
590 if (tsr & TSR_OWC)
[3c106e88]591 ne2k->stats.send_window_errors++;
[21580dd]592 }
[0777f4c5]593
[3c106e88]594 fibril_mutex_lock(&ne2k->sq_mutex);
[0777f4c5]595
[3c106e88]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);
[21580dd]605 }
[0777f4c5]606
[3c106e88]607 fibril_mutex_unlock(&ne2k->sq_mutex);
[21580dd]608 }
[0777f4c5]609
[aa1e202]610 if (isr & ISR_PRX)
[3c106e88]611 ne2k_receive(ne2k, nil_phone, device_id);
[21580dd]612
[0777f4c5]613 if (isr & ISR_RXE)
[3c106e88]614 ne2k->stats.receive_errors++;
[0777f4c5]615
616 if (isr & ISR_CNT) {
[3c106e88]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);
[21580dd]623 }
[0777f4c5]624
625 if (isr & ISR_RST) {
626 /*
[66b628a]627 * This means we got an interrupt but the ethernet
628 * chip is shutdown. We set the flag 'stopped'
[21580dd]629 * and continue processing arrived packets. When the
[3c106e88]630 * receive buffer is empty, we reset the DP8390.
[21580dd]631 */
[3c106e88]632 stopped = true;
[21580dd]633 }
634 }
[0777f4c5]635
[3c106e88]636 if (stopped) {
[0777f4c5]637 /*
[66b628a]638 * The chip is stopped, and all arrived
639 * frames are delivered.
[21580dd]640 */
[3c106e88]641 ne2k_reset(ne2k);
[7922dea]642 }
[b590c21]643
[3c106e88]644 /* Signal a next frame to be sent */
645 if (signal)
646 fibril_condvar_broadcast(&ne2k->sq_cv);
[21580dd]647}
648
649/** @}
650 */
Note: See TracBrowser for help on using the repository browser.