@@ -405,6 +405,15 @@ enum cxl_decoder_target_type {
};
cxl_decoder_get_target_type(struct cxl_decoder *decoder);
+
+enum cxl_decoder_mode {
+ CXL_DECODER_MODE_NONE,
+ CXL_DECODER_MODE_MIXED,
+ CXL_DECODER_MODE_PMEM,
+ CXL_DECODER_MODE_RAM,
+};
+enum cxl_decoder_mode cxl_decoder_get_mode(struct cxl_decoder *decoder);
+
bool cxl_decoder_is_pmem_capable(struct cxl_decoder *decoder);
bool cxl_decoder_is_volatile_capable(struct cxl_decoder *decoder);
bool cxl_decoder_is_mem_capable(struct cxl_decoder *decoder);
@@ -473,6 +473,8 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,
}
if (cxl_port_is_endpoint(port)) {
+ enum cxl_decoder_mode mode = cxl_decoder_get_mode(decoder);
+
size = cxl_decoder_get_dpa_size(decoder);
val = cxl_decoder_get_dpa_resource(decoder);
if (size && val < ULLONG_MAX) {
@@ -488,6 +490,12 @@ struct json_object *util_cxl_decoder_to_json(struct cxl_decoder *decoder,
json_object_object_add(jdecoder, "dpa_size",
jobj);
}
+
+ if (mode > CXL_DECODER_MODE_NONE) {
+ jobj = json_object_new_string(cxl_decoder_mode_name(mode));
+ if (jobj)
+ json_object_object_add(jdecoder, "mode", jobj);
+ }
}
if (cxl_port_is_root(port) && cxl_decoder_is_mem_capable(decoder)) {
@@ -960,6 +960,21 @@ static void *add_cxl_decoder(void *parent, int id, const char *cxldecoder_base)
else
decoder->size = strtoull(buf, NULL, 0);
+ sprintf(path, "%s/mode", cxldecoder_base);
+ if (sysfs_read_attr(ctx, path, buf) == 0) {
+ if (strcmp(buf, "ram") == 0)
+ decoder->mode = CXL_DECODER_MODE_RAM;
+ else if (strcmp(buf, "pmem") == 0)
+ decoder->mode = CXL_DECODER_MODE_PMEM;
+ else if (strcmp(buf, "mixed") == 0)
+ decoder->mode = CXL_DECODER_MODE_MIXED;
+ else if (strcmp(buf, "none") == 0)
+ decoder->mode = CXL_DECODER_MODE_NONE;
+ else
+ decoder->mode = CXL_DECODER_MODE_MIXED;
+ } else
+ decoder->mode = CXL_DECODER_MODE_NONE;
+
switch (port->type) {
case CXL_PORT_ENDPOINT:
sprintf(path, "%s/dpa_resource", cxldecoder_base);
@@ -1160,6 +1175,21 @@ cxl_decoder_get_dpa_size(struct cxl_decoder *decoder)
return decoder->dpa_size;
}
+CXL_EXPORT enum cxl_decoder_mode
+cxl_decoder_get_mode(struct cxl_decoder *decoder)
+{
+ struct cxl_port *port = cxl_decoder_get_port(decoder);
+ struct cxl_ctx *ctx = cxl_decoder_get_ctx(decoder);
+
+ if (!cxl_port_is_endpoint(port)) {
+ err(ctx, "%s: not an endpoint decoder\n",
+ cxl_decoder_get_devname(decoder));
+ return CXL_DECODER_MODE_NONE;
+ }
+
+ return decoder->mode;
+}
+
CXL_EXPORT enum cxl_decoder_target_type
cxl_decoder_get_target_type(struct cxl_decoder *decoder)
{
@@ -172,4 +172,5 @@ LIBCXL_3 {
global:
cxl_decoder_get_dpa_resource;
cxl_decoder_get_dpa_size;
+ cxl_decoder_get_mode;
} LIBCXL_2;
@@ -108,6 +108,7 @@ struct cxl_decoder {
char *dev_path;
int nr_targets;
int id;
+ enum cxl_decoder_mode mode;
bool pmem_capable;
bool volatile_capable;
bool mem_capable;
@@ -127,10 +127,33 @@ struct cxl_dport *cxl_port_get_dport_by_memdev(struct cxl_port *port,
struct cxl_decoder;
struct cxl_decoder *cxl_decoder_get_first(struct cxl_port *port);
struct cxl_decoder *cxl_decoder_get_next(struct cxl_decoder *decoder);
+struct cxl_decoder *cxl_decoder_get_last(struct cxl_port *port);
+struct cxl_decoder *cxl_decoder_get_prev(struct cxl_decoder *decoder);
unsigned long long cxl_decoder_get_resource(struct cxl_decoder *decoder);
unsigned long long cxl_decoder_get_size(struct cxl_decoder *decoder);
unsigned long long cxl_decoder_get_dpa_resource(struct cxl_decoder *decoder);
unsigned long long cxl_decoder_get_dpa_size(struct cxl_decoder *decoder);
+enum cxl_decoder_mode {
+ CXL_DECODER_MODE_NONE,
+ CXL_DECODER_MODE_MIXED,
+ CXL_DECODER_MODE_PMEM,
+ CXL_DECODER_MODE_RAM,
+};
+static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode)
+{
+ static const char *names[] = {
+ [CXL_DECODER_MODE_NONE] = "none",
+ [CXL_DECODER_MODE_MIXED] = "mixed",
+ [CXL_DECODER_MODE_PMEM] = "pmem",
+ [CXL_DECODER_MODE_RAM] = "ram",
+ };
+
+ if (mode < CXL_DECODER_MODE_NONE || mode > CXL_DECODER_MODE_RAM)
+ mode = CXL_DECODER_MODE_NONE;
+ return names[mode];
+}
+
+enum cxl_decoder_mode cxl_decoder_get_mode(struct cxl_decoder *decoder);
const char *cxl_decoder_get_devname(struct cxl_decoder *decoder);
struct cxl_target *cxl_decoder_get_target_by_memdev(struct cxl_decoder *decoder,
struct cxl_memdev *memdev);
The 'mode' property of an endpoint decoder indicates the access properties of the DPA (device physical address) mapped into HPA (host physical address) by the decoder. Where the modes are 'none' (decoder-disabled), 'ram' (voltaile memory), 'pmem' (persistent memory), and 'mixed' (an unexpected, but possible, case where the decoder straddles a mode / partition boundary). Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- Documentation/cxl/lib/libcxl.txt | 9 +++++++++ cxl/json.c | 8 ++++++++ cxl/lib/libcxl.c | 30 ++++++++++++++++++++++++++++++ cxl/lib/libcxl.sym | 1 + cxl/lib/private.h | 1 + cxl/libcxl.h | 23 +++++++++++++++++++++++ 6 files changed, 72 insertions(+)