From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59152) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V2glg-0001Pk-Oo for qemu-devel@nongnu.org; Fri, 26 Jul 2013 08:05:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1V2gle-0006tO-0K for qemu-devel@nongnu.org; Fri, 26 Jul 2013 08:05:08 -0400 Received: from cantor2.suse.de ([195.135.220.15]:55158 helo=mx2.suse.de) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V2gld-0006rw-Jk for qemu-devel@nongnu.org; Fri, 26 Jul 2013 08:05:05 -0400 Message-ID: <51F265ED.3060205@suse.de> Date: Fri, 26 Jul 2013 14:05:01 +0200 From: =?ISO-8859-1?Q?Andreas_F=E4rber?= MIME-Version: 1.0 References: In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH v2] e1000: add interrupt mitigation support List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Vincenzo Maffione Cc: Anthony Liguori , "Michael S. Tsirkin" , Jason Wang , qemu-devel@nongnu.org, Stefan Hajnoczi , Paolo Bonzini , Giuseppe Lettieri , Luigi Rizzo Hi, Am 26.07.2013 12:14, schrieb Vincenzo Maffione: > I tried to support cross-version migration using version_id and > VMState subsections. The point of using a subsection is to avoid incrementing version_id AFAIU= . > I also disable MIT if the machine is "pc-i440fx-1.5": Is that the > correct way to do it? The usual way is to add a textual entry to compat_props, setting the mitigation property on initialization. It is then not necessary to do special post-load handling. Please use git-send-email to send the patch inline, so that it can be applied by tools. I.e., there should be no Date: or Subject: headers in the body, and comments/questions can go under --- or in a cover letter. http://wiki.qemu.org/Contribute/SubmitAPatch Regards, Andreas > From 4e692113753db8dea6cbcc7a729cfa81469a76ca Mon Sep 17 00:00:00 2001 > From: Vincenzo Maffione > Date: Fri, 26 Jul 2013 11:58:33 +0200 > Subject: [PATCH] e1000: add interrupt mitigation support >=20 > This patch partially implements the e1000 interrupt mitigation mechanis= ms. > Using a single QEMUTimer, it emulates the ITR register (which is the ne= wer > mitigation register, recommended by Intel) and approximately emulates > RADV and TADV registers. TIDV and RDTR register functionalities are not > emulated (RDTR is only used to validate RADV, according to the e1000 sp= ecs). >=20 > RADV, TADV, TIDV and RDTR registers make up the older e1000 mitigation > mechanism and would need a timer each to be completely emulated. Howeve= r, > a single timer has been used in order to reach a good compromise betwee= n > emulation accuracy and simplicity/efficiency. >=20 > The implemented mechanism can be enabled/disabled specifying the comman= d > line e1000-specific boolean parameter "mit", e.g. >=20 > qemu-system-x86_64 -device e1000,mit=3Don,... ... >=20 > For more information, see the Software developer's manual at > http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf. >=20 > Signed-off-by: Vincenzo Maffione > --- > hw/net/e1000.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++= ++++++-- > 1 file changed, 135 insertions(+), 4 deletions(-) >=20 > diff --git a/hw/net/e1000.c b/hw/net/e1000.c > index b952d8d..003b7ce 100644 > --- a/hw/net/e1000.c > +++ b/hw/net/e1000.c > @@ -135,9 +135,16 @@ typedef struct E1000State_st { >=20 > QEMUTimer *autoneg_timer; >=20 > + QEMUTimer *mit_timer; /* Mitigation timer. */ > + bool mit_timer_on; /* Mitigation timer is running. */ > + bool mit_irq_level; /* Tracks interrupt pin level. */ > + uint32_t mit_ide; /* Tracks E1000_TXD_CMD_IDE bit. */ > + > /* Compatibility flags for migration to/from qemu 1.3.0 and older */ > #define E1000_FLAG_AUTONEG_BIT 0 > +#define E1000_FLAG_MIT_BIT 1 > #define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT) > +#define E1000_FLAG_MIT (1 << E1000_FLAG_MIT_BIT) > uint32_t compat_flags; > } E1000State; >=20 > @@ -158,7 +165,8 @@ enum { > defreg(TORH), defreg(TORL), defreg(TOTH), defreg(TOTL), > defreg(TPR), defreg(TPT), defreg(TXDCTL), defreg(WUFC), > defreg(RA), defreg(MTA), defreg(CRCERRS),defreg(VFTA), > - defreg(VET), > + defreg(VET), defreg(RDTR), defreg(RADV), defreg(TADV), > + defreg(ITR), > }; >=20 > static void > @@ -245,10 +253,21 @@ static const uint32_t mac_reg_init[] =3D { > E1000_MANC_RMCP_EN, > }; >=20 > +/* Helper function, *curr =3D=3D 0 means the value is not set */ > +static inline void > +mit_update_delay(uint32_t *curr, uint32_t value) > +{ > + if (value && (*curr =3D=3D 0 || value < *curr)) { > + *curr =3D value; > + } > +} > + > static void > set_interrupt_cause(E1000State *s, int index, uint32_t val) > { > PCIDevice *d =3D PCI_DEVICE(s); > + uint32_t pending_ints; > + uint32_t mit_delay; >=20 > if (val && (E1000_DEVID >=3D E1000_DEV_ID_82547EI_MOBILE)) { > /* Only for 8257x */ > @@ -266,7 +285,57 @@ set_interrupt_cause(E1000State *s, int index, uint= 32_t val) > */ > s->mac_reg[ICS] =3D val; >=20 > - qemu_set_irq(d->irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) !=3D 0= ); > + pending_ints =3D (s->mac_reg[IMS] & s->mac_reg[ICR]); > + if (!s->mit_irq_level && pending_ints) { > + /* > + * Here we detect a potential raising edge. We postpone raisin= g the > + * interrupt line if we are inside the mitigation delay window > + * (s->mit_timer_on =3D=3D 1). > + * We provide a partial implementation of interrupt mitigation= , > + * emulating only RADV, TADV and ITR (lower 16 bits, 1024ns un= its for > + * RADV and TADV, 256ns units for ITR). RDTR is only used to e= nable > + * RADV; relative timers based on TIDV and RDTR are not implem= ented. > + */ > + if (s->mit_timer_on) { > + return; > + } > + if (s->compat_flags & E1000_FLAG_MIT) { > + /* Compute the next mitigation delay according to pending > + * interrupts and the current values of RADV (provided > + * RDTR!=3D0), TADV and ITR. > + * Then rearm the timer. > + */ > + mit_delay =3D 0; > + if (s->mit_ide && > + (pending_ints & (E1000_ICR_TXQE | E1000_ICR_TXDW))= ) { > + mit_update_delay(&mit_delay, s->mac_reg[TADV] * 4); > + } > + if (s->mac_reg[RDTR] && (pending_ints & E1000_ICS_RXT0)) { > + mit_update_delay(&mit_delay, s->mac_reg[RADV] * 4); > + } > + mit_update_delay(&mit_delay, s->mac_reg[ITR]); > + > + if (mit_delay) { > + s->mit_timer_on =3D 1; > + qemu_mod_timer(s->mit_timer, > + qemu_get_clock_ns(vm_clock) + mit_delay * 256)= ; > + } > + s->mit_ide =3D 0; > + } > + } > + > + s->mit_irq_level =3D (pending_ints !=3D 0); > + qemu_set_irq(d->irq[0], s->mit_irq_level); > +} > + > +static void > +e1000_mit_timer(void *opaque) > +{ > + E1000State *s =3D opaque; > + > + s->mit_timer_on =3D 0; > + /* Call set_interrupt_cause to update the irq level (if necessary)= . */ > + set_interrupt_cause(s, 0, s->mac_reg[ICR]); > } >=20 > static void > @@ -307,6 +376,10 @@ static void e1000_reset(void *opaque) > int i; >=20 > qemu_del_timer(d->autoneg_timer); > + qemu_del_timer(d->mit_timer); > + d->mit_timer_on =3D 0; > + d->mit_irq_level =3D 0; > + d->mit_ide =3D 0; > memset(d->phy_reg, 0, sizeof d->phy_reg); > memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init); > memset(d->mac_reg, 0, sizeof d->mac_reg); > @@ -572,6 +645,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc= *dp) > struct e1000_context_desc *xp =3D (struct e1000_context_desc *)dp; > struct e1000_tx *tp =3D &s->tx; >=20 > + s->mit_ide |=3D (txd_lower & E1000_TXD_CMD_IDE); > if (dtype =3D=3D E1000_TXD_CMD_DEXT) { // context descriptor > op =3D le32_to_cpu(xp->cmd_and_length); > tp->ipcss =3D xp->lower_setup.ip_fields.ipcss; > @@ -1047,7 +1121,8 @@ static uint32_t (*macreg_readops[])(E1000State *,= int) =3D { > getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL), > getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS), > getreg(TDBAL), getreg(TDBAH), getreg(RDBAH), getreg(RDBAL= ), > - getreg(TDLEN), getreg(RDLEN), > + getreg(TDLEN), getreg(RDLEN), getreg(RDTR), getreg(RADV), > + getreg(TADV), getreg(ITR), >=20 > [TOTH] =3D mac_read_clr8, [TORH] =3D mac_read_clr8, [GPRC] =3D > mac_read_clr4, > [GPTC] =3D mac_read_clr4, [TPR] =3D mac_read_clr4, [TPT] =3D= mac_read_clr4, > @@ -1069,6 +1144,8 @@ static void (*macreg_writeops[])(E1000State *, > int, uint32_t) =3D { > [TDH] =3D set_16bit, [RDH] =3D set_16bit, [RDT] =3D set_rdt, > [IMC] =3D set_imc, [IMS] =3D set_ims, [ICR] =3D set_icr, > [EECD] =3D set_eecd, [RCTL] =3D set_rx_control, [CTRL] =3D set_= ctrl, > + [RDTR] =3D set_16bit, [RADV] =3D set_16bit, [TADV] =3D set_16b= it, > + [ITR] =3D set_16bit, > [RA ... RA+31] =3D &mac_writereg, > [MTA ... MTA+127] =3D &mac_writereg, > [VFTA ... VFTA+127] =3D &mac_writereg, > @@ -1150,6 +1227,11 @@ static void e1000_pre_save(void *opaque) > E1000State *s =3D opaque; > NetClientState *nc =3D qemu_get_queue(s->nic); >=20 > + /* If the mitigation timer is active, emulate a timeout now. */ > + if (s->mit_timer_on) { > + e1000_mit_timer(s); > + } > + > if (!(s->compat_flags & E1000_FLAG_AUTONEG)) { > return; > } > @@ -1171,6 +1253,12 @@ static int e1000_post_load(void *opaque, int ver= sion_id) > E1000State *s =3D opaque; > NetClientState *nc =3D qemu_get_queue(s->nic); >=20 > + if (version_id < 3 || !(s->compat_flags & E1000_FLAG_MIT)) { > + s->mac_reg[ITR] =3D s->mac_reg[RDTR] =3D s->mac_reg[RADV] =3D > + s->mac_reg[TADV] =3D s->mit_ide =3D 0; > + s->mit_timer_on =3D s->mit_irq_level =3D false; > + } > + > /* nc.link_down can't be migrated, so infer link_down according > * to link status bit in mac_reg[STATUS]. > * Alternatively, restart link negotiation if it was in progress. = */ > @@ -1190,9 +1278,33 @@ static int e1000_post_load(void *opaque, int ver= sion_id) > return 0; > } >=20 > +static bool e1000_mit_state_needed(void *opaque) > +{ > + E1000State *s =3D opaque; > + > + return s->compat_flags & E1000_FLAG_MIT; > +} > + > +static const VMStateDescription vmstate_e1000_mit_state =3D { > + .name =3D "e1000/mit_state", > + .version_id =3D 1, > + .minimum_version_id =3D 1, > + .minimum_version_id_old =3D 1, > + .fields =3D (VMStateField[]) { > + VMSTATE_UINT32(mac_reg[RDTR], E1000State), > + VMSTATE_UINT32(mac_reg[RADV], E1000State), > + VMSTATE_UINT32(mac_reg[TADV], E1000State), > + VMSTATE_UINT32(mac_reg[ITR], E1000State), > + VMSTATE_BOOL(mit_timer_on, E1000State), > + VMSTATE_BOOL(mit_irq_level, E1000State), > + VMSTATE_UINT32(mit_ide, E1000State), > + VMSTATE_END_OF_LIST() > + } > +}; > + > static const VMStateDescription vmstate_e1000 =3D { > .name =3D "e1000", > - .version_id =3D 2, > + .version_id =3D 3, > .minimum_version_id =3D 1, > .minimum_version_id_old =3D 1, > .pre_save =3D e1000_pre_save, > @@ -1267,6 +1379,14 @@ static const VMStateDescription vmstate_e1000 =3D= { > VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128), > VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128), > VMSTATE_END_OF_LIST() > + }, > + .subsections =3D (VMStateSubsection[]) { > + { > + .vmsd =3D &vmstate_e1000_mit_state, > + .needed =3D e1000_mit_state_needed, > + }, { > + /* empty */ > + } > } > }; >=20 > @@ -1316,6 +1436,8 @@ pci_e1000_uninit(PCIDevice *dev) >=20 > qemu_del_timer(d->autoneg_timer); > qemu_free_timer(d->autoneg_timer); > + qemu_del_timer(d->mit_timer); > + qemu_free_timer(d->mit_timer); > memory_region_destroy(&d->mmio); > memory_region_destroy(&d->io); > qemu_del_nic(d->nic); > @@ -1338,6 +1460,7 @@ static int pci_e1000_init(PCIDevice *pci_dev) > uint16_t checksum =3D 0; > int i; > uint8_t *macaddr; > + const char *machine_type; >=20 > pci_conf =3D pci_dev->config; >=20 > @@ -1371,6 +1494,12 @@ static int pci_e1000_init(PCIDevice *pci_dev) > add_boot_device_path(d->conf.bootindex, dev, "/ethernet-phy@0"); >=20 > d->autoneg_timer =3D qemu_new_timer_ms(vm_clock, e1000_autoneg_tim= er, d); > + d->mit_timer =3D qemu_new_timer_ns(vm_clock, e1000_mit_timer, d); > + > + machine_type =3D qemu_opt_get(qemu_get_machine_opts(), "type"); > + if (machine_type && strcmp(machine_type, "pc-i440fx-1.5") =3D=3D 0= ) { > + d->compat_flags &=3D ~E1000_FLAG_MIT; > + } >=20 > return 0; > } > @@ -1385,6 +1514,8 @@ static Property e1000_properties[] =3D { > DEFINE_NIC_PROPERTIES(E1000State, conf), > DEFINE_PROP_BIT("autonegotiation", E1000State, > compat_flags, E1000_FLAG_AUTONEG_BIT, true), > + DEFINE_PROP_BIT("mitigation", E1000State, > + compat_flags, E1000_FLAG_MIT_BIT, true), > DEFINE_PROP_END_OF_LIST(), > }; >=20 --=20 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 N=FCrnberg, Germany GF: Jeff Hawn, Jennifer Guild, Felix Imend=F6rffer; HRB 16746 AG N=FCrnbe= rg