]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/network/drvPPCBMac/BMacEnet.cpp
xnu-123.5.tar.gz
[apple/xnu.git] / iokit / Drivers / network / drvPPCBMac / BMacEnet.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 by Apple Computer, Inc., All rights reserved.
24 *
25 * Hardware independent (relatively) code for the BMac Ethernet Controller
26 *
27 * HISTORY
28 *
29 * dd-mmm-yy
30 * Created.
31 *
32 * Dec 10, 1998 jliu
33 * Converted to IOKit/C++.
34 */
35
36 #include "BMacEnet.h"
37 #include "BMacEnetPrivate.h"
38
39 #include <IOKit/IORegistryEntry.h>
40 #include <IOKit/IODeviceTreeSupport.h>
41 #include <IOKit/platform/AppleMacIODevice.h>
42 #include <IOKit/assert.h>
43
44 // #define DEBUG_JOE 1
45
46 //------------------------------------------------------------------------
47
48 #define super IOEthernetController
49
50 OSDefineMetaClassAndStructors( BMacEnet, IOEthernetController )
51
52 //------------------------------------------------------------------------
53
54 #define PROVIDER_DEV 0
55 #define PROVIDER_DMA_TX 1
56 #define PROVIDER_DMA_RX 2
57
58 /*
59 * Public Instance Methods
60 */
61
62 /*-------------------------------------------------------------------------
63 *
64 *
65 *
66 *-------------------------------------------------------------------------*/
67
68 bool BMacEnet::init(OSDictionary * properties = 0)
69 {
70 if ( super::init(properties) == false )
71 return false;
72
73 /*
74 * Initialize my ivars.
75 */
76 phyId = 0xff;
77 phyMIIDelay = MII_DEFAULT_DELAY;
78 sromAddressBits = 6;
79 enetAddressOffset = 20;
80 phyStatusPrev = 0;
81
82 return true;
83 }
84
85 bool BMacEnet::start(IOService * provider)
86 {
87 AppleMacIODevice *nub = OSDynamicCast(AppleMacIODevice, provider);
88 IOInterruptEventSource *intES;
89
90 if (!nub || !super::start(provider))
91 return false;
92
93 transmitQueue = OSDynamicCast(IOGatedOutputQueue, getOutputQueue());
94 if (!transmitQueue) {
95 IOLog("BMac: output queue initialization failed\n");
96 return false;
97 }
98 transmitQueue->retain();
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 return false;
111
112 // Allocate a IOMbufBigMemoryCursor instance. Currently, the maximum
113 // number of segments is set to 2. The maximum length for each segment
114 // is set to the maximum ethernet frame size (plus padding).
115
116 mbufCursor = IOMbufBigMemoryCursor::withSpecification(NETWORK_BUFSIZE, 2);
117 if (!mbufCursor) {
118 IOLog("Ethernet(BMac): IOMbufBigMemoryCursor allocation failure\n");
119 return false;
120 }
121
122 //
123 // Our provider is the nub representing the BMacEnet hardware
124 // controller. We will query it for our resource information.
125 //
126
127 for (int i = 0; i < MEMORY_MAP_HEATHROW_INDEX; i++) {
128 IOMemoryMap * map;
129
130 map = provider->mapDeviceMemoryWithIndex(i);
131 if (!map)
132 return false;
133 #ifdef DEBUG_JOE
134 IOLog("map %d: Phys:%08x Virt:%08x len:%d\n",
135 i,
136 (unsigned) map->getPhysicalAddress(),
137 (unsigned) map->getVirtualAddress(),
138 (unsigned) map->getLength());
139 #endif DEBUG_JOE
140
141 switch (i) {
142 case MEMORY_MAP_ENET_INDEX:
143 ioBaseEnet = (IOPPCAddress) map->getVirtualAddress();
144 break;
145
146 case MEMORY_MAP_TXDMA_INDEX:
147 ioBaseEnetTxDMA = (IODBDMAChannelRegisters *)
148 map->getVirtualAddress();
149 break;
150
151 case MEMORY_MAP_RXDMA_INDEX:
152 ioBaseEnetRxDMA = (IODBDMAChannelRegisters *)
153 map->getVirtualAddress();
154 break;
155 }
156
157 maps[i] = map;
158 }
159
160 #ifdef DEBUG_JOE
161 IOLog("ioBaseEnet: 0x%08x\n", ioBaseEnet);
162 IOLog("ioBaseEnetTxDMA: 0x%08x\n", ioBaseEnetTxDMA);
163 IOLog("ioBaseEnetRxDMA: 0x%08x\n", ioBaseEnetRxDMA);
164 #endif DEBUG_JOE
165
166 //
167 // We need to get the I/O address for the Heathrow controller.
168 // We ask the provider (bmac) for its device tree parent.
169 //
170 IOService *heathrow;
171 if (!(heathrow = OSDynamicCast(IOService,
172 provider->getParentEntry( gIODTPlane ))))
173 return false;
174
175 // Check whether the hardware is susceptible to the broken unicast
176 // filter problem.
177 //
178 OSData * devIDData;
179 devIDData = OSDynamicCast(OSData, heathrow->getProperty("device-id"));
180
181 if (devIDData) {
182 useUnicastFilter = ( *((UInt32 *) devIDData->getBytesNoCopy()) ==
183 0x10 );
184 if (useUnicastFilter)
185 IOLog("%s: Enabling workaround for broken unicast filter\n",
186 getName());
187 }
188
189 IOMemoryMap * map = heathrow->mapDeviceMemoryWithIndex(0);
190 if (map)
191 {
192 #ifdef DEBUG_JOE
193 IOLog("Heathrow: Phys:%08x Virt:%08x len:%d\n",
194 (unsigned) map->getPhysicalAddress(),
195 (unsigned) map->getVirtualAddress(),
196 (unsigned) map->getLength());
197 #endif DEBUG_JOE
198 ioBaseHeathrow = (IOPPCAddress) map->getVirtualAddress();
199
200 maps[MEMORY_MAP_HEATHROW_INDEX] = map;
201 }
202 else {
203 return false;
204 }
205
206 //
207 // Get a reference to the IOWorkLoop in our superclass.
208 //
209 IOWorkLoop * myWorkLoop = getWorkLoop();
210 assert(myWorkLoop);
211
212 //
213 // Allocate three IOInterruptEventSources.
214 //
215 rxIntSrc = IOInterruptEventSource::interruptEventSource
216 (this,
217 (IOInterruptEventAction) &BMacEnet::interruptOccurredForSource,
218 provider, PROVIDER_DMA_RX);
219 if (!rxIntSrc
220 || (myWorkLoop->addEventSource(rxIntSrc) != kIOReturnSuccess)) {
221 IOLog("Ethernet(BMac): rxIntSrc init failure\n");
222 return false;
223 }
224
225 intES = IOInterruptEventSource::interruptEventSource
226 (this,
227 (IOInterruptEventAction) &BMacEnet::interruptOccurredForSource,
228 provider, PROVIDER_DMA_TX);
229 if (intES) {
230 bool res = (myWorkLoop->addEventSource(intES) != kIOReturnSuccess);
231 intES->release();
232 if (res) {
233 IOLog("Ethernet(BMac): PROVIDER_DMA_TX add failure\n");
234 return false;
235 }
236 }
237 else {
238 IOLog("Mace: PROVIDER_DMA_TX init failure\n");
239 return false;
240 }
241
242 intES = IOInterruptEventSource::interruptEventSource
243 (this,
244 (IOInterruptEventAction) &BMacEnet::interruptOccurredForSource,
245 provider, PROVIDER_DEV);
246 if (intES) {
247 bool res = (myWorkLoop->addEventSource(intES) != kIOReturnSuccess);
248 intES->release();
249 if (res) {
250 IOLog("Ethernet(BMac): PROVIDER_DEV add failure\n");
251 return false;
252 }
253 }
254 else {
255 IOLog("Ethernet(BMac): PROVIDER_DEV init failure\n");
256 return false;
257 }
258
259 timerSrc = IOTimerEventSource::timerEventSource
260 (this, (IOTimerEventSource::Action) &BMacEnet::timeoutOccurred);
261 if (!timerSrc
262 || (myWorkLoop->addEventSource(timerSrc) != kIOReturnSuccess)) {
263 IOLog("Ethernet(BMac): timerSrc init failure\n");
264 return false;
265 }
266
267 MGETHDR(txDebuggerPkt, M_DONTWAIT, MT_DATA);
268 if (!txDebuggerPkt) {
269 IOLog("Ethernet(BMac): Couldn't allocate KDB buffer\n");
270 return false;
271 }
272
273 #if 0
274 // Enable the interrupt event sources. The hardware interrupts
275 // sources remain disabled until _resetAndEnable(true) is called.
276 //
277 // myWorkLoop->enableAllInterrupts();
278 #endif
279
280 // Perform a hardware reset.
281 //
282 if ( !_resetAndEnable(false) )
283 {
284 return false;
285 }
286
287 // Cache my MAC address.
288 //
289 getHardwareAddress(&myAddress);
290
291 // Allocate memory for ring buffers.
292 //
293 if (_allocateMemory() == false)
294 {
295 return false;
296 }
297
298 // Create a table of supported media types.
299 //
300 if ( !createMediumTables() )
301 return false;
302
303 // Attach an IOEthernetInterface client.
304 //
305 if ( !attachInterface((IONetworkInterface **) &networkInterface, false) )
306 return false;
307
308 // Attach a kernel debugger client.
309 //
310 attachDebuggerClient(&debugger);
311
312 // Ready to service interface requests.
313 //
314 networkInterface->registerService();
315
316 return true;
317 }
318
319 /*-------------------------------------------------------------------------
320 *
321 *
322 *
323 *-------------------------------------------------------------------------*/
324
325 void BMacEnet::free()
326 {
327 UInt i;
328
329 _resetAndEnable(false);
330
331 if (debugger)
332 debugger->release();
333
334 if (getWorkLoop())
335 getWorkLoop()->disableAllEventSources();
336
337 if (timerSrc)
338 timerSrc->release();
339
340 if (rxIntSrc)
341 rxIntSrc->release();
342
343 if (txDebuggerPkt)
344 freePacket(txDebuggerPkt);
345
346 if (transmitQueue)
347 transmitQueue->release();
348
349 if (debugQueue)
350 debugQueue->release();
351
352 if (networkInterface)
353 networkInterface->release();
354
355 if (mbufCursor)
356 mbufCursor->release();
357
358 if ( mediumDict )
359 mediumDict->release();
360
361 for (i = 0; i < rxMaxCommand; i++)
362 if (rxMbuf[i]) freePacket(rxMbuf[i]);
363
364 for (i = 0; i < txMaxCommand; i++)
365 if (txMbuf[i]) freePacket(txMbuf[i]);
366
367 for (i = 0; i < MEMORY_MAP_COUNT; i++)
368 if (maps[i]) maps[i]->release();
369
370 if (dmaMemory.ptr)
371 {
372 IOFree(dmaMemory.ptrReal, dmaMemory.sizeReal);
373 dmaMemory.ptr = 0;
374 }
375
376 if ( workLoop )
377 {
378 workLoop->release();
379 workLoop = 0;
380 }
381
382 super::free();
383 }
384
385 /*-------------------------------------------------------------------------
386 * Override IONetworkController::createWorkLoop() method and create
387 * a workloop.
388 *
389 *-------------------------------------------------------------------------*/
390
391 bool BMacEnet::createWorkLoop()
392 {
393 workLoop = IOWorkLoop::workLoop();
394
395 return ( workLoop != 0 );
396 }
397
398 /*-------------------------------------------------------------------------
399 * Override IOService::getWorkLoop() method to return our workloop.
400 *
401 *
402 *-------------------------------------------------------------------------*/
403
404 IOWorkLoop * BMacEnet::getWorkLoop() const
405 {
406 return workLoop;
407 }
408
409 /*-------------------------------------------------------------------------
410 *
411 *
412 *
413 *-------------------------------------------------------------------------*/
414
415 void BMacEnet::interruptOccurredForSource(IOInterruptEventSource *src,
416 int /*count*/)
417 {
418 bool doFlushQueue = false;
419 bool doService = false;
420
421 reserveDebuggerLock();
422
423 statReg = ReadBigMacRegister( ioBaseEnet, kSTAT );
424
425 if (src == rxIntSrc) {
426 KERNEL_DEBUG(DBG_BMAC_RXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
427 doFlushQueue = _receiveInterruptOccurred();
428 KERNEL_DEBUG(DBG_BMAC_RXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
429 }
430 else {
431 /*
432 * On the transmit side, we use the chipset interrupt. Using the
433 * transmit DMA interrupt (or having multiple transmit DMA entries)
434 * would allows us to send the next frame to the chipset prior the
435 * transmit fifo going empty.
436 * However, this aggrevates a BMac chipset bug where the next frame going
437 * out gets corrupted (first two bytes lost) if the chipset had to retry
438 * the previous frame.
439 */
440 txWDInterrupts++;
441 KERNEL_DEBUG(DBG_BMAC_TXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
442 doService = _transmitInterruptOccurred();
443 KERNEL_DEBUG(DBG_BMAC_TXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
444 }
445
446 releaseDebuggerLock();
447
448 /*
449 * Submit all received packets queued up by _receiveInterruptOccurred()
450 * to the network stack. The up call is performed without holding the
451 * debugger lock.
452 */
453 if ( doFlushQueue )
454 networkInterface->flushInputQueue();
455
456 /*
457 * Unstall the output queue if some space was made available.
458 */
459 if ( doService && netifEnabled )
460 transmitQueue->service();
461 }
462
463 /*-------------------------------------------------------------------------
464 *
465 *
466 *
467 *-------------------------------------------------------------------------*/
468
469 UInt32 BMacEnet::outputPacket(struct mbuf * pkt, void * param)
470 {
471 u_int32_t i;
472 UInt32 ret = kIOReturnOutputSuccess;
473
474 KERNEL_DEBUG(DBG_BMAC_TXQUEUE | DBG_FUNC_NONE, (int) pkt,
475 (int) pkt->m_pkthdr.len, 0, 0, 0 );
476
477 /*
478 * Hold the debugger lock so the debugger can't interrupt us
479 */
480 reserveDebuggerLock();
481
482 do
483 {
484 /*
485 * Preliminary sanity checks
486 */
487 assert( pkt && netifEnabled );
488
489 #if 0
490 /*
491 * Remove any completed packets from the Tx ring
492 */
493 if ( chipId >= kCHIPID_PaddingtonXmitStreaming )
494 {
495 _transmitInterruptOccurred();
496 }
497 #endif
498
499 i = txCommandTail + 1;
500 if ( i >= txMaxCommand ) i = 0;
501 if ( i == txCommandHead )
502 {
503 /*
504 * Ring buffer is full. Disable the dequeueing process.
505 * We reenable it when an entry is made available by the
506 * transmit interrupt handler, or if a timeout occurs.
507 */
508 ret = kIOReturnOutputStall;
509 continue;
510 }
511
512 /*
513 * If there is space on the Tx ring, add the packet directly to the
514 * ring.
515 */
516 _transmitPacket(pkt);
517 }
518 while ( 0 );
519
520 releaseDebuggerLock();
521
522 return ret;
523 }
524
525 /*-------------------------------------------------------------------------
526 *
527 *
528 *
529 *-------------------------------------------------------------------------*/
530
531 bool BMacEnet::_resetAndEnable(bool enable)
532 {
533 bool ret = true;
534
535 // reserveDebuggerLock();
536
537 ready = false;
538
539 if (timerSrc) timerSrc->cancelTimeout();
540
541 _disableAdapterInterrupts();
542 if (getWorkLoop()) getWorkLoop()->disableAllInterrupts();
543
544 if (enable)
545 {
546 phyId = 0xff;
547 }
548
549 _resetChip();
550
551 // Initialize the link status.
552
553 phyStatusPrev = 0;
554 setLinkStatus( 0, 0 );
555
556 while (enable)
557 {
558 if (!_initRxRing() || !_initTxRing())
559 {
560 ret = false;
561 break;
562 }
563
564 if ( phyId != 0xff )
565 {
566 miiInitializePHY(phyId);
567 }
568
569 if (_initChip() == false)
570 {
571 ret = false;
572 break;
573 }
574
575 _startChip();
576
577 timerSrc->setTimeoutMS(WATCHDOG_TIMER_MS);
578
579 if (getWorkLoop()) getWorkLoop()->enableAllInterrupts();
580 _enableAdapterInterrupts();
581
582 ready = true;
583
584 _sendDummyPacket();
585
586 monitorLinkStatus( true );
587
588 break;
589 }
590
591 // releaseDebuggerLock();
592
593 return ret;
594 }
595
596 /*-------------------------------------------------------------------------
597 * Grab a pointer to the statistics counters.
598 *
599 *
600 *-------------------------------------------------------------------------*/
601
602 bool BMacEnet::configureInterface( IONetworkInterface * netif )
603 {
604 IONetworkData * nd;
605
606 if ( super::configureInterface( netif ) == false )
607 return false;
608
609 /*
610 * Grab a pointer to the statistics structure in the interface.
611 */
612 nd = netif->getNetworkData( kIONetworkStatsKey );
613
614 if ( !nd || !(netStats = (IONetworkStats *) nd->getBuffer()) )
615 {
616 IOLog("EtherNet(BMac): invalid network statistics\n");
617 return false;
618 }
619
620 return true;
621 }
622
623 /*-------------------------------------------------------------------------
624 * Called by IOEthernetInterface client to enable the controller.
625 * This method is always called while running on the default workloop
626 * thread.
627 *-------------------------------------------------------------------------*/
628
629 IOReturn BMacEnet::enable(IONetworkInterface * netif)
630 {
631 // If an interface client has previously enabled us,
632 // and we know there can only be one interface client
633 // for this driver, then simply return true.
634 //
635 if ( netifEnabled )
636 {
637 IOLog("EtherNet(BMac): already enabled\n");
638 return kIOReturnSuccess;
639 }
640
641 if ( (ready == false) && !_resetAndEnable(true) )
642 return kIOReturnIOError;
643
644 // Record the interface as an active client.
645 //
646 netifEnabled = true;
647
648 // Start our IOOutputQueue object.
649 //
650 transmitQueue->setCapacity(TRANSMIT_QUEUE_SIZE);
651 transmitQueue->start();
652
653 return kIOReturnSuccess;
654 }
655
656 /*-------------------------------------------------------------------------
657 * Called by IOEthernetInterface client to disable the controller.
658 * This method is always called while running on the default workloop
659 * thread.
660 *-------------------------------------------------------------------------*/
661
662 IOReturn BMacEnet::disable(IONetworkInterface * /*netif*/)
663 {
664 // Disable our IOOutputQueue object. This will prevent the
665 // outputPacket() method from being called.
666 //
667 transmitQueue->stop();
668
669 // Flush all packets currently in the output queue.
670 //
671 transmitQueue->setCapacity(0);
672 transmitQueue->flush();
673
674 // If we have no active clients, then disable the controller.
675 //
676 if ( debugEnabled == false )
677 {
678 _resetAndEnable(false);
679 }
680
681 netifEnabled = false;
682
683 return kIOReturnSuccess;
684 }
685
686 /*-------------------------------------------------------------------------
687 * This method is called by our debugger client to bring up the controller
688 * just before the controller is registered as the debugger device. The
689 * debugger client is attached in response to the attachDebuggerClient()
690 * call.
691 *
692 * This method is always called while running on the default workloop
693 * thread.
694 *-------------------------------------------------------------------------*/
695
696 IOReturn BMacEnet::enable(IOKernelDebugger *debugger)
697 {
698 // Enable hardware and make it ready to support the debugger client.
699 //
700 if ( (ready == false) && !_resetAndEnable(true) )
701 {
702 return kIOReturnIOError;
703 }
704
705 // Record the debugger as an active client of ours.
706 //
707 debugEnabled = true;
708
709 return kIOReturnSuccess;
710 }
711
712 /*-------------------------------------------------------------------------
713 * This method is called by our debugger client to stop the controller.
714 * The debugger will call this method when we issue a detachDebuggerClient().
715 *
716 * This method is always called while running on the default workloop
717 * thread.
718 *-------------------------------------------------------------------------*/
719
720 IOReturn BMacEnet::disable(IOKernelDebugger * /*debugger*/)
721 {
722 debugEnabled = false;
723
724 // If we have no active clients, then disable the controller.
725 //
726 if ( netifEnabled == false )
727 {
728 _resetAndEnable(false);
729 }
730
731 return kIOReturnSuccess;
732 }
733
734 /*-------------------------------------------------------------------------
735 *
736 *
737 *
738 *-------------------------------------------------------------------------*/
739
740 void BMacEnet::timeoutOccurred(IOTimerEventSource * /*timer*/)
741 {
742 u_int32_t dmaStatus;
743 bool doFlushQueue = false;
744 bool doService = false;
745
746 if ( ready == false )
747 {
748 return;
749 }
750
751 // IOLog("Ethernet(BMac): watchdog timer\n");
752
753 reserveDebuggerLock();
754
755 /*
756 * Check for DMA shutdown on receive channel
757 */
758 dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetRxDMA );
759 if ( !(dmaStatus & kdbdmaActive) )
760 {
761 #if 0
762 IOLog( "Ethernet(BMac): Timeout check - RxHead = %d RxTail = %d\n",
763 rxCommandHead, rxCommandTail);
764
765 IOLog( "Ethernet(BMac): Rx Commands = %08x(p) Rx DMA Ptr = %08x(p)\n\r", rxDMACommandsPhys, IOGetDBDMACommandPtr(ioBaseEnetRxDMA) );
766 [self _dumpDesc:(void *)rxDMACommands Size:rxMaxCommand * sizeof(enet_dma_cmd_t)];
767 #endif
768
769 doFlushQueue = _receiveInterruptOccurred();
770 }
771
772 /*
773 * If there are pending entries on the Tx ring
774 */
775 if ( txCommandHead != txCommandTail )
776 {
777 /*
778 * If we did not service the Tx ring during the last timeout interval,
779 * then force servicing of the Tx ring
780 */
781 if ( txWDInterrupts == 0 )
782 {
783 if ( txWDCount++ > 0 )
784 {
785 if (_transmitInterruptOccurred() == false)
786 {
787 #if 0
788 IOLog( "Ethernet(BMac): Timeout check - TxHead = %d TxTail = %d\n",
789 txCommandHead, txCommandTail);
790 #endif
791 _restartTransmitter();
792 }
793 doService = true;
794 }
795 }
796 else
797 {
798 txWDInterrupts = 0;
799 txWDCount = 0;
800 }
801 }
802 else
803 {
804 txWDInterrupts = 0;
805 txWDCount = 0;
806 }
807
808 // Poll link status periodically.
809
810 monitorLinkStatus();
811
812 // Clean-up after the debugger if the debugger was active.
813 //
814 if ( debugTxPoll )
815 {
816 debugQueue->flush();
817 debugTxPoll = false;
818 doService = true;
819 }
820
821 releaseDebuggerLock();
822
823 /*
824 * Submit all received packets queued up by _receiveInterruptOccurred()
825 * to the network stack. This call is performed without holding the
826 * debugger lock.
827 */
828 if ( doFlushQueue )
829 {
830 networkInterface->flushInputQueue();
831 }
832
833 /*
834 * Make sure the output queue is not stalled.
835 */
836 if ( doService && netifEnabled )
837 {
838 transmitQueue->service();
839 }
840
841 /*
842 * Restart the watchdog timer
843 */
844 timerSrc->setTimeoutMS(WATCHDOG_TIMER_MS);
845 }
846
847 /*-------------------------------------------------------------------------
848 *
849 *
850 *
851 *-------------------------------------------------------------------------*/
852
853 void BMacEnet::monitorLinkStatus( bool firstPoll )
854 {
855 u_int16_t phyStatus;
856 u_int16_t phyReg;
857 u_int16_t phyStatusChange;
858 bool fullDuplex;
859 bool reportLinkStatus = false;
860 UInt32 linkSpeed;
861 UInt32 linkStatus;
862
863 if ( phyId == 0xff )
864 {
865 // For implementations without a PHY, query the link status bit from
866 // the transceiver control register (kXCVRIF).
867
868 phyStatus = ReadBigMacRegister(ioBaseEnet, kXCVRIF);
869
870 if ( ( ( phyStatus ^ phyStatusPrev ) & kLinkStatus ) || firstPoll )
871 {
872 linkStatus = kIONetworkLinkValid;
873 linkSpeed = 0;
874 fullDuplex = false;
875 reportLinkStatus = true;
876
877 if ( ( phyStatus & kLinkStatus ) == 0 )
878 {
879 linkSpeed = 10;
880 linkStatus |= kIONetworkLinkActive;
881 }
882
883 phyStatusPrev = phyStatus;
884 }
885 }
886 else if ( miiReadWord(&phyStatus, MII_STATUS, phyId) == true )
887 {
888 phyStatusChange = ( phyStatusPrev ^ phyStatus ) &
889 ( MII_STATUS_LINK_STATUS |
890 MII_STATUS_NEGOTIATION_COMPLETE);
891
892 if ( phyStatusChange || firstPoll )
893 {
894 if ( firstPoll )
895 {
896 // For the initial link status poll, wait a bit, then
897 // re-read the status register to clear any latched bits.
898 // Why wait? Well, the debugger can kick in shortly after
899 // this function returns, and we want the duplex setting
900 // on the MAC to match the PHY.
901
902 miiWaitForAutoNegotiation( phyId );
903 miiReadWord(&phyStatus, MII_STATUS, phyId);
904 miiReadWord(&phyStatus, MII_STATUS, phyId);
905 }
906
907 if ( (phyStatus & MII_STATUS_LINK_STATUS) &&
908 (firstPoll || (phyStatus & MII_STATUS_NEGOTIATION_COMPLETE)) )
909 {
910 if ( (phyType & MII_ST10040_MASK) == MII_ST10040_ID )
911 {
912 miiReadWord(&phyReg, MII_ST10040_CHIPST, phyId);
913 linkSpeed = (phyReg & MII_ST10040_CHIPST_SPEED) ?
914 100 : 10;
915 fullDuplex = (phyReg & MII_ST10040_CHIPST_DUPLEX) ?
916 true : false;
917 }
918 else if ( (phyType & MII_DP83843_MASK) == MII_DP83843_ID )
919 {
920 miiReadWord(&phyReg, MII_DP83843_PHYSTS, phyId);
921 linkSpeed = (phyReg & MII_DP83843_PHYSTS_SPEED10) ?
922 10 : 100;
923 fullDuplex = (phyReg & MII_DP83843_PHYSTS_DUPLEX) ?
924 true : false;
925 }
926 else
927 {
928 linkSpeed = 0;
929 fullDuplex = false;
930 }
931
932 if ( fullDuplex != isFullDuplex )
933 {
934 _setDuplexMode(fullDuplex);
935 }
936
937 linkStatus = kIONetworkLinkActive | kIONetworkLinkValid;
938 }
939 else
940 {
941 linkStatus = kIONetworkLinkValid;
942 linkSpeed = 0;
943 fullDuplex = false;
944 }
945
946 reportLinkStatus = true;
947 phyStatusPrev = phyStatus;
948 }
949 }
950
951 if ( reportLinkStatus )
952 {
953 IONetworkMedium * medium;
954 IOMediumType mediumType;
955
956 switch ( linkSpeed )
957 {
958 case 10:
959 mediumType = kIOMediumEthernet10BaseT;
960 mediumType |= (fullDuplex == true) ?
961 kIOMediumOptionFullDuplex :
962 kIOMediumOptionHalfDuplex;
963 break;
964 case 100:
965 mediumType = kIOMediumEthernet100BaseTX;
966 mediumType |= (fullDuplex == true) ?
967 kIOMediumOptionFullDuplex :
968 kIOMediumOptionHalfDuplex;
969 break;
970 default:
971 mediumType = kIOMediumEthernetNone;
972 break;
973 }
974
975 medium = IONetworkMedium::getMediumWithType(mediumDict, mediumType);
976
977 setLinkStatus( linkStatus, medium, linkSpeed * 1000000 );
978
979 if ( linkStatus & kIONetworkLinkActive )
980 IOLog( "Ethernet(BMac): Link up at %ld Mbps - %s Duplex\n",
981 linkSpeed, (fullDuplex) ? "Full" : "Half" );
982 else
983 IOLog( "Ethernet(BMac): Link down\n" );
984 }
985 }
986
987 /*-------------------------------------------------------------------------
988 *
989 *
990 *
991 *-------------------------------------------------------------------------*/
992
993 const OSString * BMacEnet::newVendorString() const
994 {
995 return OSString::withCString("Apple");
996 }
997
998 const OSString * BMacEnet::newModelString() const
999 {
1000 return OSString::withCString("BMac");
1001 }
1002
1003 const OSString * BMacEnet::newRevisionString() const
1004 {
1005 return OSString::withCString("");
1006 }
1007
1008 /*-------------------------------------------------------------------------
1009 *
1010 *
1011 *
1012 *-------------------------------------------------------------------------*/
1013
1014 IOReturn BMacEnet::setPromiscuousMode(IOEnetPromiscuousMode mode)
1015 {
1016 u_int16_t rxCFGVal;
1017
1018 reserveDebuggerLock();
1019
1020 /*
1021 * Turn off the receiver and wait for the chipset to acknowledge
1022 */
1023 rxCFGVal = ReadBigMacRegister(ioBaseEnet, kRXCFG);
1024 WriteBigMacRegister(ioBaseEnet, kRXCFG, rxCFGVal & ~kRxMACEnable );
1025 while( ReadBigMacRegister(ioBaseEnet, kRXCFG) & kRxMACEnable )
1026 ;
1027
1028 /*
1029 * Set or reset promiscuous mode and restore receiver state
1030 */
1031 if (mode == kIOEnetPromiscuousModeOff) {
1032 rxCFGVal &= ~kRxPromiscEnable;
1033 isPromiscuous = false;
1034 }
1035 else {
1036 rxCFGVal |= kRxPromiscEnable;
1037 isPromiscuous = true;
1038 }
1039
1040 WriteBigMacRegister( ioBaseEnet, kRXCFG, rxCFGVal );
1041
1042 releaseDebuggerLock();
1043
1044 return kIOReturnSuccess;
1045 }
1046
1047 IOReturn BMacEnet::setMulticastMode(IOEnetMulticastMode mode)
1048 {
1049 multicastEnabled = (mode == kIOEnetMulticastModeOff) ? false : true;
1050
1051 return kIOReturnSuccess;
1052 }
1053
1054 IOReturn BMacEnet::setMulticastList(IOEthernetAddress *addrs, UInt32 count)
1055 {
1056 reserveDebuggerLock();
1057 _resetHashTableMask();
1058 for (UInt32 i = 0; i < count; i++) {
1059 _addToHashTableMask(addrs->bytes);
1060 addrs++;
1061 }
1062 _updateBMacHashTableMask();
1063 releaseDebuggerLock();
1064 return kIOReturnSuccess;
1065 }
1066
1067 /*-------------------------------------------------------------------------
1068 *
1069 *
1070 *
1071 *-------------------------------------------------------------------------*/
1072
1073 static struct MediumTable
1074 {
1075 UInt32 type;
1076 UInt32 speed;
1077 }
1078 mediumTable[] =
1079 {
1080 { kIOMediumEthernetNone , 0 },
1081 { kIOMediumEthernetAuto , 0 },
1082 { kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex, 10 },
1083 { kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex, 10 },
1084 { kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex, 100 },
1085 { kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex, 100 },
1086 };
1087
1088
1089 bool BMacEnet::createMediumTables()
1090 {
1091 IONetworkMedium *medium;
1092 UInt32 i;
1093
1094 mediumDict = OSDictionary::withCapacity( sizeof(mediumTable)/sizeof(mediumTable[0]) );
1095 if ( mediumDict == 0 ) return false;
1096
1097 for ( i=0; i < sizeof(mediumTable)/sizeof(mediumTable[0]); i++ )
1098 {
1099 medium = IONetworkMedium::medium( mediumTable[i].type, mediumTable[i].speed );
1100 if ( medium != 0 )
1101 {
1102 IONetworkMedium::addMedium( mediumDict, medium );
1103 medium->release();
1104 }
1105 }
1106
1107 if ( publishMediumDictionary( mediumDict ) != true )
1108 {
1109 return false;
1110 }
1111
1112 medium = IONetworkMedium::getMediumWithType( mediumDict,
1113 kIOMediumEthernetAuto );
1114
1115 setCurrentMedium( medium );
1116
1117 return true;
1118 }
1119
1120 /*-------------------------------------------------------------------------
1121 *
1122 *
1123 *
1124 *-------------------------------------------------------------------------*/
1125
1126 /*
1127 * Kernel Debugger Support
1128 */
1129 void BMacEnet::sendPacket( void * pkt, UInt32 pkt_len )
1130 {
1131 _sendPacket(pkt, pkt_len);
1132 }
1133
1134 void BMacEnet::receivePacket( void * pkt,
1135 UInt32 * pkt_len,
1136 UInt32 timeout )
1137 {
1138 _receivePacket(pkt, (UInt *) pkt_len, timeout);
1139 }
1140
1141 /*
1142 * Create a WorkLoop serialized output queue object.
1143 */
1144 IOOutputQueue * BMacEnet::createOutputQueue()
1145 {
1146 return IOGatedOutputQueue::withTarget( this,
1147 getWorkLoop(),
1148 TRANSMIT_QUEUE_SIZE );
1149 }
1150
1151 /*
1152 * Power management methods.
1153 */
1154
1155 IOReturn BMacEnet::registerWithPolicyMaker(IOService * policyMaker)
1156 {
1157 #define number_of_power_states 2
1158
1159 static IOPMPowerState ourPowerStates[number_of_power_states] = {
1160 {1,0,0,0,0,0,0,0,0,0,0,0},
1161 {1,IOPMDeviceUsable,IOPMPowerOn,IOPMPowerOn,0,0,0,0,0,0,0,0}
1162 };
1163
1164 currentPowerState = 1;
1165
1166 return policyMaker->registerPowerDriver( this,
1167 ourPowerStates,
1168 number_of_power_states );
1169 }
1170
1171 IOReturn BMacEnet::setPowerState( unsigned long powerStateOrdinal,
1172 IOService * whatDevice )
1173 {
1174 IOReturn ret = IOPMAckImplied;
1175
1176 // kprintf("Ethernet(BMac): setPowerState %d\n", powerStateOrdinal);
1177
1178 if ( currentPowerState == powerStateOrdinal )
1179 return IOPMAckImplied;
1180
1181 switch ( powerStateOrdinal )
1182 {
1183 case 0:
1184 kprintf("Ethernet(BMac): powering off\n");
1185 currentPowerState = powerStateOrdinal;
1186 break;
1187
1188 case 1:
1189 kprintf("Ethernet(BMac): powering on\n");
1190 currentPowerState = powerStateOrdinal;
1191 break;
1192
1193 default:
1194 ret = IOPMNoSuchState;
1195 break;
1196 }
1197
1198 return ret;
1199 }