mirror of https://github.com/xemu-project/xemu.git
pci,misc enhancements
This includes some pci enhancements: Better support for systems with multiple PCI root buses FW cfg interface for more robust pci programming in BIOS Minor fixes/cleanups for fw cfg and cross-version migration - because of dependencies with other patches Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) iQEcBAABAgAGBQJR2ctmAAoJECgfDbjSjVRpQpAH/Rk00yLrQ2R5ScNa8AL9LeaJ gVFndBmmuRz4gdhyATx6lzR98ic32iTr0+YR5mL51btgmM5a0bEd/SIu34nXriWj PsM0wdXfo/oEygdttxhvzJOH17tohRV9xg2WA2d8BEwDzrDyqoQ4J0VJlHlG7u3W nq4KVDVUpLNQFKG8ZgJ2vW0WMw/mBSj2rluhQUALhcuvChphtvAFZ2rsSfJr6bzD aBELrtIvfLvPGN/0WVeYs9qlp4EE03H3X6gN61QvV3/YElxubKUV5XyMDOX2dW3D 2j0NQi84LYHn0SFap2r/Kgm47/F6Q56SFk5lrgZrg60mhQTwocw7PfL8CGxjXRI= =gxxc -----END PGP SIGNATURE----- Merge remote-tracking branch 'mst/tags/for_anthony' into staging pci,misc enhancements This includes some pci enhancements: Better support for systems with multiple PCI root buses FW cfg interface for more robust pci programming in BIOS Minor fixes/cleanups for fw cfg and cross-version migration - because of dependencies with other patches Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Sun 07 Jul 2013 03:11:18 PM CDT using RSA key ID D28D5469 # gpg: Can't check signature: public key not found # By David Gibson (10) and others # Via Michael S. Tsirkin * mst/tags/for_anthony: pci: Fold host_buses list into PCIHostState functionality pci: Remove domain from PCIHostBus pci: Simpler implementation of primary PCI bus pci: Add root bus parameter to pci_nic_init() pci: Add root bus argument to pci_get_bus_devfn() pci: Replace pci_find_domain() with more general pci_root_bus_path() pci: Use helper to find device's root bus in pci_find_domain() pci: Abolish pci_find_root_bus() pci: Move pci_read_devaddr to pci-hotplug-old.c pci: Cleanup configuration for pci-hotplug.c pvpanic: fix fwcfg for big endian hosts pvpanic: initialization cleanup MAINTAINERS: s/Marcelo/Paolo/ e1000: cleanup process_tx_desc pc_piix: cleanup init compat handling pc: pass PCI hole ranges to Guests pci: store PCI hole ranges in guestinfo structure range: add Range structure Message-id: 1373228271-31223-1-git-send-email-mst@redhat.com Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
commit
dc11549ec2
|
@ -161,7 +161,7 @@ Guest CPU Cores (KVM):
|
|||
|
||||
Overall
|
||||
M: Gleb Natapov <gleb@redhat.com>
|
||||
M: Marcelo Tosatti <mtosatti@redhat.com>
|
||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||
L: kvm@vger.kernel.org
|
||||
S: Supported
|
||||
F: kvm-*
|
||||
|
|
|
@ -28,11 +28,10 @@ CONFIG_APPLESMC=y
|
|||
CONFIG_I8259=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_TPM_TIS=$(CONFIG_TPM)
|
||||
CONFIG_PCI_HOTPLUG=y
|
||||
CONFIG_PCI_HOTPLUG_OLD=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_PAM=y
|
||||
CONFIG_PCI_PIIX=y
|
||||
CONFIG_PCI_HOTPLUG=y
|
||||
CONFIG_WDT_IB700=y
|
||||
CONFIG_PC_SYSFW=y
|
||||
CONFIG_XEN_I386=$(CONFIG_XEN)
|
||||
|
|
|
@ -45,7 +45,5 @@ CONFIG_OPENPIC=y
|
|||
CONFIG_PSERIES=y
|
||||
CONFIG_E500=y
|
||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
||||
# For pSeries
|
||||
CONFIG_PCI_HOTPLUG=y
|
||||
# For PReP
|
||||
CONFIG_MC146818RTC=y
|
||||
|
|
|
@ -28,11 +28,10 @@ CONFIG_APPLESMC=y
|
|||
CONFIG_I8259=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_TPM_TIS=$(CONFIG_TPM)
|
||||
CONFIG_PCI_HOTPLUG=y
|
||||
CONFIG_PCI_HOTPLUG_OLD=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_PAM=y
|
||||
CONFIG_PCI_PIIX=y
|
||||
CONFIG_PCI_HOTPLUG=y
|
||||
CONFIG_WDT_IB700=y
|
||||
CONFIG_PC_SYSFW=y
|
||||
CONFIG_XEN_I386=$(CONFIG_XEN)
|
||||
|
|
|
@ -1077,7 +1077,7 @@ STEXI
|
|||
Add drive to PCI storage controller.
|
||||
ETEXI
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#if defined(CONFIG_PCI_HOTPLUG_OLD)
|
||||
{
|
||||
.name = "pci_add",
|
||||
.args_type = "pci_addr:s,type:s,opts:s?",
|
||||
|
@ -1093,7 +1093,7 @@ STEXI
|
|||
Hot-add PCI device.
|
||||
ETEXI
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
#if defined(CONFIG_PCI_HOTPLUG_OLD)
|
||||
{
|
||||
.name = "pci_del",
|
||||
.args_type = "pci_addr:s",
|
||||
|
|
|
@ -89,7 +89,7 @@ static void clipper_init(QEMUMachineInitArgs *args)
|
|||
|
||||
/* Network setup. e1000 is good enough, failing Tulip support. */
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
pci_nic_init_nofail(&nd_table[i], "e1000", NULL);
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
|
||||
}
|
||||
|
||||
/* IDE disk setup. */
|
||||
|
|
|
@ -59,7 +59,7 @@ static void realview_init(QEMUMachineInitArgs *args,
|
|||
qemu_irq *irqp;
|
||||
qemu_irq pic[64];
|
||||
qemu_irq mmc_irq[2];
|
||||
PCIBus *pci_bus;
|
||||
PCIBus *pci_bus = NULL;
|
||||
NICInfo *nd;
|
||||
i2c_bus *i2c;
|
||||
int n;
|
||||
|
@ -250,7 +250,9 @@ static void realview_init(QEMUMachineInitArgs *args,
|
|||
}
|
||||
done_nic = 1;
|
||||
} else {
|
||||
pci_nic_init_nofail(nd, "rtl8139", NULL);
|
||||
if (pci_bus) {
|
||||
pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -245,7 +245,7 @@ static void versatile_init(QEMUMachineInitArgs *args, int board_id)
|
|||
smc91c111_init(nd, 0x10010000, sic[25]);
|
||||
done_smc = 1;
|
||||
} else {
|
||||
pci_nic_init_nofail(nd, "rtl8139", NULL);
|
||||
pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
|
||||
}
|
||||
}
|
||||
if (usb_enabled(false)) {
|
||||
|
|
74
hw/i386/pc.c
74
hw/i386/pc.c
|
@ -989,6 +989,74 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
|
|||
}
|
||||
}
|
||||
|
||||
/* pci-info ROM file. Little endian format */
|
||||
typedef struct PcRomPciInfo {
|
||||
uint64_t w32_min;
|
||||
uint64_t w32_max;
|
||||
uint64_t w64_min;
|
||||
uint64_t w64_max;
|
||||
} PcRomPciInfo;
|
||||
|
||||
static void pc_fw_cfg_guest_info(PcGuestInfo *guest_info)
|
||||
{
|
||||
PcRomPciInfo *info;
|
||||
if (!guest_info->has_pci_info) {
|
||||
return;
|
||||
}
|
||||
|
||||
info = g_malloc(sizeof *info);
|
||||
info->w32_min = cpu_to_le64(guest_info->pci_info.w32.begin);
|
||||
info->w32_max = cpu_to_le64(guest_info->pci_info.w32.end);
|
||||
info->w64_min = cpu_to_le64(guest_info->pci_info.w64.begin);
|
||||
info->w64_max = cpu_to_le64(guest_info->pci_info.w64.end);
|
||||
/* Pass PCI hole info to guest via a side channel.
|
||||
* Required so guest PCI enumeration does the right thing. */
|
||||
fw_cfg_add_file(guest_info->fw_cfg, "etc/pci-info", info, sizeof *info);
|
||||
}
|
||||
|
||||
typedef struct PcGuestInfoState {
|
||||
PcGuestInfo info;
|
||||
Notifier machine_done;
|
||||
} PcGuestInfoState;
|
||||
|
||||
static
|
||||
void pc_guest_info_machine_done(Notifier *notifier, void *data)
|
||||
{
|
||||
PcGuestInfoState *guest_info_state = container_of(notifier,
|
||||
PcGuestInfoState,
|
||||
machine_done);
|
||||
pc_fw_cfg_guest_info(&guest_info_state->info);
|
||||
}
|
||||
|
||||
PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
|
||||
ram_addr_t above_4g_mem_size)
|
||||
{
|
||||
PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
|
||||
PcGuestInfo *guest_info = &guest_info_state->info;
|
||||
|
||||
guest_info->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS;
|
||||
if (sizeof(hwaddr) == 4) {
|
||||
guest_info->pci_info.w64.begin = 0;
|
||||
guest_info->pci_info.w64.end = 0;
|
||||
} else {
|
||||
/*
|
||||
* BIOS does not set MTRR entries for the 64 bit window, so no need to
|
||||
* align address to power of two. Align address at 1G, this makes sure
|
||||
* it can be exactly covered with a PAT entry even when using huge
|
||||
* pages.
|
||||
*/
|
||||
guest_info->pci_info.w64.begin =
|
||||
ROUND_UP((0x1ULL << 32) + above_4g_mem_size, 0x1ULL << 30);
|
||||
guest_info->pci_info.w64.end = guest_info->pci_info.w64.begin +
|
||||
(0x1ULL << 62);
|
||||
assert(guest_info->pci_info.w64.begin <= guest_info->pci_info.w64.end);
|
||||
}
|
||||
|
||||
guest_info_state->machine_done.notify = pc_guest_info_machine_done;
|
||||
qemu_add_machine_init_done_notifier(&guest_info_state->machine_done);
|
||||
return guest_info;
|
||||
}
|
||||
|
||||
void pc_acpi_init(const char *default_dsdt)
|
||||
{
|
||||
char *filename;
|
||||
|
@ -1030,7 +1098,8 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,
|
|||
ram_addr_t below_4g_mem_size,
|
||||
ram_addr_t above_4g_mem_size,
|
||||
MemoryRegion *rom_memory,
|
||||
MemoryRegion **ram_memory)
|
||||
MemoryRegion **ram_memory,
|
||||
PcGuestInfo *guest_info)
|
||||
{
|
||||
int linux_boot, i;
|
||||
MemoryRegion *ram, *option_rom_mr;
|
||||
|
@ -1082,6 +1151,7 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,
|
|||
for (i = 0; i < nb_option_roms; i++) {
|
||||
rom_add_option(option_rom[i].name, option_rom[i].bootindex);
|
||||
}
|
||||
guest_info->fw_cfg = fw_cfg;
|
||||
return fw_cfg;
|
||||
}
|
||||
|
||||
|
@ -1240,7 +1310,7 @@ void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus)
|
|||
if (!pci_bus || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) {
|
||||
pc_init_ne2k_isa(isa_bus, nd);
|
||||
} else {
|
||||
pci_nic_init_nofail(nd, "e1000", NULL);
|
||||
pci_nic_init_nofail(nd, pci_bus, "e1000", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
|
|||
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
|
||||
|
||||
static bool has_pvpanic = true;
|
||||
static bool has_pci_info = true;
|
||||
|
||||
/* PC hardware initialisation */
|
||||
static void pc_init1(MemoryRegion *system_memory,
|
||||
|
@ -90,6 +91,7 @@ static void pc_init1(MemoryRegion *system_memory,
|
|||
MemoryRegion *rom_memory;
|
||||
DeviceState *icc_bridge;
|
||||
FWCfgState *fw_cfg = NULL;
|
||||
PcGuestInfo *guest_info;
|
||||
|
||||
if (xen_enabled() && xen_hvm_init() != 0) {
|
||||
fprintf(stderr, "xen hardware virtual machine initialisation failed\n");
|
||||
|
@ -124,12 +126,24 @@ static void pc_init1(MemoryRegion *system_memory,
|
|||
rom_memory = system_memory;
|
||||
}
|
||||
|
||||
guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
|
||||
guest_info->has_pci_info = has_pci_info;
|
||||
|
||||
/* Set PCI window size the way seabios has always done it. */
|
||||
/* Power of 2 so bios can cover it with a single MTRR */
|
||||
if (ram_size <= 0x80000000)
|
||||
guest_info->pci_info.w32.begin = 0x80000000;
|
||||
else if (ram_size <= 0xc0000000)
|
||||
guest_info->pci_info.w32.begin = 0xc0000000;
|
||||
else
|
||||
guest_info->pci_info.w32.begin = 0xe0000000;
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
if (!xen_enabled()) {
|
||||
fw_cfg = pc_memory_init(system_memory,
|
||||
kernel_filename, kernel_cmdline, initrd_filename,
|
||||
below_4g_mem_size, above_4g_mem_size,
|
||||
rom_memory, &ram_memory);
|
||||
rom_memory, &ram_memory, guest_info);
|
||||
}
|
||||
|
||||
gsi_state = g_malloc0(sizeof(*gsi_state));
|
||||
|
@ -248,36 +262,36 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
|
|||
initrd_filename, cpu_model, 1, 1);
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_5(QEMUMachineInitArgs *args)
|
||||
{
|
||||
has_pci_info = false;
|
||||
pc_init_pci(args);
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_4(QEMUMachineInitArgs *args)
|
||||
{
|
||||
has_pvpanic = false;
|
||||
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
|
||||
pc_init_pci(args);
|
||||
pc_init_pci_1_5(args);
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
|
||||
{
|
||||
enable_compat_apic_id_mode();
|
||||
has_pvpanic = false;
|
||||
pc_init_pci(args);
|
||||
pc_init_pci_1_4(args);
|
||||
}
|
||||
|
||||
/* PC machine init function for pc-1.1 to pc-1.2 */
|
||||
static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
|
||||
{
|
||||
disable_kvm_pv_eoi();
|
||||
enable_compat_apic_id_mode();
|
||||
has_pvpanic = false;
|
||||
pc_init_pci(args);
|
||||
pc_init_pci_1_3(args);
|
||||
}
|
||||
|
||||
/* PC machine init function for pc-0.14 to pc-1.0 */
|
||||
static void pc_init_pci_1_0(QEMUMachineInitArgs *args)
|
||||
{
|
||||
disable_kvm_pv_eoi();
|
||||
enable_compat_apic_id_mode();
|
||||
has_pvpanic = false;
|
||||
pc_init_pci(args);
|
||||
pc_init_pci_1_2(args);
|
||||
}
|
||||
|
||||
/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
|
||||
|
@ -290,6 +304,7 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
|
|||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
has_pvpanic = false;
|
||||
has_pci_info = false;
|
||||
disable_kvm_pv_eoi();
|
||||
enable_compat_apic_id_mode();
|
||||
pc_init1(get_system_memory(),
|
||||
|
@ -308,6 +323,7 @@ static void pc_init_isa(QEMUMachineInitArgs *args)
|
|||
const char *initrd_filename = args->initrd_filename;
|
||||
const char *boot_device = args->boot_device;
|
||||
has_pvpanic = false;
|
||||
has_pci_info = false;
|
||||
if (cpu_model == NULL)
|
||||
cpu_model = "486";
|
||||
disable_kvm_pv_eoi();
|
||||
|
@ -326,7 +342,7 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
|
|||
|
||||
pc_init_pci(args);
|
||||
|
||||
bus = pci_find_root_bus(0);
|
||||
bus = pci_find_primary_bus();
|
||||
if (bus != NULL) {
|
||||
pci_create_simple(bus, -1, "xen-platform");
|
||||
}
|
||||
|
@ -347,7 +363,7 @@ static QEMUMachine pc_i440fx_machine_v1_6 = {
|
|||
static QEMUMachine pc_i440fx_machine_v1_5 = {
|
||||
.name = "pc-i440fx-1.5",
|
||||
.desc = "Standard PC (i440FX + PIIX, 1996)",
|
||||
.init = pc_init_pci,
|
||||
.init = pc_init_pci_1_5,
|
||||
.hot_add_cpu = pc_hot_add_cpu,
|
||||
.max_cpus = 255,
|
||||
.compat_props = (GlobalProperty[]) {
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#define MAX_SATA_PORTS 6
|
||||
|
||||
static bool has_pvpanic = true;
|
||||
static bool has_pci_info = true;
|
||||
|
||||
/* PC hardware initialisation */
|
||||
static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
|
@ -77,6 +78,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
|||
ICH9LPCState *ich9_lpc;
|
||||
PCIDevice *ahci;
|
||||
DeviceState *icc_bridge;
|
||||
PcGuestInfo *guest_info;
|
||||
|
||||
icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE);
|
||||
object_property_add_child(qdev_get_machine(), "icc-bridge",
|
||||
|
@ -105,11 +107,14 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
|||
rom_memory = get_system_memory();
|
||||
}
|
||||
|
||||
guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
|
||||
guest_info->has_pci_info = has_pci_info;
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
if (!xen_enabled()) {
|
||||
pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline,
|
||||
initrd_filename, below_4g_mem_size, above_4g_mem_size,
|
||||
rom_memory, &ram_memory);
|
||||
rom_memory, &ram_memory, guest_info);
|
||||
}
|
||||
|
||||
/* irq lines */
|
||||
|
@ -131,6 +136,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
|||
q35_host->mch.address_space_io = get_system_io();
|
||||
q35_host->mch.below_4g_mem_size = below_4g_mem_size;
|
||||
q35_host->mch.above_4g_mem_size = above_4g_mem_size;
|
||||
q35_host->mch.guest_info = guest_info;
|
||||
/* pci */
|
||||
qdev_init_nofail(DEVICE(q35_host));
|
||||
host_bus = q35_host->host.pci.bus;
|
||||
|
@ -208,11 +214,17 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
|||
}
|
||||
}
|
||||
|
||||
static void pc_q35_init_1_5(QEMUMachineInitArgs *args)
|
||||
{
|
||||
has_pci_info = false;
|
||||
pc_q35_init(args);
|
||||
}
|
||||
|
||||
static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
|
||||
{
|
||||
has_pvpanic = false;
|
||||
x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE);
|
||||
pc_q35_init(args);
|
||||
pc_q35_init_1_5(args);
|
||||
}
|
||||
|
||||
static QEMUMachine pc_q35_machine_v1_6 = {
|
||||
|
@ -228,7 +240,7 @@ static QEMUMachine pc_q35_machine_v1_6 = {
|
|||
static QEMUMachine pc_q35_machine_v1_5 = {
|
||||
.name = "pc-q35-1.5",
|
||||
.desc = "Standard PC (Q35 + ICH9, 2009)",
|
||||
.init = pc_q35_init,
|
||||
.init = pc_q35_init_1_5,
|
||||
.hot_add_cpu = pc_hot_add_cpu,
|
||||
.max_cpus = 255,
|
||||
.compat_props = (GlobalProperty[]) {
|
||||
|
|
|
@ -231,7 +231,7 @@ static void audio_init (PCIBus *pci_bus)
|
|||
}
|
||||
|
||||
/* Network support */
|
||||
static void network_init (void)
|
||||
static void network_init (PCIBus *pci_bus)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -244,7 +244,7 @@ static void network_init (void)
|
|||
default_devaddr = "07";
|
||||
}
|
||||
|
||||
pci_nic_init_nofail(nd, "rtl8139", default_devaddr);
|
||||
pci_nic_init_nofail(nd, pci_bus, "rtl8139", default_devaddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,7 +393,7 @@ static void mips_fulong2e_init(QEMUMachineInitArgs *args)
|
|||
/* Sound card */
|
||||
audio_init(pci_bus);
|
||||
/* Network card */
|
||||
network_init();
|
||||
network_init(pci_bus);
|
||||
}
|
||||
|
||||
static QEMUMachine mips_fulong2e_machine = {
|
||||
|
|
|
@ -468,7 +468,7 @@ static MaltaFPGAState *malta_fpga_init(MemoryRegion *address_space,
|
|||
}
|
||||
|
||||
/* Network support */
|
||||
static void network_init(void)
|
||||
static void network_init(PCIBus *pci_bus)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -480,7 +480,7 @@ static void network_init(void)
|
|||
/* The malta board has a PCNet card using PCI SLOT 11 */
|
||||
default_devaddr = "0b";
|
||||
|
||||
pci_nic_init_nofail(nd, "pcnet", default_devaddr);
|
||||
pci_nic_init_nofail(nd, pci_bus, "pcnet", default_devaddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -985,7 +985,7 @@ void mips_malta_init(QEMUMachineInitArgs *args)
|
|||
fdctrl_init_isa(isa_bus, fd);
|
||||
|
||||
/* Network card */
|
||||
network_init();
|
||||
network_init(pci_bus);
|
||||
|
||||
/* Optional PCI video card */
|
||||
pci_vga_init(pci_bus);
|
||||
|
|
|
@ -97,26 +97,29 @@ static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
|
|||
{
|
||||
ISADevice *d = ISA_DEVICE(dev);
|
||||
PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
|
||||
static bool port_configured;
|
||||
FWCfgState *fw_cfg;
|
||||
|
||||
isa_register_ioport(d, &s->io, s->ioport);
|
||||
|
||||
if (!port_configured) {
|
||||
fw_cfg = fw_cfg_find();
|
||||
if (fw_cfg) {
|
||||
fw_cfg_add_file(fw_cfg, "etc/pvpanic-port",
|
||||
g_memdup(&s->ioport, sizeof(s->ioport)),
|
||||
sizeof(s->ioport));
|
||||
port_configured = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pvpanic_init(ISABus *bus)
|
||||
static void pvpanic_fw_cfg(ISADevice *dev, FWCfgState *fw_cfg)
|
||||
{
|
||||
isa_create_simple(bus, TYPE_ISA_PVPANIC_DEVICE);
|
||||
return 0;
|
||||
PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
|
||||
uint16_t *pvpanic_port = g_malloc(sizeof(*pvpanic_port));
|
||||
*pvpanic_port = cpu_to_le16(s->ioport);
|
||||
|
||||
fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port,
|
||||
sizeof(*pvpanic_port));
|
||||
}
|
||||
|
||||
void pvpanic_init(ISABus *bus)
|
||||
{
|
||||
ISADevice *dev;
|
||||
FWCfgState *fw_cfg = fw_cfg_find();
|
||||
if (!fw_cfg) {
|
||||
return;
|
||||
}
|
||||
dev = isa_create_simple (bus, TYPE_ISA_PVPANIC_DEVICE);
|
||||
pvpanic_fw_cfg(dev, fw_cfg);
|
||||
}
|
||||
|
||||
static Property pvpanic_isa_properties[] = {
|
||||
|
|
|
@ -556,7 +556,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
|||
uint32_t txd_lower = le32_to_cpu(dp->lower.data);
|
||||
uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
|
||||
unsigned int split_size = txd_lower & 0xffff, bytes, sz, op;
|
||||
unsigned int msh = 0xfffff, hdr = 0;
|
||||
unsigned int msh = 0xfffff;
|
||||
uint64_t addr;
|
||||
struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
|
||||
struct e1000_tx *tp = &s->tx;
|
||||
|
@ -603,8 +603,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
|||
|
||||
addr = le64_to_cpu(dp->buffer_addr);
|
||||
if (tp->tse && tp->cptse) {
|
||||
hdr = tp->hdr_len;
|
||||
msh = hdr + tp->mss;
|
||||
msh = tp->hdr_len + tp->mss;
|
||||
do {
|
||||
bytes = split_size;
|
||||
if (tp->size + bytes > msh)
|
||||
|
@ -612,14 +611,16 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
|||
|
||||
bytes = MIN(sizeof(tp->data) - tp->size, bytes);
|
||||
pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes);
|
||||
if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)
|
||||
memmove(tp->header, tp->data, hdr);
|
||||
sz = tp->size + bytes;
|
||||
if (sz >= tp->hdr_len && tp->size < tp->hdr_len) {
|
||||
memmove(tp->header, tp->data, tp->hdr_len);
|
||||
}
|
||||
tp->size = sz;
|
||||
addr += bytes;
|
||||
if (sz == msh) {
|
||||
xmit_seg(s);
|
||||
memmove(tp->data, tp->header, hdr);
|
||||
tp->size = hdr;
|
||||
memmove(tp->data, tp->header, tp->hdr_len);
|
||||
tp->size = tp->hdr_len;
|
||||
}
|
||||
} while (split_size -= bytes);
|
||||
} else if (!tp->tse && tp->cptse) {
|
||||
|
@ -633,8 +634,9 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
|||
|
||||
if (!(txd_lower & E1000_TXD_CMD_EOP))
|
||||
return;
|
||||
if (!(tp->tse && tp->cptse && tp->size < hdr))
|
||||
if (!(tp->tse && tp->cptse && tp->size < tp->hdr_len)) {
|
||||
xmit_seg(s);
|
||||
}
|
||||
tp->tso_frames = 0;
|
||||
tp->sum_needed = 0;
|
||||
tp->vlan_needed = 0;
|
||||
|
|
|
@ -630,11 +630,20 @@ static const TypeInfo i440fx_info = {
|
|||
.class_init = i440fx_class_init,
|
||||
};
|
||||
|
||||
static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
|
||||
PCIBus *rootbus)
|
||||
{
|
||||
/* For backwards compat with old device paths */
|
||||
return "0000";
|
||||
}
|
||||
|
||||
static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
|
||||
|
||||
hc->root_bus_path = i440fx_pcihost_root_bus_path;
|
||||
k->init = i440fx_pcihost_initfn;
|
||||
dc->fw_name = "pci";
|
||||
dc->no_user = 1;
|
||||
|
|
|
@ -63,6 +63,13 @@ static int q35_host_init(SysBusDevice *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *q35_host_root_bus_path(PCIHostState *host_bridge,
|
||||
PCIBus *rootbus)
|
||||
{
|
||||
/* For backwards compat with old device paths */
|
||||
return "0000";
|
||||
}
|
||||
|
||||
static Property mch_props[] = {
|
||||
DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
|
||||
MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
|
||||
|
@ -73,7 +80,9 @@ static void q35_host_class_init(ObjectClass *klass, void *data)
|
|||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
|
||||
|
||||
hc->root_bus_path = q35_host_root_bus_path;
|
||||
k->init = q35_host_init;
|
||||
dc->props = mch_props;
|
||||
dc->fw_name = "pci";
|
||||
|
@ -244,6 +253,14 @@ static int mch_init(PCIDevice *d)
|
|||
hwaddr pci_hole64_size;
|
||||
MCHPCIState *mch = MCH_PCI_DEVICE(d);
|
||||
|
||||
/* Leave enough space for the biggest MCFG BAR */
|
||||
/* TODO: this matches current bios behaviour, but
|
||||
* it's not a power of two, which means an MTRR
|
||||
* can't cover it exactly.
|
||||
*/
|
||||
mch->guest_info->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT +
|
||||
MCH_HOST_BRIDGE_PCIEXBAR_MAX;
|
||||
|
||||
/* setup pci memory regions */
|
||||
memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
|
||||
mch->pci_address_space,
|
||||
|
|
|
@ -8,4 +8,4 @@ common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
|
|||
common-obj-$(CONFIG_NO_PCI) += pci-stub.o
|
||||
common-obj-$(CONFIG_ALL) += pci-stub.o
|
||||
|
||||
obj-$(CONFIG_PCI_HOTPLUG) += pci-hotplug.o
|
||||
common-obj-$(CONFIG_PCI_HOTPLUG_OLD) += pci-hotplug-old.o
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/*
|
||||
* QEMU PCI hotplug support
|
||||
* Deprecated PCI hotplug interface support
|
||||
* This covers the old pci_add / pci_del command, whereas the more general
|
||||
* device_add / device_del commands are now preferred.
|
||||
*
|
||||
* Copyright (c) 2004 Fabrice Bellard
|
||||
*
|
||||
|
@ -34,17 +36,43 @@
|
|||
#include "sysemu/blockdev.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
static int pci_read_devaddr(Monitor *mon, const char *addr,
|
||||
int *busp, unsigned *slotp)
|
||||
{
|
||||
int dom;
|
||||
|
||||
/* strip legacy tag */
|
||||
if (!strncmp(addr, "pci_addr=", 9)) {
|
||||
addr += 9;
|
||||
}
|
||||
if (pci_parse_devaddr(addr, &dom, busp, slotp, NULL)) {
|
||||
monitor_printf(mon, "Invalid pci address\n");
|
||||
return -1;
|
||||
}
|
||||
if (dom != 0) {
|
||||
monitor_printf(mon, "Multiple PCI domains not supported, use device_add\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
|
||||
const char *devaddr,
|
||||
const char *opts_str)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
QemuOpts *opts;
|
||||
PCIBus *root = pci_find_primary_bus();
|
||||
PCIBus *bus;
|
||||
int ret, devfn;
|
||||
|
||||
bus = pci_get_bus_devfn(&devfn, devaddr);
|
||||
if (!root) {
|
||||
monitor_printf(mon, "no primary PCI bus (if there are multiple"
|
||||
" PCI roots, you must use device_add instead)");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bus = pci_get_bus_devfn(&devfn, root, devaddr);
|
||||
if (!bus) {
|
||||
monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
|
||||
return NULL;
|
||||
|
@ -71,7 +99,7 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
|
|||
monitor_printf(mon, "Parameter addr not supported\n");
|
||||
return NULL;
|
||||
}
|
||||
return pci_nic_init(&nd_table[ret], "rtl8139", devaddr);
|
||||
return pci_nic_init(&nd_table[ret], root, "rtl8139", devaddr);
|
||||
}
|
||||
|
||||
static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
|
||||
|
@ -113,18 +141,23 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
|
|||
|
||||
int pci_drive_hot_add(Monitor *mon, const QDict *qdict, DriveInfo *dinfo)
|
||||
{
|
||||
int dom, pci_bus;
|
||||
int pci_bus;
|
||||
unsigned slot;
|
||||
PCIBus *root = pci_find_primary_bus();
|
||||
PCIDevice *dev;
|
||||
const char *pci_addr = qdict_get_str(qdict, "pci_addr");
|
||||
|
||||
switch (dinfo->type) {
|
||||
case IF_SCSI:
|
||||
if (pci_read_devaddr(mon, pci_addr, &dom, &pci_bus, &slot)) {
|
||||
if (!root) {
|
||||
monitor_printf(mon, "no primary PCI bus (if there are multiple"
|
||||
" PCI roots, you must use device_add instead)");
|
||||
goto err;
|
||||
}
|
||||
dev = pci_find_device(pci_find_root_bus(dom), pci_bus,
|
||||
PCI_DEVFN(slot, 0));
|
||||
if (pci_read_devaddr(mon, pci_addr, &pci_bus, &slot)) {
|
||||
goto err;
|
||||
}
|
||||
dev = pci_find_device(root, pci_bus, PCI_DEVFN(slot, 0));
|
||||
if (!dev) {
|
||||
monitor_printf(mon, "no pci device with address %s\n", pci_addr);
|
||||
goto err;
|
||||
|
@ -151,6 +184,7 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
|
|||
DriveInfo *dinfo = NULL;
|
||||
int type = -1;
|
||||
char buf[128];
|
||||
PCIBus *root = pci_find_primary_bus();
|
||||
PCIBus *bus;
|
||||
int devfn;
|
||||
|
||||
|
@ -180,7 +214,12 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
|
|||
dinfo = NULL;
|
||||
}
|
||||
|
||||
bus = pci_get_bus_devfn(&devfn, devaddr);
|
||||
if (!root) {
|
||||
monitor_printf(mon, "no primary PCI bus (if there are multiple"
|
||||
" PCI roots, you must use device_add instead)");
|
||||
return NULL;
|
||||
}
|
||||
bus = pci_get_bus_devfn(&devfn, root, devaddr);
|
||||
if (!bus) {
|
||||
monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
|
||||
return NULL;
|
||||
|
@ -250,27 +289,33 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict)
|
|||
}
|
||||
|
||||
if (dev) {
|
||||
monitor_printf(mon, "OK domain %d, bus %d, slot %d, function %d\n",
|
||||
pci_find_domain(dev->bus),
|
||||
monitor_printf(mon, "OK root bus %s, bus %d, slot %d, function %d\n",
|
||||
pci_root_bus_path(dev),
|
||||
pci_bus_num(dev->bus), PCI_SLOT(dev->devfn),
|
||||
PCI_FUNC(dev->devfn));
|
||||
} else
|
||||
monitor_printf(mon, "failed to add %s\n", opts);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
|
||||
{
|
||||
PCIBus *root = pci_find_primary_bus();
|
||||
PCIDevice *d;
|
||||
int dom, bus;
|
||||
int bus;
|
||||
unsigned slot;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (pci_read_devaddr(mon, pci_addr, &dom, &bus, &slot)) {
|
||||
if (!root) {
|
||||
monitor_printf(mon, "no primary PCI bus (if there are multiple"
|
||||
" PCI roots, you must use device_del instead)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
d = pci_find_device(pci_find_root_bus(dom), bus, PCI_DEVFN(slot, 0));
|
||||
if (pci_read_devaddr(mon, pci_addr, &bus, &slot)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
d = pci_find_device(root, bus, PCI_DEVFN(slot, 0));
|
||||
if (!d) {
|
||||
monitor_printf(mon, "slot %d empty\n", slot);
|
||||
return -1;
|
137
hw/pci/pci.c
137
hw/pci/pci.c
|
@ -25,6 +25,7 @@
|
|||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_bridge.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "hw/pci/pci_host.h"
|
||||
#include "monitor/monitor.h"
|
||||
#include "net/net.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
@ -89,12 +90,7 @@ static void pci_del_option_rom(PCIDevice *pdev);
|
|||
static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
|
||||
static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
|
||||
|
||||
struct PCIHostBus {
|
||||
int domain;
|
||||
struct PCIBus *bus;
|
||||
QLIST_ENTRY(PCIHostBus) next;
|
||||
};
|
||||
static QLIST_HEAD(, PCIHostBus) host_buses;
|
||||
static QLIST_HEAD(, PCIHostState) pci_host_bridges;
|
||||
|
||||
static const VMStateDescription vmstate_pcibus = {
|
||||
.name = "PCIBUS",
|
||||
|
@ -237,46 +233,54 @@ static int pcibus_reset(BusState *qbus)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void pci_host_bus_register(int domain, PCIBus *bus)
|
||||
static void pci_host_bus_register(PCIBus *bus, DeviceState *parent)
|
||||
{
|
||||
struct PCIHostBus *host;
|
||||
host = g_malloc0(sizeof(*host));
|
||||
host->domain = domain;
|
||||
host->bus = bus;
|
||||
QLIST_INSERT_HEAD(&host_buses, host, next);
|
||||
PCIHostState *host_bridge = PCI_HOST_BRIDGE(parent);
|
||||
|
||||
QLIST_INSERT_HEAD(&pci_host_bridges, host_bridge, next);
|
||||
}
|
||||
|
||||
PCIBus *pci_find_root_bus(int domain)
|
||||
PCIBus *pci_find_primary_bus(void)
|
||||
{
|
||||
struct PCIHostBus *host;
|
||||
PCIBus *primary_bus = NULL;
|
||||
PCIHostState *host;
|
||||
|
||||
QLIST_FOREACH(host, &host_buses, next) {
|
||||
if (host->domain == domain) {
|
||||
return host->bus;
|
||||
QLIST_FOREACH(host, &pci_host_bridges, next) {
|
||||
if (primary_bus) {
|
||||
/* We have multiple root buses, refuse to select a primary */
|
||||
return NULL;
|
||||
}
|
||||
primary_bus = host->bus;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return primary_bus;
|
||||
}
|
||||
|
||||
int pci_find_domain(const PCIBus *bus)
|
||||
PCIBus *pci_device_root_bus(const PCIDevice *d)
|
||||
{
|
||||
PCIDevice *d;
|
||||
struct PCIHostBus *host;
|
||||
PCIBus *bus = d->bus;
|
||||
|
||||
/* obtain root bus */
|
||||
while ((d = bus->parent_dev) != NULL) {
|
||||
bus = d->bus;
|
||||
}
|
||||
|
||||
QLIST_FOREACH(host, &host_buses, next) {
|
||||
if (host->bus == bus) {
|
||||
return host->domain;
|
||||
}
|
||||
return bus;
|
||||
}
|
||||
|
||||
const char *pci_root_bus_path(PCIDevice *dev)
|
||||
{
|
||||
PCIBus *rootbus = pci_device_root_bus(dev);
|
||||
PCIHostState *host_bridge = PCI_HOST_BRIDGE(rootbus->qbus.parent);
|
||||
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_GET_CLASS(host_bridge);
|
||||
|
||||
assert(!rootbus->parent_dev);
|
||||
assert(host_bridge->bus == rootbus);
|
||||
|
||||
if (hc->root_bus_path) {
|
||||
return (*hc->root_bus_path)(host_bridge, rootbus);
|
||||
}
|
||||
|
||||
abort(); /* should not be reached */
|
||||
return -1;
|
||||
return rootbus->qbus.name;
|
||||
}
|
||||
|
||||
static void pci_bus_init(PCIBus *bus, DeviceState *parent,
|
||||
|
@ -292,7 +296,8 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent,
|
|||
|
||||
/* host bridge */
|
||||
QLIST_INIT(&bus->child);
|
||||
pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */
|
||||
|
||||
pci_host_bus_register(bus, parent);
|
||||
|
||||
vmstate_register(NULL, -1, &vmstate_pcibus, bus);
|
||||
}
|
||||
|
@ -522,7 +527,7 @@ static void pci_set_default_subsystem_id(PCIDevice *pci_dev)
|
|||
* Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
|
||||
* [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
|
||||
*/
|
||||
static int pci_parse_devaddr(const char *addr, int *domp, int *busp,
|
||||
int pci_parse_devaddr(const char *addr, int *domp, int *busp,
|
||||
unsigned int *slotp, unsigned int *funcp)
|
||||
{
|
||||
const char *p;
|
||||
|
@ -581,36 +586,34 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
|
||||
unsigned *slotp)
|
||||
{
|
||||
/* strip legacy tag */
|
||||
if (!strncmp(addr, "pci_addr=", 9)) {
|
||||
addr += 9;
|
||||
}
|
||||
if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) {
|
||||
monitor_printf(mon, "Invalid pci address\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
|
||||
PCIBus *pci_get_bus_devfn(int *devfnp, PCIBus *root, const char *devaddr)
|
||||
{
|
||||
int dom, bus;
|
||||
unsigned slot;
|
||||
|
||||
assert(!root->parent_dev);
|
||||
|
||||
if (!root) {
|
||||
fprintf(stderr, "No primary PCI bus\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!devaddr) {
|
||||
*devfnp = -1;
|
||||
return pci_find_bus_nr(pci_find_root_bus(0), 0);
|
||||
return pci_find_bus_nr(root, 0);
|
||||
}
|
||||
|
||||
if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dom != 0) {
|
||||
fprintf(stderr, "No support for non-zero PCI domains\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*devfnp = PCI_DEVFN(slot, 0);
|
||||
return pci_find_bus_nr(pci_find_root_bus(dom), bus);
|
||||
return pci_find_bus_nr(root, bus);
|
||||
}
|
||||
|
||||
static void pci_init_cmask(PCIDevice *dev)
|
||||
|
@ -1526,11 +1529,11 @@ static PciInfo *qmp_query_pci_bus(PCIBus *bus, int bus_num)
|
|||
PciInfoList *qmp_query_pci(Error **errp)
|
||||
{
|
||||
PciInfoList *info, *head = NULL, *cur_item = NULL;
|
||||
struct PCIHostBus *host;
|
||||
PCIHostState *host_bridge;
|
||||
|
||||
QLIST_FOREACH(host, &host_buses, next) {
|
||||
QLIST_FOREACH(host_bridge, &pci_host_bridges, next) {
|
||||
info = g_malloc0(sizeof(*info));
|
||||
info->value = qmp_query_pci_bus(host->bus, 0);
|
||||
info->value = qmp_query_pci_bus(host_bridge->bus, 0);
|
||||
|
||||
/* XXX: waiting for the qapi to support GSList */
|
||||
if (!cur_item) {
|
||||
|
@ -1570,7 +1573,8 @@ static const char * const pci_nic_names[] = {
|
|||
|
||||
/* Initialize a PCI NIC. */
|
||||
/* FIXME callers should check for failure, but don't */
|
||||
PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
|
||||
PCIDevice *pci_nic_init(NICInfo *nd, PCIBus *rootbus,
|
||||
const char *default_model,
|
||||
const char *default_devaddr)
|
||||
{
|
||||
const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
|
||||
|
@ -1584,7 +1588,7 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
|
|||
if (i < 0)
|
||||
return NULL;
|
||||
|
||||
bus = pci_get_bus_devfn(&devfn, devaddr);
|
||||
bus = pci_get_bus_devfn(&devfn, rootbus, devaddr);
|
||||
if (!bus) {
|
||||
error_report("Invalid PCI device address %s for device %s",
|
||||
devaddr, pci_nic_names[i]);
|
||||
|
@ -1599,7 +1603,8 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
|
|||
return pci_dev;
|
||||
}
|
||||
|
||||
PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
|
||||
PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
|
||||
const char *default_model,
|
||||
const char *default_devaddr)
|
||||
{
|
||||
PCIDevice *res;
|
||||
|
@ -1607,7 +1612,7 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
|
|||
if (qemu_show_nic_models(nd->model, pci_nic_models))
|
||||
exit(0);
|
||||
|
||||
res = pci_nic_init(nd, default_model, default_devaddr);
|
||||
res = pci_nic_init(nd, rootbus, default_model, default_devaddr);
|
||||
if (!res)
|
||||
exit(1);
|
||||
return res;
|
||||
|
@ -1998,10 +2003,10 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
|
|||
for (i = offset; i < offset + size; i++) {
|
||||
overlapping_cap = pci_find_capability_at_offset(pdev, i);
|
||||
if (overlapping_cap) {
|
||||
fprintf(stderr, "ERROR: %04x:%02x:%02x.%x "
|
||||
fprintf(stderr, "ERROR: %s:%02x:%02x.%x "
|
||||
"Attempt to add PCI capability %x at offset "
|
||||
"%x overlaps existing capability %x at offset %x\n",
|
||||
pci_find_domain(pdev->bus), pci_bus_num(pdev->bus),
|
||||
pci_root_bus_path(pdev), pci_bus_num(pdev->bus),
|
||||
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
|
||||
cap_id, offset, overlapping_cap, i);
|
||||
return -EINVAL;
|
||||
|
@ -2135,30 +2140,30 @@ static char *pcibus_get_dev_path(DeviceState *dev)
|
|||
* domain:Bus:Slot.Func for systems without nested PCI bridges.
|
||||
* Slot.Function list specifies the slot and function numbers for all
|
||||
* devices on the path from root to the specific device. */
|
||||
char domain[] = "DDDD:00";
|
||||
const char *root_bus_path;
|
||||
int root_bus_len;
|
||||
char slot[] = ":SS.F";
|
||||
int domain_len = sizeof domain - 1 /* For '\0' */;
|
||||
int slot_len = sizeof slot - 1 /* For '\0' */;
|
||||
int path_len;
|
||||
char *path, *p;
|
||||
int s;
|
||||
|
||||
root_bus_path = pci_root_bus_path(d);
|
||||
root_bus_len = strlen(root_bus_path);
|
||||
|
||||
/* Calculate # of slots on path between device and root. */;
|
||||
slot_depth = 0;
|
||||
for (t = d; t; t = t->bus->parent_dev) {
|
||||
++slot_depth;
|
||||
}
|
||||
|
||||
path_len = domain_len + slot_len * slot_depth;
|
||||
path_len = root_bus_len + slot_len * slot_depth;
|
||||
|
||||
/* Allocate memory, fill in the terminating null byte. */
|
||||
path = g_malloc(path_len + 1 /* For '\0' */);
|
||||
path[path_len] = '\0';
|
||||
|
||||
/* First field is the domain. */
|
||||
s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus));
|
||||
assert(s == domain_len);
|
||||
memcpy(path, domain, domain_len);
|
||||
memcpy(path, root_bus_path, root_bus_len);
|
||||
|
||||
/* Fill in slot numbers. We walk up from device to root, so need to print
|
||||
* them in the reverse order, last to first. */
|
||||
|
@ -2192,11 +2197,11 @@ static int pci_qdev_find_recursive(PCIBus *bus,
|
|||
|
||||
int pci_qdev_find_device(const char *id, PCIDevice **pdev)
|
||||
{
|
||||
struct PCIHostBus *host;
|
||||
PCIHostState *host_bridge;
|
||||
int rc = -ENODEV;
|
||||
|
||||
QLIST_FOREACH(host, &host_buses, next) {
|
||||
int tmp = pci_qdev_find_recursive(host->bus, id, pdev);
|
||||
QLIST_FOREACH(host_bridge, &pci_host_bridges, next) {
|
||||
int tmp = pci_qdev_find_recursive(host_bridge->bus, id, pdev);
|
||||
if (!tmp) {
|
||||
rc = 0;
|
||||
break;
|
||||
|
|
|
@ -169,6 +169,7 @@ static const TypeInfo pci_host_type_info = {
|
|||
.name = TYPE_PCI_HOST_BRIDGE,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(PCIHostBridgeClass),
|
||||
.instance_size = sizeof(PCIHostState),
|
||||
};
|
||||
|
||||
|
|
|
@ -817,9 +817,9 @@ void pcie_aer_inject_error_print(Monitor *mon, const QObject *data)
|
|||
qdict = qobject_to_qdict(data);
|
||||
|
||||
devfn = (int)qdict_get_int(qdict, "devfn");
|
||||
monitor_printf(mon, "OK id: %s domain: %x, bus: %x devfn: %x.%x\n",
|
||||
monitor_printf(mon, "OK id: %s root bus: %s, bus: %x devfn: %x.%x\n",
|
||||
qdict_get_str(qdict, "id"),
|
||||
(int) qdict_get_int(qdict, "domain"),
|
||||
qdict_get_str(qdict, "root_bus"),
|
||||
(int) qdict_get_int(qdict, "bus"),
|
||||
PCI_SLOT(devfn), PCI_FUNC(devfn));
|
||||
}
|
||||
|
@ -1020,10 +1020,9 @@ int do_pcie_aer_inject_error(Monitor *mon,
|
|||
|
||||
ret = pcie_aer_inject_error(dev, &err);
|
||||
*ret_data = qobject_from_jsonf("{'id': %s, "
|
||||
"'domain': %d, 'bus': %d, 'devfn': %d, "
|
||||
"'root_bus': %s, 'bus': %d, 'devfn': %d, "
|
||||
"'ret': %d}",
|
||||
id,
|
||||
pci_find_domain(dev->bus),
|
||||
id, pci_root_bus_path(dev),
|
||||
pci_bus_num(dev->bus), dev->devfn,
|
||||
ret);
|
||||
assert(*ret_data);
|
||||
|
|
|
@ -707,7 +707,7 @@ void ppce500_init(PPCE500Params *params)
|
|||
if (pci_bus) {
|
||||
/* Register network interfaces. */
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -375,7 +375,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
|
|||
escc_mem, 0, memory_region_size(escc_mem));
|
||||
|
||||
for(i = 0; i < nb_nics; i++)
|
||||
pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
|
||||
|
||||
ide_drive_get(hd, MAX_IDE_BUS);
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args)
|
|||
escc_mem, 0, memory_region_size(escc_mem));
|
||||
|
||||
for(i = 0; i < nb_nics; i++)
|
||||
pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
|
||||
|
||||
|
||||
ide_drive_get(hd, MAX_IDE_BUS);
|
||||
|
|
|
@ -243,7 +243,7 @@ static void bamboo_init(QEMUMachineInitArgs *args)
|
|||
for (i = 0; i < nb_nics; i++) {
|
||||
/* There are no PCI NICs on the Bamboo board, but there are
|
||||
* PCI slots, so we can pick whatever default model we want. */
|
||||
pci_nic_init_nofail(&nd_table[i], "e1000", NULL);
|
||||
pci_nic_init_nofail(&nd_table[i], pcibus, "e1000", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -639,7 +639,7 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
|
|||
isa_ne2000_init(isa_bus, ne2000_io[i], ne2000_irq[i],
|
||||
&nd_table[i]);
|
||||
} else {
|
||||
pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -887,7 +887,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
|
|||
if (strcmp(nd->model, "ibmveth") == 0) {
|
||||
spapr_vlan_create(spapr->vio_bus, nd);
|
||||
} else {
|
||||
pci_nic_init_nofail(&nd_table[i], nd->model, NULL);
|
||||
pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -699,11 +699,21 @@ static Property spapr_phb_properties[] = {
|
|||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static const char *spapr_phb_root_bus_path(PCIHostState *host_bridge,
|
||||
PCIBus *rootbus)
|
||||
{
|
||||
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(host_bridge);
|
||||
|
||||
return sphb->dtbusname;
|
||||
}
|
||||
|
||||
static void spapr_phb_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
|
||||
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
hc->root_bus_path = spapr_phb_root_bus_path;
|
||||
sdc->init = spapr_phb_init;
|
||||
dc->props = spapr_phb_properties;
|
||||
dc->reset = spapr_phb_reset;
|
||||
|
|
|
@ -236,6 +236,7 @@ static void r2d_init(QEMUMachineInitArgs *args)
|
|||
DeviceState *dev;
|
||||
SysBusDevice *busdev;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
PCIBus *pci_bus;
|
||||
|
||||
if (cpu_model == NULL) {
|
||||
cpu_model = "SH7751R";
|
||||
|
@ -264,6 +265,7 @@ static void r2d_init(QEMUMachineInitArgs *args)
|
|||
dev = qdev_create(NULL, "sh_pci");
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
qdev_init_nofail(dev);
|
||||
pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci"));
|
||||
sysbus_mmio_map(busdev, 0, P4ADDR(0x1e200000));
|
||||
sysbus_mmio_map(busdev, 1, A7ADDR(0x1e200000));
|
||||
sysbus_connect_irq(busdev, 0, irq[PCI_INTA]);
|
||||
|
@ -295,7 +297,8 @@ static void r2d_init(QEMUMachineInitArgs *args)
|
|||
|
||||
/* NIC: rtl8139 on-board, and 2 slots. */
|
||||
for (i = 0; i < nb_nics; i++)
|
||||
pci_nic_init_nofail(&nd_table[i], "rtl8139", i==0 ? "2" : NULL);
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus,
|
||||
"rtl8139", i==0 ? "2" : NULL);
|
||||
|
||||
/* USB keyboard */
|
||||
usbdevice_create("keyboard");
|
||||
|
|
|
@ -854,7 +854,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
|||
}
|
||||
|
||||
for(i = 0; i < nb_nics; i++)
|
||||
pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
|
||||
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
|
||||
|
||||
ide_drive_get(hd, MAX_IDE_BUS);
|
||||
|
||||
|
|
|
@ -8,8 +8,21 @@
|
|||
#include "net/net.h"
|
||||
#include "hw/i386/ioapic.h"
|
||||
|
||||
#include "qemu/range.h"
|
||||
|
||||
/* PC-style peripherals (also used by other machines). */
|
||||
|
||||
typedef struct PcPciInfo {
|
||||
Range w32;
|
||||
Range w64;
|
||||
} PcPciInfo;
|
||||
|
||||
struct PcGuestInfo {
|
||||
PcPciInfo pci_info;
|
||||
bool has_pci_info;
|
||||
FWCfgState *fw_cfg;
|
||||
};
|
||||
|
||||
/* parallel.c */
|
||||
static inline bool parallel_init(ISABus *bus, int index, CharDriverState *chr)
|
||||
{
|
||||
|
@ -84,6 +97,10 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
|
|||
void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge);
|
||||
void pc_hot_add_cpu(const int64_t id, Error **errp);
|
||||
void pc_acpi_init(const char *default_dsdt);
|
||||
|
||||
PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
|
||||
ram_addr_t above_4g_mem_size);
|
||||
|
||||
FWCfgState *pc_memory_init(MemoryRegion *system_memory,
|
||||
const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
|
@ -91,7 +108,8 @@ FWCfgState *pc_memory_init(MemoryRegion *system_memory,
|
|||
ram_addr_t below_4g_mem_size,
|
||||
ram_addr_t above_4g_mem_size,
|
||||
MemoryRegion *rom_memory,
|
||||
MemoryRegion **ram_memory);
|
||||
MemoryRegion **ram_memory,
|
||||
PcGuestInfo *guest_info);
|
||||
qemu_irq *pc_allocate_cpu_irq(void);
|
||||
DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus);
|
||||
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
|
@ -177,7 +195,7 @@ static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
|
|||
void pc_system_firmware_init(MemoryRegion *rom_memory);
|
||||
|
||||
/* pvpanic.c */
|
||||
int pvpanic_init(ISABus *bus);
|
||||
void pvpanic_init(ISABus *bus);
|
||||
|
||||
/* e820 types */
|
||||
#define E820_RAM 1
|
||||
|
|
|
@ -55,6 +55,7 @@ typedef struct MCHPCIState {
|
|||
uint8_t smm_enabled;
|
||||
ram_addr_t below_4g_mem_size;
|
||||
ram_addr_t above_4g_mem_size;
|
||||
PcGuestInfo *guest_info;
|
||||
} MCHPCIState;
|
||||
|
||||
typedef struct Q35PCIHost {
|
||||
|
@ -81,6 +82,7 @@ typedef struct Q35PCIHost {
|
|||
#define MCH_HOST_BRIDGE_PCIEXBAR 0x60 /* 64bit register */
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_SIZE 8 /* 64bit register */
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT 0xb0000000
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_MAX (0x10000000) /* 256M */
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_ADMSK Q35_MASK(64, 35, 28)
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK ((uint64_t)(1 << 26))
|
||||
#define MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK ((uint64_t)(1 << 25))
|
||||
|
|
|
@ -378,9 +378,11 @@ void pci_device_set_intx_routing_notifier(PCIDevice *dev,
|
|||
void pci_device_reset(PCIDevice *dev);
|
||||
void pci_bus_reset(PCIBus *bus);
|
||||
|
||||
PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
|
||||
PCIDevice *pci_nic_init(NICInfo *nd, PCIBus *rootbus,
|
||||
const char *default_model,
|
||||
const char *default_devaddr);
|
||||
PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
|
||||
PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
|
||||
const char *default_model,
|
||||
const char *default_devaddr);
|
||||
|
||||
PCIDevice *pci_vga_init(PCIBus *bus);
|
||||
|
@ -389,14 +391,15 @@ int pci_bus_num(PCIBus *s);
|
|||
void pci_for_each_device(PCIBus *bus, int bus_num,
|
||||
void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque),
|
||||
void *opaque);
|
||||
PCIBus *pci_find_root_bus(int domain);
|
||||
int pci_find_domain(const PCIBus *bus);
|
||||
PCIBus *pci_find_primary_bus(void);
|
||||
PCIBus *pci_device_root_bus(const PCIDevice *d);
|
||||
const char *pci_root_bus_path(PCIDevice *dev);
|
||||
PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
|
||||
int pci_qdev_find_device(const char *id, PCIDevice **pdev);
|
||||
PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
|
||||
PCIBus *pci_get_bus_devfn(int *devfnp, PCIBus *root, const char *devaddr);
|
||||
|
||||
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
|
||||
unsigned *slotp);
|
||||
int pci_parse_devaddr(const char *addr, int *domp, int *busp,
|
||||
unsigned int *slotp, unsigned int *funcp);
|
||||
|
||||
void pci_device_deassert_intx(PCIDevice *dev);
|
||||
|
||||
|
|
|
@ -33,6 +33,10 @@
|
|||
#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge"
|
||||
#define PCI_HOST_BRIDGE(obj) \
|
||||
OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE)
|
||||
#define PCI_HOST_BRIDGE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(PCIHostBridgeClass, (klass), TYPE_PCI_HOST_BRIDGE)
|
||||
#define PCI_HOST_BRIDGE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(PCIHostBridgeClass, (obj), TYPE_PCI_HOST_BRIDGE)
|
||||
|
||||
struct PCIHostState {
|
||||
SysBusDevice busdev;
|
||||
|
@ -42,8 +46,16 @@ struct PCIHostState {
|
|||
MemoryRegion mmcfg;
|
||||
uint32_t config_reg;
|
||||
PCIBus *bus;
|
||||
|
||||
QLIST_ENTRY(PCIHostState) next;
|
||||
};
|
||||
|
||||
typedef struct PCIHostBridgeClass {
|
||||
SysBusDeviceClass parent_class;
|
||||
|
||||
const char *(*root_bus_path)(PCIHostState *, PCIBus *);
|
||||
} PCIHostBridgeClass;
|
||||
|
||||
/* common internal helpers for PCI/PCIe hosts, cut off overflows */
|
||||
void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
|
||||
uint32_t limit, uint32_t val, uint32_t len);
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
#ifndef QEMU_RANGE_H
|
||||
#define QEMU_RANGE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/*
|
||||
* Operations on 64 bit address ranges.
|
||||
* Notes:
|
||||
* - ranges must not wrap around 0, but can include the last byte ~0x0LL.
|
||||
* - this can not represent a full 0 to ~0x0LL range.
|
||||
*/
|
||||
|
||||
/* A structure representing a range of addresses. */
|
||||
struct Range {
|
||||
uint64_t begin; /* First byte of the range, or 0 if empty. */
|
||||
uint64_t end; /* 1 + the last byte. 0 if range empty or ends at ~0x0LL. */
|
||||
};
|
||||
typedef struct Range Range;
|
||||
|
||||
/* Get last byte of a range from offset + length.
|
||||
* Undefined for ranges that wrap around 0. */
|
||||
static inline uint64_t range_get_last(uint64_t offset, uint64_t len)
|
||||
|
|
|
@ -64,5 +64,6 @@ typedef struct VirtIODevice VirtIODevice;
|
|||
typedef struct QEMUSGList QEMUSGList;
|
||||
typedef struct SHPCDevice SHPCDevice;
|
||||
typedef struct FWCfgState FWCfgState;
|
||||
typedef struct PcGuestInfo PcGuestInfo;
|
||||
|
||||
#endif /* QEMU_TYPEDEFS_H */
|
||||
|
|
Loading…
Reference in New Issue