Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / devs / networks / via-rhine / unit.c
blob44c3e42b7f73d82212f2139b05b5d4887f1555ea
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 #include <exec/types.h>
23 #include <exec/resident.h>
24 #include <exec/io.h>
25 #include <exec/ports.h>
26 #include <exec/errors.h>
28 #include <aros/io.h>
30 #include <devices/sana2.h>
31 #include <devices/sana2specialstats.h>
32 #include <devices/newstyle.h>
33 #include <devices/timer.h>
35 #include <utility/utility.h>
36 #include <utility/tagitem.h>
37 #include <utility/hooks.h>
39 #include <proto/exec.h>
40 #include <proto/dos.h>
41 #include <proto/oop.h>
42 #include <proto/timer.h>
43 #include <proto/utility.h>
45 #include <stdlib.h>
46 #include <stdio.h>
48 #include "via-rhine.h"
49 #include "unit.h"
50 #include LC_LIBDEFS_FILE
53 * Report incoming events to all hyphotetical event receivers
55 VOID ReportEvents(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *unit, ULONG events)
57 struct IOSana2Req *request, *tail, *next_request;
58 struct List *list;
60 list = &unit->rhineu_request_ports[EVENT_QUEUE]->mp_MsgList;
61 next_request = (APTR)list->lh_Head;
62 tail = (APTR)&list->lh_Tail;
64 /* Go through list of event listeners. If send messages to receivers if event found */
65 Disable();
66 while(next_request != tail)
68 request = next_request;
69 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
71 if((request->ios2_WireError&events) != 0)
73 request->ios2_WireError = events;
74 Remove((APTR)request);
75 ReplyMsg((APTR)request);
78 Enable();
80 return;
83 struct TypeStats *FindTypeStats(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *unit,
84 struct MinList *list, ULONG packet_type)
86 struct TypeStats *stats, *tail;
87 BOOL found = FALSE;
89 stats = (APTR)list->mlh_Head;
90 tail = (APTR)&list->mlh_Tail;
92 while(stats != tail && !found)
94 if(stats->packet_type == packet_type)
95 found = TRUE;
96 else
97 stats = (APTR)stats->node.mln_Succ;
100 if(!found)
101 stats = NULL;
103 return stats;
106 void FlushUnit(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit, UBYTE last_queue, BYTE error)
108 struct IORequest *request;
109 UBYTE i;
110 struct Opener *opener, *tail;
112 D(bug("%s unit.FlushUnit\n", unit->rhineu_name));
114 /* Abort queued operations */
116 for (i=0; i <= last_queue; i++)
118 while ((request = (APTR)GetMsg(unit->rhineu_request_ports[i])) != NULL)
120 request->io_Error = IOERR_ABORTED;
121 ReplyMsg((struct Message *)request);
125 opener = (APTR)unit->rhineu_Openers.mlh_Head;
126 tail = (APTR)&unit->rhineu_Openers.mlh_Tail;
128 /* Flush every opener's read queue */
130 while(opener != tail)
132 while ((request = (APTR)GetMsg(&opener->read_port)) != NULL)
134 request->io_Error = error;
135 ReplyMsg((struct Message *)request);
137 opener = (struct Opener *)opener->node.mln_Succ;
142 * Interrupt handler called whenever RTL8139 NIC interface generates interrupt.
143 * It's duty is to iterate throgh RX queue searching for new packets.
145 * Please note, that allthough multicast support could be done on interface
146 * basis, it is done in this function as result of quick integration of both
147 * the forcedeth driver (IFF_ALLMULTI flag) and etherling3 driver (AddressMatch
148 * filter function).
150 AROS_INTH1(VIARHINE_RX_IntF, struct VIARHINEUnit *, unit)
152 AROS_INTFUNC_INIT
154 struct VIARHINEBase *VIARHINEDeviceBase = unit->rhineu_device;
155 struct fe_priv *np = unit->rhineu_fe_priv;
156 // UWORD Flags;
157 struct TypeStats *tracker;
158 ULONG packet_type;
159 struct Opener *opener, *opener_tail;
160 struct IOSana2Req *request, *request_tail;
161 BOOL accepted, is_orphan;
163 UBYTE *base = (UBYTE*) unit->rhineu_BaseMem;
165 int count = 0;
167 D(bug("%s: VIARHINE_RX_IntF() !!!!\n", unit->rhineu_name));
169 /* Endless loop, with break from inside */
170 for(;;)
172 int i, len=0;
173 struct eth_frame *frame;
175 if (count >= RX_RING_SIZE)
176 break; /* we scanned the whole ring - do not continue */
178 /* Get the in-queue number */
179 i = np->cur_rx % RX_RING_SIZE;
181 /* Do we own the packet or the chipset? */
182 if (np->rx_desc[i].rx_status & DescOwn)
184 //D(bug("%s: VIARHINE_RX_IntF: buffer %d owned by chipset\n", unit->rhineu_name, i));
185 //goto next_pkt; // still owned by hardware,
186 break;
189 if (np->rx_desc[i].rx_status & RxErr)
191 D(bug("%s: VIARHINE_RX_IntF: buffer %d has recieve error! skipping..\n", unit->rhineu_name, i));
192 goto next_pkt; // still owned by hardware,
195 if (!(np->rx_desc[i].rx_status & RxWholePkt))
197 D(bug("%s: VIARHINE_RX_IntF: buffer %d has recieved oversized packet! skipping..\n", unit->rhineu_name, i));
198 goto next_pkt; // still owned by hardware,
201 if (np->rx_desc[i].rx_status & RxOK)
203 D(bug("%s: VIARHINE_RX_IntF: packet in buffer %d was successfully recieved.\n", unit->rhineu_name, i));
206 D(bug("%s: VIARHINE_RX_IntF: buffer %d @ %x is for us\n", unit->rhineu_name, i, np->rx_desc[i].addr));
207 /* the packet is for us - get it */
209 /* got a valid packet - forward it to the network core */
210 frame = (struct eth_frame *)(IPTR)np->rx_desc[i].addr;
211 is_orphan = TRUE;
213 /* Dump contents of frame if DEBUG enabled */
214 #ifdef DEBUG
216 int j;
217 for (j=0; j<64; j++) {
218 if ((j%16) == 0)
219 D(bug("\n%03x:", j));
220 D(bug(" %02x", ((unsigned char*)frame)[j]));
222 D(bug("\n"));
224 #endif
226 /* Check for address validity */
227 if(AddressFilter(LIBBASE, unit, frame->eth_packet_dest))
229 /* Packet is addressed to this driver */
230 len = (np->rx_desc[i].rx_status >> 16)-4;
232 packet_type = AROS_BE2WORD(frame->eth_packet_type);
233 D(bug("%s: VIARHINE_RX_IntF: Packet IP accepted with type = %d, len = %d, desc_length = %d\n", unit->rhineu_name, packet_type, len, np->rx_desc[i].desc_length));
235 opener = (APTR)unit->rhineu_Openers.mlh_Head;
236 opener_tail = (APTR)&unit->rhineu_Openers.mlh_Tail;
238 /* Offer packet to every opener */
239 while(opener != opener_tail)
241 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
242 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
243 accepted = FALSE;
245 /* Offer packet to each request until it's accepted */
246 while((request != request_tail) && !accepted)
248 if((request->ios2_PacketType == packet_type)
249 || ((request->ios2_PacketType <= ETH_MTU)
250 && (packet_type <= ETH_MTU)))
252 D(bug("%s: VIARHINE_RX_IntF: copy packet for opener ..\n", unit->rhineu_name));
253 CopyPacket(LIBBASE, unit, request, len, packet_type, frame);
254 accepted = TRUE;
256 request =
257 (struct IOSana2Req *)request->ios2_Req.io_Message.mn_Node.ln_Succ;
259 if(accepted)
260 is_orphan = FALSE;
262 opener = (APTR)opener->node.mln_Succ;
265 /* If packet was unwanted, give it to S2_READORPHAN request */
266 if(is_orphan)
268 unit->rhineu_stats.UnknownTypesReceived++;
270 if(!IsMsgPortEmpty(unit->rhineu_request_ports[ADOPT_QUEUE]))
272 CopyPacket(LIBBASE, unit,
273 (APTR)unit->rhineu_request_ports[ADOPT_QUEUE]->
274 mp_MsgList.lh_Head, len, packet_type, frame);
275 D(bug("%s: VIARHINE_RX_IntF: packet copied to orphan queue\n", unit->rhineu_name));
278 np->rx_desc[i].desc_length = MAX_FRAME_SIZE; //Set the buffer size back to max (before enabling it)
279 np->rx_desc[i].rx_status = DescOwn;
281 WORDOUT(base, CmdRxDemand | np->cmd);
283 /* Update remaining statistics */
285 tracker =
286 FindTypeStats(LIBBASE, unit, &unit->rhineu_type_trackers, packet_type);
288 if(tracker != NULL)
290 tracker->stats.PacketsReceived++;
291 tracker->stats.BytesReceived += len;
295 unit->rhineu_stats.PacketsReceived++;
296 // ((struct rx_ring_desc *)np->ring_addr)[i].BufferStatus = AROS_WORD2LE((1 << 8)|(1 << 9)|(1 << 15)); // Mark packet as available again
298 next_pkt:
299 np->cur_rx++;
300 count++;
303 return FALSE;
305 AROS_INTFUNC_EXIT
309 * Interrupt generated by Cause() to push new packets into the NIC interface
311 AROS_INTH1(VIARHINE_TX_IntF, struct VIARHINEUnit *, unit)
313 AROS_INTFUNC_INIT
315 struct fe_priv *np = unit->rhineu_fe_priv;
316 struct VIARHINEBase *VIARHINEDeviceBase = unit->rhineu_device;
317 int nr, try_count=1;
318 BOOL proceed = FALSE; /* Fails by default */
320 D(bug("%s: VIARHINE_TX_IntF()\n", unit->rhineu_name));
322 /* send packet only if there is free space on tx queue. Otherwise do nothing */
323 if (!netif_queue_stopped(unit))
325 UWORD packet_size, data_size;
326 struct IOSana2Req *request;
327 struct Opener *opener;
328 UBYTE *buffer;
329 ULONG wire_error=0;
330 BYTE error;
331 struct MsgPort *port;
332 struct TypeStats *tracker;
334 proceed = TRUE; /* Success by default */
335 UBYTE *base = (UBYTE*) unit->rhineu_BaseMem;
336 port = unit->rhineu_request_ports[WRITE_QUEUE];
338 /* Still no error and there are packets to be sent? */
339 while(proceed && (!IsMsgPortEmpty(port)))
341 rhine_nexttx:
342 if (try_count >= (TX_BUFFERS * 3))
344 /* TODO: We should probably report that we couldnt send the packet here.. */
345 D(bug("%s: VIARHINE_TX_IntF: Send FAILED! no free Tx buffer(s)\n", unit->rhineu_name));
346 break;
349 nr = np->tx_current % TX_BUFFERS;
350 np->tx_current++;
352 if (np->tx_desc[nr].tx_status & DescOwn)
354 D(bug("%s: VIARHINE_TX_IntF: Buffer %d in use!\n", unit->rhineu_name, nr));
355 try_count++;
356 goto rhine_nexttx;
359 request = (APTR)port->mp_MsgList.lh_Head;
360 data_size = packet_size = request->ios2_DataLength;
362 opener = (APTR)request->ios2_BufferManagement;
364 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
366 packet_size += ETH_PACKET_DATA;
367 CopyMem(request->ios2_DstAddr, &((struct eth_frame *)(IPTR)np->tx_desc[nr].addr)->eth_packet_dest, ETH_ADDRESSSIZE);
368 CopyMem(unit->rhineu_dev_addr, &((struct eth_frame *)(IPTR)np->tx_desc[nr].addr)->eth_packet_source, ETH_ADDRESSSIZE);
369 ((struct eth_frame *)(IPTR)np->tx_desc[nr].addr)->eth_packet_type = AROS_WORD2BE(request->ios2_PacketType);
371 buffer = (UBYTE *)&((struct eth_frame *)(IPTR)np->tx_desc[nr].addr)->eth_packet_data;
373 else
374 buffer = (UBYTE *)(IPTR)np->tx_desc[nr].addr;
376 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
378 error = S2ERR_NO_RESOURCES;
379 wire_error = S2WERR_BUFF_ERROR;
380 ReportEvents(LIBBASE, unit,
381 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
382 | S2EVENT_TX);
385 /* Now the packet is already in TX buffer, update flags for NIC */
386 D(bug("%s: VIARHINE_TX_IntF: packet %d @ %x [type = %d] queued for transmission.", unit->rhineu_name, nr, np->tx_desc[nr].addr, ((struct eth_frame *)(IPTR)np->tx_desc[nr].addr)->eth_packet_type));
387 Disable();
388 /* DEBUG? Dump frame if so */
389 #ifdef DEBUG
391 int j;
392 for (j=0; j<64; j++) {
393 if ((j%16) == 0)
394 D(bug("\n%03x:", j));
395 D(bug(" %02x", ((unsigned char*)(IPTR)np->tx_desc[nr].addr)[j]));
397 D(bug("\n"));
399 #endif
400 Enable();
402 /* Set the ring details for the packet .. */
403 np->tx_desc[nr].tx_status = DescOwn;
404 np->tx_desc[nr].desc_length = 0x00e08000 | packet_size;
405 WORDOUT(base + VIAR_ChipCmd, CmdTxDemand | np->cmd);
406 D(bug("%s: VIARHINE_TX_IntF: Packet Queued.\n", unit->rhineu_name));
408 /* Reply packet */
410 request->ios2_Req.io_Error = error;
411 request->ios2_WireError = wire_error;
412 Disable();
413 Remove((APTR)request);
414 Enable();
415 ReplyMsg((APTR)request);
417 /* Update statistics */
419 if(error == 0)
421 tracker = FindTypeStats(LIBBASE, unit, &unit->rhineu_type_trackers,
422 request->ios2_PacketType);
423 if(tracker != NULL)
425 tracker->stats.PacketsSent++;
426 tracker->stats.BytesSent += packet_size;
432 /* Was there success? Enable incomming of new packets */
433 if(proceed)
434 unit->rhineu_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
435 else
436 unit->rhineu_request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
438 return FALSE;
440 AROS_INTFUNC_EXIT
444 * Handle timeouts and other strange cases
446 static AROS_INTH1(VIARHINE_TimeoutHandlerF, struct VIARHINEUnit *, dev)
448 AROS_INTFUNC_INIT
450 struct timeval time;
451 struct Device *TimerBase = dev->rhineu_TimerSlowReq->tr_node.io_Device;
453 GetSysTime(&time);
454 //D(bug("%s: VIARHINE_TimeoutHandlerF()\n", dev->rhineu_name));
457 * If timeout timer is expected, and time elapsed - regenerate the
458 * interrupt handler
460 if (dev->rhineu_toutNEED && (CmpTime(&time, &dev->rhineu_toutPOLL ) < 0))
462 dev->rhineu_toutNEED = FALSE;
463 //Cause(&dev->rhineu_tx_end_int);
466 return FALSE;
468 AROS_INTFUNC_EXIT
472 * The interrupt handler - schedules code execution to proper handlers
474 static AROS_INTH1(VIARHINE_IntHandlerF, struct VIARHINEUnit *, dev)
476 AROS_INTFUNC_INIT
478 struct VIARHINEBase *VIARHINEDeviceBase = dev->rhineu_device;
479 struct fe_priv *np = dev->rhineu_fe_priv;
480 UBYTE *base = (UBYTE*) dev->rhineu_BaseMem;
481 // ULONG events;
482 // int i, link_changed;
483 int interrupt_work = 20;
484 // struct Device *TimerBase = dev->rhineu_TimerSlowReq->tr_node.io_Device;
485 // struct timeval time;
487 D(bug("%s: VIARHINE_IntHandlerF()!!!!!!!\n", dev->rhineu_name));
489 while (1)
491 int status = WORDIN(base + VIAR_IntrStatus);
492 WORDOUT(base + VIAR_IntrStatus, status & 0xffff); // Aknowledge All Interrupt SOurces ASAP.
494 if (!(status & (IntrRxDone | IntrRxErr | IntrRxEmpty | IntrRxOverflow| IntrRxDropped | IntrTxDone | IntrTxAbort | IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange)))
496 D(bug("%s: VIARHINE_IntHandlerF: No Signals for us!\n", dev->rhineu_name));
497 break;
500 if ( status & (IntrRxErr | IntrRxDropped | IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf )) // Chipset has Reported a Recieve problem
502 D(bug("%s: VIARHINE_IntHandlerF: Packet Reception Problem detected!\n", dev->rhineu_name));
503 WORDOUT(base, CmdRxDemand | np->cmd);
504 ReportEvents(LIBBASE, dev, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
505 dev->rhineu_stats.BadData++;
507 else if ( status & IntrRxDone ) // Chipset has Recieved packet(s)
509 D(bug("%s: VIARHINE_IntHandlerF: Packet Reception Attempt detected!\n", dev->rhineu_name));
510 Cause(&dev->rhineu_rx_int);
513 if ( status & IntrTxAbort ) // Chipset has Aborted Packet Transmition
515 D(bug("%s: VIARHINE_IntHandlerF: Chipset has Aborted Packet Transmition!\n", dev->rhineu_name));
516 WORDOUT(base, CmdTxDemand | np->cmd);
517 ReportEvents(LIBBASE, dev, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX);
520 if ( status & IntrTxUnderrun ) // Chipset Reports Tx Underrun
522 D(bug("%s: VIARHINE_IntHandlerF: Chipset Reports Tx Underrun!\n", dev->rhineu_name));
523 if (np->tx_thresh < 0xe0) BYTEOUT(base + VIAR_TxConfig, np->tx_thresh += 0x20);
524 WORDOUT(base, CmdTxDemand | np->cmd);
525 ReportEvents(LIBBASE, dev, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX);
528 if ( status & IntrTxDone ) // Chipset has Sent packet(s)
530 D(bug("%s: VIARHINE_IntHandlerF: Packet Transmision detected!\n", dev->rhineu_name));
531 dev->rhineu_stats.PacketsSent++;
534 if (--interrupt_work < 0)
536 D(bug("%s: VIARHINE_IntHandlerF: MAX interrupt work reached.\n", dev->rhineu_name));
537 break;
541 return FALSE;
543 AROS_INTFUNC_EXIT
546 VOID CopyPacket(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *unit,
547 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
548 struct eth_frame *buffer)
550 struct Opener *opener;
551 BOOL filtered = FALSE;
552 UBYTE *ptr;
554 D(bug("%s: CopyPacket(packet @ %x, len = %d)\n", unit->rhineu_name, buffer, packet_size));
556 /* Set multicast and broadcast flags */
558 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
559 if((*((ULONG *)(buffer->eth_packet_dest)) == 0xffffffff) &&
560 (*((UWORD *)(buffer->eth_packet_dest + 4)) == 0xffff))
562 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
563 D(bug("%s: CopyPacket: BROADCAST Flag set\n", unit->rhineu_name));
565 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
567 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
568 D(bug("%s: CopyPacket: MULTICAST Flag set\n", unit->rhineu_name));
571 /* Set source and destination addresses and packet type */
572 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
573 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
574 request->ios2_PacketType = packet_type;
576 /* Adjust for cooked packet request */
578 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
580 packet_size -= ETH_PACKET_DATA;
581 ptr = (UBYTE*)&buffer->eth_packet_data[0];
583 else
585 ptr = (UBYTE*)buffer;
588 request->ios2_DataLength = packet_size;
590 D(bug("%s: CopyPacket: packet @ %x (%d bytes)\n", unit->rhineu_name, ptr, packet_size));
592 /* Filter packet */
594 opener = request->ios2_BufferManagement;
595 if((request->ios2_Req.io_Command == CMD_READ) &&
596 (opener->filter_hook != NULL))
597 if(!CallHookPkt(opener->filter_hook, request, ptr))
599 D(bug("%s: CopyPacket: packet filtered\n", unit->rhineu_name));
600 filtered = TRUE;
603 if(!filtered)
605 /* Copy packet into opener's buffer and reply packet */
606 D(bug("%s: CopyPacket: opener recieve packet .. ", unit->rhineu_name));
607 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
609 D(bug("ERROR occured!!\n"));
610 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
611 request->ios2_WireError = S2WERR_BUFF_ERROR;
612 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
614 else
616 D(bug("SUCCESS!!\n"));
618 Disable();
619 Remove((APTR)request);
620 Enable();
621 ReplyMsg((APTR)request);
622 D(bug("%s: CopyPacket: opener notified.\n", unit->rhineu_name));
626 BOOL AddressFilter(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *unit, UBYTE *address)
628 struct AddressRange *range, *tail;
629 BOOL accept = TRUE;
630 ULONG address_left;
631 UWORD address_right;
633 /* Check whether address is unicast/broadcast or multicast */
635 address_left = AROS_BE2LONG(*((ULONG *)address));
636 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
638 if((address_left & 0x01000000) != 0 &&
639 !(address_left == 0xffffffff && address_right == 0xffff))
641 /* Check if this multicast address is wanted */
643 range = (APTR)unit->rhineu_multicast_ranges.mlh_Head;
644 tail = (APTR)&unit->rhineu_multicast_ranges.mlh_Tail;
645 accept = FALSE;
647 while((range != tail) && !accept)
649 if((address_left > range->lower_bound_left ||
650 (address_left == range->lower_bound_left &&
651 address_right >= range->lower_bound_right)) &&
652 (address_left < range->upper_bound_left ||
653 (address_left == range->upper_bound_left &&
654 address_right <= range->upper_bound_right)))
655 accept = TRUE;
656 range = (APTR)range->node.mln_Succ;
659 if(!accept)
660 unit->rhineu_special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
662 return accept;
666 * Unit process
668 AROS_UFH3(void, VIARHINE_Schedular,
669 AROS_UFHA(STRPTR, argPtr, A0),
670 AROS_UFHA(ULONG, argSize, D0),
671 AROS_UFHA(struct ExecBase *, SysBase, A6))
673 AROS_USERFUNC_INIT
675 struct VIARHINEUnit *dev = FindTask(NULL)->tc_UserData;
676 LIBBASETYPEPTR LIBBASE = dev->rhineu_device;
677 struct MsgPort *reply_port, *input;
679 D(bug("%s VIARHINE_Schedular()\n", dev->rhineu_name));
680 D(bug("%s VIARHINE_Schedular: Setting device up\n", dev->rhineu_name));
682 reply_port = CreateMsgPort();
683 input = CreateMsgPort();
685 dev->rhineu_input_port = input;
687 dev->rhineu_TimerSlowPort = CreateMsgPort();
689 if (dev->rhineu_TimerSlowPort)
691 dev->rhineu_TimerSlowReq = (struct timerequest *)
692 CreateIORequest((struct MsgPort *)dev->rhineu_TimerSlowPort, sizeof(struct timerequest));
694 if (dev->rhineu_TimerSlowReq)
696 if (!OpenDevice("timer.device", UNIT_VBLANK,
697 (struct IORequest *)dev->rhineu_TimerSlowReq, 0))
699 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC|MEMF_CLEAR);
700 ULONG sigset;
702 D(bug("%s VIARHINE_Schedular: Got VBLANK unit of timer.device\n", dev->rhineu_name));
704 dev->initialize(dev);
706 msg->mn_ReplyPort = reply_port;
707 msg->mn_Length = sizeof(struct Message);
709 D(bug("%s VIARHINE_Schedular: Setup complete. Sending handshake\n", dev->rhineu_name));
710 PutMsg(LIBBASE->rhineb_syncport, msg);
711 WaitPort(reply_port);
712 GetMsg(reply_port);
714 FreeVec(msg);
716 D(bug("%s VIARHINE_Schedular: entering forever loop ... \n", dev->rhineu_name));
718 dev->rhineu_signal_0 = AllocSignal(-1);
719 dev->rhineu_signal_1 = AllocSignal(-1);
720 dev->rhineu_signal_2 = AllocSignal(-1);
721 dev->rhineu_signal_3 = AllocSignal(-1);
723 sigset = 1 << input->mp_SigBit |
724 1 << dev->rhineu_signal_0 |
725 1 << dev->rhineu_signal_1 |
726 1 << dev->rhineu_signal_2 |
727 1 << dev->rhineu_signal_3;
728 for(;;)
730 ULONG recvd = Wait(sigset);
731 if (recvd & dev->rhineu_signal_0)
734 * Shutdown process. Driver should close everything
735 * already and waits for our process to complete. Free
736 * memory allocared here and kindly return.
738 dev->deinitialize(dev);
739 CloseDevice((struct IORequest *)dev->rhineu_TimerSlowReq);
740 DeleteIORequest((struct IORequest *)dev->rhineu_TimerSlowReq);
741 DeleteMsgPort(dev->rhineu_TimerSlowPort);
742 DeleteMsgPort(input);
743 DeleteMsgPort(reply_port);
745 D(bug("%s VIARHINE_Schedular: Process shutdown.\n", dev->rhineu_name));
746 return;
748 else if (recvd & (1 << input->mp_SigBit))
750 struct IOSana2Req *io;
752 /* Handle incoming transactions */
753 while ((io = (struct IOSana2Req *)GetMsg(input))!= NULL);
755 D(bug("%s VIARHINE_Schedular: Handle incomming transaction.\n", dev->rhineu_name));
756 ObtainSemaphore(&dev->rhineu_unit_lock);
757 handle_request(LIBBASE, io);
760 else
762 D(bug("%s VIARHINE_Schedular: Handle incomming signal.\n", dev->rhineu_name));
763 /* Handle incoming signals */
770 AROS_USERFUNC_EXIT
774 * Create new RTL8139 ethernet device unit
776 struct VIARHINEUnit *CreateUnit(struct VIARHINEBase *VIARHINEDeviceBase, OOP_Object *pciDevice, ULONG CardCapabilities, char * CardName)
778 BOOL success = TRUE;
779 int i;
781 D(bug("[VIA-RHINE] CreateUnit()\n"));
783 struct VIARHINEUnit *unit = AllocMem(sizeof(struct VIARHINEUnit), MEMF_PUBLIC | MEMF_CLEAR);
785 if (unit != NULL)
787 IPTR DeviceID, base, len;
788 OOP_Object *driver;
790 D(bug("[VIA-RHINE] CreateUnit: Unit allocated @ %x\n", unit));
792 OOP_GetAttr(pciDevice, aHidd_PCIDevice_ProductID, &DeviceID);
793 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&driver);
795 unit->rhineu_cardname = CardName;
796 unit->rhineu_chipcapabilities = CardCapabilities;
797 unit->rhineu_device = VIARHINEDeviceBase;
798 unit->rhineu_DeviceID = DeviceID;
799 unit->rhineu_mtu = ETH_MTU;
800 unit->rhineu_PCIDevice = pciDevice;
801 unit->rhineu_PCIDriver = driver;
802 unit->rhineu_UnitNum = VIARHINEDeviceBase->rhineb_UnitCount++;
804 int unitname_len = 12 + ((unit->rhineu_UnitNum/10)+1);
806 unit->rhineu_name = AllocVec(unitname_len, MEMF_CLEAR|MEMF_PUBLIC);
807 D(bug("[VIA-RHINE] CreateUnit: Allocated %d bytes for Unit %d's Name @ %x\n", unitname_len, unit->rhineu_UnitNum, unit->rhineu_name));
808 sprintf(unit->rhineu_name, "[VIARHINE.%d]", unit->rhineu_UnitNum);
810 InitSemaphore(&unit->rhineu_unit_lock);
811 NEWLIST(&unit->rhineu_Openers);
812 NEWLIST(&unit->rhineu_multicast_ranges);
813 NEWLIST(&unit->rhineu_type_trackers);
815 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->rhineu_IRQ);
816 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base1, &unit->rhineu_BaseIO);
817 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, &base);
818 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size0, &len);
820 D(bug("%s CreateUnit: INT:%d, base1:%x, base0:%x, size0:%d\n", unit->rhineu_name,
821 unit->rhineu_IRQ, unit->rhineu_BaseIO,
822 base, len));
824 unit->rhineu_BaseMem = (IPTR)HIDD_PCIDriver_MapPCI(driver, (APTR)base, len);
825 unit->rhineu_SizeMem = len;
827 if (unit->rhineu_BaseMem)
829 struct TagItem attrs[] = {
830 { aHidd_PCIDevice_isIO, TRUE },
831 { aHidd_PCIDevice_isMEM, TRUE },
832 { aHidd_PCIDevice_isMaster, TRUE },
833 { TAG_DONE, 0 },
835 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
837 D(bug("%s CreateUnit: PCI_BaseMem @ %x\n", unit->rhineu_name, unit->rhineu_BaseMem));
839 unit->rhineu_fe_priv = HIDD_PCIDriver_AllocPCIMem(
840 unit->rhineu_PCIDriver,
841 sizeof(struct fe_priv));
843 viarhinenic_get_functions(unit);
845 if (unit->rhineu_fe_priv)
847 D(bug("%s CreateUnit: NIC Private Data Area @ %x, start @ %x\n", unit->rhineu_name, unit->rhineu_fe_priv));
849 unit->rhineu_fe_priv->pci_dev = unit;
850 InitSemaphore(&unit->rhineu_fe_priv->lock);
853 struct Message *msg;
855 unit->rhineu_irqhandler.is_Node.ln_Type = NT_INTERRUPT;
856 unit->rhineu_irqhandler.is_Node.ln_Pri = 100;
857 unit->rhineu_irqhandler.is_Node.ln_Name = LIBBASE->rhineb_Device.dd_Library.lib_Node.ln_Name;
858 unit->rhineu_irqhandler.is_Code = VIARHINE_IntHandlerF;
859 unit->rhineu_irqhandler.is_Data = unit;
861 unit->rhineu_touthandler.is_Node.ln_Type = NT_INTERRUPT;
862 unit->rhineu_touthandler.is_Node.ln_Pri = 100;
863 unit->rhineu_touthandler.is_Node.ln_Name = LIBBASE->rhineb_Device.dd_Library.lib_Node.ln_Name;
864 unit->rhineu_touthandler.is_Code = VIARHINE_TimeoutHandlerF;
865 unit->rhineu_touthandler.is_Data = unit;
867 unit->rhineu_rx_int.is_Node.ln_Name = unit->rhineu_name;
868 unit->rhineu_rx_int.is_Code = VIARHINE_RX_IntF;
869 unit->rhineu_rx_int.is_Data = unit;
871 unit->rhineu_tx_int.is_Node.ln_Name = unit->rhineu_name;
872 unit->rhineu_tx_int.is_Code = VIARHINE_TX_IntF;
873 unit->rhineu_tx_int.is_Data = unit;
875 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
877 struct MsgPort *port = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR);
878 unit->rhineu_request_ports[i] = port;
880 if (port == NULL) success = FALSE;
882 if (success)
884 NEWLIST(&port->mp_MsgList);
885 port->mp_Flags = PA_IGNORE;
886 port->mp_SigTask = &unit->rhineu_tx_int;
890 unit->rhineu_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
892 if (success)
894 LIBBASE->rhineb_syncport = CreateMsgPort();
896 unit->rhineu_Process = CreateNewProcTags(
897 NP_Entry, (IPTR)VIARHINE_Schedular,
898 NP_Name, VIARHINE_TASK_NAME,
899 NP_Priority, 0,
900 NP_UserData, (IPTR)unit,
901 NP_StackSize, 140960,
902 TAG_DONE);
904 WaitPort(LIBBASE->rhineb_syncport);
905 msg = GetMsg(LIBBASE->rhineb_syncport);
906 ReplyMsg(msg);
907 DeleteMsgPort(LIBBASE->rhineb_syncport);
909 D(bug("[VIA-RHINE] Unit up and running\n"));
911 return unit;
913 else
915 D(bug("%s: ERRORS occured during Device setup - ABORTING\n", unit->rhineu_name));
920 else
921 D(bug("[VIA-RHINE] PANIC! Couldn't get MMIO area. Aborting\n"));
923 DeleteUnit(VIARHINEDeviceBase, unit);
924 return NULL;
928 * DeleteUnit - removes selected unit. Frees all resources and structures.
930 * The caller should be sure, that given unit is really ready to be freed.
933 void DeleteUnit(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *Unit)
935 int i;
936 if (Unit)
938 if (Unit->rhineu_Process)
940 Signal(&Unit->rhineu_Process->pr_Task, Unit->rhineu_signal_0);
943 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
945 if (Unit->rhineu_request_ports[i] != NULL)
946 FreeMem(Unit->rhineu_request_ports[i], sizeof(struct MsgPort));
948 Unit->rhineu_request_ports[i] = NULL;
951 if (Unit->rhineu_fe_priv)
953 FreeMem(Unit->rhineu_fe_priv, sizeof(struct fe_priv));
954 Unit->rhineu_fe_priv = NULL;
957 if (Unit->rhineu_BaseMem)
959 HIDD_PCIDriver_UnmapPCI(Unit->rhineu_PCIDriver,
960 (APTR)Unit->rhineu_BaseMem,
961 Unit->rhineu_SizeMem);
964 FreeMem(Unit, sizeof(struct VIARHINEUnit));
968 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit,
969 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
971 struct AddressRange *range, *tail;
972 BOOL found = FALSE;
974 range = (APTR)unit->rhineu_multicast_ranges.mlh_Head;
975 tail = (APTR)&unit->rhineu_multicast_ranges.mlh_Tail;
977 while((range != tail) && !found)
979 if((lower_bound_left == range->lower_bound_left) &&
980 (lower_bound_right == range->lower_bound_right) &&
981 (upper_bound_left == range->upper_bound_left) &&
982 (upper_bound_right == range->upper_bound_right))
983 found = TRUE;
984 else
985 range = (APTR)range->node.mln_Succ;
988 if(!found)
989 range = NULL;
991 return range;
994 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit, const UBYTE *lower_bound,
995 const UBYTE *upper_bound)
997 struct AddressRange *range;
998 ULONG lower_bound_left, upper_bound_left;
999 UWORD lower_bound_right, upper_bound_right;
1001 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1002 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1003 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1004 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1006 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1007 upper_bound_left, upper_bound_right);
1009 if(range != NULL)
1010 range->add_count++;
1011 else
1013 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1014 if(range != NULL)
1016 range->lower_bound_left = lower_bound_left;
1017 range->lower_bound_right = lower_bound_right;
1018 range->upper_bound_left = upper_bound_left;
1019 range->upper_bound_right = upper_bound_right;
1020 range->add_count = 1;
1022 Disable();
1023 AddTail((APTR)&unit->rhineu_multicast_ranges, (APTR)range);
1024 Enable();
1026 if (unit->rhineu_range_count++ == 0)
1028 unit->rhineu_flags |= IFF_ALLMULTI;
1029 unit->set_multicast(unit);
1034 return range != NULL;
1037 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
1039 struct AddressRange *range;
1040 ULONG lower_bound_left, upper_bound_left;
1041 UWORD lower_bound_right, upper_bound_right;
1043 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1044 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1045 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1046 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1048 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1049 upper_bound_left, upper_bound_right);
1051 if(range != NULL)
1053 if(--range->add_count == 0)
1055 Disable();
1056 Remove((APTR)range);
1057 Enable();
1058 FreeMem(range, sizeof(struct AddressRange));
1060 if (--unit->rhineu_range_count == 0)
1062 unit->rhineu_flags &= ~IFF_ALLMULTI;
1063 unit->set_multicast(unit);
1067 return range != NULL;