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