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 AROS_UFH3(void, RX_Int
,
169 AROS_UFHA(struct NFUnit
*, unit
, A1
),
170 AROS_UFHA(APTR
, dummy
, A5
),
171 AROS_UFHA(struct ExecBase
*,SysBase
, A6
))
175 struct NFBase
*NforceBase
= unit
->nu_device
;
176 struct fe_priv
*np
= unit
->nu_fe_priv
;
178 struct TypeStats
*tracker
;
180 struct Opener
*opener
, *opener_tail
;
181 struct IOSana2Req
*request
, *request_tail
;
182 BOOL accepted
, is_orphan
;
184 /* Endless loop, with break from inside */
188 struct eth_frame
*frame
;
190 if (np
->cur_rx
- np
->refill_rx
>= RX_RING
)
191 break; /* we scanned the whole ring - do not continue */
193 /* Get the in-queue number */
194 i
= np
->cur_rx
% RX_RING
;
195 Flags
= AROS_LE2LONG(np
->rx_ring
[i
].FlagLen
);
196 len
= unit
->descr_getlength(&np
->rx_ring
[i
], np
->desc_ver
);
198 D(bug("%s: nv_rx_process: looking at packet %d, Flags 0x%x, len=%d\n",
199 unit
->name
, np
->cur_rx
, Flags
, len
));
201 /* Free frame? Do nothing - we've empty queue now */
202 if (Flags
& NV_RX_AVAIL
)
203 break; /* still owned by hardware, */
206 * the packet is for us - get it :)
209 /* look at what we actually got: */
210 if (np
->desc_ver
== DESC_VER_1
) {
211 if (!(Flags
& NV_RX_DESCRIPTORVALID
))
214 if (Flags
& NV_RX_MISSEDFRAME
) {
215 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
216 unit
->stats
.BadData
++;
219 if (Flags
& (NV_RX_ERROR1
|NV_RX_ERROR2
|NV_RX_ERROR3
|NV_RX_ERROR4
)) {
220 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
221 unit
->stats
.BadData
++;
224 if (Flags
& NV_RX_CRCERR
) {
225 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
226 unit
->stats
.BadData
++;
229 if (Flags
& NV_RX_OVERFLOW
) {
230 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
231 unit
->stats
.BadData
++;
234 if (Flags
& NV_RX_ERROR
) {
235 /* framing errors are soft errors, the rest is fatal. */
236 if (Flags
& NV_RX_FRAMINGERR
) {
237 if (Flags
& NV_RX_SUBSTRACT1
) {
241 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
242 unit
->stats
.BadData
++;
247 if (!(Flags
& NV_RX2_DESCRIPTORVALID
))
250 if (Flags
& (NV_RX2_ERROR1
|NV_RX2_ERROR2
|NV_RX2_ERROR3
|NV_RX2_ERROR4
)) {
251 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
252 unit
->stats
.BadData
++;
255 if (Flags
& NV_RX2_CRCERR
) {
256 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
257 unit
->stats
.BadData
++;
260 if (Flags
& NV_RX2_OVERFLOW
) {
261 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
262 unit
->stats
.BadData
++;
265 if (Flags
& NV_RX2_ERROR
) {
266 /* framing errors are soft errors, the rest is fatal. */
267 if (Flags
& NV_RX2_FRAMINGERR
) {
268 if (Flags
& NV_RX2_SUBSTRACT1
) {
272 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
273 unit
->stats
.BadData
++;
277 Flags
&= NV_RX2_CHECKSUMMASK
;
278 if (Flags
== NV_RX2_CHECKSUMOK1
||
279 Flags
== NV_RX2_CHECKSUMOK2
||
280 Flags
== NV_RX2_CHECKSUMOK3
) {
281 D(bug("%s: hw checksum hit!.\n", unit
->name
));
283 D(bug("%s: hwchecksum miss!.\n", unit
->name
));
287 /* got a valid packet - forward it to the network core */
288 frame
= &np
->rx_buffer
[i
];
291 /* Dump contents of frame if DEBUG enabled */
295 for (j
=0; j
<64; j
++) {
297 D(bug("\n%03x:", j
));
298 D(bug(" %02x", ((unsigned char*)frame
)[j
]));
304 /* Check for address validity */
305 if(AddressFilter(LIBBASE
, unit
, frame
->eth_packet_dest
))
307 /* Packet is addressed to this driver */
308 packet_type
= AROS_BE2WORD(frame
->eth_packet_type
);
310 opener
= (APTR
)unit
->nu_Openers
.mlh_Head
;
311 opener_tail
= (APTR
)&unit
->nu_Openers
.mlh_Tail
;
313 /* Offer packet to every opener */
314 while(opener
!= opener_tail
)
316 request
= (APTR
)opener
->read_port
.mp_MsgList
.lh_Head
;
317 request_tail
= (APTR
)&opener
->read_port
.mp_MsgList
.lh_Tail
;
320 /* Offer packet to each request until it's accepted */
321 while((request
!= request_tail
) && !accepted
)
323 if((request
->ios2_PacketType
== packet_type
)
324 || ((request
->ios2_PacketType
<= ETH_MTU
)
325 && (packet_type
<= ETH_MTU
)))
327 CopyPacket(LIBBASE
, unit
, request
, len
, packet_type
, frame
);
331 (struct IOSana2Req
*)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
337 opener
= (APTR
)opener
->node
.mln_Succ
;
340 /* If packet was unwanted, give it to S2_READORPHAN request */
343 unit
->stats
.UnknownTypesReceived
++;
345 if(!IsMsgPortEmpty(unit
->request_ports
[ADOPT_QUEUE
]))
347 CopyPacket(LIBBASE
, unit
,
348 (APTR
)unit
->request_ports
[ADOPT_QUEUE
]->
349 mp_MsgList
.lh_Head
, len
, packet_type
, frame
);
353 /* Update remaining statistics */
356 FindTypeStats(LIBBASE
, unit
, &unit
->type_trackers
, packet_type
);
359 tracker
->stats
.PacketsReceived
++;
360 tracker
->stats
.BytesReceived
+= len
;
364 unit
->stats
.PacketsReceived
++;
374 * Check status of packets which we've already sent to the NIC. Update
375 * statistics, and reenable TX queue if only there is some free space.
377 static void nv_tx_done(struct NFUnit
*unit
)
379 struct fe_priv
*np
= unit
->nu_fe_priv
;
380 struct NFBase
*NforceBase
= unit
->nu_device
;
384 /* Go through tx chain and mark all send packets as free */
385 while (np
->nic_tx
!= np
->next_tx
)
387 i
= np
->nic_tx
% TX_RING
;
389 Flags
= AROS_LE2LONG(np
->tx_ring
[i
].FlagLen
);
391 D(bug("%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
392 unit
->name
, np
->nic_tx
, Flags
));
394 if (Flags
& NV_TX_VALID
)
397 if (np
->desc_ver
== DESC_VER_1
) {
398 if (Flags
& (NV_TX_RETRYERROR
|NV_TX_CARRIERLOST
|NV_TX_LATECOLLISION
|
399 NV_TX_UNDERFLOW
|NV_TX_ERROR
))
401 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_TX
);
405 unit
->stats
.PacketsSent
++;
410 if (Flags
& (NV_TX2_RETRYERROR
|NV_TX2_CARRIERLOST
|NV_TX2_LATECOLLISION
|
411 NV_TX2_UNDERFLOW
|NV_TX2_ERROR
))
413 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_TX
);
417 unit
->stats
.PacketsSent
++;
424 * Do we have some spare space in TX queue and the queue self is blocked?
427 if (np
->next_tx
- np
->nic_tx
< TX_LIMIT_START
) {
428 if (netif_queue_stopped(unit
)) {
429 bug("%s: output queue restart\n", unit
->name
);
430 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
431 netif_wake_queue(unit
);
437 * Interrupt generated by Cause() to push new packets into the NIC interface
439 AROS_UFH3(void, TX_Int
,
440 AROS_UFHA(struct NFUnit
*, unit
, A1
),
441 AROS_UFHA(APTR
, dummy
, A5
),
442 AROS_UFHA(struct ExecBase
*,SysBase
, A6
))
446 struct fe_priv
*np
= unit
->nu_fe_priv
;
447 struct NFBase
*NforceBase
= unit
->nu_device
;
449 BOOL proceed
= FALSE
; /* Fails by default */
451 /* send packet only if there is free space on tx queue. Otherwise do nothing */
452 if (!netif_queue_stopped(unit
))
454 UWORD packet_size
, data_size
;
455 struct IOSana2Req
*request
;
456 struct Opener
*opener
;
460 struct MsgPort
*port
;
461 struct TypeStats
*tracker
;
463 proceed
= TRUE
; /* Success by default */
464 port
= unit
->request_ports
[WRITE_QUEUE
];
466 /* Still no error and there are packets to be sent? */
467 while(proceed
&& (!IsMsgPortEmpty(port
)))
469 nr
= np
->next_tx
% TX_RING
;
472 request
= (APTR
)port
->mp_MsgList
.lh_Head
;
473 data_size
= packet_size
= request
->ios2_DataLength
;
475 opener
= (APTR
)request
->ios2_BufferManagement
;
477 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
479 packet_size
+= ETH_PACKET_DATA
;
480 CopyMem(request
->ios2_DstAddr
, np
->tx_buffer
[nr
].eth_packet_dest
, ETH_ADDRESSSIZE
);
481 CopyMem(unit
->dev_addr
, np
->tx_buffer
[nr
].eth_packet_source
, ETH_ADDRESSSIZE
);
482 np
->tx_buffer
[nr
].eth_packet_type
= AROS_WORD2BE(request
->ios2_PacketType
);
484 buffer
= np
->tx_buffer
[nr
].eth_packet_data
;
487 buffer
= (UBYTE
*)&np
->tx_buffer
[nr
];
489 if (!opener
->tx_function(buffer
, request
->ios2_Data
, data_size
))
491 error
= S2ERR_NO_RESOURCES
;
492 wire_error
= S2WERR_BUFF_ERROR
;
493 ReportEvents(LIBBASE
, unit
,
494 S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
498 /* Now the packet is already in TX buffer, update flags for NIC */
502 np
->tx_ring
[nr
].FlagLen
= AROS_LONG2LE((packet_size
-1) | np
->tx_flags
);
503 D(bug("%s: nv_start_xmit: packet packet %d queued for transmission.",
504 unit
->name
, np
->next_tx
));
506 /* DEBUG? Dump frame if so */
510 for (j
=0; j
<64; j
++) {
512 D(bug("\n%03x:", j
));
513 D(bug(" %02x", ((unsigned char*)&np
->tx_buffer
[nr
])[j
]));
521 * If we've just run out of free space on the TX queue, stop
522 * it and give up pushing further frames
524 if (np
->next_tx
- np
->nic_tx
>= TX_LIMIT_STOP
)
526 bug("%s: output queue full. Stopping\n", unit
->name
);
527 netif_stop_queue(unit
);
532 * At this place linux driver used to trigger NIC to output
533 * the queued packets through wire. We will not do it as we
534 * may already see if there are new outcomming packets.
536 * Yes, this driver might be a bit faster than linux one.
542 request
->ios2_Req
.io_Error
= error
;
543 request
->ios2_WireError
= wire_error
;
545 Remove((APTR
)request
);
547 ReplyMsg((APTR
)request
);
549 /* Update statistics */
553 tracker
= FindTypeStats(LIBBASE
, unit
, &unit
->type_trackers
,
554 request
->ios2_PacketType
);
557 tracker
->stats
.PacketsSent
++;
558 tracker
->stats
.BytesSent
+= packet_size
;
564 * Here either we've filled the queue with packets to be transmitted,
565 * or just run out of spare space in TX queue. In both cases tell the
566 * NIC to start transmitting them all through wire.
568 writel(NVREG_TXRXCTL_KICK
|np
->desc_ver
, (UBYTE
*)unit
->nu_BaseMem
+ NvRegTxRxControl
);
569 pci_push((UBYTE
*)unit
->nu_BaseMem
);
572 /* Was there success? Enable incomming of new packets */
574 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
576 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_IGNORE
;
582 * Interrupt used to restart the real one
584 AROS_UFH3(void, TX_End_Int
,
585 AROS_UFHA(struct NFUnit
*, unit
, A1
),
586 AROS_UFHA(APTR
, dummy
, A5
),
587 AROS_UFHA(struct ExecBase
*,SysBase
, A6
))
591 struct NFUnit
*dev
= unit
;
592 struct fe_priv
*np
= dev
->nu_fe_priv
;
593 UBYTE
*base
= (UBYTE
*) dev
->nu_BaseMem
;
597 writel(np
->irqmask
, base
+ NvRegIrqMask
);
599 dev
->nu_irqhandler
->h_Code(dev
->nu_irqhandler
, NULL
);
606 * Maximum number of loops until we assume that a bit in the irq mask
607 * is stuck. Overridable with module param.
609 static const int max_interrupt_work
= 5;
612 * Handle timeouts and other strange cases
614 static void NF_TimeoutHandler(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
616 struct NFUnit
*dev
= (struct NFUnit
*) irq
->h_Data
;
618 struct Device
*TimerBase
= dev
->nu_TimerSlowReq
->tr_node
.io_Device
;
623 * If timeout timer is expected, and time elapsed - regenerate the
626 if (dev
->nu_toutNEED
&& (CmpTime(&time
, &dev
->nu_toutPOLL
) < 0))
628 dev
->nu_toutNEED
= FALSE
;
629 Cause(&dev
->tx_end_int
);
634 * The interrupt handler - schedules code execution to proper handlers depending
635 * on the message from nForce.
639 * Don't be surprised - this driver used to restart itself several times, in
640 * order to handle events which occur when the driver was handling previous
641 * events. It reduces the latency and amount of dropped packets. Additionally,
642 * this interrupt may put itself into deep sleep (or just quit) and restarts
643 * after certain amount of time (POLL_WAIT).
645 static void NF_IntHandler(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
647 struct NFUnit
*dev
= (struct NFUnit
*) irq
->h_Data
;
648 struct fe_priv
*np
= dev
->nu_fe_priv
;
649 UBYTE
*base
= (UBYTE
*) dev
->nu_BaseMem
;
652 struct Device
*TimerBase
= dev
->nu_TimerSlowReq
->tr_node
.io_Device
;
657 /* Restart automagically :) */
660 events
= readl(base
+ NvRegIrqStatus
) & NVREG_IRQSTAT_MASK
;
661 writel(NVREG_IRQSTAT_MASK
, base
+ NvRegIrqStatus
);
664 if (!(events
& np
->irqmask
))
668 * Some packets have been sent? Just update statistics and empty the
671 if (events
& (NVREG_IRQ_TX1
|NVREG_IRQ_TX2
|NVREG_IRQ_TX_ERR
)) {
675 /* Something received? Handle it! */
676 if (events
& (NVREG_IRQ_RX_ERROR
|NVREG_IRQ_RX
|NVREG_IRQ_RX_NOBUF
)) {
677 AROS_UFC3(void, dev
->rx_int
.is_Code
,
678 AROS_UFCA(APTR
, dev
->rx_int
.is_Data
, A1
),
679 AROS_UFCA(APTR
, dev
->rx_int
.is_Code
, A5
),
680 AROS_UFCA(struct ExecBase
*, SysBase
, A6
));
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
)) {
744 VOID
CopyPacket(struct NFBase
*NforceBase
, struct NFUnit
*unit
,
745 struct IOSana2Req
*request
, UWORD packet_size
, UWORD packet_type
,
746 struct eth_frame
*buffer
)
748 struct Opener
*opener
;
749 BOOL filtered
= FALSE
;
751 const UBYTE broadcast
[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
753 /* Set multicast and broadcast flags */
755 request
->ios2_Req
.io_Flags
&= ~(SANA2IOF_BCAST
| SANA2IOF_MCAST
);
756 if(memcmp(buffer
->eth_packet_dest
, broadcast
, 6) == 0)
757 request
->ios2_Req
.io_Flags
|= SANA2IOF_BCAST
;
759 else if((buffer
->eth_packet_dest
[0] & 0x1) != 0)
760 request
->ios2_Req
.io_Flags
|= SANA2IOF_MCAST
;
762 /* Set source and destination addresses and packet type */
763 CopyMem(buffer
->eth_packet_source
, request
->ios2_SrcAddr
, ETH_ADDRESSSIZE
);
764 CopyMem(buffer
->eth_packet_dest
, request
->ios2_DstAddr
, ETH_ADDRESSSIZE
);
765 request
->ios2_PacketType
= packet_type
;
767 /* Adjust for cooked packet request */
769 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
771 packet_size
-= ETH_PACKET_DATA
;
772 ptr
= buffer
->eth_packet_data
;
776 ptr
= (UBYTE
*)buffer
;
779 request
->ios2_DataLength
= packet_size
;
783 opener
= request
->ios2_BufferManagement
;
784 if((request
->ios2_Req
.io_Command
== CMD_READ
) &&
785 (opener
->filter_hook
!= NULL
))
786 if(!CallHookPkt(opener
->filter_hook
, request
, ptr
))
791 /* Copy packet into opener's buffer and reply packet */
793 if(!opener
->rx_function(request
->ios2_Data
, ptr
, packet_size
))
795 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
796 request
->ios2_WireError
= S2WERR_BUFF_ERROR
;
797 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
| S2EVENT_RX
);
800 Remove((APTR
)request
);
802 ReplyMsg((APTR
)request
);
806 BOOL
AddressFilter(struct NFBase
*NforceBase
, struct NFUnit
*unit
, UBYTE
*address
)
808 struct AddressRange
*range
, *tail
;
813 /* Check whether address is unicast/broadcast or multicast */
815 address_left
= AROS_BE2LONG(*((ULONG
*)address
));
816 address_right
= AROS_BE2WORD(*((UWORD
*)(address
+ 4)));
818 if((address_left
& 0x01000000) != 0 &&
819 !(address_left
== 0xffffffff && address_right
== 0xffff))
821 /* Check if this multicast address is wanted */
823 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
824 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
827 while((range
!= tail
) && !accept
)
829 if((address_left
> range
->lower_bound_left
||
830 (address_left
== range
->lower_bound_left
&&
831 address_right
>= range
->lower_bound_right
)) &&
832 (address_left
< range
->upper_bound_left
||
833 (address_left
== range
->upper_bound_left
&&
834 address_right
<= range
->upper_bound_right
)))
836 range
= (APTR
)range
->node
.mln_Succ
;
840 unit
->special_stats
[S2SS_ETHERNET_BADMULTICAST
& 0xffff]++;
848 AROS_UFH3(void, NF_Scheduler
,
849 AROS_UFHA(STRPTR
, argPtr
, A0
),
850 AROS_UFHA(ULONG
, argSize
, D0
),
851 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
855 struct NFUnit
*dev
= FindTask(NULL
)->tc_UserData
;
856 LIBBASETYPEPTR LIBBASE
= dev
->nu_device
;
858 struct MsgPort
*reply_port
, *input
;
860 D(bug("[NFORCE] In nforce process\n"));
861 D(bug("[NFORCE] Setting device up\n"));
863 reply_port
= CreateMsgPort();
864 input
= CreateMsgPort();
866 dev
->nu_input_port
= input
;
868 /* Randomize the generator with current time */
869 BattClockBase
= OpenResource("battclock.resource");
870 srandom(ReadBattClock());
872 dev
->nu_TimerSlowPort
= CreateMsgPort();
874 if (dev
->nu_TimerSlowPort
)
876 dev
->nu_TimerSlowReq
= (struct timerequest
*)
877 CreateIORequest((struct MsgPort
*)dev
->nu_TimerSlowPort
, sizeof(struct timerequest
));
879 if (dev
->nu_TimerSlowReq
)
881 if (!OpenDevice("timer.device", UNIT_VBLANK
,
882 (struct IORequest
*)dev
->nu_TimerSlowReq
, 0))
884 struct Message
*msg
= AllocVec(sizeof(struct Message
), MEMF_PUBLIC
|MEMF_CLEAR
);
887 D(bug("[NFORCE] Got VBLANK unit of timer.device\n"));
889 dev
->initialize(dev
);
891 msg
->mn_ReplyPort
= reply_port
;
892 msg
->mn_Length
= sizeof(struct Message
);
894 D(bug("[NFORCE] Setup complete. Sending handshake\n"));
895 PutMsg(LIBBASE
->nf_syncport
, msg
);
896 WaitPort(reply_port
);
901 D(bug("[NFORCE] Forever loop\n"));
903 dev
->nu_signal_0
= AllocSignal(-1);
904 dev
->nu_signal_1
= AllocSignal(-1);
905 dev
->nu_signal_2
= AllocSignal(-1);
906 dev
->nu_signal_3
= AllocSignal(-1);
908 sigset
= 1 << input
->mp_SigBit
|
909 1 << dev
->nu_signal_0
|
910 1 << dev
->nu_signal_1
|
911 1 << dev
->nu_signal_2
|
912 1 << dev
->nu_signal_3
;
915 ULONG recvd
= Wait(sigset
);
916 if (recvd
& dev
->nu_signal_0
)
919 * Shutdown process. Driver should close everything
920 * already and waits for our process to complete. Free
921 * memory allocared here and kindly return.
923 dev
->deinitialize(dev
);
924 CloseDevice((struct IORequest
*)dev
->nu_TimerSlowReq
);
925 DeleteIORequest((struct IORequest
*)dev
->nu_TimerSlowReq
);
926 DeleteMsgPort(dev
->nu_TimerSlowPort
);
927 DeleteMsgPort(input
);
928 DeleteMsgPort(reply_port
);
930 D(bug("[NFORCE] Process shutdown.\n"));
933 else if (recvd
& (1 << input
->mp_SigBit
))
935 struct IOSana2Req
*io
;
937 /* Handle incoming transactions */
938 while ((io
= (struct IOSana2Req
*)GetMsg(input
))!= NULL
);
940 ObtainSemaphore(&dev
->unit_lock
);
941 handle_request(LIBBASE
, io
);
946 /* Handle incoming signals */
956 static const struct DriverConfig
{
961 { NFORCE_MCPNET1_ID
, DEV_IRQMASK_1
|DEV_NEED_TIMERIRQ
|DEV_NEED_LINKTIMER
, DESC_VER_1
},
962 { NFORCE_MCPNET2_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LINKTIMER
|DEV_NEED_LASTPACKET1
, DESC_VER_1
},
963 { NFORCE_MCPNET3_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LINKTIMER
|DEV_NEED_LASTPACKET1
, DESC_VER_1
},
964 { NFORCE_MCPNET4_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
965 { NFORCE_MCPNET5_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
966 { NFORCE_MCPNET6_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
967 { NFORCE_MCPNET7_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
968 { NFORCE_MCPNET8_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
969 { NFORCE_MCPNET9_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
970 { NFORCE_MCPNET10_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
971 { NFORCE_MCPNET11_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
976 * Create new nForce ethernet device unit
978 struct NFUnit
*CreateUnit(struct NFBase
*NforceBase
, OOP_Object
*pciDevice
)
980 struct NFUnit
*unit
= AllocMem(sizeof(struct NFUnit
), MEMF_PUBLIC
| MEMF_CLEAR
);
986 IPTR DeviceID
, base
, len
;
989 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_ProductID
, &DeviceID
);
990 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
, (APTR
)&driver
);
992 for (i
=0; Config
[i
].ProductID
; i
++)
994 if (Config
[i
].ProductID
== DeviceID
)
996 unit
->nu_DriverFlags
= Config
[i
].DriverFlags
;
997 unit
->nu_fe_priv
->desc_ver
= Config
[i
].DescVer
;
1002 unit
->nu_device
= NforceBase
;
1003 unit
->nu_DeviceID
= DeviceID
;
1005 unit
->nu_PCIDevice
= pciDevice
;
1006 unit
->nu_PCIDriver
= driver
;
1008 InitSemaphore(&unit
->unit_lock
);
1009 NEWLIST(&unit
->nu_Openers
);
1010 NEWLIST(&unit
->multicast_ranges
);
1011 NEWLIST(&unit
->type_trackers
);
1013 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &unit
->nu_IRQ
);
1014 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Base1
, &unit
->nu_BaseIO
);
1015 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Base0
, &base
);
1016 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Size0
, &len
);
1018 unit
->nu_BaseMem
= (IPTR
)HIDD_PCIDriver_MapPCI(driver
, (APTR
)base
, len
);
1019 unit
->nu_SizeMem
= len
;
1021 if (unit
->nu_BaseMem
)
1023 struct TagItem attrs
[] = {
1024 { aHidd_PCIDevice_isIO
, TRUE
},
1025 { aHidd_PCIDevice_isMEM
, TRUE
},
1026 { aHidd_PCIDevice_isMaster
, TRUE
},
1029 OOP_SetAttrs(pciDevice
, (struct TagItem
*)&attrs
);
1031 unit
->name
= "[nforce0]";
1032 unit
->nu_fe_priv
= AllocMem(sizeof(struct fe_priv
), MEMF_PUBLIC
|MEMF_CLEAR
);
1033 unit
->nu_UnitNum
= 0;
1035 nv_get_functions(unit
);
1037 if (unit
->nu_fe_priv
)
1039 unit
->nu_fe_priv
->pci_dev
= unit
;
1040 InitSemaphore(&unit
->nu_fe_priv
->lock
);
1042 unit
->nu_irqhandler
= AllocMem(sizeof(HIDDT_IRQ_Handler
), MEMF_PUBLIC
|MEMF_CLEAR
);
1043 unit
->nu_touthandler
= AllocMem(sizeof(HIDDT_IRQ_Handler
), MEMF_PUBLIC
|MEMF_CLEAR
);
1045 if (unit
->nu_irqhandler
&& unit
->nu_touthandler
)
1047 struct Message
*msg
;
1049 unit
->nu_irqhandler
->h_Node
.ln_Pri
= 100;
1050 unit
->nu_irqhandler
->h_Node
.ln_Name
= LIBBASE
->nf_Device
.dd_Library
.lib_Node
.ln_Name
;
1051 unit
->nu_irqhandler
->h_Code
= NF_IntHandler
;
1052 unit
->nu_irqhandler
->h_Data
= unit
;
1054 unit
->nu_touthandler
->h_Node
.ln_Pri
= 100;
1055 unit
->nu_touthandler
->h_Node
.ln_Name
= LIBBASE
->nf_Device
.dd_Library
.lib_Node
.ln_Name
;
1056 unit
->nu_touthandler
->h_Code
= NF_TimeoutHandler
;
1057 unit
->nu_touthandler
->h_Data
= unit
;
1059 unit
->rx_int
.is_Node
.ln_Name
= unit
->name
;
1060 unit
->rx_int
.is_Code
= RX_Int
;
1061 unit
->rx_int
.is_Data
= unit
;
1063 unit
->tx_int
.is_Node
.ln_Name
= unit
->name
;
1064 unit
->tx_int
.is_Code
= TX_Int
;
1065 unit
->tx_int
.is_Data
= unit
;
1067 unit
->tx_end_int
.is_Node
.ln_Name
= unit
->name
;
1068 unit
->tx_end_int
.is_Code
= TX_End_Int
;
1069 unit
->tx_end_int
.is_Data
= unit
;
1071 for (i
=0; i
< REQUEST_QUEUE_COUNT
; i
++)
1073 struct MsgPort
*port
= AllocMem(sizeof(struct MsgPort
), MEMF_PUBLIC
| MEMF_CLEAR
);
1074 unit
->request_ports
[i
] = port
;
1076 if (port
== NULL
) success
= FALSE
;
1080 NEWLIST(&port
->mp_MsgList
);
1081 port
->mp_Flags
= PA_IGNORE
;
1082 port
->mp_SigTask
= &unit
->tx_int
;
1086 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
1090 LIBBASE
->nf_syncport
= CreateMsgPort();
1092 unit
->nu_Process
= CreateNewProcTags(
1093 NP_Entry
, (IPTR
)NF_Scheduler
,
1094 NP_Name
, NFORCE_TASK_NAME
,
1096 NP_UserData
, (IPTR
)unit
,
1097 NP_StackSize
, 140960,
1100 WaitPort(LIBBASE
->nf_syncport
);
1101 msg
= GetMsg(LIBBASE
->nf_syncport
);
1103 DeleteMsgPort(LIBBASE
->nf_syncport
);
1105 D(bug("[nforce] Unit up and running\n"));
1113 D(bug("[nforce] PANIC! Couldn't get MMIO area. Aborting\n"));
1116 DeleteUnit(NforceBase
, unit
);
1121 * DeleteUnit - removes selected unit. Frees all resources and structures.
1123 * The caller should be sure, that given unit is really ready to be freed.
1126 void DeleteUnit(struct NFBase
*NforceBase
, struct NFUnit
*Unit
)
1131 if (Unit
->nu_Process
)
1133 Signal(&Unit
->nu_Process
->pr_Task
, Unit
->nu_signal_0
);
1136 for (i
=0; i
< REQUEST_QUEUE_COUNT
; i
++)
1138 if (Unit
->request_ports
[i
] != NULL
)
1139 FreeMem(Unit
->request_ports
[i
], sizeof(struct MsgPort
));
1141 Unit
->request_ports
[i
] = NULL
;
1144 if (Unit
->nu_irqhandler
)
1146 FreeMem(Unit
->nu_irqhandler
, sizeof(HIDDT_IRQ_Handler
));
1147 LIBBASE
->nf_irq
= NULL
;
1150 if (Unit
->nu_fe_priv
)
1152 FreeMem(Unit
->nu_fe_priv
, sizeof(struct fe_priv
));
1153 Unit
->nu_fe_priv
= NULL
;
1156 if (Unit
->nu_BaseMem
)
1158 HIDD_PCIDriver_UnmapPCI(Unit
->nu_PCIDriver
,
1159 (APTR
)Unit
->nu_BaseMem
,
1163 FreeMem(Unit
, sizeof(struct NFUnit
));
1167 static struct AddressRange
*FindMulticastRange(LIBBASETYPEPTR LIBBASE
, struct NFUnit
*unit
,
1168 ULONG lower_bound_left
, UWORD lower_bound_right
, ULONG upper_bound_left
, UWORD upper_bound_right
)
1170 struct AddressRange
*range
, *tail
;
1173 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
1174 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
1176 while((range
!= tail
) && !found
)
1178 if((lower_bound_left
== range
->lower_bound_left
) &&
1179 (lower_bound_right
== range
->lower_bound_right
) &&
1180 (upper_bound_left
== range
->upper_bound_left
) &&
1181 (upper_bound_right
== range
->upper_bound_right
))
1184 range
= (APTR
)range
->node
.mln_Succ
;
1193 BOOL
AddMulticastRange(LIBBASETYPEPTR LIBBASE
, struct NFUnit
*unit
, const UBYTE
*lower_bound
,
1194 const UBYTE
*upper_bound
)
1196 struct AddressRange
*range
;
1197 ULONG lower_bound_left
, upper_bound_left
;
1198 UWORD lower_bound_right
, upper_bound_right
;
1200 lower_bound_left
= AROS_BE2LONG(*((ULONG
*)lower_bound
));
1201 lower_bound_right
= AROS_BE2WORD(*((UWORD
*)(lower_bound
+ 4)));
1202 upper_bound_left
= AROS_BE2LONG(*((ULONG
*)upper_bound
));
1203 upper_bound_right
= AROS_BE2WORD(*((UWORD
*)(upper_bound
+ 4)));
1205 range
= FindMulticastRange(LIBBASE
, unit
, lower_bound_left
, lower_bound_right
,
1206 upper_bound_left
, upper_bound_right
);
1212 range
= AllocMem(sizeof(struct AddressRange
), MEMF_PUBLIC
);
1215 range
->lower_bound_left
= lower_bound_left
;
1216 range
->lower_bound_right
= lower_bound_right
;
1217 range
->upper_bound_left
= upper_bound_left
;
1218 range
->upper_bound_right
= upper_bound_right
;
1219 range
->add_count
= 1;
1222 AddTail((APTR
)&unit
->multicast_ranges
, (APTR
)range
);
1225 if (unit
->range_count
++ == 0)
1227 unit
->flags
|= IFF_ALLMULTI
;
1228 unit
->set_multicast(unit
);
1233 return range
!= NULL
;
1236 BOOL
RemMulticastRange(LIBBASETYPEPTR LIBBASE
, struct NFUnit
*unit
, const UBYTE
*lower_bound
, const UBYTE
*upper_bound
)
1238 struct AddressRange
*range
;
1239 ULONG lower_bound_left
, upper_bound_left
;
1240 UWORD lower_bound_right
, upper_bound_right
;
1242 lower_bound_left
= AROS_BE2LONG(*((ULONG
*)lower_bound
));
1243 lower_bound_right
= AROS_BE2WORD(*((UWORD
*)(lower_bound
+ 4)));
1244 upper_bound_left
= AROS_BE2LONG(*((ULONG
*)upper_bound
));
1245 upper_bound_right
= AROS_BE2WORD(*((UWORD
*)(upper_bound
+ 4)));
1247 range
= FindMulticastRange(LIBBASE
, unit
, lower_bound_left
, lower_bound_right
,
1248 upper_bound_left
, upper_bound_right
);
1252 if(--range
->add_count
== 0)
1255 Remove((APTR
)range
);
1257 FreeMem(range
, sizeof(struct AddressRange
));
1259 if (--unit
->range_count
== 0)
1261 unit
->flags
&= ~IFF_ALLMULTI
;
1262 unit
->set_multicast(unit
);
1266 return range
!= NULL
;