ChimeraTK-DeviceAccess  03.18.00
XdmaBackend.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2 // SPDX-License-Identifier: LGPL-3.0-or-later
3 
4 #include "XdmaBackend.h"
5 
6 #include <boost/make_shared.hpp>
7 
8 #include <functional>
9 #include <iomanip>
10 
11 namespace ChimeraTK {
12 
13  XdmaBackend::XdmaBackend(std::string devicePath, std::string mapFileName)
14  : NumericAddressedBackend(mapFileName), _devicePath(devicePath) {}
15 
17 
19 #ifdef _DEBUG
20  std::cout << "XDMA: opening dev: " << _devicePath << std::endl;
21 #endif
22  if(_ctrlIntf) {
23  if(isFunctional()) {
24  return;
25  }
26  }
27 
28  _ctrlIntf.emplace(_devicePath);
29 
30  std::for_each(_eventFiles.begin(), _eventFiles.end(), [](auto& eventFile) { eventFile = nullptr; });
31 
32  // Build vector of DMA channels
33  _dmaChannels.clear();
34  for(size_t i = 0; i < _maxDmaChannels; i++) {
35  try {
36  _dmaChannels.emplace_back(_devicePath, i);
37  }
38  catch(const runtime_error&) {
39  break;
40  }
41  }
42 
43 #ifdef _DEBUG
44  std::cout << "XDMA: opened interface with " << _dmaChannels.size() << " DMA channels and " << _eventFiles.size()
45  << " interrupt sources\n";
46 #endif
48  }
49 
51  std::for_each(_eventFiles.begin(), _eventFiles.end(), [](auto& eventFile) { eventFile = nullptr; });
52  _ctrlIntf.reset();
53  _dmaChannels.clear();
54  _opened = false;
55  }
56 
58  return _opened;
59  }
60 
61  XdmaIntfAbstract& XdmaBackend::_intfFromBar(uint64_t bar) {
62  if(bar == 0 && _ctrlIntf.has_value()) {
63  return _ctrlIntf.value();
64  }
65  // 13 is magic value for DMA channel (by convention)
66  // We provide N DMA channels starting from there
67  if(bar >= 13) {
68  const size_t dmaChIdx = bar - 13;
69  if(dmaChIdx < _dmaChannels.size()) {
70  return _dmaChannels[dmaChIdx];
71  }
72  }
73  throw ChimeraTK::logic_error("Couldn't find XDMA channel for BAR value " + std::to_string(bar));
74  }
75 
76 #ifdef _DEBUG
77  void XdmaBackend::dump(const int32_t* data, size_t nbytes) {
78  constexpr size_t wordsPerLine = 8;
79  size_t n;
80  for(n = 0; n < (nbytes / sizeof(*data)) && n < 64; n++) {
81  if(!(n % wordsPerLine)) {
82  std::cout << std::hex << std::setw(4) << std::setfill('0') << n * sizeof(*data) << ":";
83  }
84  std::cout << " " << std::hex << std::setw(8) << std::setfill('0') << data[n];
85  if((n % wordsPerLine) == wordsPerLine - 1) {
86  std::cout << "\n";
87  }
88  }
89  if((n % wordsPerLine) != wordsPerLine) {
90  std::cout << "\n";
91  }
92  }
93 #endif
94 
95  void XdmaBackend::read(uint64_t bar, uint64_t address, int32_t* data, size_t sizeInBytes) {
96 #ifdef _DEBUGDUMP
97  std::cout << "XDMA: read " << sizeInBytes << " bytes @ BAR" << bar << ", 0x" << std::hex << address << std::endl;
98 #endif
99  auto& intf = _intfFromBar(bar);
100  intf.read(address, data, sizeInBytes);
101 #ifdef _DEBUGDUMP
102  dump(data, sizeInBytes);
103 #endif
104  }
105 
106  void XdmaBackend::write(uint64_t bar, uint64_t address, const int32_t* data, size_t sizeInBytes) {
107 #ifdef _DEBUGDUMP
108  std::cout << "XDMA: write " << sizeInBytes << " bytes @ BAR" << bar << ", 0x" << std::hex << address << std::endl;
109 #endif
110  auto& intf = _intfFromBar(bar);
111  intf.write(address, data, sizeInBytes);
112 #ifdef _DEBUGDUMP
113  dump(data, sizeInBytes);
114 #endif
115  }
116 
118  uint32_t interruptNumber, boost::shared_ptr<async::DomainImpl<std::nullptr_t>> asyncDomain) {
119  std::promise<void> subscriptionDonePromise;
120  auto subscriptionDoneFuture = subscriptionDonePromise.get_future();
121  if(interruptNumber >= _maxInterrupts) {
122  setException("XDMA interrupt " + std::to_string(interruptNumber) + " out of range, only 0.." +
123  std::to_string(_maxInterrupts - 1) + " available\n");
124  subscriptionDonePromise.set_value();
125  return subscriptionDoneFuture;
126  }
127 
128  if(!_eventFiles[interruptNumber]) {
129  _eventFiles[interruptNumber] = std::make_unique<EventFile>(this, _devicePath, interruptNumber, asyncDomain);
130  _eventFiles[interruptNumber]->startThread(std::move(subscriptionDonePromise));
131  }
132  else {
133  // thread is already running, just fulfil the promise
134  subscriptionDonePromise.set_value();
135  }
136  return subscriptionDoneFuture;
137  }
138 
140  std::string result = "XDMA backend: Device path = " + _devicePath + ", number of DMA channels = ";
141  if(isOpen()) {
142  result += std::to_string(_dmaChannels.size());
143  }
144  else {
145  result += "unknown (device closed)";
146  }
147 
148  // TODO: retrieve other interesting stuff (driver version...) via ioctl
149  return result;
150  }
151 
152  boost::shared_ptr<DeviceBackend> XdmaBackend::createInstance(
153  std::string address, std::map<std::string, std::string> parameters) {
154  if(address.empty()) {
155  throw ChimeraTK::logic_error("XDMA device address not specified.");
156  }
157 
158  return boost::make_shared<XdmaBackend>("/dev/" + address, parameters["map"]);
159  }
160 
161 } // namespace ChimeraTK
ChimeraTK::XdmaBackend::read
void read(uint64_t bar, uint64_t address, int32_t *data, size_t sizeInBytes) override
Read function to be implemented by backends.
Definition: XdmaBackend.cc:95
XdmaBackend.h
ChimeraTK::DeviceBackendImpl::setOpenedAndClearException
void setOpenedAndClearException() noexcept
Backends should call this function at the end of a (successful) open() call.
Definition: DeviceBackendImpl.cc:12
ChimeraTK::XdmaBackend::open
void open() override
Open the device.
Definition: XdmaBackend.cc:18
ChimeraTK::XdmaBackend::closeImpl
void closeImpl() override
All backends derrived from NumericAddressedBackend must implement closeImpl() instead of close.
Definition: XdmaBackend.cc:50
ChimeraTK::XdmaBackend::write
void write(uint64_t bar, uint64_t address, const int32_t *data, size_t sizeInBytes) override
Write function to be implemented by backends.
Definition: XdmaBackend.cc:106
ChimeraTK::DeviceBackendImpl::_opened
std::atomic< bool > _opened
flag if backend is opened
Definition: DeviceBackendImpl.h:60
ChimeraTK::runtime_error
Exception thrown when a runtime error has occured.
Definition: Exception.h:18
ChimeraTK::XdmaBackend::~XdmaBackend
~XdmaBackend() override
Definition: XdmaBackend.cc:16
ChimeraTK::XdmaIntfAbstract
Definition: XdmaIntfAbstract.h:10
ChimeraTK::NumericAddressedBackend
Base class for address-based device backends (e.g.
Definition: NumericAddressedBackend.h:20
ChimeraTK::DeviceBackendImpl::setException
void setException(const std::string &message) noexcept final
Set the backend into an exception state.
Definition: DeviceBackendImpl.cc:26
ChimeraTK::XdmaBackend::XdmaBackend
XdmaBackend(std::string devicePath, std::string mapFileName="")
Definition: XdmaBackend.cc:13
ChimeraTK::async::DomainImpl
Definition: DomainImpl.h:15
ChimeraTK::DeviceBackendImpl::isFunctional
bool isFunctional() const noexcept final
Return whether a device is working as intended, usually this means it is opened and does not have any...
Definition: DeviceBackendImpl.h:85
ChimeraTK::XdmaBackend::dump
void dump(const int32_t *data, size_t nbytes)
ChimeraTK::XdmaBackend::createInstance
static boost::shared_ptr< DeviceBackend > createInstance(std::string address, std::map< std::string, std::string > parameters)
Definition: XdmaBackend.cc:152
ChimeraTK::for_each
void for_each(MAPTYPE &map, const LAMBDATYPE &lambda)
Variant of boost::fusion::for_each() to iterate a boost::fusion::map, which accepts a lambda instead ...
Definition: SupportedUserTypes.h:888
ChimeraTK::XdmaBackend::readDeviceInfo
std::string readDeviceInfo() override
Return a device information string containing hardware details like the firmware version number or th...
Definition: XdmaBackend.cc:139
ChimeraTK::XdmaBackend::activateSubscription
std::future< void > activateSubscription(uint32_t interruptNumber, boost::shared_ptr< async::DomainImpl< std::nullptr_t >> asyncDomain) override
Activate/create the subscription for a given interrupt (for instance by starting the according interr...
Definition: XdmaBackend.cc:117
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::to_string
std::string to_string(Boolean &value)
Definition: SupportedUserTypes.h:59
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51
ChimeraTK::XdmaBackend::isOpen
bool isOpen() override
Return whether a device has been opened or not.
Definition: XdmaBackend.cc:57