mirror of https://gitee.com/openkylin/linux.git
384 lines
14 KiB
Plaintext
384 lines
14 KiB
Plaintext
Coherent Accelerator Interface (CXL)
|
|
====================================
|
|
|
|
Introduction
|
|
============
|
|
|
|
The coherent accelerator interface is designed to allow the
|
|
coherent connection of accelerators (FPGAs and other devices) to a
|
|
POWER system. These devices need to adhere to the Coherent
|
|
Accelerator Interface Architecture (CAIA).
|
|
|
|
IBM refers to this as the Coherent Accelerator Processor Interface
|
|
or CAPI. In the kernel it's referred to by the name CXL to avoid
|
|
confusion with the ISDN CAPI subsystem.
|
|
|
|
Coherent in this context means that the accelerator and CPUs can
|
|
both access system memory directly and with the same effective
|
|
addresses.
|
|
|
|
|
|
Hardware overview
|
|
=================
|
|
|
|
POWER8 FPGA
|
|
+----------+ +---------+
|
|
| | | |
|
|
| CPU | | AFU |
|
|
| | | |
|
|
| | | |
|
|
| | | |
|
|
+----------+ +---------+
|
|
| PHB | | |
|
|
| +------+ | PSL |
|
|
| | CAPP |<------>| |
|
|
+---+------+ PCIE +---------+
|
|
|
|
The POWER8 chip has a Coherently Attached Processor Proxy (CAPP)
|
|
unit which is part of the PCIe Host Bridge (PHB). This is managed
|
|
by Linux by calls into OPAL. Linux doesn't directly program the
|
|
CAPP.
|
|
|
|
The FPGA (or coherently attached device) consists of two parts.
|
|
The POWER Service Layer (PSL) and the Accelerator Function Unit
|
|
(AFU). The AFU is used to implement specific functionality behind
|
|
the PSL. The PSL, among other things, provides memory address
|
|
translation services to allow each AFU direct access to userspace
|
|
memory.
|
|
|
|
The AFU is the core part of the accelerator (eg. the compression,
|
|
crypto etc function). The kernel has no knowledge of the function
|
|
of the AFU. Only userspace interacts directly with the AFU.
|
|
|
|
The PSL provides the translation and interrupt services that the
|
|
AFU needs. This is what the kernel interacts with. For example, if
|
|
the AFU needs to read a particular effective address, it sends
|
|
that address to the PSL, the PSL then translates it, fetches the
|
|
data from memory and returns it to the AFU. If the PSL has a
|
|
translation miss, it interrupts the kernel and the kernel services
|
|
the fault. The context to which this fault is serviced is based on
|
|
who owns that acceleration function.
|
|
|
|
|
|
AFU Modes
|
|
=========
|
|
|
|
There are two programming modes supported by the AFU. Dedicated
|
|
and AFU directed. AFU may support one or both modes.
|
|
|
|
When using dedicated mode only one MMU context is supported. In
|
|
this mode, only one userspace process can use the accelerator at
|
|
time.
|
|
|
|
When using AFU directed mode, up to 16K simultaneous contexts can
|
|
be supported. This means up to 16K simultaneous userspace
|
|
applications may use the accelerator (although specific AFUs may
|
|
support fewer). In this mode, the AFU sends a 16 bit context ID
|
|
with each of its requests. This tells the PSL which context is
|
|
associated with each operation. If the PSL can't translate an
|
|
operation, the ID can also be accessed by the kernel so it can
|
|
determine the userspace context associated with an operation.
|
|
|
|
|
|
MMIO space
|
|
==========
|
|
|
|
A portion of the accelerator MMIO space can be directly mapped
|
|
from the AFU to userspace. Either the whole space can be mapped or
|
|
just a per context portion. The hardware is self describing, hence
|
|
the kernel can determine the offset and size of the per context
|
|
portion.
|
|
|
|
|
|
Interrupts
|
|
==========
|
|
|
|
AFUs may generate interrupts that are destined for userspace. These
|
|
are received by the kernel as hardware interrupts and passed onto
|
|
userspace by a read syscall documented below.
|
|
|
|
Data storage faults and error interrupts are handled by the kernel
|
|
driver.
|
|
|
|
|
|
Work Element Descriptor (WED)
|
|
=============================
|
|
|
|
The WED is a 64-bit parameter passed to the AFU when a context is
|
|
started. Its format is up to the AFU hence the kernel has no
|
|
knowledge of what it represents. Typically it will be the
|
|
effective address of a work queue or status block where the AFU
|
|
and userspace can share control and status information.
|
|
|
|
|
|
|
|
|
|
User API
|
|
========
|
|
|
|
For AFUs operating in AFU directed mode, two character device
|
|
files will be created. /dev/cxl/afu0.0m will correspond to a
|
|
master context and /dev/cxl/afu0.0s will correspond to a slave
|
|
context. Master contexts have access to the full MMIO space an
|
|
AFU provides. Slave contexts have access to only the per process
|
|
MMIO space an AFU provides.
|
|
|
|
For AFUs operating in dedicated process mode, the driver will
|
|
only create a single character device per AFU called
|
|
/dev/cxl/afu0.0d. This will have access to the entire MMIO space
|
|
that the AFU provides (like master contexts in AFU directed).
|
|
|
|
The types described below are defined in include/uapi/misc/cxl.h
|
|
|
|
The following file operations are supported on both slave and
|
|
master devices.
|
|
|
|
A userspace library libcxl is available here:
|
|
https://github.com/ibm-capi/libcxl
|
|
This provides a C interface to this kernel API.
|
|
|
|
open
|
|
----
|
|
|
|
Opens the device and allocates a file descriptor to be used with
|
|
the rest of the API.
|
|
|
|
A dedicated mode AFU only has one context and only allows the
|
|
device to be opened once.
|
|
|
|
An AFU directed mode AFU can have many contexts, the device can be
|
|
opened once for each context that is available.
|
|
|
|
When all available contexts are allocated the open call will fail
|
|
and return -ENOSPC.
|
|
|
|
Note: IRQs need to be allocated for each context, which may limit
|
|
the number of contexts that can be created, and therefore
|
|
how many times the device can be opened. The POWER8 CAPP
|
|
supports 2040 IRQs and 3 are used by the kernel, so 2037 are
|
|
left. If 1 IRQ is needed per context, then only 2037
|
|
contexts can be allocated. If 4 IRQs are needed per context,
|
|
then only 2037/4 = 509 contexts can be allocated.
|
|
|
|
|
|
ioctl
|
|
-----
|
|
|
|
CXL_IOCTL_START_WORK:
|
|
Starts the AFU context and associates it with the current
|
|
process. Once this ioctl is successfully executed, all memory
|
|
mapped into this process is accessible to this AFU context
|
|
using the same effective addresses. No additional calls are
|
|
required to map/unmap memory. The AFU memory context will be
|
|
updated as userspace allocates and frees memory. This ioctl
|
|
returns once the AFU context is started.
|
|
|
|
Takes a pointer to a struct cxl_ioctl_start_work:
|
|
|
|
struct cxl_ioctl_start_work {
|
|
__u64 flags;
|
|
__u64 work_element_descriptor;
|
|
__u64 amr;
|
|
__s16 num_interrupts;
|
|
__s16 reserved1;
|
|
__s32 reserved2;
|
|
__u64 reserved3;
|
|
__u64 reserved4;
|
|
__u64 reserved5;
|
|
__u64 reserved6;
|
|
};
|
|
|
|
flags:
|
|
Indicates which optional fields in the structure are
|
|
valid.
|
|
|
|
work_element_descriptor:
|
|
The Work Element Descriptor (WED) is a 64-bit argument
|
|
defined by the AFU. Typically this is an effective
|
|
address pointing to an AFU specific structure
|
|
describing what work to perform.
|
|
|
|
amr:
|
|
Authority Mask Register (AMR), same as the powerpc
|
|
AMR. This field is only used by the kernel when the
|
|
corresponding CXL_START_WORK_AMR value is specified in
|
|
flags. If not specified the kernel will use a default
|
|
value of 0.
|
|
|
|
num_interrupts:
|
|
Number of userspace interrupts to request. This field
|
|
is only used by the kernel when the corresponding
|
|
CXL_START_WORK_NUM_IRQS value is specified in flags.
|
|
If not specified the minimum number required by the
|
|
AFU will be allocated. The min and max number can be
|
|
obtained from sysfs.
|
|
|
|
reserved fields:
|
|
For ABI padding and future extensions
|
|
|
|
CXL_IOCTL_GET_PROCESS_ELEMENT:
|
|
Get the current context id, also known as the process element.
|
|
The value is returned from the kernel as a __u32.
|
|
|
|
|
|
mmap
|
|
----
|
|
|
|
An AFU may have an MMIO space to facilitate communication with the
|
|
AFU. If it does, the MMIO space can be accessed via mmap. The size
|
|
and contents of this area are specific to the particular AFU. The
|
|
size can be discovered via sysfs.
|
|
|
|
In AFU directed mode, master contexts are allowed to map all of
|
|
the MMIO space and slave contexts are allowed to only map the per
|
|
process MMIO space associated with the context. In dedicated
|
|
process mode the entire MMIO space can always be mapped.
|
|
|
|
This mmap call must be done after the START_WORK ioctl.
|
|
|
|
Care should be taken when accessing MMIO space. Only 32 and 64-bit
|
|
accesses are supported by POWER8. Also, the AFU will be designed
|
|
with a specific endianness, so all MMIO accesses should consider
|
|
endianness (recommend endian(3) variants like: le64toh(),
|
|
be64toh() etc). These endian issues equally apply to shared memory
|
|
queues the WED may describe.
|
|
|
|
|
|
read
|
|
----
|
|
|
|
Reads events from the AFU. Blocks if no events are pending
|
|
(unless O_NONBLOCK is supplied). Returns -EIO in the case of an
|
|
unrecoverable error or if the card is removed.
|
|
|
|
read() will always return an integral number of events.
|
|
|
|
The buffer passed to read() must be at least 4K bytes.
|
|
|
|
The result of the read will be a buffer of one or more events,
|
|
each event is of type struct cxl_event, of varying size.
|
|
|
|
struct cxl_event {
|
|
struct cxl_event_header header;
|
|
union {
|
|
struct cxl_event_afu_interrupt irq;
|
|
struct cxl_event_data_storage fault;
|
|
struct cxl_event_afu_error afu_error;
|
|
};
|
|
};
|
|
|
|
The struct cxl_event_header is defined as:
|
|
|
|
struct cxl_event_header {
|
|
__u16 type;
|
|
__u16 size;
|
|
__u16 process_element;
|
|
__u16 reserved1;
|
|
};
|
|
|
|
type:
|
|
This defines the type of event. The type determines how
|
|
the rest of the event is structured. These types are
|
|
described below and defined by enum cxl_event_type.
|
|
|
|
size:
|
|
This is the size of the event in bytes including the
|
|
struct cxl_event_header. The start of the next event can
|
|
be found at this offset from the start of the current
|
|
event.
|
|
|
|
process_element:
|
|
Context ID of the event.
|
|
|
|
reserved field:
|
|
For future extensions and padding.
|
|
|
|
If the event type is CXL_EVENT_AFU_INTERRUPT then the event
|
|
structure is defined as:
|
|
|
|
struct cxl_event_afu_interrupt {
|
|
__u16 flags;
|
|
__u16 irq; /* Raised AFU interrupt number */
|
|
__u32 reserved1;
|
|
};
|
|
|
|
flags:
|
|
These flags indicate which optional fields are present
|
|
in this struct. Currently all fields are mandatory.
|
|
|
|
irq:
|
|
The IRQ number sent by the AFU.
|
|
|
|
reserved field:
|
|
For future extensions and padding.
|
|
|
|
If the event type is CXL_EVENT_DATA_STORAGE then the event
|
|
structure is defined as:
|
|
|
|
struct cxl_event_data_storage {
|
|
__u16 flags;
|
|
__u16 reserved1;
|
|
__u32 reserved2;
|
|
__u64 addr;
|
|
__u64 dsisr;
|
|
__u64 reserved3;
|
|
};
|
|
|
|
flags:
|
|
These flags indicate which optional fields are present in
|
|
this struct. Currently all fields are mandatory.
|
|
|
|
address:
|
|
The address that the AFU unsuccessfully attempted to
|
|
access. Valid accesses will be handled transparently by the
|
|
kernel but invalid accesses will generate this event.
|
|
|
|
dsisr:
|
|
This field gives information on the type of fault. It is a
|
|
copy of the DSISR from the PSL hardware when the address
|
|
fault occurred. The form of the DSISR is as defined in the
|
|
CAIA.
|
|
|
|
reserved fields:
|
|
For future extensions
|
|
|
|
If the event type is CXL_EVENT_AFU_ERROR then the event structure
|
|
is defined as:
|
|
|
|
struct cxl_event_afu_error {
|
|
__u16 flags;
|
|
__u16 reserved1;
|
|
__u32 reserved2;
|
|
__u64 error;
|
|
};
|
|
|
|
flags:
|
|
These flags indicate which optional fields are present in
|
|
this struct. Currently all fields are Mandatory.
|
|
|
|
error:
|
|
Error status from the AFU. Defined by the AFU.
|
|
|
|
reserved fields:
|
|
For future extensions and padding
|
|
|
|
Sysfs Class
|
|
===========
|
|
|
|
A cxl sysfs class is added under /sys/class/cxl to facilitate
|
|
enumeration and tuning of the accelerators. Its layout is
|
|
described in Documentation/ABI/testing/sysfs-class-cxl
|
|
|
|
|
|
Udev rules
|
|
==========
|
|
|
|
The following udev rules could be used to create a symlink to the
|
|
most logical chardev to use in any programming mode (afuX.Yd for
|
|
dedicated, afuX.Ys for afu directed), since the API is virtually
|
|
identical for each:
|
|
|
|
SUBSYSTEM=="cxl", ATTRS{mode}=="dedicated_process", SYMLINK="cxl/%b"
|
|
SUBSYSTEM=="cxl", ATTRS{mode}=="afu_directed", \
|
|
KERNEL=="afu[0-9]*.[0-9]*s", SYMLINK="cxl/%b"
|