Fixed my network drivers to work with ABIv1 (apart from prism2.device, which
[AROS.git] / workbench / devs / networks / nForce / unit.c
blob808e6ad1a5cd62a05afe8bac9da424b09eb0450f
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 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 IOSana2Req *request;
456 struct Opener *opener;
457 UBYTE *buffer;
458 ULONG wire_error=0;
459 BYTE error;
460 struct MsgPort *port;
461 struct TypeStats *tracker;
463 proceed = TRUE; /* Success by default */
464 port = unit->request_ports[WRITE_QUEUE];
466 /* Still no error and there are packets to be sent? */
467 while(proceed && (!IsMsgPortEmpty(port)))
469 nr = np->next_tx % TX_RING;
470 error = 0;
472 request = (APTR)port->mp_MsgList.lh_Head;
473 data_size = packet_size = request->ios2_DataLength;
475 opener = (APTR)request->ios2_BufferManagement;
477 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
479 packet_size += ETH_PACKET_DATA;
480 CopyMem(request->ios2_DstAddr, np->tx_buffer[nr].eth_packet_dest, ETH_ADDRESSSIZE);
481 CopyMem(unit->dev_addr, np->tx_buffer[nr].eth_packet_source, ETH_ADDRESSSIZE);
482 np->tx_buffer[nr].eth_packet_type = AROS_WORD2BE(request->ios2_PacketType);
484 buffer = np->tx_buffer[nr].eth_packet_data;
486 else
487 buffer = (UBYTE*)&np->tx_buffer[nr];
489 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
491 error = S2ERR_NO_RESOURCES;
492 wire_error = S2WERR_BUFF_ERROR;
493 ReportEvents(LIBBASE, unit,
494 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
495 | S2EVENT_TX);
498 /* Now the packet is already in TX buffer, update flags for NIC */
499 if (error == 0)
501 Disable();
502 np->tx_ring[nr].FlagLen = AROS_LONG2LE((packet_size-1) | np->tx_flags );
503 D(bug("%s: nv_start_xmit: packet packet %d queued for transmission.",
504 unit->name, np->next_tx));
506 /* DEBUG? Dump frame if so */
507 #ifdef DEBUG
509 int j;
510 for (j=0; j<64; j++) {
511 if ((j%16) == 0)
512 D(bug("\n%03x:", j));
513 D(bug(" %02x", ((unsigned char*)&np->tx_buffer[nr])[j]));
515 D(bug("\n"));
517 #endif
518 np->next_tx++;
521 * If we've just run out of free space on the TX queue, stop
522 * it and give up pushing further frames
524 if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP)
526 bug("%s: output queue full. Stopping\n", unit->name);
527 netif_stop_queue(unit);
528 proceed = FALSE;
530 Enable();
532 * At this place linux driver used to trigger NIC to output
533 * the queued packets through wire. We will not do it as we
534 * may already see if there are new outcomming packets.
536 * Yes, this driver might be a bit faster than linux one.
540 /* Reply packet */
542 request->ios2_Req.io_Error = error;
543 request->ios2_WireError = wire_error;
544 Disable();
545 Remove((APTR)request);
546 Enable();
547 ReplyMsg((APTR)request);
549 /* Update statistics */
551 if(error == 0)
553 tracker = FindTypeStats(LIBBASE, unit, &unit->type_trackers,
554 request->ios2_PacketType);
555 if(tracker != NULL)
557 tracker->stats.PacketsSent++;
558 tracker->stats.BytesSent += packet_size;
564 * Here either we've filled the queue with packets to be transmitted,
565 * or just run out of spare space in TX queue. In both cases tell the
566 * NIC to start transmitting them all through wire.
568 writel(NVREG_TXRXCTL_KICK|np->desc_ver, (UBYTE*)unit->nu_BaseMem + NvRegTxRxControl);
569 pci_push((UBYTE*)unit->nu_BaseMem);
572 /* Was there success? Enable incomming of new packets */
573 if(proceed)
574 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
575 else
576 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
578 AROS_USERFUNC_EXIT
582 * Interrupt used to restart the real one
584 AROS_UFH3(void, TX_End_Int,
585 AROS_UFHA(struct NFUnit *, unit, A1),
586 AROS_UFHA(APTR, dummy, A5),
587 AROS_UFHA(struct ExecBase *,SysBase, A6))
589 AROS_USERFUNC_INIT
591 struct NFUnit *dev = unit;
592 struct fe_priv *np = dev->nu_fe_priv;
593 UBYTE *base = (UBYTE*) dev->nu_BaseMem;
595 Disable();
597 writel(np->irqmask, base + NvRegIrqMask);
598 pci_push(base);
599 dev->nu_irqhandler->h_Code(dev->nu_irqhandler, NULL);
600 Enable();
602 AROS_USERFUNC_EXIT
606 * Maximum number of loops until we assume that a bit in the irq mask
607 * is stuck. Overridable with module param.
609 static const int max_interrupt_work = 5;
612 * Handle timeouts and other strange cases
614 static void NF_TimeoutHandler(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
616 struct NFUnit *dev = (struct NFUnit *) irq->h_Data;
617 struct timeval time;
618 struct Device *TimerBase = dev->nu_TimerSlowReq->tr_node.io_Device;
620 GetSysTime(&time);
623 * If timeout timer is expected, and time elapsed - regenerate the
624 * interrupt handler
626 if (dev->nu_toutNEED && (CmpTime(&time, &dev->nu_toutPOLL ) < 0))
628 dev->nu_toutNEED = FALSE;
629 Cause(&dev->tx_end_int);
634 * The interrupt handler - schedules code execution to proper handlers depending
635 * on the message from nForce.
637 * NOTE.
639 * Don't be surprised - this driver used to restart itself several times, in
640 * order to handle events which occur when the driver was handling previous
641 * events. It reduces the latency and amount of dropped packets. Additionally,
642 * this interrupt may put itself into deep sleep (or just quit) and restarts
643 * after certain amount of time (POLL_WAIT).
645 static void NF_IntHandler(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
647 struct NFUnit *dev = (struct NFUnit *) irq->h_Data;
648 struct fe_priv *np = dev->nu_fe_priv;
649 UBYTE *base = (UBYTE*) dev->nu_BaseMem;
650 ULONG events;
651 int i;
652 struct Device *TimerBase = dev->nu_TimerSlowReq->tr_node.io_Device;
653 struct timeval time;
655 GetSysTime(&time);
657 /* Restart automagically :) */
658 for (i=0; ; i++)
660 events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
661 writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
662 pci_push(base);
664 if (!(events & np->irqmask))
665 break;
668 * Some packets have been sent? Just update statistics and empty the
669 * TX queue
671 if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) {
672 nv_tx_done(dev);
675 /* Something received? Handle it! */
676 if (events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) {
677 AROS_UFC3(void, dev->rx_int.is_Code,
678 AROS_UFCA(APTR, dev->rx_int.is_Data, A1),
679 AROS_UFCA(APTR, dev->rx_int.is_Code, A5),
680 AROS_UFCA(struct ExecBase *, SysBase, A6));
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);
744 VOID CopyPacket(struct NFBase *NforceBase, struct NFUnit *unit,
745 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
746 struct eth_frame *buffer)
748 struct Opener *opener;
749 BOOL filtered = FALSE;
750 UBYTE *ptr;
751 const UBYTE broadcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
753 /* Set multicast and broadcast flags */
755 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
756 if(memcmp(buffer->eth_packet_dest, broadcast, 6) == 0)
757 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
759 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
760 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
762 /* Set source and destination addresses and packet type */
763 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
764 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
765 request->ios2_PacketType = packet_type;
767 /* Adjust for cooked packet request */
769 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
771 packet_size -= ETH_PACKET_DATA;
772 ptr = buffer->eth_packet_data;
774 else
776 ptr = (UBYTE*)buffer;
779 request->ios2_DataLength = packet_size;
781 /* Filter packet */
783 opener = request->ios2_BufferManagement;
784 if((request->ios2_Req.io_Command == CMD_READ) &&
785 (opener->filter_hook != NULL))
786 if(!CallHookPkt(opener->filter_hook, request, ptr))
787 filtered = TRUE;
789 if(!filtered)
791 /* Copy packet into opener's buffer and reply packet */
793 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
795 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
796 request->ios2_WireError = S2WERR_BUFF_ERROR;
797 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
799 Disable();
800 Remove((APTR)request);
801 Enable();
802 ReplyMsg((APTR)request);
806 BOOL AddressFilter(struct NFBase *NforceBase, struct NFUnit *unit, UBYTE *address)
808 struct AddressRange *range, *tail;
809 BOOL accept = TRUE;
810 ULONG address_left;
811 UWORD address_right;
813 /* Check whether address is unicast/broadcast or multicast */
815 address_left = AROS_BE2LONG(*((ULONG *)address));
816 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
818 if((address_left & 0x01000000) != 0 &&
819 !(address_left == 0xffffffff && address_right == 0xffff))
821 /* Check if this multicast address is wanted */
823 range = (APTR)unit->multicast_ranges.mlh_Head;
824 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
825 accept = FALSE;
827 while((range != tail) && !accept)
829 if((address_left > range->lower_bound_left ||
830 (address_left == range->lower_bound_left &&
831 address_right >= range->lower_bound_right)) &&
832 (address_left < range->upper_bound_left ||
833 (address_left == range->upper_bound_left &&
834 address_right <= range->upper_bound_right)))
835 accept = TRUE;
836 range = (APTR)range->node.mln_Succ;
839 if(!accept)
840 unit->special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
842 return accept;
846 * Unit process
848 AROS_UFH3(void, NF_Scheduler,
849 AROS_UFHA(STRPTR, argPtr, A0),
850 AROS_UFHA(ULONG, argSize, D0),
851 AROS_UFHA(struct ExecBase *, SysBase, A6))
853 AROS_USERFUNC_INIT
855 struct NFUnit *dev = FindTask(NULL)->tc_UserData;
856 LIBBASETYPEPTR LIBBASE = dev->nu_device;
857 APTR BattClockBase;
858 struct MsgPort *reply_port, *input;
860 D(bug("[NFORCE] In nforce process\n"));
861 D(bug("[NFORCE] Setting device up\n"));
863 reply_port = CreateMsgPort();
864 input = CreateMsgPort();
866 dev->nu_input_port = input;
868 /* Randomize the generator with current time */
869 BattClockBase = OpenResource("battclock.resource");
870 srandom(ReadBattClock());
872 dev->nu_TimerSlowPort = CreateMsgPort();
874 if (dev->nu_TimerSlowPort)
876 dev->nu_TimerSlowReq = (struct timerequest *)
877 CreateIORequest((struct MsgPort *)dev->nu_TimerSlowPort, sizeof(struct timerequest));
879 if (dev->nu_TimerSlowReq)
881 if (!OpenDevice("timer.device", UNIT_VBLANK,
882 (struct IORequest *)dev->nu_TimerSlowReq, 0))
884 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC|MEMF_CLEAR);
885 ULONG sigset;
887 D(bug("[NFORCE] Got VBLANK unit of timer.device\n"));
889 dev->initialize(dev);
891 msg->mn_ReplyPort = reply_port;
892 msg->mn_Length = sizeof(struct Message);
894 D(bug("[NFORCE] Setup complete. Sending handshake\n"));
895 PutMsg(LIBBASE->nf_syncport, msg);
896 WaitPort(reply_port);
897 GetMsg(reply_port);
899 FreeVec(msg);
901 D(bug("[NFORCE] Forever loop\n"));
903 dev->nu_signal_0 = AllocSignal(-1);
904 dev->nu_signal_1 = AllocSignal(-1);
905 dev->nu_signal_2 = AllocSignal(-1);
906 dev->nu_signal_3 = AllocSignal(-1);
908 sigset = 1 << input->mp_SigBit |
909 1 << dev->nu_signal_0 |
910 1 << dev->nu_signal_1 |
911 1 << dev->nu_signal_2 |
912 1 << dev->nu_signal_3;
913 for(;;)
915 ULONG recvd = Wait(sigset);
916 if (recvd & dev->nu_signal_0)
919 * Shutdown process. Driver should close everything
920 * already and waits for our process to complete. Free
921 * memory allocared here and kindly return.
923 dev->deinitialize(dev);
924 CloseDevice((struct IORequest *)dev->nu_TimerSlowReq);
925 DeleteIORequest((struct IORequest *)dev->nu_TimerSlowReq);
926 DeleteMsgPort(dev->nu_TimerSlowPort);
927 DeleteMsgPort(input);
928 DeleteMsgPort(reply_port);
930 D(bug("[NFORCE] Process shutdown.\n"));
931 return;
933 else if (recvd & (1 << input->mp_SigBit))
935 struct IOSana2Req *io;
937 /* Handle incoming transactions */
938 while ((io = (struct IOSana2Req *)GetMsg(input))!= NULL);
940 ObtainSemaphore(&dev->unit_lock);
941 handle_request(LIBBASE, io);
944 else
946 /* Handle incoming signals */
953 AROS_USERFUNC_EXIT
956 static const struct DriverConfig {
957 ULONG ProductID;
958 ULONG DriverFlags;
959 ULONG DescVer;
960 } Config[] = {
961 { NFORCE_MCPNET1_ID, DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, DESC_VER_1 },
962 { NFORCE_MCPNET2_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_NEED_LASTPACKET1, DESC_VER_1 },
963 { NFORCE_MCPNET3_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_NEED_LASTPACKET1, DESC_VER_1 },
964 { NFORCE_MCPNET4_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
965 { NFORCE_MCPNET5_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
966 { NFORCE_MCPNET6_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
967 { NFORCE_MCPNET7_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
968 { NFORCE_MCPNET8_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
969 { NFORCE_MCPNET9_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
970 { NFORCE_MCPNET10_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
971 { NFORCE_MCPNET11_ID, DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LASTPACKET1, DESC_VER_2 },
972 { 0, 0 }
976 * Create new nForce ethernet device unit
978 struct NFUnit *CreateUnit(struct NFBase *NforceBase, OOP_Object *pciDevice)
980 struct NFUnit *unit = AllocMem(sizeof(struct NFUnit), MEMF_PUBLIC | MEMF_CLEAR);
981 BOOL success = TRUE;
982 int i;
984 if (unit != NULL)
986 IPTR DeviceID, base, len;
987 OOP_Object *driver;
989 OOP_GetAttr(pciDevice, aHidd_PCIDevice_ProductID, &DeviceID);
990 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&driver);
992 for (i=0; Config[i].ProductID; i++)
994 if (Config[i].ProductID == DeviceID)
996 unit->nu_DriverFlags = Config[i].DriverFlags;
997 unit->nu_fe_priv->desc_ver = Config[i].DescVer;
998 break;
1002 unit->nu_device = NforceBase;
1003 unit->nu_DeviceID = DeviceID;
1004 unit->mtu = 1500;
1005 unit->nu_PCIDevice = pciDevice;
1006 unit->nu_PCIDriver = driver;
1008 InitSemaphore(&unit->unit_lock);
1009 NEWLIST(&unit->nu_Openers);
1010 NEWLIST(&unit->multicast_ranges);
1011 NEWLIST(&unit->type_trackers);
1013 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->nu_IRQ);
1014 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base1, &unit->nu_BaseIO);
1015 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, &base);
1016 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size0, &len);
1018 unit->nu_BaseMem = (IPTR)HIDD_PCIDriver_MapPCI(driver, (APTR)base, len);
1019 unit->nu_SizeMem = len;
1021 if (unit->nu_BaseMem)
1023 struct TagItem attrs[] = {
1024 { aHidd_PCIDevice_isIO, TRUE },
1025 { aHidd_PCIDevice_isMEM, TRUE },
1026 { aHidd_PCIDevice_isMaster, TRUE },
1027 { TAG_DONE, 0 },
1029 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
1031 unit->name = "[nforce0]";
1032 unit->nu_fe_priv = AllocMem(sizeof(struct fe_priv), MEMF_PUBLIC|MEMF_CLEAR);
1033 unit->nu_UnitNum = 0;
1035 nv_get_functions(unit);
1037 if (unit->nu_fe_priv)
1039 unit->nu_fe_priv->pci_dev = unit;
1040 InitSemaphore(&unit->nu_fe_priv->lock);
1042 unit->nu_irqhandler = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_PUBLIC|MEMF_CLEAR);
1043 unit->nu_touthandler = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_PUBLIC|MEMF_CLEAR);
1045 if (unit->nu_irqhandler && unit->nu_touthandler)
1047 struct Message *msg;
1049 unit->nu_irqhandler->h_Node.ln_Pri = 100;
1050 unit->nu_irqhandler->h_Node.ln_Name = LIBBASE->nf_Device.dd_Library.lib_Node.ln_Name;
1051 unit->nu_irqhandler->h_Code = NF_IntHandler;
1052 unit->nu_irqhandler->h_Data = unit;
1054 unit->nu_touthandler->h_Node.ln_Pri = 100;
1055 unit->nu_touthandler->h_Node.ln_Name = LIBBASE->nf_Device.dd_Library.lib_Node.ln_Name;
1056 unit->nu_touthandler->h_Code = NF_TimeoutHandler;
1057 unit->nu_touthandler->h_Data = unit;
1059 unit->rx_int.is_Node.ln_Name = unit->name;
1060 unit->rx_int.is_Code = RX_Int;
1061 unit->rx_int.is_Data = unit;
1063 unit->tx_int.is_Node.ln_Name = unit->name;
1064 unit->tx_int.is_Code = TX_Int;
1065 unit->tx_int.is_Data = unit;
1067 unit->tx_end_int.is_Node.ln_Name = unit->name;
1068 unit->tx_end_int.is_Code = TX_End_Int;
1069 unit->tx_end_int.is_Data = unit;
1071 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1073 struct MsgPort *port = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR);
1074 unit->request_ports[i] = port;
1076 if (port == NULL) success = FALSE;
1078 if (success)
1080 NEWLIST(&port->mp_MsgList);
1081 port->mp_Flags = PA_IGNORE;
1082 port->mp_SigTask = &unit->tx_int;
1086 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
1088 if (success)
1090 LIBBASE->nf_syncport = CreateMsgPort();
1092 unit->nu_Process = CreateNewProcTags(
1093 NP_Entry, (IPTR)NF_Scheduler,
1094 NP_Name, NFORCE_TASK_NAME,
1095 NP_Priority, 0,
1096 NP_UserData, (IPTR)unit,
1097 NP_StackSize, 140960,
1098 TAG_DONE);
1100 WaitPort(LIBBASE->nf_syncport);
1101 msg = GetMsg(LIBBASE->nf_syncport);
1102 ReplyMsg(msg);
1103 DeleteMsgPort(LIBBASE->nf_syncport);
1105 D(bug("[nforce] Unit up and running\n"));
1107 return unit;
1112 else
1113 D(bug("[nforce] PANIC! Couldn't get MMIO area. Aborting\n"));
1116 DeleteUnit(NforceBase, unit);
1117 return NULL;
1121 * DeleteUnit - removes selected unit. Frees all resources and structures.
1123 * The caller should be sure, that given unit is really ready to be freed.
1126 void DeleteUnit(struct NFBase *NforceBase, struct NFUnit *Unit)
1128 int i;
1129 if (Unit)
1131 if (Unit->nu_Process)
1133 Signal(&Unit->nu_Process->pr_Task, Unit->nu_signal_0);
1136 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1138 if (Unit->request_ports[i] != NULL)
1139 FreeMem(Unit->request_ports[i], sizeof(struct MsgPort));
1141 Unit->request_ports[i] = NULL;
1144 if (Unit->nu_irqhandler)
1146 FreeMem(Unit->nu_irqhandler, sizeof(HIDDT_IRQ_Handler));
1147 LIBBASE->nf_irq = NULL;
1150 if (Unit->nu_fe_priv)
1152 FreeMem(Unit->nu_fe_priv, sizeof(struct fe_priv));
1153 Unit->nu_fe_priv = NULL;
1156 if (Unit->nu_BaseMem)
1158 HIDD_PCIDriver_UnmapPCI(Unit->nu_PCIDriver,
1159 (APTR)Unit->nu_BaseMem,
1160 Unit->nu_SizeMem);
1163 FreeMem(Unit, sizeof(struct NFUnit));
1167 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct NFUnit *unit,
1168 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
1170 struct AddressRange *range, *tail;
1171 BOOL found = FALSE;
1173 range = (APTR)unit->multicast_ranges.mlh_Head;
1174 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1176 while((range != tail) && !found)
1178 if((lower_bound_left == range->lower_bound_left) &&
1179 (lower_bound_right == range->lower_bound_right) &&
1180 (upper_bound_left == range->upper_bound_left) &&
1181 (upper_bound_right == range->upper_bound_right))
1182 found = TRUE;
1183 else
1184 range = (APTR)range->node.mln_Succ;
1187 if(!found)
1188 range = NULL;
1190 return range;
1193 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct NFUnit *unit, const UBYTE *lower_bound,
1194 const UBYTE *upper_bound)
1196 struct AddressRange *range;
1197 ULONG lower_bound_left, upper_bound_left;
1198 UWORD lower_bound_right, upper_bound_right;
1200 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1201 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1202 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1203 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1205 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1206 upper_bound_left, upper_bound_right);
1208 if(range != NULL)
1209 range->add_count++;
1210 else
1212 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1213 if(range != NULL)
1215 range->lower_bound_left = lower_bound_left;
1216 range->lower_bound_right = lower_bound_right;
1217 range->upper_bound_left = upper_bound_left;
1218 range->upper_bound_right = upper_bound_right;
1219 range->add_count = 1;
1221 Disable();
1222 AddTail((APTR)&unit->multicast_ranges, (APTR)range);
1223 Enable();
1225 if (unit->range_count++ == 0)
1227 unit->flags |= IFF_ALLMULTI;
1228 unit->set_multicast(unit);
1233 return range != NULL;
1236 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE, struct NFUnit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
1238 struct AddressRange *range;
1239 ULONG lower_bound_left, upper_bound_left;
1240 UWORD lower_bound_right, upper_bound_right;
1242 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1243 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1244 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1245 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1247 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1248 upper_bound_left, upper_bound_right);
1250 if(range != NULL)
1252 if(--range->add_count == 0)
1254 Disable();
1255 Remove((APTR)range);
1256 Enable();
1257 FreeMem(range, sizeof(struct AddressRange));
1259 if (--unit->range_count == 0)
1261 unit->flags &= ~IFF_ALLMULTI;
1262 unit->set_multicast(unit);
1266 return range != NULL;