qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] 64 bit I/O support v7
@ 2009-04-21 11:42 Robert Reif
  2009-05-01 12:03 ` Paul Brook
  0 siblings, 1 reply; 21+ messages in thread
From: Robert Reif @ 2009-04-21 11:42 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2290 bytes --]

This patch is a rebase on current svn of my previous patch.

This patch adds support for 64 bit I/O by essentially replacing an
array of 4 function pointers with a structure containing 4 function
pointers. The current array contains 4 pointers, one for 8, 16 and 32
bit function pointers which really support only 32 bits and a
forth pointer which is unused but I assume is a place holder for a
64 bit function pointer.  The current trick of passing 8, 16 or 32 bits
in a 32 bit variable doesn't extend to passing 64 bits in a 32 bit
bit variable and creating a 64 bit function would require casts to
allow being saved in the array so a sutrcture is used that can take
different function pointers.

Here are the relevant parts of the patch:

+typedef void CPUWriteMemoryFunc64(void *opaque, target_phys_addr_t 
addr, uint64_t value);
+typedef uint64_t CPUReadMemoryFunc64(void *opaque, target_phys_addr_t 
addr);
+
+typedef struct CPUWriteMemoryFuncs {
+    CPUWriteMemoryFunc   *b;
+    CPUWriteMemoryFunc   *w;
+    CPUWriteMemoryFunc   *l;
+    CPUWriteMemoryFunc64 *q;
+} CPUWriteMemoryFuncs;
+
+typedef struct CPUReadMemoryFuncs {
+    CPUReadMemoryFunc   *b;
+    CPUReadMemoryFunc   *w;
+    CPUReadMemoryFunc   *l;
+    CPUReadMemoryFunc64 *q;
+} CPUReadMemoryFuncs;

-extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
-extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+extern CPUWriteMemoryFuncs io_mem_write[IO_MEM_NB_ENTRIES];
+extern CPUReadMemoryFuncs io_mem_read[IO_MEM_NB_ENTRIES];

The rest of the patch just does the array to structure conversion and
adds the 64 bit functions.

The old array function call is supported so no existing drivers need
to be modified.  They can continue to do 2 32 bit accesses because 2
helper functions have been added to break up the accesses automatically.
However, the helper functions should only be used until all drivers are
converted to use the structure and then can be removed along
with the old array functions api.  The replacement of the arrays with
structures in the drivers is very straightforward for drivers that don't
do 64 bit I/O and the few that do can be cleaned up to remove the
work arounds for the lack of true 64 bit I/O by their maintainers.

Signed-off-by: Robert Reif <reif@earthlink.net>

[-- Attachment #2: io64-v7.diff.txt --]
[-- Type: text/plain, Size: 24805 bytes --]

Index: softmmu_template.h
===================================================================
--- softmmu_template.h	(revision 7190)
+++ softmmu_template.h	(working copy)
@@ -65,17 +65,7 @@
     }
 
     env->mem_io_vaddr = addr;
-#if SHIFT <= 2
-    res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
-#else
-#ifdef TARGET_WORDS_BIGENDIAN
-    res = (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr) << 32;
-    res |= io_mem_read[index][2](io_mem_opaque[index], physaddr + 4);
-#else
-    res = io_mem_read[index][2](io_mem_opaque[index], physaddr);
-    res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4) << 32;
-#endif
-#endif /* SHIFT > 2 */
+    res = io_mem_read[index].SUFFIX(io_mem_opaque[index], physaddr);
 #ifdef CONFIG_KQEMU
     env->last_io_time = cpu_get_time_fast();
 #endif
@@ -210,17 +200,7 @@
 
     env->mem_io_vaddr = addr;
     env->mem_io_pc = (unsigned long)retaddr;
-#if SHIFT <= 2
-    io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val);
-#else
-#ifdef TARGET_WORDS_BIGENDIAN
-    io_mem_write[index][2](io_mem_opaque[index], physaddr, val >> 32);
-    io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val);
-#else
-    io_mem_write[index][2](io_mem_opaque[index], physaddr, val);
-    io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32);
-#endif
-#endif /* SHIFT > 2 */
+    io_mem_write[index].SUFFIX(io_mem_opaque[index], physaddr, val);
 #ifdef CONFIG_KQEMU
     env->last_io_time = cpu_get_time_fast();
 #endif
Index: exec.c
===================================================================
--- exec.c	(revision 7190)
+++ exec.c	(working copy)
@@ -47,6 +47,7 @@
 //#define DEBUG_FLUSH
 //#define DEBUG_TLB
 //#define DEBUG_UNASSIGNED
+//#define DEBUG_MMIO64
 
 /* make various TB consistency checks */
 //#define DEBUG_TB_CHECK
@@ -182,8 +183,8 @@
 static void io_mem_init(void);
 
 /* io memory support */
-CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
-CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+CPUWriteMemoryFuncs io_mem_write[IO_MEM_NB_ENTRIES];
+CPUReadMemoryFuncs io_mem_read[IO_MEM_NB_ENTRIES];
 void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 static char io_mem_used[IO_MEM_NB_ENTRIES];
 static int io_mem_watch;
@@ -2588,6 +2589,17 @@
     return 0;
 }
 
+static uint64_t unassigned_mem_readq(void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
+#endif
+#if defined(TARGET_SPARC)
+    do_unassigned_access(addr, 0, 0, 0, 8);
+#endif
+    return 0;
+}
+
 static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
 #ifdef DEBUG_UNASSIGNED
@@ -2618,16 +2630,28 @@
 #endif
 }
 
-static CPUReadMemoryFunc *unassigned_mem_read[3] = {
+static void unassigned_mem_writeq(void *opaque, target_phys_addr_t addr, uint64_t val)
+{
+#ifdef DEBUG_UNASSIGNED
+    printf("Unassigned mem write " TARGET_FMT_plx " = 0x%016llx\n", addr, val);
+#endif
+#if defined(TARGET_SPARC)
+    do_unassigned_access(addr, 1, 0, 0, 8);
+#endif
+}
+
+static CPUReadMemoryFuncs unassigned_mem_read = {
     unassigned_mem_readb,
     unassigned_mem_readw,
     unassigned_mem_readl,
+    unassigned_mem_readq,
 };
 
-static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
+static CPUWriteMemoryFuncs unassigned_mem_write = {
     unassigned_mem_writeb,
     unassigned_mem_writew,
     unassigned_mem_writel,
+    unassigned_mem_writeq,
 };
 
 static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
@@ -2705,16 +2729,43 @@
         tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
 }
 
-static CPUReadMemoryFunc *error_mem_read[3] = {
+static void notdirty_mem_writeq(void *opaque, target_phys_addr_t ram_addr,
+                                uint64_t val)
+{
+    int dirty_flags;
+    dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
+    if (!(dirty_flags & CODE_DIRTY_FLAG)) {
+#if !defined(CONFIG_USER_ONLY)
+        tb_invalidate_phys_page_fast(ram_addr, 8);
+        dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
+#endif
+    }
+    stq_p(qemu_get_ram_ptr(ram_addr), val);
+#ifdef USE_KQEMU
+    if (cpu_single_env->kqemu_enabled &&
+        (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
+        kqemu_modify_page(cpu_single_env, ram_addr);
+#endif
+    dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
+    phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
+    /* we remove the notdirty callback only if the code has been
+       flushed */
+    if (dirty_flags == 0xff)
+        tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
+}
+
+static CPUReadMemoryFuncs error_mem_read = {
     NULL, /* never used */
     NULL, /* never used */
     NULL, /* never used */
+    NULL, /* never used */
 };
 
-static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
+static CPUWriteMemoryFuncs notdirty_mem_write = {
     notdirty_mem_writeb,
     notdirty_mem_writew,
     notdirty_mem_writel,
+    notdirty_mem_writeq,
 };
 
 /* Generate a debug exception if a watchpoint has been hit.  */
@@ -2783,6 +2834,12 @@
     return ldl_phys(addr);
 }
 
+static uint64_t watch_mem_readq(void *opaque, target_phys_addr_t addr)
+{
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x7, BP_MEM_READ);
+    return ldq_phys(addr);
+}
+
 static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
                              uint32_t val)
 {
@@ -2804,16 +2861,25 @@
     stl_phys(addr, val);
 }
 
-static CPUReadMemoryFunc *watch_mem_read[3] = {
+static void watch_mem_writeq(void *opaque, target_phys_addr_t addr,
+                             uint64_t val)
+{
+    check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x7, BP_MEM_WRITE);
+    stq_phys(addr, val);
+}
+
+static CPUReadMemoryFuncs watch_mem_read = {
     watch_mem_readb,
     watch_mem_readw,
     watch_mem_readl,
+    watch_mem_readq,
 };
 
-static CPUWriteMemoryFunc *watch_mem_write[3] = {
+static CPUWriteMemoryFuncs watch_mem_write = {
     watch_mem_writeb,
     watch_mem_writew,
     watch_mem_writel,
+    watch_mem_writeq,
 };
 
 static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
@@ -2902,23 +2968,54 @@
     subpage_writelen(opaque, addr, value, 2);
 }
 
-static CPUReadMemoryFunc *subpage_read[] = {
-    &subpage_readb,
-    &subpage_readw,
-    &subpage_readl,
+static uint64_t subpage_readq (void *opaque, target_phys_addr_t addr)
+{
+    subpage_t *mmio = (subpage_t *)opaque;
+    unsigned int idx;
+
+    idx = SUBPAGE_IDX(addr);
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
+           mmio, 3, addr, idx);
+#endif
+    return ((CPUReadMemoryFunc64*)(*mmio->mem_read[idx][3]))(mmio->opaque[idx][0][3],
+                                       addr + mmio->region_offset[idx][0][3]);
+}
+
+static void subpage_writeq (void *opaque,
+                         target_phys_addr_t addr, uint64_t value)
+{
+    subpage_t *mmio = (subpage_t *)opaque;
+    unsigned int idx;
+
+    idx = SUBPAGE_IDX(addr);
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %016llx\n", __func__,
+           mmio, 3, addr, idx, value);
+#endif
+    ((CPUWriteMemoryFunc64*)(*mmio->mem_write[idx][3]))(mmio->opaque[idx][1][3],
+                                  addr + mmio->region_offset[idx][1][3],
+                                  value);
+}
+
+static CPUReadMemoryFuncs subpage_read = {
+    subpage_readb,
+    subpage_readw,
+    subpage_readl,
+    subpage_readq,
 };
 
-static CPUWriteMemoryFunc *subpage_write[] = {
-    &subpage_writeb,
-    &subpage_writew,
-    &subpage_writel,
+static CPUWriteMemoryFuncs subpage_write = {
+    subpage_writeb,
+    subpage_writew,
+    subpage_writel,
+    subpage_writeq,
 };
 
 static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
                              ram_addr_t memory, ram_addr_t region_offset)
 {
     int idx, eidx;
-    unsigned int i;
 
     if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
         return -1;
@@ -2930,18 +3027,46 @@
 #endif
     memory >>= IO_MEM_SHIFT;
     for (; idx <= eidx; idx++) {
-        for (i = 0; i < 4; i++) {
-            if (io_mem_read[memory][i]) {
-                mmio->mem_read[idx][i] = &io_mem_read[memory][i];
-                mmio->opaque[idx][0][i] = io_mem_opaque[memory];
-                mmio->region_offset[idx][0][i] = region_offset;
-            }
-            if (io_mem_write[memory][i]) {
-                mmio->mem_write[idx][i] = &io_mem_write[memory][i];
-                mmio->opaque[idx][1][i] = io_mem_opaque[memory];
-                mmio->region_offset[idx][1][i] = region_offset;
-            }
+        if (io_mem_read[memory].b) {
+            mmio->mem_read[idx][0] = &io_mem_read[memory].b;
+            mmio->opaque[idx][0][0] = io_mem_opaque[memory];
+            mmio->region_offset[idx][0][0] = region_offset;
         }
+        if (io_mem_write[memory].b) {
+            mmio->mem_write[idx][0] = &io_mem_write[memory].b;
+            mmio->opaque[idx][1][0] = io_mem_opaque[memory];
+            mmio->region_offset[idx][1][0] = region_offset;
+        }
+        if (io_mem_read[memory].w) {
+            mmio->mem_read[idx][1] = &io_mem_read[memory].w;
+            mmio->opaque[idx][0][1] = io_mem_opaque[memory];
+            mmio->region_offset[idx][0][1] = region_offset;
+        }
+        if (io_mem_write[memory].w) {
+            mmio->mem_write[idx][1] = &io_mem_write[memory].w;
+            mmio->opaque[idx][1][1] = io_mem_opaque[memory];
+            mmio->region_offset[idx][1][1] = region_offset;
+        }
+        if (io_mem_read[memory].l) {
+            mmio->mem_read[idx][2] = &io_mem_read[memory].l;
+            mmio->opaque[idx][0][2] = io_mem_opaque[memory];
+            mmio->region_offset[idx][0][2] = region_offset;
+        }
+        if (io_mem_write[memory].l) {
+            mmio->mem_write[idx][2] = &io_mem_write[memory].l;
+            mmio->opaque[idx][1][2] = io_mem_opaque[memory];
+            mmio->region_offset[idx][1][2] = region_offset;
+        }
+        if (io_mem_read[memory].q) {
+            mmio->mem_read[idx][3] = (CPUReadMemoryFunc**)&io_mem_read[memory].q;
+            mmio->opaque[idx][0][3] = io_mem_opaque[memory];
+            mmio->region_offset[idx][0][3] = region_offset;
+        }
+        if (io_mem_write[memory].q) {
+            mmio->mem_write[idx][3] = (CPUWriteMemoryFunc**)&io_mem_write[memory].q;
+            mmio->opaque[idx][1][3] = io_mem_opaque[memory];
+            mmio->region_offset[idx][1][3] = region_offset;
+        }
     }
 
     return 0;
@@ -2956,7 +3081,7 @@
     mmio = qemu_mallocz(sizeof(subpage_t));
 
     mmio->base = base;
-    subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
+    subpage_memory = cpu_register_io_memory64(0, &subpage_read, &subpage_write, mmio);
 #if defined(DEBUG_SUBPAGE)
     printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
            mmio, base, TARGET_PAGE_SIZE, subpage_memory);
@@ -2985,14 +3110,14 @@
 {
     int i;
 
-    cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
-    cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
-    cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
+    cpu_register_io_memory64(IO_MEM_ROM >> IO_MEM_SHIFT, &error_mem_read, &unassigned_mem_write, NULL);
+    cpu_register_io_memory64(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, &unassigned_mem_read, &unassigned_mem_write, NULL);
+    cpu_register_io_memory64(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, &error_mem_read, &notdirty_mem_write, NULL);
     for (i=0; i<5; i++)
         io_mem_used[i] = 1;
 
-    io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
-                                          watch_mem_write, NULL);
+    io_mem_watch = cpu_register_io_memory64(0, &watch_mem_read,
+                                            &watch_mem_write, NULL);
 #ifdef CONFIG_KQEMU
     if (kqemu_phys_ram_base) {
         /* alloc dirty bits array */
@@ -3002,6 +3127,58 @@
 #endif
 }
 
+/* mem_readq and mem_writeq are helper functions that are
+   used to emulate 64 bit accesses for hardware devices
+   that are doing 64 bit mmio but have not been converted
+   to use cpu_register_io_memory64.  These functions should
+   only be used until all hardware devices are converted to
+   the new api and then removed because they are not efficient.  */
+static void mem_writeq(void *opaque, target_phys_addr_t addr, uint64_t val)
+{
+    int i;
+
+    for (i = 0; i < IO_MEM_NB_ENTRIES; i++) {
+        if (io_mem_opaque[i] == opaque && io_mem_used[i]) {
+#ifdef TARGET_WORDS_BIGENDIAN
+            io_mem_write[i].l(opaque, addr, val >> 32);
+            io_mem_write[i].l(opaque, addr + 4, val);
+#else
+            io_mem_write[i].l(opaque, addr, val);
+            io_mem_write[i].l(opaque, addr + 4, val >> 32);
+#endif
+#ifdef DEBUG_MMIO64
+            printf("FIXME: emulating 64 bit I/O using 32 bit I/O.\n");
+#endif
+            return;
+        }
+    }
+}
+
+static uint64_t mem_readq(void *opaque, target_phys_addr_t addr)
+{
+    int i;
+
+    for (i = 0; i < IO_MEM_NB_ENTRIES; i++) {
+        if (io_mem_opaque[i] == opaque && io_mem_used[i]) {
+            uint64_t val;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+            val = (uint64_t)io_mem_read[i].l(opaque, addr) << 32;
+            val |= io_mem_read[i].l(opaque, addr + 4);
+#else
+            val = io_mem_read[i].l(opaque, addr);
+            val |= (uint64_t)io_mem_read[i].l(opaque, addr + 4) << 32;
+#endif
+#ifdef DEBUG_MMIO64
+            printf("FIXME: emulating 64 bit I/O using 32 bit I/O.\n");
+#endif
+            return val;
+        }
+    }
+
+    return 0;
+}
+
 /* mem_read and mem_write are arrays of functions containing the
    function to access byte (index 0), word (index 1) and dword (index
    2). Functions can be omitted with a NULL function pointer. The
@@ -3015,8 +3192,38 @@
                            CPUWriteMemoryFunc **mem_write,
                            void *opaque)
 {
-    int i, subwidth = 0;
+    if (io_index <= 0) {
+        io_index = get_free_io_mem_idx();
+        if (io_index == -1)
+            return io_index;
+    } else {
+        if (io_index >= IO_MEM_NB_ENTRIES)
+            return -1;
+    }
 
+    io_mem_read[io_index].b = mem_read[0];
+    io_mem_write[io_index].b = mem_write[0];
+
+    io_mem_read[io_index].w = mem_read[1];
+    io_mem_write[io_index].w = mem_write[1];
+
+    io_mem_read[io_index].l = mem_read[2];
+    io_mem_write[io_index].l = mem_write[2];
+
+    io_mem_read[io_index].q = mem_readq;
+    io_mem_write[io_index].q = mem_writeq;
+
+    io_mem_opaque[io_index] = opaque;
+    return (io_index << IO_MEM_SHIFT) | IO_MEM_SUBWIDTH;
+}
+
+int cpu_register_io_memory64(int io_index,
+                             CPUReadMemoryFuncs *mem_read,
+                             CPUWriteMemoryFuncs *mem_write,
+                             void *opaque)
+{
+    int subwidth = 0;
+
     if (io_index <= 0) {
         io_index = get_free_io_mem_idx();
         if (io_index == -1)
@@ -3026,37 +3233,36 @@
             return -1;
     }
 
-    for(i = 0;i < 3; i++) {
-        if (!mem_read[i] || !mem_write[i])
-            subwidth = IO_MEM_SUBWIDTH;
-        io_mem_read[io_index][i] = mem_read[i];
-        io_mem_write[io_index][i] = mem_write[i];
-    }
+    if (!mem_read->b || !mem_write->b ||
+        !mem_read->w || !mem_write->w ||
+        !mem_read->l || !mem_write->l ||
+        !mem_read->q || !mem_write->q)
+        subwidth = IO_MEM_SUBWIDTH;
+    
+    io_mem_read[io_index] = *mem_read;
+    io_mem_write[io_index] = *mem_write;
     io_mem_opaque[io_index] = opaque;
     return (io_index << IO_MEM_SHIFT) | subwidth;
 }
 
 void cpu_unregister_io_memory(int io_table_address)
 {
-    int i;
     int io_index = io_table_address >> IO_MEM_SHIFT;
 
-    for (i=0;i < 3; i++) {
-        io_mem_read[io_index][i] = unassigned_mem_read[i];
-        io_mem_write[io_index][i] = unassigned_mem_write[i];
-    }
+    io_mem_read[io_index] = unassigned_mem_read;
+    io_mem_write[io_index] = unassigned_mem_write;
     io_mem_opaque[io_index] = NULL;
     io_mem_used[io_index] = 0;
 }
 
 CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
 {
-    return io_mem_write[io_index >> IO_MEM_SHIFT];
+    return &io_mem_write[io_index >> IO_MEM_SHIFT].b;
 }
 
 CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
 {
-    return io_mem_read[io_index >> IO_MEM_SHIFT];
+    return &io_mem_read[io_index >> IO_MEM_SHIFT].b;
 }
 
 #endif /* !defined(CONFIG_USER_ONLY) */
@@ -3134,20 +3340,25 @@
                     addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
                 /* XXX: could force cpu_single_env to NULL to avoid
                    potential bugs */
-                if (l >= 4 && ((addr1 & 3) == 0)) {
+                if (l >= 8 && ((addr1 & 7) == 0)) {
+                    /* 64 bit write access */
+                    uint64_t val64 = ldq_p(buf);
+                    io_mem_write[io_index].q(io_mem_opaque[io_index], addr1, val64);
+                    l = 8;
+                } else if (l >= 4 && ((addr1 & 3) == 0)) {
                     /* 32 bit write access */
                     val = ldl_p(buf);
-                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
+                    io_mem_write[io_index].l(io_mem_opaque[io_index], addr1, val);
                     l = 4;
                 } else if (l >= 2 && ((addr1 & 1) == 0)) {
                     /* 16 bit write access */
                     val = lduw_p(buf);
-                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
+                    io_mem_write[io_index].w(io_mem_opaque[io_index], addr1, val);
                     l = 2;
                 } else {
                     /* 8 bit write access */
                     val = ldub_p(buf);
-                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
+                    io_mem_write[io_index].b(io_mem_opaque[io_index], addr1, val);
                     l = 1;
                 }
             } else {
@@ -3172,19 +3383,24 @@
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
                 if (p)
                     addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-                if (l >= 4 && ((addr1 & 3) == 0)) {
+                if (l >= 8 && ((addr1 & 7) == 0)) {
+                    /* 64 bit read access */
+                    uint64_t val64 = io_mem_read[io_index].q(io_mem_opaque[io_index], addr1);
+                    stq_p(buf, val64);
+                    l = 8;
+                } else if (l >= 4 && ((addr1 & 3) == 0)) {
                     /* 32 bit read access */
-                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
+                    val = io_mem_read[io_index].l(io_mem_opaque[io_index], addr1);
                     stl_p(buf, val);
                     l = 4;
                 } else if (l >= 2 && ((addr1 & 1) == 0)) {
                     /* 16 bit read access */
-                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
+                    val = io_mem_read[io_index].w(io_mem_opaque[io_index], addr1);
                     stw_p(buf, val);
                     l = 2;
                 } else {
                     /* 8 bit read access */
-                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
+                    val = io_mem_read[io_index].b(io_mem_opaque[io_index], addr1);
                     stb_p(buf, val);
                     l = 1;
                 }
@@ -3405,7 +3621,7 @@
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-        val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+        val = io_mem_read[io_index].l(io_mem_opaque[io_index], addr);
     } else {
         /* RAM case */
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
@@ -3437,13 +3653,7 @@
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-#ifdef TARGET_WORDS_BIGENDIAN
-        val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
-        val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
-#else
-        val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
-        val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
-#endif
+        val = io_mem_read[io_index].q(io_mem_opaque[io_index], addr);
     } else {
         /* RAM case */
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
@@ -3490,7 +3700,7 @@
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+        io_mem_write[io_index].l(io_mem_opaque[io_index], addr, val);
     } else {
         unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
         ptr = qemu_get_ram_ptr(addr1);
@@ -3526,13 +3736,7 @@
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-#ifdef TARGET_WORDS_BIGENDIAN
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
-#else
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
-#endif
+        io_mem_write[io_index].q(io_mem_opaque[io_index], addr, val);
     } else {
         ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
@@ -3559,7 +3763,7 @@
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         if (p)
             addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
-        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+        io_mem_write[io_index].l(io_mem_opaque[io_index], addr, val);
     } else {
         unsigned long addr1;
         addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
Index: exec-all.h
===================================================================
--- exec-all.h	(revision 7190)
+++ exec-all.h	(working copy)
@@ -265,8 +265,8 @@
 
 TranslationBlock *tb_find_pc(unsigned long pc_ptr);
 
-extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
-extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+extern CPUWriteMemoryFuncs io_mem_write[IO_MEM_NB_ENTRIES];
+extern CPUReadMemoryFuncs io_mem_read[IO_MEM_NB_ENTRIES];
 extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 
 #include "qemu-lock.h"
Index: cpu-all.h
===================================================================
--- cpu-all.h	(revision 7190)
+++ cpu-all.h	(working copy)
@@ -891,6 +891,23 @@
 typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
 typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
 
+typedef void CPUWriteMemoryFunc64(void *opaque, target_phys_addr_t addr, uint64_t value);
+typedef uint64_t CPUReadMemoryFunc64(void *opaque, target_phys_addr_t addr);
+
+typedef struct CPUWriteMemoryFuncs {
+    CPUWriteMemoryFunc   *b;
+    CPUWriteMemoryFunc   *w;
+    CPUWriteMemoryFunc   *l;
+    CPUWriteMemoryFunc64 *q;
+} CPUWriteMemoryFuncs;
+
+typedef struct CPUReadMemoryFuncs {
+    CPUReadMemoryFunc   *b;
+    CPUReadMemoryFunc   *w;
+    CPUReadMemoryFunc   *l;
+    CPUReadMemoryFunc64 *q;
+} CPUReadMemoryFuncs;
+
 void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
                                          ram_addr_t size,
                                          ram_addr_t phys_offset,
@@ -914,6 +931,10 @@
                            CPUReadMemoryFunc **mem_read,
                            CPUWriteMemoryFunc **mem_write,
                            void *opaque);
+int cpu_register_io_memory64(int io_index,
+                             CPUReadMemoryFuncs *mem_read,
+                             CPUWriteMemoryFuncs *mem_write,
+                             void *opaque);
 void cpu_unregister_io_memory(int table_address);
 CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index);
 CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index);

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-04-21 11:42 [Qemu-devel] [PATCH] 64 bit I/O support v7 Robert Reif
@ 2009-05-01 12:03 ` Paul Brook
  2009-05-01 13:46   ` Robert Reif
  2009-05-01 14:25   ` Robert Reif
  0 siblings, 2 replies; 21+ messages in thread
From: Paul Brook @ 2009-05-01 12:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: Robert Reif

> The old array function call is supported so no existing drivers need
> to be modified.  They can continue to do 2 32 bit accesses because 2
> helper functions have been added to break up the accesses automatically.
> However, the helper functions should only be used until all drivers are
> converted to use the structure and then can be removed along
> with the old array functions api.  The replacement of the arrays with
> structures in the drivers is very straightforward for drivers that don't
> do 64 bit I/O and the few that do can be cleaned up to remove the
> work arounds for the lack of true 64 bit I/O by their maintainers.

This is going to be a bit of a pain, and a lot of duplication.  My expectation 
is that most devices don't know/care about 64-bit accesses and want them to 
be automatically split into a pair of 32-bit accesses. I suggest pushing this 
down into the lower level dispatch routines. By my reading your mem_writeq 
helpers are broken if we happen to have multiple regions with the same opaque 
value (this effects at least lsi53c895a.c).

In the interests of avoiding duplication, I'd also implement 
cpu_register_io_memory in terms of cpu_register_io_memory64.

> +    return ((CPUReadMemoryFunc64*)(*mmio->mem_read[idx][3]))
> (mmio->opaque[idx][0][3],  addr + mmio->region_offset[idx][0][3]);

Eww. It would be a good idea to fix this at the same time.

Paul

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 12:03 ` Paul Brook
@ 2009-05-01 13:46   ` Robert Reif
  2009-05-01 14:14     ` Paul Brook
  2009-05-01 14:25   ` Robert Reif
  1 sibling, 1 reply; 21+ messages in thread
From: Robert Reif @ 2009-05-01 13:46 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

Paul Brook wrote:
>> The old array function call is supported so no existing drivers need
>> to be modified.  They can continue to do 2 32 bit accesses because 2
>> helper functions have been added to break up the accesses automatically.
>> However, the helper functions should only be used until all drivers are
>> converted to use the structure and then can be removed along
>> with the old array functions api.  The replacement of the arrays with
>> structures in the drivers is very straightforward for drivers that don't
>> do 64 bit I/O and the few that do can be cleaned up to remove the
>> work arounds for the lack of true 64 bit I/O by their maintainers.
>>     
>
> This is going to be a bit of a pain, and a lot of duplication.  My expectation 
> is that most devices don't know/care about 64-bit accesses and want them to 
> be automatically split into a pair of 32-bit accesses. I suggest pushing this 
> down into the lower level dispatch routines. By my reading your mem_writeq 
> helpers are broken if we happen to have multiple regions with the same opaque 
> value (this effects at least lsi53c895a.c).
>
> In the interests of avoiding duplication, I'd also implement 
> cpu_register_io_memory in terms of cpu_register_io_memory64.
>
>   
>> +    return ((CPUReadMemoryFunc64*)(*mmio->mem_read[idx][3]))
>> (mmio->opaque[idx][0][3],  addr + mmio->region_offset[idx][0][3]);
>>     
>
> Eww. It would be a good idea to fix this at the same time.
>
> Paul
>
>   
The right way to do this is to convert the whole tree at once
so we don't need the helper functions and two versions of
cpu_register_io_memory.  Unfortunately people have written
hardware drivers that rely on the current weird behavior by
caching half of a 64 bit access so it can be accessed later.  This doesn't
work if the registers can also be accessed as 32 bits because the
cache trick implies a specific order of access.

95% of the hardware drivers could be trivially converted and
work fine.  It's those few that play games that need to be looked
at carefully and converted properly to do the right thing.  I think
the authors or maintainers of those drivers have the best knowledge
to back out the current workarounds and do 64 bit I/O properly.

That's why I'm taking a 2 step approach using the helper functions
and 2 cpu_register_io_memory functions.  Once the entire tree is
converted to use the structures, the helper functions and the second
cpu_register_io_memory function would be removed.  I can provide
patches to convert sparc to the new API and also convert most of
the simple drivers.  However it's the ones that have workarounds
for the current behavior that need careful scrutiny.

The ideal time for applying this patch would be at the start of a
new development cycle.  95% of the drivers could be converted
immediately and the problem ones could be identified and fixed
afterwards.  The issues with the helper functions doing a linear
scan and not supporting overlapping regions for 64 bit accesses
would only be a problem for a short period of time (maybe a week)
and only for some of the drivers that have 64 bit access issues.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 13:46   ` Robert Reif
@ 2009-05-01 14:14     ` Paul Brook
  2009-05-01 14:39       ` Robert Reif
  0 siblings, 1 reply; 21+ messages in thread
From: Paul Brook @ 2009-05-01 14:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: Robert Reif

> The right way to do this is to convert the whole tree at once
> so we don't need the helper functions and two versions of
> cpu_register_io_memory.
> 95% of the hardware drivers could be trivially converted and
> work fine.  

I think you're missing my point. It's the 95% of drivers that I don't want to 
have to "convert". I'm working on the assumption that devices that actually 
implement 64-bit transfers are the exception rather than the rule.

So we have three options:

1) Omit the 64-bit handler for most devices. This will trigger the subwith 
code and associated overhead for no good reason[1].
2) Implement a 64-bit handler for every single device. 90% of these are going 
to be identical trivial wrappers round the 32-bit function. Maybe 5% actually 
need 64-bit accesses, and 5% are broken because someone messed up a 
copy/paste.
3) Implement splitting of 64-bit accesses in generic code.  Devices that 
actually care about 64-bit accesses can install a handler. Everything else 
indicates that it wants accesses split, either by a magic handler or a 
different registration function.

Your current patch implements a broken version of (3), with a vague hope that 
we'll switch to (2) at some time in the future.

I'm suggesting we implement (3) properly from the start.

Paul

[1] I still don't understand why the subwidth code exists, It's seems rather 
unlikely we'll have two different devices responding to different types of 
access the same address range. That's a separate argument though.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 12:03 ` Paul Brook
  2009-05-01 13:46   ` Robert Reif
@ 2009-05-01 14:25   ` Robert Reif
  2009-05-01 14:39     ` Paul Brook
  1 sibling, 1 reply; 21+ messages in thread
From: Robert Reif @ 2009-05-01 14:25 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

Paul Brook wrote:
>> The old array function call is supported so no existing drivers need
>> to be modified.  They can continue to do 2 32 bit accesses because 2
>> helper functions have been added to break up the accesses automatically.
>> However, the helper functions should only be used until all drivers are
>> converted to use the structure and then can be removed along
>> with the old array functions api.  The replacement of the arrays with
>> structures in the drivers is very straightforward for drivers that don't
>> do 64 bit I/O and the few that do can be cleaned up to remove the
>> work arounds for the lack of true 64 bit I/O by their maintainers.
>>     
>
> This is going to be a bit of a pain, and a lot of duplication.  My expectation 
> is that most devices don't know/care about 64-bit accesses and want them to 
> be automatically split into a pair of 32-bit accesses. I suggest pushing this 
> down into the lower level dispatch routines. By my reading your mem_writeq 
> helpers are broken if we happen to have multiple regions with the same opaque 
> value (this effects at least lsi53c895a.c).
>
> In the interests of avoiding duplication, I'd also implement 
> cpu_register_io_memory in terms of cpu_register_io_memory64.
>
>   
>> +    return ((CPUReadMemoryFunc64*)(*mmio->mem_read[idx][3]))
>> (mmio->opaque[idx][0][3],  addr + mmio->region_offset[idx][0][3]);
>>     
>
> Eww. It would be a good idea to fix this at the same time.
>
> Paul
>
>
>
>   
The issue this patch is trying to address is not the case where
software is trying to access 2 32 bit registers using a 64 bit
access (because that should fault on sane hardware) but the
case where we have a 64 bit counter and the 64 bit access is
split up into 2 32 bit accesses and the counter ends up being
read twice.  Some drivers work around this by caching half
of the 64 bit access so the cache is accessed for the second
half rather than the hardware.  However some hardware
(like sparc) can access the timer as either 32 or 64 bits so
this trick doesn't work.

Hardware that supports reading 2 32 bit registers with one 64
bit access can have the 64 callback do 2 32 bit accesses.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 14:25   ` Robert Reif
@ 2009-05-01 14:39     ` Paul Brook
  0 siblings, 0 replies; 21+ messages in thread
From: Paul Brook @ 2009-05-01 14:39 UTC (permalink / raw)
  To: Robert Reif; +Cc: qemu-devel

> Hardware that supports reading 2 32 bit registers with one 64
> bit access can have the 64 callback do 2 32 bit accesses.

Doesn't this include most PCI devices?

Paul

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 14:14     ` Paul Brook
@ 2009-05-01 14:39       ` Robert Reif
  2009-05-01 14:52         ` Paul Brook
  0 siblings, 1 reply; 21+ messages in thread
From: Robert Reif @ 2009-05-01 14:39 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1922 bytes --]

Paul Brook wrote:
>> The right way to do this is to convert the whole tree at once
>> so we don't need the helper functions and two versions of
>> cpu_register_io_memory.
>> 95% of the hardware drivers could be trivially converted and
>> work fine.  
>>     
>
> I think you're missing my point. It's the 95% of drivers that I don't want to 
> have to "convert". I'm working on the assumption that devices that actually 
> implement 64-bit transfers are the exception rather than the rule.
>
> So we have three options:
>
> 1) Omit the 64-bit handler for most devices. This will trigger the subwith 
> code and associated overhead for no good reason[1].
> 2) Implement a 64-bit handler for every single device. 90% of these are going 
> to be identical trivial wrappers round the 32-bit function. Maybe 5% actually 
> need 64-bit accesses, and 5% are broken because someone messed up a 
> copy/paste.
> 3) Implement splitting of 64-bit accesses in generic code.  Devices that 
> actually care about 64-bit accesses can install a handler. Everything else 
> indicates that it wants accesses split, either by a magic handler or a 
> different registration function.
>
> Your current patch implements a broken version of (3), with a vague hope that 
> we'll switch to (2) at some time in the future.
>
> I'm suggesting we implement (3) properly from the start.
>
> Paul
>
> [1] I still don't understand why the subwidth code exists, It's seems rather 
> unlikely we'll have two different devices responding to different types of 
> access the same address range. That's a separate argument though.
>
>   
Here is a patch for most of the sparc32 hardware drivers.  It's
a very trivial and mechanical process for these drivers.  The one
driver that does 64 bit accesses just adds 64 bit access functions
because it's broken now and has no workaround to remove.  I don't
think converting most other drivers will be much harder.

[-- Attachment #2: hw.diff.txt --]
[-- Type: text/plain, Size: 17209 bytes --]

Index: hw/sparc32_dma.c
===================================================================
--- hw/sparc32_dma.c	(revision 7191)
+++ hw/sparc32_dma.c	(working copy)
@@ -199,16 +199,18 @@
     s->dmaregs[saddr] = val;
 }
 
-static CPUReadMemoryFunc *dma_mem_read[3] = {
+static CPUReadMemoryFuncs dma_mem_read = {
     NULL,
     NULL,
     dma_mem_readl,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *dma_mem_write[3] = {
+static CPUWriteMemoryFuncs dma_mem_write = {
     NULL,
     NULL,
     dma_mem_writel,
+    NULL,
 };
 
 static void dma_reset(void *opaque)
@@ -252,7 +254,7 @@
     s->irq = parent_irq;
     s->iommu = iommu;
 
-    dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s);
+    dma_io_memory = cpu_register_io_memory64(0, &dma_mem_read, &dma_mem_write, s);
     cpu_register_physical_memory(daddr, DMA_SIZE, dma_io_memory);
 
     register_savevm("sparc32_dma", daddr, 2, dma_save, dma_load, s);
Index: hw/slavio_intctl.c
===================================================================
--- hw/slavio_intctl.c	(revision 7191)
+++ hw/slavio_intctl.c	(working copy)
@@ -132,16 +132,18 @@
     }
 }
 
-static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
+static CPUReadMemoryFuncs slavio_intctl_mem_read = {
     NULL,
     NULL,
     slavio_intctl_mem_readl,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
+static CPUWriteMemoryFuncs slavio_intctl_mem_write = {
     NULL,
     NULL,
     slavio_intctl_mem_writel,
+    NULL,
 };
 
 // master system interrupt controller
@@ -206,16 +208,18 @@
     }
 }
 
-static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
+static CPUReadMemoryFuncs slavio_intctlm_mem_read = {
     NULL,
     NULL,
     slavio_intctlm_mem_readl,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
+static CPUWriteMemoryFuncs slavio_intctlm_mem_write = {
     NULL,
     NULL,
     slavio_intctlm_mem_writel,
+    NULL,
 };
 
 void slavio_pic_info(Monitor *mon, void *opaque)
@@ -388,10 +392,10 @@
         slave->cpu = i;
         slave->master = s;
 
-        slavio_intctl_io_memory = cpu_register_io_memory(0,
-                                                         slavio_intctl_mem_read,
-                                                         slavio_intctl_mem_write,
-                                                         slave);
+        slavio_intctl_io_memory = cpu_register_io_memory64(0,
+                                                           &slavio_intctl_mem_read,
+                                                           &slavio_intctl_mem_write,
+                                                           slave);
         cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE,
                                      slavio_intctl_io_memory);
 
@@ -399,10 +403,10 @@
         s->cpu_irqs[i] = parent_irq[i];
     }
 
-    slavio_intctlm_io_memory = cpu_register_io_memory(0,
-                                                      slavio_intctlm_mem_read,
-                                                      slavio_intctlm_mem_write,
-                                                      s);
+    slavio_intctlm_io_memory = cpu_register_io_memory64(0,
+                                                        &slavio_intctlm_mem_read,
+                                                        &slavio_intctlm_mem_write,
+                                                        s);
     cpu_register_physical_memory(addrg, INTCTLM_SIZE, slavio_intctlm_io_memory);
 
     register_savevm("slavio_intctl", addr, 1, slavio_intctl_save,
Index: hw/tcx.c
===================================================================
--- hw/tcx.c	(revision 7191)
+++ hw/tcx.c	(working copy)
@@ -463,16 +463,18 @@
     return;
 }
 
-static CPUReadMemoryFunc *tcx_dac_read[3] = {
+static CPUReadMemoryFuncs tcx_dac_read = {
     NULL,
     NULL,
     tcx_dac_readl,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *tcx_dac_write[3] = {
+static CPUWriteMemoryFuncs tcx_dac_write = {
     NULL,
     NULL,
     tcx_dac_writel,
+    NULL,
 };
 
 static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
@@ -485,16 +487,18 @@
 {
 }
 
-static CPUReadMemoryFunc *tcx_dummy_read[3] = {
+static CPUReadMemoryFuncs tcx_dummy_read = {
     NULL,
     NULL,
     tcx_dummy_readl,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
+static CPUWriteMemoryFuncs tcx_dummy_write = {
     NULL,
     NULL,
     tcx_dummy_writel,
+    NULL,
 };
 
 void tcx_init(target_phys_addr_t addr, int vram_size, int width, int height,
@@ -523,12 +527,12 @@
     vram_offset += size;
     vram_base += size;
 
-    io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
+    io_memory = cpu_register_io_memory64(0, &tcx_dac_read, &tcx_dac_write, s);
     cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS,
                                  io_memory);
 
-    dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write,
-                                          s);
+    dummy_memory = cpu_register_io_memory64(0, &tcx_dummy_read,
+                                            &tcx_dummy_write, s);
     cpu_register_physical_memory(addr + 0x00700000ULL, TCX_TEC_NREGS,
                                  dummy_memory);
     if (depth == 24) {
Index: hw/iommu.c
===================================================================
--- hw/iommu.c	(revision 7191)
+++ hw/iommu.c	(working copy)
@@ -236,16 +236,18 @@
     }
 }
 
-static CPUReadMemoryFunc *iommu_mem_read[3] = {
+static CPUReadMemoryFuncs iommu_mem_read = {
     NULL,
     NULL,
     iommu_mem_readl,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *iommu_mem_write[3] = {
+static CPUWriteMemoryFuncs iommu_mem_write = {
     NULL,
     NULL,
     iommu_mem_writel,
+    NULL,
 };
 
 static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr)
@@ -375,8 +377,8 @@
     s->version = version;
     s->irq = irq;
 
-    iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read,
-                                             iommu_mem_write, s);
+    iommu_io_memory = cpu_register_io_memory64(0, &iommu_mem_read,
+                                               &iommu_mem_write, s);
     cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory);
 
     register_savevm("iommu", addr, 2, iommu_save, iommu_load, s);
Index: hw/esp.c
===================================================================
--- hw/esp.c	(revision 7191)
+++ hw/esp.c	(working copy)
@@ -563,16 +563,18 @@
     s->wregs[saddr] = val;
 }
 
-static CPUReadMemoryFunc *esp_mem_read[3] = {
+static CPUReadMemoryFuncs esp_mem_read = {
     esp_mem_readb,
     NULL,
     NULL,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *esp_mem_write[3] = {
+static CPUWriteMemoryFuncs esp_mem_write = {
     esp_mem_writeb,
     NULL,
     esp_mem_writeb,
+    NULL,
 };
 
 static void esp_save(QEMUFile *f, void *opaque)
@@ -660,7 +662,8 @@
     s->dma_memory_write = dma_memory_write;
     s->dma_opaque = dma_opaque;
 
-    esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
+    esp_io_memory = cpu_register_io_memory64(0, &esp_mem_read, &esp_mem_write,
+                                             s);
     cpu_register_physical_memory(espaddr, ESP_REGS << it_shift, esp_io_memory);
 
     esp_reset(s);
Index: hw/m48t59.c
===================================================================
--- hw/m48t59.c	(revision 7191)
+++ hw/m48t59.c	(working copy)
@@ -565,16 +565,18 @@
     return retval;
 }
 
-static CPUWriteMemoryFunc *nvram_write[] = {
-    &nvram_writeb,
-    &nvram_writew,
-    &nvram_writel,
+static CPUWriteMemoryFuncs nvram_write = {
+    nvram_writeb,
+    nvram_writew,
+    nvram_writel,
+    NULL,
 };
 
-static CPUReadMemoryFunc *nvram_read[] = {
-    &nvram_readb,
-    &nvram_readw,
-    &nvram_readl,
+static CPUReadMemoryFuncs nvram_read = {
+    nvram_readb,
+    nvram_readw,
+    nvram_readl,
+    NULL,
 };
 
 static void m48t59_save(QEMUFile *f, void *opaque)
@@ -632,7 +634,8 @@
         register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
     }
     if (mem_base != 0) {
-        s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
+        s->mem_index = cpu_register_io_memory64(0, &nvram_read, &nvram_write,
+                                                s);
         cpu_register_physical_memory(mem_base, size, s->mem_index);
     }
     if (type == 59) {
Index: hw/slavio_misc.c
===================================================================
--- hw/slavio_misc.c	(revision 7191)
+++ hw/slavio_misc.c	(working copy)
@@ -128,16 +128,18 @@
     return ret;
 }
 
-static CPUReadMemoryFunc *slavio_cfg_mem_read[3] = {
+static CPUReadMemoryFuncs slavio_cfg_mem_read = {
     slavio_cfg_mem_readb,
     NULL,
     NULL,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *slavio_cfg_mem_write[3] = {
+static CPUWriteMemoryFuncs slavio_cfg_mem_write = {
     slavio_cfg_mem_writeb,
     NULL,
     NULL,
+    NULL,
 };
 
 static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
@@ -159,16 +161,18 @@
     return ret;
 }
 
-static CPUReadMemoryFunc *slavio_diag_mem_read[3] = {
+static CPUReadMemoryFuncs slavio_diag_mem_read = {
     slavio_diag_mem_readb,
     NULL,
     NULL,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *slavio_diag_mem_write[3] = {
+static CPUWriteMemoryFuncs slavio_diag_mem_write = {
     slavio_diag_mem_writeb,
     NULL,
     NULL,
+    NULL,
 };
 
 static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
@@ -190,16 +194,18 @@
     return ret;
 }
 
-static CPUReadMemoryFunc *slavio_mdm_mem_read[3] = {
+static CPUReadMemoryFuncs slavio_mdm_mem_read = {
     slavio_mdm_mem_readb,
     NULL,
     NULL,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *slavio_mdm_mem_write[3] = {
+static CPUWriteMemoryFuncs slavio_mdm_mem_write = {
     slavio_mdm_mem_writeb,
     NULL,
     NULL,
+    NULL,
 };
 
 static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
@@ -230,16 +236,18 @@
     return ret;
 }
 
-static CPUReadMemoryFunc *slavio_aux1_mem_read[3] = {
+static CPUReadMemoryFuncs slavio_aux1_mem_read = {
     slavio_aux1_mem_readb,
     NULL,
     NULL,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *slavio_aux1_mem_write[3] = {
+static CPUWriteMemoryFuncs slavio_aux1_mem_write = {
     slavio_aux1_mem_writeb,
     NULL,
     NULL,
+    NULL,
 };
 
 static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
@@ -269,16 +277,18 @@
     return ret;
 }
 
-static CPUReadMemoryFunc *slavio_aux2_mem_read[3] = {
+static CPUReadMemoryFuncs slavio_aux2_mem_read = {
     slavio_aux2_mem_readb,
     NULL,
     NULL,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *slavio_aux2_mem_write[3] = {
+static CPUWriteMemoryFuncs slavio_aux2_mem_write = {
     slavio_aux2_mem_writeb,
     NULL,
     NULL,
+    NULL,
 };
 
 static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -297,16 +307,18 @@
     return ret;
 }
 
-static CPUReadMemoryFunc *apc_mem_read[3] = {
+static CPUReadMemoryFuncs apc_mem_read = {
     apc_mem_readb,
     NULL,
     NULL,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *apc_mem_write[3] = {
+static CPUWriteMemoryFuncs apc_mem_write = {
     apc_mem_writeb,
     NULL,
     NULL,
+    NULL,
 };
 
 static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
@@ -343,16 +355,18 @@
     }
 }
 
-static CPUReadMemoryFunc *slavio_sysctrl_mem_read[3] = {
+static CPUReadMemoryFuncs slavio_sysctrl_mem_read = {
     NULL,
     NULL,
     slavio_sysctrl_mem_readl,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = {
+static CPUWriteMemoryFuncs slavio_sysctrl_mem_write = {
     NULL,
     NULL,
     slavio_sysctrl_mem_writel,
+    NULL,
 };
 
 static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
@@ -386,16 +400,18 @@
     }
 }
 
-static CPUReadMemoryFunc *slavio_led_mem_read[3] = {
+static CPUReadMemoryFuncs slavio_led_mem_read = {
     NULL,
     slavio_led_mem_readw,
     NULL,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *slavio_led_mem_write[3] = {
+static CPUWriteMemoryFuncs slavio_led_mem_write = {
     NULL,
     slavio_led_mem_writew,
     NULL,
+    NULL,
 };
 
 static void slavio_misc_save(QEMUFile *f, void *opaque)
@@ -448,50 +464,50 @@
         /* 8 bit registers */
 
         // Slavio control
-        io = cpu_register_io_memory(0, slavio_cfg_mem_read,
-                                    slavio_cfg_mem_write, s);
+        io = cpu_register_io_memory64(0, &slavio_cfg_mem_read,
+                                      &slavio_cfg_mem_write, s);
         cpu_register_physical_memory(base + MISC_CFG, MISC_SIZE, io);
 
         // Diagnostics
-        io = cpu_register_io_memory(0, slavio_diag_mem_read,
-                                    slavio_diag_mem_write, s);
+        io = cpu_register_io_memory64(0, &slavio_diag_mem_read,
+                                      &slavio_diag_mem_write, s);
         cpu_register_physical_memory(base + MISC_DIAG, MISC_SIZE, io);
 
         // Modem control
-        io = cpu_register_io_memory(0, slavio_mdm_mem_read,
-                                    slavio_mdm_mem_write, s);
+        io = cpu_register_io_memory64(0, &slavio_mdm_mem_read,
+                                      &slavio_mdm_mem_write, s);
         cpu_register_physical_memory(base + MISC_MDM, MISC_SIZE, io);
 
         /* 16 bit registers */
-        io = cpu_register_io_memory(0, slavio_led_mem_read,
-                                    slavio_led_mem_write, s);
+        io = cpu_register_io_memory64(0, &slavio_led_mem_read,
+                                      &slavio_led_mem_write, s);
         /* ss600mp diag LEDs */
         cpu_register_physical_memory(base + MISC_LEDS, MISC_SIZE, io);
 
         /* 32 bit registers */
-        io = cpu_register_io_memory(0, slavio_sysctrl_mem_read,
-                                    slavio_sysctrl_mem_write, s);
+        io = cpu_register_io_memory64(0, &slavio_sysctrl_mem_read,
+                                      &slavio_sysctrl_mem_write, s);
         // System control
         cpu_register_physical_memory(base + MISC_SYS, SYSCTRL_SIZE, io);
     }
 
     // AUX 1 (Misc System Functions)
     if (aux1_base) {
-        io = cpu_register_io_memory(0, slavio_aux1_mem_read,
-                                    slavio_aux1_mem_write, s);
+        io = cpu_register_io_memory64(0, &slavio_aux1_mem_read,
+                                      &slavio_aux1_mem_write, s);
         cpu_register_physical_memory(aux1_base, MISC_SIZE, io);
     }
 
     // AUX 2 (Software Powerdown Control)
     if (aux2_base) {
-        io = cpu_register_io_memory(0, slavio_aux2_mem_read,
-                                    slavio_aux2_mem_write, s);
+        io = cpu_register_io_memory64(0, &slavio_aux2_mem_read,
+                                      &slavio_aux2_mem_write, s);
         cpu_register_physical_memory(aux2_base, MISC_SIZE, io);
     }
 
     // Power management (APC) XXX: not a Slavio device
     if (power_base) {
-        io = cpu_register_io_memory(0, apc_mem_read, apc_mem_write, s);
+        io = cpu_register_io_memory64(0, &apc_mem_read, &apc_mem_write, s);
         cpu_register_physical_memory(power_base, MISC_SIZE, io);
     }
 
Index: hw/eccmemctl.c
===================================================================
--- hw/eccmemctl.c	(revision 7191)
+++ hw/eccmemctl.c	(working copy)
@@ -220,16 +220,18 @@
     return ret;
 }
 
-static CPUReadMemoryFunc *ecc_mem_read[3] = {
+static CPUReadMemoryFuncs ecc_mem_read = {
     NULL,
     NULL,
     ecc_mem_readl,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *ecc_mem_write[3] = {
+static CPUWriteMemoryFuncs ecc_mem_write = {
     NULL,
     NULL,
     ecc_mem_writel,
+    NULL,
 };
 
 static void ecc_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
@@ -250,16 +252,18 @@
     return ret;
 }
 
-static CPUReadMemoryFunc *ecc_diag_mem_read[3] = {
+static CPUReadMemoryFuncs ecc_diag_mem_read = {
     ecc_diag_mem_readb,
     NULL,
     NULL,
+    NULL,
 };
 
-static CPUWriteMemoryFunc *ecc_diag_mem_write[3] = {
+static CPUWriteMemoryFuncs ecc_diag_mem_write = {
     ecc_diag_mem_writeb,
     NULL,
     NULL,
+    NULL,
 };
 
 static int ecc_load(QEMUFile *f, void *opaque, int version_id)
@@ -325,11 +329,12 @@
     s->regs[0] = version;
     s->irq = irq;
 
-    ecc_io_memory = cpu_register_io_memory(0, ecc_mem_read, ecc_mem_write, s);
+    ecc_io_memory = cpu_register_io_memory64(0, &ecc_mem_read, &ecc_mem_write,
+                                             s);
     cpu_register_physical_memory(base, ECC_SIZE, ecc_io_memory);
     if (version == ECC_MCC) { // SS-600MP only
-        ecc_io_memory = cpu_register_io_memory(0, ecc_diag_mem_read,
-                                               ecc_diag_mem_write, s);
+        ecc_io_memory = cpu_register_io_memory64(0, &ecc_diag_mem_read,
+                                                 &ecc_diag_mem_write, s);
         cpu_register_physical_memory(base + 0x1000, ECC_DIAG_SIZE,
                                      ecc_io_memory);
     }

[-- Attachment #3: slavio_timer.diff.txt --]
[-- Type: text/plain, Size: 3785 bytes --]

Index: hw/slavio_timer.c
===================================================================
--- hw/slavio_timer.c	(revision 7190)
+++ hw/slavio_timer.c	(working copy)
@@ -137,9 +137,17 @@
         // read limit (system counter mode) or read most signifying
         // part of counter (user mode)
         if (slavio_timer_is_user(s)) {
+            uint64_t last_count = (uint64_t)(s->counthigh) << 32 | s->count;
             // read user timer MSW
             slavio_timer_get_out(s);
             ret = s->counthigh | s->reached;
+            if (last_count == TIMER_MAX_COUNT64) { 
+                uint64_t new_count = (uint64_t)ret << 32 | s->count;
+                if (new_count != last_count) {
+                    s->reached = TIMER_REACHED;
+                    ret |= TIMER_REACHED;
+                }
+            }  
         } else {
             // read limit
             // clear irq
@@ -177,6 +185,31 @@
     return ret;
 }
 
+static uint64_t slavio_timer_mem_readq(void *opaque, target_phys_addr_t addr)
+{
+    SLAVIO_TIMERState *s = opaque;
+    uint32_t saddr;
+    uint64_t ret = 0;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case TIMER_LIMIT:
+        if (slavio_timer_is_user(s)) {
+            uint64_t last_count = (uint64_t)(s->counthigh) << 32 | s->count;
+            slavio_timer_get_out(s);
+            ret = (uint64_t)(s->counthigh | s->reached) << 32 | s->count;
+            if (last_count == TIMER_MAX_COUNT64 && ret != last_count) {
+                s->reached = TIMER_REACHED;
+                ret |= ((uint64_t)TIMER_REACHED << 32);
+            }  
+        }
+        break;
+    }
+    DPRINTF("read " TARGET_FMT_plx " = %016llx\n", addr, ret);
+
+    return ret;
+}
+
 static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
                                     uint32_t val)
 {
@@ -303,16 +336,45 @@
     }
 }
 
-static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
+static void slavio_timer_mem_writeq(void *opaque, target_phys_addr_t addr,
+                                    uint64_t val)
+{
+    SLAVIO_TIMERState *s = opaque;
+    uint32_t saddr;
+
+    DPRINTF("write " TARGET_FMT_plx " %016llx\n", addr, val);
+    saddr = addr >> 2;
+    switch (saddr) {
+    case TIMER_LIMIT:
+        if (slavio_timer_is_user(s)) {
+            uint64_t count;
+
+            s->limit = TIMER_MAX_COUNT64;
+            s->count = val & TIMER_MAX_COUNT64;
+            s->counthigh = (val & TIMER_MAX_COUNT64) >> 32;
+            s->reached = 0;
+            count = ((uint64_t)s->counthigh << 32) | s->count;
+            DPRINTF("processor %d user timer set to %016llx\n", s->slave_index,
+                    count);
+            if (s->timer)
+                ptimer_set_count(s->timer, LIMIT_TO_PERIODS(s->limit - count));
+        }
+        break;
+    }
+}
+
+static CPUReadMemoryFuncs slavio_timer_mem_read = {
     NULL,
     NULL,
     slavio_timer_mem_readl,
+    slavio_timer_mem_readq
 };
 
-static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
+static CPUWriteMemoryFuncs slavio_timer_mem_write = {
     NULL,
     NULL,
     slavio_timer_mem_writel,
+    slavio_timer_mem_writeq
 };
 
 static void slavio_timer_save(QEMUFile *f, void *opaque)
@@ -381,8 +443,8 @@
         ptimer_set_period(s->timer, TIMER_PERIOD);
     }
 
-    slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
-                                                    slavio_timer_mem_write, s);
+    slavio_timer_io_memory = cpu_register_io_memory64(0, &slavio_timer_mem_read,
+                                                      &slavio_timer_mem_write, s);
     if (master)
         cpu_register_physical_memory(addr, CPU_TIMER_SIZE,
                                      slavio_timer_io_memory);

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 14:39       ` Robert Reif
@ 2009-05-01 14:52         ` Paul Brook
  2009-05-01 15:19           ` Robert Reif
  0 siblings, 1 reply; 21+ messages in thread
From: Paul Brook @ 2009-05-01 14:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: Robert Reif

> Here is a patch for most of the sparc32 hardware drivers.  It's
> a very trivial and mechanical process for these drivers.  The one
> driver that does 64 bit accesses just adds 64 bit access functions
> because it's broken now and has no workaround to remove.  I don't
> think converting most other drivers will be much harder.

sparc hardware is rather abnormal (for qemu at least) because it cares what 
happens when you use the wrong width. Most devices don't care, and having any 
NULL functions is liable to introduce significant overhead.

Paul

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 14:52         ` Paul Brook
@ 2009-05-01 15:19           ` Robert Reif
  2009-05-01 15:33             ` Paul Brook
  2009-05-01 23:42             ` Robert Reif
  0 siblings, 2 replies; 21+ messages in thread
From: Robert Reif @ 2009-05-01 15:19 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

Paul Brook wrote:
>> Here is a patch for most of the sparc32 hardware drivers.  It's
>> a very trivial and mechanical process for these drivers.  The one
>> driver that does 64 bit accesses just adds 64 bit access functions
>> because it's broken now and has no workaround to remove.  I don't
>> think converting most other drivers will be much harder.
>>     
>
> sparc hardware is rather abnormal (for qemu at least) because it cares what 
> happens when you use the wrong width. Most devices don't care, and having any 
> NULL functions is liable to introduce significant overhead.
>
> Paul
>
>   
Ok, so that explains the curious code in m48t59.c:

static void nvram_writeb (void *opaque, target_phys_addr_t addr, 
uint32_t value)
{
    m48t59_t *NVRAM = opaque;

    m48t59_write(NVRAM, addr, value & 0xff);
}

static void nvram_writew (void *opaque, target_phys_addr_t addr, 
uint32_t value)
{
    m48t59_t *NVRAM = opaque;

    m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
    m48t59_write(NVRAM, addr + 1, value & 0xff);
}

static void nvram_writel (void *opaque, target_phys_addr_t addr, 
uint32_t value)
{
    m48t59_t *NVRAM = opaque;

    m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
    m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
    m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
    m48t59_write(NVRAM, addr + 3, value & 0xff);
}

So nvram_writeq should be present on non sparc architectures
and actually should be doing 8 byte accesses?  How do we handle
architecture differences like this?  On sparc, it looks like the
sbus controller does this because the actual hardware really
only has an 8 bit bus.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 15:19           ` Robert Reif
@ 2009-05-01 15:33             ` Paul Brook
  2009-05-01 15:51               ` Blue Swirl
  2009-05-02  0:02               ` Robert Reif
  2009-05-01 23:42             ` Robert Reif
  1 sibling, 2 replies; 21+ messages in thread
From: Paul Brook @ 2009-05-01 15:33 UTC (permalink / raw)
  To: Robert Reif; +Cc: qemu-devel

> > sparc hardware is rather abnormal (for qemu at least) because it cares
> > what happens when you use the wrong width. Most devices don't care, and
> > having any NULL functions is liable to introduce significant overhead.
>
> Ok, so that explains the curious code in m48t59.c:
>...
> So nvram_writeq should be present on non sparc architectures
> and actually should be doing 8 byte accesses?  How do we handle
> architecture differences like this?  On sparc, it looks like the
> sbus controller does this because the actual hardware really
> only has an 8 bit bus.

Are there actually any cases where this matters?

My guess is that in pactice we only have certain SPARC devices that need to 
trap when you do a wrong sized access, and for everything else you're told 
not to do that, and qemu can happily return garbage.

If this is the case then the IO_MEM_SUBWIDTH code seems like complete 
overkill. I reccommend ripping it out, and maybe having the registration 
function replace NULL with the unassigned hander.

Paul

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 15:33             ` Paul Brook
@ 2009-05-01 15:51               ` Blue Swirl
  2009-05-01 16:36                 ` Edgar E. Iglesias
  2009-05-01 17:29                 ` Robert Reif
  2009-05-02  0:02               ` Robert Reif
  1 sibling, 2 replies; 21+ messages in thread
From: Blue Swirl @ 2009-05-01 15:51 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel, Robert Reif

On 5/1/09, Paul Brook <paul@codesourcery.com> wrote:
> > > sparc hardware is rather abnormal (for qemu at least) because it cares
>  > > what happens when you use the wrong width. Most devices don't care, and
>  > > having any NULL functions is liable to introduce significant overhead.
>  >
>
> > Ok, so that explains the curious code in m48t59.c:
>
> >...
>
> > So nvram_writeq should be present on non sparc architectures
>  > and actually should be doing 8 byte accesses?  How do we handle
>  > architecture differences like this?  On sparc, it looks like the
>  > sbus controller does this because the actual hardware really
>  > only has an 8 bit bus.
>
>
> Are there actually any cases where this matters?
>
>  My guess is that in pactice we only have certain SPARC devices that need to
>  trap when you do a wrong sized access, and for everything else you're told
>  not to do that, and qemu can happily return garbage.
>
>  If this is the case then the IO_MEM_SUBWIDTH code seems like complete
>  overkill. I reccommend ripping it out, and maybe having the registration
>  function replace NULL with the unassigned hander.

Maybe the registration could also be changed so that if the device
only cares for (say) 16 bits (and does not want trapping for the wrong
sized access), the 64, 32 and 8 bit cases are emulated at higher
level. This would shrink the code base a bit and maybe fits to the bus
model.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 15:51               ` Blue Swirl
@ 2009-05-01 16:36                 ` Edgar E. Iglesias
  2009-05-01 17:29                 ` Robert Reif
  1 sibling, 0 replies; 21+ messages in thread
From: Edgar E. Iglesias @ 2009-05-01 16:36 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Robert Reif, Paul Brook, qemu-devel

On Fri, May 01, 2009 at 06:51:08PM +0300, Blue Swirl wrote:
> On 5/1/09, Paul Brook <paul@codesourcery.com> wrote:
> > > > sparc hardware is rather abnormal (for qemu at least) because it cares
> >  > > what happens when you use the wrong width. Most devices don't care, and
> >  > > having any NULL functions is liable to introduce significant overhead.
> >  >
> >
> > > Ok, so that explains the curious code in m48t59.c:
> >
> > >...
> >
> > > So nvram_writeq should be present on non sparc architectures
> >  > and actually should be doing 8 byte accesses?  How do we handle
> >  > architecture differences like this?  On sparc, it looks like the
> >  > sbus controller does this because the actual hardware really
> >  > only has an 8 bit bus.
> >
> >
> > Are there actually any cases where this matters?
> >
> >  My guess is that in pactice we only have certain SPARC devices that need to
> >  trap when you do a wrong sized access, and for everything else you're told
> >  not to do that, and qemu can happily return garbage.
> >
> >  If this is the case then the IO_MEM_SUBWIDTH code seems like complete
> >  overkill. I reccommend ripping it out, and maybe having the registration
> >  function replace NULL with the unassigned hander.
> 
> Maybe the registration could also be changed so that if the device
> only cares for (say) 16 bits (and does not want trapping for the wrong
> sized access), the 64, 32 and 8 bit cases are emulated at higher
> level. This would shrink the code base a bit and maybe fits to the bus
> model.

I'd appreciate something along these lines :)

Cheers

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 15:51               ` Blue Swirl
  2009-05-01 16:36                 ` Edgar E. Iglesias
@ 2009-05-01 17:29                 ` Robert Reif
  1 sibling, 0 replies; 21+ messages in thread
From: Robert Reif @ 2009-05-01 17:29 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Paul Brook, qemu-devel

Blue Swirl wrote:
> On 5/1/09, Paul Brook <paul@codesourcery.com> wrote:
>   
>>>> sparc hardware is rather abnormal (for qemu at least) because it cares
>>>>         
>>  > > what happens when you use the wrong width. Most devices don't care, and
>>  > > having any NULL functions is liable to introduce significant overhead.
>>  >
>>
>>     
>>> Ok, so that explains the curious code in m48t59.c:
>>>       
>>> ...
>>>       
>>> So nvram_writeq should be present on non sparc architectures
>>>       
>>  > and actually should be doing 8 byte accesses?  How do we handle
>>  > architecture differences like this?  On sparc, it looks like the
>>  > sbus controller does this because the actual hardware really
>>  > only has an 8 bit bus.
>>
>>
>> Are there actually any cases where this matters?
>>
>>  My guess is that in pactice we only have certain SPARC devices that need to
>>  trap when you do a wrong sized access, and for everything else you're told
>>  not to do that, and qemu can happily return garbage.
>>
>>  If this is the case then the IO_MEM_SUBWIDTH code seems like complete
>>  overkill. I reccommend ripping it out, and maybe having the registration
>>  function replace NULL with the unassigned hander.
>>     
>
> Maybe the registration could also be changed so that if the device
> only cares for (say) 16 bits (and does not want trapping for the wrong
> sized access), the 64, 32 and 8 bit cases are emulated at higher
> level. This would shrink the code base a bit and maybe fits to the bus
> model.
>
>
>
>   
This sounds like the way to go.  The device would only need to support
its natural bus width and a higher level bus driver would be responsible
for doing the bus width conversion or faulting.  This moves the bus width
conversion code from each driver up to a specific bus driver.  The bus
driver could be a simple as converting NULL to helper functions.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 15:19           ` Robert Reif
  2009-05-01 15:33             ` Paul Brook
@ 2009-05-01 23:42             ` Robert Reif
  2009-05-01 23:57               ` Paul Brook
  1 sibling, 1 reply; 21+ messages in thread
From: Robert Reif @ 2009-05-01 23:42 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

Robert Reif wrote:
>
> static void nvram_writel (void *opaque, target_phys_addr_t addr, 
> uint32_t value)
> {
>    m48t59_t *NVRAM = opaque;
>
>    m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
>    m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
>    m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
>    m48t59_write(NVRAM, addr + 3, value & 0xff);
> }
>
static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, 
uint32_t val)
{
#ifdef TARGET_WORDS_BIGENDIAN
    cirrus_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
    cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
    cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
    cirrus_vga_mem_writeb(opaque, addr + 3, val & 0xff);
#else
    cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
    cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
    cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
    cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
#endif
}

Should a new intermediate bus layer also do byte swapping?

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 23:42             ` Robert Reif
@ 2009-05-01 23:57               ` Paul Brook
  2009-05-02 15:23                 ` Blue Swirl
  0 siblings, 1 reply; 21+ messages in thread
From: Paul Brook @ 2009-05-01 23:57 UTC (permalink / raw)
  To: qemu-devel; +Cc: Robert Reif

> Should a new intermediate bus layer also do byte swapping?

Yes, though a bus layer isn't actually a necessary prerequisite.

As I mentioned in the recent "Smarter compilation for target devices" 
thread[1], having individual devices do byteswapping is bogus. A while ago I 
reworked the TLB handling, so there should now be spare bits that can be used 
for things like byteswapping.

Paul

[1] http://lists.gnu.org/archive/html/qemu-devel/2009-04/msg01820.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 15:33             ` Paul Brook
  2009-05-01 15:51               ` Blue Swirl
@ 2009-05-02  0:02               ` Robert Reif
  2009-05-02  0:40                 ` Paul Brook
  1 sibling, 1 reply; 21+ messages in thread
From: Robert Reif @ 2009-05-02  0:02 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel

Paul Brook wrote:
>>> sparc hardware is rather abnormal (for qemu at least) because it cares
>>> what happens when you use the wrong width. Most devices don't care, and
>>> having any NULL functions is liable to introduce significant overhead.
>>>       
>> Ok, so that explains the curious code in m48t59.c:
>> ...
>> So nvram_writeq should be present on non sparc architectures
>> and actually should be doing 8 byte accesses?  How do we handle
>> architecture differences like this?  On sparc, it looks like the
>> sbus controller does this because the actual hardware really
>> only has an 8 bit bus.
>>     
>
> Are there actually any cases where this matters?
>
> My guess is that in pactice we only have certain SPARC devices that need to 
> trap when you do a wrong sized access, and for everything else you're told 
> not to do that, and qemu can happily return garbage.
>
> If this is the case then the IO_MEM_SUBWIDTH code seems like complete 
> overkill. I reccommend ripping it out, and maybe having the registration 
> function replace NULL with the unassigned hander.
>
> Paul
>
>
>
>   
Wouldn't making a version of the subpage structure the default
and getting rid of the multiple parallel arrays make more sense.
Then there would only be one type of I/O memory and no special
cases.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-02  0:02               ` Robert Reif
@ 2009-05-02  0:40                 ` Paul Brook
  0 siblings, 0 replies; 21+ messages in thread
From: Paul Brook @ 2009-05-02  0:40 UTC (permalink / raw)
  To: qemu-devel; +Cc: Robert Reif

> > My guess is that in pactice we only have certain SPARC devices that need
> > to trap when you do a wrong sized access, and for everything else you're
> > told not to do that, and qemu can happily return garbage.
> >
> > If this is the case then the IO_MEM_SUBWIDTH code seems like complete
> > overkill. I reccommend ripping it out, and maybe having the registration
> > function replace NULL with the unassigned hander.
>
> Wouldn't making a version of the subpage structure the default
> and getting rid of the multiple parallel arrays make more sense.
> Then there would only be one type of I/O memory and no special
> cases.

I'm not sure what you're suggesting. I've yet to see any actual use of the 
subwidth code, and the subpage stuff is fairly rare. 

Trying to push the subpage code down into the TLB handler might be possible, 
but you'd have to be careful to avoid performance regressions in the common 
code.

Paul

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-01 23:57               ` Paul Brook
@ 2009-05-02 15:23                 ` Blue Swirl
  2009-05-02 19:35                   ` Paul Brook
  2009-05-05  1:59                   ` Jamie Lokier
  0 siblings, 2 replies; 21+ messages in thread
From: Blue Swirl @ 2009-05-02 15:23 UTC (permalink / raw)
  To: Paul Brook; +Cc: qemu-devel, Robert Reif

[-- Attachment #1: Type: text/plain, Size: 1070 bytes --]

On 5/2/09, Paul Brook <paul@codesourcery.com> wrote:
> > Should a new intermediate bus layer also do byte swapping?
>
>
> Yes, though a bus layer isn't actually a necessary prerequisite.
>
>  As I mentioned in the recent "Smarter compilation for target devices"
>  thread[1], having individual devices do byteswapping is bogus. A while ago I
>  reworked the TLB handling, so there should now be spare bits that can be used
>  for things like byteswapping.

This version does the byte swapping and width translation in exec.c.
Sparc32 OpenBIOS/Linux does not use the wrong sized accesses, so that
part may be untested.

Some problems:

- Small writes cause a read-modify-write cycle, but I think that may
happen with real devices too. Another solution is to write zero in
other byte lanes without reading.

- The LE/BE distinction does not seem to be very obvious for devices.
I think the board should give the is_le value to the device.

- There is a small performance hit for the native access case. This
could be avoided by extending io_mem_opaque to cover all sizes.

[-- Attachment #2: Emulate_non_native_widths.patch --]
[-- Type: application/mbox, Size: 22862 bytes --]

[-- Attachment #3: Use_new_registration_functions.patch --]
[-- Type: application/mbox, Size: 4761 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-02 15:23                 ` Blue Swirl
@ 2009-05-02 19:35                   ` Paul Brook
  2009-05-05  1:59                   ` Jamie Lokier
  1 sibling, 0 replies; 21+ messages in thread
From: Paul Brook @ 2009-05-02 19:35 UTC (permalink / raw)
  To: qemu-devel; +Cc: Blue Swirl, Robert Reif

On Saturday 02 May 2009, Blue Swirl wrote:
> On 5/2/09, Paul Brook <paul@codesourcery.com> wrote:
> > > Should a new intermediate bus layer also do byte swapping?
> >
> > Yes, though a bus layer isn't actually a necessary prerequisite.
> >
> >  As I mentioned in the recent "Smarter compilation for target devices"
> >  thread[1], having individual devices do byteswapping is bogus. A while
> > ago I reworked the TLB handling, so there should now be spare bits that
> > can be used for things like byteswapping.
>
> This version does the byte swapping and width translation in exec.c.
> Sparc32 OpenBIOS/Linux does not use the wrong sized accesses, so that
> part may be untested.

This appears to be adding yet annother layer of indirection, which isn't 
really what I had inmind.

Paul

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-02 15:23                 ` Blue Swirl
  2009-05-02 19:35                   ` Paul Brook
@ 2009-05-05  1:59                   ` Jamie Lokier
  2009-05-05  6:05                     ` Edgar E. Iglesias
  1 sibling, 1 reply; 21+ messages in thread
From: Jamie Lokier @ 2009-05-05  1:59 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Robert Reif, Paul Brook, qemu-devel

Blue Swirl wrote:
> - Small writes cause a read-modify-write cycle, but I think that may
> happen with real devices too. Another solution is to write zero in
> other byte lanes without reading.

On PCI and I think most buses, there are separate byte-enable pins for
writing each byte lane and the hardware can decide to ignore the
unenabled bytes or not.

-- Jamie

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH] 64 bit I/O support v7
  2009-05-05  1:59                   ` Jamie Lokier
@ 2009-05-05  6:05                     ` Edgar E. Iglesias
  0 siblings, 0 replies; 21+ messages in thread
From: Edgar E. Iglesias @ 2009-05-05  6:05 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: Blue Swirl, qemu-devel, Paul Brook, Robert Reif

On Tue, May 05, 2009 at 02:59:28AM +0100, Jamie Lokier wrote:
> Blue Swirl wrote:
> > - Small writes cause a read-modify-write cycle, but I think that may
> > happen with real devices too. Another solution is to write zero in
> > other byte lanes without reading.
> 
> On PCI and I think most buses, there are separate byte-enable pins for
> writing each byte lane and the hardware can decide to ignore the
> unenabled bytes or not.

>From my experience it is not uncommon for peripheral busses to
don't have the byte strobes. In fact, most (if not all) of the
embedded ones I've worked with are purely 32bit.

Cheers

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2009-05-05  6:05 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-21 11:42 [Qemu-devel] [PATCH] 64 bit I/O support v7 Robert Reif
2009-05-01 12:03 ` Paul Brook
2009-05-01 13:46   ` Robert Reif
2009-05-01 14:14     ` Paul Brook
2009-05-01 14:39       ` Robert Reif
2009-05-01 14:52         ` Paul Brook
2009-05-01 15:19           ` Robert Reif
2009-05-01 15:33             ` Paul Brook
2009-05-01 15:51               ` Blue Swirl
2009-05-01 16:36                 ` Edgar E. Iglesias
2009-05-01 17:29                 ` Robert Reif
2009-05-02  0:02               ` Robert Reif
2009-05-02  0:40                 ` Paul Brook
2009-05-01 23:42             ` Robert Reif
2009-05-01 23:57               ` Paul Brook
2009-05-02 15:23                 ` Blue Swirl
2009-05-02 19:35                   ` Paul Brook
2009-05-05  1:59                   ` Jamie Lokier
2009-05-05  6:05                     ` Edgar E. Iglesias
2009-05-01 14:25   ` Robert Reif
2009-05-01 14:39     ` Paul Brook

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).