Revision e9845f09 hw/net/e1000.c
b/hw/net/e1000.c | ||
---|---|---|
135 | 135 |
|
136 | 136 |
QEMUTimer *autoneg_timer; |
137 | 137 |
|
138 |
QEMUTimer *mit_timer; /* Mitigation timer. */ |
|
139 |
bool mit_timer_on; /* Mitigation timer is running. */ |
|
140 |
bool mit_irq_level; /* Tracks interrupt pin level. */ |
|
141 |
uint32_t mit_ide; /* Tracks E1000_TXD_CMD_IDE bit. */ |
|
142 |
|
|
138 | 143 |
/* Compatibility flags for migration to/from qemu 1.3.0 and older */ |
139 | 144 |
#define E1000_FLAG_AUTONEG_BIT 0 |
145 |
#define E1000_FLAG_MIT_BIT 1 |
|
140 | 146 |
#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT) |
147 |
#define E1000_FLAG_MIT (1 << E1000_FLAG_MIT_BIT) |
|
141 | 148 |
uint32_t compat_flags; |
142 | 149 |
} E1000State; |
143 | 150 |
|
... | ... | |
158 | 165 |
defreg(TORH), defreg(TORL), defreg(TOTH), defreg(TOTL), |
159 | 166 |
defreg(TPR), defreg(TPT), defreg(TXDCTL), defreg(WUFC), |
160 | 167 |
defreg(RA), defreg(MTA), defreg(CRCERRS),defreg(VFTA), |
161 |
defreg(VET), |
|
168 |
defreg(VET), defreg(RDTR), defreg(RADV), defreg(TADV), |
|
169 |
defreg(ITR), |
|
162 | 170 |
}; |
163 | 171 |
|
164 | 172 |
static void |
... | ... | |
245 | 253 |
E1000_MANC_RMCP_EN, |
246 | 254 |
}; |
247 | 255 |
|
256 |
/* Helper function, *curr == 0 means the value is not set */ |
|
257 |
static inline void |
|
258 |
mit_update_delay(uint32_t *curr, uint32_t value) |
|
259 |
{ |
|
260 |
if (value && (*curr == 0 || value < *curr)) { |
|
261 |
*curr = value; |
|
262 |
} |
|
263 |
} |
|
264 |
|
|
248 | 265 |
static void |
249 | 266 |
set_interrupt_cause(E1000State *s, int index, uint32_t val) |
250 | 267 |
{ |
251 | 268 |
PCIDevice *d = PCI_DEVICE(s); |
269 |
uint32_t pending_ints; |
|
270 |
uint32_t mit_delay; |
|
252 | 271 |
|
253 | 272 |
if (val && (E1000_DEVID >= E1000_DEV_ID_82547EI_MOBILE)) { |
254 | 273 |
/* Only for 8257x */ |
... | ... | |
266 | 285 |
*/ |
267 | 286 |
s->mac_reg[ICS] = val; |
268 | 287 |
|
269 |
qemu_set_irq(d->irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0); |
|
288 |
pending_ints = (s->mac_reg[IMS] & s->mac_reg[ICR]); |
|
289 |
if (!s->mit_irq_level && pending_ints) { |
|
290 |
/* |
|
291 |
* Here we detect a potential raising edge. We postpone raising the |
|
292 |
* interrupt line if we are inside the mitigation delay window |
|
293 |
* (s->mit_timer_on == 1). |
|
294 |
* We provide a partial implementation of interrupt mitigation, |
|
295 |
* emulating only RADV, TADV and ITR (lower 16 bits, 1024ns units for |
|
296 |
* RADV and TADV, 256ns units for ITR). RDTR is only used to enable |
|
297 |
* RADV; relative timers based on TIDV and RDTR are not implemented. |
|
298 |
*/ |
|
299 |
if (s->mit_timer_on) { |
|
300 |
return; |
|
301 |
} |
|
302 |
if (s->compat_flags & E1000_FLAG_MIT) { |
|
303 |
/* Compute the next mitigation delay according to pending |
|
304 |
* interrupts and the current values of RADV (provided |
|
305 |
* RDTR!=0), TADV and ITR. |
|
306 |
* Then rearm the timer. |
|
307 |
*/ |
|
308 |
mit_delay = 0; |
|
309 |
if (s->mit_ide && |
|
310 |
(pending_ints & (E1000_ICR_TXQE | E1000_ICR_TXDW))) { |
|
311 |
mit_update_delay(&mit_delay, s->mac_reg[TADV] * 4); |
|
312 |
} |
|
313 |
if (s->mac_reg[RDTR] && (pending_ints & E1000_ICS_RXT0)) { |
|
314 |
mit_update_delay(&mit_delay, s->mac_reg[RADV] * 4); |
|
315 |
} |
|
316 |
mit_update_delay(&mit_delay, s->mac_reg[ITR]); |
|
317 |
|
|
318 |
if (mit_delay) { |
|
319 |
s->mit_timer_on = 1; |
|
320 |
timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + |
|
321 |
mit_delay * 256); |
|
322 |
} |
|
323 |
s->mit_ide = 0; |
|
324 |
} |
|
325 |
} |
|
326 |
|
|
327 |
s->mit_irq_level = (pending_ints != 0); |
|
328 |
qemu_set_irq(d->irq[0], s->mit_irq_level); |
|
329 |
} |
|
330 |
|
|
331 |
static void |
|
332 |
e1000_mit_timer(void *opaque) |
|
333 |
{ |
|
334 |
E1000State *s = opaque; |
|
335 |
|
|
336 |
s->mit_timer_on = 0; |
|
337 |
/* Call set_interrupt_cause to update the irq level (if necessary). */ |
|
338 |
set_interrupt_cause(s, 0, s->mac_reg[ICR]); |
|
270 | 339 |
} |
271 | 340 |
|
272 | 341 |
static void |
... | ... | |
307 | 376 |
int i; |
308 | 377 |
|
309 | 378 |
timer_del(d->autoneg_timer); |
379 |
timer_del(d->mit_timer); |
|
380 |
d->mit_timer_on = 0; |
|
381 |
d->mit_irq_level = 0; |
|
382 |
d->mit_ide = 0; |
|
310 | 383 |
memset(d->phy_reg, 0, sizeof d->phy_reg); |
311 | 384 |
memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init); |
312 | 385 |
memset(d->mac_reg, 0, sizeof d->mac_reg); |
... | ... | |
572 | 645 |
struct e1000_context_desc *xp = (struct e1000_context_desc *)dp; |
573 | 646 |
struct e1000_tx *tp = &s->tx; |
574 | 647 |
|
648 |
s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE); |
|
575 | 649 |
if (dtype == E1000_TXD_CMD_DEXT) { // context descriptor |
576 | 650 |
op = le32_to_cpu(xp->cmd_and_length); |
577 | 651 |
tp->ipcss = xp->lower_setup.ip_fields.ipcss; |
... | ... | |
1047 | 1121 |
getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL), |
1048 | 1122 |
getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS), |
1049 | 1123 |
getreg(TDBAL), getreg(TDBAH), getreg(RDBAH), getreg(RDBAL), |
1050 |
getreg(TDLEN), getreg(RDLEN), |
|
1124 |
getreg(TDLEN), getreg(RDLEN), getreg(RDTR), getreg(RADV), |
|
1125 |
getreg(TADV), getreg(ITR), |
|
1051 | 1126 |
|
1052 | 1127 |
[TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4, |
1053 | 1128 |
[GPTC] = mac_read_clr4, [TPR] = mac_read_clr4, [TPT] = mac_read_clr4, |
... | ... | |
1069 | 1144 |
[TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt, |
1070 | 1145 |
[IMC] = set_imc, [IMS] = set_ims, [ICR] = set_icr, |
1071 | 1146 |
[EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl, |
1147 |
[RDTR] = set_16bit, [RADV] = set_16bit, [TADV] = set_16bit, |
|
1148 |
[ITR] = set_16bit, |
|
1072 | 1149 |
[RA ... RA+31] = &mac_writereg, |
1073 | 1150 |
[MTA ... MTA+127] = &mac_writereg, |
1074 | 1151 |
[VFTA ... VFTA+127] = &mac_writereg, |
... | ... | |
1150 | 1227 |
E1000State *s = opaque; |
1151 | 1228 |
NetClientState *nc = qemu_get_queue(s->nic); |
1152 | 1229 |
|
1230 |
/* If the mitigation timer is active, emulate a timeout now. */ |
|
1231 |
if (s->mit_timer_on) { |
|
1232 |
e1000_mit_timer(s); |
|
1233 |
} |
|
1234 |
|
|
1153 | 1235 |
if (!(s->compat_flags & E1000_FLAG_AUTONEG)) { |
1154 | 1236 |
return; |
1155 | 1237 |
} |
... | ... | |
1171 | 1253 |
E1000State *s = opaque; |
1172 | 1254 |
NetClientState *nc = qemu_get_queue(s->nic); |
1173 | 1255 |
|
1256 |
if (!(s->compat_flags & E1000_FLAG_MIT)) { |
|
1257 |
s->mac_reg[ITR] = s->mac_reg[RDTR] = s->mac_reg[RADV] = |
|
1258 |
s->mac_reg[TADV] = 0; |
|
1259 |
s->mit_irq_level = false; |
|
1260 |
} |
|
1261 |
s->mit_ide = 0; |
|
1262 |
s->mit_timer_on = false; |
|
1263 |
|
|
1174 | 1264 |
/* nc.link_down can't be migrated, so infer link_down according |
1175 | 1265 |
* to link status bit in mac_reg[STATUS]. |
1176 | 1266 |
* Alternatively, restart link negotiation if it was in progress. */ |
... | ... | |
1190 | 1280 |
return 0; |
1191 | 1281 |
} |
1192 | 1282 |
|
1283 |
static bool e1000_mit_state_needed(void *opaque) |
|
1284 |
{ |
|
1285 |
E1000State *s = opaque; |
|
1286 |
|
|
1287 |
return s->compat_flags & E1000_FLAG_MIT; |
|
1288 |
} |
|
1289 |
|
|
1290 |
static const VMStateDescription vmstate_e1000_mit_state = { |
|
1291 |
.name = "e1000/mit_state", |
|
1292 |
.version_id = 1, |
|
1293 |
.minimum_version_id = 1, |
|
1294 |
.minimum_version_id_old = 1, |
|
1295 |
.fields = (VMStateField[]) { |
|
1296 |
VMSTATE_UINT32(mac_reg[RDTR], E1000State), |
|
1297 |
VMSTATE_UINT32(mac_reg[RADV], E1000State), |
|
1298 |
VMSTATE_UINT32(mac_reg[TADV], E1000State), |
|
1299 |
VMSTATE_UINT32(mac_reg[ITR], E1000State), |
|
1300 |
VMSTATE_BOOL(mit_irq_level, E1000State), |
|
1301 |
VMSTATE_END_OF_LIST() |
|
1302 |
} |
|
1303 |
}; |
|
1304 |
|
|
1193 | 1305 |
static const VMStateDescription vmstate_e1000 = { |
1194 | 1306 |
.name = "e1000", |
1195 | 1307 |
.version_id = 2, |
... | ... | |
1267 | 1379 |
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128), |
1268 | 1380 |
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128), |
1269 | 1381 |
VMSTATE_END_OF_LIST() |
1382 |
}, |
|
1383 |
.subsections = (VMStateSubsection[]) { |
|
1384 |
{ |
|
1385 |
.vmsd = &vmstate_e1000_mit_state, |
|
1386 |
.needed = e1000_mit_state_needed, |
|
1387 |
}, { |
|
1388 |
/* empty */ |
|
1389 |
} |
|
1270 | 1390 |
} |
1271 | 1391 |
}; |
1272 | 1392 |
|
... | ... | |
1316 | 1436 |
|
1317 | 1437 |
timer_del(d->autoneg_timer); |
1318 | 1438 |
timer_free(d->autoneg_timer); |
1439 |
timer_del(d->mit_timer); |
|
1440 |
timer_free(d->mit_timer); |
|
1319 | 1441 |
memory_region_destroy(&d->mmio); |
1320 | 1442 |
memory_region_destroy(&d->io); |
1321 | 1443 |
qemu_del_nic(d->nic); |
... | ... | |
1371 | 1493 |
add_boot_device_path(d->conf.bootindex, dev, "/ethernet-phy@0"); |
1372 | 1494 |
|
1373 | 1495 |
d->autoneg_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, e1000_autoneg_timer, d); |
1496 |
d->mit_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000_mit_timer, d); |
|
1374 | 1497 |
|
1375 | 1498 |
return 0; |
1376 | 1499 |
} |
... | ... | |
1385 | 1508 |
DEFINE_NIC_PROPERTIES(E1000State, conf), |
1386 | 1509 |
DEFINE_PROP_BIT("autonegotiation", E1000State, |
1387 | 1510 |
compat_flags, E1000_FLAG_AUTONEG_BIT, true), |
1511 |
DEFINE_PROP_BIT("mitigation", E1000State, |
|
1512 |
compat_flags, E1000_FLAG_MIT_BIT, true), |
|
1388 | 1513 |
DEFINE_PROP_END_OF_LIST(), |
1389 | 1514 |
}; |
1390 | 1515 |
|
Also available in: Unified diff