应用程序实现读写PCIE设备配置空间

pcie设备的配置空间相对于pci设备从256增大到4K,只有前256可以通过ioport方式读写,后面的内容则需要从MCONF空间读写。

可通过cat /proc/iomem查看MCONF空间地址,我设备的MCONF空间定义为0x80000000.


适用于x86设备

#############################代码如下#############################

#include <stdio.h>

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/io.h>
#include <sys/mman.h>


#define PCI_CTRL_PORT   0xCF8
#define PCI_DATA_PORT   0xCFC


#define PCI_DEV_NUM             0x0
#define PRI_BUS_NUM             0x18
#define SEC_BUS_NUM             0x19
#define SUB_BUS_NUM             0x1a
#define PCI_MCONF_CTRL  0x260
#define PCI_MCONF_BUFF  0x264


#define EEPROM_BIT              16
#define PLX8632_DEV             0x863210B5


#define BUS_BIT                 20
#define SLOT_BIT                15
#define FUNC_BIT                12
#define REG_BIT                 2
#define EN_BIT                  0


#define PCIE_CONF_SIZE  0x1000
#define PCIEXBAR_ADDR   0x80000000


typedef struct {
        unsigned char bus;
        unsigned char slot;
        unsigned char func;
} pci_dev_t;


static pci_dev_t ninja_slot[3] = {
        {0, 3, 0},
        {0, 3, 2},
        {0, 2, 2},
};




int mem_fd = -1;
volatile char * mem = NULL;


unsigned int map_pci_config_space(unsigned char bus, unsigned char slot, unsigned char func)
{
        unsigned long phyaddr;
        unsigned int len;


        mem_fd = open("/dev/mem", O_RDWR);
        if(mem_fd < 0)
        {
                printf("file /dev/mem open error\n");
                return 1;
        }


        phyaddr = (PCIEXBAR_ADDR) | (bus << BUS_BIT) | (slot << SLOT_BIT) | (func << FUNC_BIT);
        len = PCIE_CONF_SIZE;
        //printf("phyaddr %lx, len %x\n", phyaddr, len);
        mem = (volatile char *) mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, phyaddr);
        if((char *) MAP_FAILED == mem)
        {
                printf("mmap failed %d, pbyaddr : 0x%lx, len : 0x%08x\n", bus, phyaddr, len);
                return 1;
        }


        return 0;
}


unsigned int unmap_pci_config_space(void)
{
        unsigned int len = PCIE_CONF_SIZE;


        if (mem != NULL)
        {
                munmap((void *)mem, len);
                mem = NULL;
        }


        close(mem_fd);


        return 0;
}


/* for offset < 0xff */
static unsigned char read_pci_config_8(unsigned char bus, unsigned char slot, unsigned char func, unsigned char offset)
{
        unsigned char v;
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, PCI_CTRL_PORT);
        v = inb(PCI_DATA_PORT + (offset&3));
        return v;
}


#if 0
static unsigned short read_pci_config_16(unsigned char bus, unsigned char slot, unsigned char func, unsigned char offset)
{
        unsigned short v;
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, PCI_CTRL_PORT);
        v = inw(PCI_DATA_PORT + (offset&2));
        return v;
}


static unsigned int read_pci_config_32(unsigned char bus, unsigned char slot, unsigned char func, unsigned char offset)
{
        unsigned int v;
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, PCI_CTRL_PORT);
        v = inl(PCI_DATA_PORT);
        return v;
}


static void write_pci_config_8(unsigned char bus,unsigned char slot, unsigned char func, unsigned char offset, unsigned char val)
{
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, PCI_CTRL_PORT);
        outb(val, PCI_DATA_PORT + (offset&3));
}


static void write_pci_config_16(unsigned char bus,unsigned char slot, unsigned char func, unsigned char offset, unsigned char val)
{
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, PCI_CTRL_PORT);
        outw(val, PCI_DATA_PORT + (offset&2));
}


static void write_pci_config_32(unsigned char bus, unsigned char slot, unsigned char func, unsigned char offset, unsigned int val)
{
        outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, PCI_CTRL_PORT);
        outl(val, PCI_DATA_PORT);
}
#endif


/* for offset 0 - 0x1000 */
static unsigned int pci_mmconfig_write_32(unsigned short offset, unsigned int val)
{
        if (mem == NULL)
                return 1;


        *(volatile unsigned int *)(mem + (offset << REG_BIT)/sizeof(unsigned int)) = val;


        return 0;
}


static unsigned int pci_mmconfig_read_32(unsigned short offset, unsigned int * val)
{
        if (mem == NULL)
                return 1;


        *val = *(volatile unsigned int *)(mem + (offset << REG_BIT)/sizeof(unsigned int));


        return 0;
}


unsigned int is_valid_slot(unsigned int slot_num, unsigned char * bus)
{
        pci_dev_t * pci_dev;
        unsigned char sec_bus;
        unsigned char sub_bus;


        if (slot_num > 3)
                return 1;


        pci_dev = &ninja_slot[slot_num];
        sec_bus = read_pci_config_8(pci_dev->bus, pci_dev->slot, pci_dev->func, SEC_BUS_NUM);
        sub_bus = read_pci_config_8(pci_dev->bus, pci_dev->slot, pci_dev->func, SUB_BUS_NUM);
        //printf("%x [%x - %x]\n", slot_num, sec_bus, sub_bus);


        if ((sub_bus - sec_bus) == 10)
        {
                *bus = sec_bus;
                return 0;
        }


        return 1;
}

static unsigned int plx8632_eeprom_read(unsigned int slot_num, unsigned char * board_type)
{
        unsigned char bus;
        unsigned int eeprom_addr;
        unsigned int version[64], ver_start;
        //unsigned char board_type[16];
        unsigned int val;
        unsigned int count;
        int i;


        if (is_valid_slot(slot_num, &bus) == 0)
        {
                if (map_pci_config_space(bus, 0, 0))
                {
                        printf("map pci config space error.\n");
                        return 1;
                }


                if (pci_mmconfig_read_32(PCI_DEV_NUM, &val))
                {
                        printf("mmconfig read error.\n");
                        return 1;
                }
                if (val != PLX8632_DEV)
                {
                        printf("it is not plx8632.\n");
                        return 1;
                }


                if (pci_mmconfig_read_32(PCI_MCONF_CTRL, &val))
                {
                        printf("mmconfig read error.\n");
                        return 1;
                }
                if ((val & (1 << EEPROM_BIT)) == 0)
                {
                        printf("no eeprom here.\n");
                        return 1;
                }


                eeprom_addr = (val & 0xffff0000) | (0x3 << 13);


                for( i = 0; i < 64; i++)
                {
                        if (pci_mmconfig_write_32(PCI_MCONF_CTRL, eeprom_addr))
                        {
                                printf("get eeprom address error.\n");
                                return 1;
                        }
                        //wait command executed complete
                        count = 0;
                        do
                        {
                                if (pci_mmconfig_read_32(PCI_MCONF_CTRL, &val))
                                {
                                        printf("read status error.\n");
                                        return 1;
                                }
                                usleep(100);
                                count++;
                        } while((((val >> 18) & 0x1) && (count < 1000)));
                        if(count >= 1000)
                        {
                                printf("read EEPROM timeout\n");
                                return 1;
                        }


                        if(pci_mmconfig_read_32(PCI_MCONF_BUFF, &val))
                        {
                                printf("read EEPROM value error.\n");
                                return 1;
                        }
                        version[i] = val;
                        if( val == 0xffffffff)
                                break;
                        eeprom_addr++;
                }


                // eeprom data : [0xaa55] [data_len] [register_data] [serial_num]
                ver_start = (version[0] >> 16)/4 + 1;
                if ((version[0] >> 16) % 4)
                {
                        int j = 0;
                        int k = 0;
                        *(unsigned char *)(board_type + k++) = ((version[ver_start] >> 16) & 0xff);
                        *(unsigned char *)(board_type + k++) = ((version[ver_start] >> 24) & 0xff);
                        for(i = 1;i < 4; i++)
                        {
                                for(j = 0;j < 32; j+=8)
                                        *(unsigned char *)(board_type + k++) = ((version[ver_start+i] >> j) & 0xff);
                        }
                        *(unsigned char *)(board_type + k++) = (version[ver_start+i]) & 0xff;
                        *(unsigned char *)(board_type + k++) = (version[ver_start+i]>>8) & 0xff;
                }
                else
                {
                        int j = 0;
                        int k = 0;
                        for (i = 0;i < 4; i++)
                        {
                                for (j = 0;j < 32; j+=8)
                                        *(unsigned char *)(board_type + k++) = (version[ver_start + i] >> j) & 0xff;
                        } 
                }
                if((board_type[12] == 0x0) && (board_type[13] == 0x0) && (board_type[14] == 0x0) && (board_type[15] == 0x0))
                {
                        printf("there is no hardware version available,please to have a check\n");
                        return 1;
                }
                //printf("Board type:%12s Hardware Version: %d.%d.%d.%d\n", board_type, board_type[12], board_type[13], board_type[14], board_type[15]);


                unmap_pci_config_space();


                return 0;
        }
        else
        {
                printf("slot is invalid\n");
                return 1;
        }
}


int main(void)
{
        unsigned char board[16];
        iopl(3);


        printf("slot0\n");
        if (0 == plx8632_eeprom_read(0, board))
        {
                printf("%12s\n", board);
                printf("%d %d %d %d\n", board[12], board[13], board[14], board[15]);
        }
        printf("slot1\n");
        if (0 == plx8632_eeprom_read(1, board))
        {
                printf("%12s\n", board);
                printf("%d %d %d %d\n", board[12], board[13], board[14], board[15]);
        }
        printf("slot2\n");
        if (0 == plx8632_eeprom_read(2, board))
        {
                printf("%12s\n", board);
                printf("%d %d %d %d\n", board[12], board[13], board[14], board[15]);
        }


        return 0;
}
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这里提供一个简单的PCIe设备驱动代码样例和注释,请根据自己实际的硬件情况进行修改: ```c #include <linux/module.h> // 模块相关的头文件 #include <linux/pci.h> // PCIe相关的头文件 #include <linux/init.h> // 初始化相关的头文件 // 定义PCIe设备ID static struct pci_device_id pci_ids[] = { { 0x1234, 0x5678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0 } }; MODULE_DEVICE_TABLE(pci, pci_ids); // 定义PCIe设备的初始化函数 static int pcie_driver_probe(struct pci_dev *dev, const struct pci_device_id *id) { int err; // 停用设备 pci_disable_device(dev); // 分配设备资源 err = pci_enable_device(dev); if (err) return err; // 映射设备内存 void *hw_addr = pci_iomap(dev, 0, pci_resource_len(dev, 0)); if (!hw_addr) return -EIO; // 打印设备信息 pr_info("PCIe device found (%04x:%04x)\n", dev->vendor, dev->device); // TODO: 对设备进行初始化 return 0; } // 定义PCIe设备的卸载函数 static void pcie_driver_remove(struct pci_dev *dev) { // 解除映射设备内存 pci_iounmap(dev, pci_resource_len(dev, 0)); // 停用设备 pci_disable_device(dev); // 打印设备卸载信息 pr_info("PCIe device removed (%04x:%04x)\n", dev->vendor, dev->device); } // 定义PCIe设备驱动结构体 static struct pci_driver pcie_driver = { .name = "pcie_driver", .id_table = pci_ids, .probe = pcie_driver_probe, .remove = pcie_driver_remove }; // 注册PCIe设备驱动 static int __init pcie_driver_init(void) { return pci_register_driver(&pcie_driver); } // 注销PCIe设备驱动 static void __exit pcie_driver_exit(void) { pci_unregister_driver(&pcie_driver); } // 指定初始化函数和卸载函数 module_init(pcie_driver_init); module_exit(pcie_driver_exit); // 指定模块的信息 MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("PCIe device driver example"); ``` 注释: - `pci_device_id` 结构体用于定义 PCIe 设备的厂商 ID、设备 ID、子系统厂商 ID、子系统 ID 等信息。使用 `MODULE_DEVICE_TABLE(pci, pci_ids)` 宏定义设备 ID 列表,供内核自动匹配设备使用。 - `pcie_driver_probe()` 函数是 PCI 设备驱动的初始化函数,当内核发现匹配的 PCIe 设备时,会调用此函数完成对设备配置和初始化。在函数中,需要先停用设备,然后为设备分配资源(如内存和 I/O 端口),并将资源地址映射到内核虚拟地址空间。最后,对设备进行初始化,如设置寄存器值、清空中断等。如果初始化失败,需要返回错误码,否则返回 0 表示初始化成功。 - `pcie_driver_remove()` 函数是 PCI 设备驱动的卸载函数。当内核需要卸载 PCIe 设备驱动时,会调用此函数完成对设备的解除映射和停用操作。在函数中,需要先解除内核虚拟地址空间设备资源的映射,然后停用设备。最后可以打印设备卸载信息(可选)。 - `pci_driver` 结构体用于定义 PCI 设备驱动的名字、设备 ID 列表、初始化函数和卸载函数。使用 `pci_register_driver()` 函数注册 PCI 设备驱动,使用 `pci_unregister_driver()` 函数注销设备驱动。 - `module_init()` 和 `module_exit()` 宏指定初始化函数和卸载函数。`MODULE_LICENSE()` 宏指定此模块的许可证,如 GPL 或 LGPL。其他常用的模块指定宏还包括 `MODULE_AUTHOR()`、`MODULE_DESCRIPTION()` 和 `MODULE_VERSION()`。 - 常用的 PCI 总线相关函数包括 `pci_enable_device()`、`pci_disable_device()`、`pci_resource_start()`、`pci_resource_len()` 和 `pci_iomap()` 等。函数的具体使用方式,请参考相关文档和例程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值