virtio, vhost, pci: fixes, features
generic pci root port support disable shpc by default safer version of ARRAY_SIZE and QEMU_BUILD_BUG_ON fixes and cleanups all over the place Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJYkTwaAAoJECgfDbjSjVRpHHoIALlEhk7iZJvjJBiT0BQ51lGB uU0fq+8H2G+WZoM83dpSv/pG1Ob6SZtiehsXWf+6Za+AgnU3STCZDXGKo9Jxs2EO jp73puewWCq69VMyjGnGEWWh4bf41xjWYVrhVrY9LSz7u6hCM9sdWPRy/PGLSlLo s3xgYefGdtol0S5qMdb4LOb2tfcdGYHADyMiERT994pmfZKrBMXlHlVM0jOo5ytw zknRh4JwH+zZMQPczrvWUTjdxRE0UIUd4fFz9cRwX8F6zVpAbKAT2Ird2jGNlpyh jQBX+sxXQR3u+mjZDxZBYbpxOZARUTriagAJPs343uIUCPOmvVXsluidF9bkU+A= =ZBEs -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging virtio, vhost, pci: fixes, features generic pci root port support disable shpc by default safer version of ARRAY_SIZE and QEMU_BUILD_BUG_ON fixes and cleanups all over the place Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Wed 01 Feb 2017 01:38:34 GMT # gpg: using RSA key 0x281F0DB8D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * remotes/mst/tags/for_upstream: (22 commits) arm: add trailing ; after MISMATCH_CHECK arm: better stub version for MISMATCH_CHECK hw/pci: disable pci-bridge's shpc by default vhost-user: delete chardev on cleanup vhost: skip ROM sections virtio: make virtio_should_notify static pci: Convert msix_init() to Error and fix callers hcd-xhci: check & correct param before using it msix: Follow CODING_STYLE hw/i386: check if nvdimm is enabled before plugging hw/pcie: Introduce Generic PCI Express Root Port hw/ioh3420: derive from PCI Express Root Port base class hw/pcie: Introduce a base class for PCI Express Root Ports intel_iommu: fix and simplify size calculation in process_device_iotlb_desc() pci: mark ROMs read-only ARRAY_SIZE: check that argument is an array compiler: expression version of QEMU_BUILD_BUG_ON compiler: rework BUG_ON using a struct QEMU_BUILD_BUG_ON: use __COUNTER__ ppc: switch to constants within BUILD_BUG_ON ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e905587b75
@ -108,6 +108,7 @@ CONFIG_FSL_IMX25=y
|
||||
|
||||
CONFIG_IMX_I2C=y
|
||||
|
||||
CONFIG_PCIE_PORT=y
|
||||
CONFIG_XIO3130=y
|
||||
CONFIG_IOH3420=y
|
||||
CONFIG_I82801B11=y
|
||||
|
@ -51,6 +51,7 @@ CONFIG_PVPANIC=y
|
||||
CONFIG_MEM_HOTPLUG=y
|
||||
CONFIG_NVDIMM=y
|
||||
CONFIG_ACPI_NVDIMM=y
|
||||
CONFIG_PCIE_PORT=y
|
||||
CONFIG_XIO3130=y
|
||||
CONFIG_IOH3420=y
|
||||
CONFIG_I82801B11=y
|
||||
|
@ -51,6 +51,7 @@ CONFIG_PVPANIC=y
|
||||
CONFIG_MEM_HOTPLUG=y
|
||||
CONFIG_NVDIMM=y
|
||||
CONFIG_ACPI_NVDIMM=y
|
||||
CONFIG_PCIE_PORT=y
|
||||
CONFIG_XIO3130=y
|
||||
CONFIG_IOH3420=y
|
||||
CONFIG_I82801B11=y
|
||||
|
@ -872,7 +872,7 @@ static int nvme_init(PCIDevice *pci_dev)
|
||||
pci_register_bar(&n->parent_obj, 0,
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64,
|
||||
&n->iomem);
|
||||
msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4);
|
||||
msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4, NULL);
|
||||
|
||||
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
|
||||
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
|
||||
|
@ -306,12 +306,11 @@ void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
|
||||
|
||||
static ram_addr_t qxl_rom_size(void)
|
||||
{
|
||||
uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) +
|
||||
sizeof(qxl_modes);
|
||||
uint32_t rom_size = 8192; /* two pages */
|
||||
#define QXL_REQUIRED_SZ (sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes))
|
||||
#define QXL_ROM_SZ 8192
|
||||
|
||||
QEMU_BUILD_BUG_ON(required_rom_size > rom_size);
|
||||
return rom_size;
|
||||
QEMU_BUILD_BUG_ON(QXL_REQUIRED_SZ > QXL_ROM_SZ);
|
||||
return QXL_ROM_SZ;
|
||||
}
|
||||
|
||||
static void init_qxl_rom(PCIQXLDevice *d)
|
||||
|
@ -1485,8 +1485,16 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* According to ATS spec table 2.4:
|
||||
* S = 0, bits 15:12 = xxxx range size: 4K
|
||||
* S = 1, bits 15:12 = xxx0 range size: 8K
|
||||
* S = 1, bits 15:12 = xx01 range size: 16K
|
||||
* S = 1, bits 15:12 = x011 range size: 32K
|
||||
* S = 1, bits 15:12 = 0111 range size: 64K
|
||||
* ...
|
||||
*/
|
||||
if (size) {
|
||||
sz = 1 << (ctz64(~(addr | (VTD_PAGE_MASK_4K - 1))) + 1);
|
||||
sz = (VTD_PAGE_SIZE * 2) << cto64(addr >> VTD_PAGE_SHIFT);
|
||||
addr &= ~(sz - 1);
|
||||
} else {
|
||||
sz = VTD_PAGE_SIZE;
|
||||
|
@ -1708,6 +1708,11 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
|
||||
}
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
|
||||
if (!pcms->acpi_nvdimm_state.is_enabled) {
|
||||
error_setg(&local_err,
|
||||
"nvdimm is not enabled: missing 'nvdimm' in '-M'");
|
||||
goto out;
|
||||
}
|
||||
nvdimm_plug(&pcms->acpi_nvdimm_state);
|
||||
}
|
||||
|
||||
|
@ -749,13 +749,13 @@ static void ivshmem_reset(DeviceState *d)
|
||||
}
|
||||
}
|
||||
|
||||
static int ivshmem_setup_interrupts(IVShmemState *s)
|
||||
static int ivshmem_setup_interrupts(IVShmemState *s, Error **errp)
|
||||
{
|
||||
/* allocate QEMU callback data for receiving interrupts */
|
||||
s->msi_vectors = g_malloc0(s->vectors * sizeof(MSIVector));
|
||||
|
||||
if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
|
||||
if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1)) {
|
||||
if (msix_init_exclusive_bar(PCI_DEVICE(s), s->vectors, 1, errp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -898,8 +898,8 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
|
||||
qemu_chr_fe_set_handlers(&s->server_chr, ivshmem_can_receive,
|
||||
ivshmem_read, NULL, s, NULL, true);
|
||||
|
||||
if (ivshmem_setup_interrupts(s) < 0) {
|
||||
error_setg(errp, "failed to initialize interrupts");
|
||||
if (ivshmem_setup_interrupts(s, errp) < 0) {
|
||||
error_prepend(errp, "Failed to initialize interrupts: ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ e1000e_init_msix(E1000EState *s)
|
||||
E1000E_MSIX_IDX, E1000E_MSIX_TABLE,
|
||||
&s->msix,
|
||||
E1000E_MSIX_IDX, E1000E_MSIX_PBA,
|
||||
0xA0);
|
||||
0xA0, NULL);
|
||||
|
||||
if (res < 0) {
|
||||
trace_e1000e_msix_init_fail(res);
|
||||
|
@ -1256,14 +1256,16 @@ static int rocker_msix_init(Rocker *r)
|
||||
{
|
||||
PCIDevice *dev = PCI_DEVICE(r);
|
||||
int err;
|
||||
Error *local_err = NULL;
|
||||
|
||||
err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
|
||||
&r->msix_bar,
|
||||
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
|
||||
&r->msix_bar,
|
||||
ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
|
||||
0);
|
||||
0, &local_err);
|
||||
if (err) {
|
||||
error_report_err(local_err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -2191,7 +2191,7 @@ vmxnet3_init_msix(VMXNET3State *s)
|
||||
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
|
||||
&s->msix_bar,
|
||||
VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s),
|
||||
VMXNET3_MSIX_OFFSET(s));
|
||||
VMXNET3_MSIX_OFFSET(s), NULL);
|
||||
|
||||
if (0 > res) {
|
||||
VMW_WRPRN("Failed to initialize MSI-X, error %d", res);
|
||||
|
@ -1,5 +1,6 @@
|
||||
common-obj-y += pci_bridge_dev.o
|
||||
common-obj-y += pci_expander_bridge.o
|
||||
common-obj-$(CONFIG_PCIE_PORT) += pcie_root_port.o gen_pcie_root_port.o
|
||||
common-obj-$(CONFIG_XIO3130) += xio3130_upstream.o xio3130_downstream.o
|
||||
common-obj-$(CONFIG_IOH3420) += ioh3420.o
|
||||
common-obj-$(CONFIG_I82801B11) += i82801b11.o
|
||||
|
87
hw/pci-bridge/gen_pcie_root_port.c
Normal file
87
hw/pci-bridge/gen_pcie_root_port.c
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Generic PCI Express Root Port emulation
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat Inc
|
||||
*
|
||||
* Authors:
|
||||
* Marcel Apfelbaum <marcel@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/pci/msix.h"
|
||||
#include "hw/pci/pcie_port.h"
|
||||
|
||||
#define TYPE_GEN_PCIE_ROOT_PORT "pcie-root-port"
|
||||
|
||||
#define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100
|
||||
#define GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR 1
|
||||
|
||||
static uint8_t gen_rp_aer_vector(const PCIDevice *d)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen_rp_interrupts_init(PCIDevice *d, Error **errp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = msix_init_exclusive_bar(d, GEN_PCIE_ROOT_PORT_MSIX_NR_VECTOR, 0, errp);
|
||||
|
||||
if (rc < 0) {
|
||||
assert(rc == -ENOTSUP);
|
||||
} else {
|
||||
msix_vector_use(d, 0);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void gen_rp_interrupts_uninit(PCIDevice *d)
|
||||
{
|
||||
msix_uninit_exclusive_bar(d);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_rp_dev = {
|
||||
.name = "pcie-root-port",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = pcie_cap_slot_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot),
|
||||
VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log,
|
||||
PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void gen_rp_dev_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
|
||||
|
||||
k->vendor_id = PCI_VENDOR_ID_REDHAT;
|
||||
k->device_id = PCI_DEVICE_ID_REDHAT_PCIE_RP;
|
||||
dc->desc = "PCI Express Root Port";
|
||||
dc->vmsd = &vmstate_rp_dev;
|
||||
rpc->aer_vector = gen_rp_aer_vector;
|
||||
rpc->interrupts_init = gen_rp_interrupts_init;
|
||||
rpc->interrupts_uninit = gen_rp_interrupts_uninit;
|
||||
rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET;
|
||||
}
|
||||
|
||||
static const TypeInfo gen_rp_dev_info = {
|
||||
.name = TYPE_GEN_PCIE_ROOT_PORT,
|
||||
.parent = TYPE_PCIE_ROOT_PORT,
|
||||
.class_init = gen_rp_dev_class_init,
|
||||
};
|
||||
|
||||
static void gen_rp_register_types(void)
|
||||
{
|
||||
type_register_static(&gen_rp_dev_info);
|
||||
}
|
||||
type_init(gen_rp_register_types)
|
@ -61,119 +61,28 @@ static uint8_t ioh3420_aer_vector(const PCIDevice *d)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ioh3420_aer_vector_update(PCIDevice *d)
|
||||
static int ioh3420_interrupts_init(PCIDevice *d, Error **errp)
|
||||
{
|
||||
pcie_aer_root_set_vector(d, ioh3420_aer_vector(d));
|
||||
}
|
||||
|
||||
static void ioh3420_write_config(PCIDevice *d,
|
||||
uint32_t address, uint32_t val, int len)
|
||||
{
|
||||
uint32_t root_cmd =
|
||||
pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
|
||||
|
||||
pci_bridge_write_config(d, address, val, len);
|
||||
ioh3420_aer_vector_update(d);
|
||||
pcie_cap_slot_write_config(d, address, val, len);
|
||||
pcie_aer_write_config(d, address, val, len);
|
||||
pcie_aer_root_write_config(d, address, val, len, root_cmd);
|
||||
}
|
||||
|
||||
static void ioh3420_reset(DeviceState *qdev)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(qdev);
|
||||
|
||||
ioh3420_aer_vector_update(d);
|
||||
pcie_cap_root_reset(d);
|
||||
pcie_cap_deverr_reset(d);
|
||||
pcie_cap_slot_reset(d);
|
||||
pcie_cap_arifwd_reset(d);
|
||||
pcie_aer_root_reset(d);
|
||||
pci_bridge_reset(qdev);
|
||||
pci_bridge_disable_base_limit(d);
|
||||
}
|
||||
|
||||
static int ioh3420_initfn(PCIDevice *d)
|
||||
{
|
||||
PCIEPort *p = PCIE_PORT(d);
|
||||
PCIESlot *s = PCIE_SLOT(d);
|
||||
int rc;
|
||||
Error *err = NULL;
|
||||
|
||||
pci_config_set_interrupt_pin(d->config, 1);
|
||||
pci_bridge_initfn(d, TYPE_PCIE_BUS);
|
||||
pcie_port_init_reg(d);
|
||||
|
||||
rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
|
||||
IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
|
||||
if (rc < 0) {
|
||||
goto err_bridge;
|
||||
}
|
||||
Error *local_err = NULL;
|
||||
|
||||
rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
|
||||
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
|
||||
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err);
|
||||
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT,
|
||||
&local_err);
|
||||
if (rc < 0) {
|
||||
assert(rc == -ENOTSUP);
|
||||
error_report_err(err);
|
||||
goto err_bridge;
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
|
||||
if (rc < 0) {
|
||||
goto err_msi;
|
||||
}
|
||||
|
||||
pcie_cap_arifwd_init(d);
|
||||
pcie_cap_deverr_init(d);
|
||||
pcie_cap_slot_init(d, s->slot);
|
||||
pcie_cap_root_init(d);
|
||||
|
||||
pcie_chassis_create(s->chassis);
|
||||
rc = pcie_chassis_add_slot(s);
|
||||
if (rc < 0) {
|
||||
goto err_pcie_cap;
|
||||
}
|
||||
|
||||
rc = pcie_aer_init(d, PCI_ERR_VER, IOH_EP_AER_OFFSET,
|
||||
PCI_ERR_SIZEOF, &err);
|
||||
if (rc < 0) {
|
||||
error_report_err(err);
|
||||
goto err;
|
||||
}
|
||||
pcie_aer_root_init(d);
|
||||
ioh3420_aer_vector_update(d);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
pcie_chassis_del_slot(s);
|
||||
err_pcie_cap:
|
||||
pcie_cap_exit(d);
|
||||
err_msi:
|
||||
msi_uninit(d);
|
||||
err_bridge:
|
||||
pci_bridge_exitfn(d);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ioh3420_exitfn(PCIDevice *d)
|
||||
static void ioh3420_interrupts_uninit(PCIDevice *d)
|
||||
{
|
||||
PCIESlot *s = PCIE_SLOT(d);
|
||||
|
||||
pcie_aer_exit(d);
|
||||
pcie_chassis_del_slot(s);
|
||||
pcie_cap_exit(d);
|
||||
msi_uninit(d);
|
||||
pci_bridge_exitfn(d);
|
||||
}
|
||||
|
||||
static Property ioh3420_props[] = {
|
||||
DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
|
||||
QEMU_PCIE_SLTCAP_PCP_BITNR, true),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_ioh3420 = {
|
||||
.name = "ioh-3240-express-root-port",
|
||||
.version_id = 1,
|
||||
@ -191,25 +100,25 @@ static void ioh3420_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass);
|
||||
|
||||
k->is_express = 1;
|
||||
k->is_bridge = 1;
|
||||
k->config_write = ioh3420_write_config;
|
||||
k->init = ioh3420_initfn;
|
||||
k->exit = ioh3420_exitfn;
|
||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||
k->device_id = PCI_DEVICE_ID_IOH_EPORT;
|
||||
k->revision = PCI_DEVICE_ID_IOH_REV;
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
dc->desc = "Intel IOH device id 3420 PCIE Root Port";
|
||||
dc->reset = ioh3420_reset;
|
||||
dc->vmsd = &vmstate_ioh3420;
|
||||
dc->props = ioh3420_props;
|
||||
rpc->aer_vector = ioh3420_aer_vector;
|
||||
rpc->interrupts_init = ioh3420_interrupts_init;
|
||||
rpc->interrupts_uninit = ioh3420_interrupts_uninit;
|
||||
rpc->exp_offset = IOH_EP_EXP_OFFSET;
|
||||
rpc->aer_offset = IOH_EP_AER_OFFSET;
|
||||
rpc->ssvid_offset = IOH_EP_SSVID_OFFSET;
|
||||
rpc->ssid = IOH_EP_SSVID_SSID;
|
||||
}
|
||||
|
||||
static const TypeInfo ioh3420_info = {
|
||||
.name = "ioh3420",
|
||||
.parent = TYPE_PCIE_SLOT,
|
||||
.parent = TYPE_PCIE_ROOT_PORT,
|
||||
.class_init = ioh3420_class_init,
|
||||
};
|
||||
|
||||
|
@ -163,7 +163,7 @@ static Property pci_bridge_dev_properties[] = {
|
||||
DEFINE_PROP_ON_OFF_AUTO(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, msi,
|
||||
ON_OFF_AUTO_AUTO),
|
||||
DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_SHPC, PCIBridgeDev, flags,
|
||||
PCI_BRIDGE_DEV_F_SHPC_REQ, true),
|
||||
PCI_BRIDGE_DEV_F_SHPC_REQ, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
171
hw/pci-bridge/pcie_root_port.c
Normal file
171
hw/pci-bridge/pcie_root_port.c
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Base class for PCI Express Root Ports
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat Inc
|
||||
*
|
||||
* Authors:
|
||||
* Marcel Apfelbaum <marcel@redhat.com>
|
||||
*
|
||||
* Most of the code was migrated from hw/pci-bridge/ioh3420.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/pci/pcie_port.h"
|
||||
|
||||
static void rp_aer_vector_update(PCIDevice *d)
|
||||
{
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
|
||||
|
||||
if (rpc->aer_vector) {
|
||||
pcie_aer_root_set_vector(d, rpc->aer_vector(d));
|
||||
}
|
||||
}
|
||||
|
||||
static void rp_write_config(PCIDevice *d, uint32_t address,
|
||||
uint32_t val, int len)
|
||||
{
|
||||
uint32_t root_cmd =
|
||||
pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
|
||||
|
||||
pci_bridge_write_config(d, address, val, len);
|
||||
rp_aer_vector_update(d);
|
||||
pcie_cap_slot_write_config(d, address, val, len);
|
||||
pcie_aer_write_config(d, address, val, len);
|
||||
pcie_aer_root_write_config(d, address, val, len, root_cmd);
|
||||
}
|
||||
|
||||
static void rp_reset(DeviceState *qdev)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(qdev);
|
||||
|
||||
rp_aer_vector_update(d);
|
||||
pcie_cap_root_reset(d);
|
||||
pcie_cap_deverr_reset(d);
|
||||
pcie_cap_slot_reset(d);
|
||||
pcie_cap_arifwd_reset(d);
|
||||
pcie_aer_root_reset(d);
|
||||
pci_bridge_reset(qdev);
|
||||
pci_bridge_disable_base_limit(d);
|
||||
}
|
||||
|
||||
static void rp_realize(PCIDevice *d, Error **errp)
|
||||
{
|
||||
PCIEPort *p = PCIE_PORT(d);
|
||||
PCIESlot *s = PCIE_SLOT(d);
|
||||
PCIDeviceClass *dc = PCI_DEVICE_GET_CLASS(d);
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
|
||||
int rc;
|
||||
Error *local_err = NULL;
|
||||
|
||||
pci_config_set_interrupt_pin(d->config, 1);
|
||||
pci_bridge_initfn(d, TYPE_PCIE_BUS);
|
||||
pcie_port_init_reg(d);
|
||||
|
||||
rc = pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id, rpc->ssid);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "Can't init SSV ID, error %d", rc);
|
||||
goto err_bridge;
|
||||
}
|
||||
|
||||
if (rpc->interrupts_init) {
|
||||
rc = rpc->interrupts_init(d, &local_err);
|
||||
if (rc < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto err_bridge;
|
||||
}
|
||||
}
|
||||
|
||||
rc = pcie_cap_init(d, rpc->exp_offset, PCI_EXP_TYPE_ROOT_PORT, p->port);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "Can't add Root Port capability, error %d", rc);
|
||||
goto err_int;
|
||||
}
|
||||
|
||||
pcie_cap_arifwd_init(d);
|
||||
pcie_cap_deverr_init(d);
|
||||
pcie_cap_slot_init(d, s->slot);
|
||||
pcie_cap_root_init(d);
|
||||
|
||||
pcie_chassis_create(s->chassis);
|
||||
rc = pcie_chassis_add_slot(s);
|
||||
if (rc < 0) {
|
||||
error_setg(errp, "Can't add chassis slot, error %d", rc);
|
||||
goto err_pcie_cap;
|
||||
}
|
||||
|
||||
rc = pcie_aer_init(d, PCI_ERR_VER, rpc->aer_offset,
|
||||
PCI_ERR_SIZEOF, &local_err);
|
||||
if (rc < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto err;
|
||||
}
|
||||
pcie_aer_root_init(d);
|
||||
rp_aer_vector_update(d);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
pcie_chassis_del_slot(s);
|
||||
err_pcie_cap:
|
||||
pcie_cap_exit(d);
|
||||
err_int:
|
||||
if (rpc->interrupts_uninit) {
|
||||
rpc->interrupts_uninit(d);
|
||||
}
|
||||
err_bridge:
|
||||
pci_bridge_exitfn(d);
|
||||
}
|
||||
|
||||
static void rp_exit(PCIDevice *d)
|
||||
{
|
||||
PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
|
||||
PCIESlot *s = PCIE_SLOT(d);
|
||||
|
||||
pcie_aer_exit(d);
|
||||
pcie_chassis_del_slot(s);
|
||||
pcie_cap_exit(d);
|
||||
if (rpc->interrupts_uninit) {
|
||||
rpc->interrupts_uninit(d);
|
||||
}
|
||||
pci_bridge_exitfn(d);
|
||||
}
|
||||
|
||||
static Property rp_props[] = {
|
||||
DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
|
||||
QEMU_PCIE_SLTCAP_PCP_BITNR, true),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void rp_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->is_express = 1;
|
||||
k->is_bridge = 1;
|
||||
k->config_write = rp_write_config;
|
||||
k->realize = rp_realize;
|
||||
k->exit = rp_exit;
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
dc->reset = rp_reset;
|
||||
dc->props = rp_props;
|
||||
}
|
||||
|
||||
static const TypeInfo rp_info = {
|
||||
.name = TYPE_PCIE_ROOT_PORT,
|
||||
.parent = TYPE_PCIE_SLOT,
|
||||
.class_init = rp_class_init,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(PCIERootPortClass),
|
||||
};
|
||||
|
||||
static void rp_register_types(void)
|
||||
{
|
||||
type_register_static(&rp_info);
|
||||
}
|
||||
|
||||
type_init(rp_register_types)
|
@ -21,6 +21,7 @@
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define MSIX_CAP_LENGTH 12
|
||||
|
||||
@ -238,11 +239,31 @@ static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the MSI-X structures */
|
||||
/*
|
||||
* Make PCI device @dev MSI-X capable
|
||||
* @nentries is the max number of MSI-X vectors that the device support.
|
||||
* @table_bar is the MemoryRegion that MSI-X table structure resides.
|
||||
* @table_bar_nr is number of base address register corresponding to @table_bar.
|
||||
* @table_offset indicates the offset that the MSI-X table structure starts with
|
||||
* in @table_bar.
|
||||
* @pba_bar is the MemoryRegion that the Pending Bit Array structure resides.
|
||||
* @pba_bar_nr is number of base address register corresponding to @pba_bar.
|
||||
* @pba_offset indicates the offset that the Pending Bit Array structure
|
||||
* starts with in @pba_bar.
|
||||
* Non-zero @cap_pos puts capability MSI-X at that offset in PCI config space.
|
||||
* @errp is for returning errors.
|
||||
*
|
||||
* Return 0 on success; set @errp and return -errno on error:
|
||||
* -ENOTSUP means lacking msi support for a msi-capable platform.
|
||||
* -EINVAL means capability overlap, happens when @cap_pos is non-zero,
|
||||
* also means a programming error, except device assignment, which can check
|
||||
* if a real HW is broken.
|
||||
*/
|
||||
int msix_init(struct PCIDevice *dev, unsigned short nentries,
|
||||
MemoryRegion *table_bar, uint8_t table_bar_nr,
|
||||
unsigned table_offset, MemoryRegion *pba_bar,
|
||||
uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos)
|
||||
uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos,
|
||||
Error **errp)
|
||||
{
|
||||
int cap;
|
||||
unsigned table_size, pba_size;
|
||||
@ -250,10 +271,12 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
|
||||
|
||||
/* Nothing to do if MSI is not supported by interrupt controller */
|
||||
if (!msi_nonbroken) {
|
||||
error_setg(errp, "MSI-X is not supported by interrupt controller");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) {
|
||||
error_setg(errp, "The number of MSI-X vectors is invalid");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -266,10 +289,13 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
|
||||
table_offset + table_size > memory_region_size(table_bar) ||
|
||||
pba_offset + pba_size > memory_region_size(pba_bar) ||
|
||||
(table_offset | pba_offset) & PCI_MSIX_FLAGS_BIRMASK) {
|
||||
error_setg(errp, "table & pba overlap, or they don't fit in BARs,"
|
||||
" or don't align");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cap = pci_add_capability(dev, PCI_CAP_ID_MSIX, cap_pos, MSIX_CAP_LENGTH);
|
||||
cap = pci_add_capability2(dev, PCI_CAP_ID_MSIX,
|
||||
cap_pos, MSIX_CAP_LENGTH, errp);
|
||||
if (cap < 0) {
|
||||
return cap;
|
||||
}
|
||||
@ -306,7 +332,7 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
|
||||
}
|
||||
|
||||
int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
|
||||
uint8_t bar_nr)
|
||||
uint8_t bar_nr, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
char *name;
|
||||
@ -338,7 +364,7 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
|
||||
ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
|
||||
0, &dev->msix_exclusive_bar,
|
||||
bar_nr, bar_pba_offset,
|
||||
0);
|
||||
0, errp);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
@ -447,8 +473,10 @@ void msix_notify(PCIDevice *dev, unsigned vector)
|
||||
{
|
||||
MSIMessage msg;
|
||||
|
||||
if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
|
||||
if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msix_is_masked(dev, vector)) {
|
||||
msix_set_pending(dev, vector);
|
||||
return;
|
||||
@ -483,8 +511,10 @@ void msix_reset(PCIDevice *dev)
|
||||
/* Mark vector as used. */
|
||||
int msix_vector_use(PCIDevice *dev, unsigned vector)
|
||||
{
|
||||
if (vector >= dev->msix_entries_nr)
|
||||
if (vector >= dev->msix_entries_nr) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev->msix_entry_used[vector]++;
|
||||
return 0;
|
||||
}
|
||||
|
@ -2195,7 +2195,7 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom,
|
||||
snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev)));
|
||||
}
|
||||
pdev->has_rom = true;
|
||||
memory_region_init_ram(&pdev->rom, OBJECT(pdev), name, size, &error_fatal);
|
||||
memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, size, &error_fatal);
|
||||
vmstate_register_ram(&pdev->rom, &pdev->qdev);
|
||||
ptr = memory_region_get_ram_ptr(&pdev->rom);
|
||||
load_image(path, ptr);
|
||||
|
@ -2630,8 +2630,8 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
|
||||
* 1TiB 64-bit MMIO windows for each PHB.
|
||||
*/
|
||||
const uint64_t base_buid = 0x800000020000000ULL;
|
||||
const int max_phbs =
|
||||
(SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / SPAPR_PCI_MEM64_WIN_SIZE - 1;
|
||||
#define SPAPR_MAX_PHBS ((SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / \
|
||||
SPAPR_PCI_MEM64_WIN_SIZE - 1)
|
||||
int i;
|
||||
|
||||
/* Sanity check natural alignments */
|
||||
@ -2640,12 +2640,14 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
|
||||
QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM64_WIN_SIZE % SPAPR_PCI_MEM32_WIN_SIZE) != 0);
|
||||
QEMU_BUILD_BUG_ON((SPAPR_PCI_MEM32_WIN_SIZE % SPAPR_PCI_IO_WIN_SIZE) != 0);
|
||||
/* Sanity check bounds */
|
||||
QEMU_BUILD_BUG_ON((max_phbs * SPAPR_PCI_IO_WIN_SIZE) > SPAPR_PCI_MEM32_WIN_SIZE);
|
||||
QEMU_BUILD_BUG_ON((max_phbs * SPAPR_PCI_MEM32_WIN_SIZE) > SPAPR_PCI_MEM64_WIN_SIZE);
|
||||
QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_IO_WIN_SIZE) >
|
||||
SPAPR_PCI_MEM32_WIN_SIZE);
|
||||
QEMU_BUILD_BUG_ON((SPAPR_MAX_PHBS * SPAPR_PCI_MEM32_WIN_SIZE) >
|
||||
SPAPR_PCI_MEM64_WIN_SIZE);
|
||||
|
||||
if (index >= max_phbs) {
|
||||
error_setg(errp, "\"index\" for PAPR PHB is too large (max %u)",
|
||||
max_phbs - 1);
|
||||
if (index >= SPAPR_MAX_PHBS) {
|
||||
error_setg(errp, "\"index\" for PAPR PHB is too large (max %llu)",
|
||||
SPAPR_MAX_PHBS - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2367,9 +2367,11 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
|
||||
|
||||
if (megasas_use_msix(s) &&
|
||||
msix_init(dev, 15, &s->mmio_io, b->mmio_bar, 0x2000,
|
||||
&s->mmio_io, b->mmio_bar, 0x3800, 0x68)) {
|
||||
&s->mmio_io, b->mmio_bar, 0x3800, 0x68, NULL)) {
|
||||
/* TODO: check msix_init's error, and should fail on msix=on */
|
||||
s->msix = ON_OFF_AUTO_OFF;
|
||||
}
|
||||
|
||||
if (pci_is_express(dev)) {
|
||||
pcie_endpoint_cap_init(dev, 0xa0);
|
||||
}
|
||||
|
@ -3627,25 +3627,6 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
|
||||
dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
|
||||
dev->config[0x60] = 0x30; /* release number */
|
||||
|
||||
usb_xhci_init(xhci);
|
||||
|
||||
if (xhci->msi != ON_OFF_AUTO_OFF) {
|
||||
ret = msi_init(dev, 0x70, xhci->numintrs, true, false, &err);
|
||||
/* Any error other than -ENOTSUP(board's MSI support is broken)
|
||||
* is a programming error */
|
||||
assert(!ret || ret == -ENOTSUP);
|
||||
if (ret && xhci->msi == ON_OFF_AUTO_ON) {
|
||||
/* Can't satisfy user's explicit msi=on request, fail */
|
||||
error_append_hint(&err, "You have to use msi=auto (default) or "
|
||||
"msi=off with this machine type.\n");
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
assert(!err || xhci->msi == ON_OFF_AUTO_AUTO);
|
||||
/* With msi=auto, we fall back to MSI off silently */
|
||||
error_free(err);
|
||||
}
|
||||
|
||||
if (xhci->numintrs > MAXINTRS) {
|
||||
xhci->numintrs = MAXINTRS;
|
||||
}
|
||||
@ -3667,6 +3648,24 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
|
||||
xhci->max_pstreams_mask = 0;
|
||||
}
|
||||
|
||||
if (xhci->msi != ON_OFF_AUTO_OFF) {
|
||||
ret = msi_init(dev, 0x70, xhci->numintrs, true, false, &err);
|
||||
/* Any error other than -ENOTSUP(board's MSI support is broken)
|
||||
* is a programming error */
|
||||
assert(!ret || ret == -ENOTSUP);
|
||||
if (ret && xhci->msi == ON_OFF_AUTO_ON) {
|
||||
/* Can't satisfy user's explicit msi=on request, fail */
|
||||
error_append_hint(&err, "You have to use msi=auto (default) or "
|
||||
"msi=off with this machine type.\n");
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
assert(!err || xhci->msi == ON_OFF_AUTO_AUTO);
|
||||
/* With msi=auto, we fall back to MSI off silently */
|
||||
error_free(err);
|
||||
}
|
||||
|
||||
usb_xhci_init(xhci);
|
||||
xhci->mfwrap_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, xhci_mfwrap_timer, xhci);
|
||||
|
||||
memory_region_init(&xhci->mem, OBJECT(xhci), "xhci", LEN_REGS);
|
||||
@ -3704,11 +3703,11 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
|
||||
}
|
||||
|
||||
if (xhci->msix != ON_OFF_AUTO_OFF) {
|
||||
/* TODO check for errors */
|
||||
/* TODO check for errors, and should fail when msix=on */
|
||||
msix_init(dev, xhci->numintrs,
|
||||
&xhci->mem, 0, OFF_MSIX_TABLE,
|
||||
&xhci->mem, 0, OFF_MSIX_PBA,
|
||||
0x90);
|
||||
0x90, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1432,6 +1432,7 @@ static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
|
||||
static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
Error *err = NULL;
|
||||
|
||||
vdev->msix->pending = g_malloc0(BITS_TO_LONGS(vdev->msix->entries) *
|
||||
sizeof(unsigned long));
|
||||
@ -1439,12 +1440,15 @@ static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
|
||||
vdev->bars[vdev->msix->table_bar].region.mem,
|
||||
vdev->msix->table_bar, vdev->msix->table_offset,
|
||||
vdev->bars[vdev->msix->pba_bar].region.mem,
|
||||
vdev->msix->pba_bar, vdev->msix->pba_offset, pos);
|
||||
vdev->msix->pba_bar, vdev->msix->pba_offset, pos,
|
||||
&err);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOTSUP) {
|
||||
error_report_err(err);
|
||||
return 0;
|
||||
}
|
||||
error_setg(errp, "msix_init failed");
|
||||
|
||||
error_propagate(errp, err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -612,7 +612,8 @@ static void vhost_set_memory(MemoryListener *listener,
|
||||
|
||||
static bool vhost_section(MemoryRegionSection *section)
|
||||
{
|
||||
return memory_region_is_ram(section->mr);
|
||||
return memory_region_is_ram(section->mr) &&
|
||||
!memory_region_is_rom(section->mr);
|
||||
}
|
||||
|
||||
static void vhost_begin(MemoryListener *listener)
|
||||
|
@ -1686,9 +1686,9 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
|
||||
|
||||
if (proxy->nvectors) {
|
||||
int err = msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors,
|
||||
proxy->msix_bar_idx);
|
||||
proxy->msix_bar_idx, NULL);
|
||||
if (err) {
|
||||
/* Notice when a system that supports MSIx can't initialize it. */
|
||||
/* Notice when a system that supports MSIx can't initialize it */
|
||||
if (err != -ENOTSUP) {
|
||||
error_report("unable to init msix vectors to %" PRIu32,
|
||||
proxy->nvectors);
|
||||
|
@ -1383,7 +1383,7 @@ static void virtio_set_isr(VirtIODevice *vdev, int value)
|
||||
}
|
||||
}
|
||||
|
||||
bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
static bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
uint16_t old, new;
|
||||
bool v;
|
||||
|
@ -14,6 +14,10 @@
|
||||
.driver = "pflash_cfi01",\
|
||||
.property = "old-multiple-chip-handling",\
|
||||
.value = "on",\
|
||||
},{\
|
||||
.driver = "pci-bridge",\
|
||||
.property = "shpc",\
|
||||
.value = "on",\
|
||||
},
|
||||
|
||||
#define HW_COMPAT_2_7 \
|
||||
|
@ -9,9 +9,10 @@ MSIMessage msix_get_message(PCIDevice *dev, unsigned int vector);
|
||||
int msix_init(PCIDevice *dev, unsigned short nentries,
|
||||
MemoryRegion *table_bar, uint8_t table_bar_nr,
|
||||
unsigned table_offset, MemoryRegion *pba_bar,
|
||||
uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos);
|
||||
uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos,
|
||||
Error **errp);
|
||||
int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
|
||||
uint8_t bar_nr);
|
||||
uint8_t bar_nr, Error **errp);
|
||||
|
||||
void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len);
|
||||
|
||||
|
@ -96,6 +96,7 @@
|
||||
#define PCI_DEVICE_ID_REDHAT_PXB 0x0009
|
||||
#define PCI_DEVICE_ID_REDHAT_BRIDGE_SEAT 0x000a
|
||||
#define PCI_DEVICE_ID_REDHAT_PXB_PCIE 0x000b
|
||||
#define PCI_DEVICE_ID_REDHAT_PCIE_RP 0x000c
|
||||
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100
|
||||
|
||||
#define FMT_PCIBUS PRIx64
|
||||
|
@ -57,4 +57,23 @@ PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot);
|
||||
int pcie_chassis_add_slot(struct PCIESlot *slot);
|
||||
void pcie_chassis_del_slot(PCIESlot *s);
|
||||
|
||||
#define TYPE_PCIE_ROOT_PORT "pcie-root-port-base"
|
||||
#define PCIE_ROOT_PORT_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(PCIERootPortClass, (klass), TYPE_PCIE_ROOT_PORT)
|
||||
#define PCIE_ROOT_PORT_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(PCIERootPortClass, (obj), TYPE_PCIE_ROOT_PORT)
|
||||
|
||||
typedef struct PCIERootPortClass {
|
||||
PCIDeviceClass parent_class;
|
||||
|
||||
uint8_t (*aer_vector)(const PCIDevice *dev);
|
||||
int (*interrupts_init)(PCIDevice *dev, Error **errp);
|
||||
void (*interrupts_uninit)(PCIDevice *dev);
|
||||
|
||||
int exp_offset;
|
||||
int aer_offset;
|
||||
int ssvid_offset;
|
||||
int ssid;
|
||||
} PCIERootPortClass;
|
||||
|
||||
#endif /* QEMU_PCIE_PORT_H */
|
||||
|
@ -182,7 +182,6 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
|
||||
unsigned int *out_bytes,
|
||||
unsigned max_in_bytes, unsigned max_out_bytes);
|
||||
|
||||
bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq);
|
||||
void virtio_notify_irqfd(VirtIODevice *vdev, VirtQueue *vq);
|
||||
void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
|
||||
|
||||
|
@ -85,8 +85,20 @@
|
||||
#define typeof_field(type, field) typeof(((type *)0)->field)
|
||||
#define type_check(t1,t2) ((t1*)0 - (t2*)0)
|
||||
|
||||
#define QEMU_BUILD_BUG_ON(x) \
|
||||
typedef char glue(qemu_build_bug_on__,__LINE__)[(x)?-1:1] __attribute__((unused));
|
||||
#define QEMU_BUILD_BUG_ON_STRUCT(x) \
|
||||
struct { \
|
||||
int:(x) ? -1 : 1; \
|
||||
}
|
||||
|
||||
#ifdef __COUNTER__
|
||||
#define QEMU_BUILD_BUG_ON(x) typedef QEMU_BUILD_BUG_ON_STRUCT(x) \
|
||||
glue(qemu_build_bug_on__, __COUNTER__) __attribute__((unused))
|
||||
#else
|
||||
#define QEMU_BUILD_BUG_ON(x)
|
||||
#endif
|
||||
|
||||
#define QEMU_BUILD_BUG_ON_ZERO(x) (sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)) - \
|
||||
sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)))
|
||||
|
||||
#if defined __GNUC__
|
||||
# if !QEMU_GNUC_PREREQ(4, 4)
|
||||
|
@ -198,8 +198,15 @@ extern int daemon(int, int);
|
||||
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* &(x)[0] is always a pointer - if it's same type as x then the argument is a
|
||||
* pointer, not an array.
|
||||
*/
|
||||
#define QEMU_IS_ARRAY(x) (!__builtin_types_compatible_p(typeof(x), \
|
||||
typeof(&(x)[0])))
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0])) + \
|
||||
QEMU_BUILD_BUG_ON_ZERO(!QEMU_IS_ARRAY(x)))
|
||||
#endif
|
||||
|
||||
int qemu_daemon(int nochdir, int noclose);
|
||||
|
@ -151,7 +151,10 @@ static void vhost_user_cleanup(NetClientState *nc)
|
||||
s->vhost_net = NULL;
|
||||
}
|
||||
if (nc->queue_index == 0) {
|
||||
Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
|
||||
|
||||
qemu_chr_fe_deinit(&s->chr);
|
||||
qemu_chr_delete(chr);
|
||||
}
|
||||
|
||||
qemu_purge_queued_packets(nc);
|
||||
|
@ -21,7 +21,9 @@
|
||||
#define MISMATCH_CHECK(X, Y) QEMU_BUILD_BUG_ON(X != Y)
|
||||
|
||||
#else
|
||||
#define MISMATCH_CHECK(X, Y)
|
||||
|
||||
#define MISMATCH_CHECK(X, Y) QEMU_BUILD_BUG_ON(0)
|
||||
|
||||
#endif
|
||||
|
||||
#define CP_REG_SIZE_SHIFT 52
|
||||
@ -31,12 +33,12 @@
|
||||
#define CP_REG_ARM 0x4000000000000000ULL
|
||||
#define CP_REG_ARCH_MASK 0xff00000000000000ULL
|
||||
|
||||
MISMATCH_CHECK(CP_REG_SIZE_SHIFT, KVM_REG_SIZE_SHIFT)
|
||||
MISMATCH_CHECK(CP_REG_SIZE_MASK, KVM_REG_SIZE_MASK)
|
||||
MISMATCH_CHECK(CP_REG_SIZE_U32, KVM_REG_SIZE_U32)
|
||||
MISMATCH_CHECK(CP_REG_SIZE_U64, KVM_REG_SIZE_U64)
|
||||
MISMATCH_CHECK(CP_REG_ARM, KVM_REG_ARM)
|
||||
MISMATCH_CHECK(CP_REG_ARCH_MASK, KVM_REG_ARCH_MASK)
|
||||
MISMATCH_CHECK(CP_REG_SIZE_SHIFT, KVM_REG_SIZE_SHIFT);
|
||||
MISMATCH_CHECK(CP_REG_SIZE_MASK, KVM_REG_SIZE_MASK);
|
||||
MISMATCH_CHECK(CP_REG_SIZE_U32, KVM_REG_SIZE_U32);
|
||||
MISMATCH_CHECK(CP_REG_SIZE_U64, KVM_REG_SIZE_U64);
|
||||
MISMATCH_CHECK(CP_REG_ARM, KVM_REG_ARM);
|
||||
MISMATCH_CHECK(CP_REG_ARCH_MASK, KVM_REG_ARCH_MASK);
|
||||
|
||||
#define QEMU_PSCI_0_1_FN_BASE 0x95c1ba5e
|
||||
#define QEMU_PSCI_0_1_FN(n) (QEMU_PSCI_0_1_FN_BASE + (n))
|
||||
@ -45,10 +47,10 @@ MISMATCH_CHECK(CP_REG_ARCH_MASK, KVM_REG_ARCH_MASK)
|
||||
#define QEMU_PSCI_0_1_FN_CPU_ON QEMU_PSCI_0_1_FN(2)
|
||||
#define QEMU_PSCI_0_1_FN_MIGRATE QEMU_PSCI_0_1_FN(3)
|
||||
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_SUSPEND, KVM_PSCI_FN_CPU_SUSPEND)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_OFF, KVM_PSCI_FN_CPU_OFF)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_ON, KVM_PSCI_FN_CPU_ON)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_1_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_SUSPEND, KVM_PSCI_FN_CPU_SUSPEND);
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_OFF, KVM_PSCI_FN_CPU_OFF);
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_1_FN_CPU_ON, KVM_PSCI_FN_CPU_ON);
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_1_FN_MIGRATE, KVM_PSCI_FN_MIGRATE);
|
||||
|
||||
#define QEMU_PSCI_0_2_FN_BASE 0x84000000
|
||||
#define QEMU_PSCI_0_2_FN(n) (QEMU_PSCI_0_2_FN_BASE + (n))
|
||||
@ -75,13 +77,13 @@ MISMATCH_CHECK(QEMU_PSCI_0_1_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
|
||||
#define QEMU_PSCI_0_2_FN64_AFFINITY_INFO QEMU_PSCI_0_2_FN64(4)
|
||||
#define QEMU_PSCI_0_2_FN64_MIGRATE QEMU_PSCI_0_2_FN64(5)
|
||||
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_SUSPEND, PSCI_0_2_FN_CPU_SUSPEND)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_OFF, PSCI_0_2_FN_CPU_OFF)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_ON, PSCI_0_2_FN_CPU_ON)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_MIGRATE, PSCI_0_2_FN_MIGRATE)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_CPU_SUSPEND, PSCI_0_2_FN64_CPU_SUSPEND)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_CPU_ON, PSCI_0_2_FN64_CPU_ON)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_MIGRATE, PSCI_0_2_FN64_MIGRATE)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_SUSPEND, PSCI_0_2_FN_CPU_SUSPEND);
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_OFF, PSCI_0_2_FN_CPU_OFF);
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_ON, PSCI_0_2_FN_CPU_ON);
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_MIGRATE, PSCI_0_2_FN_MIGRATE);
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_CPU_SUSPEND, PSCI_0_2_FN64_CPU_SUSPEND);
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_CPU_ON, PSCI_0_2_FN64_CPU_ON);
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_MIGRATE, PSCI_0_2_FN64_MIGRATE);
|
||||
|
||||
/* PSCI v0.2 return values used by TCG emulation of PSCI */
|
||||
|
||||
@ -91,9 +93,9 @@ MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_MIGRATE, PSCI_0_2_FN64_MIGRATE)
|
||||
/* We implement version 0.2 only */
|
||||
#define QEMU_PSCI_0_2_RET_VERSION_0_2 2
|
||||
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED, PSCI_0_2_TOS_MP)
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED, PSCI_0_2_TOS_MP);
|
||||
MISMATCH_CHECK(QEMU_PSCI_0_2_RET_VERSION_0_2,
|
||||
(PSCI_VERSION_MAJOR(0) | PSCI_VERSION_MINOR(2)))
|
||||
(PSCI_VERSION_MAJOR(0) | PSCI_VERSION_MINOR(2)));
|
||||
|
||||
/* PSCI return values (inclusive of all PSCI versions) */
|
||||
#define QEMU_PSCI_RET_SUCCESS 0
|
||||
@ -106,15 +108,15 @@ MISMATCH_CHECK(QEMU_PSCI_0_2_RET_VERSION_0_2,
|
||||
#define QEMU_PSCI_RET_NOT_PRESENT -7
|
||||
#define QEMU_PSCI_RET_DISABLED -8
|
||||
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_SUCCESS, PSCI_RET_SUCCESS)
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_NOT_SUPPORTED, PSCI_RET_NOT_SUPPORTED)
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_INVALID_PARAMS, PSCI_RET_INVALID_PARAMS)
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_DENIED, PSCI_RET_DENIED)
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_ALREADY_ON, PSCI_RET_ALREADY_ON)
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_ON_PENDING, PSCI_RET_ON_PENDING)
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_INTERNAL_FAILURE, PSCI_RET_INTERNAL_FAILURE)
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_NOT_PRESENT, PSCI_RET_NOT_PRESENT)
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED)
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_SUCCESS, PSCI_RET_SUCCESS);
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_NOT_SUPPORTED, PSCI_RET_NOT_SUPPORTED);
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_INVALID_PARAMS, PSCI_RET_INVALID_PARAMS);
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_DENIED, PSCI_RET_DENIED);
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_ALREADY_ON, PSCI_RET_ALREADY_ON);
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_ON_PENDING, PSCI_RET_ON_PENDING);
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_INTERNAL_FAILURE, PSCI_RET_INTERNAL_FAILURE);
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_NOT_PRESENT, PSCI_RET_NOT_PRESENT);
|
||||
MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED);
|
||||
|
||||
/* Note that KVM uses overlapping values for AArch32 and AArch64
|
||||
* target CPU numbers. AArch32 targets:
|
||||
@ -135,14 +137,14 @@ MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED)
|
||||
#define QEMU_KVM_ARM_TARGET_NONE UINT_MAX
|
||||
|
||||
#ifdef TARGET_AARCH64
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_AEM_V8, KVM_ARM_TARGET_AEM_V8)
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8)
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57)
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_XGENE_POTENZA, KVM_ARM_TARGET_XGENE_POTENZA)
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53)
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_AEM_V8, KVM_ARM_TARGET_AEM_V8);
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8);
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57);
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_XGENE_POTENZA, KVM_ARM_TARGET_XGENE_POTENZA);
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53);
|
||||
#else
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15)
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A7, KVM_ARM_TARGET_CORTEX_A7)
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15);
|
||||
MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A7, KVM_ARM_TARGET_CORTEX_A7);
|
||||
#endif
|
||||
|
||||
#define CP_REG_ARM64 0x6000000000000000ULL
|
||||
@ -164,20 +166,20 @@ MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A7, KVM_ARM_TARGET_CORTEX_A7)
|
||||
#define CP_REG_ARM64_SYSREG_CP (CP_REG_ARM64_SYSREG >> CP_REG_ARM_COPROC_SHIFT)
|
||||
|
||||
#ifdef TARGET_AARCH64
|
||||
MISMATCH_CHECK(CP_REG_ARM64, KVM_REG_ARM64)
|
||||
MISMATCH_CHECK(CP_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_MASK)
|
||||
MISMATCH_CHECK(CP_REG_ARM_COPROC_SHIFT, KVM_REG_ARM_COPROC_SHIFT)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG, KVM_REG_ARM64_SYSREG)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_MASK)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP0_SHIFT)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP1_SHIFT)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_MASK)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRN_SHIFT, KVM_REG_ARM64_SYSREG_CRN_SHIFT)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRM_MASK, KVM_REG_ARM64_SYSREG_CRM_MASK)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRM_SHIFT)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK)
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP2_SHIFT, KVM_REG_ARM64_SYSREG_OP2_SHIFT)
|
||||
MISMATCH_CHECK(CP_REG_ARM64, KVM_REG_ARM64);
|
||||
MISMATCH_CHECK(CP_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_MASK);
|
||||
MISMATCH_CHECK(CP_REG_ARM_COPROC_SHIFT, KVM_REG_ARM_COPROC_SHIFT);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG, KVM_REG_ARM64_SYSREG);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_MASK);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP0_SHIFT);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP1_SHIFT);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_MASK);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRN_SHIFT, KVM_REG_ARM64_SYSREG_CRN_SHIFT);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRM_MASK, KVM_REG_ARM64_SYSREG_CRM_MASK);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRM_SHIFT);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK);
|
||||
MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP2_SHIFT, KVM_REG_ARM64_SYSREG_OP2_SHIFT);
|
||||
#endif
|
||||
|
||||
#undef MISMATCH_CHECK
|
||||
|
Loading…
Reference in New Issue
Block a user