mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
cxl/test: Fixup hdm init for auto region to support type2
Add support to setup initialization of decoders in order to support type2 auto region. Reviewed-by: Alison Schofield <alison.schofield@intel.com> Tested-by: Alison Schofield <alison.schofield@intel.com> Link: https://patch.msgid.link/20260629221104.3891733-7-dave.jiang@intel.com Signed-off-by: Dave Jiang <dave.jiang@intel.com>
This commit is contained in:
parent
98ba41c323
commit
b3df5a5a38
|
|
@ -1084,74 +1084,26 @@ static int first_decoder(struct device *dev, const void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a decoder during HDM enumeration.
|
||||
*
|
||||
* If a saved registry entry exists:
|
||||
* - enabled decoders are restored from the saved programming
|
||||
* - disabled decoders are initialized in a clean disabled state
|
||||
*
|
||||
* If no registry entry exists the decoder follows the normal mock
|
||||
* initialization path, including the special auto-region setup for
|
||||
* the first endpoints under host-bridge0.
|
||||
*
|
||||
* Returns true if decoder state was restored from the registry. In
|
||||
* that case the saved decode configuration (including target mapping)
|
||||
* has already been applied and the map_targets() is skipped.
|
||||
*/
|
||||
static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
|
||||
enum cxld_init_type {
|
||||
MOCK_DECODER_INIT_DEFAULT,
|
||||
MOCK_DECODER_INIT_SAVED,
|
||||
MOCK_DECODER_INIT_TYPE3_AUTO,
|
||||
MOCK_DECODER_INIT_TYPE2_AUTO,
|
||||
};
|
||||
|
||||
static enum cxld_init_type get_decoder_init_type(struct cxl_decoder *cxld,
|
||||
struct platform_device *pdev,
|
||||
bool hb0,
|
||||
struct cxl_test_decoder **td)
|
||||
{
|
||||
struct acpi_cedt_cfmws *window = mock_cfmws[0];
|
||||
struct platform_device *pdev = NULL;
|
||||
struct cxl_endpoint_decoder *cxled;
|
||||
struct cxl_switch_decoder *cxlsd;
|
||||
struct cxl_port *port, *iter;
|
||||
struct cxl_test_decoder *td;
|
||||
struct cxl_memdev *cxlmd;
|
||||
struct cxl_dport *dport;
|
||||
struct device *dev;
|
||||
bool hb0 = false;
|
||||
u64 base;
|
||||
int i;
|
||||
struct cxl_test_decoder *found_td = cxld_registry_find(cxld);
|
||||
|
||||
if (is_endpoint_decoder(&cxld->dev)) {
|
||||
cxled = to_cxl_endpoint_decoder(&cxld->dev);
|
||||
cxlmd = cxled_to_memdev(cxled);
|
||||
WARN_ON(!dev_is_platform(cxlmd->dev.parent));
|
||||
pdev = to_platform_device(cxlmd->dev.parent);
|
||||
|
||||
/* check is endpoint is attach to host-bridge0 */
|
||||
port = cxled_to_port(cxled);
|
||||
do {
|
||||
if (port->uport_dev == &cxl_host_bridge[0]->dev) {
|
||||
hb0 = true;
|
||||
break;
|
||||
}
|
||||
if (is_cxl_port(port->dev.parent))
|
||||
port = to_cxl_port(port->dev.parent);
|
||||
else
|
||||
port = NULL;
|
||||
} while (port);
|
||||
port = cxled_to_port(cxled);
|
||||
} else {
|
||||
port = to_cxl_port(cxld->dev.parent);
|
||||
if (found_td) {
|
||||
*td = found_td;
|
||||
return MOCK_DECODER_INIT_SAVED;
|
||||
}
|
||||
|
||||
td = cxld_registry_find(cxld);
|
||||
if (td) {
|
||||
bool enabled;
|
||||
|
||||
if (is_switch_decoder(&cxld->dev))
|
||||
enabled = td->cxlsd.cxld.flags & CXL_DECODER_F_ENABLE;
|
||||
else
|
||||
enabled = td->cxled.cxld.flags & CXL_DECODER_F_ENABLE;
|
||||
|
||||
if (enabled)
|
||||
return !cxld_registry_restore(cxld, td);
|
||||
|
||||
init_disabled_mock_decoder(cxld);
|
||||
return false;
|
||||
}
|
||||
*td = NULL;
|
||||
|
||||
/*
|
||||
* The first decoder on the first 2 devices on the first switch
|
||||
|
|
@ -1162,15 +1114,119 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
|
|||
* See 'cxl list -BMPu -m cxl_mem.0,cxl_mem.4'
|
||||
*/
|
||||
if (!is_endpoint_decoder(&cxld->dev) || !hb0 || pdev->id % 4 ||
|
||||
pdev->id > 4 || cxld->id > 0) {
|
||||
default_mock_decoder(cxld);
|
||||
return false;
|
||||
}
|
||||
pdev->id > 4 || cxld->id > 0)
|
||||
return MOCK_DECODER_INIT_DEFAULT;
|
||||
|
||||
return type2_test ? MOCK_DECODER_INIT_TYPE2_AUTO :
|
||||
MOCK_DECODER_INIT_TYPE3_AUTO;
|
||||
}
|
||||
|
||||
static bool mock_decoder_handle_saved(struct cxl_decoder *cxld, struct cxl_test_decoder *td)
|
||||
{
|
||||
bool enabled;
|
||||
|
||||
if (is_switch_decoder(&cxld->dev))
|
||||
enabled = td->cxlsd.cxld.flags & CXL_DECODER_F_ENABLE;
|
||||
else
|
||||
enabled = td->cxled.cxld.flags & CXL_DECODER_F_ENABLE;
|
||||
|
||||
if (enabled)
|
||||
return !cxld_registry_restore(cxld, td);
|
||||
|
||||
init_disabled_mock_decoder(cxld);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void mock_init_hdm_type2_cxled(struct cxl_endpoint_decoder *cxled,
|
||||
struct cxl_port *port)
|
||||
{
|
||||
struct acpi_cedt_cfmws *window = mock_cfmws[0];
|
||||
struct cxl_decoder *cxld = &cxled->cxld;
|
||||
struct cxl_switch_decoder *cxlsd;
|
||||
struct cxl_dport *dport;
|
||||
struct cxl_port *root_port;
|
||||
struct device *dev;
|
||||
u64 base;
|
||||
|
||||
base = window->base_hpa;
|
||||
cxld->hpa_range = (struct range) {
|
||||
.start = base,
|
||||
.end = base + mock_auto_region_size - 1,
|
||||
};
|
||||
|
||||
cxld->interleave_ways = 1;
|
||||
eig_to_granularity(window->granularity, &cxld->interleave_granularity);
|
||||
cxld->target_type = CXL_DECODER_DEVMEM;
|
||||
cxld->flags = CXL_DECODER_F_ENABLE;
|
||||
cxled->state = CXL_DECODER_STATE_AUTO;
|
||||
port->commit_end = cxld->id;
|
||||
devm_cxl_dpa_reserve(cxled, 0,
|
||||
mock_auto_region_size / cxld->interleave_ways, 0);
|
||||
cxld->commit = mock_decoder_commit;
|
||||
cxld->reset = mock_decoder_reset;
|
||||
|
||||
WARN_ON_ONCE(!cxld_registry_new(cxld));
|
||||
/*
|
||||
* Now that endpoint decoder is set up, walk up the hierarchy
|
||||
* and setup the root port decoder targeting @cxlmd.
|
||||
*/
|
||||
dport = port->parent_dport;
|
||||
root_port = dport->port;
|
||||
dev = device_find_child(&root_port->dev, NULL, first_decoder);
|
||||
/*
|
||||
* Ancestor ports are guaranteed to be enumerated before
|
||||
* @port, and all ports have at least one decoder.
|
||||
*/
|
||||
if (WARN_ON(!dev))
|
||||
return;
|
||||
|
||||
cxlsd = to_cxl_switch_decoder(dev);
|
||||
cxld = &cxlsd->cxld;
|
||||
cxld->target_type = CXL_DECODER_DEVMEM;
|
||||
cxld->flags = CXL_DECODER_F_ENABLE;
|
||||
root_port->commit_end = 0;
|
||||
cxld->interleave_ways = 1;
|
||||
cxld->interleave_granularity = 4096;
|
||||
cxld->target_map[0] = dport->port_id;
|
||||
cxld->hpa_range = (struct range) {
|
||||
.start = base,
|
||||
.end = base + mock_auto_region_size - 1,
|
||||
};
|
||||
cxld->commit = mock_decoder_commit;
|
||||
cxld->reset = mock_decoder_reset;
|
||||
|
||||
/*
|
||||
* Only target_map[] is programmed above, mimicking
|
||||
* firmware. On real hardware target[] is populated as
|
||||
* dports enumerate, via update_decoder_targets(). The
|
||||
* mock's dports are already bound by now, so fire that
|
||||
* resolution explicitly here rather than stamping
|
||||
* target[] directly.
|
||||
*/
|
||||
cxl_port_update_decoder_targets(root_port, dport);
|
||||
|
||||
cxld_registry_update(cxld);
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
static void mock_init_hdm_type3_cxled(struct cxl_endpoint_decoder *cxled,
|
||||
struct cxl_port *port,
|
||||
struct platform_device *pdev,
|
||||
bool hb0)
|
||||
{
|
||||
struct acpi_cedt_cfmws *window = mock_cfmws[0];
|
||||
struct cxl_decoder *cxld = &cxled->cxld;
|
||||
struct cxl_switch_decoder *cxlsd;
|
||||
struct cxl_dport *dport;
|
||||
struct cxl_port *iter;
|
||||
struct device *dev;
|
||||
u64 base;
|
||||
int i;
|
||||
|
||||
/* Simulate missing cxl_mem.4 configuration */
|
||||
if (hb0 && pdev->id == 4 && cxld->id == 0 && fail_autoassemble) {
|
||||
default_mock_decoder(cxld);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
base = window->base_hpa;
|
||||
|
|
@ -1252,7 +1308,76 @@ static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
|
|||
cxld_registry_update(cxld);
|
||||
put_device(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a decoder during HDM enumeration.
|
||||
*
|
||||
* If a saved registry entry exists:
|
||||
* - enabled decoders are restored from the saved programming
|
||||
* - disabled decoders are initialized in a clean disabled state
|
||||
*
|
||||
* If no registry entry exists the decoder follows the normal mock
|
||||
* initialization path, including the special auto-region setup for
|
||||
* the first endpoints under host-bridge0.
|
||||
*
|
||||
* Returns true if decoder state was restored from the registry. In
|
||||
* that case the saved decode configuration (including target mapping)
|
||||
* has already been applied and the map_targets() is skipped.
|
||||
*/
|
||||
static bool mock_init_hdm_decoder(struct cxl_decoder *cxld)
|
||||
{
|
||||
struct cxl_endpoint_decoder *cxled = NULL;
|
||||
struct platform_device *pdev = NULL;
|
||||
struct cxl_test_decoder *td;
|
||||
struct cxl_memdev *cxlmd;
|
||||
struct cxl_port *port;
|
||||
bool hb0 = false;
|
||||
|
||||
if (is_endpoint_decoder(&cxld->dev)) {
|
||||
cxled = to_cxl_endpoint_decoder(&cxld->dev);
|
||||
cxlmd = cxled_to_memdev(cxled);
|
||||
WARN_ON(!dev_is_platform(cxlmd->dev.parent));
|
||||
pdev = to_platform_device(cxlmd->dev.parent);
|
||||
|
||||
/* check is endpoint is attach to host-bridge0 */
|
||||
port = cxled_to_port(cxled);
|
||||
do {
|
||||
if (port->uport_dev == &cxl_host_bridge[0]->dev) {
|
||||
hb0 = true;
|
||||
break;
|
||||
}
|
||||
if (is_cxl_port(port->dev.parent))
|
||||
port = to_cxl_port(port->dev.parent);
|
||||
else
|
||||
port = NULL;
|
||||
} while (port);
|
||||
port = cxled_to_port(cxled);
|
||||
} else {
|
||||
port = to_cxl_port(cxld->dev.parent);
|
||||
}
|
||||
|
||||
switch (get_decoder_init_type(cxld, pdev, hb0, &td)) {
|
||||
case MOCK_DECODER_INIT_SAVED:
|
||||
if (WARN_ON(!td))
|
||||
return false;
|
||||
return mock_decoder_handle_saved(cxld, td);
|
||||
case MOCK_DECODER_INIT_DEFAULT:
|
||||
/*
|
||||
* The default path picks up all the decoders that are not
|
||||
* endpoint.
|
||||
*/
|
||||
default_mock_decoder(cxld);
|
||||
return false;
|
||||
case MOCK_DECODER_INIT_TYPE3_AUTO:
|
||||
mock_init_hdm_type3_cxled(cxled, port, pdev, hb0);
|
||||
return false;
|
||||
case MOCK_DECODER_INIT_TYPE2_AUTO:
|
||||
mock_init_hdm_type2_cxled(cxled, port);
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user