Skip to content

Commit 7acc137

Browse files
committed
Merge tag 'cxl-for-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
Pull compute express link updates from Dan Williams: "DOE support is promoted from drivers/cxl/ to drivers/pci/ with Bjorn's blessing, and the CXL core continues to mature its media management capabilities with support for listing and injecting media errors. Some late fixes that missed v6.3-final are also included: - Refactor the DOE infrastructure (Data Object Exchange PCI-config-cycle mailbox) to be a facility of the PCI core rather than the CXL core. This is foundational for upcoming support for PCI device-attestation and PCIe / CXL link encryption. - Add support for retrieving and injecting poison for CXL memory expanders. This enabling uses trace-events to convey CXL media error records to user tooling. It includes translation of device-local addresses (DPA) to system physical addresses (SPA) and their corresponding CXL region. - Fixes for decoder enumeration that missed v6.3-final - Miscellaneous fixups" * tag 'cxl-for-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl: (38 commits) cxl/test: Add mock test for set_timestamp cxl/mbox: Update CMD_RC_TABLE tools/testing/cxl: Require CONFIG_DEBUG_FS tools/testing/cxl: Add a sysfs attr to test poison inject limits tools/testing/cxl: Use injected poison for get poison list tools/testing/cxl: Mock the Clear Poison mailbox command tools/testing/cxl: Mock the Inject Poison mailbox command cxl/mem: Add debugfs attributes for poison inject and clear cxl/memdev: Trace inject and clear poison as cxl_poison events cxl/memdev: Warn of poison inject or clear to a mapped region cxl/memdev: Add support for the Clear Poison mailbox command cxl/memdev: Add support for the Inject Poison mailbox command tools/testing/cxl: Mock support for Get Poison List cxl/trace: Add an HPA to cxl_poison trace events cxl/region: Provide region info to the cxl_poison trace event cxl/memdev: Add trigger_poison_list sysfs attribute cxl/trace: Add TRACE support for CXL media-error records cxl/mbox: Add GET_POISON_LIST mailbox command cxl/mbox: Initialize the poison state cxl/mbox: Restrict poison cmds to debugfs cxl_raw_allow_all ...
2 parents 10de638 + fd35fdc commit 7acc137

File tree

25 files changed

+1583
-313
lines changed

25 files changed

+1583
-313
lines changed

.clang-format

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,6 @@ ForEachMacros:
521521
- 'of_property_for_each_u32'
522522
- 'pci_bus_for_each_resource'
523523
- 'pci_dev_for_each_resource'
524-
- 'pci_doe_for_each_off'
525524
- 'pcl_for_each_chunk'
526525
- 'pcl_for_each_segment'
527526
- 'pcm_for_each_format'

Documentation/ABI/testing/debugfs-cxl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
What: /sys/kernel/debug/cxl/memX/inject_poison
2+
Date: April, 2023
3+
KernelVersion: v6.4
4+
5+
Description:
6+
(WO) When a Device Physical Address (DPA) is written to this
7+
attribute, the memdev driver sends an inject poison command to
8+
the device for the specified address. The DPA must be 64-byte
9+
aligned and the length of the injected poison is 64-bytes. If
10+
successful, the device returns poison when the address is
11+
accessed through the CXL.mem bus. Injecting poison adds the
12+
address to the device's Poison List and the error source is set
13+
to Injected. In addition, the device adds a poison creation
14+
event to its internal Informational Event log, updates the
15+
Event Status register, and if configured, interrupts the host.
16+
It is not an error to inject poison into an address that
17+
already has poison present and no error is returned. The
18+
inject_poison attribute is only visible for devices supporting
19+
the capability.
20+
21+
22+
What: /sys/kernel/debug/memX/clear_poison
23+
Date: April, 2023
24+
KernelVersion: v6.4
25+
26+
Description:
27+
(WO) When a Device Physical Address (DPA) is written to this
28+
attribute, the memdev driver sends a clear poison command to
29+
the device for the specified address. Clearing poison removes
30+
the address from the device's Poison List and writes 0 (zero)
31+
for 64 bytes starting at address. It is not an error to clear
32+
poison from an address that does not have poison set. If the
33+
device cannot clear poison from the address, -ENXIO is returned.
34+
The clear_poison attribute is only visible for devices
35+
supporting the capability.

Documentation/ABI/testing/sysfs-bus-cxl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,3 +415,17 @@ Description:
415415
1), and checks that the hardware accepts the commit request.
416416
Reading this value indicates whether the region is committed or
417417
not.
418+
419+
420+
What: /sys/bus/cxl/devices/memX/trigger_poison_list
421+
Date: April, 2023
422+
KernelVersion: v6.4
423+
424+
Description:
425+
(WO) When a boolean 'true' is written to this attribute the
426+
memdev driver retrieves the poison list from the device. The
427+
list consists of addresses that are poisoned, or would result
428+
in poison if accessed, and the source of the poison. This
429+
attribute is only visible for devices supporting the
430+
capability. The retrieved errors are logged as kernel
431+
events when cxl_poison event tracing is enabled.

drivers/cxl/core/core.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled);
2525
#define CXL_DAX_REGION_TYPE(x) (&cxl_dax_region_type)
2626
int cxl_region_init(void);
2727
void cxl_region_exit(void);
28+
int cxl_get_poison_by_endpoint(struct cxl_port *port);
2829
#else
30+
static inline int cxl_get_poison_by_endpoint(struct cxl_port *port)
31+
{
32+
return 0;
33+
}
2934
static inline void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled)
3035
{
3136
}
@@ -64,4 +69,10 @@ int cxl_memdev_init(void);
6469
void cxl_memdev_exit(void);
6570
void cxl_mbox_init(void);
6671

72+
enum cxl_poison_trace_type {
73+
CXL_POISON_TRACE_LIST,
74+
CXL_POISON_TRACE_INJECT,
75+
CXL_POISON_TRACE_CLEAR,
76+
};
77+
6778
#endif /* __CXL_CORE_H__ */

drivers/cxl/core/hdm.c

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
3-
#include <linux/io-64-nonatomic-hi-lo.h>
43
#include <linux/seq_file.h>
54
#include <linux/device.h>
65
#include <linux/delay.h>
@@ -93,8 +92,9 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb,
9392

9493
cxl_probe_component_regs(&port->dev, crb, &map.component_map);
9594
if (!map.component_map.hdm_decoder.valid) {
96-
dev_err(&port->dev, "HDM decoder registers invalid\n");
97-
return -ENXIO;
95+
dev_dbg(&port->dev, "HDM decoder registers not implemented\n");
96+
/* unique error code to indicate no HDM decoder capability */
97+
return -ENODEV;
9898
}
9999

100100
return cxl_map_component_regs(&port->dev, regs, &map,
@@ -130,6 +130,14 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
130130
*/
131131
for (i = 0; i < cxlhdm->decoder_count; i++) {
132132
ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i));
133+
dev_dbg(&info->port->dev,
134+
"decoder%d.%d: committed: %ld base: %#x_%.8x size: %#x_%.8x\n",
135+
info->port->id, i,
136+
FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl),
137+
readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(i)),
138+
readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(i)),
139+
readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(i)),
140+
readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(i)));
133141
if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl))
134142
return false;
135143
}
@@ -269,8 +277,11 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
269277

270278
lockdep_assert_held_write(&cxl_dpa_rwsem);
271279

272-
if (!len)
273-
goto success;
280+
if (!len) {
281+
dev_warn(dev, "decoder%d.%d: empty reservation attempted\n",
282+
port->id, cxled->cxld.id);
283+
return -EINVAL;
284+
}
274285

275286
if (cxled->dpa_res) {
276287
dev_dbg(dev, "decoder%d.%d: existing allocation %pr assigned\n",
@@ -323,7 +334,6 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled,
323334
cxled->mode = CXL_DECODER_MIXED;
324335
}
325336

326-
success:
327337
port->hdm_end++;
328338
get_device(&cxled->cxld.dev);
329339
return 0;
@@ -783,8 +793,8 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
783793
int *target_map, void __iomem *hdm, int which,
784794
u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)
785795
{
796+
u64 size, base, skip, dpa_size, lo, hi;
786797
struct cxl_endpoint_decoder *cxled;
787-
u64 size, base, skip, dpa_size;
788798
bool committed;
789799
u32 remainder;
790800
int i, rc;
@@ -799,8 +809,12 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
799809
which, info);
800810

801811
ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which));
802-
base = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which));
803-
size = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which));
812+
lo = readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which));
813+
hi = readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(which));
814+
base = (hi << 32) + lo;
815+
lo = readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which));
816+
hi = readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(which));
817+
size = (hi << 32) + lo;
804818
committed = !!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED);
805819
cxld->commit = cxl_decoder_commit;
806820
cxld->reset = cxl_decoder_reset;
@@ -833,6 +847,13 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
833847
port->id, cxld->id);
834848
return -ENXIO;
835849
}
850+
851+
if (size == 0) {
852+
dev_warn(&port->dev,
853+
"decoder%d.%d: Committed with zero size\n",
854+
port->id, cxld->id);
855+
return -ENXIO;
856+
}
836857
port->commit_end = cxld->id;
837858
} else {
838859
/* unless / until type-2 drivers arrive, assume type-3 */
@@ -855,9 +876,14 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
855876
if (rc)
856877
return rc;
857878

879+
dev_dbg(&port->dev, "decoder%d.%d: range: %#llx-%#llx iw: %d ig: %d\n",
880+
port->id, cxld->id, cxld->hpa_range.start, cxld->hpa_range.end,
881+
cxld->interleave_ways, cxld->interleave_granularity);
882+
858883
if (!info) {
859-
target_list.value =
860-
ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which));
884+
lo = readl(hdm + CXL_HDM_DECODER0_TL_LOW(which));
885+
hi = readl(hdm + CXL_HDM_DECODER0_TL_HIGH(which));
886+
target_list.value = (hi << 32) + lo;
861887
for (i = 0; i < cxld->interleave_ways; i++)
862888
target_map[i] = target_list.target_id[i];
863889

@@ -874,7 +900,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
874900
port->id, cxld->id, size, cxld->interleave_ways);
875901
return -ENXIO;
876902
}
877-
skip = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SKIP_LOW(which));
903+
lo = readl(hdm + CXL_HDM_DECODER0_SKIP_LOW(which));
904+
hi = readl(hdm + CXL_HDM_DECODER0_SKIP_HIGH(which));
905+
skip = (hi << 32) + lo;
878906
cxled = to_cxl_endpoint_decoder(&cxld->dev);
879907
rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip);
880908
if (rc) {

0 commit comments

Comments
 (0)