这是我正在研究的SR-IOV驱动程序的起点。我之前从未做过PCIe驱动程序,很多都是我弄清楚到底发生了什么。在这个驱动程序中,我寻找一个特定的供应商ID,只需加载驱动程序,然后我在日志文件中打印一堆东西,看看发生了什么。它加载,当我运行lspci时,我可以看到PF和4 VF。
我没想到的(可能是因为我没有想到)是探针功能会为每个VF运行。我看到的英特尔示例代码在其结构中都有一个.sriov_configure成员。我以为会被召唤,但事实并非如此,所以也许我在这里做错了。
我的问题是,因为当我正在查看VF时,我想在探测PF和某些其他事情时做某些事情,确定这个探测器的特定实例是否适用于PF的“正确”方法是什么还是VF?
为了完整性,日志(大量日志)和来源如下。您可以看到em_probe被多次调用。 提前谢谢。
[ 10.516072] em: em initialize
[ 10.526026] em: ENTER --> em_probe
[ 10.546857] pci_em 0000:04:00.0: enabling device (0100 -> 0102)
[ 10.571659] em: ====== em CONFIG SPACE ======
[ 10.583073] em: VENDOR_ID = 0x1172
[ 10.593789] em: DEVICE_ID = 0xBEAD
[ 10.604454] em: SUBSYSTEM_ID = 0x0011
[ 10.615089] em: SUBSYSTEM VENDOR ID = 0xABCD
[ 10.625698] em: Address Start : 0x00000000FBE00000
[ 10.636847] em: Address End : 0x00000000FBEFFFFF
[ 10.670164] em: Address Length: 0x0000000000100000
[ 10.681285] em: Address Base : 0x000000000000E000
[ 10.692352] em: PCI NUM VF before enable sriov: 0x0000000000000000
[ 10.805976] em: ENTER --> em_probe
[ 10.805984] pci_em 0000:04:00.1: enabling device (0000 -> 0002)
[ 10.805997] em: ====== em CONFIG SPACE ======
[ 10.805998] em: VENDOR_ID = 0xFFFF
[ 10.805999] em: DEVICE_ID = 0xFFFF
[ 10.806001] em: SUBSYSTEM_ID = 0x0011
[ 10.806002] em: SUBSYSTEM VENDOR ID = 0xABCD
[ 10.806015] em: Address Start : 0x0000000090000000
[ 10.806016] em: Address End : 0x0000000090000FFF
[ 10.806018] em: Address Length: 0x0000000000001000
[ 10.806019] em: Address Base : 0x0000000000396000
[ 10.806020] em: PCI NUM VF before enable sriov: 0x0000000000000000
[ 10.806021] em: PCI NUM VF after enable sriov: 0x0000000000000000
[ 10.806025] em: SR-IOV CapID : 0x0000
[ 10.806026] em: SR-IOV CapVer : 0x0000
[ 10.806027] em: EXIT <-- em_probe
[ 10.807806] em: ENTER --> em_probe
[ 10.807855] pci_em 0000:04:00.2: enabling device (0000 -> 0002)
[ 10.807933] em: ====== em CONFIG SPACE ======
[ 10.807934] em: VENDOR_ID = 0xFFFF
[ 10.807935] em: DEVICE_ID = 0xFFFF
[ 10.807938] em: SUBSYSTEM_ID = 0x0011
[ 10.807940] em: SUBSYSTEM VENDOR ID = 0xABCD
[ 10.808018] em: Address Start : 0x0000000090001000
[ 10.808019] em: Address End : 0x0000000090001FFF
[ 10.808026] em: Address Length: 0x0000000000001000
[ 10.808027] em: Address Base : 0x00000000003A6000
[ 10.808033] em: PCI NUM VF before enable sriov: 0x0000000000000000
[ 10.808035] em: PCI NUM VF after enable sriov: 0x0000000000000000
[ 10.808046] em: SR-IOV CapID : 0x0000
[ 10.808048] em: SR-IOV CapVer : 0x0000
[ 10.808049] em: EXIT <-- em_probe
[ 10.811562] em: ENTER --> em_probe
[ 10.811637] pci_em 0000:04:00.3: enabling device (0000 -> 0002)
[ 10.811734] em: ====== em CONFIG SPACE ======
[ 10.811735] em: VENDOR_ID = 0xFFFF
[ 10.811750] em: DEVICE_ID = 0xFFFF
[ 10.811751] em: SUBSYSTEM_ID = 0x0011
[ 10.811765] em: SUBSYSTEM VENDOR ID = 0xABCD
[ 10.812144] em: Address Start : 0x0000000090002000
[ 10.812151] em: Address End : 0x0000000090002FFF
[ 10.812158] em: Address Length: 0x0000000000001000
[ 10.812162] em: Address Base : 0x00000000003CC000
[ 10.812172] em: PCI NUM VF before enable sriov: 0x0000000000000000
[ 10.812180] em: PCI NUM VF after enable sriov: 0x0000000000000000
[ 10.812184] em: SR-IOV CapID : 0x0000
[ 10.812185] em: SR-IOV CapVer : 0x0000
[ 10.812185] em: EXIT <-- em_probe
[ 10.812609] em: ENTER --> em_probe
[ 10.812615] pci_em 0000:04:00.4: enabling device (0000 -> 0002)
[ 10.812626] em: ====== em CONFIG SPACE ======
[ 10.812627] em: VENDOR_ID = 0xFFFF
[ 10.812628] em: DEVICE_ID = 0xFFFF
[ 10.812629] em: SUBSYSTEM_ID = 0x0011
[ 10.812630] em: SUBSYSTEM VENDOR ID = 0xABCD
[ 10.812648] em: Address Start : 0x0000000090003000
[ 10.812649] em: Address End : 0x0000000090003FFF
[ 10.812650] em: Address Length: 0x0000000000001000
[ 10.812651] em: Address Base : 0x00000000003EE000
[ 10.812652] em: PCI NUM VF before enable sriov: 0x0000000000000000
[ 10.812653] em: PCI NUM VF after enable sriov: 0x0000000000000000
[ 10.812657] em: SR-IOV CapID : 0x0000
[ 10.812658] em: SR-IOV CapVer : 0x0000
[ 10.812659] em: EXIT <-- em_probe
[ 10.812695] em: PCI NUM VF after enable sriov: 0x0000000000000004
[ 10.812698] em: SR-IOV CapID : 0x0010
[ 10.812699] em: SR-IOV CapVer : 0x0001
[ 10.812700] em: EXIT <-- em_probe
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#define em_DEV_NAME "em"
#define NR_VIRTFN 4
#define SR_IOV_CAP_BASE_ADDR 0x200
MODULE_LICENSE("GPL");
static struct pci_device_id em_ids[] = {
{PCI_DEVICE(0x1172,PCI_ANY_ID)},
{0},
};
MODULE_DEVICE_TABLE(pci, em_ids);
static struct {
/* (mmio) control registers i.e. the "register memory region" */
void __iomem *regs_base_addr;
resource_size_t regs_start;
resource_size_t regs_end;
resource_size_t regs_len;
resource_size_t regs_flags;
resource_size_t regs_sys_page_size;
u16 sriov_capid;
u16 sriov_capver;
u16 numvf;
u16 totalvf;
/* irq handling */
unsigned int irq;
} em_dev;
static u16 em_get_vendorid( struct pci_dev *pdev)
{
u16 vendorid;
pci_read_config_word( pdev, PCI_VENDOR_ID, &vendorid);
return vendorid;
}
static u16 em_get_deviceid( struct pci_dev *pdev)
{
u16 deviceid;
pci_read_config_word( pdev, PCI_DEVICE_ID, &deviceid);
return deviceid;
}
static unsigned char em_get_revision( struct pci_dev *pdev)
{
u8 revision;
pci_read_config_byte( pdev, PCI_REVISION_ID, &revision);
return revision;
}
static u16 em_get_subsystemid( struct pci_dev *pdev)
{
u16 subsystemid;
pci_read_config_word( pdev, PCI_SUBSYSTEM_ID, &subsystemid);
return subsystemid;
}
static u16 em_get_subsystemvendorid( struct pci_dev *pdev)
{
u16 subsystemvendorid;
pci_read_config_word( pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystemvendorid);
return subsystemvendorid;
}
static u16 em_get_iov_capid( struct pci_dev *pdev)
{
u16 result;
pci_read_config_word(pdev, SR_IOV_CAP_BASE_ADDR, &result);
return result;
}
static u16 em_get_iov_version( struct pci_dev *pdev)
{
u16 result;
pci_read_config_word(pdev, SR_IOV_CAP_BASE_ADDR+2, &result);
result = result & 0x000F;
return result;
}
static u16 em_get_num_vf( struct pci_dev *pdev)
{
u16 result;
pci_read_config_word(pdev, SR_IOV_CAP_BASE_ADDR+PCI_SRIOV_NUM_VF, &result);
return result;
}
static u16 em_get_total_vf( struct pci_dev *pdev)
{
u16 result;
pci_read_config_word(pdev, SR_IOV_CAP_BASE_ADDR+PCI_SRIOV_TOTAL_VF, &result);
return result;
}
static int em_probe(struct pci_dev *pdev,
const struct pci_device_id *pdev_id)
{
printk(KERN_ALERT "em: ENTER --> em_probe\n");
u16 subsystemid;
u16 subvendorid;
u16 vendorid;
u16 deviceid;
int err;
struct device *dev = &pdev->dev;
if ((err = pci_enable_device(pdev))) {
dev_err(dev, "em: pci_enable_device probe error %d for device %s\n",
err, pci_name(pdev));
return err;
}
if ((err = pci_request_regions(pdev, em_DEV_NAME)) < 0) {
dev_err(dev, "pci_request_regions error %d\n", err);
goto pci_disable;
}
subsystemid = em_get_subsystemid(pdev);
subvendorid = em_get_subsystemvendorid(pdev);
vendorid = em_get_vendorid(pdev);
deviceid = em_get_deviceid(pdev);
printk (KERN_ALERT "em: ====== em CONFIG SPACE ======\n");
printk (KERN_ALERT "em: VENDOR_ID = 0x%04X\n", vendorid);
printk (KERN_ALERT "em: DEVICE_ID = 0x%04X\n", deviceid);
printk (KERN_ALERT "em: SUBSYSTEM_ID = 0x%04X\n", subsystemid);
printk (KERN_ALERT "em: SUBSYSTEM VENDOR ID = 0x%04X\n", subvendorid);
/* bar0: control registers */
em_dev.regs_start = pci_resource_start(pdev, 0);
em_dev.regs_end = pci_resource_end(pdev, 0);
em_dev.regs_len = pci_resource_len(pdev, 0);
em_dev.regs_base_addr = pci_iomap(pdev, 0, 0x100);
if (!em_dev.regs_base_addr) {
dev_err(dev, "em: cannot ioremap registers of size %lu\n",
(unsigned long)em_dev.regs_len);
goto region_release;
}
printk (KERN_ALERT "em: Address Start : 0x%016X\n", em_dev.regs_start);
printk (KERN_ALERT "em: Address End : 0x%016X\n", em_dev.regs_end);
printk (KERN_ALERT "em: Address Length: 0x%016X\n", em_dev.regs_len);
printk (KERN_ALERT "em: Address Base : 0x%016X\n", em_dev.regs_base_addr);
em_dev.numvf = pci_num_vf(pdev);
printk (KERN_ALERT "em: PCI NUM VF before enable sriov: 0x%016X\n", em_dev.numvf);
pci_enable_sriov(pdev, NR_VIRTFN);
em_dev.numvf = pci_num_vf(pdev);
printk (KERN_ALERT "em: PCI NUM VF after enable sriov: 0x%016X\n", em_dev.numvf);
em_dev.sriov_capid = em_get_iov_capid(pdev);
em_dev.sriov_capver = em_get_iov_version(pdev);
em_dev.totalvf = em_get_total_vf(pdev);
printk (KERN_ALERT "em: SR-IOV CapID : 0x%04X\n", em_dev.sriov_capid);
printk (KERN_ALERT "em: SR-IOV CapVer : 0x%04X\n", em_dev.sriov_capver);
printk(KERN_ALERT "em: EXIT <-- em_probe\n");
return 0;
map_release:
pci_iounmap(pdev, em_dev.regs_base_addr);
region_release:
pci_release_regions(pdev);
pci_disable:
pci_disable_device(pdev);
return -EBUSY;
}
// Validate that the error path in em_probe is modeled after this
// remove function. Everything needs to be backed out in order and cleanly
// or we leave reserved memory in the kernel
static void em_remove(struct pci_dev *pdev)
{
pci_enable_sriov(pdev, NR_VIRTFN);
pci_iounmap(pdev, em_dev.regs_base_addr);
pci_release_regions(pdev);
pci_disable_device(pdev);
}
static int em_sriov_configure(struct pci_dev *dev, int numvfs)
{
printk(KERN_ALERT "em: ENTER --> em_sriov_configure\n");
if (numvfs > 0) {
printk(KERN_ALERT "em: NUMVFS > 0 em_sriov_configure\n");
pci_enable_sriov(dev,numvfs);
return numvfs;
}
if (numvfs == 0) {
printk(KERN_ALERT "em: NUMVFS == 0 em_sriov_configure\n");
pci_disable_sriov(dev);
return 0;
}
printk(KERN_ALERT "em: EXIT <-- em_sriov_configure\n");
}
static struct pci_driver em_pci_driver = {
.name = "pci_em",
.id_table = em_ids,
.probe = em_probe,
.remove = em_remove,
.sriov_configure = em_sriov_configure,
};
static int em_init(void)
{
int err = -ENOMEM;
printk(KERN_ALERT "em: em initialize\n");
/* register pci device driver */
if ((err = pci_register_driver(&em_pci_driver)) < 0) {
pr_err("em: pci_register_driver error\n");
goto exit;
}
return 0;
exit:
return err;
}
static void em_exit(void)
{
printk(KERN_ALERT "em: em exit\n");
pci_unregister_driver(&em_pci_driver);
}
module_init(em_init);
module_exit(em_exit);
答案 0 :(得分:1)
确定此特定探测实例是针对PF还是VF的“正确”方法是什么?
您可以使用这些简单的条件
if (pdev->is_physfn) { .... }
if (pdev->is_virtfn) { .... }