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

Version: GnuPG v1
 
 iQEcBAABAgAGBQJeg0JmAAoJEO8Ells5jWIRriwIAIJP3RSeSZpipxXoI8aIVOHv
 mkteuLqJpid0+wwpmT+YAv6PpniJ76Rwrc54VsOKBURG/baJAoGR5ozsu+dS/pF5
 VW9rFarR6FyRcLJWA/I4q3C9rhzcNwhoA2l0Jwy0sXQFYegsptb2Qc+Mr+Fw1hGZ
 mnIB7g4wXZc0NuGY+SAuQdlS0HvIgf8Lbv8z1i0vO2h1ADTFIjhrrnbsZ2//Nttu
 YwFh4IZJzirZ7VqRbfqo0fK6yElAA3EI6VjkPospuxOT6XcNp4ODEMMfeEl2qSa/
 TSVCnCXBXaoX8HPdVfdb3zK4GA11wITDkF+uv9Nx0/AUYJSsOgMkqItHoQr24uQ=
 =Kh21
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging

# gpg: Signature made Tue 31 Mar 2020 14:15:18 BST
# gpg:                using RSA key EF04965B398D6211
# gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [marginal]
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 215D 46F4 8246 689E C77F  3562 EF04 965B 398D 6211

* remotes/jasowang/tags/net-pull-request:
  qtest: add tulip test case
  hw/net/allwinner-sun8i-emac.c: Fix REG_ADDR_HIGH/LOW reads
  net: tulip: check frame size and r/w data length
  net/colo-compare.c: Expose "expired_scan_cycle" to users
  net/colo-compare.c: Expose "compare_timeout" to users
  hw/net/can: Make CanBusClientInfo::can_receive() return a boolean
  hw/net: Make NetCanReceive() return a boolean
  hw/net/rtl8139: Update coding style to make checkpatch.pl happy
  hw/net/rtl8139: Simplify if/else statement
  hw/net/smc91c111: Let smc91c111_can_receive() return a boolean
  hw/net/e1000e_core: Let e1000e_can_receive() return a boolean
  Fixed integer overflow in e1000e
  hw/net/i82596.c: Avoid reading off end of buffer in i82596_receive()
  hw/net/i82596: Correct command bitmask (CID 1419392)

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-03-31 14:49:46 +01:00
commit 17083d6d1e
32 changed files with 328 additions and 112 deletions

View File

@ -395,7 +395,7 @@ static void allwinner_sun8i_emac_flush_desc(FrameDescriptor *desc,
cpu_physical_memory_write(phys_addr, desc, sizeof(*desc)); cpu_physical_memory_write(phys_addr, desc, sizeof(*desc));
} }
static int allwinner_sun8i_emac_can_receive(NetClientState *nc) static bool allwinner_sun8i_emac_can_receive(NetClientState *nc)
{ {
AwSun8iEmacState *s = qemu_get_nic_opaque(nc); AwSun8iEmacState *s = qemu_get_nic_opaque(nc);
FrameDescriptor desc; FrameDescriptor desc;
@ -611,10 +611,10 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset,
value = s->mii_data; value = s->mii_data;
break; break;
case REG_ADDR_HIGH: /* MAC Address High */ case REG_ADDR_HIGH: /* MAC Address High */
value = *(((uint32_t *) (s->conf.macaddr.a)) + 1); value = lduw_le_p(s->conf.macaddr.a + 4);
break; break;
case REG_ADDR_LOW: /* MAC Address Low */ case REG_ADDR_LOW: /* MAC Address Low */
value = *(uint32_t *) (s->conf.macaddr.a); value = ldl_le_p(s->conf.macaddr.a);
break; break;
case REG_TX_DMA_STA: /* Transmit DMA Status */ case REG_TX_DMA_STA: /* Transmit DMA Status */
break; break;
@ -728,14 +728,10 @@ static void allwinner_sun8i_emac_write(void *opaque, hwaddr offset,
s->mii_data = value; s->mii_data = value;
break; break;
case REG_ADDR_HIGH: /* MAC Address High */ case REG_ADDR_HIGH: /* MAC Address High */
s->conf.macaddr.a[4] = (value & 0xff); stw_le_p(s->conf.macaddr.a + 4, value);
s->conf.macaddr.a[5] = (value & 0xff00) >> 8;
break; break;
case REG_ADDR_LOW: /* MAC Address Low */ case REG_ADDR_LOW: /* MAC Address Low */
s->conf.macaddr.a[0] = (value & 0xff); stl_le_p(s->conf.macaddr.a, value);
s->conf.macaddr.a[1] = (value & 0xff00) >> 8;
s->conf.macaddr.a[2] = (value & 0xff0000) >> 16;
s->conf.macaddr.a[3] = (value & 0xff000000) >> 24;
break; break;
case REG_TX_DMA_STA: /* Transmit DMA Status */ case REG_TX_DMA_STA: /* Transmit DMA Status */
case REG_TX_CUR_DESC: /* Transmit Current Descriptor */ case REG_TX_CUR_DESC: /* Transmit Current Descriptor */

View File

@ -178,7 +178,7 @@ static uint32_t fifo8_pop_word(Fifo8 *fifo)
return ret; return ret;
} }
static int aw_emac_can_receive(NetClientState *nc) static bool aw_emac_can_receive(NetClientState *nc)
{ {
AwEmacState *s = qemu_get_nic_opaque(nc); AwEmacState *s = qemu_get_nic_opaque(nc);

View File

@ -505,7 +505,7 @@ static void phy_update_link(CadenceGEMState *s)
} }
} }
static int gem_can_receive(NetClientState *nc) static bool gem_can_receive(NetClientState *nc)
{ {
CadenceGEMState *s; CadenceGEMState *s;
int i; int i;
@ -518,7 +518,7 @@ static int gem_can_receive(NetClientState *nc)
s->can_rx_state = 1; s->can_rx_state = 1;
DB_PRINT("can't receive - no enable\n"); DB_PRINT("can't receive - no enable\n");
} }
return 0; return false;
} }
for (i = 0; i < s->num_priority_queues; i++) { for (i = 0; i < s->num_priority_queues; i++) {
@ -532,14 +532,14 @@ static int gem_can_receive(NetClientState *nc)
s->can_rx_state = 2; s->can_rx_state = 2;
DB_PRINT("can't receive - all the buffer descriptors are busy\n"); DB_PRINT("can't receive - all the buffer descriptors are busy\n");
} }
return 0; return false;
} }
if (s->can_rx_state != 0) { if (s->can_rx_state != 0) {
s->can_rx_state = 0; s->can_rx_state = 0;
DB_PRINT("can receive\n"); DB_PRINT("can receive\n");
} }
return 1; return true;
} }
/* /*

View File

@ -733,21 +733,21 @@ uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size)
return temp; return temp;
} }
int can_sja_can_receive(CanBusClientState *client) bool can_sja_can_receive(CanBusClientState *client)
{ {
CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client); CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client);
if (s->clock & 0x80) { /* PeliCAN Mode */ if (s->clock & 0x80) { /* PeliCAN Mode */
if (s->mode & 0x01) { /* reset mode. */ if (s->mode & 0x01) { /* reset mode. */
return 0; return false;
} }
} else { /* BasicCAN mode */ } else { /* BasicCAN mode */
if (s->control & 0x01) { if (s->control & 0x01) {
return 0; return false;
} }
} }
return 1; /* always return 1, when operation mode */ return true; /* always return true, when operation mode */
} }
ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames, ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames,

View File

@ -137,7 +137,7 @@ void can_sja_disconnect(CanSJA1000State *s);
int can_sja_init(CanSJA1000State *s, qemu_irq irq); int can_sja_init(CanSJA1000State *s, qemu_irq irq);
int can_sja_can_receive(CanBusClientState *client); bool can_sja_can_receive(CanBusClientState *client);
ssize_t can_sja_receive(CanBusClientState *client, ssize_t can_sja_receive(CanBusClientState *client,
const qemu_can_frame *frames, size_t frames_cnt); const qemu_can_frame *frames, size_t frames_cnt);

View File

@ -414,7 +414,7 @@ static void dp8393x_do_stop_timer(dp8393xState *s)
dp8393x_update_wt_regs(s); dp8393x_update_wt_regs(s);
} }
static int dp8393x_can_receive(NetClientState *nc); static bool dp8393x_can_receive(NetClientState *nc);
static void dp8393x_do_receiver_enable(dp8393xState *s) static void dp8393x_do_receiver_enable(dp8393xState *s)
{ {
@ -718,13 +718,11 @@ static void dp8393x_watchdog(void *opaque)
dp8393x_update_irq(s); dp8393x_update_irq(s);
} }
static int dp8393x_can_receive(NetClientState *nc) static bool dp8393x_can_receive(NetClientState *nc)
{ {
dp8393xState *s = qemu_get_nic_opaque(nc); dp8393xState *s = qemu_get_nic_opaque(nc);
if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN)) return !!(s->regs[SONIC_CR] & SONIC_CR_RXEN);
return 0;
return 1;
} }
static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf, static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf,

View File

@ -845,7 +845,7 @@ static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
return total_size <= bufs * s->rxbuf_size; return total_size <= bufs * s->rxbuf_size;
} }
static int static bool
e1000_can_receive(NetClientState *nc) e1000_can_receive(NetClientState *nc)
{ {
E1000State *s = qemu_get_nic_opaque(nc); E1000State *s = qemu_get_nic_opaque(nc);

View File

@ -199,7 +199,7 @@ static const MemoryRegionOps io_ops = {
}, },
}; };
static int static bool
e1000e_nc_can_receive(NetClientState *nc) e1000e_nc_can_receive(NetClientState *nc)
{ {
E1000EState *s = qemu_get_nic_opaque(nc); E1000EState *s = qemu_get_nic_opaque(nc);
@ -328,7 +328,7 @@ e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr)
s->nic = qemu_new_nic(&net_e1000e_info, &s->conf, s->nic = qemu_new_nic(&net_e1000e_info, &s->conf,
object_get_typename(OBJECT(s)), dev->id, s); object_get_typename(OBJECT(s)), dev->id, s);
s->core.max_queue_num = s->conf.peers.queues - 1; s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0;
trace_e1000e_mac_set_permanent(MAC_ARG(macaddr)); trace_e1000e_mac_set_permanent(MAC_ARG(macaddr));
memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac)); memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac));

View File

@ -967,7 +967,7 @@ e1000e_start_recv(E1000ECore *core)
} }
} }
int bool
e1000e_can_receive(E1000ECore *core) e1000e_can_receive(E1000ECore *core)
{ {
int i; int i;

View File

@ -143,7 +143,7 @@ e1000e_core_set_link_status(E1000ECore *core);
void void
e1000e_core_pci_uninit(E1000ECore *core); e1000e_core_pci_uninit(E1000ECore *core);
int bool
e1000e_can_receive(E1000ECore *core); e1000e_can_receive(E1000ECore *core);
ssize_t ssize_t

View File

@ -562,18 +562,18 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring,
ftgmac100_update_irq(s); ftgmac100_update_irq(s);
} }
static int ftgmac100_can_receive(NetClientState *nc) static bool ftgmac100_can_receive(NetClientState *nc)
{ {
FTGMAC100State *s = FTGMAC100(qemu_get_nic_opaque(nc)); FTGMAC100State *s = FTGMAC100(qemu_get_nic_opaque(nc));
FTGMAC100Desc bd; FTGMAC100Desc bd;
if ((s->maccr & (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) if ((s->maccr & (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN))
!= (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) { != (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) {
return 0; return false;
} }
if (ftgmac100_read_bd(&bd, s->rx_descriptor)) { if (ftgmac100_read_bd(&bd, s->rx_descriptor)) {
return 0; return false;
} }
return !(bd.des0 & FTGMAC100_RXDES0_RXPKT_RDY); return !(bd.des0 & FTGMAC100_RXDES0_RXPKT_RDY);
} }

View File

@ -43,6 +43,9 @@
#define SCB_STATUS_CNA 0x2000 /* CU left active state */ #define SCB_STATUS_CNA 0x2000 /* CU left active state */
#define SCB_STATUS_RNR 0x1000 /* RU left active state */ #define SCB_STATUS_RNR 0x1000 /* RU left active state */
#define SCB_COMMAND_ACK_MASK \
(SCB_STATUS_CX | SCB_STATUS_FR | SCB_STATUS_CNA | SCB_STATUS_RNR)
#define CU_IDLE 0 #define CU_IDLE 0
#define CU_SUSPENDED 1 #define CU_SUSPENDED 1
#define CU_ACTIVE 2 #define CU_ACTIVE 2
@ -348,14 +351,7 @@ static void examine_scb(I82596State *s)
/* and clear the scb command word */ /* and clear the scb command word */
set_uint16(s->scb + 2, 0); set_uint16(s->scb + 2, 0);
if (command & BIT(31)) /* ACK-CX */ s->scb_status &= ~(command & SCB_COMMAND_ACK_MASK);
s->scb_status &= ~SCB_STATUS_CX;
if (command & BIT(30)) /*ACK-FR */
s->scb_status &= ~SCB_STATUS_FR;
if (command & BIT(29)) /*ACK-CNA */
s->scb_status &= ~SCB_STATUS_CNA;
if (command & BIT(28)) /*ACK-RNR */
s->scb_status &= ~SCB_STATUS_RNR;
switch (cuc) { switch (cuc) {
case 0: /* no change */ case 0: /* no change */
@ -474,23 +470,23 @@ void i82596_h_reset(void *opaque)
i82596_s_reset(s); i82596_s_reset(s);
} }
int i82596_can_receive(NetClientState *nc) bool i82596_can_receive(NetClientState *nc)
{ {
I82596State *s = qemu_get_nic_opaque(nc); I82596State *s = qemu_get_nic_opaque(nc);
if (s->rx_status == RX_SUSPENDED) { if (s->rx_status == RX_SUSPENDED) {
return 0; return false;
} }
if (!s->lnkst) { if (!s->lnkst) {
return 0; return false;
} }
if (USE_TIMER && !timer_pending(s->flush_queue_timer)) { if (USE_TIMER && !timer_pending(s->flush_queue_timer)) {
return 1; return true;
} }
return 1; return true;
} }
#define MIN_BUF_SIZE 60 #define MIN_BUF_SIZE 60
@ -501,7 +497,8 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz)
uint32_t rfd_p; uint32_t rfd_p;
uint32_t rbd; uint32_t rbd;
uint16_t is_broadcast = 0; uint16_t is_broadcast = 0;
size_t len = sz; size_t len = sz; /* length of data for guest (including CRC) */
size_t bufsz = sz; /* length of data in buf */
uint32_t crc; uint32_t crc;
uint8_t *crc_ptr; uint8_t *crc_ptr;
uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN]; uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN];
@ -595,6 +592,7 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz)
if (len < MIN_BUF_SIZE) { if (len < MIN_BUF_SIZE) {
len = MIN_BUF_SIZE; len = MIN_BUF_SIZE;
} }
bufsz = len;
} }
/* Calculate the ethernet checksum (4 bytes) */ /* Calculate the ethernet checksum (4 bytes) */
@ -627,6 +625,7 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz)
while (len) { while (len) {
uint16_t buffer_size, num; uint16_t buffer_size, num;
uint32_t rba; uint32_t rba;
size_t bufcount, crccount;
/* printf("Receive: rbd is %08x\n", rbd); */ /* printf("Receive: rbd is %08x\n", rbd); */
buffer_size = get_uint16(rbd + 12); buffer_size = get_uint16(rbd + 12);
@ -639,14 +638,37 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz)
} }
rba = get_uint32(rbd + 8); rba = get_uint32(rbd + 8);
/* printf("rba is 0x%x\n", rba); */ /* printf("rba is 0x%x\n", rba); */
/*
* Calculate how many bytes we want from buf[] and how many
* from the CRC.
*/
if ((len - num) >= 4) {
/* The whole guest buffer, we haven't hit the CRC yet */
bufcount = num;
} else {
/* All that's left of buf[] */
bufcount = len - 4;
}
crccount = num - bufcount;
if (bufcount > 0) {
/* Still some of the actual data buffer to transfer */
assert(bufsz >= bufcount);
bufsz -= bufcount;
address_space_write(&address_space_memory, rba, address_space_write(&address_space_memory, rba,
MEMTXATTRS_UNSPECIFIED, buf, num); MEMTXATTRS_UNSPECIFIED, buf, bufcount);
rba += num; rba += bufcount;
buf += num; buf += bufcount;
len -= num; len -= bufcount;
if (len == 0) { /* copy crc */ }
address_space_write(&address_space_memory, rba - 4,
MEMTXATTRS_UNSPECIFIED, crc_ptr, 4); /* Write as much of the CRC as fits */
if (crccount > 0) {
address_space_write(&address_space_memory, rba,
MEMTXATTRS_UNSPECIFIED, crc_ptr, crccount);
rba += crccount;
crc_ptr += crccount;
len -= crccount;
} }
num |= 0x4000; /* set F BIT */ num |= 0x4000; /* set F BIT */

View File

@ -48,7 +48,7 @@ void i82596_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
uint32_t i82596_ioport_readl(void *opaque, uint32_t addr); uint32_t i82596_ioport_readl(void *opaque, uint32_t addr);
uint32_t i82596_bcr_readw(I82596State *s, uint32_t rap); uint32_t i82596_bcr_readw(I82596State *s, uint32_t rap);
ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t size_); ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
int i82596_can_receive(NetClientState *nc); bool i82596_can_receive(NetClientState *nc);
void i82596_set_link_status(NetClientState *nc); void i82596_set_link_status(NetClientState *nc);
void i82596_common_init(DeviceState *dev, I82596State *s, NetClientInfo *info); void i82596_common_init(DeviceState *dev, I82596State *s, NetClientInfo *info);
extern const VMStateDescription vmstate_i82596; extern const VMStateDescription vmstate_i82596;

View File

@ -1049,7 +1049,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value,
imx_eth_update(s); imx_eth_update(s);
} }
static int imx_eth_can_receive(NetClientState *nc) static bool imx_eth_can_receive(NetClientState *nc)
{ {
IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc));

View File

@ -349,12 +349,11 @@ static void open_eth_reset(void *opaque)
open_eth_set_link_status(qemu_get_queue(s->nic)); open_eth_set_link_status(qemu_get_queue(s->nic));
} }
static int open_eth_can_receive(NetClientState *nc) static bool open_eth_can_receive(NetClientState *nc)
{ {
OpenEthState *s = qemu_get_nic_opaque(nc); OpenEthState *s = qemu_get_nic_opaque(nc);
return GET_REGBIT(s, MODER, RXEN) && return GET_REGBIT(s, MODER, RXEN) && (s->regs[TX_BD_NUM] < 0x80);
(s->regs[TX_BD_NUM] < 0x80);
} }
static ssize_t open_eth_receive(NetClientState *nc, static ssize_t open_eth_receive(NetClientState *nc,

View File

@ -793,26 +793,28 @@ static bool rtl8139_cp_rx_valid(RTL8139State *s)
return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0); return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0);
} }
static int rtl8139_can_receive(NetClientState *nc) static bool rtl8139_can_receive(NetClientState *nc)
{ {
RTL8139State *s = qemu_get_nic_opaque(nc); RTL8139State *s = qemu_get_nic_opaque(nc);
int avail; int avail;
/* Receive (drop) packets if card is disabled. */ /* Receive (drop) packets if card is disabled. */
if (!s->clock_enabled) if (!s->clock_enabled) {
return 1; return true;
if (!rtl8139_receiver_enabled(s)) }
return 1; if (!rtl8139_receiver_enabled(s)) {
return true;
}
if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) { if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) {
/* ??? Flow control not implemented in c+ mode. /* ??? Flow control not implemented in c+ mode.
This is a hack to work around slirp deficiencies anyway. */ This is a hack to work around slirp deficiencies anyway. */
return 1; return true;
} else { }
avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
s->RxBufferSize); s->RxBufferSize);
return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow)); return avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow);
}
} }
static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt) static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)

View File

@ -130,16 +130,16 @@ static void smc91c111_update(smc91c111_state *s)
qemu_set_irq(s->irq, level); qemu_set_irq(s->irq, level);
} }
static int smc91c111_can_receive(smc91c111_state *s) static bool smc91c111_can_receive(smc91c111_state *s)
{ {
if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) { if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) {
return 1; return true;
} }
if (s->allocated == (1 << NUM_PACKETS) - 1 || if (s->allocated == (1 << NUM_PACKETS) - 1 ||
s->rx_fifo_len == NUM_PACKETS) { s->rx_fifo_len == NUM_PACKETS) {
return 0; return false;
} }
return 1; return true;
} }
static inline void smc91c111_flush_queued_packets(smc91c111_state *s) static inline void smc91c111_flush_queued_packets(smc91c111_state *s)
@ -667,7 +667,7 @@ static void smc91c111_writefn(void *opaque, hwaddr addr,
} }
} }
static int smc91c111_can_receive_nc(NetClientState *nc) static bool smc91c111_can_receive_nc(NetClientState *nc)
{ {
smc91c111_state *s = qemu_get_nic_opaque(nc); smc91c111_state *s = qemu_get_nic_opaque(nc);

View File

@ -110,11 +110,11 @@ typedef struct SpaprVioVlan {
RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */ RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */
} SpaprVioVlan; } SpaprVioVlan;
static int spapr_vlan_can_receive(NetClientState *nc) static bool spapr_vlan_can_receive(NetClientState *nc)
{ {
SpaprVioVlan *dev = qemu_get_nic_opaque(nc); SpaprVioVlan *dev = qemu_get_nic_opaque(nc);
return (dev->isopen && dev->rx_bufs > 0); return dev->isopen && dev->rx_bufs > 0;
} }
/** /**

View File

@ -433,7 +433,7 @@ static bool sungem_rx_full(SunGEMState *s, uint32_t kick, uint32_t done)
return kick == ((done + 1) & s->rx_mask); return kick == ((done + 1) & s->rx_mask);
} }
static int sungem_can_receive(NetClientState *nc) static bool sungem_can_receive(NetClientState *nc)
{ {
SunGEMState *s = qemu_get_nic_opaque(nc); SunGEMState *s = qemu_get_nic_opaque(nc);
uint32_t kick, done, rxdma_cfg, rxmac_cfg; uint32_t kick, done, rxdma_cfg, rxmac_cfg;
@ -445,11 +445,11 @@ static int sungem_can_receive(NetClientState *nc)
/* If MAC disabled, can't receive */ /* If MAC disabled, can't receive */
if ((rxmac_cfg & MAC_RXCFG_ENAB) == 0) { if ((rxmac_cfg & MAC_RXCFG_ENAB) == 0) {
trace_sungem_rx_mac_disabled(); trace_sungem_rx_mac_disabled();
return 0; return false;
} }
if ((rxdma_cfg & RXDMA_CFG_ENABLE) == 0) { if ((rxdma_cfg & RXDMA_CFG_ENABLE) == 0) {
trace_sungem_rx_txdma_disabled(); trace_sungem_rx_txdma_disabled();
return 0; return false;
} }
/* Check RX availability */ /* Check RX availability */

View File

@ -657,11 +657,11 @@ static void sunhme_transmit(SunHMEState *s)
sunhme_update_irq(s); sunhme_update_irq(s);
} }
static int sunhme_can_receive(NetClientState *nc) static bool sunhme_can_receive(NetClientState *nc)
{ {
SunHMEState *s = qemu_get_nic_opaque(nc); SunHMEState *s = qemu_get_nic_opaque(nc);
return s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_ENABLE; return !!(s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_ENABLE);
} }
static void sunhme_link_status_changed(NetClientState *nc) static void sunhme_link_status_changed(NetClientState *nc)

View File

@ -170,6 +170,10 @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
} else { } else {
len = s->rx_frame_len; len = s->rx_frame_len;
} }
if (s->rx_frame_len + len > sizeof(s->rx_frame)) {
return;
}
pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame + pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame +
(s->rx_frame_size - s->rx_frame_len), len); (s->rx_frame_size - s->rx_frame_len), len);
s->rx_frame_len -= len; s->rx_frame_len -= len;
@ -181,6 +185,10 @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
} else { } else {
len = s->rx_frame_len; len = s->rx_frame_len;
} }
if (s->rx_frame_len + len > sizeof(s->rx_frame)) {
return;
}
pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame + pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame +
(s->rx_frame_size - s->rx_frame_len), len); (s->rx_frame_size - s->rx_frame_len), len);
s->rx_frame_len -= len; s->rx_frame_len -= len;
@ -227,7 +235,8 @@ static ssize_t tulip_receive(TULIPState *s, const uint8_t *buf, size_t size)
trace_tulip_receive(buf, size); trace_tulip_receive(buf, size);
if (size < 14 || size > 2048 || s->rx_frame_len || tulip_rx_stopped(s)) { if (size < 14 || size > sizeof(s->rx_frame) - 4
|| s->rx_frame_len || tulip_rx_stopped(s)) {
return 0; return 0;
} }
@ -275,7 +284,6 @@ static ssize_t tulip_receive_nc(NetClientState *nc,
return tulip_receive(qemu_get_nic_opaque(nc), buf, size); return tulip_receive(qemu_get_nic_opaque(nc), buf, size);
} }
static NetClientInfo net_tulip_info = { static NetClientInfo net_tulip_info = {
.type = NET_CLIENT_DRIVER_NIC, .type = NET_CLIENT_DRIVER_NIC,
.size = sizeof(NICState), .size = sizeof(NICState),
@ -558,7 +566,7 @@ static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc)
if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) { if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) {
/* Internal or external Loopback */ /* Internal or external Loopback */
tulip_receive(s, s->tx_frame, s->tx_frame_len); tulip_receive(s, s->tx_frame, s->tx_frame_len);
} else { } else if (s->tx_frame_len <= sizeof(s->tx_frame)) {
qemu_send_packet(qemu_get_queue(s->nic), qemu_send_packet(qemu_get_queue(s->nic),
s->tx_frame, s->tx_frame_len); s->tx_frame, s->tx_frame_len);
} }
@ -570,23 +578,31 @@ static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc)
} }
} }
static void tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc) static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
{ {
int len1 = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK; int len1 = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK;
int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK; int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK;
if (s->tx_frame_len + len1 > sizeof(s->tx_frame)) {
return -1;
}
if (len1) { if (len1) {
pci_dma_read(&s->dev, desc->buf_addr1, pci_dma_read(&s->dev, desc->buf_addr1,
s->tx_frame + s->tx_frame_len, len1); s->tx_frame + s->tx_frame_len, len1);
s->tx_frame_len += len1; s->tx_frame_len += len1;
} }
if (s->tx_frame_len + len2 > sizeof(s->tx_frame)) {
return -1;
}
if (len2) { if (len2) {
pci_dma_read(&s->dev, desc->buf_addr2, pci_dma_read(&s->dev, desc->buf_addr2,
s->tx_frame + s->tx_frame_len, len2); s->tx_frame + s->tx_frame_len, len2);
s->tx_frame_len += len2; s->tx_frame_len += len2;
} }
desc->status = (len1 + len2) ? 0 : 0x7fffffff; desc->status = (len1 + len2) ? 0 : 0x7fffffff;
return 0;
} }
static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n) static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n)
@ -651,13 +667,15 @@ static uint32_t tulip_ts(TULIPState *s)
static void tulip_xmit_list_update(TULIPState *s) static void tulip_xmit_list_update(TULIPState *s)
{ {
#define TULIP_DESC_MAX 128
uint8_t i = 0;
struct tulip_descriptor desc; struct tulip_descriptor desc;
if (tulip_ts(s) != CSR5_TS_SUSPENDED) { if (tulip_ts(s) != CSR5_TS_SUSPENDED) {
return; return;
} }
for (;;) { for (i = 0; i < TULIP_DESC_MAX; i++) {
tulip_desc_read(s, s->current_tx_desc, &desc); tulip_desc_read(s, s->current_tx_desc, &desc);
tulip_dump_tx_descriptor(s, &desc); tulip_dump_tx_descriptor(s, &desc);
@ -675,12 +693,12 @@ static void tulip_xmit_list_update(TULIPState *s)
s->tx_frame_len = 0; s->tx_frame_len = 0;
} }
tulip_copy_tx_buffers(s, &desc); if (!tulip_copy_tx_buffers(s, &desc)) {
if (desc.control & TDES1_LS) { if (desc.control & TDES1_LS) {
tulip_tx(s, &desc); tulip_tx(s, &desc);
} }
} }
}
tulip_desc_write(s, s->current_tx_desc, &desc); tulip_desc_write(s, s->current_tx_desc, &desc);
tulip_next_tx_descriptor(s, &desc); tulip_next_tx_descriptor(s, &desc);
} }

View File

@ -1234,26 +1234,26 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index)); qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index));
} }
static int virtio_net_can_receive(NetClientState *nc) static bool virtio_net_can_receive(NetClientState *nc)
{ {
VirtIONet *n = qemu_get_nic_opaque(nc); VirtIONet *n = qemu_get_nic_opaque(nc);
VirtIODevice *vdev = VIRTIO_DEVICE(n); VirtIODevice *vdev = VIRTIO_DEVICE(n);
VirtIONetQueue *q = virtio_net_get_subqueue(nc); VirtIONetQueue *q = virtio_net_get_subqueue(nc);
if (!vdev->vm_running) { if (!vdev->vm_running) {
return 0; return false;
} }
if (nc->queue_index >= n->curr_queues) { if (nc->queue_index >= n->curr_queues) {
return 0; return false;
} }
if (!virtio_queue_ready(q->rx_vq) || if (!virtio_queue_ready(q->rx_vq) ||
!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { !(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
return 0; return false;
} }
return 1; return true;
} }
static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize)

View File

@ -175,7 +175,7 @@ static const MemoryRegionOps eth_ops = {
} }
}; };
static int eth_can_rx(NetClientState *nc) static bool eth_can_rx(NetClientState *nc)
{ {
struct xlx_ethlite *s = qemu_get_nic_opaque(nc); struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
unsigned int rxbase = s->rxbuf * (0x800 / 4); unsigned int rxbase = s->rxbuf * (0x800 / 4);

View File

@ -83,7 +83,7 @@ typedef struct CanBusClientState CanBusClientState;
typedef struct CanBusState CanBusState; typedef struct CanBusState CanBusState;
typedef struct CanBusClientInfo { typedef struct CanBusClientInfo {
int (*can_receive)(CanBusClientState *); bool (*can_receive)(CanBusClientState *);
ssize_t (*receive)(CanBusClientState *, ssize_t (*receive)(CanBusClientState *,
const struct qemu_can_frame *frames, size_t frames_cnt); const struct qemu_can_frame *frames, size_t frames_cnt);
} CanBusClientInfo; } CanBusClientInfo;

View File

@ -42,7 +42,7 @@ typedef struct NICConf {
/* Net clients */ /* Net clients */
typedef void (NetPoll)(NetClientState *, bool enable); typedef void (NetPoll)(NetClientState *, bool enable);
typedef int (NetCanReceive)(NetClientState *); typedef bool (NetCanReceive)(NetClientState *);
typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t);
typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int);
typedef void (NetCleanup) (NetClientState *); typedef void (NetCleanup) (NetClientState *);

View File

@ -110,9 +110,9 @@ static void can_host_socketcan_read(void *opaque)
} }
} }
static int can_host_socketcan_can_receive(CanBusClientState *client) static bool can_host_socketcan_can_receive(CanBusClientState *client)
{ {
return 1; return true;
} }
static ssize_t can_host_socketcan_receive(CanBusClientState *client, static ssize_t can_host_socketcan_receive(CanBusClientState *client,

View File

@ -48,8 +48,8 @@ static NotifierList colo_compare_notifiers =
#define COLO_COMPARE_FREE_PRIMARY 0x01 #define COLO_COMPARE_FREE_PRIMARY 0x01
#define COLO_COMPARE_FREE_SECONDARY 0x02 #define COLO_COMPARE_FREE_SECONDARY 0x02
/* TODO: Should be configurable */
#define REGULAR_PACKET_CHECK_MS 3000 #define REGULAR_PACKET_CHECK_MS 3000
#define DEFAULT_TIME_OUT_MS 3000
static QemuMutex event_mtx; static QemuMutex event_mtx;
static QemuCond event_complete_cond; static QemuCond event_complete_cond;
@ -92,6 +92,8 @@ typedef struct CompareState {
SocketReadState sec_rs; SocketReadState sec_rs;
SocketReadState notify_rs; SocketReadState notify_rs;
bool vnet_hdr; bool vnet_hdr;
uint32_t compare_timeout;
uint32_t expired_scan_cycle;
/* /*
* Record the connection that through the NIC * Record the connection that through the NIC
@ -607,10 +609,9 @@ static int colo_old_packet_check_one_conn(Connection *conn,
CompareState *s) CompareState *s)
{ {
GList *result = NULL; GList *result = NULL;
int64_t check_time = REGULAR_PACKET_CHECK_MS;
result = g_queue_find_custom(&conn->primary_list, result = g_queue_find_custom(&conn->primary_list,
&check_time, &s->compare_timeout,
(GCompareFunc)colo_old_packet_check_one); (GCompareFunc)colo_old_packet_check_one);
if (result) { if (result) {
@ -822,7 +823,7 @@ static void check_old_packet_regular(void *opaque)
/* if have old packet we will notify checkpoint */ /* if have old packet we will notify checkpoint */
colo_old_packet_check(s); colo_old_packet_check(s);
timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
REGULAR_PACKET_CHECK_MS); s->expired_scan_cycle);
} }
/* Public API, Used for COLO frame to notify compare event */ /* Public API, Used for COLO frame to notify compare event */
@ -852,7 +853,7 @@ static void colo_compare_timer_init(CompareState *s)
SCALE_MS, check_old_packet_regular, SCALE_MS, check_old_packet_regular,
s); s);
timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
REGULAR_PACKET_CHECK_MS); s->expired_scan_cycle);
} }
static void colo_compare_timer_del(CompareState *s) static void colo_compare_timer_del(CompareState *s)
@ -984,6 +985,72 @@ static void compare_set_notify_dev(Object *obj, const char *value, Error **errp)
s->notify_dev = g_strdup(value); s->notify_dev = g_strdup(value);
} }
static void compare_get_timeout(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
CompareState *s = COLO_COMPARE(obj);
uint32_t value = s->compare_timeout;
visit_type_uint32(v, name, &value, errp);
}
static void compare_set_timeout(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
CompareState *s = COLO_COMPARE(obj);
Error *local_err = NULL;
uint32_t value;
visit_type_uint32(v, name, &value, &local_err);
if (local_err) {
goto out;
}
if (!value) {
error_setg(&local_err, "Property '%s.%s' requires a positive value",
object_get_typename(obj), name);
goto out;
}
s->compare_timeout = value;
out:
error_propagate(errp, local_err);
}
static void compare_get_expired_scan_cycle(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
CompareState *s = COLO_COMPARE(obj);
uint32_t value = s->expired_scan_cycle;
visit_type_uint32(v, name, &value, errp);
}
static void compare_set_expired_scan_cycle(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
CompareState *s = COLO_COMPARE(obj);
Error *local_err = NULL;
uint32_t value;
visit_type_uint32(v, name, &value, &local_err);
if (local_err) {
goto out;
}
if (!value) {
error_setg(&local_err, "Property '%s.%s' requires a positive value",
object_get_typename(obj), name);
goto out;
}
s->expired_scan_cycle = value;
out:
error_propagate(errp, local_err);
}
static void compare_pri_rs_finalize(SocketReadState *pri_rs) static void compare_pri_rs_finalize(SocketReadState *pri_rs)
{ {
CompareState *s = container_of(pri_rs, CompareState, pri_rs); CompareState *s = container_of(pri_rs, CompareState, pri_rs);
@ -1090,6 +1157,16 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
return; return;
} }
if (!s->compare_timeout) {
/* Set default value to 3000 MS */
s->compare_timeout = DEFAULT_TIME_OUT_MS;
}
if (!s->expired_scan_cycle) {
/* Set default value to 3000 MS */
s->expired_scan_cycle = REGULAR_PACKET_CHECK_MS;
}
if (find_and_check_chardev(&chr, s->pri_indev, errp) || if (find_and_check_chardev(&chr, s->pri_indev, errp) ||
!qemu_chr_fe_init(&s->chr_pri_in, chr, errp)) { !qemu_chr_fe_init(&s->chr_pri_in, chr, errp)) {
return; return;
@ -1185,6 +1262,14 @@ static void colo_compare_init(Object *obj)
compare_get_notify_dev, compare_set_notify_dev, compare_get_notify_dev, compare_set_notify_dev,
NULL); NULL);
object_property_add(obj, "compare_timeout", "uint32",
compare_get_timeout,
compare_set_timeout, NULL, NULL, NULL);
object_property_add(obj, "expired_scan_cycle", "uint32",
compare_get_expired_scan_cycle,
compare_set_expired_scan_cycle, NULL, NULL, NULL);
s->vnet_hdr = false; s->vnet_hdr = false;
object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr, object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr,
compare_set_vnet_hdr, NULL); compare_set_vnet_hdr, NULL);

View File

@ -74,7 +74,7 @@ static ssize_t filter_buffer_receive_iov(NetFilterState *nf,
* the filter can still accept packets until its internal queue is full. * the filter can still accept packets until its internal queue is full.
* For example: * For example:
* For some reason, receiver could not receive more packets * For some reason, receiver could not receive more packets
* (.can_receive() returns zero). Without a filter, at most one packet * (.can_receive() returns false). Without a filter, at most one packet
* will be queued in incoming queue and sender's poll will be disabled * will be queued in incoming queue and sender's poll will be disabled
* unit its sent_cb() was called. With a filter, it will keep receiving * unit its sent_cb() was called. With a filter, it will keep receiving
* the packets without caring about the receiver. This is suboptimal. * the packets without caring about the receiver. This is suboptimal.

View File

@ -90,7 +90,7 @@ static NetHub *net_hub_new(int id)
return hub; return hub;
} }
static int net_hub_port_can_receive(NetClientState *nc) static bool net_hub_port_can_receive(NetClientState *nc)
{ {
NetHubPort *port; NetHubPort *port;
NetHubPort *src_port = DO_UPCAST(NetHubPort, nc, nc); NetHubPort *src_port = DO_UPCAST(NetHubPort, nc, nc);
@ -102,11 +102,11 @@ static int net_hub_port_can_receive(NetClientState *nc)
} }
if (qemu_can_send_packet(&port->nc)) { if (qemu_can_send_packet(&port->nc)) {
return 1; return true;
} }
} }
return 0; return false;
} }
static ssize_t net_hub_port_receive(NetClientState *nc, static ssize_t net_hub_port_receive(NetClientState *nc,

View File

@ -4615,7 +4615,7 @@ SRST
stored. The file format is libpcap, so it can be analyzed with stored. The file format is libpcap, so it can be analyzed with
tools such as tcpdump or Wireshark. tools such as tcpdump or Wireshark.
``-object colo-compare,id=id,primary_in=chardevid,secondary_in=chardevid,outdev=chardevid,iothread=id[,vnet_hdr_support][,notify_dev=id]`` ``-object colo-compare,id=id,primary_in=chardevid,secondary_in=chardevid,outdev=chardevid,iothread=id[,vnet_hdr_support][,notify_dev=id][,compare_timeout=@var{ms}][,expired_scan_cycle=@var{ms}``
Colo-compare gets packet from primary\_inchardevid and Colo-compare gets packet from primary\_inchardevid and
secondary\_inchardevid, than compare primary packet with secondary\_inchardevid, than compare primary packet with
secondary packet. If the packets are same, we will output secondary packet. If the packets are same, we will output
@ -4624,8 +4624,12 @@ SRST
outdevchardevid. In order to improve efficiency, we need to put outdevchardevid. In order to improve efficiency, we need to put
the task of comparison in another thread. If it has the the task of comparison in another thread. If it has the
vnet\_hdr\_support flag, colo compare will send/recv packet with vnet\_hdr\_support flag, colo compare will send/recv packet with
vnet\_hdr\_len. If you want to use Xen COLO, will need the vnet\_hdr\_len. Then compare\_timeout=@var{ms} determines the
notify\_dev to notify Xen colo-frame to do checkpoint. maximum delay colo-compare wait for the packet.
The expired\_scan\_cycle=@var{ms} to set the period of scanning
expired primary node network packets.
If you want to use Xen COLO, will need the notify\_dev to
notify Xen colo-frame to do checkpoint.
we must use it with the help of filter-mirror and we must use it with the help of filter-mirror and
filter-redirector. filter-redirector.

View File

@ -217,6 +217,7 @@ qos-test-obj-y += tests/qtest/es1370-test.o
qos-test-obj-y += tests/qtest/ipoctal232-test.o qos-test-obj-y += tests/qtest/ipoctal232-test.o
qos-test-obj-y += tests/qtest/megasas-test.o qos-test-obj-y += tests/qtest/megasas-test.o
qos-test-obj-y += tests/qtest/ne2000-test.o qos-test-obj-y += tests/qtest/ne2000-test.o
qos-test-obj-y += tests/qtest/tulip-test.o
qos-test-obj-y += tests/qtest/nvme-test.o qos-test-obj-y += tests/qtest/nvme-test.o
qos-test-obj-y += tests/qtest/pca9552-test.o qos-test-obj-y += tests/qtest/pca9552-test.o
qos-test-obj-y += tests/qtest/pci-test.o qos-test-obj-y += tests/qtest/pci-test.o

91
tests/qtest/tulip-test.c Normal file
View File

@ -0,0 +1,91 @@
/*
* QTest testcase for DEC/Intel Tulip 21143
*
* Copyright (c) 2020 Li Qiang <liq3ea@gmail.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "libqtest.h"
#include "qemu/module.h"
#include "libqos/qgraph.h"
#include "libqos/pci.h"
#include "qemu/bitops.h"
#include "hw/net/tulip.h"
typedef struct QTulip_pci QTulip_pci;
struct QTulip_pci {
QOSGraphObject obj;
QPCIDevice dev;
};
static void *tulip_pci_get_driver(void *obj, const char *interface)
{
QTulip_pci *tulip_pci = obj;
if (!g_strcmp0(interface, "pci-device")) {
return &tulip_pci->dev;
}
fprintf(stderr, "%s not present in tulip_pci\n", interface);
g_assert_not_reached();
}
static void *tulip_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
{
QTulip_pci *tulip_pci = g_new0(QTulip_pci, 1);
QPCIBus *bus = pci_bus;
qpci_device_init(&tulip_pci->dev, bus, addr);
tulip_pci->obj.get_driver = tulip_pci_get_driver;
return &tulip_pci->obj;
}
static void tulip_large_tx(void *obj, void *data, QGuestAllocator *alloc)
{
QTulip_pci *tulip_pci = obj;
QPCIDevice *dev = &tulip_pci->dev;
QPCIBar bar;
struct tulip_descriptor context;
char guest_data[4096];
uint64_t context_pa;
uint64_t guest_pa;
qpci_device_enable(dev);
bar = qpci_iomap(dev, 0, NULL);
context_pa = guest_alloc(alloc, sizeof(context));
guest_pa = guest_alloc(alloc, 4096);
memset(guest_data, 'A', sizeof(guest_data));
context.status = TDES0_OWN;
context.control = TDES1_BUF2_SIZE_MASK << TDES1_BUF2_SIZE_SHIFT |
TDES1_BUF1_SIZE_MASK << TDES1_BUF1_SIZE_SHIFT;
context.buf_addr2 = guest_pa;
context.buf_addr1 = guest_pa;
qtest_memwrite(dev->bus->qts, context_pa, &context, sizeof(context));
qtest_memwrite(dev->bus->qts, guest_pa, guest_data, sizeof(guest_data));
qpci_io_writel(dev, bar, 0x20, context_pa);
qpci_io_writel(dev, bar, 0x30, CSR6_ST);
guest_free(alloc, context_pa);
guest_free(alloc, guest_pa);
}
static void tulip_register_nodes(void)
{
QOSGraphEdgeOptions opts = {
.extra_device_opts = "addr=04.0",
};
add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
qos_node_create_driver("tulip", tulip_pci_create);
qos_node_consumes("tulip", "pci-bus", &opts);
qos_node_produces("tulip", "pci-device");
qos_add_test("tulip_large_tx", "tulip", tulip_large_tx, NULL);
}
libqos_init(tulip_register_nodes);