Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / devs / networks / nForce / unit.c
blob1ca6c83fed15972a15e46353e523229c4c8cd0a7
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 volatile ULONG readl(APTR base)
145 return *((ULONG*)base);
148 static inline volatile void writel(ULONG val, APTR base)
150 *((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 AROS_UFH3(void, RX_Int,
169 AROS_UFHA(struct NFUnit *, unit, A1),
170 AROS_UFHA(APTR, dummy, A5),
171 AROS_UFHA(struct ExecBase *,SysBase, A6))
173 AROS_USERFUNC_INIT
175 struct NFBase *NforceBase = unit->nu_device;
176 struct fe_priv *np = unit->nu_fe_priv;
177 ULONG Flags;
178 struct TypeStats *tracker;
179 ULONG packet_type;
180 struct Opener *opener, *opener_tail;
181 struct IOSana2Req *request, *request_tail;
182 BOOL accepted, is_orphan;
184 /* Endless loop, with break from inside */
185 for(;;)
187 int i,len;
188 struct eth_frame *frame;
190 if (np->cur_rx - np->refill_rx >= RX_RING)
191 break; /* we scanned the whole ring - do not continue */
193 /* Get the in-queue number */
194 i = np->cur_rx % RX_RING;
195 Flags = AROS_LE2LONG(np->rx_ring[i].FlagLen);
196 len = unit->descr_getlength(&np->rx_ring[i], np->desc_ver);
198 D(bug("%s: nv_rx_process: looking at packet %d, Flags 0x%x, len=%d\n",
199 unit->name, np->cur_rx, Flags, len));
201 /* Free frame? Do nothing - we've empty queue now */
202 if (Flags & NV_RX_AVAIL)
203 break; /* still owned by hardware, */
206 * the packet is for us - get it :)
209 /* look at what we actually got: */
210 if (np->desc_ver == DESC_VER_1) {
211 if (!(Flags & NV_RX_DESCRIPTORVALID))
212 goto next_pkt;
214 if (Flags & NV_RX_MISSEDFRAME) {
215 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
216 unit->stats.BadData++;
217 goto next_pkt;
219 if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) {
220 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
221 unit->stats.BadData++;
222 goto next_pkt;
224 if (Flags & NV_RX_CRCERR) {
225 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
226 unit->stats.BadData++;
227 goto next_pkt;
229 if (Flags & NV_RX_OVERFLOW) {
230 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
231 unit->stats.BadData++;
232 goto next_pkt;
234 if (Flags & NV_RX_ERROR) {
235 /* framing errors are soft errors, the rest is fatal. */
236 if (Flags & NV_RX_FRAMINGERR) {
237 if (Flags & NV_RX_SUBSTRACT1) {
238 len--;
240 } else {
241 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
242 unit->stats.BadData++;
243 goto next_pkt;
246 } else {
247 if (!(Flags & NV_RX2_DESCRIPTORVALID))
248 goto next_pkt;
250 if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4)) {
251 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
252 unit->stats.BadData++;
253 goto next_pkt;
255 if (Flags & NV_RX2_CRCERR) {
256 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
257 unit->stats.BadData++;
258 goto next_pkt;
260 if (Flags & NV_RX2_OVERFLOW) {
261 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
262 unit->stats.BadData++;
263 goto next_pkt;
265 if (Flags & NV_RX2_ERROR) {
266 /* framing errors are soft errors, the rest is fatal. */
267 if (Flags & NV_RX2_FRAMINGERR) {
268 if (Flags & NV_RX2_SUBSTRACT1) {
269 len--;
271 } else {
272 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
273 unit->stats.BadData++;
274 goto next_pkt;
277 Flags &= NV_RX2_CHECKSUMMASK;
278 if (Flags == NV_RX2_CHECKSUMOK1 ||
279 Flags == NV_RX2_CHECKSUMOK2 ||
280 Flags == NV_RX2_CHECKSUMOK3) {
281 D(bug("%s: hw checksum hit!.\n", unit->name));
282 } else {
283 D(bug("%s: hwchecksum miss!.\n", unit->name));
287 /* got a valid packet - forward it to the network core */
288 frame = &np->rx_buffer[i];
289 is_orphan = TRUE;
291 /* Dump contents of frame if DEBUG enabled */
292 #ifdef DEBUG
294 int j;
295 for (j=0; j<64; j++) {
296 if ((j%16) == 0)
297 D(bug("\n%03x:", j));
298 D(bug(" %02x", ((unsigned char*)frame)[j]));
300 D(bug("\n"));
302 #endif
304 /* Check for address validity */
305 if(AddressFilter(LIBBASE, unit, frame->eth_packet_dest))
307 /* Packet is addressed to this driver */
308 packet_type = AROS_BE2WORD(frame->eth_packet_type);
310 opener = (APTR)unit->nu_Openers.mlh_Head;
311 opener_tail = (APTR)&unit->nu_Openers.mlh_Tail;
313 /* Offer packet to every opener */
314 while(opener != opener_tail)
316 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
317 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
318 accepted = FALSE;
320 /* Offer packet to each request until it's accepted */
321 while((request != request_tail) && !accepted)
323 if((request->ios2_PacketType == packet_type)
324 || ((request->ios2_PacketType <= ETH_MTU)
325 && (packet_type <= ETH_MTU)))
327 CopyPacket(LIBBASE, unit, request, len, packet_type, frame);
328 accepted = TRUE;
330 request =
331 (struct IOSana2Req *)request->ios2_Req.io_Message.mn_Node.ln_Succ;
334 if(accepted)
335 is_orphan = FALSE;
337 opener = (APTR)opener->node.mln_Succ;
340 /* If packet was unwanted, give it to S2_READORPHAN request */
341 if(is_orphan)
343 unit->stats.UnknownTypesReceived++;
345 if(!IsMsgPortEmpty(unit->request_ports[ADOPT_QUEUE]))
347 CopyPacket(LIBBASE, unit,
348 (APTR)unit->request_ports[ADOPT_QUEUE]->
349 mp_MsgList.lh_Head, len, packet_type, frame);
353 /* Update remaining statistics */
355 tracker =
356 FindTypeStats(LIBBASE, unit, &unit->type_trackers, packet_type);
357 if(tracker != NULL)
359 tracker->stats.PacketsReceived++;
360 tracker->stats.BytesReceived += len;
364 unit->stats.PacketsReceived++;
366 next_pkt:
367 np->cur_rx++;
370 AROS_USERFUNC_EXIT
374 * Check status of packets which we've already sent to the NIC. Update
375 * statistics, and reenable TX queue if only there is some free space.
377 static void nv_tx_done(struct NFUnit *unit)
379 struct fe_priv *np = unit->nu_fe_priv;
380 struct NFBase *NforceBase = unit->nu_device;
381 ULONG Flags;
382 int i;
384 /* Go through tx chain and mark all send packets as free */
385 while (np->nic_tx != np->next_tx)
387 i = np->nic_tx % TX_RING;
389 Flags = AROS_LE2LONG(np->tx_ring[i].FlagLen);
391 D(bug("%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
392 unit->name, np->nic_tx, Flags));
394 if (Flags & NV_TX_VALID)
395 break;
397 if (np->desc_ver == DESC_VER_1) {
398 if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
399 NV_TX_UNDERFLOW|NV_TX_ERROR))
401 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX);
403 else
405 unit->stats.PacketsSent++;
408 else
410 if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
411 NV_TX2_UNDERFLOW|NV_TX2_ERROR))
413 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX);
415 else
417 unit->stats.PacketsSent++;
420 np->nic_tx++;
424 * Do we have some spare space in TX queue and the queue self is blocked?
425 * Reenable it then!
427 if (np->next_tx - np->nic_tx < TX_LIMIT_START) {
428 if (netif_queue_stopped(unit)) {
429 bug("%s: output queue restart\n", unit->name);
430 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
431 netif_wake_queue(unit);
437 * Interrupt generated by Cause() to push new packets into the NIC interface
439 AROS_UFH3(void, TX_Int,
440 AROS_UFHA(struct NFUnit *, unit, A1),
441 AROS_UFHA(APTR, dummy, A5),
442 AROS_UFHA(struct ExecBase *,SysBase, A6))
444 AROS_USERFUNC_INIT
446 struct fe_priv *np = unit->nu_fe_priv;
447 struct NFBase *NforceBase = unit->nu_device;
448 int nr;
449 BOOL proceed = FALSE; /* Fails by default */
451 /* send packet only if there is free space on tx queue. Otherwise do nothing */
452 if (!netif_queue_stopped(unit))
454 UWORD packet_size, data_size;
455 struct NFBase *base;
456 struct IOSana2Req *request;
457 struct Opener *opener;
458 UBYTE *buffer;
459 ULONG wire_error=0;
460 BYTE error;
461 struct MsgPort *port;
462 struct TypeStats *tracker;
464 proceed = TRUE; /* Success by default */
465 base = unit->nu_device;
466 port = unit->request_ports[WRITE_QUEUE];
468 /* Still no error and there are packets to be sent? */
469 while(proceed && (!IsMsgPortEmpty(port)))
471 nr = np->next_tx % TX_RING;
472 error = 0;
474 request = (APTR)port->mp_MsgList.lh_Head;
475 data_size = packet_size = request->ios2_DataLength;
477 opener = (APTR)request->ios2_BufferManagement;
479 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
481 packet_size += ETH_PACKET_DATA;
482 CopyMem(request->ios2_DstAddr, np->tx_buffer[nr].eth_packet_dest, ETH_ADDRESSSIZE);
483 CopyMem(unit->dev_addr, np->tx_buffer[nr].eth_packet_source, ETH_ADDRESSSIZE);
484 np->tx_buffer[nr].eth_packet_type = AROS_WORD2BE(request->ios2_PacketType);
486 buffer = np->tx_buffer[nr].eth_packet_data;
488 else
489 buffer = (UBYTE*)&np->tx_buffer[nr];
491 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
493 error = S2ERR_NO_RESOURCES;
494 wire_error = S2WERR_BUFF_ERROR;
495 ReportEvents(LIBBASE, unit,
496 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
497 | S2EVENT_TX);
500 /* Now the packet is already in TX buffer, update flags for NIC */
501 if (error == 0)
503 Disable();
504 np->tx_ring[nr].FlagLen = AROS_LONG2LE((packet_size-1) | np->tx_flags );
505 D(bug("%s: nv_start_xmit: packet packet %d queued for transmission.",
506 unit->name, np->next_tx));
508 /* DEBUG? Dump frame if so */
509 #ifdef DEBUG
511 int j;
512 for (j=0; j<64; j++) {
513 if ((j%16) == 0)
514 D(bug("\n%03x:", j));
515 D(bug(" %02x", ((unsigned char*)&np->tx_buffer[nr])[j]));
517 D(bug("\n"));
519 #endif
520 np->next_tx++;
523 * If we've just run out of free space on the TX queue, stop
524 * it and give up pushing further frames
526 if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP)
528 bug("%s: output queue full. Stopping\n", unit->name);
529 netif_stop_queue(unit);
530 proceed = FALSE;
532 Enable();
534 * At this place linux driver used to trigger NIC to output
535 * the queued packets through wire. We will not do it as we
536 * may already see if there are new outcomming packets.
538 * Yes, this driver might be a bit faster than linux one.
542 /* Reply packet */
544 request->ios2_Req.io_Error = error;
545 request->ios2_WireError = wire_error;
546 Disable();
547 Remove((APTR)request);
548 Enable();
549 ReplyMsg((APTR)request);
551 /* Update statistics */
553 if(error == 0)
555 tracker = FindTypeStats(LIBBASE, unit, &unit->type_trackers,
556 request->ios2_PacketType);
557 if(tracker != NULL)
559 tracker->stats.PacketsSent++;
560 tracker->stats.BytesSent += packet_size;
566 * Here either we've filled the queue with packets to be transmitted,
567 * or just run out of spare space in TX queue. In both cases tell the
568 * NIC to start transmitting them all through wire.
570 writel(NVREG_TXRXCTL_KICK|np->desc_ver, (UBYTE*)unit->nu_BaseMem + NvRegTxRxControl);
571 pci_push((UBYTE*)unit->nu_BaseMem);
574 /* Was there success? Enable incomming of new packets */
575 if(proceed)
576 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
577 else
578 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
580 AROS_USERFUNC_EXIT
584 * Interrupt used to restart the real one
586 AROS_UFH3(void, TX_End_Int,
587 AROS_UFHA(struct NFUnit *, unit, A1),
588 AROS_UFHA(APTR, dummy, A5),
589 AROS_UFHA(struct ExecBase *,SysBase, A6))
591 AROS_USERFUNC_INIT
593 struct NFUnit *dev = unit;
594 struct fe_priv *np = dev->nu_fe_priv;
595 UBYTE *base = (UBYTE*) dev->nu_BaseMem;
597 Disable();
599 writel(np->irqmask, base + NvRegIrqMask);
600 pci_push(base);
601 dev->nu_irqhandler->h_Code(dev->nu_irqhandler, NULL);
602 Enable();
604 AROS_USERFUNC_EXIT
608 * Maximum number of loops until we assume that a bit in the irq mask
609 * is stuck. Overridable with module param.
611 static const int max_interrupt_work = 5;
614 * Handle timeouts and other strange cases
616 static void NF_TimeoutHandler(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
618 struct NFUnit *dev = (struct NFUnit *) irq->h_Data;
619 struct timeval time;
620 struct Device *TimerBase = dev->nu_TimerSlowReq->tr_node.io_Device;
622 GetSysTime(&time);
625 * If timeout timer is expected, and time elapsed - regenerate the
626 * interrupt handler
628 if (dev->nu_toutNEED && (CmpTime(&time, &dev->nu_toutPOLL ) < 0))
630 dev->nu_toutNEED = FALSE;
631 Cause(&dev->tx_end_int);
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 void NF_IntHandler(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
649 struct NFUnit *dev = (struct NFUnit *) irq->h_Data;
650 struct fe_priv *np = dev->nu_fe_priv;
651 UBYTE *base = (UBYTE*) dev->nu_BaseMem;
652 ULONG events;
653 int i;
654 struct Device *TimerBase = dev->nu_TimerSlowReq->tr_node.io_Device;
655 struct timeval time;
657 GetSysTime(&time);
659 /* Restart automagically :) */
660 for (i=0; ; i++)
662 events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
663 writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
664 pci_push(base);
666 if (!(events & np->irqmask))
667 break;
670 * Some packets have been sent? Just update statistics and empty the
671 * TX queue
673 if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {
674 nv_tx_done(dev);
677 /* Something received? Handle it! */
678 if (events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {
679 AROS_UFC3(void, dev->rx_int.is_Code,
680 AROS_UFCA(APTR, dev->rx_int.is_Data, A1),
681 AROS_UFCA(APTR, dev->rx_int.is_Code, A5),
682 AROS_UFCA(struct ExecBase *, SysBase, A6));
683 /* Mark received frames as free for hardware */
684 dev->alloc_rx(dev);
687 if (events & (NVREG_IRQ_LINK)) {
688 Disable();
689 dev->linkirq(dev);
690 Enable();
693 /* If linktimer interrupt required, handle it here */
694 if (np->need_linktimer && (CmpTime(&time, &np->link_timeout) < 0)) {
695 Disable();
696 dev->linkchange(dev);
697 Enable();
698 np->link_timeout.tv_micro = LINK_TIMEOUT % 1000000;
699 np->link_timeout.tv_secs = LINK_TIMEOUT / 1000000;
700 AddTime(&np->link_timeout, &time);
703 /* Erm? */
704 if (events & (NVREG_IRQ_TX_ERR)) {
705 bug("%s: received irq with events 0x%x. Probably TX fail.\n",
706 dev->name, events);
709 if (events & (NVREG_IRQ_UNKNOWN)) {
710 bug("%s: received irq with unknown events 0x%x. Please report\n",
711 dev->name, events);
715 * Straaaaaaaange, the interrupt was restarted more than
716 * max_interrupt_work times. Normally it should not happen, even on
717 * gigabit ethernet. In any case setup poll handler which restart this
718 * handler after specified amount of time.
720 if (i > max_interrupt_work)
722 bug("%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
723 writel(0, base + NvRegIrqMask);
724 pci_push(base);
726 /* When to wake up? */
727 Disable();
728 dev->nu_toutPOLL.tv_micro = POLL_WAIT % 1000000;
729 dev->nu_toutPOLL.tv_secs = POLL_WAIT / 1000000;
730 AddTime(&dev->nu_toutPOLL, &time);
731 dev->nu_toutNEED = TRUE;
732 Enable();
734 break; /* break the for() loop */
739 * If TX queue was stopped, try to reenable it *ALWAYS*
741 if (netif_queue_stopped(dev)) {
742 nv_tx_done(dev);
746 VOID CopyPacket(struct NFBase *NforceBase, struct NFUnit *unit,
747 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
748 struct eth_frame *buffer)
750 struct Opener *opener;
751 BOOL filtered = FALSE;
752 UBYTE *ptr;
754 /* Set multicast and broadcast flags */
756 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
757 if((*((ULONG *)(buffer->eth_packet_dest)) == 0xffffffff) &&
758 (*((UWORD *)(buffer->eth_packet_dest + 4)) == 0xffff))
759 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
761 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
762 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
764 /* Set source and destination addresses and packet type */
765 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
766 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
767 request->ios2_PacketType = packet_type;
769 /* Adjust for cooked packet request */
771 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
773 packet_size -= ETH_PACKET_DATA;
774 ptr = buffer->eth_packet_data;
776 else
778 ptr = (UBYTE*)buffer;
781 request->ios2_DataLength = packet_size;
783 /* Filter packet */
785 opener = request->ios2_BufferManagement;
786 if((request->ios2_Req.io_Command == CMD_READ) &&
787 (opener->filter_hook != NULL))
788 if(!CallHookPkt(opener->filter_hook, request, ptr))
789 filtered = TRUE;
791 if(!filtered)
793 /* Copy packet into opener's buffer and reply packet */
795 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
797 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
798 request->ios2_WireError = S2WERR_BUFF_ERROR;
799 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
801 Disable();
802 Remove((APTR)request);
803 Enable();
804 ReplyMsg((APTR)request);
808 BOOL AddressFilter(struct NFBase *NforceBase, struct NFUnit *unit, UBYTE *address)
810 struct AddressRange *range, *tail;
811 BOOL accept = TRUE;
812 ULONG address_left;
813 UWORD address_right;
815 /* Check whether address is unicast/broadcast or multicast */
817 address_left = AROS_BE2LONG(*((ULONG *)address));
818 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
820 if((address_left & 0x01000000) != 0 &&
821 !(address_left == 0xffffffff && address_right == 0xffff))
823 /* Check if this multicast address is wanted */
825 range = (APTR)unit->multicast_ranges.mlh_Head;
826 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
827 accept = FALSE;
829 while((range != tail) && !accept)
831 if((address_left > range->lower_bound_left ||
832 (address_left == range->lower_bound_left &&
833 address_right >= range->lower_bound_right)) &&
834 (address_left < range->upper_bound_left ||
835 (address_left == range->upper_bound_left &&
836 address_right <= range->upper_bound_right)))
837 accept = TRUE;
838 range = (APTR)range->node.mln_Succ;
841 if(!accept)
842 unit->special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
844 return accept;
848 * Unit process
850 AROS_UFH3(void, NF_Scheduler,
851 AROS_UFHA(STRPTR, argPtr, A0),
852 AROS_UFHA(ULONG, argSize, D0),
853 AROS_UFHA(struct ExecBase *, SysBase, A6))
855 AROS_USERFUNC_INIT
857 struct NFUnit *dev = FindTask(NULL)->tc_UserData;
858 LIBBASETYPEPTR LIBBASE = dev->nu_device;
859 APTR BattClockBase;
860 struct MsgPort *reply_port, *input;
862 D(bug("[NFORCE] In nforce process\n"));
863 D(bug("[NFORCE] Setting device up\n"));
865 reply_port = CreateMsgPort();
866 input = CreateMsgPort();
868 dev->nu_input_port = input;
870 /* Randomize the generator with current time */
871 BattClockBase = OpenResource("battclock.resource");
872 srandom(ReadBattClock());
874 dev->nu_TimerSlowPort = CreateMsgPort();
876 if (dev->nu_TimerSlowPort)
878 dev->nu_TimerSlowReq = (struct timerequest *)
879 CreateIORequest((struct MsgPort *)dev->nu_TimerSlowPort, sizeof(struct timerequest));
881 if (dev->nu_TimerSlowReq)
883 if (!OpenDevice("timer.device", UNIT_VBLANK,
884 (struct IORequest *)dev->nu_TimerSlowReq, 0))
886 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC|MEMF_CLEAR);
887 ULONG sigset;
889 D(bug("[NFORCE] Got VBLANK unit of timer.device\n"));
891 dev->initialize(dev);
893 msg->mn_ReplyPort = reply_port;
894 msg->mn_Length = sizeof(struct Message);
896 D(bug("[NFORCE] Setup complete. Sending handshake\n"));
897 PutMsg(LIBBASE->nf_syncport, msg);
898 WaitPort(reply_port);
899 GetMsg(reply_port);
901 FreeVec(msg);
903 D(bug("[NFORCE] Forever loop\n"));
905 dev->nu_signal_0 = AllocSignal(-1);
906 dev->nu_signal_1 = AllocSignal(-1);
907 dev->nu_signal_2 = AllocSignal(-1);
908 dev->nu_signal_3 = AllocSignal(-1);
910 sigset = 1 << input->mp_SigBit |
911 1 << dev->nu_signal_0 |
912 1 << dev->nu_signal_1 |
913 1 << dev->nu_signal_2 |
914 1 << dev->nu_signal_3;
915 for(;;)
917 ULONG recvd = Wait(sigset);
918 if (recvd & dev->nu_signal_0)
921 * Shutdown process. Driver should close everything
922 * already and waits for our process to complete. Free
923 * memory allocared here and kindly return.
925 dev->deinitialize(dev);
926 CloseDevice((struct IORequest *)dev->nu_TimerSlowReq);
927 DeleteIORequest((struct IORequest *)dev->nu_TimerSlowReq);
928 DeleteMsgPort(dev->nu_TimerSlowPort);
929 DeleteMsgPort(input);
930 DeleteMsgPort(reply_port);
932 D(bug("[NFORCE] Process shutdown.\n"));
933 return;
935 else if (recvd & (1 << input->mp_SigBit))
937 struct IOSana2Req *io;
939 /* Handle incoming transactions */
940 while ((io = (struct IOSana2Req *)GetMsg(input))!= NULL);
942 ObtainSemaphore(&dev->unit_lock);
943 handle_request(LIBBASE, io);
946 else
948 /* Handle incoming signals */
955 AROS_USERFUNC_EXIT
958 static const struct DriverConfig {
959 ULONG ProductID;
960 ULONG DriverFlags;
961 ULONG DescVer;
962 } Config[] = {
963 { NFORCE_MCPNET1_ID, DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, DESC_VER_1 },
964 { NFORCE_MCPNET2_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_NEED_LASTPACKET1, DESC_VER_1 },
965 { NFORCE_MCPNET3_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_NEED_LASTPACKET1, DESC_VER_1 },
966 { NFORCE_MCPNET4_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
967 { NFORCE_MCPNET5_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
968 { NFORCE_MCPNET6_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
969 { NFORCE_MCPNET7_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
970 { NFORCE_MCPNET8_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
971 { NFORCE_MCPNET9_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
972 { NFORCE_MCPNET10_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
973 { NFORCE_MCPNET11_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
974 { 0, 0 }
978 * Create new nForce ethernet device unit
980 struct NFUnit *CreateUnit(struct NFBase *NforceBase, OOP_Object *pciDevice)
982 struct NFUnit *unit = AllocMem(sizeof(struct NFUnit), MEMF_PUBLIC | MEMF_CLEAR);
983 BOOL success = TRUE;
984 int i;
986 if (unit != NULL)
988 IPTR DeviceID, base, len;
989 OOP_Object *driver;
991 OOP_GetAttr(pciDevice, aHidd_PCIDevice_ProductID, &DeviceID);
992 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&driver);
994 for (i=0; Config[i].ProductID; i++)
996 if (Config[i].ProductID == DeviceID)
998 unit->nu_DriverFlags = Config[i].DriverFlags;
999 unit->nu_fe_priv->desc_ver = Config[i].DescVer;
1000 break;
1004 unit->nu_device = NforceBase;
1005 unit->nu_DeviceID = DeviceID;
1006 unit->mtu = 1500;
1007 unit->nu_PCIDevice = pciDevice;
1008 unit->nu_PCIDriver = driver;
1010 InitSemaphore(&unit->unit_lock);
1011 NEWLIST(&unit->nu_Openers);
1012 NEWLIST(&unit->multicast_ranges);
1013 NEWLIST(&unit->type_trackers);
1015 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->nu_IRQ);
1016 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base1, &unit->nu_BaseIO);
1017 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, &base);
1018 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size0, &len);
1020 unit->nu_BaseMem = (IPTR)HIDD_PCIDriver_MapPCI(driver, (APTR)base, len);
1021 unit->nu_SizeMem = len;
1023 if (unit->nu_BaseMem)
1025 struct TagItem attrs[] = {
1026 { aHidd_PCIDevice_isIO, TRUE },
1027 { aHidd_PCIDevice_isMEM, TRUE },
1028 { aHidd_PCIDevice_isMaster, TRUE },
1029 { TAG_DONE, 0 },
1031 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
1033 unit->name = "[nforce0]";
1034 unit->nu_fe_priv = AllocMem(sizeof(struct fe_priv), MEMF_PUBLIC|MEMF_CLEAR);
1035 unit->nu_UnitNum = 0;
1037 nv_get_functions(unit);
1039 if (unit->nu_fe_priv)
1041 unit->nu_fe_priv->pci_dev = unit;
1042 InitSemaphore(&unit->nu_fe_priv->lock);
1044 unit->nu_irqhandler = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_PUBLIC|MEMF_CLEAR);
1045 unit->nu_touthandler = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_PUBLIC|MEMF_CLEAR);
1047 if (unit->nu_irqhandler && unit->nu_touthandler)
1049 struct Message *msg;
1051 unit->nu_irqhandler->h_Node.ln_Pri = 100;
1052 unit->nu_irqhandler->h_Node.ln_Name = LIBBASE->nf_Device.dd_Library.lib_Node.ln_Name;
1053 unit->nu_irqhandler->h_Code = NF_IntHandler;
1054 unit->nu_irqhandler->h_Data = unit;
1056 unit->nu_touthandler->h_Node.ln_Pri = 100;
1057 unit->nu_touthandler->h_Node.ln_Name = LIBBASE->nf_Device.dd_Library.lib_Node.ln_Name;
1058 unit->nu_touthandler->h_Code = NF_TimeoutHandler;
1059 unit->nu_touthandler->h_Data = unit;
1061 unit->rx_int.is_Node.ln_Name = unit->name;
1062 unit->rx_int.is_Code = 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 = 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 = 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_irqhandler)
1148 FreeMem(Unit->nu_irqhandler, sizeof(HIDDT_IRQ_Handler));
1149 LIBBASE->nf_irq = NULL;
1152 if (Unit->nu_fe_priv)
1154 FreeMem(Unit->nu_fe_priv, sizeof(struct fe_priv));
1155 Unit->nu_fe_priv = NULL;
1158 if (Unit->nu_BaseMem)
1160 HIDD_PCIDriver_UnmapPCI(Unit->nu_PCIDriver,
1161 (APTR)Unit->nu_BaseMem,
1162 Unit->nu_SizeMem);
1165 FreeMem(Unit, sizeof(struct NFUnit));
1169 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct NFUnit *unit,
1170 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
1172 struct AddressRange *range, *tail;
1173 BOOL found = FALSE;
1175 range = (APTR)unit->multicast_ranges.mlh_Head;
1176 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1178 while((range != tail) && !found)
1180 if((lower_bound_left == range->lower_bound_left) &&
1181 (lower_bound_right == range->lower_bound_right) &&
1182 (upper_bound_left == range->upper_bound_left) &&
1183 (upper_bound_right == range->upper_bound_right))
1184 found = TRUE;
1185 else
1186 range = (APTR)range->node.mln_Succ;
1189 if(!found)
1190 range = NULL;
1192 return range;
1195 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct NFUnit *unit, const UBYTE *lower_bound,
1196 const UBYTE *upper_bound)
1198 struct AddressRange *range;
1199 ULONG lower_bound_left, upper_bound_left;
1200 UWORD lower_bound_right, upper_bound_right;
1202 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1203 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1204 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1205 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1207 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1208 upper_bound_left, upper_bound_right);
1210 if(range != NULL)
1211 range->add_count++;
1212 else
1214 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1215 if(range != NULL)
1217 range->lower_bound_left = lower_bound_left;
1218 range->lower_bound_right = lower_bound_right;
1219 range->upper_bound_left = upper_bound_left;
1220 range->upper_bound_right = upper_bound_right;
1221 range->add_count = 1;
1223 Disable();
1224 AddTail((APTR)&unit->multicast_ranges, (APTR)range);
1225 Enable();
1227 if (unit->range_count++ == 0)
1229 unit->flags |= IFF_ALLMULTI;
1230 unit->set_multicast(unit);
1235 return range != NULL;
1238 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE, struct NFUnit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
1240 struct AddressRange *range;
1241 ULONG lower_bound_left, upper_bound_left;
1242 UWORD lower_bound_right, upper_bound_right;
1244 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1245 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1246 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1247 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1249 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1250 upper_bound_left, upper_bound_right);
1252 if(range != NULL)
1254 if(--range->add_count == 0)
1256 Disable();
1257 Remove((APTR)range);
1258 Enable();
1259 FreeMem(range, sizeof(struct AddressRange));
1261 if (--unit->range_count == 0)
1263 unit->flags &= ~IFF_ALLMULTI;
1264 unit->set_multicast(unit);
1268 return range != NULL;