root/trunk/libffado/src/libieee1394/IsoHandlerManager.cpp

Revision 754, 18.8 kB (checked in by ppalmers, 13 years ago)

- simplify IsoHandler?
- fix some small issues

Line 
1 /*
2  * Copyright (C) 2005-2007 by Pieter Palmers
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include "IsoHandlerManager.h"
25 #include "ieee1394service.h"
26 #include "IsoHandler.h"
27 #include "libstreaming/generic/StreamProcessor.h"
28
29 #include "libutil/Atomic.h"
30
31 #include <assert.h>
32
33 #define MINIMUM_INTERRUPTS_PER_PERIOD  8U
34
35 IMPL_DEBUG_MODULE( IsoHandlerManager, IsoHandlerManager, DEBUG_LEVEL_NORMAL );
36
37 using namespace Streaming;
38
39 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service)
40    : m_State(E_Created)
41    , m_service( service )
42    , m_realtime(false), m_priority(0)
43 {}
44
45 IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio)
46    : m_State(E_Created)
47    , m_service( service )
48    , m_realtime(run_rt), m_priority(rt_prio)
49 {}
50
51 IsoHandlerManager::~IsoHandlerManager()
52 {
53     stopHandlers();
54 }
55
56 bool
57 IsoHandlerManager::setThreadParameters(bool rt, int priority) {
58     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) switch to: (rt=%d, prio=%d)...\n", this, rt, priority);
59     if (priority > 98) priority = 98; // cap the priority
60     m_realtime = rt;
61     m_priority = priority;
62     bool result = true;
63     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
64         it != m_IsoHandlers.end();
65         ++it )
66     {
67         result &= (*it)->setThreadParameters(m_realtime, m_priority);
68     }
69     return result;
70 }
71
72 bool IsoHandlerManager::init()
73 {
74     debugOutput( DEBUG_LEVEL_VERBOSE, "Initializing ISO manager %p...\n", this);
75     // check state
76     if(m_State != E_Created) {
77         debugError("Manager already initialized...\n");
78         return false;
79     }
80
81     m_State=E_Running;
82     return true;
83 }
84
85 bool
86 IsoHandlerManager::disable(IsoHandler *h) {
87     bool result;
88     int i=0;
89     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Disable on IsoHandler %p\n", h);
90     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
91         it != m_IsoHandlers.end();
92         ++it )
93     {
94         if ((*it) == h) {
95             result = h->disable();
96             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " disabled\n");
97             return result;
98         }
99         i++;
100     }
101     debugError("Handler not found\n");
102     return false;
103 }
104
105 bool
106 IsoHandlerManager::enable(IsoHandler *h) {
107     bool result;
108     int i=0;
109     debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Enable on IsoHandler %p\n", h);
110     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
111         it != m_IsoHandlers.end();
112         ++it )
113     {
114         if ((*it) == h) {
115             result = h->enable();
116             debugOutput(DEBUG_LEVEL_VERY_VERBOSE, " enabled\n");
117             return result;
118         }
119         i++;
120     }
121     debugError("Handler not found\n");
122     return false;
123 }
124
125 bool IsoHandlerManager::registerHandler(IsoHandler *handler)
126 {
127     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
128     assert(handler);
129     handler->setVerboseLevel(getDebugLevel());
130     m_IsoHandlers.push_back(handler);
131     return true;
132 }
133
134 bool IsoHandlerManager::unregisterHandler(IsoHandler *handler)
135 {
136     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
137     assert(handler);
138
139     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
140       it != m_IsoHandlers.end();
141       ++it )
142     {
143         if ( *it == handler ) {
144             m_IsoHandlers.erase(it);
145             return true;
146         }
147     }
148     debugFatal("Could not find handler (%p)\n", handler);
149     return false; //not found
150 }
151
152 /**
153  * Registers an StreamProcessor with the IsoHandlerManager.
154  *
155  * If nescessary, an IsoHandler is created to handle this stream.
156  * Once an StreamProcessor is registered to the handler, it will be included
157  * in the ISO streaming cycle (i.e. receive/transmit of it will occur).
158  *
159  * @param stream the stream to register
160  * @return true if registration succeeds
161  *
162  * \todo : currently there is a one-to-one mapping
163  *        between streams and handlers, this is not ok for
164  *        multichannel receive
165  */
166 bool IsoHandlerManager::registerStream(StreamProcessor *stream)
167 {
168     debugOutput( DEBUG_LEVEL_VERBOSE, "Registering stream %p\n",stream);
169     assert(stream);
170
171     IsoHandler* h = NULL;
172
173     // make sure the stream isn't already attached to a handler
174     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
175       it != m_IsoHandlers.end();
176       ++it )
177     {
178         if((*it)->isStreamRegistered(stream)) {
179             debugError( "stream already registered!\n");
180             return false;
181         }
182     }
183
184     // clean up all handlers that aren't used
185     pruneHandlers();
186
187     // allocate a handler for this stream
188     if (stream->getType()==StreamProcessor::ePT_Receive) {
189         // setup the optimal parameters for the raw1394 ISO buffering
190         unsigned int packets_per_period = stream->getPacketsPerPeriod();
191
192 #if 1
193         // hardware interrupts occur when one DMA block is full, and the size of one DMA
194         // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq
195         // occurs at a period boundary (optimal CPU use)
196
197         // NOTE: try and use MINIMUM_INTERRUPTS_PER_PERIOD hardware interrupts
198         //       per period for better latency.
199         unsigned int max_packet_size=(MINIMUM_INTERRUPTS_PER_PERIOD * getpagesize()) / packets_per_period;
200
201         if (max_packet_size < stream->getMaxPacketSize()) {
202             debugWarning("calculated max packet size (%u) < stream max packet size (%u)\n",
203                          max_packet_size ,(unsigned int)stream->getMaxPacketSize());
204             max_packet_size = stream->getMaxPacketSize();
205         }
206
207         // Ensure we don't request a packet size bigger than the
208         // kernel-enforced maximum which is currently 1 page.
209         if (max_packet_size > (unsigned int)getpagesize()) {
210             debugWarning("max packet size (%u) > page size (%u)\n", max_packet_size ,(unsigned int)getpagesize());
211             max_packet_size = getpagesize();
212         }
213
214         unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
215         if(irq_interval <= 0) irq_interval=1;
216         // FIXME: test
217         //irq_interval=1;
218
219 #else
220         // hardware interrupts occur when one DMA block is full, and the size of one DMA
221         // block = PAGE_SIZE. Setting the max_packet_size enables control over the IRQ
222         // frequency, as the controller uses max_packet_size, and not the effective size
223         // when writing to the DMA buffer.
224
225         // configure it such that we have an irq for every PACKETS_PER_INTERRUPT packets
226         unsigned int irq_interval=PACKETS_PER_INTERRUPT;
227
228         // unless the period size doesn't allow this
229         if ((packets_per_period/MINIMUM_INTERRUPTS_PER_PERIOD) < irq_interval) {
230             irq_interval=1;
231         }
232
233         // FIXME: test
234         irq_interval=1;
235 #warning Using fixed irq_interval
236
237         unsigned int max_packet_size=getpagesize() / irq_interval;
238
239         if (max_packet_size < stream->getMaxPacketSize()) {
240             max_packet_size=stream->getMaxPacketSize();
241         }
242
243         // Ensure we don't request a packet size bigger than the
244         // kernel-enforced maximum which is currently 1 page.
245         if (max_packet_size > (unsigned int)getpagesize())
246                     max_packet_size = getpagesize();
247
248 #endif
249         /* the receive buffer size doesn't matter for the latency,
250            but it has a minimal value in order for libraw to operate correctly (300) */
251         int buffers=400;
252         //max_packet_size = getpagesize(); // HACK
253         //irq_interval=2; // HACK
254         // create the actual handler
255         h = new IsoHandler(*this, IsoHandler::eHT_Receive,
256                            buffers, max_packet_size, irq_interval);
257         if(!h) {
258             debugFatal("Could not create IsoRecvHandler\n");
259             return false;
260         }
261         debugOutput( DEBUG_LEVEL_VERBOSE, " registering IsoRecvHandler\n");
262
263     } else if (stream->getType()==StreamProcessor::ePT_Transmit) {
264         // setup the optimal parameters for the raw1394 ISO buffering
265         unsigned int packets_per_period = stream->getPacketsPerPeriod();
266
267         // hardware interrupts occur when one DMA block is full, and the size of one DMA
268         // block = PAGE_SIZE. Setting the max_packet_size makes sure that the HW irq
269         // occurs at a period boundary (optimal CPU use)
270         // NOTE: try and use MINIMUM_INTERRUPTS_PER_PERIOD interrupts per period
271         //       for better latency.
272         unsigned int max_packet_size=MINIMUM_INTERRUPTS_PER_PERIOD * getpagesize() / packets_per_period;
273         if (max_packet_size < stream->getMaxPacketSize()) {
274             max_packet_size = stream->getMaxPacketSize();
275         }
276
277         // Ensure we don't request a packet size bigger than the
278         // kernel-enforced maximum which is currently 1 page.
279         if (max_packet_size > (unsigned int)getpagesize())
280                     max_packet_size = getpagesize();
281
282          unsigned int irq_interval = packets_per_period / MINIMUM_INTERRUPTS_PER_PERIOD;
283          if(irq_interval <= 0) irq_interval = 1;
284
285         // the transmit buffer size should be as low as possible for latency.
286         // note however that the raw1394 subsystem tries to keep this buffer
287         // full, so we have to make sure that we have enough events in our
288         // event buffers
289
290         // FIXME: latency spoiler
291         // every irq_interval packets an interrupt will occur. that is when
292         // buffers get transfered, meaning that we should have at least some
293         // margin here
294         //irq_interval=2;
295         //int buffers=30;
296         //max_packet_size = getpagesize(); // HACK
297
298         // the SP specifies how many packets to buffer
299         int buffers = stream->getNbPacketsIsoXmitBuffer();
300
301         // create the actual handler
302         h = new IsoHandler(*this, IsoHandler::eHT_Transmit,
303                            buffers, max_packet_size, irq_interval);
304
305         debugOutput( DEBUG_LEVEL_VERBOSE, " registering IsoXmitHandler\n");
306
307         if(!h) {
308             debugFatal("Could not create IsoXmitHandler\n");
309             return false;
310         }
311     } else {
312         debugFatal("Bad stream type\n");
313         return false;
314     }
315
316     h->setVerboseLevel(getDebugLevel());
317
318     // init the handler
319     if(!h->init()) {
320         debugFatal("Could not initialize receive handler\n");
321         return false;
322     }
323
324     // set the handler's thread parameters
325     if(!h->setThreadParameters(m_realtime, m_priority)) {
326         debugFatal("Could not set handler thread parameters\n");
327         return false;
328     }
329
330     // register the stream with the handler
331     if(!h->registerStream(stream)) {
332         debugFatal("Could not register receive stream with handler\n");
333         return false;
334     }
335
336     // register the handler with the manager
337     if(!registerHandler(h)) {
338         debugFatal("Could not register receive handler with manager\n");
339         return false;
340     }
341     debugOutput( DEBUG_LEVEL_VERBOSE, " registered stream (%p) with handler (%p)\n", stream, h);
342
343     m_StreamProcessors.push_back(stream);
344     debugOutput( DEBUG_LEVEL_VERBOSE, " %d streams, %d handlers registered\n",
345                                       m_StreamProcessors.size(), m_IsoHandlers.size());
346     return true;
347 }
348
349 bool IsoHandlerManager::unregisterStream(StreamProcessor *stream)
350 {
351     debugOutput( DEBUG_LEVEL_VERBOSE, "Unregistering stream %p\n",stream);
352     assert(stream);
353
354     // make sure the stream isn't attached to a handler anymore
355     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
356       it != m_IsoHandlers.end();
357       ++it )
358     {
359         if((*it)->isStreamRegistered(stream)) {
360             if(!(*it)->unregisterStream(stream)) {
361                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not unregister stream (%p) from handler (%p)...\n",stream,*it);
362                 return false;
363             }
364             debugOutput( DEBUG_LEVEL_VERBOSE, " unregistered stream (%p) from handler (%p)...\n",stream,*it);
365         }
366     }
367
368     // clean up all handlers that aren't used
369     pruneHandlers();
370
371     // remove the stream from the registered streams list
372     for ( StreamProcessorVectorIterator it = m_StreamProcessors.begin();
373       it != m_StreamProcessors.end();
374       ++it )
375     {
376         if ( *it == stream ) {
377             m_StreamProcessors.erase(it);
378             debugOutput( DEBUG_LEVEL_VERBOSE, " deleted stream (%p) from list...\n", *it);
379             return true;
380         }
381     }
382     return false; //not found
383 }
384
385 /**
386  * @brief unregister a handler from the manager
387  * @note called without the lock held.
388  */
389 void IsoHandlerManager::pruneHandlers() {
390     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
391     IsoHandlerVector toUnregister;
392
393     // find all handlers that are not in use
394     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
395           it != m_IsoHandlers.end();
396           ++it )
397     {
398         if(!((*it)->inUse())) {
399             debugOutput( DEBUG_LEVEL_VERBOSE, " handler (%p) not in use\n",*it);
400             toUnregister.push_back(*it);
401         }
402     }
403     // delete them
404     for ( IsoHandlerVectorIterator it = toUnregister.begin();
405           it != toUnregister.end();
406           ++it )
407     {
408         unregisterHandler(*it);
409
410         debugOutput( DEBUG_LEVEL_VERBOSE, " deleting handler (%p)\n",*it);
411
412         // Now the handler's been unregistered it won't be reused
413         // again.  Therefore it really needs to be formally deleted
414         // to free up the raw1394 handle.  Otherwise things fall
415         // apart after several xrun recoveries as the system runs
416         // out of resources to support all the disused but still
417         // allocated raw1394 handles.  At least this is the current
418         // theory as to why we end up with "memory allocation"
419         // failures after several Xrun recoveries.
420         delete *it;
421     }
422 }
423
424 bool
425 IsoHandlerManager::stopHandlerForStream(Streaming::StreamProcessor *stream) {
426     // check state
427     if(m_State != E_Running) {
428         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
429         return false;
430     }
431     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
432       it != m_IsoHandlers.end();
433       ++it )
434     {
435         if((*it)->isStreamRegistered(stream)) {
436             bool result;
437             debugOutput( DEBUG_LEVEL_VERBOSE, " stopping handler %p for stream %p\n", *it, stream);
438             result = (*it)->disable();
439             if(!result) {
440                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not disable handler (%p)\n",*it);
441                 return false;
442             }
443             return true;
444         }
445     }
446     debugError("Stream %p has no attached handler\n", stream);
447     return false;
448 }
449
450 int
451 IsoHandlerManager::getPacketLatencyForStream(Streaming::StreamProcessor *stream) {
452     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
453       it != m_IsoHandlers.end();
454       ++it )
455     {
456         if((*it)->isStreamRegistered(stream)) {
457             return (*it)->getPacketLatency();
458         }
459     }
460     debugError("Stream %p has no attached handler\n", stream);
461     return 0;
462 }
463
464 void
465 IsoHandlerManager::flushHandlerForStream(Streaming::StreamProcessor *stream) {
466     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
467       it != m_IsoHandlers.end();
468       ++it )
469     {
470         if((*it)->isStreamRegistered(stream)) {
471             return (*it)->flush();
472         }
473     }
474     debugError("Stream %p has no attached handler\n", stream);
475     return;
476 }
477
478 bool
479 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream) {
480     return startHandlerForStream(stream, -1);
481 }
482
483 bool
484 IsoHandlerManager::startHandlerForStream(Streaming::StreamProcessor *stream, int cycle) {
485     // check state
486     if(m_State != E_Running) {
487         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
488         return false;
489     }
490     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
491       it != m_IsoHandlers.end();
492       ++it )
493     {
494         if((*it)->isStreamRegistered(stream)) {
495             bool result;
496             debugOutput( DEBUG_LEVEL_VERBOSE, " starting handler %p for stream %p\n", *it, stream);
497             result = (*it)->enable(cycle);
498             if(!result) {
499                 debugOutput( DEBUG_LEVEL_VERBOSE, " could not enable handler (%p)\n",*it);
500                 return false;
501             }
502             return true;
503         }
504     }
505     debugError("Stream %p has no attached handler\n", stream);
506     return false;
507 }
508
509 bool IsoHandlerManager::stopHandlers() {
510     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
511
512     // check state
513     if(m_State != E_Running) {
514         debugError("Incorrect state, expected E_Running, got %s\n", eHSToString(m_State));
515         return false;
516     }
517
518     bool retval=true;
519
520     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
521         it != m_IsoHandlers.end();
522         ++it )
523     {
524         debugOutput( DEBUG_LEVEL_VERBOSE, "Stopping handler (%p)\n",*it);
525         if(!(*it)->disable()){
526             debugOutput( DEBUG_LEVEL_VERBOSE, " could not stop handler (%p)\n",*it);
527             retval=false;
528         }
529     }
530
531     if (retval) {
532         m_State=E_Prepared;
533     } else {
534         m_State=E_Error;
535     }
536     return retval;
537 }
538
539 bool IsoHandlerManager::reset() {
540     debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n");
541     // check state
542     if(m_State == E_Error) {
543         debugFatal("Resetting from error condition not yet supported...\n");
544         return false;
545     }
546     // if not in an error condition, reset means stop the handlers
547     return stopHandlers();
548 }
549
550 void IsoHandlerManager::setVerboseLevel(int i) {
551     setDebugLevel(i);
552     // propagate the debug level
553     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
554           it != m_IsoHandlers.end();
555           ++it )
556     {
557         (*it)->setVerboseLevel(i);
558     }
559 }
560
561 void IsoHandlerManager::dumpInfo() {
562     int i=0;
563     debugOutputShort( DEBUG_LEVEL_NORMAL, "Dumping IsoHandlerManager Stream handler information...\n");
564     debugOutputShort( DEBUG_LEVEL_NORMAL, " State: %d\n",(int)m_State);
565
566     for ( IsoHandlerVectorIterator it = m_IsoHandlers.begin();
567           it != m_IsoHandlers.end();
568           ++it )
569     {
570         debugOutputShort( DEBUG_LEVEL_NORMAL, " IsoHandler %d (%p)\n",i++,*it);
571         (*it)->dumpInfo();
572     }
573 }
574
575 const char *
576 IsoHandlerManager::eHSToString(enum eHandlerStates s) {
577     switch (s) {
578         default: return "Invalid";
579         case E_Created: return "Created";
580         case E_Prepared: return "Prepared";
581         case E_Running: return "Running";
582         case E_Error: return "Error";
583     }
584 }
Note: See TracBrowser for help on using the browser.