|
@@ -60,6 +60,12 @@
|
|
#define CTRL_P 0x2
|
|
#define CTRL_P 0x2
|
|
#define CTRL_S 0x1
|
|
#define CTRL_S 0x1
|
|
|
|
|
|
|
|
+typedef struct XlnxXpsEthLitePort {
|
|
|
|
+ struct {
|
|
|
|
+ uint32_t rx_ctrl;
|
|
|
|
+ } reg;
|
|
|
|
+} XlnxXpsEthLitePort;
|
|
|
|
+
|
|
#define TYPE_XILINX_ETHLITE "xlnx.xps-ethernetlite"
|
|
#define TYPE_XILINX_ETHLITE "xlnx.xps-ethernetlite"
|
|
OBJECT_DECLARE_SIMPLE_TYPE(XlnxXpsEthLite, XILINX_ETHLITE)
|
|
OBJECT_DECLARE_SIMPLE_TYPE(XlnxXpsEthLite, XILINX_ETHLITE)
|
|
|
|
|
|
@@ -77,6 +83,7 @@ struct XlnxXpsEthLite
|
|
unsigned int port_index; /* dual port RAM index */
|
|
unsigned int port_index; /* dual port RAM index */
|
|
|
|
|
|
UnimplementedDeviceState mdio;
|
|
UnimplementedDeviceState mdio;
|
|
|
|
+ XlnxXpsEthLitePort port[2];
|
|
uint32_t regs[R_MAX];
|
|
uint32_t regs[R_MAX];
|
|
};
|
|
};
|
|
|
|
|
|
@@ -100,10 +107,18 @@ static void *txbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
|
|
return &s->regs[rxbase + R_TX_BUF0];
|
|
return &s->regs[rxbase + R_TX_BUF0];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void *rxbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
|
|
|
|
+{
|
|
|
|
+ unsigned int rxbase = port_index * (0x800 / 4);
|
|
|
|
+
|
|
|
|
+ return &s->regs[rxbase + R_RX_BUF0];
|
|
|
|
+}
|
|
|
|
+
|
|
static uint64_t
|
|
static uint64_t
|
|
eth_read(void *opaque, hwaddr addr, unsigned int size)
|
|
eth_read(void *opaque, hwaddr addr, unsigned int size)
|
|
{
|
|
{
|
|
XlnxXpsEthLite *s = opaque;
|
|
XlnxXpsEthLite *s = opaque;
|
|
|
|
+ unsigned port_index = addr_to_port_index(addr);
|
|
uint32_t r = 0;
|
|
uint32_t r = 0;
|
|
|
|
|
|
addr >>= 2;
|
|
addr >>= 2;
|
|
@@ -115,9 +130,12 @@ eth_read(void *opaque, hwaddr addr, unsigned int size)
|
|
case R_TX_LEN1:
|
|
case R_TX_LEN1:
|
|
case R_TX_CTRL1:
|
|
case R_TX_CTRL1:
|
|
case R_TX_CTRL0:
|
|
case R_TX_CTRL0:
|
|
|
|
+ r = s->regs[addr];
|
|
|
|
+ break;
|
|
|
|
+
|
|
case R_RX_CTRL1:
|
|
case R_RX_CTRL1:
|
|
case R_RX_CTRL0:
|
|
case R_RX_CTRL0:
|
|
- r = s->regs[addr];
|
|
|
|
|
|
+ r = s->port[port_index].reg.rx_ctrl;
|
|
break;
|
|
break;
|
|
|
|
|
|
default:
|
|
default:
|
|
@@ -167,7 +185,9 @@ eth_write(void *opaque, hwaddr addr,
|
|
if (!(value & CTRL_S)) {
|
|
if (!(value & CTRL_S)) {
|
|
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
|
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
|
}
|
|
}
|
|
- /* fall through */
|
|
|
|
|
|
+ s->port[port_index].reg.rx_ctrl = value;
|
|
|
|
+ break;
|
|
|
|
+
|
|
case R_TX_LEN0:
|
|
case R_TX_LEN0:
|
|
case R_TX_LEN1:
|
|
case R_TX_LEN1:
|
|
case R_TX_GIE0:
|
|
case R_TX_GIE0:
|
|
@@ -197,22 +217,21 @@ static const MemoryRegionOps eth_ops = {
|
|
static bool eth_can_rx(NetClientState *nc)
|
|
static bool eth_can_rx(NetClientState *nc)
|
|
{
|
|
{
|
|
XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
|
|
XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
|
|
- unsigned int rxbase = s->port_index * (0x800 / 4);
|
|
|
|
|
|
|
|
- return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S);
|
|
|
|
|
|
+ return !(s->port[s->port_index].reg.rx_ctrl & CTRL_S);
|
|
}
|
|
}
|
|
|
|
|
|
static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
|
|
static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
|
|
{
|
|
{
|
|
XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
|
|
XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
|
|
- unsigned int rxbase = s->port_index * (0x800 / 4);
|
|
|
|
|
|
+ unsigned int port_index = s->port_index;
|
|
|
|
|
|
/* DA filter. */
|
|
/* DA filter. */
|
|
if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
|
|
if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
|
|
return size;
|
|
return size;
|
|
|
|
|
|
- if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
|
|
|
|
- trace_ethlite_pkt_lost(s->regs[R_RX_CTRL0]);
|
|
|
|
|
|
+ if (s->port[port_index].reg.rx_ctrl & CTRL_S) {
|
|
|
|
+ trace_ethlite_pkt_lost(s->port[port_index].reg.rx_ctrl);
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -220,10 +239,10 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
|
|
trace_ethlite_pkt_size_too_big(size);
|
|
trace_ethlite_pkt_size_too_big(size);
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
- memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
|
|
|
|
|
|
+ memcpy(rxbuf_ptr(s, port_index), buf, size);
|
|
|
|
|
|
- s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
|
|
|
|
- if (s->regs[R_RX_CTRL0] & CTRL_I) {
|
|
|
|
|
|
+ s->port[port_index].reg.rx_ctrl |= CTRL_S;
|
|
|
|
+ if (s->port[port_index].reg.rx_ctrl & CTRL_I) {
|
|
eth_pulse_irq(s);
|
|
eth_pulse_irq(s);
|
|
}
|
|
}
|
|
|
|
|