|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
| 2 | +/* Copyright(c) 2023 Intel Corporation. All rights reserved. */ |
| 3 | +#include <linux/acpi.h> |
| 4 | +#include <linux/xarray.h> |
| 5 | +#include <linux/fw_table.h> |
| 6 | +#include "cxlpci.h" |
| 7 | +#include "cxl.h" |
| 8 | + |
| 9 | +struct dsmas_entry { |
| 10 | + struct range dpa_range; |
| 11 | + u8 handle; |
| 12 | +}; |
| 13 | + |
| 14 | +static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg, |
| 15 | + const unsigned long end) |
| 16 | +{ |
| 17 | + struct acpi_cdat_header *hdr = &header->cdat; |
| 18 | + struct acpi_cdat_dsmas *dsmas; |
| 19 | + int size = sizeof(*hdr) + sizeof(*dsmas); |
| 20 | + struct xarray *dsmas_xa = arg; |
| 21 | + struct dsmas_entry *dent; |
| 22 | + u16 len; |
| 23 | + int rc; |
| 24 | + |
| 25 | + len = le16_to_cpu((__force __le16)hdr->length); |
| 26 | + if (len != size || (unsigned long)hdr + len > end) { |
| 27 | + pr_warn("Malformed DSMAS table length: (%u:%u)\n", size, len); |
| 28 | + return -EINVAL; |
| 29 | + } |
| 30 | + |
| 31 | + /* Skip common header */ |
| 32 | + dsmas = (struct acpi_cdat_dsmas *)(hdr + 1); |
| 33 | + |
| 34 | + dent = kzalloc(sizeof(*dent), GFP_KERNEL); |
| 35 | + if (!dent) |
| 36 | + return -ENOMEM; |
| 37 | + |
| 38 | + dent->handle = dsmas->dsmad_handle; |
| 39 | + dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address); |
| 40 | + dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) + |
| 41 | + le64_to_cpu((__force __le64)dsmas->dpa_length) - 1; |
| 42 | + |
| 43 | + rc = xa_insert(dsmas_xa, dent->handle, dent, GFP_KERNEL); |
| 44 | + if (rc) { |
| 45 | + kfree(dent); |
| 46 | + return rc; |
| 47 | + } |
| 48 | + |
| 49 | + return 0; |
| 50 | +} |
| 51 | + |
| 52 | +static int cxl_cdat_endpoint_process(struct cxl_port *port, |
| 53 | + struct xarray *dsmas_xa) |
| 54 | +{ |
| 55 | + return cdat_table_parse(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler, |
| 56 | + dsmas_xa, port->cdat.table); |
| 57 | +} |
| 58 | + |
| 59 | +static void discard_dsmas(struct xarray *xa) |
| 60 | +{ |
| 61 | + unsigned long index; |
| 62 | + void *ent; |
| 63 | + |
| 64 | + xa_for_each(xa, index, ent) { |
| 65 | + xa_erase(xa, index); |
| 66 | + kfree(ent); |
| 67 | + } |
| 68 | + xa_destroy(xa); |
| 69 | +} |
| 70 | +DEFINE_FREE(dsmas, struct xarray *, if (_T) discard_dsmas(_T)) |
| 71 | + |
| 72 | +void cxl_endpoint_parse_cdat(struct cxl_port *port) |
| 73 | +{ |
| 74 | + struct xarray __dsmas_xa; |
| 75 | + struct xarray *dsmas_xa __free(dsmas) = &__dsmas_xa; |
| 76 | + int rc; |
| 77 | + |
| 78 | + xa_init(&__dsmas_xa); |
| 79 | + if (!port->cdat.table) |
| 80 | + return; |
| 81 | + |
| 82 | + rc = cxl_cdat_endpoint_process(port, dsmas_xa); |
| 83 | + if (rc < 0) { |
| 84 | + dev_dbg(&port->dev, "Failed to parse CDAT: %d\n", rc); |
| 85 | + return; |
| 86 | + } |
| 87 | + |
| 88 | + /* Performance data processing */ |
| 89 | +} |
| 90 | +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_parse_cdat, CXL); |
| 91 | + |
| 92 | +MODULE_IMPORT_NS(CXL); |
0 commit comments