• Libpci库的调用


    这几天发现在Redhat AS6.5 X86_64下用outl(index, 0xcf8)和inl(0xcfc)下读取PCIe配置空间是系统有时性的会hang, 于是去寻找解决方案,首先想到的是用/dev/port这种方案去替代,折腾了半天发现不行,后来想到为什么不用lspci的方法了,结果就成功了,如下为分享。

    1.基本介绍

    Lspci的工具包名为pciutils, 是由捷克的大伽Martin Mares 开发的,目前最新的版本为3.5.1, 你可以通过mj@ucw.cz 联系他, 他的个人主页为http://mj.ucw.cz/, 在上面可以找到他的联系方式。

     

    Lspci支持众多OS,

        Linux        (via /sys/bus/pci, /proc/bus/pci or i386 ports)

        FreeBSD        (via /dev/pci)

        NetBSD        (via libpci)

        OpenBSD        (via /dev/pci)

        GNU/kFreeBSD    (via /dev/pci)

        Solaris/i386    (direct port access)

        Aix        (via /dev/pci and odmget)

        GNU Hurd    (direct port access)

        Windows        (direct port access, see README.Windows for caveats)

        CYGWIN        (direct port access)

        BeOS        (via syscalls)

        Haiku        (via /dev/misc/poke)

        Darwin        (via IOKit)

    当然我们最关心的Linux.

     

    2.下载

    你可以从ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/ 下载到最新的pciutils,下载后将pciutils-3.5.1.tar.gz解压。然后进入目录运行make进行编译, 编译后你会看到如下目录。

     

    3.Libpci库

    进入lib目录, 就会看到生成了一个libpci.a的静态库,这个库你是可以调用的,如果想调用动态库,只需要修改Makefile, 将SHARED参数改为yes即可

    SHARED=yes

    #make clean

    #make

    就会有libpci.so.3.5.1生成,如果嫌后面的版本麻烦,可以将其直接改名为libpci.so.

    实际上无论是lspci还是setpci都是调用libpci这个库的。

    4. libpci库的调用

    首先将libpci.so加到makefile中去,以下为一个例子。

    LIB+=-lpthread -ldl ../../lib/libpci.so

     

     

    以下是具体的调用例子:

     

    将lib目录下的头文件全部copy到/usr/include/pci目录下,有些Linux系统是没有pci目录的,需要创建一个。

     

    #include <pci/pci.h>

     

    bool PCIe::getPCIConfig(PCI_CONFIG *pci_cfg, unsigned char BusNum, unsigned char DevNum, unsigned char FuncNum)

    {

        bool bRet = true;

        unsigned int* pPCIConfig = (unsigned int*)pci_cfg;

        int i,j;

        unsigned char value[256];

        memset(value, 0, sizeof(value));

        struct pci_access *pacc;

        struct pci_dev *dev;

        pacc = pci_alloc();        /* Get the pci_access structure */

        /* Set all options you want -- here we stick with the defaults */

        pci_init(pacc);        /* Initialize the PCI library */

        pci_scan_bus(pacc);        /* We want to get the list of devices */

        for (dev=pacc->devices; dev; dev=dev->next)    /* Iterate over all devices */

        {

            if(! pci_read_block(dev, 0, value, 256))

            {

                printf("Get PCIE configuration space block fail ");

                break;

            }

     

            if((BusNum == dev->bus) && (DevNum == dev->dev) && (FuncNum == dev->func))

            {

                for(i=0, j=0;i<64, j<256;i++, j+=4)

                {

                    pPCIConfig[i] = value[j] | (value[j+1] <<8) | (value[j+2] <<16) | (value[j+3] <<24);

                    // printf("%d: %04x ", i, pPCIConfig[i] );

                    if (i == 0 && ((pPCIConfig[i] == 0xFFFFFFFF) || ((pPCIConfig[i]&0xFFFF) == 0L)))

                    {

                        bRet = false;

                        break;

                    }

                }

                break;

            }

        }

        pci_cleanup(pacc);        /* Close everything */

        return bRet;

    }

     

    调用的函数都在pci.h中可以参考如下。

    /*

    *    The PCI Library

    *

    *    Copyright (c) 1997--2016 Martin Mares <mj@ucw.cz>

    *

    *    Can be freely distributed and used under the terms of the GNU GPL.

    */

     

    #ifndef _PCI_LIB_H

    #define _PCI_LIB_H

     

    #ifndef PCI_CONFIG_H

    #include "config.h"

    #endif

     

    #include "header.h"

    #include "types.h"

     

    #define PCI_LIB_VERSION 0x030501

     

    #ifndef PCI_ABI

    #define PCI_ABI

    #endif

     

    /*

    *    PCI Access Structure

    */

     

    struct pci_methods;

     

    enum pci_access_type {

    /* Known access methods, remember to update access.c as well */

    PCI_ACCESS_AUTO,            /* Autodetection */

    PCI_ACCESS_SYS_BUS_PCI,        /* Linux /sys/bus/pci */

    PCI_ACCESS_PROC_BUS_PCI,        /* Linux /proc/bus/pci */

    PCI_ACCESS_I386_TYPE1,        /* i386 ports, type 1 */

    PCI_ACCESS_I386_TYPE2,        /* i386 ports, type 2 */

    PCI_ACCESS_FBSD_DEVICE,        /* FreeBSD /dev/pci */

    PCI_ACCESS_AIX_DEVICE,        /* /dev/pci0, /dev/bus0, etc. */

    PCI_ACCESS_NBSD_LIBPCI,        /* NetBSD libpci */

    PCI_ACCESS_OBSD_DEVICE,        /* OpenBSD /dev/pci */

    PCI_ACCESS_DUMP,            /* Dump file */

    PCI_ACCESS_DARWIN,            /* Darwin */

    PCI_ACCESS_MAX

    };

     

    struct pci_access {

    /* Options you can change: */

    unsigned int method;            /* Access method */

    int writeable;            /* Open in read/write mode */

    int buscentric;            /* Bus-centric view of the world */

     

    char *id_file_name;            /* Name of ID list file (use pci_set_name_list_path()) */

    int free_id_name;            /* Set if id_file_name is malloced */

    int numeric_ids;            /* Enforce PCI_LOOKUP_NUMERIC (>1 => PCI_LOOKUP_MIXED) */

     

    unsigned int id_lookup_mode;        /* pci_lookup_mode flags which are set automatically */

                        /* Default: PCI_LOOKUP_CACHE */

     

    int debugging;            /* Turn on debugging messages */

     

    /* Functions you can override: */

    void (*error)(char *msg, ...) PCI_PRINTF(1,2);    /* Write error message and quit */

    void (*warning)(char *msg, ...) PCI_PRINTF(1,2);    /* Write a warning message */

    void (*debug)(char *msg, ...) PCI_PRINTF(1,2);    /* Write a debugging message */

     

    struct pci_dev *devices;        /* Devices found on this bus */

     

    /* Fields used internally: */

    struct pci_methods *methods;

    struct pci_param *params;

    struct id_entry **id_hash;        /* names.c */

    struct id_bucket *current_id_bucket;

    int id_load_failed;

    int id_cache_status;            /* 0=not read, 1=read, 2=dirty */

    struct udev *id_udev;            /* names-hwdb.c */

    struct udev_hwdb *id_udev_hwdb;

    int fd;                /* proc/sys: fd for config space */

    int fd_rw;                /* proc/sys: fd opened read-write */

    int fd_pos;                /* proc/sys: current position */

    int fd_vpd;                /* sys: fd for VPD */

    struct pci_dev *cached_dev;        /* proc/sys: device the fds are for */

    };

     

    /* Initialize PCI access */

    struct pci_access *pci_alloc(void) PCI_ABI;

    void pci_init(struct pci_access *) PCI_ABI;

    void pci_cleanup(struct pci_access *) PCI_ABI;

     

    /* Scanning of devices */

    void pci_scan_bus(struct pci_access *acc) PCI_ABI;

    struct pci_dev *pci_get_dev(struct pci_access *acc, int domain, int bus, int dev, int func) PCI_ABI; /* Raw access to specified device */

    void pci_free_dev(struct pci_dev *) PCI_ABI;

     

    /* Names of access methods */

    int pci_lookup_method(char *name) PCI_ABI;    /* Returns -1 if not found */

    char *pci_get_method_name(int index) PCI_ABI;    /* Returns "" if unavailable, NULL if index out of range */

     

    /*

    *    Named parameters

    */

     

    struct pci_param {

    struct pci_param *next;        /* Please use pci_walk_params() for traversing the list */

    char *param;                /* Name of the parameter */

    char *value;                /* Value of the parameter */

    int value_malloced;            /* used internally */

    char *help;                /* Explanation of the parameter */

    };

     

    char *pci_get_param(struct pci_access *acc, char *param) PCI_ABI;

    int pci_set_param(struct pci_access *acc, char *param, char *value) PCI_ABI;    /* 0 on success, -1 if no such parameter */

    /* To traverse the list, call pci_walk_params repeatedly, first with prev=NULL, and do not modify the parameters during traversal. */

    struct pci_param *pci_walk_params(struct pci_access *acc, struct pci_param *prev) PCI_ABI;

     

    /*

    *    Devices

    */

     

    struct pci_dev {

    struct pci_dev *next;            /* Next device in the chain */

    u16 domain_16;            /* 16-bit version of the PCI domain for backward compatibility */

                        /* 0xffff if the real domain doesn't fit in 16 bits */

    u8 bus, dev, func;            /* Bus inside domain, device and function */

     

    /* These fields are set by pci_fill_info() */

    int known_fields;            /* Set of info fields already known */

    u16 vendor_id, device_id;        /* Identity of the device */

    u16 device_class;            /* PCI device class */

    int irq;                /* IRQ number */

    pciaddr_t base_addr[6];        /* Base addresses including flags in lower bits */

    pciaddr_t size[6];            /* Region sizes */

    pciaddr_t rom_base_addr;        /* Expansion ROM base address */

    pciaddr_t rom_size;            /* Expansion ROM size */

    struct pci_cap *first_cap;        /* List of capabilities */

    char *phy_slot;            /* Physical slot */

    char *module_alias;            /* Linux kernel module alias */

    char *label;                /* Device name as exported by BIOS */

    int numa_node;            /* NUMA node */

    pciaddr_t flags[6];            /* PCI_IORESOURCE_* flags for regions */

    pciaddr_t rom_flags;            /* PCI_IORESOURCE_* flags for expansion ROM */

    int domain;                /* PCI domain (host bridge) */

     

    /* Fields used internally: */

    struct pci_access *access;

    struct pci_methods *methods;

    u8 *cache;                /* Cached config registers */

    int cache_len;

    int hdrtype;                /* Cached low 7 bits of header type, -1 if unknown */

    void *aux;                /* Auxillary data */

    };

     

    #define PCI_ADDR_IO_MASK (~(pciaddr_t) 0x3)

    #define PCI_ADDR_MEM_MASK (~(pciaddr_t) 0xf)

    #define PCI_ADDR_FLAG_MASK 0xf

     

    u8 pci_read_byte(struct pci_dev *, int pos) PCI_ABI; /* Access to configuration space */

    u16 pci_read_word(struct pci_dev *, int pos) PCI_ABI;

    u32 pci_read_long(struct pci_dev *, int pos) PCI_ABI;

    int pci_read_block(struct pci_dev *, int pos, u8 *buf, int len) PCI_ABI;

    int pci_read_vpd(struct pci_dev *d, int pos, u8 *buf, int len) PCI_ABI;

    int pci_write_byte(struct pci_dev *, int pos, u8 data) PCI_ABI;

    int pci_write_word(struct pci_dev *, int pos, u16 data) PCI_ABI;

    int pci_write_long(struct pci_dev *, int pos, u32 data) PCI_ABI;

    int pci_write_block(struct pci_dev *, int pos, u8 *buf, int len) PCI_ABI;

     

    int pci_fill_info(struct pci_dev *, int flags) PCI_ABI; /* Fill in device information */

     

    #define PCI_FILL_IDENT        0x0001

    #define PCI_FILL_IRQ        0x0002

    #define PCI_FILL_BASES        0x0004

    #define PCI_FILL_ROM_BASE    0x0008

    #define PCI_FILL_SIZES        0x0010

    #define PCI_FILL_CLASS        0x0020

    #define PCI_FILL_CAPS        0x0040

    #define PCI_FILL_EXT_CAPS    0x0080

    #define PCI_FILL_PHYS_SLOT    0x0100

    #define PCI_FILL_MODULE_ALIAS    0x0200

    #define PCI_FILL_LABEL        0x0400

    #define PCI_FILL_NUMA_NODE    0x0800

    #define PCI_FILL_IO_FLAGS    0x1000

    #define PCI_FILL_RESCAN        0x00010000

     

    void pci_setup_cache(struct pci_dev *, u8 *cache, int len) PCI_ABI;

     

    /*

    *    Capabilities

    */

     

    struct pci_cap {

    struct pci_cap *next;

    u16 id;                /* PCI_CAP_ID_xxx */

    u16 type;                /* PCI_CAP_xxx */

    unsigned int addr;            /* Position in the config space */

    };

     

    #define PCI_CAP_NORMAL        1    /* Traditional PCI capabilities */

    #define PCI_CAP_EXTENDED    2    /* PCIe extended capabilities */

     

    struct pci_cap *pci_find_cap(struct pci_dev *, unsigned int id, unsigned int type) PCI_ABI;

     

    /*

    *    Filters

    */

     

    struct pci_filter {

    int domain, bus, slot, func;            /* -1 = ANY */

    int vendor, device, device_class;

    int rfu[3];

    };

     

    void pci_filter_init(struct pci_access *, struct pci_filter *) PCI_ABI;

    char *pci_filter_parse_slot(struct pci_filter *, char *) PCI_ABI;

    char *pci_filter_parse_id(struct pci_filter *, char *) PCI_ABI;

    int pci_filter_match(struct pci_filter *, struct pci_dev *) PCI_ABI;

     

    /*

    *    Conversion of PCI ID's to names (according to the pci.ids file)

    *

    *    Call pci_lookup_name() to identify different types of ID's:

    *

    *    VENDOR                (vendorID) -> vendor

    *    DEVICE                (vendorID, deviceID) -> device

    *    VENDOR | DEVICE            (vendorID, deviceID) -> combined vendor and device

    *    SUBSYSTEM | VENDOR        (subvendorID) -> subsystem vendor

    *    SUBSYSTEM | DEVICE        (vendorID, deviceID, subvendorID, subdevID) -> subsystem device

    *    SUBSYSTEM | VENDOR | DEVICE    (vendorID, deviceID, subvendorID, subdevID) -> combined subsystem v+d

    *    SUBSYSTEM | ...            (-1, -1, subvendorID, subdevID) -> generic subsystem

    *    CLASS                (classID) -> class

    *    PROGIF                (classID, progif) -> programming interface

    */

     

    char *pci_lookup_name(struct pci_access *a, char *buf, int size, int flags, ...) PCI_ABI;

     

    int pci_load_name_list(struct pci_access *a) PCI_ABI;    /* Called automatically by pci_lookup_*() when needed; returns success */

    void pci_free_name_list(struct pci_access *a) PCI_ABI;    /* Called automatically by pci_cleanup() */

    void pci_set_name_list_path(struct pci_access *a, char *name, int to_be_freed) PCI_ABI;

    void pci_id_cache_flush(struct pci_access *a) PCI_ABI;

     

    enum pci_lookup_mode {

    PCI_LOOKUP_VENDOR = 1,        /* Vendor name (args: vendorID) */

    PCI_LOOKUP_DEVICE = 2,        /* Device name (args: vendorID, deviceID) */

    PCI_LOOKUP_CLASS = 4,            /* Device class (args: classID) */

    PCI_LOOKUP_SUBSYSTEM = 8,

    PCI_LOOKUP_PROGIF = 16,        /* Programming interface (args: classID, prog_if) */

    PCI_LOOKUP_NUMERIC = 0x10000,        /* Want only formatted numbers; default if access->numeric_ids is set */

    PCI_LOOKUP_NO_NUMBERS = 0x20000,    /* Return NULL if not found in the database; default is to print numerically */

    PCI_LOOKUP_MIXED = 0x40000,        /* Include both numbers and names */

    PCI_LOOKUP_NETWORK = 0x80000,        /* Try to resolve unknown ID's by DNS */

    PCI_LOOKUP_SKIP_LOCAL = 0x100000,    /* Do not consult local database */

    PCI_LOOKUP_CACHE = 0x200000,        /* Consult the local cache before using DNS */

    PCI_LOOKUP_REFRESH_CACHE = 0x400000,    /* Forget all previously cached entries, but still allow updating the cache */

    PCI_LOOKUP_NO_HWDB = 0x800000,    /* Do not ask udev's hwdb */

    };

     

    #endif

     

     

     

  • 相关阅读:
    .Net Intelligencia.UrlRewriter 重定向参数中文支持配置方法
    Debian 9 vsftpd: version 3.0.3 配置
    Debian 静态网络配置
    iptables常用配置
    Debian防御DDOS(简易版本)
    Debian9+PHP7+MySQL+Apache2配置Thinkphp运行环境LAMP
    Discuz3.3注册程序修改添加记录推荐人账号
    .NetCore WPF 指定一个相对路径的图片,报错“找不到资源”
    C语言的unsigned做双目运算符的奇怪问题
    关于人脸识别的视频图片处理
  • 原文地址:https://www.cnblogs.com/terrytian88/p/5896423.html
Copyright © 2020-2023  润新知