|
3 | 3 | #include <linux/acpi.h> |
4 | 4 | #include <linux/xarray.h> |
5 | 5 | #include <linux/fw_table.h> |
| 6 | +#include <linux/node.h> |
| 7 | +#include <linux/overflow.h> |
6 | 8 | #include "cxlpci.h" |
7 | 9 | #include "cxl.h" |
8 | 10 |
|
9 | 11 | struct dsmas_entry { |
10 | 12 | struct range dpa_range; |
11 | 13 | u8 handle; |
| 14 | + struct access_coordinate coord; |
12 | 15 | }; |
13 | 16 |
|
14 | 17 | static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg, |
@@ -49,11 +52,106 @@ static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg, |
49 | 52 | return 0; |
50 | 53 | } |
51 | 54 |
|
| 55 | +static void cxl_access_coordinate_set(struct access_coordinate *coord, |
| 56 | + int access, unsigned int val) |
| 57 | +{ |
| 58 | + switch (access) { |
| 59 | + case ACPI_HMAT_ACCESS_LATENCY: |
| 60 | + coord->read_latency = val; |
| 61 | + coord->write_latency = val; |
| 62 | + break; |
| 63 | + case ACPI_HMAT_READ_LATENCY: |
| 64 | + coord->read_latency = val; |
| 65 | + break; |
| 66 | + case ACPI_HMAT_WRITE_LATENCY: |
| 67 | + coord->write_latency = val; |
| 68 | + break; |
| 69 | + case ACPI_HMAT_ACCESS_BANDWIDTH: |
| 70 | + coord->read_bandwidth = val; |
| 71 | + coord->write_bandwidth = val; |
| 72 | + break; |
| 73 | + case ACPI_HMAT_READ_BANDWIDTH: |
| 74 | + coord->read_bandwidth = val; |
| 75 | + break; |
| 76 | + case ACPI_HMAT_WRITE_BANDWIDTH: |
| 77 | + coord->write_bandwidth = val; |
| 78 | + break; |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +static int cdat_dslbis_handler(union acpi_subtable_headers *header, void *arg, |
| 83 | + const unsigned long end) |
| 84 | +{ |
| 85 | + struct acpi_cdat_header *hdr = &header->cdat; |
| 86 | + struct acpi_cdat_dslbis *dslbis; |
| 87 | + int size = sizeof(*hdr) + sizeof(*dslbis); |
| 88 | + struct xarray *dsmas_xa = arg; |
| 89 | + struct dsmas_entry *dent; |
| 90 | + __le64 le_base; |
| 91 | + __le16 le_val; |
| 92 | + u64 val; |
| 93 | + u16 len; |
| 94 | + int rc; |
| 95 | + |
| 96 | + len = le16_to_cpu((__force __le16)hdr->length); |
| 97 | + if (len != size || (unsigned long)hdr + len > end) { |
| 98 | + pr_warn("Malformed DSLBIS table length: (%u:%u)\n", size, len); |
| 99 | + return -EINVAL; |
| 100 | + } |
| 101 | + |
| 102 | + /* Skip common header */ |
| 103 | + dslbis = (struct acpi_cdat_dslbis *)(hdr + 1); |
| 104 | + |
| 105 | + /* Skip unrecognized data type */ |
| 106 | + if (dslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH) |
| 107 | + return 0; |
| 108 | + |
| 109 | + /* Not a memory type, skip */ |
| 110 | + if ((dslbis->flags & ACPI_HMAT_MEMORY_HIERARCHY) != ACPI_HMAT_MEMORY) |
| 111 | + return 0; |
| 112 | + |
| 113 | + dent = xa_load(dsmas_xa, dslbis->handle); |
| 114 | + if (!dent) { |
| 115 | + pr_warn("No matching DSMAS entry for DSLBIS entry.\n"); |
| 116 | + return 0; |
| 117 | + } |
| 118 | + |
| 119 | + le_base = (__force __le64)dslbis->entry_base_unit; |
| 120 | + le_val = (__force __le16)dslbis->entry[0]; |
| 121 | + rc = check_mul_overflow(le64_to_cpu(le_base), |
| 122 | + le16_to_cpu(le_val), &val); |
| 123 | + if (rc) |
| 124 | + pr_warn("DSLBIS value overflowed.\n"); |
| 125 | + |
| 126 | + cxl_access_coordinate_set(&dent->coord, dslbis->data_type, val); |
| 127 | + |
| 128 | + return 0; |
| 129 | +} |
| 130 | + |
| 131 | +static int cdat_table_parse_output(int rc) |
| 132 | +{ |
| 133 | + if (rc < 0) |
| 134 | + return rc; |
| 135 | + if (rc == 0) |
| 136 | + return -ENOENT; |
| 137 | + |
| 138 | + return 0; |
| 139 | +} |
| 140 | + |
52 | 141 | static int cxl_cdat_endpoint_process(struct cxl_port *port, |
53 | 142 | struct xarray *dsmas_xa) |
54 | 143 | { |
55 | | - return cdat_table_parse(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler, |
56 | | - dsmas_xa, port->cdat.table); |
| 144 | + int rc; |
| 145 | + |
| 146 | + rc = cdat_table_parse(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler, |
| 147 | + dsmas_xa, port->cdat.table); |
| 148 | + rc = cdat_table_parse_output(rc); |
| 149 | + if (rc) |
| 150 | + return rc; |
| 151 | + |
| 152 | + rc = cdat_table_parse(ACPI_CDAT_TYPE_DSLBIS, cdat_dslbis_handler, |
| 153 | + dsmas_xa, port->cdat.table); |
| 154 | + return cdat_table_parse_output(rc); |
57 | 155 | } |
58 | 156 |
|
59 | 157 | static void discard_dsmas(struct xarray *xa) |
|
0 commit comments