aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDan Williams2023-10-31 10:59:26 -0700
committerDan Williams2023-10-31 10:59:26 -0700
commit624eda92abd47f35386028e4a54d423037a75d12 (patch)
tree15fb6ca0683ce93bb4077009865b53a79b2e94ae /drivers
parent7f946e6d830fbdf411cd0641314edf11831efc88 (diff)
parenta103f46633fdcddc2aaca506420f177e8803a2bd (diff)
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.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Kconfig1
-rw-r--r--drivers/acpi/tables.c173
-rw-r--r--drivers/cxl/acpi.c3
-rw-r--r--drivers/cxl/core/pci.c52
-rw-r--r--drivers/cxl/core/port.c11
-rw-r--r--drivers/cxl/cxl.h3
-rw-r--r--drivers/cxl/port.c3
7 files changed, 61 insertions, 185 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index cee82b473dc5..c0a2d43f8451 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -12,6 +12,7 @@ menuconfig ACPI
select PNP
select NLS
select CRC32
+ select FIRMWARE_TABLE
default y if X86
help
Advanced Configuration and Power Interface (ACPI) support for
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 8ab0a82b4da4..c1516337f668 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -37,18 +37,6 @@ static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
static int acpi_apic_instance __initdata_or_acpilib;
-enum acpi_subtable_type {
- ACPI_SUBTABLE_COMMON,
- ACPI_SUBTABLE_HMAT,
- ACPI_SUBTABLE_PRMT,
- ACPI_SUBTABLE_CEDT,
-};
-
-struct acpi_subtable_entry {
- union acpi_subtable_headers *hdr;
- enum acpi_subtable_type type;
-};
-
/*
* Disable table checksum verification for the early stage due to the size
* limitation of the current x86 early mapping implementation.
@@ -237,167 +225,6 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
}
}
-static unsigned long __init_or_acpilib
-acpi_get_entry_type(struct acpi_subtable_entry *entry)
-{
- switch (entry->type) {
- case ACPI_SUBTABLE_COMMON:
- return entry->hdr->common.type;
- case ACPI_SUBTABLE_HMAT:
- return entry->hdr->hmat.type;
- case ACPI_SUBTABLE_PRMT:
- return 0;
- case ACPI_SUBTABLE_CEDT:
- return entry->hdr->cedt.type;
- }
- return 0;
-}
-
-static unsigned long __init_or_acpilib
-acpi_get_entry_length(struct acpi_subtable_entry *entry)
-{
- switch (entry->type) {
- case ACPI_SUBTABLE_COMMON:
- return entry->hdr->common.length;
- case ACPI_SUBTABLE_HMAT:
- return entry->hdr->hmat.length;
- case ACPI_SUBTABLE_PRMT:
- return entry->hdr->prmt.length;
- case ACPI_SUBTABLE_CEDT:
- return entry->hdr->cedt.length;
- }
- return 0;
-}
-
-static unsigned long __init_or_acpilib
-acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
-{
- switch (entry->type) {
- case ACPI_SUBTABLE_COMMON:
- return sizeof(entry->hdr->common);
- case ACPI_SUBTABLE_HMAT:
- return sizeof(entry->hdr->hmat);
- case ACPI_SUBTABLE_PRMT:
- return sizeof(entry->hdr->prmt);
- case ACPI_SUBTABLE_CEDT:
- return sizeof(entry->hdr->cedt);
- }
- return 0;
-}
-
-static enum acpi_subtable_type __init_or_acpilib
-acpi_get_subtable_type(char *id)
-{
- if (strncmp(id, ACPI_SIG_HMAT, 4) == 0)
- return ACPI_SUBTABLE_HMAT;
- if (strncmp(id, ACPI_SIG_PRMT, 4) == 0)
- return ACPI_SUBTABLE_PRMT;
- if (strncmp(id, ACPI_SIG_CEDT, 4) == 0)
- return ACPI_SUBTABLE_CEDT;
- return ACPI_SUBTABLE_COMMON;
-}
-
-static __init_or_acpilib bool has_handler(struct acpi_subtable_proc *proc)
-{
- return proc->handler || proc->handler_arg;
-}
-
-static __init_or_acpilib int call_handler(struct acpi_subtable_proc *proc,
- union acpi_subtable_headers *hdr,
- unsigned long end)
-{
- if (proc->handler)
- return proc->handler(hdr, end);
- if (proc->handler_arg)
- return proc->handler_arg(hdr, proc->arg, end);
- return -EINVAL;
-}
-
-/**
- * acpi_parse_entries_array - for each proc_num find a suitable subtable
- *
- * @id: table id (for debugging purposes)
- * @table_size: size of the root table
- * @table_header: where does the table start?
- * @proc: array of acpi_subtable_proc struct containing entry id
- * and associated handler with it
- * @proc_num: how big proc is?
- * @max_entries: how many entries can we process?
- *
- * For each proc_num find a subtable with proc->id and run proc->handler
- * on it. Assumption is that there's only single handler for particular
- * entry id.
- *
- * The table_size is not the size of the complete ACPI table (the length
- * field in the header struct), but only the size of the root table; i.e.,
- * the offset from the very first byte of the complete ACPI table, to the
- * first byte of the very first subtable.
- *
- * On success returns sum of all matching entries for all proc handlers.
- * Otherwise, -ENODEV or -EINVAL is returned.
- */
-static int __init_or_acpilib acpi_parse_entries_array(
- char *id, unsigned long table_size,
- struct acpi_table_header *table_header, struct acpi_subtable_proc *proc,
- int proc_num, unsigned int max_entries)
-{
- struct acpi_subtable_entry entry;
- unsigned long table_end, subtable_len, entry_len;
- int count = 0;
- int errs = 0;
- int i;
-
- table_end = (unsigned long)table_header + table_header->length;
-
- /* Parse all entries looking for a match. */
-
- entry.type = acpi_get_subtable_type(id);
- entry.hdr = (union acpi_subtable_headers *)
- ((unsigned long)table_header + table_size);
- subtable_len = acpi_get_subtable_header_length(&entry);
-
- while (((unsigned long)entry.hdr) + subtable_len < table_end) {
- if (max_entries && count >= max_entries)
- break;
-
- for (i = 0; i < proc_num; i++) {
- if (acpi_get_entry_type(&entry) != proc[i].id)
- continue;
- if (!has_handler(&proc[i]) ||
- (!errs &&
- call_handler(&proc[i], entry.hdr, table_end))) {
- errs++;
- continue;
- }
-
- proc[i].count++;
- break;
- }
- if (i != proc_num)
- count++;
-
- /*
- * If entry->length is 0, break from this loop to avoid
- * infinite loop.
- */
- entry_len = acpi_get_entry_length(&entry);
- if (entry_len == 0) {
- pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, proc->id);
- return -EINVAL;
- }
-
- entry.hdr = (union acpi_subtable_headers *)
- ((unsigned long)entry.hdr + entry_len);
- }
-
- if (max_entries && count > max_entries) {
- pr_warn("[%4.4s:0x%02x] found the maximum %i entries\n",
- id, proc->id, count);
- }
-
- return errs ? -EINVAL : count;
-}
-
int __init_or_acpilib acpi_table_parse_entries_array(
char *id, unsigned long table_size, struct acpi_subtable_proc *proc,
int proc_num, unsigned int max_entries)
diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index 40d055560e52..2034eb4ce83f 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -289,6 +289,9 @@ static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
}
}
}
+
+ cxlrd->qos_class = cfmws->qtg_id;
+
rc = cxl_decoder_add(cxld, target_map);
err_xormap:
if (rc)
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 3da195caa4ad..8c26e9fefa46 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -596,6 +596,16 @@ static int cxl_cdat_read_table(struct device *dev,
return 0;
}
+static unsigned char cdat_checksum(void *buf, size_t size)
+{
+ unsigned char sum, *data = buf;
+ size_t i;
+
+ for (sum = 0, i = 0; i < size; i++)
+ sum += data[i];
+ return sum;
+}
+
/**
* read_cdat_data - Read the CDAT data on this port
* @port: Port to read data from
@@ -604,18 +614,30 @@ static int cxl_cdat_read_table(struct device *dev,
*/
void read_cdat_data(struct cxl_port *port)
{
- struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
- struct device *host = cxlmd->dev.parent;
+ struct device *uport = port->uport_dev;
struct device *dev = &port->dev;
struct pci_doe_mb *cdat_doe;
+ struct pci_dev *pdev = NULL;
+ struct cxl_memdev *cxlmd;
size_t cdat_length;
void *cdat_table;
int rc;
- if (!dev_is_pci(host))
+ if (is_cxl_memdev(uport)) {
+ struct device *host;
+
+ cxlmd = to_cxl_memdev(uport);
+ host = cxlmd->dev.parent;
+ if (dev_is_pci(host))
+ pdev = to_pci_dev(host);
+ } else if (dev_is_pci(uport)) {
+ pdev = to_pci_dev(uport);
+ }
+
+ if (!pdev)
return;
- cdat_doe = pci_find_doe_mailbox(to_pci_dev(host),
- PCI_DVSEC_VENDOR_ID_CXL,
+
+ cdat_doe = pci_find_doe_mailbox(pdev, PCI_DVSEC_VENDOR_ID_CXL,
CXL_DOE_PROTOCOL_TABLE_ACCESS);
if (!cdat_doe) {
dev_dbg(dev, "No CDAT mailbox\n");
@@ -635,15 +657,21 @@ void read_cdat_data(struct cxl_port *port)
return;
rc = cxl_cdat_read_table(dev, cdat_doe, cdat_table, &cdat_length);
- if (rc) {
- /* Don't leave table data allocated on error */
- devm_kfree(dev, cdat_table);
- dev_err(dev, "CDAT data read error\n");
- return;
- }
+ if (rc)
+ goto err;
+
+ cdat_table = cdat_table + sizeof(__le32);
+ if (cdat_checksum(cdat_table, cdat_length))
+ goto err;
- port->cdat.table = cdat_table + sizeof(__le32);
+ port->cdat.table = cdat_table;
port->cdat.length = cdat_length;
+ return;
+
+err:
+ /* Don't leave table data allocated on error */
+ devm_kfree(dev, cdat_table);
+ dev_err(dev, "Failed to read/validate CDAT.\n");
}
EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL);
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index e2f888224362..ecdaf88311a1 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -284,6 +284,15 @@ static ssize_t interleave_ways_show(struct device *dev,
static DEVICE_ATTR_RO(interleave_ways);
+static ssize_t qos_class_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+
+ return sysfs_emit(buf, "%d\n", cxlrd->qos_class);
+}
+static DEVICE_ATTR_RO(qos_class);
+
static struct attribute *cxl_decoder_base_attrs[] = {
&dev_attr_start.attr,
&dev_attr_size.attr,
@@ -303,6 +312,7 @@ static struct attribute *cxl_decoder_root_attrs[] = {
&dev_attr_cap_type2.attr,
&dev_attr_cap_type3.attr,
&dev_attr_target_list.attr,
+ &dev_attr_qos_class.attr,
SET_CXL_REGION_ATTR(create_pmem_region)
SET_CXL_REGION_ATTR(create_ram_region)
SET_CXL_REGION_ATTR(delete_region)
@@ -1735,6 +1745,7 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
}
atomic_set(&cxlrd->region_id, rc);
+ cxlrd->qos_class = CXL_QOS_CLASS_INVALID;
return cxlrd;
}
EXPORT_SYMBOL_NS_GPL(cxl_root_decoder_alloc, CXL);
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 378fc96ff7ff..02d307fa793a 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -328,6 +328,7 @@ enum cxl_decoder_type {
*/
#define CXL_DECODER_MAX_INTERLEAVE 16
+#define CXL_QOS_CLASS_INVALID -1
/**
* 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,
* @calc_hb: which host bridge covers the n'th position by granularity
* @platform_data: platform specific configuration data
* @range_lock: sync region autodiscovery by address range
+ * @qos_class: QoS performance class cookie
* @cxlsd: base cxl switch decoder
*/
struct cxl_root_decoder {
@@ -447,6 +449,7 @@ struct cxl_root_decoder {
cxl_calc_hb_fn calc_hb;
void *platform_data;
struct mutex range_lock;
+ int qos_class;
struct cxl_switch_decoder cxlsd;
};
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 6240e05b9542..47bc8e0b8590 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -62,6 +62,9 @@ static int cxl_switch_port_probe(struct cxl_port *port)
struct cxl_hdm *cxlhdm;
int rc;
+ /* Cache the data early to ensure is_visible() works */
+ read_cdat_data(port);
+
rc = devm_cxl_port_enumerate_dports(port);
if (rc < 0)
return rc;