aboutsummaryrefslogtreecommitdiff
path: root/hw/iommu.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2005-04-06 20:47:48 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2005-04-06 20:47:48 +0000
commit66321a11a4ef45942b3bee7377a36bb94831365a (patch)
treef038f1aef344fa93923d874d348d09542d4c5b68 /hw/iommu.c
parentc44644bb966bd0cf7e09d94b043814ea0740fe8f (diff)
downloadqemu-66321a11a4ef45942b3bee7377a36bb94831365a.zip
qemu-66321a11a4ef45942b3bee7377a36bb94831365a.tar.gz
qemu-66321a11a4ef45942b3bee7377a36bb94831365a.tar.bz2
sparc update (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1350 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/iommu.c')
-rw-r--r--hw/iommu.c97
1 files changed, 25 insertions, 72 deletions
diff --git a/hw/iommu.c b/hw/iommu.c
index 62927ac..d0b16ea 100644
--- a/hw/iommu.c
+++ b/hw/iommu.c
@@ -1,7 +1,7 @@
/*
* QEMU SPARC iommu emulation
*
- * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2003-2005 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,30 +26,14 @@
/* debug iommu */
//#define DEBUG_IOMMU
-/* The IOMMU registers occupy three pages in IO space. */
-struct iommu_regs {
- /* First page */
- volatile unsigned long control; /* IOMMU control */
- volatile unsigned long base; /* Physical base of iopte page table */
- volatile unsigned long _unused1[3];
- volatile unsigned long tlbflush; /* write only */
- volatile unsigned long pageflush; /* write only */
- volatile unsigned long _unused2[1017];
- /* Second page */
- volatile unsigned long afsr; /* Async-fault status register */
- volatile unsigned long afar; /* Async-fault physical address */
- volatile unsigned long _unused3[2];
- volatile unsigned long sbuscfg0; /* SBUS configuration registers, per-slot */
- volatile unsigned long sbuscfg1;
- volatile unsigned long sbuscfg2;
- volatile unsigned long sbuscfg3;
- volatile unsigned long mfsr; /* Memory-fault status register */
- volatile unsigned long mfar; /* Memory-fault physical address */
- volatile unsigned long _unused4[1014];
- /* Third page */
- volatile unsigned long mid; /* IOMMU module-id */
-};
+#ifdef DEBUG_IOMMU
+#define DPRINTF(fmt, args...) \
+do { printf("IOMMU: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+#define IOMMU_NREGS (3*4096)
#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */
#define IOMMU_CTRL_VERS 0x0f000000 /* Version */
#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */
@@ -63,43 +47,6 @@ struct iommu_regs {
#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */
#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */
-#define IOMMU_AFSR_ERR 0x80000000 /* LE, TO, or BE asserted */
-#define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after transaction */
-#define IOMMU_AFSR_TO 0x20000000 /* Write access took more than 12.8 us. */
-#define IOMMU_AFSR_BE 0x10000000 /* Write access received error acknowledge */
-#define IOMMU_AFSR_SIZE 0x0e000000 /* Size of transaction causing error */
-#define IOMMU_AFSR_S 0x01000000 /* Sparc was in supervisor mode */
-#define IOMMU_AFSR_RESV 0x00f00000 /* Reserver, forced to 0x8 by hardware */
-#define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */
-#define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */
-#define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */
-
-#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */
-#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */
-#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */
-#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses
- produced by this device as pure
- physical. */
-
-#define IOMMU_MFSR_ERR 0x80000000 /* One or more of PERR1 or PERR0 */
-#define IOMMU_MFSR_S 0x01000000 /* Sparc was in supervisor mode */
-#define IOMMU_MFSR_CPU 0x00800000 /* CPU transaction caused parity error */
-#define IOMMU_MFSR_ME 0x00080000 /* Multiple parity errors occurred */
-#define IOMMU_MFSR_PERR 0x00006000 /* high bit indicates parity error occurred
- on the even word of the access, low bit
- indicated odd word caused the parity error */
-#define IOMMU_MFSR_BM 0x00001000 /* Error occurred while in boot mode */
-#define IOMMU_MFSR_C 0x00000800 /* Address causing error was marked cacheable */
-#define IOMMU_MFSR_RTYP 0x000000f0 /* Memory request transaction type */
-
-#define IOMMU_MID_SBAE 0x001f0000 /* SBus arbitration enable */
-#define IOMMU_MID_SE 0x00100000 /* Enables SCSI/ETHERNET arbitration */
-#define IOMMU_MID_SB3 0x00080000 /* Enable SBUS device 3 arbitration */
-#define IOMMU_MID_SB2 0x00040000 /* Enable SBUS device 2 arbitration */
-#define IOMMU_MID_SB1 0x00020000 /* Enable SBUS device 1 arbitration */
-#define IOMMU_MID_SB0 0x00010000 /* Enable SBUS device 0 arbitration */
-#define IOMMU_MID_MID 0x0000000f /* Module-id, hardcoded to 0x8 */
-
/* The format of an iopte in the page tables */
#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */
#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */
@@ -113,7 +60,7 @@ struct iommu_regs {
typedef struct IOMMUState {
uint32_t addr;
- uint32_t regs[sizeof(struct iommu_regs)];
+ uint32_t regs[IOMMU_NREGS];
uint32_t iostart;
} IOMMUState;
@@ -125,6 +72,7 @@ static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
saddr = (addr - s->addr) >> 2;
switch (saddr) {
default:
+ DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]);
return s->regs[saddr];
break;
}
@@ -137,6 +85,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val
uint32_t saddr;
saddr = (addr - s->addr) >> 2;
+ DPRINTF("write reg[%d] = %x\n", saddr, val);
switch (saddr) {
case 0:
switch (val & IOMMU_CTRL_RNGE) {
@@ -166,6 +115,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val
s->iostart = 0x80000000;
break;
}
+ DPRINTF("iostart = %x\n", s->iostart);
/* Fall through */
default:
s->regs[saddr] = val;
@@ -188,13 +138,17 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = {
uint32_t iommu_translate_local(void *opaque, uint32_t addr)
{
IOMMUState *s = opaque;
- uint32_t *iopte = (void *)(s->regs[1] << 4), pa;
+ uint32_t iopte, pa, tmppte;
- iopte += ((addr - s->iostart) >> PAGE_SHIFT);
- cpu_physical_memory_read((uint32_t)iopte, (void *) &pa, 4);
+ iopte = s->regs[1] << 4;
+ addr &= ~s->iostart;
+ iopte += (addr >> (PAGE_SHIFT - 2)) & ~3;
+ cpu_physical_memory_read(iopte, (void *) &pa, 4);
bswap32s(&pa);
- pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */
- return pa + (addr & PAGE_MASK);
+ tmppte = pa;
+ pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK);
+ DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte);
+ return pa;
}
static void iommu_save(QEMUFile *f, void *opaque)
@@ -203,7 +157,7 @@ static void iommu_save(QEMUFile *f, void *opaque)
int i;
qemu_put_be32s(f, &s->addr);
- for (i = 0; i < sizeof(struct iommu_regs); i += 4)
+ for (i = 0; i < IOMMU_NREGS; i++)
qemu_put_be32s(f, &s->regs[i]);
qemu_put_be32s(f, &s->iostart);
}
@@ -217,7 +171,7 @@ static int iommu_load(QEMUFile *f, void *opaque, int version_id)
return -EINVAL;
qemu_get_be32s(f, &s->addr);
- for (i = 0; i < sizeof(struct iommu_regs); i += 4)
+ for (i = 0; i < IOMMU_NREGS; i++)
qemu_put_be32s(f, &s->regs[i]);
qemu_get_be32s(f, &s->iostart);
@@ -228,7 +182,7 @@ static void iommu_reset(void *opaque)
{
IOMMUState *s = opaque;
- memset(s->regs, 0, sizeof(struct iommu_regs));
+ memset(s->regs, 0, IOMMU_NREGS * 4);
s->iostart = 0;
}
@@ -244,8 +198,7 @@ void *iommu_init(uint32_t addr)
s->addr = addr;
iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s);
- cpu_register_physical_memory(addr, sizeof(struct iommu_regs),
- iommu_io_memory);
+ cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory);
register_savevm("iommu", addr, 1, iommu_save, iommu_load, s);
qemu_register_reset(iommu_reset, s);