From 8729856c1904c11a9b016cba600767f814e237b1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 24 Nov 2023 19:33:25 +0100 Subject: [PATCH] hw/net/can/xlnx-zynqmp: Avoid underflow while popping RX FIFO MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Per https://docs.xilinx.com/r/en-US/ug1085-zynq-ultrascale-trm/Message-Format Message Format The same message format is used for RXFIFO, TXFIFO, and TXHPB. Each message includes four words (16 bytes). Software must read and write all four words regardless of the actual number of data bytes and valid fields in the message. There is no mention in this reference manual about what the hardware does when not all four words are read. To fix the reported underflow behavior, I choose to fill the 4 frame data registers when the first register (ID) is accessed, which is how I expect hardware would do. Reported-by: Qiang Liu Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Francisco Iglesias Reviewed-by: Vikram Garhwal Message-id: 20231124183325.95392-3-philmd@linaro.org Fixes: 98e5d7a2b7 ("hw/net/can: Introduce Xilinx ZynqMP CAN controller") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1427 Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Francisco Iglesias Reviewed-by: Vikram Garhwal Signed-off-by: Peter Maydell Reviewed-by: Peter Maydell --- hw/net/can/xlnx-zynqmp-can.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c index 1f1c686479..f60e480c3a 100644 --- a/hw/net/can/xlnx-zynqmp-can.c +++ b/hw/net/can/xlnx-zynqmp-can.c @@ -778,14 +778,18 @@ static void update_rx_fifo(XlnxZynqMPCANState *s, const qemu_can_frame *frame) } } -static uint64_t can_rxfifo_pre_read(RegisterInfo *reg, uint64_t val) +static uint64_t can_rxfifo_post_read_id(RegisterInfo *reg, uint64_t val) { XlnxZynqMPCANState *s = XLNX_ZYNQMP_CAN(reg->opaque); + unsigned used = fifo32_num_used(&s->rx_fifo); - if (!fifo32_is_empty(&s->rx_fifo)) { - val = fifo32_pop(&s->rx_fifo); - } else { + if (used < CAN_FRAME_SIZE) { ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXUFLW, 1); + } else { + val = s->regs[R_RXFIFO_ID] = fifo32_pop(&s->rx_fifo); + s->regs[R_RXFIFO_DLC] = fifo32_pop(&s->rx_fifo); + s->regs[R_RXFIFO_DATA1] = fifo32_pop(&s->rx_fifo); + s->regs[R_RXFIFO_DATA2] = fifo32_pop(&s->rx_fifo); } can_update_irq(s); @@ -946,14 +950,11 @@ static const RegisterAccessInfo can_regs_info[] = { .post_write = can_tx_post_write, },{ .name = "RXFIFO_ID", .addr = A_RXFIFO_ID, .ro = 0xffffffff, - .post_read = can_rxfifo_pre_read, + .post_read = can_rxfifo_post_read_id, },{ .name = "RXFIFO_DLC", .addr = A_RXFIFO_DLC, .rsvd = 0xfff0000, - .post_read = can_rxfifo_pre_read, },{ .name = "RXFIFO_DATA1", .addr = A_RXFIFO_DATA1, - .post_read = can_rxfifo_pre_read, },{ .name = "RXFIFO_DATA2", .addr = A_RXFIFO_DATA2, - .post_read = can_rxfifo_pre_read, },{ .name = "AFR", .addr = A_AFR, .rsvd = 0xfffffff0, .post_write = can_filter_enable_post_write, -- 2.30.2