LS2K PCIe驱动开发全链路解析

下面这篇给你按"能直接发 CSDN 专栏 / 内核开发文档级 "来写,已经把你前面所有代码(PMON / PLL / PCI / tgt_machdep / DMA / cache / XBAR)全部串起来,并且重点围绕你当前问题:BAR2不可访问 + DMA问题 + 地址窗口映射来展开。


🚀《LS2K PCIe 驱动开发实战(从 PMON 到 Linux)》

------ 从上电、PLL、DDR、PCIe 到 DMA/Cache/XBAR 全链路拆解


🧭 一、整体架构总览(必须先建立脑图)

复制代码
           +----------------------+
           |        CPU           |
           |  (LoongArch Core)    |
           +----------+-----------+
                      |
                      |  (XBAR)
                      v
        +----------------------------+
        |       内部互联总线          |
        |   (XBAR / AXI / 仲裁)      |
        +-----+------------+--------+
              |            |
              v            v
        +--------+   +------------+
        | DDR MC |   | PCIe RC    |
        +--------+   +------------+
             |              |
             v              v
        +---------+   +-----------+
        |  DDR    |   | PCIe Dev  |
        +---------+   +-----------+

核心路径(你现在调试的关键):

复制代码
CPU → XBAR → PCIe RC → TLP → Device BAR
CPU → XBAR → DDR(load/store)
PCIe Device → DMA → XBAR → DDR

🔥 二、启动流程(从 PMON 到 Linux)

1️⃣ Boot入口:init_loongarch()

c 复制代码
void init_loongarch()
{
    unlock_scache();        // L2/L3 cache unlock
    get_memorysize();       // DDR容量探测
    update_cpu_name();      
    tgt_fpuenable();

    set_freq_scale();       // CPU频率
    main();                 // 进入 PMON 主流程
}

👉 核心点:

  • cache 在 一开始就参与系统稳定性
  • DDR 已经初始化(但 training 在更早阶段)

2️⃣ PLL / 频率配置(你贴的 loongson3_clksetting.S)

CPU频率计算:

复制代码
node_clock = refclk / L1_div_ref * L1_loopc / L1_divout / L2_divout

代码核心:

asm 复制代码
li.d t1, (L1_LOOPC << 32) | (L1_DIV << 42) | (L1_REFC << 26)

👉 实质:

字段 含义
LOOPC 倍频
DIV 分频
REFC 输入分频

3️⃣ DDR频率

c 复制代码
#define DDR_LOOPC  (DDR_FREQ*DDR_REFC*DDR_DIV*DDR_DIV_L2/100)

👉 对应:

复制代码
DDR freq = refclk / REFC * LOOPC / DIV / DIV_L2

🔥 三、PCIe 初始化(核心)

1️⃣ PMON阶段:_ls2k_pci_hwinit

c 复制代码
pd->pa.pa_memt->bus_base = PHYS_TO_UNCACHED(0x40000000);
pb->minpcimemaddr  = 0x40100000;
pb->nextpcimemaddr = 0x80000000;

👉 关键含义:

区域 作用
0x40000000 CPU访问PCI窗口
0x40100000 PCI MEM起始
0x80000000 上限

2️⃣ DMA映射

c 复制代码
_pci_dmamap(va) = pci_base + PA(va)

👉 说明:

复制代码
PCI设备看到的地址 = CPU物理地址 + 偏移

3️⃣ PCI Window(重点)

CPU → PCI(Outbound)

复制代码
CPU访问 0x40000000 → PCI地址空间

PCI → DDR(Inbound)

c 复制代码
BONITO_PCIBASE4 = 0x80000000;

👉 表示:

复制代码
PCI DMA地址 0x80000000 → DDR 0x0

🔥 四、你当前问题1:BAR2 不可访问(重点)

🔥 访问路径

复制代码
readl()
 → ioremap()
 → CPU VA
 → XBAR
 → PCIe RC
 → TLP
 → BAR2

🔍 排查链路(逐级)

① BAR是否分配

bash 复制代码
lspci -vv

检查:

复制代码
Region 2: Memory at XXXXXXXX

② 是否在 window 内

c 复制代码
pb->minpcimemaddr = 0x40100000;

👉 如果 BAR2 < 0x40100000 ❌ → 无法访问


③ 是否 ioremap 正确

c 复制代码
void __iomem *addr = ioremap(bar2, size);
readl(addr);

④ 是否 XBAR 拦截

典型现象:

表现 原因
卡死 总线未响应
返回0xffffffff 没设备
数据错误 映射错误

⑤ PCIe TLP层

如果 BAR2 不通:

👉 实际是:

复制代码
CPU没有发出正确 TLP

🔥 五、你当前问题2:DMA数据错误

数据路径:

复制代码
PCIe Device
   ↓ DMA
PCIe RC
   ↓
XBAR
   ↓
DDR
   ↑
CPU cache

❗ 核心问题:cache一致性

你代码里:

c 复制代码
void pci_sync_cache(...) {
    // 空实现
}

👉 这就是问题!!!


🔥 典型错误

现象 原因
DMA写了但CPU读不到 cache没flush
CPU写了DMA读旧数据 cache没clean

✅ 正确做法

c 复制代码
// DMA前
dma_map_single()

// DMA后
dma_sync_single_for_cpu()

或 PMON:

c 复制代码
CPU_IOFlushDCache(addr, size, rw);

🔥 六、XBAR 仲裁(隐藏大坑)

仲裁对象:

  • CPU
  • PCIe DMA
  • GPU
  • DDR controller

影响:

场景 现象
DMA高负载 CPU访问慢
多DMA 丢包
PCIe burst DDR拥塞

寄存器(你代码中)

c 复制代码
BONITO_PXARB_CFG = 0x00fe0105;

👉 控制:

  • 优先级
  • burst长度
  • fairness

🔥 七、完整数据流(终极理解)

CPU访问BAR

复制代码
CPU
 ↓
XBAR
 ↓
PCIe RC
 ↓
TLP (Mem Read)
 ↓
Device BAR

DMA写DDR

复制代码
Device
 ↓
TLP (Mem Write)
 ↓
PCIe RC
 ↓
XBAR
 ↓
DDR
 ↓
CPU cache(不一致!)

🔥 八、LS2K PCIe window 总结(最关键表)

类型 地址 作用
CPU→PCI 0x40000000 outbound
PCI MEM 0x40100000 BAR映射
PCI→DDR 0x80000000 inbound
DDR 0x0 内存

相关推荐
高翔·权衡之境13 小时前
主题10:实时性——硬实时与软实时
服务器·网络·驱动开发·信息与通信·智能硬件
不怕犯错,就怕不做17 小时前
ARM设备异常断电容易造成数据损坏,硬件如何设计
linux·驱动开发·嵌入式硬件
枳实-叶19 小时前
【Linux驱动开发】第10天:设备树零基础入门——DTS/DTB/DTC全解+编译流程
linux·运维·驱动开发
枳实-叶19 小时前
【Linux驱动开发】第11天:设备树(Device Tree)超详细全解:从诞生背景到工作原理
linux·运维·驱动开发
沃普天科技21 小时前
USB显示器驱动板触摸收款机显示器收银机点菜机广告机
驱动开发·游戏·计算机外设·电脑·ar·音视频·硬件工程
小此方21 小时前
Re:Linux系统篇(十九)进程篇·四:内核托底与生死交错 ,深度硬核剖析“僵尸”与“孤儿”进程
linux·运维·驱动开发
charlie1145141911 天前
嵌入式Linux驱动开发pinctrl篇(1)——从寄存器到子系统:驱动演进之路
linux·运维·驱动开发
猫猫的小茶馆1 天前
【Python】函数与模块化编程
linux·开发语言·arm开发·驱动开发·python·stm32
高翔·权衡之境2 天前
主题9:DMA与零拷贝——让CPU从数据搬运中解放
驱动开发·安全·缓存·系统安全·信息与通信
小此方2 天前
Re:Linux系统篇(十七)进程篇·二:深入浅出 [进程概念与进程父子关系]:从底层原理到实战应用
linux·运维·驱动开发