|
@@ -26,6 +26,7 @@
|
|
|
#include <zlib.h> /* For crc32 */
|
|
|
|
|
|
#include "hw/net/cadence_gem.h"
|
|
|
+#include "qapi/error.h"
|
|
|
#include "net/checksum.h"
|
|
|
|
|
|
#ifdef CADENCE_GEM_ERR_DEBUG
|
|
@@ -428,18 +429,18 @@ static int gem_can_receive(NetClientState *nc)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- if (rx_desc_get_ownership(s->rx_desc) == 1) {
|
|
|
+ if (rx_desc_get_ownership(s->rx_desc[0]) == 1) {
|
|
|
if (s->can_rx_state != 2) {
|
|
|
s->can_rx_state = 2;
|
|
|
DB_PRINT("can't receive - busy buffer descriptor 0x%x\n",
|
|
|
- s->rx_desc_addr);
|
|
|
+ s->rx_desc_addr[0]);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
if (s->can_rx_state != 0) {
|
|
|
s->can_rx_state = 0;
|
|
|
- DB_PRINT("can receive 0x%x\n", s->rx_desc_addr);
|
|
|
+ DB_PRINT("can receive 0x%x\n", s->rx_desc_addr[0]);
|
|
|
}
|
|
|
return 1;
|
|
|
}
|
|
@@ -452,7 +453,7 @@ static void gem_update_int_status(CadenceGEMState *s)
|
|
|
{
|
|
|
if (s->regs[GEM_ISR]) {
|
|
|
DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]);
|
|
|
- qemu_set_irq(s->irq, 1);
|
|
|
+ qemu_set_irq(s->irq[0], 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -603,15 +604,15 @@ static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet)
|
|
|
|
|
|
static void gem_get_rx_desc(CadenceGEMState *s)
|
|
|
{
|
|
|
- DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr);
|
|
|
+ DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[0]);
|
|
|
/* read current descriptor */
|
|
|
- cpu_physical_memory_read(s->rx_desc_addr,
|
|
|
- (uint8_t *)s->rx_desc, sizeof(s->rx_desc));
|
|
|
+ cpu_physical_memory_read(s->rx_desc_addr[0],
|
|
|
+ (uint8_t *)s->rx_desc[0], sizeof(s->rx_desc[0]));
|
|
|
|
|
|
/* Descriptor owned by software ? */
|
|
|
- if (rx_desc_get_ownership(s->rx_desc) == 1) {
|
|
|
+ if (rx_desc_get_ownership(s->rx_desc[0]) == 1) {
|
|
|
DB_PRINT("descriptor 0x%x owned by sw.\n",
|
|
|
- (unsigned)s->rx_desc_addr);
|
|
|
+ (unsigned)s->rx_desc_addr[0]);
|
|
|
s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
|
|
|
s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
|
|
|
/* Handle interrupt consequences */
|
|
@@ -632,6 +633,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|
|
uint8_t *rxbuf_ptr;
|
|
|
bool first_desc = true;
|
|
|
int maf;
|
|
|
+ int q = 0;
|
|
|
|
|
|
s = qemu_get_nic_opaque(nc);
|
|
|
|
|
@@ -718,54 +720,56 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|
|
}
|
|
|
|
|
|
DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize),
|
|
|
- rx_desc_get_buffer(s->rx_desc));
|
|
|
+ rx_desc_get_buffer(s->rx_desc[q]));
|
|
|
|
|
|
/* Copy packet data to emulated DMA buffer */
|
|
|
- cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc) + rxbuf_offset,
|
|
|
+ cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc[q]) +
|
|
|
+ rxbuf_offset,
|
|
|
rxbuf_ptr, MIN(bytes_to_copy, rxbufsize));
|
|
|
rxbuf_ptr += MIN(bytes_to_copy, rxbufsize);
|
|
|
bytes_to_copy -= MIN(bytes_to_copy, rxbufsize);
|
|
|
|
|
|
/* Update the descriptor. */
|
|
|
if (first_desc) {
|
|
|
- rx_desc_set_sof(s->rx_desc);
|
|
|
+ rx_desc_set_sof(s->rx_desc[q]);
|
|
|
first_desc = false;
|
|
|
}
|
|
|
if (bytes_to_copy == 0) {
|
|
|
- rx_desc_set_eof(s->rx_desc);
|
|
|
- rx_desc_set_length(s->rx_desc, size);
|
|
|
+ rx_desc_set_eof(s->rx_desc[q]);
|
|
|
+ rx_desc_set_length(s->rx_desc[q], size);
|
|
|
}
|
|
|
- rx_desc_set_ownership(s->rx_desc);
|
|
|
+ rx_desc_set_ownership(s->rx_desc[q]);
|
|
|
|
|
|
switch (maf) {
|
|
|
case GEM_RX_PROMISCUOUS_ACCEPT:
|
|
|
break;
|
|
|
case GEM_RX_BROADCAST_ACCEPT:
|
|
|
- rx_desc_set_broadcast(s->rx_desc);
|
|
|
+ rx_desc_set_broadcast(s->rx_desc[q]);
|
|
|
break;
|
|
|
case GEM_RX_UNICAST_HASH_ACCEPT:
|
|
|
- rx_desc_set_unicast_hash(s->rx_desc);
|
|
|
+ rx_desc_set_unicast_hash(s->rx_desc[q]);
|
|
|
break;
|
|
|
case GEM_RX_MULTICAST_HASH_ACCEPT:
|
|
|
- rx_desc_set_multicast_hash(s->rx_desc);
|
|
|
+ rx_desc_set_multicast_hash(s->rx_desc[q]);
|
|
|
break;
|
|
|
case GEM_RX_REJECT:
|
|
|
abort();
|
|
|
default: /* SAR */
|
|
|
- rx_desc_set_sar(s->rx_desc, maf);
|
|
|
+ rx_desc_set_sar(s->rx_desc[q], maf);
|
|
|
}
|
|
|
|
|
|
/* Descriptor write-back. */
|
|
|
- cpu_physical_memory_write(s->rx_desc_addr,
|
|
|
- (uint8_t *)s->rx_desc, sizeof(s->rx_desc));
|
|
|
+ cpu_physical_memory_write(s->rx_desc_addr[q],
|
|
|
+ (uint8_t *)s->rx_desc[q],
|
|
|
+ sizeof(s->rx_desc[q]));
|
|
|
|
|
|
/* Next descriptor */
|
|
|
- if (rx_desc_get_wrap(s->rx_desc)) {
|
|
|
+ if (rx_desc_get_wrap(s->rx_desc[q])) {
|
|
|
DB_PRINT("wrapping RX descriptor list\n");
|
|
|
- s->rx_desc_addr = s->regs[GEM_RXQBASE];
|
|
|
+ s->rx_desc_addr[q] = s->regs[GEM_RXQBASE];
|
|
|
} else {
|
|
|
DB_PRINT("incrementing RX descriptor list\n");
|
|
|
- s->rx_desc_addr += 8;
|
|
|
+ s->rx_desc_addr[q] += 8;
|
|
|
}
|
|
|
gem_get_rx_desc(s);
|
|
|
}
|
|
@@ -839,6 +843,7 @@ static void gem_transmit(CadenceGEMState *s)
|
|
|
uint8_t tx_packet[2048];
|
|
|
uint8_t *p;
|
|
|
unsigned total_bytes;
|
|
|
+ int q = 0;
|
|
|
|
|
|
/* Do nothing if transmit is not enabled. */
|
|
|
if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) {
|
|
@@ -855,7 +860,7 @@ static void gem_transmit(CadenceGEMState *s)
|
|
|
total_bytes = 0;
|
|
|
|
|
|
/* read current descriptor */
|
|
|
- packet_desc_addr = s->tx_desc_addr;
|
|
|
+ packet_desc_addr = s->tx_desc_addr[q];
|
|
|
|
|
|
DB_PRINT("read descriptor 0x%" HWADDR_PRIx "\n", packet_desc_addr);
|
|
|
cpu_physical_memory_read(packet_desc_addr,
|
|
@@ -902,18 +907,18 @@ static void gem_transmit(CadenceGEMState *s)
|
|
|
/* Modify the 1st descriptor of this packet to be owned by
|
|
|
* the processor.
|
|
|
*/
|
|
|
- cpu_physical_memory_read(s->tx_desc_addr, (uint8_t *)desc_first,
|
|
|
+ cpu_physical_memory_read(s->tx_desc_addr[q], (uint8_t *)desc_first,
|
|
|
sizeof(desc_first));
|
|
|
tx_desc_set_used(desc_first);
|
|
|
- cpu_physical_memory_write(s->tx_desc_addr, (uint8_t *)desc_first,
|
|
|
+ cpu_physical_memory_write(s->tx_desc_addr[q], (uint8_t *)desc_first,
|
|
|
sizeof(desc_first));
|
|
|
/* Advance the hardware current descriptor past this packet */
|
|
|
if (tx_desc_get_wrap(desc)) {
|
|
|
- s->tx_desc_addr = s->regs[GEM_TXQBASE];
|
|
|
+ s->tx_desc_addr[q] = s->regs[GEM_TXQBASE];
|
|
|
} else {
|
|
|
- s->tx_desc_addr = packet_desc_addr + 8;
|
|
|
+ s->tx_desc_addr[q] = packet_desc_addr + 8;
|
|
|
}
|
|
|
- DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr);
|
|
|
+ DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]);
|
|
|
|
|
|
s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL;
|
|
|
s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]);
|
|
@@ -1076,7 +1081,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
|
|
|
switch (offset) {
|
|
|
case GEM_ISR:
|
|
|
DB_PRINT("lowering irq on ISR read\n");
|
|
|
- qemu_set_irq(s->irq, 0);
|
|
|
+ qemu_set_irq(s->irq[0], 0);
|
|
|
break;
|
|
|
case GEM_PHYMNTNC:
|
|
|
if (retval & GEM_PHYMNTNC_OP_R) {
|
|
@@ -1139,7 +1144,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
|
|
}
|
|
|
if (!(val & GEM_NWCTRL_TXENA)) {
|
|
|
/* Reset to start of Q when transmit disabled. */
|
|
|
- s->tx_desc_addr = s->regs[GEM_TXQBASE];
|
|
|
+ s->tx_desc_addr[0] = s->regs[GEM_TXQBASE];
|
|
|
}
|
|
|
if (gem_can_receive(qemu_get_queue(s->nic))) {
|
|
|
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
|
@@ -1150,10 +1155,10 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
|
|
gem_update_int_status(s);
|
|
|
break;
|
|
|
case GEM_RXQBASE:
|
|
|
- s->rx_desc_addr = val;
|
|
|
+ s->rx_desc_addr[0] = val;
|
|
|
break;
|
|
|
case GEM_TXQBASE:
|
|
|
- s->tx_desc_addr = val;
|
|
|
+ s->tx_desc_addr[0] = val;
|
|
|
break;
|
|
|
case GEM_RXSTATUS:
|
|
|
gem_update_int_status(s);
|
|
@@ -1218,7 +1223,14 @@ static void gem_realize(DeviceState *dev, Error **errp)
|
|
|
{
|
|
|
CadenceGEMState *s = CADENCE_GEM(dev);
|
|
|
|
|
|
- sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
|
|
|
+ if (s->num_priority_queues == 0 ||
|
|
|
+ s->num_priority_queues > MAX_PRIORITY_QUEUES) {
|
|
|
+ error_setg(errp, "Invalid num-priority-queues value: %" PRIx8,
|
|
|
+ s->num_priority_queues);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]);
|
|
|
|
|
|
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
|
|
|
|
@@ -1242,14 +1254,16 @@ static void gem_init(Object *obj)
|
|
|
|
|
|
static const VMStateDescription vmstate_cadence_gem = {
|
|
|
.name = "cadence_gem",
|
|
|
- .version_id = 2,
|
|
|
- .minimum_version_id = 2,
|
|
|
+ .version_id = 3,
|
|
|
+ .minimum_version_id = 3,
|
|
|
.fields = (VMStateField[]) {
|
|
|
VMSTATE_UINT32_ARRAY(regs, CadenceGEMState, CADENCE_GEM_MAXREG),
|
|
|
VMSTATE_UINT16_ARRAY(phy_regs, CadenceGEMState, 32),
|
|
|
VMSTATE_UINT8(phy_loop, CadenceGEMState),
|
|
|
- VMSTATE_UINT32(rx_desc_addr, CadenceGEMState),
|
|
|
- VMSTATE_UINT32(tx_desc_addr, CadenceGEMState),
|
|
|
+ VMSTATE_UINT32_ARRAY(rx_desc_addr, CadenceGEMState,
|
|
|
+ MAX_PRIORITY_QUEUES),
|
|
|
+ VMSTATE_UINT32_ARRAY(tx_desc_addr, CadenceGEMState,
|
|
|
+ MAX_PRIORITY_QUEUES),
|
|
|
VMSTATE_BOOL_ARRAY(sar_active, CadenceGEMState, 4),
|
|
|
VMSTATE_END_OF_LIST(),
|
|
|
}
|
|
@@ -1257,6 +1271,8 @@ static const VMStateDescription vmstate_cadence_gem = {
|
|
|
|
|
|
static Property gem_properties[] = {
|
|
|
DEFINE_NIC_PROPERTIES(CadenceGEMState, conf),
|
|
|
+ DEFINE_PROP_UINT8("num-priority-queues", CadenceGEMState,
|
|
|
+ num_priority_queues, 1),
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
};
|
|
|
|