- Corrected signal masks. Process now quits on shutdown, which allows
[AROS.git] / workbench / devs / networks / rtl8169 / unit.c
blob3b0717cb638424f53d41c2d40cc199666d8fedfe
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 "rtl8169.h"
49 #include "unit.h"
50 #include LC_LIBDEFS_FILE
52 extern UBYTE MMIO_R8(UBYTE *);
53 extern UWORD MMIO_R16(UWORD *);
54 extern ULONG MMIO_R32(ULONG *);
56 extern void rtl8169_CheckLinkStatus(struct net_device *);
59 * Report incoming events to all hyphotetical event receivers
61 VOID ReportEvents(struct RTL8169Base *RTL8169DeviceBase, struct RTL8169Unit *unit, ULONG events)
63 struct IOSana2Req *request, *tail, *next_request;
64 struct List *list;
66 list = &unit->rtl8169u_request_ports[EVENT_QUEUE]->mp_MsgList;
67 next_request = (APTR)list->lh_Head;
68 tail = (APTR)&list->lh_Tail;
70 /* Go through list of event listeners. If send messages to receivers if event found */
71 Disable();
72 while(next_request != tail)
74 request = next_request;
75 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
77 if((request->ios2_WireError&events) != 0)
79 request->ios2_WireError = events;
80 Remove((APTR) request);
81 ReplyMsg((APTR) request);
84 Enable();
87 struct TypeStats *FindTypeStats(struct RTL8169Base *RTL8169DeviceBase, struct RTL8169Unit *unit,
88 struct MinList *list, ULONG packet_type)
90 struct TypeStats *stats, *tail;
91 BOOL found = FALSE;
93 stats = (APTR)list->mlh_Head;
94 tail = (APTR)&list->mlh_Tail;
96 while(stats != tail && !found)
98 if(stats->packet_type == packet_type)
100 found = TRUE;
102 else
104 stats = (APTR) stats->node.mln_Succ;
108 if(!found)
110 stats = NULL;
113 return stats;
116 void FlushUnit(LIBBASETYPEPTR LIBBASE, struct RTL8169Unit *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->rtl8169u_name))
124 /* Abort queued operations */
125 for (i=0; i <= last_queue; i++)
127 while ((request = (APTR) GetMsg(unit->rtl8169u_request_ports[i])) != NULL)
129 request->io_Error = IOERR_ABORTED;
130 ReplyMsg((struct Message *)request);
134 opener = (APTR) unit->rtl8169u_Openers.mlh_Head;
135 tail = (APTR) unit->rtl8169u_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 int rtl8169_fragmented_frame(ULONG status)
151 return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
154 static inline void rtl8169_MarkToASIC(struct RxDesc *desc, ULONG rx_buf_sz)
156 // ULONG eor = AROS_LE2LONG(desc->opts1) & RingEnd;
158 desc->opts1 = AROS_LONG2LE(DescOwn | rx_buf_sz);
161 /* Interrupt Rx Support Function ..
162 * It's duty is to iterate through RX queue searching for new packets.
164 void RTL8169_Rx_Process(struct RTL8169Unit *unit)
166 struct RTL8169Base *RTL8169DeviceBase = unit->rtl8169u_device;
167 struct rtl8169_priv *np = unit->rtl8169u_priv;
168 // UBYTE *base = unit->rtl8169u_BaseMem;
170 struct TypeStats *tracker;
171 ULONG packet_type;
172 struct Opener *opener;
173 struct Opener *opener_tail;
174 struct IOSana2Req *request;
175 struct IOSana2Req *request_tail;
176 BOOL accepted;
177 BOOL is_orphan;
178 // unsigned int delta;
179 // unsigned int count;
180 // unsigned int rx_left;
181 unsigned int cur_rx;
183 RTLD(bug("[%s] RTL8169_Rx_Process()\n", unit->rtl8169u_name))
185 for(;;)
187 UWORD len = 0;
188 // UWORD overspill = 0;
189 struct eth_frame *frame;
191 unsigned long rx_status;
192 unsigned int rx_size;
194 cur_rx = np->cur_rx;
195 struct RxDesc *desc = np->RxDescArray + cur_rx;
197 rx_status = AROS_LE2LONG(desc->opts1);
199 if(rx_status & DescOwn)
201 break;
204 rx_size = (rx_status & 0x00001FFF) - ETH_CRCSIZE;
206 if (rx_status & RxRES)
208 RTLD(bug("[%s] RTL8169_RX_Process: Ethernet frame had errors, Status %8.8x\n",
209 unit->rtl8169u_name, rx_status))
210 rtl8169_MarkToASIC(desc, (ULONG) np->rx_buf_sz);
212 else
214 len = rx_size;
215 frame = (APTR)(IPTR)AROS_LE2LONG(desc->addr);
217 RTLD(bug("[%s] RTL8169_RX_Process: frame @ %p, len=%d, pool index=%d\n", unit->rtl8169u_name, frame, len, cur_rx))
219 // got a valid packet - forward it to the network core
220 is_orphan = TRUE;
222 // Check for address validity
223 if(AddressFilter(LIBBASE, unit, frame->eth_packet_dest))
225 // Packet is addressed to this driver
226 packet_type = AROS_BE2WORD(frame->eth_packet_type);
227 RTLD(bug("[%s] RTL8169_RX_Process: Packet IP accepted with type = %d\n",
228 unit->rtl8169u_name, packet_type))
230 opener = (APTR) unit->rtl8169u_Openers.mlh_Head;
231 opener_tail = (APTR) &unit->rtl8169u_Openers.mlh_Tail;
233 // Offer packet to every opener
234 while(opener != opener_tail)
236 RTLD(bug("[%s] RTL8169_RX_Process: checking opener %p\n", unit->rtl8169u_name, opener))
238 request = (APTR) opener->read_port.mp_MsgList.lh_Head;
239 request_tail = (APTR) &opener->read_port.mp_MsgList.lh_Tail;
240 accepted = FALSE;
242 // Offer packet to each request until it's accepted
243 while((request != request_tail) && !accepted)
245 if((request->ios2_PacketType == packet_type)
246 || ((request->ios2_PacketType <= ETH_MTU)
247 && (packet_type <= ETH_MTU)))
249 RTLD(bug("[%s] RTL8169_RX_Process: copy packet for opener ...\n", unit->rtl8169u_name))
250 CopyPacket(LIBBASE, unit, request, len, packet_type, frame);
251 accepted = TRUE;
253 request = (struct IOSana2Req *) request->ios2_Req.io_Message.mn_Node.ln_Succ;
256 if(accepted)
258 is_orphan = FALSE;
261 opener = (APTR) opener->node.mln_Succ;
264 // If packet was unwanted, give it to S2_READORPHAN request
265 if(is_orphan)
267 unit->rtl8169u_stats.UnknownTypesReceived++;
269 if(!IsMsgPortEmpty(unit->rtl8169u_request_ports[ADOPT_QUEUE]))
271 RTLD(bug("[%s] RTL8169_RX_Process: copy orphan packet ...\n", unit->rtl8169u_name))
272 CopyPacket(LIBBASE, unit,
273 (APTR) unit->rtl8169u_request_ports[ADOPT_QUEUE]->mp_MsgList.lh_Head,
274 len,
275 packet_type,
276 frame
278 RTLD(bug("[%s] RTL8169_RX_Process: packet copied to orphan queue\n", unit->rtl8169u_name))
282 rtl8169_MarkToASIC(desc, (ULONG) np->rx_buf_sz);
284 // Update remaining statistics
285 tracker = FindTypeStats(LIBBASE, unit, &unit->rtl8169u_type_trackers, packet_type);
287 if(tracker != NULL)
289 tracker->stats.PacketsReceived++;
290 tracker->stats.BytesReceived += len;
291 RTLD(bug("[%s] RTL8169_RX_Process: stats updated.\n", unit->rtl8169u_name))
294 unit->rtl8169u_stats.PacketsReceived++;
297 /* if((desc->opts2 & AROS_LONG2LE(0xfffe000) &&
298 np->mcfg == RTL_GIGA_MAC_VER_05))
300 desc->opts2 = 0;
301 // np->cur_rx++;
304 if(np->cur_rx == (NUM_RX_DESC - 1))
306 desc->opts1 = AROS_LONG2LE((DescOwn | RingEnd | (ULONG) np->rx_buf_sz));
307 desc->opts2 = 0;
309 else
311 desc->opts1 = AROS_LONG2LE(DescOwn | (ULONG) np->rx_buf_sz);
312 desc->opts2 = 0;
315 np->cur_rx++;
316 np->cur_rx %= NUM_RX_DESC;
318 // if(np->cur_rx >= NUM_RX_DESC)
319 // {
320 // RTLD(bug("[%s] RTL8169_RX_Process: rx buffers pool exhausted.\n", unit->rtl8169u_name))
321 // break;
322 // }
327 * Interrupt generated by Cause() to push new packets into the NIC interface
329 static AROS_INTH1(RTL8169_TX_IntF, struct RTL8169Unit *, unit)
331 AROS_INTFUNC_INIT
333 struct rtl8169_priv *np = unit->rtl8169u_priv;
334 struct RTL8169Base *RTL8169DeviceBase = unit->rtl8169u_device;
335 int nr;
336 BOOL proceed = FALSE; /* Fails by default */
338 RTLD(bug("[%s] RTL8169_TX_IntF()\n", unit->rtl8169u_name))
340 // send packet only if there is free space on tx queue. Otherwise do nothing
341 if (!netif_queue_stopped(unit))
343 UWORD packet_size, data_size;
344 struct IOSana2Req *request;
345 struct Opener *opener;
346 UBYTE *buffer;
347 ULONG wire_error = 0;
348 BYTE error;
349 struct MsgPort *port;
350 struct TypeStats *tracker;
352 proceed = TRUE; // Success by default
353 UBYTE *base = (UBYTE *) unit->rtl8169u_BaseMem;
354 port = unit->rtl8169u_request_ports[WRITE_QUEUE];
356 // Still no error and there are packets to be sent ?
357 while(!IsMsgPortEmpty(port))
359 nr = np->cur_tx % NUM_TX_DESC;
360 error = 0;
362 request = (APTR) port->mp_MsgList.lh_Head;
363 data_size = packet_size = request->ios2_DataLength;
365 opener = (APTR) request->ios2_BufferManagement;
367 if (!(AROS_LE2LONG(np->TxDescArray[nr].opts1) & DescOwn))
369 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
371 packet_size += ETH_PACKET_DATA;
372 CopyMem(request->ios2_DstAddr,
373 &((struct eth_frame *)(IPTR)np->TxDescArray[nr].addr)->eth_packet_dest,
374 ETH_ADDRESSSIZE);
375 CopyMem(unit->rtl8169u_dev_addr,
376 &((struct eth_frame *)(IPTR)np->TxDescArray[nr].addr)->eth_packet_source,
377 ETH_ADDRESSSIZE);
378 ((struct eth_frame *)(IPTR)np->TxDescArray[nr].addr)->eth_packet_type = AROS_WORD2BE(request->ios2_PacketType);
380 buffer = (APTR)&((struct eth_frame *)(IPTR)np->TxDescArray[nr].addr)->eth_packet_data;
382 else
384 buffer = (APTR)(IPTR)np->TxDescArray[nr].addr;
386 if (packet_size < TX_BUF_SIZE)
388 memset(buffer, 0, TX_BUF_SIZE - packet_size);
391 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
393 error = S2ERR_NO_RESOURCES;
394 wire_error = S2WERR_BUFF_ERROR;
395 ReportEvents(LIBBASE, unit,
396 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF |
397 S2EVENT_TX);
400 // Now the packet is already in TX buffer, update flags for NIC
401 if (error == 0)
403 #ifdef DEBUG
404 Disable();
405 RTLD(bug("[%s] RTL8139_TX_IntF: packet %d @ %p [type = %d] queued for transmission.",
406 unit->rtl8169u_name,
408 (APTR)(IPTR)np->TxDescArray[nr].addr,
409 AROS_BE2WORD(((struct eth_frame *)(IPTR)np->TxDescArray[nr].addr)->eth_packet_type)))
411 RTLD( int j;
412 for (j = 0; j < 64; j++)
414 if ((j%16) == 0)
416 bug("\n%03x:", j);
418 bug(" %02x", ((unsigned char*)(IPTR)np->TxDescArray[nr].addr)[j]);
420 bug("\n");)
423 Enable();
424 #endif
425 // Set the ring details for the packet ..
426 np->TxDescArray[nr].opts1 = AROS_LONG2LE(DescOwn | FirstFrag | LastFrag | packet_size | (RingEnd * !((nr + 1) % NUM_TX_DESC)));
427 np->TxDescArray[nr].opts2 = AROS_LONG2LE(0);
429 RTL_W8(base + (TxPoll), NPQ);
432 // Reply packet
433 request->ios2_Req.io_Error = error;
434 request->ios2_WireError = wire_error;
435 Disable();
436 Remove((APTR) request);
437 Enable();
438 ReplyMsg((APTR) request);
440 // Update statistics
441 if(error == 0)
443 tracker = FindTypeStats(LIBBASE, unit,
444 &unit->rtl8169u_type_trackers,
445 request->ios2_PacketType);
446 if(tracker != NULL)
448 tracker->stats.PacketsSent++;
449 tracker->stats.BytesSent += packet_size;
454 np->cur_tx++;
455 } // while
458 // Was there success? Enable incoming of new packets
459 if(proceed)
461 unit->rtl8169u_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
463 else
465 unit->rtl8169u_request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
468 return FALSE;
470 AROS_INTFUNC_EXIT
474 * Handle timeouts and other strange cases
476 static AROS_INTH1(RTL8169_TimeoutHandlerF, struct RTL8169Unit *,unit)
478 AROS_INTFUNC_INIT
480 struct timeval time;
481 struct Device *TimerBase = unit->rtl8169u_TimerSlowReq->tr_node.io_Device;
483 GetSysTime(&time);
484 //RTLD(bug("[%s] RTL8169_TimeoutHandlerF()\n", unit->rtl8169u_name))
487 * If timeout timer is expected, and time elapsed - regenerate the
488 * interrupt handler
490 if (unit->rtl8169u_toutNEED && (CmpTime(&time, &unit->rtl8169u_toutPOLL ) < 0))
492 unit->rtl8169u_toutNEED = FALSE;
493 //Cause(&unit->rtl8169u_tx_end_int);
496 return FALSE;
498 AROS_INTFUNC_EXIT
501 /*static void RTL8169_Tx_Cleanup(struct net_device *unit)
503 struct rtl8169_priv *np = unit->rtl8169u_priv;
504 unsigned int dirty_tx, tx_left;
505 struct TypeStats *tracker;
507 dirty_tx = np->dirty_tx;
508 tx_left = np->cur_tx - dirty_tx;
510 while (tx_left > 0)
512 unsigned int entry = dirty_tx % NUM_TX_DESC;
513 ULONG packet_size, status;
515 status = AROS_LE2LONG(np->TxDescArray[entry].opts1);
517 if (status & DescOwn)
519 break;
522 packet_size = status & 0x3FFF;
523 tracker = FindTypeStats(unit->rtl8169u_device,
524 unit,
525 &unit->rtl8169u_type_trackers,
526 ((struct eth_frame *) np->TxDescArray[entry].addr)->eth_packet_type);
527 if(tracker != NULL)
529 tracker->stats.PacketsSent++;
530 tracker->stats.BytesSent += packet_size;
533 if (status & LastFrag)
535 RTLD(bug("[%s] RTL8169_Tx_Cleanup: Released buffer %d (%d bytes)\n", unit->rtl8169u_name, entry, packet_size))
536 np->TxDescArray[entry].opts1 = AROS_LONG2LE(RingEnd);
537 np->TxDescArray[entry].addr = NULL;
539 dirty_tx++;
540 tx_left--;
542 if (np->dirty_tx != dirty_tx)
544 np->dirty_tx = dirty_tx;
549 * Interrupt handler called whenever RTL8169 NIC interface generates interrupt.
551 static AROS_INTH1(RTL8169_IntHandlerF, struct RTL8169Unit *, unit)
553 AROS_INTFUNC_INIT
555 struct rtl8169_priv *np = unit->rtl8169u_priv;
556 UBYTE *base = (UBYTE *) unit->rtl8169u_BaseMem;
557 int status;
559 int boguscnt = unit->rtl8169u_device->rtl8169b_MaxIntWork;
561 np->intr_mask = 0xffff;
563 RTL_W16(base + (IntrMask), 0x0000);
567 status = RTL_R16(base + (IntrStatus));
569 RTLD(bug("[%s] RTL8169_IntHandlerF(), Status: %x\n", unit->rtl8169u_name, status))
571 /* hotplug/major error/no more work/shared irq */
572 if ((status == 0xFFFF) || !status)
574 break;
577 status &= np->intr_mask;
578 RTL_W16(base + (IntrStatus), (status & RxFIFOOver) ? (status | RxOverflow) : status);
580 if (!(status & np->intr_event))
582 break;
585 /* Work around for rx fifo overflow */
586 if ((status & RxFIFOOver) &&
587 (np->mcfg == RTL_GIGA_MAC_VER_11))
589 RTL_W16(base + (IntrStatus), RxFIFOOver);
590 RTLD(bug("[%s] RTL8169_IntHandlerF: Rx FIFO overflow occured!\n", unit->rtl8169u_name))
591 break;
594 if (status & SYSErr)
596 RTLD(bug("[%s] RTL8169_IntHandlerF: PCI error occured!\n", unit->rtl8169u_name))
597 break;
600 if (status & LinkChg)
602 RTLD(bug("[%s] RTL8169_IntHandlerF: Link Change!\n", unit->rtl8169u_name))
603 rtl8169_CheckLinkStatus(unit);
606 if ((status & TxOK) && (status & TxDescUnavail))
608 RTL_W8(base + (TxPoll), NPQ);
609 RTL_W16(base + (IntrStatus), TxDescUnavail);
612 if(status & (RxOK | RxFIFOOver))
614 RTL8169_Rx_Process(unit);
617 // if (status & (TxOK | TxErr))
618 // {
619 // RTL8169_Tx_Cleanup(unit);
620 // }
622 /* if (status & np->napi_event)
624 RTLD(bug("[%s] RTL8169_IntHandlerF: napi event!\n", unit->rtl8169u_name))
625 RTL_W16(base + IntrMask, np->intr_event & ~np->napi_event);
626 // np->intr_mask = ~np->napi_event;
629 boguscnt--;
630 } while (boguscnt > 0);
632 if (boguscnt <= 0)
634 RTLD(bug("[%s] RTL8169_IntHandlerF: Too much work in interrupt!\n", unit->rtl8169u_name))
635 // Clear all interrupt sources.
636 RTL_W16(base + (IntrStatus), 0xffff);
639 RTL_W16(base + (IntrMask), np->intr_mask);
641 return FALSE;
643 AROS_INTFUNC_EXIT
646 int CopyPacket(struct RTL8169Base *RTL8169DeviceBase, struct RTL8169Unit *unit,
647 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
648 struct eth_frame *buffer)
650 struct Opener *opener;
651 BOOL filtered = FALSE;
652 UBYTE *ptr;
653 const UBYTE broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
655 RTLD(bug("[%s] CopyPacket(packet @ %x, len = %d)\n", unit->rtl8169u_name, buffer, packet_size))
657 /* Set multicast and broadcast flags */
659 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
660 if (memcmp(buffer->eth_packet_dest, broadcast, 6) == 0)
662 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
663 RTLD(bug("[%s] CopyPacket: BROADCAST Flag set\n", unit->rtl8169u_name))
665 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
667 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
668 RTLD(bug("[%s] CopyPacket: MULTICAST Flag set\n", unit->rtl8169u_name))
671 /* Set source and destination addresses and packet type */
672 RTLD(bug("[%s] Copymem... @ %x\n", unit->rtl8169u_name, buffer))
673 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
674 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
675 request->ios2_PacketType = packet_type;
677 /* Adjust for cooked packet request */
679 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
681 packet_size -= ETH_PACKET_DATA;
682 ptr = (UBYTE *) &buffer->eth_packet_data[0];
684 else
686 ptr = (UBYTE *) buffer;
689 request->ios2_DataLength = packet_size;
691 RTLD(bug("[%s] CopyPacket: packet @ %x (%d bytes)\n", unit->rtl8169u_name, ptr, packet_size))
693 /* Filter packet */
694 opener = request->ios2_BufferManagement;
695 if((request->ios2_Req.io_Command == CMD_READ) &&
696 (opener->filter_hook != NULL))
698 if(!CallHookPkt(opener->filter_hook, request, ptr))
700 RTLD(bug("[%s] CopyPacket: packet filtered\n", unit->rtl8169u_name))
701 filtered = TRUE;
705 if(!filtered)
707 /* Copy packet into opener's buffer and reply packet */
708 RTLD(bug("[%s] CopyPacket: opener receive packet ... ", unit->rtl8169u_name))
709 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
711 RTLD(bug("ERROR occured!!\n"))
712 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
713 request->ios2_WireError = S2WERR_BUFF_ERROR;
714 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
716 else
718 RTLD(bug("SUCCESS!!\n"))
720 Disable();
721 Remove((APTR) request);
722 Enable();
723 ReplyMsg((APTR) request);
724 RTLD(bug("[%s] CopyPacket: opener notified.\n", unit->rtl8169u_name))
725 return(1);
727 return(0);
730 BOOL AddressFilter(struct RTL8169Base *RTL8169DeviceBase, struct RTL8169Unit *unit, UBYTE *address)
732 struct AddressRange *range, *tail;
733 BOOL accept = TRUE;
734 ULONG address_left;
735 UWORD address_right;
737 /* Check whether address is unicast/broadcast or multicast */
739 RTLD(bug("[%s] AddressFilter()\n", unit->rtl8169u_name))
741 address_left = AROS_BE2LONG(*((ULONG *) address));
742 address_right = AROS_BE2WORD(*((UWORD *) (address + 4)));
744 if((address_left & 0x01000000) != 0 &&
745 !(address_left == 0xffffffff && address_right == 0xffff))
747 /* Check if this multicast address is wanted */
749 range = (APTR) unit->rtl8169u_multicast_ranges.mlh_Head;
750 tail = (APTR) &unit->rtl8169u_multicast_ranges.mlh_Tail;
751 accept = FALSE;
753 while((range != tail) && !accept)
755 if((address_left > range->lower_bound_left ||
756 (address_left == range->lower_bound_left &&
757 address_right >= range->lower_bound_right)) &&
758 (address_left < range->upper_bound_left ||
759 (address_left == range->upper_bound_left &&
760 address_right <= range->upper_bound_right)))
762 RTLD(bug("[%s] AddressFilter: packet accepted.\n", unit->rtl8169u_name))
763 accept = TRUE;
765 range = (APTR) range->node.mln_Succ;
768 if(!accept)
770 unit->rtl8169u_special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
773 return accept;
777 * Unit process
779 AROS_UFH3(void, RTL8169_Schedular,
780 AROS_UFHA(STRPTR, argPtr, A0),
781 AROS_UFHA(ULONG, argSize, D0),
782 AROS_UFHA(struct ExecBase *, SysBase, A6))
784 AROS_USERFUNC_INIT
786 struct Task *taskSelf = FindTask(NULL);
787 struct RTL8169Startup *sm_UD = taskSelf->tc_UserData;
788 struct RTL8169Unit *unit = sm_UD->rtl8169sm_Unit;
790 LIBBASETYPEPTR LIBBASE = unit->rtl8169u_device;
791 struct MsgPort *reply_port, *input;
793 RTLD(bug("[%s] RTL8169_Schedular()\n", taskSelf->tc_Node.ln_Name))
794 RTLD(bug("[%s] RTL8169_Schedular: Setting up device '%s'\n", taskSelf->tc_Node.ln_Name, unit->rtl8169u_name))
796 if ((reply_port = CreateMsgPort()) == NULL)
798 RTLD(bug("[%s] RTL8169_Schedular: Failed to create Reply message port\n", taskSelf->tc_Node.ln_Name))
801 if ((input = CreateMsgPort()) == NULL)
803 RTLD(bug("[%s] RTL8169_Schedular: Failed to create Input message port\n", taskSelf->tc_Node.ln_Name))
806 unit->rtl8169u_input_port = input;
808 if ((unit->rtl8169u_TimerSlowPort = CreateMsgPort()) != NULL)
810 unit->rtl8169u_TimerSlowReq = (struct timerequest *) CreateIORequest(
811 (struct MsgPort *) unit->rtl8169u_TimerSlowPort,
812 sizeof(struct timerequest));
814 if (unit->rtl8169u_TimerSlowReq)
816 if (!OpenDevice("timer.device", UNIT_MICROHZ,
817 (struct IORequest *)unit->rtl8169u_TimerSlowReq, 0))
819 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC | MEMF_CLEAR);
820 ULONG sigset;
822 RTLD(bug("[%s] RTL8169_Schedular: Got MICROHZ unit of timer.device\n", taskSelf->tc_Node.ln_Name))
824 unit->initialize(unit);
826 msg->mn_ReplyPort = reply_port;
827 msg->mn_Length = sizeof(struct Message);
829 RTLD(bug("[%s] RTL8169_Schedular: Setup complete. Sending handshake\n", taskSelf->tc_Node.ln_Name))
830 PutMsg(sm_UD->rtl8169sm_SyncPort, msg);
831 WaitPort(reply_port);
832 GetMsg(reply_port);
834 FreeVec(msg);
836 RTLD(bug("[%s] RTL8169_Schedular: entering forever loop ... \n", taskSelf->tc_Node.ln_Name))
838 unit->rtl8169u_signal_0 = AllocSignal(-1);
839 unit->rtl8169u_signal_1 = AllocSignal(-1);
840 unit->rtl8169u_signal_2 = AllocSignal(-1);
841 unit->rtl8169u_signal_3 = AllocSignal(-1);
843 sigset = 1 << input->mp_SigBit |
844 1 << unit->rtl8169u_signal_0 |
845 1 << unit->rtl8169u_signal_1 |
846 1 << unit->rtl8169u_signal_2 |
847 1 << unit->rtl8169u_signal_3;
848 for(;;)
850 ULONG recvd = Wait(sigset);
851 if (recvd & 1 << unit->rtl8169u_signal_0)
854 * Shutdown process. Driver should close everything
855 * already and waits for our process to complete. Free
856 * memory allocated here and kindly return.
858 unit->deinitialize(unit);
859 CloseDevice((struct IORequest *) unit->rtl8169u_TimerSlowReq);
860 DeleteIORequest((struct IORequest *) unit->rtl8169u_TimerSlowReq);
861 DeleteMsgPort(unit->rtl8169u_TimerSlowPort);
862 DeleteMsgPort(input);
863 DeleteMsgPort(reply_port);
865 RTLD(bug("[%s] RTL8169_Schedular: Process shutdown.\n", taskSelf->tc_Node.ln_Name))
866 return;
868 else if (recvd & (1 << input->mp_SigBit))
870 struct IOSana2Req *io;
872 /* Handle incoming transactions */
873 while ((io = (struct IOSana2Req *) GetMsg(input)) != NULL)
875 RTLD(bug("[%s] RTL8169_Schedular: Handle incoming transaction.\n",
876 taskSelf->tc_Node.ln_Name))
877 ObtainSemaphore(&unit->rtl8169u_unit_lock);
878 handle_request(LIBBASE, io);
881 else
883 RTLD(bug("[%s] RTL8169_Schedular: Handle incoming signal.\n", taskSelf->tc_Node.ln_Name))
884 /* Handle incoming signals */
891 AROS_USERFUNC_EXIT
894 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct RTL8169Unit *unit,
895 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
897 struct AddressRange *range, *tail;
898 BOOL found = FALSE;
900 range = (APTR) unit->rtl8169u_multicast_ranges.mlh_Head;
901 tail = (APTR) &unit->rtl8169u_multicast_ranges.mlh_Tail;
903 while((range != tail) && !found)
905 if((lower_bound_left == range->lower_bound_left) &&
906 (lower_bound_right == range->lower_bound_right) &&
907 (upper_bound_left == range->upper_bound_left) &&
908 (upper_bound_right == range->upper_bound_right))
910 found = TRUE;
912 else
914 range = (APTR) range->node.mln_Succ;
918 if(!found)
920 range = NULL;
923 return range;
926 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct RTL8169Unit *unit, const UBYTE *lower_bound,
927 const UBYTE *upper_bound)
929 struct AddressRange *range;
930 ULONG lower_bound_left, upper_bound_left;
931 UWORD lower_bound_right, upper_bound_right;
933 lower_bound_left = AROS_BE2LONG(*((ULONG *) lower_bound));
934 lower_bound_right = AROS_BE2WORD(*((UWORD *) (lower_bound + 4)));
935 upper_bound_left = AROS_BE2LONG(*((ULONG *) upper_bound));
936 upper_bound_right = AROS_BE2WORD(*((UWORD *) (upper_bound + 4)));
938 range = FindMulticastRange(LIBBASE,
939 unit,
940 lower_bound_left,
941 lower_bound_right,
942 upper_bound_left,
943 upper_bound_right);
945 if(range != NULL)
947 range->add_count++;
949 else
951 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
952 if(range != NULL)
954 range->lower_bound_left = lower_bound_left;
955 range->lower_bound_right = lower_bound_right;
956 range->upper_bound_left = upper_bound_left;
957 range->upper_bound_right = upper_bound_right;
958 range->add_count = 1;
960 Disable();
961 AddTail((APTR)&unit->rtl8169u_multicast_ranges, (APTR) range);
962 Enable();
964 if (unit->rtl8169u_range_count++ == 0)
966 unit->rtl8169u_flags |= IFF_ALLMULTI;
967 unit->set_multicast(unit);
972 return range != NULL;
975 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE,
976 struct RTL8169Unit *unit,
977 const UBYTE *lower_bound,
978 const UBYTE *upper_bound)
980 struct AddressRange *range;
981 ULONG lower_bound_left, upper_bound_left;
982 UWORD lower_bound_right, upper_bound_right;
984 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
985 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
986 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
987 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
989 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
990 upper_bound_left, upper_bound_right);
992 if(range != NULL)
994 if(--range->add_count == 0)
996 Disable();
997 Remove((APTR)range);
998 Enable();
999 FreeMem(range, sizeof(struct AddressRange));
1001 if (--unit->rtl8169u_range_count == 0)
1003 unit->rtl8169u_flags &= ~IFF_ALLMULTI;
1004 unit->set_multicast(unit);
1008 return range != NULL;
1012 * Create new RTL8169 ethernet device unit
1014 struct RTL8169Unit *CreateUnit(struct RTL8169Base *RTL8169DeviceBase, OOP_Object *pciDevice, IPTR CardRevision)
1016 struct RTL8169Unit *unit;
1017 BOOL success = TRUE;
1018 IPTR VendorId;
1019 IPTR ProductId;
1020 int i;
1022 #if defined(RTL_DEBUG)
1023 BOOL doDebug = TRUE;
1024 #else
1025 /* TODO: Get option to debug from somewhere .. */
1026 BOOL doDebug = FALSE;
1027 #endif
1029 if ((unit = AllocMem(sizeof(struct RTL8169Unit), MEMF_PUBLIC | MEMF_CLEAR)) != NULL)
1031 IPTR mmiobase, mmiolen, type;
1032 OOP_Object *driver;
1033 BOOL mmioerror = FALSE;
1035 RTLD(bug("[rtl8169] CreateUnit()\n"))
1037 if (doDebug)
1038 unit->rtl8169u_flags |= IFF_DEBUG;
1040 unit->rtl8169u_UnitNum = RTL8169DeviceBase->rtl8169b_UnitCount++;
1042 unit->rtl8169u_Sana2Info.HardwareType = S2WireType_Ethernet;
1043 unit->rtl8169u_Sana2Info.MTU = ETH_MTU;
1044 unit->rtl8169u_Sana2Info.AddrFieldSize = 8 * ETH_ADDRESSSIZE;
1046 // Determine which configuration to use for this card
1047 OOP_GetAttr(pciDevice, aHidd_PCIDevice_VendorID, &VendorId);
1048 OOP_GetAttr(pciDevice, aHidd_PCIDevice_ProductID, &ProductId);
1050 unit->rtl8169u_config = UNKNOWN_CFG;
1052 for(i = 0; i < NBR_CARDS; i++)
1054 if(cards[i].vendorID == VendorId &&
1055 cards[i].productID == ProductId)
1057 unit->rtl8169u_config = cards[i].config;
1058 break;
1062 switch(unit->rtl8169u_config)
1064 case RTL_CFG_0:
1065 unit->rtl8169u_intr_event = SYSErr | LinkChg | RxOverflow |
1066 RxFIFOOver | TxErr | TxOK | RxOK | RxErr;
1067 unit->rtl8169u_napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow;
1068 break;
1069 case RTL_CFG_2:
1070 unit->rtl8169u_intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
1071 RxFIFOOver | TxErr | TxOK | RxOK | RxErr;
1072 unit->rtl8169u_napi_event = TxErr | TxOK | RxOK | RxOverflow;
1073 break;
1074 case UNKNOWN_CFG:
1075 case RTL_CFG_1:
1076 default:
1077 unit->rtl8169u_intr_event = SYSErr | LinkChg | RxOverflow |
1078 TxErr | TxOK | RxOK | RxErr;
1079 unit->rtl8169u_napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow;
1080 break;
1083 if ((unit->rtl8169u_name = AllocVec(8 + (unit->rtl8169u_UnitNum / 10) + 2,
1084 MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
1086 FreeMem(unit, sizeof(struct RTL8169Unit));
1087 return NULL;
1089 sprintf((char *) unit->rtl8169u_name, "rtl8169.%d", unit->rtl8169u_UnitNum);
1091 RTLD(bug("[rtl8169] CreateUnit: Unit allocated @ 0x%p\n", unit))
1093 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR) &driver);
1095 unit->rtl8169u_device = RTL8169DeviceBase;
1096 unit->rtl8169u_PCIDevice = pciDevice;
1097 unit->rtl8169u_PCIDriver = driver;
1099 unit->rtl8169u_mtu = unit->rtl8169u_Sana2Info.MTU;
1101 InitSemaphore(&unit->rtl8169u_unit_lock);
1102 NEWLIST(&unit->rtl8169u_Openers);
1103 NEWLIST(&unit->rtl8169u_multicast_ranges);
1104 NEWLIST(&unit->rtl8169u_type_trackers);
1106 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->rtl8169u_IRQ);
1107 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, (IPTR *)&unit->rtl8169u_BaseIO);
1108 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base1, &mmiobase);
1109 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size1, &mmiolen);
1110 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Type1, &type);
1111 if(mmiolen == 0)
1113 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base2, &mmiobase);
1114 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size2, &mmiolen);
1115 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Type2, &type);
1116 if(mmiolen == 0)
1118 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base3, &mmiobase);
1119 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size3, &mmiolen);
1120 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Type3, &type);
1121 if(mmiolen == 0)
1123 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base4, &mmiobase);
1124 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size4, &mmiolen);
1125 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Type4, &type);
1126 if(mmiolen == 0)
1128 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base5, &mmiobase);
1129 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size5, &mmiolen);
1130 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Type5, &type);
1136 RTLD(bug("[%s] CreateUnit: INT:%d, base0:0x%p, base2:0x%p, size2:%d\n", unit->rtl8169u_name,
1137 unit->rtl8169u_IRQ, unit->rtl8169u_BaseIO, mmiobase, mmiolen))
1139 if (type & ADDRF_IO)
1141 RTLD(bug("[%s] CreateUnit: MMIO Region of wrong type!\n", unit->rtl8169u_name))
1142 mmioerror = TRUE;
1145 if (mmiolen < R8169_REGS_SIZE)
1147 RTLD(bug("[%s] CreateUnit: Invalid MMIO Reg size (%d, expected %d)\n", unit->rtl8169u_name,
1148 mmiolen, R8169_REGS_SIZE))
1149 mmioerror = TRUE;
1152 if ((!mmioerror) &&
1153 HIDD_PCIDevice_Obtain(pciDevice,
1154 RTL8169DeviceBase->rtl8169b_Device.dd_Library.lib_Node.ln_Name))
1156 RTLD(bug("[%s] CreateUnit: Device is already owned\n", unit->rtl8169u_name))
1157 mmioerror = TRUE;
1160 if (mmioerror)
1162 FreeMem(unit->rtl8169u_name, 8 + (unit->rtl8169u_UnitNum/10) + 2);
1163 FreeMem(unit, sizeof(struct RTL8169Unit));
1164 return NULL;
1167 unit->rtl8169u_SizeMem = R8169_REGS_SIZE;
1168 unit->rtl8169u_BaseMem = HIDD_PCIDriver_MapPCI(driver, (APTR)mmiobase, unit->rtl8169u_SizeMem);
1170 if (unit->rtl8169u_BaseMem != NULL)
1172 struct TagItem attrs[] =
1174 { aHidd_PCIDevice_isIO, TRUE },
1175 { aHidd_PCIDevice_isMEM, TRUE },
1176 { aHidd_PCIDevice_isMaster, TRUE },
1177 { TAG_DONE, 0 },
1179 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
1181 RTLD(bug("[%s] CreateUnit: PCI_BaseMem @ 0x%p\n", unit->rtl8169u_name, unit->rtl8169u_BaseMem))
1183 unit->rtl8169u_DelayPort.mp_SigBit = SIGB_SINGLE;
1184 unit->rtl8169u_DelayPort.mp_Flags = PA_SIGNAL;
1185 unit->rtl8169u_DelayPort.mp_SigTask = FindTask(NULL);
1186 unit->rtl8169u_DelayPort.mp_Node.ln_Type = NT_MSGPORT;
1187 NEWLIST(&unit->rtl8169u_DelayPort.mp_MsgList);
1189 unit->rtl8169u_DelayReq.tr_node.io_Message.mn_ReplyPort = &unit->rtl8169u_DelayPort;
1190 unit->rtl8169u_DelayReq.tr_node.io_Message.mn_Length = sizeof(struct timerequest);
1192 OpenDevice((STRPTR) "timer.device", UNIT_MICROHZ, (struct IORequest *) &unit->rtl8169u_DelayReq, 0);
1194 if ((unit->rtl8169u_priv = AllocMem(sizeof(struct rtl8169_priv), MEMF_PUBLIC | MEMF_CLEAR)) != NULL)
1196 struct Message *msg;
1198 unit->rtl8169u_priv->pci_dev = unit;
1199 InitSemaphore(&unit->rtl8169u_priv->lock);
1201 unit->rtl8169u_irqhandler.is_Node.ln_Type = NT_INTERRUPT;
1202 unit->rtl8169u_irqhandler.is_Node.ln_Pri = 100;
1203 unit->rtl8169u_irqhandler.is_Node.ln_Name = LIBBASE->rtl8169b_Device.dd_Library.lib_Node.ln_Name;
1204 unit->rtl8169u_irqhandler.is_Code = (VOID_FUNC)RTL8169_IntHandlerF;
1205 unit->rtl8169u_irqhandler.is_Data = unit;
1207 unit->rtl8169u_touthandler.is_Node.ln_Type = NT_INTERRUPT;
1208 unit->rtl8169u_touthandler.is_Node.ln_Pri = 100;
1209 unit->rtl8169u_touthandler.is_Node.ln_Name = LIBBASE->rtl8169b_Device.dd_Library.lib_Node.ln_Name;
1210 unit->rtl8169u_touthandler.is_Code = (VOID_FUNC)RTL8169_TimeoutHandlerF;
1211 unit->rtl8169u_touthandler.is_Data = unit;
1213 unit->rtl8169u_tx_int.is_Node.ln_Name = unit->rtl8169u_name;
1214 unit->rtl8169u_tx_int.is_Code = (VOID_FUNC)RTL8169_TX_IntF;
1215 unit->rtl8169u_tx_int.is_Data = unit;
1217 for (i = 0; i < REQUEST_QUEUE_COUNT; i++)
1219 struct MsgPort *port = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR);
1221 unit->rtl8169u_request_ports[i] = port;
1223 if (port == NULL) success = FALSE;
1225 if (success)
1227 NEWLIST(&port->mp_MsgList);
1228 port->mp_Flags = PA_IGNORE;
1229 port->mp_SigTask = &unit->rtl8169u_tx_int;
1233 // (All others are PA_IGNORE)
1234 unit->rtl8169u_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
1236 if (success)
1238 struct RTL8169Startup *sm_UD;
1239 UBYTE tmpbuff[100];
1241 if ((sm_UD = AllocMem(sizeof(struct RTL8169Startup), MEMF_PUBLIC | MEMF_CLEAR)) != NULL)
1243 sprintf((char *) tmpbuff, RTL8169_TASK_NAME, unit->rtl8169u_name);
1245 sm_UD->rtl8169sm_SyncPort = CreateMsgPort();
1246 sm_UD->rtl8169sm_Unit = unit;
1248 rtl8169_get_functions(unit);
1250 unit->rtl8169u_Process = CreateNewProcTags(
1251 NP_Entry, (IPTR)RTL8169_Schedular,
1252 NP_Name, tmpbuff,
1253 NP_Synchronous , FALSE,
1254 NP_Priority, 0,
1255 NP_UserData, (IPTR)sm_UD,
1256 NP_StackSize, 140960,
1257 TAG_DONE);
1259 WaitPort(sm_UD->rtl8169sm_SyncPort);
1260 msg = GetMsg(sm_UD->rtl8169sm_SyncPort);
1261 ReplyMsg(msg);
1262 DeleteMsgPort(sm_UD->rtl8169sm_SyncPort);
1263 FreeMem(sm_UD, sizeof(struct RTL8169Startup));
1265 RTLD(bug("[%s] CreateUnit: Device Initialised. Unit %d @ %p\n",
1266 unit->rtl8169u_name,
1267 unit->rtl8169u_UnitNum,
1268 unit))
1269 return unit;
1273 RTLD(bug("[%s] ERRORS occured during Device setup - ABORTING\n", unit->rtl8169u_name))
1275 else
1277 RTLD(bug("[rtl8169] PANIC! Couldn't get MMIO area. Aborting\n"))
1279 DeleteUnit(RTL8169DeviceBase, unit);
1281 else if (doDebug)
1283 bug("[rtl8169] CreateUnit: Failed to Allocate Unit storage!\n");
1285 return NULL;
1289 * DeleteUnit - removes selected unit. Frees all resources and structures.
1291 * The caller should be sure, that given unit is really ready to be freed.
1293 void DeleteUnit(struct RTL8169Base *RTL8169DeviceBase, struct RTL8169Unit *Unit)
1295 UBYTE tmpbuff[100];
1296 int i;
1298 if (Unit)
1300 if (Unit->rtl8169u_Process)
1302 /* Tell our process to quit, and wait until it does so */
1303 Signal(&Unit->rtl8169u_Process->pr_Task,
1304 1 << Unit->rtl8169u_signal_0);
1305 sprintf((char *) tmpbuff, RTL8169_TASK_NAME, Unit->rtl8169u_name);
1306 while (FindTask(tmpbuff) != NULL)
1307 Delay(5);
1310 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1312 if (Unit->rtl8169u_request_ports[i] != NULL)
1313 FreeMem(Unit->rtl8169u_request_ports[i], sizeof(struct MsgPort));
1315 Unit->rtl8169u_request_ports[i] = NULL;
1318 if (Unit->rtl8169u_priv)
1320 FreeMem(Unit->rtl8169u_priv, sizeof(struct rtl8169_priv));
1321 Unit->rtl8169u_priv = NULL;
1324 if (Unit->rtl8169u_BaseMem)
1326 HIDD_PCIDriver_UnmapPCI(Unit->rtl8169u_PCIDriver,
1327 (APTR)Unit->rtl8169u_BaseMem,
1328 Unit->rtl8169u_SizeMem);
1331 HIDD_PCIDevice_Release(Unit->rtl8169u_PCIDevice);
1332 FreeMem(Unit, sizeof(struct RTL8169Unit));