summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi_piix4.c37
-rw-r--r--hw/msi.c5
-rw-r--r--hw/msix.c5
-rw-r--r--hw/pci.c27
-rw-r--r--hw/pci.h2
-rw-r--r--hw/virtio-serial-bus.c10
6 files changed, 71 insertions, 15 deletions
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 273097d480..5bbc2b5a26 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -37,6 +37,7 @@
 #define GPE_BASE 0xafe0
 #define PCI_BASE 0xae00
 #define PCI_EJ_BASE 0xae08
+#define PCI_RMV_BASE 0xae0c
 
 #define PIIX4_PCI_HOTPLUG_STATUS 2
 
@@ -73,6 +74,7 @@ typedef struct PIIX4PMState {
     /* for pci hotplug */
     struct gpe_regs gpe;
     struct pci_status pci0_status;
+    uint32_t pci0_hotplug_enable;
 } PIIX4PMState;
 
 static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
@@ -322,6 +324,25 @@ static const VMStateDescription vmstate_acpi = {
     }
 };
 
+static void piix4_update_hotplug(PIIX4PMState *s)
+{
+    PCIDevice *dev = &s->dev;
+    BusState *bus = qdev_get_parent_bus(&dev->qdev);
+    DeviceState *qdev, *next;
+
+    s->pci0_hotplug_enable = ~0;
+
+    QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+        PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
+        PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+        int slot = PCI_SLOT(pdev->devfn);
+
+        if (info->no_hotplug) {
+            s->pci0_hotplug_enable &= ~(1 << slot);
+        }
+    }
+}
+
 static void piix4_reset(void *opaque)
 {
     PIIX4PMState *s = opaque;
@@ -336,6 +357,7 @@ static void piix4_reset(void *opaque)
         /* Mark SMM as already inited (until KVM supports SMM). */
         pci_conf[0x5B] = 0x02;
     }
+    piix4_update_hotplug(s);
 }
 
 static void piix4_powerdown(void *opaque, int irq, int power_failing)
@@ -576,6 +598,18 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
     PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val);
 }
 
+static uint32_t pcirmv_read(void *opaque, uint32_t addr)
+{
+    PIIX4PMState *s = opaque;
+
+    return s->pci0_hotplug_enable;
+}
+
+static void pcirmv_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    return;
+}
+
 static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
                                 PCIHotplugState state);
 
@@ -592,6 +626,9 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
     register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
     register_ioport_read(PCI_EJ_BASE, 4, 4,  pciej_read, bus);
 
+    register_ioport_write(PCI_RMV_BASE, 4, 4, pcirmv_write, s);
+    register_ioport_read(PCI_RMV_BASE, 4, 4,  pcirmv_read, s);
+
     pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
 }
 
diff --git a/hw/msi.c b/hw/msi.c
index f03f519a2e..3dc3a24b77 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -255,7 +255,6 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
     uint8_t log_max_vecs;
     unsigned int vector;
     uint32_t pending;
-    int i;
 
     if (!ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
         return;
@@ -296,9 +295,7 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
      *   from using its INTx# pin (if implemented) to request
      *   service (MSI, MSI-X, and INTx# are mutually exclusive).
      */
-    for (i = 0; i < PCI_NUM_PINS; ++i) {
-        qemu_set_irq(dev->irq[i], 0);
-    }
+    pci_device_deassert_intx(dev);
 
     /*
      * nr_vectors might be set bigger than capable. So clamp it.
diff --git a/hw/msix.c b/hw/msix.c
index e1230824b2..daaf9b7878 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -159,7 +159,6 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
 {
     unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
     int vector;
-    int i;
 
     if (!range_covers_byte(addr, len, enable_pos)) {
         return;
@@ -169,9 +168,7 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
         return;
     }
 
-    for (i = 0; i < PCI_NUM_PINS; ++i) {
-        qemu_set_irq(dev->irq[i], 0);
-    }
+    pci_device_deassert_intx(dev);
 
     if (msix_function_masked(dev)) {
         return;
diff --git a/hw/pci.c b/hw/pci.c
index 8d0e3df2e5..b8f5385170 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -137,6 +137,14 @@ static void pci_update_irq_status(PCIDevice *dev)
     }
 }
 
+void pci_device_deassert_intx(PCIDevice *dev)
+{
+    int i;
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        qemu_set_irq(dev->irq[i], 0);
+    }
+}
+
 /*
  * This function is called on #RST and FLR.
  * FLR if PCI_EXP_DEVCTL_BCR_FLR is set
@@ -152,6 +160,7 @@ void pci_device_reset(PCIDevice *dev)
 
     dev->irq_state = 0;
     pci_update_irq_status(dev);
+    pci_device_deassert_intx(dev);
     /* Clear all writeable bits */
     pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
                                  pci_get_word(dev->wmask + PCI_COMMAND) |
@@ -2032,10 +2041,13 @@ static char *pcibus_get_dev_path(DeviceState *dev)
      * domain:Bus:Slot.Func for systems without nested PCI bridges.
      * Slot.Function list specifies the slot and function numbers for all
      * devices on the path from root to the specific device. */
-    int domain_len = strlen("DDDD:00");
-    int slot_len = strlen(":SS.F");
+    char domain[] = "DDDD:00";
+    char slot[] = ":SS.F";
+    int domain_len = sizeof domain - 1 /* For '\0' */;
+    int slot_len = sizeof slot - 1 /* For '\0' */;
     int path_len;
     char *path, *p;
+    int s;
 
     /* Calculate # of slots on path between device and root. */;
     slot_depth = 0;
@@ -2046,18 +2058,23 @@ static char *pcibus_get_dev_path(DeviceState *dev)
     path_len = domain_len + slot_len * slot_depth;
 
     /* Allocate memory, fill in the terminating null byte. */
-    path = malloc(path_len + 1 /* For '\0' */);
+    path = qemu_malloc(path_len + 1 /* For '\0' */);
     path[path_len] = '\0';
 
     /* First field is the domain. */
-    snprintf(path, domain_len, "%04x:00", pci_find_domain(d->bus));
+    s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus));
+    assert(s == domain_len);
+    memcpy(path, domain, domain_len);
 
     /* Fill in slot numbers. We walk up from device to root, so need to print
      * them in the reverse order, last to first. */
     p = path + path_len;
     for (t = d; t; t = t->bus->parent_dev) {
         p -= slot_len;
-        snprintf(p, slot_len, ":%02x.%x", PCI_SLOT(t->devfn), PCI_FUNC(d->devfn));
+        s = snprintf(slot, sizeof slot, ":%02x.%x",
+                     PCI_SLOT(t->devfn), PCI_FUNC(d->devfn));
+        assert(s == slot_len);
+        memcpy(p, slot, slot_len);
     }
 
     return path;
diff --git a/hw/pci.h b/hw/pci.h
index bc8d5bb3c7..0d2753f27e 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -264,6 +264,8 @@ void do_pci_info_print(Monitor *mon, const QObject *data);
 void do_pci_info(Monitor *mon, QObject **ret_data);
 void pci_bridge_update_mappings(PCIBus *b);
 
+void pci_device_deassert_intx(PCIDevice *dev);
+
 static inline void
 pci_set_byte(uint8_t *config, uint8_t val)
 {
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 74ba5ec3d3..b728040f3a 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -769,10 +769,16 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
     /* Add a queue for guest to host transfers for port 0 (backward compat) */
     vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
 
+    /* TODO: host to guest notifications can get dropped
+     * if the queue fills up. Implement queueing in host,
+     * this might also make it possible to reduce the control
+     * queue size: as guest preposts buffers there,
+     * this will save 4Kbyte of guest memory per entry. */
+
     /* control queue: host to guest */
-    vser->c_ivq = virtio_add_queue(vdev, 16, control_in);
+    vser->c_ivq = virtio_add_queue(vdev, 32, control_in);
     /* control queue: guest to host */
-    vser->c_ovq = virtio_add_queue(vdev, 16, control_out);
+    vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
 
     for (i = 1; i < vser->bus->max_nr_ports; i++) {
         /* Add a per-port queue for host to guest transfers */