SystemC Library API Reference Manual
Reference documentation for the Simics SystemC Library.
 
Loading...
Searching...
No Matches
pci_mapping_interconnect.h
Go to the documentation of this file.
1/* -*- mode: C++; c-file-style: "virtutech-c++" -*-
2
3 © 2015 Intel Corporation
4
5 This software and the related documents are Intel copyrighted materials, and
6 your use of them is governed by the express license under which they were
7 provided to you ("License"). Unless the License provides otherwise, you may
8 not use, modify, copy, publish, distribute, disclose or transmit this software
9 or the related documents without Intel's prior written permission.
10
11 This software and the related documents are provided as is, with no express or
12 implied warranties, other than those that are expressly stated in the License.
13*/
14
15#ifndef SIMICS_SYSTEMC_COMPOSITE_PCI_MAPPING_INTERCONNECT_H
16#define SIMICS_SYSTEMC_COMPOSITE_PCI_MAPPING_INTERCONNECT_H
17
18#if defined SIMICS_5_API || defined SIMICS_6_API
19
20#include <systemc>
21#include <tlm>
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>
25
32
37
38#include <vector>
39
40namespace { // NOLINT(build/namespaces)
41const char *const PCI_MAPPING_INTERCONNECT_TAG = "intel/PciMappingInterconnect";
42} // namespace
43
44namespace simics {
45namespace systemc {
46namespace composite {
47
50template<typename TSocket>
51class PciMappingInterconnectExtensionSender
52 : public iface::ExtensionSender<TSocket> {
53 public:
54 virtual ~PciMappingInterconnectExtensionSender() {}
55 virtual void send_extension(iface::Transaction *transaction) {
56 failed_transaction_ = iface::Transaction(NULL);
57 iface::ExtensionSender<TSocket>::send_extension(transaction);
58 }
59 virtual void send_failed(iface::Transaction *transaction) {
60 failed_transaction_ = *transaction;
61 iface::ExtensionSender<TSocket>::send_failed(transaction);
62 }
63 iface::Transaction failed_transaction_;
64};
65
84template <unsigned int BUSWIDTH, typename TYPES>
85class PciMappingInterconnect : public sc_core::sc_module {
86 private:
87 // Socket types used by the interconnect
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;
94 typedef struct {
95 tlm::tlm_target_socket<BUSWIDTH, TYPES> *tlm;
96 tlm_utils::multi_target_base<BUSWIDTH, TYPES> *multi;
97 } supported_target_socket_t;
98
99 public:
100 SC_HAS_PROCESS(PciMappingInterconnect);
101 explicit PciMappingInterconnect(
102 sc_core::sc_module_name = "PciMappingInterconnect")
103 : target_socket("target_socket"),
104 simics_target_socket("simics_target_socket"),
105 pci_bus_initiator_socket("pci_bus_initiator_socket"),
106 initiator_sockets_("initiator_socket"),
107 pci_target_socket_(),
108 pci_device_target_socket_(),
109 pci_bus_target_socket_("pci_bus_target_socket"),
110 number_of_functions_(1),
111 mapping_id_offset_(0x10100) { // 255 + 64k (max VFs) + 1 (round up)
112 target_socket.register_b_transport(
113 this, &PciMappingInterconnect::b_transport);
114 target_socket.register_transport_dbg(
115 this, &PciMappingInterconnect::transport_dbg);
116 simics_target_socket.register_b_transport(
117 this, &PciMappingInterconnect::simics_b_transport);
118 pci_bus_target_socket_.register_b_transport(
119 this, &PciMappingInterconnect::pci_bus_b_transport);
120 pci_bus_target_socket_.register_transport_dbg(
121 this, &PciMappingInterconnect::pci_bus_transport_dbg);
122 pci_bus_target_socket_.register_get_direct_mem_ptr(
123 this, &PciMappingInterconnect::pci_bus_get_direct_mem_ptr);
124 pci_bus_initiator_socket.register_invalidate_direct_mem_ptr(
125 this, &PciMappingInterconnect::pci_bus_invalidate_direct_mem_ptr);
126 sender_.init(&pci_bus_initiator_socket);
127 extension_.init(&sender_);
128 }
129
130 virtual void before_end_of_elaboration();
131
132 void retrieveFunctionData(int id, int bar);
133
134 void connect(iface::PciDeviceQueryInterface *pci, ConfObjectRef o);
135
136 void connectConfig(iface::BaseAddressRegisterQueryInterface *bar,
137 simics2tlm::IoMemory *gasket,
138 ConfObjectRef o);
139
140 void connectMmio(iface::BaseAddressRegisterQueryInterface *bar,
141 simics2tlm::IoMemory *gasket,
142 ConfObjectRef o);
143
144 void busReset();
145
146 // Sockets bound by external logic (see also private scope):
148 multi_target_socket_t target_socket;
149 multi_target_socket_t simics_target_socket;
151 initiator_socket_t pci_bus_initiator_socket;
152
153 private:
154 // TLM2 methods
155 void b_transport(int id, tlm::tlm_generic_payload &trans, // NOLINT: SystemC API
156 sc_core::sc_time &t); // NOLINT: SystemC API
157 unsigned int transport_dbg(int id, tlm::tlm_generic_payload &trans); // NOLINT: SystemC API
158 void simics_b_transport(int id, tlm::tlm_generic_payload &trans, // NOLINT: SystemC API
159 sc_core::sc_time &t); // NOLINT: SystemC API
160 void pci_bus_b_transport(tlm::tlm_generic_payload &trans, // NOLINT: SystemC API
161 sc_core::sc_time &t); // NOLINT: SystemC API
162 unsigned int pci_bus_transport_dbg(tlm::tlm_generic_payload &trans); // NOLINT: SystemC API
163 bool pci_bus_get_direct_mem_ptr(tlm::tlm_generic_payload &trans, // NOLINT: SystemC API
164 tlm::tlm_dmi &dmi_data); // NOLINT: SystemC API
165 void pci_bus_invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
166 sc_dt::uint64 end_range);
167
168 // Helper methods
169 void castToTarget(sc_core::sc_object *object,
170 supported_target_socket_t *target);
171 template <typename TGasket>
172 void bindToGasket(supported_target_socket_t target,
173 TGasket *gasket, ConfObjectRef o, int id);
174 void updateCommand(int id, uint16_t old_command);
175 void updateBaseAddress(int id, int bar);
176 void updateMemoryMapping(bool enable, types::addr_space_t space,
177 uint64_t base_address, int bar_size_bits,
178 int mapping_id);
179 void interceptBarAccess(int id, tlm::tlm_generic_payload &trans, // NOLINT
180 sc_core::sc_time &t); // NOLINT: SystemC API
181
182 // Sockets created and bound by internal logic (see also public scope):
183 // IC -> Device, forwards the incoming PCI transactions
184 sc_core::sc_vector<initiator_socket_t> initiator_sockets_;
185 supported_target_socket_t pci_target_socket_;
186 initiator_socket_t pci_device_initiator_socket_;
187 supported_target_socket_t pci_device_target_socket_;
188 // Device -> IC, intercept upstream pci-bus transactions
189 target_socket_t pci_bus_target_socket_;
190
191 struct function_data_t {
192 int function;
193 uint16_t command;
194 uint32_t base_address[6];
195 };
196 std::vector<function_data_t> function_data_;
197 int number_of_functions_;
198 int mapping_id_offset_;
199 iface::BaseAddressRegisterQueryInterface::BarInfo bar_info_;
200
201 PciMappingInterconnectExtensionSender<
202 initiator_socket_t> sender_;
203 iface::PciBusExtension extension_;
204};
205
206template <unsigned int BUSWIDTH, typename TYPES>
207void PciMappingInterconnect<BUSWIDTH, TYPES>::before_end_of_elaboration() {
208 // Because of the way SystemC has been designed, we cannot create new
209 // sockets dynamically ouside of the CTOR except for in the
210 // before_end_of_elaboration() method.
211
212 // Create initiator sockets equal to the number of PCI functions
213 initiator_sockets_.init(number_of_functions_);
214 for (std::size_t i = 0; i < initiator_sockets_.size(); ++i) {
215 if (pci_target_socket_.tlm) {
216 initiator_sockets_[i].bind(*pci_target_socket_.tlm);
217 } else {
218 initiator_sockets_[i].bind(*pci_target_socket_.multi);
219 }
220 }
221
222 // Allocate and initialize function data based on device configuration
223 function_data_ = std::vector<function_data_t>(number_of_functions_);
224 int prev_function = -1;
225 int id = -1;
226 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
227 = bar_info_.begin(); it != bar_info_.end(); ++it) {
228 int current_function = (*it).function;
229 if (current_function != prev_function) {
230 function_data_[++id].function = current_function;
231 prev_function = current_function;
232 }
233 }
234
235 if (pci_device_target_socket_.tlm) {
236 pci_device_initiator_socket_.bind(*pci_device_target_socket_.tlm);
237 } else if (pci_device_target_socket_.multi) {
238 pci_device_initiator_socket_.bind(*pci_device_target_socket_.multi);
239 }
240}
241
242// Get up-to-date BAR/CMD information whenever we need it. It cannot be cached
243// in the interconnect module as it might change over time by the model,
244// reverse execution, checkpoint restore, ...
245// @id is the function ID (socket ID) currently accessed
246// @bar is the BAR number currently access, or -1 for config register access in
247// which case all BARs must be retrieved
248template <unsigned int BUSWIDTH, typename TYPES>
249void PciMappingInterconnect<BUSWIDTH, TYPES>::retrieveFunctionData(
250 int id, int bar) {
251 tlm::tlm_generic_payload trans;
252 trans.set_command(tlm::TLM_READ_COMMAND);
253 trans.set_data_length(4);
254 trans.set_streaming_width(4);
255
256 uint32_t value = 0;
257 trans.set_data_ptr(reinterpret_cast<unsigned char *>(&value));
258 trans.set_address(0x4);
259 initiator_sockets_[id]->transport_dbg(trans);
260 function_data_[id].command = value;
261
262 // -1 means config register access => read all bars
263 bool all_bars = (bar == -1) ? true : false;
264
265 // NOTE: the IO, Mem32, Mem64 bits are ignored by updateMemoryMapping, no
266 // need to filter them out here
267 int function = function_data_[id].function;
268 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator
269 it = bar_info_.begin(); it != bar_info_.end(); ++it) {
270 // BarInfo holds _all_ BARs for _all_ functions. This can probably
271 // be done in a much more clever way that avoids iterating over the
272 // entire BarInfo for each function in the outer loop.
273 if ((*it).function != function) {
274 continue;
275 }
276 if (all_bars) {
277 bar = ((*it).offset - 0x10) / 4;
278 } else if (bar != ((*it).offset - 0x10) / 4) {
279 continue;
280 }
281 uint32_t base_address = 0;
282 trans.set_address((*it).offset);
283 trans.set_data_ptr(
284 reinterpret_cast<unsigned char *>(&base_address));
285 trans.set_data_length(sizeof base_address);
286 trans.set_streaming_width(trans.get_data_length());
287 initiator_sockets_[id]->transport_dbg(trans);
288 function_data_[id].base_address[bar] = base_address;
289 if ((*it).is_64bit) {
290 // Read higher 32 bits in next BAR
291 trans.set_address((*it).offset + 4);
292 trans.set_data_ptr(
293 reinterpret_cast<unsigned char *>(&base_address));
294 trans.set_data_length(sizeof base_address);
295 trans.set_streaming_width(trans.get_data_length());
296 initiator_sockets_[id]->transport_dbg(trans);
297 function_data_[id].base_address[bar + 1] = base_address;
298 }
299 }
300}
301
310template <unsigned int BUSWIDTH, typename TYPES>
311void PciMappingInterconnect<BUSWIDTH, TYPES>::connect(
312 iface::PciDeviceQueryInterface *pci, ConfObjectRef o) {
313 castToTarget(pci->getPciDeviceTargetSocket(),
314 &pci_device_target_socket_);
315 castToTarget(pci->getConfigTargetSocket(), &pci_target_socket_);
316 tlm::tlm_initiator_socket<BUSWIDTH, TYPES> *initiator
317 = dynamic_cast<tlm::tlm_initiator_socket<BUSWIDTH, TYPES> *>(
318 pci->getPciBusInitiatorSocket());
319 if (initiator) {
320 pci_bus_target_socket_.bind(*initiator);
321 } else {
322 SIM_LOG_ERROR(o, Log_Configuration,
323 "object returned by getPciBusInitiatorSocket was not"
324 " a tlm::tlm_initiator_socket.");
325 }
326}
327
334template <unsigned int BUSWIDTH, typename TYPES>
335void PciMappingInterconnect<BUSWIDTH, TYPES>::connectConfig(
336 iface::BaseAddressRegisterQueryInterface *bar,
337 simics2tlm::IoMemory *gasket, ConfObjectRef o) {
338 // F0 must always exist
339 // NOTE: by Simics convention, F0 always get mapping ID = 255
340 gasket->addGasket(
341 255, simics2tlm::createGasket(&target_socket, o));
342
343 // How many more functions are there?
344 bar_info_ = bar->getBarInfo();
345 int prev_function = 0;
346 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
347 = bar_info_.begin(); it != bar_info_.end(); ++it) {
348 int current_function = (*it).function;
349 if (current_function != prev_function) {
350 ++number_of_functions_;
351 prev_function = current_function;
352 gasket->addGasket(255 + current_function,
353 simics2tlm::createGasket(&target_socket, o));
354 }
355 FATAL_ERROR_IF(current_function < prev_function,
356 "BarInfo must be sorted on function number"
357 " in ascending order");
358 }
359}
360
366template <unsigned int BUSWIDTH, typename TYPES>
367void PciMappingInterconnect<BUSWIDTH, TYPES>::connectMmio(
368 iface::BaseAddressRegisterQueryInterface *bar,
369 simics2tlm::IoMemory *gasket, ConfObjectRef o) {
370 iface::BaseAddressRegisterQueryInterface::BarSockets bar_sockets
371 = bar->getBarTargetSockets();
372 iface::BaseAddressRegisterQueryInterface::BarSockets::const_iterator it;
373 for (iface::BaseAddressRegisterQueryInterface::BarSockets::const_iterator it
374 = bar_sockets.begin(); it != bar_sockets.end(); ++it) {
375 supported_target_socket_t target = {};
376 castToTarget((*it).second, &target);
377 bindToGasket(target, gasket, o,
378 (*it).first.mapping_id + mapping_id_offset_);
379 }
380}
381
383template <unsigned int BUSWIDTH, typename TYPES>
384void PciMappingInterconnect<BUSWIDTH, TYPES>::busReset() {
385 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
386 = bar_info_.begin(); it != bar_info_.end(); ++it) {
387 int mapping_id = (*it).mapping_id + mapping_id_offset_;
388 types::addr_space_t space = types::Sim_Addr_Space_IO;
389 if ((*it).is_memory) {
390 space = types::Sim_Addr_Space_Memory;
391 }
392 extension_.remove_map(space, mapping_id);
393 if (sender_.failed_transaction_.payload()) {
394 SC_REPORT_INFO(PCI_MAPPING_INTERCONNECT_TAG,
395 "Failure to unmap device on bus_reset");
396 }
397 }
398}
399
401
402/*
403 * Intercept the BAR and Command regs, always forward transaction to target to
404 * handle all errors there
405 */
406template <unsigned int BUSWIDTH, typename TYPES>
407void PciMappingInterconnect<BUSWIDTH, TYPES>::b_transport(
408 int id,
409 tlm::tlm_generic_payload &trans, // NOLINT
410 sc_core::sc_time &t) { // NOLINT
411 interceptBarAccess(id, trans, t);
412 initiator_sockets_[id]->b_transport(trans, t);
413}
414
415/*
416 * transport_dbg is side-effect free = forwarded without inspection
417 */
418template <unsigned int BUSWIDTH, typename TYPES>
419unsigned int PciMappingInterconnect<BUSWIDTH, TYPES>::transport_dbg(
420 int id,
421 tlm::tlm_generic_payload &trans) { // NOLINT
422 return initiator_sockets_[id]->transport_dbg(trans);
423}
424
425/*
426 * For pci-device, just relay the incoming transaction to outgoing socket
427 */
428template <unsigned int BUSWIDTH, typename TYPES>
429void PciMappingInterconnect<BUSWIDTH, TYPES>::simics_b_transport(
430 int id, tlm::tlm_generic_payload &trans, // NOLINT
431 sc_core::sc_time &t) { // NOLINT
432 pci_device_initiator_socket_->b_transport(trans, t);
433}
434
435/*
436 * For pci-bus, just relay the incoming transaction to outgoing socket
437 */
438template <unsigned int BUSWIDTH, typename TYPES>
439void PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_b_transport(
440 tlm::tlm_generic_payload &trans, // NOLINT
441 sc_core::sc_time &t) { // NOLINT
442 pci_bus_initiator_socket->b_transport(trans, t);
443}
444
445/*
446 * For pci-bus, just relay the incoming transaction to outgoing socket
447 */
448template <unsigned int BUSWIDTH, typename TYPES>
449unsigned int PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_transport_dbg(
450 tlm::tlm_generic_payload &trans) { // NOLINT
451 return pci_bus_initiator_socket->transport_dbg(trans);
452}
453
454/*
455 * For pci-bus, just relay the incoming transaction to outgoing socket
456 */
457template <unsigned int BUSWIDTH, typename TYPES>
458bool PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_get_direct_mem_ptr(
459 tlm::tlm_generic_payload &trans, // NOLINT
460 tlm::tlm_dmi &dmi_data) { // NOLINT
461 return pci_bus_initiator_socket->get_direct_mem_ptr(trans, dmi_data);
462}
463
464/*
465 * For pci-bus, just relay the incoming BW transaction to target socket
466 */
467template <unsigned int BUSWIDTH, typename TYPES>
468void PciMappingInterconnect<BUSWIDTH, TYPES>::pci_bus_invalidate_direct_mem_ptr(
469 sc_dt::uint64 start_range,
470 sc_dt::uint64 end_range) {
471 pci_bus_target_socket_->invalidate_direct_mem_ptr(start_range,
472 end_range);
473}
474
475// Cast sc_object to a supported target socket and return it.
476// TPciDevice is the type of the PCI device,
477template <unsigned int BUSWIDTH, typename TYPES>
478void PciMappingInterconnect<BUSWIDTH, TYPES>::castToTarget(
479 sc_core::sc_object *object, supported_target_socket_t *target) {
480 tlm::tlm_target_socket<BUSWIDTH, TYPES> *tlm_target
481 = dynamic_cast<tlm::tlm_target_socket<BUSWIDTH, TYPES> *>(object);
482 if (tlm_target) {
483 target->tlm = tlm_target;
484 return;
485 }
486
487 tlm_utils::multi_target_base<BUSWIDTH, TYPES> *multi_target
488 = dynamic_cast<tlm_utils::multi_target_base<BUSWIDTH, TYPES> *>(object);
489 if (multi_target) {
490 target->multi = multi_target;
491 return;
492 }
493
494 SC_REPORT_ERROR(PCI_MAPPING_INTERCONNECT_TAG,
495 "Unable to dynamic-cast PCI target socket");
496}
497
498template <unsigned int BUSWIDTH, typename TYPES>
499template <typename TGasket>
500void PciMappingInterconnect<BUSWIDTH, TYPES>::bindToGasket(
501 supported_target_socket_t target,
502 TGasket *gasket, ConfObjectRef o, int id) {
503 if (target.tlm) {
504 gasket->addGasket(id, simics2tlm::createGasket(target.tlm, o));
505 } else if (target.multi) {
506 // coverity[var_deref_model], safe cast based on castToTarget() func
507 gasket->addGasket(id, simics2tlm::createGasket(target.multi, o));
508 }
509}
510
511/*
512 * When command register is written to, the mappings need to be re-evaluated
513 * and possibly updated.
514 *
515 * There is no error handling, so if the mapping fails this will only be logged
516 * but the access will still pass (i.e. transaction forwarded to target device
517 * where registers are updated without side-effects)
518 */
519template <unsigned int BUSWIDTH, typename TYPES>
520void PciMappingInterconnect<BUSWIDTH, TYPES>::updateCommand(
521 int id, uint16_t old_command) {
522 int command = function_data_[id].command;
523 if (command == old_command) {
524 return;
525 }
526 int function = function_data_[id].function;
527 bool mem_enable = (command >> 1) & 1;
528 bool io_enable = command & 1;
529
530 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
531 = bar_info_.begin(); it != bar_info_.end(); ++it) {
532 if ((*it).function == function) {
533 bool enable
534 = (*it).is_memory ? mem_enable : io_enable;
535 types::addr_space_t space
536 = (*it).is_memory ? types::Sim_Addr_Space_Memory
537 : types::Sim_Addr_Space_IO;
538 int bar = ((*it).offset - 0x10) / 4;
539 uint64_t base_address = function_data_[id].base_address[bar];
540 if ((*it).is_64bit) {
541 base_address |= static_cast<uint64_t>(
542 function_data_[id].base_address[bar + 1]) << 32;
543 }
544 updateMemoryMapping(enable, space, base_address,
545 (*it).size_bits,
546 (*it).mapping_id + mapping_id_offset_);
547 }
548 }
549}
550
551/*
552 * When BAR register is written to, the mapping need to be re-evaluated and
553 * possibly updated.
554 *
555 * There is no error handling, so if the mapping fails this will only be logged
556 * but the access will still pass (i.e. transaction forwarded to target device
557 * where registers are updated without side-effects)
558 */
559template <unsigned int BUSWIDTH, typename TYPES>
560void PciMappingInterconnect<BUSWIDTH, TYPES>::updateBaseAddress(int id,
561 int bar) {
562 int command = function_data_[id].command;
563 int function = function_data_[id].function;
564 bool mem_enable = (command >> 1) & 1;
565 bool io_enable = command & 1;
566 for (iface::BaseAddressRegisterQueryInterface::BarInfo::const_iterator it
567 = bar_info_.begin(); it != bar_info_.end(); ++it) {
568 if ((*it).function == function && (*it).offset == 0x10 + 4 * bar) {
569 bool enable = (*it).is_memory ? mem_enable : io_enable;
570 if (!enable) {
571 // no re-mapping will be done as encoding is not enabled
572 return;
573 }
574 types::addr_space_t space
575 = (*it).is_memory ? types::Sim_Addr_Space_Memory
576 : types::Sim_Addr_Space_IO;
577 uint64_t base_address = function_data_[id].base_address[bar];
578 if ((*it).is_64bit) {
579 base_address |= static_cast<uint64_t>(
580 function_data_[id].base_address[bar + 1]) << 32;
581 }
582 updateMemoryMapping(enable, space, base_address,
583 (*it).size_bits,
584 (*it).mapping_id + mapping_id_offset_);
585 break;
586 }
587 }
588}
589
590template <unsigned int BUSWIDTH, typename TYPES>
591void PciMappingInterconnect<BUSWIDTH, TYPES>::updateMemoryMapping(
592 bool enable,
593 types::addr_space_t space,
594 uint64_t base_address,
595 int bar_size_bits,
596 int mapping_id) {
597 extension_.remove_map(space, mapping_id);
598 if (sender_.failed_transaction_.payload()) {
599 SC_REPORT_INFO(PCI_MAPPING_INTERCONNECT_TAG, "Failure to unmap device");
600 return;
601 }
602
603 if (enable) {
604 types::map_info_t info(base_address & ~((1 << bar_size_bits) - 1),
605 0, 1 << bar_size_bits,
606 mapping_id);
607 extension_.add_map(space, info);
608
609 if (sender_.failed_transaction_.payload()) {
610 SC_REPORT_INFO(PCI_MAPPING_INTERCONNECT_TAG,
611 "Failure to map device");
612 return;
613 }
614 }
615}
616
617template <unsigned int BUSWIDTH, typename TYPES>
618void PciMappingInterconnect<BUSWIDTH, TYPES>::interceptBarAccess(
619 int id,
620 tlm::tlm_generic_payload &trans, // NOLINT
621 sc_core::sc_time &t) { // NOLINT
622 // Decode the generic payload (GP) struct
623 sc_dt::uint64 offset = trans.get_address();
624 unsigned int size = trans.get_data_length();
625 uint64_t *data = reinterpret_cast<uint64_t *>(trans.get_data_ptr());
626
627 // Check assumptions (but leave it up to target device to report errors)
628 if (trans.get_byte_enable_ptr()) {
629 return;
630 }
631 if (trans.get_streaming_width() != size) {
632 return;
633 }
634 // NOTE: we should also check that address is DWORD/4-byte aligned, but
635 // our Viper/X58 platform seems to address single bytes so ...
636
637 // We are only interested in write access to BARn or Command regs
638 if (trans.is_write()) {
639 uint16_t old_command = function_data_[id].command;
640
641 switch (offset) {
642 case 0x04: { // command & status
643 retrieveFunctionData(id, -1);
644 function_data_[id].command = (*data) & 0xffff; // ignore status
645 updateCommand(id, old_command);
646 break;
647 }
648 case 0x10: // BAR0-BAR5
649 case 0x14:
650 case 0x18:
651 case 0x1c:
652 case 0x20:
653 case 0x24:
654 int bar = (offset - 0x10) / 4;
655 retrieveFunctionData(id, bar);
656 // NOTE: the IO, Mem32, Mem64 bits are ignored by
657 // updateMemoryMapping, no need to filter them out here. In
658 // addition, any bits less than the size of the BAR as defined by
659 // the BarInfo will also be ignored/truncated by
660 // updateMemoryMapping; making sure we always send a naturally
661 // aligned address to Simics
662 function_data_[id].base_address[bar] = *data & 0xffffffff;
663 if (size == 8 && !(offset % 8)) {
664 function_data_[id].base_address[bar + 1] = *data >> 32;
665 }
666 updateBaseAddress(id, bar);
667 break;
668 }
669 }
670}
671
672} // namespace composite
673} // namespace systemc
674} // namespace simics
675
676#endif
677#endif
Definition: pci_bus_interface.h:24