qdev: Introduce lost tick policy property

Potentially tick-generating timer devices will gain a common property:
lock_tick_policy. It allows to encode 4 different ways how to deal with
tick events the guest did not process in time:

discard - ignore lost ticks (e.g. if the guest compensates for them
          already)
delay   - replay all lost ticks in a row once the guest accepts them
          again
merge   - if multiple ticks are lost, all of them are merged into one
          which is replayed once the guest accepts it again
slew    - lost ticks are gradually replayed at a higher frequency than
          the original tick

Not all timer device will need to support all modes. However, all need
to accept the configuration via this common property.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index c98219a..028bee7 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -885,6 +885,55 @@
     .set   = set_generic,
 };
 
+
+/* --- lost tick policy --- */
+
+static const struct {
+    const char *name;
+    LostTickPolicy code;
+} lost_tick_policy_table[] = {
+    { .name = "discard", .code = LOST_TICK_DISCARD },
+    { .name = "delay", .code = LOST_TICK_DELAY },
+    { .name = "merge", .code = LOST_TICK_MERGE },
+    { .name = "slew", .code = LOST_TICK_SLEW },
+};
+
+static int parse_lost_tick_policy(DeviceState *dev, Property *prop,
+                                  const char *str)
+{
+    LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(lost_tick_policy_table); i++) {
+        if (!strcasecmp(str, lost_tick_policy_table[i].name)) {
+            *ptr = lost_tick_policy_table[i].code;
+            break;
+        }
+    }
+    if (i == ARRAY_SIZE(lost_tick_policy_table)) {
+        return -EINVAL;
+    }
+    return 0;
+}
+
+static int print_lost_tick_policy(DeviceState *dev, Property *prop, char *dest,
+                                  size_t len)
+{
+    LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
+
+    return snprintf(dest, len, "%s", lost_tick_policy_table[*ptr].name);
+}
+
+PropertyInfo qdev_prop_losttickpolicy = {
+    .name  = "lost_tick_policy",
+    .type  = PROP_TYPE_LOSTTICKPOLICY,
+    .size  = sizeof(LostTickPolicy),
+    .parse = parse_lost_tick_policy,
+    .print = print_lost_tick_policy,
+    .get   = get_generic,
+    .set   = set_generic,
+};
+
 /* --- pci address --- */
 
 /*
@@ -1127,6 +1176,12 @@
     qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR);
 }
 
+void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name,
+                                  LostTickPolicy *value)
+{
+    qdev_prop_set(dev, name, value, PROP_TYPE_LOSTTICKPOLICY);
+}
+
 void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_PTR);