source: mainline/uspace/srv/hw/netif/ne2000/dp8390.c@ cd79391

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since cd79391 was cd79391, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Fix ne2k driver not transmitting last byte of even-sized frame properly.

  • Property mode set to 100644
File size: 16.8 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>
[c7bbf029]55#include <stdio.h>
[3c106e88]56#include <libarch/ddi.h>
[c69d327]57#include <net/packet.h>
[0a866eeb]58#include <packet_client.h>
[21580dd]59#include "dp8390.h"
60
[3c106e88]61/** Page size */
62#define DP_PAGE 256
63
64/** 6 * DP_PAGE >= 1514 bytes */
65#define SQ_PAGES 6
66
67/* NE2000 implementation. */
68
69/** NE2000 Data Register */
70#define NE2K_DATA 0x0010
71
72/** NE2000 Reset register */
73#define NE2K_RESET 0x001f
74
75/** NE2000 data start */
76#define NE2K_START 0x4000
77
78/** NE2000 data size */
79#define NE2K_SIZE 0x4000
80
81/** NE2000 retry count */
[43b4314]82#define NE2K_RETRY 0x1000
[3c106e88]83
84/** NE2000 error messages rate limiting */
85#define NE2K_ERL 10
86
87/** Minimum Ethernet packet size in bytes */
88#define ETH_MIN_PACK_SIZE 60
89
90/** Maximum Ethernet packet size in bytes */
91#define ETH_MAX_PACK_SIZE_TAGGED 1518
92
93/** Type definition of the receive header
[39d70ec]94 *
[21580dd]95 */
[3c106e88]96typedef struct {
97 /** Copy of RSR */
98 uint8_t status;
99
100 /** Pointer to next packet */
101 uint8_t next;
102
103 /** Receive Byte Count Low */
104 uint8_t rbcl;
105
106 /** Receive Byte Count High */
107 uint8_t rbch;
108} recv_header_t;
[21580dd]109
[39d70ec]110/** Read a memory block word by word.
111 *
[3c106e88]112 * @param[in] port Source address.
113 * @param[out] buf Destination buffer.
114 * @param[in] size Memory block size in bytes.
[39d70ec]115 *
[21580dd]116 */
[3c106e88]117static void pio_read_buf_16(void *port, void *buf, size_t size)
[95ff5c4]118{
[3c106e88]119 size_t i;
[95ff5c4]120
[3c106e88]121 for (i = 0; (i << 1) < size; i++)
122 *((uint16_t *) buf + i) = pio_read_16((ioport16_t *) (port));
[21580dd]123}
124
[3c106e88]125/** Write a memory block word by word.
[66b628a]126 *
[3c106e88]127 * @param[in] port Destination address.
128 * @param[in] buf Source buffer.
129 * @param[in] size Memory block size in bytes.
[66b628a]130 *
131 */
[3c106e88]132static void pio_write_buf_16(void *port, void *buf, size_t size)
[95ff5c4]133{
[3c106e88]134 size_t i;
[95ff5c4]135
[3c106e88]136 for (i = 0; (i << 1) < size; i++)
137 pio_write_16((ioport16_t *) port, *((uint16_t *) buf + i));
[21580dd]138}
139
[3c106e88]140static void ne2k_download(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
[95ff5c4]141{
[3c106e88]142 size_t esize = size & ~1;
143
144 pio_write_8(ne2k->port + DP_RBCR0, esize & 0xff);
145 pio_write_8(ne2k->port + DP_RBCR1, (esize >> 8) & 0xff);
146 pio_write_8(ne2k->port + DP_RSAR0, addr & 0xff);
147 pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
148 pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
149
150 if (esize != 0) {
151 pio_read_buf_16(ne2k->data_port, buf, esize);
152 size -= esize;
153 buf += esize;
154 }
155
156 if (size) {
157 assert(size == 1);
[7922dea]158
[3c106e88]159 uint16_t word = pio_read_16(ne2k->data_port);
160 memcpy(buf, &word, 1);
[21580dd]161 }
162}
163
[3c106e88]164static void ne2k_upload(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
[7922dea]165{
[cd79391]166 size_t esize_ru = (size + 1) & ~1;
[3c106e88]167 size_t esize = size & ~1;
168
[cd79391]169 pio_write_8(ne2k->port + DP_RBCR0, esize_ru & 0xff);
170 pio_write_8(ne2k->port + DP_RBCR1, (esize_ru >> 8) & 0xff);
[3c106e88]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
[43b4314]191static void ne2k_init(ne2k_t *ne2k)
192{
193 unsigned int i;
194
195 /* Reset the ethernet card */
196 uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
197 usleep(2000);
198 pio_write_8(ne2k->port + NE2K_RESET, val);
199 usleep(2000);
200
201 /* Reset the DP8390 */
202 pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
203 for (i = 0; i < NE2K_RETRY; i++) {
204 if (pio_read_8(ne2k->port + DP_ISR) != 0)
205 break;
206 }
207}
208
[3c106e88]209/** Probe and initialize the network interface.
210 *
211 * @param[in,out] ne2k Network interface structure.
212 * @param[in] port Device address.
213 * @param[in] irq Device interrupt vector.
214 *
215 * @return EOK on success.
216 * @return EXDEV if the network interface was not recognized.
217 *
218 */
219int ne2k_probe(ne2k_t *ne2k, void *port, int irq)
[21580dd]220{
[3c106e88]221 unsigned int i;
[95ff5c4]222
[3c106e88]223 /* General initialization */
224 ne2k->port = port;
225 ne2k->data_port = ne2k->port + NE2K_DATA;
226 ne2k->irq = irq;
227 ne2k->probed = false;
228 ne2k->up = false;
229
[43b4314]230 ne2k_init(ne2k);
[95ff5c4]231
[3c106e88]232 /* Check if the DP8390 is really there */
[43b4314]233 uint8_t val = pio_read_8(ne2k->port + DP_CR);
[3c106e88]234 if ((val & (CR_STP | CR_DM_ABORT)) != (CR_STP | CR_DM_ABORT))
235 return EXDEV;
[39d70ec]236
[3c106e88]237 /* Disable the receiver and init TCR and DCR */
238 pio_write_8(ne2k->port + DP_RCR, RCR_MON);
239 pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
240 pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
[39d70ec]241
[3c106e88]242 /* Setup a transfer to get the MAC address */
243 pio_write_8(ne2k->port + DP_RBCR0, ETH_ADDR << 1);
244 pio_write_8(ne2k->port + DP_RBCR1, 0);
245 pio_write_8(ne2k->port + DP_RSAR0, 0);
246 pio_write_8(ne2k->port + DP_RSAR1, 0);
247 pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
[95ff5c4]248
[3c106e88]249 for (i = 0; i < ETH_ADDR; i++)
250 ne2k->mac[i] = pio_read_16(ne2k->data_port);
[95ff5c4]251
[43b4314]252 ne2k->probed = true;
253 return EOK;
254}
255
256/** Start the network interface.
257 *
258 * @param[in,out] ne2k Network interface structure.
259 *
260 * @return EOK on success.
261 * @return EXDEV if the network interface is disabled.
262 *
263 */
264int ne2k_up(ne2k_t *ne2k)
265{
266 if (!ne2k->probed)
267 return EXDEV;
268
269 ne2k_init(ne2k);
270
[3c106e88]271 /*
272 * Setup send queue. Use the first
273 * SQ_PAGES of NE2000 memory for the send
274 * buffer.
275 */
276 ne2k->sq.dirty = false;
277 ne2k->sq.page = NE2K_START / DP_PAGE;
278 fibril_mutex_initialize(&ne2k->sq_mutex);
279 fibril_condvar_initialize(&ne2k->sq_cv);
[95ff5c4]280
[3c106e88]281 /*
282 * Setup receive ring buffer. Use all the rest
283 * of the NE2000 memory (except the first SQ_PAGES
284 * reserved for the send buffer) for the receive
285 * ring buffer.
286 */
287 ne2k->start_page = ne2k->sq.page + SQ_PAGES;
288 ne2k->stop_page = ne2k->sq.page + NE2K_SIZE / DP_PAGE;
[d3c9b60]289
290 /*
[3c106e88]291 * Initialization of the DP8390 following the mandatory procedure
[21580dd]292 * in reference manual ("DP8390D/NS32490D NIC Network Interface
293 * Controller", National Semiconductor, July 1995, Page 29).
294 */
[d3c9b60]295
[21580dd]296 /* Step 1: */
[3c106e88]297 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
[d3c9b60]298
[21580dd]299 /* Step 2: */
[3c106e88]300 pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
[d3c9b60]301
[21580dd]302 /* Step 3: */
[3c106e88]303 pio_write_8(ne2k->port + DP_RBCR0, 0);
304 pio_write_8(ne2k->port + DP_RBCR1, 0);
[d3c9b60]305
[21580dd]306 /* Step 4: */
[3c106e88]307 pio_write_8(ne2k->port + DP_RCR, RCR_AB);
[d3c9b60]308
[21580dd]309 /* Step 5: */
[3c106e88]310 pio_write_8(ne2k->port + DP_TCR, TCR_INTERNAL);
[d3c9b60]311
[21580dd]312 /* Step 6: */
[3c106e88]313 pio_write_8(ne2k->port + DP_BNRY, ne2k->start_page);
314 pio_write_8(ne2k->port + DP_PSTART, ne2k->start_page);
315 pio_write_8(ne2k->port + DP_PSTOP, ne2k->stop_page);
[d3c9b60]316
[21580dd]317 /* Step 7: */
[3c106e88]318 pio_write_8(ne2k->port + DP_ISR, 0xff);
[d3c9b60]319
[21580dd]320 /* Step 8: */
[3c106e88]321 pio_write_8(ne2k->port + DP_IMR,
322 IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
[d3c9b60]323
[21580dd]324 /* Step 9: */
[3c106e88]325 pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
326
327 pio_write_8(ne2k->port + DP_PAR0, ne2k->mac[0]);
328 pio_write_8(ne2k->port + DP_PAR1, ne2k->mac[1]);
329 pio_write_8(ne2k->port + DP_PAR2, ne2k->mac[2]);
330 pio_write_8(ne2k->port + DP_PAR3, ne2k->mac[3]);
331 pio_write_8(ne2k->port + DP_PAR4, ne2k->mac[4]);
332 pio_write_8(ne2k->port + DP_PAR5, ne2k->mac[5]);
333
334 pio_write_8(ne2k->port + DP_MAR0, 0xff);
335 pio_write_8(ne2k->port + DP_MAR1, 0xff);
336 pio_write_8(ne2k->port + DP_MAR2, 0xff);
337 pio_write_8(ne2k->port + DP_MAR3, 0xff);
338 pio_write_8(ne2k->port + DP_MAR4, 0xff);
339 pio_write_8(ne2k->port + DP_MAR5, 0xff);
340 pio_write_8(ne2k->port + DP_MAR6, 0xff);
341 pio_write_8(ne2k->port + DP_MAR7, 0xff);
342
343 pio_write_8(ne2k->port + DP_CURR, ne2k->start_page + 1);
[d3c9b60]344
[21580dd]345 /* Step 10: */
[7300c37]346 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_DM_ABORT | CR_STA);
[d3c9b60]347
[21580dd]348 /* Step 11: */
[3c106e88]349 pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
[d3c9b60]350
[3c106e88]351 /* Reset counters by reading */
352 pio_read_8(ne2k->port + DP_CNTR0);
353 pio_read_8(ne2k->port + DP_CNTR1);
354 pio_read_8(ne2k->port + DP_CNTR2);
355
356 /* Finish the initialization */
357 ne2k->up = true;
358 return EOK;
359}
360
361/** Stop the network interface.
362 *
363 * @param[in,out] ne2k Network interface structure.
364 *
365 */
366void ne2k_down(ne2k_t *ne2k)
367{
368 if ((ne2k->probed) && (ne2k->up)) {
369 pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
[43b4314]370 ne2k_init(ne2k);
[3c106e88]371 ne2k->up = false;
372 }
[21580dd]373}
374
[3c106e88]375/** Send a frame.
376 *
377 * @param[in,out] ne2k Network interface structure.
378 * @param[in] packet Frame to be sent.
379 *
380 */
381void ne2k_send(ne2k_t *ne2k, packet_t *packet)
[21580dd]382{
[3c106e88]383 assert(ne2k->probed);
384 assert(ne2k->up);
385
386 fibril_mutex_lock(&ne2k->sq_mutex);
[b590c21]387
[3c106e88]388 while (ne2k->sq.dirty)
389 fibril_condvar_wait(&ne2k->sq_cv, &ne2k->sq_mutex);
[b590c21]390
[3c106e88]391 void *buf = packet_get_data(packet);
392 size_t size = packet_get_data_length(packet);
393
394 if ((size < ETH_MIN_PACK_SIZE) || (size > ETH_MAX_PACK_SIZE_TAGGED)) {
[8f17503]395 fibril_mutex_unlock(&ne2k->sq_mutex);
[3c106e88]396 fprintf(stderr, "%s: Frame dropped (invalid size %zu bytes)\n",
397 NAME, size);
398 return;
399 }
[b590c21]400
[3c106e88]401 /* Upload the frame to the ethernet card */
402 ne2k_upload(ne2k, buf, ne2k->sq.page * DP_PAGE, size);
403 ne2k->sq.dirty = true;
404 ne2k->sq.size = size;
405
406 /* Initialize the transfer */
407 pio_write_8(ne2k->port + DP_TPSR, ne2k->sq.page);
408 pio_write_8(ne2k->port + DP_TBCR0, size & 0xff);
409 pio_write_8(ne2k->port + DP_TBCR1, (size >> 8) & 0xff);
410 pio_write_8(ne2k->port + DP_CR, CR_TXP | CR_STA);
411
412 fibril_mutex_unlock(&ne2k->sq_mutex);
[21580dd]413}
414
[3c106e88]415static void ne2k_reset(ne2k_t *ne2k)
[21580dd]416{
[3c106e88]417 unsigned int i;
[b590c21]418
[3c106e88]419 /* Stop the chip */
420 pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
421 pio_write_8(ne2k->port + DP_RBCR0, 0);
422 pio_write_8(ne2k->port + DP_RBCR1, 0);
[b590c21]423
[43b4314]424 for (i = 0; i < NE2K_RETRY; i++) {
[3c106e88]425 if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RST) != 0)
426 break;
427 }
[b590c21]428
[3c106e88]429 pio_write_8(ne2k->port + DP_TCR, TCR_1EXTERNAL | TCR_OFST);
430 pio_write_8(ne2k->port + DP_CR, CR_STA | CR_DM_ABORT);
431 pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
[b590c21]432
[3c106e88]433 /* Acknowledge the ISR_RDC (remote DMA) interrupt */
[43b4314]434 for (i = 0; i < NE2K_RETRY; i++) {
[3c106e88]435 if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RDC) != 0)
436 break;
437 }
[b590c21]438
[3c106e88]439 uint8_t val = pio_read_8(ne2k->port + DP_ISR);
440 pio_write_8(ne2k->port + DP_ISR, val & ~ISR_RDC);
[b590c21]441
442 /*
[3c106e88]443 * Reset the transmit ring. If we were transmitting a frame,
444 * we pretend that the packet is processed. Higher layers will
[21580dd]445 * retransmit if the packet wasn't actually sent.
446 */
[3c106e88]447 fibril_mutex_lock(&ne2k->sq_mutex);
448 ne2k->sq.dirty = false;
449 fibril_mutex_unlock(&ne2k->sq_mutex);
[21580dd]450}
451
[7300c37]452static frame_t *ne2k_receive_frame(ne2k_t *ne2k, uint8_t page, size_t length)
[3c106e88]453{
[7300c37]454 frame_t *frame = (frame_t *) malloc(sizeof(frame_t));
455 if (frame == NULL)
456 return NULL;
457
458 link_initialize(&frame->link);
459
460 frame->packet = netif_packet_get_1(length);
461 if (frame->packet == NULL) {
462 free(frame);
463 return NULL;
464 }
[3c106e88]465
[7300c37]466 void *buf = packet_suffix(frame->packet, length);
[3c106e88]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++;
[7300c37]483 return frame;
[3c106e88]484}
485
[b72efe8]486static list_t *ne2k_receive(ne2k_t *ne2k)
[21580dd]487{
[7300c37]488 /*
489 * Allocate memory for the list of received frames.
490 * If the allocation fails here we still receive the
491 * frames from the network, but they will be lost.
492 */
[b72efe8]493 list_t *frames = (list_t *) malloc(sizeof(list_t));
[7300c37]494 if (frames != NULL)
495 list_initialize(frames);
496
[3c106e88]497 while (true) {
498 uint8_t boundary = pio_read_8(ne2k->port + DP_BNRY) + 1;
499
500 if (boundary == ne2k->stop_page)
501 boundary = ne2k->start_page;
502
503 pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_STA);
504 uint8_t current = pio_read_8(ne2k->port + DP_CURR);
505 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STA);
506
507 if (current == boundary)
508 /* No more frames to process */
509 break;
510
511 recv_header_t header;
512 size_t size = sizeof(header);
513 size_t offset = boundary * DP_PAGE;
514
515 /* Get the frame header */
516 pio_write_8(ne2k->port + DP_RBCR0, size & 0xff);
517 pio_write_8(ne2k->port + DP_RBCR1, (size >> 8) & 0xff);
518 pio_write_8(ne2k->port + DP_RSAR0, offset & 0xff);
519 pio_write_8(ne2k->port + DP_RSAR1, (offset >> 8) & 0xff);
520 pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
521
522 pio_read_buf_16(ne2k->data_port, (void *) &header, size);
523
524 size_t length =
525 (((size_t) header.rbcl) | (((size_t) header.rbch) << 8)) - size;
526 uint8_t next = header.next;
527
528 if ((length < ETH_MIN_PACK_SIZE)
529 || (length > ETH_MAX_PACK_SIZE_TAGGED)) {
530 fprintf(stderr, "%s: Rant frame (%zu bytes)\n", NAME, length);
531 next = current;
532 } else if ((header.next < ne2k->start_page)
533 || (header.next > ne2k->stop_page)) {
534 fprintf(stderr, "%s: Malformed next frame %u\n", NAME,
535 header.next);
536 next = current;
537 } else if (header.status & RSR_FO) {
538 /*
539 * This is very serious, so we issue a warning and
540 * reset the buffers.
541 */
542 fprintf(stderr, "%s: FIFO overrun\n", NAME);
543 ne2k->overruns++;
544 next = current;
[7300c37]545 } else if ((header.status & RSR_PRX) && (ne2k->up)) {
[bddec0c]546 if (frames != NULL) {
547 frame_t *frame = ne2k_receive_frame(ne2k, boundary, length);
548 if (frame != NULL)
549 list_append(&frame->link, frames);
550 }
[7300c37]551 }
[3c106e88]552
553 /*
554 * Update the boundary pointer
555 * to the value of the page
556 * prior to the next packet to
557 * be processed.
558 */
559 if (next == ne2k->start_page)
560 next = ne2k->stop_page - 1;
561 else
562 next--;
563
564 pio_write_8(ne2k->port + DP_BNRY, next);
565 }
[7300c37]566
567 return frames;
[3c106e88]568}
569
[b72efe8]570list_t *ne2k_interrupt(ne2k_t *ne2k, uint8_t isr, uint8_t tsr)
[3c106e88]571{
[7300c37]572 /* List of received frames */
[b72efe8]573 list_t *frames = NULL;
[7300c37]574
[abe95c9]575 if (isr & (ISR_PTX | ISR_TXE)) {
576 if (isr & ISR_TXE)
577 ne2k->stats.send_errors++;
578 else {
579 if (tsr & TSR_PTX)
580 ne2k->stats.send_packets++;
[0777f4c5]581
[abe95c9]582 if (tsr & TSR_COL)
583 ne2k->stats.collisions++;
[0777f4c5]584
[abe95c9]585 if (tsr & TSR_ABT)
586 ne2k->stats.send_aborted_errors++;
587
588 if (tsr & TSR_CRS)
589 ne2k->stats.send_carrier_errors++;
590
591 if (tsr & TSR_FU) {
592 ne2k->underruns++;
593 if (ne2k->underruns < NE2K_ERL)
594 fprintf(stderr, "%s: FIFO underrun\n", NAME);
[21580dd]595 }
[0777f4c5]596
[abe95c9]597 if (tsr & TSR_CDH) {
598 ne2k->stats.send_heartbeat_errors++;
599 if (ne2k->stats.send_heartbeat_errors < NE2K_ERL)
600 fprintf(stderr, "%s: CD heartbeat failure\n", NAME);
601 }
602
603 if (tsr & TSR_OWC)
604 ne2k->stats.send_window_errors++;
[21580dd]605 }
[0777f4c5]606
[abe95c9]607 fibril_mutex_lock(&ne2k->sq_mutex);
[0777f4c5]608
[abe95c9]609 if (ne2k->sq.dirty) {
610 /* Prepare the buffer for next packet */
611 ne2k->sq.dirty = false;
612 ne2k->sq.size = 0;
613
614 /* Signal a next frame to be sent */
615 fibril_condvar_broadcast(&ne2k->sq_cv);
616 } else {
617 ne2k->misses++;
618 if (ne2k->misses < NE2K_ERL)
619 fprintf(stderr, "%s: Spurious PTX interrupt\n", NAME);
[21580dd]620 }
[0777f4c5]621
[abe95c9]622 fibril_mutex_unlock(&ne2k->sq_mutex);
623 }
624
625 if (isr & ISR_RXE)
626 ne2k->stats.receive_errors++;
627
628 if (isr & ISR_CNT) {
629 ne2k->stats.receive_crc_errors +=
630 pio_read_8(ne2k->port + DP_CNTR0);
631 ne2k->stats.receive_frame_errors +=
632 pio_read_8(ne2k->port + DP_CNTR1);
633 ne2k->stats.receive_missed_errors +=
634 pio_read_8(ne2k->port + DP_CNTR2);
[21580dd]635 }
[0777f4c5]636
[7300c37]637 if (isr & ISR_PRX)
638 frames = ne2k_receive(ne2k);
639
[abe95c9]640 if (isr & ISR_RST) {
[0777f4c5]641 /*
[66b628a]642 * The chip is stopped, and all arrived
643 * frames are delivered.
[21580dd]644 */
[3c106e88]645 ne2k_reset(ne2k);
[7922dea]646 }
[b590c21]647
[abe95c9]648 /* Unmask interrupts to be processed in the next round */
649 pio_write_8(ne2k->port + DP_IMR,
650 IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
[7300c37]651
652 return frames;
[21580dd]653}
654
655/** @}
656 */
Note: See TracBrowser for help on using the repository browser.