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

来源:互联网 发布:安卓源码分享 编辑:程序博客网 时间:2024/06/05 10:25

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;
}