Skip to content

Commit 9f39bd0

Browse files
committed
Merge branch 'for-6.7/cxl-qtg' into cxl/next
Merge some prep-work for CXL QOS class support. This cycle saw large collisions with mm on this topic, so the bulk of this topic needs to wait.
2 parents e100c36 + a103f46 commit 9f39bd0

File tree

15 files changed

+329
-216
lines changed

15 files changed

+329
-216
lines changed

Documentation/ABI/testing/sysfs-bus-cxl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,21 @@ Description:
369369
provided it is currently idle / not bound to a driver.
370370

371371

372+
What: /sys/bus/cxl/devices/decoderX.Y/qos_class
373+
Date: May, 2023
374+
KernelVersion: v6.5
375+
Contact: linux-cxl@vger.kernel.org
376+
Description:
377+
(RO) For CXL host platforms that support "QoS Telemmetry" this
378+
root-decoder-only attribute conveys a platform specific cookie
379+
that identifies a QoS performance class for the CXL Window.
380+
This class-id can be compared against a similar "qos_class"
381+
published for each memory-type that an endpoint supports. While
382+
it is not required that endpoints map their local memory-class
383+
to a matching platform class, mismatches are not recommended and
384+
there are platform specific side-effects that may result.
385+
386+
372387
What: /sys/bus/cxl/devices/regionZ/uuid
373388
Date: May, 2022
374389
KernelVersion: v6.0

MAINTAINERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ F: drivers/pnp/pnpacpi/
294294
F: include/acpi/
295295
F: include/linux/acpi.h
296296
F: include/linux/fwnode.h
297+
F: include/linux/fw_table.h
298+
F: lib/fw_table.c
297299
F: tools/power/acpi/
298300

299301
ACPI APEI

drivers/acpi/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ menuconfig ACPI
1212
select PNP
1313
select NLS
1414
select CRC32
15+
select FIRMWARE_TABLE
1516
default y if X86
1617
help
1718
Advanced Configuration and Power Interface (ACPI) support for

drivers/acpi/tables.c

Lines changed: 0 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,6 @@ static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
3737

3838
static int acpi_apic_instance __initdata_or_acpilib;
3939

40-
enum acpi_subtable_type {
41-
ACPI_SUBTABLE_COMMON,
42-
ACPI_SUBTABLE_HMAT,
43-
ACPI_SUBTABLE_PRMT,
44-
ACPI_SUBTABLE_CEDT,
45-
};
46-
47-
struct acpi_subtable_entry {
48-
union acpi_subtable_headers *hdr;
49-
enum acpi_subtable_type type;
50-
};
51-
5240
/*
5341
* Disable table checksum verification for the early stage due to the size
5442
* limitation of the current x86 early mapping implementation.
@@ -237,167 +225,6 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
237225
}
238226
}
239227

240-
static unsigned long __init_or_acpilib
241-
acpi_get_entry_type(struct acpi_subtable_entry *entry)
242-
{
243-
switch (entry->type) {
244-
case ACPI_SUBTABLE_COMMON:
245-
return entry->hdr->common.type;
246-
case ACPI_SUBTABLE_HMAT:
247-
return entry->hdr->hmat.type;
248-
case ACPI_SUBTABLE_PRMT:
249-
return 0;
250-
case ACPI_SUBTABLE_CEDT:
251-
return entry->hdr->cedt.type;
252-
}
253-
return 0;
254-
}
255-
256-
static unsigned long __init_or_acpilib
257-
acpi_get_entry_length(struct acpi_subtable_entry *entry)
258-
{
259-
switch (entry->type) {
260-
case ACPI_SUBTABLE_COMMON:
261-
return entry->hdr->common.length;
262-
case ACPI_SUBTABLE_HMAT:
263-
return entry->hdr->hmat.length;
264-
case ACPI_SUBTABLE_PRMT:
265-
return entry->hdr->prmt.length;
266-
case ACPI_SUBTABLE_CEDT:
267-
return entry->hdr->cedt.length;
268-
}
269-
return 0;
270-
}
271-
272-
static unsigned long __init_or_acpilib
273-
acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
274-
{
275-
switch (entry->type) {
276-
case ACPI_SUBTABLE_COMMON:
277-
return sizeof(entry->hdr->common);
278-
case ACPI_SUBTABLE_HMAT:
279-
return sizeof(entry->hdr->hmat);
280-
case ACPI_SUBTABLE_PRMT:
281-
return sizeof(entry->hdr->prmt);
282-
case ACPI_SUBTABLE_CEDT:
283-
return sizeof(entry->hdr->cedt);
284-
}
285-
return 0;
286-
}
287-
288-
static enum acpi_subtable_type __init_or_acpilib
289-
acpi_get_subtable_type(char *id)
290-
{
291-
if (strncmp(id, ACPI_SIG_HMAT, 4) == 0)
292-
return ACPI_SUBTABLE_HMAT;
293-
if (strncmp(id, ACPI_SIG_PRMT, 4) == 0)
294-
return ACPI_SUBTABLE_PRMT;
295-
if (strncmp(id, ACPI_SIG_CEDT, 4) == 0)
296-
return ACPI_SUBTABLE_CEDT;
297-
return ACPI_SUBTABLE_COMMON;
298-
}
299-
300-
static __init_or_acpilib bool has_handler(struct acpi_subtable_proc *proc)
301-
{
302-
return proc->handler || proc->handler_arg;
303-
}
304-
305-
static __init_or_acpilib int call_handler(struct acpi_subtable_proc *proc,
306-
union acpi_subtable_headers *hdr,
307-
unsigned long end)
308-
{
309-
if (proc->handler)
310-
return proc->handler(hdr, end);
311-
if (proc->handler_arg)
312-
return proc->handler_arg(hdr, proc->arg, end);
313-
return -EINVAL;
314-
}
315-
316-
/**
317-
* acpi_parse_entries_array - for each proc_num find a suitable subtable
318-
*
319-
* @id: table id (for debugging purposes)
320-
* @table_size: size of the root table
321-
* @table_header: where does the table start?
322-
* @proc: array of acpi_subtable_proc struct containing entry id
323-
* and associated handler with it
324-
* @proc_num: how big proc is?
325-
* @max_entries: how many entries can we process?
326-
*
327-
* For each proc_num find a subtable with proc->id and run proc->handler
328-
* on it. Assumption is that there's only single handler for particular
329-
* entry id.
330-
*
331-
* The table_size is not the size of the complete ACPI table (the length
332-
* field in the header struct), but only the size of the root table; i.e.,
333-
* the offset from the very first byte of the complete ACPI table, to the
334-
* first byte of the very first subtable.
335-
*
336-
* On success returns sum of all matching entries for all proc handlers.
337-
* Otherwise, -ENODEV or -EINVAL is returned.
338-
*/
339-
static int __init_or_acpilib acpi_parse_entries_array(
340-
char *id, unsigned long table_size,
341-
struct acpi_table_header *table_header, struct acpi_subtable_proc *proc,
342-
int proc_num, unsigned int max_entries)
343-
{
344-
struct acpi_subtable_entry entry;
345-
unsigned long table_end, subtable_len, entry_len;
346-
int count = 0;
347-
int errs = 0;
348-
int i;
349-
350-
table_end = (unsigned long)table_header + table_header->length;
351-
352-
/* Parse all entries looking for a match. */
353-
354-
entry.type = acpi_get_subtable_type(id);
355-
entry.hdr = (union acpi_subtable_headers *)
356-
((unsigned long)table_header + table_size);
357-
subtable_len = acpi_get_subtable_header_length(&entry);
358-
359-
while (((unsigned long)entry.hdr) + subtable_len < table_end) {
360-
if (max_entries && count >= max_entries)
361-
break;
362-
363-
for (i = 0; i < proc_num; i++) {
364-
if (acpi_get_entry_type(&entry) != proc[i].id)
365-
continue;
366-
if (!has_handler(&proc[i]) ||
367-
(!errs &&
368-
call_handler(&proc[i], entry.hdr, table_end))) {
369-
errs++;
370-
continue;
371-
}
372-
373-
proc[i].count++;
374-
break;
375-
}
376-
if (i != proc_num)
377-
count++;
378-
379-
/*
380-
* If entry->length is 0, break from this loop to avoid
381-
* infinite loop.
382-
*/
383-
entry_len = acpi_get_entry_length(&entry);
384-
if (entry_len == 0) {
385-
pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, proc->id);
386-
return -EINVAL;
387-
}
388-
389-
entry.hdr = (union acpi_subtable_headers *)
390-
((unsigned long)entry.hdr + entry_len);
391-
}
392-
393-
if (max_entries && count > max_entries) {
394-
pr_warn("[%4.4s:0x%02x] found the maximum %i entries\n",
395-
id, proc->id, count);
396-
}
397-
398-
return errs ? -EINVAL : count;
399-
}
400-
401228
int __init_or_acpilib acpi_table_parse_entries_array(
402229
char *id, unsigned long table_size, struct acpi_subtable_proc *proc,
403230
int proc_num, unsigned int max_entries)

drivers/cxl/acpi.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,9 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
289289
}
290290
}
291291
}
292+
293+
cxlrd->qos_class = cfmws->qtg_id;
294+
292295
rc = cxl_decoder_add(cxld, target_map);
293296
err_xormap:
294297
if (rc)

drivers/cxl/core/pci.c

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,16 @@ static int cxl_cdat_read_table(struct device *dev,
596596
return 0;
597597
}
598598

599+
static unsigned char cdat_checksum(void *buf, size_t size)
600+
{
601+
unsigned char sum, *data = buf;
602+
size_t i;
603+
604+
for (sum = 0, i = 0; i < size; i++)
605+
sum += data[i];
606+
return sum;
607+
}
608+
599609
/**
600610
* read_cdat_data - Read the CDAT data on this port
601611
* @port: Port to read data from
@@ -604,18 +614,30 @@ static int cxl_cdat_read_table(struct device *dev,
604614
*/
605615
void read_cdat_data(struct cxl_port *port)
606616
{
607-
struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
608-
struct device *host = cxlmd->dev.parent;
617+
struct device *uport = port->uport_dev;
609618
struct device *dev = &port->dev;
610619
struct pci_doe_mb *cdat_doe;
620+
struct pci_dev *pdev = NULL;
621+
struct cxl_memdev *cxlmd;
611622
size_t cdat_length;
612623
void *cdat_table;
613624
int rc;
614625

615-
if (!dev_is_pci(host))
626+
if (is_cxl_memdev(uport)) {
627+
struct device *host;
628+
629+
cxlmd = to_cxl_memdev(uport);
630+
host = cxlmd->dev.parent;
631+
if (dev_is_pci(host))
632+
pdev = to_pci_dev(host);
633+
} else if (dev_is_pci(uport)) {
634+
pdev = to_pci_dev(uport);
635+
}
636+
637+
if (!pdev)
616638
return;
617-
cdat_doe = pci_find_doe_mailbox(to_pci_dev(host),
618-
PCI_DVSEC_VENDOR_ID_CXL,
639+
640+
cdat_doe = pci_find_doe_mailbox(pdev, PCI_DVSEC_VENDOR_ID_CXL,
619641
CXL_DOE_PROTOCOL_TABLE_ACCESS);
620642
if (!cdat_doe) {
621643
dev_dbg(dev, "No CDAT mailbox\n");
@@ -635,15 +657,21 @@ void read_cdat_data(struct cxl_port *port)
635657
return;
636658

637659
rc = cxl_cdat_read_table(dev, cdat_doe, cdat_table, &cdat_length);
638-
if (rc) {
639-
/* Don't leave table data allocated on error */
640-
devm_kfree(dev, cdat_table);
641-
dev_err(dev, "CDAT data read error\n");
642-
return;
643-
}
660+
if (rc)
661+
goto err;
662+
663+
cdat_table = cdat_table + sizeof(__le32);
664+
if (cdat_checksum(cdat_table, cdat_length))
665+
goto err;
644666

645-
port->cdat.table = cdat_table + sizeof(__le32);
667+
port->cdat.table = cdat_table;
646668
port->cdat.length = cdat_length;
669+
return;
670+
671+
err:
672+
/* Don't leave table data allocated on error */
673+
devm_kfree(dev, cdat_table);
674+
dev_err(dev, "Failed to read/validate CDAT.\n");
647675
}
648676
EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL);
649677

drivers/cxl/core/port.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,15 @@ static ssize_t interleave_ways_show(struct device *dev,
284284

285285
static DEVICE_ATTR_RO(interleave_ways);
286286

287+
static ssize_t qos_class_show(struct device *dev,
288+
struct device_attribute *attr, char *buf)
289+
{
290+
struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
291+
292+
return sysfs_emit(buf, "%d\n", cxlrd->qos_class);
293+
}
294+
static DEVICE_ATTR_RO(qos_class);
295+
287296
static struct attribute *cxl_decoder_base_attrs[] = {
288297
&dev_attr_start.attr,
289298
&dev_attr_size.attr,
@@ -303,6 +312,7 @@ static struct attribute *cxl_decoder_root_attrs[] = {
303312
&dev_attr_cap_type2.attr,
304313
&dev_attr_cap_type3.attr,
305314
&dev_attr_target_list.attr,
315+
&dev_attr_qos_class.attr,
306316
SET_CXL_REGION_ATTR(create_pmem_region)
307317
SET_CXL_REGION_ATTR(create_ram_region)
308318
SET_CXL_REGION_ATTR(delete_region)
@@ -1735,6 +1745,7 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
17351745
}
17361746

17371747
atomic_set(&cxlrd->region_id, rc);
1748+
cxlrd->qos_class = CXL_QOS_CLASS_INVALID;
17381749
return cxlrd;
17391750
}
17401751
EXPORT_SYMBOL_NS_GPL(cxl_root_decoder_alloc, CXL);

drivers/cxl/cxl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ enum cxl_decoder_type {
328328
*/
329329
#define CXL_DECODER_MAX_INTERLEAVE 16
330330

331+
#define CXL_QOS_CLASS_INVALID -1
331332

332333
/**
333334
* struct cxl_decoder - Common CXL HDM Decoder Attributes
@@ -439,6 +440,7 @@ typedef struct cxl_dport *(*cxl_calc_hb_fn)(struct cxl_root_decoder *cxlrd,
439440
* @calc_hb: which host bridge covers the n'th position by granularity
440441
* @platform_data: platform specific configuration data
441442
* @range_lock: sync region autodiscovery by address range
443+
* @qos_class: QoS performance class cookie
442444
* @cxlsd: base cxl switch decoder
443445
*/
444446
struct cxl_root_decoder {
@@ -447,6 +449,7 @@ struct cxl_root_decoder {
447449
cxl_calc_hb_fn calc_hb;
448450
void *platform_data;
449451
struct mutex range_lock;
452+
int qos_class;
450453
struct cxl_switch_decoder cxlsd;
451454
};
452455

drivers/cxl/port.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ static int cxl_switch_port_probe(struct cxl_port *port)
6262
struct cxl_hdm *cxlhdm;
6363
int rc;
6464

65+
/* Cache the data early to ensure is_visible() works */
66+
read_cdat_data(port);
67+
6568
rc = devm_cxl_port_enumerate_dports(port);
6669
if (rc < 0)
6770
return rc;

include/acpi/actbl1.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,9 @@ struct acpi_cdat_sslbe {
465465
u16 reserved;
466466
};
467467

468+
#define ACPI_CDAT_SSLBIS_US_PORT 0x0100
469+
#define ACPI_CDAT_SSLBIS_ANY_PORT 0xffff
470+
468471
/*******************************************************************************
469472
*
470473
* CEDT - CXL Early Discovery Table

0 commit comments

Comments
 (0)