Logo

Linux 内核

6.16.0-rc4

快速搜索

目录

  • 开发流程
  • 提交补丁
  • 行为准则
  • 维护者手册
  • 所有开发流程文档
  • 核心 API
  • 驱动程序 API
    • 驱动程序作者的一般信息
    • 有用的支持库
    • 总线级文档
      • 辅助总线
      • Compute Express Link
      • EISA 总线支持
      • Firewire (IEEE 1394) 驱动程序接口指南
      • I3C 子系统
      • ISA 驱动程序
      • MEN Chameleon 总线
      • Linux PCI 驱动程序实现者 API 指南
      • Linux RapidIO 子系统
      • Linux 内核 SLIMbus 支持
      • Linux USB API
      • Virtio
      • VME 设备驱动程序
      • W1: Dallas 的 1-wire 总线
      • 用于通用 FPGA 接口的 Xillybus 驱动程序
    • 子系统特定 API
  • 子系统
  • 锁定
  • 许可规则
  • 编写文档
  • 开发工具
  • 测试指南
  • 黑客指南
  • 跟踪
  • 故障注入
  • Livepatching
  • Rust
  • 管理
  • 构建系统
  • 报告问题
  • 用户空间工具
  • 用户空间 API
  • 固件
  • 固件和设备树
  • CPU 架构
  • 未排序的文档
  • 翻译

本页

  • 显示源代码

Compute Express Link 驱动程序操作理论¶

Compute Express Link 内存设备是一个实现 CXL.mem 协议的 CXL 组件。它包含一定量的易失性存储器、持久性存储器或两者。它被枚举为 PCI 设备,用于配置和通过 MMIO 邮箱传递消息。它对系统物理地址空间的贡献通过 HDM(主机管理设备内存)解码器处理,这些解码器可以选择性地定义设备对主机桥下的多个设备或跨主机桥交织的地址范围的贡献。

CXL 总线¶

类似于 RAID 驱动程序如何获取磁盘对象并将它们组装成新的逻辑设备,CXL 子系统的任务是获取 PCIe 和 ACPI 对象并将它们组装成 CXL.mem 解码拓扑。CXL.mem 拓扑的运行时配置需求也类似于 RAID,因为具有相同硬件配置的不同环境可能会决定以不同的方式组装拓扑。一种方式可以选择性能(RAID0),跨多个主机桥和端点进行内存条带化,而另一种方式可以选择容错并禁用 CXL.mem 拓扑中的任何条带化。

平台固件在“CXL 根端口”(Linux 术语,表示 CXL 解码拓扑的顶部)枚举一个交织选项菜单。从那里,PCIe 拓扑决定了哪些端点可以参与哪些主机桥解码方案。根端口和端点之间的路径中的每个 PCIe 交换机都引入了一个可以分割交织的点。例如,平台固件可能会说在给定的范围内仅解码到一个主机桥,但该主机桥可能会依次跨多个根端口交织周期。端口和端点之间的中间交换机可能会跨多个下游交换机端口交织周期,等等。

这是一个由“cxl_test”定义的 CXL 拓扑示例列表。“cxl_test”模块生成一个模拟 CXL 拓扑,包含 2 个主机桥,每个主机桥有 2 个根端口。每个根端口都连接到 2 路交换机,端点连接到这些下游端口,总共有 8 个端点

# cxl list -BEMPu -b cxl_test
{
  "bus":"root3",
  "provider":"cxl_test",
  "ports:root3":[
    {
      "port":"port5",
      "host":"cxl_host_bridge.1",
      "ports:port5":[
        {
          "port":"port8",
          "host":"cxl_switch_uport.1",
          "endpoints:port8":[
            {
              "endpoint":"endpoint9",
              "host":"mem2",
              "memdev":{
                "memdev":"mem2",
                "pmem_size":"256.00 MiB (268.44 MB)",
                "ram_size":"256.00 MiB (268.44 MB)",
                "serial":"0x1",
                "numa_node":1,
                "host":"cxl_mem.1"
              }
            },
            {
              "endpoint":"endpoint15",
              "host":"mem6",
              "memdev":{
                "memdev":"mem6",
                "pmem_size":"256.00 MiB (268.44 MB)",
                "ram_size":"256.00 MiB (268.44 MB)",
                "serial":"0x5",
                "numa_node":1,
                "host":"cxl_mem.5"
              }
            }
          ]
        },
        {
          "port":"port12",
          "host":"cxl_switch_uport.3",
          "endpoints:port12":[
            {
              "endpoint":"endpoint17",
              "host":"mem8",
              "memdev":{
                "memdev":"mem8",
                "pmem_size":"256.00 MiB (268.44 MB)",
                "ram_size":"256.00 MiB (268.44 MB)",
                "serial":"0x7",
                "numa_node":1,
                "host":"cxl_mem.7"
              }
            },
            {
              "endpoint":"endpoint13",
              "host":"mem4",
              "memdev":{
                "memdev":"mem4",
                "pmem_size":"256.00 MiB (268.44 MB)",
                "ram_size":"256.00 MiB (268.44 MB)",
                "serial":"0x3",
                "numa_node":1,
                "host":"cxl_mem.3"
              }
            }
          ]
        }
      ]
    },
    {
      "port":"port4",
      "host":"cxl_host_bridge.0",
      "ports:port4":[
        {
          "port":"port6",
          "host":"cxl_switch_uport.0",
          "endpoints:port6":[
            {
              "endpoint":"endpoint7",
              "host":"mem1",
              "memdev":{
                "memdev":"mem1",
                "pmem_size":"256.00 MiB (268.44 MB)",
                "ram_size":"256.00 MiB (268.44 MB)",
                "serial":"0",
                "numa_node":0,
                "host":"cxl_mem.0"
              }
            },
            {
              "endpoint":"endpoint14",
              "host":"mem5",
              "memdev":{
                "memdev":"mem5",
                "pmem_size":"256.00 MiB (268.44 MB)",
                "ram_size":"256.00 MiB (268.44 MB)",
                "serial":"0x4",
                "numa_node":0,
                "host":"cxl_mem.4"
              }
            }
          ]
        },
        {
          "port":"port10",
          "host":"cxl_switch_uport.2",
          "endpoints:port10":[
            {
              "endpoint":"endpoint16",
              "host":"mem7",
              "memdev":{
                "memdev":"mem7",
                "pmem_size":"256.00 MiB (268.44 MB)",
                "ram_size":"256.00 MiB (268.44 MB)",
                "serial":"0x6",
                "numa_node":0,
                "host":"cxl_mem.6"
              }
            },
            {
              "endpoint":"endpoint11",
              "host":"mem3",
              "memdev":{
                "memdev":"mem3",
                "pmem_size":"256.00 MiB (268.44 MB)",
                "ram_size":"256.00 MiB (268.44 MB)",
                "serial":"0x2",
                "numa_node":0,
                "host":"cxl_mem.2"
              }
            }
          ]
        }
      ]
    }
  ]
}

在该列表中,每个“root”、“port”和“endpoint”对象对应一个内核“struct cxl_port”对象。“cxl_port”是一个可以将其后代解码为 CXL.mem 的设备。因此,“root”声明非 PCIe 可枚举的平台解码范围并将它们解码为“ports”,“ports”解码为“endpoints”,而“endpoints”表示从 SPA(系统物理地址)到 DPA(设备物理地址)的解码。

继续 RAID 类比,磁盘既有拓扑元数据,也有设备上的元数据,用于确定 RAID 集的组装。CXL 端口拓扑和 CXL 端口链接状态是 CXL.mem 集组装的元数据。CXL 端口拓扑是通过 CXL.mem 设备的到达来枚举的。也就是说,除非 PCIe 核心将 cxl_pci 驱动程序附加到 CXL 内存扩展器,否则 CXL 端口对象没有任何作用。相反,对于热插拔/移除场景,Linux PCI 核心不需要拆除交换机级别的 CXL 资源,因为 endpoint ->remove() 事件会清理为支持该内存扩展器而建立的端口数据。

可以通过以下命令确定端口元数据和给定内存设备可能参与的潜在解码方案

# cxl list -BDMu -d root -m mem3
{
  "bus":"root3",
  "provider":"cxl_test",
  "decoders:root3":[
    {
      "decoder":"decoder3.1",
      "resource":"0x8030000000",
      "size":"512.00 MiB (536.87 MB)",
      "volatile_capable":true,
      "nr_targets":2
    },
    {
      "decoder":"decoder3.3",
      "resource":"0x8060000000",
      "size":"512.00 MiB (536.87 MB)",
      "pmem_capable":true,
      "nr_targets":2
    },
    {
      "decoder":"decoder3.0",
      "resource":"0x8020000000",
      "size":"256.00 MiB (268.44 MB)",
      "volatile_capable":true,
      "nr_targets":1
    },
    {
      "decoder":"decoder3.2",
      "resource":"0x8050000000",
      "size":"256.00 MiB (268.44 MB)",
      "pmem_capable":true,
      "nr_targets":1
    }
  ],
  "memdevs:root3":[
    {
      "memdev":"mem3",
      "pmem_size":"256.00 MiB (268.44 MB)",
      "ram_size":"256.00 MiB (268.44 MB)",
      "serial":"0x2",
      "numa_node":0,
      "host":"cxl_mem.2"
    }
  ]
}

...它查询 CXL 拓扑以询问“给定内核设备名称为‘mem3’的 CXL 内存扩展器,此设备可能参与哪些平台级别解码范围”。给定的扩展器可以同时参与多个 CXL.mem 交织集,具体取决于它有多少解码器资源。在此示例中,mem3 可以参与一个或多个跨主机桥的 PMEM 交织,一个针对单个主机桥的 PMEM 交织,一个跨 2 个主机桥的易失性内存交织,以及一个仅针对单个主机桥的易失性内存交织。

相反,可以通过以下命令确定可以参与给定平台级别解码方案的内存设备

# cxl list -MDu -d 3.2
[
  {
    "memdevs":[
      {
        "memdev":"mem1",
        "pmem_size":"256.00 MiB (268.44 MB)",
        "ram_size":"256.00 MiB (268.44 MB)",
        "serial":"0",
        "numa_node":0,
        "host":"cxl_mem.0"
      },
      {
        "memdev":"mem5",
        "pmem_size":"256.00 MiB (268.44 MB)",
        "ram_size":"256.00 MiB (268.44 MB)",
        "serial":"0x4",
        "numa_node":0,
        "host":"cxl_mem.4"
      },
      {
        "memdev":"mem7",
        "pmem_size":"256.00 MiB (268.44 MB)",
        "ram_size":"256.00 MiB (268.44 MB)",
        "serial":"0x6",
        "numa_node":0,
        "host":"cxl_mem.6"
      },
      {
        "memdev":"mem3",
        "pmem_size":"256.00 MiB (268.44 MB)",
        "ram_size":"256.00 MiB (268.44 MB)",
        "serial":"0x2",
        "numa_node":0,
        "host":"cxl_mem.2"
      }
    ]
  },
  {
    "root decoders":[
      {
        "decoder":"decoder3.2",
        "resource":"0x8050000000",
        "size":"256.00 MiB (268.44 MB)",
        "pmem_capable":true,
        "nr_targets":1
      }
    ]
  }
]

...其中解码器的命名方案是“decoder<port_id>.<instance_id>”。

驱动程序基础设施¶

本节介绍 CXL 内存设备的驱动程序基础设施。

CXL 内存设备¶

这实现了 CXL 设备由 Compute Express Link 规范定义的 PCI 独有功能。即使未启用 CXL,CXL 设备也可能会显示某些功能。虽然此驱动程序专注于 CXL 设备的 PCI 特定方面,但它绑定到特定的 CXL 内存设备类代码,因此 cxl_pci 的实现专注于 CXL 内存设备。

该驱动程序有几个职责,主要包括
  • 创建 memX 设备并在 CXL 总线上注册。

  • 枚举设备的寄存器接口并映射它们。

  • 使用 cxl_core 注册 nvdimm 桥接设备。

  • 使用 cxl_core 注册 CXL 邮箱。

int __cxl_pci_mbox_send_cmd(struct cxl_mailbox *cxl_mbox, struct cxl_mbox_cmd *mbox_cmd)¶

执行邮箱命令

参数

struct cxl_mailbox *cxl_mbox

CXL 邮箱上下文

struct cxl_mbox_cmd *mbox_cmd

要发送到内存设备的命令。

上下文

任何上下文。需要持有 mbox_mutex。

返回

-ETIMEDOUT 如果等待完成时发生超时。成功则返回 0。

调用者应检查 mbox_cmd 中的返回值,以确保它成功。

描述

这是 CXL 邮箱发送命令的通用形式,因此仅使用邮箱功能 ID 定义的寄存器 - CXL 2.0 8.2.8.4。内存设备,以及其他类型的 CXL 设备,可能在错误情况下提供更多信息。希望发送邮箱命令的驱动程序设施应使用包装器命令。

CXL 规范允许最多两个邮箱。目的是让主邮箱由操作系统控制,而辅助邮箱由系统固件使用。这允许操作系统和固件与设备通信,而无需相互协调。驱动程序仅使用主邮箱。

CXL 内存端点设备和交换机是参与 CXL.mem 协议的具有 CXL 功能的设备。它们的功能建立在 CXL.io 协议之上,该协议允许通过标准 PCI 机制枚举和配置组件。

cxl_mem 驱动程序拥有启动此 CXL.mem 功能枚举的权限。通过检测到具有 CXL 功能的端点,驱动程序将向上查找其连接到的平台特定端口,并确定路径中是否存在中间交换机。如果存在交换机,则辅助操作是枚举这些交换机(在 cxl_core 中实现)。最后,cxl_mem 驱动程序将它绑定的设备添加为 CXL 端点端口,以用于更高级别的操作。

struct cxl_memdev¶

表示 Type-3 内存设备的 CXL 总线对象

定义:

struct cxl_memdev {
    struct device dev;
    struct cdev cdev;
    struct cxl_dev_state *cxlds;
    struct work_struct detach_work;
    struct cxl_nvdimm_bridge *cxl_nvb;
    struct cxl_nvdimm *cxl_nvd;
    struct cxl_port *endpoint;
    int id;
    int depth;
    u8 scrub_cycle;
    int scrub_region_id;
    void *err_rec_array;
};

成员

dev

驱动程序核心设备对象

cdev

用于 ioctl 操作的字符设备核心对象

cxlds

支持此设备的设备状态

detach_work

活动 memdev 在其祖先中失去了一个端口

cxl_nvb

如果存在 cxl_nvd,则协调移除

cxl_nvd

如果设备支持 pmem,则可选的 nvdimm 桥

endpoint

此内存设备与 CXL 端口拓扑的连接

id

此 memdev 实例的 ID 号。

depth

端点端口深度

scrub_cycle

为此设备设置的当前 scrub 周期

scrub_region_id

为其设置当前 scrub 周期的支持区域的 ID 号(如果有)

err_rec_array

存储 memdev 错误记录的 xarrays 列表,用于检查内存修复操作的属性是否来自当前启动。

struct cxl_event_state¶

事件日志驱动程序状态

定义:

struct cxl_event_state {
    struct cxl_get_event_payload *buf;
    struct mutex log_lock;
};

成员

buf

用于接收事件数据的缓冲区

log_lock

序列化 event_buf 和日志使用

struct cxl_poison_state¶

驱动程序中毒状态信息

定义:

struct cxl_poison_state {
    u32 max_errors;
    unsigned long enabled_cmds[BITS_TO_LONGS(CXL_POISON_ENABLED_MAX)];
    struct cxl_mbox_poison_out *list_out;
    struct mutex lock;
};

成员

max_errors

设备缓存中保存的最大介质错误记录数

enabled_cmds

CEL 中启用的所有中毒命令

list_out

设备返回的中毒列表有效负载

lock

保护中毒列表的读取

描述

中毒列表的读取是同步的,以确保读取器不会获得不完整的列表,因为他们的请求重叠(被中断或前面有)同一 DPA 范围的另一个读取请求。CXL 规范 3.0 第 8.2.9.8.4.1 节

struct cxl_fw_state¶

固件上传/激活状态

定义:

struct cxl_fw_state {
    unsigned long state[BITS_TO_LONGS(CXL_FW_STATE_BITS)];
    bool oneshot;
    int num_slots;
    int cur_slot;
    int next_slot;
};

成员

state

fw_uploader 状态位掩码

oneshot

固件上传是否适合单次传输

num_slots

可用的固件插槽数

cur_slot

当前活动的插槽号

next_slot

新固件的插槽号

struct cxl_security_state¶

设备安全状态

定义:

struct cxl_security_state {
    unsigned long state;
    unsigned long enabled_cmds[BITS_TO_LONGS(CXL_SEC_ENABLED_MAX)];
    int poll_tmo_secs;
    bool sanitize_active;
    struct delayed_work poll_dwork;
    struct kernfs_node *sanitize_node;
};

成员

state

上次安全操作的状态

enabled_cmds

CEL 中启用的所有安全命令

poll_tmo_secs

轮询超时

sanitize_active

待处理的清理完成

poll_dwork

轮询工作项

sanitize_node

要通知的清理 sysfs 文件

struct cxl_dpa_perf¶

DPA 性能属性条目

定义:

struct cxl_dpa_perf {
    struct range dpa_range;
    struct access_coordinate coord[ACCESS_COORDINATE_MAX];
    struct access_coordinate cdat_coord[ACCESS_COORDINATE_MAX];
    int qos_class;
};

成员

dpa_range

DPA 地址的范围

coord

QoS 性能数据(即延迟、带宽)

cdat_coord

来自 CDAT 的原始 QoS 性能数据

qos_class

QoS 类 Cookie

struct cxl_dpa_partition¶

DPA 分区描述符

定义:

struct cxl_dpa_partition {
    struct resource res;
    struct cxl_dpa_perf perf;
    enum cxl_partition_mode mode;
};

成员

res

DPA 资源树 (cxlds->dpa_res) 中分区的快捷方式

perf

来自 CDAT 的分区的性能属性

mode

DPA 容量的操作模式,例如 ram、pmem、dynamic...

struct cxl_dev_state¶

驱动程序设备状态

定义:

struct cxl_dev_state {
    struct device *dev;
    struct cxl_memdev *cxlmd;
    struct cxl_register_map reg_map;
    struct cxl_regs regs;
    int cxl_dvsec;
    bool rcd;
    bool media_ready;
    struct resource dpa_res;
    struct cxl_dpa_partition part[CXL_NR_PARTITIONS_MAX];
    unsigned int nr_partitions;
    u64 serial;
    enum cxl_devtype type;
    struct cxl_mailbox cxl_mbox;
#ifdef CONFIG_CXL_FEATURES;
    struct cxl_features_state *cxlfs;
#endif;
};

成员

dev

与此 CXL 状态关联的设备

cxlmd

表示 dev 的 CXL.mem 功能的设备

reg_map

组件和 ras 寄存器映射参数

regs

已解析的寄存器块

cxl_dvsec

PCIe 设备 DVSEC 的偏移量

rcd

在 RCD 模式下运行 (CXL 3.0 9.11.8 连接到 RCH 的 CXL 设备)

media_ready

指示设备介质是否可用

dpa_res

设备的整体 DPA 资源树

part

DPA 分区数组

nr_partitions

DPA 分区数

serial

PCIe 设备序列号

type

通用内存类设备或供应商特定内存设备

cxl_mbox

CXL 邮箱上下文

cxlfs

CXL 功能上下文

描述

cxl_dev_state 表示 CXL 驱动程序/设备状态。它提供与邮箱命令的接口以及有关设备的一些缓存数据。目前仅表示内存设备。

struct cxl_memdev_state¶

通用 Type-3 内存设备类驱动程序数据

定义:

struct cxl_memdev_state {
    struct cxl_dev_state cxlds;
    size_t lsa_size;
    char firmware_version[0x10];
    u64 total_bytes;
    u64 volatile_only_bytes;
    u64 persistent_only_bytes;
    u64 partition_align_bytes;
    u64 active_volatile_bytes;
    u64 active_persistent_bytes;
    struct cxl_event_state event;
    struct cxl_poison_state poison;
    struct cxl_security_state security;
    struct cxl_fw_state fw;
    struct notifier_block mce_notifier;
};

成员

cxlds

跨 Type-2 和 Type-3 设备的核心驱动程序状态

lsa_size

标签存储区域的大小 (CXL 2.0 8.2.9.5.1.1 识别内存设备)

firmware_version

内存设备的固件版本。

total_bytes

所有可能容量的总和

volatile_only_bytes

硬易失性容量

persistent_only_bytes

硬持久性容量

partition_align_bytes

可分区容量的对齐大小

active_volatile_bytes

硬 + 软易失性容量的总和

active_persistent_bytes

硬 + 软持久性容量的总和

event

事件日志驱动程序状态

poison

中毒驱动程序状态信息

security

安全驱动程序状态信息

fw

固件上传/激活状态

mce_notifier

MCE 通知程序

描述

CXL 8.1.12.1 PCI 标头 - 类代码寄存器内存设备定义了通用内存设备功能,例如邮箱的存在以及与之相关的功能,例如识别内存设备和获取分区信息。有关容量参数的详细信息,请参见 CXL 3.0 8.2.9.8.2 容量配置和标签存储。

struct cxl_mem_command¶

内存设备命令的驱动程序表示

定义:

struct cxl_mem_command {
    struct cxl_command_info info;
    enum cxl_opcode opcode;
    u32 flags;
#define CXL_CMD_FLAG_FORCE_ENABLE BIT(0);
};

成员

info

UAPI 中存在的命令信息

opcode

用于邮箱协议的实际位

flags

影响驱动程序行为的一组标志。

  • CXL_CMD_FLAG_FORCE_ENABLE:在发生错误的情况下,无论硬件可能已通告什么,驱动程序都将启用带有此标志的命令。

描述

cxl_mem_command 是驱动程序内部表示驱动程序支持的命令。某些命令可能不受硬件支持。驱动程序将使用 info 来验证用户传入的字段,然后将 opcode 提交给硬件。

参见 struct cxl_command_info。

struct cxl_hdm¶

HDM 解码器寄存器和缓存/解码功能

定义:

struct cxl_hdm {
    struct cxl_component_regs regs;
    unsigned int decoder_count;
    unsigned int target_count;
    unsigned int interleave_mask;
    unsigned long iw_cap_mask;
    struct cxl_port *port;
};

成员

regs

映射的寄存器,参见 devm_cxl_setup_hdm()

decoder_count

此端口的解码器数量

target_count

对于交换机解码器,最大下游端口目标数

interleave_mask

交织粒度功能,参见 check_interleave_cap()

iw_cap_mask

支持的交织方式的位掩码,参见 check_interleave_cap()

port

映射的 cxl_port,参见 devm_cxl_setup_hdm()

void set_exclusive_cxl_commands(struct cxl_memdev_state *mds, unsigned long *cmds)¶

原子地禁用用户 cxl 命令

参数

struct cxl_memdev_state *mds

要操作的设备状态

unsigned long *cmds

要标记为独占的命令的位图

描述

以写入模式获取 cxl_memdev_rwsem 以刷新飞行中的 ioctl 路径调用,然后禁用未来执行在 cmds 中设置了命令 ID 的命令。

void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds, unsigned long *cmds)¶

原子地启用用户 cxl 命令

参数

struct cxl_memdev_state *mds

要修改的设备状态

unsigned long *cmds

要标记为对用户空间可用的命令的位图

int cxl_mem_get_fw_info(struct cxl_memdev_state *mds)¶

获取固件信息

参数

struct cxl_memdev_state *mds

操作的设备数据

描述

检索指定设备的固件信息。

参见 CXL-3.0 8.2.9.3.1 获取固件信息

返回

如果没有错误,则返回 0;否则返回邮箱命令的结果。

int cxl_mem_activate_fw(struct cxl_memdev_state *mds, int slot)¶

激活固件

参数

struct cxl_memdev_state *mds

操作的设备数据

int slot

要激活的插槽号

描述

激活指定设备中给定插槽中的固件。

参见 CXL-3.0 8.2.9.3.3 激活固件

返回

如果没有错误,则返回 0;否则返回邮箱命令的结果。

int cxl_mem_abort_fw_xfer(struct cxl_memdev_state *mds)¶

中止正在进行的固件传输

参数

struct cxl_memdev_state *mds

操作的设备数据

描述

中止指定设备的正在进行的固件传输。

参见 CXL-3.0 8.2.9.3.2 传输固件

返回

如果没有错误,则返回 0;否则返回邮箱命令的结果。

CXL 端口¶

端口驱动程序通过 PCI 枚举 dport,并通过代理注册端口时传入的 component_reg_phys 值扫描 HDM(主机管理设备内存)解码器资源。CXL 根端口(由平台固件描述)的所有后代端口都在此驱动程序上下文中进行管理。每个驱动程序实例负责拆除直接后代端口的驱动程序上下文。此锁定的验证由 CONFIG_PROVE_CXL_LOCKING 完成。

此驱动程序提供的主要服务是向其他驱动程序提供 API 以利用解码器,并通过绑定状态向用户空间指示整个 PCIe 拓扑中 CXL.mem 协议的连接。

CXL Core¶

CXL 核心对象(如端口、解码器和区域)在子系统驱动程序 cxl_acpi、cxl_pci 和核心驱动程序(端口驱动程序、区域驱动程序、nvdimm 对象驱动程序等)之间共享。

struct cxl_register_map¶

DVSEC 收集的寄存器块映射参数

定义:

struct cxl_register_map {
    struct device *host;
    void __iomem *base;
    resource_size_t resource;
    resource_size_t max_size;
    u8 reg_type;
    union {
        struct cxl_component_reg_map component_map;
        struct cxl_device_reg_map device_map;
        struct cxl_pmu_reg_map pmu_map;
    };
};

成员

host

用于 devm 操作和日志记录的设备

base

寄存器块的虚拟基地址 - BAR + block_offset

resource

寄存器块的物理资源基地址

max_size

执行寄存器搜索的最大映射大小

reg_type

参见 enum cxl_regloc_type

{unnamed_union}

anonymous

component_map

组件寄存器的 cxl_reg_map

device_map

设备寄存器的 cxl_reg_maps

pmu_map

CXL 性能监视单元的 cxl_reg_maps

struct cxl_decoder¶

通用 CXL HDM 解码器属性

定义:

struct cxl_decoder {
    struct device dev;
    int id;
    struct range hpa_range;
    int interleave_ways;
    int interleave_granularity;
    enum cxl_decoder_type target_type;
    struct cxl_region *region;
    unsigned long flags;
    int (*commit)(struct cxl_decoder *cxld);
    void (*reset)(struct cxl_decoder *cxld);
};

成员

dev

此解码器的设备

id

内核设备名称 ID

hpa_range

此解码器映射的主机物理地址范围

interleave_ways

此解码中的 cxl_dports 数量

interleave_granularity

每个 dport 的数据步幅

target_type

加速器与扩展器(type2 与 type3)选择器

region

当前为此解码器分配的区域

flags

内存类型功能和锁定

commit

特定于设备/解码器类型的回调,用于将设置提交到硬件

reset

特定于设备/解码器类型的回调,用于重置硬件设置

struct cxl_endpoint_decoder¶

端点/ SPA 到 DPA 解码器

定义:

struct cxl_endpoint_decoder {
    struct cxl_decoder cxld;
    struct resource *dpa_res;
    resource_size_t skip;
    enum cxl_decoder_state state;
    int part;
    int pos;
};

成员

cxld

基本 cxl_decoder_object

dpa_res

此解码器主动声明的 DPA 跨度

skip

dpa_res 中的偏移量,其中映射 cxld.hpa_range

state

autodiscovery 状态

part

此解码器映射的分区索引

pos

cxld.region 中的交织位置

struct cxl_switch_decoder¶

交换机特定的 CXL HDM 解码器

定义:

struct cxl_switch_decoder {
    struct cxl_decoder cxld;
    int nr_targets;
    struct cxl_dport *target[];
};

成员

cxld

基本 cxl_decoder 对象

nr_targets

target 中的元素数量

target

当前解码器配置中的活动有序目标列表

描述

“switch”解码器类型表示 cxl_port 的解码器实例,这些实例将 CXL 内存解码拓扑的根路由到端点。它们有两种类型:根级解码器,由平台固件静态定义;以及中间级解码器,其中交织粒度、交织宽度和目标列表是可变的。

struct cxl_root_decoder¶

静态平台 CXL 地址解码器

定义:

struct cxl_root_decoder {
    struct resource *res;
    atomic_t region_id;
    cxl_hpa_to_spa_fn hpa_to_spa;
    void *platform_data;
    struct mutex range_lock;
    int qos_class;
    struct cxl_switch_decoder cxlsd;
};

成员

res

区域分配的主机/父资源

region_id

下一个区域配置事件的区域 ID

hpa_to_spa

将 CXL 主机物理地址转换为平台系统物理地址

platform_data

特定于平台的配置数据

range_lock

按地址范围同步区域自动发现

qos_class

QoS 性能类 Cookie

cxlsd

基本 cxl 交换机解码器

struct cxl_region_params¶

区域设置

定义:

struct cxl_region_params {
    enum cxl_config_state state;
    uuid_t uuid;
    int interleave_ways;
    int interleave_granularity;
    struct resource *res;
    struct cxl_endpoint_decoder *targets[CXL_DECODER_MAX_INTERLEAVE];
    int nr_targets;
    resource_size_t cache_size;
};

成员

state

允许驱动程序锁定进一步的参数更改

uuid

持久性区域的唯一 ID

interleave_ways

区域中的端点数量

interleave_granularity

每个端点对条带的贡献容量

res

为此区域分配的 iomem 容量

targets

当前解码器配置中的活动有序目标

nr_targets

目标数量

cache_size

如果存在,则为扩展线性缓存大小,否则为零。

描述

状态转换由 cxl_region_rwsem 保护

struct cxl_region¶

CXL 区域

定义:

struct cxl_region {
    struct device dev;
    int id;
    enum cxl_partition_mode mode;
    enum cxl_decoder_type type;
    struct cxl_nvdimm_bridge *cxl_nvb;
    struct cxl_pmem_region *cxlr_pmem;
    unsigned long flags;
    struct cxl_region_params params;
    struct access_coordinate coord[ACCESS_COORDINATE_MAX];
    struct notifier_block memory_notifier;
    struct notifier_block adist_notifier;
};

成员

dev

此区域的设备

id

此区域的 ID。ID 在所有区域中都是全局唯一的

mode

映射容量的操作模式

type

端点解码器目标类型

cxl_nvb

用于协调 cxlr_pmem 设置/关闭的 nvdimm 桥

cxlr_pmem

(对于 pmem 区域)nvdimm 桥的缓存副本

flags

区域状态标志

params

区域的活动 + 配置参数

coord

区域的 QoS 访问坐标

memory_notifier

用于将访问坐标设置为节点的通知程序

adist_notifier

用于计算节点抽象距离的通知程序

struct cxl_port¶

上游端口设备和下游端口设备的逻辑集合,用于构建 CXL 内存解码层次结构。

定义:

struct cxl_port {
    struct device dev;
    struct device *uport_dev;
    struct device *host_bridge;
    int id;
    struct xarray dports;
    struct xarray endpoints;
    struct xarray regions;
    struct cxl_dport *parent_dport;
    struct ida decoder_ida;
    struct cxl_register_map reg_map;
    int nr_dports;
    int hdm_end;
    int commit_end;
    bool dead;
    unsigned int depth;
    struct cxl_cdat {
        void *table;
        size_t length;
    } cdat;
    bool cdat_available;
    long pci_latency;
};

成员

dev

此端口的设备

uport_dev

实现上游端口功能的 PCI 或平台设备

host_bridge

此端口的平台附加点的快捷方式

id

端口设备名称的 ID

dports

解码器引用的 cxl_dport 实例

endpoints

cxl_ep 实例,是此端口后代的端点

regions

cxl_region_ref 实例,由此端口映射的区域

parent_dport

指向父端口中的该端口的 dport

decoder_ida

解码器 ID 的分配器

reg_map

组件和 ras 寄存器映射参数

nr_dports

dports 中的条目数

hdm_end

跟踪最后分配的 HDM 解码器实例以进行分配排序

commit_end

跟踪最高提交解码器的游标以进行提交排序

dead

已移除最后一个 ep,强制端口重新创建

depth

此端口相对于根端口的深度。深度 0 为根端口。

cdat

缓存的 CDAT 数据

cdat_available

sysfs 中是否应提供 CDAT 属性

pci_latency

上游延迟(皮秒)

struct cxl_root¶

根 cxl_port 项的逻辑集合

定义:

struct cxl_root {
    struct cxl_port port;
    const struct cxl_root_ops *ops;
};

成员

port

cxl_port 成员

ops

cxl 根操作

struct cxl_dport¶

CXL 下游端口

定义:

struct cxl_dport {
    struct device *dport_dev;
    struct cxl_register_map reg_map;
    int port_id;
    struct cxl_rcrb_info rcrb;
    bool rch;
    struct cxl_port *port;
    struct cxl_regs regs;
    struct access_coordinate coord[ACCESS_COORDINATE_MAX];
    long link_latency;
    int gpf_dvsec;
};

成员

dport_dev

表示下游链路的 PCI 桥或固件设备

reg_map

组件和 ras 寄存器映射参数

port_id

解码器目标列表中 dport 的唯一硬件标识符

rcrb

有关根复合体寄存器块布局的数据

rch

指示此 dport 是在 RCH 模式还是 VH 模式下枚举的

port

对包含此下游端口的 cxl_port 的引用

regs

已解析的 Dport 寄存器块

coord

访问坐标(带宽和延迟性能属性)

link_latency

计算的 PCIe 下游延迟

gpf_dvsec

缓存的 GPF 端口 DVSEC

struct cxl_ep¶

跟踪端点对端口的兴趣

定义:

struct cxl_ep {
    struct device *ep;
    struct cxl_dport *dport;
    struct cxl_port *next;
};

成员

ep

托管通用 CXL 端点(扩展器或加速器)的设备

dport

哪个 dport 在 port 上路由到此端点

next

跨连接到 dport 的链路的 cxl 交换机端口,如果连接到端点则为 NULL

struct cxl_region_ref¶

跟踪区域对端口的兴趣

定义:

struct cxl_region_ref {
    struct cxl_port *port;
    struct cxl_decoder *decoder;
    struct cxl_region *region;
    struct xarray endpoints;
    int nr_targets_set;
    int nr_eps;
    int nr_targets;
};

成员

port

拓扑中安装此参考的点

decoder

为 port 中的 region 分配的解码器

region

此参考的区域

endpoints

位于 port 下方的区域成员的 cxl_ep 参考

nr_targets_set

跟踪设置期间已编程的目标数

nr_eps

port 下方的端点数

nr_targets

到达 nr_eps 所需的不同目标数

struct cxl_endpoint_dvsec_info¶

缓存的 DVSEC 信息

定义:

struct cxl_endpoint_dvsec_info {
    bool mem_enabled;
    int ranges;
    struct cxl_port *port;
    struct range dvsec_range[2];
};

成员

mem_enabled

初始化时 DVSEC 中 mem_enabled 的缓存值

ranges

此设备使用的活动 HDM 范围的数量。

port

与此信息实例关联的端点端口

dvsec_range

DVSEC 中范围的缓存属性,PCIE_DEVICE

int add_cxl_resources(struct resource *cxl_res)¶

在 iomem_resource 中反映 CXL 固定内存窗口

参数

struct resource *cxl_res

一个独立的资源树,其中每个 CXL 窗口都是同级窗口

描述

遍历 cxl_res 中的每个 CXL 窗口,并将其添加到 iomem_resource,可能会扩展其边界以确保任何冲突的资源都成为子资源。如果窗口被扩展,则它可能与另一个窗口条目冲突,并需要截断或修剪窗口。考虑这种情况

|-- "CXL Window 0" --||----- "CXL Window 1" -----|
|--------------- "System RAM" -------------|

...其中平台固件已在 2 个窗口中建立为系统 RAM 资源,但已将窗口 1 的某些部分留用于动态 CXL 区域配置。在这种情况下,“窗口 0”将跨越整个“系统 RAM”跨度,而“CXL 窗口 1”将被截断到该“系统 RAM”资源末尾之后的剩余尾部。

Compute Express Link Host Managed Device Memory(主机托管设备内存),从 CXL 2.0 规范开始,由每个 CXL 端口和每个 CXL 端点的一系列 HDM 解码器寄存器实例管理。定义用于枚举这些寄存器和功能的常用助手。

struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, struct cxl_endpoint_dvsec_info *info)¶

映射 HDM 解码器组件寄存器

参数

struct cxl_port *port

要映射的 cxl_port

struct cxl_endpoint_dvsec_info *info

缓存的 DVSEC 范围寄存器信息

int request_skip(struct cxl_dev_state *cxlds, struct cxl_endpoint_decoder *cxled, const resource_size_t skip_base, const resource_size_t skip_len)¶

在 cxlds->dpa_res 资源树中跟踪 DPA“跳过”

参数

struct cxl_dev_state *cxlds

CXL.mem 设备上下文,它是 cxled 的父级

struct cxl_endpoint_decoder *cxled

端点解码器建立跳过较低 DPA 的新分配

const resource_size_t skip_base

DPA < 新 DPA 分配的开始(DPAnew)

const resource_size_t skip_len

skip_base + skip_len == DPAnew

描述

相对于多个分区中的可用容量,DPA“跳过”源自乱序 DPA 分配事件。这是一个浪费的事件,因为可用的 DPA 被丢弃,但如果部署有例如双 RAM+PMEM 设备,想要使用 PMEM,并且有未分配的 RAM DPA,则必须牺牲空闲 RAM DPA 才能开始分配 PMEM。有关更多详细信息,请参阅 CXL 3.1 8.2.4.19.13 “解码器保护”中的第三个“实现说明”。

“跳过”始终覆盖先前分区中最后分配的 DPA 到当前分区要分配的开始。分配永远不会在分区的中间开始,并且分配始终以相反的顺序解除分配(请参阅 cxl_dpa_free(),或来自强制按顺序分配的自然 devm 展开顺序)。

如果保证 cxlds->nr_partitions <= 2,则“跳过”将始终包含在单个分区中。鉴于 cxlds->nr_partitions 可能 > 2,这会导致“跳过”可能跨越“partition[0] 的尾部容量,partition[1] 的全部,...,partition[N-1] 的全部”以支持从 partition[N] 进行分配的情况。反过来,这与 cxlds->dpa_res 中的分区“struct resource”边界交互,从而需要按分区划分“跳过”请求。也就是说,这是使用“struct resource”树来检测范围冲突,同时也在 cxlds->dpa_res 中跟踪分区边界的怪癖。

int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, struct cxl_endpoint_dvsec_info *info)¶

为每个 HDM 寄存器集添加解码器对象

参数

struct cxl_hdm *cxlhdm

要使用 HDM 功能填充的结构

struct cxl_endpoint_dvsec_info *info

缓存的 DVSEC 范围寄存器信息

void cxl_coordinates_combine(struct access_coordinate *out, struct access_coordinate *c1, struct access_coordinate *c2)¶

组合两个输入坐标

参数

struct access_coordinate *out

c1 和 c2 的组合的输出坐标

struct access_coordinate *c1

输入坐标

struct access_coordinate *c2

输入坐标

int cxl_endpoint_gather_bandwidth(struct cxl_region *cxlr, struct cxl_endpoint_decoder *cxled, struct xarray *usp_xa, bool *gp_is_root)¶

在一个 xarray 中收集所有端点带宽

参数

struct cxl_region *cxlr

用于带宽计算的 CXL 区域

struct cxl_endpoint_decoder *cxled

要开始的端点解码器

struct xarray *usp_xa

(输出)收集所有带宽坐标的 xarray,按上游设备索引,数据为“struct cxl_perf_ctx”。

bool *gp_is_root

(输出)祖父母是否为 cxl 根的布尔值。

返回

成功则为 0,或 -errno

描述

收集聚合的端点带宽,并将带宽存储在 xarray 中,该 xarray 由交换机的上游设备或 RP 设备索引。每个端点都包含来自端点 CDAT 的 DSLBIS、端点上游链路带宽以及来自交换机 CDAT 的 SSLBIS(用于交换机上游端口到与端点关联的下游端口)的最小带宽。如果设备直接连接到 RP,则不涉及 SSLBIS。

struct xarray *cxl_switch_gather_bandwidth(struct cxl_region *cxlr, struct xarray *input_xa, bool *gp_is_root)¶

在一个 xarray 中收集交换机级别的所有带宽

参数

struct cxl_region *cxlr

正在操作的区域

struct xarray *input_xa

由交换机的上游设备索引的 xarray,数据为“struct cxl_perf_ctx”

bool *gp_is_root

(输出)祖父母是否为 cxl 根的布尔值。

返回

每个父交换机或根端口的 resulting cxl_perf_ctx 的 xarray

或 ERR_PTR(-errno)

描述

迭代 xarray。获取下游计算带宽、上游链路带宽和上游交换机(如果存在)的 SSLBIS 的最小值。对交换机上游设备或 RP 设备下的结果带宽求和。如果存在多个交换机,则可以对该函数进行多次迭代。

struct xarray *cxl_rp_gather_bandwidth(struct xarray *xa)¶

处理根端口级别的带宽收集

参数

struct xarray *xa

保存 cxl_perf_ctx 的 xarray,该 cxl_perf_ctx 具有每个根端口设备下方计算的带宽。

返回

保存每个主机桥的 cxl_perf_ctx 的 xarray 或 ERR_PTR(-errno)

struct xarray *cxl_hb_gather_bandwidth(struct xarray *xa)¶

处理主机桥级别的带宽收集

参数

struct xarray *xa

保存 cxl_perf_ctx 的 xarray,该 cxl_perf_ctx 具有每个主机桥下方计算的带宽。

返回

保存每个 ACPI0017 设备的 cxl_perf_ctx 的 xarray 或 ERR_PTR(-errno)

void cxl_region_update_bandwidth(struct cxl_region *cxlr, struct xarray *input_xa)¶

更新区域的带宽访问坐标

参数

struct cxl_region *cxlr

正在操作的区域

struct xarray *input_xa

Xarray 保存每个 ACPI0017 实例的具有计算带宽的 cxl_perf_ctx

void cxl_region_shared_upstream_bandwidth_update(struct cxl_region *cxlr)¶

重新计算区域的带宽

参数

struct cxl_region *cxlr

要重新计算的 cxl 区域

描述

该函数从下到上遍历拓扑并计算带宽。它从端点开始,在交换机(如果有)处进行处理,在根端口级别进行处理,在主机桥级别进行处理,最后在区域进行聚合。

CXL 核心提供一组可由 CXL 感知驱动程序使用的接口。这些接口允许创建、修改和销毁区域、内存设备、端口和解码器。CXL 感知驱动程序必须通过这些接口向 CXL 核心注册,以便能够参与跨设备交错协调。CXL 核心还建立和维护与 nvdimm 子系统的桥梁。

CXL 核心引入 sysfs 层次结构来控制由核心实例化的设备。

struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport_dev, resource_size_t component_reg_phys, struct cxl_dport *parent_dport)¶

在 CXL 内存解码层次结构中注册 cxl_port

参数

struct device *host

devm 操作的主机设备

struct device *uport_dev

实现此上游端口的“物理”设备

resource_size_t component_reg_phys

(可选)用于可配置的 cxl_port 实例

struct cxl_dport *parent_dport

CXL 内存解码层次结构中的下一跳

struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, int port_id, resource_size_t component_reg_phys)¶

将 VH 下游端口数据附加到 cxl_port

参数

struct cxl_port *port

引用此 dport 的 cxl_port

struct device *dport_dev

表示 dport 的固件或 PCI 设备

int port_id

解码器目标列表中此 dport 的标识符

resource_size_t component_reg_phys

CXL 组件寄存器的可选位置

描述

请注意,dports 会附加到端口主机(对于根端口)或端口本身(对于交换机端口)的 devm 发布操作。

struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port, struct device *dport_dev, int port_id, resource_size_t rcrb)¶

将 RCH 下游端口数据附加到 cxl_port

参数

struct cxl_port *port

引用此 dport 的 cxl_port

struct device *dport_dev

表示 dport 的固件或 PCI 设备

int port_id

解码器目标列表中此 dport 的标识符

resource_size_t rcrb

根复合体寄存器块的强制位置

描述

请参阅 CXL 3.0 9.11.8 连接到 RCH 的 CXL 设备

int cxl_add_ep(struct cxl_dport *dport, struct device *ep_dev)¶

注册端点对端口的兴趣

参数

struct cxl_dport *dport

路由到 ep_dev 的 dport

struct device *ep_dev

表示端点的设备

描述

中间 CXL 端口根据端点的到达进行扫描。当这些端点离开时,一旦所有关心该端口的端点都已移除,就可以销毁该端口。

int cxl_decoder_init(struct cxl_port *port, struct cxl_decoder *cxld)¶

常见的解码器设置/初始化

参数

struct cxl_port *port

此解码器的拥有端口

struct cxl_decoder *cxld

要初始化的常见解码器属性

描述

一个端口可能包含一个或多个解码器。这些解码器中的每一个都启用了 CXL.mem 利用的一些地址空间。预计解码器在通过 cxl_decoder_add() 注册之前由调用方配置

struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port, unsigned int nr_targets)¶

分配根级别解码器

参数

struct cxl_port *port

此解码器的拥有 CXL 根

unsigned int nr_targets

下游目标的静态数量

返回

要通过 cxl_decoder_add() 注册的新 cxl 解码器。“CXL 根”解码器是一种将 CXL 资源从顶层/静态平台固件描述解码到 CXL 标准解码拓扑中的解码器。

struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port, unsigned int nr_targets)¶

分配交换机级别解码器

参数

struct cxl_port *port

此解码器的拥有 CXL 交换机端口

unsigned int nr_targets

可动态寻址的下游目标的最大数量

返回

要通过 cxl_decoder_add() 注册的新 cxl 解码器。“交换机”解码器是可以由 PCIe 拓扑和 HDM 解码器功能枚举的任何解码器。这包括位于交换机上游端口/交换机下游端口和主机桥/根端口之间的解码器。

struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port)¶

分配端点解码器

参数

struct cxl_port *port

此解码器的拥有端口

返回

要通过 cxl_decoder_add() 注册的新 cxl 解码器

int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map)¶

添加具有目标的解码器

参数

struct cxl_decoder *cxld

由 cxl__decoder_alloc() 分配的 cxl 解码器

int *target_map

此解码器可以将内存流量定向到的下游端口的列表。这些数字应与 PCIe 链路功能结构中的端口号相对应。

描述

某些类型的解码器可能没有任何目标。这方面的主要示例是端点设备。一个更令人尴尬的例子是主机桥,其根端口被热添加(技术上可能,尽管不太可能)。

这是 cxl_decoder_add() 的锁定变体。

上下文

进程上下文。期望拥有 cxld 的端口的设备锁被持有。

返回

如果解码器未正确配置,则为负错误代码;否则

返回 0。

int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map)¶

添加具有目标的解码器

参数

struct cxl_decoder *cxld

由 cxl__decoder_alloc() 分配的 cxl 解码器

int *target_map

此解码器可以将内存流量定向到的下游端口的列表。这些数字应与 PCIe 链路功能结构中的端口号相对应。

描述

这是 cxl_decoder_add_locked() 的未锁定变体。请参阅 cxl_decoder_add_locked()。

上下文

处理上下文。获取和释放拥有 cxld 的端口的设备锁。

int __cxl_driver_register(struct cxl_driver *cxl_drv, struct module *owner, const char *modname)¶

为 cxl 总线注册驱动程序

参数

struct cxl_driver *cxl_drv

要附加的 cxl 驱动程序结构

struct module *owner

拥有模块/驱动程序

const char *modname

父驱动程序的 KBUILD_MODNAME

int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, struct access_coordinate *coord)¶

检索存储在 CXL 路径的 dport 中的性能数字

参数

struct cxl_port *port

端点 cxl_port

struct access_coordinate *coord

输出性能数据

返回

失败时返回 errno,成功时返回 0。

Compute Express Link 协议分层在 PCIe 之上。CXL 核心为 CXL 交互提供了一组助手函数,这些交互通过 PCIe 发生。

int devm_cxl_port_enumerate_dports(struct cxl_port *port)¶

枚举上游端口的下游端口

参数

struct cxl_port *port

cxl_port,其 ->uport_dev 是要枚举的 dport 的上游

描述

返回枚举的 dport 的正数或负错误代码。

int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, struct cxl_endpoint_dvsec_info *info)¶

为端点设置 HDM 解码

参数

struct cxl_dev_state *cxlds

设备状态

struct cxl_hdm *cxlhdm

映射的 HDM 解码器功能

struct cxl_endpoint_dvsec_info *info

缓存的 DVSEC 范围寄存器信息

描述

尝试启用端点的 HDM 解码器功能

void read_cdat_data(struct cxl_port *port)¶

读取此端口上的 CDAT 数据

参数

struct cxl_port *port

从中读取数据的端口

描述

此调用将休眠等待来自 DOE 邮箱的响应。

void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)¶

在此 dport 上设置 CXL RAS 报告

参数

struct cxl_dport *dport

需要初始化的 cxl_dport

struct device *host

devm 操作的主机设备

long cxl_pci_get_latency(struct pci_dev *pdev)¶

计算 PCIe 链路的链路延迟

参数

struct pci_dev *pdev

PCI 设备

返回

计算出的延迟或 0(无延迟)

描述

CXL 内存设备 SW 指南 v1.0 2.11.4 链路延迟计算 链路延迟 = 链路传播延迟 + Flit 延迟 + Retimer 延迟 LinkProgationLatency 可以忽略不计,因此将使用 0 RetimerLatency 假定可以忽略不计,因此将使用 0 FlitLatency = FlitSize / LinkBandwidth FlitSize 由规范定义。CXL rev3.0 4.2.1。 68B flit 用于高达 32GT/s。 >32GT/s,使用 256B flit 大小。 FlitLatency 转换为皮秒。

核心 CXL PMEM 基础设施支持持久性内存配置,并充当与 LIBNVDIMM 子系统的桥梁。如果平台固件至少通告一个支持持久性内存的 CXL 窗口,则会在 CXL 设备拓扑的根添加一个 CXL“桥”设备。该根级别桥对应于 LIBNVDIMM “总线”设备。然后,对于 CXL 设备拓扑中的每个 cxl_memdev,都会添加一个桥设备来托管 LIBNVDIMM dimm 对象。当这些桥注册时,原生 LIBNVDIMM uapi 会转换为 CXL 操作,例如,命名空间标签访问命令。

struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port)¶

查找相对于端口的桥设备

参数

struct cxl_port *port

与 nvdimm-bridge 关联的 root-cxl-port 的任何后代端口

struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, struct cxl_port *port)¶

添加 LIBNVDIMM 拓扑的根

参数

struct device *host

平台固件根设备

struct cxl_port *port

CXL 拓扑根目录的 CXL 端口

返回

可以托管 cxl_nvdimm 对象的桥设备

int devm_cxl_add_nvdimm(struct cxl_port *parent_port, struct cxl_memdev *cxlmd)¶

在 cxl_memdev 和 nvdimm 之间添加桥梁

参数

struct cxl_port *parent_port

(要添加的)cxlmd 端点端口的父端口

struct cxl_memdev *cxlmd

将执行 LIBNVDIMM 操作的 cxl_memdev 实例

返回

成功时返回 0,失败时返回负错误代码。

CXL 设备功能由 PCI DVSEC(指定供应商特定)和/或平台固件提供的描述符枚举。 它们可以定义为一组,例如 CXL 第 8.1.12.2 节内存设备 PCIe 功能和扩展功能授权的设备和组件寄存器,或者它们可以是附加到桥接和端点设备的单个功能。

提供用于枚举和映射这些离散功能的通用基础设施。

void cxl_probe_component_regs(struct device *dev, void __iomem *base, struct cxl_component_reg_map *map)¶

检测 CXL 组件寄存器块

参数

struct device *dev

base 映射的主机设备

void __iomem *base

包含 HDM 解码器功能标头的映射

struct cxl_component_reg_map *map

描述找到的寄存器块信息的映射对象

描述

请参阅 CXL 2.0 8.2.4 组件寄存器布局和定义 请参阅 CXL 2.0 8.2.5.5 CXL 设备寄存器接口

探测组件寄存器信息并在映射对象中返回它。

void cxl_probe_device_regs(struct device *dev, void __iomem *base, struct cxl_device_reg_map *map)¶

检测 CXL 设备寄存器块

参数

struct device *dev

base 映射的主机设备

void __iomem *base

CXL 2.0 8.2.8 CXL 设备寄存器接口的映射

struct cxl_device_reg_map *map

描述找到的寄存器块信息的映射对象

描述

探测设备寄存器信息并在映射对象中返回它。

int cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_type type, struct cxl_register_map *map, unsigned int index)¶

按类型/索引查找寄存器块

参数

struct pci_dev *pdev

要枚举的 CXL PCI 设备。

enum cxl_regloc_type type

寄存器块指示器 id

struct cxl_register_map *map

枚举输出,错误时被破坏

unsigned int index

寄存器定位器 DVSEC 中找到的所需 regblock 的特定实例的索引。

返回

如果寄存器块已枚举,则为 0;否则为负错误代码

描述

CXL DVSEC 可能会指向一个或多个寄存器块,按 type 和 index 搜索它们。

int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, struct cxl_register_map *map)¶

按类型查找寄存器块

参数

struct pci_dev *pdev

要枚举的 CXL PCI 设备。

enum cxl_regloc_type type

寄存器块指示器 id

struct cxl_register_map *map

枚举输出,错误时被破坏

返回

如果寄存器块已枚举,则为 0;否则为负错误代码

描述

CXL DVSEC 可能会指向一个或多个寄存器块,按 type 搜索它们。

int cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type)¶

计算给定 regblock 类型的实例。

参数

struct pci_dev *pdev

要枚举的 CXL PCI 设备。

enum cxl_regloc_type type

寄存器块指示器 id

描述

某些 regblock 可能会重复。 计算有多少个实例。

返回

匹配 regblock 的非负计数,否则为负错误代码。

CXL 2.0 Type-3 内存设备邮箱的核心实现。 该实现由 cxl_pci 驱动程序用于初始化设备并实现 cxl_mem.h IOCTL UAPI。 它还实现了用于 LIBNVDIMM 的 cxl_pmem_ctl() 传输的后端。

int cxl_internal_send_cmd(struct cxl_mailbox *cxl_mbox, struct cxl_mbox_cmd *mbox_cmd)¶

内核内部接口,用于发送邮箱命令

参数

struct cxl_mailbox *cxl_mbox

CXL 邮箱上下文

struct cxl_mbox_cmd *mbox_cmd

要执行的已初始化命令

上下文

任何上下文。

返回

  • %>=0 - 在 out 中返回的字节数。

  • -E2BIG - 有效负载对于硬件来说太大。

  • -EBUSY - 无法获得独占邮箱访问权限。

  • -EFAULT - 发生硬件错误。

  • -ENXIO - 命令已完成,但设备报告了错误。

  • -EIO - 意外的输出大小。

描述

邮箱命令可能会成功执行,但设备本身报告了错误。 虽然这种区别对于来自用户空间的命令可能很有用,但内核只能在两者都成功时使用结果。

bool cxl_payload_from_user_allowed(u16 opcode, void *payload_in)¶

检查 in_payload 的内容。

参数

u16 opcode

邮箱命令操作码。

void *payload_in

指向从用户空间传入的输入有效负载的指针。

返回

  • true - payload_in 通过了 opcode 的检查。

  • false - payload_in 包含无效或不支持的值。

描述

驱动程序可能会在将来自用户空间的邮箱命令发送到设备之前检查有效负载内容。 其目的是拒绝具有已知不安全的输入有效负载的命令。 此检查并非旨在取代用户对邮箱命令参数的仔细选择,也不保证用户命令会成功或适当。

特定检查由操作码确定。

int cxl_validate_cmd_from_user(struct cxl_mbox_cmd *mbox_cmd, struct cxl_mailbox *cxl_mbox, const struct cxl_send_command *send_cmd)¶

检查 CXL_MEM_SEND_COMMAND 的字段。

参数

struct cxl_mbox_cmd *mbox_cmd

已清理和填充的 struct cxl_mbox_cmd。

struct cxl_mailbox *cxl_mbox

CXL 邮箱上下文

const struct cxl_send_command *send_cmd

从用户空间复制的 struct cxl_send_command。

返回

  • 0 - out_cmd 准备好发送。

  • -ENOTTY - 指定了无效命令。

  • -EINVAL - 使用了保留字段或无效值。

  • -ENOMEM - 输入或输出缓冲区大小不正确。

  • -EPERM - 尝试使用受保护的命令。

  • -EBUSY - 内核已声明对此操作码的独占访问权限

描述

此命令的结果是 mbox_cmd 中完全验证的命令,可以安全地发送到硬件。

int handle_mailbox_cmd_from_user(struct cxl_mailbox *cxl_mbox, struct cxl_mbox_cmd *mbox_cmd, u64 out_payload, s32 *size_out, u32 *retval)¶

为用户空间分派邮箱命令。

参数

struct cxl_mailbox *cxl_mbox

操作的邮箱上下文。

struct cxl_mbox_cmd *mbox_cmd

经过验证的邮箱命令。

u64 out_payload

指向用户空间的输出有效负载的指针。

s32 *size_out

(输入)要复制出的最大有效负载大小。(输出)硬件生成的有效负载大小。

u32 *retval

来自操作的硬件生成的返回代码。

返回

  • 0 - 邮箱事务成功。 这意味着邮箱

    协议已成功完成,而不是操作本身成功。

  • -ENOMEM - 无法分配反弹缓冲区。

  • -EFAULT - copy_to/from_user 发生了某些情况。

  • -EINTR - 邮箱获取中断。

  • -EXXX - 事务级别故障。

描述

代表用户空间请求分派邮箱命令。 输出有效负载已复制到用户空间。

请参阅 cxl_send_cmd()。

void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel)¶

遍历命令效果日志。

参数

struct cxl_memdev_state *mds

操作的驱动程序数据

size_t size

命令效果日志的长度。

u8 *cel

CEL

描述

迭代 CEL 中的每个条目,并确定驱动程序是否支持该命令。 如果是,则该命令已为设备启用,并且可以在以后使用。

int cxl_enumerate_cmds(struct cxl_memdev_state *mds)¶

枚举设备的命令。

参数

struct cxl_memdev_state *mds

操作的驱动程序数据

描述

如果枚举成功完成,则返回 0。

CXL 设备可选地支持某些命令。 此函数将确定硬件支持的命令集,并更新 mds 中的 enabled_cmds 位图。

void cxl_mem_get_event_records(struct cxl_memdev_state *mds, u32 status)¶

从设备获取事件记录

参数

struct cxl_memdev_state *mds

操作的驱动程序数据

u32 status

事件状态寄存器值,用于标识哪些事件可用。

描述

检索设备上所有可用的事件记录,将其报告为跟踪事件,并清除它们。

请参阅 CXL rev 3.0 8.2.9.2.2 获取事件记录 请参阅 CXL rev 3.0 8.2.9.2.3 清除事件记录

int cxl_mem_get_partition_info(struct cxl_memdev_state *mds)¶

获取分区信息

参数

struct cxl_memdev_state *mds

操作的驱动程序数据

描述

检索指定设备的当前分区信息。 活动值是以字节为单位的当前容量。 如果不为 0,“next”值是以字节为单位的待定值,将在下次冷复位时生效。

请参阅 CXL 8.2.9.5.2.1 获取分区信息

返回

如果没有错误,则返回 0;否则返回邮箱命令的结果。

int cxl_dev_state_identify(struct cxl_memdev_state *mds)¶

将 IDENTIFY 命令发送到设备。

参数

struct cxl_memdev_state *mds

操作的驱动程序数据

返回

如果 identify 已成功执行或介质未准备好,则返回 0。

描述

这会将 identify 命令分派到设备,并在成功时填充要导出到 sysfs 的结构。

int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)¶

将清理命令发送到设备。

参数

struct cxl_memdev *cxlmd

操作的设备

u16 cmd

特定的清理命令操作码

返回

如果命令已成功执行,则返回 0,无论实际的安全操作是否在后台完成,例如对于清理的情况。 错误返回值可能是邮箱命令的结果,如果不满足安全要求或上下文无效,则为 -EINVAL;如果清理操作已经在进行中,则为 -EBUSY。

描述

请参阅 CXL 3.0 8.2.9.8.5.1 清理和 8.2.9.8.5.2 安全擦除。

CXL 功能:包括邮箱的 CXL 设备支持允许列出、获取和设置可选定义的功能的命令,例如内存备用或后封装备用。 供应商可以为设备定义自定义功能。

有关 API 详细信息,请参阅 devm_cxl_setup_features()。

CXL 区域¶

CXL 区域表示系统物理地址空间中映射的内存容量。 虽然 CXL 根解码器标识潜在 CXL 内存范围的边界,但区域表示主机桥、交换机和拓扑中端点的 HDM 解码器功能结构映射的活动容量。

区域配置具有排序约束。 UUID 可以随时设置,但仅对持久性区域可见。 1. 交错粒度 2. 交错大小 3. 解码器目标

struct cxl_decoder *cxl_port_pick_region_decoder(struct cxl_port *port, struct cxl_endpoint_decoder *cxled, struct cxl_region *cxlr)¶

为区域分配或查找解码器

参数

struct cxl_port *port

cxled 暗示的端点的祖先端口

struct cxl_endpoint_decoder *cxled

要由 port 映射或当前映射的端点解码器

struct cxl_region *cxlr

要建立或验证解码 port 的区域

描述

在区域创建路径中,cxl_port_pick_region_decoder() 是一个分配器,用于查找空闲端口。 在区域组装路径中,它是调用平台固件选择的解码器以用于验证目的。

结果记录在 port 中的 'struct cxl_region_ref' 中。

int cxl_port_attach_region(struct cxl_port *port, struct cxl_region *cxlr, struct cxl_endpoint_decoder *cxled, int pos)¶

通过端点跟踪区域对端口的兴趣

参数

struct cxl_port *port

要添加新区域引用“struct cxl_region_ref”的端口

struct cxl_region *cxlr

要附加到 port 的区域

struct cxl_endpoint_decoder *cxled

用于创建或进一步固定区域引用的端点解码器

int pos

cxled 在 cxlr 中的交错位置

描述

附加事件是一个验证 CXL 解码设置约束和记录编程 HDM 解码器所需的元数据的机会,特别是解码器目标列表。

步骤如下:

  • 验证是否没有其他具有更高 HPA 的区域已经与 port 关联

  • 如果区域引用尚不存在,则建立一个

    • 此外,分配一个解码器实例,该实例将在 port 上托管 cxlr

  • 通过端点固定区域引用

  • 说明需要多少 port 的目标列表条目来覆盖所有添加的端点。

int cxl_calc_interleave_pos(struct cxl_endpoint_decoder *cxled)¶

计算区域中的端点位置

参数

struct cxl_endpoint_decoder *cxled

给定区域的端点解码器成员

描述

端点位置是通过从端点到根解码器的拓扑结构遍历,并迭代应用此计算来计算的

position = position * parent_ways + parent_pos;

...其中 position 是从交换机和根解码器目标列表推断出来的。

返回

成功时 position >= 0

失败时 -ENXIO

struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd, int id, enum cxl_partition_mode mode, enum cxl_decoder_type type)¶

向解码器添加区域

参数

struct cxl_root_decoder *cxlrd

根解码器

int id

要创建的 memregion id,或失败时 memregion_free()

enum cxl_partition_mode mode

此区域的端点解码器的模式

enum cxl_decoder_type type

选择这是扩展器还是加速器(type-2 或 type-3)

描述

这是区域初始化的第二步。区域存在于一个地址空间中,该地址空间由 cxlrd 映射。

返回

如果该区域已添加到 cxlrd,则为 0,否则返回负错误代码。该区域将被命名为“regionZ”,其中 Z 是唯一的区域编号。

int devm_cxl_add_pmem_region(struct cxl_region *cxlr)¶

添加 cxl_region 到 nd_region 的桥梁

参数

struct cxl_region *cxlr

此 pmem 区域桥设备的上层 CXL 区域

返回

成功时返回 0,失败时返回负错误代码。

外部接口¶

CXL IOCTL 接口¶

并非驱动程序支持的所有命令都可以在任何时候供用户空间使用。用户空间可以检查 QUERY 命令的结果以确定实时命令集。或者,它可以发出命令并检查是否失败。

struct cxl_command_info¶

从查询返回的命令信息。

定义:

struct cxl_command_info {
    __u32 id;
    __u32 flags;
#define CXL_MEM_COMMAND_FLAG_MASK               GENMASK(1, 0);
#define CXL_MEM_COMMAND_FLAG_ENABLED            BIT(0);
#define CXL_MEM_COMMAND_FLAG_EXCLUSIVE          BIT(1);
    __u32 size_in;
    __u32 size_out;
};

成员

id

命令的 ID 号。

flags

指定命令行为的标志。

CXL_MEM_COMMAND_FLAG_USER_ENABLED

给定的命令 ID 受驱动程序支持,并且受设备上相关操作码的支持。

CXL_MEM_COMMAND_FLAG_EXCLUSIVE

具有给定命令 ID 的请求将以 EBUSY 终止,因为内核主动拥有给定资源的管理。例如,当内核主动管理该空间时,无法写入标签存储区域。

size_in

预期输入大小,如果长度可变,则为 ~0。

size_out

预期输出大小,如果长度可变,则为 ~0。

描述

表示驱动程序和硬件都支持的单个命令。这是作为查询 ioctl 的数组的一部分返回的。以下命令将采用可变长度的输入并返回 0 字节的输出。

  • id = 10

  • flags = CXL_MEM_COMMAND_FLAG_ENABLED

  • size_in = ~0

  • size_out = 0

参见 struct cxl_mem_query_commands。

struct cxl_mem_query_commands¶

查询支持的命令。

定义:

struct cxl_mem_query_commands {
    __u32 n_commands;
    __u32 rsvd;
    struct cxl_command_info __user commands[];
};

成员

n_commands

输入/输出参数。当 n_commands > 0 时,驱动程序将返回 min(num_support_commands, n_commands)。当 n_commands 为 0 时,驱动程序将返回支持的命令的总数。

rsvd

保留供将来使用。

commands

支持的命令的输出数组。此数组必须由用户空间分配,至少为 min(num_support_commands, n_commands)

描述

允许用户空间查询驱动程序和硬件都支持的可用命令。查询中不会返回驱动程序或硬件不支持的命令。

例子

  • { .n_commands = 0 } // 获取支持的命令数

  • { .n_commands = 15, .commands = buf } // 返回前 15 个(或更少)支持的命令

参见 struct cxl_command_info。

struct cxl_send_command¶

向内存设备发送命令。

定义:

struct cxl_send_command {
    __u32 id;
    __u32 flags;
    union {
        struct {
            __u16 opcode;
            __u16 rsvd;
        } raw;
        __u32 rsvd;
    };
    __u32 retval;
    struct {
        __u32 size;
        __u32 rsvd;
        __u64 payload;
    } in;
    struct {
        __u32 size;
        __u32 rsvd;
        __u64 payload;
    } out;
};

成员

id

要发送到内存设备的命令。这必须是查询命令返回的命令之一。

flags

命令的标志(输入)。

{unnamed_union}

anonymous

raw

原始命令的特殊字段

raw.opcode

使用 RAW 命令时传递给硬件的操作码。

raw.rsvd

必须为零。

rsvd

必须为零。

retval

来自内存设备的返回值(输出)。

in

与输入有效负载关联的参数。

in.size

提供给设备的有效负载的大小(输入)。

in.rsvd

必须为零。

in.payload

指向有效负载输入的内存的指针,有效负载是小端字节序。

out

与输出有效负载关联的参数。

out.size

从设备接收的有效负载的大小(输入/输出)。此字段由用户空间填写,以告知驱动程序为输出分配了多少空间。它由驱动程序填充,以使用户空间知道实际的输出有效负载有多大。

out.rsvd

必须为零。

out.payload

指向有效负载输出的内存的指针,有效负载是小端字节序。

描述

用户空间向硬件发送命令进行处理的机制。驱动程序将对命令大小进行基本验证。在某些情况下,甚至可能会检查有效负载。用户空间需要为 size_out 分配足够大的缓冲区,在某些情况下,size_out 的长度可能可变。

©The kernel development community. | Powered by Sphinx 5.3.0 & Alabaster 0.7.16 | Page source