mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
um: add PCI over virtio emulation driver
To support testing of PCI/PCIe drivers in UML, add a PCI bus support driver. This driver uses virtio, which in UML is really just vhost-user, to talk to devices, and adds the devices to the virtual PCI bus in the system. Since virtio already allows DMA/bus mastering this really isn't all that hard, of course we need the logic_iomem infrastructure that was added by a previous patch. The protocol to talk to the device is has a few fairly simple messages for reading to/writing from config and IO spaces, and messages for the device to send the various interrupts (INT#, MSI/MSI-X and while suspended PME#). Note that currently no offical virtio device ID is assigned for this protocol, as a consequence this patch requires defining it in the Kconfig, with a default that makes the driver refuse to work at all. Finally, in order to add support for MSI/MSI-X interrupts, some small changes are needed in the UML IRQ code, it needs to have more interrupts, changing NR_IRQS from 64 to 128 if this driver is enabled, but not actually use them for anything so that the generic IRQ domain/MSI infrastructure can allocate IRQ numbers. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
committed by
Richard Weinberger
parent
a5ab7c8467
commit
68f5d3f3b6
@@ -15,7 +15,7 @@ config UML
|
||||
select HAVE_FUTEX_CMPXCHG if FUTEX
|
||||
select HAVE_DEBUG_KMEMLEAK
|
||||
select HAVE_DEBUG_BUGVERBOSE
|
||||
select NO_DMA
|
||||
select NO_DMA if !UML_DMA_EMULATION
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_CPU_DEVICES
|
||||
select HAVE_GCC_PLUGINS
|
||||
@@ -26,10 +26,21 @@ config MMU
|
||||
bool
|
||||
default y
|
||||
|
||||
config UML_DMA_EMULATION
|
||||
bool
|
||||
|
||||
config NO_IOMEM
|
||||
bool "disable IOMEM" if EXPERT
|
||||
depends on !INDIRECT_IOMEM
|
||||
default y
|
||||
|
||||
config UML_IOMEM_EMULATION
|
||||
bool
|
||||
select INDIRECT_IOMEM
|
||||
select GENERIC_PCI_IOMAP
|
||||
select GENERIC_IOMAP
|
||||
select NO_GENERIC_PCI_IOPORT_MAP
|
||||
|
||||
config NO_IOPORT_MAP
|
||||
def_bool y
|
||||
|
||||
|
||||
@@ -357,3 +357,23 @@ config UML_RTC
|
||||
rtcwake, especially in time-travel mode. This driver enables that
|
||||
by providing a fake RTC clock that causes a wakeup at the right
|
||||
time.
|
||||
|
||||
config UML_PCI_OVER_VIRTIO
|
||||
bool "Enable PCI over VIRTIO device simulation"
|
||||
# in theory, just VIRTIO is enough, but that causes recursion
|
||||
depends on VIRTIO_UML
|
||||
select FORCE_PCI
|
||||
select UML_IOMEM_EMULATION
|
||||
select UML_DMA_EMULATION
|
||||
select PCI_MSI
|
||||
select PCI_MSI_IRQ_DOMAIN
|
||||
select PCI_LOCKLESS_CONFIG
|
||||
|
||||
config UML_PCI_OVER_VIRTIO_DEVICE_ID
|
||||
int "set the virtio device ID for PCI emulation"
|
||||
default -1
|
||||
depends on UML_PCI_OVER_VIRTIO
|
||||
help
|
||||
There's no official device ID assigned (yet), set the one you
|
||||
wish to use for experimentation here. The default of -1 is
|
||||
not valid and will cause the driver to fail at probe.
|
||||
|
||||
@@ -64,6 +64,7 @@ obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
|
||||
obj-$(CONFIG_UML_RANDOM) += random.o
|
||||
obj-$(CONFIG_VIRTIO_UML) += virtio_uml.o
|
||||
obj-$(CONFIG_UML_RTC) += rtc.o
|
||||
obj-$(CONFIG_UML_PCI_OVER_VIRTIO) += virt-pci.o
|
||||
|
||||
# pcap_user.o must be added explicitly.
|
||||
USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o
|
||||
|
||||
885
arch/um/drivers/virt-pci.c
Normal file
885
arch/um/drivers/virt-pci.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,6 @@ generic-y += mcs_spinlock.h
|
||||
generic-y += mmiowb.h
|
||||
generic-y += module.lds.h
|
||||
generic-y += param.h
|
||||
generic-y += pci.h
|
||||
generic-y += percpu.h
|
||||
generic-y += preempt.h
|
||||
generic-y += softirq_stack.h
|
||||
|
||||
@@ -3,16 +3,23 @@
|
||||
#define _ASM_UM_IO_H
|
||||
#include <linux/types.h>
|
||||
|
||||
/* get emulated iomem (if desired) */
|
||||
#include <asm-generic/logic_io.h>
|
||||
|
||||
#ifndef ioremap
|
||||
#define ioremap ioremap
|
||||
static inline void __iomem *ioremap(phys_addr_t offset, size_t size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* ioremap */
|
||||
|
||||
#ifndef iounmap
|
||||
#define iounmap iounmap
|
||||
static inline void iounmap(void __iomem *addr)
|
||||
{
|
||||
}
|
||||
#endif /* iounmap */
|
||||
|
||||
#include <asm-generic/io.h>
|
||||
|
||||
|
||||
@@ -31,7 +31,13 @@
|
||||
|
||||
#endif
|
||||
|
||||
#define NR_IRQS 64
|
||||
#define UM_LAST_SIGNAL_IRQ 64
|
||||
/* If we have (simulated) PCI MSI, allow 64 more interrupt numbers for it */
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
#define NR_IRQS (UM_LAST_SIGNAL_IRQ + 64)
|
||||
#else
|
||||
#define NR_IRQS UM_LAST_SIGNAL_IRQ
|
||||
#endif /* CONFIG_PCI_MSI */
|
||||
|
||||
#include <asm-generic/irq.h>
|
||||
#endif
|
||||
|
||||
1
arch/um/include/asm/msi.h
Normal file
1
arch/um/include/asm/msi.h
Normal file
@@ -0,0 +1 @@
|
||||
#include <asm-generic/msi.h>
|
||||
39
arch/um/include/asm/pci.h
Normal file
39
arch/um/include/asm/pci.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef __ASM_UM_PCI_H
|
||||
#define __ASM_UM_PCI_H
|
||||
#include <linux/types.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define PCIBIOS_MIN_IO 0
|
||||
#define PCIBIOS_MIN_MEM 0
|
||||
|
||||
#define pcibios_assign_all_busses() 1
|
||||
|
||||
extern int isa_dma_bridge_buggy;
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
|
||||
{
|
||||
/* no legacy IRQs */
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI_DOMAINS
|
||||
static inline int pci_proc_domain(struct pci_bus *bus)
|
||||
{
|
||||
/* always show the domain in /proc */
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
|
||||
/*
|
||||
* This is a bit of an annoying hack, and it assumes we only have
|
||||
* the virt-pci (if anything). Which is true, but still.
|
||||
*/
|
||||
void *pci_root_bus_fwnode(struct pci_bus *bus);
|
||||
#define pci_root_bus_fwnode pci_root_bus_fwnode
|
||||
#endif
|
||||
|
||||
#endif /* __ASM_UM_PCI_H */
|
||||
@@ -23,6 +23,7 @@ obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
|
||||
obj-$(CONFIG_GPROF) += gprof_syms.o
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||
obj-$(CONFIG_GENERIC_PCI_IOMAP) += ioport.o
|
||||
|
||||
USER_OBJS := config.o
|
||||
|
||||
|
||||
13
arch/um/kernel/ioport.c
Normal file
13
arch/um/kernel/ioport.c
Normal file
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2021 Intel Corporation
|
||||
* Author: Johannes Berg <johannes@sipsolutions.net>
|
||||
*/
|
||||
#include <asm/iomap.h>
|
||||
#include <asm-generic/pci_iomap.h>
|
||||
|
||||
void __iomem *__pci_ioport_map(struct pci_dev *dev, unsigned long port,
|
||||
unsigned int nr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ struct irq_entry {
|
||||
|
||||
static DEFINE_SPINLOCK(irq_lock);
|
||||
static LIST_HEAD(active_fds);
|
||||
static DECLARE_BITMAP(irqs_allocated, NR_IRQS);
|
||||
static DECLARE_BITMAP(irqs_allocated, UM_LAST_SIGNAL_IRQ);
|
||||
static bool irqs_suspended;
|
||||
|
||||
static void irq_io_loop(struct irq_reg *irq, struct uml_pt_regs *regs)
|
||||
@@ -419,7 +419,8 @@ unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)
|
||||
|
||||
void um_free_irq(int irq, void *dev)
|
||||
{
|
||||
if (WARN(irq < 0 || irq > NR_IRQS, "freeing invalid irq %d", irq))
|
||||
if (WARN(irq < 0 || irq > UM_LAST_SIGNAL_IRQ,
|
||||
"freeing invalid irq %d", irq))
|
||||
return;
|
||||
|
||||
free_irq_by_irq_and_dev(irq, dev);
|
||||
@@ -648,7 +649,7 @@ void __init init_IRQ(void)
|
||||
|
||||
irq_set_chip_and_handler(TIMER_IRQ, &alarm_irq_type, handle_edge_irq);
|
||||
|
||||
for (i = 1; i < NR_IRQS; i++)
|
||||
for (i = 1; i < UM_LAST_SIGNAL_IRQ; i++)
|
||||
irq_set_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
|
||||
/* Initialize EPOLL Loop */
|
||||
os_setup_epoll();
|
||||
|
||||
64
include/uapi/linux/virtio_pcidev.h
Normal file
64
include/uapi/linux/virtio_pcidev.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/*
|
||||
* Copyright (C) 2021 Intel Corporation
|
||||
* Author: Johannes Berg <johannes@sipsolutions.net>
|
||||
*/
|
||||
#ifndef _UAPI_LINUX_VIRTIO_PCIDEV_H
|
||||
#define _UAPI_LINUX_VIRTIO_PCIDEV_H
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* enum virtio_pcidev_ops - virtual PCI device operations
|
||||
* @VIRTIO_PCIDEV_OP_CFG_READ: read config space, size is 1, 2, 4 or 8;
|
||||
* the @data field should be filled in by the device (in little endian).
|
||||
* @VIRTIO_PCIDEV_OP_CFG_WRITE: write config space, size is 1, 2, 4 or 8;
|
||||
* the @data field contains the data to write (in little endian).
|
||||
* @VIRTIO_PCIDEV_OP_BAR_READ: read BAR mem/pio, size can be variable;
|
||||
* the @data field should be filled in by the device (in little endian).
|
||||
* @VIRTIO_PCIDEV_OP_BAR_WRITE: write BAR mem/pio, size can be variable;
|
||||
* the @data field contains the data to write (in little endian).
|
||||
* @VIRTIO_PCIDEV_OP_MMIO_MEMSET: memset MMIO, size is variable but
|
||||
* the @data field only has one byte (unlike @VIRTIO_PCIDEV_OP_MMIO_WRITE)
|
||||
* @VIRTIO_PCIDEV_OP_INT: legacy INTx# pin interrupt, the addr field is 1-4 for
|
||||
* the number
|
||||
* @VIRTIO_PCIDEV_OP_MSI: MSI(-X) interrupt, this message basically transports
|
||||
* the 16- or 32-bit write that would otherwise be done into memory,
|
||||
* analogous to the write messages (@VIRTIO_PCIDEV_OP_MMIO_WRITE) above
|
||||
* @VIRTIO_PCIDEV_OP_PME: Dummy message whose content is ignored (and should be
|
||||
* all zeroes) to signal the PME# pin.
|
||||
*/
|
||||
enum virtio_pcidev_ops {
|
||||
VIRTIO_PCIDEV_OP_RESERVED = 0,
|
||||
VIRTIO_PCIDEV_OP_CFG_READ,
|
||||
VIRTIO_PCIDEV_OP_CFG_WRITE,
|
||||
VIRTIO_PCIDEV_OP_MMIO_READ,
|
||||
VIRTIO_PCIDEV_OP_MMIO_WRITE,
|
||||
VIRTIO_PCIDEV_OP_MMIO_MEMSET,
|
||||
VIRTIO_PCIDEV_OP_INT,
|
||||
VIRTIO_PCIDEV_OP_MSI,
|
||||
VIRTIO_PCIDEV_OP_PME,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct virtio_pcidev_msg - virtio PCI device operation
|
||||
* @op: the operation to do
|
||||
* @bar: the bar (only with BAR read/write messages)
|
||||
* @reserved: reserved
|
||||
* @size: the size of the read/write (in bytes)
|
||||
* @addr: the address to read/write
|
||||
* @data: the data, normally @size long, but just one byte for
|
||||
* %VIRTIO_PCIDEV_OP_MMIO_MEMSET
|
||||
*
|
||||
* Note: the fields are all in native (CPU) endian, however, the
|
||||
* @data values will often be in little endian (see the ops above.)
|
||||
*/
|
||||
struct virtio_pcidev_msg {
|
||||
__u8 op;
|
||||
__u8 bar;
|
||||
__u16 reserved;
|
||||
__u32 size;
|
||||
__u64 addr;
|
||||
__u8 data[];
|
||||
};
|
||||
|
||||
#endif /* _UAPI_LINUX_VIRTIO_PCIDEV_H */
|
||||
Reference in New Issue
Block a user