LoginSignup
3
4

More than 3 years have passed since last update.

Linux Kernel FPGAのドキュメントを読んでみる

Posted at

Introduction

FPGAサブシステムは、linux上でFPGAの動的な再プログラミングをサポートします。FPGAサブシステムの中心的な考えは以下です。

  • FPGAサブシステムは、ベンダー依存しない。

  • FPGAサブシステムは、上位レイヤー(ユーザースペースでのインタフェイスや列挙)と、FPGA特有のプログラミングをするための下位レイヤーに分かれる。

  • コードは、上位レイヤーと下位レイヤーの間で共有してはならない。このことは、言うまでもない。もしそれが必要な場合、frameworkの機能はおそらくほかのユーザーにとって利益ある追加がなされるべきです。linux^fpgaメーリングリストに書き、幅広い再利用のために、フレームワークを拡張する解決策を模索してください。

  • 一般的に、コードを追加するときには、将来のことも考えてください。再利用を検討してください。

カーネルのフレームワークは次のように分割されます。

FPGA Manager

新しいFPGAや、新しいFPGAのプログラミング手法を追加するときに、このサブシステムを使ってください。Low level FPGA manager driverには、既存ドライバでプログラムする方法の知識が含まれています。このサブシステムは、fpga-mgr.cに含まれており、登録されているlow level driverが含まれます。

FPGA Bridge

FPGA Bridge は、FPGAやプログラミング中のFPGAのregionからの疑似的なシグナルを止めるためのものである。プログラミングを開始する前や、最有効した後に無効化する。FPGA bridgeは実際のハードウェアかもしれない、つまり、FPGAの再設定可能なそれぞれのリージョン周辺に位置する、FPGA実装に含まれる、CPUやSoft("freeze") Bridgeのバスのゲートかもしれない。このサブシステムは、fpga-bridge.cに含まれ、登録されているlow level driverが含まれます。

FPGA Region

FPGA frameworkに新しいインタフェイスを追加したい場合、FPGA regionの先頭に追加するべきである。

FPGA region framework(fpga-region.c)は、managerとbridgeを再設定可能なregionとして関連付ける。regionは完全に再設定するためにFPGA全体を参照するかもしれないし、部分的に山椒するかもしれない。

Device Tree FPGA Region サポート(fpga-region.c) device tree overlaysが適用されたときに、FPGAの再プログラミングをハンドリングする。

FPGA Manager

Overview

FPGA manager coreは、imageに対するFPGAのプログラミングするための関数の集合をexportする。このAPIはmanufacturer非依存である。すべてのmanufacturorerの仕様は、coreに含まれる処理の集合が登録されているlow level driverの中に秘匿されている。

FPGA image data自身は、非常にmanufacturer 特有である、しかし、我々の目的からすると単なるバイナリデータでしかない。FPGA manager はそれを解釈しない。

プログラムされたFPGA imageは、単純な線形バッファであるscatter gater list、もしくはファームウェアファイルに保持される。バッファに対するカーネルのメモリが連続的に確保されることが保証できないため、可能な限りその代わりにユーザーはscatter fater listを大体として使おうとする。

Imageにプログラムされた詳細は構造体に記憶される(fpga_image_info)。この構造体には、FPGA imageのポインターや完全にあるいは部分的に再設計するためのImage固有の情報などが含まれます。、

How to support FPGA device

異なるFPGA managerを追加する場合、opsの集合をドライバに実装します。probe function は、fpga_mgr_register()を呼び出します。

    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 = devm_fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager",
                       &socfpga_fpga_ops, priv);
        if (!mgr)
            return -ENOMEM;

        platform_set_drvdata(pdev, mgr);

        return fpga_mgr_register(mgr);
    }

    static int socfpga_fpga_remove(struct platform_device *pdev)
    {
        struct fpga_manager *mgr = platform_get_drvdata(pdev);

        fpga_mgr_unregister(mgr);

        return 0;
    }

このopsには、デバイス固有のそれぞれのFPGAのプログラミングシーケンスが必要としているレジスタ記載が記述されます。opsがreturn 0をした場合には成功であり、負であれば何らかのエラーコードを意味します。

プログラミングシーケンスは以下の通りです。
1. .write_init
2. .write or .write_sg (may be called once or multiple times)
3. .write_complete

.write_init functionは、FPGAがimage dataを受け取る前に行う処理です。.write_initを通過したbufferは、.initial_header_size bytes超以上になるはずです。

もし、全体のbitstreamが即時有効でなければ、その時はcore codeは少なくとも開始する前にbufferがそれを満たすだけ待ちます。

.write functionは、FPGAに対してbufferを書き込む関数です。bufferはFPGA imageの全体もしくはFPGA imageの小さいチャンクが含まれています。後者のケースでは、この関数はチャンクが成功するまで複数回呼ばれることになります。このインタフェイスはPIOを使う場合に適しています。

.write_sg versionは.witerと同じような挙動をするが、入力がsg_table scatter listであることを想定している。このインタフェイスは、DMAを用いた場合に適している。

The .write_complete function is called after all the image has been written to put the FPGA into operating mode.

.write_complete functionは、FPGAが処理するためにすべてのイメージが書き込まれた後に呼び出される。

opsに含まれる.state functionは、FPGAの状態を判断するためのものであり、fpga_mgr_statesのenumで定義されているコードを返す。stateの変化中には処理を返さない。

API for implementing a new FPGA Manager driver

* ``fpga_mgr_states``   Values for :c:member:`fpga_manager->state`.
* struct :c:type:`fpga_manager`   the FPGA manager struct
* struct :c:type:`fpga_manager_ops`   Low level FPGA manager driver ops
* :c:func:`devm_fpga_mgr_create`   Allocate and init a manager struct
* :c:func:`fpga_mgr_register`   Register an FPGA manager
* :c:func:`fpga_mgr_unregister`   Unregister an FPGA manager

.. 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:: drivers/fpga/fpga-mgr.c
   :functions: devm_fpga_mgr_create

.. kernel-doc:: drivers/fpga/fpga-mgr.c
   :functions: fpga_mgr_register

.. kernel-doc:: drivers/fpga/fpga-mgr.c
   :functions: fpga_mgr_unregister

FPGA Bridge

API to implement a new FPGA bridge

(コメント)何も書いてない…

* struct :c:type:`fpga_bridge`  The FPGA Bridge structure
* struct :c:type:`fpga_bridge_ops`  Low level Bridge driver ops
* :c:func:`devm_fpga_bridge_create()`  Allocate and init a bridge struct
* :c:func:`fpga_bridge_register()`  Register a bridge
* :c:func:`fpga_bridge_unregister()`  Unregister a bridge

.. kernel-doc:: include/linux/fpga/fpga-bridge.h
   :functions: fpga_bridge

.. kernel-doc:: include/linux/fpga/fpga-bridge.h
   :functions: fpga_bridge_ops

.. kernel-doc:: drivers/fpga/fpga-bridge.c
   :functions: devm_fpga_bridge_create

.. kernel-doc:: drivers/fpga/fpga-bridge.c
   :functions: fpga_bridge_register

.. kernel-doc:: drivers/fpga/fpga-bridge.c
   :functions: fpga_bridge_unregister

FPGA Region

Overview

このドキュメントでは、FPGA region APIの使い方に関する簡単なoverviewを表すものである。regionに関するもっと概念的な話については、[F1]のDevice tree binding documentを参照する事。

このAPIドキュメントの目的は、FPGA managerとbridgeを関連付けてFPGAのregionやFPGA全体の再プログラミングについて言及する事にある。このAPIは、regionの登録と、regionのプログラミングする手段を提供とする。

[#f1]に書かれている、Kernelに含まれるfpga-region.cのレイヤーは、Device treeサポートする実装である。デバイスツリーは、FPGAをプログラミングそ、列挙をハンドリングするためにregionを使うためのレイヤーをサポートしている。共通region codeは、プログラミングの後、enumerationを成し遂げた他のスキーマによって使われる。

FPGA-regionは、下記手順によって準備される

  • プログラミングされるどのFPGA managerが選択されるか
  • プログラミングする前とEnableした後に、どのbridgeが無効化するか

FPGA imageをプログラムするのに必要となる追加情報は、fpga_image_info構造体に保持される。

  • scatter-gather bufferで提供される連続バッファの、イメージのポインタ、あるいは、firmware fileの名称
  • 特異的な再設定に対するイメージに通知するべき設定を意味するフラグ

How to add a new FPGA region

[#f2] に、probe functionの利用例が記載されている

.. [#f1] ../devicetree/bindings/fpga/fpga-region.txt
.. [#f2] ../../drivers/fpga/of-fpga-region.c

* struct :c:type:`fpga_region`  The FPGA region struct
* :c:func:`devm_fpga_region_create`  Allocate and init a region struct
* :c:func:`fpga_region_register`   Register an FPGA region
* :c:func:`fpga_region_unregister`   Unregister an FPGA region

FPGA regiuonのprobe functionは、プログラミングされるFPGA managerが参照するために必要となる。通常の場合には、region probe functionの間に発生する。

* :c:func:`fpga_mgr_get`  Get a reference to an FPGA manager, raise ref count
* :c:func:`of_fpga_mgr_get`   Get a reference to an FPGA manager, raise ref count,
  given a device node.
* :c:func:`fpga_mgr_put`  Put an FPGA manager

FPGA regionは、FPGAをプログラミングするときに制御しようとするbridgeが必要ととされる。region driverは、probe timeの間にbridgeのリストを生成することができる(:c:member: fpga_region->bridge_list )。あるいは、プログラミングをする直前にプログラミングしようとするbridgeのリストを作る関数を有する(:c:member: fpga_region->get_bridges)。FPGA bridge grameworkは、これらの関数によって提供され、生成時あるいは破壊時に適用する。

* :c:func:`fpga_bridge_get_to_list`  Get a ref of an FPGA bridge, add it to a
  list
* :c:func:`of_fpga_bridge_get_to_list`  Get a ref of an FPGA bridge, add it to a
  list, given a device node
* :c:func:`fpga_bridges_put`  Given a list of bridges, put them

.. kernel-doc:: include/linux/fpga/fpga-region.h
   :functions: fpga_region

.. kernel-doc:: drivers/fpga/fpga-region.c
   :functions: devm_fpga_region_create

.. kernel-doc:: drivers/fpga/fpga-region.c
   :functions: fpga_region_register

.. kernel-doc:: drivers/fpga/fpga-region.c
   :functions: fpga_region_unregister

.. kernel-doc:: drivers/fpga/fpga-mgr.c
   :functions: fpga_mgr_get

.. kernel-doc:: drivers/fpga/fpga-mgr.c
   :functions: of_fpga_mgr_get

.. kernel-doc:: drivers/fpga/fpga-mgr.c
   :functions: fpga_mgr_put

.. kernel-doc:: drivers/fpga/fpga-bridge.c
   :functions: fpga_bridge_get_to_list

.. kernel-doc:: drivers/fpga/fpga-bridge.c
   :functions: of_fpga_bridge_get_to_list

.. kernel-doc:: drivers/fpga/fpga-bridge.c
   :functions: fpga_bridges_put

In-kernel API for FPGA Programming

Overview

FPGA プログラミングをカーネル内APIで行う場合、FPGA manager,bridge,regionのAPIを組み合わせて行う。FPGA プログラミングのトリガーとして用いる実質的な関数は、:c:func:fpga_region_program_fpga() である。

:c:func: fpga_region_program_fpga() は、FPGA managerとbridgeが提供する関数を用いる::

  • lock the region's mutex
  • lock the mutex of the region's FPGA manager
  • build a list of FPGA bridges if a method has been specified to do so
  • disable the bridges
  • program the FPGA using info passed in :c:member:fpga_region->info.
  • re-enable the bridges
  • release the locks

The struct fpga_image_info specifies what FPGA image to program. It is allocated/freed by :c:func:fpga_image_info_alloc() and freed with :c:func:fpga_image_info_free()

fpga_image_info 構造体は、プログラミングするFPGAイメージを記述する。この構造体の確保と解放には、:c:func:fpga_image_info_alloc()と、:c:func:fpga_image_info_free()を用いる。

How to program an FPGA using a region

FPGA region driverがprobeされたとき、Fmanagerが利用しようとするPGA manager driverへのポインタが提供される。regionはまた、プログラミングの間に制御するべきbridgeのリスト、あるいは、そのリストを生成するための関数のポインタを持つ。その結果、以下のようなサンプルコードとなる。

    #include <linux/fpga/fpga-mgr.h>
    #include <linux/fpga/fpga-region.h>

    struct fpga_image_info *info;
    int ret;

    /*
     * First, alloc the struct with information about the FPGA image to
     * program.
     */
    info = fpga_image_info_alloc(dev);
    if (!info)
        return -ENOMEM;

    /* Set flags as needed, such as: */
    info->flags = FPGA_MGR_PARTIAL_RECONFIG;

    /*
     * Indicate where the FPGA image is. This is pseudo-code; you're
     * going to use one of these three.
     */
    if (image is in a scatter gather table) {

        info->sgt = [your scatter gather table]

    } else if (image is in a buffer) {

        info->buf = [your image buffer]
        info->count = [image buffer size]

    } else if (image is in a firmware file) {

        info->firmware_name = devm_kstrdup(dev, firmware_name,
                           GFP_KERNEL);

    }

    /* Add info to region and do the programming */
    region->info = info;
    ret = fpga_region_program_fpga(region);

    /* Deallocate the image info if you're done with it */
    region->info = NULL;
    fpga_image_info_free(info);

    if (ret)
        return ret;

    /* Now enumerate whatever hardware has appeared in the FPGA. */

API for programming an FPGA

* :c:func:`fpga_region_program_fpga`   Program an FPGA
* :c:type:`fpga_image_info`   Specifies what FPGA image to program
* :c:func:`fpga_image_info_alloc()`   Allocate an FPGA image info struct
* :c:func:`fpga_image_info_free()`   Free an FPGA image info struct

.. kernel-doc:: drivers/fpga/fpga-region.c
   :functions: fpga_region_program_fpga

FPGA Manager flags

.. kernel-doc:: include/linux/fpga/fpga-mgr.h
   :doc: FPGA Manager flags

.. kernel-doc:: include/linux/fpga/fpga-mgr.h
   :functions: fpga_image_info

.. kernel-doc:: drivers/fpga/fpga-mgr.c
   :functions: fpga_image_info_alloc

.. kernel-doc:: drivers/fpga/fpga-mgr.c

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4