Skip to content

Commit 1423885

Browse files
committed
cxl/hdm: Use 4-byte reads to retrieve HDM decoder base+limit
The CXL specification mandates that 4-byte registers must be accessed with 4-byte access cycles. CXL 3.0 8.2.3 "Component Register Layout and Definition" states that the behavior is undefined if (2) 32-bit registers are accessed as an 8-byte quantity. It turns out that at least one hardware implementation is sensitive to this in practice. The @SiZe variable results in zero with: size = readq(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which)); ...and the correct size with: lo = readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which)); hi = readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(which)); size = (hi << 32) + lo; Fixes: d17d054 ("cxl/core/hdm: Add CXL standard decoder enumeration to the core") Cc: <stable@vger.kernel.org> Reviewed-by: Dave Jiang <dave.jiang@intel.com> Reviewed-by: Alison Schofield <alison.schofield@intel.com> Link: https://lore.kernel.org/r/168149844056.792294.8224490474529733736.stgit@dwillia2-xfh.jf.intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent 7701c8b commit 1423885

1 file changed

Lines changed: 13 additions & 7 deletions

File tree

drivers/cxl/core/hdm.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
3-
#include <linux/io-64-nonatomic-hi-lo.h>
43
#include <linux/seq_file.h>
54
#include <linux/device.h>
65
#include <linux/delay.h>
@@ -785,8 +784,8 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
785784
int *target_map, void __iomem *hdm, int which,
786785
u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)
787786
{
787+
u64 size, base, skip, dpa_size, lo, hi;
788788
struct cxl_endpoint_decoder *cxled;
789-
u64 size, base, skip, dpa_size;
790789
bool committed;
791790
u32 remainder;
792791
int i, rc;
@@ -801,8 +800,12 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
801800
which, info);
802801

803802
ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which));
804-
base = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which));
805-
size = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which));
803+
lo = readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which));
804+
hi = readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(which));
805+
base = (hi << 32) + lo;
806+
lo = readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which));
807+
hi = readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(which));
808+
size = (hi << 32) + lo;
806809
committed = !!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED);
807810
cxld->commit = cxl_decoder_commit;
808811
cxld->reset = cxl_decoder_reset;
@@ -865,8 +868,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
865868
return rc;
866869

867870
if (!info) {
868-
target_list.value =
869-
ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which));
871+
lo = readl(hdm + CXL_HDM_DECODER0_TL_LOW(which));
872+
hi = readl(hdm + CXL_HDM_DECODER0_TL_HIGH(which));
873+
target_list.value = (hi << 32) + lo;
870874
for (i = 0; i < cxld->interleave_ways; i++)
871875
target_map[i] = target_list.target_id[i];
872876

@@ -883,7 +887,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
883887
port->id, cxld->id, size, cxld->interleave_ways);
884888
return -ENXIO;
885889
}
886-
skip = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SKIP_LOW(which));
890+
lo = readl(hdm + CXL_HDM_DECODER0_SKIP_LOW(which));
891+
hi = readl(hdm + CXL_HDM_DECODER0_SKIP_HIGH(which));
892+
skip = (hi << 32) + lo;
887893
cxled = to_cxl_endpoint_decoder(&cxld->dev);
888894
rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip);
889895
if (rc) {

0 commit comments

Comments
 (0)