Show
Ignore:
Timestamp:
12/07/08 05:50:41 (15 years ago)
Author:
ppalmers
Message:

Merge all changes from 2.0 branch into trunk (since r1361). This _should_ contain all forward merges done in the mean time. At this moment in time both branches should be in sync.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/libffado/src/libieee1394/CycleTimerHelper.cpp

    r1348 r1498  
    357357    uint64_t local_time; 
    358358    int64_t usecs_late; 
    359     int ntries=4
     359    int ntries=10
    360360    uint64_t cycle_timer_ticks; 
    361     double diff_ticks; 
    362  
    363     // if the difference between the predicted value and the 
     361    int64_t err_ticks; 
     362    bool not_good; 
     363 
     364    // if the difference between the predicted value at readout time and the 
    364365    // actual value seems to be too large, retry reading the cycle timer 
    365366    // some host controllers return bogus values on some reads 
     
    373374        usecs_late = local_time - m_sleep_until; 
    374375        cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(cycle_timer); 
    375         diff_ticks = diffTicks(cycle_timer_ticks, (int64_t)m_next_time_ticks); 
     376 
     377        // calculate the CTR_TICKS we expect to read at "local_time" 
     378        // then calculate the difference with what we actually read, 
     379        // taking wraparound into account. If these deviate too much 
     380        // from eachother then read the register again (bogus read). 
     381        int64_t expected_ticks = getCycleTimerTicks(local_time); 
     382        err_ticks = diffTicks(cycle_timer_ticks, expected_ticks); 
    376383 
    377384        // check for unrealistic CTR reads (NEC controller does that sometimes) 
    378         if(diff_ticks < -((double)TICKS_PER_HALFCYCLE)) { 
    379             debugOutput(DEBUG_LEVEL_ULTRA_VERBOSE,  
    380                         "(%p) have to retry CTR read, diff unrealistic: diff: %f, max: %f (try: %d)\n",  
    381                         this, diff_ticks, -((double)TICKS_PER_HALFCYCLE), ntries); 
    382         } 
    383  
    384     } while( diff_ticks < -((double)TICKS_PER_HALFCYCLE)  
    385              && --ntries && !m_first_run && !m_unhandled_busreset); 
     385        not_good = (-err_ticks > 1*TICKS_PER_HALFCYCLE || err_ticks > 1*TICKS_PER_HALFCYCLE); 
     386        if(not_good) { 
     387            debugOutput(DEBUG_LEVEL_VERBOSE,  
     388                        "(%p) have to retry CTR read, diff unrealistic: diff: %lld, max: +/- %ld (try: %d) %lld\n",  
     389                        this, err_ticks, 1*TICKS_PER_CYCLE, ntries, expected_ticks); 
     390            // sleep half a cycle to make sure the hardware moved on 
     391            Util::SystemTimeSource::SleepUsecRelative(USECS_PER_CYCLE/2); 
     392        } 
     393 
     394    } while(not_good && --ntries && !m_first_run && !m_unhandled_busreset); 
    386395 
    387396    // grab the lock after sleeping, otherwise we can't be interrupted by 
     
    390399    // wakeup and read is as small as possible 
    391400    Util::MutexLockHelper lock(*m_update_lock); 
     401 
     402    // the difference between the measured and the expected time 
     403    int64_t diff_ticks = diffTicks(cycle_timer_ticks, (int64_t)m_next_time_ticks); 
    392404 
    393405    // // simulate a random scheduling delay between (0-10ms) 
     
    418430        } 
    419431        m_first_run = false; 
    420     } else if (diff_ticks > 20.0*m_ticks_per_update) { 
     432    } else if (diff_ticks > m_ticks_per_update * 20) { 
    421433        debugOutput(DEBUG_LEVEL_VERBOSE, 
    422                     "re-init dll due to too large tick diff: %f >> %f\n", 
    423                     diff_ticks, (float)(20.0*m_ticks_per_update)); 
     434                    "re-init dll due to too large tick diff: %lld >> %f\n", 
     435                    diff_ticks, (float)(m_ticks_per_update * 20)); 
    424436        if(!initDLL()) { 
    425437            debugError("(%p) Could not init DLL\n", this); 
     
    442454        // the corrected difference between predicted and actual ctr 
    443455        // i.e. DLL error signal 
    444         double diff_ticks_corr; 
     456        int64_t diff_ticks_corr; 
    445457        if (ticks_late > 0) { 
    446458            diff_ticks_corr = diff_ticks - ticks_late; 
    447459            debugOutputExtreme(DEBUG_LEVEL_ULTRA_VERBOSE, 
    448                                "diff_ticks_corr=%f, diff_ticks = %f, ticks_late = %lld\n", 
     460                               "diff_ticks_corr=%lld, diff_ticks = %lld, ticks_late = %lld\n", 
    449461                               diff_ticks_corr, diff_ticks, ticks_late); 
    450462        } else { 
     
    487499        // and coeff_b < 1, hence tmp is not near wrapping 
    488500 
    489         double step_ticks = (coeff_b * diff_ticks_corr); 
     501        double diff_ticks_corr_d =  (double)diff_ticks_corr; 
     502        double step_ticks = (coeff_b * diff_ticks_corr_d); 
    490503        debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, 
    491504                           "diff_ticks_corr=%f, step_ticks=%f\n", 
    492                            diff_ticks_corr, step_ticks); 
     505                           diff_ticks_corr_d, step_ticks); 
    493506 
    494507        // the same goes for m_dll_e2, which should be approx equal 
     
    515528 
    516529        // update the DLL state 
    517         m_dll_e2 += coeff_c * diff_ticks_corr
     530        m_dll_e2 += coeff_c * diff_ticks_corr_d
    518531 
    519532        // update the y-axis values 
     
    525538                           m_current_time_usecs, m_next_time_usecs, usecs_late, ticks_late); 
    526539        debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, 
    527                            " ticks: current: %f next: %f diff=%f\n", 
     540                           " ticks: current: %f next: %f diff=%lld\n", 
    528541                           m_current_time_ticks, m_next_time_ticks, diff_ticks); 
    529542        debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, 
  • trunk/libffado/src/libieee1394/ieee1394service.cpp

    r1441 r1498  
    3131#include "CycleTimerHelper.h" 
    3232 
    33 #include <libavc1394/avc1394.h> 
    3433#include <libraw1394/csr.h> 
    3534#include <libiec61883/iec61883.h> 
     
    3837#include "libutil/Watchdog.h" 
    3938#include "libutil/PosixMutex.h" 
     39#include "libutil/Configuration.h" 
    4040 
    4141#include <errno.h> 
     
    5252 
    5353Ieee1394Service::Ieee1394Service() 
    54     : m_handle( 0 ) 
     54    : m_configuration( NULL ) 
     55    , m_handle( 0 ) 
    5556    , m_handle_lock( new Util::PosixMutex("SRCVHND") ) 
    5657    , m_resetHandle( 0 ) 
     
    6465    , m_pCTRHelper ( new CycleTimerHelper( *this, IEEE1394SERVICE_CYCLETIMER_DLL_UPDATE_INTERVAL_USEC ) ) 
    6566    , m_have_new_ctr_read ( false ) 
     67    , m_filterFCPResponse ( false ) 
    6668    , m_pWatchdog ( new Util::Watchdog() ) 
    6769{ 
     
    7880 
    7981Ieee1394Service::Ieee1394Service(bool rt, int prio) 
    80     : m_handle( 0 ) 
     82    : m_configuration( NULL ) 
     83    , m_handle( 0 ) 
    8184    , m_handle_lock( new Util::PosixMutex("SRCVHND") ) 
    8285    , m_resetHandle( 0 ) 
     
    9093    , m_pCTRHelper ( new CycleTimerHelper( *this, IEEE1394SERVICE_CYCLETIMER_DLL_UPDATE_INTERVAL_USEC, 
    9194                                           rt && IEEE1394SERVICE_CYCLETIMER_HELPER_RUN_REALTIME, 
    92                                            prio + IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO_INCREASE ) ) 
     95                                           IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO ) ) 
    9396    , m_have_new_ctr_read ( false ) 
     97    , m_filterFCPResponse ( false ) 
    9498    , m_pWatchdog ( new Util::Watchdog() ) 
    9599{ 
     
    137141} 
    138142 
     143bool 
     144Ieee1394Service::useConfiguration(Util::Configuration *c) 
     145{ 
     146    m_configuration = c; 
     147    return configurationUpdated(); 
     148} 
     149 
     150bool 
     151Ieee1394Service::configurationUpdated() 
     152{ 
     153    if(m_configuration) { 
     154         
     155    } 
     156    return true; 
     157} 
     158 
    139159#define DEVICEFAILTEXT "Could not get libraw1394 handle.\n\ 
    140160This usually means:\n\ 
     
    190210        Util::SystemTimeSource::SleepUsecRelative( sleep_time_ms * 1000); 
    191211    } while (gen_current != getGeneration() && --nb_tries); 
     212 
     213    debugOutput(DEBUG_LEVEL_VERBOSE, "Bus reset storm over at gen: %u\n", gen_current); 
    192214 
    193215    if (!nb_tries) { 
     
    278300    raw1394handle_t tmp_handle = raw1394_new_handle(); 
    279301    if ( tmp_handle == NULL ) { 
    280         debugError("Could not get temporaty libraw1394 handle.\n"); 
     302        debugError("Could not get temporary libraw1394 handle.\n"); 
    281303        return false; 
    282304    } 
     
    299321    } 
    300322 
     323    // set userdata 
    301324    raw1394_set_userdata( m_handle, this ); 
    302325    raw1394_set_userdata( m_resetHandle, this ); 
     
    308331                                   this->armHandlerLowLevel ); 
    309332 
     333    int split_timeout = IEEE1394SERVICE_MIN_SPLIT_TIMEOUT_USECS; 
     334    if(m_configuration) { 
     335        m_configuration->getValueForSetting("ieee1394.min_split_timeout_usecs", split_timeout); 
     336    } 
     337 
     338    // set SPLIT_TIMEOUT to one second to cope with DM1x00 devices that 
     339    // send responses regardless of the timeout 
     340    int timeout = getSplitTimeoutUsecs(getLocalNodeId()); 
     341    debugOutput(DEBUG_LEVEL_VERBOSE, "Minimum SPLIT_TIMEOUT: %d. Current: %d\n", split_timeout, timeout); 
     342    if (timeout < split_timeout) { 
     343        if(!setSplitTimeoutUsecs(getLocalNodeId(), split_timeout+124)) { 
     344            debugWarning("Could not set SPLIT_TIMEOUT to min requested (%d)\n", split_timeout); 
     345        } 
     346        timeout = getSplitTimeoutUsecs(getLocalNodeId()); 
     347        if (timeout < split_timeout) { 
     348            debugWarning("Set SPLIT_TIMEOUT to min requested (%d) did not succeed\n", split_timeout); 
     349        } 
     350    } 
     351 
     352    // init helpers 
    310353    if(!m_pCTRHelper) { 
    311354        debugFatal("No CycleTimerHelper available, bad!\n"); 
     
    323366    } 
    324367    m_pIsoManager->setVerboseLevel(getDebugLevel()); 
     368 
    325369    if(!m_pIsoManager->init()) { 
    326370        debugFatal("Could not initialize IsoHandlerManager\n"); 
     
    342386    bool result = true; 
    343387    if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO; 
     388    if (priority < THREAD_MIN_RTPRIO) priority = THREAD_MIN_RTPRIO; 
    344389    m_base_priority = priority; 
    345390    m_realtime = rt; 
     
    352397        debugOutput(DEBUG_LEVEL_VERBOSE, "Switching CycleTimerHelper to (rt=%d, prio=%d)\n",  
    353398                                         rt && IEEE1394SERVICE_CYCLETIMER_HELPER_RUN_REALTIME, 
    354                                          priority + IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO_INCREASE); 
     399                                         IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO); 
    355400        result &= m_pCTRHelper->setThreadParameters(rt && IEEE1394SERVICE_CYCLETIMER_HELPER_RUN_REALTIME, 
    356                                                     priority + IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO_INCREASE); 
     401                                                    IEEE1394SERVICE_CYCLETIMER_HELPER_PRIO); 
    357402    } 
    358403    return result; 
     
    463508{ 
    464509    Util::MutexLockHelper lock(*m_handle_lock); 
     510    return readNoLock(nodeId, addr, length, buffer); 
     511} 
     512 
     513bool 
     514Ieee1394Service::readNoLock( fb_nodeid_t nodeId, 
     515                             fb_nodeaddr_t addr, 
     516                             size_t length, 
     517                             fb_quadlet_t* buffer ) 
     518{ 
    465519    if (nodeId == INVALID_NODE_ID) { 
    466520        debugWarning("operation on invalid node\n"); 
     
    511565{ 
    512566    Util::MutexLockHelper lock(*m_handle_lock); 
     567    return writeNoLock(nodeId, addr, length, data); 
     568} 
     569 
     570bool 
     571Ieee1394Service::writeNoLock( fb_nodeid_t nodeId, 
     572                              fb_nodeaddr_t addr, 
     573                              size_t length, 
     574                              fb_quadlet_t* data ) 
     575{ 
    513576    if (nodeId == INVALID_NODE_ID) { 
    514577        debugWarning("operation on invalid node\n"); 
     
    601664                                   unsigned int* resp_len ) 
    602665{ 
     666    // FIXME: simplify semantics 
    603667    if (nodeId == INVALID_NODE_ID) { 
    604668        debugWarning("operation on invalid node\n"); 
    605669        return false; 
    606670    } 
    607     // FIXME: this requires transactionBlockClose to unlock 
     671    // NOTE: this expects a call to transactionBlockClose to unlock 
    608672    m_handle_lock->Lock(); 
    609     for (int i = 0; i < len; ++i) { 
    610         buf[i] = CondSwapFromBus32( buf[i] ); 
    611     } 
    612  
    613     fb_quadlet_t* result = 
    614         avc1394_transaction_block2( m_handle, 
    615                                     nodeId, 
    616                                     buf, 
    617                                     len, 
    618                                     resp_len, 
    619                                     10 ); 
    620  
    621     for ( unsigned int i = 0; i < *resp_len; ++i ) { 
    622         result[i] = CondSwapToBus32( result[i] ); 
    623     } 
    624  
    625     return result; 
    626 
    627  
     673 
     674    // clear the request & response memory 
     675    memset(&m_fcp_block, 0, sizeof(m_fcp_block)); 
     676 
     677    // make a local copy of the request 
     678    if(len < MAX_FCP_BLOCK_SIZE_QUADS) { 
     679        memcpy(m_fcp_block.request, buf, len*sizeof(quadlet_t)); 
     680        m_fcp_block.request_length = len; 
     681    } else { 
     682        debugWarning("Truncating FCP request\n"); 
     683        memcpy(m_fcp_block.request, buf, MAX_FCP_BLOCK_SIZE_BYTES); 
     684        m_fcp_block.request_length = MAX_FCP_BLOCK_SIZE_QUADS; 
     685    } 
     686    m_fcp_block.target_nodeid = 0xffc0 | nodeId; 
     687 
     688    bool success = doFcpTransaction(); 
     689    if(success) { 
     690        *resp_len = m_fcp_block.response_length; 
     691        return m_fcp_block.response; 
     692    } else { 
     693        debugWarning("FCP transaction failed\n"); 
     694        *resp_len = 0; 
     695        return NULL; 
     696    } 
     697
    628698 
    629699bool 
    630700Ieee1394Service::transactionBlockClose() 
    631701{ 
    632     avc1394_transaction_block_close( m_handle ); 
    633702    m_handle_lock->Unlock(); 
    634703    return true; 
     704} 
     705 
     706// FCP code 
     707bool 
     708Ieee1394Service::doFcpTransaction() 
     709{ 
     710    for(int i=0; i < IEEE1394SERVICE_FCP_MAX_TRIES; i++) { 
     711        if(doFcpTransactionTry()) { 
     712            return true; 
     713        } else { 
     714            debugOutput(DEBUG_LEVEL_VERBOSE, "FCP transaction try %d failed\n", i); 
     715            Util::SystemTimeSource::SleepUsecRelative( IEEE1394SERVICE_FCP_SLEEP_BETWEEN_FAILURES_USECS); 
     716        } 
     717    } 
     718    debugError("FCP transaction didn't succeed in %d tries\n", IEEE1394SERVICE_FCP_MAX_TRIES); 
     719    return false; 
     720} 
     721 
     722#define FCP_COMMAND_ADDR   0xFFFFF0000B00ULL 
     723#define FCP_RESPONSE_ADDR  0xFFFFF0000D00ULL 
     724 
     725/* AV/C FCP response codes */ 
     726#define FCP_RESPONSE_NOT_IMPLEMENTED 0x08000000 
     727#define FCP_RESPONSE_ACCEPTED 0x09000000 
     728#define FCP_RESPONSE_REJECTED 0x0A000000 
     729#define FCP_RESPONSE_IN_TRANSITION 0x0B000000 
     730#define FCP_RESPONSE_IMPLEMENTED 0x0C000000 
     731#define FCP_RESPONSE_STABLE 0x0C000000 
     732#define FCP_RESPONSE_CHANGED 0x0D000000 
     733#define FCP_RESPONSE_INTERIM 0x0F000000 
     734 
     735/* AV/C FCP mask macros */ 
     736#define FCP_MASK_START(x) ((x) & 0xF0000000) 
     737#define FCP_MASK_CTYPE(x) ((x) & 0x0F000000) 
     738#define FCP_MASK_RESPONSE(x) ((x) & 0x0F000000) 
     739#define FCP_MASK_SUBUNIT(x) ((x) & 0x00FF0000) 
     740#define FCP_MASK_SUBUNIT_TYPE(x) ((x) & 0x00F80000) 
     741#define FCP_MASK_SUBUNIT_ID(x) ((x) & 0x00070000) 
     742#define FCP_MASK_OPCODE(x) ((x) & 0x0000FF00) 
     743#define FCP_MASK_SUBUNIT_AND_OPCODE(x) ((x) & 0x00FFFF00) 
     744#define FCP_MASK_OPERAND0(x) ((x) & 0x000000FF) 
     745#define FCP_MASK_OPERAND(x, n) ((x) & (0xFF000000 >> ((((n)-1)%4)*8))) 
     746#define FCP_MASK_RESPONSE_OPERAND(x, n) ((x) & (0xFF000000 >> (((n)%4)*8))) 
     747 
     748bool 
     749Ieee1394Service::doFcpTransactionTry() 
     750{ 
     751    // NOTE that access to this is protected by the m_handle lock 
     752    int err; 
     753    bool retval = true; 
     754    uint64_t timeout; 
     755 
     756    // prepare an fcp response handler 
     757    raw1394_set_fcp_handler(m_handle, _avc_fcp_handler); 
     758 
     759    // start listening for FCP requests 
     760    // this fails if some other program is listening for a FCP response 
     761    err = raw1394_start_fcp_listen(m_handle); 
     762    if(err) { 
     763        debugOutput(DEBUG_LEVEL_VERBOSE, "could not start FCP listen (err=%d, errno=%d)\n", err, errno); 
     764        retval = false; 
     765        goto out; 
     766    } 
     767 
     768    m_fcp_block.status = eFS_Waiting; 
     769 
     770    #ifdef DEBUG 
     771    debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"fcp request: node 0x%hX, length = %d bytes\n", 
     772                m_fcp_block.target_nodeid, m_fcp_block.request_length*4); 
     773    printBuffer(DEBUG_LEVEL_VERY_VERBOSE, m_fcp_block.request_length, m_fcp_block.request ); 
     774    #endif 
     775 
     776    // write the FCP request 
     777    if(!writeNoLock( m_fcp_block.target_nodeid, FCP_COMMAND_ADDR, 
     778                     m_fcp_block.request_length, m_fcp_block.request)) { 
     779        debugOutput(DEBUG_LEVEL_VERBOSE, "write of FCP request failed\n"); 
     780        retval = false; 
     781        goto out; 
     782    } 
     783 
     784    // wait for the response to arrive 
     785    struct pollfd raw1394_poll; 
     786    raw1394_poll.fd = raw1394_get_fd(m_handle); 
     787    raw1394_poll.events = POLLIN; 
     788 
     789    timeout = Util::SystemTimeSource::getCurrentTimeAsUsecs() + 
     790              IEEE1394SERVICE_FCP_RESPONSE_TIMEOUT_USEC; 
     791 
     792    while(m_fcp_block.status == eFS_Waiting  
     793          && Util::SystemTimeSource::getCurrentTimeAsUsecs() < timeout) { 
     794        if(poll( &raw1394_poll, 1, IEEE1394SERVICE_FCP_POLL_TIMEOUT_MSEC) > 0) { 
     795            if (raw1394_poll.revents & POLLIN) { 
     796                raw1394_loop_iterate(m_handle); 
     797            } 
     798        } 
     799    } 
     800 
     801    // stop listening for FCP responses 
     802    err = raw1394_stop_fcp_listen(m_handle); 
     803    if(err) { 
     804        debugOutput(DEBUG_LEVEL_VERBOSE, "could not stop FCP listen (err=%d, errno=%d)\n", err, errno); 
     805        retval = false; 
     806        goto out; 
     807    } 
     808 
     809    // check the request and figure out what happened 
     810    if(m_fcp_block.status == eFS_Waiting) { 
     811        debugOutput(DEBUG_LEVEL_VERBOSE, "FCP response timed out\n"); 
     812        retval = false; 
     813        goto out; 
     814    } 
     815    if(m_fcp_block.status == eFS_Error) { 
     816        debugError("FCP request/response error\n"); 
     817        retval = false; 
     818        goto out; 
     819    } 
     820 
     821out: 
     822    m_fcp_block.status = eFS_Empty; 
     823    return retval; 
     824} 
     825 
     826int 
     827Ieee1394Service::_avc_fcp_handler(raw1394handle_t handle, nodeid_t nodeid,  
     828                                  int response, size_t length, 
     829                                  unsigned char *data) 
     830{ 
     831    Ieee1394Service *service = static_cast<Ieee1394Service *>(raw1394_get_userdata(handle)); 
     832    if(service) { 
     833        return service->handleFcpResponse(nodeid, response, length, data); 
     834    } else return -1; 
     835} 
     836 
     837int 
     838Ieee1394Service::handleFcpResponse(nodeid_t nodeid, 
     839                                   int response, size_t length, 
     840                                   unsigned char *data) 
     841{ 
     842    static struct sFcpBlock fcp_block_last; 
     843 
     844    fb_quadlet_t *data_quads = (fb_quadlet_t *)data; 
     845    #ifdef DEBUG 
     846    debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"fcp response: node 0x%hX, response = %d, length = %d bytes\n", 
     847                nodeid, response, length); 
     848    printBuffer(DEBUG_LEVEL_VERY_VERBOSE, (length+3)/4, data_quads ); 
     849    #endif 
     850 
     851    if (response && length > 3) { 
     852        if(length > MAX_FCP_BLOCK_SIZE_BYTES) { 
     853            length = MAX_FCP_BLOCK_SIZE_BYTES; 
     854            debugWarning("Truncated FCP response\n"); 
     855        } 
     856 
     857        // is it an actual response or is it INTERIM? 
     858        quadlet_t first_quadlet = CondSwapFromBus32(data_quads[0]); 
     859        if(FCP_MASK_RESPONSE(first_quadlet) == FCP_RESPONSE_INTERIM) { 
     860            debugOutput(DEBUG_LEVEL_VERBOSE, "INTERIM\n"); 
     861        } else { 
     862            // it's an actual response, check if it matches our request 
     863            if(nodeid != m_fcp_block.target_nodeid) { 
     864                debugOutput(DEBUG_LEVEL_VERBOSE, "FCP response node id's don't match! (%x, %x)\n", 
     865                                                 m_fcp_block.target_nodeid, nodeid); 
     866            } else if (first_quadlet == 0) { 
     867                debugWarning("Bogus FCP response\n"); 
     868                printBuffer(DEBUG_LEVEL_WARNING, (length+3)/4, data_quads ); 
     869#ifdef DEBUG 
     870            } else if(FCP_MASK_RESPONSE(first_quadlet) < 0x08000000) { 
     871                debugWarning("Bogus AV/C FCP response code\n"); 
     872                printBuffer(DEBUG_LEVEL_WARNING, (length+3)/4, data_quads ); 
     873#endif 
     874            } else if(FCP_MASK_SUBUNIT_AND_OPCODE(first_quadlet)  
     875                      != FCP_MASK_SUBUNIT_AND_OPCODE(CondSwapFromBus32(m_fcp_block.request[0]))) { 
     876                debugOutput(DEBUG_LEVEL_VERBOSE, "FCP response not for this request: %08lX != %08lX\n", 
     877                             FCP_MASK_SUBUNIT_AND_OPCODE(first_quadlet), 
     878                             FCP_MASK_SUBUNIT_AND_OPCODE(CondSwapFromBus32(m_fcp_block.request[0]))); 
     879            } else if(m_filterFCPResponse && (memcmp(fcp_block_last.response, data, length) == 0)) { 
     880                // This is workaround for the Edirol FA-101. The device tends to send more than 
     881                // one responde to one request. This seems to happen when discovering  
     882                // function blocks and looks very likely there is a race condition in the  
     883                // device. The workaround here compares the just arrived FCP responde 
     884                // to the last one. If it is the same as the previously one then we 
     885                // just ignore it. The downside of this approach is, we cannot issue 
     886                // the same FCP twice. 
     887                debugWarning("Received duplicate FCP response. Ignore it\n"); 
     888            } else { 
     889                m_fcp_block.response_length = (length + sizeof(quadlet_t) - 1) / sizeof(quadlet_t); 
     890                memcpy(m_fcp_block.response, data, length); 
     891                if (m_filterFCPResponse) { 
     892                    memcpy(fcp_block_last.response, data, length); 
     893                } 
     894                m_fcp_block.status = eFS_Responded; 
     895            } 
     896       } 
     897    } 
     898    return 0; 
     899} 
     900 
     901bool 
     902Ieee1394Service::setSplitTimeoutUsecs(fb_nodeid_t nodeId, unsigned int timeout) 
     903{ 
     904    Util::MutexLockHelper lock(*m_handle_lock); 
     905    debugOutput(DEBUG_LEVEL_VERBOSE, "setting SPLIT_TIMEOUT on node 0x%X to %uusecs...\n", nodeId, timeout); 
     906    unsigned int secs = timeout / 1000000; 
     907    unsigned int usecs = timeout % 1000000; 
     908 
     909    quadlet_t split_timeout_hi = CondSwapToBus32(secs & 7); 
     910    quadlet_t split_timeout_low = CondSwapToBus32(((usecs / 125) & 0x1FFF) << 19); 
     911 
     912    // write the CSR registers 
     913    if(!writeNoLock( 0xffc0 | nodeId, CSR_REGISTER_BASE + CSR_SPLIT_TIMEOUT_HI, 1, 
     914                  &split_timeout_hi)) { 
     915        debugOutput(DEBUG_LEVEL_VERBOSE, "write of CSR_SPLIT_TIMEOUT_HI failed\n"); 
     916        return false; 
     917    } 
     918    if(!writeNoLock( 0xffc0 | nodeId, CSR_REGISTER_BASE + CSR_SPLIT_TIMEOUT_LO, 1, 
     919                  &split_timeout_low)) { 
     920        debugOutput(DEBUG_LEVEL_VERBOSE, "write of CSR_SPLIT_TIMEOUT_LO failed\n"); 
     921        return false; 
     922    } 
     923    return true; 
     924} 
     925 
     926int 
     927Ieee1394Service::getSplitTimeoutUsecs(fb_nodeid_t nodeId) 
     928{ 
     929    Util::MutexLockHelper lock(*m_handle_lock); 
     930    quadlet_t split_timeout_hi; 
     931    quadlet_t split_timeout_low; 
     932 
     933    debugOutput(DEBUG_LEVEL_VERBOSE, "reading SPLIT_TIMEOUT on node 0x%X...\n", nodeId); 
     934 
     935    if(!readNoLock( 0xffc0 | nodeId, CSR_REGISTER_BASE + CSR_SPLIT_TIMEOUT_HI, 1, 
     936                  &split_timeout_hi)) { 
     937        debugOutput(DEBUG_LEVEL_VERBOSE, "read of CSR_SPLIT_TIMEOUT_HI failed\n"); 
     938        return 0; 
     939    } 
     940    debugOutput(DEBUG_LEVEL_VERBOSE, " READ HI: 0x%08lX\n", split_timeout_hi); 
     941 
     942    if(!readNoLock( 0xffc0 | nodeId, CSR_REGISTER_BASE + CSR_SPLIT_TIMEOUT_LO, 1, 
     943                  &split_timeout_low)) { 
     944        debugOutput(DEBUG_LEVEL_VERBOSE, "read of CSR_SPLIT_TIMEOUT_LO failed\n"); 
     945        return 0; 
     946    } 
     947    debugOutput(DEBUG_LEVEL_VERBOSE, " READ LO: 0x%08lX\n", split_timeout_low); 
     948 
     949    split_timeout_hi = CondSwapFromBus32(split_timeout_hi); 
     950    split_timeout_low = CondSwapFromBus32(split_timeout_low); 
     951 
     952    return (split_timeout_hi & 7) * 1000000 + (split_timeout_low >> 19) * 125; 
     953} 
     954 
     955void  
     956Ieee1394Service::setFCPResponseFiltering(bool enable) 
     957{ 
     958    m_filterFCPResponse = enable; 
    635959} 
    636960 
  • trunk/libffado/src/libieee1394/ieee1394service.h

    r1348 r1498  
    4141 
    4242class ARMHandler; 
     43 
     44#define MAX_FCP_BLOCK_SIZE_BYTES (512) 
     45#define MAX_FCP_BLOCK_SIZE_QUADS (MAX_FCP_BLOCK_SIZE_BYTES / 4) 
     46 
    4347class IsoHandlerManager; 
    4448class CycleTimerHelper; 
     
    4650namespace Util { 
    4751    class Watchdog; 
     52    class Configuration; 
    4853} 
    4954 
     
    227232     * @return true if succesful, false otherwise 
    228233     */ 
    229     bool lockCompareSwap64(  fb_nodeid_t nodeId, 
    230                         fb_nodeaddr_t addr, 
    231                         fb_octlet_t  compare_value, 
    232                         fb_octlet_t  swap_value, 
    233                         fb_octlet_t* result ); 
    234  
     234    bool lockCompareSwap64( fb_nodeid_t nodeId, 
     235                            fb_nodeaddr_t addr, 
     236                            fb_octlet_t  compare_value, 
     237                            fb_octlet_t  swap_value, 
     238                            fb_octlet_t* result ); 
     239 
     240    /** 
     241     * initiate AV/C transaction 
     242     * @param nodeId  
     243     * @param buf  
     244     * @param len  
     245     * @param resp_len  
     246     * @return  
     247     */ 
    235248    fb_quadlet_t* transactionBlock( fb_nodeid_t nodeId, 
    236249                                    fb_quadlet_t* buf, 
    237250                                    int len, 
    238                     unsigned int* resp_len ); 
    239  
     251                                    unsigned int* resp_len ); 
     252 
     253    /** 
     254     * close AV/C transaction. 
     255     * @param nodeId  
     256     * @param buf  
     257     * @param len  
     258     * @param resp_len  
     259     * @return  
     260     */ 
    240261    bool transactionBlockClose(); 
    241262 
     
    247268    void doBusReset(); 
    248269    bool waitForBusResetStormToEnd( int nb_tries, int sleep_time_ms ); 
     270 
     271    /** 
     272     * @brief register an AddressRangeMapping Handler 
     273     * @param h pointer to the handler to register 
     274     * 
     275     * @return true on success or false on failure 
     276     **/ 
     277 
     278    bool registerARMHandler( ARMHandler *h ); 
     279 
     280    /** 
     281     * @brief unregister ARM range 
     282     * @param h pointer to the handler to unregister 
     283     * @return true if successful, false otherwise 
     284     */ 
     285    bool unregisterARMHandler( ARMHandler *h ); 
     286 
     287    nodeaddr_t findFreeARMBlock( nodeaddr_t start, size_t length, size_t step ); 
    249288 
    250289    /** 
     
    259298 
    260299    /** 
    261      * @brief register an AddressRangeMapping Handler 
    262      * @param h pointer to the handler to register 
    263      * 
    264      * @return true on success or false on failure 
     300     * @brief update the current generation 
     301     * 
     302     * @return the current generation 
    265303     **/ 
    266  
    267     bool registerARMHandler( ARMHandler *h ); 
    268  
    269     /** 
    270      * @brief unregister ARM range 
    271      * @param h pointer to the handler to unregister 
    272      * @return true if successful, false otherwise 
    273      */ 
    274     bool unregisterARMHandler( ARMHandler *h ); 
    275  
    276     nodeaddr_t findFreeARMBlock( nodeaddr_t start, size_t length, size_t step ); 
     304    void updateGeneration() { 
     305        Util::MutexLockHelper lock(*m_handle_lock); 
     306        raw1394_update_generation( m_handle, getGeneration()); 
     307    } 
     308 
     309    /** 
     310     * @brief sets the SPLIT_TIMEOUT_HI and SPLIT_TIMEOUT_LO CSR registers 
     311     * 
     312     * sets the SPLIT_TIMEOUT_HI and SPLIT_TIMEOUT_LO CSR registers on node 
     313     * nodeId such that the timeout is equal to timeout 
     314     * 
     315     * @param nodeId node to set CSR registers on 
     316     * @param timeout timeout in usecs 
     317     * @return true if successful 
     318     */ 
     319    bool setSplitTimeoutUsecs(fb_nodeid_t nodeId, unsigned int timeout); 
     320 
     321    /** 
     322     * @brief gets the SPLIT_TIMEOUT_X timeout value 
     323     * 
     324     * gets the SPLIT_TIMEOUT_HI and SPLIT_TIMEOUT_LO CSR registers on node 
     325     * nodeId and recombine them into one usec value 
     326     * 
     327     * @param nodeId node to get CSR registers from 
     328     * @return timeout in usecs if successful, 0 else 
     329     */ 
     330    int getSplitTimeoutUsecs(fb_nodeid_t nodeId); 
     331 
     332    /** 
     333     * @brief use the provided configuration for this service 
     334     * 
     335     * only update the config once, before init. not thread safe, 
     336     * and no effect when things are already running. 
     337     * 
     338     * @param c configuration to use 
     339     * @return bool if this config is ok. 
     340     */ 
     341    bool useConfiguration(Util::Configuration *c); 
     342 
     343    Util::Configuration *getConfiguration() {return m_configuration;}; 
     344 
     345    /** 
     346     * @brief enable or disable FCP response doublicate filtering 
     347     * 
     348     * this is use only for devices (e.g. edirol fa101) which have a  
     349     * buggy FCP implementation and send more then one FCP response  
     350     * for one request.  
     351     */ 
     352    void setFCPResponseFiltering(bool enable); 
    277353 
    278354// ISO channel stuff 
     
    312388    raw1394handle_t getHandle() {return m_handle;}; 
    313389 
     390protected: 
     391    Util::Configuration     *m_configuration; 
     392 
    314393private: 
     394    bool configurationUpdated(); 
     395 
    315396    bool startRHThread(); 
    316397    void stopRHThread(); 
     
    349430    bool                    m_have_new_ctr_read; 
    350431 
     432    bool            m_filterFCPResponse; 
     433 
    351434    // the RT watchdog 
    352435    Util::Watchdog*     m_pWatchdog; 
     
    360443    typedef std::vector< ARMHandler * > arm_handler_vec_t; 
    361444    arm_handler_vec_t m_armHandlers; 
     445 
     446    // unprotected variants 
     447    bool writeNoLock( fb_nodeid_t nodeId, 
     448        fb_nodeaddr_t addr, 
     449        size_t length, 
     450        fb_quadlet_t* data ); 
     451    bool readNoLock( fb_nodeid_t nodeId, 
     452           fb_nodeaddr_t addr, 
     453           size_t length, 
     454           fb_quadlet_t* buffer ); 
     455 
     456    // FCP transaction support 
     457    static int _avc_fcp_handler(raw1394handle_t handle, nodeid_t nodeid,  
     458                                int response, size_t length, 
     459                                unsigned char *data); 
     460    int handleFcpResponse(nodeid_t nodeid, 
     461                          int response, size_t length, 
     462                          unsigned char *data); 
     463 
     464    enum eFcpStatus { 
     465        eFS_Empty, 
     466        eFS_Waiting, 
     467        eFS_Responded, 
     468        eFS_Error, 
     469    }; 
     470 
     471    struct sFcpBlock { 
     472        enum eFcpStatus status; 
     473        nodeid_t target_nodeid; 
     474        unsigned int request_length; 
     475        quadlet_t request[MAX_FCP_BLOCK_SIZE_QUADS]; 
     476        unsigned int response_length; 
     477        quadlet_t response[MAX_FCP_BLOCK_SIZE_QUADS]; 
     478    }; 
     479    struct sFcpBlock m_fcp_block; 
     480 
     481    bool doFcpTransaction(); 
     482    bool doFcpTransactionTry(); 
    362483 
    363484public: 
  • trunk/libffado/src/libieee1394/IsoHandler.cpp

    r1348 r1498  
    8181   , m_last_now( 0xFFFFFFFF ) 
    8282   , m_last_packet_handled_at( 0xFFFFFFFF ) 
     83   , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER ) 
    8384   , m_Client( 0 ) 
    8485   , m_speed( RAW1394_ISO_SPEED_400 ) 
     
    106107   , m_last_now( 0xFFFFFFFF ) 
    107108   , m_last_packet_handled_at( 0xFFFFFFFF ) 
     109   , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER ) 
    108110   , m_Client( 0 ) 
    109111   , m_speed( RAW1394_ISO_SPEED_400 ) 
     
    131133   , m_last_now( 0xFFFFFFFF ) 
    132134   , m_last_packet_handled_at( 0xFFFFFFFF ) 
     135   , m_receive_mode ( RAW1394_DMA_PACKET_PER_BUFFER ) 
    133136   , m_Client( 0 ) 
    134137   , m_speed( speed ) 
     
    376379                    unsigned char channel, unsigned char tag, unsigned char sy, 
    377380                    unsigned int cycle, unsigned int dropped) { 
    378  
    379381    // keep track of dropped cycles 
    380382    int dropped_cycles = 0; 
     
    396398    m_last_cycle = cycle; 
    397399 
    398     uint32_t pkt_ctr = cycle << 12; 
    399  
    400     // if we assume that one iterate() loop doesn't take longer than 0.5 seconds, 
    401     // the seconds field won't change while the iterate loop runs 
    402     // this means that we can preset 'now' before running iterate() 
    403     uint32_t now_secs = CYCLE_TIMER_GET_SECS(m_last_now); 
    404     // causality results in the fact that 'now' is always after 'cycle' 
    405     // except if additional packets are received between setting the 
    406     // m_last_now and the starting the iterate() loop. 
    407     // this causes the m_last_now to be set at a time before the last packet 
    408     // in this loop is received. however, it's not going to be >4000 cycles. 
    409     // hence: 
    410     // - if the m_last_now > cycle, there is no need to unwrap 
    411     //   both values are within the same second 
    412     // - if m_last_now < cycle it can mean two things: 
    413     //    * m_last_now has wrapped, but is still later than cycle 
    414     //      hence diffCycles(m_last_now, cycle) > 0. We should unwrap 
    415     //    * m_last_now has not wrapped, and cycle is ahead of m_last_now 
    416     //      this means that the cycle is more recent than the saved 
    417     //      m_last_now value 
    418     // . Hence if we calculate 
    419     // the unwrapped difference, and it's larger than 0, this means 
    420     // that m_last_now is after the current cycle. . 
    421     // it m_last_now is before the current cycle, we should not unwrap 
    422     // NOTE: another option is to reread the m_last_now 
    423     if( (CYCLE_TIMER_GET_CYCLES(m_last_now) < cycle) 
    424         && diffCycles(CYCLE_TIMER_GET_CYCLES(m_last_now), cycle) >= 0) { 
    425         debugOutputExtreme(DEBUG_LEVEL_VERBOSE, 
    426                            "unwrapping %d => %d, %d\n", 
    427                            CYCLE_TIMER_GET_CYCLES(m_last_now), 
    428                            cycle); 
    429         // the cycle field has wrapped, substract one second 
    430         if(now_secs == 0) { 
    431             now_secs = 127; 
    432         } else  { 
    433             now_secs -= 1; 
    434         } 
    435     } 
    436  
     400    // the m_last_now value is set when the iterate() function is called. 
     401    uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(m_last_now); 
     402 
     403    // two cases can occur: 
     404    // (1) this packet has been received before iterate() was called (normal case). 
     405    // (2) this packet has been received after iterate() was called. 
     406    //     happens when the kernel flushes more packets while we are already processing. 
     407    // 
     408    // In case (1) now_cycles is a small number of cycles larger than cycle. In 
     409    // case (2) now_cycles is a small number of cycles smaller than cycle. 
     410    // hence  abs(diffCycles(now_cycles, cycles)) has to be 'small' 
     411 
     412    // we can calculate the time of arrival for this packet as 
     413    // 'now' + diffCycles(cycles, now_cycles) * TICKS_PER_CYCLE 
     414    // in its properly wrapped version 
     415    int64_t diff_cycles = diffCycles(cycle, now_cycles); 
     416    int64_t tmp = CYCLE_TIMER_TO_TICKS(m_last_now); 
     417    tmp += diff_cycles * (int64_t)TICKS_PER_CYCLE; 
     418    uint64_t pkt_ctr_ticks = wrapAtMinMaxTicks(tmp); 
     419    uint32_t pkt_ctr = TICKS_TO_CYCLE_TIMER(pkt_ctr_ticks); 
    437420    #ifdef DEBUG 
    438     if( (CYCLE_TIMER_GET_CYCLES(m_last_now) < cycle) 
    439         && diffCycles(CYCLE_TIMER_GET_CYCLES(m_last_now), cycle) < 0 
     421    if( (now_cycles < cycle) 
     422        && diffCycles(now_cycles, cycle) < 0 
    440423        // ignore this on dropped cycles, since it's normal 
    441424        // that now is ahead on the received packets (as we miss packets) 
     
    445428    } 
    446429    #endif 
    447     pkt_ctr |= (now_secs & 0x7F) << 25; 
    448430 
    449431    #if ISOHANDLER_CHECK_CTR_RECONSTRUCTION 
     
    465447    pkt_ctr_ref |= (now_secs_ref & 0x7F) << 25; 
    466448 
    467     if(pkt_ctr != pkt_ctr_ref) { 
     449    if((pkt_ctr & ~0x0FFFL) != pkt_ctr_ref) { 
    468450        debugWarning("reconstructed CTR counter discrepancy\n"); 
    469         debugWarning(" ingredients: %X, %lX, %lX, %lX, %lX, %ld, %ld\n", 
    470                        cycle, pkt_ctr_ref, pkt_ctr, now, m_last_now, now_secs_ref, now_secs); 
     451        debugWarning(" ingredients: %X, %lX, %lX, %lX, %lX, %ld, %ld, %ld, %lld\n", 
     452                       cycle, pkt_ctr_ref, pkt_ctr, now, m_last_now, now_secs_ref, CYCLE_TIMER_GET_SECS(now), CYCLE_TIMER_GET_SECS(m_last_now), tmp); 
     453        debugWarning(" diffcy = %ld \n", diff_cycles); 
    471454    } 
    472455    #endif 
     
    520503        pkt_ctr = 0xFFFFFFFF; 
    521504    } else { 
    522         pkt_ctr = cycle << 12; 
    523  
    524         // if we assume that one iterate() loop doesn't take longer than 0.5 seconds, 
    525         // the seconds field won't change while the iterate loop runs 
    526         // this means that we can preset 'now' before running iterate() 
    527         uint32_t now_secs = CYCLE_TIMER_GET_SECS(m_last_now); 
    528         // causality results in the fact that 'now' is always after 'cycle' 
    529         if(CYCLE_TIMER_GET_CYCLES(m_last_now) > (unsigned int)cycle) { 
    530             // the cycle field has wrapped, add one second 
    531             now_secs += 1; 
    532             // no need for this: 
    533             //if(now_secs == 128) { 
    534             //    now_secs = 0; 
    535             //} 
    536             // since we mask later on 
    537         } 
    538         pkt_ctr |= (now_secs & 0x7F) << 25; 
     505        // the m_last_now value is set when the iterate() function is called. 
     506        uint32_t now_cycles = CYCLE_TIMER_GET_CYCLES(m_last_now); 
     507 
     508        // two cases can occur: 
     509        // (1) this packet has been received before iterate() was called (normal case). 
     510        // (2) this packet has been received after iterate() was called. 
     511        //     happens when the kernel flushes more packets while we are already processing. 
     512        // 
     513        // In case (1) now_cycles is a small number of cycles larger than cycle. In 
     514        // case (2) now_cycles is a small number of cycles smaller than cycle. 
     515        // hence  abs(diffCycles(now_cycles, cycles)) has to be 'small' 
     516 
     517        // we can calculate the time of arrival for this packet as 
     518        // 'now' + diffCycles(cycles, now_cycles) * TICKS_PER_CYCLE 
     519        // in its properly wrapped version 
     520        int64_t diff_cycles = diffCycles(cycle, now_cycles); 
     521        int64_t tmp = CYCLE_TIMER_TO_TICKS(m_last_now); 
     522        tmp += diff_cycles * (int64_t)TICKS_PER_CYCLE; 
     523        uint64_t pkt_ctr_ticks = wrapAtMinMaxTicks(tmp); 
     524        pkt_ctr = TICKS_TO_CYCLE_TIMER(pkt_ctr_ticks); 
    539525 
    540526        #if ISOHANDLER_CHECK_CTR_RECONSTRUCTION 
     
    547533            now_secs_ref += 1; 
    548534            // no need for this: 
    549             //if(now_secs == 128) { 
    550             //    now_secs = 0; 
    551             //} 
    552             // since we mask later on 
     535            if(now_secs_ref == 128) { 
     536               now_secs_ref = 0; 
     537            } 
    553538        } 
    554539        uint32_t pkt_ctr_ref = cycle << 12; 
    555540        pkt_ctr_ref |= (now_secs_ref & 0x7F) << 25; 
    556541 
    557         if(pkt_ctr != pkt_ctr_ref) { 
     542        if((pkt_ctr & ~0x0FFFL) != pkt_ctr_ref) { 
    558543            debugWarning("reconstructed CTR counter discrepancy\n"); 
    559             pkt_ctr=pkt_ctr_ref; 
     544            debugWarning(" ingredients: %X, %lX, %lX, %lX, %lX, %ld, %ld, %ld, %lld\n", 
     545                        cycle, pkt_ctr_ref, pkt_ctr, now, m_last_now, now_secs_ref, CYCLE_TIMER_GET_SECS(now), CYCLE_TIMER_GET_SECS(m_last_now), tmp); 
     546            debugWarning(" diffcy = %ld \n", diff_cycles); 
    560547        } 
    561548        #endif 
     
    675662                                m_max_packet_size, 
    676663                                m_Client->getChannel(), 
    677                                 RAW1394_DMA_PACKET_PER_BUFFER
     664                                m_receive_mode
    678665                                m_irq_interval)) { 
    679             debugFatal("Could not do receive initialisation (DMA_BUFFERFILL)!\n" ); 
     666            debugFatal("Could not do receive initialisation!\n" ); 
    680667            debugFatal("  %s\n",strerror(errno)); 
    681668            return false; 
     
    728715    // indicate that the first iterate() still has to occur. 
    729716    m_last_now = 0xFFFFFFFF; 
     717    m_last_packet_handled_at = 0xFFFFFFFF; 
    730718 
    731719    m_State = E_Running; 
  • trunk/libffado/src/libieee1394/IsoHandler.h

    r1348 r1498  
    168168    uint32_t getLastPacketTime() {return m_last_packet_handled_at;}; 
    169169 
     170    /** 
     171     * @brief set iso receive mode. doesn't have any effect if the stream is running 
     172     * @param m receive mode 
     173     */ 
     174    void setReceiveMode(enum raw1394_iso_dma_recv_mode m) 
     175        {m_receive_mode = m;} 
     176 
    170177    void notifyOfDeath(); 
    171178    bool handleBusReset(); 
     
    181188    uint32_t        m_last_now; 
    182189    uint32_t        m_last_packet_handled_at; 
     190    enum raw1394_iso_dma_recv_mode m_receive_mode; 
    183191 
    184192    Streaming::StreamProcessor *m_Client; // FIXME: implement with functors 
  • trunk/libffado/src/libieee1394/IsoHandlerManager.cpp

    r1348 r1498  
    3333#include "libutil/SystemTimeSource.h" 
    3434#include "libutil/Watchdog.h" 
     35#include "libutil/Configuration.h" 
    3536 
    3637#include <cstring> 
     
    5051    , m_running( false ) 
    5152    , m_in_busreset( false ) 
     53    , m_activity_wait_timeout_nsec (ISOHANDLERMANAGER_ISO_TASK_WAIT_TIMEOUT_USECS * 1000LL) 
    5254{ 
    5355} 
     
    344346        } 
    345347    } 
     348 
    346349    if(handler_died) { 
    347350        m_running = false; 
     
    389392    struct timespec ts; 
    390393    int result; 
    391     long long int timeout_nsec = ISOHANDLERMANAGER_ISO_TASK_WAIT_TIMEOUT_USECS * 1000LL; 
    392394 
    393395    if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { 
     
    396398    } 
    397399 
    398     ts.tv_nsec += timeout_nsec; 
     400    ts.tv_nsec += m_activity_wait_timeout_nsec; 
    399401    while(ts.tv_nsec >= 1000000000LL) { 
    400402        ts.tv_sec += 1; 
     
    419421                        this, result); 
    420422            debugError("(%p) timeout_nsec=%lld ts.sec=%d ts.nsec=%lld\n",  
    421                        this, timeout_nsec, ts.tv_sec, ts.tv_nsec); 
     423                       this, m_activity_wait_timeout_nsec, ts.tv_sec, ts.tv_nsec); 
    422424            return eAR_Error; 
    423425        } else { 
     
    425427                        this, result, errno); 
    426428            debugError("(%p) timeout_nsec=%lld ts.sec=%d ts.nsec=%lld\n",  
    427                        this, timeout_nsec, ts.tv_sec, ts.tv_nsec); 
     429                       this, m_activity_wait_timeout_nsec, ts.tv_sec, ts.tv_nsec); 
    428430            return eAR_Error; 
    429431        } 
     
    533535    debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) switch to: (rt=%d, prio=%d)...\n", this, rt, priority); 
    534536    if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO; // cap the priority 
     537    if (priority < THREAD_MIN_RTPRIO) priority = THREAD_MIN_RTPRIO; // cap the priority 
    535538    m_realtime = rt; 
    536539    m_priority = priority; 
     540 
     541    // grab the options from the parent 
     542    Util::Configuration *config = m_service.getConfiguration(); 
     543    int ihm_iso_prio_increase = ISOHANDLERMANAGER_ISO_PRIO_INCREASE; 
     544    int ihm_iso_prio_increase_xmit = ISOHANDLERMANAGER_ISO_PRIO_INCREASE_XMIT; 
     545    int ihm_iso_prio_increase_recv = ISOHANDLERMANAGER_ISO_PRIO_INCREASE_RECV; 
     546    if(config) { 
     547        config->getValueForSetting("ieee1394.isomanager.prio_increase", ihm_iso_prio_increase); 
     548        config->getValueForSetting("ieee1394.isomanager.prio_increase_xmit", ihm_iso_prio_increase_xmit); 
     549        config->getValueForSetting("ieee1394.isomanager.prio_increase_recv", ihm_iso_prio_increase_recv); 
     550    } 
    537551 
    538552    if (m_IsoThreadTransmit) { 
    539553        if (m_realtime) { 
    540554            m_IsoThreadTransmit->AcquireRealTime(m_priority 
    541                                                  + ISOHANDLERMANAGER_ISO_PRIO_INCREASE 
    542                                                  + ISOHANDLERMANAGER_ISO_PRIO_INCREASE_XMIT); 
     555                                                 + ihm_iso_prio_increase 
     556                                                 + ihm_iso_prio_increase_xmit); 
    543557        } else { 
    544558            m_IsoThreadTransmit->DropRealTime(); 
     
    548562        if (m_realtime) { 
    549563            m_IsoThreadReceive->AcquireRealTime(m_priority  
    550                                                 + ISOHANDLERMANAGER_ISO_PRIO_INCREASE 
    551                                                 + ISOHANDLERMANAGER_ISO_PRIO_INCREASE_RECV); 
     564                                                + ihm_iso_prio_increase 
     565                                                + ihm_iso_prio_increase_recv); 
    552566        } else { 
    553567            m_IsoThreadReceive->DropRealTime(); 
     
    565579        debugError("Manager already initialized...\n"); 
    566580        return false; 
     581    } 
     582 
     583    // grab the options from the parent 
     584    Util::Configuration *config = m_service.getConfiguration(); 
     585    int ihm_iso_prio_increase = ISOHANDLERMANAGER_ISO_PRIO_INCREASE; 
     586    int ihm_iso_prio_increase_xmit = ISOHANDLERMANAGER_ISO_PRIO_INCREASE_XMIT; 
     587    int ihm_iso_prio_increase_recv = ISOHANDLERMANAGER_ISO_PRIO_INCREASE_RECV; 
     588    int64_t isotask_activity_timeout_usecs = ISOHANDLERMANAGER_ISO_TASK_WAIT_TIMEOUT_USECS; 
     589    if(config) { 
     590        config->getValueForSetting("ieee1394.isomanager.prio_increase", ihm_iso_prio_increase); 
     591        config->getValueForSetting("ieee1394.isomanager.prio_increase_xmit", ihm_iso_prio_increase_xmit); 
     592        config->getValueForSetting("ieee1394.isomanager.prio_increase_recv", ihm_iso_prio_increase_recv); 
     593        config->getValueForSetting("ieee1394.isomanager.isotask_activity_timeout_usecs", isotask_activity_timeout_usecs); 
    567594    } 
    568595 
     
    575602    } 
    576603    m_IsoTaskTransmit->setVerboseLevel(getDebugLevel()); 
     604    m_IsoTaskTransmit->m_activity_wait_timeout_nsec = isotask_activity_timeout_usecs * 1000LL; 
    577605    m_IsoThreadTransmit = new Util::PosixThread(m_IsoTaskTransmit, "ISOXMT", m_realtime, 
    578                                                 m_priority + ISOHANDLERMANAGER_ISO_PRIO_INCREASE 
    579                                                 + ISOHANDLERMANAGER_ISO_PRIO_INCREASE_XMIT
     606                                                m_priority + ihm_iso_prio_increase 
     607                                                + ihm_iso_prio_increase_xmit
    580608                                                PTHREAD_CANCEL_DEFERRED); 
    581609 
     
    594622    m_IsoTaskReceive->setVerboseLevel(getDebugLevel()); 
    595623    m_IsoThreadReceive = new Util::PosixThread(m_IsoTaskReceive, "ISORCV", m_realtime, 
    596                                                m_priority + ISOHANDLERMANAGER_ISO_PRIO_INCREASE 
    597                                                + ISOHANDLERMANAGER_ISO_PRIO_INCREASE_RECV
     624                                               m_priority + ihm_iso_prio_increase 
     625                                               + ihm_iso_prio_increase_recv
    598626                                               PTHREAD_CANCEL_DEFERRED); 
    599627 
     
    759787    // allocate a handler for this stream 
    760788    if (stream->getType()==StreamProcessor::ePT_Receive) { 
     789        // grab the options from the parent 
     790        Util::Configuration *config = m_service.getConfiguration(); 
     791        int receive_mode_setting = DEFAULT_ISO_RECEIVE_MODE; 
     792        int bufferfill_mode_threshold = BUFFERFILL_MODE_THRESHOLD; 
     793        int min_interrupts_per_period = MINIMUM_INTERRUPTS_PER_PERIOD; 
     794        int max_nb_buffers_recv = MAX_RECV_NB_BUFFERS; 
     795        int min_packetsize_recv = MIN_RECV_PACKET_SIZE; 
     796        if(config) { 
     797            config->getValueForSetting("ieee1394.isomanager.iso_receive_mode", receive_mode_setting); 
     798            config->getValueForSetting("ieee1394.isomanager.bufferfill_mode_threshold", bufferfill_mode_threshold); 
     799            config->getValueForSetting("ieee1394.isomanager.min_interrupts_per_period", min_interrupts_per_period); 
     800            config->getValueForSetting("ieee1394.isomanager.max_nb_buffers_recv", max_nb_buffers_recv); 
     801            config->getValueForSetting("ieee1394.isomanager.min_packetsize_recv", min_packetsize_recv); 
     802        } 
     803 
    761804        // setup the optimal parameters for the raw1394 ISO buffering 
    762805        unsigned int packets_per_period = stream->getPacketsPerPeriod(); 
    763         unsigned int max_packet_size = stream->getMaxPacketSize() + 8; // bufferfill takes another 8 bytes for headers 
     806        // reserve space for the 1394 header too (might not be necessary) 
     807        unsigned int max_packet_size = stream->getMaxPacketSize() + 8; 
    764808        unsigned int page_size = getpagesize(); 
     809 
     810        enum raw1394_iso_dma_recv_mode receive_mode; 
     811        switch(receive_mode_setting) { 
     812            case 0: 
     813                if(packets_per_period < (unsigned)bufferfill_mode_threshold) { 
     814                    debugOutput( DEBUG_LEVEL_VERBOSE, "Using packet-per-buffer mode (auto) [%d, %d]\n", 
     815                                 packets_per_period, bufferfill_mode_threshold); 
     816                    receive_mode = RAW1394_DMA_PACKET_PER_BUFFER; 
     817                } else { 
     818                    debugOutput( DEBUG_LEVEL_VERBOSE, "Using bufferfill mode (auto) [%d, %d]\n", 
     819                                 packets_per_period, bufferfill_mode_threshold); 
     820                    receive_mode = RAW1394_DMA_BUFFERFILL; 
     821                } 
     822                break; 
     823            case 1:  
     824                debugOutput( DEBUG_LEVEL_VERBOSE, "Using packet-per-buffer mode (config)\n"); 
     825                receive_mode = RAW1394_DMA_PACKET_PER_BUFFER; 
     826                break; 
     827            case 2: 
     828                debugOutput( DEBUG_LEVEL_VERBOSE, "Using bufferfill mode (config)\n"); 
     829                receive_mode = RAW1394_DMA_BUFFERFILL; 
     830                break; 
     831            default: debugWarning("Bogus receive mode setting in config: %d\n", receive_mode_setting); 
     832        } 
    765833 
    766834        // Ensure we don't request a packet size bigger than the 
     
    771839            return false; 
    772840        } 
     841        if (max_packet_size < (unsigned)min_packetsize_recv) { 
     842            debugError("min packet size (%u) < MIN_RECV_PACKET_SIZE (%u), using min value\n", 
     843                       max_packet_size, min_packetsize_recv); 
     844            max_packet_size = min_packetsize_recv; 
     845        } 
    773846 
    774847        // the interrupt/wakeup interval prediction of raw1394 is a mess... 
    775         int irq_interval = (packets_per_period-1) / MINIMUM_INTERRUPTS_PER_PERIOD
     848        int irq_interval = (packets_per_period-1) / min_interrupts_per_period
    776849        if(irq_interval <= 0) irq_interval=1; 
    777850 
    778851        // the receive buffer size doesn't matter for the latency, 
    779         // but it has a minimal value in order for libraw to operate correctly (300) 
    780         int buffers=400; 
     852        // it does seem to be confined to a certain region for correct 
     853        // operation. However it is not clear how many. 
     854        int buffers = max_nb_buffers_recv; 
     855 
     856        // ensure at least 2 hardware interrupts per ISO buffer wraparound 
     857        if(irq_interval > buffers/2) { 
     858            irq_interval = buffers/2; 
     859        } 
    781860 
    782861        // create the actual handler 
     862        debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoRecvHandler\n"); 
    783863        h = new IsoHandler(*this, IsoHandler::eHT_Receive, 
    784864                           buffers, max_packet_size, irq_interval); 
    785  
    786         debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoRecvHandler\n"); 
    787865 
    788866        if(!h) { 
     
    791869        } 
    792870 
     871        h->setReceiveMode(receive_mode); 
     872 
    793873    } else if (stream->getType()==StreamProcessor::ePT_Transmit) { 
     874        // grab the options from the parent 
     875        Util::Configuration *config = m_service.getConfiguration(); 
     876        int min_interrupts_per_period = MINIMUM_INTERRUPTS_PER_PERIOD; 
     877        int max_nb_buffers_xmit = MAX_XMIT_NB_BUFFERS; 
     878        int max_packetsize_xmit = MAX_XMIT_PACKET_SIZE; 
     879        int min_packetsize_xmit = MIN_XMIT_PACKET_SIZE; 
     880        if(config) { 
     881            config->getValueForSetting("ieee1394.isomanager.min_interrupts_per_period", min_interrupts_per_period); 
     882            config->getValueForSetting("ieee1394.isomanager.max_nb_buffers_xmit", max_nb_buffers_xmit); 
     883            config->getValueForSetting("ieee1394.isomanager.max_packetsize_xmit", max_packetsize_xmit); 
     884            config->getValueForSetting("ieee1394.isomanager.min_packetsize_xmit", min_packetsize_xmit); 
     885        } 
     886 
    794887        // setup the optimal parameters for the raw1394 ISO buffering 
    795 //        unsigned int packets_per_period = stream->getPacketsPerPeriod(); 
    796         unsigned int max_packet_size = stream->getMaxPacketSize(); 
    797 //         unsigned int page_size = getpagesize(); 
    798  
    799         // Ensure we don't request a packet size bigger than the 
    800         // kernel-enforced maximum which is currently 1 page. 
    801 //         if (max_packet_size > page_size) { 
    802 //             debugError("max packet size (%u) > page size (%u)\n", max_packet_size, page_size); 
    803 //             return false; 
    804 //         } 
    805         if (max_packet_size > MAX_XMIT_PACKET_SIZE) { 
     888        // reserve space for the 1394 header too (might not be necessary) 
     889        unsigned int max_packet_size = stream->getMaxPacketSize() + 8; 
     890 
     891        if (max_packet_size > (unsigned)max_packetsize_xmit) { 
    806892            debugError("max packet size (%u) > MAX_XMIT_PACKET_SIZE (%u)\n", 
    807                        max_packet_size, MAX_XMIT_PACKET_SIZE); 
     893                       max_packet_size, max_packetsize_xmit); 
    808894            return false; 
    809895        } 
    810  
    811         // the SP specifies how many packets to ISO-buffer 
    812         int buffers = stream->getNbPacketsIsoXmitBuffer(); 
    813         if (buffers > MAX_XMIT_NB_BUFFERS) { 
    814             debugOutput(DEBUG_LEVEL_VERBOSE, 
    815                         "nb buffers (%u) > MAX_XMIT_NB_BUFFERS (%u)\n", 
    816                         buffers, MAX_XMIT_NB_BUFFERS)
    817             buffers = MAX_XMIT_NB_BUFFERS
    818         } 
    819         unsigned int irq_interval = buffers / MINIMUM_INTERRUPTS_PER_PERIOD
     896        if (max_packet_size < (unsigned)min_packetsize_xmit) { 
     897            debugError("min packet size (%u) < MIN_XMIT_PACKET_SIZE (%u), using min value\n", 
     898                       max_packet_size, min_packetsize_xmit); 
     899            max_packet_size = min_packetsize_xmit; 
     900        } 
     901 
     902        int buffers = max_nb_buffers_xmit
     903        unsigned int packets_per_period = stream->getPacketsPerPeriod()
     904 
     905        int irq_interval = (packets_per_period-1) / min_interrupts_per_period
    820906        if(irq_interval <= 0) irq_interval=1; 
     907        // ensure at least 2 hardware interrupts per ISO buffer wraparound 
     908        if(irq_interval > buffers/2) { 
     909            irq_interval = buffers/2; 
     910        } 
    821911 
    822912        debugOutput( DEBUG_LEVEL_VERBOSE, " creating IsoXmitHandler\n"); 
  • trunk/libffado/src/libieee1394/IsoHandlerManager.h

    r1336 r1498  
    5858class IsoTask : public Util::RunnableInterface 
    5959{ 
     60    friend class IsoHandlerManager; 
    6061    public: 
    6162        IsoTask(IsoHandlerManager& manager, enum IsoHandler::EHandlerType); 
     
    114115#endif 
    115116 
    116         // activity signaling 
    117         sem_t m_activity_semaphore; 
    118  
    119117        enum IsoHandler::EHandlerType m_handlerType; 
    120118        bool m_running; 
    121119        bool m_in_busreset; 
     120 
     121        // activity signaling 
     122        sem_t m_activity_semaphore; 
     123        long long int m_activity_wait_timeout_nsec; 
    122124 
    123125        // debug stuff 
     
    198200         */ 
    199201        bool handleBusReset(); 
     202 
    200203    // the state machine 
    201204    private: