pc: fixes, cleanups, features

Some fixes and cleanups. Extended TSEG sizes.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJZQ/0DAAoJECgfDbjSjVRpqkQH/A83wqyTJJp7V87FqsC4l5Yc
 W7sIAqI/nrdSurzPyV98hUusOX+GgQ6AviQyjbtH/jKtaFK1kSD+nLudcDbQCeu7
 l4bskTupKuSdzEOm8ybbM1bcIlw0RnaQTMQOfB0QRTNOhPv8dA8uclrIACVA3LSb
 0IQT5wj8ni50bc56qNrJjY8F02M0CzUBVq5HdGrpOolm2c9yvNmCg8JZWwQP5iQp
 F0FvvcyJ2XqhNSKI3mcuf9/z90lDm1C+pEAc3GtLarDlfQIIsZhkAHmBNBIIxAAa
 +1qsFfLGYaKcmEzvNmLoUlP1cQ6X7kU7A7KEpnVv93uzmuVo1oHIM8jKpHOaohg=
 =Xzi1
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

pc: fixes, cleanups, features

Some fixes and cleanups. Extended TSEG sizes.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Fri 16 Jun 2017 16:45:07 BST
# 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:
  hw/i386: fix nvdimm check error path
  intel_iommu: cleanup vtd_interrupt_remap_msi()
  intel_iommu: cleanup vtd_{do_}iommu_translate()
  intel_iommu: switching the rest DPRINTF to trace
  tests/q35-test: add TSEG size checks
  tests/q35-test: push down qtest_start / qtest_end to test case(s)
  q35/mch: implement extended TSEG sizes

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-06-20 17:12:41 +01:00
commit e85c0d1401
8 changed files with 371 additions and 286 deletions

File diff suppressed because it is too large Load Diff

View File

@ -384,6 +384,7 @@ typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo;
/* Pagesize of VTD paging structures, including root and context tables */
#define VTD_PAGE_SHIFT 12
#define VTD_PAGE_SIZE (1ULL << VTD_PAGE_SHIFT)
#define VTD_PAGE_MASK (VTD_PAGE_SIZE - 1)
#define VTD_PAGE_SHIFT_4K 12
#define VTD_PAGE_MASK_4K (~((1ULL << VTD_PAGE_SHIFT_4K) - 1))

View File

@ -1692,6 +1692,7 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
MemoryRegion *mr = ddc->get_memory_region(dimm);
uint64_t align = TARGET_PAGE_SIZE;
bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
if (memory_region_get_alignment(mr) && pcmc->enforce_aligned_dimm) {
align = memory_region_get_alignment(mr);
@ -1703,17 +1704,18 @@ static void pc_dimm_plug(HotplugHandler *hotplug_dev,
goto out;
}
if (is_nvdimm && !pcms->acpi_nvdimm_state.is_enabled) {
error_setg(&local_err,
"nvdimm is not enabled: missing 'nvdimm' in '-M'");
goto out;
}
pc_dimm_memory_plug(dev, &pcms->hotplug_memory, mr, align, &local_err);
if (local_err) {
goto out;
}
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;
}
if (is_nvdimm) {
nvdimm_plug(&pcms->acpi_nvdimm_state);
}

View File

@ -19,6 +19,13 @@ vtd_inv_desc_wait_sw(uint64_t addr, uint32_t data) "wait invalidate status write
vtd_inv_desc_wait_irq(const char *msg) "%s"
vtd_inv_desc_wait_invalid(uint64_t hi, uint64_t lo) "invalid wait desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_wait_write_fail(uint64_t hi, uint64_t lo) "write fail for wait desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_iec(uint32_t granularity, uint32_t index, uint32_t mask) "granularity 0x%"PRIx32" index 0x%"PRIx32" mask 0x%"PRIx32
vtd_inv_qi_enable(bool enable) "enabled %d"
vtd_inv_qi_setup(uint64_t addr, int size) "addr 0x%"PRIx64" size %d"
vtd_inv_qi_head(uint16_t head) "read head %d"
vtd_inv_qi_tail(uint16_t head) "write tail %d"
vtd_inv_qi_fetch(void) ""
vtd_context_cache_reset(void) ""
vtd_re_not_present(uint8_t bus) "Root entry bus %"PRIu8" not present"
vtd_re_invalid(uint64_t hi, uint64_t lo) "invalid root entry hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_ce_not_present(uint8_t bus, uint8_t devfn) "Context entry bus %"PRIu8" devfn %"PRIu8" not present"
@ -40,6 +47,43 @@ vtd_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device
vtd_as_unmap_whole(uint8_t bus, uint8_t slot, uint8_t fn, uint64_t iova, uint64_t size) "Device %02x:%02x.%x start 0x%"PRIx64" size 0x%"PRIx64
vtd_translate_pt(uint16_t sid, uint64_t addr) "source id 0x%"PRIu16", iova 0x%"PRIx64
vtd_pt_enable_fast_path(uint16_t sid, bool success) "sid 0x%"PRIu16" %d"
vtd_irq_generate(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64
vtd_reg_read(uint64_t addr, uint64_t size) "addr 0x%"PRIx64" size 0x%"PRIx64
vtd_reg_write(uint64_t addr, uint64_t size, uint64_t val) "addr 0x%"PRIx64" size 0x%"PRIx64" value 0x%"PRIx64
vtd_reg_dmar_root(uint64_t addr, bool extended) "addr 0x%"PRIx64" extended %d"
vtd_reg_ir_root(uint64_t addr, uint32_t size) "addr 0x%"PRIx64" size 0x%"PRIx32
vtd_reg_write_gcmd(uint32_t status, uint32_t val) "status 0x%"PRIx32" value 0x%"PRIx32
vtd_reg_write_fectl(uint32_t value) "value 0x%"PRIx32
vtd_reg_write_iectl(uint32_t value) "value 0x%"PRIx32
vtd_reg_ics_clear_ip(void) ""
vtd_dmar_translate(uint8_t bus, uint8_t slot, uint8_t func, uint64_t iova, uint64_t gpa, uint64_t mask) "dev %02x:%02x.%02x iova 0x%"PRIx64" -> gpa 0x%"PRIx64" mask 0x%"PRIx64
vtd_dmar_enable(bool en) "enable %d"
vtd_dmar_fault(uint16_t sid, int fault, uint64_t addr, bool is_write) "sid 0x%"PRIx16" fault %d addr 0x%"PRIx64" write %d"
vtd_ir_enable(bool en) "enable %d"
vtd_ir_irte_get(int index, uint64_t lo, uint64_t hi) "index %d low 0x%"PRIx64" high 0x%"PRIx64
vtd_ir_remap(int index, int tri, int vec, int deliver, uint32_t dest, int dest_mode) "index %d trigger %d vector %d deliver %d dest 0x%"PRIx32" mode %d"
vtd_ir_remap_type(const char *type) "%s"
vtd_ir_remap_msi(uint64_t addr, uint64_t data, uint64_t addr2, uint64_t data2) "(addr 0x%"PRIx64", data 0x%"PRIx64") -> (addr 0x%"PRIx64", data 0x%"PRIx64")"
vtd_ir_remap_msi_req(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64
vtd_fsts_ppf(bool set) "FSTS PPF bit set to %d"
vtd_fsts_clear_ip(void) ""
vtd_frr_new(int index, uint64_t hi, uint64_t lo) "index %d high 0x%"PRIx64" low 0x%"PRIx64
vtd_err(const char *str) "%s"
vtd_err_dmar_iova_overflow(uint64_t iova) "iova 0x%"PRIx64
vtd_err_dmar_slpte_read_error(uint64_t iova, int level) "iova 0x%"PRIx64" level %d"
vtd_err_dmar_slpte_perm_error(uint64_t iova, int level, uint64_t slpte, bool is_write) "iova 0x%"PRIx64" level %d slpte 0x%"PRIx64" write %d"
vtd_err_dmar_slpte_resv_error(uint64_t iova, int level, uint64_t slpte) "iova 0x%"PRIx64" level %d slpte 0x%"PRIx64
vtd_err_dmar_translate(uint8_t bus, uint8_t slot, uint8_t func, uint64_t iova) "dev %02x:%02x.%02x iova 0x%"PRIx64
vtd_err_qi_enable(uint16_t tail) "tail 0x%"PRIx16
vtd_err_qi_disable(uint16_t head, uint16_t tail, int type) "head 0x%"PRIx16" tail 0x%"PRIx16" last_desc_type %d"
vtd_err_qi_tail(uint16_t tail, uint16_t size) "tail 0x%"PRIx16" size 0x%"PRIx16
vtd_err_irte(int index, uint64_t lo, uint64_t hi) "index %d low 0x%"PRIx64" high 0x%"PRIx64
vtd_err_irte_sid(int index, uint16_t req, uint16_t target) "index %d SVT_ALL sid 0x%"PRIx16" (should be: 0x%"PRIx16")"
vtd_err_irte_sid_bus(int index, uint8_t bus, uint8_t min, uint8_t max) "index %d SVT_BUS bus 0x%"PRIx8" (should be: 0x%"PRIx8"-0x%"PRIx8")"
vtd_err_irte_svt(int index, int type) "index %d SVT type %d"
vtd_err_ir_msi_invalid(uint16_t sid, uint64_t addr, uint64_t data) "sid 0x%"PRIx16" addr 0x%"PRIx64" data 0x%"PRIx64
vtd_warn_ir_vector(uint16_t sid, int index, int vec, int target) "sid 0x%"PRIx16" index %d vec %d (should be: %d)"
vtd_warn_ir_trigger(uint16_t sid, int index, int trig, int target) "sid 0x%"PRIx16" index %d trigger %d (should be: %d)"
# hw/i386/amd_iommu.c
amdvi_evntlog_fail(uint64_t addr, uint32_t head) "error: fail to write at addr 0x%"PRIx64" + offset 0x%"PRIx32

View File

@ -134,7 +134,7 @@ static void q35_host_get_mmcfg_size(Object *obj, Visitor *v, const char *name,
visit_type_uint32(v, name, &value, errp);
}
static Property mch_props[] = {
static Property q35_host_props[] = {
DEFINE_PROP_UINT64(PCIE_HOST_MCFG_BASE, Q35PCIHost, parent_obj.base_addr,
MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, Q35PCIHost,
@ -154,7 +154,7 @@ static void q35_host_class_init(ObjectClass *klass, void *data)
hc->root_bus_path = q35_host_root_bus_path;
dc->realize = q35_host_realize;
dc->props = mch_props;
dc->props = q35_host_props;
/* Reason: needs to be wired up by pc_q35_init */
dc->user_creatable = false;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
@ -369,7 +369,7 @@ static void mch_update_smram(MCHPCIState *mch)
tseg_size = 1024 * 1024 * 8;
break;
default:
tseg_size = 0;
tseg_size = 1024 * 1024 * (uint32_t)mch->ext_tseg_mbytes;
break;
}
} else {
@ -392,6 +392,17 @@ static void mch_update_smram(MCHPCIState *mch)
memory_region_transaction_commit();
}
static void mch_update_ext_tseg_mbytes(MCHPCIState *mch)
{
PCIDevice *pd = PCI_DEVICE(mch);
uint8_t *reg = pd->config + MCH_HOST_BRIDGE_EXT_TSEG_MBYTES;
if (mch->ext_tseg_mbytes > 0 &&
pci_get_word(reg) == MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_QUERY) {
pci_set_word(reg, mch->ext_tseg_mbytes);
}
}
static void mch_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len)
{
@ -413,6 +424,11 @@ static void mch_write_config(PCIDevice *d,
MCH_HOST_BRIDGE_SMRAM_SIZE)) {
mch_update_smram(mch);
}
if (ranges_overlap(address, len, MCH_HOST_BRIDGE_EXT_TSEG_MBYTES,
MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_SIZE)) {
mch_update_ext_tseg_mbytes(mch);
}
}
static void mch_update(MCHPCIState *mch)
@ -420,6 +436,7 @@ static void mch_update(MCHPCIState *mch)
mch_update_pciexbar(mch);
mch_update_pam(mch);
mch_update_smram(mch);
mch_update_ext_tseg_mbytes(mch);
}
static int mch_post_load(void *opaque, int version_id)
@ -457,6 +474,11 @@ static void mch_reset(DeviceState *qdev)
d->wmask[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_WMASK;
d->wmask[MCH_HOST_BRIDGE_ESMRAMC] = MCH_HOST_BRIDGE_ESMRAMC_WMASK;
if (mch->ext_tseg_mbytes > 0) {
pci_set_word(d->config + MCH_HOST_BRIDGE_EXT_TSEG_MBYTES,
MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_QUERY);
}
mch_update(mch);
}
@ -465,6 +487,12 @@ static void mch_realize(PCIDevice *d, Error **errp)
int i;
MCHPCIState *mch = MCH_PCI_DEVICE(d);
if (mch->ext_tseg_mbytes > MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_MAX) {
error_setg(errp, "invalid extended-tseg-mbytes value: %" PRIu16,
mch->ext_tseg_mbytes);
return;
}
/* setup pci memory mapping */
pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory,
mch->pci_address_space);
@ -530,6 +558,12 @@ uint64_t mch_mcfg_base(void)
return MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT;
}
static Property mch_props[] = {
DEFINE_PROP_UINT16("extended-tseg-mbytes", MCHPCIState, ext_tseg_mbytes,
16),
DEFINE_PROP_END_OF_LIST(),
};
static void mch_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@ -538,6 +572,7 @@ static void mch_class_init(ObjectClass *klass, void *data)
k->realize = mch_realize;
k->config_write = mch_write_config;
dc->reset = mch_reset;
dc->props = mch_props;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "Host bridge";
dc->vmsd = &vmstate_mch;

View File

@ -384,6 +384,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
#define PC_COMPAT_2_9 \
HW_COMPAT_2_9 \
{\
.driver = "mch",\
.property = "extended-tseg-mbytes",\
.value = stringify(0),\
},\
#define PC_COMPAT_2_8 \
HW_COMPAT_2_8 \

View File

@ -60,6 +60,7 @@ typedef struct MCHPCIState {
uint64_t above_4g_mem_size;
uint64_t pci_hole64_size;
uint32_t short_root_bus;
uint16_t ext_tseg_mbytes;
} MCHPCIState;
typedef struct Q35PCIHost {
@ -91,6 +92,11 @@ typedef struct Q35PCIHost {
/* D0:F0 configuration space */
#define MCH_HOST_BRIDGE_REVISION_DEFAULT 0x0
#define MCH_HOST_BRIDGE_EXT_TSEG_MBYTES 0x50
#define MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_SIZE 2
#define MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_QUERY 0xffff
#define MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_MAX 0xfff
#define MCH_HOST_BRIDGE_PCIEXBAR 0x60 /* 64bit register */
#define MCH_HOST_BRIDGE_PCIEXBAR_SIZE 8 /* 64bit register */
#define MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT 0xb0000000

View File

@ -15,6 +15,48 @@
#include "libqos/pci-pc.h"
#include "hw/pci-host/q35.h"
#define TSEG_SIZE_TEST_GUEST_RAM_MBYTES 128
/* @esmramc_tseg_sz: ESMRAMC.TSEG_SZ bitmask for selecting the requested TSEG
* size. Must be a subset of
* MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK.
*
* @extended_tseg_mbytes: Size of the extended TSEG. Only consulted if
* @esmramc_tseg_sz equals
* MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK precisely.
*
* @expected_tseg_mbytes: Expected guest-visible TSEG size in megabytes,
* matching @esmramc_tseg_sz and @extended_tseg_mbytes
* above.
*/
struct TsegSizeArgs {
uint8_t esmramc_tseg_sz;
uint16_t extended_tseg_mbytes;
uint16_t expected_tseg_mbytes;
};
typedef struct TsegSizeArgs TsegSizeArgs;
static const TsegSizeArgs tseg_1mb = {
.esmramc_tseg_sz = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB,
.extended_tseg_mbytes = 0,
.expected_tseg_mbytes = 1,
};
static const TsegSizeArgs tseg_2mb = {
.esmramc_tseg_sz = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB,
.extended_tseg_mbytes = 0,
.expected_tseg_mbytes = 2,
};
static const TsegSizeArgs tseg_8mb = {
.esmramc_tseg_sz = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB,
.extended_tseg_mbytes = 0,
.expected_tseg_mbytes = 8,
};
static const TsegSizeArgs tseg_ext_16mb = {
.esmramc_tseg_sz = MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK,
.extended_tseg_mbytes = 16,
.expected_tseg_mbytes = 16,
};
static void smram_set_bit(QPCIDevice *pcidev, uint8_t mask, bool enabled)
{
uint8_t smram;
@ -42,6 +84,8 @@ static void test_smram_lock(void)
QPCIDevice *pcidev;
QDict *response;
qtest_start("-M q35");
pcibus = qpci_init_pc(NULL);
g_assert(pcibus != NULL);
@ -74,19 +118,86 @@ static void test_smram_lock(void)
g_free(pcidev);
qpci_free_pc(pcibus);
qtest_end();
}
static void test_tseg_size(const void *data)
{
const TsegSizeArgs *args = data;
char *cmdline;
QPCIBus *pcibus;
QPCIDevice *pcidev;
uint8_t smram_val;
uint8_t esmramc_val;
uint32_t ram_offs;
if (args->esmramc_tseg_sz == MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK) {
cmdline = g_strdup_printf("-M q35 -m %uM "
"-global mch.extended-tseg-mbytes=%u",
TSEG_SIZE_TEST_GUEST_RAM_MBYTES,
args->extended_tseg_mbytes);
} else {
cmdline = g_strdup_printf("-M q35 -m %uM",
TSEG_SIZE_TEST_GUEST_RAM_MBYTES);
}
qtest_start(cmdline);
g_free(cmdline);
/* locate the DRAM controller */
pcibus = qpci_init_pc(NULL);
g_assert(pcibus != NULL);
pcidev = qpci_device_find(pcibus, 0);
g_assert(pcidev != NULL);
/* Set TSEG size. Restrict TSEG visibility to SMM by setting T_EN. */
esmramc_val = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_ESMRAMC);
esmramc_val &= ~MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK;
esmramc_val |= args->esmramc_tseg_sz;
esmramc_val |= MCH_HOST_BRIDGE_ESMRAMC_T_EN;
qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_ESMRAMC, esmramc_val);
/* Enable TSEG by setting G_SMRAME. Close TSEG by setting D_CLS. */
smram_val = qpci_config_readb(pcidev, MCH_HOST_BRIDGE_SMRAM);
smram_val &= ~(MCH_HOST_BRIDGE_SMRAM_D_OPEN |
MCH_HOST_BRIDGE_SMRAM_D_LCK);
smram_val |= (MCH_HOST_BRIDGE_SMRAM_D_CLS |
MCH_HOST_BRIDGE_SMRAM_G_SMRAME);
qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram_val);
/* lock TSEG */
smram_val |= MCH_HOST_BRIDGE_SMRAM_D_LCK;
qpci_config_writeb(pcidev, MCH_HOST_BRIDGE_SMRAM, smram_val);
/* Now check that the byte right before the TSEG is r/w, and that the first
* byte in the TSEG always reads as 0xff.
*/
ram_offs = (TSEG_SIZE_TEST_GUEST_RAM_MBYTES - args->expected_tseg_mbytes) *
1024 * 1024 - 1;
g_assert_cmpint(readb(ram_offs), ==, 0);
writeb(ram_offs, 1);
g_assert_cmpint(readb(ram_offs), ==, 1);
ram_offs++;
g_assert_cmpint(readb(ram_offs), ==, 0xff);
writeb(ram_offs, 1);
g_assert_cmpint(readb(ram_offs), ==, 0xff);
g_free(pcidev);
qpci_free_pc(pcibus);
qtest_end();
}
int main(int argc, char **argv)
{
int ret;
g_test_init(&argc, &argv, NULL);
qtest_add_func("/q35/smram/lock", test_smram_lock);
qtest_start("-M q35");
ret = g_test_run();
qtest_end();
return ret;
qtest_add_data_func("/q35/tseg-size/1mb", &tseg_1mb, test_tseg_size);
qtest_add_data_func("/q35/tseg-size/2mb", &tseg_2mb, test_tseg_size);
qtest_add_data_func("/q35/tseg-size/8mb", &tseg_8mb, test_tseg_size);
qtest_add_data_func("/q35/tseg-size/ext/16mb", &tseg_ext_16mb,
test_tseg_size);
return g_test_run();
}