e1000e: Implement system clock

The system clock is necessary to implement PTP features. While we are
not implementing PTP features for e1000e yet, we do have a plan to
implement them for igb, a new network device derived from e1000e,
so add system clock to the common base first.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
This commit is contained in:
Akihiko Odaki 2023-02-23 19:20:18 +09:00 committed by Jason Wang
parent 69ff5ef847
commit 5fb7d14995
7 changed files with 103 additions and 5 deletions

View file

@ -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);

View file

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

View file

@ -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(),
};

View file

@ -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,

View file

@ -112,6 +112,8 @@ struct E1000Core {
void (*owner_start_recv)(PCIDevice *d);
uint32_t msi_causes_pending;
int64_t timadj;
};
void

View file

@ -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;
}

View file

@ -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