source: mainline/uspace/drv/nic/ne2k/dp8390.c@ 1ae74c6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1ae74c6 was 1ae74c6, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

Fix ddi.h header includes.

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