요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
FPGA Manager
============
Overview
--------
The FPGA manager core exports a set of functions for programming an FPGA with
an image. The API is manufacturer agnostic. All manufacturer specifics are
hidden away in a low level driver which registers a set of ops with the core.
The FPGA image data itself is very manufacturer specific, but for our purposes
it's just binary data. The FPGA manager core won't parse it.
The FPGA image to be programmed can be in a scatter gather list, a single
contiguous buffer, or a firmware file. Because allocating contiguous kernel
memory for the buffer should be avoided, users are encouraged to use a scatter
gather list instead if possible.
The particulars for programming the image are presented in a structure (struct
fpga_image_info). This struct contains parameters such as pointers to the
FPGA image as well as image-specific particulars such as whether the image was
built for full or partial reconfiguration.
How to support a new FPGA device
--------------------------------
To add another FPGA manager, write a driver that implements a set of ops. The
probe function calls ``fpga_mgr_register()`` or ``fpga_mgr_register_full()``,
such as::
static const struct fpga_manager_ops socfpga_fpga_ops = {
.write_init = socfpga_fpga_ops_configure_init,
.write = socfpga_fpga_ops_configure_write,
.write_complete = socfpga_fpga_ops_configure_complete,
.state = socfpga_fpga_ops_state,
};
static int socfpga_fpga_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct socfpga_fpga_priv *priv;
struct fpga_manager *mgr;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/*
* do ioremaps, get interrupts, etc. and save
* them in priv
*/
mgr = fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager",
&socfpga_fpga_ops, priv);
if (IS_ERR(mgr))
return PTR_ERR(mgr);
platform_set_drvdata(pdev, mgr);
return 0;
}
static int socfpga_fpga_remove(struct platform_device *pdev)
{
struct fpga_manager *mgr = platform_get_drvdata(pdev);
fpga_mgr_unregister(mgr);
return 0;
}
Alternatively, the probe function could call one of the resource managed
register functions, ``devm_fpga_mgr_register()`` or
``devm_fpga_mgr_register_full()``. When these functions are used, the
parameter syntax is the same, but the call to ``fpga_mgr_unregister()`` should be
removed. In the above example, the ``socfpga_fpga_remove()`` function would not be
required.
The ops will implement whatever device specific register writes are needed to
do the programming sequence for this particular FPGA. These ops return 0 for
success or negative error codes otherwise.
The programming sequence is::
1. .parse_header (optional, may be called once or multiple times)
2. .write_init
3. .write or .write_sg (may be called once or multiple times)
4. .write_complete
The .parse_header function will set header_size and data_size to
struct fpga_image_info. Before parse_header call, header_size is initialized
with initial_header_size. If flag skip_header of fpga_manager_ops is true,
.write function will get image buffer starting at header_size offset from the
beginning. If data_size is set, .write function will get data_size bytes of
the image buffer, otherwise .write will get data up to the end of image buffer.
This will not affect .write_sg, .write_sg will still get whole image in
sg_table form. If FPGA image is already mapped as a single contiguous buffer,
whole buffer will be passed into .parse_header. If image is in scatter-gather
form, core code will buffer up at least .initial_header_size before the first
call of .parse_header, if it is not enough, .parse_header should set desired
size into info->header_size and return -EAGAIN, then it will be called again
with greater part of image buffer on the input.
The .write_init function will prepare the FPGA to receive the image data. The
buffer passed into .write_init will be at least info->header_size bytes long;
if the whole bitstream is not immediately available then the core code will
buffer up at least this much before starting.
The .write function writes a buffer to the FPGA. The buffer may be contain the
whole FPGA image or may be a smaller chunk of an FPGA image. In the latter
case, this function is called multiple times for successive chunks. This interface
is suitable for drivers which use PIO.
The .write_sg version behaves the same as .write except the input is a sg_table
scatter list. This interface is suitable for drivers which use DMA.
The .write_complete function is called after all the image has been written
to put the FPGA into operating mode.
The ops include a .state function which will determine the state the FPGA is in
and return a code of type enum fpga_mgr_states. It doesn't result in a change
in state.
API for implementing a new FPGA Manager driver
----------------------------------------------
* ``fpga_mgr_states`` - Values for :c:expr:`fpga_manager->state`.
* struct fpga_manager - the FPGA manager struct
* struct fpga_manager_ops - Low level FPGA manager driver ops
* struct fpga_manager_info - Parameter structure for fpga_mgr_register_full()
* __fpga_mgr_register_full() - Create and register an FPGA manager using the
fpga_mgr_info structure to provide the full flexibility of options
* __fpga_mgr_register() - Create and register an FPGA manager using standard
arguments
* __devm_fpga_mgr_register_full() - Resource managed version of
__fpga_mgr_register_full()
* __devm_fpga_mgr_register() - Resource managed version of __fpga_mgr_register()
* fpga_mgr_unregister() - Unregister an FPGA manager
Helper macros ``fpga_mgr_register_full()``, ``fpga_mgr_register()``,
``devm_fpga_mgr_register_full()``, and ``devm_fpga_mgr_register()`` are available
to ease the registration.
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
:functions: fpga_mgr_states
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
:functions: fpga_manager
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
:functions: fpga_manager_ops
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
:functions: fpga_manager_info
.. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: __fpga_mgr_register_full
.. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: __fpga_mgr_register
.. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: __devm_fpga_mgr_register_full
.. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: __devm_fpga_mgr_register
.. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: fpga_mgr_unregister
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
FPGA manager 개요
1-22문서 제목은 `FPGA Manager`입니다.
FPGA manager core는 image로 FPGA를 programming하는 function 집합을 export합니다. API는 manufacturer-agnostic이며, manufacturer별 세부 사항은 core에 operation 집합을 등록하는 low-level driver 안에 숨깁니다.
FPGA image data 자체는 manufacturer별로 매우 다르지만 manager core 관점에서는 binary data일 뿐이며 core가 이를 parse하지 않습니다.
Programming할 FPGA image는 scatter-gather list, 하나의 contiguous buffer 또는 firmware file에 있을 수 있습니다. Contiguous kernel memory allocation은 피해야 하므로 가능하면 scatter-gather list 사용을 권장합니다.
Programming 세부 사항은 `struct fpga_image_info`에 전달합니다. 이 structure에는 FPGA image pointer와 image가 full reconfiguration용인지 partial reconfiguration용인지 같은 image별 parameter가 들어 있습니다.
Manager core가 받을 수 있는 image storage와 사용상 권장 사항입니다.
새 FPGA manager driver 지원
23-78새 FPGA manager를 추가하려면 operation 집합을 구현하는 driver를 작성합니다. Probe function은 `fpga_mgr_register()` 또는 `fpga_mgr_register_full()`을 호출합니다.
예제는 `write_init`, `write`, `write_complete`, `state` callback을 `socfpga_fpga_ops`에 연결하고, probe에서 private data를 준비해 manager를 등록한 뒤 remove에서 `fpga_mgr_unregister()`를 호출합니다.
static const struct fpga_manager_ops socfpga_fpga_ops = {
.write_init = socfpga_fpga_ops_configure_init,
.write = socfpga_fpga_ops_configure_write,
.write_complete = socfpga_fpga_ops_configure_complete,
.state = socfpga_fpga_ops_state,
};
static int socfpga_fpga_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct socfpga_fpga_priv *priv;
struct fpga_manager *mgr;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/*
* do ioremaps, get interrupts, etc. and save
* them in priv
*/
mgr = fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager",
&socfpga_fpga_ops, priv);
if (IS_ERR(mgr))
return PTR_ERR(mgr);
platform_set_drvdata(pdev, mgr);
return 0;
}
static int socfpga_fpga_remove(struct platform_device *pdev)
{
struct fpga_manager *mgr = platform_get_drvdata(pdev);
fpga_mgr_unregister(mgr);
return 0;
}
대신 resource-managed function인 `devm_fpga_mgr_register()` 또는 `devm_fpga_mgr_register_full()`을 호출할 수 있습니다. Parameter syntax는 같지만 이 경우 `fpga_mgr_unregister()` 호출을 제거해야 하며 위 예제의 `socfpga_fpga_remove()`도 필요하지 않습니다.
일반 등록과 devm 등록의 resource 해제 차이를 보여줍니다.
Programming sequence와 parse_header
79-102Operation은 해당 FPGA의 programming sequence에 필요한 device-specific register write를 구현합니다. 성공하면 0, 실패하면 negative error code를 반환합니다.
Programming 순서는 optional `.parse_header`, `.write_init`, 한 번 이상 호출될 수 있는 `.write` 또는 `.write_sg`, 마지막 `.write_complete`입니다.
`.parse_header`는 `struct fpga_image_info`의 `header_size`와 `data_size`를 설정합니다. 호출 전 `header_size`는 `initial_header_size`로 초기화됩니다.
`fpga_manager_ops.skip_header`가 true이면 `.write`에는 image 시작에서 `header_size`만큼 지난 buffer가 전달됩니다. `data_size`가 설정되면 그 byte 수만 전달하고, 설정하지 않으면 image 끝까지 전달합니다. 이 규칙은 `.write_sg`에는 영향을 주지 않아 `.write_sg`는 전체 image를 `sg_table` 형식으로 받습니다.
Image가 contiguous buffer이면 전체 buffer를 `.parse_header`에 전달합니다. Scatter-gather 형식이면 core가 첫 호출 전에 최소 `.initial_header_size`만큼 buffer를 모읍니다. 부족하면 `.parse_header`가 원하는 크기를 `info->header_size`에 설정하고 `-EAGAIN`을 반환하며, 더 큰 image 부분으로 다시 호출됩니다.
Header parsing에서 image write와 operating mode 전환까지의 callback 흐름입니다.
Write operation과 state
103-122`.write_init`은 FPGA가 image data를 받을 준비를 하게 합니다. 전달되는 buffer는 최소 `info->header_size` byte이며 전체 bitstream이 바로 준비되지 않으면 core가 시작 전에 이 크기 이상을 모읍니다.
`.write`는 buffer를 FPGA에 기록합니다. Buffer는 전체 image 또는 더 작은 chunk일 수 있으며, chunk이면 연속 부분마다 여러 번 호출됩니다. 이 interface는 PIO를 사용하는 driver에 적합합니다.
`.write_sg`는 input이 `sg_table` scatter list라는 점을 제외하면 `.write`와 같으며 DMA를 사용하는 driver에 적합합니다.
`.write_complete`는 모든 image 기록이 끝난 뒤 FPGA를 operating mode로 전환하도록 호출됩니다.
`.state`는 FPGA의 현재 state를 판별해 `enum fpga_mgr_states` code를 반환하며 state 자체를 변경하지 않습니다.
각 callback의 input 형식과 책임입니다.
새 manager driver 구현 API
123-142새 FPGA manager driver 구현에 사용하는 API는 state enum, manager·operation·registration info structure, 일반·full·devm registration function과 unregister function으로 구성됩니다.
- `fpga_mgr_states`: `fpga_manager->state` 값
- `struct fpga_manager`: manager structure
- `struct fpga_manager_ops`: low-level driver operation
- `struct fpga_manager_info`: `fpga_mgr_register_full()` parameter structure
- `__fpga_mgr_register_full()`과 `__fpga_mgr_register()`: manager 생성·등록
- `__devm_fpga_mgr_register_full()`과 `__devm_fpga_mgr_register()`: resource-managed 등록
- `fpga_mgr_unregister()`: manager 등록 해제
Registration을 쉽게 하도록 `fpga_mgr_register_full()`, `fpga_mgr_register()`, `devm_fpga_mgr_register_full()`, `devm_fpga_mgr_register()` helper macro를 제공합니다.
Parameter 유연성과 resource 관리 여부에 따른 helper입니다.
FPGA manager kernel-doc
143-168State, manager, operation과 registration info 문서는 `include/linux/fpga/fpga-mgr.h`에서 가져옵니다.
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
:functions: fpga_mgr_states
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
:functions: fpga_manager
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
:functions: fpga_manager_ops
.. kernel-doc:: include/linux/fpga/fpga-mgr.h
:functions: fpga_manager_info
Registration과 unregister function 문서는 `drivers/fpga/fpga-mgr.c`에서 가져옵니다.
.. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: __fpga_mgr_register_full
.. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: __fpga_mgr_register
.. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: __devm_fpga_mgr_register_full
.. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: __devm_fpga_mgr_register
.. kernel-doc:: drivers/fpga/fpga-mgr.c
:functions: fpga_mgr_unregister
요약과 해설
fpga-mgr.rst:1-168FPGA manager core는 image 형식을 해석하지 않는 manufacturer-neutral programming framework입니다. Low-level driver가 parse·init·write·complete·state operation을 구현하며, 큰 contiguous allocation 대신 scatter-gather image가 권장됩니다.
Driver는 일반 또는 devm registration을 선택할 수 있습니다. `.parse_header`는 더 많은 header가 필요하면 `-EAGAIN`으로 재호출을 요청하고, PIO driver는 `.write`, DMA driver는 `.write_sg`를 사용합니다.