1c0907c9eSPaolo Bonzini /*
2c0907c9eSPaolo Bonzini * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
3c0907c9eSPaolo Bonzini *
4c0907c9eSPaolo Bonzini * Written by Richard Henderson.
5c0907c9eSPaolo Bonzini *
6c0907c9eSPaolo Bonzini * This work is licensed under the GNU GPL license version 2 or later.
7c0907c9eSPaolo Bonzini */
8c0907c9eSPaolo Bonzini
9e2e5e114SPeter Maydell #include "qemu/osdep.h"
100b8fa32fSMarkus Armbruster #include "qemu/module.h"
112b41742aSPhilippe Mathieu-Daudé #include "qemu/units.h"
12da34e65cSMarkus Armbruster #include "qapi/error.h"
13674b0a57SMarkus Armbruster #include "hw/pci/pci_host.h"
14c0907c9eSPaolo Bonzini #include "cpu.h"
1564552b6bSMarkus Armbruster #include "hw/irq.h"
1647b43a1fSPaolo Bonzini #include "alpha_sys.h"
17c0907c9eSPaolo Bonzini
18c0907c9eSPaolo Bonzini
19c0907c9eSPaolo Bonzini #define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
201221a474SAlexey Kardashevskiy #define TYPE_TYPHOON_IOMMU_MEMORY_REGION "typhoon-iommu-memory-region"
21c0907c9eSPaolo Bonzini
22c0907c9eSPaolo Bonzini typedef struct TyphoonCchip {
23c0907c9eSPaolo Bonzini MemoryRegion region;
24c0907c9eSPaolo Bonzini uint64_t misc;
25c0907c9eSPaolo Bonzini uint64_t drir;
26c0907c9eSPaolo Bonzini uint64_t dim[4];
27c0907c9eSPaolo Bonzini uint32_t iic[4];
28c0907c9eSPaolo Bonzini AlphaCPU *cpu[4];
29c0907c9eSPaolo Bonzini } TyphoonCchip;
30c0907c9eSPaolo Bonzini
31c0907c9eSPaolo Bonzini typedef struct TyphoonWindow {
32b83c4db8SRichard Henderson uint64_t wba;
33b83c4db8SRichard Henderson uint64_t wsm;
34b83c4db8SRichard Henderson uint64_t tba;
35c0907c9eSPaolo Bonzini } TyphoonWindow;
36c0907c9eSPaolo Bonzini
37c0907c9eSPaolo Bonzini typedef struct TyphoonPchip {
38c0907c9eSPaolo Bonzini MemoryRegion region;
39c0907c9eSPaolo Bonzini MemoryRegion reg_iack;
40c0907c9eSPaolo Bonzini MemoryRegion reg_mem;
41c0907c9eSPaolo Bonzini MemoryRegion reg_io;
42c0907c9eSPaolo Bonzini MemoryRegion reg_conf;
43b83c4db8SRichard Henderson
44b83c4db8SRichard Henderson AddressSpace iommu_as;
453df9d748SAlexey Kardashevskiy IOMMUMemoryRegion iommu;
46b83c4db8SRichard Henderson
47c0907c9eSPaolo Bonzini uint64_t ctl;
48c0907c9eSPaolo Bonzini TyphoonWindow win[4];
49c0907c9eSPaolo Bonzini } TyphoonPchip;
50c0907c9eSPaolo Bonzini
518063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(TyphoonState, TYPHOON_PCI_HOST_BRIDGE)
52c0907c9eSPaolo Bonzini
53db1015e9SEduardo Habkost struct TyphoonState {
54c0907c9eSPaolo Bonzini PCIHostState parent_obj;
55c0907c9eSPaolo Bonzini
56c0907c9eSPaolo Bonzini TyphoonCchip cchip;
57c0907c9eSPaolo Bonzini TyphoonPchip pchip;
58c0907c9eSPaolo Bonzini MemoryRegion dchip_region;
59db1015e9SEduardo Habkost };
60c0907c9eSPaolo Bonzini
61c0907c9eSPaolo Bonzini /* Called when one of DRIR or DIM changes. */
cpu_irq_change(AlphaCPU * cpu,uint64_t req)62c0907c9eSPaolo Bonzini static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
63c0907c9eSPaolo Bonzini {
64c0907c9eSPaolo Bonzini /* If there are any non-masked interrupts, tell the cpu. */
65c0907c9eSPaolo Bonzini if (cpu != NULL) {
66c0907c9eSPaolo Bonzini CPUState *cs = CPU(cpu);
67c0907c9eSPaolo Bonzini if (req) {
68c0907c9eSPaolo Bonzini cpu_interrupt(cs, CPU_INTERRUPT_HARD);
69c0907c9eSPaolo Bonzini } else {
70c0907c9eSPaolo Bonzini cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
71c0907c9eSPaolo Bonzini }
72c0907c9eSPaolo Bonzini }
73c0907c9eSPaolo Bonzini }
74c0907c9eSPaolo Bonzini
cchip_read(void * opaque,hwaddr addr,uint64_t * data,unsigned size,MemTxAttrs attrs)75b7ed683aSPeter Maydell static MemTxResult cchip_read(void *opaque, hwaddr addr,
76b7ed683aSPeter Maydell uint64_t *data, unsigned size,
77b7ed683aSPeter Maydell MemTxAttrs attrs)
78c0907c9eSPaolo Bonzini {
794917cf44SAndreas Färber CPUState *cpu = current_cpu;
80c0907c9eSPaolo Bonzini TyphoonState *s = opaque;
81c0907c9eSPaolo Bonzini uint64_t ret = 0;
82c0907c9eSPaolo Bonzini
83c0907c9eSPaolo Bonzini switch (addr) {
84c0907c9eSPaolo Bonzini case 0x0000:
85c0907c9eSPaolo Bonzini /* CSC: Cchip System Configuration Register. */
86c0907c9eSPaolo Bonzini /* All sorts of data here; probably the only thing relevant is
87c0907c9eSPaolo Bonzini PIP<14> Pchip 1 Present = 0. */
88c0907c9eSPaolo Bonzini break;
89c0907c9eSPaolo Bonzini
90c0907c9eSPaolo Bonzini case 0x0040:
91c0907c9eSPaolo Bonzini /* MTR: Memory Timing Register. */
92c0907c9eSPaolo Bonzini /* All sorts of stuff related to real DRAM. */
93c0907c9eSPaolo Bonzini break;
94c0907c9eSPaolo Bonzini
95c0907c9eSPaolo Bonzini case 0x0080:
96c0907c9eSPaolo Bonzini /* MISC: Miscellaneous Register. */
97c0907c9eSPaolo Bonzini ret = s->cchip.misc | (cpu->cpu_index & 3);
98c0907c9eSPaolo Bonzini break;
99c0907c9eSPaolo Bonzini
100c0907c9eSPaolo Bonzini case 0x00c0:
101c0907c9eSPaolo Bonzini /* MPD: Memory Presence Detect Register. */
102c0907c9eSPaolo Bonzini break;
103c0907c9eSPaolo Bonzini
104c0907c9eSPaolo Bonzini case 0x0100: /* AAR0 */
105c0907c9eSPaolo Bonzini case 0x0140: /* AAR1 */
106c0907c9eSPaolo Bonzini case 0x0180: /* AAR2 */
107c0907c9eSPaolo Bonzini case 0x01c0: /* AAR3 */
108c0907c9eSPaolo Bonzini /* AAR: Array Address Register. */
109c0907c9eSPaolo Bonzini /* All sorts of information about DRAM. */
110c0907c9eSPaolo Bonzini break;
111c0907c9eSPaolo Bonzini
112c0907c9eSPaolo Bonzini case 0x0200:
113c0907c9eSPaolo Bonzini /* DIM0: Device Interrupt Mask Register, CPU0. */
114c0907c9eSPaolo Bonzini ret = s->cchip.dim[0];
115c0907c9eSPaolo Bonzini break;
116c0907c9eSPaolo Bonzini case 0x0240:
117c0907c9eSPaolo Bonzini /* DIM1: Device Interrupt Mask Register, CPU1. */
118c0907c9eSPaolo Bonzini ret = s->cchip.dim[1];
119c0907c9eSPaolo Bonzini break;
120c0907c9eSPaolo Bonzini case 0x0280:
121c0907c9eSPaolo Bonzini /* DIR0: Device Interrupt Request Register, CPU0. */
122c0907c9eSPaolo Bonzini ret = s->cchip.dim[0] & s->cchip.drir;
123c0907c9eSPaolo Bonzini break;
124c0907c9eSPaolo Bonzini case 0x02c0:
125c0907c9eSPaolo Bonzini /* DIR1: Device Interrupt Request Register, CPU1. */
126c0907c9eSPaolo Bonzini ret = s->cchip.dim[1] & s->cchip.drir;
127c0907c9eSPaolo Bonzini break;
128c0907c9eSPaolo Bonzini case 0x0300:
129c0907c9eSPaolo Bonzini /* DRIR: Device Raw Interrupt Request Register. */
130c0907c9eSPaolo Bonzini ret = s->cchip.drir;
131c0907c9eSPaolo Bonzini break;
132c0907c9eSPaolo Bonzini
133c0907c9eSPaolo Bonzini case 0x0340:
134c0907c9eSPaolo Bonzini /* PRBEN: Probe Enable Register. */
135c0907c9eSPaolo Bonzini break;
136c0907c9eSPaolo Bonzini
137c0907c9eSPaolo Bonzini case 0x0380:
138c0907c9eSPaolo Bonzini /* IIC0: Interval Ignore Count Register, CPU0. */
139c0907c9eSPaolo Bonzini ret = s->cchip.iic[0];
140c0907c9eSPaolo Bonzini break;
141c0907c9eSPaolo Bonzini case 0x03c0:
142c0907c9eSPaolo Bonzini /* IIC1: Interval Ignore Count Register, CPU1. */
143c0907c9eSPaolo Bonzini ret = s->cchip.iic[1];
144c0907c9eSPaolo Bonzini break;
145c0907c9eSPaolo Bonzini
146c0907c9eSPaolo Bonzini case 0x0400: /* MPR0 */
147c0907c9eSPaolo Bonzini case 0x0440: /* MPR1 */
148c0907c9eSPaolo Bonzini case 0x0480: /* MPR2 */
149c0907c9eSPaolo Bonzini case 0x04c0: /* MPR3 */
150c0907c9eSPaolo Bonzini /* MPR: Memory Programming Register. */
151c0907c9eSPaolo Bonzini break;
152c0907c9eSPaolo Bonzini
153c0907c9eSPaolo Bonzini case 0x0580:
154c0907c9eSPaolo Bonzini /* TTR: TIGbus Timing Register. */
155c0907c9eSPaolo Bonzini /* All sorts of stuff related to interrupt delivery timings. */
156c0907c9eSPaolo Bonzini break;
157c0907c9eSPaolo Bonzini case 0x05c0:
158c0907c9eSPaolo Bonzini /* TDR: TIGbug Device Timing Register. */
159c0907c9eSPaolo Bonzini break;
160c0907c9eSPaolo Bonzini
161c0907c9eSPaolo Bonzini case 0x0600:
162c0907c9eSPaolo Bonzini /* DIM2: Device Interrupt Mask Register, CPU2. */
163c0907c9eSPaolo Bonzini ret = s->cchip.dim[2];
164c0907c9eSPaolo Bonzini break;
165c0907c9eSPaolo Bonzini case 0x0640:
166c0907c9eSPaolo Bonzini /* DIM3: Device Interrupt Mask Register, CPU3. */
167c0907c9eSPaolo Bonzini ret = s->cchip.dim[3];
168c0907c9eSPaolo Bonzini break;
169c0907c9eSPaolo Bonzini case 0x0680:
170c0907c9eSPaolo Bonzini /* DIR2: Device Interrupt Request Register, CPU2. */
171c0907c9eSPaolo Bonzini ret = s->cchip.dim[2] & s->cchip.drir;
172c0907c9eSPaolo Bonzini break;
173c0907c9eSPaolo Bonzini case 0x06c0:
174c0907c9eSPaolo Bonzini /* DIR3: Device Interrupt Request Register, CPU3. */
175c0907c9eSPaolo Bonzini ret = s->cchip.dim[3] & s->cchip.drir;
176c0907c9eSPaolo Bonzini break;
177c0907c9eSPaolo Bonzini
178c0907c9eSPaolo Bonzini case 0x0700:
179c0907c9eSPaolo Bonzini /* IIC2: Interval Ignore Count Register, CPU2. */
180c0907c9eSPaolo Bonzini ret = s->cchip.iic[2];
181c0907c9eSPaolo Bonzini break;
182c0907c9eSPaolo Bonzini case 0x0740:
183c0907c9eSPaolo Bonzini /* IIC3: Interval Ignore Count Register, CPU3. */
184c0907c9eSPaolo Bonzini ret = s->cchip.iic[3];
185c0907c9eSPaolo Bonzini break;
186c0907c9eSPaolo Bonzini
187c0907c9eSPaolo Bonzini case 0x0780:
188c0907c9eSPaolo Bonzini /* PWR: Power Management Control. */
189c0907c9eSPaolo Bonzini break;
190c0907c9eSPaolo Bonzini
191c0907c9eSPaolo Bonzini case 0x0c00: /* CMONCTLA */
192c0907c9eSPaolo Bonzini case 0x0c40: /* CMONCTLB */
193c0907c9eSPaolo Bonzini case 0x0c80: /* CMONCNT01 */
194c0907c9eSPaolo Bonzini case 0x0cc0: /* CMONCNT23 */
195c0907c9eSPaolo Bonzini break;
196c0907c9eSPaolo Bonzini
197c0907c9eSPaolo Bonzini default:
198b7ed683aSPeter Maydell return MEMTX_ERROR;
199c0907c9eSPaolo Bonzini }
200c0907c9eSPaolo Bonzini
201b7ed683aSPeter Maydell *data = ret;
202b7ed683aSPeter Maydell return MEMTX_OK;
203c0907c9eSPaolo Bonzini }
204c0907c9eSPaolo Bonzini
dchip_read(void * opaque,hwaddr addr,unsigned size)205c0907c9eSPaolo Bonzini static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
206c0907c9eSPaolo Bonzini {
207c0907c9eSPaolo Bonzini /* Skip this. It's all related to DRAM timing and setup. */
208c0907c9eSPaolo Bonzini return 0;
209c0907c9eSPaolo Bonzini }
210c0907c9eSPaolo Bonzini
pchip_read(void * opaque,hwaddr addr,uint64_t * data,unsigned size,MemTxAttrs attrs)211b7ed683aSPeter Maydell static MemTxResult pchip_read(void *opaque, hwaddr addr, uint64_t *data,
212b7ed683aSPeter Maydell unsigned size, MemTxAttrs attrs)
213c0907c9eSPaolo Bonzini {
214c0907c9eSPaolo Bonzini TyphoonState *s = opaque;
215c0907c9eSPaolo Bonzini uint64_t ret = 0;
216c0907c9eSPaolo Bonzini
217c0907c9eSPaolo Bonzini switch (addr) {
218c0907c9eSPaolo Bonzini case 0x0000:
219c0907c9eSPaolo Bonzini /* WSBA0: Window Space Base Address Register. */
220b83c4db8SRichard Henderson ret = s->pchip.win[0].wba;
221c0907c9eSPaolo Bonzini break;
222c0907c9eSPaolo Bonzini case 0x0040:
223c0907c9eSPaolo Bonzini /* WSBA1 */
224b83c4db8SRichard Henderson ret = s->pchip.win[1].wba;
225c0907c9eSPaolo Bonzini break;
226c0907c9eSPaolo Bonzini case 0x0080:
227c0907c9eSPaolo Bonzini /* WSBA2 */
228b83c4db8SRichard Henderson ret = s->pchip.win[2].wba;
229c0907c9eSPaolo Bonzini break;
230c0907c9eSPaolo Bonzini case 0x00c0:
231c0907c9eSPaolo Bonzini /* WSBA3 */
232b83c4db8SRichard Henderson ret = s->pchip.win[3].wba;
233c0907c9eSPaolo Bonzini break;
234c0907c9eSPaolo Bonzini
235c0907c9eSPaolo Bonzini case 0x0100:
236c0907c9eSPaolo Bonzini /* WSM0: Window Space Mask Register. */
237b83c4db8SRichard Henderson ret = s->pchip.win[0].wsm;
238c0907c9eSPaolo Bonzini break;
239c0907c9eSPaolo Bonzini case 0x0140:
240c0907c9eSPaolo Bonzini /* WSM1 */
241b83c4db8SRichard Henderson ret = s->pchip.win[1].wsm;
242c0907c9eSPaolo Bonzini break;
243c0907c9eSPaolo Bonzini case 0x0180:
244c0907c9eSPaolo Bonzini /* WSM2 */
245b83c4db8SRichard Henderson ret = s->pchip.win[2].wsm;
246c0907c9eSPaolo Bonzini break;
247c0907c9eSPaolo Bonzini case 0x01c0:
248c0907c9eSPaolo Bonzini /* WSM3 */
249b83c4db8SRichard Henderson ret = s->pchip.win[3].wsm;
250c0907c9eSPaolo Bonzini break;
251c0907c9eSPaolo Bonzini
252c0907c9eSPaolo Bonzini case 0x0200:
253c0907c9eSPaolo Bonzini /* TBA0: Translated Base Address Register. */
254b83c4db8SRichard Henderson ret = s->pchip.win[0].tba;
255c0907c9eSPaolo Bonzini break;
256c0907c9eSPaolo Bonzini case 0x0240:
257c0907c9eSPaolo Bonzini /* TBA1 */
258b83c4db8SRichard Henderson ret = s->pchip.win[1].tba;
259c0907c9eSPaolo Bonzini break;
260c0907c9eSPaolo Bonzini case 0x0280:
261c0907c9eSPaolo Bonzini /* TBA2 */
262b83c4db8SRichard Henderson ret = s->pchip.win[2].tba;
263c0907c9eSPaolo Bonzini break;
264c0907c9eSPaolo Bonzini case 0x02c0:
265c0907c9eSPaolo Bonzini /* TBA3 */
266b83c4db8SRichard Henderson ret = s->pchip.win[3].tba;
267c0907c9eSPaolo Bonzini break;
268c0907c9eSPaolo Bonzini
269c0907c9eSPaolo Bonzini case 0x0300:
270c0907c9eSPaolo Bonzini /* PCTL: Pchip Control Register. */
271c0907c9eSPaolo Bonzini ret = s->pchip.ctl;
272c0907c9eSPaolo Bonzini break;
273c0907c9eSPaolo Bonzini case 0x0340:
274c0907c9eSPaolo Bonzini /* PLAT: Pchip Master Latency Register. */
275c0907c9eSPaolo Bonzini break;
276c0907c9eSPaolo Bonzini case 0x03c0:
277c0907c9eSPaolo Bonzini /* PERROR: Pchip Error Register. */
278c0907c9eSPaolo Bonzini break;
279c0907c9eSPaolo Bonzini case 0x0400:
280c0907c9eSPaolo Bonzini /* PERRMASK: Pchip Error Mask Register. */
281c0907c9eSPaolo Bonzini break;
282c0907c9eSPaolo Bonzini case 0x0440:
283c0907c9eSPaolo Bonzini /* PERRSET: Pchip Error Set Register. */
284c0907c9eSPaolo Bonzini break;
285c0907c9eSPaolo Bonzini case 0x0480:
286c0907c9eSPaolo Bonzini /* TLBIV: Translation Buffer Invalidate Virtual Register (WO). */
287c0907c9eSPaolo Bonzini break;
288c0907c9eSPaolo Bonzini case 0x04c0:
289c0907c9eSPaolo Bonzini /* TLBIA: Translation Buffer Invalidate All Register (WO). */
290c0907c9eSPaolo Bonzini break;
291c0907c9eSPaolo Bonzini case 0x0500: /* PMONCTL */
292c0907c9eSPaolo Bonzini case 0x0540: /* PMONCNT */
293c0907c9eSPaolo Bonzini case 0x0800: /* SPRST */
294c0907c9eSPaolo Bonzini break;
295c0907c9eSPaolo Bonzini
296c0907c9eSPaolo Bonzini default:
297b7ed683aSPeter Maydell return MEMTX_ERROR;
298c0907c9eSPaolo Bonzini }
299c0907c9eSPaolo Bonzini
300b7ed683aSPeter Maydell *data = ret;
301b7ed683aSPeter Maydell return MEMTX_OK;
302c0907c9eSPaolo Bonzini }
303c0907c9eSPaolo Bonzini
cchip_write(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)304b7ed683aSPeter Maydell static MemTxResult cchip_write(void *opaque, hwaddr addr,
305b7ed683aSPeter Maydell uint64_t val, unsigned size,
306b7ed683aSPeter Maydell MemTxAttrs attrs)
307c0907c9eSPaolo Bonzini {
308c0907c9eSPaolo Bonzini TyphoonState *s = opaque;
30967842165SRichard Henderson uint64_t oldval, newval;
310c0907c9eSPaolo Bonzini
311c0907c9eSPaolo Bonzini switch (addr) {
312c0907c9eSPaolo Bonzini case 0x0000:
313c0907c9eSPaolo Bonzini /* CSC: Cchip System Configuration Register. */
314c0907c9eSPaolo Bonzini /* All sorts of data here; nothing relevant RW. */
315c0907c9eSPaolo Bonzini break;
316c0907c9eSPaolo Bonzini
317c0907c9eSPaolo Bonzini case 0x0040:
318c0907c9eSPaolo Bonzini /* MTR: Memory Timing Register. */
319c0907c9eSPaolo Bonzini /* All sorts of stuff related to real DRAM. */
320c0907c9eSPaolo Bonzini break;
321c0907c9eSPaolo Bonzini
322c0907c9eSPaolo Bonzini case 0x0080:
323c0907c9eSPaolo Bonzini /* MISC: Miscellaneous Register. */
324c0907c9eSPaolo Bonzini newval = oldval = s->cchip.misc;
325c0907c9eSPaolo Bonzini newval &= ~(val & 0x10000ff0); /* W1C fields */
326c0907c9eSPaolo Bonzini if (val & 0x100000) {
327c0907c9eSPaolo Bonzini newval &= ~0xff0000ull; /* ACL clears ABT and ABW */
328c0907c9eSPaolo Bonzini } else {
329c0907c9eSPaolo Bonzini newval |= val & 0x00f00000; /* ABT field is W1S */
330c0907c9eSPaolo Bonzini if ((newval & 0xf0000) == 0) {
331c0907c9eSPaolo Bonzini newval |= val & 0xf0000; /* ABW field is W1S iff zero */
332c0907c9eSPaolo Bonzini }
333c0907c9eSPaolo Bonzini }
334c0907c9eSPaolo Bonzini newval |= (val & 0xf000) >> 4; /* IPREQ field sets IPINTR. */
335c0907c9eSPaolo Bonzini
336c0907c9eSPaolo Bonzini newval &= ~0xf0000000000ull; /* WO and RW fields */
337c0907c9eSPaolo Bonzini newval |= val & 0xf0000000000ull;
338c0907c9eSPaolo Bonzini s->cchip.misc = newval;
339c0907c9eSPaolo Bonzini
340c0907c9eSPaolo Bonzini /* Pass on changes to IPI and ITI state. */
341c0907c9eSPaolo Bonzini if ((newval ^ oldval) & 0xff0) {
342c0907c9eSPaolo Bonzini int i;
343c0907c9eSPaolo Bonzini for (i = 0; i < 4; ++i) {
344c0907c9eSPaolo Bonzini AlphaCPU *cpu = s->cchip.cpu[i];
345c0907c9eSPaolo Bonzini if (cpu != NULL) {
346c0907c9eSPaolo Bonzini CPUState *cs = CPU(cpu);
347c0907c9eSPaolo Bonzini /* IPI can be either cleared or set by the write. */
348c0907c9eSPaolo Bonzini if (newval & (1 << (i + 8))) {
349c0907c9eSPaolo Bonzini cpu_interrupt(cs, CPU_INTERRUPT_SMP);
350c0907c9eSPaolo Bonzini } else {
351c0907c9eSPaolo Bonzini cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
352c0907c9eSPaolo Bonzini }
353c0907c9eSPaolo Bonzini
354c0907c9eSPaolo Bonzini /* ITI can only be cleared by the write. */
355c0907c9eSPaolo Bonzini if ((newval & (1 << (i + 4))) == 0) {
356c0907c9eSPaolo Bonzini cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
357c0907c9eSPaolo Bonzini }
358c0907c9eSPaolo Bonzini }
359c0907c9eSPaolo Bonzini }
360c0907c9eSPaolo Bonzini }
361c0907c9eSPaolo Bonzini break;
362c0907c9eSPaolo Bonzini
363c0907c9eSPaolo Bonzini case 0x00c0:
364c0907c9eSPaolo Bonzini /* MPD: Memory Presence Detect Register. */
365c0907c9eSPaolo Bonzini break;
366c0907c9eSPaolo Bonzini
367c0907c9eSPaolo Bonzini case 0x0100: /* AAR0 */
368c0907c9eSPaolo Bonzini case 0x0140: /* AAR1 */
369c0907c9eSPaolo Bonzini case 0x0180: /* AAR2 */
370c0907c9eSPaolo Bonzini case 0x01c0: /* AAR3 */
371c0907c9eSPaolo Bonzini /* AAR: Array Address Register. */
372c0907c9eSPaolo Bonzini /* All sorts of information about DRAM. */
373c0907c9eSPaolo Bonzini break;
374c0907c9eSPaolo Bonzini
375c0907c9eSPaolo Bonzini case 0x0200: /* DIM0 */
376c0907c9eSPaolo Bonzini /* DIM: Device Interrupt Mask Register, CPU0. */
377c0907c9eSPaolo Bonzini s->cchip.dim[0] = val;
378c0907c9eSPaolo Bonzini cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
379c0907c9eSPaolo Bonzini break;
380c0907c9eSPaolo Bonzini case 0x0240: /* DIM1 */
381c0907c9eSPaolo Bonzini /* DIM: Device Interrupt Mask Register, CPU1. */
382424ad838SRichard Henderson s->cchip.dim[1] = val;
383c0907c9eSPaolo Bonzini cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
384c0907c9eSPaolo Bonzini break;
385c0907c9eSPaolo Bonzini
386c0907c9eSPaolo Bonzini case 0x0280: /* DIR0 (RO) */
387c0907c9eSPaolo Bonzini case 0x02c0: /* DIR1 (RO) */
388c0907c9eSPaolo Bonzini case 0x0300: /* DRIR (RO) */
389c0907c9eSPaolo Bonzini break;
390c0907c9eSPaolo Bonzini
391c0907c9eSPaolo Bonzini case 0x0340:
392c0907c9eSPaolo Bonzini /* PRBEN: Probe Enable Register. */
393c0907c9eSPaolo Bonzini break;
394c0907c9eSPaolo Bonzini
395c0907c9eSPaolo Bonzini case 0x0380: /* IIC0 */
396c0907c9eSPaolo Bonzini s->cchip.iic[0] = val & 0xffffff;
397c0907c9eSPaolo Bonzini break;
398c0907c9eSPaolo Bonzini case 0x03c0: /* IIC1 */
399c0907c9eSPaolo Bonzini s->cchip.iic[1] = val & 0xffffff;
400c0907c9eSPaolo Bonzini break;
401c0907c9eSPaolo Bonzini
402c0907c9eSPaolo Bonzini case 0x0400: /* MPR0 */
403c0907c9eSPaolo Bonzini case 0x0440: /* MPR1 */
404c0907c9eSPaolo Bonzini case 0x0480: /* MPR2 */
405c0907c9eSPaolo Bonzini case 0x04c0: /* MPR3 */
406c0907c9eSPaolo Bonzini /* MPR: Memory Programming Register. */
407c0907c9eSPaolo Bonzini break;
408c0907c9eSPaolo Bonzini
409c0907c9eSPaolo Bonzini case 0x0580:
410c0907c9eSPaolo Bonzini /* TTR: TIGbus Timing Register. */
411c0907c9eSPaolo Bonzini /* All sorts of stuff related to interrupt delivery timings. */
412c0907c9eSPaolo Bonzini break;
413c0907c9eSPaolo Bonzini case 0x05c0:
414c0907c9eSPaolo Bonzini /* TDR: TIGbug Device Timing Register. */
415c0907c9eSPaolo Bonzini break;
416c0907c9eSPaolo Bonzini
417c0907c9eSPaolo Bonzini case 0x0600:
418c0907c9eSPaolo Bonzini /* DIM2: Device Interrupt Mask Register, CPU2. */
419c0907c9eSPaolo Bonzini s->cchip.dim[2] = val;
420c0907c9eSPaolo Bonzini cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
421c0907c9eSPaolo Bonzini break;
422c0907c9eSPaolo Bonzini case 0x0640:
423c0907c9eSPaolo Bonzini /* DIM3: Device Interrupt Mask Register, CPU3. */
424c0907c9eSPaolo Bonzini s->cchip.dim[3] = val;
425c0907c9eSPaolo Bonzini cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
426c0907c9eSPaolo Bonzini break;
427c0907c9eSPaolo Bonzini
428c0907c9eSPaolo Bonzini case 0x0680: /* DIR2 (RO) */
429c0907c9eSPaolo Bonzini case 0x06c0: /* DIR3 (RO) */
430c0907c9eSPaolo Bonzini break;
431c0907c9eSPaolo Bonzini
432c0907c9eSPaolo Bonzini case 0x0700: /* IIC2 */
433c0907c9eSPaolo Bonzini s->cchip.iic[2] = val & 0xffffff;
434c0907c9eSPaolo Bonzini break;
435c0907c9eSPaolo Bonzini case 0x0740: /* IIC3 */
436c0907c9eSPaolo Bonzini s->cchip.iic[3] = val & 0xffffff;
437c0907c9eSPaolo Bonzini break;
438c0907c9eSPaolo Bonzini
439c0907c9eSPaolo Bonzini case 0x0780:
440c0907c9eSPaolo Bonzini /* PWR: Power Management Control. */
441c0907c9eSPaolo Bonzini break;
442c0907c9eSPaolo Bonzini
443c0907c9eSPaolo Bonzini case 0x0c00: /* CMONCTLA */
444c0907c9eSPaolo Bonzini case 0x0c40: /* CMONCTLB */
445c0907c9eSPaolo Bonzini case 0x0c80: /* CMONCNT01 */
446c0907c9eSPaolo Bonzini case 0x0cc0: /* CMONCNT23 */
447c0907c9eSPaolo Bonzini break;
448c0907c9eSPaolo Bonzini
449c0907c9eSPaolo Bonzini default:
450b7ed683aSPeter Maydell return MEMTX_ERROR;
451c0907c9eSPaolo Bonzini }
452b7ed683aSPeter Maydell
453b7ed683aSPeter Maydell return MEMTX_OK;
454c0907c9eSPaolo Bonzini }
455c0907c9eSPaolo Bonzini
dchip_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)456c0907c9eSPaolo Bonzini static void dchip_write(void *opaque, hwaddr addr,
457c0907c9eSPaolo Bonzini uint64_t val, unsigned size)
458c0907c9eSPaolo Bonzini {
459c0907c9eSPaolo Bonzini /* Skip this. It's all related to DRAM timing and setup. */
460c0907c9eSPaolo Bonzini }
461c0907c9eSPaolo Bonzini
pchip_write(void * opaque,hwaddr addr,uint64_t val,unsigned size,MemTxAttrs attrs)462b7ed683aSPeter Maydell static MemTxResult pchip_write(void *opaque, hwaddr addr,
463b7ed683aSPeter Maydell uint64_t val, unsigned size,
464b7ed683aSPeter Maydell MemTxAttrs attrs)
465c0907c9eSPaolo Bonzini {
466c0907c9eSPaolo Bonzini TyphoonState *s = opaque;
46767842165SRichard Henderson uint64_t oldval;
468c0907c9eSPaolo Bonzini
469c0907c9eSPaolo Bonzini switch (addr) {
470c0907c9eSPaolo Bonzini case 0x0000:
471c0907c9eSPaolo Bonzini /* WSBA0: Window Space Base Address Register. */
472b83c4db8SRichard Henderson s->pchip.win[0].wba = val & 0xfff00003u;
473c0907c9eSPaolo Bonzini break;
474c0907c9eSPaolo Bonzini case 0x0040:
475c0907c9eSPaolo Bonzini /* WSBA1 */
476b83c4db8SRichard Henderson s->pchip.win[1].wba = val & 0xfff00003u;
477c0907c9eSPaolo Bonzini break;
478c0907c9eSPaolo Bonzini case 0x0080:
479c0907c9eSPaolo Bonzini /* WSBA2 */
480b83c4db8SRichard Henderson s->pchip.win[2].wba = val & 0xfff00003u;
481c0907c9eSPaolo Bonzini break;
482c0907c9eSPaolo Bonzini case 0x00c0:
483c0907c9eSPaolo Bonzini /* WSBA3 */
484b83c4db8SRichard Henderson s->pchip.win[3].wba = (val & 0x80fff00001ull) | 2;
485c0907c9eSPaolo Bonzini break;
486c0907c9eSPaolo Bonzini
487c0907c9eSPaolo Bonzini case 0x0100:
488c0907c9eSPaolo Bonzini /* WSM0: Window Space Mask Register. */
489b83c4db8SRichard Henderson s->pchip.win[0].wsm = val & 0xfff00000u;
490c0907c9eSPaolo Bonzini break;
491c0907c9eSPaolo Bonzini case 0x0140:
492c0907c9eSPaolo Bonzini /* WSM1 */
493b83c4db8SRichard Henderson s->pchip.win[1].wsm = val & 0xfff00000u;
494c0907c9eSPaolo Bonzini break;
495c0907c9eSPaolo Bonzini case 0x0180:
496c0907c9eSPaolo Bonzini /* WSM2 */
497b83c4db8SRichard Henderson s->pchip.win[2].wsm = val & 0xfff00000u;
498c0907c9eSPaolo Bonzini break;
499c0907c9eSPaolo Bonzini case 0x01c0:
500c0907c9eSPaolo Bonzini /* WSM3 */
501b83c4db8SRichard Henderson s->pchip.win[3].wsm = val & 0xfff00000u;
502c0907c9eSPaolo Bonzini break;
503c0907c9eSPaolo Bonzini
504c0907c9eSPaolo Bonzini case 0x0200:
505c0907c9eSPaolo Bonzini /* TBA0: Translated Base Address Register. */
506b83c4db8SRichard Henderson s->pchip.win[0].tba = val & 0x7fffffc00ull;
507c0907c9eSPaolo Bonzini break;
508c0907c9eSPaolo Bonzini case 0x0240:
509c0907c9eSPaolo Bonzini /* TBA1 */
510b83c4db8SRichard Henderson s->pchip.win[1].tba = val & 0x7fffffc00ull;
511c0907c9eSPaolo Bonzini break;
512c0907c9eSPaolo Bonzini case 0x0280:
513c0907c9eSPaolo Bonzini /* TBA2 */
514b83c4db8SRichard Henderson s->pchip.win[2].tba = val & 0x7fffffc00ull;
515c0907c9eSPaolo Bonzini break;
516c0907c9eSPaolo Bonzini case 0x02c0:
517c0907c9eSPaolo Bonzini /* TBA3 */
518b83c4db8SRichard Henderson s->pchip.win[3].tba = val & 0x7fffffc00ull;
519c0907c9eSPaolo Bonzini break;
520c0907c9eSPaolo Bonzini
521c0907c9eSPaolo Bonzini case 0x0300:
522c0907c9eSPaolo Bonzini /* PCTL: Pchip Control Register. */
523c0907c9eSPaolo Bonzini oldval = s->pchip.ctl;
524c0907c9eSPaolo Bonzini oldval &= ~0x00001cff0fc7ffull; /* RW fields */
525c0907c9eSPaolo Bonzini oldval |= val & 0x00001cff0fc7ffull;
526c0907c9eSPaolo Bonzini s->pchip.ctl = oldval;
527c0907c9eSPaolo Bonzini break;
528c0907c9eSPaolo Bonzini
529c0907c9eSPaolo Bonzini case 0x0340:
530c0907c9eSPaolo Bonzini /* PLAT: Pchip Master Latency Register. */
531c0907c9eSPaolo Bonzini break;
532c0907c9eSPaolo Bonzini case 0x03c0:
533c0907c9eSPaolo Bonzini /* PERROR: Pchip Error Register. */
534c0907c9eSPaolo Bonzini break;
535c0907c9eSPaolo Bonzini case 0x0400:
536c0907c9eSPaolo Bonzini /* PERRMASK: Pchip Error Mask Register. */
537c0907c9eSPaolo Bonzini break;
538c0907c9eSPaolo Bonzini case 0x0440:
539c0907c9eSPaolo Bonzini /* PERRSET: Pchip Error Set Register. */
540c0907c9eSPaolo Bonzini break;
541c0907c9eSPaolo Bonzini
542c0907c9eSPaolo Bonzini case 0x0480:
543c0907c9eSPaolo Bonzini /* TLBIV: Translation Buffer Invalidate Virtual Register. */
544c0907c9eSPaolo Bonzini break;
545c0907c9eSPaolo Bonzini
546c0907c9eSPaolo Bonzini case 0x04c0:
547c0907c9eSPaolo Bonzini /* TLBIA: Translation Buffer Invalidate All Register (WO). */
548c0907c9eSPaolo Bonzini break;
549c0907c9eSPaolo Bonzini
550c0907c9eSPaolo Bonzini case 0x0500:
551c0907c9eSPaolo Bonzini /* PMONCTL */
552c0907c9eSPaolo Bonzini case 0x0540:
553c0907c9eSPaolo Bonzini /* PMONCNT */
554c0907c9eSPaolo Bonzini case 0x0800:
555c0907c9eSPaolo Bonzini /* SPRST */
556c0907c9eSPaolo Bonzini break;
557c0907c9eSPaolo Bonzini
558c0907c9eSPaolo Bonzini default:
559b7ed683aSPeter Maydell return MEMTX_ERROR;
560c0907c9eSPaolo Bonzini }
561b7ed683aSPeter Maydell
562b7ed683aSPeter Maydell return MEMTX_OK;
563c0907c9eSPaolo Bonzini }
564c0907c9eSPaolo Bonzini
565c0907c9eSPaolo Bonzini static const MemoryRegionOps cchip_ops = {
566b7ed683aSPeter Maydell .read_with_attrs = cchip_read,
567b7ed683aSPeter Maydell .write_with_attrs = cchip_write,
568c0907c9eSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
569c0907c9eSPaolo Bonzini .valid = {
57067842165SRichard Henderson .min_access_size = 8,
571c0907c9eSPaolo Bonzini .max_access_size = 8,
572c0907c9eSPaolo Bonzini },
573c0907c9eSPaolo Bonzini .impl = {
57467842165SRichard Henderson .min_access_size = 8,
57567842165SRichard Henderson .max_access_size = 8,
576c0907c9eSPaolo Bonzini },
577c0907c9eSPaolo Bonzini };
578c0907c9eSPaolo Bonzini
579c0907c9eSPaolo Bonzini static const MemoryRegionOps dchip_ops = {
580c0907c9eSPaolo Bonzini .read = dchip_read,
581c0907c9eSPaolo Bonzini .write = dchip_write,
582c0907c9eSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
583c0907c9eSPaolo Bonzini .valid = {
58467842165SRichard Henderson .min_access_size = 8,
585c0907c9eSPaolo Bonzini .max_access_size = 8,
586c0907c9eSPaolo Bonzini },
587c0907c9eSPaolo Bonzini .impl = {
58867842165SRichard Henderson .min_access_size = 8,
589c0907c9eSPaolo Bonzini .max_access_size = 8,
590c0907c9eSPaolo Bonzini },
591c0907c9eSPaolo Bonzini };
592c0907c9eSPaolo Bonzini
593c0907c9eSPaolo Bonzini static const MemoryRegionOps pchip_ops = {
594b7ed683aSPeter Maydell .read_with_attrs = pchip_read,
595b7ed683aSPeter Maydell .write_with_attrs = pchip_write,
596c0907c9eSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
597c0907c9eSPaolo Bonzini .valid = {
59867842165SRichard Henderson .min_access_size = 8,
599c0907c9eSPaolo Bonzini .max_access_size = 8,
600c0907c9eSPaolo Bonzini },
601c0907c9eSPaolo Bonzini .impl = {
60267842165SRichard Henderson .min_access_size = 8,
60367842165SRichard Henderson .max_access_size = 8,
604c0907c9eSPaolo Bonzini },
605c0907c9eSPaolo Bonzini };
606c0907c9eSPaolo Bonzini
607b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that builds an IOMMUTLBEntry
608b83c4db8SRichard Henderson using the given translated address and mask. */
make_iommu_tlbe(hwaddr taddr,hwaddr mask,IOMMUTLBEntry * ret)609b83c4db8SRichard Henderson static bool make_iommu_tlbe(hwaddr taddr, hwaddr mask, IOMMUTLBEntry *ret)
610b83c4db8SRichard Henderson {
611b83c4db8SRichard Henderson *ret = (IOMMUTLBEntry) {
612b83c4db8SRichard Henderson .target_as = &address_space_memory,
613b83c4db8SRichard Henderson .translated_addr = taddr,
614b83c4db8SRichard Henderson .addr_mask = mask,
615b83c4db8SRichard Henderson .perm = IOMMU_RW,
616b83c4db8SRichard Henderson };
617b83c4db8SRichard Henderson return true;
618b83c4db8SRichard Henderson }
619b83c4db8SRichard Henderson
620b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles scatter-gather
621b83c4db8SRichard Henderson translation, given the address of the PTE. */
pte_translate(hwaddr pte_addr,IOMMUTLBEntry * ret)622b83c4db8SRichard Henderson static bool pte_translate(hwaddr pte_addr, IOMMUTLBEntry *ret)
623b83c4db8SRichard Henderson {
62442874d3aSPeter Maydell uint64_t pte = address_space_ldq(&address_space_memory, pte_addr,
62542874d3aSPeter Maydell MEMTXATTRS_UNSPECIFIED, NULL);
626b83c4db8SRichard Henderson
627b83c4db8SRichard Henderson /* Check valid bit. */
628b83c4db8SRichard Henderson if ((pte & 1) == 0) {
629b83c4db8SRichard Henderson return false;
630b83c4db8SRichard Henderson }
631b83c4db8SRichard Henderson
632b83c4db8SRichard Henderson return make_iommu_tlbe((pte & 0x3ffffe) << 12, 0x1fff, ret);
633b83c4db8SRichard Henderson }
634b83c4db8SRichard Henderson
635b83c4db8SRichard Henderson /* A subroutine of typhoon_translate_iommu that handles one of the
636b83c4db8SRichard Henderson four single-address-cycle translation windows. */
window_translate(TyphoonWindow * win,hwaddr addr,IOMMUTLBEntry * ret)637b83c4db8SRichard Henderson static bool window_translate(TyphoonWindow *win, hwaddr addr,
638b83c4db8SRichard Henderson IOMMUTLBEntry *ret)
639b83c4db8SRichard Henderson {
640b83c4db8SRichard Henderson uint32_t wba = win->wba;
641b83c4db8SRichard Henderson uint64_t wsm = win->wsm;
642b83c4db8SRichard Henderson uint64_t tba = win->tba;
643b83c4db8SRichard Henderson uint64_t wsm_ext = wsm | 0xfffff;
644b83c4db8SRichard Henderson
645b83c4db8SRichard Henderson /* Check for window disabled. */
646b83c4db8SRichard Henderson if ((wba & 1) == 0) {
647b83c4db8SRichard Henderson return false;
648b83c4db8SRichard Henderson }
649b83c4db8SRichard Henderson
650b83c4db8SRichard Henderson /* Check for window hit. */
651b83c4db8SRichard Henderson if ((addr & ~wsm_ext) != (wba & 0xfff00000u)) {
652b83c4db8SRichard Henderson return false;
653b83c4db8SRichard Henderson }
654b83c4db8SRichard Henderson
655b83c4db8SRichard Henderson if (wba & 2) {
656b83c4db8SRichard Henderson /* Scatter-gather translation. */
657b83c4db8SRichard Henderson hwaddr pte_addr;
658b83c4db8SRichard Henderson
659b83c4db8SRichard Henderson /* See table 10-6, Generating PTE address for PCI DMA Address. */
660b83c4db8SRichard Henderson pte_addr = tba & ~(wsm >> 10);
661b83c4db8SRichard Henderson pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
662b83c4db8SRichard Henderson return pte_translate(pte_addr, ret);
663b83c4db8SRichard Henderson } else {
664b83c4db8SRichard Henderson /* Direct-mapped translation. */
665b83c4db8SRichard Henderson return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
666b83c4db8SRichard Henderson }
667b83c4db8SRichard Henderson }
668b83c4db8SRichard Henderson
669b83c4db8SRichard Henderson /* Handle PCI-to-system address translation. */
670b83c4db8SRichard Henderson /* TODO: A translation failure here ought to set PCI error codes on the
671b83c4db8SRichard Henderson Pchip and generate a machine check interrupt. */
typhoon_translate_iommu(IOMMUMemoryRegion * iommu,hwaddr addr,IOMMUAccessFlags flag,int iommu_idx)6723df9d748SAlexey Kardashevskiy static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
6733df9d748SAlexey Kardashevskiy hwaddr addr,
6742c91bcf2SPeter Maydell IOMMUAccessFlags flag,
6752c91bcf2SPeter Maydell int iommu_idx)
676b83c4db8SRichard Henderson {
677b83c4db8SRichard Henderson TyphoonPchip *pchip = container_of(iommu, TyphoonPchip, iommu);
678b83c4db8SRichard Henderson IOMMUTLBEntry ret;
679b83c4db8SRichard Henderson int i;
680b83c4db8SRichard Henderson
681b83c4db8SRichard Henderson if (addr <= 0xffffffffu) {
682b83c4db8SRichard Henderson /* Single-address cycle. */
683b83c4db8SRichard Henderson
684b83c4db8SRichard Henderson /* Check for the Window Hole, inhibiting matching. */
685b83c4db8SRichard Henderson if ((pchip->ctl & 0x20)
686b83c4db8SRichard Henderson && addr >= 0x80000
687b83c4db8SRichard Henderson && addr <= 0xfffff) {
688b83c4db8SRichard Henderson goto failure;
689b83c4db8SRichard Henderson }
690b83c4db8SRichard Henderson
691b83c4db8SRichard Henderson /* Check the first three windows. */
692b83c4db8SRichard Henderson for (i = 0; i < 3; ++i) {
693b83c4db8SRichard Henderson if (window_translate(&pchip->win[i], addr, &ret)) {
694b83c4db8SRichard Henderson goto success;
695b83c4db8SRichard Henderson }
696b83c4db8SRichard Henderson }
697b83c4db8SRichard Henderson
698b83c4db8SRichard Henderson /* Check the fourth window for DAC disable. */
699b83c4db8SRichard Henderson if ((pchip->win[3].wba & 0x80000000000ull) == 0
700b83c4db8SRichard Henderson && window_translate(&pchip->win[3], addr, &ret)) {
701b83c4db8SRichard Henderson goto success;
702b83c4db8SRichard Henderson }
703b83c4db8SRichard Henderson } else {
704b83c4db8SRichard Henderson /* Double-address cycle. */
705b83c4db8SRichard Henderson
706b83c4db8SRichard Henderson if (addr >= 0x10000000000ull && addr < 0x20000000000ull) {
707b83c4db8SRichard Henderson /* Check for the DMA monster window. */
708b83c4db8SRichard Henderson if (pchip->ctl & 0x40) {
709b83c4db8SRichard Henderson /* See 10.1.4.4; in particular <39:35> is ignored. */
710b83c4db8SRichard Henderson make_iommu_tlbe(0, 0x007ffffffffull, &ret);
711b83c4db8SRichard Henderson goto success;
712b83c4db8SRichard Henderson }
713b83c4db8SRichard Henderson }
714b83c4db8SRichard Henderson
7159b2caaf4SStefan Weil if (addr >= 0x80000000000ull && addr <= 0xfffffffffffull) {
716b83c4db8SRichard Henderson /* Check the fourth window for DAC enable and window enable. */
717b83c4db8SRichard Henderson if ((pchip->win[3].wba & 0x80000000001ull) == 0x80000000001ull) {
718b83c4db8SRichard Henderson uint64_t pte_addr;
719b83c4db8SRichard Henderson
720b83c4db8SRichard Henderson pte_addr = pchip->win[3].tba & 0x7ffc00000ull;
721b83c4db8SRichard Henderson pte_addr |= (addr & 0xffffe000u) >> 10;
722b83c4db8SRichard Henderson if (pte_translate(pte_addr, &ret)) {
723b83c4db8SRichard Henderson goto success;
724b83c4db8SRichard Henderson }
725b83c4db8SRichard Henderson }
726b83c4db8SRichard Henderson }
727b83c4db8SRichard Henderson }
728b83c4db8SRichard Henderson
729b83c4db8SRichard Henderson failure:
730b83c4db8SRichard Henderson ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE };
731b83c4db8SRichard Henderson success:
732b83c4db8SRichard Henderson return ret;
733b83c4db8SRichard Henderson }
734b83c4db8SRichard Henderson
typhoon_pci_dma_iommu(PCIBus * bus,void * opaque,int devfn)735b83c4db8SRichard Henderson static AddressSpace *typhoon_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
736b83c4db8SRichard Henderson {
737b83c4db8SRichard Henderson TyphoonState *s = opaque;
738b83c4db8SRichard Henderson return &s->pchip.iommu_as;
739b83c4db8SRichard Henderson }
740b83c4db8SRichard Henderson
741*ba7d12ebSYi Liu static const PCIIOMMUOps typhoon_iommu_ops = {
742*ba7d12ebSYi Liu .get_address_space = typhoon_pci_dma_iommu,
743*ba7d12ebSYi Liu };
744*ba7d12ebSYi Liu
typhoon_set_irq(void * opaque,int irq,int level)745c0907c9eSPaolo Bonzini static void typhoon_set_irq(void *opaque, int irq, int level)
746c0907c9eSPaolo Bonzini {
747c0907c9eSPaolo Bonzini TyphoonState *s = opaque;
748c0907c9eSPaolo Bonzini uint64_t drir;
749c0907c9eSPaolo Bonzini int i;
750c0907c9eSPaolo Bonzini
751c0907c9eSPaolo Bonzini /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL. */
752c0907c9eSPaolo Bonzini drir = s->cchip.drir;
753c0907c9eSPaolo Bonzini if (level) {
754c0907c9eSPaolo Bonzini drir |= 1ull << irq;
755c0907c9eSPaolo Bonzini } else {
756c0907c9eSPaolo Bonzini drir &= ~(1ull << irq);
757c0907c9eSPaolo Bonzini }
758c0907c9eSPaolo Bonzini s->cchip.drir = drir;
759c0907c9eSPaolo Bonzini
760c0907c9eSPaolo Bonzini for (i = 0; i < 4; ++i) {
761c0907c9eSPaolo Bonzini cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
762c0907c9eSPaolo Bonzini }
763c0907c9eSPaolo Bonzini }
764c0907c9eSPaolo Bonzini
typhoon_set_isa_irq(void * opaque,int irq,int level)765c0907c9eSPaolo Bonzini static void typhoon_set_isa_irq(void *opaque, int irq, int level)
766c0907c9eSPaolo Bonzini {
767c0907c9eSPaolo Bonzini typhoon_set_irq(opaque, 55, level);
768c0907c9eSPaolo Bonzini }
769c0907c9eSPaolo Bonzini
typhoon_set_timer_irq(void * opaque,int irq,int level)770c0907c9eSPaolo Bonzini static void typhoon_set_timer_irq(void *opaque, int irq, int level)
771c0907c9eSPaolo Bonzini {
772c0907c9eSPaolo Bonzini TyphoonState *s = opaque;
773c0907c9eSPaolo Bonzini int i;
774c0907c9eSPaolo Bonzini
775c0907c9eSPaolo Bonzini /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
776c0907c9eSPaolo Bonzini and so we don't have to worry about missing interrupts just
777c0907c9eSPaolo Bonzini because we never actually ACK the interrupt. Just ignore any
778c0907c9eSPaolo Bonzini case of the interrupt level going low. */
779c0907c9eSPaolo Bonzini if (level == 0) {
780c0907c9eSPaolo Bonzini return;
781c0907c9eSPaolo Bonzini }
782c0907c9eSPaolo Bonzini
783c0907c9eSPaolo Bonzini /* Deliver the interrupt to each CPU, considering each CPU's IIC. */
784c0907c9eSPaolo Bonzini for (i = 0; i < 4; ++i) {
785c0907c9eSPaolo Bonzini AlphaCPU *cpu = s->cchip.cpu[i];
786c0907c9eSPaolo Bonzini if (cpu != NULL) {
787c0907c9eSPaolo Bonzini uint32_t iic = s->cchip.iic[i];
788c0907c9eSPaolo Bonzini
789c0907c9eSPaolo Bonzini /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
790c0907c9eSPaolo Bonzini Bit 24 is the OverFlow bit, RO, and set when the count
791c0907c9eSPaolo Bonzini decrements past 0. When is OF cleared? My guess is that
792c0907c9eSPaolo Bonzini OF is actually cleared when the IIC is written, and that
793c0907c9eSPaolo Bonzini the ICNT field always decrements. At least, that's an
794c0907c9eSPaolo Bonzini interpretation that makes sense, and "allows the CPU to
795c0907c9eSPaolo Bonzini determine exactly how mant interval timer ticks were
796c0907c9eSPaolo Bonzini skipped". At least within the next 4M ticks... */
797c0907c9eSPaolo Bonzini
798c0907c9eSPaolo Bonzini iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
799c0907c9eSPaolo Bonzini s->cchip.iic[i] = iic;
800c0907c9eSPaolo Bonzini
801c0907c9eSPaolo Bonzini if (iic & 0x1000000) {
802c0907c9eSPaolo Bonzini /* Set the ITI bit for this cpu. */
803c0907c9eSPaolo Bonzini s->cchip.misc |= 1 << (i + 4);
804c0907c9eSPaolo Bonzini /* And signal the interrupt. */
805c0907c9eSPaolo Bonzini cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
806c0907c9eSPaolo Bonzini }
807c0907c9eSPaolo Bonzini }
808c0907c9eSPaolo Bonzini }
809c0907c9eSPaolo Bonzini }
810c0907c9eSPaolo Bonzini
typhoon_alarm_timer(void * opaque)811c0907c9eSPaolo Bonzini static void typhoon_alarm_timer(void *opaque)
812c0907c9eSPaolo Bonzini {
813c0907c9eSPaolo Bonzini TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
814c0907c9eSPaolo Bonzini int cpu = (uintptr_t)opaque & 3;
815c0907c9eSPaolo Bonzini
816c0907c9eSPaolo Bonzini /* Set the ITI bit for this cpu. */
817c0907c9eSPaolo Bonzini s->cchip.misc |= 1 << (cpu + 4);
818c0907c9eSPaolo Bonzini cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
819c0907c9eSPaolo Bonzini }
820c0907c9eSPaolo Bonzini
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)8215ec4f1d3SJason Thorpe PCIBus *typhoon_init(MemoryRegion *ram, qemu_irq *p_isa_irq,
8225ec4f1d3SJason Thorpe qemu_irq *p_rtc_irq, AlphaCPU *cpus[4],
8235ec4f1d3SJason Thorpe pci_map_irq_fn sys_map_irq, uint8_t devfn_min)
824c0907c9eSPaolo Bonzini {
825c0907c9eSPaolo Bonzini MemoryRegion *addr_space = get_system_memory();
826c0907c9eSPaolo Bonzini DeviceState *dev;
827c0907c9eSPaolo Bonzini TyphoonState *s;
828c0907c9eSPaolo Bonzini PCIHostState *phb;
829c0907c9eSPaolo Bonzini PCIBus *b;
830c0907c9eSPaolo Bonzini int i;
831c0907c9eSPaolo Bonzini
8323e80f690SMarkus Armbruster dev = qdev_new(TYPE_TYPHOON_PCI_HOST_BRIDGE);
833c0907c9eSPaolo Bonzini
834c0907c9eSPaolo Bonzini s = TYPHOON_PCI_HOST_BRIDGE(dev);
835c0907c9eSPaolo Bonzini phb = PCI_HOST_BRIDGE(dev);
836c0907c9eSPaolo Bonzini
837b83c4db8SRichard Henderson s->cchip.misc = 0x800000000ull; /* Revision: Typhoon. */
838b83c4db8SRichard Henderson s->pchip.win[3].wba = 2; /* Window 3 SG always enabled. */
839b83c4db8SRichard Henderson
840c0907c9eSPaolo Bonzini /* Remember the CPUs so that we can deliver interrupts to them. */
841c0907c9eSPaolo Bonzini for (i = 0; i < 4; i++) {
842c0907c9eSPaolo Bonzini AlphaCPU *cpu = cpus[i];
843c0907c9eSPaolo Bonzini s->cchip.cpu[i] = cpu;
844c0907c9eSPaolo Bonzini if (cpu != NULL) {
845bc72ad67SAlex Bligh cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
846c0907c9eSPaolo Bonzini typhoon_alarm_timer,
847c0907c9eSPaolo Bonzini (void *)((uintptr_t)s + i));
848c0907c9eSPaolo Bonzini }
849c0907c9eSPaolo Bonzini }
850c0907c9eSPaolo Bonzini
8515ec4f1d3SJason Thorpe *p_isa_irq = qemu_allocate_irq(typhoon_set_isa_irq, s, 0);
85254292736SShannon Zhao *p_rtc_irq = qemu_allocate_irq(typhoon_set_timer_irq, s, 0);
853c0907c9eSPaolo Bonzini
854c0907c9eSPaolo Bonzini /* Main memory region, 0x00.0000.0000. Real hardware supports 32GB,
855c0907c9eSPaolo Bonzini but the address space hole reserved at this point is 8TB. */
856b844d822SIgor Mammedov memory_region_add_subregion(addr_space, 0, ram);
857c0907c9eSPaolo Bonzini
858c0907c9eSPaolo Bonzini /* TIGbus, 0x801.0000.0000, 1GB. */
859c0907c9eSPaolo Bonzini /* ??? The TIGbus is used for delivering interrupts, and access to
860c0907c9eSPaolo Bonzini the flash ROM. I'm not sure that we need to implement it at all. */
861c0907c9eSPaolo Bonzini
862c0907c9eSPaolo Bonzini /* Pchip0 CSRs, 0x801.8000.0000, 256MB. */
86364bde0f3SPaolo Bonzini memory_region_init_io(&s->pchip.region, OBJECT(s), &pchip_ops, s, "pchip0",
8642b41742aSPhilippe Mathieu-Daudé 256 * MiB);
865c0907c9eSPaolo Bonzini memory_region_add_subregion(addr_space, 0x80180000000ULL,
866c0907c9eSPaolo Bonzini &s->pchip.region);
867c0907c9eSPaolo Bonzini
868c0907c9eSPaolo Bonzini /* Cchip CSRs, 0x801.A000.0000, 256MB. */
86964bde0f3SPaolo Bonzini memory_region_init_io(&s->cchip.region, OBJECT(s), &cchip_ops, s, "cchip0",
8702b41742aSPhilippe Mathieu-Daudé 256 * MiB);
871c0907c9eSPaolo Bonzini memory_region_add_subregion(addr_space, 0x801a0000000ULL,
872c0907c9eSPaolo Bonzini &s->cchip.region);
873c0907c9eSPaolo Bonzini
874c0907c9eSPaolo Bonzini /* Dchip CSRs, 0x801.B000.0000, 256MB. */
87564bde0f3SPaolo Bonzini memory_region_init_io(&s->dchip_region, OBJECT(s), &dchip_ops, s, "dchip0",
8762b41742aSPhilippe Mathieu-Daudé 256 * MiB);
877c0907c9eSPaolo Bonzini memory_region_add_subregion(addr_space, 0x801b0000000ULL,
878c0907c9eSPaolo Bonzini &s->dchip_region);
879c0907c9eSPaolo Bonzini
880c0907c9eSPaolo Bonzini /* Pchip0 PCI memory, 0x800.0000.0000, 4GB. */
8812b41742aSPhilippe Mathieu-Daudé memory_region_init(&s->pchip.reg_mem, OBJECT(s), "pci0-mem", 4 * GiB);
882c0907c9eSPaolo Bonzini memory_region_add_subregion(addr_space, 0x80000000000ULL,
883c0907c9eSPaolo Bonzini &s->pchip.reg_mem);
884c0907c9eSPaolo Bonzini
885c0907c9eSPaolo Bonzini /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB. */
8863661049fSRichard Henderson memory_region_init_io(&s->pchip.reg_io, OBJECT(s), &alpha_pci_ignore_ops,
8872b41742aSPhilippe Mathieu-Daudé NULL, "pci0-io", 32 * MiB);
888c0907c9eSPaolo Bonzini memory_region_add_subregion(addr_space, 0x801fc000000ULL,
889c0907c9eSPaolo Bonzini &s->pchip.reg_io);
890c0907c9eSPaolo Bonzini
8911115ff6dSDavid Gibson b = pci_register_root_bus(dev, "pci",
892c0907c9eSPaolo Bonzini typhoon_set_irq, sys_map_irq, s,
893056e6baeSRichard Henderson &s->pchip.reg_mem, &s->pchip.reg_io,
8943a8233dcSJason Thorpe devfn_min, 64, TYPE_PCI_BUS);
895c0907c9eSPaolo Bonzini phb->bus = b;
8963c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
897c0907c9eSPaolo Bonzini
898b83c4db8SRichard Henderson /* Host memory as seen from the PCI side, via the IOMMU. */
8991221a474SAlexey Kardashevskiy memory_region_init_iommu(&s->pchip.iommu, sizeof(s->pchip.iommu),
9001221a474SAlexey Kardashevskiy TYPE_TYPHOON_IOMMU_MEMORY_REGION, OBJECT(s),
901b83c4db8SRichard Henderson "iommu-typhoon", UINT64_MAX);
9023df9d748SAlexey Kardashevskiy address_space_init(&s->pchip.iommu_as, MEMORY_REGION(&s->pchip.iommu),
9033df9d748SAlexey Kardashevskiy "pchip0-pci");
904*ba7d12ebSYi Liu pci_setup_iommu(b, &typhoon_iommu_ops, s);
905b83c4db8SRichard Henderson
906c0907c9eSPaolo Bonzini /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */
907056e6baeSRichard Henderson memory_region_init_io(&s->pchip.reg_iack, OBJECT(s), &alpha_pci_iack_ops,
9082b41742aSPhilippe Mathieu-Daudé b, "pci0-iack", 64 * MiB);
909c0907c9eSPaolo Bonzini memory_region_add_subregion(addr_space, 0x801f8000000ULL,
910c0907c9eSPaolo Bonzini &s->pchip.reg_iack);
911c0907c9eSPaolo Bonzini
912c0907c9eSPaolo Bonzini /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB. */
913056e6baeSRichard Henderson memory_region_init_io(&s->pchip.reg_conf, OBJECT(s), &alpha_pci_conf1_ops,
9142b41742aSPhilippe Mathieu-Daudé b, "pci0-conf", 16 * MiB);
915c0907c9eSPaolo Bonzini memory_region_add_subregion(addr_space, 0x801fe000000ULL,
916c0907c9eSPaolo Bonzini &s->pchip.reg_conf);
917c0907c9eSPaolo Bonzini
918c0907c9eSPaolo Bonzini /* For the record, these are the mappings for the second PCI bus.
919c0907c9eSPaolo Bonzini We can get away with not implementing them because we indicate
920c0907c9eSPaolo Bonzini via the Cchip.CSC<PIP> bit that Pchip1 is not present. */
921c0907c9eSPaolo Bonzini /* Pchip1 PCI memory, 0x802.0000.0000, 4GB. */
922c0907c9eSPaolo Bonzini /* Pchip1 CSRs, 0x802.8000.0000, 256MB. */
923c0907c9eSPaolo Bonzini /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB. */
924c0907c9eSPaolo Bonzini /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB. */
925c0907c9eSPaolo Bonzini /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB. */
926c0907c9eSPaolo Bonzini
927c0907c9eSPaolo Bonzini return b;
928c0907c9eSPaolo Bonzini }
929c0907c9eSPaolo Bonzini
930c0907c9eSPaolo Bonzini static const TypeInfo typhoon_pcihost_info = {
931c0907c9eSPaolo Bonzini .name = TYPE_TYPHOON_PCI_HOST_BRIDGE,
932c0907c9eSPaolo Bonzini .parent = TYPE_PCI_HOST_BRIDGE,
933c0907c9eSPaolo Bonzini .instance_size = sizeof(TyphoonState),
934c0907c9eSPaolo Bonzini };
935c0907c9eSPaolo Bonzini
typhoon_iommu_memory_region_class_init(ObjectClass * klass,void * data)9361221a474SAlexey Kardashevskiy static void typhoon_iommu_memory_region_class_init(ObjectClass *klass,
9371221a474SAlexey Kardashevskiy void *data)
9381221a474SAlexey Kardashevskiy {
9391221a474SAlexey Kardashevskiy IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
9401221a474SAlexey Kardashevskiy
9411221a474SAlexey Kardashevskiy imrc->translate = typhoon_translate_iommu;
9421221a474SAlexey Kardashevskiy }
9431221a474SAlexey Kardashevskiy
9441221a474SAlexey Kardashevskiy static const TypeInfo typhoon_iommu_memory_region_info = {
9451221a474SAlexey Kardashevskiy .parent = TYPE_IOMMU_MEMORY_REGION,
9461221a474SAlexey Kardashevskiy .name = TYPE_TYPHOON_IOMMU_MEMORY_REGION,
9471221a474SAlexey Kardashevskiy .class_init = typhoon_iommu_memory_region_class_init,
9481221a474SAlexey Kardashevskiy };
9491221a474SAlexey Kardashevskiy
typhoon_register_types(void)950c0907c9eSPaolo Bonzini static void typhoon_register_types(void)
951c0907c9eSPaolo Bonzini {
952c0907c9eSPaolo Bonzini type_register_static(&typhoon_pcihost_info);
9531221a474SAlexey Kardashevskiy type_register_static(&typhoon_iommu_memory_region_info);
954c0907c9eSPaolo Bonzini }
955c0907c9eSPaolo Bonzini
956c0907c9eSPaolo Bonzini type_init(typhoon_register_types)
957