应用程序实现读写PCIE设备配置空间
2013-03-30 09:49
585 查看
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;
}
可通过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;
}
相关文章推荐
- PCIe 配置空间读写内核实现
- Linux PCI Express 配置空间读写内核实现
- 4.3 PCIe设备的扩展配置空间
- PCIe配置空间和PCI设备中的寄存器
- PCIe设备的配置空间 分类: 浅谈PCI-E 2013-07-22 16:31 720人阅读 评论(0) 收藏
- PCIe设备的配置空间
- PCI Express设备驱动 (4,PCIe配置空间和PCI设备中的寄存器)
- PCI Express设备驱动 (4,PCIe配置空间和PCI设备中的寄存器)
- PCIe设备的配置空间
- 【Linux c】读写pcie配置空间(安装lib库)
- PCIe设备的配置空间
- 如何在Linux下实现设备的配置(上)
- STL——模拟实现空间配置器
- 如何在Linux下实现设备的配置
- Linux I2C设备读写应用程序
- 配置文件键值对读写API函数实现
- pcie的配置空间
- C语言实现读写配置文件项目
- PCIe学习笔记(11)--- 配置空间的读写请求
- 如何在Linux下实现设备的配置(下)