pcie设备驱动无法工作排查

c 复制代码
pci_register_driver() (include/linux/pci.h)
  -->pci_register_driver()  (drivers/pci/pci-driver.c)
    -->driver_register()  (drivers/base/driver.c)
      -->bus_add_driver (drivers/base/driver.c)
        -->driver_attach() (drivers/base/dd.c)
          -->__driver_attach()  (drivers/base/dd.c)
            -->driver_match_device()
                pci_bus_match

driver_match_device()
  -->pci_bus_match  (drivers/pci/pci-driver.c)
    -->pci_match_device() (drivers/pci/pci-driver.c)
      -->pci_match_id() (drivers/pci/pci-driver.c)
        -->pci_match_one_device (drivers/pci/pci.h)     

整个驱动的注册后触发使能的过程如上。这里核心位于bus_for_each_dev

c 复制代码
int bus_for_each_dev(struct bus_type *bus, struct device *start,
		     void *data, int (*fn)(struct device *, void *))
{
	struct klist_iter i;
	struct device *dev;
	int error = 0;

	if (!bus || !bus->p)
		return -EINVAL;

	klist_iter_init_node(&bus->p->klist_devices, &i,
			     (start ? &start->p->knode_bus : NULL));
	while (!error && (dev = next_device(&i)))
		error = fn(dev, data);
	klist_iter_exit(&i);
	return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);
c 复制代码
static int pci_bus_match(struct device *dev, struct device_driver *drv)
{
	struct pci_dev *pci_dev = to_pci_dev(dev);
	struct pci_driver *pci_drv;
	const struct pci_device_id *found_id;

	if (!pci_dev->match_driver)
		return 0;

	pci_drv = to_pci_driver(drv);
	found_id = pci_match_device(pci_drv, pci_dev);
	if (found_id)
		return 1;

	return 0;
}

static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
						    struct pci_dev *dev)
{
	struct pci_dynid *dynid;
	const struct pci_device_id *found_id = NULL;

	/* When driver_override is set, only bind to the matching driver */
	if (dev->driver_override && strcmp(dev->driver_override, drv->name))
		return NULL;

	/* Look at the dynamic ids first, before the static ones */
	spin_lock(&drv->dynids.lock);
	list_for_each_entry(dynid, &drv->dynids.list, node) {
		if (pci_match_one_device(&dynid->id, dev)) {
			found_id = &dynid->id;
			break;
		}
	}
	spin_unlock(&drv->dynids.lock);

	if (!found_id)
		found_id = pci_match_id(drv->id_table, dev);

	/* driver_override will always match, send a dummy id */
	if (!found_id && dev->driver_override)
		found_id = &pci_device_id_any;

	return found_id;
}

为了查看为什么驱动匹配不到设备,我写了如下测试代码。当然必须重构部分数据结构,因为没有导出。

c 复制代码
int test_bus_for_each_dev( void )
{
	struct klist_iter i;
	struct device *dev;
	int error = 0;
    struct device *start = NULL;

    struct bus_type *bus = &pci_bus_type;

    printk("pci_bus_type %lx \n", pci_bus_type);

	klist_iter_init_node(&bus->p->klist_devices, &i,
			     ( NULL));
	while (!error && (dev = next_device(&i))){
        struct pci_dev *pci_dev = to_pci_dev(dev);
        printk("pci_dev %x %x match driver %x \n", 
            pci_dev->vendor, pci_dev->device, pci_dev->match_driver);
    }
	klist_iter_exit(&i);
	return error;
}

最后发现pci_dev->match_driver没有使能。

c 复制代码
struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops,
					void *sysdata)
{
	LIST_HEAD(resources);
	struct pci_bus *b;

	pci_add_resource(&resources, &ioport_resource);
	pci_add_resource(&resources, &iomem_resource);
	pci_add_resource(&resources, &busn_resource);
	b = pci_create_root_bus(NULL, bus, ops, sysdata, &resources);
	if (b) {
		pci_scan_child_bus(b);
	} else {
		pci_free_resource_list(&resources);
	}
	return b;
}
EXPORT_SYMBOL(pci_scan_bus);


struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
		struct pci_ops *ops, void *sysdata, struct list_head *resources)
{
	int error;
	struct pci_host_bridge *bridge;

	bridge = pci_alloc_host_bridge(0);
	if (!bridge)
		return NULL;

	bridge->dev.parent = parent;

	list_splice_init(resources, &bridge->windows);
	bridge->sysdata = sysdata;
	bridge->busnr = bus;
	bridge->ops = ops;

	error = pci_register_host_bridge(bridge);
	if (error < 0)
		goto err_out;

	return bridge->bus;

err_out:
	put_device(&bridge->dev);
	return NULL;
}
EXPORT_SYMBOL_GPL(pci_create_root_bus);

总线设备其实对于总线驱动来看,仅仅是配置空间和bar空间。只要过滤插槽号和func就能过滤任意设别,或者虚拟一个设备出来。

相关推荐
yuki_uix10 小时前
虚拟 DOM 与 Diff 算法——React 性能优化的底层逻辑
前端·react.js·面试
yuki_uix10 小时前
从输入 URL 到页面显示——浏览器工作原理全解析
前端·面试
weixin_4080996710 小时前
【完整教程】天诺脚本如何调用 OCR 文字识别 API?自动识别屏幕文字实战(附代码)
前端·人工智能·后端·ocr·api·天诺脚本·自动识别文字脚本
吴声子夜歌10 小时前
ES6——Generator函数详解
前端·javascript·es6
吴声子夜歌10 小时前
ES6——Set和Map详解
前端·javascript·es6
不是书本的小明11 小时前
K8S应用优化方向
网络·容器·kubernetes
程序猿编码11 小时前
一个授予普通进程ROOT权限的Linux内核级后门:原理与实现深度解析
linux·运维·服务器·内核·root权限
码喽7号11 小时前
vue学习四:Axios网络请求
前端·vue.js·学习
小夏子_riotous11 小时前
openstack的使用——9. 密钥管理服务Barbican
linux·运维·服务器·系统架构·centos·云计算·openstack
~plus~12 小时前
.NET 8 C# 委托与事件实战教程
网络·c#·.net·.net 8·委托与事件·c#进阶