15#ifndef SIMICS_SYSTEMC_COMPOSITE_PCIE_MAPPING_INTERCONNECT_H
16#define SIMICS_SYSTEMC_COMPOSITE_PCIE_MAPPING_INTERCONNECT_H
20#include <tlm_utils/multi_socket_bases.h>
21#include <tlm_utils/simple_initiator_socket.h>
22#include <tlm_utils/simple_target_socket.h>
24#include <simics/cc-api.h>
42const char *
const PCIE_MAPPING_INTERCONNECT_TAG = \
43 "intel/PcieMappingInterconnect";
65std::string pcieDeviceIdStr(uint16_t device_id) {
66 std::ostringstream os;
67 os <<
"device id 0x" << std::hex << device_id
68 <<
" (" << std::dec << (device_id >> 8)
69 <<
":" << ((device_id >> 3) & 0x1f)
70 <<
"." << (device_id & 7) <<
")";
81template<
typename TSocket>
106template <
unsigned int BUSWIDTH,
typename TYPES>
109 typedef tlm_utils::simple_target_socket<
111 typedef tlm_utils::simple_initiator_socket<
114 tlm::tlm_target_socket<BUSWIDTH, TYPES> *tlm;
115 tlm_utils::multi_target_base<BUSWIDTH, TYPES> *multi;
116 } supported_target_socket_t;
123 sc_core::sc_module_name =
"PcieMappingInterconnect")
127 initiator_sockets_(
"initiator_socket"),
128 config_target_socket_(),
129 msg_target_socket_(),
130 pcie_map_target_socket_(
"pcie_map_target_socket") {
132 this, &PcieMappingInterconnect::transaction_b_transport);
134 this, &PcieMappingInterconnect::transaction_transport_dbg);
136 this, &PcieMappingInterconnect::pcie_map_invalidate_direct_mem_ptr);
137 pcie_map_target_socket_.register_b_transport(
138 this, &PcieMappingInterconnect::pcie_map_b_transport);
139 pcie_map_target_socket_.register_transport_dbg(
140 this, &PcieMappingInterconnect::pcie_map_transport_dbg);
141 pcie_map_target_socket_.register_get_direct_mem_ptr(
142 this, &PcieMappingInterconnect::pcie_map_get_direct_mem_ptr);
145 pcie_map_extension_.
init(&sender_);
150 SC_METHOD(warmReset);
154 config_target_socket_.tlm =
nullptr;
155 config_target_socket_.multi =
nullptr;
156 msg_target_socket_.tlm =
nullptr;
157 msg_target_socket_.multi =
nullptr;
231 void addFunction(uint16_t device_id);
234 void delFunction(uint16_t device_id);
237 void castToTarget(sc_core::sc_object *
object,
238 supported_target_socket_t *target);
245 void updateMappings(
int function_id = -1,
int bar_id = -1);
255 void updateCommand(uint16_t function_id, uint16_t old_command);
263 void retrieveFunctionData(
size_t socket_id,
int bar_id);
266 void interceptCfgHeaderAccess(
size_t socket_id,
267 tlm::tlm_generic_payload &trans);
272 tlm::tlm_generic_payload &trans)
const;
275 conf_object_t *getCfgMapHelper(uint16_t device_id);
281 virtual bool validateBarInfo(ConfObjectRef o);
285 size_t validateTransaction(tlm::tlm_generic_payload &trans);
292 void transaction_b_transport(tlm::tlm_generic_payload &trans,
293 sc_core::sc_time &t);
294 unsigned int transaction_transport_dbg(
295 tlm::tlm_generic_payload &trans);
297 void pcie_map_invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
298 sc_dt::uint64 end_range);
299 void pcie_map_b_transport(
300 tlm::tlm_generic_payload &trans,
301 sc_core::sc_time &t);
302 unsigned int pcie_map_transport_dbg(
303 tlm::tlm_generic_payload &trans);
304 bool pcie_map_get_direct_mem_ptr(
305 tlm::tlm_generic_payload &trans,
306 tlm::tlm_dmi &dmi_data);
310 sc_core::sc_vector<initiator_socket_t> initiator_sockets_;
311 supported_target_socket_t config_target_socket_;
312 supported_target_socket_t msg_target_socket_;
314 target_socket_t pcie_map_target_socket_;
316 struct cfg_header_t {
318 uint32_t base_address[7];
321 std::map<uint16_t, cfg_header_t> function_data_;
322 std::vector<iface::PcieBaseAddressRegisterQueryInterface::PCIeBar>
326 PcieMappingInterconnectExtensionSender<initiator_socket_t> sender_;
333 std::map<std::pair<size_t, size_t>,
size_t> address_id_mem_map_;
335 std::map<std::pair<size_t, size_t>,
size_t> address_id_io_map_;
337 std::map<std::pair<size_t, size_t>,
size_t> fn_bar_id_map_;
339 ConfObjectRef simulation_obj_ {
nullptr};
343 ConfObjectRef gasket_obj_ {
nullptr};
348 bool function_number_has_8bits_ {
false};
352 uint16_t device_id_ {0};
356 iface::PcieSriovQueryInterface *sriov_query_ {
nullptr};
363 uint16_t cap_offset = 0;
366 int first_vf_function = 0;
382 uint32_t vf_bar[6] = {};
385 uint16_t control = 0;
386 uint16_t num_vfs = 0;
388 std::vector<SriovState> sriov_states_;
395 void setupSriovStates();
400 void updateVfCfgMappings(SriovState &state,
bool enable);
405 void updateVfBarMappings(SriovState &state,
bool enable);
408template <
unsigned int BUSWIDTH,
typename TYPES>
416 initiator_sockets_.init(function_data_.size() + bar_info_.size() + 1);
418 size_t socket_id = 0;
420 for (; socket_id < function_data_.size(); ++socket_id) {
421 if (config_target_socket_.tlm) {
422 initiator_sockets_[socket_id].bind(*config_target_socket_.tlm);
424 initiator_sockets_[socket_id].bind(*config_target_socket_.multi);
428 for (
const auto &bar : bar_info_) {
429 supported_target_socket_t target = {};
430 castToTarget(bar.target_socket, &target);
432 initiator_sockets_[socket_id].bind(*target.tlm);
433 }
else if (target.multi) {
434 initiator_sockets_[socket_id].bind(*target.multi);
437 PCIE_MAPPING_INTERCONNECT_TAG,
438 "BAR target_socket type is not supported");
440 fn_bar_id_map_[std::make_pair(bar.function, bar.offset)] = socket_id;
444 if (msg_target_socket_.tlm) {
445 initiator_sockets_[socket_id].bind(*msg_target_socket_.tlm);
447 initiator_sockets_[socket_id].bind(*msg_target_socket_.multi);
451template <
unsigned int BUSWIDTH,
typename TYPES>
456 pcie_map_extension_.get_device_id(gasket_obj_);
458 const uint16_t function_mask =
459 function_number_has_8bits_ ? 0xffu : 0x7u;
460 device_id_ = device_id &
static_cast<uint16_t
>(~function_mask);
463 std::ostringstream os;
464 os <<
"connected(): raw device_id=0x" << std::hex << device_id
465 <<
", ARI=" << std::boolalpha << function_number_has_8bits_
466 <<
", masked device_id_=0x" << std::hex << device_id_;
467 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
475 for (
const auto &fd : function_data_) {
476 delFunction(device_id_ | fd.first);
477 addFunction(device_id_ | fd.first);
487 for (
const auto &state : sriov_states_) {
488 for (
int i = 0; i < state.total_vfs; ++i) {
489 const uint16_t fn =
static_cast<uint16_t
>(
490 state.first_vf_function
491 + i * state.vf_stride);
492 pcie_map_extension_.disable_function(device_id_ | fn);
497template <
unsigned int BUSWIDTH,
typename TYPES>
500 const uint16_t function_mask =
501 function_number_has_8bits_ ? 0xffu : 0x7u;
502 const uint16_t masked_device_id =
503 device_id &
static_cast<uint16_t
>(~function_mask);
504 if (masked_device_id != device_id_) {
507 "disconnected() called with device_id 0x%x, but currently"
508 " connected to 0x%x", masked_device_id, device_id_);
511 for (
auto &fd : function_data_) {
512 delFunction(device_id_ | fd.first);
514 fd.second.command = 0;
515 updateMappings(fd.first);
519template <
unsigned int BUSWIDTH,
typename TYPES>
523 for (
auto &fd : function_data_) {
525 fd.second.command = 0;
526 updateMappings(fd.first);
534 for (
auto &state : sriov_states_) {
535 if (state.control & 0x1u) {
536 updateVfCfgMappings(state,
false);
540 std::fill(std::begin(state.vf_bar), std::end(state.vf_bar), 0u);
545template <
unsigned int BUSWIDTH,
typename TYPES>
549 for (
auto &fd : function_data_) {
551 fd.second.command = 0;
552 updateMappings(fd.first);
557template <
unsigned int BUSWIDTH,
typename TYPES>
558void PcieMappingInterconnect<BUSWIDTH, TYPES>::
559addFunction(uint16_t device_id) {
560 std::ostringstream os;
561 os <<
"Adding function for device_id: "
563 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
564 auto *map_helper = getCfgMapHelper(device_id);
565 if (map_helper ==
nullptr) {
566 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG,
567 "Failure to get map helper");
570 pcie_map_extension_.add_function(map_helper, device_id);
571 if (sender_.failed_transaction_.payload()) {
572 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG,
573 "Failure to add function");
578template <
unsigned int BUSWIDTH,
typename TYPES>
579void PcieMappingInterconnect<BUSWIDTH, TYPES>::
580delFunction(uint16_t device_id) {
581 std::ostringstream os;
582 os <<
"Deleting function for device_id: "
584 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
585 auto *map_helper = getCfgMapHelper(device_id);
586 if (map_helper ==
nullptr) {
587 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG,
588 "Failure to get map helper");
591 pcie_map_extension_.del_function(map_helper, device_id);
592 if (sender_.failed_transaction_.payload()) {
593 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG,
594 "Failure to delete function");
599template <
unsigned int BUSWIDTH,
typename TYPES>
600bool PcieMappingInterconnect<BUSWIDTH, TYPES>::
601validateBarInfo(ConfObjectRef o) {
603 std::map<std::pair<int, int>,
bool> seen;
606 for (
const auto &bar : bar_info_) {
608 auto err = [&](
const std::string &msg) {
609 std::ostringstream os;
610 os <<
"BAR (function=" << bar.function
611 <<
", offset=0x" << std::hex << bar.offset
617 if (bar.function < 0) {
618 err(
"function number must be >= 0");
622 if (bar.size_bits <= 0 || bar.size_bits >= 64) {
623 std::ostringstream os;
624 os <<
"size_bits=" << bar.size_bits
625 <<
" is out of valid range [1, 63]";
631 if (!bar.is_memory && bar.is_64bit) {
632 err(
"I/O BARs cannot be 64-bit");
639 static constexpr int kValidOffsets[] = {
640 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, 0x30};
641 if (std::none_of(std::begin(kValidOffsets),
642 std::end(kValidOffsets),
643 [&](
int vo) {
return bar.offset == vo; })) {
644 std::ostringstream os;
645 os <<
"offset=0x" << std::hex << bar.offset
646 <<
" is not a valid BAR offset;"
647 <<
" expected one of 0x10, 0x14, 0x18, 0x1C, 0x20, 0x24, or"
648 <<
" 0x30 (Expansion ROM)";
654 if (bar.offset == 0x30) {
655 if (!bar.is_memory) {
656 err(
"Expansion ROM BAR must have is_memory=true");
659 err(
"Expansion ROM BAR cannot be 64-bit");
665 if (bar.is_64bit && (bar.offset & 7) != 0) {
666 err(
"64-bit BAR must be naturally aligned to 8-byte boundary; "
667 "offset must be 0x10, 0x18, or 0x20");
673 if (!bar.is_64bit && bar.size_bits > 32) {
674 std::ostringstream os;
675 os <<
"32-bit BAR size_bits=" << bar.size_bits
676 <<
" exceeds maximum of 32";
680 if (bar.target_socket ==
nullptr) {
681 err(
"target_socket must not be null");
686 auto key = std::make_pair(bar.function, bar.offset);
687 if (seen.count(key)) {
688 err(
"duplicate BAR entry; each (function, offset)"
689 " pair must be unique");
702 std::map<std::pair<int, int>,
int> upper_half_of;
703 for (
const auto &bar : bar_info_) {
704 if (bar.is_64bit && bar.offset != 0x30) {
705 upper_half_of[std::make_pair(bar.function,
706 bar.offset + 4)] = bar.offset;
709 for (
const auto &bar : bar_info_) {
710 auto it = upper_half_of.find(
711 std::make_pair(bar.function, bar.offset));
712 if (it != upper_half_of.end()) {
713 std::ostringstream os;
714 os <<
"BAR (function=" << bar.function
715 <<
", offset=0x" << std::hex << bar.offset
716 <<
"): offset is already occupied as the upper 32-bit half"
717 <<
" of the 64-bit BAR at offset 0x" << it->second;
725template <
unsigned int BUSWIDTH,
typename TYPES>
731 if (pci ==
nullptr) {
734 "PcieDeviceQueryInterface not implemented on the device");
738 if (bar ==
nullptr) {
741 "PcieBaseAddressRegisterQueryInterface not implemented on"
746 if (reset ==
nullptr) {
748 "PcieResetInterface not implemented on the device");
754 if (!validateBarInfo(o)) {
769 for (
const auto &bar : bar_info_) {
770 if (function_data_.find(bar.function) == function_data_.end()) {
771 function_data_[bar.function];
772 if (bar.function > 7) {
773 function_number_has_8bits_ =
true;
779 auto *initiator =
dynamic_cast<
780 tlm::tlm_initiator_socket<BUSWIDTH, TYPES> *
>(
783 pcie_map_target_socket_.bind(*initiator);
786 "object returned by getPcieMapInitiatorSocket was not"
787 " a tlm::tlm_initiator_socket.");
791 sriov_query_ = sriov;
793 createCfgMapHelper();
796template <
unsigned int BUSWIDTH,
typename TYPES>
797std::map<std::pair<size_t, size_t>,
size_t>
799 return address_id_mem_map_;
802template <
unsigned int BUSWIDTH,
typename TYPES>
803std::map<std::pair<size_t, size_t>,
size_t>
805 return address_id_io_map_;
808template <
unsigned int BUSWIDTH,
typename TYPES>
811 sriov_states_.clear();
812 if (sriov_query_ !=
nullptr) {
813 for (
const auto &info : sriov_query_->getSriovInfo()) {
814 SriovState state = {};
815 state.cap_offset = info.cap_offset;
816 state.pf_function = info.pf_function;
817 state.total_vfs = info.total_vfs;
818 state.first_vf_function = info.first_vf_function;
819 state.vf_stride = (info.vf_stride <= 0) ? 1 : info.vf_stride;
822 for (
const auto &bi : bar_info_) {
823 const int fn = bi.function;
825 (fn >= state.first_vf_function)
826 && ((fn - state.first_vf_function) % state.vf_stride == 0)
827 && ((fn - state.first_vf_function) / state.vf_stride
829 if (is_vf && !bi.is_memory) {
830 std::ostringstream oss;
831 oss <<
"SR-IOV: VF BAR (function=" << fn
832 <<
" offset=0x" << std::hex << bi.offset
833 <<
") has is_memory=false; VF BARs must be"
834 " Memory Space only per PCIe SR-IOV spec";
836 "%s", oss.str().c_str());
840 sriov_states_.push_back(state);
847template <
unsigned int BUSWIDTH,
typename TYPES>
848void PcieMappingInterconnect<BUSWIDTH, TYPES>::
849updateVfCfgMappings(SriovState &state,
bool enable) {
850 const int num_vfs =
static_cast<int>(state.num_vfs);
852 std::ostringstream os;
853 os <<
"SR-IOV PF" << state.pf_function <<
": "
854 << (enable ?
"enabling " :
"disabling ") << num_vfs
855 <<
" VF config space(s)";
856 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
858 for (
int i = 0; i < num_vfs; ++i) {
859 const uint16_t fn =
static_cast<uint16_t
>(
860 state.first_vf_function + i * state.vf_stride);
862 pcie_map_extension_.enable_function(device_id_ | fn);
864 pcie_map_extension_.disable_function(device_id_ | fn);
872template <
unsigned int BUSWIDTH,
typename TYPES>
873void PcieMappingInterconnect<BUSWIDTH, TYPES>::
874updateVfBarMappings(SriovState &state,
bool enable) {
875 const int num_vfs =
static_cast<int>(state.num_vfs);
879 if (num_vfs > state.total_vfs) {
880 std::ostringstream os;
881 os <<
"SR-IOV: NumVFs (" << num_vfs
882 <<
") exceeds TotalVFs (" << state.total_vfs
883 <<
") for PF" << state.pf_function
884 <<
" — refusing to update VF BAR mappings";
885 SC_REPORT_WARNING(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
893 for (
const auto &bi : bar_info_) {
894 if (bi.function != state.first_vf_function || !bi.is_memory)
897 const int ba_idx = (bi.offset - 0x10) / 4;
898 if (ba_idx < 0 || ba_idx >= 6)
901 const int sz = bi.size_bits;
907 const uint32_t lo = state.vf_bar[ba_idx];
908 const uint32_t hi = (bi.is_64bit && ba_idx + 1 < 6)
909 ? state.vf_bar[ba_idx + 1] : 0u;
910 const uint64_t vf_bar_raw = (
static_cast<uint64_t
>(hi) << 32) | lo;
911 const uint64_t align_mask = ~((1ULL << sz) - 1ULL);
912 const uint64_t vf_base = vf_bar_raw & align_mask;
915 std::ostringstream os;
916 os <<
"SR-IOV PF" << state.pf_function
917 <<
" VF BAR (cfg 0x" << std::hex << bi.offset <<
"): "
918 << (enable ?
"enabling " :
"disabling ")
919 << std::dec << num_vfs <<
" VF BAR(s)";
920 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
924 for (
int i = 0; i < num_vfs; ++i) {
925 const uint16_t fn =
static_cast<uint16_t
>(
926 state.first_vf_function + i * state.vf_stride);
927 auto it = function_data_.find(fn);
928 if (it == function_data_.end()) {
929 std::ostringstream os;
930 os <<
"SR-IOV PF" << state.pf_function
931 <<
": VF function " << fn
932 <<
" not found in function_data_ — inconsistent SR-IOV"
933 " configuration (getSriovInfo() and getBarInfo()"
935 SC_REPORT_ERROR(PCIE_MAPPING_INTERCONNECT_TAG,
939 auto &fd = it->second;
944 const size_t socket_id = fn_bar_id_map_.at(
945 std::make_pair(
static_cast<size_t>(fn),
946 static_cast<size_t>(bi.offset)));
949 const uint64_t vf_addr =
950 vf_base +
static_cast<uint64_t
>(i) * (1ULL << sz);
951 fd.base_address[ba_idx] =
static_cast<uint32_t
>(vf_addr);
952 if (bi.is_64bit && ba_idx + 1 < 7)
953 fd.base_address[ba_idx + 1] =
954 static_cast<uint32_t
>(vf_addr >> 32);
955 const types::map_info_t info(
956 vf_addr, vf_addr, 1ULL << sz,
957 static_cast<int>(fn));
958 address_id_mem_map_[std::make_pair(
959 vf_addr, vf_addr + (1ULL << sz))] = socket_id;
962 fd.base_address[ba_idx] = 0;
963 if (bi.is_64bit && ba_idx + 1 < 7)
964 fd.base_address[ba_idx + 1] = 0;
970template <
unsigned int BUSWIDTH,
typename TYPES>
971void PcieMappingInterconnect<BUSWIDTH, TYPES>::
972retrieveFunctionData(
size_t socket_id,
int bar_id) {
973 if (initiator_sockets_.size() <= socket_id) {
974 std::ostringstream os;
975 os <<
"Invalid socket_id: " << socket_id;
976 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
980 tlm::tlm_generic_payload trans;
984 trans.set_data_ptr(
reinterpret_cast<unsigned char *
>(&value));
985 trans.set_data_length(4);
986 trans.set_streaming_width(4);
988 trans.set_command(tlm::TLM_READ_COMMAND);
989 trans.set_address(0x4);
991 auto ret = initiator_sockets_[socket_id]->transport_dbg(trans);
999 auto fd = function_data_.begin();
1000 std::advance(fd, socket_id);
1001 fd->second.command = value;
1005 for (
const auto &bar : bar_info_) {
1009 if (bar.function != fd->first) {
1013 int expected_bar_id = bar.offset == 0x30 ? 6 : (bar.offset - 0x10) / 4;
1015 if (bar_id != -1 && bar_id != expected_bar_id) {
1019 trans.set_address(bar.offset);
1020 initiator_sockets_[socket_id]->transport_dbg(trans);
1021 fd->second.base_address[expected_bar_id] = value;
1023 if (expected_bar_id == 6) {
1025 PCIE_MAPPING_INTERCONNECT_TAG,
1026 "Expansion ROM BAR can't support 64-bit address");
1029 trans.set_address(bar.offset + 4);
1030 initiator_sockets_[socket_id]->transport_dbg(trans);
1031 fd->second.base_address[expected_bar_id + 1] = value;
1037template <
unsigned int BUSWIDTH,
typename TYPES>
1038void PcieMappingInterconnect<BUSWIDTH, TYPES>::
1040 std::ostringstream os;
1041 os <<
"Adding mapping of type: "
1042 << pcieTypeName(type);
1043 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
1044 pcie_map_extension_.add_map(info, type);
1045 if (sender_.failed_transaction_.payload()) {
1046 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG,
"Failure to add map");
1051template <
unsigned int BUSWIDTH,
typename TYPES>
1052void PcieMappingInterconnect<BUSWIDTH, TYPES>::
1056 auto it = std::find_if(
1057 address_id_mem_map_.begin(),
1058 address_id_mem_map_.end(),
1060 const std::pair<std::pair<size_t, size_t>,
size_t> &entry) {
1061 return entry.second == socket_id;
1064 if (it != address_id_mem_map_.end()) {
1065 base = it->first.first;
1066 address_id_mem_map_.erase(it);
1069 auto it = std::find_if(
1070 address_id_io_map_.begin(),
1071 address_id_io_map_.end(),
1073 const std::pair<std::pair<size_t, size_t>,
size_t> &entry) {
1074 return entry.second == socket_id;
1077 if (it != address_id_io_map_.end()) {
1078 base = it->first.first;
1079 address_id_io_map_.erase(it);
1083 if (base != 0xffffffffffffffff) {
1084 std::ostringstream os;
1085 os <<
"Deleting mapping of type: "
1086 << pcieTypeName(type) <<
", base: 0x" << std::hex << base;
1087 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
1089 pcie_map_extension_.del_map(base, type);
1090 if (sender_.failed_transaction_.payload()) {
1091 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG,
"Failure to del map");
1097template <
unsigned int BUSWIDTH,
typename TYPES>
1098void PcieMappingInterconnect<BUSWIDTH, TYPES>::
1099updateMappings(
int function_id,
int bar_id) {
1100 for (
const auto &bi : bar_info_) {
1101 if (function_id != -1 && bi.function != function_id) {
1105 auto header = function_data_.at(bi.function);
1107 int expected_bar_id = bi.offset == 0x30 ? 6 : (bi.offset - 0x10) / 4;
1108 if (bar_id != -1 && bar_id != expected_bar_id) {
1112 uint64_t base_address = header.base_address[expected_bar_id];
1114 if (expected_bar_id == 6) {
1116 PCIE_MAPPING_INTERCONNECT_TAG,
1117 "Expansion ROM BAR can't support 64-bit address");
1119 base_address |=
static_cast<uint64_t
>(
1120 header.base_address[expected_bar_id + 1]) << 32;
1124 bool enable = header.command & 1;
1128 if (bi.offset == 0x30) {
1129 enable = base_address & 1;
1131 enable = (header.command >> 1) & 1;
1134 base_address &= ~((1ULL << bi.size_bits) - 1);
1135 size_t socket_id = fn_bar_id_map_.at(
1136 std::make_pair(bi.function, bi.offset));
1137 delMap(socket_id, type);
1142 types::map_info_t info(base_address, base_address,
1143 1ULL << bi.size_bits, function_id);
1144 auto address_range = std::make_pair(info.base,
1145 info.base + info.length);
1148 address_id_mem_map_[address_range] = socket_id;
1149 std::ostringstream os;
1150 os <<
"Memory address for function " << bi.function
1151 <<
" and bar ID " << expected_bar_id
1152 <<
" in range of [0x" << std::hex << info.base
1153 <<
"-0x" << info.base + info.length <<
"] maps to socket ID "
1155 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
1157 address_id_io_map_[address_range] = socket_id;
1158 std::ostringstream os;
1159 os <<
"IO address for function " << bi.function
1160 <<
" and bar ID " << expected_bar_id
1161 <<
" in range of [0x" << std::hex << info.base
1162 <<
"-0x" << info.base + info.length <<
"] maps to socket ID "
1164 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
1171template <
unsigned int BUSWIDTH,
typename TYPES>
1172void PcieMappingInterconnect<BUSWIDTH, TYPES>::
1173updateCommand(uint16_t function_id, uint16_t old_command) {
1174 if (function_data_[function_id].command != old_command) {
1175 updateMappings(function_id);
1179template <
unsigned int BUSWIDTH,
typename TYPES>
1180void PcieMappingInterconnect<BUSWIDTH, TYPES>::
1181interceptCfgHeaderAccess(
size_t socket_id,
1182 tlm::tlm_generic_payload &trans) {
1183 unsigned int size = trans.get_data_length();
1185 if (trans.get_byte_enable_ptr() || trans.get_streaming_width() != size) {
1190 if (!trans.is_write()) {
1195 uint64_t *data =
reinterpret_cast<uint64_t *
>(trans.get_data_ptr());
1197 auto it = function_data_.begin();
1198 std::advance(it, socket_id);
1199 uint16_t function_id = it->first;
1200 auto &header = it->second;
1201 sc_dt::uint64 offset = trans.get_address();
1204 uint16_t old_command = header.command;
1205 retrieveFunctionData(socket_id, -1);
1206 header.command = (*data) & 0xffff;
1207 updateCommand(function_id, old_command);
1216 int bar_id = (offset - 0x10) / 4;
1217 retrieveFunctionData(socket_id, bar_id);
1224 header.base_address[bar_id] = *data & 0xffffffff;
1225 if (size == 8 && !(offset % 8)) {
1226 header.base_address[bar_id + 1] = *data >> 32;
1228 updateMappings(function_id, bar_id);
1233 retrieveFunctionData(socket_id, bar_id);
1234 header.base_address[bar_id] = *data & 0xffffffff;
1235 updateMappings(function_id, bar_id);
1240 for (
auto &state : sriov_states_) {
1241 if (
static_cast<int>(function_id) != state.pf_function)
1243 const sc_dt::uint64 cap = state.cap_offset;
1244 const uint32_t written =
static_cast<uint32_t
>(*data);
1245 if (offset == cap + 0x08) {
1246 const uint16_t old_ctrl = state.control;
1247 state.control =
static_cast<uint16_t
>(written & 0xFFFFu);
1257 const bool vf_enable_was = old_ctrl & 0x1u;
1258 const bool vf_enable_now = state.control & 0x1u;
1259 const bool vf_mse_was = (old_ctrl >> 3) & 0x1u;
1260 const bool vf_mse_now = (state.control >> 3) & 0x1u;
1261 const bool bars_were_live = vf_enable_was && vf_mse_was;
1262 const bool bars_are_live = vf_enable_now && vf_mse_now;
1263 if (vf_enable_was != vf_enable_now) {
1264 updateVfCfgMappings(state, vf_enable_now);
1266 if (bars_were_live != bars_are_live) {
1267 updateVfBarMappings(state, bars_are_live);
1269 }
else if (offset == cap + 0x10) {
1270 state.num_vfs =
static_cast<uint16_t
>(written & 0xFFFFu);
1271 }
else if (offset >= cap + 0x24 && offset < cap + 0x24 + 6 * 4) {
1275 const int idx =
static_cast<int>((offset - (cap + 0x24)) / 4);
1276 state.vf_bar[idx] = written;
1281 const bool vf_en = (state.control & 0x1u) != 0;
1282 const bool vf_mse = ((state.control >> 3) & 0x1u) != 0;
1283 if (vf_en && vf_mse)
1284 updateVfBarMappings(state,
true);
1290template <
unsigned int BUSWIDTH,
typename TYPES>
1291size_t PcieMappingInterconnect<BUSWIDTH, TYPES>::
1293 tlm::tlm_generic_payload &trans)
const {
1295 auto found = function_data_.find(function_id);
1296 if (found == function_data_.end()) {
1297 std::ostringstream os;
1298 os <<
"Function id(" << function_id
1299 <<
") not found for this device";
1300 throw std::invalid_argument {
1304 return std::distance(function_data_.begin(), found);
1306 size_t address = trans.get_address();
1307 for (
const auto &entry : address_id_mem_map_) {
1308 auto startAddress = entry.first.first;
1309 auto endAddress = entry.first.second;
1310 auto id = entry.second;
1312 if (address >= startAddress && address < endAddress) {
1313 if (enable_base_address_subtraction) {
1314 trans.set_address(address - startAddress);
1319 throw std::invalid_argument {
1320 "Unable to find the initiator_socket to forward the MEM transaction"
1323 size_t address = trans.get_address();
1324 for (
const auto &entry : address_id_io_map_) {
1325 auto startAddress = entry.first.first;
1326 auto endAddress = entry.first.second;
1327 auto id = entry.second;
1329 if (address >= startAddress && address < endAddress) {
1330 if (enable_base_address_subtraction) {
1331 trans.set_address(address - startAddress);
1336 throw std::invalid_argument {
1337 "Unable to find the initiator_socket to forward the IO transaction"
1340 return function_data_.size() + bar_info_.size();
1342 throw std::invalid_argument {
1343 "Unsupported PCIe type"
1347template <
unsigned int BUSWIDTH,
typename TYPES>
1351 if (map_helper ==
nullptr) {
1354 "Simics class pcie_map_helper_cpp is required."
1355 "Try load the module pcie-map-helper-c++ first.");
1359 if (SIM_c_get_interface(simulation_obj_,
"pcie_device") ==
nullptr) {
1361 if (!SIM_object_is_configured(simulation_obj_)) {
1364 "Simulation object is not configured yet, cannot get"
1365 " its gasket_list attribute");
1372 int gasket_count = SIM_attr_list_size(gasket_list);
1373 for (
int i = 0; i < gasket_count; ++i) {
1374 auto obj = SIM_attr_object(SIM_attr_list_item(gasket_list, i));
1375 if (SIM_c_get_interface(obj,
"pcie_device")) {
1380 if (gasket_obj_.object() ==
nullptr) {
1383 "No gasket object implemented the required"
1384 " pcie_device interface");
1388 gasket_obj_ = simulation_obj_.object();
1391 for (
const auto &fd : function_data_) {
1392 auto pcie_type = std_to_attr<>(
1394 auto forward_target = std_to_attr<>(
1395 std::pair<std::string, ConfObjectRef>(
"forward_target",
1397 auto function_id = std_to_attr<>(
1398 std::pair<std::string, int>(
"function_id", fd.first));
1399 attr_value_t attr = SIM_make_attr_list(3, pcie_type, forward_target,
1402 auto obj_name = gasket_obj_.name() +
".port.cfg" + \
1403 std::to_string(fd.first);
1406 std::ignore = SIM_clear_exception();
1410 SIM_attr_free(&attr);
1414template <
unsigned int BUSWIDTH,
typename TYPES>
1417 std::string name =
"port.cfg";
1418 if (function_number_has_8bits_) {
1419 name += std::to_string(device_id & 0xff);
1421 name += std::to_string(device_id & 7);
1423 auto map_helper = SIM_object_descendant(gasket_obj_, name.c_str());
1426 "Could not find map helper object with name '%s.%s'",
1427 gasket_obj_.name().c_str(), name.c_str());
1432template <
unsigned int BUSWIDTH,
typename TYPES>
1433size_t PcieMappingInterconnect<BUSWIDTH, TYPES>::
1434validateTransaction(tlm::tlm_generic_payload &trans) {
1435 PcieTlmExtension *pcie_ext =
nullptr;
1436 trans.get_extension<PcieTlmExtension>(pcie_ext);
1438 if (pcie_ext ==
nullptr) {
1439 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
1440 SC_REPORT_ERROR(PCIE_MAPPING_INTERCONNECT_TAG,
1441 "PcieTlmExtension is required but not found");
1445 std::ostringstream os;
1446 os <<
"Received a PCIe transaction with type "
1447 << pcieTypeName(pcie_ext->type);
1448 if (pcie_ext->device_id_set) {
1449 os <<
", " << pcieDeviceIdStr(pcie_ext->device_id);
1451 os <<
", address 0x" << std::hex << trans.get_address() << std::endl;
1452 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
1456 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG,
1457 "Only support following PCIe types: MEM/IO/CFG/MSG");
1458 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
1463 && !pcie_ext->device_id_set) {
1464 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG,
1465 "PCIe device ID ATOM is required");
1466 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
1470 size_t socket_id = 0;
1474 const uint16_t fn = function_number_has_8bits_
1475 ? (pcie_ext->device_id & 0xFF)
1476 : (pcie_ext->device_id & 7);
1477 socket_id = findSocketId(pcie_ext->type, fn, trans);
1478 }
catch (
const std::exception &e) {
1479 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, e.what());
1480 trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
1484 if (socket_id >= initiator_sockets_.size()) {
1486 os <<
"Initiator socket ID " << socket_id <<
" not created yet";
1487 SC_REPORT_INFO(PCIE_MAPPING_INTERCONNECT_TAG, os.str().c_str());
1488 trans.set_response_status(tlm::TLM_GENERIC_ERROR_RESPONSE);
1493 interceptCfgHeaderAccess(socket_id, trans);
1499template <
unsigned int BUSWIDTH,
typename TYPES>
1500void PcieMappingInterconnect<BUSWIDTH, TYPES>::
1501transaction_b_transport(tlm::tlm_generic_payload &trans,
1502 sc_core::sc_time &t) {
1503 trans.set_response_status(tlm::TLM_OK_RESPONSE);
1504 size_t socket_id = validateTransaction(trans);
1505 if (trans.get_response_status() == tlm::TLM_OK_RESPONSE) {
1506 initiator_sockets_.at(socket_id)->b_transport(trans, t);
1510template <
unsigned int BUSWIDTH,
typename TYPES>
1511unsigned int PcieMappingInterconnect<BUSWIDTH, TYPES>::
1512transaction_transport_dbg(tlm::tlm_generic_payload &trans) {
1513 trans.set_response_status(tlm::TLM_OK_RESPONSE);
1514 size_t socket_id = validateTransaction(trans);
1515 if (trans.get_response_status() == tlm::TLM_OK_RESPONSE) {
1516 return initiator_sockets_.at(socket_id)->transport_dbg(trans);
1525template <
unsigned int BUSWIDTH,
typename TYPES>
1526void PcieMappingInterconnect<BUSWIDTH, TYPES>::
1527pcie_map_invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
1528 sc_dt::uint64 end_range) {
1529 pcie_map_target_socket_->invalidate_direct_mem_ptr(start_range,
1536template <
unsigned int BUSWIDTH,
typename TYPES>
1537void PcieMappingInterconnect<BUSWIDTH, TYPES>::pcie_map_b_transport(
1538 tlm::tlm_generic_payload &trans,
1539 sc_core::sc_time &t) {
1540 pcie_map_initiator_socket->b_transport(trans, t);
1546template <
unsigned int BUSWIDTH,
typename TYPES>
1547unsigned int PcieMappingInterconnect<BUSWIDTH, TYPES>::pcie_map_transport_dbg(
1548 tlm::tlm_generic_payload &trans) {
1549 return pcie_map_initiator_socket->transport_dbg(trans);
1555template <
unsigned int BUSWIDTH,
typename TYPES>
1556bool PcieMappingInterconnect<BUSWIDTH, TYPES>::pcie_map_get_direct_mem_ptr(
1557 tlm::tlm_generic_payload &trans,
1558 tlm::tlm_dmi &dmi_data) {
1559 return pcie_map_initiator_socket->get_direct_mem_ptr(trans, dmi_data);
1562template <
unsigned int BUSWIDTH,
typename TYPES>
1563void PcieMappingInterconnect<BUSWIDTH, TYPES>::
1564castToTarget(sc_core::sc_object *
object, supported_target_socket_t *target) {
1565 if (
object ==
nullptr) {
1566 SC_REPORT_ERROR(PCIE_MAPPING_INTERCONNECT_TAG,
1567 "Unable to castToTarget from a nullptr");
1571 auto *tlm_target =
dynamic_cast<
1572 tlm::tlm_target_socket<BUSWIDTH, TYPES> *
>(object);
1574 target->tlm = tlm_target;
1578 auto *multi_target =
dynamic_cast<
1579 tlm_utils::multi_target_base<BUSWIDTH, TYPES> *
>(object);
1581 target->multi = multi_target;
1585 SC_REPORT_ERROR(PCIE_MAPPING_INTERCONNECT_TAG,
1586 "Unable to dynamic-cast PCIe target socket");
Definition: pcie_mapping_interconnect.h:83
void send_extension(iface::Transaction *transaction) override
Called by extension after the extension is set on the payload.
Definition: pcie_mapping_interconnect.h:88
virtual ~PcieMappingInterconnectExtensionSender()
Definition: pcie_mapping_interconnect.h:85
iface::Transaction failed_transaction_
Definition: pcie_mapping_interconnect.h:97
void send_failed(iface::Transaction *transaction) override
Called by extension if method_call invocation was missing.
Definition: pcie_mapping_interconnect.h:92
Definition: pcie_mapping_interconnect.h:107
PcieMappingInterconnect(sc_core::sc_module_name="PcieMappingInterconnect")
Definition: pcie_mapping_interconnect.h:122
void connected(uint16_t device_id)
Definition: pcie_mapping_interconnect.h:452
void before_end_of_elaboration() override
Definition: pcie_mapping_interconnect.h:409
bool enable_base_address_subtraction
Definition: pcie_mapping_interconnect.h:215
SC_HAS_PROCESS(PcieMappingInterconnect)
initiator_socket_t pcie_map_initiator_socket
IC -> Simics, forwards the upstream pcie-map transactions.
Definition: pcie_mapping_interconnect.h:210
void connect(iface::PcieDeviceQueryInterface *pci, iface::PcieBaseAddressRegisterQueryInterface *bar, iface::PcieResetInterface *reset, ConfObjectRef o, iface::PcieSriovQueryInterface *sriov=nullptr)
Called by (outer) composite class to retrieve the required information to connect the IC with the PCI...
Definition: pcie_mapping_interconnect.h:727
void hotReset()
Definition: pcie_mapping_interconnect.h:520
void createCfgMapHelper()
Definition: pcie_mapping_interconnect.h:1349
target_socket_t pcie_device_target_socket
Definition: pcie_mapping_interconnect.h:208
std::map< std::pair< size_t, size_t >, size_t > addressIdMemMap() const
Definition: pcie_mapping_interconnect.h:798
target_socket_t transaction_target_socket
Definition: pcie_mapping_interconnect.h:206
void disconnected(uint16_t device_id)
Definition: pcie_mapping_interconnect.h:499
sc_core::sc_in< bool > warm_reset_pin
Definition: pcie_mapping_interconnect.h:212
std::map< std::pair< size_t, size_t >, size_t > addressIdIoMap() const
Definition: pcie_mapping_interconnect.h:804
Generic extension sender initialized with a TLM2 initiator socket of TSocket type.
Definition: extension_sender.h:33
void send_extension(Transaction *transaction) override
Called by extension after the extension is set on the payload.
Definition: extension_sender.h:53
void init(TSocket *socket)
Definition: extension_sender.h:38
Transaction transaction() override
Called by extension to get a new Transaction.
Definition: extension_sender.h:47
void send_failed(Transaction *transaction) override
Called by extension if method_call invocation was missing.
Definition: extension_sender.h:56
void init(ExtensionSenderInterface *sender, tlm::tlm_generic_payload *payload)
Deprecated, use the init(ExtensionSenderInterface *sender) instead.
Definition: extension.h:43
Interface that allows the Simics glue to perform snooping and automatic connection of the device's ta...
Definition: pcie_device_query_interface.h:51
virtual std::vector< PCIeBar > getBarInfo()=0
BAR register information.
Interface required from a SystemC PCIe device in order to connect to Simics.
Definition: pcie_device_query_interface.h:30
virtual sc_core::sc_object * getMsgTargetSocket()=0
virtual sc_core::sc_object * getConfigTargetSocket()=0
virtual sc_core::sc_object * getPcieMapInitiatorSocket()=0
Extension for Simics pcie_map interface.
Definition: pcie_map_extension.h:26
Definition: pcie_device_query_interface.h:93
Interface providing static SR-IOV configuration to the PcieMappingInterconnect.
Definition: pcie_device_query_interface.h:124
Class that encapsulates a generic_payload and returns it to the TransactionPool when the Transaction ...
Definition: transaction.h:29
conf_object_t * SIM_create_object(conf_class_t *NOTNULL cls, const char *name, attr_value_t attrs)
conf_object_t * SIM_get_object(const char *NOTNULL name)
attr_value_t SIM_get_attribute(conf_object_t *NOTNULL obj, const char *name)
conf_class_t * SIM_get_class(const char *NOTNULL name)
@ Log_Configuration
Definition: adapter_log_groups.h:23
pcie_type_t
Definition: pcie_type.h:20
@ PCIE_Type_Cfg
Definition: pcie_type.h:24
@ PCIE_Type_Mem
Definition: pcie_type.h:22
@ PCIE_Type_Msg
Definition: pcie_type.h:25
@ PCIE_Type_Not_Set
Definition: pcie_type.h:21
@ PCIE_Type_Other
Definition: pcie_type.h:26
@ PCIE_Type_IO
Definition: pcie_type.h:23
Reduced, stand-alone, version of the Simics map_info_t struct.
Definition: map_info.h:23
uint64_t physical_address_t
Definition: map_info.h:24