- Now splits paragraphs into multiple lines, with each line fitting the
[AROS.git] / workbench / devs / networks / nForce / unit.c
blobfeec05faac6f75d5144ed11b4d6cf18ea54532c1
1 /*
2 * $Id$
3 */
5 /*
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 MA 02111-1307, USA.
22 #define DEBUG 0
24 #include <exec/types.h>
25 #include <exec/resident.h>
26 #include <exec/io.h>
27 #include <exec/ports.h>
28 #include <exec/errors.h>
30 #include <aros/debug.h>
32 #include <devices/sana2.h>
33 #include <devices/sana2specialstats.h>
34 #include <devices/newstyle.h>
35 #include <devices/timer.h>
37 #include <utility/utility.h>
38 #include <utility/tagitem.h>
39 #include <utility/hooks.h>
41 #include <proto/exec.h>
42 #include <proto/dos.h>
43 #include <proto/battclock.h>
44 #include <proto/oop.h>
45 #include <proto/timer.h>
46 #include <proto/utility.h>
48 #include <stdlib.h>
50 #include "nforce.h"
51 #include "unit.h"
52 #include LC_LIBDEFS_FILE
55 * Report incoming events to all hyphotetical event receivers
57 VOID ReportEvents(struct NFBase *NforceBase, struct NFUnit *unit, ULONG events)
59 struct IOSana2Req *request, *tail, *next_request;
60 struct List *list;
62 list = &unit->request_ports[EVENT_QUEUE]->mp_MsgList;
63 next_request = (APTR)list->lh_Head;
64 tail = (APTR)&list->lh_Tail;
66 /* Go through list of event listeners. If send messages to receivers if event found */
67 Disable();
68 while(next_request != tail)
70 request = next_request;
71 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
73 if((request->ios2_WireError&events) != 0)
75 request->ios2_WireError = events;
76 Remove((APTR)request);
77 ReplyMsg((APTR)request);
80 Enable();
82 return;
85 struct TypeStats *FindTypeStats(struct NFBase *NforceBase, struct NFUnit *unit,
86 struct MinList *list, ULONG packet_type)
88 struct TypeStats *stats, *tail;
89 BOOL found = FALSE;
91 stats = (APTR)list->mlh_Head;
92 tail = (APTR)&list->mlh_Tail;
94 while(stats != tail && !found)
96 if(stats->packet_type == packet_type)
97 found = TRUE;
98 else
99 stats = (APTR)stats->node.mln_Succ;
102 if(!found)
103 stats = NULL;
105 return stats;
108 void FlushUnit(LIBBASETYPEPTR LIBBASE, struct NFUnit *unit, UBYTE last_queue, BYTE error)
110 struct IORequest *request;
111 UBYTE i;
112 struct Opener *opener, *tail;
114 D(bug("[nforce] FlushUnit\n"));
116 /* Abort queued operations */
118 for (i=0; i <= last_queue; i++)
120 while ((request = (APTR)GetMsg(unit->request_ports[i])) != NULL)
122 request->io_Error = IOERR_ABORTED;
123 ReplyMsg((struct Message *)request);
127 opener = (APTR)unit->nu_Openers.mlh_Head;
128 tail = (APTR)unit->nu_Openers.mlh_Tail;
130 /* Flush every opener's read queue */
132 while(opener != tail)
134 while ((request = (APTR)GetMsg(&opener->read_port)) != NULL)
136 request->io_Error = error;
137 ReplyMsg((struct Message *)request);
139 opener = (struct Opener *)opener->node.mln_Succ;
143 static inline ULONG readl(APTR base)
145 return *((volatile ULONG*)base);
148 static inline void writel(ULONG val, APTR base)
150 *((volatile ULONG*)base) = val;
153 static inline void pci_push(UBYTE *base)
155 /* force out pending posted writes */
156 readl(base);
160 * Interrupt handler called whenever nForce NIC interface generates interrupt.
161 * It's duty is to iterate throgh RX queue searching for new packets.
163 * Please note, that allthough multicast support could be done on interface
164 * basis, it is done in this function as result of quick integration of both
165 * the forcedeth driver (IFF_ALLMULTI flag) and etherling3 driver (AddressMatch
166 * filter function).
168 static AROS_INTH1(RX_Int, struct NFUnit *, unit)
170 AROS_INTFUNC_INIT
172 struct NFBase *NforceBase = unit->nu_device;
173 struct fe_priv *np = unit->nu_fe_priv;
174 ULONG Flags;
175 struct TypeStats *tracker;
176 ULONG packet_type;
177 struct Opener *opener, *opener_tail;
178 struct IOSana2Req *request, *request_tail;
179 BOOL accepted, is_orphan;
181 /* Endless loop, with break from inside */
182 for(;;)
184 int i,len;
185 struct eth_frame *frame;
187 if (np->cur_rx - np->refill_rx >= RX_RING)
188 break; /* we scanned the whole ring - do not continue */
190 /* Get the in-queue number */
191 i = np->cur_rx % RX_RING;
192 Flags = AROS_LE2LONG(np->rx_ring[i].FlagLen);
193 len = unit->descr_getlength(&np->rx_ring[i], np->desc_ver);
195 D(bug("%s: nv_rx_process: looking at packet %d, Flags 0x%x, len=%d\n",
196 unit->name, np->cur_rx, Flags, len));
198 /* Free frame? Do nothing - we've empty queue now */
199 if (Flags & NV_RX_AVAIL)
200 break; /* still owned by hardware, */
203 * the packet is for us - get it :)
206 /* look at what we actually got: */
207 if (np->desc_ver == DESC_VER_1) {
208 if (!(Flags & NV_RX_DESCRIPTORVALID))
209 goto next_pkt;
211 if (Flags & NV_RX_MISSEDFRAME) {
212 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
213 unit->stats.BadData++;
214 goto next_pkt;
216 if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) {
217 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
218 unit->stats.BadData++;
219 goto next_pkt;
221 if (Flags & NV_RX_CRCERR) {
222 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
223 unit->stats.BadData++;
224 goto next_pkt;
226 if (Flags & NV_RX_OVERFLOW) {
227 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
228 unit->stats.BadData++;
229 goto next_pkt;
231 if (Flags & NV_RX_ERROR) {
232 /* framing errors are soft errors, the rest is fatal. */
233 if (Flags & NV_RX_FRAMINGERR) {
234 if (Flags & NV_RX_SUBSTRACT1) {
235 len--;
237 } else {
238 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
239 unit->stats.BadData++;
240 goto next_pkt;
243 } else {
244 if (!(Flags & NV_RX2_DESCRIPTORVALID))
245 goto next_pkt;
247 if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4)) {
248 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
249 unit->stats.BadData++;
250 goto next_pkt;
252 if (Flags & NV_RX2_CRCERR) {
253 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
254 unit->stats.BadData++;
255 goto next_pkt;
257 if (Flags & NV_RX2_OVERFLOW) {
258 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
259 unit->stats.BadData++;
260 goto next_pkt;
262 if (Flags & NV_RX2_ERROR) {
263 /* framing errors are soft errors, the rest is fatal. */
264 if (Flags & NV_RX2_FRAMINGERR) {
265 if (Flags & NV_RX2_SUBSTRACT1) {
266 len--;
268 } else {
269 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
270 unit->stats.BadData++;
271 goto next_pkt;
274 Flags &= NV_RX2_CHECKSUMMASK;
275 if (Flags == NV_RX2_CHECKSUMOK1 ||
276 Flags == NV_RX2_CHECKSUMOK2 ||
277 Flags == NV_RX2_CHECKSUMOK3) {
278 D(bug("%s: hw checksum hit!.\n", unit->name));
279 } else {
280 D(bug("%s: hwchecksum miss!.\n", unit->name));
284 /* got a valid packet - forward it to the network core */
285 frame = &np->rx_buffer[i];
286 is_orphan = TRUE;
288 /* Dump contents of frame if DEBUG enabled */
289 #ifdef DEBUG
291 int j;
292 for (j=0; j<64; j++) {
293 if ((j%16) == 0)
294 D(bug("\n%03x:", j));
295 D(bug(" %02x", ((unsigned char*)frame)[j]));
297 D(bug("\n"));
299 #endif
301 /* Check for address validity */
302 if(AddressFilter(LIBBASE, unit, frame->eth_packet_dest))
304 /* Packet is addressed to this driver */
305 packet_type = AROS_BE2WORD(frame->eth_packet_type);
307 opener = (APTR)unit->nu_Openers.mlh_Head;
308 opener_tail = (APTR)&unit->nu_Openers.mlh_Tail;
310 /* Offer packet to every opener */
311 while(opener != opener_tail)
313 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
314 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
315 accepted = FALSE;
317 /* Offer packet to each request until it's accepted */
318 while((request != request_tail) && !accepted)
320 if((request->ios2_PacketType == packet_type)
321 || ((request->ios2_PacketType <= ETH_MTU)
322 && (packet_type <= ETH_MTU)))
324 CopyPacket(LIBBASE, unit, request, len, packet_type, frame);
325 accepted = TRUE;
327 request =
328 (struct IOSana2Req *)request->ios2_Req.io_Message.mn_Node.ln_Succ;
331 if(accepted)
332 is_orphan = FALSE;
334 opener = (APTR)opener->node.mln_Succ;
337 /* If packet was unwanted, give it to S2_READORPHAN request */
338 if(is_orphan)
340 unit->stats.UnknownTypesReceived++;
342 if(!IsMsgPortEmpty(unit->request_ports[ADOPT_QUEUE]))
344 CopyPacket(LIBBASE, unit,
345 (APTR)unit->request_ports[ADOPT_QUEUE]->
346 mp_MsgList.lh_Head, len, packet_type, frame);
350 /* Update remaining statistics */
352 tracker =
353 FindTypeStats(LIBBASE, unit, &unit->type_trackers, packet_type);
354 if(tracker != NULL)
356 tracker->stats.PacketsReceived++;
357 tracker->stats.BytesReceived += len;
361 unit->stats.PacketsReceived++;
363 next_pkt:
364 np->cur_rx++;
367 return FALSE;
369 AROS_INTFUNC_EXIT
373 * Check status of packets which we've already sent to the NIC. Update
374 * statistics, and reenable TX queue if only there is some free space.
376 static void nv_tx_done(struct NFUnit *unit)
378 struct fe_priv *np = unit->nu_fe_priv;
379 struct NFBase *NforceBase = unit->nu_device;
380 ULONG Flags;
381 int i;
383 /* Go through tx chain and mark all send packets as free */
384 while (np->nic_tx != np->next_tx)
386 i = np->nic_tx % TX_RING;
388 Flags = AROS_LE2LONG(np->tx_ring[i].FlagLen);
390 D(bug("%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
391 unit->name, np->nic_tx, Flags));
393 if (Flags & NV_TX_VALID)
394 break;
396 if (np->desc_ver == DESC_VER_1) {
397 if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
398 NV_TX_UNDERFLOW|NV_TX_ERROR))
400 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX);
402 else
404 unit->stats.PacketsSent++;
407 else
409 if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
410 NV_TX2_UNDERFLOW|NV_TX2_ERROR))
412 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX);
414 else
416 unit->stats.PacketsSent++;
419 np->nic_tx++;
423 * Do we have some spare space in TX queue and the queue self is blocked?
424 * Reenable it then!
426 if (np->next_tx - np->nic_tx < TX_LIMIT_START) {
427 if (netif_queue_stopped(unit)) {
428 bug("%s: output queue restart\n", unit->name);
429 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
430 netif_wake_queue(unit);
436 * Interrupt generated by Cause() to push new packets into the NIC interface
438 static AROS_INTH1(TX_Int, struct NFUnit *, unit)
440 AROS_INTFUNC_INIT
442 struct fe_priv *np = unit->nu_fe_priv;
443 struct NFBase *NforceBase = unit->nu_device;
444 int nr;
445 BOOL proceed = FALSE; /* Fails by default */
447 /* send packet only if there is free space on tx queue. Otherwise do nothing */
448 if (!netif_queue_stopped(unit))
450 UWORD packet_size, data_size;
451 struct IOSana2Req *request;
452 struct Opener *opener;
453 UBYTE *buffer;
454 ULONG wire_error=0;
455 BYTE error;
456 struct MsgPort *port;
457 struct TypeStats *tracker;
459 proceed = TRUE; /* Success by default */
460 port = unit->request_ports[WRITE_QUEUE];
462 /* Still no error and there are packets to be sent? */
463 while(proceed && (!IsMsgPortEmpty(port)))
465 nr = np->next_tx % TX_RING;
466 error = 0;
468 request = (APTR)port->mp_MsgList.lh_Head;
469 data_size = packet_size = request->ios2_DataLength;
471 opener = (APTR)request->ios2_BufferManagement;
473 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
475 packet_size += ETH_PACKET_DATA;
476 CopyMem(request->ios2_DstAddr, np->tx_buffer[nr].eth_packet_dest, ETH_ADDRESSSIZE);
477 CopyMem(unit->dev_addr, np->tx_buffer[nr].eth_packet_source, ETH_ADDRESSSIZE);
478 np->tx_buffer[nr].eth_packet_type = AROS_WORD2BE(request->ios2_PacketType);
480 buffer = np->tx_buffer[nr].eth_packet_data;
482 else
483 buffer = (UBYTE*)&np->tx_buffer[nr];
485 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
487 error = S2ERR_NO_RESOURCES;
488 wire_error = S2WERR_BUFF_ERROR;
489 ReportEvents(LIBBASE, unit,
490 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
491 | S2EVENT_TX);
494 /* Now the packet is already in TX buffer, update flags for NIC */
495 if (error == 0)
497 Disable();
498 np->tx_ring[nr].FlagLen = AROS_LONG2LE((packet_size-1) | np->tx_flags );
499 D(bug("%s: nv_start_xmit: packet packet %d queued for transmission.",
500 unit->name, np->next_tx));
502 /* DEBUG? Dump frame if so */
503 #ifdef DEBUG
505 int j;
506 for (j=0; j<64; j++) {
507 if ((j%16) == 0)
508 D(bug("\n%03x:", j));
509 D(bug(" %02x", ((unsigned char*)&np->tx_buffer[nr])[j]));
511 D(bug("\n"));
513 #endif
514 np->next_tx++;
517 * If we've just run out of free space on the TX queue, stop
518 * it and give up pushing further frames
520 if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP)
522 bug("%s: output queue full. Stopping\n", unit->name);
523 netif_stop_queue(unit);
524 proceed = FALSE;
526 Enable();
528 * At this place linux driver used to trigger NIC to output
529 * the queued packets through wire. We will not do it as we
530 * may already see if there are new outcomming packets.
532 * Yes, this driver might be a bit faster than linux one.
536 /* Reply packet */
538 request->ios2_Req.io_Error = error;
539 request->ios2_WireError = wire_error;
540 Disable();
541 Remove((APTR)request);
542 Enable();
543 ReplyMsg((APTR)request);
545 /* Update statistics */
547 if(error == 0)
549 tracker = FindTypeStats(LIBBASE, unit, &unit->type_trackers,
550 request->ios2_PacketType);
551 if(tracker != NULL)
553 tracker->stats.PacketsSent++;
554 tracker->stats.BytesSent += packet_size;
560 * Here either we've filled the queue with packets to be transmitted,
561 * or just run out of spare space in TX queue. In both cases tell the
562 * NIC to start transmitting them all through wire.
564 writel(NVREG_TXRXCTL_KICK|np->desc_ver, (UBYTE*)unit->nu_BaseMem + NvRegTxRxControl);
565 pci_push((UBYTE*)unit->nu_BaseMem);
568 /* Was there success? Enable incomming of new packets */
569 if(proceed)
570 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
571 else
572 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
574 return FALSE;
576 AROS_INTFUNC_EXIT
580 * Interrupt used to restart the real one
582 static AROS_INTH1(TX_End_Int, struct NFUnit *, unit)
584 AROS_INTFUNC_INIT
586 struct NFUnit *dev = unit;
587 struct fe_priv *np = dev->nu_fe_priv;
588 UBYTE *base = (UBYTE*) dev->nu_BaseMem;
590 Disable();
592 writel(np->irqmask, base + NvRegIrqMask);
593 pci_push(base);
594 AROS_INTC1(dev->nu_irqhandler.is_Code, dev->nu_irqhandler.is_Data);
595 Enable();
597 return FALSE;
599 AROS_INTFUNC_EXIT
603 * Maximum number of loops until we assume that a bit in the irq mask
604 * is stuck. Overridable with module param.
606 static const int max_interrupt_work = 5;
609 * Handle timeouts and other strange cases
611 static AROS_INTH1(NF_TimeoutHandler, struct NFUnit *, dev)
613 AROS_INTFUNC_INIT
615 struct timeval time;
616 struct Device *TimerBase = dev->nu_TimerSlowReq->tr_node.io_Device;
618 GetSysTime(&time);
621 * If timeout timer is expected, and time elapsed - regenerate the
622 * interrupt handler
624 if (dev->nu_toutNEED && (CmpTime(&time, &dev->nu_toutPOLL ) < 0))
626 dev->nu_toutNEED = FALSE;
627 Cause(&dev->tx_end_int);
630 return FALSE;
632 AROS_INTFUNC_EXIT
636 * The interrupt handler - schedules code execution to proper handlers depending
637 * on the message from nForce.
639 * NOTE.
641 * Don't be surprised - this driver used to restart itself several times, in
642 * order to handle events which occur when the driver was handling previous
643 * events. It reduces the latency and amount of dropped packets. Additionally,
644 * this interrupt may put itself into deep sleep (or just quit) and restarts
645 * after certain amount of time (POLL_WAIT).
647 static AROS_INTH1(NF_IntHandler, struct NFUnit *, dev)
649 AROS_INTFUNC_INIT
651 struct fe_priv *np = dev->nu_fe_priv;
652 UBYTE *base = (UBYTE*) dev->nu_BaseMem;
653 ULONG events;
654 int i;
655 struct Device *TimerBase = dev->nu_TimerSlowReq->tr_node.io_Device;
656 struct timeval time;
658 GetSysTime(&time);
660 /* Restart automagically :) */
661 for (i=0; ; i++)
663 events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
664 writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
665 pci_push(base);
667 if (!(events & np->irqmask))
668 break;
671 * Some packets have been sent? Just update statistics and empty the
672 * TX queue
674 if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {
675 nv_tx_done(dev);
678 /* Something received? Handle it! */
679 if (events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {
680 AROS_INTC1(dev->rx_int.is_Code, dev->rx_int.is_Data);
681 /* Mark received frames as free for hardware */
682 dev->alloc_rx(dev);
685 if (events & (NVREG_IRQ_LINK)) {
686 Disable();
687 dev->linkirq(dev);
688 Enable();
691 /* If linktimer interrupt required, handle it here */
692 if (np->need_linktimer && (CmpTime(&time, &np->link_timeout) < 0)) {
693 Disable();
694 dev->linkchange(dev);
695 Enable();
696 np->link_timeout.tv_micro = LINK_TIMEOUT % 1000000;
697 np->link_timeout.tv_secs = LINK_TIMEOUT / 1000000;
698 AddTime(&np->link_timeout, &time);
701 /* Erm? */
702 if (events & (NVREG_IRQ_TX_ERR)) {
703 bug("%s: received irq with events 0x%x. Probably TX fail.\n",
704 dev->name, events);
707 if (events & (NVREG_IRQ_UNKNOWN)) {
708 bug("%s: received irq with unknown events 0x%x. Please report\n",
709 dev->name, events);
713 * Straaaaaaaange, the interrupt was restarted more than
714 * max_interrupt_work times. Normally it should not happen, even on
715 * gigabit ethernet. In any case setup poll handler which restart this
716 * handler after specified amount of time.
718 if (i > max_interrupt_work)
720 bug("%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
721 writel(0, base + NvRegIrqMask);
722 pci_push(base);
724 /* When to wake up? */
725 Disable();
726 dev->nu_toutPOLL.tv_micro = POLL_WAIT % 1000000;
727 dev->nu_toutPOLL.tv_secs = POLL_WAIT / 1000000;
728 AddTime(&dev->nu_toutPOLL, &time);
729 dev->nu_toutNEED = TRUE;
730 Enable();
732 break; /* break the for() loop */
737 * If TX queue was stopped, try to reenable it *ALWAYS*
739 if (netif_queue_stopped(dev)) {
740 nv_tx_done(dev);
743 return FALSE;
745 AROS_INTFUNC_EXIT
748 VOID CopyPacket(struct NFBase *NforceBase, struct NFUnit *unit,
749 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
750 struct eth_frame *buffer)
752 struct Opener *opener;
753 BOOL filtered = FALSE;
754 UBYTE *ptr;
755 const UBYTE broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
757 /* Set multicast and broadcast flags */
759 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
760 if(memcmp(buffer->eth_packet_dest, broadcast, 6) == 0)
761 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
763 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
764 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
766 /* Set source and destination addresses and packet type */
767 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
768 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
769 request->ios2_PacketType = packet_type;
771 /* Adjust for cooked packet request */
773 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
775 packet_size -= ETH_PACKET_DATA;
776 ptr = buffer->eth_packet_data;
778 else
780 ptr = (UBYTE*)buffer;
783 request->ios2_DataLength = packet_size;
785 /* Filter packet */
787 opener = request->ios2_BufferManagement;
788 if((request->ios2_Req.io_Command == CMD_READ) &&
789 (opener->filter_hook != NULL))
790 if(!CallHookPkt(opener->filter_hook, request, ptr))
791 filtered = TRUE;
793 if(!filtered)
795 /* Copy packet into opener's buffer and reply packet */
797 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
799 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
800 request->ios2_WireError = S2WERR_BUFF_ERROR;
801 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
803 Disable();
804 Remove((APTR)request);
805 Enable();
806 ReplyMsg((APTR)request);
810 BOOL AddressFilter(struct NFBase *NforceBase, struct NFUnit *unit, UBYTE *address)
812 struct AddressRange *range, *tail;
813 BOOL accept = TRUE;
814 ULONG address_left;
815 UWORD address_right;
817 /* Check whether address is unicast/broadcast or multicast */
819 address_left = AROS_BE2LONG(*((ULONG *)address));
820 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
822 if((address_left & 0x01000000) != 0 &&
823 !(address_left == 0xffffffff && address_right == 0xffff))
825 /* Check if this multicast address is wanted */
827 range = (APTR)unit->multicast_ranges.mlh_Head;
828 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
829 accept = FALSE;
831 while((range != tail) && !accept)
833 if((address_left > range->lower_bound_left ||
834 (address_left == range->lower_bound_left &&
835 address_right >= range->lower_bound_right)) &&
836 (address_left < range->upper_bound_left ||
837 (address_left == range->upper_bound_left &&
838 address_right <= range->upper_bound_right)))
839 accept = TRUE;
840 range = (APTR)range->node.mln_Succ;
843 if(!accept)
844 unit->special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
846 return accept;
850 * Unit process
852 AROS_UFH3(void, NF_Scheduler,
853 AROS_UFHA(STRPTR, argPtr, A0),
854 AROS_UFHA(ULONG, argSize, D0),
855 AROS_UFHA(struct ExecBase *, SysBase, A6))
857 AROS_USERFUNC_INIT
859 struct NFUnit *dev = FindTask(NULL)->tc_UserData;
860 LIBBASETYPEPTR LIBBASE = dev->nu_device;
861 APTR BattClockBase;
862 struct MsgPort *reply_port, *input;
864 D(bug("[NFORCE] In nforce process\n"));
865 D(bug("[NFORCE] Setting device up\n"));
867 reply_port = CreateMsgPort();
868 input = CreateMsgPort();
870 dev->nu_input_port = input;
872 /* Randomize the generator with current time */
873 BattClockBase = OpenResource("battclock.resource");
874 srand(ReadBattClock());
876 dev->nu_TimerSlowPort = CreateMsgPort();
878 if (dev->nu_TimerSlowPort)
880 dev->nu_TimerSlowReq = (struct timerequest *)
881 CreateIORequest((struct MsgPort *)dev->nu_TimerSlowPort, sizeof(struct timerequest));
883 if (dev->nu_TimerSlowReq)
885 if (!OpenDevice("timer.device", UNIT_VBLANK,
886 (struct IORequest *)dev->nu_TimerSlowReq, 0))
888 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC|MEMF_CLEAR);
889 ULONG sigset;
891 D(bug("[NFORCE] Got VBLANK unit of timer.device\n"));
893 dev->initialize(dev);
895 msg->mn_ReplyPort = reply_port;
896 msg->mn_Length = sizeof(struct Message);
898 D(bug("[NFORCE] Setup complete. Sending handshake\n"));
899 PutMsg(LIBBASE->nf_syncport, msg);
900 WaitPort(reply_port);
901 GetMsg(reply_port);
903 FreeVec(msg);
905 D(bug("[NFORCE] Forever loop\n"));
907 dev->nu_signal_0 = AllocSignal(-1);
908 dev->nu_signal_1 = AllocSignal(-1);
909 dev->nu_signal_2 = AllocSignal(-1);
910 dev->nu_signal_3 = AllocSignal(-1);
912 sigset = 1 << input->mp_SigBit |
913 1 << dev->nu_signal_0 |
914 1 << dev->nu_signal_1 |
915 1 << dev->nu_signal_2 |
916 1 << dev->nu_signal_3;
917 for(;;)
919 ULONG recvd = Wait(sigset);
920 if (recvd & dev->nu_signal_0)
923 * Shutdown process. Driver should close everything
924 * already and waits for our process to complete. Free
925 * memory allocared here and kindly return.
927 dev->deinitialize(dev);
928 CloseDevice((struct IORequest *)dev->nu_TimerSlowReq);
929 DeleteIORequest((struct IORequest *)dev->nu_TimerSlowReq);
930 DeleteMsgPort(dev->nu_TimerSlowPort);
931 DeleteMsgPort(input);
932 DeleteMsgPort(reply_port);
934 D(bug("[NFORCE] Process shutdown.\n"));
935 return;
937 else if (recvd & (1 << input->mp_SigBit))
939 struct IOSana2Req *io;
941 /* Handle incoming transactions */
942 while ((io = (struct IOSana2Req *)GetMsg(input))!= NULL);
944 ObtainSemaphore(&dev->unit_lock);
945 handle_request(LIBBASE, io);
948 else
950 /* Handle incoming signals */
957 AROS_USERFUNC_EXIT
960 static const struct DriverConfig {
961 ULONG ProductID;
962 ULONG DriverFlags;
963 ULONG DescVer;
964 } Config[] = {
965 { NFORCE_MCPNET1_ID, DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, DESC_VER_1 },
966 { NFORCE_MCPNET2_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_NEED_LASTPACKET1, DESC_VER_1 },
967 { NFORCE_MCPNET3_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_NEED_LASTPACKET1, DESC_VER_1 },
968 { NFORCE_MCPNET4_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
969 { NFORCE_MCPNET5_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
970 { NFORCE_MCPNET6_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
971 { NFORCE_MCPNET7_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
972 { NFORCE_MCPNET8_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
973 { NFORCE_MCPNET9_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
974 { NFORCE_MCPNET10_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
975 { NFORCE_MCPNET11_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
976 { 0, 0 }
980 * Create new nForce ethernet device unit
982 struct NFUnit *CreateUnit(struct NFBase *NforceBase, OOP_Object *pciDevice)
984 struct NFUnit *unit = AllocMem(sizeof(struct NFUnit), MEMF_PUBLIC | MEMF_CLEAR);
985 BOOL success = TRUE;
986 int i;
988 if (unit != NULL)
990 IPTR DeviceID, base, len;
991 OOP_Object *driver;
993 OOP_GetAttr(pciDevice, aHidd_PCIDevice_ProductID, &DeviceID);
994 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&driver);
996 for (i=0; Config[i].ProductID; i++)
998 if (Config[i].ProductID == DeviceID)
1000 unit->nu_DriverFlags = Config[i].DriverFlags;
1001 unit->nu_fe_priv->desc_ver = Config[i].DescVer;
1002 break;
1006 unit->nu_device = NforceBase;
1007 unit->nu_DeviceID = DeviceID;
1008 unit->mtu = 1500;
1009 unit->nu_PCIDevice = pciDevice;
1010 unit->nu_PCIDriver = driver;
1012 InitSemaphore(&unit->unit_lock);
1013 NEWLIST(&unit->nu_Openers);
1014 NEWLIST(&unit->multicast_ranges);
1015 NEWLIST(&unit->type_trackers);
1017 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->nu_IRQ);
1018 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base1, &unit->nu_BaseIO);
1019 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, &base);
1020 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size0, &len);
1022 unit->nu_BaseMem = (IPTR)HIDD_PCIDriver_MapPCI(driver, (APTR)base, len);
1023 unit->nu_SizeMem = len;
1025 if (unit->nu_BaseMem)
1027 struct TagItem attrs[] = {
1028 { aHidd_PCIDevice_isIO, TRUE },
1029 { aHidd_PCIDevice_isMEM, TRUE },
1030 { aHidd_PCIDevice_isMaster, TRUE },
1031 { TAG_DONE, 0 },
1033 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
1035 unit->name = "[nforce0]";
1036 unit->nu_fe_priv = AllocMem(sizeof(struct fe_priv), MEMF_PUBLIC|MEMF_CLEAR);
1037 unit->nu_UnitNum = 0;
1039 nv_get_functions(unit);
1041 if (unit->nu_fe_priv)
1043 unit->nu_fe_priv->pci_dev = unit;
1044 InitSemaphore(&unit->nu_fe_priv->lock);
1047 struct Message *msg;
1049 unit->nu_irqhandler.is_Node.ln_Type = NT_INTERRUPT;
1050 unit->nu_irqhandler.is_Node.ln_Pri = 100;
1051 unit->nu_irqhandler.is_Node.ln_Name = LIBBASE->nf_Device.dd_Library.lib_Node.ln_Name;
1052 unit->nu_irqhandler.is_Code = (VOID_FUNC)NF_IntHandler;
1053 unit->nu_irqhandler.is_Data = unit;
1055 unit->nu_touthandler.is_Node.ln_Type = NT_INTERRUPT;
1056 unit->nu_touthandler.is_Node.ln_Pri = 100;
1057 unit->nu_touthandler.is_Node.ln_Name = LIBBASE->nf_Device.dd_Library.lib_Node.ln_Name;
1058 unit->nu_touthandler.is_Code = (VOID_FUNC)NF_TimeoutHandler;
1059 unit->nu_touthandler.is_Data = unit;
1061 unit->rx_int.is_Node.ln_Name = unit->name;
1062 unit->rx_int.is_Code = (VOID_FUNC)RX_Int;
1063 unit->rx_int.is_Data = unit;
1065 unit->tx_int.is_Node.ln_Name = unit->name;
1066 unit->tx_int.is_Code = (VOID_FUNC)TX_Int;
1067 unit->tx_int.is_Data = unit;
1069 unit->tx_end_int.is_Node.ln_Name = unit->name;
1070 unit->tx_end_int.is_Code = (VOID_FUNC)TX_End_Int;
1071 unit->tx_end_int.is_Data = unit;
1073 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1075 struct MsgPort *port = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR);
1076 unit->request_ports[i] = port;
1078 if (port == NULL) success = FALSE;
1080 if (success)
1082 NEWLIST(&port->mp_MsgList);
1083 port->mp_Flags = PA_IGNORE;
1084 port->mp_SigTask = &unit->tx_int;
1088 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
1090 if (success)
1092 LIBBASE->nf_syncport = CreateMsgPort();
1094 unit->nu_Process = CreateNewProcTags(
1095 NP_Entry, (IPTR)NF_Scheduler,
1096 NP_Name, NFORCE_TASK_NAME,
1097 NP_Priority, 0,
1098 NP_UserData, (IPTR)unit,
1099 NP_StackSize, 140960,
1100 TAG_DONE);
1102 WaitPort(LIBBASE->nf_syncport);
1103 msg = GetMsg(LIBBASE->nf_syncport);
1104 ReplyMsg(msg);
1105 DeleteMsgPort(LIBBASE->nf_syncport);
1107 D(bug("[nforce] Unit up and running\n"));
1109 return unit;
1114 else
1115 D(bug("[nforce] PANIC! Couldn't get MMIO area. Aborting\n"));
1118 DeleteUnit(NforceBase, unit);
1119 return NULL;
1123 * DeleteUnit - removes selected unit. Frees all resources and structures.
1125 * The caller should be sure, that given unit is really ready to be freed.
1128 void DeleteUnit(struct NFBase *NforceBase, struct NFUnit *Unit)
1130 int i;
1131 if (Unit)
1133 if (Unit->nu_Process)
1135 Signal(&Unit->nu_Process->pr_Task, Unit->nu_signal_0);
1138 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1140 if (Unit->request_ports[i] != NULL)
1141 FreeMem(Unit->request_ports[i], sizeof(struct MsgPort));
1143 Unit->request_ports[i] = NULL;
1146 if (Unit->nu_fe_priv)
1148 FreeMem(Unit->nu_fe_priv, sizeof(struct fe_priv));
1149 Unit->nu_fe_priv = NULL;
1152 if (Unit->nu_BaseMem)
1154 HIDD_PCIDriver_UnmapPCI(Unit->nu_PCIDriver,
1155 (APTR)Unit->nu_BaseMem,
1156 Unit->nu_SizeMem);
1159 FreeMem(Unit, sizeof(struct NFUnit));
1163 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct NFUnit *unit,
1164 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
1166 struct AddressRange *range, *tail;
1167 BOOL found = FALSE;
1169 range = (APTR)unit->multicast_ranges.mlh_Head;
1170 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1172 while((range != tail) && !found)
1174 if((lower_bound_left == range->lower_bound_left) &&
1175 (lower_bound_right == range->lower_bound_right) &&
1176 (upper_bound_left == range->upper_bound_left) &&
1177 (upper_bound_right == range->upper_bound_right))
1178 found = TRUE;
1179 else
1180 range = (APTR)range->node.mln_Succ;
1183 if(!found)
1184 range = NULL;
1186 return range;
1189 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct NFUnit *unit, const UBYTE *lower_bound,
1190 const UBYTE *upper_bound)
1192 struct AddressRange *range;
1193 ULONG lower_bound_left, upper_bound_left;
1194 UWORD lower_bound_right, upper_bound_right;
1196 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1197 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1198 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1199 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1201 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1202 upper_bound_left, upper_bound_right);
1204 if(range != NULL)
1205 range->add_count++;
1206 else
1208 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1209 if(range != NULL)
1211 range->lower_bound_left = lower_bound_left;
1212 range->lower_bound_right = lower_bound_right;
1213 range->upper_bound_left = upper_bound_left;
1214 range->upper_bound_right = upper_bound_right;
1215 range->add_count = 1;
1217 Disable();
1218 AddTail((APTR)&unit->multicast_ranges, (APTR)range);
1219 Enable();
1221 if (unit->range_count++ == 0)
1223 unit->flags |= IFF_ALLMULTI;
1224 unit->set_multicast(unit);
1229 return range != NULL;
1232 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE, struct NFUnit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
1234 struct AddressRange *range;
1235 ULONG lower_bound_left, upper_bound_left;
1236 UWORD lower_bound_right, upper_bound_right;
1238 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1239 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1240 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1241 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1243 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1244 upper_bound_left, upper_bound_right);
1246 if(range != NULL)
1248 if(--range->add_count == 0)
1250 Disable();
1251 Remove((APTR)range);
1252 Enable();
1253 FreeMem(range, sizeof(struct AddressRange));
1255 if (--unit->range_count == 0)
1257 unit->flags &= ~IFF_ALLMULTI;
1258 unit->set_multicast(unit);
1262 return range != NULL;