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 内存

相关推荐
Joseph Cooper2 小时前
Linux Power Management 子系统:从 suspend/resume 到 Runtime PM、PM QoS
linux·驱动开发·linux kernel·嵌入式linux·电源管理
d111111111d9 小时前
移植MQTT到STM32
驱动开发
码踏樱花9 小时前
navicat17安装包和破解
驱动开发
senijusene1 天前
基于 MX6UL 的 DHT11 温湿度传感器 驱动开发
驱动开发
charlie1145141911 天前
嵌入式Linux驱动开发(8)——内存映射 I/O - 别拿物理地址当指针用
linux·开发语言·驱动开发·c·imx6ull
Wallace Zhang1 天前
SimpleFOC源码学习09(v2.3.2) - 磁编码器MagneticSensorSPI.cpp与MagneticSensorSPI.h
驱动开发·stm32·simplefoc·foc电机控制
Freak嵌入式1 天前
亲测可用!可本地部署的 MicroPython 开源仿真器
ide·驱动开发·嵌入式·仿真·micropython·upypi
进击的小头2 天前
20_第20篇:嵌入式外设驱动开发基础:寄存器级开发与库函数开发对比实战
arm开发·驱动开发·单片机
低调小一2 天前
BDD(行为驱动开发)入门:把“测试”写成“行为”,把“需求”写成“场景”
驱动开发·tdd·bdd