[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 19/27] hw/net/can/xlnx-versal-canfd: Translate CAN ID registers
From: |
Peter Maydell |
Subject: |
[PULL 19/27] hw/net/can/xlnx-versal-canfd: Translate CAN ID registers |
Date: |
Fri, 13 Sep 2024 16:14:03 +0100 |
From: Doug Brown <doug@schmorgal.com>
Previously the emulated CAN ID register was being set to the exact same
value stored in qemu_can_frame.can_id. This doesn't work correctly
because the Xilinx IP core uses a different bit arrangement than
qemu_can_frame for all of its ID registers. Correct this problem for
both RX and TX, including RX filtering.
Signed-off-by: Doug Brown <doug@schmorgal.com>
Reviewed-by: Francisco Iglesias <francisco.iglesias@amd.com>
Acked-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
Message-id: 20240827034927.66659-4-doug@schmorgal.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/net/can/xlnx-versal-canfd.c | 53 ++++++++++++++++++++++++++++++++--
1 file changed, 50 insertions(+), 3 deletions(-)
diff --git a/hw/net/can/xlnx-versal-canfd.c b/hw/net/can/xlnx-versal-canfd.c
index add1e0fbf17..9e825746736 100644
--- a/hw/net/can/xlnx-versal-canfd.c
+++ b/hw/net/can/xlnx-versal-canfd.c
@@ -869,6 +869,8 @@ static void regs2frame(XlnxVersalCANFDState *s,
qemu_can_frame *frame,
uint32_t val = 0;
uint32_t dlc_reg_val = 0;
uint32_t dlc_value = 0;
+ uint32_t id_reg_val = 0;
+ bool is_rtr = false;
/* Check that reg_num should be within TX register space. */
assert(reg_num <= R_TB_ID_REGISTER + (NUM_REGS_PER_MSG_SPACE *
@@ -877,7 +879,20 @@ static void regs2frame(XlnxVersalCANFDState *s,
qemu_can_frame *frame,
dlc_reg_val = s->regs[reg_num + 1];
dlc_value = FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, DLC);
- frame->can_id = s->regs[reg_num];
+ id_reg_val = s->regs[reg_num];
+ if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, IDE)) {
+ frame->can_id = (FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID) << 18) |
+ (FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID_EXT)) |
+ QEMU_CAN_EFF_FLAG;
+ if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, RTR_RRS)) {
+ is_rtr = true;
+ }
+ } else {
+ frame->can_id = FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID);
+ if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, SRR_RTR_RRS)) {
+ is_rtr = true;
+ }
+ }
if (FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, FDF)) {
/*
@@ -923,6 +938,10 @@ static void regs2frame(XlnxVersalCANFDState *s,
qemu_can_frame *frame,
} else {
frame->can_dlc = dlc_value;
}
+
+ if (is_rtr) {
+ frame->can_id |= QEMU_CAN_RTR_FLAG;
+ }
}
for (j = 0; j < frame->can_dlc; j++) {
@@ -948,6 +967,33 @@ static void
process_cancellation_requests(XlnxVersalCANFDState *s)
canfd_update_irq(s);
}
+static uint32_t frame_to_reg_id(const qemu_can_frame *frame)
+{
+ uint32_t id_reg_val = 0;
+ const bool is_canfd_frame = frame->flags & QEMU_CAN_FRMF_TYPE_FD;
+ const bool is_rtr = !is_canfd_frame && (frame->can_id & QEMU_CAN_RTR_FLAG);
+
+ if (frame->can_id & QEMU_CAN_EFF_FLAG) {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID,
+ (frame->can_id & QEMU_CAN_EFF_MASK) >> 18);
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID_EXT,
+ frame->can_id & QEMU_CAN_EFF_MASK);
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, IDE, 1);
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, SRR_RTR_RRS, 1);
+ if (is_rtr) {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, RTR_RRS, 1);
+ }
+ } else {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID,
+ frame->can_id & QEMU_CAN_SFF_MASK);
+ if (is_rtr) {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, SRR_RTR_RRS, 1);
+ }
+ }
+
+ return id_reg_val;
+}
+
static void store_rx_sequential(XlnxVersalCANFDState *s,
const qemu_can_frame *frame,
uint32_t fill_level, uint32_t read_index,
@@ -999,7 +1045,7 @@ static void store_rx_sequential(XlnxVersalCANFDState *s,
NUM_REGS_PER_MSG_SPACE));
}
- s->regs[store_location] = frame->can_id;
+ s->regs[store_location] = frame_to_reg_id(frame);
dlc = frame->can_dlc;
@@ -1090,11 +1136,12 @@ static void update_rx_sequential(XlnxVersalCANFDState
*s,
if (s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER]) {
uint32_t acceptance_filter_status =
s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER];
+ const uint32_t reg_id = frame_to_reg_id(frame);
for (i = 0; i < 32; i++) {
if (acceptance_filter_status & 0x1) {
uint32_t msg_id_masked = s->regs[R_AFMR_REGISTER + 2 * i] &
- frame->can_id;
+ reg_id;
uint32_t afir_id_masked = s->regs[R_AFIR_REGISTER + 2 * i] &
s->regs[R_AFMR_REGISTER + 2 * i];
uint16_t std_msg_id_masked = FIELD_EX32(msg_id_masked,
--
2.34.1
- [PULL 17/27] hw/net/can/xlnx-versal-canfd: Fix interrupt level, (continued)
- [PULL 17/27] hw/net/can/xlnx-versal-canfd: Fix interrupt level, Peter Maydell, 2024/09/13
- [PULL 16/27] target/arm/tcg: refine cache descriptions with a wrapper, Peter Maydell, 2024/09/13
- [PULL 08/27] hw: Rename DeviceClass::reset field to legacy_reset, Peter Maydell, 2024/09/13
- [PULL 23/27] hw/net/can/xlnx-versal-canfd: Fix FIFO issues, Peter Maydell, 2024/09/13
- [PULL 20/27] hw/net/can/xlnx-versal-canfd: Handle flags correctly, Peter Maydell, 2024/09/13
- [PULL 10/27] hw/core/qdev: Simplify legacy_reset handling, Peter Maydell, 2024/09/13
- [PULL 12/27] kvm: Use 'unsigned long' for request argument in functions wrapping ioctl(), Peter Maydell, 2024/09/13
- [PULL 18/27] hw/net/can/xlnx-versal-canfd: Fix CAN FD flag check, Peter Maydell, 2024/09/13
- [PULL 22/27] hw/net/can/xlnx-versal-canfd: Simplify DLC conversions, Peter Maydell, 2024/09/13
- [PULL 27/27] hw/intc/arm_gic: fix spurious level triggered interrupts, Peter Maydell, 2024/09/13
- [PULL 19/27] hw/net/can/xlnx-versal-canfd: Translate CAN ID registers,
Peter Maydell <=
- [PULL 15/27] hvf: arm: Implement and use hvf_get_physical_address_range, Peter Maydell, 2024/09/13
- [PULL 07/27] hw: Use device_class_set_legacy_reset() instead of opencoding, Peter Maydell, 2024/09/13
- [PULL 11/27] hw/core/resettable: Remove transitional_function machinery, Peter Maydell, 2024/09/13
- [PULL 14/27] hvf: Split up hv_vm_create logic per arch, Peter Maydell, 2024/09/13
- [PULL 26/27] MAINTAINERS: Add my-self as CAN maintainer, Peter Maydell, 2024/09/13
- Re: [PULL 00/27] target-arm queue, Peter Maydell, 2024/09/13