Skip to content

Commit

Permalink
net/cadence_gem: Prefetch rx descriptors ASAP
Browse files Browse the repository at this point in the history
The real hardware prefetches rx buffer descriptors ASAP and
potentially throws relevant interrupts following the fetch
even in the absence of a received packet.

Reported-by: Deepika Dhamija <deepika@xilinx.com>
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Message-id: 41629e35edfdb1f02f1e401f2c3d0e2e4c9e44b3.1386136219.git.peter.crosthwaite@xilinx.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pete128 authored and pm215 committed Dec 10, 2013
1 parent 7cfd65e commit 06c2fe9
Showing 1 changed file with 35 additions and 27 deletions.
62 changes: 35 additions & 27 deletions hw/net/cadence_gem.c
Expand Up @@ -346,6 +346,8 @@ typedef struct GemState {
uint32_t rx_desc_addr;
uint32_t tx_desc_addr;

unsigned rx_desc[2];

} GemState;

/* The broadcast MAC address: 0xFFFFFFFFFFFF */
Expand Down Expand Up @@ -579,13 +581,30 @@ static int gem_mac_address_filter(GemState *s, const uint8_t *packet)
return GEM_RX_REJECT;
}

static void gem_get_rx_desc(GemState *s)
{
DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr);
/* read current descriptor */
cpu_physical_memory_read(s->rx_desc_addr,
(uint8_t *)s->rx_desc, sizeof(s->rx_desc));

/* Descriptor owned by software ? */
if (rx_desc_get_ownership(s->rx_desc) == 1) {
DB_PRINT("descriptor 0x%x owned by sw.\n",
(unsigned)s->rx_desc_addr);
s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
/* Handle interrupt consequences */
gem_update_int_status(s);
}
}

/*
* gem_receive:
* Fit a packet handed to us by QEMU into the receive descriptor ring.
*/
static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{
unsigned desc[2];
GemState *s;
unsigned rxbufsize, bytes_to_copy;
unsigned rxbuf_offset;
Expand All @@ -595,11 +614,6 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)

s = qemu_get_nic_opaque(nc);

/* Do nothing if receive is not enabled. */
if (!gem_can_receive(nc)) {
return -1;
}

/* Is this destination MAC address "for us" ? */
if (gem_mac_address_filter(s, buf) == GEM_RX_REJECT) {
return -1;
Expand Down Expand Up @@ -667,53 +681,44 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);

while (bytes_to_copy) {
DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr);
/* read current descriptor */
cpu_physical_memory_read(s->rx_desc_addr,
(uint8_t *)&desc[0], sizeof(desc));

/* Descriptor owned by software ? */
if (rx_desc_get_ownership(desc) == 1) {
DB_PRINT("descriptor 0x%x owned by sw.\n",
(unsigned)s->rx_desc_addr);
s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
/* Handle interrupt consequences */
gem_update_int_status(s);
/* Do nothing if receive is not enabled. */
if (!gem_can_receive(nc)) {
assert(!first_desc);
return -1;
}

DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize),
rx_desc_get_buffer(desc));
rx_desc_get_buffer(s->rx_desc));

/* Copy packet data to emulated DMA buffer */
cpu_physical_memory_write(rx_desc_get_buffer(desc) + rxbuf_offset,
cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc) + rxbuf_offset,
rxbuf_ptr, MIN(bytes_to_copy, rxbufsize));
bytes_to_copy -= MIN(bytes_to_copy, rxbufsize);
rxbuf_ptr += MIN(bytes_to_copy, rxbufsize);

/* Update the descriptor. */
if (first_desc) {
rx_desc_set_sof(desc);
rx_desc_set_sof(s->rx_desc);
first_desc = false;
}
if (bytes_to_copy == 0) {
rx_desc_set_eof(desc);
rx_desc_set_length(desc, size);
rx_desc_set_eof(s->rx_desc);
rx_desc_set_length(s->rx_desc, size);
}
rx_desc_set_ownership(desc);
rx_desc_set_ownership(s->rx_desc);
/* Descriptor write-back. */
cpu_physical_memory_write(s->rx_desc_addr,
(uint8_t *)&desc[0], sizeof(desc));
(uint8_t *)s->rx_desc, sizeof(s->rx_desc));

/* Next descriptor */
if (rx_desc_get_wrap(desc)) {
if (rx_desc_get_wrap(s->rx_desc)) {
DB_PRINT("wrapping RX descriptor list\n");
s->rx_desc_addr = s->regs[GEM_RXQBASE];
} else {
DB_PRINT("incrementing RX descriptor list\n");
s->rx_desc_addr += 8;
}
gem_get_rx_desc(s);
}

/* Count it */
Expand Down Expand Up @@ -1053,6 +1058,9 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
/* Handle register write side effects */
switch (offset) {
case GEM_NWCTRL:
if (val & GEM_NWCTRL_RXENA) {
gem_get_rx_desc(s);
}
if (val & GEM_NWCTRL_TXSTART) {
gem_transmit(s);
}
Expand Down

0 comments on commit 06c2fe9

Please sign in to comment.