]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/network/drvPPCUniN/UniNEnet.cpp
958fbb6b4613073bacf6b0a601c2bad489e4cb2a
[apple/xnu.git] / iokit / Drivers / network / drvPPCUniN / UniNEnet.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1998-1999 Apple Computer
24 *
25 * Hardware independent (relatively) code for the Sun GEM Ethernet Controller
26 *
27 * HISTORY
28 *
29 * dd-mmm-yy
30 * Created.
31 *
32 */
33
34 //void call_kdp(void);
35
36 #include "UniNEnetPrivate.h"
37
38 #define super IOEthernetController
39
40 OSDefineMetaClassAndStructors( UniNEnet, IOEthernetController )
41
42 /*-------------------------------------------------------------------------
43 *
44 *
45 *
46 *-------------------------------------------------------------------------*/
47
48 bool UniNEnet::init(OSDictionary * properties)
49 {
50 if ( super::init(properties) == false )
51 return false;
52
53 /*
54 * Initialize my ivars.
55 */
56 phyId = 0xff;
57 linkStatusPrev = kLinkStatusUnknown;
58
59 return true;
60 }
61
62 /*-------------------------------------------------------------------------
63 *
64 *
65 *
66 *-------------------------------------------------------------------------*/
67
68 bool UniNEnet::start(IOService * provider)
69 {
70 OSString *matchEntry;
71
72 keyLargo_resetUniNEthernetPhy = OSSymbol::withCString("keyLargo_resetUniNEthernetPhy");
73
74 // Wait for KeyLargo to show up.
75 keyLargo = waitForService(serviceMatching("KeyLargo"));
76 if (keyLargo == 0) return false;
77
78 nub = OSDynamicCast(IOPCIDevice, provider);
79
80 if (!nub || !super::start(provider))
81 {
82 return false;
83 }
84
85 // Create spinlock to protect TxElementQueue.
86
87 txQueueLock = IOSimpleLockAlloc();
88 if ( txQueueLock == 0 ) return false;
89 IOSimpleLockInit(txQueueLock);
90
91 transmitQueue = (IOGatedOutputQueue *) getOutputQueue();
92 if (!transmitQueue)
93 {
94 IOLog("Ethernet(UniN): Output queue initialization failed\n");
95 return false;
96 }
97 transmitQueue->retain();
98
99 /*
100 * Allocate debug queue. This stores packets retired from the TX ring
101 * by the polling routine. We cannot call freePacket() or m_free() within
102 * the debugger context.
103 *
104 * The capacity of the queue is set at maximum to prevent the queue from
105 * calling m_free() due to over-capacity. But we don't expect the size
106 * of the queue to grow too large.
107 */
108 debugQueue = IOPacketQueue::withCapacity((UInt) -1);
109 if (!debugQueue)
110 {
111 return false;
112 }
113
114 /*
115 * Allocate a IOMbufBigMemoryCursor instance. Currently, the maximum
116 * number of segments is set to 1. The maximum length for each segment
117 * is set to the maximum ethernet frame size (plus padding).
118 */
119 mbufCursor = IOMbufBigMemoryCursor::withSpecification(NETWORK_BUFSIZE, 1);
120 if (!mbufCursor)
121 {
122 IOLog("Ethernet(UniN): IOMbufBigMemoryCursor allocation failure\n");
123 return false;
124 }
125
126 matchEntry = OSDynamicCast( OSString, getProperty( gIONameMatchedKey ) );
127 if ( matchEntry == 0 )
128 {
129 IOLog("Ethernet(UniN): Cannot obtain matching property.\n");
130 return false;
131 }
132
133 if ( matchEntry->isEqualTo( "gmac" ) == true )
134 {
135 callPlatformFunction("EnableUniNEthernetClock", true,
136 (void *)true, 0, 0, 0);
137 }
138
139 /*
140 * BUS MASTER, MEM I/O Space, MEM WR & INV
141 */
142 nub->configWrite32( 0x04, 0x16 );
143
144 /*
145 * set Latency to Max , cache 32
146 */
147 nub->configWrite32( 0x0C, ((2 + (kGEMBurstSize * (0+1)))<< 8) | (CACHE_LINE_SIZE >> 2) );
148
149 ioMapEnet = nub->mapDeviceMemoryWithRegister( 0x10 );
150 if ( ioMapEnet == NULL )
151 {
152 return false;
153 }
154 ioBaseEnet = (volatile IOPPCAddress)ioMapEnet->getVirtualAddress();
155 fpRegs = (GMAC_Registers*) ioBaseEnet;
156 phyId = (UInt8) -1;
157
158 /*
159 * Get a reference to the IOWorkLoop in our superclass.
160 */
161 IOWorkLoop * myWorkLoop = getWorkLoop();
162
163 /*
164 * Allocate three IOInterruptEventSources.
165 */
166 interruptSource = IOInterruptEventSource::interruptEventSource(
167 (OSObject *) this,
168 (IOInterruptEventAction) &UniNEnet::interruptOccurred,
169 (IOService *) provider,
170 (int) 0 );
171
172 if ( interruptSource == NULL )
173 {
174 IOLog("Ethernet(UniN): Couldn't allocate Interrupt event source\n");
175 return false;
176 }
177
178 if ( myWorkLoop->addEventSource( interruptSource ) != kIOReturnSuccess )
179 {
180 IOLog("Ethernet(UniN): Couldn't add Interrupt event source\n");
181 return false;
182 }
183
184
185 timerSource = IOTimerEventSource::timerEventSource
186 (this, (IOTimerEventSource::Action) &UniNEnet::timeoutOccurred);
187 if ( timerSource == NULL )
188 {
189 IOLog("Ethernet(UniN): Couldn't allocate timer event source\n");
190 return false;
191 }
192
193 if ( myWorkLoop->addEventSource( timerSource ) != kIOReturnSuccess )
194 {
195 IOLog("Ethernet(UniN): Couldn't add timer event source\n");
196 return false;
197 }
198
199 MGETHDR(txDebuggerPkt, M_DONTWAIT, MT_DATA);
200
201 if (!txDebuggerPkt)
202 {
203 IOLog("Ethernet(UniN): Couldn't allocate KDB buffer\n");
204 return false;
205 }
206
207 /*
208 * Perform a hardware reset.
209 */
210 if ( resetAndEnable(false) == false )
211 {
212 IOLog("Ethernet(UniN): resetAndEnable() failed\n");
213 return false;
214 }
215
216 /*
217 * Cache my MAC address.
218 */
219 if ( getHardwareAddress(&myAddress) != kIOReturnSuccess )
220 {
221 IOLog("Ethernet(UniN): getHardwareAddress() failed\n");
222 return false;
223 }
224
225 /*
226 * Allocate memory for ring buffers.
227 */
228 if ( allocateMemory() == false)
229 {
230 IOLog("Ethernet(UniN): allocateMemory() failed\n");
231 return false;
232 }
233
234 if ( createMediumTables() == false )
235 {
236 IOLog("Ethernet(UniN): createMediumTables() failed\n");
237 return false;
238 }
239
240 /*
241 * Attach an IOEthernetInterface client. But don't registers it just yet.
242 */
243 if ( !attachInterface((IONetworkInterface **) &networkInterface, false) )
244 {
245 IOLog("Ethernet(UniN): attachInterface() failed\n");
246 return false;
247 }
248
249 /*
250 * Attach a kernel debugger client.
251 */
252 attachDebuggerClient(&debugger);
253
254 /*
255 * Ready to service interface requests.
256 */
257 networkInterface->registerService();
258
259 return true;
260 }
261
262 /*-------------------------------------------------------------------------
263 *
264 *
265 *
266 *-------------------------------------------------------------------------*/
267
268 bool UniNEnet::configureInterface(IONetworkInterface * netif)
269 {
270 IONetworkData * nd;
271
272 if ( super::configureInterface( netif ) == false )
273 return false;
274
275 /*
276 * Grab a pointer to the statistics structure in the interface.
277 */
278 nd = netif->getNetworkData( kIONetworkStatsKey );
279 if (!nd || !(fpNetStats = (IONetworkStats *) nd->getBuffer()))
280 {
281 IOLog("EtherNet(UniN): invalid network statistics\n");
282 return false;
283 }
284
285 // Get the Ethernet statistics structure:
286 nd = netif->getParameter( kIOEthernetStatsKey );
287 if ( !nd || !(fpEtherStats = (IOEthernetStats*)nd->getBuffer()) )
288 {
289 IOLog("EtherNet(UniN): invalid ethernet statistics\n");
290 return false;
291 }
292
293 /*
294 * Set the driver/stack reentrancy flag. This is meant to reduce
295 * context switches. May become irrelevant in the future.
296 */
297 return true;
298 }/* end configureInterface */
299
300
301 /*-------------------------------------------------------------------------
302 *
303 *
304 *
305 *-------------------------------------------------------------------------*/
306
307 void UniNEnet::free()
308 {
309 TxQueueElement * txElement;
310
311 resetAndEnable(false);
312
313 if (debugger)
314 debugger->release();
315
316 if (getWorkLoop())
317 {
318 getWorkLoop()->disableAllEventSources();
319 }
320
321 if (timerSource)
322 {
323 timerSource->release();
324 timerSource = 0;
325 }
326
327 if (interruptSource)
328 {
329 interruptSource->release();
330 }
331
332 if (txDebuggerPkt)
333 {
334 freePacket(txDebuggerPkt);
335 }
336
337 if (transmitQueue)
338 {
339 transmitQueue->release();
340 }
341
342 if (debugQueue)
343 {
344 debugQueue->release();
345 }
346
347 if (networkInterface)
348 {
349 networkInterface->release();
350 }
351
352 if (mbufCursor)
353 {
354 mbufCursor->release();
355 }
356
357 if ( mediumDict )
358 {
359 mediumDict->release();
360 }
361
362 while ( ( txElement = getTxElement() ) )
363 {
364 IOFree( txElement, sizeof(TxQueueElement) );
365 }
366
367 if ( ioMapEnet )
368 {
369 ioMapEnet->release();
370 }
371
372 if ( dmaCommands != 0 )
373 {
374 IOFreeContiguous( (void *)dmaCommands, dmaCommandsSize );
375 }
376
377 if ( workLoop )
378 {
379 workLoop->release();
380 workLoop = 0;
381 }
382
383 if ( txQueueLock )
384 {
385 IOSimpleLockFree( txQueueLock );
386 txQueueLock = 0;
387 }
388
389 super::free();
390 }
391
392 /*-------------------------------------------------------------------------
393 * Override IONetworkController::createWorkLoop() method and create
394 * a workloop.
395 *
396 *-------------------------------------------------------------------------*/
397
398 bool UniNEnet::createWorkLoop()
399 {
400 workLoop = IOWorkLoop::workLoop();
401
402 return ( workLoop != 0 );
403 }
404
405 /*-------------------------------------------------------------------------
406 * Override IOService::getWorkLoop() method to return our workloop.
407 *
408 *
409 *-------------------------------------------------------------------------*/
410
411 IOWorkLoop * UniNEnet::getWorkLoop() const
412 {
413 return workLoop;
414 }
415
416 /*-------------------------------------------------------------------------
417 *
418 *
419 *
420 *-------------------------------------------------------------------------*/
421
422 void UniNEnet::interruptOccurred(IOInterruptEventSource * src, int /*count*/)
423 {
424 IODebuggerLockState lockState;
425 UInt32 interruptStatus;
426 bool doFlushQueue;
427 bool doService;
428
429
430 if ( ready == false ) return;
431
432 do
433 {
434 lockState = IODebuggerLock( this );
435
436 interruptStatus = READ_REGISTER( Status )
437 & ( kStatus_TX_INT_ME | kStatus_RX_DONE );
438
439 doService = false;
440
441 if ( interruptStatus & kStatus_TX_INT_ME )
442 {
443 txWDInterrupts++;
444 KERNEL_DEBUG(DBG_GEM_TXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
445 doService = transmitInterruptOccurred();
446 KERNEL_DEBUG(DBG_GEM_TXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
447 ETHERNET_STAT_ADD( dot3TxExtraEntry.interrupts );
448 }
449
450 doFlushQueue = false;
451
452 if ( interruptStatus & kStatus_RX_DONE )
453 {
454 rxWDInterrupts++;
455 KERNEL_DEBUG(DBG_GEM_RXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
456 doFlushQueue = receiveInterruptOccurred();
457 KERNEL_DEBUG(DBG_GEM_RXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
458 ETHERNET_STAT_ADD( dot3RxExtraEntry.interrupts );
459 }
460
461 IODebuggerUnlock( lockState );
462
463 /*
464 * Submit all received packets queued up by _receiveInterruptOccurred()
465 * to the network stack. The up call is performed without holding the
466 * debugger lock.
467 */
468 if (doFlushQueue)
469 {
470 networkInterface->flushInputQueue();
471 }
472
473 /*
474 * Make sure the output queue is not stalled.
475 */
476 if (doService && netifEnabled)
477 {
478 transmitQueue->service();
479 }
480 }
481 while ( interruptStatus );
482
483 // interruptSource->enable();
484 return;
485 }/* end interruptOccurred */
486
487
488 /*-------------------------------------------------------------------------
489 *
490 *
491 *
492 *-------------------------------------------------------------------------*/
493
494 UInt32 UniNEnet::outputPacket(struct mbuf * pkt, void * param)
495 {
496 UInt32 ret = kIOReturnOutputSuccess;
497
498 KERNEL_DEBUG( DBG_GEM_TXQUEUE | DBG_FUNC_NONE,
499 (int) pkt, (int) pkt->m_pkthdr.len, 0, 0, 0 );
500
501 /*
502 * Hold the debugger lock so the debugger can't interrupt us
503 */
504 reserveDebuggerLock();
505
506 if ( linkStatusPrev != kLinkStatusUp )
507 {
508 freePacket( pkt );
509 }
510 else if ( transmitPacket(pkt) == false )
511 {
512 ret = kIOReturnOutputStall;
513 }
514
515 releaseDebuggerLock();
516
517 return ret;
518 }
519
520 /*-------------------------------------------------------------------------
521 *
522 *
523 *
524 *-------------------------------------------------------------------------*/
525
526 bool UniNEnet::resetAndEnable(bool enable)
527 {
528 bool ret = true;
529
530 reserveDebuggerLock();
531
532 ready = false;
533
534 if (timerSource)
535 {
536 timerSource->cancelTimeout();
537 }
538
539 disableAdapterInterrupts();
540 if (getWorkLoop())
541 {
542 getWorkLoop()->disableAllInterrupts();
543 }
544
545 if (enable)
546 {
547 phyId = 0xff;
548 }
549
550 if ( resetChip() == false )
551 {
552 ret = false;
553 goto resetAndEnable_exit;
554 }
555
556 // Initialize the link status.
557
558 setLinkStatus( 0, 0 );
559
560 // Flush all mbufs from RX and TX rings.
561
562 flushRings();
563
564 while (enable)
565 {
566 if (!initRxRing() || !initTxRing())
567 {
568 ret = false;
569 break;
570 }
571
572 if ( phyId != 0xff )
573 {
574 miiInitializePHY(phyId);
575 }
576
577 if (initChip() == false)
578 {
579 ret = false;
580 break;
581 }
582
583 // startChip();
584
585 timerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
586
587 if (getWorkLoop())
588 {
589 getWorkLoop()->enableAllInterrupts();
590 }
591 enableAdapterInterrupts();
592
593 ready = true;
594
595 monitorLinkStatus( true );
596
597 break;
598 }
599
600 resetAndEnable_exit: ;
601
602 releaseDebuggerLock();
603
604 return ret;
605 }
606
607 /*-------------------------------------------------------------------------
608 * Called by IOEthernetInterface client to enable the controller.
609 * This method is always called while running on the default workloop
610 * thread.
611 *-------------------------------------------------------------------------*/
612
613 IOReturn UniNEnet::enable(IONetworkInterface * netif)
614 {
615 /*
616 * If an interface client has previously enabled us,
617 * and we know there can only be one interface client
618 * for this driver, then simply return true.
619 */
620 if ( netifEnabled )
621 {
622 IOLog("EtherNet(UniN): already enabled\n");
623 return kIOReturnSuccess;
624 }
625
626 if ( (ready == false) && !resetAndEnable(true) )
627 return kIOReturnIOError;
628
629 /*
630 * Mark the controller as enabled by the interface.
631 */
632 netifEnabled = true;
633
634 /*
635 * Start our IOOutputQueue object.
636 */
637 transmitQueue->setCapacity( TRANSMIT_QUEUE_SIZE );
638 transmitQueue->start();
639
640 return kIOReturnSuccess;
641 }
642
643 /*-------------------------------------------------------------------------
644 * Called by IOEthernetInterface client to disable the controller.
645 * This method is always called while running on the default workloop
646 * thread.
647 *-------------------------------------------------------------------------*/
648
649 IOReturn UniNEnet::disable(IONetworkInterface * /*netif*/)
650 {
651 /*
652 * Disable our IOOutputQueue object. This will prevent the
653 * outputPacket() method from being called.
654 */
655 transmitQueue->stop();
656
657 /*
658 * Flush all packets currently in the output queue.
659 */
660 transmitQueue->setCapacity(0);
661 transmitQueue->flush();
662
663 /*
664 * If we have no active clients, then disable the controller.
665 */
666 if ( debugEnabled == false )
667 {
668 resetAndEnable(false);
669 }
670
671 netifEnabled = false;
672
673 return kIOReturnSuccess;
674 }
675
676 /*-------------------------------------------------------------------------
677 * This method is called by our debugger client to bring up the controller
678 * just before the controller is registered as the debugger device. The
679 * debugger client is attached in response to the attachDebuggerClient()
680 * call.
681 *
682 * This method is always called while running on the default workloop
683 * thread.
684 *-------------------------------------------------------------------------*/
685
686 IOReturn UniNEnet::enable(IOKernelDebugger * /*debugger*/)
687 {
688 /*
689 * Enable hardware and make it ready to support the debugger client.
690 */
691 if ( (ready == false) && !resetAndEnable(true) )
692 {
693 return kIOReturnIOError;
694 }
695
696 /*
697 * Mark the controller as enabled by the debugger.
698 */
699 debugEnabled = true;
700
701 /*
702 * Returning true will allow the kdp registration to continue.
703 * If we return false, then we will not be registered as the
704 * debugger device, and the attachDebuggerClient() call will
705 * return NULL.
706 */
707 return kIOReturnSuccess;
708 }
709
710 /*-------------------------------------------------------------------------
711 * This method is called by our debugger client to stop the controller.
712 * The debugger will call this method when we issue a detachDebuggerClient().
713 *
714 * This method is always called while running on the default workloop
715 * thread.
716 *-------------------------------------------------------------------------*/
717
718 IOReturn UniNEnet::disable(IOKernelDebugger * /*debugger*/)
719 {
720 debugEnabled = false;
721
722 /*
723 * If we have no active clients, then disable the controller.
724 */
725 if ( netifEnabled == false )
726 {
727 resetAndEnable(false);
728 }
729
730 return kIOReturnSuccess;
731 }
732
733 /*-------------------------------------------------------------------------
734 *
735 *
736 *
737 *-------------------------------------------------------------------------*/
738
739 void UniNEnet::timeoutOccurred(IOTimerEventSource * /*timer*/)
740 {
741 IODebuggerLockState lockState;
742 bool doService = false;
743 UInt32 txRingIndex;
744 UInt32 x;
745
746
747 if ( ready == false )
748 {
749 // IOLog("EtherNet(UniN): Spurious timeout event!!\n");
750 return;
751 }
752
753
754 /* Update statistics from the GMAC statistics registers: */
755
756 x = READ_REGISTER( LengthErrorCounter );
757 writeRegister( &fpRegs->LengthErrorCounter, 0 );
758 fpEtherStats->dot3StatsEntry.frameTooLongs += x;
759
760 x = READ_REGISTER( AlignmentErrorCounter );
761 writeRegister( &fpRegs->AlignmentErrorCounter, 0 );
762 fpEtherStats->dot3StatsEntry.alignmentErrors += x;
763
764 x = READ_REGISTER( FCSErrorCounter );
765 writeRegister( &fpRegs->FCSErrorCounter, 0 );
766 fpEtherStats->dot3StatsEntry.fcsErrors += x;
767
768 x = READ_REGISTER( RxCodeViolationErrorCounter );
769 writeRegister( &fpRegs->RxCodeViolationErrorCounter, 0 );
770 fpEtherStats->dot3StatsEntry.internalMacTransmitErrors += x;
771
772 x = READ_REGISTER( FirstAttemptSuccessfulCollisionCounter );
773 writeRegister( &fpRegs->FirstAttemptSuccessfulCollisionCounter, 0 );
774 fpEtherStats->dot3StatsEntry.singleCollisionFrames += x;
775
776 x = READ_REGISTER( ExcessiveCollisionCounter );
777 writeRegister( &fpRegs->ExcessiveCollisionCounter, 0 );
778 fpEtherStats->dot3StatsEntry.excessiveCollisions += x;
779
780 x = READ_REGISTER( LateCollisionCounter );
781 writeRegister( &fpRegs->LateCollisionCounter, 0 );
782 fpEtherStats->dot3StatsEntry.lateCollisions += x;
783
784 lockState = IODebuggerLock( this );
785
786 monitorLinkStatus();
787
788 /*
789 * If there are pending entries on the Tx ring
790 */
791 if ( txCommandHead != txCommandTail )
792 {
793 /*
794 * If the hardware tx pointer did not move since the last
795 * check, increment the txWDCount.
796 */
797 txRingIndex = READ_REGISTER( TxCompletion );
798 if ( txRingIndex == txRingIndexLast )
799 {
800 txWDCount++;
801 }
802 else
803 {
804 txWDCount = 0;
805 txRingIndexLast = txRingIndex;
806 }
807
808 if ( txWDCount > 2 )
809 {
810 /*
811 * We only take interrupts every 64 tx completions, so we may be here just
812 * to do normal clean-up of tx packets. We check if the hardware tx pointer
813 * points to the next available tx slot. This indicates that we transmitted all
814 * packets that were scheduled vs rather than the hardware tx being stalled.
815 */
816 if ( txRingIndex != txCommandTail )
817 {
818 UInt32 interruptStatus, compReg, kickReg;
819
820 interruptStatus = READ_REGISTER( Status );
821 compReg = READ_REGISTER( TxCompletion );
822 kickReg = READ_REGISTER( TxKick );
823
824 IOLog( "Tx Int Timeout - Comp = %04x Kick = %04x Int = %08x\n\r", (int)compReg, (int)kickReg, (int)interruptStatus );
825 }
826
827 // dumpRegisters();
828
829 transmitInterruptOccurred();
830
831 doService = true;
832
833 txRingIndexLast = txRingIndex;
834 txWDCount = 0;
835 }
836 }
837 else
838 {
839 txWDCount = 0;
840 }
841
842 // Monitor receiver's health.
843
844 if ( rxWDInterrupts == 0 )
845 {
846 UInt32 rxMACStatus;
847
848 switch ( rxWDCount )
849 {
850 case 0:
851 case 1:
852 rxWDCount++; // Extend timeout
853 break;
854
855 default:
856 // We could be less conservative here and restart the
857 // receiver unconditionally.
858
859 rxMACStatus = READ_REGISTER( RxMACStatus );
860
861 if ( rxMACStatus & kRX_MAC_Status_Rx_Overflow )
862 {
863 // Bad news, the receiver may be deaf as a result of this
864 // condition, and if so, a RX MAC reset is needed. Note
865 // that reading this register will clear all bits.
866
867 restartReceiver();
868
869 NETWORK_STAT_ADD( inputErrors );
870 ETHERNET_STAT_ADD( dot3RxExtraEntry.watchdogTimeouts );
871 }
872 rxWDCount = 0;
873 break;
874 }
875 }
876 else
877 {
878 // Reset watchdog
879
880 rxWDCount = 0;
881 rxWDInterrupts = 0;
882 }
883
884 /* Clean-up after the debugger if the debugger was active: */
885
886 if ( debugTxPoll )
887 {
888 debugQueue->flush();
889 debugTxPoll = false;
890 doService = true;
891 }
892 IODebuggerUnlock( lockState );
893
894 /*
895 * Make sure the queue is not stalled.
896 */
897 if (doService && netifEnabled)
898 {
899 transmitQueue->service();
900 }
901
902 /*
903 * Restart the watchdog timer
904 */
905 timerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
906 return;
907 }/* end timeoutOccurred */
908
909
910 /*-------------------------------------------------------------------------
911 *
912 *
913 *
914 *-------------------------------------------------------------------------*/
915
916 const OSString * UniNEnet::newVendorString() const
917 {
918 return OSString::withCString("Apple");
919 }
920
921 const OSString * UniNEnet::newModelString() const
922 {
923 return OSString::withCString("gmac+");
924 }
925
926 const OSString * UniNEnet::newRevisionString() const
927 {
928 return OSString::withCString("");
929 }
930
931
932 /*-------------------------------------------------------------------------
933 *
934 *
935 *
936 *-------------------------------------------------------------------------*/
937
938 IOReturn UniNEnet::setPromiscuousMode(IOEnetPromiscuousMode mode)
939 {
940 reserveDebuggerLock();
941
942 rxMacConfigReg = READ_REGISTER( RxMACConfiguration );
943 if (mode == kIOEnetPromiscuousModeOff)
944 {
945 rxMacConfigReg &= ~(kRxMACConfiguration_Promiscuous);
946 isPromiscuous = false;
947
948 }
949 else
950 {
951 rxMacConfigReg |= kRxMACConfiguration_Promiscuous;
952 isPromiscuous = true;
953
954 }
955 WRITE_REGISTER( RxMACConfiguration, rxMacConfigReg );
956
957 releaseDebuggerLock();
958
959 return kIOReturnSuccess;
960 }
961
962 /*-------------------------------------------------------------------------
963 *
964 *
965 *
966 *-------------------------------------------------------------------------*/
967
968 IOReturn UniNEnet::setMulticastMode(IOEnetMulticastMode mode)
969 {
970 multicastEnabled = (mode == kIOEnetMulticastModeOff) ? false : true;
971
972 return kIOReturnSuccess;
973 }
974
975 /*-------------------------------------------------------------------------
976 *
977 *
978 *
979 *-------------------------------------------------------------------------*/
980
981 IOReturn UniNEnet::setMulticastList(IOEthernetAddress *addrs, UInt32 count)
982 {
983 reserveDebuggerLock();
984
985 resetHashTableMask();
986 for (UInt32 i = 0; i < count; i++)
987 {
988 addToHashTableMask(addrs->bytes);
989 addrs++;
990 }
991 updateHashTableMask();
992
993 releaseDebuggerLock();
994 return kIOReturnSuccess;
995 }
996
997 /*-------------------------------------------------------------------------
998 *
999 *
1000 *
1001 *-------------------------------------------------------------------------*/
1002
1003 IOOutputQueue* UniNEnet::createOutputQueue()
1004 {
1005 return IOBasicOutputQueue::withTarget( this, TRANSMIT_QUEUE_SIZE );
1006 }/* end createOutputQueue */
1007
1008
1009 /*-------------------------------------------------------------------------
1010 *
1011 *
1012 *
1013 *-------------------------------------------------------------------------*/
1014
1015 static struct MediumTable
1016 {
1017 UInt32 type;
1018 UInt32 speed;
1019 }
1020 mediumTable[] =
1021 {
1022 { kIOMediumEthernetNone , 0 },
1023 { kIOMediumEthernetAuto , 0 },
1024 { kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex, 10 },
1025 { kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex, 10 },
1026 { kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex, 100 },
1027 { kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex, 100 },
1028 { kIOMediumEthernet1000BaseSX | kIOMediumOptionFullDuplex, 1000 },
1029 { kIOMediumEthernet1000BaseTX | kIOMediumOptionFullDuplex, 1000 }
1030 };
1031
1032
1033 bool UniNEnet::createMediumTables()
1034 {
1035 IONetworkMedium *medium;
1036 UInt32 i;
1037
1038 mediumDict = OSDictionary::withCapacity( sizeof(mediumTable)/sizeof(mediumTable[0]) );
1039 if ( mediumDict == 0 ) return false;
1040
1041 for ( i=0; i < sizeof(mediumTable)/sizeof(mediumTable[0]); i++ )
1042 {
1043 medium = IONetworkMedium::medium( mediumTable[i].type, mediumTable[i].speed );
1044 if ( medium != 0 )
1045 {
1046 IONetworkMedium::addMedium( mediumDict, medium );
1047 medium->release();
1048 }
1049 }
1050
1051 if ( publishMediumDictionary( mediumDict ) != true )
1052 {
1053 return false;
1054 }
1055
1056 medium = IONetworkMedium::getMediumWithType( mediumDict,
1057 kIOMediumEthernetAuto );
1058
1059 setCurrentMedium( medium );
1060
1061 return true;
1062 }
1063
1064
1065 void UniNEnet::writeRegister( UInt32 *pReg, UInt32 data )
1066 {
1067 /// ELG( data, (UInt32)pReg - (UInt32)fpRegs, 'wReg', "writeRegister" );
1068
1069 OSWriteLittleInt32( pReg, 0, data );
1070 return;
1071 }/* end writeRegister */