grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / networks / fec / fec_unit.c
blob9b90466bf8abd54c2d9db6757f3907b1ca74da39
1 /*
2 * fec_unit.c
4 * Created on: May 18, 2009
5 * Author: misc
6 */
8 #define DEBUG 1
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>
24 #include <inttypes.h>
26 #include "fec.h"
28 static int FEC_void(struct FECUnit *unit)
30 D(bug("[FEC] DUMB FUNCITON CALLED\n"));
31 return 0;
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;
38 BOOL found = FALSE;
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))
49 found = TRUE;
50 else
51 range = (APTR)range->node.mln_Succ;
54 if(!found)
55 range = NULL;
57 return range;
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);
74 if(range != NULL)
75 range->add_count++;
76 else
78 range = AllocPooled(FECBase->feb_Pool, sizeof(struct AddressRange));
79 if(range != NULL)
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;
85 range->add_count = 1;
87 Disable();
88 AddTail((APTR)&unit->feu_MulticastRanges, (APTR)range);
89 Enable();
91 if (unit->feu_RangeCount++ == 0)
93 unit->feu_Flags |= IFF_ALLMULTI;
94 unit->set_multicast(unit);
99 return range != NULL;
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);
116 if(range != NULL)
118 if(--range->add_count == 0)
120 Disable();
121 Remove((APTR)range);
122 Enable();
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;
139 BOOL found = FALSE;
141 stats = (APTR)list->mlh_Head;
142 tail = (APTR)&list->mlh_Tail;
144 while(stats != tail && !found)
146 if(stats->packet_type == packet_type)
147 found = TRUE;
148 else
149 stats = (APTR)stats->node.mln_Succ;
152 if(!found)
153 stats = NULL;
155 return stats;
158 static int FEC_Start(struct FECUnit *unit)
160 uint16_t reg;
162 D(bug("[FEC] Start\n"));
164 FEC_HW_Init(unit);
165 FEC_Reset_Stats(unit);
167 unit->feu_phy_id = FEC_PHY_Find(unit);
169 /* Detect link status and speed */
170 FEC_PHY_Reset(unit);
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"));
183 int i = 0;
184 while (!(reg & PHY_BMSR_AUTN_COMP))
187 * Timeout reached ?
189 if (i > 10000)
191 D(bug(" TIMEOUT !\n"));
192 break;
195 if ((i++ % 100) == 0)
197 D(bug("."));
199 FEC_UDelay(unit, 1000); /* 1 ms */
200 reg = FEC_MDIO_Read(unit, unit->feu_phy_id, PHY_BMSR);
202 D(bug(" done\n"));
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;
215 return 1;
218 /* Unit process */
219 static
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))
225 AROS_USERFUNC_INIT
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));
239 unit->feu_Flags = 0;
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... */
266 FEC_Start(unit);
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);
277 /* Main loop. */
279 uint32_t rcvd;
280 const uint32_t sigset =
281 1 << iport->mp_SigBit |
282 1 << tport->mp_SigBit |
283 SIGBREAKF_CTRL_C;
287 rcvd = Wait(sigset);
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"));
317 unit->stop(unit);
319 else
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;
327 if (!link)
328 unit->stop(unit);
329 else
330 unit->start(unit);
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);
365 AROS_USERFUNC_EXIT
368 int FEC_CreateUnit(struct FECBase *FECBase, fec_t *regs)
370 int retval = 0;
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));
378 if (unit)
380 int i;
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;
395 if (prop)
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;
419 if (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);
435 CreateNewProcTags(
436 NP_Entry, (IPTR)FEC_UnitProcess,
437 NP_Name, "FEC Process",
438 NP_Priority, 5,
439 NP_UserData, (IPTR)unit,
440 NP_StackSize, 40960,
441 TAG_DONE);
443 /* Wait for synchronisation signal */
444 Wait(SIGF_SINGLE);
446 D(bug("[FEC] Unit up and running\n"));
448 FECBase->feb_Unit = unit;
450 retval = 1;
454 return retval;