diff options
Diffstat (limited to 'qemu/hw/alpha/typhoon.c')
-rw-r--r-- | qemu/hw/alpha/typhoon.c | 959 |
1 files changed, 0 insertions, 959 deletions
diff --git a/qemu/hw/alpha/typhoon.c b/qemu/hw/alpha/typhoon.c deleted file mode 100644 index 97721b535..000000000 --- a/qemu/hw/alpha/typhoon.c +++ /dev/null @@ -1,959 +0,0 @@ -/* - * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation. - * - * Written by Richard Henderson. - * - * This work is licensed under the GNU GPL license version 2 or later. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "cpu.h" -#include "hw/hw.h" -#include "hw/devices.h" -#include "sysemu/sysemu.h" -#include "alpha_sys.h" -#include "exec/address-spaces.h" - - -#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost" - -typedef struct TyphoonCchip { - MemoryRegion region; - uint64_t misc; - uint64_t drir; - uint64_t dim[4]; - uint32_t iic[4]; - AlphaCPU *cpu[4]; -} TyphoonCchip; - -typedef struct TyphoonWindow { - uint64_t wba; - uint64_t wsm; - uint64_t tba; -} TyphoonWindow; - -typedef struct TyphoonPchip { - MemoryRegion region; - MemoryRegion reg_iack; - MemoryRegion reg_mem; - MemoryRegion reg_io; - MemoryRegion reg_conf; - - AddressSpace iommu_as; - MemoryRegion iommu; - - uint64_t ctl; - TyphoonWindow win[4]; -} TyphoonPchip; - -#define TYPHOON_PCI_HOST_BRIDGE(obj) \ - OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE) - -typedef struct TyphoonState { - PCIHostState parent_obj; - - TyphoonCchip cchip; - TyphoonPchip pchip; - MemoryRegion dchip_region; - MemoryRegion ram_region; -} TyphoonState; - -/* Called when one of DRIR or DIM changes. */ -static void cpu_irq_change(AlphaCPU *cpu, uint64_t req) -{ - /* If there are any non-masked interrupts, tell the cpu. */ - if (cpu != NULL) { - CPUState *cs = CPU(cpu); - if (req) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } - } -} - -static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size) -{ - CPUState *cpu = current_cpu; - TyphoonState *s = opaque; - uint64_t ret = 0; - - switch (addr) { - case 0x0000: - /* CSC: Cchip System Configuration Register. */ - /* All sorts of data here; probably the only thing relevant is - PIP<14> Pchip 1 Present = 0. */ - break; - - case 0x0040: - /* MTR: Memory Timing Register. */ - /* All sorts of stuff related to real DRAM. */ - break; - - case 0x0080: - /* MISC: Miscellaneous Register. */ - ret = s->cchip.misc | (cpu->cpu_index & 3); - break; - - case 0x00c0: - /* MPD: Memory Presence Detect Register. */ - break; - - case 0x0100: /* AAR0 */ - case 0x0140: /* AAR1 */ - case 0x0180: /* AAR2 */ - case 0x01c0: /* AAR3 */ - /* AAR: Array Address Register. */ - /* All sorts of information about DRAM. */ - break; - - case 0x0200: - /* DIM0: Device Interrupt Mask Register, CPU0. */ - ret = s->cchip.dim[0]; - break; - case 0x0240: - /* DIM1: Device Interrupt Mask Register, CPU1. */ - ret = s->cchip.dim[1]; - break; - case 0x0280: - /* DIR0: Device Interrupt Request Register, CPU0. */ - ret = s->cchip.dim[0] & s->cchip.drir; - break; - case 0x02c0: - /* DIR1: Device Interrupt Request Register, CPU1. */ - ret = s->cchip.dim[1] & s->cchip.drir; - break; - case 0x0300: - /* DRIR: Device Raw Interrupt Request Register. */ - ret = s->cchip.drir; - break; - - case 0x0340: - /* PRBEN: Probe Enable Register. */ - break; - - case 0x0380: - /* IIC0: Interval Ignore Count Register, CPU0. */ - ret = s->cchip.iic[0]; - break; - case 0x03c0: - /* IIC1: Interval Ignore Count Register, CPU1. */ - ret = s->cchip.iic[1]; - break; - - case 0x0400: /* MPR0 */ - case 0x0440: /* MPR1 */ - case 0x0480: /* MPR2 */ - case 0x04c0: /* MPR3 */ - /* MPR: Memory Programming Register. */ - break; - - case 0x0580: - /* TTR: TIGbus Timing Register. */ - /* All sorts of stuff related to interrupt delivery timings. */ - break; - case 0x05c0: - /* TDR: TIGbug Device Timing Register. */ - break; - - case 0x0600: - /* DIM2: Device Interrupt Mask Register, CPU2. */ - ret = s->cchip.dim[2]; - break; - case 0x0640: - /* DIM3: Device Interrupt Mask Register, CPU3. */ - ret = s->cchip.dim[3]; - break; - case 0x0680: - /* DIR2: Device Interrupt Request Register, CPU2. */ - ret = s->cchip.dim[2] & s->cchip.drir; - break; - case 0x06c0: - /* DIR3: Device Interrupt Request Register, CPU3. */ - ret = s->cchip.dim[3] & s->cchip.drir; - break; - - case 0x0700: - /* IIC2: Interval Ignore Count Register, CPU2. */ - ret = s->cchip.iic[2]; - break; - case 0x0740: - /* IIC3: Interval Ignore Count Register, CPU3. */ - ret = s->cchip.iic[3]; - break; - - case 0x0780: - /* PWR: Power Management Control. */ - break; - - case 0x0c00: /* CMONCTLA */ - case 0x0c40: /* CMONCTLB */ - case 0x0c80: /* CMONCNT01 */ - case 0x0cc0: /* CMONCNT23 */ - break; - - default: - cpu_unassigned_access(cpu, addr, false, false, 0, size); - return -1; - } - - return ret; -} - -static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size) -{ - /* Skip this. It's all related to DRAM timing and setup. */ - return 0; -} - -static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size) -{ - TyphoonState *s = opaque; - uint64_t ret = 0; - - switch (addr) { - case 0x0000: - /* WSBA0: Window Space Base Address Register. */ - ret = s->pchip.win[0].wba; - break; - case 0x0040: - /* WSBA1 */ - ret = s->pchip.win[1].wba; - break; - case 0x0080: - /* WSBA2 */ - ret = s->pchip.win[2].wba; - break; - case 0x00c0: - /* WSBA3 */ - ret = s->pchip.win[3].wba; - break; - - case 0x0100: - /* WSM0: Window Space Mask Register. */ - ret = s->pchip.win[0].wsm; - break; - case 0x0140: - /* WSM1 */ - ret = s->pchip.win[1].wsm; - break; - case 0x0180: - /* WSM2 */ - ret = s->pchip.win[2].wsm; - break; - case 0x01c0: - /* WSM3 */ - ret = s->pchip.win[3].wsm; - break; - - case 0x0200: - /* TBA0: Translated Base Address Register. */ - ret = s->pchip.win[0].tba; - break; - case 0x0240: - /* TBA1 */ - ret = s->pchip.win[1].tba; - break; - case 0x0280: - /* TBA2 */ - ret = s->pchip.win[2].tba; - break; - case 0x02c0: - /* TBA3 */ - ret = s->pchip.win[3].tba; - break; - - case 0x0300: - /* PCTL: Pchip Control Register. */ - ret = s->pchip.ctl; - break; - case 0x0340: - /* PLAT: Pchip Master Latency Register. */ - break; - case 0x03c0: - /* PERROR: Pchip Error Register. */ - break; - case 0x0400: - /* PERRMASK: Pchip Error Mask Register. */ - break; - case 0x0440: - /* PERRSET: Pchip Error Set Register. */ - break; - case 0x0480: - /* TLBIV: Translation Buffer Invalidate Virtual Register (WO). */ - break; - case 0x04c0: - /* TLBIA: Translation Buffer Invalidate All Register (WO). */ - break; - case 0x0500: /* PMONCTL */ - case 0x0540: /* PMONCNT */ - case 0x0800: /* SPRST */ - break; - - default: - cpu_unassigned_access(current_cpu, addr, false, false, 0, size); - return -1; - } - - return ret; -} - -static void cchip_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - TyphoonState *s = opaque; - uint64_t oldval, newval; - - switch (addr) { - case 0x0000: - /* CSC: Cchip System Configuration Register. */ - /* All sorts of data here; nothing relevant RW. */ - break; - - case 0x0040: - /* MTR: Memory Timing Register. */ - /* All sorts of stuff related to real DRAM. */ - break; - - case 0x0080: - /* MISC: Miscellaneous Register. */ - newval = oldval = s->cchip.misc; - newval &= ~(val & 0x10000ff0); /* W1C fields */ - if (val & 0x100000) { - newval &= ~0xff0000ull; /* ACL clears ABT and ABW */ - } else { - newval |= val & 0x00f00000; /* ABT field is W1S */ - if ((newval & 0xf0000) == 0) { - newval |= val & 0xf0000; /* ABW field is W1S iff zero */ - } - } - newval |= (val & 0xf000) >> 4; /* IPREQ field sets IPINTR. */ - - newval &= ~0xf0000000000ull; /* WO and RW fields */ - newval |= val & 0xf0000000000ull; - s->cchip.misc = newval; - - /* Pass on changes to IPI and ITI state. */ - if ((newval ^ oldval) & 0xff0) { - int i; - for (i = 0; i < 4; ++i) { - AlphaCPU *cpu = s->cchip.cpu[i]; - if (cpu != NULL) { - CPUState *cs = CPU(cpu); - /* IPI can be either cleared or set by the write. */ - if (newval & (1 << (i + 8))) { - cpu_interrupt(cs, CPU_INTERRUPT_SMP); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP); - } - - /* ITI can only be cleared by the write. */ - if ((newval & (1 << (i + 4))) == 0) { - cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER); - } - } - } - } - break; - - case 0x00c0: - /* MPD: Memory Presence Detect Register. */ - break; - - case 0x0100: /* AAR0 */ - case 0x0140: /* AAR1 */ - case 0x0180: /* AAR2 */ - case 0x01c0: /* AAR3 */ - /* AAR: Array Address Register. */ - /* All sorts of information about DRAM. */ - break; - - case 0x0200: /* DIM0 */ - /* DIM: Device Interrupt Mask Register, CPU0. */ - s->cchip.dim[0] = val; - cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir); - break; - case 0x0240: /* DIM1 */ - /* DIM: Device Interrupt Mask Register, CPU1. */ - s->cchip.dim[0] = val; - cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir); - break; - - case 0x0280: /* DIR0 (RO) */ - case 0x02c0: /* DIR1 (RO) */ - case 0x0300: /* DRIR (RO) */ - break; - - case 0x0340: - /* PRBEN: Probe Enable Register. */ - break; - - case 0x0380: /* IIC0 */ - s->cchip.iic[0] = val & 0xffffff; - break; - case 0x03c0: /* IIC1 */ - s->cchip.iic[1] = val & 0xffffff; - break; - - case 0x0400: /* MPR0 */ - case 0x0440: /* MPR1 */ - case 0x0480: /* MPR2 */ - case 0x04c0: /* MPR3 */ - /* MPR: Memory Programming Register. */ - break; - - case 0x0580: - /* TTR: TIGbus Timing Register. */ - /* All sorts of stuff related to interrupt delivery timings. */ - break; - case 0x05c0: - /* TDR: TIGbug Device Timing Register. */ - break; - - case 0x0600: - /* DIM2: Device Interrupt Mask Register, CPU2. */ - s->cchip.dim[2] = val; - cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir); - break; - case 0x0640: - /* DIM3: Device Interrupt Mask Register, CPU3. */ - s->cchip.dim[3] = val; - cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir); - break; - - case 0x0680: /* DIR2 (RO) */ - case 0x06c0: /* DIR3 (RO) */ - break; - - case 0x0700: /* IIC2 */ - s->cchip.iic[2] = val & 0xffffff; - break; - case 0x0740: /* IIC3 */ - s->cchip.iic[3] = val & 0xffffff; - break; - - case 0x0780: - /* PWR: Power Management Control. */ - break; - - case 0x0c00: /* CMONCTLA */ - case 0x0c40: /* CMONCTLB */ - case 0x0c80: /* CMONCNT01 */ - case 0x0cc0: /* CMONCNT23 */ - break; - - default: - cpu_unassigned_access(current_cpu, addr, true, false, 0, size); - return; - } -} - -static void dchip_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - /* Skip this. It's all related to DRAM timing and setup. */ -} - -static void pchip_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - TyphoonState *s = opaque; - uint64_t oldval; - - switch (addr) { - case 0x0000: - /* WSBA0: Window Space Base Address Register. */ - s->pchip.win[0].wba = val & 0xfff00003u; - break; - case 0x0040: - /* WSBA1 */ - s->pchip.win[1].wba = val & 0xfff00003u; - break; - case 0x0080: - /* WSBA2 */ - s->pchip.win[2].wba = val & 0xfff00003u; - break; - case 0x00c0: - /* WSBA3 */ - s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2; - break; - - case 0x0100: - /* WSM0: Window Space Mask Register. */ - s->pchip.win[0].wsm = val & 0xfff00000u; - break; - case 0x0140: - /* WSM1 */ - s->pchip.win[1].wsm = val & 0xfff00000u; - break; - case 0x0180: - /* WSM2 */ - s->pchip.win[2].wsm = val & 0xfff00000u; - break; - case 0x01c0: - /* WSM3 */ - s->pchip.win[3].wsm = val & 0xfff00000u; - break; - - case 0x0200: - /* TBA0: Translated Base Address Register. */ - s->pchip.win[0].tba = val & 0x7fffffc00ull; - break; - case 0x0240: - /* TBA1 */ - s->pchip.win[1].tba = val & 0x7fffffc00ull; - break; - case 0x0280: - /* TBA2 */ - s->pchip.win[2].tba = val & 0x7fffffc00ull; - break; - case 0x02c0: - /* TBA3 */ - s->pchip.win[3].tba = val & 0x7fffffc00ull; - break; - - case 0x0300: - /* PCTL: Pchip Control Register. */ - oldval = s->pchip.ctl; - oldval &= ~0x00001cff0fc7ffull; /* RW fields */ - oldval |= val & 0x00001cff0fc7ffull; - s->pchip.ctl = oldval; - break; - - case 0x0340: - /* PLAT: Pchip Master Latency Register. */ - break; - case 0x03c0: - /* PERROR: Pchip Error Register. */ - break; - case 0x0400: - /* PERRMASK: Pchip Error Mask Register. */ - break; - case 0x0440: - /* PERRSET: Pchip Error Set Register. */ - break; - - case 0x0480: - /* TLBIV: Translation Buffer Invalidate Virtual Register. */ - break; - - case 0x04c0: - /* TLBIA: Translation Buffer Invalidate All Register (WO). */ - break; - - case 0x0500: - /* PMONCTL */ - case 0x0540: - /* PMONCNT */ - case 0x0800: - /* SPRST */ - break; - - default: - cpu_unassigned_access(current_cpu, addr, true, false, 0, size); - return; - } -} - -static const MemoryRegionOps cchip_ops = { - .read = cchip_read, - .write = cchip_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 8, - .max_access_size = 8, - }, - .impl = { - .min_access_size = 8, - .max_access_size = 8, - }, -}; - -static const MemoryRegionOps dchip_ops = { - .read = dchip_read, - .write = dchip_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 8, - .max_access_size = 8, - }, - .impl = { - .min_access_size = 8, - .max_access_size = 8, - }, -}; - -static const MemoryRegionOps pchip_ops = { - .read = pchip_read, - .write = pchip_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 8, - .max_access_size = 8, - }, - .impl = { - .min_access_size = 8, - .max_access_size = 8, - }, -}; - -/* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry - using the given translated address and mask. */ -static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret) -{ - *ret = (IOMMUTLBEntry) { - .target_as = &address_space_memory, - .translated_addr = taddr, - .addr_mask = mask, - .perm = IOMMU_RW, - }; - return true; -} - -/* A subroutine of typhoon_translate_iommu that handles scatter-gather - translation, given the address of the PTE. */ -static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret) -{ - uint64_t pte = address_space_ldq(&address_space_memory, pte_addr, - MEMTXATTRS_UNSPECIFIED, NULL); - - /* Check valid bit. */ - if ((pte & 1) == 0) { - return false; - } - - return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret); -} - -/* A subroutine of typhoon_translate_iommu that handles one of the - four single-address-cycle translation windows. */ -static bool window_translate(TyphoonWindow *win, hwaddr addr, - IOMMUTLBEntry *ret) -{ - uint32_t wba = win->wba; - uint64_t wsm = win->wsm; - uint64_t tba = win->tba; - uint64_t wsm_ext = wsm | 0xfffff; - - /* Check for window disabled. */ - if ((wba & 1) == 0) { - return false; - } - - /* Check for window hit. */ - if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) { - return false; - } - - if (wba & 2) { - /* Scatter-gather translation. */ - hwaddr pte_addr; - - /* See table 10-6, Generating PTE address for PCI DMA Address. */ - pte_addr = tba & ~(wsm >> 10); - pte_addr |= (addr & (wsm | 0xfe000)) >> 10; - return pte_translate(pte_addr, ret); - } else { - /* Direct-mapped translation. */ - return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret); - } -} - -/* Handle PCI-to-system address translation. */ -/* TODO: A translation failure here ought to set PCI error codes on the - Pchip and generate a machine check interrupt. */ -static IOMMUTLBEntry typhoon_translate_iommu(MemoryRegion *iommu, hwaddr addr, - bool is_write) -{ - TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu); - IOMMUTLBEntry ret; - int i; - - if (addr <= 0xffffffffu) { - /* Single-address cycle. */ - - /* Check for the Window Hole, inhibiting matching. */ - if ((pchip->ctl & 0x20) - && addr >= 0x80000 - && addr <= 0xfffff) { - goto failure; - } - - /* Check the first three windows. */ - for (i = 0; i < 3; ++i) { - if (window_translate(&pchip->win[i], addr, &ret)) { - goto success; - } - } - - /* Check the fourth window for DAC disable. */ - if ((pchip->win[3].wba & 0x80000000000ull) == 0 - && window_translate(&pchip->win[3], addr, &ret)) { - goto success; - } - } else { - /* Double-address cycle. */ - - if (addr >= 0x10000000000ull && addr < 0x20000000000ull) { - /* Check for the DMA monster window. */ - if (pchip->ctl & 0x40) { - /* See 10.1.4.4; in particular <39:35> is ignored. */ - make_iommu_tlbe(0, 0x007ffffffffull, &ret); - goto success; - } - } - - if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) { - /* Check the fourth window for DAC enable and window enable. */ - if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) { - uint64_t pte_addr; - - pte_addr = pchip->win[3].tba & 0x7ffc00000ull; - pte_addr |= (addr & 0xffffe000u) >> 10; - if (pte_translate(pte_addr, &ret)) { - goto success; - } - } - } - } - - failure: - ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE }; - success: - return ret; -} - -static const MemoryRegionIOMMUOps typhoon_iommu_ops = { - .translate = typhoon_translate_iommu, -}; - -static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) -{ - TyphoonState *s = opaque; - return &s->pchip.iommu_as; -} - -static void typhoon_set_irq(void *opaque, int irq, int level) -{ - TyphoonState *s = opaque; - uint64_t drir; - int i; - - /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL. */ - drir = s->cchip.drir; - if (level) { - drir |= 1ull << irq; - } else { - drir &= ~(1ull << irq); - } - s->cchip.drir = drir; - - for (i = 0; i < 4; ++i) { - cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir); - } -} - -static void typhoon_set_isa_irq(void *opaque, int irq, int level) -{ - typhoon_set_irq(opaque, 55, level); -} - -static void typhoon_set_timer_irq(void *opaque, int irq, int level) -{ - TyphoonState *s = opaque; - int i; - - /* Thankfully, the mc146818rtc code doesn't track the IRQ state, - and so we don't have to worry about missing interrupts just - because we never actually ACK the interrupt. Just ignore any - case of the interrupt level going low. */ - if (level == 0) { - return; - } - - /* Deliver the interrupt to each CPU, considering each CPU's IIC. */ - for (i = 0; i < 4; ++i) { - AlphaCPU *cpu = s->cchip.cpu[i]; - if (cpu != NULL) { - uint32_t iic = s->cchip.iic[i]; - - /* ??? The verbage in Section 10.2.2.10 isn't 100% clear. - Bit 24 is the OverFlow bit, RO, and set when the count - decrements past 0. When is OF cleared? My guess is that - OF is actually cleared when the IIC is written, and that - the ICNT field always decrements. At least, that's an - interpretation that makes sense, and "allows the CPU to - determine exactly how mant interval timer ticks were - skipped". At least within the next 4M ticks... */ - - iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000); - s->cchip.iic[i] = iic; - - if (iic & 0x1000000) { - /* Set the ITI bit for this cpu. */ - s->cchip.misc |= 1 << (i + 4); - /* And signal the interrupt. */ - cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER); - } - } - } -} - -static void typhoon_alarm_timer(void *opaque) -{ - TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3); - int cpu = (uintptr_t)opaque & 3; - - /* Set the ITI bit for this cpu. */ - s->cchip.misc |= 1 << (cpu + 4); - cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER); -} - -PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, - qemu_irq *p_rtc_irq, - AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq) -{ - const uint64_t MB = 1024 * 1024; - const uint64_t GB = 1024 * MB; - MemoryRegion *addr_space = get_system_memory(); - DeviceState *dev; - TyphoonState *s; - PCIHostState *phb; - PCIBus *b; - int i; - - dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE); - qdev_init_nofail(dev); - - s = TYPHOON_PCI_HOST_BRIDGE(dev); - phb = PCI_HOST_BRIDGE(dev); - - s->cchip.misc = 0x800000000ull; /* Revision: Typhoon. */ - s->pchip.win[3].wba = 2; /* Window 3 SG always enabled. */ - - /* Remember the CPUs so that we can deliver interrupts to them. */ - for (i = 0; i < 4; i++) { - AlphaCPU *cpu = cpus[i]; - s->cchip.cpu[i] = cpu; - if (cpu != NULL) { - cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - typhoon_alarm_timer, - (void *)((uintptr_t)s + i)); - } - } - - *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0); - - /* Main memory region, 0x00.0000.0000. Real hardware supports 32GB, - but the address space hole reserved at this point is 8TB. */ - memory_region_allocate_system_memory(&s->ram_region, OBJECT(s), "ram", - ram_size); - memory_region_add_subregion(addr_space, 0, &s->ram_region); - - /* TIGbus, 0x801.0000.0000, 1GB. */ - /* ??? The TIGbus is used for delivering interrupts, and access to - the flash ROM. I'm not sure that we need to implement it at all. */ - - /* Pchip0 CSRs, 0x801.8000.0000, 256MB. */ - memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0", - 256*MB); - memory_region_add_subregion(addr_space, 0x80180000000ULL, - &s->pchip.region); - - /* Cchip CSRs, 0x801.A000.0000, 256MB. */ - memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0", - 256*MB); - memory_region_add_subregion(addr_space, 0x801a0000000ULL, - &s->cchip.region); - - /* Dchip CSRs, 0x801.B000.0000, 256MB. */ - memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0", - 256*MB); - memory_region_add_subregion(addr_space, 0x801b0000000ULL, - &s->dchip_region); - - /* Pchip0 PCI memory, 0x800.0000.0000, 4GB. */ - memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4*GB); - memory_region_add_subregion(addr_space, 0x80000000000ULL, - &s->pchip.reg_mem); - - /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB. */ - memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops, - NULL, "pci0-io", 32*MB); - memory_region_add_subregion(addr_space, 0x801fc000000ULL, - &s->pchip.reg_io); - - b = pci_register_bus(dev, "pci", - typhoon_set_irq, sys_map_irq, s, - &s->pchip.reg_mem, &s->pchip.reg_io, - 0, 64, TYPE_PCI_BUS); - phb->bus = b; - - /* Host memory as seen from the PCI side, via the IOMMU. */ - memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops, - "iommu-typhoon", UINT64_MAX); - address_space_init(&s->pchip.iommu_as, &s->pchip.iommu, "pchip0-pci"); - pci_setup_iommu(b, typhoon_pci_dma_iommu, s); - - /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */ - memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops, - b, "pci0-iack", 64*MB); - memory_region_add_subregion(addr_space, 0x801f8000000ULL, - &s->pchip.reg_iack); - - /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB. */ - memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops, - b, "pci0-conf", 16*MB); - memory_region_add_subregion(addr_space, 0x801fe000000ULL, - &s->pchip.reg_conf); - - /* For the record, these are the mappings for the second PCI bus. - We can get away with not implementing them because we indicate - via the Cchip.CSC<PIP> bit that Pchip1 is not present. */ - /* Pchip1 PCI memory, 0x802.0000.0000, 4GB. */ - /* Pchip1 CSRs, 0x802.8000.0000, 256MB. */ - /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB. */ - /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB. */ - /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB. */ - - /* Init the ISA bus. */ - /* ??? Technically there should be a cy82c693ub pci-isa bridge. */ - { - qemu_irq *isa_irqs; - - *isa_bus = isa_bus_new(NULL, get_system_memory(), &s->pchip.reg_io, - &error_abort); - isa_irqs = i8259_init(*isa_bus, - qemu_allocate_irq(typhoon_set_isa_irq, s, 0)); - isa_bus_irqs(*isa_bus, isa_irqs); - } - - return b; -} - -static int typhoon_pcihost_init(SysBusDevice *dev) -{ - return 0; -} - -static void typhoon_pcihost_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = typhoon_pcihost_init; -} - -static const TypeInfo typhoon_pcihost_info = { - .name = TYPE_TYPHOON_PCI_HOST_BRIDGE, - .parent = TYPE_PCI_HOST_BRIDGE, - .instance_size = sizeof(TyphoonState), - .class_init = typhoon_pcihost_class_init, -}; - -static void typhoon_register_types(void) -{ - type_register_static(&typhoon_pcihost_info); -} - -type_init(typhoon_register_types) |