xref: /qemu/hw/alpha/typhoon.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
180bb2ff7SRichard Henderson /*
280bb2ff7SRichard Henderson  * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
380bb2ff7SRichard Henderson  *
480bb2ff7SRichard Henderson  * Written by Richard Henderson.
580bb2ff7SRichard Henderson  *
680bb2ff7SRichard Henderson  * This work is licensed under the GNU GPL license version 2 or later.
780bb2ff7SRichard Henderson  */
880bb2ff7SRichard Henderson 
9e2e5e114SPeter Maydell #include "qemu/osdep.h"
100b8fa32fSMarkus Armbruster #include "qemu/module.h"
112b41742aSPhilippe Mathieu-Daudé #include "qemu/units.h"
1222a7c2f2SPierrick Bouvier #include "exec/cpu-interrupt.h"
13da34e65cSMarkus Armbruster #include "qapi/error.h"
14674b0a57SMarkus Armbruster #include "hw/pci/pci_host.h"
1580bb2ff7SRichard Henderson #include "cpu.h"
1664552b6bSMarkus Armbruster #include "hw/irq.h"
1747b43a1fSPaolo Bonzini #include "alpha_sys.h"
1880bb2ff7SRichard Henderson 
1980bb2ff7SRichard Henderson 
2094dd91d6SAndreas Färber #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
211221a474SAlexey Kardashevskiy #define TYPE_TYPHOON_IOMMU_MEMORY_REGION "typhoon-iommu-memory-region"
2294dd91d6SAndreas Färber 
2380bb2ff7SRichard Henderson typedef struct TyphoonCchip {
2480bb2ff7SRichard Henderson     MemoryRegion region;
2580bb2ff7SRichard Henderson     uint64_t misc;
2680bb2ff7SRichard Henderson     uint64_t drir;
2780bb2ff7SRichard Henderson     uint64_t dim[4];
2880bb2ff7SRichard Henderson     uint32_t iic[4];
29ad601177SAndreas Färber     AlphaCPU *cpu[4];
3080bb2ff7SRichard Henderson } TyphoonCchip;
3180bb2ff7SRichard Henderson 
3280bb2ff7SRichard Henderson typedef struct TyphoonWindow {
33b83c4db8SRichard Henderson     uint64_t wba;
34b83c4db8SRichard Henderson     uint64_t wsm;
35b83c4db8SRichard Henderson     uint64_t tba;
3680bb2ff7SRichard Henderson } TyphoonWindow;
3780bb2ff7SRichard Henderson 
3880bb2ff7SRichard Henderson typedef struct TyphoonPchip {
3980bb2ff7SRichard Henderson     MemoryRegion region;
4080bb2ff7SRichard Henderson     MemoryRegion reg_iack;
4180bb2ff7SRichard Henderson     MemoryRegion reg_mem;
4280bb2ff7SRichard Henderson     MemoryRegion reg_io;
4380bb2ff7SRichard Henderson     MemoryRegion reg_conf;
44b83c4db8SRichard Henderson 
45b83c4db8SRichard Henderson     AddressSpace iommu_as;
463df9d748SAlexey Kardashevskiy     IOMMUMemoryRegion iommu;
47b83c4db8SRichard Henderson 
4880bb2ff7SRichard Henderson     uint64_t ctl;
4980bb2ff7SRichard Henderson     TyphoonWindow win[4];
5080bb2ff7SRichard Henderson } TyphoonPchip;
5180bb2ff7SRichard Henderson 
528063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(TyphoonState, TYPHOON_PCI_HOST_BRIDGE)
5394dd91d6SAndreas Färber 
54db1015e9SEduardo Habkost struct TyphoonState {
5567c332fdSAndreas Färber     PCIHostState parent_obj;
5694dd91d6SAndreas Färber 
5780bb2ff7SRichard Henderson     TyphoonCchip cchip;
5880bb2ff7SRichard Henderson     TyphoonPchip pchip;
5980bb2ff7SRichard Henderson     MemoryRegion dchip_region;
60db1015e9SEduardo Habkost };
6180bb2ff7SRichard Henderson 
6280bb2ff7SRichard Henderson /* Called when one of DRIR or DIM changes.  */
cpu_irq_change(AlphaCPU * cpu,uint64_t req)63ad601177SAndreas Färber static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
6480bb2ff7SRichard Henderson {
6580bb2ff7SRichard Henderson     /* If there are any non-masked interrupts, tell the cpu.  */
66ad601177SAndreas Färber     if (cpu != NULL) {
67d8ed887bSAndreas Färber         CPUState *cs = CPU(cpu);
6880bb2ff7SRichard Henderson         if (req) {
69c3affe56SAndreas Färber             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
7080bb2ff7SRichard Henderson         } else {
71d8ed887bSAndreas Färber             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
7280bb2ff7SRichard Henderson         }
7380bb2ff7SRichard Henderson     }
7480bb2ff7SRichard Henderson }
7580bb2ff7SRichard Henderson 
cchip_read(void * opaque,hwaddr addr,uint64_t * data,unsigned size,MemTxAttrs attrs)76b7ed683aSPeter Maydell static MemTxResult cchip_read(void *opaque, hwaddr addr,
77b7ed683aSPeter Maydell                               uint64_t *data, unsigned size,
78b7ed683aSPeter Maydell                               MemTxAttrs attrs)
7980bb2ff7SRichard Henderson {
804917cf44SAndreas Färber     CPUState *cpu = current_cpu;
8180bb2ff7SRichard Henderson     TyphoonState *s = opaque;
8280bb2ff7SRichard Henderson     uint64_t ret = 0;
8380bb2ff7SRichard Henderson 
8480bb2ff7SRichard Henderson     switch (addr) {
8580bb2ff7SRichard Henderson     case 0x0000:
8680bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
8780bb2ff7SRichard Henderson         /* All sorts of data here; probably the only thing relevant is
8880bb2ff7SRichard Henderson            PIP<14> Pchip 1 Present = 0.  */
8980bb2ff7SRichard Henderson         break;
9080bb2ff7SRichard Henderson 
9180bb2ff7SRichard Henderson     case 0x0040:
9280bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
9380bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
9480bb2ff7SRichard Henderson         break;
9580bb2ff7SRichard Henderson 
9680bb2ff7SRichard Henderson     case 0x0080:
9780bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
9855e5c285SAndreas Färber         ret = s->cchip.misc | (cpu->cpu_index & 3);
9980bb2ff7SRichard Henderson         break;
10080bb2ff7SRichard Henderson 
10180bb2ff7SRichard Henderson     case 0x00c0:
10280bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
10380bb2ff7SRichard Henderson         break;
10480bb2ff7SRichard Henderson 
10580bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
10680bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
10780bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
10880bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
10980bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
11080bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
11180bb2ff7SRichard Henderson         break;
11280bb2ff7SRichard Henderson 
11380bb2ff7SRichard Henderson     case 0x0200:
11480bb2ff7SRichard Henderson         /* DIM0: Device Interrupt Mask Register, CPU0.  */
11580bb2ff7SRichard Henderson         ret = s->cchip.dim[0];
11680bb2ff7SRichard Henderson         break;
11780bb2ff7SRichard Henderson     case 0x0240:
11880bb2ff7SRichard Henderson         /* DIM1: Device Interrupt Mask Register, CPU1.  */
11980bb2ff7SRichard Henderson         ret = s->cchip.dim[1];
12080bb2ff7SRichard Henderson         break;
12180bb2ff7SRichard Henderson     case 0x0280:
12280bb2ff7SRichard Henderson         /* DIR0: Device Interrupt Request Register, CPU0.  */
12380bb2ff7SRichard Henderson         ret = s->cchip.dim[0] & s->cchip.drir;
12480bb2ff7SRichard Henderson         break;
12580bb2ff7SRichard Henderson     case 0x02c0:
12680bb2ff7SRichard Henderson         /* DIR1: Device Interrupt Request Register, CPU1.  */
12780bb2ff7SRichard Henderson         ret = s->cchip.dim[1] & s->cchip.drir;
12880bb2ff7SRichard Henderson         break;
12980bb2ff7SRichard Henderson     case 0x0300:
13080bb2ff7SRichard Henderson         /* DRIR: Device Raw Interrupt Request Register.  */
13180bb2ff7SRichard Henderson         ret = s->cchip.drir;
13280bb2ff7SRichard Henderson         break;
13380bb2ff7SRichard Henderson 
13480bb2ff7SRichard Henderson     case 0x0340:
13580bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
13680bb2ff7SRichard Henderson         break;
13780bb2ff7SRichard Henderson 
13880bb2ff7SRichard Henderson     case 0x0380:
13980bb2ff7SRichard Henderson         /* IIC0: Interval Ignore Count Register, CPU0.  */
14080bb2ff7SRichard Henderson         ret = s->cchip.iic[0];
14180bb2ff7SRichard Henderson         break;
14280bb2ff7SRichard Henderson     case 0x03c0:
14380bb2ff7SRichard Henderson         /* IIC1: Interval Ignore Count Register, CPU1.  */
14480bb2ff7SRichard Henderson         ret = s->cchip.iic[1];
14580bb2ff7SRichard Henderson         break;
14680bb2ff7SRichard Henderson 
14780bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
14880bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
14980bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
15080bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
15180bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
15280bb2ff7SRichard Henderson         break;
15380bb2ff7SRichard Henderson 
15480bb2ff7SRichard Henderson     case 0x0580:
15580bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
15680bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
15780bb2ff7SRichard Henderson         break;
15880bb2ff7SRichard Henderson     case 0x05c0:
15980bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
16080bb2ff7SRichard Henderson         break;
16180bb2ff7SRichard Henderson 
16280bb2ff7SRichard Henderson     case 0x0600:
16380bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
16480bb2ff7SRichard Henderson         ret = s->cchip.dim[2];
16580bb2ff7SRichard Henderson         break;
16680bb2ff7SRichard Henderson     case 0x0640:
16780bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
16880bb2ff7SRichard Henderson         ret = s->cchip.dim[3];
16980bb2ff7SRichard Henderson         break;
17080bb2ff7SRichard Henderson     case 0x0680:
17180bb2ff7SRichard Henderson         /* DIR2: Device Interrupt Request Register, CPU2.  */
17280bb2ff7SRichard Henderson         ret = s->cchip.dim[2] & s->cchip.drir;
17380bb2ff7SRichard Henderson         break;
17480bb2ff7SRichard Henderson     case 0x06c0:
17580bb2ff7SRichard Henderson         /* DIR3: Device Interrupt Request Register, CPU3.  */
17680bb2ff7SRichard Henderson         ret = s->cchip.dim[3] & s->cchip.drir;
17780bb2ff7SRichard Henderson         break;
17880bb2ff7SRichard Henderson 
17980bb2ff7SRichard Henderson     case 0x0700:
18080bb2ff7SRichard Henderson         /* IIC2: Interval Ignore Count Register, CPU2.  */
18180bb2ff7SRichard Henderson         ret = s->cchip.iic[2];
18280bb2ff7SRichard Henderson         break;
18380bb2ff7SRichard Henderson     case 0x0740:
18480bb2ff7SRichard Henderson         /* IIC3: Interval Ignore Count Register, CPU3.  */
18580bb2ff7SRichard Henderson         ret = s->cchip.iic[3];
18680bb2ff7SRichard Henderson         break;
18780bb2ff7SRichard Henderson 
18880bb2ff7SRichard Henderson     case 0x0780:
18980bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
19080bb2ff7SRichard Henderson         break;
19180bb2ff7SRichard Henderson 
19280bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
19380bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
19480bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
19580bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
19680bb2ff7SRichard Henderson         break;
19780bb2ff7SRichard Henderson 
19880bb2ff7SRichard Henderson     default:
199b7ed683aSPeter Maydell         return MEMTX_ERROR;
20080bb2ff7SRichard Henderson     }
20180bb2ff7SRichard Henderson 
202b7ed683aSPeter Maydell     *data = ret;
203b7ed683aSPeter Maydell     return MEMTX_OK;
20480bb2ff7SRichard Henderson }
20580bb2ff7SRichard Henderson 
dchip_read(void * opaque,hwaddr addr,unsigned size)206a8170e5eSAvi Kivity static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
20780bb2ff7SRichard Henderson {
20880bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
20980bb2ff7SRichard Henderson     return 0;
21080bb2ff7SRichard Henderson }
21180bb2ff7SRichard Henderson 
pchip_read(void * opaque,hwaddr addr,uint64_t * data,unsigned size,MemTxAttrs attrs)212b7ed683aSPeter Maydell static MemTxResult pchip_read(void *opaque, hwaddr addr, uint64_t *data,
213b7ed683aSPeter Maydell                               unsigned size, MemTxAttrs attrs)
21480bb2ff7SRichard Henderson {
21580bb2ff7SRichard Henderson     TyphoonState *s = opaque;
21680bb2ff7SRichard Henderson     uint64_t ret = 0;
21780bb2ff7SRichard Henderson 
21880bb2ff7SRichard Henderson     switch (addr) {
21980bb2ff7SRichard Henderson     case 0x0000:
22080bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
221b83c4db8SRichard Henderson         ret = s->pchip.win[0].wba;
22280bb2ff7SRichard Henderson         break;
22380bb2ff7SRichard Henderson     case 0x0040:
22480bb2ff7SRichard Henderson         /* WSBA1 */
225b83c4db8SRichard Henderson         ret = s->pchip.win[1].wba;
22680bb2ff7SRichard Henderson         break;
22780bb2ff7SRichard Henderson     case 0x0080:
22880bb2ff7SRichard Henderson         /* WSBA2 */
229b83c4db8SRichard Henderson         ret = s->pchip.win[2].wba;
23080bb2ff7SRichard Henderson         break;
23180bb2ff7SRichard Henderson     case 0x00c0:
23280bb2ff7SRichard Henderson         /* WSBA3 */
233b83c4db8SRichard Henderson         ret = s->pchip.win[3].wba;
23480bb2ff7SRichard Henderson         break;
23580bb2ff7SRichard Henderson 
23680bb2ff7SRichard Henderson     case 0x0100:
23780bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
238b83c4db8SRichard Henderson         ret = s->pchip.win[0].wsm;
23980bb2ff7SRichard Henderson         break;
24080bb2ff7SRichard Henderson     case 0x0140:
24180bb2ff7SRichard Henderson         /* WSM1 */
242b83c4db8SRichard Henderson         ret = s->pchip.win[1].wsm;
24380bb2ff7SRichard Henderson         break;
24480bb2ff7SRichard Henderson     case 0x0180:
24580bb2ff7SRichard Henderson         /* WSM2 */
246b83c4db8SRichard Henderson         ret = s->pchip.win[2].wsm;
24780bb2ff7SRichard Henderson         break;
24880bb2ff7SRichard Henderson     case 0x01c0:
24980bb2ff7SRichard Henderson         /* WSM3 */
250b83c4db8SRichard Henderson         ret = s->pchip.win[3].wsm;
25180bb2ff7SRichard Henderson         break;
25280bb2ff7SRichard Henderson 
25380bb2ff7SRichard Henderson     case 0x0200:
25480bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
255b83c4db8SRichard Henderson         ret = s->pchip.win[0].tba;
25680bb2ff7SRichard Henderson         break;
25780bb2ff7SRichard Henderson     case 0x0240:
25880bb2ff7SRichard Henderson         /* TBA1 */
259b83c4db8SRichard Henderson         ret = s->pchip.win[1].tba;
26080bb2ff7SRichard Henderson         break;
26180bb2ff7SRichard Henderson     case 0x0280:
26280bb2ff7SRichard Henderson         /* TBA2 */
263b83c4db8SRichard Henderson         ret = s->pchip.win[2].tba;
26480bb2ff7SRichard Henderson         break;
26580bb2ff7SRichard Henderson     case 0x02c0:
26680bb2ff7SRichard Henderson         /* TBA3 */
267b83c4db8SRichard Henderson         ret = s->pchip.win[3].tba;
26880bb2ff7SRichard Henderson         break;
26980bb2ff7SRichard Henderson 
27080bb2ff7SRichard Henderson     case 0x0300:
27180bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
27280bb2ff7SRichard Henderson         ret = s->pchip.ctl;
27380bb2ff7SRichard Henderson         break;
27480bb2ff7SRichard Henderson     case 0x0340:
27580bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
27680bb2ff7SRichard Henderson         break;
27780bb2ff7SRichard Henderson     case 0x03c0:
27880bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
27980bb2ff7SRichard Henderson         break;
28080bb2ff7SRichard Henderson     case 0x0400:
28180bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
28280bb2ff7SRichard Henderson         break;
28380bb2ff7SRichard Henderson     case 0x0440:
28480bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
28580bb2ff7SRichard Henderson         break;
28680bb2ff7SRichard Henderson     case 0x0480:
28780bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
28880bb2ff7SRichard Henderson         break;
28980bb2ff7SRichard Henderson     case 0x04c0:
29080bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
29180bb2ff7SRichard Henderson         break;
29280bb2ff7SRichard Henderson     case 0x0500: /* PMONCTL */
29380bb2ff7SRichard Henderson     case 0x0540: /* PMONCNT */
29480bb2ff7SRichard Henderson     case 0x0800: /* SPRST */
29580bb2ff7SRichard Henderson         break;
29680bb2ff7SRichard Henderson 
29780bb2ff7SRichard Henderson     default:
298b7ed683aSPeter Maydell         return MEMTX_ERROR;
29980bb2ff7SRichard Henderson     }
30080bb2ff7SRichard Henderson 
301b7ed683aSPeter Maydell     *data = ret;
302b7ed683aSPeter Maydell     return MEMTX_OK;
30380bb2ff7SRichard Henderson }
30480bb2ff7SRichard Henderson 
cchip_write(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)305b7ed683aSPeter Maydell static MemTxResult cchip_write(void *opaque, hwaddr addr,
306b7ed683aSPeter Maydell                                uint64_t val, unsigned size,
307b7ed683aSPeter Maydell                                MemTxAttrs attrs)
30880bb2ff7SRichard Henderson {
30980bb2ff7SRichard Henderson     TyphoonState *s = opaque;
31067842165SRichard Henderson     uint64_t oldval, newval;
31180bb2ff7SRichard Henderson 
31280bb2ff7SRichard Henderson     switch (addr) {
31380bb2ff7SRichard Henderson     case 0x0000:
31480bb2ff7SRichard Henderson         /* CSC: Cchip System Configuration Register.  */
31580bb2ff7SRichard Henderson         /* All sorts of data here; nothing relevant RW.  */
31680bb2ff7SRichard Henderson         break;
31780bb2ff7SRichard Henderson 
31880bb2ff7SRichard Henderson     case 0x0040:
31980bb2ff7SRichard Henderson         /* MTR: Memory Timing Register.  */
32080bb2ff7SRichard Henderson         /* All sorts of stuff related to real DRAM.  */
32180bb2ff7SRichard Henderson         break;
32280bb2ff7SRichard Henderson 
32380bb2ff7SRichard Henderson     case 0x0080:
32480bb2ff7SRichard Henderson         /* MISC: Miscellaneous Register.  */
32580bb2ff7SRichard Henderson         newval = oldval = s->cchip.misc;
32680bb2ff7SRichard Henderson         newval &= ~(val & 0x10000ff0);     /* W1C fields */
32780bb2ff7SRichard Henderson         if (val & 0x100000) {
32880bb2ff7SRichard Henderson             newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
32980bb2ff7SRichard Henderson         } else {
33080bb2ff7SRichard Henderson             newval |= val & 0x00f00000;    /* ABT field is W1S */
33180bb2ff7SRichard Henderson             if ((newval & 0xf0000) == 0) {
33280bb2ff7SRichard Henderson                 newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
33380bb2ff7SRichard Henderson             }
33480bb2ff7SRichard Henderson         }
33580bb2ff7SRichard Henderson         newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
33680bb2ff7SRichard Henderson 
33780bb2ff7SRichard Henderson         newval &= ~0xf0000000000ull;       /* WO and RW fields */
33880bb2ff7SRichard Henderson         newval |= val & 0xf0000000000ull;
33980bb2ff7SRichard Henderson         s->cchip.misc = newval;
34080bb2ff7SRichard Henderson 
34180bb2ff7SRichard Henderson         /* Pass on changes to IPI and ITI state.  */
34280bb2ff7SRichard Henderson         if ((newval ^ oldval) & 0xff0) {
34380bb2ff7SRichard Henderson             int i;
34480bb2ff7SRichard Henderson             for (i = 0; i < 4; ++i) {
345ad601177SAndreas Färber                 AlphaCPU *cpu = s->cchip.cpu[i];
346ad601177SAndreas Färber                 if (cpu != NULL) {
347d8ed887bSAndreas Färber                     CPUState *cs = CPU(cpu);
34880bb2ff7SRichard Henderson                     /* IPI can be either cleared or set by the write.  */
34980bb2ff7SRichard Henderson                     if (newval & (1 << (i + 8))) {
350c3affe56SAndreas Färber                         cpu_interrupt(cs, CPU_INTERRUPT_SMP);
35180bb2ff7SRichard Henderson                     } else {
352d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
35380bb2ff7SRichard Henderson                     }
35480bb2ff7SRichard Henderson 
35580bb2ff7SRichard Henderson                     /* ITI can only be cleared by the write.  */
35680bb2ff7SRichard Henderson                     if ((newval & (1 << (i + 4))) == 0) {
357d8ed887bSAndreas Färber                         cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
35880bb2ff7SRichard Henderson                     }
35980bb2ff7SRichard Henderson                 }
36080bb2ff7SRichard Henderson             }
36180bb2ff7SRichard Henderson         }
36280bb2ff7SRichard Henderson         break;
36380bb2ff7SRichard Henderson 
36480bb2ff7SRichard Henderson     case 0x00c0:
36580bb2ff7SRichard Henderson         /* MPD: Memory Presence Detect Register.  */
36680bb2ff7SRichard Henderson         break;
36780bb2ff7SRichard Henderson 
36880bb2ff7SRichard Henderson     case 0x0100: /* AAR0 */
36980bb2ff7SRichard Henderson     case 0x0140: /* AAR1 */
37080bb2ff7SRichard Henderson     case 0x0180: /* AAR2 */
37180bb2ff7SRichard Henderson     case 0x01c0: /* AAR3 */
37280bb2ff7SRichard Henderson         /* AAR: Array Address Register.  */
37380bb2ff7SRichard Henderson         /* All sorts of information about DRAM.  */
37480bb2ff7SRichard Henderson         break;
37580bb2ff7SRichard Henderson 
37680bb2ff7SRichard Henderson     case 0x0200: /* DIM0 */
37780bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU0.  */
37880bb2ff7SRichard Henderson         s->cchip.dim[0] = val;
37980bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
38080bb2ff7SRichard Henderson         break;
38180bb2ff7SRichard Henderson     case 0x0240: /* DIM1 */
38280bb2ff7SRichard Henderson         /* DIM: Device Interrupt Mask Register, CPU1.  */
383424ad838SRichard Henderson         s->cchip.dim[1] = val;
38480bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
38580bb2ff7SRichard Henderson         break;
38680bb2ff7SRichard Henderson 
38780bb2ff7SRichard Henderson     case 0x0280: /* DIR0 (RO) */
38880bb2ff7SRichard Henderson     case 0x02c0: /* DIR1 (RO) */
38980bb2ff7SRichard Henderson     case 0x0300: /* DRIR (RO) */
39080bb2ff7SRichard Henderson         break;
39180bb2ff7SRichard Henderson 
39280bb2ff7SRichard Henderson     case 0x0340:
39380bb2ff7SRichard Henderson         /* PRBEN: Probe Enable Register.  */
39480bb2ff7SRichard Henderson         break;
39580bb2ff7SRichard Henderson 
39680bb2ff7SRichard Henderson     case 0x0380: /* IIC0 */
39780bb2ff7SRichard Henderson         s->cchip.iic[0] = val & 0xffffff;
39880bb2ff7SRichard Henderson         break;
39980bb2ff7SRichard Henderson     case 0x03c0: /* IIC1 */
40080bb2ff7SRichard Henderson         s->cchip.iic[1] = val & 0xffffff;
40180bb2ff7SRichard Henderson         break;
40280bb2ff7SRichard Henderson 
40380bb2ff7SRichard Henderson     case 0x0400: /* MPR0 */
40480bb2ff7SRichard Henderson     case 0x0440: /* MPR1 */
40580bb2ff7SRichard Henderson     case 0x0480: /* MPR2 */
40680bb2ff7SRichard Henderson     case 0x04c0: /* MPR3 */
40780bb2ff7SRichard Henderson         /* MPR: Memory Programming Register.  */
40880bb2ff7SRichard Henderson         break;
40980bb2ff7SRichard Henderson 
41080bb2ff7SRichard Henderson     case 0x0580:
41180bb2ff7SRichard Henderson         /* TTR: TIGbus Timing Register.  */
41280bb2ff7SRichard Henderson         /* All sorts of stuff related to interrupt delivery timings.  */
41380bb2ff7SRichard Henderson         break;
41480bb2ff7SRichard Henderson     case 0x05c0:
41580bb2ff7SRichard Henderson         /* TDR: TIGbug Device Timing Register.  */
41680bb2ff7SRichard Henderson         break;
41780bb2ff7SRichard Henderson 
41880bb2ff7SRichard Henderson     case 0x0600:
41980bb2ff7SRichard Henderson         /* DIM2: Device Interrupt Mask Register, CPU2.  */
42080bb2ff7SRichard Henderson         s->cchip.dim[2] = val;
42180bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
42280bb2ff7SRichard Henderson         break;
42380bb2ff7SRichard Henderson     case 0x0640:
42480bb2ff7SRichard Henderson         /* DIM3: Device Interrupt Mask Register, CPU3.  */
42580bb2ff7SRichard Henderson         s->cchip.dim[3] = val;
42680bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
42780bb2ff7SRichard Henderson         break;
42880bb2ff7SRichard Henderson 
42980bb2ff7SRichard Henderson     case 0x0680: /* DIR2 (RO) */
43080bb2ff7SRichard Henderson     case 0x06c0: /* DIR3 (RO) */
43180bb2ff7SRichard Henderson         break;
43280bb2ff7SRichard Henderson 
43380bb2ff7SRichard Henderson     case 0x0700: /* IIC2 */
43480bb2ff7SRichard Henderson         s->cchip.iic[2] = val & 0xffffff;
43580bb2ff7SRichard Henderson         break;
43680bb2ff7SRichard Henderson     case 0x0740: /* IIC3 */
43780bb2ff7SRichard Henderson         s->cchip.iic[3] = val & 0xffffff;
43880bb2ff7SRichard Henderson         break;
43980bb2ff7SRichard Henderson 
44080bb2ff7SRichard Henderson     case 0x0780:
44180bb2ff7SRichard Henderson         /* PWR: Power Management Control.   */
44280bb2ff7SRichard Henderson         break;
44380bb2ff7SRichard Henderson 
44480bb2ff7SRichard Henderson     case 0x0c00: /* CMONCTLA */
44580bb2ff7SRichard Henderson     case 0x0c40: /* CMONCTLB */
44680bb2ff7SRichard Henderson     case 0x0c80: /* CMONCNT01 */
44780bb2ff7SRichard Henderson     case 0x0cc0: /* CMONCNT23 */
44880bb2ff7SRichard Henderson         break;
44980bb2ff7SRichard Henderson 
45080bb2ff7SRichard Henderson     default:
451b7ed683aSPeter Maydell         return MEMTX_ERROR;
45280bb2ff7SRichard Henderson     }
453b7ed683aSPeter Maydell 
454b7ed683aSPeter Maydell     return MEMTX_OK;
45580bb2ff7SRichard Henderson }
45680bb2ff7SRichard Henderson 
dchip_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)457a8170e5eSAvi Kivity static void dchip_write(void *opaque, hwaddr addr,
45880bb2ff7SRichard Henderson                         uint64_t val, unsigned size)
45980bb2ff7SRichard Henderson {
46080bb2ff7SRichard Henderson     /* Skip this.  It's all related to DRAM timing and setup.  */
46180bb2ff7SRichard Henderson }
46280bb2ff7SRichard Henderson 
pchip_write(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)463b7ed683aSPeter Maydell static MemTxResult pchip_write(void *opaque, hwaddr addr,
464b7ed683aSPeter Maydell                                uint64_t val, unsigned size,
465b7ed683aSPeter Maydell                                MemTxAttrs attrs)
46680bb2ff7SRichard Henderson {
46780bb2ff7SRichard Henderson     TyphoonState *s = opaque;
46867842165SRichard Henderson     uint64_t oldval;
46980bb2ff7SRichard Henderson 
47080bb2ff7SRichard Henderson     switch (addr) {
47180bb2ff7SRichard Henderson     case 0x0000:
47280bb2ff7SRichard Henderson         /* WSBA0: Window Space Base Address Register.  */
473b83c4db8SRichard Henderson         s->pchip.win[0].wba = val & 0xfff00003u;
47480bb2ff7SRichard Henderson         break;
47580bb2ff7SRichard Henderson     case 0x0040:
47680bb2ff7SRichard Henderson         /* WSBA1 */
477b83c4db8SRichard Henderson         s->pchip.win[1].wba = val & 0xfff00003u;
47880bb2ff7SRichard Henderson         break;
47980bb2ff7SRichard Henderson     case 0x0080:
48080bb2ff7SRichard Henderson         /* WSBA2 */
481b83c4db8SRichard Henderson         s->pchip.win[2].wba = val & 0xfff00003u;
48280bb2ff7SRichard Henderson         break;
48380bb2ff7SRichard Henderson     case 0x00c0:
48480bb2ff7SRichard Henderson         /* WSBA3 */
485b83c4db8SRichard Henderson         s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
48680bb2ff7SRichard Henderson         break;
48780bb2ff7SRichard Henderson 
48880bb2ff7SRichard Henderson     case 0x0100:
48980bb2ff7SRichard Henderson         /* WSM0: Window Space Mask Register.  */
490b83c4db8SRichard Henderson         s->pchip.win[0].wsm = val & 0xfff00000u;
49180bb2ff7SRichard Henderson         break;
49280bb2ff7SRichard Henderson     case 0x0140:
49380bb2ff7SRichard Henderson         /* WSM1 */
494b83c4db8SRichard Henderson         s->pchip.win[1].wsm = val & 0xfff00000u;
49580bb2ff7SRichard Henderson         break;
49680bb2ff7SRichard Henderson     case 0x0180:
49780bb2ff7SRichard Henderson         /* WSM2 */
498b83c4db8SRichard Henderson         s->pchip.win[2].wsm = val & 0xfff00000u;
49980bb2ff7SRichard Henderson         break;
50080bb2ff7SRichard Henderson     case 0x01c0:
50180bb2ff7SRichard Henderson         /* WSM3 */
502b83c4db8SRichard Henderson         s->pchip.win[3].wsm = val & 0xfff00000u;
50380bb2ff7SRichard Henderson         break;
50480bb2ff7SRichard Henderson 
50580bb2ff7SRichard Henderson     case 0x0200:
50680bb2ff7SRichard Henderson         /* TBA0: Translated Base Address Register.  */
507b83c4db8SRichard Henderson         s->pchip.win[0].tba = val & 0x7fffffc00ull;
50880bb2ff7SRichard Henderson         break;
50980bb2ff7SRichard Henderson     case 0x0240:
51080bb2ff7SRichard Henderson         /* TBA1 */
511b83c4db8SRichard Henderson         s->pchip.win[1].tba = val & 0x7fffffc00ull;
51280bb2ff7SRichard Henderson         break;
51380bb2ff7SRichard Henderson     case 0x0280:
51480bb2ff7SRichard Henderson         /* TBA2 */
515b83c4db8SRichard Henderson         s->pchip.win[2].tba = val & 0x7fffffc00ull;
51680bb2ff7SRichard Henderson         break;
51780bb2ff7SRichard Henderson     case 0x02c0:
51880bb2ff7SRichard Henderson         /* TBA3 */
519b83c4db8SRichard Henderson         s->pchip.win[3].tba = val & 0x7fffffc00ull;
52080bb2ff7SRichard Henderson         break;
52180bb2ff7SRichard Henderson 
52280bb2ff7SRichard Henderson     case 0x0300:
52380bb2ff7SRichard Henderson         /* PCTL: Pchip Control Register.  */
52480bb2ff7SRichard Henderson         oldval = s->pchip.ctl;
52580bb2ff7SRichard Henderson         oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
52680bb2ff7SRichard Henderson         oldval |= val & 0x00001cff0fc7ffull;
52780bb2ff7SRichard Henderson         s->pchip.ctl = oldval;
52880bb2ff7SRichard Henderson         break;
52980bb2ff7SRichard Henderson 
53080bb2ff7SRichard Henderson     case 0x0340:
53180bb2ff7SRichard Henderson         /* PLAT: Pchip Master Latency Register.  */
53280bb2ff7SRichard Henderson         break;
53380bb2ff7SRichard Henderson     case 0x03c0:
53480bb2ff7SRichard Henderson         /* PERROR: Pchip Error Register.  */
53580bb2ff7SRichard Henderson         break;
53680bb2ff7SRichard Henderson     case 0x0400:
53780bb2ff7SRichard Henderson         /* PERRMASK: Pchip Error Mask Register.  */
53880bb2ff7SRichard Henderson         break;
53980bb2ff7SRichard Henderson     case 0x0440:
54080bb2ff7SRichard Henderson         /* PERRSET: Pchip Error Set Register.  */
54180bb2ff7SRichard Henderson         break;
54280bb2ff7SRichard Henderson 
54380bb2ff7SRichard Henderson     case 0x0480:
54480bb2ff7SRichard Henderson         /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
54580bb2ff7SRichard Henderson         break;
54680bb2ff7SRichard Henderson 
54780bb2ff7SRichard Henderson     case 0x04c0:
54880bb2ff7SRichard Henderson         /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
54980bb2ff7SRichard Henderson         break;
55080bb2ff7SRichard Henderson 
55180bb2ff7SRichard Henderson     case 0x0500:
55280bb2ff7SRichard Henderson         /* PMONCTL */
55380bb2ff7SRichard Henderson     case 0x0540:
55480bb2ff7SRichard Henderson         /* PMONCNT */
55580bb2ff7SRichard Henderson     case 0x0800:
55680bb2ff7SRichard Henderson         /* SPRST */
55780bb2ff7SRichard Henderson         break;
55880bb2ff7SRichard Henderson 
55980bb2ff7SRichard Henderson     default:
560b7ed683aSPeter Maydell         return MEMTX_ERROR;
56180bb2ff7SRichard Henderson     }
562b7ed683aSPeter Maydell 
563b7ed683aSPeter Maydell     return MEMTX_OK;
56480bb2ff7SRichard Henderson }
56580bb2ff7SRichard Henderson 
56680bb2ff7SRichard Henderson static const MemoryRegionOps cchip_ops = {
567b7ed683aSPeter Maydell     .read_with_attrs = cchip_read,
568b7ed683aSPeter Maydell     .write_with_attrs = cchip_write,
56980bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
57080bb2ff7SRichard Henderson     .valid = {
57167842165SRichard Henderson         .min_access_size = 8,
57280bb2ff7SRichard Henderson         .max_access_size = 8,
57380bb2ff7SRichard Henderson     },
57480bb2ff7SRichard Henderson     .impl = {
57567842165SRichard Henderson         .min_access_size = 8,
57667842165SRichard Henderson         .max_access_size = 8,
57780bb2ff7SRichard Henderson     },
57880bb2ff7SRichard Henderson };
57980bb2ff7SRichard Henderson 
58080bb2ff7SRichard Henderson static const MemoryRegionOps dchip_ops = {
58180bb2ff7SRichard Henderson     .read = dchip_read,
58280bb2ff7SRichard Henderson     .write = dchip_write,
58380bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
58480bb2ff7SRichard Henderson     .valid = {
58567842165SRichard Henderson         .min_access_size = 8,
58680bb2ff7SRichard Henderson         .max_access_size = 8,
58780bb2ff7SRichard Henderson     },
58880bb2ff7SRichard Henderson     .impl = {
58967842165SRichard Henderson         .min_access_size = 8,
59080bb2ff7SRichard Henderson         .max_access_size = 8,
59180bb2ff7SRichard Henderson     },
59280bb2ff7SRichard Henderson };
59380bb2ff7SRichard Henderson 
59480bb2ff7SRichard Henderson static const MemoryRegionOps pchip_ops = {
595b7ed683aSPeter Maydell     .read_with_attrs = pchip_read,
596b7ed683aSPeter Maydell     .write_with_attrs = pchip_write,
59780bb2ff7SRichard Henderson     .endianness = DEVICE_LITTLE_ENDIAN,
59880bb2ff7SRichard Henderson     .valid = {
59967842165SRichard Henderson         .min_access_size = 8,
60080bb2ff7SRichard Henderson         .max_access_size = 8,
60180bb2ff7SRichard Henderson     },
60280bb2ff7SRichard Henderson     .impl = {
60367842165SRichard Henderson         .min_access_size = 8,
60467842165SRichard Henderson         .max_access_size = 8,
60580bb2ff7SRichard Henderson     },
60680bb2ff7SRichard Henderson };
60780bb2ff7SRichard Henderson 
608b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
609b83c4db8SRichard Henderson    using the given translated address and mask.  */
make_iommu_tlbe(hwaddr taddr,hwaddr mask,IOMMUTLBEntry * ret)610b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
611b83c4db8SRichard Henderson {
612b83c4db8SRichard Henderson     *ret = (IOMMUTLBEntry) {
613b83c4db8SRichard Henderson         .target_as = &address_space_memory,
614b83c4db8SRichard Henderson         .translated_addr = taddr,
615b83c4db8SRichard Henderson         .addr_mask = mask,
616b83c4db8SRichard Henderson         .perm = IOMMU_RW,
617b83c4db8SRichard Henderson     };
618b83c4db8SRichard Henderson     return true;
619b83c4db8SRichard Henderson }
620b83c4db8SRichard Henderson 
621b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather
622b83c4db8SRichard Henderson    translation, given the address of the PTE.  */
pte_translate(hwaddr pte_addr,IOMMUTLBEntry * ret)623b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
624b83c4db8SRichard Henderson {
62542874d3aSPeter Maydell     uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
62642874d3aSPeter Maydell                                      MEMTXATTRS_UNSPECIFIED, NULL);
627b83c4db8SRichard Henderson 
628b83c4db8SRichard Henderson     /* Check valid bit.  */
629b83c4db8SRichard Henderson     if ((pte & 1) == 0) {
630b83c4db8SRichard Henderson         return false;
631b83c4db8SRichard Henderson     }
632b83c4db8SRichard Henderson 
633b83c4db8SRichard Henderson     return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
634b83c4db8SRichard Henderson }
635b83c4db8SRichard Henderson 
636b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the
637b83c4db8SRichard Henderson    four single-address-cycle translation windows.  */
window_translate(TyphoonWindow * win,hwaddr addr,IOMMUTLBEntry * ret)638b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr,
639b83c4db8SRichard Henderson                              IOMMUTLBEntry *ret)
640b83c4db8SRichard Henderson {
641b83c4db8SRichard Henderson     uint32_t wba = win->wba;
642b83c4db8SRichard Henderson     uint64_t wsm = win->wsm;
643b83c4db8SRichard Henderson     uint64_t tba = win->tba;
644b83c4db8SRichard Henderson     uint64_t wsm_ext = wsm | 0xfffff;
645b83c4db8SRichard Henderson 
646b83c4db8SRichard Henderson     /* Check for window disabled.  */
647b83c4db8SRichard Henderson     if ((wba & 1) == 0) {
648b83c4db8SRichard Henderson         return false;
649b83c4db8SRichard Henderson     }
650b83c4db8SRichard Henderson 
651b83c4db8SRichard Henderson     /* Check for window hit.  */
652b83c4db8SRichard Henderson     if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
653b83c4db8SRichard Henderson         return false;
654b83c4db8SRichard Henderson     }
655b83c4db8SRichard Henderson 
656b83c4db8SRichard Henderson     if (wba & 2) {
657b83c4db8SRichard Henderson         /* Scatter-gather translation.  */
658b83c4db8SRichard Henderson         hwaddr pte_addr;
659b83c4db8SRichard Henderson 
660b83c4db8SRichard Henderson         /* See table 10-6, Generating PTE address for PCI DMA Address.  */
661b83c4db8SRichard Henderson         pte_addr  = tba & ~(wsm >> 10);
662b83c4db8SRichard Henderson         pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
663b83c4db8SRichard Henderson         return pte_translate(pte_addr, ret);
664b83c4db8SRichard Henderson     } else {
665b83c4db8SRichard Henderson         /* Direct-mapped translation.  */
666b83c4db8SRichard Henderson         return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
667b83c4db8SRichard Henderson     }
668b83c4db8SRichard Henderson }
669b83c4db8SRichard Henderson 
670b83c4db8SRichard Henderson /* Handle PCI-to-system address translation.  */
671b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the
672b83c4db8SRichard Henderson    Pchip and generate a machine check interrupt.  */
typhoon_translate_iommu(IOMMUMemoryRegion * iommu,hwaddr addr,IOMMUAccessFlags flag,int iommu_idx)6733df9d748SAlexey Kardashevskiy static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
6743df9d748SAlexey Kardashevskiy                                              hwaddr addr,
6752c91bcf2SPeter Maydell                                              IOMMUAccessFlags flag,
6762c91bcf2SPeter Maydell                                              int iommu_idx)
677b83c4db8SRichard Henderson {
678b83c4db8SRichard Henderson     TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
679b83c4db8SRichard Henderson     IOMMUTLBEntry ret;
680b83c4db8SRichard Henderson     int i;
681b83c4db8SRichard Henderson 
682b83c4db8SRichard Henderson     if (addr <= 0xffffffffu) {
683b83c4db8SRichard Henderson         /* Single-address cycle.  */
684b83c4db8SRichard Henderson 
685b83c4db8SRichard Henderson         /* Check for the Window Hole, inhibiting matching.  */
686b83c4db8SRichard Henderson         if ((pchip->ctl & 0x20)
687b83c4db8SRichard Henderson             && addr >= 0x80000
688b83c4db8SRichard Henderson             && addr <= 0xfffff) {
689b83c4db8SRichard Henderson             goto failure;
690b83c4db8SRichard Henderson         }
691b83c4db8SRichard Henderson 
692b83c4db8SRichard Henderson         /* Check the first three windows.  */
693b83c4db8SRichard Henderson         for (i = 0; i < 3; ++i) {
694b83c4db8SRichard Henderson             if (window_translate(&pchip->win[i], addr, &ret)) {
695b83c4db8SRichard Henderson                 goto success;
696b83c4db8SRichard Henderson             }
697b83c4db8SRichard Henderson         }
698b83c4db8SRichard Henderson 
699b83c4db8SRichard Henderson         /* Check the fourth window for DAC disable.  */
700b83c4db8SRichard Henderson         if ((pchip->win[3].wba & 0x80000000000ull) == 0
701b83c4db8SRichard Henderson             && window_translate(&pchip->win[3], addr, &ret)) {
702b83c4db8SRichard Henderson             goto success;
703b83c4db8SRichard Henderson         }
704b83c4db8SRichard Henderson     } else {
705b83c4db8SRichard Henderson         /* Double-address cycle.  */
706b83c4db8SRichard Henderson 
707b83c4db8SRichard Henderson         if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
708b83c4db8SRichard Henderson             /* Check for the DMA monster window.  */
709b83c4db8SRichard Henderson             if (pchip->ctl & 0x40) {
710b83c4db8SRichard Henderson                 /* See 10.1.4.4; in particular <39:35> is ignored.  */
711b83c4db8SRichard Henderson                 make_iommu_tlbe(0, 0x007ffffffffull, &ret);
712b83c4db8SRichard Henderson                 goto success;
713b83c4db8SRichard Henderson             }
714b83c4db8SRichard Henderson         }
715b83c4db8SRichard Henderson 
7169b2caaf4SStefan Weil         if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) {
717b83c4db8SRichard Henderson             /* Check the fourth window for DAC enable and window enable.  */
718b83c4db8SRichard Henderson             if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
719b83c4db8SRichard Henderson                 uint64_t pte_addr;
720b83c4db8SRichard Henderson 
721b83c4db8SRichard Henderson                 pte_addr  = pchip->win[3].tba & 0x7ffc00000ull;
722b83c4db8SRichard Henderson                 pte_addr |= (addr & 0xffffe000u) >> 10;
723b83c4db8SRichard Henderson                 if (pte_translate(pte_addr, &ret)) {
724b83c4db8SRichard Henderson                         goto success;
725b83c4db8SRichard Henderson                 }
726b83c4db8SRichard Henderson             }
727b83c4db8SRichard Henderson         }
728b83c4db8SRichard Henderson     }
729b83c4db8SRichard Henderson 
730b83c4db8SRichard Henderson  failure:
731b83c4db8SRichard Henderson     ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
732b83c4db8SRichard Henderson  success:
733b83c4db8SRichard Henderson     return ret;
734b83c4db8SRichard Henderson }
735b83c4db8SRichard Henderson 
typhoon_pci_dma_iommu(PCIBus * bus,void * opaque,int devfn)736b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
737b83c4db8SRichard Henderson {
738b83c4db8SRichard Henderson     TyphoonState *s = opaque;
739b83c4db8SRichard Henderson     return &s->pchip.iommu_as;
740b83c4db8SRichard Henderson }
741b83c4db8SRichard Henderson 
742ba7d12ebSYi Liu static const PCIIOMMUOps typhoon_iommu_ops = {
743ba7d12ebSYi Liu     .get_address_space = typhoon_pci_dma_iommu,
744ba7d12ebSYi Liu };
745ba7d12ebSYi Liu 
typhoon_set_irq(void * opaque,int irq,int level)74680bb2ff7SRichard Henderson static void typhoon_set_irq(void *opaque, int irq, int level)
74780bb2ff7SRichard Henderson {
74880bb2ff7SRichard Henderson     TyphoonState *s = opaque;
74980bb2ff7SRichard Henderson     uint64_t drir;
75080bb2ff7SRichard Henderson     int i;
75180bb2ff7SRichard Henderson 
75280bb2ff7SRichard Henderson     /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
75380bb2ff7SRichard Henderson     drir = s->cchip.drir;
75480bb2ff7SRichard Henderson     if (level) {
75580bb2ff7SRichard Henderson         drir |= 1ull << irq;
75680bb2ff7SRichard Henderson     } else {
75780bb2ff7SRichard Henderson         drir &= ~(1ull << irq);
75880bb2ff7SRichard Henderson     }
75980bb2ff7SRichard Henderson     s->cchip.drir = drir;
76080bb2ff7SRichard Henderson 
76180bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
76280bb2ff7SRichard Henderson         cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
76380bb2ff7SRichard Henderson     }
76480bb2ff7SRichard Henderson }
76580bb2ff7SRichard Henderson 
typhoon_set_isa_irq(void * opaque,int irq,int level)76680bb2ff7SRichard Henderson static void typhoon_set_isa_irq(void *opaque, int irq, int level)
76780bb2ff7SRichard Henderson {
76880bb2ff7SRichard Henderson     typhoon_set_irq(opaque, 55, level);
76980bb2ff7SRichard Henderson }
77080bb2ff7SRichard Henderson 
typhoon_set_timer_irq(void * opaque,int irq,int level)77180bb2ff7SRichard Henderson static void typhoon_set_timer_irq(void *opaque, int irq, int level)
77280bb2ff7SRichard Henderson {
77380bb2ff7SRichard Henderson     TyphoonState *s = opaque;
77480bb2ff7SRichard Henderson     int i;
77580bb2ff7SRichard Henderson 
77680bb2ff7SRichard Henderson     /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
77780bb2ff7SRichard Henderson        and so we don't have to worry about missing interrupts just
77880bb2ff7SRichard Henderson        because we never actually ACK the interrupt.  Just ignore any
77980bb2ff7SRichard Henderson        case of the interrupt level going low.  */
78080bb2ff7SRichard Henderson     if (level == 0) {
78180bb2ff7SRichard Henderson         return;
78280bb2ff7SRichard Henderson     }
78380bb2ff7SRichard Henderson 
78480bb2ff7SRichard Henderson     /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
78580bb2ff7SRichard Henderson     for (i = 0; i < 4; ++i) {
786ad601177SAndreas Färber         AlphaCPU *cpu = s->cchip.cpu[i];
787ad601177SAndreas Färber         if (cpu != NULL) {
78880bb2ff7SRichard Henderson             uint32_t iic = s->cchip.iic[i];
78980bb2ff7SRichard Henderson 
79080bb2ff7SRichard Henderson             /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
79180bb2ff7SRichard Henderson                Bit 24 is the OverFlow bit, RO, and set when the count
79280bb2ff7SRichard Henderson                decrements past 0.  When is OF cleared?  My guess is that
79380bb2ff7SRichard Henderson                OF is actually cleared when the IIC is written, and that
79480bb2ff7SRichard Henderson                the ICNT field always decrements.  At least, that's an
79580bb2ff7SRichard Henderson                interpretation that makes sense, and "allows the CPU to
79680bb2ff7SRichard Henderson                determine exactly how mant interval timer ticks were
79780bb2ff7SRichard Henderson                skipped".  At least within the next 4M ticks...  */
79880bb2ff7SRichard Henderson 
79980bb2ff7SRichard Henderson             iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
80080bb2ff7SRichard Henderson             s->cchip.iic[i] = iic;
80180bb2ff7SRichard Henderson 
80280bb2ff7SRichard Henderson             if (iic & 0x1000000) {
80380bb2ff7SRichard Henderson                 /* Set the ITI bit for this cpu.  */
80480bb2ff7SRichard Henderson                 s->cchip.misc |= 1 << (i + 4);
80580bb2ff7SRichard Henderson                 /* And signal the interrupt.  */
806c3affe56SAndreas Färber                 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
80780bb2ff7SRichard Henderson             }
80880bb2ff7SRichard Henderson         }
80980bb2ff7SRichard Henderson     }
81080bb2ff7SRichard Henderson }
81180bb2ff7SRichard Henderson 
typhoon_alarm_timer(void * opaque)812c781cf96SRichard Henderson static void typhoon_alarm_timer(void *opaque)
813c781cf96SRichard Henderson {
814c781cf96SRichard Henderson     TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
815c781cf96SRichard Henderson     int cpu = (uintptr_t)opaque & 3;
816c781cf96SRichard Henderson 
817c781cf96SRichard Henderson     /* Set the ITI bit for this cpu.  */
818c781cf96SRichard Henderson     s->cchip.misc |= 1 << (cpu + 4);
819c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
820c781cf96SRichard Henderson }
821c781cf96SRichard Henderson 
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)8225ec4f1d3SJason Thorpe PCIBus *typhoon_init(MemoryRegion *ram, qemu_irq *p_isa_irq,
8235ec4f1d3SJason Thorpe                      qemu_irq *p_rtc_irq, AlphaCPU *cpus[4],
8245ec4f1d3SJason Thorpe                      pci_map_irq_fn sys_map_irq, uint8_t devfn_min)
82580bb2ff7SRichard Henderson {
82680bb2ff7SRichard Henderson     MemoryRegion *addr_space = get_system_memory();
82780bb2ff7SRichard Henderson     DeviceState *dev;
82880bb2ff7SRichard Henderson     TyphoonState *s;
82994dd91d6SAndreas Färber     PCIHostState *phb;
83080bb2ff7SRichard Henderson     PCIBus *b;
831c781cf96SRichard Henderson     int i;
83280bb2ff7SRichard Henderson 
8333e80f690SMarkus Armbruster     dev = qdev_new(TYPE_TYPHOON_PCI_HOST_BRIDGE);
83480bb2ff7SRichard Henderson 
83594dd91d6SAndreas Färber     s = TYPHOON_PCI_HOST_BRIDGE(dev);
8368558d942SAndreas Färber     phb = PCI_HOST_BRIDGE(dev);
83780bb2ff7SRichard Henderson 
838b83c4db8SRichard Henderson     s->cchip.misc = 0x800000000ull; /* Revision: Typhoon.  */
839b83c4db8SRichard Henderson     s->pchip.win[3].wba = 2;        /* Window 3 SG always enabled. */
840b83c4db8SRichard Henderson 
84180bb2ff7SRichard Henderson     /* Remember the CPUs so that we can deliver interrupts to them.  */
842c781cf96SRichard Henderson     for (i = 0; i < 4; i++) {
843ad601177SAndreas Färber         AlphaCPU *cpu = cpus[i];
844ad601177SAndreas Färber         s->cchip.cpu[i] = cpu;
845ad601177SAndreas Färber         if (cpu != NULL) {
846bc72ad67SAlex Bligh             cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
847c781cf96SRichard Henderson                                                  typhoon_alarm_timer,
848c781cf96SRichard Henderson                                                  (void *)((uintptr_t)s + i));
849c781cf96SRichard Henderson         }
850c781cf96SRichard Henderson     }
85180bb2ff7SRichard Henderson 
8525ec4f1d3SJason Thorpe     *p_isa_irq = qemu_allocate_irq(typhoon_set_isa_irq, s, 0);
85354292736SShannon Zhao     *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
85480bb2ff7SRichard Henderson 
85580bb2ff7SRichard Henderson     /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
85680bb2ff7SRichard Henderson        but the address space hole reserved at this point is 8TB.  */
857b844d822SIgor Mammedov     memory_region_add_subregion(addr_space, 0, ram);
85880bb2ff7SRichard Henderson 
85980bb2ff7SRichard Henderson     /* TIGbus, 0x801.0000.0000, 1GB.  */
86080bb2ff7SRichard Henderson     /* ??? The TIGbus is used for delivering interrupts, and access to
86180bb2ff7SRichard Henderson        the flash ROM.  I'm not sure that we need to implement it at all.  */
86280bb2ff7SRichard Henderson 
86380bb2ff7SRichard Henderson     /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
86464bde0f3SPaolo Bonzini     memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
8652b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
86602d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80180000000ULL,
86702d6516cSStefan Weil                                 &s->pchip.region);
86880bb2ff7SRichard Henderson 
86980bb2ff7SRichard Henderson     /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
87064bde0f3SPaolo Bonzini     memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
8712b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
87202d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801a0000000ULL,
87302d6516cSStefan Weil                                 &s->cchip.region);
87480bb2ff7SRichard Henderson 
87580bb2ff7SRichard Henderson     /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
87664bde0f3SPaolo Bonzini     memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
8772b41742aSPhilippe Mathieu-Daudé                           256 * MiB);
87802d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801b0000000ULL,
87902d6516cSStefan Weil                                 &s->dchip_region);
88080bb2ff7SRichard Henderson 
88180bb2ff7SRichard Henderson     /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
8822b41742aSPhilippe Mathieu-Daudé     memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4 * GiB);
88302d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x80000000000ULL,
88402d6516cSStefan Weil                                 &s->pchip.reg_mem);
88580bb2ff7SRichard Henderson 
88680bb2ff7SRichard Henderson     /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
8873661049fSRichard Henderson     memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops,
8882b41742aSPhilippe Mathieu-Daudé                           NULL, "pci0-io", 32 * MiB);
88902d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fc000000ULL,
89002d6516cSStefan Weil                                 &s->pchip.reg_io);
89180bb2ff7SRichard Henderson 
8921115ff6dSDavid Gibson     b = pci_register_root_bus(dev, "pci",
89380bb2ff7SRichard Henderson                               typhoon_set_irq, sys_map_irq, s,
894056e6baeSRichard Henderson                               &s->pchip.reg_mem, &s->pchip.reg_io,
8953a8233dcSJason Thorpe                               devfn_min, 64, TYPE_PCI_BUS);
89694dd91d6SAndreas Färber     phb->bus = b;
8973c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
89880bb2ff7SRichard Henderson 
899b83c4db8SRichard Henderson     /* Host memory as seen from the PCI side, via the IOMMU.  */
9001221a474SAlexey Kardashevskiy     memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu),
9011221a474SAlexey Kardashevskiy                              TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s),
902b83c4db8SRichard Henderson                              "iommu-typhoon", UINT64_MAX);
9033df9d748SAlexey Kardashevskiy     address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
9043df9d748SAlexey Kardashevskiy                        "pchip0-pci");
905ba7d12ebSYi Liu     pci_setup_iommu(b, &typhoon_iommu_ops, s);
906b83c4db8SRichard Henderson 
90780bb2ff7SRichard Henderson     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
908056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
9092b41742aSPhilippe Mathieu-Daudé                           b, "pci0-iack", 64 * MiB);
91002d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801f8000000ULL,
91102d6516cSStefan Weil                                 &s->pchip.reg_iack);
91280bb2ff7SRichard Henderson 
91380bb2ff7SRichard Henderson     /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
914056e6baeSRichard Henderson     memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
9152b41742aSPhilippe Mathieu-Daudé                           b, "pci0-conf", 16 * MiB);
91602d6516cSStefan Weil     memory_region_add_subregion(addr_space, 0x801fe000000ULL,
91702d6516cSStefan Weil                                 &s->pchip.reg_conf);
91880bb2ff7SRichard Henderson 
91980bb2ff7SRichard Henderson     /* For the record, these are the mappings for the second PCI bus.
92080bb2ff7SRichard Henderson        We can get away with not implementing them because we indicate
92180bb2ff7SRichard Henderson        via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
92280bb2ff7SRichard Henderson     /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
92380bb2ff7SRichard Henderson     /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
92480bb2ff7SRichard Henderson     /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
92580bb2ff7SRichard Henderson     /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
92680bb2ff7SRichard Henderson     /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
92780bb2ff7SRichard Henderson 
92880bb2ff7SRichard Henderson     return b;
92980bb2ff7SRichard Henderson }
93080bb2ff7SRichard Henderson 
9314240abffSAndreas Färber static const TypeInfo typhoon_pcihost_info = {
93294dd91d6SAndreas Färber     .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
9338558d942SAndreas Färber     .parent        = TYPE_PCI_HOST_BRIDGE,
93439bffca2SAnthony Liguori     .instance_size = sizeof(TyphoonState),
93580bb2ff7SRichard Henderson };
93680bb2ff7SRichard Henderson 
typhoon_iommu_memory_region_class_init(ObjectClass * klass,const void * data)9371221a474SAlexey Kardashevskiy static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
938*12d1a768SPhilippe Mathieu-Daudé                                                    const void *data)
9391221a474SAlexey Kardashevskiy {
9401221a474SAlexey Kardashevskiy     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
9411221a474SAlexey Kardashevskiy 
9421221a474SAlexey Kardashevskiy     imrc->translate = typhoon_translate_iommu;
9431221a474SAlexey Kardashevskiy }
9441221a474SAlexey Kardashevskiy 
9451221a474SAlexey Kardashevskiy static const TypeInfo typhoon_iommu_memory_region_info = {
9461221a474SAlexey Kardashevskiy     .parent = TYPE_IOMMU_MEMORY_REGION,
9471221a474SAlexey Kardashevskiy     .name = TYPE_TYPHOON_IOMMU_MEMORY_REGION,
9481221a474SAlexey Kardashevskiy     .class_init = typhoon_iommu_memory_region_class_init,
9491221a474SAlexey Kardashevskiy };
9501221a474SAlexey Kardashevskiy 
typhoon_register_types(void)95183f7d43aSAndreas Färber static void typhoon_register_types(void)
95280bb2ff7SRichard Henderson {
95339bffca2SAnthony Liguori     type_register_static(&typhoon_pcihost_info);
9541221a474SAlexey Kardashevskiy     type_register_static(&typhoon_iommu_memory_region_info);
95580bb2ff7SRichard Henderson }
95683f7d43aSAndreas Färber 
95783f7d43aSAndreas Färber type_init(typhoon_register_types)
958