1 // SPDX-License-Identifier: GPL-2.0-only
2 /****************************************************************************
3 *
4 * Driver for AMD network controllers and boards
5 * Copyright (C) 2025, Advanced Micro Devices, Inc.
6 */
7
8 #include <linux/pci.h>
9
10 #include <cxl/cxl.h>
11 #include <cxl/pci.h>
12 #include "net_driver.h"
13 #include "efx_cxl.h"
14
15 #define EFX_CTPIO_BUFFER_SIZE SZ_256M
16
efx_cxl_init(struct efx_probe_data * probe_data)17 int efx_cxl_init(struct efx_probe_data *probe_data)
18 {
19 struct efx_nic *efx = &probe_data->efx;
20 struct pci_dev *pci_dev = efx->pci_dev;
21 struct range cxl_pio_range;
22 struct efx_cxl *cxl;
23 u16 dvsec;
24 int rc;
25
26 /* Is the device configured with and using CXL? */
27 if (!pcie_is_cxl(pci_dev))
28 return 0;
29
30 dvsec = pci_find_dvsec_capability(pci_dev, PCI_VENDOR_ID_CXL,
31 PCI_DVSEC_CXL_DEVICE);
32 if (!dvsec) {
33 pci_info(pci_dev, "CXL_DVSEC_PCIE_DEVICE capability not found\n");
34 return 0;
35 }
36
37 pci_dbg(pci_dev, "CXL_DVSEC_PCIE_DEVICE capability found\n");
38
39 /* Create a cxl_dev_state embedded in the cxl struct using cxl core api
40 * specifying no mbox available.
41 */
42 cxl = devm_cxl_dev_state_create(&pci_dev->dev, CXL_DEVTYPE_DEVMEM,
43 pci_get_dsn(pci_dev), dvsec,
44 struct efx_cxl, cxlds, false);
45
46 if (!cxl)
47 return -ENOMEM;
48
49 rc = cxl_pci_setup_regs(pci_dev, CXL_REGLOC_RBI_COMPONENT,
50 &cxl->cxlds.reg_map);
51 if (rc) {
52 pci_err(pci_dev, "No component registers\n");
53 return rc;
54 }
55
56 if (!cxl->cxlds.reg_map.component_map.hdm_decoder.valid) {
57 pci_err(pci_dev, "Expected HDM component register not found\n");
58 return -ENODEV;
59 }
60
61 if (!cxl->cxlds.reg_map.component_map.ras.valid) {
62 pci_err(pci_dev, "Expected RAS component register not found\n");
63 return -ENODEV;
64 }
65
66 /* Set media ready explicitly as there are neither mailbox for checking
67 * this state nor the CXL register involved, both not mandatory for
68 * type2.
69 */
70 cxl->cxlds.media_ready = true;
71
72 if (cxl_set_capacity(&cxl->cxlds, EFX_CTPIO_BUFFER_SIZE)) {
73 pci_err(pci_dev, "dpa capacity setup failed\n");
74 return -ENODEV;
75 }
76
77 cxl->cxlmd = devm_cxl_probe_mem(&cxl->cxlds, &cxl_pio_range);
78 if (IS_ERR(cxl->cxlmd)) {
79 pci_err(pci_dev, "CXL accel memdev creation failed\n");
80 return PTR_ERR(cxl->cxlmd);
81 }
82
83 cxl->ctpio_cxl = ioremap_wc(cxl_pio_range.start,
84 range_len(&cxl_pio_range));
85 if (!cxl->ctpio_cxl) {
86 pci_err(pci_dev, "CXL ioremap region (%pra) failed\n",
87 &cxl_pio_range);
88 return -ENOMEM;
89 }
90
91 probe_data->cxl_pio_initialised = true;
92 probe_data->cxl = cxl;
93
94 return 0;
95 }
96
efx_cxl_exit(struct efx_probe_data * probe_data)97 void efx_cxl_exit(struct efx_probe_data *probe_data)
98 {
99 if (!probe_data->cxl)
100 return;
101
102 iounmap(probe_data->cxl->ctpio_cxl);
103 }
104
105 MODULE_IMPORT_NS("CXL");
106