Skip to content

Commit

Permalink
mem/cxl_type3: Add read and write functions for associated hostmem.
Browse files Browse the repository at this point in the history
Once a read or write reaches a CXL type 3 device, the HDM decoders
on the device are used to establish the Device Physical Address
which should be accessed.  These functions peform the required maths
and then use a device specific address space to access the
hostmem->mr to fullfil the actual operation.  Note that failed writes
are silent, but failed reads return poison.  Note this is based
loosely on:

https://lore.kernel.org/qemu-devel/20200817161853.593247-6-f4bug@amsat.org/
[RFC PATCH 0/9] hw/misc: Add support for interleaved memory accesses

Only lightly tested so far.  More complex test cases yet to be written.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Message-Id: <20220429144110.25167-33-Jonathan.Cameron@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
  • Loading branch information
jic23 authored and mstsirkin committed May 13, 2022
1 parent 0b4aec2 commit 5fcc499
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 0 deletions.
91 changes: 91 additions & 0 deletions hw/mem/cxl_type3.c
Expand Up @@ -97,7 +97,9 @@ static void ct3d_reg_write(void *opaque, hwaddr offset, uint64_t value,

static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
{
DeviceState *ds = DEVICE(ct3d);
MemoryRegion *mr;
char *name;

if (!ct3d->hostmem) {
error_setg(errp, "memdev property must be set");
Expand All @@ -112,6 +114,15 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
memory_region_set_nonvolatile(mr, true);
memory_region_set_enabled(mr, true);
host_memory_backend_set_mapped(ct3d->hostmem, true);

if (ds->id) {
name = g_strdup_printf("cxl-type3-dpa-space:%s", ds->id);
} else {
name = g_strdup("cxl-type3-dpa-space");
}
address_space_init(&ct3d->hostmem_as, mr, name);
g_free(name);

ct3d->cxl_dstate.pmem_size = ct3d->hostmem->size;

if (!ct3d->lsa) {
Expand Down Expand Up @@ -167,6 +178,86 @@ static void ct3_exit(PCIDevice *pci_dev)
ComponentRegisters *regs = &cxl_cstate->crb;

g_free(regs->special_ops);
address_space_destroy(&ct3d->hostmem_as);
}

/* TODO: Support multiple HDM decoders and DPA skip */
static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa)
{
uint32_t *cache_mem = ct3d->cxl_cstate.crb.cache_mem_registers;
uint64_t decoder_base, decoder_size, hpa_offset;
uint32_t hdm0_ctrl;
int ig, iw;

decoder_base = (((uint64_t)cache_mem[R_CXL_HDM_DECODER0_BASE_HI] << 32) |
cache_mem[R_CXL_HDM_DECODER0_BASE_LO]);
if ((uint64_t)host_addr < decoder_base) {
return false;
}

hpa_offset = (uint64_t)host_addr - decoder_base;

decoder_size = ((uint64_t)cache_mem[R_CXL_HDM_DECODER0_SIZE_HI] << 32) |
cache_mem[R_CXL_HDM_DECODER0_SIZE_LO];
if (hpa_offset >= decoder_size) {
return false;
}

hdm0_ctrl = cache_mem[R_CXL_HDM_DECODER0_CTRL];
iw = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IW);
ig = FIELD_EX32(hdm0_ctrl, CXL_HDM_DECODER0_CTRL, IG);

*dpa = (MAKE_64BIT_MASK(0, 8 + ig) & hpa_offset) |
((MAKE_64BIT_MASK(8 + ig + iw, 64 - 8 - ig - iw) & hpa_offset) >> iw);

return true;
}

MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data,
unsigned size, MemTxAttrs attrs)
{
CXLType3Dev *ct3d = CXL_TYPE3(d);
uint64_t dpa_offset;
MemoryRegion *mr;

/* TODO support volatile region */
mr = host_memory_backend_get_memory(ct3d->hostmem);
if (!mr) {
return MEMTX_ERROR;
}

if (!cxl_type3_dpa(ct3d, host_addr, &dpa_offset)) {
return MEMTX_ERROR;
}

if (dpa_offset > int128_get64(mr->size)) {
return MEMTX_ERROR;
}

return address_space_read(&ct3d->hostmem_as, dpa_offset, attrs, data, size);
}

MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data,
unsigned size, MemTxAttrs attrs)
{
CXLType3Dev *ct3d = CXL_TYPE3(d);
uint64_t dpa_offset;
MemoryRegion *mr;

mr = host_memory_backend_get_memory(ct3d->hostmem);
if (!mr) {
return MEMTX_OK;
}

if (!cxl_type3_dpa(ct3d, host_addr, &dpa_offset)) {
return MEMTX_OK;
}

if (dpa_offset > int128_get64(mr->size)) {
return MEMTX_OK;
}
return address_space_write(&ct3d->hostmem_as, dpa_offset, attrs,
&data, size);
}

static void ct3d_reset(DeviceState *dev)
Expand Down
6 changes: 6 additions & 0 deletions include/hw/cxl/cxl_device.h
Expand Up @@ -239,6 +239,7 @@ struct CXLType3Dev {
HostMemoryBackend *lsa;

/* State */
AddressSpace hostmem_as;
CXLComponentState cxl_cstate;
CXLDeviceState cxl_dstate;
};
Expand All @@ -259,4 +260,9 @@ struct CXLType3Class {
uint64_t offset);
};

MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data,
unsigned size, MemTxAttrs attrs);
MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data,
unsigned size, MemTxAttrs attrs);

#endif

0 comments on commit 5fcc499

Please sign in to comment.