[PATCH v5 2/4] cxl/hdm: Make switch decoder target parsing endian-safe
Alison Schofield <[email protected]>
| Newsgroups | org.kernel.vger.linux-cxl |
|---|---|
| Message-ID | <b0526825b3c3ffdb78837563e178d9aa27b6bbb8.1786143520.git.alison.schofield@intel.com> |
Switch decoder target IDs are stored one per byte, starting with
target 0 in the least significant byte. The current code accesses
those bytes in memory order, which only matches register order on
little-endian hosts.
On big-endian hosts, the target IDs are reversed and the decoder is
associated with the wrong downstream ports.
Place the register values in a byte array in little-endian order and
index the target IDs from there, so the target mapping is independent
of host endianness.
Fixes: d17d0540a0db ("cxl/core/hdm: Add CXL standard decoder enumeration to the core")
Signed-off-by: Alison Schofield <[email protected]>
---
drivers/cxl/core/hdm.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index c394b3d54d36..fc22d515b638 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
#include <linux/seq_file.h>
+#include <linux/unaligned.h>
#include <linux/device.h>
#include <linux/delay.h>
@@ -975,15 +976,12 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)
{
struct cxl_endpoint_decoder *cxled = NULL;
+ u8 target_id[CXL_HDM_DECODER0_TL_TARGETS];
u64 size, base, skip, dpa_size, lo, hi;
bool committed;
u32 remainder;
int i, rc;
u32 ctrl;
- union {
- u64 value;
- unsigned char target_id[8];
- } target_list;
if (should_emulate_decoders(info))
return cxl_setup_hdm_decoder_from_dvsec(port, cxld, dpa_base,
@@ -1096,11 +1094,12 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
return -ENXIO;
}
- lo = readl(hdm + CXL_HDM_DECODER0_TL_LOW(which));
- hi = readl(hdm + CXL_HDM_DECODER0_TL_HIGH(which));
- target_list.value = (hi << 32) + lo;
+ put_unaligned_le32(readl(hdm + CXL_HDM_DECODER0_TL_LOW(which)),
+ &target_id[0]);
+ put_unaligned_le32(readl(hdm + CXL_HDM_DECODER0_TL_HIGH(which)),
+ &target_id[4]);
for (i = 0; i < cxld->interleave_ways; i++)
- cxld->target_map[i] = target_list.target_id[i];
+ cxld->target_map[i] = target_id[i];
return 0;
}
--
2.37.3