aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-01-20 09:05:37 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2011-01-20 09:05:37 -0600
commit5dbbda340533cd7d217dcf3ab904fb353598cbde (patch)
tree1e0bc27430f12e9f27bdd466a21072802f7cbbb5 /hw
parentd788b57051ee91aa39de67cff8d8e15953bc100c (diff)
parente10990c3f0c39e92ab5f74004b89a24fcc36fa14 (diff)
Merge remote branch 'mst/for_anthony' into staging
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 */