VirtIO实现原理之VirtIO-PCI(4)

132 篇文章 41 订阅 ¥49.90 ¥99.00

接前一篇文章:VirtIO实现原理之VirtIO-PCI(3)

本文内容参考:

VirtIO实现原理——PCI基础_virtio-pci-CSDN博客

QEMU源码全解析 —— virtio(3)_qemu virtio block bus-CSDN博客

特此致谢!

一、VirtIO-PCI初始化

virtio设备首先需要创建一个PCI设备,叫作virtio PCI代理设备,这个代理设备挂到PCI总线上

接着,virtio代理设备再创建一条virtio总线,这样virtio设备就可以挂到这条virtio总线上了

1. PCI初始化

(1)枚举

本回继续解析发生在pci_subsys_init()中的枚举过程。上一回解析了整体流程中的开始部分:

027666fca7ef49318e8929690b6695c1.png

上一回给出了pci_legacy_init函数的代码。为了便于理解和回顾,再次贴出其代码,在arch/x86/pci/legacy.c中,如下:

int __init pci_legacy_init(void)
{
	if (!raw_pci_ops)
		return 1;

	pr_info("PCI: Probing PCI hardware\n");
	pcibios_scan_root(0);
	return 0;
}

当前来到了流程中的以下位置:

abb09488ca744ebc92efd48b76235bab.png

pci_legacy_init函数很简单,主要是调用了pcibios_scan_root函数。不过在调用之前,pci_legacy_init函数一开始先判断了raw_pci_ops是否为空。在内核代码中搜索raw_pci_ops,会看到有几处其赋值的地方,这里一一列举出来:

  • arch/x86/pci/ce4100.c的ce4100_pci_init函数中

代码如下:

static const struct pci_raw_ops ce4100_pci_conf = {
	.read	= ce4100_conf_read,
	.write	= ce4100_conf_write,
};

int __init ce4100_pci_init(void)
{
	init_sim_regs();
	raw_pci_ops = &ce4100_pci_conf;
	/* Indicate caller that it should invoke pci_legacy_init() */
	return 1;
}
  • arch/x86/pci/direct.c的pci_direct_init函数中

代码如下:

void __init pci_direct_init(int type)
{
	if (type == 0)
		return;
	printk(KERN_INFO "PCI: Using configuration type %d for base access\n",
		 type);
	if (type == 1) {
		raw_pci_ops = &pci_direct_conf1;
		if (raw_pci_ext_ops)
			return;
		if (!(pci_probe & PCI_HAS_IO_ECS))
			return;
		printk(KERN_INFO "PCI: Using configuration type 1 "
		       "for extended access\n");
		raw_pci_ext_ops = &pci_direct_conf1;
		return;
	}
	raw_pci_ops = &pci_direct_conf2;
}
  • arch/x86/pci/direct.c的pci_direct_probe函数中

代码如下:

int __init pci_direct_probe(void)
{
	if ((pci_probe & PCI_PROBE_CONF1) == 0)
		goto type2;
	if (!request_region(0xCF8, 8, "PCI conf1"))
		goto type2;

	if (pci_check_type1()) {
		raw_pci_ops = &pci_direct_conf1;
		port_cf9_safe = true;
		return 1;
	}
	release_region(0xCF8, 8);

 type2:
	if ((pci_probe & PCI_PROBE_CONF2) == 0)
		return 0;
	if (!request_region(0xCF8, 4, "PCI conf2"))
		return 0;
	if (!request_region(0xC000, 0x1000, "PCI conf2"))
		goto fail2;

	if (pci_check_type2()) {
		raw_pci_ops = &pci_direct_conf2;
		port_cf9_safe = true;
		return 2;
	}

	release_region(0xC000, 0x1000);
 fail2:
	release_region(0xCF8, 4);
	return 0;
}
  • arch/x86/pci/numachip.c的pci_numachip_init函数中

代码如下:

static const struct pci_raw_ops pci_mmcfg_numachip = {
	.read = pci_mmcfg_read_numachip,
	.write = pci_mmcfg_write_numachip,
};

int __init pci_numachip_init(void)
{
	int ret = 0;
	u32 val;

	/* For remote I/O, restrict bus 0 access to the actual number of AMD
	   Northbridges, which starts at device number 0x18 */
	ret = raw_pci_read(0, 0, PCI_DEVFN(0x18, 0), 0x60, sizeof(val), &val);
	if (ret)
		goto out;

	/* HyperTransport fabric size in bits 6:4 */
	limit = PCI_DEVFN(0x18 + ((val >> 4) & 7) + 1, 0);

	/* Use NumaChip PCI accessors for non-extended and extended access */
	raw_pci_ops = raw_pci_ext_ops = &pci_mmcfg_numachip;
out:
	return ret;
}
  • arch/x86/pci/olpc.c的pci_olpc_init函数中

代码如下:

static const struct pci_raw_ops pci_olpc_conf = {
	.read =	pci_olpc_read,
	.write = pci_olpc_write,
};

int __init pci_olpc_init(void)
{
	printk(KERN_INFO "PCI: Using configuration type OLPC XO-1\n");
	raw_pci_ops = &pci_olpc_conf;
	is_lx = is_geode_lx();
	return 0;
}
  • arch/x86/pci/pcbios.c的pci_pcbios_init函数中

代码如下:

void __init pci_pcbios_init(void)
{
	if ((pci_probe & PCI_PROBE_BIOS) 
		&& ((raw_pci_ops = pci_find_bios()))) {
		pci_bios_present = 1;
	}
}

下一回正式对于pcibios_scan_root函数进行深入解析。

评论
成就一亿技术人!
拼手气红包 6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠  查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额 3.43前往充值 >
需支付: 10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝天居士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付: ¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值