diff options
author | Christopher Hall <christopher.s.hall@intel.com> | 2014-04-03 16:29:05 -0700 |
---|---|---|
committer | Christopher Hall <christopher.s.hall@intel.com> | 2014-04-03 16:29:05 -0700 |
commit | 01efdf94bfdfc2e535e7b06e8a79de0d076f0623 (patch) | |
tree | 700a7597cf6ba429db5ccf9a153143e22b3c7894 | |
parent | b0d89f2af30c5ff369b4549229eac70d64038905 (diff) | |
download | Open-AVB-01efdf94bfdfc2e535e7b06e8a79de0d076f0623.tar.gz |
Added missing Linux files
-rw-r--r-- | daemons/gptp/linux/src/linux_hal_common.cpp | 798 | ||||
-rw-r--r-- | daemons/gptp/linux/src/linux_hal_common.hpp | 309 | ||||
-rw-r--r-- | daemons/gptp/linux/src/linux_hal_generic.cpp | 403 | ||||
-rw-r--r-- | daemons/gptp/linux/src/linux_hal_generic.hpp | 110 | ||||
-rw-r--r-- | daemons/gptp/linux/src/linux_hal_generic_adj.cpp | 101 | ||||
-rw-r--r-- | daemons/gptp/linux/src/linux_hal_generic_tsprivate.hpp | 53 | ||||
-rw-r--r-- | daemons/gptp/linux/src/linux_hal_i210.cpp | 171 | ||||
-rw-r--r-- | daemons/gptp/linux/src/linux_hal_intelce.cpp | 243 | ||||
-rw-r--r-- | daemons/gptp/linux/src/linux_hal_intelce.hpp | 75 | ||||
-rw-r--r-- | daemons/gptp/linux/src/platform.cpp | 48 |
10 files changed, 2311 insertions, 0 deletions
diff --git a/daemons/gptp/linux/src/linux_hal_common.cpp b/daemons/gptp/linux/src/linux_hal_common.cpp new file mode 100644 index 00000000..38287274 --- /dev/null +++ b/daemons/gptp/linux/src/linux_hal_common.cpp @@ -0,0 +1,798 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +#include <linux_hal_common.hpp> +#include <sys/types.h> +#include <avbts_clock.hpp> +#include <avbts_port.hpp> + +#include <pthread.h> +#include <ipcdef.hpp> + +#include <sys/mman.h> +#include <fcntl.h> +#include <grp.h> +#include <net/if.h> + +#include <unistd.h> +#include <errno.h> + +#include <signal.h> +#include <net/ethernet.h> /* the L2 protocols */ + +#include <netpacket/packet.h> +#include <sys/ioctl.h> +#include <sys/types.h> + +Timestamp tsToTimestamp(struct timespec *ts) +{ + Timestamp ret; + int seclen = sizeof(ts->tv_sec) - sizeof(ret.seconds_ls); + if (seclen > 0) { + ret.seconds_ms = + ts->tv_sec >> (sizeof(ts->tv_sec) - seclen) * 8; + ret.seconds_ls = ts->tv_sec & 0xFFFFFFFF; + } else { + ret.seconds_ms = 0; + ret.seconds_ls = ts->tv_sec; + } + ret.nanoseconds = ts->tv_nsec; + return ret; +} + +LinuxNetworkInterface::~LinuxNetworkInterface() { + close( sd_event ); + close( sd_general ); +} + +net_result LinuxNetworkInterface::send +( LinkLayerAddress *addr, uint8_t *payload, size_t length, bool timestamp ) { + sockaddr_ll *remote = NULL; + int err; + remote = new struct sockaddr_ll; + memset( remote, 0, sizeof( *remote )); + remote->sll_family = AF_PACKET; + remote->sll_protocol = PLAT_htons( PTP_ETHERTYPE ); + remote->sll_ifindex = ifindex; + remote->sll_halen = ETH_ALEN; + addr->toOctetArray( remote->sll_addr ); + + if( timestamp ) { +#ifndef ARCH_INTELCE + net_lock.lock(); +#endif + err = sendto + ( sd_event, payload, length, 0, (sockaddr *) remote, + sizeof( *remote )); + } else { + err = sendto + ( sd_general, payload, length, 0, (sockaddr *) remote, + sizeof( *remote )); + } + delete remote; + if( err == -1 ) { + XPTPD_ERROR( "Failed to send: %s(%d)", strerror(errno), errno ); + return net_fatal; + } + return net_succeed; +} + + +void LinuxNetworkInterface::disable_clear_rx_queue() { + struct packet_mreq mr_8021as; + int err; + char buf[256]; + + if( !net_lock.lock() ) { + fprintf( stderr, "D rx lock failed\n" ); + _exit(0); + } + + memset( &mr_8021as, 0, sizeof( mr_8021as )); + mr_8021as.mr_ifindex = ifindex; + mr_8021as.mr_type = PACKET_MR_MULTICAST; + mr_8021as.mr_alen = 6; + memcpy( mr_8021as.mr_address, P8021AS_MULTICAST, mr_8021as.mr_alen ); + err = setsockopt + ( sd_event, SOL_PACKET, PACKET_DROP_MEMBERSHIP, &mr_8021as, + sizeof( mr_8021as )); + if( err == -1 ) { + XPTPD_ERROR + ( "Unable to add PTP multicast addresses to port id: %u", + ifindex ); + return; + } + + while( recvfrom( sd_event, buf, 256, MSG_DONTWAIT, NULL, 0 ) != -1 ); + + return; +} + +void LinuxNetworkInterface::reenable_rx_queue() { + struct packet_mreq mr_8021as; + int err; + + memset( &mr_8021as, 0, sizeof( mr_8021as )); + mr_8021as.mr_ifindex = ifindex; + mr_8021as.mr_type = PACKET_MR_MULTICAST; + mr_8021as.mr_alen = 6; + memcpy( mr_8021as.mr_address, P8021AS_MULTICAST, mr_8021as.mr_alen ); + err = setsockopt + ( sd_event, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr_8021as, + sizeof( mr_8021as )); + if( err == -1 ) { + XPTPD_ERROR + ( "Unable to add PTP multicast addresses to port id: %u", + ifindex ); + return; + } + + if( !net_lock.unlock() ) { + fprintf( stderr, "D failed unlock rx lock, %d\n", err ); + } +} + +struct LinuxTimerQueuePrivate { + pthread_t signal_thread; +}; + +struct LinuxTimerQueueActionArg { + timer_t timer_handle; + struct sigevent sevp; + event_descriptor_t *inner_arg; + ostimerq_handler func; + int type; + bool rm; +}; + +LinuxTimerQueue::~LinuxTimerQueue() { + pthread_join(_private->signal_thread,NULL); + if( _private != NULL ) delete _private; +} + +bool LinuxTimerQueue::init() { + _private = new LinuxTimerQueuePrivate; + if( _private == NULL ) return false; + + return true; +} + +void *LinuxTimerQueueHandler( void *arg ) { + LinuxTimerQueue *timerq = (LinuxTimerQueue *) arg; + sigset_t waitfor; + struct timespec timeout; + timeout.tv_sec = 0; timeout.tv_nsec = 100000000; /* 100 ms */ + + sigemptyset( &waitfor ); + + while( !timerq->stop ) { + siginfo_t info; + LinuxTimerQueueMap_t::iterator iter; + sigaddset( &waitfor, SIGUSR1 ); + if( sigtimedwait( &waitfor, &info, &timeout ) == -1 ) { + if( errno == EAGAIN ) continue; + else break; + } + if( timerq->lock->lock() != oslock_ok ) { + break; + } + + iter = timerq->timerQueueMap.find(info.si_value.sival_int); + if( iter != timerq->timerQueueMap.end() ) { + struct LinuxTimerQueueActionArg *arg = iter->second; + timerq->timerQueueMap.erase(iter); + timerq->LinuxTimerQueueAction( arg ); + timer_delete(arg->timer_handle); + delete arg; + } + if( timerq->lock->unlock() != oslock_ok ) { + break; + } + } + + return NULL; +} + +void LinuxTimerQueue::LinuxTimerQueueAction( LinuxTimerQueueActionArg *arg ) { + arg->func( arg->inner_arg ); + + return; +} + +OSTimerQueue *LinuxTimerQueueFactory::createOSTimerQueue + ( IEEE1588Clock *clock ) { + LinuxTimerQueue *ret = new LinuxTimerQueue(); + + if( !ret->init() ) { + return NULL; + } + + if( pthread_create + ( &(ret->_private->signal_thread), + NULL, LinuxTimerQueueHandler, ret ) != 0 ) { + delete ret; + return NULL; + } + + ret->stop = false; + ret->key = 0; + ret->lock = clock->timerQLock(); + + return ret; +} + + + +bool LinuxTimerQueue::addEvent +( unsigned long micros, int type, ostimerq_handler func, + event_descriptor_t * arg, bool rm, unsigned *event) { + LinuxTimerQueueActionArg *outer_arg; + int err; + LinuxTimerQueueMap_t::iterator iter; + + + outer_arg = new LinuxTimerQueueActionArg; + outer_arg->inner_arg = arg; + outer_arg->rm = rm; + outer_arg->func = func; + outer_arg->type = type; + outer_arg->rm = rm; + + // Find key that we can use + while( timerQueueMap.find( key ) != timerQueueMap.end() ) { + ++key; + } + + { + struct itimerspec its; + memset(&(outer_arg->sevp), 0, sizeof(outer_arg->sevp)); + outer_arg->sevp.sigev_notify = SIGEV_SIGNAL; + outer_arg->sevp.sigev_signo = SIGUSR1; + outer_arg->sevp.sigev_value.sival_int = key; + if ( timer_create + (CLOCK_MONOTONIC, &outer_arg->sevp, &outer_arg->timer_handle) + == -1) { + XPTPD_ERROR("timer_create failed - %s", strerror(errno)); + return false; + } + timerQueueMap[key] = outer_arg; + + memset(&its, 0, sizeof(its)); + its.it_value.tv_sec = micros / 1000000; + its.it_value.tv_nsec = (micros % 1000000) * 1000; + err = timer_settime( outer_arg->timer_handle, 0, &its, NULL ); + if( err < 0 ) { + fprintf + ( stderr, "Failed to arm timer: %s\n", + strerror( errno )); + return false; + } + } + + return true; +} + + +bool LinuxTimerQueue::cancelEvent( int type, unsigned *event ) { + LinuxTimerQueueMap_t::iterator iter; + for( iter = timerQueueMap.begin(); iter != timerQueueMap.end();) { + if( (iter->second)->type == type ) { + // Delete element + if( (iter->second)->rm ) { + delete (iter->second)->inner_arg; + } + timer_delete(iter->second->timer_handle); + delete iter->second; + timerQueueMap.erase(iter++); + } else { + ++iter; + } + } + + return true; +} + + +void* OSThreadCallback( void* input ) { + OSThreadArg *arg = (OSThreadArg*) input; + + arg->ret = arg->func( arg->arg ); + return 0; +} + +bool LinuxTimestamper::post_init( int ifindex, int sd, TicketingLock *lock ) { + return true; +} + +LinuxTimestamper::~LinuxTimestamper() {} + +unsigned long LinuxTimer::sleep(unsigned long micros) { + struct timespec req = { 0, (long int)(micros * 1000) }; + struct timespec rem; + int ret = nanosleep( &req, &rem ); + while( ret == -1 && errno == EINTR ) { + req = rem; + ret = nanosleep( &req, &rem ); + } + if( ret == -1 ) { + fprintf + ( stderr, "Error calling nanosleep: %s\n", strerror( errno )); + _exit(-1); + } + return micros; +} + +struct TicketingLockPrivate { + pthread_cond_t condition; + pthread_mutex_t cond_lock; +}; + +bool TicketingLock::lock( bool *got ) { + uint8_t ticket; + bool yield = false; + bool ret = true; + if( !init_flag ) return false; + + if( pthread_mutex_lock( &_private->cond_lock ) != 0 ) { + ret = false; + goto done; + } + // Take a ticket + ticket = cond_ticket_issue++; + while( ticket != cond_ticket_serving ) { + if( got != NULL ) { + *got = false; + --cond_ticket_issue; + yield = true; + goto unlock; + } + if( pthread_cond_wait( &_private->condition, &_private->cond_lock ) != 0 ) { + ret = false; + goto unlock; + } + } + + if( got != NULL ) *got = true; + + unlock: + if( pthread_mutex_unlock( &_private->cond_lock ) != 0 ) { + ret = false; + goto done; + } + + if( yield ) pthread_yield(); + + done: + return ret; +} + +bool TicketingLock::unlock() { + bool ret = true; + if( !init_flag ) return false; + + if( pthread_mutex_lock( &_private->cond_lock ) != 0 ) { + ret = false; + goto done; + } + ++cond_ticket_serving; + if( pthread_cond_broadcast( &_private->condition ) != 0 ) { + ret = false; + goto unlock; + } + + unlock: + if( pthread_mutex_unlock( &_private->cond_lock ) != 0 ) { + ret = false; + goto done; + } + + done: + return ret; +} + +bool TicketingLock::init() { + int err; + if( init_flag ) return false; // Don't do this more than once + _private = new TicketingLockPrivate; + if( _private == NULL ) return false; + + err = pthread_mutex_init( &_private->cond_lock, NULL ); + if( err != 0 ) return false; + err = pthread_cond_init( &_private->condition, NULL ); + if( err != 0 ) return false; + in_use = false; + cond_ticket_issue = 0; + cond_ticket_serving = 0; + init_flag = true; + + return true; +} + +TicketingLock::TicketingLock() { + init_flag = false; + _private = NULL; +} + +TicketingLock::~TicketingLock() { + if( _private != NULL ) delete _private; +} + +struct LinuxLockPrivate { + pthread_t thread_id; + pthread_mutexattr_t mta; + pthread_mutex_t mutex; + pthread_cond_t port_ready_signal; +}; + +bool LinuxLock::initialize( OSLockType type ) { + int lock_c; + + _private = new LinuxLockPrivate; + if( _private == NULL ) return false; + + pthread_mutexattr_init(&_private->mta); + if( type == oslock_recursive ) + pthread_mutexattr_settype(&_private->mta, PTHREAD_MUTEX_RECURSIVE); + lock_c = pthread_mutex_init(&_private->mutex,&_private->mta); + if(lock_c != 0) { + XPTPD_ERROR("Mutex initialization failed - %s\n",strerror(errno)); + return oslock_fail; + } + return oslock_ok; +} + +LinuxLock::~LinuxLock() { + int lock_c = pthread_mutex_lock(&_private->mutex); + if(lock_c == 0) { + pthread_mutex_destroy( &_private->mutex ); + } +} + +OSLockResult LinuxLock::lock() { + int lock_c; + lock_c = pthread_mutex_lock(&_private->mutex); + if(lock_c != 0) { + fprintf( stderr, "LinuxLock: lock failed %d\n", lock_c ); + return oslock_fail; + } + return oslock_ok; +} + +OSLockResult LinuxLock::trylock() { + int lock_c; + lock_c = pthread_mutex_trylock(&_private->mutex); + if(lock_c != 0) return oslock_fail; + return oslock_ok; +} + +OSLockResult LinuxLock::unlock() { + int lock_c; + lock_c = pthread_mutex_unlock(&_private->mutex); + if(lock_c != 0) { + fprintf( stderr, "LinuxLock: unlock failed %d\n", lock_c ); + return oslock_fail; + } + return oslock_ok; +} + +struct LinuxConditionPrivate { + pthread_cond_t port_ready_signal; + pthread_mutex_t port_lock; +}; + + +LinuxCondition::~LinuxCondition() { + if( _private != NULL ) delete _private; +} + +bool LinuxCondition::initialize() { + int lock_c; + + _private = new LinuxConditionPrivate; + if( _private == NULL ) return false; + + pthread_cond_init(&_private->port_ready_signal, NULL); + lock_c = pthread_mutex_init(&_private->port_lock, NULL); + if (lock_c != 0) + return false; + return true; +} + +bool LinuxCondition::wait_prelock() { + pthread_mutex_lock(&_private->port_lock); + up(); + return true; +} + +bool LinuxCondition::wait() { + pthread_cond_wait(&_private->port_ready_signal, &_private->port_lock); + down(); + pthread_mutex_unlock(&_private->port_lock); + return true; +} + +bool LinuxCondition::signal() { + pthread_mutex_lock(&_private->port_lock); + if (waiting()) + pthread_cond_broadcast(&_private->port_ready_signal); + pthread_mutex_unlock(&_private->port_lock); + return true; +} + +struct LinuxThreadPrivate { + pthread_t thread_id; +}; + +bool LinuxThread::start(OSThreadFunction function, void *arg) { + sigset_t set; + sigset_t oset; + int err; + + _private = new LinuxThreadPrivate; + if( _private == NULL ) return false; + + arg_inner = new OSThreadArg(); + arg_inner->func = function; + arg_inner->arg = arg; + sigemptyset(&set); + sigaddset(&set, SIGALRM); + err = pthread_sigmask(SIG_BLOCK, &set, &oset); + if (err != 0) { + XPTPD_ERROR + ("Add timer pthread_sigmask( SIG_BLOCK ... )"); + return false; + } + err = pthread_create(&_private->thread_id, NULL, OSThreadCallback, + arg_inner); + if (err != 0) + return false; + sigdelset(&oset, SIGALRM); + err = pthread_sigmask(SIG_SETMASK, &oset, NULL); + if (err != 0) { + XPTPD_ERROR + ("Add timer pthread_sigmask( SIG_SETMASK ... )"); + return false; + } + + return true; +} + +bool LinuxThread::join(OSThreadExitCode & exit_code) { + int err; + err = pthread_join(_private->thread_id, NULL); + if (err != 0) + return false; + exit_code = arg_inner->ret; + delete arg_inner; + return true; +} + +LinuxThread::LinuxThread() { + _private = NULL; +}; + +LinuxThread::~LinuxThread() { + if( _private != NULL ) delete _private; +} + +LinuxSharedMemoryIPC::~LinuxSharedMemoryIPC() { + munmap(master_offset_buffer, SHM_SIZE); + shm_unlink(SHM_NAME); +} + +bool LinuxSharedMemoryIPC::init( OS_IPC_ARG *barg ) { + LinuxIPCArg *arg; + struct group *grp; + const char *group_name; + if( barg == NULL ) { + group_name = DEFAULT_GROUPNAME; + } else { + arg = dynamic_cast<LinuxIPCArg *> (barg); + if( arg == NULL ) { + XPTPD_ERROR( "Wrong IPC init arg type" ); + goto exit_error; + } else { + group_name = arg->group_name; + } + } + grp = getgrnam( group_name ); + if( grp == NULL ) { + XPTPD_ERROR( "Group %s not found", group_name ); + goto exit_error; + } + + shm_fd = shm_open( SHM_NAME, O_RDWR | O_CREAT, 0660 ); + if( shm_fd == -1 ) { + XPTPD_ERROR( "shm_open(): %s", strerror(errno) ); + goto exit_error; + } + if (fchown(shm_fd, -1, grp->gr_gid) < 0) { + XPTPD_ERROR("fchwon()"); + goto exit_unlink; + } + if( ftruncate( shm_fd, SHM_SIZE ) == -1 ) { + XPTPD_ERROR( "ftruncate()" ); + goto exit_unlink; + } + master_offset_buffer = (char *) mmap + ( NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_LOCKED | MAP_SHARED, + shm_fd, 0 ); + if( master_offset_buffer == (char *) -1 ) { + XPTPD_ERROR( "mmap()" ); + goto exit_unlink; + } + /*create a mutex */ + err = pthread_mutex_init((pthread_mutex_t *) master_offset_buffer, NULL); + if(err != 0) { + XPTPD_ERROR + ("sharedmem - Mutex initialization failed - %s\n", + strerror(errno)); + goto exit_unlink; + } + return true; + exit_unlink: + shm_unlink( SHM_NAME ); + exit_error: + return false; +} + +bool LinuxSharedMemoryIPC::update +(int64_t ml_phoffset, int64_t ls_phoffset, FrequencyRatio ml_freqoffset, + FrequencyRatio ls_freqoffset, uint64_t local_time, uint32_t sync_count, + uint32_t pdelay_count, PortState port_state ) { + int buf_offset = 0; + char *shm_buffer = master_offset_buffer; + gPtpTimeData *ptimedata; + if( shm_buffer != NULL ) { + /* lock */ + pthread_mutex_lock((pthread_mutex_t *) shm_buffer); + buf_offset += sizeof(pthread_mutex_t); + ptimedata = (gPtpTimeData *) (shm_buffer + buf_offset); + ptimedata->ml_phoffset = ml_phoffset; + ptimedata->ls_phoffset = ls_phoffset; + ptimedata->ml_freqoffset = ml_freqoffset; + ptimedata->ls_freqoffset = ls_freqoffset; + ptimedata->local_time = local_time; + ptimedata->sync_count = sync_count; + ptimedata->pdelay_count = pdelay_count; + ptimedata->port_state = port_state; + /* unlock */ + pthread_mutex_unlock((pthread_mutex_t *) shm_buffer); + } + return true; +} + +void LinuxSharedMemoryIPC::stop() { + if( master_offset_buffer != NULL ) { + munmap( master_offset_buffer, SHM_SIZE ); + shm_unlink( SHM_NAME ); + } +} + +bool LinuxNetworkInterfaceFactory::createInterface +( OSNetworkInterface **net_iface, InterfaceLabel *label, + HWTimestamper *timestamper ) { + struct ifreq device; + int err; + struct sockaddr_ll ifsock_addr; + struct packet_mreq mr_8021as; + LinkLayerAddress addr; + int ifindex; + + LinuxNetworkInterface *net_iface_l = new LinuxNetworkInterface(); + + if( !net_iface_l->net_lock.init()) { + XPTPD_ERROR( "Failed to initialize network lock"); + return false; + } + + InterfaceName *ifname = dynamic_cast<InterfaceName *>(label); + if( ifname == NULL ){ + XPTPD_ERROR( "ifname == NULL"); + return false; + } + + net_iface_l->sd_general = socket( PF_PACKET, SOCK_DGRAM, 0 ); + if( net_iface_l->sd_general == -1 ) { + XPTPD_ERROR( "failed to open general socket: %s", strerror(errno)); + return false; + } + net_iface_l->sd_event = socket( PF_PACKET, SOCK_DGRAM, 0 ); + if( net_iface_l->sd_event == -1 ) { + XPTPD_ERROR + ( "failed to open event socket: %s \n", strerror(errno)); + return false; + } + + memset( &device, 0, sizeof(device)); + ifname->toString( device.ifr_name, IFNAMSIZ ); + err = ioctl( net_iface_l->sd_event, SIOCGIFHWADDR, &device ); + if( err == -1 ) { + XPTPD_ERROR + ( "Failed to get interface address: %s", strerror( errno )); + return false; + } + + addr = LinkLayerAddress( (uint8_t *)&device.ifr_hwaddr.sa_data ); + net_iface_l->local_addr = addr; + err = ioctl( net_iface_l->sd_event, SIOCGIFINDEX, &device ); + if( err == -1 ) { + XPTPD_ERROR + ( "Failed to get interface index: %s", strerror( errno )); + return false; + } + ifindex = device.ifr_ifindex; + net_iface_l->ifindex = ifindex; + memset( &mr_8021as, 0, sizeof( mr_8021as )); + mr_8021as.mr_ifindex = ifindex; + mr_8021as.mr_type = PACKET_MR_MULTICAST; + mr_8021as.mr_alen = 6; + memcpy( mr_8021as.mr_address, P8021AS_MULTICAST, mr_8021as.mr_alen ); + err = setsockopt + ( net_iface_l->sd_event, SOL_PACKET, PACKET_ADD_MEMBERSHIP, + &mr_8021as, sizeof( mr_8021as )); + if( err == -1 ) { + XPTPD_ERROR + ( "Unable to add PTP multicast addresses to port id: %u", + ifindex ); + return false; + } + + memset( &ifsock_addr, 0, sizeof( ifsock_addr )); + ifsock_addr.sll_family = AF_PACKET; + ifsock_addr.sll_ifindex = ifindex; + ifsock_addr.sll_protocol = PLAT_htons( PTP_ETHERTYPE ); + err = bind + ( net_iface_l->sd_event, (sockaddr *) &ifsock_addr, + sizeof( ifsock_addr )); + if( err == -1 ) { + XPTPD_ERROR( "Call to bind() failed: %s", strerror(errno) ); + return false; + } + + net_iface_l->timestamper = + dynamic_cast <LinuxTimestamper *>(timestamper); + if(net_iface_l->timestamper == NULL) { + XPTPD_ERROR( "timestamper == NULL\n" ); + return false; + } + if( !net_iface_l->timestamper->post_init + ( ifindex, net_iface_l->sd_event, &net_iface_l->net_lock )) { + XPTPD_ERROR( "post_init failed\n" ); + return false; + } + *net_iface = net_iface_l; + + return true; +} + diff --git a/daemons/gptp/linux/src/linux_hal_common.hpp b/daemons/gptp/linux/src/linux_hal_common.hpp new file mode 100644 index 00000000..cfe54fcb --- /dev/null +++ b/daemons/gptp/linux/src/linux_hal_common.hpp @@ -0,0 +1,309 @@ +/****************************************************************************** + + Copyright (c) 2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +#ifndef LINUX_HAL_COMMON_HPP +#define LINUX_HAL_COMMON_HPP + +#include "avbts_osnet.hpp" +#include "avbts_oslock.hpp" +#include "avbts_oscondition.hpp" +#include "avbts_ostimerq.hpp" +#include "avbts_ostimer.hpp" +#include "avbts_osthread.hpp" +#include "avbts_osipc.hpp" +#include "ieee1588.hpp" + +#include <list> + +#define ONE_WAY_PHY_DELAY 400 +#define P8021AS_MULTICAST "\x01\x80\xC2\x00\x00\x0E" +#define PTP_DEVICE "/dev/ptpXX" +#define PTP_DEVICE_IDX_OFFS 8 +#define CLOCKFD 3 +#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) + +struct timespec; +extern Timestamp tsToTimestamp(struct timespec *ts); + +struct TicketingLockPrivate; +typedef struct TicketingLockPrivate * TicketingLockPrivate_t; + + +class TicketingLock { +public: + bool lock( bool *got = NULL ); + bool unlock(); + bool init(); + TicketingLock(); + ~TicketingLock(); +private: + bool init_flag; + TicketingLockPrivate_t _private; + bool in_use; + uint8_t cond_ticket_issue; + uint8_t cond_ticket_serving; +}; + +class LinuxTimestamper : public HWTimestamper { +public: + virtual ~LinuxTimestamper() = 0; + virtual bool post_init( int ifindex, int sd, TicketingLock *lock ) = 0; +}; + +class LinuxNetworkInterface : public OSNetworkInterface { + friend class LinuxNetworkInterfaceFactory; +private: + LinkLayerAddress local_addr; + int sd_event; + int sd_general; + LinuxTimestamper *timestamper; + int ifindex; + + TicketingLock net_lock; +public: + virtual net_result send + ( LinkLayerAddress *addr, uint8_t *payload, size_t length, + bool timestamp ); + + virtual net_result nrecv + ( LinkLayerAddress *addr, uint8_t *payload, size_t &length ); + + void disable_clear_rx_queue(); + void reenable_rx_queue(); + + virtual void getLinkLayerAddress( LinkLayerAddress *addr ) { + *addr = local_addr; + } + + // No offset needed for Linux SOCK_DGRAM packet + virtual unsigned getPayloadOffset() { + return 0; + } + ~LinuxNetworkInterface(); +protected: + LinuxNetworkInterface() {}; +}; + +typedef std::list<LinuxNetworkInterface *> LinuxNetworkInterfaceList; + +struct LinuxLockPrivate; +typedef LinuxLockPrivate * LinuxLockPrivate_t; + +class LinuxLock : public OSLock { + friend class LinuxLockFactory; +private: + OSLockType type; + LinuxLockPrivate_t _private; +protected: + LinuxLock() { + _private = NULL; + } + bool initialize( OSLockType type ); + ~LinuxLock(); + OSLockResult lock(); + OSLockResult trylock(); + OSLockResult unlock(); +}; + +class LinuxLockFactory:public OSLockFactory { +public: + OSLock * createLock(OSLockType type) { + LinuxLock *lock = new LinuxLock(); + if (lock->initialize(type) != oslock_ok) { + delete lock; + lock = NULL; + } + return lock; + } +}; + +struct LinuxConditionPrivate; +typedef struct LinuxConditionPrivate * LinuxConditionPrivate_t; + +class LinuxCondition : public OSCondition { + friend class LinuxConditionFactory; +private: + LinuxConditionPrivate_t _private; +protected: + bool initialize(); +public: + bool wait_prelock(); + bool wait(); + bool signal(); + ~LinuxCondition(); + LinuxCondition() { + _private = NULL; + } +}; + +class LinuxConditionFactory : public OSConditionFactory { +public: + OSCondition * createCondition() { + LinuxCondition *result = new LinuxCondition(); + return result->initialize() ? result : NULL; + } +}; + +struct LinuxTimerQueueActionArg; + +typedef std::map < int, struct LinuxTimerQueueActionArg *> LinuxTimerQueueMap_t; + +void *LinuxTimerQueueHandler( void *arg ); + +struct LinuxTimerQueuePrivate; +typedef struct LinuxTimerQueuePrivate * LinuxTimerQueuePrivate_t; + +class LinuxTimerQueue : public OSTimerQueue { + friend class LinuxTimerQueueFactory; + friend void *LinuxTimerQueueHandler( void *); +private: + LinuxTimerQueueMap_t timerQueueMap; + int key; + bool stop; + LinuxTimerQueuePrivate_t _private; + OSLock *lock; + void LinuxTimerQueueAction( LinuxTimerQueueActionArg *arg ); +protected: + LinuxTimerQueue() { + _private = NULL; + } + virtual bool init(); +public: + ~LinuxTimerQueue(); + bool addEvent + ( unsigned long micros, int type, ostimerq_handler func, + event_descriptor_t * arg, bool rm, unsigned *event ); + bool cancelEvent( int type, unsigned *event ); +}; + +class LinuxTimerQueueFactory : public OSTimerQueueFactory { +public: + virtual OSTimerQueue *createOSTimerQueue( IEEE1588Clock *clock ); +}; + + + +class LinuxTimer : public OSTimer { + friend class LinuxTimerFactory; + public: + virtual unsigned long sleep(unsigned long micros); + protected: + LinuxTimer() {}; +}; + +class LinuxTimerFactory : public OSTimerFactory { + public: + virtual OSTimer * createTimer() { + return new LinuxTimer(); + } +}; + +struct OSThreadArg { + OSThreadFunction func; + void *arg; + OSThreadExitCode ret; +}; + +void *OSThreadCallback(void *input); + +struct LinuxThreadPrivate; +typedef LinuxThreadPrivate * LinuxThreadPrivate_t; + +class LinuxThread : public OSThread { + friend class LinuxThreadFactory; + private: + LinuxThreadPrivate_t _private; + OSThreadArg *arg_inner; + public: + virtual bool start(OSThreadFunction function, void *arg); + virtual bool join(OSThreadExitCode & exit_code); + virtual ~LinuxThread(); + protected: + LinuxThread(); +}; + +class LinuxThreadFactory:public OSThreadFactory { + public: + OSThread * createThread() { + return new LinuxThread(); + } +}; + +class LinuxNetworkInterfaceFactory : public OSNetworkInterfaceFactory { +public: + virtual bool createInterface + ( OSNetworkInterface **net_iface, InterfaceLabel *label, + HWTimestamper *timestamper ); +}; + + +class LinuxIPCArg : public OS_IPC_ARG { +private: + char *group_name; +public: + LinuxIPCArg( char *group_name ) { + int len = strnlen(group_name,16); + this->group_name = new char[len+1]; + strncpy( this->group_name, group_name, len+1 ); + this->group_name[len] = '\0'; + } + virtual ~LinuxIPCArg() { + delete group_name; + } + friend class LinuxSharedMemoryIPC; +}; + +#define DEFAULT_GROUPNAME "ptp" + +class LinuxSharedMemoryIPC:public OS_IPC { +private: + int shm_fd; + char *master_offset_buffer; + int err; +public: + LinuxSharedMemoryIPC() { + shm_fd = 0; + err = 0; + master_offset_buffer = NULL; + }; + ~LinuxSharedMemoryIPC(); + virtual bool init( OS_IPC_ARG *barg = NULL ); + virtual bool update + (int64_t ml_phoffset, int64_t ls_phoffset, FrequencyRatio ml_freqoffset, + FrequencyRatio ls_freqoffset, uint64_t local_time, uint32_t sync_count, + uint32_t pdelay_count, PortState port_state ); + void stop(); +}; + + +#endif/*LINUX_HAL_COMMON_HPP*/ diff --git a/daemons/gptp/linux/src/linux_hal_generic.cpp b/daemons/gptp/linux/src/linux_hal_generic.cpp new file mode 100644 index 00000000..feb03796 --- /dev/null +++ b/daemons/gptp/linux/src/linux_hal_generic.cpp @@ -0,0 +1,403 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +#include <linux_hal_generic.hpp> +#include <linux_hal_generic_tsprivate.hpp> +#include <sys/select.h> +#include <sys/socket.h> +#include <netpacket/packet.h> +#include <errno.h> +#include <linux/ethtool.h> +#include <net/if.h> +#include <linux/sockios.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <fcntl.h> +#include <linux/net_tstamp.h> +#include <syscall.h> + +#define TX_PHY_TIME 184 +#define RX_PHY_TIME 382 + +net_result LinuxNetworkInterface::nrecv +( LinkLayerAddress *addr, uint8_t *payload, size_t &length ) { + fd_set readfds; + int err; + struct msghdr msg; + struct cmsghdr *cmsg; + struct { + struct cmsghdr cm; + char control[256]; + } control; + struct sockaddr_ll remote; + struct iovec sgentry; + net_result ret = net_succeed; + bool got_net_lock; + + LinuxTimestamperGeneric *gtimestamper; + + struct timeval timeout = { 0, 16000 }; // 16 ms + + if( !net_lock.lock( &got_net_lock )) { + fprintf( stderr, "A Failed to lock mutex\n" ); + return net_fatal; + } + if( !got_net_lock ) { + return net_trfail; + } + + FD_ZERO( &readfds ); + FD_SET( sd_event, &readfds ); + + err = select( sd_event+1, &readfds, NULL, NULL, &timeout ); + if( err == 0 ) { + ret = net_trfail; + goto done; + } else if( err == -1 ) { + if( err == EINTR ) { + // Caught signal + XPTPD_ERROR( "select() recv signal" ); + ret = net_trfail; + goto done; + } else { + XPTPD_ERROR( "select() failed" ); + ret = net_fatal; + goto done; + } + } else if( !FD_ISSET( sd_event, &readfds )) { + ret = net_trfail; + goto done; + } + + memset( &msg, 0, sizeof( msg )); + + msg.msg_iov = &sgentry; + msg.msg_iovlen = 1; + + sgentry.iov_base = payload; + sgentry.iov_len = length; + + memset( &remote, 0, sizeof(remote)); + msg.msg_name = (caddr_t) &remote; + msg.msg_namelen = sizeof( remote ); + msg.msg_control = &control; + msg.msg_controllen = sizeof(control); + + err = recvmsg( sd_event, &msg, 0 ); + if( err < 0 ) { + if( errno == ENOMSG ) { + fprintf( stderr, "Got ENOMSG: %s:%d\n", __FILE__, __LINE__ ); + ret = net_trfail; + goto done; + } + XPTPD_ERROR( "recvmsg() failed: %s", strerror(errno) ); + ret = net_fatal; + goto done; + } + *addr = LinkLayerAddress( remote.sll_addr ); + + gtimestamper = dynamic_cast<LinuxTimestamperGeneric *>(timestamper); + if( err > 0 && !(payload[0] & 0x8) && gtimestamper != NULL ) { + /* Retrieve the timestamp */ + cmsg = CMSG_FIRSTHDR(&msg); + while( cmsg != NULL ) { + if + ( cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SO_TIMESTAMPING ) { + Timestamp latency( RX_PHY_TIME, 0, 0 ); + struct timespec *ts_device, *ts_system; + Timestamp device, system; + ts_system = ((struct timespec *) CMSG_DATA(cmsg)) + 1; + system = tsToTimestamp( ts_system ); + ts_device = ts_system + 1; device = tsToTimestamp( ts_device ); + gtimestamper->updateCrossStamp( &system, &device ); + device = device - latency; + gtimestamper->pushRXTimestamp( &device ); + break; + } + cmsg = CMSG_NXTHDR(&msg,cmsg); + } + } + + length = err; + + done: + if( !net_lock.unlock()) { + fprintf( stderr, "A Failed to unlock, %d\n", err ); + return net_fatal; + } + + return ret; +} + +int findPhcIndex( InterfaceLabel *iface_label ) { + int sd; + InterfaceName *ifname; + struct ethtool_ts_info info; + struct ifreq ifr; + + if(( ifname = dynamic_cast<InterfaceName *>(iface_label)) == NULL ) { + fprintf( stderr, "findPTPIndex requires InterfaceName\n" ); + return -1; + } + + sd = socket( AF_UNIX, SOCK_DGRAM, 0 ); + if( sd < 0 ) { + fprintf( stderr, "findPTPIndex: failed to open socket\n" ); + return -1; + } + + memset( &ifr, 0, sizeof(ifr)); + memset( &info, 0, sizeof(info)); + info.cmd = ETHTOOL_GET_TS_INFO; + ifname->toString( ifr.ifr_name, IFNAMSIZ-1 ); + ifr.ifr_data = (char *) &info; + + if( ioctl( sd, SIOCETHTOOL, &ifr ) < 0 ) { + fprintf( stderr, "findPTPIndex: ioctl(SIOETHTOOL) failed\n" ); + return -1; + } + + close(sd); + + return info.phc_index; +} + +LinuxTimestamperGeneric::~LinuxTimestamperGeneric() { + if( _private != NULL ) delete _private; +#ifdef WITH_IGBLIB + if( igb_private != NULL ) delete igb_private; +#endif +} + +LinuxTimestamperGeneric::LinuxTimestamperGeneric() { + _private = NULL; +#ifdef WITH_IGBLIB + igb_private = NULL; +#endif + sd = -1; +} + +bool LinuxTimestamperGeneric::Adjust( void *tmx ) { + if( syscall(__NR_clock_adjtime, _private->clockid, tmx ) != 0 ) { + XPTPD_ERROR( "Failed to adjust PTP clock rate" ); + return false; + } + return true; +} + +bool LinuxTimestamperGeneric::HWTimestamper_init +( InterfaceLabel *iface_label, OSNetworkInterface *iface ) { + int fd; + cross_stamp_good = false; + int phc_index; + char ptp_device[] = PTP_DEVICE; + + _private = new LinuxTimestamperGenericPrivate; + + pthread_mutex_init( &_private->cross_stamp_lock, NULL ); + + // Determine the correct PTP clock interface + phc_index = findPhcIndex( iface_label ); + if( phc_index < 0 ) { + fprintf( stderr, "Failed to find PTP device index\n" ); + return false; + } + + snprintf + ( ptp_device+PTP_DEVICE_IDX_OFFS, + sizeof(ptp_device)-PTP_DEVICE_IDX_OFFS, "%d", phc_index ); + fprintf( stderr, "Using clock device: %s\n", ptp_device ); + fd = open( ptp_device, O_RDWR ); + if( fd == -1 || (_private->clockid = FD_TO_CLOCKID(fd)) == -1 ) { + fprintf( stderr, "Failed to open PTP clock device\n" ); + return false; + } + + if( !resetFrequencyAdjustment() ) { + XPTPD_ERROR( "Failed to reset (zero) frequency adjustment" ); + return false; + } + + if( dynamic_cast<LinuxNetworkInterface *>(iface) != NULL ) { + iface_list.push_front + ( (dynamic_cast<LinuxNetworkInterface *>(iface)) ); + } + + return true; +} + +int LinuxTimestamperGeneric::HWTimestamper_txtimestamp +( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, + unsigned &clock_value, bool last ) { + int err; + int ret = -72; + struct msghdr msg; + struct cmsghdr *cmsg; + struct sockaddr_ll remote; + struct iovec sgentry; + struct { + struct cmsghdr cm; + char control[256]; + } control; + Timestamp latency( TX_PHY_TIME, 0, 0 ); + + if( sd == -1 ) return -1; + memset( &msg, 0, sizeof( msg )); + + msg.msg_iov = &sgentry; + msg.msg_iovlen = 1; + + sgentry.iov_base = NULL; + sgentry.iov_len = 0; + + memset( &remote, 0, sizeof(remote)); + msg.msg_name = (caddr_t) &remote; + msg.msg_namelen = sizeof( remote ); + msg.msg_control = &control; + msg.msg_controllen = sizeof(control); + + err = recvmsg( sd, &msg, MSG_ERRQUEUE ); + if( err == -1 ) { + if( errno == EAGAIN ) { + ret = -72; + goto done; + } + else { + ret = -1; + goto done; + } + } + + // Retrieve the timestamp + cmsg = CMSG_FIRSTHDR(&msg); + while( cmsg != NULL ) { + if( cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SO_TIMESTAMPING ) { + struct timespec *ts_device, *ts_system; + Timestamp device, system; + ts_system = ((struct timespec *) CMSG_DATA(cmsg)) + 1; + system = tsToTimestamp( ts_system ); + ts_device = ts_system + 1; device = tsToTimestamp( ts_device ); + system._version = version; + device._version = version; + device = device + latency; + updateCrossStamp( &system, &device ); + timestamp = device; + ret = 0; + break; + } + cmsg = CMSG_NXTHDR(&msg,cmsg); + } + + if( ret != 0 ) { + fprintf( stderr, "Received a error message, but didn't find a valid timestamp\n" ); + } + + done: + if( ret == 0 || last ) { + net_lock->unlock(); + } + + return ret; +} + +bool LinuxTimestamperGeneric::post_init( int ifindex, int sd, TicketingLock *lock ) { + int timestamp_flags = 0; + struct ifreq device; + struct hwtstamp_config hwconfig; + int err; + + this->sd = sd; + this->net_lock = lock; + + memset( &device, 0, sizeof(device)); + device.ifr_ifindex = ifindex; + err = ioctl( sd, SIOCGIFNAME, &device ); + if( err == -1 ) { + XPTPD_ERROR + ( "Failed to get interface name: %s", strerror( errno )); + return false; + } + + device.ifr_data = (char *) &hwconfig; + memset( &hwconfig, 0, sizeof( hwconfig )); + hwconfig.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + hwconfig.tx_type = HWTSTAMP_TX_ON; + err = ioctl( sd, SIOCSHWTSTAMP, &device ); + if( err == -1 ) { + XPTPD_ERROR + ( "Failed to configure timestamping: %s", strerror( errno )); + return false; + } + + timestamp_flags |= SOF_TIMESTAMPING_TX_HARDWARE; + timestamp_flags |= SOF_TIMESTAMPING_RX_HARDWARE; + timestamp_flags |= SOF_TIMESTAMPING_SYS_HARDWARE; + timestamp_flags |= SOF_TIMESTAMPING_RAW_HARDWARE; + err = setsockopt + ( sd, SOL_SOCKET, SO_TIMESTAMPING, ×tamp_flags, + sizeof(timestamp_flags) ); + if( err == -1 ) { + XPTPD_ERROR + ( "Failed to configure timestamping on socket: %s", + strerror( errno )); + return false; + } + + return true; +} + +void LinuxTimestamperGeneric::updateCrossStamp( Timestamp *system_time, Timestamp *device_time ) { + pthread_mutex_lock( &_private->cross_stamp_lock ); + crstamp_system = *system_time; + crstamp_device = *device_time; + cross_stamp_good = true; + pthread_mutex_unlock( &_private->cross_stamp_lock ); +} + +bool LinuxTimestamperGeneric::HWTimestamper_gettime +( Timestamp *system_time, Timestamp *device_time, uint32_t *local_clock, + uint32_t *nominal_clock_rate ) { + bool ret = false; + pthread_mutex_lock( &_private->cross_stamp_lock ); + if( cross_stamp_good ) { + *system_time = crstamp_system; + *device_time = crstamp_device; + ret = true; + } + pthread_mutex_unlock( &_private->cross_stamp_lock ); + + return ret; +} + diff --git a/daemons/gptp/linux/src/linux_hal_generic.hpp b/daemons/gptp/linux/src/linux_hal_generic.hpp new file mode 100644 index 00000000..a37b52a3 --- /dev/null +++ b/daemons/gptp/linux/src/linux_hal_generic.hpp @@ -0,0 +1,110 @@ +/****************************************************************************** + + Copyright (c) 2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +#ifndef LINUX_HAL_GENERIC_HPP +#define LINUX_HAL_GENERIC_HPP + +#include <linux_hal_common.hpp> + +struct LinuxTimestamperGenericPrivate; +typedef struct LinuxTimestamperGenericPrivate * LinuxTimestamperGenericPrivate_t; + +#ifdef WITH_IGBLIB +struct LinuxTimestamperIGBPrivate; +typedef struct LinuxTimestamperIGBPrivate * LinuxTimestamperIGBPrivate_t; +#endif + +class LinuxTimestamperGeneric : public LinuxTimestamper { +private: + int sd; + Timestamp crstamp_system; + Timestamp crstamp_device; + LinuxTimestamperGenericPrivate_t _private; + bool cross_stamp_good; + std::list<Timestamp> rxTimestampList; + LinuxNetworkInterfaceList iface_list; + + TicketingLock *net_lock; + +#ifdef WITH_IGBLIB + LinuxTimestamperIGBPrivate_t igb_private; +#endif + +public: + LinuxTimestamperGeneric(); + bool resetFrequencyAdjustment(); + bool Adjust( void *tmx ); + virtual bool HWTimestamper_init + ( InterfaceLabel *iface_label, OSNetworkInterface *iface ); + + void updateCrossStamp( Timestamp *system_time, Timestamp *device_time ); + + void pushRXTimestamp( Timestamp *tstamp ) { + tstamp->_version = version; + rxTimestampList.push_front(*tstamp); + } + bool post_init( int ifindex, int sd, TicketingLock *lock ); + + virtual bool HWTimestamper_gettime + ( Timestamp *system_time, Timestamp *device_time, uint32_t *local_clock, + uint32_t *nominal_clock_rate ); + + virtual int HWTimestamper_txtimestamp + ( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, + unsigned &clock_value, bool last ); + + virtual int HWTimestamper_rxtimestamp + ( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, + unsigned &clock_value, bool last ) { + /* This shouldn't happen. Ever. */ + if( rxTimestampList.empty() ) return -72; + timestamp = rxTimestampList.back(); + rxTimestampList.pop_back(); + + return 0; + } + + virtual bool HWTimestamper_adjclockphase( int64_t phase_adjust ); + + virtual bool HWTimestamper_adjclockrate( float freq_offset ); + +#ifdef WITH_IGBLIB + bool HWTimestamper_PPS_start( ); + bool HWTimestamper_PPS_stop(); +#endif + + virtual ~LinuxTimestamperGeneric(); +}; + + +#endif/*LINUX_HAL_GENERIC_HPP*/ diff --git a/daemons/gptp/linux/src/linux_hal_generic_adj.cpp b/daemons/gptp/linux/src/linux_hal_generic_adj.cpp new file mode 100644 index 00000000..64dba960 --- /dev/null +++ b/daemons/gptp/linux/src/linux_hal_generic_adj.cpp @@ -0,0 +1,101 @@ +/****************************************************************************** + + Copyright (c) 2009-2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +#include <linux/timex.h> +#include <linux_hal_generic.hpp> +#include <syscall.h> +#include <math.h> + +bool LinuxTimestamperGeneric::resetFrequencyAdjustment() { + struct timex tx; + tx.modes = ADJ_FREQUENCY; + tx.freq = 0; + + return Adjust(&tx); +} + +bool LinuxTimestamperGeneric::HWTimestamper_adjclockphase( int64_t phase_adjust ) { + struct timex tx; + LinuxNetworkInterfaceList::iterator iface_iter; + bool ret = true; + LinuxTimerFactory factory; + OSTimer *timer = factory.createTimer(); + + /* Walk list of interfaces disabling them all */ + iface_iter = iface_list.begin(); + for + ( iface_iter = iface_list.begin(); iface_iter != iface_list.end(); + ++iface_iter ) { + (*iface_iter)->disable_clear_rx_queue(); + } + + rxTimestampList.clear(); + + /* Wait 180 ms - This is plenty of time for any time sync frames + to clear the queue */ + timer->sleep(180000); + + ++version; + + tx.modes = ADJ_SETOFFSET | ADJ_NANO; + if( phase_adjust >= 0 ) { + tx.time.tv_sec = phase_adjust / 1000000000LL; + tx.time.tv_usec = phase_adjust % 1000000000LL; + } else { + tx.time.tv_sec = (phase_adjust / 1000000000LL)-1; + tx.time.tv_usec = (phase_adjust % 1000000000LL)+1000000000; + } + + if( !Adjust( &tx )) { + ret = false; + } + + // Walk list of interfaces re-enabling them + iface_iter = iface_list.begin(); + for( iface_iter = iface_list.begin(); iface_iter != iface_list.end(); + ++iface_iter ) { + (*iface_iter)->reenable_rx_queue(); + } + + delete timer; + return ret; +} + +bool LinuxTimestamperGeneric::HWTimestamper_adjclockrate( float freq_offset ) { + struct timex tx; + tx.modes = ADJ_FREQUENCY; + tx.freq = long(freq_offset) << 16; + tx.freq += long(fmodf( freq_offset, 1.0 )*65536.0); + + return Adjust(&tx); +} diff --git a/daemons/gptp/linux/src/linux_hal_generic_tsprivate.hpp b/daemons/gptp/linux/src/linux_hal_generic_tsprivate.hpp new file mode 100644 index 00000000..94fa5137 --- /dev/null +++ b/daemons/gptp/linux/src/linux_hal_generic_tsprivate.hpp @@ -0,0 +1,53 @@ +/****************************************************************************** + + Copyright (c) 2012 Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +#ifndef LINUX_HAL_TSPRIVATE +#define LINUX_HAL_TSPRIVATE + +#include <pthread.h> +#ifdef WITH_IGBLIB +extern "C" { +#include <igb.h> +} +struct LinuxTimestamperIGBPrivate { + device_t igb_dev; + bool igb_initd; +}; +#endif + +struct LinuxTimestamperGenericPrivate { + pthread_mutex_t cross_stamp_lock; + clockid_t clockid; +}; + +#endif/*LINUX_HAL_TSPRIVATE*/ diff --git a/daemons/gptp/linux/src/linux_hal_i210.cpp b/daemons/gptp/linux/src/linux_hal_i210.cpp new file mode 100644 index 00000000..124d075c --- /dev/null +++ b/daemons/gptp/linux/src/linux_hal_i210.cpp @@ -0,0 +1,171 @@ +/****************************************************************************** + + Copyright (c) 2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +#include <linux_hal_generic.hpp> +#include <linux_hal_generic_tsprivate.hpp> +#include <errno.h> + +extern "C" { +#include <pci/pci.h> +#include <igb.h> +} + +#define IGB_BIND_NAMESZ 24 + +#define TSSDP 0x003C // Time Sync SDP Configuration Register +#define FREQOUT0 0xB654 +#define TSAUXC 0xB640 +#define IGB_CTRL 0x0000 +#define SYSTIMH 0xB604 +#define TRGTTIML0 0xB644 +#define TRGTTIMH0 0xB648 + + +static int +pci_connect( device_t *igb_dev ) +{ + struct pci_access *pacc; + struct pci_dev *dev; + int err; + char devpath[IGB_BIND_NAMESZ]; + + memset( igb_dev, 0, sizeof(device_t)); + + pacc = pci_alloc(); + pci_init(pacc); + pci_scan_bus(pacc); + for (dev=pacc->devices; dev; dev=dev->next) + { + pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); + + igb_dev->pci_vendor_id = dev->vendor_id; + igb_dev->pci_device_id = dev->device_id; + igb_dev->domain = dev->domain; + igb_dev->bus = dev->bus; + igb_dev->dev = dev->dev; + igb_dev->func = dev->func; + + snprintf + (devpath, IGB_BIND_NAMESZ, "%04x:%02x:%02x.%d", dev->domain, + dev->bus, dev->dev, dev->func ); + + err = igb_probe( igb_dev ); + + if (err) { + continue; + } + + printf ("attaching to %s\n", devpath); + err = igb_attach( devpath, igb_dev ); + + if (err) { + printf ("attach failed! (%s)\n", strerror(errno)); + continue; + } + goto out; + } + + pci_cleanup(pacc); + return ENXIO; + +out: + pci_cleanup(pacc); + return 0; +} + + +bool LinuxTimestamperGeneric::HWTimestamper_PPS_start( ) { + unsigned tssdp; + unsigned freqout; + unsigned ctrl; + unsigned tsauxc; + unsigned trgttimh; + + if( igb_private == NULL ) { + igb_private = new LinuxTimestamperIGBPrivate; + } + + if( pci_connect( &igb_private->igb_dev ) != 0 ) { + return false; + } + + if( igb_init( &igb_private->igb_dev ) != 0 ) { + return false; + } + + igb_private->igb_initd = true; + + igb_lock( &igb_private->igb_dev ); + + // Edges must be second aligned + igb_readreg( &igb_private->igb_dev, SYSTIMH, &trgttimh ); + trgttimh += 2; // First edge in 1-2 seconds + igb_writereg(&igb_private->igb_dev, TRGTTIMH0, trgttimh ); + igb_writereg(&igb_private->igb_dev, TRGTTIML0, 0 ); + + freqout = 500000000; + igb_writereg(&igb_private->igb_dev, FREQOUT0, freqout ); + + igb_readreg(&igb_private->igb_dev, IGB_CTRL, &ctrl ); + ctrl |= 0x400000; // set bit 22 SDP0 enabling output + igb_writereg(&igb_private->igb_dev, IGB_CTRL, ctrl ); + + igb_readreg( &igb_private->igb_dev, TSAUXC, &tsauxc ); + tsauxc |= 0x14; + igb_writereg( &igb_private->igb_dev, TSAUXC, tsauxc ); + + igb_readreg(&igb_private->igb_dev, TSSDP, &tssdp); + tssdp &= ~0x40; // Set SDP0 output to freq clock 0 + tssdp |= 0x80; + igb_writereg(&igb_private->igb_dev, TSSDP, tssdp); + + igb_readreg(&igb_private->igb_dev, TSSDP, &tssdp); + tssdp |= 0x100; // set bit 8 -> SDP0 Time Sync Output + igb_writereg(&igb_private->igb_dev, TSSDP, tssdp); + + igb_unlock( &igb_private->igb_dev ); + + return true; +} + +bool LinuxTimestamperGeneric::HWTimestamper_PPS_stop() { + unsigned tssdp; + + if( !igb_private->igb_initd ) return false; + + igb_readreg(&igb_private->igb_dev, TSSDP, &tssdp); + tssdp &= ~0x100; // set bit 8 -> SDP0 Time Sync Output + igb_writereg(&igb_private->igb_dev, TSSDP, tssdp); + + return true; +} diff --git a/daemons/gptp/linux/src/linux_hal_intelce.cpp b/daemons/gptp/linux/src/linux_hal_intelce.cpp new file mode 100644 index 00000000..fd1cd0e3 --- /dev/null +++ b/daemons/gptp/linux/src/linux_hal_intelce.cpp @@ -0,0 +1,243 @@ +/****************************************************************************** + + Copyright (c) 2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +#include <linux_hal_intelce.hpp> +#include <avbts_message.hpp> +extern "C" { +#include <ismd_sysclk.h> +#include <ismd_core.h> +} +#include <netpacket/packet.h> +#include <errno.h> +#include <sys/socket.h> +#include <sys/types.h> + +#define NOMINAL_NET_CLOCK_RATE (25)/* MHz */ +#define NET_CLOCK_ADJUST (1000/NOMINAL_NET_CLOCK_RATE) + +#define TX_PHY_TIME 8000 +#define RX_PHY_TIME 8000 + +uint64_t scale_clock( uint64_t count ) { + return count*NET_CLOCK_ADJUST; +} + +int LinuxTimestamperIntelCE::ce_timestamp_common +( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, + unsigned &clock_value, bool tx ) { + uint64_t timestamp_s; + uint16_t captured_sequence; + uint16_t port_no; + PortIdentity captured_id; + ismd_sysclk_msg_t message; + ismd_result_t result; + int ret = -72; + + if( tx ) { + result = ismd_sysclk_get_tx_time( ×tamp_s, &message ); + if( timestamp_s == last_tx_time ) { + result = ISMD_ERROR_NO_DATA_AVAILABLE; + } else { + last_tx_time = timestamp_s; + } + } else { + struct timespec ts; + clock_gettime( CLOCK_REALTIME, &ts ); + result = ismd_sysclk_get_rx_time( ×tamp_s, &message ); + if( timestamp_s == last_rx_time ) { + result = ISMD_ERROR_NO_DATA_AVAILABLE; + } else { + last_rx_time = timestamp_s; + } + } + + if( result == ISMD_ERROR_NO_DATA_AVAILABLE ) { + goto fail; + } else if( result != ISMD_SUCCESS ) { + ret = -1; + goto fail; + } + + timestamp_s = scale_clock( timestamp_s ); + + captured_id.setClockIdentity( ClockIdentity(message.msgid) ); + port_no = + PLAT_ntohs(*((uint16_t *)(message.msgid+PTP_CLOCK_IDENTITY_LENGTH))); + captured_id.setPortNumber( &port_no ); + captured_sequence = PLAT_ntohs( *((uint16_t *)message.msgseq )); + + if( captured_sequence != sequenceId || captured_id != *identity ) { + uint16_t cap_port_no; + uint16_t id_port_no; + captured_id.getPortNumber(&cap_port_no); + identity->getPortNumber(&id_port_no); + goto fail; + } + + ret = 0; + + if( tx ) { + timestamp_s += TX_PHY_TIME; + } else { + timestamp_s -= RX_PHY_TIME; + } + + timestamp.set64( timestamp_s ); + timestamp._version = version; + clock_value = (unsigned) timestamp_s; + + fail: + return ret; +} + +int LinuxTimestamperIntelCE::HWTimestamper_txtimestamp +( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, + unsigned &clock_value, bool last ) { + return ce_timestamp_common + ( identity, sequenceId, timestamp, clock_value, true ); +} + +int LinuxTimestamperIntelCE::HWTimestamper_rxtimestamp +( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, + unsigned &clock_value, bool last ) { + return ce_timestamp_common + ( identity, sequenceId, timestamp, clock_value, false ); +} + +bool LinuxTimestamperIntelCE::post_init( int ifindex, int sd, TicketingLock *lock ) { + ismd_sysclk_ptp_filter_config_t filter_config; + filter_config.tx_filter_enable = true; + filter_config.rx_filter_enable = true; + filter_config.compare_ptp_ver = true; + filter_config.ip_l2 = false; + filter_config.ptp_version = GPTP_VERSION; + filter_config.ether_type = PTP_ETHERTYPE; + filter_config.da_hash_inclusion = false; + ismd_result_t result; + + result = ismd_sysclk_set_ptp_filter( filter_config ); + if( result != ISMD_SUCCESS ) return false; + + return true; +} +bool LinuxTimestamperIntelCE::HWTimestamper_init +( InterfaceLabel *iface_label, OSNetworkInterface *iface ) { + ismd_result_t result; + + // Allocate clock + result = ismd_clock_alloc_typed + ( ISMD_CLOCK_CLASS_SLAVE, ISMD_CLOCK_DOMAIN_TYPE_AV, &iclock ); + if( result != ISMD_SUCCESS ) return false; + + return true; +} + +bool LinuxTimestamperIntelCE::HWTimestamper_gettime +( Timestamp *system_time, Timestamp *device_time, uint32_t *local_clock, + uint32_t *nominal_clock_rate ) { + uint64_t system_time_s; + uint64_t device_time_s; + + if( ismd_clock_trigger_software_event( iclock ) != ISMD_SUCCESS ) + return false; + + if( ismd_clock_get_last_trigger_correlated_time + ( iclock, &system_time_s, &device_time_s ) != ISMD_SUCCESS ) + return false; + + system_time->set64( system_time_s ); + + device_time_s = scale_clock( device_time_s ); + device_time->set64( device_time_s ); + + return true; +} + + + +net_result LinuxNetworkInterface::nrecv +( LinkLayerAddress *addr, uint8_t *payload, size_t &length ) { + fd_set readfds; + int err; + struct sockaddr_ll remote; + net_result ret = net_succeed; + bool got_net_lock; + + struct timeval timeout = { 0, 16000 }; // 16 ms + + if( !net_lock.lock( &got_net_lock ) || !got_net_lock ) { + XPTPD_ERROR( "A Failed to lock mutex" ); + return net_fatal; + } + + FD_ZERO( &readfds ); + FD_SET( sd_event, &readfds ); + + err = select( sd_event+1, &readfds, NULL, NULL, &timeout ); + if( err == 0 ) { + ret = net_trfail; + goto done; + } else if( err == -1 ) { + if( err == EINTR ) { + // Caught signal + XPTPD_ERROR( "select() recv signal" ); + ret = net_trfail; + goto done; + } else { + XPTPD_ERROR( "select() failed" ); + ret = net_fatal; + goto done; + } + } else if( !FD_ISSET( sd_event, &readfds )) { + ret = net_trfail; + goto done; + } + + err = recv( sd_event, payload, length, 0 ); + if( err < 0 ) { + XPTPD_ERROR( "recvmsg() failed: %s", strerror(errno) ); + ret = net_fatal; + goto done; + } + *addr = LinkLayerAddress( remote.sll_addr ); + + length = err; + + done: + if( !net_lock.unlock()) { + XPTPD_ERROR( "A Failed to unlock, %d\n", err ); + return net_fatal; + } + + return ret; +} diff --git a/daemons/gptp/linux/src/linux_hal_intelce.hpp b/daemons/gptp/linux/src/linux_hal_intelce.hpp new file mode 100644 index 00000000..6511559c --- /dev/null +++ b/daemons/gptp/linux/src/linux_hal_intelce.hpp @@ -0,0 +1,75 @@ +/****************************************************************************** + + Copyright (c) 2012, Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +#ifndef LINUX_HAL_INTELCE_HPP +#define LINUX_HAL_INTELCE_HPP + +#include <linux_hal_common.hpp> +#include <ismd_core.h> + +class LinuxTimestamperIntelCE : public LinuxTimestamper { +private: + ismd_clock_t iclock; + uint64_t last_tx_time; + uint64_t last_rx_time; + int ce_timestamp_common + ( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, + unsigned &clock_value, bool tx ); +public: + virtual bool HWTimestamper_init + ( InterfaceLabel *iface_label, OSNetworkInterface *iface ); + + virtual int HWTimestamper_txtimestamp + ( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, + unsigned &clock_value, bool last ); + + virtual int HWTimestamper_rxtimestamp + ( PortIdentity *identity, uint16_t sequenceId, Timestamp ×tamp, + unsigned &clock_value, bool last ); + + bool post_init( int ifindex, int sd, TicketingLock *lock ); + + virtual ~LinuxTimestamperIntelCE() { + } + + LinuxTimestamperIntelCE() { + last_tx_time = 0; + last_rx_time = 0; + } + + virtual bool HWTimestamper_gettime + ( Timestamp *system_time, Timestamp *device_time, uint32_t *local_clock, + uint32_t *nominal_clock_rate ); +}; + +#endif/*LINUX_HAL_INTELCE_HPP*/ diff --git a/daemons/gptp/linux/src/platform.cpp b/daemons/gptp/linux/src/platform.cpp new file mode 100644 index 00000000..7a5bb71d --- /dev/null +++ b/daemons/gptp/linux/src/platform.cpp @@ -0,0 +1,48 @@ +/****************************************************************************** + + Copyright (c) 2012 Intel Corporation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +#include <platform.hpp> +#include <arpa/inet.h> + +uint16_t PLAT_htons( uint16_t s ) { + return htons( s ); +} +uint32_t PLAT_htonl( uint32_t l ) { + return htonl( l ); +} +uint16_t PLAT_ntohs( uint16_t s ) { + return ntohs( s ); +} +uint32_t PLAT_ntohl( uint32_t l ) { + return ntohl( l ); +} |