diff --git a/devices/common/pci/pcidevice.cpp b/devices/common/pci/pcidevice.cpp index 615487c..016f891 100644 --- a/devices/common/pci/pcidevice.cpp +++ b/devices/common/pci/pcidevice.cpp @@ -100,11 +100,7 @@ void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails & case PCI_CFG_BAR3: case PCI_CFG_BAR4: case PCI_CFG_BAR5: - if (value == 0xFFFFFFFFUL) { - this->do_bar_sizing((reg_offs - 0x10) >> 2); - } else { - this->set_bar_value((reg_offs - 0x10) >> 2, value); - } + this->set_bar_value((reg_offs - 0x10) >> 2, value); break; case PCI_CFG_ROM_BAR: if ((value & this->exp_bar_cfg) == this->exp_bar_cfg) { @@ -207,23 +203,75 @@ int PCIDevice::attach_exp_rom_image(const std::string img_path) void PCIDevice::do_bar_sizing(int bar_num) { - this->bars[bar_num] = this->bars_cfg[bar_num]; } void PCIDevice::set_bar_value(int bar_num, uint32_t value) { uint32_t bar_cfg = this->bars_cfg[bar_num]; - if (bar_cfg & 1) { - this->bars[bar_num] = (value & 0xFFFFFFFCUL) | (bar_cfg & 3); - } else { - if (bar_cfg & 6) { - ABORT_F("Invalid or unsupported PCI space type: %d", (bar_cfg >> 1) & 3); - } - this->bars[bar_num] = (value & 0xFFFFFFF0UL) | (bar_cfg & 0xF); + switch (bars_typ[bar_num]) { + case BAR_Unused: + return; + + case BAR_IO_16Bit: + case BAR_IO_32Bit: + this->bars[bar_num] = (value & bar_cfg & ~3) | (bar_cfg & 3); + break; + + case BAR_MEM_20Bit: + case BAR_MEM_32Bit: + case BAR_MEM_64Bit: + this->bars[bar_num] = (value & bar_cfg & ~0xF) | (bar_cfg & 0xF); + break; + + case BAR_MEM_64BitHi: + this->bars[bar_num] = (value & bar_cfg); + break; } + + if (value == 0xFFFFFFFFUL) { + do_bar_sizing(bar_num); + return; + } + this->pci_notify_bar_change(bar_num); } +void PCIDevice::finish_config_bars() +{ + for (int bar_num = 0; bar_num < 6; bar_num++) { + uint32_t bar_cfg = this->bars_cfg[bar_num]; + if (bar_cfg & 1) { + bars_typ[bar_num] = (bar_cfg & 0xffff0000) ? BAR_IO_32Bit : BAR_IO_16Bit; + } + else if (bar_cfg != 0) { + int pci_space_type = (bar_cfg >> 1) & 3; + switch (pci_space_type) { + case 0: + bars_typ[bar_num] = BAR_MEM_32Bit; + break; + case 1: + bars_typ[bar_num] = BAR_MEM_20Bit; + break; + case 2: + if (bar_num > 4) { + ABORT_F("%s: BAR %d cannot be 64-bit", this->pci_name.c_str(), bar_num); + } + else if (this->bars_cfg[bar_num+1] == 0) { + ABORT_F("%s: 64-bit BAR %d has zero for upper 32 bits", this->pci_name.c_str(), bar_num); + } + else { + bars_typ[bar_num++] = BAR_MEM_64Bit; + bars_typ[bar_num] = BAR_MEM_64BitHi; + } + break; + case 3: + ABORT_F("%s: invalid or unsupported PCI space type %d for BAR %d", this->pci_name.c_str(), pci_space_type, bar_num); + break; + } // switch pci_space_type + } // if BAR_MEM + } // for bar_num +} + void PCIDevice::map_exp_rom_mem() { uint32_t rom_addr, rom_size; diff --git a/devices/common/pci/pcidevice.h b/devices/common/pci/pcidevice.h index 147a59c..c215ea2 100644 --- a/devices/common/pci/pcidevice.h +++ b/devices/common/pci/pcidevice.h @@ -58,6 +58,16 @@ enum { PCI_VENDOR_NVIDIA = 0x10DE, }; +/** PCI BAR types */ +enum PCIBarType { + BAR_Unused, + BAR_IO_16Bit, + BAR_IO_32Bit, + BAR_MEM_20Bit, // < 1M + BAR_MEM_32Bit, + BAR_MEM_64Bit, + BAR_MEM_64BitHi, +}; class PCIDevice : public MMIODevice { public: @@ -108,6 +118,7 @@ public: protected: void do_bar_sizing(int bar_num); void set_bar_value(int bar_num, uint32_t value); + void finish_config_bars(); void map_exp_rom_mem(); std::string pci_name; // human-readable device name @@ -132,6 +143,7 @@ protected: uint32_t bars[6] = { 0 }; // base address registers uint32_t bars_cfg[6] = { 0 }; // configuration values for base address registers + PCIBarType bars_typ[6] = { BAR_Unused }; // types for base address registers uint32_t exp_bar_cfg = 0; // expansion ROM configuration uint32_t exp_rom_bar = 0; // expansion ROM base address register diff --git a/devices/ioctrl/grandcentral.cpp b/devices/ioctrl/grandcentral.cpp index 56309d8..18fc5f2 100644 --- a/devices/ioctrl/grandcentral.cpp +++ b/devices/ioctrl/grandcentral.cpp @@ -43,6 +43,7 @@ GrandCentral::GrandCentral() : PCIDevice("mac-io/grandcentral"), InterruptCtrl() this->class_rev = 0xFF000002; this->cache_ln_sz = 8; this->bars_cfg[0] = 0xFFFE0000UL; // declare 128Kb of memory-mapped I/O space + this->finish_config_bars(); this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num); diff --git a/devices/ioctrl/heathrow.cpp b/devices/ioctrl/heathrow.cpp index 782af0d..9331fb0 100644 --- a/devices/ioctrl/heathrow.cpp +++ b/devices/ioctrl/heathrow.cpp @@ -55,6 +55,7 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow"), InterruptCtrl() this->cache_ln_sz = 8; this->lat_timer = 0x40; this->bars_cfg[0] = 0xFFF80000UL; // declare 512Kb of memory-mapped I/O space + this->finish_config_bars(); this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num); diff --git a/devices/ioctrl/ohare.cpp b/devices/ioctrl/ohare.cpp index 4cf8df6..50b1d03 100644 --- a/devices/ioctrl/ohare.cpp +++ b/devices/ioctrl/ohare.cpp @@ -37,6 +37,7 @@ OHare::OHare() : PCIDevice("mac-io/ohare"), InterruptCtrl() this->class_rev = 0xFF000001; this->cache_ln_sz = 8; this->bars_cfg[0] = 0xFFF80000UL; // declare 512Kb of memory-mapped I/O space + this->finish_config_bars(); this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num); diff --git a/devices/video/atimach64gx.cpp b/devices/video/atimach64gx.cpp index b903fcc..fa975f2 100644 --- a/devices/video/atimach64gx.cpp +++ b/devices/video/atimach64gx.cpp @@ -45,6 +45,7 @@ AtiMach64Gx::AtiMach64Gx() this->device_id = ATI_MACH64_GX_DEV_ID; this->class_rev = (0x030000 << 8) | 3; this->bars_cfg[0] = 0xFF000000UL; // declare main aperture (16MB) + this->finish_config_bars(); this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num); diff --git a/devices/video/atirage.cpp b/devices/video/atirage.cpp index c88bd64..f24c2c9 100644 --- a/devices/video/atirage.cpp +++ b/devices/video/atirage.cpp @@ -127,6 +127,7 @@ ATIRage::ATIRage(uint16_t dev_id) this->bars_cfg[0] = 0xFF000000UL; // declare main aperture (16MB) this->bars_cfg[1] = 0xFFFFFF01UL; // declare I/O region (256 bytes) this->bars_cfg[2] = 0xFFFFF000UL; // declare register aperture (4KB) + this->finish_config_bars(); this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num); diff --git a/devices/video/control.cpp b/devices/video/control.cpp index cfbcedc..30d26cd 100644 --- a/devices/video/control.cpp +++ b/devices/video/control.cpp @@ -62,6 +62,7 @@ ControlVideo::ControlVideo() this->bars_cfg[0] = 0xFFFFFFFFUL; // I/O region (4 bytes but it's weird because bit 1 is set) this->bars_cfg[1] = 0xFFFFF000UL; // base address for the HW registers (4KB) this->bars_cfg[2] = 0xFC000000UL; // base address for the VRAM (64MB) + this->finish_config_bars(); this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num);