</choice>
</attribute>
<optional>
- <attribute name="wallclock">
+ <attribute name="track">
<choice>
- <value>host</value>
+ <value>boot</value>
<value>guest</value>
+ <value>wall</value>
</choice>
</attribute>
</optional>
</choice>
</attribute>
</optional>
+ <optional>
+ <ref name="catchup"/>
+ </optional>
<optional>
<attribute name="frequency">
<ref name="unsignedInt"/>
<value>native</value>
<value>emulate</value>
<value>paravirt</value>
+ <value>smpsafe</value>
</choice>
</attribute>
</optional>
<empty/>
</element>
</define>
+ <define name="catchup">
+ <element name="catchup">
+ <optional>
+ <attribute name="threshold">
+ <ref name="unsignedInt"/>
+ </attribute>
+ <attribute name="slew">
+ <ref name="unsignedInt"/>
+ </attribute>
+ <attribute name="limit">
+ <ref name="unsignedInt"/>
+ </attribute>
+ </optional>
+ </element>
+ </define>
<!--
A bootloader may be used to extract the OS information instead of
defining the OS parameter in the instance. It points just to the
"hpet",
"tsc");
-VIR_ENUM_IMPL(virDomainTimerWallclock, VIR_DOMAIN_TIMER_WALLCLOCK_LAST,
- "host",
- "guest");
+VIR_ENUM_IMPL(virDomainTimerTrack, VIR_DOMAIN_TIMER_TRACK_LAST,
+ "boot",
+ "guest",
+ "wall");
VIR_ENUM_IMPL(virDomainTimerTickpolicy, VIR_DOMAIN_TIMER_TICKPOLICY_LAST,
"delay",
"auto",
"native",
"emulate",
- "paravirt");
+ "paravirt",
+ "smpsafe");
#define virDomainReportError(code, ...) \
virReportErrorHelper(NULL, VIR_FROM_DOMAIN, code, __FILE__, \
char *name = NULL;
char *present = NULL;
char *tickpolicy = NULL;
- char *wallclock = NULL;
+ char *track = NULL;
char *mode = NULL;
virDomainTimerDefPtr def;
}
}
- def->wallclock = -1;
- wallclock = virXMLPropString(node, "wallclock");
- if (wallclock != NULL) {
- if ((def->wallclock = virDomainTimerWallclockTypeFromString(wallclock)) < 0) {
+ def->track = -1;
+ track = virXMLPropString(node, "track");
+ if (track != NULL) {
+ if ((def->track = virDomainTimerTrackTypeFromString(track)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
- _("unknown timer wallclock '%s'"), wallclock);
+ _("unknown timer track '%s'"), track);
goto error;
}
}
int ret = virXPathULong("string(./frequency)", ctxt, &def->frequency);
if (ret == -1) {
def->frequency = 0;
- } else if (ret <= 0) {
+ } else if (ret < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("invalid timer frequency"));
goto error;
}
}
+ xmlNodePtr catchup = virXPathNode("./catchup", ctxt);
+ if (catchup != NULL) {
+ ret = virXPathULong("string(./catchup/@threshold)", ctxt,
+ &def->catchup.threshold);
+ if (ret == -1) {
+ def->catchup.threshold = 0;
+ } else if (ret < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("invalid catchup threshold"));
+ goto error;
+ }
+
+ ret = virXPathULong("string(./catchup/@slew)", ctxt, &def->catchup.slew);
+ if (ret == -1) {
+ def->catchup.slew = 0;
+ } else if (ret < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("invalid catchup slew"));
+ goto error;
+ }
+
+ ret = virXPathULong("string(./catchup/@limit)", ctxt, &def->catchup.limit);
+ if (ret == -1) {
+ def->catchup.limit = 0;
+ } else if (ret < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("invalid catchup limit"));
+ goto error;
+ }
+ }
+
cleanup:
VIR_FREE(name);
VIR_FREE(present);
VIR_FREE(tickpolicy);
- VIR_FREE(wallclock);
+ VIR_FREE(track);
VIR_FREE(mode);
ctxt->node = oldnode;
if ((def->name == VIR_DOMAIN_TIMER_NAME_PLATFORM)
|| (def->name == VIR_DOMAIN_TIMER_NAME_RTC)) {
- if (def->wallclock != -1) {
- const char *wallclock
- = virDomainTimerWallclockTypeToString(def->wallclock);
- if (!wallclock) {
+ if (def->track != -1) {
+ const char *track
+ = virDomainTimerTrackTypeToString(def->track);
+ if (!track) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
- _("unexpected timer wallclock %d"),
- def->wallclock);
+ _("unexpected timer track %d"),
+ def->track);
return -1;
}
- virBufferVSprintf(buf, " wallclock='%s'", wallclock);
+ virBufferVSprintf(buf, " track='%s'", track);
}
}
}
}
- virBufferAddLit(buf, "/>\n");
+ if ((def->catchup.threshold == 0)
+ && (def->catchup.slew == 0)
+ && (def->catchup.limit == 0)) {
+ virBufferAddLit(buf, "/>\n");
+ } else {
+ virBufferAddLit(buf, ">\n <catchup ");
+ if (def->catchup.threshold > 0) {
+ virBufferVSprintf(buf, " threshold='%lu'", def->catchup.threshold);
+ }
+ if (def->catchup.slew > 0) {
+ virBufferVSprintf(buf, " slew='%lu'", def->catchup.slew);
+ }
+ if (def->catchup.limit > 0) {
+ virBufferVSprintf(buf, " limit='%lu'", def->catchup.limit);
+ }
+ virBufferAddLit(buf, "/>\n </timer>\n");
+ }
return 0;
}
VIR_DOMAIN_TIMER_NAME_LAST,
};
-enum virDomainTimerWallclockType {
- VIR_DOMAIN_TIMER_WALLCLOCK_HOST = 0,
- VIR_DOMAIN_TIMER_WALLCLOCK_GUEST,
+enum virDomainTimerTrackType {
+ VIR_DOMAIN_TIMER_TRACK_BOOT = 0,
+ VIR_DOMAIN_TIMER_TRACK_GUEST,
+ VIR_DOMAIN_TIMER_TRACK_WALL,
- VIR_DOMAIN_TIMER_WALLCLOCK_LAST,
+ VIR_DOMAIN_TIMER_TRACK_LAST,
};
enum virDomainTimerTickpolicyType {
VIR_DOMAIN_TIMER_MODE_NATIVE,
VIR_DOMAIN_TIMER_MODE_EMULATE,
VIR_DOMAIN_TIMER_MODE_PARAVIRT,
+ VIR_DOMAIN_TIMER_MODE_SMPSAFE,
VIR_DOMAIN_TIMER_MODE_LAST,
};
+typedef struct _virDomainTimerCatchupDef virDomainTimerCatchupDef;
+typedef virDomainTimerCatchupDef *virDomainTimerCatchupDefPtr;
+struct _virDomainTimerCatchupDef {
+ unsigned long threshold;
+ unsigned long slew;
+ unsigned long limit;
+};
+
typedef struct _virDomainTimerDef virDomainTimerDef;
typedef virDomainTimerDef *virDomainTimerDefPtr;
struct _virDomainTimerDef {
int present; /* unspecified = -1, no = 0, yes = 1 */
int tickpolicy; /* none|catchup|merge|discard */
- /* wallclock is only valid for name='platform|rtc' */
- int wallclock; /* host|guest */
+ virDomainTimerCatchupDef catchup;
+
+ /* track is only valid for name='platform|rtc' */
+ int track; /* host|guest */
/* frequency & mode are only valid for name='tsc' */
unsigned long frequency; /* in Hz, unspecified = 0 */
VIR_ENUM_DECL(virDomainNetdevMacvtap)
VIR_ENUM_DECL(virDomainTimerName)
-VIR_ENUM_DECL(virDomainTimerWallclock)
+VIR_ENUM_DECL(virDomainTimerTrack)
VIR_ENUM_DECL(virDomainTimerTickpolicy)
VIR_ENUM_DECL(virDomainTimerMode)
virDomainDiskErrorPolicyTypeToString;
virDomainTimerNameTypeToString;
virDomainTimerNameTypeFromString;
-virDomainTimerWallclockTypeToString;
-virDomainTimerWallclockTypeFromString;
+virDomainTimerTrackTypeToString;
+virDomainTimerTrackTypeFromString;
virDomainTimerTickpolicyTypeToString;
virDomainTimerTickpolicyTypeFromString;
virDomainTimerModeTypeToString;
int i;
for (i = 0; i < def->ntimers; i++) {
if (def->timers[i]->name == VIR_DOMAIN_TIMER_NAME_RTC) {
- if (def->timers[i]->wallclock == VIR_DOMAIN_TIMER_WALLCLOCK_HOST) {
- virBufferAddLit(&buf, ",clock=host");
- } else if (def->timers[i]->wallclock == VIR_DOMAIN_TIMER_WALLCLOCK_GUEST) {
+ switch (def->timers[i]->track) {
+ case -1: /* unspecified - use hypervisor default */
+ break;
+ case VIR_DOMAIN_TIMER_TRACK_BOOT:
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unsupported rtc timer track '%s'"),
+ virDomainTimerTrackTypeToString(def->timers[i]->track));
+ goto error;
+ case VIR_DOMAIN_TIMER_TRACK_GUEST:
virBufferAddLit(&buf, ",clock=vm");
+ break;
+ case VIR_DOMAIN_TIMER_TRACK_WALL:
+ virBufferAddLit(&buf, ",clock=host");
+ break;
}
+
switch (def->timers[i]->tickpolicy) {
case -1:
case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY: