Files
Will Deacon f83cd1611d kvm tools: irq: replace the x86 irq rbtree with the PCI device tree
The x86 code keeps its own rbtree of PCI devices in order to allocate
interrupts. However, this functionality can be moved into the generic
PCI device tree and be reused by other architectures.

This patch removes the x86 tree and reworks the ACPI mptable generation
to use the PCI device tree for enumerating the bus.

Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
2015-06-01 16:39:55 +01:00

281 lines
6.8 KiB
C

#include "kvm/kvm.h"
#include "kvm/bios.h"
#include "kvm/apic.h"
#include "kvm/mptable.h"
#include "kvm/util.h"
#include "kvm/devices.h"
#include "kvm/pci.h"
#include <linux/kernel.h>
#include <string.h>
#include <asm/mpspec_def.h>
#include <linux/types.h>
/*
* FIXME: please make sure the addresses borrowed
* for apic/ioapic never overlaped! We need a global
* tracker of system resources (including io, mmio,
* and friends).
*/
static unsigned int mpf_checksum(unsigned char *mp, int len)
{
unsigned int sum = 0;
while (len--)
sum += *mp++;
return sum & 0xFF;
}
static unsigned int gen_cpu_flag(unsigned int cpu, unsigned int ncpu)
{
/* sets enabled/disabled | BSP/AP processor */
return ( (cpu < ncpu) ? CPU_ENABLED : 0) |
((cpu == 0) ? CPU_BOOTPROCESSOR : 0x00);
}
#define MPTABLE_SIG_FLOATING "_MP_"
#define MPTABLE_OEM "KVMCPU00"
#define MPTABLE_PRODUCTID "0.1 "
#define MPTABLE_PCIBUSTYPE "PCI "
#define MPTABLE_ISABUSTYPE "ISA "
#define MPTABLE_STRNCPY(d, s) memcpy(d, s, sizeof(d))
/* It should be more than enough */
#define MPTABLE_MAX_SIZE (32 << 20)
/*
* Too many cpus will require x2apic mode
* and rather ACPI support so we limit it
* here for a while.
*/
#define MPTABLE_MAX_CPUS 255
static void mptable_add_irq_src(struct mpc_intsrc *mpc_intsrc,
u16 srcbusid, u16 srcbusirq,
u16 dstapic, u16 dstirq)
{
*mpc_intsrc = (struct mpc_intsrc) {
.type = MP_INTSRC,
.irqtype = mp_INT,
.irqflag = MP_IRQDIR_DEFAULT,
.srcbus = srcbusid,
.srcbusirq = srcbusirq,
.dstapic = dstapic,
.dstirq = dstirq
};
}
/**
* mptable_setup - create mptable and fill guest memory with it
*/
int mptable__init(struct kvm *kvm)
{
unsigned long real_mpc_table, real_mpf_intel, size;
struct mpf_intel *mpf_intel;
struct mpc_table *mpc_table;
struct mpc_cpu *mpc_cpu;
struct mpc_bus *mpc_bus;
struct mpc_ioapic *mpc_ioapic;
struct mpc_intsrc *mpc_intsrc;
struct device_header *dev_hdr;
const int pcibusid = 0;
const int isabusid = 1;
unsigned int i, nentries = 0, ncpus = kvm->nrcpus;
unsigned int ioapicid;
void *last_addr;
/* That is where MP table will be in guest memory */
real_mpc_table = ALIGN(MB_BIOS_BEGIN + bios_rom_size, 16);
if (ncpus > MPTABLE_MAX_CPUS) {
pr_warning("Too many cpus: %d limited to %d",
ncpus, MPTABLE_MAX_CPUS);
ncpus = MPTABLE_MAX_CPUS;
}
mpc_table = calloc(1, MPTABLE_MAX_SIZE);
if (!mpc_table)
return -ENOMEM;
MPTABLE_STRNCPY(mpc_table->signature, MPC_SIGNATURE);
MPTABLE_STRNCPY(mpc_table->oem, MPTABLE_OEM);
MPTABLE_STRNCPY(mpc_table->productid, MPTABLE_PRODUCTID);
mpc_table->spec = 4;
mpc_table->lapic = APIC_ADDR(0);
mpc_table->oemcount = ncpus; /* will be updated again at end */
/*
* CPUs enumeration. Technically speaking we should
* ask either host or HV for apic version supported
* but for a while we simply put some random value
* here.
*/
mpc_cpu = (void *)&mpc_table[1];
for (i = 0; i < ncpus; i++) {
mpc_cpu->type = MP_PROCESSOR;
mpc_cpu->apicid = i;
mpc_cpu->apicver = KVM_APIC_VERSION;
mpc_cpu->cpuflag = gen_cpu_flag(i, ncpus);
mpc_cpu->cpufeature = 0x600; /* some default value */
mpc_cpu->featureflag = 0x201; /* some default value */
mpc_cpu++;
}
last_addr = (void *)mpc_cpu;
nentries += ncpus;
/*
* PCI buses.
* FIXME: Some callback here to obtain real number
* of PCI buses present in system.
*/
mpc_bus = last_addr;
mpc_bus->type = MP_BUS;
mpc_bus->busid = pcibusid;
MPTABLE_STRNCPY(mpc_bus->bustype, MPTABLE_PCIBUSTYPE);
last_addr = (void *)&mpc_bus[1];
nentries++;
/*
* ISA bus.
* FIXME: Same issue as for PCI bus.
*/
mpc_bus = last_addr;
mpc_bus->type = MP_BUS;
mpc_bus->busid = isabusid;
MPTABLE_STRNCPY(mpc_bus->bustype, MPTABLE_ISABUSTYPE);
last_addr = (void *)&mpc_bus[1];
nentries++;
/*
* IO-APIC chip.
*/
ioapicid = ncpus + 1;
mpc_ioapic = last_addr;
mpc_ioapic->type = MP_IOAPIC;
mpc_ioapic->apicid = ioapicid;
mpc_ioapic->apicver = KVM_APIC_VERSION;
mpc_ioapic->flags = MPC_APIC_USABLE;
mpc_ioapic->apicaddr = IOAPIC_ADDR(0);
last_addr = (void *)&mpc_ioapic[1];
nentries++;
/*
* IRQ sources.
* Also note we use PCI irqs here, no for ISA bus yet.
*/
dev_hdr = device__first_dev(DEVICE_BUS_PCI);
while (dev_hdr) {
unsigned char srcbusirq;
struct pci_device_header *pci_hdr = dev_hdr->data;
srcbusirq = (pci_hdr->subsys_id << 2) | (pci_hdr->irq_pin - 1);
mpc_intsrc = last_addr;
mptable_add_irq_src(mpc_intsrc, pcibusid, srcbusirq, ioapicid, pci_hdr->irq_line);
last_addr = (void *)&mpc_intsrc[dev_hdr->dev_num];
nentries++;
dev_hdr = device__next_dev(dev_hdr);
}
/*
* Local IRQs assignment (LINT0, LINT1)
*/
mpc_intsrc = last_addr;
mpc_intsrc->type = MP_LINTSRC;
mpc_intsrc->irqtype = mp_ExtINT;
mpc_intsrc->irqtype = mp_INT;
mpc_intsrc->irqflag = MP_IRQDIR_DEFAULT;
mpc_intsrc->srcbus = isabusid;
mpc_intsrc->srcbusirq = 0;
mpc_intsrc->dstapic = 0; /* FIXME: BSP apic */
mpc_intsrc->dstirq = 0; /* LINT0 */
last_addr = (void *)&mpc_intsrc[1];
nentries++;
mpc_intsrc = last_addr;
mpc_intsrc->type = MP_LINTSRC;
mpc_intsrc->irqtype = mp_NMI;
mpc_intsrc->irqflag = MP_IRQDIR_DEFAULT;
mpc_intsrc->srcbus = isabusid;
mpc_intsrc->srcbusirq = 0;
mpc_intsrc->dstapic = 0; /* FIXME: BSP apic */
mpc_intsrc->dstirq = 1; /* LINT1 */
last_addr = (void *)&mpc_intsrc[1];
nentries++;
/*
* Floating MP table finally.
*/
real_mpf_intel = ALIGN((unsigned long)last_addr - (unsigned long)mpc_table, 16);
mpf_intel = (void *)((unsigned long)mpc_table + real_mpf_intel);
MPTABLE_STRNCPY(mpf_intel->signature, MPTABLE_SIG_FLOATING);
mpf_intel->length = 1;
mpf_intel->specification= 4;
mpf_intel->physptr = (unsigned int)real_mpc_table;
mpf_intel->checksum = -mpf_checksum((unsigned char *)mpf_intel, sizeof(*mpf_intel));
/*
* No last_addr inclrement here please, we need last
* active position here to compute table size.
*/
/*
* Don't forget to update header in fixed table.
*/
mpc_table->oemcount = nentries;
mpc_table->length = last_addr - (void *)mpc_table;
mpc_table->checksum = -mpf_checksum((unsigned char *)mpc_table, mpc_table->length);
/*
* We will copy the whole table, no need to separate
* floating structure and table itkvm.
*/
size = (unsigned long)mpf_intel + sizeof(*mpf_intel) - (unsigned long)mpc_table;
/*
* The finial check -- never get out of system bios
* area. Lets also check for allocated memory overrun,
* in real it's late but still usefull.
*/
if (size > (unsigned long)(MB_BIOS_END - bios_rom_size) ||
size > MPTABLE_MAX_SIZE) {
free(mpc_table);
pr_err("MP table is too big");
return -E2BIG;
}
/*
* OK, it is time to move it to guest memory.
*/
memcpy(guest_flat_to_host(kvm, real_mpc_table), mpc_table, size);
free(mpc_table);
return 0;
}
firmware_init(mptable__init);
int mptable__exit(struct kvm *kvm)
{
return 0;
}
firmware_exit(mptable__exit);