Merge tag 'cxl-for-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
Pull CXL updates from Dave Jiang:
"Core:
- A CXL maturity map has been added to the documentation to detail
the current state of CXL enabling.
It provides the status of the current state of various CXL features
to inform current and future contributors of where things are and
which areas need contribution.
- A notifier handler has been added in order for a newly created CXL
memory region to trigger the abstract distance metrics calculation.
This should bring parity for CXL memory to the same level vs
hotplugged DRAM for NUMA abstract distance calculation. The
abstract distance reflects relative performance used for memory
tiering handling.
- An addition for XOR math has been added to address the CXL DPA to
SPA translation.
CXL address translation did not support address interleave math
with XOR prior to this change.
Fixes:
- Fix to address race condition in the CXL memory hotplug notifier
- Add missing MODULE_DESCRIPTION() for CXL modules
- Fix incorrect vendor debug UUID define
Misc:
- A warning has been added to inform users of an unsupported
configuration when mixing CXL VH and RCH/RCD hierarchies
- The ENXIO error code has been replaced with EBUSY for inject poison
limit reached via debugfs and cxl-test support
- Moving the PCI config read in cxl_dvsec_rr_decode() to avoid
unnecessary PCI config reads
- A refactor to a common struct for DRAM and general media CXL
events"
* tag 'cxl-for-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl:
cxl/core/pci: Move reading of control register to immediately before usage
cxl: Remove defunct code calculating host bridge target positions
cxl/region: Verify target positions using the ordered target list
cxl: Restore XOR'd position bits during address translation
cxl/core: Fold cxl_trace_hpa() into cxl_dpa_to_hpa()
cxl/test: Replace ENXIO with EBUSY for inject poison limit reached
cxl/memdev: Replace ENXIO with EBUSY for inject poison limit reached
cxl/acpi: Warn on mixed CXL VH and RCH/RCD Hierarchy
cxl/core: Fix incorrect vendor debug UUID define
Documentation: CXL Maturity Map
cxl/region: Simplify cxl_region_nid()
cxl/region: Support to calculate memory tier abstract distance
cxl/region: Fix a race condition in memory hotplug notifier
cxl: add missing MODULE_DESCRIPTION() macros
cxl/events: Use a common struct for DRAM and General Media events
This commit is contained in:
@@ -28,12 +28,12 @@ int cxl_region_init(void);
|
||||
void cxl_region_exit(void);
|
||||
int cxl_get_poison_by_endpoint(struct cxl_port *port);
|
||||
struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa);
|
||||
u64 cxl_trace_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
|
||||
u64 dpa);
|
||||
u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
|
||||
u64 dpa);
|
||||
|
||||
#else
|
||||
static inline u64
|
||||
cxl_trace_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa)
|
||||
static inline u64 cxl_dpa_to_hpa(struct cxl_region *cxlr,
|
||||
const struct cxl_memdev *cxlmd, u64 dpa)
|
||||
{
|
||||
return ULLONG_MAX;
|
||||
}
|
||||
|
||||
@@ -875,10 +875,10 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd,
|
||||
guard(rwsem_read)(&cxl_region_rwsem);
|
||||
guard(rwsem_read)(&cxl_dpa_rwsem);
|
||||
|
||||
dpa = le64_to_cpu(evt->common.phys_addr) & CXL_DPA_MASK;
|
||||
dpa = le64_to_cpu(evt->media_hdr.phys_addr) & CXL_DPA_MASK;
|
||||
cxlr = cxl_dpa_to_region(cxlmd, dpa);
|
||||
if (cxlr)
|
||||
hpa = cxl_trace_hpa(cxlr, cxlmd, dpa);
|
||||
hpa = cxl_dpa_to_hpa(cxlr, cxlmd, dpa);
|
||||
|
||||
if (event_type == CXL_CPER_EVENT_GEN_MEDIA)
|
||||
trace_cxl_general_media(cxlmd, type, cxlr, hpa,
|
||||
|
||||
@@ -338,10 +338,6 @@ int cxl_dvsec_rr_decode(struct device *dev, int d,
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_read_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, &ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!(cap & CXL_DVSEC_MEM_CAPABLE)) {
|
||||
dev_dbg(dev, "Not MEM Capable\n");
|
||||
return -ENXIO;
|
||||
@@ -368,6 +364,10 @@ int cxl_dvsec_rr_decode(struct device *dev, int d,
|
||||
* disabled, and they will remain moot after the HDM Decoder
|
||||
* capability is enabled.
|
||||
*/
|
||||
rc = pci_read_config_word(pdev, d + CXL_DVSEC_CTRL_OFFSET, &ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
info->mem_enabled = FIELD_GET(CXL_DVSEC_MEM_ENABLE, ctrl);
|
||||
if (!info->mem_enabled)
|
||||
return 0;
|
||||
|
||||
+2
-19
@@ -1733,21 +1733,6 @@ static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos)
|
||||
{
|
||||
struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd;
|
||||
struct cxl_decoder *cxld = &cxlsd->cxld;
|
||||
int iw;
|
||||
|
||||
iw = cxld->interleave_ways;
|
||||
if (dev_WARN_ONCE(&cxld->dev, iw != cxlsd->nr_targets,
|
||||
"misconfigured root decoder\n"))
|
||||
return NULL;
|
||||
|
||||
return cxlrd->cxlsd.target[pos % iw];
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cxl_hb_modulo, CXL);
|
||||
|
||||
static struct lock_class_key cxl_decoder_key;
|
||||
|
||||
/**
|
||||
@@ -1807,7 +1792,6 @@ static int cxl_switch_decoder_init(struct cxl_port *port,
|
||||
* cxl_root_decoder_alloc - Allocate a root level decoder
|
||||
* @port: owning CXL root of this decoder
|
||||
* @nr_targets: static number of downstream targets
|
||||
* @calc_hb: which host bridge covers the n'th position by granularity
|
||||
*
|
||||
* Return: A new cxl decoder to be registered by cxl_decoder_add(). A
|
||||
* 'CXL root' decoder is one that decodes from a top-level / static platform
|
||||
@@ -1815,8 +1799,7 @@ static int cxl_switch_decoder_init(struct cxl_port *port,
|
||||
* topology.
|
||||
*/
|
||||
struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
|
||||
unsigned int nr_targets,
|
||||
cxl_calc_hb_fn calc_hb)
|
||||
unsigned int nr_targets)
|
||||
{
|
||||
struct cxl_root_decoder *cxlrd;
|
||||
struct cxl_switch_decoder *cxlsd;
|
||||
@@ -1838,7 +1821,6 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
cxlrd->calc_hb = calc_hb;
|
||||
mutex_init(&cxlrd->range_lock);
|
||||
|
||||
cxld = &cxlsd->cxld;
|
||||
@@ -2356,5 +2338,6 @@ static void cxl_core_exit(void)
|
||||
|
||||
subsys_initcall(cxl_core_init);
|
||||
module_exit(cxl_core_exit);
|
||||
MODULE_DESCRIPTION("CXL: Core Compute Express Link support");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS(CXL);
|
||||
|
||||
+71
-34
@@ -9,6 +9,7 @@
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/memory-tiers.h>
|
||||
#include <cxlmem.h>
|
||||
#include <cxl.h>
|
||||
#include "core.h"
|
||||
@@ -1632,10 +1633,13 @@ static int cxl_region_attach_position(struct cxl_region *cxlr,
|
||||
const struct cxl_dport *dport, int pos)
|
||||
{
|
||||
struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
|
||||
struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd;
|
||||
struct cxl_decoder *cxld = &cxlsd->cxld;
|
||||
int iw = cxld->interleave_ways;
|
||||
struct cxl_port *iter;
|
||||
int rc;
|
||||
|
||||
if (cxlrd->calc_hb(cxlrd, pos) != dport) {
|
||||
if (dport != cxlrd->cxlsd.target[pos % iw]) {
|
||||
dev_dbg(&cxlr->dev, "%s:%s invalid target position for %s\n",
|
||||
dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
|
||||
dev_name(&cxlrd->cxlsd.cxld.dev));
|
||||
@@ -2310,6 +2314,7 @@ static void unregister_region(void *_cxlr)
|
||||
int i;
|
||||
|
||||
unregister_memory_notifier(&cxlr->memory_notifier);
|
||||
unregister_mt_adistance_algorithm(&cxlr->adist_notifier);
|
||||
device_del(&cxlr->dev);
|
||||
|
||||
/*
|
||||
@@ -2386,14 +2391,23 @@ static bool cxl_region_update_coordinates(struct cxl_region *cxlr, int nid)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int cxl_region_nid(struct cxl_region *cxlr)
|
||||
{
|
||||
struct cxl_region_params *p = &cxlr->params;
|
||||
struct resource *res;
|
||||
|
||||
guard(rwsem_read)(&cxl_region_rwsem);
|
||||
res = p->res;
|
||||
if (!res)
|
||||
return NUMA_NO_NODE;
|
||||
return phys_to_target_node(res->start);
|
||||
}
|
||||
|
||||
static int cxl_region_perf_attrs_callback(struct notifier_block *nb,
|
||||
unsigned long action, void *arg)
|
||||
{
|
||||
struct cxl_region *cxlr = container_of(nb, struct cxl_region,
|
||||
memory_notifier);
|
||||
struct cxl_region_params *p = &cxlr->params;
|
||||
struct cxl_endpoint_decoder *cxled = p->targets[0];
|
||||
struct cxl_decoder *cxld = &cxled->cxld;
|
||||
struct memory_notify *mnb = arg;
|
||||
int nid = mnb->status_change_nid;
|
||||
int region_nid;
|
||||
@@ -2401,7 +2415,7 @@ static int cxl_region_perf_attrs_callback(struct notifier_block *nb,
|
||||
if (nid == NUMA_NO_NODE || action != MEM_ONLINE)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
region_nid = phys_to_target_node(cxld->hpa_range.start);
|
||||
region_nid = cxl_region_nid(cxlr);
|
||||
if (nid != region_nid)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
@@ -2411,6 +2425,27 @@ static int cxl_region_perf_attrs_callback(struct notifier_block *nb,
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int cxl_region_calculate_adistance(struct notifier_block *nb,
|
||||
unsigned long nid, void *data)
|
||||
{
|
||||
struct cxl_region *cxlr = container_of(nb, struct cxl_region,
|
||||
adist_notifier);
|
||||
struct access_coordinate *perf;
|
||||
int *adist = data;
|
||||
int region_nid;
|
||||
|
||||
region_nid = cxl_region_nid(cxlr);
|
||||
if (nid != region_nid)
|
||||
return NOTIFY_OK;
|
||||
|
||||
perf = &cxlr->coord[ACCESS_COORDINATE_CPU];
|
||||
|
||||
if (mt_perf_to_adistance(perf, adist))
|
||||
return NOTIFY_OK;
|
||||
|
||||
return NOTIFY_STOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_cxl_add_region - Adds a region to a decoder
|
||||
* @cxlrd: root decoder
|
||||
@@ -2453,6 +2488,10 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd,
|
||||
cxlr->memory_notifier.priority = CXL_CALLBACK_PRI;
|
||||
register_memory_notifier(&cxlr->memory_notifier);
|
||||
|
||||
cxlr->adist_notifier.notifier_call = cxl_region_calculate_adistance;
|
||||
cxlr->adist_notifier.priority = 100;
|
||||
register_mt_adistance_algorithm(&cxlr->adist_notifier);
|
||||
|
||||
rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
@@ -2816,20 +2855,13 @@ struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa)
|
||||
return ctx.cxlr;
|
||||
}
|
||||
|
||||
static bool cxl_is_hpa_in_range(u64 hpa, struct cxl_region *cxlr, int pos)
|
||||
static bool cxl_is_hpa_in_chunk(u64 hpa, struct cxl_region *cxlr, int pos)
|
||||
{
|
||||
struct cxl_region_params *p = &cxlr->params;
|
||||
int gran = p->interleave_granularity;
|
||||
int ways = p->interleave_ways;
|
||||
u64 offset;
|
||||
|
||||
/* Is the hpa within this region at all */
|
||||
if (hpa < p->res->start || hpa > p->res->end) {
|
||||
dev_dbg(&cxlr->dev,
|
||||
"Addr trans fail: hpa 0x%llx not in region\n", hpa);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Is the hpa in an expected chunk for its pos(-ition) */
|
||||
offset = hpa - p->res->start;
|
||||
offset = do_div(offset, gran * ways);
|
||||
@@ -2842,15 +2874,26 @@ static bool cxl_is_hpa_in_range(u64 hpa, struct cxl_region *cxlr, int pos)
|
||||
return false;
|
||||
}
|
||||
|
||||
static u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr,
|
||||
struct cxl_endpoint_decoder *cxled)
|
||||
u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
|
||||
u64 dpa)
|
||||
{
|
||||
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
|
||||
u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa;
|
||||
struct cxl_region_params *p = &cxlr->params;
|
||||
int pos = cxled->pos;
|
||||
struct cxl_endpoint_decoder *cxled = NULL;
|
||||
u16 eig = 0;
|
||||
u8 eiw = 0;
|
||||
int pos;
|
||||
|
||||
for (int i = 0; i < p->nr_targets; i++) {
|
||||
cxled = p->targets[i];
|
||||
if (cxlmd == cxled_to_memdev(cxled))
|
||||
break;
|
||||
}
|
||||
if (!cxled || cxlmd != cxled_to_memdev(cxled))
|
||||
return ULLONG_MAX;
|
||||
|
||||
pos = cxled->pos;
|
||||
ways_to_eiw(p->interleave_ways, &eiw);
|
||||
granularity_to_eig(p->interleave_granularity, &eig);
|
||||
|
||||
@@ -2884,29 +2927,23 @@ static u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr,
|
||||
/* Apply the hpa_offset to the region base address */
|
||||
hpa = hpa_offset + p->res->start;
|
||||
|
||||
if (!cxl_is_hpa_in_range(hpa, cxlr, cxled->pos))
|
||||
/* Root decoder translation overrides typical modulo decode */
|
||||
if (cxlrd->hpa_to_spa)
|
||||
hpa = cxlrd->hpa_to_spa(cxlrd, hpa);
|
||||
|
||||
if (hpa < p->res->start || hpa > p->res->end) {
|
||||
dev_dbg(&cxlr->dev,
|
||||
"Addr trans fail: hpa 0x%llx not in region\n", hpa);
|
||||
return ULLONG_MAX;
|
||||
}
|
||||
|
||||
/* Simple chunk check, by pos & gran, only applies to modulo decodes */
|
||||
if (!cxlrd->hpa_to_spa && (!cxl_is_hpa_in_chunk(hpa, cxlr, pos)))
|
||||
return ULLONG_MAX;
|
||||
|
||||
return hpa;
|
||||
}
|
||||
|
||||
u64 cxl_trace_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd,
|
||||
u64 dpa)
|
||||
{
|
||||
struct cxl_region_params *p = &cxlr->params;
|
||||
struct cxl_endpoint_decoder *cxled = NULL;
|
||||
|
||||
for (int i = 0; i < p->nr_targets; i++) {
|
||||
cxled = p->targets[i];
|
||||
if (cxlmd == cxled_to_memdev(cxled))
|
||||
break;
|
||||
}
|
||||
if (!cxled || cxlmd != cxled_to_memdev(cxled))
|
||||
return ULLONG_MAX;
|
||||
|
||||
return cxl_dpa_to_hpa(dpa, cxlr, cxled);
|
||||
}
|
||||
|
||||
static struct lock_class_key cxl_pmem_region_key;
|
||||
|
||||
static int cxl_pmem_region_alloc(struct cxl_region *cxlr)
|
||||
|
||||
+18
-18
@@ -340,23 +340,23 @@ TRACE_EVENT(cxl_general_media,
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
|
||||
CXL_EVT_TP_fast_assign(cxlmd, log, rec->media_hdr.hdr);
|
||||
__entry->hdr_uuid = CXL_EVENT_GEN_MEDIA_UUID;
|
||||
|
||||
/* General Media */
|
||||
__entry->dpa = le64_to_cpu(rec->phys_addr);
|
||||
__entry->dpa = le64_to_cpu(rec->media_hdr.phys_addr);
|
||||
__entry->dpa_flags = __entry->dpa & CXL_DPA_FLAGS_MASK;
|
||||
/* Mask after flags have been parsed */
|
||||
__entry->dpa &= CXL_DPA_MASK;
|
||||
__entry->descriptor = rec->descriptor;
|
||||
__entry->type = rec->type;
|
||||
__entry->transaction_type = rec->transaction_type;
|
||||
__entry->channel = rec->channel;
|
||||
__entry->rank = rec->rank;
|
||||
__entry->descriptor = rec->media_hdr.descriptor;
|
||||
__entry->type = rec->media_hdr.type;
|
||||
__entry->transaction_type = rec->media_hdr.transaction_type;
|
||||
__entry->channel = rec->media_hdr.channel;
|
||||
__entry->rank = rec->media_hdr.rank;
|
||||
__entry->device = get_unaligned_le24(rec->device);
|
||||
memcpy(__entry->comp_id, &rec->component_id,
|
||||
CXL_EVENT_GEN_MED_COMP_ID_SIZE);
|
||||
__entry->validity_flags = get_unaligned_le16(&rec->validity_flags);
|
||||
__entry->validity_flags = get_unaligned_le16(&rec->media_hdr.validity_flags);
|
||||
__entry->hpa = hpa;
|
||||
if (cxlr) {
|
||||
__assign_str(region_name);
|
||||
@@ -440,19 +440,19 @@ TRACE_EVENT(cxl_dram,
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
|
||||
CXL_EVT_TP_fast_assign(cxlmd, log, rec->media_hdr.hdr);
|
||||
__entry->hdr_uuid = CXL_EVENT_DRAM_UUID;
|
||||
|
||||
/* DRAM */
|
||||
__entry->dpa = le64_to_cpu(rec->phys_addr);
|
||||
__entry->dpa = le64_to_cpu(rec->media_hdr.phys_addr);
|
||||
__entry->dpa_flags = __entry->dpa & CXL_DPA_FLAGS_MASK;
|
||||
__entry->dpa &= CXL_DPA_MASK;
|
||||
__entry->descriptor = rec->descriptor;
|
||||
__entry->type = rec->type;
|
||||
__entry->transaction_type = rec->transaction_type;
|
||||
__entry->validity_flags = get_unaligned_le16(rec->validity_flags);
|
||||
__entry->channel = rec->channel;
|
||||
__entry->rank = rec->rank;
|
||||
__entry->descriptor = rec->media_hdr.descriptor;
|
||||
__entry->type = rec->media_hdr.type;
|
||||
__entry->transaction_type = rec->media_hdr.transaction_type;
|
||||
__entry->validity_flags = get_unaligned_le16(rec->media_hdr.validity_flags);
|
||||
__entry->channel = rec->media_hdr.channel;
|
||||
__entry->rank = rec->media_hdr.rank;
|
||||
__entry->nibble_mask = get_unaligned_le24(rec->nibble_mask);
|
||||
__entry->bank_group = rec->bank_group;
|
||||
__entry->bank = rec->bank;
|
||||
@@ -704,8 +704,8 @@ TRACE_EVENT(cxl_poison,
|
||||
if (cxlr) {
|
||||
__assign_str(region);
|
||||
memcpy(__entry->uuid, &cxlr->params.uuid, 16);
|
||||
__entry->hpa = cxl_trace_hpa(cxlr, cxlmd,
|
||||
__entry->dpa);
|
||||
__entry->hpa = cxl_dpa_to_hpa(cxlr, cxlmd,
|
||||
__entry->dpa);
|
||||
} else {
|
||||
__assign_str(region);
|
||||
memset(__entry->uuid, 0, 16);
|
||||
|
||||
Reference in New Issue
Block a user