2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1995-1996 NeXT Software, Inc.
25 * Hardware independent (relatively) code for the Mace Ethernet Controller
34 #include <IOKit/assert.h>
35 #include <IOKit/platform/AppleMacIODevice.h>
36 #include "MaceEnetPrivate.h"
38 //------------------------------------------------------------------------
40 #define super IOEthernetController
42 OSDefineMetaClassAndStructors( MaceEnet
, IOEthernetController
)
44 //------------------------------------------------------------------------
46 #define PROVIDER_DEV 0
47 #define PROVIDER_DMA_TX 1
48 #define PROVIDER_DMA_RX 2
51 * Public Instance Methods
54 bool MaceEnet::init(OSDictionary
* properties
)
56 if (!super::init(properties
))
59 isPromiscuous
= false;
60 multicastEnabled
= false;
69 MaceEnet
* MaceEnet::probe(IOService
* /*provider*/,
70 unsigned int * /*score*/,
71 unsigned int * /*specificity*/)
77 * If bootargs: kdp bit 0 using in-kernel mace driver for early debugging,
78 * Don't probe this driver.
89 bool MaceEnet::start(IOService
* provider
)
91 AppleMacIODevice
*nub
= OSDynamicCast(AppleMacIODevice
, provider
);
93 if (!nub
|| !super::start(provider
))
96 transmitQueue
= OSDynamicCast(IOGatedOutputQueue
, getOutputQueue());
99 IOLog("Mace: output queue initialization failed\n");
102 transmitQueue
->retain();
104 // Allocate debug queue. This stores packets retired from the TX ring
105 // by the polling routine. We cannot call freePacket() or m_free() within
106 // the debugger context.
108 // The capacity of the queue is set at maximum to prevent the queue from
109 // calling m_free() due to over-capacity. But we don't expect the size
110 // of the queue to grow too large.
112 debugQueue
= IOPacketQueue::withCapacity((UInt
) -1);
116 // Allocate a IOMbufBigMemoryCursor instance. Currently, the maximum
117 // number of segments is set to 2. The maximum length for each segment
118 // is set to the maximum ethernet frame size (plus padding).
120 mbufCursor
= IOMbufBigMemoryCursor::withSpecification(NETWORK_BUFSIZE
, 2);
123 IOLog("Mace: IOMbufMemoryCursor allocation failed\n");
128 // Our provider is the nub representing the MaceEnet hardware
129 // controller. We will query it for our resource information.
132 for (int i
= 0; i
< MEMORY_MAP_COUNT
; i
++) {
135 map
= provider
->mapDeviceMemoryWithIndex(i
);
140 IOLog("map %d: Phys:%08x Virt:%08x len:%d\n",
142 (UInt
) map
->getPhysicalAddress(),
143 (UInt
) map
->getVirtualAddress(),
144 (UInt
) map
->getLength());
148 case MEMORY_MAP_ENET_INDEX
:
149 ioBaseEnet
= (IOPPCAddress
) map
->getVirtualAddress();
150 ioBaseEnetROM
= (IOPPCAddress
) ((map
->getPhysicalAddress() &
151 ~0xffff) | kControllerROMOffset
);
154 case MEMORY_MAP_TXDMA_INDEX
:
155 ioBaseEnetTxDMA
= (IODBDMAChannelRegisters
*)
156 map
->getVirtualAddress();
159 case MEMORY_MAP_RXDMA_INDEX
:
160 ioBaseEnetRxDMA
= (IODBDMAChannelRegisters
*)
161 map
->getVirtualAddress();
168 // Manually create an IODeviceMemory for the ROM memory
171 IODeviceMemory
* romMemory
= IODeviceMemory::withRange(
172 (UInt
) ioBaseEnetROM
, 0x1000);
174 IOLog("Mace: can't create ROM memory object\n");
178 romMap
= romMemory
->map();
179 romMemory
->release();
184 ioBaseEnetROM
= (IOPPCAddress
) romMap
->getVirtualAddress();
187 IOLog("Mace: ioBaseEnet : %08x\n", (UInt
) ioBaseEnet
);
188 IOLog("Mace: ioBaseEnetTxDMA : %08x\n", (UInt
) ioBaseEnetTxDMA
);
189 IOLog("Mace: ioBaseEnetRxDMA : %08x\n", (UInt
) ioBaseEnetRxDMA
);
190 IOLog("Mace: ioBaseEnetROM : %08x\n", (UInt
) ioBaseEnetROM
);
194 // Get a reference to the IOWorkLoop in our superclass.
196 IOWorkLoop
* myWorkLoop
= (IOWorkLoop
*) getWorkLoop();
200 // Allocate two IOInterruptEventSources.
202 txIntSrc
= IOInterruptEventSource::interruptEventSource
204 (IOInterruptEventAction
) &MaceEnet::interruptOccurredForSource
,
205 provider
, PROVIDER_DMA_TX
);
207 || (myWorkLoop
->addEventSource(txIntSrc
) != kIOReturnSuccess
)) {
208 IOLog("Mace: txIntSrc init failure\n");
212 rxIntSrc
= IOInterruptEventSource::interruptEventSource
214 (IOInterruptEventAction
) &MaceEnet::interruptOccurredForSource
,
215 provider
, PROVIDER_DMA_RX
);
217 || (myWorkLoop
->addEventSource(rxIntSrc
) != kIOReturnSuccess
)) {
218 IOLog("Mace: rxIntSrc init failure\n");
222 timerSrc
= IOTimerEventSource::timerEventSource
223 (this, (IOTimerEventSource::Action
) &MaceEnet::timeoutOccurred
);
225 || (myWorkLoop
->addEventSource(timerSrc
) != kIOReturnSuccess
)) {
226 IOLog("Mace: timerSrc init failure\n");
230 MGETHDR(txDebuggerPkt
, M_DONTWAIT
, MT_DATA
);
233 IOLog("Mace: Can't allocate KDB buffer\n");
238 // Do not enable interrupt sources until the hardware
241 // Enable the interrupt event sources.
242 myWorkLoop
->enableAllInterrupts();
246 // Do not reset the hardware until we are ready to use it.
247 // Otherwise, we would have messed up kdp_mace driver's
248 // state. And we won't be able to break into the debugger
249 // until we attach our debugger client.
252 // Perform a hardware reset.
254 if ( !resetAndEnable(false) )
260 // Cache my MAC address.
262 getHardwareAddress(&myAddress
);
265 // Allocate memory for ring buffers.
267 if (_allocateMemory() == false)
273 // Attach a kernel debugger client.
275 attachDebuggerClient(&debugger
);
278 // Allocate and initialize an IONetworkInterface object.
280 if (!attachInterface((IONetworkInterface
**) &networkInterface
))
286 /*-------------------------------------------------------------------------
290 *-------------------------------------------------------------------------*/
292 void MaceEnet::free()
296 timerSrc
->cancelTimeout();
313 transmitQueue
->release();
316 debugQueue
->release();
318 if (networkInterface
)
319 networkInterface
->release();
322 mbufCursor
->release();
325 freePacket(txDebuggerPkt
);
327 for (i
= 0; i
< rxMaxCommand
; i
++)
328 if (rxMbuf
[i
]) freePacket(rxMbuf
[i
]);
330 for (i
= 0; i
< txMaxCommand
; i
++)
331 if (txMbuf
[i
]) freePacket(txMbuf
[i
]);
333 if (romMap
) romMap
->release();
335 for (i
= 0; i
< MEMORY_MAP_COUNT
; i
++)
336 if (maps
[i
]) maps
[i
]->release();
340 IOFree(dmaMemory
.ptrReal
, dmaMemory
.sizeReal
);
353 /*-------------------------------------------------------------------------
354 * Override IONetworkController::createWorkLoop() method and create
357 *-------------------------------------------------------------------------*/
359 bool MaceEnet::createWorkLoop()
361 workLoop
= IOWorkLoop::workLoop();
363 return ( workLoop
!= 0 );
366 /*-------------------------------------------------------------------------
367 * Override IOService::getWorkLoop() method to return our workloop.
370 *-------------------------------------------------------------------------*/
372 IOWorkLoop
* MaceEnet::getWorkLoop() const
377 /*-------------------------------------------------------------------------
381 *-------------------------------------------------------------------------*/
383 void MaceEnet::interruptOccurredForSource(IOInterruptEventSource
*src
,
386 bool doFlushQueue
= false;
387 bool doService
= false;
389 // IOLog("Mace: interrupt %08x %d\n", (UInt) src, count);
392 // IOLog("Mace: unexpected interrupt\n");
396 reserveDebuggerLock();
398 if (src
== txIntSrc
) {
400 KERNEL_DEBUG(DBG_MACE_TXIRQ
| DBG_FUNC_START
, 0, 0, 0, 0, 0 );
401 doService
= _transmitInterruptOccurred();
402 KERNEL_DEBUG(DBG_MACE_TXIRQ
| DBG_FUNC_END
, 0, 0, 0, 0, 0 );
405 KERNEL_DEBUG(DBG_MACE_RXIRQ
| DBG_FUNC_START
, 0, 0, 0, 0, 0 );
406 doFlushQueue
= _receiveInterruptOccurred();
407 KERNEL_DEBUG(DBG_MACE_RXIRQ
| DBG_FUNC_END
, 0, 0, 0, 0, 0 );
410 releaseDebuggerLock();
413 * Submit all received packets queued up by _receiveInterruptOccurred()
414 * to the network stack. The up call is performed without holding the
418 networkInterface
->flushInputQueue();
421 * Make sure the output queue is not stalled.
423 if (doService
&& netifClient
)
424 transmitQueue
->service();
427 /*-------------------------------------------------------------------------
431 *-------------------------------------------------------------------------*/
433 UInt32
MaceEnet::outputPacket(struct mbuf
*pkt
, void *param
)
437 UInt32 ret
= kIOReturnOutputSuccess
;
439 // IOLog("Mace: outputPacket %d\n", pkt->m_pkthdr.len);
441 KERNEL_DEBUG(DBG_MACE_TXQUEUE
| DBG_FUNC_NONE
, (int) pkt
,
442 (int) pkt
->m_pkthdr
.len
, 0, 0, 0 );
445 * Hold the debugger lock so the debugger can't interrupt us
447 reserveDebuggerLock();
452 * Someone is turning off the receiver before the first transmit.
455 regValue
= ReadMaceRegister( ioBaseEnet
, kMacCC
);
456 regValue
|= kMacCCEnRcv
;
457 WriteMaceRegister( ioBaseEnet
, kMacCC
, regValue
);
460 * Preliminary sanity checks
462 assert(pkt
&& netifClient
);
465 * Remove any completed packets from the Tx ring
467 _transmitInterruptOccurred();
469 i
= txCommandTail
+ 1;
470 if ( i
>= txMaxCommand
) i
= 0;
471 if ( i
== txCommandHead
)
473 ret
= kIOReturnOutputStall
;
478 * If there is space on the Tx ring, add the packet directly to the
481 _transmitPacket(pkt
);
485 releaseDebuggerLock();
490 /*-------------------------------------------------------------------------
491 * Called by IOEthernetInterface client to enable the controller.
492 * This method is always called while running on the default workloop
494 *-------------------------------------------------------------------------*/
496 IOReturn
MaceEnet::enable(IONetworkInterface
* netif
)
498 IONetworkParameter
* param
;
500 // If an interface client has previously enabled us,
501 // and we know there can only be one interface client
502 // for this driver, then simply return true.
505 IOLog("Mace: already enabled\n");
506 return kIOReturnSuccess
;
509 param
= netif
->getParameter(kIONetworkStatsKey
);
510 if (!param
|| !(netStats
= (IONetworkStats
*) param
->getBuffer()))
512 IOLog("Mace: invalid network statistics\n");
513 return kIOReturnError
;
516 if ((ready
== false) && !resetAndEnable(true))
517 return kIOReturnIOError
;
519 // Record the interface as an active client.
523 // Start our IOOutputQueue object.
525 transmitQueue
->setCapacity(TRANSMIT_QUEUE_SIZE
);
526 transmitQueue
->start();
528 return kIOReturnSuccess
;
531 /*-------------------------------------------------------------------------
532 * Called by IOEthernetInterface client to disable the controller.
533 * This method is always called while running on the default workloop
535 *-------------------------------------------------------------------------*/
537 IOReturn
MaceEnet::disable(IONetworkInterface
* /*netif*/)
539 // If we have no active clients, then disable the controller.
541 if (debugClient
== false)
542 resetAndEnable(false);
544 // Disable our IOOutputQueue object.
546 transmitQueue
->stop();
548 // Flush all packets currently in the output queue.
550 transmitQueue
->setCapacity(0);
551 transmitQueue
->flush();
555 return kIOReturnSuccess
;
558 /*-------------------------------------------------------------------------
559 * This method is called by our debugger client to bring up the controller
560 * just before the controller is registered as the debugger device. The
561 * debugger client is attached in response to the attachDebuggerClient()
564 * This method is always called while running on the default workloop
566 *-------------------------------------------------------------------------*/
568 IOReturn
MaceEnet::enable(IOKernelDebugger
* /*debugger*/)
570 // Enable hardware and make it ready to support the debugger client.
572 if ((ready
== false) && !resetAndEnable(true))
573 return kIOReturnIOError
;
575 // Record the debugger as an active client of ours.
579 // Returning true will allow the kdp registration to continue.
580 // If we return false, then we will not be registered as the
581 // debugger device, and the attachDebuggerClient() call will
584 return kIOReturnSuccess
;
587 /*-------------------------------------------------------------------------
588 * This method is called by our debugger client to stop the controller.
589 * The debugger will call this method when we issue a detachDebuggerClient().
591 * This method is always called while running on the default workloop
593 *-------------------------------------------------------------------------*/
595 IOReturn
MaceEnet::disable(IOKernelDebugger
* /*debugger*/)
599 // If we have no active clients, then disable the controller.
601 if (netifClient
== false)
602 resetAndEnable(false);
604 return kIOReturnSuccess
;
607 /*-------------------------------------------------------------------------
611 *-------------------------------------------------------------------------*/
613 bool MaceEnet::resetAndEnable(bool enable
)
618 timerSrc
->cancelTimeout();
620 _disableAdapterInterrupts();
621 if (getWorkLoop()) getWorkLoop()->disableAllInterrupts();
623 reserveDebuggerLock();
632 if ( !_initRxRing() || !_initTxRing() || !_initChip() )
642 releaseDebuggerLock();
644 timerSrc
->setTimeoutMS(WATCHDOG_TIMER_MS
);
646 if (getWorkLoop()) getWorkLoop()->enableAllInterrupts();
647 _enableAdapterInterrupts();
653 releaseDebuggerLock();
658 /*-------------------------------------------------------------------------
662 *-------------------------------------------------------------------------*/
664 void MaceEnet::_sendTestPacket()
666 // IOOutputPacketStatus ret;
668 const unsigned int size
= 64;
670 struct mbuf
* m
= allocatePacket(size
);
672 IOLog("Mace: _sendTestpacket: allocatePacket() failed\n");
676 buf
= mtod(m
, unsigned char *);
678 bcopy(&myAddress
, buf
, NUM_EN_ADDR_BYTES
);
679 buf
+= NUM_EN_ADDR_BYTES
;
680 bcopy(&myAddress
, buf
, NUM_EN_ADDR_BYTES
);
681 buf
+= NUM_EN_ADDR_BYTES
;
688 /*-------------------------------------------------------------------------
692 *-------------------------------------------------------------------------*/
694 void MaceEnet::timeoutOccurred(IOTimerEventSource
* /*timer*/)
697 bool doFlushQueue
= false;
698 bool doService
= false;
700 reserveDebuggerLock();
703 * Check for DMA shutdown on receive channel
705 dmaStatus
= IOGetDBDMAChannelStatus( ioBaseEnetRxDMA
);
706 if ( !(dmaStatus
& kdbdmaActive
) )
709 IOLog("Mace: Timeout check - RxHead = %d RxTail = %d\n",
710 rxCommandHead
, rxCommandTail
);
714 IOLog( "Mace: Rx Commands = %08x(p) Rx DMA Ptr = %08x(p)\n\r", rxDMACommandsPhys
, IOGetDBDMACommandPtr(ioBaseEnetRxDMA
) );
715 [self _dumpDesc
:(void *)rxDMACommands Size
:rxMaxCommand
* sizeof(enet_dma_cmd_t
)];
718 doFlushQueue
= _receiveInterruptOccurred();
722 * If there are pending entries on the Tx ring
724 if ( txCommandHead
!= txCommandTail
)
727 * If we did not service the Tx ring during the last timeout interval,
728 * then force servicing of the Tx ring.
729 * If we have more than one timeout interval without any transmit
730 * interrupts, then force the transmitter to reset.
732 if ( txWDInterrupts
== 0 )
734 if ( ++txWDTimeouts
> 1 ) txWDForceReset
= true;
737 IOLog( "Mace: Checking for timeout - TxHead = %d TxTail = %d\n",
738 txCommandHead
, txCommandTail
);
740 doService
= _transmitInterruptOccurred();
754 // Clean-up after the debugger if the debugger was active.
760 releaseDebuggerLock();
765 releaseDebuggerLock();
769 * Submit all received packets queued up by _receiveInterruptOccurred()
770 * to the network stack. The up call is performed without holding the
775 networkInterface
->flushInputQueue();
779 * Make sure the output queue is not stalled.
781 if (doService
&& netifClient
)
783 transmitQueue
->service();
787 * Restart the watchdog timer
789 timerSrc
->setTimeoutMS(WATCHDOG_TIMER_MS
);
792 /*-------------------------------------------------------------------------
796 *-------------------------------------------------------------------------*/
798 const OSString
* MaceEnet::newVendorString() const
800 return OSString::withCString("Apple");
803 const OSString
* MaceEnet::newModelString() const
805 return OSString::withCString("Mace");
808 const OSString
* MaceEnet::newRevisionString() const
810 return OSString::withCString("");
813 /*-------------------------------------------------------------------------
817 *-------------------------------------------------------------------------*/
819 IOReturn
MaceEnet::_setPromiscuousMode(IOEnetPromiscuousMode mode
)
823 regVal
= ReadMaceRegister( ioBaseEnet
, kMacCC
);
824 WriteMaceRegister( ioBaseEnet
, kMacCC
, regVal
& ~kMacCCEnRcv
);
825 if (mode
== kIOEnetPromiscuousModeOff
) {
826 regVal
&= ~kMacCCProm
;
827 isPromiscuous
= false;
830 regVal
|= kMacCCProm
;
831 isPromiscuous
= true;
833 WriteMaceRegister( ioBaseEnet
, kMacCC
, regVal
);
835 return kIOReturnSuccess
;
839 IOReturn
MaceEnet::setPromiscuousMode(IOEnetPromiscuousMode mode
)
843 reserveDebuggerLock();
844 ret
= _setPromiscuousMode(mode
);
845 releaseDebuggerLock();
850 IOReturn
MaceEnet::setMulticastMode(IOEnetMulticastMode mode
)
852 multicastEnabled
= (mode
== kIOEnetMulticastModeOff
) ? false : true;
853 return kIOReturnSuccess
;
856 IOReturn
MaceEnet::setMulticastList(IOEthernetAddress
*addrs
, UInt32 count
)
858 reserveDebuggerLock();
859 _resetHashTableMask();
860 for (UInt32 i
= 0; i
< count
; i
++) {
861 _addToHashTableMask(addrs
->bytes
);
864 _updateHashTableMask();
865 releaseDebuggerLock();
866 return kIOReturnSuccess
;
870 * Allocate an IOOutputQueue object.
872 IOOutputQueue
* MaceEnet::createOutputQueue()
874 return IOGatedOutputQueue::withTarget( this, getWorkLoop() );
878 * Kernel Debugger Support
880 void MaceEnet::sendPacket(void *pkt
, UInt32 pkt_len
)
882 _sendPacket(pkt
, pkt_len
);
885 void MaceEnet::receivePacket(void *pkt
, UInt32
*pkt_len
, UInt32 timeout
)
887 _receivePacket(pkt
, (UInt
*) pkt_len
, timeout
);
890 #if 0 // no power management stuff in IOKit yet.
892 * Power management methods.
894 - (IOReturn
)getPowerState
:(PMPowerState
*)state_p
896 return kIOReturnUnsupported
;
899 - (IOReturn
)setPowerState
:(PMPowerState
)state
901 if (state
== PM_OFF
) {
902 resetAndEnabled
= NO
;
904 return kIOReturnSuccess
;
906 return kIOReturnUnsupported
;
909 - (IOReturn
)getPowerManagement
:(PMPowerManagementState
*)state_p
911 return kIOReturnUnsupported
;
914 - (IOReturn
)setPowerManagement
:(PMPowerManagementState
)state
916 return kIOReturnUnsupported
;