-----BEGIN PGP SIGNATURE-----

Version: GnuPG v1
 
 iQEcBAABAgAGBQJkCvgFAAoJEO8Ells5jWIRHiUH/jhydpJHIqnAPxHQAwGtmyhb
 9Z52UOzW5V6KxfZJ+bQ4RPFkS2UwcxmeadPHY4zvvJTVBLAgG3QVgP4igj8CXKCI
 xRnwMgTNeu655kZQ5P/elTwdBTCJFODk7Egg/bH3H1ZiUhXBhVRhK7q/wMgtlZkZ
 Kexo6txCK4d941RNzEh45ZaGhdELE+B+D7cRuQgBs/DXZtJpsyEzBbP8KYSMHuER
 AXfWo0YIBYj7X3ek9D6j0pbOkB61vqtYd7W6xV4iDrJCcFBIOspJbbBb1tGCHola
 AXo5/OhRmiQnp/c/HTbJIDbrj0sq/r7LxYK4zY1x7UPbewHS9R+wz+FfqSmoBF0=
 =056y
 -----END PGP SIGNATURE-----

Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging

# -----BEGIN PGP SIGNATURE-----
# Version: GnuPG v1
#
# iQEcBAABAgAGBQJkCvgFAAoJEO8Ells5jWIRHiUH/jhydpJHIqnAPxHQAwGtmyhb
# 9Z52UOzW5V6KxfZJ+bQ4RPFkS2UwcxmeadPHY4zvvJTVBLAgG3QVgP4igj8CXKCI
# xRnwMgTNeu655kZQ5P/elTwdBTCJFODk7Egg/bH3H1ZiUhXBhVRhK7q/wMgtlZkZ
# Kexo6txCK4d941RNzEh45ZaGhdELE+B+D7cRuQgBs/DXZtJpsyEzBbP8KYSMHuER
# AXfWo0YIBYj7X3ek9D6j0pbOkB61vqtYd7W6xV4iDrJCcFBIOspJbbBb1tGCHola
# AXo5/OhRmiQnp/c/HTbJIDbrj0sq/r7LxYK4zY1x7UPbewHS9R+wz+FfqSmoBF0=
# =056y
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 10 Mar 2023 09:27:33 GMT
# gpg:                using RSA key EF04965B398D6211
# gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [marginal]
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 215D 46F4 8246 689E C77F  3562 EF04 965B 398D 6211

* tag 'net-pull-request' of https://github.com/jasowang/qemu: (44 commits)
  ebpf: fix compatibility with libbpf 1.0+
  docs/system/devices/igb: Add igb documentation
  tests/avocado: Add igb test
  igb: Introduce qtest for igb device
  tests/qtest/libqos/e1000e: Export macreg functions
  tests/qtest/e1000e-test: Fabricate ethernet header
  Intrdocue igb device emulation
  e1000: Split header files
  pcie: Introduce pcie_sriov_num_vfs
  net/eth: Introduce EthL4HdrProto
  e1000e: Implement system clock
  net/eth: Report if headers are actually present
  e1000e: Count CRC in Tx statistics
  e1000: Count CRC in Tx statistics
  e1000e: Combine rx traces
  MAINTAINERS: Add e1000e test files
  MAINTAINERS: Add Akihiko Odaki as a e1000e reviewer
  e1000e: Do not assert when MSI-X is disabled later
  hw/net/net_tx_pkt: Check the payload length
  hw/net/net_tx_pkt: Implement TCP segmentation
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2023-03-11 17:17:17 +00:00
commit 7284d53f6f
53 changed files with 9775 additions and 2307 deletions

View File

@ -2236,14 +2236,27 @@ F: docs/specs/rocker.txt
e1000x
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
R: Akihiko Odaki <akihiko.odaki@daynix.com>
S: Maintained
F: hw/net/e1000x*
e1000e
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
R: Akihiko Odaki <akihiko.odaki@daynix.com>
S: Maintained
F: hw/net/e1000e*
F: tests/qtest/fuzz-e1000e-test.c
F: tests/qtest/e1000e-test.c
F: tests/qtest/libqos/e1000e.*
igb
M: Akihiko Odaki <akihiko.odaki@daynix.com>
S: Maintained
F: docs/system/devices/igb.rst
F: hw/net/igb*
F: tests/avocado/igb.py
F: tests/qtest/igb-test.c
F: tests/qtest/libqos/igb.c
eepro100
M: Stefan Weil <sw@weilnetz.de>

View File

@ -93,3 +93,4 @@ Emulated Devices
devices/virtio-pmem.rst
devices/vhost-user-rng.rst
devices/canokey.rst
devices/igb.rst

View File

@ -0,0 +1,71 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
.. _igb:
igb
---
igb is a family of Intel's gigabit ethernet controllers. In QEMU, 82576
emulation is implemented in particular. Its datasheet is available at [1]_.
This implementation is expected to be useful to test SR-IOV networking without
requiring physical hardware.
Limitations
===========
This igb implementation was tested with Linux Test Project [2]_ and Windows HLK
[3]_ during the initial development. The command used when testing with LTP is:
.. code-block:: shell
network.sh -6mta
Be aware that this implementation lacks many functionalities available with the
actual hardware, and you may experience various failures if you try to use it
with a different operating system other than Linux and Windows or if you try
functionalities not covered by the tests.
Using igb
=========
Using igb should be nothing different from using another network device. See
:ref:`pcsys_005fnetwork` in general.
However, you may also need to perform additional steps to activate SR-IOV
feature on your guest. For Linux, refer to [4]_.
Developing igb
==============
igb is the successor of e1000e, and e1000e is the successor of e1000 in turn.
As these devices are very similar, if you make a change for igb and the same
change can be applied to e1000e and e1000, please do so.
Please do not forget to run tests before submitting a change. As tests included
in QEMU is very minimal, run some application which is likely to be affected by
the change to confirm it works in an integrated system.
Testing igb
===========
A qtest of the basic functionality is available. Run the below at the build
directory:
.. code-block:: shell
meson test qtest-x86_64/qos-test
ethtool can test register accesses, interrupts, etc. It is automated as an
Avocado test and can be ran with the following command:
.. code:: shell
make check-avocado AVOCADO_TESTS=tests/avocado/igb.py
References
==========
.. [1] https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eb-gigabit-ethernet-controller-datasheet.pdf
.. [2] https://github.com/linux-test-project/ltp
.. [3] https://learn.microsoft.com/en-us/windows-hardware/test/hlk/
.. [4] https://docs.kernel.org/PCI/pci-iov-howto.html

File diff suppressed because it is too large Load Diff

View File

@ -40,6 +40,7 @@
#include "hw/virtio/virtio-pci.h"
GlobalProperty hw_compat_7_2[] = {
{ "e1000e", "migrate-timadj", "off" },
{ "virtio-mem", "x-early-migration", "false" },
};
const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2);

View File

@ -44,6 +44,11 @@ config E1000E_PCI_EXPRESS
default y if PCI_DEVICES
depends on PCI_EXPRESS && MSI_NONBROKEN
config IGB_PCI_EXPRESS
bool
default y if PCI_DEVICES
depends on PCI_EXPRESS && MSI_NONBROKEN
config RTL8139_PCI
bool
default y if PCI_DEVICES

View File

@ -26,6 +26,7 @@
#include "qemu/osdep.h"
#include "hw/net/mii.h"
#include "hw/pci/pci_device.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
@ -38,12 +39,11 @@
#include "qemu/module.h"
#include "qemu/range.h"
#include "e1000_common.h"
#include "e1000x_common.h"
#include "trace.h"
#include "qom/object.h"
static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
/* #define E1000_DEBUG */
#ifdef E1000_DEBUG
@ -66,9 +66,8 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
#define IOPORT_SIZE 0x40
#define PNPMMIO_SIZE 0x20000
#define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */
#define MAXIMUM_ETHERNET_HDR_LEN (14+4)
#define MAXIMUM_ETHERNET_HDR_LEN (ETH_HLEN + 4)
/*
* HW models:
@ -181,67 +180,73 @@ e1000_autoneg_done(E1000State *s)
static bool
have_autoneg(E1000State *s)
{
return chkflag(AUTONEG) && (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN);
return chkflag(AUTONEG) && (s->phy_reg[MII_BMCR] & MII_BMCR_AUTOEN);
}
static void
set_phy_ctrl(E1000State *s, int index, uint16_t val)
{
/* bits 0-5 reserved; MII_CR_[RESTART_AUTO_NEG,RESET] are self clearing */
s->phy_reg[PHY_CTRL] = val & ~(0x3f |
MII_CR_RESET |
MII_CR_RESTART_AUTO_NEG);
/* bits 0-5 reserved; MII_BMCR_[ANRESTART,RESET] are self clearing */
s->phy_reg[MII_BMCR] = val & ~(0x3f |
MII_BMCR_RESET |
MII_BMCR_ANRESTART);
/*
* QEMU 1.3 does not support link auto-negotiation emulation, so if we
* migrate during auto negotiation, after migration the link will be
* down.
*/
if (have_autoneg(s) && (val & MII_CR_RESTART_AUTO_NEG)) {
if (have_autoneg(s) && (val & MII_BMCR_ANRESTART)) {
e1000x_restart_autoneg(s->mac_reg, s->phy_reg, s->autoneg_timer);
}
}
static void (*phyreg_writeops[])(E1000State *, int, uint16_t) = {
[PHY_CTRL] = set_phy_ctrl,
[MII_BMCR] = set_phy_ctrl,
};
enum { NPHYWRITEOPS = ARRAY_SIZE(phyreg_writeops) };
enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };
static const char phy_regcap[0x20] = {
[PHY_STATUS] = PHY_R, [M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,
[PHY_ID1] = PHY_R, [M88E1000_PHY_SPEC_CTRL] = PHY_RW,
[PHY_CTRL] = PHY_RW, [PHY_1000T_CTRL] = PHY_RW,
[PHY_LP_ABILITY] = PHY_R, [PHY_1000T_STATUS] = PHY_R,
[PHY_AUTONEG_ADV] = PHY_RW, [M88E1000_RX_ERR_CNTR] = PHY_R,
[PHY_ID2] = PHY_R, [M88E1000_PHY_SPEC_STATUS] = PHY_R,
[PHY_AUTONEG_EXP] = PHY_R,
[MII_BMSR] = PHY_R, [M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,
[MII_PHYID1] = PHY_R, [M88E1000_PHY_SPEC_CTRL] = PHY_RW,
[MII_BMCR] = PHY_RW, [MII_CTRL1000] = PHY_RW,
[MII_ANLPAR] = PHY_R, [MII_STAT1000] = PHY_R,
[MII_ANAR] = PHY_RW, [M88E1000_RX_ERR_CNTR] = PHY_R,
[MII_PHYID2] = PHY_R, [M88E1000_PHY_SPEC_STATUS] = PHY_R,
[MII_ANER] = PHY_R,
};
/* PHY_ID2 documented in 8254x_GBe_SDM.pdf, pp. 250 */
/* MII_PHYID2 documented in 8254x_GBe_SDM.pdf, pp. 250 */
static const uint16_t phy_reg_init[] = {
[PHY_CTRL] = MII_CR_SPEED_SELECT_MSB |
MII_CR_FULL_DUPLEX |
MII_CR_AUTO_NEG_EN,
[MII_BMCR] = MII_BMCR_SPEED1000 |
MII_BMCR_FD |
MII_BMCR_AUTOEN,
[PHY_STATUS] = MII_SR_EXTENDED_CAPS |
MII_SR_LINK_STATUS | /* link initially up */
MII_SR_AUTONEG_CAPS |
/* MII_SR_AUTONEG_COMPLETE: initially NOT completed */
MII_SR_PREAMBLE_SUPPRESS |
MII_SR_EXTENDED_STATUS |
MII_SR_10T_HD_CAPS |
MII_SR_10T_FD_CAPS |
MII_SR_100X_HD_CAPS |
MII_SR_100X_FD_CAPS,
[MII_BMSR] = MII_BMSR_EXTCAP |
MII_BMSR_LINK_ST | /* link initially up */
MII_BMSR_AUTONEG |
/* MII_BMSR_AN_COMP: initially NOT completed */
MII_BMSR_MFPS |
MII_BMSR_EXTSTAT |
MII_BMSR_10T_HD |
MII_BMSR_10T_FD |
MII_BMSR_100TX_HD |
MII_BMSR_100TX_FD,
[PHY_ID1] = 0x141,
/* [PHY_ID2] configured per DevId, from e1000_reset() */
[PHY_AUTONEG_ADV] = 0xde1,
[PHY_LP_ABILITY] = 0x1e0,
[PHY_1000T_CTRL] = 0x0e00,
[PHY_1000T_STATUS] = 0x3c00,
[MII_PHYID1] = 0x141,
/* [MII_PHYID2] configured per DevId, from e1000_reset() */
[MII_ANAR] = MII_ANAR_CSMACD | MII_ANAR_10 |
MII_ANAR_10FD | MII_ANAR_TX |
MII_ANAR_TXFD | MII_ANAR_PAUSE |
MII_ANAR_PAUSE_ASYM,
[MII_ANLPAR] = MII_ANLPAR_10 | MII_ANLPAR_10FD |
MII_ANLPAR_TX | MII_ANLPAR_TXFD,
[MII_CTRL1000] = MII_CTRL1000_FULL | MII_CTRL1000_PORT |
MII_CTRL1000_MASTER,
[MII_STAT1000] = MII_STAT1000_HALF | MII_STAT1000_FULL |
MII_STAT1000_ROK | MII_STAT1000_LOK,
[M88E1000_PHY_SPEC_CTRL] = 0x360,
[M88E1000_PHY_SPEC_STATUS] = 0xac00,
[M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,
@ -373,9 +378,9 @@ static bool e1000_vet_init_need(void *opaque)
return chkflag(VET);
}
static void e1000_reset(void *opaque)
static void e1000_reset_hold(Object *obj)
{
E1000State *d = opaque;
E1000State *d = E1000(obj);
E1000BaseClass *edc = E1000_GET_CLASS(d);
uint8_t *macaddr = d->conf.macaddr.a;
@ -386,10 +391,10 @@ static void e1000_reset(void *opaque)
d->mit_irq_level = 0;
d->mit_ide = 0;
memset(d->phy_reg, 0, sizeof d->phy_reg);
memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
d->phy_reg[PHY_ID2] = edc->phy_id2;
memcpy(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
d->phy_reg[MII_PHYID2] = edc->phy_id2;
memset(d->mac_reg, 0, sizeof d->mac_reg);
memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
memcpy(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
d->rxbuf_min_shift = 1;
memset(&d->tx, 0, sizeof d->tx);
@ -547,9 +552,9 @@ putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
static inline void
inc_tx_bcast_or_mcast_count(E1000State *s, const unsigned char *arr)
{
if (!memcmp(arr, bcast, sizeof bcast)) {
if (is_broadcast_ether_addr(arr)) {
e1000x_inc_reg_if_not_full(s->mac_reg, BPTC);
} else if (arr[0] & 1) {
} else if (is_multicast_ether_addr(arr)) {
e1000x_inc_reg_if_not_full(s->mac_reg, MPTC);
}
}
@ -561,13 +566,13 @@ e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
PTC1023, PTC1522 };
NetClientState *nc = qemu_get_queue(s->nic);
if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) {
if (s->phy_reg[MII_BMCR] & MII_BMCR_LOOPBACK) {
qemu_receive_packet(nc, buf, size);
} else {
qemu_send_packet(nc, buf, size);
}
inc_tx_bcast_or_mcast_count(s, buf);
e1000x_increase_size_stats(s->mac_reg, PTCregs, size);
e1000x_increase_size_stats(s->mac_reg, PTCregs, size + 4);
}
static void
@ -631,7 +636,7 @@ xmit_seg(E1000State *s)
}
e1000x_inc_reg_if_not_full(s->mac_reg, TPT);
e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size);
e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size + 4);
s->mac_reg[GPTC] = s->mac_reg[TPT];
s->mac_reg[GOTCL] = s->mac_reg[TOTL];
s->mac_reg[GOTCH] = s->mac_reg[TOTH];
@ -803,15 +808,18 @@ static int
receive_filter(E1000State *s, const uint8_t *buf, int size)
{
uint32_t rctl = s->mac_reg[RCTL];
int isbcast = !memcmp(buf, bcast, sizeof bcast), ismcast = (buf[0] & 1);
int isbcast = is_broadcast_ether_addr(buf);
int ismcast = is_multicast_ether_addr(buf);
if (e1000x_is_vlan_packet(buf, le16_to_cpu(s->mac_reg[VET])) &&
e1000x_vlan_rx_filter_enabled(s->mac_reg)) {
uint16_t vid = lduw_be_p(buf + 14);
uint32_t vfta = ldl_le_p((uint32_t*)(s->mac_reg + VFTA) +
((vid >> 5) & 0x7f));
if ((vfta & (1 << (vid & 0x1f))) == 0)
uint16_t vid = lduw_be_p(&PKT_GET_VLAN_HDR(buf)->h_tci);
uint32_t vfta =
ldl_le_p((uint32_t *)(s->mac_reg + VFTA) +
((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
return 0;
}
}
if (!isbcast && !ismcast && (rctl & E1000_RCTL_UPE)) { /* promiscuous ucast */
@ -841,7 +849,7 @@ e1000_set_link_status(NetClientState *nc)
e1000x_update_regs_on_link_down(s->mac_reg, s->phy_reg);
} else {
if (have_autoneg(s) &&
!(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
!(s->phy_reg[MII_BMSR] & MII_BMSR_AN_COMP)) {
e1000x_restart_autoneg(s->mac_reg, s->phy_reg, s->autoneg_timer);
} else {
e1000_link_up(s);
@ -907,7 +915,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
uint32_t rdh_start;
uint16_t vlan_special = 0;
uint8_t vlan_status = 0;
uint8_t min_buf[MIN_BUF_SIZE];
uint8_t min_buf[ETH_ZLEN];
struct iovec min_iov;
uint8_t *filter_buf = iov->iov_base;
size_t size = iov_size(iov, iovcnt);
@ -1060,30 +1068,6 @@ mac_readreg(E1000State *s, int index)
return s->mac_reg[index];
}
static uint32_t
mac_low4_read(E1000State *s, int index)
{
return s->mac_reg[index] & 0xf;
}
static uint32_t
mac_low11_read(E1000State *s, int index)
{
return s->mac_reg[index] & 0x7ff;
}
static uint32_t
mac_low13_read(E1000State *s, int index)
{
return s->mac_reg[index] & 0x1fff;
}
static uint32_t
mac_low16_read(E1000State *s, int index)
{
return s->mac_reg[index] & 0xffff;
}
static uint32_t
mac_icr_read(E1000State *s, int index)
{
@ -1136,11 +1120,17 @@ set_rdt(E1000State *s, int index, uint32_t val)
}
}
static void
set_16bit(E1000State *s, int index, uint32_t val)
{
s->mac_reg[index] = val & 0xffff;
}
#define LOW_BITS_SET_FUNC(num) \
static void \
set_##num##bit(E1000State *s, int index, uint32_t val) \
{ \
s->mac_reg[index] = val & (BIT(num) - 1); \
}
LOW_BITS_SET_FUNC(4)
LOW_BITS_SET_FUNC(11)
LOW_BITS_SET_FUNC(13)
LOW_BITS_SET_FUNC(16)
static void
set_dlen(E1000State *s, int index, uint32_t val)
@ -1194,7 +1184,9 @@ static const readops macreg_readops[] = {
getreg(XONRXC), getreg(XONTXC), getreg(XOFFRXC), getreg(XOFFTXC),
getreg(RFC), getreg(RJC), getreg(RNBC), getreg(TSCTFC),
getreg(MGTPRC), getreg(MGTPDC), getreg(MGTPTC), getreg(GORCL),
getreg(GOTCL),
getreg(GOTCL), getreg(RDFH), getreg(RDFT), getreg(RDFHS),
getreg(RDFTS), getreg(RDFPC), getreg(TDFH), getreg(TDFT),
getreg(TDFHS), getreg(TDFTS), getreg(TDFPC), getreg(AIT),
[TOTH] = mac_read_clr8, [TORH] = mac_read_clr8,
[GOTCH] = mac_read_clr8, [GORCH] = mac_read_clr8,
@ -1212,24 +1204,17 @@ static const readops macreg_readops[] = {
[MPTC] = mac_read_clr4,
[ICR] = mac_icr_read, [EECD] = get_eecd,
[EERD] = flash_eerd_read,
[RDFH] = mac_low13_read, [RDFT] = mac_low13_read,
[RDFHS] = mac_low13_read, [RDFTS] = mac_low13_read,
[RDFPC] = mac_low13_read,
[TDFH] = mac_low11_read, [TDFT] = mac_low11_read,
[TDFHS] = mac_low13_read, [TDFTS] = mac_low13_read,
[TDFPC] = mac_low13_read,
[AIT] = mac_low16_read,
[CRCERRS ... MPC] = &mac_readreg,
[IP6AT ... IP6AT+3] = &mac_readreg, [IP4AT ... IP4AT+6] = &mac_readreg,
[FFLT ... FFLT+6] = &mac_low11_read,
[RA ... RA+31] = &mac_readreg,
[WUPM ... WUPM+31] = &mac_readreg,
[MTA ... MTA+127] = &mac_readreg,
[VFTA ... VFTA+127] = &mac_readreg,
[FFMT ... FFMT+254] = &mac_low4_read,
[FFVT ... FFVT+254] = &mac_readreg,
[PBM ... PBM+16383] = &mac_readreg,
[CRCERRS ... MPC] = &mac_readreg,
[IP6AT ... IP6AT + 3] = &mac_readreg, [IP4AT ... IP4AT + 6] = &mac_readreg,
[FFLT ... FFLT + 6] = &mac_readreg,
[RA ... RA + 31] = &mac_readreg,
[WUPM ... WUPM + 31] = &mac_readreg,
[MTA ... MTA + E1000_MC_TBL_SIZE - 1] = &mac_readreg,
[VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1] = &mac_readreg,
[FFMT ... FFMT + 254] = &mac_readreg,
[FFVT ... FFVT + 254] = &mac_readreg,
[PBM ... PBM + 16383] = &mac_readreg,
};
enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
@ -1239,27 +1224,28 @@ static const writeops macreg_writeops[] = {
putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC),
putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH),
putreg(RDBAL), putreg(LEDCTL), putreg(VET), putreg(FCRUC),
putreg(TDFH), putreg(TDFT), putreg(TDFHS), putreg(TDFTS),
putreg(TDFPC), putreg(RDFH), putreg(RDFT), putreg(RDFHS),
putreg(RDFTS), putreg(RDFPC), putreg(IPAV), putreg(WUC),
putreg(WUS), putreg(AIT),
putreg(IPAV), putreg(WUC),
putreg(WUS),
[TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl,
[TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics,
[TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt,
[IMC] = set_imc, [IMS] = set_ims, [ICR] = set_icr,
[EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl,
[RDTR] = set_16bit, [RADV] = set_16bit, [TADV] = set_16bit,
[ITR] = set_16bit,
[TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl,
[TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics,
[TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt,
[IMC] = set_imc, [IMS] = set_ims, [ICR] = set_icr,
[EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl,
[RDTR] = set_16bit, [RADV] = set_16bit, [TADV] = set_16bit,
[ITR] = set_16bit, [TDFH] = set_11bit, [TDFT] = set_11bit,
[TDFHS] = set_13bit, [TDFTS] = set_13bit, [TDFPC] = set_13bit,
[RDFH] = set_13bit, [RDFT] = set_13bit, [RDFHS] = set_13bit,
[RDFTS] = set_13bit, [RDFPC] = set_13bit, [AIT] = set_16bit,
[IP6AT ... IP6AT+3] = &mac_writereg, [IP4AT ... IP4AT+6] = &mac_writereg,
[FFLT ... FFLT+6] = &mac_writereg,
[RA ... RA+31] = &mac_writereg,
[WUPM ... WUPM+31] = &mac_writereg,
[MTA ... MTA+127] = &mac_writereg,
[VFTA ... VFTA+127] = &mac_writereg,
[FFMT ... FFMT+254] = &mac_writereg, [FFVT ... FFVT+254] = &mac_writereg,
[PBM ... PBM+16383] = &mac_writereg,
[IP6AT ... IP6AT + 3] = &mac_writereg, [IP4AT ... IP4AT + 6] = &mac_writereg,
[FFLT ... FFLT + 6] = &set_11bit,
[RA ... RA + 31] = &mac_writereg,
[WUPM ... WUPM + 31] = &mac_writereg,
[MTA ... MTA + E1000_MC_TBL_SIZE - 1] = &mac_writereg,
[VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1] = &mac_writereg,
[FFMT ... FFMT + 254] = &set_4bit, [FFVT ... FFVT + 254] = &mac_writereg,
[PBM ... PBM + 16383] = &mac_writereg,
};
enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
@ -1415,10 +1401,10 @@ static int e1000_pre_save(void *opaque)
/*
* If link is down and auto-negotiation is supported and ongoing,
* complete auto-negotiation immediately. This allows us to look
* at MII_SR_AUTONEG_COMPLETE to infer link status on load.
* at MII_BMSR_AN_COMP to infer link status on load.
*/
if (nc->link_down && have_autoneg(s)) {
s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
s->phy_reg[MII_BMSR] |= MII_BMSR_AN_COMP;
}
/* Decide which set of props to migrate in the main structure */
@ -1457,8 +1443,7 @@ static int e1000_post_load(void *opaque, int version_id)
* Alternatively, restart link negotiation if it was in progress. */
nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
if (have_autoneg(s) &&
!(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
if (have_autoneg(s) && !(s->phy_reg[MII_BMSR] & MII_BMSR_AN_COMP)) {
nc->link_down = false;
timer_mod(s->autoneg_timer,
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
@ -1624,8 +1609,9 @@ static const VMStateDescription vmstate_e1000 = {
VMSTATE_UINT32(mac_reg[WUFC], E1000State),
VMSTATE_UINT32(mac_reg[VET], E1000State),
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, E1000_MC_TBL_SIZE),
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA,
E1000_VLAN_FILTER_TBL_SIZE),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
@ -1746,12 +1732,6 @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp)
e1000_flush_queue_timer, d);
}
static void qdev_e1000_reset(DeviceState *dev)
{
E1000State *d = E1000(dev);
e1000_reset(d);
}
static Property e1000_properties[] = {
DEFINE_NIC_PROPERTIES(E1000State, conf),
DEFINE_PROP_BIT("autonegotiation", E1000State,
@ -1777,6 +1757,7 @@ typedef struct E1000Info {
static void e1000_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
E1000BaseClass *e = E1000_CLASS(klass);
const E1000Info *info = data;
@ -1789,9 +1770,9 @@ static void e1000_class_init(ObjectClass *klass, void *data)
k->revision = info->revision;
e->phy_id2 = info->phy_id2;
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
rc->phases.hold = e1000_reset_hold;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "Intel Gigabit Ethernet";
dc->reset = qdev_e1000_reset;
dc->vmsd = &vmstate_e1000;
device_class_set_props(dc, e1000_properties);
}

102
hw/net/e1000_common.h Normal file
View File

@ -0,0 +1,102 @@
/*
* QEMU e1000(e) emulation - shared definitions
*
* Copyright (c) 2008 Qumranet
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HW_NET_E1000_COMMON_H
#define HW_NET_E1000_COMMON_H
#include "e1000_regs.h"
#define defreg(x) x = (E1000_##x >> 2)
enum {
defreg(CTRL), defreg(EECD), defreg(EERD), defreg(GPRC),
defreg(GPTC), defreg(ICR), defreg(ICS), defreg(IMC),
defreg(IMS), defreg(LEDCTL), defreg(MANC), defreg(MDIC),
defreg(MPC), defreg(PBA), defreg(RCTL), defreg(RDBAH0),
defreg(RDBAL0), defreg(RDH0), defreg(RDLEN0), defreg(RDT0),
defreg(STATUS), defreg(SWSM), defreg(TCTL), defreg(TDBAH),
defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT),
defreg(TDLEN1), defreg(TDBAL1), defreg(TDBAH1), defreg(TDH1),
defreg(TDT1), defreg(TORH), defreg(TORL), defreg(TOTH),
defreg(TOTL), defreg(TPR), defreg(TPT), defreg(TXDCTL),
defreg(WUFC), defreg(RA), defreg(MTA), defreg(CRCERRS),
defreg(VFTA), defreg(VET), defreg(RDTR), defreg(RADV),
defreg(TADV), defreg(ITR), defreg(SCC), defreg(ECOL),
defreg(MCC), defreg(LATECOL), defreg(COLC), defreg(DC),
defreg(TNCRS), defreg(SEQEC), defreg(CEXTERR), defreg(RLEC),
defreg(XONRXC), defreg(XONTXC), defreg(XOFFRXC), defreg(XOFFTXC),
defreg(FCRUC), defreg(AIT), defreg(TDFH), defreg(TDFT),
defreg(TDFHS), defreg(TDFTS), defreg(TDFPC), defreg(WUC),
defreg(WUS), defreg(POEMB), defreg(PBS), defreg(RDFH),
defreg(RDFT), defreg(RDFHS), defreg(RDFTS), defreg(RDFPC),
defreg(PBM), defreg(IPAV), defreg(IP4AT), defreg(IP6AT),
defreg(WUPM), defreg(FFLT), defreg(FFMT), defreg(FFVT),
defreg(TARC0), defreg(TARC1), defreg(IAM), defreg(EXTCNF_CTRL),
defreg(GCR), defreg(TIMINCA), defreg(EIAC), defreg(CTRL_EXT),
defreg(IVAR), defreg(MFUTP01), defreg(MFUTP23), defreg(MANC2H),
defreg(MFVAL), defreg(MDEF), defreg(FACTPS), defreg(FTFT),
defreg(RUC), defreg(ROC), defreg(RFC), defreg(RJC),
defreg(PRC64), defreg(PRC127), defreg(PRC255), defreg(PRC511),
defreg(PRC1023), defreg(PRC1522), defreg(PTC64), defreg(PTC127),
defreg(PTC255), defreg(PTC511), defreg(PTC1023), defreg(PTC1522),
defreg(GORCL), defreg(GORCH), defreg(GOTCL), defreg(GOTCH),
defreg(RNBC), defreg(BPRC), defreg(MPRC), defreg(RFCTL),
defreg(PSRCTL), defreg(MPTC), defreg(BPTC), defreg(TSCTFC),
defreg(IAC), defreg(MGTPRC), defreg(MGTPDC), defreg(MGTPTC),
defreg(TSCTC), defreg(RXCSUM), defreg(FUNCTAG), defreg(GSCL_1),
defreg(GSCL_2), defreg(GSCL_3), defreg(GSCL_4), defreg(GSCN_0),
defreg(GSCN_1), defreg(GSCN_2), defreg(GSCN_3), defreg(GCR2),
defreg(RAID), defreg(RSRPD), defreg(TIDV), defreg(EITR),
defreg(MRQC), defreg(RETA), defreg(RSSRK), defreg(RDBAH1),
defreg(RDBAL1), defreg(RDLEN1), defreg(RDH1), defreg(RDT1),
defreg(PBACLR), defreg(FCAL), defreg(FCAH), defreg(FCT),
defreg(FCRTH), defreg(FCRTL), defreg(FCTTV), defreg(FCRTV),
defreg(FLA), defreg(EEWR), defreg(FLOP), defreg(FLOL),
defreg(FLSWCTL), defreg(FLSWCNT), defreg(RXDCTL), defreg(RXDCTL1),
defreg(MAVTV0), defreg(MAVTV1), defreg(MAVTV2), defreg(MAVTV3),
defreg(TXSTMPL), defreg(TXSTMPH), defreg(SYSTIML), defreg(SYSTIMH),
defreg(RXCFGL), defreg(RXUDP), defreg(TIMADJL), defreg(TIMADJH),
defreg(RXSTMPH), defreg(RXSTMPL), defreg(RXSATRL), defreg(RXSATRH),
defreg(FLASHT), defreg(TIPG), defreg(RDH), defreg(RDT),
defreg(RDLEN), defreg(RDBAH), defreg(RDBAL),
defreg(TXDCTL1),
defreg(FLSWDATA),
defreg(CTRL_DUP),
defreg(EXTCNF_SIZE),
defreg(EEMNGCTL),
defreg(EEMNGDATA),
defreg(FLMNGCTL),
defreg(FLMNGDATA),
defreg(FLMNGCNT),
defreg(TSYNCRXCTL),
defreg(TSYNCTXCTL),
/* Aliases */
defreg(RDH0_A), defreg(RDT0_A), defreg(RDTR_A), defreg(RDFH_A),
defreg(RDFT_A), defreg(TDH_A), defreg(TDT_A), defreg(TIDV_A),
defreg(TDFH_A), defreg(TDFT_A), defreg(RA_A), defreg(RDBAL0_A),
defreg(TDBAL_A), defreg(TDLEN_A), defreg(VFTA_A), defreg(RDLEN0_A),
defreg(FCRTL_A), defreg(FCRTH_A)
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +1,37 @@
/*
* QEMU INTEL 82574 GbE NIC emulation
*
* Software developer's manuals:
* http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
*
* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
* Developed by Daynix Computing LTD (http://www.daynix.com)
*
* Authors:
* Dmitry Fleytman <dmitry@daynix.com>
* Leonid Bloch <leonid@daynix.com>
* Yan Vugenfirer <yan@daynix.com>
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2008 Qumranet
* Based on work done by:
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
* QEMU INTEL 82574 GbE NIC emulation
*
* Software developer's manuals:
* http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
*
* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
* Developed by Daynix Computing LTD (http://www.daynix.com)
*
* Authors:
* Dmitry Fleytman <dmitry@daynix.com>
* Leonid Bloch <leonid@daynix.com>
* Yan Vugenfirer <yan@daynix.com>
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2008 Qumranet
* Based on work done by:
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
@ -42,13 +42,13 @@
#include "qemu/range.h"
#include "sysemu/sysemu.h"
#include "hw/hw.h"
#include "hw/net/mii.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "e1000_regs.h"
#include "e1000_common.h"
#include "e1000x_common.h"
#include "e1000e_core.h"
@ -81,6 +81,7 @@ struct E1000EState {
E1000ECore core;
bool init_vet;
bool timadj;
};
#define E1000E_MMIO_IDX 0
@ -239,9 +240,9 @@ static NetClientInfo net_e1000e_info = {
};
/*
* EEPROM (NVM) contents documented in Table 36, section 6.1
* and generally 6.1.2 Software accessed words.
*/
* EEPROM (NVM) contents documented in Table 36, section 6.1
* and generally 6.1.2 Software accessed words.
*/
static const uint16_t e1000e_eeprom_template[64] = {
/* Address | Compat. | ImVer | Compat. */
0x0000, 0x0000, 0x0000, 0x0420, 0xf746, 0x2010, 0xffff, 0xffff,
@ -512,11 +513,11 @@ static void e1000e_pci_uninit(PCIDevice *pci_dev)
msi_uninit(pci_dev);
}
static void e1000e_qdev_reset(DeviceState *dev)
static void e1000e_qdev_reset_hold(Object *obj)
{
E1000EState *s = E1000E(dev);
E1000EState *s = E1000E(obj);
trace_e1000e_cb_qdev_reset();
trace_e1000e_cb_qdev_reset_hold();
e1000e_core_reset(&s->core);
@ -553,6 +554,12 @@ static int e1000e_post_load(void *opaque, int version_id)
return e1000e_core_post_load(&s->core);
}
static bool e1000e_migrate_timadj(void *opaque, int version_id)
{
E1000EState *s = opaque;
return s->timadj;
}
static const VMStateDescription e1000e_vmstate_tx = {
.name = "e1000e-tx",
.version_id = 1,
@ -630,12 +637,11 @@ static const VMStateDescription e1000e_vmstate = {
VMSTATE_E1000E_INTR_DELAY_TIMER(core.tidv, E1000EState),
VMSTATE_E1000E_INTR_DELAY_TIMER(core.itr, E1000EState),
VMSTATE_BOOL(core.itr_intr_pending, E1000EState),
VMSTATE_UNUSED(1),
VMSTATE_E1000E_INTR_DELAY_TIMER_ARRAY(core.eitr, E1000EState,
E1000E_MSIX_VEC_NUM),
VMSTATE_BOOL_ARRAY(core.eitr_intr_pending, E1000EState,
E1000E_MSIX_VEC_NUM),
VMSTATE_UNUSED(E1000E_MSIX_VEC_NUM),
VMSTATE_UINT32(core.itr_guest_value, E1000EState),
VMSTATE_UINT32_ARRAY(core.eitr_guest_value, E1000EState,
@ -645,6 +651,9 @@ static const VMStateDescription e1000e_vmstate = {
VMSTATE_STRUCT_ARRAY(core.tx, E1000EState, E1000E_NUM_QUEUES, 0,
e1000e_vmstate_tx, struct e1000e_tx),
VMSTATE_INT64_TEST(core.timadj, E1000EState, e1000e_migrate_timadj),
VMSTATE_END_OF_LIST()
}
};
@ -663,12 +672,14 @@ static Property e1000e_properties[] = {
DEFINE_PROP_SIGNED("subsys", E1000EState, subsys, 0,
e1000e_prop_subsys, uint16_t),
DEFINE_PROP_BOOL("init-vet", E1000EState, init_vet, true),
DEFINE_PROP_BOOL("migrate-timadj", E1000EState, timadj, true),
DEFINE_PROP_END_OF_LIST(),
};
static void e1000e_class_init(ObjectClass *class, void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
ResettableClass *rc = RESETTABLE_CLASS(class);
PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
c->realize = e1000e_pci_realize;
@ -679,8 +690,9 @@ static void e1000e_class_init(ObjectClass *class, void *data)
c->romfile = "efi-e1000e.rom";
c->class_id = PCI_CLASS_NETWORK_ETHERNET;
rc->phases.hold = e1000e_qdev_reset_hold;
dc->desc = "Intel 82574L GbE Controller";
dc->reset = e1000e_qdev_reset;
dc->vmsd = &e1000e_vmstate;
e1000e_prop_disable_vnet = qdev_prop_uint8;

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +1,37 @@
/*
* Core code for QEMU e1000e emulation
*
* Software developer's manuals:
* http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
*
* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
* Developed by Daynix Computing LTD (http://www.daynix.com)
*
* Authors:
* Dmitry Fleytman <dmitry@daynix.com>
* Leonid Bloch <leonid@daynix.com>
* Yan Vugenfirer <yan@daynix.com>
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2008 Qumranet
* Based on work done by:
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
* Core code for QEMU e1000e emulation
*
* Software developer's manuals:
* http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
*
* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
* Developed by Daynix Computing LTD (http://www.daynix.com)
*
* Authors:
* Dmitry Fleytman <dmitry@daynix.com>
* Leonid Bloch <leonid@daynix.com>
* Yan Vugenfirer <yan@daynix.com>
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2008 Qumranet
* Based on work done by:
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HW_NET_E1000E_CORE_H
#define HW_NET_E1000E_CORE_H
@ -95,10 +95,8 @@ struct E1000Core {
E1000IntrDelayTimer tidv;
E1000IntrDelayTimer itr;
bool itr_intr_pending;
E1000IntrDelayTimer eitr[E1000E_MSIX_VEC_NUM];
bool eitr_intr_pending[E1000E_MSIX_VEC_NUM];
VMChangeStateEntry *vmstate;
@ -114,6 +112,8 @@ struct E1000Core {
void (*owner_start_recv)(PCIDevice *d);
uint32_t msi_causes_pending;
int64_t timadj;
};
void

View File

@ -24,9 +24,12 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "hw/net/mii.h"
#include "hw/pci/pci_device.h"
#include "net/eth.h"
#include "net/net.h"
#include "e1000_common.h"
#include "e1000x_common.h"
#include "trace.h"
@ -45,9 +48,9 @@ bool e1000x_rx_ready(PCIDevice *d, uint32_t *mac)
return true;
}
bool e1000x_is_vlan_packet(const uint8_t *buf, uint16_t vet)
bool e1000x_is_vlan_packet(const void *buf, uint16_t vet)
{
uint16_t eth_proto = lduw_be_p(buf + 12);
uint16_t eth_proto = lduw_be_p(&PKT_GET_ETH_HDR(buf)->h_proto);
bool res = (eth_proto == vet);
trace_e1000x_vlan_is_vlan_pkt(res, eth_proto, vet);
@ -66,7 +69,7 @@ bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf)
}
ra[0] = cpu_to_le32(rp[0]);
ra[1] = cpu_to_le32(rp[1]);
if (!memcmp(buf, (uint8_t *)ra, 6)) {
if (!memcmp(buf, (uint8_t *)ra, ETH_ALEN)) {
trace_e1000x_rx_flt_ucast_match((int)(rp - mac - RA) / 2,
MAC_ARG(buf));
return true;
@ -152,8 +155,8 @@ void e1000x_reset_mac_addr(NICState *nic, uint32_t *mac_regs,
void e1000x_update_regs_on_autoneg_done(uint32_t *mac, uint16_t *phy)
{
e1000x_update_regs_on_link_up(mac, phy);
phy[PHY_LP_ABILITY] |= MII_LPAR_LPACK;
phy[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
phy[MII_ANLPAR] |= MII_ANLPAR_ACK;
phy[MII_BMSR] |= MII_BMSR_AN_COMP;
trace_e1000x_link_negotiation_done();
}
@ -265,3 +268,28 @@ e1000x_read_tx_ctx_descr(struct e1000_context_desc *d,
props->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
props->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
}
void e1000x_timestamp(uint32_t *mac, int64_t timadj, size_t lo, size_t hi)
{
int64_t ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint32_t timinca = mac[TIMINCA];
uint32_t incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK;
uint32_t incperiod = MAX(timinca >> E1000_TIMINCA_INCPERIOD_SHIFT, 1);
int64_t timestamp = timadj + muldiv64(ns, incvalue, incperiod * 16);
mac[lo] = timestamp & 0xffffffff;
mac[hi] = timestamp >> 32;
}
void e1000x_set_timinca(uint32_t *mac, int64_t *timadj, uint32_t val)
{
int64_t ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint32_t old_val = mac[TIMINCA];
uint32_t old_incvalue = old_val & E1000_TIMINCA_INCVALUE_MASK;
uint32_t old_incperiod = MAX(old_val >> E1000_TIMINCA_INCPERIOD_SHIFT, 1);
uint32_t incvalue = val & E1000_TIMINCA_INCVALUE_MASK;
uint32_t incperiod = MAX(val >> E1000_TIMINCA_INCPERIOD_SHIFT, 1);
mac[TIMINCA] = val;
*timadj += (muldiv64(ns, incvalue, incperiod) - muldiv64(ns, old_incvalue, old_incperiod)) / 16;
}

View File

@ -1,108 +1,34 @@
/*
* QEMU e1000(e) emulation - shared code
*
* Copyright (c) 2008 Qumranet
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
* QEMU e1000(e) emulation - shared code
*
* Copyright (c) 2008 Qumranet
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HW_NET_E1000X_COMMON_H
#define HW_NET_E1000X_COMMON_H
#include "e1000_regs.h"
#define defreg(x) x = (E1000_##x >> 2)
enum {
defreg(CTRL), defreg(EECD), defreg(EERD), defreg(GPRC),
defreg(GPTC), defreg(ICR), defreg(ICS), defreg(IMC),
defreg(IMS), defreg(LEDCTL), defreg(MANC), defreg(MDIC),
defreg(MPC), defreg(PBA), defreg(RCTL), defreg(RDBAH0),
defreg(RDBAL0), defreg(RDH0), defreg(RDLEN0), defreg(RDT0),
defreg(STATUS), defreg(SWSM), defreg(TCTL), defreg(TDBAH),
defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT),
defreg(TDLEN1), defreg(TDBAL1), defreg(TDBAH1), defreg(TDH1),
defreg(TDT1), defreg(TORH), defreg(TORL), defreg(TOTH),
defreg(TOTL), defreg(TPR), defreg(TPT), defreg(TXDCTL),
defreg(WUFC), defreg(RA), defreg(MTA), defreg(CRCERRS),
defreg(VFTA), defreg(VET), defreg(RDTR), defreg(RADV),
defreg(TADV), defreg(ITR), defreg(SCC), defreg(ECOL),
defreg(MCC), defreg(LATECOL), defreg(COLC), defreg(DC),
defreg(TNCRS), defreg(SEQEC), defreg(CEXTERR), defreg(RLEC),
defreg(XONRXC), defreg(XONTXC), defreg(XOFFRXC), defreg(XOFFTXC),
defreg(FCRUC), defreg(AIT), defreg(TDFH), defreg(TDFT),
defreg(TDFHS), defreg(TDFTS), defreg(TDFPC), defreg(WUC),
defreg(WUS), defreg(POEMB), defreg(PBS), defreg(RDFH),
defreg(RDFT), defreg(RDFHS), defreg(RDFTS), defreg(RDFPC),
defreg(PBM), defreg(IPAV), defreg(IP4AT), defreg(IP6AT),
defreg(WUPM), defreg(FFLT), defreg(FFMT), defreg(FFVT),
defreg(TARC0), defreg(TARC1), defreg(IAM), defreg(EXTCNF_CTRL),
defreg(GCR), defreg(TIMINCA), defreg(EIAC), defreg(CTRL_EXT),
defreg(IVAR), defreg(MFUTP01), defreg(MFUTP23), defreg(MANC2H),
defreg(MFVAL), defreg(MDEF), defreg(FACTPS), defreg(FTFT),
defreg(RUC), defreg(ROC), defreg(RFC), defreg(RJC),
defreg(PRC64), defreg(PRC127), defreg(PRC255), defreg(PRC511),
defreg(PRC1023), defreg(PRC1522), defreg(PTC64), defreg(PTC127),
defreg(PTC255), defreg(PTC511), defreg(PTC1023), defreg(PTC1522),
defreg(GORCL), defreg(GORCH), defreg(GOTCL), defreg(GOTCH),
defreg(RNBC), defreg(BPRC), defreg(MPRC), defreg(RFCTL),
defreg(PSRCTL), defreg(MPTC), defreg(BPTC), defreg(TSCTFC),
defreg(IAC), defreg(MGTPRC), defreg(MGTPDC), defreg(MGTPTC),
defreg(TSCTC), defreg(RXCSUM), defreg(FUNCTAG), defreg(GSCL_1),
defreg(GSCL_2), defreg(GSCL_3), defreg(GSCL_4), defreg(GSCN_0),
defreg(GSCN_1), defreg(GSCN_2), defreg(GSCN_3), defreg(GCR2),
defreg(RAID), defreg(RSRPD), defreg(TIDV), defreg(EITR),
defreg(MRQC), defreg(RETA), defreg(RSSRK), defreg(RDBAH1),
defreg(RDBAL1), defreg(RDLEN1), defreg(RDH1), defreg(RDT1),
defreg(PBACLR), defreg(FCAL), defreg(FCAH), defreg(FCT),
defreg(FCRTH), defreg(FCRTL), defreg(FCTTV), defreg(FCRTV),
defreg(FLA), defreg(EEWR), defreg(FLOP), defreg(FLOL),
defreg(FLSWCTL), defreg(FLSWCNT), defreg(RXDCTL), defreg(RXDCTL1),
defreg(MAVTV0), defreg(MAVTV1), defreg(MAVTV2), defreg(MAVTV3),
defreg(TXSTMPL), defreg(TXSTMPH), defreg(SYSTIML), defreg(SYSTIMH),
defreg(RXCFGL), defreg(RXUDP), defreg(TIMADJL), defreg(TIMADJH),
defreg(RXSTMPH), defreg(RXSTMPL), defreg(RXSATRL), defreg(RXSATRH),
defreg(FLASHT), defreg(TIPG), defreg(RDH), defreg(RDT),
defreg(RDLEN), defreg(RDBAH), defreg(RDBAL),
defreg(TXDCTL1),
defreg(FLSWDATA),
defreg(CTRL_DUP),
defreg(EXTCNF_SIZE),
defreg(EEMNGCTL),
defreg(EEMNGDATA),
defreg(FLMNGCTL),
defreg(FLMNGDATA),
defreg(FLMNGCNT),
defreg(TSYNCRXCTL),
defreg(TSYNCTXCTL),
/* Aliases */
defreg(RDH0_A), defreg(RDT0_A), defreg(RDTR_A), defreg(RDFH_A),
defreg(RDFT_A), defreg(TDH_A), defreg(TDT_A), defreg(TIDV_A),
defreg(TDFH_A), defreg(TDFT_A), defreg(RA_A), defreg(RDBAL0_A),
defreg(TDBAL_A), defreg(TDLEN_A), defreg(VFTA_A), defreg(RDLEN0_A),
defreg(FCRTL_A), defreg(FCRTH_A)
};
static inline void
e1000x_inc_reg_if_not_full(uint32_t *mac, int index)
{
if (mac[index] != 0xffffffff) {
if (mac[index] != UINT32_MAX) {
mac[index]++;
}
}
@ -152,16 +78,16 @@ static inline void
e1000x_update_regs_on_link_down(uint32_t *mac, uint16_t *phy)
{
mac[STATUS] &= ~E1000_STATUS_LU;
phy[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
phy[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
phy[PHY_LP_ABILITY] &= ~MII_LPAR_LPACK;
phy[MII_BMSR] &= ~MII_BMSR_LINK_ST;
phy[MII_BMSR] &= ~MII_BMSR_AN_COMP;
phy[MII_ANLPAR] &= ~MII_ANLPAR_ACK;
}
static inline void
e1000x_update_regs_on_link_up(uint32_t *mac, uint16_t *phy)
{
mac[STATUS] |= E1000_STATUS_LU;
phy[PHY_STATUS] |= MII_SR_LINK_STATUS;
phy[MII_BMSR] |= MII_BMSR_LINK_ST;
}
void e1000x_update_rx_total_stats(uint32_t *mac,
@ -178,7 +104,7 @@ uint32_t e1000x_rxbufsize(uint32_t rctl);
bool e1000x_rx_ready(PCIDevice *d, uint32_t *mac);
bool e1000x_is_vlan_packet(const uint8_t *buf, uint16_t vet);
bool e1000x_is_vlan_packet(const void *buf, uint16_t vet);
bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf);
@ -213,4 +139,7 @@ typedef struct e1000x_txd_props {
void e1000x_read_tx_ctx_descr(struct e1000_context_desc *d,
e1000x_txd_props *props);
void e1000x_timestamp(uint32_t *mac, int64_t timadj, size_t lo, size_t hi);
void e1000x_set_timinca(uint32_t *mac, int64_t *timadj, uint32_t val);
#endif

967
hw/net/e1000x_regs.h Normal file
View File

@ -0,0 +1,967 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
Copyright(c) 1999 - 2006 Intel Corporation.
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, see <http://www.gnu.org/licenses/>.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
/* e1000_hw.h
* Structures, enums, and macros for the MAC
*/
#ifndef HW_E1000X_REGS_H
#define HW_E1000X_REGS_H
/* PCI Device IDs */
#define E1000_DEV_ID_82542 0x1000
#define E1000_DEV_ID_82543GC_FIBER 0x1001
#define E1000_DEV_ID_82543GC_COPPER 0x1004
#define E1000_DEV_ID_82544EI_COPPER 0x1008
#define E1000_DEV_ID_82544EI_FIBER 0x1009
#define E1000_DEV_ID_82544GC_COPPER 0x100C
#define E1000_DEV_ID_82544GC_LOM 0x100D
#define E1000_DEV_ID_82540EM 0x100E
#define E1000_DEV_ID_82540EM_LOM 0x1015
#define E1000_DEV_ID_82540EP_LOM 0x1016
#define E1000_DEV_ID_82540EP 0x1017
#define E1000_DEV_ID_82540EP_LP 0x101E
#define E1000_DEV_ID_82545EM_COPPER 0x100F
#define E1000_DEV_ID_82545EM_FIBER 0x1011
#define E1000_DEV_ID_82545GM_COPPER 0x1026
#define E1000_DEV_ID_82545GM_FIBER 0x1027
#define E1000_DEV_ID_82545GM_SERDES 0x1028
#define E1000_DEV_ID_82546EB_COPPER 0x1010
#define E1000_DEV_ID_82546EB_FIBER 0x1012
#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
#define E1000_DEV_ID_82541EI 0x1013
#define E1000_DEV_ID_82541EI_MOBILE 0x1018
#define E1000_DEV_ID_82541ER_LOM 0x1014
#define E1000_DEV_ID_82541ER 0x1078
#define E1000_DEV_ID_82547GI 0x1075
#define E1000_DEV_ID_82541GI 0x1076
#define E1000_DEV_ID_82541GI_MOBILE 0x1077
#define E1000_DEV_ID_82541GI_LF 0x107C
#define E1000_DEV_ID_82546GB_COPPER 0x1079
#define E1000_DEV_ID_82546GB_FIBER 0x107A
#define E1000_DEV_ID_82546GB_SERDES 0x107B
#define E1000_DEV_ID_82546GB_PCIE 0x108A
#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
#define E1000_DEV_ID_82547EI 0x1019
#define E1000_DEV_ID_82547EI_MOBILE 0x101A
#define E1000_DEV_ID_82571EB_COPPER 0x105E
#define E1000_DEV_ID_82571EB_FIBER 0x105F
#define E1000_DEV_ID_82571EB_SERDES 0x1060
#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5
#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE 0x10BC
#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
#define E1000_DEV_ID_82572EI_COPPER 0x107D
#define E1000_DEV_ID_82572EI_FIBER 0x107E
#define E1000_DEV_ID_82572EI_SERDES 0x107F
#define E1000_DEV_ID_82572EI 0x10B9
#define E1000_DEV_ID_82573E 0x108B
#define E1000_DEV_ID_82573E_IAMT 0x108C
#define E1000_DEV_ID_82573L 0x109A
#define E1000_DEV_ID_82574L 0x10D3
#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
#define E1000_DEV_ID_ICH8_IGP_C 0x104B
#define E1000_DEV_ID_ICH8_IFE 0x104C
#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4
#define E1000_DEV_ID_ICH8_IFE_G 0x10C5
#define E1000_DEV_ID_ICH8_IGP_M 0x104D
/* Device Specific Register Defaults */
#define E1000_PHY_ID2_82541x 0x380
#define E1000_PHY_ID2_82544x 0xC30
#define E1000_PHY_ID2_8254xx_DEFAULT 0xC20 /* 82540x, 82545x, and 82546x */
#define E1000_PHY_ID2_82573x 0xCC0
#define E1000_PHY_ID2_82574x 0xCB1
/* Register Set. (82543, 82544)
*
* Registers are defined to be 32 bits and should be accessed as 32 bit values.
* These registers are physically located on the NIC, but are mapped into the
* host memory address space.
*
* RW - register is both readable and writable
* RO - register is read only
* WO - register is write only
* R/clr - register is read only and is cleared when read
* A - register array
*/
#define E1000_CTRL 0x00000 /* Device Control - RW */
#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */
#define E1000_STATUS 0x00008 /* Device Status - RO */
#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
#define E1000_EERD 0x00014 /* EEPROM Read - RW */
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
#define E1000_SCTL 0x00024 /* SerDes Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */
#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
#define E1000_RCTL 0x00100 /* RX Control - RW */
#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
#define E1000_TCTL 0x00400 /* TX Control - RW */
#define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
#define E1000_EEMNGDATA 0x01014 /* MNG EEPROM Read/Write data */
#define E1000_FLMNGCTL 0x01018 /* MNG Flash Control */
#define E1000_FLMNGDATA 0x0101C /* MNG FLASH Read data */
#define E1000_FLMNGCNT 0x01020 /* MNG FLASH Read Counter */
#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */
#define E1000_FLOP 0x0103C /* FLASH Opcode Register */
#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
#define E1000_FCRTL_A 0x00168 /* Alias to FCRTL */
#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */
#define E1000_RDFH 0x02410 /* Receive Data FIFO Head Register - RW */
#define E1000_RDFH_A 0x08000 /* Alias to RDFH */
#define E1000_RDFT 0x02418 /* Receive Data FIFO Tail Register - RW */
#define E1000_RDFT_A 0x08008 /* Alias to RDFT */
#define E1000_RDFHS 0x02420 /* Receive Data FIFO Head Saved Register - RW */
#define E1000_RDFTS 0x02428 /* Receive Data FIFO Tail Saved Register - RW */
#define E1000_RDFPC 0x02430 /* Receive Data FIFO Packet Count - RW */
#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */
#define E1000_TDFH_A 0x08010 /* Alias to TDFH */
#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */
#define E1000_TDFT_A 0x08018 /* Alias to TDFT */
#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */
#define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */
#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */
#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */
#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */
#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */
#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */
#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */
#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */
#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */
#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */
#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */
#define E1000_COLC 0x04028 /* Collision Count - R/clr */
#define E1000_DC 0x04030 /* Defer Count - R/clr */
#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */
#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */
#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */
#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */
#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */
#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */
#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */
#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */
#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */
#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */
#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */
#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */
#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */
#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */
#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */
#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */
#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */
#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */
#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */
#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */
#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */
#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */
#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */
#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */
#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */
#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */
#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */
#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */
#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */
#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */
#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */
#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */
#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */
#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */
#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */
#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */
#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */
#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */
#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */
#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */
#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */
#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */
#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */
#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */
#define E1000_IAC 0x04100 /* Interrupt Assertion Count */
#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */
#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */
#define E1000_RFCTL 0x05008 /* Receive Filter Control*/
#define E1000_MAVTV0 0x05010 /* Management VLAN TAG Value 0 */
#define E1000_MAVTV1 0x05014 /* Management VLAN TAG Value 1 */
#define E1000_MAVTV2 0x05018 /* Management VLAN TAG Value 2 */
#define E1000_MAVTV3 0x0501c /* Management VLAN TAG Value 3 */
#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
#define E1000_RA 0x05400 /* Receive Address - RW Array */
#define E1000_RA_A 0x00040 /* Alias to RA */
#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */
#define E1000_VFTA_A 0x00600 /* Alias to VFTA */
#define E1000_WUC 0x05800 /* Wakeup Control - RW */
#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */
#define E1000_WUS 0x05810 /* Wakeup Status - RO */
#define E1000_MANC 0x05820 /* Management Control - RW */
#define E1000_IPAV 0x05838 /* IP Address Valid - RW */
#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */
#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */
#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */
#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */
#define E1000_MFVAL 0x05824 /* Manageability Filters Valid - RW */
#define E1000_MDEF 0x05890 /* Manageability Decision Filters - RW Array */
#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */
#define E1000_FTFT 0x09400 /* Flexible TCO Filter Table - RW Array */
#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */
#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
#define E1000_GCR 0x05B00 /* PCI-Ex Control */
#define E1000_FUNCTAG 0x05B08 /* Function-Tag Register */
#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */
#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */
#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */
#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */
#define E1000_GSCN_0 0x05B20 /* 3GIO Statistic Counter Register #0 */
#define E1000_GSCN_1 0x05B24 /* 3GIO Statistic Counter Register #1 */
#define E1000_GSCN_2 0x05B28 /* 3GIO Statistic Counter Register #2 */
#define E1000_GSCN_3 0x05B2C /* 3GIO Statistic Counter Register #3 */
#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
#define E1000_SWSM 0x05B50 /* SW Semaphore */
#define E1000_FWSM 0x05B54 /* FW Semaphore */
#define E1000_PBACLR 0x05B68 /* MSI-X PBA Clear */
#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */
#define E1000_RXSTMPL 0x0B624 /* Rx timestamp Low - RO */
#define E1000_RXSTMPH 0x0B628 /* Rx timestamp High - RO */
#define E1000_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */
#define E1000_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */
#define E1000_SYSTIML 0x0B600 /* System time register Low - RO */
#define E1000_SYSTIMH 0x0B604 /* System time register High - RO */
#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */
#define E1000_RXSATRL 0x0B62C /* Rx timestamp attribute low - RO */
#define E1000_RXSATRH 0x0B630 /* Rx timestamp attribute high - RO */
#define E1000_TIMADJL 0x0B60C /* Time Adjustment Offset register Low - RW */
#define E1000_TIMADJH 0x0B610 /* Time Adjustment Offset register High - RW */
/* RSS registers */
#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */
#define E1000_RETA 0x05C00 /* Redirection Table - RW Array */
#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */
#define E1000_RETA_IDX(hash) ((hash) & (BIT(7) - 1))
#define E1000_RETA_VAL(reta, hash) (((uint8_t *)(reta))[E1000_RETA_IDX(hash)])
#define E1000_MRQC_EN_TCPIPV4(mrqc) ((mrqc) & BIT(16))
#define E1000_MRQC_EN_IPV4(mrqc) ((mrqc) & BIT(17))
#define E1000_MRQC_EN_TCPIPV6(mrqc) ((mrqc) & BIT(18))
#define E1000_MRQC_EN_IPV6EX(mrqc) ((mrqc) & BIT(19))
#define E1000_MRQC_EN_IPV6(mrqc) ((mrqc) & BIT(20))
#define E1000_MRQ_RSS_TYPE_NONE (0)
#define E1000_MRQ_RSS_TYPE_IPV4TCP (1)
#define E1000_MRQ_RSS_TYPE_IPV4 (2)
#define E1000_MRQ_RSS_TYPE_IPV6TCP (3)
#define E1000_MRQ_RSS_TYPE_IPV6EX (4)
#define E1000_MRQ_RSS_TYPE_IPV6 (5)
#define E1000_ICR_ASSERTED BIT(31)
#define E1000_EIAC_MASK 0x01F00000
/* RFCTL register bits */
#define E1000_RFCTL_ISCSI_DIS 0x00000001
#define E1000_RFCTL_NFSW_DIS 0x00000040
#define E1000_RFCTL_NFSR_DIS 0x00000080
#define E1000_RFCTL_IPV6_DIS 0x00000400
#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800
#define E1000_RFCTL_IPFRSP_DIS 0x00004000
#define E1000_RFCTL_EXTEN 0x00008000
#define E1000_RFCTL_IPV6_EX_DIS 0x00010000
#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000
/* TARC* parsing */
#define E1000_TARC_ENABLE BIT(10)
/* SW Semaphore Register */
#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */
#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */
/* Interrupt Cause Read */
#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */
#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */
#define E1000_ICR_LSC 0x00000004 /* Link Status Change */
#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */
#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */
#define E1000_ICR_RXO 0x00000040 /* rx overrun */
#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */
#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */
#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */
#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */
#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */
#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */
#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */
#define E1000_ICR_TXD_LOW 0x00008000
#define E1000_ICR_SRPD 0x00010000
#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */
#define E1000_ICR_MNG 0x00040000 /* Manageability event */
#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */
#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */
#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */
#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */
#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity error */
#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */
#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */
#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */
#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */
#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */
#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */
#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */
#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */
#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */
#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */
#define E1000_ICR_OTHER_CAUSES (E1000_ICR_LSC | \
E1000_ICR_RXO | \
E1000_ICR_MDAC | \
E1000_ICR_SRPD | \
E1000_ICR_ACK | \
E1000_ICR_MNG)
/* Interrupt Cause Set */
#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */
#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */
#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
#define E1000_ICS_SRPD E1000_ICR_SRPD
#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */
#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */
#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */
#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */
#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
#define E1000_ICS_DSW E1000_ICR_DSW
#define E1000_ICS_PHYINT E1000_ICR_PHYINT
#define E1000_ICS_EPRST E1000_ICR_EPRST
/* Interrupt Mask Set */
#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */
#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */
#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */
#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
#define E1000_IMS_SRPD E1000_ICR_SRPD
#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */
#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */
#define E1000_IMS_RXQ0 E1000_ICR_RXQ0
#define E1000_IMS_RXQ1 E1000_ICR_RXQ1
#define E1000_IMS_TXQ0 E1000_ICR_TXQ0
#define E1000_IMS_TXQ1 E1000_ICR_TXQ1
#define E1000_IMS_OTHER E1000_ICR_OTHER
#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */
#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */
#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
#define E1000_IMS_DSW E1000_ICR_DSW
#define E1000_IMS_PHYINT E1000_ICR_PHYINT
#define E1000_IMS_EPRST E1000_ICR_EPRST
/* Interrupt Mask Clear */
#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */
#define E1000_IMC_TXQE E1000_ICR_TXQE /* Transmit Queue empty */
#define E1000_IMC_LSC E1000_ICR_LSC /* Link Status Change */
#define E1000_IMC_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
#define E1000_IMC_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
#define E1000_IMC_RXO E1000_ICR_RXO /* rx overrun */
#define E1000_IMC_RXT0 E1000_ICR_RXT0 /* rx timer intr */
#define E1000_IMC_MDAC E1000_ICR_MDAC /* MDIO access complete */
#define E1000_IMC_RXCFG E1000_ICR_RXCFG /* RX /c/ ordered set */
#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */
#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */
#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */
#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */
#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW
#define E1000_IMC_SRPD E1000_ICR_SRPD
#define E1000_IMC_ACK E1000_ICR_ACK /* Receive Ack frame */
#define E1000_IMC_MNG E1000_ICR_MNG /* Manageability event */
#define E1000_IMC_DOCK E1000_ICR_DOCK /* Dock/Undock */
#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
#define E1000_IMC_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */
#define E1000_IMC_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
#define E1000_IMC_DSW E1000_ICR_DSW
#define E1000_IMC_PHYINT E1000_ICR_PHYINT
#define E1000_IMC_EPRST E1000_ICR_EPRST
/* Receive Control */
#define E1000_RCTL_RST 0x00000001 /* Software reset */
#define E1000_RCTL_EN 0x00000002 /* enable */
#define E1000_RCTL_SBP 0x00000004 /* store bad packet */
#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */
#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */
#define E1000_RCTL_LPE 0x00000020 /* long packet enable */
#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */
#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */
#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */
#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */
#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */
#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min threshold size */
#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min threshold size */
#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */
#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */
#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */
#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */
#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */
#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */
#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */
#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */
#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */
#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */
/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */
#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */
#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */
#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */
#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */
#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */
#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */
#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */
#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */
#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */
#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */
#define E1000_EEPROM_LED_LOGIC 0x0020 /* Led Logic Word */
#define E1000_EEPROM_RW_REG_DATA 16 /* Offset to data in EEPROM read/write registers */
#define E1000_EEPROM_RW_REG_DONE 0x10 /* Offset to READ/WRITE done bit */
#define E1000_EEPROM_RW_REG_START 1 /* First bit for telling part to start operation */
#define E1000_EEPROM_RW_ADDR_SHIFT 8 /* Shift to the address bits */
#define E1000_EEPROM_POLL_WRITE 1 /* Flag for polling for write complete */
#define E1000_EEPROM_POLL_READ 0 /* Flag for polling for read complete */
/* 82574 EERD/EEWR registers layout */
#define E1000_EERW_START BIT(0)
#define E1000_EERW_DONE BIT(1)
#define E1000_EERW_ADDR_SHIFT 2
#define E1000_EERW_ADDR_MASK ((1L << 14) - 1)
#define E1000_EERW_DATA_SHIFT 16
#define E1000_EERW_DATA_MASK ((1L << 16) - 1)
/* Register Bit Masks */
/* Device Control */
#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */
#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */
#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */
#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */
#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */
#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */
#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */
#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */
#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */
#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */
#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */
#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */
#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */
#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */
#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */
#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */
#define E1000_CTRL_SPD_SHIFT 8 /* Speed Select Shift */
#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* auto speed detection check */
#define E1000_CTRL_EXT_EE_RST 0x00002000 /* EEPROM reset */
#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */
#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
#define E1000_CTRL_EXT_EIAME 0x01000000
#define E1000_CTRL_EXT_IAME 0x08000000 /* Int ACK Auto-mask */
#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
#define E1000_CTRL_EXT_INT_TIMERS_CLEAR_ENA 0x20000000
#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */
#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */
#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */
#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */
#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */
#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */
#define E1000_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */
#define E1000_CTRL_RST 0x04000000 /* Global reset */
#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */
#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */
/* Device Status */
#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */
#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000
/* EEPROM/Flash Control */
#define E1000_EECD_SK 0x00000001 /* EEPROM Clock */
#define E1000_EECD_CS 0x00000002 /* EEPROM Chip Select */
#define E1000_EECD_DI 0x00000004 /* EEPROM Data In */
#define E1000_EECD_DO 0x00000008 /* EEPROM Data Out */
#define E1000_EECD_FWE_MASK 0x00000030
#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */
#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */
#define E1000_EECD_FWE_SHIFT 4
#define E1000_EECD_REQ 0x00000040 /* EEPROM Access Request */
#define E1000_EECD_GNT 0x00000080 /* EEPROM Access Grant */
#define E1000_EECD_PRES 0x00000100 /* EEPROM Present */
#define E1000_EECD_SIZE 0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
* (0-small, 1-large) */
#define E1000_EECD_TYPE 0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
#ifndef E1000_EEPROM_GRANT_ATTEMPTS
#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
#endif
#define E1000_EECD_AUTO_RD 0x00000200 /* EEPROM Auto Read done */
#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* EEprom Size */
#define E1000_EECD_SIZE_EX_SHIFT 11
#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */
#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */
#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */
#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */
#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
#define E1000_EECD_SECVAL_SHIFT 22
#define E1000_STM_OPCODE 0xDB00
#define E1000_HICR_FW_RESET 0xC0
#define E1000_SHADOW_RAM_WORDS 2048
#define E1000_ICH_NVM_SIG_WORD 0x13
#define E1000_ICH_NVM_SIG_MASK 0xC0
/* MDI Control */
#define E1000_MDIC_DATA_MASK 0x0000FFFF
#define E1000_MDIC_REG_MASK 0x001F0000
#define E1000_MDIC_REG_SHIFT 16
#define E1000_MDIC_PHY_MASK 0x03E00000
#define E1000_MDIC_PHY_SHIFT 21
#define E1000_MDIC_OP_WRITE 0x04000000
#define E1000_MDIC_OP_READ 0x08000000
#define E1000_MDIC_READY 0x10000000
#define E1000_MDIC_INT_EN 0x20000000
#define E1000_MDIC_ERROR 0x40000000
/* Rx Interrupt Delay Timer */
#define E1000_RDTR_FPD BIT(31)
/* Tx Interrupt Delay Timer */
#define E1000_TIDV_FPD BIT(31)
/* Delay increments in nanoseconds for delayed interrupts registers */
#define E1000_INTR_DELAY_NS_RES (1024)
/* Delay increments in nanoseconds for interrupt throttling registers */
#define E1000_INTR_THROTTLING_NS_RES (256)
/* EEPROM Commands - Microwire */
#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */
#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */
#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7 /* EEPROM erase opcode */
#define EEPROM_EWEN_OPCODE_MICROWIRE 0x13 /* EEPROM erase/write enable */
#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */
/* EEPROM Word Offsets */
#define EEPROM_COMPAT 0x0003
#define EEPROM_ID_LED_SETTINGS 0x0004
#define EEPROM_VERSION 0x0005
#define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */
#define EEPROM_PHY_CLASS_WORD 0x0007
#define EEPROM_INIT_CONTROL1_REG 0x000A
#define EEPROM_INIT_CONTROL2_REG 0x000F
#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
#define EEPROM_INIT_CONTROL3_PORT_B 0x0014
#define EEPROM_INIT_3GIO_3 0x001A
#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
#define EEPROM_INIT_CONTROL3_PORT_A 0x0024
#define EEPROM_CFG 0x0012
#define EEPROM_FLASH_VERSION 0x0032
#define EEPROM_CHECKSUM_REG 0x003F
#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */
#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */
/* HH Time Sync */
#define E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */
#define E1000_TSYNCTXCTL_SYNC_COMP 0x40000000 /* sync complete */
#define E1000_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync */
#define E1000_TSYNCTXCTL_VALID 0x00000001 /* Tx timestamp valid */
#define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */
#define E1000_TSYNCRXCTL_VALID 0x00000001 /* Rx timestamp valid */
#define E1000_TSYNCRXCTL_TYPE_MASK 0x0000000E /* Rx type mask */
#define E1000_TSYNCRXCTL_TYPE_L2_V2 0x00
#define E1000_TSYNCRXCTL_TYPE_L4_V1 0x02
#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2 0x04
#define E1000_TSYNCRXCTL_TYPE_ALL 0x08
#define E1000_TSYNCRXCTL_TYPE_EVENT_V2 0x0A
#define E1000_TSYNCRXCTL_ENABLED 0x00000010 /* enable Rx timestamping */
#define E1000_TSYNCRXCTL_SYSCFI 0x00000020 /* Sys clock frequency */
#define E1000_RXMTRL_PTP_V1_SYNC_MESSAGE 0x00000000
#define E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE 0x00010000
#define E1000_RXMTRL_PTP_V2_SYNC_MESSAGE 0x00000000
#define E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE 0x01000000
#define E1000_TIMINCA_INCPERIOD_SHIFT 24
#define E1000_TIMINCA_INCVALUE_MASK 0x00FFFFFF
/* PCI Express Control */
/* 3GIO Control Register - GCR (0x05B00; RW) */
#define E1000_L0S_ADJUST (1 << 9)
#define E1000_L1_ENTRY_LATENCY_MSB (1 << 23)
#define E1000_L1_ENTRY_LATENCY_LSB (1 << 25 | 1 << 26)
#define E1000_L0S_ADJUST (1 << 9)
#define E1000_L1_ENTRY_LATENCY_MSB (1 << 23)
#define E1000_L1_ENTRY_LATENCY_LSB (1 << 25 | 1 << 26)
#define E1000_GCR_RO_BITS (1 << 23 | 1 << 25 | 1 << 26)
/* MSI-X PBA Clear register */
#define E1000_PBACLR_VALID_MASK (BIT(5) - 1)
/* Transmit Descriptor bit definitions */
#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */
#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
#define E1000_TXD_CMD_SNAP 0x40000000 /* Update SNAP header */
#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
#define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
/* Transmit Control */
#define E1000_TCTL_RST 0x00000001 /* software reset */
#define E1000_TCTL_EN 0x00000002 /* enable tx */
#define E1000_TCTL_BCE 0x00000004 /* busy check enable */
#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */
#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */
#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */
#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */
/* Legacy Receive Descriptor */
struct e1000_rx_desc {
uint64_t buffer_addr; /* Address of the descriptor's data buffer */
uint16_t length; /* Length of data DMAed into data buffer */
uint16_t csum; /* Packet checksum */
uint8_t status; /* Descriptor status */
uint8_t errors; /* Descriptor Errors */
uint16_t special;
};
/* Extended Receive Descriptor */
union e1000_rx_desc_extended {
struct {
uint64_t buffer_addr;
uint64_t reserved;
} read;
struct {
struct {
uint32_t mrq; /* Multiple Rx Queues */
union {
uint32_t rss; /* RSS Hash */
struct {
uint16_t ip_id; /* IP id */
uint16_t csum; /* Packet Checksum */
} csum_ip;
} hi_dword;
} lower;
struct {
uint32_t status_error; /* ext status/error */
uint16_t length;
uint16_t vlan; /* VLAN tag */
} upper;
} wb; /* writeback */
};
#define MAX_PS_BUFFERS 4
/* Number of packet split data buffers (not including the header buffer) */
#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1)
/* Receive Descriptor - Packet Split */
union e1000_rx_desc_packet_split {
struct {
/* one buffer for protocol header(s), three data buffers */
uint64_t buffer_addr[MAX_PS_BUFFERS];
} read;
struct {
struct {
uint32_t mrq; /* Multiple Rx Queues */
union {
uint32_t rss; /* RSS Hash */
struct {
uint16_t ip_id; /* IP id */
uint16_t csum; /* Packet Checksum */
} csum_ip;
} hi_dword;
} lower;
struct {
uint32_t status_error; /* ext status/error */
uint16_t length0; /* length of buffer 0 */
uint16_t vlan; /* VLAN tag */
} middle;
struct {
uint16_t header_status;
/* length of buffers 1-3 */
uint16_t length[PS_PAGE_BUFFERS];
} upper;
uint64_t reserved;
} wb; /* writeback */
};
/* Receive Checksum Control bits */
#define E1000_RXCSUM_IPOFLD 0x100 /* IP Checksum Offload Enable */
#define E1000_RXCSUM_TUOFLD 0x200 /* TCP/UDP Checksum Offload Enable */
#define E1000_RXCSUM_PCSD 0x2000 /* Packet Checksum Disable */
#define E1000_RING_DESC_LEN (16)
#define E1000_RING_DESC_LEN_SHIFT (4)
#define E1000_MIN_RX_DESC_LEN E1000_RING_DESC_LEN
/* Receive Descriptor bit definitions */
#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */
#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */
#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */
#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */
#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */
#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */
#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */
#define E1000_RXD_ERR_CE 0x01 /* CRC Error */
#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */
#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */
#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */
#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */
#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */
#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */
#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */
#define E1000_RXD_SPC_PRI_SHIFT 13
#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */
#define E1000_RXD_SPC_CFI_SHIFT 12
/* RX packet types */
#define E1000_RXD_PKT_MAC (0)
#define E1000_RXD_PKT_IP4 (1)
#define E1000_RXD_PKT_IP4_XDP (2)
#define E1000_RXD_PKT_IP6 (5)
#define E1000_RXD_PKT_IP6_XDP (6)
#define E1000_RXD_PKT_TYPE(t) ((t) << 16)
#define E1000_RXDEXT_STATERR_CE 0x01000000
#define E1000_RXDEXT_STATERR_SE 0x02000000
#define E1000_RXDEXT_STATERR_SEQ 0x04000000
#define E1000_RXDEXT_STATERR_CXE 0x10000000
#define E1000_RXDEXT_STATERR_TCPE 0x20000000
#define E1000_RXDEXT_STATERR_IPE 0x40000000
#define E1000_RXDEXT_STATERR_RXE 0x80000000
#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000
#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF
/* Receive Address */
#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
/* Offload Context Descriptor */
struct e1000_context_desc {
union {
uint32_t ip_config;
struct {
uint8_t ipcss; /* IP checksum start */
uint8_t ipcso; /* IP checksum offset */
uint16_t ipcse; /* IP checksum end */
} ip_fields;
} lower_setup;
union {
uint32_t tcp_config;
struct {
uint8_t tucss; /* TCP checksum start */
uint8_t tucso; /* TCP checksum offset */
uint16_t tucse; /* TCP checksum end */
} tcp_fields;
} upper_setup;
uint32_t cmd_and_length; /* */
union {
uint32_t data;
struct {
uint8_t status; /* Descriptor status */
uint8_t hdr_len; /* Header length */
uint16_t mss; /* Maximum segment size */
} fields;
} tcp_seg_setup;
};
/* Filters */
#define E1000_NUM_UNICAST 16 /* Unicast filter entries */
#define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */
#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
/* Management Control */
#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */
#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */
#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */
#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */
#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */
#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */
#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */
#define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery
* Filtering */
#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */
#define E1000_MANC_DIS_IP_CHK_ARP 0x10000000 /* Disable IP address chacking */
/*for ARP packets - in 82574 */
#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */
#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */
#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address
* filtering */
#define E1000_MANC_EN_MNG2HOST 0x00200000 /* Enable MNG packets to host
* memory */
#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 /* Enable IP address
* filtering */
#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */
#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */
#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */
#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */
#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */
#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */
#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */
#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */
#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */
#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */
/* FACTPS Control */
#define E1000_FACTPS_LAN0_ON 0x00000004 /* Lan 0 enable */
/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
#define EEPROM_SUM 0xBABA
/* I/O-Mapped Access to Internal Registers, Memories, and Flash */
#define E1000_IOADDR 0x00
#define E1000_IODATA 0x04
#define E1000_VFTA_ENTRY_SHIFT 5
#define E1000_VFTA_ENTRY_MASK 0x7F
#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
#endif /* HW_E1000_REGS_H */

View File

@ -29,6 +29,7 @@
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "hw/net/mii.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
#include "etsec.h"
@ -339,11 +340,11 @@ static void etsec_reset(DeviceState *d)
etsec->rx_buffer_len = 0;
etsec->phy_status =
MII_SR_EXTENDED_CAPS | MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS |
MII_SR_EXTENDED_STATUS | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
MII_SR_10T_HD_CAPS | MII_SR_10T_FD_CAPS | MII_SR_100X_HD_CAPS |
MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
MII_BMSR_EXTCAP | MII_BMSR_LINK_ST | MII_BMSR_AUTONEG |
MII_BMSR_AN_COMP | MII_BMSR_MFPS | MII_BMSR_EXTSTAT |
MII_BMSR_100T2_HD | MII_BMSR_100T2_FD |
MII_BMSR_10T_HD | MII_BMSR_10T_FD |
MII_BMSR_100TX_HD | MII_BMSR_100TX_FD | MII_BMSR_100T4;
etsec_update_irq(etsec);
}

View File

@ -76,23 +76,6 @@ typedef struct eTSEC_rxtx_bd {
#define FCB_TX_CTU (1 << 1)
#define FCB_TX_NPH (1 << 0)
/* PHY Status Register */
#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
/* eTSEC */
/* Number of register in the device */

View File

@ -23,6 +23,7 @@
*/
#include "qemu/osdep.h"
#include "hw/net/mii.h"
#include "etsec.h"
#include "registers.h"
@ -140,8 +141,8 @@ void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc)
{
/* Set link status */
if (nc->link_down) {
etsec->phy_status &= ~MII_SR_LINK_STATUS;
etsec->phy_status &= ~MII_BMSR_LINK_ST;
} else {
etsec->phy_status |= MII_SR_LINK_STATUS;
etsec->phy_status |= MII_BMSR_LINK_ST;
}
}

623
hw/net/igb.c Normal file
View File

@ -0,0 +1,623 @@
/*
* QEMU Intel 82576 SR/IOV Ethernet Controller Emulation
*
* Datasheet:
* https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eg-gbe-datasheet.pdf
*
* Copyright (c) 2020-2023 Red Hat, Inc.
* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
* Developed by Daynix Computing LTD (http://www.daynix.com)
*
* Authors:
* Akihiko Odaki <akihiko.odaki@daynix.com>
* Gal Hammmer <gal.hammer@sap.com>
* Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
* Dmitry Fleytman <dmitry@daynix.com>
* Leonid Bloch <leonid@daynix.com>
* Yan Vugenfirer <yan@daynix.com>
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2008 Qumranet
* Based on work done by:
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "net/eth.h"
#include "net/net.h"
#include "net/tap.h"
#include "qemu/module.h"
#include "qemu/range.h"
#include "sysemu/sysemu.h"
#include "hw/hw.h"
#include "hw/net/mii.h"
#include "hw/pci/pci.h"
#include "hw/pci/pcie.h"
#include "hw/pci/pcie_sriov.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "igb_common.h"
#include "igb_core.h"
#include "trace.h"
#include "qapi/error.h"
#include "qom/object.h"
#define TYPE_IGB "igb"
OBJECT_DECLARE_SIMPLE_TYPE(IGBState, IGB)
struct IGBState {
PCIDevice parent_obj;
NICState *nic;
NICConf conf;
MemoryRegion mmio;
MemoryRegion flash;
MemoryRegion io;
MemoryRegion msix;
uint32_t ioaddr;
IGBCore core;
};
#define IGB_CAP_SRIOV_OFFSET (0x160)
#define IGB_VF_OFFSET (0x80)
#define IGB_VF_STRIDE (2)
#define E1000E_MMIO_IDX 0
#define E1000E_FLASH_IDX 1
#define E1000E_IO_IDX 2
#define E1000E_MSIX_IDX 3
#define E1000E_MMIO_SIZE (128 * KiB)
#define E1000E_FLASH_SIZE (128 * KiB)
#define E1000E_IO_SIZE (32)
#define E1000E_MSIX_SIZE (16 * KiB)
static void igb_write_config(PCIDevice *dev, uint32_t addr,
uint32_t val, int len)
{
IGBState *s = IGB(dev);
trace_igb_write_config(addr, val, len);
pci_default_write_config(dev, addr, val, len);
if (range_covers_byte(addr, len, PCI_COMMAND) &&
(dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
igb_start_recv(&s->core);
}
}
uint64_t
igb_mmio_read(void *opaque, hwaddr addr, unsigned size)
{
IGBState *s = opaque;
return igb_core_read(&s->core, addr, size);
}
void
igb_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
IGBState *s = opaque;
igb_core_write(&s->core, addr, val, size);
}
static bool
igb_io_get_reg_index(IGBState *s, uint32_t *idx)
{
if (s->ioaddr < 0x1FFFF) {
*idx = s->ioaddr;
return true;
}
if (s->ioaddr < 0x7FFFF) {
trace_e1000e_wrn_io_addr_undefined(s->ioaddr);
return false;
}
if (s->ioaddr < 0xFFFFF) {
trace_e1000e_wrn_io_addr_flash(s->ioaddr);
return false;
}
trace_e1000e_wrn_io_addr_unknown(s->ioaddr);
return false;
}
static uint64_t
igb_io_read(void *opaque, hwaddr addr, unsigned size)
{
IGBState *s = opaque;
uint32_t idx = 0;
uint64_t val;
switch (addr) {
case E1000_IOADDR:
trace_e1000e_io_read_addr(s->ioaddr);
return s->ioaddr;
case E1000_IODATA:
if (igb_io_get_reg_index(s, &idx)) {
val = igb_core_read(&s->core, idx, sizeof(val));
trace_e1000e_io_read_data(idx, val);
return val;
}
return 0;
default:
trace_e1000e_wrn_io_read_unknown(addr);
return 0;
}
}
static void
igb_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
IGBState *s = opaque;
uint32_t idx = 0;
switch (addr) {
case E1000_IOADDR:
trace_e1000e_io_write_addr(val);
s->ioaddr = (uint32_t) val;
return;
case E1000_IODATA:
if (igb_io_get_reg_index(s, &idx)) {
trace_e1000e_io_write_data(idx, val);
igb_core_write(&s->core, idx, val, sizeof(val));
}
return;
default:
trace_e1000e_wrn_io_write_unknown(addr);
return;
}
}
static const MemoryRegionOps mmio_ops = {
.read = igb_mmio_read,
.write = igb_mmio_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static const MemoryRegionOps io_ops = {
.read = igb_io_read,
.write = igb_io_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static bool
igb_nc_can_receive(NetClientState *nc)
{
IGBState *s = qemu_get_nic_opaque(nc);
return igb_can_receive(&s->core);
}
static ssize_t
igb_nc_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
{
IGBState *s = qemu_get_nic_opaque(nc);
return igb_receive_iov(&s->core, iov, iovcnt);
}
static ssize_t
igb_nc_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{
IGBState *s = qemu_get_nic_opaque(nc);
return igb_receive(&s->core, buf, size);
}
static void
igb_set_link_status(NetClientState *nc)
{
IGBState *s = qemu_get_nic_opaque(nc);
igb_core_set_link_status(&s->core);
}
static NetClientInfo net_igb_info = {
.type = NET_CLIENT_DRIVER_NIC,
.size = sizeof(NICState),
.can_receive = igb_nc_can_receive,
.receive = igb_nc_receive,
.receive_iov = igb_nc_receive_iov,
.link_status_changed = igb_set_link_status,
};
/*
* EEPROM (NVM) contents documented in section 6.1, table 6-1:
* and in 6.10 Software accessed words.
*/
static const uint16_t igb_eeprom_template[] = {
/* Address |Compat.|OEM sp.| ImRev | OEM sp. */
0x0000, 0x0000, 0x0000, 0x0d34, 0xffff, 0x2010, 0xffff, 0xffff,
/* PBA |ICtrl1 | SSID | SVID | DevID |-------|ICtrl2 */
0x1040, 0xffff, 0x002b, 0x0000, 0x8086, 0x10c9, 0x0000, 0x70c3,
/* SwPin0| DevID | EESZ |-------|ICtrl3 |PCI-tc | MSIX | APtr */
0x0004, 0x10c9, 0x5c00, 0x0000, 0x2880, 0x0014, 0x4a40, 0x0060,
/* PCIe Init. Conf 1,2,3 |PCICtrl| LD1,3 |DDevID |DevRev | LD0,2 */
0x6cfb, 0xc7b0, 0x0abe, 0x0403, 0x0783, 0x10a6, 0x0001, 0x0602,
/* SwPin1| FunC |LAN-PWR|ManHwC |ICtrl3 | IOVct |VDevID |-------*/
0x0004, 0x0020, 0x0000, 0x004a, 0x2080, 0x00f5, 0x10ca, 0x0000,
/*---------------| LD1,3 | LD0,2 | ROEnd | ROSta | Wdog | VPD */
0x0000, 0x0000, 0x4784, 0x4602, 0x0000, 0x0000, 0x1000, 0xffff,
/* PCSet0| Ccfg0 |PXEver |IBAcap |PCSet1 | Ccfg1 |iSCVer | ?? */
0x0100, 0x4000, 0x131f, 0x4013, 0x0100, 0x4000, 0xffff, 0xffff,
/* PCSet2| Ccfg2 |PCSet3 | Ccfg3 | ?? |AltMacP| ?? |CHKSUM */
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00e0, 0xffff, 0x0000,
/* NC-SIC */
0x0003,
};
static void igb_core_realize(IGBState *s)
{
s->core.owner = &s->parent_obj;
s->core.owner_nic = s->nic;
}
static void
igb_init_msix(IGBState *s)
{
int i, res;
res = msix_init(PCI_DEVICE(s), IGB_MSIX_VEC_NUM,
&s->msix,
E1000E_MSIX_IDX, 0,
&s->msix,
E1000E_MSIX_IDX, 0x2000,
0x70, NULL);
if (res < 0) {
trace_e1000e_msix_init_fail(res);
} else {
for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
msix_vector_use(PCI_DEVICE(s), i);
}
}
}
static void
igb_cleanup_msix(IGBState *s)
{
msix_unuse_all_vectors(PCI_DEVICE(s));
msix_uninit(PCI_DEVICE(s), &s->msix, &s->msix);
}
static void
igb_init_net_peer(IGBState *s, PCIDevice *pci_dev, uint8_t *macaddr)
{
DeviceState *dev = DEVICE(pci_dev);
NetClientState *nc;
int i;
s->nic = qemu_new_nic(&net_igb_info, &s->conf,
object_get_typename(OBJECT(s)), dev->id, s);
s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0;
trace_e1000e_mac_set_permanent(MAC_ARG(macaddr));
memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac));
qemu_format_nic_info_str(qemu_get_queue(s->nic), macaddr);
/* Setup virtio headers */
for (i = 0; i < s->conf.peers.queues; i++) {
nc = qemu_get_subqueue(s->nic, i);
if (!nc->peer || !qemu_has_vnet_hdr(nc->peer)) {
trace_e1000e_cfg_support_virtio(false);
return;
}
}
trace_e1000e_cfg_support_virtio(true);
s->core.has_vnet = true;
for (i = 0; i < s->conf.peers.queues; i++) {
nc = qemu_get_subqueue(s->nic, i);
qemu_set_vnet_hdr_len(nc->peer, sizeof(struct virtio_net_hdr));
qemu_using_vnet_hdr(nc->peer, true);
}
}
static int
igb_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
{
Error *local_err = NULL;
int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset,
PCI_PM_SIZEOF, &local_err);
if (local_err) {
error_report_err(local_err);
return ret;
}
pci_set_word(pdev->config + offset + PCI_PM_PMC,
PCI_PM_CAP_VER_1_1 |
pmc);
pci_set_word(pdev->wmask + offset + PCI_PM_CTRL,
PCI_PM_CTRL_STATE_MASK |
PCI_PM_CTRL_PME_ENABLE |
PCI_PM_CTRL_DATA_SEL_MASK);
pci_set_word(pdev->w1cmask + offset + PCI_PM_CTRL,
PCI_PM_CTRL_PME_STATUS);
return ret;
}
static void igb_pci_realize(PCIDevice *pci_dev, Error **errp)
{
IGBState *s = IGB(pci_dev);
uint8_t *macaddr;
int ret;
trace_e1000e_cb_pci_realize();
pci_dev->config_write = igb_write_config;
pci_dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
pci_dev->config[PCI_INTERRUPT_PIN] = 1;
/* Define IO/MMIO regions */
memory_region_init_io(&s->mmio, OBJECT(s), &mmio_ops, s,
"igb-mmio", E1000E_MMIO_SIZE);
pci_register_bar(pci_dev, E1000E_MMIO_IDX,
PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
/*
* We provide a dummy implementation for the flash BAR
* for drivers that may theoretically probe for its presence.
*/
memory_region_init(&s->flash, OBJECT(s),
"igb-flash", E1000E_FLASH_SIZE);
pci_register_bar(pci_dev, E1000E_FLASH_IDX,
PCI_BASE_ADDRESS_SPACE_MEMORY, &s->flash);
memory_region_init_io(&s->io, OBJECT(s), &io_ops, s,
"igb-io", E1000E_IO_SIZE);
pci_register_bar(pci_dev, E1000E_IO_IDX,
PCI_BASE_ADDRESS_SPACE_IO, &s->io);
memory_region_init(&s->msix, OBJECT(s), "igb-msix",
E1000E_MSIX_SIZE);
pci_register_bar(pci_dev, E1000E_MSIX_IDX,
PCI_BASE_ADDRESS_MEM_TYPE_64, &s->msix);
/* Create networking backend */
qemu_macaddr_default_if_unset(&s->conf.macaddr);
macaddr = s->conf.macaddr.a;
/* Add PCI capabilities in reverse order */
assert(pcie_endpoint_cap_init(pci_dev, 0xa0) > 0);
igb_init_msix(s);
ret = msi_init(pci_dev, 0x50, 1, true, true, NULL);
if (ret) {
trace_e1000e_msi_init_fail(ret);
}
if (igb_add_pm_capability(pci_dev, 0x40, PCI_PM_CAP_DSI) < 0) {
hw_error("Failed to initialize PM capability");
}
/* PCIe extended capabilities (in order) */
if (pcie_aer_init(pci_dev, 1, 0x100, 0x40, errp) < 0) {
hw_error("Failed to initialize AER capability");
}
pcie_ari_init(pci_dev, 0x150, 1);
pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, "igbvf",
IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS, IGB_MAX_VF_FUNCTIONS,
IGB_VF_OFFSET, IGB_VF_STRIDE);
pcie_sriov_pf_init_vf_bar(pci_dev, 0,
PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH,
16 * KiB);
pcie_sriov_pf_init_vf_bar(pci_dev, 3,
PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH,
16 * KiB);
igb_init_net_peer(s, pci_dev, macaddr);
/* Initialize core */
igb_core_realize(s);
igb_core_pci_realize(&s->core,
igb_eeprom_template,
sizeof(igb_eeprom_template),
macaddr);
}
static void igb_pci_uninit(PCIDevice *pci_dev)
{
IGBState *s = IGB(pci_dev);
trace_e1000e_cb_pci_uninit();
igb_core_pci_uninit(&s->core);
pcie_sriov_pf_exit(pci_dev);
pcie_cap_exit(pci_dev);
qemu_del_nic(s->nic);
igb_cleanup_msix(s);
msi_uninit(pci_dev);
}
static void igb_qdev_reset_hold(Object *obj)
{
PCIDevice *d = PCI_DEVICE(obj);
IGBState *s = IGB(obj);
trace_e1000e_cb_qdev_reset_hold();
pcie_sriov_pf_disable_vfs(d);
igb_core_reset(&s->core);
}
static int igb_pre_save(void *opaque)
{
IGBState *s = opaque;
trace_e1000e_cb_pre_save();
igb_core_pre_save(&s->core);
return 0;
}
static int igb_post_load(void *opaque, int version_id)
{
IGBState *s = opaque;
trace_e1000e_cb_post_load();
return igb_core_post_load(&s->core);
}
static const VMStateDescription igb_vmstate_tx = {
.name = "igb-tx",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT16(vlan, struct igb_tx),
VMSTATE_UINT16(mss, struct igb_tx),
VMSTATE_BOOL(tse, struct igb_tx),
VMSTATE_BOOL(ixsm, struct igb_tx),
VMSTATE_BOOL(txsm, struct igb_tx),
VMSTATE_BOOL(first, struct igb_tx),
VMSTATE_BOOL(skip_cp, struct igb_tx),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription igb_vmstate_intr_timer = {
.name = "igb-intr-timer",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_TIMER_PTR(timer, IGBIntrDelayTimer),
VMSTATE_BOOL(running, IGBIntrDelayTimer),
VMSTATE_END_OF_LIST()
}
};
#define VMSTATE_IGB_INTR_DELAY_TIMER(_f, _s) \
VMSTATE_STRUCT(_f, _s, 0, \
igb_vmstate_intr_timer, IGBIntrDelayTimer)
#define VMSTATE_IGB_INTR_DELAY_TIMER_ARRAY(_f, _s, _num) \
VMSTATE_STRUCT_ARRAY(_f, _s, _num, 0, \
igb_vmstate_intr_timer, IGBIntrDelayTimer)
static const VMStateDescription igb_vmstate = {
.name = "igb",
.version_id = 1,
.minimum_version_id = 1,
.pre_save = igb_pre_save,
.post_load = igb_post_load,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, IGBState),
VMSTATE_MSIX(parent_obj, IGBState),
VMSTATE_UINT32(ioaddr, IGBState),
VMSTATE_UINT8(core.rx_desc_len, IGBState),
VMSTATE_UINT16_ARRAY(core.eeprom, IGBState, IGB_EEPROM_SIZE),
VMSTATE_UINT16_ARRAY(core.phy, IGBState, MAX_PHY_REG_ADDRESS + 1),
VMSTATE_UINT32_ARRAY(core.mac, IGBState, E1000E_MAC_SIZE),
VMSTATE_UINT8_ARRAY(core.permanent_mac, IGBState, ETH_ALEN),
VMSTATE_IGB_INTR_DELAY_TIMER_ARRAY(core.eitr, IGBState,
IGB_INTR_NUM),
VMSTATE_UINT32_ARRAY(core.eitr_guest_value, IGBState, IGB_INTR_NUM),
VMSTATE_STRUCT_ARRAY(core.tx, IGBState, IGB_NUM_QUEUES, 0,
igb_vmstate_tx, struct igb_tx),
VMSTATE_INT64(core.timadj, IGBState),
VMSTATE_END_OF_LIST()
}
};
static Property igb_properties[] = {
DEFINE_NIC_PROPERTIES(IGBState, conf),
DEFINE_PROP_END_OF_LIST(),
};
static void igb_class_init(ObjectClass *class, void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
ResettableClass *rc = RESETTABLE_CLASS(class);
PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
c->realize = igb_pci_realize;
c->exit = igb_pci_uninit;
c->vendor_id = PCI_VENDOR_ID_INTEL;
c->device_id = E1000_DEV_ID_82576;
c->revision = 1;
c->class_id = PCI_CLASS_NETWORK_ETHERNET;
rc->phases.hold = igb_qdev_reset_hold;
dc->desc = "Intel 82576 Gigabit Ethernet Controller";
dc->vmsd = &igb_vmstate;
device_class_set_props(dc, igb_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
static void igb_instance_init(Object *obj)
{
IGBState *s = IGB(obj);
device_add_bootindex_property(obj, &s->conf.bootindex,
"bootindex", "/ethernet-phy@0",
DEVICE(obj));
}
static const TypeInfo igb_info = {
.name = TYPE_IGB,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(IGBState),
.class_init = igb_class_init,
.instance_init = igb_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
};
static void igb_register_types(void)
{
type_register_static(&igb_info);
}
type_init(igb_register_types)

146
hw/net/igb_common.h Normal file
View File

@ -0,0 +1,146 @@
/*
* QEMU igb emulation - shared definitions
*
* Copyright (c) 2020-2023 Red Hat, Inc.
* Copyright (c) 2008 Qumranet
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HW_NET_IGB_COMMON_H
#define HW_NET_IGB_COMMON_H
#include "igb_regs.h"
#define defreg(x) x = (E1000_##x >> 2)
#define defreg_indexed(x, i) x##i = (E1000_##x(i) >> 2)
#define defreg_indexeda(x, i) x##i##_A = (E1000_##x##_A(i) >> 2)
#define defregd(x) defreg_indexed(x, 0), defreg_indexed(x, 1), \
defreg_indexed(x, 2), defreg_indexed(x, 3), \
defreg_indexed(x, 4), defreg_indexed(x, 5), \
defreg_indexed(x, 6), defreg_indexed(x, 7), \
defreg_indexed(x, 8), defreg_indexed(x, 9), \
defreg_indexed(x, 10), defreg_indexed(x, 11), \
defreg_indexed(x, 12), defreg_indexed(x, 13), \
defreg_indexed(x, 14), defreg_indexed(x, 15), \
defreg_indexeda(x, 0), defreg_indexeda(x, 1), \
defreg_indexeda(x, 2), defreg_indexeda(x, 3)
#define defregv(x) defreg_indexed(x, 0), defreg_indexed(x, 1), \
defreg_indexed(x, 2), defreg_indexed(x, 3), \
defreg_indexed(x, 4), defreg_indexed(x, 5), \
defreg_indexed(x, 6), defreg_indexed(x, 7)
enum {
defreg(CTRL), defreg(EECD), defreg(EERD), defreg(GPRC),
defreg(GPTC), defreg(ICR), defreg(ICS), defreg(IMC),
defreg(IMS), defreg(LEDCTL), defreg(MANC), defreg(MDIC),
defreg(MPC), defreg(RCTL),
defreg(STATUS), defreg(SWSM), defreg(TCTL),
defreg(TORH), defreg(TORL), defreg(TOTH),
defreg(TOTL), defreg(TPR), defreg(TPT),
defreg(WUFC), defreg(RA), defreg(MTA), defreg(CRCERRS),
defreg(VFTA), defreg(VET),
defreg(SCC), defreg(ECOL),
defreg(MCC), defreg(LATECOL), defreg(COLC), defreg(DC),
defreg(TNCRS), defreg(RLEC),
defreg(XONRXC), defreg(XONTXC), defreg(XOFFRXC), defreg(XOFFTXC),
defreg(FCRUC), defreg(TDFH), defreg(TDFT),
defreg(TDFHS), defreg(TDFTS), defreg(TDFPC), defreg(WUC),
defreg(WUS), defreg(RDFH),
defreg(RDFT), defreg(RDFHS), defreg(RDFTS), defreg(RDFPC),
defreg(IPAV), defreg(IP4AT), defreg(IP6AT),
defreg(WUPM), defreg(FFMT),
defreg(IAM),
defreg(GCR), defreg(TIMINCA), defreg(EIAC), defreg(CTRL_EXT),
defreg(IVAR0), defreg(MANC2H),
defreg(MFVAL), defreg(MDEF), defreg(FACTPS), defreg(FTFT),
defreg(RUC), defreg(ROC), defreg(RFC), defreg(RJC),
defreg(PRC64), defreg(PRC127), defreg(PRC255), defreg(PRC511),
defreg(PRC1023), defreg(PRC1522), defreg(PTC64), defreg(PTC127),
defreg(PTC255), defreg(PTC511), defreg(PTC1023), defreg(PTC1522),
defreg(GORCL), defreg(GORCH), defreg(GOTCL), defreg(GOTCH),
defreg(RNBC), defreg(BPRC), defreg(MPRC), defreg(RFCTL),
defreg(MPTC), defreg(BPTC),
defreg(IAC), defreg(MGTPRC), defreg(MGTPDC), defreg(MGTPTC),
defreg(TSCTC), defreg(RXCSUM), defreg(FUNCTAG), defreg(GSCL_1),
defreg(GSCL_2), defreg(GSCL_3), defreg(GSCL_4), defreg(GSCN_0),
defreg(GSCN_1), defreg(GSCN_2), defreg(GSCN_3),
defreg_indexed(EITR, 0),
defreg(MRQC), defreg(RETA), defreg(RSSRK),
defreg(PBACLR), defreg(FCAL), defreg(FCAH), defreg(FCT),
defreg(FCRTH), defreg(FCRTL), defreg(FCTTV), defreg(FCRTV),
defreg(FLA), defreg(FLOP),
defreg(MAVTV0), defreg(MAVTV1), defreg(MAVTV2), defreg(MAVTV3),
defreg(TXSTMPL), defreg(TXSTMPH), defreg(SYSTIML), defreg(SYSTIMH),
defreg(TIMADJL), defreg(TIMADJH),
defreg(RXSTMPH), defreg(RXSTMPL), defreg(RXSATRL), defreg(RXSATRH),
defreg(TIPG),
defreg(CTRL_DUP),
defreg(EEMNGCTL),
defreg(EEMNGDATA),
defreg(FLMNGCTL),
defreg(FLMNGDATA),
defreg(FLMNGCNT),
defreg(TSYNCRXCTL),
defreg(TSYNCTXCTL),
defreg(RLPML),
defreg(UTA),
/* Aliases */
defreg(RDFH_A), defreg(RDFT_A), defreg(TDFH_A), defreg(TDFT_A),
defreg(RA_A), defreg(VFTA_A), defreg(FCRTL_A),
/* Additional regs used by IGB */
defreg(FWSM), defreg(SW_FW_SYNC),
defreg(EICS), defreg(EIMS), defreg(EIMC), defreg(EIAM),
defreg(EICR), defreg(IVAR_MISC), defreg(GPIE),
defreg(RXPBS), defregd(RDBAL), defregd(RDBAH), defregd(RDLEN),
defregd(SRRCTL), defregd(RDH), defregd(RDT),
defregd(RXDCTL), defregd(RXCTL), defregd(RQDPC), defreg(RA2),
defreg(TXPBS), defreg(TCTL_EXT), defreg(DTXCTL), defreg(HTCBDPC),
defregd(TDBAL), defregd(TDBAH), defregd(TDLEN), defregd(TDH),
defregd(TDT), defregd(TXDCTL), defregd(TXCTL),
defregd(TDWBAL), defregd(TDWBAH),
defreg(VT_CTL),
defregv(P2VMAILBOX), defregv(V2PMAILBOX), defreg(MBVFICR), defreg(MBVFIMR),
defreg(VFLRE), defreg(VFRE), defreg(VFTE), defreg(WVBR),
defreg(QDE), defreg(DTXSWC), defreg_indexed(VLVF, 0),
defregv(VMOLR), defreg(RPLOLR), defregv(VMBMEM), defregv(VMVIR),
defregv(PVTCTRL), defregv(PVTEICS), defregv(PVTEIMS), defregv(PVTEIMC),
defregv(PVTEIAC), defregv(PVTEIAM), defregv(PVTEICR), defregv(PVFGPRC),
defregv(PVFGPTC), defregv(PVFGORC), defregv(PVFGOTC), defregv(PVFMPRC),
defregv(PVFGPRLBC), defregv(PVFGPTLBC), defregv(PVFGORLBC), defregv(PVFGOTLBC),
defreg(MTA_A),
defreg(VTIVAR), defreg(VTIVAR_MISC),
};
uint64_t igb_mmio_read(void *opaque, hwaddr addr, unsigned size);
void igb_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size);
#endif

4077
hw/net/igb_core.c Normal file

File diff suppressed because it is too large Load Diff

146
hw/net/igb_core.h Normal file
View File

@ -0,0 +1,146 @@
/*
* Core code for QEMU igb emulation
*
* Datasheet:
* https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eg-gbe-datasheet.pdf
*
* Copyright (c) 2020-2023 Red Hat, Inc.
* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
* Developed by Daynix Computing LTD (http://www.daynix.com)
*
* Authors:
* Akihiko Odaki <akihiko.odaki@daynix.com>
* Gal Hammmer <gal.hammer@sap.com>
* Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
* Dmitry Fleytman <dmitry@daynix.com>
* Leonid Bloch <leonid@daynix.com>
* Yan Vugenfirer <yan@daynix.com>
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2008 Qumranet
* Based on work done by:
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HW_NET_IGB_CORE_H
#define HW_NET_IGB_CORE_H
#define E1000E_MAC_SIZE (0x8000)
#define IGB_EEPROM_SIZE (1024)
#define IGB_INTR_NUM (25)
#define IGB_MSIX_VEC_NUM (10)
#define IGBVF_MSIX_VEC_NUM (3)
#define IGB_NUM_QUEUES (16)
typedef struct IGBCore IGBCore;
enum { PHY_R = BIT(0),
PHY_W = BIT(1),
PHY_RW = PHY_R | PHY_W };
typedef struct IGBIntrDelayTimer_st {
QEMUTimer *timer;
bool running;
uint32_t delay_reg;
uint32_t delay_resolution_ns;
IGBCore *core;
} IGBIntrDelayTimer;
struct IGBCore {
uint32_t mac[E1000E_MAC_SIZE];
uint16_t phy[MAX_PHY_REG_ADDRESS + 1];
uint16_t eeprom[IGB_EEPROM_SIZE];
uint8_t rx_desc_len;
QEMUTimer *autoneg_timer;
struct igb_tx {
uint16_t vlan; /* VLAN Tag */
uint16_t mss; /* Maximum Segment Size */
bool tse; /* TCP/UDP Segmentation Enable */
bool ixsm; /* Insert IP Checksum */
bool txsm; /* Insert TCP/UDP Checksum */
bool first;
bool skip_cp;
struct NetTxPkt *tx_pkt;
} tx[IGB_NUM_QUEUES];
struct NetRxPkt *rx_pkt;
bool has_vnet;
int max_queue_num;
IGBIntrDelayTimer eitr[IGB_INTR_NUM];
VMChangeStateEntry *vmstate;
uint32_t eitr_guest_value[IGB_INTR_NUM];
uint8_t permanent_mac[ETH_ALEN];
NICState *owner_nic;
PCIDevice *owner;
void (*owner_start_recv)(PCIDevice *d);
int64_t timadj;
};
void
igb_core_write(IGBCore *core, hwaddr addr, uint64_t val, unsigned size);
uint64_t
igb_core_read(IGBCore *core, hwaddr addr, unsigned size);
void
igb_core_pci_realize(IGBCore *regs,
const uint16_t *eeprom_templ,
uint32_t eeprom_size,
const uint8_t *macaddr);
void
igb_core_reset(IGBCore *core);
void
igb_core_pre_save(IGBCore *core);
int
igb_core_post_load(IGBCore *core);
void
igb_core_set_link_status(IGBCore *core);
void
igb_core_pci_uninit(IGBCore *core);
bool
igb_can_receive(IGBCore *core);
ssize_t
igb_receive(IGBCore *core, const uint8_t *buf, size_t size);
ssize_t
igb_receive_iov(IGBCore *core, const struct iovec *iov, int iovcnt);
void
igb_start_recv(IGBCore *core);
#endif

648
hw/net/igb_regs.h Normal file
View File

@ -0,0 +1,648 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This is copied + edited from kernel header files in
* drivers/net/ethernet/intel/igb
*/
#ifndef HW_IGB_REGS_H_
#define HW_IGB_REGS_H_
#include "e1000x_regs.h"
/* from igb/e1000_hw.h */
#define E1000_DEV_ID_82576 0x10C9
#define E1000_DEV_ID_82576_FIBER 0x10E6
#define E1000_DEV_ID_82576_SERDES 0x10E7
#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8
#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526
#define E1000_DEV_ID_82576_NS 0x150A
#define E1000_DEV_ID_82576_NS_SERDES 0x1518
#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
/* Context Descriptor */
struct e1000_adv_tx_context_desc {
uint32_t vlan_macip_lens;
uint32_t seqnum_seed;
uint32_t type_tucmd_mlhl;
uint32_t mss_l4len_idx;
};
/* Advanced Transmit Descriptor */
union e1000_adv_tx_desc {
struct {
uint64_t buffer_addr; /* Address of descriptor's data buffer */
uint32_t cmd_type_len;
uint32_t olinfo_status;
} read;
struct {
uint64_t rsvd; /* Reserved */
uint32_t nxtseq_seed;
uint32_t status;
} wb;
};
#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor Extension (1=Adv) */
#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP/UDP Segmentation Enable */
#define E1000_ADVTXD_POTS_IXSM 0x00000100 /* Insert TCP/UDP Checksum */
#define E1000_ADVTXD_POTS_TXSM 0x00000200 /* Insert TCP/UDP Checksum */
#define E1000_TXD_POPTS_IXSM 0x00000001 /* Insert IP checksum */
#define E1000_TXD_POPTS_TXSM 0x00000002 /* Insert TCP/UDP checksum */
/* Receive Descriptor - Advanced */
union e1000_adv_rx_desc {
struct {
uint64_t pkt_addr; /* Packet Buffer Address */
uint64_t hdr_addr; /* Header Buffer Address */
} read;
struct {
struct {
struct {
uint16_t pkt_info; /* RSS Type, Packet Type */
uint16_t hdr_info; /* Split Head, Buffer Length */
} lo_dword;
union {
uint32_t rss; /* RSS Hash */
struct {
uint16_t ip_id; /* IP Id */
uint16_t csum; /* Packet Checksum */
} csum_ip;
} hi_dword;
} lower;
struct {
uint32_t status_error; /* Ext Status/Error */
uint16_t length; /* Packet Length */
uint16_t vlan; /* VLAN tag */
} upper;
} wb; /* writeback */
};
/* from igb/e1000_phy.h */
/* IGP01E1000 Specific Registers */
#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */
#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */
#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */
#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */
#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */
#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
#define IGP01E1000_PHY_POLARITY_MASK 0x0078
#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */
#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
/* Enable flexible speed on link-up */
#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */
#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */
#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000
#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
#define IGP01E1000_PSSR_MDIX 0x0800
#define IGP01E1000_PSSR_SPEED_MASK 0xC000
#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000
#define IGP02E1000_PHY_CHANNEL_NUM 4
#define IGP02E1000_PHY_AGC_A 0x11B1
#define IGP02E1000_PHY_AGC_B 0x12B1
#define IGP02E1000_PHY_AGC_C 0x14B1
#define IGP02E1000_PHY_AGC_D 0x18B1
#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */
#define IGP02E1000_AGC_LENGTH_MASK 0x7F
#define IGP02E1000_AGC_RANGE 15
/* from igb/igb.h */
#define E1000_PCS_CFG_IGN_SD 1
/* Interrupt defines */
#define IGB_START_ITR 648 /* ~6000 ints/sec */
#define IGB_4K_ITR 980
#define IGB_20K_ITR 196
#define IGB_70K_ITR 56
/* TX/RX descriptor defines */
#define IGB_DEFAULT_TXD 256
#define IGB_DEFAULT_TX_WORK 128
#define IGB_MIN_TXD 80
#define IGB_MAX_TXD 4096
#define IGB_DEFAULT_RXD 256
#define IGB_MIN_RXD 80
#define IGB_MAX_RXD 4096
#define IGB_DEFAULT_ITR 3 /* dynamic */
#define IGB_MAX_ITR_USECS 10000
#define IGB_MIN_ITR_USECS 10
#define NON_Q_VECTORS 1
#define MAX_Q_VECTORS 8
#define MAX_MSIX_ENTRIES 10
/* Transmit and receive queues */
#define IGB_MAX_RX_QUEUES 8
#define IGB_MAX_RX_QUEUES_82575 4
#define IGB_MAX_RX_QUEUES_I211 2
#define IGB_MAX_TX_QUEUES 8
#define IGB_MAX_VF_MC_ENTRIES 30
#define IGB_MAX_VF_FUNCTIONS 8
#define IGB_MAX_VFTA_ENTRIES 128
#define IGB_82576_VF_DEV_ID 0x10CA
#define IGB_I350_VF_DEV_ID 0x1520
/* from igb/e1000_82575.h */
#define E1000_MRQC_ENABLE_RSS_MQ 0x00000002
#define E1000_MRQC_ENABLE_VMDQ 0x00000003
#define E1000_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
#define E1000_MRQC_ENABLE_VMDQ_RSS_MQ 0x00000005
#define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000
/* Additional Receive Descriptor Control definitions */
#define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Rx Queue */
/* Direct Cache Access (DCA) definitions */
#define E1000_DCA_CTRL_DCA_MODE_DISABLE 0x01 /* DCA Disable */
#define E1000_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */
#define E1000_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
#define E1000_DCA_RXCTRL_DESC_DCA_EN BIT(5) /* DCA Rx Desc enable */
#define E1000_DCA_RXCTRL_HEAD_DCA_EN BIT(6) /* DCA Rx Desc header enable */
#define E1000_DCA_RXCTRL_DATA_DCA_EN BIT(7) /* DCA Rx Desc payload enable */
#define E1000_DCA_RXCTRL_DESC_RRO_EN BIT(9) /* DCA Rx rd Desc Relax Order */
#define E1000_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
#define E1000_DCA_TXCTRL_DESC_DCA_EN BIT(5) /* DCA Tx Desc enable */
#define E1000_DCA_TXCTRL_DESC_RRO_EN BIT(9) /* Tx rd Desc Relax Order */
#define E1000_DCA_TXCTRL_TX_WB_RO_EN BIT(11) /* Tx Desc writeback RO bit */
#define E1000_DCA_TXCTRL_DATA_RRO_EN BIT(13) /* Tx rd data Relax Order */
/* Additional DCA related definitions, note change in position of CPUID */
#define E1000_DCA_TXCTRL_CPUID_MASK_82576 0xFF000000 /* Tx CPUID Mask */
#define E1000_DCA_RXCTRL_CPUID_MASK_82576 0xFF000000 /* Rx CPUID Mask */
#define E1000_DCA_TXCTRL_CPUID_SHIFT 24 /* Tx CPUID now in the last byte */
#define E1000_DCA_RXCTRL_CPUID_SHIFT 24 /* Rx CPUID now in the last byte */
#define E1000_DTXSWC_MAC_SPOOF_MASK 0x000000FF /* Per VF MAC spoof control */
#define E1000_DTXSWC_VLAN_SPOOF_MASK 0x0000FF00 /* Per VF VLAN spoof control */
#define E1000_DTXSWC_LLE_MASK 0x00FF0000 /* Per VF Local LB enables */
#define E1000_DTXSWC_VLAN_SPOOF_SHIFT 8
#define E1000_DTXSWC_VMDQ_LOOPBACK_EN BIT(31) /* global VF LB enable */
/* Easy defines for setting default pool, would normally be left a zero */
#define E1000_VT_CTL_DEFAULT_POOL_SHIFT 7
#define E1000_VT_CTL_DEFAULT_POOL_MASK (0x7 << E1000_VT_CTL_DEFAULT_POOL_SHIFT)
/* Other useful VMD_CTL register defines */
#define E1000_VT_CTL_IGNORE_MAC BIT(28)
#define E1000_VT_CTL_DISABLE_DEF_POOL BIT(29)
#define E1000_VT_CTL_VM_REPL_EN BIT(30)
/* Per VM Offload register setup */
#define E1000_VMOLR_RLPML_MASK 0x00003FFF /* Long Packet Maximum Length mask */
#define E1000_VMOLR_LPE 0x00010000 /* Accept Long packet */
#define E1000_VMOLR_RSSE 0x00020000 /* Enable RSS */
#define E1000_VMOLR_AUPE 0x01000000 /* Accept untagged packets */
#define E1000_VMOLR_ROMPE 0x02000000 /* Accept overflow multicast */
#define E1000_VMOLR_ROPE 0x04000000 /* Accept overflow unicast */
#define E1000_VMOLR_BAM 0x08000000 /* Accept Broadcast packets */
#define E1000_VMOLR_MPME 0x10000000 /* Multicast promiscuous mode */
#define E1000_VMOLR_STRVLAN 0x40000000 /* Vlan stripping enable */
#define E1000_VMOLR_STRCRC 0x80000000 /* CRC stripping enable */
#define E1000_DVMOLR_HIDEVLAN 0x20000000 /* Hide vlan enable */
#define E1000_DVMOLR_STRVLAN 0x40000000 /* Vlan stripping enable */
#define E1000_DVMOLR_STRCRC 0x80000000 /* CRC stripping enable */
#define E1000_VLVF_ARRAY_SIZE 32
#define E1000_VLVF_VLANID_MASK 0x00000FFF
#define E1000_VLVF_POOLSEL_SHIFT 12
#define E1000_VLVF_POOLSEL_MASK (0xFF << E1000_VLVF_POOLSEL_SHIFT)
#define E1000_VLVF_LVLAN 0x00100000
#define E1000_VLVF_VLANID_ENABLE 0x80000000
#define E1000_VMVIR_VLANA_DEFAULT 0x40000000 /* Always use default VLAN */
#define E1000_VMVIR_VLANA_NEVER 0x80000000 /* Never insert VLAN tag */
#define E1000_IOVCTL 0x05BBC
#define E1000_IOVCTL_REUSE_VFQ 0x00000001
#define E1000_RPLOLR_STRVLAN 0x40000000
#define E1000_RPLOLR_STRCRC 0x80000000
#define E1000_DTXCTL_8023LL 0x0004
#define E1000_DTXCTL_VLAN_ADDED 0x0008
#define E1000_DTXCTL_OOS_ENABLE 0x0010
#define E1000_DTXCTL_MDP_EN 0x0020
#define E1000_DTXCTL_SPOOF_INT 0x0040
/* from igb/e1000_defines.h */
#define E1000_IVAR_VALID 0x80
#define E1000_GPIE_NSICR 0x00000001
#define E1000_GPIE_MSIX_MODE 0x00000010
#define E1000_GPIE_EIAME 0x40000000
#define E1000_GPIE_PBA 0x80000000
/* Transmit Control */
#define E1000_TCTL_EN 0x00000002 /* enable tx */
#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
/* Collision related configuration parameters */
#define E1000_COLLISION_THRESHOLD 15
#define E1000_CT_SHIFT 4
#define E1000_COLLISION_DISTANCE 63
#define E1000_COLD_SHIFT 12
#define E1000_RAH_POOL_MASK 0x03FC0000
#define E1000_RAH_POOL_1 0x00040000
#define E1000_ICR_VMMB 0x00000100 /* VM MB event */
#define E1000_ICR_TS 0x00080000 /* Time Sync Interrupt */
#define E1000_ICR_DRSTA 0x40000000 /* Device Reset Asserted */
/* If this bit asserted, the driver should claim the interrupt */
#define E1000_ICR_INT_ASSERTED 0x80000000
/* LAN connected device generates an interrupt */
#define E1000_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */
/* Extended Interrupt Cause Read */
#define E1000_EICR_RX_QUEUE0 0x00000001 /* Rx Queue 0 Interrupt */
#define E1000_EICR_RX_QUEUE1 0x00000002 /* Rx Queue 1 Interrupt */
#define E1000_EICR_RX_QUEUE2 0x00000004 /* Rx Queue 2 Interrupt */
#define E1000_EICR_RX_QUEUE3 0x00000008 /* Rx Queue 3 Interrupt */
#define E1000_EICR_TX_QUEUE0 0x00000100 /* Tx Queue 0 Interrupt */
#define E1000_EICR_TX_QUEUE1 0x00000200 /* Tx Queue 1 Interrupt */
#define E1000_EICR_TX_QUEUE2 0x00000400 /* Tx Queue 2 Interrupt */
#define E1000_EICR_TX_QUEUE3 0x00000800 /* Tx Queue 3 Interrupt */
#define E1000_EICR_OTHER 0x80000000 /* Interrupt Cause Active */
/* Extended Interrupt Cause Set */
/* E1000_EITR_CNT_IGNR is only for 82576 and newer */
#define E1000_EITR_CNT_IGNR 0x80000000 /* Don't reset counters on write */
/* PCI Express Control */
#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000
#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000
#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000
#define E1000_GCR_CAP_VER2 0x00040000
#define PHY_REVISION_MASK 0xFFFFFFF0
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
#define MAX_PHY_MULTI_PAGE_REG 0xF
#define IGP03E1000_E_PHY_ID 0x02A80390
/* from igb/e1000_mbox.h */
#define E1000_P2VMAILBOX_STS 0x00000001 /* Initiate message send to VF */
#define E1000_P2VMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */
#define E1000_P2VMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */
#define E1000_P2VMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */
#define E1000_P2VMAILBOX_RVFU 0x00000010 /* Reset VFU - used when VF stuck */
#define E1000_MBVFICR_VFREQ_MASK 0x000000FF /* bits for VF messages */
#define E1000_MBVFICR_VFREQ_VF1 0x00000001 /* bit for VF 1 message */
#define E1000_MBVFICR_VFACK_MASK 0x00FF0000 /* bits for VF acks */
#define E1000_MBVFICR_VFACK_VF1 0x00010000 /* bit for VF 1 ack */
#define E1000_V2PMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
/*
* If it's a E1000_VF_* msg then it originates in the VF and is sent to the
* PF. The reverse is true if it is E1000_PF_*.
* Message ACK's are the value or'd with 0xF0000000
*/
/* Messages below or'd with this are the ACK */
#define E1000_VT_MSGTYPE_ACK 0x80000000
/* Messages below or'd with this are the NACK */
#define E1000_VT_MSGTYPE_NACK 0x40000000
/* Indicates that VF is still clear to send requests */
#define E1000_VT_MSGTYPE_CTS 0x20000000
#define E1000_VT_MSGINFO_SHIFT 16
/* bits 23:16 are used for exra info for certain messages */
#define E1000_VT_MSGINFO_MASK (0xFF << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_RESET 0x01 /* VF requests reset */
#define E1000_VF_SET_MAC_ADDR 0x02 /* VF requests to set MAC addr */
/* VF requests to clear all unicast MAC filters */
#define E1000_VF_MAC_FILTER_CLR (0x01 << E1000_VT_MSGINFO_SHIFT)
/* VF requests to add unicast MAC filter */
#define E1000_VF_MAC_FILTER_ADD (0x02 << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_SET_MULTICAST 0x03 /* VF requests to set MC addr */
#define E1000_VF_SET_VLAN 0x04 /* VF requests to set VLAN */
#define E1000_VF_SET_LPE 0x05 /* VF requests to set VMOLR.LPE */
#define E1000_VF_SET_PROMISC 0x06 /*VF requests to clear VMOLR.ROPE/MPME*/
#define E1000_VF_SET_PROMISC_MULTICAST (0x02 << E1000_VT_MSGINFO_SHIFT)
#define E1000_PF_CONTROL_MSG 0x0100 /* PF control message */
/* from igb/e1000_regs.h */
#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */
#define E1000_EITR(_n) (0x01680 + (0x4 * (_n)))
#define E1000_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */
#define E1000_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */
#define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */
#define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */
#define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */
#define E1000_GPIE 0x01514 /* General Purpose Interrupt Enable; RW */
#define E1000_IVAR0 0x01700 /* Interrupt Vector Allocation Register - RW */
#define E1000_IVAR_MISC 0x01740 /* Interrupt Vector Allocation Register (last) - RW */
#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */
#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */
#define E1000_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
#define E1000_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */
#define E1000_DTXCTL 0x03590 /* DMA TX Control - RW */
#define E1000_HTCBDPC 0x04124 /* Host TX Circuit Breaker Dropped Count */
#define E1000_RLPML 0x05004 /* RX Long Packet Max Length */
#define E1000_RA2 0x054E0 /* 2nd half of Rx address array - RW Array */
#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4))
#define E1000_VT_CTL 0x0581C /* VMDq Control - RW */
/* VT Registers */
#define E1000_MBVFICR 0x00C80 /* Mailbox VF Cause - RWC */
#define E1000_MBVFIMR 0x00C84 /* Mailbox VF int Mask - RW */
#define E1000_VFLRE 0x00C88 /* VF Register Events - RWC */
#define E1000_VFRE 0x00C8C /* VF Receive Enables */
#define E1000_VFTE 0x00C90 /* VF Transmit Enables */
#define E1000_QDE 0x02408 /* Queue Drop Enable - RW */
#define E1000_DTXSWC 0x03500 /* DMA Tx Switch Control - RW */
#define E1000_WVBR 0x03554 /* VM Wrong Behavior - RWS */
#define E1000_RPLOLR 0x05AF0 /* Replication Offload - RW */
#define E1000_UTA 0x0A000 /* Unicast Table Array - RW */
#define E1000_IOVTCL 0x05BBC /* IOV Control Register */
#define E1000_TXSWC 0x05ACC /* Tx Switch Control */
#define E1000_LVMMC 0x03548 /* Last VM Misbehavior cause */
/* These act per VF so an array friendly macro is used */
#define E1000_P2VMAILBOX(_n) (0x00C00 + (4 * (_n)))
#define E1000_VMBMEM(_n) (0x00800 + (64 * (_n)))
#define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n)))
#define E1000_DVMOLR(_n) (0x0C038 + (64 * (_n)))
#define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN VM Filter */
#define E1000_VMVIR(_n) (0x03700 + (4 * (_n)))
/* from igbvf/defines.h */
/* SRRCTL bit definitions */
#define E1000_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */
#define E1000_SRRCTL_BSIZEHDRSIZE_MASK 0x00000F00
#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
#define E1000_SRRCTL_DESCTYPE_MASK 0x0E000000
#define E1000_SRRCTL_DROP_EN 0x80000000
#define E1000_SRRCTL_BSIZEPKT_MASK 0x0000007F
#define E1000_SRRCTL_BSIZEHDR_MASK 0x00003F00
/* from igbvf/mbox.h */
#define E1000_V2PMAILBOX_REQ 0x00000001 /* Request for PF Ready bit */
#define E1000_V2PMAILBOX_ACK 0x00000002 /* Ack PF message received */
#define E1000_V2PMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */
#define E1000_V2PMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */
#define E1000_V2PMAILBOX_PFSTS 0x00000010 /* PF wrote a message in the MB */
#define E1000_V2PMAILBOX_PFACK 0x00000020 /* PF ack the previous VF msg */
#define E1000_V2PMAILBOX_RSTI 0x00000040 /* PF has reset indication */
#define E1000_V2PMAILBOX_RSTD 0x00000080 /* PF has indicated reset done */
#define E1000_V2PMAILBOX_R2C_BITS 0x000000B0 /* All read to clear bits */
#define E1000_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
/*
* If it's a E1000_VF_* msg then it originates in the VF and is sent to the
* PF. The reverse is true if it is E1000_PF_*.
* Message ACK's are the value or'd with 0xF0000000
*/
/* Messages below or'd with this are the ACK */
#define E1000_VT_MSGTYPE_ACK 0x80000000
/* Messages below or'd with this are the NACK */
#define E1000_VT_MSGTYPE_NACK 0x40000000
/* Indicates that VF is still clear to send requests */
#define E1000_VT_MSGTYPE_CTS 0x20000000
/* We have a total wait time of 1s for vf mailbox posted messages */
#define E1000_VF_MBX_INIT_TIMEOUT 2000 /* retry count for mbx timeout */
#define E1000_VF_MBX_INIT_DELAY 500 /* usec delay between retries */
#define E1000_VT_MSGINFO_SHIFT 16
/* bits 23:16 are used for exra info for certain messages */
#define E1000_VT_MSGINFO_MASK (0xFF << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_RESET 0x01 /* VF requests reset */
#define E1000_VF_SET_MAC_ADDR 0x02 /* VF requests PF to set MAC addr */
/* VF requests PF to clear all unicast MAC filters */
#define E1000_VF_MAC_FILTER_CLR (0x01 << E1000_VT_MSGINFO_SHIFT)
/* VF requests PF to add unicast MAC filter */
#define E1000_VF_MAC_FILTER_ADD (0x02 << E1000_VT_MSGINFO_SHIFT)
#define E1000_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */
#define E1000_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */
#define E1000_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */
#define E1000_PF_CONTROL_MSG 0x0100 /* PF control message */
/* from igbvf/regs.h */
/* Statistics registers */
#define E1000_VFGPRC 0x00F10
#define E1000_VFGORC 0x00F18
#define E1000_VFMPRC 0x00F3C
#define E1000_VFGPTC 0x00F14
#define E1000_VFGOTC 0x00F34
#define E1000_VFGOTLBC 0x00F50
#define E1000_VFGPTLBC 0x00F44
#define E1000_VFGORLBC 0x00F48
#define E1000_VFGPRLBC 0x00F40
/* These act per VF so an array friendly macro is used */
#define E1000_V2PMAILBOX(_n) (0x00C40 + (4 * (_n)))
#define E1000_VMBMEM(_n) (0x00800 + (64 * (_n)))
/* from igbvf/vf.h */
#define E1000_DEV_ID_82576_VF 0x10CA
/* new */
/* Receive Registers */
/* RX Descriptor Base Low; RW */
#define E1000_RDBAL(_n) (0x0C000 + (0x40 * (_n)))
#define E1000_RDBAL_A(_n) (0x02800 + (0x100 * (_n)))
/* RX Descriptor Base High; RW */
#define E1000_RDBAH(_n) (0x0C004 + (0x40 * (_n)))
#define E1000_RDBAH_A(_n) (0x02804 + (0x100 * (_n)))
/* RX Descriptor Ring Length; RW */
#define E1000_RDLEN(_n) (0x0C008 + (0x40 * (_n)))
#define E1000_RDLEN_A(_n) (0x02808 + (0x100 * (_n)))
/* Split and Replication Receive Control; RW */
#define E1000_SRRCTL(_n) (0x0C00C + (0x40 * (_n)))
#define E1000_SRRCTL_A(_n) (0x0280C + (0x100 * (_n)))
/* RX Descriptor Head; RW */
#define E1000_RDH(_n) (0x0C010 + (0x40 * (_n)))
#define E1000_RDH_A(_n) (0x02810 + (0x100 * (_n)))
/* RX DCA Control; RW */
#define E1000_RXCTL(_n) (0x0C014 + (0x40 * (_n)))
#define E1000_RXCTL_A(_n) (0x02814 + (0x100 * (_n)))
/* RX Descriptor Tail; RW */
#define E1000_RDT(_n) (0x0C018 + (0x40 * (_n)))
#define E1000_RDT_A(_n) (0x02818 + (0x100 * (_n)))
/* RX Descriptor Control; RW */
#define E1000_RXDCTL(_n) (0x0C028 + (0x40 * (_n)))
#define E1000_RXDCTL_A(_n) (0x02828 + (0x100 * (_n)))
/* RX Queue Drop Packet Count; RC */
#define E1000_RQDPC_A(_n) (0x02830 + (0x100 * (_n)))
/* Transmit Registers */
/* TX Descriptor Base Low; RW */
#define E1000_TDBAL(_n) (0x0E000 + (0x40 * (_n)))
#define E1000_TDBAL_A(_n) (0x03800 + (0x100 * (_n)))
/* TX Descriptor Base High; RW */
#define E1000_TDBAH(_n) (0x0E004 + (0x40 * (_n)))
#define E1000_TDBAH_A(_n) (0x03804 + (0x100 * (_n)))
/* TX Descriptor Ring Length; RW */
#define E1000_TDLEN(_n) (0x0E008 + (0x40 * (_n)))
#define E1000_TDLEN_A(_n) (0x03808 + (0x100 * (_n)))
/* TX Descriptor Head; RW */
#define E1000_TDH(_n) (0x0E010 + (0x40 * (_n)))
#define E1000_TDH_A(_n) (0x03810 + (0x100 * (_n)))
/* TX DCA Control; RW */
#define E1000_TXCTL(_n) (0x0E014 + (0x40 * (_n)))
#define E1000_TXCTL_A(_n) (0x03814 + (0x100 * (_n)))
/* TX Descriptor Tail; RW */
#define E1000_TDT(_n) (0x0E018 + (0x40 * (_n)))
#define E1000_TDT_A(_n) (0x03818 + (0x100 * (_n)))
/* TX Descriptor Control; RW */
#define E1000_TXDCTL(_n) (0x0E028 + (0x40 * (_n)))
#define E1000_TXDCTL_A(_n) (0x03828 + (0x100 * (_n)))
/* TX Descriptor Completion WriteBack Address Low; RW */
#define E1000_TDWBAL(_n) (0x0E038 + (0x40 * (_n)))
#define E1000_TDWBAL_A(_n) (0x03838 + (0x100 * (_n)))
/* TX Descriptor Completion WriteBack Address High; RW */
#define E1000_TDWBAH(_n) (0x0E03C + (0x40 * (_n)))
#define E1000_TDWBAH_A(_n) (0x0383C + (0x100 * (_n)))
#define E1000_MTA_A 0x0200
#define E1000_XDBAL_MASK (~(BIT(5) - 1)) /* TDBAL and RDBAL Registers Mask */
#define E1000_ICR_MACSEC 0x00000020 /* MACSec */
#define E1000_ICR_RX0 0x00000040 /* Receiver Overrun */
#define E1000_ICR_GPI_SDP0 0x00000800 /* General Purpose, SDP0 pin */
#define E1000_ICR_GPI_SDP1 0x00001000 /* General Purpose, SDP1 pin */
#define E1000_ICR_GPI_SDP2 0x00002000 /* General Purpose, SDP2 pin */
#define E1000_ICR_GPI_SDP3 0x00004000 /* General Purpose, SDP3 pin */
#define E1000_ICR_PTRAP 0x00008000 /* Probe Trap */
#define E1000_ICR_MNG 0x00040000 /* Management Event */
#define E1000_ICR_OMED 0x00100000 /* Other Media Energy Detected */
#define E1000_ICR_FER 0x00400000 /* Fatal Error */
#define E1000_ICR_NFER 0x00800000 /* Non Fatal Error */
#define E1000_ICR_CSRTO 0x01000000 /* CSR access Time Out Indication */
#define E1000_ICR_SCE 0x02000000 /* Storm Control Event */
#define E1000_ICR_SW_WD 0x04000000 /* Software Watchdog */
/* Extended Interrupts */
#define E1000_EICR_MSIX_MASK 0x01FFFFFF /* Bits used in MSI-X mode */
#define E1000_EICR_LEGACY_MASK 0x4000FFFF /* Bits used in non MSI-X mode */
/* Mirror VF Control (only RST bit); RW */
#define E1000_PVTCTRL(_n) (0x10000 + (_n) * 0x100)
/* Mirror Good Packets Received Count; RO */
#define E1000_PVFGPRC(_n) (0x10010 + (_n) * 0x100)
/* Mirror Good Packets Transmitted Count; RO */
#define E1000_PVFGPTC(_n) (0x10014 + (_n) * 0x100)
/* Mirror Good Octets Received Count; RO */
#define E1000_PVFGORC(_n) (0x10018 + (_n) * 0x100)
/* Mirror Extended Interrupt Cause Set; WO */
#define E1000_PVTEICS(_n) (0x10020 + (_n) * 0x100)
/* Mirror Extended Interrupt Mask Set/Read; RW */
#define E1000_PVTEIMS(_n) (0x10024 + (_n) * 0x100)
/* Mirror Extended Interrupt Mask Clear; WO */
#define E1000_PVTEIMC(_n) (0x10028 + (_n) * 0x100)
/* Mirror Extended Interrupt Auto Clear; RW */
#define E1000_PVTEIAC(_n) (0x1002C + (_n) * 0x100)
/* Mirror Extended Interrupt Auto Mask Enable; RW */
#define E1000_PVTEIAM(_n) (0x10030 + (_n) * 0x100)
/* Mirror Good Octets Transmitted Count; RO */
#define E1000_PVFGOTC(_n) (0x10034 + (_n) * 0x100)
/* Mirror Multicast Packets Received Count; RO */
#define E1000_PVFMPRC(_n) (0x1003C + (_n) * 0x100)
/* Mirror Good RX Packets loopback Count; RO */
#define E1000_PVFGPRLBC(_n) (0x10040 + (_n) * 0x100)
/* Mirror Good TX packets loopback Count; RO */
#define E1000_PVFGPTLBC(_n) (0x10044 + (_n) * 0x100)
/* Mirror Good RX Octets loopback Count; RO */
#define E1000_PVFGORLBC(_n) (0x10048 + (_n) * 0x100)
/* Mirror Good TX Octets loopback Count; RO */
#define E1000_PVFGOTLBC(_n) (0x10050 + (_n) * 0x100)
/* Mirror Extended Interrupt Cause Set; RC/W1C */
#define E1000_PVTEICR(_n) (0x10080 + (_n) * 0x100)
/*
* These are fake addresses that, according to the specification, the device
* is not using. They are used to distinguish between the PF and the VFs
* accessing their VTIVAR register (which is the same address, 0x1700)
*/
#define E1000_VTIVAR 0x11700
#define E1000_VTIVAR_MISC 0x11720
#define E1000_RSS_QUEUE(reta, hash) (E1000_RETA_VAL(reta, hash) & 0x0F)
#define E1000_STATUS_IOV_MODE 0x00040000
#define E1000_STATUS_NUM_VFS_SHIFT 14
static inline uint8_t igb_ivar_entry_rx(uint8_t i)
{
return i < 8 ? i * 4 : (i - 8) * 4 + 2;
}
static inline uint8_t igb_ivar_entry_tx(uint8_t i)
{
return i < 8 ? i * 4 + 1 : (i - 8) * 4 + 3;
}
#endif

327
hw/net/igbvf.c Normal file
View File

@ -0,0 +1,327 @@
/*
* QEMU Intel 82576 SR/IOV Ethernet Controller Emulation
*
* Datasheet:
* https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eg-gbe-datasheet.pdf
*
* Copyright (c) 2020-2023 Red Hat, Inc.
* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
* Developed by Daynix Computing LTD (http://www.daynix.com)
*
* Authors:
* Akihiko Odaki <akihiko.odaki@daynix.com>
* Gal Hammmer <gal.hammer@sap.com>
* Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
* Dmitry Fleytman <dmitry@daynix.com>
* Leonid Bloch <leonid@daynix.com>
* Yan Vugenfirer <yan@daynix.com>
*
* Based on work done by:
* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
* Copyright (c) 2008 Qumranet
* Based on work done by:
* Copyright (c) 2007 Dan Aloni
* Copyright (c) 2004 Antony T Curtis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/net/mii.h"
#include "hw/pci/pci_device.h"
#include "hw/pci/pcie.h"
#include "hw/pci/msix.h"
#include "net/eth.h"
#include "net/net.h"
#include "igb_common.h"
#include "igb_core.h"
#include "trace.h"
#include "qapi/error.h"
#define TYPE_IGBVF "igbvf"
OBJECT_DECLARE_SIMPLE_TYPE(IgbVfState, IGBVF)
#define IGBVF_MMIO_BAR_IDX (0)
#define IGBVF_MSIX_BAR_IDX (3)
#define IGBVF_MMIO_SIZE (16 * 1024)
#define IGBVF_MSIX_SIZE (16 * 1024)
struct IgbVfState {
PCIDevice parent_obj;
MemoryRegion mmio;
MemoryRegion msix;
};
static hwaddr vf_to_pf_addr(hwaddr addr, uint16_t vfn, bool write)
{
switch (addr) {
case E1000_CTRL:
case E1000_CTRL_DUP:
return E1000_PVTCTRL(vfn);
case E1000_EICS:
return E1000_PVTEICS(vfn);
case E1000_EIMS:
return E1000_PVTEIMS(vfn);
case E1000_EIMC:
return E1000_PVTEIMC(vfn);
case E1000_EIAC:
return E1000_PVTEIAC(vfn);
case E1000_EIAM:
return E1000_PVTEIAM(vfn);
case E1000_EICR:
return E1000_PVTEICR(vfn);
case E1000_EITR(0):
case E1000_EITR(1):
case E1000_EITR(2):
return E1000_EITR(22) + (addr - E1000_EITR(0)) - vfn * 0xC;
case E1000_IVAR0:
return E1000_VTIVAR + vfn * 4;
case E1000_IVAR_MISC:
return E1000_VTIVAR_MISC + vfn * 4;
case 0x0F04: /* PBACL */
return E1000_PBACLR;
case 0x0F0C: /* PSRTYPE */
return E1000_PSRTYPE(vfn);
case E1000_V2PMAILBOX(0):
return E1000_V2PMAILBOX(vfn);
case E1000_VMBMEM(0) ... E1000_VMBMEM(0) + 0x3F:
return addr + vfn * 0x40;
case E1000_RDBAL_A(0):
return E1000_RDBAL(vfn);
case E1000_RDBAL_A(1):
return E1000_RDBAL(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_RDBAH_A(0):
return E1000_RDBAH(vfn);
case E1000_RDBAH_A(1):
return E1000_RDBAH(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_RDLEN_A(0):
return E1000_RDLEN(vfn);
case E1000_RDLEN_A(1):
return E1000_RDLEN(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_SRRCTL_A(0):
return E1000_SRRCTL(vfn);
case E1000_SRRCTL_A(1):
return E1000_SRRCTL(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_RDH_A(0):
return E1000_RDH(vfn);
case E1000_RDH_A(1):
return E1000_RDH(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_RXCTL_A(0):
return E1000_RXCTL(vfn);
case E1000_RXCTL_A(1):
return E1000_RXCTL(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_RDT_A(0):
return E1000_RDT(vfn);
case E1000_RDT_A(1):
return E1000_RDT(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_RXDCTL_A(0):
return E1000_RXDCTL(vfn);
case E1000_RXDCTL_A(1):
return E1000_RXDCTL(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_RQDPC_A(0):
return E1000_RQDPC(vfn);
case E1000_RQDPC_A(1):
return E1000_RQDPC(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_TDBAL_A(0):
return E1000_TDBAL(vfn);
case E1000_TDBAL_A(1):
return E1000_TDBAL(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_TDBAH_A(0):
return E1000_TDBAH(vfn);
case E1000_TDBAH_A(1):
return E1000_TDBAH(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_TDLEN_A(0):
return E1000_TDLEN(vfn);
case E1000_TDLEN_A(1):
return E1000_TDLEN(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_TDH_A(0):
return E1000_TDH(vfn);
case E1000_TDH_A(1):
return E1000_TDH(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_TXCTL_A(0):
return E1000_TXCTL(vfn);
case E1000_TXCTL_A(1):
return E1000_TXCTL(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_TDT_A(0):
return E1000_TDT(vfn);
case E1000_TDT_A(1):
return E1000_TDT(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_TXDCTL_A(0):
return E1000_TXDCTL(vfn);
case E1000_TXDCTL_A(1):
return E1000_TXDCTL(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_TDWBAL_A(0):
return E1000_TDWBAL(vfn);
case E1000_TDWBAL_A(1):
return E1000_TDWBAL(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_TDWBAH_A(0):
return E1000_TDWBAH(vfn);
case E1000_TDWBAH_A(1):
return E1000_TDWBAH(vfn + IGB_MAX_VF_FUNCTIONS);
case E1000_VFGPRC:
return E1000_PVFGPRC(vfn);
case E1000_VFGPTC:
return E1000_PVFGPTC(vfn);
case E1000_VFGORC:
return E1000_PVFGORC(vfn);
case E1000_VFGOTC:
return E1000_PVFGOTC(vfn);
case E1000_VFMPRC:
return E1000_PVFMPRC(vfn);
case E1000_VFGPRLBC:
return E1000_PVFGPRLBC(vfn);
case E1000_VFGPTLBC:
return E1000_PVFGPTLBC(vfn);
case E1000_VFGORLBC:
return E1000_PVFGORLBC(vfn);
case E1000_VFGOTLBC:
return E1000_PVFGOTLBC(vfn);
case E1000_STATUS:
case E1000_FRTIMER:
if (write) {
return HWADDR_MAX;
}
/* fallthrough */
case 0x34E8: /* PBTWAC */
case 0x24E8: /* PBRWAC */
return addr;
}
trace_igbvf_wrn_io_addr_unknown(addr);
return HWADDR_MAX;
}
static void igbvf_write_config(PCIDevice *dev, uint32_t addr, uint32_t val,
int len)
{
trace_igbvf_write_config(addr, val, len);
pci_default_write_config(dev, addr, val, len);
}
static uint64_t igbvf_mmio_read(void *opaque, hwaddr addr, unsigned size)
{
PCIDevice *vf = PCI_DEVICE(opaque);
PCIDevice *pf = pcie_sriov_get_pf(vf);
addr = vf_to_pf_addr(addr, pcie_sriov_vf_number(vf), false);
return addr == HWADDR_MAX ? 0 : igb_mmio_read(pf, addr, size);
}
static void igbvf_mmio_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
PCIDevice *vf = PCI_DEVICE(opaque);
PCIDevice *pf = pcie_sriov_get_pf(vf);
addr = vf_to_pf_addr(addr, pcie_sriov_vf_number(vf), true);
if (addr != HWADDR_MAX) {
igb_mmio_write(pf, addr, val, size);
}
}
static const MemoryRegionOps mmio_ops = {
.read = igbvf_mmio_read,
.write = igbvf_mmio_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static void igbvf_pci_realize(PCIDevice *dev, Error **errp)
{
IgbVfState *s = IGBVF(dev);
int ret;
int i;
dev->config_write = igbvf_write_config;
memory_region_init_io(&s->mmio, OBJECT(dev), &mmio_ops, s, "igbvf-mmio",
IGBVF_MMIO_SIZE);
pcie_sriov_vf_register_bar(dev, IGBVF_MMIO_BAR_IDX, &s->mmio);
memory_region_init(&s->msix, OBJECT(dev), "igbvf-msix", IGBVF_MSIX_SIZE);
pcie_sriov_vf_register_bar(dev, IGBVF_MSIX_BAR_IDX, &s->msix);
ret = msix_init(dev, IGBVF_MSIX_VEC_NUM, &s->msix, IGBVF_MSIX_BAR_IDX, 0,
&s->msix, IGBVF_MSIX_BAR_IDX, 0x2000, 0x70, errp);
if (ret) {
return;
}
for (i = 0; i < IGBVF_MSIX_VEC_NUM; i++) {
msix_vector_use(dev, i);
}
if (pcie_endpoint_cap_init(dev, 0xa0) < 0) {
hw_error("Failed to initialize PCIe capability");
}
if (pcie_aer_init(dev, 1, 0x100, 0x40, errp) < 0) {
hw_error("Failed to initialize AER capability");
}
pcie_ari_init(dev, 0x150, 1);
}
static void igbvf_pci_uninit(PCIDevice *dev)
{
IgbVfState *s = IGBVF(dev);
pcie_aer_exit(dev);
pcie_cap_exit(dev);
msix_unuse_all_vectors(dev);
msix_uninit(dev, &s->msix, &s->msix);
}
static void igbvf_class_init(ObjectClass *class, void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
c->realize = igbvf_pci_realize;
c->exit = igbvf_pci_uninit;
c->vendor_id = PCI_VENDOR_ID_INTEL;
c->device_id = E1000_DEV_ID_82576_VF;
c->revision = 1;
c->class_id = PCI_CLASS_NETWORK_ETHERNET;
dc->desc = "Intel 82576 Virtual Function";
dc->user_creatable = false;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
static const TypeInfo igbvf_info = {
.name = TYPE_IGBVF,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(IgbVfState),
.class_init = igbvf_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
};
static void igb_register_types(void)
{
type_register_static(&igbvf_info);
}
type_init(igb_register_types)

View File

@ -10,6 +10,8 @@ softmmu_ss.add(when: 'CONFIG_PCNET_COMMON', if_true: files('pcnet.c'))
softmmu_ss.add(when: 'CONFIG_E1000_PCI', if_true: files('e1000.c', 'e1000x_common.c'))
softmmu_ss.add(when: 'CONFIG_E1000E_PCI_EXPRESS', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))
softmmu_ss.add(when: 'CONFIG_E1000E_PCI_EXPRESS', if_true: files('e1000e.c', 'e1000e_core.c', 'e1000x_common.c'))
softmmu_ss.add(when: 'CONFIG_IGB_PCI_EXPRESS', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))
softmmu_ss.add(when: 'CONFIG_IGB_PCI_EXPRESS', if_true: files('igb.c', 'igbvf.c', 'igb_core.c'))
softmmu_ss.add(when: 'CONFIG_RTL8139_PCI', if_true: files('rtl8139.c'))
softmmu_ss.add(when: 'CONFIG_TULIP', if_true: files('tulip.c'))
softmmu_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))

View File

@ -30,14 +30,11 @@ struct NetRxPkt {
uint32_t tot_len;
uint16_t tci;
size_t ehdr_buf_len;
bool has_virt_hdr;
eth_pkt_types_e packet_type;
/* Analysis results */
bool isip4;
bool isip6;
bool isudp;
bool istcp;
bool hasip4;
bool hasip6;
size_t l3hdr_off;
size_t l4hdr_off;
@ -48,10 +45,9 @@ struct NetRxPkt {
eth_l4_hdr_info l4hdr_info;
};
void net_rx_pkt_init(struct NetRxPkt **pkt, bool has_virt_hdr)
void net_rx_pkt_init(struct NetRxPkt **pkt)
{
struct NetRxPkt *p = g_malloc0(sizeof *p);
p->has_virt_hdr = has_virt_hdr;
p->vec = NULL;
p->vec_len_total = 0;
*pkt = p;
@ -107,12 +103,11 @@ net_rx_pkt_pull_data(struct NetRxPkt *pkt,
iov, iovcnt, ploff, pkt->tot_len);
}
eth_get_protocols(pkt->vec, pkt->vec_len, &pkt->isip4, &pkt->isip6,
&pkt->isudp, &pkt->istcp,
eth_get_protocols(pkt->vec, pkt->vec_len, &pkt->hasip4, &pkt->hasip6,
&pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
&pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
trace_net_rx_pkt_parsed(pkt->isip4, pkt->isip6, pkt->isudp, pkt->istcp,
trace_net_rx_pkt_parsed(pkt->hasip4, pkt->hasip6, pkt->l4hdr_info.proto,
pkt->l3hdr_off, pkt->l4hdr_off, pkt->l5hdr_off);
}
@ -201,22 +196,20 @@ void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data,
assert(pkt);
eth_get_protocols(&iov, 1, &pkt->isip4, &pkt->isip6,
&pkt->isudp, &pkt->istcp,
eth_get_protocols(&iov, 1, &pkt->hasip4, &pkt->hasip6,
&pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
&pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
}
void net_rx_pkt_get_protocols(struct NetRxPkt *pkt,
bool *isip4, bool *isip6,
bool *isudp, bool *istcp)
bool *hasip4, bool *hasip6,
EthL4HdrProto *l4hdr_proto)
{
assert(pkt);
*isip4 = pkt->isip4;
*isip6 = pkt->isip6;
*isudp = pkt->isudp;
*istcp = pkt->istcp;
*hasip4 = pkt->hasip4;
*hasip6 = pkt->hasip6;
*l4hdr_proto = pkt->l4hdr_info.proto;
}
size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt)
@ -333,58 +326,58 @@ net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt,
switch (type) {
case NetPktRssIpV4:
assert(pkt->isip4);
assert(pkt->hasip4);
trace_net_rx_pkt_rss_ip4();
_net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length);
break;
case NetPktRssIpV4Tcp:
assert(pkt->isip4);
assert(pkt->istcp);
assert(pkt->hasip4);
assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP);
trace_net_rx_pkt_rss_ip4_tcp();
_net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length);
_net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length);
break;
case NetPktRssIpV6Tcp:
assert(pkt->isip6);
assert(pkt->istcp);
assert(pkt->hasip6);
assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP);
trace_net_rx_pkt_rss_ip6_tcp();
_net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length);
_net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length);
break;
case NetPktRssIpV6:
assert(pkt->isip6);
assert(pkt->hasip6);
trace_net_rx_pkt_rss_ip6();
_net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length);
break;
case NetPktRssIpV6Ex:
assert(pkt->isip6);
assert(pkt->hasip6);
trace_net_rx_pkt_rss_ip6_ex();
_net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length);
break;
case NetPktRssIpV6TcpEx:
assert(pkt->isip6);
assert(pkt->istcp);
assert(pkt->hasip6);
assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP);
trace_net_rx_pkt_rss_ip6_ex_tcp();
_net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length);
_net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length);
break;
case NetPktRssIpV4Udp:
assert(pkt->isip4);
assert(pkt->isudp);
assert(pkt->hasip4);
assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP);
trace_net_rx_pkt_rss_ip4_udp();
_net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length);
_net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
break;
case NetPktRssIpV6Udp:
assert(pkt->isip6);
assert(pkt->isudp);
assert(pkt->hasip6);
assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP);
trace_net_rx_pkt_rss_ip6_udp();
_net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length);
_net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
break;
case NetPktRssIpV6UdpEx:
assert(pkt->isip6);
assert(pkt->isudp);
assert(pkt->hasip6);
assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP);
trace_net_rx_pkt_rss_ip6_ex_udp();
_net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length);
_net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
@ -406,7 +399,7 @@ uint16_t net_rx_pkt_get_ip_id(struct NetRxPkt *pkt)
{
assert(pkt);
if (pkt->isip4) {
if (pkt->hasip4) {
return be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_id);
}
@ -417,7 +410,7 @@ bool net_rx_pkt_is_tcp_ack(struct NetRxPkt *pkt)
{
assert(pkt);
if (pkt->istcp) {
if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) {
return TCP_HEADER_FLAGS(&pkt->l4hdr_info.hdr.tcp) & TCP_FLAG_ACK;
}
@ -428,7 +421,7 @@ bool net_rx_pkt_has_tcp_data(struct NetRxPkt *pkt)
{
assert(pkt);
if (pkt->istcp) {
if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) {
return pkt->l4hdr_info.has_tcp_data;
}
@ -465,6 +458,13 @@ void net_rx_pkt_set_vhdr_iovec(struct NetRxPkt *pkt,
iov_to_buf(iov, iovcnt, 0, &pkt->virt_hdr, sizeof pkt->virt_hdr);
}
void net_rx_pkt_unset_vhdr(struct NetRxPkt *pkt)
{
assert(pkt);
memset(&pkt->virt_hdr, 0, sizeof(pkt->virt_hdr));
}
bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt)
{
assert(pkt);
@ -472,13 +472,6 @@ bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt)
return pkt->ehdr_buf_len ? true : false;
}
bool net_rx_pkt_has_virt_hdr(struct NetRxPkt *pkt)
{
assert(pkt);
return pkt->has_virt_hdr;
}
uint16_t net_rx_pkt_get_vlan_tag(struct NetRxPkt *pkt)
{
assert(pkt);
@ -494,7 +487,7 @@ bool net_rx_pkt_validate_l3_csum(struct NetRxPkt *pkt, bool *csum_valid)
trace_net_rx_pkt_l3_csum_validate_entry();
if (!pkt->isip4) {
if (!pkt->hasip4) {
trace_net_rx_pkt_l3_csum_validate_not_ip4();
return false;
}
@ -525,8 +518,8 @@ _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt)
trace_net_rx_pkt_l4_csum_calc_entry();
if (pkt->isip4) {
if (pkt->isudp) {
if (pkt->hasip4) {
if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) {
csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen);
trace_net_rx_pkt_l4_csum_calc_ip4_udp();
} else {
@ -539,7 +532,7 @@ _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt)
csl, &cso);
trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl);
} else {
if (pkt->isudp) {
if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) {
csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen);
trace_net_rx_pkt_l4_csum_calc_ip6_udp();
} else {
@ -573,17 +566,19 @@ bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid)
trace_net_rx_pkt_l4_csum_validate_entry();
if (!pkt->istcp && !pkt->isudp) {
if (pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_TCP &&
pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_UDP) {
trace_net_rx_pkt_l4_csum_validate_not_xxp();
return false;
}
if (pkt->isudp && (pkt->l4hdr_info.hdr.udp.uh_sum == 0)) {
if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP &&
pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
return false;
}
if (pkt->isip4 && pkt->ip4hdr_info.fragment) {
if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
trace_net_rx_pkt_l4_csum_validate_ip4_fragment();
return false;
}
@ -604,22 +599,27 @@ bool net_rx_pkt_fix_l4_csum(struct NetRxPkt *pkt)
trace_net_rx_pkt_l4_csum_fix_entry();
if (pkt->istcp) {
switch (pkt->l4hdr_info.proto) {
case ETH_L4_HDR_PROTO_TCP:
l4_cso = offsetof(struct tcp_header, th_sum);
trace_net_rx_pkt_l4_csum_fix_tcp(l4_cso);
} else if (pkt->isudp) {
break;
case ETH_L4_HDR_PROTO_UDP:
if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
trace_net_rx_pkt_l4_csum_fix_udp_with_no_checksum();
return false;
}
l4_cso = offsetof(struct udp_header, uh_sum);
trace_net_rx_pkt_l4_csum_fix_udp(l4_cso);
} else {
break;
default:
trace_net_rx_pkt_l4_csum_fix_not_xxp();
return false;
}
if (pkt->isip4 && pkt->ip4hdr_info.fragment) {
if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
trace_net_rx_pkt_l4_csum_fix_ip4_fragment();
return false;
}

View File

@ -37,10 +37,9 @@ void net_rx_pkt_uninit(struct NetRxPkt *pkt);
* Init function for rx packet functionality
*
* @pkt: packet pointer
* @has_virt_hdr: device uses virtio header
*
*/
void net_rx_pkt_init(struct NetRxPkt **pkt, bool has_virt_hdr);
void net_rx_pkt_init(struct NetRxPkt **pkt);
/**
* returns total length of data attached to rx context
@ -67,15 +66,14 @@ void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data,
* fetches packet analysis results
*
* @pkt: packet
* @isip4: whether the packet given is IPv4
* @isip6: whether the packet given is IPv6
* @isudp: whether the packet given is UDP
* @istcp: whether the packet given is TCP
* @hasip4: whether the packet has an IPv4 header
* @hasip6: whether the packet has an IPv6 header
* @l4hdr_proto: protocol of L4 header
*
*/
void net_rx_pkt_get_protocols(struct NetRxPkt *pkt,
bool *isip4, bool *isip6,
bool *isudp, bool *istcp);
bool *hasip4, bool *hasip6,
EthL4HdrProto *l4hdr_proto);
/**
* fetches L3 header offset
@ -214,15 +212,6 @@ uint16_t net_rx_pkt_get_vlan_tag(struct NetRxPkt *pkt);
*/
bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt);
/**
* notifies caller if the packet has virtio header
*
* @pkt: packet
* @ret: true if packet has virtio header, false otherwize
*
*/
bool net_rx_pkt_has_virt_hdr(struct NetRxPkt *pkt);
/**
* attach scatter-gather data to rx packet
*
@ -322,6 +311,14 @@ void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt,
void net_rx_pkt_set_vhdr_iovec(struct NetRxPkt *pkt,
const struct iovec *iov, int iovcnt);
/**
* unset vhdr data from packet context
*
* @pkt: packet
*
*/
void net_rx_pkt_unset_vhdr(struct NetRxPkt *pkt);
/**
* save packet type in packet context
*

View File

@ -35,7 +35,6 @@ struct NetTxPkt {
PCIDevice *pci_dev;
struct virtio_net_hdr virt_hdr;
bool has_virt_hdr;
struct iovec *raw;
uint32_t raw_frags;
@ -54,12 +53,10 @@ struct NetTxPkt {
uint16_t hdr_len;
eth_pkt_types_e packet_type;
uint8_t l4proto;
bool is_loopback;
};
void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev,
uint32_t max_frags, bool has_virt_hdr)
uint32_t max_frags)
{
struct NetTxPkt *p = g_malloc0(sizeof *p);
@ -71,10 +68,8 @@ void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev,
p->max_payload_frags = max_frags;
p->max_raw_frags = max_frags;
p->has_virt_hdr = has_virt_hdr;
p->vec[NET_TX_PKT_VHDR_FRAG].iov_base = &p->virt_hdr;
p->vec[NET_TX_PKT_VHDR_FRAG].iov_len =
p->has_virt_hdr ? sizeof p->virt_hdr : 0;
p->vec[NET_TX_PKT_VHDR_FRAG].iov_len = sizeof p->virt_hdr;
p->vec[NET_TX_PKT_L2HDR_FRAG].iov_base = &p->l2_hdr;
p->vec[NET_TX_PKT_L3HDR_FRAG].iov_base = &p->l3_hdr;
@ -304,10 +299,11 @@ func_exit:
return rc;
}
void net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable,
bool net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable,
bool csum_enable, uint32_t gso_size)
{
struct tcp_hdr l4hdr;
size_t bytes_read;
assert(pkt);
/* csum has to be enabled if tso is. */
@ -328,8 +324,13 @@ void net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable,
case VIRTIO_NET_HDR_GSO_TCPV4:
case VIRTIO_NET_HDR_GSO_TCPV6:
iov_to_buf(&pkt->vec[NET_TX_PKT_PL_START_FRAG], pkt->payload_frags,
0, &l4hdr, sizeof(l4hdr));
bytes_read = iov_to_buf(&pkt->vec[NET_TX_PKT_PL_START_FRAG],
pkt->payload_frags, 0, &l4hdr, sizeof(l4hdr));
if (bytes_read < sizeof(l4hdr) ||
l4hdr.th_off * sizeof(uint32_t) < sizeof(l4hdr)) {
return false;
}
pkt->virt_hdr.hdr_len = pkt->hdr_len + l4hdr.th_off * sizeof(uint32_t);
pkt->virt_hdr.gso_size = gso_size;
break;
@ -341,11 +342,17 @@ void net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable,
if (csum_enable) {
switch (pkt->l4proto) {
case IP_PROTO_TCP:
if (pkt->payload_len < sizeof(struct tcp_hdr)) {
return false;
}
pkt->virt_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
pkt->virt_hdr.csum_start = pkt->hdr_len;
pkt->virt_hdr.csum_offset = offsetof(struct tcp_hdr, th_sum);
break;
case IP_PROTO_UDP:
if (pkt->payload_len < sizeof(struct udp_hdr)) {
return false;
}
pkt->virt_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
pkt->virt_hdr.csum_start = pkt->hdr_len;
pkt->virt_hdr.csum_offset = offsetof(struct udp_hdr, uh_sum);
@ -354,6 +361,8 @@ void net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable,
break;
}
}
return true;
}
void net_tx_pkt_setup_vlan_header_ex(struct NetTxPkt *pkt,
@ -464,15 +473,14 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt)
pkt->l4proto = 0;
}
static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt)
static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt,
struct iovec *iov, uint32_t iov_len,
uint16_t csl)
{
struct iovec *iov = &pkt->vec[NET_TX_PKT_L2HDR_FRAG];
uint32_t csum_cntr;
uint16_t csum = 0;
uint32_t cso;
/* num of iovec without vhdr */
uint32_t iov_len = pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - 1;
uint16_t csl;
size_t csum_offset = pkt->virt_hdr.csum_start + pkt->virt_hdr.csum_offset;
uint16_t l3_proto = eth_get_l3_proto(iov, 1, iov->iov_len);
@ -480,8 +488,6 @@ static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt)
iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum);
/* Calculate L4 TCP/UDP checksum */
csl = pkt->payload_len;
csum_cntr = 0;
cso = 0;
/* add pseudo header to csum */
@ -504,23 +510,16 @@ static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt)
iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum);
}
enum {
NET_TX_PKT_FRAGMENT_L2_HDR_POS = 0,
NET_TX_PKT_FRAGMENT_L3_HDR_POS,
NET_TX_PKT_FRAGMENT_HEADER_NUM
};
#define NET_MAX_FRAG_SG_LIST (64)
static size_t net_tx_pkt_fetch_fragment(struct NetTxPkt *pkt,
int *src_idx, size_t *src_offset, struct iovec *dst, int *dst_idx)
int *src_idx, size_t *src_offset, size_t src_len,
struct iovec *dst, int *dst_idx)
{
size_t fetched = 0;
struct iovec *src = pkt->vec;
*dst_idx = NET_TX_PKT_FRAGMENT_HEADER_NUM;
while (fetched < IP_FRAG_ALIGN_SIZE(pkt->virt_hdr.gso_size)) {
while (fetched < src_len) {
/* no more place in fragment iov */
if (*dst_idx == NET_MAX_FRAG_SG_LIST) {
@ -535,7 +534,7 @@ static size_t net_tx_pkt_fetch_fragment(struct NetTxPkt *pkt,
dst[*dst_idx].iov_base = src[*src_idx].iov_base + *src_offset;
dst[*dst_idx].iov_len = MIN(src[*src_idx].iov_len - *src_offset,
IP_FRAG_ALIGN_SIZE(pkt->virt_hdr.gso_size) - fetched);
src_len - fetched);
*src_offset += dst[*dst_idx].iov_len;
fetched += dst[*dst_idx].iov_len;
@ -551,71 +550,250 @@ static size_t net_tx_pkt_fetch_fragment(struct NetTxPkt *pkt,
return fetched;
}
static inline void net_tx_pkt_sendv(struct NetTxPkt *pkt,
NetClientState *nc, const struct iovec *iov, int iov_cnt)
static void net_tx_pkt_sendv(
void *opaque, const struct iovec *iov, int iov_cnt,
const struct iovec *virt_iov, int virt_iov_cnt)
{
if (pkt->is_loopback) {
qemu_receive_packet_iov(nc, iov, iov_cnt);
NetClientState *nc = opaque;
if (qemu_get_using_vnet_hdr(nc->peer)) {
qemu_sendv_packet(nc, virt_iov, virt_iov_cnt);
} else {
qemu_sendv_packet(nc, iov, iov_cnt);
}
}
static bool net_tx_pkt_do_sw_fragmentation(struct NetTxPkt *pkt,
NetClientState *nc)
static bool net_tx_pkt_tcp_fragment_init(struct NetTxPkt *pkt,
struct iovec *fragment,
int *pl_idx,
size_t *l4hdr_len,
int *src_idx,
size_t *src_offset,
size_t *src_len)
{
struct iovec *l4 = fragment + NET_TX_PKT_PL_START_FRAG;
size_t bytes_read = 0;
struct tcp_hdr *th;
if (!pkt->payload_frags) {
return false;
}
l4->iov_len = pkt->virt_hdr.hdr_len - pkt->hdr_len;
l4->iov_base = g_malloc(l4->iov_len);
*src_idx = NET_TX_PKT_PL_START_FRAG;
while (pkt->vec[*src_idx].iov_len < l4->iov_len - bytes_read) {
memcpy((char *)l4->iov_base + bytes_read, pkt->vec[*src_idx].iov_base,
pkt->vec[*src_idx].iov_len);
bytes_read += pkt->vec[*src_idx].iov_len;
(*src_idx)++;
if (*src_idx >= pkt->payload_frags + NET_TX_PKT_PL_START_FRAG) {
g_free(l4->iov_base);
return false;
}
}
*src_offset = l4->iov_len - bytes_read;
memcpy((char *)l4->iov_base + bytes_read, pkt->vec[*src_idx].iov_base,
*src_offset);
th = l4->iov_base;
th->th_flags &= ~(TH_FIN | TH_PUSH);
*pl_idx = NET_TX_PKT_PL_START_FRAG + 1;
*l4hdr_len = l4->iov_len;
*src_len = pkt->virt_hdr.gso_size;
return true;
}
static void net_tx_pkt_tcp_fragment_deinit(struct iovec *fragment)
{
g_free(fragment[NET_TX_PKT_PL_START_FRAG].iov_base);
}
static void net_tx_pkt_tcp_fragment_fix(struct NetTxPkt *pkt,
struct iovec *fragment,
size_t fragment_len,
uint8_t gso_type)
{
struct iovec *l3hdr = fragment + NET_TX_PKT_L3HDR_FRAG;
struct iovec *l4hdr = fragment + NET_TX_PKT_PL_START_FRAG;
struct ip_header *ip = l3hdr->iov_base;
struct ip6_header *ip6 = l3hdr->iov_base;
size_t len = l3hdr->iov_len + l4hdr->iov_len + fragment_len;
switch (gso_type) {
case VIRTIO_NET_HDR_GSO_TCPV4:
ip->ip_len = cpu_to_be16(len);
eth_fix_ip4_checksum(l3hdr->iov_base, l3hdr->iov_len);
break;
case VIRTIO_NET_HDR_GSO_TCPV6:
len -= sizeof(struct ip6_header);
ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = cpu_to_be16(len);
break;
}
}
static void net_tx_pkt_tcp_fragment_advance(struct NetTxPkt *pkt,
struct iovec *fragment,
size_t fragment_len,
uint8_t gso_type)
{
struct iovec *l3hdr = fragment + NET_TX_PKT_L3HDR_FRAG;
struct iovec *l4hdr = fragment + NET_TX_PKT_PL_START_FRAG;
struct ip_header *ip = l3hdr->iov_base;
struct tcp_hdr *th = l4hdr->iov_base;
if (gso_type == VIRTIO_NET_HDR_GSO_TCPV4) {
ip->ip_id = cpu_to_be16(be16_to_cpu(ip->ip_id) + 1);
}
th->th_seq = cpu_to_be32(be32_to_cpu(th->th_seq) + fragment_len);
th->th_flags &= ~TH_CWR;
}
static void net_tx_pkt_udp_fragment_init(struct NetTxPkt *pkt,
int *pl_idx,
size_t *l4hdr_len,
int *src_idx, size_t *src_offset,
size_t *src_len)
{
*pl_idx = NET_TX_PKT_PL_START_FRAG;
*l4hdr_len = 0;
*src_idx = NET_TX_PKT_PL_START_FRAG;
*src_offset = 0;
*src_len = IP_FRAG_ALIGN_SIZE(pkt->virt_hdr.gso_size);
}
static void net_tx_pkt_udp_fragment_fix(struct NetTxPkt *pkt,
struct iovec *fragment,
size_t fragment_offset,
size_t fragment_len)
{
bool more_frags = fragment_offset + fragment_len < pkt->payload_len;
uint16_t orig_flags;
struct iovec *l3hdr = fragment + NET_TX_PKT_L3HDR_FRAG;
struct ip_header *ip = l3hdr->iov_base;
uint16_t frag_off_units = fragment_offset / IP_FRAG_UNIT_SIZE;
uint16_t new_ip_off;
assert(fragment_offset % IP_FRAG_UNIT_SIZE == 0);
assert((frag_off_units & ~IP_OFFMASK) == 0);
orig_flags = be16_to_cpu(ip->ip_off) & ~(IP_OFFMASK | IP_MF);
new_ip_off = frag_off_units | orig_flags | (more_frags ? IP_MF : 0);
ip->ip_off = cpu_to_be16(new_ip_off);
ip->ip_len = cpu_to_be16(l3hdr->iov_len + fragment_len);
eth_fix_ip4_checksum(l3hdr->iov_base, l3hdr->iov_len);
}
static bool net_tx_pkt_do_sw_fragmentation(struct NetTxPkt *pkt,
NetTxPktCallback callback,
void *context)
{
uint8_t gso_type = pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN;
struct iovec fragment[NET_MAX_FRAG_SG_LIST];
size_t fragment_len = 0;
bool more_frags = false;
size_t fragment_len;
size_t l4hdr_len;
size_t src_len;
/* some pointers for shorter code */
void *l2_iov_base, *l3_iov_base;
size_t l2_iov_len, l3_iov_len;
int src_idx = NET_TX_PKT_PL_START_FRAG, dst_idx;
size_t src_offset = 0;
int src_idx, dst_idx, pl_idx;
size_t src_offset;
size_t fragment_offset = 0;
l2_iov_base = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_base;
l2_iov_len = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len;
l3_iov_base = pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base;
l3_iov_len = pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len;
struct virtio_net_hdr virt_hdr = {
.flags = pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM ?
VIRTIO_NET_HDR_F_DATA_VALID : 0
};
/* Copy headers */
fragment[NET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_base = l2_iov_base;
fragment[NET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_len = l2_iov_len;
fragment[NET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_base = l3_iov_base;
fragment[NET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_len = l3_iov_len;
fragment[NET_TX_PKT_VHDR_FRAG].iov_base = &virt_hdr;
fragment[NET_TX_PKT_VHDR_FRAG].iov_len = sizeof(virt_hdr);
fragment[NET_TX_PKT_L2HDR_FRAG] = pkt->vec[NET_TX_PKT_L2HDR_FRAG];
fragment[NET_TX_PKT_L3HDR_FRAG] = pkt->vec[NET_TX_PKT_L3HDR_FRAG];
switch (gso_type) {
case VIRTIO_NET_HDR_GSO_TCPV4:
case VIRTIO_NET_HDR_GSO_TCPV6:
if (!net_tx_pkt_tcp_fragment_init(pkt, fragment, &pl_idx, &l4hdr_len,
&src_idx, &src_offset, &src_len)) {
return false;
}
break;
case VIRTIO_NET_HDR_GSO_UDP:
net_tx_pkt_do_sw_csum(pkt, &pkt->vec[NET_TX_PKT_L2HDR_FRAG],
pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - 1,
pkt->payload_len);
net_tx_pkt_udp_fragment_init(pkt, &pl_idx, &l4hdr_len,
&src_idx, &src_offset, &src_len);
break;
default:
abort();
}
/* Put as much data as possible and send */
do {
fragment_len = net_tx_pkt_fetch_fragment(pkt, &src_idx, &src_offset,
fragment, &dst_idx);
while (true) {
dst_idx = pl_idx;
fragment_len = net_tx_pkt_fetch_fragment(pkt,
&src_idx, &src_offset, src_len, fragment, &dst_idx);
if (!fragment_len) {
break;
}
more_frags = (fragment_offset + fragment_len < pkt->payload_len);
switch (gso_type) {
case VIRTIO_NET_HDR_GSO_TCPV4:
case VIRTIO_NET_HDR_GSO_TCPV6:
net_tx_pkt_tcp_fragment_fix(pkt, fragment, fragment_len, gso_type);
net_tx_pkt_do_sw_csum(pkt, fragment + NET_TX_PKT_L2HDR_FRAG,
dst_idx - NET_TX_PKT_L2HDR_FRAG,
l4hdr_len + fragment_len);
break;
eth_setup_ip4_fragmentation(l2_iov_base, l2_iov_len, l3_iov_base,
l3_iov_len, fragment_len, fragment_offset, more_frags);
case VIRTIO_NET_HDR_GSO_UDP:
net_tx_pkt_udp_fragment_fix(pkt, fragment, fragment_offset,
fragment_len);
break;
}
eth_fix_ip4_checksum(l3_iov_base, l3_iov_len);
callback(context,
fragment + NET_TX_PKT_L2HDR_FRAG, dst_idx - NET_TX_PKT_L2HDR_FRAG,
fragment + NET_TX_PKT_VHDR_FRAG, dst_idx - NET_TX_PKT_VHDR_FRAG);
net_tx_pkt_sendv(pkt, nc, fragment, dst_idx);
if (gso_type == VIRTIO_NET_HDR_GSO_TCPV4 ||
gso_type == VIRTIO_NET_HDR_GSO_TCPV6) {
net_tx_pkt_tcp_fragment_advance(pkt, fragment, fragment_len,
gso_type);
}
fragment_offset += fragment_len;
}
} while (fragment_len && more_frags);
if (gso_type == VIRTIO_NET_HDR_GSO_TCPV4 ||
gso_type == VIRTIO_NET_HDR_GSO_TCPV6) {
net_tx_pkt_tcp_fragment_deinit(fragment);
}
return true;
}
bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc)
{
assert(pkt);
bool offload = qemu_get_using_vnet_hdr(nc->peer);
return net_tx_pkt_send_custom(pkt, offload, net_tx_pkt_sendv, nc);
}
if (!pkt->has_virt_hdr &&
pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
net_tx_pkt_do_sw_csum(pkt);
}
bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool offload,
NetTxPktCallback callback, void *context)
{
assert(pkt);
/*
* Since underlying infrastructure does not support IP datagrams longer
@ -629,26 +807,22 @@ bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc)
}
}
if (pkt->has_virt_hdr ||
pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) {
if (offload || pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) {
if (!offload && pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
net_tx_pkt_do_sw_csum(pkt, &pkt->vec[NET_TX_PKT_L2HDR_FRAG],
pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - 1,
pkt->payload_len);
}
net_tx_pkt_fix_ip6_payload_len(pkt);
net_tx_pkt_sendv(pkt, nc, pkt->vec,
pkt->payload_frags + NET_TX_PKT_PL_START_FRAG);
callback(context, pkt->vec + NET_TX_PKT_L2HDR_FRAG,
pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - NET_TX_PKT_L2HDR_FRAG,
pkt->vec + NET_TX_PKT_VHDR_FRAG,
pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - NET_TX_PKT_VHDR_FRAG);
return true;
}
return net_tx_pkt_do_sw_fragmentation(pkt, nc);
}
bool net_tx_pkt_send_loopback(struct NetTxPkt *pkt, NetClientState *nc)
{
bool res;
pkt->is_loopback = true;
res = net_tx_pkt_send(pkt, nc);
pkt->is_loopback = false;
return res;
return net_tx_pkt_do_sw_fragmentation(pkt, callback, context);
}
void net_tx_pkt_fix_ip6_payload_len(struct NetTxPkt *pkt)

View File

@ -26,16 +26,17 @@
struct NetTxPkt;
typedef void (* NetTxPktCallback)(void *, const struct iovec *, int, const struct iovec *, int);
/**
* Init function for tx packet functionality
*
* @pkt: packet pointer
* @pci_dev: PCI device processing this packet
* @max_frags: max tx ip fragments
* @has_virt_hdr: device uses virtio header.
*/
void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev,
uint32_t max_frags, bool has_virt_hdr);
uint32_t max_frags);
/**
* Clean all tx packet resources.
@ -59,9 +60,10 @@ struct virtio_net_hdr *net_tx_pkt_get_vhdr(struct NetTxPkt *pkt);
* @tso_enable: TSO enabled
* @csum_enable: CSO enabled
* @gso_size: MSS size for TSO
* @ret: operation result
*
*/
void net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable,
bool net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable,
bool csum_enable, uint32_t gso_size);
/**
@ -161,15 +163,16 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt);
bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc);
/**
* Redirect packet directly to receive path (emulate loopback phy).
* Handles sw offloads if vhdr is not supported.
*
* @pkt: packet
* @nc: NetClientState
* @ret: operation result
*
*/
bool net_tx_pkt_send_loopback(struct NetTxPkt *pkt, NetClientState *nc);
* Send packet with a custom function.
*
* @pkt: packet
* @offload: whether the callback implements offloading
* @callback: a function to be called back for each transformed packet
* @context: a pointer to be passed to the callback.
* @ret: operation result
*/
bool net_tx_pkt_send_custom(struct NetTxPkt *pkt, bool offload,
NetTxPktCallback callback, void *context);
/**
* parse raw packet data and analyze offload requirements.

View File

@ -61,7 +61,7 @@ pcnet_ioport_read(void *opaque, uint64_t addr, unsigned size) "opaque=%p addr=0x
pcnet_ioport_write(void *opaque, uint64_t addr, uint64_t data, unsigned size) "opaque=%p addr=0x%"PRIx64" data=0x%"PRIx64" size=%d"
# net_rx_pkt.c
net_rx_pkt_parsed(bool ip4, bool ip6, bool udp, bool tcp, size_t l3o, size_t l4o, size_t l5o) "RX packet parsed: ip4: %d, ip6: %d, udp: %d, tcp: %d, l3 offset: %zu, l4 offset: %zu, l5 offset: %zu"
net_rx_pkt_parsed(bool ip4, bool ip6, int l4proto, size_t l3o, size_t l4o, size_t l5o) "RX packet parsed: ip4: %d, ip6: %d, l4 protocol: %d, l3 offset: %zu, l4 offset: %zu, l5 offset: %zu"
net_rx_pkt_l4_csum_validate_entry(void) "Starting L4 checksum validation"
net_rx_pkt_l4_csum_validate_not_xxp(void) "Not a TCP/UDP packet"
net_rx_pkt_l4_csum_validate_udp_with_no_checksum(void) "UDP packet without checksum"
@ -165,8 +165,8 @@ e1000e_rx_descr(int ridx, uint64_t base, uint8_t len) "Next RX descriptor: ring
e1000e_rx_set_rctl(uint32_t rctl) "RCTL = 0x%x"
e1000e_rx_receive_iov(int iovcnt) "Received vector of %d fragments"
e1000e_rx_flt_dropped(void) "Received packet dropped by RX filter"
e1000e_rx_written_to_guest(uint32_t causes) "Received packet written to guest (ICR causes %u)"
e1000e_rx_not_written_to_guest(uint32_t causes) "Received packet NOT written to guest (ICR causes %u)"
e1000e_rx_written_to_guest(int queue_idx) "Received packet written to guest (queue %d)"
e1000e_rx_not_written_to_guest(int queue_idx) "Received packet NOT written to guest (queue %d)"
e1000e_rx_interrupt_set(uint32_t causes) "Receive interrupt set (ICR causes %u)"
e1000e_rx_interrupt_delayed(uint32_t causes) "Receive interrupt delayed (ICR causes %u)"
e1000e_rx_set_cso(int cso_state) "RX CSO state set to %d"
@ -177,18 +177,16 @@ e1000e_rx_start_recv(void)
e1000e_rx_rss_started(void) "Starting RSS processing"
e1000e_rx_rss_disabled(void) "RSS is disabled"
e1000e_rx_rss_type(uint32_t type) "RSS type is %u"
e1000e_rx_rss_ip4(bool isfragment, bool istcp, uint32_t mrqc, bool tcpipv4_enabled, bool ipv4_enabled) "RSS IPv4: fragment %d, tcp %d, mrqc 0x%X, tcpipv4 enabled %d, ipv4 enabled %d"
e1000e_rx_rss_ip4(int l4hdr_proto, uint32_t mrqc, bool tcpipv4_enabled, bool ipv4_enabled) "RSS IPv4: L4 header protocol %d, mrqc 0x%X, tcpipv4 enabled %d, ipv4 enabled %d"
e1000e_rx_rss_ip6_rfctl(uint32_t rfctl) "RSS IPv6: rfctl 0x%X"
e1000e_rx_rss_ip6(bool ex_dis, bool new_ex_dis, bool istcp, bool has_ext_headers, bool ex_dst_valid, bool ex_src_valid, uint32_t mrqc, bool tcpipv6_enabled, bool ipv6ex_enabled, bool ipv6_enabled) "RSS IPv6: ex_dis: %d, new_ex_dis: %d, tcp %d, has_ext_headers %d, ex_dst_valid %d, ex_src_valid %d, mrqc 0x%X, tcpipv6 enabled %d, ipv6ex enabled %d, ipv6 enabled %d"
e1000e_rx_rss_dispatched_to_queue(int queue_idx) "Packet being dispatched to queue %d"
e1000e_rx_rss_ip6(bool ex_dis, bool new_ex_dis, int l4hdr_proto, bool has_ext_headers, bool ex_dst_valid, bool ex_src_valid, uint32_t mrqc, bool tcpipv6_enabled, bool ipv6ex_enabled, bool ipv6_enabled) "RSS IPv6: ex_dis: %d, new_ex_dis: %d, L4 header protocol %d, has_ext_headers %d, ex_dst_valid %d, ex_src_valid %d, mrqc 0x%X, tcpipv6 enabled %d, ipv6ex enabled %d, ipv6 enabled %d"
e1000e_rx_metadata_protocols(bool isip4, bool isip6, bool isudp, bool istcp) "protocols: ip4: %d, ip6: %d, udp: %d, tcp: %d"
e1000e_rx_metadata_protocols(bool hasip4, bool hasip6, int l4hdr_protocol) "protocols: ip4: %d, ip6: %d, l4hdr: %d"
e1000e_rx_metadata_vlan(uint16_t vlan_tag) "VLAN tag is 0x%X"
e1000e_rx_metadata_rss(uint32_t rss, uint32_t mrq) "RSS data: rss: 0x%X, mrq: 0x%X"
e1000e_rx_metadata_ip_id(uint16_t ip_id) "the IPv4 ID is 0x%X"
e1000e_rx_metadata_ack(void) "the packet is TCP ACK"
e1000e_rx_metadata_pkt_type(uint32_t pkt_type) "the packet type is %u"
e1000e_rx_metadata_no_virthdr(void) "the packet has no virt-header"
e1000e_rx_metadata_virthdr_no_csum_info(void) "virt-header does not contain checksum info"
e1000e_rx_metadata_l3_cso_disabled(void) "IP4 CSO is disabled"
e1000e_rx_metadata_l4_cso_disabled(void) "TCP/UDP CSO is disabled"
@ -201,10 +199,8 @@ e1000e_rx_metadata_ipv6_filtering_disabled(void) "IPv6 RX filtering disabled by
e1000e_vlan_vet(uint16_t vet) "Setting VLAN ethernet type 0x%X"
e1000e_irq_msi_notify(uint32_t cause) "MSI notify 0x%x"
e1000e_irq_throttling_no_pending_interrupts(void) "No pending interrupts to notify"
e1000e_irq_msi_notify_postponed(void) "Sending MSI postponed by ITR"
e1000e_irq_legacy_notify_postponed(void) "Raising legacy IRQ postponed by ITR"
e1000e_irq_throttling_no_pending_vec(int idx) "No pending interrupts for vector %d"
e1000e_irq_msix_notify_postponed_vec(int idx) "Sending MSI-X postponed by EITR[%d]"
e1000e_irq_legacy_notify(bool level) "IRQ line state: %d"
e1000e_irq_msix_notify_vec(uint32_t vector) "MSI-X notify vector 0x%x"
@ -253,7 +249,7 @@ e1000e_vm_state_stopped(void) "VM state is stopped"
# e1000e.c
e1000e_cb_pci_realize(void) "E1000E PCI realize entry"
e1000e_cb_pci_uninit(void) "E1000E PCI unit entry"
e1000e_cb_qdev_reset(void) "E1000E qdev reset entry"
e1000e_cb_qdev_reset_hold(void) "E1000E qdev reset hold"
e1000e_cb_pre_save(void) "E1000E pre save entry"
e1000e_cb_post_load(void) "E1000E post load entry"
@ -274,6 +270,38 @@ e1000e_msix_use_vector_fail(uint32_t vec, int32_t res) "Failed to use MSI-X vect
e1000e_mac_set_permanent(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "Set permanent MAC: %02x:%02x:%02x:%02x:%02x:%02x"
e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d"
# igb.c
igb_write_config(uint32_t address, uint32_t val, int len) "CONFIG write 0x%"PRIx32", value: 0x%"PRIx32", len: %"PRId32
igbvf_write_config(uint32_t address, uint32_t val, int len) "CONFIG write 0x%"PRIx32", value: 0x%"PRIx32", len: %"PRId32
# igb_core.c
igb_core_mdic_read(uint32_t addr, uint32_t data) "MDIC READ: PHY[%u] = 0x%x"
igb_core_mdic_read_unhandled(uint32_t addr) "MDIC READ: PHY[%u] UNHANDLED"
igb_core_mdic_write(uint32_t addr, uint32_t data) "MDIC WRITE: PHY[%u] = 0x%x"
igb_core_mdic_write_unhandled(uint32_t addr) "MDIC WRITE: PHY[%u] UNHANDLED"
igb_rx_desc_buff_size(uint32_t b) "buffer size: %u"
igb_rx_desc_buff_write(uint64_t addr, uint16_t offset, const void* source, uint32_t len) "addr: 0x%"PRIx64", offset: %u, from: %p, length: %u"
igb_rx_metadata_rss(uint32_t rss) "RSS data: 0x%X"
igb_irq_icr_clear_gpie_nsicr(void) "Clearing ICR on read due to GPIE.NSICR enabled"
igb_irq_icr_write(uint32_t bits, uint32_t old_icr, uint32_t new_icr) "Clearing ICR bits 0x%x: 0x%x --> 0x%x"
igb_irq_set_iam(uint32_t icr) "Update IAM: 0x%x"
igb_irq_read_iam(uint32_t icr) "Current IAM: 0x%x"
igb_irq_write_eics(uint32_t val, bool msix) "Update EICS: 0x%x MSI-X: %d"
igb_irq_write_eims(uint32_t val, bool msix) "Update EIMS: 0x%x MSI-X: %d"
igb_irq_write_eimc(uint32_t val, uint32_t eims, bool msix) "Update EIMC: 0x%x EIMS: 0x%x MSI-X: %d"
igb_irq_write_eiac(uint32_t val) "Update EIAC: 0x%x"
igb_irq_write_eiam(uint32_t val, bool msix) "Update EIAM: 0x%x MSI-X: %d"
igb_irq_write_eicr(uint32_t val, bool msix) "Update EICR: 0x%x MSI-X: %d"
igb_irq_eitr_set(uint32_t eitr_num, uint32_t val) "EITR[%u] = 0x%x"
igb_set_pfmailbox(uint32_t vf_num, uint32_t val) "PFMailbox[%d]: 0x%x"
igb_set_vfmailbox(uint32_t vf_num, uint32_t val) "VFMailbox[%d]: 0x%x"
# igbvf.c
igbvf_wrn_io_addr_unknown(uint64_t addr) "IO unknown register 0x%"PRIx64
# spapr_llan.c
spapr_vlan_get_rx_bd_from_pool_found(int pool, int32_t count, uint32_t rx_bufs) "pool=%d count=%"PRId32" rxbufs=%"PRIu32
spapr_vlan_get_rx_bd_from_page(int buf_ptr, uint64_t bd) "use_buf_ptr=%d bd=0x%016"PRIx64

View File

@ -1746,39 +1746,61 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
return 0;
}
static uint8_t virtio_net_get_hash_type(bool isip4,
bool isip6,
bool isudp,
bool istcp,
static uint8_t virtio_net_get_hash_type(bool hasip4,
bool hasip6,
EthL4HdrProto l4hdr_proto,
uint32_t types)
{
if (isip4) {
if (istcp && (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4)) {
return NetPktRssIpV4Tcp;
}
if (isudp && (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4)) {
return NetPktRssIpV4Udp;
if (hasip4) {
switch (l4hdr_proto) {
case ETH_L4_HDR_PROTO_TCP:
if (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4) {
return NetPktRssIpV4Tcp;
}
break;
case ETH_L4_HDR_PROTO_UDP:
if (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4) {
return NetPktRssIpV4Udp;
}
break;
default:
break;
}
if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
return NetPktRssIpV4;
}
} else if (isip6) {
uint32_t mask = VIRTIO_NET_RSS_HASH_TYPE_TCP_EX |
VIRTIO_NET_RSS_HASH_TYPE_TCPv6;
} else if (hasip6) {
switch (l4hdr_proto) {
case ETH_L4_HDR_PROTO_TCP:
if (types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) {
return NetPktRssIpV6TcpEx;
}
if (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv6) {
return NetPktRssIpV6Tcp;
}
break;
if (istcp && (types & mask)) {
return (types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) ?
NetPktRssIpV6TcpEx : NetPktRssIpV6Tcp;
case ETH_L4_HDR_PROTO_UDP:
if (types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) {
return NetPktRssIpV6UdpEx;
}
if (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv6) {
return NetPktRssIpV6Udp;
}
break;
default:
break;
}
mask = VIRTIO_NET_RSS_HASH_TYPE_UDP_EX | VIRTIO_NET_RSS_HASH_TYPE_UDPv6;
if (isudp && (types & mask)) {
return (types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) ?
NetPktRssIpV6UdpEx : NetPktRssIpV6Udp;
if (types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) {
return NetPktRssIpV6Ex;
}
mask = VIRTIO_NET_RSS_HASH_TYPE_IP_EX | VIRTIO_NET_RSS_HASH_TYPE_IPv6;
if (types & mask) {
return (types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) ?
NetPktRssIpV6Ex : NetPktRssIpV6;
if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
return NetPktRssIpV6;
}
}
return 0xff;
@ -1800,7 +1822,8 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
struct NetRxPkt *pkt = n->rx_pkt;
uint8_t net_hash_type;
uint32_t hash;
bool isip4, isip6, isudp, istcp;
bool hasip4, hasip6;
EthL4HdrProto l4hdr_proto;
static const uint8_t reports[NetPktRssIpV6UdpEx + 1] = {
VIRTIO_NET_HASH_REPORT_IPv4,
VIRTIO_NET_HASH_REPORT_TCPv4,
@ -1815,14 +1838,8 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len,
size - n->host_hdr_len);
net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
if (isip4 && (net_rx_pkt_get_ip4_info(pkt)->fragment)) {
istcp = isudp = false;
}
if (isip6 && (net_rx_pkt_get_ip6_info(pkt)->fragment)) {
istcp = isudp = false;
}
net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp,
net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
net_hash_type = virtio_net_get_hash_type(hasip4, hasip6, l4hdr_proto,
n->rss_data.hash_types);
if (net_hash_type > NetPktRssIpV6UdpEx) {
if (n->rss_data.populate_hash) {
@ -3718,7 +3735,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
QTAILQ_INIT(&n->rsc_chains);
n->qdev = dev;
net_rx_pkt_init(&n->rx_pkt, false);
net_rx_pkt_init(&n->rx_pkt);
if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
virtio_net_load_ebpf(n);

View File

@ -440,19 +440,19 @@ vmxnet3_setup_tx_offloads(VMXNET3State *s)
{
switch (s->offload_mode) {
case VMXNET3_OM_NONE:
net_tx_pkt_build_vheader(s->tx_pkt, false, false, 0);
break;
return net_tx_pkt_build_vheader(s->tx_pkt, false, false, 0);
case VMXNET3_OM_CSUM:
net_tx_pkt_build_vheader(s->tx_pkt, false, true, 0);
VMW_PKPRN("L4 CSO requested\n");
break;
return net_tx_pkt_build_vheader(s->tx_pkt, false, true, 0);
case VMXNET3_OM_TSO:
net_tx_pkt_build_vheader(s->tx_pkt, true, true,
s->cso_or_gso_size);
net_tx_pkt_update_ip_checksums(s->tx_pkt);
VMW_PKPRN("GSO offload requested.");
if (!net_tx_pkt_build_vheader(s->tx_pkt, true, true,
s->cso_or_gso_size)) {
return false;
}
net_tx_pkt_update_ip_checksums(s->tx_pkt);
break;
default:
@ -847,21 +847,20 @@ static void vmxnet3_rx_need_csum_calculate(struct NetRxPkt *pkt,
size_t pkt_len)
{
struct virtio_net_hdr *vhdr;
bool isip4, isip6, istcp, isudp;
bool hasip4, hasip6;
EthL4HdrProto l4hdr_proto;
uint8_t *data;
int len;
if (!net_rx_pkt_has_virt_hdr(pkt)) {
return;
}
vhdr = net_rx_pkt_get_vhdr(pkt);
if (!VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_NEEDS_CSUM)) {
return;
}
net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
if (!(isip4 || isip6) || !(istcp || isudp)) {
net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
if (!(hasip4 || hasip6) ||
(l4hdr_proto != ETH_L4_HDR_PROTO_TCP &&
l4hdr_proto != ETH_L4_HDR_PROTO_UDP)) {
return;
}
@ -889,7 +888,8 @@ static void vmxnet3_rx_update_descr(struct NetRxPkt *pkt,
struct Vmxnet3_RxCompDesc *rxcd)
{
int csum_ok, is_gso;
bool isip4, isip6, istcp, isudp;
bool hasip4, hasip6;
EthL4HdrProto l4hdr_proto;
struct virtio_net_hdr *vhdr;
uint8_t offload_type;
@ -898,10 +898,6 @@ static void vmxnet3_rx_update_descr(struct NetRxPkt *pkt,
rxcd->tci = net_rx_pkt_get_vlan_tag(pkt);
}
if (!net_rx_pkt_has_virt_hdr(pkt)) {
goto nocsum;
}
vhdr = net_rx_pkt_get_vhdr(pkt);
/*
* Checksum is valid when lower level tell so or when lower level
@ -919,16 +915,18 @@ static void vmxnet3_rx_update_descr(struct NetRxPkt *pkt,
goto nocsum;
}
net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
if ((!istcp && !isudp) || (!isip4 && !isip6)) {
net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
if ((l4hdr_proto != ETH_L4_HDR_PROTO_TCP &&
l4hdr_proto != ETH_L4_HDR_PROTO_UDP) ||
(!hasip4 && !hasip6)) {
goto nocsum;
}
rxcd->cnc = 0;
rxcd->v4 = isip4 ? 1 : 0;
rxcd->v6 = isip6 ? 1 : 0;
rxcd->tcp = istcp ? 1 : 0;
rxcd->udp = isudp ? 1 : 0;
rxcd->v4 = hasip4 ? 1 : 0;
rxcd->v6 = hasip6 ? 1 : 0;
rxcd->tcp = l4hdr_proto == ETH_L4_HDR_PROTO_TCP;
rxcd->udp = l4hdr_proto == ETH_L4_HDR_PROTO_UDP;
rxcd->fcs = rxcd->tuc = rxcd->ipc = 1;
return;
@ -1521,9 +1519,8 @@ static void vmxnet3_activate_device(VMXNET3State *s)
/* Preallocate TX packet wrapper */
VMW_CFPRN("Max TX fragments is %u", s->max_tx_frags);
net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s),
s->max_tx_frags, s->peer_has_vhdr);
net_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr);
net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), s->max_tx_frags);
net_rx_pkt_init(&s->rx_pkt);
/* Read rings memory locations for RX queues */
for (i = 0; i < s->rxq_num; i++) {
@ -2402,9 +2399,8 @@ static int vmxnet3_post_load(void *opaque, int version_id)
{
VMXNET3State *s = opaque;
net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s),
s->max_tx_frags, s->peer_has_vhdr);
net_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr);
net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), s->max_tx_frags);
net_rx_pkt_init(&s->rx_pkt);
if (s->msix_used) {
vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS);

View File

@ -300,3 +300,8 @@ PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n)
}
return NULL;
}
uint16_t pcie_sriov_num_vfs(PCIDevice *dev)
{
return dev->exp.sriov_pf.num_vfs;
}

View File

@ -55,6 +55,7 @@
#define MII_BMCR_CTST (1 << 7) /* Collision test */
#define MII_BMCR_SPEED1000 (1 << 6) /* MSB of Speed (1000) */
#define MII_BMSR_100T4 (1 << 15) /* Can do 100mbps T4 */
#define MII_BMSR_100TX_FD (1 << 14) /* Can do 100mbps, full-duplex */
#define MII_BMSR_100TX_HD (1 << 13) /* Can do 100mbps, half-duplex */
#define MII_BMSR_10T_FD (1 << 12) /* Can do 10mbps, full-duplex */
@ -81,20 +82,31 @@
#define MII_ANLPAR_ACK (1 << 14)
#define MII_ANLPAR_PAUSEASY (1 << 11) /* can pause asymmetrically */
#define MII_ANLPAR_PAUSE (1 << 10) /* can pause */
#define MII_ANLPAR_T4 (1 << 9)
#define MII_ANLPAR_TXFD (1 << 8)
#define MII_ANLPAR_TX (1 << 7)
#define MII_ANLPAR_10FD (1 << 6)
#define MII_ANLPAR_10 (1 << 5)
#define MII_ANLPAR_CSMACD (1 << 0)
#define MII_ANER_NWAY (1 << 0) /* Can do N-way auto-nego */
#define MII_ANER_NP (1 << 2) /* Next Page Able */
#define MII_ANER_NWAY (1 << 0) /* Can do N-way auto-nego */
#define MII_ANNP_MP (1 << 13) /* Message Page */
#define MII_CTRL1000_MASTER (1 << 11) /* MASTER-SLAVE Manual Configuration Value */
#define MII_CTRL1000_PORT (1 << 10) /* T2_Repeater/DTE bit */
#define MII_CTRL1000_FULL (1 << 9) /* 1000BASE-T full duplex */
#define MII_CTRL1000_HALF (1 << 8) /* 1000BASE-T half duplex */
#define MII_STAT1000_LOK (1 << 13) /* Local Receiver Status */
#define MII_STAT1000_ROK (1 << 12) /* Remote Receiver Status */
#define MII_STAT1000_FULL (1 << 11) /* 1000BASE-T full duplex */
#define MII_STAT1000_HALF (1 << 10) /* 1000BASE-T half duplex */
#define MII_EXTSTAT_1000T_FD (1 << 13) /* 1000BASE-T Full Duplex */
#define MII_EXTSTAT_1000T_HD (1 << 12) /* 1000BASE-T Half Duplex */
/* List of vendor identifiers */
/* RealTek 8201 */
#define RTL8201CP_PHYID1 0x0000

View File

@ -76,4 +76,7 @@ PCIDevice *pcie_sriov_get_pf(PCIDevice *dev);
*/
PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n);
/* Returns the current number of virtual functions. */
uint16_t pcie_sriov_num_vfs(PCIDevice *dev);
#endif /* QEMU_PCIE_SRIOV_H */

View File

@ -381,18 +381,24 @@ typedef struct eth_ip4_hdr_info_st {
bool fragment;
} eth_ip4_hdr_info;
typedef enum EthL4HdrProto {
ETH_L4_HDR_PROTO_INVALID,
ETH_L4_HDR_PROTO_TCP,
ETH_L4_HDR_PROTO_UDP
} EthL4HdrProto;
typedef struct eth_l4_hdr_info_st {
union {
struct tcp_header tcp;
struct udp_header udp;
} hdr;
EthL4HdrProto proto;
bool has_tcp_data;
} eth_l4_hdr_info;
void eth_get_protocols(const struct iovec *iov, int iovcnt,
bool *isip4, bool *isip6,
bool *isudp, bool *istcp,
bool *hasip4, bool *hasip6,
size_t *l3hdr_off,
size_t *l4hdr_off,
size_t *l5hdr_off,
@ -400,11 +406,6 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
eth_ip4_hdr_info *ip4hdr_info,
eth_l4_hdr_info *l4hdr_info);
void eth_setup_ip4_fragmentation(const void *l2hdr, size_t l2hdr_len,
void *l3hdr, size_t l3hdr_len,
size_t l3payload_len,
size_t frag_offset, bool more_frags);
void
eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len);

View File

@ -56,8 +56,10 @@ typedef RxFilterInfo *(QueryRxFilter)(NetClientState *);
typedef bool (HasUfo)(NetClientState *);
typedef bool (HasVnetHdr)(NetClientState *);
typedef bool (HasVnetHdrLen)(NetClientState *, int);
typedef bool (GetUsingVnetHdr)(NetClientState *);
typedef void (UsingVnetHdr)(NetClientState *, bool);
typedef void (SetOffload)(NetClientState *, int, int, int, int, int);
typedef int (GetVnetHdrLen)(NetClientState *);
typedef void (SetVnetHdrLen)(NetClientState *, int);
typedef int (SetVnetLE)(NetClientState *, bool);
typedef int (SetVnetBE)(NetClientState *, bool);
@ -84,8 +86,10 @@ typedef struct NetClientInfo {
HasUfo *has_ufo;
HasVnetHdr *has_vnet_hdr;
HasVnetHdrLen *has_vnet_hdr_len;
GetUsingVnetHdr *get_using_vnet_hdr;
UsingVnetHdr *using_vnet_hdr;
SetOffload *set_offload;
GetVnetHdrLen *get_vnet_hdr_len;
SetVnetHdrLen *set_vnet_hdr_len;
SetVnetLE *set_vnet_le;
SetVnetBE *set_vnet_be;
@ -185,9 +189,11 @@ void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]);
bool qemu_has_ufo(NetClientState *nc);
bool qemu_has_vnet_hdr(NetClientState *nc);
bool qemu_has_vnet_hdr_len(NetClientState *nc, int len);
bool qemu_get_using_vnet_hdr(NetClientState *nc);
void qemu_using_vnet_hdr(NetClientState *nc, bool enable);
void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
int ecn, int ufo);
int qemu_get_vnet_hdr_len(NetClientState *nc);
void qemu_set_vnet_hdr_len(NetClientState *nc, int len);
int qemu_set_vnet_le(NetClientState *nc, bool is_le);
int qemu_set_vnet_be(NetClientState *nc, bool is_be);

View File

@ -61,12 +61,13 @@ struct pcap_sf_pkthdr {
uint32_t len;
};
static ssize_t dump_receive_iov(DumpState *s, const struct iovec *iov, int cnt)
static ssize_t dump_receive_iov(DumpState *s, const struct iovec *iov, int cnt,
int offset)
{
struct pcap_sf_pkthdr hdr;
int64_t ts;
int caplen;
size_t size = iov_size(iov, cnt);
size_t size = iov_size(iov, cnt) - offset;
struct iovec dumpiov[cnt + 1];
/* Early return in case of previous error. */
@ -84,7 +85,7 @@ static ssize_t dump_receive_iov(DumpState *s, const struct iovec *iov, int cnt)
dumpiov[0].iov_base = &hdr;
dumpiov[0].iov_len = sizeof(hdr);
cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen);
cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, offset, caplen);
if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) {
error_report("network dump write error - stopping dump");
@ -153,8 +154,10 @@ static ssize_t filter_dump_receive_iov(NetFilterState *nf, NetClientState *sndr,
int iovcnt, NetPacketSent *sent_cb)
{
NetFilterDumpState *nfds = FILTER_DUMP(nf);
int offset = qemu_get_using_vnet_hdr(nf->netdev) ?
qemu_get_vnet_hdr_len(nf->netdev) : 0;
dump_receive_iov(&nfds->ds, iov, iovcnt);
dump_receive_iov(&nfds->ds, iov, iovcnt, offset);
return 0;
}

114
net/eth.c
View File

@ -137,8 +137,7 @@ _eth_tcp_has_data(bool is_ip4,
}
void eth_get_protocols(const struct iovec *iov, int iovcnt,
bool *isip4, bool *isip6,
bool *isudp, bool *istcp,
bool *hasip4, bool *hasip6,
size_t *l3hdr_off,
size_t *l4hdr_off,
size_t *l5hdr_off,
@ -151,8 +150,10 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
size_t l2hdr_len = eth_get_l2_hdr_length_iov(iov, iovcnt);
size_t input_size = iov_size(iov, iovcnt);
size_t copied;
uint8_t ip_p;
*isip4 = *isip6 = *isudp = *istcp = false;
*hasip4 = *hasip6 = false;
l4hdr_info->proto = ETH_L4_HDR_PROTO_INVALID;
proto = eth_get_l3_proto(iov, iovcnt, l2hdr_len);
@ -166,68 +167,62 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
}
copied = iov_to_buf(iov, iovcnt, l2hdr_len, iphdr, sizeof(*iphdr));
*isip4 = true;
if (copied < sizeof(*iphdr)) {
if (copied < sizeof(*iphdr) ||
IP_HEADER_VERSION(iphdr) != IP_HEADER_VERSION_4) {
return;
}
if (IP_HEADER_VERSION(iphdr) == IP_HEADER_VERSION_4) {
if (iphdr->ip_p == IP_PROTO_TCP) {
*istcp = true;
} else if (iphdr->ip_p == IP_PROTO_UDP) {
*isudp = true;
}
}
*hasip4 = true;
ip_p = iphdr->ip_p;
ip4hdr_info->fragment = IP4_IS_FRAGMENT(iphdr);
*l4hdr_off = l2hdr_len + IP_HDR_GET_LEN(iphdr);
fragment = ip4hdr_info->fragment;
} else if (proto == ETH_P_IPV6) {
*isip6 = true;
if (eth_parse_ipv6_hdr(iov, iovcnt, l2hdr_len,
ip6hdr_info)) {
if (ip6hdr_info->l4proto == IP_PROTO_TCP) {
*istcp = true;
} else if (ip6hdr_info->l4proto == IP_PROTO_UDP) {
*isudp = true;
}
} else {
if (!eth_parse_ipv6_hdr(iov, iovcnt, l2hdr_len, ip6hdr_info)) {
return;
}
*hasip6 = true;
ip_p = ip6hdr_info->l4proto;
*l4hdr_off = l2hdr_len + ip6hdr_info->full_hdr_len;
fragment = ip6hdr_info->fragment;
} else {
return;
}
if (!fragment) {
if (*istcp) {
*istcp = _eth_copy_chunk(input_size,
iov, iovcnt,
*l4hdr_off, sizeof(l4hdr_info->hdr.tcp),
&l4hdr_info->hdr.tcp);
if (fragment) {
return;
}
if (*istcp) {
*l5hdr_off = *l4hdr_off +
TCP_HEADER_DATA_OFFSET(&l4hdr_info->hdr.tcp);
switch (ip_p) {
case IP_PROTO_TCP:
if (_eth_copy_chunk(input_size,
iov, iovcnt,
*l4hdr_off, sizeof(l4hdr_info->hdr.tcp),
&l4hdr_info->hdr.tcp)) {
l4hdr_info->proto = ETH_L4_HDR_PROTO_TCP;
*l5hdr_off = *l4hdr_off +
TCP_HEADER_DATA_OFFSET(&l4hdr_info->hdr.tcp);
l4hdr_info->has_tcp_data =
_eth_tcp_has_data(proto == ETH_P_IP,
&ip4hdr_info->ip4_hdr,
&ip6hdr_info->ip6_hdr,
*l4hdr_off - *l3hdr_off,
&l4hdr_info->hdr.tcp);
}
} else if (*isudp) {
*isudp = _eth_copy_chunk(input_size,
iov, iovcnt,
*l4hdr_off, sizeof(l4hdr_info->hdr.udp),
&l4hdr_info->hdr.udp);
l4hdr_info->has_tcp_data =
_eth_tcp_has_data(proto == ETH_P_IP,
&ip4hdr_info->ip4_hdr,
&ip6hdr_info->ip6_hdr,
*l4hdr_off - *l3hdr_off,
&l4hdr_info->hdr.tcp);
}
break;
case IP_PROTO_UDP:
if (_eth_copy_chunk(input_size,
iov, iovcnt,
*l4hdr_off, sizeof(l4hdr_info->hdr.udp),
&l4hdr_info->hdr.udp)) {
l4hdr_info->proto = ETH_L4_HDR_PROTO_UDP;
*l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp);
}
break;
}
}
@ -314,33 +309,6 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
return 0;
}
void
eth_setup_ip4_fragmentation(const void *l2hdr, size_t l2hdr_len,
void *l3hdr, size_t l3hdr_len,
size_t l3payload_len,
size_t frag_offset, bool more_frags)
{
const struct iovec l2vec = {
.iov_base = (void *) l2hdr,
.iov_len = l2hdr_len
};
if (eth_get_l3_proto(&l2vec, 1, l2hdr_len) == ETH_P_IP) {
uint16_t orig_flags;
struct ip_header *iphdr = (struct ip_header *) l3hdr;
uint16_t frag_off_units = frag_offset / IP_FRAG_UNIT_SIZE;
uint16_t new_ip_off;
assert(frag_offset % IP_FRAG_UNIT_SIZE == 0);
assert((frag_off_units & ~IP_OFFMASK) == 0);
orig_flags = be16_to_cpu(iphdr->ip_off) & ~(IP_OFFMASK|IP_MF);
new_ip_off = frag_off_units | orig_flags | (more_frags ? IP_MF : 0);
iphdr->ip_off = cpu_to_be16(new_ip_off);
iphdr->ip_len = cpu_to_be16(l3payload_len + l3hdr_len);
}
}
void
eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len)
{

View File

@ -513,6 +513,15 @@ bool qemu_has_vnet_hdr_len(NetClientState *nc, int len)
return nc->info->has_vnet_hdr_len(nc, len);
}
bool qemu_get_using_vnet_hdr(NetClientState *nc)
{
if (!nc || !nc->info->get_using_vnet_hdr) {
return false;
}
return nc->info->get_using_vnet_hdr(nc);
}
void qemu_using_vnet_hdr(NetClientState *nc, bool enable)
{
if (!nc || !nc->info->using_vnet_hdr) {
@ -532,6 +541,15 @@ void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo);
}
int qemu_get_vnet_hdr_len(NetClientState *nc)
{
if (!nc || !nc->info->get_vnet_hdr_len) {
return 0;
}
return nc->info->get_vnet_hdr_len(nc);
}
void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
{
if (!nc || !nc->info->set_vnet_hdr_len) {

View File

@ -255,6 +255,13 @@ static bool tap_has_vnet_hdr_len(NetClientState *nc, int len)
return !!tap_probe_vnet_hdr_len(s->fd, len);
}
static int tap_get_vnet_hdr_len(NetClientState *nc)
{
TAPState *s = DO_UPCAST(TAPState, nc, nc);
return s->host_vnet_hdr_len;
}
static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
{
TAPState *s = DO_UPCAST(TAPState, nc, nc);
@ -268,6 +275,13 @@ static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
s->host_vnet_hdr_len = len;
}
static bool tap_get_using_vnet_hdr(NetClientState *nc)
{
TAPState *s = DO_UPCAST(TAPState, nc, nc);
return s->using_vnet_hdr;
}
static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr)
{
TAPState *s = DO_UPCAST(TAPState, nc, nc);
@ -372,8 +386,10 @@ static NetClientInfo net_tap_info = {
.has_ufo = tap_has_ufo,
.has_vnet_hdr = tap_has_vnet_hdr,
.has_vnet_hdr_len = tap_has_vnet_hdr_len,
.get_using_vnet_hdr = tap_get_using_vnet_hdr,
.using_vnet_hdr = tap_using_vnet_hdr,
.set_offload = tap_set_offload,
.get_vnet_hdr_len = tap_get_vnet_hdr_len,
.set_vnet_hdr_len = tap_set_vnet_hdr_len,
.set_vnet_le = tap_set_vnet_le,
.set_vnet_be = tap_set_vnet_be,

View File

@ -30,6 +30,7 @@ make get-vm-images
tests/avocado/cpu_queries.py:QueryCPUModelExpansion.test \
tests/avocado/empty_cpu_model.py:EmptyCPUModel.test \
tests/avocado/hotplug_cpu.py:HotPlugCPU.test \
tests/avocado/igb.py:IGB.test \
tests/avocado/info_usernet.py:InfoUsernet.test_hostfwd \
tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu \
tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu_pt \

38
tests/avocado/igb.py Normal file
View File

@ -0,0 +1,38 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# ethtool tests for igb registers, interrupts, etc
from avocado_qemu import LinuxTest
class IGB(LinuxTest):
"""
:avocado: tags=accel:kvm
:avocado: tags=arch:x86_64
:avocado: tags=distro:fedora
:avocado: tags=distro_version:31
:avocado: tags=machine:q35
"""
timeout = 180
def test(self):
self.require_accelerator('kvm')
kernel_url = self.distro.pxeboot_url + 'vmlinuz'
kernel_hash = '5b6f6876e1b5bda314f93893271da0d5777b1f3c'
kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
initrd_url = self.distro.pxeboot_url + 'initrd.img'
initrd_hash = 'dd0340a1b39bd28f88532babd4581c67649ec5b1'
initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
# Ideally we want to test MSI as well, but it is blocked by a bug
# fixed with:
# https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=28e96556baca7056d11d9fb3cdd0aba4483e00d8
kernel_params = self.distro.default_kernel_params + ' pci=nomsi'
self.vm.add_args('-kernel', kernel_path,
'-initrd', initrd_path,
'-append', kernel_params,
'-accel', 'kvm',
'-device', 'igb')
self.launch_and_wait()
self.ssh_command('dnf -y install ethtool')
self.ssh_command('ethtool -t eth1 offline')

View File

@ -27,6 +27,7 @@
#include "qemu/osdep.h"
#include "libqtest-single.h"
#include "libqos/pci-pc.h"
#include "net/eth.h"
#include "qemu/sockets.h"
#include "qemu/iov.h"
#include "qemu/module.h"
@ -35,9 +36,13 @@
#include "libqos/e1000e.h"
#include "hw/net/e1000_regs.h"
static const struct eth_header packet = {
.h_dest = E1000E_ADDRESS,
.h_source = E1000E_ADDRESS,
};
static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
{
static const char test[] = "TEST";
struct e1000_tx_desc descr;
char buffer[64];
int ret;
@ -45,7 +50,7 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
/* Prepare test data buffer */
uint64_t data = guest_alloc(alloc, sizeof(buffer));
memwrite(data, test, sizeof(test));
memwrite(data, &packet, sizeof(packet));
/* Prepare TX descriptor */
memset(&descr, 0, sizeof(descr));
@ -71,7 +76,7 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
g_assert_cmpint(ret, == , sizeof(recv_len));
ret = recv(test_sockets[0], buffer, sizeof(buffer), 0);
g_assert_cmpint(ret, ==, sizeof(buffer));
g_assert_cmpstr(buffer, == , test);
g_assert_false(memcmp(buffer, &packet, sizeof(packet)));
/* Free test data buffer */
guest_free(alloc, data);
@ -81,15 +86,15 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator
{
union e1000_rx_desc_extended descr;
char test[] = "TEST";
int len = htonl(sizeof(test));
struct eth_header test_iov = packet;
int len = htonl(sizeof(packet));
struct iovec iov[] = {
{
.iov_base = &len,
.iov_len = sizeof(len),
},{
.iov_base = test,
.iov_len = sizeof(test),
.iov_base = &test_iov,
.iov_len = sizeof(packet),
},
};
@ -97,8 +102,8 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator
int ret;
/* Send a dummy packet to device's socket*/
ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(test));
g_assert_cmpint(ret, == , sizeof(test) + sizeof(len));
ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(packet));
g_assert_cmpint(ret, == , sizeof(packet) + sizeof(len));
/* Prepare test data buffer */
uint64_t data = guest_alloc(alloc, sizeof(buffer));
@ -119,7 +124,7 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator
/* Check data sent to the backend */
memread(data, buffer, sizeof(buffer));
g_assert_cmpstr(buffer, == , test);
g_assert_false(memcmp(buffer, &packet, sizeof(packet)));
/* Free test data buffer */
guest_free(alloc, data);

View File

@ -90,6 +90,11 @@ const generic_fuzz_config predefined_configs[] = {
.args = "-M q35 -nodefaults "
"-device e1000e,netdev=net0 -netdev user,id=net0",
.objects = "e1000e",
},{
.name = "igb",
.args = "-M q35 -nodefaults "
"-device igb,netdev=net0 -netdev user,id=net0",
.objects = "igb",
},{
.name = "cirrus-vga",
.args = "-machine q35 -nodefaults -device cirrus-vga",

256
tests/qtest/igb-test.c Normal file
View File

@ -0,0 +1,256 @@
/*
* QTest testcase for igb NIC
*
* Copyright (c) 2022-2023 Red Hat, Inc.
* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
* Developed by Daynix Computing LTD (http://www.daynix.com)
*
* Authors:
* Akihiko Odaki <akihiko.odaki@daynix.com>
* Dmitry Fleytman <dmitry@daynix.com>
* Leonid Bloch <leonid@daynix.com>
* Yan Vugenfirer <yan@daynix.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "libqtest-single.h"
#include "libqos/pci-pc.h"
#include "net/eth.h"
#include "qemu/sockets.h"
#include "qemu/iov.h"
#include "qemu/module.h"
#include "qemu/bitops.h"
#include "libqos/libqos-malloc.h"
#include "libqos/e1000e.h"
#include "hw/net/igb_regs.h"
#ifndef _WIN32
static const struct eth_header packet = {
.h_dest = E1000E_ADDRESS,
.h_source = E1000E_ADDRESS,
};
static void igb_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
{
union e1000_adv_tx_desc descr;
char buffer[64];
int ret;
uint32_t recv_len;
/* Prepare test data buffer */
uint64_t data = guest_alloc(alloc, sizeof(buffer));
memwrite(data, &packet, sizeof(packet));
/* Prepare TX descriptor */
memset(&descr, 0, sizeof(descr));
descr.read.buffer_addr = cpu_to_le64(data);
descr.read.cmd_type_len = cpu_to_le32(E1000_TXD_CMD_RS |
E1000_TXD_CMD_EOP |
E1000_TXD_DTYP_D |
sizeof(buffer));
/* Put descriptor to the ring */
e1000e_tx_ring_push(d, &descr);
/* Wait for TX WB interrupt */
e1000e_wait_isr(d, E1000E_TX0_MSG_ID);
/* Check DD bit */
g_assert_cmphex(le32_to_cpu(descr.wb.status) & E1000_TXD_STAT_DD, ==,
E1000_TXD_STAT_DD);
/* Check data sent to the backend */
ret = recv(test_sockets[0], &recv_len, sizeof(recv_len), 0);
g_assert_cmpint(ret, == , sizeof(recv_len));
ret = recv(test_sockets[0], buffer, sizeof(buffer), 0);
g_assert_cmpint(ret, ==, sizeof(buffer));
g_assert_false(memcmp(buffer, &packet, sizeof(packet)));
/* Free test data buffer */
guest_free(alloc, data);
}
static void igb_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
{
union e1000_adv_rx_desc descr;
struct eth_header test_iov = packet;
int len = htonl(sizeof(packet));
struct iovec iov[] = {
{
.iov_base = &len,
.iov_len = sizeof(len),
},{
.iov_base = &test_iov,
.iov_len = sizeof(packet),
},
};
char buffer[64];
int ret;
/* Send a dummy packet to device's socket*/
ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(packet));
g_assert_cmpint(ret, == , sizeof(packet) + sizeof(len));
/* Prepare test data buffer */
uint64_t data = guest_alloc(alloc, sizeof(buffer));
/* Prepare RX descriptor */
memset(&descr, 0, sizeof(descr));
descr.read.pkt_addr = cpu_to_le64(data);
/* Put descriptor to the ring */
e1000e_rx_ring_push(d, &descr);
/* Wait for TX WB interrupt */
e1000e_wait_isr(d, E1000E_RX0_MSG_ID);
/* Check DD bit */
g_assert_cmphex(le32_to_cpu(descr.wb.upper.status_error) &
E1000_RXD_STAT_DD, ==, E1000_RXD_STAT_DD);
/* Check data sent to the backend */
memread(data, buffer, sizeof(buffer));
g_assert_false(memcmp(buffer, &packet, sizeof(packet)));
/* Free test data buffer */
guest_free(alloc, data);
}
static void test_e1000e_init(void *obj, void *data, QGuestAllocator * alloc)
{
/* init does nothing */
}
static void test_igb_tx(void *obj, void *data, QGuestAllocator * alloc)
{
QE1000E_PCI *e1000e = obj;
QE1000E *d = &e1000e->e1000e;
QOSGraphObject *e_object = obj;
QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
/* FIXME: add spapr support */
if (qpci_check_buggy_msi(dev)) {
return;
}
igb_send_verify(d, data, alloc);
}
static void test_igb_rx(void *obj, void *data, QGuestAllocator * alloc)
{
QE1000E_PCI *e1000e = obj;
QE1000E *d = &e1000e->e1000e;
QOSGraphObject *e_object = obj;
QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
/* FIXME: add spapr support */
if (qpci_check_buggy_msi(dev)) {
return;
}
igb_receive_verify(d, data, alloc);
}
static void test_igb_multiple_transfers(void *obj, void *data,
QGuestAllocator *alloc)
{
static const long iterations = 4 * 1024;
long i;
QE1000E_PCI *e1000e = obj;
QE1000E *d = &e1000e->e1000e;
QOSGraphObject *e_object = obj;
QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
/* FIXME: add spapr support */
if (qpci_check_buggy_msi(dev)) {
return;
}
for (i = 0; i < iterations; i++) {
igb_send_verify(d, data, alloc);
igb_receive_verify(d, data, alloc);
}
}
static void data_test_clear(void *sockets)
{
int *test_sockets = sockets;
close(test_sockets[0]);
qos_invalidate_command_line();
close(test_sockets[1]);
g_free(test_sockets);
}
static void *data_test_init(GString *cmd_line, void *arg)
{
int *test_sockets = g_new(int, 2);
int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
g_assert_cmpint(ret, != , -1);
g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ",
test_sockets[1]);
g_test_queue_destroy(data_test_clear, test_sockets);
return test_sockets;
}
#endif
static void *data_test_init_no_socket(GString *cmd_line, void *arg)
{
g_string_append(cmd_line, " -netdev hubport,hubid=0,id=hs0 ");
return arg;
}
static void test_igb_hotplug(void *obj, void *data, QGuestAllocator * alloc)
{
QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */
QE1000E_PCI *dev = obj;
if (dev->pci_dev.bus->not_hotpluggable) {
g_test_skip("pci bus does not support hotplug");
return;
}
qtest_qmp_device_add(qts, "igb", "igb_net", "{'addr': '0x06'}");
qpci_unplug_acpi_device_test(qts, "igb_net", 0x06);
}
static void register_igb_test(void)
{
QOSGraphTestOptions opts = { 0 };
#ifndef _WIN32
opts.before = data_test_init,
qos_add_test("init", "igb", test_e1000e_init, &opts);
qos_add_test("tx", "igb", test_igb_tx, &opts);
qos_add_test("rx", "igb", test_igb_rx, &opts);
qos_add_test("multiple_transfers", "igb",
test_igb_multiple_transfers, &opts);
#endif
opts.before = data_test_init_no_socket;
qos_add_test("hotplug", "igb", test_igb_hotplug, &opts);
}
libqos_init(register_igb_test);

View File

@ -36,18 +36,6 @@
#define E1000E_RING_LEN (0x1000)
static void e1000e_macreg_write(QE1000E *d, uint32_t reg, uint32_t val)
{
QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
qpci_io_writel(&d_pci->pci_dev, d_pci->mac_regs, reg, val);
}
static uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg)
{
QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
return qpci_io_readl(&d_pci->pci_dev, d_pci->mac_regs, reg);
}
void e1000e_tx_ring_push(QE1000E *d, void *descr)
{
QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);

View File

@ -25,6 +25,8 @@
#define E1000E_RX0_MSG_ID (0)
#define E1000E_TX0_MSG_ID (1)
#define E1000E_ADDRESS { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 }
typedef struct QE1000E QE1000E;
typedef struct QE1000E_PCI QE1000E_PCI;
@ -40,6 +42,18 @@ struct QE1000E_PCI {
QE1000E e1000e;
};
static inline void e1000e_macreg_write(QE1000E *d, uint32_t reg, uint32_t val)
{
QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
qpci_io_writel(&d_pci->pci_dev, d_pci->mac_regs, reg, val);
}
static inline uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg)
{
QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
return qpci_io_readl(&d_pci->pci_dev, d_pci->mac_regs, reg);
}
void e1000e_wait_isr(QE1000E *d, uint16_t msg_id);
void e1000e_tx_ring_push(QE1000E *d, void *descr);
void e1000e_rx_ring_push(QE1000E *d, void *descr);

185
tests/qtest/libqos/igb.c Normal file
View File

@ -0,0 +1,185 @@
/*
* libqos driver framework
*
* Copyright (c) 2022-2023 Red Hat, Inc.
* Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
#include "qemu/osdep.h"
#include "hw/net/igb_regs.h"
#include "hw/net/mii.h"
#include "hw/pci/pci_ids.h"
#include "../libqtest.h"
#include "pci-pc.h"
#include "qemu/sockets.h"
#include "qemu/iov.h"
#include "qemu/module.h"
#include "qemu/bitops.h"
#include "libqos-malloc.h"
#include "qgraph.h"
#include "e1000e.h"
#define IGB_IVAR_TEST_CFG \
((E1000E_RX0_MSG_ID | E1000_IVAR_VALID) << (igb_ivar_entry_rx(0) * 8) | \
((E1000E_TX0_MSG_ID | E1000_IVAR_VALID) << (igb_ivar_entry_tx(0) * 8)))
#define E1000E_RING_LEN (0x1000)
static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data)
{
QPCIDevice *res = data;
memcpy(res, dev, sizeof(QPCIDevice));
g_free(dev);
}
static void e1000e_pci_destructor(QOSGraphObject *obj)
{
QE1000E_PCI *epci = (QE1000E_PCI *) obj;
qpci_iounmap(&epci->pci_dev, epci->mac_regs);
qpci_msix_disable(&epci->pci_dev);
}
static void igb_pci_start_hw(QOSGraphObject *obj)
{
static const uint8_t address[] = E1000E_ADDRESS;
QE1000E_PCI *d = (QE1000E_PCI *) obj;
uint32_t val;
/* Enable the device */
qpci_device_enable(&d->pci_dev);
/* Reset the device */
val = e1000e_macreg_read(&d->e1000e, E1000_CTRL);
e1000e_macreg_write(&d->e1000e, E1000_CTRL, val | E1000_CTRL_RST | E1000_CTRL_SLU);
/* Setup link */
e1000e_macreg_write(&d->e1000e, E1000_MDIC,
MII_BMCR_AUTOEN | MII_BMCR_ANRESTART |
(MII_BMCR << E1000_MDIC_REG_SHIFT) |
(1 << E1000_MDIC_PHY_SHIFT) |
E1000_MDIC_OP_WRITE);
qtest_clock_step(d->pci_dev.bus->qts, 900000000);
/* Enable and configure MSI-X */
qpci_msix_enable(&d->pci_dev);
e1000e_macreg_write(&d->e1000e, E1000_IVAR0, IGB_IVAR_TEST_CFG);
/* Check the device link status */
val = e1000e_macreg_read(&d->e1000e, E1000_STATUS);
g_assert_cmphex(val & E1000_STATUS_LU, ==, E1000_STATUS_LU);
/* Initialize TX/RX logic */
e1000e_macreg_write(&d->e1000e, E1000_RCTL, 0);
e1000e_macreg_write(&d->e1000e, E1000_TCTL, 0);
e1000e_macreg_write(&d->e1000e, E1000_TDBAL(0),
(uint32_t) d->e1000e.tx_ring);
e1000e_macreg_write(&d->e1000e, E1000_TDBAH(0),
(uint32_t) (d->e1000e.tx_ring >> 32));
e1000e_macreg_write(&d->e1000e, E1000_TDLEN(0), E1000E_RING_LEN);
e1000e_macreg_write(&d->e1000e, E1000_TDT(0), 0);
e1000e_macreg_write(&d->e1000e, E1000_TDH(0), 0);
/* Enable transmit */
e1000e_macreg_write(&d->e1000e, E1000_TCTL, E1000_TCTL_EN);
e1000e_macreg_write(&d->e1000e, E1000_RDBAL(0),
(uint32_t)d->e1000e.rx_ring);
e1000e_macreg_write(&d->e1000e, E1000_RDBAH(0),
(uint32_t)(d->e1000e.rx_ring >> 32));
e1000e_macreg_write(&d->e1000e, E1000_RDLEN(0), E1000E_RING_LEN);
e1000e_macreg_write(&d->e1000e, E1000_RDT(0), 0);
e1000e_macreg_write(&d->e1000e, E1000_RDH(0), 0);
e1000e_macreg_write(&d->e1000e, E1000_RA,
le32_to_cpu(*(uint32_t *)address));
e1000e_macreg_write(&d->e1000e, E1000_RA + 4,
E1000_RAH_AV | E1000_RAH_POOL_1 |
le16_to_cpu(*(uint16_t *)(address + 4)));
/* Enable receive */
e1000e_macreg_write(&d->e1000e, E1000_RFCTL, E1000_RFCTL_EXTEN);
e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN);
/* Enable all interrupts */
e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF);
e1000e_macreg_write(&d->e1000e, E1000_EIMS, 0xFFFFFFFF);
}
static void *igb_pci_get_driver(void *obj, const char *interface)
{
QE1000E_PCI *epci = obj;
if (!g_strcmp0(interface, "igb-if")) {
return &epci->e1000e;
}
/* implicit contains */
if (!g_strcmp0(interface, "pci-device")) {
return &epci->pci_dev;
}
fprintf(stderr, "%s not present in igb\n", interface);
g_assert_not_reached();
}
static void *igb_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
{
QE1000E_PCI *d = g_new0(QE1000E_PCI, 1);
QPCIBus *bus = pci_bus;
QPCIAddress *address = addr;
qpci_device_foreach(bus, address->vendor_id, address->device_id,
e1000e_foreach_callback, &d->pci_dev);
/* Map BAR0 (mac registers) */
d->mac_regs = qpci_iomap(&d->pci_dev, 0, NULL);
/* Allocate and setup TX ring */
d->e1000e.tx_ring = guest_alloc(alloc, E1000E_RING_LEN);
g_assert(d->e1000e.tx_ring != 0);
/* Allocate and setup RX ring */
d->e1000e.rx_ring = guest_alloc(alloc, E1000E_RING_LEN);
g_assert(d->e1000e.rx_ring != 0);
d->obj.get_driver = igb_pci_get_driver;
d->obj.start_hw = igb_pci_start_hw;
d->obj.destructor = e1000e_pci_destructor;
return &d->obj;
}
static void igb_register_nodes(void)
{
QPCIAddress addr = {
.vendor_id = PCI_VENDOR_ID_INTEL,
.device_id = E1000_DEV_ID_82576,
};
/*
* FIXME: every test using this node needs to setup a -netdev socket,id=hs0
* otherwise QEMU is not going to start
*/
QOSGraphEdgeOptions opts = {
.extra_device_opts = "netdev=hs0",
};
add_qpci_address(&opts, &addr);
qos_node_create_driver("igb", igb_pci_create);
qos_node_consumes("igb", "pci-bus", &opts);
}
libqos_init(igb_register_nodes);

View File

@ -30,6 +30,7 @@ libqos_srcs = files(
'i2c.c',
'i2c-imx.c',
'i2c-omap.c',
'igb.c',
'sdhci.c',
'tpci200.c',
'virtio.c',

View File

@ -259,6 +259,7 @@ qos_test_ss.add(
'virtio-scsi-test.c',
'virtio-iommu-test.c',
'vmxnet3-test.c',
'igb-test.c',
)
if config_all_devices.has_key('CONFIG_VIRTIO_SERIAL')

View File

@ -1,9 +1,9 @@
OBJS = rss.bpf.o
LLC ?= llc
LLVM_STRIP ?= llvm-strip
CLANG ?= clang
INC_FLAGS = `$(CLANG) -print-file-name=include`
EXTRA_CFLAGS ?= -O2 -emit-llvm -fno-stack-protector
EXTRA_CFLAGS ?= -O2 -g -target bpf
all: $(OBJS)
@ -11,11 +11,13 @@ all: $(OBJS)
clean:
rm -f $(OBJS)
rm -f rss.bpf.skeleton.h
$(OBJS): %.o:%.c
$(CLANG) $(INC_FLAGS) \
-D__KERNEL__ -D__ASM_SYSREG_H \
-I../include $(LINUXINCLUDE) \
$(EXTRA_CFLAGS) -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
$(EXTRA_CFLAGS) -c $< -o $@
$(LLVM_STRIP) -g $@
bpftool gen skeleton rss.bpf.o > rss.bpf.skeleton.h
cp rss.bpf.skeleton.h ../../ebpf/

View File

@ -76,29 +76,26 @@ struct packet_hash_info_t {
};
};
struct bpf_map_def SEC("maps")
tap_rss_map_configurations = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct rss_config_t),
.max_entries = 1,
};
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(struct rss_config_t));
__uint(max_entries, 1);
} tap_rss_map_configurations SEC(".maps");
struct bpf_map_def SEC("maps")
tap_rss_map_toeplitz_key = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct toeplitz_key_data_t),
.max_entries = 1,
};
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(struct toeplitz_key_data_t));
__uint(max_entries, 1);
} tap_rss_map_toeplitz_key SEC(".maps");
struct bpf_map_def SEC("maps")
tap_rss_map_indirection_table = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u16),
.max_entries = INDIRECTION_TABLE_SIZE,
};
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(__u16));
__uint(max_entries, INDIRECTION_TABLE_SIZE);
} tap_rss_map_indirection_table SEC(".maps");
static inline void net_rx_rss_add_chunk(__u8 *rss_input, size_t *bytes_written,
const void *ptr, size_t size) {