]>
Commit | Line | Data |
---|---|---|
1c79356b A |
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) 1995-1996 NeXT Software, Inc. | |
24 | * | |
25 | * Hardware independent (relatively) code for the Mace Ethernet Controller | |
26 | * | |
27 | * HISTORY | |
28 | * | |
29 | * dd-mmm-yy | |
30 | * Created. | |
31 | * | |
32 | */ | |
33 | ||
34 | #include <IOKit/assert.h> | |
35 | #include <IOKit/platform/AppleMacIODevice.h> | |
36 | #include "MaceEnetPrivate.h" | |
37 | ||
38 | //------------------------------------------------------------------------ | |
39 | ||
40 | #define super IOEthernetController | |
41 | ||
42 | OSDefineMetaClassAndStructors( MaceEnet, IOEthernetController ) | |
43 | ||
44 | //------------------------------------------------------------------------ | |
45 | ||
46 | #define PROVIDER_DEV 0 | |
47 | #define PROVIDER_DMA_TX 1 | |
48 | #define PROVIDER_DMA_RX 2 | |
49 | ||
50 | /* | |
51 | * Public Instance Methods | |
52 | */ | |
53 | ||
54 | bool MaceEnet::init(OSDictionary * properties) | |
55 | { | |
56 | if (!super::init(properties)) | |
57 | return false; | |
58 | ||
59 | isPromiscuous = false; | |
60 | multicastEnabled = false; | |
61 | ready = false; | |
62 | debugClient = false; | |
63 | debugTxPoll = false; | |
64 | netifClient = false; | |
65 | ||
66 | return true; | |
67 | } | |
68 | ||
69 | MaceEnet * MaceEnet::probe(IOService * /*provider*/, | |
70 | unsigned int * /*score*/, | |
71 | unsigned int * /*specificity*/) | |
72 | { | |
73 | #ifdef OLD_CODE | |
74 | extern int kdp_flag; | |
75 | ||
76 | /* | |
77 | * If bootargs: kdp bit 0 using in-kernel mace driver for early debugging, | |
78 | * Don't probe this driver. | |
79 | */ | |
80 | if( kdp_flag & 1) | |
81 | { | |
82 | return 0; | |
83 | } | |
84 | #endif | |
85 | ||
86 | return this; | |
87 | } | |
88 | ||
89 | bool MaceEnet::start(IOService * provider) | |
90 | { | |
91 | AppleMacIODevice *nub = OSDynamicCast(AppleMacIODevice, provider); | |
92 | ||
93 | if (!nub || !super::start(provider)) | |
94 | return false; | |
95 | ||
96 | transmitQueue = OSDynamicCast(IOGatedOutputQueue, getOutputQueue()); | |
97 | if (!transmitQueue) | |
98 | { | |
99 | IOLog("Mace: output queue initialization failed\n"); | |
100 | return false; | |
101 | } | |
102 | transmitQueue->retain(); | |
103 | ||
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. | |
107 | // | |
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. | |
111 | // | |
112 | debugQueue = IOPacketQueue::withCapacity((UInt) -1); | |
113 | if (!debugQueue) | |
114 | return false; | |
115 | ||
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). | |
119 | ||
120 | mbufCursor = IOMbufBigMemoryCursor::withSpecification(NETWORK_BUFSIZE, 2); | |
121 | if (!mbufCursor) | |
122 | { | |
123 | IOLog("Mace: IOMbufMemoryCursor allocation failed\n"); | |
124 | return false; | |
125 | } | |
126 | ||
127 | // | |
128 | // Our provider is the nub representing the MaceEnet hardware | |
129 | // controller. We will query it for our resource information. | |
130 | // | |
131 | ||
132 | for (int i = 0; i < MEMORY_MAP_COUNT; i++) { | |
133 | IOMemoryMap * map; | |
134 | ||
135 | map = provider->mapDeviceMemoryWithIndex(i); | |
136 | if (!map) | |
137 | return false; | |
138 | ||
139 | #ifdef DEBUG_XXX | |
140 | IOLog("map %d: Phys:%08x Virt:%08x len:%d\n", | |
141 | i, | |
142 | (UInt) map->getPhysicalAddress(), | |
143 | (UInt) map->getVirtualAddress(), | |
144 | (UInt) map->getLength()); | |
145 | #endif | |
146 | ||
147 | switch (i) { | |
148 | case MEMORY_MAP_ENET_INDEX: | |
149 | ioBaseEnet = (IOPPCAddress) map->getVirtualAddress(); | |
150 | ioBaseEnetROM = (IOPPCAddress) ((map->getPhysicalAddress() & | |
151 | ~0xffff) | kControllerROMOffset); | |
152 | break; | |
153 | ||
154 | case MEMORY_MAP_TXDMA_INDEX: | |
155 | ioBaseEnetTxDMA = (IODBDMAChannelRegisters *) | |
156 | map->getVirtualAddress(); | |
157 | break; | |
158 | ||
159 | case MEMORY_MAP_RXDMA_INDEX: | |
160 | ioBaseEnetRxDMA = (IODBDMAChannelRegisters *) | |
161 | map->getVirtualAddress(); | |
162 | break; | |
163 | } | |
164 | ||
165 | maps[i] = map; | |
166 | } | |
167 | ||
168 | // Manually create an IODeviceMemory for the ROM memory | |
169 | // range. | |
170 | // | |
171 | IODeviceMemory * romMemory = IODeviceMemory::withRange( | |
172 | (UInt) ioBaseEnetROM, 0x1000); | |
173 | if (!romMemory) { | |
174 | IOLog("Mace: can't create ROM memory object\n"); | |
175 | return false; | |
176 | } | |
177 | ||
178 | romMap = romMemory->map(); | |
179 | romMemory->release(); | |
180 | ||
181 | if (!romMap) | |
182 | return false; | |
183 | ||
184 | ioBaseEnetROM = (IOPPCAddress) romMap->getVirtualAddress(); | |
185 | ||
186 | #ifdef DEBUG_XXX | |
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); | |
191 | #endif | |
192 | ||
193 | // | |
194 | // Get a reference to the IOWorkLoop in our superclass. | |
195 | // | |
196 | IOWorkLoop * myWorkLoop = (IOWorkLoop *) getWorkLoop(); | |
197 | assert(myWorkLoop); | |
198 | ||
199 | // | |
200 | // Allocate two IOInterruptEventSources. | |
201 | // | |
202 | txIntSrc = IOInterruptEventSource::interruptEventSource | |
203 | (this, | |
204 | (IOInterruptEventAction) &MaceEnet::interruptOccurredForSource, | |
205 | provider, PROVIDER_DMA_TX); | |
206 | if (!txIntSrc | |
207 | || (myWorkLoop->addEventSource(txIntSrc) != kIOReturnSuccess)) { | |
208 | IOLog("Mace: txIntSrc init failure\n"); | |
209 | return false; | |
210 | } | |
211 | ||
212 | rxIntSrc = IOInterruptEventSource::interruptEventSource | |
213 | (this, | |
214 | (IOInterruptEventAction) &MaceEnet::interruptOccurredForSource, | |
215 | provider, PROVIDER_DMA_RX); | |
216 | if (!rxIntSrc | |
217 | || (myWorkLoop->addEventSource(rxIntSrc) != kIOReturnSuccess)) { | |
218 | IOLog("Mace: rxIntSrc init failure\n"); | |
219 | return false; | |
220 | } | |
221 | ||
222 | timerSrc = IOTimerEventSource::timerEventSource | |
223 | (this, (IOTimerEventSource::Action) &MaceEnet::timeoutOccurred); | |
224 | if (!timerSrc | |
225 | || (myWorkLoop->addEventSource(timerSrc) != kIOReturnSuccess)) { | |
226 | IOLog("Mace: timerSrc init failure\n"); | |
227 | return false; | |
228 | } | |
229 | ||
230 | MGETHDR(txDebuggerPkt, M_DONTWAIT, MT_DATA); | |
231 | if (!txDebuggerPkt) | |
232 | { | |
233 | IOLog("Mace: Can't allocate KDB buffer\n"); | |
234 | return false; | |
235 | } | |
236 | ||
237 | #if 0 | |
238 | // Do not enable interrupt sources until the hardware | |
239 | // is enabled. | |
240 | ||
241 | // Enable the interrupt event sources. | |
242 | myWorkLoop->enableAllInterrupts(); | |
243 | #endif | |
244 | ||
245 | #if 0 | |
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. | |
250 | ||
251 | // | |
252 | // Perform a hardware reset. | |
253 | // | |
254 | if ( !resetAndEnable(false) ) | |
255 | { | |
256 | return false; | |
257 | } | |
258 | #endif | |
259 | ||
260 | // Cache my MAC address. | |
261 | // | |
262 | getHardwareAddress(&myAddress); | |
263 | ||
264 | // | |
265 | // Allocate memory for ring buffers. | |
266 | // | |
267 | if (_allocateMemory() == false) | |
268 | { | |
269 | return false; | |
270 | } | |
271 | ||
272 | // | |
273 | // Attach a kernel debugger client. | |
274 | // | |
275 | attachDebuggerClient(&debugger); | |
276 | ||
277 | // | |
278 | // Allocate and initialize an IONetworkInterface object. | |
279 | // | |
280 | if (!attachInterface((IONetworkInterface **) &networkInterface)) | |
281 | return false; | |
282 | ||
283 | return true; | |
284 | } | |
285 | ||
286 | /*------------------------------------------------------------------------- | |
287 | * | |
288 | * | |
289 | * | |
290 | *-------------------------------------------------------------------------*/ | |
291 | ||
292 | void MaceEnet::free() | |
293 | { | |
294 | UInt i; | |
295 | ||
296 | timerSrc->cancelTimeout(); | |
297 | ||
298 | _resetChip(); | |
299 | ||
300 | if (debugger) | |
301 | debugger->release(); | |
302 | ||
303 | if (timerSrc) | |
304 | timerSrc->release(); | |
305 | ||
306 | if (rxIntSrc) | |
307 | rxIntSrc->release(); | |
308 | ||
309 | if (txIntSrc) | |
310 | txIntSrc->release(); | |
311 | ||
312 | if (transmitQueue) | |
313 | transmitQueue->release(); | |
314 | ||
315 | if (debugQueue) | |
316 | debugQueue->release(); | |
317 | ||
318 | if (networkInterface) | |
319 | networkInterface->release(); | |
320 | ||
321 | if (mbufCursor) | |
322 | mbufCursor->release(); | |
323 | ||
324 | if (txDebuggerPkt) | |
325 | freePacket(txDebuggerPkt); | |
326 | ||
327 | for (i = 0; i < rxMaxCommand; i++) | |
328 | if (rxMbuf[i]) freePacket(rxMbuf[i]); | |
329 | ||
330 | for (i = 0; i < txMaxCommand; i++) | |
331 | if (txMbuf[i]) freePacket(txMbuf[i]); | |
332 | ||
333 | if (romMap) romMap->release(); | |
334 | ||
335 | for (i = 0; i < MEMORY_MAP_COUNT; i++) | |
336 | if (maps[i]) maps[i]->release(); | |
337 | ||
338 | if (dmaMemory.ptr) | |
339 | { | |
340 | IOFree(dmaMemory.ptrReal, dmaMemory.sizeReal); | |
341 | dmaMemory.ptr = 0; | |
342 | } | |
343 | ||
344 | if ( workLoop ) | |
345 | { | |
346 | workLoop->release(); | |
347 | workLoop = 0; | |
348 | } | |
349 | ||
350 | super::free(); | |
351 | } | |
352 | ||
353 | /*------------------------------------------------------------------------- | |
354 | * Override IONetworkController::createWorkLoop() method and create | |
355 | * a workloop. | |
356 | * | |
357 | *-------------------------------------------------------------------------*/ | |
358 | ||
359 | bool MaceEnet::createWorkLoop() | |
360 | { | |
361 | workLoop = IOWorkLoop::workLoop(); | |
362 | ||
363 | return ( workLoop != 0 ); | |
364 | } | |
365 | ||
366 | /*------------------------------------------------------------------------- | |
367 | * Override IOService::getWorkLoop() method to return our workloop. | |
368 | * | |
369 | * | |
370 | *-------------------------------------------------------------------------*/ | |
371 | ||
372 | IOWorkLoop * MaceEnet::getWorkLoop() const | |
373 | { | |
374 | return workLoop; | |
375 | } | |
376 | ||
377 | /*------------------------------------------------------------------------- | |
378 | * | |
379 | * | |
380 | * | |
381 | *-------------------------------------------------------------------------*/ | |
382 | ||
383 | void MaceEnet::interruptOccurredForSource(IOInterruptEventSource *src, | |
384 | int /*count*/) | |
385 | { | |
386 | bool doFlushQueue = false; | |
387 | bool doService = false; | |
388 | ||
389 | // IOLog("Mace: interrupt %08x %d\n", (UInt) src, count); | |
390 | ||
391 | if (!ready) { | |
392 | // IOLog("Mace: unexpected interrupt\n"); | |
393 | return; | |
394 | } | |
395 | ||
396 | reserveDebuggerLock(); | |
397 | ||
398 | if (src == txIntSrc) { | |
399 | txWDInterrupts++; | |
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 ); | |
403 | } | |
404 | else { | |
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 ); | |
408 | } | |
409 | ||
410 | releaseDebuggerLock(); | |
411 | ||
412 | /* | |
413 | * Submit all received packets queued up by _receiveInterruptOccurred() | |
414 | * to the network stack. The up call is performed without holding the | |
415 | * debugger lock. | |
416 | */ | |
417 | if (doFlushQueue) | |
418 | networkInterface->flushInputQueue(); | |
419 | ||
420 | /* | |
421 | * Make sure the output queue is not stalled. | |
422 | */ | |
423 | if (doService && netifClient) | |
424 | transmitQueue->service(); | |
425 | } | |
426 | ||
427 | /*------------------------------------------------------------------------- | |
428 | * | |
429 | * | |
430 | * | |
431 | *-------------------------------------------------------------------------*/ | |
432 | ||
433 | UInt32 MaceEnet::outputPacket(struct mbuf *pkt, void *param) | |
434 | { | |
435 | u_int32_t i; | |
436 | u_int8_t regValue; | |
437 | UInt32 ret = kIOReturnOutputSuccess; | |
438 | ||
439 | // IOLog("Mace: outputPacket %d\n", pkt->m_pkthdr.len); | |
440 | ||
441 | KERNEL_DEBUG(DBG_MACE_TXQUEUE | DBG_FUNC_NONE, (int) pkt, | |
442 | (int) pkt->m_pkthdr.len, 0, 0, 0 ); | |
443 | ||
444 | /* | |
445 | * Hold the debugger lock so the debugger can't interrupt us | |
446 | */ | |
447 | reserveDebuggerLock(); | |
448 | ||
449 | do | |
450 | { | |
451 | /* | |
452 | * Someone is turning off the receiver before the first transmit. | |
453 | * Dont know who yet! | |
454 | */ | |
455 | regValue = ReadMaceRegister( ioBaseEnet, kMacCC ); | |
456 | regValue |= kMacCCEnRcv; | |
457 | WriteMaceRegister( ioBaseEnet, kMacCC, regValue ); | |
458 | ||
459 | /* | |
460 | * Preliminary sanity checks | |
461 | */ | |
462 | assert(pkt && netifClient); | |
463 | ||
464 | /* | |
465 | * Remove any completed packets from the Tx ring | |
466 | */ | |
467 | _transmitInterruptOccurred(); | |
468 | ||
469 | i = txCommandTail + 1; | |
470 | if ( i >= txMaxCommand ) i = 0; | |
471 | if ( i == txCommandHead ) | |
472 | { | |
473 | ret = kIOReturnOutputStall; | |
474 | continue; | |
475 | } | |
476 | ||
477 | /* | |
478 | * If there is space on the Tx ring, add the packet directly to the | |
479 | * ring | |
480 | */ | |
481 | _transmitPacket(pkt); | |
482 | } | |
483 | while ( 0 ); | |
484 | ||
485 | releaseDebuggerLock(); | |
486 | ||
487 | return ret; | |
488 | } | |
489 | ||
490 | /*------------------------------------------------------------------------- | |
491 | * Called by IOEthernetInterface client to enable the controller. | |
492 | * This method is always called while running on the default workloop | |
493 | * thread. | |
494 | *-------------------------------------------------------------------------*/ | |
495 | ||
496 | IOReturn MaceEnet::enable(IONetworkInterface * netif) | |
497 | { | |
498 | IONetworkParameter * param; | |
499 | ||
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. | |
503 | // | |
504 | if (netifClient) { | |
505 | IOLog("Mace: already enabled\n"); | |
506 | return kIOReturnSuccess; | |
507 | } | |
508 | ||
509 | param = netif->getParameter(kIONetworkStatsKey); | |
510 | if (!param || !(netStats = (IONetworkStats *) param->getBuffer())) | |
511 | { | |
512 | IOLog("Mace: invalid network statistics\n"); | |
513 | return kIOReturnError; | |
514 | } | |
515 | ||
516 | if ((ready == false) && !resetAndEnable(true)) | |
517 | return kIOReturnIOError; | |
518 | ||
519 | // Record the interface as an active client. | |
520 | // | |
521 | netifClient = true; | |
522 | ||
523 | // Start our IOOutputQueue object. | |
524 | // | |
525 | transmitQueue->setCapacity(TRANSMIT_QUEUE_SIZE); | |
526 | transmitQueue->start(); | |
527 | ||
528 | return kIOReturnSuccess; | |
529 | } | |
530 | ||
531 | /*------------------------------------------------------------------------- | |
532 | * Called by IOEthernetInterface client to disable the controller. | |
533 | * This method is always called while running on the default workloop | |
534 | * thread. | |
535 | *-------------------------------------------------------------------------*/ | |
536 | ||
537 | IOReturn MaceEnet::disable(IONetworkInterface * /*netif*/) | |
538 | { | |
539 | // If we have no active clients, then disable the controller. | |
540 | // | |
541 | if (debugClient == false) | |
542 | resetAndEnable(false); | |
543 | ||
544 | // Disable our IOOutputQueue object. | |
545 | // | |
546 | transmitQueue->stop(); | |
547 | ||
548 | // Flush all packets currently in the output queue. | |
549 | // | |
550 | transmitQueue->setCapacity(0); | |
551 | transmitQueue->flush(); | |
552 | ||
553 | netifClient = false; | |
554 | ||
555 | return kIOReturnSuccess; | |
556 | } | |
557 | ||
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() | |
562 | * call. | |
563 | * | |
564 | * This method is always called while running on the default workloop | |
565 | * thread. | |
566 | *-------------------------------------------------------------------------*/ | |
567 | ||
568 | IOReturn MaceEnet::enable(IOKernelDebugger * /*debugger*/) | |
569 | { | |
570 | // Enable hardware and make it ready to support the debugger client. | |
571 | // | |
572 | if ((ready == false) && !resetAndEnable(true)) | |
573 | return kIOReturnIOError; | |
574 | ||
575 | // Record the debugger as an active client of ours. | |
576 | // | |
577 | debugClient = true; | |
578 | ||
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 | |
582 | // return NULL. | |
583 | // | |
584 | return kIOReturnSuccess; | |
585 | } | |
586 | ||
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(). | |
590 | * | |
591 | * This method is always called while running on the default workloop | |
592 | * thread. | |
593 | *-------------------------------------------------------------------------*/ | |
594 | ||
595 | IOReturn MaceEnet::disable(IOKernelDebugger * /*debugger*/) | |
596 | { | |
597 | debugClient = false; | |
598 | ||
599 | // If we have no active clients, then disable the controller. | |
600 | // | |
601 | if (netifClient == false) | |
602 | resetAndEnable(false); | |
603 | ||
604 | return kIOReturnSuccess; | |
605 | } | |
606 | ||
607 | /*------------------------------------------------------------------------- | |
608 | * | |
609 | * | |
610 | * | |
611 | *-------------------------------------------------------------------------*/ | |
612 | ||
613 | bool MaceEnet::resetAndEnable(bool enable) | |
614 | { | |
615 | bool ret = true; | |
616 | ||
617 | if (timerSrc) | |
618 | timerSrc->cancelTimeout(); | |
619 | ||
620 | _disableAdapterInterrupts(); | |
621 | if (getWorkLoop()) getWorkLoop()->disableAllInterrupts(); | |
622 | ||
623 | reserveDebuggerLock(); | |
624 | ||
625 | ready = false; | |
626 | ||
627 | _resetChip(); | |
628 | ||
629 | do { | |
630 | if (!enable) break; | |
631 | ||
632 | if ( !_initRxRing() || !_initTxRing() || !_initChip() ) | |
633 | { | |
634 | ret = false; | |
635 | break; | |
636 | } | |
637 | ||
638 | _startChip(); | |
639 | ||
640 | ready = true; | |
641 | ||
642 | releaseDebuggerLock(); | |
643 | ||
644 | timerSrc->setTimeoutMS(WATCHDOG_TIMER_MS); | |
645 | ||
646 | if (getWorkLoop()) getWorkLoop()->enableAllInterrupts(); | |
647 | _enableAdapterInterrupts(); | |
648 | ||
649 | return true; | |
650 | } | |
651 | while (0); | |
652 | ||
653 | releaseDebuggerLock(); | |
654 | ||
655 | return ret; | |
656 | } | |
657 | ||
658 | /*------------------------------------------------------------------------- | |
659 | * | |
660 | * | |
661 | * | |
662 | *-------------------------------------------------------------------------*/ | |
663 | ||
664 | void MaceEnet::_sendTestPacket() | |
665 | { | |
666 | // IOOutputPacketStatus ret; | |
667 | unsigned char * buf; | |
668 | const unsigned int size = 64; | |
669 | ||
670 | struct mbuf * m = allocatePacket(size); | |
671 | if (!m) { | |
672 | IOLog("Mace: _sendTestpacket: allocatePacket() failed\n"); | |
673 | return; | |
674 | } | |
675 | ||
676 | buf = mtod(m, unsigned char *); | |
677 | ||
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; | |
682 | *buf++ = 0; | |
683 | *buf++ = 0; | |
684 | ||
685 | outputPacket(m, 0); | |
686 | } | |
687 | ||
688 | /*------------------------------------------------------------------------- | |
689 | * | |
690 | * | |
691 | * | |
692 | *-------------------------------------------------------------------------*/ | |
693 | ||
694 | void MaceEnet::timeoutOccurred(IOTimerEventSource * /*timer*/) | |
695 | { | |
696 | u_int32_t dmaStatus; | |
697 | bool doFlushQueue = false; | |
698 | bool doService = false; | |
699 | ||
700 | reserveDebuggerLock(); | |
701 | ||
702 | /* | |
703 | * Check for DMA shutdown on receive channel | |
704 | */ | |
705 | dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetRxDMA ); | |
706 | if ( !(dmaStatus & kdbdmaActive) ) | |
707 | { | |
708 | #if 0 | |
709 | IOLog("Mace: Timeout check - RxHead = %d RxTail = %d\n", | |
710 | rxCommandHead, rxCommandTail); | |
711 | #endif | |
712 | ||
713 | #if 0 | |
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)]; | |
716 | #endif | |
717 | ||
718 | doFlushQueue = _receiveInterruptOccurred(); | |
719 | } | |
720 | ||
721 | /* | |
722 | * If there are pending entries on the Tx ring | |
723 | */ | |
724 | if ( txCommandHead != txCommandTail ) | |
725 | { | |
726 | /* | |
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. | |
731 | */ | |
732 | if ( txWDInterrupts == 0 ) | |
733 | { | |
734 | if ( ++txWDTimeouts > 1 ) txWDForceReset = true; | |
735 | ||
736 | #if 0 | |
737 | IOLog( "Mace: Checking for timeout - TxHead = %d TxTail = %d\n", | |
738 | txCommandHead, txCommandTail); | |
739 | #endif | |
740 | doService = _transmitInterruptOccurred(); | |
741 | } | |
742 | else | |
743 | { | |
744 | txWDTimeouts = 0; | |
745 | txWDInterrupts = 0; | |
746 | } | |
747 | } | |
748 | else | |
749 | { | |
750 | txWDTimeouts = 0; | |
751 | txWDInterrupts = 0; | |
752 | } | |
753 | ||
754 | // Clean-up after the debugger if the debugger was active. | |
755 | // | |
756 | if (debugTxPoll) | |
757 | { | |
758 | debugQueue->flush(); | |
759 | debugTxPoll = false; | |
760 | releaseDebuggerLock(); | |
761 | doService = true; | |
762 | } | |
763 | else | |
764 | { | |
765 | releaseDebuggerLock(); | |
766 | } | |
767 | ||
768 | /* | |
769 | * Submit all received packets queued up by _receiveInterruptOccurred() | |
770 | * to the network stack. The up call is performed without holding the | |
771 | * debugger lock. | |
772 | */ | |
773 | if (doFlushQueue) | |
774 | { | |
775 | networkInterface->flushInputQueue(); | |
776 | } | |
777 | ||
778 | /* | |
779 | * Make sure the output queue is not stalled. | |
780 | */ | |
781 | if (doService && netifClient) | |
782 | { | |
783 | transmitQueue->service(); | |
784 | } | |
785 | ||
786 | /* | |
787 | * Restart the watchdog timer | |
788 | */ | |
789 | timerSrc->setTimeoutMS(WATCHDOG_TIMER_MS); | |
790 | } | |
791 | ||
792 | /*------------------------------------------------------------------------- | |
793 | * | |
794 | * | |
795 | * | |
796 | *-------------------------------------------------------------------------*/ | |
797 | ||
798 | const OSString * MaceEnet::newVendorString() const | |
799 | { | |
800 | return OSString::withCString("Apple"); | |
801 | } | |
802 | ||
803 | const OSString * MaceEnet::newModelString() const | |
804 | { | |
805 | return OSString::withCString("Mace"); | |
806 | } | |
807 | ||
808 | const OSString * MaceEnet::newRevisionString() const | |
809 | { | |
810 | return OSString::withCString(""); | |
811 | } | |
812 | ||
813 | /*------------------------------------------------------------------------- | |
814 | * | |
815 | * | |
816 | * | |
817 | *-------------------------------------------------------------------------*/ | |
818 | ||
819 | IOReturn MaceEnet::_setPromiscuousMode(IOEnetPromiscuousMode mode) | |
820 | { | |
821 | u_int8_t regVal; | |
822 | ||
823 | regVal = ReadMaceRegister( ioBaseEnet, kMacCC ); | |
824 | WriteMaceRegister( ioBaseEnet, kMacCC, regVal & ~kMacCCEnRcv ); | |
825 | if (mode == kIOEnetPromiscuousModeOff) { | |
826 | regVal &= ~kMacCCProm; | |
827 | isPromiscuous = false; | |
828 | } | |
829 | else { | |
830 | regVal |= kMacCCProm; | |
831 | isPromiscuous = true; | |
832 | } | |
833 | WriteMaceRegister( ioBaseEnet, kMacCC, regVal ); | |
834 | ||
835 | return kIOReturnSuccess; | |
836 | ||
837 | } | |
838 | ||
839 | IOReturn MaceEnet::setPromiscuousMode(IOEnetPromiscuousMode mode) | |
840 | { | |
841 | IOReturn ret; | |
842 | ||
843 | reserveDebuggerLock(); | |
844 | ret = _setPromiscuousMode(mode); | |
845 | releaseDebuggerLock(); | |
846 | ||
847 | return ret; | |
848 | } | |
849 | ||
850 | IOReturn MaceEnet::setMulticastMode(IOEnetMulticastMode mode) | |
851 | { | |
852 | multicastEnabled = (mode == kIOEnetMulticastModeOff) ? false : true; | |
853 | return kIOReturnSuccess; | |
854 | } | |
855 | ||
856 | IOReturn MaceEnet::setMulticastList(IOEthernetAddress *addrs, UInt32 count) | |
857 | { | |
858 | reserveDebuggerLock(); | |
859 | _resetHashTableMask(); | |
860 | for (UInt32 i = 0; i < count; i++) { | |
861 | _addToHashTableMask(addrs->bytes); | |
862 | addrs++; | |
863 | } | |
864 | _updateHashTableMask(); | |
865 | releaseDebuggerLock(); | |
866 | return kIOReturnSuccess; | |
867 | } | |
868 | ||
869 | /* | |
870 | * Allocate an IOOutputQueue object. | |
871 | */ | |
872 | IOOutputQueue * MaceEnet::createOutputQueue() | |
873 | { | |
874 | return IOGatedOutputQueue::withTarget( this, getWorkLoop() ); | |
875 | } | |
876 | ||
877 | /* | |
878 | * Kernel Debugger Support | |
879 | */ | |
880 | void MaceEnet::sendPacket(void *pkt, UInt32 pkt_len) | |
881 | { | |
882 | _sendPacket(pkt, pkt_len); | |
883 | } | |
884 | ||
885 | void MaceEnet::receivePacket(void *pkt, UInt32 *pkt_len, UInt32 timeout) | |
886 | { | |
887 | _receivePacket(pkt, (UInt *) pkt_len, timeout); | |
888 | } | |
889 | ||
890 | #if 0 // no power management stuff in IOKit yet. | |
891 | /* | |
892 | * Power management methods. | |
893 | */ | |
894 | - (IOReturn)getPowerState:(PMPowerState *)state_p | |
895 | { | |
896 | return kIOReturnUnsupported; | |
897 | } | |
898 | ||
899 | - (IOReturn)setPowerState:(PMPowerState)state | |
900 | { | |
901 | if (state == PM_OFF) { | |
902 | resetAndEnabled = NO; | |
903 | [self _resetChip]; | |
904 | return kIOReturnSuccess; | |
905 | } | |
906 | return kIOReturnUnsupported; | |
907 | } | |
908 | ||
909 | - (IOReturn)getPowerManagement:(PMPowerManagementState *)state_p | |
910 | { | |
911 | return kIOReturnUnsupported; | |
912 | } | |
913 | ||
914 | - (IOReturn)setPowerManagement:(PMPowerManagementState)state | |
915 | { | |
916 | return kIOReturnUnsupported; | |
917 | } | |
918 | #endif /* 0 */ |