| // Copyright 2019 The Fuchsia Authors |
| // |
| // Use of this source code is governed by a MIT-style |
| // license that can be found in the LICENSE file or at |
| // https://opensource.org/licenses/MIT |
| |
| #ifndef ZIRCON_SYSTEM_DEV_BUS_PCI_TEST_FAKE_PCIROOT_H_ |
| #define ZIRCON_SYSTEM_DEV_BUS_PCI_TEST_FAKE_PCIROOT_H_ |
| |
| #include "fake_ecam.h" |
| #include <ddktl/protocol/pciroot.h> |
| #include <lib/fake_ddk/fake_ddk.h> |
| |
| // This FakePciroot class for the moment is a stub and test files |
| // will specialize the methods they need. Eventually when more tests |
| // are sorted out it may make sense to have pciroot tests be similar |
| // to the mock-i2c style fakes. |
| class FakePciroot : public ddk::PcirootProtocol<FakePciroot> { |
| public: |
| // By default, pciroot won't populate an ecam unless it's called with Create(). |
| static zx_status_t Create(uint8_t bus_start, uint8_t bus_end, std::unique_ptr<FakePciroot>* out) { |
| std::optional<FakeEcam> ecam; |
| zx_status_t st = FakeEcam::Create(bus_start, bus_end, &ecam); |
| if (st != ZX_OK) { |
| return st; |
| } |
| |
| *out = std::unique_ptr<FakePciroot>(new FakePciroot(bus_start, bus_end, std::move(*ecam))); |
| return ZX_OK; |
| } |
| |
| // Allow move. |
| FakePciroot(FakePciroot&&) = default; |
| FakePciroot& operator=(FakePciroot&&) = default; |
| // Disallow copy. |
| FakePciroot(const FakePciroot&) = delete; |
| FakePciroot& operator=(const FakePciroot&) = delete; |
| |
| const pciroot_protocol_t* proto() const { return &proto_; } |
| uint8_t bus_start() { return bus_start_; } |
| uint8_t bus_end() { return bus_end_; } |
| int32_t allocation_cnt() { return allocation_cnt_; } |
| FakeEcam& ecam() { return ecam_; } |
| |
| // Protocol methods. |
| zx_status_t PcirootGetAuxdata(const char* args, void* out_data, size_t data_size, |
| size_t* out_data_actual) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| zx_status_t PcirootGetBti(uint32_t bdf, uint32_t index, zx::bti* bti) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| zx_status_t PcirootConnectSysmem(zx::handle handle) { return ZX_ERR_NOT_SUPPORTED; } |
| zx_status_t PcirootGetPciPlatformInfo(pci_platform_info_t* info) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| zx_status_t PcirootGetPciIrqInfo(pci_irq_info_t* info) { return ZX_ERR_NOT_SUPPORTED; } |
| bool PcirootDriverShouldProxyConfig(void) { return false; } |
| zx_status_t PcirootConfigRead8(const pci_bdf_t* address, uint16_t offset, |
| uint8_t* value) { |
| if (address->bus_id < bus_start_ || address->bus_id > bus_end_) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| |
| memcpy(value, &ecam_.get(*address).ext_config[offset], sizeof(*value)); |
| return ZX_OK; |
| } |
| zx_status_t PcirootConfigRead16(const pci_bdf_t* address, uint16_t offset, |
| uint16_t* value) { |
| if (address->bus_id < bus_start_ || address->bus_id > bus_end_) { |
| printf("bus_start_ %u bus_end_ %u bus addr %u\n", bus_start_, bus_end_, address->bus_id); |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| |
| memcpy(value, &ecam_.get(*address).ext_config[offset], sizeof(*value)); |
| return ZX_OK; |
| } |
| zx_status_t PcirootConfigRead32(const pci_bdf_t* address, uint16_t offset, |
| uint32_t* value) { |
| if (address->bus_id < bus_start_ || address->bus_id > bus_end_) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| |
| memcpy(value, &ecam_.get(*address).ext_config[offset], sizeof(*value)); |
| return ZX_OK; |
| } |
| zx_status_t PcirootConfigWrite8(const pci_bdf_t* address, uint16_t offset, |
| uint8_t value) { |
| if (address->bus_id < bus_start_ || address->bus_id > bus_end_) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| memcpy(&ecam_.get(*address).ext_config[offset], &value, sizeof(value)); |
| return ZX_OK; |
| } |
| zx_status_t PcirootConfigWrite16(const pci_bdf_t* address, uint16_t offset, |
| uint16_t value) { |
| if (address->bus_id < bus_start_ || address->bus_id > bus_end_) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| memcpy(&ecam_.get(*address).ext_config[offset], &value, sizeof(value)); |
| return ZX_OK; |
| } |
| zx_status_t PcirootConfigWrite32(const pci_bdf_t* address, uint16_t offset, |
| uint32_t value) { |
| if (address->bus_id < bus_start_ || address->bus_id > bus_end_) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| memcpy(&ecam_.get(*address).ext_config[offset], &value, sizeof(value)); |
| return ZX_OK; |
| } |
| zx_status_t PcirootAllocMsiBlock(uint64_t requested_irqs, bool can_target_64bit, |
| msi_block_t* out_block) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| zx_status_t PcirootFreeMsiBlock(const msi_block_t* block) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| zx_status_t PcirootMaskUnmaskMsi(uint64_t msi_id, bool mask) { |
| return ZX_ERR_NOT_SUPPORTED; |
| } |
| zx_status_t PcirootGetAddressSpace(zx_paddr_t in_base, size_t len, |
| pci_address_space_t type, bool low, |
| uint64_t* out_base, zx::resource* resource) { |
| allocation_cnt_++; |
| return ZX_OK; |
| } |
| zx_status_t PcirootFreeAddressSpace(uint64_t base, size_t len, |
| pci_address_space_t type) { |
| allocation_cnt_--; |
| return ZX_OK; |
| } |
| |
| private: |
| FakePciroot(uint8_t bus_start, uint8_t bus_end, FakeEcam&& ecam) |
| : bus_start_(bus_start), bus_end_(bus_end), proto_({&pciroot_protocol_ops_, this}), |
| ecam_(std::move(ecam)) {} |
| |
| uint8_t bus_start_ = 0; |
| uint8_t bus_end_ = 0; |
| pciroot_protocol_t proto_; |
| FakeEcam ecam_; |
| int32_t allocation_cnt_ = 0; |
| }; |
| |
| #endif // ZIRCON_SYSTEM_DEV_BUS_PCI_TEST_FAKE_PCIROOT_H_ |