mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
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
This commit is contained in:
commit
e53ef72033
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user