Xilinx ZynqMP CAN controller logical error - mixed RX and TX channels
Host environment
- Operating system: -
- OS/kernel version: -
- Architecture: -
- QEMU flavor: qemu-system-arm
- QEMU version: any
- QEMU command line:
./qemu-system-arm -M xlnx-zcu102 <anything>
Emulated/Virtualized environment
- Operating system: anything
- OS/kernel version: -
- Architecture: ARM
Description of problem
In the code of CAN controller of Xilinx ZynqMP board (hw/net/can/xlnx-zynqmp-can.c
) in function update_rx_fifo()
there seems to be a typo or logical error mixing RX and TX buffers:
/* Store the message in fifo if it passed through any of the filters. */
if (filter_pass && frame->can_dlc <= MAX_DLC) {
if (fifo32_is_full(&s->rx_fifo)) {
ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOFLW, 1);
} else {
timestamp = CAN_TIMER_MAX - ptimer_get_count(s->can_timer);
fifo32_push(&s->rx_fifo, frame->can_id);
fifo32_push(&s->rx_fifo, deposit32(0, R_RXFIFO_DLC_DLC_SHIFT,
R_RXFIFO_DLC_DLC_LENGTH,
frame->can_dlc) |
deposit32(0, R_RXFIFO_DLC_RXT_SHIFT,
R_RXFIFO_DLC_RXT_LENGTH,
timestamp));
/* First 32 bit of the data. */
fifo32_push(&s->rx_fifo, deposit32(0, R_TXFIFO_DATA1_DB3_SHIFT,
R_TXFIFO_DATA1_DB3_LENGTH,
frame->data[0]) |
deposit32(0, R_TXFIFO_DATA1_DB2_SHIFT,
R_TXFIFO_DATA1_DB2_LENGTH,
frame->data[1]) |
deposit32(0, R_TXFIFO_DATA1_DB1_SHIFT,
R_TXFIFO_DATA1_DB1_LENGTH,
frame->data[2]) |
deposit32(0, R_TXFIFO_DATA1_DB0_SHIFT,
R_TXFIFO_DATA1_DB0_LENGTH,
frame->data[3]));
Additional information
Possible fix:
git diff 12:29:23
diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c
index 82ac48cee2..e93e6c5e19 100644
--- a/hw/net/can/xlnx-zynqmp-can.c
+++ b/hw/net/can/xlnx-zynqmp-can.c
@@ -696,30 +696,30 @@ static void update_rx_fifo(XlnxZynqMPCANState *s, const qemu_can_frame *frame)
timestamp));
/* First 32 bit of the data. */
- fifo32_push(&s->rx_fifo, deposit32(0, R_TXFIFO_DATA1_DB3_SHIFT,
- R_TXFIFO_DATA1_DB3_LENGTH,
+ fifo32_push(&s->rx_fifo, deposit32(0, R_RXFIFO_DATA1_DB3_SHIFT,
+ R_RXFIFO_DATA1_DB3_LENGTH,
frame->data[0]) |
- deposit32(0, R_TXFIFO_DATA1_DB2_SHIFT,
- R_TXFIFO_DATA1_DB2_LENGTH,
+ deposit32(0, R_RXFIFO_DATA1_DB2_SHIFT,
+ R_RXFIFO_DATA1_DB2_LENGTH,
frame->data[1]) |
- deposit32(0, R_TXFIFO_DATA1_DB1_SHIFT,
- R_TXFIFO_DATA1_DB1_LENGTH,
+ deposit32(0, R_RXFIFO_DATA1_DB1_SHIFT,
+ R_RXFIFO_DATA1_DB1_LENGTH,
frame->data[2]) |
- deposit32(0, R_TXFIFO_DATA1_DB0_SHIFT,
- R_TXFIFO_DATA1_DB0_LENGTH,
+ deposit32(0, R_RXFIFO_DATA1_DB0_SHIFT,
+ R_RXFIFO_DATA1_DB0_LENGTH,
frame->data[3]));
/* Last 32 bit of the data. */
- fifo32_push(&s->rx_fifo, deposit32(0, R_TXFIFO_DATA2_DB7_SHIFT,
- R_TXFIFO_DATA2_DB7_LENGTH,
+ fifo32_push(&s->rx_fifo, deposit32(0, R_RXFIFO_DATA2_DB7_SHIFT,
+ R_RXFIFO_DATA2_DB7_LENGTH,
frame->data[4]) |
- deposit32(0, R_TXFIFO_DATA2_DB6_SHIFT,
- R_TXFIFO_DATA2_DB6_LENGTH,
+ deposit32(0, R_RXFIFO_DATA2_DB6_SHIFT,
+ R_RXFIFO_DATA2_DB6_LENGTH,
frame->data[5]) |
- deposit32(0, R_TXFIFO_DATA2_DB5_SHIFT,
- R_TXFIFO_DATA2_DB5_LENGTH,
+ deposit32(0, R_RXFIFO_DATA2_DB5_SHIFT,
+ R_RXFIFO_DATA2_DB5_LENGTH,
frame->data[6]) |
- deposit32(0, R_TXFIFO_DATA2_DB4_SHIFT,
- R_TXFIFO_DATA2_DB4_LENGTH,
+ deposit32(0, R_RXFIFO_DATA2_DB4_SHIFT,
+ R_RXFIFO_DATA2_DB4_LENGTH,
frame->data[7]));
ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOK, 1);
Edited by Anton Kochkov