From: Ben Widawsky <ben.widawsky@intel.com>
To: linux-cxl@vger.kernel.org
Cc: Ben Widawsky <ben.widawsky@intel.com>,
kernel test robot <lkp@intel.com>,
Alison Schofield <alison.schofield@intel.com>,
Dan Williams <dan.j.williams@intel.com>,
Ira Weiny <ira.weiny@intel.com>,
Jonathan Cameron <Jonathan.Cameron@Huawei.com>,
Vishal Verma <vishal.l.verma@intel.com>
Subject: [PATCH v2 07/14] cxl: Cache and pass DVSEC ranges
Date: Wed, 1 Dec 2021 20:37:43 -0800 [thread overview]
Message-ID: <20211202043750.3501494-8-ben.widawsky@intel.com> (raw)
In-Reply-To: <20211202043750.3501494-1-ben.widawsky@intel.com>
CXL 1.1 specification provided a mechanism for mapping an address space
of a CXL device. That functionality is known as a "range" and can be
programmed through PCIe DVSEC. In addition to this, the specification
defines an active bit which a device will expose through the same DVSEC
to notify system software that memory is initialized and ready.
While CXL 2.0 introduces a more powerful mechanism called HDM decoders
that are controlled by MMIO behind a PCIe BAR, the spec does allow the
1.1 style mapping to still be present. In such a case, when the CXL
driver takes over, if it were to enable HDM decoding and there was an
actively used range, things would likely blow up, in particular if it
wasn't an identical mapping.
This patch caches the relevant information which the cxl_mem driver will
need to make the proper decision and passes it along.
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Ben Widawsky <ben.widawsky@intel.com>
---
Changes since v1:
- Fix unused size (LKP)
- Use struct range
- Get rid of macros for pci config reads (Jonathan)
---
drivers/cxl/cxlmem.h | 15 ++++++
drivers/cxl/pci.c | 121 +++++++++++++++++++++++++++++++++++++++++++
drivers/cxl/pci.h | 13 +++++
3 files changed, 149 insertions(+)
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 3ef3c652599e..8d0a14c53518 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -89,6 +89,18 @@ struct cxl_mbox_cmd {
*/
#define CXL_CAPACITY_MULTIPLIER SZ_256M
+/**
+ * struct cxl_endpoint_dvsec_info - Cached DVSEC info
+ * @mem_enabled: cached value of mem_enabled in the DVSEC, PCIE_DEVICE
+ * @ranges: Number of active HDM ranges this device uses.
+ * @dvsec_range: cached attributes of the ranges in the DVSEC, PCIE_DEVICE
+ */
+struct cxl_endpoint_dvsec_info {
+ bool mem_enabled;
+ int ranges;
+ struct range dvsec_range[2];
+};
+
/**
* struct cxl_dev_state - The driver device state
*
@@ -117,6 +129,7 @@ struct cxl_mbox_cmd {
* @active_persistent_bytes: sum of hard + soft persistent
* @next_volatile_bytes: volatile capacity change pending device reset
* @next_persistent_bytes: persistent capacity change pending device reset
+ * @info: Cached DVSEC information about the device.
* @mbox_send: @dev specific transport for transmitting mailbox commands
*
* See section 8.2.9.5.2 Capacity Configuration and Label Storage for
@@ -147,6 +160,8 @@ struct cxl_dev_state {
u64 next_volatile_bytes;
u64 next_persistent_bytes;
+ struct cxl_endpoint_dvsec_info *info;
+
int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd);
};
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 09ff82b4ea06..4e00abde5dbb 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -435,8 +435,121 @@ static int cxl_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
return rc;
}
+static int wait_for_valid(struct cxl_dev_state *cxlds)
+{
+ struct pci_dev *pdev = to_pci_dev(cxlds->dev);
+ const unsigned long timeout = jiffies + HZ;
+ int d = cxlds->device_dvsec;
+ bool valid;
+
+ do {
+ u32 temp;
+ int rc;
+
+ rc = pci_read_config_dword(pdev,
+ d + CXL_DVSEC_PCIE_DEVICE_RANGE_SIZE_LOW_OFFSET(0),
+ &temp);
+ if (rc)
+ return -ENXIO;
+
+ /*
+ * Memory_Info_Valid: When set, indicates that the CXL Range 1
+ * Size high and Size Low registers are valid. Must be set
+ * within 1 second of deassertion of reset to CXL device.
+ */
+ valid = FIELD_GET(CXL_DVSEC_PCIE_DEVICE_MEM_INFO_VALID, temp);
+ if (valid)
+ break;
+ cpu_relax();
+ } while (!time_after(jiffies, timeout));
+
+ return valid ? 0 : -ETIMEDOUT;
+}
+
+static struct cxl_endpoint_dvsec_info *dvsec_ranges(struct cxl_dev_state *cxlds)
+{
+ struct pci_dev *pdev = to_pci_dev(cxlds->dev);
+ struct cxl_endpoint_dvsec_info *info;
+ int d = cxlds->device_dvsec;
+ int hdm_count, rc, i;
+ u16 cap, ctrl;
+
+ rc = pci_read_config_word(pdev, d + CXL_DVSEC_PCIE_DEVICE_CAP_OFFSET, &cap);
+ if (rc)
+ return ERR_PTR(-ENXIO);
+ rc = pci_read_config_word(pdev, d + CXL_DVSEC_PCIE_DEVICE_CTRL_OFFSET, &ctrl);
+ if (rc)
+ return ERR_PTR(-ENXIO);
+
+ if (!(cap & CXL_DVSEC_PCIE_DEVICE_MEM_CAPABLE))
+ return ERR_PTR(-ENODEV);
+
+ /*
+ * It is not allowed by spec for MEM.capable to be set and have 0 HDM
+ * decoders. As this driver is for a spec defined class code which must
+ * be CXL.mem capable, there is no point in continuing.
+ */
+ hdm_count = FIELD_GET(CXL_DVSEC_PCIE_DEVICE_HDM_COUNT_MASK, cap);
+ if (!hdm_count || hdm_count > 2)
+ return ERR_PTR(-EINVAL);
+
+ rc = wait_for_valid(cxlds);
+ if (rc)
+ return ERR_PTR(rc);
+
+ info = devm_kzalloc(cxlds->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ info->mem_enabled = FIELD_GET(CXL_DVSEC_PCIE_DEVICE_MEM_ENABLE, ctrl);
+
+ for (i = 0; i < hdm_count; i++) {
+ u64 base, size;
+ u32 temp;
+
+ rc = pci_read_config_dword(pdev,
+ d + CXL_DVSEC_PCIE_DEVICE_RANGE_SIZE_HIGH_OFFSET(i),
+ &temp);
+ if (rc)
+ continue;
+ size = (u64)temp << 32;
+
+ rc = pci_read_config_dword(pdev,
+ d + CXL_DVSEC_PCIE_DEVICE_RANGE_SIZE_LOW_OFFSET(i),
+ &temp);
+ if (rc)
+ continue;
+ size |= temp & CXL_DVSEC_PCIE_DEVICE_MEM_SIZE_LOW_MASK;
+
+ rc = pci_read_config_dword(pdev,
+ d + CXL_DVSEC_PCIE_DEVICE_RANGE_BASE_HIGH_OFFSET(i),
+ &temp);
+ if (rc)
+ continue;
+ base = (u64)temp << 32;
+
+ rc = pci_read_config_dword(pdev,
+ d + CXL_DVSEC_PCIE_DEVICE_RANGE_BASE_LOW_OFFSET(i),
+ &temp);
+ if (rc)
+ continue;
+ base |= temp & CXL_DVSEC_PCIE_DEVICE_MEM_BASE_LOW_MASK;
+
+ info->dvsec_range[i] = (struct range) {
+ .start = base,
+ .end = base + size - 1
+ };
+
+ if (size)
+ info->ranges++;
+ }
+
+ return info;
+}
+
static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ struct cxl_endpoint_dvsec_info *info;
struct cxl_register_map map;
struct cxl_memdev *cxlmd;
struct cxl_dev_state *cxlds;
@@ -490,6 +603,14 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (rc)
return rc;
+ info = dvsec_ranges(cxlds);
+ if (IS_ERR(info))
+ dev_err(&pdev->dev,
+ "Failed to get DVSEC range information (%ld)\n",
+ PTR_ERR(info));
+ else
+ cxlds->info = info;
+
cxlmd = devm_cxl_add_memdev(cxlds);
if (IS_ERR(cxlmd))
return PTR_ERR(cxlmd);
diff --git a/drivers/cxl/pci.h b/drivers/cxl/pci.h
index f418272dbe38..7eb38030e376 100644
--- a/drivers/cxl/pci.h
+++ b/drivers/cxl/pci.h
@@ -15,6 +15,19 @@
/* CXL 2.0 8.1.3: PCIe DVSEC for CXL Device */
#define CXL_DVSEC_PCIE_DEVICE 0
+#define CXL_DVSEC_PCIE_DEVICE_CAP_OFFSET 0xA
+#define CXL_DVSEC_PCIE_DEVICE_MEM_CAPABLE BIT(2)
+#define CXL_DVSEC_PCIE_DEVICE_HDM_COUNT_MASK GENMASK(5, 4)
+#define CXL_DVSEC_PCIE_DEVICE_CTRL_OFFSET 0xC
+#define CXL_DVSEC_PCIE_DEVICE_MEM_ENABLE BIT(2)
+#define CXL_DVSEC_PCIE_DEVICE_RANGE_SIZE_HIGH_OFFSET(i) (0x18 + (i * 0x10))
+#define CXL_DVSEC_PCIE_DEVICE_RANGE_SIZE_LOW_OFFSET(i) (0x1C + (i * 0x10))
+#define CXL_DVSEC_PCIE_DEVICE_MEM_INFO_VALID BIT(0)
+#define CXL_DVSEC_PCIE_DEVICE_MEM_ACTIVE BIT(1)
+#define CXL_DVSEC_PCIE_DEVICE_MEM_SIZE_LOW_MASK GENMASK(31, 28)
+#define CXL_DVSEC_PCIE_DEVICE_RANGE_BASE_HIGH_OFFSET(i) (0x20 + (i * 0x10))
+#define CXL_DVSEC_PCIE_DEVICE_RANGE_BASE_LOW_OFFSET(i) (0x24 + (i * 0x10))
+#define CXL_DVSEC_PCIE_DEVICE_MEM_BASE_LOW_MASK GENMASK(31, 28)
/* CXL 2.0 8.1.4: Non-CXL Function Map DVSEC */
#define CXL_DVSEC_FUNCTION_MAP 2
--
2.34.1
next prev parent reply other threads:[~2021-12-02 4:40 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-12-02 4:37 [PATCH v2 00/14] Add drivers for CXL ports and mem devices Ben Widawsky
2021-12-02 4:37 ` [PATCH v2 01/14] cxl/core: Add, document, and tighten up decoder APIs Ben Widawsky
2021-12-06 10:51 ` Jonathan Cameron
2021-12-02 4:37 ` [PATCH v2 02/14] cxl: Introduce endpoint decoders Ben Widawsky
2021-12-02 4:37 ` [PATCH v2 03/14] cxl/core: Move target population locking to caller Ben Widawsky
2021-12-02 4:37 ` [PATCH v2 04/14] cxl: Introduce topology host registration Ben Widawsky
2021-12-02 5:58 ` Dan Williams
2021-12-03 21:06 ` Dan Williams
2021-12-04 3:21 ` Ben Widawsky
2021-12-02 4:37 ` [PATCH v2 05/14] cxl/core: Store global list of root ports Ben Widawsky
2021-12-02 4:37 ` [PATCH v2 06/14] cxl/pci: Cache device DVSEC offset Ben Widawsky
2021-12-02 4:37 ` Ben Widawsky [this message]
2021-12-02 4:37 ` [PATCH v2 08/14] cxl/pci: Implement wait for media active Ben Widawsky
2021-12-02 4:37 ` [PATCH v2 09/14] cxl/pci: Store component register base in cxlds Ben Widawsky
2021-12-02 4:37 ` [PATCH v2 10/14] cxl: Make passthrough decoder init implicit Ben Widawsky
2021-12-02 4:37 ` [PATCH v2 11/14] cxl/port: Introduce a port driver Ben Widawsky
2021-12-02 6:36 ` Dan Williams
2021-12-02 4:37 ` [PATCH v2 12/14] cxl: Unify port enumeration for decoders Ben Widawsky
2021-12-02 4:37 ` [PATCH v2 13/14] cxl/port: Cleanup adding passthrough decoders Ben Widawsky
2021-12-02 4:37 ` [PATCH v2 14/14] cxl/mem: Introduce cxl_mem driver Ben Widawsky
2021-12-04 4:07 ` Dan Williams
2021-12-15 17:25 ` [PATCH v2 00/14] Add drivers for CXL ports and mem devices Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211202043750.3501494-8-ben.widawsky@intel.com \
--to=ben.widawsky@intel.com \
--cc=Jonathan.Cameron@Huawei.com \
--cc=alison.schofield@intel.com \
--cc=dan.j.williams@intel.com \
--cc=ira.weiny@intel.com \
--cc=linux-cxl@vger.kernel.org \
--cc=lkp@intel.com \
--cc=vishal.l.verma@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.