aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-05-27 10:11:11 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-05-27 10:11:11 +0100
commit34c99d7b93c9181aa8c426300beca130b2b19e39 (patch)
treed7792ce9c3f0acd47c7dc23313010047d13cc9a9 /hw
parent84cfc756d158a061bd462473d42b0a9f072218de (diff)
parentb4daafbd13826dfa9d2596fb0f31f1453611189f (diff)
downloadqemu-34c99d7b93c9181aa8c426300beca130b2b19e39.zip
qemu-34c99d7b93c9181aa8c426300beca130b2b19e39.tar.gz
qemu-34c99d7b93c9181aa8c426300beca130b2b19e39.tar.bz2
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.7-20160527' into staging
ppc patch queue for 2016-05-27 (first pull for qemu-2.7) I'm back from holidays now, and have re-collated the ppc patch queue. This is a first pull request against the qemu-2.7 branch, mostly consisting of patches which were posted before the 2.6 freeze, but weren't suitable for late inclusion in the 2.6 branch. * Assorted bugfixes and cleanups * Some preliminary patches towards dynamic DMA windows and CPU hotplug * Significant performance impovement for the spapr-llan device * Added myself to MAINTAINERS for ppc (overdue) # gpg: Signature made Fri 27 May 2016 04:04:15 BST using RSA key ID 20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * remotes/dgibson/tags/ppc-for-2.7-20160527: MAINTAINERS: Add David Gibson as ppc maintainer spapr_iommu: Move table allocation to helpers spapr_iommu: Finish renaming vfio_accel to need_vfio spapr_pci: Use correct DMA LIOBN when composing the device tree spapr: ensure device trees are always associated with DRC PPC/KVM: early validation of vcpu id Added negative check for get_image_size() hw/net/spapr_llan: Provide counter with dropped rx frames to the guest hw/net/spapr_llan: Delay flushing of the RX queue while adding new RX buffers target-ppc: Cleanups to rldinm, rldnm, rldimi target-ppc: Use 32-bit rotate instead of deposit + 64-bit rotate target-ppc: Use movcond in isel target-ppc: Correct KVM synchronization for ppc_hash64_set_external_hpt() Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/net/spapr_llan.c45
-rw-r--r--hw/ppc/spapr.c20
-rw-r--r--hw/ppc/spapr_iommu.c58
-rw-r--r--hw/ppc/spapr_pci.c14
4 files changed, 97 insertions, 40 deletions
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index a8266f8..8b2eebd 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -110,6 +110,7 @@ typedef struct VIOsPAPRVLANDevice {
hwaddr buf_list;
uint32_t add_buf_ptr, use_buf_ptr, rx_bufs;
hwaddr rxq_ptr;
+ QEMUTimer *rxp_timer;
uint32_t compat_flags; /* Compatability flags for migration */
RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */
} VIOsPAPRVLANDevice;
@@ -122,6 +123,21 @@ static int spapr_vlan_can_receive(NetClientState *nc)
}
/**
+ * The last 8 bytes of the receive buffer list page (that has been
+ * supplied by the guest with the H_REGISTER_LOGICAL_LAN call) contain
+ * a counter for frames that have been dropped because there was no
+ * suitable receive buffer available. This function is used to increase
+ * this counter by one.
+ */
+static void spapr_vlan_record_dropped_rx_frame(VIOsPAPRVLANDevice *dev)
+{
+ uint64_t cnt;
+
+ cnt = vio_ldq(&dev->sdev, dev->buf_list + 4096 - 8);
+ vio_stq(&dev->sdev, dev->buf_list + 4096 - 8, cnt + 1);
+}
+
+/**
* Get buffer descriptor from one of our receive buffer pools
*/
static vlan_bd_t spapr_vlan_get_rx_bd_from_pool(VIOsPAPRVLANDevice *dev,
@@ -206,7 +222,8 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
}
if (!dev->rx_bufs) {
- return -1;
+ spapr_vlan_record_dropped_rx_frame(dev);
+ return 0;
}
if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) {
@@ -215,7 +232,8 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
bd = spapr_vlan_get_rx_bd_from_page(dev, size);
}
if (!bd) {
- return -1;
+ spapr_vlan_record_dropped_rx_frame(dev);
+ return 0;
}
dev->rx_bufs--;
@@ -266,6 +284,13 @@ static NetClientInfo net_spapr_vlan_info = {
.receive = spapr_vlan_receive,
};
+static void spapr_vlan_flush_rx_queue(void *opaque)
+{
+ VIOsPAPRVLANDevice *dev = opaque;
+
+ qemu_flush_queued_packets(qemu_get_queue(dev->nic));
+}
+
static void spapr_vlan_reset_rx_pool(RxBufPool *rxp)
{
/*
@@ -302,6 +327,9 @@ static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
+
+ dev->rxp_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, spapr_vlan_flush_rx_queue,
+ dev);
}
static void spapr_vlan_instance_init(Object *obj)
@@ -332,6 +360,11 @@ static void spapr_vlan_instance_finalize(Object *obj)
dev->rx_pool[i] = NULL;
}
}
+
+ if (dev->rxp_timer) {
+ timer_del(dev->rxp_timer);
+ timer_free(dev->rxp_timer);
+ }
}
void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
@@ -629,7 +662,13 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
dev->rx_bufs++;
- qemu_flush_queued_packets(qemu_get_queue(dev->nic));
+ /*
+ * Give guest some more time to add additional RX buffers before we
+ * flush the receive queue, so that e.g. fragmented IP packets can
+ * be passed to the guest in one go later (instead of passing single
+ * fragments if there is only one receive buffer available).
+ */
+ timer_mod(dev->rxp_timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 500);
return H_SUCCESS;
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index add68ac..44e401a 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1842,6 +1842,10 @@ static void ppc_spapr_init(MachineState *machine)
exit(1);
}
spapr->rtas_size = get_image_size(filename);
+ if (spapr->rtas_size < 0) {
+ error_report("Could not get size of LPAR rtas '%s'", filename);
+ exit(1);
+ }
spapr->rtas_blob = g_malloc(spapr->rtas_size);
if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) {
error_report("Could not load LPAR rtas '%s'", filename);
@@ -2132,15 +2136,6 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr, uint64_t size,
int i, fdt_offset, fdt_size;
void *fdt;
- /*
- * Check for DRC connectors and send hotplug notification to the
- * guest only in case of hotplugged memory. This allows cold plugged
- * memory to be specified at boot time.
- */
- if (!dev->hotplugged) {
- return;
- }
-
for (i = 0; i < nr_lmbs; i++) {
drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
addr/SPAPR_MEMORY_BLOCK_SIZE);
@@ -2154,7 +2149,12 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr, uint64_t size,
drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp);
addr += SPAPR_MEMORY_BLOCK_SIZE;
}
- spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs);
+ /* send hotplug notification to the
+ * guest only in case of hotplugged memory
+ */
+ if (dev->hotplugged) {
+ spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs);
+ }
}
static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index b6fe1dd..96bb018 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -76,6 +76,37 @@ static IOMMUAccessFlags spapr_tce_iommu_access_flags(uint64_t tce)
}
}
+static uint64_t *spapr_tce_alloc_table(uint32_t liobn,
+ uint32_t page_shift,
+ uint32_t nb_table,
+ int *fd,
+ bool need_vfio)
+{
+ uint64_t *table = NULL;
+ uint64_t window_size = (uint64_t)nb_table << page_shift;
+
+ if (kvm_enabled() && !(window_size >> 32)) {
+ table = kvmppc_create_spapr_tce(liobn, window_size, fd, need_vfio);
+ }
+
+ if (!table) {
+ *fd = -1;
+ table = g_malloc0(nb_table * sizeof(uint64_t));
+ }
+
+ trace_spapr_iommu_new_table(liobn, table, *fd);
+
+ return table;
+}
+
+static void spapr_tce_free_table(uint64_t *table, int fd, uint32_t nb_table)
+{
+ if (!kvm_enabled() ||
+ (kvmppc_remove_spapr_tce(table, fd, nb_table) != 0)) {
+ g_free(table);
+ }
+}
+
/* Called from RCU critical section */
static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr,
bool is_write)
@@ -142,21 +173,13 @@ static MemoryRegionIOMMUOps spapr_iommu_ops = {
static int spapr_tce_table_realize(DeviceState *dev)
{
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
- uint64_t window_size = (uint64_t)tcet->nb_table << tcet->page_shift;
-
- if (kvm_enabled() && !(window_size >> 32)) {
- tcet->table = kvmppc_create_spapr_tce(tcet->liobn,
- window_size,
- &tcet->fd,
- tcet->need_vfio);
- }
- if (!tcet->table) {
- size_t table_size = tcet->nb_table * sizeof(uint64_t);
- tcet->table = g_malloc0(table_size);
- }
-
- trace_spapr_iommu_new_table(tcet->liobn, tcet, tcet->table, tcet->fd);
+ tcet->fd = -1;
+ tcet->table = spapr_tce_alloc_table(tcet->liobn,
+ tcet->page_shift,
+ tcet->nb_table,
+ &tcet->fd,
+ tcet->need_vfio);
memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops,
"iommu-spapr",
@@ -242,11 +265,8 @@ static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
QLIST_REMOVE(tcet, list);
- if (!kvm_enabled() ||
- (kvmppc_remove_spapr_tce(tcet->table, tcet->fd,
- tcet->nb_table) != 0)) {
- g_free(tcet->table);
- }
+ spapr_tce_free_table(tcet->table, tcet->fd, tcet->nb_table);
+ tcet->fd = -1;
}
MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet)
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index e55b505..856aec7 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1093,13 +1093,11 @@ static void spapr_phb_add_pci_device(sPAPRDRConnector *drc,
spapr_tce_set_need_vfio(tcet, true);
}
- if (dev->hotplugged) {
- fdt = create_device_tree(&fdt_size);
- fdt_start_offset = spapr_create_pci_child_dt(phb, pdev, fdt, 0);
- if (!fdt_start_offset) {
- error_setg(errp, "Failed to create pci child device tree node");
- goto out;
- }
+ fdt = create_device_tree(&fdt_size);
+ fdt_start_offset = spapr_create_pci_child_dt(phb, pdev, fdt, 0);
+ if (!fdt_start_offset) {
+ error_setg(errp, "Failed to create pci child device tree node");
+ goto out;
}
drck->attach(drc, DEVICE(pdev),
@@ -1816,7 +1814,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
sizeof(interrupt_map)));
- tcet = spapr_tce_find_by_liobn(SPAPR_PCI_LIOBN(phb->index, 0));
+ tcet = spapr_tce_find_by_liobn(phb->dma_liobn);
if (!tcet) {
return -1;
}