15#ifndef SIMICS_SYSTEMC_COMPOSITE_PCI_MAPPING_INTERCONNECT_H
16#define SIMICS_SYSTEMC_COMPOSITE_PCI_MAPPING_INTERCONNECT_H
18#if defined SIMICS_5_API || defined SIMICS_6_API
22#include <tlm_utils/multi_passthrough_target_socket.h>
23#include <tlm_utils/simple_target_socket.h>
24#include <tlm_utils/simple_initiator_socket.h>
41const char *
const PCI_MAPPING_INTERCONNECT_TAG =
"intel/PciMappingInterconnect";
50template<
typename TSocket>
51class PciMappingInterconnectExtensionSender
52 :
public iface::ExtensionSender<TSocket> {
54 virtual ~PciMappingInterconnectExtensionSender() {}
55 virtual void send_extension(iface::Transaction *transaction) {
56 failed_transaction_ = iface::Transaction(NULL);
57 iface::ExtensionSender<TSocket>::send_extension(transaction);
59 virtual void send_failed(iface::Transaction *transaction) {
60 failed_transaction_ = *transaction;
61 iface::ExtensionSender<TSocket>::send_failed(transaction);
63 iface::Transaction failed_transaction_;
84template <
unsigned int BUSWIDTH,
typename TYPES>
85class PciMappingInterconnect :
public sc_core::sc_module {
88 typedef tlm_utils::simple_target_socket<
89 PciMappingInterconnect, BUSWIDTH, TYPES> target_socket_t;
90 typedef tlm_utils::multi_passthrough_target_socket<
91 PciMappingInterconnect, BUSWIDTH, TYPES> multi_target_socket_t;
92 typedef tlm_utils::simple_initiator_socket<
93 PciMappingInterconnect, BUSWIDTH, TYPES> initiator_socket_t;
95 tlm::tlm_target_socket<BUSWIDTH, TYPES> *tlm;
96 tlm_utils::multi_target_base<BUSWIDTH, TYPES> *multi;
97 } supported_target_socket_t;
101 SC_HAS_PROCESS(PciMappingInterconnect);
103 explicit PciMappingInterconnect(
104 sc_core::sc_module_name =
"PciMappingInterconnect")
105 : target_socket(
"target_socket"),
106 simics_target_socket(
"simics_target_socket"),
107 pci_bus_initiator_socket(
"pci_bus_initiator_socket"),
108 initiator_sockets_(
"initiator_socket"),
109 pci_target_socket_(),
110 pci_device_target_socket_(),
111 pci_bus_target_socket_(
"pci_bus_target_socket"),
112 number_of_functions_(1),
113 mapping_id_offset_(0x10100) {
114 target_socket.register_b_transport(
115 this, &PciMappingInterconnect::b_transport);
116 target_socket.register_transport_dbg(
117 this, &PciMappingInterconnect::transport_dbg);
118 simics_target_socket.register_b_transport(
119 this, &PciMappingInterconnect::simics_b_transport);
120 pci_bus_target_socket_.register_b_transport(
121 this, &PciMappingInterconnect::pci_bus_b_transport);
122 pci_bus_target_socket_.register_transport_dbg(
123 this, &PciMappingInterconnect::pci_bus_transport_dbg);
124 pci_bus_target_socket_.register_get_direct_mem_ptr(
125 this, &PciMappingInterconnect::pci_bus_get_direct_mem_ptr);
126 pci_bus_initiator_socket.register_invalidate_direct_mem_ptr(
127 this, &PciMappingInterconnect::pci_bus_invalidate_direct_mem_ptr);
128 sender_.init(&pci_bus_initiator_socket);
129 extension_.init(&sender_);
132 virtual void before_end_of_elaboration();
134 void retrieveFunctionData(
int id,
int bar);
136 void connect(iface::PciDeviceQueryInterface *pci, ConfObjectRef o);
138 void connectConfig(iface::BaseAddressRegisterQueryInterface *bar,
139 simics2tlm::IoMemory *gasket,
142 void connectMmio(iface::BaseAddressRegisterQueryInterface *bar,
143 simics2tlm::IoMemory *gasket,
150 multi_target_socket_t target_socket;
151 multi_target_socket_t simics_target_socket;
153 initiator_socket_t pci_bus_initiator_socket;
157 void b_transport(
int id, tlm::tlm_generic_payload &trans,
158 sc_core::sc_time &t);
159 unsigned int transport_dbg(
int id, tlm::tlm_generic_payload &trans);
160 void simics_b_transport(
int id, tlm::tlm_generic_payload &trans,
161 sc_core::sc_time &t);
162 void pci_bus_b_transport(tlm::tlm_generic_payload &trans,
163 sc_core::sc_time &t);
164 unsigned int pci_bus_transport_dbg(tlm::tlm_generic_payload &trans);
165 bool pci_bus_get_direct_mem_ptr(tlm::tlm_generic_payload &trans,
166 tlm::tlm_dmi &dmi_data);
167 void pci_bus_invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
168 sc_dt::uint64 end_range);
171 void castToTarget(sc_core::sc_object *
object,
172 supported_target_socket_t *target);
173 template <
typename TGasket>
174 void bindToGasket(supported_target_socket_t target,
175 TGasket *gasket, ConfObjectRef o,
int id);
176 void updateCommand(
int id, uint16_t old_command);
177 void updateBaseAddress(
int id,
int bar);
178 void updateMemoryMapping(
bool enable, types::addr_space_t space,
179 uint64_t base_address,
int bar_size_bits,
181 void interceptBarAccess(
int id, tlm::tlm_generic_payload &trans,
182 sc_core::sc_time &t);
186 sc_core::sc_vector<initiator_socket_t> initiator_sockets_;
187 supported_target_socket_t pci_target_socket_;
188 initiator_socket_t pci_device_initiator_socket_;
189 supported_target_socket_t pci_device_target_socket_;
191 target_socket_t pci_bus_target_socket_;
193 struct function_data_t {
196 uint32_t base_address[6];
198 std::vector<function_data_t> function_data_;
199 int number_of_functions_;
200 int mapping_id_offset_;
201 iface::BaseAddressRegisterQueryInterface::BarInfo bar_info_;
203 PciMappingInterconnectExtensionSender<
204 initiator_socket_t> sender_;
205 iface::PciBusExtension extension_;
208template <
unsigned int BUSWIDTH,
typename TYPES>
209void PciMappingInterconnect<BUSWIDTH, TYPES>::before_end_of_elaboration() {
215 initiator_sockets_.init(number_of_functions_);
216 for (std::size_t i = 0; i < initiator_sockets_.size(); ++i) {
217 if (pci_target_socket_.tlm) {
218 initiator_sockets_[i].bind(*pci_target_socket_.tlm);
220 initiator_sockets_[i].bind(*pci_target_socket_.multi);
225 function_data_ = std::vector<function_data_t>(number_of_functions_);
226 int prev_function = -1;
228 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
229 = bar_info_.begin(); it != bar_info_.end(); ++it) {
230 int current_function = (*it).function;
231 if (current_function != prev_function) {
232 function_data_[++id].function = current_function;
233 prev_function = current_function;
237 if (pci_device_target_socket_.tlm) {
238 pci_device_initiator_socket_.bind(*pci_device_target_socket_.tlm);
239 }
else if (pci_device_target_socket_.multi) {
240 pci_device_initiator_socket_.bind(*pci_device_target_socket_.multi);
250template <
unsigned int BUSWIDTH,
typename TYPES>
251void PciMappingInterconnect<BUSWIDTH, TYPES>::retrieveFunctionData(
253 tlm::tlm_generic_payload trans;
254 trans.set_command(tlm::TLM_READ_COMMAND);
255 trans.set_data_length(4);
256 trans.set_streaming_width(4);
259 trans.set_data_ptr(
reinterpret_cast<unsigned char *
>(&value));
260 trans.set_address(0x4);
262 auto ret = initiator_sockets_[id]->transport_dbg(trans);
270 function_data_[id].command = value;
273 bool all_bars = (bar == -1) ?
true :
false;
277 int function = function_data_[id].function;
278 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator
279 it = bar_info_.begin(); it != bar_info_.end(); ++it) {
283 if ((*it).function != function) {
287 bar = ((*it).offset - 0x10) / 4;
288 }
else if (bar != ((*it).offset - 0x10) / 4) {
291 uint32_t base_address = 0;
292 trans.set_address((*it).offset);
294 reinterpret_cast<unsigned char *
>(&base_address));
295 trans.set_data_length(
sizeof base_address);
296 trans.set_streaming_width(trans.get_data_length());
297 initiator_sockets_[id]->transport_dbg(trans);
298 function_data_[id].base_address[bar] = base_address;
299 if ((*it).is_64bit) {
301 trans.set_address((*it).offset + 4);
303 reinterpret_cast<unsigned char *
>(&base_address));
304 trans.set_data_length(
sizeof base_address);
305 trans.set_streaming_width(trans.get_data_length());
306 initiator_sockets_[id]->transport_dbg(trans);
307 function_data_[id].base_address[bar + 1] = base_address;
320template <
unsigned int BUSWIDTH,
typename TYPES>
321void PciMappingInterconnect<BUSWIDTH, TYPES>::connect(
322 iface::PciDeviceQueryInterface *pci, ConfObjectRef o) {
323 castToTarget(pci->getPciDeviceTargetSocket(),
324 &pci_device_target_socket_);
325 castToTarget(pci->getConfigTargetSocket(), &pci_target_socket_);
326 tlm::tlm_initiator_socket<BUSWIDTH, TYPES> *initiator
327 =
dynamic_cast<tlm::tlm_initiator_socket<BUSWIDTH, TYPES> *
>(
328 pci->getPciBusInitiatorSocket());
330 pci_bus_target_socket_.bind(*initiator);
333 "object returned by getPciBusInitiatorSocket was not"
334 " a tlm::tlm_initiator_socket.");
344template <
unsigned int BUSWIDTH,
typename TYPES>
345void PciMappingInterconnect<BUSWIDTH, TYPES>::connectConfig(
346 iface::BaseAddressRegisterQueryInterface *bar,
347 simics2tlm::IoMemory *gasket, ConfObjectRef o) {
351 255, simics2tlm::createGasket(&target_socket, o));
354 bar_info_ = bar->getBarInfo();
355 int prev_function = 0;
356 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
357 = bar_info_.begin(); it != bar_info_.end(); ++it) {
358 int current_function = (*it).function;
359 if (current_function != prev_function) {
360 ++number_of_functions_;
361 prev_function = current_function;
362 gasket->addGasket(255 + current_function,
363 simics2tlm::createGasket(&target_socket, o));
365 FATAL_ERROR_IF(current_function < prev_function,
366 "BarInfo must be sorted on function number"
367 " in ascending order");
376template <
unsigned int BUSWIDTH,
typename TYPES>
377void PciMappingInterconnect<BUSWIDTH, TYPES>::connectMmio(
378 iface::BaseAddressRegisterQueryInterface *bar,
379 simics2tlm::IoMemory *gasket, ConfObjectRef o) {
381 = bar->getBarTargetSockets();
382 iface::BaseAddressRegisterQueryInterface::BarSockets::const_iterator it;
383 for (iface::BaseAddressRegisterQueryInterface::BarSockets::const_iterator it
384 = bar_sockets.begin(); it != bar_sockets.end(); ++it) {
385 supported_target_socket_t target = {};
386 castToTarget((*it).second, &target);
387 bindToGasket(target, gasket, o,
388 (*it).first.mapping_id + mapping_id_offset_);
393template <
unsigned int BUSWIDTH,
typename TYPES>
394void PciMappingInterconnect<BUSWIDTH, TYPES>::busReset() {
395 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
396 = bar_info_.begin(); it != bar_info_.end(); ++it) {
397 int mapping_id = (*it).mapping_id + mapping_id_offset_;
399 if ((*it).is_memory) {
402 extension_.remove_map(space, mapping_id);
403 if (sender_.failed_transaction_.payload()) {
404 SC_REPORT_INFO(PCI_MAPPING_INTERCONNECT_TAG,
405 "Failure to unmap device on bus_reset");
416template <
unsigned int BUSWIDTH,
typename TYPES>
417void PciMappingInterconnect<BUSWIDTH, TYPES>::b_transport(
419 tlm::tlm_generic_payload &trans,
420 sc_core::sc_time &t) {
421 interceptBarAccess(
id, trans, t);
422 initiator_sockets_[id]->b_transport(trans, t);
428template <
unsigned int BUSWIDTH,
typename TYPES>
429unsigned int PciMappingInterconnect<BUSWIDTH, TYPES>::transport_dbg(
431 tlm::tlm_generic_payload &trans) {
432 return initiator_sockets_[id]->transport_dbg(trans);
438template <
unsigned int BUSWIDTH,
typename TYPES>
439void PciMappingInterconnect<BUSWIDTH, TYPES>::simics_b_transport(
440 int id, tlm::tlm_generic_payload &trans,
441 sc_core::sc_time &t) {
442 pci_device_initiator_socket_->b_transport(trans, t);
448template <
unsigned int BUSWIDTH,
typename TYPES>
449void PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_b_transport(
450 tlm::tlm_generic_payload &trans,
451 sc_core::sc_time &t) {
452 pci_bus_initiator_socket->b_transport(trans, t);
458template <
unsigned int BUSWIDTH,
typename TYPES>
459unsigned int PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_transport_dbg(
460 tlm::tlm_generic_payload &trans) {
461 return pci_bus_initiator_socket->transport_dbg(trans);
467template <
unsigned int BUSWIDTH,
typename TYPES>
468bool PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_get_direct_mem_ptr(
469 tlm::tlm_generic_payload &trans,
470 tlm::tlm_dmi &dmi_data) {
471 return pci_bus_initiator_socket->get_direct_mem_ptr(trans, dmi_data);
477template <
unsigned int BUSWIDTH,
typename TYPES>
478void PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_invalidate_direct_mem_ptr(
479 sc_dt::uint64 start_range,
480 sc_dt::uint64 end_range) {
481 pci_bus_target_socket_->invalidate_direct_mem_ptr(start_range,
487template <
unsigned int BUSWIDTH,
typename TYPES>
488void PciMappingInterconnect<BUSWIDTH, TYPES>::castToTarget(
489 sc_core::sc_object *
object, supported_target_socket_t *target) {
490 tlm::tlm_target_socket<BUSWIDTH, TYPES> *tlm_target
491 =
dynamic_cast<tlm::tlm_target_socket<BUSWIDTH, TYPES> *
>(object);
493 target->tlm = tlm_target;
497 tlm_utils::multi_target_base<BUSWIDTH, TYPES> *multi_target
498 =
dynamic_cast<tlm_utils::multi_target_base<BUSWIDTH, TYPES> *
>(object);
500 target->multi = multi_target;
504 SC_REPORT_ERROR(PCI_MAPPING_INTERCONNECT_TAG,
505 "Unable to dynamic-cast PCI target socket");
508template <
unsigned int BUSWIDTH,
typename TYPES>
509template <
typename TGasket>
510void PciMappingInterconnect<BUSWIDTH, TYPES>::bindToGasket(
511 supported_target_socket_t target,
512 TGasket *gasket, ConfObjectRef o,
int id) {
514 gasket->addGasket(
id, simics2tlm::createGasket(target.tlm, o));
515 }
else if (target.multi) {
517 gasket->addGasket(
id, simics2tlm::createGasket(target.multi, o));
529template <
unsigned int BUSWIDTH,
typename TYPES>
530void PciMappingInterconnect<BUSWIDTH, TYPES>::updateCommand(
531 int id, uint16_t old_command) {
532 int command = function_data_[id].command;
533 if (command == old_command) {
536 int function = function_data_[id].function;
537 bool mem_enable = (command >> 1) & 1;
538 bool io_enable = command & 1;
540 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
541 = bar_info_.begin(); it != bar_info_.end(); ++it) {
542 if ((*it).function == function) {
544 = (*it).is_memory ? mem_enable : io_enable;
548 int bar = ((*it).offset - 0x10) / 4;
549 uint64_t base_address = function_data_[id].base_address[bar];
550 if ((*it).is_64bit) {
551 base_address |=
static_cast<uint64_t
>(
552 function_data_[id].base_address[bar + 1]) << 32;
554 updateMemoryMapping(enable, space, base_address,
556 (*it).mapping_id + mapping_id_offset_);
569template <
unsigned int BUSWIDTH,
typename TYPES>
570void PciMappingInterconnect<BUSWIDTH, TYPES>::updateBaseAddress(
int id,
572 int command = function_data_[id].command;
573 int function = function_data_[id].function;
574 bool mem_enable = (command >> 1) & 1;
575 bool io_enable = command & 1;
576 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
577 = bar_info_.begin(); it != bar_info_.end(); ++it) {
578 if ((*it).function == function && (*it).offset == 0x10 + 4 * bar) {
579 bool enable = (*it).is_memory ? mem_enable : io_enable;
587 uint64_t base_address = function_data_[id].base_address[bar];
588 if ((*it).is_64bit) {
589 base_address |=
static_cast<uint64_t
>(
590 function_data_[id].base_address[bar + 1]) << 32;
592 updateMemoryMapping(enable, space, base_address,
594 (*it).mapping_id + mapping_id_offset_);
600template <
unsigned int BUSWIDTH,
typename TYPES>
601void PciMappingInterconnect<BUSWIDTH, TYPES>::updateMemoryMapping(
604 uint64_t base_address,
607 extension_.remove_map(space, mapping_id);
608 if (sender_.failed_transaction_.payload()) {
609 SC_REPORT_INFO(PCI_MAPPING_INTERCONNECT_TAG,
"Failure to unmap device");
614 types::map_info_t info(base_address & ~((1ULL << bar_size_bits) - 1),
615 0, 1ULL << bar_size_bits,
617 extension_.add_map(space, info);
619 if (sender_.failed_transaction_.payload()) {
620 SC_REPORT_INFO(PCI_MAPPING_INTERCONNECT_TAG,
621 "Failure to map device");
627template <
unsigned int BUSWIDTH,
typename TYPES>
628void PciMappingInterconnect<BUSWIDTH, TYPES>::interceptBarAccess(
630 tlm::tlm_generic_payload &trans,
631 sc_core::sc_time &t) {
633 sc_dt::uint64 offset = trans.get_address();
634 unsigned int size = trans.get_data_length();
635 uint64_t *data =
reinterpret_cast<uint64_t *
>(trans.get_data_ptr());
638 if (trans.get_byte_enable_ptr()) {
641 if (trans.get_streaming_width() != size) {
648 if (trans.is_write()) {
649 uint16_t old_command = function_data_[id].command;
653 retrieveFunctionData(
id, -1);
654 function_data_[id].command = (*data) & 0xffff;
655 updateCommand(
id, old_command);
664 int bar = (offset - 0x10) / 4;
665 retrieveFunctionData(
id, bar);
672 function_data_[id].base_address[bar] = *data & 0xffffffff;
673 if (size == 8 && !(offset % 8)) {
674 function_data_[id].base_address[bar + 1] = *data >> 32;
676 updateBaseAddress(
id, bar);
std::vector< std::pair< BaseAddressRegister, sc_core::sc_object * > > BarSockets
IO/Memory space target socket(s).
Definition: pci_device_query_interface.h:106
@ Log_Configuration
Definition: adapter_log_groups.h:25
addr_space_t
Stand-alone, version of the Simics addr_space_t enum.
Definition: addr_space.h:23
@ Sim_Addr_Space_Memory
Definition: addr_space.h:26
@ Sim_Addr_Space_IO
Definition: addr_space.h:25