Skip to content

Commit dd72945

Browse files
committed
Merge tag 'cxl-for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
Pull cxl updates from Dan Williams: "More preparation and plumbing work in the CXL subsystem. From an end user perspective the highlight here is lighting up the CXL Persistent Memory related commands (label read / write) with the generic ioctl() front-end in LIBNVDIMM. Otherwise, the ability to instantiate new persistent and volatile memory regions is still on track for v5.17. Summary: - Fix support for platforms that do not enumerate every ACPI0016 (CXL Host Bridge) in the CHBS (ACPI Host Bridge Structure). - Introduce a common pci_find_dvsec_capability() helper, clean up open coded implementations in various drivers. - Add 'cxl_test' for regression testing CXL subsystem ABIs. 'cxl_test' is a module built from tools/testing/cxl/ that mocks up a CXL topology to augment the nascent support for emulation of CXL devices in QEMU. - Convert libnvdimm to use the uuid API. - Complete the definition of CXL namespace labels in libnvdimm. - Tunnel libnvdimm label operations from nd_ioctl() back to the CXL mailbox driver. Enable 'ndctl {read,write}-labels' for CXL. - Continue to sort and refactor functionality into distinct driver and core-infrastructure buckets. For example, mailbox handling is now a generic core capability consumed by the PCI and cxl_test drivers" * tag 'cxl-for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl: (34 commits) ocxl: Use pci core's DVSEC functionality cxl/pci: Use pci core's DVSEC functionality PCI: Add pci_find_dvsec_capability to find designated VSEC cxl/pci: Split cxl_pci_setup_regs() cxl/pci: Add @base to cxl_register_map cxl/pci: Make more use of cxl_register_map cxl/pci: Remove pci request/release regions cxl/pci: Fix NULL vs ERR_PTR confusion cxl/pci: Remove dev_dbg for unknown register blocks cxl/pci: Convert register block identifiers to an enum cxl/acpi: Do not fail cxl_acpi_probe() based on a missing CHBS cxl/pci: Disambiguate cxl_pci further from cxl_mem Documentation/cxl: Add bus internal docs cxl/core: Split decoder setup into alloc + add tools/testing/cxl: Introduce a mock memory device + driver cxl/mbox: Move command definitions to common location cxl/bus: Populate the target list at decoder create tools/testing/cxl: Introduce a mocked-up CXL port hierarchy cxl/pmem: Add support for multiple nvdimm-bridge objects cxl/pmem: Translate NVDIMM label commands to CXL label commands ...
2 parents dab334c + c6d7e13 commit dd72945

File tree

36 files changed

+3269
-1490
lines changed

36 files changed

+3269
-1490
lines changed

Documentation/driver-api/cxl/memory-devices.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,18 @@ CXL Core
3939
.. kernel-doc:: drivers/cxl/core/bus.c
4040
:doc: cxl core
4141

42+
.. kernel-doc:: drivers/cxl/core/bus.c
43+
:identifiers:
44+
4245
.. kernel-doc:: drivers/cxl/core/pmem.c
4346
:doc: cxl pmem
4447

4548
.. kernel-doc:: drivers/cxl/core/regs.c
4649
:doc: cxl registers
4750

51+
.. kernel-doc:: drivers/cxl/core/mbox.c
52+
:doc: cxl mbox
53+
4854
External Interfaces
4955
===================
5056

arch/powerpc/platforms/powernv/ocxl.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ static int get_max_afu_index(struct pci_dev *dev, int *afu_idx)
107107
int pos;
108108
u32 val;
109109

110-
pos = find_dvsec_from_pos(dev, OCXL_DVSEC_FUNC_ID, 0);
110+
pos = pci_find_dvsec_capability(dev, PCI_VENDOR_ID_IBM,
111+
OCXL_DVSEC_FUNC_ID);
111112
if (!pos)
112113
return -ESRCH;
113114

drivers/cxl/acpi.c

Lines changed: 97 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
5252
return -EINVAL;
5353
}
5454

55+
if (CFMWS_INTERLEAVE_WAYS(cfmws) > CXL_DECODER_MAX_INTERLEAVE) {
56+
dev_err(dev, "CFMWS Interleave Ways (%d) too large\n",
57+
CFMWS_INTERLEAVE_WAYS(cfmws));
58+
return -EINVAL;
59+
}
60+
5561
expected_len = struct_size((cfmws), interleave_targets,
5662
CFMWS_INTERLEAVE_WAYS(cfmws));
5763

@@ -71,18 +77,19 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
7177
static void cxl_add_cfmws_decoders(struct device *dev,
7278
struct cxl_port *root_port)
7379
{
80+
int target_map[CXL_DECODER_MAX_INTERLEAVE];
7481
struct acpi_cedt_cfmws *cfmws;
7582
struct cxl_decoder *cxld;
7683
acpi_size len, cur = 0;
7784
void *cedt_subtable;
78-
unsigned long flags;
7985
int rc;
8086

8187
len = acpi_cedt->length - sizeof(*acpi_cedt);
8288
cedt_subtable = acpi_cedt + 1;
8389

8490
while (cur < len) {
8591
struct acpi_cedt_header *c = cedt_subtable + cur;
92+
int i;
8693

8794
if (c->type != ACPI_CEDT_TYPE_CFMWS) {
8895
cur += c->length;
@@ -108,24 +115,39 @@ static void cxl_add_cfmws_decoders(struct device *dev,
108115
continue;
109116
}
110117

111-
flags = cfmws_to_decoder_flags(cfmws->restrictions);
112-
cxld = devm_cxl_add_decoder(dev, root_port,
113-
CFMWS_INTERLEAVE_WAYS(cfmws),
114-
cfmws->base_hpa, cfmws->window_size,
115-
CFMWS_INTERLEAVE_WAYS(cfmws),
116-
CFMWS_INTERLEAVE_GRANULARITY(cfmws),
117-
CXL_DECODER_EXPANDER,
118-
flags);
118+
for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++)
119+
target_map[i] = cfmws->interleave_targets[i];
119120

120-
if (IS_ERR(cxld)) {
121+
cxld = cxl_decoder_alloc(root_port,
122+
CFMWS_INTERLEAVE_WAYS(cfmws));
123+
if (IS_ERR(cxld))
124+
goto next;
125+
126+
cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
127+
cxld->target_type = CXL_DECODER_EXPANDER;
128+
cxld->range = (struct range) {
129+
.start = cfmws->base_hpa,
130+
.end = cfmws->base_hpa + cfmws->window_size - 1,
131+
};
132+
cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws);
133+
cxld->interleave_granularity =
134+
CFMWS_INTERLEAVE_GRANULARITY(cfmws);
135+
136+
rc = cxl_decoder_add(cxld, target_map);
137+
if (rc)
138+
put_device(&cxld->dev);
139+
else
140+
rc = cxl_decoder_autoremove(dev, cxld);
141+
if (rc) {
121142
dev_err(dev, "Failed to add decoder for %#llx-%#llx\n",
122143
cfmws->base_hpa, cfmws->base_hpa +
123144
cfmws->window_size - 1);
124-
} else {
125-
dev_dbg(dev, "add: %s range %#llx-%#llx\n",
126-
dev_name(&cxld->dev), cfmws->base_hpa,
127-
cfmws->base_hpa + cfmws->window_size - 1);
145+
goto next;
128146
}
147+
dev_dbg(dev, "add: %s range %#llx-%#llx\n",
148+
dev_name(&cxld->dev), cfmws->base_hpa,
149+
cfmws->base_hpa + cfmws->window_size - 1);
150+
next:
129151
cur += c->length;
130152
}
131153
}
@@ -182,15 +204,7 @@ static resource_size_t get_chbcr(struct acpi_cedt_chbs *chbs)
182204
return IS_ERR(chbs) ? CXL_RESOURCE_NONE : chbs->base;
183205
}
184206

185-
struct cxl_walk_context {
186-
struct device *dev;
187-
struct pci_bus *root;
188-
struct cxl_port *port;
189-
int error;
190-
int count;
191-
};
192-
193-
static int match_add_root_ports(struct pci_dev *pdev, void *data)
207+
__mock int match_add_root_ports(struct pci_dev *pdev, void *data)
194208
{
195209
struct cxl_walk_context *ctx = data;
196210
struct pci_bus *root_bus = ctx->root;
@@ -239,7 +253,8 @@ static struct cxl_dport *find_dport_by_dev(struct cxl_port *port, struct device
239253
return NULL;
240254
}
241255

242-
static struct acpi_device *to_cxl_host_bridge(struct device *dev)
256+
__mock struct acpi_device *to_cxl_host_bridge(struct device *host,
257+
struct device *dev)
243258
{
244259
struct acpi_device *adev = to_acpi_device(dev);
245260

@@ -257,11 +272,12 @@ static struct acpi_device *to_cxl_host_bridge(struct device *dev)
257272
*/
258273
static int add_host_bridge_uport(struct device *match, void *arg)
259274
{
260-
struct acpi_device *bridge = to_cxl_host_bridge(match);
261275
struct cxl_port *root_port = arg;
262276
struct device *host = root_port->dev.parent;
277+
struct acpi_device *bridge = to_cxl_host_bridge(host, match);
263278
struct acpi_pci_root *pci_root;
264279
struct cxl_walk_context ctx;
280+
int single_port_map[1], rc;
265281
struct cxl_decoder *cxld;
266282
struct cxl_dport *dport;
267283
struct cxl_port *port;
@@ -272,7 +288,7 @@ static int add_host_bridge_uport(struct device *match, void *arg)
272288
dport = find_dport_by_dev(root_port, match);
273289
if (!dport) {
274290
dev_dbg(host, "host bridge expected and not found\n");
275-
return -ENODEV;
291+
return 0;
276292
}
277293

278294
port = devm_cxl_add_port(host, match, dport->component_reg_phys,
@@ -297,22 +313,46 @@ static int add_host_bridge_uport(struct device *match, void *arg)
297313
return -ENODEV;
298314
if (ctx.error)
299315
return ctx.error;
316+
if (ctx.count > 1)
317+
return 0;
300318

301319
/* TODO: Scan CHBCR for HDM Decoder resources */
302320

303321
/*
304-
* In the single-port host-bridge case there are no HDM decoders
305-
* in the CHBCR and a 1:1 passthrough decode is implied.
322+
* Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability
323+
* Structure) single ported host-bridges need not publish a decoder
324+
* capability when a passthrough decode can be assumed, i.e. all
325+
* transactions that the uport sees are claimed and passed to the single
326+
* dport. Disable the range until the first CXL region is enumerated /
327+
* activated.
306328
*/
307-
if (ctx.count == 1) {
308-
cxld = devm_cxl_add_passthrough_decoder(host, port);
309-
if (IS_ERR(cxld))
310-
return PTR_ERR(cxld);
329+
cxld = cxl_decoder_alloc(port, 1);
330+
if (IS_ERR(cxld))
331+
return PTR_ERR(cxld);
332+
333+
cxld->interleave_ways = 1;
334+
cxld->interleave_granularity = PAGE_SIZE;
335+
cxld->target_type = CXL_DECODER_EXPANDER;
336+
cxld->range = (struct range) {
337+
.start = 0,
338+
.end = -1,
339+
};
311340

312-
dev_dbg(host, "add: %s\n", dev_name(&cxld->dev));
313-
}
341+
device_lock(&port->dev);
342+
dport = list_first_entry(&port->dports, typeof(*dport), list);
343+
device_unlock(&port->dev);
314344

315-
return 0;
345+
single_port_map[0] = dport->port_id;
346+
347+
rc = cxl_decoder_add(cxld, single_port_map);
348+
if (rc)
349+
put_device(&cxld->dev);
350+
else
351+
rc = cxl_decoder_autoremove(host, cxld);
352+
353+
if (rc == 0)
354+
dev_dbg(host, "add: %s\n", dev_name(&cxld->dev));
355+
return rc;
316356
}
317357

318358
static int add_host_bridge_dport(struct device *match, void *arg)
@@ -323,7 +363,7 @@ static int add_host_bridge_dport(struct device *match, void *arg)
323363
struct acpi_cedt_chbs *chbs;
324364
struct cxl_port *root_port = arg;
325365
struct device *host = root_port->dev.parent;
326-
struct acpi_device *bridge = to_cxl_host_bridge(match);
366+
struct acpi_device *bridge = to_cxl_host_bridge(host, match);
327367

328368
if (!bridge)
329369
return 0;
@@ -337,9 +377,11 @@ static int add_host_bridge_dport(struct device *match, void *arg)
337377
}
338378

339379
chbs = cxl_acpi_match_chbs(host, uid);
340-
if (IS_ERR(chbs))
341-
dev_dbg(host, "No CHBS found for Host Bridge: %s\n",
342-
dev_name(match));
380+
if (IS_ERR(chbs)) {
381+
dev_warn(host, "No CHBS found for Host Bridge: %s\n",
382+
dev_name(match));
383+
return 0;
384+
}
343385

344386
rc = cxl_add_dport(root_port, match, uid, get_chbcr(chbs));
345387
if (rc) {
@@ -375,6 +417,17 @@ static int add_root_nvdimm_bridge(struct device *match, void *data)
375417
return 1;
376418
}
377419

420+
static u32 cedt_instance(struct platform_device *pdev)
421+
{
422+
const bool *native_acpi0017 = acpi_device_get_match_data(&pdev->dev);
423+
424+
if (native_acpi0017 && *native_acpi0017)
425+
return 0;
426+
427+
/* for cxl_test request a non-canonical instance */
428+
return U32_MAX;
429+
}
430+
378431
static int cxl_acpi_probe(struct platform_device *pdev)
379432
{
380433
int rc;
@@ -388,7 +441,7 @@ static int cxl_acpi_probe(struct platform_device *pdev)
388441
return PTR_ERR(root_port);
389442
dev_dbg(host, "add: %s\n", dev_name(&root_port->dev));
390443

391-
status = acpi_get_table(ACPI_SIG_CEDT, 0, &acpi_cedt);
444+
status = acpi_get_table(ACPI_SIG_CEDT, cedt_instance(pdev), &acpi_cedt);
392445
if (ACPI_FAILURE(status))
393446
return -ENXIO;
394447

@@ -419,9 +472,11 @@ static int cxl_acpi_probe(struct platform_device *pdev)
419472
return 0;
420473
}
421474

475+
static bool native_acpi0017 = true;
476+
422477
static const struct acpi_device_id cxl_acpi_ids[] = {
423-
{ "ACPI0017", 0 },
424-
{ "", 0 },
478+
{ "ACPI0017", (unsigned long) &native_acpi0017 },
479+
{ },
425480
};
426481
MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids);
427482

drivers/cxl/core/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ cxl_core-y := bus.o
66
cxl_core-y += pmem.o
77
cxl_core-y += regs.o
88
cxl_core-y += memdev.o
9+
cxl_core-y += mbox.o

0 commit comments

Comments
 (0)