Loading drivers/cxl/core/core.h +14 −0 Original line number Diff line number Diff line Loading @@ -27,7 +27,21 @@ void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled); 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); #else static inline u64 cxl_trace_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa) { return ULLONG_MAX; } static inline struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) { return NULL; } static inline int cxl_get_poison_by_endpoint(struct cxl_port *port) { return 0; Loading drivers/cxl/core/mbox.c +30 −6 Original line number Diff line number Diff line Loading @@ -854,14 +854,38 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd, enum cxl_event_type event_type, const uuid_t *uuid, union cxl_event *evt) { if (event_type == CXL_CPER_EVENT_GEN_MEDIA) trace_cxl_general_media(cxlmd, type, &evt->gen_media); else if (event_type == CXL_CPER_EVENT_DRAM) trace_cxl_dram(cxlmd, type, &evt->dram); else if (event_type == CXL_CPER_EVENT_MEM_MODULE) if (event_type == CXL_CPER_EVENT_MEM_MODULE) { trace_cxl_memory_module(cxlmd, type, &evt->mem_module); else return; } if (event_type == CXL_CPER_EVENT_GENERIC) { trace_cxl_generic_event(cxlmd, type, uuid, &evt->generic); return; } if (trace_cxl_general_media_enabled() || trace_cxl_dram_enabled()) { u64 dpa, hpa = ULLONG_MAX; struct cxl_region *cxlr; /* * These trace points are annotated with HPA and region * translations. Take topology mutation locks and lookup * { HPA, REGION } from { DPA, MEMDEV } in the event record. */ guard(rwsem_read)(&cxl_region_rwsem); guard(rwsem_read)(&cxl_dpa_rwsem); dpa = le64_to_cpu(evt->common.phys_addr) & CXL_DPA_MASK; cxlr = cxl_dpa_to_region(cxlmd, dpa); if (cxlr) hpa = cxl_trace_hpa(cxlr, cxlmd, dpa); if (event_type == CXL_CPER_EVENT_GEN_MEDIA) trace_cxl_general_media(cxlmd, type, cxlr, hpa, &evt->gen_media); else if (event_type == CXL_CPER_EVENT_DRAM) trace_cxl_dram(cxlmd, type, cxlr, hpa, &evt->dram); } } EXPORT_SYMBOL_NS_GPL(cxl_event_trace_record, CXL); Loading drivers/cxl/core/memdev.c +0 −44 Original line number Diff line number Diff line Loading @@ -251,50 +251,6 @@ int cxl_trigger_poison_list(struct cxl_memdev *cxlmd) } EXPORT_SYMBOL_NS_GPL(cxl_trigger_poison_list, CXL); struct cxl_dpa_to_region_context { struct cxl_region *cxlr; u64 dpa; }; static int __cxl_dpa_to_region(struct device *dev, void *arg) { struct cxl_dpa_to_region_context *ctx = arg; struct cxl_endpoint_decoder *cxled; u64 dpa = ctx->dpa; if (!is_endpoint_decoder(dev)) return 0; cxled = to_cxl_endpoint_decoder(dev); if (!cxled->dpa_res || !resource_size(cxled->dpa_res)) return 0; if (dpa > cxled->dpa_res->end || dpa < cxled->dpa_res->start) return 0; dev_dbg(dev, "dpa:0x%llx mapped in region:%s\n", dpa, dev_name(&cxled->cxld.region->dev)); ctx->cxlr = cxled->cxld.region; return 1; } static struct cxl_region *cxl_dpa_to_region(struct cxl_memdev *cxlmd, u64 dpa) { struct cxl_dpa_to_region_context ctx; struct cxl_port *port; ctx = (struct cxl_dpa_to_region_context) { .dpa = dpa, }; port = cxlmd->endpoint; if (port && is_cxl_endpoint(port) && cxl_num_decoders_committed(port)) device_for_each_child(&port->dev, &ctx, __cxl_dpa_to_region); return ctx.cxlr; } static int cxl_validate_poison_dpa(struct cxl_memdev *cxlmd, u64 dpa) { struct cxl_dev_state *cxlds = cxlmd->cxlds; Loading drivers/cxl/core/region.c +135 −0 Original line number Diff line number Diff line Loading @@ -2679,6 +2679,141 @@ int cxl_get_poison_by_endpoint(struct cxl_port *port) return rc; } struct cxl_dpa_to_region_context { struct cxl_region *cxlr; u64 dpa; }; static int __cxl_dpa_to_region(struct device *dev, void *arg) { struct cxl_dpa_to_region_context *ctx = arg; struct cxl_endpoint_decoder *cxled; u64 dpa = ctx->dpa; if (!is_endpoint_decoder(dev)) return 0; cxled = to_cxl_endpoint_decoder(dev); if (!cxled->dpa_res || !resource_size(cxled->dpa_res)) return 0; if (dpa > cxled->dpa_res->end || dpa < cxled->dpa_res->start) return 0; dev_dbg(dev, "dpa:0x%llx mapped in region:%s\n", dpa, dev_name(&cxled->cxld.region->dev)); ctx->cxlr = cxled->cxld.region; return 1; } struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) { struct cxl_dpa_to_region_context ctx; struct cxl_port *port; ctx = (struct cxl_dpa_to_region_context) { .dpa = dpa, }; port = cxlmd->endpoint; if (port && is_cxl_endpoint(port) && cxl_num_decoders_committed(port)) device_for_each_child(&port->dev, &ctx, __cxl_dpa_to_region); return ctx.cxlr; } static bool cxl_is_hpa_in_range(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); if ((offset >= pos * gran) && (offset < (pos + 1) * gran)) return true; dev_dbg(&cxlr->dev, "Addr trans fail: hpa 0x%llx not in expected chunk\n", hpa); return false; } static u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr, struct cxl_endpoint_decoder *cxled) { u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa; struct cxl_region_params *p = &cxlr->params; int pos = cxled->pos; u16 eig = 0; u8 eiw = 0; ways_to_eiw(p->interleave_ways, &eiw); granularity_to_eig(p->interleave_granularity, &eig); /* * The device position in the region interleave set was removed * from the offset at HPA->DPA translation. To reconstruct the * HPA, place the 'pos' in the offset. * * The placement of 'pos' in the HPA is determined by interleave * ways and granularity and is defined in the CXL Spec 3.0 Section * 8.2.4.19.13 Implementation Note: Device Decode Logic */ /* Remove the dpa base */ dpa_offset = dpa - cxl_dpa_resource_start(cxled); mask_upper = GENMASK_ULL(51, eig + 8); if (eiw < 8) { hpa_offset = (dpa_offset & mask_upper) << eiw; hpa_offset |= pos << (eig + 8); } else { bits_upper = (dpa_offset & mask_upper) >> (eig + 8); bits_upper = bits_upper * 3; hpa_offset = ((bits_upper << (eiw - 8)) + pos) << (eig + 8); } /* The lower bits remain unchanged */ hpa_offset |= dpa_offset & GENMASK_ULL(eig + 7, 0); /* 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)) 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 struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr) Loading drivers/cxl/core/trace.c +0 −91 Original line number Diff line number Diff line Loading @@ -6,94 +6,3 @@ #define CREATE_TRACE_POINTS #include "trace.h" static bool cxl_is_hpa_in_range(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); if ((offset >= pos * gran) && (offset < (pos + 1) * gran)) return true; dev_dbg(&cxlr->dev, "Addr trans fail: hpa 0x%llx not in expected chunk\n", hpa); return false; } static u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr, struct cxl_endpoint_decoder *cxled) { u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa; struct cxl_region_params *p = &cxlr->params; int pos = cxled->pos; u16 eig = 0; u8 eiw = 0; ways_to_eiw(p->interleave_ways, &eiw); granularity_to_eig(p->interleave_granularity, &eig); /* * The device position in the region interleave set was removed * from the offset at HPA->DPA translation. To reconstruct the * HPA, place the 'pos' in the offset. * * The placement of 'pos' in the HPA is determined by interleave * ways and granularity and is defined in the CXL Spec 3.0 Section * 8.2.4.19.13 Implementation Note: Device Decode Logic */ /* Remove the dpa base */ dpa_offset = dpa - cxl_dpa_resource_start(cxled); mask_upper = GENMASK_ULL(51, eig + 8); if (eiw < 8) { hpa_offset = (dpa_offset & mask_upper) << eiw; hpa_offset |= pos << (eig + 8); } else { bits_upper = (dpa_offset & mask_upper) >> (eig + 8); bits_upper = bits_upper * 3; hpa_offset = ((bits_upper << (eiw - 8)) + pos) << (eig + 8); } /* The lower bits remain unchanged */ hpa_offset |= dpa_offset & GENMASK_ULL(eig + 7, 0); /* 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)) return ULLONG_MAX; return hpa; } u64 cxl_trace_hpa(struct cxl_region *cxlr, 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); } Loading
drivers/cxl/core/core.h +14 −0 Original line number Diff line number Diff line Loading @@ -27,7 +27,21 @@ void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled); 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); #else static inline u64 cxl_trace_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa) { return ULLONG_MAX; } static inline struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) { return NULL; } static inline int cxl_get_poison_by_endpoint(struct cxl_port *port) { return 0; Loading
drivers/cxl/core/mbox.c +30 −6 Original line number Diff line number Diff line Loading @@ -854,14 +854,38 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd, enum cxl_event_type event_type, const uuid_t *uuid, union cxl_event *evt) { if (event_type == CXL_CPER_EVENT_GEN_MEDIA) trace_cxl_general_media(cxlmd, type, &evt->gen_media); else if (event_type == CXL_CPER_EVENT_DRAM) trace_cxl_dram(cxlmd, type, &evt->dram); else if (event_type == CXL_CPER_EVENT_MEM_MODULE) if (event_type == CXL_CPER_EVENT_MEM_MODULE) { trace_cxl_memory_module(cxlmd, type, &evt->mem_module); else return; } if (event_type == CXL_CPER_EVENT_GENERIC) { trace_cxl_generic_event(cxlmd, type, uuid, &evt->generic); return; } if (trace_cxl_general_media_enabled() || trace_cxl_dram_enabled()) { u64 dpa, hpa = ULLONG_MAX; struct cxl_region *cxlr; /* * These trace points are annotated with HPA and region * translations. Take topology mutation locks and lookup * { HPA, REGION } from { DPA, MEMDEV } in the event record. */ guard(rwsem_read)(&cxl_region_rwsem); guard(rwsem_read)(&cxl_dpa_rwsem); dpa = le64_to_cpu(evt->common.phys_addr) & CXL_DPA_MASK; cxlr = cxl_dpa_to_region(cxlmd, dpa); if (cxlr) hpa = cxl_trace_hpa(cxlr, cxlmd, dpa); if (event_type == CXL_CPER_EVENT_GEN_MEDIA) trace_cxl_general_media(cxlmd, type, cxlr, hpa, &evt->gen_media); else if (event_type == CXL_CPER_EVENT_DRAM) trace_cxl_dram(cxlmd, type, cxlr, hpa, &evt->dram); } } EXPORT_SYMBOL_NS_GPL(cxl_event_trace_record, CXL); Loading
drivers/cxl/core/memdev.c +0 −44 Original line number Diff line number Diff line Loading @@ -251,50 +251,6 @@ int cxl_trigger_poison_list(struct cxl_memdev *cxlmd) } EXPORT_SYMBOL_NS_GPL(cxl_trigger_poison_list, CXL); struct cxl_dpa_to_region_context { struct cxl_region *cxlr; u64 dpa; }; static int __cxl_dpa_to_region(struct device *dev, void *arg) { struct cxl_dpa_to_region_context *ctx = arg; struct cxl_endpoint_decoder *cxled; u64 dpa = ctx->dpa; if (!is_endpoint_decoder(dev)) return 0; cxled = to_cxl_endpoint_decoder(dev); if (!cxled->dpa_res || !resource_size(cxled->dpa_res)) return 0; if (dpa > cxled->dpa_res->end || dpa < cxled->dpa_res->start) return 0; dev_dbg(dev, "dpa:0x%llx mapped in region:%s\n", dpa, dev_name(&cxled->cxld.region->dev)); ctx->cxlr = cxled->cxld.region; return 1; } static struct cxl_region *cxl_dpa_to_region(struct cxl_memdev *cxlmd, u64 dpa) { struct cxl_dpa_to_region_context ctx; struct cxl_port *port; ctx = (struct cxl_dpa_to_region_context) { .dpa = dpa, }; port = cxlmd->endpoint; if (port && is_cxl_endpoint(port) && cxl_num_decoders_committed(port)) device_for_each_child(&port->dev, &ctx, __cxl_dpa_to_region); return ctx.cxlr; } static int cxl_validate_poison_dpa(struct cxl_memdev *cxlmd, u64 dpa) { struct cxl_dev_state *cxlds = cxlmd->cxlds; Loading
drivers/cxl/core/region.c +135 −0 Original line number Diff line number Diff line Loading @@ -2679,6 +2679,141 @@ int cxl_get_poison_by_endpoint(struct cxl_port *port) return rc; } struct cxl_dpa_to_region_context { struct cxl_region *cxlr; u64 dpa; }; static int __cxl_dpa_to_region(struct device *dev, void *arg) { struct cxl_dpa_to_region_context *ctx = arg; struct cxl_endpoint_decoder *cxled; u64 dpa = ctx->dpa; if (!is_endpoint_decoder(dev)) return 0; cxled = to_cxl_endpoint_decoder(dev); if (!cxled->dpa_res || !resource_size(cxled->dpa_res)) return 0; if (dpa > cxled->dpa_res->end || dpa < cxled->dpa_res->start) return 0; dev_dbg(dev, "dpa:0x%llx mapped in region:%s\n", dpa, dev_name(&cxled->cxld.region->dev)); ctx->cxlr = cxled->cxld.region; return 1; } struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) { struct cxl_dpa_to_region_context ctx; struct cxl_port *port; ctx = (struct cxl_dpa_to_region_context) { .dpa = dpa, }; port = cxlmd->endpoint; if (port && is_cxl_endpoint(port) && cxl_num_decoders_committed(port)) device_for_each_child(&port->dev, &ctx, __cxl_dpa_to_region); return ctx.cxlr; } static bool cxl_is_hpa_in_range(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); if ((offset >= pos * gran) && (offset < (pos + 1) * gran)) return true; dev_dbg(&cxlr->dev, "Addr trans fail: hpa 0x%llx not in expected chunk\n", hpa); return false; } static u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr, struct cxl_endpoint_decoder *cxled) { u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa; struct cxl_region_params *p = &cxlr->params; int pos = cxled->pos; u16 eig = 0; u8 eiw = 0; ways_to_eiw(p->interleave_ways, &eiw); granularity_to_eig(p->interleave_granularity, &eig); /* * The device position in the region interleave set was removed * from the offset at HPA->DPA translation. To reconstruct the * HPA, place the 'pos' in the offset. * * The placement of 'pos' in the HPA is determined by interleave * ways and granularity and is defined in the CXL Spec 3.0 Section * 8.2.4.19.13 Implementation Note: Device Decode Logic */ /* Remove the dpa base */ dpa_offset = dpa - cxl_dpa_resource_start(cxled); mask_upper = GENMASK_ULL(51, eig + 8); if (eiw < 8) { hpa_offset = (dpa_offset & mask_upper) << eiw; hpa_offset |= pos << (eig + 8); } else { bits_upper = (dpa_offset & mask_upper) >> (eig + 8); bits_upper = bits_upper * 3; hpa_offset = ((bits_upper << (eiw - 8)) + pos) << (eig + 8); } /* The lower bits remain unchanged */ hpa_offset |= dpa_offset & GENMASK_ULL(eig + 7, 0); /* 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)) 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 struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr) Loading
drivers/cxl/core/trace.c +0 −91 Original line number Diff line number Diff line Loading @@ -6,94 +6,3 @@ #define CREATE_TRACE_POINTS #include "trace.h" static bool cxl_is_hpa_in_range(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); if ((offset >= pos * gran) && (offset < (pos + 1) * gran)) return true; dev_dbg(&cxlr->dev, "Addr trans fail: hpa 0x%llx not in expected chunk\n", hpa); return false; } static u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr, struct cxl_endpoint_decoder *cxled) { u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa; struct cxl_region_params *p = &cxlr->params; int pos = cxled->pos; u16 eig = 0; u8 eiw = 0; ways_to_eiw(p->interleave_ways, &eiw); granularity_to_eig(p->interleave_granularity, &eig); /* * The device position in the region interleave set was removed * from the offset at HPA->DPA translation. To reconstruct the * HPA, place the 'pos' in the offset. * * The placement of 'pos' in the HPA is determined by interleave * ways and granularity and is defined in the CXL Spec 3.0 Section * 8.2.4.19.13 Implementation Note: Device Decode Logic */ /* Remove the dpa base */ dpa_offset = dpa - cxl_dpa_resource_start(cxled); mask_upper = GENMASK_ULL(51, eig + 8); if (eiw < 8) { hpa_offset = (dpa_offset & mask_upper) << eiw; hpa_offset |= pos << (eig + 8); } else { bits_upper = (dpa_offset & mask_upper) >> (eig + 8); bits_upper = bits_upper * 3; hpa_offset = ((bits_upper << (eiw - 8)) + pos) << (eig + 8); } /* The lower bits remain unchanged */ hpa_offset |= dpa_offset & GENMASK_ULL(eig + 7, 0); /* 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)) return ULLONG_MAX; return hpa; } u64 cxl_trace_hpa(struct cxl_region *cxlr, 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); }