From 6503a300ccbd8be0de762b9ee6f6b00b3b42eb60 Mon Sep 17 00:00:00 2001 From: joevt Date: Mon, 18 Sep 2023 17:24:50 -0700 Subject: [PATCH] Add PCI interrupt method. A PCI device passes an interrupt to its host. The host will determine from the PCI device which interrupt to trigger. --- devices/common/pci/bandit.h | 3 +++ devices/common/pci/pcibase.h | 7 ++++++- devices/common/pci/pcihost.h | 1 + devices/memctrl/mpc106.cpp | 37 ++++++++++++++++++++++++++++++++++++ devices/memctrl/mpc106.h | 14 +++++++++++++- 5 files changed, 60 insertions(+), 2 deletions(-) diff --git a/devices/common/pci/bandit.h b/devices/common/pci/bandit.h index 60e60f4..fa078f3 100644 --- a/devices/common/pci/bandit.h +++ b/devices/common/pci/bandit.h @@ -70,6 +70,9 @@ enum { */ class BanditHost : public PCIHost, public MMIODevice { public: + // PCIHost methods + virtual void pci_interrupt(uint8_t irq_line_state, PCIBase *dev) {} + // MMIODevice methods uint32_t read(uint32_t rgn_start, uint32_t offset, int size); void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size); diff --git a/devices/common/pci/pcibase.h b/devices/common/pci/pcibase.h index fa19ae7..420671a 100644 --- a/devices/common/pci/pcibase.h +++ b/devices/common/pci/pcibase.h @@ -115,15 +115,20 @@ public: virtual void set_host(PCIHost* host_instance) { this->host_instance = host_instance; - }; + } virtual void set_multi_function(bool is_multi_function) { this->hdr_type = is_multi_function ? (this->hdr_type | 0x80) : (this->hdr_type & 0x7f); } + virtual void set_irq_pin(uint8_t irq_pin) { this->irq_pin = irq_pin; } + virtual void pci_interrupt(uint8_t irq_line_state) { + this->host_instance->pci_interrupt(irq_line_state, this); + } + // MMIODevice methods virtual uint32_t read(uint32_t rgn_start, uint32_t offset, int size) { return 0; } virtual void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) { } diff --git a/devices/common/pci/pcihost.h b/devices/common/pci/pcihost.h index 56df770..0a354e6 100644 --- a/devices/common/pci/pcihost.h +++ b/devices/common/pci/pcihost.h @@ -77,6 +77,7 @@ public: virtual PCIBase *pci_find_device(uint8_t bus_num, uint8_t dev_num, uint8_t fun_num); + virtual void pci_interrupt(uint8_t irq_line_state, PCIBase *dev) {} protected: std::unordered_map dev_map; diff --git a/devices/memctrl/mpc106.cpp b/devices/memctrl/mpc106.cpp index b8b0759..ba6ce56 100644 --- a/devices/memctrl/mpc106.cpp +++ b/devices/memctrl/mpc106.cpp @@ -22,6 +22,7 @@ along with this program. If not, see . /** MPC106 (Grackle) emulation. */ #include +#include #include #include #include @@ -68,9 +69,45 @@ int MPC106::device_postinit() this->attach_pci_device(pci_dev_name, slot.second); } } + + this->int_ctrl = dynamic_cast( + gMachineObj->get_comp_by_type(HWCompType::INT_CTRL)); + this->irq_id_PCI_A = this->int_ctrl->register_dev_int(IntSrc::PCI_A ); + this->irq_id_PCI_B = this->int_ctrl->register_dev_int(IntSrc::PCI_B ); + this->irq_id_PCI_C = this->int_ctrl->register_dev_int(IntSrc::PCI_C ); + this->irq_id_PCI_GPU = this->int_ctrl->register_dev_int(IntSrc::PCI_GPU ); + this->irq_id_PCI_PERCH = this->int_ctrl->register_dev_int(IntSrc::PCI_PERCH); + return 0; } +void MPC106::pci_interrupt(uint8_t irq_line_state, PCIBase *dev) { + auto it = std::find_if(dev_map.begin(), dev_map.end(), + [&dev](const std::pair &p) { + return p.second == dev; + } + ); + + if (it == dev_map.end()) { + LOG_F(ERROR, "Interrupt from unknown device %s", dev->get_name().c_str()); + } + else { + uint32_t irq_id; + switch (it->first) { + case DEV_FUN(0x0C,0): irq_id = this->irq_id_PCI_PERCH; break; + case DEV_FUN(0x0D,0): irq_id = this->irq_id_PCI_A ; break; + case DEV_FUN(0x0E,0): irq_id = this->irq_id_PCI_B ; break; + case DEV_FUN(0x0F,0): irq_id = this->irq_id_PCI_C ; break; + case DEV_FUN(0x12,0): irq_id = this->irq_id_PCI_GPU ; break; + default: + LOG_F(ERROR, "Interrupt from device %s at unexpected device/function %02x.%x", dev->get_name().c_str(), it->first >> 3, it->first & 7); + return; + } + if (this->int_ctrl) + this->int_ctrl->ack_int(irq_id, irq_line_state); + } +} + uint32_t MPC106::read(uint32_t rgn_start, uint32_t offset, int size) { if (rgn_start == 0xFE000000) { return pci_io_read_broadcast(offset, size); diff --git a/devices/memctrl/mpc106.h b/devices/memctrl/mpc106.h index 05ab36d..9149133 100644 --- a/devices/memctrl/mpc106.h +++ b/devices/memctrl/mpc106.h @@ -36,11 +36,13 @@ along with this program. If not, see . #include #include -#include +#include #include #include +class InterruptCtrl; + /** Grackle configuration space registers. */ enum GrackleReg : uint32_t { CFG10 = 0x40, // bus # + subordinate bus # + disconnect counter @@ -79,6 +81,8 @@ public: uint32_t read(uint32_t rgn_start, uint32_t offset, int size); void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size); + virtual void pci_interrupt(uint8_t irq_line_state, PCIBase *dev); + int device_postinit(); protected: @@ -110,6 +114,14 @@ private: uint32_t mem_end[2] = {}; uint32_t ext_mem_end[2] = {}; uint8_t mem_bank_en = 0; + + // interrupt related stuff + InterruptCtrl* int_ctrl = nullptr; + uint32_t irq_id_PCI_A = 0; + uint32_t irq_id_PCI_B = 0; + uint32_t irq_id_PCI_C = 0; + uint32_t irq_id_PCI_GPU = 0; + uint32_t irq_id_PCI_PERCH = 0; }; #endif // MPC106_H