Linux CXL
 help / color / mirror / Atom feed
* [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem
@ 2023-05-08 20:46 Dave Jiang
  2023-05-08 20:46 ` [PATCH v5 01/14] cxl: Add callback to parse the DSMAS subtables from CDAT Dave Jiang
                   ` (14 more replies)
  0 siblings, 15 replies; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:46 UTC (permalink / raw)
  To: linux-cxl
  Cc: Jonathan Cameron, Dan Williams, dan.j.williams, ira.weiny,
	vishal.l.verma, alison.schofield, Jonathan.Cameron

v5:
- Please see specific patches for log entries addressing comments from v4.
- Split out ACPI and generic node code to send separately to respective maintainers
- Reworked to use ACPI tables code for CDAT parsing (Dan)
- Cache relevant perf data under dports (Dan)
- Add cxl root callback for QTG ID _DSM (Dan)
- Rename 'node_hmem_attr' to 'access_coordinate' (Dan)
- Change qtg_id sysfs attrib to qos_class (Dan)

v4:
- Reworked PCIe link path latency calculation
- 0-day fixes
- Removed unused qos_list from cxl_memdev and its stray usages

v3:
- Please see specific patches for log entries addressing comments from v2.
- Refactor cxl_port_probe() additions. (Alison)
- Convert to use 'struct node_hmem_attrs'
- Refactor to use common code for genport target allocation.
- Add third array entry for target hmem_attrs to store genport locality data.
- Go back to per partition QTG ID. (Dan)

v2:
- Please see specific patches for log entries addressing comments from v1.
- Removed ACPICA code usages.
- Removed PCI subsystem helpers for latency and bandwidth.
- Add CXL switch CDAT parsing support (SSLBIS)
- Add generic port SRAT+HMAT support (ACPI)
- Export a single QTG ID via sysfs per memory device (Dan)
- Provide rest of DSMAS range info in debugfs (Dan)

For v6, some of the patches has been split out to ease the review and upstream process.
The following have been split out from this series and are dependencies:
1. QTG series prep patches:
https://lore.kernel.org/linux-cxl/168330433154.1986478.2238692205077357255.stgit@djiang5-mobl3/
2. ACPI CDAT handling
https://lore.kernel.org/linux-cxl/168330787964.2042604.17648905811002211147.stgit@djiang5-mobl3/
3. 'node_hmem_attrs' to 'access_coordinates'
https://lore.kernel.org/linux-cxl/168332248685.2190392.1983307884583782116.stgit@djiang5-mobl3/
4. ACPI hmat target update
https://lore.kernel.org/linux-cxl/168333141100.2290593.16294670316057617744.stgit@djiang5-mobl3/

This series adds the retrieval of QoS Throttling Group (QTG) IDs for the CXL Fixed
Memory Window Structure (CFMWS) and the CXL memory device. It provides the QTG IDs
to user space to provide some guidance with putting the proper DPA range under the
appropriate CFMWS window for a hot-plugged CXL memory device.

The CFMWS structure contains a QTG ID that is associated with the memory window that the
structure exports. On Linux, the CFMWS is represented as a CXL root decoder. The QTG
ID will be attached to the CXL root decoder and exported as a sysfs attribute (qtg_id).

The QTG ID for a device is retrieved via sending a _DSM method to the ACPI0017 device.
The _DSM expects an input package of 4 DWORDS that contains the read latency, write
latency, read bandwidth, and write banwidth. These are the caluclated numbers for the
path between the CXL device and the CPU. The QTG ID is also exported as a sysfs
attribute under the mem device memory partition type:
/sys/bus/cxl/devices/memX/ram/qos_class
/sys/bus/cxl/devices/memX/pmem/qos_class
Only the first QTG ID is exported. The rest of the information can be found under
/sys/kernel/debug/cxl/memX/qtgmap where all the DPA ranges with the correlated QTG ID
are displayed. Each DSMAS from the device CDAT will provide a DPA range.

The latency numbers are the aggregated latencies for the path between the CXL device and
the CPU. If a CXL device is directly attached to the CXL HB, the latency
would be the aggregated latencies from the device Coherent Device Attribute Table (CDAT),
the caluclated PCIe link latency between the device and the HB, and the generic port data
from ACPI SRAT+HMAT. The bandwidth in this configuration would be the minimum between the
CDAT bandwidth number, link bandwidth between the device and the HB, and the bandwidth data
from the generic port data via ACPI SRAT+HMAT.

If a configuration has a switch in between then the latency would be the aggregated
latencies from the device CDAT, the link latency between device and switch, the
latency from the switch CDAT, the link latency between switch and the HB, and the
generic port latency between the CPU and the CXL HB. The bandwidth calculation would be the
min of device CDAT bandwidth, link bandwith between device and switch, switch CDAT
bandwidth, the link bandwidth between switch and HB, and the generic port bandwidth

There can be 0 or more switches between the CXL device and the CXL HB. There are detailed
examples on calculating bandwidth and latency in the CXL Memory Device Software Guide [4].

The CDAT provides Device Scoped Memory Affinity Structures (DSMAS) that contains the
Device Physical Address (DPA) range and the related Device Scoped Latency and Bandwidth
Informat Stuctures (DSLBIS). Each DSLBIS provides a latency or bandwidth entry that is
tied to a DSMAS entry via a per DSMAS unique DSMAD handle.

This series is based on Lukas's latest DOE changes [5]. Kernel branch with all the code can
be retrieved here [6] for convenience.

Test setup is done with runqemu genport support branch [6]. The setup provides 2 CXL HBs
with one HB having a CXL switch underneath. It also provides generic port support detailed
below.

A hacked up qemu branch is used to support generic port SRAT and HMAT [7].

To create the appropriate HMAT entries for generic port, the following qemu paramters must
be added:

-object genport,id=$X -numa node,genport=genport$X,nodeid=$Y,initiator=$Z
-numa hmat-lb,initiator=$Z,target=$X,hierarchy=memory,data-type=access-latency,latency=$latency
-numa hmat-lb,initiator=$Z,target=$X,hierarchy=memory,data-type=access-bandwidth,bandwidth=$bandwidthM
for ((i = 0; i < total_nodes; i++)); do
	for ((j = 0; j < cxl_hbs; j++ )); do	# 2 CXL HBs
		-numa dist,src=$i,dst=$X,val=$dist
	done
done

See the genport run_qemu branch for full details.

[1]: https://www.computeexpresslink.org/download-the-specification
[2]: https://uefi.org/sites/default/files/resources/Coherent%20Device%20Attribute%20Table_1.01.pdf
[3]: https://uefi.org/sites/default/files/resources/ACPI_Spec_6_5_Aug29.pdf
[4]: https://cdrdv2-public.intel.com/643805/643805_CXL%20Memory%20Device%20SW%20Guide_Rev1p0.pdf
[5]: https://lore.kernel.org/linux-cxl/20230313195530.GA1532686@bhelgaas/T/#t
[6]: https://git.kernel.org/pub/scm/linux/kernel/git/djiang/linux.git/log/?h=cxl-qtg
[7]: https://github.com/pmem/run_qemu/tree/djiang/genport
[8]: https://github.com/davejiang/qemu/tree/genport

---

Dave Jiang (14):
      cxl: Add callback to parse the DSMAS subtables from CDAT
      cxl: Add callback to parse the DSLBIS subtable from CDAT
      cxl: Add callback to parse the SSLBIS subtable from CDAT
      cxl: Add support for _DSM Function for retrieving QTG ID
      cxl: Calculate and store PCI link latency for the downstream ports
      cxl: Store the access coordinates for the generic ports
      cxl: Add helper function that calculate performance data for downstream ports
      cxl: Compute the entire CXL path latency and bandwidth data
      cxl: Wait Memory_Info_Valid before access memory related info
      cxl: Move identify and partition query from pci probe to port probe
      cxl: Move read_cdat_data() to after media is ready
      cxl: Store QTG IDs and related info to the CXL memory device context
      cxl: Export sysfs attributes for memory device QoS class
      cxl/mem: Add debugfs output for QTG related data


 Documentation/ABI/testing/debugfs-cxl   |  11 ++
 Documentation/ABI/testing/sysfs-bus-cxl |  32 ++++
 MAINTAINERS                             |   1 +
 drivers/cxl/acpi.c                      | 154 ++++++++++++++++-
 drivers/cxl/core/Makefile               |   1 +
 drivers/cxl/core/cdat.c                 | 214 ++++++++++++++++++++++++
 drivers/cxl/core/mbox.c                 |   3 +
 drivers/cxl/core/memdev.c               |  26 +++
 drivers/cxl/core/pci.c                  | 156 ++++++++++++++++-
 drivers/cxl/core/port.c                 | 116 ++++++++++++-
 drivers/cxl/cxl.h                       |  71 ++++++++
 drivers/cxl/cxlmem.h                    |  21 +++
 drivers/cxl/cxlpci.h                    |  17 ++
 drivers/cxl/mem.c                       |  17 ++
 drivers/cxl/pci.c                       |  21 ---
 drivers/cxl/port.c                      | 134 ++++++++++++++-
 include/acpi/actbl1.h                   |   3 +
 17 files changed, 957 insertions(+), 41 deletions(-)
 create mode 100644 Documentation/ABI/testing/debugfs-cxl
 create mode 100644 drivers/cxl/core/cdat.c

--


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v5 01/14] cxl: Add callback to parse the DSMAS subtables from CDAT
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
@ 2023-05-08 20:46 ` Dave Jiang
  2023-05-12 14:26   ` Jonathan Cameron
  2023-05-08 20:47 ` [PATCH v5 02/14] cxl: Add callback to parse the DSLBIS subtable " Dave Jiang
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:46 UTC (permalink / raw)
  To: linux-cxl
  Cc: dan.j.williams, ira.weiny, vishal.l.verma, alison.schofield,
	Jonathan.Cameron

Provide a callback function to the CDAT parser in order to parse the Device
Scoped Memory Affinity Structure (DSMAS). Each DSMAS structure contains the
DPA range and its associated attributes in each entry. See the CDAT
specification for details. The device handle and the DPA range is saved and
to be associated with the DSLBIS locality data when the DSLBIS entries are
parsed. The list is a local list. When the total path performance data is
calculated and storred this list can be discarded.

Coherent Device Attribute Table 1.03 2.1 Device Scoped memory Affinity
Structure (DSMAS)

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
v5:
- Update commit log to indicate what list is used for. (Jonathan, Dan)
- Use acpi_table_parse_cdat()
- Isolate cdat code behind CONFIG_ACPI
v3:
- Add spec section number. (Alison)
- Remove cast from void *. (Alison)
- Refactor cxl_port_probe() block. (Alison)
- Move CDAT parse to cxl_endpoint_port_probe()

v2:
- Add DSMAS table size check. (Lukas)
- Use local DSMAS header for LE handling.
- Remove dsmas lock. (Jonathan)
- Fix handle size (Jonathan)
- Add LE to host conversion for DSMAS address and length.
- Make dsmas_list local
---
 drivers/cxl/core/Makefile |    1 +
 drivers/cxl/core/cdat.c   |   40 ++++++++++++++++++++++++++++++++++++++++
 drivers/cxl/cxl.h         |   18 ++++++++++++++++++
 drivers/cxl/port.c        |   22 ++++++++++++++++++++++
 4 files changed, 81 insertions(+)
 create mode 100644 drivers/cxl/core/cdat.c

diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile
index ca4ae31d8f57..98ddfd110f9b 100644
--- a/drivers/cxl/core/Makefile
+++ b/drivers/cxl/core/Makefile
@@ -12,5 +12,6 @@ cxl_core-y += memdev.o
 cxl_core-y += mbox.o
 cxl_core-y += pci.o
 cxl_core-y += hdm.o
+cxl_core-$(CONFIG_ACPI) += cdat.o
 cxl_core-$(CONFIG_TRACING) += trace.o
 cxl_core-$(CONFIG_CXL_REGION) += region.o
diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
new file mode 100644
index 000000000000..61979f0789aa
--- /dev/null
+++ b/drivers/cxl/core/cdat.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2023 Intel Corporation. All rights reserved. */
+#include <linux/acpi.h>
+#include "cxlpci.h"
+#include "cxl.h"
+
+static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
+			      const unsigned long end)
+{
+	struct acpi_cdat_dsmas *dsmas = (struct acpi_cdat_dsmas *)header;
+	struct list_head *dsmas_list = arg;
+	struct dsmas_entry *dent;
+	u16 len;
+
+	len = le16_to_cpu((__force __le16)dsmas->header.length);
+	if (len != sizeof(*dsmas) || (unsigned long)header + len > end) {
+		pr_warn("Malformed DSMAS table length: (%lu:%u)\n",
+			(unsigned long)sizeof(*dsmas), len);
+		return -EINVAL;
+	}
+
+	dent = kzalloc(sizeof(*dent), GFP_KERNEL);
+	if (!dent)
+		return -ENOMEM;
+
+	dent->handle = dsmas->dsmad_handle;
+	dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address);
+	dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) +
+			      le64_to_cpu((__force __le64)dsmas->dpa_length) - 1;
+	list_add_tail(&dent->list, dsmas_list);
+
+	return 0;
+}
+
+int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list)
+{
+	return acpi_table_parse_cdat(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler,
+				     list, port->cdat.table);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_cdat_endpoint_process, CXL);
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 4577d808ac6d..dda7238b47f5 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -7,6 +7,7 @@
 #include <linux/libnvdimm.h>
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
+#include <linux/list.h>
 #include <linux/log2.h>
 #include <linux/io.h>
 
@@ -791,6 +792,23 @@ static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
 }
 #endif
 
+/* CDAT related bits */
+struct dsmas_entry {
+	struct list_head list;
+	struct range dpa_range;
+	u8 handle;
+};
+
+#ifdef CONFIG_ACPI
+int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list);
+#else
+static inline int cxl_cdat_endpoint_process(struct cxl_port *port,
+					    struct list_head *list)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
 /*
  * Unit test builds overrides this to __weak, find the 'strong' version
  * of these symbols in tools/testing/cxl/.
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index a49f5eb149f1..da023feaa6e2 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -57,6 +57,16 @@ static int discover_region(struct device *dev, void *root)
 	return 0;
 }
 
+static void dsmas_list_destroy(struct list_head *dsmas_list)
+{
+	struct dsmas_entry *dentry, *n;
+
+	list_for_each_entry_safe(dentry, n, dsmas_list, list) {
+		list_del(&dentry->list);
+		kfree(dentry);
+	}
+}
+
 static int cxl_switch_port_probe(struct cxl_port *port)
 {
 	struct cxl_hdm *cxlhdm;
@@ -131,6 +141,18 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 	device_for_each_child(&port->dev, root, discover_region);
 	put_device(&root->dev);
 
+	if (port->cdat.table) {
+		LIST_HEAD(dsmas_list);
+
+		rc = cxl_cdat_endpoint_process(port, &dsmas_list);
+		if (rc < 0)
+			dev_dbg(&port->dev, "Failed to parse CDAT: %d\n", rc);
+
+		/* Performance data processing */
+
+		dsmas_list_destroy(&dsmas_list);
+	}
+
 	return 0;
 }
 



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 02/14] cxl: Add callback to parse the DSLBIS subtable from CDAT
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
  2023-05-08 20:46 ` [PATCH v5 01/14] cxl: Add callback to parse the DSMAS subtables from CDAT Dave Jiang
@ 2023-05-08 20:47 ` Dave Jiang
  2023-05-12 14:33   ` Jonathan Cameron
  2023-05-08 20:47 ` [PATCH v5 03/14] cxl: Add callback to parse the SSLBIS " Dave Jiang
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:47 UTC (permalink / raw)
  To: linux-cxl
  Cc: dan.j.williams, ira.weiny, vishal.l.verma, alison.schofield,
	Jonathan.Cameron

Provide a callback to parse the Device Scoped Latency and Bandwidth
Information Structure (DSLBIS) in the CDAT structures. The DSLBIS
contains the bandwidth and latency information that's tied to a DSMAS
handle. The driver will retrieve the read and write latency and
bandwidth associated with the DSMAS which is tied to a DPA range.

Coherent Device Attribute Table 1.03 2.1 Device Scoped Latency and
Bandwidth Information Structure (DSLBIS)

Signed-off-by: Dave Jiang <dave.jiang@intel.com>

---
v5:
- Remove macro for common headers. (Jonathan)
- Use acpi_table_parse_cdat().
- Remove unlikely(). (Dan)
v3:
- Added spec section in commit header. (Alison)
- Remove void * recast. (Alison)
- Rework comment. (Alison)
- Move CDAT parse to cxl_endpoint_port_probe()
- Convert to use 'struct node_hmem_attrs'

v2:
- Add size check to DSLIBIS table. (Lukas)
- Remove unnecessary entry type check. (Jonathan)
- Move data_type check to after match. (Jonathan)
- Skip unknown data type. (Jonathan)
- Add overflow check for unit multiply. (Jonathan)
- Use dev_warn() when entries parsing fail. (Jonathan)
---
 drivers/cxl/core/cdat.c |   90 ++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/cxl/cxl.h       |    2 +
 2 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
index 61979f0789aa..6e14d04c0453 100644
--- a/drivers/cxl/core/cdat.c
+++ b/drivers/cxl/core/cdat.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(c) 2023 Intel Corporation. All rights reserved. */
 #include <linux/acpi.h>
+#include <linux/overflow.h>
 #include "cxlpci.h"
 #include "cxl.h"
 
@@ -32,9 +33,94 @@ static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
 	return 0;
 }
 
+static void cxl_access_coordinate_set(struct access_coordinate *coord,
+				      int access, unsigned int val)
+{
+	switch (access) {
+	case ACPI_HMAT_ACCESS_LATENCY:
+		coord->read_latency = val;
+		coord->write_latency = val;
+		break;
+	case ACPI_HMAT_READ_LATENCY:
+		coord->read_latency = val;
+		break;
+	case ACPI_HMAT_WRITE_LATENCY:
+		coord->write_latency = val;
+		break;
+	case ACPI_HMAT_ACCESS_BANDWIDTH:
+		coord->read_bandwidth = val;
+		coord->write_bandwidth = val;
+		break;
+	case ACPI_HMAT_READ_BANDWIDTH:
+		coord->read_bandwidth = val;
+		break;
+	case ACPI_HMAT_WRITE_BANDWIDTH:
+		coord->write_bandwidth = val;
+		break;
+	}
+}
+
+static int cdat_dslbis_handler(union acpi_subtable_headers *header, void *arg,
+			       const unsigned long end)
+{
+	struct acpi_cdat_dslbis *dslbis = (struct acpi_cdat_dslbis *)header;
+	struct list_head *dsmas_list = arg;
+	struct dsmas_entry *dent;
+	u16 len;
+
+	len = le16_to_cpu((__force __le16)dslbis->header.length);
+	if (len != sizeof(*dslbis) || (unsigned long)header + len > end) {
+		pr_warn("Malformed DSLBIS table length: (%lu:%u)\n",
+			(unsigned long)sizeof(*dslbis), len);
+		return -EINVAL;
+	}
+
+	/* Skip unrecognized data type */
+	if (dslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH)
+		return 0;
+
+	list_for_each_entry(dent, dsmas_list, list) {
+		u64 val;
+		int rc;
+
+		if (dslbis->handle != dent->handle)
+			continue;
+
+		/* Not a memory type, skip */
+		if ((dslbis->flags & ACPI_HMAT_MEMORY_HIERARCHY) !=
+		    ACPI_HMAT_MEMORY)
+			return 0;
+
+		rc = check_mul_overflow(le64_to_cpu((__force __le64)dslbis->entry_base_unit),
+					le16_to_cpu((__force __le16)dslbis->entry[0]), &val);
+		if (rc)
+			pr_warn("DSLBIS value overflowed.\n");
+
+		cxl_access_coordinate_set(&dent->coord, dslbis->data_type, val);
+		break;
+	}
+
+	return 0;
+}
+
 int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list)
 {
-	return acpi_table_parse_cdat(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler,
-				     list, port->cdat.table);
+	int rc;
+
+	rc = acpi_table_parse_cdat(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler,
+				   list, port->cdat.table);
+	if (rc <= 0) {
+		if (rc == 0)
+			rc = -ENOENT;
+		return rc;
+	}
+
+	rc = acpi_table_parse_cdat(ACPI_CDAT_TYPE_DSLBIS,
+				   cdat_dslbis_handler,
+				   list, port->cdat.table);
+	if (rc == 0)
+		rc = -ENOENT;
+
+	return rc;
 }
 EXPORT_SYMBOL_NS_GPL(cxl_cdat_endpoint_process, CXL);
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index dda7238b47f5..ca3d0d74f2e5 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -8,6 +8,7 @@
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/list.h>
+#include <linux/node.h>
 #include <linux/log2.h>
 #include <linux/io.h>
 
@@ -797,6 +798,7 @@ struct dsmas_entry {
 	struct list_head list;
 	struct range dpa_range;
 	u8 handle;
+	struct access_coordinate coord;
 };
 
 #ifdef CONFIG_ACPI



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 03/14] cxl: Add callback to parse the SSLBIS subtable from CDAT
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
  2023-05-08 20:46 ` [PATCH v5 01/14] cxl: Add callback to parse the DSMAS subtables from CDAT Dave Jiang
  2023-05-08 20:47 ` [PATCH v5 02/14] cxl: Add callback to parse the DSLBIS subtable " Dave Jiang
@ 2023-05-08 20:47 ` Dave Jiang
  2023-05-12 14:41   ` Jonathan Cameron
  2023-05-08 20:47 ` [PATCH v5 04/14] cxl: Add support for _DSM Function for retrieving QTG ID Dave Jiang
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:47 UTC (permalink / raw)
  To: linux-cxl
  Cc: Jonathan Cameron, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield, Jonathan.Cameron

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>

---
v5:
- Store data to cxl_dport directly instead. (Dan)
- Use acpi_table_parse_cdat().
v3:
- Add spec section in commit header (Alison)
- Move CDAT parse to cxl_switch_port_probe()
- Use 'struct node_hmem_attrs'
---
 drivers/cxl/core/cdat.c |   88 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/cxl/cxl.h       |    8 ++++
 drivers/cxl/port.c      |   12 ++++++
 include/acpi/actbl1.h   |    3 ++
 4 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
index 6e14d04c0453..37b135c900d5 100644
--- a/drivers/cxl/core/cdat.c
+++ b/drivers/cxl/core/cdat.c
@@ -124,3 +124,91 @@ int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list)
 	return rc;
 }
 EXPORT_SYMBOL_NS_GPL(cxl_cdat_endpoint_process, CXL);
+
+static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg,
+			       const unsigned long end)
+{
+	struct acpi_cdat_sslbis *sslbis = (struct acpi_cdat_sslbis *)header;
+	struct acpi_cdat_sslbe *entry;
+	struct cxl_port *port = arg;
+	struct device *dev = &port->dev;
+	int remain, entries, i;
+	u16 len;
+
+	len = le16_to_cpu((__force __le16)sslbis->header.length);
+	remain = len - sizeof(*sslbis);
+	if (!remain || remain % sizeof(*entry) ||
+	    (unsigned long)header + len > end) {
+		dev_warn(dev, "Malformed SSLBIS table length: (%u)\n", len);
+		return -EINVAL;
+	}
+
+	/* Unrecognized data type, we can skip */
+	if (sslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH)
+		return 0;
+
+	entries = remain / sizeof(*entry);
+	entry = (struct acpi_cdat_sslbe *)((unsigned long)header + sizeof(*sslbis));
+
+	for (i = 0; i < entries; i++) {
+		u16 x = le16_to_cpu(entry->portx_id);
+		u16 y = le16_to_cpu(entry->porty_id);
+		struct cxl_dport *dport;
+		unsigned long index;
+		u16 dsp_id;
+		u64 val;
+
+		switch (x) {
+		case ACPI_CDAT_SSLBIS_US_PORT:
+			dsp_id = y;
+			break;
+		case ACPI_CDAT_SSLBIS_ANY_PORT:
+			switch (y) {
+			case ACPI_CDAT_SSLBIS_US_PORT:
+				dsp_id = x;
+				break;
+			case ACPI_CDAT_SSLBIS_ANY_PORT:
+				dsp_id = ACPI_CDAT_SSLBIS_ANY_PORT;
+				break;
+			default:
+				dsp_id = y;
+				break;
+			}
+			break;
+		default:
+			dsp_id = x;
+			break;
+		}
+
+		if (check_mul_overflow(le64_to_cpu(sslbis->entry_base_unit),
+				       le16_to_cpu(entry->latency_or_bandwidth),
+				       &val))
+			dev_warn(dev, "SSLBIS value overflowed!\n");
+
+		xa_for_each(&port->dports, index, dport) {
+			if (dsp_id == ACPI_CDAT_SSLBIS_ANY_PORT ||
+			    dsp_id == dport->port_id)
+				cxl_access_coordinate_set(&dport->coord,
+							  sslbis->data_type,
+							  val);
+		}
+
+		entry++;
+	}
+
+	return 0;
+}
+
+int cxl_cdat_switch_process(struct cxl_port *port)
+{
+	int rc;
+
+	rc = acpi_table_parse_cdat(ACPI_CDAT_TYPE_SSLBIS,
+				   cdat_sslbis_handler,
+				   port, port->cdat.table);
+	if (rc == 0)
+		rc = -ENOENT;
+
+	return rc;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_cdat_switch_process, CXL);
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index ca3d0d74f2e5..3e8020e0a132 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -600,6 +600,7 @@ cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
  * @rcrb: base address for the Root Complex Register Block
  * @rch: Indicate whether this dport was enumerated in RCH or VH mode
  * @port: reference to cxl_port that contains this downstream port
+ * @coord: access coordinates (performance) for switch from CDAT
  */
 struct cxl_dport {
 	struct device *dport;
@@ -608,6 +609,7 @@ struct cxl_dport {
 	resource_size_t rcrb;
 	bool rch;
 	struct cxl_port *port;
+	struct access_coordinate coord;
 };
 
 /**
@@ -803,12 +805,18 @@ struct dsmas_entry {
 
 #ifdef CONFIG_ACPI
 int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list);
+int cxl_cdat_switch_process(struct cxl_port *port);
 #else
 static inline int cxl_cdat_endpoint_process(struct cxl_port *port,
 					    struct list_head *list)
 {
 	return -EOPNOTSUPP;
 }
+
+static inline int cxl_cdat_switch_process(struct cxl_port *port)
+{
+	return -EOPNOTSUPP;
+}
 #endif
 
 /*
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index da023feaa6e2..c5a24b75bf03 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -86,7 +86,17 @@ static int cxl_switch_port_probe(struct cxl_port *port)
 	if (IS_ERR(cxlhdm))
 		return PTR_ERR(cxlhdm);
 
-	return devm_cxl_enumerate_decoders(cxlhdm, NULL);
+	rc = devm_cxl_enumerate_decoders(cxlhdm, NULL);
+	if (rc < 0)
+		return rc;
+
+	if (port->cdat.table) {
+		rc = cxl_cdat_switch_process(port);
+		if (rc < 0)
+			dev_warn(&port->dev, "Failed to parse SSLBIS: %d\n", rc);
+	}
+
+	return 0;
 }
 
 static int cxl_endpoint_port_probe(struct cxl_port *port)
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index 8ea7e5d64bc1..82def138a7e4 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -419,6 +419,9 @@ struct acpi_cdat_sslbis {
 	u64 entry_base_unit;
 };
 
+#define ACPI_CDAT_SSLBIS_US_PORT	0x0100
+#define ACPI_CDAT_SSLBIS_ANY_PORT	0xffff
+
 /* Sub-subtable for above, sslbe_entries field */
 
 struct acpi_cdat_sslbe {



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 04/14] cxl: Add support for _DSM Function for retrieving QTG ID
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (2 preceding siblings ...)
  2023-05-08 20:47 ` [PATCH v5 03/14] cxl: Add callback to parse the SSLBIS " Dave Jiang
@ 2023-05-08 20:47 ` Dave Jiang
  2023-05-12 14:50   ` Jonathan Cameron
  2023-05-08 20:47 ` [PATCH v5 05/14] cxl: Calculate and store PCI link latency for the downstream ports Dave Jiang
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:47 UTC (permalink / raw)
  To: linux-cxl
  Cc: dan.j.williams, ira.weiny, vishal.l.verma, alison.schofield,
	Jonathan.Cameron

CXL spec v3.0 9.17.3 CXL Root Device Specific Methods (_DSM)

Add support to retrieve QTG ID via ACPI _DSM call. The _DSM call requires
an input of an ACPI package with 4 dwords (read latency, write latency,
read bandwidth, write bandwidth). The call returns a package with 1 WORD
that provides the max supported QTG ID and a package that may contain 0 or
more WORDs as the recommended QTG IDs in the recommended order.

Create a cxl_root container for the root cxl_port and provide a callback
->get_qos_class() in order to retrieve the QoS class. For the ACPI case,
the _DSM helper is used to retrieve the QTG ID and returned. A
devm_cxl_add_root() function is added for root port setup and registration
of the cxl_root callback operation(s).

Signed-off-by: Dave Jiang <dave.jiang@intel.com>

---
v5:
- Make the helper a callback for the CXL root. (Dan)
- Drop the addition of core/acpi.c. (Dan)
- Add endiness handling. (Jonathan)
- Refactor error exits. (Jonathan)
- Update evaluate function description. (Jonathan)
- Make uuid static. (Dan)
v2:
- Reorder var declaration and use C99 style. (Jonathan)
- Allow >2 ACPI objects in package for future expansion. (Jonathan)
- Check QTG IDs against MAX QTG ID provided by output package. (Jonathan)
---
 drivers/cxl/acpi.c      |  126 ++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/cxl/core/port.c |   41 +++++++++++++--
 drivers/cxl/cxl.h       |   33 ++++++++++++
 3 files changed, 192 insertions(+), 8 deletions(-)

diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index e063df2bf876..f9b35e8fe810 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -17,6 +17,10 @@ struct cxl_cxims_data {
 	u64 xormaps[];
 };
 
+static const guid_t acpi_cxl_qtg_id_guid =
+	GUID_INIT(0xF365F9A6, 0xA7DE, 0x4071,
+		  0xA6, 0x6A, 0xB4, 0x0C, 0x0B, 0x4F, 0x8E, 0x52);
+
 /*
  * Find a targets entry (n) in the host bridge interleave list.
  * CXL Specification 3.0 Table 9-22
@@ -194,6 +198,120 @@ struct cxl_cfmws_context {
 	int id;
 };
 
+/**
+ * cxl_acpi_evaluate_qtg_dsm - Retrieve QTG ids via ACPI _DSM
+ * @handle: ACPI handle
+ * @input: bandwidth and latency data
+ *
+ * Issue QTG _DSM with accompanied bandwidth and latency data in order to get
+ * the QTG IDs that are suitable for the performance point in order of most
+ * suitable to least suitable. Return first QTG ID.
+ */
+static int cxl_acpi_evaluate_qtg_dsm(acpi_handle handle,
+				     struct qtg_dsm_input *input)
+{
+	union acpi_object *out_obj, *out_buf, *pkg;
+	union acpi_object in_buf = {
+		.buffer = {
+			.type = ACPI_TYPE_BUFFER,
+			.pointer = (u8 *)input,
+			.length = cpu_to_le32(sizeof(*input)),
+		},
+	};
+	union acpi_object in_obj = {
+		.package = {
+			.type = ACPI_TYPE_PACKAGE,
+			.count = cpu_to_le32(1),
+			.elements = &in_buf
+		},
+	};
+	u16 max_qtg;
+	int rc = 0;
+	int len;
+
+	out_obj = acpi_evaluate_dsm(handle, &acpi_cxl_qtg_id_guid, 1, 1, &in_obj);
+	if (!out_obj)
+		return -ENXIO;
+
+	if (out_obj->type != ACPI_TYPE_PACKAGE) {
+		rc = -ENXIO;
+		goto out;
+	}
+
+	/* Check Max QTG ID */
+	pkg = &out_obj->package.elements[0];
+	if (pkg->type != ACPI_TYPE_BUFFER) {
+		rc = -ENXIO;
+		goto out;
+	}
+
+	if (le32_to_cpu(pkg->buffer.length) != sizeof(u16)) {
+		rc = -ENXIO;
+		goto out;
+	}
+
+	max_qtg = le16_to_cpu(*(__le16 *)pkg->buffer.pointer);
+
+	/* Retrieve QTG IDs package */
+	pkg = &out_obj->package.elements[1];
+	if (pkg->type != ACPI_TYPE_PACKAGE) {
+		rc = -ENXIO;
+		goto out;
+	}
+
+	out_buf = &pkg->package.elements[0];
+	if (out_buf->type != ACPI_TYPE_BUFFER) {
+		rc = -ENXIO;
+		goto out;
+	}
+
+	len = le32_to_cpu(out_buf->buffer.length);
+
+	/* It's legal to have 0 QTG entries */
+	if (len == 0) {
+		rc = -EEXIST;
+		goto out;
+	}
+
+	/* Malformed package, not multiple of WORD size */
+	if (len % sizeof(u16)) {
+		rc = -ENXIO;
+		goto out;
+	}
+
+	rc = le16_to_cpu(*(__le16 *)out_buf->buffer.pointer);
+	if (rc > max_qtg) {
+		rc = -ERANGE;
+		pr_warn("QTG ID %u greater than MAX %u\n", rc, max_qtg);
+	}
+
+out:
+	ACPI_FREE(out_obj);
+	return rc;
+}
+
+static int cxl_acpi_get_qos_class(struct cxl_port *root_port,
+				  struct qtg_dsm_input *input)
+{
+	acpi_handle handle;
+	struct device *dev;
+
+	dev = root_port->uport;
+
+	if (!dev_is_platform(dev))
+		return -ENODEV;
+
+	handle = ACPI_HANDLE(dev);
+	if (!handle)
+		return -ENODEV;
+
+	return cxl_acpi_evaluate_qtg_dsm(handle, input);
+}
+
+static const struct cxl_root_ops acpi_root_ops = {
+	.get_qos_class = cxl_acpi_get_qos_class,
+};
+
 static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
 			   const unsigned long end)
 {
@@ -631,6 +749,7 @@ static int cxl_acpi_probe(struct platform_device *pdev)
 {
 	int rc;
 	struct resource *cxl_res;
+	struct cxl_root *cxl_root;
 	struct cxl_port *root_port;
 	struct device *host = &pdev->dev;
 	struct acpi_device *adev = ACPI_COMPANION(host);
@@ -650,9 +769,10 @@ static int cxl_acpi_probe(struct platform_device *pdev)
 	cxl_res->end = -1;
 	cxl_res->flags = IORESOURCE_MEM;
 
-	root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
-	if (IS_ERR(root_port))
-		return PTR_ERR(root_port);
+	cxl_root = devm_cxl_add_root(host, &acpi_root_ops);
+	if (IS_ERR(cxl_root))
+		return PTR_ERR(cxl_root);
+	root_port = &cxl_root->port;
 
 	rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
 			      add_host_bridge_dport);
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index a0130aeb8d42..60693c3f85f6 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -526,7 +526,10 @@ static void cxl_port_release(struct device *dev)
 	xa_destroy(&port->dports);
 	xa_destroy(&port->regions);
 	ida_free(&cxl_port_ida, port->id);
-	kfree(port);
+	if (is_cxl_root(port))
+		kfree(to_cxl_root(port));
+	else
+		kfree(port);
 }
 
 static const struct attribute_group *cxl_port_attribute_groups[] = {
@@ -629,13 +632,22 @@ static struct cxl_port *cxl_port_alloc(struct device *uport,
 				       resource_size_t component_reg_phys,
 				       struct cxl_dport *parent_dport)
 {
+	struct cxl_root *cxl_root = NULL;
 	struct cxl_port *port;
 	struct device *dev;
 	int rc;
 
-	port = kzalloc(sizeof(*port), GFP_KERNEL);
-	if (!port)
-		return ERR_PTR(-ENOMEM);
+	/* No parent_dport, root cxl_port */
+	if (!parent_dport) {
+		cxl_root = kzalloc(sizeof(*cxl_root), GFP_KERNEL);
+		if (!cxl_root)
+			return ERR_PTR(-ENOMEM);
+		port = &cxl_root->port;
+	} else {
+		port = kzalloc(sizeof(*port), GFP_KERNEL);
+		if (!port)
+			return ERR_PTR(-ENOMEM);
+	}
 
 	rc = ida_alloc(&cxl_port_ida, GFP_KERNEL);
 	if (rc < 0)
@@ -693,7 +705,10 @@ static struct cxl_port *cxl_port_alloc(struct device *uport,
 	return port;
 
 err:
-	kfree(port);
+	if (cxl_root)
+		kfree(cxl_root);
+	else
+		kfree(port);
 	return ERR_PTR(rc);
 }
 
@@ -779,6 +794,22 @@ struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
 }
 EXPORT_SYMBOL_NS_GPL(devm_cxl_add_port, CXL);
 
+struct cxl_root *devm_cxl_add_root(struct device *host,
+				   const struct cxl_root_ops *ops)
+{
+	struct cxl_root *cxl_root;
+	struct cxl_port *port;
+
+	port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
+	if (IS_ERR(port))
+		return (struct cxl_root *)port;
+
+	cxl_root = to_cxl_root(port);
+	cxl_root->ops = ops;
+	return cxl_root;
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_add_root, CXL);
+
 struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port)
 {
 	/* There is no pci_bus associated with a CXL platform-root port */
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 3e8020e0a132..16fc14d43aa4 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -586,6 +586,30 @@ struct cxl_port {
 	bool cdat_available;
 };
 
+struct qtg_dsm_input;
+
+struct cxl_root_ops {
+	int (*get_qos_class)(struct cxl_port *root_port,
+			     struct qtg_dsm_input *input);
+};
+
+/**
+ * struct cxl_root - logical collection of root cxl_port items
+ *
+ * @port: cxl_port member
+ * @ops: cxl root operations
+ */
+struct cxl_root {
+	struct cxl_port port;
+	const struct cxl_root_ops *ops;
+};
+
+static inline struct cxl_root *
+to_cxl_root(const struct cxl_port *port)
+{
+	return container_of(port, struct cxl_root, port);
+}
+
 static inline struct cxl_dport *
 cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
 {
@@ -665,6 +689,8 @@ struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port);
 struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
 				   resource_size_t component_reg_phys,
 				   struct cxl_dport *parent_dport);
+struct cxl_root *devm_cxl_add_root(struct device *host,
+				   const struct cxl_root_ops *ops);
 struct cxl_port *find_cxl_root(struct cxl_port *port);
 int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
 void cxl_bus_rescan(void);
@@ -819,6 +845,13 @@ static inline int cxl_cdat_switch_process(struct cxl_port *port)
 }
 #endif
 
+struct qtg_dsm_input {
+	__le32 rd_lat;
+	__le32 wr_lat;
+	__le32 rd_bw;
+	__le32 wr_bw;
+};
+
 /*
  * Unit test builds overrides this to __weak, find the 'strong' version
  * of these symbols in tools/testing/cxl/.



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 05/14] cxl: Calculate and store PCI link latency for the downstream ports
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (3 preceding siblings ...)
  2023-05-08 20:47 ` [PATCH v5 04/14] cxl: Add support for _DSM Function for retrieving QTG ID Dave Jiang
@ 2023-05-08 20:47 ` Dave Jiang
  2023-05-08 20:47 ` [PATCH v5 06/14] cxl: Store the access coordinates for the generic ports Dave Jiang
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:47 UTC (permalink / raw)
  To: linux-cxl
  Cc: Jonathan Cameron, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield, Jonathan.Cameron

The latency is calculated by dividing the flit size over the bandwidth. Add
support to retrieve the flit size for the CXL switch device and calculate
the latency of the PCIe link. Cache the latency number with cxl_dport.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>

---
v5:
- Store the latency numbers under dports. (Dan)
- Use defines instead of magic numbers. (Jonathan)
v2:
- Fix commit log issues. (Jonathan)
- Fix var declaration issues. (Jonathan)
---
 drivers/cxl/core/pci.c  |   73 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/cxl/core/port.c |    6 ++++
 drivers/cxl/cxl.h       |    4 +++
 drivers/cxl/cxlpci.h    |   15 ++++++++++
 drivers/cxl/pci.c       |   13 --------
 5 files changed, 98 insertions(+), 13 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 58051154ab1a..6c99a964eb54 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(c) 2021 Intel Corporation. All rights reserved. */
+#include <linux/units.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/device.h>
 #include <linux/delay.h>
@@ -718,3 +719,75 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
 	return PCI_ERS_RESULT_NEED_RESET;
 }
 EXPORT_SYMBOL_NS_GPL(cxl_error_detected, CXL);
+
+extern const unsigned char pcie_link_speed[];
+
+static enum pci_bus_speed get_link_speed(struct pci_dev *pdev)
+{
+	u16 linkstat;
+	int err;
+
+	err = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &linkstat);
+	if (err)
+		return -EINVAL;
+
+	return pcie_link_speed[linkstat & PCI_EXP_LNKSTA_CLS];
+}
+
+static int pci_bus_speed_to_mbps(enum pci_bus_speed speed)
+{
+	switch (speed) {
+	case PCIE_SPEED_2_5GT:
+		return 2500;
+	case PCIE_SPEED_5_0GT:
+		return 5000;
+	case PCIE_SPEED_8_0GT:
+		return 8000;
+	case PCIE_SPEED_16_0GT:
+		return 16000;
+	case PCIE_SPEED_32_0GT:
+		return 32000;
+	case PCIE_SPEED_64_0GT:
+		return 64000;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int cxl_flit_size(struct pci_dev *pdev)
+{
+	if (cxl_pci_flit_256(pdev))
+		return 256;
+
+	return 68;
+}
+
+/**
+ * cxl_pci_get_latency - calculate the link latency for the PCIe link
+ * @pdev - PCI device
+ *
+ * return: calculated latency or 0 for no latency
+ *
+ * CXL Memory Device SW Guide v1.0 2.11.4 Link latency calculation
+ * Link latency = LinkPropagationLatency + FlitLatency + RetimerLatency
+ * LinkProgationLatency is negligible, so 0 will be used
+ * RetimerLatency is assumed to be negligible and 0 will be used
+ * FlitLatency = FlitSize / LinkBandwidth
+ * FlitSize is defined by spec. CXL rev3.0 4.2.1.
+ * 68B flit is used up to 32GT/s. >32GT/s, 256B flit size is used.
+ * The FlitLatency is converted to picoseconds.
+ */
+long cxl_pci_get_latency(struct pci_dev *pdev)
+{
+	long bw;
+
+	bw = pci_bus_speed_to_mbps(get_link_speed(pdev));
+	if (bw < 0)
+		return 0;
+	bw /= BITS_PER_BYTE;
+
+	return cxl_flit_size(pdev) * MEGA / bw;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_pci_get_latency, CXL);
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 60693c3f85f6..e4f75847b851 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -751,6 +751,9 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host,
 	if (rc)
 		return ERR_PTR(rc);
 
+	if (parent_dport && dev_is_pci(uport))
+		port->pci_latency = cxl_pci_get_latency(to_pci_dev(uport));
+
 	return port;
 
 err:
@@ -1008,6 +1011,9 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
 	if (rc)
 		return ERR_PTR(rc);
 
+	if (dev_is_pci(dport_dev))
+		dport->link_latency = cxl_pci_get_latency(to_pci_dev(dport_dev));
+
 	return dport;
 }
 
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 16fc14d43aa4..c1e2c3703a63 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -562,6 +562,7 @@ struct cxl_dax_region {
  * @depth: How deep this port is relative to the root. depth 0 is the root.
  * @cdat: Cached CDAT data
  * @cdat_available: Should a CDAT attribute be available in sysfs
+ * @pci_latency: Upstream latency in picoseconds
  */
 struct cxl_port {
 	struct device dev;
@@ -584,6 +585,7 @@ struct cxl_port {
 		size_t length;
 	} cdat;
 	bool cdat_available;
+	long pci_latency;
 };
 
 struct qtg_dsm_input;
@@ -625,6 +627,7 @@ cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
  * @rch: Indicate whether this dport was enumerated in RCH or VH mode
  * @port: reference to cxl_port that contains this downstream port
  * @coord: access coordinates (performance) for switch from CDAT
+ * @link_latency: calculated PCIe downstream latency
  */
 struct cxl_dport {
 	struct device *dport;
@@ -634,6 +637,7 @@ struct cxl_dport {
 	bool rch;
 	struct cxl_port *port;
 	struct access_coordinate coord;
+	long link_latency;
 };
 
 /**
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 0465ef963cd6..84c9f73c7d92 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -82,6 +82,19 @@ struct cdat_entry_header {
 	__le16 length;
 } __packed;
 
+/*
+ * CXL v3.0 6.2.3 Table 6-4
+ * The table indicates that if PCIe Flit Mode is set, then CXL is in 256B flits
+ * mode, otherwise it's 68B flits mode.
+ */
+static inline bool cxl_pci_flit_256(struct pci_dev *pdev)
+{
+	u16 lnksta2;
+
+	pcie_capability_read_word(pdev, PCI_EXP_LNKSTA2, &lnksta2);
+	return lnksta2 & PCI_EXP_LNKSTA2_FLIT;
+}
+
 int devm_cxl_port_enumerate_dports(struct cxl_port *port);
 struct cxl_dev_state;
 int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
@@ -90,4 +103,6 @@ void read_cdat_data(struct cxl_port *port);
 void cxl_cor_error_detected(struct pci_dev *pdev);
 pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
 				    pci_channel_state_t state);
+long cxl_pci_get_latency(struct pci_dev *pdev);
+
 #endif /* __CXL_PCI_H__ */
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index ea38bd49b0cf..ed39d133b70d 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -365,19 +365,6 @@ static bool is_cxl_restricted(struct pci_dev *pdev)
 	return pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END;
 }
 
-/*
- * CXL v3.0 6.2.3 Table 6-4
- * The table indicates that if PCIe Flit Mode is set, then CXL is in 256B flits
- * mode, otherwise it's 68B flits mode.
- */
-static bool cxl_pci_flit_256(struct pci_dev *pdev)
-{
-	u16 lnksta2;
-
-	pcie_capability_read_word(pdev, PCI_EXP_LNKSTA2, &lnksta2);
-	return lnksta2 & PCI_EXP_LNKSTA2_FLIT;
-}
-
 static int cxl_pci_ras_unmask(struct pci_dev *pdev)
 {
 	struct pci_host_bridge *host_bridge = pci_find_host_bridge(pdev->bus);



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 06/14] cxl: Store the access coordinates for the generic ports
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (4 preceding siblings ...)
  2023-05-08 20:47 ` [PATCH v5 05/14] cxl: Calculate and store PCI link latency for the downstream ports Dave Jiang
@ 2023-05-08 20:47 ` Dave Jiang
  2023-05-12 14:59   ` Jonathan Cameron
  2023-05-08 20:47 ` [PATCH v5 07/14] cxl: Add helper function that calculate performance data for downstream ports Dave Jiang
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:47 UTC (permalink / raw)
  To: linux-cxl
  Cc: dan.j.williams, ira.weiny, vishal.l.verma, alison.schofield,
	Jonathan.Cameron

Each CXL host bridge is represented by an ACPI0016 device. A generic port
device handle that is an ACPI device is represented by a string of
ACPI0016 device HID and UID. Create a device handle from the ACPI device
and retrieve the access coordinates from the stored memory targets. The
access coordinates are stored under the cxl_dport that is associated with
the CXL host bridge.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 drivers/cxl/acpi.c |   28 ++++++++++++++++++++++++++++
 drivers/cxl/cxl.h  |    2 ++
 2 files changed, 30 insertions(+)

diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index f9b35e8fe810..675a4f423f4b 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -537,8 +537,26 @@ static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
 	return 0;
 }
 
+static int get_genport_coordinates(struct device *dev, struct cxl_dport *dport)
+{
+	struct acpi_device *hb = to_cxl_host_bridge(NULL, dev);
+	u8 handle[ACPI_SRAT_DEVICE_HANDLE_SIZE] = { 0 };
+	int rc;
+
+	/* ACPI spec 6.5 tABLE 5.65 */
+	memcpy(handle, acpi_device_hid(hb), 8);
+	memcpy(&handle[8], acpi_device_uid(hb), 4);
+
+	rc = acpi_get_genport_coordinates(handle, dport->genport_coord);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
 static int add_host_bridge_dport(struct device *match, void *arg)
 {
+	int ret;
 	acpi_status rc;
 	struct device *bridge;
 	unsigned long long uid;
@@ -594,6 +612,16 @@ static int add_host_bridge_dport(struct device *match, void *arg)
 	if (IS_ERR(dport))
 		return PTR_ERR(dport);
 
+	dport->genport_coord = devm_kzalloc(dport->dport,
+					    sizeof(*dport->genport_coord),
+					    GFP_KERNEL);
+	if (!dport->genport_coord)
+		return -ENOMEM;
+
+	ret = get_genport_coordinates(match, dport);
+	if (ret)
+		dev_dbg(match, "Failed to get generic port perf coordinates.\n");
+
 	return 0;
 }
 
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index c1e2c3703a63..033b822a20f2 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -626,6 +626,7 @@ cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
  * @rcrb: base address for the Root Complex Register Block
  * @rch: Indicate whether this dport was enumerated in RCH or VH mode
  * @port: reference to cxl_port that contains this downstream port
+ * @genport_coord: access coordinates (performance) from ACPI generic port
  * @coord: access coordinates (performance) for switch from CDAT
  * @link_latency: calculated PCIe downstream latency
  */
@@ -636,6 +637,7 @@ struct cxl_dport {
 	resource_size_t rcrb;
 	bool rch;
 	struct cxl_port *port;
+	struct access_coordinate *genport_coord;
 	struct access_coordinate coord;
 	long link_latency;
 };



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 07/14] cxl: Add helper function that calculate performance data for downstream ports
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (5 preceding siblings ...)
  2023-05-08 20:47 ` [PATCH v5 06/14] cxl: Store the access coordinates for the generic ports Dave Jiang
@ 2023-05-08 20:47 ` Dave Jiang
  2023-05-12 15:05   ` Jonathan Cameron
  2023-05-08 20:47 ` [PATCH v5 08/14] cxl: Compute the entire CXL path latency and bandwidth data Dave Jiang
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:47 UTC (permalink / raw)
  To: linux-cxl
  Cc: dan.j.williams, ira.weiny, vishal.l.verma, alison.schofield,
	Jonathan.Cameron

The CDAT information from the switch, Switch Scoped Latency and Bandwidth
Information Strucutre (SSLBIS), is parsed and stored under a cxl_dport
based on the correlated downstream port id from the SSLBIS entry. Walk
the entire CXL port paths and collect all the performance data. Also
pick up the link latency number that's stored under the dports. The
entire path PCIe bandwidth can be retrieved using the
pcie_bandwidth_available() call.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 drivers/cxl/core/port.c |   69 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/cxl/cxl.h       |    3 ++
 2 files changed, 72 insertions(+)

diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index e4f75847b851..1111a3cebc8e 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -9,6 +9,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/idr.h>
+#include <linux/node.h>
 #include <cxlmem.h>
 #include <cxlpci.h>
 #include <cxl.h>
@@ -1950,6 +1951,74 @@ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd)
 }
 EXPORT_SYMBOL_NS_GPL(schedule_cxl_memdev_detach, CXL);
 
+static void combine_coordinates(struct access_coordinate *c1,
+				struct access_coordinate *c2)
+{
+		if (c2->write_bandwidth)
+			c1->write_bandwidth = min_t(unsigned int,
+						    c1->write_bandwidth,
+						    c2->write_bandwidth);
+		c1->write_latency += c2->write_latency;
+
+		if (c2->read_bandwidth)
+			c1->read_bandwidth = min_t(unsigned int,
+						   c1->read_bandwidth,
+						   c2->read_bandwidth);
+		c1->read_latency += c2->read_latency;
+}
+
+/**
+ * cxl_port_get_perf_coordinates - Retrieve performance numbers stored in dports
+ *				   of CXL path
+ * @port: endpoint cxl_port
+ * @coord: output performance data
+ *
+ * Return: errno on failure, 0 on success.
+ */
+int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,
+				      struct access_coordinate *coord)
+{
+	struct access_coordinate c = {
+		.read_bandwidth = UINT_MAX,
+		.write_bandwidth = UINT_MAX,
+	};
+	struct cxl_port *iter = port;
+	struct cxl_dport *dport;
+	struct pci_dev *pdev;
+	unsigned int bw;
+
+	if (!is_cxl_endpoint(port))
+		return -EINVAL;
+
+	dport = iter->parent_dport;
+	while (iter && !is_cxl_root(iter)) {
+		combine_coordinates(&c, &dport->coord);
+		c.write_latency += dport->link_latency;
+		c.read_latency += dport->link_latency;
+
+		if (dport->genport_coord)
+			combine_coordinates(&c, dport->genport_coord);
+
+		iter = to_cxl_port(iter->dev.parent);
+		dport = iter->parent_dport;
+	}
+
+	/* Get the calculated PCI paths bandwidth */
+	pdev = to_pci_dev(port->uport->parent);
+	bw = pcie_bandwidth_available(pdev, NULL, NULL, NULL);
+	if (bw == 0)
+		return -ENXIO;
+	bw /= BITS_PER_BYTE;
+
+	c.write_bandwidth = min_t(unsigned int, c.write_bandwidth, bw);
+	c.read_bandwidth = min_t(unsigned int, c.read_bandwidth, bw);
+
+	*coord = c;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_endpoint_get_perf_coordinates, CXL);
+
 /* for user tooling to ensure port disable work has completed */
 static ssize_t flush_store(struct bus_type *bus, const char *buf, size_t count)
 {
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 033b822a20f2..0c8952e568cc 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -858,6 +858,9 @@ struct qtg_dsm_input {
 	__le32 wr_bw;
 };
 
+int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,
+				      struct access_coordinate *coord);
+
 /*
  * Unit test builds overrides this to __weak, find the 'strong' version
  * of these symbols in tools/testing/cxl/.



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 08/14] cxl: Compute the entire CXL path latency and bandwidth data
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (6 preceding siblings ...)
  2023-05-08 20:47 ` [PATCH v5 07/14] cxl: Add helper function that calculate performance data for downstream ports Dave Jiang
@ 2023-05-08 20:47 ` Dave Jiang
  2023-05-12 15:09   ` Jonathan Cameron
  2023-05-08 20:47 ` [PATCH v5 09/14] cxl: Wait Memory_Info_Valid before access memory related info Dave Jiang
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:47 UTC (permalink / raw)
  To: linux-cxl
  Cc: dan.j.williams, ira.weiny, vishal.l.verma, alison.schofield,
	Jonathan.Cameron

CXL Memory Device SW Guide rev1.0 2.11.2 provides instruction on how to
caluclate latency and bandwidth for CXL memory device. Calculate minimum
bandwidth and total latency for the path from the CXL device to the root
port. The QTG id is retrieved by providing the performance data as input
and calling the root port callback ->get_qos_class(). The retrieved id is
stored with the cxl_port of the CXL device.

For example for a device that is directly attached to a host bus:
Total Latency = Device Latency (from CDAT) + Dev to Host Bus (HB) Link
		Latency + Generic Port Latency
Min Bandwidth = Min bandwidth for link bandwidth between HB
		and CXL device, device CDAT bandwidth, and Generic Port
		Bandwidth

For a device that has a switch in between host bus and CXL device:
Total Latency = Device (CDAT) Latency + Dev to Switch Link Latency +
		Switch (CDAT) Latency + Switch to HB Link Latency +
		Generic Port Latency
Min Bandwidth = Min bandwidth for link bandwidth between CXL device
		to CXL switch, CXL device CDAT bandwidth, CXL switch CDAT
		bandwidth, CXL switch to HB bandwidth, and Generic Port
		Bandwidth.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>

---
v5:
- Use new API call cxl_endpoint_get_perf_coordinates().
- Use root_port->get_qos_class() (Dan)
- Add endieness handling to DSM input.
---
 drivers/cxl/cxl.h  |    1 +
 drivers/cxl/port.c |   56 +++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 0c8952e568cc..7c94f07771c1 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -833,6 +833,7 @@ struct dsmas_entry {
 	struct range dpa_range;
 	u8 handle;
 	struct access_coordinate coord;
+	int qos_class;
 };
 
 #ifdef CONFIG_ACPI
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index c5a24b75bf03..b474997cc7ee 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -67,6 +67,52 @@ static void dsmas_list_destroy(struct list_head *dsmas_list)
 	}
 }
 
+static int cxl_port_perf_data_calculate(struct cxl_port *port,
+					struct list_head *dsmas_list)
+{
+	struct access_coordinate c;
+	struct qtg_dsm_input input;
+	struct cxl_port *root_port;
+	struct cxl_root *cxl_root;
+	struct dsmas_entry *dent;
+	int rc, qos_class;
+
+	rc = cxl_endpoint_get_perf_coordinates(port, &c);
+	if (rc) {
+		dev_dbg(&port->dev, "Failed to retrieve perf coordinates.\n");
+		return rc;
+	}
+
+	root_port = find_cxl_root(port);
+	cxl_root = to_cxl_root(root_port);
+	if (!cxl_root->ops && !cxl_root->ops->get_qos_class)
+		return -EOPNOTSUPP;
+
+	list_for_each_entry(dent, dsmas_list, list) {
+		dent->coord.read_latency = dent->coord.read_latency +
+					   c.read_latency;
+		dent->coord.write_latency = dent->coord.write_latency +
+					    c.write_latency;
+		dent->coord.read_bandwidth = min_t(int, c.read_bandwidth,
+						   dent->coord.read_bandwidth);
+		dent->coord.write_bandwidth = min_t(int, c.write_bandwidth,
+						    dent->coord.write_bandwidth);
+
+		input.rd_lat = cpu_to_le32(dent->coord.read_latency);
+		input.wr_lat = cpu_to_le32(dent->coord.write_latency);
+		input.rd_bw = cpu_to_le32(dent->coord.read_bandwidth);
+		input.wr_bw = cpu_to_le32(dent->coord.write_bandwidth);
+
+		qos_class = cxl_root->ops->get_qos_class(root_port, &input);
+		if (qos_class < 0)
+			continue;
+
+		dent->qos_class = qos_class;
+	}
+
+	return 0;
+}
+
 static int cxl_switch_port_probe(struct cxl_port *port)
 {
 	struct cxl_hdm *cxlhdm;
@@ -155,10 +201,14 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 		LIST_HEAD(dsmas_list);
 
 		rc = cxl_cdat_endpoint_process(port, &dsmas_list);
-		if (rc < 0)
+		if (rc < 0) {
 			dev_dbg(&port->dev, "Failed to parse CDAT: %d\n", rc);
-
-		/* Performance data processing */
+		} else {
+			rc = cxl_port_perf_data_calculate(port, &dsmas_list);
+			if (rc)
+				dev_dbg(&port->dev,
+					"Failed to do perf coord calculations.\n");
+		}
 
 		dsmas_list_destroy(&dsmas_list);
 	}



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 09/14] cxl: Wait Memory_Info_Valid before access memory related info
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (7 preceding siblings ...)
  2023-05-08 20:47 ` [PATCH v5 08/14] cxl: Compute the entire CXL path latency and bandwidth data Dave Jiang
@ 2023-05-08 20:47 ` Dave Jiang
  2023-05-12 15:16   ` Jonathan Cameron
  2023-05-08 20:47 ` [PATCH v5 10/14] cxl: Move identify and partition query from pci probe to port probe Dave Jiang
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:47 UTC (permalink / raw)
  To: linux-cxl
  Cc: dan.j.williams, ira.weiny, vishal.l.verma, alison.schofield,
	Jonathan.Cameron

CXL rev3.0 8.1.3.8.2 Memory_Info_valid field

The Memory_Info_Valid bit indicates that the CXL Range Size High and Size
Low registers are valid. The bit must be set within 1 second of reset
deassertion to the device. Check valid bit before we check the
Memory_Active bit when waiting for cxl_await_media_ready() to ensure that
the memory info is valid for consumption.

Fixes: 2e4ba0ec9783 ("cxl/pci: Move cxl_await_media_ready() to the core")
Signed-off-by: Dave Jiang <dave.jiang@intel.com>

---
v2:
- Check both ranges. (Jonathan)
---
 drivers/cxl/core/pci.c |   83 +++++++++++++++++++++++++++++++++++++++++++-----
 drivers/cxl/cxlpci.h   |    2 +
 2 files changed, 77 insertions(+), 8 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 6c99a964eb54..536672d469a1 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -102,21 +102,55 @@ int devm_cxl_port_enumerate_dports(struct cxl_port *port)
 }
 EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, CXL);
 
-/*
- * Wait up to @media_ready_timeout for the device to report memory
- * active.
- */
-int cxl_await_media_ready(struct cxl_dev_state *cxlds)
+static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id)
+{
+	struct pci_dev *pdev = to_pci_dev(cxlds->dev);
+	int d = cxlds->cxl_dvsec;
+	bool valid = false;
+	int rc, i;
+	u32 temp;
+
+	if (id > CXL_DVSEC_RANGE_MAX)
+		return -EINVAL;
+
+	/* Check MEM INFO VALID bit first, give up after 1s */
+	i = 1;
+	do {
+		rc = pci_read_config_dword(pdev,
+					   d + CXL_DVSEC_RANGE_SIZE_LOW(id),
+					   &temp);
+		if (rc)
+			return rc;
+
+		valid = FIELD_GET(CXL_DVSEC_MEM_INFO_VALID, temp);
+		if (valid)
+			break;
+		msleep(1000);
+	} while (i--);
+
+	if (!valid) {
+		dev_err(&pdev->dev,
+			"Timeout awaiting memory range %d valid after 1s.\n",
+			id);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int cxl_dvsec_mem_range_active(struct cxl_dev_state *cxlds, int id)
 {
 	struct pci_dev *pdev = to_pci_dev(cxlds->dev);
 	int d = cxlds->cxl_dvsec;
 	bool active = false;
-	u64 md_status;
 	int rc, i;
+	u32 temp;
 
-	for (i = media_ready_timeout; i; i--) {
-		u32 temp;
+	if (id > CXL_DVSEC_RANGE_MAX)
+		return -EINVAL;
 
+	/* Check MEM ACTIVE bit, up to 60s timeout by default */
+	for (i = media_ready_timeout; i; i--) {
 		rc = pci_read_config_dword(
 			pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &temp);
 		if (rc)
@@ -135,6 +169,39 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds)
 		return -ETIMEDOUT;
 	}
 
+	return 0;
+}
+
+/*
+ * Wait up to @media_ready_timeout for the device to report memory
+ * active.
+ */
+int cxl_await_media_ready(struct cxl_dev_state *cxlds)
+{
+	struct pci_dev *pdev = to_pci_dev(cxlds->dev);
+	int d = cxlds->cxl_dvsec;
+	int rc, i, hdm_count;
+	u64 md_status;
+	u16 cap;
+
+	rc = pci_read_config_word(pdev,
+				  d + CXL_DVSEC_CAP_OFFSET, &cap);
+	if (rc)
+		return rc;
+
+	hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);
+	for (i = 0; i < hdm_count; i++) {
+		rc = cxl_dvsec_mem_range_valid(cxlds, i);
+		if (rc)
+			return rc;
+	}
+
+	for (i = 0; i < hdm_count; i++) {
+		rc = cxl_dvsec_mem_range_active(cxlds, i);
+		if (rc)
+			return rc;
+	}
+
 	md_status = readq(cxlds->regs.memdev + CXLMDEV_STATUS_OFFSET);
 	if (!CXLMDEV_READY(md_status))
 		return -EIO;
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 84c9f73c7d92..1772cd226108 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -31,6 +31,8 @@
 #define   CXL_DVSEC_RANGE_BASE_LOW(i)	(0x24 + (i * 0x10))
 #define     CXL_DVSEC_MEM_BASE_LOW_MASK	GENMASK(31, 28)
 
+#define CXL_DVSEC_RANGE_MAX		2
+
 /* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */
 #define CXL_DVSEC_FUNCTION_MAP					2
 



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 10/14] cxl: Move identify and partition query from pci probe to port probe
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (8 preceding siblings ...)
  2023-05-08 20:47 ` [PATCH v5 09/14] cxl: Wait Memory_Info_Valid before access memory related info Dave Jiang
@ 2023-05-08 20:47 ` Dave Jiang
  2023-05-12 15:17   ` Jonathan Cameron
  2023-05-08 20:47 ` [PATCH v5 11/14] cxl: Move read_cdat_data() to after media is ready Dave Jiang
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:47 UTC (permalink / raw)
  To: linux-cxl
  Cc: dan.j.williams, ira.weiny, vishal.l.verma, alison.schofield,
	Jonathan.Cameron

Move the enumeration of device capacity to cxl_port_probe() from
cxl_pci_probe(). The size and capacity information should be read
after cxl_await_media_ready() so the data is valid.

Fixes: 5e2411ae8071 ("cxl/memdev: Change cxl_mem to a more descriptive name")
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 drivers/cxl/pci.c  |    8 --------
 drivers/cxl/port.c |    8 ++++++++
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index ed39d133b70d..06324266eae8 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -707,14 +707,6 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (rc)
 		return rc;
 
-	rc = cxl_dev_state_identify(cxlds);
-	if (rc)
-		return rc;
-
-	rc = cxl_mem_create_range_info(cxlds);
-	if (rc)
-		return rc;
-
 	rc = cxl_alloc_irq_vectors(pdev);
 	if (rc)
 		return rc;
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index b474997cc7ee..0bdb9d73a389 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -180,6 +180,14 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 		return rc;
 	}
 
+	rc = cxl_dev_state_identify(cxlds);
+	if (rc)
+		return rc;
+
+	rc = cxl_mem_create_range_info(cxlds);
+	if (rc)
+		return rc;
+
 	rc = devm_cxl_enumerate_decoders(cxlhdm, &info);
 	if (rc)
 		return rc;



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 11/14] cxl: Move read_cdat_data() to after media is ready
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (9 preceding siblings ...)
  2023-05-08 20:47 ` [PATCH v5 10/14] cxl: Move identify and partition query from pci probe to port probe Dave Jiang
@ 2023-05-08 20:47 ` Dave Jiang
  2023-05-12 15:18   ` Jonathan Cameron
  2023-05-08 20:48 ` [PATCH v5 12/14] cxl: Store QTG IDs and related info to the CXL memory device context Dave Jiang
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:47 UTC (permalink / raw)
  To: linux-cxl
  Cc: dan.j.williams, ira.weiny, vishal.l.verma, alison.schofield,
	Jonathan.Cameron

CDAT data is only valid after the media is ready. Move read_cdat_data() to
after cxl_awai_media_read() is successful.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
 drivers/cxl/port.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 0bdb9d73a389..1d55c460e1ab 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -162,9 +162,6 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 	if (IS_ERR(cxlhdm))
 		return PTR_ERR(cxlhdm);
 
-	/* Cache the data early to ensure is_visible() works */
-	read_cdat_data(port);
-
 	get_device(&cxlmd->dev);
 	rc = devm_add_action_or_reset(&port->dev, schedule_detach, cxlmd);
 	if (rc)
@@ -180,6 +177,9 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 		return rc;
 	}
 
+	/* Cache the data early to ensure is_visible() works */
+	read_cdat_data(port);
+
 	rc = cxl_dev_state_identify(cxlds);
 	if (rc)
 		return rc;



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 12/14] cxl: Store QTG IDs and related info to the CXL memory device context
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (10 preceding siblings ...)
  2023-05-08 20:47 ` [PATCH v5 11/14] cxl: Move read_cdat_data() to after media is ready Dave Jiang
@ 2023-05-08 20:48 ` Dave Jiang
  2023-05-12 15:30   ` Jonathan Cameron
  2023-05-08 20:48 ` [PATCH v5 13/14] cxl: Export sysfs attributes for memory device QoS class Dave Jiang
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:48 UTC (permalink / raw)
  To: linux-cxl
  Cc: dan.j.williams, ira.weiny, vishal.l.verma, alison.schofield,
	Jonathan.Cameron

Once the QTG ID _DSM is executed successfully, the QTG ID is retrieved from
the return package. Create a list of entries in the cxl_memdev context and
store the QTG ID and the associated DPA range. This information can be
exposed to user space via sysfs in order to help region setup for
hot-plugged CXL memory devices.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>

---
v4:
- Remove unused qos_list from cxl_md
v3:
- Move back to QTG ID per partition
---
 drivers/cxl/core/mbox.c |    3 +++
 drivers/cxl/cxlmem.h    |   21 +++++++++++++++++++++
 drivers/cxl/port.c      |   36 ++++++++++++++++++++++++++++++++++++
 3 files changed, 60 insertions(+)

diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index f2addb457172..9c363060e5c1 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -1120,6 +1120,9 @@ struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
 	mutex_init(&cxlds->mbox_mutex);
 	mutex_init(&cxlds->event.log_lock);
 	cxlds->dev = dev;
+	INIT_LIST_HEAD(&cxlds->perf_list);
+	cxlds->ram_qos_class = CXL_QOS_CLASS_INVALID;
+	cxlds->pmem_qos_class = CXL_QOS_CLASS_INVALID;
 
 	return cxlds;
 }
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 001dabf0231b..9d77b7e420ce 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -5,6 +5,7 @@
 #include <uapi/linux/cxl_mem.h>
 #include <linux/cdev.h>
 #include <linux/uuid.h>
+#include <linux/node.h>
 #include "cxl.h"
 
 /* CXL 2.0 8.2.8.5.1.1 Memory Device Status Register */
@@ -215,6 +216,19 @@ struct cxl_event_state {
 	struct mutex log_lock;
 };
 
+/**
+ * struct perf_prop - performance property entry
+ * @list - list entry
+ * @dpa_range - range for DPA address
+ * @qos_class - QoS Class cookie
+ */
+struct perf_prop_entry {
+	struct list_head list;
+	struct range dpa_range;
+	u16 qos_class;
+	struct access_coordinate coord;
+};
+
 /**
  * struct cxl_dev_state - The driver device state
  *
@@ -251,6 +265,9 @@ struct cxl_event_state {
  * @serial: PCIe Device Serial Number
  * @event: event log driver state
  * @mbox_send: @dev specific transport for transmitting mailbox commands
+ * @ram_qos_class: QTG ID for volatile region
+ * @pmem_qos_class: QTG ID for persistent region
+ * @perf_list: performance data entries list
  *
  * See section 8.2.9.5.2 Capacity Configuration and Label Storage for
  * details on capacity parameters.
@@ -283,6 +300,10 @@ struct cxl_dev_state {
 	u64 next_volatile_bytes;
 	u64 next_persistent_bytes;
 
+	int ram_qos_class;
+	int pmem_qos_class;
+	struct list_head perf_list;
+
 	resource_size_t component_reg_phys;
 	u64 serial;
 
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 1d55c460e1ab..c8c37dd79ecc 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -113,6 +113,40 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port,
 	return 0;
 }
 
+static void cxl_memdev_set_qtg(struct cxl_dev_state *cxlds, struct list_head *dsmas_list)
+{
+	struct range pmem_range = {
+		.start = cxlds->pmem_res.start,
+		.end = cxlds->pmem_res.end,
+	};
+	struct range ram_range = {
+		.start = cxlds->ram_res.start,
+		.end = cxlds->ram_res.end,
+	};
+	struct perf_prop_entry *perf;
+	struct dsmas_entry *dent;
+
+	list_for_each_entry(dent, dsmas_list, list) {
+		perf = devm_kzalloc(cxlds->dev, sizeof(*perf), GFP_KERNEL);
+		if (!perf)
+			return;
+
+		perf->dpa_range = dent->dpa_range;
+		perf->qos_class = dent->qos_class;
+		perf->coord = dent->coord;
+		list_add_tail(&perf->list, &cxlds->perf_list);
+
+		if (resource_size(&cxlds->ram_res) &&
+		    range_contains(&ram_range, &dent->dpa_range) &&
+		    cxlds->ram_qos_class == CXL_QOS_CLASS_INVALID)
+			cxlds->ram_qos_class = dent->qos_class;
+		else if (resource_size(&cxlds->pmem_res) &&
+			 range_contains(&pmem_range, &dent->dpa_range) &&
+			 cxlds->pmem_qos_class == CXL_QOS_CLASS_INVALID)
+			cxlds->pmem_qos_class = dent->qos_class;
+	}
+}
+
 static int cxl_switch_port_probe(struct cxl_port *port)
 {
 	struct cxl_hdm *cxlhdm;
@@ -216,6 +250,8 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 			if (rc)
 				dev_dbg(&port->dev,
 					"Failed to do perf coord calculations.\n");
+			else
+				cxl_memdev_set_qtg(cxlds, &dsmas_list);
 		}
 
 		dsmas_list_destroy(&dsmas_list);



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 13/14] cxl: Export sysfs attributes for memory device QoS class
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (11 preceding siblings ...)
  2023-05-08 20:48 ` [PATCH v5 12/14] cxl: Store QTG IDs and related info to the CXL memory device context Dave Jiang
@ 2023-05-08 20:48 ` Dave Jiang
  2023-05-12 15:33   ` Jonathan Cameron
  2023-05-08 20:48 ` [PATCH v5 14/14] cxl/mem: Add debugfs output for QTG related data Dave Jiang
  2023-05-12 15:28 ` [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Jonathan Cameron
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:48 UTC (permalink / raw)
  To: linux-cxl
  Cc: Dan Williams, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield, Jonathan.Cameron

Export qos_class sysfs attributes for the CXL memory device. The QoS clas
should show up as /sys/bus/cxl/devices/memX/ram/qos_class for the volatile
partition and /sys/bus/cxl/devices/memX/pmem/qos_class for the persistent
partition. The QTG ID is retrieved via _DSM after supplying the
calculated bandwidth and latency for the entire CXL path from device to
the CPU. This ID is used to match up to the root decoder QoS class to
determine which CFMWS the memory range of a hotplugged CXL mem device
should be assigned under.

While there may be multiple DSMAS exported by the device CDAT, the driver
will only expose the first QTG ID per partition in sysfs for now. In the
future when multiple QTG IDs are necessary, they can be exposed. [1]

[1]: https://lore.kernel.org/linux-cxl/167571650007.587790.10040913293130712882.stgit@djiang5-mobl3.local/T/#md2a47b1ead3e1ba08f50eab29a4af1aed1d215ab

Suggested-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>

---
v5:
- Change qtg_id to qos_class
v4:
- Change kernel version for documentation to v6.5
v3:
- Expand description of qtg_id. (Alison)
---
 Documentation/ABI/testing/sysfs-bus-cxl |   32 +++++++++++++++++++++++++++++++
 drivers/cxl/core/memdev.c               |   26 +++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
index 2f24e42ef36d..c13ae49dd9aa 100644
--- a/Documentation/ABI/testing/sysfs-bus-cxl
+++ b/Documentation/ABI/testing/sysfs-bus-cxl
@@ -28,6 +28,22 @@ Description:
 		Payload in the CXL-2.0 specification.
 
 
+What:		/sys/bus/cxl/devices/memX/ram/qos_class
+Date:		May, 2023
+KernelVersion:	v6.5
+Contact:	linux-cxl@vger.kernel.org
+Description:
+		(RO) For CXL host platforms that support "QoS Telemmetry"
+		this attribute conveys a platform specific cookie that
+		identifies a QoS performance class for the volatile
+		partition of the CXL mem device. This class-id can be
+		compared against a similar "qos_class" published for
+		a root decoder. While it is not required that the endpoints
+		map their local memory-class to a matching platform class,
+		mismatches are not recommended and there are platform specific
+		side-effects that may result.
+
+
 What:		/sys/bus/cxl/devices/memX/pmem/size
 Date:		December, 2020
 KernelVersion:	v5.12
@@ -38,6 +54,22 @@ Description:
 		Payload in the CXL-2.0 specification.
 
 
+What:		/sys/bus/cxl/devices/memX/pmem/qos_class
+Date:		May, 2023
+KernelVersion:	v6.5
+Contact:	linux-cxl@vger.kernel.org
+Description:
+		(RO) For CXL host platforms that support "QoS Telemmetry"
+		this attribute conveys a platform specific cookie that
+		identifies a QoS performance class for the persistent
+		partition of the CXL mem device. This class-id can be
+		compared against a similar "qos_class" published for
+		a root decoder. While it is not required that the endpoints
+		map their local memory-class to a matching platform class,
+		mismatches are not recommended and there are platform specific
+		side-effects that may result.
+
+
 What:		/sys/bus/cxl/devices/memX/serial
 Date:		January, 2022
 KernelVersion:	v5.18
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 28a05f2fe32d..8e183bef33e8 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -76,6 +76,18 @@ static ssize_t ram_size_show(struct device *dev, struct device_attribute *attr,
 static struct device_attribute dev_attr_ram_size =
 	__ATTR(size, 0444, ram_size_show, NULL);
 
+static ssize_t ram_qos_class_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
+
+	return sysfs_emit(buf, "%d\n", cxlds->ram_qos_class);
+}
+
+static struct device_attribute dev_attr_ram_qos_class =
+	__ATTR(qos_class, 0444, ram_qos_class_show, NULL);
+
 static ssize_t pmem_size_show(struct device *dev, struct device_attribute *attr,
 			      char *buf)
 {
@@ -89,6 +101,18 @@ static ssize_t pmem_size_show(struct device *dev, struct device_attribute *attr,
 static struct device_attribute dev_attr_pmem_size =
 	__ATTR(size, 0444, pmem_size_show, NULL);
 
+static ssize_t pmem_qos_class_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
+
+	return sysfs_emit(buf, "%d\n", cxlds->pmem_qos_class);
+}
+
+static struct device_attribute dev_attr_pmem_qos_class =
+	__ATTR(qos_class, 0444, pmem_qos_class_show, NULL);
+
 static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
@@ -117,11 +141,13 @@ static struct attribute *cxl_memdev_attributes[] = {
 
 static struct attribute *cxl_memdev_pmem_attributes[] = {
 	&dev_attr_pmem_size.attr,
+	&dev_attr_pmem_qos_class.attr,
 	NULL,
 };
 
 static struct attribute *cxl_memdev_ram_attributes[] = {
 	&dev_attr_ram_size.attr,
+	&dev_attr_ram_qos_class.attr,
 	NULL,
 };
 



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v5 14/14] cxl/mem: Add debugfs output for QTG related data
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (12 preceding siblings ...)
  2023-05-08 20:48 ` [PATCH v5 13/14] cxl: Export sysfs attributes for memory device QoS class Dave Jiang
@ 2023-05-08 20:48 ` Dave Jiang
  2023-05-12 15:36   ` Jonathan Cameron
  2023-05-12 15:28 ` [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Jonathan Cameron
  14 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-08 20:48 UTC (permalink / raw)
  To: linux-cxl
  Cc: Dan Williams, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield, Jonathan.Cameron

Add debugfs output to /sys/kernel/debug/cxl/memX/qtgmap
The debugfs attribute will dump out all the DSMAS ranges and the associated
QTG ID exported by the CXL device CDAT.

Suggested-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>

---
v4:
- Use cxlds->qos_list instead of the stray cxlmd->qos_list
---
 Documentation/ABI/testing/debugfs-cxl |   11 +++++++++++
 MAINTAINERS                           |    1 +
 drivers/cxl/mem.c                     |   17 +++++++++++++++++
 3 files changed, 29 insertions(+)
 create mode 100644 Documentation/ABI/testing/debugfs-cxl

diff --git a/Documentation/ABI/testing/debugfs-cxl b/Documentation/ABI/testing/debugfs-cxl
new file mode 100644
index 000000000000..0f36eeb7e59b
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-cxl
@@ -0,0 +1,11 @@
+What:		/sys/kernel/debug/cxl/memX/qtg_map
+Date:		Mar, 2023
+KernelVersion:	v6.4
+Contact:	linux-cxl@vger.kernel.org
+Description:
+		(RO) Entries of all Device Physical Address (DPA) ranges
+		provided by the device Coherent Device Attributes Table (CDAT)
+		Device Scoped Memory Affinity Structure (DSMAS) entries with
+		the matching QoS Throttling Group (QTG) id calculated from the
+		latency and bandwidth of the CXL path from the memory device
+		to the CPU.
diff --git a/MAINTAINERS b/MAINTAINERS
index fd8c4c560f8d..256e4e57017c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5171,6 +5171,7 @@ M:	Ben Widawsky <bwidawsk@kernel.org>
 M:	Dan Williams <dan.j.williams@intel.com>
 L:	linux-cxl@vger.kernel.org
 S:	Maintained
+F:	Documentation/ABI/testing/debugfs-cxl
 F:	drivers/cxl/
 F:	include/uapi/linux/cxl_mem.h
 
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index 39c4b54f0715..587e261a7f76 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -45,6 +45,22 @@ static int cxl_mem_dpa_show(struct seq_file *file, void *data)
 	return 0;
 }
 
+static int cxl_mem_qtg_show(struct seq_file *file, void *data)
+{
+	struct device *dev = file->private;
+	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
+	struct perf_prop_entry *perf;
+
+	list_for_each_entry(perf, &cxlds->perf_list, list) {
+		seq_printf(file, "%08llx-%08llx : QoS Class: %u\n",
+			   perf->dpa_range.start, perf->dpa_range.end,
+			   perf->qos_class);
+	}
+
+	return 0;
+}
+
 static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
 				 struct cxl_dport *parent_dport)
 {
@@ -117,6 +133,7 @@ static int cxl_mem_probe(struct device *dev)
 
 	dentry = cxl_debugfs_create_dir(dev_name(dev));
 	debugfs_create_devm_seqfile(dev, "dpamem", dentry, cxl_mem_dpa_show);
+	debugfs_create_devm_seqfile(dev, "qtgmap", dentry, cxl_mem_qtg_show);
 	rc = devm_add_action_or_reset(dev, remove_debugfs, dentry);
 	if (rc)
 		return rc;



^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 01/14] cxl: Add callback to parse the DSMAS subtables from CDAT
  2023-05-08 20:46 ` [PATCH v5 01/14] cxl: Add callback to parse the DSMAS subtables from CDAT Dave Jiang
@ 2023-05-12 14:26   ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 14:26 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:46:59 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> Provide a callback function to the CDAT parser in order to parse the Device
> Scoped Memory Affinity Structure (DSMAS). Each DSMAS structure contains the
> DPA range and its associated attributes in each entry. See the CDAT
> specification for details. The device handle and the DPA range is saved and
> to be associated with the DSLBIS locality data when the DSLBIS entries are
> parsed. The list is a local list. When the total path performance data is
> calculated and storred this list can be discarded.
> 
> Coherent Device Attribute Table 1.03 2.1 Device Scoped memory Affinity
> Structure (DSMAS)
> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Ah. I failed to read cover letter of the precursor series that said patch 4
was there as an example.  Please carry forward comments from there.

> ---
> v5:
> - Update commit log to indicate what list is used for. (Jonathan, Dan)
> - Use acpi_table_parse_cdat()
> - Isolate cdat code behind CONFIG_ACPI
> v3:
> - Add spec section number. (Alison)
> - Remove cast from void *. (Alison)
> - Refactor cxl_port_probe() block. (Alison)
> - Move CDAT parse to cxl_endpoint_port_probe()
> 
> v2:
> - Add DSMAS table size check. (Lukas)
> - Use local DSMAS header for LE handling.
> - Remove dsmas lock. (Jonathan)
> - Fix handle size (Jonathan)
> - Add LE to host conversion for DSMAS address and length.
> - Make dsmas_list local
> ---
>  drivers/cxl/core/Makefile |    1 +
>  drivers/cxl/core/cdat.c   |   40 ++++++++++++++++++++++++++++++++++++++++
>  drivers/cxl/cxl.h         |   18 ++++++++++++++++++
>  drivers/cxl/port.c        |   22 ++++++++++++++++++++++
>  4 files changed, 81 insertions(+)
>  create mode 100644 drivers/cxl/core/cdat.c
> 
> diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile
> index ca4ae31d8f57..98ddfd110f9b 100644
> --- a/drivers/cxl/core/Makefile
> +++ b/drivers/cxl/core/Makefile
> @@ -12,5 +12,6 @@ cxl_core-y += memdev.o
>  cxl_core-y += mbox.o
>  cxl_core-y += pci.o
>  cxl_core-y += hdm.o
> +cxl_core-$(CONFIG_ACPI) += cdat.o
>  cxl_core-$(CONFIG_TRACING) += trace.o
>  cxl_core-$(CONFIG_CXL_REGION) += region.o
> diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
> new file mode 100644
> index 000000000000..61979f0789aa
> --- /dev/null
> +++ b/drivers/cxl/core/cdat.c
> @@ -0,0 +1,40 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/* Copyright(c) 2023 Intel Corporation. All rights reserved. */
> +#include <linux/acpi.h>
> +#include "cxlpci.h"
> +#include "cxl.h"
> +
> +static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
> +			      const unsigned long end)
> +{
> +	struct acpi_cdat_dsmas *dsmas = (struct acpi_cdat_dsmas *)header;
> +	struct list_head *dsmas_list = arg;
> +	struct dsmas_entry *dent;
> +	u16 len;
> +
> +	len = le16_to_cpu((__force __le16)dsmas->header.length);
> +	if (len != sizeof(*dsmas) || (unsigned long)header + len > end) {
> +		pr_warn("Malformed DSMAS table length: (%lu:%u)\n",
> +			(unsigned long)sizeof(*dsmas), len);
> +		return -EINVAL;
> +	}
> +
> +	dent = kzalloc(sizeof(*dent), GFP_KERNEL);
> +	if (!dent)
> +		return -ENOMEM;
> +
> +	dent->handle = dsmas->dsmad_handle;
> +	dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address);
> +	dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) +
> +			      le64_to_cpu((__force __le64)dsmas->dpa_length) - 1;
> +	list_add_tail(&dent->list, dsmas_list);
> +
> +	return 0;
> +}
> +
> +int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list)
> +{
> +	return acpi_table_parse_cdat(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler,
> +				     list, port->cdat.table);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_cdat_endpoint_process, CXL);
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 4577d808ac6d..dda7238b47f5 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -7,6 +7,7 @@
>  #include <linux/libnvdimm.h>
>  #include <linux/bitfield.h>
>  #include <linux/bitops.h>
> +#include <linux/list.h>
>  #include <linux/log2.h>
>  #include <linux/io.h>
>  
> @@ -791,6 +792,23 @@ static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
>  }
>  #endif
>  
> +/* CDAT related bits */
> +struct dsmas_entry {
> +	struct list_head list;
> +	struct range dpa_range;
> +	u8 handle;
> +};
> +
> +#ifdef CONFIG_ACPI
> +int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list);
> +#else
> +static inline int cxl_cdat_endpoint_process(struct cxl_port *port,
> +					    struct list_head *list)
> +{
> +	return -EOPNOTSUPP;
> +}
> +#endif
> +
>  /*
>   * Unit test builds overrides this to __weak, find the 'strong' version
>   * of these symbols in tools/testing/cxl/.
> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
> index a49f5eb149f1..da023feaa6e2 100644
> --- a/drivers/cxl/port.c
> +++ b/drivers/cxl/port.c
> @@ -57,6 +57,16 @@ static int discover_region(struct device *dev, void *root)
>  	return 0;
>  }
>  
> +static void dsmas_list_destroy(struct list_head *dsmas_list)
> +{
> +	struct dsmas_entry *dentry, *n;
> +
> +	list_for_each_entry_safe(dentry, n, dsmas_list, list) {
> +		list_del(&dentry->list);
> +		kfree(dentry);
> +	}
> +}
> +
>  static int cxl_switch_port_probe(struct cxl_port *port)
>  {
>  	struct cxl_hdm *cxlhdm;
> @@ -131,6 +141,18 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
>  	device_for_each_child(&port->dev, root, discover_region);
>  	put_device(&root->dev);
>  
> +	if (port->cdat.table) {
> +		LIST_HEAD(dsmas_list);
> +
> +		rc = cxl_cdat_endpoint_process(port, &dsmas_list);
> +		if (rc < 0)
> +			dev_dbg(&port->dev, "Failed to parse CDAT: %d\n", rc);
> +
> +		/* Performance data processing */
> +
> +		dsmas_list_destroy(&dsmas_list);
> +	}
> +
>  	return 0;
>  }
>  
> 
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 02/14] cxl: Add callback to parse the DSLBIS subtable from CDAT
  2023-05-08 20:47 ` [PATCH v5 02/14] cxl: Add callback to parse the DSLBIS subtable " Dave Jiang
@ 2023-05-12 14:33   ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 14:33 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:47:05 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> Provide a callback to parse the Device Scoped Latency and Bandwidth
> Information Structure (DSLBIS) in the CDAT structures. The DSLBIS
> contains the bandwidth and latency information that's tied to a DSMAS
> handle. The driver will retrieve the read and write latency and
> bandwidth associated with the DSMAS which is tied to a DPA range.
> 
> Coherent Device Attribute Table 1.03 2.1 Device Scoped Latency and
> Bandwidth Information Structure (DSLBIS)
> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
A few trivial suggestions inline. Change them if you like. I don't mind that much.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> 
> ---
> v5:
> - Remove macro for common headers. (Jonathan)
> - Use acpi_table_parse_cdat().
> - Remove unlikely(). (Dan)
> v3:
> - Added spec section in commit header. (Alison)
> - Remove void * recast. (Alison)
> - Rework comment. (Alison)
> - Move CDAT parse to cxl_endpoint_port_probe()
> - Convert to use 'struct node_hmem_attrs'
> 
> v2:
> - Add size check to DSLIBIS table. (Lukas)
> - Remove unnecessary entry type check. (Jonathan)
> - Move data_type check to after match. (Jonathan)
> - Skip unknown data type. (Jonathan)
> - Add overflow check for unit multiply. (Jonathan)
> - Use dev_warn() when entries parsing fail. (Jonathan)
> ---
>  drivers/cxl/core/cdat.c |   90 ++++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/cxl/cxl.h       |    2 +
>  2 files changed, 90 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
> index 61979f0789aa..6e14d04c0453 100644
> --- a/drivers/cxl/core/cdat.c
> +++ b/drivers/cxl/core/cdat.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  /* Copyright(c) 2023 Intel Corporation. All rights reserved. */
>  #include <linux/acpi.h>
> +#include <linux/overflow.h>
>  #include "cxlpci.h"
>  #include "cxl.h"
>  
> @@ -32,9 +33,94 @@ static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
>  	return 0;
>  }
>  
> +static void cxl_access_coordinate_set(struct access_coordinate *coord,
> +				      int access, unsigned int val)
> +{
> +	switch (access) {
> +	case ACPI_HMAT_ACCESS_LATENCY:
> +		coord->read_latency = val;
> +		coord->write_latency = val;
> +		break;
> +	case ACPI_HMAT_READ_LATENCY:
> +		coord->read_latency = val;
> +		break;
> +	case ACPI_HMAT_WRITE_LATENCY:
> +		coord->write_latency = val;
> +		break;
> +	case ACPI_HMAT_ACCESS_BANDWIDTH:
> +		coord->read_bandwidth = val;
> +		coord->write_bandwidth = val;
> +		break;
> +	case ACPI_HMAT_READ_BANDWIDTH:
> +		coord->read_bandwidth = val;
> +		break;
> +	case ACPI_HMAT_WRITE_BANDWIDTH:
> +		coord->write_bandwidth = val;
> +		break;
> +	}
> +}
> +
> +static int cdat_dslbis_handler(union acpi_subtable_headers *header, void *arg,
> +			       const unsigned long end)
> +{
> +	struct acpi_cdat_dslbis *dslbis = (struct acpi_cdat_dslbis *)header;

As for DSMAS, cast from the more obviously appropriate &header->cdat

> +	struct list_head *dsmas_list = arg;
> +	struct dsmas_entry *dent;
> +	u16 len;
> +
> +	len = le16_to_cpu((__force __le16)dslbis->header.length);
> +	if (len != sizeof(*dslbis) || (unsigned long)header + len > end) {
> +		pr_warn("Malformed DSLBIS table length: (%lu:%u)\n",
> +			(unsigned long)sizeof(*dslbis), len);
> +		return -EINVAL;
> +	}
> +
> +	/* Skip unrecognized data type */
> +	if (dslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH)
> +		return 0;
> +
> +	list_for_each_entry(dent, dsmas_list, list) {
> +		u64 val;
> +		int rc;
> +
> +		if (dslbis->handle != dent->handle)
> +			continue;
> +
> +		/* Not a memory type, skip */
> +		if ((dslbis->flags & ACPI_HMAT_MEMORY_HIERARCHY) !=
> +		    ACPI_HMAT_MEMORY)
> +			return 0;
> +
> +		rc = check_mul_overflow(le64_to_cpu((__force __le64)dslbis->entry_base_unit),
> +					le16_to_cpu((__force __le16)dslbis->entry[0]), &val);
> +		if (rc)
> +			pr_warn("DSLBIS value overflowed.\n");
> +
> +		cxl_access_coordinate_set(&dent->coord, dslbis->data_type, val);
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
>  int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list)
>  {
> -	return acpi_table_parse_cdat(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler,
> -				     list, port->cdat.table);
> +	int rc;
> +
> +	rc = acpi_table_parse_cdat(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler,
> +				   list, port->cdat.table);
> +	if (rc <= 0) {
> +		if (rc == 0)
> +			rc = -ENOENT;
> +		return rc;
> +	}

	if (rc < 0)
		return rc;
	if (rc == 0)
		return -ENOENT;

is a tiny bit simpler.

> +
> +	rc = acpi_table_parse_cdat(ACPI_CDAT_TYPE_DSLBIS,
> +				   cdat_dslbis_handler,
> +				   list, port->cdat.table);
> +	if (rc == 0)
> +		rc = -ENOENT;

I'd burn a few lines of code for readability rather than fudging the
return value.

	if (rc < 0)
		return rc;
	if (rc == 0)
		return -ENOENT;

	return 0;
> +
> +	return rc;
>  }
>  EXPORT_SYMBOL_NS_GPL(cxl_cdat_endpoint_process, CXL);
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index dda7238b47f5..ca3d0d74f2e5 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -8,6 +8,7 @@
>  #include <linux/bitfield.h>
>  #include <linux/bitops.h>
>  #include <linux/list.h>
> +#include <linux/node.h>
>  #include <linux/log2.h>
>  #include <linux/io.h>
>  
> @@ -797,6 +798,7 @@ struct dsmas_entry {
>  	struct list_head list;
>  	struct range dpa_range;
>  	u8 handle;
> +	struct access_coordinate coord;
>  };
>  
>  #ifdef CONFIG_ACPI
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 03/14] cxl: Add callback to parse the SSLBIS subtable from CDAT
  2023-05-08 20:47 ` [PATCH v5 03/14] cxl: Add callback to parse the SSLBIS " Dave Jiang
@ 2023-05-12 14:41   ` Jonathan Cameron
  2023-05-16 17:49     ` Dave Jiang
  0 siblings, 1 reply; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 14:41 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:47:11 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> 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>

I'm disagreeing with myself again. Some comments inline based
on a fresh read.

> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> 
> ---
> v5:
> - Store data to cxl_dport directly instead. (Dan)
> - Use acpi_table_parse_cdat().
> v3:
> - Add spec section in commit header (Alison)
> - Move CDAT parse to cxl_switch_port_probe()
> - Use 'struct node_hmem_attrs'
> ---
>  drivers/cxl/core/cdat.c |   88 +++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/cxl/cxl.h       |    8 ++++
>  drivers/cxl/port.c      |   12 ++++++
>  include/acpi/actbl1.h   |    3 ++
>  4 files changed, 110 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
> index 6e14d04c0453..37b135c900d5 100644
> --- a/drivers/cxl/core/cdat.c
> +++ b/drivers/cxl/core/cdat.c
> @@ -124,3 +124,91 @@ int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list)
>  	return rc;
>  }
>  EXPORT_SYMBOL_NS_GPL(cxl_cdat_endpoint_process, CXL);
> +
> +static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg,
> +			       const unsigned long end)
> +{
> +	struct acpi_cdat_sslbis *sslbis = (struct acpi_cdat_sslbis *)header;
> +	struct acpi_cdat_sslbe *entry;
> +	struct cxl_port *port = arg;
> +	struct device *dev = &port->dev;
> +	int remain, entries, i;
> +	u16 len;
> +
> +	len = le16_to_cpu((__force __le16)sslbis->header.length);
> +	remain = len - sizeof(*sslbis);
> +	if (!remain || remain % sizeof(*entry) ||
> +	    (unsigned long)header + len > end) {
> +		dev_warn(dev, "Malformed SSLBIS table length: (%u)\n", len);
> +		return -EINVAL;
> +	}
> +
> +	/* Unrecognized data type, we can skip */
> +	if (sslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH)
> +		return 0;
> +
> +	entries = remain / sizeof(*entry);
> +	entry = (struct acpi_cdat_sslbe *)((unsigned long)header + sizeof(*sslbis));

That's a little nasty to follow.  Perhaps.
	
	entry = (struct acpi_cdat_sslbe *)(sslbis + 1);

Bonus points if we can just use a variable length entry on the end of
struct acpi_cdat_sslbis. Might break some other locations but would make
this one nicer.

> +
> +	for (i = 0; i < entries; i++) {
> +		u16 x = le16_to_cpu(entry->portx_id);
> +		u16 y = le16_to_cpu(entry->porty_id);
> +		struct cxl_dport *dport;
> +		unsigned long index;
> +		u16 dsp_id;
> +		u64 val;
> +
> +		switch (x) {
> +		case ACPI_CDAT_SSLBIS_US_PORT:
> +			dsp_id = y;
> +			break;
> +		case ACPI_CDAT_SSLBIS_ANY_PORT:
> +			switch (y) {
> +			case ACPI_CDAT_SSLBIS_US_PORT:
> +				dsp_id = x;
> +				break;
> +			case ACPI_CDAT_SSLBIS_ANY_PORT:
> +				dsp_id = ACPI_CDAT_SSLBIS_ANY_PORT;
> +				break;
> +			default:
> +				dsp_id = y;
> +				break;
> +			}
> +			break;
> +		default:
> +			dsp_id = x;
> +			break;
> +		}
> +
> +		if (check_mul_overflow(le64_to_cpu(sslbis->entry_base_unit),
> +				       le16_to_cpu(entry->latency_or_bandwidth),
> +				       &val))
> +			dev_warn(dev, "SSLBIS value overflowed!\n");
> +
> +		xa_for_each(&port->dports, index, dport) {
> +			if (dsp_id == ACPI_CDAT_SSLBIS_ANY_PORT ||
> +			    dsp_id == dport->port_id)
> +				cxl_access_coordinate_set(&dport->coord,
> +							  sslbis->data_type,
> +							  val);
> +		}
> +
> +		entry++;
> +	}
> +
> +	return 0;
> +}
> +
> +int cxl_cdat_switch_process(struct cxl_port *port)
> +{
> +	int rc;
> +
> +	rc = acpi_table_parse_cdat(ACPI_CDAT_TYPE_SSLBIS,
> +				   cdat_sslbis_handler,
> +				   port, port->cdat.table);
> +	if (rc == 0)
> +		rc = -ENOENT;

I'm bored of this pattern now so hide it...

Howabout

	acpi_table_parse_cdat_fail_emtpy() that handles the rc
rewrite internally. (with a better name).

Gets rid of all this boilerplate.



> +
> +	return rc;
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_cdat_switch_process, CXL);
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index ca3d0d74f2e5..3e8020e0a132 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -600,6 +600,7 @@ cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
>   * @rcrb: base address for the Root Complex Register Block
>   * @rch: Indicate whether this dport was enumerated in RCH or VH mode
>   * @port: reference to cxl_port that contains this downstream port
> + * @coord: access coordinates (performance) for switch from CDAT
>   */
>  struct cxl_dport {
>  	struct device *dport;
> @@ -608,6 +609,7 @@ struct cxl_dport {
>  	resource_size_t rcrb;
>  	bool rch;
>  	struct cxl_port *port;
> +	struct access_coordinate coord;
>  };
>  
>  /**
> @@ -803,12 +805,18 @@ struct dsmas_entry {
>  
>  #ifdef CONFIG_ACPI
>  int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list);
> +int cxl_cdat_switch_process(struct cxl_port *port);
>  #else
>  static inline int cxl_cdat_endpoint_process(struct cxl_port *port,
>  					    struct list_head *list)
>  {
>  	return -EOPNOTSUPP;
>  }
> +
> +static inline int cxl_cdat_switch_process(struct cxl_port *port)
> +{
> +	return -EOPNOTSUPP;
> +}
>  #endif
>  
>  /*
> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
> index da023feaa6e2..c5a24b75bf03 100644
> --- a/drivers/cxl/port.c
> +++ b/drivers/cxl/port.c
> @@ -86,7 +86,17 @@ static int cxl_switch_port_probe(struct cxl_port *port)
>  	if (IS_ERR(cxlhdm))
>  		return PTR_ERR(cxlhdm);
>  
> -	return devm_cxl_enumerate_decoders(cxlhdm, NULL);
> +	rc = devm_cxl_enumerate_decoders(cxlhdm, NULL);
> +	if (rc < 0)
> +		return rc;
> +
> +	if (port->cdat.table) {
> +		rc = cxl_cdat_switch_process(port);
> +		if (rc < 0)
> +			dev_warn(&port->dev, "Failed to parse SSLBIS: %d\n", rc);
> +	}
> +
> +	return 0;
>  }
>  
>  static int cxl_endpoint_port_probe(struct cxl_port *port)
> diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
> index 8ea7e5d64bc1..82def138a7e4 100644
> --- a/include/acpi/actbl1.h
> +++ b/include/acpi/actbl1.h
> @@ -419,6 +419,9 @@ struct acpi_cdat_sslbis {
>  	u64 entry_base_unit;
>  };
>  
> +#define ACPI_CDAT_SSLBIS_US_PORT	0x0100
> +#define ACPI_CDAT_SSLBIS_ANY_PORT	0xffff
> +
>  /* Sub-subtable for above, sslbe_entries field */
>  
>  struct acpi_cdat_sslbe {
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 04/14] cxl: Add support for _DSM Function for retrieving QTG ID
  2023-05-08 20:47 ` [PATCH v5 04/14] cxl: Add support for _DSM Function for retrieving QTG ID Dave Jiang
@ 2023-05-12 14:50   ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 14:50 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:47:17 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> CXL spec v3.0 9.17.3 CXL Root Device Specific Methods (_DSM)
> 
> Add support to retrieve QTG ID via ACPI _DSM call. The _DSM call requires
> an input of an ACPI package with 4 dwords (read latency, write latency,
> read bandwidth, write bandwidth). The call returns a package with 1 WORD
> that provides the max supported QTG ID and a package that may contain 0 or
> more WORDs as the recommended QTG IDs in the recommended order.
> 
> Create a cxl_root container for the root cxl_port and provide a callback
> ->get_qos_class() in order to retrieve the QoS class. For the ACPI case,  
> the _DSM helper is used to retrieve the QTG ID and returned. A
> devm_cxl_add_root() function is added for root port setup and registration
> of the cxl_root callback operation(s).
> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Trivial comment inline.
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> 
> ---
> v5:
> - Make the helper a callback for the CXL root. (Dan)
> - Drop the addition of core/acpi.c. (Dan)
> - Add endiness handling. (Jonathan)
> - Refactor error exits. (Jonathan)
> - Update evaluate function description. (Jonathan)
> - Make uuid static. (Dan)
> v2:
> - Reorder var declaration and use C99 style. (Jonathan)
> - Allow >2 ACPI objects in package for future expansion. (Jonathan)
> - Check QTG IDs against MAX QTG ID provided by output package. (Jonathan)
> ---
>  drivers/cxl/acpi.c      |  126 ++++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/cxl/core/port.c |   41 +++++++++++++--
>  drivers/cxl/cxl.h       |   33 ++++++++++++
>  3 files changed, 192 insertions(+), 8 deletions(-)
> 

> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 3e8020e0a132..16fc14d43aa4 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -586,6 +586,30 @@ struct cxl_port {
>  	bool cdat_available;
>  };
>  
> +struct qtg_dsm_input;
> +
> +struct cxl_root_ops {
> +	int (*get_qos_class)(struct cxl_port *root_port,
> +			     struct qtg_dsm_input *input);
> +};
> +
> +/**
> + * struct cxl_root - logical collection of root cxl_port items
> + *
> + * @port: cxl_port member
> + * @ops: cxl root operations
> + */
> +struct cxl_root {
> +	struct cxl_port port;
> +	const struct cxl_root_ops *ops;
> +};
> +
> +static inline struct cxl_root *
> +to_cxl_root(const struct cxl_port *port)
> +{
> +	return container_of(port, struct cxl_root, port);
> +}
> +
>  static inline struct cxl_dport *
>  cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
>  {
> @@ -665,6 +689,8 @@ struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port);
>  struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
>  				   resource_size_t component_reg_phys,
>  				   struct cxl_dport *parent_dport);
> +struct cxl_root *devm_cxl_add_root(struct device *host,
> +				   const struct cxl_root_ops *ops);
>  struct cxl_port *find_cxl_root(struct cxl_port *port);
>  int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
>  void cxl_bus_rescan(void);
> @@ -819,6 +845,13 @@ static inline int cxl_cdat_switch_process(struct cxl_port *port)
>  }
>  #endif
>  
> +struct qtg_dsm_input {
> +	__le32 rd_lat;
> +	__le32 wr_lat;
> +	__le32 rd_bw;
> +	__le32 wr_bw;
> +};

Could just move this up so forwards def not needed,

> +
>  /*
>   * Unit test builds overrides this to __weak, find the 'strong' version
>   * of these symbols in tools/testing/cxl/.
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 06/14] cxl: Store the access coordinates for the generic ports
  2023-05-08 20:47 ` [PATCH v5 06/14] cxl: Store the access coordinates for the generic ports Dave Jiang
@ 2023-05-12 14:59   ` Jonathan Cameron
  2023-05-16 20:58     ` Dave Jiang
  0 siblings, 1 reply; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 14:59 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:47:29 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> Each CXL host bridge is represented by an ACPI0016 device. A generic port
> device handle that is an ACPI device is represented by a string of
> ACPI0016 device HID and UID. Create a device handle from the ACPI device
> and retrieve the access coordinates from the stored memory targets. The
> access coordinates are stored under the cxl_dport that is associated with
> the CXL host bridge.
> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> ---
>  drivers/cxl/acpi.c |   28 ++++++++++++++++++++++++++++
>  drivers/cxl/cxl.h  |    2 ++
>  2 files changed, 30 insertions(+)
> 
> diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
> index f9b35e8fe810..675a4f423f4b 100644
> --- a/drivers/cxl/acpi.c
> +++ b/drivers/cxl/acpi.c
> @@ -537,8 +537,26 @@ static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
>  	return 0;
>  }
>  
> +static int get_genport_coordinates(struct device *dev, struct cxl_dport *dport)
> +{
> +	struct acpi_device *hb = to_cxl_host_bridge(NULL, dev);
> +	u8 handle[ACPI_SRAT_DEVICE_HANDLE_SIZE] = { 0 };
> +	int rc;
> +
> +	/* ACPI spec 6.5 tABLE 5.65 */

tABLE?

> +	memcpy(handle, acpi_device_hid(hb), 8);
> +	memcpy(&handle[8], acpi_device_uid(hb), 4);
> +
> +	rc = acpi_get_genport_coordinates(handle, dport->genport_coord);
> +	if (rc)
> +		return rc;
> +
> +	return 0;
> +}
> +
>  static int add_host_bridge_dport(struct device *match, void *arg)
>  {
> +	int ret;
>  	acpi_status rc;
>  	struct device *bridge;
>  	unsigned long long uid;
> @@ -594,6 +612,16 @@ static int add_host_bridge_dport(struct device *match, void *arg)
>  	if (IS_ERR(dport))
>  		return PTR_ERR(dport);
>  
> +	dport->genport_coord = devm_kzalloc(dport->dport,
> +					    sizeof(*dport->genport_coord),
> +					    GFP_KERNEL);

It's pretty small - worth allocating separately?

Maybe add something on why to the patch description if there is another reason
for this dance.

> +	if (!dport->genport_coord)
> +		return -ENOMEM;
> +
> +	ret = get_genport_coordinates(match, dport);
> +	if (ret)
> +		dev_dbg(match, "Failed to get generic port perf coordinates.\n");
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index c1e2c3703a63..033b822a20f2 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -626,6 +626,7 @@ cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
>   * @rcrb: base address for the Root Complex Register Block
>   * @rch: Indicate whether this dport was enumerated in RCH or VH mode
>   * @port: reference to cxl_port that contains this downstream port
> + * @genport_coord: access coordinates (performance) from ACPI generic port
>   * @coord: access coordinates (performance) for switch from CDAT
>   * @link_latency: calculated PCIe downstream latency
>   */
> @@ -636,6 +637,7 @@ struct cxl_dport {
>  	resource_size_t rcrb;
>  	bool rch;
>  	struct cxl_port *port;
> +	struct access_coordinate *genport_coord;
>  	struct access_coordinate coord;
>  	long link_latency;
>  };
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 07/14] cxl: Add helper function that calculate performance data for downstream ports
  2023-05-08 20:47 ` [PATCH v5 07/14] cxl: Add helper function that calculate performance data for downstream ports Dave Jiang
@ 2023-05-12 15:05   ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 15:05 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:47:36 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> The CDAT information from the switch, Switch Scoped Latency and Bandwidth
> Information Strucutre (SSLBIS), is parsed and stored under a cxl_dport
> based on the correlated downstream port id from the SSLBIS entry. Walk
> the entire CXL port paths and collect all the performance data. Also
> pick up the link latency number that's stored under the dports. The
> entire path PCIe bandwidth can be retrieved using the
> pcie_bandwidth_available() call.
> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Trivial comment inline. Otherwise LGTM

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> ---
>  drivers/cxl/core/port.c |   69 +++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/cxl/cxl.h       |    3 ++
>  2 files changed, 72 insertions(+)
> 
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index e4f75847b851..1111a3cebc8e 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -9,6 +9,7 @@
>  #include <linux/pci.h>
>  #include <linux/slab.h>
>  #include <linux/idr.h>
> +#include <linux/node.h>
>  #include <cxlmem.h>
>  #include <cxlpci.h>
>  #include <cxl.h>
> @@ -1950,6 +1951,74 @@ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd)
>  }
>  EXPORT_SYMBOL_NS_GPL(schedule_cxl_memdev_detach, CXL);
>  
> +static void combine_coordinates(struct access_coordinate *c1,
> +				struct access_coordinate *c2)
> +{
> +		if (c2->write_bandwidth)
> +			c1->write_bandwidth = min_t(unsigned int,
> +						    c1->write_bandwidth,
> +						    c2->write_bandwidth);

min() fine here I think. All unsigned int already unless I'm missing something.

> +		c1->write_latency += c2->write_latency;
> +
> +		if (c2->read_bandwidth)
> +			c1->read_bandwidth = min_t(unsigned int,
> +						   c1->read_bandwidth,
> +						   c2->read_bandwidth);
same here.

> +		c1->read_latency += c2->read_latency;
> +}



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 08/14] cxl: Compute the entire CXL path latency and bandwidth data
  2023-05-08 20:47 ` [PATCH v5 08/14] cxl: Compute the entire CXL path latency and bandwidth data Dave Jiang
@ 2023-05-12 15:09   ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 15:09 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:47:42 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> CXL Memory Device SW Guide rev1.0 2.11.2 provides instruction on how to
> caluclate latency and bandwidth for CXL memory device. Calculate minimum
Spell check.

Also, a link for SW guide probably good to add.

> bandwidth and total latency for the path from the CXL device to the root
> port. The QTG id is retrieved by providing the performance data as input
> and calling the root port callback ->get_qos_class(). The retrieved id is
> stored with the cxl_port of the CXL device.
> 
> For example for a device that is directly attached to a host bus:
> Total Latency = Device Latency (from CDAT) + Dev to Host Bus (HB) Link
> 		Latency + Generic Port Latency
> Min Bandwidth = Min bandwidth for link bandwidth between HB
> 		and CXL device, device CDAT bandwidth, and Generic Port
> 		Bandwidth
> 
> For a device that has a switch in between host bus and CXL device:
> Total Latency = Device (CDAT) Latency + Dev to Switch Link Latency +
> 		Switch (CDAT) Latency + Switch to HB Link Latency +
> 		Generic Port Latency
> Min Bandwidth = Min bandwidth for link bandwidth between CXL device
> 		to CXL switch, CXL device CDAT bandwidth, CXL switch CDAT
> 		bandwidth, CXL switch to HB bandwidth, and Generic Port
> 		Bandwidth.
> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>

LGTM
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> 
> ---
> v5:
> - Use new API call cxl_endpoint_get_perf_coordinates().
> - Use root_port->get_qos_class() (Dan)
> - Add endieness handling to DSM input.
> ---
>  drivers/cxl/cxl.h  |    1 +
>  drivers/cxl/port.c |   56 +++++++++++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 54 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 0c8952e568cc..7c94f07771c1 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -833,6 +833,7 @@ struct dsmas_entry {
>  	struct range dpa_range;
>  	u8 handle;
>  	struct access_coordinate coord;
> +	int qos_class;
>  };
>  
>  #ifdef CONFIG_ACPI
> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
> index c5a24b75bf03..b474997cc7ee 100644
> --- a/drivers/cxl/port.c
> +++ b/drivers/cxl/port.c
> @@ -67,6 +67,52 @@ static void dsmas_list_destroy(struct list_head *dsmas_list)
>  	}
>  }
>  
> +static int cxl_port_perf_data_calculate(struct cxl_port *port,
> +					struct list_head *dsmas_list)
> +{
> +	struct access_coordinate c;
> +	struct qtg_dsm_input input;
> +	struct cxl_port *root_port;
> +	struct cxl_root *cxl_root;
> +	struct dsmas_entry *dent;
> +	int rc, qos_class;
> +
> +	rc = cxl_endpoint_get_perf_coordinates(port, &c);
> +	if (rc) {
> +		dev_dbg(&port->dev, "Failed to retrieve perf coordinates.\n");
> +		return rc;
> +	}
> +
> +	root_port = find_cxl_root(port);
> +	cxl_root = to_cxl_root(root_port);
> +	if (!cxl_root->ops && !cxl_root->ops->get_qos_class)
> +		return -EOPNOTSUPP;
> +
> +	list_for_each_entry(dent, dsmas_list, list) {
> +		dent->coord.read_latency = dent->coord.read_latency +
> +					   c.read_latency;
> +		dent->coord.write_latency = dent->coord.write_latency +
> +					    c.write_latency;
> +		dent->coord.read_bandwidth = min_t(int, c.read_bandwidth,
> +						   dent->coord.read_bandwidth);
> +		dent->coord.write_bandwidth = min_t(int, c.write_bandwidth,
> +						    dent->coord.write_bandwidth);
> +
> +		input.rd_lat = cpu_to_le32(dent->coord.read_latency);
> +		input.wr_lat = cpu_to_le32(dent->coord.write_latency);
> +		input.rd_bw = cpu_to_le32(dent->coord.read_bandwidth);
> +		input.wr_bw = cpu_to_le32(dent->coord.write_bandwidth);
> +
> +		qos_class = cxl_root->ops->get_qos_class(root_port, &input);
> +		if (qos_class < 0)
> +			continue;
> +
> +		dent->qos_class = qos_class;
> +	}
> +
> +	return 0;
> +}
> +
>  static int cxl_switch_port_probe(struct cxl_port *port)
>  {
>  	struct cxl_hdm *cxlhdm;
> @@ -155,10 +201,14 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
>  		LIST_HEAD(dsmas_list);
>  
>  		rc = cxl_cdat_endpoint_process(port, &dsmas_list);
> -		if (rc < 0)
> +		if (rc < 0) {
>  			dev_dbg(&port->dev, "Failed to parse CDAT: %d\n", rc);
> -
> -		/* Performance data processing */
> +		} else {
> +			rc = cxl_port_perf_data_calculate(port, &dsmas_list);
> +			if (rc)
> +				dev_dbg(&port->dev,
> +					"Failed to do perf coord calculations.\n");
> +		}
>  
>  		dsmas_list_destroy(&dsmas_list);
>  	}
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 09/14] cxl: Wait Memory_Info_Valid before access memory related info
  2023-05-08 20:47 ` [PATCH v5 09/14] cxl: Wait Memory_Info_Valid before access memory related info Dave Jiang
@ 2023-05-12 15:16   ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 15:16 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:47:47 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> CXL rev3.0 8.1.3.8.2 Memory_Info_valid field
> 
> The Memory_Info_Valid bit indicates that the CXL Range Size High and Size
> Low registers are valid. The bit must be set within 1 second of reset
> deassertion to the device. Check valid bit before we check the
> Memory_Active bit when waiting for cxl_await_media_ready() to ensure that
> the memory info is valid for consumption.
> 
> Fixes: 2e4ba0ec9783 ("cxl/pci: Move cxl_await_media_ready() to the core")
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>

It's a fix - should be first patch in series (to make it obvious backporting is
easy etc).

Hard to read this one as diff has been unfriendly, but I 'think'
it's fine.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>


> 
> ---
> v2:
> - Check both ranges. (Jonathan)
> ---
>  drivers/cxl/core/pci.c |   83 +++++++++++++++++++++++++++++++++++++++++++-----
>  drivers/cxl/cxlpci.h   |    2 +
>  2 files changed, 77 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index 6c99a964eb54..536672d469a1 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -102,21 +102,55 @@ int devm_cxl_port_enumerate_dports(struct cxl_port *port)
>  }
>  EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, CXL);
>  
> -/*
> - * Wait up to @media_ready_timeout for the device to report memory
> - * active.
> - */
> -int cxl_await_media_ready(struct cxl_dev_state *cxlds)
> +static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id)
> +{
> +	struct pci_dev *pdev = to_pci_dev(cxlds->dev);
> +	int d = cxlds->cxl_dvsec;
> +	bool valid = false;
> +	int rc, i;
> +	u32 temp;
> +
> +	if (id > CXL_DVSEC_RANGE_MAX)
> +		return -EINVAL;
> +
> +	/* Check MEM INFO VALID bit first, give up after 1s */
> +	i = 1;
> +	do {
> +		rc = pci_read_config_dword(pdev,
> +					   d + CXL_DVSEC_RANGE_SIZE_LOW(id),
> +					   &temp);
> +		if (rc)
> +			return rc;
> +
> +		valid = FIELD_GET(CXL_DVSEC_MEM_INFO_VALID, temp);
> +		if (valid)
> +			break;
> +		msleep(1000);
> +	} while (i--);
> +
> +	if (!valid) {
> +		dev_err(&pdev->dev,
> +			"Timeout awaiting memory range %d valid after 1s.\n",
> +			id);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
> +static int cxl_dvsec_mem_range_active(struct cxl_dev_state *cxlds, int id)
>  {
>  	struct pci_dev *pdev = to_pci_dev(cxlds->dev);
>  	int d = cxlds->cxl_dvsec;
>  	bool active = false;
> -	u64 md_status;
>  	int rc, i;
> +	u32 temp;
>  
> -	for (i = media_ready_timeout; i; i--) {
> -		u32 temp;
> +	if (id > CXL_DVSEC_RANGE_MAX)
> +		return -EINVAL;
>  
> +	/* Check MEM ACTIVE bit, up to 60s timeout by default */
> +	for (i = media_ready_timeout; i; i--) {
>  		rc = pci_read_config_dword(
>  			pdev, d + CXL_DVSEC_RANGE_SIZE_LOW(0), &temp);
>  		if (rc)
> @@ -135,6 +169,39 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds)
>  		return -ETIMEDOUT;
>  	}
>  
> +	return 0;
> +}
> +
> +/*
> + * Wait up to @media_ready_timeout for the device to report memory
> + * active.
> + */
> +int cxl_await_media_ready(struct cxl_dev_state *cxlds)
> +{
> +	struct pci_dev *pdev = to_pci_dev(cxlds->dev);
> +	int d = cxlds->cxl_dvsec;
> +	int rc, i, hdm_count;
> +	u64 md_status;
> +	u16 cap;
> +
> +	rc = pci_read_config_word(pdev,
> +				  d + CXL_DVSEC_CAP_OFFSET, &cap);
> +	if (rc)
> +		return rc;
> +
> +	hdm_count = FIELD_GET(CXL_DVSEC_HDM_COUNT_MASK, cap);
> +	for (i = 0; i < hdm_count; i++) {
> +		rc = cxl_dvsec_mem_range_valid(cxlds, i);
> +		if (rc)
> +			return rc;
> +	}
> +
> +	for (i = 0; i < hdm_count; i++) {
> +		rc = cxl_dvsec_mem_range_active(cxlds, i);
> +		if (rc)
> +			return rc;
> +	}
> +
>  	md_status = readq(cxlds->regs.memdev + CXLMDEV_STATUS_OFFSET);
>  	if (!CXLMDEV_READY(md_status))
>  		return -EIO;
> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
> index 84c9f73c7d92..1772cd226108 100644
> --- a/drivers/cxl/cxlpci.h
> +++ b/drivers/cxl/cxlpci.h
> @@ -31,6 +31,8 @@
>  #define   CXL_DVSEC_RANGE_BASE_LOW(i)	(0x24 + (i * 0x10))
>  #define     CXL_DVSEC_MEM_BASE_LOW_MASK	GENMASK(31, 28)
>  
> +#define CXL_DVSEC_RANGE_MAX		2
> +
>  /* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */
>  #define CXL_DVSEC_FUNCTION_MAP					2
>  
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 10/14] cxl: Move identify and partition query from pci probe to port probe
  2023-05-08 20:47 ` [PATCH v5 10/14] cxl: Move identify and partition query from pci probe to port probe Dave Jiang
@ 2023-05-12 15:17   ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 15:17 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:47:53 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> Move the enumeration of device capacity to cxl_port_probe() from
> cxl_pci_probe(). The size and capacity information should be read
> after cxl_await_media_ready() so the data is valid.
> 
> Fixes: 5e2411ae8071 ("cxl/memdev: Change cxl_mem to a more descriptive name")
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>

Same comment about this should be at top of patch set, not buried down at patch 10.

Change seems fine
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> ---
>  drivers/cxl/pci.c  |    8 --------
>  drivers/cxl/port.c |    8 ++++++++
>  2 files changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> index ed39d133b70d..06324266eae8 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/pci.c
> @@ -707,14 +707,6 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  	if (rc)
>  		return rc;
>  
> -	rc = cxl_dev_state_identify(cxlds);
> -	if (rc)
> -		return rc;
> -
> -	rc = cxl_mem_create_range_info(cxlds);
> -	if (rc)
> -		return rc;
> -
>  	rc = cxl_alloc_irq_vectors(pdev);
>  	if (rc)
>  		return rc;
> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
> index b474997cc7ee..0bdb9d73a389 100644
> --- a/drivers/cxl/port.c
> +++ b/drivers/cxl/port.c
> @@ -180,6 +180,14 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
>  		return rc;
>  	}
>  
> +	rc = cxl_dev_state_identify(cxlds);
> +	if (rc)
> +		return rc;
> +
> +	rc = cxl_mem_create_range_info(cxlds);
> +	if (rc)
> +		return rc;
> +
>  	rc = devm_cxl_enumerate_decoders(cxlhdm, &info);
>  	if (rc)
>  		return rc;
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 11/14] cxl: Move read_cdat_data() to after media is ready
  2023-05-08 20:47 ` [PATCH v5 11/14] cxl: Move read_cdat_data() to after media is ready Dave Jiang
@ 2023-05-12 15:18   ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 15:18 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:47:59 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> CDAT data is only valid after the media is ready. Move read_cdat_data() to
> after cxl_awai_media_read() is successful.
await

> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
No fixes tag? Plus move it to the top of the series with the other
two fixes.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> ---
>  drivers/cxl/port.c |    6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
> index 0bdb9d73a389..1d55c460e1ab 100644
> --- a/drivers/cxl/port.c
> +++ b/drivers/cxl/port.c
> @@ -162,9 +162,6 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
>  	if (IS_ERR(cxlhdm))
>  		return PTR_ERR(cxlhdm);
>  
> -	/* Cache the data early to ensure is_visible() works */
> -	read_cdat_data(port);
> -
>  	get_device(&cxlmd->dev);
>  	rc = devm_add_action_or_reset(&port->dev, schedule_detach, cxlmd);
>  	if (rc)
> @@ -180,6 +177,9 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
>  		return rc;
>  	}
>  
> +	/* Cache the data early to ensure is_visible() works */
> +	read_cdat_data(port);
> +
>  	rc = cxl_dev_state_identify(cxlds);
>  	if (rc)
>  		return rc;
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem
  2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
                   ` (13 preceding siblings ...)
  2023-05-08 20:48 ` [PATCH v5 14/14] cxl/mem: Add debugfs output for QTG related data Dave Jiang
@ 2023-05-12 15:28 ` Jonathan Cameron
  2023-05-16 21:49   ` Dan Williams
  14 siblings, 1 reply; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 15:28 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, Dan Williams, ira.weiny, vishal.l.verma,
	alison.schofield

Hi Dave,

> The QTG ID for a device is retrieved via sending a _DSM method to the ACPI0017 device.
> The _DSM expects an input package of 4 DWORDS that contains the read latency, write
> latency, read bandwidth, and write banwidth. These are the caluclated numbers for the
> path between the CXL device and the CPU. The QTG ID is also exported as a sysfs
> attribute under the mem device memory partition type:
> /sys/bus/cxl/devices/memX/ram/qos_class
> /sys/bus/cxl/devices/memX/pmem/qos_class
> Only the first QTG ID is exported.

The QTG DSM returning a list was done to allow for a case of mutual
incompatibility between the first QTG that is returned for a particular
performance point and the CFMWS that it points at.

CFMWS might say 'no pmem in here' but due to some RAM device that is a bit
slow, we might end up with a QTG DSM response that says put it in that CFMWS.

Hence the fallback list.

That is currently hidden by this approach.  It makes things more complex, but
I'd really like to see the whole of that list rather than just the first element
presented for each region.  I think it's fine to let userspace then figure
out if there is a missmatch.

Jonathan

> The rest of the information can be found under
> /sys/kernel/debug/cxl/memX/qtgmap where all the DPA ranges with the correlated QTG ID
> are displayed. Each DSMAS from the device CDAT will provide a DPA range.
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 12/14] cxl: Store QTG IDs and related info to the CXL memory device context
  2023-05-08 20:48 ` [PATCH v5 12/14] cxl: Store QTG IDs and related info to the CXL memory device context Dave Jiang
@ 2023-05-12 15:30   ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 15:30 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:48:05 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> Once the QTG ID _DSM is executed successfully, the QTG ID is retrieved from
> the return package. Create a list of entries in the cxl_memdev context and
> store the QTG ID and the associated DPA range. This information can be
> exposed to user space via sysfs in order to help region setup for
> hot-plugged CXL memory devices.
> 
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Trivial inline but my suggestion of needing to carry the full list
will apply here too...

> diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
> index 001dabf0231b..9d77b7e420ce 100644
> --- a/drivers/cxl/cxlmem.h
> +++ b/drivers/cxl/cxlmem.h
> @@ -5,6 +5,7 @@
>  #include <uapi/linux/cxl_mem.h>
>  #include <linux/cdev.h>
>  #include <linux/uuid.h>
> +#include <linux/node.h>
>  #include "cxl.h"
>  
>  /* CXL 2.0 8.2.8.5.1.1 Memory Device Status Register */
> @@ -215,6 +216,19 @@ struct cxl_event_state {
>  	struct mutex log_lock;
>  };
>  
> +/**
> + * struct perf_prop - performance property entry
> + * @list - list entry
> + * @dpa_range - range for DPA address
> + * @qos_class - QoS Class cookie

coord?

Run a W=1 build and it will moan about this sort of missing description.

> + */
> +struct perf_prop_entry {
> +	struct list_head list;
> +	struct range dpa_range;
> +	u16 qos_class;
> +	struct access_coordinate coord;
> +};
> +


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 13/14] cxl: Export sysfs attributes for memory device QoS class
  2023-05-08 20:48 ` [PATCH v5 13/14] cxl: Export sysfs attributes for memory device QoS class Dave Jiang
@ 2023-05-12 15:33   ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 15:33 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, Dan Williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:48:10 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> Export qos_class sysfs attributes for the CXL memory device. The QoS clas
> should show up as /sys/bus/cxl/devices/memX/ram/qos_class for the volatile
> partition and /sys/bus/cxl/devices/memX/pmem/qos_class for the persistent
> partition. The QTG ID is retrieved via _DSM after supplying the
> calculated bandwidth and latency for the entire CXL path from device to
> the CPU. This ID is used to match up to the root decoder QoS class to
> determine which CFMWS the memory range of a hotplugged CXL mem device
> should be assigned under.
> 
> While there may be multiple DSMAS exported by the device CDAT, the driver
> will only expose the first QTG ID per partition in sysfs for now. In the
> future when multiple QTG IDs are necessary, they can be exposed. [1]
> 
> [1]: https://lore.kernel.org/linux-cxl/167571650007.587790.10040913293130712882.stgit@djiang5-mobl3.local/T/#md2a47b1ead3e1ba08f50eab29a4af1aed1d215ab
> 
> Suggested-by: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> 

Reading this patch made me notice the whole issue of we may be exporting
a useless QTG for the device due to a missmatch of memory type and CFMWS
(as not using the full list provided by the _DSM)

> ---
> v5:
> - Change qtg_id to qos_class
> v4:
> - Change kernel version for documentation to v6.5
> v3:
> - Expand description of qtg_id. (Alison)
> ---
>  Documentation/ABI/testing/sysfs-bus-cxl |   32 +++++++++++++++++++++++++++++++
>  drivers/cxl/core/memdev.c               |   26 +++++++++++++++++++++++++
>  2 files changed, 58 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
> index 2f24e42ef36d..c13ae49dd9aa 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -28,6 +28,22 @@ Description:
>  		Payload in the CXL-2.0 specification.
>  
>  
> +What:		/sys/bus/cxl/devices/memX/ram/qos_class
> +Date:		May, 2023
> +KernelVersion:	v6.5
> +Contact:	linux-cxl@vger.kernel.org
> +Description:
> +		(RO) For CXL host platforms that support "QoS Telemmetry"
> +		this attribute conveys a platform specific cookie that
> +		identifies a QoS performance class for the volatile
> +		partition of the CXL mem device. This class-id can be
> +		compared against a similar "qos_class" published for
> +		a root decoder. While it is not required that the endpoints
> +		map their local memory-class to a matching platform class,
> +		mismatches are not recommended and there are platform specific
> +		side-effects that may result.

I think this needs to be the full ordered list from the _DSM with text suggesting
that a compatible CFMWS matching the earliest entry possible should be used.




^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 14/14] cxl/mem: Add debugfs output for QTG related data
  2023-05-08 20:48 ` [PATCH v5 14/14] cxl/mem: Add debugfs output for QTG related data Dave Jiang
@ 2023-05-12 15:36   ` Jonathan Cameron
  2023-05-17 22:28     ` Dave Jiang
  0 siblings, 1 reply; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-12 15:36 UTC (permalink / raw)
  To: Dave Jiang
  Cc: linux-cxl, Dan Williams, ira.weiny, vishal.l.verma,
	alison.schofield

On Mon, 08 May 2023 13:48:16 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> Add debugfs output to /sys/kernel/debug/cxl/memX/qtgmap
> The debugfs attribute will dump out all the DSMAS ranges and the associated
> QTG ID exported by the CXL device CDAT.
> 
> Suggested-by: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>

LTGM, though seems we haven't been keeping up with ABI docs for other
stuff in debugfs. That wants fixing but is unrelated to this.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> 
> ---
> v4:
> - Use cxlds->qos_list instead of the stray cxlmd->qos_list
> ---
>  Documentation/ABI/testing/debugfs-cxl |   11 +++++++++++
>  MAINTAINERS                           |    1 +
>  drivers/cxl/mem.c                     |   17 +++++++++++++++++
>  3 files changed, 29 insertions(+)
>  create mode 100644 Documentation/ABI/testing/debugfs-cxl
> 
> diff --git a/Documentation/ABI/testing/debugfs-cxl b/Documentation/ABI/testing/debugfs-cxl
> new file mode 100644
> index 000000000000..0f36eeb7e59b
> --- /dev/null
> +++ b/Documentation/ABI/testing/debugfs-cxl
> @@ -0,0 +1,11 @@
> +What:		/sys/kernel/debug/cxl/memX/qtg_map
> +Date:		Mar, 2023
> +KernelVersion:	v6.4
> +Contact:	linux-cxl@vger.kernel.org
> +Description:
> +		(RO) Entries of all Device Physical Address (DPA) ranges
> +		provided by the device Coherent Device Attributes Table (CDAT)
> +		Device Scoped Memory Affinity Structure (DSMAS) entries with
> +		the matching QoS Throttling Group (QTG) id calculated from the
> +		latency and bandwidth of the CXL path from the memory device
> +		to the CPU.

Curious. This file should already exist as there is clearly more debugfs ABI
from the code below.  Perhaps a precursor patch to create the file and document
existing interfaces?

> diff --git a/MAINTAINERS b/MAINTAINERS
> index fd8c4c560f8d..256e4e57017c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -5171,6 +5171,7 @@ M:	Ben Widawsky <bwidawsk@kernel.org>
>  M:	Dan Williams <dan.j.williams@intel.com>
>  L:	linux-cxl@vger.kernel.org
>  S:	Maintained
> +F:	Documentation/ABI/testing/debugfs-cxl
>  F:	drivers/cxl/
>  F:	include/uapi/linux/cxl_mem.h
>  
> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
> index 39c4b54f0715..587e261a7f76 100644
> --- a/drivers/cxl/mem.c
> +++ b/drivers/cxl/mem.c
> @@ -45,6 +45,22 @@ static int cxl_mem_dpa_show(struct seq_file *file, void *data)
>  	return 0;
>  }
>  
> +static int cxl_mem_qtg_show(struct seq_file *file, void *data)
> +{
> +	struct device *dev = file->private;
> +	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
> +	struct cxl_dev_state *cxlds = cxlmd->cxlds;
> +	struct perf_prop_entry *perf;
> +
> +	list_for_each_entry(perf, &cxlds->perf_list, list) {
> +		seq_printf(file, "%08llx-%08llx : QoS Class: %u\n",
> +			   perf->dpa_range.start, perf->dpa_range.end,
> +			   perf->qos_class);
> +	}
> +
> +	return 0;
> +}
> +
>  static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
>  				 struct cxl_dport *parent_dport)
>  {
> @@ -117,6 +133,7 @@ static int cxl_mem_probe(struct device *dev)
>  
>  	dentry = cxl_debugfs_create_dir(dev_name(dev));
>  	debugfs_create_devm_seqfile(dev, "dpamem", dentry, cxl_mem_dpa_show);
> +	debugfs_create_devm_seqfile(dev, "qtgmap", dentry, cxl_mem_qtg_show);
>  	rc = devm_add_action_or_reset(dev, remove_debugfs, dentry);
>  	if (rc)
>  		return rc;
> 
> 


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 03/14] cxl: Add callback to parse the SSLBIS subtable from CDAT
  2023-05-12 14:41   ` Jonathan Cameron
@ 2023-05-16 17:49     ` Dave Jiang
  0 siblings, 0 replies; 36+ messages in thread
From: Dave Jiang @ 2023-05-16 17:49 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield



On 5/12/23 7:41 AM, Jonathan Cameron wrote:
> On Mon, 08 May 2023 13:47:11 -0700
> Dave Jiang <dave.jiang@intel.com> wrote:
> 
>> 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>
> 
> I'm disagreeing with myself again. Some comments inline based
> on a fresh read.
> 
>> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>>
>> ---
>> v5:
>> - Store data to cxl_dport directly instead. (Dan)
>> - Use acpi_table_parse_cdat().
>> v3:
>> - Add spec section in commit header (Alison)
>> - Move CDAT parse to cxl_switch_port_probe()
>> - Use 'struct node_hmem_attrs'
>> ---
>>   drivers/cxl/core/cdat.c |   88 +++++++++++++++++++++++++++++++++++++++++++++++
>>   drivers/cxl/cxl.h       |    8 ++++
>>   drivers/cxl/port.c      |   12 ++++++
>>   include/acpi/actbl1.h   |    3 ++
>>   4 files changed, 110 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
>> index 6e14d04c0453..37b135c900d5 100644
>> --- a/drivers/cxl/core/cdat.c
>> +++ b/drivers/cxl/core/cdat.c
>> @@ -124,3 +124,91 @@ int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list)
>>   	return rc;
>>   }
>>   EXPORT_SYMBOL_NS_GPL(cxl_cdat_endpoint_process, CXL);
>> +
>> +static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg,
>> +			       const unsigned long end)
>> +{
>> +	struct acpi_cdat_sslbis *sslbis = (struct acpi_cdat_sslbis *)header;
>> +	struct acpi_cdat_sslbe *entry;
>> +	struct cxl_port *port = arg;
>> +	struct device *dev = &port->dev;
>> +	int remain, entries, i;
>> +	u16 len;
>> +
>> +	len = le16_to_cpu((__force __le16)sslbis->header.length);
>> +	remain = len - sizeof(*sslbis);
>> +	if (!remain || remain % sizeof(*entry) ||
>> +	    (unsigned long)header + len > end) {
>> +		dev_warn(dev, "Malformed SSLBIS table length: (%u)\n", len);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* Unrecognized data type, we can skip */
>> +	if (sslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH)
>> +		return 0;
>> +
>> +	entries = remain / sizeof(*entry);
>> +	entry = (struct acpi_cdat_sslbe *)((unsigned long)header + sizeof(*sslbis));
> 
> That's a little nasty to follow.  Perhaps.
> 	
> 	entry = (struct acpi_cdat_sslbe *)(sslbis + 1);

Ok. I'll also update previous 2 patches with similar usages.

> 
> Bonus points if we can just use a variable length entry on the end of
> struct acpi_cdat_sslbis. Might break some other locations but would make
> this one nicer.

I had that when I was using local data structures for CDAT tables. But 
changing the ACPI version results in touching a lot of ACPICA code 
unfortunately.

> 
>> +
>> +	for (i = 0; i < entries; i++) {
>> +		u16 x = le16_to_cpu(entry->portx_id);
>> +		u16 y = le16_to_cpu(entry->porty_id);
>> +		struct cxl_dport *dport;
>> +		unsigned long index;
>> +		u16 dsp_id;
>> +		u64 val;
>> +
>> +		switch (x) {
>> +		case ACPI_CDAT_SSLBIS_US_PORT:
>> +			dsp_id = y;
>> +			break;
>> +		case ACPI_CDAT_SSLBIS_ANY_PORT:
>> +			switch (y) {
>> +			case ACPI_CDAT_SSLBIS_US_PORT:
>> +				dsp_id = x;
>> +				break;
>> +			case ACPI_CDAT_SSLBIS_ANY_PORT:
>> +				dsp_id = ACPI_CDAT_SSLBIS_ANY_PORT;
>> +				break;
>> +			default:
>> +				dsp_id = y;
>> +				break;
>> +			}
>> +			break;
>> +		default:
>> +			dsp_id = x;
>> +			break;
>> +		}
>> +
>> +		if (check_mul_overflow(le64_to_cpu(sslbis->entry_base_unit),
>> +				       le16_to_cpu(entry->latency_or_bandwidth),
>> +				       &val))
>> +			dev_warn(dev, "SSLBIS value overflowed!\n");
>> +
>> +		xa_for_each(&port->dports, index, dport) {
>> +			if (dsp_id == ACPI_CDAT_SSLBIS_ANY_PORT ||
>> +			    dsp_id == dport->port_id)
>> +				cxl_access_coordinate_set(&dport->coord,
>> +							  sslbis->data_type,
>> +							  val);
>> +		}
>> +
>> +		entry++;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +int cxl_cdat_switch_process(struct cxl_port *port)
>> +{
>> +	int rc;
>> +
>> +	rc = acpi_table_parse_cdat(ACPI_CDAT_TYPE_SSLBIS,
>> +				   cdat_sslbis_handler,
>> +				   port, port->cdat.table);
>> +	if (rc == 0)
>> +		rc = -ENOENT;
> 
> I'm bored of this pattern now so hide it...
> 
> Howabout
> 
> 	acpi_table_parse_cdat_fail_emtpy() that handles the rc
> rewrite internally. (with a better name).
> 
> Gets rid of all this boilerplate.

ok

> 
> 
> 
>> +
>> +	return rc;
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_cdat_switch_process, CXL);
>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>> index ca3d0d74f2e5..3e8020e0a132 100644
>> --- a/drivers/cxl/cxl.h
>> +++ b/drivers/cxl/cxl.h
>> @@ -600,6 +600,7 @@ cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
>>    * @rcrb: base address for the Root Complex Register Block
>>    * @rch: Indicate whether this dport was enumerated in RCH or VH mode
>>    * @port: reference to cxl_port that contains this downstream port
>> + * @coord: access coordinates (performance) for switch from CDAT
>>    */
>>   struct cxl_dport {
>>   	struct device *dport;
>> @@ -608,6 +609,7 @@ struct cxl_dport {
>>   	resource_size_t rcrb;
>>   	bool rch;
>>   	struct cxl_port *port;
>> +	struct access_coordinate coord;
>>   };
>>   
>>   /**
>> @@ -803,12 +805,18 @@ struct dsmas_entry {
>>   
>>   #ifdef CONFIG_ACPI
>>   int cxl_cdat_endpoint_process(struct cxl_port *port, struct list_head *list);
>> +int cxl_cdat_switch_process(struct cxl_port *port);
>>   #else
>>   static inline int cxl_cdat_endpoint_process(struct cxl_port *port,
>>   					    struct list_head *list)
>>   {
>>   	return -EOPNOTSUPP;
>>   }
>> +
>> +static inline int cxl_cdat_switch_process(struct cxl_port *port)
>> +{
>> +	return -EOPNOTSUPP;
>> +}
>>   #endif
>>   
>>   /*
>> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
>> index da023feaa6e2..c5a24b75bf03 100644
>> --- a/drivers/cxl/port.c
>> +++ b/drivers/cxl/port.c
>> @@ -86,7 +86,17 @@ static int cxl_switch_port_probe(struct cxl_port *port)
>>   	if (IS_ERR(cxlhdm))
>>   		return PTR_ERR(cxlhdm);
>>   
>> -	return devm_cxl_enumerate_decoders(cxlhdm, NULL);
>> +	rc = devm_cxl_enumerate_decoders(cxlhdm, NULL);
>> +	if (rc < 0)
>> +		return rc;
>> +
>> +	if (port->cdat.table) {
>> +		rc = cxl_cdat_switch_process(port);
>> +		if (rc < 0)
>> +			dev_warn(&port->dev, "Failed to parse SSLBIS: %d\n", rc);
>> +	}
>> +
>> +	return 0;
>>   }
>>   
>>   static int cxl_endpoint_port_probe(struct cxl_port *port)
>> diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
>> index 8ea7e5d64bc1..82def138a7e4 100644
>> --- a/include/acpi/actbl1.h
>> +++ b/include/acpi/actbl1.h
>> @@ -419,6 +419,9 @@ struct acpi_cdat_sslbis {
>>   	u64 entry_base_unit;
>>   };
>>   
>> +#define ACPI_CDAT_SSLBIS_US_PORT	0x0100
>> +#define ACPI_CDAT_SSLBIS_ANY_PORT	0xffff
>> +
>>   /* Sub-subtable for above, sslbe_entries field */
>>   
>>   struct acpi_cdat_sslbe {
>>
>>
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 06/14] cxl: Store the access coordinates for the generic ports
  2023-05-12 14:59   ` Jonathan Cameron
@ 2023-05-16 20:58     ` Dave Jiang
  2023-05-16 21:13       ` Dan Williams
  0 siblings, 1 reply; 36+ messages in thread
From: Dave Jiang @ 2023-05-16 20:58 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield



On 5/12/23 7:59 AM, Jonathan Cameron wrote:
> On Mon, 08 May 2023 13:47:29 -0700
> Dave Jiang <dave.jiang@intel.com> wrote:
> 
>> Each CXL host bridge is represented by an ACPI0016 device. A generic port
>> device handle that is an ACPI device is represented by a string of
>> ACPI0016 device HID and UID. Create a device handle from the ACPI device
>> and retrieve the access coordinates from the stored memory targets. The
>> access coordinates are stored under the cxl_dport that is associated with
>> the CXL host bridge.
>>
>> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>> ---
>>   drivers/cxl/acpi.c |   28 ++++++++++++++++++++++++++++
>>   drivers/cxl/cxl.h  |    2 ++
>>   2 files changed, 30 insertions(+)
>>
>> diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
>> index f9b35e8fe810..675a4f423f4b 100644
>> --- a/drivers/cxl/acpi.c
>> +++ b/drivers/cxl/acpi.c
>> @@ -537,8 +537,26 @@ static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
>>   	return 0;
>>   }
>>   
>> +static int get_genport_coordinates(struct device *dev, struct cxl_dport *dport)
>> +{
>> +	struct acpi_device *hb = to_cxl_host_bridge(NULL, dev);
>> +	u8 handle[ACPI_SRAT_DEVICE_HANDLE_SIZE] = { 0 };
>> +	int rc;
>> +
>> +	/* ACPI spec 6.5 tABLE 5.65 */
> 
> tABLE?

ooops caps lock

> 
>> +	memcpy(handle, acpi_device_hid(hb), 8);
>> +	memcpy(&handle[8], acpi_device_uid(hb), 4);
>> +
>> +	rc = acpi_get_genport_coordinates(handle, dport->genport_coord);
>> +	if (rc)
>> +		return rc;
>> +
>> +	return 0;
>> +}
>> +
>>   static int add_host_bridge_dport(struct device *match, void *arg)
>>   {
>> +	int ret;
>>   	acpi_status rc;
>>   	struct device *bridge;
>>   	unsigned long long uid;
>> @@ -594,6 +612,16 @@ static int add_host_bridge_dport(struct device *match, void *arg)
>>   	if (IS_ERR(dport))
>>   		return PTR_ERR(dport);
>>   
>> +	dport->genport_coord = devm_kzalloc(dport->dport,
>> +					    sizeof(*dport->genport_coord),
>> +					    GFP_KERNEL);
> 
> It's pretty small - worth allocating separately?
> 
> Maybe add something on why to the patch description if there is another reason
> for this dance.

My intention was to allow detection of whether the data exists or not 
based on if the ptr is NULL. I'll add explanation in patch description.

> 
>> +	if (!dport->genport_coord)
>> +		return -ENOMEM;
>> +
>> +	ret = get_genport_coordinates(match, dport);
>> +	if (ret)
>> +		dev_dbg(match, "Failed to get generic port perf coordinates.\n");
>> +
>>   	return 0;
>>   }
>>   
>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>> index c1e2c3703a63..033b822a20f2 100644
>> --- a/drivers/cxl/cxl.h
>> +++ b/drivers/cxl/cxl.h
>> @@ -626,6 +626,7 @@ cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
>>    * @rcrb: base address for the Root Complex Register Block
>>    * @rch: Indicate whether this dport was enumerated in RCH or VH mode
>>    * @port: reference to cxl_port that contains this downstream port
>> + * @genport_coord: access coordinates (performance) from ACPI generic port
>>    * @coord: access coordinates (performance) for switch from CDAT
>>    * @link_latency: calculated PCIe downstream latency
>>    */
>> @@ -636,6 +637,7 @@ struct cxl_dport {
>>   	resource_size_t rcrb;
>>   	bool rch;
>>   	struct cxl_port *port;
>> +	struct access_coordinate *genport_coord;
>>   	struct access_coordinate coord;
>>   	long link_latency;
>>   };
>>
>>
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 06/14] cxl: Store the access coordinates for the generic ports
  2023-05-16 20:58     ` Dave Jiang
@ 2023-05-16 21:13       ` Dan Williams
  2023-05-16 21:52         ` Dave Jiang
  0 siblings, 1 reply; 36+ messages in thread
From: Dan Williams @ 2023-05-16 21:13 UTC (permalink / raw)
  To: Dave Jiang, Jonathan Cameron
  Cc: linux-cxl, dan.j.williams, ira.weiny, vishal.l.verma,
	alison.schofield

Dave Jiang wrote:
> 
> 
> On 5/12/23 7:59 AM, Jonathan Cameron wrote:
> > On Mon, 08 May 2023 13:47:29 -0700
> > Dave Jiang <dave.jiang@intel.com> wrote:
> > 
> >> Each CXL host bridge is represented by an ACPI0016 device. A generic port
> >> device handle that is an ACPI device is represented by a string of
> >> ACPI0016 device HID and UID. Create a device handle from the ACPI device
> >> and retrieve the access coordinates from the stored memory targets. The
> >> access coordinates are stored under the cxl_dport that is associated with
> >> the CXL host bridge.
> >>
> >> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> >> ---
> >>   drivers/cxl/acpi.c |   28 ++++++++++++++++++++++++++++
> >>   drivers/cxl/cxl.h  |    2 ++
> >>   2 files changed, 30 insertions(+)
> >>
> >> diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
> >> index f9b35e8fe810..675a4f423f4b 100644
> >> --- a/drivers/cxl/acpi.c
> >> +++ b/drivers/cxl/acpi.c
> >> @@ -537,8 +537,26 @@ static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
> >>   	return 0;
> >>   }
> >>   
> >> +static int get_genport_coordinates(struct device *dev, struct cxl_dport *dport)
> >> +{
> >> +	struct acpi_device *hb = to_cxl_host_bridge(NULL, dev);
> >> +	u8 handle[ACPI_SRAT_DEVICE_HANDLE_SIZE] = { 0 };
> >> +	int rc;
> >> +
> >> +	/* ACPI spec 6.5 tABLE 5.65 */
> > 
> > tABLE?
> 
> ooops caps lock
> 
> > 
> >> +	memcpy(handle, acpi_device_hid(hb), 8);
> >> +	memcpy(&handle[8], acpi_device_uid(hb), 4);
> >> +
> >> +	rc = acpi_get_genport_coordinates(handle, dport->genport_coord);
> >> +	if (rc)
> >> +		return rc;
> >> +
> >> +	return 0;
> >> +}
> >> +
> >>   static int add_host_bridge_dport(struct device *match, void *arg)
> >>   {
> >> +	int ret;
> >>   	acpi_status rc;
> >>   	struct device *bridge;
> >>   	unsigned long long uid;
> >> @@ -594,6 +612,16 @@ static int add_host_bridge_dport(struct device *match, void *arg)
> >>   	if (IS_ERR(dport))
> >>   		return PTR_ERR(dport);
> >>   
> >> +	dport->genport_coord = devm_kzalloc(dport->dport,

This needs to be the same device as was used to allocate @dport, and
that's not @dport->dport.

> >> +					    sizeof(*dport->genport_coord),
> >> +					    GFP_KERNEL);
> > 
> > It's pretty small - worth allocating separately?
> > 
> > Maybe add something on why to the patch description if there is another reason
> > for this dance.
> 
> My intention was to allow detection of whether the data exists or not 
> based on if the ptr is NULL. I'll add explanation in patch description.

A couple reactions, is a "zero" access coordinate not sufficient for
that?

Also, "genport" is an ACPI-ism and I was aiming for cxl-core objects
like cxl_dport to remain platform implementation independent. The
concept of a dport having a host-bridge access_coordinate is generic
though, so I would just rename this to "hb_access" or some other
host-bridge generic naming.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem
  2023-05-12 15:28 ` [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Jonathan Cameron
@ 2023-05-16 21:49   ` Dan Williams
  2023-05-17  8:50     ` Jonathan Cameron
  0 siblings, 1 reply; 36+ messages in thread
From: Dan Williams @ 2023-05-16 21:49 UTC (permalink / raw)
  To: Jonathan Cameron, Dave Jiang
  Cc: linux-cxl, Dan Williams, ira.weiny, vishal.l.verma,
	alison.schofield

Jonathan Cameron wrote:
> Hi Dave,
> 
> > The QTG ID for a device is retrieved via sending a _DSM method to the ACPI0017 device.
> > The _DSM expects an input package of 4 DWORDS that contains the read latency, write
> > latency, read bandwidth, and write banwidth. These are the caluclated numbers for the
> > path between the CXL device and the CPU. The QTG ID is also exported as a sysfs
> > attribute under the mem device memory partition type:
> > /sys/bus/cxl/devices/memX/ram/qos_class
> > /sys/bus/cxl/devices/memX/pmem/qos_class
> > Only the first QTG ID is exported.
> 
> The QTG DSM returning a list was done to allow for a case of mutual
> incompatibility between the first QTG that is returned for a particular
> performance point and the CFMWS that it points at.
> 
> CFMWS might say 'no pmem in here' but due to some RAM device that is a bit
> slow, we might end up with a QTG DSM response that says put it in that CFMWS.
> 
> Hence the fallback list.
> 
> That is currently hidden by this approach.  It makes things more complex, but
> I'd really like to see the whole of that list rather than just the first element
> presented for each region.  I think it's fine to let userspace then figure
> out if there is a missmatch.

There is some confusion here, the "Only the first QTG ID is exported"
statement is with respect to the case of multiple DSMAS entries per
partition. For the case of multiple platform QoS classes per single
DSMAS I would be ok if this qos_class returned a comma-separated
list/tuple.

So, for example, in a case where DSMAS0 for the 'ram' partition results
in QoS class-ids 0,1,2 and DSMAS1 for the 'ram' partition results in QoS
class-ids 3,4 then /sys/bus/cxl/devices/memX/ram/qos_class would be
allowed to report "0,1,2".

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 06/14] cxl: Store the access coordinates for the generic ports
  2023-05-16 21:13       ` Dan Williams
@ 2023-05-16 21:52         ` Dave Jiang
  0 siblings, 0 replies; 36+ messages in thread
From: Dave Jiang @ 2023-05-16 21:52 UTC (permalink / raw)
  To: Dan Williams, Jonathan Cameron
  Cc: linux-cxl, ira.weiny, vishal.l.verma, alison.schofield



On 5/16/23 2:13 PM, Dan Williams wrote:
> Dave Jiang wrote:
>>
>>
>> On 5/12/23 7:59 AM, Jonathan Cameron wrote:
>>> On Mon, 08 May 2023 13:47:29 -0700
>>> Dave Jiang <dave.jiang@intel.com> wrote:
>>>
>>>> Each CXL host bridge is represented by an ACPI0016 device. A generic port
>>>> device handle that is an ACPI device is represented by a string of
>>>> ACPI0016 device HID and UID. Create a device handle from the ACPI device
>>>> and retrieve the access coordinates from the stored memory targets. The
>>>> access coordinates are stored under the cxl_dport that is associated with
>>>> the CXL host bridge.
>>>>
>>>> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>>>> ---
>>>>    drivers/cxl/acpi.c |   28 ++++++++++++++++++++++++++++
>>>>    drivers/cxl/cxl.h  |    2 ++
>>>>    2 files changed, 30 insertions(+)
>>>>
>>>> diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
>>>> index f9b35e8fe810..675a4f423f4b 100644
>>>> --- a/drivers/cxl/acpi.c
>>>> +++ b/drivers/cxl/acpi.c
>>>> @@ -537,8 +537,26 @@ static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
>>>>    	return 0;
>>>>    }
>>>>    
>>>> +static int get_genport_coordinates(struct device *dev, struct cxl_dport *dport)
>>>> +{
>>>> +	struct acpi_device *hb = to_cxl_host_bridge(NULL, dev);
>>>> +	u8 handle[ACPI_SRAT_DEVICE_HANDLE_SIZE] = { 0 };
>>>> +	int rc;
>>>> +
>>>> +	/* ACPI spec 6.5 tABLE 5.65 */
>>>
>>> tABLE?
>>
>> ooops caps lock
>>
>>>
>>>> +	memcpy(handle, acpi_device_hid(hb), 8);
>>>> +	memcpy(&handle[8], acpi_device_uid(hb), 4);
>>>> +
>>>> +	rc = acpi_get_genport_coordinates(handle, dport->genport_coord);
>>>> +	if (rc)
>>>> +		return rc;
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>>    static int add_host_bridge_dport(struct device *match, void *arg)
>>>>    {
>>>> +	int ret;
>>>>    	acpi_status rc;
>>>>    	struct device *bridge;
>>>>    	unsigned long long uid;
>>>> @@ -594,6 +612,16 @@ static int add_host_bridge_dport(struct device *match, void *arg)
>>>>    	if (IS_ERR(dport))
>>>>    		return PTR_ERR(dport);
>>>>    
>>>> +	dport->genport_coord = devm_kzalloc(dport->dport,
> 
> This needs to be the same device as was used to allocate @dport, and
> that's not @dport->dport.

ok

> 
>>>> +					    sizeof(*dport->genport_coord),
>>>> +					    GFP_KERNEL);
>>>
>>> It's pretty small - worth allocating separately?
>>>
>>> Maybe add something on why to the patch description if there is another reason
>>> for this dance.
>>
>> My intention was to allow detection of whether the data exists or not
>> based on if the ptr is NULL. I'll add explanation in patch description.
> 
> A couple reactions, is a "zero" access coordinate not sufficient for
> that?

Probably. I can change. I was being paranoid.

> 
> Also, "genport" is an ACPI-ism and I was aiming for cxl-core objects
> like cxl_dport to remain platform implementation independent. The
> concept of a dport having a host-bridge access_coordinate is generic
> though, so I would just rename this to "hb_access" or some other
> host-bridge generic naming.

Ok

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem
  2023-05-16 21:49   ` Dan Williams
@ 2023-05-17  8:50     ` Jonathan Cameron
  0 siblings, 0 replies; 36+ messages in thread
From: Jonathan Cameron @ 2023-05-17  8:50 UTC (permalink / raw)
  To: Dan Williams
  Cc: Dave Jiang, linux-cxl, ira.weiny, vishal.l.verma,
	alison.schofield

On Tue, 16 May 2023 14:49:46 -0700
Dan Williams <dan.j.williams@intel.com> wrote:

> Jonathan Cameron wrote:
> > Hi Dave,
> >   
> > > The QTG ID for a device is retrieved via sending a _DSM method to the ACPI0017 device.
> > > The _DSM expects an input package of 4 DWORDS that contains the read latency, write
> > > latency, read bandwidth, and write banwidth. These are the caluclated numbers for the
> > > path between the CXL device and the CPU. The QTG ID is also exported as a sysfs
> > > attribute under the mem device memory partition type:
> > > /sys/bus/cxl/devices/memX/ram/qos_class
> > > /sys/bus/cxl/devices/memX/pmem/qos_class
> > > Only the first QTG ID is exported.  
> > 
> > The QTG DSM returning a list was done to allow for a case of mutual
> > incompatibility between the first QTG that is returned for a particular
> > performance point and the CFMWS that it points at.
> > 
> > CFMWS might say 'no pmem in here' but due to some RAM device that is a bit
> > slow, we might end up with a QTG DSM response that says put it in that CFMWS.
> > 
> > Hence the fallback list.
> > 
> > That is currently hidden by this approach.  It makes things more complex, but
> > I'd really like to see the whole of that list rather than just the first element
> > presented for each region.  I think it's fine to let userspace then figure
> > out if there is a missmatch.  
> 
> There is some confusion here, the "Only the first QTG ID is exported"
> statement is with respect to the case of multiple DSMAS entries per
> partition. For the case of multiple platform QoS classes per single
> DSMAS I would be ok if this qos_class returned a comma-separated
> list/tuple.
> 
> So, for example, in a case where DSMAS0 for the 'ram' partition results
> in QoS class-ids 0,1,2 and DSMAS1 for the 'ram' partition results in QoS
> class-ids 3,4 then /sys/bus/cxl/devices/memX/ram/qos_class would be
> allowed to report "0,1,2".
> 
Great, that works nicely.

Jonathan



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v5 14/14] cxl/mem: Add debugfs output for QTG related data
  2023-05-12 15:36   ` Jonathan Cameron
@ 2023-05-17 22:28     ` Dave Jiang
  0 siblings, 0 replies; 36+ messages in thread
From: Dave Jiang @ 2023-05-17 22:28 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-cxl, Dan Williams, ira.weiny, vishal.l.verma,
	alison.schofield



On 5/12/23 8:36 AM, Jonathan Cameron wrote:
> On Mon, 08 May 2023 13:48:16 -0700
> Dave Jiang <dave.jiang@intel.com> wrote:
> 
>> Add debugfs output to /sys/kernel/debug/cxl/memX/qtgmap
>> The debugfs attribute will dump out all the DSMAS ranges and the associated
>> QTG ID exported by the CXL device CDAT.
>>
>> Suggested-by: Dan Williams <dan.j.williams@intel.com>
>> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> 
> LTGM, though seems we haven't been keeping up with ABI docs for other
> stuff in debugfs. That wants fixing but is unrelated to this.
> 
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> 
>>
>> ---
>> v4:
>> - Use cxlds->qos_list instead of the stray cxlmd->qos_list
>> ---
>>   Documentation/ABI/testing/debugfs-cxl |   11 +++++++++++
>>   MAINTAINERS                           |    1 +
>>   drivers/cxl/mem.c                     |   17 +++++++++++++++++
>>   3 files changed, 29 insertions(+)
>>   create mode 100644 Documentation/ABI/testing/debugfs-cxl
>>
>> diff --git a/Documentation/ABI/testing/debugfs-cxl b/Documentation/ABI/testing/debugfs-cxl
>> new file mode 100644
>> index 000000000000..0f36eeb7e59b
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/debugfs-cxl
>> @@ -0,0 +1,11 @@
>> +What:		/sys/kernel/debug/cxl/memX/qtg_map
>> +Date:		Mar, 2023
>> +KernelVersion:	v6.4
>> +Contact:	linux-cxl@vger.kernel.org
>> +Description:
>> +		(RO) Entries of all Device Physical Address (DPA) ranges
>> +		provided by the device Coherent Device Attributes Table (CDAT)
>> +		Device Scoped Memory Affinity Structure (DSMAS) entries with
>> +		the matching QoS Throttling Group (QTG) id calculated from the
>> +		latency and bandwidth of the CXL path from the memory device
>> +		to the CPU.
> 
> Curious. This file should already exist as there is clearly more debugfs ABI
> from the code below.  Perhaps a precursor patch to create the file and document
> existing interfaces?

Looks like Alison got it into 6.4-rc1.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=50d527f52cbf0680c87d11a254383ca730c5c19f

I just need to wait for cxl/next to rebase to 6.4-rc so I can rebase the 
series.

> 
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index fd8c4c560f8d..256e4e57017c 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -5171,6 +5171,7 @@ M:	Ben Widawsky <bwidawsk@kernel.org>
>>   M:	Dan Williams <dan.j.williams@intel.com>
>>   L:	linux-cxl@vger.kernel.org
>>   S:	Maintained
>> +F:	Documentation/ABI/testing/debugfs-cxl
>>   F:	drivers/cxl/
>>   F:	include/uapi/linux/cxl_mem.h
>>   
>> diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
>> index 39c4b54f0715..587e261a7f76 100644
>> --- a/drivers/cxl/mem.c
>> +++ b/drivers/cxl/mem.c
>> @@ -45,6 +45,22 @@ static int cxl_mem_dpa_show(struct seq_file *file, void *data)
>>   	return 0;
>>   }
>>   
>> +static int cxl_mem_qtg_show(struct seq_file *file, void *data)
>> +{
>> +	struct device *dev = file->private;
>> +	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
>> +	struct cxl_dev_state *cxlds = cxlmd->cxlds;
>> +	struct perf_prop_entry *perf;
>> +
>> +	list_for_each_entry(perf, &cxlds->perf_list, list) {
>> +		seq_printf(file, "%08llx-%08llx : QoS Class: %u\n",
>> +			   perf->dpa_range.start, perf->dpa_range.end,
>> +			   perf->qos_class);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>   static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd,
>>   				 struct cxl_dport *parent_dport)
>>   {
>> @@ -117,6 +133,7 @@ static int cxl_mem_probe(struct device *dev)
>>   
>>   	dentry = cxl_debugfs_create_dir(dev_name(dev));
>>   	debugfs_create_devm_seqfile(dev, "dpamem", dentry, cxl_mem_dpa_show);
>> +	debugfs_create_devm_seqfile(dev, "qtgmap", dentry, cxl_mem_qtg_show);
>>   	rc = devm_add_action_or_reset(dev, remove_debugfs, dentry);
>>   	if (rc)
>>   		return rc;
>>
>>
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2023-05-17 22:28 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-08 20:46 [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Dave Jiang
2023-05-08 20:46 ` [PATCH v5 01/14] cxl: Add callback to parse the DSMAS subtables from CDAT Dave Jiang
2023-05-12 14:26   ` Jonathan Cameron
2023-05-08 20:47 ` [PATCH v5 02/14] cxl: Add callback to parse the DSLBIS subtable " Dave Jiang
2023-05-12 14:33   ` Jonathan Cameron
2023-05-08 20:47 ` [PATCH v5 03/14] cxl: Add callback to parse the SSLBIS " Dave Jiang
2023-05-12 14:41   ` Jonathan Cameron
2023-05-16 17:49     ` Dave Jiang
2023-05-08 20:47 ` [PATCH v5 04/14] cxl: Add support for _DSM Function for retrieving QTG ID Dave Jiang
2023-05-12 14:50   ` Jonathan Cameron
2023-05-08 20:47 ` [PATCH v5 05/14] cxl: Calculate and store PCI link latency for the downstream ports Dave Jiang
2023-05-08 20:47 ` [PATCH v5 06/14] cxl: Store the access coordinates for the generic ports Dave Jiang
2023-05-12 14:59   ` Jonathan Cameron
2023-05-16 20:58     ` Dave Jiang
2023-05-16 21:13       ` Dan Williams
2023-05-16 21:52         ` Dave Jiang
2023-05-08 20:47 ` [PATCH v5 07/14] cxl: Add helper function that calculate performance data for downstream ports Dave Jiang
2023-05-12 15:05   ` Jonathan Cameron
2023-05-08 20:47 ` [PATCH v5 08/14] cxl: Compute the entire CXL path latency and bandwidth data Dave Jiang
2023-05-12 15:09   ` Jonathan Cameron
2023-05-08 20:47 ` [PATCH v5 09/14] cxl: Wait Memory_Info_Valid before access memory related info Dave Jiang
2023-05-12 15:16   ` Jonathan Cameron
2023-05-08 20:47 ` [PATCH v5 10/14] cxl: Move identify and partition query from pci probe to port probe Dave Jiang
2023-05-12 15:17   ` Jonathan Cameron
2023-05-08 20:47 ` [PATCH v5 11/14] cxl: Move read_cdat_data() to after media is ready Dave Jiang
2023-05-12 15:18   ` Jonathan Cameron
2023-05-08 20:48 ` [PATCH v5 12/14] cxl: Store QTG IDs and related info to the CXL memory device context Dave Jiang
2023-05-12 15:30   ` Jonathan Cameron
2023-05-08 20:48 ` [PATCH v5 13/14] cxl: Export sysfs attributes for memory device QoS class Dave Jiang
2023-05-12 15:33   ` Jonathan Cameron
2023-05-08 20:48 ` [PATCH v5 14/14] cxl/mem: Add debugfs output for QTG related data Dave Jiang
2023-05-12 15:36   ` Jonathan Cameron
2023-05-17 22:28     ` Dave Jiang
2023-05-12 15:28 ` [PATCH v5 00/14] cxl: Add support for QTG ID retrieval for CXL subsystem Jonathan Cameron
2023-05-16 21:49   ` Dan Williams
2023-05-17  8:50     ` Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox