Skip to content

Commit 80aa780

Browse files
davejiangdjbw
authored andcommitted
cxl: Add callback to parse the SSLBIS subtable from CDAT
Provide a callback to parse the Switched Scoped Latency and Bandwidth Information Structure (SSLBIS) in the CDAT structures. The SSLBIS contains the bandwidth and latency information that's tied to the CXL switch that the data table has been read from. The extracted values are stored to the cxl_dport correlated by the port_id depending on the SSLBIS entry. Coherent Device Attribute Table 1.03 2.1 Switched Scoped Latency and Bandwidth Information Structure (DSLBIS) Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Dave Jiang <dave.jiang@intel.com> Link: https://lore.kernel.org/r/170319620635.2212653.5194389158785365150.stgit@djiang5-mobl3 Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent 63cef81 commit 80aa780

3 files changed

Lines changed: 104 additions & 0 deletions

File tree

drivers/cxl/core/cdat.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,102 @@ void cxl_endpoint_parse_cdat(struct cxl_port *port)
187187
}
188188
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_parse_cdat, CXL);
189189

190+
static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg,
191+
const unsigned long end)
192+
{
193+
struct acpi_cdat_sslbis *sslbis;
194+
int size = sizeof(header->cdat) + sizeof(*sslbis);
195+
struct cxl_port *port = arg;
196+
struct device *dev = &port->dev;
197+
struct acpi_cdat_sslbe *entry;
198+
int remain, entries, i;
199+
u16 len;
200+
201+
len = le16_to_cpu((__force __le16)header->cdat.length);
202+
remain = len - size;
203+
if (!remain || remain % sizeof(*entry) ||
204+
(unsigned long)header + len > end) {
205+
dev_warn(dev, "Malformed SSLBIS table length: (%u)\n", len);
206+
return -EINVAL;
207+
}
208+
209+
/* Skip common header */
210+
sslbis = (struct acpi_cdat_sslbis *)((unsigned long)header +
211+
sizeof(header->cdat));
212+
213+
/* Unrecognized data type, we can skip */
214+
if (sslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH)
215+
return 0;
216+
217+
entries = remain / sizeof(*entry);
218+
entry = (struct acpi_cdat_sslbe *)((unsigned long)header + sizeof(*sslbis));
219+
220+
for (i = 0; i < entries; i++) {
221+
u16 x = le16_to_cpu((__force __le16)entry->portx_id);
222+
u16 y = le16_to_cpu((__force __le16)entry->porty_id);
223+
__le64 le_base;
224+
__le16 le_val;
225+
struct cxl_dport *dport;
226+
unsigned long index;
227+
u16 dsp_id;
228+
u64 val;
229+
230+
switch (x) {
231+
case ACPI_CDAT_SSLBIS_US_PORT:
232+
dsp_id = y;
233+
break;
234+
case ACPI_CDAT_SSLBIS_ANY_PORT:
235+
switch (y) {
236+
case ACPI_CDAT_SSLBIS_US_PORT:
237+
dsp_id = x;
238+
break;
239+
case ACPI_CDAT_SSLBIS_ANY_PORT:
240+
dsp_id = ACPI_CDAT_SSLBIS_ANY_PORT;
241+
break;
242+
default:
243+
dsp_id = y;
244+
break;
245+
}
246+
break;
247+
default:
248+
dsp_id = x;
249+
break;
250+
}
251+
252+
le_base = (__force __le64)sslbis->entry_base_unit;
253+
le_val = (__force __le16)entry->latency_or_bandwidth;
254+
255+
if (check_mul_overflow(le64_to_cpu(le_base),
256+
le16_to_cpu(le_val), &val))
257+
dev_warn(dev, "SSLBIS value overflowed!\n");
258+
259+
xa_for_each(&port->dports, index, dport) {
260+
if (dsp_id == ACPI_CDAT_SSLBIS_ANY_PORT ||
261+
dsp_id == dport->port_id)
262+
cxl_access_coordinate_set(&dport->sw_coord,
263+
sslbis->data_type,
264+
val);
265+
}
266+
267+
entry++;
268+
}
269+
270+
return 0;
271+
}
272+
273+
void cxl_switch_parse_cdat(struct cxl_port *port)
274+
{
275+
int rc;
276+
277+
if (!port->cdat.table)
278+
return;
279+
280+
rc = cdat_table_parse(ACPI_CDAT_TYPE_SSLBIS, cdat_sslbis_handler,
281+
port, port->cdat.table);
282+
rc = cdat_table_parse_output(rc);
283+
if (rc)
284+
dev_dbg(&port->dev, "Failed to parse SSLBIS: %d\n", rc);
285+
}
286+
EXPORT_SYMBOL_NS_GPL(cxl_switch_parse_cdat, CXL);
287+
190288
MODULE_IMPORT_NS(CXL);

drivers/cxl/cxl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/bitfield.h>
99
#include <linux/bitops.h>
1010
#include <linux/log2.h>
11+
#include <linux/node.h>
1112
#include <linux/io.h>
1213

1314
/**
@@ -634,6 +635,7 @@ struct cxl_rcrb_info {
634635
* @rch: Indicate whether this dport was enumerated in RCH or VH mode
635636
* @port: reference to cxl_port that contains this downstream port
636637
* @regs: Dport parsed register blocks
638+
* @sw_coord: access coordinates (performance) for switch from CDAT
637639
*/
638640
struct cxl_dport {
639641
struct device *dport_dev;
@@ -643,6 +645,7 @@ struct cxl_dport {
643645
bool rch;
644646
struct cxl_port *port;
645647
struct cxl_regs regs;
648+
struct access_coordinate sw_coord;
646649
};
647650

648651
/**
@@ -840,6 +843,7 @@ static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
840843
#endif
841844

842845
void cxl_endpoint_parse_cdat(struct cxl_port *port);
846+
void cxl_switch_parse_cdat(struct cxl_port *port);
843847

844848
/*
845849
* Unit test builds overrides this to __weak, find the 'strong' version

drivers/cxl/port.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ static int cxl_switch_port_probe(struct cxl_port *port)
6969
if (rc < 0)
7070
return rc;
7171

72+
cxl_switch_parse_cdat(port);
73+
7274
cxlhdm = devm_cxl_setup_hdm(port, NULL);
7375
if (!IS_ERR(cxlhdm))
7476
return devm_cxl_enumerate_decoders(cxlhdm, NULL);

0 commit comments

Comments
 (0)