Comcerto 2000のEthernetは1000とはまったく違っていてPacket Fowording Engine(PFE)という仕組みになります。
この仕組みのコードは
barebox
uboot
kernel
に入っていて、
mindspeed
freescale (kernel:fsl_ppfe)
NXP
がオープンソースにしたものがあります。mindspeedのコードは買収間直で社内が混乱していたのか、結構汚いコードです。freescaleになってずいぶん整理したみたいです。
NXPのS32G2という車載向けのSOCでもPFEが採用されているようです。
mindspeedの頃にgoogle fiberで採用されていたので、googleのアーカイブにソースが残っています。
このアーカイブのdriversに含まれるコード(pfe)は他のコードとかなり違う作り込みになっていて、ファーム(pfe_firmware)が特殊なようです。
c1kもfreescaleでも生産されたようですが、それほど多くは生産されなくてディスコンになった模様です。
ターゲットにはQCA8337が使われています。
c1kのモジュールにはAR8316が使われていたが、Atherosとしてはこの後、AR8327,AR8328という製品を作って、買収後の最初のチップがQCA8337となったようだ。
最初はGPLでしたがNXPになってからDPDKにコードを提供した時にBSD 3か条にしたようです。
PFEはOpen Packet Acceleration Logic(OPAL)と呼ばれた機能の一部かもしれません。情報もかなり混乱しています。
Gigabit Ethernet Controllerはc1kと同じでCadence Design Systems, Inc.のIPのようです。
ターゲットのGMAC0はQCA8337のport6側のRGMIIに接続されていて、GMAC1はPort0側のRGMIIに接続されているようです。
Comcerto 2000はfreescaleに買収されてからもしばらくM862xxとしていたようなのですが、途中からLS1024Aという型番に変わって、そのPFEのドキュメントはありました。freescaleになってからはProgramaerble PFE(PPFE)とも呼ばれていたようです。
Bareboxの初期化は以下のように行われています。
init eth0, eth1
cbus_baseaddr: 9c000000, ddr_baseaddr: 03800000, ddr_phys_baseaddr: 03800000
class init complete
tmu init complete
bmu1 init: done
bmu2 init: done
util init complete
GPI1 init complete
GPI2 init complete
HGPI init complete
HIF rx desc: base_va: 03e80000, base_pa: 03e80000
HIF tx desc: base_va: 03e80400, base_pa: 03e80400
HIF init complete
bmu1 enabled
bmu2 enabled
pfe_hw_init: done
pfe_firmware_init
pfe_load_elf
pfe_load_elf no of sections: 10
pfe_firmware_init: class firmware loaded
pfe_load_elf
pfe_load_elf no of sections: 10
pfe_firmware_init: tmu firmware loaded
pfe_load_elf
pfe_load_elf no of sections: 14
pfe_firmware_init: util firmware loaded
Switch Reset Delay 1 sec here
PCE0 Reset Delay 100ms here
PCE1 Reset Delay 100ms here
athrs17_init:done
athrs17_phy_init 4
Port 4, Neg Success
phy4 link down
miidev_restart_aneg for PHY4
athrs17_phy_init 0
Port 0, Neg Success
phy0 link down
athrs17_phy_init 1
Port 1, Neg Success
phy1 link down
athrs17_phy_init 2
Port 2, Neg Success
phy2 link down
athrs17_phy_init 3
Port 3, Neg Success
phy3 link down
Linuxはこうです。
[ 9.412740] pfe_probe
[ 9.415024] PFE Driver version:
[ 9.415028] pfe_ctrl_10_00_6
[ 9.415032] built with pfe sources version: pfe_10_00_5_00_3
[ 9.426748] cbus_baseaddr: d8000000, ddr_baseaddr: d7000000, ddr_phys_baseaddr: 3400000, ddr_size: c00000
[ 9.436355] pfe_hw_init
[ 9.438821] CLASS version: 20
[ 9.441799] TMU version: 1011231
[ 9.445038] BMU1 version: 21
[ 9.447927] BMU2 version: 21
[ 9.450832] EMAC1 network cfg: 80000
[ 9.454421] EMAC2 network cfg: 80000
[ 9.458017] EMAC3 network cfg: 80000
[ 9.461612] EGPI1 version: 50
[ 9.464595] EGPI2 version: 50
[ 9.467576] EGPI3 version: 50
[ 9.470570] HGPI version: 50
[ 9.473463] GPT version: 0
[ 9.476185] HIF version: 10
[ 9.479007] HIF NOPCY version: 10
[ 9.482336] UTIL version: 20
[ 9.485231] bmu_init(1) done
[ 9.488139] bmu_init(2) done
[ 9.498964] class_init() done
[ 9.501960] tmu_init: mem init
[ 9.505032] tmu_init: lmem init
[ 9.508317] tmu_init() done
[ 9.511126] util_init() done
[ 9.514027] gpi_init(1) done
[ 9.516927] gpi_init(2) done
[ 9.519855] gpi_init(3) done
[ 9.522755] gpi_init(hif) done
[ 9.525824] bmu_enable(1) done
[ 9.528908] bmu_enable(2) done
[ 9.531978] pfe_hif_lib_init
[ 9.535213] pfe_hif_init
[ 9.537763] pfe_hif_alloc_descr
[ 9.541251] pfe_hif_init_buffers
[ 9.544684] pfe_firmware_init
[ 9.897125] pfe_load_elf
[ 9.899704] pe_load_ddr_section: load address(3fb0000) and elf file address(d083b000) rcvd
[ 9.935893] PFE binary version: pfe_10_00_5_00_6
[ 9.940543] pfe_firmware_init: class firmware loaded 0xb40 0xc3010000
[ 9.947005] pfe_load_elf
[ 9.951241] pfe_firmware_init: tmu firmware loaded 0x220
[ 9.956569] pfe_load_elf
[ 9.961430] pfe_firmware_init: util firmware loaded 0x16e0
[ 9.966980] pfe_ctrl_init
[ 9.996076] pfe_ctrl_init finished
[ 9.998787] pfe_ctrl_timer
[ 10.002221] pfe_eth_init
[ 10.006143] Comcerto MDIO Bus: probed
[ 10.016288] eth0: pfe_eth_init_one: created interface, baseaddr: d8200000
[ 10.023138] pfe_eth_init_one: eth0 g_EMAC_BaseAddr = d8200000
[ 10.036501] eth2: pfe_eth_init_one: created interface, baseaddr: d8220000
[ 10.051081] eth3: pfe_eth_init_one: created interface, baseaddr: d8330000
[ 10.057895] INIT MulticastSnooping!!
[ 10.061719] pfe_vwd_init
[ 10.064426] pfe_vwd_init: created vwd device(252, 0)
[ 10.069430] pfe_vwd_driver_init: start
[ 10.073193] pfe_vwd_up: start
[ 10.076213] comcerto_wifi_rx_fastpath_register:33 VWD Tx function registered
[ 10.083332] pfe_vwd_driver_init: end
[ 10.086930] pfe_pcap_init
オープンソースなどから解析した人もいます。
いろいろ略されています。
略 | 機能 |
---|---|
BMU | Buffer Management Unit |
GPI | Generic Packet Interface |
TMU | Traffic/Time Management/Multiplexing Unit |
CSR | control and status registers |
Class,TMU,Utilにはfirmwareが必要です。
firmwareを実行するcpuにはプログラムとデータの内部メモリがあり、そこにELFをロードして実行するようです。またホストCPUのメモリにもアクセスできるようです。内部メモリは小さいので大きなプログラムはホスト側のメモリに置いて実行しているような気がします。
HIF,GPI,BMUは上のfirmwareで実装されているのかもしれません。
データ送受信のCPUとのインターフェースはHost Interface(HIF)と呼ばれていて、データをコピーする方法とコピーしない方法がサポートされているようです。
32Bitのレジスタで数ビットしか使っていないものが結構あり、大雑把な感じがします。
GEMACは三つあり1始まりで1,2,3です。freescaleになってからは0始まりになっています。
このGEMACにはmibがあり、デバッグで重宝しました。
HIFは一本でGEMACのデーターをヘッダーをつけて区別して、まとめて送受信します。
アドレス | サイズ | 用途 |
---|---|---|
0x9c000000-0x9cffffff | 16M | PFE 各機能レジスタ |
0xc0000000-0xc0ffffff | 16M | CBUS? |
PFEは最初はHFEと呼ばれていたよう。
linuxのカーネルコードのmach-comcerto/mspというディレクトリのソースもpfeと関係あるようなのですが、なにしてるか分かりません。
このほかにディスクリプタやバッファのメモリが必要です。またPFEの各機能の作業領域やファームウエアのメモリも必要なようです。
PFEにはなんらかのCPUが入っていて、その処理をファームウエアで変更することが出来るようです。メインメモリとは別にファームウエア用のメモリがあり、そこにファームウエアをロードして実行しているようです。
ELF Header:
Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, big endian
Version: 1 (current)
OS/ABI: NONE
ABI Version: 0
Type: EXEC (Executable file)
Machine: <unknown: 0x6f>
Version: 0x1
Entry point address: 0x3fb01c0
Start of program headers: 52 (bytes into file)
Start of section headers: 51876 (bytes into file)
Flags: 0x40005
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 6
Size of section headers: 40 (bytes)
Number of section headers: 18
Section header string table index: 17
0x6f(111)はeXcess: 16/32/64-bit configurable embedded CPUとなっています。
当初はファームウエアも開発できるようなプラットフォームを考えていたのかもしれませんが、買収されて吹っ飛んだような気がします。
ほとんどのリポジトリにはファームウエアのバイナリが含まれていませんが、google fiberのubootのアーカイブに入っていました。
c1kもfastpathで使えるような仕様でしたが、c2kでまったく作り込みを変えています。 と思ったのですが、c1kでもSCH,ADMという仕組みがあって、それを拡張したのかもしれません。 いろいろ見てみるとやっぱ別物です。チップ屋さんがいろいろ考えたのがドライバー屋さんに伝わっていない気がします。
c2kのディスクリプタのフラグ
/*Buffer descriptor control bits */
#define BD_CTRL_BUFLEN_MASK (0xffff)
#define BD_BUF_LEN(x) (x & BD_CTRL_BUFLEN_MASK)
#define BD_CTRL_CBD_INT_EN (1 << 16)
#define BD_CTRL_PKT_INT_EN (1 << 17)
#define BD_CTRL_LIFM (1 << 18)
#define BD_CTRL_LAST_BD (1 << 19)
#define BD_CTRL_DIR (1 << 20)
#define BD_CTRL_PKT_XFER (1 << 24)
#define BD_CTRL_DESC_EN (1 << 31)
#define BD_CTRL_PARSE_DISABLE (1 << 25)
#define BD_CTRL_BRFETCH_DISABLE (1 << 26)
#define BD_CTRL_RTFETCH_DISABLE (1 << 27)
c1kのTXのディスクリプタのフラグ
#define GEMTX_USED_MASK (1UL<<31)
#define GEMTX_WRAP (1UL<<30)
#define GEMTX_IE (1UL<<29)
#define GEMTX_L4_CSUM (1UL<<26)
#define GEMTX_L3_CSUM (1UL<<25)
#define GEMTX_FCS (1UL<<24)
#define GEMTX_OFFSET_MASK 0xff
#define GEMTX_OFFSET_SHIFT 16
#define GEMTX_LAST (1UL<<15)
#define GEMTX_POOLB (1UL<<14)
#define GEMTX_BUFRET (1UL<<13)
#define GEMTX_LENGTH_MASK 0x1fff
#define GEMTX_LENGTH_SHIFT 0
#define GEMTX_LENGTH_MAX 0x1fff
ぜんぜん違いますね。c2kは全般的に大作りでc1kの作りをベースにしたほうが良かったのではないかと思います。
c2kのチップが破綻していると思うのはPFEのリセットビットが二箇所にあることがあります。一つはAXI_RESET_1にあり、もう一つはPFE_RESETというレジスタにあります。PFE_RESETは1ビットだけのレジスタで、他にも1ビットしか使っていないRESETレジスタがあります。なんらか設計に破綻して、二箇所に分かれてしまったのではないでしょうか?
githubの検索が以前よりよくなっていろいろコードが出てきました。
ターゲットのモジュールのBareboxはネットワークのディスクリプタが生きた状態でOSを起動しています。まじやばいです。
ターゲットはfreescaleの頃のSOCなんですが、おそらくSDKも怪しく開発期間も限られていたので、ともかく動くようにしたのではないかと思われます。
ディスクリプタの送信受信処理は動くようになったのですが、TXがCRS Errorで送信されないのと、MDIOが見えない問題がなかなか解決しません。(2023/07/23)
いろいろ試行錯誤して使えるようになりました。設定に順序があったりかなりやばいです。(2023/07/25)
ifstartで頻繁にDMAをSTARTさせるとTXが暴走して使えなくなります。(2023/08/02) 設定に誤りがありました
MACとスイッチの接続はRGMIIですがWAN用にスイッチのPHYを切り出して100Mでつないだ場合、MACとスイッチの接続も100Mにする必要があります。
落ちなくはなりましたが、異常に遅いです。
オリジナルソースの狂ってるところ。
pe[CLASS0_ID].pmem_base_addr = CLASS_IMEM_BASE_ADDR(0);
pmemといったりIMEMといったり一貫性がありません。
.route_table_baseaddr = pfe->ddr_phys_baseaddr + ROUTE_TABLE_BASEADDR,
...
.llm_base_addr = pfe->ddr_phys_baseaddr + TMU_LLM_BASEADDR,
...
.baseaddr = pfe->ddr_phys_baseaddr + BMU2_DDR_BASEADDR,
Class,TMU,BMUでホストの物理アドレスを指定しているのですが、メンバーにもマクロのオフセットにもまったく一貫性がありません。
CBUS_BASE_ADDRというマクロがいろいろなファイルで定義されていて、0x9c000000だったり0xc0000000だったりします。
0x9c000000と0xc0000000の変換のCBUS_VIRT_TO_PFEというマクロがあるのですが、両方とも物理アドレスで、仮想アドレスではありません。
c1kとmiiは同じなのですが、c1kは
write_data = 0x50020000;
write_data |= ((mii_id << 23) | (regnum << 18) | value);
なのですが、c2kは
write_data = 0x50020000 | ( (phy_addr & (u32) 0x1f) << 23) | ( (phy_reg & (u32) 0x1f) << 18) | (val & (u32) 0xffff); // write_op
長々と書いているのもあれですが、引数はプログラム内の処理なのでマスクで正規化する必要はありません。
val = readl(EXTPHY0_CLK_CNTRL);
val &=~(CLK_PLL_SRC_MASK << CLK_PLL_SRC_SHIFT);
val |= (cfg_clk->extphy0_clk_src << 1);
writel(val, EXTPHY0_CLK_CNTRL);
マスクはマクロを使っているのですが、値のセットに直値を使っています。
val = readl(AXI_RESET_1);
val &= PFE_SYS_AXI_RESET_BIT; //skip HFE
writel(0, AXI_RESET_0);
writel(val, AXI_RESET_1);
writel(0, AXI_RESET_2);
~を忘れてるような気がするし、結果としてvalは0になって0を書いてるように思われます。
#define IRQ_G0 SPI_IRQ(14)
GPIOをGと省略してます。省略する必要ある?
HAL_set_clock_divider(cfg_clk->csys_clk, cfg_clk->csys_clk_src, CSYS_CLK_DIV_CNTRL);
}
static inline void HAL_set_clock_divider(int clk_freq, int pll_src, u32 reg)
{
u32 pll_freq;
int pll_freq_idx;
int divider;
u32 val;
if (pll_src < PLL3)
{
switch(pll_src)
{
case PLL0:
pll_freq_idx = pll_freq_table[cfg_clk->pll_cfg_idx].pll0_freq_idx;
break;
グローバル変数を関数に渡しているのですが、呼ばれた関数でもグローバル変数を参照しています。見通しがよくありません。
static inline void HAL_set_clock(void)
{
HAL_set_clock_divider(cfg_clk->axi_clk, cfg_clk->axi_clk_src, AXI_CLK_DIV_CNTRL);
HAL_set_clockの実体がなぜHAL_set_clock_dividerなのでしょうか?
/*Double reset HFE helps some times */
val = readl(AXI_RESET_1);
writel((val | HFE_AXI_RESET), AXI_RESET_1);
writel((val & ~(HFE_AXI_RESET)), AXI_RESET_1);
ときどき役に立つコードって、いかがなもんですかね。
include/mach/clkcore.h:#define HFE_AXI_RESET (1 << 3)
clkcore.c:#define PFE_SYS_AXI_RESET_BIT (1<<3)
なぜ再定義する?
gemac_enable_mdio(EMAC1_BASE_ADDR);
gemac_enable_mdio(EMAC2_BASE_ADDR);
MDIOはMAC1でしかサポートされてません。
やっぱ会社が傾いて、まともなエンジニアはみんな逃げてしまっていたのかも知れませんね。
エンジニアの問題のように見えますが、本質的にはマネージメントの問題だと思います。