tools/pci: refactor PCI bridge
Use polymorphism to handle the differences between Aspeed and Nuvoton
PCI devices.
Add unit tests (now at 100% line coverage for tools/pci.cpp).
Signed-off-by: Benjamin Fair <benjaminfair@google.com>
Change-Id: I43e63ec5eb9fce5fb0fc74e0e69667dd13b7433f
diff --git a/tools/pci.hpp b/tools/pci.hpp
index f421892..7f0cfb7 100644
--- a/tools/pci.hpp
+++ b/tools/pci.hpp
@@ -1,19 +1,30 @@
+/*
+ * Copyright 2020 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#pragma once
+#include "data.hpp"
#include "internal/sys.hpp"
-
-extern "C"
-{
-#include <pciaccess.h>
-} // extern "C"
+#include "pciaccess.hpp"
#include <linux/pci_regs.h>
-#include <cstdint>
-#include <memory>
-#include <optional>
-#include <vector>
+#include <stdplus/types.hpp>
+// Some versions of the linux/pci_regs.h header don't define this
#ifndef PCI_STD_NUM_BARS
#define PCI_STD_NUM_BARS 6
#endif // !PCI_STD_NUM_BARS
@@ -21,76 +32,113 @@
namespace host_tool
{
-/* The ASPEED AST2400 & AST2500 have the same VIDDID. */
-
-/**
- * The PciDevice structure is a copy of the information to uniquely identify a
- * PCI device.
- */
-struct PciDevice
-{
- std::uint16_t vid;
- std::uint16_t did;
- std::uint8_t bus;
- std::uint8_t dev;
- std::uint8_t func;
- pciaddr_t bars[PCI_STD_NUM_BARS];
-};
-
-/**
- * The PciFilter structure is a simple mechanism for filtering devices by their
- * vendor and/or device ids.
- */
-struct PciFilter
-{
- std::uint16_t vid;
- std::uint16_t did;
-};
-
-class PciUtilInterface
+class PciBridgeIntf
{
public:
- virtual ~PciUtilInterface() = default;
+ virtual ~PciBridgeIntf() = default;
- /**
- * Get a list of PCI devices from a system.
- *
- * @param[in] filter - optional filter for the list.
- * @return the list of devices.
- */
- virtual std::vector<PciDevice>
- getPciDevices(std::optional<PciFilter> filter = std::nullopt) = 0;
+ virtual void write(const stdplus::span<const std::uint8_t> data) = 0;
+ virtual void configure(const ipmi_flash::PciConfigResponse& config) = 0;
+
+ virtual std::size_t getDataLength() = 0;
};
-class PciUtilImpl : public PciUtilInterface
+class PciAccessBridge : public PciBridgeIntf
{
public:
- static PciUtilImpl& getInstance()
+ virtual ~PciAccessBridge();
+
+ virtual void write(const stdplus::span<const std::uint8_t> data) override;
+ virtual void
+ configure(const ipmi_flash::PciConfigResponse& configResp) override{};
+
+ std::size_t getDataLength() override
{
- static PciUtilImpl instance;
- return instance;
+ return dataLength;
}
- std::vector<PciDevice>
- getPciDevices(std::optional<PciFilter> filter = std::nullopt) override;
+ protected:
+ /**
+ * Finds the PCI device matching @a match and saves a reference to it in @a
+ * dev. Also maps the memory region described in BAR number @a bar to
+ * address @a addr,
+ */
+ PciAccessBridge(const struct pci_id_match* match, int bar,
+ std::size_t dataOffset, std::size_t dataLength,
+ const PciAccess* pci);
- PciUtilImpl(const PciUtilImpl&) = delete;
- PciUtilImpl& operator=(const PciUtilImpl&) = delete;
+ struct pci_device* dev = nullptr;
+ std::uint8_t* addr = nullptr;
+ std::size_t size = 0;
private:
- PciUtilImpl()
+ std::size_t dataOffset;
+ std::size_t dataLength;
+
+ protected:
+ const PciAccess* pci;
+};
+
+class NuvotonPciBridge : public PciAccessBridge
+{
+ public:
+ explicit NuvotonPciBridge(const PciAccess* pci) :
+ PciAccessBridge(&match, bar, dataOffset, dataLength, pci)
+ {}
+
+ ~NuvotonPciBridge()
+ {}
+
+ private:
+ static constexpr std::uint32_t vid = 0x1050;
+ static constexpr std::uint32_t did = 0x0750;
+ static constexpr int bar = 0;
+ static constexpr struct pci_id_match match
{
- int ret = pci_system_init();
- if (ret)
- {
- throw internal::errnoException("pci_system_init");
- }
+ vid, did, PCI_MATCH_ANY, PCI_MATCH_ANY
+ };
+
+ static constexpr pciaddr_t bridge = 0x04;
+ static constexpr std::uint8_t bridgeEnabled = 0x02;
+
+ static constexpr std::size_t dataOffset = 0x0;
+ static constexpr std::size_t dataLength = 0x4000;
+};
+
+class AspeedPciBridge : public PciAccessBridge
+{
+ public:
+ explicit AspeedPciBridge(const PciAccess* pci) :
+ PciAccessBridge(&match, bar, dataOffset, dataLength, pci)
+ {
+ enableBridge();
}
- ~PciUtilImpl()
+ ~AspeedPciBridge()
{
- pci_system_cleanup();
+ disableBridge();
}
+
+ void configure(const ipmi_flash::PciConfigResponse& configResp) override;
+
+ private:
+ static constexpr std::uint32_t vid = 0x1a03;
+ static constexpr std::uint32_t did = 0x2000;
+ static constexpr int bar = 1;
+ static constexpr struct pci_id_match match
+ {
+ vid, did, PCI_MATCH_ANY, PCI_MATCH_ANY
+ };
+
+ static constexpr std::size_t config = 0x0f000;
+ static constexpr std::size_t bridge = 0x0f004;
+ static constexpr std::uint32_t bridgeEnabled = 0x1;
+
+ static constexpr std::size_t dataOffset = 0x10000;
+ static constexpr std::size_t dataLength = 0x10000;
+
+ void enableBridge();
+ void disableBridge();
};
} // namespace host_tool