Skip to content

Conversation

@alyssais
Copy link
Member

While non-Intel CPU architectures don't have a special concept of IO address space, support for PCI I/O regions is still needed to be able to handle PCI devices that use them.

With this change, I'm able to pass through an e1000e device from QEMU to a cloud-hypervisor VM on aarch64 and use it in the cloud-hypervisor guest. Previously, it would hit the unimplemented!().


I'd appreciate some checking here, as while this does fix a problem, I've been learning about PCI as I've gone. In particular:

  • Is starting at address 0 in the MMIO space okay on other architectures?
  • When I try to pass through a virtio-net device instead of e1000e, the guest kernel ends up stuck in rtnl_lock. I'm not sure what's going wrong there (or if it's a Cloud Hypervisor problem, or a problem with something else).

Fixes: def98fa ("vmm, vm-allocator: Introduce an allocator for platform devices")
Signed-off-by: Alyssa Ross <[email protected]>
@rbradford
Copy link
Member

The ARM failure is because we're in a kernel transition.

While non-Intel CPU architectures don't have a special concept of IO
address space, support for PCI I/O regions is still needed to be able
to handle PCI devices that use them.

With this change, I'm able to pass through an e1000e device from QEMU
to a cloud-hypervisor VM on aarch64 and use it in the cloud-hypervisor
guest.  Previously, it would hit the unimplemented!().

Signed-off-by: Alyssa Ross <[email protected]>
@rbradford
Copy link
Member

Thanks @alyssais - your changes are fine and correct. I'm a little bit perplexed how this works in practice but I found this quote:

I/O space can be accessed differently on different platforms. Processors with special I/O instructions, like the Intel processor family, access the I/O space with in and out instructions. Machines without special I/O instructions will map to the address locations corresponding to the PCI host bridge in the host address domain. When the processor accesses the memory-mapped addresses, an I/O request will be sent to the PCI host bridge, which then translates the addresses into I/O cycles and puts them on the PCI bus.

I guess that because these are VFIO devices the real host bridge on the system takes care of all this.

Did you verify that I/O port BAR on that particular PCI device was required and working (e.g. with like a print statement in the QEMU code for the I/O bar region)

@rbradford
Copy link
Member

@alyssais
Copy link
Member Author

I'll have a look.

@alyssais
Copy link
Member Author

I don't see those being called. It does have a non-zero size set though — that's how I ran into this.

@rbradford
Copy link
Member

I don't see those being called. It does have a non-zero size set though — that's how I ran into this.

The Linux driver only uses I/O port for certain device types:

	/* do not allocate ioport bars when not needed */
	need_ioport = e1000_is_need_ioport(pdev);
	if (need_ioport) {
		bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
		err = pci_enable_device(pdev);
	} else {
		bars = pci_select_bars(pdev, IORESOURCE_MEM);
		err = pci_enable_device_mem(pdev);
	}

QEMU advertises:

#define E1000_DEV_ID_82574L 0x10D3

Which isn't in the list:

static int e1000_is_need_ioport(struct pci_dev *pdev)
{
	switch (pdev->device) {
	case E1000_DEV_ID_82540EM:
	case E1000_DEV_ID_82540EM_LOM:
	case E1000_DEV_ID_82540EP:
	case E1000_DEV_ID_82540EP_LOM:
	case E1000_DEV_ID_82540EP_LP:
	case E1000_DEV_ID_82541EI:
	case E1000_DEV_ID_82541EI_MOBILE:
	case E1000_DEV_ID_82541ER:
	case E1000_DEV_ID_82541ER_LOM:
	case E1000_DEV_ID_82541GI:
	case E1000_DEV_ID_82541GI_LF:
	case E1000_DEV_ID_82541GI_MOBILE:
	case E1000_DEV_ID_82544EI_COPPER:
	case E1000_DEV_ID_82544EI_FIBER:
	case E1000_DEV_ID_82544GC_COPPER:
	case E1000_DEV_ID_82544GC_LOM:
	case E1000_DEV_ID_82545EM_COPPER:
	case E1000_DEV_ID_82545EM_FIBER:
	case E1000_DEV_ID_82546EB_COPPER:
	case E1000_DEV_ID_82546EB_FIBER:
	case E1000_DEV_ID_82546EB_QUAD_COPPER:
		return true;
	default:
		return false;
	}
}

What about trying ne2k-pci ? That seems to be only I/O bar based!

@alyssais
Copy link
Member Author

On aarch64 in the cloud-hypervisor guest I get:

ne2k-pci 0000:00:08.0: of_irq_parse_pci: failed with rc=-22

On x86_64, it doesn't work either, but for a different reason. This is printed repeatedly:

ne2k-pci 0000:00:08.0 eth0: NETDEV WATCHDOG: CPU: 0: transmit queue 0 timed out 892 ms

It does work on the cloud-hypervisor host (the QEMU guest).

@rbradford
Copy link
Member

On aarch64 in the cloud-hypervisor guest I get:

ne2k-pci 0000:00:08.0: of_irq_parse_pci: failed with rc=-22

On x86_64, it doesn't work either, but for a different reason. This is printed repeatedly:

ne2k-pci 0000:00:08.0 eth0: NETDEV WATCHDOG: CPU: 0: transmit queue 0 timed out 892 ms

It does work on the cloud-hypervisor host (the QEMU guest).

Ah - I can see it uses INTx - rather than MSI!

Copy link
Member

@rbradford rbradford left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to go ahead since it does resolve the use case where a device has I/O bars but doesn't need them for operation.

@rbradford rbradford enabled auto-merge December 14, 2024 13:09
@alyssais
Copy link
Member Author

Because I was already testing it — if I replace Cloud Hypervisor with QEMU, it does work on aarch64.

@rbradford
Copy link
Member

Because I was already testing it — if I replace Cloud Hypervisor with QEMU, it does work on aarch64.

It's probably because it requires INTx interrupts - not something we support (or maybe we did add support but weren't able to test it regularly!)

@rbradford rbradford added this pull request to the merge queue Dec 14, 2024
Merged via the queue into cloud-hypervisor:main with commit 50bac16 Dec 14, 2024
37 of 38 checks passed
@alyssais alyssais deleted the io branch December 14, 2024 22:59
shymega pushed a commit to shymega/spectrum-os that referenced this pull request Feb 9, 2025
The default is virtio-net on aarch64.  virtio-net isn't very
realistic, and it also causes guest kernels to get stuck in a lock
when it's passed through.

Link: cloud-hypervisor/cloud-hypervisor#6871
Signed-off-by: Alyssa Ross <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants