59 #include <boost/chrono/duration.hpp>
60 #include <boost/chrono/time_point.hpp>
61 #include <boost/lexical_cast.hpp>
62 #include <boost/thread/thread.hpp>
63 #include <boost/date_time/posix_time/posix_time_types.hpp>
64 #include <boost/interprocess/sync/scoped_lock.hpp>
79 mData(1, std::pair<const uint8_t*, size_t>(aPtr, aNrBytes))
94 std::ios::fmtflags lOrigFlags( aStream.flags() );
96 size_t lNrBytesWritten = 0;
97 for (
size_t i = 0; i < aPacket.
mData.size(); i++) {
98 for (
const uint8_t* lPtr = aPacket.
mData.at(i).first; lPtr != (aPacket.
mData.at(i).first + aPacket.
mData.at(i).second); lPtr++, lNrBytesWritten++) {
99 if ((lNrBytesWritten & 3) == 0)
100 aStream << std::endl <<
" @ " << std::setw(3) <<
std::dec << (lNrBytesWritten >> 2) <<
" : x";
101 aStream << std::setw(2) <<
std::hex << uint16_t(*lPtr) <<
" ";
105 aStream.flags( lOrigFlags );
147 mFd = ::open(mPath.c_str(), mFlags);
149 exception::PCIeInitialisationError lExc;
150 log(lExc,
"Failed to open device file ",
Quote(mPath),
"; errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
161 int rc = ::close(mFd);
172 if (mBuffer != NULL) {
173 if (mBufferSize >= aNrBytes)
182 posix_memalign((
void**)&mBuffer, 4096, aNrBytes + 4096);
183 if (mBuffer == NULL) {
184 exception::PCIeCommunicationError lExc;
185 log(lExc,
"Failed to allocate ",
Integer(aNrBytes + 4096),
" bytes in PCIe::File::createBuffer");
189 mBufferSize=aNrBytes+4096;
193 void PCIe::File::read(
const uint32_t aAddr,
const uint32_t aNrWords, std::vector<uint32_t>& aValues)
198 createBuffer(4 * aNrWords);
201 off_t off = lseek(mFd, 4*aAddr, SEEK_SET);
202 if ( off != off_t(4 * aAddr)) {
203 exception::PCIeCommunicationError lExc;
204 log(lExc,
"Offset returned by lseek, ",
Integer(off),
", does not match that requested, ",
Integer(4*aAddr),
" (in preparation for read of ",
Integer(aNrWords),
" words)");
209 int rc =
::read(mFd, mBuffer, 4*aNrWords);
211 exception::PCIeCommunicationError lExc;
212 log(lExc,
"Read of ",
Integer(4*aNrWords),
" bytes at address ",
Integer(4 * aAddr),
" failed! errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
215 else if (
size_t(rc) < 4*aNrWords) {
216 exception::PCIeCommunicationError lExc;
217 log(lExc,
"Only ",
Integer(rc),
" bytes transferred in read of ",
Integer(4*aNrWords),
" bytes at address ",
Integer(4 * aAddr));
221 aValues.insert(aValues.end(),
reinterpret_cast<uint32_t*
>(mBuffer),
reinterpret_cast<uint32_t*
>(mBuffer)+ aNrWords);
227 write(4 * aAddr,
reinterpret_cast<const uint8_t* const
>(aValues.data()), 4 * aValues.size());
236 assert((aNrBytes % 4) == 0);
238 createBuffer(aNrBytes);
241 memcpy(mBuffer, aPtr, aNrBytes);
244 off_t off = lseek(mFd, aAddr, SEEK_SET);
245 if ( off != off_t(aAddr)) {
247 if (fstat(mFd, &st) or (not S_ISFIFO(st.st_mode))) {
248 exception::PCIeCommunicationError lExc;
249 log(lExc,
"Offset returned by lseek, ",
Integer(off),
", does not match that requested, ",
Integer(aAddr),
" (in preparation for write of ",
Integer(aNrBytes),
" bytes)");
255 int rc =
::write(mFd, mBuffer, aNrBytes);
257 exception::PCIeCommunicationError lExc;
258 log(lExc,
"Write of ",
Integer(aNrBytes),
" bytes at address ",
Integer(aAddr),
" failed! errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
261 else if (
size_t(rc) < aNrBytes) {
262 exception::PCIeCommunicationError lExc;
263 log(lExc,
"Only ",
Integer(rc),
" bytes transferred in write of ",
Integer(aNrBytes),
" bytes at address ",
Integer(aAddr));
269 void PCIe::File::write(
const uint32_t aAddr,
const std::vector<std::pair<const uint8_t*, size_t> >& aData)
275 for (
size_t i = 0; i < aData.size(); i++)
276 lNrBytes += aData.at(i).second;
278 assert((lNrBytes % 4) == 0);
280 createBuffer(lNrBytes);
283 size_t lNrBytesCopied = 0;
284 for (
size_t i = 0; i < aData.size(); i++) {
285 memcpy(mBuffer + lNrBytesCopied, aData.at(i).first, aData.at(i).second);
286 lNrBytesCopied += aData.at(i).second;
290 off_t off = lseek(mFd, aAddr, SEEK_SET);
291 if ( off != off_t(aAddr)) {
293 if (fstat(mFd, &st) or (not S_ISFIFO(st.st_mode))) {
294 exception::PCIeCommunicationError lExc;
295 log(lExc,
"Offset returned by lseek, ",
Integer(off),
", does not match that requested, ",
Integer(aAddr),
" (in preparation for write of ",
Integer(lNrBytes),
" bytes)");
301 int rc =
::write(mFd, mBuffer, lNrBytes);
303 exception::PCIeCommunicationError lExc;
304 log(lExc,
"Write of ",
Integer(lNrBytes),
" bytes at address ",
Integer(aAddr),
" failed! errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
307 else if (
size_t(rc) < lNrBytes) {
308 exception::PCIeCommunicationError lExc;
309 log(lExc,
"Only ",
Integer(rc),
" bytes transferred in write of ",
Integer(lNrBytes),
" bytes at address ",
Integer(aAddr));
323 if ( flock(mFd, LOCK_EX) == -1 ) {
324 exception::MutexError lExc;
325 log(lExc,
"Failed to lock device file ",
Quote(mPath),
"; errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
334 if ( flock(mFd, LOCK_UN) == -1 ) {
346 mSessionActive(false)
348 pthread_mutexattr_t lAttr;
350 int s = pthread_mutexattr_init(&lAttr);
352 exception::MutexError lExc;
353 log(lExc,
"Error code ",
Integer(s),
" (", strerror(s),
") returned in mutex attr initialisation");
357 s = pthread_mutexattr_setpshared(&lAttr, PTHREAD_PROCESS_SHARED);
359 exception::MutexError lExc;
360 log(lExc,
"Error code ",
Integer(s),
" (", strerror(s),
") returned by pthread_mutexattr_setpshared");
364 s = pthread_mutexattr_setrobust(&lAttr, PTHREAD_MUTEX_ROBUST);
366 exception::MutexError lExc;
367 log(lExc,
"Error code ",
Integer(s),
" (", strerror(s),
") returned by pthread_mutexattr_setrobust");
371 s = pthread_mutex_init(&
mMutex, &lAttr);
373 exception::MutexError lExc;
374 log(lExc,
"Error code ",
Integer(s),
" (", strerror(s),
") returned in mutex initialisation");
387 int s = pthread_mutex_lock(&mMutex);
388 bool lLastOwnerDied = (s == EOWNERDEAD);
390 s = pthread_mutex_consistent(&mMutex);
393 exception::MutexError lExc;
394 log(lExc,
"Error code ",
Integer(s),
" (", strerror(s),
") returned when ", lLastOwnerDied ?
"making mutex state consistent" :
"locking mutex");
402 int s = pthread_mutex_unlock(&mMutex);
404 log(
Error(),
"Error code ",
Integer(s),
" (", strerror(s),
") returned when unlocking mutex");
416 return mSessionActive;
423 mSessionActive =
true;
428 mSessionActive =
false;
437 mSharedMem(
boost::interprocess::open_or_create, aName.c_str(), 1024, 0x0,
boost::interprocess::permissions(0666)),
438 mObj(mSharedMem.find_or_construct<T>(
boost::interprocess::unique_instance)())
465 std::string lSanitizedPath(aPath);
466 std::replace(lSanitizedPath.begin(), lSanitizedPath.end(),
'/',
':');
468 return "/uhal::ipbuspcie-2.0::" + lSanitizedPath;
473 IPbus< 2 , 0 > ( aId , aUri ),
489 if ( aUri.
mHostname.find(
",") == std::string::npos ) {
490 exception::PCIeInitialisationError lExc;
491 log(lExc,
"No comma found in hostname of PCIe client URI '" +
uri() +
"'; cannot construct 2 paths for device files");
495 exception::PCIeInitialisationError lExc;
496 log(lExc,
"Hostname of PCIe client URI '" +
uri() +
"' starts/ends with a comma; cannot construct 2 paths for device files");
502 for (NameValuePairVectorType::const_iterator lIt = aUri.
mArguments.begin(); lIt != aUri.
mArguments.end(); lIt++) {
503 if (lIt->first ==
"events") {
505 exception::PCIeInitialisationError lExc;
506 log(lExc,
"PCIe client URI ",
Quote(
uri()),
": 'events' attribute is specified multiple times");
512 log (
Info() ,
"PCIe client with URI ",
Quote (
uri()),
" is configured to use interrupts");
514 else if (lIt->first ==
"sleep") {
515 mSleepDuration = boost::chrono::microseconds(boost::lexical_cast<size_t>(lIt->second));
516 log (
Notice() ,
"PCIe client with URI ",
Quote (
uri()),
" : Inter-poll-/-interrupt sleep duration set to ", boost::lexical_cast<size_t>(lIt->second),
" us by URI 'sleep' attribute");
518 else if (lIt->first ==
"max_in_flight") {
519 mMaxInFlight = boost::lexical_cast<size_t>(lIt->second);
520 log (
Notice() ,
"PCIe client with URI ",
Quote (
uri()),
" : 'Maximum number of packets in flight' set to ", boost::lexical_cast<size_t>(lIt->second),
" by URI 'max_in_flight' attribute");
522 else if (lIt->first ==
"max_packet_size") {
524 log (
Notice() ,
"PCIe client with URI ",
Quote (
uri()),
" : 'Maximum packet size (in 32-bit words) set to ", boost::lexical_cast<size_t>(lIt->second),
" by URI 'max_packet_size' attribute");
526 else if (lIt->first ==
"xdma_7series_workaround") {
528 log (
Notice() ,
"PCIe client with URI ",
Quote (
uri()),
" : Adjusting size of PCIe reads to a few fixed sizes as workaround for 7-series xdma firmware bug");
544 log(
Debug(),
"PCIe client (URI: ",
Quote(
uri()),
") : implementDispatch method called");
557 log(
Debug(),
"PCIe client (URI: ",
Quote(
uri()),
") : Flush method called");
570 log(
Notice(),
"PCIe client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : closing device files since exception detected");
578 InnerProtocol::dispatchExceptionHandler();
617 std::vector<uint32_t> lValues;
620 log (
Debug(),
"Read status info (",
Integer(lValues.at(0)),
", ",
Integer(lValues.at(1)),
", ",
Integer(lValues.at(2)),
", ",
Integer(lValues.at(3)),
"): ",
PacketFmt((
const uint8_t*)lValues.data(), 4 * lValues.size()));
632 if (lValues.at(1) > 0xFFFF) {
633 exception::PCIeInitialisationError lExc;
639 exception::PCIeInitialisationError lExc;
654 log (
Info() ,
"PCIe client connected to device at ",
Quote(
mDeviceFileHostToFPGA.
getPath()),
", ",
Quote(
mDeviceFileFPGAToHost.
getPath()),
"; FPGA has ",
Integer(
mNumberOfPages),
" pages, each of size ",
Integer(
mPageSize),
" words, index ",
Integer(
mIndexNextPage),
" should be filled next" );
683 log (
Info(),
"PCIe client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : writing ",
Integer(aBuffers->sendCounter() / 4),
"-word packet to page ",
Integer(
mIndexNextPage),
" in ",
Quote(
mDeviceFileHostToFPGA.
getPath()));
685 const uint32_t lHeaderWord = (0x10000 | (((aBuffers->sendCounter() / 4) - 1) & 0xFFFF));
686 std::vector<std::pair<const uint8_t*, size_t> > lDataToWrite;
687 lDataToWrite.push_back( std::make_pair(
reinterpret_cast<const uint8_t*
>(&lHeaderWord),
sizeof lHeaderWord) );
688 lDataToWrite.push_back( std::make_pair(aBuffers->getSendBuffer(), aBuffers->sendCounter()) );
702 SteadyClock_t::time_point lStartTime = SteadyClock_t::now();
708 std::vector<uint32_t> lRxEvent;
712 if (lRxEvent.at(0) == 1) {
717 if (SteadyClock_t::now() - lStartTime > boost::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
718 exception::PCIeTimeout lExc;
729 log(
Info(),
"PCIe client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : Reading page ",
Integer(lPageIndexToRead),
" (interrupt received)");
733 uint32_t lHwPublishedPageCount = 0x0;
735 std::vector<uint32_t> lValues;
740 lHwPublishedPageCount = lValues.at(3);
741 log (
Debug(),
"Read status info from addr 0 (",
Integer(lValues.at(0)),
", ",
Integer(lValues.at(1)),
", ",
Integer(lValues.at(2)),
", ",
Integer(lValues.at(3)),
"): ",
PacketFmt((
const uint8_t*)lValues.data(), 4 * lValues.size()));
749 if (SteadyClock_t::now() - lStartTime > boost::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
750 exception::PCIeTimeout lExc;
755 log(
Debug(),
"PCIe client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : Trying to read page index ",
Integer(lPageIndexToRead),
" = count ",
Integer(
mReadReplyPageCount+1),
"; published page count is ",
Integer(lHwPublishedPageCount),
"; sleeping for ",
mSleepDuration.count(),
"us");
761 log(
Info(),
"PCIe client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : Reading page ",
Integer(lPageIndexToRead),
" (published count ",
Integer(lHwPublishedPageCount),
", surpasses required, ",
Integer(
mReadReplyPageCount + 1),
")");
770 uint32_t lNrWordsToRead(lBuffers->replyCounter() >> 2);
771 if(
mXdma7seriesWorkaround and (lNrWordsToRead % 32 == 0 || lNrWordsToRead % 32 == 28 || lNrWordsToRead < 4))
775 std::vector<uint32_t> lPageContents;
779 log (
Debug(),
"Read " ,
Integer(lNrWordsToRead),
" 32-bit words from address " ,
Integer(4 + lPageIndexToRead * 4 *
mPageSize),
" ... ",
PacketFmt((
const uint8_t*)lPageContents.data(), 4 * lPageContents.size()));
782 const std::deque< std::pair< uint8_t* , uint32_t > >& lReplyBuffers ( lBuffers->getReplyBuffer() );
783 size_t lNrWordsInPacket = (lPageContents.at(0) >> 16) + (lPageContents.at(0) & 0xFFFF);
784 if (lNrWordsInPacket != (lBuffers->replyCounter() >> 2))
785 log (
Warning(),
"Expected reply packet to contain ",
Integer(lBuffers->replyCounter() >> 2),
" words, but it actually contains ",
Integer(lNrWordsInPacket),
" words");
787 size_t lNrBytesCopied = 0;
788 for ( std::deque< std::pair< uint8_t* , uint32_t > >::const_iterator lIt = lReplyBuffers.begin() ; lIt != lReplyBuffers.end() ; ++lIt )
791 if ( lNrBytesCopied >= 4*lNrWordsInPacket)
794 size_t lNrBytesToCopy =
std::min( lIt->second , uint32_t(4*lNrWordsInPacket - lNrBytesCopied) );
795 memcpy ( lIt->first, &lPageContents.at(1 + (lNrBytesCopied / 4)), lNrBytesToCopy );
796 lNrBytesCopied += lNrBytesToCopy;
808 exception::ValidationError lExc2;
809 log ( lExc2 ,
"Exception caught during reply validation for PCIe device with URI " ,
Quote ( this->
uri() ) ,
"; what returned: " ,
Quote ( aExc.
what() ) );