Skip to content

Commit 5485eb9

Browse files
committed
Merge branch 'for-6.3/cxl' into cxl/next
Merge the general CXL updates with fixes targeting v6.2-rc for v6.3. Resolve a conflict with the fix and move of cxl_report_and_clear() from pci.c to core/pci.c.
2 parents 711442e + 623c075 commit 5485eb9

File tree

25 files changed

+301
-136
lines changed

25 files changed

+301
-136
lines changed

Documentation/ABI/testing/sysfs-bus-cxl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,21 @@ Description:
9090
capability.
9191

9292

93+
What: /sys/bus/cxl/devices/{port,endpoint}X/parent_dport
94+
Date: January, 2023
95+
KernelVersion: v6.3
96+
97+
Description:
98+
(RO) CXL port objects are instantiated for each upstream port in
99+
a CXL/PCIe switch, and for each endpoint to map the
100+
corresponding memory device into the CXL port hierarchy. When a
101+
descendant CXL port (switch or endpoint) is enumerated it is
102+
useful to know which 'dport' object in the parent CXL port
103+
routes to this descendant. The 'parent_dport' symlink points to
104+
the device representing the downstream port of a CXL switch that
105+
routes to {port,endpoint}X.
106+
107+
93108
What: /sys/bus/cxl/devices/portX/dportY
94109
Date: June, 2021
95110
KernelVersion: v5.14

drivers/acpi/pci_root.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,9 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
10471047
if (!(root->osc_control_set & OSC_PCI_EXPRESS_DPC_CONTROL))
10481048
host_bridge->native_dpc = 0;
10491049

1050+
if (!(root->osc_ext_control_set & OSC_CXL_ERROR_REPORTING_CONTROL))
1051+
host_bridge->native_cxl_error = 0;
1052+
10501053
/*
10511054
* Evaluate the "PCI Boot Configuration" _DSM Function. If it
10521055
* exists and returns 0, we must preserve any PCI resource

drivers/cxl/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ config CXL_REGION_INVALIDATION_TEST
116116
depends on CXL_REGION
117117
help
118118
CXL Region management and security operations potentially invalidate
119-
the content of CPU caches without notifiying those caches to
119+
the content of CPU caches without notifying those caches to
120120
invalidate the affected cachelines. The CXL Region driver attempts
121121
to invalidate caches when those events occur. If that invalidation
122122
fails the region will fail to enable. Reasons for cache

drivers/cxl/acpi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct cxl_cxims_data {
1919

2020
/*
2121
* Find a targets entry (n) in the host bridge interleave list.
22-
* CXL Specfication 3.0 Table 9-22
22+
* CXL Specification 3.0 Table 9-22
2323
*/
2424
static int cxl_xor_calc_n(u64 hpa, struct cxl_cxims_data *cximsd, int iw,
2525
int ig)

drivers/cxl/core/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ obj-$(CONFIG_CXL_BUS) += cxl_core.o
33
obj-$(CONFIG_CXL_SUSPEND) += suspend.o
44

55
ccflags-y += -I$(srctree)/drivers/cxl
6+
CFLAGS_trace.o = -DTRACE_INCLUDE_PATH=. -I$(src)
7+
68
cxl_core-y := port.o
79
cxl_core-y += pmem.o
810
cxl_core-y += regs.o
911
cxl_core-y += memdev.o
1012
cxl_core-y += mbox.o
1113
cxl_core-y += pci.o
1214
cxl_core-y += hdm.o
15+
cxl_core-$(CONFIG_TRACING) += trace.o
1316
cxl_core-$(CONFIG_CXL_REGION) += region.o

drivers/cxl/core/mbox.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ int cxl_internal_send_cmd(struct cxl_dev_state *cxlds,
170170
out_size = mbox_cmd->size_out;
171171
min_out = mbox_cmd->min_out;
172172
rc = cxlds->mbox_send(cxlds, mbox_cmd);
173+
/*
174+
* EIO is reserved for a payload size mismatch and mbox_send()
175+
* may not return this error.
176+
*/
177+
if (WARN_ONCE(rc == -EIO, "Bad return code: -EIO"))
178+
return -ENXIO;
173179
if (rc)
174180
return rc;
175181

@@ -550,9 +556,9 @@ int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s)
550556
return 0;
551557
}
552558

553-
static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 size, u8 *out)
559+
static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 *size, u8 *out)
554560
{
555-
u32 remaining = size;
561+
u32 remaining = *size;
556562
u32 offset = 0;
557563

558564
while (remaining) {
@@ -576,6 +582,17 @@ static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 size, u8
576582
};
577583

578584
rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
585+
586+
/*
587+
* The output payload length that indicates the number
588+
* of valid bytes can be smaller than the Log buffer
589+
* size.
590+
*/
591+
if (rc == -EIO && mbox_cmd.size_out < xfer_size) {
592+
offset += mbox_cmd.size_out;
593+
break;
594+
}
595+
579596
if (rc < 0)
580597
return rc;
581598

@@ -584,6 +601,8 @@ static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 size, u8
584601
offset += xfer_size;
585602
}
586603

604+
*size = offset;
605+
587606
return 0;
588607
}
589608

@@ -610,11 +629,12 @@ static void cxl_walk_cel(struct cxl_dev_state *cxlds, size_t size, u8 *cel)
610629

611630
if (!cmd) {
612631
dev_dbg(cxlds->dev,
613-
"Opcode 0x%04x unsupported by driver", opcode);
632+
"Opcode 0x%04x unsupported by driver\n", opcode);
614633
continue;
615634
}
616635

617636
set_bit(cmd->info.id, cxlds->enabled_cmds);
637+
dev_dbg(cxlds->dev, "Opcode 0x%04x enabled\n", opcode);
618638
}
619639
}
620640

@@ -694,7 +714,7 @@ int cxl_enumerate_cmds(struct cxl_dev_state *cxlds)
694714
goto out;
695715
}
696716

697-
rc = cxl_xfer_log(cxlds, &uuid, size, log);
717+
rc = cxl_xfer_log(cxlds, &uuid, &size, log);
698718
if (rc) {
699719
kvfree(log);
700720
goto out;

drivers/cxl/core/pci.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <cxlmem.h>
1010
#include <cxl.h>
1111
#include "core.h"
12+
#include "trace.h"
1213

1314
/**
1415
* DOC: cxl core pci
@@ -622,3 +623,117 @@ void read_cdat_data(struct cxl_port *port)
622623
}
623624
}
624625
EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL);
626+
627+
void cxl_cor_error_detected(struct pci_dev *pdev)
628+
{
629+
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
630+
struct cxl_memdev *cxlmd = cxlds->cxlmd;
631+
struct device *dev = &cxlmd->dev;
632+
void __iomem *addr;
633+
u32 status;
634+
635+
if (!cxlds->regs.ras)
636+
return;
637+
638+
addr = cxlds->regs.ras + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
639+
status = readl(addr);
640+
if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
641+
writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
642+
trace_cxl_aer_correctable_error(dev, status);
643+
}
644+
}
645+
EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, CXL);
646+
647+
/* CXL spec rev3.0 8.2.4.16.1 */
648+
static void header_log_copy(struct cxl_dev_state *cxlds, u32 *log)
649+
{
650+
void __iomem *addr;
651+
u32 *log_addr;
652+
int i, log_u32_size = CXL_HEADERLOG_SIZE / sizeof(u32);
653+
654+
addr = cxlds->regs.ras + CXL_RAS_HEADER_LOG_OFFSET;
655+
log_addr = log;
656+
657+
for (i = 0; i < log_u32_size; i++) {
658+
*log_addr = readl(addr);
659+
log_addr++;
660+
addr += sizeof(u32);
661+
}
662+
}
663+
664+
/*
665+
* Log the state of the RAS status registers and prepare them to log the
666+
* next error status. Return 1 if reset needed.
667+
*/
668+
static bool cxl_report_and_clear(struct cxl_dev_state *cxlds)
669+
{
670+
struct cxl_memdev *cxlmd = cxlds->cxlmd;
671+
struct device *dev = &cxlmd->dev;
672+
u32 hl[CXL_HEADERLOG_SIZE_U32];
673+
void __iomem *addr;
674+
u32 status;
675+
u32 fe;
676+
677+
if (!cxlds->regs.ras)
678+
return false;
679+
680+
addr = cxlds->regs.ras + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
681+
status = readl(addr);
682+
if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
683+
return false;
684+
685+
/* If multiple errors, log header points to first error from ctrl reg */
686+
if (hweight32(status) > 1) {
687+
void __iomem *rcc_addr =
688+
cxlds->regs.ras + CXL_RAS_CAP_CONTROL_OFFSET;
689+
690+
fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK,
691+
readl(rcc_addr)));
692+
} else {
693+
fe = status;
694+
}
695+
696+
header_log_copy(cxlds, hl);
697+
trace_cxl_aer_uncorrectable_error(dev, status, fe, hl);
698+
writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
699+
700+
return true;
701+
}
702+
703+
pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
704+
pci_channel_state_t state)
705+
{
706+
struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
707+
struct cxl_memdev *cxlmd = cxlds->cxlmd;
708+
struct device *dev = &cxlmd->dev;
709+
bool ue;
710+
711+
/*
712+
* A frozen channel indicates an impending reset which is fatal to
713+
* CXL.mem operation, and will likely crash the system. On the off
714+
* chance the situation is recoverable dump the status of the RAS
715+
* capability registers and bounce the active state of the memdev.
716+
*/
717+
ue = cxl_report_and_clear(cxlds);
718+
719+
switch (state) {
720+
case pci_channel_io_normal:
721+
if (ue) {
722+
device_release_driver(dev);
723+
return PCI_ERS_RESULT_NEED_RESET;
724+
}
725+
return PCI_ERS_RESULT_CAN_RECOVER;
726+
case pci_channel_io_frozen:
727+
dev_warn(&pdev->dev,
728+
"%s: frozen state error detected, disable CXL.mem\n",
729+
dev_name(dev));
730+
device_release_driver(dev);
731+
return PCI_ERS_RESULT_NEED_RESET;
732+
case pci_channel_io_perm_failure:
733+
dev_warn(&pdev->dev,
734+
"failure state error detected, request disconnect\n");
735+
return PCI_ERS_RESULT_DISCONNECT;
736+
}
737+
return PCI_ERS_RESULT_NEED_RESET;
738+
}
739+
EXPORT_SYMBOL_NS_GPL(cxl_error_detected, CXL);

drivers/cxl/core/port.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,29 @@ static int devm_cxl_link_uport(struct device *host, struct cxl_port *port)
583583
return devm_add_action_or_reset(host, cxl_unlink_uport, port);
584584
}
585585

586+
static void cxl_unlink_parent_dport(void *_port)
587+
{
588+
struct cxl_port *port = _port;
589+
590+
sysfs_remove_link(&port->dev.kobj, "parent_dport");
591+
}
592+
593+
static int devm_cxl_link_parent_dport(struct device *host,
594+
struct cxl_port *port,
595+
struct cxl_dport *parent_dport)
596+
{
597+
int rc;
598+
599+
if (!parent_dport)
600+
return 0;
601+
602+
rc = sysfs_create_link(&port->dev.kobj, &parent_dport->dport->kobj,
603+
"parent_dport");
604+
if (rc)
605+
return rc;
606+
return devm_add_action_or_reset(host, cxl_unlink_parent_dport, port);
607+
}
608+
586609
static struct lock_class_key cxl_port_key;
587610

588611
static struct cxl_port *cxl_port_alloc(struct device *uport,
@@ -692,6 +715,10 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host,
692715
if (rc)
693716
return ERR_PTR(rc);
694717

718+
rc = devm_cxl_link_parent_dport(host, port, parent_dport);
719+
if (rc)
720+
return ERR_PTR(rc);
721+
695722
return port;
696723

697724
err:
@@ -1137,7 +1164,7 @@ static struct cxl_port *find_cxl_port_at(struct cxl_port *parent_port,
11371164
}
11381165

11391166
/*
1140-
* All users of grandparent() are using it to walk PCIe-like swich port
1167+
* All users of grandparent() are using it to walk PCIe-like switch port
11411168
* hierarchy. A PCIe switch is comprised of a bridge device representing the
11421169
* upstream switch port and N bridges representing downstream switch ports. When
11431170
* bridges stack the grand-parent of a downstream switch port is another
@@ -1164,6 +1191,7 @@ static void delete_endpoint(void *data)
11641191

11651192
device_lock(parent);
11661193
if (parent->driver && !endpoint->dead) {
1194+
devm_release_action(parent, cxl_unlink_parent_dport, endpoint);
11671195
devm_release_action(parent, cxl_unlink_uport, endpoint);
11681196
devm_release_action(parent, unregister_port, endpoint);
11691197
}
@@ -1194,6 +1222,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, CXL);
11941222
*/
11951223
static void delete_switch_port(struct cxl_port *port)
11961224
{
1225+
devm_release_action(port->dev.parent, cxl_unlink_parent_dport, port);
11971226
devm_release_action(port->dev.parent, cxl_unlink_uport, port);
11981227
devm_release_action(port->dev.parent, unregister_port, port);
11991228
}

drivers/cxl/core/region.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,22 @@ static int cxl_region_decode_reset(struct cxl_region *cxlr, int count)
157157
return 0;
158158
}
159159

160+
static int commit_decoder(struct cxl_decoder *cxld)
161+
{
162+
struct cxl_switch_decoder *cxlsd = NULL;
163+
164+
if (cxld->commit)
165+
return cxld->commit(cxld);
166+
167+
if (is_switch_decoder(&cxld->dev))
168+
cxlsd = to_cxl_switch_decoder(&cxld->dev);
169+
170+
if (dev_WARN_ONCE(&cxld->dev, !cxlsd || cxlsd->nr_targets > 1,
171+
"->commit() is required\n"))
172+
return -ENXIO;
173+
return 0;
174+
}
175+
160176
static int cxl_region_decode_commit(struct cxl_region *cxlr)
161177
{
162178
struct cxl_region_params *p = &cxlr->params;
@@ -175,8 +191,7 @@ static int cxl_region_decode_commit(struct cxl_region *cxlr)
175191
iter = to_cxl_port(iter->dev.parent)) {
176192
cxl_rr = cxl_rr_load(iter, cxlr);
177193
cxld = cxl_rr->decoder;
178-
if (cxld->commit)
179-
rc = cxld->commit(cxld);
194+
rc = commit_decoder(cxld);
180195
if (rc)
181196
break;
182197
}
@@ -401,7 +416,7 @@ static ssize_t interleave_granularity_store(struct device *dev,
401416
* When the host-bridge is interleaved, disallow region granularity !=
402417
* root granularity. Regions with a granularity less than the root
403418
* interleave result in needing multiple endpoints to support a single
404-
* slot in the interleave (possible to suport in the future). Regions
419+
* slot in the interleave (possible to support in the future). Regions
405420
* with a granularity greater than the root interleave result in invalid
406421
* DPA translations (invalid to support).
407422
*/
@@ -1969,7 +1984,7 @@ static int cxl_region_invalidate_memregion(struct cxl_region *cxlr)
19691984

19701985
if (!cpu_cache_has_invalidate_memregion()) {
19711986
if (IS_ENABLED(CONFIG_CXL_REGION_INVALIDATION_TEST)) {
1972-
dev_warn(
1987+
dev_warn_once(
19731988
&cxlr->dev,
19741989
"Bypassing cpu_cache_invalidate_memregion() for testing!\n");
19751990
clear_bit(CXL_REGION_F_INCOHERENT, &cxlr->flags);

drivers/cxl/core/trace.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
3+
4+
#define CREATE_TRACE_POINTS
5+
#include "trace.h"

0 commit comments

Comments
 (0)