All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915
@ 2017-09-15  3:51 David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 01/18] net: Add SunGEM device emulation as found on Apple UniNorth David Gibson
                   ` (19 more replies)
  0 siblings, 20 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell; +Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, David Gibson

The following changes since commit 3dabde1128b671f36ac6cb36b97b273139964420:

  Merge remote-tracking branch 'remotes/dgilbert/tags/pull-hmp-20170914' into staging (2017-09-14 16:33:02 +0100)

are available in the git repository at:

  git://github.com/dgibson/qemu.git tags/ppc-for-2.11-20170915

for you to fetch changes up to 70a0c19e83aa4c71c879d51e426e89e4b3d4e014:

  ppc/kvm: use kvm_vm_check_extension() in kvmppc_is_pr() (2017-09-15 10:29:48 +1000)

----------------------------------------------------------------
ppc patch queue 2017-09-15

Here's the current batch of accumulated ppc patches.  These are all
pretty simple bugfixes or cleanups, no big new features here.

----------------------------------------------------------------
Alexey Kardashevskiy (1):
      vfio, spapr: Fix levels calculation

Benjamin Herrenschmidt (1):
      net: Add SunGEM device emulation as found on Apple UniNorth

Cédric Le Goater (2):
      ppc/xive: fix OV5_XIVE_EXPLOIT bits
      spapr: fix CAS-generated reset

Daniel Henrique Barboza (1):
      hw/ppc/spapr.c: cleaning up qdev_get_machine() calls

Greg Kurz (13):
      spapr_pci: drop useless check in spapr_phb_vfio_get_loc_code()
      spapr_pci: drop useless check in spapr_populate_pci_child_dt()
      spapr_pci: use g_strdup_printf()
      spapr: only update SDR1 once per-cpu during CAS
      spapr_pci: use the common _FDT() helper
      spapr_pci: handle FDT creation errors with _FDT()
      xics: fix several error leaks
      spapr_cpu_core: fail gracefully with non-pseries machine types
      spapr_pci: convert sprintf() to g_strdup_printf()
      spapr_pci: don't create 64-bit MMIO window if we don't need to
      spapr_cpu_core: cleaning up qdev_get_machine() calls
      spapr_events: use QTAILQ_FOREACH_SAFE() in spapr_clear_pending_events()
      ppc/kvm: use kvm_vm_check_extension() in kvmppc_is_pr()

 default-configs/ppc-softmmu.mak |    1 +
 hw/intc/xics.c                  |   12 +-
 hw/net/Makefile.objs            |    1 +
 hw/net/sungem.c                 | 1447 +++++++++++++++++++++++++++++++++++++++
 hw/net/trace-events             |   44 ++
 hw/pci/pci.c                    |    2 +
 hw/ppc/spapr.c                  |   21 +-
 hw/ppc/spapr_cpu_core.c         |   11 +-
 hw/ppc/spapr_events.c           |    4 +-
 hw/ppc/spapr_hcall.c            |   21 +-
 hw/ppc/spapr_pci.c              |  106 ++-
 hw/vfio/spapr.c                 |    2 +-
 include/hw/pci/pci_ids.h        |    1 +
 include/hw/ppc/spapr_ovec.h     |    3 +-
 target/ppc/kvm.c                |    2 +-
 15 files changed, 1580 insertions(+), 98 deletions(-)
 create mode 100644 hw/net/sungem.c

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 01/18] net: Add SunGEM device emulation as found on Apple UniNorth
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 02/18] hw/ppc/spapr.c: cleaning up qdev_get_machine() calls David Gibson
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Benjamin Herrenschmidt,
	Mark Cave-Ayland, David Gibson

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

This adds a simplistic emulation of the Sun GEM ethernet controller
found in Apple ASICs.

Currently we only support the Apple UniNorth 1.x variant, but the
other Apple or Sun variants should mostly be a matter of adding
PCI IDs options.

We have a very primitive emulation of a single Broadcom 5201 PHY
which is supported by the MacOS driver.

This model brings out-of-the-box networking to MacOS 9, and all
versions of OS X I tried with the mac99 platform.

Further improvements from Mark:
- Remove sungem.h file, moving constants into sungem.c as required
- Switch to using tracepoints for debugging
- Split register blocks into separate memory regions
- Use arrays in SunGEMState to hold register values
- Add state-saving support

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 default-configs/ppc-softmmu.mak |    1 +
 hw/net/Makefile.objs            |    1 +
 hw/net/sungem.c                 | 1447 +++++++++++++++++++++++++++++++++++++++
 hw/net/trace-events             |   44 ++
 hw/pci/pci.c                    |    2 +
 include/hw/pci/pci_ids.h        |    1 +
 6 files changed, 1496 insertions(+)
 create mode 100644 hw/net/sungem.c

diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index d4d44eb66b..a3972c55fe 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -18,6 +18,7 @@ CONFIG_PREP_PCI=y
 CONFIG_I82378=y
 CONFIG_PC87312=y
 CONFIG_MACIO=y
+CONFIG_SUNGEM=y
 CONFIG_PCSPK=y
 CONFIG_CS4231A=y
 CONFIG_CUDA=y
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 5ddaffe63a..7e87d0176b 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -27,6 +27,7 @@ common-obj-$(CONFIG_CADENCE) += cadence_gem.o
 common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
 common-obj-$(CONFIG_LANCE) += lance.o
 common-obj-$(CONFIG_FTGMAC100) += ftgmac100.o
+common-obj-$(CONFIG_SUNGEM) += sungem.o
 
 obj-$(CONFIG_ETRAXFS) += etraxfs_eth.o
 obj-$(CONFIG_COLDFIRE) += mcf_fec.o
diff --git a/hw/net/sungem.c b/hw/net/sungem.c
new file mode 100644
index 0000000000..dffa0c90f3
--- /dev/null
+++ b/hw/net/sungem.c
@@ -0,0 +1,1447 @@
+/*
+ * QEMU model of SUN GEM ethernet controller
+ *
+ * As found in Apple ASICs among others
+ *
+ * Copyright 2016 Ben Herrenschmidt
+ * Copyright 2017 Mark Cave-Ayland
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci/pci.h"
+#include "qemu/log.h"
+#include "net/net.h"
+#include "net/checksum.h"
+#include "hw/net/mii.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+/* For crc32 */
+#include <zlib.h>
+
+#define TYPE_SUNGEM "sungem"
+
+#define SUNGEM(obj) OBJECT_CHECK(SunGEMState, (obj), TYPE_SUNGEM)
+
+#define MAX_PACKET_SIZE 9016
+
+#define SUNGEM_MMIO_SIZE        0x200000
+
+/* Global registers */
+#define SUNGEM_MMIO_GREG_SIZE   0x2000
+
+#define GREG_SEBSTATE     0x0000UL    /* SEB State Register */
+
+#define GREG_STAT         0x000CUL    /* Status Register */
+#define GREG_STAT_TXINTME     0x00000001    /* TX INTME frame transferred */
+#define GREG_STAT_TXALL       0x00000002    /* All TX frames transferred */
+#define GREG_STAT_TXDONE      0x00000004    /* One TX frame transferred */
+#define GREG_STAT_RXDONE      0x00000010    /* One RX frame arrived */
+#define GREG_STAT_RXNOBUF     0x00000020    /* No free RX buffers available */
+#define GREG_STAT_RXTAGERR    0x00000040    /* RX tag framing is corrupt */
+#define GREG_STAT_TXMAC       0x00004000    /* TX MAC signalled interrupt */
+#define GREG_STAT_RXMAC       0x00008000    /* RX MAC signalled interrupt */
+#define GREG_STAT_MAC         0x00010000    /* MAC Control signalled irq */
+#define GREG_STAT_TXNR        0xfff80000    /* == TXDMA_TXDONE reg val */
+#define GREG_STAT_TXNR_SHIFT  19
+
+/* These interrupts are edge latches in the status register,
+ * reading it (or writing the corresponding bit in IACK) will
+ * clear them
+ */
+#define GREG_STAT_LATCH       (GREG_STAT_TXALL  | GREG_STAT_TXINTME | \
+                               GREG_STAT_RXDONE | GREG_STAT_RXDONE |  \
+                               GREG_STAT_RXNOBUF | GREG_STAT_RXTAGERR)
+
+#define GREG_IMASK        0x0010UL    /* Interrupt Mask Register */
+#define GREG_IACK         0x0014UL    /* Interrupt ACK Register */
+#define GREG_STAT2        0x001CUL    /* Alias of GREG_STAT */
+#define GREG_PCIESTAT     0x1000UL    /* PCI Error Status Register */
+#define GREG_PCIEMASK     0x1004UL    /* PCI Error Mask Register */
+
+#define GREG_SWRST        0x1010UL    /* Software Reset Register */
+#define GREG_SWRST_TXRST      0x00000001    /* TX Software Reset */
+#define GREG_SWRST_RXRST      0x00000002    /* RX Software Reset */
+#define GREG_SWRST_RSTOUT     0x00000004    /* Force RST# pin active */
+
+/* TX DMA Registers */
+#define SUNGEM_MMIO_TXDMA_SIZE   0x1000
+
+#define TXDMA_KICK        0x0000UL    /* TX Kick Register */
+
+#define TXDMA_CFG         0x0004UL    /* TX Configuration Register */
+#define TXDMA_CFG_ENABLE      0x00000001    /* Enable TX DMA channel */
+#define TXDMA_CFG_RINGSZ      0x0000001e    /* TX descriptor ring size */
+
+#define TXDMA_DBLOW       0x0008UL    /* TX Desc. Base Low */
+#define TXDMA_DBHI        0x000CUL    /* TX Desc. Base High */
+#define TXDMA_PCNT        0x0024UL    /* TX FIFO Packet Counter */
+#define TXDMA_SMACHINE    0x0028UL    /* TX State Machine Register */
+#define TXDMA_DPLOW       0x0030UL    /* TX Data Pointer Low */
+#define TXDMA_DPHI        0x0034UL    /* TX Data Pointer High */
+#define TXDMA_TXDONE      0x0100UL    /* TX Completion Register */
+#define TXDMA_FTAG        0x0108UL    /* TX FIFO Tag */
+#define TXDMA_FSZ         0x0118UL    /* TX FIFO Size */
+
+/* Receive DMA Registers */
+#define SUNGEM_MMIO_RXDMA_SIZE   0x2000
+
+#define RXDMA_CFG         0x0000UL    /* RX Configuration Register */
+#define RXDMA_CFG_ENABLE      0x00000001    /* Enable RX DMA channel */
+#define RXDMA_CFG_RINGSZ      0x0000001e    /* RX descriptor ring size */
+#define RXDMA_CFG_FBOFF       0x00001c00    /* Offset of first data byte */
+#define RXDMA_CFG_CSUMOFF     0x000fe000    /* Skip bytes before csum calc */
+
+#define RXDMA_DBLOW       0x0004UL    /* RX Descriptor Base Low */
+#define RXDMA_DBHI        0x0008UL    /* RX Descriptor Base High */
+#define RXDMA_PCNT        0x0018UL    /* RX FIFO Packet Counter */
+#define RXDMA_SMACHINE    0x001CUL    /* RX State Machine Register */
+#define RXDMA_PTHRESH     0x0020UL    /* Pause Thresholds */
+#define RXDMA_DPLOW       0x0024UL    /* RX Data Pointer Low */
+#define RXDMA_DPHI        0x0028UL    /* RX Data Pointer High */
+#define RXDMA_KICK        0x0100UL    /* RX Kick Register */
+#define RXDMA_DONE        0x0104UL    /* RX Completion Register */
+#define RXDMA_BLANK       0x0108UL    /* RX Blanking Register */
+#define RXDMA_FTAG        0x0110UL    /* RX FIFO Tag */
+#define RXDMA_FSZ         0x0120UL    /* RX FIFO Size */
+
+/* MAC Registers */
+#define SUNGEM_MMIO_MAC_SIZE   0x200
+
+#define MAC_TXRST         0x0000UL    /* TX MAC Software Reset Command */
+#define MAC_RXRST         0x0004UL    /* RX MAC Software Reset Command */
+#define MAC_TXSTAT        0x0010UL    /* TX MAC Status Register */
+#define MAC_RXSTAT        0x0014UL    /* RX MAC Status Register */
+
+#define MAC_CSTAT         0x0018UL    /* MAC Control Status Register */
+#define MAC_CSTAT_PTR         0xffff0000    /* Pause Time Received */
+
+#define MAC_TXMASK        0x0020UL    /* TX MAC Mask Register */
+#define MAC_RXMASK        0x0024UL    /* RX MAC Mask Register */
+#define MAC_MCMASK        0x0028UL    /* MAC Control Mask Register */
+
+#define MAC_TXCFG         0x0030UL    /* TX MAC Configuration Register */
+#define MAC_TXCFG_ENAB        0x00000001    /* TX MAC Enable */
+
+#define MAC_RXCFG         0x0034UL    /* RX MAC Configuration Register */
+#define MAC_RXCFG_ENAB        0x00000001    /* RX MAC Enable */
+#define MAC_RXCFG_SFCS        0x00000004    /* Strip FCS */
+#define MAC_RXCFG_PROM        0x00000008    /* Promiscuous Mode */
+#define MAC_RXCFG_PGRP        0x00000010    /* Promiscuous Group */
+#define MAC_RXCFG_HFE         0x00000020    /* Hash Filter Enable */
+
+#define MAC_XIFCFG        0x003CUL    /* XIF Configuration Register */
+#define MAC_XIFCFG_LBCK       0x00000002    /* Loopback TX to RX */
+
+#define MAC_MINFSZ        0x0050UL    /* MinFrameSize Register */
+#define MAC_MAXFSZ        0x0054UL    /* MaxFrameSize Register */
+#define MAC_ADDR0         0x0080UL    /* MAC Address 0 Register */
+#define MAC_ADDR1         0x0084UL    /* MAC Address 1 Register */
+#define MAC_ADDR2         0x0088UL    /* MAC Address 2 Register */
+#define MAC_ADDR3         0x008CUL    /* MAC Address 3 Register */
+#define MAC_ADDR4         0x0090UL    /* MAC Address 4 Register */
+#define MAC_ADDR5         0x0094UL    /* MAC Address 5 Register */
+#define MAC_HASH0         0x00C0UL    /* Hash Table 0 Register */
+#define MAC_PATMPS        0x0114UL    /* Peak Attempts Register */
+#define MAC_SMACHINE      0x0134UL    /* State Machine Register */
+
+/* MIF Registers */
+#define SUNGEM_MMIO_MIF_SIZE   0x20
+
+#define MIF_FRAME         0x000CUL    /* MIF Frame/Output Register */
+#define MIF_FRAME_OP          0x30000000    /* OPcode */
+#define MIF_FRAME_PHYAD       0x0f800000    /* PHY ADdress */
+#define MIF_FRAME_REGAD       0x007c0000    /* REGister ADdress */
+#define MIF_FRAME_TALSB       0x00010000    /* Turn Around LSB */
+#define MIF_FRAME_DATA        0x0000ffff    /* Instruction Payload */
+
+#define MIF_CFG           0x0010UL    /* MIF Configuration Register */
+#define MIF_CFG_MDI0          0x00000100    /* MDIO_0 present or read-bit */
+#define MIF_CFG_MDI1          0x00000200    /* MDIO_1 present or read-bit */
+
+#define MIF_STATUS        0x0018UL    /* MIF Status Register */
+#define MIF_SMACHINE      0x001CUL    /* MIF State Machine Register */
+
+/* PCS/Serialink Registers */
+#define SUNGEM_MMIO_PCS_SIZE   0x60
+#define PCS_MIISTAT       0x0004UL    /* PCS MII Status Register */
+#define PCS_ISTAT         0x0018UL    /* PCS Interrupt Status Reg */
+#define PCS_SSTATE        0x005CUL    /* Serialink State Register */
+
+/* Descriptors */
+struct gem_txd {
+    uint64_t control_word;
+    uint64_t buffer;
+};
+
+#define TXDCTRL_BUFSZ     0x0000000000007fffULL  /* Buffer Size */
+#define TXDCTRL_CSTART    0x00000000001f8000ULL  /* CSUM Start Offset */
+#define TXDCTRL_COFF      0x000000001fe00000ULL  /* CSUM Stuff Offset */
+#define TXDCTRL_CENAB     0x0000000020000000ULL  /* CSUM Enable */
+#define TXDCTRL_EOF       0x0000000040000000ULL  /* End of Frame */
+#define TXDCTRL_SOF       0x0000000080000000ULL  /* Start of Frame */
+#define TXDCTRL_INTME     0x0000000100000000ULL  /* "Interrupt Me" */
+
+struct gem_rxd {
+    uint64_t status_word;
+    uint64_t buffer;
+};
+
+#define RXDCTRL_HPASS     0x1000000000000000ULL  /* Passed Hash Filter */
+#define RXDCTRL_ALTMAC    0x2000000000000000ULL  /* Matched ALT MAC */
+
+
+typedef struct {
+    PCIDevice pdev;
+
+    MemoryRegion sungem;
+    MemoryRegion greg;
+    MemoryRegion txdma;
+    MemoryRegion rxdma;
+    MemoryRegion mac;
+    MemoryRegion mif;
+    MemoryRegion pcs;
+    NICState *nic;
+    NICConf conf;
+    uint32_t phy_addr;
+
+    uint32_t gregs[SUNGEM_MMIO_GREG_SIZE >> 2];
+    uint32_t txdmaregs[SUNGEM_MMIO_TXDMA_SIZE >> 2];
+    uint32_t rxdmaregs[SUNGEM_MMIO_RXDMA_SIZE >> 2];
+    uint32_t macregs[SUNGEM_MMIO_MAC_SIZE >> 2];
+    uint32_t mifregs[SUNGEM_MMIO_MIF_SIZE >> 2];
+    uint32_t pcsregs[SUNGEM_MMIO_PCS_SIZE >> 2];
+
+    /* Cache some useful things */
+    uint32_t rx_mask;
+    uint32_t tx_mask;
+
+    /* Current tx packet */
+    uint8_t tx_data[MAX_PACKET_SIZE];
+    uint32_t tx_size;
+    uint64_t tx_first_ctl;
+} SunGEMState;
+
+
+static void sungem_eval_irq(SunGEMState *s)
+{
+    uint32_t stat, mask;
+
+    mask = s->gregs[GREG_IMASK >> 2];
+    stat = s->gregs[GREG_STAT >> 2] & ~GREG_STAT_TXNR;
+    if (stat & ~mask) {
+        pci_set_irq(PCI_DEVICE(s), 1);
+    } else {
+        pci_set_irq(PCI_DEVICE(s), 0);
+    }
+}
+
+static void sungem_update_status(SunGEMState *s, uint32_t bits, bool val)
+{
+    uint32_t stat;
+
+    stat = s->gregs[GREG_STAT >> 2];
+    if (val) {
+        stat |= bits;
+    } else {
+        stat &= ~bits;
+    }
+    s->gregs[GREG_STAT >> 2] = stat;
+    sungem_eval_irq(s);
+}
+
+static void sungem_eval_cascade_irq(SunGEMState *s)
+{
+    uint32_t stat, mask;
+
+    mask = s->macregs[MAC_TXSTAT >> 2];
+    stat = s->macregs[MAC_TXMASK >> 2];
+    if (stat & ~mask) {
+        sungem_update_status(s, GREG_STAT_TXMAC, true);
+    } else {
+        sungem_update_status(s, GREG_STAT_TXMAC, false);
+    }
+
+    mask = s->macregs[MAC_RXSTAT >> 2];
+    stat = s->macregs[MAC_RXMASK >> 2];
+    if (stat & ~mask) {
+        sungem_update_status(s, GREG_STAT_RXMAC, true);
+    } else {
+        sungem_update_status(s, GREG_STAT_RXMAC, false);
+    }
+
+    mask = s->macregs[MAC_CSTAT >> 2];
+    stat = s->macregs[MAC_MCMASK >> 2] & ~MAC_CSTAT_PTR;
+    if (stat & ~mask) {
+        sungem_update_status(s, GREG_STAT_MAC, true);
+    } else {
+        sungem_update_status(s, GREG_STAT_MAC, false);
+    }
+}
+
+static void sungem_do_tx_csum(SunGEMState *s)
+{
+    uint16_t start, off;
+    uint32_t csum;
+
+    start = (s->tx_first_ctl & TXDCTRL_CSTART) >> 15;
+    off = (s->tx_first_ctl & TXDCTRL_COFF) >> 21;
+
+    trace_sungem_tx_checksum(start, off);
+
+    if (start > (s->tx_size - 2) || off > (s->tx_size - 2)) {
+        trace_sungem_tx_checksum_oob();
+        return;
+    }
+
+    csum = net_raw_checksum(s->tx_data + start, s->tx_size - start);
+    stw_be_p(s->tx_data + off, csum);
+}
+
+static void sungem_send_packet(SunGEMState *s, const uint8_t *buf,
+                               int size)
+{
+    NetClientState *nc = qemu_get_queue(s->nic);
+
+    if (s->macregs[MAC_XIFCFG >> 2] & MAC_XIFCFG_LBCK) {
+        nc->info->receive(nc, buf, size);
+    } else {
+        qemu_send_packet(nc, buf, size);
+    }
+}
+
+static void sungem_process_tx_desc(SunGEMState *s, struct gem_txd *desc)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+    uint32_t len;
+
+    /* If it's a start of frame, discard anything we had in the
+     * buffer and start again. This should be an error condition
+     * if we had something ... for now we ignore it
+     */
+    if (desc->control_word & TXDCTRL_SOF) {
+        if (s->tx_first_ctl) {
+            trace_sungem_tx_unfinished();
+        }
+        s->tx_size = 0;
+        s->tx_first_ctl = desc->control_word;
+    }
+
+    /* Grab data size */
+    len = desc->control_word & TXDCTRL_BUFSZ;
+
+    /* Clamp it to our max size */
+    if ((s->tx_size + len) > MAX_PACKET_SIZE) {
+        trace_sungem_tx_overflow();
+        len = MAX_PACKET_SIZE - s->tx_size;
+    }
+
+    /* Read the data */
+    pci_dma_read(d, desc->buffer, &s->tx_data[s->tx_size], len);
+    s->tx_size += len;
+
+    /* If end of frame, send packet */
+    if (desc->control_word & TXDCTRL_EOF) {
+        trace_sungem_tx_finished(s->tx_size);
+
+        /* Handle csum */
+        if (s->tx_first_ctl & TXDCTRL_CENAB) {
+            sungem_do_tx_csum(s);
+        }
+
+        /* Send it */
+        sungem_send_packet(s, s->tx_data, s->tx_size);
+
+        /* No more pending packet */
+        s->tx_size = 0;
+        s->tx_first_ctl = 0;
+    }
+}
+
+static void sungem_tx_kick(SunGEMState *s)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+    uint32_t comp, kick;
+    uint32_t txdma_cfg, txmac_cfg, ints;
+    uint64_t dbase;
+
+    trace_sungem_tx_kick();
+
+    /* Check that both TX MAC and TX DMA are enabled. We don't
+     * handle DMA-less direct FIFO operations (we don't emulate
+     * the FIFO at all).
+     *
+     * A write to TXDMA_KICK while DMA isn't enabled can happen
+     * when the driver is resetting the pointer.
+     */
+    txdma_cfg = s->txdmaregs[TXDMA_CFG >> 2];
+    txmac_cfg = s->macregs[MAC_TXCFG >> 2];
+    if (!(txdma_cfg & TXDMA_CFG_ENABLE) ||
+        !(txmac_cfg & MAC_TXCFG_ENAB)) {
+        trace_sungem_tx_disabled();
+        return;
+    }
+
+    /* XXX Test min frame size register ? */
+    /* XXX Test max frame size register ? */
+
+    dbase = s->txdmaregs[TXDMA_DBHI >> 2];
+    dbase = (dbase << 32) | s->txdmaregs[TXDMA_DBLOW >> 2];
+
+    comp = s->txdmaregs[TXDMA_TXDONE >> 2] & s->tx_mask;
+    kick = s->txdmaregs[TXDMA_KICK >> 2] & s->tx_mask;
+
+    trace_sungem_tx_process(comp, kick, s->tx_mask + 1);
+
+    /* This is rather primitive for now, we just send everything we
+     * can in one go, like e1000. Ideally we should do the sending
+     * from some kind of background task
+     */
+    while (comp != kick) {
+        struct gem_txd desc;
+
+        /* Read the next descriptor */
+        pci_dma_read(d, dbase + comp * sizeof(desc), &desc, sizeof(desc));
+
+        /* Byteswap descriptor */
+        desc.control_word = le64_to_cpu(desc.control_word);
+        desc.buffer = le64_to_cpu(desc.buffer);
+        trace_sungem_tx_desc(comp, desc.control_word, desc.buffer);
+
+        /* Send it for processing */
+        sungem_process_tx_desc(s, &desc);
+
+        /* Interrupt */
+        ints = GREG_STAT_TXDONE;
+        if (desc.control_word & TXDCTRL_INTME) {
+            ints |= GREG_STAT_TXINTME;
+        }
+        sungem_update_status(s, ints, true);
+
+        /* Next ! */
+        comp = (comp + 1) & s->tx_mask;
+        s->txdmaregs[TXDMA_TXDONE >> 2] = comp;
+    }
+
+    /* We sent everything, set status/irq bit */
+    sungem_update_status(s, GREG_STAT_TXALL, true);
+}
+
+static bool sungem_rx_full(SunGEMState *s, uint32_t kick, uint32_t done)
+{
+    return kick == ((done + 1) & s->rx_mask);
+}
+
+static int sungem_can_receive(NetClientState *nc)
+{
+    SunGEMState *s = qemu_get_nic_opaque(nc);
+    uint32_t kick, done, rxdma_cfg, rxmac_cfg;
+    bool full;
+
+    rxmac_cfg = s->macregs[MAC_RXCFG >> 2];
+    rxdma_cfg = s->rxdmaregs[RXDMA_CFG >> 2];
+
+    /* If MAC disabled, can't receive */
+    if ((rxmac_cfg & MAC_RXCFG_ENAB) == 0) {
+        trace_sungem_rx_mac_disabled();
+        return 0;
+    }
+    if ((rxdma_cfg & RXDMA_CFG_ENABLE) == 0) {
+        trace_sungem_rx_txdma_disabled();
+        return 0;
+    }
+
+    /* Check RX availability */
+    kick = s->rxdmaregs[RXDMA_KICK >> 2];
+    done = s->rxdmaregs[RXDMA_DONE >> 2];
+    full = sungem_rx_full(s, kick, done);
+
+    trace_sungem_rx_check(!full, kick, done);
+
+    return !full;
+}
+
+enum {
+        rx_no_match,
+        rx_match_promisc,
+        rx_match_bcast,
+        rx_match_allmcast,
+        rx_match_mcast,
+        rx_match_mac,
+        rx_match_altmac,
+};
+
+static int sungem_check_rx_mac(SunGEMState *s, const uint8_t *mac, uint32_t crc)
+{
+    uint32_t rxcfg = s->macregs[MAC_RXCFG >> 2];
+    uint32_t mac0, mac1, mac2;
+
+    /* Promisc enabled ? */
+    if (rxcfg & MAC_RXCFG_PROM) {
+        return rx_match_promisc;
+    }
+
+    /* Format MAC address into dwords */
+    mac0 = (mac[4] << 8) | mac[5];
+    mac1 = (mac[2] << 8) | mac[3];
+    mac2 = (mac[0] << 8) | mac[1];
+
+    trace_sungem_rx_mac_check(mac0, mac1, mac2);
+
+    /* Is this a broadcast frame ? */
+    if (mac0 == 0xffff && mac1 == 0xffff && mac2 == 0xffff) {
+        return rx_match_bcast;
+    }
+
+    /* TODO: Implement address filter registers (or we don't care ?) */
+
+    /* Is this a multicast frame ? */
+    if (mac[0] & 1) {
+        trace_sungem_rx_mac_multicast();
+
+        /* Promisc group enabled ? */
+        if (rxcfg & MAC_RXCFG_PGRP) {
+            return rx_match_allmcast;
+        }
+
+        /* TODO: Check MAC control frames (or we don't care) ? */
+
+        /* Check hash filter (somebody check that's correct ?) */
+        if (rxcfg & MAC_RXCFG_HFE) {
+            uint32_t hash, idx;
+
+            crc >>= 24;
+            idx = (crc >> 2) & 0x3c;
+            hash = s->macregs[(MAC_HASH0 + idx) >> 2];
+            if (hash & (1 << (15 - (crc & 0xf)))) {
+                return rx_match_mcast;
+            }
+        }
+        return rx_no_match;
+    }
+
+    /* Main MAC check */
+    trace_sungem_rx_mac_compare(s->macregs[MAC_ADDR0 >> 2],
+                                s->macregs[MAC_ADDR1 >> 2],
+                                s->macregs[MAC_ADDR2 >> 2]);
+
+    if (mac0 == s->macregs[MAC_ADDR0 >> 2] &&
+        mac1 == s->macregs[MAC_ADDR1 >> 2] &&
+        mac2 == s->macregs[MAC_ADDR2 >> 2]) {
+        return rx_match_mac;
+    }
+
+    /* Alt MAC check */
+    if (mac0 == s->macregs[MAC_ADDR3 >> 2] &&
+        mac1 == s->macregs[MAC_ADDR4 >> 2] &&
+        mac2 == s->macregs[MAC_ADDR5 >> 2]) {
+        return rx_match_altmac;
+    }
+
+    return rx_no_match;
+}
+
+static ssize_t sungem_receive(NetClientState *nc, const uint8_t *buf,
+                              size_t size)
+{
+    SunGEMState *s = qemu_get_nic_opaque(nc);
+    PCIDevice *d = PCI_DEVICE(s);
+    uint32_t mac_crc, done, kick, max_fsize;
+    uint32_t fcs_size, ints, rxdma_cfg, rxmac_cfg, csum, coff;
+    uint8_t smallbuf[60];
+    struct gem_rxd desc;
+    uint64_t dbase, baddr;
+    unsigned int rx_cond;
+
+    trace_sungem_rx_packet(size);
+
+    rxmac_cfg = s->macregs[MAC_RXCFG >> 2];
+    rxdma_cfg = s->rxdmaregs[RXDMA_CFG >> 2];
+    max_fsize = s->macregs[MAC_MAXFSZ >> 2] & 0x7fff;
+
+    /* If MAC or DMA disabled, can't receive */
+    if (!(rxdma_cfg & RXDMA_CFG_ENABLE) ||
+        !(rxmac_cfg & MAC_RXCFG_ENAB)) {
+        trace_sungem_rx_disabled();
+        return 0;
+    }
+
+    /* Size adjustment for FCS */
+    if (rxmac_cfg & MAC_RXCFG_SFCS) {
+        fcs_size = 0;
+    } else {
+        fcs_size = 4;
+    }
+
+    /* Discard frame smaller than a MAC or larger than max frame size
+     * (when accounting for FCS)
+     */
+    if (size < 6 || (size + 4) > max_fsize) {
+        trace_sungem_rx_bad_frame_size(size);
+        /* XXX Increment error statistics ? */
+        return size;
+    }
+
+    /* We don't drop too small frames since we get them in qemu, we pad
+     * them instead. We should probably use the min frame size register
+     * but I don't want to use a variable size staging buffer and I
+     * know both MacOS and Linux use the default 64 anyway. We use 60
+     * here to account for the non-existent FCS.
+     */
+    if (size < 60) {
+        memcpy(smallbuf, buf, size);
+        memset(&smallbuf[size], 0, 60 - size);
+        buf = smallbuf;
+        size = 60;
+    }
+
+    /* Get MAC crc */
+    mac_crc = crc32(~0, buf, 6);
+
+    /* Packet isn't for me ? */
+    rx_cond = sungem_check_rx_mac(s, buf, mac_crc);
+    if (rx_cond == rx_no_match) {
+        /* Just drop it */
+        trace_sungem_rx_unmatched();
+        return size;
+    }
+
+    /* Get ring pointers */
+    kick = s->rxdmaregs[RXDMA_KICK >> 2] & s->rx_mask;
+    done = s->rxdmaregs[RXDMA_DONE >> 2] & s->rx_mask;
+
+    trace_sungem_rx_process(done, kick, s->rx_mask + 1);
+
+    /* Ring full ? Can't receive */
+    if (sungem_rx_full(s, kick, done)) {
+        trace_sungem_rx_ringfull();
+        return 0;
+    }
+
+    /* Note: The real GEM will fetch descriptors in blocks of 4,
+     * for now we handle them one at a time, I think the driver will
+     * cope
+     */
+
+    dbase = s->rxdmaregs[RXDMA_DBHI >> 2];
+    dbase = (dbase << 32) | s->rxdmaregs[RXDMA_DBLOW >> 2];
+
+    /* Read the next descriptor */
+    pci_dma_read(d, dbase + done * sizeof(desc), &desc, sizeof(desc));
+
+    trace_sungem_rx_desc(le64_to_cpu(desc.status_word),
+                         le64_to_cpu(desc.buffer));
+
+    /* Effective buffer address */
+    baddr = le64_to_cpu(desc.buffer) & ~7ull;
+    baddr |= (rxdma_cfg & RXDMA_CFG_FBOFF) >> 10;
+
+    /* Write buffer out */
+    pci_dma_write(d, baddr, buf, size);
+
+    if (fcs_size) {
+        /* Should we add an FCS ? Linux doesn't ask us to strip it,
+         * however I believe nothing checks it... For now we just
+         * do nothing. It's faster this way.
+         */
+    }
+
+    /* Calculate the checksum */
+    coff = (rxdma_cfg & RXDMA_CFG_CSUMOFF) >> 13;
+    csum = net_raw_checksum((uint8_t *)buf + coff, size - coff);
+
+    /* Build the updated descriptor */
+    desc.status_word = (size + fcs_size) << 16;
+    desc.status_word |= ((uint64_t)(mac_crc >> 16)) << 44;
+    desc.status_word |= csum;
+    if (rx_cond == rx_match_mcast) {
+        desc.status_word |= RXDCTRL_HPASS;
+    }
+    if (rx_cond == rx_match_altmac) {
+        desc.status_word |= RXDCTRL_ALTMAC;
+    }
+    desc.status_word = cpu_to_le64(desc.status_word);
+
+    pci_dma_write(d, dbase + done * sizeof(desc), &desc, sizeof(desc));
+
+    done = (done + 1) & s->rx_mask;
+    s->rxdmaregs[RXDMA_DONE >> 2] = done;
+
+    /* XXX Unconditionally set RX interrupt for now. The interrupt
+     * mitigation timer might well end up adding more overhead than
+     * helping here...
+     */
+    ints = GREG_STAT_RXDONE;
+    if (sungem_rx_full(s, kick, done)) {
+        ints |= GREG_STAT_RXNOBUF;
+    }
+    sungem_update_status(s, ints, true);
+
+    return size;
+}
+
+static void sungem_set_link_status(NetClientState *nc)
+{
+    /* We don't do anything for now as I believe none of the OSes
+     * drivers use the MIF autopoll feature nor the PHY interrupt
+     */
+}
+
+static void sungem_update_masks(SunGEMState *s)
+{
+    uint32_t sz;
+
+    sz = 1 << (((s->rxdmaregs[RXDMA_CFG >> 2] & RXDMA_CFG_RINGSZ) >> 1) + 5);
+    s->rx_mask = sz - 1;
+
+    sz = 1 << (((s->txdmaregs[TXDMA_CFG >> 2] & TXDMA_CFG_RINGSZ) >> 1) + 5);
+    s->tx_mask = sz - 1;
+}
+
+static void sungem_reset_rx(SunGEMState *s)
+{
+    trace_sungem_rx_reset();
+
+    /* XXX Do RXCFG */
+    /* XXX Check value */
+    s->rxdmaregs[RXDMA_FSZ >> 2] = 0x140;
+    s->rxdmaregs[RXDMA_DONE >> 2] = 0;
+    s->rxdmaregs[RXDMA_KICK >> 2] = 0;
+    s->rxdmaregs[RXDMA_CFG >> 2] = 0x1000010;
+    s->rxdmaregs[RXDMA_PTHRESH >> 2] = 0xf8;
+    s->rxdmaregs[RXDMA_BLANK >> 2] = 0;
+
+    sungem_update_masks(s);
+}
+
+static void sungem_reset_tx(SunGEMState *s)
+{
+    trace_sungem_tx_reset();
+
+    /* XXX Do TXCFG */
+    /* XXX Check value */
+    s->txdmaregs[TXDMA_FSZ >> 2] = 0x90;
+    s->txdmaregs[TXDMA_TXDONE >> 2] = 0;
+    s->txdmaregs[TXDMA_KICK >> 2] = 0;
+    s->txdmaregs[TXDMA_CFG >> 2] = 0x118010;
+
+    sungem_update_masks(s);
+
+    s->tx_size = 0;
+    s->tx_first_ctl = 0;
+}
+
+static void sungem_reset_all(SunGEMState *s, bool pci_reset)
+{
+    trace_sungem_reset(pci_reset);
+
+    sungem_reset_rx(s);
+    sungem_reset_tx(s);
+
+    s->gregs[GREG_IMASK >> 2] = 0xFFFFFFF;
+    s->gregs[GREG_STAT >> 2] = 0;
+    if (pci_reset) {
+        uint8_t *ma = s->conf.macaddr.a;
+
+        s->gregs[GREG_SWRST >> 2] = 0;
+        s->macregs[MAC_ADDR0 >> 2] = (ma[4] << 8) | ma[5];
+        s->macregs[MAC_ADDR1 >> 2] = (ma[2] << 8) | ma[3];
+        s->macregs[MAC_ADDR2 >> 2] = (ma[0] << 8) | ma[1];
+    } else {
+        s->gregs[GREG_SWRST >> 2] &= GREG_SWRST_RSTOUT;
+    }
+    s->mifregs[MIF_CFG >> 2] = MIF_CFG_MDI0;
+}
+
+static void sungem_mii_write(SunGEMState *s, uint8_t phy_addr,
+                             uint8_t reg_addr, uint16_t val)
+{
+    trace_sungem_mii_write(phy_addr, reg_addr, val);
+
+    /* XXX TODO */
+}
+
+static uint16_t __sungem_mii_read(SunGEMState *s, uint8_t phy_addr,
+                                  uint8_t reg_addr)
+{
+    if (phy_addr != s->phy_addr) {
+        return 0xffff;
+    }
+    /* Primitive emulation of a BCM5201 to please the driver,
+     * ID is 0x00406210. TODO: Do a gigabit PHY like BCM5400
+     */
+    switch (reg_addr) {
+    case MII_BMCR:
+        return 0;
+    case MII_PHYID1:
+        return 0x0040;
+    case MII_PHYID2:
+        return 0x6210;
+    case MII_BMSR:
+        if (qemu_get_queue(s->nic)->link_down) {
+            return MII_BMSR_100TX_FD  | MII_BMSR_AUTONEG;
+        } else {
+            return MII_BMSR_100TX_FD | MII_BMSR_AN_COMP |
+                    MII_BMSR_AUTONEG | MII_BMSR_LINK_ST;
+        }
+    case MII_ANLPAR:
+    case MII_ANAR:
+        return MII_ANLPAR_TXFD;
+    case 0x18: /* 5201 AUX status */
+        return 3; /* 100FD */
+    default:
+        return 0;
+    };
+}
+static uint16_t sungem_mii_read(SunGEMState *s, uint8_t phy_addr,
+                                uint8_t reg_addr)
+{
+    uint16_t val;
+
+    val = __sungem_mii_read(s, phy_addr, reg_addr);
+
+    trace_sungem_mii_read(phy_addr, reg_addr, val);
+
+    return val;
+}
+
+static uint32_t sungem_mii_op(SunGEMState *s, uint32_t val)
+{
+    uint8_t phy_addr, reg_addr, op;
+
+    /* Ignore not start of frame */
+    if ((val >> 30) != 1) {
+        trace_sungem_mii_invalid_sof(val >> 30);
+        return 0xffff;
+    }
+    phy_addr = (val & MIF_FRAME_PHYAD) >> 23;
+    reg_addr = (val & MIF_FRAME_REGAD) >> 18;
+    op = (val & MIF_FRAME_OP) >> 28;
+    switch (op) {
+    case 1:
+        sungem_mii_write(s, phy_addr, reg_addr, val & MIF_FRAME_DATA);
+        return val | MIF_FRAME_TALSB;
+    case 2:
+        return sungem_mii_read(s, phy_addr, reg_addr) | MIF_FRAME_TALSB;
+    default:
+        trace_sungem_mii_invalid_op(op);
+    }
+    return 0xffff | MIF_FRAME_TALSB;
+}
+
+static void sungem_mmio_greg_write(void *opaque, hwaddr addr, uint64_t val,
+                                   unsigned size)
+{
+    SunGEMState *s = opaque;
+
+    if (!(addr < 0x20) && !(addr >= 0x1000 && addr <= 0x1010)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Write to unknown GREG register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return;
+    }
+
+    trace_sungem_mmio_greg_write(addr, val);
+
+    /* Pre-write filter */
+    switch (addr) {
+    /* Read only registers */
+    case GREG_SEBSTATE:
+    case GREG_STAT:
+    case GREG_STAT2:
+    case GREG_PCIESTAT:
+        return; /* No actual write */
+    case GREG_IACK:
+        val &= GREG_STAT_LATCH;
+        s->gregs[GREG_STAT >> 2] &= ~val;
+        sungem_eval_irq(s);
+        return; /* No actual write */
+    case GREG_PCIEMASK:
+        val &= 0x7;
+        break;
+    }
+
+    s->gregs[addr  >> 2] = val;
+
+    /* Post write action */
+    switch (addr) {
+    case GREG_IMASK:
+        /* Re-evaluate interrupt */
+        sungem_eval_irq(s);
+        break;
+    case GREG_SWRST:
+        switch (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST)) {
+        case GREG_SWRST_RXRST:
+            sungem_reset_rx(s);
+            break;
+        case GREG_SWRST_TXRST:
+            sungem_reset_tx(s);
+            break;
+        case GREG_SWRST_RXRST | GREG_SWRST_TXRST:
+            sungem_reset_all(s, false);
+        }
+        break;
+    }
+}
+
+static uint64_t sungem_mmio_greg_read(void *opaque, hwaddr addr, unsigned size)
+{
+    SunGEMState *s = opaque;
+    uint32_t val;
+
+    if (!(addr < 0x20) && !(addr >= 0x1000 && addr <= 0x1010)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Read from unknown GREG register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return 0;
+    }
+
+    val = s->gregs[addr >> 2];
+
+    trace_sungem_mmio_greg_read(addr, val);
+
+    switch (addr) {
+    case GREG_STAT:
+        /* Side effect, clear bottom 7 bits */
+        s->gregs[GREG_STAT >> 2] &= ~GREG_STAT_LATCH;
+        sungem_eval_irq(s);
+
+        /* Inject TX completion in returned value */
+        val = (val & ~GREG_STAT_TXNR) |
+                (s->txdmaregs[TXDMA_TXDONE >> 2] << GREG_STAT_TXNR_SHIFT);
+        break;
+    case GREG_STAT2:
+        /* Return the status reg without side effect
+         * (and inject TX completion in returned value)
+         */
+        val = (s->gregs[GREG_STAT >> 2] & ~GREG_STAT_TXNR) |
+              (s->txdmaregs[TXDMA_TXDONE >> 2] << GREG_STAT_TXNR_SHIFT);
+        break;
+    }
+
+    return val;
+}
+
+static const MemoryRegionOps sungem_mmio_greg_ops = {
+    .read = sungem_mmio_greg_read,
+    .write = sungem_mmio_greg_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void sungem_mmio_txdma_write(void *opaque, hwaddr addr, uint64_t val,
+                                    unsigned size)
+{
+    SunGEMState *s = opaque;
+
+    if (!(addr < 0x38) && !(addr >= 0x100 && addr <= 0x118)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Write to unknown TXDMA register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return;
+    }
+
+    trace_sungem_mmio_txdma_write(addr, val);
+
+    /* Pre-write filter */
+    switch (addr) {
+    /* Read only registers */
+    case TXDMA_TXDONE:
+    case TXDMA_PCNT:
+    case TXDMA_SMACHINE:
+    case TXDMA_DPLOW:
+    case TXDMA_DPHI:
+    case TXDMA_FSZ:
+    case TXDMA_FTAG:
+        return; /* No actual write */
+    }
+
+    s->txdmaregs[addr >> 2] = val;
+
+    /* Post write action */
+    switch (addr) {
+    case TXDMA_KICK:
+        sungem_tx_kick(s);
+        break;
+    case TXDMA_CFG:
+        sungem_update_masks(s);
+        break;
+    }
+}
+
+static uint64_t sungem_mmio_txdma_read(void *opaque, hwaddr addr, unsigned size)
+{
+    SunGEMState *s = opaque;
+    uint32_t val;
+
+    if (!(addr < 0x38) && !(addr >= 0x100 && addr <= 0x118)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Read from unknown TXDMA register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return 0;
+    }
+
+    val = s->txdmaregs[addr >> 2];
+
+    trace_sungem_mmio_txdma_read(addr, val);
+
+    return val;
+}
+
+static const MemoryRegionOps sungem_mmio_txdma_ops = {
+    .read = sungem_mmio_txdma_read,
+    .write = sungem_mmio_txdma_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void sungem_mmio_rxdma_write(void *opaque, hwaddr addr, uint64_t val,
+                                    unsigned size)
+{
+    SunGEMState *s = opaque;
+
+    if (!(addr <= 0x28) && !(addr >= 0x100 && addr <= 0x120)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Write to unknown RXDMA register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return;
+    }
+
+    trace_sungem_mmio_rxdma_write(addr, val);
+
+    /* Pre-write filter */
+    switch (addr) {
+    /* Read only registers */
+    case RXDMA_DONE:
+    case RXDMA_PCNT:
+    case RXDMA_SMACHINE:
+    case RXDMA_DPLOW:
+    case RXDMA_DPHI:
+    case RXDMA_FSZ:
+    case RXDMA_FTAG:
+        return; /* No actual write */
+    }
+
+    s->rxdmaregs[addr >> 2] = val;
+
+    /* Post write action */
+    switch (addr) {
+    case RXDMA_KICK:
+        trace_sungem_rx_kick(val);
+        break;
+    case RXDMA_CFG:
+        sungem_update_masks(s);
+        if ((s->macregs[MAC_RXCFG >> 2] & MAC_RXCFG_ENAB) != 0 &&
+            (s->rxdmaregs[RXDMA_CFG >> 2] & RXDMA_CFG_ENABLE) != 0) {
+            qemu_flush_queued_packets(qemu_get_queue(s->nic));
+        }
+        break;
+    }
+}
+
+static uint64_t sungem_mmio_rxdma_read(void *opaque, hwaddr addr, unsigned size)
+{
+    SunGEMState *s = opaque;
+    uint32_t val;
+
+    if (!(addr <= 0x28) && !(addr >= 0x100 && addr <= 0x120)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Read from unknown RXDMA register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return 0;
+    }
+
+    val = s->rxdmaregs[addr >> 2];
+
+    trace_sungem_mmio_rxdma_read(addr, val);
+
+    return val;
+}
+
+static const MemoryRegionOps sungem_mmio_rxdma_ops = {
+    .read = sungem_mmio_rxdma_read,
+    .write = sungem_mmio_rxdma_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void sungem_mmio_mac_write(void *opaque, hwaddr addr, uint64_t val,
+                                  unsigned size)
+{
+    SunGEMState *s = opaque;
+
+    if (!(addr <= 0x134)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Write to unknown MAC register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return;
+    }
+
+    trace_sungem_mmio_mac_write(addr, val);
+
+    /* Pre-write filter */
+    switch (addr) {
+    /* Read only registers */
+    case MAC_TXRST: /* Not technically read-only but will do for now */
+    case MAC_RXRST: /* Not technically read-only but will do for now */
+    case MAC_TXSTAT:
+    case MAC_RXSTAT:
+    case MAC_CSTAT:
+    case MAC_PATMPS:
+    case MAC_SMACHINE:
+        return; /* No actual write */
+    case MAC_MINFSZ:
+        /* 10-bits implemented */
+        val &= 0x3ff;
+        break;
+    }
+
+    s->macregs[addr >> 2] = val;
+
+    /* Post write action */
+    switch (addr) {
+    case MAC_TXMASK:
+    case MAC_RXMASK:
+    case MAC_MCMASK:
+        sungem_eval_cascade_irq(s);
+        break;
+    case MAC_RXCFG:
+        sungem_update_masks(s);
+        if ((s->macregs[MAC_RXCFG >> 2] & MAC_RXCFG_ENAB) != 0 &&
+            (s->rxdmaregs[RXDMA_CFG >> 2] & RXDMA_CFG_ENABLE) != 0) {
+            qemu_flush_queued_packets(qemu_get_queue(s->nic));
+        }
+        break;
+    }
+}
+
+static uint64_t sungem_mmio_mac_read(void *opaque, hwaddr addr, unsigned size)
+{
+    SunGEMState *s = opaque;
+    uint32_t val;
+
+    if (!(addr <= 0x134)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Read from unknown MAC register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return 0;
+    }
+
+    val = s->macregs[addr >> 2];
+
+    trace_sungem_mmio_mac_read(addr, val);
+
+    switch (addr) {
+    case MAC_TXSTAT:
+        /* Side effect, clear all */
+        s->macregs[addr >> 2] = 0;
+        sungem_update_status(s, GREG_STAT_TXMAC, false);
+        break;
+    case MAC_RXSTAT:
+        /* Side effect, clear all */
+        s->macregs[addr >> 2] = 0;
+        sungem_update_status(s, GREG_STAT_RXMAC, false);
+        break;
+    case MAC_CSTAT:
+        /* Side effect, interrupt bits */
+        s->macregs[addr >> 2] &= MAC_CSTAT_PTR;
+        sungem_update_status(s, GREG_STAT_MAC, false);
+        break;
+    }
+
+    return val;
+}
+
+static const MemoryRegionOps sungem_mmio_mac_ops = {
+    .read = sungem_mmio_mac_read,
+    .write = sungem_mmio_mac_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void sungem_mmio_mif_write(void *opaque, hwaddr addr, uint64_t val,
+                                  unsigned size)
+{
+    SunGEMState *s = opaque;
+
+    if (!(addr <= 0x1c)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Write to unknown MIF register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return;
+    }
+
+    trace_sungem_mmio_mif_write(addr, val);
+
+    /* Pre-write filter */
+    switch (addr) {
+    /* Read only registers */
+    case MIF_STATUS:
+    case MIF_SMACHINE:
+        return; /* No actual write */
+    case MIF_CFG:
+        /* Maintain the RO MDI bits to advertize an MDIO PHY on MDI0 */
+        val &= ~MIF_CFG_MDI1;
+        val |= MIF_CFG_MDI0;
+        break;
+    }
+
+    s->mifregs[addr >> 2] = val;
+
+    /* Post write action */
+    switch (addr) {
+    case MIF_FRAME:
+        s->mifregs[addr >> 2] = sungem_mii_op(s, val);
+        break;
+    }
+}
+
+static uint64_t sungem_mmio_mif_read(void *opaque, hwaddr addr, unsigned size)
+{
+    SunGEMState *s = opaque;
+    uint32_t val;
+
+    if (!(addr <= 0x1c)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Read from unknown MIF register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return 0;
+    }
+
+    val = s->mifregs[addr >> 2];
+
+    trace_sungem_mmio_mif_read(addr, val);
+
+    return val;
+}
+
+static const MemoryRegionOps sungem_mmio_mif_ops = {
+    .read = sungem_mmio_mif_read,
+    .write = sungem_mmio_mif_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void sungem_mmio_pcs_write(void *opaque, hwaddr addr, uint64_t val,
+                                  unsigned size)
+{
+    SunGEMState *s = opaque;
+
+    if (!(addr <= 0x18) && !(addr >= 0x50 && addr <= 0x5c)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Write to unknown PCS register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return;
+    }
+
+    trace_sungem_mmio_pcs_write(addr, val);
+
+    /* Pre-write filter */
+    switch (addr) {
+    /* Read only registers */
+    case PCS_MIISTAT:
+    case PCS_ISTAT:
+    case PCS_SSTATE:
+        return; /* No actual write */
+    }
+
+    s->pcsregs[addr >> 2] = val;
+}
+
+static uint64_t sungem_mmio_pcs_read(void *opaque, hwaddr addr, unsigned size)
+{
+    SunGEMState *s = opaque;
+    uint32_t val;
+
+    if (!(addr <= 0x18) && !(addr >= 0x50 && addr <= 0x5c)) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Read from unknown PCS register 0x%"HWADDR_PRIx"\n",
+                      addr);
+        return 0;
+    }
+
+    val = s->pcsregs[addr >> 2];
+
+    trace_sungem_mmio_pcs_read(addr, val);
+
+    return val;
+}
+
+static const MemoryRegionOps sungem_mmio_pcs_ops = {
+    .read = sungem_mmio_pcs_read,
+    .write = sungem_mmio_pcs_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void sungem_uninit(PCIDevice *dev)
+{
+    SunGEMState *s = SUNGEM(dev);
+
+    qemu_del_nic(s->nic);
+}
+
+static NetClientInfo net_sungem_info = {
+    .type = NET_CLIENT_DRIVER_NIC,
+    .size = sizeof(NICState),
+    .can_receive = sungem_can_receive,
+    .receive = sungem_receive,
+    .link_status_changed = sungem_set_link_status,
+};
+
+static void sungem_realize(PCIDevice *pci_dev, Error **errp)
+{
+    DeviceState *dev = DEVICE(pci_dev);
+    SunGEMState *s = SUNGEM(pci_dev);
+    uint8_t *pci_conf;
+
+    pci_conf = pci_dev->config;
+
+    pci_set_word(pci_conf + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK |
+                 PCI_STATUS_DEVSEL_MEDIUM |
+                 PCI_STATUS_66MHZ);
+
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
+    pci_conf[PCI_MIN_GNT] = 0x40;
+    pci_conf[PCI_MAX_LAT] = 0x40;
+
+    sungem_reset_all(s, true);
+    memory_region_init(&s->sungem, OBJECT(s), "sungem", SUNGEM_MMIO_SIZE);
+
+    memory_region_init_io(&s->greg, OBJECT(s), &sungem_mmio_greg_ops, s,
+                          "sungem.greg", SUNGEM_MMIO_GREG_SIZE);
+    memory_region_add_subregion(&s->sungem, 0, &s->greg);
+
+    memory_region_init_io(&s->txdma, OBJECT(s), &sungem_mmio_txdma_ops, s,
+                          "sungem.txdma", SUNGEM_MMIO_TXDMA_SIZE);
+    memory_region_add_subregion(&s->sungem, 0x2000, &s->txdma);
+
+    memory_region_init_io(&s->rxdma, OBJECT(s), &sungem_mmio_rxdma_ops, s,
+                          "sungem.rxdma", SUNGEM_MMIO_RXDMA_SIZE);
+    memory_region_add_subregion(&s->sungem, 0x4000, &s->rxdma);
+
+    memory_region_init_io(&s->mac, OBJECT(s), &sungem_mmio_mac_ops, s,
+                          "sungem.mac", SUNGEM_MMIO_MAC_SIZE);
+    memory_region_add_subregion(&s->sungem, 0x6000, &s->mac);
+
+    memory_region_init_io(&s->mif, OBJECT(s), &sungem_mmio_mif_ops, s,
+                          "sungem.mif", SUNGEM_MMIO_MIF_SIZE);
+    memory_region_add_subregion(&s->sungem, 0x6200, &s->mif);
+
+    memory_region_init_io(&s->pcs, OBJECT(s), &sungem_mmio_pcs_ops, s,
+                          "sungem.pcs", SUNGEM_MMIO_PCS_SIZE);
+    memory_region_add_subregion(&s->sungem, 0x9000, &s->pcs);
+
+    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->sungem);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_sungem_info, &s->conf,
+                          object_get_typename(OBJECT(dev)),
+                          dev->id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic),
+                             s->conf.macaddr.a);
+}
+
+static void sungem_reset(DeviceState *dev)
+{
+    SunGEMState *s = SUNGEM(dev);
+
+    sungem_reset_all(s, true);
+}
+
+static void sungem_instance_init(Object *obj)
+{
+    SunGEMState *s = SUNGEM(obj);
+
+    device_add_bootindex_property(obj, &s->conf.bootindex,
+                                  "bootindex", "/ethernet-phy@0",
+                                  DEVICE(obj), NULL);
+}
+
+static Property sungem_properties[] = {
+    DEFINE_NIC_PROPERTIES(SunGEMState, conf),
+    /* Phy address should be 0 for most Apple machines except
+     * for K2 in which case it's 1. Will be set by a machine
+     * override.
+     */
+    DEFINE_PROP_UINT32("phy_addr", SunGEMState, phy_addr, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_sungem = {
+    .name = "sungem",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(pdev, SunGEMState),
+        VMSTATE_MACADDR(conf.macaddr, SunGEMState),
+        VMSTATE_UINT32(phy_addr, SunGEMState),
+        VMSTATE_UINT32_ARRAY(gregs, SunGEMState, (SUNGEM_MMIO_GREG_SIZE >> 2)),
+        VMSTATE_UINT32_ARRAY(txdmaregs, SunGEMState,
+                             (SUNGEM_MMIO_TXDMA_SIZE >> 2)),
+        VMSTATE_UINT32_ARRAY(rxdmaregs, SunGEMState,
+                             (SUNGEM_MMIO_RXDMA_SIZE >> 2)),
+        VMSTATE_UINT32_ARRAY(macregs, SunGEMState, (SUNGEM_MMIO_MAC_SIZE >> 2)),
+        VMSTATE_UINT32_ARRAY(mifregs, SunGEMState, (SUNGEM_MMIO_MIF_SIZE >> 2)),
+        VMSTATE_UINT32_ARRAY(pcsregs, SunGEMState, (SUNGEM_MMIO_PCS_SIZE >> 2)),
+        VMSTATE_UINT32(rx_mask, SunGEMState),
+        VMSTATE_UINT32(tx_mask, SunGEMState),
+        VMSTATE_UINT8_ARRAY(tx_data, SunGEMState, MAX_PACKET_SIZE),
+        VMSTATE_UINT32(tx_size, SunGEMState),
+        VMSTATE_UINT64(tx_first_ctl, SunGEMState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void sungem_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->realize = sungem_realize;
+    k->exit = sungem_uninit;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_GMAC;
+    k->revision = 0x01;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->vmsd = &vmstate_sungem;
+    dc->reset = sungem_reset;
+    dc->props = sungem_properties;
+    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
+}
+
+static const TypeInfo sungem_info = {
+    .name          = TYPE_SUNGEM,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(SunGEMState),
+    .class_init    = sungem_class_init,
+    .instance_init = sungem_instance_init,
+};
+
+static void sungem_register_types(void)
+{
+    type_register_static(&sungem_info);
+}
+
+type_init(sungem_register_types)
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 27e5482765..5f816ef58e 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -278,3 +278,47 @@ spapr_vlan_h_send_logical_lan(uint64_t reg, uint64_t continue_token) "H_SEND_LOG
 spapr_vlan_h_send_logical_lan_rxbufs(uint32_t rx_bufs) "rxbufs = %"PRIu32
 spapr_vlan_h_send_logical_lan_buf_desc(uint64_t buf) "   buf desc: 0x%"PRIx64
 spapr_vlan_h_send_logical_lan_total(int nbufs, unsigned total_len) "%d buffers, total length 0x%x"
+
+# hw/net/sungem.c
+sungem_tx_checksum(uint16_t start, uint16_t off) "TX checksumming from byte %d, inserting at %d"
+sungem_tx_checksum_oob(void) "TX checksum out of packet bounds"
+sungem_tx_unfinished(void) "TX packet started without finishing the previous one"
+sungem_tx_overflow(void) "TX packet queue overflow"
+sungem_tx_finished(uint32_t size) "TX completing %"PRIu32 " bytes packet"
+sungem_tx_kick(void) "TX Kick..."
+sungem_tx_disabled(void) "TX not enabled"
+sungem_tx_process(uint32_t comp, uint32_t kick, uint32_t size) "TX processing comp=%"PRIu32", kick=%"PRIu32" out of %"PRIu32
+sungem_tx_desc(uint32_t comp, uint64_t control, uint64_t buffer) "TX desc %"PRIu32 ": 0x%"PRIx64" 0x%"PRIx64
+sungem_tx_reset(void) "TX reset"
+sungem_rx_mac_disabled(void) "Check RX MAC disabled"
+sungem_rx_txdma_disabled(void) "Check RX TXDMA disabled"
+sungem_rx_check(bool full, uint32_t kick, uint32_t done) "Check RX %d (kick=%"PRIu32", done=%"PRIu32")"
+sungem_rx_mac_check(uint32_t mac0, uint32_t mac1, uint32_t mac2) "Word MAC: 0x%"PRIx32" 0x%"PRIx32" 0x%"PRIx32
+sungem_rx_mac_multicast(void) "Multicast"
+sungem_rx_mac_compare(uint32_t mac0, uint32_t mac1, uint32_t mac2) "Compare MAC to 0x%"PRIx32" 0x%"PRIx32" 0x%"PRIx32".."
+sungem_rx_packet(size_t size) "RX got %zu bytes packet"
+sungem_rx_disabled(void) "RX not enabled"
+sungem_rx_bad_frame_size(size_t size) "RX bad frame size %zu, dropped"
+sungem_rx_unmatched(void) "No match, dropped"
+sungem_rx_process(uint32_t done, uint32_t kick, uint32_t size) "RX processing done=%"PRIu32", kick=%"PRIu32" out of %"PRIu32
+sungem_rx_ringfull(void) "RX ring full"
+sungem_rx_desc(uint64_t control, uint64_t buffer) "RX desc: 0x%"PRIx64" 0x%"PRIx64
+sungem_rx_reset(void) "RX reset"
+sungem_rx_kick(uint64_t val) "RXDMA_KICK written to %"PRIu64
+sungem_reset(bool pci_reset) "Full reset (PCI:%d)"
+sungem_mii_write(uint8_t phy_addr, uint8_t reg_addr, uint16_t val) "MII write addr 0x%x reg 0x%02x val 0x%04x"
+sungem_mii_read(uint8_t phy_addr, uint8_t reg_addr, uint16_t val) "MII read addr 0x%x reg 0x%02x val 0x%04x"
+sungem_mii_invalid_sof(uint32_t val) "MII op, invalid SOF field 0x%"PRIx32
+sungem_mii_invalid_op(uint8_t op) "MII op, invalid op field 0x%x"
+sungem_mmio_greg_write(uint64_t addr, uint64_t val) "MMIO greg write to 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_greg_read(uint64_t addr, uint64_t val) "MMIO greg read from 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_txdma_write(uint64_t addr, uint64_t val) "MMIO txdma write to 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_txdma_read(uint64_t addr, uint64_t val) "MMIO txdma read from 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_rxdma_write(uint64_t addr, uint64_t val) "MMIO rxdma write to 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_rxdma_read(uint64_t addr, uint64_t val) "MMIO rxdma read from 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_mac_write(uint64_t addr, uint64_t val) "MMIO mac write to 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_mac_read(uint64_t addr, uint64_t val) "MMIO mac read from 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_mif_write(uint64_t addr, uint64_t val) "MMIO mif write to 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_mif_read(uint64_t addr, uint64_t val) "MMIO mif read from 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_pcs_write(uint64_t addr, uint64_t val) "MMIO pcs write to 0x%"PRIx64" val=0x%"PRIx64
+sungem_mmio_pcs_read(uint64_t addr, uint64_t val) "MMIO pcs read from 0x%"PRIx64" val=0x%"PRIx64
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 21e203b056..1e6fb88eba 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1821,6 +1821,7 @@ static const char * const pci_nic_models[] = {
     "e1000",
     "pcnet",
     "virtio",
+    "sungem",
     NULL
 };
 
@@ -1833,6 +1834,7 @@ static const char * const pci_nic_names[] = {
     "e1000",
     "pcnet",
     "virtio-net-pci",
+    "sungem",
     NULL
 };
 
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
index 3752ddc93a..b9c2bad851 100644
--- a/include/hw/pci/pci_ids.h
+++ b/include/hw/pci/pci_ids.h
@@ -183,6 +183,7 @@
 #define PCI_VENDOR_ID_APPLE              0x106b
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP    0x0020
 #define PCI_DEVICE_ID_APPLE_U3_AGP       0x004b
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC   0x0021
 
 #define PCI_VENDOR_ID_SUN                0x108e
 #define PCI_DEVICE_ID_SUN_EBUS           0x1000
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 02/18] hw/ppc/spapr.c: cleaning up qdev_get_machine() calls
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 01/18] net: Add SunGEM device emulation as found on Apple UniNorth David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 03/18] spapr_pci: drop useless check in spapr_phb_vfio_get_loc_code() David Gibson
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Daniel Henrique Barboza,
	David Gibson

From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>

This patch removes the qdev_get_machine() calls that are made in
spapr.c in situations where we can get an existing pointer for
the MachineState by either passing it as an argument to the function
or by using other already available pointers.

The following changes were made:

- spapr_node0_size: static function that is called two times:
at spapr_setup_hpt_and_vrma and ppc_spapr_init. In both cases we can
pass an existing MachineState pointer to it.

- spapr_build_fdt: MachineState pointer can be retrieved from
the existing sPAPRMachineState pointer.

- spapr_boot_set: the opaque in the first arg is a sPAPRMachineState
pointer as we can see inside ppc_spapr_init:

    qemu_register_boot_set(spapr_boot_set, spapr);

We can get a MachineState pointer from it.

- spapr_machine_device_plug and spapr_machine_device_unplug_request: the
MachineState, sPAPRMachineState, MachineClass and sPAPRMachineClass pointers
can all be retrieved from the HotplugHandler pointer.

Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index caffa12763..06a008b43c 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -391,10 +391,8 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
     return ret;
 }
 
-static hwaddr spapr_node0_size(void)
+static hwaddr spapr_node0_size(MachineState *machine)
 {
-    MachineState *machine = MACHINE(qdev_get_machine());
-
     if (nb_numa_nodes) {
         int i;
         for (i = 0; i < nb_numa_nodes; ++i) {
@@ -1052,7 +1050,7 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
                              hwaddr rtas_addr,
                              hwaddr rtas_size)
 {
-    MachineState *machine = MACHINE(qdev_get_machine());
+    MachineState *machine = MACHINE(spapr);
     MachineClass *mc = MACHINE_GET_CLASS(machine);
     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
     int ret;
@@ -1372,7 +1370,7 @@ void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr)
     spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal);
 
     if (spapr->vrma_adjust) {
-        spapr->rma_size = kvmppc_rma_size(spapr_node0_size(),
+        spapr->rma_size = kvmppc_rma_size(spapr_node0_size(MACHINE(spapr)),
                                           spapr->htab_shift);
     }
     /* We're setting up a hash table, so that means we're not radix */
@@ -2033,7 +2031,7 @@ static SaveVMHandlers savevm_htab_handlers = {
 static void spapr_boot_set(void *opaque, const char *boot_device,
                            Error **errp)
 {
-    MachineState *machine = MACHINE(qdev_get_machine());
+    MachineState *machine = MACHINE(opaque);
     machine->boot_order = g_strdup(boot_device);
 }
 
@@ -2235,7 +2233,7 @@ static void ppc_spapr_init(MachineState *machine)
     MemoryRegion *rma_region;
     void *rma = NULL;
     hwaddr rma_alloc_size;
-    hwaddr node0_size = spapr_node0_size();
+    hwaddr node0_size = spapr_node0_size(machine);
     long load_limit, fw_size;
     char *filename;
     Error *resize_hpt_err = NULL;
@@ -3298,7 +3296,8 @@ out:
 static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
                                       DeviceState *dev, Error **errp)
 {
-    sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(qdev_get_machine());
+    MachineState *ms = MACHINE(hotplug_dev);
+    sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(ms);
 
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
         int node;
@@ -3347,8 +3346,8 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
 static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
                                                 DeviceState *dev, Error **errp)
 {
-    sPAPRMachineState *sms = SPAPR_MACHINE(qdev_get_machine());
-    MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
+    sPAPRMachineState *sms = SPAPR_MACHINE(OBJECT(hotplug_dev));
+    MachineClass *mc = MACHINE_GET_CLASS(sms);
 
     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
         if (spapr_ovec_test(sms->ov5_cas, OV5_HP_EVT)) {
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 03/18] spapr_pci: drop useless check in spapr_phb_vfio_get_loc_code()
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 01/18] net: Add SunGEM device emulation as found on Apple UniNorth David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 02/18] hw/ppc/spapr.c: cleaning up qdev_get_machine() calls David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 04/18] spapr_pci: drop useless check in spapr_populate_pci_child_dt() David Gibson
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

g_strdup_printf() either returns a non-null pointer, or aborts if it
failed to allocate memory.

Signed-off-by: Greg Kurz <groug@kaod.org>
[dwg: Grammatical fix to commit message]
Acked-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_pci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index d7880f257a..ef982f2ef3 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -766,7 +766,7 @@ static char *spapr_phb_vfio_get_loc_code(sPAPRPHBState *sphb,  PCIDevice *pdev)
     /* Construct the path of the file that will give us the DT location */
     path = g_strdup_printf("/sys/bus/pci/devices/%s/devspec", host);
     g_free(host);
-    if (!path || !g_file_get_contents(path, &buf, NULL, NULL)) {
+    if (!g_file_get_contents(path, &buf, NULL, NULL)) {
         goto err_out;
     }
     g_free(path);
@@ -774,7 +774,7 @@ static char *spapr_phb_vfio_get_loc_code(sPAPRPHBState *sphb,  PCIDevice *pdev)
     /* Construct and read from host device tree the loc-code */
     path = g_strdup_printf("/proc/device-tree%s/ibm,loc-code", buf);
     g_free(buf);
-    if (!path || !g_file_get_contents(path, &buf, NULL, NULL)) {
+    if (!g_file_get_contents(path, &buf, NULL, NULL)) {
         goto err_out;
     }
     return buf;
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 04/18] spapr_pci: drop useless check in spapr_populate_pci_child_dt()
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (2 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 03/18] spapr_pci: drop useless check in spapr_phb_vfio_get_loc_code() David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 05/18] spapr_pci: use g_strdup_printf() David Gibson
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

spapr_phb_get_loc_code() either returns a non-null pointer, or aborts
if g_strdup_printf() failed to allocate memory.

Signed-off-by: Greg Kurz <groug@kaod.org>
[dwg: Grammatical fix to commit message]
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_pci.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index ef982f2ef3..cd8efb1812 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1282,12 +1282,8 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
                             pci_find_device_name((ccode >> 16) & 0xff,
                                                  (ccode >> 8) & 0xff,
                                                  ccode & 0xff)));
-    buf = spapr_phb_get_loc_code(sphb, dev);
-    if (!buf) {
-        error_report("Failed setting the ibm,loc-code");
-        return -1;
-    }
 
+    buf = spapr_phb_get_loc_code(sphb, dev);
     err = fdt_setprop_string(fdt, offset, "ibm,loc-code", buf);
     g_free(buf);
     if (err < 0) {
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 05/18] spapr_pci: use g_strdup_printf()
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (3 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 04/18] spapr_pci: drop useless check in spapr_populate_pci_child_dt() David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 06/18] spapr: only update SDR1 once per-cpu during CAS David Gibson
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

Building strings with g_strdup_printf() instead of snprintf() is
a QEMU common practice.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_pci.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index cd8efb1812..6da73fe6bc 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -61,8 +61,6 @@
 #define RTAS_TYPE_MSI           1
 #define RTAS_TYPE_MSIX          2
 
-#define FDT_NAME_MAX          128
-
 #define _FDT(exp) \
     do { \
         int ret = (exp);                                           \
@@ -1194,7 +1192,7 @@ static const char *pci_find_device_name(uint8_t class, uint8_t subclass,
     return name;
 }
 
-static void pci_get_node_name(char *nodename, int len, PCIDevice *dev)
+static gchar *pci_get_node_name(PCIDevice *dev)
 {
     int slot = PCI_SLOT(dev->devfn);
     int func = PCI_FUNC(dev->devfn);
@@ -1205,9 +1203,9 @@ static void pci_get_node_name(char *nodename, int len, PCIDevice *dev)
                                 ccode & 0xff);
 
     if (func != 0) {
-        snprintf(nodename, len, "%s@%x,%x", name, slot, func);
+        return g_strdup_printf("%s@%x,%x", name, slot, func);
     } else {
-        snprintf(nodename, len, "%s@%x", name, slot);
+        return g_strdup_printf("%s@%x", name, slot);
     }
 }
 
@@ -1325,10 +1323,12 @@ static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev,
                                      void *fdt, int node_offset)
 {
     int offset, ret;
-    char nodename[FDT_NAME_MAX];
+    gchar *nodename;
 
-    pci_get_node_name(nodename, FDT_NAME_MAX, dev);
+    nodename = pci_get_node_name(dev);
     offset = fdt_add_subnode(fdt, node_offset, nodename);
+    g_free(nodename);
+
     ret = spapr_populate_pci_child_dt(dev, fdt, offset, phb);
 
     g_assert(!ret);
@@ -2072,7 +2072,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
                           void *fdt)
 {
     int bus_off, i, j, ret;
-    char nodename[FDT_NAME_MAX];
+    gchar *nodename;
     uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
     struct {
         uint32_t hi;
@@ -2121,8 +2121,9 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
     sPAPRFDT s_fdt;
 
     /* Start populating the FDT */
-    snprintf(nodename, FDT_NAME_MAX, "pci@%" PRIx64, phb->buid);
+    nodename = g_strdup_printf("pci@%" PRIx64, phb->buid);
     bus_off = fdt_add_subnode(fdt, 0, nodename);
+    g_free(nodename);
     if (bus_off < 0) {
         return bus_off;
     }
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 06/18] spapr: only update SDR1 once per-cpu during CAS
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (4 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 05/18] spapr_pci: use g_strdup_printf() David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 07/18] ppc/xive: fix OV5_XIVE_EXPLOIT bits David Gibson
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

Commit b55d295e3ec9 added the possibility to support HPT resizing with KVM.
In the case of PR, we need to pass the userspace address of the HPT to KVM
using the SDR1 slot.
This is handled by kvmppc_update_sdr1() which uses CPU_FOREACH() to update
all CPUs. It is hence not needed to call kvmppc_update_sdr1() for each CPU.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_hcall.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 8b3c0e17e7..6ab8c188f3 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1559,20 +1559,16 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
         }
 
         if (spapr->htab_shift < maxshift) {
-            CPUState *cs;
-
             /* Guest doesn't know about HPT resizing, so we
              * pre-emptively resize for the maximum permitted RAM.  At
              * the point this is called, nothing should have been
              * entered into the existing HPT */
             spapr_reallocate_hpt(spapr, maxshift, &error_fatal);
-            CPU_FOREACH(cs) {
-                if (kvm_enabled()) {
-                    /* For KVM PR, update the HPT pointer */
-                    target_ulong sdr1 = (target_ulong)(uintptr_t)spapr->htab
-                        | (spapr->htab_shift - 18);
-                    kvmppc_update_sdr1(sdr1);
-                }
+            if (kvm_enabled()) {
+                /* For KVM PR, update the HPT pointer */
+                target_ulong sdr1 = (target_ulong)(uintptr_t)spapr->htab
+                    | (spapr->htab_shift - 18);
+                kvmppc_update_sdr1(sdr1);
             }
         }
     }
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 07/18] ppc/xive: fix OV5_XIVE_EXPLOIT bits
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (5 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 06/18] spapr: only update SDR1 once per-cpu during CAS David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 08/18] spapr: fix CAS-generated reset David Gibson
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Cédric Le Goater,
	David Gibson

From: Cédric Le Goater <clg@kaod.org>

On POWER9, the Client Architecture Support (CAS) negotiation process
determines whether the guest operates in XIVE Legacy compatibility or
in XIVE exploitation mode. Now that we have initial guest support for
the XIVE interrupt controller, let's fix the bits definition which have
evolved in the latest specs.

The platform advertises the XIVE Exploitation Mode support using the
property "ibm,arch-vec-5-platform-support-vec-5", byte 23 bits 0-1 :

 - 0b00 XIVE legacy mode Only
 - 0b01 XIVE exploitation mode Only
 - 0b10 XIVE legacy or exploitation mode

The OS asks for XIVE Exploitation Mode support using the property
"ibm,architecture-vec-5", byte 23 bits 0-1:

 - 0b00 XIVE legacy mode Only
 - 0b01 XIVE exploitation mode Only

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr.c              | 2 +-
 include/hw/ppc/spapr_ovec.h | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 06a008b43c..f680f28a15 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -937,7 +937,7 @@ static void spapr_dt_ov5_platform_support(void *fdt, int chosen)
     PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
 
     char val[2 * 4] = {
-        23, 0x00, /* Xive mode: 0 = legacy (as in ISA 2.7), 1 = Exploitation */
+        23, 0x00, /* Xive mode, filled in below. */
         24, 0x00, /* Hash/Radix, filled in below. */
         25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
         26, 0x40, /* Radix options: GTSE == yes. */
diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h
index 9edfa5ff75..bf25e5d954 100644
--- a/include/hw/ppc/spapr_ovec.h
+++ b/include/hw/ppc/spapr_ovec.h
@@ -51,7 +51,8 @@ typedef struct sPAPROptionVector sPAPROptionVector;
 #define OV5_FORM1_AFFINITY      OV_BIT(5, 0)
 #define OV5_HP_EVT              OV_BIT(6, 5)
 #define OV5_HPT_RESIZE          OV_BIT(6, 7)
-#define OV5_XIVE_EXPLOIT        OV_BIT(23, 7)
+#define OV5_XIVE_BOTH           OV_BIT(23, 0)
+#define OV5_XIVE_EXPLOIT        OV_BIT(23, 1) /* 1=exploitation 0=legacy */
 
 /* ISA 3.00 MMU features: */
 #define OV5_MMU_BOTH            OV_BIT(24, 0) /* Radix and hash */
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 08/18] spapr: fix CAS-generated reset
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (6 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 07/18] ppc/xive: fix OV5_XIVE_EXPLOIT bits David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 09/18] spapr_pci: use the common _FDT() helper David Gibson
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Cédric Le Goater,
	David Gibson

From: Cédric Le Goater <clg@kaod.org>

The OV5_MMU_RADIX_300 requires special handling in the CAS negotiation
process. It is cleared from the option vector of the guest before
evaluating the changes and re-added later. But, when testing for a
possible CAS reset :

    spapr->cas_reboot = spapr_ovec_diff(ov5_updates,
                                        ov5_cas_old, spapr->ov5_cas);

the bit OV5_MMU_RADIX_300 will each time be seen as removed from the
previous OV5 set, hence generating a reset loop.

Fix this problem by also clearing the same bit in the ov5_cas_old set.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_hcall.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 6ab8c188f3..57bb411394 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1581,6 +1581,13 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
      * to worry about this for now.
      */
     ov5_cas_old = spapr_ovec_clone(spapr->ov5_cas);
+
+    /* also clear the radix/hash bit from the current ov5_cas bits to
+     * be in sync with the newly ov5 bits. Else the radix bit will be
+     * seen as being removed and this will generate a reset loop
+     */
+    spapr_ovec_clear(ov5_cas_old, OV5_MMU_RADIX_300);
+
     /* full range of negotiated ov5 capabilities */
     spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest);
     spapr_ovec_cleanup(ov5_guest);
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 09/18] spapr_pci: use the common _FDT() helper
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (7 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 08/18] spapr: fix CAS-generated reset David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 10/18] spapr_pci: handle FDT creation errors with _FDT() David Gibson
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

All other users in hw/ppc already consider an error when building
the FDT to be fatal, even on hotplug paths. There's no valid reason
for spapr_pci to behave differently. So let's used the common _FDT()
helper which terminates QEMU when libfdt fails.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_pci.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 6da73fe6bc..abb9f05e7b 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -40,7 +40,7 @@
 #include "trace.h"
 #include "qemu/error-report.h"
 #include "qapi/qmp/qerror.h"
-
+#include "hw/ppc/fdt.h"
 #include "hw/pci/pci_bridge.h"
 #include "hw/pci/pci_bus.h"
 #include "hw/pci/pci_ids.h"
@@ -61,14 +61,6 @@
 #define RTAS_TYPE_MSI           1
 #define RTAS_TYPE_MSIX          2
 
-#define _FDT(exp) \
-    do { \
-        int ret = (exp);                                           \
-        if (ret < 0) {                                             \
-            return ret;                                            \
-        }                                                          \
-    } while (0)
-
 sPAPRPHBState *spapr_pci_find_phb(sPAPRMachineState *spapr, uint64_t buid)
 {
     sPAPRPHBState *sphb;
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 10/18] spapr_pci: handle FDT creation errors with _FDT()
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (8 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 09/18] spapr_pci: use the common _FDT() helper David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 11/18] vfio, spapr: Fix levels calculation David Gibson
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

libfdt failures when creating the FDT should cause QEMU to terminate.

Let's use the _FDT() macro which does just that instead of propagating
the error to the caller. spapr_populate_pci_child_dt() no longer needs
to return a value in this case.

Note that, on the way, this get rids of the following nonsensical lines:

    g_assert(!ret);
    if (ret) {

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_pci.c | 30 +++++++-----------------------
 1 file changed, 7 insertions(+), 23 deletions(-)

diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index abb9f05e7b..75cd939223 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1204,12 +1204,12 @@ static gchar *pci_get_node_name(PCIDevice *dev)
 static uint32_t spapr_phb_get_pci_drc_index(sPAPRPHBState *phb,
                                             PCIDevice *pdev);
 
-static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
+static void spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
                                        sPAPRPHBState *sphb)
 {
     ResourceProps rp;
     bool is_bridge = false;
-    int pci_status, err;
+    int pci_status;
     char *buf = NULL;
     uint32_t drc_index = spapr_phb_get_pci_drc_index(sphb, dev);
     uint32_t ccode = pci_default_read_config(dev, PCI_CLASS_PROG, 3);
@@ -1274,11 +1274,8 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
                                                  ccode & 0xff)));
 
     buf = spapr_phb_get_loc_code(sphb, dev);
-    err = fdt_setprop_string(fdt, offset, "ibm,loc-code", buf);
+    _FDT(fdt_setprop_string(fdt, offset, "ibm,loc-code", buf));
     g_free(buf);
-    if (err < 0) {
-        return err;
-    }
 
     if (drc_index) {
         _FDT(fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index));
@@ -1306,27 +1303,21 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
     if (sphb->pcie_ecs && pci_is_express(dev)) {
         _FDT(fdt_setprop_cell(fdt, offset, "ibm,pci-config-space-type", 0x1));
     }
-
-    return 0;
 }
 
 /* create OF node for pci device and required OF DT properties */
 static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev,
                                      void *fdt, int node_offset)
 {
-    int offset, ret;
+    int offset;
     gchar *nodename;
 
     nodename = pci_get_node_name(dev);
-    offset = fdt_add_subnode(fdt, node_offset, nodename);
+    _FDT(offset = fdt_add_subnode(fdt, node_offset, nodename));
     g_free(nodename);
 
-    ret = spapr_populate_pci_child_dt(dev, fdt, offset, phb);
+    spapr_populate_pci_child_dt(dev, fdt, offset, phb);
 
-    g_assert(!ret);
-    if (ret) {
-        return 0;
-    }
     return offset;
 }
 
@@ -1416,10 +1407,6 @@ static void spapr_pci_plug(HotplugHandler *plug_handler,
 
     fdt = create_device_tree(&fdt_size);
     fdt_start_offset = spapr_create_pci_child_dt(phb, pdev, fdt, 0);
-    if (!fdt_start_offset) {
-        error_setg(&local_err, "Failed to create pci child device tree node");
-        goto out;
-    }
 
     spapr_drc_attach(drc, DEVICE(pdev), fdt, fdt_start_offset, &local_err);
     if (local_err) {
@@ -2114,11 +2101,8 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
 
     /* Start populating the FDT */
     nodename = g_strdup_printf("pci@%" PRIx64, phb->buid);
-    bus_off = fdt_add_subnode(fdt, 0, nodename);
+    _FDT(bus_off = fdt_add_subnode(fdt, 0, nodename));
     g_free(nodename);
-    if (bus_off < 0) {
-        return bus_off;
-    }
 
     /* Write PHB properties */
     _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 11/18] vfio, spapr: Fix levels calculation
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (9 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 10/18] spapr_pci: handle FDT creation errors with _FDT() David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 12/18] xics: fix several error leaks David Gibson
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell; +Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, David Gibson

From: Alexey Kardashevskiy <aik@ozlabs.ru>

The existing tries to round up the number of pages but @pages is always
calculated as the rounded up value minus one  which makes ctz64() always
return 0 and have create.levels always set 1.

This removes wrong "-1" and allows having more than 1 levels. This becomes
handy for >128GB guests with standard 64K pages as this requires blocks
with zone order 9 and the popular limit of CONFIG_FORCE_MAX_ZONEORDER=9
means that only blocks up to order 8 are allowed.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/vfio/spapr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c
index 32fd6a9b54..259397c002 100644
--- a/hw/vfio/spapr.c
+++ b/hw/vfio/spapr.c
@@ -163,7 +163,7 @@ int vfio_spapr_create_window(VFIOContainer *container,
      */
     entries = create.window_size >> create.page_shift;
     pages = MAX((entries * sizeof(uint64_t)) / getpagesize(), 1);
-    pages = MAX(pow2ceil(pages) - 1, 1); /* Round up */
+    pages = MAX(pow2ceil(pages), 1); /* Round up */
     create.levels = ctz64(pages) / 6 + 1;
 
     ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create);
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 12/18] xics: fix several error leaks
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (10 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 11/18] vfio, spapr: Fix levels calculation David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 13/18] spapr_cpu_core: fail gracefully with non-pseries machine types David Gibson
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

If object_property_get_link() fails then it allocates an error, which
must be freed before returning. The error_get_pretty() function is
merely an accessor to the error message and doesn't free anything.

The error.h header indicates how to do it right:

 * Pass an existing error to the caller with the message modified:
 *     error_propagate(errp, err);
 *     error_prepend(errp, "Could not frobnicate '%s': ", name);

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/intc/xics.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index a84ba51ad8..80c33be02e 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -306,8 +306,8 @@ static void icp_realize(DeviceState *dev, Error **errp)
 
     obj = object_property_get_link(OBJECT(dev), ICP_PROP_XICS, &err);
     if (!obj) {
-        error_setg(errp, "%s: required link '" ICP_PROP_XICS "' not found: %s",
-                   __func__, error_get_pretty(err));
+        error_propagate(errp, err);
+        error_prepend(errp, "required link '" ICP_PROP_XICS "' not found: ");
         return;
     }
 
@@ -315,8 +315,8 @@ static void icp_realize(DeviceState *dev, Error **errp)
 
     obj = object_property_get_link(OBJECT(dev), ICP_PROP_CPU, &err);
     if (!obj) {
-        error_setg(errp, "%s: required link '" ICP_PROP_CPU "' not found: %s",
-                   __func__, error_get_pretty(err));
+        error_propagate(errp, err);
+        error_prepend(errp, "required link '" ICP_PROP_CPU "' not found: ");
         return;
     }
 
@@ -641,8 +641,8 @@ static void ics_base_realize(DeviceState *dev, Error **errp)
 
     obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err);
     if (!obj) {
-        error_setg(errp, "%s: required link '" ICS_PROP_XICS "' not found: %s",
-                   __func__, error_get_pretty(err));
+        error_propagate(errp, err);
+        error_prepend(errp, "required link '" ICS_PROP_XICS "' not found: ");
         return;
     }
     ics->xics = XICS_FABRIC(obj);
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 13/18] spapr_cpu_core: fail gracefully with non-pseries machine types
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (11 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 12/18] xics: fix several error leaks David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 14/18] spapr_pci: convert sprintf() to g_strdup_printf() David Gibson
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

Since commit 7cca3e466eb0 ("ppc: spapr: Move VCPU ID calculation into
sPAPR"), QEMU aborts when started with a *-spapr-cpu-core device and
a non-pseries machine.

Let's rely on the already existing call to object_dynamic_cast() instead
of using the SPAPR_MACHINE() macro.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_cpu_core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 85037ef71e..3f7ef20910 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -213,7 +213,7 @@ error:
 
 static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
 {
-    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+    sPAPRMachineState *spapr;
     sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
     sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev));
     CPUCore *cc = CPU_CORE(OBJECT(dev));
@@ -223,7 +223,8 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
     void *obj;
     int i, j;
 
-    if (!object_dynamic_cast(qdev_get_machine(), TYPE_SPAPR_MACHINE)) {
+    spapr = (sPAPRMachineState *) qdev_get_machine();
+    if (!object_dynamic_cast((Object *) spapr, TYPE_SPAPR_MACHINE)) {
         error_setg(errp, "spapr-cpu-core needs a pseries machine");
         return;
     }
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 14/18] spapr_pci: convert sprintf() to g_strdup_printf()
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (12 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 13/18] spapr_cpu_core: fail gracefully with non-pseries machine types David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 15/18] spapr_pci: don't create 64-bit MMIO window if we don't need to David Gibson
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

In order to follow a QEMU common practice.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_pci.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 75cd939223..7d84b9766e 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1609,34 +1609,37 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
 
     sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid);
 
-    namebuf = alloca(strlen(sphb->dtbusname) + 32);
-
     /* Initialize memory regions */
-    sprintf(namebuf, "%s.mmio", sphb->dtbusname);
+    namebuf = g_strdup_printf("%s.mmio", sphb->dtbusname);
     memory_region_init(&sphb->memspace, OBJECT(sphb), namebuf, UINT64_MAX);
+    g_free(namebuf);
 
-    sprintf(namebuf, "%s.mmio32-alias", sphb->dtbusname);
+    namebuf = g_strdup_printf("%s.mmio32-alias", sphb->dtbusname);
     memory_region_init_alias(&sphb->mem32window, OBJECT(sphb),
                              namebuf, &sphb->memspace,
                              SPAPR_PCI_MEM_WIN_BUS_OFFSET, sphb->mem_win_size);
+    g_free(namebuf);
     memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
                                 &sphb->mem32window);
 
-    sprintf(namebuf, "%s.mmio64-alias", sphb->dtbusname);
+    namebuf = g_strdup_printf("%s.mmio64-alias", sphb->dtbusname);
     memory_region_init_alias(&sphb->mem64window, OBJECT(sphb),
                              namebuf, &sphb->memspace,
                              sphb->mem64_win_pciaddr, sphb->mem64_win_size);
+    g_free(namebuf);
     memory_region_add_subregion(get_system_memory(), sphb->mem64_win_addr,
                                 &sphb->mem64window);
 
     /* Initialize IO regions */
-    sprintf(namebuf, "%s.io", sphb->dtbusname);
+    namebuf = g_strdup_printf("%s.io", sphb->dtbusname);
     memory_region_init(&sphb->iospace, OBJECT(sphb),
                        namebuf, SPAPR_PCI_IO_WIN_SIZE);
+    g_free(namebuf);
 
-    sprintf(namebuf, "%s.io-alias", sphb->dtbusname);
+    namebuf = g_strdup_printf("%s.io-alias", sphb->dtbusname);
     memory_region_init_alias(&sphb->iowindow, OBJECT(sphb), namebuf,
                              &sphb->iospace, 0, SPAPR_PCI_IO_WIN_SIZE);
+    g_free(namebuf);
     memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
                                 &sphb->iowindow);
 
@@ -1654,10 +1657,10 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
      * Later the guest might want to create another DMA window
      * which will become another memory subregion.
      */
-    sprintf(namebuf, "%s.iommu-root", sphb->dtbusname);
-
+    namebuf = g_strdup_printf("%s.iommu-root", sphb->dtbusname);
     memory_region_init(&sphb->iommu_root, OBJECT(sphb),
                        namebuf, UINT64_MAX);
+    g_free(namebuf);
     address_space_init(&sphb->iommu_as, &sphb->iommu_root,
                        sphb->dtbusname);
 
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 15/18] spapr_pci: don't create 64-bit MMIO window if we don't need to
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (13 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 14/18] spapr_pci: convert sprintf() to g_strdup_printf() David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 16/18] spapr_cpu_core: cleaning up qdev_get_machine() calls David Gibson
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

When running a pseries-2.2 or older machine type, we get the following
lines in info mtree:

address-space: memory
...
ffffffffffffffff-ffffffffffffffff (prio 0, i/o): alias
 pci@800000020000000.mmio64-alias @pci@800000020000000.mmio
  ffffffffffffffff-ffffffffffffffff

address-space: cpu-memory
...
ffffffffffffffff-ffffffffffffffff (prio 0, i/o): alias
 pci@800000020000000.mmio64-alias @pci@800000020000000.mmio
  ffffffffffffffff-ffffffffffffffff

The same thing occurs when running a pseries-2.7 with

    -global spapr-pci-host-bridge.mem_win_size=2147483648

This happens because we always create a 64-bit MMIO window, even if
we didn't explicitely requested it (ie, mem64_win_size == 0) and the
32-bit window is below 2GiB. It doesn't seem to have an impact on the
guest though because spapr_populate_pci_dt() doesn't advertise the
bogus windows when mem64_win_size == 0.

Since these memory regions don't induce any state, we can safely
choose to not create them when their address is equal to -1,
without breaking migration from existing setups.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_pci.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 7d84b9766e..cf54160526 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1622,13 +1622,19 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
     memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
                                 &sphb->mem32window);
 
-    namebuf = g_strdup_printf("%s.mmio64-alias", sphb->dtbusname);
-    memory_region_init_alias(&sphb->mem64window, OBJECT(sphb),
-                             namebuf, &sphb->memspace,
-                             sphb->mem64_win_pciaddr, sphb->mem64_win_size);
-    g_free(namebuf);
-    memory_region_add_subregion(get_system_memory(), sphb->mem64_win_addr,
-                                &sphb->mem64window);
+    if (sphb->mem64_win_pciaddr != (hwaddr)-1) {
+        namebuf = g_strdup_printf("%s.mmio64-alias", sphb->dtbusname);
+        memory_region_init_alias(&sphb->mem64window, OBJECT(sphb),
+                                 namebuf, &sphb->memspace,
+                                 sphb->mem64_win_pciaddr, sphb->mem64_win_size);
+        g_free(namebuf);
+
+        if (sphb->mem64_win_addr != (hwaddr)-1) {
+            memory_region_add_subregion(get_system_memory(),
+                                        sphb->mem64_win_addr,
+                                        &sphb->mem64window);
+        }
+    }
 
     /* Initialize IO regions */
     namebuf = g_strdup_printf("%s.io", sphb->dtbusname);
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 16/18] spapr_cpu_core: cleaning up qdev_get_machine() calls
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (14 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 15/18] spapr_pci: don't create 64-bit MMIO window if we don't need to David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 17/18] spapr_events: use QTAILQ_FOREACH_SAFE() in spapr_clear_pending_events() David Gibson
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

This patch removes the qdev_get_machine() calls that are made
in spapr_cpu_core.c in situations where we can get an existing
pointer for the MachineState by either passing it as an argument
to the function or by using other already available pointers.

Credits to Daniel Henrique Barboza for the idea and the changelog
text.

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_cpu_core.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 3f7ef20910..c08ee7571a 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -174,10 +174,10 @@ static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp)
     g_free(sc->threads);
 }
 
-static void spapr_cpu_core_realize_child(Object *child, Error **errp)
+static void spapr_cpu_core_realize_child(Object *child,
+                                         sPAPRMachineState *spapr, Error **errp)
 {
     Error *local_err = NULL;
-    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
     CPUState *cs = CPU(child);
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     Object *obj;
@@ -266,7 +266,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
     for (j = 0; j < cc->nr_threads; j++) {
         obj = sc->threads + j * size;
 
-        spapr_cpu_core_realize_child(obj, &local_err);
+        spapr_cpu_core_realize_child(obj, spapr, &local_err);
         if (local_err) {
             goto err;
         }
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 17/18] spapr_events: use QTAILQ_FOREACH_SAFE() in spapr_clear_pending_events()
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (15 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 16/18] spapr_cpu_core: cleaning up qdev_get_machine() calls David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  3:51 ` [Qemu-devel] [PULL 18/18] ppc/kvm: use kvm_vm_check_extension() in kvmppc_is_pr() David Gibson
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

QTAILQ_FOREACH_SAFE() must be used when removing the current element
inside the loop block.

This fixes a user-after-free error introduced by commit 56258174238eb
and reported by Coverity (CID 1381017).

Signed-off-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/ppc/spapr_events.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index 66b8164f30..e377fc7dde 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -702,9 +702,9 @@ static void event_scan(PowerPCCPU *cpu, sPAPRMachineState *spapr,
 
 void spapr_clear_pending_events(sPAPRMachineState *spapr)
 {
-    sPAPREventLogEntry *entry = NULL;
+    sPAPREventLogEntry *entry = NULL, *next_entry;
 
-    QTAILQ_FOREACH(entry, &spapr->pending_events, next) {
+    QTAILQ_FOREACH_SAFE(entry, &spapr->pending_events, next, next_entry) {
         QTAILQ_REMOVE(&spapr->pending_events, entry, next);
         g_free(entry->extended_log);
         g_free(entry);
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [Qemu-devel] [PULL 18/18] ppc/kvm: use kvm_vm_check_extension() in kvmppc_is_pr()
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (16 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 17/18] spapr_events: use QTAILQ_FOREACH_SAFE() in spapr_clear_pending_events() David Gibson
@ 2017-09-15  3:51 ` David Gibson
  2017-09-15  4:26 ` [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 no-reply
  2017-09-15 19:28 ` Peter Maydell
  19 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  3:51 UTC (permalink / raw)
  To: peter.maydell
  Cc: agraf, gkurz, qemu-devel, qemu-ppc, aik, Greg Kurz, David Gibson

From: Greg Kurz <groug@kaod.org>

If the host has both KVM PR and KVM HV loaded and we pass:

	-machine pseries,accel=kvm,kvm-type=PR

the kvmppc_is_pr() returns false instead of true. Since the helper
is mostly used as fallback, it doesn't have any real impact with
recent kernels. A notable exception is the workaround to allow
migration between compatible hosts with different PVRs (eg, POWER8
and POWER8E), since KVM still doesn't provide a way to check if a
specific PVR is supported (see commit c363a37a450f for details).

According to the official KVM API documentation [1], KVM_PPC_GET_PVINFO
is "vm ioctl", but we check it as a global ioctl. The following function
in KVM is hence called with kvm == NULL and considers we're in HV mode.

int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
{
	int r;
	/* Assume we're using HV mode when the HV module is loaded */
	int hv_enabled = kvmppc_hv_ops ? 1 : 0;

	if (kvm) {
		/*
		 * Hooray - we know which VM type we're running on. Depend on
		 * that rather than the guess above.
		 */
		hv_enabled = is_kvmppc_hv_enabled(kvm);
	}

Let's use kvm_vm_check_extension() to fix the issue.

[1] https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt

Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 target/ppc/kvm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 6442dfcb95..1deaf106d2 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -120,7 +120,7 @@ static void kvm_kick_cpu(void *opaque)
 static bool kvmppc_is_pr(KVMState *ks)
 {
     /* Assume KVM-PR if the GET_PVINFO capability is available */
-    return kvm_check_extension(ks, KVM_CAP_PPC_GET_PVINFO) != 0;
+    return kvm_vm_check_extension(ks, KVM_CAP_PPC_GET_PVINFO) != 0;
 }
 
 static int kvm_ppc_register_host_cpu_type(void);
-- 
2.13.5

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (17 preceding siblings ...)
  2017-09-15  3:51 ` [Qemu-devel] [PULL 18/18] ppc/kvm: use kvm_vm_check_extension() in kvmppc_is_pr() David Gibson
@ 2017-09-15  4:26 ` no-reply
  2017-09-15  5:00   ` David Gibson
  2017-09-15 19:28 ` Peter Maydell
  19 siblings, 1 reply; 22+ messages in thread
From: no-reply @ 2017-09-15  4:26 UTC (permalink / raw)
  To: david; +Cc: famz, peter.maydell, aik, gkurz, agraf, qemu-devel, qemu-ppc

Hi,

This series seems to have some coding style problems. See output below for
more information:

Subject: [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915
Message-id: 20170915035130.8354-1-david@gibson.dropbear.id.au
Type: series

=== TEST SCRIPT BEGIN ===
#!/bin/bash

BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0

git config --local diff.renamelimit 0
git config --local diff.renames True

commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
    echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
    if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
        failed=1
        echo
    fi
    n=$((n+1))
done

exit $failed
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
872afb4d17 ppc/kvm: use kvm_vm_check_extension() in kvmppc_is_pr()
7a25c28fcc spapr_events: use QTAILQ_FOREACH_SAFE() in spapr_clear_pending_events()
925177495a spapr_cpu_core: cleaning up qdev_get_machine() calls
e0a96b5c4d spapr_pci: don't create 64-bit MMIO window if we don't need to
1851b264d5 spapr_pci: convert sprintf() to g_strdup_printf()
e62bfeb753 spapr_cpu_core: fail gracefully with non-pseries machine types
d68c815c09 xics: fix several error leaks
165724544b vfio, spapr: Fix levels calculation
e0d3f60741 spapr_pci: handle FDT creation errors with _FDT()
9d82d580aa spapr_pci: use the common _FDT() helper
fe74e07d9f spapr: fix CAS-generated reset
53b3f63411 ppc/xive: fix OV5_XIVE_EXPLOIT bits
48ced9b1af spapr: only update SDR1 once per-cpu during CAS
868444ad8c spapr_pci: use g_strdup_printf()
dbfa7f0124 spapr_pci: drop useless check in spapr_populate_pci_child_dt()
2d5463163b spapr_pci: drop useless check in spapr_phb_vfio_get_loc_code()
0d760c3eed hw/ppc/spapr.c: cleaning up qdev_get_machine() calls
2add13654e net: Add SunGEM device emulation as found on Apple UniNorth

=== OUTPUT BEGIN ===
Checking PATCH 1/18: net: Add SunGEM device emulation as found on Apple UniNorth...
Checking PATCH 2/18: hw/ppc/spapr.c: cleaning up qdev_get_machine() calls...
Checking PATCH 3/18: spapr_pci: drop useless check in spapr_phb_vfio_get_loc_code()...
Checking PATCH 4/18: spapr_pci: drop useless check in spapr_populate_pci_child_dt()...
Checking PATCH 5/18: spapr_pci: use g_strdup_printf()...
Checking PATCH 6/18: spapr: only update SDR1 once per-cpu during CAS...
Checking PATCH 7/18: ppc/xive: fix OV5_XIVE_EXPLOIT bits...
Checking PATCH 8/18: spapr: fix CAS-generated reset...
Checking PATCH 9/18: spapr_pci: use the common _FDT() helper...
Checking PATCH 10/18: spapr_pci: handle FDT creation errors with _FDT()...
Checking PATCH 11/18: vfio, spapr: Fix levels calculation...
Checking PATCH 12/18: xics: fix several error leaks...
Checking PATCH 13/18: spapr_cpu_core: fail gracefully with non-pseries machine types...
Checking PATCH 14/18: spapr_pci: convert sprintf() to g_strdup_printf()...
Checking PATCH 15/18: spapr_pci: don't create 64-bit MMIO window if we don't need to...
ERROR: spaces required around that '-' (ctx:VxV)
#55: FILE: hw/ppc/spapr_pci.c:1625:
+    if (sphb->mem64_win_pciaddr != (hwaddr)-1) {
                                            ^

ERROR: spaces required around that '-' (ctx:VxV)
#62: FILE: hw/ppc/spapr_pci.c:1632:
+        if (sphb->mem64_win_addr != (hwaddr)-1) {
                                             ^

total: 2 errors, 0 warnings, 26 lines checked

Your patch has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

Checking PATCH 16/18: spapr_cpu_core: cleaning up qdev_get_machine() calls...
Checking PATCH 17/18: spapr_events: use QTAILQ_FOREACH_SAFE() in spapr_clear_pending_events()...
Checking PATCH 18/18: ppc/kvm: use kvm_vm_check_extension() in kvmppc_is_pr()...
=== OUTPUT END ===

Test command exited with code: 1


---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915
  2017-09-15  4:26 ` [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 no-reply
@ 2017-09-15  5:00   ` David Gibson
  0 siblings, 0 replies; 22+ messages in thread
From: David Gibson @ 2017-09-15  5:00 UTC (permalink / raw)
  To: qemu-devel; +Cc: famz, peter.maydell, aik, gkurz, agraf, qemu-ppc

[-- Attachment #1: Type: text/plain, Size: 3973 bytes --]

On Thu, Sep 14, 2017 at 09:26:49PM -0700, no-reply@patchew.org wrote:
> Hi,
> 
> This series seems to have some coding style problems. See output below for
> more information:
> 
> Subject: [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915
> Message-id: 20170915035130.8354-1-david@gibson.dropbear.id.au
> Type: series
> 
> === TEST SCRIPT BEGIN ===
> #!/bin/bash
> 
> BASE=base
> n=1
> total=$(git log --oneline $BASE.. | wc -l)
> failed=0
> 
> git config --local diff.renamelimit 0
> git config --local diff.renames True
> 
> commits="$(git log --format=%H --reverse $BASE..)"
> for c in $commits; do
>     echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
>     if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
>         failed=1
>         echo
>     fi
>     n=$((n+1))
> done
> 
> exit $failed
> === TEST SCRIPT END ===
> 
> Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
> Switched to a new branch 'test'
> 872afb4d17 ppc/kvm: use kvm_vm_check_extension() in kvmppc_is_pr()
> 7a25c28fcc spapr_events: use QTAILQ_FOREACH_SAFE() in spapr_clear_pending_events()
> 925177495a spapr_cpu_core: cleaning up qdev_get_machine() calls
> e0a96b5c4d spapr_pci: don't create 64-bit MMIO window if we don't need to
> 1851b264d5 spapr_pci: convert sprintf() to g_strdup_printf()
> e62bfeb753 spapr_cpu_core: fail gracefully with non-pseries machine types
> d68c815c09 xics: fix several error leaks
> 165724544b vfio, spapr: Fix levels calculation
> e0d3f60741 spapr_pci: handle FDT creation errors with _FDT()
> 9d82d580aa spapr_pci: use the common _FDT() helper
> fe74e07d9f spapr: fix CAS-generated reset
> 53b3f63411 ppc/xive: fix OV5_XIVE_EXPLOIT bits
> 48ced9b1af spapr: only update SDR1 once per-cpu during CAS
> 868444ad8c spapr_pci: use g_strdup_printf()
> dbfa7f0124 spapr_pci: drop useless check in spapr_populate_pci_child_dt()
> 2d5463163b spapr_pci: drop useless check in spapr_phb_vfio_get_loc_code()
> 0d760c3eed hw/ppc/spapr.c: cleaning up qdev_get_machine() calls
> 2add13654e net: Add SunGEM device emulation as found on Apple UniNorth
> 
> === OUTPUT BEGIN ===
> Checking PATCH 1/18: net: Add SunGEM device emulation as found on Apple UniNorth...
> Checking PATCH 2/18: hw/ppc/spapr.c: cleaning up qdev_get_machine() calls...
> Checking PATCH 3/18: spapr_pci: drop useless check in spapr_phb_vfio_get_loc_code()...
> Checking PATCH 4/18: spapr_pci: drop useless check in spapr_populate_pci_child_dt()...
> Checking PATCH 5/18: spapr_pci: use g_strdup_printf()...
> Checking PATCH 6/18: spapr: only update SDR1 once per-cpu during CAS...
> Checking PATCH 7/18: ppc/xive: fix OV5_XIVE_EXPLOIT bits...
> Checking PATCH 8/18: spapr: fix CAS-generated reset...
> Checking PATCH 9/18: spapr_pci: use the common _FDT() helper...
> Checking PATCH 10/18: spapr_pci: handle FDT creation errors with _FDT()...
> Checking PATCH 11/18: vfio, spapr: Fix levels calculation...
> Checking PATCH 12/18: xics: fix several error leaks...
> Checking PATCH 13/18: spapr_cpu_core: fail gracefully with non-pseries machine types...
> Checking PATCH 14/18: spapr_pci: convert sprintf() to g_strdup_printf()...
> Checking PATCH 15/18: spapr_pci: don't create 64-bit MMIO window if we don't need to...
> ERROR: spaces required around that '-' (ctx:VxV)
> #55: FILE: hw/ppc/spapr_pci.c:1625:
> +    if (sphb->mem64_win_pciaddr != (hwaddr)-1) {
>                                             ^
> 
> ERROR: spaces required around that '-' (ctx:VxV)
> #62: FILE: hw/ppc/spapr_pci.c:1632:
> +        if (sphb->mem64_win_addr != (hwaddr)-1) {
>                                              ^
>

These are false positives, a patch for checkpatch.pl is in the works.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915
  2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
                   ` (18 preceding siblings ...)
  2017-09-15  4:26 ` [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 no-reply
@ 2017-09-15 19:28 ` Peter Maydell
  19 siblings, 0 replies; 22+ messages in thread
From: Peter Maydell @ 2017-09-15 19:28 UTC (permalink / raw)
  To: David Gibson
  Cc: Alexander Graf, gkurz, QEMU Developers, qemu-ppc, Alexey Kardashevskiy

On 15 September 2017 at 04:51, David Gibson <david@gibson.dropbear.id.au> wrote:
> The following changes since commit 3dabde1128b671f36ac6cb36b97b273139964420:
>
>   Merge remote-tracking branch 'remotes/dgilbert/tags/pull-hmp-20170914' into staging (2017-09-14 16:33:02 +0100)
>
> are available in the git repository at:
>
>   git://github.com/dgibson/qemu.git tags/ppc-for-2.11-20170915
>
> for you to fetch changes up to 70a0c19e83aa4c71c879d51e426e89e4b3d4e014:
>
>   ppc/kvm: use kvm_vm_check_extension() in kvmppc_is_pr() (2017-09-15 10:29:48 +1000)
>
> ----------------------------------------------------------------
> ppc patch queue 2017-09-15
>
> Here's the current batch of accumulated ppc patches.  These are all
> pretty simple bugfixes or cleanups, no big new features here.
>

Applied, thanks.

-- PMM

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2017-09-15 19:29 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-15  3:51 [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 01/18] net: Add SunGEM device emulation as found on Apple UniNorth David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 02/18] hw/ppc/spapr.c: cleaning up qdev_get_machine() calls David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 03/18] spapr_pci: drop useless check in spapr_phb_vfio_get_loc_code() David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 04/18] spapr_pci: drop useless check in spapr_populate_pci_child_dt() David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 05/18] spapr_pci: use g_strdup_printf() David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 06/18] spapr: only update SDR1 once per-cpu during CAS David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 07/18] ppc/xive: fix OV5_XIVE_EXPLOIT bits David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 08/18] spapr: fix CAS-generated reset David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 09/18] spapr_pci: use the common _FDT() helper David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 10/18] spapr_pci: handle FDT creation errors with _FDT() David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 11/18] vfio, spapr: Fix levels calculation David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 12/18] xics: fix several error leaks David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 13/18] spapr_cpu_core: fail gracefully with non-pseries machine types David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 14/18] spapr_pci: convert sprintf() to g_strdup_printf() David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 15/18] spapr_pci: don't create 64-bit MMIO window if we don't need to David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 16/18] spapr_cpu_core: cleaning up qdev_get_machine() calls David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 17/18] spapr_events: use QTAILQ_FOREACH_SAFE() in spapr_clear_pending_events() David Gibson
2017-09-15  3:51 ` [Qemu-devel] [PULL 18/18] ppc/kvm: use kvm_vm_check_extension() in kvmppc_is_pr() David Gibson
2017-09-15  4:26 ` [Qemu-devel] [PULL 00/18] ppc-for-2.11 queue 20170915 no-reply
2017-09-15  5:00   ` David Gibson
2017-09-15 19:28 ` Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.