|
|
|
|
@@ -1,6 +1,5 @@
|
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
|
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
|
|
|
|
|
#include <linux/io-64-nonatomic-hi-lo.h>
|
|
|
|
|
#include <linux/seq_file.h>
|
|
|
|
|
#include <linux/device.h>
|
|
|
|
|
#include <linux/delay.h>
|
|
|
|
|
@@ -93,8 +92,9 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb,
|
|
|
|
|
|
|
|
|
|
cxl_probe_component_regs(&port->dev, crb, &map.component_map);
|
|
|
|
|
if (!map.component_map.hdm_decoder.valid) {
|
|
|
|
|
dev_err(&port->dev, "HDM decoder registers invalid\n");
|
|
|
|
|
return -ENXIO;
|
|
|
|
|
dev_dbg(&port->dev, "HDM decoder registers not implemented\n");
|
|
|
|
|
/* unique error code to indicate no HDM decoder capability */
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cxl_map_component_regs(&port->dev, regs, &map,
|
|
|
|
|
@@ -130,6 +130,14 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < cxlhdm->decoder_count; i++) {
|
|
|
|
|
ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i));
|
|
|
|
|
dev_dbg(&info->port->dev,
|
|
|
|
|
"decoder%d.%d: committed: %ld base: %#x_%.8x size: %#x_%.8x\n",
|
|
|
|
|
info->port->id, i,
|
|
|
|
|
FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl),
|
|
|
|
|
readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(i)),
|
|
|
|
|
readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(i)),
|
|
|
|
|
readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(i)),
|
|
|
|
|
readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(i)));
|
|
|
|
|
if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@@ -269,8 +277,11 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
|
|
|
|
|
|
|
|
|
|
lockdep_assert_held_write(&cxl_dpa_rwsem);
|
|
|
|
|
|
|
|
|
|
if (!len)
|
|
|
|
|
goto success;
|
|
|
|
|
if (!len) {
|
|
|
|
|
dev_warn(dev, "decoder%d.%d: empty reservation attempted\n",
|
|
|
|
|
port->id, cxled->cxld.id);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cxled->dpa_res) {
|
|
|
|
|
dev_dbg(dev, "decoder%d.%d: existing allocation %pr assigned\n",
|
|
|
|
|
@@ -323,7 +334,6 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
|
|
|
|
|
cxled->mode = CXL_DECODER_MIXED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
success:
|
|
|
|
|
port->hdm_end++;
|
|
|
|
|
get_device(&cxled->cxld.dev);
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -783,8 +793,8 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
|
|
|
|
|
int *target_map, void __iomem *hdm, int which,
|
|
|
|
|
u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)
|
|
|
|
|
{
|
|
|
|
|
u64 size, base, skip, dpa_size, lo, hi;
|
|
|
|
|
struct cxl_endpoint_decoder *cxled;
|
|
|
|
|
u64 size, base, skip, dpa_size;
|
|
|
|
|
bool committed;
|
|
|
|
|
u32 remainder;
|
|
|
|
|
int i, rc;
|
|
|
|
|
@@ -799,8 +809,12 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
|
|
|
|
|
which, info);
|
|
|
|
|
|
|
|
|
|
ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which));
|
|
|
|
|
base = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which));
|
|
|
|
|
size = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which));
|
|
|
|
|
lo = readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which));
|
|
|
|
|
hi = readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(which));
|
|
|
|
|
base = (hi << 32) + lo;
|
|
|
|
|
lo = readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which));
|
|
|
|
|
hi = readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(which));
|
|
|
|
|
size = (hi << 32) + lo;
|
|
|
|
|
committed = !!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED);
|
|
|
|
|
cxld->commit = cxl_decoder_commit;
|
|
|
|
|
cxld->reset = cxl_decoder_reset;
|
|
|
|
|
@@ -833,6 +847,13 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
|
|
|
|
|
port->id, cxld->id);
|
|
|
|
|
return -ENXIO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (size == 0) {
|
|
|
|
|
dev_warn(&port->dev,
|
|
|
|
|
"decoder%d.%d: Committed with zero size\n",
|
|
|
|
|
port->id, cxld->id);
|
|
|
|
|
return -ENXIO;
|
|
|
|
|
}
|
|
|
|
|
port->commit_end = cxld->id;
|
|
|
|
|
} else {
|
|
|
|
|
/* unless / until type-2 drivers arrive, assume type-3 */
|
|
|
|
|
@@ -855,9 +876,14 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
|
|
dev_dbg(&port->dev, "decoder%d.%d: range: %#llx-%#llx iw: %d ig: %d\n",
|
|
|
|
|
port->id, cxld->id, cxld->hpa_range.start, cxld->hpa_range.end,
|
|
|
|
|
cxld->interleave_ways, cxld->interleave_granularity);
|
|
|
|
|
|
|
|
|
|
if (!info) {
|
|
|
|
|
target_list.value =
|
|
|
|
|
ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which));
|
|
|
|
|
lo = readl(hdm + CXL_HDM_DECODER0_TL_LOW(which));
|
|
|
|
|
hi = readl(hdm + CXL_HDM_DECODER0_TL_HIGH(which));
|
|
|
|
|
target_list.value = (hi << 32) + lo;
|
|
|
|
|
for (i = 0; i < cxld->interleave_ways; i++)
|
|
|
|
|
target_map[i] = target_list.target_id[i];
|
|
|
|
|
|
|
|
|
|
@@ -874,7 +900,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
|
|
|
|
|
port->id, cxld->id, size, cxld->interleave_ways);
|
|
|
|
|
return -ENXIO;
|
|
|
|
|
}
|
|
|
|
|
skip = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SKIP_LOW(which));
|
|
|
|
|
lo = readl(hdm + CXL_HDM_DECODER0_SKIP_LOW(which));
|
|
|
|
|
hi = readl(hdm + CXL_HDM_DECODER0_SKIP_HIGH(which));
|
|
|
|
|
skip = (hi << 32) + lo;
|
|
|
|
|
cxled = to_cxl_endpoint_decoder(&cxld->dev);
|
|
|
|
|
rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip);
|
|
|
|
|
if (rc) {
|
|
|
|
|
|