store the pre-alphacomposit hook and allow it to be queried.
[AROS.git] / workbench / devs / networks / emac / emac_unit.c
blob96cd58a555dc3e922473211d5c9a0d9d141c28a1
1 #define DEBUG 0
2 #include <aros/debug.h>
3 #include <aros/macros.h>
4 #include <asm/amcc440.h>
5 #include <asm/io.h>
6 #include <inttypes.h>
8 #include <proto/kernel.h>
9 #include <proto/dos.h>
10 #include <proto/utility.h>
11 #include <proto/processor.h>
13 #include <utility/utility.h>
14 #include <utility/hooks.h>
15 #include <utility/tagitem.h>
17 #include <resources/processor.h>
19 #include "emac.h"
20 #include LC_LIBDEFS_FILE
22 // TODO: Implement CmdFlush!!!!!!!!!
24 static void EMAC_UDelay(struct EMACUnit *unit, uint32_t usec)
26 unit->eu_TimerPort.mp_SigTask = FindTask(NULL);
27 unit->eu_TimerRequest.tr_node.io_Command = TR_ADDREQUEST;
28 unit->eu_TimerRequest.tr_time.tv_secs = usec / 1000000;
29 unit->eu_TimerRequest.tr_time.tv_micro = usec % 1000000;
31 DoIO((struct IORequest *)&unit->eu_TimerRequest);
34 static int EMAC_Start(struct EMACUnit *unit)
36 void *stack;
37 uint16_t reg_short;
38 uint32_t reg, mode_reg, speed, duplex;
39 int i;
41 D(bug("[EMAC%d] start()\n", unit->eu_UnitNum));
44 * Enable MAL channels:
45 * TX Channels 0 and 1 are assigned to unit 0, Channels 2 and 3 are assigned to unit 1.
46 * RX Channel 0 is assigned to unit 0, channel 1 is assigned to unit 1.
48 stack = SuperState();
49 D(bug("[EMAC%d] Enable MAL\n", unit->eu_UnitNum));
50 wrdcr(MAL0_RXCASR, 0x80000000 >> unit->eu_UnitNum);
51 wrdcr(MAL0_TXCASR, 0x80000000 >> (2*unit->eu_UnitNum));
52 UserState(stack);
54 /* set RMII mode */
55 outl(0, ZMII_FER);
56 unit->udelay(unit, 100);
57 outl((ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (unit->eu_UnitNum), ZMII_FER);
58 outl(ZMII_SSR_SP << ZMII_SSR_V(unit->eu_UnitNum), ZMII_SSR);
60 /* Reset EMAC */
61 outl(EMAC_M0_SRST, EMAC_M0 + unit->eu_IOBase);
62 while(inl(EMAC_M0 + unit->eu_IOBase) & EMAC_M0_SRST)
63 unit->udelay(unit, 1000);
65 EMAC_miiphy_reset(unit);
67 /* Start/Restart autonegotiation */
68 EMAC_phy_setup_aneg(unit);
69 unit->udelay(unit, 1000);
71 EMAC_miiphy_read (unit, PHY_BMSR, &reg_short);
74 * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
76 if ((reg_short & PHY_BMSR_AUTN_ABLE)
77 && !(reg_short & PHY_BMSR_AUTN_COMP)) {
78 D(bug("[EMAC%d] Waiting for PHY auto negotiation to complete", unit->eu_UnitNum));
79 i = 0;
80 while (!(reg_short & PHY_BMSR_AUTN_COMP)) {
82 * Timeout reached ?
84 if (i > 10000) {
85 D(bug(" TIMEOUT !\n"));
86 break;
89 if ((i++ % 1000) == 0) {
90 D(bug("."));
92 unit->udelay (unit, 1000); /* 1 ms */
93 EMAC_miiphy_read (unit, PHY_BMSR, &reg_short);
96 D(bug(" done\n"));
97 unit->udelay (unit, 500000); /* another 500 ms (results in faster booting) */
100 speed = EMAC_miiphy_speed (unit);
101 duplex = EMAC_miiphy_duplex (unit);
103 D(bug("[EMAC%d] Speed is %d Mbps - %s duplex connection\n", unit->eu_UnitNum,
104 (int) speed, (duplex == HALF) ? "HALF" : "FULL"));
106 stack = SuperState();
107 wrdcr(SDR0_CFGADDR, SDR0_MFR);
108 reg = rddcr(SDR0_CFGDATA);
109 if (speed == 100) {
110 reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_100M;
111 } else {
112 reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_10M;
114 wrdcr(SDR0_CFGADDR, SDR0_MFR);
115 wrdcr(SDR0_CFGDATA, reg);
116 UserState(stack);
118 /* Set ZMII/RGMII speed according to the phy link speed */
119 reg = inl(ZMII_SSR);
120 if ( (speed == 100) || (speed == 1000) )
121 outl (reg | (ZMII_SSR_SP << ZMII_SSR_V (unit->eu_UnitNum)), ZMII_SSR);
122 else
123 outl (reg & (~(ZMII_SSR_SP << ZMII_SSR_V (unit->eu_UnitNum))), ZMII_SSR);
125 /* set transmit enable & receive enable */
126 outl (EMAC_M0_TXE | EMAC_M0_RXE, EMAC_M0 + unit->eu_IOBase);
128 /* set receive fifo to 4k and tx fifo to 2k */
129 mode_reg = inl (EMAC_M1 + unit->eu_IOBase);
130 mode_reg |= EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K;
132 /* set speed */
133 if (speed == _1000BASET) {
134 mode_reg = mode_reg | EMAC_M1_MF_1000MBPS | EMAC_M1_IST;
135 } else if (speed == _100BASET)
136 mode_reg = mode_reg | EMAC_M1_MF_100MBPS | EMAC_M1_IST;
137 else
138 mode_reg = mode_reg & ~0x00C00000; /* 10 MBPS */
139 if (duplex == FULL)
140 mode_reg = mode_reg | 0x80000000 | EMAC_M1_IST;
142 outl (mode_reg, EMAC_M1 + unit->eu_IOBase);
144 /* Enable broadcast and indvidual address */
145 /* TBS: enabling runts as some misbehaved nics will send runts */
146 outl (EMAC_RMR_BAE | EMAC_RMR_IAE, EMAC_RXM + unit->eu_IOBase);
148 /* we probably need to set the tx mode1 reg? maybe at tx time */
150 /* set transmit request threshold register */
151 outl (0x18000000, EMAC_TRTR + unit->eu_IOBase); /* 256 byte threshold */
153 /* set receive low/high water mark register */
154 /* 440s has a 64 byte burst length */
155 outl (0x80009000, EMAC_RX_HI_LO_WMARK + unit->eu_IOBase);
157 outl (0xf8640000, EMAC_TXM1 + unit->eu_IOBase);
159 /* Set fifo limit entry in tx mode 0 */
160 outl (0x00000003, EMAC_TXM0 + unit->eu_IOBase);
161 /* Frame gap set */
162 outl (0x00000008, EMAC_I_FRAME_GAP_REG + unit->eu_IOBase);
164 /* Set EMAC IER */
165 unit->eu_IER = EMAC_ISR_PTLE | EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE;
166 if (speed == _100BASET)
167 unit->eu_IER = unit->eu_IER | EMAC_ISR_SYE;
169 outl (0xffffffff, EMAC_ISR + unit->eu_IOBase); /* clear pending interrupts */
170 outl (unit->eu_IER, EMAC_IER + unit->eu_IOBase);
172 unit->eu_Flags |= IFF_UP;
174 return 0;
177 static int EMAC_Stop(struct EMACUnit *unit)
179 void *stack;
180 uint32_t casr;
182 D(bug("[EMAC%d] stop()\n", unit->eu_UnitNum));
184 unit->eu_Flags &= ~IFF_UP;
186 /* Stop MAL channels */
187 stack = SuperState();
189 D(bug("[EMAC%d] Disable and reset MAL\n", unit->eu_UnitNum));
190 wrdcr(MAL0_RXCARR, 0x80000000 >> unit->eu_UnitNum);
191 wrdcr(MAL0_TXCARR, 0xc0000000 >> (2*unit->eu_UnitNum));
193 casr = rddcr(MAL0_RXCASR);
194 UserState(stack);
196 /* Wait for Reset to complete */
197 while(casr & (0x80000000 >> unit->eu_UnitNum))
199 unit->udelay(unit, 1000);
201 stack = SuperState();
202 casr = rddcr(MAL0_RXCASR);
203 UserState(stack);
206 /* Reset the EMAC */
207 outl(EMAC_M0_SRST, EMAC_M0 + unit->eu_IOBase);
209 D(bug("[EMAC%d] stopped\n", unit->eu_UnitNum));
211 return 1;
214 static void EMAC_SetMacAddress(struct EMACUnit *unit)
216 uint32_t reg;
218 D(bug("[EMAC%d] set_mac_address()\n", unit->eu_UnitNum));
219 D(bug("[EMAC%d] New addr=%02x:%02x:%02x:%02x:%02x:%02x\n", unit->eu_UnitNum,
220 unit->eu_DevAddr[0],unit->eu_DevAddr[1],
221 unit->eu_DevAddr[2],unit->eu_DevAddr[3],
222 unit->eu_DevAddr[4],unit->eu_DevAddr[5]));
224 reg = 0;
226 reg |= unit->eu_DevAddr[0];
227 reg = reg << 8;
228 reg |= unit->eu_DevAddr[1];
230 outl (reg, EMAC_IAH + unit->eu_IOBase);
232 reg = 0;
234 reg |= unit->eu_DevAddr[2];
235 reg = reg << 8;
236 reg |= unit->eu_DevAddr[3];
237 reg = reg << 8;
238 reg |= unit->eu_DevAddr[4];
239 reg = reg << 8;
240 reg |= unit->eu_DevAddr[5];
242 outl (reg, EMAC_IAL + unit->eu_IOBase);
246 * Report incoming events to all hyphotetical event receivers
248 VOID ReportEvents(struct EMACBase *EMACBase, struct EMACUnit *unit, ULONG events)
250 struct IOSana2Req *request, *tail, *next_request;
251 struct List *list;
253 list = &unit->eu_RequestPorts[EVENT_QUEUE]->mp_MsgList;
254 next_request = (APTR)list->lh_Head;
255 tail = (APTR)&list->lh_Tail;
257 /* Go through list of event listeners. If send messages to receivers if event found */
258 Disable();
259 while(next_request != tail)
261 request = next_request;
262 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
264 if((request->ios2_WireError&events) != 0)
266 request->ios2_WireError = events;
267 Remove((APTR)request);
268 ReplyMsg((APTR)request);
271 Enable();
273 return;
276 VOID CopyPacket(struct EMACBase *EMACBase, struct EMACUnit *unit,
277 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
278 struct eth_frame *buffer)
280 struct Opener *opener;
281 BOOL filtered = FALSE;
282 UBYTE *ptr;
284 D(bug("[EMAC%d] CopyPacket(packet @ %x, len = %d)\n", unit->eu_UnitNum, buffer, packet_size));
286 /* Set multicast and broadcast flags */
288 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
289 if((*((ULONG *)(buffer->eth_packet_dest)) == 0xffffffff) &&
290 (*((UWORD *)(buffer->eth_packet_dest + 4)) == 0xffff))
292 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
293 D(bug("[EMAC%d] CopyPacket: BROADCAST Flag set\n", unit->eu_UnitNum));
295 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
297 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
298 D(bug("[EMAC%d] CopyPacket: MULTICAST Flag set\n", unit->eu_UnitNum));
301 /* Set source and destination addresses and packet type */
302 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
303 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
304 request->ios2_PacketType = packet_type;
306 /* Adjust for cooked packet request */
308 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
310 packet_size -= ETH_PACKET_DATA;
311 ptr = (UBYTE*)&buffer->eth_packet_data[0];
313 else
315 ptr = (UBYTE*)buffer;
318 request->ios2_DataLength = packet_size;
319 D(bug("[EMAC%d] CopyPacket: packet @ %x (%d bytes)\n", unit->eu_UnitNum, ptr, packet_size));
321 /* Filter packet */
323 opener = request->ios2_BufferManagement;
324 if((request->ios2_Req.io_Command == CMD_READ) &&
325 (opener->filter_hook != NULL))
326 if(!CallHookPkt(opener->filter_hook, request, ptr))
328 D(bug("[EMAC%d] CopyPacket: packet filtered\n", unit->eu_UnitNum));
329 filtered = TRUE;
332 if(!filtered)
334 /* Copy packet into opener's buffer and reply packet */
335 D(bug("[EMAC%d] CopyPacket: opener recieve packet .. ", unit->eu_UnitNum));
336 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
338 D(bug("ERROR occured!!\n"));
339 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
340 request->ios2_WireError = S2WERR_BUFF_ERROR;
341 ReportEvents(EMACBase, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
343 else
345 D(bug("SUCCESS!!\n"));
347 Disable();
348 Remove((APTR)request);
349 Enable();
350 ReplyMsg((APTR)request);
351 D(bug("[EMAC%d] CopyPacket: opener notified.\n", unit->eu_UnitNum));
355 BOOL AddressFilter(struct EMACBase *EMACBase, struct EMACUnit *unit, UBYTE *address)
357 struct AddressRange *range, *tail;
358 BOOL accept = TRUE;
359 ULONG address_left;
360 UWORD address_right;
362 /* Check whether address is unicast/broadcast or multicast */
364 address_left = AROS_BE2LONG(*((ULONG *)address));
365 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
367 if((address_left & 0x01000000) != 0 &&
368 !(address_left == 0xffffffff && address_right == 0xffff))
370 /* Check if this multicast address is wanted */
372 range = (APTR)unit->eu_MulticastRanges.mlh_Head;
373 tail = (APTR)&unit->eu_MulticastRanges.mlh_Tail;
374 accept = FALSE;
376 while((range != tail) && !accept)
378 if((address_left > range->lower_bound_left ||
379 (address_left == range->lower_bound_left &&
380 address_right >= range->lower_bound_right)) &&
381 (address_left < range->upper_bound_left ||
382 (address_left == range->upper_bound_left &&
383 address_right <= range->upper_bound_right)))
384 accept = TRUE;
385 range = (APTR)range->node.mln_Succ;
387 if(!accept)
388 unit->eu_SpecialStats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
390 return accept;
393 void rx_int(struct EMACUnit *unit, struct ExecBase *SysBase)
395 mal_descriptor_t descr;
396 int i;
397 int last_slot = unit->eu_LastRXSlot;
398 struct TypeStats *tracker;
399 ULONG packet_type;
400 struct Opener *opener, *opener_tail;
401 struct IOSana2Req *request, *request_tail;
402 BOOL accepted, is_orphan;
405 D(bug("[EMAC%d] RX Int\n", unit->eu_UnitNum));
406 D(bug("[EMAC%d] Starting at packet %d", unit->eu_UnitNum, (unit->eu_LastRXSlot + 1) % RX_RING_SIZE));
407 for (i=1; i <= RX_RING_SIZE; i++)
409 int packet_pos = ((i + last_slot) % RX_RING_SIZE) >> 2 ;
410 int sub_pos = ((i + last_slot) % RX_RING_SIZE) % 4;
411 mal_packet_t mal_packet;
413 /* Invalidate each cache line - four mal descriptors at once - the very special case is
414 * the first run of interrupt handler - it has to fetch the cache line unconditionally */
415 if (!sub_pos || i == 1)
417 /* Invalidate memory containing MAL descriptor */
418 CacheClearE(&unit->eu_RXChannel[packet_pos], sizeof(mal_packet), CACRF_InvalidateD);
419 mal_packet = unit->eu_RXChannel[packet_pos];
422 /* Work on local descriptor's copy */
423 descr = mal_packet.descr[sub_pos];
425 if (!(descr.md_ctrl & MAL_CTRL_RX_E))
427 struct eth_frame *frame;
428 is_orphan = TRUE;
430 unit->eu_LastRXSlot = (packet_pos << 2) + sub_pos;
432 D(bug("[EMAC%d] MAL descriptor %d filled with %d bytes\n", unit->eu_UnitNum, (packet_pos << 2) + sub_pos, descr.md_length));
434 /* Invalidate memory containing MAL descriptor */
435 CacheClearE(descr.md_buffer, descr.md_length, CACRF_InvalidateD);
436 frame = (struct eth_frame *)descr.md_buffer;
438 /* Dump contents of frame if DEBUG enabled */
440 int j;
441 for (j=0; j<64; j++) {
442 if ((j%16) == 0)
443 D(bug("\n%03x:", j));
444 D(bug(" %02x", ((unsigned char*)frame)[j]));
446 D(bug("\n"));
449 /* Check for address validity */
450 if(AddressFilter(unit->eu_EMACBase, unit, frame->eth_packet_dest))
452 /* Packet is addressed to this driver */
453 packet_type = frame->eth_packet_type;
454 D(bug("[EMAC%d] Packet IP accepted with type = %d\n", unit->eu_UnitNum, packet_type));
456 opener = (APTR)unit->eu_Openers.mlh_Head;
457 opener_tail = (APTR)&unit->eu_Openers.mlh_Tail;
458 /* Offer packet to every opener */
460 while(opener != opener_tail)
462 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
463 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
464 accepted = FALSE;
466 /* Offer packet to each request until it's accepted */
467 while((request != request_tail) && !accepted)
469 if((request->ios2_PacketType == packet_type)
470 || ((request->ios2_PacketType <= ETH_MTU)
471 && (packet_type <= ETH_MTU)))
473 D(bug("[EMAC%d] copy packet for opener ..\n", unit->eu_UnitNum));
474 CopyPacket(unit->eu_EMACBase, unit, request, descr.md_length, packet_type, frame);
475 accepted = TRUE;
477 request =
478 (struct IOSana2Req *)request->ios2_Req.io_Message.mn_Node.ln_Succ;
481 if(accepted)
482 is_orphan = FALSE;
484 opener = (APTR)opener->node.mln_Succ;
487 /* If packet was unwanted, give it to S2_READORPHAN request */
488 if(is_orphan)
490 unit->eu_Stats.UnknownTypesReceived++;
492 if(!IsMsgPortEmpty(unit->eu_RequestPorts[ADOPT_QUEUE]))
494 CopyPacket(unit->eu_EMACBase, unit,
495 (APTR)unit->eu_RequestPorts[ADOPT_QUEUE]->
496 mp_MsgList.lh_Head, descr.md_length, packet_type, frame);
497 D(bug("[EMAC%d] packet copied to orphan queue\n", unit->eu_UnitNum));
501 /* Update remaining statistics */
503 tracker =
504 FindTypeStats(unit->eu_EMACBase, unit, &unit->eu_TypeTrackers, packet_type);
505 if(tracker != NULL)
507 tracker->stats.PacketsReceived++;
508 tracker->stats.BytesReceived += descr.md_length;
513 /* Set the descriptor back as free */
514 descr.md_ctrl |= MAL_CTRL_RX_E;
515 descr.md_length = 0;
517 /* Save local copy and flush data cache */
518 /* Invalidate memory containing MAL descriptor */
519 CacheClearE(&unit->eu_RXChannel[packet_pos], sizeof(mal_packet), CACRF_InvalidateD);
520 mal_packet = unit->eu_RXChannel[packet_pos];
522 mal_packet.descr[sub_pos] = descr;
523 unit->eu_RXChannel[packet_pos] = mal_packet;
524 CacheClearE(&unit->eu_RXChannel[packet_pos], sizeof(mal_packet), CACRF_ClearD);
529 static AROS_INTH1(EMAC_RX_Int, struct EMACUnit *, unit)
531 AROS_INTFUNC_INIT
533 D(bug("[EMAC%d] RX Int\n", unit->eu_UnitNum));
534 rx_int(unit, SysBase);
536 return 0;
538 AROS_INTFUNC_EXIT
541 void tx_int(struct EMACUnit *unit, struct ExecBase *SysBase)
543 struct EMACBase *EMACBase = unit->eu_EMACBase;
544 mal_descriptor_t descr;
545 int nr, try_count = 1;
546 int last_slot = unit->eu_LastTXSlot;
547 UWORD packet_size, data_size;
548 struct IOSana2Req *request;
549 struct Opener *opener;
550 UBYTE *buffer;
551 ULONG wire_error=0;
552 BYTE error;
553 struct MsgPort *port;
554 struct TypeStats *tracker;
555 int packet_pos;
556 int sub_pos;
557 BOOL proceed = TRUE; /* Success by default */
559 port = unit->eu_RequestPorts[WRITE_QUEUE];
561 D(bug("[EMAC%d] TX Int\n", unit->eu_UnitNum));
562 D(bug("[EMAC%d] Starting at packet %d\d", unit->eu_UnitNum, (last_slot + 1) % TX_RING_SIZE));
564 // for (nr=0; nr < TX_RING_SIZE; nr++)
565 // {
566 // CacheClearE(&unit->eu_TXChannel[nr>>2], sizeof(mal_packet_t), CACRF_InvalidateD);
567 // D(bug("%04x ",unit->eu_TXChannel[nr>>2].descr[nr%4].md_ctrl));
568 // }
569 /* Still no error and there are packets to be sent? */
570 while(proceed && (!IsMsgPortEmpty(port)))
572 mal_packet_t mal_packet;
574 nr = (last_slot + 1) % TX_RING_SIZE;
576 packet_pos = nr >> 2 ;
577 sub_pos = nr % 4;
579 error = 0;
581 /* Invalidate memory containing MAL descriptor */
582 CacheClearE(&unit->eu_TXChannel[packet_pos], sizeof(mal_packet), CACRF_InvalidateD);
583 mal_packet = unit->eu_TXChannel[packet_pos];
584 /* Work on local descriptor's copy */
585 descr = mal_packet.descr[sub_pos];
587 if (!(descr.md_ctrl & MAL_CTRL_TX_R))
589 struct eth_frame *eth = (struct eth_frame *)descr.md_buffer;
590 request = (APTR)port->mp_MsgList.lh_Head;
591 data_size = packet_size = request->ios2_DataLength;
593 opener = (APTR)request->ios2_BufferManagement;
595 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
597 packet_size += ETH_PACKET_DATA;
598 CopyMem(request->ios2_DstAddr, eth->eth_packet_dest, ETH_ADDRESSSIZE);
599 CopyMem(unit->eu_DevAddr, eth->eth_packet_source, ETH_ADDRESSSIZE);
600 eth->eth_packet_type = request->ios2_PacketType;
602 buffer = eth->eth_packet_data;
604 else
605 buffer = descr.md_buffer;
607 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
609 error = S2ERR_NO_RESOURCES;
610 wire_error = S2WERR_BUFF_ERROR;
611 ReportEvents(EMACBase, unit,
612 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
613 | S2EVENT_TX);
616 if (error == 0)
618 D(bug("[EMAC%d] packet %d:%d [type = %d] queued for transmission.", unit->eu_UnitNum, last_slot, nr, eth->eth_packet_type));
620 /* Dump contents of frame if DEBUG enabled */
622 int j;
623 for (j=0; j<64; j++) {
624 if ((j%16) == 0)
625 D(bug("\n%03x:", j));
626 D(bug(" %02x", ((unsigned char*)eth)[j]));
628 D(bug("\n"));
631 /* Update the descriptor */
632 descr.md_length = packet_size;
633 descr.md_ctrl |= MAL_CTRL_TX_R | MAL_CTRL_TX_I | MAL_CTRL_TX_L | EMAC_CTRL_TX_GFCS | EMAC_CTRL_TX_GP;
634 CacheClearE(descr.md_buffer, descr.md_length, CACRF_ClearD);
636 CacheClearE(&unit->eu_TXChannel[packet_pos], sizeof(mal_packet), CACRF_InvalidateD);
637 mal_packet = unit->eu_TXChannel[packet_pos];
638 mal_packet.descr[sub_pos] = descr;
639 unit->eu_TXChannel[packet_pos] = mal_packet;
640 CacheClearE(&unit->eu_TXChannel[packet_pos], sizeof(mal_packet), CACRF_ClearD);
643 /* Reply packet */
645 request->ios2_Req.io_Error = error;
646 request->ios2_WireError = wire_error;
647 Disable();
648 Remove((APTR)request);
649 Enable();
650 ReplyMsg((APTR)request);
652 /* Update statistics */
654 if(error == 0)
656 tracker = FindTypeStats(EMACBase, unit, &unit->eu_TypeTrackers,
657 request->ios2_PacketType);
658 if(tracker != NULL)
660 tracker->stats.PacketsSent++;
661 tracker->stats.BytesSent += packet_size;
664 try_count=0;
667 unit->eu_LastTXSlot = ++last_slot;
668 try_count++;
671 * If we've just run out of free space on the TX queue, stop
672 * it and give up pushing further frames
674 if ( (try_count + 1) >= TX_RING_SIZE)
676 D(bug("[EMAC%d] output queue full!. Stopping [count = %d, TX_RING_SIZE = %d\n", unit->eu_UnitNum, try_count, TX_RING_SIZE));
677 proceed = FALSE;
681 /* Tell EMAC that it has new packets to process */
682 outl(inl(EMAC_TXM0 + unit->eu_IOBase) | EMAC_TXM0_GNP0, EMAC_TXM0 + unit->eu_IOBase);
684 /* Was there success? Enable incomming of new packets */
685 if(proceed)
686 unit->eu_RequestPorts[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
687 else
688 unit->eu_RequestPorts[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
692 static AROS_INTH1(EMAC_TX_Int, struct EMACUnit *, unit)
694 AROS_INTFUNC_INIT
696 D(bug("[EMAC%d] TX Int\n", unit->eu_UnitNum));
697 tx_int(unit, SysBase);
699 return 0;
701 AROS_INTFUNC_EXIT
704 static AROS_INTH1(EMAC_TXEnd_Int, struct EMACUnit *, unit)
706 AROS_INTFUNC_INIT
708 D(bug("[EMAC%d] TX End Int\n", unit->eu_UnitNum));
710 return FALSE;
712 AROS_INTFUNC_EXIT
715 struct TypeStats *FindTypeStats(struct EMACBase *EMACBase, struct EMACUnit *unit,
716 struct MinList *list, ULONG packet_type)
718 struct TypeStats *stats, *tail;
719 BOOL found = FALSE;
721 stats = (APTR)list->mlh_Head;
722 tail = (APTR)&list->mlh_Tail;
724 while(stats != tail && !found)
726 if(stats->packet_type == packet_type)
727 found = TRUE;
728 else
729 stats = (APTR)stats->node.mln_Succ;
732 if(!found)
733 stats = NULL;
735 return stats;
738 static
739 AROS_UFH3(void, EMAC_UnitProcess,
740 AROS_UFHA(char *, argPtr, A0),
741 AROS_UFHA(ULONG, argSize, D0),
742 AROS_UFHA(struct ExecBase *, SysBase, A6))
744 AROS_USERFUNC_INIT
746 struct MsgPort *iport;
747 struct EMACUnit *unit = (struct EMACUnit *)(FindTask(NULL)->tc_UserData);
748 struct Process *parent = unit->eu_Process;
750 unit->eu_Process = (struct Process *)FindTask(NULL);
752 D(bug("[EMAC%d] Hello there.\n", unit->eu_UnitNum));
753 D(bug("[EMAC%d] Process @ %p\n", unit->eu_UnitNum, unit->eu_Process));
755 unit->eu_Flags = 0;
756 unit->eu_OpenCount = 0;
757 unit->eu_RangeCount = 0;
759 iport = CreateMsgPort();
761 unit->eu_InputPort = iport;
763 unit->eu_TimerPort.mp_SigBit = SIGB_SINGLE;
764 unit->eu_TimerPort.mp_Flags = PA_SIGNAL;
765 unit->eu_TimerPort.mp_SigTask = FindTask(NULL);
766 unit->eu_TimerPort.mp_Node.ln_Type = NT_MSGPORT;
767 NEWLIST(&unit->eu_TimerPort.mp_MsgList);
769 unit->eu_TimerRequest.tr_node.io_Message.mn_ReplyPort = &unit->eu_TimerPort;
770 unit->eu_TimerRequest.tr_node.io_Message.mn_Length = sizeof(unit->eu_TimerRequest);
772 OpenDevice((STRPTR)"timer.device", UNIT_MICROHZ, (struct IORequest *)&unit->eu_TimerRequest, 0);
774 EMAC_Startup(unit);
776 Signal((struct Task *)parent, SIGF_SINGLE);
778 do {
779 uint32_t sigset = 1 << iport->mp_SigBit |
780 SIGBREAKF_CTRL_C;
782 uint32_t rcvd = Wait(sigset);
784 if (rcvd & SIGBREAKF_CTRL_C)
786 D(bug("[EMAC%d] CTRL_C signal\n", unit->eu_UnitNum));
788 else if (rcvd & (1 << iport->mp_SigBit))
790 struct IOSana2Req *io;
792 /* Handle incoming transactions */
793 while ((io = (struct IOSana2Req *)GetMsg(iport))!= NULL);
795 D(bug("[EMAC%d] Handle incomming transaction.\n", unit->eu_UnitNum));
796 ObtainSemaphore(&unit->eu_Lock);
797 handle_request(unit->eu_EMACBase, io);
801 } while(1);
803 AROS_USERFUNC_EXIT
806 static const struct UnitInfo {
807 uint8_t ui_IrqNum;
808 char *ui_TaskName;
809 intptr_t ui_IOBase;
810 uint8_t ui_PHYAddr;
811 } EMAC_Units_sam440[2] = {
812 { INTR_ETH0, EMAC_TASK1_NAME, EMAC0_BASE, 24 },
813 { INTR_ETH1, EMAC_TASK2_NAME, EMAC1_BASE, 25 },
814 }, EMAC_Units_sam460[2] = {
815 { INTR_UIC2_BASE + INTR_UIC2_EMAC0, EMAC_TASK1_NAME, EMAC0_BASE, 0 },
816 { INTR_UIC2_BASE + INTR_UIC2_EMAC0, EMAC_TASK2_NAME, EMAC1_BASE, 1 },
819 ULONG GetPVR(void)
821 struct Library *ProcessorBase = OpenResource(PROCESSORNAME);
822 ULONG pvr = 0;
824 if (ProcessorBase) {
825 struct TagItem tags[] = {
826 { GCIT_Model, (IPTR)&pvr },
827 { TAG_END }
829 GetCPUInfo(tags);
832 return pvr;
835 struct EMACUnit *CreateUnit(struct EMACBase *EMACBase, uint8_t num)
837 void *KernelBase = OpenResource("kernel.resource");
839 D(bug("[EMAC ] CreateUnit(%d)\n", num));
841 struct EMACUnit *unit = AllocPooled(EMACBase->emb_Pool, sizeof(struct EMACUnit));
843 if (unit)
845 int i;
846 const struct UnitInfo *EMAC_Units;
848 if (GetPVR() == PVR_PPC460EX_B) {
849 EMAC_Units = &EMAC_Units_sam460[0];
850 } else {
851 EMAC_Units = &EMAC_Units_sam440[0];
854 InitSemaphore(&unit->eu_Lock);
856 NEWLIST(&unit->eu_Openers);
857 NEWLIST(&unit->eu_MulticastRanges);
858 NEWLIST(&unit->eu_TypeTrackers);
860 unit->eu_UnitNum = num;
861 unit->eu_IRQHandler = KrnAddIRQHandler(EMAC_Units[num].ui_IrqNum, EMACIRQHandler, EMACBase, unit);
862 unit->eu_EMACBase = EMACBase;
863 unit->eu_IOBase = EMAC_Units[num].ui_IOBase;
864 unit->eu_PHYAddr = EMAC_Units[num].ui_PHYAddr;
865 unit->eu_MTU = ETH_MTU;
867 unit->eu_LastTXSlot = TX_RING_SIZE - 1;
868 unit->eu_LastRXSlot = RX_RING_SIZE - 1;
870 unit->start = EMAC_Start;
871 unit->stop = EMAC_Stop;
872 unit->set_mac_address = EMAC_SetMacAddress;
873 unit->udelay = EMAC_UDelay;
875 unit->eu_RXInt.is_Node.ln_Name = "EMAC RX Int";
876 unit->eu_RXInt.is_Code = (VOID_FUNC)EMAC_RX_Int;
877 unit->eu_RXInt.is_Data = unit;
879 unit->eu_TXInt.is_Node.ln_Name = "EMAC TX Int";
880 unit->eu_TXInt.is_Code = (VOID_FUNC)EMAC_TX_Int;
881 unit->eu_TXInt.is_Data = unit;
883 unit->eu_TXEndInt.is_Node.ln_Name = "EMAC TX Int";
884 unit->eu_TXEndInt.is_Code = (VOID_FUNC)EMAC_TXEnd_Int;
885 unit->eu_TXEndInt.is_Data = unit;
887 unit->eu_RXChannel = (mal_packet_t *)EMACBase->emb_MALRXChannels[num];
888 unit->eu_TXChannel = (mal_packet_t *)EMACBase->emb_MALTXChannels[num];
889 //unit->eu_TXChannel[1] = (mal_packet_t *)EMACBase->emb_MALTXChannels[2*num+1];
891 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
893 struct MsgPort *port = AllocPooled(EMACBase->emb_Pool, sizeof(struct MsgPort));
894 unit->eu_RequestPorts[i] = port;
896 if (port)
898 NEWLIST(&port->mp_MsgList);
899 port->mp_Flags = PA_IGNORE;
900 port->mp_SigTask = &unit->eu_TXInt;
904 unit->eu_RequestPorts[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
906 /* Create the unit's process */
908 /* Unit's process pointer will temporarly contain the parent */
909 unit->eu_Process = (struct Process *)FindTask(NULL);
910 CreateNewProcTags(
911 NP_Entry, (IPTR)EMAC_UnitProcess,
912 NP_Name, EMAC_Units[num].ui_TaskName,
913 NP_Priority, 0,
914 NP_UserData, (IPTR)unit,
915 NP_StackSize, 40960,
916 TAG_DONE);
918 /* Wait for synchronisation signal */
919 Wait(SIGF_SINGLE);
921 D(bug("[EMAC ] Unit %d up and running\n", num));
924 return unit;
927 static struct AddressRange *FindMulticastRange(struct EMACBase *EMACBase, struct EMACUnit *unit,
928 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
930 struct AddressRange *range, *tail;
931 BOOL found = FALSE;
933 range = (APTR)unit->eu_MulticastRanges.mlh_Head;
934 tail = (APTR)&unit->eu_MulticastRanges.mlh_Tail;
936 while((range != tail) && !found)
938 if((lower_bound_left == range->lower_bound_left) &&
939 (lower_bound_right == range->lower_bound_right) &&
940 (upper_bound_left == range->upper_bound_left) &&
941 (upper_bound_right == range->upper_bound_right))
942 found = TRUE;
943 else
944 range = (APTR)range->node.mln_Succ;
947 if(!found)
948 range = NULL;
950 return range;
953 BOOL AddMulticastRange(struct EMACBase *EMACBase, struct EMACUnit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
955 struct AddressRange *range;
956 ULONG lower_bound_left, upper_bound_left;
957 UWORD lower_bound_right, upper_bound_right;
959 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
960 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
961 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
962 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
964 range = FindMulticastRange(EMACBase, unit, lower_bound_left, lower_bound_right,
965 upper_bound_left, upper_bound_right);
967 if(range != NULL)
968 range->add_count++;
969 else
971 range = AllocPooled(EMACBase->emb_Pool, sizeof(struct AddressRange));
972 if(range != NULL)
974 range->lower_bound_left = lower_bound_left;
975 range->lower_bound_right = lower_bound_right;
976 range->upper_bound_left = upper_bound_left;
977 range->upper_bound_right = upper_bound_right;
978 range->add_count = 1;
980 Disable();
981 AddTail((APTR)&unit->eu_MulticastRanges, (APTR)range);
982 Enable();
984 if (unit->eu_RangeCount++ == 0)
986 unit->eu_Flags |= IFF_ALLMULTI;
987 unit->set_multicast(unit);
992 return range != NULL;
995 BOOL RemMulticastRange(struct EMACBase *EMACBase, struct EMACUnit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
997 struct AddressRange *range;
998 ULONG lower_bound_left, upper_bound_left;
999 UWORD lower_bound_right, upper_bound_right;
1001 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1002 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1003 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1004 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1006 range = FindMulticastRange(EMACBase, unit, lower_bound_left, lower_bound_right,
1007 upper_bound_left, upper_bound_right);
1009 if(range != NULL)
1011 if(--range->add_count == 0)
1013 Disable();
1014 Remove((APTR)range);
1015 Enable();
1016 FreePooled(EMACBase->emb_Pool, range, sizeof(struct AddressRange));
1018 if (--unit->eu_RangeCount == 0)
1020 unit->eu_Flags &= ~IFF_ALLMULTI;
1021 unit->set_multicast(unit);
1025 return range != NULL;