Signed-off-by: Josh Hilke <[email protected]>
---
hw/net/igb_common.h | 1 +
hw/net/igb_core.c | 17 +++++++++++++++++
hw/net/igb_core.h | 11 +++++++++++
hw/net/igb_regs.h | 11 +++++++++++
4 files changed, 40 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..64f21c1 100644
--- a/hw/net/igb_core.c
+++ b/hw/net/igb_core.c
@@ -4282,6 +4282,11 @@ igb_autoneg_resume(IGBCore *core)
}
}
+static void igb_trl_timer_cb(void *opaque)
+{
+ /* Stub */
+}
+
void
igb_core_pci_realize(IGBCore *core,
const uint16_t *eeprom_templ,
@@ -4296,6 +4301,11 @@ 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);
+ core->trl_timer[i].timer =
+ timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_trl_timer_cb,
+ &core->trl_timer[i]);
+ core->trl_timer[i].core = core;
+ core->trl_timer[i].queue_idx = i;
}
net_rx_pkt_init(&core->rx_pkt);
@@ -4319,6 +4329,7 @@ igb_core_pci_uninit(IGBCore *core)
for (i = 0; i < IGB_NUM_QUEUES; i++) {
net_tx_pkt_uninit(core->tx[i].tx_pkt);
+ timer_free(core->trl_timer[i].timer);
}
net_rx_pkt_uninit(core->rx_pkt);
@@ -4469,6 +4480,12 @@ static void igb_reset(IGBCore *core, bool sw)
igb_intrmgr_reset(core);
+ for (i = 0; i < IGB_NUM_QUEUES; i++) {
+ timer_del(core->trl_timer[i].timer);
+ core->trl_throttled[i] = false;
+ core->trl_target_rate[i] = 0;
+ }
+
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..ffd45ed 100644
--- a/hw/net/igb_core.h
+++ b/hw/net/igb_core.h
@@ -63,6 +63,12 @@ typedef struct IGBIntrDelayTimer_st {
IGBCore *core;
} IGBIntrDelayTimer;
+typedef struct IGBTrlTimer_st {
+ QEMUTimer *timer;
+ IGBCore *core;
+ int queue_idx;
+} IGBTrlTimer;
+
struct IGBCore {
uint32_t mac[E1000E_MAC_SIZE];
uint16_t phy[MAX_PHY_REG_ADDRESS + 1];
@@ -99,6 +105,11 @@ struct IGBCore {
void (*owner_start_recv)(PCIDevice *d);
int64_t timadj;
+
+ /* Transmit Rate Limiting */
+ IGBTrlTimer trl_timer[IGB_NUM_QUEUES];
+ bool trl_throttled[IGB_NUM_QUEUES];
+ uint64_t trl_target_rate[IGB_NUM_QUEUES]; /* in bytes per second */
};
void
diff --git a/hw/net/igb_regs.h b/hw/net/igb_regs.h
index 4dc4c31..f7895ef 100644
--- a/hw/net/igb_regs.h
+++ b/hw/net/igb_regs.h
@@ -718,4 +718,15 @@ 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)
+#define E1000_TRLRC_RF_DEC_MASK 0x3FFF
+#define E1000_TRLRC_RF_INT_MASK 0x3FF
+
+/* 1 Gbps link rate in bytes per second (1,000,000,000 bits/s / 8) */
+#define E1000_LINK_RATE_1GBPS 125000000ULL
+
#endif