pci_stub的使用方法

先看一下pci_stub 是如何使用的,通过下面这段code 可以将0000:00:19.0的driver和device 分来
* # echo "8086 10f5" > /sys/bus/pci/drivers/pci-stub/new_id
 * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind
 * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/pci-stub/bind
 * # ls -l /sys/bus/pci/devices/0000:00:19.0/driver
 * .../0000:00:19.0/driver -> ../../../bus/pci/drivers/pci-stub
从这里能看出如果往driver的unbind写0000:00:19.0的话,就可以将device和driver 分开。这样0000:00:19.0 对应的的driver就能和pci_stub 绑定而和0000:00:19.0对应的硬件解帮
使用PCI Stub ,能够将这个pci设备跟目前绑定的驱动分离,暂时由PCI Stub driver接管,最后交给虚拟机。
static int pci_stub_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
    dev_info(&dev->dev, "claimed by stub\n");
    return 0;
}

static struct pci_driver stub_driver = {
    .name        = "pci-stub",
    .id_table    = NULL,    /* only dynamic id's */
    .probe        = pci_stub_probe,
};

static int __init pci_stub_init(void)
{
    char *p, *id;
    int rc;
//注册pci_stub 对应的driver
    rc = pci_register_driver(&stub_driver);
    if (rc)
        return rc;

    /* no ids passed actually */
    if (ids[0] == '\0')
        return 0;

    /* add ids specified in the module parameter */
    p = ids;
    while ((id = strsep(&p, ","))) {
        unsigned int vendor, device, subvendor = PCI_ANY_ID,
            subdevice = PCI_ANY_ID, class = 0, class_mask = 0;
        int fields;

        if (!strlen(id))
            continue;
//从ids中拿到vendor,device等
        fields = sscanf(id, "%x:%x:%x:%x:%x:%x",
                &vendor, &device, &subvendor, &subdevice,
                &class, &class_mask);

        if (fields < 2) {
            printk(KERN_WARNING
                   "pci-stub: invalid id string \"%s\"\n", id);
            continue;
        }

        printk(KERN_INFO
               "pci-stub: add %04X:%04X sub=%04X:%04X cls=%08X/%08X\n",
               vendor, device, subvendor, subdevice, class, class_mask);

        rc = pci_add_dynid(&stub_driver, vendor, device,
                   subvendor, subdevice, class, class_mask, 0);
        if (rc)
            printk(KERN_WARNING
                   "pci-stub: failed to add dynamic id (%d)\n", rc);
    }

    return 0;
}

从pci_stub的看如果把pci_stub build 成ko的话,就可以在insmod ko的时候通过ids制定参数。而一般我们是把pci_stub buildin的,这样ids就是NULL。这时候while循环的条件while ((id = strsep(&p, ","))) 就不成立,就直接可以退出了,这样pci_stub 的probe函数就只注册了stub_driver。
这时候就要通过echo "8086 10f5" > /sys/bus/pci/drivers/pci-stub/new_id 来写如id。
而这个new_id是在pci-driver中实现的
static ssize_t store_new_id(struct device_driver *driver, const char *buf,
                size_t count)
{
    struct pci_driver *pdrv = to_pci_driver(driver);
    const struct pci_device_id *ids = pdrv->id_table;
    __u32 vendor, device, subvendor = PCI_ANY_ID,
        subdevice = PCI_ANY_ID, class = 0, class_mask = 0;
    unsigned long driver_data = 0;
    int fields = 0;
    int retval = 0;
//从/sys/bus/pci/drivers/pci-stub/new_id 中parse出来vendor/device 等变量,本例中"8086 10f5",对应vendor和//device

    fields = sscanf(buf, "%x %x %x %x %x %x %lx",
            &vendor, &device, &subvendor, &subdevice,
            &class, &class_mask, &driver_data);
    if (fields < 2)
        return -EINVAL;
//field 不等于7 说明没有指定特定的pci设备,需要调用pci_match_id 来看哪个pci设备最匹配.
    if (fields != 7) {
        struct pci_dev *pdev = kzalloc(sizeof(*pdev), GFP_KERNEL);
        if (!pdev)
            return -ENOMEM;

        pdev->vendor = vendor;
        pdev->device = device;
        pdev->subsystem_vendor = subvendor;
        pdev->subsystem_device = subdevice;
        pdev->class = class;

        if (pci_match_id(pdrv->id_table, pdev))
            retval = -EEXIST;

        kfree(pdev);

        if (retval)
            return retval;
    }

    /* Only accept driver_data values that match an existing id_table
       entry */
    if (ids) {
        retval = -EINVAL;
        while (ids->vendor || ids->subvendor || ids->class_mask) {
            if (driver_data == ids->driver_data) {
                retval = 0;
                break;
            }
            ids++;
        }
        if (retval)    /* No match */
            return retval;
    }
// 将8086 10f5 这个pci设备和pci_stub 绑定
    retval = pci_add_dynid(pdrv, vendor, device, subvendor, subdevice,
                   class, class_mask, driver_data);
    if (retval)
        return retval;
    return count;
}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
总结一下:每个pci 设备都有new_id 这个属性,所以每个pci设备都可以在解帮后再和pci_stub 帮订.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值