mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-25 15:14:31 +00:00
-----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:
commit
7284d53f6f
13
MAINTAINERS
13
MAINTAINERS
@ -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>
|
||||
|
@ -93,3 +93,4 @@ Emulated Devices
|
||||
devices/virtio-pmem.rst
|
||||
devices/vhost-user-rng.rst
|
||||
devices/canokey.rst
|
||||
devices/igb.rst
|
||||
|
71
docs/system/devices/igb.rst
Normal file
71
docs/system/devices/igb.rst
Normal 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
@ -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);
|
||||
|
@ -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
|
||||
|
249
hw/net/e1000.c
249
hw/net/e1000.c
@ -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
102
hw/net/e1000_common.h
Normal 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
102
hw/net/e1000e.c
102
hw/net/e1000e.c
@ -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
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
967
hw/net/e1000x_regs.h
Normal 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 */
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
623
hw/net/igb.c
Normal 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
146
hw/net/igb_common.h
Normal 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
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
146
hw/net/igb_core.h
Normal 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
648
hw/net/igb_regs.h
Normal 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 Write–Back Address Low; RW */
|
||||
#define E1000_TDWBAL(_n) (0x0E038 + (0x40 * (_n)))
|
||||
#define E1000_TDWBAL_A(_n) (0x03838 + (0x100 * (_n)))
|
||||
|
||||
/* TX Descriptor Completion Write–Back 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
327
hw/net/igbvf.c
Normal 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)
|
@ -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'))
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
11
net/dump.c
11
net/dump.c
@ -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
114
net/eth.c
@ -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)
|
||||
{
|
||||
|
18
net/net.c
18
net/net.c
@ -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) {
|
||||
|
16
net/tap.c
16
net/tap.c
@ -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,
|
||||
|
@ -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
38
tests/avocado/igb.py
Normal 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')
|
@ -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);
|
||||
|
@ -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
256
tests/qtest/igb-test.c
Normal 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);
|
@ -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);
|
||||
|
@ -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
185
tests/qtest/libqos/igb.c
Normal 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);
|
@ -30,6 +30,7 @@ libqos_srcs = files(
|
||||
'i2c.c',
|
||||
'i2c-imx.c',
|
||||
'i2c-omap.c',
|
||||
'igb.c',
|
||||
'sdhci.c',
|
||||
'tpci200.c',
|
||||
'virtio.c',
|
||||
|
@ -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')
|
||||
|
@ -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/
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user