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,
24 #include <exec/types.h>
25 #include <exec/resident.h>
27 #include <exec/ports.h>
28 #include <exec/errors.h>
30 #include <aros/debug.h>
32 #include <devices/sana2.h>
33 #include <devices/sana2specialstats.h>
34 #include <devices/newstyle.h>
35 #include <devices/timer.h>
37 #include <utility/utility.h>
38 #include <utility/tagitem.h>
39 #include <utility/hooks.h>
41 #include <proto/exec.h>
42 #include <proto/dos.h>
43 #include <proto/battclock.h>
44 #include <proto/oop.h>
45 #include <proto/timer.h>
46 #include <proto/utility.h>
52 #include LC_LIBDEFS_FILE
55 * Report incoming events to all hyphotetical event receivers
57 VOID
ReportEvents(struct NFBase
*NforceBase
, struct NFUnit
*unit
, ULONG events
)
59 struct IOSana2Req
*request
, *tail
, *next_request
;
62 list
= &unit
->request_ports
[EVENT_QUEUE
]->mp_MsgList
;
63 next_request
= (APTR
)list
->lh_Head
;
64 tail
= (APTR
)&list
->lh_Tail
;
66 /* Go through list of event listeners. If send messages to receivers if event found */
68 while(next_request
!= tail
)
70 request
= next_request
;
71 next_request
= (APTR
)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
73 if((request
->ios2_WireError
&events
) != 0)
75 request
->ios2_WireError
= events
;
76 Remove((APTR
)request
);
77 ReplyMsg((APTR
)request
);
85 struct TypeStats
*FindTypeStats(struct NFBase
*NforceBase
, struct NFUnit
*unit
,
86 struct MinList
*list
, ULONG packet_type
)
88 struct TypeStats
*stats
, *tail
;
91 stats
= (APTR
)list
->mlh_Head
;
92 tail
= (APTR
)&list
->mlh_Tail
;
94 while(stats
!= tail
&& !found
)
96 if(stats
->packet_type
== packet_type
)
99 stats
= (APTR
)stats
->node
.mln_Succ
;
108 void FlushUnit(LIBBASETYPEPTR LIBBASE
, struct NFUnit
*unit
, UBYTE last_queue
, BYTE error
)
110 struct IORequest
*request
;
112 struct Opener
*opener
, *tail
;
114 D(bug("[nforce] FlushUnit\n"));
116 /* Abort queued operations */
118 for (i
=0; i
<= last_queue
; i
++)
120 while ((request
= (APTR
)GetMsg(unit
->request_ports
[i
])) != NULL
)
122 request
->io_Error
= IOERR_ABORTED
;
123 ReplyMsg((struct Message
*)request
);
127 opener
= (APTR
)unit
->nu_Openers
.mlh_Head
;
128 tail
= (APTR
)unit
->nu_Openers
.mlh_Tail
;
130 /* Flush every opener's read queue */
132 while(opener
!= tail
)
134 while ((request
= (APTR
)GetMsg(&opener
->read_port
)) != NULL
)
136 request
->io_Error
= error
;
137 ReplyMsg((struct Message
*)request
);
139 opener
= (struct Opener
*)opener
->node
.mln_Succ
;
143 static inline ULONG
readl(APTR base
)
145 return *((volatile ULONG
*)base
);
148 static inline void writel(ULONG val
, APTR base
)
150 *((volatile ULONG
*)base
) = val
;
153 static inline void pci_push(UBYTE
*base
)
155 /* force out pending posted writes */
160 * Interrupt handler called whenever nForce NIC interface generates interrupt.
161 * It's duty is to iterate throgh RX queue searching for new packets.
163 * Please note, that allthough multicast support could be done on interface
164 * basis, it is done in this function as result of quick integration of both
165 * the forcedeth driver (IFF_ALLMULTI flag) and etherling3 driver (AddressMatch
168 static AROS_INTH1(RX_Int
, struct NFUnit
*, unit
)
172 struct NFBase
*NforceBase
= unit
->nu_device
;
173 struct fe_priv
*np
= unit
->nu_fe_priv
;
175 struct TypeStats
*tracker
;
177 struct Opener
*opener
, *opener_tail
;
178 struct IOSana2Req
*request
, *request_tail
;
179 BOOL accepted
, is_orphan
;
181 /* Endless loop, with break from inside */
185 struct eth_frame
*frame
;
187 if (np
->cur_rx
- np
->refill_rx
>= RX_RING
)
188 break; /* we scanned the whole ring - do not continue */
190 /* Get the in-queue number */
191 i
= np
->cur_rx
% RX_RING
;
192 Flags
= AROS_LE2LONG(np
->rx_ring
[i
].FlagLen
);
193 len
= unit
->descr_getlength(&np
->rx_ring
[i
], np
->desc_ver
);
195 D(bug("%s: nv_rx_process: looking at packet %d, Flags 0x%x, len=%d\n",
196 unit
->name
, np
->cur_rx
, Flags
, len
));
198 /* Free frame? Do nothing - we've empty queue now */
199 if (Flags
& NV_RX_AVAIL
)
200 break; /* still owned by hardware, */
203 * the packet is for us - get it :)
206 /* look at what we actually got: */
207 if (np
->desc_ver
== DESC_VER_1
) {
208 if (!(Flags
& NV_RX_DESCRIPTORVALID
))
211 if (Flags
& NV_RX_MISSEDFRAME
) {
212 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
213 unit
->stats
.BadData
++;
216 if (Flags
& (NV_RX_ERROR1
|NV_RX_ERROR2
|NV_RX_ERROR3
|NV_RX_ERROR4
)) {
217 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
218 unit
->stats
.BadData
++;
221 if (Flags
& NV_RX_CRCERR
) {
222 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
223 unit
->stats
.BadData
++;
226 if (Flags
& NV_RX_OVERFLOW
) {
227 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
228 unit
->stats
.BadData
++;
231 if (Flags
& NV_RX_ERROR
) {
232 /* framing errors are soft errors, the rest is fatal. */
233 if (Flags
& NV_RX_FRAMINGERR
) {
234 if (Flags
& NV_RX_SUBSTRACT1
) {
238 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
239 unit
->stats
.BadData
++;
244 if (!(Flags
& NV_RX2_DESCRIPTORVALID
))
247 if (Flags
& (NV_RX2_ERROR1
|NV_RX2_ERROR2
|NV_RX2_ERROR3
|NV_RX2_ERROR4
)) {
248 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
249 unit
->stats
.BadData
++;
252 if (Flags
& NV_RX2_CRCERR
) {
253 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
254 unit
->stats
.BadData
++;
257 if (Flags
& NV_RX2_OVERFLOW
) {
258 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
259 unit
->stats
.BadData
++;
262 if (Flags
& NV_RX2_ERROR
) {
263 /* framing errors are soft errors, the rest is fatal. */
264 if (Flags
& NV_RX2_FRAMINGERR
) {
265 if (Flags
& NV_RX2_SUBSTRACT1
) {
269 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
270 unit
->stats
.BadData
++;
274 Flags
&= NV_RX2_CHECKSUMMASK
;
275 if (Flags
== NV_RX2_CHECKSUMOK1
||
276 Flags
== NV_RX2_CHECKSUMOK2
||
277 Flags
== NV_RX2_CHECKSUMOK3
) {
278 D(bug("%s: hw checksum hit!.\n", unit
->name
));
280 D(bug("%s: hwchecksum miss!.\n", unit
->name
));
284 /* got a valid packet - forward it to the network core */
285 frame
= &np
->rx_buffer
[i
];
288 /* Dump contents of frame if DEBUG enabled */
292 for (j
=0; j
<64; j
++) {
294 D(bug("\n%03x:", j
));
295 D(bug(" %02x", ((unsigned char*)frame
)[j
]));
301 /* Check for address validity */
302 if(AddressFilter(LIBBASE
, unit
, frame
->eth_packet_dest
))
304 /* Packet is addressed to this driver */
305 packet_type
= AROS_BE2WORD(frame
->eth_packet_type
);
307 opener
= (APTR
)unit
->nu_Openers
.mlh_Head
;
308 opener_tail
= (APTR
)&unit
->nu_Openers
.mlh_Tail
;
310 /* Offer packet to every opener */
311 while(opener
!= opener_tail
)
313 request
= (APTR
)opener
->read_port
.mp_MsgList
.lh_Head
;
314 request_tail
= (APTR
)&opener
->read_port
.mp_MsgList
.lh_Tail
;
317 /* Offer packet to each request until it's accepted */
318 while((request
!= request_tail
) && !accepted
)
320 if((request
->ios2_PacketType
== packet_type
)
321 || ((request
->ios2_PacketType
<= ETH_MTU
)
322 && (packet_type
<= ETH_MTU
)))
324 CopyPacket(LIBBASE
, unit
, request
, len
, packet_type
, frame
);
328 (struct IOSana2Req
*)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
334 opener
= (APTR
)opener
->node
.mln_Succ
;
337 /* If packet was unwanted, give it to S2_READORPHAN request */
340 unit
->stats
.UnknownTypesReceived
++;
342 if(!IsMsgPortEmpty(unit
->request_ports
[ADOPT_QUEUE
]))
344 CopyPacket(LIBBASE
, unit
,
345 (APTR
)unit
->request_ports
[ADOPT_QUEUE
]->
346 mp_MsgList
.lh_Head
, len
, packet_type
, frame
);
350 /* Update remaining statistics */
353 FindTypeStats(LIBBASE
, unit
, &unit
->type_trackers
, packet_type
);
356 tracker
->stats
.PacketsReceived
++;
357 tracker
->stats
.BytesReceived
+= len
;
361 unit
->stats
.PacketsReceived
++;
373 * Check status of packets which we've already sent to the NIC. Update
374 * statistics, and reenable TX queue if only there is some free space.
376 static void nv_tx_done(struct NFUnit
*unit
)
378 struct fe_priv
*np
= unit
->nu_fe_priv
;
379 struct NFBase
*NforceBase
= unit
->nu_device
;
383 /* Go through tx chain and mark all send packets as free */
384 while (np
->nic_tx
!= np
->next_tx
)
386 i
= np
->nic_tx
% TX_RING
;
388 Flags
= AROS_LE2LONG(np
->tx_ring
[i
].FlagLen
);
390 D(bug("%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
391 unit
->name
, np
->nic_tx
, Flags
));
393 if (Flags
& NV_TX_VALID
)
396 if (np
->desc_ver
== DESC_VER_1
) {
397 if (Flags
& (NV_TX_RETRYERROR
|NV_TX_CARRIERLOST
|NV_TX_LATECOLLISION
|
398 NV_TX_UNDERFLOW
|NV_TX_ERROR
))
400 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_TX
);
404 unit
->stats
.PacketsSent
++;
409 if (Flags
& (NV_TX2_RETRYERROR
|NV_TX2_CARRIERLOST
|NV_TX2_LATECOLLISION
|
410 NV_TX2_UNDERFLOW
|NV_TX2_ERROR
))
412 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_TX
);
416 unit
->stats
.PacketsSent
++;
423 * Do we have some spare space in TX queue and the queue self is blocked?
426 if (np
->next_tx
- np
->nic_tx
< TX_LIMIT_START
) {
427 if (netif_queue_stopped(unit
)) {
428 bug("%s: output queue restart\n", unit
->name
);
429 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
430 netif_wake_queue(unit
);
436 * Interrupt generated by Cause() to push new packets into the NIC interface
438 static AROS_INTH1(TX_Int
, struct NFUnit
*, unit
)
442 struct fe_priv
*np
= unit
->nu_fe_priv
;
443 struct NFBase
*NforceBase
= unit
->nu_device
;
445 BOOL proceed
= FALSE
; /* Fails by default */
447 /* send packet only if there is free space on tx queue. Otherwise do nothing */
448 if (!netif_queue_stopped(unit
))
450 UWORD packet_size
, data_size
;
451 struct IOSana2Req
*request
;
452 struct Opener
*opener
;
456 struct MsgPort
*port
;
457 struct TypeStats
*tracker
;
459 proceed
= TRUE
; /* Success by default */
460 port
= unit
->request_ports
[WRITE_QUEUE
];
462 /* Still no error and there are packets to be sent? */
463 while(proceed
&& (!IsMsgPortEmpty(port
)))
465 nr
= np
->next_tx
% TX_RING
;
468 request
= (APTR
)port
->mp_MsgList
.lh_Head
;
469 data_size
= packet_size
= request
->ios2_DataLength
;
471 opener
= (APTR
)request
->ios2_BufferManagement
;
473 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
475 packet_size
+= ETH_PACKET_DATA
;
476 CopyMem(request
->ios2_DstAddr
, np
->tx_buffer
[nr
].eth_packet_dest
, ETH_ADDRESSSIZE
);
477 CopyMem(unit
->dev_addr
, np
->tx_buffer
[nr
].eth_packet_source
, ETH_ADDRESSSIZE
);
478 np
->tx_buffer
[nr
].eth_packet_type
= AROS_WORD2BE(request
->ios2_PacketType
);
480 buffer
= np
->tx_buffer
[nr
].eth_packet_data
;
483 buffer
= (UBYTE
*)&np
->tx_buffer
[nr
];
485 if (!opener
->tx_function(buffer
, request
->ios2_Data
, data_size
))
487 error
= S2ERR_NO_RESOURCES
;
488 wire_error
= S2WERR_BUFF_ERROR
;
489 ReportEvents(LIBBASE
, unit
,
490 S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
494 /* Now the packet is already in TX buffer, update flags for NIC */
498 np
->tx_ring
[nr
].FlagLen
= AROS_LONG2LE((packet_size
-1) | np
->tx_flags
);
499 D(bug("%s: nv_start_xmit: packet packet %d queued for transmission.",
500 unit
->name
, np
->next_tx
));
502 /* DEBUG? Dump frame if so */
506 for (j
=0; j
<64; j
++) {
508 D(bug("\n%03x:", j
));
509 D(bug(" %02x", ((unsigned char*)&np
->tx_buffer
[nr
])[j
]));
517 * If we've just run out of free space on the TX queue, stop
518 * it and give up pushing further frames
520 if (np
->next_tx
- np
->nic_tx
>= TX_LIMIT_STOP
)
522 bug("%s: output queue full. Stopping\n", unit
->name
);
523 netif_stop_queue(unit
);
528 * At this place linux driver used to trigger NIC to output
529 * the queued packets through wire. We will not do it as we
530 * may already see if there are new outcomming packets.
532 * Yes, this driver might be a bit faster than linux one.
538 request
->ios2_Req
.io_Error
= error
;
539 request
->ios2_WireError
= wire_error
;
541 Remove((APTR
)request
);
543 ReplyMsg((APTR
)request
);
545 /* Update statistics */
549 tracker
= FindTypeStats(LIBBASE
, unit
, &unit
->type_trackers
,
550 request
->ios2_PacketType
);
553 tracker
->stats
.PacketsSent
++;
554 tracker
->stats
.BytesSent
+= packet_size
;
560 * Here either we've filled the queue with packets to be transmitted,
561 * or just run out of spare space in TX queue. In both cases tell the
562 * NIC to start transmitting them all through wire.
564 writel(NVREG_TXRXCTL_KICK
|np
->desc_ver
, (UBYTE
*)unit
->nu_BaseMem
+ NvRegTxRxControl
);
565 pci_push((UBYTE
*)unit
->nu_BaseMem
);
568 /* Was there success? Enable incomming of new packets */
570 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
572 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_IGNORE
;
580 * Interrupt used to restart the real one
582 static AROS_INTH1(TX_End_Int
, struct NFUnit
*, unit
)
586 struct NFUnit
*dev
= unit
;
587 struct fe_priv
*np
= dev
->nu_fe_priv
;
588 UBYTE
*base
= (UBYTE
*) dev
->nu_BaseMem
;
592 writel(np
->irqmask
, base
+ NvRegIrqMask
);
594 AROS_INTC1(dev
->nu_irqhandler
.is_Code
, dev
->nu_irqhandler
.is_Data
);
603 * Maximum number of loops until we assume that a bit in the irq mask
604 * is stuck. Overridable with module param.
606 static const int max_interrupt_work
= 5;
609 * Handle timeouts and other strange cases
611 static AROS_INTH1(NF_TimeoutHandler
, struct NFUnit
*, dev
)
616 struct Device
*TimerBase
= dev
->nu_TimerSlowReq
->tr_node
.io_Device
;
621 * If timeout timer is expected, and time elapsed - regenerate the
624 if (dev
->nu_toutNEED
&& (CmpTime(&time
, &dev
->nu_toutPOLL
) < 0))
626 dev
->nu_toutNEED
= FALSE
;
627 Cause(&dev
->tx_end_int
);
636 * The interrupt handler - schedules code execution to proper handlers depending
637 * on the message from nForce.
641 * Don't be surprised - this driver used to restart itself several times, in
642 * order to handle events which occur when the driver was handling previous
643 * events. It reduces the latency and amount of dropped packets. Additionally,
644 * this interrupt may put itself into deep sleep (or just quit) and restarts
645 * after certain amount of time (POLL_WAIT).
647 static AROS_INTH1(NF_IntHandler
, struct NFUnit
*, dev
)
651 struct fe_priv
*np
= dev
->nu_fe_priv
;
652 UBYTE
*base
= (UBYTE
*) dev
->nu_BaseMem
;
655 struct Device
*TimerBase
= dev
->nu_TimerSlowReq
->tr_node
.io_Device
;
660 /* Restart automagically :) */
663 events
= readl(base
+ NvRegIrqStatus
) & NVREG_IRQSTAT_MASK
;
664 writel(NVREG_IRQSTAT_MASK
, base
+ NvRegIrqStatus
);
667 if (!(events
& np
->irqmask
))
671 * Some packets have been sent? Just update statistics and empty the
674 if (events
& (NVREG_IRQ_TX1
|NVREG_IRQ_TX2
|NVREG_IRQ_TX_ERR
)) {
678 /* Something received? Handle it! */
679 if (events
& (NVREG_IRQ_RX_ERROR
|NVREG_IRQ_RX
|NVREG_IRQ_RX_NOBUF
)) {
680 AROS_INTC1(dev
->rx_int
.is_Code
, dev
->rx_int
.is_Data
);
681 /* Mark received frames as free for hardware */
685 if (events
& (NVREG_IRQ_LINK
)) {
691 /* If linktimer interrupt required, handle it here */
692 if (np
->need_linktimer
&& (CmpTime(&time
, &np
->link_timeout
) < 0)) {
694 dev
->linkchange(dev
);
696 np
->link_timeout
.tv_micro
= LINK_TIMEOUT
% 1000000;
697 np
->link_timeout
.tv_secs
= LINK_TIMEOUT
/ 1000000;
698 AddTime(&np
->link_timeout
, &time
);
702 if (events
& (NVREG_IRQ_TX_ERR
)) {
703 bug("%s: received irq with events 0x%x. Probably TX fail.\n",
707 if (events
& (NVREG_IRQ_UNKNOWN
)) {
708 bug("%s: received irq with unknown events 0x%x. Please report\n",
713 * Straaaaaaaange, the interrupt was restarted more than
714 * max_interrupt_work times. Normally it should not happen, even on
715 * gigabit ethernet. In any case setup poll handler which restart this
716 * handler after specified amount of time.
718 if (i
> max_interrupt_work
)
720 bug("%s: too many iterations (%d) in nv_nic_irq.\n", dev
->name
, i
);
721 writel(0, base
+ NvRegIrqMask
);
724 /* When to wake up? */
726 dev
->nu_toutPOLL
.tv_micro
= POLL_WAIT
% 1000000;
727 dev
->nu_toutPOLL
.tv_secs
= POLL_WAIT
/ 1000000;
728 AddTime(&dev
->nu_toutPOLL
, &time
);
729 dev
->nu_toutNEED
= TRUE
;
732 break; /* break the for() loop */
737 * If TX queue was stopped, try to reenable it *ALWAYS*
739 if (netif_queue_stopped(dev
)) {
748 VOID
CopyPacket(struct NFBase
*NforceBase
, struct NFUnit
*unit
,
749 struct IOSana2Req
*request
, UWORD packet_size
, UWORD packet_type
,
750 struct eth_frame
*buffer
)
752 struct Opener
*opener
;
753 BOOL filtered
= FALSE
;
755 const UBYTE broadcast
[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
757 /* Set multicast and broadcast flags */
759 request
->ios2_Req
.io_Flags
&= ~(SANA2IOF_BCAST
| SANA2IOF_MCAST
);
760 if(memcmp(buffer
->eth_packet_dest
, broadcast
, 6) == 0)
761 request
->ios2_Req
.io_Flags
|= SANA2IOF_BCAST
;
763 else if((buffer
->eth_packet_dest
[0] & 0x1) != 0)
764 request
->ios2_Req
.io_Flags
|= SANA2IOF_MCAST
;
766 /* Set source and destination addresses and packet type */
767 CopyMem(buffer
->eth_packet_source
, request
->ios2_SrcAddr
, ETH_ADDRESSSIZE
);
768 CopyMem(buffer
->eth_packet_dest
, request
->ios2_DstAddr
, ETH_ADDRESSSIZE
);
769 request
->ios2_PacketType
= packet_type
;
771 /* Adjust for cooked packet request */
773 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
775 packet_size
-= ETH_PACKET_DATA
;
776 ptr
= buffer
->eth_packet_data
;
780 ptr
= (UBYTE
*)buffer
;
783 request
->ios2_DataLength
= packet_size
;
787 opener
= request
->ios2_BufferManagement
;
788 if((request
->ios2_Req
.io_Command
== CMD_READ
) &&
789 (opener
->filter_hook
!= NULL
))
790 if(!CallHookPkt(opener
->filter_hook
, request
, ptr
))
795 /* Copy packet into opener's buffer and reply packet */
797 if(!opener
->rx_function(request
->ios2_Data
, ptr
, packet_size
))
799 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
800 request
->ios2_WireError
= S2WERR_BUFF_ERROR
;
801 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
| S2EVENT_RX
);
804 Remove((APTR
)request
);
806 ReplyMsg((APTR
)request
);
810 BOOL
AddressFilter(struct NFBase
*NforceBase
, struct NFUnit
*unit
, UBYTE
*address
)
812 struct AddressRange
*range
, *tail
;
817 /* Check whether address is unicast/broadcast or multicast */
819 address_left
= AROS_BE2LONG(*((ULONG
*)address
));
820 address_right
= AROS_BE2WORD(*((UWORD
*)(address
+ 4)));
822 if((address_left
& 0x01000000) != 0 &&
823 !(address_left
== 0xffffffff && address_right
== 0xffff))
825 /* Check if this multicast address is wanted */
827 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
828 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
831 while((range
!= tail
) && !accept
)
833 if((address_left
> range
->lower_bound_left
||
834 (address_left
== range
->lower_bound_left
&&
835 address_right
>= range
->lower_bound_right
)) &&
836 (address_left
< range
->upper_bound_left
||
837 (address_left
== range
->upper_bound_left
&&
838 address_right
<= range
->upper_bound_right
)))
840 range
= (APTR
)range
->node
.mln_Succ
;
844 unit
->special_stats
[S2SS_ETHERNET_BADMULTICAST
& 0xffff]++;
852 AROS_UFH3(void, NF_Scheduler
,
853 AROS_UFHA(STRPTR
, argPtr
, A0
),
854 AROS_UFHA(ULONG
, argSize
, D0
),
855 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
859 struct NFUnit
*dev
= FindTask(NULL
)->tc_UserData
;
860 LIBBASETYPEPTR LIBBASE
= dev
->nu_device
;
862 struct MsgPort
*reply_port
, *input
;
864 D(bug("[NFORCE] In nforce process\n"));
865 D(bug("[NFORCE] Setting device up\n"));
867 reply_port
= CreateMsgPort();
868 input
= CreateMsgPort();
870 dev
->nu_input_port
= input
;
872 /* Randomize the generator with current time */
873 BattClockBase
= OpenResource("battclock.resource");
874 srand(ReadBattClock());
876 dev
->nu_TimerSlowPort
= CreateMsgPort();
878 if (dev
->nu_TimerSlowPort
)
880 dev
->nu_TimerSlowReq
= (struct timerequest
*)
881 CreateIORequest((struct MsgPort
*)dev
->nu_TimerSlowPort
, sizeof(struct timerequest
));
883 if (dev
->nu_TimerSlowReq
)
885 if (!OpenDevice("timer.device", UNIT_VBLANK
,
886 (struct IORequest
*)dev
->nu_TimerSlowReq
, 0))
888 struct Message
*msg
= AllocVec(sizeof(struct Message
), MEMF_PUBLIC
|MEMF_CLEAR
);
891 D(bug("[NFORCE] Got VBLANK unit of timer.device\n"));
893 dev
->initialize(dev
);
895 msg
->mn_ReplyPort
= reply_port
;
896 msg
->mn_Length
= sizeof(struct Message
);
898 D(bug("[NFORCE] Setup complete. Sending handshake\n"));
899 PutMsg(LIBBASE
->nf_syncport
, msg
);
900 WaitPort(reply_port
);
905 D(bug("[NFORCE] Forever loop\n"));
907 dev
->nu_signal_0
= AllocSignal(-1);
908 dev
->nu_signal_1
= AllocSignal(-1);
909 dev
->nu_signal_2
= AllocSignal(-1);
910 dev
->nu_signal_3
= AllocSignal(-1);
912 sigset
= 1 << input
->mp_SigBit
|
913 1 << dev
->nu_signal_0
|
914 1 << dev
->nu_signal_1
|
915 1 << dev
->nu_signal_2
|
916 1 << dev
->nu_signal_3
;
919 ULONG recvd
= Wait(sigset
);
920 if (recvd
& dev
->nu_signal_0
)
923 * Shutdown process. Driver should close everything
924 * already and waits for our process to complete. Free
925 * memory allocared here and kindly return.
927 dev
->deinitialize(dev
);
928 CloseDevice((struct IORequest
*)dev
->nu_TimerSlowReq
);
929 DeleteIORequest((struct IORequest
*)dev
->nu_TimerSlowReq
);
930 DeleteMsgPort(dev
->nu_TimerSlowPort
);
931 DeleteMsgPort(input
);
932 DeleteMsgPort(reply_port
);
934 D(bug("[NFORCE] Process shutdown.\n"));
937 else if (recvd
& (1 << input
->mp_SigBit
))
939 struct IOSana2Req
*io
;
941 /* Handle incoming transactions */
942 while ((io
= (struct IOSana2Req
*)GetMsg(input
))!= NULL
)
944 ObtainSemaphore(&dev
->unit_lock
);
945 handle_request(LIBBASE
, io
);
950 /* Handle incoming signals */
960 static const struct DriverConfig
{
965 { NFORCE_MCPNET1_ID
, DEV_IRQMASK_1
|DEV_NEED_TIMERIRQ
|DEV_NEED_LINKTIMER
, DESC_VER_1
},
966 { NFORCE_MCPNET2_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LINKTIMER
|DEV_NEED_LASTPACKET1
, DESC_VER_1
},
967 { NFORCE_MCPNET3_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LINKTIMER
|DEV_NEED_LASTPACKET1
, DESC_VER_1
},
968 { NFORCE_MCPNET4_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
969 { NFORCE_MCPNET5_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
970 { NFORCE_MCPNET6_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
971 { NFORCE_MCPNET7_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
972 { NFORCE_MCPNET8_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
973 { NFORCE_MCPNET9_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
974 { NFORCE_MCPNET10_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
975 { NFORCE_MCPNET11_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
980 * Create new nForce ethernet device unit
982 struct NFUnit
*CreateUnit(struct NFBase
*NforceBase
, OOP_Object
*pciDevice
)
984 struct NFUnit
*unit
= AllocMem(sizeof(struct NFUnit
), MEMF_PUBLIC
| MEMF_CLEAR
);
990 IPTR DeviceID
, base
, len
;
993 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_ProductID
, &DeviceID
);
994 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
, (APTR
)&driver
);
996 for (i
=0; Config
[i
].ProductID
; i
++)
998 if (Config
[i
].ProductID
== DeviceID
)
1000 unit
->nu_DriverFlags
= Config
[i
].DriverFlags
;
1001 unit
->nu_fe_priv
->desc_ver
= Config
[i
].DescVer
;
1006 unit
->nu_device
= NforceBase
;
1007 unit
->nu_DeviceID
= DeviceID
;
1009 unit
->nu_PCIDevice
= pciDevice
;
1010 unit
->nu_PCIDriver
= driver
;
1012 InitSemaphore(&unit
->unit_lock
);
1013 NEWLIST(&unit
->nu_Openers
);
1014 NEWLIST(&unit
->multicast_ranges
);
1015 NEWLIST(&unit
->type_trackers
);
1017 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &unit
->nu_IRQ
);
1018 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Base1
, &unit
->nu_BaseIO
);
1019 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Base0
, &base
);
1020 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Size0
, &len
);
1022 unit
->nu_BaseMem
= (IPTR
)HIDD_PCIDriver_MapPCI(driver
, (APTR
)base
, len
);
1023 unit
->nu_SizeMem
= len
;
1025 if (unit
->nu_BaseMem
)
1027 struct TagItem attrs
[] = {
1028 { aHidd_PCIDevice_isIO
, TRUE
},
1029 { aHidd_PCIDevice_isMEM
, TRUE
},
1030 { aHidd_PCIDevice_isMaster
, TRUE
},
1033 OOP_SetAttrs(pciDevice
, (struct TagItem
*)&attrs
);
1035 unit
->name
= "[nforce0]";
1036 unit
->nu_fe_priv
= AllocMem(sizeof(struct fe_priv
), MEMF_PUBLIC
|MEMF_CLEAR
);
1037 unit
->nu_UnitNum
= 0;
1039 nv_get_functions(unit
);
1041 if (unit
->nu_fe_priv
)
1043 unit
->nu_fe_priv
->pci_dev
= unit
;
1044 InitSemaphore(&unit
->nu_fe_priv
->lock
);
1047 struct Message
*msg
;
1049 unit
->nu_irqhandler
.is_Node
.ln_Type
= NT_INTERRUPT
;
1050 unit
->nu_irqhandler
.is_Node
.ln_Pri
= 100;
1051 unit
->nu_irqhandler
.is_Node
.ln_Name
= LIBBASE
->nf_Device
.dd_Library
.lib_Node
.ln_Name
;
1052 unit
->nu_irqhandler
.is_Code
= (VOID_FUNC
)NF_IntHandler
;
1053 unit
->nu_irqhandler
.is_Data
= unit
;
1055 unit
->nu_touthandler
.is_Node
.ln_Type
= NT_INTERRUPT
;
1056 unit
->nu_touthandler
.is_Node
.ln_Pri
= 100;
1057 unit
->nu_touthandler
.is_Node
.ln_Name
= LIBBASE
->nf_Device
.dd_Library
.lib_Node
.ln_Name
;
1058 unit
->nu_touthandler
.is_Code
= (VOID_FUNC
)NF_TimeoutHandler
;
1059 unit
->nu_touthandler
.is_Data
= unit
;
1061 unit
->rx_int
.is_Node
.ln_Name
= unit
->name
;
1062 unit
->rx_int
.is_Code
= (VOID_FUNC
)RX_Int
;
1063 unit
->rx_int
.is_Data
= unit
;
1065 unit
->tx_int
.is_Node
.ln_Name
= unit
->name
;
1066 unit
->tx_int
.is_Code
= (VOID_FUNC
)TX_Int
;
1067 unit
->tx_int
.is_Data
= unit
;
1069 unit
->tx_end_int
.is_Node
.ln_Name
= unit
->name
;
1070 unit
->tx_end_int
.is_Code
= (VOID_FUNC
)TX_End_Int
;
1071 unit
->tx_end_int
.is_Data
= unit
;
1073 for (i
=0; i
< REQUEST_QUEUE_COUNT
; i
++)
1075 struct MsgPort
*port
= AllocMem(sizeof(struct MsgPort
), MEMF_PUBLIC
| MEMF_CLEAR
);
1076 unit
->request_ports
[i
] = port
;
1078 if (port
== NULL
) success
= FALSE
;
1082 NEWLIST(&port
->mp_MsgList
);
1083 port
->mp_Flags
= PA_IGNORE
;
1084 port
->mp_SigTask
= &unit
->tx_int
;
1088 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
1092 LIBBASE
->nf_syncport
= CreateMsgPort();
1094 unit
->nu_Process
= CreateNewProcTags(
1095 NP_Entry
, (IPTR
)NF_Scheduler
,
1096 NP_Name
, NFORCE_TASK_NAME
,
1098 NP_UserData
, (IPTR
)unit
,
1099 NP_StackSize
, 140960,
1102 WaitPort(LIBBASE
->nf_syncport
);
1103 msg
= GetMsg(LIBBASE
->nf_syncport
);
1105 DeleteMsgPort(LIBBASE
->nf_syncport
);
1107 D(bug("[nforce] Unit up and running\n"));
1115 D(bug("[nforce] PANIC! Couldn't get MMIO area. Aborting\n"));
1118 DeleteUnit(NforceBase
, unit
);
1123 * DeleteUnit - removes selected unit. Frees all resources and structures.
1125 * The caller should be sure, that given unit is really ready to be freed.
1128 void DeleteUnit(struct NFBase
*NforceBase
, struct NFUnit
*Unit
)
1133 if (Unit
->nu_Process
)
1135 Signal(&Unit
->nu_Process
->pr_Task
, Unit
->nu_signal_0
);
1138 for (i
=0; i
< REQUEST_QUEUE_COUNT
; i
++)
1140 if (Unit
->request_ports
[i
] != NULL
)
1141 FreeMem(Unit
->request_ports
[i
], sizeof(struct MsgPort
));
1143 Unit
->request_ports
[i
] = NULL
;
1146 if (Unit
->nu_fe_priv
)
1148 FreeMem(Unit
->nu_fe_priv
, sizeof(struct fe_priv
));
1149 Unit
->nu_fe_priv
= NULL
;
1152 if (Unit
->nu_BaseMem
)
1154 HIDD_PCIDriver_UnmapPCI(Unit
->nu_PCIDriver
,
1155 (APTR
)Unit
->nu_BaseMem
,
1159 FreeMem(Unit
, sizeof(struct NFUnit
));
1163 static struct AddressRange
*FindMulticastRange(LIBBASETYPEPTR LIBBASE
, struct NFUnit
*unit
,
1164 ULONG lower_bound_left
, UWORD lower_bound_right
, ULONG upper_bound_left
, UWORD upper_bound_right
)
1166 struct AddressRange
*range
, *tail
;
1169 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
1170 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
1172 while((range
!= tail
) && !found
)
1174 if((lower_bound_left
== range
->lower_bound_left
) &&
1175 (lower_bound_right
== range
->lower_bound_right
) &&
1176 (upper_bound_left
== range
->upper_bound_left
) &&
1177 (upper_bound_right
== range
->upper_bound_right
))
1180 range
= (APTR
)range
->node
.mln_Succ
;
1189 BOOL
AddMulticastRange(LIBBASETYPEPTR LIBBASE
, struct NFUnit
*unit
, const UBYTE
*lower_bound
,
1190 const UBYTE
*upper_bound
)
1192 struct AddressRange
*range
;
1193 ULONG lower_bound_left
, upper_bound_left
;
1194 UWORD lower_bound_right
, upper_bound_right
;
1196 lower_bound_left
= AROS_BE2LONG(*((ULONG
*)lower_bound
));
1197 lower_bound_right
= AROS_BE2WORD(*((UWORD
*)(lower_bound
+ 4)));
1198 upper_bound_left
= AROS_BE2LONG(*((ULONG
*)upper_bound
));
1199 upper_bound_right
= AROS_BE2WORD(*((UWORD
*)(upper_bound
+ 4)));
1201 range
= FindMulticastRange(LIBBASE
, unit
, lower_bound_left
, lower_bound_right
,
1202 upper_bound_left
, upper_bound_right
);
1208 range
= AllocMem(sizeof(struct AddressRange
), MEMF_PUBLIC
);
1211 range
->lower_bound_left
= lower_bound_left
;
1212 range
->lower_bound_right
= lower_bound_right
;
1213 range
->upper_bound_left
= upper_bound_left
;
1214 range
->upper_bound_right
= upper_bound_right
;
1215 range
->add_count
= 1;
1218 AddTail((APTR
)&unit
->multicast_ranges
, (APTR
)range
);
1221 if (unit
->range_count
++ == 0)
1223 unit
->flags
|= IFF_ALLMULTI
;
1224 unit
->set_multicast(unit
);
1229 return range
!= NULL
;
1232 BOOL
RemMulticastRange(LIBBASETYPEPTR LIBBASE
, struct NFUnit
*unit
, const UBYTE
*lower_bound
, const UBYTE
*upper_bound
)
1234 struct AddressRange
*range
;
1235 ULONG lower_bound_left
, upper_bound_left
;
1236 UWORD lower_bound_right
, upper_bound_right
;
1238 lower_bound_left
= AROS_BE2LONG(*((ULONG
*)lower_bound
));
1239 lower_bound_right
= AROS_BE2WORD(*((UWORD
*)(lower_bound
+ 4)));
1240 upper_bound_left
= AROS_BE2LONG(*((ULONG
*)upper_bound
));
1241 upper_bound_right
= AROS_BE2WORD(*((UWORD
*)(upper_bound
+ 4)));
1243 range
= FindMulticastRange(LIBBASE
, unit
, lower_bound_left
, lower_bound_right
,
1244 upper_bound_left
, upper_bound_right
);
1248 if(--range
->add_count
== 0)
1251 Remove((APTR
)range
);
1253 FreeMem(range
, sizeof(struct AddressRange
));
1255 if (--unit
->range_count
== 0)
1257 unit
->flags
&= ~IFF_ALLMULTI
;
1258 unit
->set_multicast(unit
);
1262 return range
!= NULL
;