Introduce register offsets and bitmask constants for the Transmit Rate Limiter (TRL). Add the IGBTrlQueue structure and corresponding fields to IGBCore to track TRL state (timers, throttling status, and target rates) per queue. Initialize and free these timers during the device realize/uninit lifecycle, and reset them on device reset.
Signed-off-by: Josh Hilke <[email protected]> --- hw/net/igb_common.h | 1 + hw/net/igb_core.c | 41 +++++++++++++++++++++++++++++++++++++++++ hw/net/igb_core.h | 12 ++++++++++++ hw/net/igb_regs.h | 5 +++++ 4 files changed, 59 insertions(+) diff --git a/hw/net/igb_common.h b/hw/net/igb_common.h index b316a5b..8c0a0cf 100644 --- a/hw/net/igb_common.h +++ b/hw/net/igb_common.h @@ -148,6 +148,7 @@ enum { defreg(MTA_A), defreg(VTIVAR), defreg(VTIVAR_MISC), + defreg(TRLDQSEL), defreg(TRLRC), }; uint64_t igb_mmio_read(void *opaque, hwaddr addr, unsigned size); diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c index 45d8fd7..44e8e58 100644 --- a/hw/net/igb_core.c +++ b/hw/net/igb_core.c @@ -2136,6 +2136,15 @@ igb_set_phy_ctrl(IGBCore *core, uint16_t val) } } + +static void igb_trl_reset(IGBCore *core) +{ + for (int i = 0; i < IGB_NUM_QUEUES; i++) { + core->trl[i].trlrc = 0; + timer_del(core->trl[i].timer); + } +} + void igb_core_set_link_status(IGBCore *core) { NetClientState *nc = qemu_get_queue(core->owner_nic); @@ -4282,6 +4291,33 @@ igb_autoneg_resume(IGBCore *core) } } +bool igb_trl_enabled(const IGBTrlQueue *q) +{ + return q->trlrc & E1000_TRLRC_RS_ENA; +} + +static void igb_trl_timer_cb(void *opaque) +{ + /* Stub */ +} + +static void igb_trl_init(IGBCore *core) +{ + for (int i = 0; i < IGB_NUM_QUEUES; i++) { + IGBTrlQueue *q = &core->trl[i]; + q->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_trl_timer_cb, q); + q->core = core; + q->qidx = i; + } +} + +static void igb_trl_uninit(IGBCore *core) +{ + for (int i = 0; i < IGB_NUM_QUEUES; i++) { + timer_free(core->trl[i].timer); + } +} + void igb_core_pci_realize(IGBCore *core, const uint16_t *eeprom_templ, @@ -4297,6 +4333,7 @@ igb_core_pci_realize(IGBCore *core, for (i = 0; i < IGB_NUM_QUEUES; i++) { net_tx_pkt_init(&core->tx[i].tx_pkt, E1000E_MAX_TX_FRAGS); } + igb_trl_init(core); net_rx_pkt_init(&core->rx_pkt); @@ -4321,6 +4358,8 @@ igb_core_pci_uninit(IGBCore *core) net_tx_pkt_uninit(core->tx[i].tx_pkt); } + igb_trl_uninit(core); + net_rx_pkt_uninit(core->rx_pkt); } @@ -4469,6 +4508,8 @@ static void igb_reset(IGBCore *core, bool sw) igb_intrmgr_reset(core); + igb_trl_reset(core); + memset(core->phy, 0, sizeof core->phy); memcpy(core->phy, igb_phy_reg_init, sizeof igb_phy_reg_init); diff --git a/hw/net/igb_core.h b/hw/net/igb_core.h index d70b54e..922d8cd 100644 --- a/hw/net/igb_core.h +++ b/hw/net/igb_core.h @@ -63,6 +63,13 @@ typedef struct IGBIntrDelayTimer_st { IGBCore *core; } IGBIntrDelayTimer; +typedef struct IGBTrlQueue_st { + QEMUTimer *timer; + IGBCore *core; + uint32_t qidx; + uint32_t trlrc; +} IGBTrlQueue; + struct IGBCore { uint32_t mac[E1000E_MAC_SIZE]; uint16_t phy[MAX_PHY_REG_ADDRESS + 1]; @@ -99,6 +106,9 @@ struct IGBCore { void (*owner_start_recv)(PCIDevice *d); int64_t timadj; + + /* Transmit Rate Limiting */ + IGBTrlQueue trl[IGB_NUM_QUEUES]; }; void @@ -143,4 +153,6 @@ igb_receive_iov(IGBCore *core, const struct iovec *iov, int iovcnt); void igb_start_recv(IGBCore *core); +bool igb_trl_enabled(const IGBTrlQueue *q); + #endif diff --git a/hw/net/igb_regs.h b/hw/net/igb_regs.h index 4dc4c31..4c31e4b 100644 --- a/hw/net/igb_regs.h +++ b/hw/net/igb_regs.h @@ -718,4 +718,9 @@ static inline uint8_t igb_ivar_entry_tx(uint8_t i) return i < 8 ? i * 4 + 1 : (i - 8) * 4 + 3; } +/* Transmit Rate Limiting */ +#define E1000_TRLDQSEL 0x03604 +#define E1000_TRLRC 0x036B0 +#define E1000_TRLRC_RS_ENA BIT(31) + #endif -- 2.55.0.rc0.786.g65d90a0328-goog
