On 2026/06/23 17:58, Philippe Mathieu-Daudé wrote:
On 22/6/26 21:05, Josh Hilke wrote:Integrate throttling logic into the transmission path. In `igb_start_xmit`, check if the queue is currently throttled. Accumulate bytes sent, calculate the transmission delay based on the configured target rate, and if a throttle is triggered, set the virtual timer, mark the queue as throttled, and defer remaining packets. Implement the timer callback to clear the throttled state and resume transmission when the timer expires.Signed-off-by: Josh Hilke <[email protected]> ---hw/net/igb_core.c | 66 +++++++++++++++++++++++++++++++++++++++++++++ +++++++---1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c index 9a8ef15..e158837 100644 --- a/hw/net/igb_core.c +++ b/hw/net/igb_core.c@@ -97,6 +97,7 @@ igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt, static void igb_raise_interrupts(IGBCore *core, size_t index, uint32_t causes);static void igb_reset(IGBCore *core, bool sw); +Hmm?static inline void igb_raise_legacy_irq(IGBCore *core) {@@ -875,6 +876,48 @@ igb_tx_enabled(IGBCore *core, const E1000ERingInfo *txi)(core->mac[TXDCTL0 + (qn * 16)] & E1000_TXDCTL_QUEUE_ENABLE); }+static uint64_t igb_trl_calculate_delay(const IGBTrlQueue *q, size_t bytes_sent)+{ + uint32_t divisor; + uint32_t rf; + + if (!igb_trl_enabled(q)) { + return 0; + } + + /* + * 7.8 Transmit Rate Limiting (TRL) + * + * > RF = 1Gb/s / Target-Rate (Rate Factor) is the ratio between the + * > nominal link rate and the target maximum rate to achieve for + * > that rate controlled queue. It is a decimal number ranging from + * > 1 to 1,000 (1 Mb/s minimum target rate) at least 10-bits before + * > the hexadecimal point and 14-bits after, as required for the + * > maximum PL by which it is multiplied. + * + * The TRLRC register stores the RF in 10.14 fixed-point format: + * - Bits 13:0: Fractional part + * - Bits 23:14: Integer part + * + * Combined, the lower 24 bits of the register (23:0) represent the + * RF directly. + */ + rf = MAX(extract32(q->trlrc, 0, 24), 1 << 14); + + /* + * Delay = PL (Packet Length) / Target-Rate + * = PL / (1Gb/s / RF) + * = PL * RF / 1Gb/s + * = PL * RF / (1G / b/B / ns/s) B/ns + * = (bytes_sent * (RF_scaled / 2^14) / (1G / b/B / ns/s)) ns + * = (bytes_sent * RF_scaled / (1G / b/B * 2^14 / ns/s)) ns
s/RF_scaled/RF/g since RF is defined as including 14-bits after the point, as quoted above. (i.e., RF is already defined as "scaled".)
Regards, Akihiko Odaki
+ */ + divisor = ((1000000000ULL / BITS_PER_BYTE) << 14) / + NANOSECONDS_PER_SECOND; + + return (uint64_t)bytes_sent * rf / divisor;Any reason for not using muldiv64()?+} + static void igb_start_xmit(IGBCore *core, const IGB_TxRing *txr) {@@ -883,12 +926,19 @@ igb_start_xmit(IGBCore *core, const IGB_TxRing *txr)union e1000_adv_tx_desc desc; const E1000ERingInfo *txi = txr->i; uint32_t eic = 0; + size_t bytes_sent = 0; + uint64_t delay_ns; if (!igb_tx_enabled(core, txi)) { trace_e1000e_tx_disabled(); return; } + if (igb_trl_enabled(&core->trl[txi->idx]) && + timer_pending(core->trl[txi->idx].timer)) { + return; + } + d = pcie_sriov_get_vf_at_index(core->owner, txi->idx % 8); if (!d) { d = core->owner; @@ -902,9 +952,16 @@ igb_start_xmit(IGBCore *core, const IGB_TxRing *txr) trace_e1000e_tx_descr((void *)(intptr_t)desc.read.buffer_addr, desc.read.cmd_type_len, desc.wb.status); - igb_process_tx_desc(core, d, txr->tx, &desc, txi->idx);+ bytes_sent += igb_process_tx_desc(core, d, txr->tx, &desc, txi->idx);igb_ring_advance(core, txi, 1); eic |= igb_txdesc_writeback(core, base, &desc, txi); ++ delay_ns = igb_trl_calculate_delay(&core->trl[txi->idx], bytes_sent);+ if (delay_ns > 0) { + timer_mod(core->trl[txi->idx].timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + delay_ns); + break; + } } if (eic) { @@ -4321,7 +4378,6 @@ igb_autoneg_resume(IGBCore *core) qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500); } } -Hmm?bool igb_trl_enabled(const IGBTrlQueue *q) { return q->trlrc & E1000_TRLRC_RS_ENA; @@ -4329,7 +4385,11 @@ bool igb_trl_enabled(const IGBTrlQueue *q) static void igb_trl_timer_cb(void *opaque) { - /* Stub */ + IGBTrlQueue *trl = opaque; + IGB_TxRing txr; + + igb_tx_ring_init(trl->core, &txr, trl->qidx); + igb_start_xmit(trl->core, &txr); } static void igb_trl_init(IGBCore *core)Modulo muldiv: Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
