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:
parent
69ff5ef847
commit
5fb7d14995
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user