SFC changes for CXL type2 enabling

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE5DAy15EJMCV1R6v9YGjFFmlTOEoFAmpEQsUACgkQYGjFFmlT
 OEpejQ/+OQ0+5tLHUP80eHPJDMx/WBlsGozmWF9LsTIkdZjd9WgVHTbQFMnny85Q
 Fnzy1vBpXR7du4tAW+0TiDT7EsFqn1oxm3l5Ccpk2zP35SrPoGaWWSK9Sz6EXkrs
 Ky90sJQw8WpggcZ4AnI1uXcsCtgvtMzdX7KHa51uox8g5JWFIAL5tVqCqhPSizlU
 oL7iuvWETGLITw8VBu+TDm8fo/ZgrqzW7LE/GEyS+ZaDY3/OV+51DxMDqtNlLeE/
 g3V9cGwiLEKhDo5UgVdBHUHcLLMOjJcWA6J90MlQ4Hc+SoIP35JN6lJ4zaXxfoEQ
 GtOFRJNFs0m5uD5xDG2RpowPVnDuO73gLNwcxyI8G3uNVnNQKng03U0l34OMwnHv
 aZa2FokgjreQ+3gKGKa7YD3d9VKw3TBoQL1bmU53vDMKuNHIedORdEGJgrwk5yLc
 +AfFWKsSBUmYn3KdtnJqr8mxFDkzyD754OdIIVSra2fgkugb4pC8k0soEe2FI/9c
 Q/ucYyyTUR/v+/9P5ZEV7GeOWzvcvRcuMwesarVsnSIXy40KYlDWjUBZ77t3/K9p
 YmFe0/LX0bh1Z1KU0IxIUTWPFT74RCbgAhYK+e0AZ2NQB2loWkg/xsWbXj+ifmH4
 iV9dK1qBTpIYoOs+Cd0dABqaR/RSIrbvtS7X0h8zyP22Eh/2xl4=
 =PhAT
 -----END PGP SIGNATURE-----

Merge tag 'sfc-net-pullrequest-20260630' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl

Lucero Palau, Alejandro says:

====================
pull request: sfc 2026-07-01

here are the last CXL core changes for enabling CXL Type2 drivers to
initialize a CXL-capable device plus the netdev sfc driver changes using
this new CXL core Type2 support.

Please pull or let me know of any problem!

SFC changes for CXL type2 enabling

* tag 'sfc-net-pullrequest-20260630' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl:
  sfc: support pio mapping based on cxl
  sfc: obtain and map cxl range using devm_cxl_probe_mem
  sfc: Initialize cxl dpa
  sfc: Map cxl regs
  sfc: add cxl support
  cxl: Support dpa without a mailbox
  cxl: Support Type2 cxl regs mapping
====================

Link: https://patch.msgid.link/20260701113805.14072-1-alejandro.lucero-palau@amd.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2026-07-07 12:51:16 +02:00
commit 997bfb05c9
18 changed files with 309 additions and 70 deletions

View File

@ -101,6 +101,8 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
struct dentry *cxl_debugfs_create_dir(const char *dir);
int cxl_dpa_set_part(struct cxl_endpoint_decoder *cxled,
enum cxl_partition_mode mode);
struct cxl_memdev_state;
int cxl_mem_get_partition_info(struct cxl_memdev_state *mds);
int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, u64 size);
int cxl_dpa_free(struct cxl_endpoint_decoder *cxled);
resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled);

View File

@ -1152,7 +1152,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, "CXL");
*
* See CXL @8.2.9.5.2.1 Get Partition Info
*/
static int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)
{
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
struct cxl_mbox_get_partition_info pi;
@ -1308,55 +1308,6 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
return -EBUSY;
}
static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
{
int i = info->nr_partitions;
if (size == 0)
return;
info->part[i].range = (struct range) {
.start = start,
.end = start + size - 1,
};
info->part[i].mode = mode;
info->nr_partitions++;
}
int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
{
struct cxl_dev_state *cxlds = &mds->cxlds;
struct device *dev = cxlds->dev;
int rc;
if (!cxlds->media_ready) {
info->size = 0;
return 0;
}
info->size = mds->total_bytes;
if (mds->partition_align_bytes == 0) {
add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM);
add_part(info, mds->volatile_only_bytes,
mds->persistent_only_bytes, CXL_PARTMODE_PMEM);
return 0;
}
rc = cxl_mem_get_partition_info(mds);
if (rc) {
dev_err(dev, "Failed to query partition information\n");
return rc;
}
add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM);
add_part(info, mds->active_volatile_bytes, mds->active_persistent_bytes,
CXL_PARTMODE_PMEM);
return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_mem_dpa_fetch, "CXL");
int cxl_get_dirty_count(struct cxl_memdev_state *mds, u32 *count)
{
struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;

View File

@ -594,6 +594,73 @@ bool is_cxl_memdev(const struct device *dev)
}
EXPORT_SYMBOL_NS_GPL(is_cxl_memdev, "CXL");
static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
{
int i = info->nr_partitions;
if (size == 0)
return;
info->part[i].range = (struct range) {
.start = start,
.end = start + size - 1,
};
info->part[i].mode = mode;
info->nr_partitions++;
}
int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
{
struct cxl_dev_state *cxlds = &mds->cxlds;
struct device *dev = cxlds->dev;
int rc;
if (!cxlds->media_ready) {
info->size = 0;
return 0;
}
info->size = mds->total_bytes;
if (mds->partition_align_bytes == 0) {
add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM);
add_part(info, mds->volatile_only_bytes,
mds->persistent_only_bytes, CXL_PARTMODE_PMEM);
return 0;
}
rc = cxl_mem_get_partition_info(mds);
if (rc) {
dev_err(dev, "Failed to query partition information\n");
return rc;
}
add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM);
add_part(info, mds->active_volatile_bytes, mds->active_persistent_bytes,
CXL_PARTMODE_PMEM);
return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_mem_dpa_fetch, "CXL");
/**
* cxl_set_capacity: initialize dpa by a driver without a mailbox.
*
* @cxlds: pointer to cxl_dev_state
* @capacity: device volatile memory size
*/
int cxl_set_capacity(struct cxl_dev_state *cxlds, u64 capacity)
{
struct cxl_dpa_info range_info = {
.size = capacity,
};
add_part(&range_info, 0, capacity, CXL_PARTMODE_RAM);
return cxl_dpa_setup(cxlds, &range_info);
}
EXPORT_SYMBOL_NS_GPL(cxl_set_capacity, "CXL");
/**
* set_exclusive_cxl_commands() - atomically disable user cxl commands
* @mds: The device state to operate on

View File

@ -6,6 +6,7 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/pci-doe.h>
#include <cxl/pci.h>
#include <linux/aer.h>
#include <cxlpci.h>
#include <cxlmem.h>

View File

@ -11,6 +11,7 @@
#include <linux/idr.h>
#include <linux/node.h>
#include <cxl/einj.h>
#include <cxl/pci.h>
#include <cxlmem.h>
#include <cxlpci.h>
#include <cxl.h>

View File

@ -4,6 +4,7 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <cxl/pci.h>
#include <cxlmem.h>
#include <cxlpci.h>
#include <pmu.h>

View File

@ -13,16 +13,6 @@
*/
#define CXL_PCI_DEFAULT_MAX_VECTORS 16
/* Register Block Identifier (RBI) */
enum cxl_regloc_type {
CXL_REGLOC_RBI_EMPTY = 0,
CXL_REGLOC_RBI_COMPONENT,
CXL_REGLOC_RBI_VIRT,
CXL_REGLOC_RBI_MEMDEV,
CXL_REGLOC_RBI_PMU,
CXL_REGLOC_RBI_TYPES
};
/*
* Table Access DOE, CDAT Read Entry Response
*
@ -112,6 +102,4 @@ static inline void devm_cxl_port_ras_setup(struct cxl_port *port)
}
#endif
int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
struct cxl_register_map *map);
#endif /* __CXL_PCI_H__ */

View File

@ -11,6 +11,7 @@
#include <linux/pci.h>
#include <linux/aer.h>
#include <linux/io.h>
#include <cxl/pci.h>
#include <cxl/mailbox.h>
#include "cxlmem.h"
#include "cxlpci.h"

View File

@ -66,6 +66,15 @@ config SFC_MCDI_LOGGING
Driver-Interface) commands and responses, allowing debugging of
driver/firmware interaction. The tracing is actually enabled by
a sysfs file 'mcdi_logging' under the PCI device.
config SFC_CXL
bool "Solarflare SFC9100-family CXL support"
depends on SFC && CXL_BUS >= SFC
default SFC
help
This enables SFC CXL support if the kernel is configuring CXL for
using CTPIO with CXL.mem. The SFC device with CXL support and
with a CXL-aware firmware can be used for minimizing latencies
when sending through CTPIO.
source "drivers/net/ethernet/sfc/falcon/Kconfig"
source "drivers/net/ethernet/sfc/siena/Kconfig"

View File

@ -13,6 +13,7 @@ sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
mae.o tc.o tc_bindings.o tc_counters.o \
tc_encap_actions.o tc_conntrack.o
sfc-$(CONFIG_SFC_CXL) += efx_cxl.o
obj-$(CONFIG_SFC) += sfc.o
obj-$(CONFIG_SFC_FALCON) += falcon/

View File

@ -24,6 +24,7 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <net/udp_tunnel.h>
#include "efx_cxl.h"
/* Hardware control for EF10 architecture including 'Huntington'. */
@ -106,7 +107,7 @@ static int efx_ef10_get_vf_index(struct efx_nic *efx)
static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V4_OUT_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V7_OUT_LEN);
struct efx_ef10_nic_data *nic_data = efx->nic_data;
size_t outlen;
int rc;
@ -177,6 +178,12 @@ static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
efx->num_mac_stats);
}
if (outlen < MC_CMD_GET_CAPABILITIES_V7_OUT_LEN)
nic_data->datapath_caps3 = 0;
else
nic_data->datapath_caps3 = MCDI_DWORD(outbuf,
GET_CAPABILITIES_V7_OUT_FLAGS3);
return 0;
}
@ -1140,6 +1147,9 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
unsigned int channel_vis, pio_write_vi_base, max_vis;
struct efx_ef10_nic_data *nic_data = efx->nic_data;
unsigned int uc_mem_map_size, wc_mem_map_size;
#ifdef CONFIG_SFC_CXL
struct efx_probe_data *probe_data;
#endif
void __iomem *membase;
int rc;
@ -1263,8 +1273,23 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
iounmap(efx->membase);
efx->membase = membase;
/* Set up the WC mapping if needed */
if (wc_mem_map_size) {
if (!wc_mem_map_size)
goto skip_pio;
/* Set up the WC mapping */
#ifdef CONFIG_SFC_CXL
probe_data = container_of(efx, struct efx_probe_data, efx);
if ((nic_data->datapath_caps3 &
(1 << MC_CMD_GET_CAPABILITIES_V7_OUT_CXL_CONFIG_ENABLE_LBN)) &&
probe_data->cxl_pio_initialised) {
/* Using PIO through CXL mapping */
nic_data->pio_write_base = probe_data->cxl->ctpio_cxl;
nic_data->pio_write_vi_base = pio_write_vi_base;
} else
#endif
{
/* Using legacy PIO BAR mapping */
nic_data->wc_membase = ioremap_wc(efx->membase_phys +
uc_mem_map_size,
wc_mem_map_size);
@ -1279,12 +1304,14 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx)
nic_data->wc_membase +
(pio_write_vi_base * efx->vi_stride + ER_DZ_TX_PIOBUF -
uc_mem_map_size);
rc = efx_ef10_link_piobufs(efx);
if (rc)
efx_ef10_free_piobufs(efx);
}
rc = efx_ef10_link_piobufs(efx);
if (rc)
efx_ef10_free_piobufs(efx);
skip_pio:
netif_dbg(efx, probe, efx->net_dev,
"memory BAR at %pa (virtual %p+%x UC, %p+%x WC)\n",
&efx->membase_phys, efx->membase, uc_mem_map_size,

View File

@ -34,6 +34,7 @@
#include "selftest.h"
#include "sriov.h"
#include "efx_devlink.h"
#include "efx_cxl.h"
#include "mcdi_port_common.h"
#include "mcdi_pcol.h"
@ -981,12 +982,15 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_pci_remove_main(efx);
efx_fini_io(efx);
probe_data = container_of(efx, struct efx_probe_data, efx);
efx_cxl_exit(probe_data);
pci_dbg(efx->pci_dev, "shutdown successful\n");
efx_fini_devlink_and_unlock(efx);
efx_fini_struct(efx);
free_netdev(efx->net_dev);
probe_data = container_of(efx, struct efx_probe_data, efx);
kfree(probe_data);
};
@ -1190,6 +1194,17 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
if (rc)
goto fail2;
/* A successful cxl initialization implies a CXL region created to be
* used for PIO buffers. If there is no CXL support legacy PIO buffers
* defined at specific PCI BAR regions will be used. If there is CXL
* support and the cxl initialization fails, the driver probe fails.
*/
rc = efx_cxl_init(probe_data);
if (rc) {
pci_err(pci_dev, "CXL initialization failed with error %d\n", rc);
goto fail3;
}
rc = efx_pci_probe_post_io(efx);
if (rc) {
/* On failure, retry once immediately.
@ -1228,6 +1243,7 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
return 0;
fail3:
efx_cxl_exit(probe_data);
efx_fini_io(efx);
fail2:
efx_fini_struct(efx);

View File

@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0-only
/****************************************************************************
*
* Driver for AMD network controllers and boards
* Copyright (C) 2025, Advanced Micro Devices, Inc.
*/
#include <linux/pci.h>
#include <cxl/cxl.h>
#include <cxl/pci.h>
#include "net_driver.h"
#include "efx_cxl.h"
#define EFX_CTPIO_BUFFER_SIZE SZ_256M
int efx_cxl_init(struct efx_probe_data *probe_data)
{
struct efx_nic *efx = &probe_data->efx;
struct pci_dev *pci_dev = efx->pci_dev;
struct range cxl_pio_range;
struct efx_cxl *cxl;
u16 dvsec;
int rc;
/* Is the device configured with and using CXL? */
if (!pcie_is_cxl(pci_dev))
return 0;
dvsec = pci_find_dvsec_capability(pci_dev, PCI_VENDOR_ID_CXL,
PCI_DVSEC_CXL_DEVICE);
if (!dvsec) {
pci_info(pci_dev, "CXL_DVSEC_PCIE_DEVICE capability not found\n");
return 0;
}
pci_dbg(pci_dev, "CXL_DVSEC_PCIE_DEVICE capability found\n");
/* Create a cxl_dev_state embedded in the cxl struct using cxl core api
* specifying no mbox available.
*/
cxl = devm_cxl_dev_state_create(&pci_dev->dev, CXL_DEVTYPE_DEVMEM,
pci_get_dsn(pci_dev), dvsec,
struct efx_cxl, cxlds, false);
if (!cxl)
return -ENOMEM;
rc = cxl_pci_setup_regs(pci_dev, CXL_REGLOC_RBI_COMPONENT,
&cxl->cxlds.reg_map);
if (rc) {
pci_err(pci_dev, "No component registers\n");
return rc;
}
if (!cxl->cxlds.reg_map.component_map.hdm_decoder.valid) {
pci_err(pci_dev, "Expected HDM component register not found\n");
return -ENODEV;
}
if (!cxl->cxlds.reg_map.component_map.ras.valid) {
pci_err(pci_dev, "Expected RAS component register not found\n");
return -ENODEV;
}
/* Set media ready explicitly as there are neither mailbox for checking
* this state nor the CXL register involved, both not mandatory for
* type2.
*/
cxl->cxlds.media_ready = true;
if (cxl_set_capacity(&cxl->cxlds, EFX_CTPIO_BUFFER_SIZE)) {
pci_err(pci_dev, "dpa capacity setup failed\n");
return -ENODEV;
}
cxl->cxlmd = devm_cxl_probe_mem(&cxl->cxlds, &cxl_pio_range);
if (IS_ERR(cxl->cxlmd)) {
pci_err(pci_dev, "CXL accel memdev creation failed\n");
return PTR_ERR(cxl->cxlmd);
}
cxl->ctpio_cxl = ioremap_wc(cxl_pio_range.start,
range_len(&cxl_pio_range));
if (!cxl->ctpio_cxl) {
pci_err(pci_dev, "CXL ioremap region (%pra) failed\n",
&cxl_pio_range);
return -ENOMEM;
}
probe_data->cxl_pio_initialised = true;
probe_data->cxl = cxl;
return 0;
}
void efx_cxl_exit(struct efx_probe_data *probe_data)
{
if (!probe_data->cxl)
return;
iounmap(probe_data->cxl->ctpio_cxl);
}
MODULE_IMPORT_NS("CXL");

View File

@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/****************************************************************************
* Driver for AMD network controllers and boards
* Copyright (C) 2025, Advanced Micro Devices, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_CXL_H
#define EFX_CXL_H
#ifdef CONFIG_SFC_CXL
#include <cxl/cxl.h>
struct efx_probe_data;
struct efx_cxl {
struct cxl_dev_state cxlds;
struct cxl_memdev *cxlmd;
void __iomem *ctpio_cxl;
};
int efx_cxl_init(struct efx_probe_data *probe_data);
void efx_cxl_exit(struct efx_probe_data *probe_data);
#else
static inline int efx_cxl_init(struct efx_probe_data *probe_data) { return 0; }
static inline void efx_cxl_exit(struct efx_probe_data *probe_data) {}
#endif
#endif

View File

@ -1197,14 +1197,24 @@ struct efx_nic {
atomic_t n_rx_noskb_drops;
};
#ifdef CONFIG_SFC_CXL
struct efx_cxl;
#endif
/**
* struct efx_probe_data - State after hardware probe
* @pci_dev: The PCI device
* @efx: Efx NIC details
* @cxl: details of related cxl objects
* @cxl_pio_initialised: cxl initialization outcome.
*/
struct efx_probe_data {
struct pci_dev *pci_dev;
struct efx_nic efx;
#ifdef CONFIG_SFC_CXL
struct efx_cxl *cxl;
bool cxl_pio_initialised;
#endif
};
static inline struct efx_nic *efx_netdev_priv(struct net_device *dev)

View File

@ -152,6 +152,8 @@ enum {
* %MC_CMD_GET_CAPABILITIES response)
* @datapath_caps2: Further Capabilities of datapath firmware (FLAGS2 field of
* %MC_CMD_GET_CAPABILITIES response)
* @datapath_caps3: Further Capabilities of datapath firmware (FLAGS3 field of
* %MC_CMD_GET_CAPABILITIES response)
* @rx_dpcpu_fw_id: Firmware ID of the RxDPCPU
* @tx_dpcpu_fw_id: Firmware ID of the TxDPCPU
* @must_probe_vswitching: Flag: vswitching has yet to be setup after MC reboot
@ -187,6 +189,7 @@ struct efx_ef10_nic_data {
bool must_check_datapath_caps;
u32 datapath_caps;
u32 datapath_caps2;
u32 datapath_caps3;
unsigned int rx_dpcpu_fw_id;
unsigned int tx_dpcpu_fw_id;
bool must_probe_vswitching;

View File

@ -226,4 +226,6 @@ struct cxl_dev_state *_devm_cxl_dev_state_create(struct device *dev,
struct cxl_memdev *devm_cxl_probe_mem(struct cxl_dev_state *cxlds,
struct range *range);
int cxl_set_capacity(struct cxl_dev_state *cxlds, u64 capacity);
#endif /* __CXL_CXL_H__ */

22
include/cxl/pci.h Normal file
View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright(c) 2020 Intel Corporation. All rights reserved. */
#ifndef __CXL_CXL_PCI_H__
#define __CXL_CXL_PCI_H__
/* Register Block Identifier (RBI) */
enum cxl_regloc_type {
CXL_REGLOC_RBI_EMPTY = 0,
CXL_REGLOC_RBI_COMPONENT,
CXL_REGLOC_RBI_VIRT,
CXL_REGLOC_RBI_MEMDEV,
CXL_REGLOC_RBI_PMU,
CXL_REGLOC_RBI_TYPES
};
struct cxl_register_map;
struct pci_dev;
int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type,
struct cxl_register_map *map);
#endif