Add 64-bit BAR support.

While dingusppc only emulates 32-bit Macs (for now), it is possible for a 32-bit Power Mac to use a PCIe card that has 64-bit BARs.

finish_config_bars is added to scan the cfg values of the BARs and determine their type. The type is stored separately so that it does not need to be determined again.
The type can be I/O (16 or 32 bit) or Mem (20 or 32 or 64 bit). A 64 bit bar is two BARs, the second contains the most significant 32 bits.

set_bar_value uses the stored type instead of trying to determine the type itself. It is always called even when the firmware is doing sizing. For sizing, It does the job of setting the bar value so do_bar_sizing is now just a stub.

Every PCIDevice that has a BAR needs to call finish_config_bars after setting up the cfg values just as they need to setup the cfg values. Since they need to do both, maybe the cfg values should be arguments of finish_config_bars, then finish_config_bars() should be renamed config_bars().
This commit is contained in:
joevt 2022-12-11 13:37:14 -08:00
parent fba2ff4231
commit 2a64f547cc
8 changed files with 79 additions and 13 deletions

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);