您的位置:首页 > 运维架构 > Linux

应用程序实现读写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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息