@@ -40,6 +40,7 @@
#include "hw/virtio/virtio-pci.h"
GlobalProperty hw_compat_7_2[] = {
+ { "e1000e", "migrate-timadj", "off" },
{ "virtio-mem", "x-early-migration", "false" },
};
const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2);
@@ -908,6 +908,33 @@
#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */
#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */
+/* HH Time Sync */
+#define E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
+#define E1000_TSYNCTXCTL_SYNC_COMP 0x40000000 /* sync complete */
+#define E1000_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
+
+#define E1000_TSYNCTXCTL_VALID 0x00000001 /* Tx timestamp valid */
+#define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
+
+#define E1000_TSYNCRXCTL_VALID 0x00000001 /* Rx timestamp valid */
+#define E1000_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
+#define E1000_TSYNCRXCTL_TYPE_L2_V2 0x00
+#define E1000_TSYNCRXCTL_TYPE_L4_V1 0x02
+#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
+#define E1000_TSYNCRXCTL_TYPE_ALL 0x08
+#define E1000_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
+#define E1000_TSYNCRXCTL_ENABLED 0x00000010 /* enable Rx timestamping */
+#define E1000_TSYNCRXCTL_SYSCFI 0x00000020 /* Sys clock frequency */
+
+#define E1000_RXMTRL_PTP_V1_SYNC_MESSAGE 0x00000000
+#define E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE 0x00010000
+
+#define E1000_RXMTRL_PTP_V2_SYNC_MESSAGE 0x00000000
+#define E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE 0x01000000
+
+#define E1000_TIMINCA_INCPERIOD_SHIFT 24
+#define E1000_TIMINCA_INCVALUE_MASK 0x00FFFFFF
+
/* PCI Express Control */
/* 3GIO Control Register - GCR (0x05B00; RW) */
#define E1000_L0S_ADJUST (1 << 9)
@@ -82,6 +82,7 @@ struct E1000EState {
E1000ECore core;
bool init_vet;
+ bool timadj;
};
#define E1000E_MMIO_IDX 0
@@ -554,6 +555,12 @@ static int e1000e_post_load(void *opaque, int version_id)
return e1000e_core_post_load(&s->core);
}
+static bool e1000e_migrate_timadj(void *opaque, int version_id)
+{
+ E1000EState *s = opaque;
+ return s->timadj;
+}
+
static const VMStateDescription e1000e_vmstate_tx = {
.name = "e1000e-tx",
.version_id = 1,
@@ -645,6 +652,9 @@ static const VMStateDescription e1000e_vmstate = {
VMSTATE_STRUCT_ARRAY(core.tx, E1000EState, E1000E_NUM_QUEUES, 0,
e1000e_vmstate_tx, struct e1000e_tx),
+
+ VMSTATE_INT64_TEST(core.timadj, E1000EState, e1000e_migrate_timadj),
+
VMSTATE_END_OF_LIST()
}
};
@@ -663,6 +673,7 @@ static Property e1000e_properties[] = {
DEFINE_PROP_SIGNED("subsys", E1000EState, subsys, 0,
e1000e_prop_subsys, uint16_t),
DEFINE_PROP_BOOL("init-vet", E1000EState, init_vet, true),
+ DEFINE_PROP_BOOL("migrate-timadj", E1000EState, timadj, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -2902,6 +2902,35 @@ e1000e_set_gcr(E1000ECore *core, int index, uint32_t val)
core->mac[GCR] = (val & ~E1000_GCR_RO_BITS) | ro_bits;
}
+static uint32_t e1000e_get_systiml(E1000ECore *core, int index)
+{
+ e1000x_timestamp(core->mac, core->timadj, SYSTIML, SYSTIMH);
+ return core->mac[SYSTIML];
+}
+
+static uint32_t e1000e_get_rxsatrh(E1000ECore *core, int index)
+{
+ core->mac[TSYNCRXCTL] &= ~E1000_TSYNCRXCTL_VALID;
+ return core->mac[RXSATRH];
+}
+
+static uint32_t e1000e_get_txstmph(E1000ECore *core, int index)
+{
+ core->mac[TSYNCTXCTL] &= ~E1000_TSYNCTXCTL_VALID;
+ return core->mac[TXSTMPH];
+}
+
+static void e1000e_set_timinca(E1000ECore *core, int index, uint32_t val)
+{
+ e1000x_set_timinca(core->mac, &core->timadj, val);
+}
+
+static void e1000e_set_timadjh(E1000ECore *core, int index, uint32_t val)
+{
+ core->mac[TIMADJH] = val;
+ core->timadj += core->mac[TIMADJL] | ((int64_t)core->mac[TIMADJH] << 32);
+}
+
#define e1000e_getreg(x) [x] = e1000e_mac_readreg
typedef uint32_t (*readops)(E1000ECore *, int);
static const readops e1000e_macreg_readops[] = {
@@ -2957,7 +2986,6 @@ static const readops e1000e_macreg_readops[] = {
e1000e_getreg(GSCL_2),
e1000e_getreg(RDBAH1),
e1000e_getreg(FLSWDATA),
- e1000e_getreg(RXSATRH),
e1000e_getreg(TIPG),
e1000e_getreg(FLMNGCTL),
e1000e_getreg(FLMNGCNT),
@@ -2998,7 +3026,6 @@ static const readops e1000e_macreg_readops[] = {
e1000e_getreg(FLSWCTL),
e1000e_getreg(RXDCTL1),
e1000e_getreg(RXSATRL),
- e1000e_getreg(SYSTIML),
e1000e_getreg(RXUDP),
e1000e_getreg(TORL),
e1000e_getreg(TDLEN1),
@@ -3038,7 +3065,6 @@ static const readops e1000e_macreg_readops[] = {
e1000e_getreg(FLOL),
e1000e_getreg(RXDCTL),
e1000e_getreg(RXSTMPL),
- e1000e_getreg(TXSTMPH),
e1000e_getreg(TIMADJH),
e1000e_getreg(FCRTL),
e1000e_getreg(TDBAH),
@@ -3087,6 +3113,9 @@ static const readops e1000e_macreg_readops[] = {
[TARC1] = e1000e_get_tarc,
[SWSM] = e1000e_mac_swsm_read,
[IMS] = e1000e_mac_ims_read,
+ [SYSTIML] = e1000e_get_systiml,
+ [RXSATRH] = e1000e_get_rxsatrh,
+ [TXSTMPH] = e1000e_get_txstmph,
[CRCERRS ... MPC] = e1000e_mac_readreg,
[IP6AT ... IP6AT + 3] = e1000e_mac_readreg,
@@ -3125,7 +3154,6 @@ static const writeops e1000e_macreg_writeops[] = {
e1000e_putreg(WUS),
e1000e_putreg(IPAV),
e1000e_putreg(TDBAH1),
- e1000e_putreg(TIMINCA),
e1000e_putreg(IAM),
e1000e_putreg(EIAC),
e1000e_putreg(IVAR),
@@ -3168,7 +3196,6 @@ static const writeops e1000e_macreg_writeops[] = {
e1000e_putreg(SYSTIML),
e1000e_putreg(SYSTIMH),
e1000e_putreg(TIMADJL),
- e1000e_putreg(TIMADJH),
e1000e_putreg(RXUDP),
e1000e_putreg(RXCFGL),
e1000e_putreg(TSYNCRXCTL),
@@ -3241,6 +3268,8 @@ static const writeops e1000e_macreg_writeops[] = {
[CTRL_DUP] = e1000e_set_ctrl,
[RFCTL] = e1000e_set_rfctl,
[RA + 1] = e1000e_mac_setmacaddr,
+ [TIMINCA] = e1000e_set_timinca,
+ [TIMADJH] = e1000e_set_timadjh,
[IP6AT ... IP6AT + 3] = e1000e_mac_writereg,
[IP4AT ... IP4AT + 6] = e1000e_mac_writereg,
@@ -112,6 +112,8 @@ struct E1000Core {
void (*owner_start_recv)(PCIDevice *d);
uint32_t msi_causes_pending;
+
+ int64_t timadj;
};
void
@@ -267,3 +267,28 @@ e1000x_read_tx_ctx_descr(struct e1000_context_desc *d,
props->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
props->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
}
+
+void e1000x_timestamp(uint32_t *mac, int64_t timadj, size_t lo, size_t hi)
+{
+ int64_t ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ uint32_t timinca = mac[TIMINCA];
+ uint32_t incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK;
+ uint32_t incperiod = MAX(timinca >> E1000_TIMINCA_INCPERIOD_SHIFT, 1);
+ int64_t timestamp = timadj + muldiv64(ns, incvalue, incperiod * 16);
+
+ mac[lo] = timestamp & 0xffffffff;
+ mac[hi] = timestamp >> 32;
+}
+
+void e1000x_set_timinca(uint32_t *mac, int64_t *timadj, uint32_t val)
+{
+ int64_t ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ uint32_t old_val = mac[TIMINCA];
+ uint32_t old_incvalue = old_val & E1000_TIMINCA_INCVALUE_MASK;
+ uint32_t old_incperiod = MAX(old_val >> E1000_TIMINCA_INCPERIOD_SHIFT, 1);
+ uint32_t incvalue = val & E1000_TIMINCA_INCVALUE_MASK;
+ uint32_t incperiod = MAX(val >> E1000_TIMINCA_INCPERIOD_SHIFT, 1);
+
+ mac[TIMINCA] = val;
+ *timadj += (muldiv64(ns, incvalue, incperiod) - muldiv64(ns, old_incvalue, old_incperiod)) / 16;
+}
@@ -213,4 +213,7 @@ typedef struct e1000x_txd_props {
void e1000x_read_tx_ctx_descr(struct e1000_context_desc *d,
e1000x_txd_props *props);
+void e1000x_timestamp(uint32_t *mac, int64_t timadj, size_t lo, size_t hi);
+void e1000x_set_timinca(uint32_t *mac, int64_t *timadj, uint32_t val);
+
#endif