grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / networks / rtl8168 / unit.c
blobaf2edf876b237f2a94cb543193747998cc548bd7
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 "rtl8168.h"
49 #include "unit.h"
50 #include LC_LIBDEFS_FILE
53 extern UBYTE MMIO_R8(UBYTE *);
54 extern UWORD MMIO_R16(UWORD *);
55 extern ULONG MMIO_R32(ULONG *);
56 extern void MMIO_W8(UBYTE *, UBYTE);
57 extern void MMIO_W16(UWORD *, UWORD);
58 extern void MMIO_W32(ULONG *, ULONG);
60 extern void rtl8168_CheckLinkStatus(struct net_device *);
63 * Report incoming events to all hyphotetical event receivers
65 VOID ReportEvents(struct RTL8168Base *RTL8168DeviceBase, struct RTL8168Unit *unit, ULONG events)
67 struct IOSana2Req *request, *tail, *next_request;
68 struct List *list;
70 list = &unit->rtl8168u_request_ports[EVENT_QUEUE]->mp_MsgList;
71 next_request = (APTR)list->lh_Head;
72 tail = (APTR)&list->lh_Tail;
74 /* Go through list of event listeners. If send messages to receivers if event found */
75 Disable();
76 while(next_request != tail)
78 request = next_request;
79 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
81 if((request->ios2_WireError&events) != 0)
83 request->ios2_WireError = events;
84 Remove((APTR)request);
85 ReplyMsg((APTR)request);
88 Enable();
90 return;
93 struct TypeStats *FindTypeStats(struct RTL8168Base *RTL8168DeviceBase, struct RTL8168Unit *unit,
94 struct MinList *list, ULONG packet_type)
96 struct TypeStats *stats, *tail;
97 BOOL found = FALSE;
99 stats = (APTR)list->mlh_Head;
100 tail = (APTR)&list->mlh_Tail;
102 while(stats != tail && !found)
104 if(stats->packet_type == packet_type)
105 found = TRUE;
106 else
107 stats = (APTR)stats->node.mln_Succ;
110 if(!found)
111 stats = NULL;
113 return stats;
116 void FlushUnit(LIBBASETYPEPTR LIBBASE, struct RTL8168Unit *unit, UBYTE last_queue, BYTE error)
118 struct IORequest *request;
119 UBYTE i;
120 struct Opener *opener, *tail;
122 RTLD(bug("[%s] unit.FlushUnit\n", unit->rtl8168u_name))
124 /* Abort queued operations */
125 for (i=0; i <= last_queue; i++)
127 while ((request = (APTR)GetMsg(unit->rtl8168u_request_ports[i])) != NULL)
129 request->io_Error = IOERR_ABORTED;
130 ReplyMsg((struct Message *)request);
134 opener = (APTR)unit->rtl8168u_Openers.mlh_Head;
135 tail = (APTR)unit->rtl8168u_Openers.mlh_Tail;
137 /* Flush every opener's read queue */
138 while(opener != tail)
140 while ((request = (APTR)GetMsg(&opener->read_port)) != NULL)
142 request->io_Error = error;
143 ReplyMsg((struct Message *)request);
145 opener = (struct Opener *)opener->node.mln_Succ;
149 static inline void rtl8168_MarkToASIC(struct RxDesc *desc, ULONG rx_buf_sz)
151 ULONG eor = AROS_LE2LONG(desc->opts1) & RingEnd;
153 desc->opts1 = AROS_LONG2LE(DescOwn | eor | rx_buf_sz);
156 /* Interrupt Rx Support Function ..
157 * It's duty is to iterate throgh RX queue searching for new packets.
159 void RTL8168_Rx_Process(struct RTL8168Unit *unit)
161 struct RTL8168Base *RTL8168DeviceBase = unit->rtl8168u_device;
162 struct rtl8168_priv *np = unit->rtl8168u_priv;
163 // APTR base = unit->rtl8168u_BaseMem;
165 struct TypeStats *tracker;
166 ULONG packet_type;
167 struct Opener *opener, *opener_tail;
168 struct IOSana2Req *request, *request_tail;
169 BOOL accepted, is_orphan;
171 RTLD(bug("[%s] RTL8168_Rx_Process() !!!!\n", unit->rtl8168u_name))
173 struct eth_frame *frame;
175 unsigned short cur_rx, rx_left;
176 cur_rx = np->cur_rx;
177 rx_left = NUM_RX_DESC - np->dirty_rx;
179 RTLD(bug("[%s] RTL8168_Rx_Process: cur_rx = %d, rx_left = %d, dirty = %d\n", unit->rtl8168u_name, cur_rx, rx_left, np->dirty_rx))
181 for (; rx_left > 0; rx_left--, cur_rx++) {
182 unsigned int entry = cur_rx % NUM_RX_DESC;
183 struct RxDesc *desc = np->RxDescArray + entry;
184 ULONG status;
186 status = AROS_LE2LONG(desc->opts1);
188 if (status & DescOwn)
189 break;
191 RTLD(bug("[%s] RTL8168_Rx_Process: Packet %d\n", unit->rtl8168u_name, entry))
193 if (status & RxRES) {
194 RTLD(bug("[%s] RTL8168_Rx_Process: Rx ERROR, status = %08x\n",
195 unit->rtl8168u_name, status))
197 /* TODO: record rx errors .. */
198 /* RTLDEV->stats.rx_errors++;
200 if (status & (RxRWT | RxRUNT))
201 RTLDEV->stats.rx_length_errors++;
202 if (status & RxCRC)
203 RTLDEV->stats.rx_crc_errors++;
205 rtl8168_MarkToASIC(desc, np->rx_buf_sz);
207 else
209 int pkt_size = (status & 0x00003FFF) - ETH_CRCSIZE;
211 frame = (APTR)(IPTR)desc->addr;
212 RTLD(bug("[%s] RTL8168_Rx_Process: frame @ %p, pkt_size=%d\n", unit->rtl8168u_name, frame, pkt_size))
214 /* got a valid packet - forward it to the network core */
215 is_orphan = TRUE;
217 RTLDP(
218 int j;
219 for (j = 0; j < pkt_size; j++) {
220 if ((j%16) == 0)
222 if (j != 0)
224 bug("\n");
226 bug("[%s] RTL8168_Rx_Process: %03x:", unit->rtl8168u_name, j);
228 bug(" %02x", ((unsigned char*)frame)[j]);
230 bug("\n")
233 /* Check for address validity */
234 if(AddressFilter(LIBBASE, unit, frame->eth_packet_dest))
236 /* Packet is addressed to this driver */
237 packet_type = AROS_BE2WORD(frame->eth_packet_type);
238 RTLD(bug("[%s] RTL8168_Rx_Process: Packet IP accepted with type = %d\n", unit->rtl8168u_name, packet_type))
240 opener = (APTR)unit->rtl8168u_Openers.mlh_Head;
241 opener_tail = (APTR)&unit->rtl8168u_Openers.mlh_Tail;
243 /* Offer packet to every opener */
244 while(opener != opener_tail)
246 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
247 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
248 accepted = FALSE;
250 /* Offer packet to each request until it's accepted */
251 while((request != request_tail) && !accepted)
253 if((request->ios2_PacketType == packet_type)
254 || ((request->ios2_PacketType <= ETH_MTU)
255 && (packet_type <= ETH_MTU)))
257 RTLD(bug("[%s] RTL8168_Rx_Process: copy packet for opener ..\n", unit->rtl8168u_name))
258 CopyPacket(LIBBASE, unit, request, pkt_size, packet_type, frame);
259 accepted = TRUE;
261 request = (struct IOSana2Req *)request->ios2_Req.io_Message.mn_Node.ln_Succ;
264 if(accepted)
265 is_orphan = FALSE;
267 opener = (APTR)opener->node.mln_Succ;
270 /* If packet was unwanted, give it to S2_READORPHAN request */
271 if(is_orphan)
273 unit->rtl8168u_stats.UnknownTypesReceived++;
275 if(!IsMsgPortEmpty(unit->rtl8168u_request_ports[ADOPT_QUEUE]))
277 CopyPacket(LIBBASE, unit,
278 (APTR)unit->rtl8168u_request_ports[ADOPT_QUEUE]->
279 mp_MsgList.lh_Head, pkt_size, packet_type, frame);
280 RTLD(bug("[%s] RTL8168_Rx_Process: packet copied to orphan queue\n", unit->rtl8168u_name))
284 rtl8168_MarkToASIC(desc, (ULONG)np->rx_buf_sz);
286 /* Update remaining statistics */
287 tracker = FindTypeStats(LIBBASE, unit, &unit->rtl8168u_type_trackers, packet_type);
289 if(tracker != NULL)
291 tracker->stats.PacketsReceived++;
292 tracker->stats.BytesReceived += pkt_size;
295 unit->rtl8168u_stats.PacketsReceived++;
298 np->cur_rx = cur_rx;
299 RTLD(bug("[%s] RTL8168_Rx_Process: Rx Packet Processing complete\n", unit->rtl8168u_name))
303 * Interrupt generated by Cause() to push new packets into the NIC interface
305 static AROS_INTH1(RTL8168_TX_IntF, struct RTL8168Unit *, unit)
307 AROS_INTFUNC_INIT
309 struct rtl8168_priv *np = unit->rtl8168u_priv;
310 struct RTL8168Base *RTL8168DeviceBase = unit->rtl8168u_device;
311 APTR base = unit->rtl8168u_BaseMem;
313 int nr, try_count=1;
314 BOOL proceed = FALSE; /* Fails by default */
316 RTLD(bug("[%s] RTL8168_TX_IntF()\n", unit->rtl8168u_name))
318 /* send packet only if there is free space on tx queue. Otherwise do nothing */
319 if (!netif_queue_stopped(unit))
321 UWORD packet_size, data_size;
322 struct IOSana2Req *request;
323 struct Opener *opener;
324 UBYTE *buffer;
325 ULONG wire_error=0;
326 BYTE error;
327 struct MsgPort *port;
329 proceed = TRUE; /* Success by default */
330 port = unit->rtl8168u_request_ports[WRITE_QUEUE];
332 /* Still no error and there are packets to be sent? */
333 while(proceed && (!IsMsgPortEmpty(port)))
335 nr = np->cur_tx % NUM_TX_DESC;
336 error = 0;
338 request = (APTR)port->mp_MsgList.lh_Head;
339 data_size = packet_size = request->ios2_DataLength;
341 opener = (APTR)request->ios2_BufferManagement;
343 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
345 packet_size += ETH_PACKET_DATA;
348 if ((!(AROS_LE2LONG(np->TxDescArray[nr].opts1) & DescOwn)) &&
349 ((np->TxDescArray[nr].addr = (IPTR)AllocMem(packet_size, MEMF_CLEAR | MEMF_PUBLIC)) != 0))
351 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
353 CopyMem(request->ios2_DstAddr, &((struct eth_frame *)(IPTR)np->TxDescArray[nr].addr)->eth_packet_dest, ETH_ADDRESSSIZE);
354 CopyMem(unit->rtl8168u_dev_addr, &((struct eth_frame *)(IPTR)np->TxDescArray[nr].addr)->eth_packet_source, ETH_ADDRESSSIZE);
355 ((struct eth_frame *)(IPTR)np->TxDescArray[nr].addr)->eth_packet_type = AROS_WORD2BE(request->ios2_PacketType);
357 buffer = (APTR)&((struct eth_frame *)(IPTR)np->TxDescArray[nr].addr)->eth_packet_data;
359 else
360 buffer = (APTR)(IPTR)np->TxDescArray[nr].addr;
362 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
364 error = S2ERR_NO_RESOURCES;
365 wire_error = S2WERR_BUFF_ERROR;
366 ReportEvents(LIBBASE, unit,
367 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
368 | S2EVENT_TX);
371 // Now the packet is already in TX buffer, update flags for NIC
372 if (error == 0)
374 RTLD(
375 APTR packet = (APTR)(IPTR)np->TxDescArray[nr].addr;
376 bug("[%s] RTL8168_TX_IntF: packet %d @ %p [type = %d] queued for transmission.\n", unit->rtl8168u_name, nr, (APTR)(IPTR)np->TxDescArray[nr].addr, AROS_BE2WORD(((struct eth_frame *)packet)->eth_packet_type))
379 RTLDP(
380 int j;
381 for (j = 0; j < packet_size; j++) {
382 if ((j%16) == 0)
384 if (j != 0)
386 bug("\n");
388 bug("[%s] RTL8168_TX_IntF: %03x:", unit->rtl8168u_name, j);
390 bug(" %02x", ((unsigned char*)np->TxDescArray[nr].addr)[j]);
392 bug("\n")
395 // Set the ring details for the packet ..
396 np->TxDescArray[nr].opts1 = AROS_LONG2LE(DescOwn | FirstFrag | LastFrag | packet_size | (RingEnd * !((nr + 1) % NUM_TX_DESC)));
397 np->TxDescArray[nr].opts2 = AROS_LONG2LE(0);
399 /* TODO: Perhaps set the Tx Poll bit after we leave the while loop .. */
400 RTL_W8(base + (TxPoll), NPQ); /* set polling bit */
403 // Reply packet
404 request->ios2_Req.io_Error = error;
405 request->ios2_WireError = wire_error;
406 Disable();
407 Remove((APTR)request);
408 Enable();
409 ReplyMsg((APTR)request);
411 try_count = 0;
413 np->cur_tx++;
414 try_count++;
416 // If we've just run out of free space on the TX queue, stop
417 // it and give up pushing further frames
418 if ( (try_count + 1) >= NUM_TX_DESC)
420 RTLD(bug("[%s] output queue full!. Stopping [count = %d, NUM_TX_DESC = %d\n", unit->rtl8168u_name, try_count, NUM_TX_DESC))
421 netif_stop_queue(unit);
422 proceed = FALSE;
427 /* Was there success? Enable incomming of new packets */
428 if(proceed)
429 unit->rtl8168u_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
430 else
431 unit->rtl8168u_request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
433 return FALSE;
435 AROS_INTFUNC_EXIT;
439 * Handle timeouts and other strange cases
441 static AROS_INTH1(RTL8168_TimeoutHandlerF, struct RTL8168Unit *, unit)
443 AROS_INTFUNC_INIT
445 struct timeval time;
446 struct Device *TimerBase = unit->rtl8168u_TimerSlowReq->tr_node.io_Device;
448 GetSysTime(&time);
449 //RTLD(bug("[%s] RTL8168_TimeoutHandlerF()\n", unit->rtl8168u_name))
452 * If timeout timer is expected, and time elapsed - regenerate the
453 * interrupt handler
455 if (unit->rtl8168u_toutNEED && (CmpTime(&time, &unit->rtl8168u_toutPOLL ) < 0))
457 unit->rtl8168u_toutNEED = FALSE;
458 //Cause(&unit->rtl8168u_tx_end_int);
461 return FALSE;
463 AROS_INTFUNC_EXIT
466 static void RTL8168_Tx_Cleanup(struct net_device *unit)
468 struct rtl8168_priv *np = unit->rtl8168u_priv;
469 unsigned int dirty_tx, tx_left;
470 struct TypeStats *tracker;
472 dirty_tx = np->dirty_tx;
473 tx_left = np->cur_tx - dirty_tx;
475 while (tx_left > 0) {
476 unsigned int entry = dirty_tx % NUM_TX_DESC;
477 ULONG packet_size, status;
479 status = AROS_LE2LONG(np->TxDescArray[entry].opts1);
481 if (status & DescOwn)
482 break;
484 packet_size = status & 0x3FFF;
485 tracker = FindTypeStats(unit->rtl8168u_device, unit, &unit->rtl8168u_type_trackers, ((struct eth_frame *)(IPTR)np->TxDescArray[entry].addr)->eth_packet_type);
486 if(tracker != NULL)
488 tracker->stats.PacketsSent++;
489 tracker->stats.BytesSent += packet_size;
492 if (status & LastFrag) {
493 RTLD(bug("[%s] RTL8168_Tx_Cleanup: Released buffer %d (%d bytes)\n", unit->rtl8168u_name, entry, packet_size))
494 np->TxDescArray[entry].opts1 = AROS_LONG2LE(RingEnd);
495 np->TxDescArray[entry].addr = 0;
497 dirty_tx++;
498 tx_left--;
500 if (np->dirty_tx != dirty_tx) {
501 np->dirty_tx = dirty_tx;
503 if (netif_queue_stopped(dev) &&
504 (TX_BUFFS_AVAIL(np) >= MAX_SKB_FRAGS)) {
505 netif_wake_queue(dev);
512 * Interrupt handler called whenever RTL8168 NIC interface generates interrupt.
514 static AROS_INTH1(RTL8168_IntHandlerF, struct RTL8168Unit *, unit)
516 AROS_INTFUNC_INIT
518 struct rtl8168_priv *np = unit->rtl8168u_priv;
519 APTR base = unit->rtl8168u_BaseMem;
520 int status;
522 int boguscnt = unit->rtl8168u_device->rtl8168b_MaxIntWork;
524 UWORD intr_clean_mask = SYSErr | PCSTimeout | SWInt |
525 LinkChg | RxDescUnavail |
526 TxErr | TxOK | RxErr | RxOK;
528 RTL_W16(base + (IntrMask), 0x0000);
530 RTLD(bug("[%s] RTL8168_IntHandlerF()!!!!!!!\n", unit->rtl8168u_name))
532 do {
533 status = RTL_R16(base + (IntrStatus));
535 /* hotplug/major error/no more work/shared irq */
536 if ((status == 0xFFFF) || !status)
537 break;
539 // if (!netif_running(unit)) {
540 // rtl8168_asic_down(unit);
541 // goto out;
542 // }
544 status &= (np->intr_mask | TxDescUnavail);
545 RTL_W16(base + (IntrStatus), intr_clean_mask);
547 if (!(status & unit->rtl8168u_intr_mask))
548 break;
550 //Work around for rx fifo overflow
551 if (status & RxFIFOOver)
553 RTLD(bug("[%s] RTL8168_IntHandlerF: Rx FIFO overflow occured!\n", unit->rtl8168u_name))
554 if (np->mcfg == CFG_METHOD_1) {
555 /*np->rx_fifo_overflow = 1;
556 netif_stop_queue(unit);
557 udelay(300);
558 rtl8168_rx_clear(np);
559 rtl8168_init_ring(unit);
560 rtl8168_hw_start(unit);*/
561 RTL_W16(base + (IntrStatus), RxFIFOOver);
562 /*netif_wake_queue(unit);
563 np->rx_fifo_overflow = 0;*/
567 if (status & SYSErr) {
568 RTLD(bug("[%s] RTL8168_IntHandlerF: PCI error occured!\n", unit->rtl8168u_name))
569 // rtl8168_pcierr_interrupt(unit);
570 break;
573 if (status & LinkChg)
575 RTLD(bug("[%s] RTL8168_IntHandlerF: Link Change!\n", unit->rtl8168u_name))
576 rtl8168_CheckLinkStatus(unit);
579 if ((status & TxOK) && (status & TxDescUnavail))
581 RTL_W8(base + (TxPoll), NPQ); /* set polling bit */
582 RTL_W16(base + (IntrStatus), TxDescUnavail);
584 /* Rx interrupt */
585 if (status & (RxOK | RxDescUnavail | RxFIFOOver))
587 RTLD(bug("[%s] RTL8168_IntHandlerF: Packet Reception detected!\n", unit->rtl8168u_name))
588 RTL8168_Rx_Process(unit);
589 // rtl8168_rx_interrupt(unit, np, np->mmio_addr, ~(u32)0);
591 /* Tx interrupt */
592 if (status & (TxOK | TxErr))
594 RTLD(bug("[%s] RTL8168_IntHandlerF: Packet Transmission detected!\n", unit->rtl8168u_name))
595 RTL8168_Tx_Cleanup(unit);
597 boguscnt--;
598 } while (boguscnt > 0);
600 if (boguscnt <= 0) {
601 RTLD(bug("[%s] RTL8168_IntHandlerF: Too much work at interrupt!\n", unit->rtl8168u_name))
602 /* Clear all interrupt sources. */
603 RTL_W16(base + (IntrStatus), 0xffff);
606 RTL_W16(base + (IntrMask), np->intr_mask);
608 return FALSE;
610 AROS_INTFUNC_EXIT
613 VOID CopyPacket(struct RTL8168Base *RTL8168DeviceBase, struct RTL8168Unit *unit,
614 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
615 struct eth_frame *buffer)
617 struct Opener *opener;
618 BOOL filtered = FALSE;
619 UBYTE *ptr;
620 const UBYTE broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
622 RTLD(bug("[%s] CopyPacket(packet @ %x, len = %d)\n", unit->rtl8168u_name, buffer, packet_size))
624 /* Set multicast and broadcast flags */
626 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
627 if (memcmp(buffer->eth_packet_dest, broadcast, 6) == 0)
629 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
630 RTLD(bug("[%s] CopyPacket: BROADCAST Flag set\n", unit->rtl8168u_name))
632 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
634 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
635 RTLD(bug("[%s] CopyPacket: MULTICAST Flag set\n", unit->rtl8168u_name))
638 /* Set source and destination addresses and packet type */
639 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
640 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
641 request->ios2_PacketType = packet_type;
643 /* Adjust for cooked packet request */
645 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
647 packet_size -= ETH_PACKET_DATA;
648 ptr = (UBYTE*)&buffer->eth_packet_data[0];
650 else
652 ptr = (UBYTE*)buffer;
655 request->ios2_DataLength = packet_size;
657 RTLD(bug("[%s] CopyPacket: packet @ %x (%d bytes)\n", unit->rtl8168u_name, ptr, packet_size))
659 /* Filter packet */
661 opener = request->ios2_BufferManagement;
662 if((request->ios2_Req.io_Command == CMD_READ) &&
663 (opener->filter_hook != NULL))
664 if(!CallHookPkt(opener->filter_hook, request, ptr))
666 RTLD(bug("[%s] CopyPacket: packet filtered\n", unit->rtl8168u_name))
667 filtered = TRUE;
670 if(!filtered)
672 /* Copy packet into opener's buffer and reply packet */
673 RTLD(bug("[%s] CopyPacket: opener recieve packet .. ", unit->rtl8168u_name))
674 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
676 RTLD(bug("ERROR occured!!\n"))
677 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
678 request->ios2_WireError = S2WERR_BUFF_ERROR;
679 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
681 else
683 RTLD(bug("SUCCESS!!\n"))
685 Disable();
686 Remove((APTR)request);
687 Enable();
688 ReplyMsg((APTR)request);
689 RTLD(bug("[%s] CopyPacket: opener notified.\n", unit->rtl8168u_name))
693 BOOL AddressFilter(struct RTL8168Base *RTL8168DeviceBase, struct RTL8168Unit *unit, UBYTE *address)
695 struct AddressRange *range, *tail;
696 BOOL accept = TRUE;
697 ULONG address_left;
698 UWORD address_right;
700 /* Check whether address is unicast/broadcast or multicast */
702 address_left = AROS_BE2LONG(*((ULONG *)address));
703 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
705 if((address_left & 0x01000000) != 0 &&
706 !(address_left == 0xffffffff && address_right == 0xffff))
708 /* Check if this multicast address is wanted */
710 range = (APTR)unit->rtl8168u_multicast_ranges.mlh_Head;
711 tail = (APTR)&unit->rtl8168u_multicast_ranges.mlh_Tail;
712 accept = FALSE;
714 while((range != tail) && !accept)
716 if((address_left > range->lower_bound_left ||
717 (address_left == range->lower_bound_left &&
718 address_right >= range->lower_bound_right)) &&
719 (address_left < range->upper_bound_left ||
720 (address_left == range->upper_bound_left &&
721 address_right <= range->upper_bound_right)))
722 accept = TRUE;
723 range = (APTR)range->node.mln_Succ;
726 if(!accept)
727 unit->rtl8168u_special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
729 return accept;
733 * Unit process
735 AROS_UFH3(void, RTL8168_Schedular,
736 AROS_UFHA(STRPTR, argPtr, A0),
737 AROS_UFHA(ULONG, argSize, D0),
738 AROS_UFHA(struct ExecBase *, SysBase, A6))
740 AROS_USERFUNC_INIT
742 struct Task *taskSelf = FindTask(NULL);
743 struct RTL8168Startup *sm_UD = taskSelf->tc_UserData;
744 struct RTL8168Unit *unit = sm_UD->rtl8168sm_Unit;
746 LIBBASETYPEPTR LIBBASE = unit->rtl8168u_device;
747 struct MsgPort *reply_port, *input;
749 RTLD(bug("[%s] RTL8168_Schedular()\n", taskSelf->tc_Node.ln_Name))
750 RTLD(bug("[%s] RTL8168_Schedular: Setting up device '%s'\n", taskSelf->tc_Node.ln_Name, unit->rtl8168u_name))
752 if ((reply_port = CreateMsgPort()) == NULL)
754 RTLD(bug("[%s] RTL8168_Schedular: Failed to create Reply message port\n", taskSelf->tc_Node.ln_Name))
757 if ((input = CreateMsgPort()) == NULL)
759 RTLD(bug("[%s] RTL8168_Schedular: Failed to create Input message port\n", taskSelf->tc_Node.ln_Name))
762 unit->rtl8168u_input_port = input;
764 if ((unit->rtl8168u_TimerSlowPort = CreateMsgPort()) != NULL)
766 unit->rtl8168u_TimerSlowReq = (struct timerequest *)
767 CreateIORequest((struct MsgPort *)unit->rtl8168u_TimerSlowPort, sizeof(struct timerequest));
769 if (unit->rtl8168u_TimerSlowReq)
771 if (!OpenDevice("timer.device", UNIT_MICROHZ,
772 (struct IORequest *)unit->rtl8168u_TimerSlowReq, 0))
774 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC|MEMF_CLEAR);
775 ULONG sigset;
777 RTLD(bug("[%s] RTL8168_Schedular: Got MICROHZ unit of timer.device\n", taskSelf->tc_Node.ln_Name))
779 unit->initialize(unit);
781 msg->mn_ReplyPort = reply_port;
782 msg->mn_Length = sizeof(struct Message);
784 RTLD(bug("[%s] RTL8168_Schedular: Setup complete. Sending handshake\n", taskSelf->tc_Node.ln_Name))
785 PutMsg(sm_UD->rtl8168sm_SyncPort, msg);
786 WaitPort(reply_port);
787 GetMsg(reply_port);
789 FreeVec(msg);
791 RTLD(bug("[%s] RTL8168_Schedular: entering forever loop ... \n", taskSelf->tc_Node.ln_Name))
793 unit->rtl8168u_signal_0 = AllocSignal(-1);
794 unit->rtl8168u_signal_1 = AllocSignal(-1);
795 unit->rtl8168u_signal_2 = AllocSignal(-1);
796 unit->rtl8168u_signal_3 = AllocSignal(-1);
798 sigset = 1 << input->mp_SigBit |
799 1 << unit->rtl8168u_signal_0 |
800 1 << unit->rtl8168u_signal_1 |
801 1 << unit->rtl8168u_signal_2 |
802 1 << unit->rtl8168u_signal_3;
803 for(;;)
805 ULONG recvd = Wait(sigset);
806 if (recvd & unit->rtl8168u_signal_0)
809 * Shutdown process. Driver should close everything
810 * already and waits for our process to complete. Free
811 * memory allocared here and kindly return.
813 unit->deinitialize(unit);
814 CloseDevice((struct IORequest *)unit->rtl8168u_TimerSlowReq);
815 DeleteIORequest((struct IORequest *)unit->rtl8168u_TimerSlowReq);
816 DeleteMsgPort(unit->rtl8168u_TimerSlowPort);
817 DeleteMsgPort(input);
818 DeleteMsgPort(reply_port);
820 RTLD(bug("[%s] RTL8168_Schedular: Process shutdown.\n", taskSelf->tc_Node.ln_Name))
821 return;
823 else if (recvd & (1 << input->mp_SigBit))
825 struct IOSana2Req *io;
827 /* Handle incoming transactions */
828 while ((io = (struct IOSana2Req *)GetMsg(input)) != NULL)
830 RTLD(bug("[%s] RTL8168_Schedular: Handle incomming transaction.\n", taskSelf->tc_Node.ln_Name))
831 ObtainSemaphore(&unit->rtl8168u_unit_lock);
832 handle_request(LIBBASE, io);
835 else
837 RTLD(bug("[%s] RTL8168_Schedular: Handle incomming signal.\n", taskSelf->tc_Node.ln_Name))
838 /* Handle incoming signals */
845 AROS_USERFUNC_EXIT
848 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct RTL8168Unit *unit,
849 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
851 struct AddressRange *range, *tail;
852 BOOL found = FALSE;
854 range = (APTR)unit->rtl8168u_multicast_ranges.mlh_Head;
855 tail = (APTR)&unit->rtl8168u_multicast_ranges.mlh_Tail;
857 while((range != tail) && !found)
859 if((lower_bound_left == range->lower_bound_left) &&
860 (lower_bound_right == range->lower_bound_right) &&
861 (upper_bound_left == range->upper_bound_left) &&
862 (upper_bound_right == range->upper_bound_right))
863 found = TRUE;
864 else
865 range = (APTR)range->node.mln_Succ;
868 if(!found)
869 range = NULL;
871 return range;
874 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct RTL8168Unit *unit, const UBYTE *lower_bound,
875 const UBYTE *upper_bound)
877 struct AddressRange *range;
878 ULONG lower_bound_left, upper_bound_left;
879 UWORD lower_bound_right, upper_bound_right;
881 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
882 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
883 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
884 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
886 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
887 upper_bound_left, upper_bound_right);
889 if(range != NULL)
890 range->add_count++;
891 else
893 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
894 if(range != NULL)
896 range->lower_bound_left = lower_bound_left;
897 range->lower_bound_right = lower_bound_right;
898 range->upper_bound_left = upper_bound_left;
899 range->upper_bound_right = upper_bound_right;
900 range->add_count = 1;
902 Disable();
903 AddTail((APTR)&unit->rtl8168u_multicast_ranges, (APTR)range);
904 Enable();
906 if (unit->rtl8168u_range_count++ == 0)
908 unit->rtl8168u_flags |= IFF_ALLMULTI;
909 unit->set_multicast(unit);
914 return range != NULL;
917 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE, struct RTL8168Unit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
919 struct AddressRange *range;
920 ULONG lower_bound_left, upper_bound_left;
921 UWORD lower_bound_right, upper_bound_right;
923 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
924 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
925 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
926 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
928 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
929 upper_bound_left, upper_bound_right);
931 if(range != NULL)
933 if(--range->add_count == 0)
935 Disable();
936 Remove((APTR)range);
937 Enable();
938 FreeMem(range, sizeof(struct AddressRange));
940 if (--unit->rtl8168u_range_count == 0)
942 unit->rtl8168u_flags &= ~IFF_ALLMULTI;
943 unit->set_multicast(unit);
947 return range != NULL;
951 * Create new RTL8168 ethernet device unit
953 struct RTL8168Unit *CreateUnit(struct RTL8168Base *RTL8168DeviceBase, OOP_Object *pciDevice, IPTR CardRevision)
955 struct RTL8168Unit *unit;
956 BOOL success = TRUE;
957 int i;
959 #if defined(RTL_DEBUG)
960 BOOL doDebug = TRUE;
961 #else
962 /* TODO: Get option to debug from somewhere .. */
963 BOOL doDebug = FALSE;
964 #endif
966 if (doDebug)
968 bug("[rtl8168] CreateUnit()\n");
971 if ((unit = AllocMem(sizeof(struct RTL8168Unit), MEMF_PUBLIC | MEMF_CLEAR)) != NULL)
973 IPTR mmiobase, mmiolen, type;
974 // IPTR DeviceID;
975 OOP_Object *driver;
976 BOOL mmioerror = FALSE;
978 if (doDebug)
979 unit->rtl8168u_flags |= IFF_DEBUG;
981 unit->rtl8168u_UnitNum = RTL8168DeviceBase->rtl8168b_UnitCount++;
983 unit->rtl8168u_Sana2Info.HardwareType = S2WireType_Ethernet;
984 unit->rtl8168u_Sana2Info.MTU = ETH_MTU;
985 unit->rtl8168u_Sana2Info.AddrFieldSize = 8 * ETH_ADDRESSSIZE;
987 unit->rtl8168u_intr_mask = SYSErr | LinkChg | RxDescUnavail | TxErr | TxOK | RxErr | RxOK;
989 if ((unit->rtl8168u_name = AllocVec(8 + (unit->rtl8168u_UnitNum/10) + 2, MEMF_CLEAR|MEMF_PUBLIC)) == NULL)
991 FreeMem(unit, sizeof(struct RTL8168Unit));
992 return NULL;
994 sprintf((char *)unit->rtl8168u_name, "rtl8168.%d", unit->rtl8168u_UnitNum);
996 RTLD(bug("[rtl8168] CreateUnit: Unit allocated @ 0x%p\n", unit))
998 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&driver);
1000 unit->rtl8168u_device = RTL8168DeviceBase;
1001 unit->rtl8168u_PCIDevice = pciDevice;
1002 unit->rtl8168u_PCIDriver = driver;
1004 unit->rtl8168u_mtu = unit->rtl8168u_Sana2Info.MTU;
1006 InitSemaphore(&unit->rtl8168u_unit_lock);
1007 NEWLIST(&unit->rtl8168u_Openers);
1008 NEWLIST(&unit->rtl8168u_multicast_ranges);
1009 NEWLIST(&unit->rtl8168u_type_trackers);
1011 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->rtl8168u_IRQ);
1012 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, (IPTR *)&unit->rtl8168u_BaseIO);
1013 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base2, &mmiobase);
1014 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size2, &mmiolen);
1015 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Type2, &type);
1017 RTLD(bug("[%s] CreateUnit: INT:%d, base0:0x%p, base2:0x%p, size2:%d\n", unit->rtl8168u_name,
1018 unit->rtl8168u_IRQ, unit->rtl8168u_BaseIO,
1019 mmiobase, mmiolen))
1021 if (type & ADDRF_IO)
1023 RTLD(bug("[%s] CreateUnit: MMIO Region of wrong type!\n", unit->rtl8168u_name))
1024 mmioerror = TRUE;
1027 if (mmiolen < R8168_REGS_SIZE)
1029 RTLD(bug("[%s] CreateUnit: Invalid MMIO Reg size (%d, expected %d)\n", unit->rtl8168u_name,
1030 mmiolen,
1031 R8168_REGS_SIZE))
1032 mmioerror = TRUE;
1035 if (mmioerror)
1037 FreeMem(unit->rtl8168u_name, 8 + (unit->rtl8168u_UnitNum/10) + 2);
1038 FreeMem(unit, sizeof(struct RTL8168Unit));
1039 return NULL;
1042 /* TODO: how do we set memory write invalidate for PCI devices on AROS? */
1044 unit->rtl8168u_SizeMem = R8168_REGS_SIZE;
1045 unit->rtl8168u_BaseMem = HIDD_PCIDriver_MapPCI(driver, (APTR)mmiobase, unit->rtl8168u_SizeMem);
1047 if (unit->rtl8168u_BaseMem != NULL)
1049 struct TagItem attrs[] = {
1050 { aHidd_PCIDevice_isIO, TRUE },
1051 { aHidd_PCIDevice_isMEM, TRUE },
1052 { aHidd_PCIDevice_isMaster, TRUE },
1053 { TAG_DONE, 0 },
1055 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
1057 RTLD(bug("[%s] CreateUnit: PCI_BaseMem @ 0x%p\n", unit->rtl8168u_name, unit->rtl8168u_BaseMem))
1059 unit->rtl8168u_DelayPort.mp_SigBit = SIGB_SINGLE;
1060 unit->rtl8168u_DelayPort.mp_Flags = PA_SIGNAL;
1061 unit->rtl8168u_DelayPort.mp_SigTask = FindTask(NULL);
1062 unit->rtl8168u_DelayPort.mp_Node.ln_Type = NT_MSGPORT;
1063 NEWLIST(&unit->rtl8168u_DelayPort.mp_MsgList);
1065 unit->rtl8168u_DelayReq.tr_node.io_Message.mn_ReplyPort = &unit->rtl8168u_DelayPort;
1066 unit->rtl8168u_DelayReq.tr_node.io_Message.mn_Length = sizeof(struct timerequest);
1068 OpenDevice((STRPTR)"timer.device", UNIT_MICROHZ, (struct IORequest *)&unit->rtl8168u_DelayReq, 0);
1070 if ((unit->rtl8168u_priv = AllocMem(sizeof(struct rtl8168_priv), MEMF_PUBLIC|MEMF_CLEAR)) != NULL)
1072 unit->rtl8168u_priv->pci_dev = unit;
1073 InitSemaphore(&unit->rtl8168u_priv->lock);
1076 struct Message *msg;
1078 unit->rtl8168u_irqhandler.is_Node.ln_Type = NT_INTERRUPT;
1079 unit->rtl8168u_irqhandler.is_Node.ln_Pri = 100;
1080 unit->rtl8168u_irqhandler.is_Node.ln_Name = LIBBASE->rtl8168b_Device.dd_Library.lib_Node.ln_Name;
1081 unit->rtl8168u_irqhandler.is_Code = (VOID_FUNC)RTL8168_IntHandlerF;
1082 unit->rtl8168u_irqhandler.is_Data = unit;
1084 unit->rtl8168u_touthandler.is_Node.ln_Type = NT_INTERRUPT;
1085 unit->rtl8168u_touthandler.is_Node.ln_Pri = 100;
1086 unit->rtl8168u_touthandler.is_Node.ln_Name = LIBBASE->rtl8168b_Device.dd_Library.lib_Node.ln_Name;
1087 unit->rtl8168u_touthandler.is_Code = (VOID_FUNC)RTL8168_TimeoutHandlerF;
1088 unit->rtl8168u_touthandler.is_Data = unit;
1090 unit->rtl8168u_rx_int.is_Node.ln_Type = NT_INTERRUPT;
1091 unit->rtl8168u_rx_int.is_Node.ln_Name = unit->rtl8168u_name;
1092 //unit->rtl8168u_rx_int.is_Code = (VOID_FUNC)RTL8168_RX_IntF;
1093 unit->rtl8168u_rx_int.is_Data = unit;
1095 unit->rtl8168u_tx_int.is_Node.ln_Type = NT_INTERRUPT;
1096 unit->rtl8168u_tx_int.is_Node.ln_Name = unit->rtl8168u_name;
1097 unit->rtl8168u_tx_int.is_Code = (VOID_FUNC)RTL8168_TX_IntF;
1098 unit->rtl8168u_tx_int.is_Data = unit;
1100 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1102 struct MsgPort *port = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR);
1103 unit->rtl8168u_request_ports[i] = port;
1105 if (port == NULL) success = FALSE;
1107 if (success)
1109 NEWLIST(&port->mp_MsgList);
1110 port->mp_Flags = PA_IGNORE;
1111 port->mp_SigTask = &unit->rtl8168u_tx_int;
1115 unit->rtl8168u_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
1117 if (success)
1119 struct RTL8168Startup *sm_UD;
1120 UBYTE tmpbuff[100];
1122 if ((sm_UD = AllocMem(sizeof(struct RTL8168Startup), MEMF_PUBLIC | MEMF_CLEAR)) != NULL)
1124 sprintf((char *)tmpbuff, RTL8168_TASK_NAME, unit->rtl8168u_name);
1126 sm_UD->rtl8168sm_SyncPort = CreateMsgPort();
1127 sm_UD->rtl8168sm_Unit = unit;
1129 rtl8168nic_get_functions(unit);
1131 unit->rtl8168u_Process = CreateNewProcTags(
1132 NP_Entry, (IPTR)RTL8168_Schedular,
1133 NP_Name, tmpbuff,
1134 NP_Synchronous , FALSE,
1135 NP_Priority, 0,
1136 NP_UserData, (IPTR)sm_UD,
1137 NP_StackSize, 140960,
1138 TAG_DONE);
1140 WaitPort(sm_UD->rtl8168sm_SyncPort);
1141 msg = GetMsg(sm_UD->rtl8168sm_SyncPort);
1142 ReplyMsg(msg);
1143 DeleteMsgPort(sm_UD->rtl8168sm_SyncPort);
1144 FreeMem(sm_UD, sizeof(struct RTL8168Startup));
1146 RTLD(bug("[%s] CreateUnit: Device Initialised. Unit %d @ %p\n", unit->rtl8168u_name, unit->rtl8168u_UnitNum, unit))
1147 return unit;
1150 else
1152 RTLD(bug("[%s] ERRORS occured during Device setup - ABORTING\n", unit->rtl8168u_name))
1157 else
1159 RTLD(bug("[rtl8168] PANIC! Couldn't get MMIO area. Aborting\n"))
1162 else if (doDebug)
1164 bug("[rtl8168] CreateUnit: Failed to Allocate Unit storage!\n");
1165 return NULL;
1167 DeleteUnit(RTL8168DeviceBase, unit);
1168 return NULL;
1172 * DeleteUnit - removes selected unit. Frees all resources and structures.
1174 * The caller should be sure, that given unit is really ready to be freed.
1177 void DeleteUnit(struct RTL8168Base *RTL8168DeviceBase, struct RTL8168Unit *Unit)
1179 int i;
1180 if (Unit)
1182 if (Unit->rtl8168u_Process)
1184 Signal(&Unit->rtl8168u_Process->pr_Task, Unit->rtl8168u_signal_0);
1187 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1189 if (Unit->rtl8168u_request_ports[i] != NULL)
1190 FreeMem(Unit->rtl8168u_request_ports[i], sizeof(struct MsgPort));
1192 Unit->rtl8168u_request_ports[i] = NULL;
1195 if (Unit->rtl8168u_priv)
1197 FreeMem(Unit->rtl8168u_priv, sizeof(struct rtl8168_priv));
1198 Unit->rtl8168u_priv = NULL;
1201 if (Unit->rtl8168u_BaseMem)
1203 HIDD_PCIDriver_UnmapPCI(Unit->rtl8168u_PCIDriver,
1204 (APTR)Unit->rtl8168u_BaseMem,
1205 Unit->rtl8168u_SizeMem);
1208 FreeMem(Unit, sizeof(struct RTL8168Unit));