Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / devs / networks / emac / emac_unit.c
blob63fce11a942e81a55fde1c49eb1ff22b2a54bcdd
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>
12 #include <utility/utility.h>
13 #include <utility/hooks.h>
14 #include <utility/tagitem.h>
16 #include "emac.h"
17 #include LC_LIBDEFS_FILE
19 #warning TODO: Implement CmdFlush!!!!!!!!!
21 static void EMAC_UDelay(struct EMACUnit *unit, uint32_t usec)
23 unit->eu_TimerPort.mp_SigTask = FindTask(NULL);
24 unit->eu_TimerRequest.tr_node.io_Command = TR_ADDREQUEST;
25 unit->eu_TimerRequest.tr_time.tv_secs = usec / 1000000;
26 unit->eu_TimerRequest.tr_time.tv_micro = usec % 1000000;
28 DoIO((struct IORequest *)&unit->eu_TimerRequest);
31 static int EMAC_Start(struct EMACUnit *unit)
33 void *stack;
34 uint16_t reg_short;
35 uint32_t reg, mode_reg, speed, duplex;
36 int i;
38 D(bug("[EMAC%d] start()\n", unit->eu_UnitNum));
41 * Enable MAL channels:
42 * TX Channels 0 and 1 are assigned to unit 0, Channels 2 and 3 are assigned to unit 1.
43 * RX Channel 0 is assigned to unit 0, channel 1 is assigned to unit 1.
45 stack = SuperState();
46 D(bug("[EMAC%d] Enable MAL\n", unit->eu_UnitNum));
47 wrdcr(MAL0_RXCASR, 0x80000000 >> unit->eu_UnitNum);
48 wrdcr(MAL0_TXCASR, 0x80000000 >> (2*unit->eu_UnitNum));
49 UserState(stack);
51 /* set RMII mode */
52 outl(0, ZMII_FER);
53 unit->udelay(unit, 100);
54 outl((ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (unit->eu_UnitNum), ZMII_FER);
55 outl(ZMII_SSR_SP << ZMII_SSR_V(unit->eu_UnitNum), ZMII_SSR);
57 /* Reset EMAC */
58 outl(EMAC_M0_SRST, EMAC_M0 + unit->eu_IOBase);
59 while(inl(EMAC_M0 + unit->eu_IOBase) & EMAC_M0_SRST)
60 unit->udelay(unit, 1000);
62 EMAC_miiphy_reset(unit);
64 /* Start/Restart autonegotiation */
65 EMAC_phy_setup_aneg(unit);
66 unit->udelay(unit, 1000);
68 EMAC_miiphy_read (unit, PHY_BMSR, &reg_short);
71 * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
73 if ((reg_short & PHY_BMSR_AUTN_ABLE)
74 && !(reg_short & PHY_BMSR_AUTN_COMP)) {
75 D(bug("[EMAC%d] Waiting for PHY auto negotiation to complete", unit->eu_UnitNum));
76 i = 0;
77 while (!(reg_short & PHY_BMSR_AUTN_COMP)) {
79 * Timeout reached ?
81 if (i > 10000) {
82 D(bug(" TIMEOUT !\n"));
83 break;
86 if ((i++ % 1000) == 0) {
87 D(bug("."));
89 unit->udelay (unit, 1000); /* 1 ms */
90 EMAC_miiphy_read (unit, PHY_BMSR, &reg_short);
93 D(bug(" done\n"));
94 unit->udelay (unit, 500000); /* another 500 ms (results in faster booting) */
97 speed = EMAC_miiphy_speed (unit);
98 duplex = EMAC_miiphy_duplex (unit);
100 D(bug("[EMAC%d] Speed is %d Mbps - %s duplex connection\n", unit->eu_UnitNum,
101 (int) speed, (duplex == HALF) ? "HALF" : "FULL"));
103 stack = SuperState();
104 wrdcr(SDR0_CFGADDR, SDR0_MFR);
105 reg = rddcr(SDR0_CFGDATA);
106 if (speed == 100) {
107 reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_100M;
108 } else {
109 reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_10M;
111 wrdcr(SDR0_CFGADDR, SDR0_MFR);
112 wrdcr(SDR0_CFGDATA, reg);
113 UserState(stack);
115 /* Set ZMII/RGMII speed according to the phy link speed */
116 reg = inl(ZMII_SSR);
117 if ( (speed == 100) || (speed == 1000) )
118 outl (reg | (ZMII_SSR_SP << ZMII_SSR_V (unit->eu_UnitNum)), ZMII_SSR);
119 else
120 outl (reg & (~(ZMII_SSR_SP << ZMII_SSR_V (unit->eu_UnitNum))), ZMII_SSR);
122 /* set transmit enable & receive enable */
123 outl (EMAC_M0_TXE | EMAC_M0_RXE, EMAC_M0 + unit->eu_IOBase);
125 /* set receive fifo to 4k and tx fifo to 2k */
126 mode_reg = inl (EMAC_M1 + unit->eu_IOBase);
127 mode_reg |= EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K;
129 /* set speed */
130 if (speed == _1000BASET) {
131 mode_reg = mode_reg | EMAC_M1_MF_1000MBPS | EMAC_M1_IST;
132 } else if (speed == _100BASET)
133 mode_reg = mode_reg | EMAC_M1_MF_100MBPS | EMAC_M1_IST;
134 else
135 mode_reg = mode_reg & ~0x00C00000; /* 10 MBPS */
136 if (duplex == FULL)
137 mode_reg = mode_reg | 0x80000000 | EMAC_M1_IST;
139 outl (mode_reg, EMAC_M1 + unit->eu_IOBase);
141 /* Enable broadcast and indvidual address */
142 /* TBS: enabling runts as some misbehaved nics will send runts */
143 outl (EMAC_RMR_BAE | EMAC_RMR_IAE, EMAC_RXM + unit->eu_IOBase);
145 /* we probably need to set the tx mode1 reg? maybe at tx time */
147 /* set transmit request threshold register */
148 outl (0x18000000, EMAC_TRTR + unit->eu_IOBase); /* 256 byte threshold */
150 /* set receive low/high water mark register */
151 /* 440s has a 64 byte burst length */
152 outl (0x80009000, EMAC_RX_HI_LO_WMARK + unit->eu_IOBase);
154 outl (0xf8640000, EMAC_TXM1 + unit->eu_IOBase);
156 /* Set fifo limit entry in tx mode 0 */
157 outl (0x00000003, EMAC_TXM0 + unit->eu_IOBase);
158 /* Frame gap set */
159 outl (0x00000008, EMAC_I_FRAME_GAP_REG + unit->eu_IOBase);
161 /* Set EMAC IER */
162 unit->eu_IER = EMAC_ISR_PTLE | EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE;
163 if (speed == _100BASET)
164 unit->eu_IER = unit->eu_IER | EMAC_ISR_SYE;
166 outl (0xffffffff, EMAC_ISR + unit->eu_IOBase); /* clear pending interrupts */
167 outl (unit->eu_IER, EMAC_IER + unit->eu_IOBase);
169 unit->eu_Flags |= IFF_UP;
171 return 0;
174 static int EMAC_Stop(struct EMACUnit *unit)
176 void *stack;
177 uint32_t casr;
179 D(bug("[EMAC%d] stop()\n", unit->eu_UnitNum));
181 unit->eu_Flags &= ~IFF_UP;
183 /* Stop MAL channels */
184 stack = SuperState();
186 D(bug("[EMAC%d] Disable and reset MAL\n", unit->eu_UnitNum));
187 wrdcr(MAL0_RXCARR, 0x80000000 >> unit->eu_UnitNum);
188 wrdcr(MAL0_TXCARR, 0xc0000000 >> (2*unit->eu_UnitNum));
190 casr = rddcr(MAL0_RXCASR);
191 UserState(stack);
193 /* Wait for Reset to complete */
194 while(casr & (0x80000000 >> unit->eu_UnitNum))
196 unit->udelay(unit, 1000);
198 stack = SuperState();
199 casr = rddcr(MAL0_RXCASR);
200 UserState(stack);
203 /* Reset the EMAC */
204 outl(EMAC_M0_SRST, EMAC_M0 + unit->eu_IOBase);
206 D(bug("[EMAC%d] stopped\n", unit->eu_UnitNum));
208 return 1;
211 static void EMAC_SetMacAddress(struct EMACUnit *unit)
213 uint32_t reg;
215 D(bug("[EMAC%d] set_mac_address()\n", unit->eu_UnitNum));
216 D(bug("[EMAC%d] New addr=%02x:%02x:%02x:%02x:%02x:%02x\n", unit->eu_UnitNum,
217 unit->eu_DevAddr[0],unit->eu_DevAddr[1],
218 unit->eu_DevAddr[2],unit->eu_DevAddr[3],
219 unit->eu_DevAddr[4],unit->eu_DevAddr[5]));
221 reg = 0;
223 reg |= unit->eu_DevAddr[0];
224 reg = reg << 8;
225 reg |= unit->eu_DevAddr[1];
227 outl (reg, EMAC_IAH + unit->eu_IOBase);
229 reg = 0;
231 reg |= unit->eu_DevAddr[2];
232 reg = reg << 8;
233 reg |= unit->eu_DevAddr[3];
234 reg = reg << 8;
235 reg |= unit->eu_DevAddr[4];
236 reg = reg << 8;
237 reg |= unit->eu_DevAddr[5];
239 outl (reg, EMAC_IAL + unit->eu_IOBase);
243 * Report incoming events to all hyphotetical event receivers
245 VOID ReportEvents(struct EMACBase *EMACBase, struct EMACUnit *unit, ULONG events)
247 struct IOSana2Req *request, *tail, *next_request;
248 struct List *list;
250 list = &unit->eu_RequestPorts[EVENT_QUEUE]->mp_MsgList;
251 next_request = (APTR)list->lh_Head;
252 tail = (APTR)&list->lh_Tail;
254 /* Go through list of event listeners. If send messages to receivers if event found */
255 Disable();
256 while(next_request != tail)
258 request = next_request;
259 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
261 if((request->ios2_WireError&events) != 0)
263 request->ios2_WireError = events;
264 Remove((APTR)request);
265 ReplyMsg((APTR)request);
268 Enable();
270 return;
273 VOID CopyPacket(struct EMACBase *EMACBase, struct EMACUnit *unit,
274 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
275 struct eth_frame *buffer)
277 struct Opener *opener;
278 BOOL filtered = FALSE;
279 UBYTE *ptr;
281 D(bug("[EMAC%d] CopyPacket(packet @ %x, len = %d)\n", unit->eu_UnitNum, buffer, packet_size));
283 /* Set multicast and broadcast flags */
285 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
286 if((*((ULONG *)(buffer->eth_packet_dest)) == 0xffffffff) &&
287 (*((UWORD *)(buffer->eth_packet_dest + 4)) == 0xffff))
289 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
290 D(bug("[EMAC%d] CopyPacket: BROADCAST Flag set\n", unit->eu_UnitNum));
292 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
294 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
295 D(bug("[EMAC%d] CopyPacket: MULTICAST Flag set\n", unit->eu_UnitNum));
298 /* Set source and destination addresses and packet type */
299 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
300 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
301 request->ios2_PacketType = packet_type;
303 /* Adjust for cooked packet request */
305 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
307 packet_size -= ETH_PACKET_DATA;
308 ptr = (UBYTE*)&buffer->eth_packet_data[0];
310 else
312 ptr = (UBYTE*)buffer;
315 request->ios2_DataLength = packet_size;
316 D(bug("[EMAC%d] CopyPacket: packet @ %x (%d bytes)\n", unit->eu_UnitNum, ptr, packet_size));
318 /* Filter packet */
320 opener = request->ios2_BufferManagement;
321 if((request->ios2_Req.io_Command == CMD_READ) &&
322 (opener->filter_hook != NULL))
323 if(!CallHookPkt(opener->filter_hook, request, ptr))
325 D(bug("[EMAC%d] CopyPacket: packet filtered\n", unit->eu_UnitNum));
326 filtered = TRUE;
329 if(!filtered)
331 /* Copy packet into opener's buffer and reply packet */
332 D(bug("[EMAC%d] CopyPacket: opener recieve packet .. ", unit->eu_UnitNum));
333 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
335 D(bug("ERROR occured!!\n"));
336 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
337 request->ios2_WireError = S2WERR_BUFF_ERROR;
338 ReportEvents(EMACBase, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
340 else
342 D(bug("SUCCESS!!\n"));
344 Disable();
345 Remove((APTR)request);
346 Enable();
347 ReplyMsg((APTR)request);
348 D(bug("[EMAC%d] CopyPacket: opener notified.\n", unit->eu_UnitNum));
352 BOOL AddressFilter(struct EMACBase *EMACBase, struct EMACUnit *unit, UBYTE *address)
354 struct AddressRange *range, *tail;
355 BOOL accept = TRUE;
356 ULONG address_left;
357 UWORD address_right;
359 /* Check whether address is unicast/broadcast or multicast */
361 address_left = AROS_BE2LONG(*((ULONG *)address));
362 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
364 if((address_left & 0x01000000) != 0 &&
365 !(address_left == 0xffffffff && address_right == 0xffff))
367 /* Check if this multicast address is wanted */
369 range = (APTR)unit->eu_MulticastRanges.mlh_Head;
370 tail = (APTR)&unit->eu_MulticastRanges.mlh_Tail;
371 accept = FALSE;
373 while((range != tail) && !accept)
375 if((address_left > range->lower_bound_left ||
376 (address_left == range->lower_bound_left &&
377 address_right >= range->lower_bound_right)) &&
378 (address_left < range->upper_bound_left ||
379 (address_left == range->upper_bound_left &&
380 address_right <= range->upper_bound_right)))
381 accept = TRUE;
382 range = (APTR)range->node.mln_Succ;
384 if(!accept)
385 unit->eu_SpecialStats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
387 return accept;
390 void rx_int(struct EMACUnit *unit, struct ExecBase *SysBase)
392 mal_descriptor_t descr;
393 int i;
394 int last_slot = unit->eu_LastRXSlot;
395 struct TypeStats *tracker;
396 ULONG packet_type;
397 struct Opener *opener, *opener_tail;
398 struct IOSana2Req *request, *request_tail;
399 BOOL accepted, is_orphan;
402 D(bug("[EMAC%d] RX Int\n", unit->eu_UnitNum));
403 D(bug("[EMAC%d] Starting at packet %d", unit->eu_UnitNum, (unit->eu_LastRXSlot + 1) % RX_RING_SIZE));
404 for (i=1; i <= RX_RING_SIZE; i++)
406 int packet_pos = ((i + last_slot) % RX_RING_SIZE) >> 2 ;
407 int sub_pos = ((i + last_slot) % RX_RING_SIZE) % 4;
408 mal_packet_t mal_packet;
410 /* Invalidate each cache line - four mal descriptors at once - the very special case is
411 * the first run of interrupt handler - it has to fetch the cache line unconditionally */
412 if (!sub_pos || i == 1)
414 /* Invalidate memory containing MAL descriptor */
415 CacheClearE(&unit->eu_RXChannel[packet_pos], sizeof(mal_packet), CACRF_InvalidateD);
416 mal_packet = unit->eu_RXChannel[packet_pos];
419 /* Work on local descriptor's copy */
420 descr = mal_packet.descr[sub_pos];
422 if (!(descr.md_ctrl & MAL_CTRL_RX_E))
424 struct eth_frame *frame;
425 is_orphan = TRUE;
427 unit->eu_LastRXSlot = (packet_pos << 2) + sub_pos;
429 D(bug("[EMAC%d] MAL descriptor %d filled with %d bytes\n", unit->eu_UnitNum, (packet_pos << 2) + sub_pos, descr.md_length));
431 /* Invalidate memory containing MAL descriptor */
432 CacheClearE(descr.md_buffer, descr.md_length, CACRF_InvalidateD);
433 frame = (struct eth_frame *)descr.md_buffer;
435 /* Dump contents of frame if DEBUG enabled */
437 int j;
438 for (j=0; j<64; j++) {
439 if ((j%16) == 0)
440 D(bug("\n%03x:", j));
441 D(bug(" %02x", ((unsigned char*)frame)[j]));
443 D(bug("\n"));
446 /* Check for address validity */
447 if(AddressFilter(unit->eu_EMACBase, unit, frame->eth_packet_dest))
449 /* Packet is addressed to this driver */
450 packet_type = frame->eth_packet_type;
451 D(bug("[EMAC%d] Packet IP accepted with type = %d\n", unit->eu_UnitNum, packet_type));
453 opener = (APTR)unit->eu_Openers.mlh_Head;
454 opener_tail = (APTR)&unit->eu_Openers.mlh_Tail;
455 /* Offer packet to every opener */
457 while(opener != opener_tail)
459 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
460 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
461 accepted = FALSE;
463 /* Offer packet to each request until it's accepted */
464 while((request != request_tail) && !accepted)
466 if((request->ios2_PacketType == packet_type)
467 || ((request->ios2_PacketType <= ETH_MTU)
468 && (packet_type <= ETH_MTU)))
470 D(bug("[EMAC%d] copy packet for opener ..\n", unit->eu_UnitNum));
471 CopyPacket(unit->eu_EMACBase, unit, request, descr.md_length, packet_type, frame);
472 accepted = TRUE;
474 request =
475 (struct IOSana2Req *)request->ios2_Req.io_Message.mn_Node.ln_Succ;
478 if(accepted)
479 is_orphan = FALSE;
481 opener = (APTR)opener->node.mln_Succ;
484 /* If packet was unwanted, give it to S2_READORPHAN request */
485 if(is_orphan)
487 unit->eu_Stats.UnknownTypesReceived++;
489 if(!IsMsgPortEmpty(unit->eu_RequestPorts[ADOPT_QUEUE]))
491 CopyPacket(unit->eu_EMACBase, unit,
492 (APTR)unit->eu_RequestPorts[ADOPT_QUEUE]->
493 mp_MsgList.lh_Head, descr.md_length, packet_type, frame);
494 D(bug("[EMAC%d] packet copied to orphan queue\n", unit->eu_UnitNum));
498 /* Update remaining statistics */
500 tracker =
501 FindTypeStats(unit->eu_EMACBase, unit, &unit->eu_TypeTrackers, packet_type);
502 if(tracker != NULL)
504 tracker->stats.PacketsReceived++;
505 tracker->stats.BytesReceived += descr.md_length;
510 /* Set the descriptor back as free */
511 descr.md_ctrl |= MAL_CTRL_RX_E;
512 descr.md_length = 0;
514 /* Save local copy and flush data cache */
515 /* Invalidate memory containing MAL descriptor */
516 CacheClearE(&unit->eu_RXChannel[packet_pos], sizeof(mal_packet), CACRF_InvalidateD);
517 mal_packet = unit->eu_RXChannel[packet_pos];
519 mal_packet.descr[sub_pos] = descr;
520 unit->eu_RXChannel[packet_pos] = mal_packet;
521 CacheClearE(&unit->eu_RXChannel[packet_pos], sizeof(mal_packet), CACRF_ClearD);
526 static
527 AROS_UFH3(void, EMAC_RX_Int,
528 AROS_UFHA(struct EMACUnit *, unit, A1),
529 AROS_UFHA(APTR, dummy, A5),
530 AROS_UFHA(struct ExecBase *, SysBase, A6))
532 AROS_USERFUNC_INIT
534 D(bug("[EMAC%d] RX Int\n", unit->eu_UnitNum));
535 rx_int(unit, SysBase);
537 AROS_USERFUNC_EXIT
540 void tx_int(struct EMACUnit *unit, struct ExecBase *SysBase)
542 struct EMACBase *EMACBase = unit->eu_EMACBase;
543 mal_descriptor_t descr;
544 int nr, try_count = 1;
545 int last_slot = unit->eu_LastTXSlot;
546 UWORD packet_size, data_size;
547 struct IOSana2Req *request;
548 struct Opener *opener;
549 UBYTE *buffer;
550 ULONG wire_error=0;
551 BYTE error;
552 struct MsgPort *port;
553 struct TypeStats *tracker;
554 int packet_pos;
555 int sub_pos;
556 BOOL proceed = TRUE; /* Success by default */
558 port = unit->eu_RequestPorts[WRITE_QUEUE];
560 D(bug("[EMAC%d] TX Int\n", unit->eu_UnitNum));
561 D(bug("[EMAC%d] Starting at packet %d\d", unit->eu_UnitNum, (last_slot + 1) % TX_RING_SIZE));
563 // for (nr=0; nr < TX_RING_SIZE; nr++)
564 // {
565 // CacheClearE(&unit->eu_TXChannel[nr>>2], sizeof(mal_packet_t), CACRF_InvalidateD);
566 // D(bug("%04x ",unit->eu_TXChannel[nr>>2].descr[nr%4].md_ctrl));
567 // }
568 /* Still no error and there are packets to be sent? */
569 while(proceed && (!IsMsgPortEmpty(port)))
571 mal_packet_t mal_packet;
573 nr = (last_slot + 1) % TX_RING_SIZE;
575 packet_pos = nr >> 2 ;
576 sub_pos = nr % 4;
578 error = 0;
580 /* Invalidate memory containing MAL descriptor */
581 CacheClearE(&unit->eu_TXChannel[packet_pos], sizeof(mal_packet), CACRF_InvalidateD);
582 mal_packet = unit->eu_TXChannel[packet_pos];
583 /* Work on local descriptor's copy */
584 descr = mal_packet.descr[sub_pos];
586 if (!(descr.md_ctrl & MAL_CTRL_TX_R))
588 struct eth_frame *eth = (struct eth_frame *)descr.md_buffer;
589 request = (APTR)port->mp_MsgList.lh_Head;
590 data_size = packet_size = request->ios2_DataLength;
592 opener = (APTR)request->ios2_BufferManagement;
594 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
596 packet_size += ETH_PACKET_DATA;
597 CopyMem(request->ios2_DstAddr, eth->eth_packet_dest, ETH_ADDRESSSIZE);
598 CopyMem(unit->eu_DevAddr, eth->eth_packet_source, ETH_ADDRESSSIZE);
599 eth->eth_packet_type = request->ios2_PacketType;
601 buffer = eth->eth_packet_data;
603 else
604 buffer = descr.md_buffer;
606 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
608 error = S2ERR_NO_RESOURCES;
609 wire_error = S2WERR_BUFF_ERROR;
610 ReportEvents(EMACBase, unit,
611 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
612 | S2EVENT_TX);
615 if (error == 0)
617 D(bug("[EMAC%d] packet %d:%d [type = %d] queued for transmission.", unit->eu_UnitNum, last_slot, nr, eth->eth_packet_type));
619 /* Dump contents of frame if DEBUG enabled */
621 int j;
622 for (j=0; j<64; j++) {
623 if ((j%16) == 0)
624 D(bug("\n%03x:", j));
625 D(bug(" %02x", ((unsigned char*)eth)[j]));
627 D(bug("\n"));
630 /* Update the descriptor */
631 descr.md_length = packet_size;
632 descr.md_ctrl |= MAL_CTRL_TX_R | MAL_CTRL_TX_I | MAL_CTRL_TX_L | EMAC_CTRL_TX_GFCS | EMAC_CTRL_TX_GP;
633 CacheClearE(descr.md_buffer, descr.md_length, CACRF_ClearD);
635 CacheClearE(&unit->eu_TXChannel[packet_pos], sizeof(mal_packet), CACRF_InvalidateD);
636 mal_packet = unit->eu_TXChannel[packet_pos];
637 mal_packet.descr[sub_pos] = descr;
638 unit->eu_TXChannel[packet_pos] = mal_packet;
639 CacheClearE(&unit->eu_TXChannel[packet_pos], sizeof(mal_packet), CACRF_ClearD);
642 /* Reply packet */
644 request->ios2_Req.io_Error = error;
645 request->ios2_WireError = wire_error;
646 Disable();
647 Remove((APTR)request);
648 Enable();
649 ReplyMsg((APTR)request);
651 /* Update statistics */
653 if(error == 0)
655 tracker = FindTypeStats(EMACBase, unit, &unit->eu_TypeTrackers,
656 request->ios2_PacketType);
657 if(tracker != NULL)
659 tracker->stats.PacketsSent++;
660 tracker->stats.BytesSent += packet_size;
663 try_count=0;
666 unit->eu_LastTXSlot = ++last_slot;
667 try_count++;
670 * If we've just run out of free space on the TX queue, stop
671 * it and give up pushing further frames
673 if ( (try_count + 1) >= TX_RING_SIZE)
675 D(bug("[EMAC%d] output queue full!. Stopping [count = %d, TX_RING_SIZE = %d\n", unit->eu_UnitNum, try_count, TX_RING_SIZE));
676 proceed = FALSE;
680 /* Tell EMAC that it has new packets to process */
681 outl(inl(EMAC_TXM0 + unit->eu_IOBase) | EMAC_TXM0_GNP0, EMAC_TXM0 + unit->eu_IOBase);
683 /* Was there success? Enable incomming of new packets */
684 if(proceed)
685 unit->eu_RequestPorts[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
686 else
687 unit->eu_RequestPorts[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
691 static
692 AROS_UFH3(void, EMAC_TX_Int,
693 AROS_UFHA(struct EMACUnit *, unit, A1),
694 AROS_UFHA(APTR, dummy, A5),
695 AROS_UFHA(struct ExecBase *, SysBase, A6))
697 AROS_USERFUNC_INIT
699 D(bug("[EMAC%d] TX Int\n", unit->eu_UnitNum));
700 tx_int(unit, SysBase);
702 AROS_USERFUNC_EXIT
705 static
706 AROS_UFH3(void, EMAC_TXEnd_Int,
707 AROS_UFHA(struct EMACUnit *, unit, A1),
708 AROS_UFHA(APTR, dummy, A5),
709 AROS_UFHA(struct ExecBase *, SysBase, A6))
711 AROS_USERFUNC_INIT
713 D(bug("[EMAC%d] TX End Int\n", unit->eu_UnitNum));
715 AROS_USERFUNC_EXIT
718 struct TypeStats *FindTypeStats(struct EMACBase *EMACBase, struct EMACUnit *unit,
719 struct MinList *list, ULONG packet_type)
721 struct TypeStats *stats, *tail;
722 BOOL found = FALSE;
724 stats = (APTR)list->mlh_Head;
725 tail = (APTR)&list->mlh_Tail;
727 while(stats != tail && !found)
729 if(stats->packet_type == packet_type)
730 found = TRUE;
731 else
732 stats = (APTR)stats->node.mln_Succ;
735 if(!found)
736 stats = NULL;
738 return stats;
741 static
742 AROS_UFH3(void, EMAC_UnitProcess,
743 AROS_UFHA(char *, argPtr, A0),
744 AROS_UFHA(ULONG, argSize, D0),
745 AROS_UFHA(struct ExecBase *, SysBase, A6))
747 AROS_USERFUNC_INIT
749 struct MsgPort *iport;
750 struct EMACUnit *unit = (struct EMACUnit *)(FindTask(NULL)->tc_UserData);
751 struct Process *parent = unit->eu_Process;
753 unit->eu_Process = (struct Process *)FindTask(NULL);
755 D(bug("[EMAC%d] Hello there.\n", unit->eu_UnitNum));
756 D(bug("[EMAC%d] Process @ %p\n", unit->eu_UnitNum, unit->eu_Process));
758 unit->eu_Flags = 0;
759 unit->eu_OpenCount = 0;
760 unit->eu_RangeCount = 0;
762 iport = CreateMsgPort();
764 unit->eu_InputPort = iport;
766 unit->eu_TimerPort.mp_SigBit = SIGB_SINGLE;
767 unit->eu_TimerPort.mp_Flags = PA_SIGNAL;
768 unit->eu_TimerPort.mp_SigTask = FindTask(NULL);
769 unit->eu_TimerPort.mp_Node.ln_Type = NT_MSGPORT;
770 NEWLIST(&unit->eu_TimerPort.mp_MsgList);
772 unit->eu_TimerRequest.tr_node.io_Message.mn_ReplyPort = &unit->eu_TimerPort;
773 unit->eu_TimerRequest.tr_node.io_Message.mn_Length = sizeof(unit->eu_TimerRequest);
775 OpenDevice((STRPTR)"timer.device", UNIT_MICROHZ, (struct IORequest *)&unit->eu_TimerRequest, 0);
777 EMAC_Startup(unit);
779 Signal(parent, SIGF_SINGLE);
781 do {
782 uint32_t sigset = 1 << iport->mp_SigBit |
783 SIGBREAKF_CTRL_C;
785 uint32_t rcvd = Wait(sigset);
787 if (rcvd & SIGBREAKF_CTRL_C)
789 D(bug("[EMAC%d] CTRL_C signal\n", unit->eu_UnitNum));
791 else if (rcvd & (1 << iport->mp_SigBit))
793 struct IOSana2Req *io;
795 /* Handle incoming transactions */
796 while ((io = (struct IOSana2Req *)GetMsg(iport))!= NULL);
798 D(bug("[EMAC%d] Handle incomming transaction.\n", unit->eu_UnitNum));
799 ObtainSemaphore(&unit->eu_Lock);
800 handle_request(unit->eu_EMACBase, io);
804 } while(1);
806 AROS_USERFUNC_EXIT
809 static const struct UnitInfo {
810 uint8_t ui_IrqNum;
811 char *ui_TaskName;
812 intptr_t ui_IOBase;
813 uint8_t ui_PHYAddr;
814 } EMAC_Units[2] = {
815 { INTR_ETH0, EMAC_TASK1_NAME, EMAC0_BASE, 24 },
816 { INTR_ETH1, EMAC_TASK2_NAME, EMAC1_BASE, 25 },
819 struct EMACUnit *CreateUnit(struct EMACBase *EMACBase, uint8_t num)
821 void *KernelBase = OpenResource("kernel.resource");
823 D(bug("[EMAC ] CreateUnit(%d)\n", num));
825 struct EMACUnit *unit = AllocPooled(EMACBase->emb_Pool, sizeof(struct EMACUnit));
827 if (unit)
829 int i;
831 InitSemaphore(&unit->eu_Lock);
833 NEWLIST(&unit->eu_Openers);
834 NEWLIST(&unit->eu_MulticastRanges);
835 NEWLIST(&unit->eu_TypeTrackers);
837 unit->eu_UnitNum = num;
838 unit->eu_IRQHandler = KrnAddIRQHandler(EMAC_Units[num].ui_IrqNum, EMACIRQHandler, EMACBase, unit);
839 unit->eu_EMACBase = EMACBase;
840 unit->eu_IOBase = EMAC_Units[num].ui_IOBase;
841 unit->eu_PHYAddr = EMAC_Units[num].ui_PHYAddr;
842 unit->eu_MTU = ETH_MTU;
844 unit->eu_LastTXSlot = TX_RING_SIZE - 1;
845 unit->eu_LastRXSlot = RX_RING_SIZE - 1;
847 unit->start = EMAC_Start;
848 unit->stop = EMAC_Stop;
849 unit->set_mac_address = EMAC_SetMacAddress;
850 unit->udelay = EMAC_UDelay;
852 unit->eu_RXInt.is_Node.ln_Name = "EMAC RX Int";
853 unit->eu_RXInt.is_Code = EMAC_RX_Int;
854 unit->eu_RXInt.is_Data = unit;
856 unit->eu_TXInt.is_Node.ln_Name = "EMAC TX Int";
857 unit->eu_TXInt.is_Code = EMAC_TX_Int;
858 unit->eu_TXInt.is_Data = unit;
860 unit->eu_TXEndInt.is_Node.ln_Name = "EMAC TX Int";
861 unit->eu_TXEndInt.is_Code = EMAC_TXEnd_Int;
862 unit->eu_TXEndInt.is_Data = unit;
864 unit->eu_RXChannel = (mal_packet_t *)EMACBase->emb_MALRXChannels[num];
865 unit->eu_TXChannel = (mal_packet_t *)EMACBase->emb_MALTXChannels[num];
866 //unit->eu_TXChannel[1] = (mal_packet_t *)EMACBase->emb_MALTXChannels[2*num+1];
868 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
870 struct MsgPort *port = AllocPooled(EMACBase->emb_Pool, sizeof(struct MsgPort));
871 unit->eu_RequestPorts[i] = port;
873 if (port)
875 NEWLIST(&port->mp_MsgList);
876 port->mp_Flags = PA_IGNORE;
877 port->mp_SigTask = &unit->eu_TXInt;
881 unit->eu_RequestPorts[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
883 /* Create the unit's process */
885 /* Unit's process pointer will temporarly contain the parent */
886 unit->eu_Process = FindTask(NULL);
887 CreateNewProcTags(
888 NP_Entry, (IPTR)EMAC_UnitProcess,
889 NP_Name, EMAC_Units[num].ui_TaskName,
890 NP_Priority, 0,
891 NP_UserData, (IPTR)unit,
892 NP_StackSize, 40960,
893 TAG_DONE);
895 /* Wait for synchronisation signal */
896 Wait(SIGF_SINGLE);
898 D(bug("[EMAC ] Unit %d up and running\n", num));
901 return unit;
904 static struct AddressRange *FindMulticastRange(struct EMACBase *EMACBase, struct EMACUnit *unit,
905 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
907 struct AddressRange *range, *tail;
908 BOOL found = FALSE;
910 range = (APTR)unit->eu_MulticastRanges.mlh_Head;
911 tail = (APTR)&unit->eu_MulticastRanges.mlh_Tail;
913 while((range != tail) && !found)
915 if((lower_bound_left == range->lower_bound_left) &&
916 (lower_bound_right == range->lower_bound_right) &&
917 (upper_bound_left == range->upper_bound_left) &&
918 (upper_bound_right == range->upper_bound_right))
919 found = TRUE;
920 else
921 range = (APTR)range->node.mln_Succ;
924 if(!found)
925 range = NULL;
927 return range;
930 BOOL AddMulticastRange(struct EMACBase *EMACBase, struct EMACUnit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
932 struct AddressRange *range;
933 ULONG lower_bound_left, upper_bound_left;
934 UWORD lower_bound_right, upper_bound_right;
936 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
937 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
938 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
939 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
941 range = FindMulticastRange(EMACBase, unit, lower_bound_left, lower_bound_right,
942 upper_bound_left, upper_bound_right);
944 if(range != NULL)
945 range->add_count++;
946 else
948 range = AllocPooled(EMACBase->emb_Pool, sizeof(struct AddressRange));
949 if(range != NULL)
951 range->lower_bound_left = lower_bound_left;
952 range->lower_bound_right = lower_bound_right;
953 range->upper_bound_left = upper_bound_left;
954 range->upper_bound_right = upper_bound_right;
955 range->add_count = 1;
957 Disable();
958 AddTail((APTR)&unit->eu_MulticastRanges, (APTR)range);
959 Enable();
961 if (unit->eu_RangeCount++ == 0)
963 unit->eu_Flags |= IFF_ALLMULTI;
964 unit->set_multicast(unit);
969 return range != NULL;
972 BOOL RemMulticastRange(struct EMACBase *EMACBase, struct EMACUnit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
974 struct AddressRange *range;
975 ULONG lower_bound_left, upper_bound_left;
976 UWORD lower_bound_right, upper_bound_right;
978 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
979 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
980 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
981 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
983 range = FindMulticastRange(EMACBase, unit, lower_bound_left, lower_bound_right,
984 upper_bound_left, upper_bound_right);
986 if(range != NULL)
988 if(--range->add_count == 0)
990 Disable();
991 Remove((APTR)range);
992 Enable();
993 FreePooled(EMACBase->emb_Pool, range, sizeof(struct AddressRange));
995 if (--unit->eu_RangeCount == 0)
997 unit->eu_Flags &= ~IFF_ALLMULTI;
998 unit->set_multicast(unit);
1002 return range != NULL;