【问题标题】:PCI-E Altera transmit-change-receive troublePCI-E Altera 发送-更改-接收故障
【发布时间】:2014-09-17 14:22:51
【问题描述】:

帮助解决问题。 我有一块 Altera db4kgh15 板。它内置支持pci-e接口。我有一个Linux内核模块,由费用控制。使用下面的功能,我扫描基本寄存器狗并尝试写入寄存器数据。 板应采用 32 位字并通过添加 2 将其发回。 但是,我们得到的输出是相同的数字。该项目上的FPGA到主电路模块附ksis自己设计。 截图方案和代码模块如下所示。 我做错了什么?

static int scan_bars(struct pci_dev *dev) {
    int i;
    int end = 0x3f;
    ulong j;
    for (i = 0; i < ALTPCIE_BAR_NUM; i++) {
    unsigned long bar_start = pci_resource_start(dev, i);
    if (bar_start) {
        unsigned long bar_end = pci_resource_end(dev, i);
        unsigned long bar_flags = pci_resource_flags(dev, i);
        printk(KERN_INFO "##pci_m.ko# BAR%d 0x%08lx-0x%08lx flags 0x%08lx\n",
          i, bar_start, bar_end, bar_flags);
        virt_bar0 = (ulong) bus_to_virt(bar_start);
        bar0 = bar_start;
        printk(KERN_INFO "##pci_m.ko# Virt bar0 ADDR = 0x%08lx\n", virt_bar0);

        if(bar0 == virt_bar0) {
        printk(KERN_INFO "##pci_m.ko# bars equals!");
        }

        outl_p(number, bar0);
        printk(KERN_INFO "##pci_m.ko# (bus) outl_p 0x%08lx\n", number);

        /*for(j = bar0; j <= bar0 + end + 5; j++) {
        printk(KERN_INFO "##pci_m.ko# (bus) inb_p[0x%08lx + %d] 0x%08lx\n", bar0, j - bar0, inb_p(j));
        }*/

        for(j = bar0; j <= bar0 + end + 5; j += 4) {
        printk(KERN_INFO "##pci_m.ko# (bus) inl_p[0x%08lx + %d] 0x%08lx\n", bar0, j - bar0, inl_p(j));
        }

        outl_p(number, virt_bar0);
        printk(KERN_INFO "##pci_m.ko# (virtual) outl_p 0x%08lx\n", number);

        /*for(j = virt_bar0; j <= virt_bar0 + end + 5; j++) {
        printk(KERN_INFO "##pci_m.ko# (virtual) inb_p[0x%08lx + %d] 0x%08lx\n", virt_bar0, j - virt_bar0, inb_p(j));
        }*/

        for(j = virt_bar0; j <= virt_bar0 + end + 5; j += 4) {
        printk(KERN_INFO "##pci_m.ko# (virtual) inb_p[0x%08lx + %d] 0x%08lx\n", virt_bar0, j - virt_bar0, inl_p(j));
        }

    } else {
        printk(KERN_INFO "##pci_m.ko# Could not correct read BAR #%d\n", i);
        break;
    }
    }

    return 0;

}

// bvs_pci_server1bar.v

`timescale 1 ps / 1 ps
module bvs_pci_server1bar #(
        parameter AUTO_CLOCK_SINK_CLOCK_RATE = "-1"
    ) (
        input  wire [31:0] serv_bar1_0_addr,          //     avalon_slave.address
        input  wire        serv_bar1_0_read,          //                 .read
        output wire        serv_bar1_0_waitreq,       //                 .waitrequest
        input  wire        serv_bar1_0_write,         //                 .write
        output wire [63:0] serv_bar1_0_readd,         //                 .readdata
        input  wire [63:0] serv_bar1_0_writed,        //                 .writedata
        input  wire [6:0]  serv_bar1_0_burstcnt,      //                 .burstcount
        input  wire [8:0]  serv_bar1_0_byteen,        //                 .byteenable
        output wire        serv_bar1_0_readdatavalid, //                 .readdatavalid
        output wire [19:0] serv_txs_addr,             //    avalon_master.address
        output wire [7:0]  serv_txs_byteen,           //                 .byteenable
        input  wire [63:0] serv_txs_readd,            //                 .readdata
        output wire        serv_txs_read,             //                 .read
        output wire        serv_txs_write,            //                 .write
        input  wire        serv_txs_readdatavalid,    //                 .readdatavalid
        input  wire        serv_txs_waitreq,          //                 .waitrequest
        output wire        serv_txs_chipsel,          //                 .chipselect
        output wire [6:0]  serv_txs_burstcnt,         //                 .burstcount
        output wire [63:0] serv_txs_writed,           //                 .writedata
        input  wire        serv_rst,                  //       reset_sink.reset
        input  wire        serv_clk,                  //       clock_sink.clk
        output wire        serv_irq                   // interrupt_sender.irq
    );

    // TODO: Auto-generated HDL template

    assign serv_bar1_0_waitreq = 1'b0;

    assign serv_bar1_0_readd = 64'b0000000000000000000000000000000000000000000000000000000000000000;

    assign serv_bar1_0_readdatavalid = 1'b0;

    assign serv_txs_burstcnt = 7'b0000000;

    //assign serv_txs_writed = 64'b0000000000000000000000000000000000000000000000000000000000000000;

    assign serv_txs_addr = 20'b00000000000000000000;

    assign serv_txs_chipsel = 1'b0;

    assign serv_txs_write = 1'b0;

    assign serv_txs_read = 1'b0;

    assign serv_txs_byteen = 8'b00000000;

    //assign serv_irq = 1'b0;

    reg[63:0] _value = 64'b0000000000000000000000000000000000000000000000000000000000000000;
    reg _irq = 1'b0;
    reg _txs_writed = 64'b0000000000000000000000000000000000000000000000000000000000000000;

    always @(posedge serv_clk)
    begin
        if(serv_bar1_0_readd != _value)
            begin
                _value <= serv_bar1_0_readd;
                _txs_writed <= serv_bar1_0_readd | 64'b0100000000000000000000000000000000000000000000000000000000000010;
                _irq <= 1'b1;
            end
        else
            _irq <= 1'b0;
    end

    assign serv_value = _value;
    assign serv_irq = _irq;
    assign serv_txs_writed = _txs_writed;

endmodule

【问题讨论】:

    标签: linux-device-driver fpga intel-fpga pci-e


    【解决方案1】:
    plx_pci_io_base = pci_resource_start(dev, 0);
    iolength = pci_resource_len(dev, 0);
    
    if (!request_mem_region(plx_pci_io_base, iolength, "PGDR IO Base")) {
        DEBUG(KERN_ERR "request region #1\n");
        return -EBUSY;
    }
    
    iobase = ioremap_nocache(plx_pci_io_base, iolength);
    if (!iobase) {
        DEBUG(KERN_ERR "ioremap #1\n");
        ret_status = -ENOMEM;
        goto cleanup1;
    }
    

    【讨论】:

    • 谢谢 TSP!它帮助我成功调用了这些函数。但我第一次在登记册上有一个条目。在删除我的内核模块之后的后续时间。我有一个未注册的驱动程序,不是由扫描基址寄存器的功能引起的。另外,我无法在 FPGA 上处理这些数据以返回结果,并读取加 2 的值。
    • 对不起弗拉基米尔。请您改写“我有一个未注册的”。我听不懂你想说什么。
    • 不,不! TSP,error是不可能的error是模块重启了,函数request_mem_region(plx_pci_io_base, iolength, "PGDR IO Base");没有成功。
    • 好的。那可能是因为您没有释放内存。您必须调用 iounmap,然后在 cleanup_module 中调用 release_mem_region。
    • 非常感谢! TSP,你能帮我解决FPGA上数据处理的问题吗?
    【解决方案2】:

    您可以尝试以下方法:

    1. 使用 writel 和 readl 代替 outl_p 和 inl_p
    2. 检查您正在写入/读取的 BAR 寄存器和 RTL 使用的 BAR 寄存器是否相同
    3. 使用 Signal Tap 检查 RD/WR 是否到达您的 RTL 逻辑

    【讨论】:

    • 我检查设备并且 BAR 已注册 root@vbochkov:~# lspci -d 1172:0004 -vv 02:00.0 未分配类 [ff00]: Altera Corporation 设备 0004 (rev 01) 子系统: Altera公司设备 0004 控制:I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx- 。延迟:0,缓存线大小:64 字节中断:引脚 A 路由到 IRQ 7 区域 0:内存位于 fdcf0000(32 位,不可预取)[大小=64K]
    • 我尝试使用 writel()/readl(),但是系统给我一个错误信息如下: [ 470.764942] BUG:无法在 ffff8800fdcf0000 处理内核分页请求 [ 470.765359] CPU: 5 PID:2216 Comm:insmod污染:G o 3.10.17#2 [470.765440]任务:FFFF880205B0E2E0 TI:FFFF8801A9C7A000 Task.Ti:FFFF8801A9C7A000 RIP:0010:[] [] [] [] Altpcie_Init + 0xcc / 0x14d [pci_m] [470.766232] 代码:48 8b 05 18 e8 ff ff 48 39 05 09 e8 ff ff 75 0e 48 c7 c7 46 82 b4 a0 31 c0 e8 bc 5b 01 e1 8b 05 eb e7 ff e7 ff 48 8b 15 ff ff 02 8b 35 ..
    • 不能直接对从BAR寄存器读取的地址进行读写操作。读取 BAR 寄存器后,您必须调用 request_mem_region,然后调用 ioremap_nocache。 ioremap_nocache 将返回一个地址,您可以在该地址上执行读/写操作。
    猜你喜欢
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多