Skip to content

Commit

Permalink
cxl/hdm: Emulate HDM decoder from DVSEC range registers
Browse files Browse the repository at this point in the history
In the case where HDM decoder register block exists but is not programmed
and at the same time the DVSEC range register range is active, populate the
CXL decoder object 'cxl_decoder' with info from DVSEC range registers.

Reviewed-by: Jonathan Cameron <[email protected]>
Signed-off-by: Dave Jiang <[email protected]>
Link: https://lore.kernel.org/r/167640368454.935665.13806415120298330717.stgit@dwillia2-xfh.jf.intel.com
Signed-off-by: Dan Williams <[email protected]>
  • Loading branch information
davejiang authored and djbw committed Feb 14, 2023
1 parent 9de321e commit b777e9b
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 11 deletions.
36 changes: 33 additions & 3 deletions drivers/cxl/core/hdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -679,9 +679,34 @@ static int cxl_decoder_reset(struct cxl_decoder *cxld)
return 0;
}

static int cxl_setup_hdm_decoder_from_dvsec(struct cxl_port *port,
struct cxl_decoder *cxld, int which,
struct cxl_endpoint_dvsec_info *info)
{
if (!is_cxl_endpoint(port))
return -EOPNOTSUPP;

if (!range_len(&info->dvsec_range[which]))
return -ENOENT;

cxld->target_type = CXL_DECODER_EXPANDER;
cxld->commit = NULL;
cxld->reset = NULL;
cxld->hpa_range = info->dvsec_range[which];

/*
* Set the emulated decoder as locked pending additional support to
* change the range registers at run time.
*/
cxld->flags |= CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK;
port->commit_end = cxld->id;

return 0;
}

static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
int *target_map, void __iomem *hdm, int which,
u64 *dpa_base)
u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)
{
struct cxl_endpoint_decoder *cxled = NULL;
u64 size, base, skip, dpa_size;
Expand Down Expand Up @@ -717,6 +742,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
.end = base + size - 1,
};

if (cxled && !committed && range_len(&info->dvsec_range[which]))
return cxl_setup_hdm_decoder_from_dvsec(port, cxld, which, info);

/* decoders are enabled if committed */
if (committed) {
cxld->flags |= CXL_DECODER_F_ENABLE;
Expand Down Expand Up @@ -790,7 +818,8 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
* devm_cxl_enumerate_decoders - add decoder objects per HDM register set
* @cxlhdm: Structure to populate with HDM capabilities
*/
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
struct cxl_endpoint_dvsec_info *info)
{
void __iomem *hdm = cxlhdm->regs.hdm_decoder;
struct cxl_port *port = cxlhdm->port;
Expand Down Expand Up @@ -842,7 +871,8 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
cxld = &cxlsd->cxld;
}

rc = init_hdm_decoder(port, cxld, target_map, hdm, i, &dpa_base);
rc = init_hdm_decoder(port, cxld, target_map, hdm, i,
&dpa_base, info);
if (rc) {
put_device(&cxld->dev);
return rc;
Expand Down
2 changes: 1 addition & 1 deletion drivers/cxl/core/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
* Decoder Capability Enable.
*/
if (info->mem_enabled)
return -EBUSY;
return 0;

rc = devm_cxl_enable_hdm(&port->dev, cxlhdm);
if (rc)
Expand Down
3 changes: 2 additions & 1 deletion drivers/cxl/cxl.h
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,8 @@ struct cxl_endpoint_dvsec_info {

struct cxl_hdm;
struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port);
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm);
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
struct cxl_endpoint_dvsec_info *info);
int devm_cxl_add_passthrough_decoder(struct cxl_port *port);
int cxl_dvsec_rr_decode(struct device *dev, int dvsec,
struct cxl_endpoint_dvsec_info *info);
Expand Down
2 changes: 1 addition & 1 deletion drivers/cxl/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ static int cxl_port_probe(struct device *dev)
}
}

rc = devm_cxl_enumerate_decoders(cxlhdm);
rc = devm_cxl_enumerate_decoders(cxlhdm, &info);
if (rc) {
dev_err(dev, "Couldn't enumerate decoders (%d)\n", rc);
return rc;
Expand Down
3 changes: 2 additions & 1 deletion tools/testing/cxl/test/cxl.c
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,8 @@ static int mock_decoder_reset(struct cxl_decoder *cxld)
return 0;
}

static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
struct cxl_endpoint_dvsec_info *info)
{
struct cxl_port *port = cxlhdm->port;
struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
Expand Down
7 changes: 4 additions & 3 deletions tools/testing/cxl/test/mock.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,17 @@ int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port)
}
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_passthrough_decoder, CXL);

int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
struct cxl_endpoint_dvsec_info *info)
{
int rc, index;
struct cxl_port *port = cxlhdm->port;
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);

if (ops && ops->is_mock_port(port->uport))
rc = ops->devm_cxl_enumerate_decoders(cxlhdm);
rc = ops->devm_cxl_enumerate_decoders(cxlhdm, info);
else
rc = devm_cxl_enumerate_decoders(cxlhdm);
rc = devm_cxl_enumerate_decoders(cxlhdm, info);
put_cxl_mock_ops(index);

return rc;
Expand Down
3 changes: 2 additions & 1 deletion tools/testing/cxl/test/mock.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ struct cxl_mock_ops {
int (*devm_cxl_port_enumerate_dports)(struct cxl_port *port);
struct cxl_hdm *(*devm_cxl_setup_hdm)(struct cxl_port *port);
int (*devm_cxl_add_passthrough_decoder)(struct cxl_port *port);
int (*devm_cxl_enumerate_decoders)(struct cxl_hdm *hdm);
int (*devm_cxl_enumerate_decoders)(
struct cxl_hdm *hdm, struct cxl_endpoint_dvsec_info *info);
};

void register_cxl_mock_ops(struct cxl_mock_ops *ops);
Expand Down

0 comments on commit b777e9b

Please sign in to comment.