123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956 |
- /*
- * 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 "qemu/module.h"
- #include "qemu/units.h"
- #include "qapi/error.h"
- #include "hw/pci/pci_host.h"
- #include "cpu.h"
- #include "hw/irq.h"
- #include "alpha_sys.h"
- #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
- #define TYPE_TYPHOON_IOMMU_MEMORY_REGION "typhoon-iommu-memory-region"
- 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;
- IOMMUMemoryRegion iommu;
- uint64_t ctl;
- TyphoonWindow win[4];
- } TyphoonPchip;
- OBJECT_DECLARE_SIMPLE_TYPE(TyphoonState, TYPHOON_PCI_HOST_BRIDGE)
- struct TyphoonState {
- PCIHostState parent_obj;
- TyphoonCchip cchip;
- TyphoonPchip pchip;
- MemoryRegion dchip_region;
- };
- /* 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 MemTxResult cchip_read(void *opaque, hwaddr addr,
- uint64_t *data, unsigned size,
- MemTxAttrs attrs)
- {
- 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:
- return MEMTX_ERROR;
- }
- *data = ret;
- return MEMTX_OK;
- }
- 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 MemTxResult pchip_read(void *opaque, hwaddr addr, uint64_t *data,
- unsigned size, MemTxAttrs attrs)
- {
- 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:
- return MEMTX_ERROR;
- }
- *data = ret;
- return MEMTX_OK;
- }
- static MemTxResult cchip_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size,
- MemTxAttrs attrs)
- {
- 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[1] = 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:
- return MEMTX_ERROR;
- }
- return MEMTX_OK;
- }
- 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 MemTxResult pchip_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size,
- MemTxAttrs attrs)
- {
- 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:
- return MEMTX_ERROR;
- }
- return MEMTX_OK;
- }
- static const MemoryRegionOps cchip_ops = {
- .read_with_attrs = cchip_read,
- .write_with_attrs = 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_with_attrs = pchip_read,
- .write_with_attrs = 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(IOMMUMemoryRegion *iommu,
- hwaddr addr,
- IOMMUAccessFlags flag,
- int iommu_idx)
- {
- 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 AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
- {
- TyphoonState *s = opaque;
- return &s->pchip.iommu_as;
- }
- static const PCIIOMMUOps typhoon_iommu_ops = {
- .get_address_space = typhoon_pci_dma_iommu,
- };
- 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(MemoryRegion *ram, qemu_irq *p_isa_irq,
- qemu_irq *p_rtc_irq, AlphaCPU *cpus[4],
- pci_map_irq_fn sys_map_irq, uint8_t devfn_min)
- {
- MemoryRegion *addr_space = get_system_memory();
- DeviceState *dev;
- TyphoonState *s;
- PCIHostState *phb;
- PCIBus *b;
- int i;
- dev = qdev_new(TYPE_TYPHOON_PCI_HOST_BRIDGE);
- 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_isa_irq = qemu_allocate_irq(typhoon_set_isa_irq, s, 0);
- *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_add_subregion(addr_space, 0, ram);
- /* 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 * MiB);
- 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 * MiB);
- 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 * MiB);
- 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 * GiB);
- 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 * MiB);
- memory_region_add_subregion(addr_space, 0x801fc000000ULL,
- &s->pchip.reg_io);
- b = pci_register_root_bus(dev, "pci",
- typhoon_set_irq, sys_map_irq, s,
- &s->pchip.reg_mem, &s->pchip.reg_io,
- devfn_min, 64, TYPE_PCI_BUS);
- phb->bus = b;
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- /* Host memory as seen from the PCI side, via the IOMMU. */
- memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu),
- TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s),
- "iommu-typhoon", UINT64_MAX);
- address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
- "pchip0-pci");
- pci_setup_iommu(b, &typhoon_iommu_ops, 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 * MiB);
- 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 * MiB);
- 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. */
- return b;
- }
- static const TypeInfo typhoon_pcihost_info = {
- .name = TYPE_TYPHOON_PCI_HOST_BRIDGE,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(TyphoonState),
- };
- static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
- void *data)
- {
- IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
- imrc->translate = typhoon_translate_iommu;
- }
- static const TypeInfo typhoon_iommu_memory_region_info = {
- .parent = TYPE_IOMMU_MEMORY_REGION,
- .name = TYPE_TYPHOON_IOMMU_MEMORY_REGION,
- .class_init = typhoon_iommu_memory_region_class_init,
- };
- static void typhoon_register_types(void)
- {
- type_register_static(&typhoon_pcihost_info);
- type_register_static(&typhoon_iommu_memory_region_info);
- }
- type_init(typhoon_register_types)
|