revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / networks / via-rhine / unit.c
blobf4f8f9d9e2ce4d9f412e6c6b7935d44de9a13a09
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, *address;
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 address = buffer->eth_packet_dest;
560 if((*((ULONG *)address) == 0xffffffff) &&
561 (*((UWORD *)(address + 4)) == 0xffff))
563 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
564 D(bug("%s: CopyPacket: BROADCAST Flag set\n", unit->rhineu_name));
566 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
568 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
569 D(bug("%s: CopyPacket: MULTICAST Flag set\n", unit->rhineu_name));
572 /* Set source and destination addresses and packet type */
573 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
574 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
575 request->ios2_PacketType = packet_type;
577 /* Adjust for cooked packet request */
579 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
581 packet_size -= ETH_PACKET_DATA;
582 ptr = (UBYTE*)&buffer->eth_packet_data[0];
584 else
586 ptr = (UBYTE*)buffer;
589 request->ios2_DataLength = packet_size;
591 D(bug("%s: CopyPacket: packet @ %x (%d bytes)\n", unit->rhineu_name, ptr, packet_size));
593 /* Filter packet */
595 opener = request->ios2_BufferManagement;
596 if((request->ios2_Req.io_Command == CMD_READ) &&
597 (opener->filter_hook != NULL))
598 if(!CallHookPkt(opener->filter_hook, request, ptr))
600 D(bug("%s: CopyPacket: packet filtered\n", unit->rhineu_name));
601 filtered = TRUE;
604 if(!filtered)
606 /* Copy packet into opener's buffer and reply packet */
607 D(bug("%s: CopyPacket: opener recieve packet .. ", unit->rhineu_name));
608 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
610 D(bug("ERROR occured!!\n"));
611 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
612 request->ios2_WireError = S2WERR_BUFF_ERROR;
613 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
615 else
617 D(bug("SUCCESS!!\n"));
619 Disable();
620 Remove((APTR)request);
621 Enable();
622 ReplyMsg((APTR)request);
623 D(bug("%s: CopyPacket: opener notified.\n", unit->rhineu_name));
627 BOOL AddressFilter(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *unit, UBYTE *address)
629 struct AddressRange *range, *tail;
630 BOOL accept = TRUE;
631 ULONG address_left;
632 UWORD address_right;
634 /* Check whether address is unicast/broadcast or multicast */
636 address_left = AROS_BE2LONG(*((ULONG *)address));
637 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
639 if((address_left & 0x01000000) != 0 &&
640 !(address_left == 0xffffffff && address_right == 0xffff))
642 /* Check if this multicast address is wanted */
644 range = (APTR)unit->rhineu_multicast_ranges.mlh_Head;
645 tail = (APTR)&unit->rhineu_multicast_ranges.mlh_Tail;
646 accept = FALSE;
648 while((range != tail) && !accept)
650 if((address_left > range->lower_bound_left ||
651 (address_left == range->lower_bound_left &&
652 address_right >= range->lower_bound_right)) &&
653 (address_left < range->upper_bound_left ||
654 (address_left == range->upper_bound_left &&
655 address_right <= range->upper_bound_right)))
656 accept = TRUE;
657 range = (APTR)range->node.mln_Succ;
660 if(!accept)
661 unit->rhineu_special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
663 return accept;
667 * Unit process
669 AROS_UFH3(void, VIARHINE_Schedular,
670 AROS_UFHA(STRPTR, argPtr, A0),
671 AROS_UFHA(ULONG, argSize, D0),
672 AROS_UFHA(struct ExecBase *, SysBase, A6))
674 AROS_USERFUNC_INIT
676 struct VIARHINEUnit *dev = FindTask(NULL)->tc_UserData;
677 LIBBASETYPEPTR LIBBASE = dev->rhineu_device;
678 struct MsgPort *reply_port, *input;
680 D(bug("%s VIARHINE_Schedular()\n", dev->rhineu_name));
681 D(bug("%s VIARHINE_Schedular: Setting device up\n", dev->rhineu_name));
683 reply_port = CreateMsgPort();
684 input = CreateMsgPort();
686 dev->rhineu_input_port = input;
688 dev->rhineu_TimerSlowPort = CreateMsgPort();
690 if (dev->rhineu_TimerSlowPort)
692 dev->rhineu_TimerSlowReq = (struct timerequest *)
693 CreateIORequest((struct MsgPort *)dev->rhineu_TimerSlowPort, sizeof(struct timerequest));
695 if (dev->rhineu_TimerSlowReq)
697 if (!OpenDevice("timer.device", UNIT_VBLANK,
698 (struct IORequest *)dev->rhineu_TimerSlowReq, 0))
700 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC|MEMF_CLEAR);
701 ULONG sigset;
703 D(bug("%s VIARHINE_Schedular: Got VBLANK unit of timer.device\n", dev->rhineu_name));
705 dev->initialize(dev);
707 msg->mn_ReplyPort = reply_port;
708 msg->mn_Length = sizeof(struct Message);
710 D(bug("%s VIARHINE_Schedular: Setup complete. Sending handshake\n", dev->rhineu_name));
711 PutMsg(LIBBASE->rhineb_syncport, msg);
712 WaitPort(reply_port);
713 GetMsg(reply_port);
715 FreeVec(msg);
717 D(bug("%s VIARHINE_Schedular: entering forever loop ... \n", dev->rhineu_name));
719 dev->rhineu_signal_0 = AllocSignal(-1);
720 dev->rhineu_signal_1 = AllocSignal(-1);
721 dev->rhineu_signal_2 = AllocSignal(-1);
722 dev->rhineu_signal_3 = AllocSignal(-1);
724 sigset = 1 << input->mp_SigBit |
725 1 << dev->rhineu_signal_0 |
726 1 << dev->rhineu_signal_1 |
727 1 << dev->rhineu_signal_2 |
728 1 << dev->rhineu_signal_3;
729 for(;;)
731 ULONG recvd = Wait(sigset);
732 if (recvd & dev->rhineu_signal_0)
735 * Shutdown process. Driver should close everything
736 * already and waits for our process to complete. Free
737 * memory allocared here and kindly return.
739 dev->deinitialize(dev);
740 CloseDevice((struct IORequest *)dev->rhineu_TimerSlowReq);
741 DeleteIORequest((struct IORequest *)dev->rhineu_TimerSlowReq);
742 DeleteMsgPort(dev->rhineu_TimerSlowPort);
743 DeleteMsgPort(input);
744 DeleteMsgPort(reply_port);
746 D(bug("%s VIARHINE_Schedular: Process shutdown.\n", dev->rhineu_name));
747 return;
749 else if (recvd & (1 << input->mp_SigBit))
751 struct IOSana2Req *io;
753 /* Handle incoming transactions */
754 while ((io = (struct IOSana2Req *)GetMsg(input))!= NULL);
756 D(bug("%s VIARHINE_Schedular: Handle incomming transaction.\n", dev->rhineu_name));
757 ObtainSemaphore(&dev->rhineu_unit_lock);
758 handle_request(LIBBASE, io);
761 else
763 D(bug("%s VIARHINE_Schedular: Handle incomming signal.\n", dev->rhineu_name));
764 /* Handle incoming signals */
771 AROS_USERFUNC_EXIT
775 * Create new RTL8139 ethernet device unit
777 struct VIARHINEUnit *CreateUnit(struct VIARHINEBase *VIARHINEDeviceBase, OOP_Object *pciDevice, ULONG CardCapabilities, char * CardName)
779 BOOL success = TRUE;
780 int i;
782 D(bug("[VIA-RHINE] CreateUnit()\n"));
784 struct VIARHINEUnit *unit = AllocMem(sizeof(struct VIARHINEUnit), MEMF_PUBLIC | MEMF_CLEAR);
786 if (unit != NULL)
788 IPTR DeviceID, base, len;
789 OOP_Object *driver;
791 D(bug("[VIA-RHINE] CreateUnit: Unit allocated @ %x\n", unit));
793 OOP_GetAttr(pciDevice, aHidd_PCIDevice_ProductID, &DeviceID);
794 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&driver);
796 unit->rhineu_cardname = CardName;
797 unit->rhineu_chipcapabilities = CardCapabilities;
798 unit->rhineu_device = VIARHINEDeviceBase;
799 unit->rhineu_DeviceID = DeviceID;
800 unit->rhineu_mtu = ETH_MTU;
801 unit->rhineu_PCIDevice = pciDevice;
802 unit->rhineu_PCIDriver = driver;
803 unit->rhineu_UnitNum = VIARHINEDeviceBase->rhineb_UnitCount++;
805 int unitname_len = 12 + ((unit->rhineu_UnitNum/10)+1);
807 unit->rhineu_name = AllocVec(unitname_len, MEMF_CLEAR|MEMF_PUBLIC);
808 D(bug("[VIA-RHINE] CreateUnit: Allocated %d bytes for Unit %d's Name @ %x\n", unitname_len, unit->rhineu_UnitNum, unit->rhineu_name));
809 sprintf(unit->rhineu_name, "[VIARHINE.%d]", unit->rhineu_UnitNum);
811 InitSemaphore(&unit->rhineu_unit_lock);
812 NEWLIST(&unit->rhineu_Openers);
813 NEWLIST(&unit->rhineu_multicast_ranges);
814 NEWLIST(&unit->rhineu_type_trackers);
816 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->rhineu_IRQ);
817 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base1, &unit->rhineu_BaseIO);
818 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, &base);
819 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size0, &len);
821 D(bug("%s CreateUnit: INT:%d, base1:%x, base0:%x, size0:%d\n", unit->rhineu_name,
822 unit->rhineu_IRQ, unit->rhineu_BaseIO,
823 base, len));
825 unit->rhineu_BaseMem = (IPTR)HIDD_PCIDriver_MapPCI(driver, (APTR)base, len);
826 unit->rhineu_SizeMem = len;
828 if (unit->rhineu_BaseMem)
830 struct TagItem attrs[] = {
831 { aHidd_PCIDevice_isIO, TRUE },
832 { aHidd_PCIDevice_isMEM, TRUE },
833 { aHidd_PCIDevice_isMaster, TRUE },
834 { TAG_DONE, 0 },
836 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
838 D(bug("%s CreateUnit: PCI_BaseMem @ %x\n", unit->rhineu_name, unit->rhineu_BaseMem));
840 unit->rhineu_fe_priv = HIDD_PCIDriver_AllocPCIMem(
841 unit->rhineu_PCIDriver,
842 sizeof(struct fe_priv));
844 viarhinenic_get_functions(unit);
846 if (unit->rhineu_fe_priv)
848 D(bug("%s CreateUnit: NIC Private Data Area @ %x, start @ %x\n", unit->rhineu_name, unit->rhineu_fe_priv));
850 unit->rhineu_fe_priv->pci_dev = unit;
851 InitSemaphore(&unit->rhineu_fe_priv->lock);
854 struct Message *msg;
856 unit->rhineu_irqhandler.is_Node.ln_Type = NT_INTERRUPT;
857 unit->rhineu_irqhandler.is_Node.ln_Pri = 100;
858 unit->rhineu_irqhandler.is_Node.ln_Name = LIBBASE->rhineb_Device.dd_Library.lib_Node.ln_Name;
859 unit->rhineu_irqhandler.is_Code = (APTR)VIARHINE_IntHandlerF;
860 unit->rhineu_irqhandler.is_Data = unit;
862 unit->rhineu_touthandler.is_Node.ln_Type = NT_INTERRUPT;
863 unit->rhineu_touthandler.is_Node.ln_Pri = 100;
864 unit->rhineu_touthandler.is_Node.ln_Name = LIBBASE->rhineb_Device.dd_Library.lib_Node.ln_Name;
865 unit->rhineu_touthandler.is_Code = (APTR)VIARHINE_TimeoutHandlerF;
866 unit->rhineu_touthandler.is_Data = unit;
868 unit->rhineu_rx_int.is_Node.ln_Name = unit->rhineu_name;
869 unit->rhineu_rx_int.is_Code = (APTR)VIARHINE_RX_IntF;
870 unit->rhineu_rx_int.is_Data = unit;
872 unit->rhineu_tx_int.is_Node.ln_Name = unit->rhineu_name;
873 unit->rhineu_tx_int.is_Code = (APTR)VIARHINE_TX_IntF;
874 unit->rhineu_tx_int.is_Data = unit;
876 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
878 struct MsgPort *port = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR);
879 unit->rhineu_request_ports[i] = port;
881 if (port == NULL) success = FALSE;
883 if (success)
885 NEWLIST(&port->mp_MsgList);
886 port->mp_Flags = PA_IGNORE;
887 port->mp_SigTask = &unit->rhineu_tx_int;
891 unit->rhineu_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
893 if (success)
895 LIBBASE->rhineb_syncport = CreateMsgPort();
897 unit->rhineu_Process = CreateNewProcTags(
898 NP_Entry, (IPTR)VIARHINE_Schedular,
899 NP_Name, VIARHINE_TASK_NAME,
900 NP_Priority, 0,
901 NP_UserData, (IPTR)unit,
902 NP_StackSize, 140960,
903 TAG_DONE);
905 WaitPort(LIBBASE->rhineb_syncport);
906 msg = GetMsg(LIBBASE->rhineb_syncport);
907 ReplyMsg(msg);
908 DeleteMsgPort(LIBBASE->rhineb_syncport);
910 D(bug("[VIA-RHINE] Unit up and running\n"));
912 return unit;
914 else
916 D(bug("%s: ERRORS occured during Device setup - ABORTING\n", unit->rhineu_name));
921 else
922 D(bug("[VIA-RHINE] PANIC! Couldn't get MMIO area. Aborting\n"));
924 DeleteUnit(VIARHINEDeviceBase, unit);
925 return NULL;
929 * DeleteUnit - removes selected unit. Frees all resources and structures.
931 * The caller should be sure, that given unit is really ready to be freed.
934 void DeleteUnit(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *Unit)
936 int i;
937 if (Unit)
939 if (Unit->rhineu_Process)
941 Signal(&Unit->rhineu_Process->pr_Task, Unit->rhineu_signal_0);
944 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
946 if (Unit->rhineu_request_ports[i] != NULL)
947 FreeMem(Unit->rhineu_request_ports[i], sizeof(struct MsgPort));
949 Unit->rhineu_request_ports[i] = NULL;
952 if (Unit->rhineu_fe_priv)
954 FreeMem(Unit->rhineu_fe_priv, sizeof(struct fe_priv));
955 Unit->rhineu_fe_priv = NULL;
958 if (Unit->rhineu_BaseMem)
960 HIDD_PCIDriver_UnmapPCI(Unit->rhineu_PCIDriver,
961 (APTR)Unit->rhineu_BaseMem,
962 Unit->rhineu_SizeMem);
965 FreeMem(Unit, sizeof(struct VIARHINEUnit));
969 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit,
970 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
972 struct AddressRange *range, *tail;
973 BOOL found = FALSE;
975 range = (APTR)unit->rhineu_multicast_ranges.mlh_Head;
976 tail = (APTR)&unit->rhineu_multicast_ranges.mlh_Tail;
978 while((range != tail) && !found)
980 if((lower_bound_left == range->lower_bound_left) &&
981 (lower_bound_right == range->lower_bound_right) &&
982 (upper_bound_left == range->upper_bound_left) &&
983 (upper_bound_right == range->upper_bound_right))
984 found = TRUE;
985 else
986 range = (APTR)range->node.mln_Succ;
989 if(!found)
990 range = NULL;
992 return range;
995 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit, const UBYTE *lower_bound,
996 const UBYTE *upper_bound)
998 struct AddressRange *range;
999 ULONG lower_bound_left, upper_bound_left;
1000 UWORD lower_bound_right, upper_bound_right;
1002 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1003 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1004 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1005 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1007 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1008 upper_bound_left, upper_bound_right);
1010 if(range != NULL)
1011 range->add_count++;
1012 else
1014 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1015 if(range != NULL)
1017 range->lower_bound_left = lower_bound_left;
1018 range->lower_bound_right = lower_bound_right;
1019 range->upper_bound_left = upper_bound_left;
1020 range->upper_bound_right = upper_bound_right;
1021 range->add_count = 1;
1023 Disable();
1024 AddTail((APTR)&unit->rhineu_multicast_ranges, (APTR)range);
1025 Enable();
1027 if (unit->rhineu_range_count++ == 0)
1029 unit->rhineu_flags |= IFF_ALLMULTI;
1030 unit->set_multicast(unit);
1035 return range != NULL;
1038 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
1040 struct AddressRange *range;
1041 ULONG lower_bound_left, upper_bound_left;
1042 UWORD lower_bound_right, upper_bound_right;
1044 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1045 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1046 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1047 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1049 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1050 upper_bound_left, upper_bound_right);
1052 if(range != NULL)
1054 if(--range->add_count == 0)
1056 Disable();
1057 Remove((APTR)range);
1058 Enable();
1059 FreeMem(range, sizeof(struct AddressRange));
1061 if (--unit->rhineu_range_count == 0)
1063 unit->rhineu_flags &= ~IFF_ALLMULTI;
1064 unit->set_multicast(unit);
1068 return range != NULL;