mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 12:34:02 +02:00
CXL for v7.3
CXL core type2 support: cxl: Support dpa without a mailbox cxl: Support Type2 cxl regs mapping CXL test type2 support: cxl/test: Rework cxl_type2_mem_init() to use cxl_mock_platform_device_add() cxl/test: Add cxl_test accelerator driver cxl/test: Fixup hdm init for auto region to support type2 cxl/test: Propagate -ENOMEM on platform_device_alloc() failures cxl/test: Add hierarchy enumeration support for type2 device cxl/test: Refactor platform device enumerations cxl/test: Add type2 support for mock CFMWS0 cxl/test: Add test for module parameters CXL port error handling support prep patches: cxl: Rename find_cxl_port() to find_cxl_port_by_dport() cxl: Tighten CPER kfifo registration API and symbol visibility acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register cxl/ras: Fix cxl_rch_get_aer_info() out-of-bounds AER register read CXL misc patches: cxl/Documentation: Spell out globbed sysfs attribute names cxl/test: Assign one mock memdev a full-width serial number cxl/core: Format the memdev serial number as unsigned in TP_printk cxl/pmem: Format the nvdimm serial number as unsigned decimal cxl: Use %pe to print error pointers cxl: Deny Features commands on the RAW mailbox path CXL fixes: cxl/region: Use __free(put_device) in find_pos_and_ways() cxl/region: Fix use-after-free in find_pos_and_ways() error path cxl/features: Clamp Get Feature output size to the remaining buffer cxl/features: Reject Set Features output buffer smaller than the header cxl/features: Reject Get Feature count larger than the output buffer cxl/port: Restart port enumeration when a sibling adds the dport first cxl/features: Serialize multi-part Get/Set Feature transfers cxl/pci: Honor -EPROBE_DEFER from component register setup cxl/mbox: Break poison list loop on an empty payload cxl/memdev: Fix firmware upload exact-fit handling cxl/features: bound fwctl command payload to the input buffer cxl/mce: Make the MCE notifier per-region cxl/pci: Remove incorrect mbox.valid check in cxl_pci_type3_init_mailbox() cxl: docs/linux/dax-driver - fix typos cxl: fix mailbox return code description typo cxl/mbox: Clamp mailbox output allocation to the payload size -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE5DAy15EJMCV1R6v9YGjFFmlTOEoFAmqDPQEACgkQYGjFFmlT OEqNBw/+LP25RACa3Jtwb53KtycNi/MzyVBXV311rDaBGzSKUixkO9LYCIV76lI/ 86x+U7+fmXBTmynD8lNwgVUw2P18xguYPe3bfn9qlmC2AZ6zmyeEzRU4p4BRzxTv iE9utK7DLetNRLGMnYIz3ziHLaSaZf0RslvecXF61y+nNhfd5N/pg52Bw1dUdpRi 91m8v0JJ+v+OtEKwCsinV4lck07WRmk+roCFFqcwIdR4GkhKBKiipf+Vv9EoR/k5 zBkhPazWFNKmnvf3VAY+vvo/Nh+wmHOrLqJUi5QYOQDXUGiJgt6/2JDVDBrY+QZL 1I7BN66d4PE7lQnYpZHnu/aSlhcV/QI/4tKRnt1eZ7kIFO0s7QbPo7Fg8+Ql+43m V/qYWPxC6BgQXHBYAcnvJZO6COL1EIG1+sGy+x6kInTn33KPBeit6Ru7c3wxmYFa jXfdrudfN+0fUtjEhrMb2IIxfhNV5O/wLQqlj2c8vXgRmZo9dElyyiIxOC87EnOG sWD2Z+4z9Id4egU6bU5iTdVdT+CW0WkUHAd9gtmYwlr9Ttrqh01CTu7vc0XEKyKS j5YU/3sV2H8KbU5PqVo9GeYRukylESe+w42+7UemBUSzX6OIDaiNNokmDt9L+Cg7 pdBr1qzjasR7XIDXNP9IRdkPKTgqDbSrg/gVIZJe+j7OsUHu0Nw= =6Bd/ -----END PGP SIGNATURE----- Merge tag 'cxl-for-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl Pull CXL updates from Dave Jiang: "This includes the remaining patches to complete the basic support for CXL type2 (accelerators) drivers by the CXL core. A set of unit testing support to catch regressions for the CXL core type2 exported functions has also been added. The actual CXL type 2 driver support for the AMD Solarflare NIC driver has been picked up by net-dev. A set of preparatory patches has been picked up from the CXL port error handling series in order to reduce the number of patches in that series for review. The rest of that series is getting close to be merged but was not ready for the 7.3 merge window. There are also a number of misc patches and a large number of bug fixes against pre-existing issues flagged by sashiko reviews as contributors post new patches on the mailing list. We will continue to work through the sashiko raised issues as they show up." * tag 'cxl-for-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl: (35 commits) cxl/Documentation: Spell out globbed sysfs attribute names cxl: Rename find_cxl_port() to find_cxl_port_by_dport() cxl: Tighten CPER kfifo registration API and symbol visibility acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register cxl/ras: Fix cxl_rch_get_aer_info() out-of-bounds AER register read cxl/test: Assign one mock memdev a full-width serial number cxl/core: Format the memdev serial number as unsigned in TP_printk cxl/pmem: Format the nvdimm serial number as unsigned decimal cxl: Use %pe to print error pointers cxl/region: Use __free(put_device) in find_pos_and_ways() cxl/region: Fix use-after-free in find_pos_and_ways() error path cxl: Deny Features commands on the RAW mailbox path cxl/features: Clamp Get Feature output size to the remaining buffer cxl/features: Reject Set Features output buffer smaller than the header cxl/features: Reject Get Feature count larger than the output buffer cxl/port: Restart port enumeration when a sibling adds the dport first cxl/features: Serialize multi-part Get/Set Feature transfers cxl/pci: Honor -EPROBE_DEFER from component register setup cxl/mbox: Break poison list loop on an empty payload ...
This commit is contained in:
commit
920f27122c
|
|
@ -201,7 +201,8 @@ Description:
|
|||
capability.
|
||||
|
||||
|
||||
What: /sys/bus/cxl/devices/{port,endpoint}X/parent_dport
|
||||
What: /sys/bus/cxl/devices/portX/parent_dport
|
||||
What: /sys/bus/cxl/devices/endpointX/parent_dport
|
||||
Date: January, 2023
|
||||
KernelVersion: v6.3
|
||||
Contact: linux-cxl@vger.kernel.org
|
||||
|
|
@ -258,7 +259,8 @@ Description:
|
|||
instance id of a given decoder resource.
|
||||
|
||||
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/{start,size}
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/start
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/size
|
||||
Date: June, 2021
|
||||
KernelVersion: v5.14
|
||||
Contact: linux-cxl@vger.kernel.org
|
||||
|
|
@ -297,7 +299,10 @@ Description:
|
|||
Each entry in the list is a dport id.
|
||||
|
||||
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/cap_{pmem,ram,type2,type3}
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/cap_pmem
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/cap_ram
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/cap_type2
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/cap_type3
|
||||
Date: June, 2021
|
||||
KernelVersion: v5.14
|
||||
Contact: linux-cxl@vger.kernel.org
|
||||
|
|
@ -410,7 +415,8 @@ Description:
|
|||
interleave_granularity).
|
||||
|
||||
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/create_{pmem,ram}_region
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/create_pmem_region
|
||||
What: /sys/bus/cxl/devices/decoderX.Y/create_ram_region
|
||||
Date: May, 2022, January, 2023
|
||||
KernelVersion: v6.0 (pmem), v6.3 (ram)
|
||||
Contact: linux-cxl@vger.kernel.org
|
||||
|
|
@ -500,6 +506,7 @@ Description:
|
|||
cache is present, the size indicates extended linear cache size
|
||||
plus the CXL region size.
|
||||
|
||||
|
||||
What: /sys/bus/cxl/devices/regionZ/extended_linear_cache_size
|
||||
Date: October, 2025
|
||||
KernelVersion: v6.19
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ What: /sys/bus/nd/devices/nmemX/cxl/id
|
|||
Date: November 2022
|
||||
KernelVersion: 6.2
|
||||
Contact: Dave Jiang <dave.jiang@intel.com>
|
||||
Description: (RO) Show the id (serial) of the device. This is CXL specific.
|
||||
Description: (RO) Show the id (serial) of the device, formatted as an
|
||||
unsigned 64-bit decimal value. This is CXL specific.
|
||||
|
||||
What: /sys/bus/nd/devices/nmemX/cxl/provider
|
||||
Date: November 2022
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ will be exposed to the kernel page allocator in the user-selected memory
|
|||
zone.
|
||||
|
||||
The :code:`memmap_on_memory` setting (both global and DAX device local)
|
||||
dictates where the kernell will allocate the :code:`struct folio` descriptors
|
||||
dictates where the kernel will allocate the :code:`struct folio` descriptors
|
||||
for this memory will come from. If :code:`memmap_on_memory` is set, memory
|
||||
hotplug will set aside a portion of the memory block capacity to allocate
|
||||
folios. If unset, the memory is allocated via a normal :code:`GFP_KERNEL`
|
||||
allocation - and as a result will most likely land on the local NUM node of the
|
||||
allocation - and as a result will most likely land on the local NUMA node of the
|
||||
CPU executing the hotplug operation.
|
||||
|
|
|
|||
|
|
@ -749,7 +749,7 @@ static DEFINE_KFIFO(cxl_cper_prot_err_fifo, struct cxl_cper_prot_err_work_data,
|
|||
CXL_CPER_PROT_ERR_FIFO_DEPTH);
|
||||
|
||||
/* Synchronize schedule_work() with cxl_cper_prot_err_work changes */
|
||||
static DEFINE_SPINLOCK(cxl_cper_prot_err_work_lock);
|
||||
static DEFINE_RAW_SPINLOCK(cxl_cper_prot_err_work_lock);
|
||||
struct work_struct *cxl_cper_prot_err_work;
|
||||
|
||||
static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
|
||||
|
|
@ -761,7 +761,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
|
|||
if (cxl_cper_sec_prot_err_valid(prot_err))
|
||||
return;
|
||||
|
||||
guard(spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
|
||||
guard(raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
|
||||
|
||||
if (!cxl_cper_prot_err_work)
|
||||
return;
|
||||
|
|
@ -778,40 +778,48 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
|
|||
#endif
|
||||
}
|
||||
|
||||
int cxl_cper_register_prot_err_work(struct work_struct *work)
|
||||
void cxl_cper_register_prot_err_work(struct work_struct *work)
|
||||
{
|
||||
if (cxl_cper_prot_err_work)
|
||||
return -EINVAL;
|
||||
guard(raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
|
||||
|
||||
guard(spinlock)(&cxl_cper_prot_err_work_lock);
|
||||
if (WARN_ONCE(cxl_cper_prot_err_work,
|
||||
"CPER-CXL kfifo consumer already registered\n"))
|
||||
return;
|
||||
cxl_cper_prot_err_work = work;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_cper_register_prot_err_work, "CXL");
|
||||
EXPORT_SYMBOL_FOR_MODULES(cxl_cper_register_prot_err_work, "cxl_core");
|
||||
|
||||
int cxl_cper_unregister_prot_err_work(struct work_struct *work)
|
||||
void cxl_cper_unregister_prot_err_work(void)
|
||||
{
|
||||
if (cxl_cper_prot_err_work != work)
|
||||
return -EINVAL;
|
||||
struct work_struct *old;
|
||||
|
||||
guard(spinlock)(&cxl_cper_prot_err_work_lock);
|
||||
cxl_cper_prot_err_work = NULL;
|
||||
return 0;
|
||||
scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) {
|
||||
WARN_ONCE(!cxl_cper_prot_err_work,
|
||||
"CPER-CXL kfifo consumer not registered on unregister\n");
|
||||
old = cxl_cper_prot_err_work;
|
||||
cxl_cper_prot_err_work = NULL;
|
||||
}
|
||||
|
||||
if (old)
|
||||
cancel_work_sync(old);
|
||||
|
||||
/* Discard stale entries so they are not replayed on next module load */
|
||||
kfifo_reset(&cxl_cper_prot_err_fifo);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_prot_err_work, "CXL");
|
||||
EXPORT_SYMBOL_FOR_MODULES(cxl_cper_unregister_prot_err_work, "cxl_core");
|
||||
|
||||
int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data *wd)
|
||||
{
|
||||
return kfifo_get(&cxl_cper_prot_err_fifo, wd);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_cper_prot_err_kfifo_get, "CXL");
|
||||
EXPORT_SYMBOL_FOR_MODULES(cxl_cper_prot_err_kfifo_get, "cxl_core");
|
||||
|
||||
/* Room for 8 entries for each of the 4 event log queues */
|
||||
#define CXL_CPER_FIFO_DEPTH 32
|
||||
DEFINE_KFIFO(cxl_cper_fifo, struct cxl_cper_work_data, CXL_CPER_FIFO_DEPTH);
|
||||
|
||||
/* Synchronize schedule_work() with cxl_cper_work changes */
|
||||
static DEFINE_SPINLOCK(cxl_cper_work_lock);
|
||||
static DEFINE_RAW_SPINLOCK(cxl_cper_work_lock);
|
||||
struct work_struct *cxl_cper_work;
|
||||
|
||||
static void cxl_cper_post_event(enum cxl_event_type event_type,
|
||||
|
|
@ -831,7 +839,7 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,
|
|||
return;
|
||||
}
|
||||
|
||||
guard(spinlock_irqsave)(&cxl_cper_work_lock);
|
||||
guard(raw_spinlock_irqsave)(&cxl_cper_work_lock);
|
||||
|
||||
if (!cxl_cper_work)
|
||||
return;
|
||||
|
|
@ -849,23 +857,29 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,
|
|||
|
||||
int cxl_cper_register_work(struct work_struct *work)
|
||||
{
|
||||
if (cxl_cper_work)
|
||||
guard(raw_spinlock_irqsave)(&cxl_cper_work_lock);
|
||||
if (WARN_ONCE(cxl_cper_work,
|
||||
"CXL CPER kfifo consumer already registered\n"))
|
||||
return -EINVAL;
|
||||
|
||||
guard(spinlock)(&cxl_cper_work_lock);
|
||||
cxl_cper_work = work;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, "CXL");
|
||||
|
||||
int cxl_cper_unregister_work(struct work_struct *work)
|
||||
void cxl_cper_unregister_work(struct work_struct *work)
|
||||
{
|
||||
if (cxl_cper_work != work)
|
||||
return -EINVAL;
|
||||
scoped_guard(raw_spinlock_irqsave, &cxl_cper_work_lock) {
|
||||
if (WARN_ONCE(cxl_cper_work != work,
|
||||
"CXL CPER kfifo consumer mismatch on unregister\n"))
|
||||
return;
|
||||
cxl_cper_work = NULL;
|
||||
}
|
||||
|
||||
guard(spinlock)(&cxl_cper_work_lock);
|
||||
cxl_cper_work = NULL;
|
||||
return 0;
|
||||
cancel_work_sync(work);
|
||||
|
||||
/* Discard stale entries so they are not replayed on next module load */
|
||||
kfifo_reset(&cxl_cper_fifo);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_work, "CXL");
|
||||
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ static inline struct device *dport_to_host(struct cxl_dport *dport)
|
|||
return &port->dev;
|
||||
}
|
||||
#ifdef CONFIG_CXL_RAS
|
||||
int cxl_ras_init(void);
|
||||
void cxl_ras_init(void);
|
||||
void cxl_ras_exit(void);
|
||||
bool cxl_handle_ras(struct device *dev, void __iomem *ras_base);
|
||||
void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base);
|
||||
|
|
@ -194,10 +194,7 @@ void cxl_disable_rch_root_ints(struct cxl_dport *dport);
|
|||
void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds);
|
||||
void devm_cxl_dport_ras_setup(struct cxl_dport *dport);
|
||||
#else
|
||||
static inline int cxl_ras_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void cxl_ras_init(void) { }
|
||||
static inline void cxl_ras_exit(void) { }
|
||||
static inline bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
|
|||
void *feat_out, size_t feat_out_size, u16 offset,
|
||||
u16 *return_code)
|
||||
{
|
||||
size_t data_to_rd_size, size_out;
|
||||
size_t data_to_rd_size;
|
||||
struct cxl_mbox_get_feat_in pi;
|
||||
struct cxl_mbox_cmd mbox_cmd;
|
||||
size_t data_rcvd_size = 0;
|
||||
|
|
@ -237,9 +237,10 @@ size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
|
|||
if (!feat_out || !feat_out_size)
|
||||
return 0;
|
||||
|
||||
size_out = min(feat_out_size, cxl_mbox->payload_size);
|
||||
uuid_copy(&pi.uuid, feat_uuid);
|
||||
pi.selection = selection;
|
||||
|
||||
guard(mutex)(&cxl_mbox->feat_mutex);
|
||||
do {
|
||||
data_to_rd_size = min(feat_out_size - data_rcvd_size,
|
||||
cxl_mbox->payload_size);
|
||||
|
|
@ -250,7 +251,7 @@ size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
|
|||
.opcode = CXL_MBOX_OP_GET_FEATURE,
|
||||
.size_in = sizeof(pi),
|
||||
.payload_in = &pi,
|
||||
.size_out = size_out,
|
||||
.size_out = data_to_rd_size,
|
||||
.payload_out = feat_out + data_rcvd_size,
|
||||
.min_out = data_to_rd_size,
|
||||
};
|
||||
|
|
@ -314,6 +315,7 @@ int cxl_set_feature(struct cxl_mailbox *cxl_mbox,
|
|||
data_in_size = cxl_mbox->payload_size - hdr_size;
|
||||
}
|
||||
|
||||
guard(mutex)(&cxl_mbox->feat_mutex);
|
||||
do {
|
||||
int rc;
|
||||
|
||||
|
|
@ -471,6 +473,10 @@ static void *cxlctl_get_feature(struct cxl_features_state *cxlfs,
|
|||
if (!count)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (out_size < offsetof(struct fwctl_rpc_cxl_out, payload) ||
|
||||
count > out_size - offsetof(struct fwctl_rpc_cxl_out, payload))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
struct fwctl_rpc_cxl_out *rpc_out __free(kvfree) =
|
||||
kvzalloc(out_size, GFP_KERNEL);
|
||||
if (!rpc_out)
|
||||
|
|
@ -516,6 +522,9 @@ static void *cxlctl_set_feature(struct cxl_features_state *cxlfs,
|
|||
flags = le32_to_cpu(feat_in->flags);
|
||||
out_size = *out_len;
|
||||
|
||||
if (out_size < offsetof(struct fwctl_rpc_cxl_out, payload))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
struct fwctl_rpc_cxl_out *rpc_out __free(kvfree) =
|
||||
kvzalloc(out_size, GFP_KERNEL);
|
||||
if (!rpc_out)
|
||||
|
|
@ -649,7 +658,13 @@ static void *cxlctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
|
|||
struct cxl_memdev *cxlmd = fwctl_to_memdev(fwctl_dev);
|
||||
struct cxl_features_state *cxlfs = to_cxlfs(cxlmd->cxlds);
|
||||
const struct fwctl_rpc_cxl *rpc_in = in;
|
||||
u16 opcode = rpc_in->opcode;
|
||||
u16 opcode;
|
||||
|
||||
if (in_len < sizeof(rpc_in->hdr) ||
|
||||
rpc_in->op_size > in_len - sizeof(rpc_in->hdr))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
opcode = rpc_in->opcode;
|
||||
|
||||
if (!cxlctl_validate_hw_command(cxlfs, rpc_in, scope, opcode))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "core.h"
|
||||
#include "trace.h"
|
||||
#include "mce.h"
|
||||
|
||||
static bool cxl_raw_allow_all;
|
||||
|
||||
|
|
@ -91,6 +90,10 @@ static struct cxl_mem_command cxl_mem_commands[CXL_MEM_COMMAND_ID_MAX] = {
|
|||
*
|
||||
* CXL_MBOX_OP_[GET_,INJECT_,CLEAR_]POISON: These commands require kernel
|
||||
* driver orchestration for safety.
|
||||
*
|
||||
* CXL_MBOX_OP_[GET_SUPPORTED_FEATURES,GET_FEATURE,SET_FEATURE]: Features are
|
||||
* accessed through the fwctl ABI, which applies scope-based access control.
|
||||
* The RAW path would bypass those checks, so it is not permitted here.
|
||||
*/
|
||||
static u16 cxl_disabled_raw_commands[] = {
|
||||
CXL_MBOX_OP_ACTIVATE_FW,
|
||||
|
|
@ -102,6 +105,9 @@ static u16 cxl_disabled_raw_commands[] = {
|
|||
CXL_MBOX_OP_GET_POISON,
|
||||
CXL_MBOX_OP_INJECT_POISON,
|
||||
CXL_MBOX_OP_CLEAR_POISON,
|
||||
CXL_MBOX_OP_GET_SUPPORTED_FEATURES,
|
||||
CXL_MBOX_OP_GET_FEATURE,
|
||||
CXL_MBOX_OP_SET_FEATURE,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -380,11 +386,7 @@ static int cxl_mbox_cmd_ctor(struct cxl_mbox_cmd *mbox_cmd,
|
|||
}
|
||||
}
|
||||
|
||||
/* Prepare to handle a full payload for variable sized output */
|
||||
if (out_size == CXL_VARIABLE_PAYLOAD)
|
||||
mbox_cmd->size_out = cxl_mbox->payload_size;
|
||||
else
|
||||
mbox_cmd->size_out = out_size;
|
||||
mbox_cmd->size_out = min_t(size_t, out_size, cxl_mbox->payload_size);
|
||||
|
||||
if (mbox_cmd->size_out) {
|
||||
mbox_cmd->payload_out = kvzalloc(mbox_cmd->size_out, GFP_KERNEL);
|
||||
|
|
@ -1406,6 +1408,11 @@ int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len,
|
|||
if (rc)
|
||||
break;
|
||||
|
||||
if (!le16_to_cpu(po->count)) {
|
||||
dev_dbg(&cxlmd->dev, "Poison empty payload!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < le16_to_cpu(po->count); i++)
|
||||
trace_cxl_poison(cxlmd, cxlr, &po->record[i],
|
||||
po->flags, po->overflow_ts,
|
||||
|
|
@ -1467,6 +1474,7 @@ int cxl_mailbox_init(struct cxl_mailbox *cxl_mbox, struct device *host)
|
|||
|
||||
cxl_mbox->host = host;
|
||||
mutex_init(&cxl_mbox->mbox_mutex);
|
||||
mutex_init(&cxl_mbox->feat_mutex);
|
||||
rcuwait_init(&cxl_mbox->mbox_wait);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1477,7 +1485,6 @@ struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev, u64 serial,
|
|||
u16 dvsec)
|
||||
{
|
||||
struct cxl_memdev_state *mds;
|
||||
int rc;
|
||||
|
||||
mds = devm_cxl_dev_state_create(dev, CXL_DEVTYPE_CLASSMEM, serial,
|
||||
dvsec, struct cxl_memdev_state, cxlds,
|
||||
|
|
@ -1489,12 +1496,6 @@ struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev, u64 serial,
|
|||
|
||||
mutex_init(&mds->event.log_lock);
|
||||
|
||||
rc = devm_cxl_register_mce_notifier(dev, &mds->mce_notifier);
|
||||
if (rc == -EOPNOTSUPP)
|
||||
dev_warn(dev, "CXL MCE unsupported\n");
|
||||
else if (rc)
|
||||
return ERR_PTR(rc);
|
||||
|
||||
return mds;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_memdev_state_create, "CXL");
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@
|
|||
#include <linux/notifier.h>
|
||||
#include <linux/set_memory.h>
|
||||
#include <asm/mce.h>
|
||||
#include <cxlmem.h>
|
||||
#include <cxl.h>
|
||||
#include "core.h"
|
||||
#include "mce.h"
|
||||
|
||||
static int cxl_handle_mce(struct notifier_block *nb, unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
struct cxl_memdev_state *mds = container_of(nb, struct cxl_memdev_state,
|
||||
mce_notifier);
|
||||
struct cxl_memdev *cxlmd = mds->cxlds.cxlmd;
|
||||
struct cxl_port *endpoint = cxlmd->endpoint;
|
||||
struct cxl_region *cxlr = container_of(nb, struct cxl_region,
|
||||
mce_notifier);
|
||||
struct cxl_region_params *p = &cxlr->params;
|
||||
struct mce *mce = data;
|
||||
u64 spa, spa_alias;
|
||||
unsigned long pfn;
|
||||
|
|
@ -21,26 +21,25 @@ static int cxl_handle_mce(struct notifier_block *nb, unsigned long val,
|
|||
if (!mce || !mce_usable_address(mce))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (!endpoint)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
spa = mce->addr & MCI_ADDR_PHYSADDR;
|
||||
|
||||
pfn = spa >> PAGE_SHIFT;
|
||||
if (!pfn_valid(pfn))
|
||||
if (!cxl_resource_contains_addr(p->res, spa))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
spa_alias = cxl_port_get_spa_cache_alias(endpoint, spa);
|
||||
if (spa_alias == ~0ULL)
|
||||
return NOTIFY_DONE;
|
||||
if (spa >= p->res->start + p->cache_size)
|
||||
spa_alias = spa - p->cache_size;
|
||||
else
|
||||
spa_alias = spa + p->cache_size;
|
||||
|
||||
pfn = spa_alias >> PAGE_SHIFT;
|
||||
if (!pfn_valid(pfn))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/*
|
||||
* Take down the aliased memory page. The original memory page flagged
|
||||
* by the MCE will be taken cared of by the standard MCE handler.
|
||||
*/
|
||||
dev_emerg(mds->cxlds.dev, "Offlining aliased SPA address0: %#llx\n",
|
||||
dev_emerg(&cxlr->dev, "Offlining aliased SPA address0: %#llx\n",
|
||||
spa_alias);
|
||||
if (!memory_failure(pfn, 0))
|
||||
set_mce_nospec(pfn);
|
||||
|
|
|
|||
|
|
@ -988,7 +988,7 @@ static enum fw_upload_err cxl_fw_prepare(struct fw_upload *fwl, const u8 *data,
|
|||
if (!size)
|
||||
return FW_UPLOAD_ERR_INVALID_SIZE;
|
||||
|
||||
mds->fw.oneshot = struct_size(transfer, data, size) <
|
||||
mds->fw.oneshot = struct_size(transfer, data, size) <=
|
||||
cxl_mbox->payload_size;
|
||||
|
||||
if (cxl_mem_get_fw_info(mds))
|
||||
|
|
|
|||
|
|
@ -219,12 +219,14 @@ static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_nvdimm_bridge *cxl_nvb,
|
|||
dev->bus = &cxl_bus_type;
|
||||
dev->type = &cxl_nvdimm_type;
|
||||
/*
|
||||
* A "%llx" string is 17-bytes vs dimm_id that is max
|
||||
* NVDIMM_KEY_DESC_LEN
|
||||
* dev_id is the nvdimm dimm_id used for security key lookup.
|
||||
* It must match id_show(), which emits the CXL serial as an
|
||||
* unsigned decimal. A u64 decimal string is at most 20 digits
|
||||
* plus NUL.
|
||||
*/
|
||||
BUILD_BUG_ON(sizeof(cxl_nvd->dev_id) < 17 ||
|
||||
BUILD_BUG_ON(sizeof(cxl_nvd->dev_id) < 21 ||
|
||||
sizeof(cxl_nvd->dev_id) > NVDIMM_KEY_DESC_LEN);
|
||||
sprintf(cxl_nvd->dev_id, "%llx", cxlmd->cxlds->serial);
|
||||
sprintf(cxl_nvd->dev_id, "%llu", cxlmd->cxlds->serial);
|
||||
|
||||
return cxl_nvd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -933,11 +933,10 @@ struct cxl_port *devm_cxl_add_port(struct device *host,
|
|||
|
||||
parent_port = parent_dport ? parent_dport->port : NULL;
|
||||
if (IS_ERR(port)) {
|
||||
dev_dbg(uport_dev, "Failed to add%s%s%s: %ld\n",
|
||||
dev_dbg(uport_dev, "Failed to add%s%s%s: %pe\n",
|
||||
parent_port ? " port to " : "",
|
||||
parent_port ? dev_name(&parent_port->dev) : "",
|
||||
parent_port ? "" : " root port",
|
||||
PTR_ERR(port));
|
||||
parent_port ? "" : " root port", port);
|
||||
} else {
|
||||
dev_dbg(uport_dev, "%s added%s%s%s\n",
|
||||
dev_name(&port->dev),
|
||||
|
|
@ -1272,8 +1271,8 @@ struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
|
|||
dport = __devm_cxl_add_dport(port, dport_dev, port_id,
|
||||
component_reg_phys, CXL_RESOURCE_NONE);
|
||||
if (IS_ERR(dport)) {
|
||||
dev_dbg(dport_dev, "failed to add dport to %s: %ld\n",
|
||||
dev_name(&port->dev), PTR_ERR(dport));
|
||||
dev_dbg(dport_dev, "failed to add dport to %s: %pe\n",
|
||||
dev_name(&port->dev), dport);
|
||||
} else {
|
||||
dev_dbg(dport_dev, "dport added to %s\n",
|
||||
dev_name(&port->dev));
|
||||
|
|
@ -1306,8 +1305,8 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
|
|||
dport = __devm_cxl_add_dport(port, dport_dev, port_id,
|
||||
CXL_RESOURCE_NONE, rcrb);
|
||||
if (IS_ERR(dport)) {
|
||||
dev_dbg(dport_dev, "failed to add RCH dport to %s: %ld\n",
|
||||
dev_name(&port->dev), PTR_ERR(dport));
|
||||
dev_dbg(dport_dev, "failed to add RCH dport to %s: %pe\n",
|
||||
dev_name(&port->dev), dport);
|
||||
} else {
|
||||
dev_dbg(dport_dev, "RCH dport added to %s\n",
|
||||
dev_name(&port->dev));
|
||||
|
|
@ -1380,7 +1379,7 @@ static int match_port_by_dport(struct device *dev, const void *data)
|
|||
return dport != NULL;
|
||||
}
|
||||
|
||||
static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)
|
||||
static struct cxl_port *__find_cxl_port_by_dport(struct cxl_find_port_ctx *ctx)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
|
|
@ -1393,8 +1392,16 @@ static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct cxl_port *find_cxl_port(struct device *dport_dev,
|
||||
struct cxl_dport **dport)
|
||||
/**
|
||||
* find_cxl_port_by_dport - find a cxl_port by one of its targets
|
||||
* @dport_dev: device representing the dport target
|
||||
* @dport: optional output of the 'struct cxl_dport' companion of the @dport_dev
|
||||
*
|
||||
* Return a 'struct cxl_port' with an elevated reference if found. Use
|
||||
* __free(put_cxl_port) to release.
|
||||
*/
|
||||
static struct cxl_port *find_cxl_port_by_dport(struct device *dport_dev,
|
||||
struct cxl_dport **dport)
|
||||
{
|
||||
struct cxl_find_port_ctx ctx = {
|
||||
.dport_dev = dport_dev,
|
||||
|
|
@ -1402,7 +1409,7 @@ static struct cxl_port *find_cxl_port(struct device *dport_dev,
|
|||
};
|
||||
struct cxl_port *port;
|
||||
|
||||
port = __find_cxl_port(&ctx);
|
||||
port = __find_cxl_port_by_dport(&ctx);
|
||||
return port;
|
||||
}
|
||||
|
||||
|
|
@ -1750,8 +1757,8 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd,
|
|||
parent_dport, uport_dev,
|
||||
dport_dev);
|
||||
if (IS_ERR(dport)) {
|
||||
/* Port already exists, restart iteration */
|
||||
if (PTR_ERR(dport) == -EAGAIN)
|
||||
/* Port or dport already exists, restart iteration */
|
||||
if (PTR_ERR(dport) == -EAGAIN || PTR_ERR(dport) == -EBUSY)
|
||||
return 0;
|
||||
return PTR_ERR(dport);
|
||||
}
|
||||
|
|
@ -1896,14 +1903,14 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, "CXL");
|
|||
struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev,
|
||||
struct cxl_dport **dport)
|
||||
{
|
||||
return find_cxl_port(pdev->dev.parent, dport);
|
||||
return find_cxl_port_by_dport(pdev->dev.parent, dport);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_pci_find_port, "CXL");
|
||||
|
||||
struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
|
||||
struct cxl_dport **dport)
|
||||
{
|
||||
return find_cxl_port(grandparent(&cxlmd->dev), dport);
|
||||
return find_cxl_port_by_dport(grandparent(&cxlmd->dev), dport);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, "CXL");
|
||||
|
||||
|
|
@ -2532,14 +2539,10 @@ static __init int cxl_core_init(void)
|
|||
if (rc)
|
||||
goto err_region;
|
||||
|
||||
rc = cxl_ras_init();
|
||||
if (rc)
|
||||
goto err_ras;
|
||||
cxl_ras_init();
|
||||
|
||||
return 0;
|
||||
|
||||
err_ras:
|
||||
cxl_region_exit();
|
||||
err_region:
|
||||
bus_unregister(&cxl_bus_type);
|
||||
err_bus:
|
||||
|
|
|
|||
|
|
@ -129,15 +129,14 @@ static void cxl_cper_prot_err_work_fn(struct work_struct *work)
|
|||
}
|
||||
static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
|
||||
|
||||
int cxl_ras_init(void)
|
||||
void cxl_ras_init(void)
|
||||
{
|
||||
return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
|
||||
cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
|
||||
}
|
||||
|
||||
void cxl_ras_exit(void)
|
||||
{
|
||||
cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work);
|
||||
cancel_work_sync(&cxl_cper_prot_err_work);
|
||||
cxl_cper_unregister_prot_err_work();
|
||||
}
|
||||
|
||||
static void cxl_dport_map_ras(struct cxl_dport *dport)
|
||||
|
|
|
|||
|
|
@ -58,13 +58,28 @@ void cxl_disable_rch_root_ints(struct cxl_dport *dport)
|
|||
static bool cxl_rch_get_aer_info(void __iomem *aer_base,
|
||||
struct aer_capability_regs *aer_regs)
|
||||
{
|
||||
int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32);
|
||||
/*
|
||||
* Bound the copy to the physically-defined AER registers (header
|
||||
* through the 16-byte Header Log). struct aer_capability_regs is a
|
||||
* software layout whose embedded struct pcie_tlp_log is larger than
|
||||
* the on-wire AER capability; copying sizeof(*aer_regs) would
|
||||
* over-read the RCRB-mapped MMIO block.
|
||||
*/
|
||||
int read_cnt = (PCI_ERR_HEADER_LOG + 16) / sizeof(u32);
|
||||
u32 *aer_regs_buf = (u32 *)aer_regs;
|
||||
int n;
|
||||
|
||||
if (!aer_base)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Zero the destination so the software-only tail fields
|
||||
* (e.g. header_log.header_len) are deterministic rather than
|
||||
* left as uninitialized stack, which could drive a bogus loop
|
||||
* length in pcie_print_tlp_log().
|
||||
*/
|
||||
memset(aer_regs, 0, sizeof(*aer_regs));
|
||||
|
||||
/* Use readl() to guarantee 32-bit accesses */
|
||||
for (n = 0; n < read_cnt; n++)
|
||||
aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
|
||||
|
|
@ -79,11 +94,11 @@ static bool cxl_rch_get_aer_info(void __iomem *aer_base,
|
|||
static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,
|
||||
int *severity)
|
||||
{
|
||||
if (aer_regs->uncor_status & ~aer_regs->uncor_mask) {
|
||||
if (aer_regs->uncor_status & PCI_ERR_ROOT_FATAL_RCV)
|
||||
*severity = AER_FATAL;
|
||||
else
|
||||
*severity = AER_NONFATAL;
|
||||
u32 uncor_status = aer_regs->uncor_status & ~aer_regs->uncor_mask;
|
||||
|
||||
if (uncor_status) {
|
||||
*severity = (uncor_status & aer_regs->uncor_severity) ?
|
||||
AER_FATAL : AER_NONFATAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include <cxlmem.h>
|
||||
#include <cxl.h>
|
||||
#include "core.h"
|
||||
#include "mce.h"
|
||||
|
||||
/**
|
||||
* DOC: cxl core region
|
||||
|
|
@ -682,8 +683,8 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size)
|
|||
dev_name(&cxlr->dev));
|
||||
if (IS_ERR(res)) {
|
||||
dev_dbg(&cxlr->dev,
|
||||
"HPA allocation error (%ld) for size:%pap in %s %pr\n",
|
||||
PTR_ERR(res), &size, cxlrd->res->name, cxlrd->res);
|
||||
"HPA allocation error (%pe) for size:%pap in %s %pr\n",
|
||||
res, &size, cxlrd->res->name, cxlrd->res);
|
||||
return PTR_ERR(res);
|
||||
}
|
||||
|
||||
|
|
@ -1913,15 +1914,14 @@ static int find_pos_and_ways(struct cxl_port *port, struct range *range,
|
|||
{
|
||||
struct cxl_switch_decoder *cxlsd;
|
||||
struct cxl_port *parent;
|
||||
struct device *dev;
|
||||
int rc = -ENXIO;
|
||||
|
||||
parent = parent_port_of(port);
|
||||
if (!parent)
|
||||
return rc;
|
||||
|
||||
dev = device_find_child(&parent->dev, range,
|
||||
match_switch_decoder_by_range);
|
||||
struct device *dev __free(put_device) =
|
||||
device_find_child(&parent->dev, range, match_switch_decoder_by_range);
|
||||
if (!dev) {
|
||||
dev_err(port->uport_dev,
|
||||
"failed to find decoder mapping %#llx-%#llx\n",
|
||||
|
|
@ -1938,14 +1938,11 @@ static int find_pos_and_ways(struct cxl_port *port, struct range *range,
|
|||
break;
|
||||
}
|
||||
}
|
||||
put_device(dev);
|
||||
|
||||
if (rc)
|
||||
dev_err(port->uport_dev,
|
||||
"failed to find %s:%s in target list of %s\n",
|
||||
dev_name(&port->dev),
|
||||
dev_name(port->parent_dport->dport_dev),
|
||||
dev_name(&cxlsd->cxld.dev));
|
||||
dev_name(port->parent_dport->dport_dev), dev_name(dev));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -3773,9 +3770,9 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
|
|||
|
||||
if (IS_ERR(cxlr)) {
|
||||
dev_err(cxlmd->dev.parent,
|
||||
"%s:%s: %s failed assign region: %ld\n",
|
||||
"%s:%s: %s failed assign region: %pe\n",
|
||||
dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
|
||||
__func__, PTR_ERR(cxlr));
|
||||
__func__, cxlr);
|
||||
return cxlr;
|
||||
}
|
||||
|
||||
|
|
@ -3859,34 +3856,6 @@ int cxl_add_to_region(struct cxl_endpoint_decoder *cxled)
|
|||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_add_to_region, "CXL");
|
||||
|
||||
u64 cxl_port_get_spa_cache_alias(struct cxl_port *endpoint, u64 spa)
|
||||
{
|
||||
struct cxl_region_ref *iter;
|
||||
unsigned long index;
|
||||
|
||||
if (!endpoint)
|
||||
return ~0ULL;
|
||||
|
||||
guard(rwsem_write)(&cxl_rwsem.region);
|
||||
|
||||
xa_for_each(&endpoint->regions, index, iter) {
|
||||
struct cxl_region_params *p = &iter->region->params;
|
||||
|
||||
if (cxl_resource_contains_addr(p->res, spa)) {
|
||||
if (!p->cache_size)
|
||||
return ~0ULL;
|
||||
|
||||
if (spa >= p->res->start + p->cache_size)
|
||||
return spa - p->cache_size;
|
||||
|
||||
return spa + p->cache_size;
|
||||
}
|
||||
}
|
||||
|
||||
return ~0ULL;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_port_get_spa_cache_alias, "CXL");
|
||||
|
||||
static int is_system_ram(struct resource *res, void *arg)
|
||||
{
|
||||
struct cxl_region *cxlr = arg;
|
||||
|
|
@ -4217,6 +4186,20 @@ static int cxl_region_probe(struct device *dev)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* Regions fronted by an extended linear cache need the MCE notifier to
|
||||
* offline the aliased page on a memory error.
|
||||
*/
|
||||
if (p->cache_size) {
|
||||
rc = devm_cxl_register_mce_notifier(&cxlr->dev,
|
||||
&cxlr->mce_notifier);
|
||||
if (rc == -EOPNOTSUPP)
|
||||
dev_warn(&cxlr->dev,
|
||||
"CONFIG_CXL_MCE disabled, MCE notifier not registered\n");
|
||||
else if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cxl_region_setup_poison(cxlr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
|
|||
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'",
|
||||
TP_printk("memdev=%s host=%s serial=%llu: status: '%s' first_error: '%s'",
|
||||
__get_str(memdev), __get_str(host), __entry->serial,
|
||||
show_uc_errs(__entry->status),
|
||||
show_uc_errs(__entry->first_error)
|
||||
|
|
@ -166,7 +166,7 @@ TRACE_EVENT(cxl_aer_correctable_error,
|
|||
__entry->serial = cxlmd->cxlds->serial;
|
||||
__entry->status = status;
|
||||
),
|
||||
TP_printk("memdev=%s host=%s serial=%lld: status: '%s'",
|
||||
TP_printk("memdev=%s host=%s serial=%llu: status: '%s'",
|
||||
__get_str(memdev), __get_str(host), __entry->serial,
|
||||
show_ce_errs(__entry->status)
|
||||
)
|
||||
|
|
@ -206,7 +206,7 @@ TRACE_EVENT(cxl_overflow,
|
|||
__entry->last_ts = le64_to_cpu(payload->last_overflow_timestamp);
|
||||
),
|
||||
|
||||
TP_printk("memdev=%s host=%s serial=%lld: log=%s : %u records from %llu to %llu",
|
||||
TP_printk("memdev=%s host=%s serial=%llu: log=%s : %u records from %llu to %llu",
|
||||
__get_str(memdev), __get_str(host), __entry->serial,
|
||||
cxl_event_log_type_str(__entry->log), __entry->count,
|
||||
__entry->first_ts, __entry->last_ts)
|
||||
|
|
@ -279,7 +279,7 @@ TRACE_EVENT(cxl_overflow,
|
|||
__entry->hdr_head_id = (hdr).head_id
|
||||
|
||||
#define CXL_EVT_TP_printk(fmt, ...) \
|
||||
TP_printk("memdev=%s host=%s serial=%lld log=%s : time=%llu uuid=%pUb " \
|
||||
TP_printk("memdev=%s host=%s serial=%llu log=%s : time=%llu uuid=%pUb " \
|
||||
"len=%d flags='%s' handle=%x related_handle=%x " \
|
||||
"maint_op_class=%u maint_op_sub_class=%u " \
|
||||
"ld_id=%x head_id=%x : " fmt, \
|
||||
|
|
@ -1088,7 +1088,7 @@ TRACE_EVENT(cxl_poison,
|
|||
}
|
||||
),
|
||||
|
||||
TP_printk("memdev=%s host=%s serial=%lld trace_type=%s region=%s " \
|
||||
TP_printk("memdev=%s host=%s serial=%llu trace_type=%s region=%s " \
|
||||
"region_uuid=%pU hpa=0x%llx hpa_alias0=0x%llx dpa=0x%llx " \
|
||||
"dpa_length=0x%x source=%s flags=%s overflow_time=%llu",
|
||||
__get_str(memdev),
|
||||
|
|
|
|||
|
|
@ -478,6 +478,7 @@ struct cxl_region_params {
|
|||
* @coord: QoS access coordinates for the region
|
||||
* @node_notifier: notifier for setting the access coordinates to node
|
||||
* @adist_notifier: notifier for calculating the abstract distance of node
|
||||
* @mce_notifier: notifier for MCE
|
||||
*/
|
||||
struct cxl_region {
|
||||
struct device dev;
|
||||
|
|
@ -493,6 +494,7 @@ struct cxl_region {
|
|||
struct access_coordinate coord[ACCESS_COORDINATE_MAX];
|
||||
struct notifier_block node_notifier;
|
||||
struct notifier_block adist_notifier;
|
||||
struct notifier_block mce_notifier;
|
||||
};
|
||||
|
||||
struct cxl_nvdimm_bridge {
|
||||
|
|
@ -503,7 +505,8 @@ struct cxl_nvdimm_bridge {
|
|||
struct nvdimm_bus_descriptor nd_desc;
|
||||
};
|
||||
|
||||
#define CXL_DEV_ID_LEN 19
|
||||
/* Holds a u64 serial as a decimal string: up to 20 digits + NUL */
|
||||
#define CXL_DEV_ID_LEN 21
|
||||
|
||||
enum {
|
||||
CXL_NVD_F_INVALIDATED = 0,
|
||||
|
|
@ -870,7 +873,6 @@ bool is_cxl_pmem_region(struct device *dev);
|
|||
struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
|
||||
int cxl_add_to_region(struct cxl_endpoint_decoder *cxled);
|
||||
struct cxl_dax_region *to_cxl_dax_region(struct device *dev);
|
||||
u64 cxl_port_get_spa_cache_alias(struct cxl_port *endpoint, u64 spa);
|
||||
bool cxl_region_contains_resource(const struct resource *res);
|
||||
#else
|
||||
static inline bool is_cxl_pmem_region(struct device *dev)
|
||||
|
|
@ -889,11 +891,6 @@ static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline u64 cxl_port_get_spa_cache_alias(struct cxl_port *endpoint,
|
||||
u64 spa)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline bool cxl_region_contains_resource(const struct resource *res)
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port,
|
|||
C(MBUNSUPPORTED, -ENXIO, "unsupported on the mailbox it was issued on"),\
|
||||
C(PAYLOADLEN, -ENXIO, "invalid payload length"), \
|
||||
C(LOG, -ENXIO, "invalid or unsupported log page"), \
|
||||
C(INTERRUPTED, -ENXIO, "asynchronous event occured"), \
|
||||
C(INTERRUPTED, -ENXIO, "asynchronous event occurred"), \
|
||||
C(FEATUREVERSION, -ENXIO, "unsupported feature version"), \
|
||||
C(FEATURESELVALUE, -ENXIO, "unsupported feature selection value"), \
|
||||
C(FEATURETRANSFERIP, -ENXIO, "feature transfer in progress"), \
|
||||
|
|
@ -431,7 +431,6 @@ static inline struct cxl_dev_state *mbox_to_cxlds(struct cxl_mailbox *cxl_mbox)
|
|||
* @poison: poison driver state info
|
||||
* @security: security driver state info
|
||||
* @fw: firmware upload / activation state
|
||||
* @mce_notifier: MCE notifier
|
||||
*
|
||||
* See CXL 3.0 8.2.9.8.2 Capacity Configuration and Label Storage for
|
||||
* details on capacity parameters.
|
||||
|
|
@ -451,7 +450,6 @@ struct cxl_memdev_state {
|
|||
struct cxl_poison_state poison;
|
||||
struct cxl_security_state security;
|
||||
struct cxl_fw_state fw;
|
||||
struct notifier_block mce_notifier;
|
||||
};
|
||||
|
||||
static inline struct cxl_memdev_state *
|
||||
|
|
|
|||
|
|
@ -692,12 +692,6 @@ static int cxl_pci_type3_init_mailbox(struct cxl_dev_state *cxlds)
|
|||
{
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Fail the init if there's no mailbox. For a type3 this is out of spec.
|
||||
*/
|
||||
if (!cxlds->reg_map.device_map.mbox.valid)
|
||||
return -ENODEV;
|
||||
|
||||
rc = cxl_mailbox_init(&cxlds->cxl_mbox, cxlds->dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
@ -830,10 +824,13 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
*/
|
||||
rc = cxl_pci_setup_regs(pdev, CXL_REGLOC_RBI_COMPONENT,
|
||||
&cxlds->reg_map);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
if (rc == -EPROBE_DEFER)
|
||||
return rc;
|
||||
dev_warn(&pdev->dev, "No component registers (%d)\n", rc);
|
||||
else if (!cxlds->reg_map.component_map.ras.valid)
|
||||
} else if (!cxlds->reg_map.component_map.ras.valid) {
|
||||
dev_dbg(&pdev->dev, "RAS registers not found\n");
|
||||
}
|
||||
|
||||
rc = cxl_pci_type3_init_mailbox(cxlds);
|
||||
if (rc)
|
||||
|
|
@ -1084,7 +1081,6 @@ static int __init cxl_pci_driver_init(void)
|
|||
static void __exit cxl_pci_driver_exit(void)
|
||||
{
|
||||
cxl_cper_unregister_work(&cxl_cper_work);
|
||||
cancel_work_sync(&cxl_cper_work);
|
||||
pci_unregister_driver(&cxl_pci_driver);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *
|
|||
struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
|
||||
struct cxl_dev_state *cxlds = cxl_nvd->cxlmd->cxlds;
|
||||
|
||||
return sysfs_emit(buf, "%lld\n", cxlds->serial);
|
||||
return sysfs_emit(buf, "%llu\n", cxlds->serial);
|
||||
}
|
||||
static DEVICE_ATTR_RO(id);
|
||||
|
||||
|
|
|
|||
|
|
@ -287,10 +287,10 @@ struct cxl_cper_prot_err_work_data {
|
|||
|
||||
#ifdef CONFIG_ACPI_APEI_GHES
|
||||
int cxl_cper_register_work(struct work_struct *work);
|
||||
int cxl_cper_unregister_work(struct work_struct *work);
|
||||
void cxl_cper_unregister_work(struct work_struct *work);
|
||||
int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd);
|
||||
int cxl_cper_register_prot_err_work(struct work_struct *work);
|
||||
int cxl_cper_unregister_prot_err_work(struct work_struct *work);
|
||||
void cxl_cper_register_prot_err_work(struct work_struct *work);
|
||||
void cxl_cper_unregister_prot_err_work(void);
|
||||
int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data *wd);
|
||||
#else
|
||||
static inline int cxl_cper_register_work(struct work_struct *work)
|
||||
|
|
@ -298,22 +298,13 @@ static inline int cxl_cper_register_work(struct work_struct *work)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int cxl_cper_unregister_work(struct work_struct *work)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void cxl_cper_unregister_work(struct work_struct *work) { }
|
||||
static inline int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int cxl_cper_register_prot_err_work(struct work_struct *work)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int cxl_cper_unregister_prot_err_work(struct work_struct *work)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void cxl_cper_register_prot_err_work(struct work_struct *work) { }
|
||||
static inline void cxl_cper_unregister_prot_err_work(void) { }
|
||||
static inline int cxl_cper_prot_err_kfifo_get(struct cxl_cper_prot_err_work_data *wd)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ struct cxl_mbox_cmd {
|
|||
* @payload_size: Size of space for payload
|
||||
* (CXL 3.1 8.2.8.4.3 Mailbox Capabilities Register)
|
||||
* @mbox_mutex: mutex protects device mailbox and firmware
|
||||
* @feat_mutex: serializes multi-part Get/Set Feature transfers
|
||||
* @mbox_wait: rcuwait for mailbox
|
||||
* @mbox_send: @dev specific transport for transmitting mailbox commands
|
||||
* @feat_cap: Features capability
|
||||
|
|
@ -60,6 +61,7 @@ struct cxl_mailbox {
|
|||
DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);
|
||||
size_t payload_size;
|
||||
struct mutex mbox_mutex; /* lock to protect mailbox context */
|
||||
struct mutex feat_mutex;
|
||||
struct rcuwait mbox_wait;
|
||||
int (*mbox_send)(struct cxl_mailbox *cxl_mbox, struct cxl_mbox_cmd *cmd);
|
||||
enum cxl_features_capability feat_cap;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@ obj-m += cxl_test.o
|
|||
obj-m += cxl_mock.o
|
||||
obj-m += cxl_mock_mem.o
|
||||
obj-m += cxl_translate.o
|
||||
obj-m += cxl_mock_accel.o
|
||||
|
||||
cxl_test-y := cxl.o
|
||||
cxl_test-y += hmem_test.o
|
||||
cxl_mock-y := mock.o
|
||||
cxl_mock_mem-y := mem.o
|
||||
cxl_mock_accel-y := accel.o
|
||||
|
||||
KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS))
|
||||
|
|
|
|||
66
tools/testing/cxl/test/accel.c
Normal file
66
tools/testing/cxl/test/accel.c
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright(c) 2026 Intel Corporation. All rights reserved.
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <cxl/mailbox.h>
|
||||
#include <cxlmem.h>
|
||||
|
||||
struct mock_cxl_accel {
|
||||
struct cxl_dev_state cxlds;
|
||||
struct cxl_memdev *cxlmd;
|
||||
};
|
||||
|
||||
static int cxl_mock_accel_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mock_cxl_accel *cxl_accel;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cxl_dev_state *cxlds;
|
||||
struct cxl_memdev *cxlmd;
|
||||
struct range mock_range;
|
||||
int rc;
|
||||
|
||||
cxl_accel = devm_cxl_dev_state_create(&pdev->dev, CXL_DEVTYPE_DEVMEM,
|
||||
pdev->id + 1, 0,
|
||||
struct mock_cxl_accel, cxlds,
|
||||
false);
|
||||
if (!cxl_accel)
|
||||
return -ENOMEM;
|
||||
|
||||
cxlds = &cxl_accel->cxlds;
|
||||
cxlds->media_ready = true;
|
||||
rc = cxl_set_capacity(cxlds, SZ_512M);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
cxlmd = devm_cxl_probe_mem(cxlds, &mock_range);
|
||||
if (IS_ERR(cxlmd))
|
||||
return PTR_ERR(cxlmd);
|
||||
cxl_accel->cxlmd = cxlmd;
|
||||
|
||||
dev_dbg(dev, "Probed mock accelerator with range %pra\n", &mock_range);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id cxl_mock_accel_ids[] = {
|
||||
{ .name = "cxl_type2_accel" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, cxl_mock_accel_ids);
|
||||
|
||||
static struct platform_driver cxl_mock_accel_driver = {
|
||||
.probe = cxl_mock_accel_probe,
|
||||
.id_table = cxl_mock_accel_ids,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(cxl_mock_accel_driver);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("cxl_test: accelerator device mock module");
|
||||
MODULE_IMPORT_NS("CXL");
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -3,8 +3,9 @@
|
|||
#include <linux/moduleparam.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include "../../../drivers/dax/bus.h"
|
||||
#include "mock.h"
|
||||
|
||||
static bool hmem_test;
|
||||
bool hmem_test;
|
||||
|
||||
static void hmem_test_work(struct work_struct *work)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1713,6 +1713,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
|
|||
struct cxl_mockmem_data *mdata;
|
||||
struct cxl_mailbox *cxl_mbox;
|
||||
struct cxl_dpa_info range_info = { 0 };
|
||||
u64 serial;
|
||||
int rc;
|
||||
|
||||
/* Increase async probe race window */
|
||||
|
|
@ -1739,7 +1740,19 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
mds = cxl_memdev_state_create(dev, pdev->id + 1, 0);
|
||||
/*
|
||||
* Mock serials have historically been derived from pdev->id and stayed
|
||||
* single-digit, so they never exercised either decimal-vs-hex key
|
||||
* lookup or unsigned formatting. Give one mock device a full-width
|
||||
* serial with bit 63 set, matching real hardware such as Montage CXL
|
||||
* devices. pdev->id 7 is unused by the auto-region topology.
|
||||
*/
|
||||
if (pdev->id == 7)
|
||||
serial = 0x8a34567890abcdef;
|
||||
else
|
||||
serial = pdev->id + 1;
|
||||
|
||||
mds = cxl_memdev_state_create(dev, serial, 0);
|
||||
if (IS_ERR(mds))
|
||||
return PTR_ERR(mds);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include <linux/dax.h>
|
||||
#include <cxl.h>
|
||||
|
||||
extern bool hmem_test;
|
||||
|
||||
struct cxl_mock_ops {
|
||||
struct list_head list;
|
||||
bool (*is_mock_adev)(struct acpi_device *dev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user