cadence_gem: Add queue support
Signed-off-by: Alistair Francis <alistair.francis@xilinx.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 28921252217b1d14f16889bafa88675f5b7a66cb.1469727764.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
e8e4994313
commit
6710172501
@ -143,6 +143,30 @@
|
||||
#define GEM_DESCONF6 (0x00000294/4)
|
||||
#define GEM_DESCONF7 (0x00000298/4)
|
||||
|
||||
#define GEM_INT_Q1_STATUS (0x00000400 / 4)
|
||||
#define GEM_INT_Q1_MASK (0x00000640 / 4)
|
||||
|
||||
#define GEM_TRANSMIT_Q1_PTR (0x00000440 / 4)
|
||||
#define GEM_TRANSMIT_Q15_PTR (GEM_TRANSMIT_Q1_PTR + 14)
|
||||
|
||||
#define GEM_RECEIVE_Q1_PTR (0x00000480 / 4)
|
||||
#define GEM_RECEIVE_Q15_PTR (GEM_RECEIVE_Q1_PTR + 14)
|
||||
|
||||
#define GEM_INT_Q1_ENABLE (0x00000600 / 4)
|
||||
#define GEM_INT_Q7_ENABLE (GEM_INT_Q1_ENABLE + 6)
|
||||
#define GEM_INT_Q8_ENABLE (0x00000660 / 4)
|
||||
#define GEM_INT_Q15_ENABLE (GEM_INT_Q8_ENABLE + 7)
|
||||
|
||||
#define GEM_INT_Q1_DISABLE (0x00000620 / 4)
|
||||
#define GEM_INT_Q7_DISABLE (GEM_INT_Q1_DISABLE + 6)
|
||||
#define GEM_INT_Q8_DISABLE (0x00000680 / 4)
|
||||
#define GEM_INT_Q15_DISABLE (GEM_INT_Q8_DISABLE + 7)
|
||||
|
||||
#define GEM_INT_Q1_MASK (0x00000640 / 4)
|
||||
#define GEM_INT_Q7_MASK (GEM_INT_Q1_MASK + 6)
|
||||
#define GEM_INT_Q8_MASK (0x000006A0 / 4)
|
||||
#define GEM_INT_Q15_MASK (GEM_INT_Q8_MASK + 7)
|
||||
|
||||
#define GEM_SCREENING_TYPE1_REGISTER_0 (0x00000500 / 4)
|
||||
|
||||
#define GEM_ST1R_UDP_PORT_MATCH_ENABLE (1 << 29)
|
||||
@ -317,9 +341,9 @@ static inline unsigned tx_desc_get_length(unsigned *desc)
|
||||
return desc[1] & DESC_1_LENGTH;
|
||||
}
|
||||
|
||||
static inline void print_gem_tx_desc(unsigned *desc)
|
||||
static inline void print_gem_tx_desc(unsigned *desc, uint8_t queue)
|
||||
{
|
||||
DB_PRINT("TXDESC:\n");
|
||||
DB_PRINT("TXDESC (queue %" PRId8 "):\n", queue);
|
||||
DB_PRINT("bufaddr: 0x%08x\n", *desc);
|
||||
DB_PRINT("used_hw: %d\n", tx_desc_get_used(desc));
|
||||
DB_PRINT("wrap: %d\n", tx_desc_get_wrap(desc));
|
||||
@ -449,6 +473,7 @@ static void phy_update_link(CadenceGEMState *s)
|
||||
static int gem_can_receive(NetClientState *nc)
|
||||
{
|
||||
CadenceGEMState *s;
|
||||
int i;
|
||||
|
||||
s = qemu_get_nic_opaque(nc);
|
||||
|
||||
@ -461,18 +486,20 @@ static int gem_can_receive(NetClientState *nc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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[0]);
|
||||
for (i = 0; i < s->num_priority_queues; i++) {
|
||||
if (rx_desc_get_ownership(s->rx_desc[i]) == 1) {
|
||||
if (s->can_rx_state != 2) {
|
||||
s->can_rx_state = 2;
|
||||
DB_PRINT("can't receive - busy buffer descriptor (q%d) 0x%x\n",
|
||||
i, s->rx_desc_addr[i]);
|
||||
}
|
||||
return 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[0]);
|
||||
DB_PRINT("can receive\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -483,9 +510,20 @@ static int gem_can_receive(NetClientState *nc)
|
||||
*/
|
||||
static void gem_update_int_status(CadenceGEMState *s)
|
||||
{
|
||||
if (s->regs[GEM_ISR]) {
|
||||
DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]);
|
||||
int i;
|
||||
|
||||
if ((s->num_priority_queues == 1) && s->regs[GEM_ISR]) {
|
||||
/* No priority queues, just trigger the interrupt */
|
||||
DB_PRINT("asserting int.\n", i);
|
||||
qemu_set_irq(s->irq[0], 1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < s->num_priority_queues; ++i) {
|
||||
if (s->regs[GEM_INT_Q1_STATUS + i]) {
|
||||
DB_PRINT("asserting int. (q=%d)\n", i);
|
||||
qemu_set_irq(s->irq[i], 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -754,17 +792,17 @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gem_get_rx_desc(CadenceGEMState *s)
|
||||
static void gem_get_rx_desc(CadenceGEMState *s, int q)
|
||||
{
|
||||
DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[0]);
|
||||
DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[q]);
|
||||
/* read current descriptor */
|
||||
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[0]) == 1) {
|
||||
if (rx_desc_get_ownership(s->rx_desc[q]) == 1) {
|
||||
DB_PRINT("descriptor 0x%x owned by sw.\n",
|
||||
(unsigned)s->rx_desc_addr[0]);
|
||||
(unsigned)s->rx_desc_addr[q]);
|
||||
s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
|
||||
s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
|
||||
/* Handle interrupt consequences */
|
||||
@ -926,7 +964,8 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
DB_PRINT("incrementing RX descriptor list\n");
|
||||
s->rx_desc_addr[q] += 8;
|
||||
}
|
||||
gem_get_rx_desc(s);
|
||||
|
||||
gem_get_rx_desc(s, q);
|
||||
}
|
||||
|
||||
/* Count it */
|
||||
@ -1014,6 +1053,7 @@ static void gem_transmit(CadenceGEMState *s)
|
||||
p = tx_packet;
|
||||
total_bytes = 0;
|
||||
|
||||
for (q = s->num_priority_queues - 1; q >= 0; q--) {
|
||||
/* read current descriptor */
|
||||
packet_desc_addr = s->tx_desc_addr[q];
|
||||
|
||||
@ -1027,7 +1067,7 @@ static void gem_transmit(CadenceGEMState *s)
|
||||
if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) {
|
||||
return;
|
||||
}
|
||||
print_gem_tx_desc(desc);
|
||||
print_gem_tx_desc(desc, q);
|
||||
|
||||
/* The real hardware would eat this (and possibly crash).
|
||||
* For QEMU let's lend a helping hand.
|
||||
@ -1078,6 +1118,12 @@ static void gem_transmit(CadenceGEMState *s)
|
||||
s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL;
|
||||
s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]);
|
||||
|
||||
/* Update queue interrupt status */
|
||||
if (s->num_priority_queues > 1) {
|
||||
s->regs[GEM_INT_Q1_STATUS + q] |=
|
||||
GEM_INT_TXCMPL & ~(s->regs[GEM_INT_Q1_MASK + q]);
|
||||
}
|
||||
|
||||
/* Handle interrupt consequences */
|
||||
gem_update_int_status(s);
|
||||
|
||||
@ -1119,6 +1165,7 @@ static void gem_transmit(CadenceGEMState *s)
|
||||
s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]);
|
||||
gem_update_int_status(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gem_phy_reset(CadenceGEMState *s)
|
||||
@ -1225,7 +1272,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
CadenceGEMState *s;
|
||||
uint32_t retval;
|
||||
|
||||
int i;
|
||||
s = (CadenceGEMState *)opaque;
|
||||
|
||||
offset >>= 2;
|
||||
@ -1235,8 +1282,10 @@ 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], 0);
|
||||
DB_PRINT("lowering irqs on ISR read\n");
|
||||
for (i = 0; i < s->num_priority_queues; ++i) {
|
||||
qemu_set_irq(s->irq[i], 0);
|
||||
}
|
||||
break;
|
||||
case GEM_PHYMNTNC:
|
||||
if (retval & GEM_PHYMNTNC_OP_R) {
|
||||
@ -1261,6 +1310,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
|
||||
retval &= ~(s->regs_wo[offset]);
|
||||
|
||||
DB_PRINT("0x%08x\n", retval);
|
||||
gem_update_int_status(s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1273,6 +1323,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
||||
{
|
||||
CadenceGEMState *s = (CadenceGEMState *)opaque;
|
||||
uint32_t readonly;
|
||||
int i;
|
||||
|
||||
DB_PRINT("offset: 0x%04x write: 0x%08x ", (unsigned)offset, (unsigned)val);
|
||||
offset >>= 2;
|
||||
@ -1292,14 +1343,18 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
||||
switch (offset) {
|
||||
case GEM_NWCTRL:
|
||||
if (val & GEM_NWCTRL_RXENA) {
|
||||
gem_get_rx_desc(s);
|
||||
for (i = 0; i < s->num_priority_queues; ++i) {
|
||||
gem_get_rx_desc(s, i);
|
||||
}
|
||||
}
|
||||
if (val & GEM_NWCTRL_TXSTART) {
|
||||
gem_transmit(s);
|
||||
}
|
||||
if (!(val & GEM_NWCTRL_TXENA)) {
|
||||
/* Reset to start of Q when transmit disabled. */
|
||||
s->tx_desc_addr[0] = s->regs[GEM_TXQBASE];
|
||||
for (i = 0; i < s->num_priority_queues; i++) {
|
||||
s->tx_desc_addr[i] = s->regs[GEM_TXQBASE];
|
||||
}
|
||||
}
|
||||
if (gem_can_receive(qemu_get_queue(s->nic))) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
@ -1312,9 +1367,15 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
||||
case GEM_RXQBASE:
|
||||
s->rx_desc_addr[0] = val;
|
||||
break;
|
||||
case GEM_RECEIVE_Q1_PTR ... GEM_RECEIVE_Q15_PTR:
|
||||
s->rx_desc_addr[offset - GEM_RECEIVE_Q1_PTR + 1] = val;
|
||||
break;
|
||||
case GEM_TXQBASE:
|
||||
s->tx_desc_addr[0] = val;
|
||||
break;
|
||||
case GEM_TRANSMIT_Q1_PTR ... GEM_TRANSMIT_Q15_PTR:
|
||||
s->tx_desc_addr[offset - GEM_TRANSMIT_Q1_PTR + 1] = val;
|
||||
break;
|
||||
case GEM_RXSTATUS:
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
@ -1322,10 +1383,26 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
||||
s->regs[GEM_IMR] &= ~val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_INT_Q1_ENABLE ... GEM_INT_Q7_ENABLE:
|
||||
s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_INT_Q8_ENABLE ... GEM_INT_Q15_ENABLE:
|
||||
s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_ENABLE] &= ~val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_IDR:
|
||||
s->regs[GEM_IMR] |= val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_INT_Q1_DISABLE ... GEM_INT_Q7_DISABLE:
|
||||
s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_DISABLE] |= val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_INT_Q8_DISABLE ... GEM_INT_Q15_DISABLE:
|
||||
s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_DISABLE] |= val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_SPADDR1LO:
|
||||
case GEM_SPADDR2LO:
|
||||
case GEM_SPADDR3LO:
|
||||
@ -1362,8 +1439,11 @@ static const MemoryRegionOps gem_ops = {
|
||||
|
||||
static void gem_set_link(NetClientState *nc)
|
||||
{
|
||||
CadenceGEMState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
DB_PRINT("\n");
|
||||
phy_update_link(qemu_get_nic_opaque(nc));
|
||||
phy_update_link(s);
|
||||
gem_update_int_status(s);
|
||||
}
|
||||
|
||||
static NetClientInfo net_gem_info = {
|
||||
@ -1377,6 +1457,7 @@ static NetClientInfo net_gem_info = {
|
||||
static void gem_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CadenceGEMState *s = CADENCE_GEM(dev);
|
||||
int i;
|
||||
|
||||
if (s->num_priority_queues == 0 ||
|
||||
s->num_priority_queues > MAX_PRIORITY_QUEUES) {
|
||||
@ -1393,7 +1474,9 @@ static void gem_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]);
|
||||
for (i = 0; i < s->num_priority_queues; ++i) {
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
|
||||
}
|
||||
|
||||
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user