4 * Created on: May 18, 2009
9 #include <aros/debug.h>
10 #include <aros/libcall.h>
11 #include <aros/asmcall.h>
12 #include <aros/symbolsets.h>
14 #include <exec/memory.h>
16 #include <devices/timer.h>
17 #include <devices/sana2.h>
18 #include <devices/sana2specialstats.h>
20 #include <proto/openfirmware.h>
21 #include <proto/exec.h>
22 #include <proto/dos.h>
28 static int FEC_void(struct FECUnit
*unit
)
30 D(bug("[FEC] DUMB FUNCITON CALLED\n"));
34 static struct AddressRange
*FindMulticastRange(struct FECBase
*FECBase
, struct FECUnit
*unit
,
35 ULONG lower_bound_left
, UWORD lower_bound_right
, ULONG upper_bound_left
, UWORD upper_bound_right
)
37 struct AddressRange
*range
, *tail
;
40 range
= (APTR
)unit
->feu_MulticastRanges
.mlh_Head
;
41 tail
= (APTR
)&unit
->feu_MulticastRanges
.mlh_Tail
;
43 while((range
!= tail
) && !found
)
45 if((lower_bound_left
== range
->lower_bound_left
) &&
46 (lower_bound_right
== range
->lower_bound_right
) &&
47 (upper_bound_left
== range
->upper_bound_left
) &&
48 (upper_bound_right
== range
->upper_bound_right
))
51 range
= (APTR
)range
->node
.mln_Succ
;
60 BOOL
AddMulticastRange(struct FECBase
*FECBase
, struct FECUnit
*unit
, const UBYTE
*lower_bound
, const UBYTE
*upper_bound
)
62 struct AddressRange
*range
;
63 ULONG lower_bound_left
, upper_bound_left
;
64 UWORD lower_bound_right
, upper_bound_right
;
66 lower_bound_left
= AROS_BE2LONG(*((ULONG
*)lower_bound
));
67 lower_bound_right
= AROS_BE2WORD(*((UWORD
*)(lower_bound
+ 4)));
68 upper_bound_left
= AROS_BE2LONG(*((ULONG
*)upper_bound
));
69 upper_bound_right
= AROS_BE2WORD(*((UWORD
*)(upper_bound
+ 4)));
71 range
= FindMulticastRange(FECBase
, unit
, lower_bound_left
, lower_bound_right
,
72 upper_bound_left
, upper_bound_right
);
78 range
= AllocPooled(FECBase
->feb_Pool
, sizeof(struct AddressRange
));
81 range
->lower_bound_left
= lower_bound_left
;
82 range
->lower_bound_right
= lower_bound_right
;
83 range
->upper_bound_left
= upper_bound_left
;
84 range
->upper_bound_right
= upper_bound_right
;
88 AddTail((APTR
)&unit
->feu_MulticastRanges
, (APTR
)range
);
91 if (unit
->feu_RangeCount
++ == 0)
93 unit
->feu_Flags
|= IFF_ALLMULTI
;
94 unit
->set_multicast(unit
);
102 BOOL
RemMulticastRange(struct FECBase
*FECBase
, struct FECUnit
*unit
, const UBYTE
*lower_bound
, const UBYTE
*upper_bound
)
104 struct AddressRange
*range
;
105 ULONG lower_bound_left
, upper_bound_left
;
106 UWORD lower_bound_right
, upper_bound_right
;
108 lower_bound_left
= AROS_BE2LONG(*((ULONG
*)lower_bound
));
109 lower_bound_right
= AROS_BE2WORD(*((UWORD
*)(lower_bound
+ 4)));
110 upper_bound_left
= AROS_BE2LONG(*((ULONG
*)upper_bound
));
111 upper_bound_right
= AROS_BE2WORD(*((UWORD
*)(upper_bound
+ 4)));
113 range
= FindMulticastRange(FECBase
, unit
, lower_bound_left
, lower_bound_right
,
114 upper_bound_left
, upper_bound_right
);
118 if(--range
->add_count
== 0)
123 FreePooled(FECBase
->feb_Pool
, range
, sizeof(struct AddressRange
));
125 if (--unit
->feu_RangeCount
== 0)
127 unit
->feu_Flags
&= ~IFF_ALLMULTI
;
128 unit
->set_multicast(unit
);
132 return range
!= NULL
;
135 struct TypeStats
*FindTypeStats(struct FECBase
*FECBase
, struct FECUnit
*unit
,
136 struct MinList
*list
, ULONG packet_type
)
138 struct TypeStats
*stats
, *tail
;
141 stats
= (APTR
)list
->mlh_Head
;
142 tail
= (APTR
)&list
->mlh_Tail
;
144 while(stats
!= tail
&& !found
)
146 if(stats
->packet_type
== packet_type
)
149 stats
= (APTR
)stats
->node
.mln_Succ
;
158 static int FEC_Start(struct FECUnit
*unit
)
162 D(bug("[FEC] Start\n"));
165 FEC_Reset_Stats(unit
);
167 unit
->feu_phy_id
= FEC_PHY_Find(unit
);
169 /* Detect link status and speed */
171 FEC_PHY_Setup_Autonegotiation(unit
);
173 FEC_UDelay(unit
, 1000);
175 reg
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_BMSR
);
178 * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
180 if ((reg
& PHY_BMSR_AUTN_ABLE
) && !(reg
& PHY_BMSR_AUTN_COMP
))
182 D(bug("[FEC] Waiting for PHY auto negotiation to complete"));
184 while (!(reg
& PHY_BMSR_AUTN_COMP
))
191 D(bug(" TIMEOUT !\n"));
195 if ((i
++ % 100) == 0)
199 FEC_UDelay(unit
, 1000); /* 1 ms */
200 reg
= FEC_MDIO_Read(unit
, unit
->feu_phy_id
, PHY_BMSR
);
203 FEC_UDelay(unit
, 500000); /* another 500 ms (results in faster booting) */
206 unit
->feu_speed
= FEC_PHY_Speed(unit
);
207 unit
->feu_duplex
= FEC_PHY_Duplex(unit
);
208 unit
->feu_link
= FEC_PHY_Link(unit
);
210 D(bug("[FEC] Link %s\n", unit
->feu_link
? "up" : "down"));
211 D(bug("[FEC] Speed %d, %s duplex\n", unit
->feu_speed
, unit
->feu_duplex
== HALF
? "half":"full"));
213 unit
->feu_Flags
|= IFF_UP
;
220 AROS_UFH3(void, FEC_UnitProcess
,
221 AROS_UFHA(char *, argPtr
, A0
),
222 AROS_UFHA(ULONG
, argSize
, D0
),
223 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
227 struct MsgPort
*iport
;
228 struct MsgPort
*tport
;
229 struct timerequest
*timer
;
231 struct FECUnit
*unit
= (struct FECUnit
*)(FindTask(NULL
)->tc_UserData
);
232 struct Process
*parent
= unit
->feu_Process
;
234 unit
->feu_Process
= (struct Process
*)FindTask(NULL
);
236 D(bug("[FEC] Hello there.\n"));
237 D(bug("[FEC] Process @ %p\n", unit
->feu_Process
));
240 unit
->feu_OpenCount
= 0;
241 unit
->feu_RangeCount
= 0;
243 /* Input port for incoming requests */
244 iport
= CreateMsgPort();
246 /* Timer request and corresponding port will be used to periodically test the link status of PHY */
247 tport
= CreateMsgPort();
248 timer
= (struct timerequest
*)CreateIORequest(tport
, sizeof(struct timerequest
));
249 OpenDevice("timer.device", UNIT_VBLANK
, &timer
->tr_node
, 0);
251 unit
->feu_InputPort
= iport
;
253 unit
->feu_TimerPort
.mp_SigBit
= SIGB_SINGLE
;
254 unit
->feu_TimerPort
.mp_Flags
= PA_SIGNAL
;
255 unit
->feu_TimerPort
.mp_SigTask
= FindTask(NULL
);
256 unit
->feu_TimerPort
.mp_Node
.ln_Type
= NT_MSGPORT
;
257 NEWLIST(&unit
->feu_TimerPort
.mp_MsgList
);
259 unit
->feu_TimerRequest
.tr_node
.io_Message
.mn_ReplyPort
= &unit
->feu_TimerPort
;
260 unit
->feu_TimerRequest
.tr_node
.io_Message
.mn_Length
= sizeof(unit
->feu_TimerRequest
);
262 OpenDevice((STRPTR
)"timer.device", UNIT_MICROHZ
, (struct IORequest
*)&unit
->feu_TimerRequest
, 0);
264 /* Start the unit now... */
268 Signal(&parent
->pr_Task
, SIGF_SINGLE
);
271 /* Come back in one second ;) */
272 timer
->tr_node
.io_Command
= TR_ADDREQUEST
;
273 timer
->tr_time
.tv_secs
= 1;
274 timer
->tr_time
.tv_micro
= 0;
275 SendIO(&timer
->tr_node
);
280 const uint32_t sigset
=
281 1 << iport
->mp_SigBit
|
282 1 << tport
->mp_SigBit
|
289 if (rcvd
& SIGBREAKF_CTRL_C
)
291 D(bug("[FEC] CTRL_C signal. Bye now ;) \n"));
293 /* Abort potentially pending timer request */
294 if (!CheckIO(&timer
->tr_node
))
295 AbortIO(&timer
->tr_node
);
296 WaitIO(&timer
->tr_node
);
297 SetSignal(0, 1 << timer
->tr_node
.io_Message
.mn_ReplyPort
->mp_SigBit
);
299 else if (rcvd
& (1 << tport
->mp_SigBit
))
301 /* timer request. Check the PHY link state */
302 int link
= FEC_PHY_Link(unit
);
303 int duplex
= FEC_PHY_Duplex(unit
);
304 int speed
= FEC_PHY_Speed(unit
);
306 if ((link
!= unit
->feu_link
) || (duplex
!= unit
->feu_duplex
) || (speed
!= unit
->feu_speed
))
311 * If link status is unchanged (how come!??), stop the unit. It will be
312 * restarted few lines below.
314 if (unit
->feu_link
== link
)
316 D(bug("[FEC] LINK CHANGED\n"));
320 D(bug("[FEC] LINK %s\n", link
? "UP":"DOWN"));
323 unit
->feu_link
= link
;
324 unit
->feu_speed
= speed
;
325 unit
->feu_duplex
= duplex
;
333 /* Empty the reply port */
334 while (GetMsg(timer
->tr_node
.io_Message
.mn_ReplyPort
));
336 /* Come back in one second ;) */
337 timer
->tr_node
.io_Command
= TR_ADDREQUEST
;
338 timer
->tr_time
.tv_secs
= 1;
339 timer
->tr_time
.tv_micro
= 0;
340 SendIO(&timer
->tr_node
);
342 else if (rcvd
& (1 << iport
->mp_SigBit
))
344 struct IOSana2Req
*io
;
346 /* Handle incoming transactions */
347 while ((io
= (struct IOSana2Req
*)GetMsg(iport
))!= NULL
);
349 D(bug("[FEC] Handle incoming transaction.\n"));
350 ObtainSemaphore(&unit
->feu_Lock
);
351 handle_request(unit
->feu_FECBase
, io
);
356 } while((rcvd
& SIGBREAKF_CTRL_C
) == 0);
359 CloseDevice(&unit
->feu_TimerRequest
.tr_node
);
360 CloseDevice(&timer
->tr_node
);
361 DeleteIORequest(&timer
->tr_node
);
362 DeleteMsgPort(tport
);
363 DeleteMsgPort(iport
);
368 int FEC_CreateUnit(struct FECBase
*FECBase
, fec_t
*regs
)
371 struct FECUnit
*unit
= NULL
;
372 void *OpenFirmwareBase
= NULL
;
374 D(bug("[FEC] Creating FEC Unit\n"));
376 unit
= AllocPooled(FECBase
->feb_Pool
, sizeof(struct FECUnit
));
382 D(bug("[FEC] Unit @ %08x, Registers @ %08x\n", unit
, regs
));
384 unit
->feu_regs
= regs
;
386 OpenFirmwareBase
= OpenResource("openfirmware.resource");
388 if (OpenFirmwareBase
)
390 void *key
= OF_OpenKey("/builtin");
391 void *prop
= OF_FindProperty(key
, "bus-frequency");
393 uint32_t bus_frequency
= 0;
397 bus_frequency
= *(uint32_t *)OF_GetPropValue(prop
);
400 D(bug("[FEC] Bus frequency %d MHz\n", bus_frequency
/ 1000000));
402 unit
->feu_phy_speed
= (((bus_frequency
+ 2500000) / 5000000)) << 1;
404 D(bug("[FEC] MII speed %d\n", unit
->feu_phy_speed
));
406 InitSemaphore(&unit
->feu_Lock
);
408 NEWLIST(&unit
->feu_Openers
);
409 NEWLIST(&unit
->feu_MulticastRanges
);
410 NEWLIST(&unit
->feu_TypeTrackers
);
412 unit
->feu_FECBase
= FECBase
;
414 for (i
=0; i
< REQUEST_QUEUE_COUNT
; i
++)
416 struct MsgPort
*port
= AllocPooled(FECBase
->feb_Pool
, sizeof(struct MsgPort
));
417 unit
->feu_RequestPorts
[i
] = port
;
421 NEWLIST(&port
->mp_MsgList
);
422 port
->mp_Flags
= PA_IGNORE
;
423 port
->mp_SigTask
= &unit
->feu_TXInt
;
426 unit
->feu_RequestPorts
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
428 unit
->start
= FEC_Start
;
429 unit
->stop
= FEC_void
;
431 /* Create the unit's process */
433 /* Unit's process pointer will temporarly contain the parent */
434 unit
->feu_Process
= (struct Process
*)FindTask(NULL
);
436 NP_Entry
, (IPTR
)FEC_UnitProcess
,
437 NP_Name
, "FEC Process",
439 NP_UserData
, (IPTR
)unit
,
443 /* Wait for synchronisation signal */
446 D(bug("[FEC] Unit up and running\n"));
448 FECBase
->feb_Unit
= unit
;