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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� 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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