summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Hall <christopher.s.hall@intel.com>2014-04-03 16:29:05 -0700
committerChristopher Hall <christopher.s.hall@intel.com>2014-04-03 16:29:05 -0700
commit01efdf94bfdfc2e535e7b06e8a79de0d076f0623 (patch)
tree700a7597cf6ba429db5ccf9a153143e22b3c7894
parentb0d89f2af30c5ff369b4549229eac70d64038905 (diff)
downloadOpen-AVB-01efdf94bfdfc2e535e7b06e8a79de0d076f0623.tar.gz
Added missing Linux files
-rw-r--r--daemons/gptp/linux/src/linux_hal_common.cpp798
-rw-r--r--daemons/gptp/linux/src/linux_hal_common.hpp309
-rw-r--r--daemons/gptp/linux/src/linux_hal_generic.cpp403
-rw-r--r--daemons/gptp/linux/src/linux_hal_generic.hpp110
-rw-r--r--daemons/gptp/linux/src/linux_hal_generic_adj.cpp101
-rw-r--r--daemons/gptp/linux/src/linux_hal_generic_tsprivate.hpp53
-rw-r--r--daemons/gptp/linux/src/linux_hal_i210.cpp171
-rw-r--r--daemons/gptp/linux/src/linux_hal_intelce.cpp243
-rw-r--r--daemons/gptp/linux/src/linux_hal_intelce.hpp75
-rw-r--r--daemons/gptp/linux/src/platform.cpp48
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 &timestamp,
+ 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, &timestamp_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 &timestamp,
+ unsigned &clock_value, bool last );
+
+ virtual int HWTimestamper_rxtimestamp
+ ( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp,
+ 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 &timestamp,
+ 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( &timestamp_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( &timestamp_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 &timestamp,
+ 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 &timestamp,
+ 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 &timestamp,
+ 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 &timestamp,
+ unsigned &clock_value, bool last );
+
+ virtual int HWTimestamper_rxtimestamp
+ ( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp,
+ 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 );
+}