summaryrefslogtreecommitdiffstats
path: root/qemu/hw/net
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/hw/net')
-rw-r--r--qemu/hw/net/Makefile.objs1
-rw-r--r--qemu/hw/net/allwinner_emac.c1
-rw-r--r--qemu/hw/net/cadence_gem.c21
-rw-r--r--qemu/hw/net/dp8393x.c4
-rw-r--r--qemu/hw/net/e1000.c499
-rw-r--r--qemu/hw/net/e1000_regs.h8
-rw-r--r--qemu/hw/net/eepro100.c18
-rw-r--r--qemu/hw/net/etraxfs_eth.c6
-rw-r--r--qemu/hw/net/fsl_etsec/etsec.c3
-rw-r--r--qemu/hw/net/fsl_etsec/miim.c1
-rw-r--r--qemu/hw/net/fsl_etsec/registers.c1
-rw-r--r--qemu/hw/net/fsl_etsec/registers.h1
-rw-r--r--qemu/hw/net/fsl_etsec/rings.c5
-rw-r--r--qemu/hw/net/imx_fec.c711
-rw-r--r--qemu/hw/net/lan9118.c21
-rw-r--r--qemu/hw/net/lance.c1
-rw-r--r--qemu/hw/net/mcf_fec.c1
-rw-r--r--qemu/hw/net/milkymist-minimac2.c6
-rw-r--r--qemu/hw/net/mipsnet.c1
-rw-r--r--qemu/hw/net/ne2000-isa.c17
-rw-r--r--qemu/hw/net/ne2000.c25
-rw-r--r--qemu/hw/net/ne2000.h1
-rw-r--r--qemu/hw/net/opencores_eth.c3
-rw-r--r--qemu/hw/net/pcnet-pci.c1
-rw-r--r--qemu/hw/net/pcnet.c18
-rw-r--r--qemu/hw/net/rocker/qmp-norocker.c1
-rw-r--r--qemu/hw/net/rocker/rocker.c59
-rw-r--r--qemu/hw/net/rocker/rocker_desc.c13
-rw-r--r--qemu/hw/net/rocker/rocker_fp.c8
-rw-r--r--qemu/hw/net/rocker/rocker_fp.h1
-rw-r--r--qemu/hw/net/rocker/rocker_of_dpa.c23
-rw-r--r--qemu/hw/net/rocker/rocker_world.c8
-rw-r--r--qemu/hw/net/rocker/rocker_world.h1
-rw-r--r--qemu/hw/net/rtl8139.c135
-rw-r--r--qemu/hw/net/smc91c111.c34
-rw-r--r--qemu/hw/net/spapr_llan.c323
-rw-r--r--qemu/hw/net/stellaris_enet.c13
-rw-r--r--qemu/hw/net/vhost_net.c140
-rw-r--r--qemu/hw/net/virtio-net.c223
-rw-r--r--qemu/hw/net/vmware_utils.h7
-rw-r--r--qemu/hw/net/vmxnet3.c205
-rw-r--r--qemu/hw/net/vmxnet3.h6
-rw-r--r--qemu/hw/net/vmxnet_debug.h139
-rw-r--r--qemu/hw/net/vmxnet_rx_pkt.c1
-rw-r--r--qemu/hw/net/vmxnet_rx_pkt.h2
-rw-r--r--qemu/hw/net/vmxnet_tx_pkt.c20
-rw-r--r--qemu/hw/net/vmxnet_tx_pkt.h2
-rw-r--r--qemu/hw/net/xen_nic.c30
-rw-r--r--qemu/hw/net/xgmac.c1
-rw-r--r--qemu/hw/net/xilinx_axienet.c2
-rw-r--r--qemu/hw/net/xilinx_ethlite.c3
51 files changed, 2184 insertions, 591 deletions
diff --git a/qemu/hw/net/Makefile.objs b/qemu/hw/net/Makefile.objs
index 98801739e..64d044923 100644
--- a/qemu/hw/net/Makefile.objs
+++ b/qemu/hw/net/Makefile.objs
@@ -19,6 +19,7 @@ common-obj-$(CONFIG_XGMAC) += xgmac.o
common-obj-$(CONFIG_MIPSNET) += mipsnet.o
common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
common-obj-$(CONFIG_ALLWINNER_EMAC) += allwinner_emac.o
+common-obj-$(CONFIG_IMX_FEC) += imx_fec.o
common-obj-$(CONFIG_CADENCE) += cadence_gem.o
common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
diff --git a/qemu/hw/net/allwinner_emac.c b/qemu/hw/net/allwinner_emac.c
index 0407dee6d..16d4b63ba 100644
--- a/qemu/hw/net/allwinner_emac.c
+++ b/qemu/hw/net/allwinner_emac.c
@@ -16,6 +16,7 @@
* GNU General Public License for more details.
*
*/
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "net/net.h"
#include "qemu/fifo8.h"
diff --git a/qemu/hw/net/cadence_gem.c b/qemu/hw/net/cadence_gem.c
index 494a346cf..0346f3e33 100644
--- a/qemu/hw/net/cadence_gem.c
+++ b/qemu/hw/net/cadence_gem.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include <zlib.h> /* For crc32 */
#include "hw/net/cadence_gem.h"
@@ -677,6 +678,10 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
} else {
unsigned crc_val;
+ if (size > sizeof(rxbuf) - sizeof(crc_val)) {
+ size = sizeof(rxbuf) - sizeof(crc_val);
+ }
+ bytes_to_copy = size;
/* The application wants the FCS field, which QEMU does not provide.
* We must try and calculate one.
*/
@@ -862,6 +867,14 @@ static void gem_transmit(CadenceGEMState *s)
break;
}
+ if (tx_desc_get_length(desc) > sizeof(tx_packet) - (p - tx_packet)) {
+ DB_PRINT("TX descriptor @ 0x%x too large: size 0x%x space 0x%x\n",
+ (unsigned)packet_desc_addr,
+ (unsigned)tx_desc_get_length(desc),
+ sizeof(tx_packet) - (p - tx_packet));
+ break;
+ }
+
/* Gather this fragment of the packet from "dma memory" to our contig.
* buffer.
*/
@@ -951,7 +964,7 @@ static void gem_phy_reset(CadenceGEMState *s)
s->phy_regs[PHY_REG_1000BTSTAT] = 0x7C00;
s->phy_regs[PHY_REG_EXTSTAT] = 0x3000;
s->phy_regs[PHY_REG_PHYSPCFC_CTL] = 0x0078;
- s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0xBC00;
+ s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0x7C00;
s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL] = 0x0C60;
s->phy_regs[PHY_REG_LED] = 0x4100;
s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL2] = 0x000A;
@@ -964,6 +977,7 @@ static void gem_reset(DeviceState *d)
{
int i;
CadenceGEMState *s = CADENCE_GEM(d);
+ const uint8_t *a;
DB_PRINT("\n");
@@ -982,6 +996,11 @@ static void gem_reset(DeviceState *d)
s->regs[GEM_DESCONF5] = 0x002f2145;
s->regs[GEM_DESCONF6] = 0x00000200;
+ /* Set MAC address */
+ a = &s->conf.macaddr.a[0];
+ s->regs[GEM_SPADDR1LO] = a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24);
+ s->regs[GEM_SPADDR1HI] = a[4] | (a[5] << 8);
+
for (i = 0; i < 4; i++) {
s->sar_active[i] = false;
}
diff --git a/qemu/hw/net/dp8393x.c b/qemu/hw/net/dp8393x.c
index ab607e484..0fa652c39 100644
--- a/qemu/hw/net/dp8393x.c
+++ b/qemu/hw/net/dp8393x.c
@@ -17,9 +17,11 @@
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/devices.h"
#include "net/net.h"
+#include "qapi/error.h"
#include "qemu/timer.h"
#include <zlib.h>
@@ -292,7 +294,7 @@ static void dp8393x_set_next_tick(dp8393xState *s)
ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
s->wt_last_update = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- delay = get_ticks_per_sec() * ticks / 5000000;
+ delay = NANOSECONDS_PER_SECOND * ticks / 5000000;
timer_mod(s->watchdog, s->wt_last_update + delay);
}
diff --git a/qemu/hw/net/e1000.c b/qemu/hw/net/e1000.c
index 09c9e9d53..8e79b550e 100644
--- a/qemu/hw/net/e1000.c
+++ b/qemu/hw/net/e1000.c
@@ -25,6 +25,7 @@
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "net/net.h"
@@ -37,24 +38,26 @@
#include "e1000_regs.h"
+static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
#define E1000_DEBUG
#ifdef E1000_DEBUG
enum {
- DEBUG_GENERAL, DEBUG_IO, DEBUG_MMIO, DEBUG_INTERRUPT,
- DEBUG_RX, DEBUG_TX, DEBUG_MDIC, DEBUG_EEPROM,
- DEBUG_UNKNOWN, DEBUG_TXSUM, DEBUG_TXERR, DEBUG_RXERR,
+ DEBUG_GENERAL, DEBUG_IO, DEBUG_MMIO, DEBUG_INTERRUPT,
+ DEBUG_RX, DEBUG_TX, DEBUG_MDIC, DEBUG_EEPROM,
+ DEBUG_UNKNOWN, DEBUG_TXSUM, DEBUG_TXERR, DEBUG_RXERR,
DEBUG_RXFILTER, DEBUG_PHY, DEBUG_NOTYET,
};
-#define DBGBIT(x) (1<<DEBUG_##x)
+#define DBGBIT(x) (1<<DEBUG_##x)
static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
-#define DBGOUT(what, fmt, ...) do { \
+#define DBGOUT(what, fmt, ...) do { \
if (debugflags & DBGBIT(what)) \
fprintf(stderr, "e1000: " fmt, ## __VA_ARGS__); \
} while (0)
#else
-#define DBGOUT(what, fmt, ...) do {} while (0)
+#define DBGOUT(what, fmt, ...) do {} while (0)
#endif
#define IOPORT_SIZE 0x40
@@ -118,7 +121,7 @@ typedef struct E1000State_st {
} tx;
struct {
- uint32_t val_in; // shifted in from guest driver
+ uint32_t val_in; /* shifted in from guest driver */
uint16_t bitnum_in;
uint16_t bitnum_out;
uint16_t reading;
@@ -135,11 +138,15 @@ typedef struct E1000State_st {
/* Compatibility flags for migration to/from qemu 1.3.0 and older */
#define E1000_FLAG_AUTONEG_BIT 0
#define E1000_FLAG_MIT_BIT 1
+#define E1000_FLAG_MAC_BIT 2
#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT)
#define E1000_FLAG_MIT (1 << E1000_FLAG_MIT_BIT)
+#define E1000_FLAG_MAC (1 << E1000_FLAG_MAC_BIT)
uint32_t compat_flags;
} E1000State;
+#define chkflag(x) (s->compat_flags & E1000_FLAG_##x)
+
typedef struct E1000BaseClass {
PCIDeviceClass parent_class;
uint16_t phy_id2;
@@ -155,20 +162,36 @@ typedef struct E1000BaseClass {
#define E1000_DEVICE_GET_CLASS(obj) \
OBJECT_GET_CLASS(E1000BaseClass, (obj), TYPE_E1000_BASE)
-#define defreg(x) x = (E1000_##x>>2)
+#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(RDBAH),
- defreg(RDBAL), defreg(RDH), defreg(RDLEN), defreg(RDT),
- defreg(STATUS), defreg(SWSM), defreg(TCTL), defreg(TDBAH),
- defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT),
- 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(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(RDBAH),
+ defreg(RDBAL), defreg(RDH), defreg(RDLEN), defreg(RDT),
+ defreg(STATUS), defreg(SWSM), defreg(TCTL), defreg(TDBAH),
+ defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT),
+ 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(FCRUC), defreg(TDFH), defreg(TDFT),
+ defreg(TDFHS), defreg(TDFTS), defreg(TDFPC), defreg(RDFH),
+ defreg(RDFT), defreg(RDFHS), defreg(RDFTS), defreg(RDFPC),
+ defreg(IPAV), defreg(WUC), defreg(WUS), defreg(AIT),
+ defreg(IP6AT), defreg(IP4AT), defreg(FFLT), defreg(FFMT),
+ defreg(FFVT), defreg(WUPM), defreg(PBM), defreg(SCC),
+ defreg(ECOL), defreg(MCC), defreg(LATECOL), defreg(COLC),
+ defreg(DC), defreg(TNCRS), defreg(SEC), defreg(CEXTERR),
+ defreg(RLEC), defreg(XONRXC), defreg(XONTXC), defreg(XOFFRXC),
+ defreg(XOFFTXC), defreg(RFC), defreg(RJC), defreg(RNBC),
+ defreg(TSCTFC), defreg(MGTPRC), defreg(MGTPDC), defreg(MGTPTC),
+ defreg(RUC), defreg(ROC), defreg(GORCL), defreg(GORCH),
+ defreg(GOTCL), defreg(GOTCH), defreg(BPRC), defreg(MPRC),
+ defreg(TSCTC), 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(MPTC), defreg(BPTC)
};
static void
@@ -193,8 +216,7 @@ e1000_link_up(E1000State *s)
static bool
have_autoneg(E1000State *s)
{
- return (s->compat_flags & E1000_FLAG_AUTONEG) &&
- (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN);
+ return chkflag(AUTONEG) && (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN);
}
static void
@@ -226,18 +248,18 @@ 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_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,
};
/* PHY_ID2 documented in 8254x_GBe_SDM.pdf, pp. 250 */
static const uint16_t phy_reg_init[] = {
- [PHY_CTRL] = MII_CR_SPEED_SELECT_MSB |
+ [PHY_CTRL] = MII_CR_SPEED_SELECT_MSB |
MII_CR_FULL_DUPLEX |
MII_CR_AUTO_NEG_EN,
@@ -264,15 +286,15 @@ static const uint16_t phy_reg_init[] = {
};
static const uint32_t mac_reg_init[] = {
- [PBA] = 0x00100030,
- [LEDCTL] = 0x602,
- [CTRL] = E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
+ [PBA] = 0x00100030,
+ [LEDCTL] = 0x602,
+ [CTRL] = E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
- [STATUS] = 0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
+ [STATUS] = 0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
E1000_STATUS_LU,
- [MANC] = E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
+ [MANC] = E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
E1000_MANC_RMCP_EN,
};
@@ -319,7 +341,7 @@ set_interrupt_cause(E1000State *s, int index, uint32_t val)
if (s->mit_timer_on) {
return;
}
- if (s->compat_flags & E1000_FLAG_MIT) {
+ if (chkflag(MIT)) {
/* Compute the next mitigation delay according to pending
* interrupts and the current values of RADV (provided
* RDTR!=0), TADV and ITR.
@@ -335,6 +357,14 @@ set_interrupt_cause(E1000State *s, int index, uint32_t val)
}
mit_update_delay(&mit_delay, s->mac_reg[ITR]);
+ /*
+ * According to e1000 SPEC, the Ethernet controller guarantees
+ * a maximum observable interrupt rate of 7813 interrupts/sec.
+ * Thus if mit_delay < 500 then the delay should be set to the
+ * minimum delay possible which is 500.
+ */
+ mit_delay = (mit_delay < 500) ? 500 : mit_delay;
+
if (mit_delay) {
s->mit_timer_on = 1;
timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
@@ -510,17 +540,19 @@ set_eecd(E1000State *s, int index, uint32_t val)
s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
- if (!(E1000_EECD_CS & val)) // CS inactive; nothing to do
- return;
- if (E1000_EECD_CS & (val ^ oldval)) { // CS rise edge; reset state
- s->eecd_state.val_in = 0;
- s->eecd_state.bitnum_in = 0;
- s->eecd_state.bitnum_out = 0;
- s->eecd_state.reading = 0;
+ if (!(E1000_EECD_CS & val)) { /* CS inactive; nothing to do */
+ return;
}
- if (!(E1000_EECD_SK & (val ^ oldval))) // no clock edge
+ if (E1000_EECD_CS & (val ^ oldval)) { /* CS rise edge; reset state */
+ s->eecd_state.val_in = 0;
+ s->eecd_state.bitnum_in = 0;
+ s->eecd_state.bitnum_out = 0;
+ s->eecd_state.reading = 0;
+ }
+ if (!(E1000_EECD_SK & (val ^ oldval))) { /* no clock edge */
return;
- if (!(E1000_EECD_SK & val)) { // falling edge
+ }
+ if (!(E1000_EECD_SK & val)) { /* falling edge */
s->eecd_state.bitnum_out++;
return;
}
@@ -565,6 +597,56 @@ putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
}
}
+static inline void
+inc_reg_if_not_full(E1000State *s, int index)
+{
+ if (s->mac_reg[index] != 0xffffffff) {
+ s->mac_reg[index]++;
+ }
+}
+
+static inline void
+inc_tx_bcast_or_mcast_count(E1000State *s, const unsigned char *arr)
+{
+ if (!memcmp(arr, bcast, sizeof bcast)) {
+ inc_reg_if_not_full(s, BPTC);
+ } else if (arr[0] & 1) {
+ inc_reg_if_not_full(s, MPTC);
+ }
+}
+
+static void
+grow_8reg_if_not_full(E1000State *s, int index, int size)
+{
+ uint64_t sum = s->mac_reg[index] | (uint64_t)s->mac_reg[index+1] << 32;
+
+ if (sum + size < sum) {
+ sum = ~0ULL;
+ } else {
+ sum += size;
+ }
+ s->mac_reg[index] = sum;
+ s->mac_reg[index+1] = sum >> 32;
+}
+
+static void
+increase_size_stats(E1000State *s, const int *size_regs, int size)
+{
+ if (size > 1023) {
+ inc_reg_if_not_full(s, size_regs[5]);
+ } else if (size > 511) {
+ inc_reg_if_not_full(s, size_regs[4]);
+ } else if (size > 255) {
+ inc_reg_if_not_full(s, size_regs[3]);
+ } else if (size > 127) {
+ inc_reg_if_not_full(s, size_regs[2]);
+ } else if (size > 64) {
+ inc_reg_if_not_full(s, size_regs[1]);
+ } else if (size == 64) {
+ inc_reg_if_not_full(s, size_regs[0]);
+ }
+}
+
static inline int
vlan_enabled(E1000State *s)
{
@@ -602,40 +684,49 @@ fcs_len(E1000State *s)
static void
e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
{
+ static const int PTCregs[6] = { PTC64, PTC127, PTC255, PTC511,
+ PTC1023, PTC1522 };
+
NetClientState *nc = qemu_get_queue(s->nic);
if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) {
nc->info->receive(nc, buf, size);
} else {
qemu_send_packet(nc, buf, size);
}
+ inc_tx_bcast_or_mcast_count(s, buf);
+ increase_size_stats(s, PTCregs, size);
}
static void
xmit_seg(E1000State *s)
{
uint16_t len, *sp;
- unsigned int frames = s->tx.tso_frames, css, sofar, n;
+ unsigned int frames = s->tx.tso_frames, css, sofar;
struct e1000_tx *tp = &s->tx;
if (tp->tse && tp->cptse) {
css = tp->ipcss;
DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
frames, tp->size, css);
- if (tp->ip) { // IPv4
+ if (tp->ip) { /* IPv4 */
stw_be_p(tp->data+css+2, tp->size - css);
stw_be_p(tp->data+css+4,
- be16_to_cpup((uint16_t *)(tp->data+css+4))+frames);
- } else // IPv6
+ be16_to_cpup((uint16_t *)(tp->data+css+4))+frames);
+ } else { /* IPv6 */
stw_be_p(tp->data+css+4, tp->size - css);
+ }
css = tp->tucss;
len = tp->size - css;
DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len);
if (tp->tcp) {
sofar = frames * tp->mss;
stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* seq */
- if (tp->paylen - sofar > tp->mss)
- tp->data[css + 13] &= ~9; // PSH, FIN
- } else // UDP
+ if (tp->paylen - sofar > tp->mss) {
+ tp->data[css + 13] &= ~9; /* PSH, FIN */
+ } else if (frames) {
+ inc_reg_if_not_full(s, TSCTC);
+ }
+ } else /* UDP */
stw_be_p(tp->data+css+4, len);
if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
unsigned int phsum;
@@ -657,13 +748,15 @@ xmit_seg(E1000State *s)
memmove(tp->data, tp->data + 4, 8);
memcpy(tp->data + 8, tp->vlan_header, 4);
e1000_send_packet(s, tp->vlan, tp->size + 4);
- } else
+ } else {
e1000_send_packet(s, tp->data, tp->size);
- s->mac_reg[TPT]++;
- s->mac_reg[GPTC]++;
- n = s->mac_reg[TOTL];
- if ((s->mac_reg[TOTL] += s->tx.size) < n)
- s->mac_reg[TOTH]++;
+ }
+
+ inc_reg_if_not_full(s, TPT);
+ grow_8reg_if_not_full(s, TOTL, s->tx.size);
+ s->mac_reg[GPTC] = s->mac_reg[TPT];
+ s->mac_reg[GOTCL] = s->mac_reg[TOTL];
+ s->mac_reg[GOTCH] = s->mac_reg[TOTH];
}
static void
@@ -679,7 +772,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
struct e1000_tx *tp = &s->tx;
s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE);
- if (dtype == E1000_TXD_CMD_DEXT) { // context descriptor
+ if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */
op = le32_to_cpu(xp->cmd_and_length);
tp->ipcss = xp->lower_setup.ip_fields.ipcss;
tp->ipcso = xp->lower_setup.ip_fields.ipcso;
@@ -694,7 +787,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
tp->tso_frames = 0;
- if (tp->tucso == 0) { // this is probably wrong
+ if (tp->tucso == 0) { /* this is probably wrong */
DBGOUT(TXSUM, "TCP/UDP: cso 0!\n");
tp->tucso = tp->tucss + (tp->tcp ? 16 : 6);
}
@@ -718,7 +811,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
stw_be_p(tp->vlan_header + 2,
le16_to_cpu(dp->upper.fields.special));
}
-
+
addr = le64_to_cpu(dp->buffer_addr);
if (tp->tse && tp->cptse) {
msh = tp->hdr_len + tp->mss;
@@ -819,7 +912,8 @@ start_xmit(E1000State *s)
* bogus values to TDT/TDLEN.
* there's nothing too intelligent we could do about this.
*/
- if (s->mac_reg[TDH] == tdh_start) {
+ if (s->mac_reg[TDH] == tdh_start ||
+ tdh_start >= s->mac_reg[TDLEN] / sizeof(desc)) {
DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
break;
@@ -831,9 +925,9 @@ start_xmit(E1000State *s)
static int
receive_filter(E1000State *s, const uint8_t *buf, int size)
{
- static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const int mta_shift[] = {4, 3, 2, 0};
uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
+ int isbcast = !memcmp(buf, bcast, sizeof bcast), ismcast = (buf[0] & 1);
if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14));
@@ -843,14 +937,19 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
return 0;
}
- if (rctl & E1000_RCTL_UPE) // promiscuous
+ if (!isbcast && !ismcast && (rctl & E1000_RCTL_UPE)) { /* promiscuous ucast */
return 1;
+ }
- if ((buf[0] & 1) && (rctl & E1000_RCTL_MPE)) // promiscuous mcast
+ if (ismcast && (rctl & E1000_RCTL_MPE)) { /* promiscuous mcast */
+ inc_reg_if_not_full(s, MPRC);
return 1;
+ }
- if ((rctl & E1000_RCTL_BAM) && !memcmp(buf, bcast, sizeof bcast))
+ if (isbcast && (rctl & E1000_RCTL_BAM)) { /* broadcast enabled */
+ inc_reg_if_not_full(s, BPRC);
return 1;
+ }
for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) {
if (!(rp[1] & E1000_RAH_AV))
@@ -870,8 +969,10 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
- if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f)))
+ if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f))) {
+ inc_reg_if_not_full(s, MPRC);
return 1;
+ }
DBGOUT(RXFILTER,
"dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
@@ -960,6 +1061,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
size_t desc_offset;
size_t desc_size;
size_t total_size;
+ static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511,
+ PRC1023, PRC1522 };
if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) {
return -1;
@@ -973,6 +1076,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
if (size < sizeof(min_buf)) {
iov_to_buf(iov, iovcnt, 0, min_buf, size);
memset(&min_buf[size], 0, sizeof(min_buf) - size);
+ inc_reg_if_not_full(s, RUC);
min_iov.iov_base = filter_buf = min_buf;
min_iov.iov_len = size = sizeof(min_buf);
iovcnt = 1;
@@ -988,6 +1092,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
(size > MAXIMUM_ETHERNET_VLAN_SIZE
&& !(s->mac_reg[RCTL] & E1000_RCTL_LPE)))
&& !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) {
+ inc_reg_if_not_full(s, ROC);
return size;
}
@@ -1065,7 +1170,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
s->mac_reg[RDH] = 0;
/* see comment in start_xmit; same here */
- if (s->mac_reg[RDH] == rdh_start) {
+ if (s->mac_reg[RDH] == rdh_start ||
+ rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) {
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
set_ics(s, 0, E1000_ICS_RXO);
@@ -1073,16 +1179,17 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
}
} while (desc_offset < total_size);
- s->mac_reg[GPRC]++;
- s->mac_reg[TPR]++;
+ increase_size_stats(s, PRCregs, total_size);
+ inc_reg_if_not_full(s, TPR);
+ s->mac_reg[GPRC] = s->mac_reg[TPR];
/* TOR - Total Octets Received:
* This register includes bytes received in a packet from the <Destination
* Address> field through the <CRC> field, inclusively.
+ * Always include FCS length (4) in size.
*/
- n = s->mac_reg[TORL] + size + /* Always include FCS length. */ 4;
- if (n < s->mac_reg[TORL])
- s->mac_reg[TORH]++;
- s->mac_reg[TORL] = n;
+ grow_8reg_if_not_full(s, TORL, size+4);
+ s->mac_reg[GORCL] = s->mac_reg[TORL];
+ s->mac_reg[GORCH] = s->mac_reg[TORH];
n = E1000_ICS_RXT0;
if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
@@ -1114,6 +1221,30 @@ mac_readreg(E1000State *s, int 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)
{
uint32_t ret = s->mac_reg[ICR];
@@ -1206,46 +1337,144 @@ set_ims(E1000State *s, int index, uint32_t val)
set_ics(s, 0, 0);
}
-#define getreg(x) [x] = mac_readreg
+#define getreg(x) [x] = mac_readreg
static uint32_t (*macreg_readops[])(E1000State *, int) = {
- getreg(PBA), getreg(RCTL), getreg(TDH), getreg(TXDCTL),
- getreg(WUFC), getreg(TDT), getreg(CTRL), getreg(LEDCTL),
- getreg(MANC), getreg(MDIC), getreg(SWSM), getreg(STATUS),
- getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL),
- getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS),
- getreg(TDBAL), getreg(TDBAH), getreg(RDBAH), getreg(RDBAL),
- getreg(TDLEN), getreg(RDLEN), getreg(RDTR), getreg(RADV),
- getreg(TADV), getreg(ITR),
-
- [TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4,
- [GPTC] = mac_read_clr4, [TPR] = mac_read_clr4, [TPT] = mac_read_clr4,
- [ICR] = mac_icr_read, [EECD] = get_eecd, [EERD] = flash_eerd_read,
- [CRCERRS ... MPC] = &mac_readreg,
- [RA ... RA+31] = &mac_readreg,
- [MTA ... MTA+127] = &mac_readreg,
+ getreg(PBA), getreg(RCTL), getreg(TDH), getreg(TXDCTL),
+ getreg(WUFC), getreg(TDT), getreg(CTRL), getreg(LEDCTL),
+ getreg(MANC), getreg(MDIC), getreg(SWSM), getreg(STATUS),
+ getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL),
+ getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS),
+ getreg(TDBAL), getreg(TDBAH), getreg(RDBAH), getreg(RDBAL),
+ getreg(TDLEN), getreg(RDLEN), getreg(RDTR), getreg(RADV),
+ getreg(TADV), getreg(ITR), getreg(FCRUC), getreg(IPAV),
+ getreg(WUC), getreg(WUS), getreg(SCC), getreg(ECOL),
+ getreg(MCC), getreg(LATECOL), getreg(COLC), getreg(DC),
+ getreg(TNCRS), getreg(SEC), getreg(CEXTERR), getreg(RLEC),
+ 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),
+
+ [TOTH] = mac_read_clr8, [TORH] = mac_read_clr8,
+ [GOTCH] = mac_read_clr8, [GORCH] = mac_read_clr8,
+ [PRC64] = mac_read_clr4, [PRC127] = mac_read_clr4,
+ [PRC255] = mac_read_clr4, [PRC511] = mac_read_clr4,
+ [PRC1023] = mac_read_clr4, [PRC1522] = mac_read_clr4,
+ [PTC64] = mac_read_clr4, [PTC127] = mac_read_clr4,
+ [PTC255] = mac_read_clr4, [PTC511] = mac_read_clr4,
+ [PTC1023] = mac_read_clr4, [PTC1522] = mac_read_clr4,
+ [GPRC] = mac_read_clr4, [GPTC] = mac_read_clr4,
+ [TPT] = mac_read_clr4, [TPR] = mac_read_clr4,
+ [RUC] = mac_read_clr4, [ROC] = mac_read_clr4,
+ [BPRC] = mac_read_clr4, [MPRC] = mac_read_clr4,
+ [TSCTC] = mac_read_clr4, [BPTC] = mac_read_clr4,
+ [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,
};
enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
-#define putreg(x) [x] = mac_writereg
+#define putreg(x) [x] = mac_writereg
static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
- putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC),
- putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH),
- putreg(RDBAL), putreg(LEDCTL), putreg(VET),
- [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,
- [RA ... RA+31] = &mac_writereg,
- [MTA ... MTA+127] = &mac_writereg,
+ 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),
+
+ [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,
+
+ [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,
};
enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
+enum { MAC_ACCESS_PARTIAL = 1, MAC_ACCESS_FLAG_NEEDED = 2 };
+
+#define markflag(x) ((E1000_FLAG_##x << 2) | MAC_ACCESS_FLAG_NEEDED)
+/* In the array below the meaning of the bits is: [f|f|f|f|f|f|n|p]
+ * f - flag bits (up to 6 possible flags)
+ * n - flag needed
+ * p - partially implenented */
+static const uint8_t mac_reg_access[0x8000] = {
+ [RDTR] = markflag(MIT), [TADV] = markflag(MIT),
+ [RADV] = markflag(MIT), [ITR] = markflag(MIT),
+
+ [IPAV] = markflag(MAC), [WUC] = markflag(MAC),
+ [IP6AT] = markflag(MAC), [IP4AT] = markflag(MAC),
+ [FFVT] = markflag(MAC), [WUPM] = markflag(MAC),
+ [ECOL] = markflag(MAC), [MCC] = markflag(MAC),
+ [DC] = markflag(MAC), [TNCRS] = markflag(MAC),
+ [RLEC] = markflag(MAC), [XONRXC] = markflag(MAC),
+ [XOFFTXC] = markflag(MAC), [RFC] = markflag(MAC),
+ [TSCTFC] = markflag(MAC), [MGTPRC] = markflag(MAC),
+ [WUS] = markflag(MAC), [AIT] = markflag(MAC),
+ [FFLT] = markflag(MAC), [FFMT] = markflag(MAC),
+ [SCC] = markflag(MAC), [FCRUC] = markflag(MAC),
+ [LATECOL] = markflag(MAC), [COLC] = markflag(MAC),
+ [SEC] = markflag(MAC), [CEXTERR] = markflag(MAC),
+ [XONTXC] = markflag(MAC), [XOFFRXC] = markflag(MAC),
+ [RJC] = markflag(MAC), [RNBC] = markflag(MAC),
+ [MGTPDC] = markflag(MAC), [MGTPTC] = markflag(MAC),
+ [RUC] = markflag(MAC), [ROC] = markflag(MAC),
+ [GORCL] = markflag(MAC), [GORCH] = markflag(MAC),
+ [GOTCL] = markflag(MAC), [GOTCH] = markflag(MAC),
+ [BPRC] = markflag(MAC), [MPRC] = markflag(MAC),
+ [TSCTC] = markflag(MAC), [PRC64] = markflag(MAC),
+ [PRC127] = markflag(MAC), [PRC255] = markflag(MAC),
+ [PRC511] = markflag(MAC), [PRC1023] = markflag(MAC),
+ [PRC1522] = markflag(MAC), [PTC64] = markflag(MAC),
+ [PTC127] = markflag(MAC), [PTC255] = markflag(MAC),
+ [PTC511] = markflag(MAC), [PTC1023] = markflag(MAC),
+ [PTC1522] = markflag(MAC), [MPTC] = markflag(MAC),
+ [BPTC] = markflag(MAC),
+
+ [TDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [TDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [TDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [TDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [TDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [RDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [RDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [RDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [RDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [RDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+ [PBM] = markflag(MAC) | MAC_ACCESS_PARTIAL,
+};
+
static void
e1000_mmio_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
@@ -1254,9 +1483,20 @@ e1000_mmio_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int index = (addr & 0x1ffff) >> 2;
if (index < NWRITEOPS && macreg_writeops[index]) {
- macreg_writeops[index](s, index, val);
+ if (!(mac_reg_access[index] & MAC_ACCESS_FLAG_NEEDED)
+ || (s->compat_flags & (mac_reg_access[index] >> 2))) {
+ if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
+ DBGOUT(GENERAL, "Writing to register at offset: 0x%08x. "
+ "It is not fully implemented.\n", index<<2);
+ }
+ macreg_writeops[index](s, index, val);
+ } else { /* "flag needed" bit is set, but the flag is not active */
+ DBGOUT(MMIO, "MMIO write attempt to disabled reg. addr=0x%08x\n",
+ index<<2);
+ }
} else if (index < NREADOPS && macreg_readops[index]) {
- DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04"PRIx64"\n", index<<2, val);
+ DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04"PRIx64"\n",
+ index<<2, val);
} else {
DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08"PRIx64"\n",
index<<2, val);
@@ -1269,11 +1509,21 @@ e1000_mmio_read(void *opaque, hwaddr addr, unsigned size)
E1000State *s = opaque;
unsigned int index = (addr & 0x1ffff) >> 2;
- if (index < NREADOPS && macreg_readops[index])
- {
- return macreg_readops[index](s, index);
+ if (index < NREADOPS && macreg_readops[index]) {
+ if (!(mac_reg_access[index] & MAC_ACCESS_FLAG_NEEDED)
+ || (s->compat_flags & (mac_reg_access[index] >> 2))) {
+ if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
+ DBGOUT(GENERAL, "Reading register at offset: 0x%08x. "
+ "It is not fully implemented.\n", index<<2);
+ }
+ return macreg_readops[index](s, index);
+ } else { /* "flag needed" bit is set, but the flag is not active */
+ DBGOUT(MMIO, "MMIO read attempt of disabled reg. addr=0x%08x\n",
+ index<<2);
+ }
+ } else {
+ DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2);
}
- DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2);
return 0;
}
@@ -1340,7 +1590,7 @@ static int e1000_post_load(void *opaque, int version_id)
E1000State *s = opaque;
NetClientState *nc = qemu_get_queue(s->nic);
- if (!(s->compat_flags & E1000_FLAG_MIT)) {
+ if (!chkflag(MIT)) {
s->mac_reg[ITR] = s->mac_reg[RDTR] = s->mac_reg[RADV] =
s->mac_reg[TADV] = 0;
s->mit_irq_level = false;
@@ -1367,7 +1617,14 @@ static bool e1000_mit_state_needed(void *opaque)
{
E1000State *s = opaque;
- return s->compat_flags & E1000_FLAG_MIT;
+ return chkflag(MIT);
+}
+
+static bool e1000_full_mac_needed(void *opaque)
+{
+ E1000State *s = opaque;
+
+ return chkflag(MAC);
}
static const VMStateDescription vmstate_e1000_mit_state = {
@@ -1385,6 +1642,17 @@ static const VMStateDescription vmstate_e1000_mit_state = {
}
};
+static const VMStateDescription vmstate_e1000_full_mac_state = {
+ .name = "e1000/full_mac_state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = e1000_full_mac_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(mac_reg, E1000State, 0x8000),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_e1000 = {
.name = "e1000",
.version_id = 2,
@@ -1464,6 +1732,7 @@ static const VMStateDescription vmstate_e1000 = {
},
.subsections = (const VMStateDescription*[]) {
&vmstate_e1000_mit_state,
+ &vmstate_e1000_full_mac_state,
NULL
}
};
@@ -1596,6 +1865,8 @@ static Property e1000_properties[] = {
compat_flags, E1000_FLAG_AUTONEG_BIT, true),
DEFINE_PROP_BIT("mitigation", E1000State,
compat_flags, E1000_FLAG_MIT_BIT, true),
+ DEFINE_PROP_BIT("extra_mac_registers", E1000State,
+ compat_flags, E1000_FLAG_MAC_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1647,7 +1918,7 @@ static const TypeInfo e1000_base_info = {
static const E1000Info e1000_devices[] = {
{
- .name = "e1000-82540em",
+ .name = "e1000",
.device_id = E1000_DEV_ID_82540EM,
.revision = 0x03,
.phy_id2 = E1000_PHY_ID2_8254xx_DEFAULT,
@@ -1666,11 +1937,6 @@ static const E1000Info e1000_devices[] = {
},
};
-static const TypeInfo e1000_default_info = {
- .name = "e1000",
- .parent = "e1000-82540em",
-};
-
static void e1000_register_types(void)
{
int i;
@@ -1688,7 +1954,6 @@ static void e1000_register_types(void)
type_register(&type_info);
}
- type_register_static(&e1000_default_info);
}
type_init(e1000_register_types)
diff --git a/qemu/hw/net/e1000_regs.h b/qemu/hw/net/e1000_regs.h
index 60b96aaf1..1c40244ab 100644
--- a/qemu/hw/net/e1000_regs.h
+++ b/qemu/hw/net/e1000_regs.h
@@ -158,7 +158,8 @@
#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
#define FEXTNVM_SW_CONFIG 0x0001
#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
-#define E1000_PBS 0x01008 /* Packet Buffer Size */
+#define E1000_PBM 0x10000 /* Packet Buffer Memory - RW */
+#define E1000_PBS 0x01008 /* Packet Buffer Size - RW */
#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
#define E1000_FLASH_UPDATES 1000
#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */
@@ -191,6 +192,11 @@
#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */
#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */
#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */
+#define E1000_RDFH 0x02410 /* Receive Data FIFO Head Register - RW */
+#define E1000_RDFT 0x02418 /* Receive Data FIFO Tail Register - RW */
+#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_TDFT 0x03418 /* TX Data FIFO Tail - RW */
#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */
diff --git a/qemu/hw/net/eepro100.c b/qemu/hw/net/eepro100.c
index 60333b7fc..9b4b9b59d 100644
--- a/qemu/hw/net/eepro100.c
+++ b/qemu/hw/net/eepro100.c
@@ -40,7 +40,7 @@
* * Wake-on-LAN is not implemented.
*/
-#include <stddef.h> /* offsetof */
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "net/net.h"
@@ -774,6 +774,11 @@ static void tx_command(EEPRO100State *s)
#if 0
uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6);
#endif
+ if (tx_buffer_size == 0) {
+ /* Prevent an endless loop. */
+ logout("loop in %s:%u\n", __FILE__, __LINE__);
+ break;
+ }
tbd_address += 8;
TRACE(RXTX, logout
("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
@@ -855,6 +860,10 @@ static void set_multicast_list(EEPRO100State *s)
static void action_command(EEPRO100State *s)
{
+ /* The loop below won't stop if it gets special handcrafted data.
+ Therefore we limit the number of iterations. */
+ unsigned max_loop_count = 16;
+
for (;;) {
bool bit_el;
bool bit_s;
@@ -870,6 +879,13 @@ static void action_command(EEPRO100State *s)
#if 0
bool bit_sf = ((s->tx.command & COMMAND_SF) != 0);
#endif
+
+ if (max_loop_count-- == 0) {
+ /* Prevent an endless loop. */
+ logout("loop in %s:%u\n", __FILE__, __LINE__);
+ break;
+ }
+
s->cu_offset = s->tx.link;
TRACE(OTHER,
logout("val=(cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
diff --git a/qemu/hw/net/etraxfs_eth.c b/qemu/hw/net/etraxfs_eth.c
index d6002750f..05495ec40 100644
--- a/qemu/hw/net/etraxfs_eth.c
+++ b/qemu/hw/net/etraxfs_eth.c
@@ -22,10 +22,11 @@
* THE SOFTWARE.
*/
-#include <stdio.h>
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "net/net.h"
#include "hw/cris/etraxfs.h"
+#include "qemu/error-report.h"
#define D(x)
@@ -589,7 +590,8 @@ static int fs_eth_init(SysBusDevice *sbd)
ETRAXFSEthState *s = ETRAX_FS_ETH(dev);
if (!s->dma_out || !s->dma_in) {
- hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
+ error_report("Unconnected ETRAX-FS Ethernet MAC");
+ return -1;
}
s->dma_out->client.push = eth_tx_push;
diff --git a/qemu/hw/net/fsl_etsec/etsec.c b/qemu/hw/net/fsl_etsec/etsec.c
index 0f5cf4477..1e35f7f8c 100644
--- a/qemu/hw/net/fsl_etsec/etsec.c
+++ b/qemu/hw/net/fsl_etsec/etsec.c
@@ -26,6 +26,7 @@
* This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
*/
+#include "qemu/osdep.h"
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
#include "trace.h"
@@ -353,7 +354,7 @@ static ssize_t etsec_receive(NetClientState *nc,
etsec->need_flush = false;
ret = etsec_rx_ring_write(etsec, buf, size);
if (ret == 0) {
- /* The packet will be queued, let's flush it when buffer is avilable
+ /* The packet will be queued, let's flush it when buffer is available
* again. */
etsec->need_flush = true;
}
diff --git a/qemu/hw/net/fsl_etsec/miim.c b/qemu/hw/net/fsl_etsec/miim.c
index 1931b74e6..6bba01c82 100644
--- a/qemu/hw/net/fsl_etsec/miim.c
+++ b/qemu/hw/net/fsl_etsec/miim.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "etsec.h"
#include "registers.h"
diff --git a/qemu/hw/net/fsl_etsec/registers.c b/qemu/hw/net/fsl_etsec/registers.c
index a7bbfa113..46ce7a84b 100644
--- a/qemu/hw/net/fsl_etsec/registers.c
+++ b/qemu/hw/net/fsl_etsec/registers.c
@@ -21,6 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "registers.h"
const eTSEC_Register_Definition eTSEC_registers_def[] = {
diff --git a/qemu/hw/net/fsl_etsec/registers.h b/qemu/hw/net/fsl_etsec/registers.h
index 7ad768647..6fb96842b 100644
--- a/qemu/hw/net/fsl_etsec/registers.h
+++ b/qemu/hw/net/fsl_etsec/registers.h
@@ -24,7 +24,6 @@
#ifndef _ETSEC_REGISTERS_H_
#define _ETSEC_REGISTERS_H_
-#include <stdint.h>
enum eTSEC_Register_Access_Type {
ACC_RW = 1, /* Read/Write */
diff --git a/qemu/hw/net/fsl_etsec/rings.c b/qemu/hw/net/fsl_etsec/rings.c
index 68e7b6d16..ed1de7da9 100644
--- a/qemu/hw/net/fsl_etsec/rings.c
+++ b/qemu/hw/net/fsl_etsec/rings.c
@@ -21,6 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "net/checksum.h"
#include "etsec.h"
@@ -464,9 +465,7 @@ static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
etsec->rx_fcb_size = 0;
}
- if (etsec->rx_buffer != NULL) {
- g_free(etsec->rx_buffer);
- }
+ g_free(etsec->rx_buffer);
/* Do not copy the frame for now */
etsec->rx_buffer = (uint8_t *)buf;
diff --git a/qemu/hw/net/imx_fec.c b/qemu/hw/net/imx_fec.c
new file mode 100644
index 000000000..e60e3380e
--- /dev/null
+++ b/qemu/hw/net/imx_fec.c
@@ -0,0 +1,711 @@
+/*
+ * i.MX Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
+ *
+ * Based on Coldfire Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 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/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/net/imx_fec.h"
+#include "sysemu/dma.h"
+
+/* For crc32 */
+#include <zlib.h>
+
+#ifndef DEBUG_IMX_FEC
+#define DEBUG_IMX_FEC 0
+#endif
+
+#define FEC_PRINTF(fmt, args...) \
+ do { \
+ if (DEBUG_IMX_FEC) { \
+ fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_FEC, \
+ __func__, ##args); \
+ } \
+ } while (0)
+
+#ifndef DEBUG_IMX_PHY
+#define DEBUG_IMX_PHY 0
+#endif
+
+#define PHY_PRINTF(fmt, args...) \
+ do { \
+ if (DEBUG_IMX_PHY) { \
+ fprintf(stderr, "[%s.phy]%s: " fmt , TYPE_IMX_FEC, \
+ __func__, ##args); \
+ } \
+ } while (0)
+
+static const VMStateDescription vmstate_imx_fec = {
+ .name = TYPE_IMX_FEC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(irq_state, IMXFECState),
+ VMSTATE_UINT32(eir, IMXFECState),
+ VMSTATE_UINT32(eimr, IMXFECState),
+ VMSTATE_UINT32(rx_enabled, IMXFECState),
+ VMSTATE_UINT32(rx_descriptor, IMXFECState),
+ VMSTATE_UINT32(tx_descriptor, IMXFECState),
+ VMSTATE_UINT32(ecr, IMXFECState),
+ VMSTATE_UINT32(mmfr, IMXFECState),
+ VMSTATE_UINT32(mscr, IMXFECState),
+ VMSTATE_UINT32(mibc, IMXFECState),
+ VMSTATE_UINT32(rcr, IMXFECState),
+ VMSTATE_UINT32(tcr, IMXFECState),
+ VMSTATE_UINT32(tfwr, IMXFECState),
+ VMSTATE_UINT32(frsr, IMXFECState),
+ VMSTATE_UINT32(erdsr, IMXFECState),
+ VMSTATE_UINT32(etdsr, IMXFECState),
+ VMSTATE_UINT32(emrbr, IMXFECState),
+ VMSTATE_UINT32(miigsk_cfgr, IMXFECState),
+ VMSTATE_UINT32(miigsk_enr, IMXFECState),
+
+ VMSTATE_UINT32(phy_status, IMXFECState),
+ VMSTATE_UINT32(phy_control, IMXFECState),
+ VMSTATE_UINT32(phy_advertise, IMXFECState),
+ VMSTATE_UINT32(phy_int, IMXFECState),
+ VMSTATE_UINT32(phy_int_mask, IMXFECState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+#define PHY_INT_ENERGYON (1 << 7)
+#define PHY_INT_AUTONEG_COMPLETE (1 << 6)
+#define PHY_INT_FAULT (1 << 5)
+#define PHY_INT_DOWN (1 << 4)
+#define PHY_INT_AUTONEG_LP (1 << 3)
+#define PHY_INT_PARFAULT (1 << 2)
+#define PHY_INT_AUTONEG_PAGE (1 << 1)
+
+static void imx_fec_update(IMXFECState *s);
+
+/*
+ * The MII phy could raise a GPIO to the processor which in turn
+ * could be handled as an interrpt by the OS.
+ * For now we don't handle any GPIO/interrupt line, so the OS will
+ * have to poll for the PHY status.
+ */
+static void phy_update_irq(IMXFECState *s)
+{
+ imx_fec_update(s);
+}
+
+static void phy_update_link(IMXFECState *s)
+{
+ /* Autonegotiation status mirrors link status. */
+ if (qemu_get_queue(s->nic)->link_down) {
+ PHY_PRINTF("link is down\n");
+ s->phy_status &= ~0x0024;
+ s->phy_int |= PHY_INT_DOWN;
+ } else {
+ PHY_PRINTF("link is up\n");
+ s->phy_status |= 0x0024;
+ s->phy_int |= PHY_INT_ENERGYON;
+ s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
+ }
+ phy_update_irq(s);
+}
+
+static void imx_fec_set_link(NetClientState *nc)
+{
+ phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc)));
+}
+
+static void phy_reset(IMXFECState *s)
+{
+ s->phy_status = 0x7809;
+ s->phy_control = 0x3000;
+ s->phy_advertise = 0x01e1;
+ s->phy_int_mask = 0;
+ s->phy_int = 0;
+ phy_update_link(s);
+}
+
+static uint32_t do_phy_read(IMXFECState *s, int reg)
+{
+ uint32_t val;
+
+ if (reg > 31) {
+ /* we only advertise one phy */
+ return 0;
+ }
+
+ switch (reg) {
+ case 0: /* Basic Control */
+ val = s->phy_control;
+ break;
+ case 1: /* Basic Status */
+ val = s->phy_status;
+ break;
+ case 2: /* ID1 */
+ val = 0x0007;
+ break;
+ case 3: /* ID2 */
+ val = 0xc0d1;
+ break;
+ case 4: /* Auto-neg advertisement */
+ val = s->phy_advertise;
+ break;
+ case 5: /* Auto-neg Link Partner Ability */
+ val = 0x0f71;
+ break;
+ case 6: /* Auto-neg Expansion */
+ val = 1;
+ break;
+ case 29: /* Interrupt source. */
+ val = s->phy_int;
+ s->phy_int = 0;
+ phy_update_irq(s);
+ break;
+ case 30: /* Interrupt mask */
+ val = s->phy_int_mask;
+ break;
+ case 17:
+ case 18:
+ case 27:
+ case 31:
+ qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n",
+ TYPE_IMX_FEC, __func__, reg);
+ val = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
+ TYPE_IMX_FEC, __func__, reg);
+ val = 0;
+ break;
+ }
+
+ PHY_PRINTF("read 0x%04x @ %d\n", val, reg);
+
+ return val;
+}
+
+static void do_phy_write(IMXFECState *s, int reg, uint32_t val)
+{
+ PHY_PRINTF("write 0x%04x @ %d\n", val, reg);
+
+ if (reg > 31) {
+ /* we only advertise one phy */
+ return;
+ }
+
+ switch (reg) {
+ case 0: /* Basic Control */
+ if (val & 0x8000) {
+ phy_reset(s);
+ } else {
+ s->phy_control = val & 0x7980;
+ /* Complete autonegotiation immediately. */
+ if (val & 0x1000) {
+ s->phy_status |= 0x0020;
+ }
+ }
+ break;
+ case 4: /* Auto-neg advertisement */
+ s->phy_advertise = (val & 0x2d7f) | 0x80;
+ break;
+ case 30: /* Interrupt mask */
+ s->phy_int_mask = val & 0xff;
+ phy_update_irq(s);
+ break;
+ case 17:
+ case 18:
+ case 27:
+ case 31:
+ qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n",
+ TYPE_IMX_FEC, __func__, reg);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n",
+ TYPE_IMX_FEC, __func__, reg);
+ break;
+ }
+}
+
+static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr)
+{
+ dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd));
+}
+
+static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr)
+{
+ dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd));
+}
+
+static void imx_fec_update(IMXFECState *s)
+{
+ uint32_t active;
+ uint32_t changed;
+
+ active = s->eir & s->eimr;
+ changed = active ^ s->irq_state;
+ if (changed) {
+ qemu_set_irq(s->irq, active);
+ }
+ s->irq_state = active;
+}
+
+static void imx_fec_do_tx(IMXFECState *s)
+{
+ int frame_size = 0;
+ uint8_t frame[FEC_MAX_FRAME_SIZE];
+ uint8_t *ptr = frame;
+ uint32_t addr = s->tx_descriptor;
+
+ while (1) {
+ IMXFECBufDesc bd;
+ int len;
+
+ imx_fec_read_bd(&bd, addr);
+ FEC_PRINTF("tx_bd %x flags %04x len %d data %08x\n",
+ addr, bd.flags, bd.length, bd.data);
+ if ((bd.flags & FEC_BD_R) == 0) {
+ /* Run out of descriptors to transmit. */
+ break;
+ }
+ len = bd.length;
+ if (frame_size + len > FEC_MAX_FRAME_SIZE) {
+ len = FEC_MAX_FRAME_SIZE - frame_size;
+ s->eir |= FEC_INT_BABT;
+ }
+ dma_memory_read(&address_space_memory, bd.data, ptr, len);
+ ptr += len;
+ frame_size += len;
+ if (bd.flags & FEC_BD_L) {
+ /* Last buffer in frame. */
+ qemu_send_packet(qemu_get_queue(s->nic), frame, len);
+ ptr = frame;
+ frame_size = 0;
+ s->eir |= FEC_INT_TXF;
+ }
+ s->eir |= FEC_INT_TXB;
+ bd.flags &= ~FEC_BD_R;
+ /* Write back the modified descriptor. */
+ imx_fec_write_bd(&bd, addr);
+ /* Advance to the next descriptor. */
+ if ((bd.flags & FEC_BD_W) != 0) {
+ addr = s->etdsr;
+ } else {
+ addr += 8;
+ }
+ }
+
+ s->tx_descriptor = addr;
+
+ imx_fec_update(s);
+}
+
+static void imx_fec_enable_rx(IMXFECState *s)
+{
+ IMXFECBufDesc bd;
+ uint32_t tmp;
+
+ imx_fec_read_bd(&bd, s->rx_descriptor);
+
+ tmp = ((bd.flags & FEC_BD_E) != 0);
+
+ if (!tmp) {
+ FEC_PRINTF("RX buffer full\n");
+ } else if (!s->rx_enabled) {
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
+ }
+
+ s->rx_enabled = tmp;
+}
+
+static void imx_fec_reset(DeviceState *d)
+{
+ IMXFECState *s = IMX_FEC(d);
+
+ /* Reset the FEC */
+ s->eir = 0;
+ s->eimr = 0;
+ s->rx_enabled = 0;
+ s->ecr = 0;
+ s->mscr = 0;
+ s->mibc = 0xc0000000;
+ s->rcr = 0x05ee0001;
+ s->tcr = 0;
+ s->tfwr = 0;
+ s->frsr = 0x500;
+ s->miigsk_cfgr = 0;
+ s->miigsk_enr = 0x6;
+
+ /* We also reset the PHY */
+ phy_reset(s);
+}
+
+static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size)
+{
+ IMXFECState *s = IMX_FEC(opaque);
+
+ FEC_PRINTF("reading from @ 0x%" HWADDR_PRIx "\n", addr);
+
+ switch (addr & 0x3ff) {
+ case 0x004:
+ return s->eir;
+ case 0x008:
+ return s->eimr;
+ case 0x010:
+ return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
+ case 0x014:
+ return 0; /* TDAR */
+ case 0x024:
+ return s->ecr;
+ case 0x040:
+ return s->mmfr;
+ case 0x044:
+ return s->mscr;
+ case 0x064:
+ return s->mibc; /* MIBC */
+ case 0x084:
+ return s->rcr;
+ case 0x0c4:
+ return s->tcr;
+ case 0x0e4: /* PALR */
+ return (s->conf.macaddr.a[0] << 24)
+ | (s->conf.macaddr.a[1] << 16)
+ | (s->conf.macaddr.a[2] << 8)
+ | s->conf.macaddr.a[3];
+ break;
+ case 0x0e8: /* PAUR */
+ return (s->conf.macaddr.a[4] << 24)
+ | (s->conf.macaddr.a[5] << 16)
+ | 0x8808;
+ case 0x0ec:
+ return 0x10000; /* OPD */
+ case 0x118:
+ return 0;
+ case 0x11c:
+ return 0;
+ case 0x120:
+ return 0;
+ case 0x124:
+ return 0;
+ case 0x144:
+ return s->tfwr;
+ case 0x14c:
+ return 0x600;
+ case 0x150:
+ return s->frsr;
+ case 0x180:
+ return s->erdsr;
+ case 0x184:
+ return s->etdsr;
+ case 0x188:
+ return s->emrbr;
+ case 0x300:
+ return s->miigsk_cfgr;
+ case 0x308:
+ return s->miigsk_enr;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr);
+ return 0;
+ }
+}
+
+static void imx_fec_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ IMXFECState *s = IMX_FEC(opaque);
+
+ FEC_PRINTF("writing 0x%08x @ 0x%" HWADDR_PRIx "\n", (int)value, addr);
+
+ switch (addr & 0x3ff) {
+ case 0x004: /* EIR */
+ s->eir &= ~value;
+ break;
+ case 0x008: /* EIMR */
+ s->eimr = value;
+ break;
+ case 0x010: /* RDAR */
+ if ((s->ecr & FEC_EN) && !s->rx_enabled) {
+ imx_fec_enable_rx(s);
+ }
+ break;
+ case 0x014: /* TDAR */
+ if (s->ecr & FEC_EN) {
+ imx_fec_do_tx(s);
+ }
+ break;
+ case 0x024: /* ECR */
+ s->ecr = value;
+ if (value & FEC_RESET) {
+ imx_fec_reset(DEVICE(s));
+ }
+ if ((s->ecr & FEC_EN) == 0) {
+ s->rx_enabled = 0;
+ }
+ break;
+ case 0x040: /* MMFR */
+ /* store the value */
+ s->mmfr = value;
+ if (extract32(value, 28, 1)) {
+ do_phy_write(s, extract32(value, 18, 9), extract32(value, 0, 16));
+ } else {
+ s->mmfr = do_phy_read(s, extract32(value, 18, 9));
+ }
+ /* raise the interrupt as the PHY operation is done */
+ s->eir |= FEC_INT_MII;
+ break;
+ case 0x044: /* MSCR */
+ s->mscr = value & 0xfe;
+ break;
+ case 0x064: /* MIBC */
+ /* TODO: Implement MIB. */
+ s->mibc = (value & 0x80000000) ? 0xc0000000 : 0;
+ break;
+ case 0x084: /* RCR */
+ s->rcr = value & 0x07ff003f;
+ /* TODO: Implement LOOP mode. */
+ break;
+ case 0x0c4: /* TCR */
+ /* We transmit immediately, so raise GRA immediately. */
+ s->tcr = value;
+ if (value & 1) {
+ s->eir |= FEC_INT_GRA;
+ }
+ break;
+ case 0x0e4: /* PALR */
+ s->conf.macaddr.a[0] = value >> 24;
+ s->conf.macaddr.a[1] = value >> 16;
+ s->conf.macaddr.a[2] = value >> 8;
+ s->conf.macaddr.a[3] = value;
+ break;
+ case 0x0e8: /* PAUR */
+ s->conf.macaddr.a[4] = value >> 24;
+ s->conf.macaddr.a[5] = value >> 16;
+ break;
+ case 0x0ec: /* OPDR */
+ break;
+ case 0x118: /* IAUR */
+ case 0x11c: /* IALR */
+ case 0x120: /* GAUR */
+ case 0x124: /* GALR */
+ /* TODO: implement MAC hash filtering. */
+ break;
+ case 0x144: /* TFWR */
+ s->tfwr = value & 3;
+ break;
+ case 0x14c: /* FRBR */
+ /* FRBR writes ignored. */
+ break;
+ case 0x150: /* FRSR */
+ s->frsr = (value & 0x3fc) | 0x400;
+ break;
+ case 0x180: /* ERDSR */
+ s->erdsr = value & ~3;
+ s->rx_descriptor = s->erdsr;
+ break;
+ case 0x184: /* ETDSR */
+ s->etdsr = value & ~3;
+ s->tx_descriptor = s->etdsr;
+ break;
+ case 0x188: /* EMRBR */
+ s->emrbr = value & 0x7f0;
+ break;
+ case 0x300: /* MIIGSK_CFGR */
+ s->miigsk_cfgr = value & 0x53;
+ break;
+ case 0x308: /* MIIGSK_ENR */
+ s->miigsk_enr = (value & 0x2) ? 0x6 : 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr);
+ break;
+ }
+
+ imx_fec_update(s);
+}
+
+static int imx_fec_can_receive(NetClientState *nc)
+{
+ IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+
+ return s->rx_enabled;
+}
+
+static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
+ size_t len)
+{
+ IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+ IMXFECBufDesc bd;
+ uint32_t flags = 0;
+ uint32_t addr;
+ uint32_t crc;
+ uint32_t buf_addr;
+ uint8_t *crc_ptr;
+ unsigned int buf_len;
+ size_t size = len;
+
+ FEC_PRINTF("len %d\n", (int)size);
+
+ if (!s->rx_enabled) {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Unexpected packet\n",
+ TYPE_IMX_FEC, __func__);
+ return 0;
+ }
+
+ /* 4 bytes for the CRC. */
+ size += 4;
+ crc = cpu_to_be32(crc32(~0, buf, size));
+ crc_ptr = (uint8_t *) &crc;
+
+ /* Huge frames are truncted. */
+ if (size > FEC_MAX_FRAME_SIZE) {
+ size = FEC_MAX_FRAME_SIZE;
+ flags |= FEC_BD_TR | FEC_BD_LG;
+ }
+
+ /* Frames larger than the user limit just set error flags. */
+ if (size > (s->rcr >> 16)) {
+ flags |= FEC_BD_LG;
+ }
+
+ addr = s->rx_descriptor;
+ while (size > 0) {
+ imx_fec_read_bd(&bd, addr);
+ if ((bd.flags & FEC_BD_E) == 0) {
+ /* No descriptors available. Bail out. */
+ /*
+ * FIXME: This is wrong. We should probably either
+ * save the remainder for when more RX buffers are
+ * available, or flag an error.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Lost end of frame\n",
+ TYPE_IMX_FEC, __func__);
+ break;
+ }
+ buf_len = (size <= s->emrbr) ? size : s->emrbr;
+ bd.length = buf_len;
+ size -= buf_len;
+
+ FEC_PRINTF("rx_bd 0x%x length %d\n", addr, bd.length);
+
+ /* The last 4 bytes are the CRC. */
+ if (size < 4) {
+ buf_len += size - 4;
+ }
+ buf_addr = bd.data;
+ dma_memory_write(&address_space_memory, buf_addr, buf, buf_len);
+ buf += buf_len;
+ if (size < 4) {
+ dma_memory_write(&address_space_memory, buf_addr + buf_len,
+ crc_ptr, 4 - size);
+ crc_ptr += 4 - size;
+ }
+ bd.flags &= ~FEC_BD_E;
+ if (size == 0) {
+ /* Last buffer in frame. */
+ bd.flags |= flags | FEC_BD_L;
+ FEC_PRINTF("rx frame flags %04x\n", bd.flags);
+ s->eir |= FEC_INT_RXF;
+ } else {
+ s->eir |= FEC_INT_RXB;
+ }
+ imx_fec_write_bd(&bd, addr);
+ /* Advance to the next descriptor. */
+ if ((bd.flags & FEC_BD_W) != 0) {
+ addr = s->erdsr;
+ } else {
+ addr += 8;
+ }
+ }
+ s->rx_descriptor = addr;
+ imx_fec_enable_rx(s);
+ imx_fec_update(s);
+ return len;
+}
+
+static const MemoryRegionOps imx_fec_ops = {
+ .read = imx_fec_read,
+ .write = imx_fec_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void imx_fec_cleanup(NetClientState *nc)
+{
+ IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));
+
+ s->nic = NULL;
+}
+
+static NetClientInfo net_imx_fec_info = {
+ .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .size = sizeof(NICState),
+ .can_receive = imx_fec_can_receive,
+ .receive = imx_fec_receive,
+ .cleanup = imx_fec_cleanup,
+ .link_status_changed = imx_fec_set_link,
+};
+
+
+static void imx_fec_realize(DeviceState *dev, Error **errp)
+{
+ IMXFECState *s = IMX_FEC(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &imx_fec_ops, s,
+ TYPE_IMX_FEC, 0x400);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq);
+ qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+ s->conf.peers.ncs[0] = nd_table[0].netdev;
+
+ s->nic = qemu_new_nic(&net_imx_fec_info, &s->conf,
+ object_get_typename(OBJECT(dev)), DEVICE(dev)->id,
+ s);
+ qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
+
+static Property imx_fec_properties[] = {
+ DEFINE_NIC_PROPERTIES(IMXFECState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void imx_fec_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_imx_fec;
+ dc->reset = imx_fec_reset;
+ dc->props = imx_fec_properties;
+ dc->realize = imx_fec_realize;
+ dc->desc = "i.MX FEC Ethernet Controller";
+}
+
+static const TypeInfo imx_fec_info = {
+ .name = TYPE_IMX_FEC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXFECState),
+ .class_init = imx_fec_class_init,
+};
+
+static void imx_fec_register_types(void)
+{
+ type_register_static(&imx_fec_info);
+}
+
+type_init(imx_fec_register_types)
diff --git a/qemu/hw/net/lan9118.c b/qemu/hw/net/lan9118.c
index 4f0e840f0..08dc474d6 100644
--- a/qemu/hw/net/lan9118.c
+++ b/qemu/hw/net/lan9118.c
@@ -10,6 +10,7 @@
* GNU GPL, version 2 or (at your option) any later version.
*/
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "net/net.h"
#include "hw/devices.h"
@@ -56,6 +57,8 @@ do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
#define CSR_E2P_CMD 0xb0
#define CSR_E2P_DATA 0xb4
+#define E2P_CMD_MAC_ADDR_LOADED 0x100
+
/* IRQ_CFG */
#define IRQ_INT 0x00001000
#define IRQ_EN 0x00000100
@@ -352,14 +355,14 @@ static void lan9118_reload_eeprom(lan9118_state *s)
{
int i;
if (s->eeprom[0] != 0xa5) {
- s->e2p_cmd &= ~0x10;
+ s->e2p_cmd &= ~E2P_CMD_MAC_ADDR_LOADED;
DPRINTF("MACADDR load failed\n");
return;
}
for (i = 0; i < 6; i++) {
s->conf.macaddr.a[i] = s->eeprom[i + 1];
}
- s->e2p_cmd |= 0x10;
+ s->e2p_cmd |= E2P_CMD_MAC_ADDR_LOADED;
DPRINTF("MACADDR loaded from eeprom\n");
lan9118_mac_changed(s);
}
@@ -902,7 +905,8 @@ static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
*/
break;
default:
- hw_error("lan9118: Unimplemented MAC register write: %d = 0x%x\n",
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "lan9118: Unimplemented MAC register write: %d = 0x%x\n",
s->mac_cmd & 0xf, val);
}
}
@@ -930,14 +934,16 @@ static uint32_t do_mac_read(lan9118_state *s, int reg)
case MAC_FLOW:
return s->mac_flow;
default:
- hw_error("lan9118: Unimplemented MAC register read: %d\n",
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "lan9118: Unimplemented MAC register read: %d\n",
s->mac_cmd & 0xf);
+ return 0;
}
}
static void lan9118_eeprom_cmd(lan9118_state *s, int cmd, int addr)
{
- s->e2p_cmd = (s->e2p_cmd & 0x10) | (cmd << 28) | addr;
+ s->e2p_cmd = (s->e2p_cmd & E2P_CMD_MAC_ADDR_LOADED) | (cmd << 28) | addr;
switch (cmd) {
case 0:
s->e2p_data = s->eeprom[addr];
@@ -1128,7 +1134,8 @@ static void lan9118_writel(void *opaque, hwaddr offset,
break;
default:
- hw_error("lan9118_write: Bad reg 0x%x = %x\n", (int)offset, (int)val);
+ qemu_log_mask(LOG_GUEST_ERROR, "lan9118_write: Bad reg 0x%x = %x\n",
+ (int)offset, (int)val);
break;
}
lan9118_update(s);
@@ -1246,7 +1253,7 @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
case CSR_E2P_DATA:
return s->e2p_data;
}
- hw_error("lan9118_read: Bad reg 0x%x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR, "lan9118_read: Bad reg 0x%x\n", (int)offset);
return 0;
}
diff --git a/qemu/hw/net/lance.c b/qemu/hw/net/lance.c
index 780b39d65..6253d2103 100644
--- a/qemu/hw/net/lance.c
+++ b/qemu/hw/net/lance.c
@@ -35,6 +35,7 @@
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
*/
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "net/net.h"
#include "qemu/timer.h"
diff --git a/qemu/hw/net/mcf_fec.c b/qemu/hw/net/mcf_fec.c
index 21928f9f3..7c0398ed9 100644
--- a/qemu/hw/net/mcf_fec.c
+++ b/qemu/hw/net/mcf_fec.c
@@ -5,6 +5,7 @@
*
* This code is licensed under the GPL
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "net/net.h"
#include "hw/m68k/mcf.h"
diff --git a/qemu/hw/net/milkymist-minimac2.c b/qemu/hw/net/milkymist-minimac2.c
index 5d1cf0851..1e147c33c 100644
--- a/qemu/hw/net/milkymist-minimac2.c
+++ b/qemu/hw/net/milkymist-minimac2.c
@@ -22,6 +22,10 @@
*
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "cpu.h" /* FIXME: why does this use TARGET_PAGE_ALIGN? */
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "trace.h"
@@ -463,7 +467,7 @@ static int milkymist_minimac2_init(SysBusDevice *sbd)
/* register buffers memory */
memory_region_init_ram(&s->buffers, OBJECT(dev), "milkymist-minimac2.buffers",
- buffers_size, &error_abort);
+ buffers_size, &error_fatal);
vmstate_register_ram_global(&s->buffers);
s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
diff --git a/qemu/hw/net/mipsnet.c b/qemu/hw/net/mipsnet.c
index f261011a2..740cd98ff 100644
--- a/qemu/hw/net/mipsnet.c
+++ b/qemu/hw/net/mipsnet.c
@@ -1,3 +1,4 @@
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "net/net.h"
#include "trace.h"
diff --git a/qemu/hw/net/ne2000-isa.c b/qemu/hw/net/ne2000-isa.c
index 17e7199f7..a7f5a9464 100644
--- a/qemu/hw/net/ne2000-isa.c
+++ b/qemu/hw/net/ne2000-isa.c
@@ -21,6 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/isa/isa.h"
@@ -28,6 +29,7 @@
#include "net/net.h"
#include "ne2000.h"
#include "exec/address-spaces.h"
+#include "qapi/error.h"
#include "qapi/visitor.h"
#define TYPE_ISA_NE2000 "ne2k_isa"
@@ -44,7 +46,6 @@ typedef struct ISANE2000State {
static NetClientInfo net_ne2000_isa_info = {
.type = NET_CLIENT_OPTIONS_KIND_NIC,
.size = sizeof(NICState),
- .can_receive = ne2000_can_receive,
.receive = ne2000_receive,
};
@@ -94,24 +95,26 @@ static void isa_ne2000_class_initfn(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
-static void isa_ne2000_get_bootindex(Object *obj, Visitor *v, void *opaque,
- const char *name, Error **errp)
+static void isa_ne2000_get_bootindex(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
{
ISANE2000State *isa = ISA_NE2000(obj);
NE2000State *s = &isa->ne2000;
- visit_type_int32(v, &s->c.bootindex, name, errp);
+ visit_type_int32(v, name, &s->c.bootindex, errp);
}
-static void isa_ne2000_set_bootindex(Object *obj, Visitor *v, void *opaque,
- const char *name, Error **errp)
+static void isa_ne2000_set_bootindex(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
{
ISANE2000State *isa = ISA_NE2000(obj);
NE2000State *s = &isa->ne2000;
int32_t boot_index;
Error *local_err = NULL;
- visit_type_int32(v, &boot_index, name, &local_err);
+ visit_type_int32(v, name, &boot_index, &local_err);
if (local_err) {
goto out;
}
diff --git a/qemu/hw/net/ne2000.c b/qemu/hw/net/ne2000.c
index 2bdb4c927..f0feaf96b 100644
--- a/qemu/hw/net/ne2000.c
+++ b/qemu/hw/net/ne2000.c
@@ -21,6 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "net/net.h"
@@ -154,6 +155,10 @@ static int ne2000_buffer_full(NE2000State *s)
{
int avail, index, boundary;
+ if (s->stop <= s->start) {
+ return 1;
+ }
+
index = s->curpag << 8;
boundary = s->boundary << 8;
if (index < boundary)
@@ -165,15 +170,6 @@ static int ne2000_buffer_full(NE2000State *s)
return 0;
}
-int ne2000_can_receive(NetClientState *nc)
-{
- NE2000State *s = qemu_get_nic_opaque(nc);
-
- if (s->cmd & E8390_STOP)
- return 1;
- return !ne2000_buffer_full(s);
-}
-
#define MIN_BUF_SIZE 60
ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
@@ -476,8 +472,9 @@ static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
uint32_t val)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+ if (addr < 32
+ || (addr >= NE2000_PMEM_START
+ && addr + sizeof(uint32_t) <= NE2000_MEM_SIZE)) {
stl_le_p(s->mem + addr, val);
}
}
@@ -506,8 +503,9 @@ static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
{
addr &= ~1; /* XXX: check exact behaviour if not even */
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+ if (addr < 32
+ || (addr >= NE2000_PMEM_START
+ && addr + sizeof(uint32_t) <= NE2000_MEM_SIZE)) {
return ldl_le_p(s->mem + addr);
} else {
return 0xffffffff;
@@ -716,7 +714,6 @@ void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size)
static NetClientInfo net_ne2000_info = {
.type = NET_CLIENT_OPTIONS_KIND_NIC,
.size = sizeof(NICState),
- .can_receive = ne2000_can_receive,
.receive = ne2000_receive,
};
diff --git a/qemu/hw/net/ne2000.h b/qemu/hw/net/ne2000.h
index e500306aa..d022b28fc 100644
--- a/qemu/hw/net/ne2000.h
+++ b/qemu/hw/net/ne2000.h
@@ -34,7 +34,6 @@ typedef struct NE2000State {
void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size);
extern const VMStateDescription vmstate_ne2000;
void ne2000_reset(NE2000State *s);
-int ne2000_can_receive(NetClientState *nc);
ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
#endif
diff --git a/qemu/hw/net/opencores_eth.c b/qemu/hw/net/opencores_eth.c
index 3642046ef..c6094fbb5 100644
--- a/qemu/hw/net/opencores_eth.c
+++ b/qemu/hw/net/opencores_eth.c
@@ -31,6 +31,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/sysbus.h"
#include "net/net.h"
@@ -84,7 +85,7 @@ static void mii_reset(Mii *s)
{
memset(s->regs, 0, sizeof(s->regs));
s->regs[MII_BMCR] = 0x1000;
- s->regs[MII_BMSR] = 0x7848; /* no ext regs */
+ s->regs[MII_BMSR] = 0x7868; /* no ext regs */
s->regs[MII_PHYIDR1] = 0x2000;
s->regs[MII_PHYIDR2] = 0x5c90;
s->regs[MII_ANAR] = 0x01e1;
diff --git a/qemu/hw/net/pcnet-pci.c b/qemu/hw/net/pcnet-pci.c
index b4d60b812..595439a65 100644
--- a/qemu/hw/net/pcnet-pci.c
+++ b/qemu/hw/net/pcnet-pci.c
@@ -27,6 +27,7 @@
* AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
*/
+#include "qemu/osdep.h"
#include "hw/pci/pci.h"
#include "net/net.h"
#include "hw/loader.h"
diff --git a/qemu/hw/net/pcnet.c b/qemu/hw/net/pcnet.c
index 34373767d..198a01f92 100644
--- a/qemu/hw/net/pcnet.c
+++ b/qemu/hw/net/pcnet.c
@@ -35,6 +35,7 @@
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
*/
+#include "qemu/osdep.h"
#include "hw/qdev.h"
#include "net/net.h"
#include "qemu/timer.h"
@@ -670,8 +671,7 @@ static inline hwaddr pcnet_rdra_addr(PCNetState *s, int idx)
static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
{
int64_t next_time = current_time +
- muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
- get_ticks_per_sec(), 33000000L);
+ (65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s))) * 30;
if (next_time <= current_time)
next_time = current_time + 1;
return next_time;
@@ -1065,6 +1065,12 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
int pktcount = 0;
if (!s->looptest) {
+ if (size > 4092) {
+#ifdef PCNET_DEBUG_RMD
+ fprintf(stderr, "pcnet: truncates rx packet.\n");
+#endif
+ size = 4092;
+ }
memcpy(src, buf, size);
/* no need to compute the CRC */
src[size] = 0;
@@ -1085,7 +1091,7 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
uint32_t fcs = ~0;
uint8_t *p = src;
- while (p != &src[size-4])
+ while (p != &src[size])
CRC(fcs, *p++);
crc_err = (*(uint32_t *)p != htonl(fcs));
}
@@ -1234,8 +1240,10 @@ static void pcnet_transmit(PCNetState *s)
bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
/* if multi-tmd packet outsizes s->buffer then skip it silently.
- Note: this is not what real hw does */
- if (s->xmit_pos + bcnt > sizeof(s->buffer)) {
+ * Note: this is not what real hw does.
+ * Last four bytes of s->buffer are used to store CRC FCS code.
+ */
+ if (s->xmit_pos + bcnt > sizeof(s->buffer) - 4) {
s->xmit_pos = -1;
goto txdone;
}
diff --git a/qemu/hw/net/rocker/qmp-norocker.c b/qemu/hw/net/rocker/qmp-norocker.c
index 49b498b64..6acbcdb02 100644
--- a/qemu/hw/net/rocker/qmp-norocker.c
+++ b/qemu/hw/net/rocker/qmp-norocker.c
@@ -15,6 +15,7 @@
* GNU General Public License for more details.
*/
+#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qmp-commands.h"
#include "qapi/qmp/qerror.h"
diff --git a/qemu/hw/net/rocker/rocker.c b/qemu/hw/net/rocker/rocker.c
index 47d080fd3..30f2ce417 100644
--- a/qemu/hw/net/rocker/rocker.c
+++ b/qemu/hw/net/rocker/rocker.c
@@ -15,6 +15,7 @@
* GNU General Public License for more details.
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "hw/pci/msix.h"
@@ -42,6 +43,7 @@ struct rocker {
/* switch configuration */
char *name; /* switch name */
+ char *world_name; /* world name */
uint32_t fp_ports; /* front-panel port count */
NICPeers *fp_ports_peers;
MACAddr fp_start_macaddr; /* front-panel port 0 mac addr */
@@ -101,8 +103,7 @@ RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
r = rocker_find(name);
if (!r) {
- error_set(errp, ERROR_CLASS_GENERIC_ERROR,
- "rocker %s not found", name);
+ error_setg(errp, "rocker %s not found", name);
return NULL;
}
@@ -122,8 +123,7 @@ RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
r = rocker_find(name);
if (!r) {
- error_set(errp, ERROR_CLASS_GENERIC_ERROR,
- "rocker %s not found", name);
+ error_setg(errp, "rocker %s not found", name);
return NULL;
}
@@ -234,6 +234,9 @@ static int tx_consume(Rocker *r, DescInfo *info)
frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]);
frag_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]);
+ if (iovcnt >= ROCKER_TX_FRAGS_MAX) {
+ goto err_too_many_frags;
+ }
iov[iovcnt].iov_len = frag_len;
iov[iovcnt].iov_base = g_malloc(frag_len);
if (!iov[iovcnt].iov_base) {
@@ -246,10 +249,7 @@ static int tx_consume(Rocker *r, DescInfo *info)
err = -ROCKER_ENXIO;
goto err_bad_io;
}
-
- if (++iovcnt > ROCKER_TX_FRAGS_MAX) {
- goto err_too_many_frags;
- }
+ iovcnt++;
}
if (iovcnt) {
@@ -265,9 +265,7 @@ err_bad_io:
err_no_mem:
err_bad_attr:
for (i = 0; i < ROCKER_TX_FRAGS_MAX; i++) {
- if (iov[i].iov_base) {
- g_free(iov[i].iov_base);
- }
+ g_free(iov[i].iov_base);
}
return err;
@@ -403,7 +401,13 @@ static int cmd_set_port_settings(Rocker *r,
if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]) {
mode = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]);
- fp_port_set_world(fp_port, r->worlds[mode]);
+ if (mode >= ROCKER_WORLD_TYPE_MAX) {
+ return -ROCKER_EINVAL;
+ }
+ /* We don't support world change. */
+ if (!fp_port_check_world(fp_port, r->worlds[mode])) {
+ return -ROCKER_EINVAL;
+ }
}
if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]) {
@@ -1283,6 +1287,18 @@ static void rocker_msix_uninit(Rocker *r)
rocker_msix_vectors_unuse(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
}
+static World *rocker_world_type_by_name(Rocker *r, const char *name)
+{
+ int i;
+
+ for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
+ if (strcmp(name, world_name(r->worlds[i])) == 0) {
+ return r->worlds[i];
+ }
+ }
+ return NULL;
+}
+
static int pci_rocker_init(PCIDevice *dev)
{
Rocker *r = to_rocker(dev);
@@ -1294,14 +1310,27 @@ static int pci_rocker_init(PCIDevice *dev)
/* allocate worlds */
r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r);
- r->world_dflt = r->worlds[ROCKER_WORLD_TYPE_OF_DPA];
for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
if (!r->worlds[i]) {
+ err = -ENOMEM;
goto err_world_alloc;
}
}
+ if (!r->world_name) {
+ r->world_name = g_strdup(world_name(r->worlds[ROCKER_WORLD_TYPE_OF_DPA]));
+ }
+
+ r->world_dflt = rocker_world_type_by_name(r, r->world_name);
+ if (!r->world_dflt) {
+ fprintf(stderr,
+ "rocker: requested world \"%s\" does not exist\n",
+ r->world_name);
+ err = -EINVAL;
+ goto err_world_type_by_name;
+ }
+
/* set up memory-mapped region at BAR0 */
memory_region_init_io(&r->mmio, OBJECT(r), &rocker_mmio_ops, r,
@@ -1364,7 +1393,7 @@ static int pci_rocker_init(PCIDevice *dev)
r->fp_ports = ROCKER_FP_PORTS_MAX;
}
- r->rings = g_malloc(sizeof(DescRing *) * rocker_pci_ring_count(r));
+ r->rings = g_new(DescRing *, rocker_pci_ring_count(r));
if (!r->rings) {
goto err_rings_alloc;
}
@@ -1435,6 +1464,7 @@ err_duplicate:
err_msix_init:
object_unparent(OBJECT(&r->msix_bar));
object_unparent(OBJECT(&r->mmio));
+err_world_type_by_name:
err_world_alloc:
for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
if (r->worlds[i]) {
@@ -1506,6 +1536,7 @@ static void rocker_reset(DeviceState *dev)
static Property rocker_properties[] = {
DEFINE_PROP_STRING("name", Rocker, name),
+ DEFINE_PROP_STRING("world", Rocker, world_name),
DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker,
fp_start_macaddr),
DEFINE_PROP_UINT64("switch_id", Rocker,
diff --git a/qemu/hw/net/rocker/rocker_desc.c b/qemu/hw/net/rocker/rocker_desc.c
index 9d896fe47..ac02797b7 100644
--- a/qemu/hw/net/rocker/rocker_desc.c
+++ b/qemu/hw/net/rocker/rocker_desc.c
@@ -14,6 +14,7 @@
* GNU General Public License for more details.
*/
+#include "qemu/osdep.h"
#include "net/net.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
@@ -136,15 +137,13 @@ bool desc_ring_set_size(DescRing *ring, uint32_t size)
}
for (i = 0; i < ring->size; i++) {
- if (ring->info[i].buf) {
- g_free(ring->info[i].buf);
- }
+ g_free(ring->info[i].buf);
}
ring->size = size;
ring->head = ring->tail = 0;
- ring->info = g_realloc(ring->info, size * sizeof(DescInfo));
+ ring->info = g_renew(DescInfo, ring->info, size);
if (!ring->info) {
return false;
}
@@ -347,7 +346,7 @@ DescRing *desc_ring_alloc(Rocker *r, int index)
{
DescRing *ring;
- ring = g_malloc0(sizeof(DescRing));
+ ring = g_new0(DescRing, 1);
if (!ring) {
return NULL;
}
@@ -360,9 +359,7 @@ DescRing *desc_ring_alloc(Rocker *r, int index)
void desc_ring_free(DescRing *ring)
{
- if (ring->info) {
- g_free(ring->info);
- }
+ g_free(ring->info);
g_free(ring);
}
diff --git a/qemu/hw/net/rocker/rocker_fp.c b/qemu/hw/net/rocker/rocker_fp.c
index c693ae508..0149899c6 100644
--- a/qemu/hw/net/rocker/rocker_fp.c
+++ b/qemu/hw/net/rocker/rocker_fp.c
@@ -14,6 +14,7 @@
* GNU General Public License for more details.
*/
+#include "qemu/osdep.h"
#include "net/clients.h"
#include "rocker.h"
@@ -185,6 +186,11 @@ void fp_port_set_world(FpPort *port, World *world)
port->world = world;
}
+bool fp_port_check_world(FpPort *port, World *world)
+{
+ return port->world == world;
+}
+
bool fp_port_enabled(FpPort *port)
{
return port->enabled;
@@ -218,7 +224,7 @@ FpPort *fp_port_alloc(Rocker *r, char *sw_name,
MACAddr *start_mac, unsigned int index,
NICPeers *peers)
{
- FpPort *port = g_malloc0(sizeof(FpPort));
+ FpPort *port = g_new0(FpPort, 1);
if (!port) {
return NULL;
diff --git a/qemu/hw/net/rocker/rocker_fp.h b/qemu/hw/net/rocker/rocker_fp.h
index ab80fd833..04592bbfd 100644
--- a/qemu/hw/net/rocker/rocker_fp.h
+++ b/qemu/hw/net/rocker/rocker_fp.h
@@ -40,6 +40,7 @@ int fp_port_set_settings(FpPort *port, uint32_t speed,
bool fp_port_from_pport(uint32_t pport, uint32_t *port);
World *fp_port_get_world(FpPort *port);
void fp_port_set_world(FpPort *port, World *world);
+bool fp_port_check_world(FpPort *port, World *world);
bool fp_port_enabled(FpPort *port);
void fp_port_enable(FpPort *port);
void fp_port_disable(FpPort *port);
diff --git a/qemu/hw/net/rocker/rocker_of_dpa.c b/qemu/hw/net/rocker/rocker_of_dpa.c
index 874fb01d6..0a134ebca 100644
--- a/qemu/hw/net/rocker/rocker_of_dpa.c
+++ b/qemu/hw/net/rocker/rocker_of_dpa.c
@@ -14,6 +14,7 @@
* GNU General Public License for more details.
*/
+#include "qemu/osdep.h"
#include "net/eth.h"
#include "qemu/iov.h"
#include "qemu/timer.h"
@@ -367,7 +368,7 @@ static OfDpaFlow *of_dpa_flow_alloc(uint64_t cookie)
OfDpaFlow *flow;
int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) / 1000;
- flow = g_malloc0(sizeof(OfDpaFlow));
+ flow = g_new0(OfDpaFlow, 1);
if (!flow) {
return NULL;
}
@@ -811,7 +812,7 @@ static int of_dpa_group_get_stats(OfDpa *of_dpa, uint32_t id)
static OfDpaGroup *of_dpa_group_alloc(uint32_t id)
{
- OfDpaGroup *group = g_malloc0(sizeof(OfDpaGroup));
+ OfDpaGroup *group = g_new0(OfDpaGroup, 1);
if (!group) {
return NULL;
@@ -2039,15 +2040,14 @@ static int of_dpa_cmd_add_l2_flood(OfDpa *of_dpa, OfDpaGroup *group,
group->l2_flood.group_count =
rocker_tlv_get_le16(group_tlvs[ROCKER_TLV_OF_DPA_GROUP_COUNT]);
- tlvs = g_malloc0((group->l2_flood.group_count + 1) *
- sizeof(RockerTlv *));
+ tlvs = g_new0(RockerTlv *, group->l2_flood.group_count + 1);
if (!tlvs) {
return -ROCKER_ENOMEM;
}
g_free(group->l2_flood.group_ids);
group->l2_flood.group_ids =
- g_malloc0(group->l2_flood.group_count * sizeof(uint32_t));
+ g_new0(uint32_t, group->l2_flood.group_count);
if (!group->l2_flood.group_ids) {
err = -ROCKER_ENOMEM;
goto err_out;
@@ -2463,15 +2463,13 @@ RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name,
r = rocker_find(name);
if (!r) {
- error_set(errp, ERROR_CLASS_GENERIC_ERROR,
- "rocker %s not found", name);
+ error_setg(errp, "rocker %s not found", name);
return NULL;
}
w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA);
if (!w) {
- error_set(errp, ERROR_CLASS_GENERIC_ERROR,
- "rocker %s doesn't have OF-DPA world", name);
+ error_setg(errp, "rocker %s doesn't have OF-DPA world", name);
return NULL;
}
@@ -2598,15 +2596,13 @@ RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name,
r = rocker_find(name);
if (!r) {
- error_set(errp, ERROR_CLASS_GENERIC_ERROR,
- "rocker %s not found", name);
+ error_setg(errp, "rocker %s not found", name);
return NULL;
}
w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA);
if (!w) {
- error_set(errp, ERROR_CLASS_GENERIC_ERROR,
- "rocker %s doesn't have OF-DPA world", name);
+ error_setg(errp, "rocker %s doesn't have OF-DPA world", name);
return NULL;
}
@@ -2618,6 +2614,7 @@ RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name,
}
static WorldOps of_dpa_ops = {
+ .name = "ofdpa",
.init = of_dpa_init,
.uninit = of_dpa_uninit,
.ig = of_dpa_ig,
diff --git a/qemu/hw/net/rocker/rocker_world.c b/qemu/hw/net/rocker/rocker_world.c
index a6b18f175..89777e968 100644
--- a/qemu/hw/net/rocker/rocker_world.c
+++ b/qemu/hw/net/rocker/rocker_world.c
@@ -14,6 +14,7 @@
* GNU General Public License for more details.
*/
+#include "qemu/osdep.h"
#include "qemu/iov.h"
#include "rocker.h"
@@ -97,10 +98,5 @@ enum rocker_world_type world_type(World *world)
const char *world_name(World *world)
{
- switch (world->type) {
- case ROCKER_WORLD_TYPE_OF_DPA:
- return "OF_DPA";
- default:
- return "unknown";
- }
+ return world->ops->name;
}
diff --git a/qemu/hw/net/rocker/rocker_world.h b/qemu/hw/net/rocker/rocker_world.h
index 18d277b92..58ade4733 100644
--- a/qemu/hw/net/rocker/rocker_world.h
+++ b/qemu/hw/net/rocker/rocker_world.h
@@ -33,6 +33,7 @@ typedef int (world_cmd)(World *world, DescInfo *info,
RockerTlv *cmd_info_tlv);
typedef struct world_ops {
+ const char *name;
world_init *init;
world_uninit *uninit;
world_ig *ig;
diff --git a/qemu/hw/net/rtl8139.c b/qemu/hw/net/rtl8139.c
index edbb61ccf..1e5ec149f 100644
--- a/qemu/hw/net/rtl8139.c
+++ b/qemu/hw/net/rtl8139.c
@@ -43,12 +43,13 @@
* Added rx/tx buffer reset when enabling rx/tx operation
*
* 2010-Feb-04 Frediano Ziglio: Rewrote timer support using QEMU timer only
- * when strictly needed (required for for
+ * when strictly needed (required for
* Darwin)
* 2011-Mar-22 Benjamin Poirier: Implemented VLAN offloading
*/
/* For crc32 */
+#include "qemu/osdep.h"
#include <zlib.h>
#include "hw/hw.h"
@@ -56,6 +57,7 @@
#include "sysemu/dma.h"
#include "qemu/timer.h"
#include "net/net.h"
+#include "net/eth.h"
#include "hw/loader.h"
#include "sysemu/sysemu.h"
#include "qemu/iov.h"
@@ -63,7 +65,7 @@
/* debug RTL8139 card */
//#define DEBUG_RTL8139 1
-#define PCI_FREQUENCY 33000000L
+#define PCI_PERIOD 30 /* 30 ns period = 33.333333 Mhz frequency */
#define SET_MASKED(input, mask, curr) \
( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
@@ -72,11 +74,7 @@
#define MOD2(input, size) \
( ( input ) & ( size - 1 ) )
-#define ETHER_ADDR_LEN 6
#define ETHER_TYPE_LEN 2
-#define ETH_HLEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
-#define ETH_P_IP 0x0800 /* Internet Protocol packet */
-#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
#define ETH_MTU 1500
#define VLAN_TCI_LEN 2
@@ -1016,8 +1014,8 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
/* write VLAN info to descriptor variables. */
if (s->CpCmd & CPlusRxVLAN && be16_to_cpup((uint16_t *)
- &buf[ETHER_ADDR_LEN * 2]) == ETH_P_8021Q) {
- dot1q_buf = &buf[ETHER_ADDR_LEN * 2];
+ &buf[ETH_ALEN * 2]) == ETH_P_VLAN) {
+ dot1q_buf = &buf[ETH_ALEN * 2];
size -= VLAN_HLEN;
/* if too small buffer, use the tailroom added duing expansion */
if (size < MIN_BUF_SIZE) {
@@ -1058,10 +1056,10 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
/* receive/copy to target memory */
if (dot1q_buf) {
- pci_dma_write(d, rx_addr, buf, 2 * ETHER_ADDR_LEN);
- pci_dma_write(d, rx_addr + 2 * ETHER_ADDR_LEN,
- buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN,
- size - 2 * ETHER_ADDR_LEN);
+ pci_dma_write(d, rx_addr, buf, 2 * ETH_ALEN);
+ pci_dma_write(d, rx_addr + 2 * ETH_ALEN,
+ buf + 2 * ETH_ALEN + VLAN_HLEN,
+ size - 2 * ETH_ALEN);
} else {
pci_dma_write(d, rx_addr, buf, size);
}
@@ -1148,7 +1146,9 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
/* if receiver buffer is empty then avail == 0 */
- if (avail != 0 && size + 8 >= avail)
+#define RX_ALIGN(x) (((x) + 3) & ~0x3)
+
+ if (avail != 0 && RX_ALIGN(size + 8) >= avail)
{
DPRINTF("rx overflow: rx buffer length %d head 0x%04x "
"read 0x%04x === available 0x%04x need 0x%04x\n",
@@ -1157,7 +1157,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
s->IntrStatus |= RxOverflow;
++s->RxMissed;
rtl8139_update_irq(s);
- return size_;
+ return 0;
}
packet_header |= RxStatusOK;
@@ -1176,7 +1176,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
rtl8139_write_buffer(s, (uint8_t *)&val, 4);
/* correct buffer write pointer */
- s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize);
+ s->RxBufAddr = MOD2(RX_ALIGN(s->RxBufAddr), s->RxBufferSize);
/* now we can signal we have received something */
@@ -1783,12 +1783,12 @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
return;
}
- if (dot1q_buf && size >= ETHER_ADDR_LEN * 2) {
+ if (dot1q_buf && size >= ETH_ALEN * 2) {
iov = (struct iovec[3]) {
- { .iov_base = buf, .iov_len = ETHER_ADDR_LEN * 2 },
+ { .iov_base = buf, .iov_len = ETH_ALEN * 2 },
{ .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN },
- { .iov_base = buf + ETHER_ADDR_LEN * 2,
- .iov_len = size - ETHER_ADDR_LEN * 2 },
+ { .iov_base = buf + ETH_ALEN * 2,
+ .iov_len = size - ETH_ALEN * 2 },
};
memcpy(vlan_iov, iov, sizeof(vlan_iov));
@@ -1868,64 +1868,12 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
}
/* structures and macros for task offloading */
-typedef struct ip_header
-{
- uint8_t ip_ver_len; /* version and header length */
- uint8_t ip_tos; /* type of service */
- uint16_t ip_len; /* total length */
- uint16_t ip_id; /* identification */
- uint16_t ip_off; /* fragment offset field */
- uint8_t ip_ttl; /* time to live */
- uint8_t ip_p; /* protocol */
- uint16_t ip_sum; /* checksum */
- uint32_t ip_src,ip_dst; /* source and dest address */
-} ip_header;
-
-#define IP_HEADER_VERSION_4 4
-#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf)
-#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2)
-
-typedef struct tcp_header
-{
- uint16_t th_sport; /* source port */
- uint16_t th_dport; /* destination port */
- uint32_t th_seq; /* sequence number */
- uint32_t th_ack; /* acknowledgement number */
- uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */
- uint16_t th_win; /* window */
- uint16_t th_sum; /* checksum */
- uint16_t th_urp; /* urgent pointer */
-} tcp_header;
-
-typedef struct udp_header
-{
- uint16_t uh_sport; /* source port */
- uint16_t uh_dport; /* destination port */
- uint16_t uh_ulen; /* udp length */
- uint16_t uh_sum; /* udp checksum */
-} udp_header;
-
-typedef struct ip_pseudo_header
-{
- uint32_t ip_src;
- uint32_t ip_dst;
- uint8_t zeros;
- uint8_t ip_proto;
- uint16_t ip_payload;
-} ip_pseudo_header;
-
-#define IP_PROTO_TCP 6
-#define IP_PROTO_UDP 17
-
#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2)
#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f)
#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags))
#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off)))
-#define TCP_FLAG_FIN 0x01
-#define TCP_FLAG_PUSH 0x08
-
/* produces ones' complement sum of data */
static uint16_t ones_complement_sum(uint8_t *data, size_t len)
{
@@ -2098,7 +2046,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
}
/* transfer ownership to target */
- txdw0 &= ~CP_RX_OWN;
+ txdw0 &= ~CP_TX_OWN;
/* reset error indicator bits */
txdw0 &= ~CP_TX_STATUS_UNF;
@@ -2134,7 +2082,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
bswap16(txdw1 & CP_TX_VLAN_TAG_MASK));
dot1q_buffer = (uint16_t *) dot1q_buffer_space;
- dot1q_buffer[0] = cpu_to_be16(ETH_P_8021Q);
+ dot1q_buffer[0] = cpu_to_be16(ETH_P_VLAN);
/* BE + le_to_cpu() + ~cpu_to_le()~ = BE */
dot1q_buffer[1] = cpu_to_le16(txdw1 & CP_TX_VLAN_TAG_MASK);
} else {
@@ -2151,12 +2099,12 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
DPRINTF("+++ C+ mode offloaded task checksum\n");
/* Large enough for Ethernet and IP headers? */
- if (saved_size < ETH_HLEN + sizeof(ip_header)) {
+ if (saved_size < ETH_HLEN + sizeof(struct ip_header)) {
goto skip_offload;
}
/* ip packet header */
- ip_header *ip = NULL;
+ struct ip_header *ip = NULL;
int hlen = 0;
uint8_t ip_protocol = 0;
uint16_t ip_data_len = 0;
@@ -2172,11 +2120,15 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
DPRINTF("+++ C+ mode has IP packet\n");
- /* not aligned */
+ /* Note on memory alignment: eth_payload_data is 16-bit aligned
+ * since saved_buffer is allocated with g_malloc() and ETH_HLEN is
+ * even. 32-bit accesses must use ldl/stl wrappers to avoid
+ * unaligned accesses.
+ */
eth_payload_data = saved_buffer + ETH_HLEN;
eth_payload_len = saved_size - ETH_HLEN;
- ip = (ip_header*)eth_payload_data;
+ ip = (struct ip_header*)eth_payload_data;
if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
DPRINTF("+++ C+ mode packet has bad IP version %d "
@@ -2185,8 +2137,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
goto skip_offload;
}
- hlen = IP_HEADER_LENGTH(ip);
- if (hlen < sizeof(ip_header) || hlen > eth_payload_len) {
+ hlen = IP_HDR_GET_LEN(ip);
+ if (hlen < sizeof(struct ip_header) || hlen > eth_payload_len) {
goto skip_offload;
}
@@ -2269,7 +2221,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
}
DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
- be32_to_cpu(p_tcp_hdr->th_seq));
+ ldl_be_p(&p_tcp_hdr->th_seq));
/* add 4 TCP pseudoheader fields */
/* copy IP source and destination fields */
@@ -2287,7 +2239,7 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
/* keep PUSH and FIN flags only for the last frame */
if (!is_last_frame)
{
- TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
+ TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TH_PUSH | TH_FIN);
}
/* recalculate TCP checksum */
@@ -2325,7 +2277,8 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
0, (uint8_t *) dot1q_buffer);
/* add transferred count to TCP sequence number */
- p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
+ stl_be_p(&p_tcp_hdr->th_seq,
+ chunk_size + ldl_be_p(&p_tcp_hdr->th_seq));
++send_count;
}
@@ -2881,8 +2834,7 @@ static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
static void rtl8139_set_next_tctr_time(RTL8139State *s)
{
- const uint64_t ns_per_period =
- muldiv64(0x100000000LL, get_ticks_per_sec(), PCI_FREQUENCY);
+ const uint64_t ns_per_period = (uint64_t)PCI_PERIOD << 32;
DPRINTF("entered rtl8139_set_next_tctr_time\n");
@@ -2900,7 +2852,7 @@ static void rtl8139_set_next_tctr_time(RTL8139State *s)
if (!s->TimerInt) {
timer_del(s->timer);
} else {
- uint64_t delta = muldiv64(s->TimerInt, get_ticks_per_sec(), PCI_FREQUENCY);
+ uint64_t delta = (uint64_t)s->TimerInt * PCI_PERIOD;
if (s->TCTR_base + delta <= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
delta += ns_per_period;
}
@@ -3174,8 +3126,8 @@ static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
break;
case Timer:
- ret = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->TCTR_base,
- PCI_FREQUENCY, get_ticks_per_sec());
+ ret = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->TCTR_base) /
+ PCI_PERIOD;
DPRINTF("TCTR Timer read val=0x%08x\n", ret);
break;
@@ -3269,8 +3221,7 @@ static void rtl8139_pre_save(void *opaque)
int64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
/* for migration to older versions */
- s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
- get_ticks_per_sec());
+ s->TCTR = (current_time - s->TCTR_base) / PCI_PERIOD;
s->rtl8139_mmio_io_addr_dummy = 0;
}
@@ -3438,10 +3389,8 @@ static void pci_rtl8139_uninit(PCIDevice *dev)
{
RTL8139State *s = RTL8139(dev);
- if (s->cplus_txbuffer) {
- g_free(s->cplus_txbuffer);
- s->cplus_txbuffer = NULL;
- }
+ g_free(s->cplus_txbuffer);
+ s->cplus_txbuffer = NULL;
timer_del(s->timer);
timer_free(s->timer);
qemu_del_nic(s->nic);
diff --git a/qemu/hw/net/smc91c111.c b/qemu/hw/net/smc91c111.c
index 74e06e6c7..21c1b8f54 100644
--- a/qemu/hw/net/smc91c111.c
+++ b/qemu/hw/net/smc91c111.c
@@ -7,6 +7,7 @@
* This code is licensed under the GPL
*/
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "net/net.h"
#include "hw/devices.h"
@@ -124,6 +125,25 @@ static void smc91c111_update(smc91c111_state *s)
qemu_set_irq(s->irq, level);
}
+static int smc91c111_can_receive(smc91c111_state *s)
+{
+ if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) {
+ return 1;
+ }
+ if (s->allocated == (1 << NUM_PACKETS) - 1 ||
+ s->rx_fifo_len == NUM_PACKETS) {
+ return 0;
+ }
+ return 1;
+}
+
+static inline void smc91c111_flush_queued_packets(smc91c111_state *s)
+{
+ if (smc91c111_can_receive(s)) {
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
+ }
+}
+
/* Try to allocate a packet. Returns 0x80 on failure. */
static int smc91c111_allocate_packet(smc91c111_state *s)
{
@@ -164,6 +184,7 @@ static void smc91c111_pop_rx_fifo(smc91c111_state *s)
} else {
s->int_level &= ~INT_RCV;
}
+ smc91c111_flush_queued_packets(s);
smc91c111_update(s);
}
@@ -185,7 +206,7 @@ static void smc91c111_release_packet(smc91c111_state *s, int packet)
s->allocated &= ~(1 << packet);
if (s->tx_alloc == 0x80)
smc91c111_tx_alloc(s);
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
+ smc91c111_flush_queued_packets(s);
}
/* Flush the TX FIFO. */
@@ -311,6 +332,7 @@ static void smc91c111_writeb(void *opaque, hwaddr offset,
if (s->rcr & RCR_SOFT_RST) {
smc91c111_reset(DEVICE(s));
}
+ smc91c111_flush_queued_packets(s);
return;
case 10: case 11: /* RPCR */
/* Ignored */
@@ -636,15 +658,11 @@ static uint32_t smc91c111_readl(void *opaque, hwaddr offset)
return val;
}
-static int smc91c111_can_receive(NetClientState *nc)
+static int smc91c111_can_receive_nc(NetClientState *nc)
{
smc91c111_state *s = qemu_get_nic_opaque(nc);
- if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
- return 1;
- if (s->allocated == (1 << NUM_PACKETS) - 1)
- return 0;
- return 1;
+ return smc91c111_can_receive(s);
}
static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t size)
@@ -739,7 +757,7 @@ static const MemoryRegionOps smc91c111_mem_ops = {
static NetClientInfo net_smc91c111_info = {
.type = NET_CLIENT_OPTIONS_KIND_NIC,
.size = sizeof(NICState),
- .can_receive = smc91c111_can_receive,
+ .can_receive = smc91c111_can_receive_nc,
.receive = smc91c111_receive,
};
diff --git a/qemu/hw/net/spapr_llan.c b/qemu/hw/net/spapr_llan.c
index 1ca5e9ce6..a647f25d9 100644
--- a/qemu/hw/net/spapr_llan.c
+++ b/qemu/hw/net/spapr_llan.c
@@ -24,6 +24,9 @@
* THE SOFTWARE.
*
*/
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
#include "hw/hw.h"
#include "net/net.h"
#include "hw/qdev.h"
@@ -44,6 +47,10 @@
#define DPRINTF(fmt...)
#endif
+/* Compatibility flags for migration */
+#define SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT 0
+#define SPAPRVLAN_FLAG_RX_BUF_POOLS (1 << SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT)
+
/*
* Virtual LAN device
*/
@@ -85,6 +92,15 @@ typedef uint64_t vlan_bd_t;
#define VIO_SPAPR_VLAN_DEVICE(obj) \
OBJECT_CHECK(VIOsPAPRVLANDevice, (obj), TYPE_VIO_SPAPR_VLAN_DEVICE)
+#define RX_POOL_MAX_BDS 4096
+#define RX_MAX_POOLS 5
+
+typedef struct {
+ int32_t bufsize;
+ int32_t count;
+ vlan_bd_t bds[RX_POOL_MAX_BDS];
+} RxBufPool;
+
typedef struct VIOsPAPRVLANDevice {
VIOsPAPRDevice sdev;
NICConf nicconf;
@@ -93,6 +109,8 @@ typedef struct VIOsPAPRVLANDevice {
target_ulong buf_list;
uint32_t add_buf_ptr, use_buf_ptr, rx_bufs;
target_ulong rxq_ptr;
+ uint32_t compat_flags; /* Compatability flags for migration */
+ RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */
} VIOsPAPRVLANDevice;
static int spapr_vlan_can_receive(NetClientState *nc)
@@ -102,6 +120,73 @@ static int spapr_vlan_can_receive(NetClientState *nc)
return (dev->isopen && dev->rx_bufs > 0);
}
+/**
+ * Get buffer descriptor from one of our receive buffer pools
+ */
+static vlan_bd_t spapr_vlan_get_rx_bd_from_pool(VIOsPAPRVLANDevice *dev,
+ size_t size)
+{
+ vlan_bd_t bd;
+ int pool;
+
+ for (pool = 0; pool < RX_MAX_POOLS; pool++) {
+ if (dev->rx_pool[pool]->count > 0 &&
+ dev->rx_pool[pool]->bufsize >= size + 8) {
+ break;
+ }
+ }
+ if (pool == RX_MAX_POOLS) {
+ /* Failed to find a suitable buffer */
+ return 0;
+ }
+
+ DPRINTF("Found buffer: pool=%d count=%d rxbufs=%d\n", pool,
+ dev->rx_pool[pool]->count, dev->rx_bufs);
+
+ /* Remove the buffer from the pool */
+ dev->rx_pool[pool]->count--;
+ bd = dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count];
+ dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count] = 0;
+
+ return bd;
+}
+
+/**
+ * Get buffer descriptor from the receive buffer list page that has been
+ * supplied by the guest with the H_REGISTER_LOGICAL_LAN call
+ */
+static vlan_bd_t spapr_vlan_get_rx_bd_from_page(VIOsPAPRVLANDevice *dev,
+ size_t size)
+{
+ int buf_ptr = dev->use_buf_ptr;
+ vlan_bd_t bd;
+
+ do {
+ buf_ptr += 8;
+ if (buf_ptr >= VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF) {
+ buf_ptr = VLAN_RX_BDS_OFF;
+ }
+
+ bd = vio_ldq(&dev->sdev, dev->buf_list + buf_ptr);
+ DPRINTF("use_buf_ptr=%d bd=0x%016llx\n",
+ buf_ptr, (unsigned long long)bd);
+ } while ((!(bd & VLAN_BD_VALID) || VLAN_BD_LEN(bd) < size + 8)
+ && buf_ptr != dev->use_buf_ptr);
+
+ if (!(bd & VLAN_BD_VALID) || VLAN_BD_LEN(bd) < size + 8) {
+ /* Failed to find a suitable buffer */
+ return 0;
+ }
+
+ /* Remove the buffer from the pool */
+ dev->use_buf_ptr = buf_ptr;
+ vio_stq(&dev->sdev, dev->buf_list + dev->use_buf_ptr, 0);
+
+ DPRINTF("Found buffer: ptr=%d rxbufs=%d\n", dev->use_buf_ptr, dev->rx_bufs);
+
+ return bd;
+}
+
static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
size_t size)
{
@@ -109,7 +194,6 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
VIOsPAPRDevice *sdev = VIO_SPAPR_DEVICE(dev);
vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
vlan_bd_t bd;
- int buf_ptr = dev->use_buf_ptr;
uint64_t handle;
uint8_t control;
@@ -124,29 +208,16 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
return -1;
}
- do {
- buf_ptr += 8;
- if (buf_ptr >= (VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF)) {
- buf_ptr = VLAN_RX_BDS_OFF;
- }
-
- bd = vio_ldq(sdev, dev->buf_list + buf_ptr);
- DPRINTF("use_buf_ptr=%d bd=0x%016llx\n",
- buf_ptr, (unsigned long long)bd);
- } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
- && (buf_ptr != dev->use_buf_ptr));
-
- if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
- /* Failed to find a suitable buffer */
+ if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
+ bd = spapr_vlan_get_rx_bd_from_pool(dev, size);
+ } else {
+ bd = spapr_vlan_get_rx_bd_from_page(dev, size);
+ }
+ if (!bd) {
return -1;
}
- /* Remove the buffer from the pool */
dev->rx_bufs--;
- dev->use_buf_ptr = buf_ptr;
- vio_stq(sdev, dev->buf_list + dev->use_buf_ptr, 0);
-
- DPRINTF("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
/* Transfer the packet data */
if (spapr_vio_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
@@ -194,13 +265,31 @@ static NetClientInfo net_spapr_vlan_info = {
.receive = spapr_vlan_receive,
};
+static void spapr_vlan_reset_rx_pool(RxBufPool *rxp)
+{
+ /*
+ * Use INT_MAX as bufsize so that unused buffers are moved to the end
+ * of the list during the qsort in spapr_vlan_add_rxbuf_to_pool() later.
+ */
+ rxp->bufsize = INT_MAX;
+ rxp->count = 0;
+ memset(rxp->bds, 0, sizeof(rxp->bds));
+}
+
static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
{
VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
+ int i;
dev->buf_list = 0;
dev->rx_bufs = 0;
dev->isopen = 0;
+
+ if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
+ for (i = 0; i < RX_MAX_POOLS; i++) {
+ spapr_vlan_reset_rx_pool(dev->rx_pool[i]);
+ }
+ }
}
static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
@@ -217,10 +306,31 @@ static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
static void spapr_vlan_instance_init(Object *obj)
{
VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(obj);
+ int i;
device_add_bootindex_property(obj, &dev->nicconf.bootindex,
"bootindex", "",
DEVICE(dev), NULL);
+
+ if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
+ for (i = 0; i < RX_MAX_POOLS; i++) {
+ dev->rx_pool[i] = g_new(RxBufPool, 1);
+ spapr_vlan_reset_rx_pool(dev->rx_pool[i]);
+ }
+ }
+}
+
+static void spapr_vlan_instance_finalize(Object *obj)
+{
+ VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(obj);
+ int i;
+
+ if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
+ for (i = 0; i < RX_MAX_POOLS; i++) {
+ g_free(dev->rx_pool[i]);
+ dev->rx_pool[i] = NULL;
+ }
+ }
}
void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
@@ -371,6 +481,113 @@ static target_ulong h_free_logical_lan(PowerPCCPU *cpu,
return H_SUCCESS;
}
+/**
+ * Used for qsort, this function compares two RxBufPools by size.
+ */
+static int rx_pool_size_compare(const void *p1, const void *p2)
+{
+ const RxBufPool *pool1 = *(RxBufPool **)p1;
+ const RxBufPool *pool2 = *(RxBufPool **)p2;
+
+ if (pool1->bufsize < pool2->bufsize) {
+ return -1;
+ }
+ return pool1->bufsize > pool2->bufsize;
+}
+
+/**
+ * Search for a matching buffer pool with exact matching size,
+ * or return -1 if no matching pool has been found.
+ */
+static int spapr_vlan_get_rx_pool_id(VIOsPAPRVLANDevice *dev, int size)
+{
+ int pool;
+
+ for (pool = 0; pool < RX_MAX_POOLS; pool++) {
+ if (dev->rx_pool[pool]->bufsize == size) {
+ return pool;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * Enqueuing receive buffer by adding it to one of our receive buffer pools
+ */
+static target_long spapr_vlan_add_rxbuf_to_pool(VIOsPAPRVLANDevice *dev,
+ target_ulong buf)
+{
+ int size = VLAN_BD_LEN(buf);
+ int pool;
+
+ pool = spapr_vlan_get_rx_pool_id(dev, size);
+ if (pool < 0) {
+ /*
+ * No matching pool found? Try to use a new one. If the guest used all
+ * pools before, but changed the size of one pool inbetween, we might
+ * need to recycle that pool here (if it's empty already). Thus scan
+ * all buffer pools now, starting with the last (likely empty) one.
+ */
+ for (pool = RX_MAX_POOLS - 1; pool >= 0 ; pool--) {
+ if (dev->rx_pool[pool]->count == 0) {
+ dev->rx_pool[pool]->bufsize = size;
+ /*
+ * Sort pools by size so that spapr_vlan_receive()
+ * can later find the smallest buffer pool easily.
+ */
+ qsort(dev->rx_pool, RX_MAX_POOLS, sizeof(dev->rx_pool[0]),
+ rx_pool_size_compare);
+ pool = spapr_vlan_get_rx_pool_id(dev, size);
+ DPRINTF("created RX pool %d for size %lld\n", pool,
+ VLAN_BD_LEN(buf));
+ break;
+ }
+ }
+ }
+ /* Still no usable pool? Give up */
+ if (pool < 0 || dev->rx_pool[pool]->count >= RX_POOL_MAX_BDS) {
+ return H_RESOURCE;
+ }
+
+ DPRINTF("h_add_llan_buf(): Add buf using pool %i (size %lli, count=%i)\n",
+ pool, VLAN_BD_LEN(buf), dev->rx_pool[pool]->count);
+
+ dev->rx_pool[pool]->bds[dev->rx_pool[pool]->count++] = buf;
+
+ return 0;
+}
+
+/**
+ * This is the old way of enqueuing receive buffers: Add it to the rx queue
+ * page that has been supplied by the guest (which is quite limited in size).
+ */
+static target_long spapr_vlan_add_rxbuf_to_page(VIOsPAPRVLANDevice *dev,
+ target_ulong buf)
+{
+ vlan_bd_t bd;
+
+ if (dev->rx_bufs >= VLAN_MAX_BUFS) {
+ return H_RESOURCE;
+ }
+
+ do {
+ dev->add_buf_ptr += 8;
+ if (dev->add_buf_ptr >= VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF) {
+ dev->add_buf_ptr = VLAN_RX_BDS_OFF;
+ }
+
+ bd = vio_ldq(&dev->sdev, dev->buf_list + dev->add_buf_ptr);
+ } while (bd & VLAN_BD_VALID);
+
+ vio_stq(&dev->sdev, dev->buf_list + dev->add_buf_ptr, buf);
+
+ DPRINTF("h_add_llan_buf(): Added buf ptr=%d rx_bufs=%d bd=0x%016llx\n",
+ dev->add_buf_ptr, dev->rx_bufs, (unsigned long long)buf);
+
+ return 0;
+}
+
static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
sPAPRMachineState *spapr,
target_ulong opcode,
@@ -380,7 +597,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
target_ulong buf = args[1];
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
- vlan_bd_t bd;
+ target_long ret;
DPRINTF("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
", 0x" TARGET_FMT_lx ")\n", reg, buf);
@@ -396,29 +613,23 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
return H_PARAMETER;
}
- if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
+ if (!dev->isopen) {
return H_RESOURCE;
}
- do {
- dev->add_buf_ptr += 8;
- if (dev->add_buf_ptr >= (VLAN_RX_BDS_LEN + VLAN_RX_BDS_OFF)) {
- dev->add_buf_ptr = VLAN_RX_BDS_OFF;
- }
-
- bd = vio_ldq(sdev, dev->buf_list + dev->add_buf_ptr);
- } while (bd & VLAN_BD_VALID);
-
- vio_stq(sdev, dev->buf_list + dev->add_buf_ptr, buf);
+ if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
+ ret = spapr_vlan_add_rxbuf_to_pool(dev, buf);
+ } else {
+ ret = spapr_vlan_add_rxbuf_to_page(dev, buf);
+ }
+ if (ret) {
+ return ret;
+ }
dev->rx_bufs++;
qemu_flush_queued_packets(qemu_get_queue(dev->nic));
- DPRINTF("h_add_logical_lan_buffer(): Added buf ptr=%d rx_bufs=%d"
- " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
- (unsigned long long)buf);
-
return H_SUCCESS;
}
@@ -508,9 +719,44 @@ static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static Property spapr_vlan_properties[] = {
DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
+ DEFINE_PROP_BIT("use-rx-buffer-pools", VIOsPAPRVLANDevice,
+ compat_flags, SPAPRVLAN_FLAG_RX_BUF_POOLS_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
+static bool spapr_vlan_rx_buffer_pools_needed(void *opaque)
+{
+ VIOsPAPRVLANDevice *dev = opaque;
+
+ return (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) != 0;
+}
+
+static const VMStateDescription vmstate_rx_buffer_pool = {
+ .name = "spapr_llan/rx_buffer_pool",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = spapr_vlan_rx_buffer_pools_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(bufsize, RxBufPool),
+ VMSTATE_INT32(count, RxBufPool),
+ VMSTATE_UINT64_ARRAY(bds, RxBufPool, RX_POOL_MAX_BDS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_rx_pools = {
+ .name = "spapr_llan/rx_pools",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = spapr_vlan_rx_buffer_pools_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(rx_pool, VIOsPAPRVLANDevice,
+ RX_MAX_POOLS, 1,
+ vmstate_rx_buffer_pool, RxBufPool),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_spapr_llan = {
.name = "spapr_llan",
.version_id = 1,
@@ -527,6 +773,10 @@ static const VMStateDescription vmstate_spapr_llan = {
VMSTATE_END_OF_LIST()
},
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_rx_pools,
+ NULL
+ }
};
static void spapr_vlan_class_init(ObjectClass *klass, void *data)
@@ -553,6 +803,7 @@ static const TypeInfo spapr_vlan_info = {
.instance_size = sizeof(VIOsPAPRVLANDevice),
.class_init = spapr_vlan_class_init,
.instance_init = spapr_vlan_instance_init,
+ .instance_finalize = spapr_vlan_instance_finalize,
};
static void spapr_vlan_register_types(void)
diff --git a/qemu/hw/net/stellaris_enet.c b/qemu/hw/net/stellaris_enet.c
index 21a47735d..688089494 100644
--- a/qemu/hw/net/stellaris_enet.c
+++ b/qemu/hw/net/stellaris_enet.c
@@ -6,6 +6,7 @@
*
* This code is licensed under the GPL.
*/
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "net/net.h"
#include <zlib.h>
@@ -235,8 +236,18 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si
n = s->next_packet + s->np;
if (n >= 31)
n -= 31;
- s->np++;
+ if (size >= sizeof(s->rx[n].data) - 6) {
+ /* If the packet won't fit into the
+ * emulated 2K RAM, this is reported
+ * as a FIFO overrun error.
+ */
+ s->ris |= SE_INT_FOV;
+ stellaris_enet_update(s);
+ return -1;
+ }
+
+ s->np++;
s->rx[n].len = size + 6;
p = s->rx[n].data;
*(p++) = (size + 6);
diff --git a/qemu/hw/net/vhost_net.c b/qemu/hw/net/vhost_net.c
index 5c1d11f51..6e1032fc1 100644
--- a/qemu/hw/net/vhost_net.c
+++ b/qemu/hw/net/vhost_net.c
@@ -13,6 +13,7 @@
* GNU GPL, version 2 or (at your option) any later version.
*/
+#include "qemu/osdep.h"
#include "net/net.h"
#include "net/tap.h"
#include "net/vhost-user.h"
@@ -21,24 +22,20 @@
#include "net/vhost_net.h"
#include "qemu/error-report.h"
-#include "config.h"
#ifdef CONFIG_VHOST_NET
#include <linux/vhost.h>
#include <sys/socket.h>
#include <linux/kvm.h>
-#include <fcntl.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>
-#include <stdio.h>
#include "standard-headers/linux/virtio_ring.h"
#include "hw/virtio/vhost.h"
#include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio-access.h"
struct vhost_net {
struct vhost_dev dev;
@@ -77,13 +74,9 @@ static const int user_feature_bits[] = {
VIRTIO_NET_F_HOST_ECN,
VIRTIO_NET_F_HOST_UFO,
VIRTIO_NET_F_MRG_RXBUF,
- VIRTIO_NET_F_STATUS,
- VIRTIO_NET_F_CTRL_VQ,
- VIRTIO_NET_F_CTRL_RX,
- VIRTIO_NET_F_CTRL_VLAN,
- VIRTIO_NET_F_CTRL_RX_EXTRA,
- VIRTIO_NET_F_CTRL_MAC_ADDR,
- VIRTIO_NET_F_CTRL_GUEST_OFFLOADS,
+
+ /* This bit implies RARP isn't sent by QEMU out of band */
+ VIRTIO_NET_F_GUEST_ANNOUNCE,
VIRTIO_NET_F_MQ,
@@ -122,6 +115,11 @@ void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
}
+uint64_t vhost_net_get_max_queues(VHostNetState *net)
+{
+ return net->dev.max_queues;
+}
+
static int vhost_net_get_fd(NetClientState *backend)
{
switch (backend->info->type) {
@@ -143,6 +141,11 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
fprintf(stderr, "vhost-net requires net backend to be setup\n");
goto fail;
}
+ net->nc = options->net_backend;
+
+ net->dev.max_queues = 1;
+ net->dev.nvqs = 2;
+ net->dev.vqs = net->vqs;
if (backend_kernel) {
r = vhost_net_get_fd(options->net_backend);
@@ -152,14 +155,15 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend)
? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR);
net->backend = r;
+ net->dev.protocol_features = 0;
} else {
net->dev.backend_features = 0;
+ net->dev.protocol_features = 0;
net->backend = -1;
- }
- net->nc = options->net_backend;
- net->dev.nvqs = 2;
- net->dev.vqs = net->vqs;
+ /* vhost-user needs vq_index to initiate a specific queue pair */
+ net->dev.vq_index = net->nc->queue_index * net->dev.nvqs;
+ }
r = vhost_dev_init(&net->dev, options->opaque,
options->backend_type);
@@ -192,27 +196,6 @@ static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index)
net->dev.vq_index = vq_index;
}
-static int vhost_net_set_vnet_endian(VirtIODevice *dev, NetClientState *peer,
- bool set)
-{
- int r = 0;
-
- if (virtio_has_feature(dev, VIRTIO_F_VERSION_1) ||
- (virtio_legacy_is_cross_endian(dev) && !virtio_is_big_endian(dev))) {
- r = qemu_set_vnet_le(peer, set);
- if (r) {
- error_report("backend does not support LE vnet headers");
- }
- } else if (virtio_legacy_is_cross_endian(dev)) {
- r = qemu_set_vnet_be(peer, set);
- if (r) {
- error_report("backend does not support BE vnet headers");
- }
- }
-
- return r;
-}
-
static int vhost_net_start_one(struct vhost_net *net,
VirtIODevice *dev)
{
@@ -241,8 +224,7 @@ static int vhost_net_start_one(struct vhost_net *net,
file.fd = net->backend;
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
const VhostOps *vhost_ops = net->dev.vhost_ops;
- r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND,
- &file);
+ r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
if (r < 0) {
r = -errno;
goto fail;
@@ -255,8 +237,7 @@ fail:
if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
while (file.index-- > 0) {
const VhostOps *vhost_ops = net->dev.vhost_ops;
- int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND,
- &file);
+ int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
assert(r >= 0);
}
}
@@ -278,15 +259,7 @@ static void vhost_net_stop_one(struct vhost_net *net,
if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
const VhostOps *vhost_ops = net->dev.vhost_ops;
- int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND,
- &file);
- assert(r >= 0);
- }
- } else if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
- for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
- const VhostOps *vhost_ops = net->dev.vhost_ops;
- int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_OWNER,
- NULL);
+ int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
assert(r >= 0);
}
}
@@ -307,23 +280,28 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers");
- r = -ENOSYS;
- goto err;
- }
-
- r = vhost_net_set_vnet_endian(dev, ncs[0].peer, true);
- if (r < 0) {
- goto err;
+ return -ENOSYS;
}
for (i = 0; i < total_queues; i++) {
- vhost_net_set_vq_index(get_vhost_net(ncs[i].peer), i * 2);
- }
+ struct vhost_net *net;
+
+ net = get_vhost_net(ncs[i].peer);
+ vhost_net_set_vq_index(net, i * 2);
+
+ /* Suppress the masking guest notifiers on vhost user
+ * because vhost user doesn't interrupt masking/unmasking
+ * properly.
+ */
+ if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
+ dev->use_guest_notifier_mask = false;
+ }
+ }
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
if (r < 0) {
error_report("Error binding guest notifier: %d", -r);
- goto err_endian;
+ goto err;
}
for (i = 0; i < total_queues; i++) {
@@ -345,8 +323,6 @@ err_start:
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
fflush(stderr);
}
-err_endian:
- vhost_net_set_vnet_endian(dev, ncs[0].peer, false);
err:
return r;
}
@@ -369,8 +345,6 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
fflush(stderr);
}
assert(r >= 0);
-
- assert(vhost_net_set_vnet_endian(dev, ncs[0].peer, false) >= 0);
}
void vhost_net_cleanup(struct vhost_net *net)
@@ -379,6 +353,18 @@ void vhost_net_cleanup(struct vhost_net *net)
g_free(net);
}
+int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
+{
+ const VhostOps *vhost_ops = net->dev.vhost_ops;
+ int r = -1;
+
+ if (vhost_ops->vhost_migration_done) {
+ r = vhost_ops->vhost_migration_done(&net->dev, mac_addr);
+ }
+
+ return r;
+}
+
bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
{
return vhost_virtqueue_pending(&net->dev, idx);
@@ -411,7 +397,25 @@ VHostNetState *get_vhost_net(NetClientState *nc)
return vhost_net;
}
+
+int vhost_set_vring_enable(NetClientState *nc, int enable)
+{
+ VHostNetState *net = get_vhost_net(nc);
+ const VhostOps *vhost_ops = net->dev.vhost_ops;
+
+ if (vhost_ops->vhost_set_vring_enable) {
+ return vhost_ops->vhost_set_vring_enable(&net->dev, enable);
+ }
+
+ return 0;
+}
+
#else
+uint64_t vhost_net_get_max_queues(VHostNetState *net)
+{
+ return 1;
+}
+
struct vhost_net *vhost_net_init(VhostNetOptions *options)
{
error_report("vhost-net support is not compiled in");
@@ -452,8 +456,18 @@ void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
{
}
+int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
+{
+ return -1;
+}
+
VHostNetState *get_vhost_net(NetClientState *nc)
{
return 0;
}
+
+int vhost_set_vring_enable(NetClientState *nc, int enable)
+{
+ return 0;
+}
#endif
diff --git a/qemu/hw/net/virtio-net.c b/qemu/hw/net/virtio-net.c
index 151083954..5798f87d8 100644
--- a/qemu/hw/net/virtio-net.c
+++ b/qemu/hw/net/virtio-net.c
@@ -11,6 +11,7 @@
*
*/
+#include "qemu/osdep.h"
#include "qemu/iov.h"
#include "hw/virtio/virtio.h"
#include "net/net.h"
@@ -86,8 +87,8 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
memcpy(&netcfg, config, n->config_size);
- if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) &&
- !virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) &&
+ !virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) &&
memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
memcpy(n->mac, netcfg.mac, ETH_ALEN);
qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
@@ -128,6 +129,13 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
if (!n->vhost_started) {
int r, i;
+ if (n->needs_vnet_hdr_swap) {
+ error_report("backend does not support %s vnet headers; "
+ "falling back on userspace virtio",
+ virtio_is_big_endian(vdev) ? "BE" : "LE");
+ return;
+ }
+
/* Any packets outstanding? Purge them to avoid touching rings
* when vhost is running.
*/
@@ -152,6 +160,59 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
}
}
+static int virtio_net_set_vnet_endian_one(VirtIODevice *vdev,
+ NetClientState *peer,
+ bool enable)
+{
+ if (virtio_is_big_endian(vdev)) {
+ return qemu_set_vnet_be(peer, enable);
+ } else {
+ return qemu_set_vnet_le(peer, enable);
+ }
+}
+
+static bool virtio_net_set_vnet_endian(VirtIODevice *vdev, NetClientState *ncs,
+ int queues, bool enable)
+{
+ int i;
+
+ for (i = 0; i < queues; i++) {
+ if (virtio_net_set_vnet_endian_one(vdev, ncs[i].peer, enable) < 0 &&
+ enable) {
+ while (--i >= 0) {
+ virtio_net_set_vnet_endian_one(vdev, ncs[i].peer, false);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
+ int queues = n->multiqueue ? n->max_queues : 1;
+
+ if (virtio_net_started(n, status)) {
+ /* Before using the device, we tell the network backend about the
+ * endianness to use when parsing vnet headers. If the backend
+ * can't do it, we fallback onto fixing the headers in the core
+ * virtio-net code.
+ */
+ n->needs_vnet_hdr_swap = virtio_net_set_vnet_endian(vdev, n->nic->ncs,
+ queues, true);
+ } else if (virtio_net_started(n, vdev->status)) {
+ /* After using the device, we need to reset the network backend to
+ * the default (guest native endianness), otherwise the guest may
+ * lose network connectivity if it is rebooted into a different
+ * endianness.
+ */
+ virtio_net_set_vnet_endian(vdev, n->nic->ncs, queues, false);
+ }
+}
+
static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
{
VirtIONet *n = VIRTIO_NET(vdev);
@@ -159,6 +220,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
int i;
uint8_t queue_status;
+ virtio_net_vnet_endian_status(n, status);
virtio_net_vhost_status(n, status);
for (i = 0; i < n->max_queues; i++) {
@@ -304,7 +366,7 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
info->multicast_table = str_list;
info->vlan_table = get_vlan_table(n);
- if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VLAN)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VLAN)) {
info->vlan = RX_STATE_ALL;
} else if (!info->vlan_table) {
info->vlan = RX_STATE_NONE;
@@ -406,6 +468,10 @@ static int peer_attach(VirtIONet *n, int index)
return 0;
}
+ if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
+ vhost_set_vring_enable(nc->peer, 1);
+ }
+
if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
return 0;
}
@@ -421,6 +487,10 @@ static int peer_detach(VirtIONet *n, int index)
return 0;
}
+ if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
+ vhost_set_vring_enable(nc->peer, 0);
+ }
+
if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
return 0;
}
@@ -529,13 +599,13 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
int i;
virtio_net_set_multiqueue(n,
- __virtio_has_feature(features, VIRTIO_NET_F_MQ));
+ virtio_has_feature(features, VIRTIO_NET_F_MQ));
virtio_net_set_mrg_rx_bufs(n,
- __virtio_has_feature(features,
- VIRTIO_NET_F_MRG_RXBUF),
- __virtio_has_feature(features,
- VIRTIO_F_VERSION_1));
+ virtio_has_feature(features,
+ VIRTIO_NET_F_MRG_RXBUF),
+ virtio_has_feature(features,
+ VIRTIO_F_VERSION_1));
if (n->has_vnet_hdr) {
n->curr_guest_offloads =
@@ -552,7 +622,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
vhost_net_ack_features(get_vhost_net(nc->peer), features);
}
- if (__virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) {
+ if (virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) {
memset(n->vlans, 0, MAX_VLAN >> 3);
} else {
memset(n->vlans, 0xff, MAX_VLAN >> 3);
@@ -599,7 +669,7 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd,
uint64_t offloads;
size_t s;
- if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
return VIRTIO_NET_ERR;
}
@@ -810,20 +880,24 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
VirtIONet *n = VIRTIO_NET(vdev);
struct virtio_net_ctrl_hdr ctrl;
virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
- VirtQueueElement elem;
+ VirtQueueElement *elem;
size_t s;
struct iovec *iov, *iov2;
unsigned int iov_cnt;
- while (virtqueue_pop(vq, &elem)) {
- if (iov_size(elem.in_sg, elem.in_num) < sizeof(status) ||
- iov_size(elem.out_sg, elem.out_num) < sizeof(ctrl)) {
+ for (;;) {
+ elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
+ if (!elem) {
+ break;
+ }
+ if (iov_size(elem->in_sg, elem->in_num) < sizeof(status) ||
+ iov_size(elem->out_sg, elem->out_num) < sizeof(ctrl)) {
error_report("virtio-net ctrl missing headers");
exit(1);
}
- iov_cnt = elem.out_num;
- iov2 = iov = g_memdup(elem.out_sg, sizeof(struct iovec) * elem.out_num);
+ iov_cnt = elem->out_num;
+ iov2 = iov = g_memdup(elem->out_sg, sizeof(struct iovec) * elem->out_num);
s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
iov_discard_front(&iov, &iov_cnt, sizeof(ctrl));
if (s != sizeof(ctrl)) {
@@ -842,12 +916,13 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
status = virtio_net_handle_offloads(n, ctrl.cmd, iov, iov_cnt);
}
- s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status));
+ s = iov_from_buf(elem->in_sg, elem->in_num, 0, &status, sizeof(status));
assert(s == sizeof(status));
- virtqueue_push(vq, &elem, sizeof(status));
+ virtqueue_push(vq, elem, sizeof(status));
virtio_notify(vdev, vq);
g_free(iov2);
+ g_free(elem);
}
}
@@ -949,7 +1024,10 @@ static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
void *wbuf = (void *)buf;
work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
size - n->host_hdr_len);
- virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf);
+
+ if (n->needs_vnet_hdr_swap) {
+ virtio_net_hdr_swap(VIRTIO_DEVICE(n), wbuf);
+ }
iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
} else {
struct virtio_net_hdr hdr = {
@@ -1036,13 +1114,14 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
offset = i = 0;
while (offset < size) {
- VirtQueueElement elem;
+ VirtQueueElement *elem;
int len, total;
- const struct iovec *sg = elem.in_sg;
+ const struct iovec *sg;
total = 0;
- if (virtqueue_pop(q->rx_vq, &elem) == 0) {
+ elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement));
+ if (!elem) {
if (i == 0)
return -1;
error_report("virtio-net unexpected empty queue: "
@@ -1055,21 +1134,22 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
exit(1);
}
- if (elem.in_num < 1) {
+ if (elem->in_num < 1) {
error_report("virtio-net receive queue contains no in buffers");
exit(1);
}
+ sg = elem->in_sg;
if (i == 0) {
assert(offset == 0);
if (n->mergeable_rx_bufs) {
mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
- sg, elem.in_num,
+ sg, elem->in_num,
offsetof(typeof(mhdr), num_buffers),
sizeof(mhdr.num_buffers));
}
- receive_header(n, sg, elem.in_num, buf, size);
+ receive_header(n, sg, elem->in_num, buf, size);
offset = n->host_hdr_len;
total += n->guest_hdr_len;
guest_offset = n->guest_hdr_len;
@@ -1078,7 +1158,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
}
/* copy in packet. ugh */
- len = iov_from_buf(sg, elem.in_num, guest_offset,
+ len = iov_from_buf(sg, elem->in_num, guest_offset,
buf + offset, size - offset);
total += len;
offset += len;
@@ -1086,18 +1166,14 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
* must have consumed the complete packet.
* Otherwise, drop it. */
if (!n->mergeable_rx_bufs && offset < size) {
-#if 0
- error_report("virtio-net truncated non-mergeable packet: "
- "i %zd mergeable %d offset %zd, size %zd, "
- "guest hdr len %zd, host hdr len %zd",
- i, n->mergeable_rx_bufs,
- offset, size, n->guest_hdr_len, n->host_hdr_len);
-#endif
+ virtqueue_discard(q->rx_vq, elem, total);
+ g_free(elem);
return size;
}
/* signal other side */
- virtqueue_fill(q->rx_vq, &elem, total, i++);
+ virtqueue_fill(q->rx_vq, elem, total, i++);
+ g_free(elem);
}
if (mhdr_cnt) {
@@ -1121,10 +1197,11 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
VirtIONetQueue *q = virtio_net_get_subqueue(nc);
VirtIODevice *vdev = VIRTIO_DEVICE(n);
- virtqueue_push(q->tx_vq, &q->async_tx.elem, 0);
+ virtqueue_push(q->tx_vq, q->async_tx.elem, 0);
virtio_notify(vdev, q->tx_vq);
- q->async_tx.elem.out_num = q->async_tx.len = 0;
+ g_free(q->async_tx.elem);
+ q->async_tx.elem = NULL;
virtio_queue_set_notification(q->tx_vq, 1);
virtio_net_flush_tx(q);
@@ -1135,25 +1212,31 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
{
VirtIONet *n = q->n;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
- VirtQueueElement elem;
+ VirtQueueElement *elem;
int32_t num_packets = 0;
int queue_index = vq2q(virtio_get_queue_index(q->tx_vq));
if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
return num_packets;
}
- if (q->async_tx.elem.out_num) {
+ if (q->async_tx.elem) {
virtio_queue_set_notification(q->tx_vq, 0);
return num_packets;
}
- while (virtqueue_pop(q->tx_vq, &elem)) {
- ssize_t ret, len;
- unsigned int out_num = elem.out_num;
- struct iovec *out_sg = &elem.out_sg[0];
- struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1];
+ for (;;) {
+ ssize_t ret;
+ unsigned int out_num;
+ struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg;
struct virtio_net_hdr_mrg_rxbuf mhdr;
+ elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement));
+ if (!elem) {
+ break;
+ }
+
+ out_num = elem->out_num;
+ out_sg = elem->out_sg;
if (out_num < 1) {
error_report("virtio-net header not in first element");
exit(1);
@@ -1165,7 +1248,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
error_report("virtio-net header incorrect");
exit(1);
}
- if (virtio_needs_swap(vdev)) {
+ if (n->needs_vnet_hdr_swap) {
virtio_net_hdr_swap(vdev, (void *) &mhdr);
sg2[0].iov_base = &mhdr;
sg2[0].iov_len = n->guest_hdr_len;
@@ -1196,21 +1279,18 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
out_sg = sg;
}
- len = n->guest_hdr_len;
-
ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index),
out_sg, out_num, virtio_net_tx_complete);
if (ret == 0) {
virtio_queue_set_notification(q->tx_vq, 0);
q->async_tx.elem = elem;
- q->async_tx.len = len;
return -EBUSY;
}
- len += ret;
drop:
- virtqueue_push(q->tx_vq, &elem, 0);
+ virtqueue_push(q->tx_vq, elem, 0);
virtio_notify(vdev, q->tx_vq);
+ g_free(elem);
if (++num_packets >= n->tx_burst) {
break;
@@ -1453,7 +1533,7 @@ static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f)
}
}
- if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
+ if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
qemu_put_be64(f, n->curr_guest_offloads);
}
}
@@ -1462,11 +1542,33 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
{
VirtIONet *n = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(n);
+ int ret;
if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
return -EINVAL;
- return virtio_load(vdev, f, version_id);
+ ret = virtio_load(vdev, f, version_id);
+ if (ret) {
+ return ret;
+ }
+
+ if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
+ n->curr_guest_offloads = qemu_get_be64(f);
+ } else {
+ n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
+ }
+
+ if (peer_has_vnet_hdr(n)) {
+ virtio_net_apply_guest_offloads(n);
+ }
+
+ if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
+ virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
+ n->announce_counter = SELF_ANNOUNCE_ROUNDS;
+ timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL));
+ }
+
+ return 0;
}
static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
@@ -1479,7 +1581,8 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
n->vqs[0].tx_waiting = qemu_get_be32(f);
virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f),
- virtio_has_feature(vdev, VIRTIO_F_VERSION_1));
+ virtio_vdev_has_feature(vdev,
+ VIRTIO_F_VERSION_1));
if (version_id >= 3)
n->status = qemu_get_be16(f);
@@ -1562,16 +1665,6 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
}
}
- if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
- n->curr_guest_offloads = qemu_get_be64(f);
- } else {
- n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
- }
-
- if (peer_has_vnet_hdr(n)) {
- virtio_net_apply_guest_offloads(n);
- }
-
virtio_net_set_queues(n);
/* Find the first multicast entry in the saved MAC filter */
@@ -1589,12 +1682,6 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
qemu_get_subqueue(n->nic, i)->link_down = link_down;
}
- if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
- virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
- n->announce_counter = SELF_ANNOUNCE_ROUNDS;
- timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL));
- }
-
return 0;
}
diff --git a/qemu/hw/net/vmware_utils.h b/qemu/hw/net/vmware_utils.h
index 1099df669..c0dbb2ff4 100644
--- a/qemu/hw/net/vmware_utils.h
+++ b/qemu/hw/net/vmware_utils.h
@@ -18,10 +18,7 @@
#define VMWARE_UTILS_H
#include "qemu/range.h"
-
-#ifndef VMW_SHPRN
-#define VMW_SHPRN(fmt, ...) do {} while (0)
-#endif
+#include "vmxnet_debug.h"
/*
* Shared memory access functions with byte swap support
@@ -52,7 +49,7 @@ vmw_shmem_rw(hwaddr addr, void *buf, int len, int is_write)
}
static inline void
-vmw_shmem_set(hwaddr addr, uint8 val, int len)
+vmw_shmem_set(hwaddr addr, uint8_t val, int len)
{
int i;
VMW_SHPRN("SHMEM set: %" PRIx64 ", len: %d (value 0x%X)", addr, len, val);
diff --git a/qemu/hw/net/vmxnet3.c b/qemu/hw/net/vmxnet3.c
index 59b06b841..093a71e12 100644
--- a/qemu/hw/net/vmxnet3.c
+++ b/qemu/hw/net/vmxnet3.c
@@ -15,6 +15,7 @@
*
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
#include "net/net.h"
@@ -36,12 +37,28 @@
#define VMXNET3_MSIX_BAR_SIZE 0x2000
#define MIN_BUF_SIZE 60
+/* Compatability flags for migration */
+#define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT 0
+#define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS \
+ (1 << VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT)
+#define VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT 1
+#define VMXNET3_COMPAT_FLAG_DISABLE_PCIE \
+ (1 << VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT)
+
+#define VMXNET3_EXP_EP_OFFSET (0x48)
+#define VMXNET3_MSI_OFFSET(s) \
+ ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x50 : 0x84)
+#define VMXNET3_MSIX_OFFSET(s) \
+ ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0 : 0x9c)
+#define VMXNET3_DSN_OFFSET (0x100)
+
#define VMXNET3_BAR0_IDX (0)
#define VMXNET3_BAR1_IDX (1)
#define VMXNET3_MSIX_BAR_IDX (2)
#define VMXNET3_OFF_MSIX_TABLE (0x000)
-#define VMXNET3_OFF_MSIX_PBA (0x800)
+#define VMXNET3_OFF_MSIX_PBA(s) \
+ ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x800 : 0x1000)
/* Link speed in Mbps should be shifted by 16 */
#define VMXNET3_LINK_SPEED (1000 << 16)
@@ -50,7 +67,7 @@
#define VMXNET3_LINK_STATUS_UP 0x1
/* Least significant bit should be set for revision and version */
-#define VMXNET3_DEVICE_VERSION 0x1
+#define VMXNET3_UPT_REVISION 0x1
#define VMXNET3_DEVICE_REVISION 0x1
/* Number of interrupt vectors for non-MSIx modes */
@@ -108,9 +125,19 @@
#define VMXNET_FLAG_IS_SET(field, flag) (((field) & (flag)) == (flag))
+typedef struct VMXNET3Class {
+ PCIDeviceClass parent_class;
+ DeviceRealize parent_dc_realize;
+} VMXNET3Class;
+
#define TYPE_VMXNET3 "vmxnet3"
#define VMXNET3(obj) OBJECT_CHECK(VMXNET3State, (obj), TYPE_VMXNET3)
+#define VMXNET3_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VMXNET3Class, (klass), TYPE_VMXNET3)
+#define VMXNET3_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VMXNET3Class, (obj), TYPE_VMXNET3)
+
/* Cyclic ring abstraction */
typedef struct {
hwaddr pa;
@@ -138,7 +165,7 @@ static inline void vmxnet3_ring_init(Vmxnet3Ring *ring,
}
#define VMXNET3_RING_DUMP(macro, ring_name, ridx, r) \
- macro("%s#%d: base %" PRIx64 " size %lu cell_size %lu gen %d next %lu", \
+ macro("%s#%d: base %" PRIx64 " size %zu cell_size %zu gen %d next %zu", \
(ring_name), (ridx), \
(r)->pa, (r)->size, (r)->cell_size, (r)->gen, (r)->next)
@@ -313,6 +340,9 @@ typedef struct {
MACAddr *mcast_list;
uint32_t mcast_list_len;
uint32_t mcast_list_buff_size; /* needed for live migration. */
+
+ /* Compatability flags for migration */
+ uint32_t compat_flags;
} VMXNET3State;
/* Interrupt management */
@@ -493,7 +523,7 @@ vmxnet3_dec_rx_completion_counter(VMXNET3State *s, int qidx)
vmxnet3_ring_dec(&s->rxq_descr[qidx].comp_ring);
}
-static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32 tx_ridx)
+static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32_t tx_ridx)
{
struct Vmxnet3_TxCompDesc txcq_descr;
@@ -729,9 +759,7 @@ static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx)
}
if (txd.eop) {
- if (!s->skip_current_tx_pkt) {
- vmxnet_tx_pkt_parse(s->tx_pkt);
-
+ if (!s->skip_current_tx_pkt && vmxnet_tx_pkt_parse(s->tx_pkt)) {
if (s->needs_vlan) {
vmxnet_tx_pkt_setup_vlan_header(s->tx_pkt, s->tci);
}
@@ -927,9 +955,9 @@ static void vmxnet3_rx_need_csum_calculate(struct VmxnetRxPkt *pkt,
/* Validate packet len: csum_start + scum_offset + length of csum field */
if (pkt_len < (vhdr->csum_start + vhdr->csum_offset + 2)) {
- VMW_PKPRN("packet len:%d < csum_start(%d) + csum_offset(%d) + 2, "
+ VMW_PKPRN("packet len:%zu < csum_start(%d) + csum_offset(%d) + 2, "
"cannot calculate checksum",
- len, vhdr->csum_start, vhdr->csum_offset);
+ pkt_len, vhdr->csum_start, vhdr->csum_offset);
return;
}
@@ -1165,9 +1193,13 @@ vmxnet3_io_bar0_write(void *opaque, hwaddr addr,
static uint64_t
vmxnet3_io_bar0_read(void *opaque, hwaddr addr, unsigned size)
{
+ VMXNET3State *s = opaque;
+
if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_IMR,
VMXNET3_MAX_INTRS, VMXNET3_REG_ALIGN)) {
- g_assert_not_reached();
+ int l = VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_IMR,
+ VMXNET3_REG_ALIGN);
+ return s->interrupt_states[l].is_masked;
}
VMW_CBPRN("BAR0 unknown read [%" PRIx64 "], size %d", addr, size);
@@ -1192,8 +1224,13 @@ static void vmxnet3_reset_mac(VMXNET3State *s)
static void vmxnet3_deactivate_device(VMXNET3State *s)
{
- VMW_CBPRN("Deactivating vmxnet3...");
- s->device_active = false;
+ if (s->device_active) {
+ VMW_CBPRN("Deactivating vmxnet3...");
+ vmxnet_tx_pkt_reset(s->tx_pkt);
+ vmxnet_tx_pkt_uninit(s->tx_pkt);
+ vmxnet_rx_pkt_uninit(s->rx_pkt);
+ s->device_active = false;
+ }
}
static void vmxnet3_reset(VMXNET3State *s)
@@ -1202,7 +1239,6 @@ static void vmxnet3_reset(VMXNET3State *s)
vmxnet3_deactivate_device(s);
vmxnet3_reset_interrupt_states(s);
- vmxnet_tx_pkt_reset(s->tx_pkt);
s->drv_shmem = 0;
s->tx_sop = true;
s->skip_current_tx_pkt = false;
@@ -1287,6 +1323,10 @@ static uint32_t vmxnet3_get_interrupt_config(VMXNET3State *s)
static void vmxnet3_fill_stats(VMXNET3State *s)
{
int i;
+
+ if (!s->device_active)
+ return;
+
for (i = 0; i < s->txq_num; i++) {
cpu_physical_memory_write(s->txq_descr[i].tx_stats_pa,
&s->txq_descr[i].txq_stats,
@@ -1425,6 +1465,12 @@ static void vmxnet3_activate_device(VMXNET3State *s)
return;
}
+ /* Verify if device is active */
+ if (s->device_active) {
+ VMW_CFPRN("Vmxnet3 device is active");
+ return;
+ }
+
vmxnet3_adjust_by_guest_type(s);
vmxnet3_update_features(s);
vmxnet3_update_pm_state(s);
@@ -1621,7 +1667,7 @@ static void vmxnet3_handle_command(VMXNET3State *s, uint64_t cmd)
break;
case VMXNET3_CMD_QUIESCE_DEV:
- VMW_CBPRN("Set: VMXNET3_CMD_QUIESCE_DEV - pause the device");
+ VMW_CBPRN("Set: VMXNET3_CMD_QUIESCE_DEV - deactivate the device");
vmxnet3_deactivate_device(s);
break;
@@ -1629,6 +1675,23 @@ static void vmxnet3_handle_command(VMXNET3State *s, uint64_t cmd)
VMW_CBPRN("Set: VMXNET3_CMD_GET_CONF_INTR - interrupt configuration");
break;
+ case VMXNET3_CMD_GET_ADAPTIVE_RING_INFO:
+ VMW_CBPRN("Set: VMXNET3_CMD_GET_ADAPTIVE_RING_INFO - "
+ "adaptive ring info flags");
+ break;
+
+ case VMXNET3_CMD_GET_DID_LO:
+ VMW_CBPRN("Set: Get lower part of device ID");
+ break;
+
+ case VMXNET3_CMD_GET_DID_HI:
+ VMW_CBPRN("Set: Get upper part of device ID");
+ break;
+
+ case VMXNET3_CMD_GET_DEV_EXTRA_INFO:
+ VMW_CBPRN("Set: Get device extra info");
+ break;
+
default:
VMW_CBPRN("Received unknown command: %" PRIx64, cmd);
break;
@@ -1641,13 +1704,14 @@ static uint64_t vmxnet3_get_command_status(VMXNET3State *s)
switch (s->last_command) {
case VMXNET3_CMD_ACTIVATE_DEV:
- ret = (s->device_active) ? 0 : -1;
+ ret = (s->device_active) ? 0 : 1;
VMW_CFPRN("Device active: %" PRIx64, ret);
break;
case VMXNET3_CMD_RESET_DEV:
case VMXNET3_CMD_QUIESCE_DEV:
case VMXNET3_CMD_GET_QUEUE_STATUS:
+ case VMXNET3_CMD_GET_DEV_EXTRA_INFO:
ret = 0;
break;
@@ -1668,9 +1732,21 @@ static uint64_t vmxnet3_get_command_status(VMXNET3State *s)
ret = vmxnet3_get_interrupt_config(s);
break;
+ case VMXNET3_CMD_GET_ADAPTIVE_RING_INFO:
+ ret = VMXNET3_DISABLE_ADAPTIVE_RING;
+ break;
+
+ case VMXNET3_CMD_GET_DID_LO:
+ ret = PCI_DEVICE_ID_VMWARE_VMXNET3;
+ break;
+
+ case VMXNET3_CMD_GET_DID_HI:
+ ret = VMXNET3_DEVICE_REVISION;
+ break;
+
default:
VMW_WRPRN("Received request for unknown command: %x", s->last_command);
- ret = -1;
+ ret = 0;
break;
}
@@ -1726,7 +1802,7 @@ vmxnet3_io_bar1_write(void *opaque,
* shared address only after we get the high part
*/
if (val == 0) {
- s->device_active = false;
+ vmxnet3_deactivate_device(s);
}
s->temp_shared_guest_driver_memory = val;
s->drv_shmem = 0;
@@ -1801,7 +1877,7 @@ vmxnet3_io_bar1_read(void *opaque, hwaddr addr, unsigned size)
/* UPT Version Report Selection */
case VMXNET3_REG_UVRS:
VMW_CBPRN("Read BAR1 [VMXNET3_REG_UVRS], size %d", size);
- ret = VMXNET3_DEVICE_VERSION;
+ ret = VMXNET3_UPT_REVISION;
break;
/* Command */
@@ -1959,7 +2035,7 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
vmxnet_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping);
bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1;
if (bytes_indicated < size) {
- VMW_PKPRN("RX: %lu of %lu bytes indicated", bytes_indicated, size);
+ VMW_PKPRN("RX: %zu of %zu bytes indicated", bytes_indicated, size);
}
} else {
VMW_PKPRN("Packet dropped by RX filter");
@@ -1988,7 +2064,6 @@ static void vmxnet3_set_link_status(NetClientState *nc)
static NetClientInfo net_vmxnet3_info = {
.type = NET_CLIENT_OPTIONS_KIND_NIC,
.size = sizeof(NICState),
- .can_receive = vmxnet3_can_receive,
.receive = vmxnet3_receive,
.link_status_changed = vmxnet3_set_link_status,
};
@@ -2001,16 +2076,13 @@ static bool vmxnet3_peer_has_vnet_hdr(VMXNET3State *s)
return true;
}
- VMW_WRPRN("Peer has no virtio extension. Task offloads will be emulated.");
return false;
}
static void vmxnet3_net_uninit(VMXNET3State *s)
{
g_free(s->mcast_list);
- vmxnet_tx_pkt_reset(s->tx_pkt);
- vmxnet_tx_pkt_uninit(s->tx_pkt);
- vmxnet_rx_pkt_uninit(s->rx_pkt);
+ vmxnet3_deactivate_device(s);
qemu_del_nic(s->nic);
}
@@ -2030,7 +2102,7 @@ static void vmxnet3_net_init(VMXNET3State *s)
s->link_status_and_speed = VMXNET3_LINK_SPEED | VMXNET3_LINK_STATUS_UP;
- VMW_CFPRN("Permanent MAC: " MAC_FMT, MAC_ARG(s->perm_mac.a));
+ VMW_CFPRN("Permanent MAC: " VMXNET_MF, VMXNET_MA(s->perm_mac.a));
s->nic = qemu_new_nic(&net_vmxnet3_info, &s->conf,
object_get_typename(OBJECT(s)),
@@ -2088,8 +2160,8 @@ vmxnet3_init_msix(VMXNET3State *s)
&s->msix_bar,
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
&s->msix_bar,
- VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA,
- 0);
+ VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s),
+ VMXNET3_MSIX_OFFSET(s));
if (0 > res) {
VMW_WRPRN("Failed to initialize MSI-X, error %d", res);
@@ -2117,7 +2189,6 @@ vmxnet3_cleanup_msix(VMXNET3State *s)
}
}
-#define VMXNET3_MSI_OFFSET (0x50)
#define VMXNET3_USE_64BIT (true)
#define VMXNET3_PER_VECTOR_MASK (false)
@@ -2127,7 +2198,7 @@ vmxnet3_init_msi(VMXNET3State *s)
PCIDevice *d = PCI_DEVICE(s);
int res;
- res = msi_init(d, VMXNET3_MSI_OFFSET, VMXNET3_MAX_NMSIX_INTRS,
+ res = msi_init(d, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS,
VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK);
if (0 > res) {
VMW_WRPRN("Failed to initialize MSI, error %d", res);
@@ -2184,6 +2255,22 @@ static const MemoryRegionOps b1_ops = {
},
};
+static uint8_t *vmxnet3_device_serial_num(VMXNET3State *s)
+{
+ static uint64_t dsn_payload;
+ uint8_t *dsnp = (uint8_t *)&dsn_payload;
+
+ dsnp[0] = 0xfe;
+ dsnp[1] = s->conf.macaddr.a[3];
+ dsnp[2] = s->conf.macaddr.a[4];
+ dsnp[3] = s->conf.macaddr.a[5];
+ dsnp[4] = s->conf.macaddr.a[0];
+ dsnp[5] = s->conf.macaddr.a[1];
+ dsnp[6] = s->conf.macaddr.a[2];
+ dsnp[7] = 0xff;
+ return dsnp;
+}
+
static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp)
{
DeviceState *dev = DEVICE(pci_dev);
@@ -2221,6 +2308,17 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp)
vmxnet3_net_init(s);
+ if (pci_is_express(pci_dev)) {
+ if (pci_bus_is_express(pci_dev->bus)) {
+ pcie_endpoint_cap_init(pci_dev, VMXNET3_EXP_EP_OFFSET);
+ }
+
+ pcie_add_capability(pci_dev, PCI_EXT_CAP_ID_DSN, 0x1,
+ VMXNET3_DSN_OFFSET, PCI_EXT_CAP_DSN_SIZEOF);
+ memcpy(pci_dev->config + VMXNET3_DSN_OFFSET + 4,
+ vmxnet3_device_serial_num(s), sizeof(uint64_t));
+ }
+
register_savevm(dev, "vmxnet3-msix", -1, 1,
vmxnet3_msix_save, vmxnet3_msix_load, s);
}
@@ -2490,6 +2588,29 @@ static const VMStateInfo int_state_info = {
.put = vmxnet3_put_int_state
};
+static bool vmxnet3_vmstate_need_pcie_device(void *opaque)
+{
+ VMXNET3State *s = VMXNET3(opaque);
+
+ return !(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE);
+}
+
+static bool vmxnet3_vmstate_test_pci_device(void *opaque, int version_id)
+{
+ return !vmxnet3_vmstate_need_pcie_device(opaque);
+}
+
+static const VMStateDescription vmstate_vmxnet3_pcie_device = {
+ .name = "vmxnet3/pcie",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = vmxnet3_vmstate_need_pcie_device,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCIE_DEVICE(parent_obj, VMXNET3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_vmxnet3 = {
.name = "vmxnet3",
.version_id = 1,
@@ -2497,7 +2618,9 @@ static const VMStateDescription vmstate_vmxnet3 = {
.pre_save = vmxnet3_pre_save,
.post_load = vmxnet3_post_load,
.fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State),
+ VMSTATE_STRUCT_TEST(parent_obj, VMXNET3State,
+ vmxnet3_vmstate_test_pci_device, 0,
+ vmstate_pci_device, PCIDevice),
VMSTATE_BOOL(rx_packets_compound, VMXNET3State),
VMSTATE_BOOL(rx_vlan_stripping, VMXNET3State),
VMSTATE_BOOL(lro_supported, VMXNET3State),
@@ -2532,19 +2655,38 @@ static const VMStateDescription vmstate_vmxnet3 = {
},
.subsections = (const VMStateDescription*[]) {
&vmxstate_vmxnet3_mcast_list,
+ &vmstate_vmxnet3_pcie_device,
NULL
}
};
static Property vmxnet3_properties[] = {
DEFINE_NIC_PROPERTIES(VMXNET3State, conf),
+ DEFINE_PROP_BIT("x-old-msi-offsets", VMXNET3State, compat_flags,
+ VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT, false),
+ DEFINE_PROP_BIT("x-disable-pcie", VMXNET3State, compat_flags,
+ VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT, false),
DEFINE_PROP_END_OF_LIST(),
};
+static void vmxnet3_realize(DeviceState *qdev, Error **errp)
+{
+ VMXNET3Class *vc = VMXNET3_DEVICE_GET_CLASS(qdev);
+ PCIDevice *pci_dev = PCI_DEVICE(qdev);
+ VMXNET3State *s = VMXNET3(qdev);
+
+ if (!(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE)) {
+ pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
+ }
+
+ vc->parent_dc_realize(qdev, errp);
+}
+
static void vmxnet3_class_init(ObjectClass *class, void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
+ VMXNET3Class *vc = VMXNET3_DEVICE_CLASS(class);
c->realize = vmxnet3_pci_realize;
c->exit = vmxnet3_pci_uninit;
@@ -2554,6 +2696,8 @@ static void vmxnet3_class_init(ObjectClass *class, void *data)
c->class_id = PCI_CLASS_NETWORK_ETHERNET;
c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3;
+ vc->parent_dc_realize = dc->realize;
+ dc->realize = vmxnet3_realize;
dc->desc = "VMWare Paravirtualized Ethernet v3";
dc->reset = vmxnet3_qdev_reset;
dc->vmsd = &vmstate_vmxnet3;
@@ -2564,6 +2708,7 @@ static void vmxnet3_class_init(ObjectClass *class, void *data)
static const TypeInfo vmxnet3_info = {
.name = TYPE_VMXNET3,
.parent = TYPE_PCI_DEVICE,
+ .class_size = sizeof(VMXNET3Class),
.instance_size = sizeof(VMXNET3State),
.class_init = vmxnet3_class_init,
.instance_init = vmxnet3_instance_init,
diff --git a/qemu/hw/net/vmxnet3.h b/qemu/hw/net/vmxnet3.h
index f987d7126..f7006afe9 100644
--- a/qemu/hw/net/vmxnet3.h
+++ b/qemu/hw/net/vmxnet3.h
@@ -198,9 +198,13 @@ enum {
VMXNET3_CMD_GET_DID_LO, /* 0xF00D0005 */
VMXNET3_CMD_GET_DID_HI, /* 0xF00D0006 */
VMXNET3_CMD_GET_DEV_EXTRA_INFO, /* 0xF00D0007 */
- VMXNET3_CMD_GET_CONF_INTR /* 0xF00D0008 */
+ VMXNET3_CMD_GET_CONF_INTR, /* 0xF00D0008 */
+ VMXNET3_CMD_GET_ADAPTIVE_RING_INFO /* 0xF00D0009 */
};
+/* Adaptive Ring Info Flags */
+#define VMXNET3_DISABLE_ADAPTIVE_RING 1
+
/*
* Little Endian layout of bitfields -
* Byte 0 : 7.....len.....0
diff --git a/qemu/hw/net/vmxnet_debug.h b/qemu/hw/net/vmxnet_debug.h
index 96dae0f91..96495dbb1 100644
--- a/qemu/hw/net/vmxnet_debug.h
+++ b/qemu/hw/net/vmxnet_debug.h
@@ -20,94 +20,127 @@
#define VMXNET_DEVICE_NAME "vmxnet3"
-/* #define VMXNET_DEBUG_CB */
#define VMXNET_DEBUG_WARNINGS
#define VMXNET_DEBUG_ERRORS
-/* #define VMXNET_DEBUG_INTERRUPTS */
-/* #define VMXNET_DEBUG_CONFIG */
-/* #define VMXNET_DEBUG_RINGS */
-/* #define VMXNET_DEBUG_PACKETS */
-/* #define VMXNET_DEBUG_SHMEM_ACCESS */
+
+#undef VMXNET_DEBUG_CB
+#undef VMXNET_DEBUG_INTERRUPTS
+#undef VMXNET_DEBUG_CONFIG
+#undef VMXNET_DEBUG_RINGS
+#undef VMXNET_DEBUG_PACKETS
+#undef VMXNET_DEBUG_SHMEM_ACCESS
+
+#ifdef VMXNET_DEBUG_CB
+# define VMXNET_DEBUG_CB_ENABLED 1
+#else
+# define VMXNET_DEBUG_CB_ENABLED 0
+#endif
+
+#ifdef VMXNET_DEBUG_WARNINGS
+# define VMXNET_DEBUG_WARNINGS_ENABLED 1
+#else
+# define VMXNET_DEBUG_WARNINGS_ENABLED 0
+#endif
+
+#ifdef VMXNET_DEBUG_ERRORS
+# define VMXNET_DEBUG_ERRORS_ENABLED 1
+#else
+# define VMXNET_DEBUG_ERRORS_ENABLED 0
+#endif
+
+#ifdef VMXNET_DEBUG_CONFIG
+# define VMXNET_DEBUG_CONFIG_ENABLED 1
+#else
+# define VMXNET_DEBUG_CONFIG_ENABLED 0
+#endif
+
+#ifdef VMXNET_DEBUG_RINGS
+# define VMXNET_DEBUG_RINGS_ENABLED 1
+#else
+# define VMXNET_DEBUG_RINGS_ENABLED 0
+#endif
+
+#ifdef VMXNET_DEBUG_PACKETS
+# define VMXNET_DEBUG_PACKETS_ENABLED 1
+#else
+# define VMXNET_DEBUG_PACKETS_ENABLED 0
+#endif
+
+#ifdef VMXNET_DEBUG_INTERRUPTS
+# define VMXNET_DEBUG_INTERRUPTS_ENABLED 1
+#else
+# define VMXNET_DEBUG_INTERRUPTS_ENABLED 0
+#endif
#ifdef VMXNET_DEBUG_SHMEM_ACCESS
+# define VMXNET_DEBUG_SHMEM_ACCESS_ENABLED 1
+#else
+# define VMXNET_DEBUG_SHMEM_ACCESS_ENABLED 0
+#endif
+
#define VMW_SHPRN(fmt, ...) \
do { \
- printf("[%s][SH][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
+ if (VMXNET_DEBUG_SHMEM_ACCESS_ENABLED) { \
+ printf("[%s][SH][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
+ ## __VA_ARGS__); \
+ } \
} while (0)
-#else
-#define VMW_SHPRN(fmt, ...) do {} while (0)
-#endif
-#ifdef VMXNET_DEBUG_CB
#define VMW_CBPRN(fmt, ...) \
do { \
- printf("[%s][CB][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
+ if (VMXNET_DEBUG_CB_ENABLED) { \
+ printf("[%s][CB][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
+ ## __VA_ARGS__); \
+ } \
} while (0)
-#else
-#define VMW_CBPRN(fmt, ...) do {} while (0)
-#endif
-#ifdef VMXNET_DEBUG_PACKETS
#define VMW_PKPRN(fmt, ...) \
do { \
- printf("[%s][PK][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
+ if (VMXNET_DEBUG_PACKETS_ENABLED) { \
+ printf("[%s][PK][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
+ ## __VA_ARGS__); \
+ } \
} while (0)
-#else
-#define VMW_PKPRN(fmt, ...) do {} while (0)
-#endif
-#ifdef VMXNET_DEBUG_WARNINGS
#define VMW_WRPRN(fmt, ...) \
do { \
- printf("[%s][WR][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
+ if (VMXNET_DEBUG_WARNINGS_ENABLED) { \
+ printf("[%s][WR][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
+ ## __VA_ARGS__); \
+ } \
} while (0)
-#else
-#define VMW_WRPRN(fmt, ...) do {} while (0)
-#endif
-#ifdef VMXNET_DEBUG_ERRORS
#define VMW_ERPRN(fmt, ...) \
do { \
- printf("[%s][ER][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
+ if (VMXNET_DEBUG_ERRORS_ENABLED) { \
+ printf("[%s][ER][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
+ ## __VA_ARGS__); \
+ } \
} while (0)
-#else
-#define VMW_ERPRN(fmt, ...) do {} while (0)
-#endif
-#ifdef VMXNET_DEBUG_INTERRUPTS
#define VMW_IRPRN(fmt, ...) \
do { \
- printf("[%s][IR][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
+ if (VMXNET_DEBUG_INTERRUPTS_ENABLED) { \
+ printf("[%s][IR][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
+ ## __VA_ARGS__); \
+ } \
} while (0)
-#else
-#define VMW_IRPRN(fmt, ...) do {} while (0)
-#endif
-#ifdef VMXNET_DEBUG_CONFIG
#define VMW_CFPRN(fmt, ...) \
do { \
- printf("[%s][CF][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
+ if (VMXNET_DEBUG_CONFIG_ENABLED) { \
+ printf("[%s][CF][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
+ ## __VA_ARGS__); \
+ } \
} while (0)
-#else
-#define VMW_CFPRN(fmt, ...) do {} while (0)
-#endif
-#ifdef VMXNET_DEBUG_RINGS
#define VMW_RIPRN(fmt, ...) \
do { \
- printf("[%s][RI][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
- ## __VA_ARGS__); \
+ if (VMXNET_DEBUG_RINGS_ENABLED) { \
+ printf("[%s][RI][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__, \
+ ## __VA_ARGS__); \
+ } \
} while (0)
-#else
-#define VMW_RIPRN(fmt, ...) do {} while (0)
-#endif
#define VMXNET_MF "%02X:%02X:%02X:%02X:%02X:%02X"
#define VMXNET_MA(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
diff --git a/qemu/hw/net/vmxnet_rx_pkt.c b/qemu/hw/net/vmxnet_rx_pkt.c
index aa5462931..21bb46e68 100644
--- a/qemu/hw/net/vmxnet_rx_pkt.c
+++ b/qemu/hw/net/vmxnet_rx_pkt.c
@@ -15,6 +15,7 @@
*
*/
+#include "qemu/osdep.h"
#include "vmxnet_rx_pkt.h"
#include "net/eth.h"
#include "qemu-common.h"
diff --git a/qemu/hw/net/vmxnet_rx_pkt.h b/qemu/hw/net/vmxnet_rx_pkt.h
index a425846b5..0a45c1ba0 100644
--- a/qemu/hw/net/vmxnet_rx_pkt.h
+++ b/qemu/hw/net/vmxnet_rx_pkt.h
@@ -18,8 +18,6 @@
#ifndef VMXNET_RX_PKT_H
#define VMXNET_RX_PKT_H
-#include "stdint.h"
-#include "stdbool.h"
#include "net/eth.h"
/* defines to enable packet dump functions */
diff --git a/qemu/hw/net/vmxnet_tx_pkt.c b/qemu/hw/net/vmxnet_tx_pkt.c
index f7344c4cb..91e1e08fd 100644
--- a/qemu/hw/net/vmxnet_tx_pkt.c
+++ b/qemu/hw/net/vmxnet_tx_pkt.c
@@ -15,6 +15,7 @@
*
*/
+#include "qemu/osdep.h"
#include "hw/hw.h"
#include "vmxnet_tx_pkt.h"
#include "net/eth.h"
@@ -142,11 +143,24 @@ static bool vmxnet_tx_pkt_parse_headers(struct VmxnetTxPkt *pkt)
bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, 0, l2_hdr->iov_base,
ETH_MAX_L2_HDR_LEN);
- if (bytes_read < ETH_MAX_L2_HDR_LEN) {
+ if (bytes_read < sizeof(struct eth_header)) {
+ l2_hdr->iov_len = 0;
+ return false;
+ }
+
+ l2_hdr->iov_len = sizeof(struct eth_header);
+ switch (be16_to_cpu(PKT_GET_ETH_HDR(l2_hdr->iov_base)->h_proto)) {
+ case ETH_P_VLAN:
+ l2_hdr->iov_len += sizeof(struct vlan_header);
+ break;
+ case ETH_P_DVLAN:
+ l2_hdr->iov_len += 2 * sizeof(struct vlan_header);
+ break;
+ }
+
+ if (bytes_read < l2_hdr->iov_len) {
l2_hdr->iov_len = 0;
return false;
- } else {
- l2_hdr->iov_len = eth_get_l2_hdr_length(l2_hdr->iov_base);
}
l3_proto = eth_get_l3_proto(l2_hdr->iov_base, l2_hdr->iov_len);
diff --git a/qemu/hw/net/vmxnet_tx_pkt.h b/qemu/hw/net/vmxnet_tx_pkt.h
index 57121a6fe..f51e98ad9 100644
--- a/qemu/hw/net/vmxnet_tx_pkt.h
+++ b/qemu/hw/net/vmxnet_tx_pkt.h
@@ -18,8 +18,6 @@
#ifndef VMXNET_TX_PKT_H
#define VMXNET_TX_PKT_H
-#include "stdint.h"
-#include "stdbool.h"
#include "net/eth.h"
#include "exec/hwaddr.h"
diff --git a/qemu/hw/net/xen_nic.c b/qemu/hw/net/xen_nic.c
index d7cbfc103..7281730d9 100644
--- a/qemu/hw/net/xen_nic.c
+++ b/qemu/hw/net/xen_nic.c
@@ -19,19 +19,9 @@
* GNU GPL, version 2 or (at your option) any later version.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <inttypes.h>
-#include <fcntl.h>
-#include <errno.h>
+#include "qemu/osdep.h"
#include <sys/socket.h>
#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/wait.h>
@@ -169,7 +159,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
(txreq.flags & NETTXF_more_data) ? " more_data" : "",
(txreq.flags & NETTXF_extra_info) ? " extra_info" : "");
- page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ page = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
netdev->xendev.dom,
txreq.gref, PROT_READ);
if (page == NULL) {
@@ -191,7 +181,7 @@ static void net_tx_packets(struct XenNetDev *netdev)
qemu_send_packet(qemu_get_queue(netdev->nic),
page + txreq.offset, txreq.size);
}
- xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+ xengnttab_unmap(netdev->xendev.gnttabdev, page, 1);
net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
}
if (!netdev->tx_work) {
@@ -261,7 +251,7 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
netdev->rx_ring.req_cons = ++rc;
- page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ page = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
netdev->xendev.dom,
rxreq.gref, PROT_WRITE);
if (page == NULL) {
@@ -271,7 +261,7 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
return -1;
}
memcpy(page + NET_IP_ALIGN, buf, size);
- xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+ xengnttab_unmap(netdev->xendev.gnttabdev, page, 1);
net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
return size;
@@ -343,19 +333,19 @@ static int net_connect(struct XenDevice *xendev)
return -1;
}
- netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ netdev->txs = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
netdev->xendev.dom,
netdev->tx_ring_ref,
PROT_READ | PROT_WRITE);
if (!netdev->txs) {
return -1;
}
- netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ netdev->rxs = xengnttab_map_grant_ref(netdev->xendev.gnttabdev,
netdev->xendev.dom,
netdev->rx_ring_ref,
PROT_READ | PROT_WRITE);
if (!netdev->rxs) {
- xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+ xengnttab_unmap(netdev->xendev.gnttabdev, netdev->txs, 1);
netdev->txs = NULL;
return -1;
}
@@ -380,11 +370,11 @@ static void net_disconnect(struct XenDevice *xendev)
xen_be_unbind_evtchn(&netdev->xendev);
if (netdev->txs) {
- xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+ xengnttab_unmap(netdev->xendev.gnttabdev, netdev->txs, 1);
netdev->txs = NULL;
}
if (netdev->rxs) {
- xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
+ xengnttab_unmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
netdev->rxs = NULL;
}
}
diff --git a/qemu/hw/net/xgmac.c b/qemu/hw/net/xgmac.c
index 15fb68194..0c5f793bd 100644
--- a/qemu/hw/net/xgmac.c
+++ b/qemu/hw/net/xgmac.c
@@ -24,6 +24,7 @@
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "sysemu/char.h"
#include "qemu/log.h"
diff --git a/qemu/hw/net/xilinx_axienet.c b/qemu/hw/net/xilinx_axienet.c
index d63c42324..de23ab5dc 100644
--- a/qemu/hw/net/xilinx_axienet.c
+++ b/qemu/hw/net/xilinx_axienet.c
@@ -22,7 +22,9 @@
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
+#include "qapi/error.h"
#include "qemu/log.h"
#include "net/net.h"
#include "net/checksum.h"
diff --git a/qemu/hw/net/xilinx_ethlite.c b/qemu/hw/net/xilinx_ethlite.c
index ad6b55306..bc846e709 100644
--- a/qemu/hw/net/xilinx_ethlite.c
+++ b/qemu/hw/net/xilinx_ethlite.c
@@ -22,6 +22,9 @@
* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h" /* FIXME should not use tswap* */
#include "hw/sysbus.h"
#include "hw/hw.h"
#include "net/net.h"