@@ -8,6 +8,7 @@
#include <linux/pci.h>
#include <asm/div64.h>
#include "cxlpci.h"
+#include "cxlmem.h"
#include "cxl.h"
struct cxl_cxims_data {
@@ -38,6 +39,44 @@ static int cxl_xor_calc_n(u64 hpa, struct cxl_cxims_data *cximsd, int iw,
return n;
}
+static bool cxl_xor_hpa_to_dport(u64 hpa, struct cxl_root_decoder *cxlrd,
+ struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_cxims_data *cximsd = cxlrd->platform_data;
+ int ig = cxled->cxld.interleave_granularity;
+ int iw = cxled->cxld.interleave_ways;
+ struct cxl_dport *match_dport;
+ int n = 0;
+
+ if (iw != 1)
+ n = cxl_xor_calc_n(hpa, cximsd, iw, ig);
+
+ match_dport = cxl_find_dport_by_dev(cxlrd_to_port(cxlrd),
+ cxled_to_port(cxled)->host_bridge);
+ if (cxlrd->cxlsd.target[n] != match_dport)
+ return false;
+
+ return true;
+}
+
+static u64 cxl_dpa_to_hpa_xor(u64 dpa, struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
+ u64 hpa;
+
+ hpa = cxl_dpa_to_hpa(dpa, cxlr, cxled);
+ if (!hpa)
+ return 0;
+
+ if (!cxl_xor_hpa_to_dport(hpa, cxlrd, cxled)) {
+ dev_dbg(&cxlr->dev,
+ "Addr trans fail: hpa:0x%llx dport mismatch\n", hpa);
+ return 0;
+ }
+ return hpa;
+}
+
static struct cxl_dport *cxl_hb_xor(struct cxl_root_decoder *cxlrd, int pos)
{
struct cxl_cxims_data *cximsd = cxlrd->platform_data;
@@ -193,6 +232,7 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
struct cxl_root_decoder *cxlrd;
struct device *dev = ctx->dev;
struct acpi_cedt_cfmws *cfmws;
+ cxl_calc_hpa_fn cxl_calc_hpa;
cxl_calc_hb_fn cxl_calc_hb;
struct cxl_decoder *cxld;
unsigned int ways, i, ig;
@@ -235,12 +275,16 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
if (rc)
goto err_insert;
- if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_MODULO)
+ if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_MODULO) {
cxl_calc_hb = cxl_hb_modulo;
- else
+ cxl_calc_hpa = cxl_dpa_to_hpa;
+ } else {
cxl_calc_hb = cxl_hb_xor;
+ cxl_calc_hpa = cxl_dpa_to_hpa_xor;
+ }
- cxlrd = cxl_root_decoder_alloc(root_port, ways, cxl_calc_hb);
+ cxlrd = cxl_root_decoder_alloc(root_port, ways, cxl_calc_hb,
+ cxl_calc_hpa);
if (IS_ERR(cxlrd))
return 0;
@@ -67,9 +67,6 @@ static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port,
return xa_load(&port->endpoints, (unsigned long)&cxlmd->dev);
}
-u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr,
- struct cxl_endpoint_decoder *cxled);
-
int cxl_memdev_init(void);
void cxl_memdev_exit(void);
void cxl_mbox_init(void);
@@ -1504,6 +1504,7 @@ static int cxl_switch_decoder_init(struct cxl_port *port,
* @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
+ * @calc_hpa: dpa to hpa address translation function
*
* 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
@@ -1512,7 +1513,8 @@ static int cxl_switch_decoder_init(struct cxl_port *port,
*/
struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
unsigned int nr_targets,
- cxl_calc_hb_fn calc_hb)
+ cxl_calc_hb_fn calc_hb,
+ cxl_calc_hpa_fn calc_hpa)
{
struct cxl_root_decoder *cxlrd;
struct cxl_switch_decoder *cxlsd;
@@ -1535,6 +1537,7 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
}
cxlrd->calc_hb = calc_hb;
+ cxlrd->calc_hpa = calc_hpa;
cxld = &cxlsd->cxld;
cxld->dev.type = &cxl_decoder_root_type;
@@ -1944,9 +1944,11 @@ u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr,
return hpa;
}
+EXPORT_SYMBOL_NS_GPL(cxl_dpa_to_hpa, CXL);
static bool cxl_check_addrtrans(struct cxl_region *cxlr)
{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent);
struct cxl_region_params *p = &cxlr->params;
struct cxl_endpoint_decoder *cxled;
u64 start, end, dpa;
@@ -1961,15 +1963,15 @@ static bool cxl_check_addrtrans(struct cxl_region *cxlr)
end = start + cxl_dpa_size(cxled) - 1;
dpa = start;
- if (!cxl_dpa_to_hpa(dpa, cxlr, cxled))
+ if (!cxlrd->calc_hpa(dpa, cxlr, cxled))
return false;
dpa = start + cxl_dpa_size(cxled) / 2;
- if (!cxl_dpa_to_hpa(dpa, cxlr, cxled))
+ if (!cxlrd->calc_hpa(dpa, cxlr, cxled))
return false;
dpa = end;
- if (!cxl_dpa_to_hpa(dpa, cxlr, cxled))
+ if (!cxlrd->calc_hpa(dpa, cxlr, cxled))
return false;
}
return true;
@@ -328,12 +328,15 @@ struct cxl_root_decoder;
struct cxl_endpoint_decoder;
typedef struct cxl_dport *(*cxl_calc_hb_fn)(struct cxl_root_decoder *cxlrd,
int pos);
+typedef u64 (*cxl_calc_hpa_fn)(u64 dpa, struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled);
/**
* struct cxl_root_decoder - Static platform CXL address decoder
* @res: host / parent resource for region allocations
* @region_id: region id for next region provisioning event
* @calc_hb: which host bridge covers the n'th position by granularity
+ * @calc_hpa: dpa to hpa address translation function
* @platform_data: platform specific configuration data
* @cxlsd: base cxl switch decoder
*/
@@ -341,6 +344,7 @@ struct cxl_root_decoder {
struct resource *res;
atomic_t region_id;
cxl_calc_hb_fn calc_hb;
+ cxl_calc_hpa_fn calc_hpa;
void *platform_data;
struct cxl_switch_decoder cxlsd;
};
@@ -589,7 +593,10 @@ bool is_endpoint_decoder(struct device *dev);
struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
unsigned int nr_targets,
- cxl_calc_hb_fn calc_hb);
+ cxl_calc_hb_fn calc_hb,
+ cxl_calc_hpa_fn calc_hpa);
+
+/* TODO should cxl_hb_module be of type 'cxl_calc_hb_fn */
struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos);
struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
unsigned int nr_targets);
@@ -598,6 +605,8 @@ struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port);
int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map);
int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld);
int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint);
+u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr,
+ struct cxl_endpoint_decoder *cxled);
struct cxl_hdm;
struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port);