qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v4 0/6] Data Driven device registers + Zynq DEVCFG
@ 2014-04-09  7:15 Peter Crosthwaite
  2014-04-09  7:15 ` [Qemu-devel] [PATCH v4 1/6] bitops: Add ONES macro Peter Crosthwaite
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Peter Crosthwaite @ 2014-04-09  7:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, kraxel, edgar.iglesias

Hi All. This is a new scheme i've come up with handling device registers in a
data driven way. My motivation for this is to factor out a lot of the access
checking that seems to be replicated in every device. See P2 commit message for
further discussion.

P1 is a trivial addition to bitops.h
P2 is the main patch, adds the register definition functionality
P3 adds helpers that glue the register API to the Memory API
P4 is an example new device (the Xilinx Zynq devcfg) that uses this scheme.
P5 adds devcfg to the Zynq machine model

This devcfg device was particularly finnicky with per-bit restrictions which
prompted all this. I'm also looking for a higher-than-usual modelling fidelity
on the register space, with semantics defined for random reserved bits
in-between otherwise consistent fields.

Here's an example of the qemu_log output for the devcfg device. This is produced
by now generic sharable code:

/machine/unattached/device[44]:Addr 0x000008:CFG: write of value 00000508
/machine/unattached/device[44]:Addr 0x000080:MCTRL: write of value 00800010
/machine/unattached/device[44]:Addr 0x000010:INT_MASK: write of value ffffffff
/machine/unattached/device[44]:Addr 00000000:CTRL: write of value 0c00607f

And an example of a rogue guest banging on a bad bit:

/machine/unattached/device[44]:Addr 0x000014:STATUS bits 0x000001 may not be \
								written to 1

Changed from v3:
Rebased (its been a while)
Added reserved bits.
Cleaner separation of decode and access components (Patch 3)
Changed from v2:
Fixed for hw/ re-orginisation (Paolo review)
Simplified and optimized (PMM and Gerd review)
Changed from v1:
Added ONES macro patch
Dropped bogus former patch 1 (PMM review)
Addressed Blue, Gerd and MST comments.
Simplified to be more Memory API compatible.
Added Memory API helpers.
Please see discussion already on list and commit msgs for more detail.


Peter Crosthwaite (6):
  bitops: Add ONES macro
  register: Add Register API
  register: Add Memory API glue
  register: Add support for decoding information
  xilinx_devcfg: Zynq devcfg device model
  xilinx_zynq: added devcfg to machine model

 default-configs/arm-softmmu.mak |   1 +
 hw/arm/xilinx_zynq.c            |   8 +
 hw/core/Makefile.objs           |   1 +
 hw/core/register.c              | 245 +++++++++++++++++++++
 hw/dma/Makefile.objs            |   1 +
 hw/dma/xilinx_devcfg.c          | 462 ++++++++++++++++++++++++++++++++++++++++
 include/hw/register.h           | 164 ++++++++++++++
 include/qemu/bitops.h           |   2 +
 8 files changed, 884 insertions(+)
 create mode 100644 hw/core/register.c
 create mode 100644 hw/dma/xilinx_devcfg.c
 create mode 100644 include/hw/register.h

-- 
1.9.1.1.gbb9f595

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

* [Qemu-devel] [PATCH v4 1/6] bitops: Add ONES macro
  2014-04-09  7:15 [Qemu-devel] [PATCH v4 0/6] Data Driven device registers + Zynq DEVCFG Peter Crosthwaite
@ 2014-04-09  7:15 ` Peter Crosthwaite
  2014-04-09  7:16 ` [Qemu-devel] [PATCH v4 2/6] register: Add Register API Peter Crosthwaite
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Crosthwaite @ 2014-04-09  7:15 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, kraxel, edgar.iglesias

Little macro that just gives you N ones (justified to LSB).

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---

 include/qemu/bitops.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index 340b1e7..b9fd60f 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -403,4 +403,6 @@ static inline uint64_t deposit64(uint64_t value, int start, int length,
     return (value & ~mask) | ((fieldval << start) & mask);
 }
 
+#define ONES(num) ((num) == 64 ? ~0ull : (1ull << (num)) - 1)
+
 #endif
-- 
1.9.1.1.gbb9f595

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

* [Qemu-devel] [PATCH v4 2/6] register: Add Register API
  2014-04-09  7:15 [Qemu-devel] [PATCH v4 0/6] Data Driven device registers + Zynq DEVCFG Peter Crosthwaite
  2014-04-09  7:15 ` [Qemu-devel] [PATCH v4 1/6] bitops: Add ONES macro Peter Crosthwaite
@ 2014-04-09  7:16 ` Peter Crosthwaite
  2014-04-09  7:16 ` [Qemu-devel] [PATCH v4 3/6] register: Add Memory API glue Peter Crosthwaite
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Crosthwaite @ 2014-04-09  7:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, kraxel, edgar.iglesias

This API provides some encapsulation of registers and factors our some
common functionality to common code. Bits of device state (usually MMIO
registers), often have all sorts of access restrictions and semantics
associated with them. This API allow you to define what those
restrictions are on a bit-by-bit basis.

Helper functions are then used to access the register which observe the
semantics defined by the RegisterAccessInfo struct.

Some features:
Bits can be marked as read_only (ro field)
Bits can be marked as write-1-clear (w1c field)
Bits can be marked as reserved (rsvd field)
Reset values can be defined (reset)
Bits can throw guest errors when written certain values (ge0, ge1)
Bits can throw unimp errors when written certain values (ui0, ui1)
Bits can be marked clear on read (cor)
Pre and post action callbacks can be added to read and write ops
Verbose debugging info can be enabled/disabled

Useful for defining device register spaces in a data driven way. Cuts
down on a lot of the verbosity and repetition in the switch-case blocks
in the standard foo_mmio_read/write functions.

Also useful for automated generation of device models from hardware
design sources.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
changed from v2:
Simplified! Removed pre-read, nwx, wo
Removed byte loops (Gerd Review)
Made data pointer optional
Added fast paths for simple registers
Moved into hw/core and include/hw (Paolo Review)
changed from v1:
Rebranded as the "Register API" - I think thats probably what it is.
Near total rewrite of implementation.
De-arrayified reset (this is client/Memory APIs job).
Moved out of bitops into its own file (Blue review)
Added debug, the register pointer, and prefix to a struct (Blue Review)
Made 64-bit to play friendlier with memory API (Blue review)
Made backend storage uint8_t (MST review)
Added read/write callbacks (Blue review)
Added ui0, ui1 (Blue review)
Moved re-purposed width (now byte width defining actual storage size)
Arrayified ge0, ge1 (ui0, ui1 too) and added .reason
Added wo field (not an April fools joke - this has genuine meaning here)
Added we mask to write accessor

 hw/core/Makefile.objs |   1 +
 hw/core/register.c    | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/register.h | 131 +++++++++++++++++++++++++++++++++
 3 files changed, 329 insertions(+)
 create mode 100644 hw/core/register.c
 create mode 100644 include/hw/register.h

diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index 5377d05..7839f46 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -4,6 +4,7 @@ common-obj-y += fw-path-provider.o
 # irq.o needed for qdev GPIO handling:
 common-obj-y += irq.o
 common-obj-y += hotplug.o
+common-obj-y += register.o
 
 common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
 common-obj-$(CONFIG_XILINX_AXI) += stream.o
diff --git a/hw/core/register.c b/hw/core/register.c
new file mode 100644
index 0000000..96712f2
--- /dev/null
+++ b/hw/core/register.c
@@ -0,0 +1,197 @@
+/*
+ * Register Definition API
+ *
+ * Copyright (c) 2013 Xilinx Inc.
+ * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "hw/register.h"
+#include "qemu/log.h"
+
+static inline void register_write_log(RegisterInfo *reg, int dir, uint64_t val,
+                                      int mask, const char *msg,
+                                      const char *reason)
+{
+    qemu_log_mask(mask, "%s:%s bits %#" PRIx64 " %s write of %d%s%s\n",
+                  reg->prefix, reg->access->name, val, msg, dir,
+                  reason ? ": " : "", reason ? reason : "");
+}
+
+static inline void register_write_val(RegisterInfo *reg, uint64_t val)
+{
+    if (!reg->data) {
+        return;
+    }
+    switch (reg->data_size) {
+    case 1:
+        *(uint8_t *)reg->data = val;
+        break;
+    case 2:
+        *(uint16_t *)reg->data = val;
+        break;
+    case 4:
+        *(uint32_t *)reg->data = val;
+        break;
+    case 8:
+        *(uint64_t *)reg->data = val;
+        break;
+    default:
+        abort();
+    }
+}
+
+static inline uint64_t register_read_val(RegisterInfo *reg)
+{
+    switch (reg->data_size) {
+    case 1:
+        return *(uint8_t *)reg->data;
+    case 2:
+        return *(uint16_t *)reg->data;
+    case 4:
+        return *(uint32_t *)reg->data;
+    case 8:
+        return *(uint64_t *)reg->data;
+    default:
+        abort();
+    }
+    return 0; /* unreachable */
+}
+
+void register_write(RegisterInfo *reg, uint64_t val, uint64_t we)
+{
+    uint64_t old_val, new_val, test, no_w_mask;
+    const RegisterAccessInfo *ac;
+    const RegisterAccessError *rae;
+
+    assert(reg);
+
+    ac = reg->access;
+    if (reg->write_lite && !~we) { /* fast path!! */
+        new_val = val;
+        goto register_write_fast;
+    }
+
+    old_val = reg->data ? register_read_val(reg) : ac->reset;
+    if (!ac || !ac->name) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state "
+                      "(written value: %#" PRIx64 ")\n", reg->prefix, val);
+        return;
+    }
+
+    no_w_mask = ac->ro | ac->w1c | ~we;
+
+    if (reg->debug) {
+        qemu_log("%s:%s: write of value %#" PRIx64 "\n", reg->prefix, ac->name,
+                 val);
+    }
+
+    if (qemu_loglevel_mask(LOG_GUEST_ERROR)) {
+        test = (old_val ^ val) & ac->rsvd;
+        if (test) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: change of value in reserved bit"
+                          "fields: %#" PRIx64 ")\n", reg->prefix, test);
+        }
+        for (rae = ac->ge1; rae && rae->mask; rae++) {
+            test = val & rae->mask;
+            if (test) {
+                register_write_log(reg, 1, test, LOG_GUEST_ERROR,
+                                   "invalid", rae->reason);
+            }
+        }
+        for (rae = ac->ge0; rae && rae->mask; rae++) {
+            test = ~val & rae->mask;
+            if (test) {
+                register_write_log(reg, 0, test, LOG_GUEST_ERROR,
+                                   "invalid", rae->reason);
+            }
+        }
+    }
+
+    if (qemu_loglevel_mask(LOG_UNIMP)) {
+        for (rae = ac->ui1; rae && rae->mask; rae++) {
+            test = val & rae->mask;
+            if (test) {
+                register_write_log(reg, 1, test, LOG_GUEST_ERROR,
+                                   "unimplmented", rae->reason);
+            }
+        }
+        for (rae = ac->ui0; rae && rae->mask; rae++) {
+            test = ~val & rae->mask;
+            if (test) {
+                register_write_log(reg, 0, test, LOG_GUEST_ERROR,
+                                   "unimplemented", rae->reason);
+            }
+        }
+    }
+
+    new_val = (val & ~no_w_mask) | (old_val & no_w_mask);
+    new_val &= ~(val & ac->w1c);
+
+    if (ac->pre_write) {
+        new_val = ac->pre_write(reg, new_val);
+    }
+register_write_fast:
+    register_write_val(reg, new_val);
+    if (ac->post_write) {
+        ac->post_write(reg, new_val);
+    }
+}
+
+uint64_t register_read(RegisterInfo *reg)
+{
+    uint64_t ret;
+    const RegisterAccessInfo *ac;
+
+    assert(reg);
+
+    ac = reg->access;
+    if (!ac || !ac->name) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: read from undefined device state\n",
+                      reg->prefix);
+        return 0;
+    }
+
+    ret = reg->data ? register_read_val(reg) : ac->reset;
+
+    if (!reg->read_lite) {
+        register_write_val(reg, ret & ~ac->cor);
+    }
+
+    if (ac->post_read) {
+        ret = ac->post_read(reg, ret);
+    }
+
+    if (!reg->read_lite) {
+        if (reg->debug) {
+            qemu_log("%s:%s: read of value %#" PRIx64 "\n", reg->prefix,
+                     ac->name, ret);
+        }
+    }
+
+    return ret;
+}
+
+void register_reset(RegisterInfo *reg)
+{
+    assert(reg);
+    const RegisterAccessInfo *ac;
+
+    if (!reg->data || !reg->access) {
+        return;
+    }
+
+    ac = reg->access;
+
+    /* if there are no debug msgs and no RMW requirement, mark for fast write */
+    reg->write_lite = reg->debug || ac->ro || ac->w1c || ac->pre_write ||
+            ((ac->ge0 || ac->ge1) && qemu_loglevel_mask(LOG_GUEST_ERROR)) ||
+            ((ac->ui0 || ac->ui1) && qemu_loglevel_mask(LOG_UNIMP))
+             ? false : true;
+    /* no debug and no clear-on-read is a fast read */
+    reg->read_lite = reg->debug || ac->cor ? false : true;
+
+    register_write_val(reg, reg->access->reset);
+}
diff --git a/include/hw/register.h b/include/hw/register.h
new file mode 100644
index 0000000..f747a7f
--- /dev/null
+++ b/include/hw/register.h
@@ -0,0 +1,131 @@
+/*
+ * Register Definition API
+ *
+ * Copyright (c) 2013 Xilinx Inc.
+ * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef REGISTER_H
+#define REGISTER_H
+
+#include "exec/memory.h"
+
+typedef struct RegisterInfo RegisterInfo;
+typedef struct RegisterAccessInfo RegisterAccessInfo;
+
+/**
+ * A register access error message
+ * @mask: Bits in the register the error applies to
+ * @reason: Reason why this access is an error
+ */
+
+typedef struct RegisterAccessError {
+    uint64_t mask;
+    const char *reason;
+} RegisterAccessError;
+
+/**
+ * Access description for a register that is part of guest accessible device
+ * state.
+ *
+ * @name: String name of the register
+ * @ro: whether or not the bit is read-only
+ * @w1c: bits with the common write 1 to clear semantic.
+ * @reset: reset value.
+ * @cor: Bits that are clear on read
+ * @rsvd: Bits that are reserved and should not be changed
+ *
+ * @ge1: Bits that when written 1 indicate a guest error
+ * @ge0: Bits that when written 0 indicate a guest error
+ * @ui1: Bits that when written 1 indicate use of an unimplemented feature
+ * @ui0: Bits that when written 0 indicate use of an unimplemented feature
+ *
+ * @pre_write: Pre write callback. Passed the value that's to be written,
+ * immediately before the actual write. The returned value is what is written,
+ * giving the handler a chance to modify the written value.
+ * @post_write: Post write callback. Passed the written value. Most write side
+ * effects should be implemented here.
+ *
+ * @post_read: Post read callback. Passes the value that is about to be returned
+ * for a read. The return value from this function is what is ultimately read,
+ * allowing this function to modify the value before return to the client.
+ */
+
+struct RegisterAccessInfo {
+    const char *name;
+    uint64_t ro;
+    uint64_t w1c;
+    uint64_t reset;
+    uint64_t cor;
+    uint64_t rsvd;
+
+    const RegisterAccessError *ge0;
+    const RegisterAccessError *ge1;
+    const RegisterAccessError *ui0;
+    const RegisterAccessError *ui1;
+
+    uint64_t (*pre_write)(RegisterInfo *reg, uint64_t val);
+    void (*post_write)(RegisterInfo *reg, uint64_t val);
+
+    uint64_t (*post_read)(RegisterInfo *reg, uint64_t val);
+};
+
+/**
+ * A register that is part of guest accessible state
+ * @data: pointer to the register data. Will be cast
+ * to the relevant uint type depending on data_size.
+ * @data_size: Size of the register in bytes. Must be
+ * 1, 2, 4 or 8
+ * @data_big_endian: Define endianess of data register
+ *
+ * @access: Access desciption of this register
+ *
+ * @debug: Whether or not verbose debug is enabled
+ * @prefix: String prefix for log and debug messages
+ *
+ * @opaque: Opaque data for the register
+ */
+
+struct RegisterInfo {
+    void *data;
+    int data_size;
+
+    const RegisterAccessInfo *access;
+
+    bool debug;
+    const char *prefix;
+
+    void *opaque;
+    /* private */
+    bool read_lite;
+    bool write_lite;
+};
+
+/**
+ * write a value to a register, subject to its restrictions
+ * @reg: register to write to
+ * @val: value to write
+ * @we: write enable mask
+ */
+
+void register_write(RegisterInfo *reg, uint64_t val, uint64_t we);
+
+/**
+ * read a value from a register, subject to its restrictions
+ * @reg: register to read from
+ * returns: value read
+ */
+
+uint64_t register_read(RegisterInfo *reg);
+
+/**
+ * reset a register
+ * @reg: register to reset
+ */
+
+void register_reset(RegisterInfo *reg);
+
+#endif
-- 
1.9.1.1.gbb9f595

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

* [Qemu-devel] [PATCH v4 3/6] register: Add Memory API glue
  2014-04-09  7:15 [Qemu-devel] [PATCH v4 0/6] Data Driven device registers + Zynq DEVCFG Peter Crosthwaite
  2014-04-09  7:15 ` [Qemu-devel] [PATCH v4 1/6] bitops: Add ONES macro Peter Crosthwaite
  2014-04-09  7:16 ` [Qemu-devel] [PATCH v4 2/6] register: Add Register API Peter Crosthwaite
@ 2014-04-09  7:16 ` Peter Crosthwaite
  2014-04-09  7:17 ` [Qemu-devel] [PATCH v4 4/6] register: Add support for decoding information Peter Crosthwaite
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Crosthwaite @ 2014-04-09  7:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, kraxel, edgar.iglesias

Add memory io handlers that glue the register API to the memory API.
Just translation functions at this stage. Although it does allow for
devices to be created without all-in-one mmio r/w handlers.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
changed from v2:
Added fast path to register_write_memory to skip endianness bitbashing

 hw/core/register.c    | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/register.h | 12 ++++++++++++
 2 files changed, 60 insertions(+)

diff --git a/hw/core/register.c b/hw/core/register.c
index 96712f2..29e5f04 100644
--- a/hw/core/register.c
+++ b/hw/core/register.c
@@ -195,3 +195,51 @@ void register_reset(RegisterInfo *reg)
 
     register_write_val(reg, reg->access->reset);
 }
+
+static inline void register_write_memory(void *opaque, hwaddr addr,
+                                         uint64_t value, unsigned size, bool be)
+{
+    RegisterInfo *reg = opaque;
+    uint64_t we = ~0;
+    int shift = 0;
+
+    if (reg->data_size != size) {
+        we = (size == 8) ? ~0ull : (1ull << size * 8) - 1;
+        shift = 8 * (be ? reg->data_size - size - addr : addr);
+    }
+
+    assert(size + addr <= reg->data_size);
+    register_write(reg, value << shift, we << shift);
+}
+
+void register_write_memory_be(void *opaque, hwaddr addr, uint64_t value,
+                              unsigned size)
+{
+    register_write_memory(opaque, addr, value, size, true);
+}
+
+
+void register_write_memory_le(void *opaque, hwaddr addr, uint64_t value,
+                              unsigned size)
+{
+    register_write_memory(opaque, addr, value, size, false);
+}
+
+static inline uint64_t register_read_memory(void *opaque, hwaddr addr,
+                                            unsigned size, bool be)
+{
+    RegisterInfo *reg = opaque;
+    int shift = 8 * (be ? reg->data_size - size - addr : addr);
+
+    return register_read(reg) >> shift;
+}
+
+uint64_t register_read_memory_be(void *opaque, hwaddr addr, unsigned size)
+{
+    return register_read_memory(opaque, addr, size, true);
+}
+
+uint64_t register_read_memory_le(void *opaque, hwaddr addr, unsigned size)
+{
+    return register_read_memory(opaque, addr, size, false);
+}
diff --git a/include/hw/register.h b/include/hw/register.h
index f747a7f..c595ed6 100644
--- a/include/hw/register.h
+++ b/include/hw/register.h
@@ -87,6 +87,8 @@ struct RegisterAccessInfo {
  * @prefix: String prefix for log and debug messages
  *
  * @opaque: Opaque data for the register
+ *
+ * @mem: optional Memory region for the register
  */
 
 struct RegisterInfo {
@@ -102,6 +104,8 @@ struct RegisterInfo {
     /* private */
     bool read_lite;
     bool write_lite;
+
+    MemoryRegion mem;
 };
 
 /**
@@ -128,4 +132,12 @@ uint64_t register_read(RegisterInfo *reg);
 
 void register_reset(RegisterInfo *reg);
 
+void register_write_memory_be(void *opaque, hwaddr addr, uint64_t value,
+                              unsigned size);
+void register_write_memory_le(void *opaque, hwaddr addr, uint64_t value,
+                              unsigned size);
+
+uint64_t register_read_memory_be(void *opaque, hwaddr addr, unsigned size);
+uint64_t register_read_memory_le(void *opaque, hwaddr addr, unsigned size);
+
 #endif
-- 
1.9.1.1.gbb9f595

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

* [Qemu-devel] [PATCH v4 4/6] register: Add support for decoding information
  2014-04-09  7:15 [Qemu-devel] [PATCH v4 0/6] Data Driven device registers + Zynq DEVCFG Peter Crosthwaite
                   ` (2 preceding siblings ...)
  2014-04-09  7:16 ` [Qemu-devel] [PATCH v4 3/6] register: Add Memory API glue Peter Crosthwaite
@ 2014-04-09  7:17 ` Peter Crosthwaite
  2014-04-09  7:18 ` [Qemu-devel] [PATCH v4 5/6] xilinx_devcfg: Zynq devcfg device model Peter Crosthwaite
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Crosthwaite @ 2014-04-09  7:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, kraxel, edgar.iglesias

Allow defining of optional address decoding information in register
definitions. This is useful for clients that want to associate
registers with specific addresses.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---

 include/hw/register.h | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/include/hw/register.h b/include/hw/register.h
index c595ed6..d7f602f 100644
--- a/include/hw/register.h
+++ b/include/hw/register.h
@@ -15,6 +15,7 @@
 
 typedef struct RegisterInfo RegisterInfo;
 typedef struct RegisterAccessInfo RegisterAccessInfo;
+typedef struct RegisterDecodeInfo RegisterDecodeInfo;
 
 /**
  * A register access error message
@@ -54,6 +55,11 @@ typedef struct RegisterAccessError {
  * allowing this function to modify the value before return to the client.
  */
 
+#define REG_DECODE_READ (1 << 0)
+#define REG_DECODE_WRITE (1 << 1)
+#define REG_DECODE_EXECUTE (1 << 2)
+#define REG_DECODE_RW (REG_DECODE_READ | REG_DECODE_WRITE)
+
 struct RegisterAccessInfo {
     const char *name;
     uint64_t ro;
@@ -71,6 +77,14 @@ struct RegisterAccessInfo {
     void (*post_write)(RegisterInfo *reg, uint64_t val);
 
     uint64_t (*post_read)(RegisterInfo *reg, uint64_t val);
+
+    size_t storage;
+    int data_size;
+
+    struct {
+        hwaddr addr;
+        uint8_t flags;
+    } decode;
 };
 
 /**
@@ -108,6 +122,13 @@ struct RegisterInfo {
     MemoryRegion mem;
 };
 
+
+struct RegisterDecodeInfo {
+    RegisterInfo *reg;
+    hwaddr addr;
+    unsigned len;
+};
+
 /**
  * write a value to a register, subject to its restrictions
  * @reg: register to write to
-- 
1.9.1.1.gbb9f595

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

* [Qemu-devel] [PATCH v4 5/6] xilinx_devcfg: Zynq devcfg device model
  2014-04-09  7:15 [Qemu-devel] [PATCH v4 0/6] Data Driven device registers + Zynq DEVCFG Peter Crosthwaite
                   ` (3 preceding siblings ...)
  2014-04-09  7:17 ` [Qemu-devel] [PATCH v4 4/6] register: Add support for decoding information Peter Crosthwaite
@ 2014-04-09  7:18 ` Peter Crosthwaite
  2014-04-09  7:18 ` [Qemu-devel] [PATCH v4 6/6] xilinx_zynq: added devcfg to machine model Peter Crosthwaite
       [not found] ` <CAEgOgz44H0wneRDxUrsvtLNtVD3iNAfL28VmAhYURGG95kh93g@mail.gmail.com>
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Crosthwaite @ 2014-04-09  7:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, kraxel, edgar.iglesias

Minimal device model for devcfg module of Zynq. DMA capabilities and
interrupt generation supported.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
Changed since v3:
Stylistic updates.
Changed over to new decoding scheme.
Use .rsvd in definitions as appropriate.
Author reset (s/petalogix/xilinx).
Changed since v2:
Some QOM styling updates.
Re-implemented nw0 for lock register as pre_write
Changed since v1:
Rebased against new version of Register API.
Use action callbacks for side effects rather than switch.
Documented reasons for ge0, ge1 (Verbatim from TRM)
Added ui1 definitions for unimplemented major features
Removed dead lock code

 default-configs/arm-softmmu.mak |   1 +
 hw/dma/Makefile.objs            |   1 +
 hw/dma/xilinx_devcfg.c          | 462 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 464 insertions(+)
 create mode 100644 hw/dma/xilinx_devcfg.c

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index f3513fa..e0e518c 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -62,6 +62,7 @@ CONFIG_PXA2XX=y
 CONFIG_BITBANG_I2C=y
 CONFIG_FRAMEBUFFER=y
 CONFIG_XILINX_SPIPS=y
+CONFIG_ZYNQ_DEVCFG=y
 
 CONFIG_ARM11SCU=y
 CONFIG_A9SCU=y
diff --git a/hw/dma/Makefile.objs b/hw/dma/Makefile.objs
index 0e65ed0..96025cf 100644
--- a/hw/dma/Makefile.objs
+++ b/hw/dma/Makefile.objs
@@ -5,6 +5,7 @@ common-obj-$(CONFIG_PL330) += pl330.o
 common-obj-$(CONFIG_I82374) += i82374.o
 common-obj-$(CONFIG_I8257) += i8257.o
 common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
+common-obj-$(CONFIG_ZYNQ_DEVCFG) += xilinx_devcfg.o
 common-obj-$(CONFIG_ETRAXFS) += etraxfs_dma.o
 common-obj-$(CONFIG_STP2000) += sparc32_dma.o
 common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o
diff --git a/hw/dma/xilinx_devcfg.c b/hw/dma/xilinx_devcfg.c
new file mode 100644
index 0000000..c85f808
--- /dev/null
+++ b/hw/dma/xilinx_devcfg.c
@@ -0,0 +1,462 @@
+/*
+ * QEMU model of the Xilinx Devcfg Interface
+ *
+ * (C) 2011 PetaLogix Pty Ltd
+ * (C) 2014 Xilinx Inc.
+ * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysemu/sysemu.h"
+#include "sysemu/dma.h"
+#include "hw/sysbus.h"
+#include "hw/ptimer.h"
+#include "qemu/bitops.h"
+#include "hw/register.h"
+#include "qemu/bitops.h"
+
+#define TYPE_XILINX_DEVCFG "xlnx.ps7-dev-cfg"
+
+#define XILINX_DEVCFG(obj) \
+    OBJECT_CHECK(XilinxDevcfg, (obj), TYPE_XILINX_DEVCFG)
+
+/* FIXME: get rid of hardcoded nastiness */
+
+#define FREQ_HZ 900000000
+
+#define BTT_MAX 0x400 /* bytes to transfer per delay inteval */
+#define CYCLES_BTT_MAX 10000 /*approximate 10k cycles per delay interval */
+
+#ifndef XILINX_DEVCFG_ERR_DEBUG
+#define XILINX_DEVCFG_ERR_DEBUG 0
+#endif
+#define DB_PRINT(...) do { \
+    if (XILINX_DEVCFG_ERR_DEBUG) { \
+        fprintf(stderr,  ": %s: ", __func__); \
+        fprintf(stderr, ## __VA_ARGS__); \
+    } \
+} while (0);
+
+#define R_CTRL            (0x00/4)
+    #define FORCE_RST            (1 << 31) /* Not supported, writes ignored */
+    #define PCAP_PR              (1 << 27) /* Forced to 0 on bad unlock */
+    #define PCAP_MODE            (1 << 26)
+    #define MULTIBOOT_EN         (1 << 24)
+    #define USER_MODE            (1 << 15)
+    #define PCFG_AES_FUSE        (1 << 12) /* locked by AES_FUSE_LOCK */
+    #define PCFG_AES_EN_SHIFT    9 /* locked by AES_EN_LOCK */
+    #define PCFG_AES_EN_LEN      3 /* locked by AES_EN_LOCK */
+    #define PCFG_AES_EN_MASK     (((1 << PCFG_AES_EN_LEN) - 1) \
+                                    << PCFG_AES_EN_SHIFT)
+    #define SEU_EN               (1 << 8) /* locked by SEU_LOCK */
+    #define SEC_EN               (1 << 7) /* locked by SEC_LOCK */
+    #define SPNIDEN              (1 << 6) /* locked by DBG_LOCK */
+    #define SPIDEN               (1 << 5) /* locked by DBG_LOCK */
+    #define NIDEN                (1 << 4) /* locked by DBG_LOCK */
+    #define DBGEN                (1 << 3) /* locked by DBG_LOCK */
+    #define DAP_EN               (7 << 0) /* locked by DBG_LOCK */
+
+#define R_LOCK          (0x04/4)
+    #define AES_FUSE_LOCK        4
+    #define AES_EN_LOCK          3
+    #define SEU_LOCK             2
+    #define SEC_LOCK             1
+    #define DBG_LOCK             0
+
+/* mapping bits in R_LOCK to what they lock in R_CTRL */
+static const uint32_t lock_ctrl_map[] = {
+    [AES_FUSE_LOCK] = PCFG_AES_FUSE,
+    [AES_EN_LOCK] = PCFG_AES_EN_MASK,
+    [SEU_LOCK] = SEU_LOCK,
+    [SEC_LOCK] = SEC_LOCK,
+    [DBG_LOCK] =  SPNIDEN | SPIDEN | NIDEN | DBGEN | DAP_EN,
+};
+
+#define R_CFG           (0x08/4)
+    #define RFIFO_TH_SHIFT       10
+    #define RFIFO_TH_LEN         2
+    #define WFIFO_TH_SHIFT       8
+    #define WFIFO_TH_LEN         2
+    #define DISABLE_SRC_INC      (1 << 5)
+    #define DISABLE_DST_INC      (1 << 4)
+#define R_CFG_RO 0xFFFFF800
+#define R_CFG_RESET 0x50B
+
+#define R_INT_STS       (0x0C/4)
+    #define PSS_GTS_USR_B_INT    (1 << 31)
+    #define PSS_FST_CFG_B_INT    (1 << 30)
+    #define PSS_CFG_RESET_B_INT  (1 << 27)
+    #define RX_FIFO_OV_INT       (1 << 18)
+    #define WR_FIFO_LVL_INT      (1 << 17)
+    #define RD_FIFO_LVL_INT      (1 << 16)
+    #define DMA_CMD_ERR_INT      (1 << 15)
+    #define DMA_Q_OV_INT         (1 << 14)
+    #define DMA_DONE_INT         (1 << 13)
+    #define DMA_P_DONE_INT       (1 << 12)
+    #define P2D_LEN_ERR_INT      (1 << 11)
+    #define PCFG_DONE_INT        (1 << 2)
+    #define R_INT_STS_RSVD       ((0x7 << 24) | (0x1 << 19) | (0xF < 7))
+
+#define R_INT_MASK      (0x10/4)
+
+#define R_STATUS        (0x14/4)
+    #define DMA_CMD_Q_F         (1 << 31)
+    #define DMA_CMD_Q_E         (1 << 30)
+    #define DMA_DONE_CNT_SHIFT  28
+    #define DMA_DONE_CNT_LEN    2
+    #define RX_FIFO_LVL_SHIFT   20
+    #define RX_FIFO_LVL_LEN     5
+    #define TX_FIFO_LVL_SHIFT   12
+    #define TX_FIFO_LVL_LEN     7
+    #define TX_FIFO_LVL         (0x7f << 12)
+    #define PSS_GTS_USR_B       (1 << 11)
+    #define PSS_FST_CFG_B       (1 << 10)
+    #define PSS_CFG_RESET_B     (1 << 5)
+
+#define R_DMA_SRC_ADDR  (0x18/4)
+#define R_DMA_DST_ADDR  (0x1C/4)
+#define R_DMA_SRC_LEN   (0x20/4)
+#define R_DMA_DST_LEN   (0x24/4)
+#define R_ROM_SHADOW    (0x28/4)
+#define R_SW_ID         (0x30/4)
+#define R_UNLOCK        (0x34/4)
+
+#define R_UNLOCK_MAGIC 0x757BDF0D
+
+#define R_MCTRL         (0x80/4)
+    #define PS_VERSION_SHIFT    28
+    #define PS_VERSION_MASK     (0xf << PS_VERSION_SHIFT)
+    #define PCFG_POR_B          (1 << 8)
+    #define INT_PCAP_LPBK       (1 << 4)
+
+#define R_MAX (0x118/4+1)
+
+#define RX_FIFO_LEN 32
+#define TX_FIFO_LEN 128
+
+#define DMA_COMMAND_FIFO_LEN 10
+
+typedef struct XilinxDevcfgDMACommand {
+    uint32_t src_addr;
+    uint32_t dest_addr;
+    uint32_t src_len;
+    uint32_t dest_len;
+} XilinxDevcfgDMACommand;
+
+static const VMStateDescription vmstate_xilinx_devcfg_dma_command = {
+    .name = "xilinx_devcfg_dma_command",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(src_addr, XilinxDevcfgDMACommand),
+        VMSTATE_UINT32(dest_addr, XilinxDevcfgDMACommand),
+        VMSTATE_UINT32(src_len, XilinxDevcfgDMACommand),
+        VMSTATE_UINT32(dest_len, XilinxDevcfgDMACommand),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct XilinxDevcfg {
+    SysBusDevice parent_obj;
+
+    MemoryRegion iomem;
+    qemu_irq irq;
+
+    QEMUBH *timer_bh;
+    ptimer_state *timer;
+
+    XilinxDevcfgDMACommand dma_command_fifo[DMA_COMMAND_FIFO_LEN];
+    uint8_t dma_command_fifo_num;
+
+    uint32_t regs[R_MAX];
+    RegisterInfo regs_info[R_MAX];
+} XilinxDevcfg;
+
+static const VMStateDescription vmstate_xilinx_devcfg = {
+    .name = "xilinx_devcfg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PTIMER(timer, XilinxDevcfg),
+        VMSTATE_STRUCT_ARRAY(dma_command_fifo, XilinxDevcfg,
+                             DMA_COMMAND_FIFO_LEN, 0,
+                             vmstate_xilinx_devcfg_dma_command,
+                             XilinxDevcfgDMACommand),
+        VMSTATE_UINT8(dma_command_fifo_num, XilinxDevcfg),
+        VMSTATE_UINT32_ARRAY(regs, XilinxDevcfg, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void xilinx_devcfg_update_ixr(XilinxDevcfg *s)
+{
+    qemu_set_irq(s->irq, !!(~s->regs[R_INT_MASK] & s->regs[R_INT_STS]));
+}
+
+static void xilinx_devcfg_reset(DeviceState *dev)
+{
+    XilinxDevcfg *s = XILINX_DEVCFG(dev);
+    int i;
+
+    for (i = 0; i < R_MAX; ++i) {
+        register_reset(&s->regs_info[i]);
+    }
+}
+
+static void xilinx_devcfg_dma_go(void *opaque)
+{
+    XilinxDevcfg *s = XILINX_DEVCFG(opaque);
+    uint8_t buf[BTT_MAX];
+    XilinxDevcfgDMACommand *dmah = s->dma_command_fifo;
+    uint32_t btt = BTT_MAX;
+
+    btt = MIN(btt, dmah->src_len);
+    if (s->regs[R_MCTRL] & INT_PCAP_LPBK) {
+        btt = MIN(btt, dmah->dest_len);
+    }
+    DB_PRINT("reading %x bytes from %x\n", btt, dmah->src_addr);
+    dma_memory_read(&address_space_memory, dmah->src_addr, buf, btt);
+    dmah->src_len -= btt;
+    dmah->src_addr += btt;
+    if (s->regs[R_MCTRL] & INT_PCAP_LPBK) {
+        DB_PRINT("writing %x bytes from %x\n", btt, dmah->dest_addr);
+        dma_memory_write(&address_space_memory, dmah->dest_addr, buf, btt);
+        dmah->dest_len -= btt;
+        dmah->dest_addr += btt;
+    }
+    if (!dmah->src_len && !dmah->dest_len) {
+        DB_PRINT("dma operation finished\n");
+        s->regs[R_INT_STS] |= DMA_DONE_INT | DMA_P_DONE_INT;
+        s->dma_command_fifo_num = s->dma_command_fifo_num - 1;
+        memcpy(s->dma_command_fifo, &s->dma_command_fifo[1],
+               sizeof(*s->dma_command_fifo) * DMA_COMMAND_FIFO_LEN - 1);
+    }
+    xilinx_devcfg_update_ixr(s);
+    if (s->dma_command_fifo_num) { /* there is still work to do */
+        DB_PRINT("dma work remains, setting up callback ptimer\n");
+        ptimer_set_freq(s->timer, FREQ_HZ);
+        ptimer_set_count(s->timer, CYCLES_BTT_MAX);
+        ptimer_run(s->timer, 1);
+    }
+}
+
+static void r_ixr_post_write(RegisterInfo *reg, uint64_t val)
+{
+    XilinxDevcfg *s = XILINX_DEVCFG(reg->opaque);
+
+    xilinx_devcfg_update_ixr(s);
+}
+
+static uint64_t r_ctrl_pre_write(RegisterInfo *reg, uint64_t val)
+{
+    XilinxDevcfg *s = XILINX_DEVCFG(reg->opaque);
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(lock_ctrl_map); ++i) {
+        if (s->regs[R_LOCK] & 1 << i) {
+            val &= ~lock_ctrl_map[i];
+            val |= lock_ctrl_map[i] & s->regs[R_CTRL];
+        }
+    }
+    return val;
+}
+
+static void r_ctrl_post_write(RegisterInfo *reg, uint64_t val)
+{
+    uint32_t aes_en = extract32(val, PCFG_AES_EN_SHIFT, PCFG_AES_EN_LEN);
+
+    if (aes_en != 0 && aes_en != 7) {
+        qemu_log_mask(LOG_UNIMP, "%s: warning, aes-en bits inconsistent,"
+                      "unimplemeneted security reset should happen!\n",
+                      reg->prefix);
+    }
+}
+
+static void r_unlock_post_write(RegisterInfo *reg, uint64_t val)
+{
+    XilinxDevcfg *s = XILINX_DEVCFG(reg->opaque);
+
+    if (val == R_UNLOCK_MAGIC) {
+        DB_PRINT("successful unlock\n");
+    } else { /* bad unlock attempt */
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: failed unlock\n", reg->prefix);
+        s->regs[R_CTRL] &= ~PCAP_PR;
+        s->regs[R_CTRL] &= ~PCFG_AES_EN_MASK;
+    }
+}
+
+static uint64_t r_lock_pre_write(RegisterInfo *reg, uint64_t val)
+{
+    XilinxDevcfg *s = XILINX_DEVCFG(reg->opaque);
+
+    /* once bits are locked they stay locked */
+    return s->regs[R_LOCK] | val;
+}
+
+static void r_dma_dst_len_post_write(RegisterInfo *reg, uint64_t val)
+{
+    XilinxDevcfg *s = XILINX_DEVCFG(reg->opaque);
+
+    s->dma_command_fifo[s->dma_command_fifo_num] = (XilinxDevcfgDMACommand) {
+            .src_addr = s->regs[R_DMA_SRC_ADDR] & ~0x3UL,
+            .dest_addr = s->regs[R_DMA_DST_ADDR] & ~0x3UL,
+            .src_len = s->regs[R_DMA_SRC_LEN] << 2,
+            .dest_len = s->regs[R_DMA_DST_LEN] << 2,
+    };
+    s->dma_command_fifo_num++;
+    DB_PRINT("dma transfer started; %d total transfers pending\n",
+             s->dma_command_fifo_num);
+    xilinx_devcfg_dma_go(s);
+}
+
+static const RegisterAccessInfo xilinx_devcfg_regs_info[] = {
+    {   .name = "CTRL",                 .decode.addr = R_CTRL * 4,
+        .reset = PCAP_PR | PCAP_MODE | 0x3 << 13,
+        .ro = 0x107f6000,
+        .rsvd = 0x1 << 15 | 0x3 << 13,
+        .ui1 = (RegisterAccessError[]) {
+            { .mask = FORCE_RST, .reason = "PS reset not implemented" },
+            { .mask = PCAP_MODE, .reason = "FPGA Fabric doesnt exist" },
+            { .mask = PCFG_AES_EN_MASK, .reason = "AES not implmented" },
+            {},
+        },
+        .pre_write = r_ctrl_pre_write,
+        .post_write = r_ctrl_post_write,
+    },
+    {   .name = "LOCK",                 .decode.addr = R_LOCK * 4,
+        .ro = ~ONES(5),
+        .pre_write = r_lock_pre_write,
+    },
+    {   .name = "CFG",                  .decode.addr = R_CFG * 4,
+        .reset = 1 << RFIFO_TH_SHIFT | 1 << WFIFO_TH_SHIFT | 0x8,
+        .rsvd = 0xf,
+        .ro = 0x00f | ~ONES(12),
+    },
+    {   .name = "INT_STS",              .decode.addr = R_INT_STS * 4,
+        .w1c = ~R_INT_STS_RSVD,
+        .reset = PSS_GTS_USR_B_INT | PSS_CFG_RESET_B_INT | WR_FIFO_LVL_INT,
+        .ro = R_INT_STS_RSVD,
+        .post_write = r_ixr_post_write,
+    },
+    {    .name = "INT_MASK",            .decode.addr = R_INT_MASK * 4,
+        .reset = ~0,
+        .ro = R_INT_STS_RSVD,
+        .post_write = r_ixr_post_write,
+    },
+    {   .name = "STATUS",               .decode.addr = R_STATUS * 4,
+        .reset = DMA_CMD_Q_E | PSS_GTS_USR_B | PSS_CFG_RESET_B,
+        .ro = ~0,
+    },
+    {   .name = "DMA_SRC_ADDR",         .decode.addr = R_DMA_SRC_ADDR * 4, },
+    {   .name = "DMA_DST_ADDR",         .decode.addr = R_DMA_DST_ADDR * 4, },
+    {   .name = "DMA_SRC_LEN",          .decode.addr = R_DMA_SRC_LEN * 4,
+        .ro = ~ONES(27) },
+    {   .name = "DMA_DST_LEN",          .decode.addr = R_DMA_DST_LEN * 4,
+        .ro = ~ONES(27),
+        .post_write = r_dma_dst_len_post_write,
+    },
+    {   .name = "ROM_SHADOW",           .decode.addr = R_ROM_SHADOW * 4,
+        .rsvd = ~0ull,
+    },
+    {   .name = "SW_ID",                .decode.addr = R_SW_ID * 4, },
+    {   .name = "UNLOCK",               .decode.addr = R_UNLOCK * 4,
+        .post_write = r_unlock_post_write,
+    },
+    {   .name = "MCTRL",                .decode.addr = R_MCTRL * 4,
+       /* Silicon 3.0 for version field, and the mysterious reserved bit 23 */
+       .reset = 0x2 << PS_VERSION_SHIFT | 1 << 23,
+       /* some reserved bits are rw while others are ro */
+       .ro = ~INT_PCAP_LPBK,
+       .rsvd = 0x00f00303,
+    },
+};
+
+static const MemoryRegionOps devcfg_reg_ops = {
+    .read = register_read_memory_le,
+    .write = register_write_memory_le,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static void xilinx_devcfg_realize(DeviceState *dev, Error **errp)
+{
+    XilinxDevcfg *s = XILINX_DEVCFG(dev);
+    const char *prefix = object_get_canonical_path(OBJECT(dev));
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(xilinx_devcfg_regs_info); ++i) {
+        RegisterInfo *r = &s->regs_info[i];
+
+        *r = (RegisterInfo) {
+            .data = &s->regs[i],
+            .data_size = sizeof(uint32_t),
+            .access = &xilinx_devcfg_regs_info[i],
+            .debug = XILINX_DEVCFG_ERR_DEBUG,
+            .prefix = prefix,
+            .opaque = s,
+        };
+        memory_region_init_io(&r->mem, OBJECT(dev), &devcfg_reg_ops, r,
+                              r->access->name, 4);
+        memory_region_add_subregion(&s->iomem, r->access->decode.addr, &r->mem);
+    }
+}
+
+static void xilinx_devcfg_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    XilinxDevcfg *s = XILINX_DEVCFG(obj);
+
+    s->timer_bh = qemu_bh_new(xilinx_devcfg_dma_go, s);
+    s->timer = ptimer_init(s->timer_bh);
+
+    sysbus_init_irq(sbd, &s->irq);
+
+    memory_region_init(&s->iomem, obj, "devcfg", R_MAX*4);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void xilinx_devcfg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = xilinx_devcfg_reset;
+    dc->vmsd = &vmstate_xilinx_devcfg;
+    dc->realize = xilinx_devcfg_realize;
+}
+
+static const TypeInfo xilinx_devcfg_info = {
+    .name           = TYPE_XILINX_DEVCFG,
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(XilinxDevcfg),
+    .instance_init  = xilinx_devcfg_init,
+    .class_init     = xilinx_devcfg_class_init,
+};
+
+static void xilinx_devcfg_register_types(void)
+{
+    type_register_static(&xilinx_devcfg_info);
+}
+
+type_init(xilinx_devcfg_register_types)
-- 
1.9.1.1.gbb9f595

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

* [Qemu-devel] [PATCH v4 6/6] xilinx_zynq: added devcfg to machine model
  2014-04-09  7:15 [Qemu-devel] [PATCH v4 0/6] Data Driven device registers + Zynq DEVCFG Peter Crosthwaite
                   ` (4 preceding siblings ...)
  2014-04-09  7:18 ` [Qemu-devel] [PATCH v4 5/6] xilinx_devcfg: Zynq devcfg device model Peter Crosthwaite
@ 2014-04-09  7:18 ` Peter Crosthwaite
       [not found] ` <CAEgOgz44H0wneRDxUrsvtLNtVD3iNAfL28VmAhYURGG95kh93g@mail.gmail.com>
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Crosthwaite @ 2014-04-09  7:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, kraxel, edgar.iglesias

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
Changed since v3:
Author reset.
Changed since v1:
Added manual parenting of devcfg node (evil but needed for early access
to canonical path by devcfgs realize fn).

 hw/arm/xilinx_zynq.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 9ee21e7..e3505fa 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -231,6 +231,14 @@ static void zynq_init(QEMUMachineInitArgs *args)
         sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]);
     }
 
+    dev = qdev_create(NULL, "xlnx.ps7-dev-cfg");
+    object_property_add_child(qdev_get_machine(), "xilinx-devcfg", OBJECT(dev),
+                              NULL);
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(busdev, 0, pic[40-IRQ_OFFSET]);
+    sysbus_mmio_map(busdev, 0, 0xF8007000);
+
     zynq_binfo.ram_size = ram_size;
     zynq_binfo.kernel_filename = kernel_filename;
     zynq_binfo.kernel_cmdline = kernel_cmdline;
-- 
1.9.1.1.gbb9f595

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

* Re: [Qemu-devel] [PATCH v4 0/6] Data Driven device registers + Zynq DEVCFG
       [not found] ` <CAEgOgz44H0wneRDxUrsvtLNtVD3iNAfL28VmAhYURGG95kh93g@mail.gmail.com>
@ 2014-05-05 23:42   ` Peter Crosthwaite
  0 siblings, 0 replies; 8+ messages in thread
From: Peter Crosthwaite @ 2014-05-05 23:42 UTC (permalink / raw)
  To: qemu-devel@nongnu.org Developers
  Cc: Peter Maydell, Gerd Hoffmann, Edgar E. Iglesias

Ping^2!

On Thu, Apr 24, 2014 at 9:09 AM, Peter Crosthwaite
<peter.crosthwaite@xilinx.com> wrote:
> Ping!
>
> On Wed, Apr 9, 2014 at 5:15 PM, Peter Crosthwaite
> <peter.crosthwaite@xilinx.com> wrote:
>> Hi All. This is a new scheme i've come up with handling device registers in a
>> data driven way. My motivation for this is to factor out a lot of the access
>> checking that seems to be replicated in every device. See P2 commit message for
>> further discussion.
>>
>> P1 is a trivial addition to bitops.h
>> P2 is the main patch, adds the register definition functionality
>> P3 adds helpers that glue the register API to the Memory API
>> P4 is an example new device (the Xilinx Zynq devcfg) that uses this scheme.
>> P5 adds devcfg to the Zynq machine model
>>
>> This devcfg device was particularly finnicky with per-bit restrictions which
>> prompted all this. I'm also looking for a higher-than-usual modelling fidelity
>> on the register space, with semantics defined for random reserved bits
>> in-between otherwise consistent fields.
>>
>> Here's an example of the qemu_log output for the devcfg device. This is produced
>> by now generic sharable code:
>>
>> /machine/unattached/device[44]:Addr 0x000008:CFG: write of value 00000508
>> /machine/unattached/device[44]:Addr 0x000080:MCTRL: write of value 00800010
>> /machine/unattached/device[44]:Addr 0x000010:INT_MASK: write of value ffffffff
>> /machine/unattached/device[44]:Addr 00000000:CTRL: write of value 0c00607f
>>
>> And an example of a rogue guest banging on a bad bit:
>>
>> /machine/unattached/device[44]:Addr 0x000014:STATUS bits 0x000001 may not be \
>>                                                                 written to 1
>>
>> Changed from v3:
>> Rebased (its been a while)
>> Added reserved bits.
>> Cleaner separation of decode and access components (Patch 3)
>> Changed from v2:
>> Fixed for hw/ re-orginisation (Paolo review)
>> Simplified and optimized (PMM and Gerd review)
>> Changed from v1:
>> Added ONES macro patch
>> Dropped bogus former patch 1 (PMM review)
>> Addressed Blue, Gerd and MST comments.
>> Simplified to be more Memory API compatible.
>> Added Memory API helpers.
>> Please see discussion already on list and commit msgs for more detail.
>>
>>
>> Peter Crosthwaite (6):
>>   bitops: Add ONES macro
>>   register: Add Register API
>>   register: Add Memory API glue
>>   register: Add support for decoding information
>>   xilinx_devcfg: Zynq devcfg device model
>>   xilinx_zynq: added devcfg to machine model
>>
>>  default-configs/arm-softmmu.mak |   1 +
>>  hw/arm/xilinx_zynq.c            |   8 +
>>  hw/core/Makefile.objs           |   1 +
>>  hw/core/register.c              | 245 +++++++++++++++++++++
>>  hw/dma/Makefile.objs            |   1 +
>>  hw/dma/xilinx_devcfg.c          | 462 ++++++++++++++++++++++++++++++++++++++++
>>  include/hw/register.h           | 164 ++++++++++++++
>>  include/qemu/bitops.h           |   2 +
>>  8 files changed, 884 insertions(+)
>>  create mode 100644 hw/core/register.c
>>  create mode 100644 hw/dma/xilinx_devcfg.c
>>  create mode 100644 include/hw/register.h
>>
>> --
>> 1.9.1.1.gbb9f595
>>

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

end of thread, other threads:[~2014-05-05 23:42 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-09  7:15 [Qemu-devel] [PATCH v4 0/6] Data Driven device registers + Zynq DEVCFG Peter Crosthwaite
2014-04-09  7:15 ` [Qemu-devel] [PATCH v4 1/6] bitops: Add ONES macro Peter Crosthwaite
2014-04-09  7:16 ` [Qemu-devel] [PATCH v4 2/6] register: Add Register API Peter Crosthwaite
2014-04-09  7:16 ` [Qemu-devel] [PATCH v4 3/6] register: Add Memory API glue Peter Crosthwaite
2014-04-09  7:17 ` [Qemu-devel] [PATCH v4 4/6] register: Add support for decoding information Peter Crosthwaite
2014-04-09  7:18 ` [Qemu-devel] [PATCH v4 5/6] xilinx_devcfg: Zynq devcfg device model Peter Crosthwaite
2014-04-09  7:18 ` [Qemu-devel] [PATCH v4 6/6] xilinx_zynq: added devcfg to machine model Peter Crosthwaite
     [not found] ` <CAEgOgz44H0wneRDxUrsvtLNtVD3iNAfL28VmAhYURGG95kh93g@mail.gmail.com>
2014-05-05 23:42   ` [Qemu-devel] [PATCH v4 0/6] Data Driven device registers + Zynq DEVCFG Peter Crosthwaite

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).