Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / devs / networks / via-rhine / unit.c
blob0292754aa5776f40713e0f77b82dc9cc158938e8
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/battclock.h>
42 #include <proto/oop.h>
43 #include <proto/timer.h>
44 #include <proto/utility.h>
46 #include <stdlib.h>
47 #include <stdio.h>
49 #include "via-rhine.h"
50 #include "unit.h"
51 #include LC_LIBDEFS_FILE
54 * Report incoming events to all hyphotetical event receivers
56 VOID ReportEvents(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *unit, ULONG events)
58 struct IOSana2Req *request, *tail, *next_request;
59 struct List *list;
61 list = &unit->rhineu_request_ports[EVENT_QUEUE]->mp_MsgList;
62 next_request = (APTR)list->lh_Head;
63 tail = (APTR)&list->lh_Tail;
65 /* Go through list of event listeners. If send messages to receivers if event found */
66 Disable();
67 while(next_request != tail)
69 request = next_request;
70 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
72 if((request->ios2_WireError&events) != 0)
74 request->ios2_WireError = events;
75 Remove((APTR)request);
76 ReplyMsg((APTR)request);
79 Enable();
81 return;
84 struct TypeStats *FindTypeStats(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *unit,
85 struct MinList *list, ULONG packet_type)
87 struct TypeStats *stats, *tail;
88 BOOL found = FALSE;
90 stats = (APTR)list->mlh_Head;
91 tail = (APTR)&list->mlh_Tail;
93 while(stats != tail && !found)
95 if(stats->packet_type == packet_type)
96 found = TRUE;
97 else
98 stats = (APTR)stats->node.mln_Succ;
101 if(!found)
102 stats = NULL;
104 return stats;
107 void FlushUnit(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit, UBYTE last_queue, BYTE error)
109 struct IORequest *request;
110 UBYTE i;
111 struct Opener *opener, *tail;
113 D(bug("%s unit.FlushUnit\n", unit->rhineu_name));
115 /* Abort queued operations */
117 for (i=0; i <= last_queue; i++)
119 while ((request = (APTR)GetMsg(unit->rhineu_request_ports[i])) != NULL)
121 request->io_Error = IOERR_ABORTED;
122 ReplyMsg((struct Message *)request);
126 opener = (APTR)unit->rhineu_Openers.mlh_Head;
127 tail = (APTR)&unit->rhineu_Openers.mlh_Tail;
129 /* Flush every opener's read queue */
131 while(opener != tail)
133 while ((request = (APTR)GetMsg(&opener->read_port)) != NULL)
135 request->io_Error = error;
136 ReplyMsg((struct Message *)request);
138 opener = (struct Opener *)opener->node.mln_Succ;
143 * Interrupt handler called whenever RTL8139 NIC interface generates interrupt.
144 * It's duty is to iterate throgh RX queue searching for new packets.
146 * Please note, that allthough multicast support could be done on interface
147 * basis, it is done in this function as result of quick integration of both
148 * the forcedeth driver (IFF_ALLMULTI flag) and etherling3 driver (AddressMatch
149 * filter function).
151 AROS_UFH3(void, VIARHINE_RX_IntF,
152 AROS_UFHA(struct VIARHINEUnit *, unit, A1),
153 AROS_UFHA(APTR, dummy, A5),
154 AROS_UFHA(struct ExecBase *,SysBase, A6))
156 AROS_USERFUNC_INIT
158 struct VIARHINEBase *VIARHINEDeviceBase = unit->rhineu_device;
159 struct fe_priv *np = unit->rhineu_fe_priv;
160 UWORD Flags;
161 struct TypeStats *tracker;
162 ULONG packet_type;
163 struct Opener *opener, *opener_tail;
164 struct IOSana2Req *request, *request_tail;
165 BOOL accepted, is_orphan;
167 UBYTE *base = (UBYTE*) unit->rhineu_BaseMem;
169 int count = 0;
171 D(bug("%s: VIARHINE_RX_IntF() !!!!\n", unit->rhineu_name));
173 /* Endless loop, with break from inside */
174 for(;;)
176 int i, len=0;
177 struct eth_frame *frame;
179 if (count >= RX_RING_SIZE)
180 break; /* we scanned the whole ring - do not continue */
182 /* Get the in-queue number */
183 i = np->cur_rx % RX_RING_SIZE;
185 /* Do we own the packet or the chipset? */
186 if (np->rx_desc[i].rx_status & DescOwn)
188 //D(bug("%s: VIARHINE_RX_IntF: buffer %d owned by chipset\n", unit->rhineu_name, i));
189 //goto next_pkt; // still owned by hardware,
190 break;
193 if (np->rx_desc[i].rx_status & RxErr)
195 D(bug("%s: VIARHINE_RX_IntF: buffer %d has recieve error! skipping..\n", unit->rhineu_name, i));
196 goto next_pkt; // still owned by hardware,
199 if (!(np->rx_desc[i].rx_status & RxWholePkt))
201 D(bug("%s: VIARHINE_RX_IntF: buffer %d has recieved oversized packet! skipping..\n", unit->rhineu_name, i));
202 goto next_pkt; // still owned by hardware,
205 if (np->rx_desc[i].rx_status & RxOK)
207 D(bug("%s: VIARHINE_RX_IntF: packet in buffer %d was successfully recieved.\n", unit->rhineu_name, i));
210 D(bug("%s: VIARHINE_RX_IntF: buffer %d @ %x is for us\n", unit->rhineu_name, i, np->rx_desc[i].addr));
211 /* the packet is for us - get it */
213 /* got a valid packet - forward it to the network core */
214 frame = (struct eth_frame *)np->rx_desc[i].addr;
215 is_orphan = TRUE;
217 /* Dump contents of frame if DEBUG enabled */
218 #ifdef DEBUG
220 int j;
221 for (j=0; j<64; j++) {
222 if ((j%16) == 0)
223 D(bug("\n%03x:", j));
224 D(bug(" %02x", ((unsigned char*)frame)[j]));
226 D(bug("\n"));
228 #endif
230 /* Check for address validity */
231 if(AddressFilter(LIBBASE, unit, frame->eth_packet_dest))
233 /* Packet is addressed to this driver */
234 len = (np->rx_desc[i].rx_status >> 16)-4;
236 packet_type = AROS_BE2WORD(frame->eth_packet_type);
237 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));
239 opener = (APTR)unit->rhineu_Openers.mlh_Head;
240 opener_tail = (APTR)&unit->rhineu_Openers.mlh_Tail;
242 /* Offer packet to every opener */
243 while(opener != opener_tail)
245 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
246 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
247 accepted = FALSE;
249 /* Offer packet to each request until it's accepted */
250 while((request != request_tail) && !accepted)
252 if((request->ios2_PacketType == packet_type)
253 || ((request->ios2_PacketType <= ETH_MTU)
254 && (packet_type <= ETH_MTU)))
256 D(bug("%s: VIARHINE_RX_IntF: copy packet for opener ..\n", unit->rhineu_name));
257 CopyPacket(LIBBASE, unit, request, len, packet_type, frame);
258 accepted = TRUE;
260 request =
261 (struct IOSana2Req *)request->ios2_Req.io_Message.mn_Node.ln_Succ;
263 if(accepted)
264 is_orphan = FALSE;
266 opener = (APTR)opener->node.mln_Succ;
269 /* If packet was unwanted, give it to S2_READORPHAN request */
270 if(is_orphan)
272 unit->rhineu_stats.UnknownTypesReceived++;
274 if(!IsMsgPortEmpty(unit->rhineu_request_ports[ADOPT_QUEUE]))
276 CopyPacket(LIBBASE, unit,
277 (APTR)unit->rhineu_request_ports[ADOPT_QUEUE]->
278 mp_MsgList.lh_Head, len, packet_type, frame);
279 D(bug("%s: VIARHINE_RX_IntF: packet copied to orphan queue\n", unit->rhineu_name));
282 np->rx_desc[i].desc_length = MAX_FRAME_SIZE; //Set the buffer size back to max (before enabling it)
283 np->rx_desc[i].rx_status = DescOwn;
285 WORDOUT(base, CmdRxDemand | np->cmd);
287 /* Update remaining statistics */
289 tracker =
290 FindTypeStats(LIBBASE, unit, &unit->rhineu_type_trackers, packet_type);
292 if(tracker != NULL)
294 tracker->stats.PacketsReceived++;
295 tracker->stats.BytesReceived += len;
299 unit->rhineu_stats.PacketsReceived++;
300 // ((struct rx_ring_desc *)np->ring_addr)[i].BufferStatus = AROS_WORD2LE((1 << 8)|(1 << 9)|(1 << 15)); // Mark packet as available again
302 next_pkt:
303 np->cur_rx++;
304 count++;
307 AROS_USERFUNC_EXIT
311 * Interrupt generated by Cause() to push new packets into the NIC interface
313 AROS_UFH3(void, VIARHINE_TX_IntF,
314 AROS_UFHA(struct VIARHINEUnit *, unit, A1),
315 AROS_UFHA(APTR, dummy, A5),
316 AROS_UFHA(struct ExecBase *,SysBase, A6))
318 AROS_USERFUNC_INIT
320 struct fe_priv *np = unit->rhineu_fe_priv;
321 struct VIARHINEBase *VIARHINEDeviceBase = unit->rhineu_device;
322 int nr, try_count=1;
323 BOOL proceed = FALSE; /* Fails by default */
325 D(bug("%s: VIARHINE_TX_IntF()\n", unit->rhineu_name));
327 /* send packet only if there is free space on tx queue. Otherwise do nothing */
328 if (!netif_queue_stopped(unit))
330 UWORD packet_size, data_size;
331 struct IOSana2Req *request;
332 struct Opener *opener;
333 UBYTE *buffer;
334 ULONG wire_error=0;
335 BYTE error;
336 struct MsgPort *port;
337 struct TypeStats *tracker;
339 proceed = TRUE; /* Success by default */
340 UBYTE *base = (UBYTE*) unit->rhineu_BaseMem;
341 port = unit->rhineu_request_ports[WRITE_QUEUE];
343 /* Still no error and there are packets to be sent? */
344 while(proceed && (!IsMsgPortEmpty(port)))
346 rhine_nexttx:
347 if (try_count >= (TX_BUFFERS * 3))
349 #warning "TODO: We should probably report that we couldnt send the packet here.."
350 D(bug("%s: VIARHINE_TX_IntF: Send FAILED! no free Tx buffer(s)\n", unit->rhineu_name));
351 break;
354 nr = np->tx_current % TX_BUFFERS;
355 np->tx_current++;
357 if (np->tx_desc[nr].tx_status & DescOwn)
359 D(bug("%s: VIARHINE_TX_IntF: Buffer %d in use!\n", unit->rhineu_name, nr));
360 try_count++;
361 goto rhine_nexttx;
364 request = (APTR)port->mp_MsgList.lh_Head;
365 data_size = packet_size = request->ios2_DataLength;
367 opener = (APTR)request->ios2_BufferManagement;
369 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
371 packet_size += ETH_PACKET_DATA;
372 CopyMem(request->ios2_DstAddr, &((struct eth_frame *)np->tx_desc[nr].addr)->eth_packet_dest, ETH_ADDRESSSIZE);
373 CopyMem(unit->rhineu_dev_addr, &((struct eth_frame *)np->tx_desc[nr].addr)->eth_packet_source, ETH_ADDRESSSIZE);
374 ((struct eth_frame *)np->tx_desc[nr].addr)->eth_packet_type = AROS_WORD2BE(request->ios2_PacketType);
376 buffer = (UBYTE *)&((struct eth_frame *)np->tx_desc[nr].addr)->eth_packet_data;
378 else
379 buffer = (UBYTE *)np->tx_desc[nr].addr;
381 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
383 error = S2ERR_NO_RESOURCES;
384 wire_error = S2WERR_BUFF_ERROR;
385 ReportEvents(LIBBASE, unit,
386 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
387 | S2EVENT_TX);
390 /* Now the packet is already in TX buffer, update flags for NIC */
391 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 *)np->tx_desc[nr].addr)->eth_packet_type));
392 Disable();
393 /* DEBUG? Dump frame if so */
394 #ifdef DEBUG
396 int j;
397 for (j=0; j<64; j++) {
398 if ((j%16) == 0)
399 D(bug("\n%03x:", j));
400 D(bug(" %02x", ((unsigned char*)np->tx_desc[nr].addr)[j]));
402 D(bug("\n"));
404 #endif
405 Enable();
407 /* Set the ring details for the packet .. */
408 np->tx_desc[nr].tx_status = DescOwn;
409 np->tx_desc[nr].desc_length = 0x00e08000 | packet_size;
410 WORDOUT(base + VIAR_ChipCmd, CmdTxDemand | np->cmd);
411 D(bug("%s: VIARHINE_TX_IntF: Packet Queued.\n", unit->rhineu_name));
413 /* Reply packet */
415 request->ios2_Req.io_Error = error;
416 request->ios2_WireError = wire_error;
417 Disable();
418 Remove((APTR)request);
419 Enable();
420 ReplyMsg((APTR)request);
422 /* Update statistics */
424 if(error == 0)
426 tracker = FindTypeStats(LIBBASE, unit, &unit->rhineu_type_trackers,
427 request->ios2_PacketType);
428 if(tracker != NULL)
430 tracker->stats.PacketsSent++;
431 tracker->stats.BytesSent += packet_size;
437 /* Was there success? Enable incomming of new packets */
438 if(proceed)
439 unit->rhineu_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
440 else
441 unit->rhineu_request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
443 AROS_USERFUNC_EXIT
447 * Handle timeouts and other strange cases
449 static void VIARHINE_TimeoutHandlerF(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
451 struct VIARHINEUnit *dev = (struct VIARHINEUnit *) irq->h_Data;
452 struct timeval time;
453 struct Device *TimerBase = dev->rhineu_TimerSlowReq->tr_node.io_Device;
455 GetSysTime(&time);
456 //D(bug("%s: VIARHINE_TimeoutHandlerF()\n", dev->rhineu_name));
459 * If timeout timer is expected, and time elapsed - regenerate the
460 * interrupt handler
462 if (dev->rhineu_toutNEED && (CmpTime(&time, &dev->rhineu_toutPOLL ) < 0))
464 dev->rhineu_toutNEED = FALSE;
465 //Cause(&dev->rhineu_tx_end_int);
470 * The interrupt handler - schedules code execution to proper handlers
472 static void VIARHINE_IntHandlerF(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
474 struct VIARHINEUnit *dev = (struct VIARHINEUnit *) irq->h_Data;
475 struct VIARHINEBase *VIARHINEDeviceBase = dev->rhineu_device;
476 struct fe_priv *np = dev->rhineu_fe_priv;
477 UBYTE *base = (UBYTE*) dev->rhineu_BaseMem;
478 ULONG events;
479 int i, link_changed, interrupt_work = 20;
480 struct Device *TimerBase = dev->rhineu_TimerSlowReq->tr_node.io_Device;
481 struct timeval time;
483 D(bug("%s: VIARHINE_IntHandlerF()!!!!!!!\n", dev->rhineu_name));
485 while (1)
487 int status = WORDIN(base + VIAR_IntrStatus);
488 WORDOUT(base + VIAR_IntrStatus, status & 0xffff); // Aknowledge All Interrupt SOurces ASAP.
490 if (!(status & (IntrRxDone | IntrRxErr | IntrRxEmpty | IntrRxOverflow| IntrRxDropped | IntrTxDone | IntrTxAbort | IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange)))
492 D(bug("%s: VIARHINE_IntHandlerF: No Signals for us!\n", dev->rhineu_name));
493 break;
496 if ( status & (IntrRxErr | IntrRxDropped | IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf )) // Chipset has Reported a Recieve problem
498 D(bug("%s: VIARHINE_IntHandlerF: Packet Reception Problem detected!\n", dev->rhineu_name));
499 WORDOUT(base, CmdRxDemand | np->cmd);
500 ReportEvents(LIBBASE, dev, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
501 dev->rhineu_stats.BadData++;
503 else if ( status & IntrRxDone ) // Chipset has Recieved packet(s)
505 D(bug("%s: VIARHINE_IntHandlerF: Packet Reception Attempt detected!\n", dev->rhineu_name));
506 Cause(&dev->rhineu_rx_int);
509 if ( status & IntrTxAbort ) // Chipset has Aborted Packet Transmition
511 D(bug("%s: VIARHINE_IntHandlerF: Chipset has Aborted Packet Transmition!\n", dev->rhineu_name));
512 WORDOUT(base, CmdTxDemand | np->cmd);
513 ReportEvents(LIBBASE, dev, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX);
516 if ( status & IntrTxUnderrun ) // Chipset Reports Tx Underrun
518 D(bug("%s: VIARHINE_IntHandlerF: Chipset Reports Tx Underrun!\n", dev->rhineu_name));
519 if (np->tx_thresh < 0xe0) BYTEOUT(base + VIAR_TxConfig, np->tx_thresh += 0x20);
520 WORDOUT(base, CmdTxDemand | np->cmd);
521 ReportEvents(LIBBASE, dev, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX);
524 if ( status & IntrTxDone ) // Chipset has Sent packet(s)
526 D(bug("%s: VIARHINE_IntHandlerF: Packet Transmision detected!\n", dev->rhineu_name));
527 dev->rhineu_stats.PacketsSent++;
530 if (--interrupt_work < 0)
532 D(bug("%s: VIARHINE_IntHandlerF: MAX interrupt work reached.\n", dev->rhineu_name));
533 break;
537 return;
540 VOID CopyPacket(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *unit,
541 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
542 struct eth_frame *buffer)
544 struct Opener *opener;
545 BOOL filtered = FALSE;
546 UBYTE *ptr;
548 D(bug("%s: CopyPacket(packet @ %x, len = %d)\n", unit->rhineu_name, buffer, packet_size));
550 /* Set multicast and broadcast flags */
552 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
553 if((*((ULONG *)(buffer->eth_packet_dest)) == 0xffffffff) &&
554 (*((UWORD *)(buffer->eth_packet_dest + 4)) == 0xffff))
556 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
557 D(bug("%s: CopyPacket: BROADCAST Flag set\n", unit->rhineu_name));
559 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
561 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
562 D(bug("%s: CopyPacket: MULTICAST Flag set\n", unit->rhineu_name));
565 /* Set source and destination addresses and packet type */
566 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
567 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
568 request->ios2_PacketType = packet_type;
570 /* Adjust for cooked packet request */
572 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
574 packet_size -= ETH_PACKET_DATA;
575 ptr = (UBYTE*)&buffer->eth_packet_data[0];
577 else
579 ptr = (UBYTE*)buffer;
582 request->ios2_DataLength = packet_size;
584 D(bug("%s: CopyPacket: packet @ %x (%d bytes)\n", unit->rhineu_name, ptr, packet_size));
586 /* Filter packet */
588 opener = request->ios2_BufferManagement;
589 if((request->ios2_Req.io_Command == CMD_READ) &&
590 (opener->filter_hook != NULL))
591 if(!CallHookPkt(opener->filter_hook, request, ptr))
593 D(bug("%s: CopyPacket: packet filtered\n", unit->rhineu_name));
594 filtered = TRUE;
597 if(!filtered)
599 /* Copy packet into opener's buffer and reply packet */
600 D(bug("%s: CopyPacket: opener recieve packet .. ", unit->rhineu_name));
601 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
603 D(bug("ERROR occured!!\n"));
604 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
605 request->ios2_WireError = S2WERR_BUFF_ERROR;
606 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
608 else
610 D(bug("SUCCESS!!\n"));
612 Disable();
613 Remove((APTR)request);
614 Enable();
615 ReplyMsg((APTR)request);
616 D(bug("%s: CopyPacket: opener notified.\n", unit->rhineu_name));
620 BOOL AddressFilter(struct VIARHINEBase *VIARHINEDeviceBase, struct VIARHINEUnit *unit, UBYTE *address)
622 struct AddressRange *range, *tail;
623 BOOL accept = TRUE;
624 ULONG address_left;
625 UWORD address_right;
627 /* Check whether address is unicast/broadcast or multicast */
629 address_left = AROS_BE2LONG(*((ULONG *)address));
630 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
632 if((address_left & 0x01000000) != 0 &&
633 !(address_left == 0xffffffff && address_right == 0xffff))
635 /* Check if this multicast address is wanted */
637 range = (APTR)unit->rhineu_multicast_ranges.mlh_Head;
638 tail = (APTR)&unit->rhineu_multicast_ranges.mlh_Tail;
639 accept = FALSE;
641 while((range != tail) && !accept)
643 if((address_left > range->lower_bound_left ||
644 (address_left == range->lower_bound_left &&
645 address_right >= range->lower_bound_right)) &&
646 (address_left < range->upper_bound_left ||
647 (address_left == range->upper_bound_left &&
648 address_right <= range->upper_bound_right)))
649 accept = TRUE;
650 range = (APTR)range->node.mln_Succ;
653 if(!accept)
654 unit->rhineu_special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
656 return accept;
660 * Unit process
662 AROS_UFH3(void, VIARHINE_Schedular,
663 AROS_UFHA(STRPTR, argPtr, A0),
664 AROS_UFHA(ULONG, argSize, D0),
665 AROS_UFHA(struct ExecBase *, SysBase, A6))
667 AROS_USERFUNC_INIT
669 struct VIARHINEUnit *dev = FindTask(NULL)->tc_UserData;
670 LIBBASETYPEPTR LIBBASE = dev->rhineu_device;
671 APTR BattClockBase;
672 struct MsgPort *reply_port, *input;
674 D(bug("%s VIARHINE_Schedular()\n", dev->rhineu_name));
675 D(bug("%s VIARHINE_Schedular: Setting device up\n", dev->rhineu_name));
677 reply_port = CreateMsgPort();
678 input = CreateMsgPort();
680 dev->rhineu_input_port = input;
682 /* Randomize the generator with current time */
683 BattClockBase = OpenResource("battclock.resource");
684 srandom(ReadBattClock());
686 dev->rhineu_TimerSlowPort = CreateMsgPort();
688 if (dev->rhineu_TimerSlowPort)
690 dev->rhineu_TimerSlowReq = (struct timerequest *)
691 CreateIORequest((struct MsgPort *)dev->rhineu_TimerSlowPort, sizeof(struct timerequest));
693 if (dev->rhineu_TimerSlowReq)
695 if (!OpenDevice("timer.device", UNIT_VBLANK,
696 (struct IORequest *)dev->rhineu_TimerSlowReq, 0))
698 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC|MEMF_CLEAR);
699 ULONG sigset;
701 D(bug("%s VIARHINE_Schedular: Got VBLANK unit of timer.device\n", dev->rhineu_name));
703 dev->initialize(dev);
705 msg->mn_ReplyPort = reply_port;
706 msg->mn_Length = sizeof(struct Message);
708 D(bug("%s VIARHINE_Schedular: Setup complete. Sending handshake\n", dev->rhineu_name));
709 PutMsg(LIBBASE->rhineb_syncport, msg);
710 WaitPort(reply_port);
711 GetMsg(reply_port);
713 FreeVec(msg);
715 D(bug("%s VIARHINE_Schedular: entering forever loop ... \n", dev->rhineu_name));
717 dev->rhineu_signal_0 = AllocSignal(-1);
718 dev->rhineu_signal_1 = AllocSignal(-1);
719 dev->rhineu_signal_2 = AllocSignal(-1);
720 dev->rhineu_signal_3 = AllocSignal(-1);
722 sigset = 1 << input->mp_SigBit |
723 1 << dev->rhineu_signal_0 |
724 1 << dev->rhineu_signal_1 |
725 1 << dev->rhineu_signal_2 |
726 1 << dev->rhineu_signal_3;
727 for(;;)
729 ULONG recvd = Wait(sigset);
730 if (recvd & dev->rhineu_signal_0)
733 * Shutdown process. Driver should close everything
734 * already and waits for our process to complete. Free
735 * memory allocared here and kindly return.
737 dev->deinitialize(dev);
738 CloseDevice((struct IORequest *)dev->rhineu_TimerSlowReq);
739 DeleteIORequest((struct IORequest *)dev->rhineu_TimerSlowReq);
740 DeleteMsgPort(dev->rhineu_TimerSlowPort);
741 DeleteMsgPort(input);
742 DeleteMsgPort(reply_port);
744 D(bug("%s VIARHINE_Schedular: Process shutdown.\n", dev->rhineu_name));
745 return;
747 else if (recvd & (1 << input->mp_SigBit))
749 struct IOSana2Req *io;
751 /* Handle incoming transactions */
752 while ((io = (struct IOSana2Req *)GetMsg(input))!= NULL);
754 D(bug("%s VIARHINE_Schedular: Handle incomming transaction.\n", dev->rhineu_name));
755 ObtainSemaphore(&dev->rhineu_unit_lock);
756 handle_request(LIBBASE, io);
759 else
761 D(bug("%s VIARHINE_Schedular: Handle incomming signal.\n", dev->rhineu_name));
762 /* Handle incoming signals */
769 AROS_USERFUNC_EXIT
773 * Create new RTL8139 ethernet device unit
775 struct VIARHINEUnit *CreateUnit(struct VIARHINEBase *VIARHINEDeviceBase, OOP_Object *pciDevice, ULONG CardCapabilities, char * CardName)
777 BOOL success = TRUE;
778 int i;
780 D(bug("[VIA-RHINE] CreateUnit()\n"));
782 struct VIARHINEUnit *unit = AllocMem(sizeof(struct VIARHINEUnit), MEMF_PUBLIC | MEMF_CLEAR);
784 if (unit != NULL)
786 IPTR DeviceID, base, len;
787 OOP_Object *driver;
789 D(bug("[VIA-RHINE] CreateUnit: Unit allocated @ %x\n", unit));
791 OOP_GetAttr(pciDevice, aHidd_PCIDevice_ProductID, &DeviceID);
792 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&driver);
794 unit->rhineu_cardname = CardName;
795 unit->rhineu_chipcapabilities = CardCapabilities;
796 unit->rhineu_device = VIARHINEDeviceBase;
797 unit->rhineu_DeviceID = DeviceID;
798 unit->rhineu_mtu = ETH_MTU;
799 unit->rhineu_PCIDevice = pciDevice;
800 unit->rhineu_PCIDriver = driver;
801 unit->rhineu_UnitNum = VIARHINEDeviceBase->rhineb_UnitCount++;
803 int unitname_len = 12 + ((unit->rhineu_UnitNum/10)+1);
805 unit->rhineu_name = AllocVec(unitname_len, MEMF_CLEAR|MEMF_PUBLIC);
806 D(bug("[VIA-RHINE] CreateUnit: Allocated %d bytes for Unit %d's Name @ %x\n", unitname_len, unit->rhineu_UnitNum, unit->rhineu_name));
807 sprintf(unit->rhineu_name, "[VIARHINE.%d]", unit->rhineu_UnitNum);
809 InitSemaphore(&unit->rhineu_unit_lock);
810 NEWLIST(&unit->rhineu_Openers);
811 NEWLIST(&unit->rhineu_multicast_ranges);
812 NEWLIST(&unit->rhineu_type_trackers);
814 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->rhineu_IRQ);
815 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base1, &unit->rhineu_BaseIO);
816 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, &base);
817 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size0, &len);
819 D(bug("%s CreateUnit: INT:%d, base1:%x, base0:%x, size0:%d\n", unit->rhineu_name,
820 unit->rhineu_IRQ, unit->rhineu_BaseIO,
821 base, len));
823 unit->rhineu_BaseMem = (IPTR)HIDD_PCIDriver_MapPCI(driver, (APTR)base, len);
824 unit->rhineu_SizeMem = len;
826 if (unit->rhineu_BaseMem)
828 struct TagItem attrs[] = {
829 { aHidd_PCIDevice_isIO, TRUE },
830 { aHidd_PCIDevice_isMEM, TRUE },
831 { aHidd_PCIDevice_isMaster, TRUE },
832 { TAG_DONE, 0 },
834 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
836 D(bug("%s CreateUnit: PCI_BaseMem @ %x\n", unit->rhineu_name, unit->rhineu_BaseMem));
838 unit->rhineu_fe_priv = HIDD_PCIDriver_AllocPCIMem(
839 unit->rhineu_PCIDriver,
840 sizeof(struct fe_priv));
842 viarhinenic_get_functions(unit);
844 if (unit->rhineu_fe_priv)
846 D(bug("%s CreateUnit: NIC Private Data Area @ %x, start @ %x\n", unit->rhineu_name, unit->rhineu_fe_priv));
848 unit->rhineu_fe_priv->pci_dev = unit;
849 InitSemaphore(&unit->rhineu_fe_priv->lock);
851 unit->rhineu_irqhandler = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_PUBLIC|MEMF_CLEAR);
852 unit->rhineu_touthandler = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_PUBLIC|MEMF_CLEAR);
854 if (unit->rhineu_irqhandler && unit->rhineu_touthandler)
856 struct Message *msg;
858 unit->rhineu_irqhandler->h_Node.ln_Pri = 100;
859 unit->rhineu_irqhandler->h_Node.ln_Name = LIBBASE->rhineb_Device.dd_Library.lib_Node.ln_Name;
860 unit->rhineu_irqhandler->h_Code = VIARHINE_IntHandlerF;
861 unit->rhineu_irqhandler->h_Data = unit;
863 unit->rhineu_touthandler->h_Node.ln_Pri = 100;
864 unit->rhineu_touthandler->h_Node.ln_Name = LIBBASE->rhineb_Device.dd_Library.lib_Node.ln_Name;
865 unit->rhineu_touthandler->h_Code = VIARHINE_TimeoutHandlerF;
866 unit->rhineu_touthandler->h_Data = unit;
868 unit->rhineu_rx_int.is_Node.ln_Name = unit->rhineu_name;
869 unit->rhineu_rx_int.is_Code = 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 = 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_irqhandler)
954 FreeMem(Unit->rhineu_irqhandler, sizeof(HIDDT_IRQ_Handler));
955 LIBBASE->rhineb_irq = NULL;
958 if (Unit->rhineu_fe_priv)
960 FreeMem(Unit->rhineu_fe_priv, sizeof(struct fe_priv));
961 Unit->rhineu_fe_priv = NULL;
964 if (Unit->rhineu_BaseMem)
966 HIDD_PCIDriver_UnmapPCI(Unit->rhineu_PCIDriver,
967 (APTR)Unit->rhineu_BaseMem,
968 Unit->rhineu_SizeMem);
971 FreeMem(Unit, sizeof(struct VIARHINEUnit));
975 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit,
976 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
978 struct AddressRange *range, *tail;
979 BOOL found = FALSE;
981 range = (APTR)unit->rhineu_multicast_ranges.mlh_Head;
982 tail = (APTR)&unit->rhineu_multicast_ranges.mlh_Tail;
984 while((range != tail) && !found)
986 if((lower_bound_left == range->lower_bound_left) &&
987 (lower_bound_right == range->lower_bound_right) &&
988 (upper_bound_left == range->upper_bound_left) &&
989 (upper_bound_right == range->upper_bound_right))
990 found = TRUE;
991 else
992 range = (APTR)range->node.mln_Succ;
995 if(!found)
996 range = NULL;
998 return range;
1001 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit, const UBYTE *lower_bound,
1002 const UBYTE *upper_bound)
1004 struct AddressRange *range;
1005 ULONG lower_bound_left, upper_bound_left;
1006 UWORD lower_bound_right, upper_bound_right;
1008 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1009 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1010 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1011 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1013 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1014 upper_bound_left, upper_bound_right);
1016 if(range != NULL)
1017 range->add_count++;
1018 else
1020 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1021 if(range != NULL)
1023 range->lower_bound_left = lower_bound_left;
1024 range->lower_bound_right = lower_bound_right;
1025 range->upper_bound_left = upper_bound_left;
1026 range->upper_bound_right = upper_bound_right;
1027 range->add_count = 1;
1029 Disable();
1030 AddTail((APTR)&unit->rhineu_multicast_ranges, (APTR)range);
1031 Enable();
1033 if (unit->rhineu_range_count++ == 0)
1035 unit->rhineu_flags |= IFF_ALLMULTI;
1036 unit->set_multicast(unit);
1041 return range != NULL;
1044 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE, struct VIARHINEUnit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
1046 struct AddressRange *range;
1047 ULONG lower_bound_left, upper_bound_left;
1048 UWORD lower_bound_right, upper_bound_right;
1050 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1051 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1052 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1053 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1055 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1056 upper_bound_left, upper_bound_right);
1058 if(range != NULL)
1060 if(--range->add_count == 0)
1062 Disable();
1063 Remove((APTR)range);
1064 Enable();
1065 FreeMem(range, sizeof(struct AddressRange));
1067 if (--unit->rhineu_range_count == 0)
1069 unit->rhineu_flags &= ~IFF_ALLMULTI;
1070 unit->set_multicast(unit);
1074 return range != NULL;