summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Jiang <dave.jiang@intel.com>2026-06-12 19:34:35 +0300
committerDave Jiang <dave.jiang@intel.com>2026-06-12 19:34:35 +0300
commite53ef72033b30f8ff0bf76adf956d4a27d1a2675 (patch)
tree4bb540d455251c83c2a5e13e098dce93a42cd0d1
parent26aa60e0276272ae61b843a05a91748dcb1130f9 (diff)
parentaa8a76711c15041ec1e42c3a74c15c2df0bd31f6 (diff)
downloadlinux-e53ef72033b30f8ff0bf76adf956d4a27d1a2675.tar.xz
Merge branch 'for-7.2/cxl-misc' into cxl-for-next
cxl/region: Fill first free targets[] slot during auto-discovery cxl/region: Fix out-of-bounds access in cxl_cancel_auto_attach() tools/testing/cxl: Resolve auto-region decoder targets like real HW cxl: Align interleave decode/encode helpers with their callers cxl/test: Add check after kzalloc() memory in alloc_mock_res() cxl/test: Unregister cxl_acpi in cxl_test_init() error path cxl/test: Zero out LSA backing memory to avoid leaking to user cxl/test: Fix integer overflow in mock LSA bounds checks cxl/test: Verify cmd->size_in before accessing payload cxl/port: update reference to removed CONFIG_PROVE_CXL_LOCKING cxl/region: Avoid variable shadowing in region attach paths cxl: Fix CXL_HEADERLOG_SIZE to match RAS Capability size cxl/test: Fix __fortify_panic cxl/fwctl: Fix __fortify_panic MAINTAINERS: Add CXL reviewer cxl/test: Enforce PMD alignment for volatile mock regions cxl/region: Validate partition index before array access cxl/memdev: Hold memdev lock during memdev poison injection/clear
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/cxl/acpi.c10
-rw-r--r--drivers/cxl/core/features.c2
-rw-r--r--drivers/cxl/core/ras.c27
-rw-r--r--drivers/cxl/core/region.c76
-rw-r--r--drivers/cxl/core/trace.h24
-rw-r--r--drivers/cxl/cxl.h20
-rw-r--r--drivers/cxl/mem.c10
-rw-r--r--drivers/cxl/port.c2
-rw-r--r--tools/testing/cxl/test/cxl.c41
-rw-r--r--tools/testing/cxl/test/cxl_translate.c2
-rw-r--r--tools/testing/cxl/test/mem.c45
12 files changed, 178 insertions, 82 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ec290e38b44..635b056a20c2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6437,6 +6437,7 @@ M: Alison Schofield <alison.schofield@intel.com>
M: Vishal Verma <vishal.l.verma@intel.com>
M: Ira Weiny <ira.weiny@intel.com>
M: Dan Williams <djbw@kernel.org>
+R: Li Ming <ming.li@zohomail.com>
L: linux-cxl@vger.kernel.org
S: Maintained
F: Documentation/driver-api/cxl
diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index 127537628817..3b818adbd38b 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -101,8 +101,8 @@ static int cxl_parse_cxims(union acpi_subtable_headers *header, void *arg,
struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
struct device *dev = ctx->dev;
struct cxl_cxims_data *cximsd;
- unsigned int hbig, nr_maps;
- int rc;
+ unsigned int nr_maps;
+ int hbig, rc;
rc = eig_to_granularity(cxims->hbig, &hbig);
if (rc)
@@ -160,7 +160,7 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
struct acpi_cedt_cfmws *cfmws)
{
int rc, expected_len;
- unsigned int ways;
+ int ways;
if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO &&
cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_XOR) {
@@ -405,7 +405,7 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
struct cxl_cxims_context cxims_ctx;
struct device *dev = ctx->dev;
struct cxl_decoder *cxld;
- unsigned int ways, i, ig;
+ int ways, i, ig;
int rc;
rc = cxl_acpi_cfmws_verify(dev, cfmws);
@@ -464,7 +464,7 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
if (rc < 0)
return rc;
if (!cxlrd->platform_data) {
- dev_err(dev, "No CXIMS for HBIG %u\n", ig);
+ dev_err(dev, "No CXIMS for HBIG %d\n", ig);
return -EINVAL;
}
}
diff --git a/drivers/cxl/core/features.c b/drivers/cxl/core/features.c
index 3435db9ea6b1..85185af46b72 100644
--- a/drivers/cxl/core/features.c
+++ b/drivers/cxl/core/features.c
@@ -423,6 +423,7 @@ static void *cxlctl_get_supported_features(struct cxl_features_state *cxlfs,
rpc_out->size = struct_size(feat_out, ents, requested);
feat_out = &rpc_out->get_sup_feats_out;
+ feat_out->num_entries = cpu_to_le16(requested);
for (i = start, pos = &feat_out->ents[0];
i < cxlfs->entries->num_features; i++, pos++) {
@@ -444,7 +445,6 @@ static void *cxlctl_get_supported_features(struct cxl_features_state *cxlfs,
}
}
- feat_out->num_entries = cpu_to_le16(requested);
feat_out->supported_feats = cpu_to_le16(cxlfs->entries->num_features);
rpc_out->retval = CXL_MBOX_CMD_RC_SUCCESS;
*out_len = out_size;
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 006c6ffc2f56..99fb00949c2f 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -8,6 +8,10 @@
#include <cxlpci.h>
#include "trace.h"
+/* Check that UCE header definition is maintained to keep ABI intact */
+static_assert(CXL_HEADERLOG_TRACE_SIZE_U32 == 128,
+ "rasdaemon ABI requires exactly 128 u32s");
+
static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
struct cxl_ras_capability_regs ras_cap)
{
@@ -19,6 +23,7 @@ static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
struct cxl_ras_capability_regs ras_cap)
{
+ u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};
u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask;
u32 fe;
@@ -28,8 +33,8 @@ static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
else
fe = status;
- trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe,
- ras_cap.header_log);
+ memcpy(hl, ras_cap.header_log, CXL_HEADERLOG_SIZE);
+ trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe, hl);
}
static void cxl_cper_trace_corr_prot_err(struct cxl_memdev *cxlmd,
@@ -44,6 +49,7 @@ static void
cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd,
struct cxl_ras_capability_regs ras_cap)
{
+ u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};
u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask;
u32 fe;
@@ -53,8 +59,15 @@ cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd,
else
fe = status;
- trace_cxl_aer_uncorrectable_error(cxlmd, status, fe,
- ras_cap.header_log);
+ /*
+ * ras_cap.header_log[] holds CXL_HEADERLOG_SIZE_U32 (16) hardware
+ * dwords. Copy them into the front of a zero-filled
+ * CXL_HEADERLOG_TRACE_SIZE_U32 (128) u32 staging buffer so the trace
+ * event memcpy sees a full 512-byte source and the userspace ABI
+ * (rasdaemon) is preserved.
+ */
+ memcpy(hl, ras_cap.header_log, CXL_HEADERLOG_SIZE);
+ trace_cxl_aer_uncorrectable_error(cxlmd, status, fe, hl);
}
static int match_memdev_by_parent(struct device *dev, const void *uport)
@@ -204,12 +217,12 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
{
void __iomem *addr;
u32 *log_addr;
- int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32);
+ int i;
addr = ras_base + CXL_RAS_HEADER_LOG_OFFSET;
log_addr = log;
- for (i = 0; i < log_u32_size; i++) {
+ for (i = 0; i < CXL_HEADERLOG_SIZE_U32; i++) {
*log_addr = readl(addr);
log_addr++;
addr += sizeof(u32);
@@ -222,7 +235,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)
*/
bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
{
- u32 hl[CXL_HEADERLOG_SIZE_U32];
+ u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32] = {};
void __iomem *addr;
u32 status;
u32 fe;
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index e50dc716d4e8..66c328d1c14e 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -1224,8 +1224,6 @@ static int cxl_port_attach_region(struct cxl_port *port,
nr_targets_inc = true;
}
} else {
- struct cxl_decoder *cxld;
-
cxld = cxl_port_pick_region_decoder(port, cxled, cxlr);
if (!cxld) {
dev_dbg(&cxlr->dev, "%s: no decoder available\n",
@@ -1848,8 +1846,21 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr,
* this means that userspace can view devices in the wrong position
* before the region activates, and must be careful to understand when
* it might be racing region autodiscovery.
+ *
+ * The endpoint decoder will be recorded into the first free slot of
+ * the target array.
*/
- pos = p->nr_targets;
+ for (pos = 0; pos < p->interleave_ways; pos++) {
+ if (!p->targets[pos])
+ break;
+ }
+
+ if (pos == p->interleave_ways) {
+ dev_err(&cxlr->dev, "%s: unable to find a free target slot\n",
+ dev_name(&cxled->cxld.dev));
+ return -ENXIO;
+ }
+
p->targets[pos] = cxled;
cxled->pos = pos;
cxled->state = CXL_DECODER_STATE_AUTO_STAGED;
@@ -2011,8 +2022,9 @@ static int cxl_region_sort_targets(struct cxl_region *cxlr)
cxled->pos = cxl_calc_interleave_pos(cxled, &cxlr->hpa_range);
/*
* Record that sorting failed, but still continue to calc
- * cxled->pos so that follow-on code paths can reliably
- * do p->targets[cxled->pos] to self-reference their entry.
+ * cxled->pos so that cxl_calc_interleave_pos() emits its
+ * dev_dbg() for every member. which is useful for auto
+ * discovery debug.
*/
if (cxled->pos < 0)
rc = -ENXIO;
@@ -2189,31 +2201,43 @@ static int cxl_region_attach(struct cxl_region *cxlr,
* will fail when presented as CXL_REGION_F_AUTO.
*/
for (int i = 0; i < p->nr_targets; i++) {
- struct cxl_endpoint_decoder *cxled = p->targets[i];
+ struct cxl_endpoint_decoder *target = p->targets[i];
int test_pos;
- test_pos = cxl_calc_interleave_pos(cxled, &cxlr->hpa_range);
- dev_dbg(&cxled->cxld.dev,
- "Test cxl_calc_interleave_pos(): %s test_pos:%d cxled->pos:%d\n",
- (test_pos == cxled->pos) ? "success" : "fail",
- test_pos, cxled->pos);
+ test_pos = cxl_calc_interleave_pos(target, &cxlr->hpa_range);
+ dev_dbg(&target->cxld.dev,
+ "Test cxl_calc_interleave_pos(): %s test_pos:%d target->pos:%d\n",
+ (test_pos == target->pos) ? "success" : "fail",
+ test_pos, target->pos);
}
return 0;
}
-static int cxl_region_by_target(struct device *dev, const void *data)
+static int cxl_region_remove_target(struct device *dev, void *data)
{
- const struct cxl_endpoint_decoder *cxled = data;
+ struct cxl_endpoint_decoder *cxled = data;
struct cxl_region_params *p;
struct cxl_region *cxlr;
+ int i;
if (!is_cxl_region(dev))
return 0;
cxlr = to_cxl_region(dev);
p = &cxlr->params;
- return p->targets[cxled->pos] == cxled;
+ for (i = 0; i < p->interleave_ways; i++) {
+ if (p->targets[i] == cxled) {
+ p->nr_targets--;
+ cxled->state = CXL_DECODER_STATE_AUTO;
+ cxled->pos = -1;
+ p->targets[i] = NULL;
+
+ return 1;
+ }
+ }
+
+ return 0;
}
/*
@@ -2222,25 +2246,10 @@ static int cxl_region_by_target(struct device *dev, const void *data)
*/
static void cxl_cancel_auto_attach(struct cxl_endpoint_decoder *cxled)
{
- struct cxl_region_params *p;
- struct cxl_region *cxlr;
- int pos = cxled->pos;
-
if (cxled->state != CXL_DECODER_STATE_AUTO_STAGED)
return;
- struct device *dev __free(put_device) =
- bus_find_device(&cxl_bus_type, NULL, cxled, cxl_region_by_target);
- if (!dev)
- return;
-
- cxlr = to_cxl_region(dev);
- p = &cxlr->params;
-
- p->nr_targets--;
- cxled->state = CXL_DECODER_STATE_AUTO;
- cxled->pos = -1;
- p->targets[pos] = NULL;
+ bus_for_each_dev(&cxl_bus_type, NULL, cxled, cxl_region_remove_target);
}
static struct cxl_region *
@@ -3060,7 +3069,7 @@ int cxl_validate_translation_params(u8 eiw, u16 eig, int pos)
return -EINVAL;
}
if (pos < 0 || pos >= ways) {
- pr_debug("%s: invalid pos=%d for ways=%u\n", __func__, pos,
+ pr_debug("%s: invalid pos=%d for ways=%d\n", __func__, pos,
ways);
return -EINVAL;
}
@@ -3106,7 +3115,7 @@ EXPORT_SYMBOL_FOR_MODULES(cxl_calculate_dpa_offset, "cxl_translate");
int cxl_calculate_position(u64 hpa_offset, u8 eiw, u16 eig)
{
- unsigned int ways = 0;
+ int ways = 0;
u64 shifted, rem;
int pos, ret;
@@ -3714,6 +3723,9 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
int rc, part = READ_ONCE(cxled->part);
struct cxl_region *cxlr;
+ if (part < 0)
+ return ERR_PTR(-EBUSY);
+
do {
cxlr = __create_region(cxlrd, cxlds->part[part].mode,
atomic_read(&cxlrd->region_id),
diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h
index a972e4ef1936..d37876096dd7 100644
--- a/drivers/cxl/core/trace.h
+++ b/drivers/cxl/core/trace.h
@@ -56,7 +56,7 @@ TRACE_EVENT(cxl_port_aer_uncorrectable_error,
__string(host, dev_name(dev->parent))
__field(u32, status)
__field(u32, first_error)
- __array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
+ __array(u32, header_log, CXL_HEADERLOG_TRACE_SIZE_U32)
),
TP_fast_assign(
__assign_str(device);
@@ -64,10 +64,14 @@ TRACE_EVENT(cxl_port_aer_uncorrectable_error,
__entry->status = status;
__entry->first_error = fe;
/*
- * Embed the 512B headerlog data for user app retrieval and
- * parsing, but no need to print this in the trace buffer.
+ * Embed headerlog data for user app retrieval and parsing,
+ * but no need to print in the trace buffer. Only
+ * CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data;
+ * the remaining entries preserve the 512-byte ABI layout
+ * rasdaemon depends on and are zero-filled by the caller.
*/
- memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
+ memcpy(__entry->header_log, hl,
+ CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32));
),
TP_printk("device=%s host=%s status: '%s' first_error: '%s'",
__get_str(device), __get_str(host),
@@ -85,7 +89,7 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
__field(u64, serial)
__field(u32, status)
__field(u32, first_error)
- __array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
+ __array(u32, header_log, CXL_HEADERLOG_TRACE_SIZE_U32)
),
TP_fast_assign(
__assign_str(memdev);
@@ -94,10 +98,14 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
__entry->status = status;
__entry->first_error = fe;
/*
- * Embed the 512B headerlog data for user app retrieval and
- * parsing, but no need to print this in the trace buffer.
+ * Embed headerlog data for user app retrieval and parsing,
+ * but no need to print in the trace buffer. Only
+ * CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data;
+ * the remaining entries preserve the 512-byte ABI layout
+ * rasdaemon depends on and are zero-filled by the caller.
*/
- memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
+ memcpy(__entry->header_log, hl,
+ CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32));
),
TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error: '%s'",
__get_str(memdev), __get_str(host), __entry->serial,
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 1297594beaec..4a884821ff7c 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -91,7 +91,7 @@ static inline int cxl_hdm_decoder_count(u32 cap_hdr)
}
/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
-static inline int eig_to_granularity(u16 eig, unsigned int *granularity)
+static inline int eig_to_granularity(u16 eig, int *granularity)
{
if (eig > CXL_DECODER_MAX_ENCODED_IG)
return -EINVAL;
@@ -100,7 +100,7 @@ static inline int eig_to_granularity(u16 eig, unsigned int *granularity)
}
/* Encode defined in CXL ECN "3, 6, 12 and 16-way memory Interleaving" */
-static inline int eiw_to_ways(u8 eiw, unsigned int *ways)
+static inline int eiw_to_ways(u8 eiw, int *ways)
{
switch (eiw) {
case 0 ... 4:
@@ -118,6 +118,7 @@ static inline int eiw_to_ways(u8 eiw, unsigned int *ways)
static inline int granularity_to_eig(int granularity, u16 *eig)
{
+ *eig = 0;
if (granularity > SZ_16K || granularity < CXL_DECODER_MIN_GRANULARITY ||
!is_power_of_2(granularity))
return -EINVAL;
@@ -127,6 +128,7 @@ static inline int granularity_to_eig(int granularity, u16 *eig)
static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
{
+ *eiw = 0;
if (ways > 16)
return -EINVAL;
if (is_power_of_2(ways)) {
@@ -158,8 +160,18 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
#define CXL_RAS_CAP_CONTROL_FE_MASK GENMASK(5, 0)
#define CXL_RAS_HEADER_LOG_OFFSET 0x18
#define CXL_RAS_CAPABILITY_LENGTH 0x58
-#define CXL_HEADERLOG_SIZE SZ_512
-#define CXL_HEADERLOG_SIZE_U32 SZ_512 / sizeof(u32)
+#define CXL_HEADERLOG_SIZE SZ_64
+#define CXL_HEADERLOG_SIZE_U32 (CXL_HEADERLOG_SIZE / sizeof(u32))
+
+/*
+ * The RAS UCE trace event header array was originally sized at SZ_512/sizeof(u32)
+ * = 128 u32s due to a bug. Userspace tools (rasdaemon) have grown a dependency
+ * on that 512-byte layout. Keep the trace array at 128 u32s to preserve the
+ * ABI; only CXL_HEADERLOG_SIZE_U32 (16) dwords are valid hardware data, the
+ * remainder are zero-filled.
+ */
+#define CXL_HEADERLOG_TRACE_SIZE SZ_512
+#define CXL_HEADERLOG_TRACE_SIZE_U32 (CXL_HEADERLOG_TRACE_SIZE / sizeof(u32))
/* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
#define CXLDEV_CAP_ARRAY_OFFSET 0x0
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index fcffe24dcb42..ab88eaa31d1d 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -48,6 +48,11 @@ static int cxl_mem_dpa_show(struct seq_file *file, void *data)
static int cxl_debugfs_poison_inject(void *data, u64 dpa)
{
struct cxl_memdev *cxlmd = data;
+ int rc;
+
+ ACQUIRE(device_intr, devlock)(&cxlmd->dev);
+ if ((rc = ACQUIRE_ERR(device_intr, &devlock)))
+ return rc;
return cxl_inject_poison(cxlmd, dpa);
}
@@ -58,6 +63,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(cxl_poison_inject_fops, NULL,
static int cxl_debugfs_poison_clear(void *data, u64 dpa)
{
struct cxl_memdev *cxlmd = data;
+ int rc;
+
+ ACQUIRE(device_intr, devlock)(&cxlmd->dev);
+ if ((rc = ACQUIRE_ERR(device_intr, &devlock)))
+ return rc;
return cxl_clear_poison(cxlmd, dpa);
}
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index ada51948d52f..99cf77b6b699 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -18,7 +18,7 @@
* firmware) are managed in this drivers context. Each driver instance
* is responsible for tearing down the driver context of immediate
* descendant ports. The locking for this is validated by
- * CONFIG_PROVE_CXL_LOCKING.
+ * CONFIG_PROVE_LOCKING.
*
* The primary service this driver provides is presenting APIs to other
* drivers to utilize the decoders, and indicating to userspace (via bind
diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c
index 296516eecfd6..ef92dd35e030 100644
--- a/tools/testing/cxl/test/cxl.c
+++ b/tools/testing/cxl/test/cxl.c
@@ -318,7 +318,7 @@ static struct {
.restrictions = ACPI_CEDT_CFMWS_RESTRICT_HOSTONLYMEM |
ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
.qtg_id = FAKE_QTG_ID,
- .window_size = SZ_256M,
+ .window_size = SZ_256M > PMD_SIZE ? SZ_256M : PMD_SIZE,
},
.target = { 3 },
},
@@ -433,12 +433,16 @@ static void depopulate_all_mock_resources(void)
static struct cxl_mock_res *alloc_mock_res(resource_size_t size, int align)
{
- struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL);
struct genpool_data_align data = {
.align = align,
};
unsigned long phys;
+ struct cxl_mock_res *res __free(kfree) = kzalloc(sizeof(*res),
+ GFP_KERNEL);
+ if (!res)
+ return NULL;
+
INIT_LIST_HEAD(&res->list);
phys = gen_pool_alloc_algo(cxl_mock_pool, size,
gen_pool_first_fit_align, &data);
@@ -453,7 +457,7 @@ static struct cxl_mock_res *alloc_mock_res(resource_size_t size, int align)
list_add(&res->list, &mock_res);
mutex_unlock(&mock_res_lock);
- return res;
+ return no_free_ptr(res);
}
/* Only update CFMWS0 as this is used by the auto region. */
@@ -495,9 +499,12 @@ static int populate_cedt(void)
for (i = cfmws_start; i <= cfmws_end; i++) {
struct acpi_cedt_cfmws *window = mock_cfmws[i];
+ int align = SZ_256M;
cfmws_elc_update(window, i);
- res = alloc_mock_res(window->window_size, SZ_256M);
+ if (window->restrictions & ACPI_CEDT_CFMWS_RESTRICT_VOLATILE)
+ align = max_t(int, SZ_256M, PMD_SIZE);
+ res = alloc_mock_res(window->window_size, align);
if (!res)
return -ENOMEM;
window->base_hpa = res->range.start;
@@ -1181,15 +1188,11 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
cxlsd = to_cxl_switch_decoder(dev);
if (i == 0) {
/* put cxl_mem.4 second in the decode order */
- if (pdev->id == 4) {
- cxlsd->target[1] = dport;
+ if (pdev->id == 4)
cxlsd->cxld.target_map[1] = dport->port_id;
- } else {
- cxlsd->target[0] = dport;
+ else
cxlsd->cxld.target_map[0] = dport->port_id;
- }
} else {
- cxlsd->target[0] = dport;
cxlsd->cxld.target_map[0] = dport->port_id;
}
cxld = &cxlsd->cxld;
@@ -1212,6 +1215,16 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
cxld->commit = mock_decoder_commit;
cxld->reset = mock_decoder_reset;
+ /*
+ * Only target_map[] is programmed above, mimicking
+ * firmware. On real hardware target[] is populated as
+ * dports enumerate, via update_decoder_targets(). The
+ * mock's dports are already bound by now, so fire that
+ * resolution explicitly here rather than stamping
+ * target[] directly.
+ */
+ cxl_port_update_decoder_targets(iter, dport);
+
cxld_registry_update(cxld);
put_device(dev);
}
@@ -1819,6 +1832,12 @@ static __init int cxl_test_init(void)
int rc, i;
struct range mappable;
+ if (!IS_ALIGNED(mock_auto_region_size, PMD_SIZE)) {
+ pr_err_once("mock_auto_region_size %d must be PMD-aligned\n",
+ mock_auto_region_size);
+ return -EINVAL;
+ }
+
cxl_acpi_test();
cxl_core_test();
cxl_mem_test();
@@ -1951,7 +1970,7 @@ static __init int cxl_test_init(void)
err_mem:
cxl_mem_exit();
err_root:
- platform_device_put(cxl_acpi);
+ platform_device_unregister(cxl_acpi);
err_rch:
cxl_rch_topo_exit();
err_single:
diff --git a/tools/testing/cxl/test/cxl_translate.c b/tools/testing/cxl/test/cxl_translate.c
index 16328b2112b2..25a27e01ac21 100644
--- a/tools/testing/cxl/test/cxl_translate.c
+++ b/tools/testing/cxl/test/cxl_translate.c
@@ -236,8 +236,8 @@ static int setup_xor_mapping(void)
if (!cximsd)
return -ENOMEM;
- memcpy(cximsd->xormaps, xormaps, nr_maps * sizeof(*cximsd->xormaps));
cximsd->nr_maps = nr_maps;
+ memcpy(cximsd->xormaps, xormaps, nr_maps * sizeof(*cximsd->xormaps));
return 0;
}
diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c
index 271c7ad8cc32..739343cd5802 100644
--- a/tools/testing/cxl/test/mem.c
+++ b/tools/testing/cxl/test/mem.c
@@ -312,12 +312,17 @@ static int mock_get_event(struct device *dev, struct cxl_mbox_cmd *cmd)
static int mock_clear_event(struct device *dev, struct cxl_mbox_cmd *cmd)
{
- struct cxl_mbox_clear_event_payload *pl = cmd->payload_in;
+ struct cxl_mbox_clear_event_payload *pl;
struct mock_event_log *log;
- u8 log_type = pl->event_log;
+ u8 log_type;
u16 handle;
int nr;
+ if (cmd->size_in < sizeof(*pl))
+ return -EINVAL;
+
+ pl = cmd->payload_in;
+ log_type = pl->event_log;
if (log_type >= CXL_EVENT_TYPE_MAX)
return -EINVAL;
@@ -574,14 +579,19 @@ static int mock_gsl(struct cxl_mbox_cmd *cmd)
static int mock_get_log(struct cxl_memdev_state *mds, struct cxl_mbox_cmd *cmd)
{
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
- struct cxl_mbox_get_log *gl = cmd->payload_in;
- u32 offset = le32_to_cpu(gl->offset);
- u32 length = le32_to_cpu(gl->length);
uuid_t uuid = DEFINE_CXL_CEL_UUID;
+ struct cxl_mbox_get_log *gl;
void *data = &mock_cel;
+ u32 offset;
+ u32 length;
if (cmd->size_in < sizeof(*gl))
return -EINVAL;
+
+ gl = cmd->payload_in;
+ offset = le32_to_cpu(gl->offset);
+ length = le32_to_cpu(gl->length);
+
if (length > cxl_mbox->payload_size)
return -EINVAL;
if (offset + length > sizeof(mock_cel))
@@ -1053,7 +1063,7 @@ static int mock_get_lsa(struct cxl_mockmem_data *mdata,
return -EINVAL;
offset = le32_to_cpu(get_lsa->offset);
length = le32_to_cpu(get_lsa->length);
- if (offset + length > LSA_SIZE)
+ if (offset > LSA_SIZE || length > LSA_SIZE - offset)
return -EINVAL;
if (length > cmd->size_out)
return -EINVAL;
@@ -1073,7 +1083,7 @@ static int mock_set_lsa(struct cxl_mockmem_data *mdata,
return -EINVAL;
offset = le32_to_cpu(set_lsa->offset);
length = cmd->size_in - sizeof(*set_lsa);
- if (offset + length > LSA_SIZE)
+ if (offset > LSA_SIZE || length > LSA_SIZE - offset)
return -EINVAL;
memcpy(lsa + offset, &set_lsa->data[0], length);
@@ -1336,10 +1346,14 @@ static int mock_fw_info(struct cxl_mockmem_data *mdata,
static int mock_transfer_fw(struct cxl_mockmem_data *mdata,
struct cxl_mbox_cmd *cmd)
{
- struct cxl_mbox_transfer_fw *transfer = cmd->payload_in;
+ struct cxl_mbox_transfer_fw *transfer;
void *fw = mdata->fw;
size_t offset, length;
+ if (cmd->size_in < sizeof(*transfer))
+ return -EINVAL;
+
+ transfer = cmd->payload_in;
offset = le32_to_cpu(transfer->offset) * CXL_FW_TRANSFER_ALIGNMENT;
length = cmd->size_in - sizeof(*transfer);
if (offset + length > FW_SIZE)
@@ -1415,11 +1429,18 @@ static int mock_get_test_feature(struct cxl_mockmem_data *mdata,
struct cxl_mbox_cmd *cmd)
{
struct vendor_test_feat *output = cmd->payload_out;
- struct cxl_mbox_get_feat_in *input = cmd->payload_in;
- u16 offset = le16_to_cpu(input->offset);
- u16 count = le16_to_cpu(input->count);
+ struct cxl_mbox_get_feat_in *input;
+ u16 offset;
+ u16 count;
u8 *ptr;
+ if (cmd->size_in < sizeof(*input))
+ return -EINVAL;
+
+ input = cmd->payload_in;
+ offset = le16_to_cpu(input->offset);
+ count = le16_to_cpu(input->count);
+
if (offset > sizeof(*output)) {
cmd->return_code = CXL_MBOX_CMD_RC_INPUT;
return -EINVAL;
@@ -1703,7 +1724,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
return -ENOMEM;
dev_set_drvdata(dev, mdata);
- mdata->lsa = vmalloc(LSA_SIZE);
+ mdata->lsa = vzalloc(LSA_SIZE);
if (!mdata->lsa)
return -ENOMEM;
mdata->fw = vmalloc(FW_SIZE);