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 volatile ULONG
readl(APTR base
)
145 return *((ULONG
*)base
);
148 static inline volatile void writel(ULONG val
, APTR base
)
150 *((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
;
456 struct IOSana2Req
*request
;
457 struct Opener
*opener
;
461 struct MsgPort
*port
;
462 struct TypeStats
*tracker
;
464 proceed
= TRUE
; /* Success by default */
465 base
= unit
->nu_device
;
466 port
= unit
->request_ports
[WRITE_QUEUE
];
468 /* Still no error and there are packets to be sent? */
469 while(proceed
&& (!IsMsgPortEmpty(port
)))
471 nr
= np
->next_tx
% TX_RING
;
474 request
= (APTR
)port
->mp_MsgList
.lh_Head
;
475 data_size
= packet_size
= request
->ios2_DataLength
;
477 opener
= (APTR
)request
->ios2_BufferManagement
;
479 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
481 packet_size
+= ETH_PACKET_DATA
;
482 CopyMem(request
->ios2_DstAddr
, np
->tx_buffer
[nr
].eth_packet_dest
, ETH_ADDRESSSIZE
);
483 CopyMem(unit
->dev_addr
, np
->tx_buffer
[nr
].eth_packet_source
, ETH_ADDRESSSIZE
);
484 np
->tx_buffer
[nr
].eth_packet_type
= AROS_WORD2BE(request
->ios2_PacketType
);
486 buffer
= np
->tx_buffer
[nr
].eth_packet_data
;
489 buffer
= (UBYTE
*)&np
->tx_buffer
[nr
];
491 if (!opener
->tx_function(buffer
, request
->ios2_Data
, data_size
))
493 error
= S2ERR_NO_RESOURCES
;
494 wire_error
= S2WERR_BUFF_ERROR
;
495 ReportEvents(LIBBASE
, unit
,
496 S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
500 /* Now the packet is already in TX buffer, update flags for NIC */
504 np
->tx_ring
[nr
].FlagLen
= AROS_LONG2LE((packet_size
-1) | np
->tx_flags
);
505 D(bug("%s: nv_start_xmit: packet packet %d queued for transmission.",
506 unit
->name
, np
->next_tx
));
508 /* DEBUG? Dump frame if so */
512 for (j
=0; j
<64; j
++) {
514 D(bug("\n%03x:", j
));
515 D(bug(" %02x", ((unsigned char*)&np
->tx_buffer
[nr
])[j
]));
523 * If we've just run out of free space on the TX queue, stop
524 * it and give up pushing further frames
526 if (np
->next_tx
- np
->nic_tx
>= TX_LIMIT_STOP
)
528 bug("%s: output queue full. Stopping\n", unit
->name
);
529 netif_stop_queue(unit
);
534 * At this place linux driver used to trigger NIC to output
535 * the queued packets through wire. We will not do it as we
536 * may already see if there are new outcomming packets.
538 * Yes, this driver might be a bit faster than linux one.
544 request
->ios2_Req
.io_Error
= error
;
545 request
->ios2_WireError
= wire_error
;
547 Remove((APTR
)request
);
549 ReplyMsg((APTR
)request
);
551 /* Update statistics */
555 tracker
= FindTypeStats(LIBBASE
, unit
, &unit
->type_trackers
,
556 request
->ios2_PacketType
);
559 tracker
->stats
.PacketsSent
++;
560 tracker
->stats
.BytesSent
+= packet_size
;
566 * Here either we've filled the queue with packets to be transmitted,
567 * or just run out of spare space in TX queue. In both cases tell the
568 * NIC to start transmitting them all through wire.
570 writel(NVREG_TXRXCTL_KICK
|np
->desc_ver
, (UBYTE
*)unit
->nu_BaseMem
+ NvRegTxRxControl
);
571 pci_push((UBYTE
*)unit
->nu_BaseMem
);
574 /* Was there success? Enable incomming of new packets */
576 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
578 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_IGNORE
;
584 * Interrupt used to restart the real one
586 AROS_UFH3(void, TX_End_Int
,
587 AROS_UFHA(struct NFUnit
*, unit
, A1
),
588 AROS_UFHA(APTR
, dummy
, A5
),
589 AROS_UFHA(struct ExecBase
*,SysBase
, A6
))
593 struct NFUnit
*dev
= unit
;
594 struct fe_priv
*np
= dev
->nu_fe_priv
;
595 UBYTE
*base
= (UBYTE
*) dev
->nu_BaseMem
;
599 writel(np
->irqmask
, base
+ NvRegIrqMask
);
601 dev
->nu_irqhandler
->h_Code(dev
->nu_irqhandler
, NULL
);
608 * Maximum number of loops until we assume that a bit in the irq mask
609 * is stuck. Overridable with module param.
611 static const int max_interrupt_work
= 5;
614 * Handle timeouts and other strange cases
616 static void NF_TimeoutHandler(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
618 struct NFUnit
*dev
= (struct NFUnit
*) irq
->h_Data
;
620 struct Device
*TimerBase
= dev
->nu_TimerSlowReq
->tr_node
.io_Device
;
625 * If timeout timer is expected, and time elapsed - regenerate the
628 if (dev
->nu_toutNEED
&& (CmpTime(&time
, &dev
->nu_toutPOLL
) < 0))
630 dev
->nu_toutNEED
= FALSE
;
631 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 void NF_IntHandler(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
649 struct NFUnit
*dev
= (struct NFUnit
*) irq
->h_Data
;
650 struct fe_priv
*np
= dev
->nu_fe_priv
;
651 UBYTE
*base
= (UBYTE
*) dev
->nu_BaseMem
;
654 struct Device
*TimerBase
= dev
->nu_TimerSlowReq
->tr_node
.io_Device
;
659 /* Restart automagically :) */
662 events
= readl(base
+ NvRegIrqStatus
) & NVREG_IRQSTAT_MASK
;
663 writel(NVREG_IRQSTAT_MASK
, base
+ NvRegIrqStatus
);
666 if (!(events
& np
->irqmask
))
670 * Some packets have been sent? Just update statistics and empty the
673 if (events
& (NVREG_IRQ_TX1
|NVREG_IRQ_TX2
|NVREG_IRQ_TX_ERR
)) {
677 /* Something received? Handle it! */
678 if (events
& (NVREG_IRQ_RX_ERROR
|NVREG_IRQ_RX
|NVREG_IRQ_RX_NOBUF
)) {
679 AROS_UFC3(void, dev
->rx_int
.is_Code
,
680 AROS_UFCA(APTR
, dev
->rx_int
.is_Data
, A1
),
681 AROS_UFCA(APTR
, dev
->rx_int
.is_Code
, A5
),
682 AROS_UFCA(struct ExecBase
*, SysBase
, A6
));
683 /* Mark received frames as free for hardware */
687 if (events
& (NVREG_IRQ_LINK
)) {
693 /* If linktimer interrupt required, handle it here */
694 if (np
->need_linktimer
&& (CmpTime(&time
, &np
->link_timeout
) < 0)) {
696 dev
->linkchange(dev
);
698 np
->link_timeout
.tv_micro
= LINK_TIMEOUT
% 1000000;
699 np
->link_timeout
.tv_secs
= LINK_TIMEOUT
/ 1000000;
700 AddTime(&np
->link_timeout
, &time
);
704 if (events
& (NVREG_IRQ_TX_ERR
)) {
705 bug("%s: received irq with events 0x%x. Probably TX fail.\n",
709 if (events
& (NVREG_IRQ_UNKNOWN
)) {
710 bug("%s: received irq with unknown events 0x%x. Please report\n",
715 * Straaaaaaaange, the interrupt was restarted more than
716 * max_interrupt_work times. Normally it should not happen, even on
717 * gigabit ethernet. In any case setup poll handler which restart this
718 * handler after specified amount of time.
720 if (i
> max_interrupt_work
)
722 bug("%s: too many iterations (%d) in nv_nic_irq.\n", dev
->name
, i
);
723 writel(0, base
+ NvRegIrqMask
);
726 /* When to wake up? */
728 dev
->nu_toutPOLL
.tv_micro
= POLL_WAIT
% 1000000;
729 dev
->nu_toutPOLL
.tv_secs
= POLL_WAIT
/ 1000000;
730 AddTime(&dev
->nu_toutPOLL
, &time
);
731 dev
->nu_toutNEED
= TRUE
;
734 break; /* break the for() loop */
739 * If TX queue was stopped, try to reenable it *ALWAYS*
741 if (netif_queue_stopped(dev
)) {
746 VOID
CopyPacket(struct NFBase
*NforceBase
, struct NFUnit
*unit
,
747 struct IOSana2Req
*request
, UWORD packet_size
, UWORD packet_type
,
748 struct eth_frame
*buffer
)
750 struct Opener
*opener
;
751 BOOL filtered
= FALSE
;
754 /* Set multicast and broadcast flags */
756 request
->ios2_Req
.io_Flags
&= ~(SANA2IOF_BCAST
| SANA2IOF_MCAST
);
757 if((*((ULONG
*)(buffer
->eth_packet_dest
)) == 0xffffffff) &&
758 (*((UWORD
*)(buffer
->eth_packet_dest
+ 4)) == 0xffff))
759 request
->ios2_Req
.io_Flags
|= SANA2IOF_BCAST
;
761 else if((buffer
->eth_packet_dest
[0] & 0x1) != 0)
762 request
->ios2_Req
.io_Flags
|= SANA2IOF_MCAST
;
764 /* Set source and destination addresses and packet type */
765 CopyMem(buffer
->eth_packet_source
, request
->ios2_SrcAddr
, ETH_ADDRESSSIZE
);
766 CopyMem(buffer
->eth_packet_dest
, request
->ios2_DstAddr
, ETH_ADDRESSSIZE
);
767 request
->ios2_PacketType
= packet_type
;
769 /* Adjust for cooked packet request */
771 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
773 packet_size
-= ETH_PACKET_DATA
;
774 ptr
= buffer
->eth_packet_data
;
778 ptr
= (UBYTE
*)buffer
;
781 request
->ios2_DataLength
= packet_size
;
785 opener
= request
->ios2_BufferManagement
;
786 if((request
->ios2_Req
.io_Command
== CMD_READ
) &&
787 (opener
->filter_hook
!= NULL
))
788 if(!CallHookPkt(opener
->filter_hook
, request
, ptr
))
793 /* Copy packet into opener's buffer and reply packet */
795 if(!opener
->rx_function(request
->ios2_Data
, ptr
, packet_size
))
797 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
798 request
->ios2_WireError
= S2WERR_BUFF_ERROR
;
799 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
| S2EVENT_RX
);
802 Remove((APTR
)request
);
804 ReplyMsg((APTR
)request
);
808 BOOL
AddressFilter(struct NFBase
*NforceBase
, struct NFUnit
*unit
, UBYTE
*address
)
810 struct AddressRange
*range
, *tail
;
815 /* Check whether address is unicast/broadcast or multicast */
817 address_left
= AROS_BE2LONG(*((ULONG
*)address
));
818 address_right
= AROS_BE2WORD(*((UWORD
*)(address
+ 4)));
820 if((address_left
& 0x01000000) != 0 &&
821 !(address_left
== 0xffffffff && address_right
== 0xffff))
823 /* Check if this multicast address is wanted */
825 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
826 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
829 while((range
!= tail
) && !accept
)
831 if((address_left
> range
->lower_bound_left
||
832 (address_left
== range
->lower_bound_left
&&
833 address_right
>= range
->lower_bound_right
)) &&
834 (address_left
< range
->upper_bound_left
||
835 (address_left
== range
->upper_bound_left
&&
836 address_right
<= range
->upper_bound_right
)))
838 range
= (APTR
)range
->node
.mln_Succ
;
842 unit
->special_stats
[S2SS_ETHERNET_BADMULTICAST
& 0xffff]++;
850 AROS_UFH3(void, NF_Scheduler
,
851 AROS_UFHA(STRPTR
, argPtr
, A0
),
852 AROS_UFHA(ULONG
, argSize
, D0
),
853 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
857 struct NFUnit
*dev
= FindTask(NULL
)->tc_UserData
;
858 LIBBASETYPEPTR LIBBASE
= dev
->nu_device
;
860 struct MsgPort
*reply_port
, *input
;
862 D(bug("[NFORCE] In nforce process\n"));
863 D(bug("[NFORCE] Setting device up\n"));
865 reply_port
= CreateMsgPort();
866 input
= CreateMsgPort();
868 dev
->nu_input_port
= input
;
870 /* Randomize the generator with current time */
871 BattClockBase
= OpenResource("battclock.resource");
872 srandom(ReadBattClock());
874 dev
->nu_TimerSlowPort
= CreateMsgPort();
876 if (dev
->nu_TimerSlowPort
)
878 dev
->nu_TimerSlowReq
= (struct timerequest
*)
879 CreateIORequest((struct MsgPort
*)dev
->nu_TimerSlowPort
, sizeof(struct timerequest
));
881 if (dev
->nu_TimerSlowReq
)
883 if (!OpenDevice("timer.device", UNIT_VBLANK
,
884 (struct IORequest
*)dev
->nu_TimerSlowReq
, 0))
886 struct Message
*msg
= AllocVec(sizeof(struct Message
), MEMF_PUBLIC
|MEMF_CLEAR
);
889 D(bug("[NFORCE] Got VBLANK unit of timer.device\n"));
891 dev
->initialize(dev
);
893 msg
->mn_ReplyPort
= reply_port
;
894 msg
->mn_Length
= sizeof(struct Message
);
896 D(bug("[NFORCE] Setup complete. Sending handshake\n"));
897 PutMsg(LIBBASE
->nf_syncport
, msg
);
898 WaitPort(reply_port
);
903 D(bug("[NFORCE] Forever loop\n"));
905 dev
->nu_signal_0
= AllocSignal(-1);
906 dev
->nu_signal_1
= AllocSignal(-1);
907 dev
->nu_signal_2
= AllocSignal(-1);
908 dev
->nu_signal_3
= AllocSignal(-1);
910 sigset
= 1 << input
->mp_SigBit
|
911 1 << dev
->nu_signal_0
|
912 1 << dev
->nu_signal_1
|
913 1 << dev
->nu_signal_2
|
914 1 << dev
->nu_signal_3
;
917 ULONG recvd
= Wait(sigset
);
918 if (recvd
& dev
->nu_signal_0
)
921 * Shutdown process. Driver should close everything
922 * already and waits for our process to complete. Free
923 * memory allocared here and kindly return.
925 dev
->deinitialize(dev
);
926 CloseDevice((struct IORequest
*)dev
->nu_TimerSlowReq
);
927 DeleteIORequest((struct IORequest
*)dev
->nu_TimerSlowReq
);
928 DeleteMsgPort(dev
->nu_TimerSlowPort
);
929 DeleteMsgPort(input
);
930 DeleteMsgPort(reply_port
);
932 D(bug("[NFORCE] Process shutdown.\n"));
935 else if (recvd
& (1 << input
->mp_SigBit
))
937 struct IOSana2Req
*io
;
939 /* Handle incoming transactions */
940 while ((io
= (struct IOSana2Req
*)GetMsg(input
))!= NULL
);
942 ObtainSemaphore(&dev
->unit_lock
);
943 handle_request(LIBBASE
, io
);
948 /* Handle incoming signals */
958 static const struct DriverConfig
{
963 { NFORCE_MCPNET1_ID
, DEV_IRQMASK_1
|DEV_NEED_TIMERIRQ
|DEV_NEED_LINKTIMER
, DESC_VER_1
},
964 { NFORCE_MCPNET2_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LINKTIMER
|DEV_NEED_LASTPACKET1
, DESC_VER_1
},
965 { NFORCE_MCPNET3_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LINKTIMER
|DEV_NEED_LASTPACKET1
, DESC_VER_1
},
966 { NFORCE_MCPNET4_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
967 { NFORCE_MCPNET5_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
968 { NFORCE_MCPNET6_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
969 { NFORCE_MCPNET7_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
970 { NFORCE_MCPNET8_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
971 { NFORCE_MCPNET9_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
972 { NFORCE_MCPNET10_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
973 { NFORCE_MCPNET11_ID
, DEV_IRQMASK_2
|DEV_NEED_TIMERIRQ
|DEV_NEED_LASTPACKET1
, DESC_VER_2
},
978 * Create new nForce ethernet device unit
980 struct NFUnit
*CreateUnit(struct NFBase
*NforceBase
, OOP_Object
*pciDevice
)
982 struct NFUnit
*unit
= AllocMem(sizeof(struct NFUnit
), MEMF_PUBLIC
| MEMF_CLEAR
);
988 IPTR DeviceID
, base
, len
;
991 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_ProductID
, &DeviceID
);
992 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
, (APTR
)&driver
);
994 for (i
=0; Config
[i
].ProductID
; i
++)
996 if (Config
[i
].ProductID
== DeviceID
)
998 unit
->nu_DriverFlags
= Config
[i
].DriverFlags
;
999 unit
->nu_fe_priv
->desc_ver
= Config
[i
].DescVer
;
1004 unit
->nu_device
= NforceBase
;
1005 unit
->nu_DeviceID
= DeviceID
;
1007 unit
->nu_PCIDevice
= pciDevice
;
1008 unit
->nu_PCIDriver
= driver
;
1010 InitSemaphore(&unit
->unit_lock
);
1011 NEWLIST(&unit
->nu_Openers
);
1012 NEWLIST(&unit
->multicast_ranges
);
1013 NEWLIST(&unit
->type_trackers
);
1015 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &unit
->nu_IRQ
);
1016 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Base1
, &unit
->nu_BaseIO
);
1017 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Base0
, &base
);
1018 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Size0
, &len
);
1020 unit
->nu_BaseMem
= (IPTR
)HIDD_PCIDriver_MapPCI(driver
, (APTR
)base
, len
);
1021 unit
->nu_SizeMem
= len
;
1023 if (unit
->nu_BaseMem
)
1025 struct TagItem attrs
[] = {
1026 { aHidd_PCIDevice_isIO
, TRUE
},
1027 { aHidd_PCIDevice_isMEM
, TRUE
},
1028 { aHidd_PCIDevice_isMaster
, TRUE
},
1031 OOP_SetAttrs(pciDevice
, (struct TagItem
*)&attrs
);
1033 unit
->name
= "[nforce0]";
1034 unit
->nu_fe_priv
= AllocMem(sizeof(struct fe_priv
), MEMF_PUBLIC
|MEMF_CLEAR
);
1035 unit
->nu_UnitNum
= 0;
1037 nv_get_functions(unit
);
1039 if (unit
->nu_fe_priv
)
1041 unit
->nu_fe_priv
->pci_dev
= unit
;
1042 InitSemaphore(&unit
->nu_fe_priv
->lock
);
1044 unit
->nu_irqhandler
= AllocMem(sizeof(HIDDT_IRQ_Handler
), MEMF_PUBLIC
|MEMF_CLEAR
);
1045 unit
->nu_touthandler
= AllocMem(sizeof(HIDDT_IRQ_Handler
), MEMF_PUBLIC
|MEMF_CLEAR
);
1047 if (unit
->nu_irqhandler
&& unit
->nu_touthandler
)
1049 struct Message
*msg
;
1051 unit
->nu_irqhandler
->h_Node
.ln_Pri
= 100;
1052 unit
->nu_irqhandler
->h_Node
.ln_Name
= LIBBASE
->nf_Device
.dd_Library
.lib_Node
.ln_Name
;
1053 unit
->nu_irqhandler
->h_Code
= NF_IntHandler
;
1054 unit
->nu_irqhandler
->h_Data
= unit
;
1056 unit
->nu_touthandler
->h_Node
.ln_Pri
= 100;
1057 unit
->nu_touthandler
->h_Node
.ln_Name
= LIBBASE
->nf_Device
.dd_Library
.lib_Node
.ln_Name
;
1058 unit
->nu_touthandler
->h_Code
= NF_TimeoutHandler
;
1059 unit
->nu_touthandler
->h_Data
= unit
;
1061 unit
->rx_int
.is_Node
.ln_Name
= unit
->name
;
1062 unit
->rx_int
.is_Code
= 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
= 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
= 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_irqhandler
)
1148 FreeMem(Unit
->nu_irqhandler
, sizeof(HIDDT_IRQ_Handler
));
1149 LIBBASE
->nf_irq
= NULL
;
1152 if (Unit
->nu_fe_priv
)
1154 FreeMem(Unit
->nu_fe_priv
, sizeof(struct fe_priv
));
1155 Unit
->nu_fe_priv
= NULL
;
1158 if (Unit
->nu_BaseMem
)
1160 HIDD_PCIDriver_UnmapPCI(Unit
->nu_PCIDriver
,
1161 (APTR
)Unit
->nu_BaseMem
,
1165 FreeMem(Unit
, sizeof(struct NFUnit
));
1169 static struct AddressRange
*FindMulticastRange(LIBBASETYPEPTR LIBBASE
, struct NFUnit
*unit
,
1170 ULONG lower_bound_left
, UWORD lower_bound_right
, ULONG upper_bound_left
, UWORD upper_bound_right
)
1172 struct AddressRange
*range
, *tail
;
1175 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
1176 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
1178 while((range
!= tail
) && !found
)
1180 if((lower_bound_left
== range
->lower_bound_left
) &&
1181 (lower_bound_right
== range
->lower_bound_right
) &&
1182 (upper_bound_left
== range
->upper_bound_left
) &&
1183 (upper_bound_right
== range
->upper_bound_right
))
1186 range
= (APTR
)range
->node
.mln_Succ
;
1195 BOOL
AddMulticastRange(LIBBASETYPEPTR LIBBASE
, struct NFUnit
*unit
, const UBYTE
*lower_bound
,
1196 const UBYTE
*upper_bound
)
1198 struct AddressRange
*range
;
1199 ULONG lower_bound_left
, upper_bound_left
;
1200 UWORD lower_bound_right
, upper_bound_right
;
1202 lower_bound_left
= AROS_BE2LONG(*((ULONG
*)lower_bound
));
1203 lower_bound_right
= AROS_BE2WORD(*((UWORD
*)(lower_bound
+ 4)));
1204 upper_bound_left
= AROS_BE2LONG(*((ULONG
*)upper_bound
));
1205 upper_bound_right
= AROS_BE2WORD(*((UWORD
*)(upper_bound
+ 4)));
1207 range
= FindMulticastRange(LIBBASE
, unit
, lower_bound_left
, lower_bound_right
,
1208 upper_bound_left
, upper_bound_right
);
1214 range
= AllocMem(sizeof(struct AddressRange
), MEMF_PUBLIC
);
1217 range
->lower_bound_left
= lower_bound_left
;
1218 range
->lower_bound_right
= lower_bound_right
;
1219 range
->upper_bound_left
= upper_bound_left
;
1220 range
->upper_bound_right
= upper_bound_right
;
1221 range
->add_count
= 1;
1224 AddTail((APTR
)&unit
->multicast_ranges
, (APTR
)range
);
1227 if (unit
->range_count
++ == 0)
1229 unit
->flags
|= IFF_ALLMULTI
;
1230 unit
->set_multicast(unit
);
1235 return range
!= NULL
;
1238 BOOL
RemMulticastRange(LIBBASETYPEPTR LIBBASE
, struct NFUnit
*unit
, const UBYTE
*lower_bound
, const UBYTE
*upper_bound
)
1240 struct AddressRange
*range
;
1241 ULONG lower_bound_left
, upper_bound_left
;
1242 UWORD lower_bound_right
, upper_bound_right
;
1244 lower_bound_left
= AROS_BE2LONG(*((ULONG
*)lower_bound
));
1245 lower_bound_right
= AROS_BE2WORD(*((UWORD
*)(lower_bound
+ 4)));
1246 upper_bound_left
= AROS_BE2LONG(*((ULONG
*)upper_bound
));
1247 upper_bound_right
= AROS_BE2WORD(*((UWORD
*)(upper_bound
+ 4)));
1249 range
= FindMulticastRange(LIBBASE
, unit
, lower_bound_left
, lower_bound_right
,
1250 upper_bound_left
, upper_bound_right
);
1254 if(--range
->add_count
== 0)
1257 Remove((APTR
)range
);
1259 FreeMem(range
, sizeof(struct AddressRange
));
1261 if (--unit
->range_count
== 0)
1263 unit
->flags
&= ~IFF_ALLMULTI
;
1264 unit
->set_multicast(unit
);
1268 return range
!= NULL
;