axienet: Flush queued packets when rx is done
eth_can_rx checks s->rxsize and returns false if it is non-zero. Because of the .can_receive semantics change, this will make the incoming queue disabled by peer, until it is explicitly flushed. So we should flush it when s->rxsize is becoming zero. Squash eth_can_rx semantics into etx_rx and drop .can_receive() callback, also add flush when rx buffer becomes available again after a packet gets queued. The other conditions, "!axienet_rx_resetting(s) && axienet_rx_enabled(s)" are OK because enet_write already calls qemu_flush_queued_packets when the register bits are changed. Signed-off-by: Fam Zheng <famz@redhat.com> Reviewed-by: Jason Wang <jasowang@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 1436955553-22791-13-git-send-email-famz@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
		
							parent
							
								
									4594f93a73
								
							
						
					
					
						commit
						f9f7492ea4
					
				| 
						 | 
					@ -401,6 +401,9 @@ struct XilinxAXIEnet {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t rxapp[CONTROL_PAYLOAD_SIZE];
 | 
					    uint8_t rxapp[CONTROL_PAYLOAD_SIZE];
 | 
				
			||||||
    uint32_t rxappsize;
 | 
					    uint32_t rxappsize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Whether axienet_eth_rx_notify should flush incoming queue. */
 | 
				
			||||||
 | 
					    bool need_flush;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void axienet_rx_reset(XilinxAXIEnet *s)
 | 
					static void axienet_rx_reset(XilinxAXIEnet *s)
 | 
				
			||||||
| 
						 | 
					@ -658,10 +661,8 @@ static const MemoryRegionOps enet_ops = {
 | 
				
			||||||
    .endianness = DEVICE_LITTLE_ENDIAN,
 | 
					    .endianness = DEVICE_LITTLE_ENDIAN,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int eth_can_rx(NetClientState *nc)
 | 
					static int eth_can_rx(XilinxAXIEnet *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* RX enabled?  */
 | 
					    /* RX enabled?  */
 | 
				
			||||||
    return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s);
 | 
					    return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -701,6 +702,10 @@ static void axienet_eth_rx_notify(void *opaque)
 | 
				
			||||||
        s->rxpos += ret;
 | 
					        s->rxpos += ret;
 | 
				
			||||||
        if (!s->rxsize) {
 | 
					        if (!s->rxsize) {
 | 
				
			||||||
            s->regs[R_IS] |= IS_RX_COMPLETE;
 | 
					            s->regs[R_IS] |= IS_RX_COMPLETE;
 | 
				
			||||||
 | 
					            if (s->need_flush) {
 | 
				
			||||||
 | 
					                s->need_flush = false;
 | 
				
			||||||
 | 
					                qemu_flush_queued_packets(qemu_get_queue(s->nic));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    enet_update_irq(s);
 | 
					    enet_update_irq(s);
 | 
				
			||||||
| 
						 | 
					@ -721,6 +726,11 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DENET(qemu_log("%s: %zd bytes\n", __func__, size));
 | 
					    DENET(qemu_log("%s: %zd bytes\n", __func__, size));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!eth_can_rx(s)) {
 | 
				
			||||||
 | 
					        s->need_flush = true;
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unicast = ~buf[0] & 0x1;
 | 
					    unicast = ~buf[0] & 0x1;
 | 
				
			||||||
    broadcast = memcmp(buf, sa_bcast, 6) == 0;
 | 
					    broadcast = memcmp(buf, sa_bcast, 6) == 0;
 | 
				
			||||||
    multicast = !unicast && !broadcast;
 | 
					    multicast = !unicast && !broadcast;
 | 
				
			||||||
| 
						 | 
					@ -925,7 +935,6 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size)
 | 
				
			||||||
static NetClientInfo net_xilinx_enet_info = {
 | 
					static NetClientInfo net_xilinx_enet_info = {
 | 
				
			||||||
    .type = NET_CLIENT_OPTIONS_KIND_NIC,
 | 
					    .type = NET_CLIENT_OPTIONS_KIND_NIC,
 | 
				
			||||||
    .size = sizeof(NICState),
 | 
					    .size = sizeof(NICState),
 | 
				
			||||||
    .can_receive = eth_can_rx,
 | 
					 | 
				
			||||||
    .receive = eth_rx,
 | 
					    .receive = eth_rx,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue