Skip to content

Commit 4474ce5

Browse files
davejiangdjbw
authored andcommitted
cxl/hdm: Create emulated cxl_hdm for devices that do not have HDM decoders
CXL rev3 spec 8.1.3 RCDs may not have HDM register blocks. Create a fake HDM with information from the CXL PCIe DVSEC registers. The decoder count will be set to the HDM count retrieved from the DVSEC cap register. Reviewed-by: Jonathan Cameron <[email protected]> Signed-off-by: Dave Jiang <[email protected]> Link: https://lore.kernel.org/r/167640368994.935665.15831225724059704620.stgit@dwillia2-xfh.jf.intel.com Signed-off-by: Dan Williams <[email protected]>
1 parent b777e9b commit 4474ce5

File tree

7 files changed

+66
-20
lines changed

7 files changed

+66
-20
lines changed

drivers/cxl/core/hdm.c

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,34 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb,
101101
BIT(CXL_CM_CAP_CAP_ID_HDM));
102102
}
103103

104+
static struct cxl_hdm *devm_cxl_setup_emulated_hdm(struct cxl_port *port,
105+
struct cxl_endpoint_dvsec_info *info)
106+
{
107+
struct device *dev = &port->dev;
108+
struct cxl_hdm *cxlhdm;
109+
110+
if (!info->mem_enabled)
111+
return ERR_PTR(-ENODEV);
112+
113+
cxlhdm = devm_kzalloc(dev, sizeof(*cxlhdm), GFP_KERNEL);
114+
if (!cxlhdm)
115+
return ERR_PTR(-ENOMEM);
116+
117+
cxlhdm->port = port;
118+
cxlhdm->decoder_count = info->ranges;
119+
cxlhdm->target_count = info->ranges;
120+
dev_set_drvdata(&port->dev, cxlhdm);
121+
122+
return cxlhdm;
123+
}
124+
104125
/**
105126
* devm_cxl_setup_hdm - map HDM decoder component registers
106127
* @port: cxl_port to map
128+
* @info: cached DVSEC range register info
107129
*/
108-
struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port)
130+
struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
131+
struct cxl_endpoint_dvsec_info *info)
109132
{
110133
struct device *dev = &port->dev;
111134
struct cxl_hdm *cxlhdm;
@@ -119,6 +142,9 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port)
119142
cxlhdm->port = port;
120143
crb = ioremap(port->component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE);
121144
if (!crb) {
145+
if (info->mem_enabled)
146+
return devm_cxl_setup_emulated_hdm(port, info);
147+
122148
dev_err(dev, "No component registers mapped\n");
123149
return ERR_PTR(-ENXIO);
124150
}
@@ -814,19 +840,15 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
814840
return 0;
815841
}
816842

817-
/**
818-
* devm_cxl_enumerate_decoders - add decoder objects per HDM register set
819-
* @cxlhdm: Structure to populate with HDM capabilities
820-
*/
821-
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
822-
struct cxl_endpoint_dvsec_info *info)
843+
static void cxl_settle_decoders(struct cxl_hdm *cxlhdm)
823844
{
824845
void __iomem *hdm = cxlhdm->regs.hdm_decoder;
825-
struct cxl_port *port = cxlhdm->port;
826-
int i, committed;
827-
u64 dpa_base = 0;
846+
int committed, i;
828847
u32 ctrl;
829848

849+
if (!hdm)
850+
return;
851+
830852
/*
831853
* Since the register resource was recently claimed via request_region()
832854
* be careful about trusting the "not-committed" status until the commit
@@ -843,6 +865,22 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
843865
/* ensure that future checks of committed can be trusted */
844866
if (committed != cxlhdm->decoder_count)
845867
msleep(20);
868+
}
869+
870+
/**
871+
* devm_cxl_enumerate_decoders - add decoder objects per HDM register set
872+
* @cxlhdm: Structure to populate with HDM capabilities
873+
* @info: cached DVSEC range register info
874+
*/
875+
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
876+
struct cxl_endpoint_dvsec_info *info)
877+
{
878+
void __iomem *hdm = cxlhdm->regs.hdm_decoder;
879+
struct cxl_port *port = cxlhdm->port;
880+
int i;
881+
u64 dpa_base = 0;
882+
883+
cxl_settle_decoders(cxlhdm);
846884

847885
for (i = 0; i < cxlhdm->decoder_count; i++) {
848886
int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };

drivers/cxl/core/pci.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -378,16 +378,19 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
378378
struct device *dev = cxlds->dev;
379379
struct cxl_port *root;
380380
int i, rc, allowed;
381-
u32 global_ctrl;
381+
u32 global_ctrl = 0;
382382

383-
global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);
383+
if (hdm)
384+
global_ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET);
384385

385386
/*
386387
* If the HDM Decoder Capability is already enabled then assume
387388
* that some other agent like platform firmware set it up.
388389
*/
389-
if (global_ctrl & CXL_HDM_DECODER_ENABLE)
390+
if (global_ctrl & CXL_HDM_DECODER_ENABLE || (!hdm && info->mem_enabled))
390391
return devm_cxl_enable_mem(&port->dev, cxlds);
392+
else if (!hdm)
393+
return -ENODEV;
391394

392395
root = to_cxl_port(port->dev.parent);
393396
while (!is_cxl_root(root) && is_cxl_port(root->dev.parent))

drivers/cxl/cxl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,8 @@ struct cxl_endpoint_dvsec_info {
643643
};
644644

645645
struct cxl_hdm;
646-
struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port);
646+
struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
647+
struct cxl_endpoint_dvsec_info *info);
647648
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
648649
struct cxl_endpoint_dvsec_info *info);
649650
int devm_cxl_add_passthrough_decoder(struct cxl_port *port);

drivers/cxl/port.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static int cxl_port_probe(struct device *dev)
5454
return devm_cxl_add_passthrough_decoder(port);
5555
}
5656

57-
cxlhdm = devm_cxl_setup_hdm(port);
57+
cxlhdm = devm_cxl_setup_hdm(port, &info);
5858
if (IS_ERR(cxlhdm))
5959
return PTR_ERR(cxlhdm);
6060

tools/testing/cxl/test/cxl.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,8 @@ static struct acpi_pci_root *mock_acpi_pci_find_root(acpi_handle handle)
618618
return &mock_pci_root[host_bridge_index(adev)];
619619
}
620620

621-
static struct cxl_hdm *mock_cxl_setup_hdm(struct cxl_port *port)
621+
static struct cxl_hdm *mock_cxl_setup_hdm(struct cxl_port *port,
622+
struct cxl_endpoint_dvsec_info *info)
622623
{
623624
struct cxl_hdm *cxlhdm = devm_kzalloc(&port->dev, sizeof(*cxlhdm), GFP_KERNEL);
624625

tools/testing/cxl/test/mock.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,18 @@ __wrap_nvdimm_bus_register(struct device *dev,
131131
}
132132
EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register);
133133

134-
struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port)
134+
struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port,
135+
struct cxl_endpoint_dvsec_info *info)
136+
135137
{
136138
int index;
137139
struct cxl_hdm *cxlhdm;
138140
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
139141

140142
if (ops && ops->is_mock_port(port->uport))
141-
cxlhdm = ops->devm_cxl_setup_hdm(port);
143+
cxlhdm = ops->devm_cxl_setup_hdm(port, info);
142144
else
143-
cxlhdm = devm_cxl_setup_hdm(port);
145+
cxlhdm = devm_cxl_setup_hdm(port, info);
144146
put_cxl_mock_ops(index);
145147

146148
return cxlhdm;

tools/testing/cxl/test/mock.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ struct cxl_mock_ops {
2323
bool (*is_mock_port)(struct device *dev);
2424
bool (*is_mock_dev)(struct device *dev);
2525
int (*devm_cxl_port_enumerate_dports)(struct cxl_port *port);
26-
struct cxl_hdm *(*devm_cxl_setup_hdm)(struct cxl_port *port);
26+
struct cxl_hdm *(*devm_cxl_setup_hdm)(
27+
struct cxl_port *port, struct cxl_endpoint_dvsec_info *info);
2728
int (*devm_cxl_add_passthrough_decoder)(struct cxl_port *port);
2829
int (*devm_cxl_enumerate_decoders)(
2930
struct cxl_hdm *hdm, struct cxl_endpoint_dvsec_info *info);

0 commit comments

Comments
 (0)