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 |
|