|
|
1.1 root 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) 1999 Apple Computer, Inc. All rights reserved.
24: *
25: * HISTORY
26: *
27: */
28:
29: #include <IOKit/assert.h>
30: #include <IOKit/firewire/IOFireWireController.h>
31: #include <IOKit/firewire/IOFWIsochChannel.h>
32: #include <IOKit/firewire/IOFWIsochPort.h>
33: #include <libkern/c++/OSSet.h>
34: #include <libkern/c++/OSCollectionIterator.h>
35: #include <IOKit/firewire/IOFWCommand.h>
36: #include <IOKit/firewire/IOFireWireDevice.h>
37:
38: OSDefineMetaClassAndStructors(IOFWIsochChannel, OSObject)
39:
40: void IOFWIsochChannel::threadFunc(thread_call_param_t arg, thread_call_param_t)
41: {
42: ((IOFWIsochChannel *)arg)->reallocBandwidth();
43: }
44:
45: bool IOFWIsochChannel::init(IOFireWireController *control, bool doIRM,
46: UInt32 bandwidth, IOFWSpeed prefSpeed,
47: FWIsochChannelForceStopNotificationProcPtr stopProc, void *stopRefCon)
48: {
49: if(!OSObject::init())
50: return false;
51: fControl = control;
52: fDoIRM = doIRM;
53: fMBitSec = bandwidth;
54: fPrefSpeed = prefSpeed;
55: fStopProc = stopProc;
56: fStopRefCon = stopRefCon;
57: fTalker = NULL;
58: fListeners = OSSet::withCapacity(1);
59: fChannel = 64; // Illegal channel
60: return fListeners != NULL;
61: }
62:
63: void IOFWIsochChannel::free()
64: {
65: if(fListeners)
66: fListeners->release();
67: OSObject::free();
68: }
69:
70: IOReturn IOFWIsochChannel::setTalker(IOFWIsochPort *talker)
71: {
72: fTalker = talker;
73: return kIOReturnSuccess;
74: }
75:
76: IOReturn IOFWIsochChannel::addListener(IOFWIsochPort *listener)
77: {
78: if(fListeners->setObject(listener))
79: return kIOReturnSuccess;
80: else
81: return kIOReturnNoMemory;
82: }
83:
84: IOReturn IOFWIsochChannel::updateBandwidth(bool claim)
85: {
86: FWAddress addr(kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable);
87: IOFireWireDevice *irm; // The Isochronous Resource Manager, if there is one
88: IOFWReadQuadCommand *readCmd = NULL;
89: IOFWCompareAndSwapCommand *lockCmd = NULL;
90: UInt32 newVal;
91: UInt32 oldVal;
92: IOReturn result;
93: bool tryAgain;
94:
95: do {
96: irm = fControl->getIRMDevice();
97: if(fBandwidth != 0) {
98: if(irm != NULL) {
99: readCmd = irm->createReadQuadCommand(addr, &oldVal, 1);
100: if(!readCmd) {
101: result = kIOReturnNoMemory;
102: break;
103: }
104: readCmd->submit();
105: result = readCmd->fStatus;
106: readCmd->release();
107: readCmd = NULL;
108: if(kIOReturnSuccess != result) {
109: kprintf("read result 0x%x\n", result);
110: break;
111: }
112: }
113: do {
114: if(claim)
115: newVal = oldVal - fBandwidth;
116: else
117: newVal = oldVal + fBandwidth;
118: if(irm) {
119: lockCmd = fControl->getIRMDevice()->createCompareAndSwapCommand(addr, &oldVal, &newVal, 1);
120: if(!lockCmd) {
121: result = kIOReturnNoMemory;
122: break;
123: }
124: lockCmd->submit();
125: if(kIOReturnSuccess != lockCmd->fStatus)
126: kprintf("bandwidth update result 0x%x\n", lockCmd->fStatus);
127: tryAgain = !lockCmd->locked(&oldVal);
128: lockCmd->release();
129: lockCmd = NULL;
130: if(tryAgain) {
131: kprintf("bandwidth update failed, newval 0x%x\n", oldVal);
132: }
133: }
134: else
135: tryAgain = false;
136: } while (tryAgain);
137: if(!claim)
138: fBandwidth = 0;
139: }
140: if(fChannel != 64 && (irm != NULL)) {
141: UInt32 mask;
142: if(fChannel <= 31) {
143: addr.addressLo = kCSRChannelsAvailable31_0;
144: mask = 1 << (31-fChannel);
145: }
146: else {
147: addr.addressLo = kCSRChannelsAvailable63_32;
148: mask = 1 << (63-fChannel);
149: }
150: readCmd = irm->createReadQuadCommand(addr, &oldVal, 1);
151: if(!readCmd) {
152: result = kIOReturnNoMemory;
153: break;
154: }
155: readCmd->submit();
156: result = readCmd->fStatus;
157: if(kIOReturnSuccess != result) {
158: kprintf("read result 0x%x\n", result);
159: break;
160: }
161: do {
162: if(claim)
163: newVal = oldVal & ~mask;
164: else
165: newVal = oldVal | mask;
166: lockCmd = irm->createCompareAndSwapCommand(addr, &oldVal, &newVal, 1);
167: if(!lockCmd) {
168: result = kIOReturnNoMemory;
169: break;
170: }
171: lockCmd->submit();
172: if(kIOReturnSuccess != lockCmd->fStatus)
173: kprintf("channel update result 0x%x\n", lockCmd->fStatus);
174: tryAgain = !lockCmd->locked(&oldVal);
175: lockCmd->release();
176: lockCmd = NULL;
177: if(tryAgain) {
178: kprintf("channel update failed, newval 0x%x\n", oldVal);
179: }
180: } while (tryAgain);
181: if(!claim)
182: fChannel = 64;
183: }
184: } while (false);
185: if(readCmd)
186: readCmd->release();
187: if(lockCmd)
188: lockCmd->release();
189: return result;
190: }
191:
192: IOReturn IOFWIsochChannel::allocateChannel()
193: {
194: UInt64 portChans;
195: UInt64 allowedChans, savedChans;
196: IOFireWireDevice *irm; // The Isochronous Resource Manager, if there is one
197: IOFWReadQuadCommand *readCmd = NULL;
198: IOFWCompareAndSwapCommand *lockCmd = NULL;
199: UInt32 newVal;
200: FWAddress addr(kCSRRegisterSpaceBaseAddressHi, kCSRBandwidthAvailable);
201: OSIterator *listenIterator;
202: IOFWIsochPort *listen;
203: IOFWSpeed portSpeed;
204: UInt32 old[3];
205: UInt32 bandwidth;
206: UInt32 channel;
207: bool tryAgain; // For locks.
208: IOReturn result = kIOReturnSuccess;
209:
210: // Get best speed, minimum of requested speed and paths from talker to each listener
211: fSpeed = fPrefSpeed;
212:
213: do {
214: // reduce speed to minimum of so far and what all ports can do,
215: // and find valid channels
216: allowedChans = (UInt64)-1;
217: if(fTalker) {
218: fTalker->getSupported(portSpeed, portChans);
219: if(portSpeed < fSpeed)
220: fSpeed = portSpeed;
221: allowedChans &= portChans;
222: }
223: listenIterator = OSCollectionIterator::withCollection(fListeners);
224: if(listenIterator) {
225: while( (listen = (IOFWIsochPort *) listenIterator->getNextObject())) {
226: listen->getSupported(portSpeed, portChans);
227: if(portSpeed < fSpeed)
228: fSpeed = portSpeed;
229: allowedChans &= portChans;
230: }
231: }
232:
233: // reserve bandwidth, allocate a channel
234: if(fDoIRM && (irm = fControl->getIRMDevice())) {
235: savedChans = allowedChans; // In case we have to try a few times
236: // Careful of 32 bit overflow!
237: bandwidth = fMBitSec / (1000 * (1 << fSpeed));
238: bandwidth *= 6144;
239: bandwidth /= 100000;
240: //kprintf("Bandwidth is %d\n", bandwidth);
241: readCmd = irm->createReadQuadCommand(addr, old, 3);
242: if(!readCmd) {
243: result = kIOReturnNoMemory;
244: break;
245: }
246: readCmd->submit();
247: result = readCmd->fStatus;
248: if(kIOReturnSuccess != result) {
249: kprintf("read result 0x%x\n", readCmd->fStatus);
250: break;
251: }
252: //kprintf("Allocated Bandwidth is %d, channels are 0x%x 0x%x\n", old[0], old[1], old[2]);
253: allowedChans &= old[1] | ((UInt64)old[2] << 32);
254:
255: // Claim bandwidth
256: tryAgain = false;
257: do {
258: if(old[0] < bandwidth) {
259: result = kIOReturnNoSpace;
260: break;
261: }
262: newVal = old[0] - bandwidth;
263: lockCmd = irm->createCompareAndSwapCommand(addr, &old[0], &newVal, 1);
264: if(!lockCmd) {
265: result = kIOReturnNoMemory;
266: break;
267: }
268: lockCmd->submit();
269: if(kIOReturnSuccess != lockCmd->fStatus)
270: kprintf("bandwith update result 0x%x\n", lockCmd->fStatus);
271: tryAgain = !lockCmd->locked(&old[0]);
272: lockCmd->release();
273: lockCmd = NULL;
274: if(tryAgain) {
275: kprintf("Bandwith lock failed, newval 0x%x\n", old[0]);
276: }
277: } while (tryAgain);
278: if(kIOReturnSuccess != result)
279: break;
280: fBandwidth = bandwidth;
281: }
282:
283: tryAgain = false;
284: do {
285: for(channel=0; channel<64; channel++) {
286: if(allowedChans & (1<<(63-channel))) {
287: break;
288: }
289: }
290: kprintf("using channel %d\n", channel);
291: if(channel == 64) {
292: result = kIOReturnNoResources;
293: break;
294: }
295:
296: // Allocate a channel
297: if(fDoIRM && irm) {
298: UInt32 *oldPtr;
299: // Claim channel
300: if(channel < 32) {
301: addr.addressLo = kCSRChannelsAvailable31_0;
302: oldPtr = &old[1];
303: newVal = *oldPtr & ~(1<<(31-channel));
304: }
305: else {
306: addr.addressLo = kCSRChannelsAvailable63_32;
307: oldPtr = &old[2];
308: newVal = *oldPtr & ~(1<<(63-channel));
309: }
310: lockCmd = irm->createCompareAndSwapCommand(addr, oldPtr, &newVal, 1);
311: if(!lockCmd) {
312: result = kIOReturnNoMemory;
313: break;
314: }
315: lockCmd->submit();
316: if(kIOReturnSuccess != lockCmd->fStatus)
317: kprintf("channel update result 0x%x\n", lockCmd->fStatus);
318: tryAgain = !lockCmd->locked(oldPtr);
319: lockCmd->release();
320: lockCmd = NULL;
321: if(tryAgain) {
322: kprintf("channel update failed, newval 0x%x\n", old[0]);
323: }
324: }
325: else
326: tryAgain = false;
327: } while (tryAgain);
328: if(kIOReturnSuccess != result)
329: break;
330: fChannel = channel;
331: if(fDoIRM)
332: fControl->addAllocatedChannel(this);
333:
334: // allocate hardware resources for each port
335: if(listenIterator) {
336: listenIterator->reset();
337: while( (listen = (IOFWIsochPort *) listenIterator->getNextObject())) {
338: listen->allocatePort(fSpeed, fChannel);
339: }
340: listenIterator->release();
341: }
342: if(fTalker)
343: fTalker->allocatePort(fSpeed, fChannel);
344: } while (false);
345:
346: if(readCmd)
347: readCmd->release();
348: if(lockCmd)
349: lockCmd->release();
350:
351: return result;
352: }
353:
354:
355: IOReturn IOFWIsochChannel::releaseChannel()
356: {
357: OSIterator *listenIterator;
358: IOFWIsochPort *listen;
359: IOReturn result;
360:
361: if(fTalker) {
362: fTalker->releasePort();
363: }
364: listenIterator = OSCollectionIterator::withCollection(fListeners);
365: if(listenIterator) {
366: while( (listen = (IOFWIsochPort *) listenIterator->getNextObject())) {
367: listen->releasePort();
368: }
369: listenIterator->release();
370: }
371:
372: // release bandwidth and channel
373: if(fDoIRM) {
374: /*
375: * Tell the controller that we don't need to know about
376: * bus resets bedore doing anything else, since a bus reset
377: * sets us into the state we want (no allocated bandwidth).
378: */
379: fControl->removeAllocatedChannel(this);
380: updateBandwidth(false);
381: }
382: return kIOReturnSuccess;
383: }
384:
385: void IOFWIsochChannel::reallocBandwidth()
386: {
387: kprintf("reallocBandwidth\n");
388: updateBandwidth(true);
389: }
390:
391: void IOFWIsochChannel::handleBusReset()
392: {
393: kprintf("handleBusReset\n");
394: thread_call_func(threadFunc, this, true);
395: }
396:
397: IOReturn IOFWIsochChannel::start()
398: {
399: OSIterator *listenIterator;
400: IOFWIsochPort *listen;
401:
402: // Start all listeners, then start the talker
403: listenIterator = OSCollectionIterator::withCollection(fListeners);
404: if(listenIterator) {
405: listenIterator->reset();
406: while( (listen = (IOFWIsochPort *) listenIterator->getNextObject())) {
407: listen->start();
408: }
409: listenIterator->release();
410: }
411: if(fTalker)
412: fTalker->start();
413:
414: return kIOReturnSuccess;
415: }
416:
417: IOReturn IOFWIsochChannel::stop()
418: {
419: OSIterator *listenIterator;
420: IOFWIsochPort *listen;
421:
422: // Stop all listeners, then stop the talker
423: listenIterator = OSCollectionIterator::withCollection(fListeners);
424: if(listenIterator) {
425: while( (listen = (IOFWIsochPort *) listenIterator->getNextObject())) {
426: listen->stop();
427: }
428: listenIterator->release();
429: }
430: if(fTalker)
431: fTalker->stop();
432:
433: return kIOReturnSuccess;
434: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.