From 54cdaa1bad3885448ef39faad93d40be3b223519 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 27 Oct 2010 20:03:43 +0200 Subject: [PATCH 01/30] tap: clear vhost_net backend on cleanup Frontends calling tap_get_vhost_net get an invalid pointer after the peer backend has been deleted. Jason Wang reports this leading to a crash in ack_features when we remove the vhost-net bakend of a virtio nic. The fix is simply to clear the backend pointer. Signed-off-by: Michael S. Tsirkin --- net/tap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/tap.c b/net/tap.c index 4afb314fde..937d9429eb 100644 --- a/net/tap.c +++ b/net/tap.c @@ -279,6 +279,7 @@ static void tap_cleanup(VLANClientState *nc) if (s->vhost_net) { vhost_net_cleanup(s->vhost_net); + s->vhost_net = NULL; } qemu_purge_queued_packets(nc); From a5fd2c345f7a616e48e7f2be8b3060d23252180c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 31 Oct 2010 19:06:47 +0200 Subject: [PATCH 02/30] tap: make set_offload a nop after netdev cleanup virtio-net expects set_offload to succeed after peer cleanup. Since we don't have an open fd anymore, make it so. Fixes warning about the failure of offload setting. Reported-by: Jason Wang Signed-off-by: Michael S. Tsirkin --- net/tap.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/tap.c b/net/tap.c index 937d9429eb..eada34ac2b 100644 --- a/net/tap.c +++ b/net/tap.c @@ -269,8 +269,11 @@ void tap_set_offload(VLANClientState *nc, int csum, int tso4, int tso6, int ecn, int ufo) { TAPState *s = DO_UPCAST(TAPState, nc, nc); + if (s->fd < 0) { + return; + } - return tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo); + tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo); } static void tap_cleanup(VLANClientState *nc) @@ -290,6 +293,7 @@ static void tap_cleanup(VLANClientState *nc) tap_read_poll(s, 0); tap_write_poll(s, 0); close(s->fd); + s->fd = -1; } static void tap_poll(VLANClientState *nc, bool enable) From e685b4eb649cbddd26f203b611eabeb714648f4d Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 5 Nov 2010 14:52:08 -0600 Subject: [PATCH 03/30] e1000: Fix TCP checksum overflow with TSO When adding the length to the pseudo header, we're not properly accounting for overflow. From: Mark Wu Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/e1000.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/e1000.c b/hw/e1000.c index 532efdc27d..677165f830 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -384,9 +384,12 @@ xmit_seg(E1000State *s) } else // UDP cpu_to_be16wu((uint16_t *)(tp->data+css+4), len); if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { + unsigned int phsum; // add pseudo-header length before checksum calculation sp = (uint16_t *)(tp->data + tp->tucso); - cpu_to_be16wu(sp, be16_to_cpup(sp) + len); + phsum = be16_to_cpup(sp) + len; + phsum = (phsum >> 16) + (phsum & 0xffff); + cpu_to_be16wu(sp, phsum); } tp->tso_frames++; } From 7f5feab4dda39b39dce24113313587587aa2d0ab Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 4 Oct 2010 15:53:11 -0600 Subject: [PATCH 04/30] PCI: Bus number from the bridge, not the device pcibus_dev_print() was erroneously retrieving the device bus number from the secondary bus number offset of the device instead of the bridge above the device. This ends of landing in the 2nd byte of the 3rd BAR for devices, which thankfully is usually zero. Note: pcibus_get_dev_path() copied this code, inheriting the same bug. pcibus_get_dev_path() is used for ramblock naming, so changing it can effect migration. However, I've only seen this byte be non-zero for an assigned device, which can't migrate anyway, so hopefully we won't run into any issues. This patch does not touch pcibus_get_dev_path, as bus number is guest assigned for nested buses, so using it for migration is broken anyway. Fix it properly later. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 962886e767..8f6fcf8a53 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1806,8 +1806,7 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " "pci id %04x:%04x (sub %04x:%04x)\n", - indent, "", ctxt, - d->config[PCI_SECONDARY_BUS], + indent, "", ctxt, pci_bus_num(d->bus), PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), pci_get_word(d->config + PCI_VENDOR_ID), pci_get_word(d->config + PCI_DEVICE_ID), From e927d48722fdcba50f82d653c5a1927752483054 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 12 Nov 2010 16:21:35 +0900 Subject: [PATCH 05/30] pci: allow hotplug removal of cold-plugged devices This patch fixes hot unplug of cold plugged devices (those present at system start), which got broken by 5beb8ad503c88a76f2b8106c3b74b4ce485a60e1 . Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin Acked-by: Cam Macdonell Tested-by: Cam Macdonell Reported-by: Cam Macdonell . --- hw/acpi_piix4.c | 14 ++++++++++---- hw/pci.c | 10 +++++++--- hw/pci.h | 10 +++++++++- hw/pcie.c | 10 ++++++---- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 66c7885d62..f549089a55 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -585,7 +585,8 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val) PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val); } -static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state); +static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, + PCIHotplugState state); static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) { @@ -615,18 +616,23 @@ static void disable_device(PIIX4PMState *s, int slot) s->pci0_status.down |= (1 << slot); } -static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state) +static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, + PCIHotplugState state) { int slot = PCI_SLOT(dev->devfn); PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, DO_UPCAST(PCIDevice, qdev, qdev)); - if (!dev->qdev.hotplugged) + /* Don't send event when device is enabled during qemu machine creation: + * it is present on boot, no hotplug event is necessary. We do send an + * event when the device is disabled later. */ + if (state == PCI_COLDPLUG_ENABLED) { return 0; + } s->pci0_status.up = 0; s->pci0_status.down = 0; - if (state) { + if (state == PCI_HOTPLUG_ENABLED) { enable_device(s, slot); } else { disable_device(s, slot); diff --git a/hw/pci.c b/hw/pci.c index 8f6fcf8a53..438c0d1691 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1558,8 +1558,11 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) pci_add_option_rom(pci_dev); if (bus->hotplug) { - /* lower layer must check qdev->hotplugged */ - rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1); + /* Let buses differentiate between hotplug and when device is + * enabled during qemu machine creation. */ + rc = bus->hotplug(bus->hotplug_qdev, pci_dev, + qdev->hotplugged ? PCI_HOTPLUG_ENABLED: + PCI_COLDPLUG_ENABLED); if (rc != 0) { int r = pci_unregister_device(&pci_dev->qdev); assert(!r); @@ -1573,7 +1576,8 @@ static int pci_unplug_device(DeviceState *qdev) { PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); - return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, 0); + return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, + PCI_HOTPLUG_DISABLED); } void pci_qdev_register(PCIDeviceInfo *info) diff --git a/hw/pci.h b/hw/pci.h index 7100804e7c..09b3e4c033 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -214,7 +214,15 @@ int pci_device_load(PCIDevice *s, QEMUFile *f); typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); -typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, int state); + +typedef enum { + PCI_HOTPLUG_DISABLED, + PCI_HOTPLUG_ENABLED, + PCI_COLDPLUG_ENABLED, +} PCIHotplugState; + +typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, + PCIHotplugState state); void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, int devfn_min); PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min); diff --git a/hw/pcie.c b/hw/pcie.c index 35918f7c2c..f461c1cfbe 100644 --- a/hw/pcie.c +++ b/hw/pcie.c @@ -192,14 +192,16 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) } static int pcie_cap_slot_hotplug(DeviceState *qdev, - PCIDevice *pci_dev, int state) + PCIDevice *pci_dev, PCIHotplugState state) { PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); uint8_t *exp_cap = d->config + d->exp.exp_cap; uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); - if (!pci_dev->qdev.hotplugged) { - assert(state); /* this case only happens at machine creation. */ + /* Don't send event when device is enabled during qemu machine creation: + * it is present on boot, no hotplug event is necessary. We do send an + * event when the device is disabled later. */ + if (state == PCI_COLDPLUG_ENABLED) { pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); return 0; @@ -219,7 +221,7 @@ static int pcie_cap_slot_hotplug(DeviceState *qdev, */ assert(PCI_FUNC(pci_dev->devfn) == 0); - if (state) { + if (state == PCI_HOTPLUG_ENABLED) { pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); From 89d437df5e68e8b289e501dde570917677fd6dfc Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Tue, 16 Nov 2010 17:26:07 +0900 Subject: [PATCH 06/30] pci: add W1C bits to pci status register This patch adds W1C bit support in the initialization/reset of pci status registers. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hw/pci.c b/hw/pci.c index 438c0d1691..00ec8ea5ed 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -143,6 +143,9 @@ static void pci_device_reset(PCIDevice *dev) pci_word_test_and_clear_mask(dev->config + PCI_COMMAND, pci_get_word(dev->wmask + PCI_COMMAND) | pci_get_word(dev->w1cmask + PCI_COMMAND)); + pci_word_test_and_clear_mask(dev->config + PCI_STATUS, + pci_get_word(dev->wmask + PCI_STATUS) | + pci_get_word(dev->w1cmask + PCI_STATUS)); dev->config[PCI_CACHE_LINE_SIZE] = 0x0; dev->config[PCI_INTERRUPT_LINE] = 0x0; for (r = 0; r < PCI_NUM_REGIONS; ++r) { @@ -552,6 +555,18 @@ static void pci_init_wmask(PCIDevice *dev) config_size - PCI_CONFIG_HEADER_SIZE); } +static void pci_init_w1cmask(PCIDevice *dev) +{ + /* + * Note: It's okay to set w1mask even for readonly bits as + * long as their value is hardwired to 0. + */ + pci_set_word(dev->w1cmask + PCI_STATUS, + PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY); +} + static void pci_init_wmask_bridge(PCIDevice *d) { /* PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS and @@ -676,6 +691,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, } pci_init_cmask(pci_dev); pci_init_wmask(pci_dev); + pci_init_w1cmask(pci_dev); if (is_bridge) { pci_init_wmask_bridge(pci_dev); } From 1a1ea6f093eb8cf7c01788bc3708ba7003815563 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Tue, 16 Nov 2010 17:26:08 +0900 Subject: [PATCH 07/30] pcie_regs.h: more constants Add constants for PCI AER log. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pcie_regs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/pcie_regs.h b/hw/pcie_regs.h index 3461a1b6b8..4d123d9fcc 100644 --- a/hw/pcie_regs.h +++ b/hw/pcie_regs.h @@ -94,7 +94,9 @@ #define PCI_ERR_CAP_MHRE 0x00000400 #define PCI_ERR_CAP_TLP 0x00000800 +#define PCI_ERR_HEADER_LOG_SIZE 16 #define PCI_ERR_TLP_PREFIX_LOG 0x38 +#define PCI_ERR_TLP_PREFIX_LOG_SIZE 16 #define PCI_SEC_STATUS_RCV_SYSTEM_ERROR 0x4000 From 34e65944c0351fabcd82aa8c85018980c7e87bff Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Tue, 16 Nov 2010 17:26:09 +0900 Subject: [PATCH 08/30] pcie/aer: helper functions for pcie aer capability This patch implements helper functions for pcie aer capability which will be used later. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- Makefile.objs | 2 +- hw/pcie.h | 14 + hw/pcie_aer.c | 827 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pcie_aer.h | 106 +++++++ qemu-common.h | 3 + 5 files changed, 951 insertions(+), 1 deletion(-) create mode 100644 hw/pcie_aer.c create mode 100644 hw/pcie_aer.h diff --git a/Makefile.objs b/Makefile.objs index faf485ed1b..c5919af054 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -207,7 +207,7 @@ hw-obj-$(CONFIG_PIIX4) += piix4.o # PCI watchdog devices hw-obj-y += wdt_i6300esb.o -hw-obj-y += pcie.o pcie_port.o +hw-obj-y += pcie.o pcie_aer.o pcie_port.o hw-obj-y += msix.o msi.o # PCI network cards diff --git a/hw/pcie.h b/hw/pcie.h index 87085041f2..7baa813509 100644 --- a/hw/pcie.h +++ b/hw/pcie.h @@ -24,6 +24,7 @@ #include "hw.h" #include "pci_regs.h" #include "pcie_regs.h" +#include "pcie_aer.h" typedef enum { /* for attention and power indicator */ @@ -79,6 +80,19 @@ struct PCIExpressDevice { Software Notification of Hot-Plug Events, an interrupt is sent whenever the logical and of these conditions transitions from false to true. */ + + /* AER */ + uint16_t aer_cap; + PCIEAERLog aer_log; + unsigned int aer_intx; /* INTx for error reporting + * default is 0 = INTA# + * If the chip wants to use other interrupt + * line, initialize this member with the + * desired number. + * If the chip dynamically changes this member, + * also initialize it when loaded as + * appropreately. + */ }; /* PCI express capability helper functions */ diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c new file mode 100644 index 0000000000..acf826aaae --- /dev/null +++ b/hw/pcie_aer.c @@ -0,0 +1,827 @@ +/* + * pcie_aer.c + * + * Copyright (c) 2010 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "sysemu.h" +#include "pci_bridge.h" +#include "pcie.h" +#include "msix.h" +#include "msi.h" +#include "pci_internals.h" +#include "pcie_regs.h" + +//#define DEBUG_PCIE +#ifdef DEBUG_PCIE +# define PCIE_DPRINTF(fmt, ...) \ + fprintf(stderr, "%s:%d " fmt, __func__, __LINE__, ## __VA_ARGS__) +#else +# define PCIE_DPRINTF(fmt, ...) do {} while (0) +#endif +#define PCIE_DEV_PRINTF(dev, fmt, ...) \ + PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__) + +/* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */ +static uint32_t pcie_aer_uncor_default_severity(uint32_t status) +{ + switch (status) { + case PCI_ERR_UNC_INTN: + case PCI_ERR_UNC_DLP: + case PCI_ERR_UNC_SDN: + case PCI_ERR_UNC_RX_OVER: + case PCI_ERR_UNC_FCP: + case PCI_ERR_UNC_MALF_TLP: + return PCI_ERR_ROOT_CMD_FATAL_EN; + case PCI_ERR_UNC_POISON_TLP: + case PCI_ERR_UNC_ECRC: + case PCI_ERR_UNC_UNSUP: + case PCI_ERR_UNC_COMP_TIME: + case PCI_ERR_UNC_COMP_ABORT: + case PCI_ERR_UNC_UNX_COMP: + case PCI_ERR_UNC_ACSV: + case PCI_ERR_UNC_MCBTLP: + case PCI_ERR_UNC_ATOP_EBLOCKED: + case PCI_ERR_UNC_TLP_PRF_BLOCKED: + return PCI_ERR_ROOT_CMD_NONFATAL_EN; + default: + abort(); + break; + } + return PCI_ERR_ROOT_CMD_FATAL_EN; +} + +static int aer_log_add_err(PCIEAERLog *aer_log, const PCIEAERErr *err) +{ + if (aer_log->log_num == aer_log->log_max) { + return -1; + } + memcpy(&aer_log->log[aer_log->log_num], err, sizeof *err); + aer_log->log_num++; + return 0; +} + +static void aer_log_del_err(PCIEAERLog *aer_log, PCIEAERErr *err) +{ + assert(aer_log->log_num); + *err = aer_log->log[0]; + aer_log->log_num--; + memmove(&aer_log->log[0], &aer_log->log[1], + aer_log->log_num * sizeof *err); +} + +static void aer_log_clear_all_err(PCIEAERLog *aer_log) +{ + aer_log->log_num = 0; +} + +int pcie_aer_init(PCIDevice *dev, uint16_t offset) +{ + PCIExpressDevice *exp; + + pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER, + offset, PCI_ERR_SIZEOF); + exp = &dev->exp; + exp->aer_cap = offset; + + /* log_max is property */ + if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) { + dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT; + } + /* clip down the value to avoid unreasobale memory usage */ + if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) { + return -EINVAL; + } + dev->exp.aer_log.log = qemu_mallocz(sizeof dev->exp.aer_log.log[0] * + dev->exp.aer_log.log_max); + + pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS, + PCI_ERR_UNC_SUPPORTED); + + pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER, + PCI_ERR_UNC_SEVERITY_DEFAULT); + pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_SEVER, + PCI_ERR_UNC_SUPPORTED); + + pci_long_test_and_set_mask(dev->w1cmask + offset + PCI_ERR_COR_STATUS, + PCI_ERR_COR_STATUS); + + pci_set_long(dev->config + offset + PCI_ERR_COR_MASK, + PCI_ERR_COR_MASK_DEFAULT); + pci_set_long(dev->wmask + offset + PCI_ERR_COR_MASK, + PCI_ERR_COR_SUPPORTED); + + /* capabilities and control. multiple header logging is supported */ + if (dev->exp.aer_log.log_max > 0) { + pci_set_long(dev->config + offset + PCI_ERR_CAP, + PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC | + PCI_ERR_CAP_MHRC); + pci_set_long(dev->wmask + offset + PCI_ERR_CAP, + PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE | + PCI_ERR_CAP_MHRE); + } else { + pci_set_long(dev->config + offset + PCI_ERR_CAP, + PCI_ERR_CAP_ECRC_GENC | PCI_ERR_CAP_ECRC_CHKC); + pci_set_long(dev->wmask + offset + PCI_ERR_CAP, + PCI_ERR_CAP_ECRC_GENE | PCI_ERR_CAP_ECRC_CHKE); + } + + switch (pcie_cap_get_type(dev)) { + case PCI_EXP_TYPE_ROOT_PORT: + /* this case will be set by pcie_aer_root_init() */ + /* fallthrough */ + case PCI_EXP_TYPE_DOWNSTREAM: + case PCI_EXP_TYPE_UPSTREAM: + pci_word_test_and_set_mask(dev->wmask + PCI_BRIDGE_CONTROL, + PCI_BRIDGE_CTL_SERR); + pci_long_test_and_set_mask(dev->w1cmask + PCI_STATUS, + PCI_SEC_STATUS_RCV_SYSTEM_ERROR); + break; + default: + /* nothing */ + break; + } + return 0; +} + +void pcie_aer_exit(PCIDevice *dev) +{ + qemu_free(dev->exp.aer_log.log); +} + +static void pcie_aer_update_uncor_status(PCIDevice *dev) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + PCIEAERLog *aer_log = &dev->exp.aer_log; + + uint16_t i; + for (i = 0; i < aer_log->log_num; i++) { + pci_long_test_and_set_mask(aer_cap + PCI_ERR_UNCOR_STATUS, + dev->exp.aer_log.log[i].status); + } +} + +/* + * pcie_aer_msg() is called recursively by + * pcie_aer_msg_alldev(), pci_aer_msg_vbridge() and pcie_aer_msg_root_port() + */ +static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg); + +/* + * return value: + * true: error message is sent up + * false: error message is masked + * + * 6.2.6 Error Message Control + * Figure 6-3 + * all pci express devices part + */ +static bool +pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) +{ + PCIDevice *parent_port; + + if (!(pcie_aer_msg_is_uncor(msg) && + (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) { + return false; + } + + /* Signaled System Error + * + * 7.5.1.1 Command register + * Bit 8 SERR# Enable + * + * When Set, this bit enables reporting of Non-fatal and Fatal + * errors detected by the Function to the Root Complex. Note that + * errors are reported if enabled either through this bit or through + * the PCI Express specific bits in the Device Control register (see + * Section 7.8.4). + */ + pci_word_test_and_set_mask(dev->config + PCI_STATUS, + PCI_STATUS_SIG_SYSTEM_ERROR); + + if (!(msg->severity & + pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL))) { + return false; + } + + /* send up error message */ + if (pci_is_express(dev) && + pcie_cap_get_type(dev) == PCI_EXP_TYPE_ROOT_PORT) { + /* Root port notify system itself, + or send the error message to root complex event collector. */ + /* + * if root port is associated to event collector, set + * parent_port = root complex event collector + * For now root complex event collector isn't supported. + */ + parent_port = NULL; + } else { + parent_port = pci_bridge_get_device(dev->bus); + } + if (parent_port) { + if (!pci_is_express(parent_port)) { + /* just ignore it */ + return false; + } + pcie_aer_msg(parent_port, msg); + } + return true; +} + +/* + * return value: + * true: error message is sent up + * false: error message is masked + * + * 6.2.6 Error Message Control + * Figure 6-3 + * virtual pci bridge part + */ +static bool pcie_aer_msg_vbridge(PCIDevice *dev, const PCIEAERMsg *msg) +{ + uint16_t bridge_control = pci_get_word(dev->config + PCI_BRIDGE_CONTROL); + + if (pcie_aer_msg_is_uncor(msg)) { + /* Received System Error */ + pci_word_test_and_set_mask(dev->config + PCI_SEC_STATUS, + PCI_SEC_STATUS_RCV_SYSTEM_ERROR); + } + + if (!(bridge_control & PCI_BRIDGE_CTL_SERR)) { + return false; + } + return true; +} + +void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + assert(vector < PCI_ERR_ROOT_IRQ_MAX); + pci_long_test_and_clear_mask(aer_cap + PCI_ERR_ROOT_STATUS, + PCI_ERR_ROOT_IRQ); + pci_long_test_and_set_mask(aer_cap + PCI_ERR_ROOT_STATUS, + vector << PCI_ERR_ROOT_IRQ_SHIFT); +} + +static unsigned int pcie_aer_root_get_vector(PCIDevice *dev) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); + return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT; +} + +/* + * return value: + * true: error message is sent up + * false: error message is masked + * + * 6.2.6 Error Message Control + * Figure 6-3 + * root port part + */ +static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) +{ + bool msg_sent; + uint16_t cmd; + uint8_t *aer_cap; + uint32_t root_cmd; + uint32_t root_status; + bool msi_trigger; + + msg_sent = false; + cmd = pci_get_word(dev->config + PCI_COMMAND); + aer_cap = dev->config + dev->exp.aer_cap; + root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); + root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); + msi_trigger = false; + + if (cmd & PCI_COMMAND_SERR) { + /* System Error. + * + * The way to report System Error is platform specific and + * it isn't implemented in qemu right now. + * So just discard the error for now. + * OS which cares of aer would receive errors via + * native aer mechanims, so this wouldn't matter. + */ + } + + /* Errro Message Received: Root Error Status register */ + switch (msg->severity) { + case PCI_ERR_ROOT_CMD_COR_EN: + if (root_status & PCI_ERR_ROOT_COR_RCV) { + root_status |= PCI_ERR_ROOT_MULTI_COR_RCV; + } else { + if (root_cmd & PCI_ERR_ROOT_CMD_COR_EN) { + msi_trigger = true; + } + pci_set_word(aer_cap + PCI_ERR_ROOT_COR_SRC, msg->source_id); + } + root_status |= PCI_ERR_ROOT_COR_RCV; + break; + case PCI_ERR_ROOT_CMD_NONFATAL_EN: + if (!(root_status & PCI_ERR_ROOT_NONFATAL_RCV) && + root_cmd & PCI_ERR_ROOT_CMD_NONFATAL_EN) { + msi_trigger = true; + } + root_status |= PCI_ERR_ROOT_NONFATAL_RCV; + break; + case PCI_ERR_ROOT_CMD_FATAL_EN: + if (!(root_status & PCI_ERR_ROOT_FATAL_RCV) && + root_cmd & PCI_ERR_ROOT_CMD_FATAL_EN) { + msi_trigger = true; + } + if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) { + root_status |= PCI_ERR_ROOT_FIRST_FATAL; + } + root_status |= PCI_ERR_ROOT_FATAL_RCV; + break; + default: + abort(); + break; + } + if (pcie_aer_msg_is_uncor(msg)) { + if (root_status & PCI_ERR_ROOT_UNCOR_RCV) { + root_status |= PCI_ERR_ROOT_MULTI_UNCOR_RCV; + } else { + pci_set_word(aer_cap + PCI_ERR_ROOT_SRC, msg->source_id); + } + root_status |= PCI_ERR_ROOT_UNCOR_RCV; + } + pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status); + + if (root_cmd & msg->severity) { + /* 6.2.4.1.2 Interrupt Generation */ + if (pci_msi_enabled(dev)) { + if (msi_trigger) { + pci_msi_notify(dev, pcie_aer_root_get_vector(dev)); + } + } else { + qemu_set_irq(dev->irq[dev->exp.aer_intx], 1); + } + msg_sent = true; + } + return msg_sent; +} + +/* + * 6.2.6 Error Message Control Figure 6-3 + */ +static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) +{ + uint8_t type; + bool msg_sent; + + assert(pci_is_express(dev)); + + type = pcie_cap_get_type(dev); + if (type == PCI_EXP_TYPE_ROOT_PORT || + type == PCI_EXP_TYPE_UPSTREAM || + type == PCI_EXP_TYPE_DOWNSTREAM) { + msg_sent = pcie_aer_msg_vbridge(dev, msg); + if (!msg_sent) { + return; + } + } + msg_sent = pcie_aer_msg_alldev(dev, msg); + if (type == PCI_EXP_TYPE_ROOT_PORT && msg_sent) { + pcie_aer_msg_root_port(dev, msg); + } +} + +static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint8_t first_bit = ffsl(err->status) - 1; + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); + int i; + + assert(err->status); + assert(err->status & (err->status - 1)); + + errcap &= ~(PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); + errcap |= PCI_ERR_CAP_FEP(first_bit); + + if (err->flags & PCIE_AER_ERR_HEADER_VALID) { + for (i = 0; i < ARRAY_SIZE(err->header); ++i) { + /* 7.10.8 Header Log Register */ + uint8_t *header_log = + aer_cap + PCI_ERR_HEADER_LOG + i * sizeof err->header[0]; + cpu_to_be32wu((uint32_t*)header_log, err->header[i]); + } + } else { + assert(!(err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT)); + memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); + } + + if ((err->flags & PCIE_AER_ERR_TLP_PREFIX_PRESENT) && + (pci_get_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL2) & + PCI_EXP_DEVCAP2_EETLPP)) { + for (i = 0; i < ARRAY_SIZE(err->prefix); ++i) { + /* 7.10.12 tlp prefix log register */ + uint8_t *prefix_log = + aer_cap + PCI_ERR_TLP_PREFIX_LOG + i * sizeof err->prefix[0]; + cpu_to_be32wu((uint32_t*)prefix_log, err->prefix[i]); + } + errcap |= PCI_ERR_CAP_TLP; + } else { + memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, + PCI_ERR_TLP_PREFIX_LOG_SIZE); + } + pci_set_long(aer_cap + PCI_ERR_CAP, errcap); +} + +static void pcie_aer_clear_log(PCIDevice *dev) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + + pci_long_test_and_clear_mask(aer_cap + PCI_ERR_CAP, + PCI_ERR_CAP_FEP_MASK | PCI_ERR_CAP_TLP); + + memset(aer_cap + PCI_ERR_HEADER_LOG, 0, PCI_ERR_HEADER_LOG_SIZE); + memset(aer_cap + PCI_ERR_TLP_PREFIX_LOG, 0, PCI_ERR_TLP_PREFIX_LOG_SIZE); +} + +static void pcie_aer_clear_error(PCIDevice *dev) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); + PCIEAERLog *aer_log = &dev->exp.aer_log; + PCIEAERErr err; + + if (!(errcap & PCI_ERR_CAP_MHRE) || !aer_log->log_num) { + pcie_aer_clear_log(dev); + return; + } + + /* + * If more errors are queued, set corresponding bits in uncorrectable + * error status. + * We emulate uncorrectable error status register as W1CS. + * So set bit in uncorrectable error status here again for multiple + * error recording support. + * + * 6.2.4.2 Multiple Error Handling(Advanced Error Reporting Capability) + */ + pcie_aer_update_uncor_status(dev); + + aer_log_del_err(aer_log, &err); + pcie_aer_update_log(dev, &err); +} + +static int pcie_aer_record_error(PCIDevice *dev, + const PCIEAERErr *err) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); + int fep = PCI_ERR_CAP_FEP(errcap); + + assert(err->status); + assert(err->status & (err->status - 1)); + + if (errcap & PCI_ERR_CAP_MHRE && + (pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS) & (1U << fep))) { + /* Not first error. queue error */ + if (aer_log_add_err(&dev->exp.aer_log, err) < 0) { + /* overflow */ + return -1; + } + return 0; + } + + pcie_aer_update_log(dev, err); + return 0; +} + +typedef struct PCIEAERInject { + PCIDevice *dev; + uint8_t *aer_cap; + const PCIEAERErr *err; + uint16_t devctl; + uint16_t devsta; + uint32_t error_status; + bool unsupported_request; + bool log_overflow; + PCIEAERMsg msg; +} PCIEAERInject; + +static bool pcie_aer_inject_cor_error(PCIEAERInject *inj, + uint32_t uncor_status, + bool is_advisory_nonfatal) +{ + PCIDevice *dev = inj->dev; + + inj->devsta |= PCI_EXP_DEVSTA_CED; + if (inj->unsupported_request) { + inj->devsta |= PCI_EXP_DEVSTA_URD; + } + pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); + + if (inj->aer_cap) { + uint32_t mask; + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_COR_STATUS, + inj->error_status); + mask = pci_get_long(inj->aer_cap + PCI_ERR_COR_MASK); + if (mask & inj->error_status) { + return false; + } + if (is_advisory_nonfatal) { + uint32_t uncor_mask = + pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); + if (!(uncor_mask & uncor_status)) { + inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); + } + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, + uncor_status); + } + } + + if (inj->unsupported_request && !(inj->devctl & PCI_EXP_DEVCTL_URRE)) { + return false; + } + if (!(inj->devctl & PCI_EXP_DEVCTL_CERE)) { + return false; + } + + inj->msg.severity = PCI_ERR_ROOT_CMD_COR_EN; + return true; +} + +static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal) +{ + PCIDevice *dev = inj->dev; + uint16_t cmd; + + if (is_fatal) { + inj->devsta |= PCI_EXP_DEVSTA_FED; + } else { + inj->devsta |= PCI_EXP_DEVSTA_NFED; + } + if (inj->unsupported_request) { + inj->devsta |= PCI_EXP_DEVSTA_URD; + } + pci_set_long(dev->config + dev->exp.exp_cap + PCI_EXP_DEVSTA, inj->devsta); + + if (inj->aer_cap) { + uint32_t mask = pci_get_long(inj->aer_cap + PCI_ERR_UNCOR_MASK); + if (mask & inj->error_status) { + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, + inj->error_status); + return false; + } + + inj->log_overflow = !!pcie_aer_record_error(dev, inj->err); + pci_long_test_and_set_mask(inj->aer_cap + PCI_ERR_UNCOR_STATUS, + inj->error_status); + } + + cmd = pci_get_word(dev->config + PCI_COMMAND); + if (inj->unsupported_request && + !(inj->devctl & PCI_EXP_DEVCTL_URRE) && !(cmd & PCI_COMMAND_SERR)) { + return false; + } + if (is_fatal) { + if (!((cmd & PCI_COMMAND_SERR) || + (inj->devctl & PCI_EXP_DEVCTL_FERE))) { + return false; + } + inj->msg.severity = PCI_ERR_ROOT_CMD_FATAL_EN; + } else { + if (!((cmd & PCI_COMMAND_SERR) || + (inj->devctl & PCI_EXP_DEVCTL_NFERE))) { + return false; + } + inj->msg.severity = PCI_ERR_ROOT_CMD_NONFATAL_EN; + } + return true; +} + +/* + * non-Function specific error must be recorded in all functions. + * It is the responsibility of the caller of this function. + * It is also caller's responsiblity to determine which function should + * report the rerror. + * + * 6.2.4 Error Logging + * 6.2.5 Sqeunce of Device Error Signaling and Logging Operations + * table 6-2: Flowchard Showing Sequence of Device Error Signaling and Logging + * Operations + */ +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err) +{ + uint8_t *aer_cap = NULL; + uint16_t devctl = 0; + uint16_t devsta = 0; + uint32_t error_status = err->status; + PCIEAERInject inj; + + if (!pci_is_express(dev)) { + return -ENOSYS; + } + + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { + error_status &= PCI_ERR_COR_SUPPORTED; + } else { + error_status &= PCI_ERR_UNC_SUPPORTED; + } + + /* invalid status bit. one and only one bit must be set */ + if (!error_status || (error_status & (error_status - 1))) { + return -EINVAL; + } + + if (dev->exp.aer_cap) { + uint8_t *exp_cap = dev->config + dev->exp.exp_cap; + aer_cap = dev->config + dev->exp.aer_cap; + devctl = pci_get_long(exp_cap + PCI_EXP_DEVCTL); + devsta = pci_get_long(exp_cap + PCI_EXP_DEVSTA); + } + + inj.dev = dev; + inj.aer_cap = aer_cap; + inj.err = err; + inj.devctl = devctl; + inj.devsta = devsta; + inj.error_status = error_status; + inj.unsupported_request = !(err->flags & PCIE_AER_ERR_IS_CORRECTABLE) && + err->status == PCI_ERR_UNC_UNSUP; + inj.log_overflow = false; + + if (err->flags & PCIE_AER_ERR_IS_CORRECTABLE) { + if (!pcie_aer_inject_cor_error(&inj, 0, false)) { + return 0; + } + } else { + bool is_fatal = + pcie_aer_uncor_default_severity(error_status) == + PCI_ERR_ROOT_CMD_FATAL_EN; + if (aer_cap) { + is_fatal = + error_status & pci_get_long(aer_cap + PCI_ERR_UNCOR_SEVER); + } + if (!is_fatal && (err->flags & PCIE_AER_ERR_MAYBE_ADVISORY)) { + inj.error_status = PCI_ERR_COR_ADV_NONFATAL; + if (!pcie_aer_inject_cor_error(&inj, error_status, true)) { + return 0; + } + } else { + if (!pcie_aer_inject_uncor_error(&inj, is_fatal)) { + return 0; + } + } + } + + /* send up error message */ + inj.msg.source_id = err->source_id; + pcie_aer_msg(dev, &inj.msg); + + if (inj.log_overflow) { + PCIEAERErr header_log_overflow = { + .status = PCI_ERR_COR_HL_OVERFLOW, + .flags = PCIE_AER_ERR_IS_CORRECTABLE, + }; + int ret = pcie_aer_inject_error(dev, &header_log_overflow); + assert(!ret); + } + return 0; +} + +void pcie_aer_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + uint32_t errcap = pci_get_long(aer_cap + PCI_ERR_CAP); + uint32_t first_error = 1U << PCI_ERR_CAP_FEP(errcap); + uint32_t uncorsta = pci_get_long(aer_cap + PCI_ERR_UNCOR_STATUS); + + /* uncorrectable error */ + if (!(uncorsta & first_error)) { + /* the bit that corresponds to the first error is cleared */ + pcie_aer_clear_error(dev); + } else if (errcap & PCI_ERR_CAP_MHRE) { + /* When PCI_ERR_CAP_MHRE is enabled and the first error isn't cleared + * nothing should happen. So we have to revert the modification to + * the register. + */ + pcie_aer_update_uncor_status(dev); + } else { + /* capability & control + * PCI_ERR_CAP_MHRE might be cleared, so clear of header log. + */ + aer_log_clear_all_err(&dev->exp.aer_log); + } +} + +void pcie_aer_root_init(PCIDevice *dev) +{ + uint16_t pos = dev->exp.aer_cap; + + pci_set_long(dev->wmask + pos + PCI_ERR_ROOT_COMMAND, + PCI_ERR_ROOT_CMD_EN_MASK); + pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS, + PCI_ERR_ROOT_STATUS_REPORT_MASK); +} + +void pcie_aer_root_reset(PCIDevice *dev) +{ + uint8_t* aer_cap = dev->config + dev->exp.aer_cap; + + pci_set_long(aer_cap + PCI_ERR_ROOT_COMMAND, 0); + + /* + * Advanced Error Interrupt Message Number in Root Error Status Register + * must be updated by chip dependent code because it's chip dependent + * which number is used. + */ +} + +static bool pcie_aer_root_does_trigger(uint32_t cmd, uint32_t status) +{ + return + ((cmd & PCI_ERR_ROOT_CMD_COR_EN) && (status & PCI_ERR_ROOT_COR_RCV)) || + ((cmd & PCI_ERR_ROOT_CMD_NONFATAL_EN) && + (status & PCI_ERR_ROOT_NONFATAL_RCV)) || + ((cmd & PCI_ERR_ROOT_CMD_FATAL_EN) && + (status & PCI_ERR_ROOT_FATAL_RCV)); +} + +void pcie_aer_root_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len, + uint32_t root_cmd_prev) +{ + uint8_t *aer_cap = dev->config + dev->exp.aer_cap; + + /* root command register */ + uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND); + if (root_cmd & PCI_ERR_ROOT_CMD_EN_MASK) { + /* 6.2.4.1.2 Interrupt Generation */ + + /* 0 -> 1 */ + uint32_t root_cmd_set = (root_cmd_prev ^ root_cmd) & root_cmd; + uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS); + + if (pci_msi_enabled(dev)) { + if (pcie_aer_root_does_trigger(root_cmd_set, root_status)) { + pci_msi_notify(dev, pcie_aer_root_get_vector(dev)); + } + } else { + int int_level = pcie_aer_root_does_trigger(root_cmd, root_status); + qemu_set_irq(dev->irq[dev->exp.aer_intx], int_level); + } + } +} + +static const VMStateDescription vmstate_pcie_aer_err = { + .name = "PCIE_AER_ERROR", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(status, PCIEAERErr), + VMSTATE_UINT16(source_id, PCIEAERErr), + VMSTATE_UINT16(flags, PCIEAERErr), + VMSTATE_UINT32_ARRAY(header, PCIEAERErr, 4), + VMSTATE_UINT32_ARRAY(prefix, PCIEAERErr, 4), + VMSTATE_END_OF_LIST() + } +}; + +#define VMSTATE_PCIE_AER_ERRS(_field, _state, _field_num, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .version_id = 0, \ + .num_offset = vmstate_offset_value(_state, _field_num, uint16_t), \ + .size = sizeof(_type), \ + .vmsd = &(_vmsd), \ + .flags = VMS_POINTER | VMS_VARRAY_UINT16 | VMS_STRUCT, \ + .offset = vmstate_offset_pointer(_state, _field, _type), \ +} + +const VMStateDescription vmstate_pcie_aer_log = { + .name = "PCIE_AER_ERROR_LOG", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT16(log_num, PCIEAERLog), + VMSTATE_UINT16(log_max, PCIEAERLog), + VMSTATE_PCIE_AER_ERRS(log, PCIEAERLog, log_num, + vmstate_pcie_aer_err, PCIEAERErr), + VMSTATE_END_OF_LIST() + } +}; + diff --git a/hw/pcie_aer.h b/hw/pcie_aer.h new file mode 100644 index 0000000000..7539500cd8 --- /dev/null +++ b/hw/pcie_aer.h @@ -0,0 +1,106 @@ +/* + * pcie_aer.h + * + * Copyright (c) 2010 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef QEMU_PCIE_AER_H +#define QEMU_PCIE_AER_H + +#include "hw.h" + +/* definitions which PCIExpressDevice uses */ + +/* AER log */ +struct PCIEAERLog { + /* This structure is saved/loaded. + So explicitly size them instead of unsigned int */ + + /* the number of currently recorded log in log member */ + uint16_t log_num; + + /* + * The maximum number of the log. Errors can be logged up to this. + * + * This is configurable property. + * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT + * to avoid unreasonable memory usage. + * I bet that 128 log size would be big enough, otherwise too many errors + * for system to function normaly. But could consecutive errors occur? + */ +#define PCIE_AER_LOG_MAX_DEFAULT 8 +#define PCIE_AER_LOG_MAX_LIMIT 128 +#define PCIE_AER_LOG_MAX_UNSET 0xffff + uint16_t log_max; + + /* Error log. log_max-sized array */ + PCIEAERErr *log; +}; + +/* aer error message: error signaling message has only error sevirity and + source id. See 2.2.8.3 error signaling messages */ +struct PCIEAERMsg { + /* + * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN + * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE} + */ + uint32_t severity; + + uint16_t source_id; /* bdf */ +}; + +static inline bool +pcie_aer_msg_is_uncor(const PCIEAERMsg *msg) +{ + return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN || + msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN; +} + +/* error */ +struct PCIEAERErr { + uint32_t status; /* error status bits */ + uint16_t source_id; /* bdf */ + +#define PCIE_AER_ERR_IS_CORRECTABLE 0x1 /* correctable/uncorrectable */ +#define PCIE_AER_ERR_MAYBE_ADVISORY 0x2 /* maybe advisory non-fatal */ +#define PCIE_AER_ERR_HEADER_VALID 0x4 /* TLP header is logged */ +#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8 /* TLP Prefix is logged */ + uint16_t flags; + + uint32_t header[4]; /* TLP header */ + uint32_t prefix[4]; /* TLP header prefix */ +}; + +extern const VMStateDescription vmstate_pcie_aer_log; + +int pcie_aer_init(PCIDevice *dev, uint16_t offset); +void pcie_aer_exit(PCIDevice *dev); +void pcie_aer_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len); + +/* aer root port */ +void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector); +void pcie_aer_root_init(PCIDevice *dev); +void pcie_aer_root_reset(PCIDevice *dev); +void pcie_aer_root_write_config(PCIDevice *dev, + uint32_t addr, uint32_t val, int len, + uint32_t root_cmd_prev); + +/* error injection */ +int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err); + +#endif /* QEMU_PCIE_AER_H */ diff --git a/qemu-common.h b/qemu-common.h index b3957f1859..de82c2ea13 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -240,6 +240,9 @@ typedef struct PCIBus PCIBus; typedef struct PCIDevice PCIDevice; typedef struct PCIExpressDevice PCIExpressDevice; typedef struct PCIBridge PCIBridge; +typedef struct PCIEAERMsg PCIEAERMsg; +typedef struct PCIEAERLog PCIEAERLog; +typedef struct PCIEAERErr PCIEAERErr; typedef struct PCIEPort PCIEPort; typedef struct PCIESlot PCIESlot; typedef struct SerialState SerialState; From 247c97f3f5ab0dae60778a2dea438bfed5c69e68 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 17 Nov 2010 15:02:26 +0200 Subject: [PATCH 09/30] pcie_aer: get rid of recursion Added some TODOs: they are trivial but omitted here to make the patch logic as transparent as possible. Signed-off-by: Michael S. Tsirkin --- hw/pcie_aer.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c index acf826aaae..c565d393d6 100644 --- a/hw/pcie_aer.c +++ b/hw/pcie_aer.c @@ -175,15 +175,9 @@ static void pcie_aer_update_uncor_status(PCIDevice *dev) } } -/* - * pcie_aer_msg() is called recursively by - * pcie_aer_msg_alldev(), pci_aer_msg_vbridge() and pcie_aer_msg_root_port() - */ -static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg); - /* * return value: - * true: error message is sent up + * true: error message needs to be sent up * false: error message is masked * * 6.2.6 Error Message Control @@ -193,8 +187,6 @@ static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg); static bool pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) { - PCIDevice *parent_port; - if (!(pcie_aer_msg_is_uncor(msg) && (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) { return false; @@ -220,13 +212,21 @@ pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) } /* send up error message */ + return true; +} + +/* Get parent port to send up error message on. + * TODO: clean up and open-code this logic */ +static PCIDevice *pcie_aer_parent_port(PCIDevice *dev) +{ + PCIDevice *parent_port; if (pci_is_express(dev) && pcie_cap_get_type(dev) == PCI_EXP_TYPE_ROOT_PORT) { - /* Root port notify system itself, + /* Root port can notify system itself, or send the error message to root complex event collector. */ /* - * if root port is associated to event collector, set - * parent_port = root complex event collector + * if root port is associated with an event collector, + * return the root complex event collector here. * For now root complex event collector isn't supported. */ parent_port = NULL; @@ -236,11 +236,10 @@ pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) if (parent_port) { if (!pci_is_express(parent_port)) { /* just ignore it */ - return false; + return NULL; } - pcie_aer_msg(parent_port, msg); } - return true; + return parent_port; } /* @@ -381,8 +380,12 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) /* * 6.2.6 Error Message Control Figure 6-3 + * + * Returns true in case the error needs to + * be propagated up. + * TODO: open-code. */ -static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) +static bool pcie_send_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) { uint8_t type; bool msg_sent; @@ -402,6 +405,18 @@ static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) if (type == PCI_EXP_TYPE_ROOT_PORT && msg_sent) { pcie_aer_msg_root_port(dev, msg); } + return msg_sent; +} + +static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) +{ + bool send_to_parent; + while (dev) { + if (!pcie_send_aer_msg(dev, msg)) { + return; + } + dev = pcie_aer_parent_port(dev); + } } static void pcie_aer_update_log(PCIDevice *dev, const PCIEAERErr *err) @@ -824,4 +839,3 @@ const VMStateDescription vmstate_pcie_aer_log = { VMSTATE_END_OF_LIST() } }; - From d33d9156fdffb87c99564c9630023da52c66f37a Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 17 Nov 2010 15:45:39 +0200 Subject: [PATCH 10/30] pcie_aer: complete unwinding recursion Open-code functions created in the previous patch, to make code more compact and clear. Detcted and documented what looks like a bug in code that becomes apparent from this refactoring. Signed-off-by: Michael S. Tsirkin --- hw/pcie_aer.c | 86 ++++++++++++++++++--------------------------------- 1 file changed, 30 insertions(+), 56 deletions(-) diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c index c565d393d6..235ac534d7 100644 --- a/hw/pcie_aer.c +++ b/hw/pcie_aer.c @@ -215,33 +215,6 @@ pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg) return true; } -/* Get parent port to send up error message on. - * TODO: clean up and open-code this logic */ -static PCIDevice *pcie_aer_parent_port(PCIDevice *dev) -{ - PCIDevice *parent_port; - if (pci_is_express(dev) && - pcie_cap_get_type(dev) == PCI_EXP_TYPE_ROOT_PORT) { - /* Root port can notify system itself, - or send the error message to root complex event collector. */ - /* - * if root port is associated with an event collector, - * return the root complex event collector here. - * For now root complex event collector isn't supported. - */ - parent_port = NULL; - } else { - parent_port = pci_bridge_get_device(dev->bus); - } - if (parent_port) { - if (!pci_is_express(parent_port)) { - /* just ignore it */ - return NULL; - } - } - return parent_port; -} - /* * return value: * true: error message is sent up @@ -381,41 +354,42 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg) /* * 6.2.6 Error Message Control Figure 6-3 * - * Returns true in case the error needs to - * be propagated up. - * TODO: open-code. + * Walk up the bus tree from the device, propagate the error message. */ -static bool pcie_send_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) -{ - uint8_t type; - bool msg_sent; - - assert(pci_is_express(dev)); - - type = pcie_cap_get_type(dev); - if (type == PCI_EXP_TYPE_ROOT_PORT || - type == PCI_EXP_TYPE_UPSTREAM || - type == PCI_EXP_TYPE_DOWNSTREAM) { - msg_sent = pcie_aer_msg_vbridge(dev, msg); - if (!msg_sent) { - return; - } - } - msg_sent = pcie_aer_msg_alldev(dev, msg); - if (type == PCI_EXP_TYPE_ROOT_PORT && msg_sent) { - pcie_aer_msg_root_port(dev, msg); - } - return msg_sent; -} - static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg) { - bool send_to_parent; + uint8_t type; + while (dev) { - if (!pcie_send_aer_msg(dev, msg)) { + if (!pci_is_express(dev)) { + /* just ignore it */ + /* TODO: Shouldn't we set PCI_STATUS_SIG_SYSTEM_ERROR? + * Consider e.g. a PCI bridge above a PCI Express device. */ return; } - dev = pcie_aer_parent_port(dev); + + type = pcie_cap_get_type(dev); + if ((type == PCI_EXP_TYPE_ROOT_PORT || + type == PCI_EXP_TYPE_UPSTREAM || + type == PCI_EXP_TYPE_DOWNSTREAM) && + !pcie_aer_msg_vbridge(dev, msg)) { + return; + } + if (!pcie_aer_msg_alldev(dev, msg)) { + return; + } + if (type == PCI_EXP_TYPE_ROOT_PORT) { + pcie_aer_msg_root_port(dev, msg); + /* Root port can notify system itself, + or send the error message to root complex event collector. */ + /* + * if root port is associated with an event collector, + * return the root complex event collector here. + * For now root complex event collector isn't supported. + */ + return; + } + dev = pci_bridge_get_device(dev->bus); } } From 61620c2fff7dda789dbba513c18f534c0062062b Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Tue, 16 Nov 2010 17:26:10 +0900 Subject: [PATCH 11/30] ioh3420: support aer Add aer support. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/ioh3420.c | 80 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 10 deletions(-) diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 3cc129f50b..95adf0978f 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -36,25 +36,59 @@ #define IOH_EP_EXP_OFFSET 0x90 #define IOH_EP_AER_OFFSET 0x100 +/* + * If two MSI vector are allocated, Advanced Error Interrupt Message Number + * is 1. otherwise 0. + * 17.12.5.10 RPERRSTS, 32:27 bit Advanced Error Interrupt Message Number. + */ +static uint8_t ioh3420_aer_vector(const PCIDevice *d) +{ + switch (msi_nr_vectors_allocated(d)) { + case 1: + return 0; + case 2: + return 1; + case 4: + case 8: + case 16: + case 32: + default: + break; + } + abort(); + return 0; +} + +static void ioh3420_aer_vector_update(PCIDevice *d) +{ + 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); msi_write_config(d, address, val, len); + ioh3420_aer_vector_update(d); pcie_cap_slot_write_config(d, address, val, len); - /* TODO: AER */ + 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 = DO_UPCAST(PCIDevice, qdev, qdev); msi_reset(d); + ioh3420_aer_vector_update(d); pcie_cap_root_reset(d); pcie_cap_deverr_reset(d); pcie_cap_slot_reset(d); + pcie_aer_root_reset(d); pci_bridge_reset(qdev); pci_bridge_disable_base_limit(d); - /* TODO: AER */ } static int ioh3420_initfn(PCIDevice *d) @@ -63,6 +97,7 @@ static int ioh3420_initfn(PCIDevice *d) PCIEPort *p = DO_UPCAST(PCIEPort, br, br); PCIESlot *s = DO_UPCAST(PCIESlot, port, p); int rc; + int tmp; rc = pci_bridge_initfn(d); if (rc < 0) { @@ -78,35 +113,57 @@ static int ioh3420_initfn(PCIDevice *d) rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET, IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID); if (rc < 0) { - return rc; + goto err_bridge; } 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); if (rc < 0) { - return rc; + goto err_bridge; } rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port); if (rc < 0) { - return rc; + goto err_msi; } pcie_cap_deverr_init(d); pcie_cap_slot_init(d, s->slot); pcie_chassis_create(s->chassis); rc = pcie_chassis_add_slot(s); if (rc < 0) { + goto err_pcie_cap; return rc; } pcie_cap_root_init(d); - /* TODO: AER */ + rc = pcie_aer_init(d, IOH_EP_AER_OFFSET); + if (rc < 0) { + 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: + tmp = pci_bridge_exitfn(d); + assert(!tmp); + return rc; } static int ioh3420_exitfn(PCIDevice *d) { - /* TODO: AER */ - msi_uninit(d); + PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); + PCIEPort *p = DO_UPCAST(PCIEPort, br, br); + PCIESlot *s = DO_UPCAST(PCIESlot, port, p); + + pcie_aer_exit(d); + pcie_chassis_del_slot(s); pcie_cap_exit(d); + msi_uninit(d); return pci_bridge_exitfn(d); } @@ -142,7 +199,8 @@ static const VMStateDescription vmstate_ioh3420 = { .post_load = pcie_cap_slot_post_load, .fields = (VMStateField[]) { VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot), - /* TODO: AER */ + VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0, + vmstate_pcie_aer_log, PCIEAERLog), VMSTATE_END_OF_LIST() } }; @@ -164,7 +222,9 @@ static PCIDeviceInfo ioh3420_info = { DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0), DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), - /* TODO: AER */ + DEFINE_PROP_UINT16("aer_log_max", PCIESlot, + port.br.dev.exp.aer_log.log_max, + PCIE_AER_LOG_MAX_DEFAULT), DEFINE_PROP_END_OF_LIST(), } }; From a158f92fa78b1e87e5d196b72b750fedefb7b43e Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Tue, 16 Nov 2010 17:26:11 +0900 Subject: [PATCH 12/30] x3130/upstream: support aer add aer support. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/xio3130_upstream.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index d9d637fdae..387bf6c77e 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -41,7 +41,7 @@ static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address, pci_bridge_write_config(d, address, val, len); pcie_cap_flr_write_config(d, address, val, len); msi_write_config(d, address, val, len); - /* TODO: AER */ + pcie_aer_write_config(d, address, val, len); } static void xio3130_upstream_reset(DeviceState *qdev) @@ -57,6 +57,7 @@ static int xio3130_upstream_initfn(PCIDevice *d) PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); PCIEPort *p = DO_UPCAST(PCIEPort, br, br); int rc; + int tmp; rc = pci_bridge_initfn(d); if (rc < 0) { @@ -72,33 +73,45 @@ static int xio3130_upstream_initfn(PCIDevice *d) XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT); if (rc < 0) { - return rc; + goto err_bridge; } rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET, XIO3130_SSVID_SVID, XIO3130_SSVID_SSID); if (rc < 0) { - return rc; + goto err_bridge; } rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM, p->port); if (rc < 0) { - return rc; + goto err_msi; } /* TODO: implement FLR */ pcie_cap_flr_init(d); pcie_cap_deverr_init(d); - /* TODO: AER */ + rc = pcie_aer_init(d, XIO3130_AER_OFFSET); + if (rc < 0) { + goto err; + } return 0; + +err: + pcie_cap_exit(d); +err_msi: + msi_uninit(d); +err_bridge: + tmp = pci_bridge_exitfn(d); + assert(!tmp); + return rc; } static int xio3130_upstream_exitfn(PCIDevice *d) { - /* TODO: AER */ - msi_uninit(d); + pcie_aer_exit(d); pcie_cap_exit(d); + msi_uninit(d); return pci_bridge_exitfn(d); } @@ -131,7 +144,8 @@ static const VMStateDescription vmstate_xio3130_upstream = { .minimum_version_id_old = 1, .fields = (VMStateField[]) { VMSTATE_PCIE_DEVICE(br.dev, PCIEPort), - /* TODO: AER */ + VMSTATE_STRUCT(br.dev.exp.aer_log, PCIEPort, 0, vmstate_pcie_aer_log, + PCIEAERLog), VMSTATE_END_OF_LIST() } }; @@ -151,7 +165,8 @@ static PCIDeviceInfo xio3130_upstream_info = { .qdev.props = (Property[]) { DEFINE_PROP_UINT8("port", PCIEPort, port, 0), - /* TODO: AER */ + DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max, + PCIE_AER_LOG_MAX_DEFAULT), DEFINE_PROP_END_OF_LIST(), } }; From 09b926d44674cbcf198425a5b8255e3cacb398ae Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Tue, 16 Nov 2010 17:26:12 +0900 Subject: [PATCH 13/30] x3130/downstream: support aer. add aer support. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/xio3130_downstream.c | 43 +++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 854eba8931..1a2d258bd2 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -42,7 +42,7 @@ static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address, pcie_cap_flr_write_config(d, address, val, len); pcie_cap_slot_write_config(d, address, val, len); msi_write_config(d, address, val, len); - /* TODO: AER */ + pcie_aer_write_config(d, address, val, len); } static void xio3130_downstream_reset(DeviceState *qdev) @@ -61,6 +61,7 @@ static int xio3130_downstream_initfn(PCIDevice *d) PCIEPort *p = DO_UPCAST(PCIEPort, br, br); PCIESlot *s = DO_UPCAST(PCIESlot, port, p); int rc; + int tmp; rc = pci_bridge_initfn(d); if (rc < 0) { @@ -76,17 +77,17 @@ static int xio3130_downstream_initfn(PCIDevice *d) XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT); if (rc < 0) { - return rc; + goto err_bridge; } rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET, XIO3130_SSVID_SVID, XIO3130_SSVID_SSID); if (rc < 0) { - return rc; + goto err_bridge; } rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM, p->port); if (rc < 0) { - return rc; + goto err_msi; } pcie_cap_flr_init(d); /* TODO: implement FLR */ pcie_cap_deverr_init(d); @@ -94,19 +95,38 @@ static int xio3130_downstream_initfn(PCIDevice *d) pcie_chassis_create(s->chassis); rc = pcie_chassis_add_slot(s); if (rc < 0) { - return rc; + goto err_pcie_cap; } pcie_cap_ari_init(d); - /* TODO: AER */ + rc = pcie_aer_init(d, XIO3130_AER_OFFSET); + if (rc < 0) { + goto err; + } return 0; + +err: + pcie_chassis_del_slot(s); +err_pcie_cap: + pcie_cap_exit(d); +err_msi: + msi_uninit(d); +err_bridge: + tmp = pci_bridge_exitfn(d); + assert(!tmp); + return rc; } static int xio3130_downstream_exitfn(PCIDevice *d) { - /* TODO: AER */ - msi_uninit(d); + PCIBridge* br = DO_UPCAST(PCIBridge, dev, d); + PCIEPort *p = DO_UPCAST(PCIEPort, br, br); + PCIESlot *s = DO_UPCAST(PCIESlot, port, p); + + pcie_aer_exit(d); + pcie_chassis_del_slot(s); pcie_cap_exit(d); + msi_uninit(d); return pci_bridge_exitfn(d); } @@ -144,7 +164,8 @@ static const VMStateDescription vmstate_xio3130_downstream = { .post_load = pcie_cap_slot_post_load, .fields = (VMStateField[]) { VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot), - /* TODO: AER */ + VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0, + vmstate_pcie_aer_log, PCIEAERLog), VMSTATE_END_OF_LIST() } }; @@ -166,7 +187,9 @@ static PCIDeviceInfo xio3130_downstream_info = { DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0), DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), - /* TODO: AER */ + DEFINE_PROP_UINT16("aer_log_max", PCIESlot, + port.br.dev.exp.aer_log.log_max, + PCIE_AER_LOG_MAX_DEFAULT), DEFINE_PROP_END_OF_LIST(), } }; From f6bdfcc9352e53fac5b9a144fc9ead991163484b Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 18 Nov 2010 10:42:50 +0200 Subject: [PATCH 14/30] pci: fix bridge control bit wmask Bits 12 to 15 in bridge control register are reserver and must be read-only zero, curent mask is 0xffff which makes them writeable. Fix this up by using symbolic bit names for writeable bits instead of a hardcoded constant. Fix a comment w1mask -> w1cmask as well. Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index 00ec8ea5ed..fc5d340b65 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -558,7 +558,7 @@ static void pci_init_wmask(PCIDevice *dev) static void pci_init_w1cmask(PCIDevice *dev) { /* - * Note: It's okay to set w1mask even for readonly bits as + * Note: It's okay to set w1cmask even for readonly bits as * long as their value is hardwired to 0. */ pci_set_word(dev->w1cmask + PCI_STATUS, @@ -588,7 +588,29 @@ static void pci_init_wmask_bridge(PCIDevice *d) /* PCI_PREF_BASE_UPPER32 and PCI_PREF_LIMIT_UPPER32 */ memset(d->wmask + PCI_PREF_BASE_UPPER32, 0xff, 8); - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, 0xffff); +/* TODO: add this define to pci_regs.h in linux and then in qemu. */ +#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ +#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ +#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */ +#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */ +#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */ + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, + PCI_BRIDGE_CTL_PARITY | + PCI_BRIDGE_CTL_SERR | + PCI_BRIDGE_CTL_ISA | + PCI_BRIDGE_CTL_VGA | + PCI_BRIDGE_CTL_VGA_16BIT | + PCI_BRIDGE_CTL_MASTER_ABORT | + PCI_BRIDGE_CTL_BUS_RESET | + PCI_BRIDGE_CTL_FAST_BACK | + PCI_BRIDGE_CTL_DISCARD | + PCI_BRIDGE_CTL_SEC_DISCARD | + PCI_BRIDGE_CTL_DISCARD_STATUS | + PCI_BRIDGE_CTL_DISCARD_SERR); + /* Below does not do anything as we never set this bit, put here for + * completeness. */ + pci_set_word(d->w1cmask + PCI_BRIDGE_CONTROL, + PCI_BRIDGE_CTL_DISCARD_STATUS); } static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev) From bba5ed772a562fefdb218df8d821c3b537ce5759 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Fri, 19 Nov 2010 13:28:45 +0200 Subject: [PATCH 15/30] pcie/port: fix bridge control register wmask pci generic layer initialized wmask for bridge control register according to pci spec. pcie deviates slightly from it, so initialize it properly. Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/pcie_port.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/pcie_port.c b/hw/pcie_port.c index 117de6186e..340dcdb3c4 100644 --- a/hw/pcie_port.c +++ b/hw/pcie_port.c @@ -27,6 +27,14 @@ void pcie_port_init_reg(PCIDevice *d) pci_set_word(d->config + PCI_STATUS, 0); pci_set_word(d->config + PCI_SEC_STATUS, 0); + /* Unlike conventional pci bridge, some bits are hardwared to 0. */ + pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, + PCI_BRIDGE_CTL_PARITY | + PCI_BRIDGE_CTL_ISA | + PCI_BRIDGE_CTL_VGA | + PCI_BRIDGE_CTL_SERR | + PCI_BRIDGE_CTL_BUS_RESET); + /* 7.5.3.5 Prefetchable Memory Base Limit * The Prefetchable Memory Base and Prefetchable Memory Limit registers * must indicate that 64-bit addresses are supported, as defined in From b90c73cf475d69959dde208d00961c3cb7a57475 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 19 Nov 2010 19:29:07 +0100 Subject: [PATCH 16/30] pci: Replace unneeded type casts in calls of pci_register_bar There is no need for these type casts (as other existing code shows). So re-write the first argument without type cast (and remove a related TODO comment). Cc: Michael S. Tsirkin Signed-off-by: Stefan Weil Signed-off-by: Michael S. Tsirkin --- hw/cirrus_vga.c | 4 ++-- hw/e1000.c | 4 ++-- hw/ide/via.c | 2 +- hw/lsi53c895a.c | 7 +++---- hw/openpic.c | 2 +- hw/usb-ohci.c | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index aadc56f692..40be55d1b1 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -3204,10 +3204,10 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) /* memory #0 LFB */ /* memory #1 memory-mapped I/O */ /* XXX: s->vga.vram_size must be a power of two */ - pci_register_bar((PCIDevice *)d, 0, 0x2000000, + pci_register_bar(&d->dev, 0, 0x2000000, PCI_BASE_ADDRESS_MEM_PREFETCH, cirrus_pci_lfb_map); if (device_id == CIRRUS_ID_CLGD5446) { - pci_register_bar((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE, + pci_register_bar(&d->dev, 1, CIRRUS_PNPMMIO_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map); } return 0; diff --git a/hw/e1000.c b/hw/e1000.c index 677165f830..b7f585bc08 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1130,10 +1130,10 @@ static int pci_e1000_init(PCIDevice *pci_dev) d->mmio_index = cpu_register_io_memory(e1000_mmio_read, e1000_mmio_write, d); - pci_register_bar((PCIDevice *)d, 0, PNPMMIO_SIZE, + pci_register_bar(&d->dev, 0, PNPMMIO_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY, e1000_mmio_map); - pci_register_bar((PCIDevice *)d, 1, IOPORT_SIZE, + pci_register_bar(&d->dev, 1, IOPORT_SIZE, PCI_BASE_ADDRESS_SPACE_IO, ioport_map); memmove(d->eeprom_data, e1000_eeprom_template, diff --git a/hw/ide/via.c b/hw/ide/via.c index b2c7cad622..2001a36b02 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -153,7 +153,7 @@ static int vt82c686b_ide_initfn(PCIDevice *dev) pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0); qemu_register_reset(via_reset, d); - pci_register_bar((PCIDevice *)d, 4, 0x10, + pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map); vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d); diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index f97335eaa9..1aef62f9a6 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -2177,12 +2177,11 @@ static int lsi_scsi_init(PCIDevice *dev) s->ram_io_addr = cpu_register_io_memory(lsi_ram_readfn, lsi_ram_writefn, s); - /* TODO: use dev and get rid of cast below */ - pci_register_bar((struct PCIDevice *)s, 0, 256, + pci_register_bar(&s->dev, 0, 256, PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc); - pci_register_bar((struct PCIDevice *)s, 1, 0x400, + pci_register_bar(&s->dev, 1, 0x400, PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc); - pci_register_bar((struct PCIDevice *)s, 2, 0x2000, + pci_register_bar(&s->dev, 2, 0x2000, PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc); QTAILQ_INIT(&s->queue); diff --git a/hw/openpic.c b/hw/openpic.c index 01bf15fc3b..f6b8f21272 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -1197,7 +1197,7 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, pci_conf[0x3d] = 0x00; // no interrupt pin /* Register I/O spaces */ - pci_register_bar((PCIDevice *)opp, 0, 0x40000, + pci_register_bar(&opp->pci_dev, 0, 0x40000, PCI_BASE_ADDRESS_SPACE_MEMORY, &openpic_map); } else { opp = qemu_mallocz(sizeof(openpic_t)); diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index c60fd8deef..8fb2f83f0f 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1741,7 +1741,7 @@ static int usb_ohci_initfn_pci(struct PCIDevice *dev) ohci->state.irq = ohci->pci_dev.irq[0]; /* TODO: avoid cast below by using dev */ - pci_register_bar((struct PCIDevice *)ohci, 0, 256, + pci_register_bar(&ohci->pci_dev, 0, 256, PCI_BASE_ADDRESS_SPACE_MEMORY, ohci_mapfunc); return 0; } From ab85ceb1ad8797af2fb4c06bdc70f0ce0cf9b34f Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Tue, 19 Oct 2010 23:08:21 +0200 Subject: [PATCH 17/30] pci: Automatically patch PCI vendor id and device id in PCI ROM PCI devices with different vendor or device ids sometimes share the same rom code. Only the ids and the checksum differs in a boot rom for such devices. The i825xx ethernet controller family is a typical example which is implemented in hw/eepro100.c. It uses at least 3 different device ids, so normally 3 boot roms would be needed. By automatically patching vendor id and device id (and the checksum) in qemu, all emulated family members can share the same boot rom. VGA bios roms are another example with different vendor and device ids. Only qemu's built-in default rom files will be patched. v2: * Patch also the vendor id (and remove the sanity check for vendor id). v3: * Don't patch a rom file when its name was set by the user. Thus we avoid modifications of unknown rom data. Cc: Gerd Hoffmann Cc: Markus Armbruster Cc: Michael S. Tsirkin Signed-off-by: Stefan Weil Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index fc5d340b65..c0a825876a 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -61,7 +61,7 @@ struct BusInfo pci_bus_info = { static void pci_update_mappings(PCIDevice *d); static void pci_set_irq(void *opaque, int irq_num, int level); -static int pci_add_option_rom(PCIDevice *pdev); +static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom); static void pci_del_option_rom(PCIDevice *pdev); static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET; @@ -1571,6 +1571,7 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev); PCIBus *bus; int devfn, rc; + bool is_default_rom; /* initialize cap_present for pci_is_express() and pci_config_size() */ if (info->is_express) { @@ -1591,9 +1592,12 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) } /* rom loading */ - if (pci_dev->romfile == NULL && info->romfile != NULL) + is_default_rom = false; + if (pci_dev->romfile == NULL && info->romfile != NULL) { pci_dev->romfile = qemu_strdup(info->romfile); - pci_add_option_rom(pci_dev); + is_default_rom = true; + } + pci_add_option_rom(pci_dev, is_default_rom); if (bus->hotplug) { /* Let buses differentiate between hotplug and when device is @@ -1701,8 +1705,64 @@ static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, p cpu_register_physical_memory(addr, size, pdev->rom_offset); } +/* Patch the PCI vendor and device ids in a PCI rom image if necessary. + This is needed for an option rom which is used for more than one device. */ +static void pci_patch_ids(PCIDevice *pdev, uint8_t *ptr, int size) +{ + uint16_t vendor_id; + uint16_t device_id; + uint16_t rom_vendor_id; + uint16_t rom_device_id; + uint16_t rom_magic; + uint16_t pcir_offset; + uint8_t checksum; + + /* Words in rom data are little endian (like in PCI configuration), + so they can be read / written with pci_get_word / pci_set_word. */ + + /* Only a valid rom will be patched. */ + rom_magic = pci_get_word(ptr); + if (rom_magic != 0xaa55) { + PCI_DPRINTF("Bad ROM magic %04x\n", rom_magic); + return; + } + pcir_offset = pci_get_word(ptr + 0x18); + if (pcir_offset + 8 >= size || memcmp(ptr + pcir_offset, "PCIR", 4)) { + PCI_DPRINTF("Bad PCIR offset 0x%x or signature\n", pcir_offset); + return; + } + + vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); + device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); + rom_vendor_id = pci_get_word(ptr + pcir_offset + 4); + rom_device_id = pci_get_word(ptr + pcir_offset + 6); + + PCI_DPRINTF("%s: ROM id %04x%04x / PCI id %04x%04x\n", pdev->romfile, + vendor_id, device_id, rom_vendor_id, rom_device_id); + + checksum = ptr[6]; + + if (vendor_id != rom_vendor_id) { + /* Patch vendor id and checksum (at offset 6 for etherboot roms). */ + checksum += (uint8_t)rom_vendor_id + (uint8_t)(rom_vendor_id >> 8); + checksum -= (uint8_t)vendor_id + (uint8_t)(vendor_id >> 8); + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); + ptr[6] = checksum; + pci_set_word(ptr + pcir_offset + 4, vendor_id); + } + + if (device_id != rom_device_id) { + /* Patch device id and checksum (at offset 6 for etherboot roms). */ + checksum += (uint8_t)rom_device_id + (uint8_t)(rom_device_id >> 8); + checksum -= (uint8_t)device_id + (uint8_t)(device_id >> 8); + PCI_DPRINTF("ROM checksum %02x / %02x\n", ptr[6], checksum); + ptr[6] = checksum; + pci_set_word(ptr + pcir_offset + 6, device_id); + } +} + /* Add an option rom for the device */ -static int pci_add_option_rom(PCIDevice *pdev) +static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) { int size; char *path; @@ -1753,6 +1813,11 @@ static int pci_add_option_rom(PCIDevice *pdev) load_image(path, ptr); qemu_free(path); + if (is_default_rom) { + /* Only the default rom images will be patched (if needed). */ + pci_patch_ids(pdev, ptr, size); + } + pci_register_bar(pdev, PCI_ROM_SLOT, size, 0, pci_map_option_rom); From 0389ced419d249d8742c69e177731b5d18ef3f2f Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 15 Oct 2010 22:51:07 +0200 Subject: [PATCH 18/30] eepro100: Use a single rom file for all i825xx devices Patching the rom data during load (in qemu) now also supports i82801 (which had no rom file). We only need a single rom file for the whole device family, so remove the second one which is no longer needed. Cc: Markus Armbruster Cc: Michael S. Tsirkin Signed-off-by: Stefan Weil Signed-off-by: Michael S. Tsirkin --- Makefile | 1 - hw/eepro100.c | 14 +++----------- pc-bios/README | 2 +- pc-bios/gpxe-eepro100-80861229.rom | Bin 56832 -> 0 bytes 4 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 pc-bios/gpxe-eepro100-80861229.rom diff --git a/Makefile b/Makefile index 02698e976c..2883d27f25 100644 --- a/Makefile +++ b/Makefile @@ -181,7 +181,6 @@ ifdef INSTALL_BLOBS BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ openbios-sparc32 openbios-sparc64 openbios-ppc \ gpxe-eepro100-80861209.rom \ -gpxe-eepro100-80861229.rom \ pxe-e1000.bin \ pxe-ne2k_pci.bin pxe-pcnet.bin \ pxe-rtl8139.bin pxe-virtio.bin \ diff --git a/hw/eepro100.c b/hw/eepro100.c index 41d792ad24..f8a700a2b8 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -2048,17 +2048,9 @@ static void eepro100_register_devices(void) size_t i; for (i = 0; i < ARRAY_SIZE(e100_devices); i++) { PCIDeviceInfo *pci_dev = &e100_devices[i].pci; - switch (e100_devices[i].device_id) { - case PCI_DEVICE_ID_INTEL_82551IT: - pci_dev->romfile = "gpxe-eepro100-80861209.rom"; - break; - case PCI_DEVICE_ID_INTEL_82557: - pci_dev->romfile = "gpxe-eepro100-80861229.rom"; - break; - case 0x2449: - pci_dev->romfile = "gpxe-eepro100-80862449.rom"; - break; - } + /* We use the same rom file for all device ids. + QEMU fixes the device id during rom load. */ + pci_dev->romfile = "gpxe-eepro100-80861209.rom"; pci_dev->init = e100_nic_init; pci_dev->exit = pci_nic_uninit; pci_dev->qdev.props = e100_properties; diff --git a/pc-bios/README b/pc-bios/README index 3172cf7896..4b019e08a1 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -16,7 +16,7 @@ - The PXE roms come from Rom-o-Matic gPXE 0.9.9 with BANNER_TIMEOUT=0 e1000 8086:100E - eepro100 8086:1209, 8086:1229 + eepro100 8086:1209 (also used for 8086:1229 and 8086:2449) ns8390 1050:0940 pcnet32 1022:2000 rtl8139 10ec:8139 diff --git a/pc-bios/gpxe-eepro100-80861229.rom b/pc-bios/gpxe-eepro100-80861229.rom deleted file mode 100644 index 9cf397e3de03c4b6441893cf07d9ea63a36a65c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56832 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 Date: Fri, 19 Nov 2010 18:55:58 +0900 Subject: [PATCH 19/30] qbus: add functions to walk both devices and busses There are some cases where you want to walk the busses, in particular, when searching for a bus either by name or DeviceInfo. Paolo suggested that we model the return values on how GCC's walkers work which allows an actor to skip child transversal, or terminate walking with a positive value that's returned as the qbus_walk_children's result. Signed-off-by: Isaku Yamahata Signed-off-by: Anthony Liguori Signed-off-by: Michael S. Tsirkin --- hw/qdev.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ hw/qdev.h | 11 +++++++++++ 2 files changed, 57 insertions(+) diff --git a/hw/qdev.c b/hw/qdev.c index 35858cb81b..11d845ac06 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -449,6 +449,52 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name) return NULL; } +int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, + qbus_walkerfn *busfn, void *opaque) +{ + DeviceState *dev; + int err; + + if (busfn) { + err = busfn(bus, opaque); + if (err) { + return err; + } + } + + QLIST_FOREACH(dev, &bus->children, sibling) { + err = qdev_walk_children(dev, devfn, busfn, opaque); + if (err < 0) { + return err; + } + } + + return 0; +} + +int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, + qbus_walkerfn *busfn, void *opaque) +{ + BusState *bus; + int err; + + if (devfn) { + err = devfn(dev, opaque); + if (err) { + return err; + } + } + + QLIST_FOREACH(bus, &dev->child_bus, sibling) { + err = qbus_walk_children(bus, devfn, busfn, opaque); + if (err < 0) { + return err; + } + } + + return 0; +} + static BusState *qbus_find_recursive(BusState *bus, const char *name, const BusInfo *info) { diff --git a/hw/qdev.h b/hw/qdev.h index 579328afc2..550fd9bbdc 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -173,9 +173,20 @@ BusState *qdev_get_parent_bus(DeviceState *dev); /*** BUS API. ***/ +/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */ +typedef int (qbus_walkerfn)(BusState *bus, void *opaque); +typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque); + void qbus_create_inplace(BusState *bus, BusInfo *info, DeviceState *parent, const char *name); BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name); +/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion, + * < 0 if either devfn or busfn terminate walk somewhere in cursion, + * 0 otherwise. */ +int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, + qbus_walkerfn *busfn, void *opaque); +int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, + qbus_walkerfn *busfn, void *opaque); void qbus_free(BusState *bus); #define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev) From ec990eb622ad46df5ddcb1e94c418c271894d416 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Fri, 19 Nov 2010 18:55:59 +0900 Subject: [PATCH 20/30] qdev: reset qdev along with qdev tree This patch changes the reset handling so that qdev has no knowledge of the global system reset. Instead, a new bus/device level function is introduced that allows all devices/buses on the bus/device to be reset using a depth first transversal. N.B. we have to expose the implicit system bus because we have various hacks that result in an implicit system bus existing. Instead, we ought to have an explicitly created system bus that we can trigger reset from. That's a topic for a future patch though. Signed-off-by: Anthony Liguori Signed-off-by: Isaku Yamahata Signed-off-by: Michael S. Tsirkin --- hw/qdev.c | 28 +++++++++++++++++++--------- hw/qdev.h | 4 ++++ vl.c | 1 + 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/hw/qdev.c b/hw/qdev.c index 11d845ac06..92ccc8d660 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -257,13 +257,6 @@ DeviceState *qdev_device_add(QemuOpts *opts) return qdev; } -static void qdev_reset(void *opaque) -{ - DeviceState *dev = opaque; - if (dev->info->reset) - dev->info->reset(dev); -} - /* Initialize a device. Device properties should be set before calling this function. IRQs and MMIO regions should be connected/mapped after calling this function. @@ -279,7 +272,6 @@ int qdev_init(DeviceState *dev) qdev_free(dev); return rc; } - qemu_register_reset(qdev_reset, dev); if (dev->info->vmsd) { vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev, dev->instance_id_alias, @@ -308,6 +300,25 @@ int qdev_unplug(DeviceState *dev) return dev->info->unplug(dev); } +static int qdev_reset_one(DeviceState *dev, void *opaque) +{ + if (dev->info->reset) { + dev->info->reset(dev); + } + + return 0; +} + +BusState *sysbus_get_default(void) +{ + return main_system_bus; +} + +void qbus_reset_all(BusState *bus) +{ + qbus_walk_children(bus, qdev_reset_one, NULL, NULL); +} + /* can be used as ->unplug() callback for the simple cases */ int qdev_simple_unplug_cb(DeviceState *dev) { @@ -351,7 +362,6 @@ void qdev_free(DeviceState *dev) if (dev->opts) qemu_opts_del(dev->opts); } - qemu_unregister_reset(qdev_reset, dev); QLIST_REMOVE(dev, sibling); for (prop = dev->info->props; prop && prop->name; prop++) { if (prop->info->free) { diff --git a/hw/qdev.h b/hw/qdev.h index 550fd9bbdc..e5ed3333a2 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -187,10 +187,14 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, qbus_walkerfn *busfn, void *opaque); int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, qbus_walkerfn *busfn, void *opaque); +void qbus_reset_all(BusState *bus); void qbus_free(BusState *bus); #define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev) +/* This should go away once we get rid of the NULL bus hack */ +BusState *sysbus_get_default(void); + /*** monitor commands ***/ void do_info_qtree(Monitor *mon); diff --git a/vl.c b/vl.c index c58583da48..135fdebe74 100644 --- a/vl.c +++ b/vl.c @@ -2976,6 +2976,7 @@ int main(int argc, char **argv, char **envp) exit(1); } + qemu_register_reset((void *)qbus_reset_all, sysbus_get_default()); qemu_system_reset(); if (loadvm) { if (load_vmstate(loadvm) < 0) { From b4694b7ce8bd87c4b9c6c14ad74075a31b15c784 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Fri, 19 Nov 2010 18:56:00 +0900 Subject: [PATCH 21/30] qdev: introduce reset call back for qbus level and make it called via qbus_reset_all(). The qbus reset callback will be used by pci bus reset. Signed-off-by: Isaku Yamahata Signed-off-by: Anthony Liguori Signed-off-by: Michael S. Tsirkin --- hw/qdev.c | 10 +++++++++- hw/qdev.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/qdev.c b/hw/qdev.c index 92ccc8d660..b76da07808 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -314,9 +314,17 @@ BusState *sysbus_get_default(void) return main_system_bus; } +static int qbus_reset_one(BusState *bus, void *opaque) +{ + if (bus->info->reset) { + return bus->info->reset(bus); + } + return 0; +} + void qbus_reset_all(BusState *bus) { - qbus_walk_children(bus, qdev_reset_one, NULL, NULL); + qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL); } /* can be used as ->unplug() callback for the simple cases */ diff --git a/hw/qdev.h b/hw/qdev.h index e5ed3333a2..5ac084f7de 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -49,12 +49,14 @@ struct DeviceState { typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent); typedef char *(*bus_get_dev_path)(DeviceState *dev); +typedef int (qbus_resetfn)(BusState *bus); struct BusInfo { const char *name; size_t size; bus_dev_printfn print_dev; bus_get_dev_path get_dev_path; + qbus_resetfn *reset; Property *props; }; From 5af0a04bea1f1704432b7c118c00a466e862bf00 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Fri, 19 Nov 2010 18:56:01 +0900 Subject: [PATCH 22/30] qdev: trigger reset from a given device Introduce a helper function which triggers reset from a given device. Will be used by pci bus emulation. Signed-off-by: Isaku Yamahata Signed-off-by: Anthony Liguori Signed-off-by: Michael S. Tsirkin --- hw/qdev.c | 5 +++++ hw/qdev.h | 1 + 2 files changed, 6 insertions(+) diff --git a/hw/qdev.c b/hw/qdev.c index b76da07808..b65b63e10e 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -322,6 +322,11 @@ static int qbus_reset_one(BusState *bus, void *opaque) return 0; } +void qdev_reset_all(DeviceState *dev) +{ + qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL); +} + void qbus_reset_all(BusState *bus) { qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL); diff --git a/hw/qdev.h b/hw/qdev.h index 5ac084f7de..3fac364c6b 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -189,6 +189,7 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn, qbus_walkerfn *busfn, void *opaque); int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, qbus_walkerfn *busfn, void *opaque); +void qdev_reset_all(DeviceState *dev); void qbus_reset_all(BusState *bus); void qbus_free(BusState *bus); From 9bb3358627d87d8de25fb41b7276575539d799a7 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Fri, 19 Nov 2010 18:56:02 +0900 Subject: [PATCH 23/30] pci: use qdev reset framework for pci bus reset Signed-off-by: Isaku Yamahata Signed-off-by: Anthony Liguori Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 24 +++++++++++++++++++++--- hw/pci.h | 1 + 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index c0a825876a..d02f980445 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -43,12 +43,14 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *pcibus_get_dev_path(DeviceState *dev); +static int pcibus_reset(BusState *qbus); struct BusInfo pci_bus_info = { .name = "PCI", .size = sizeof(PCIBus), .print_dev = pcibus_dev_print, .get_dev_path = pcibus_get_dev_path, + .reset = pcibus_reset, .props = (Property[]) { DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), DEFINE_PROP_STRING("romfile", PCIDevice, romfile), @@ -136,6 +138,11 @@ static void pci_update_irq_status(PCIDevice *dev) static void pci_device_reset(PCIDevice *dev) { int r; + /* TODO: call the below unconditionally once all pci devices + * are qdevified */ + if (dev->qdev.info) { + qdev_reset_all(&dev->qdev); + } dev->irq_state = 0; pci_update_irq_status(dev); @@ -164,9 +171,12 @@ static void pci_device_reset(PCIDevice *dev) pci_update_mappings(dev); } -static void pci_bus_reset(void *opaque) +/* + * Trigger pci bus reset under a given bus. + * To be called on RST# assert. + */ +void pci_bus_reset(PCIBus *bus) { - PCIBus *bus = opaque; int i; for (i = 0; i < bus->nirq; i++) { @@ -179,6 +189,15 @@ static void pci_bus_reset(void *opaque) } } +static int pcibus_reset(BusState *qbus) +{ + pci_bus_reset(DO_UPCAST(PCIBus, qbus, qbus)); + + /* topology traverse is done by pci_bus_reset(). + Tell qbus/qdev walker not to traverse the tree */ + return 1; +} + static void pci_host_bus_register(int domain, PCIBus *bus) { struct PCIHostBus *host; @@ -233,7 +252,6 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */ vmstate_register(NULL, -1, &vmstate_pcibus, bus); - qemu_register_reset(pci_bus_reset, bus); } PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min) diff --git a/hw/pci.h b/hw/pci.h index 09b3e4c033..89f7b761e7 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -232,6 +232,7 @@ void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev); PCIBus *pci_register_bus(DeviceState *parent, const char *name, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *irq_opaque, int devfn_min, int nirq); +void pci_bus_reset(PCIBus *bus); void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base); From a5fce077b134a486794b77b49f4eae1d3c9b960c Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Fri, 19 Nov 2010 18:56:03 +0900 Subject: [PATCH 24/30] pci bridge: implement secondary bus reset Trigger secondary bus reset when secondary bus reset bit value changes from 0 to 1. Signed-off-by: Isaku Yamahata Signed-off-by: Anthony Liguori Signed-off-by: Michael S. Tsirkin --- hw/pci_bridge.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c index 58cc2e4cee..464d89708f 100644 --- a/hw/pci_bridge.c +++ b/hw/pci_bridge.c @@ -139,6 +139,10 @@ pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type) void pci_bridge_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { + PCIBridge *s = container_of(d, PCIBridge, dev); + uint16_t oldctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); + uint16_t newctl; + pci_default_write_config(d, address, val, len); if (/* io base/limit */ @@ -147,9 +151,14 @@ void pci_bridge_write_config(PCIDevice *d, /* memory base/limit, prefetchable base/limit and io base/limit upper 16 */ ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) { - PCIBridge *s = container_of(d, PCIBridge, dev); pci_bridge_update_mappings(&s->sec_bus); } + + newctl = pci_get_word(d->config + PCI_BRIDGE_CONTROL); + if (~oldctl & newctl & PCI_BRIDGE_CTL_BUS_RESET) { + /* Trigger hot reset on 0->1 transition. */ + pci_bus_reset(&s->sec_bus); + } } void pci_bridge_disable_base_limit(PCIDevice *dev) From 929176c3b9f8d5feec9395401f889a3bfb95e816 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 24 Nov 2010 07:23:25 +0200 Subject: [PATCH 25/30] pci: fix bus walk under secondary bus reset Take into account secondary bus reset bit for bus walk: devices behind a reset bus should not respond to configuration cycles. Signed-off-by: Michael S. Tsirkin --- hw/pci.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/hw/pci.c b/hw/pci.c index d02f980445..0c15b13037 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1540,6 +1540,16 @@ void pci_bridge_update_mappings(PCIBus *b) } } +/* Whether a given bus number is in range of the secondary + * bus of the given bridge device. */ +static bool pci_secondary_bus_in_range(PCIDevice *dev, int bus_num) +{ + return !(pci_get_word(dev->config + PCI_BRIDGE_CONTROL) & + PCI_BRIDGE_CTL_BUS_RESET) /* Don't walk the bus if it's reset. */ && + dev->config[PCI_SECONDARY_BUS] < bus_num && + bus_num <= dev->config[PCI_SUBORDINATE_BUS]; +} + PCIBus *pci_find_bus(PCIBus *bus, int bus_num) { PCIBus *sec; @@ -1552,20 +1562,21 @@ PCIBus *pci_find_bus(PCIBus *bus, int bus_num) return bus; } + /* Consider all bus numbers in range for the host pci bridge. */ + if (bus->parent_dev && + !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) { + return NULL; + } + /* try child bus */ - if (!bus->parent_dev /* host pci bridge */ || - (bus->parent_dev->config[PCI_SECONDARY_BUS] < bus_num && - bus_num <= bus->parent_dev->config[PCI_SUBORDINATE_BUS])) { - for (; bus; bus = sec) { - QLIST_FOREACH(sec, &bus->child, sibling) { - assert(sec->parent_dev); - if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) { - return sec; - } - if (sec->parent_dev->config[PCI_SECONDARY_BUS] < bus_num && - bus_num <= sec->parent_dev->config[PCI_SUBORDINATE_BUS]) { - break; - } + for (; bus; bus = sec) { + QLIST_FOREACH(sec, &bus->child, sibling) { + assert(sec->parent_dev); + if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) { + return sec; + } + if (pci_secondary_bus_in_range(sec->parent_dev, bus_num)) { + break; } } } From ce67ed65000b8f56c6e0576a1a9d3c4b0f596f5c Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 15 Nov 2010 20:44:36 +0000 Subject: [PATCH 26/30] virtio: Convert fprintf() to error_report() Signed-off-by: Stefan Hajnoczi Signed-off-by: Anthony Liguori (cherry picked from commit cd92f4cc22fbe12a7bf60c9430731f768dc1537c) --- hw/virtio.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/hw/virtio.c b/hw/virtio.c index a2a657e132..849a60faaa 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -14,6 +14,7 @@ #include #include "trace.h" +#include "qemu-error.h" #include "virtio.h" #include "sysemu.h" @@ -253,8 +254,8 @@ static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx) /* Check it isn't doing very strange things with descriptor numbers. */ if (num_heads > vq->vring.num) { - fprintf(stderr, "Guest moved used index from %u to %u", - idx, vring_avail_idx(vq)); + error_report("Guest moved used index from %u to %u", + idx, vring_avail_idx(vq)); exit(1); } @@ -271,7 +272,7 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx) /* If their number is silly, that's a fatal mistake. */ if (head >= vq->vring.num) { - fprintf(stderr, "Guest says index %u is available", head); + error_report("Guest says index %u is available", head); exit(1); } @@ -293,7 +294,7 @@ static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa, wmb(); if (next >= max) { - fprintf(stderr, "Desc next is %u", next); + error_report("Desc next is %u", next); exit(1); } @@ -320,13 +321,13 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) { if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) { - fprintf(stderr, "Invalid size for indirect buffer table\n"); + error_report("Invalid size for indirect buffer table"); exit(1); } /* If we've got too many, that implies a descriptor loop. */ if (num_bufs >= max) { - fprintf(stderr, "Looped descriptor"); + error_report("Looped descriptor"); exit(1); } @@ -340,7 +341,7 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) do { /* If we've got too many, that implies a descriptor loop. */ if (++num_bufs > max) { - fprintf(stderr, "Looped descriptor"); + error_report("Looped descriptor"); exit(1); } @@ -374,7 +375,7 @@ void virtqueue_map_sg(struct iovec *sg, target_phys_addr_t *addr, len = sg[i].iov_len; sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write); if (sg[i].iov_base == NULL || len != sg[i].iov_len) { - fprintf(stderr, "virtio: trying to map MMIO memory\n"); + error_report("virtio: trying to map MMIO memory"); exit(1); } } @@ -397,7 +398,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) { if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) { - fprintf(stderr, "Invalid size for indirect buffer table\n"); + error_report("Invalid size for indirect buffer table"); exit(1); } @@ -423,7 +424,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) /* If we've got too many, that implies a descriptor loop. */ if ((elem->in_num + elem->out_num) > max) { - fprintf(stderr, "Looped descriptor"); + error_report("Looped descriptor"); exit(1); } } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max); @@ -694,8 +695,8 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) qemu_get_be16s(f, &vdev->queue_sel); qemu_get_be32s(f, &features); if (features & ~supported_features) { - fprintf(stderr, "Features 0x%x unsupported. Allowed features: 0x%x\n", - features, supported_features); + error_report("Features 0x%x unsupported. Allowed features: 0x%x", + features, supported_features); return -1; } if (vdev->set_features) @@ -717,11 +718,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) num_heads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx; /* Check it isn't doing very strange things with descriptor numbers. */ if (num_heads > vdev->vq[i].vring.num) { - fprintf(stderr, "VQ %d size 0x%x Guest index 0x%x " - "inconsistent with Host index 0x%x: delta 0x%x\n", - i, vdev->vq[i].vring.num, - vring_avail_idx(&vdev->vq[i]), - vdev->vq[i].last_avail_idx, num_heads); + error_report("VQ %d size 0x%x Guest index 0x%x " + "inconsistent with Host index 0x%x: delta 0x%x", + i, vdev->vq[i].vring.num, + vring_avail_idx(&vdev->vq[i]), + vdev->vq[i].last_avail_idx, num_heads); return -1; } if (vdev->binding->load_queue) { From 1abeb5a65d515f8a8a9cfc4a82342f731bd9321f Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 23 Nov 2010 21:55:39 +0200 Subject: [PATCH 27/30] virtio: fix up VQ checks When migration triggers before a VQ is initialized, base pa is 0 and last_used_index must be 0 too: we don't have a ring to compare to. Reported-by: Juan Quintela Tested-by: Juan Quintela Signed-off-by: Michael S. Tsirkin --- hw/virtio.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/hw/virtio.c b/hw/virtio.c index 849a60faaa..07dbf868fd 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -682,7 +682,6 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) uint32_t features; uint32_t supported_features = vdev->binding->get_features(vdev->binding_opaque); - uint16_t num_heads; if (vdev->binding->load_config) { ret = vdev->binding->load_config(vdev->binding_opaque, f); @@ -713,17 +712,23 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) qemu_get_be16s(f, &vdev->vq[i].last_avail_idx); if (vdev->vq[i].pa) { + uint16_t nheads; virtqueue_init(&vdev->vq[i]); - } - num_heads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx; - /* Check it isn't doing very strange things with descriptor numbers. */ - if (num_heads > vdev->vq[i].vring.num) { - error_report("VQ %d size 0x%x Guest index 0x%x " - "inconsistent with Host index 0x%x: delta 0x%x", - i, vdev->vq[i].vring.num, - vring_avail_idx(&vdev->vq[i]), - vdev->vq[i].last_avail_idx, num_heads); - return -1; + nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx; + /* Check it isn't doing very strange things with descriptor numbers. */ + if (nheads > vdev->vq[i].vring.num) { + error_report("VQ %d size 0x%x Guest index 0x%x " + "inconsistent with Host index 0x%x: delta 0x%x\n", + i, vdev->vq[i].vring.num, + vring_avail_idx(&vdev->vq[i]), + vdev->vq[i].last_avail_idx, nheads); + return -1; + } + } else if (vdev->vq[i].last_avail_idx) { + error_report("VQ %d address 0x0 " + "inconsistent with Host index 0x%x\n", + i, vdev->vq[i].last_avail_idx); + return -1; } if (vdev->binding->load_queue) { ret = vdev->binding->load_queue(vdev->binding_opaque, i, f); From b2e0a138e77245290428a7d599a929e2e1bfe510 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 22 Nov 2010 19:52:34 +0200 Subject: [PATCH 28/30] migration: stable ram block ordering This makes ram block ordering under migration stable, ordered by offset. This is especially useful for migration to exec, for debugging. Signed-off-by: Michael S. Tsirkin Tested-by: Jason Wang --- arch_init.c | 35 +++++++++++++++++++++++++++++++++++ cpu-common.h | 3 +++ exec.c | 24 ++++++++++++++++++++++-- kvm-all.c | 2 +- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/arch_init.c b/arch_init.c index 44869255ef..e32e289c8f 100644 --- a/arch_init.c +++ b/arch_init.c @@ -23,6 +23,7 @@ */ #include #include +#include #ifndef _WIN32 #include #include @@ -212,6 +213,39 @@ uint64_t ram_bytes_total(void) return total; } +static int block_compar(const void *a, const void *b) +{ + RAMBlock * const *ablock = a; + RAMBlock * const *bblock = b; + if ((*ablock)->offset < (*bblock)->offset) { + return -1; + } else if ((*ablock)->offset > (*bblock)->offset) { + return 1; + } + return 0; +} + +static void sort_ram_list(void) +{ + RAMBlock *block, *nblock, **blocks; + int n; + n = 0; + QLIST_FOREACH(block, &ram_list.blocks, next) { + ++n; + } + blocks = qemu_malloc(n * sizeof *blocks); + n = 0; + QLIST_FOREACH_SAFE(block, &ram_list.blocks, next, nblock) { + blocks[n++] = block; + QLIST_REMOVE(block, next); + } + qsort(blocks, n, sizeof *blocks, block_compar); + while (--n >= 0) { + QLIST_INSERT_HEAD(&ram_list.blocks, blocks[n], next); + } + qemu_free(blocks); +} + int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) { ram_addr_t addr; @@ -234,6 +268,7 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque) bytes_transferred = 0; last_block = NULL; last_offset = 0; + sort_ram_list(); /* Make sure all dirty bits are set */ QLIST_FOREACH(block, &ram_list.blocks, next) { diff --git a/cpu-common.h b/cpu-common.h index a543b5d7cf..bb6b137e16 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -46,6 +46,9 @@ ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size); void qemu_ram_free(ram_addr_t addr); /* This should only be used for ram local to a device. */ void *qemu_get_ram_ptr(ram_addr_t addr); +/* Same but slower, to use for migration, where the order of + * RAMBlocks must not change. */ +void *qemu_safe_ram_ptr(ram_addr_t addr); /* This should not be used by devices. */ int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr); ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr); diff --git a/exec.c b/exec.c index db9ff5515a..6c8f635ad4 100644 --- a/exec.c +++ b/exec.c @@ -2030,10 +2030,10 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, /* we modify the TLB cache so that the dirty bit will be set again when accessing the range */ - start1 = (unsigned long)qemu_get_ram_ptr(start); + start1 = (unsigned long)qemu_safe_ram_ptr(start); /* Chek that we don't span multiple blocks - this breaks the address comparisons below. */ - if ((unsigned long)qemu_get_ram_ptr(end - 1) - start1 + if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1 != (end - 1) - start) { abort(); } @@ -2858,6 +2858,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name, new_block->length = size; QLIST_INSERT_HEAD(&ram_list.blocks, new_block, next); + fprintf(stderr, "alloc ram %s len 0x%x\n", new_block->idstr, (int)new_block->length); ram_list.phys_dirty = qemu_realloc(ram_list.phys_dirty, last_ram_offset() >> TARGET_PAGE_BITS); @@ -2931,6 +2932,25 @@ void *qemu_get_ram_ptr(ram_addr_t addr) return NULL; } +/* Return a host pointer to ram allocated with qemu_ram_alloc. + * Same as qemu_get_ram_ptr but avoid reordering ramblocks. + */ +void *qemu_safe_ram_ptr(ram_addr_t addr) +{ + RAMBlock *block; + + QLIST_FOREACH(block, &ram_list.blocks, next) { + if (addr - block->offset < block->length) { + return block->host + (addr - block->offset); + } + } + + fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr); + abort(); + + return NULL; +} + int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr) { RAMBlock *block; diff --git a/kvm-all.c b/kvm-all.c index 37b99c7510..cae24bb87c 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -162,7 +162,7 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot) mem.slot = slot->slot; mem.guest_phys_addr = slot->start_addr; mem.memory_size = slot->memory_size; - mem.userspace_addr = (unsigned long)qemu_get_ram_ptr(slot->phys_offset); + mem.userspace_addr = (unsigned long)qemu_safe_ram_ptr(slot->phys_offset); mem.flags = slot->flags; if (s->migration_log) { mem.flags |= KVM_MEM_LOG_DIRTY_PAGES; From 3d002df33eb034757d98e1ae529318f57df78f91 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 23 Nov 2010 19:05:54 +0200 Subject: [PATCH 29/30] migration: allow rate > 4g I'd like to disable bandwidth limit or make it very high, Use int64_t all over to make values >= 4g work. Signed-off-by: Michael S. Tsirkin Tested-by: Jason Wang --- buffered_file.c | 9 ++++++--- hw/hw.h | 8 ++++---- migration.c | 6 ++++-- savevm.c | 4 ++-- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/buffered_file.c b/buffered_file.c index 1836e7e242..8435a31946 100644 --- a/buffered_file.c +++ b/buffered_file.c @@ -206,20 +206,23 @@ static int buffered_rate_limit(void *opaque) return 0; } -static size_t buffered_set_rate_limit(void *opaque, size_t new_rate) +static int64_t buffered_set_rate_limit(void *opaque, int64_t new_rate) { QEMUFileBuffered *s = opaque; - if (s->has_error) goto out; + if (new_rate > SIZE_MAX) { + new_rate = SIZE_MAX; + } + s->xfer_limit = new_rate / 10; out: return s->xfer_limit; } -static size_t buffered_get_rate_limit(void *opaque) +static int64_t buffered_get_rate_limit(void *opaque) { QEMUFileBuffered *s = opaque; diff --git a/hw/hw.h b/hw/hw.h index 9d2cfc219c..77bfb58b89 100644 --- a/hw/hw.h +++ b/hw/hw.h @@ -39,8 +39,8 @@ typedef int (QEMUFileRateLimit)(void *opaque); * the new actual bandwidth. It should be new_rate if everything goes ok, and * the old rate otherwise */ -typedef size_t (QEMUFileSetRateLimit)(void *opaque, size_t new_rate); -typedef size_t (QEMUFileGetRateLimit)(void *opaque); +typedef int64_t (QEMUFileSetRateLimit)(void *opaque, int64_t new_rate); +typedef int64_t (QEMUFileGetRateLimit)(void *opaque); QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, QEMUFileGetBufferFunc *get_buffer, @@ -83,8 +83,8 @@ unsigned int qemu_get_be16(QEMUFile *f); unsigned int qemu_get_be32(QEMUFile *f); uint64_t qemu_get_be64(QEMUFile *f); int qemu_file_rate_limit(QEMUFile *f); -size_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate); -size_t qemu_file_get_rate_limit(QEMUFile *f); +int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); +int64_t qemu_file_get_rate_limit(QEMUFile *f); int qemu_file_has_error(QEMUFile *f); void qemu_file_set_error(QEMUFile *f); diff --git a/migration.c b/migration.c index 9ee8b179c0..622a9d2d95 100644 --- a/migration.c +++ b/migration.c @@ -32,7 +32,7 @@ #endif /* Migration speed throttling */ -static uint32_t max_throttle = (32 << 20); +static int64_t max_throttle = (32 << 20); static MigrationState *current_migration; @@ -136,7 +136,9 @@ int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data) FdMigrationState *s; d = qdict_get_int(qdict, "value"); - d = MAX(0, MIN(UINT32_MAX, d)); + if (d < 0) { + d = 0; + } max_throttle = d; s = migrate_to_fms(current_migration); diff --git a/savevm.c b/savevm.c index 4e49765816..d38f79e6bd 100644 --- a/savevm.c +++ b/savevm.c @@ -611,7 +611,7 @@ int qemu_file_rate_limit(QEMUFile *f) return 0; } -size_t qemu_file_get_rate_limit(QEMUFile *f) +int64_t qemu_file_get_rate_limit(QEMUFile *f) { if (f->get_rate_limit) return f->get_rate_limit(f->opaque); @@ -619,7 +619,7 @@ size_t qemu_file_get_rate_limit(QEMUFile *f) return 0; } -size_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate) +int64_t qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate) { /* any failed or completed migration keeps its state to allow probing of * migration data, but has no associated file anymore */ From 0c600ce2a7a419c7247b2ac63327dea5daa3d5a2 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 27 Nov 2010 22:05:07 +0800 Subject: [PATCH 30/30] vhost: Fix address calculation in vhost_dev_sync_region() We still need advance address even we find there's no dirty pages in current chunk. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin --- hw/vhost.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/vhost.c b/hw/vhost.c index 8586f66bac..6082da287e 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -37,6 +37,7 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, /* We first check with non-atomic: much cheaper, * and we expect non-dirty to be the common case. */ if (!*from) { + addr += VHOST_LOG_CHUNK; continue; } /* Data must be read atomically. We don't really