[Qemu-devel] [PATCH v10 21/24] replay: document development rules

2019-01-16 Thread Pavel Dovgalyuk
This patch introduces docs/devel/replay.txt which describes the rules
that should be followed to make virtual devices usable in record/replay mode.

Signed-off-by: Pavel Dovgalyuk 

--

v9: fixed external virtual clock description (reported by Artem Pisarenko)
---
 docs/devel/replay.txt |   46 ++
 1 file changed, 46 insertions(+)
 create mode 100644 docs/devel/replay.txt

diff --git a/docs/devel/replay.txt b/docs/devel/replay.txt
new file mode 100644
index 000..e641c35
--- /dev/null
+++ b/docs/devel/replay.txt
@@ -0,0 +1,46 @@
+Record/replay mechanism, that could be enabled through icount mode, expects
+the virtual devices to satisfy the following requirements.
+
+The main idea behind this document is that everything that affects
+the guest state during execution in icount mode should be deterministic.
+
+Timers
+==
+
+All virtual devices should use virtual clock for timers that change the guest
+state. Virtual clock is deterministic, therefore such timers are deterministic
+too.
+
+Virtual devices can also use realtime clock for the events that do not change
+the guest state directly. When the clock ticking should depend on VM execution
+speed, use virtual clock with EXTERNAL attribute. It is not deterministic,
+but its speed depends on the guest execution. This clock is used by
+the virtual devices (e.g., slirp routing device) that lie outside the
+replayed guest.
+
+Bottom halves
+=
+
+Bottom half callbacks, that affect the guest state, should be invoked through
+replay_bh_schedule_event or replay_bh_schedule_oneshot_event functions.
+Their invocations are saved in record mode and synchronized with the existing
+log in replay mode.
+
+Saving/restoring the VM state
+=
+
+All fields in the device state structure (including virtual timers)
+should be restored by loadvm to the same values they had before savevm.
+
+Avoid accessing other devices' state, because the order of saving/restoring
+is not defined. It means that you should not call functions like
+'update_irq' in post_load callback. Save everything explicitly to avoid
+the dependencies that may make restoring the VM state non-deterministic.
+
+Stopping the VM
+===
+
+Stopping the guest should not interfere with its state (with the exception
+of the network connections, that could be broken by the remote timeouts).
+VM can be stopped at any moment of replay by the user. Restarting the VM
+after that stop should not break the replay by the unneeded guest state change.




Re: [Qemu-devel] [Qemu-ppc] [PATCH v5 2/3] ppc: Fix duplicated typedefs to be able to compile with Clang in gnu99 mode

2019-01-16 Thread Greg Kurz
On Thu, 17 Jan 2019 08:01:25 +0100
Thomas Huth  wrote:

> On 2019-01-16 14:29, Cédric Le Goater wrote:
> > On 1/16/19 12:47 PM, Thomas Huth wrote:  
> >> On 2019-01-16 12:43, Cédric Le Goater wrote:  
> >>> On 1/11/19 9:17 AM, Thomas Huth wrote:  
>  When compiling the ppc code with clang and -std=gnu99, there are a
>  couple of warnings/errors like this one:
> 
>    CC  ppc64-softmmu/hw/intc/xics.o
>  In file included from hw/intc/xics.c:35:
>  include/hw/ppc/xics.h:43:25: error: redefinition of typedef 'ICPState' 
>  is a C11 feature
>    [-Werror,-Wtypedef-redefinition]
>  typedef struct ICPState ICPState;
>  ^
>  target/ppc/cpu.h:1181:25: note: previous definition is here
>  typedef struct ICPState ICPState;
>  ^
>  Work around the problems by including the proper headers instead.  
> >>>
> >>> Thomas,
> >>>
> >>>
> >>> After a closer look, I think we should use 'void *' under PowerPCCPU 
> >>> as it was the case before I introduced the second interrupt presenter.  
> >>
> >> If you don't like the #includes, why not simply do anonymous struct
> >> forward declarations here? I think that would be better than "void *".  
> > 
> > yes.
> >
> >>> That's a bigger change reverting bits of already merged patches. I can
> >>> take care of it if you prefer.   
> >>
> >> Could I keep the current patch in my series so that I can get the
> >> patches finally merged? You could then do any clean up that you like on
> >> top of it, ok?  
> > 
> > OK. 
> > 
> > See below the patch I would propose. Compiled tested with clang -std=gnu99. 
> >  
> [...]
> > @@ -1204,8 +1199,8 @@ struct PowerPCCPU {
> >  int32_t node_id; /* NUMA node this CPU belongs to */
> >  PPCHash64Options *hash64_opts;
> >  #ifndef CONFIG_USER_ONLY
> > -ICPState *icp;
> > -XiveTCTX *tctx;
> > +struct ICPState *icp;
> > +struct XiveTCTX *tctx;
> >  #endif  
> 
> That's pretty much what I had in an earlier version of my patch:
> 
> https://lists.gnu.org/archive/html/qemu-devel/2019-01/msg01810.html
> 
> But Greg did not like it:
> 
> https://lists.gnu.org/archive/html/qemu-devel/2019-01/msg01893.html
> 

Yeah I didn't but the #includes bring even more troubles so I won't object
if we go for struct :) For the long term, I still think that icp and tctx
should be hidden behind void *machine_data in a per-machine struct.

>  Thomas




[Qemu-devel] [PATCH 3/4] spapr: move the interrupt presenters under machine_data

2019-01-16 Thread Cédric Le Goater
Next step is to remove them from under the PowerPCCPU

Signed-off-by: Cédric Le Goater 
---
 include/hw/ppc/spapr_cpu_core.h |  2 ++
 hw/intc/spapr_xive.c|  3 ++-
 hw/intc/xics_spapr.c| 11 ++-
 hw/ppc/spapr.c  |  2 +-
 hw/ppc/spapr_cpu_core.c |  8 
 hw/ppc/spapr_irq.c  | 17 ++---
 6 files changed, 25 insertions(+), 18 deletions(-)

diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index 9e2821e4b31f..d64f86bc284e 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -46,6 +46,8 @@ typedef struct sPAPRCPUState {
 uint64_t vpa_addr;
 uint64_t slb_shadow_addr, slb_shadow_size;
 uint64_t dtl_addr, dtl_size;
+struct ICPState *icp;
+struct XiveTCTX *tctx;
 } sPAPRCPUState;
 
 static inline sPAPRCPUState *spapr_cpu_state(PowerPCCPU *cpu)
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index 136d872f16bc..a0f5ff929447 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -16,6 +16,7 @@
 #include "monitor/monitor.h"
 #include "hw/ppc/fdt.h"
 #include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_cpu_core.h"
 #include "hw/ppc/spapr_xive.h"
 #include "hw/ppc/xive.h"
 #include "hw/ppc/xive_regs.h"
@@ -394,7 +395,7 @@ static XiveTCTX *spapr_xive_get_tctx(XiveRouter *xrtr, 
CPUState *cs)
 {
 PowerPCCPU *cpu = POWERPC_CPU(cs);
 
-return cpu->tctx;
+return spapr_cpu_state(cpu)->tctx;
 }
 
 static const VMStateDescription vmstate_spapr_xive_end = {
diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c
index de6cc15b6474..e2d8b3818336 100644
--- a/hw/intc/xics_spapr.c
+++ b/hw/intc/xics_spapr.c
@@ -31,6 +31,7 @@
 #include "trace.h"
 #include "qemu/timer.h"
 #include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_cpu_core.h"
 #include "hw/ppc/xics.h"
 #include "hw/ppc/xics_spapr.h"
 #include "hw/ppc/fdt.h"
@@ -45,7 +46,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState 
*spapr,
 {
 target_ulong cppr = args[0];
 
-icp_set_cppr(cpu->icp, cppr);
+icp_set_cppr(spapr_cpu_state(cpu)->icp, cppr);
 return H_SUCCESS;
 }
 
@@ -66,7 +67,7 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState 
*spapr,
 static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
 {
-uint32_t xirr = icp_accept(cpu->icp);
+uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp);
 
 args[0] = xirr;
 return H_SUCCESS;
@@ -75,7 +76,7 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState 
*spapr,
 static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
  target_ulong opcode, target_ulong *args)
 {
-uint32_t xirr = icp_accept(cpu->icp);
+uint32_t xirr = icp_accept(spapr_cpu_state(cpu)->icp);
 
 args[0] = xirr;
 args[1] = cpu_get_host_ticks();
@@ -87,7 +88,7 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState 
*spapr,
 {
 target_ulong xirr = args[0];
 
-icp_eoi(cpu->icp, xirr);
+icp_eoi(spapr_cpu_state(cpu)->icp, xirr);
 return H_SUCCESS;
 }
 
@@ -95,7 +96,7 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, 
sPAPRMachineState *spapr,
 target_ulong opcode, target_ulong *args)
 {
 uint32_t mfrr;
-uint32_t xirr = icp_ipoll(cpu->icp, );
+uint32_t xirr = icp_ipoll(spapr_cpu_state(cpu)->icp, );
 
 args[0] = xirr;
 args[1] = mfrr;
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 83081defde4e..181f994c87a7 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -3896,7 +3896,7 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int 
vcpu_id)
 {
 PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
 
-return cpu ? cpu->icp : NULL;
+return cpu ? spapr_cpu_state(cpu)->icp : NULL;
 }
 
 static void spapr_pic_print_info(InterruptStatsProvider *obj,
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 0405306d1e59..ef6cbb9c2943 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -194,11 +194,11 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, 
sPAPRCPUCore *sc)
 vmstate_unregister(NULL, _spapr_cpu_state, cpu->machine_data);
 }
 qemu_unregister_reset(spapr_cpu_reset, cpu);
-if (cpu->icp) {
-object_unparent(OBJECT(cpu->icp));
+if (spapr_cpu_state(cpu)->icp) {
+object_unparent(OBJECT(spapr_cpu_state(cpu)->icp));
 }
-if (cpu->tctx) {
-object_unparent(OBJECT(cpu->tctx));
+if (spapr_cpu_state(cpu)->tctx) {
+object_unparent(OBJECT(spapr_cpu_state(cpu)->tctx));
 }
 cpu_remove_sync(CPU(cpu));
 object_unparent(OBJECT(cpu));
diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c
index 1da7a32348fc..2d7a7c163876 100644
--- a/hw/ppc/spapr_irq.c
+++ b/hw/ppc/spapr_irq.c
@@ -12,6 +12,7 @@
 #include "qemu/error-report.h"
 #include "qapi/error.h"
 #include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_cpu_core.h"
 

[Qemu-devel] [PATCH v10 15/24] replay: flush rr queue before loading the vmstate

2019-01-16 Thread Pavel Dovgalyuk
Non-empty record/replay queue prevents saving and loading the VM state,
because it includes pending bottom halves and block coroutines.
But when the new VM state is loaded, we don't have to preserve the consistency
of the current state anymore. Therefore this patch just flushes the queue
allowing the coroutines to finish.

Signed-off-by: Pavel Dovgalyuk 
---
 include/sysemu/replay.h  |2 ++
 migration/savevm.c   |6 ++
 replay/replay-internal.h |2 --
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 3fe14b5..d7e859d 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -140,6 +140,8 @@ void replay_disable_events(void);
 void replay_enable_events(void);
 /*! Returns true when saving events is enabled */
 bool replay_events_enabled(void);
+/* Flushes events queue */
+void replay_flush_events(void);
 /*! Adds bottom half event to the queue */
 void replay_bh_schedule_event(QEMUBH *bh);
 /*! Adds input event to the queue */
diff --git a/migration/savevm.c b/migration/savevm.c
index a031e5b..5a9902d 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2701,6 +2701,12 @@ int load_snapshot(const char *name, Error **errp)
 return -EINVAL;
 }
 
+/*
+ * Flush the record/replay queue. Now the VM state is going
+ * to change. Therefore we don't need to preserve its consistency
+ */
+replay_flush_events();
+
 /* Flush all IO requests so they don't interfere with the new state.  */
 bdrv_drain_all_begin();
 
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 8c15a41..9458023 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -146,8 +146,6 @@ void replay_read_next_clock(unsigned int kind);
 void replay_init_events(void);
 /*! Clears internal data structures for events handling */
 void replay_finish_events(void);
-/*! Flushes events queue */
-void replay_flush_events(void);
 /*! Returns true if there are any unsaved events in the queue */
 bool replay_has_events(void);
 /*! Saves events from queue into the file */




[Qemu-devel] [PATCH 0/4] ppc: move the interrupt presenters under the CPU machine_data

2019-01-16 Thread Cédric Le Goater
Hello,

Currently the interrupt presenters of the sPAPR and PowerNV machines
are stored directly under PowerPCCPU which can be problematic as this
model is shared by all PPC machines.

The following patches move the interrupt presenters under the CPU
machine_data pointer which is a private field of the CPU that the
machine can use of its own needs.

To be applied on top of Thomas -std=gnu99 patchset.

Thanks,

C. 

Cédric Le Goater (4):
  xive: add a get_tctx() method to the XiveRouter
  ppc/pnv: introduce a CPU machine_data
  spapr: move the interrupt presenters under machine_data
  ppc: remove the interrupt presenters from under PowerPCCPU

 include/hw/ppc/pnv_core.h   |  9 ++
 include/hw/ppc/spapr_cpu_core.h |  2 ++
 include/hw/ppc/xive.h   | 57 +
 target/ppc/cpu.h|  9 --
 hw/intc/spapr_xive.c|  9 ++
 hw/intc/xics_spapr.c| 11 ---
 hw/intc/xive.c  | 16 +
 hw/ppc/pnv.c|  7 ++--
 hw/ppc/pnv_core.c   | 12 ++-
 hw/ppc/spapr.c  |  2 +-
 hw/ppc/spapr_cpu_core.c |  8 ++---
 hw/ppc/spapr_irq.c  | 17 ++
 12 files changed, 95 insertions(+), 64 deletions(-)

-- 
2.20.1




[Qemu-devel] [PATCH 4/4] ppc: remove the interrupt presenters from under PowerPCCPU

2019-01-16 Thread Cédric Le Goater
Signed-off-by: Cédric Le Goater 
---
 target/ppc/cpu.h | 9 -
 1 file changed, 9 deletions(-)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index bde4dff1ba80..2c22292e7f41 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -23,11 +23,6 @@
 #include "qemu-common.h"
 #include "qemu/int128.h"
 
-#ifndef CONFIG_USER_ONLY
-#include "hw/ppc/xive.h" /* for XiveTCTX */
-#include "hw/ppc/xics.h" /* for ICPState */
-#endif
-
 //#define PPC_EMULATE_32BITS_HYPV
 
 #if defined (TARGET_PPC64)
@@ -1203,10 +1198,6 @@ struct PowerPCCPU {
 void *machine_data;
 int32_t node_id; /* NUMA node this CPU belongs to */
 PPCHash64Options *hash64_opts;
-#ifndef CONFIG_USER_ONLY
-ICPState *icp;
-XiveTCTX *tctx;
-#endif
 
 /* Fields related to migration compatibility hacks */
 bool pre_2_8_migration;
-- 
2.20.1




[Qemu-devel] [PATCH v10 12/24] replay: introduce breakpoint at the specified step

2019-01-16 Thread Pavel Dovgalyuk
This patch introduces replay_break, replay_delete_break
qmp and hmp commands.
These commands allow stopping at the specified instruction.
It may be useful for debugging when there are some known
events that should be investigated.
replay_break command has one argument - number of instructions
executed since the start of the replay.
replay_delete_break removes previously set breakpoint.

Signed-off-by: Pavel Dovgalyuk 

--

v2:
 - renamed replay_break qmp command into replay-break
   (suggested by Eric Blake)
v7:
 - introduces replay_delete_break command
v9:
 - changed 'step' parameter name to 'icount'
 - moved json stuff to replay.json and updated the description
   (suggested by Markus Armbruster)
v10:
 - updated descriptions (suggested by Markus Armbruster)
---
 hmp-commands.hx   |   34 ++
 hmp.h |2 +
 qapi/replay.json  |   36 +++
 replay/replay-debugging.c |   86 +
 replay/replay-internal.h  |4 ++
 replay/replay.c   |   17 +
 6 files changed, 179 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index ba71558..d529f24 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1890,6 +1890,40 @@ Set QOM property @var{property} of object at location 
@var{path} to value @var{v
 ETEXI
 
 {
+.name   = "replay_break",
+.args_type  = "icount:i",
+.params = "icount",
+.help   = "set breakpoint at the specified instruction count",
+.cmd= hmp_replay_break,
+},
+
+STEXI
+@item replay_break @var{icount}
+@findex replay_break
+Set replay breakpoint at instruction count @var{icount}.
+Execution stops when the specified instruction is reached.
+There can be at most one breakpoint. When breakpoint is set, any prior
+one is removed.  The breakpoint may be set only in replay mode and only
+"in the future", i.e. at instruction counts greater than the current one.
+The current instruction count can be observed with 'info replay'.
+ETEXI
+
+{
+.name   = "replay_delete_break",
+.args_type  = "",
+.params = "",
+.help   = "removes replay breakpoint",
+.cmd= hmp_replay_delete_break,
+},
+
+STEXI
+@item replay_delete_break
+@findex replay_delete_break
+Removes replay breakpoint which was previously set with replay_break.
+The command is ignored when there are no replay breakpoints.
+ETEXI
+
+{
 .name   = "info",
 .args_type  = "item:s?",
 .params = "[subcommand]",
diff --git a/hmp.h b/hmp.h
index d792149..c9b9b4f 100644
--- a/hmp.h
+++ b/hmp.h
@@ -149,5 +149,7 @@ void hmp_info_vm_generation_id(Monitor *mon, const QDict 
*qdict);
 void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict);
 void hmp_info_sev(Monitor *mon, const QDict *qdict);
 void hmp_info_replay(Monitor *mon, const QDict *qdict);
+void hmp_replay_break(Monitor *mon, const QDict *qdict);
+void hmp_replay_delete_break(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi/replay.json b/qapi/replay.json
index ef2fb4b..cb94991 100644
--- a/qapi/replay.json
+++ b/qapi/replay.json
@@ -63,3 +63,39 @@
 ##
 { 'command': 'query-replay',
   'returns': 'ReplayInfo' }
+
+##
+# @replay-break:
+#
+# Set replay breakpoint at instruction count @icount.
+# Execution stops when the specified instruction is reached.
+# There can be at most one breakpoint. When breakpoint is set, any prior
+# one is removed.  The breakpoint may be set only in replay mode and only
+# "in the future", i.e. at instruction counts greater than the current one.
+# The current instruction count can be observed with @query-replay.
+#
+# @icount: instruction count to stop at
+#
+# Since: 4.0
+#
+# Example:
+#
+# -> { "execute": "replay-break", "data": { "icount": 220414 } }
+#
+##
+{ 'command': 'replay-break', 'data': { 'icount': 'int' } }
+
+##
+# @replay-delete-break:
+#
+# Removes replay breakpoint which was set with @replay-break.
+# The command is ignored when there are no replay breakpoints.
+#
+# Since: 4.0
+#
+# Example:
+#
+# -> { "execute": "replay-delete-break" }
+#
+##
+{ 'command': 'replay-delete-break' }
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
index 51f1c4d..a94685e 100644
--- a/replay/replay-debugging.c
+++ b/replay/replay-debugging.c
@@ -16,6 +16,8 @@
 #include "hmp.h"
 #include "monitor/monitor.h"
 #include "qapi/qapi-commands-replay.h"
+#include "qapi/qmp/qdict.h"
+#include "qemu/timer.h"
 
 void hmp_info_replay(Monitor *mon, const QDict *qdict)
 {
@@ -41,3 +43,87 @@ ReplayInfo *qmp_query_replay(Error **errp)
 retval->icount = replay_get_current_step();
 return retval;
 }
+
+static void replay_break(uint64_t icount, QEMUTimerCB callback, void *opaque)
+{
+assert(replay_mode == REPLAY_MODE_PLAY);
+assert(replay_mutex_locked());
+assert(replay_break_icount >= replay_get_current_step());
+assert(callback);
+
+

[Qemu-devel] [PATCH 1/4] xive: add a get_tctx() method to the XiveRouter

2019-01-16 Thread Cédric Le Goater
It provides a mean to retrieve the XiveTCTX of a CPU. This will become
necessary with future changes which move the interrupt presenter
object pointers under the PowerPCCPU machine_data.

The PowerNV machine has an extra requirement on TIMA accesses that
this new method addresses. The machine can perform indirect loads and
stores on the TIMA on behalf of another CPU. The PIR being defined in
the controller registers, we need a way to peek in the controller
model to find the PIR value.

The XiveTCTX is moved above the XiveRouter definition to avoid forward
typedef declarations.

Signed-off-by: Cédric Le Goater 
---
 include/hw/ppc/xive.h | 57 ++-
 hw/intc/spapr_xive.c  |  8 ++
 hw/intc/xive.c| 16 +++-
 3 files changed, 47 insertions(+), 34 deletions(-)

diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index 5d31c801ee53..ec3bb2aae45a 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -294,6 +294,33 @@ static inline void xive_source_irq_set(XiveSource *xsrc, 
uint32_t srcno,
 
 void xive_source_set_irq(void *opaque, int srcno, int val);
 
+/*
+ * XIVE Thread interrupt Management (TM) context
+ */
+
+#define TYPE_XIVE_TCTX "xive-tctx"
+#define XIVE_TCTX(obj) OBJECT_CHECK(XiveTCTX, (obj), TYPE_XIVE_TCTX)
+
+/*
+ * XIVE Thread interrupt Management register rings :
+ *
+ *   QW-0  User   event-based exception state
+ *   QW-1  O/SOS context for priority management, interrupt acks
+ *   QW-2  Pool   hypervisor pool context for virtual processors dispatched
+ *   QW-3  Physical   physical thread context and security context
+ */
+#define XIVE_TM_RING_COUNT  4
+#define XIVE_TM_RING_SIZE   0x10
+
+typedef struct XiveTCTX {
+DeviceState parent_obj;
+
+CPUState*cs;
+qemu_irqoutput;
+
+uint8_t regs[XIVE_TM_RING_COUNT * XIVE_TM_RING_SIZE];
+} XiveTCTX;
+
 /*
  * XIVE Router
  */
@@ -324,6 +351,7 @@ typedef struct XiveRouterClass {
XiveNVT *nvt);
 int (*write_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
  XiveNVT *nvt, uint8_t word_number);
+XiveTCTX *(*get_tctx)(XiveRouter *xrtr, CPUState *cs);
 } XiveRouterClass;
 
 void xive_eas_pic_print_info(XiveEAS *eas, uint32_t lisn, Monitor *mon);
@@ -338,7 +366,7 @@ int xive_router_get_nvt(XiveRouter *xrtr, uint8_t nvt_blk, 
uint32_t nvt_idx,
 XiveNVT *nvt);
 int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
   XiveNVT *nvt, uint8_t word_number);
-
+XiveTCTX *xive_router_get_tctx(XiveRouter *xrtr, CPUState *cs);
 
 /*
  * XIVE END ESBs
@@ -371,33 +399,6 @@ typedef struct XiveENDSource {
 void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon);
 void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon);
 
-/*
- * XIVE Thread interrupt Management (TM) context
- */
-
-#define TYPE_XIVE_TCTX "xive-tctx"
-#define XIVE_TCTX(obj) OBJECT_CHECK(XiveTCTX, (obj), TYPE_XIVE_TCTX)
-
-/*
- * XIVE Thread interrupt Management register rings :
- *
- *   QW-0  User   event-based exception state
- *   QW-1  O/SOS context for priority management, interrupt acks
- *   QW-2  Pool   hypervisor pool context for virtual processors dispatched
- *   QW-3  Physical   physical thread context and security context
- */
-#define XIVE_TM_RING_COUNT  4
-#define XIVE_TM_RING_SIZE   0x10
-
-typedef struct XiveTCTX {
-DeviceState parent_obj;
-
-CPUState*cs;
-qemu_irqoutput;
-
-uint8_t regs[XIVE_TM_RING_COUNT * XIVE_TM_RING_SIZE];
-} XiveTCTX;
-
 /*
  * XIVE Thread Interrupt Management Aera (TIMA)
  *
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index d391177ab81f..136d872f16bc 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -390,6 +390,13 @@ static int spapr_xive_write_nvt(XiveRouter *xrtr, uint8_t 
nvt_blk,
 g_assert_not_reached();
 }
 
+static XiveTCTX *spapr_xive_get_tctx(XiveRouter *xrtr, CPUState *cs)
+{
+PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+return cpu->tctx;
+}
+
 static const VMStateDescription vmstate_spapr_xive_end = {
 .name = TYPE_SPAPR_XIVE "/end",
 .version_id = 1,
@@ -454,6 +461,7 @@ static void spapr_xive_class_init(ObjectClass *klass, void 
*data)
 xrc->write_end = spapr_xive_write_end;
 xrc->get_nvt = spapr_xive_get_nvt;
 xrc->write_nvt = spapr_xive_write_nvt;
+xrc->get_tctx = spapr_xive_get_tctx;
 }
 
 static const TypeInfo spapr_xive_info = {
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 7f567a57d25a..2e9b8efd4342 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -320,8 +320,7 @@ static const XiveTmOp *xive_tm_find_op(hwaddr offset, 
unsigned size, bool write)
 static void xive_tm_write(void *opaque, hwaddr offset,
   uint64_t value, unsigned size)
 {
-PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
-XiveTCTX *tctx = cpu->tctx;
+

[Qemu-devel] [PATCH v10 17/24] gdbstub: add reverse continue support in replay mode

2019-01-16 Thread Pavel Dovgalyuk
This patch adds support of the reverse continue operation for gdbstub.
Reverse continue finds the last breakpoint that would happen in normal
execution from the beginning to the current moment.
Implementation of the reverse continue replays the execution twice:
to find the breakpoints that were hit and to seek to the last breakpoint.
Reverse continue loads the previous snapshot and tries to find the breakpoint
since that moment. If there are no such breakpoints, it proceeds to
the earlier snapshot, and so on. When no breakpoints or watchpoints were
hit at all, execution stops at the beginning of the replay log.

Signed-off-by: Pavel Dovgalyuk 
---
 cpus.c|5 +++
 exec.c|1 +
 gdbstub.c |   10 ++
 include/sysemu/replay.h   |8 +
 replay/replay-debugging.c |   71 +
 stubs/replay.c|5 +++
 6 files changed, 99 insertions(+), 1 deletion(-)

diff --git a/cpus.c b/cpus.c
index 013341c..6ef0992 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1110,6 +1110,11 @@ static void cpu_handle_guest_debug(CPUState *cpu)
 cpu->stopped = true;
 } else {
 if (!cpu->singlestep_enabled) {
+/*
+ * Report about the breakpoint and
+ * make a single step to skip it
+ */
+replay_breakpoint();
 cpu_single_step(cpu, SSTEP_ENABLE);
 } else {
 cpu_single_step(cpu, 0);
diff --git a/exec.c b/exec.c
index 6e95469..b16fa7a 100644
--- a/exec.c
+++ b/exec.c
@@ -2745,6 +2745,7 @@ static void check_watchpoint(int offset, int len, 
MemTxAttrs attrs, int flags)
  * Don't process the watchpoints when we are
  * in a reverse debugging operation.
  */
+replay_breakpoint();
 return;
 }
 if (flags == BP_MEM_READ) {
diff --git a/gdbstub.c b/gdbstub.c
index 442187d..60176d5 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1463,6 +1463,14 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 put_packet(s, "E14");
 break;
 }
+case 'c':
+if (replay_reverse_continue()) {
+gdb_continue(s);
+return RS_IDLE;
+} else {
+put_packet(s, "E14");
+break;
+}
 default:
 goto unknown_command;
 }
@@ -1773,7 +1781,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 pstrcat(buf, sizeof(buf), ";multiprocess+");
 
 if (replay_mode == REPLAY_MODE_PLAY) {
-pstrcat(buf, sizeof(buf), ";ReverseStep+");
+pstrcat(buf, sizeof(buf), ";ReverseStep+;ReverseContinue+");
 }
 
 put_packet(s, buf);
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 533003f..1d18c9b 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -80,10 +80,18 @@ const char *replay_get_filename(void);
  */
 bool replay_reverse_step(void);
 /*
+ * Start searching the last breakpoint/watchpoint.
+ * Used by gdbstub for backwards debugging.
+ * Returns true if the process successfully started.
+ */
+bool replay_reverse_continue(void);
+/*
  * Returns true if replay module is processing
  * reverse_continue or reverse_step request
  */
 bool replay_running_debug(void);
+/* Called in reverse debugging mode to collect breakpoint information */
+void replay_breakpoint(void);
 
 /* Processing the instructions */
 
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
index a2fb857..65e1bd9 100644
--- a/replay/replay-debugging.c
+++ b/replay/replay-debugging.c
@@ -22,6 +22,8 @@
 #include "migration/snapshot.h"
 
 static bool replay_is_debugging;
+static int64_t replay_last_breakpoint;
+static int64_t replay_last_snapshot;
 
 bool replay_running_debug(void)
 {
@@ -252,3 +254,72 @@ bool replay_reverse_step(void)
 
 return false;
 }
+
+static void replay_continue_end(void)
+{
+replay_is_debugging = false;
+vm_stop(RUN_STATE_DEBUG);
+replay_break(-1LL, NULL, NULL);
+}
+
+static void replay_continue_stop(void *opaque)
+{
+Error *err = NULL;
+if (replay_last_breakpoint != -1LL) {
+replay_seek(replay_last_breakpoint, replay_stop_vm_debug, );
+if (err) {
+error_free(err);
+replay_continue_end();
+}
+return;
+}
+/*
+ * No breakpoints since the last snapshot.
+ * Find previous snapshot and try again.
+ */
+if (replay_last_snapshot != 0) {
+replay_seek(replay_last_snapshot - 1, replay_continue_stop, );
+if (err) {
+error_free(err);
+replay_continue_end();
+}
+replay_last_snapshot = replay_get_current_step();
+return;
+} else {
+/* Seek to the very 

[Qemu-devel] [PATCH v10 09/24] replay: provide an accessor for rr filename

2019-01-16 Thread Pavel Dovgalyuk
This patch adds an accessor function for the name of the record/replay
log file. Adding an accessor instead of making variable global,
prevents accidental modification of this variable by other modules.

Signed-off-by: Pavel Dovgalyuk 
---
 include/sysemu/replay.h |2 ++
 replay/replay.c |5 +
 2 files changed, 7 insertions(+)

diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 3a7c58e..b3f593f 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -71,6 +71,8 @@ void replay_start(void);
 void replay_finish(void);
 /*! Adds replay blocker with the specified error description */
 void replay_add_blocker(Error *reason);
+/* Returns name of the replay log file */
+const char *replay_get_filename(void);
 
 /* Processing the instructions */
 
diff --git a/replay/replay.c b/replay/replay.c
index b75820a..aa53411 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -394,3 +394,8 @@ void replay_add_blocker(Error *reason)
 {
 replay_blockers = g_slist_prepend(replay_blockers, reason);
 }
+
+const char *replay_get_filename(void)
+{
+return replay_filename;
+}




Re: [Qemu-devel] [PATCH v3 0/4] Introduce attributes for timers subsystem and remove QEMU_CLOCK_VIRTUAL_EXT clock type

2019-01-16 Thread Pavel Dovgalyuk
> From: Artem Pisarenko [mailto:artem.k.pisare...@gmail.com]
> ср, 16 янв. 2019 г. в 12:15, Pavel Dovgalyuk :
> >
> > > From: Artem Pisarenko [mailto:artem.k.pisare...@gmail.com]
> > > > It seems, that this approach is not always correct.
> > > > Now timerlist_deadline_ns uses all virtual timers for deadline 
> > > > calculation (including
> > > external
> > > > ones).
> > > > qemu_start_warp_timer uses the deadline for setting warp timer (which 
> > > > should be
> > > deterministic).
> > > > Therefore warp timer may become non-deterministic and replay may behave 
> > > > differently
> compared
> > > to
> > > > recording phase.
> > > >
> > > > We have to rollback these or improve somehow to avoid non-determinism.
> > >
> > > I dont understand how this approach would even introduce
> > > non-determinism. I'm not sure about aspects of timers subsystem you
> > > mentioned, assuming that maybe we missed something when tried to
> > > optimize. But this has nothing to do with determinism as long as we
> > > treat all virtual clock timers as deterministic, regardless of
> > > EXTERNAL attribute being set or not. They are intended to be used as
> > > such by design, aren't? This attribute was introduced purely to avoid
> > > extra events in log.
> >
> > Right, but deadline calculation and icount warp events (that are written 
> > into the log too)
> > depend on the active virtual timers. Therefore external ones may affect 
> > icount warp
> > operation sequence.
> >
> > Pavel Dovgalyuk
> >
> 
> Sorry, but I still don't understand the source of non-determinism.

The source is the external timers, that depend on "outer world", e.g., slirp.
These timers are not recorded/replayed, but may affect the icount warping
(which should remain deterministic).

> From what you said I may understand that replay module actually has
> some additional non-trivial (for me) dependencies on EXTERNAL
> attribute other than one, introduced in 'timerlist_run_timers()' (i.e.
> it expects deadline calculations somewhere else to match decisions
> made in this function, or something like that). I would agree that
> these patch series might introduce some incorrect behavior. But it
> must be identical in all emulations running in same conditions,
> because deadline, warp timer and their effects are all dependent only
> on virtual timers, and, therefore, are deterministic too. Of course,
> it needs to be fixed. Did you find solution ?

Please check the new version of the series.
Patch 22

Pavel Dovgalyuk




[Qemu-devel] [PATCH v10 19/24] replay: add BH oneshot event for block layer

2019-01-16 Thread Pavel Dovgalyuk
Replay is capable of recording normal BH events, but sometimes
there are single use callbacks scheduled with aio_bh_schedule_oneshot
function. This patch enables recording and replaying such callbacks.
Block layer uses these events for calling the completion function.
Replaying these calls makes the execution deterministic.

Signed-off-by: Pavel Dovgalyuk 

--

v6:
 - moved stub function to the separate file for fixing linux-user build
v10:
 - replaced all block layer aio_bh_schedule_oneshot calls
---
 block/block-backend.c|8 +---
 block/io.c   |4 ++--
 block/iscsi.c|5 +++--
 block/nfs.c  |5 +++--
 block/null.c |4 +++-
 block/nvme.c |6 --
 block/rbd.c  |5 +++--
 block/vxhs.c |5 +++--
 include/sysemu/replay.h  |3 +++
 replay/replay-events.c   |   16 
 replay/replay-internal.h |1 +
 replay/replay.c  |2 +-
 stubs/Makefile.objs  |1 +
 stubs/replay-user.c  |9 +
 14 files changed, 57 insertions(+), 17 deletions(-)
 create mode 100644 stubs/replay-user.c

diff --git a/block/block-backend.c b/block/block-backend.c
index 60d37a0..32c56e9 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -17,6 +17,7 @@
 #include "block/throttle-groups.h"
 #include "sysemu/blockdev.h"
 #include "sysemu/sysemu.h"
+#include "sysemu/replay.h"
 #include "qapi/error.h"
 #include "qapi/qapi-events-block.h"
 #include "qemu/id.h"
@@ -1324,7 +1325,8 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
 acb->blk = blk;
 acb->ret = ret;
 
-aio_bh_schedule_oneshot(blk_get_aio_context(blk), error_callback_bh, acb);
+replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
+ error_callback_bh, acb);
 return >common;
 }
 
@@ -1380,8 +1382,8 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, 
int64_t offset, int bytes,
 
 acb->has_returned = true;
 if (acb->rwco.ret != NOT_DONE) {
-aio_bh_schedule_oneshot(blk_get_aio_context(blk),
-blk_aio_complete_bh, acb);
+replay_bh_schedule_oneshot_event(blk_get_aio_context(blk),
+ blk_aio_complete_bh, acb);
 }
 
 return >common;
diff --git a/block/io.c b/block/io.c
index f9a9c5a..fb3b2a9 100644
--- a/block/io.c
+++ b/block/io.c
@@ -340,8 +340,8 @@ static void coroutine_fn 
bdrv_co_yield_to_drain(BlockDriverState *bs,
 if (bs) {
 bdrv_inc_in_flight(bs);
 }
-aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
-bdrv_co_drain_bh_cb, );
+replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs),
+ bdrv_co_drain_bh_cb, );
 
 qemu_coroutine_yield();
 /* If we are resumed from some other event (such as an aio completion or a
diff --git a/block/iscsi.c b/block/iscsi.c
index a7e8c1f..026c9aa 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -38,6 +38,7 @@
 #include "qemu/iov.h"
 #include "qemu/option.h"
 #include "qemu/uuid.h"
+#include "sysemu/replay.h"
 #include "qapi/error.h"
 #include "qapi/qapi-commands-misc.h"
 #include "qapi/qmp/qdict.h"
@@ -273,8 +274,8 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
 
 out:
 if (iTask->co) {
-aio_bh_schedule_oneshot(iTask->iscsilun->aio_context,
- iscsi_co_generic_bh_cb, iTask);
+replay_bh_schedule_oneshot_event(iTask->iscsilun->aio_context,
+ iscsi_co_generic_bh_cb, iTask);
 } else {
 iTask->complete = 1;
 }
diff --git a/block/nfs.c b/block/nfs.c
index eab1a2c..e8b6c90 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -36,6 +36,7 @@
 #include "qemu/uri.h"
 #include "qemu/cutils.h"
 #include "sysemu/sysemu.h"
+#include "sysemu/replay.h"
 #include "qapi/qapi-visit-block-core.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qstring.h"
@@ -256,8 +257,8 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void 
*data,
 if (task->ret < 0) {
 error_report("NFS Error: %s", nfs_get_error(nfs));
 }
-aio_bh_schedule_oneshot(task->client->aio_context,
-nfs_co_generic_bh_cb, task);
+replay_bh_schedule_oneshot_event(task->client->aio_context,
+ nfs_co_generic_bh_cb, task);
 }
 
 static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
diff --git a/block/null.c b/block/null.c
index d442d3e..733873c 100644
--- a/block/null.c
+++ b/block/null.c
@@ -16,6 +16,7 @@
 #include "qapi/qmp/qstring.h"
 #include "qemu/option.h"
 #include "block/block_int.h"
+#include "sysemu/replay.h"
 
 #define NULL_OPT_LATENCY "latency-ns"
 #define NULL_OPT_ZEROES  "read-zeroes"
@@ -178,7 +179,8 @@ static inline BlockAIOCB *null_aio_common(BlockDriverState 
*bs,
 timer_mod_ns(>timer,
  

[Qemu-devel] [PATCH v10 20/24] replay: init rtc after enabling the replay

2019-01-16 Thread Pavel Dovgalyuk
This patch postpones the call of 'configure_rtc' function. This call
uses host clock to configure the rtc, but host clock access should be
recorded when using icount record/replay mode. Therefore now rtc
is configured after switching record/replay mode on.

Signed-off-by: Pavel Dovgalyuk 
---
 vl.c |   10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/vl.c b/vl.c
index 5992d8e..d5a3fca 100644
--- a/vl.c
+++ b/vl.c
@@ -3008,6 +3008,7 @@ int main(int argc, char **argv, char **envp)
 DisplayState *ds;
 QemuOpts *opts, *machine_opts;
 QemuOpts *icount_opts = NULL, *accel_opts = NULL;
+QemuOpts *rtc_opts = NULL;
 QemuOptsList *olist;
 int optind;
 const char *optarg;
@@ -3814,9 +3815,9 @@ int main(int argc, char **argv, char **envp)
 warn_report("This option is ignored and will be removed soon");
 break;
 case QEMU_OPTION_rtc:
-opts = qemu_opts_parse_noisily(qemu_find_opts("rtc"), optarg,
-   false);
-if (!opts) {
+rtc_opts = qemu_opts_parse_noisily(qemu_find_opts("rtc"),
+   optarg, false);
+if (!rtc_opts) {
 exit(1);
 }
 break;
@@ -4022,6 +4023,9 @@ int main(int argc, char **argv, char **envp)
 loc_set_none();
 
 replay_configure(icount_opts);
+if (rtc_opts) {
+configure_rtc(rtc_opts);
+}
 
 if (incoming && !preconfig_exit_requested) {
 error_report("'preconfig' and 'incoming' options are "




[Qemu-devel] [PATCH v10 07/24] qcow2: introduce icount field for snapshots

2019-01-16 Thread Pavel Dovgalyuk
This patch introduces the icount field for saving within the snapshot.
It is required for navigation between the snapshots in record/replay mode.

Signed-off-by: Pavel Dovgalyuk 
Acked-by: Kevin Wolf 

--

v2:
 - documented format changes in docs/interop/qcow2.txt
   (suggested by Eric Blake)
v10:
 - updated the documentation
---
 block/qcow2-snapshot.c |7 +++
 block/qcow2.h  |2 ++
 docs/interop/qcow2.txt |4 
 3 files changed, 13 insertions(+)

diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index bb6a5b7..d682946 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -103,6 +103,12 @@ int qcow2_read_snapshots(BlockDriverState *bs)
 sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
 }
 
+if (extra_data_size >= 24) {
+sn->icount = be64_to_cpu(extra.icount);
+} else {
+sn->icount = -1ULL;
+}
+
 /* Read snapshot ID */
 sn->id_str = g_malloc(id_str_size + 1);
 ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
@@ -209,6 +215,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
 memset(, 0, sizeof(extra));
 extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
 extra.disk_size = cpu_to_be64(sn->disk_size);
+extra.icount = cpu_to_be64(sn->icount);
 
 id_str_size = strlen(sn->id_str);
 name_size = strlen(sn->name);
diff --git a/block/qcow2.h b/block/qcow2.h
index 438a1de..f33e26a 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -159,6 +159,7 @@ typedef struct QEMU_PACKED QCowSnapshotHeader {
 typedef struct QEMU_PACKED QCowSnapshotExtraData {
 uint64_t vm_state_size_large;
 uint64_t disk_size;
+uint64_t icount;
 } QCowSnapshotExtraData;
 
 
@@ -172,6 +173,7 @@ typedef struct QCowSnapshot {
 uint32_t date_sec;
 uint32_t date_nsec;
 uint64_t vm_clock_nsec;
+uint64_t icount;
 } QCowSnapshot;
 
 struct Qcow2Cache;
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
index fb5cb47..14ca489 100644
--- a/docs/interop/qcow2.txt
+++ b/docs/interop/qcow2.txt
@@ -540,6 +540,10 @@ Snapshot table entry:
 
 Byte 48 - 55:   Virtual disk size of the snapshot in bytes
 
+Byte 56 - 63:   icount value which corresponds to
+the record/replay instruction count
+when the snapshot was taken
+
 Version 3 images must include extra data at least up to
 byte 55.
 




Re: [Qemu-devel] [PATCH] include/fpu/softfloat: Fix compilation with Clang on s390x

2019-01-16 Thread Alex Bennée


Thomas Huth  writes:

> On 2019-01-16 18:08, Alex Bennée wrote:
>>
>> Thomas Huth  writes:
>>
>>> On 2019-01-15 21:05, Emilio G. Cota wrote:
 On Tue, Jan 15, 2019 at 16:01:32 +, Alex Bennée wrote:
> Ahh I should have mentioned we already have the technology for this ;-)
>
> If you build the fpu/next tree on a s390x you can then run:
>
>   ./tests/fp/fp-bench f64_div
>
> with and without the CONFIG_128 path. To get an idea of the real world
> impact you can compile a foreign binary and run it on a s390x system
> with:
>
>   $QEMU ./tests/fp/fp-bench f64_div -t host
>
> And that will give you the peak performance assuming your program is
> doing nothing but f64_div operations. If the two QEMU's are basically in
> the same ballpark then it doesn't make enough difference. That said:

 I think you mean here `tests/fp/fp-bench -o div -p double', otherwise
 you'll get the default op (-o add).
>>>
>>> I tried that now, too, and -o div -p double does not really seem to
>>> exercise this function at all.
>>
>> How do you mean? It should do because by default it should be calling
>> the softfloat implementations.
>
> I've added a puts("hello") into the udiv_qrnd() function. When I then
> run "fp-bench -o div -p double", it only prints out "hello" a single
> time, so the function is only called once during the whole test.

That's very odd. With the following on my aarch64 box:

modified   include/fpu/softfloat-macros.h
@@ -637,6 +637,8 @@ static inline uint64_t estimateDiv128To64(uint64_t a0, 
uint64_t a1, uint64_t b)
 static inline uint64_t udiv_qrnnd(uint64_t *r, uint64_t n1,
   uint64_t n0, uint64_t d)
 {
+static int iter = 0;
+fprintf(stderr, "%s: %d\n", __func__, iter++);
 #if defined(__x86_64__)
 uint64_t q;
 asm("divq %4" : "=a"(q), "=d"(*r) : "0"(n0), "1"(n1), "rm"(d));

I get:

udiv_qrnnd: 0
udiv_qrnnd: 1
..
..
udiv_qrnnd: 8
udiv_qrnnd: 9

So I'm not sure what is different on s390

--
Alex Bennée



[Qemu-devel] [PATCH v10 16/24] gdbstub: add reverse step support in replay mode

2019-01-16 Thread Pavel Dovgalyuk
GDB remote protocol supports two reverse debugging commands:
reverse step and reverse continue.
This patch adds support of the first one to the gdbstub.
Reverse step is intended to step one instruction in the backwards
direction. This is not possible in regular execution.
But replayed execution is deterministic, therefore we can load one of
the prior snapshots and proceed to the desired step. It is equivalent
to stepping one instruction back.
There should be at least one snapshot preceding the debugged part of
the replay log.

Signed-off-by: Pavel Dovgalyuk 
---
 accel/tcg/translator.c|1 +
 cpus.c|   14 +++---
 exec.c|7 +++
 gdbstub.c |   44 +---
 include/sysemu/replay.h   |   11 +++
 replay/replay-debugging.c |   33 +
 stubs/replay.c|5 +
 7 files changed, 109 insertions(+), 6 deletions(-)

diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index afd0a49..33a543e 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -17,6 +17,7 @@
 #include "exec/gen-icount.h"
 #include "exec/log.h"
 #include "exec/translator.h"
+#include "sysemu/replay.h"
 
 /* Pairs with tcg_clear_temp_count.
To be called by #TranslatorOps.{translate_insn,tb_stop} if
diff --git a/cpus.c b/cpus.c
index aa33fb1..013341c 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1104,9 +1104,17 @@ static bool cpu_can_run(CPUState *cpu)
 
 static void cpu_handle_guest_debug(CPUState *cpu)
 {
-gdb_set_stop_cpu(cpu);
-qemu_system_debug_request();
-cpu->stopped = true;
+if (!replay_running_debug()) {
+gdb_set_stop_cpu(cpu);
+qemu_system_debug_request();
+cpu->stopped = true;
+} else {
+if (!cpu->singlestep_enabled) {
+cpu_single_step(cpu, SSTEP_ENABLE);
+} else {
+cpu_single_step(cpu, 0);
+}
+}
 }
 
 #ifdef CONFIG_LINUX
diff --git a/exec.c b/exec.c
index 895449f..6e95469 100644
--- a/exec.c
+++ b/exec.c
@@ -2740,6 +2740,13 @@ static void check_watchpoint(int offset, int len, 
MemTxAttrs attrs, int flags)
 QTAILQ_FOREACH(wp, >watchpoints, entry) {
 if (cpu_watchpoint_address_matches(wp, vaddr, len)
 && (wp->flags & flags)) {
+if (replay_running_debug()) {
+/*
+ * Don't process the watchpoints when we are
+ * in a reverse debugging operation.
+ */
+return;
+}
 if (flags == BP_MEM_READ) {
 wp->flags |= BP_WATCHPOINT_HIT_READ;
 } else {
diff --git a/gdbstub.c b/gdbstub.c
index bfc7afb..442187d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -39,6 +39,7 @@
 #include "sysemu/kvm.h"
 #include "exec/semihost.h"
 #include "exec/exec-all.h"
+#include "sysemu/replay.h"
 
 #ifdef CONFIG_USER_ONLY
 #define GDB_ATTACHED "0"
@@ -344,6 +345,20 @@ typedef struct GDBState {
  */
 static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
 
+/* Retrieves flags for single step mode. */
+static int get_sstep_flags(void)
+{
+/*
+ * In replay mode all events written into the log should be replayed.
+ * That is why NOIRQ flag is removed in this mode.
+ */
+if (replay_mode != REPLAY_MODE_NONE) {
+return SSTEP_ENABLE;
+} else {
+return sstep_flags;
+}
+}
+
 static GDBState *gdbserver_state;
 
 bool gdb_has_xml;
@@ -434,7 +449,7 @@ static int gdb_continue_partial(GDBState *s, char 
*newstates)
 CPU_FOREACH(cpu) {
 if (newstates[cpu->cpu_index] == 's') {
 trace_gdbstub_op_stepping(cpu->cpu_index);
-cpu_single_step(cpu, sstep_flags);
+cpu_single_step(cpu, get_sstep_flags());
 }
 }
 s->running_state = 1;
@@ -453,7 +468,7 @@ static int gdb_continue_partial(GDBState *s, char 
*newstates)
 break; /* nothing to do here */
 case 's':
 trace_gdbstub_op_stepping(cpu->cpu_index);
-cpu_single_step(cpu, sstep_flags);
+cpu_single_step(cpu, get_sstep_flags());
 cpu_resume(cpu);
 flag = 1;
 break;
@@ -1433,9 +1448,28 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 addr = strtoull(p, (char **), 16);
 gdb_set_cpu_pc(s, addr);
 }
-cpu_single_step(s->c_cpu, sstep_flags);
+cpu_single_step(s->c_cpu, get_sstep_flags());
 gdb_continue(s);
 return RS_IDLE;
+case 'b':
+/* Backward debugging commands */
+if (replay_mode == REPLAY_MODE_PLAY) {
+switch (*p) {
+case 's':
+if (replay_reverse_step()) {
+gdb_continue(s);
+return RS_IDLE;
+} else {
+put_packet(s, "E14");
+break;
+}

[Qemu-devel] [PATCH v10 06/24] replay: finish record/replay before closing the disks

2019-01-16 Thread Pavel Dovgalyuk
After recent updates block devices cannot be closed on qemu exit.
This happens due to the block request polling when replay is not finished.
Therefore now we stop execution recording before closing the block devices.

Signed-off-by: Pavel Dovgalyuk 
---
 replay/replay.c |2 ++
 vl.c|1 +
 2 files changed, 3 insertions(+)

diff --git a/replay/replay.c b/replay/replay.c
index 8b172b2..b75820a 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -385,6 +385,8 @@ void replay_finish(void)
 g_free(replay_snapshot);
 replay_snapshot = NULL;
 
+replay_mode = REPLAY_MODE_NONE;
+
 replay_finish_events();
 }
 
diff --git a/vl.c b/vl.c
index bea05cd..5992d8e 100644
--- a/vl.c
+++ b/vl.c
@@ -4671,6 +4671,7 @@ int main(int argc, char **argv, char **envp)
 
 /* No more vcpu or device emulation activity beyond this point */
 vm_shutdown();
+replay_finish();
 
 job_cancel_sync_all();
 bdrv_close_all();




[Qemu-devel] [PATCH v10 18/24] replay: describe reverse debugging in docs/replay.txt

2019-01-16 Thread Pavel Dovgalyuk
This patch updates the documentation and describes usage of the reverse
debugging in QEMU+GDB.

Signed-off-by: Pavel Dovgalyuk 
---
 docs/replay.txt |   33 +
 1 file changed, 33 insertions(+)

diff --git a/docs/replay.txt b/docs/replay.txt
index 2c2c5f6..8447fdd 100644
--- a/docs/replay.txt
+++ b/docs/replay.txt
@@ -293,6 +293,39 @@ for recording and replaying must contain identical number 
of ports in record
 and replay modes, but their backends may differ.
 E.g., '-serial stdio' in record mode, and '-serial null' in replay mode.
 
+Reverse debugging
+-
+
+Reverse debugging allows "executing" the program in reverse direction.
+GDB remote protocol supports "reverse step" and "reverse continue"
+commands. The first one steps single instruction backwards in time,
+and the second one finds the last breakpoint in the past.
+
+Recorded executions may be used to enable reverse debugging. QEMU can't
+execute the code in backwards direction, but can load a snapshot and
+replay forward to find the desired position or breakpoint.
+
+The following GDB commands are supported:
+ - reverse-stepi (or rsi) - step one instruction backwards
+ - reverse-continue (or rc) - find last breakpoint in the past
+
+Reverse step loads the nearest snapshot and replays the execution until
+the required instruction is met.
+
+Reverse continue may include several passes of examining the execution
+between the snapshots. Each of the passes include the following steps:
+ 1. loading the snapshot
+ 2. replaying to examine the breakpoints
+ 3. if breakpoint or watchpoint was met
+- loading the snaphot again
+- replaying to the required breakpoint
+ 4. else
+- proceeding to the p.1 with the earlier snapshot
+
+Therefore usage of the reverse debugging requires at least one snapshot
+created in advance. See the "Snapshotting" section to learn about running
+record/replay and creating the snapshot in these modes.
+
 Replay log format
 -
 




[Qemu-devel] [PATCH v10 22/24] util/qemu-timer: refactor deadline calculation for external timers

2019-01-16 Thread Pavel Dovgalyuk
icount-based record/replay uses qemu_clock_deadline_ns_all to measure
the period until vCPU may be interrupted.
This function takes in account the virtual timers, because they belong
to the virtual devices that may generate interrupt request or affect
the virtual machine state.
However, there are a subset of virtual timers, that are marked with
'external' flag. These do not change the virtual machine state and
only based on virtual clock. Calculating the deadling using the external
timers breaks the determinism, because they do not belong to the replayed
part of the virtual machine.
This patch fixes the deadline calculation for this case.

Signed-off-by: Pavel Dovgalyuk 
---
 cpus.c|9 -
 include/qemu/timer.h  |7 +++
 qtest.c   |2 +-
 tests/ptimer-test-stubs.c |2 +-
 tests/ptimer-test.c   |4 ++--
 util/qemu-timer.c |   41 +
 6 files changed, 44 insertions(+), 21 deletions(-)

diff --git a/cpus.c b/cpus.c
index 6ef0992..fb656ce 100644
--- a/cpus.c
+++ b/cpus.c
@@ -550,7 +550,7 @@ void qtest_clock_warp(int64_t dest)
 assert(qtest_enabled());
 aio_context = qemu_get_aio_context();
 while (clock < dest) {
-int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+int64_t deadline = virtual_clock_deadline_ns();
 int64_t warp = qemu_soonest_timeout(dest - clock, deadline);
 
 seqlock_write_lock(_state.vm_clock_seqlock,
@@ -610,7 +610,7 @@ void qemu_start_warp_timer(void)
 
 /* We want to use the earliest deadline from ALL vm_clocks */
 clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT);
-deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+deadline = virtual_clock_deadline_ns();
 if (deadline < 0) {
 static bool notified;
 if (!icount_sleep && !notified) {
@@ -1355,7 +1355,7 @@ static int64_t tcg_get_icount_limit(void)
 int64_t deadline;
 
 if (replay_mode != REPLAY_MODE_PLAY) {
-deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+deadline = virtual_clock_deadline_ns();
 
 /* Maintain prior (possibly buggy) behaviour where if no deadline
  * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than
@@ -1376,8 +1376,7 @@ static void handle_icount_deadline(void)
 {
 assert(qemu_in_vcpu_thread());
 if (use_icount) {
-int64_t deadline =
-qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+int64_t deadline = virtual_clock_deadline_ns();
 
 if (deadline == 0) {
 /* Wake up other AioContexts.  */
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index a86330c..cfc7745 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -176,16 +176,15 @@ bool qemu_clock_expired(QEMUClockType type);
 bool qemu_clock_use_for_deadline(QEMUClockType type);
 
 /**
- * qemu_clock_deadline_ns_all:
- * @type: the clock type
+ * virtual_clock_deadline_ns:
  *
  * Calculate the deadline across all timer lists associated
- * with a clock (as opposed to just the default one)
+ * with virtual clock (excluding external timers)
  * in nanoseconds, or -1 if no timer is set to expire.
  *
  * Returns: time until expiry in nanoseconds or -1
  */
-int64_t qemu_clock_deadline_ns_all(QEMUClockType type);
+int64_t virtual_clock_deadline_ns(void);
 
 /**
  * qemu_clock_get_main_loop_timerlist:
diff --git a/qtest.c b/qtest.c
index 60988c8..341190e 100644
--- a/qtest.c
+++ b/qtest.c
@@ -655,7 +655,7 @@ static void qtest_process_command(CharBackend *chr, gchar 
**words)
 int ret = qemu_strtoi64(words[1], NULL, 0, );
 g_assert(ret == 0);
 } else {
-ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+ns = virtual_clock_deadline_ns();
 }
 qtest_clock_warp(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns);
 qtest_send_prefix(chr);
diff --git a/tests/ptimer-test-stubs.c b/tests/ptimer-test-stubs.c
index 54b3fd2..31b09c8 100644
--- a/tests/ptimer-test-stubs.c
+++ b/tests/ptimer-test-stubs.c
@@ -88,7 +88,7 @@ int64_t qemu_clock_get_ns(QEMUClockType type)
 return ptimer_test_time_ns;
 }
 
-int64_t qemu_clock_deadline_ns_all(QEMUClockType type)
+int64_t virtual_clock_deadline_ns(void)
 {
 QEMUTimerList *timer_list = main_loop_tlg.tl[type];
 QEMUTimer *t = timer_list->active_timers.next;
diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c
index b30aad0..338a4e0 100644
--- a/tests/ptimer-test.c
+++ b/tests/ptimer-test.c
@@ -50,13 +50,13 @@ static void ptimer_test_set_qemu_time_ns(int64_t ns)
 
 static void qemu_clock_step(uint64_t ns)
 {
-int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+int64_t deadline = virtual_clock_deadline_ns();
 int64_t advanced_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns;
 
 while (deadline != -1 && deadline <= advanced_time) {
 ptimer_test_set_qemu_time_ns(deadline);

[Qemu-devel] [PATCH v10 13/24] replay: implement replay-seek command

2019-01-16 Thread Pavel Dovgalyuk
This patch adds hmp/qmp commands replay_seek/replay-seek that proceed
the execution to the specified instruction count.
The command automatically loads nearest snapshot and replays the execution
to find the desired instruction count.

Signed-off-by: Pavel Dovgalyuk 

--

v2:
 - renamed replay_seek qmp command into replay-seek
   (suggested by Eric Blake)
v7:
 - small fixes related to Markus Armbruster's review
v9:
 - changed 'step' parameter name to 'icount'
 - moved json stuff to replay.json and updated the description
   (suggested by Markus Armbruster)
v10:
 - updated the descriptions
---
 hmp-commands.hx   |   19 +
 hmp.h |1 
 qapi/replay.json  |   20 ++
 replay/replay-debugging.c |   92 +
 4 files changed, 132 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index d529f24..57ec43c 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1924,6 +1924,25 @@ The command is ignored when there are no replay 
breakpoints.
 ETEXI
 
 {
+.name   = "replay_seek",
+.args_type  = "icount:i",
+.params = "icount",
+.help   = "replay execution to the specified instruction count",
+.cmd= hmp_replay_seek,
+},
+
+STEXI
+@item replay_seek @var{icount}
+@findex replay_seek
+Automatically proceeds to the instruction count @var{icount}, when
+replaying the execution. The command automatically loads nearest
+snapshot and replays the execution to find the desired instruction.
+When there is no preceding snapshot or the execution is not replayed,
+then the command is ignored and error message is displayed.
+icount for the reference may be observed with 'info replay' command.
+ETEXI
+
+{
 .name   = "info",
 .args_type  = "item:s?",
 .params = "[subcommand]",
diff --git a/hmp.h b/hmp.h
index c9b9b4f..d6e1d7e 100644
--- a/hmp.h
+++ b/hmp.h
@@ -151,5 +151,6 @@ void hmp_info_sev(Monitor *mon, const QDict *qdict);
 void hmp_info_replay(Monitor *mon, const QDict *qdict);
 void hmp_replay_break(Monitor *mon, const QDict *qdict);
 void hmp_replay_delete_break(Monitor *mon, const QDict *qdict);
+void hmp_replay_seek(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi/replay.json b/qapi/replay.json
index cb94991..0b5afce 100644
--- a/qapi/replay.json
+++ b/qapi/replay.json
@@ -99,3 +99,23 @@
 #
 ##
 { 'command': 'replay-delete-break' }
+
+##
+# @replay-seek:
+#
+# Automatically proceeds to the instruction count @icount, when
+# replaying the execution. The command automatically loads nearest
+# snapshot and replays the execution to find the desired instruction.
+# When there is no preceding snapshot or the execution is not replayed,
+# then the command is ignored and error is returned.
+# icount for the reference may be obtained with @query-replay command.
+#
+# @icount: target instruction count
+#
+# Since: 4.0
+#
+# Example:
+#
+# -> { "execute": "replay-seek", "data": { "icount": 220414 } }
+##
+{ 'command': 'replay-seek', 'data': { 'icount': 'int' } }
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
index a94685e..d99a9c1 100644
--- a/replay/replay-debugging.c
+++ b/replay/replay-debugging.c
@@ -18,6 +18,8 @@
 #include "qapi/qapi-commands-replay.h"
 #include "qapi/qmp/qdict.h"
 #include "qemu/timer.h"
+#include "block/snapshot.h"
+#include "migration/snapshot.h"
 
 void hmp_info_replay(Monitor *mon, const QDict *qdict)
 {
@@ -127,3 +129,93 @@ void hmp_replay_delete_break(Monitor *mon, const QDict 
*qdict)
 return;
 }
 }
+
+static char *replay_find_nearest_snapshot(int64_t icount,
+  int64_t* snapshot_icount)
+{
+BlockDriverState *bs;
+QEMUSnapshotInfo *sn_tab;
+QEMUSnapshotInfo *nearest = NULL;
+char *ret = NULL;
+int nb_sns, i;
+AioContext *aio_context;
+
+*snapshot_icount = -1;
+
+bs = bdrv_all_find_vmstate_bs();
+if (!bs) {
+goto fail;
+}
+aio_context = bdrv_get_aio_context(bs);
+
+aio_context_acquire(aio_context);
+nb_sns = bdrv_snapshot_list(bs, _tab);
+aio_context_release(aio_context);
+
+for (i = 0; i < nb_sns; i++) {
+if (bdrv_all_find_snapshot(sn_tab[i].name, ) == 0) {
+if (sn_tab[i].icount != -1ULL
+&& sn_tab[i].icount <= icount
+&& (!nearest || nearest->icount < sn_tab[i].icount)) {
+nearest = _tab[i];
+}
+}
+}
+if (nearest) {
+ret = g_strdup(nearest->name);
+*snapshot_icount = nearest->icount;
+}
+g_free(sn_tab);
+
+fail:
+return ret;
+}
+
+static void replay_seek(int64_t icount, QEMUTimerCB callback, Error **errp)
+{
+char *snapshot = NULL;
+int64_t snapshot_icount;
+
+if (replay_mode != REPLAY_MODE_PLAY) {
+error_setg(errp, "replay must be enabled to seek");
+return;
+}
+if (!replay_snapshot) {
+

[Qemu-devel] [PATCH v10 14/24] replay: refine replay-time module

2019-01-16 Thread Pavel Dovgalyuk
This patch removes refactoring artifacts from the replay/replay-time.c

Signed-off-by: Pavel Dovgalyuk 
---
 replay/replay-time.c |   36 
 1 file changed, 16 insertions(+), 20 deletions(-)

diff --git a/replay/replay-time.c b/replay/replay-time.c
index 0df1693..60f47b7 100644
--- a/replay/replay-time.c
+++ b/replay/replay-time.c
@@ -15,18 +15,19 @@
 #include "replay-internal.h"
 #include "qemu/error-report.h"
 
-int64_t replay_save_clock(ReplayClockKind kind, int64_t clock, int64_t 
raw_icount)
+int64_t replay_save_clock(ReplayClockKind kind, int64_t clock,
+  int64_t raw_icount)
 {
-if (replay_file) {
-g_assert(replay_mutex_locked());
+g_assert(replay_file);
+g_assert(replay_mutex_locked());
 
-/* Due to the caller's locking requirements we get the icount from it
- * instead of using replay_save_instructions().
- */
-replay_advance_current_step(raw_icount);
-replay_put_event(EVENT_CLOCK + kind);
-replay_put_qword(clock);
-}
+/*
+ * Due to the caller's locking requirements we get the icount from it
+ * instead of using replay_save_instructions().
+ */
+replay_advance_current_step(raw_icount);
+replay_put_event(EVENT_CLOCK + kind);
+replay_put_qword(clock);
 
 return clock;
 }
@@ -48,20 +49,15 @@ void replay_read_next_clock(ReplayClockKind kind)
 /*! Reads next clock event from the input. */
 int64_t replay_read_clock(ReplayClockKind kind)
 {
+int64_t ret;
 g_assert(replay_file && replay_mutex_locked());
 
 replay_account_executed_instructions();
 
-if (replay_file) {
-int64_t ret;
-if (replay_next_event_is(EVENT_CLOCK + kind)) {
-replay_read_next_clock(kind);
-}
-ret = replay_state.cached_clock[kind];
-
-return ret;
+if (replay_next_event_is(EVENT_CLOCK + kind)) {
+replay_read_next_clock(kind);
 }
+ret = replay_state.cached_clock[kind];
 
-error_report("REPLAY INTERNAL ERROR %d", __LINE__);
-exit(1);
+return ret;
 }




[Qemu-devel] [PATCH v10 05/24] replay: don't drain/flush bdrv queue while RR is working

2019-01-16 Thread Pavel Dovgalyuk
In record/replay mode bdrv queue is controlled by replay mechanism.
It does not allow saving or loading the snapshots
when bdrv queue is not empty. Stopping the VM is not blocked by nonempty
queue, but flushing the queue is still impossible there,
because it may cause deadlocks in replay mode.
This patch disables bdrv_drain_all and bdrv_flush_all in
record/replay mode.

Stopping the machine when the IO requests are not finished is needed
for the debugging. E.g., breakpoint may be set at the specified step,
and forcing the IO requests to finish may break the determinism
of the execution.

Signed-off-by: Pavel Dovgalyuk 
---
 block/io.c |   28 
 cpus.c |2 --
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/block/io.c b/block/io.c
index bd9d688..f9a9c5a 100644
--- a/block/io.c
+++ b/block/io.c
@@ -32,6 +32,7 @@
 #include "qemu/cutils.h"
 #include "qapi/error.h"
 #include "qemu/error-report.h"
+#include "sysemu/replay.h"
 
 #define NOT_DONE 0x7fff /* used while emulated sync operation in progress 
*/
 
@@ -538,6 +539,15 @@ void bdrv_drain_all_begin(void)
 return;
 }
 
+/*
+ * bdrv queue is managed by record/replay,
+ * waiting for finishing the I/O requests may
+ * be infinite
+ */
+if (replay_events_enabled()) {
+return;
+}
+
 /* AIO_WAIT_WHILE() with a NULL context can only be called from the main
  * loop AioContext, so make sure we're in the main context. */
 assert(qemu_get_current_aio_context() == qemu_get_aio_context());
@@ -566,6 +576,15 @@ void bdrv_drain_all_end(void)
 {
 BlockDriverState *bs = NULL;
 
+/*
+ * bdrv queue is managed by record/replay,
+ * waiting for finishing the I/O requests may
+ * be endless
+ */
+if (replay_events_enabled()) {
+return;
+}
+
 while ((bs = bdrv_next_all_states(bs))) {
 AioContext *aio_context = bdrv_get_aio_context(bs);
 
@@ -1997,6 +2016,15 @@ int bdrv_flush_all(void)
 BlockDriverState *bs = NULL;
 int result = 0;
 
+/*
+ * bdrv queue is managed by record/replay,
+ * creating new flush request for stopping
+ * the VM may break the determinism
+ */
+if (replay_events_enabled()) {
+return result;
+}
+
 for (bs = bdrv_first(); bs; bs = bdrv_next()) {
 AioContext *aio_context = bdrv_get_aio_context(bs);
 int ret;
diff --git a/cpus.c b/cpus.c
index b09b702..aa33fb1 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1078,7 +1078,6 @@ static int do_vm_stop(RunState state, bool send_stop)
 }
 
 bdrv_drain_all();
-replay_disable_events();
 ret = bdrv_flush_all();
 
 return ret;
@@ -2149,7 +2148,6 @@ int vm_prepare_start(void)
 /* We are sending this now, but the CPUs will be resumed shortly later */
 qapi_event_send_resume();
 
-replay_enable_events();
 cpu_enable_ticks();
 runstate_set(RUN_STATE_RUNNING);
 vm_state_notify(1, RUN_STATE_RUNNING);




[Qemu-devel] [PATCH v10 11/24] replay: introduce info hmp/qmp command

2019-01-16 Thread Pavel Dovgalyuk
This patch introduces 'info replay' monitor command and
corresponding qmp request.
These commands request the current record/replay mode, replay log file
name, and the instruction count (number of recorded/replayed
instructions).  The instruction count can be used with the
replay_seek/replay_break commands added in the next two patches.

Signed-off-by: Pavel Dovgalyuk 
Acked-by: Dr. David Alan Gilbert 

--

v2:
 - renamed info_replay qmp into query-replay (suggested by Eric Blake)
v7:
 - added empty line (suggested by Markus Armbruster)
v9:
 - changed 'step' parameter name to 'icount'
 - moved json stuff to replay.json and updated the descriptions
   (suggested by Markus Armbruster)
v10:
 - updated descriptions and messages for rr stuff
---
 hmp-commands-info.hx  |   14 ++
 hmp.h |1 +
 qapi/block-core.json  |3 ++-
 qapi/replay.json  |   39 +++
 replay/Makefile.objs  |3 ++-
 replay/replay-debugging.c |   43 +++
 6 files changed, 101 insertions(+), 2 deletions(-)
 create mode 100644 replay/replay-debugging.c

diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index cbee8b9..7cc0baa 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -918,6 +918,20 @@ STEXI
 Show SEV information.
 ETEXI
 
+{
+.name   = "replay",
+.args_type  = "",
+.params = "",
+.help   = "show record/replay information",
+.cmd= hmp_info_replay,
+},
+
+STEXI
+@item info replay
+@findex info replay
+Display the record/replay information: mode and the current icount.
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/hmp.h b/hmp.h
index 5f1addc..d792149 100644
--- a/hmp.h
+++ b/hmp.h
@@ -148,5 +148,6 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict 
*qdict);
 void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
 void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict);
 void hmp_info_sev(Monitor *mon, const QDict *qdict);
+void hmp_info_replay(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 6d45c29..d70e584 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -28,7 +28,8 @@
 #
 # @icount: Current instruction count. Appears when execution record/replay
 #  is enabled. Used for "time-traveling" to match the moment
-#  in the recorded execution with the snapshots. (since 4.0)
+#  in the recorded execution with the snapshots. This counter may
+#  be obtained through @query-replay command (since 4.0)
 #
 # Since: 1.3
 #
diff --git a/qapi/replay.json b/qapi/replay.json
index 9e13551..ef2fb4b 100644
--- a/qapi/replay.json
+++ b/qapi/replay.json
@@ -24,3 +24,42 @@
 ##
 { 'enum': 'ReplayMode',
   'data': [ 'none', 'record', 'play' ] }
+
+##
+# @ReplayInfo:
+#
+# Record/replay information.
+#
+# @mode: current mode.
+#
+# @filename: name of the record/replay log file.
+#It is present only in record or replay modes, when the log
+#is recorded or replayed.
+#
+# @icount: current number of executed instructions.
+#
+# Since: 4.0
+#
+##
+{ 'struct': 'ReplayInfo',
+  'data': { 'mode': 'ReplayMode', '*filename': 'str', 'icount': 'int' } }
+
+##
+# @query-replay:
+#
+# Retrieves the record/replay information.
+# It includes current instruction count which may be used for replay-break and
+# replay-seek commands.
+#
+# Returns: record/replay information.
+#
+# Since: 4.0
+#
+# Example:
+#
+# -> { "execute": "query-replay" }
+# <- { "return": { "mode": "play", "filename": "log.rr", "icount": 220414 } }
+#
+##
+{ 'command': 'query-replay',
+  'returns': 'ReplayInfo' }
diff --git a/replay/Makefile.objs b/replay/Makefile.objs
index cee6539..6694e3e 100644
--- a/replay/Makefile.objs
+++ b/replay/Makefile.objs
@@ -6,4 +6,5 @@ common-obj-y += replay-input.o
 common-obj-y += replay-char.o
 common-obj-y += replay-snapshot.o
 common-obj-y += replay-net.o
-common-obj-y += replay-audio.o
\ No newline at end of file
+common-obj-y += replay-audio.o
+common-obj-y += replay-debugging.o
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
new file mode 100644
index 000..51f1c4d
--- /dev/null
+++ b/replay/replay-debugging.c
@@ -0,0 +1,43 @@
+/*
+ * replay-debugging.c
+ *
+ * Copyright (c) 2010-2018 Institute for System Programming
+ * of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "sysemu/replay.h"
+#include "replay-internal.h"
+#include "hmp.h"
+#include "monitor/monitor.h"
+#include "qapi/qapi-commands-replay.h"
+
+void hmp_info_replay(Monitor *mon, const QDict *qdict)
+{
+if (replay_mode == REPLAY_MODE_NONE) {
+monitor_printf(mon, "Record/replay is not 

[Qemu-devel] [PATCH v10 04/24] replay: update docs for record/replay with block devices

2019-01-16 Thread Pavel Dovgalyuk
This patch updates the description of the command lines for using
record/replay with attached block devices.

Signed-off-by: Pavel Dovgalyuk 
---
 docs/replay.txt |   12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/docs/replay.txt b/docs/replay.txt
index 3497585..2c2c5f6 100644
--- a/docs/replay.txt
+++ b/docs/replay.txt
@@ -27,7 +27,7 @@ Usage of the record/replay:
  * First, record the execution with the following command line:
 qemu-system-i386 \
  -icount shift=7,rr=record,rrfile=replay.bin \
- -drive file=disk.qcow2,if=none,id=img-direct \
+ -drive file=disk.qcow2,if=none,snapshot,id=img-direct \
  -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \
  -device ide-hd,drive=img-blkreplay \
  -netdev user,id=net1 -device rtl8139,netdev=net1 \
@@ -35,7 +35,7 @@ Usage of the record/replay:
  * After recording, you can replay it by using another command line:
 qemu-system-i386 \
  -icount shift=7,rr=replay,rrfile=replay.bin \
- -drive file=disk.qcow2,if=none,id=img-direct \
+ -drive file=disk.qcow2,if=none,snapshot,id=img-direct \
  -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay \
  -device ide-hd,drive=img-blkreplay \
  -netdev user,id=net1 -device rtl8139,netdev=net1 \
@@ -223,7 +223,7 @@ Block devices record/replay module intercepts calls of
 bdrv coroutine functions at the top of block drivers stack.
 To record and replay block operations the drive must be configured
 as following:
- -drive file=disk.qcow2,if=none,id=img-direct
+ -drive file=disk.qcow2,if=none,snapshot,id=img-direct
  -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
  -device ide-hd,drive=img-blkreplay
 
@@ -252,6 +252,12 @@ This snapshot is created at start of recording and 
restored at start
 of replaying. It also can be loaded while replaying to roll back
 the execution.
 
+'snapshot' flag of the disk image must be removed to save the snapshots
+in the overlay (or original image) instead of using the temporary overlay.
+ -drive file=disk.ovl,if=none,id=img-direct
+ -drive driver=blkreplay,if=none,image=img-direct,id=img-blkreplay
+ -device ide-hd,drive=img-blkreplay
+
 Use QEMU monitor to create additional snapshots. 'savevm ' command
 created the snapshot and 'loadvm ' restores it. To prevent corruption
 of the original disk image, use overlay files linked to the original images.




[Qemu-devel] [PATCH v10 00/24] Fixing record/replay and adding reverse debugging

2019-01-16 Thread Pavel Dovgalyuk
GDB remote protocol supports reverse debugging of the targets.
It includes 'reverse step' and 'reverse continue' operations.
The first one finds the previous step of the execution,
and the second one is intended to stop at the last breakpoint that
would happen when the program is executed normally.

Reverse debugging is possible in the replay mode, when at least
one snapshot was created at the record or replay phase.
QEMU can use these snapshots for travelling back in time with GDB.

Running the execution in replay mode allows using GDB reverse debugging
commands:
 - reverse-stepi (or rsi): Steps one instruction to the past.
   QEMU loads on of the prior snapshots and proceeds to the desired
   instruction forward. When that step is reaches, execution stops.
 - reverse-continue (or rc): Runs execution "backwards".
   QEMU tries to find breakpoint or watchpoint by loaded prior snapshot
   and replaying the execution. Then QEMU loads snapshots again and
   replays to the latest breakpoint. When there are no breakpoints in
   the examined section of the execution, QEMU finds one more snapshot
   and tries again. After the first snapshot is processed, execution
   stops at this snapshot.

The set of patches include the following modifications:
 - gdbstub update for reverse debugging support
 - functions that automatically perform reverse step and reverse
   continue operations
 - hmp/qmp commands for manipulating the replay process
 - improvement of the snapshotting for saving the execution step
   in the snapshot parameters
 - other record/replay fixes

The patches are available in the repository:
https://github.com/ispras/qemu/tree/rr-190117

v10 changes:
 - added patch for correct deadline calculation with external timers
 - updated icount-related documentation in json files
   (suggested by Markus Armbruster)
 - fixed replay shutdown
 - renamed some functions and variables to make them consistent with
   the documentation and displayed messages
 - minor changes

v9 changes:
 - moved rr qapi stuff to the separate file (suggested by Markus Armbruster)
 - minor coding style fixes

v8 changes:
 - rebased to the new master
 - added missing fix for prior rr patch
 - updated 'since' version number in json-related patches

v7 changes:
 - rebased to the new master with upstreamed patches from the series
 - several improvements in hmp/qmp commands handling (suggested by Markus 
Armbruster)
 - fixed record/replay with '-rtc base' option enabled
 - added document with virtual hardware requirements

v6 changes:
 - rebased to the new version of master
 - fixed build of linux-user configurations
 - added new clock for slirp and vnc timers

v5 changes:
 - multiple fixes of record/replay bugs appeared after QEMU core update
 - changed reverse debugging to 'since 3.1'

v4 changes:
 - changed 'since 2.13' to 'since 3.0' in json (as suggested by Eric Blake)

v3 changes:
 - Fixed PS/2 bug with save/load vm, which caused failures of the replay.
 - Rebased to the new code base.
 - Minor fixes.

v2 changes:
 - documented reverse debugging
 - fixed start vmstate loading in record mode
 - documented qcow2 changes (as suggested by Eric Blake)
 - made icount SnapshotInfo field optional (as suggested by Eric Blake)
 - renamed qmp commands (as suggested by Eric Blake)
 - minor changes

---

Pavel Dovgalyuk (23):
  block: implement bdrv_snapshot_goto for blkreplay
  replay: disable default snapshot for record/replay
  replay: update docs for record/replay with block devices
  replay: don't drain/flush bdrv queue while RR is working
  replay: finish record/replay before closing the disks
  qcow2: introduce icount field for snapshots
  migration: introduce icount field for snapshots
  replay: provide an accessor for rr filename
  qapi: introduce replay.json for record/replay-related stuff
  replay: introduce info hmp/qmp command
  replay: introduce breakpoint at the specified step
  replay: implement replay-seek command
  replay: refine replay-time module
  replay: flush rr queue before loading the vmstate
  gdbstub: add reverse step support in replay mode
  gdbstub: add reverse continue support in replay mode
  replay: describe reverse debugging in docs/replay.txt
  replay: add BH oneshot event for block layer
  replay: init rtc after enabling the replay
  replay: document development rules
  util/qemu-timer: refactor deadline calculation for external timers
  replay: fix replay shutdown
  replay: rename step-related variables and functions

pbonz...@redhat.com (1):
  replay: add missing fix for internal function


 MAINTAINERS   |1 
 Makefile.objs |4 -
 accel/tcg/translator.c|1 
 block/blkreplay.c |8 +
 block/block-backend.c |8 +
 block/io.c|   32 
 block/iscsi.c |5 -
 block/nfs.c   |5 -
 block/null.c  |4 -
 

[Qemu-devel] [PATCH v10 10/24] qapi: introduce replay.json for record/replay-related stuff

2019-01-16 Thread Pavel Dovgalyuk
This patch adds replay.json file. It will be
used for adding record/replay-related data structures and commands.

Signed-off-by: Pavel Dovgalyuk 

--

v10:
 - minor changes
---
 MAINTAINERS |1 +
 Makefile.objs   |4 ++--
 include/sysemu/replay.h |2 +-
 qapi/misc.json  |   18 --
 qapi/qapi-schema.json   |1 +
 qapi/replay.json|   26 ++
 6 files changed, 31 insertions(+), 21 deletions(-)
 create mode 100644 qapi/replay.json

diff --git a/MAINTAINERS b/MAINTAINERS
index af339b8..3bfa333 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2138,6 +2138,7 @@ F: net/filter-replay.c
 F: include/sysemu/replay.h
 F: docs/replay.txt
 F: stubs/replay.c
+F: qapi/replay.json
 
 IOVA Tree
 M: Peter Xu 
diff --git a/Makefile.objs b/Makefile.objs
index 4561159..8164b22 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -1,6 +1,6 @@
 QAPI_MODULES = block-core block char common crypto introspect job migration
-QAPI_MODULES += misc net rdma rocker run-state sockets tpm trace transaction
-QAPI_MODULES += ui
+QAPI_MODULES += misc net rdma replay rocker run-state sockets tpm trace
+QAPI_MODULES += transaction ui
 
 ###
 # Common libraries for tools and emulators
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index b3f593f..3fe14b5 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -13,7 +13,7 @@
  */
 
 #include "sysemu.h"
-#include "qapi/qapi-types-misc.h"
+#include "qapi/qapi-types-replay.h"
 #include "qapi/qapi-types-ui.h"
 
 /* replay clock kinds */
diff --git a/qapi/misc.json b/qapi/misc.json
index 24d20a8..e5e0bea 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -3125,24 +3125,6 @@
   'data': { 'offset': 'int' } }
 
 ##
-# @ReplayMode:
-#
-# Mode of the replay subsystem.
-#
-# @none: normal execution mode. Replay or record are not enabled.
-#
-# @record: record mode. All non-deterministic data is written into the
-#  replay log.
-#
-# @play: replay mode. Non-deterministic data required for system execution
-#is read from the log.
-#
-# Since: 2.5
-##
-{ 'enum': 'ReplayMode',
-  'data': [ 'none', 'record', 'play' ] }
-
-##
 # @xen-load-devices-state:
 #
 # Load the state of all devices from file. The RAM and the block devices
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index 3bbdfce..6d3fa9f 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -94,4 +94,5 @@
 { 'include': 'transaction.json' }
 { 'include': 'trace.json' }
 { 'include': 'introspect.json' }
+{ 'include': 'replay.json' }
 { 'include': 'misc.json' }
diff --git a/qapi/replay.json b/qapi/replay.json
new file mode 100644
index 000..9e13551
--- /dev/null
+++ b/qapi/replay.json
@@ -0,0 +1,26 @@
+# -*- Mode: Python -*-
+#
+
+##
+# = Record/replay
+##
+
+{ 'include': 'common.json' }
+
+##
+# @ReplayMode:
+#
+# Mode of the replay subsystem.
+#
+# @none: normal execution mode. Replay or record are not enabled.
+#
+# @record: record mode. All non-deterministic data is written into the
+#  replay log.
+#
+# @play: replay mode. Non-deterministic data required for system execution
+#is read from the log.
+#
+# Since: 2.5
+##
+{ 'enum': 'ReplayMode',
+  'data': [ 'none', 'record', 'play' ] }




[Qemu-devel] [PATCH v10 08/24] migration: introduce icount field for snapshots

2019-01-16 Thread Pavel Dovgalyuk
Saving icount as a parameters of the snapshot allows navigation between
them in the execution replay scenario.
This information can be used for finding a specific snapshot for proceeding
the recorded execution to the specific moment of the time.
E.g., 'reverse step' action (introduced in one of the following patches)
needs to load the nearest snapshot which is prior to the current moment
of time .

Signed-off-by: Pavel Dovgalyuk 

--

v2:
 - made icount in SnapshotInfo optional (suggested by Eric Blake)
v7:
 - added more comments for icount member (suggested by Markus Armbruster)
v9:
 - updated icount comment
v10:
 - updated icount comment again
---
 block/qapi.c |   18 ++
 block/qcow2-snapshot.c   |2 ++
 blockdev.c   |   10 ++
 include/block/snapshot.h |1 +
 migration/savevm.c   |5 +
 qapi/block-core.json |7 ++-
 qapi/block.json  |3 ++-
 7 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/block/qapi.c b/block/qapi.c
index c66f949..ccf23f3 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -210,6 +210,8 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
 info->date_nsec = sn_tab[i].date_nsec;
 info->vm_clock_sec  = sn_tab[i].vm_clock_nsec / 10;
 info->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 10;
+info->icount= sn_tab[i].icount;
+info->has_icount= sn_tab[i].icount != -1ULL;
 
 info_list = g_new0(SnapshotInfoList, 1);
 info_list->value = info;
@@ -663,14 +665,15 @@ void bdrv_snapshot_dump(fprintf_function func_fprintf, 
void *f,
 QEMUSnapshotInfo *sn)
 {
 char buf1[128], date_buf[128], clock_buf[128];
+char icount_buf[128] = {0};
 struct tm tm;
 time_t ti;
 int64_t secs;
 
 if (!sn) {
 func_fprintf(f,
- "%-10s%-20s%7s%20s%15s",
- "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
+ "%-10s%-18s%7s%20s%13s%11s",
+ "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK", "ICOUNT");
 } else {
 ti = sn->date_sec;
 localtime_r(, );
@@ -683,13 +686,18 @@ void bdrv_snapshot_dump(fprintf_function func_fprintf, 
void *f,
  (int)((secs / 60) % 60),
  (int)(secs % 60),
  (int)((sn->vm_clock_nsec / 100) % 1000));
+if (sn->icount != -1ULL) {
+snprintf(icount_buf, sizeof(icount_buf),
+"%"PRId64, sn->icount);
+}
 func_fprintf(f,
- "%-10s%-20s%7s%20s%15s",
+ "%-10s%-18s%7s%20s%13s%11s",
  sn->id_str, sn->name,
  get_human_readable_size(buf1, sizeof(buf1),
  sn->vm_state_size),
  date_buf,
- clock_buf);
+ clock_buf,
+ icount_buf);
 }
 }
 
@@ -857,6 +865,8 @@ void bdrv_image_info_dump(fprintf_function func_fprintf, 
void *f,
 .date_nsec = elem->value->date_nsec,
 .vm_clock_nsec = elem->value->vm_clock_sec * 10ULL +
  elem->value->vm_clock_nsec,
+.icount = elem->value->has_icount ?
+  elem->value->icount : -1ULL,
 };
 
 pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id);
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index d682946..96b57f4 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -379,6 +379,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, 
QEMUSnapshotInfo *sn_info)
 sn->date_sec = sn_info->date_sec;
 sn->date_nsec = sn_info->date_nsec;
 sn->vm_clock_nsec = sn_info->vm_clock_nsec;
+sn->icount = sn_info->icount;
 
 /* Allocate the L1 table of the snapshot and copy the current one there. */
 l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
@@ -698,6 +699,7 @@ int qcow2_snapshot_list(BlockDriverState *bs, 
QEMUSnapshotInfo **psn_tab)
 sn_info->date_sec = sn->date_sec;
 sn_info->date_nsec = sn->date_nsec;
 sn_info->vm_clock_nsec = sn->vm_clock_nsec;
+sn_info->icount = sn->icount;
 }
 *psn_tab = sn_tab;
 return s->nb_snapshots;
diff --git a/blockdev.c b/blockdev.c
index a8fa874..1f4499c 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -57,6 +57,7 @@
 #include "block/trace.h"
 #include "sysemu/arch_init.h"
 #include "sysemu/qtest.h"
+#include "sysemu/replay.h"
 #include "qemu/cutils.h"
 #include "qemu/help_option.h"
 #include "qemu/throttle-options.h"
@@ -1239,6 +1240,10 @@ SnapshotInfo 
*qmp_blockdev_snapshot_delete_internal_sync(const char *device,
 info->vm_state_size = sn.vm_state_size;
 info->vm_clock_nsec = sn.vm_clock_nsec % 10;
 info->vm_clock_sec = sn.vm_clock_nsec / 10;
+if (sn.icount != 

[Qemu-devel] [PATCH v10 03/24] replay: disable default snapshot for record/replay

2019-01-16 Thread Pavel Dovgalyuk
From: Pavel Dovgalyuk 

This patch disables setting '-snapshot' option on by default
in record/replay mode. This is needed for creating vmstates in record
and replay modes.

Signed-off-by: Pavel Dovgalyuk 
---
 vl.c |   10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/vl.c b/vl.c
index bc9fbec..bea05cd 100644
--- a/vl.c
+++ b/vl.c
@@ -3196,7 +3196,13 @@ int main(int argc, char **argv, char **envp)
 drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS);
 break;
 case QEMU_OPTION_snapshot:
-snapshot = 1;
+{
+Error *blocker = NULL;
+snapshot = 1;
+error_setg(, QERR_REPLAY_NOT_SUPPORTED,
+   "-snapshot");
+replay_add_blocker(blocker);
+}
 break;
 case QEMU_OPTION_numa:
 opts = qemu_opts_parse_noisily(qemu_find_opts("numa"),
@@ -4465,7 +4471,7 @@ int main(int argc, char **argv, char **envp)
 qapi_free_BlockdevOptions(bdo->bdo);
 g_free(bdo);
 }
-if (snapshot || replay_mode != REPLAY_MODE_NONE) {
+if (snapshot) {
 qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot,
   NULL, NULL);
 }




[Qemu-devel] [PATCH v10 02/24] block: implement bdrv_snapshot_goto for blkreplay

2019-01-16 Thread Pavel Dovgalyuk
From: Pavel Dovgalyuk 

This patch enables making snapshots with blkreplay used in
block devices.
This function is required to make bdrv_snapshot_goto without
calling .bdrv_open which is not implemented.

Signed-off-by: Pavel Dovgalyuk 
---
 block/blkreplay.c |8 
 1 file changed, 8 insertions(+)

diff --git a/block/blkreplay.c b/block/blkreplay.c
index b5d9efd..142dfe3 100644
--- a/block/blkreplay.c
+++ b/block/blkreplay.c
@@ -126,6 +126,12 @@ static int coroutine_fn 
blkreplay_co_flush(BlockDriverState *bs)
 return ret;
 }
 
+static int blkreplay_snapshot_goto(BlockDriverState *bs,
+   const char *snapshot_id)
+{
+return bdrv_snapshot_goto(bs->file->bs, snapshot_id, NULL);
+}
+
 static BlockDriver bdrv_blkreplay = {
 .format_name= "blkreplay",
 .instance_size  = 0,
@@ -140,6 +146,8 @@ static BlockDriver bdrv_blkreplay = {
 .bdrv_co_pwrite_zeroes  = blkreplay_co_pwrite_zeroes,
 .bdrv_co_pdiscard   = blkreplay_co_pdiscard,
 .bdrv_co_flush  = blkreplay_co_flush,
+
+.bdrv_snapshot_goto = blkreplay_snapshot_goto,
 };
 
 static void bdrv_blkreplay_init(void)




[Qemu-devel] [PATCH v10 01/24] replay: add missing fix for internal function

2019-01-16 Thread Pavel Dovgalyuk
From: pbonz...@redhat.com 

This is a fix which was missed by patch
74c0b816adfc6aa1b01b4426fdf385e32e35cbac, which added current_step
parameter to the replay_advance_current_step function.

Signed-off-by: Pavel Dovgalyuk 
---
 replay/replay-internal.c |2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/replay/replay-internal.c b/replay/replay-internal.c
index 8f87e9b..7e6de03 100644
--- a/replay/replay-internal.c
+++ b/replay/replay-internal.c
@@ -229,7 +229,7 @@ void replay_mutex_unlock(void)
 
 void replay_advance_current_step(uint64_t current_step)
 {
-int diff = (int)(replay_get_current_step() - replay_state.current_step);
+int diff = (int)(current_step - replay_state.current_step);
 
 /* Time can only go forward */
 assert(diff >= 0);




Re: [Qemu-devel] [Qemu-ppc] [PATCH v5 2/3] ppc: Fix duplicated typedefs to be able to compile with Clang in gnu99 mode

2019-01-16 Thread Thomas Huth
On 2019-01-16 14:29, Cédric Le Goater wrote:
> On 1/16/19 12:47 PM, Thomas Huth wrote:
>> On 2019-01-16 12:43, Cédric Le Goater wrote:
>>> On 1/11/19 9:17 AM, Thomas Huth wrote:
 When compiling the ppc code with clang and -std=gnu99, there are a
 couple of warnings/errors like this one:

   CC  ppc64-softmmu/hw/intc/xics.o
 In file included from hw/intc/xics.c:35:
 include/hw/ppc/xics.h:43:25: error: redefinition of typedef 'ICPState' is 
 a C11 feature
   [-Werror,-Wtypedef-redefinition]
 typedef struct ICPState ICPState;
 ^
 target/ppc/cpu.h:1181:25: note: previous definition is here
 typedef struct ICPState ICPState;
 ^
 Work around the problems by including the proper headers instead.
>>>
>>> Thomas,
>>>
>>>
>>> After a closer look, I think we should use 'void *' under PowerPCCPU 
>>> as it was the case before I introduced the second interrupt presenter.
>>
>> If you don't like the #includes, why not simply do anonymous struct
>> forward declarations here? I think that would be better than "void *".
> 
> yes.
>  
>>> That's a bigger change reverting bits of already merged patches. I can
>>> take care of it if you prefer. 
>>
>> Could I keep the current patch in my series so that I can get the
>> patches finally merged? You could then do any clean up that you like on
>> top of it, ok?
> 
> OK. 
> 
> See below the patch I would propose. Compiled tested with clang -std=gnu99.
[...]
> @@ -1204,8 +1199,8 @@ struct PowerPCCPU {
>  int32_t node_id; /* NUMA node this CPU belongs to */
>  PPCHash64Options *hash64_opts;
>  #ifndef CONFIG_USER_ONLY
> -ICPState *icp;
> -XiveTCTX *tctx;
> +struct ICPState *icp;
> +struct XiveTCTX *tctx;
>  #endif

That's pretty much what I had in an earlier version of my patch:

https://lists.gnu.org/archive/html/qemu-devel/2019-01/msg01810.html

But Greg did not like it:

https://lists.gnu.org/archive/html/qemu-devel/2019-01/msg01893.html

 Thomas



Re: [Qemu-devel] [PATCH v2] .cirrus.yml: basic compile and test for FreeBSD

2019-01-16 Thread Thomas Huth
On 2019-01-16 20:19, Ed Maste wrote:
> From: Ed Maste 
> 
> Signed-off-by: Ed Maste 
> Reviewed-by: Alex Bennée 
> ---
>  .cirrus.yml | 16 
>  MAINTAINERS |  8 
>  2 files changed, 24 insertions(+)
>  create mode 100644 .cirrus.yml
> 
> diff --git a/.cirrus.yml b/.cirrus.yml
> new file mode 100644
> index 00..df39d8e573
> --- /dev/null
> +++ b/.cirrus.yml
> @@ -0,0 +1,16 @@
> +freebsd_12_task:
> +  freebsd_instance:
> +image: freebsd-12-0-release-amd64
> +cpu: 8
> +memory: 24G
> +  env:
> +CIRRUS_CLONE_DEPTH: 1
> +  install_script: pkg install -y
> +bison curl cyrus-sasl fontconfig freetype2 git glib gmake gnutls

I'm still wondering why you need fontconfig and freetype2 here?

> +nettle perl5 pixman pkgconf png usbredir
> +  script:
> +- mkdir build
> +- cd build
> +- ../configure || { cat config.log; exit 1; }
> +- gmake -j8 V=1
> +- gmake -j8 V=1 check
 Thomas



Re: [Qemu-devel] [PATCH v2 4/7] softfloat: fallback to __int128 maths for s390x and others

2019-01-16 Thread Thomas Huth
On 2019-01-16 21:23, Alex Bennée wrote:
> Apparently some versions of clang can't handle inline assembly with
> __int128 parameters, especially on s390. Instead of hand-coding the
> s390 divide provide a generic fallback for anything that provides
> __int128 capable maths.
> 
> Signed-off-by: Alex Bennée 
> Cc: Thomas Huth 
> ---
>  include/fpu/softfloat-macros.h | 10 --
>  1 file changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h
> index b1d772e6d4..1a43609eef 100644
> --- a/include/fpu/softfloat-macros.h
> +++ b/include/fpu/softfloat-macros.h
> @@ -641,12 +641,6 @@ static inline uint64_t udiv_qrnnd(uint64_t *r, uint64_t 
> n1,
>  uint64_t q;
>  asm("divq %4" : "=a"(q), "=d"(*r) : "0"(n0), "1"(n1), "rm"(d));
>  return q;
> -#elif defined(__s390x__)
> -/* Need to use a TImode type to get an even register pair for DLGR.  */
> -unsigned __int128 n = (unsigned __int128)n1 << 64 | n0;
> -asm("dlgr %0, %1" : "+r"(n) : "r"(d));
> -*r = n >> 64;
> -return n;
>  #elif defined(_ARCH_PPC64) && defined(_ARCH_PWR7)
>  /* From Power ISA 2.06, programming note for divdeu.  */
>  uint64_t q1, q2, Q, r1, r2, R;
> @@ -663,6 +657,10 @@ static inline uint64_t udiv_qrnnd(uint64_t *r, uint64_t 
> n1,
>  }
>  *r = R;
>  return Q;
> +#elif defined(CONFIG_INT128)
> +unsigned __int128 n = (unsigned __int128)n1 << 64 | n0;
> +*r = n % d;
> +return n / d;
>  #else
>  uint64_t d0, d1, q0, q1, r1, r0, m;

No, please don't. Use my !defined(__clang__) patch instead, please.

 Thomas



Re: [Qemu-devel] [PATCH] include/fpu/softfloat: Fix compilation with Clang on s390x

2019-01-16 Thread Thomas Huth
On 2019-01-16 18:08, Alex Bennée wrote:
> 
> Thomas Huth  writes:
> 
>> On 2019-01-15 21:05, Emilio G. Cota wrote:
>>> On Tue, Jan 15, 2019 at 16:01:32 +, Alex Bennée wrote:
 Ahh I should have mentioned we already have the technology for this ;-)

 If you build the fpu/next tree on a s390x you can then run:

   ./tests/fp/fp-bench f64_div

 with and without the CONFIG_128 path. To get an idea of the real world
 impact you can compile a foreign binary and run it on a s390x system
 with:

   $QEMU ./tests/fp/fp-bench f64_div -t host

 And that will give you the peak performance assuming your program is
 doing nothing but f64_div operations. If the two QEMU's are basically in
 the same ballpark then it doesn't make enough difference. That said:
>>>
>>> I think you mean here `tests/fp/fp-bench -o div -p double', otherwise
>>> you'll get the default op (-o add).
>>
>> I tried that now, too, and -o div -p double does not really seem to
>> exercise this function at all.
> 
> How do you mean? It should do because by default it should be calling
> the softfloat implementations.

I've added a puts("hello") into the udiv_qrnd() function. When I then
run "fp-bench -o div -p double", it only prints out "hello" a single
time, so the function is only called once during the whole test.

 Thomas



Re: [Qemu-devel] [PATCH v3 20/50] paaudio: properly disconnect streams in fini_*

2019-01-16 Thread Marc-André Lureau
Hi

On Thu, Jan 17, 2019 at 3:37 AM Kővágó, Zoltán  wrote:
>
> Currently this needs a workaround due to bug #74624 in pulseaudio.
>
> Reviewed-by: Marc-André Lureau 
> Signed-off-by: Kővágó, Zoltán 
> ---
>  audio/paaudio.c | 25 +++--
>  1 file changed, 23 insertions(+), 2 deletions(-)
>
> diff --git a/audio/paaudio.c b/audio/paaudio.c
> index 108d3158a6..428c848863 100644
> --- a/audio/paaudio.c
> +++ b/audio/paaudio.c
> @@ -680,6 +680,27 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings 
> *as, void *drv_opaque)
>  return -1;
>  }
>
> +static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
> +{
> +int err;
> +
> +pa_threaded_mainloop_lock(c->mainloop);
> +/*
> + * wait until actually connects. workaround pa bug #74624
> + * https://bugs.freedesktop.org/show_bug.cgi?id=74624

Now that they moved to gitlab, you could update the link & # in commit message
https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247

> + */
> +while (pa_stream_get_state(stream) == PA_STREAM_CREATING) {
> +pa_threaded_mainloop_wait(c->mainloop);
> +}
> +
> +err = pa_stream_disconnect(stream);
> +if (err != 0) {
> +dolog("Failed to dissconnect! err=%d\n", err);
> +}
> +pa_stream_unref(stream);
> +pa_threaded_mainloop_unlock(c->mainloop);
> +}
> +
>  static void qpa_fini_out (HWVoiceOut *hw)
>  {
>  void *ret;
> @@ -691,7 +712,7 @@ static void qpa_fini_out (HWVoiceOut *hw)
>  audio_pt_join(>pt, , __func__);
>
>  if (pa->stream) {
> -pa_stream_unref (pa->stream);
> +qpa_simple_disconnect(pa->g->conn, pa->stream);
>  pa->stream = NULL;
>  }
>
> @@ -711,7 +732,7 @@ static void qpa_fini_in (HWVoiceIn *hw)
>  audio_pt_join(>pt, , __func__);
>
>  if (pa->stream) {
> -pa_stream_unref (pa->stream);
> +qpa_simple_disconnect(pa->g->conn, pa->stream);
>  pa->stream = NULL;
>  }
>
> --
> 2.20.1
>



Re: [Qemu-devel] [PATCH] include/fpu/softfloat: Fix compilation with Clang on s390x

2019-01-16 Thread Thomas Huth
On 2019-01-16 18:16, Alex Bennée wrote:
> 
> Cornelia Huck  writes:
> 
>> On Mon, 14 Jan 2019 13:12:35 +0100
>> Thomas Huth  wrote:
>>
> 
>>>
>>> diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h
>>> index b1d772e..bd5b641 100644
>>> --- a/include/fpu/softfloat-macros.h
>>> +++ b/include/fpu/softfloat-macros.h
>>> @@ -641,7 +641,7 @@ static inline uint64_t udiv_qrnnd(uint64_t *r, uint64_t 
>>> n1,
>>>  uint64_t q;
>>>  asm("divq %4" : "=a"(q), "=d"(*r) : "0"(n0), "1"(n1), "rm"(d));
>>>  return q;
>>> -#elif defined(__s390x__)
>>> +#elif defined(__s390x__) && !defined(__clang__)
>>>  /* Need to use a TImode type to get an even register pair for DLGR.  */
>>>  unsigned __int128 n = (unsigned __int128)n1 << 64 | n0;
>>>  asm("dlgr %0, %1" : "+r"(n) : "r"(d));
>>
>> Ok, so what's the deal with this patch now? Fix compilation now,
>> optimize later?
>>
>> If yes, should I pick it as an s390x build fix (I plan to send a pull
>> request later this week), or will the fpu maintainers pick it?
> 
> I'm planning to send a FPU PR tomorrow and I'll happily include either
> version.
> 
> I'm personally minded to go with the patch that makes s390 (and others)
> fall back to the generic CONFIG_INT128 code. The numbers Thomas gathered
> didn't look like it was much difference either way.
> 
> Unless you *really* care about milking that last bit of performance out of
> the s390 TCG back-end?

I don't think that anybody buys a mainframe for this special case ;-)
I'd go with the !defined(__clang__) patch above.

 Thomas



Re: [Qemu-devel] [PATCH] accel: Allow to build QEMU without TCG or KVM support

2019-01-16 Thread Thomas Huth
On 2019-01-16 18:35, Anthony PERARD wrote:
> Instead of deny build of QEMU without a default accelerator, simply
> report an error when the user haven't passed -accel or -machine accel=
> and TCG and KVM isn't builtin.
> 
> ./configure already check that at least one accelerator is available.
> 
> Signed-off-by: Anthony PERARD 
> ---
>  accel/accel.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/accel/accel.c b/accel/accel.c
> index 68b6d56323..0d5b370dfd 100644
> --- a/accel/accel.c
> +++ b/accel/accel.c
> @@ -91,7 +91,9 @@ void configure_accelerator(MachineState *ms, const char 
> *progname)
>  #elif defined(CONFIG_KVM)
>  accel = "kvm";
>  #else
> -#error "No default accelerator available"
> +error_report("No accelerator selected and"
> + " no default accelerator available");
> +exit(1);
>  #endif
>  }
>  }

That looks a little bit friendlier, indeed.

Reviewed-by: Thomas Huth 

Out of curiosity: Did you hit the #error while compiling? Or just by
reading the recent patches?

 Thomas



Re: [Qemu-devel] [PATCH 2/2] vfio-pci: Use vfio_register_event_notifier in vfio_intx_enable_kvm

2019-01-16 Thread Alexey Kardashevskiy



On 12/01/2019 03:58, Eric Auger wrote:
> We can also use vfio_register_event_notifier() helper in
> vfio_intx_enable_kvm to set the signalling associated to
> VFIO_PCI_INTX_IRQ_INDEX.
> 
> Signed-off-by: Eric Auger 
> ---
>  hw/vfio/pci.c | 38 +++---
>  1 file changed, 7 insertions(+), 31 deletions(-)
> 
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index c589a4e666..db0504ca10 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -136,6 +136,9 @@ static int vfio_register_event_notifier(VFIOPCIDevice 
> *vdev,
>  case VFIO_PCI_ERR_IRQ_INDEX:
>  notifier = >err_notifier;
>  break;
> +case VFIO_PCI_INTX_IRQ_INDEX:
> +notifier = >intx.interrupt;
> +break;
>  default:
>  return -EINVAL;
>  }
> @@ -351,10 +354,8 @@ static void vfio_intx_update(PCIDevice *pdev)
>  static int vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp)
>  {
>  uint8_t pin = vfio_pci_read_config(>pdev, PCI_INTERRUPT_PIN, 1);
> -int ret, argsz, retval = 0;
> -struct vfio_irq_set *irq_set;
> -int32_t *pfd;
>  Error *err = NULL;
> +int ret;
>  
>  if (!pin) {
>  return 0;
> @@ -376,34 +377,12 @@ static int vfio_intx_enable(VFIOPCIDevice *vdev, Error 
> **errp)
>  }
>  #endif
>  
> -ret = event_notifier_init(>intx.interrupt, 0);
> +ret = vfio_register_event_notifier(vdev, VFIO_PCI_INTX_IRQ_INDEX, true,
> +   vfio_intx_interrupt, errp);
>  if (ret) {
> -error_setg_errno(errp, -ret, "event_notifier_init failed");
>  return ret;
>  }
>  
> -argsz = sizeof(*irq_set) + sizeof(*pfd);
> -
> -irq_set = g_malloc0(argsz);
> -irq_set->argsz = argsz;
> -irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
> -irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
> -irq_set->start = 0;
> -irq_set->count = 1;
> -pfd = (int32_t *)_set->data;
> -
> -*pfd = event_notifier_get_fd(>intx.interrupt);
> -qemu_set_fd_handler(*pfd, vfio_intx_interrupt, NULL, vdev);
> -
> -ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
> -if (ret) {
> -error_setg_errno(errp, -ret, "failed to setup INTx fd");
> -qemu_set_fd_handler(*pfd, NULL, NULL, vdev);
> -event_notifier_cleanup(>intx.interrupt);


After this change if ioctl(VFIO_DEVICE_SET_IRQS) failed, there will be
no event_notifier_cleanup() called as this new
vfio_register_event_notifier() does not do this either.


> -retval = -errno;
> -goto cleanup;
> -}
> -
>  vfio_intx_enable_kvm(vdev, );
>  if (err) {
>  warn_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
> @@ -413,10 +392,7 @@ static int vfio_intx_enable(VFIOPCIDevice *vdev, Error 
> **errp)
>  
>  trace_vfio_intx_enable(vdev->vbasedev.name);
>  
> -cleanup:
> -g_free(irq_set);
> -
> -return retval;
> +return 0;
>  }
>  
>  static void vfio_intx_disable(VFIOPCIDevice *vdev)
> 

-- 
Alexey



Re: [Qemu-devel] [PATCH 1/2] vfio-pci: Introduce vfio_register_event_notifier helper

2019-01-16 Thread Alexey Kardashevskiy



On 12/01/2019 03:58, Eric Auger wrote:
> The code used to attach the eventfd handler for the ERR and
> REQ irq indices can be factorized into a helper. In subsequent
> patches we will extend this helper to support other irq indices.
> 
> We test the notification is allowed outside of the helper:
> respectively check vdev->pci_aer and VFIO_FEATURE_ENABLE_REQ.
> Depending on the returned value we set vdev->pci_aer and
> vdev->req_enabled. An error handle is introduced for future usage
> although not strictly useful here.>
> Signed-off-by: Eric Auger 
> ---
>  hw/vfio/pci.c | 291 ++
>  1 file changed, 127 insertions(+), 164 deletions(-)
> 
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index c0cb1ec289..c589a4e666 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -105,6 +105,95 @@ static void vfio_intx_eoi(VFIODevice *vbasedev)
>  vfio_unmask_single_irqindex(vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
>  }
>  
> +/*
> + * vfio_register_event_notifier - setup/tear down eventfd
> + * notification and handling for IRQ indices that span over
> + * a single IRQ
> + *
> + * @vdev: VFIO device handle
> + * @index: IRQ index the eventfd/handler is associated to
> + * @target_state: true means notifier needs to be set up
> + * @handler to attach if @target_state is true
> + * @errp error handle
> + */
> +static int vfio_register_event_notifier(VFIOPCIDevice *vdev,
> +int index,
> +bool target_state,
> +void (*handler)(void *opaque),
> +Error **errp)
> +{
> +struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info),
> +  .index = index };
> +struct vfio_irq_set *irq_set;
> +EventNotifier *notifier;
> +int argsz, ret = 0;
> +int32_t *pfd, fd;
> +
> +switch (index) {

I'd pass the notifier as a parameter as well so index/handler/notifier
would walk together.


> +case VFIO_PCI_REQ_IRQ_INDEX:
> +notifier = >req_notifier;
> +break;
> +case VFIO_PCI_ERR_IRQ_INDEX:
> +notifier = >err_notifier;
> +break;
> +default:
> +return -EINVAL;
> +}
> +
> +if (ioctl(vdev->vbasedev.fd,
> +  VFIO_DEVICE_GET_IRQ_INFO, _info) < 0 || irq_info.count < 
> 1) {
> +error_setg_errno(errp, errno,
> + "no irq index %d available", index);
> +return -EINVAL;
> +}
> +
> +if (target_state) {
> +ret = event_notifier_init(notifier, 0);
> +if (ret) {
> +error_setg_errno(errp, -ret,
> + "Unable to init event notifier for irq index 
> %d",
> + index);
> +return ret;
> +}
> +}
> +
> +argsz = sizeof(*irq_set) + sizeof(*pfd);
> +
> +irq_set = g_malloc0(argsz);
> +irq_set->argsz = argsz;
> +irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
> + VFIO_IRQ_SET_ACTION_TRIGGER;
> +irq_set->index = index;
> +irq_set->start = 0;
> +irq_set->count = 1;
> +pfd = (int32_t *)_set->data;
> +
> +if (!notifier) {
> +return -EINVAL;
> +}
> +
> +fd = event_notifier_get_fd(notifier);
> +
> +if (target_state) {
> +qemu_set_fd_handler(fd, handler, NULL, vdev);
> +*pfd = fd;
> +} else {
> +qemu_set_fd_handler(fd, NULL, NULL, vdev);
> +event_notifier_cleanup(notifier);
> +*pfd = -1;
> +}
> +
> +ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
> +g_free(irq_set);
> +
> +if (ret) {
> +error_setg_errno(errp, -ret,
> + "vfio: Failed to %s eventfd signalling for index 
> %d",
> + *pfd < 0 ? "set up" : "tear down", index);
> +}
> +return ret;
> +}
> +
>  static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp)
>  {
>  #ifdef CONFIG_KVM
> @@ -2621,86 +2710,6 @@ static void vfio_err_notifier_handler(void *opaque)
>  vm_stop(RUN_STATE_INTERNAL_ERROR);
>  }
>  
> -/*
> - * Registers error notifier for devices supporting error recovery.
> - * If we encounter a failure in this function, we report an error
> - * and continue after disabling error recovery support for the
> - * device.
> - */
> -static void vfio_register_err_notifier(VFIOPCIDevice *vdev)
> -{
> -int ret;
> -int argsz;
> -struct vfio_irq_set *irq_set;
> -int32_t *pfd;
> -
> -if (!vdev->pci_aer) {
> -return;
> -}
> -
> -if (event_notifier_init(>err_notifier, 0)) {
> -error_report("vfio: Unable to init event notifier for error 
> detection");
> -vdev->pci_aer = false;
> -return;
> -}
> -
> -argsz = sizeof(*irq_set) + sizeof(*pfd);
> -
> -irq_set = g_malloc0(argsz);
> -irq_set->argsz = argsz;
> -irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |

Re: [Qemu-devel] [PATCH v3 18/19] nbd/client: Work around 3.0 bug for listing meta contexts

2019-01-16 Thread Eric Blake
On 1/16/19 9:43 AM, Vladimir Sementsov-Ogievskiy wrote:

>> @@ -839,9 +842,25 @@ static int nbd_list_meta_contexts(QIOChannel *ioc,
>>
>>   ret = nbd_receive_one_meta_context(ioc, NBD_OPT_LIST_META_CONTEXT,
>>  , NULL, errp);
>> +if (ret == 0 && seen_any && !seen_qemu) {
>> +/*
>> + * Work around qemu 3.0 bug: the server forgot to send
>> + * "qemu:" replies to 0 queries. If we saw at least one
>> + * reply (probably base:allocation), but none of them were
> 
> if we are saying about 3.0, it is base:allocation for sure, isn't it?
> 
>> + * qemu:, then run a more specific query to make sure.

If the server is qemu 3.0, then yes, it is base:allocation. But it could
be some other server that has its own custom return without implementing
base:allocation.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.   +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



signature.asc
Description: OpenPGP digital signature


Re: [Qemu-devel] [Qemu-ppc] [PATCH qemu] spapr: Fix fdt warnings

2019-01-16 Thread Alexey Kardashevskiy



On 16/01/2019 23:01, BALATON Zoltan wrote:
> On Wed, 16 Jan 2019, Richard Henderson wrote:
>> On 1/16/19 3:19 PM, Alexey Kardashevskiy wrote:
>>> because TARGET_FMT_lx is defined as "%016"PRIx64.
>>>
>>> This uses simple "%lx" to suppress the warning. Since it is spapr which
>>> is always 64bit, we assume here that hwaddr is always "long".
>>
>> This file is not solely for kvm, i.e. ppc64 hosts.  Thus this
>> is a bad assumption and will fail for a 32-bit host.
>>
>> You may want to use PRIx64 and assume hwaddr == uint64_t, or
>> also include an explicit cast to uint64_t.
> 
> I don't know the context of this but there's HWADDR_PRIx as well so if
> you want to print a hwaddr that's probably the one to use.


Oh, thanks! I missed that :-/ I'll repost if otherwise the idea is
correct and nothing relies on leading zeroes (hi, David :) ).



-- 
Alexey



[Qemu-devel] [PATCH] ARM: GIC: error out early when creating VGICv2 failed

2019-01-16 Thread Shannon Zhao
Currently if creating a gicv2 VM on the platform without
VGICv2 support, it failed in kvm_arm_pmu_set_irq while
trying to set the interrupt number for PMU with below
error message.
KVM_SET_DEVICE_ATTR failed: Invalid argument

This error log is a little confused. Also it should error
out in kvm_arm_gic_realize early.

Signed-off-by: Shannon Zhao 
---
 hw/intc/arm_gic_kvm.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
index a611e8e..b4f2133 100644
--- a/hw/intc/arm_gic_kvm.c
+++ b/hw/intc/arm_gic_kvm.c
@@ -554,8 +554,9 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error 
**errp)
   KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true,
   _abort);
 }
-} else if (ret != -ENODEV && ret != -ENOTSUP) {
-error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
+} else if (ret != -ENOTSUP) {
+error_setg_errno(errp, -ret, "error creating in-kernel VGIC, maybe "
+ "vGICv2 not support on this platform");
 return;
 }
 
-- 
1.8.3.1




[Qemu-devel] [PATCH qemu 1/3] vfio/spapr: Fix indirect levels calculation

2019-01-16 Thread Alexey Kardashevskiy
The current code assumes that we can address more bits on a PCI bus
for DMA than we really can but there is no way knowing the actual limit.

This makes a better guess for the number of levels and if the kernel
fails to allocate that, this increases the level numbers till succeeded
or reached the 64bit limit.

This adds levels to the trace point.

This may cause the kernel to warn about failed allocation:
   [65122.837458] Failed to allocate a TCE memory, level shift=28
which might happen if MAX_ORDER is not large enough as it can vary:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/powerpc/Kconfig?h=v5.0-rc2#n727

Signed-off-by: Alexey Kardashevskiy 
---
 hw/vfio/spapr.c  | 38 +-
 hw/vfio/trace-events |  2 +-
 2 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c
index becf71a..2675bf5 100644
--- a/hw/vfio/spapr.c
+++ b/hw/vfio/spapr.c
@@ -146,7 +146,7 @@ int vfio_spapr_create_window(VFIOContainer *container,
 int ret;
 IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
 uint64_t pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
-unsigned entries, pages;
+unsigned entries, bits_total, bits_per_level, max_levels;
 struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };
 long systempagesize = qemu_getrampagesize();
 
@@ -176,16 +176,35 @@ int vfio_spapr_create_window(VFIOContainer *container,
 create.window_size = int128_get64(section->size);
 create.page_shift = ctz64(pagesize);
 /*
- * SPAPR host supports multilevel TCE tables, there is some
- * heuristic to decide how many levels we want for our table:
- * 0..64 = 1; 65..4096 = 2; 4097..262144 = 3; 262145.. = 4
+ * SPAPR host supports multilevel TCE tables. We try to guess optimal
+ * levels number and if this fails (for example due to the host memory
+ * fragmentation), we increase levels. The DMA address structure is:
+ *  rxxx       
+ * where:
+ *   r = reserved (bits >= 55 are reserved in the existing hardware)
+ *   i = IOMMU page offset (64K in this example)
+ *   x = bits to index a TCE which can be split to equal chunks to index
+ *  within the level.
+ * The aim is to split "x" to smaller possible number of levels.
  */
 entries = create.window_size >> create.page_shift;
-pages = MAX((entries * sizeof(uint64_t)) / getpagesize(), 1);
-pages = MAX(pow2ceil(pages), 1); /* Round up */
-create.levels = ctz64(pages) / 6 + 1;
-
-ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, );
+/* bits_total is number of "x" needed */
+bits_total = ctz64((entries * sizeof(uint64_t)));
+/*
+ * bits_per_level is a safe guess of how much we can allocate per level:
+ * 8 is the current minimum for CONFIG_FORCE_MAX_ZONEORDER and MAX_ORDER
+ * is usually bigger than that.
+ */
+bits_per_level = ctz64(systempagesize) + 8;
+create.levels = bits_total / bits_per_level;
+create.levels = MAX(1, create.levels);
+max_levels = (64 - create.page_shift) / ctz64(systempagesize);
+for ( ; create.levels <= max_levels; ++create.levels) {
+ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, );
+if (!ret) {
+break;
+}
+}
 if (ret) {
 error_report("Failed to create a window, ret = %d (%m)", ret);
 return -errno;
@@ -200,6 +219,7 @@ int vfio_spapr_create_window(VFIOContainer *container,
 return -EINVAL;
 }
 trace_vfio_spapr_create_window(create.page_shift,
+   create.levels,
create.window_size,
create.start_addr);
 *pgsize = pagesize;
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
index 0f9f810..adfa75e 100644
--- a/hw/vfio/trace-events
+++ b/hw/vfio/trace-events
@@ -129,6 +129,6 @@ vfio_prereg_listener_region_add_skip(uint64_t start, 
uint64_t end) "0x%"PRIx64"
 vfio_prereg_listener_region_del_skip(uint64_t start, uint64_t end) 
"0x%"PRIx64" - 0x%"PRIx64
 vfio_prereg_register(uint64_t va, uint64_t size, int ret) "va=0x%"PRIx64" 
size=0x%"PRIx64" ret=%d"
 vfio_prereg_unregister(uint64_t va, uint64_t size, int ret) "va=0x%"PRIx64" 
size=0x%"PRIx64" ret=%d"
-vfio_spapr_create_window(int ps, uint64_t ws, uint64_t off) "pageshift=0x%x 
winsize=0x%"PRIx64" offset=0x%"PRIx64
+vfio_spapr_create_window(int ps, unsigned int levels, uint64_t ws, uint64_t 
off) "pageshift=0x%x levels=%u winsize=0x%"PRIx64" offset=0x%"PRIx64
 vfio_spapr_remove_window(uint64_t off) "offset=0x%"PRIx64
 vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to 
liobn fd %d"
-- 
2.17.1




[Qemu-devel] [PATCH qemu 0/3] spapr_pci, vfio: NVIDIA V100 + P9 passthrough

2019-01-16 Thread Alexey Kardashevskiy


This is for passing through NVIDIA V100 GPUs on POWER9 systems.

This implements a subdriver for NVIDIA V100 GPU with coherent memory and
NPU/ATS support available in the POWER9 CPU.

1/3 is not strictly related but since new memory also needs to be mapped
to the 64bit DMA window and it is located quite high in the address space,
some adjustments are needed.


This is based on dwg/ppc-for-4.0 sha1 a0a8bff and requires headers update
from v5.0-rc1 staged by Paolo already.

Please comment. Thanks.



Alexey Kardashevskiy (3):
  vfio/spapr: Fix indirect levels calculation
  vfio: Make vfio_get_region_info_cap public
  spapr: Support NVIDIA V100 GPU with NVLink2

 hw/vfio/pci.h |   2 +
 include/hw/pci-host/spapr.h   |   9 +
 include/hw/ppc/spapr.h|   3 +-
 include/hw/vfio/vfio-common.h |   2 +
 hw/ppc/spapr.c|  25 ++-
 hw/ppc/spapr_pci.c| 333 +-
 hw/vfio/common.c  |   2 +-
 hw/vfio/pci-quirks.c  | 120 
 hw/vfio/pci.c |  14 ++
 hw/vfio/spapr.c   |  38 +++-
 hw/vfio/trace-events  |   6 +-
 11 files changed, 539 insertions(+), 15 deletions(-)

-- 
2.17.1




[Qemu-devel] [PATCH qemu 3/3] spapr: Support NVIDIA V100 GPU with NVLink2

2019-01-16 Thread Alexey Kardashevskiy
NVIDIA V100 GPUs have on-board RAM which is mapped into the host memory
space and accessible as normal RAM via an NVLink bus. The VFIO-PCI driver
implements special regions for such GPUs and emulates an NVLink bridge.
NVLink2-enabled POWER9 CPUs also provide address translation services
which includes an ATS shootdown (ATSD) register exported via the NVLink
bridge device.

This adds a quirk to VFIO to map the GPU memory and create an MR;
the new MR is stored in a PCI device as a QOM link. The sPAPR PCI uses
this to get the MR and map it to the system address space.
Another quirk does the same for ATSD.

This adds 4 additional steps to the FDT builder in spapr-pci:

1. Search for specific GPUs and NPUs and collect findings in
sPAPRPHBState::nvgpus;

2. Add properties in the device tree such as "ibm,npu", "ibm,gpu",
"memory-block" and others to advertise the NVLink2 function to the guest;

3. Add new memory blocks with an extra "linux,memory-usable" to prevent
the guest OS from accessing the new memory until it is online by the GPU
driver in the guest;

4. Add a npuphb# node representing an NPU unit for every vPHB as
the GPU driver uses it to detect NPU2 hardware and discover links; this
is not backed by any QEMU device as it does need to.

This allocates space for GPU RAM and ATSD like we do for MMIOs by
adding 2 new parameters to the phb_placement() hook. Older machine types
set these to zero.

This puts new memory nodes in a separate NUMA node to replicate the host
system setup as the GPU driver relies on this.

This adds requirement similar to EEH - one IOMMU group per vPHB.
The reason for this is that ATSD registers belong to a physical NPU
so they cannot invalidate translations on GPUs attached to another NPU.
It is guaranteed by the host platform as it does not mix NVLink bridges
or GPUs from different NPU in the same IOMMU group. If more than one
IOMMU group is detected on a vPHB, this disables ATSD support for that
vPHB and prints a warning.

Signed-off-by: Alexey Kardashevskiy 
---

The example command line for redbud system:

pbuild/qemu-aiku1804le-ppc64/ppc64-softmmu/qemu-system-ppc64 \
-nodefaults \
-chardev stdio,id=STDIO0,signal=off,mux=on \
-device spapr-vty,id=svty0,reg=0x71000110,chardev=STDIO0 \
-mon id=MON0,chardev=STDIO0,mode=readline -nographic -vga none \
-enable-kvm -m 384G \
-chardev socket,id=SOCKET0,server,nowait,host=localhost,port=4 \
-mon chardev=SOCKET0,mode=control \
-smp 80,sockets=1,threads=4 \
-netdev "tap,id=TAP0,helper=/home/aik/qemu-bridge-helper --br=br0" \
-device "virtio-net-pci,id=vnet0,mac=52:54:00:12:34:56,netdev=TAP0" \
img/vdisk0.img \
-device "vfio-pci,id=vfio0004_04_00_0,host=0004:04:00.0" \
-device "vfio-pci,id=vfio0006_00_00_0,host=0006:00:00.0" \
-device "vfio-pci,id=vfio0006_00_00_1,host=0006:00:00.1" \
-device "vfio-pci,id=vfio0006_00_00_2,host=0006:00:00.2" \
-device "vfio-pci,id=vfio0004_05_00_0,host=0004:05:00.0" \
-device "vfio-pci,id=vfio0006_00_01_0,host=0006:00:01.0" \
-device "vfio-pci,id=vfio0006_00_01_1,host=0006:00:01.1" \
-device "vfio-pci,id=vfio0006_00_01_2,host=0006:00:01.2" \
-device spapr-pci-host-bridge,id=phb1,index=1 \
-device "vfio-pci,id=vfio0035_03_00_0,host=0035:03:00.0" \
-device "vfio-pci,id=vfio0007_00_00_0,host=0007:00:00.0" \
-device "vfio-pci,id=vfio0007_00_00_1,host=0007:00:00.1" \
-device "vfio-pci,id=vfio0007_00_00_2,host=0007:00:00.2" \
-device "vfio-pci,id=vfio0035_04_00_0,host=0035:04:00.0" \
-device "vfio-pci,id=vfio0007_00_01_0,host=0007:00:01.0" \
-device "vfio-pci,id=vfio0007_00_01_1,host=0007:00:01.1" \
-device "vfio-pci,id=vfio0007_00_01_2,host=0007:00:01.2" -snapshot \
-machine pseries \
-L /home/aik/t/qemu-ppc64-bios/ -d guest_errors

Note that QEMU attaches PCI devices to the last added vPHB so first
8 devices - 4:04:00.0 till 6:00:01.2 - go to the default vPHB, and
35:03:00.0..7:00:01.2 to the vPHB with id=phb1.
---
 hw/vfio/pci.h   |   2 +
 include/hw/pci-host/spapr.h |   9 +
 include/hw/ppc/spapr.h  |   3 +-
 hw/ppc/spapr.c  |  25 ++-
 hw/ppc/spapr_pci.c  | 333 +++-
 hw/vfio/pci-quirks.c| 120 +
 hw/vfio/pci.c   |  14 ++
 hw/vfio/trace-events|   4 +
 8 files changed, 506 insertions(+), 4 deletions(-)

diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index f4c5fb6..fd7703a 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -195,6 +195,8 @@ int vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp);
 int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev,
struct vfio_region_info *info,
Error **errp);
+int vfio_pci_nvidia_v100_ram_init(VFIOPCIDevice *vdev, Error **errp);
+int vfio_pci_nvlink2_init(VFIOPCIDevice *vdev, Error **errp);
 
 void vfio_display_reset(VFIOPCIDevice *vdev);
 int vfio_display_probe(VFIOPCIDevice *vdev, Error **errp);
diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
index 4eb3a2c..bd5e43f 100644
--- 

[Qemu-devel] [PATCH qemu 2/3] vfio: Make vfio_get_region_info_cap public

2019-01-16 Thread Alexey Kardashevskiy
This makes vfio_get_region_info_cap() to be used in quirks.

Signed-off-by: Alexey Kardashevskiy 
---
 include/hw/vfio/vfio-common.h | 2 ++
 hw/vfio/common.c  | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index 1b434d0..abc82f9 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -189,6 +189,8 @@ int vfio_get_region_info(VFIODevice *vbasedev, int index,
 int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type,
  uint32_t subtype, struct vfio_region_info **info);
 bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type);
+struct vfio_info_cap_header *
+vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id);
 #endif
 extern const MemoryListener vfio_prereg_listener;
 
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 7c185e5a..f58b487 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -711,7 +711,7 @@ static void vfio_listener_release(VFIOContainer *container)
 }
 }
 
-static struct vfio_info_cap_header *
+struct vfio_info_cap_header *
 vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id)
 {
 struct vfio_info_cap_header *hdr;
-- 
2.17.1




[Qemu-devel] [PATCH v3] vhost-user-blk: add discard/write zeroes features support

2019-01-16 Thread Changpeng Liu
Linux commit 1f23816b8 "virtio_blk: add discard and write zeroes support"
added the support in the Guest kernel, while here also enable the features
support with vhost-user-blk driver. Also enable the test example utility
with DISCARD and WRITE ZEROES commands.

Signed-off-by: Changpeng Liu 
---
 contrib/vhost-user-blk/vhost-user-blk.c | 134 +---
 hw/block/vhost-user-blk.c   |   4 +
 include/standard-headers/linux/virtio_blk.h |  54 +++
 3 files changed, 159 insertions(+), 33 deletions(-)

diff --git a/contrib/vhost-user-blk/vhost-user-blk.c 
b/contrib/vhost-user-blk/vhost-user-blk.c
index 49640df..6f2662a 100644
--- a/contrib/vhost-user-blk/vhost-user-blk.c
+++ b/contrib/vhost-user-blk/vhost-user-blk.c
@@ -63,6 +63,20 @@ static size_t vub_iov_size(const struct iovec *iov,
 return len;
 }
 
+static size_t vub_iov_to_buf(const struct iovec *iov,
+ const unsigned int iov_cnt, void *buf)
+{
+size_t len;
+unsigned int i;
+
+len = 0;
+for (i = 0; i < iov_cnt; i++) {
+memcpy(buf + len,  iov[i].iov_base, iov[i].iov_len);
+len += iov[i].iov_len;
+}
+return len;
+}
+
 static void vub_panic_cb(VuDev *vu_dev, const char *buf)
 {
 VugDev *gdev;
@@ -161,6 +175,38 @@ vub_writev(VubReq *req, struct iovec *iov, uint32_t iovcnt)
 return rc;
 }
 
+static int
+vub_discard_write_zeroes(VubReq *req, struct iovec *iov, uint32_t iovcnt,
+ uint32_t type)
+{
+struct virtio_blk_discard_write_zeroes desc;
+ssize_t size;
+
+size = vub_iov_size(iov, iovcnt);
+if (size != sizeof(desc)) {
+fprintf(stderr, "Invalid size %zd, expect %zu\n", size, sizeof(desc));
+return -1;
+}
+vub_iov_to_buf(iov, iovcnt, );
+
+#if defined(__linux__) && defined(BLKDISCARD) && defined(BLKZEROOUT)
+VubDev *vdev_blk = req->vdev_blk;
+uint64_t range[2] = { le64toh(desc.sector) << 9,
+  le32toh(desc.num_sectors) << 9 };
+if (type == VIRTIO_BLK_T_DISCARD) {
+if (ioctl(vdev_blk->blk_fd, BLKDISCARD, range) == 0) {
+return 0;
+}
+} else if (type == VIRTIO_BLK_T_WRITE_ZEROES) {
+if (ioctl(vdev_blk->blk_fd, BLKZEROOUT, range) == 0) {
+return 0;
+}
+}
+#endif
+
+return -1;
+}
+
 static void
 vub_flush(VubReq *req)
 {
@@ -216,44 +262,55 @@ static int vub_virtio_process_req(VubDev *vdev_blk,
 in_num--;
 
 type = le32toh(req->out->type);
-switch (type & ~(VIRTIO_BLK_T_OUT | VIRTIO_BLK_T_BARRIER)) {
-case VIRTIO_BLK_T_IN: {
-ssize_t ret = 0;
-bool is_write = type & VIRTIO_BLK_T_OUT;
-req->sector_num = le64toh(req->out->sector);
-if (is_write) {
-ret  = vub_writev(req, >out_sg[1], out_num);
-} else {
-ret = vub_readv(req, >in_sg[0], in_num);
-}
-if (ret >= 0) {
-req->in->status = VIRTIO_BLK_S_OK;
-} else {
-req->in->status = VIRTIO_BLK_S_IOERR;
-}
-vub_req_complete(req);
-break;
+switch (type & ~VIRTIO_BLK_T_BARRIER) {
+case VIRTIO_BLK_T_IN:
+case VIRTIO_BLK_T_OUT: {
+ssize_t ret = 0;
+bool is_write = type & VIRTIO_BLK_T_OUT;
+req->sector_num = le64toh(req->out->sector);
+if (is_write) {
+ret  = vub_writev(req, >out_sg[1], out_num);
+} else {
+ret = vub_readv(req, >in_sg[0], in_num);
 }
-case VIRTIO_BLK_T_FLUSH: {
-vub_flush(req);
+if (ret >= 0) {
 req->in->status = VIRTIO_BLK_S_OK;
-vub_req_complete(req);
-break;
+} else {
+req->in->status = VIRTIO_BLK_S_IOERR;
 }
-case VIRTIO_BLK_T_GET_ID: {
-size_t size = MIN(vub_iov_size(>in_sg[0], in_num),
-  VIRTIO_BLK_ID_BYTES);
-snprintf(elem->in_sg[0].iov_base, size, "%s", "vhost_user_blk");
+vub_req_complete(req);
+break;
+}
+case VIRTIO_BLK_T_FLUSH:
+vub_flush(req);
+req->in->status = VIRTIO_BLK_S_OK;
+vub_req_complete(req);
+break;
+case VIRTIO_BLK_T_GET_ID: {
+size_t size = MIN(vub_iov_size(>in_sg[0], in_num),
+  VIRTIO_BLK_ID_BYTES);
+snprintf(elem->in_sg[0].iov_base, size, "%s", "vhost_user_blk");
+req->in->status = VIRTIO_BLK_S_OK;
+req->size = elem->in_sg[0].iov_len;
+vub_req_complete(req);
+break;
+}
+case VIRTIO_BLK_T_DISCARD:
+case VIRTIO_BLK_T_WRITE_ZEROES: {
+int rc;
+rc = vub_discard_write_zeroes(req, >out_sg[1], out_num, type);
+if (rc == 0) {
 req->in->status = VIRTIO_BLK_S_OK;
-req->size = elem->in_sg[0].iov_len;
-vub_req_complete(req);
-break;
-}

Re: [Qemu-devel] [PATCH for-4.0 0/5] fix some segmentation faults and migration issues

2019-01-16 Thread fei



> 在 2019年1月16日,23:00,Dr. David Alan Gilbert  写道:
> 
> * Philippe Mathieu-Daudé (phi...@redhat.com) wrote:
>>> On 1/16/19 5:50 AM, Fei Li wrote:
>>> Hi all,
>>> 
>>> Kindly ping. :)
>>> 
>>> As my v10 of qemu_thread_create partly rely on this patch series, I'd
>>> like to know
>>> when will these 5 patches be merged, or I join them with v10 of
>>> qemu_thread_create
>>> and send together. Could anyone shed light on me? Thanks for the advice
>>> in advance.
>> 
>> This series would get merged quicker if you include the maintainers :)
>> 
>> $ ./scripts/get_maintainer.pl -f migration/*
>> Juan Quintela  (maintainer:Migration)
>> "Dr. David Alan Gilbert"  (maintainer:Migration)
>> 
>> Doing that for you by responding to this mail.
> 
> We can do it via migration now the set is complete.
> 
> Dave
> 
Thanks all! :)

Have a nice day
Fei
>> 
>> Regards,
>> 
>> Phil.
>> 
>>> 
>>> 
>>> Have a nice day
>>> Fei
 在 2019/1/13 下午10:08, Fei Li 写道:
 All these five patches have gotten the Reviewed-by: the first patch
 is to fix one segmentation fault and the other four are to fix some
 migration issues.
 
 To be more detail, they are extracted from previous
 "[PATCH for-4.0 v9 16/16] qemu_thread_create: propagate errors to
 callers to handle.", but actually these five patches are derivative
 and not relevant to the mentioned qemu_thread_create patch series.
 Thus send them separately to make them be merged earlier.
 
 Fei Li (5):
Fix segmentation fault when qemu_signal_init fails
migration: fix the multifd code when receiving less channels
migration: multifd_save_cleanup() can't fail, simplify
migration: add more error handling for postcopy_ram_enable_notify
migration: unify error handling for process_incoming_migration_co
 
   migration/channel.c  | 11 ++-
   migration/migration.c| 40 +---
   migration/migration.h|  2 +-
   migration/postcopy-ram.c |  1 +
   migration/ram.c  | 28 ++--
   migration/ram.h  |  4 ++--
   migration/savevm.c   |  1 +
   util/main-loop.c |  8 
   8 files changed, 54 insertions(+), 41 deletions(-)
 
>>> 
> --
> Dr. David Alan Gilbert / dgilb...@redhat.com / Manchester, UK




Re: [Qemu-devel] [PATCH v1 2/5] vl.c: add -smp, dies=* command line support

2019-01-16 Thread Like Xu

On 2019/1/17 2:26, Daniel P. Berrangé wrote:

On Mon, Jan 14, 2019 at 06:51:34PM -0200, Eduardo Habkost wrote:

On Mon, Jan 14, 2019 at 08:24:56PM +0800, Like Xu wrote:

This patch updates the check rules on legeacy -smp parse from user command
and it's designed to obey the same restrictions as socket/core/thread model.

Signed-off-by: Like Xu 


This would require the documentation for -smp to be updated.
qemu-options.hx still says that "cores=" is the number of cores
per socket.

Also, I'm not completely sure we should change the meaning of
"cores=" and smp_cores to be per-die instead of per-socket.  Most
machines won't have any code for tracking dies, so we probably
shouldn't make the extra complexity affect all machines.[1]


Could we not simply have a 'max-dies' property against the machine
base class which defaults to 1. Then no existing machine types
need any changes unless they want to opt-in to supporting
"dies > 1".

It's nice to have max-dies for machine base class.



What would be the disadvantages of a simple -machine
"dies-per-socket" option, specific for PC?


Libvirt currently has

   
  
   

To me the natural way to expand that is to use

   
  
   

but this rather implies dies-per-socket + cores-per-die
not cores-per-socket.  Libvirt could of course convert
its value from  cores-per-die into cores-per-socket
before giving it to QEMU, albeit with the potential
for confusion from people comparing the libvirt and QEMU
level configs

It is a recommended update on cpu topo configuration of libvirt
as well as other upper layer apps.



Keeping core-id and smp_cores per-socket instead of per-die also
seems necessary to keep backwards compatibility on the interface
for identifying CPU hotplug slots.  Igor, what do you think?


Is there really a backwards compatibility problem, given that
no existing mgmt app will have created a VM with "dies != 1".
IOW, if an application adds logic to support configuring a
VM with "dies > 1" it seems fine that they should need to
understand how this impacts the way you identify CPUs for
hotplug.

The impacts from MCP model will be documented continuously.
Any concerns for hot-plugging CPUs in MCP socket is welcomed.



[1] I would even argue that the rest of the -smp options belong
 to the machine object, and topology rules should be
 machine-specific, but cleaning this up will require
 additional work.


If we ever expect to support non-homogenous CPUs then our
modelling of topology is fatally flawed, as it doesm't allow
us to specify  creating a VM with  1 socket containing 2
cores and a second socket containing 4 cores. Fixing that
might require modelling each socket, die, and core as a
distinct set of nested QOM objects which gets real fun.

Do we really need to go out of this non-homogeneous step?
Currently there is no support on physical host AFAIK.
Is there enough benefit?



Regards,
Daniel






[Qemu-devel] [PATCH v3 40/50] audio: split ctl_* functions into enable_* and volume_*

2019-01-16 Thread Kővágó, Zoltán
This way we no longer need vararg functions, improving compile time
error detection.  Also now it's possible to check actually what commands
are supported, without needing to manually update ctl_caps.

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h  |  15 ++---
 audio/audio_template.h |   1 -
 audio/alsaaudio.c  |  56 +++---
 audio/audio.c  |  45 +--
 audio/coreaudio.c  |  13 ++---
 audio/dsoundaudio.c|  50 +++-
 audio/noaudio.c|  14 ++---
 audio/ossaudio.c   |  78 ++---
 audio/paaudio.c| 126 -
 audio/sdlaudio.c   |  17 +-
 audio/spiceaudio.c | 101 ++---
 audio/wavaudio.c   |   7 +--
 12 files changed, 213 insertions(+), 310 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 236b523286..6fec4f159c 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -72,7 +72,6 @@ typedef struct HWVoiceOut {
 
 QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
 QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
-int ctl_caps;
 struct audio_pcm_ops *pcm_ops;
 QLIST_ENTRY (HWVoiceOut) entries;
 } HWVoiceOut;
@@ -93,7 +92,6 @@ typedef struct HWVoiceIn {
 size_t pos_emul, pending_emul, size_emul;
 
 QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
-int ctl_caps;
 struct audio_pcm_ops *pcm_ops;
 QLIST_ENTRY (HWVoiceIn) entries;
 } HWVoiceIn;
@@ -145,7 +143,6 @@ struct audio_driver {
 int max_voices_in;
 int voice_size_out;
 int voice_size_in;
-int ctl_caps;
 QLIST_ENTRY(audio_driver) next;
 };
 
@@ -167,7 +164,8 @@ struct audio_pcm_ops {
  * size may be smaller
  */
 size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size);
-int(*ctl_out) (HWVoiceOut *hw, int cmd, ...);
+void   (*enable_out)(HWVoiceOut *hw, bool enable);
+void   (*volume_out)(HWVoiceOut *hw, struct mixeng_volume *vol);
 
 int(*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
 void   (*fini_in) (HWVoiceIn *hw);
@@ -175,7 +173,8 @@ struct audio_pcm_ops {
 size_t (*buffer_size_in)(HWVoiceIn *hw);
 void  *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);
 void   (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);
-int(*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
+void   (*enable_in)(HWVoiceIn *hw, bool enable);
+void   (*volume_in)(HWVoiceIn *hw, struct mixeng_volume *vol);
 };
 
 void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
@@ -251,12 +250,6 @@ void audio_rate_start(RateCtl *rate);
 size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
 size_t bytes_avail);
 
-#define VOICE_ENABLE 1
-#define VOICE_DISABLE 2
-#define VOICE_VOLUME 3
-
-#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME)
-
 static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)
 {
 return (dst >= src) ? (dst - src) : (len - src + dst);
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 07ce9ce51f..9ec565fc48 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -267,7 +267,6 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
 
 hw->s = s;
 hw->pcm_ops = drv->pcm_ops;
-hw->ctl_caps = drv->ctl_caps;
 
 QLIST_INIT (>sw_head);
 #ifdef DAC
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 1489f50dfd..446bb90ceb 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -744,34 +744,28 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char 
*typ, int ctl)
 return 0;
 }
 
-static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static void alsa_enable_out(HWVoiceOut *hw, bool enable)
 {
 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
 AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.alsa_out;
 
-switch (cmd) {
-case VOICE_ENABLE:
-{
-bool poll_mode = apdo->try_poll;
+if (enable) {
+bool poll_mode = apdo->try_poll;
 
-ldebug ("enabling voice\n");
-if (poll_mode && alsa_poll_out (hw)) {
-poll_mode = 0;
-}
-hw->poll_mode = poll_mode;
-return alsa_voice_ctl (alsa->handle, "playback", 
VOICE_CTL_PREPARE);
+ldebug ("enabling voice\n");
+if (poll_mode && alsa_poll_out (hw)) {
+poll_mode = 0;
 }
-
-case VOICE_DISABLE:
+hw->poll_mode = poll_mode;
+alsa_voice_ctl(alsa->handle, "playback", VOICE_CTL_PREPARE);
+} else {
 ldebug ("disabling voice\n");
 if (hw->poll_mode) {
 hw->poll_mode = 0;
 alsa_fini_poll (>pollhlp);
 }
-return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE);
+alsa_voice_ctl(alsa->handle, "playback", VOICE_CTL_PAUSE);
 }
-
-return -1;
 }
 
 static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void 
*drv_opaque)
@@ 

[Qemu-devel] [PATCH v3 39/50] audio: common rate control code for timer based outputs

2019-01-16 Thread Kővágó, Zoltán
This commit removes the ad-hoc rate-limiting code from noaudio and
wavaudio, and replaces them with a (slightly modified) code from
spiceaudio.  This way multiple write calls (for example when the
circular buffer wraps around) do not cause problems.

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h  |  9 +
 audio/audio.c  | 30 
 audio/noaudio.c| 49 +-
 audio/spiceaudio.c | 49 +++---
 audio/wavaudio.c   | 21 ++--
 5 files changed, 78 insertions(+), 80 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index a5263966a8..236b523286 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -242,6 +242,15 @@ void *audio_calloc (const char *funcname, int nmemb, 
size_t size);
 
 void audio_run(AudioState *s, const char *msg);
 
+typedef struct RateCtl {
+int64_t start_ticks;
+int64_t bytes_sent;
+} RateCtl;
+
+void audio_rate_start(RateCtl *rate);
+size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
+size_t bytes_avail);
+
 #define VOICE_ENABLE 1
 #define VOICE_DISABLE 2
 #define VOICE_VOLUME 3
diff --git a/audio/audio.c b/audio/audio.c
index 4b5c1712e3..798541638e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -2032,3 +2032,33 @@ const char *audio_get_id(QEMUSoundCard *card)
 return "";
 }
 }
+
+void audio_rate_start(RateCtl *rate)
+{
+memset(rate, 0, sizeof(RateCtl));
+rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+}
+
+size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
+size_t bytes_avail)
+{
+int64_t now;
+int64_t ticks;
+int64_t bytes;
+int64_t samples;
+size_t ret;
+
+now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ticks = now - rate->start_ticks;
+bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
+samples = (bytes - rate->bytes_sent) >> info->shift;
+if (samples < 0 || samples > 65536) {
+AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)", samples);
+audio_rate_start(rate);
+samples = 0;
+}
+
+ret = MIN(samples << info->shift, bytes_avail);
+rate->bytes_sent += ret;
+return ret;
+}
diff --git a/audio/noaudio.c b/audio/noaudio.c
index dc77d1aff5..b29929dac4 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -32,32 +32,26 @@
 
 typedef struct NoVoiceOut {
 HWVoiceOut hw;
-int64_t old_ticks;
+RateCtl rate;
 } NoVoiceOut;
 
 typedef struct NoVoiceIn {
 HWVoiceIn hw;
-int64_t old_ticks;
+RateCtl rate;
 } NoVoiceIn;
 
 static size_t no_write(HWVoiceOut *hw, void *buf, size_t len)
 {
 NoVoiceOut *no = (NoVoiceOut *) hw;
-int64_t now;
-int64_t ticks;
-int64_t bytes;
-
-now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-ticks = now - no->old_ticks;
-bytes = muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
-
-no->old_ticks = now;
-return MIN(len, bytes);
+return audio_rate_get_bytes(>info, >rate, len);
 }
 
 static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void 
*drv_opaque)
 {
+NoVoiceOut *no = (NoVoiceOut *) hw;
+
 audio_pcm_init_info (>info, as);
+audio_rate_start(>rate);
 return 0;
 }
 
@@ -68,14 +62,20 @@ static void no_fini_out (HWVoiceOut *hw)
 
 static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
 {
-(void) hw;
-(void) cmd;
+NoVoiceOut *no = (NoVoiceOut *) hw;
+
+if (cmd == VOICE_ENABLE) {
+audio_rate_start(>rate);
+}
 return 0;
 }
 
 static int no_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
 {
+NoVoiceIn *no = (NoVoiceIn *) hw;
+
 audio_pcm_init_info (>info, as);
+audio_rate_start(>rate);
 return 0;
 }
 
@@ -86,25 +86,20 @@ static void no_fini_in (HWVoiceIn *hw)
 
 static size_t no_read(HWVoiceIn *hw, void *buf, size_t size)
 {
-size_t to_clear;
 NoVoiceIn *no = (NoVoiceIn *) hw;
+int64_t bytes = audio_rate_get_bytes(>info, >rate, size);
 
-int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-int64_t ticks = now - no->old_ticks;
-int64_t bytes =
-muldiv64 (ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
-
-no->old_ticks = now;
-to_clear = MIN(bytes, size);
-
-audio_pcm_info_clear_buf(>info, buf, to_clear >> hw->info.shift);
-return to_clear;
+audio_pcm_info_clear_buf(>info, buf, bytes >> hw->info.shift);
+return bytes;
 }
 
 static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
 {
-(void) hw;
-(void) cmd;
+NoVoiceIn *no = (NoVoiceIn *) hw;
+
+if (cmd == VOICE_ENABLE) {
+audio_rate_start(>rate);
+}
 return 0;
 }
 
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 709245e453..2495866c82 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -40,15 +40,10 @@
 #define LINE_IN_SAMPLES (256 * 4)
 #endif
 
-typedef 

Re: [Qemu-devel] [PATCH] slirp: Use lduw_be_p in slirp_input

2019-01-16 Thread Richard Henderson
On 1/17/19 10:50 AM, Samuel Thibault wrote:
> Hello,
> 
> Richard Henderson, le mer. 26 déc. 2018 14:42:54 +1100, a ecrit:
>> The pointer may be unaligned, so we must use our routines for that.
>> At the same time, we might as well use the big-endian version
>> instead of ntohs.
>>
>> This fixes sparc64 host SIGBUS during pxe boot.
> 
> I'm not at ease with applying this, when Marc-André is trying to make
> slirp an external library...  I'd rather apply the change below, could
> somebody review it?

Fair.

> -proto = ntohs(*(uint16_t *)(pkt + 12));
> +proto = (((uint16_t) pkt[12]) << 8) + pkt[13];

This works for me too, though I note unnecessary parenthesis around the cast.

Reviewed-by: Richard Henderson 


r~



[Qemu-devel] [PATCH v3 27/50] alsaaudio: port to the new audio backend api

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/alsaaudio.c | 306 --
 1 file changed, 81 insertions(+), 225 deletions(-)

diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 6ad2a09d16..c23dedd4bf 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -43,9 +43,6 @@ struct pollhlp {
 
 typedef struct ALSAVoiceOut {
 HWVoiceOut hw;
-int wpos;
-int pending;
-void *pcm_buf;
 snd_pcm_t *handle;
 struct pollhlp pollhlp;
 Audiodev *dev;
@@ -54,7 +51,6 @@ typedef struct ALSAVoiceOut {
 typedef struct ALSAVoiceIn {
 HWVoiceIn hw;
 snd_pcm_t *handle;
-void *pcm_buf;
 struct pollhlp pollhlp;
 Audiodev *dev;
 } ALSAVoiceIn;
@@ -609,102 +605,62 @@ static int alsa_open(bool in, struct alsa_params_req 
*req,
 return -1;
 }
 
-static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
-{
-snd_pcm_sframes_t avail;
-
-avail = snd_pcm_avail_update (handle);
-if (avail < 0) {
-if (avail == -EPIPE) {
-if (!alsa_recover (handle)) {
-avail = snd_pcm_avail_update (handle);
-}
-}
-
-if (avail < 0) {
-alsa_logerr (avail,
- "Could not obtain number of available frames\n");
-return -1;
-}
-}
-
-return avail;
-}
-
-static void alsa_write_pending (ALSAVoiceOut *alsa)
-{
-HWVoiceOut *hw = >hw;
-
-while (alsa->pending) {
-int left_till_end_samples = hw->samples - alsa->wpos;
-int len = MIN (alsa->pending, left_till_end_samples);
-char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
-
-while (len) {
-snd_pcm_sframes_t written;
-
-written = snd_pcm_writei (alsa->handle, src, len);
-
-if (written <= 0) {
-switch (written) {
-case 0:
-trace_alsa_wrote_zero(len);
-return;
-
-case -EPIPE:
-if (alsa_recover (alsa->handle)) {
-alsa_logerr (written, "Failed to write %d frames\n",
- len);
-return;
-}
-trace_alsa_xrun_out();
-continue;
-
-case -ESTRPIPE:
-/* stream is suspended and waiting for an
-   application recovery */
-if (alsa_resume (alsa->handle)) {
-alsa_logerr (written, "Failed to write %d frames\n",
- len);
-return;
-}
-trace_alsa_resume_out();
-continue;
-
-case -EAGAIN:
-return;
-
-default:
-alsa_logerr (written, "Failed to write %d frames from 
%p\n",
- len, src);
-return;
-}
-}
-
-alsa->wpos = (alsa->wpos + written) % hw->samples;
-alsa->pending -= written;
-len -= written;
-}
-}
-}
-
-static size_t alsa_run_out(HWVoiceOut *hw, size_t live)
+static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len)
 {
 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
-size_t decr;
-snd_pcm_sframes_t avail;
+size_t pos = 0;
+size_t len_frames = len >> hw->info.shift;
 
-avail = alsa_get_avail (alsa->handle);
-if (avail < 0) {
-dolog ("Could not get number of available playback frames\n");
-return 0;
+while (len_frames) {
+char *src = advance(buf, pos);
+snd_pcm_sframes_t written;
+
+written = snd_pcm_writei(alsa->handle, src, len_frames);
+
+if (written <= 0) {
+switch (written) {
+case 0:
+trace_alsa_wrote_zero(len_frames);
+return pos;
+
+case -EPIPE:
+if (alsa_recover(alsa->handle)) {
+alsa_logerr(written, "Failed to write %zu frames\n",
+len_frames);
+return pos;
+}
+trace_alsa_xrun_out();
+continue;
+
+case -ESTRPIPE:
+/* stream is suspended and waiting for an
+   application recovery */
+if (alsa_resume(alsa->handle)) {
+alsa_logerr(written, "Failed to write %zu frames\n",
+len_frames);
+return pos;
+}
+trace_alsa_resume_out();
+continue;
+
+case -EAGAIN:
+return pos;
+
+default:
+alsa_logerr(written, "Failed to write %zu frames from %p\n",
+len, src);
+return pos;
+}
+}
+
+pos += 

[Qemu-devel] [PATCH v3 47/50] paaudio: channel-map option

2019-01-16 Thread Kővágó, Zoltán
Add an option to change the channel map used by pulseaudio.  If not
specified, falls back to an OSS compatible channel map.

Signed-off-by: Kővágó, Zoltán 
---
 qapi/audio.json |  5 -
 audio/paaudio.c | 18 ++
 qemu-options.hx |  9 +
 3 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/qapi/audio.json b/qapi/audio.json
index 7bcea6240f..86078039dc 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -107,11 +107,14 @@
 #
 # @name: name of the sink/source to use
 #
+# @channel-map: channel map to use (default: OSS compatible map)
+#
 # Since: 4.0
 ##
 { 'struct': 'AudiodevPaPerDirectionOptions',
   'data': {
-'*name': 'str' } }
+'*name':'str',
+'*channel-map': 'str' } }
 
 ##
 # @AudiodevPaOptions:
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 0d67c03b4c..b0e311584a 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -337,17 +337,27 @@ static pa_stream *qpa_simple_new (
 pa_stream_direction_t dir,
 const char *dev,
 const pa_sample_spec *ss,
-const pa_channel_map *map,
+const char *map,
 const pa_buffer_attr *attr,
 int *rerror)
 {
 int r;
 pa_stream *stream;
 pa_stream_flags_t flags;
+pa_channel_map pa_map;
 
 pa_threaded_mainloop_lock(c->mainloop);
 
-stream = pa_stream_new(c->context, name, ss, map);
+if (map && !pa_channel_map_parse(_map, map)) {
+dolog("Invalid channel map specified: '%s'\n", map);
+map = NULL;
+}
+if (!map) {
+pa_channel_map_init_extend(_map, ss->channels,
+   PA_CHANNEL_MAP_OSS);
+}
+
+stream = pa_stream_new(c->context, name, ss, _map);
 if (!stream) {
 goto fail;
 }
@@ -424,7 +434,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings 
*as,
 PA_STREAM_PLAYBACK,
 ppdo->has_name ? ppdo->name : NULL,
 ,
-NULL,   /* channel map */
+ppdo->has_channel_map ? ppdo->channel_map : NULL,
 ,/* buffering attributes */
 
 );
@@ -472,7 +482,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings 
*as, void *drv_opaque)
 PA_STREAM_RECORD,
 ppdo->has_name ? ppdo->name : NULL,
 ,
-NULL,   /* channel map */
+ppdo->has_channel_map ? ppdo->channel_map : NULL,
 NULL,   /* buffering attributes */
 
 );
diff --git a/qemu-options.hx b/qemu-options.hx
index 53fc5ef453..c4835f77c3 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -468,6 +468,7 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev,
 "-audiodev pa,id=id[,prop[=value][,...]]\n"
 "server= PulseAudio server address\n"
 "sink|source.name= sink/source device name\n"
+"sink|source.channel-map= channel map to use\n"
 #endif
 #ifdef CONFIG_SDL
 "-audiodev sdl,id=id[,prop[=value][,...]]\n"
@@ -621,6 +622,14 @@ Sets the PulseAudio @var{server} to connect to.
 @item sink|source.name=@var{sink}
 Use the specified sink/source for playback/recording.
 
+@item sink|source.channel-map=@var{map}
+Use the specified channel map.  The default is an OSS compatible
+channel map.  Do not forget to escape commas inside the map:
+
+@example
+-audiodev pa,id=example,sink.channel-map=front-left,,front-right
+@end example
+
 @end table
 
 @item -audiodev sdl,id=@var{id}[,@var{prop}[=@var{value}][,...]]
-- 
2.20.1




[Qemu-devel] [PATCH v3 25/50] audio: use size_t where makes sense

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---

Notes:
Changes from v2:
* Update REPLAY_VERSION
* Fix run_in/run_out prototypes in audio_pcm_ops

 audio/audio.h   |   4 +-
 audio/audio_int.h   |  26 +++
 audio/audio_template.h  |  14 ++--
 audio/mixeng.h  |   9 ++-
 audio/rate_template.h   |   2 +-
 include/sysemu/replay.h |   4 +-
 audio/alsaaudio.c   |  26 +++
 audio/audio.c   | 162 
 audio/coreaudio.c   |  10 +--
 audio/dsoundaudio.c |  11 +--
 audio/noaudio.c |  16 ++--
 audio/ossaudio.c|  45 +--
 audio/paaudio.c |  44 +--
 audio/sdlaudio.c|  19 +++--
 audio/spiceaudio.c  |  12 +--
 audio/wavaudio.c|   8 +-
 replay/replay-audio.c   |  16 ++--
 replay/replay.c |   2 +-
 18 files changed, 214 insertions(+), 216 deletions(-)

diff --git a/audio/audio.h b/audio/audio.h
index 4a95758516..2db27bba7b 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -112,7 +112,7 @@ SWVoiceOut *AUD_open_out (
 );
 
 void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
-int  AUD_write (SWVoiceOut *sw, void *pcm_buf, int size);
+size_t AUD_write (SWVoiceOut *sw, void *pcm_buf, size_t size);
 int  AUD_get_buffer_size_out (SWVoiceOut *sw);
 void AUD_set_active_out (SWVoiceOut *sw, int on);
 int  AUD_is_active_out (SWVoiceOut *sw);
@@ -133,7 +133,7 @@ SWVoiceIn *AUD_open_in (
 );
 
 void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
-int  AUD_read (SWVoiceIn *sw, void *pcm_buf, int size);
+size_t AUD_read (SWVoiceIn *sw, void *pcm_buf, size_t size);
 void AUD_set_active_in (SWVoiceIn *sw, int on);
 int  AUD_is_active_in (SWVoiceIn *sw);
 
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 40b3515b4e..9dcdf541fb 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -60,12 +60,12 @@ typedef struct HWVoiceOut {
 
 f_sample *clip;
 
-int rpos;
+size_t rpos;
 uint64_t ts_helper;
 
 struct st_sample *mix_buf;
 
-int samples;
+size_t samples;
 QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
 QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
 int ctl_caps;
@@ -81,13 +81,13 @@ typedef struct HWVoiceIn {
 
 t_sample *conv;
 
-int wpos;
-int total_samples_captured;
+size_t wpos;
+size_t total_samples_captured;
 uint64_t ts_helper;
 
 struct st_sample *conv_buf;
 
-int samples;
+size_t samples;
 QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
 int ctl_caps;
 struct audio_pcm_ops *pcm_ops;
@@ -102,7 +102,7 @@ struct SWVoiceOut {
 int64_t ratio;
 struct st_sample *buf;
 void *rate;
-int total_hw_samples_mixed;
+size_t total_hw_samples_mixed;
 int active;
 int empty;
 HWVoiceOut *hw;
@@ -119,7 +119,7 @@ struct SWVoiceIn {
 struct audio_pcm_info info;
 int64_t ratio;
 void *rate;
-int total_hw_samples_acquired;
+size_t total_hw_samples_acquired;
 struct st_sample *buf;
 f_sample *clip;
 HWVoiceIn *hw;
@@ -148,12 +148,12 @@ struct audio_driver {
 struct audio_pcm_ops {
 int  (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
 void (*fini_out)(HWVoiceOut *hw);
-int  (*run_out) (HWVoiceOut *hw, int live);
+size_t (*run_out)(HWVoiceOut *hw, size_t live);
 int  (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
 
 int  (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
 void (*fini_in) (HWVoiceIn *hw);
-int  (*run_in)  (HWVoiceIn *hw);
+size_t (*run_in)(HWVoiceIn *hw);
 int  (*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
 };
 
@@ -207,10 +207,10 @@ audio_driver *audio_driver_lookup(const char *name);
 void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
 void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int 
len);
 
-int  audio_pcm_hw_get_live_in (HWVoiceIn *hw);
+size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw);
 
-int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
-   int live, int pending);
+size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
+ size_t live, size_t pending);
 
 int audio_bug (const char *funcname, int cond);
 void *audio_calloc (const char *funcname, int nmemb, size_t size);
@@ -223,7 +223,7 @@ void audio_run(AudioState *s, const char *msg);
 
 #define VOICE_VOLUME_CAP (1 << VOICE_VOLUME)
 
-static inline int audio_ring_dist (int dst, int src, int len)
+static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)
 {
 return (dst >= src) ? (dst - src) : (len - src + dst);
 }
diff --git a/audio/audio_template.h b/audio/audio_template.h
index ce1e5d6559..9a8aa1eebf 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -75,16 +75,16 @@ static void glue (audio_pcm_hw_free_resources_, TYPE) (HW 
*hw)
 HWBUF = NULL;
 }
 
-static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
+static bool 

[Qemu-devel] [PATCH v3 24/50] audio: remove read and write pcm_ops

2019-01-16 Thread Kővágó, Zoltán
They just called audio_pcm_sw_read/write anyway, so it makes no sense
to have them too.  (The noaudio's read is the only exception, but it
should work with the generic code too.)

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h   |  5 -
 audio/alsaaudio.c   | 12 
 audio/audio.c   |  8 
 audio/coreaudio.c   |  6 --
 audio/dsoundaudio.c | 12 
 audio/noaudio.c | 19 ---
 audio/ossaudio.c| 12 
 audio/paaudio.c | 12 
 audio/sdlaudio.c|  6 --
 audio/spiceaudio.c  | 12 
 audio/wavaudio.c|  6 --
 11 files changed, 4 insertions(+), 106 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 02ec6ea738..40b3515b4e 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -149,13 +149,11 @@ struct audio_pcm_ops {
 int  (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
 void (*fini_out)(HWVoiceOut *hw);
 int  (*run_out) (HWVoiceOut *hw, int live);
-int  (*write)   (SWVoiceOut *sw, void *buf, int size);
 int  (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
 
 int  (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
 void (*fini_in) (HWVoiceIn *hw);
 int  (*run_in)  (HWVoiceIn *hw);
-int  (*read)(SWVoiceIn *sw, void *buf, int size);
 int  (*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
 };
 
@@ -209,11 +207,8 @@ audio_driver *audio_driver_lookup(const char *name);
 void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
 void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int 
len);
 
-int  audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
 int  audio_pcm_hw_get_live_in (HWVoiceIn *hw);
 
-int  audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len);
-
 int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
int live, int pending);
 
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 9dfd5fd26f..4c6bbdbc1d 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -269,11 +269,6 @@ static int alsa_poll_in (HWVoiceIn *hw)
 return alsa_poll_helper (alsa->handle, >pollhlp, POLLIN);
 }
 
-static int alsa_write (SWVoiceOut *sw, void *buf, int len)
-{
-return audio_pcm_sw_write (sw, buf, len);
-}
-
 static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
 {
 switch (fmt) {
@@ -995,11 +990,6 @@ static int alsa_run_in (HWVoiceIn *hw)
 return read_samples;
 }
 
-static int alsa_read (SWVoiceIn *sw, void *buf, int size)
-{
-return audio_pcm_sw_read (sw, buf, size);
-}
-
 static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 {
 ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
@@ -1088,13 +1078,11 @@ static struct audio_pcm_ops alsa_pcm_ops = {
 .init_out = alsa_init_out,
 .fini_out = alsa_fini_out,
 .run_out  = alsa_run_out,
-.write= alsa_write,
 .ctl_out  = alsa_ctl_out,
 
 .init_in  = alsa_init_in,
 .fini_in  = alsa_fini_in,
 .run_in   = alsa_run_in,
-.read = alsa_read,
 .ctl_in   = alsa_ctl_in,
 };
 
diff --git a/audio/audio.c b/audio/audio.c
index 4d0d316ce3..f844411d59 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -597,7 +597,7 @@ static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
 }
 }
 
-int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
+static int audio_pcm_sw_read(SWVoiceIn *sw, void *buf, int size)
 {
 HWVoiceIn *hw = sw->hw;
 int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
@@ -699,7 +699,7 @@ static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int 
*nb_live)
 /*
  * Soft voice (playback)
  */
-int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
+static int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
 {
 int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
 int ret = 0, pos = 0, total = 0;
@@ -857,7 +857,7 @@ int AUD_write (SWVoiceOut *sw, void *buf, int size)
 return 0;
 }
 
-return sw->hw->pcm_ops->write(sw, buf, size);
+return audio_pcm_sw_write(sw, buf, size);
 }
 
 int AUD_read (SWVoiceIn *sw, void *buf, int size)
@@ -872,7 +872,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size)
 return 0;
 }
 
-return sw->hw->pcm_ops->read(sw, buf, size);
+return audio_pcm_sw_read(sw, buf, size);
 }
 
 int AUD_get_buffer_size_out (SWVoiceOut *sw)
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index b6935359ee..a45d69 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -489,11 +489,6 @@ static OSStatus audioDeviceIOProc(
 return 0;
 }
 
-static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
-{
-return audio_pcm_sw_write (sw, buf, len);
-}
-
 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
   void *drv_opaque)
 {
@@ -692,7 +687,6 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
 .init_out = coreaudio_init_out,
 .fini_out = 

[Qemu-devel] [PATCH v3 38/50] audio: remove hw->samples, buffer_size_in/out pcm_ops

2019-01-16 Thread Kővágó, Zoltán
This patch removes the samples member from HWVoiceIn and HWVoiceOut.
Backends can specify buffer size via the newly added buffer_size_in and
buffer_size_out functions in audio_pcm_ops.  They are optional, if not
defined qemu will fall back to some built-in constant.

Signed-off-by: Kővágó, Zoltán 
---

Notes:
Not sure if this is necessary.  At first it seemed like a good idea to
have a function so that backends can compute the size on demand when
needed and things like that, but currently it's just a burden.  The only
good feature is that it allows a backend to not define a function and
let the audio subsystem choose a default value, but the same could be
achieved by specifying that hw->samples = 0 means use a default value.

So if you guys agree, I'll remove this patch.  Maybe add an -audiodev
parameter to change it, overriding whatever the backends supplies.

 audio/audio_int.h   |  5 +++--
 audio/audio_template.h  | 24 +++-
 audio/dsound_template.h |  8 +++-
 audio/alsaaudio.c   | 20 ++--
 audio/audio.c   |  2 --
 audio/coreaudio.c   | 10 +-
 audio/dsoundaudio.c |  4 
 audio/noaudio.c |  2 --
 audio/ossaudio.c| 22 +++---
 audio/paaudio.c | 21 +
 audio/sdlaudio.c| 10 +-
 audio/spiceaudio.c  | 14 --
 audio/wavaudio.c|  1 -
 13 files changed, 113 insertions(+), 30 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 97d159f28e..a5263966a8 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -70,7 +70,6 @@ typedef struct HWVoiceOut {
 void *buf_emul;
 size_t pos_emul, pending_emul, size_emul;
 
-size_t samples;
 QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
 QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
 int ctl_caps;
@@ -93,7 +92,6 @@ typedef struct HWVoiceIn {
 void *buf_emul;
 size_t pos_emul, pending_emul, size_emul;
 
-size_t samples;
 QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
 int ctl_caps;
 struct audio_pcm_ops *pcm_ops;
@@ -155,6 +153,8 @@ struct audio_pcm_ops {
 int(*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
 void   (*fini_out)(HWVoiceOut *hw);
 size_t (*write)   (HWVoiceOut *hw, void *buf, size_t size);
+/* get the optimal buffer size in samples; optional */
+size_t (*buffer_size_out)(HWVoiceOut *hw);
 /*
  * get a buffer that after later can be passed to put_buffer_out; optional
  * returns the buffer, and writes it's size to size (in bytes)
@@ -172,6 +172,7 @@ struct audio_pcm_ops {
 int(*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
 void   (*fini_in) (HWVoiceIn *hw);
 size_t (*read)(HWVoiceIn *hw, void *buf, size_t size);
+size_t (*buffer_size_in)(HWVoiceIn *hw);
 void  *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);
 void   (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);
 int(*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 83ffc62183..07ce9ce51f 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -78,7 +78,20 @@ static void glue (audio_pcm_hw_free_resources_, TYPE) (HW 
*hw)
 
 static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
 {
-size_t samples = hw->samples;
+size_t samples;
+if (!hw->pcm_ops) {
+/*
+ * We should only end up here when using wavcapture hmp command (and 
not
+ * the wavcapture audio backend).
+ * It needs a lot of samples, otherwise you'll end up with "Could not
+ * mix X bytes into a capture buffer" warnings and a garbled capture.
+ */
+samples = 4096 * 4;
+} else if (hw->pcm_ops->glue(buffer_size_, TYPE)) {
+samples = hw->pcm_ops->glue(buffer_size_, TYPE)(hw);
+} else {
+samples = 1024; /* todo better default */
+}
 if (audio_bug(__func__, samples == 0)) {
 dolog("Attempted to allocate empty buffer\n");
 }
@@ -264,11 +277,6 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
 goto err0;
 }
 
-if (audio_bug(__func__, hw->samples <= 0)) {
-dolog("hw->samples=%zd\n", hw->samples);
-goto err1;
-}
-
 #ifdef DAC
 hw->clip = mixeng_clip
 #else
@@ -288,9 +296,7 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
 #endif
 return hw;
 
- err1:
-glue (hw->pcm_ops->fini_, TYPE) (hw);
- err0:
+err0:
 g_free (hw);
 return NULL;
 }
diff --git a/audio/dsound_template.h b/audio/dsound_template.h
index ff5a1f85fd..6a10b6751b 100644
--- a/audio/dsound_template.h
+++ b/audio/dsound_template.h
@@ -254,7 +254,7 @@ static int dsound_init_out(HWVoiceOut *hw, struct 
audsettings *as,
 );
 }
 hw->size_emul = bc.dwBufferBytes;
-hw->samples = bc.dwBufferBytes >> hw->info.shift;
+ds->samples 

[Qemu-devel] [PATCH v3 45/50] audio: replace shift in audio_pcm_info with bytes_per_frame

2019-01-16 Thread Kővágó, Zoltán
The bit shifting trick worked because the number of bytes per frame was
always a power-of-two (since QEMU only supports mono, stereo and 8, 16
and 32 bit samples).  But if we want to add support for surround sound,
this no longer holds true.

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h   |  3 +-
 audio/dsound_template.h | 10 +++---
 audio/alsaaudio.c   | 10 +++---
 audio/audio.c   | 76 -
 audio/coreaudio.c   |  4 +--
 audio/dsoundaudio.c |  4 +--
 audio/noaudio.c |  2 +-
 audio/ossaudio.c| 14 
 audio/spiceaudio.c  |  5 +--
 audio/wavaudio.c|  6 ++--
 10 files changed, 67 insertions(+), 67 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index cef749d647..925552a2f7 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -43,8 +43,7 @@ struct audio_pcm_info {
 int sign;
 int freq;
 int nchannels;
-int align;
-int shift;
+int bytes_per_frame;
 int bytes_per_second;
 int swap_endianness;
 };
diff --git a/audio/dsound_template.h b/audio/dsound_template.h
index 6a10b6751b..31d356d084 100644
--- a/audio/dsound_template.h
+++ b/audio/dsound_template.h
@@ -98,8 +98,8 @@ static int glue (dsound_lock_, TYPE) (
 goto fail;
 }
 
-if ((p1p && *p1p && (*blen1p & info->align)) ||
-(p2p && *p2p && (*blen2p & info->align))) {
+if ((p1p && *p1p && (*blen1p % info->bytes_per_frame)) ||
+(p2p && *p2p && (*blen2p % info->bytes_per_frame))) {
 dolog ("DirectSound returned misaligned buffer %ld %ld\n",
*blen1p, *blen2p);
 glue (dsound_unlock_, TYPE) (buf, *p1p, p2p ? *p2p : NULL, *blen1p,
@@ -247,14 +247,14 @@ static int dsound_init_out(HWVoiceOut *hw, struct 
audsettings *as,
 obt_as.endianness = 0;
 audio_pcm_init_info (>info, _as);
 
-if (bc.dwBufferBytes & hw->info.align) {
+if (bc.dwBufferBytes % hw->info.bytes_per_frame) {
 dolog (
 "GetCaps returned misaligned buffer size %ld, alignment %d\n",
-bc.dwBufferBytes, hw->info.align + 1
+bc.dwBufferBytes, hw->info.bytes_per_frame
 );
 }
 hw->size_emul = bc.dwBufferBytes;
-ds->samples = bc.dwBufferBytes >> hw->info.shift;
+ds->samples = bc.dwBufferBytes / hw->info.bytes_per_frame;
 ds->s = s;
 
 #ifdef DEBUG_DSOUND
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 446bb90ceb..3e5c800d38 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -611,7 +611,7 @@ static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t 
len)
 {
 ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
 size_t pos = 0;
-size_t len_frames = len >> hw->info.shift;
+size_t len_frames = len / hw->info.bytes_per_frame;
 
 while (len_frames) {
 char *src = advance(buf, pos);
@@ -655,7 +655,7 @@ static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t 
len)
 }
 }
 
-pos += written << hw->info.shift;
+pos += written * hw->info.bytes_per_frame;
 if (written < len_frames) {
 break;
 }
@@ -821,7 +821,7 @@ static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t 
len)
 void *dst = advance(buf, pos);
 snd_pcm_sframes_t nread;
 
-nread = snd_pcm_readi(alsa->handle, dst, len >> hw->info.shift);
+nread = snd_pcm_readi(alsa->handle, dst, len / 
hw->info.bytes_per_frame);
 
 if (nread <= 0) {
 switch (nread) {
@@ -847,8 +847,8 @@ static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t 
len)
 }
 }
 
-pos += nread << hw->info.shift;
-len -= nread << hw->info.shift;
+pos += nread * hw->info.bytes_per_frame;
+len -= nread * hw->info.bytes_per_frame;
 }
 
 return pos;
diff --git a/audio/audio.c b/audio/audio.c
index a5ee0c4324..c89e82443d 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -297,26 +297,27 @@ static int audio_pcm_info_eq (struct audio_pcm_info 
*info, struct audsettings *a
 
 void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
 {
-int bits = 8, sign = 0, shift = 0;
+int bits = 8, sign = 0, mul;
 
 switch (as->fmt) {
 case AUDIO_FORMAT_S8:
 sign = 1;
 case AUDIO_FORMAT_U8:
+mul = 1;
 break;
 
 case AUDIO_FORMAT_S16:
 sign = 1;
 case AUDIO_FORMAT_U16:
 bits = 16;
-shift = 1;
+mul = 2;
 break;
 
 case AUDIO_FORMAT_S32:
 sign = 1;
 case AUDIO_FORMAT_U32:
 bits = 32;
-shift = 2;
+mul = 4;
 break;
 
 default:
@@ -327,9 +328,8 @@ void audio_pcm_init_info (struct audio_pcm_info *info, 
struct audsettings *as)
 info->bits = bits;
 info->sign = sign;
 info->nchannels = as->nchannels;
-info->shift = (as->nchannels == 2) + shift;
-info->align = (1 << info->shift) - 1;
-info->bytes_per_second = info->freq << 

[Qemu-devel] [PATCH v3 44/50] audio: support more than two channels in volume setting

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/audio.h  | 10 ++
 audio/audio_int.h  |  4 ++--
 audio/audio.c  | 28 
 audio/paaudio.c| 20 
 audio/spiceaudio.c | 14 --
 5 files changed, 52 insertions(+), 24 deletions(-)

diff --git a/audio/audio.h b/audio/audio.h
index 2db27bba7b..bfb7ab2197 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -123,6 +123,16 @@ uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, 
QEMUAudioTimeStamp *ts);
 void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol);
 void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol);
 
+#define AUDIO_MAX_CHANNELS 16
+typedef struct Volume {
+bool mute;
+int channels;
+uint8_t vol[AUDIO_MAX_CHANNELS];
+} Volume;
+
+void audio_set_volume_out(SWVoiceOut *sw, Volume *vol);
+void audio_set_volume_in(SWVoiceIn *sw, Volume *vol);
+
 SWVoiceIn *AUD_open_in (
 QEMUSoundCard *card,
 SWVoiceIn *sw,
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 6fec4f159c..cef749d647 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -165,7 +165,7 @@ struct audio_pcm_ops {
  */
 size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size);
 void   (*enable_out)(HWVoiceOut *hw, bool enable);
-void   (*volume_out)(HWVoiceOut *hw, struct mixeng_volume *vol);
+void   (*volume_out)(HWVoiceOut *hw, Volume *vol);
 
 int(*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
 void   (*fini_in) (HWVoiceIn *hw);
@@ -174,7 +174,7 @@ struct audio_pcm_ops {
 void  *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);
 void   (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);
 void   (*enable_in)(HWVoiceIn *hw, bool enable);
-void   (*volume_in)(HWVoiceIn *hw, struct mixeng_volume *vol);
+void   (*volume_in)(HWVoiceIn *hw, Volume *vol);
 };
 
 void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
diff --git a/audio/audio.c b/audio/audio.c
index db42d89dc3..a5ee0c4324 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1901,31 +1901,43 @@ void AUD_del_capture (CaptureVoiceOut *cap, void 
*cb_opaque)
 }
 
 void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
+{
+Volume vol = { .mute = mute, .channels = 2, .vol = { lvol, rvol } };
+audio_set_volume_out(sw, );
+}
+
+void audio_set_volume_out(SWVoiceOut *sw, Volume *vol)
 {
 if (sw) {
 HWVoiceOut *hw = sw->hw;
 
-sw->vol.mute = mute;
-sw->vol.l = nominal_volume.l * lvol / 255;
-sw->vol.r = nominal_volume.r * rvol / 255;
+sw->vol.mute = vol->mute;
+sw->vol.l = nominal_volume.l * vol->vol[0] / 255;
+sw->vol.r = nominal_volume.l * vol->vol[vol->channels > 1 ? 1 : 0] / 
255;
 
 if (hw->pcm_ops->volume_out) {
-hw->pcm_ops->volume_out(hw, >vol);
+hw->pcm_ops->volume_out(hw, vol);
 }
 }
 }
 
 void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
+{
+Volume vol = { .mute = mute, .channels = 2, .vol = { lvol, rvol } };
+audio_set_volume_in(sw, );
+}
+
+void audio_set_volume_in(SWVoiceIn *sw, Volume *vol)
 {
 if (sw) {
 HWVoiceIn *hw = sw->hw;
 
-sw->vol.mute = mute;
-sw->vol.l = nominal_volume.l * lvol / 255;
-sw->vol.r = nominal_volume.r * rvol / 255;
+sw->vol.mute = vol->mute;
+sw->vol.l = nominal_volume.l * vol->vol[0] / 255;
+sw->vol.r = nominal_volume.r * vol->vol[vol->channels > 1 ? 1 : 0] / 
255;
 
 if (hw->pcm_ops->volume_in) {
-hw->pcm_ops->volume_in(hw, >vol);
+hw->pcm_ops->volume_in(hw, vol);
 }
 }
 }
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 01c5df278b..0d67c03b4c 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -537,20 +537,22 @@ static void qpa_fini_in (HWVoiceIn *hw)
 }
 }
 
-static void qpa_volume_out(HWVoiceOut *hw, struct mixeng_volume *vol)
+static void qpa_volume_out(HWVoiceOut *hw, Volume *vol)
 {
 PAVoiceOut *pa = (PAVoiceOut *) hw;
 pa_operation *op;
 pa_cvolume v;
 PAConnection *c = pa->g->conn;
+int i;
 
 #ifdef PA_CHECK_VERSION/* macro is present in 0.9.16+ */
 pa_cvolume_init ();  /* function is present in 0.9.13+ */
 #endif
 
-v.channels = 2;
-v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->l) / UINT32_MAX;
-v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->r) / UINT32_MAX;
+v.channels = vol->channels;
+for (i = 0; i < vol->channels; ++i) {
+v.values[i] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->vol[i]) / 255;
+}
 
 pa_threaded_mainloop_lock(c->mainloop);
 
@@ -577,20 +579,22 @@ static void qpa_volume_out(HWVoiceOut *hw, struct 
mixeng_volume *vol)
 pa_threaded_mainloop_unlock(c->mainloop);
 }
 
-static void qpa_volume_in(HWVoiceIn *hw, struct mixeng_volume *vol)
+static void qpa_volume_in(HWVoiceIn *hw, Volume *vol)
 {
 

[Qemu-devel] [PATCH v3 37/50] audio: unify input and output mixeng buffer management

2019-01-16 Thread Kővágó, Zoltán
Usage notes: hw->samples became hw->{mix,conv}_buf->size, except before
initialization (audio_pcm_hw_alloc_resources_*), hw->samples gives the
initial size of the STSampleBuffer.  The next commit tries to fix this
inconsistency.

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h  |  12 ++--
 audio/audio_template.h |  19 +++---
 audio/audio.c  | 130 -
 audio/ossaudio.c   |   2 +-
 4 files changed, 80 insertions(+), 83 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 1f6ec15e18..97d159f28e 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -51,6 +51,11 @@ struct audio_pcm_info {
 
 typedef struct SWVoiceCap SWVoiceCap;
 
+typedef struct STSampleBuffer {
+size_t pos, size;
+st_sample samples[];
+} STSampleBuffer;
+
 typedef struct HWVoiceOut {
 AudioState *s;
 int enabled;
@@ -59,11 +64,9 @@ typedef struct HWVoiceOut {
 struct audio_pcm_info info;
 
 f_sample *clip;
-
-size_t rpos;
 uint64_t ts_helper;
 
-struct st_sample *mix_buf;
+STSampleBuffer *mix_buf;
 void *buf_emul;
 size_t pos_emul, pending_emul, size_emul;
 
@@ -83,11 +86,10 @@ typedef struct HWVoiceIn {
 
 t_sample *conv;
 
-size_t wpos;
 size_t total_samples_captured;
 uint64_t ts_helper;
 
-struct st_sample *conv_buf;
+STSampleBuffer *conv_buf;
 void *buf_emul;
 size_t pos_emul, pending_emul, size_emul;
 
diff --git a/audio/audio_template.h b/audio/audio_template.h
index fcab583cfc..83ffc62183 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -76,16 +76,15 @@ static void glue (audio_pcm_hw_free_resources_, TYPE) (HW 
*hw)
 HWBUF = NULL;
 }
 
-static bool glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
+static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
 {
-HWBUF = audio_calloc(__func__, hw->samples, sizeof(struct st_sample));
-if (!HWBUF) {
-dolog("Could not allocate " NAME " buffer (%zu samples)\n",
-  hw->samples);
-return false;
+size_t samples = hw->samples;
+if (audio_bug(__func__, samples == 0)) {
+dolog("Attempted to allocate empty buffer\n");
 }
 
-return true;
+HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
+HWBUF->size = samples;
 }
 
 static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
@@ -104,7 +103,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW 
*sw)
 {
 int samples;
 
-samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
+samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
 
 sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
 if (!sw->buf) {
@@ -280,9 +279,7 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
 [hw->info.swap_endianness]
 [audio_bits_to_index (hw->info.bits)];
 
-if (!glue(audio_pcm_hw_alloc_resources_, TYPE)(hw)) {
-goto err1;
-}
+glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);
 
 QLIST_INSERT_HEAD (>glue (hw_head_, TYPE), hw, entries);
 glue (s->nb_hw_voices_, TYPE) -= 1;
diff --git a/audio/audio.c b/audio/audio.c
index 8bfc122e60..b5dbf5228b 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -545,8 +545,8 @@ static size_t audio_pcm_hw_find_min_in (HWVoiceIn *hw)
 static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
 {
 size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
-if (audio_bug(__func__, live > hw->samples)) {
-dolog("live=%zu hw->samples=%zu\n", live, hw->samples);
+if (audio_bug(__func__, live > hw->conv_buf->size)) {
+dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
 return 0;
 }
 return live;
@@ -555,17 +555,17 @@ static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
 static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
 {
 size_t clipped = 0;
-size_t pos = hw->rpos;
+size_t pos = hw->mix_buf->pos;
 
 while (len) {
-st_sample *src = hw->mix_buf + pos;
+st_sample *src = hw->mix_buf->samples + pos;
 uint8_t *dst = advance (pcm_buf, clipped << hw->info.shift);
-size_t samples_till_end_of_buf = hw->samples - pos;
+size_t samples_till_end_of_buf = hw->mix_buf->size - pos;
 size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
 
 hw->clip (dst, src, samples_to_clip);
 
-pos = (pos + samples_to_clip) % hw->samples;
+pos = (pos + samples_to_clip) % hw->mix_buf->size;
 len -= samples_to_clip;
 clipped += samples_to_clip;
 }
@@ -580,17 +580,17 @@ static size_t audio_pcm_sw_get_rpos_in(SWVoiceIn *sw)
 ssize_t live = hw->total_samples_captured - sw->total_hw_samples_acquired;
 ssize_t rpos;
 
-if (audio_bug(__func__, live < 0 || live > hw->samples)) {
-dolog("live=%zu hw->samples=%zu\n", live, hw->samples);
+if (audio_bug(__func__, live < 0 || live > 

[Qemu-devel] [PATCH v3 50/50] usbaudio: change playback counters to 64 bit

2019-01-16 Thread Kővágó, Zoltán
With stereo playback, they need about 375 minutes of continuous audio
playback to overflow, which is usually not a problem (as stopping and
later resuming playback resets the counters).  But with 7.1 audio, they
only need about 95 minutes to overflow.

After the overflow, the buf->prod % USBAUDIO_PACKET_SIZE(channels)
assertion no longer holds true, which will result in overflowing the
buffer.  With 64 bit variables, it would take about 762000 years to
overflow.

Signed-off-by: Kővágó, Zoltán 
---
 hw/usb/dev-audio.c | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index f7406da5a4..82bc6eb88f 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -577,9 +577,9 @@ static const USBDesc desc_audio_multi = {
 
 struct streambuf {
 uint8_t *data;
-uint32_t size;
-uint32_t prod;
-uint32_t cons;
+size_t size;
+uint64_t prod;
+uint64_t cons;
 };
 
 static void streambuf_init(struct streambuf *buf, uint32_t size,
@@ -600,7 +600,7 @@ static void streambuf_fini(struct streambuf *buf)
 
 static int streambuf_put(struct streambuf *buf, USBPacket *p, uint32_t 
channels)
 {
-uint32_t free = buf->size - (buf->prod - buf->cons);
+int64_t free = buf->size - (buf->prod - buf->cons);
 
 if (free < USBAUDIO_PACKET_SIZE(channels)) {
 return 0;
@@ -609,6 +609,8 @@ static int streambuf_put(struct streambuf *buf, USBPacket 
*p, uint32_t channels)
 return 0;
 }
 
+/* can happen if prod overflows */
+assert(buf->prod % USBAUDIO_PACKET_SIZE(channels) == 0);
 usb_packet_copy(p, buf->data + (buf->prod % buf->size),
 USBAUDIO_PACKET_SIZE(channels));
 buf->prod += USBAUDIO_PACKET_SIZE(channels);
@@ -617,10 +619,10 @@ static int streambuf_put(struct streambuf *buf, USBPacket 
*p, uint32_t channels)
 
 static uint8_t *streambuf_get(struct streambuf *buf, size_t *len)
 {
-uint32_t used = buf->prod - buf->cons;
+int64_t used = buf->prod - buf->cons;
 uint8_t *data;
 
-if (!used) {
+if (used <= 0) {
 *len = 0;
 return NULL;
 }
-- 
2.20.1




[Qemu-devel] [PATCH v3 46/50] audio: basic support for multichannel audio

2019-01-16 Thread Kővágó, Zoltán
Which currently only means removing some checks.  Old code won't require
more than two channels, but new code will need it.

Signed-off-by: Kővágó, Zoltán 
---
 audio/alsaaudio.c | 7 ---
 audio/audio.c | 2 +-
 2 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 3e5c800d38..f6fe95b557 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -497,13 +497,6 @@ static int alsa_open(bool in, struct alsa_params_req *req,
 goto err;
 }
 
-if (nchannels != 1 && nchannels != 2) {
-alsa_logerr2 (err, typ,
-  "Can not handle obtained number of channels %d\n",
-  nchannels);
-goto err;
-}
-
 if (pdo->buffer_count) {
 if (pdo->buffer_len) {
 int64_t req = pdo->buffer_len * pdo->buffer_count;
diff --git a/audio/audio.c b/audio/audio.c
index c89e82443d..f59dd0100f 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -240,7 +240,7 @@ static int audio_validate_settings (struct audsettings *as)
 {
 int invalid;
 
-invalid = as->nchannels != 1 && as->nchannels != 2;
+invalid = as->nchannels < 1;
 invalid |= as->endianness != 0 && as->endianness != 1;
 
 switch (as->fmt) {
-- 
2.20.1




Re: [Qemu-devel] [PATCH qemu 0/2] linux-headers: Update to v5.0-rc2

2019-01-16 Thread Alexey Kardashevskiy



On 16/01/2019 22:49, Paolo Bonzini wrote:
> On 16/01/19 12:47, Cornelia Huck wrote:
>> On Wed, 16 Jan 2019 15:17:10 +1100
>> Alexey Kardashevskiy  wrote:
>>
>>> Here is the update script update and what it did to the v5.0-rc2 kernel.
>>>
>>> This is based on sha1
>>> a0a8bff Greg Kurz "target/ppc/kvm: Drop useless include directive".
>>>
>>> Please comment. Thanks.
>>
>> Hm, Paolo had already posted an update to -rc1 (including an update of
>> the script). Not sure what the status of that one is?
> 
> It's queued in my next pull request.

Is this in any publicly available git tree?


-- 
Alexey



[Qemu-devel] [PATCH v3 29/50] dsoundaudio: port to the new audio backend api

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/dsound_template.h |  45 +++---
 audio/dsoundaudio.c | 329 ++--
 2 files changed, 102 insertions(+), 272 deletions(-)

diff --git a/audio/dsound_template.h b/audio/dsound_template.h
index 96181efb36..ff5a1f85fd 100644
--- a/audio/dsound_template.h
+++ b/audio/dsound_template.h
@@ -29,6 +29,8 @@
 #define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
 #define FIELD dsound_capture_buffer
 #define FIELD2 dsound_capture
+#define HWVOICE HWVoiceIn
+#define DSOUNDVOICE DSoundVoiceIn
 #else
 #define NAME "playback buffer"
 #define NAME2 "DirectSound"
@@ -37,6 +39,8 @@
 #define BUFPTR LPDIRECTSOUNDBUFFER
 #define FIELD dsound_buffer
 #define FIELD2 dsound
+#define HWVOICE HWVoiceOut
+#define DSOUNDVOICE DSoundVoiceOut
 #endif
 
 static int glue (dsound_unlock_, TYPE) (
@@ -72,8 +76,6 @@ static int glue (dsound_lock_, TYPE) (
 )
 {
 HRESULT hr;
-LPVOID p1 = NULL, p2 = NULL;
-DWORD blen1 = 0, blen2 = 0;
 DWORD flag;
 
 #ifdef DSBTYPE_IN
@@ -81,7 +83,7 @@ static int glue (dsound_lock_, TYPE) (
 #else
 flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
 #endif
-hr = glue(IFACE, _Lock)(buf, pos, len, , , , , flag);
+hr = glue(IFACE, _Lock)(buf, pos, len, p1p, blen1p, p2p, blen2p, flag);
 
 if (FAILED (hr)) {
 #ifndef DSBTYPE_IN
@@ -96,34 +98,34 @@ static int glue (dsound_lock_, TYPE) (
 goto fail;
 }
 
-if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
+if ((p1p && *p1p && (*blen1p & info->align)) ||
+(p2p && *p2p && (*blen2p & info->align))) {
 dolog ("DirectSound returned misaligned buffer %ld %ld\n",
-   blen1, blen2);
-glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
+   *blen1p, *blen2p);
+glue (dsound_unlock_, TYPE) (buf, *p1p, p2p ? *p2p : NULL, *blen1p,
+ blen2p ? *blen2p : 0);
 goto fail;
 }
 
-if (!p1 && blen1) {
-dolog ("warning: !p1 && blen1=%ld\n", blen1);
-blen1 = 0;
+if (p1p && !*p1p && *blen1p) {
+dolog("warning: !p1 && blen1=%ld\n", *blen1p);
+*blen1p = 0;
 }
 
-if (!p2 && blen2) {
-dolog ("warning: !p2 && blen2=%ld\n", blen2);
-blen2 = 0;
+if (p2p && !*p2p && *blen2p) {
+dolog("warning: !p2 && blen2=%ld\n", *blen2p);
+*blen2p = 0;
 }
 
-*p1p = p1;
-*p2p = p2;
-*blen1p = blen1;
-*blen2p = blen2;
 return 0;
 
  fail:
 *p1p = NULL - 1;
-*p2p = NULL - 1;
 *blen1p = -1;
-*blen2p = -1;
+if (p2p) {
+*p2p = NULL - 1;
+*blen2p = -1;
+}
 return -1;
 }
 
@@ -242,7 +244,6 @@ static int dsound_init_out(HWVoiceOut *hw, struct 
audsettings *as,
 goto fail0;
 }
 
-ds->first_time = 1;
 obt_as.endianness = 0;
 audio_pcm_init_info (>info, _as);
 
@@ -252,15 +253,13 @@ static int dsound_init_out(HWVoiceOut *hw, struct 
audsettings *as,
 bc.dwBufferBytes, hw->info.align + 1
 );
 }
+hw->size_emul = bc.dwBufferBytes;
 hw->samples = bc.dwBufferBytes >> hw->info.shift;
 ds->s = s;
 
 #ifdef DEBUG_DSOUND
 dolog ("caps %ld, desc %ld\n",
bc.dwBufferBytes, bd.dwBufferBytes);
-
-dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
-   hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
 #endif
 return 0;
 
@@ -276,3 +275,5 @@ static int dsound_init_out(HWVoiceOut *hw, struct 
audsettings *as,
 #undef BUFPTR
 #undef FIELD
 #undef FIELD2
+#undef HWVOICE
+#undef DSOUNDVOICE
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index 906cca3235..951152ecea 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -53,19 +53,11 @@ typedef struct {
 typedef struct {
 HWVoiceOut hw;
 LPDIRECTSOUNDBUFFER dsound_buffer;
-DWORD old_pos;
-int first_time;
 dsound *s;
-#ifdef DEBUG_DSOUND
-DWORD old_ppos;
-DWORD played;
-DWORD mixed;
-#endif
 } DSoundVoiceOut;
 
 typedef struct {
 HWVoiceIn hw;
-int first_time;
 LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
 dsound *s;
 } DSoundVoiceIn;
@@ -243,11 +235,6 @@ static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
 dsound_log_hresult (hr);
 }
 
-static uint64_t usecs_to_bytes(struct audio_pcm_info *info, uint32_t usecs)
-{
-return muldiv64(usecs, info->bytes_per_second, 100);
-}
-
 #ifdef DEBUG_DSOUND
 static void print_wave_format (WAVEFORMATEX *wfx)
 {
@@ -312,33 +299,6 @@ static int dsound_get_status_in 
(LPDIRECTSOUNDCAPTUREBUFFER dscb,
 return 0;
 }
 
-static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
-{
-int src_len1 = dst_len;
-int src_len2 = 0;
-int pos = hw->rpos + dst_len;
-struct st_sample *src1 = hw->mix_buf + hw->rpos;
-struct st_sample *src2 = NULL;
-
-if (pos > hw->samples) {
-src_len1 = hw->samples - hw->rpos;
-src2 = hw->mix_buf;
-src_len2 = 

[Qemu-devel] [PATCH v3 48/50] usb-audio: do not count on avail bytes actually available

2019-01-16 Thread Kővágó, Zoltán
This assumption is no longer true when mixeng is turned off.

Signed-off-by: Kővágó, Zoltán 
---
 hw/usb/dev-audio.c | 30 ++
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index 84e737808c..0bfdd52423 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -318,30 +318,31 @@ static int streambuf_put(struct streambuf *buf, USBPacket 
*p)
 {
 uint32_t free = buf->size - (buf->prod - buf->cons);
 
-if (!free) {
+if (free < USBAUDIO_PACKET_SIZE) {
 return 0;
 }
 if (p->iov.size != USBAUDIO_PACKET_SIZE) {
 return 0;
 }
-assert(free >= USBAUDIO_PACKET_SIZE);
+
 usb_packet_copy(p, buf->data + (buf->prod % buf->size),
 USBAUDIO_PACKET_SIZE);
 buf->prod += USBAUDIO_PACKET_SIZE;
 return USBAUDIO_PACKET_SIZE;
 }
 
-static uint8_t *streambuf_get(struct streambuf *buf)
+static uint8_t *streambuf_get(struct streambuf *buf, size_t *len)
 {
 uint32_t used = buf->prod - buf->cons;
 uint8_t *data;
 
 if (!used) {
+*len = 0;
 return NULL;
 }
-assert(used >= USBAUDIO_PACKET_SIZE);
 data = buf->data + (buf->cons % buf->size);
-buf->cons += USBAUDIO_PACKET_SIZE;
+*len = MIN(buf->prod - buf->cons,
+   buf->size - (buf->cons % buf->size));
 return data;
 }
 
@@ -373,16 +374,21 @@ static void output_callback(void *opaque, int avail)
 USBAudioState *s = opaque;
 uint8_t *data;
 
-for (;;) {
-if (avail < USBAUDIO_PACKET_SIZE) {
-return;
-}
-data = streambuf_get(>out.buf);
+while (avail) {
+size_t written, len;
+
+data = streambuf_get(>out.buf, );
 if (!data) {
 return;
 }
-AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE);
-avail -= USBAUDIO_PACKET_SIZE;
+
+written = AUD_write(s->out.voice, data, len);
+avail -= written;
+s->out.buf.cons += written;
+
+if (written < len) {
+return;
+}
 }
 }
 
-- 
2.20.1




[Qemu-devel] [PATCH v3 34/50] spiceaudio: port to the new audio backend api

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/spiceaudio.c | 112 +++--
 1 file changed, 38 insertions(+), 74 deletions(-)

diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 1a777bba17..d1605d3939 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -51,7 +51,7 @@ typedef struct SpiceVoiceOut {
 SpiceRateCtl  rate;
 int   active;
 uint32_t  *frame;
-uint32_t  *fpos;
+uint32_t  fpos;
 uint32_t  fsize;
 } SpiceVoiceOut;
 
@@ -60,7 +60,6 @@ typedef struct SpiceVoiceIn {
 SpiceRecordInstance   sin;
 SpiceRateCtl  rate;
 int   active;
-uint32_t  samples[LINE_IN_SAMPLES];
 } SpiceVoiceIn;
 
 static const SpicePlaybackInterface playback_sif = {
@@ -152,44 +151,36 @@ static void line_out_fini (HWVoiceOut *hw)
 spice_server_remove_interface (>sin.base);
 }
 
-static size_t line_out_run (HWVoiceOut *hw, size_t live)
+static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
 {
-SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
-size_t rpos, decr;
-size_t samples;
+SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+size_t decr;
 
-if (!live) {
-return 0;
+if (!out->frame) {
+spice_server_playback_get_buffer(>sin, >frame, >fsize);
+out->fpos = 0;
 }
 
-decr = rate_get_samples (>info, >rate);
-decr = MIN (live, decr);
+decr = rate_get_samples(>info, >rate);
+decr = MIN(out->fsize - out->fpos, decr);
 
-samples = decr;
-rpos = hw->rpos;
-while (samples) {
-int left_till_end_samples = hw->samples - rpos;
-int len = MIN (samples, left_till_end_samples);
+*size = decr << hw->info.shift;
+return out->frame + out->fpos;
+}
 
-if (!out->frame) {
-spice_server_playback_get_buffer (>sin, >frame, 
>fsize);
-out->fpos = out->frame;
-}
-if (out->frame) {
-len = MIN (len, out->fsize);
-hw->clip (out->fpos, hw->mix_buf + rpos, len);
-out->fsize -= len;
-out->fpos  += len;
-if (out->fsize == 0) {
-spice_server_playback_put_samples (>sin, out->frame);
-out->frame = out->fpos = NULL;
-}
-}
-rpos = (rpos + len) % hw->samples;
-samples -= len;
+static size_t line_out_put_buffer(HWVoiceOut *hw, void *buf, size_t size)
+{
+SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
+
+out->fpos += size >> 2;
+assert(buf == out->frame + out->fpos && out->fpos <= out->fsize);
+
+if (out->fpos == out->fsize) { /* buffer full */
+spice_server_playback_put_samples(>sin, out->frame);
+out->frame = NULL;
 }
-hw->rpos = rpos;
-return decr;
+
+return size;
 }
 
 static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
@@ -211,9 +202,9 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
 }
 out->active = 0;
 if (out->frame) {
-memset (out->fpos, 0, out->fsize << 2);
+memset(out->frame + out->fpos, 0, (out->fsize - out->fpos) << 2);
 spice_server_playback_put_samples (>sin, out->frame);
-out->frame = out->fpos = NULL;
+out->frame = NULL;
 }
 spice_server_playback_stop (>sin);
 break;
@@ -275,49 +266,20 @@ static void line_in_fini (HWVoiceIn *hw)
 spice_server_remove_interface (>sin.base);
 }
 
-static size_t line_in_run(HWVoiceIn *hw)
+static size_t line_in_read(HWVoiceIn *hw, void *buf, size_t len)
 {
 SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
-size_t num_samples;
-int ready;
-size_t len[2];
-uint64_t delta_samp;
-const uint32_t *samples;
+uint64_t delta_samp = rate_get_samples(>info, >rate);
+uint64_t to_read = MIN(len >> 2, delta_samp);
+size_t ready = spice_server_record_get_samples(>sin, buf, to_read);
 
-if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) {
-return 0;
-}
-
-delta_samp = rate_get_samples (>info, >rate);
-num_samples = MIN (num_samples, delta_samp);
-
-ready = spice_server_record_get_samples (>sin, in->samples, 
num_samples);
-samples = in->samples;
+/* XXX: do we need this? */
 if (ready == 0) {
-static const uint32_t silence[LINE_IN_SAMPLES];
-samples = silence;
-ready = LINE_IN_SAMPLES;
+memset(buf, 0, to_read << 2);
+ready = to_read;
 }
 
-num_samples = MIN (ready, num_samples);
-
-if (hw->wpos + num_samples > hw->samples) {
-len[0] = hw->samples - hw->wpos;
-len[1] = num_samples - len[0];
-} else {
-len[0] = num_samples;
-len[1] = 0;
-}
-
-hw->conv (hw->conv_buf + hw->wpos, samples, len[0]);
-
-if (len[1]) {
-hw->conv (hw->conv_buf, samples + len[0], 

[Qemu-devel] [PATCH v3 42/50] audio: make mixeng optional

2019-01-16 Thread Kővágó, Zoltán
Implementation of the previously added mixeng option.

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_template.h | 46 ---
 audio/audio.c  | 70 ++
 2 files changed, 92 insertions(+), 24 deletions(-)

diff --git a/audio/audio_template.h b/audio/audio_template.h
index 9ec565fc48..e5a4d6fa40 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -78,26 +78,32 @@ static void glue (audio_pcm_hw_free_resources_, TYPE) (HW 
*hw)
 
 static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
 {
-size_t samples;
-if (!hw->pcm_ops) {
-/*
- * We should only end up here when using wavcapture hmp command (and 
not
- * the wavcapture audio backend).
- * It needs a lot of samples, otherwise you'll end up with "Could not
- * mix X bytes into a capture buffer" warnings and a garbled capture.
- */
-samples = 4096 * 4;
-} else if (hw->pcm_ops->glue(buffer_size_, TYPE)) {
-samples = hw->pcm_ops->glue(buffer_size_, TYPE)(hw);
+if (hw->s->dev->TYPE->mixeng) {
+size_t samples;
+if (!hw->pcm_ops) {
+/*
+ * We should only end up here when using wavcapture hmp command 
(and
+ * not the wavcapture audio backend).
+ * It needs a lot of samples, otherwise you'll end up with "Could
+ * not mix X bytes into a capture buffer" warnings and a garbled
+ * capture.
+ */
+samples = 4096 * 4;
+} else if (hw->pcm_ops->glue(buffer_size_, TYPE)) {
+samples = hw->pcm_ops->glue(buffer_size_, TYPE)(hw);
+} else {
+samples = 1024; /* todo better default */
+}
+
+if (audio_bug(__func__, samples == 0)) {
+dolog("Attempted to allocate empty buffer\n");
+}
+
+HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * 
samples);
+HWBUF->size = samples;
 } else {
-samples = 1024; /* todo better default */
+HWBUF = NULL;
 }
-if (audio_bug(__func__, samples == 0)) {
-dolog("Attempted to allocate empty buffer\n");
-}
-
-HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
-HWBUF->size = samples;
 }
 
 static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
@@ -116,6 +122,10 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW 
*sw)
 {
 int samples;
 
+if (!sw->s->dev->TYPE->mixeng) {
+return 0;
+}
+
 samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
 
 sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
diff --git a/audio/audio.c b/audio/audio.c
index 6bbbcd3e03..db42d89dc3 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -839,32 +839,46 @@ static void audio_timer (void *opaque)
  */
 size_t AUD_write(SWVoiceOut *sw, void *buf, size_t size)
 {
+HWVoiceOut *hw;
+
 if (!sw) {
 /* XXX: Consider options */
 return size;
 }
+hw = sw->hw;
 
-if (!sw->hw->enabled) {
+if (!hw->enabled) {
 dolog ("Writing to disabled voice %s\n", SW_NAME (sw));
 return 0;
 }
 
-return audio_pcm_sw_write(sw, buf, size);
+if (hw->s->dev->out->mixeng) {
+return audio_pcm_sw_write(sw, buf, size);
+} else {
+return hw->pcm_ops->write(hw, buf, size);
+}
 }
 
 size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size)
 {
+HWVoiceIn *hw;
+
 if (!sw) {
 /* XXX: Consider options */
 return size;
 }
+hw = sw->hw;
 
-if (!sw->hw->enabled) {
+if (!hw->enabled) {
 dolog ("Reading from disabled voice %s\n", SW_NAME (sw));
 return 0;
 }
 
-return audio_pcm_sw_read(sw, buf, size);
+if (hw->s->dev->in->mixeng) {
+return audio_pcm_sw_read(sw, buf, size);
+} else {
+return hw->pcm_ops->read(hw, buf, size);
+}
 }
 
 int AUD_get_buffer_size_out (SWVoiceOut *sw)
@@ -1086,6 +1100,26 @@ static void audio_run_out (AudioState *s)
 HWVoiceOut *hw = NULL;
 SWVoiceOut *sw;
 
+if (!s->dev->out->mixeng) {
+while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
+/* there is exactly 1 sw for each hw with no mixeng */
+sw = hw->sw_head.lh_first;
+
+if (hw->pending_disable) {
+hw->enabled = 0;
+hw->pending_disable = 0;
+if (hw->pcm_ops->enable_out) {
+hw->pcm_ops->enable_out(hw, false);
+}
+}
+
+if (sw->active) {
+sw->callback.fn(sw->callback.opaque, INT_MAX);
+}
+}
+return;
+}
+
 while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
 size_t played, live, prev_rpos, free;
 int nb_live, cleanup_required;
@@ -1223,6 +1257,17 @@ static void audio_run_in (AudioState *s)
 {
 HWVoiceIn *hw = NULL;
 
+if 

[Qemu-devel] [PATCH v3 26/50] audio: api for mixeng code free backends

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h  |  41 ++--
 audio/audio_template.h |   1 +
 audio/audio.c  | 211 -
 3 files changed, 245 insertions(+), 8 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 9dcdf541fb..056c63d45c 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -64,6 +64,8 @@ typedef struct HWVoiceOut {
 uint64_t ts_helper;
 
 struct st_sample *mix_buf;
+void *buf_emul;
+size_t pos_emul, pending_emul, size_emul;
 
 size_t samples;
 QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
@@ -86,6 +88,8 @@ typedef struct HWVoiceIn {
 uint64_t ts_helper;
 
 struct st_sample *conv_buf;
+void *buf_emul;
+size_t pos_emul, pending_emul, size_emul;
 
 size_t samples;
 QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
@@ -146,17 +150,42 @@ struct audio_driver {
 };
 
 struct audio_pcm_ops {
-int  (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
-void (*fini_out)(HWVoiceOut *hw);
+int(*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
+void   (*fini_out)(HWVoiceOut *hw);
 size_t (*run_out)(HWVoiceOut *hw, size_t live);
-int  (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
+size_t (*write)   (HWVoiceOut *hw, void *buf, size_t size);
+/*
+ * get a buffer that after later can be passed to put_buffer_out; optional
+ * returns the buffer, and writes it's size to size (in bytes)
+ * this is unrelated to the above buffer_size_out function
+ */
+void  *(*get_buffer_out)(HWVoiceOut *hw, size_t *size);
+/*
+ * put back the buffer returned by get_buffer_out; optional
+ * buf must be equal the pointer returned by get_buffer_out,
+ * size may be smaller
+ */
+size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size);
+int(*ctl_out) (HWVoiceOut *hw, int cmd, ...);
 
-int  (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
-void (*fini_in) (HWVoiceIn *hw);
+int(*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
+void   (*fini_in) (HWVoiceIn *hw);
 size_t (*run_in)(HWVoiceIn *hw);
-int  (*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
+size_t (*read)(HWVoiceIn *hw, void *buf, size_t size);
+void  *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);
+void   (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);
+int(*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
 };
 
+void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
+void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
+void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
+size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
+size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
+size_t size);
+size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
+size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);
+
 struct capture_callback {
 struct audio_capture_ops ops;
 void *opaque;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 9a8aa1eebf..fcab583cfc 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -71,6 +71,7 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
 
 static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
 {
+g_free(hw->buf_emul);
 g_free (HWBUF);
 HWBUF = NULL;
 }
diff --git a/audio/audio.c b/audio/audio.c
index 33b11e4feb..f4d538618f 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -574,6 +574,25 @@ size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
 return clipped;
 }
 
+static void audio_pcm_hw_clip_out2(HWVoiceOut *hw, void *pcm_buf, size_t len)
+{
+size_t clipped = 0;
+size_t pos = hw->rpos;
+
+while (len) {
+st_sample *src = hw->mix_buf + pos;
+uint8_t *dst = advance (pcm_buf, clipped << hw->info.shift);
+size_t samples_till_end_of_buf = hw->samples - pos;
+size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
+
+hw->clip (dst, src, samples_to_clip);
+
+pos = (pos + samples_to_clip) % hw->samples;
+len -= samples_to_clip;
+clipped += samples_to_clip;
+}
+}
+
 /*
  * Soft voice (capture)
  */
@@ -1051,6 +1070,31 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, 
size_t rpos,
 mixeng_clear(hw->mix_buf, samples - n);
 }
 
+static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
+{
+size_t clipped = 0;
+
+while (live) {
+size_t size, decr, proc;
+void *buf = hw->pcm_ops->get_buffer_out(hw, );
+
+decr = MIN(size >> hw->info.shift, live);
+audio_pcm_hw_clip_out2(hw, buf, decr);
+proc = hw->pcm_ops->put_buffer_out(hw, buf, decr << hw->info.shift) >>
+hw->info.shift;
+
+live -= proc;
+clipped += proc;
+hw->rpos 

Re: [Qemu-devel] [PATCH] slirp: Use lduw_be_p in slirp_input

2019-01-16 Thread Samuel Thibault
Hello,

Richard Henderson, le mer. 26 déc. 2018 14:42:54 +1100, a ecrit:
> The pointer may be unaligned, so we must use our routines for that.
> At the same time, we might as well use the big-endian version
> instead of ntohs.
> 
> This fixes sparc64 host SIGBUS during pxe boot.

I'm not at ease with applying this, when Marc-André is trying to make
slirp an external library...  I'd rather apply the change below, could
somebody review it?

Samuel


slirp: Avoid unaligned 16bit memory access

pkt parameter may be unaligned, so we must access it byte-wise.

This fixes sparc64 host SIGBUS during pxe boot.

Signed-off-by: Samuel Thibault 

diff --git a/slirp/slirp.c b/slirp/slirp.c
index ab2fc4eb8b..0e41d5aedf 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -851,7 +851,7 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int 
pkt_len)
 if (pkt_len < ETH_HLEN)
 return;
 
-proto = ntohs(*(uint16_t *)(pkt + 12));
+proto = (((uint16_t) pkt[12]) << 8) + pkt[13];
 switch(proto) {
 case ETH_P_ARP:
 arp_input(slirp, pkt, pkt_len);



[Qemu-devel] [PATCH v3 43/50] paaudio: get/put_buffer functions

2019-01-16 Thread Kővágó, Zoltán
This lets us avoid some buffer copying when using mixeng.

Signed-off-by: Kővágó, Zoltán 
---
 audio/paaudio.c | 83 +
 1 file changed, 83 insertions(+)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index a45469066b..01c5df278b 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -97,6 +97,59 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
 }   \
 } while (0)
 
+static void *qpa_get_buffer_in(HWVoiceIn *hw, size_t *size)
+{
+PAVoiceIn *p = (PAVoiceIn *) hw;
+PAConnection *c = p->g->conn;
+int r;
+
+pa_threaded_mainloop_lock(c->mainloop);
+
+CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
+"pa_threaded_mainloop_lock failed\n");
+
+if (!p->read_length) {
+r = pa_stream_peek(p->stream, >read_data, >read_length);
+CHECK_SUCCESS_GOTO(c, r == 0, unlock_and_fail,
+   "pa_stream_peek failed\n");
+}
+
+*size = MIN(p->read_length, *size);
+
+pa_threaded_mainloop_unlock(c->mainloop);
+return (void *) p->read_data;
+
+unlock_and_fail:
+pa_threaded_mainloop_unlock(c->mainloop);
+*size = 0;
+return NULL;
+}
+
+static void qpa_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
+{
+PAVoiceIn *p = (PAVoiceIn *) hw;
+PAConnection *c = p->g->conn;
+int r;
+
+pa_threaded_mainloop_lock(c->mainloop);
+
+CHECK_DEAD_GOTO(c, p->stream, unlock,
+"pa_threaded_mainloop_lock failed\n");
+
+assert(buf == p->read_data && size <= p->read_length);
+
+p->read_data += size;
+p->read_length -= size;
+
+if (size && !p->read_length) {
+r = pa_stream_drop(p->stream);
+CHECK_SUCCESS_GOTO(c, r == 0, unlock, "pa_stream_drop failed\n");
+}
+
+unlock:
+pa_threaded_mainloop_unlock(c->mainloop);
+}
+
 static size_t qpa_read(HWVoiceIn *hw, void *data, size_t length)
 {
 PAVoiceIn *p = (PAVoiceIn *) hw;
@@ -135,6 +188,32 @@ unlock_and_fail:
 return 0;
 }
 
+static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size)
+{
+PAVoiceOut *p = (PAVoiceOut *) hw;
+PAConnection *c = p->g->conn;
+void *ret;
+int r;
+
+pa_threaded_mainloop_lock(c->mainloop);
+
+CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
+"pa_threaded_mainloop_lock failed\n");
+
+*size = -1;
+r = pa_stream_begin_write(p->stream, , size);
+CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail,
+   "pa_stream_begin_write failed\n");
+
+pa_threaded_mainloop_unlock(c->mainloop);
+return ret;
+
+unlock_and_fail:
+pa_threaded_mainloop_unlock(c->mainloop);
+*size = 0;
+return NULL;
+}
+
 static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length)
 {
 PAVoiceOut *p = (PAVoiceOut *) hw;
@@ -683,12 +762,16 @@ static struct audio_pcm_ops qpa_pcm_ops = {
 .fini_out = qpa_fini_out,
 .write= qpa_write,
 .buffer_size_out = qpa_buffer_size_out,
+.get_buffer_out = qpa_get_buffer_out,
+.put_buffer_out = qpa_write, /* pa handles it */
 .volume_out = qpa_volume_out,
 
 .init_in  = qpa_init_in,
 .fini_in  = qpa_fini_in,
 .read = qpa_read,
 .buffer_size_in = qpa_buffer_size_in,
+.get_buffer_in = qpa_get_buffer_in,
+.put_buffer_in = qpa_put_buffer_in,
 .volume_in = qpa_volume_in
 };
 
-- 
2.20.1




[Qemu-devel] [PATCH v3 33/50] sdlaudio: port to the new audio backend api

2019-01-16 Thread Kővágó, Zoltán
SDL2 is still a big mess, but it's probably not worse than the current
version.

Signed-off-by: Kővágó, Zoltán 
---
 audio/sdlaudio.c | 136 +--
 1 file changed, 50 insertions(+), 86 deletions(-)

diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index ff19484430..685cbc83b8 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -42,11 +42,6 @@
 
 typedef struct SDLVoiceOut {
 HWVoiceOut hw;
-size_t live;
-#if USE_SEMAPHORE
-size_t rpos;
-#endif
-size_t decr;
 } SDLVoiceOut;
 
 static struct SDLAudioState {
@@ -252,17 +247,13 @@ static void sdl_callback (void *opaque, Uint8 *buf, int 
len)
 SDLVoiceOut *sdl = opaque;
 SDLAudioState *s = _sdl;
 HWVoiceOut *hw = >hw;
-size_t samples = len >> hw->info.shift;
 
 if (s->exit) {
 return;
 }
 
-while (samples) {
-size_t to_mix, decr;
-
-/* dolog ("in callback samples=%d\n", samples); */
 #if USE_SEMAPHORE
+while (len) {
 sdl_wait (s, "sdl_callback");
 if (s->exit) {
 return;
@@ -271,95 +262,66 @@ static void sdl_callback (void *opaque, Uint8 *buf, int 
len)
 if (sdl_lock (s, "sdl_callback")) {
 return;
 }
-
-if (audio_bug(__func__, sdl->live < 0 || sdl->live > hw->samples)) {
-dolog("sdl->live=%d hw->samples=%zu\n", sdl->live, hw->samples);
-return;
-}
-
-if (!sdl->live) {
-goto again;
-}
-#else
-if (s->exit || !sdl->live) {
-break;
-}
 #endif
 
-/* dolog ("in callback live=%d\n", live); */
-to_mix = MIN (samples, sdl->live);
-decr = to_mix;
-while (to_mix) {
-size_t chunk = MIN(to_mix, hw->samples - hw->rpos);
-struct st_sample *src = hw->mix_buf + hw->rpos;
+while (hw->pending_emul && len) {
+size_t write_len;
+ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+if (start < 0) {
+start += hw->size_emul;
+}
+assert(start >= 0 && start < hw->size_emul);
 
-/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
-hw->clip (buf, src, chunk);
-#if USE_SEMAPHORE
-sdl->rpos = (sdl->rpos + chunk) % hw->samples;
-#else
-hw->rpos = (hw->rpos + chunk) % hw->samples;
-#endif
-to_mix -= chunk;
-buf += chunk << hw->info.shift;
+write_len = MIN(MIN(hw->pending_emul, len),
+hw->size_emul - start);
+
+memcpy(buf, hw->buf_emul + start, write_len);
+hw->pending_emul -= write_len;
+len -= write_len;
+buf += write_len;
 }
-samples -= decr;
-sdl->live -= decr;
-sdl->decr += decr;
 
 #if USE_SEMAPHORE
-again:
 if (sdl_unlock (s, "sdl_callback")) {
 return;
 }
-#endif
 }
-/* dolog ("done len=%d\n", len); */
-
-#if (SDL_MAJOR_VERSION >= 2)
-/* SDL2 does not clear the remaining buffer for us, so do it on our own */
-if (samples) {
-memset(buf, 0, samples << hw->info.shift);
-}
-#endif
-}
-
-static size_t sdl_run_out(HWVoiceOut *hw, size_t live)
-{
-size_t decr;
-SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
-SDLAudioState *s = _sdl;
-
-if (sdl_lock (s, "sdl_run_out")) {
-return 0;
-}
-
-if (sdl->decr > live) {
-ldebug ("sdl->decr %d live %d sdl->live %d\n",
-sdl->decr,
-live,
-sdl->live);
-}
-
-decr = MIN (sdl->decr, live);
-sdl->decr -= decr;
-
-#if USE_SEMAPHORE
-sdl->live = live - decr;
-hw->rpos = sdl->rpos;
 #else
-sdl->live = live;
+/* clear remaining buffer that we couldn't fill with data */
+if (len) {
+memset(buf, 0, len);
+}
 #endif
-
-if (sdl->live > 0) {
-sdl_unlock_and_post (s, "sdl_run_out");
-}
-else {
-sdl_unlock (s, "sdl_run_out");
-}
-return decr;
 }
 
+#define SDL_WRAPPER_FUNC(name, ret_type, args_decl, args, fail, unlock) \
+static ret_type glue(sdl_, name)args_decl   \
+{   \
+SDLAudioState *s = _sdl;   \
+ret_type ret;   \
+\
+if (sdl_lock(s, "sdl_" #name)) {\
+fail;   \
+return 0; /* implicitly casts to NULL */\
+}   \
+\
+ret = glue(audio_generic_, name)args;   \
+  

[Qemu-devel] [PATCH v3 04/50] audio: -audiodev command line option basic implementation

2019-01-16 Thread Kővágó, Zoltán
Audio drivers now get an Audiodev * as config paramters, instead of the
global audio_option structs.  There is some code in audio/audio_legacy.c
that converts the old environment variables to audiodev options (this
way backends do not have to worry about legacy options).  It also
contains a replacement of -audio-help, which prints out the equivalent
-audiodev based config of the currently specified environment variables.

Note that backends are not updated and still rely on environment
variables.

Also note that (due to moving try-poll from global to backend specific
option) currently ALSA and OSS will always try poll mode, regardless of
environment variables or -audiodev options.

Signed-off-by: Kővágó, Zoltán 
---

Notes:
Changes from v2:
* MAJOR: use qobject_input_visitor instead of QemuOpts
* almost completely rewrote legacy options handling
* added missing license comment to audio_legacy.c0

 audio/audio.h  |  18 +-
 audio/audio_int.h  |  16 +-
 audio/audio_template.h |  13 +-
 audio/alsaaudio.c  |   2 +-
 audio/audio.c  | 600 -
 audio/audio_legacy.c   | 294 
 audio/coreaudio.c  |   2 +-
 audio/dsoundaudio.c|   2 +-
 audio/noaudio.c|   2 +-
 audio/ossaudio.c   |   2 +-
 audio/paaudio.c|   2 +-
 audio/sdlaudio.c   |   2 +-
 audio/spiceaudio.c |   2 +-
 audio/wavaudio.c   |   2 +-
 vl.c   |   7 +-
 audio/Makefile.objs|   2 +-
 16 files changed, 588 insertions(+), 380 deletions(-)
 create mode 100644 audio/audio_legacy.c

diff --git a/audio/audio.h b/audio/audio.h
index 02f29a3b3e..64b0f761bc 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -36,12 +36,21 @@ typedef void (*audio_callback_fn) (void *opaque, int avail);
 #define AUDIO_HOST_ENDIANNESS 0
 #endif
 
-struct audsettings {
+typedef struct audsettings {
 int freq;
 int nchannels;
 AudioFormat fmt;
 int endianness;
-};
+} audsettings;
+
+audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo);
+int audioformat_bytes_per_sample(AudioFormat fmt);
+int audio_buffer_frames(AudiodevPerDirectionOptions *pdo,
+audsettings *as, int def_usecs);
+int audio_buffer_samples(AudiodevPerDirectionOptions *pdo,
+ audsettings *as, int def_usecs);
+int audio_buffer_bytes(AudiodevPerDirectionOptions *pdo,
+   audsettings *as, int def_usecs);
 
 typedef enum {
 AUD_CNOTIFY_ENABLE,
@@ -81,7 +90,6 @@ typedef struct QEMUAudioTimeStamp {
 void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 
0);
 void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
 
-void AUD_help (void);
 void AUD_register_card (const char *name, QEMUSoundCard *card);
 void AUD_remove_card (QEMUSoundCard *card);
 CaptureVoiceOut *AUD_add_capture (
@@ -163,4 +171,8 @@ void audio_sample_to_uint64(void *samples, int pos,
 void audio_sample_from_uint64(void *samples, int pos,
 uint64_t left, uint64_t right);
 
+void audio_parse_option(const char *opt);
+void audio_init_audiodevs(void);
+void audio_legacy_help(void);
+
 #endif /* QEMU_AUDIO_H */
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 244b454012..353467b505 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -146,7 +146,7 @@ struct audio_driver {
 const char *name;
 const char *descr;
 struct audio_option *options;
-void *(*init) (void);
+void *(*init) (Audiodev *);
 void (*fini) (void *);
 struct audio_pcm_ops *pcm_ops;
 int can_be_default;
@@ -193,6 +193,7 @@ struct SWVoiceCap {
 
 struct AudioState {
 struct audio_driver *drv;
+Audiodev *dev;
 void *drv_opaque;
 
 QEMUTimer *ts;
@@ -203,10 +204,13 @@ struct AudioState {
 int nb_hw_voices_out;
 int nb_hw_voices_in;
 int vm_running;
+int64_t period_ticks;
 };
 
 extern const struct mixeng_volume nominal_volume;
 
+extern const char *audio_prio_list[];
+
 void audio_driver_register(audio_driver *drv);
 audio_driver *audio_driver_lookup(const char *name);
 
@@ -248,4 +252,14 @@ static inline int audio_ring_dist (int dst, int src, int 
len)
 #define AUDIO_STRINGIFY_(n) #n
 #define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
 
+typedef struct AudiodevListEntry {
+Audiodev *dev;
+QSIMPLEQ_ENTRY(AudiodevListEntry) next;
+} AudiodevListEntry;
+
+typedef QSIMPLEQ_HEAD(, AudiodevListEntry) AudiodevListHead;
+AudiodevListHead audio_handle_legacy_opts(void);
+
+void audio_free_audiodev_list(AudiodevListHead *head);
+
 #endif /* QEMU_AUDIO_INT_H */
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 7de227d2d1..c1d7207abd 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -302,8 +302,10 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct 
audsettings *as)
 static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
 {
 HW *hw;
+AudioState *s = 

[Qemu-devel] [PATCH v3 31/50] ossaudio: port to the new audio backend api

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/ossaudio.c | 288 +--
 1 file changed, 104 insertions(+), 184 deletions(-)

diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index c6d4086573..774a41fbf9 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -39,19 +39,15 @@
 
 typedef struct OSSVoiceOut {
 HWVoiceOut hw;
-void *pcm_buf;
 int fd;
-int wpos;
 int nfrags;
 int fragsize;
 int mmapped;
-int pending;
 Audiodev *dev;
 } OSSVoiceOut;
 
 typedef struct OSSVoiceIn {
 HWVoiceIn hw;
-void *pcm_buf;
 int fd;
 int nfrags;
 int fragsize;
@@ -370,98 +366,87 @@ static int oss_open(int in, struct oss_params *req, 
audsettings *as,
 return -1;
 }
 
-static void oss_write_pending (OSSVoiceOut *oss)
+static size_t oss_get_available_bytes(OSSVoiceOut *oss)
 {
-HWVoiceOut *hw = >hw;
+int err;
+struct count_info cntinfo;
+assert(oss->mmapped);
 
+err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, );
+if (err < 0) {
+oss_logerr(errno, "SNDCTL_DSP_GETOPTR failed\n");
+return 0;
+}
+
+return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
+}
+
+static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
+{
+OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+if (oss->mmapped) {
+*size = MIN(oss_get_available_bytes(oss), hw->size_emul - 
hw->pos_emul);
+return hw->buf_emul + hw->pos_emul;
+} else {
+return audio_generic_get_buffer_out(hw, size);
+}
+}
+
+static size_t oss_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
+{
+OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 if (oss->mmapped) {
-return;
+assert(buf == hw->buf_emul + hw->pos_emul && size < hw->size_emul);
+
+hw->pos_emul = (hw->pos_emul + size) % hw->size_emul;
+return size;
+} else {
+return audio_generic_put_buffer_out(hw, buf, size);
+}
+}
+
+static size_t oss_write(HWVoiceOut *hw, void *buf, size_t len)
+{
+OSSVoiceOut *oss = (OSSVoiceOut *) hw;
+size_t pos;
+
+if (oss->mmapped) {
+size_t total_len;
+len = MIN(len, oss_get_available_bytes(oss));
+
+total_len = len;
+while (len) {
+size_t to_copy = MIN(len, hw->size_emul - hw->pos_emul);
+memcpy(hw->buf_emul + hw->pos_emul, buf, to_copy);
+
+hw->pos_emul = (hw->pos_emul + to_copy) % hw->pos_emul;
+buf += to_copy;
+len -= to_copy;
+}
+return total_len;
 }
 
-while (oss->pending) {
-int samples_written;
+pos = 0;
+while (len) {
 ssize_t bytes_written;
-int samples_till_end = hw->samples - oss->wpos;
-int samples_to_write = MIN (oss->pending, samples_till_end);
-int bytes_to_write = samples_to_write << hw->info.shift;
-void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
+void *pcm = advance(buf, pos);
 
-bytes_written = write (oss->fd, pcm, bytes_to_write);
+bytes_written = write(oss->fd, pcm, len);
 if (bytes_written < 0) {
 if (errno != EAGAIN) {
-oss_logerr (errno, "failed to write %d bytes\n",
-bytes_to_write);
+oss_logerr(errno, "failed to write %zu bytes\n",
+   len);
 }
-break;
-}
-
-if (bytes_written & hw->info.align) {
-dolog ("misaligned write asked for %d, but got %zd\n",
-   bytes_to_write, bytes_written);
-return;
+return pos;
 }
 
-samples_written = bytes_written >> hw->info.shift;
-oss->pending -= samples_written;
-oss->wpos = (oss->wpos + samples_written) % hw->samples;
-if (bytes_written - bytes_to_write) {
+pos += bytes_written;
+if (bytes_written < len) {
 break;
 }
+len -= bytes_written;
 }
-}
-
-static size_t oss_run_out(HWVoiceOut *hw, size_t live)
-{
-OSSVoiceOut *oss = (OSSVoiceOut *) hw;
-int err;
-size_t decr;
-struct audio_buf_info abinfo;
-struct count_info cntinfo;
-size_t bufsize;
-
-bufsize = hw->samples << hw->info.shift;
-
-if (oss->mmapped) {
-int bytes, pos;
-
-err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, );
-if (err < 0) {
-oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
-return 0;
-}
-
-pos = hw->rpos << hw->info.shift;
-bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
-decr = MIN (bytes >> hw->info.shift, live);
-}
-else {
-err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, );
-if (err < 0) {
-oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
-return 0;
-}
-
-if (abinfo.bytes > bufsize) {
-trace_oss_invalid_available_size(abinfo.bytes, bufsize);
- 

[Qemu-devel] [PATCH v3 30/50] noaudio: port to the new audio backend api

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/noaudio.c | 39 +++
 1 file changed, 15 insertions(+), 24 deletions(-)

diff --git a/audio/noaudio.c b/audio/noaudio.c
index 59e680db6f..647558f54c 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -40,10 +40,9 @@ typedef struct NoVoiceIn {
 int64_t old_ticks;
 } NoVoiceIn;
 
-static size_t no_run_out(HWVoiceOut *hw, size_t live)
+static size_t no_write(HWVoiceOut *hw, void *buf, size_t len)
 {
 NoVoiceOut *no = (NoVoiceOut *) hw;
-size_t decr, samples;
 int64_t now;
 int64_t ticks;
 int64_t bytes;
@@ -51,13 +50,9 @@ static size_t no_run_out(HWVoiceOut *hw, size_t live)
 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 ticks = now - no->old_ticks;
 bytes = muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
-bytes = MIN(bytes, SIZE_MAX);
-samples = bytes >> hw->info.shift;
 
 no->old_ticks = now;
-decr = MIN (live, samples);
-hw->rpos = (hw->rpos + decr) % hw->samples;
-return decr;
+return MIN(len, bytes);
 }
 
 static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void 
*drv_opaque)
@@ -91,25 +86,21 @@ static void no_fini_in (HWVoiceIn *hw)
 (void) hw;
 }
 
-static size_t no_run_in(HWVoiceIn *hw)
+static size_t no_read(HWVoiceIn *hw, void *buf, size_t size)
 {
+size_t to_clear;
 NoVoiceIn *no = (NoVoiceIn *) hw;
-size_t live = audio_pcm_hw_get_live_in(hw);
-size_t dead = hw->samples - live;
-size_t samples = 0;
 
-if (dead) {
-int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-int64_t ticks = now - no->old_ticks;
-int64_t bytes =
-muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
+int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+int64_t ticks = now - no->old_ticks;
+int64_t bytes =
+muldiv64 (ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
 
-no->old_ticks = now;
-bytes = MIN (bytes, SIZE_MAX);
-samples = bytes >> hw->info.shift;
-samples = MIN (samples, dead);
-}
-return samples;
+no->old_ticks = now;
+to_clear = MIN(bytes, size);
+
+audio_pcm_info_clear_buf(>info, buf, to_clear >> hw->info.shift);
+return to_clear;
 }
 
 static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
@@ -132,12 +123,12 @@ static void no_audio_fini (void *opaque)
 static struct audio_pcm_ops no_pcm_ops = {
 .init_out = no_init_out,
 .fini_out = no_fini_out,
-.run_out  = no_run_out,
+.write= no_write,
 .ctl_out  = no_ctl_out,
 
 .init_in  = no_init_in,
 .fini_in  = no_fini_in,
-.run_in   = no_run_in,
+.read = no_read,
 .ctl_in   = no_ctl_in
 };
 
-- 
2.20.1




[Qemu-devel] [PATCH v3 36/50] audio: remove remains of the old backend api

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h |  7 ---
 audio/audio.c | 42 ++
 2 files changed, 6 insertions(+), 43 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 056c63d45c..1f6ec15e18 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -152,7 +152,6 @@ struct audio_driver {
 struct audio_pcm_ops {
 int(*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
 void   (*fini_out)(HWVoiceOut *hw);
-size_t (*run_out)(HWVoiceOut *hw, size_t live);
 size_t (*write)   (HWVoiceOut *hw, void *buf, size_t size);
 /*
  * get a buffer that after later can be passed to put_buffer_out; optional
@@ -170,7 +169,6 @@ struct audio_pcm_ops {
 
 int(*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
 void   (*fini_in) (HWVoiceIn *hw);
-size_t (*run_in)(HWVoiceIn *hw);
 size_t (*read)(HWVoiceIn *hw, void *buf, size_t size);
 void  *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);
 void   (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);
@@ -236,11 +234,6 @@ audio_driver *audio_driver_lookup(const char *name);
 void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
 void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int 
len);
 
-size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw);
-
-size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
- size_t live, size_t pending);
-
 int audio_bug (const char *funcname, int cond);
 void *audio_calloc (const char *funcname, int nmemb, size_t size);
 
diff --git a/audio/audio.c b/audio/audio.c
index f4d538618f..8bfc122e60 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -542,7 +542,7 @@ static size_t audio_pcm_hw_find_min_in (HWVoiceIn *hw)
 return m;
 }
 
-size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
+static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
 {
 size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
 if (audio_bug(__func__, live > hw->samples)) {
@@ -552,29 +552,7 @@ size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
 return live;
 }
 
-size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
- size_t live, size_t pending)
-{
-size_t left = hw->samples - pending;
-size_t len = MIN (left, live);
-size_t clipped = 0;
-
-while (len) {
-struct st_sample *src = hw->mix_buf + hw->rpos;
-uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift);
-size_t samples_till_end_of_buf = hw->samples - hw->rpos;
-size_t samples_to_clip = MIN (len, samples_till_end_of_buf);
-
-hw->clip (dst, src, samples_to_clip);
-
-hw->rpos = (hw->rpos + samples_to_clip) % hw->samples;
-len -= samples_to_clip;
-clipped += samples_to_clip;
-}
-return clipped;
-}
-
-static void audio_pcm_hw_clip_out2(HWVoiceOut *hw, void *pcm_buf, size_t len)
+static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
 {
 size_t clipped = 0;
 size_t pos = hw->rpos;
@@ -1079,7 +1057,7 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t 
live)
 void *buf = hw->pcm_ops->get_buffer_out(hw, );
 
 decr = MIN(size >> hw->info.shift, live);
-audio_pcm_hw_clip_out2(hw, buf, decr);
+audio_pcm_hw_clip_out(hw, buf, decr);
 proc = hw->pcm_ops->put_buffer_out(hw, buf, decr << hw->info.shift) >>
 hw->info.shift;
 
@@ -1142,11 +1120,7 @@ static void audio_run_out (AudioState *s)
 }
 
 prev_rpos = hw->rpos;
-if (hw->pcm_ops->run_out) {
-played = hw->pcm_ops->run_out(hw, live);
-} else {
-played = audio_pcm_hw_run_out(hw, live);
-}
+played = audio_pcm_hw_run_out(hw, live);
 replay_audio_out();
 if (audio_bug(__func__, hw->rpos >= hw->samples)) {
 dolog("hw->rpos=%zu hw->samples=%zu played=%zu\n",
@@ -1243,12 +1217,8 @@ static void audio_run_in (AudioState *s)
 size_t captured = 0, min;
 
 if (replay_mode != REPLAY_MODE_PLAY) {
-if (hw->pcm_ops->run_in) {
-captured = hw->pcm_ops->run_in(hw);
-} else {
-captured = audio_pcm_hw_run_in(
-hw, hw->samples - audio_pcm_hw_get_live_in(hw));
-}
+captured = audio_pcm_hw_run_in(
+hw, hw->samples - audio_pcm_hw_get_live_in(hw));
 }
 replay_audio_in(, hw->conv_buf, >wpos, hw->samples);
 
-- 
2.20.1




[Qemu-devel] [PATCH v3 02/50] audio: use qapi AudioFormat instead of audfmt_e

2019-01-16 Thread Kővágó, Zoltán
I had to include an enum for audio sampling formats into qapi, but that
meant duplicating the audfmt_e enum.  This patch replaces audfmt_e and
associated values with the qapi generated AudioFormat enum.

This patch is mostly a search-and-replace, except for switches where the
qapi generated AUDIO_FORMAT_MAX caused problems.

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio.h | 12 +
 audio/alsaaudio.c | 53 +++--
 audio/audio.c | 97 +--
 audio/audio_win_int.c | 18 
 audio/ossaudio.c  | 30 ++--
 audio/paaudio.c   | 28 +--
 audio/sdlaudio.c  | 26 +--
 audio/spiceaudio.c|  4 +-
 audio/wavaudio.c  | 17 ---
 audio/wavcapture.c|  2 +-
 hw/arm/omap2.c|  2 +-
 hw/audio/ac97.c   |  2 +-
 hw/audio/adlib.c  |  2 +-
 hw/audio/cs4231a.c|  6 +--
 hw/audio/es1370.c |  4 +-
 hw/audio/gus.c|  2 +-
 hw/audio/hda-codec.c  | 18 
 hw/audio/lm4549.c |  6 +--
 hw/audio/milkymist-ac97.c |  2 +-
 hw/audio/pcspk.c  |  2 +-
 hw/audio/sb16.c   | 14 +++---
 hw/audio/wm8750.c |  6 +--
 hw/display/xlnx_dp.c  |  2 +-
 hw/input/tsc210x.c|  2 +-
 hw/usb/dev-audio.c|  2 +-
 ui/vnc.c  | 26 +--
 26 files changed, 196 insertions(+), 189 deletions(-)

diff --git a/audio/audio.h b/audio/audio.h
index f4339a185e..02f29a3b3e 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -26,18 +26,10 @@
 #define QEMU_AUDIO_H
 
 #include "qemu/queue.h"
+#include "qapi/qapi-types-audio.h"
 
 typedef void (*audio_callback_fn) (void *opaque, int avail);
 
-typedef enum {
-AUD_FMT_U8,
-AUD_FMT_S8,
-AUD_FMT_U16,
-AUD_FMT_S16,
-AUD_FMT_U32,
-AUD_FMT_S32
-} audfmt_e;
-
 #ifdef HOST_WORDS_BIGENDIAN
 #define AUDIO_HOST_ENDIANNESS 1
 #else
@@ -47,7 +39,7 @@ typedef enum {
 struct audsettings {
 int freq;
 int nchannels;
-audfmt_e fmt;
+AudioFormat fmt;
 int endianness;
 };
 
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 635be73bf4..5bd034267f 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -87,7 +87,7 @@ struct alsa_params_req {
 
 struct alsa_params_obt {
 int freq;
-audfmt_e fmt;
+AudioFormat fmt;
 int endianness;
 int nchannels;
 snd_pcm_uframes_t samples;
@@ -294,16 +294,16 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)
 return audio_pcm_sw_write (sw, buf, len);
 }
 
-static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
+static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
 {
 switch (fmt) {
-case AUD_FMT_S8:
+case AUDIO_FORMAT_S8:
 return SND_PCM_FORMAT_S8;
 
-case AUD_FMT_U8:
+case AUDIO_FORMAT_U8:
 return SND_PCM_FORMAT_U8;
 
-case AUD_FMT_S16:
+case AUDIO_FORMAT_S16:
 if (endianness) {
 return SND_PCM_FORMAT_S16_BE;
 }
@@ -311,7 +311,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int 
endianness)
 return SND_PCM_FORMAT_S16_LE;
 }
 
-case AUD_FMT_U16:
+case AUDIO_FORMAT_U16:
 if (endianness) {
 return SND_PCM_FORMAT_U16_BE;
 }
@@ -319,7 +319,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int 
endianness)
 return SND_PCM_FORMAT_U16_LE;
 }
 
-case AUD_FMT_S32:
+case AUDIO_FORMAT_S32:
 if (endianness) {
 return SND_PCM_FORMAT_S32_BE;
 }
@@ -327,7 +327,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int 
endianness)
 return SND_PCM_FORMAT_S32_LE;
 }
 
-case AUD_FMT_U32:
+case AUDIO_FORMAT_U32:
 if (endianness) {
 return SND_PCM_FORMAT_U32_BE;
 }
@@ -344,58 +344,58 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int 
endianness)
 }
 }
 
-static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
+static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
int *endianness)
 {
 switch (alsafmt) {
 case SND_PCM_FORMAT_S8:
 *endianness = 0;
-*fmt = AUD_FMT_S8;
+*fmt = AUDIO_FORMAT_S8;
 break;
 
 case SND_PCM_FORMAT_U8:
 *endianness = 0;
-*fmt = AUD_FMT_U8;
+*fmt = AUDIO_FORMAT_U8;
 break;
 
 case SND_PCM_FORMAT_S16_LE:
 *endianness = 0;
-*fmt = AUD_FMT_S16;
+*fmt = AUDIO_FORMAT_S16;
 break;
 
 case SND_PCM_FORMAT_U16_LE:
 *endianness = 0;
-*fmt = AUD_FMT_U16;
+*fmt = AUDIO_FORMAT_U16;
 break;
 
 case SND_PCM_FORMAT_S16_BE:
 *endianness = 1;
-*fmt = AUD_FMT_S16;
+*fmt = AUDIO_FORMAT_S16;
 break;
 
 case SND_PCM_FORMAT_U16_BE:
 *endianness = 1;
-*fmt = AUD_FMT_U16;
+*fmt = 

[Qemu-devel] [PATCH v3 07/50] dsoundaudio: port to -audiodev config

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/dsound_template.h |  6 ++---
 audio/audio_legacy.c| 39 +++
 audio/dsoundaudio.c | 59 -
 3 files changed, 59 insertions(+), 45 deletions(-)

diff --git a/audio/dsound_template.h b/audio/dsound_template.h
index b439f33f58..96181efb36 100644
--- a/audio/dsound_template.h
+++ b/audio/dsound_template.h
@@ -167,17 +167,18 @@ static int dsound_init_out(HWVoiceOut *hw, struct 
audsettings *as,
 dsound *s = drv_opaque;
 WAVEFORMATEX wfx;
 struct audsettings obt_as;
-DSoundConf *conf = >conf;
 #ifdef DSBTYPE_IN
 const char *typ = "ADC";
 DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
 DSCBUFFERDESC bd;
 DSCBCAPS bc;
+AudiodevPerDirectionOptions *pdo = s->dev->in;
 #else
 const char *typ = "DAC";
 DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
 DSBUFFERDESC bd;
 DSBCAPS bc;
+AudiodevPerDirectionOptions *pdo = s->dev->out;
 #endif
 
 if (!s->FIELD2) {
@@ -193,8 +194,8 @@ static int dsound_init_out(HWVoiceOut *hw, struct 
audsettings *as,
 memset (, 0, sizeof (bd));
 bd.dwSize = sizeof (bd);
 bd.lpwfxFormat = 
+bd.dwBufferBytes = audio_buffer_bytes(pdo, as, 92880);
 #ifdef DSBTYPE_IN
-bd.dwBufferBytes = conf->bufsize_in;
 hr = IDirectSoundCapture_CreateCaptureBuffer (
 s->dsound_capture,
 ,
@@ -203,7 +204,6 @@ static int dsound_init_out(HWVoiceOut *hw, struct 
audsettings *as,
 );
 #else
 bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
-bd.dwBufferBytes = conf->bufsize_out;
 hr = IDirectSound_CreateSoundBuffer (
 s->dsound,
 ,
diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c
index 955fb18241..601a68fab6 100644
--- a/audio/audio_legacy.c
+++ b/audio/audio_legacy.c
@@ -120,6 +120,30 @@ static void get_frames_to_usecs(const char *env, uint32_t 
*dst, bool *has_dst,
 }
 }
 
+static uint32_t samples_to_usecs(uint32_t samples,
+ AudiodevPerDirectionOptions *pdo)
+{
+uint32_t channels = pdo->has_channels ? pdo->channels : 2;
+return frames_to_usecs(samples / channels, pdo);
+}
+
+static uint32_t bytes_to_usecs(uint32_t bytes, AudiodevPerDirectionOptions 
*pdo)
+{
+AudioFormat fmt = pdo->has_format ? pdo->format : AUDIO_FORMAT_S16;
+uint32_t bytes_per_sample = audioformat_bytes_per_sample(fmt);
+return samples_to_usecs(bytes / bytes_per_sample, pdo);
+}
+
+static void get_bytes_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
+   AudiodevPerDirectionOptions *pdo)
+{
+const char *val = getenv(env);
+if (val) {
+*dst = bytes_to_usecs(toui32(val), pdo);
+*has_dst = true;
+}
+}
+
 /* backend specific functions */
 /* ALSA */
 static void handle_alsa_per_direction(
@@ -186,6 +210,17 @@ static void handle_coreaudio(Audiodev *dev)
 >out->buffer_count, >out->has_buffer_count);
 }
 
+/* dsound */
+static void handle_dsound(Audiodev *dev)
+{
+get_millis_to_usecs("QEMU_DSOUND_LATENCY_MILLIS",
+>u.dsound.latency, >u.dsound.has_latency);
+get_bytes_to_usecs("QEMU_DSOUND_BUFSIZE_OUT", >out->buffer_len,
+   >out->has_buffer_len, dev->out);
+get_bytes_to_usecs("QEMU_DSOUND_BUFSIZE_IN", >in->buffer_len,
+   >in->has_buffer_len, dev->in);
+}
+
 /* general */
 static void handle_per_direction(
 AudiodevPerDirectionOptions *pdo, const char *prefix)
@@ -237,6 +272,10 @@ static AudiodevListEntry *legacy_opt(const char *drvname)
 handle_coreaudio(e->dev);
 break;
 
+case AUDIODEV_DRIVER_DSOUND:
+handle_dsound(e->dev);
+break;
+
 default:
 break;
 }
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index 02fe777cba..a7d04b5033 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -32,6 +32,7 @@
 
 #define AUDIO_CAP "dsound"
 #include "audio_int.h"
+#include "qemu/host-utils.h"
 
 #include 
 #include 
@@ -42,17 +43,11 @@
 
 /* #define DEBUG_DSOUND */
 
-typedef struct {
-int bufsize_in;
-int bufsize_out;
-int latency_millis;
-} DSoundConf;
-
 typedef struct {
 LPDIRECTSOUND dsound;
 LPDIRECTSOUNDCAPTURE dsound_capture;
 struct audsettings settings;
-DSoundConf conf;
+Audiodev *dev;
 } dsound;
 
 typedef struct {
@@ -248,9 +243,9 @@ static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
 dsound_log_hresult (hr);
 }
 
-static DWORD millis_to_bytes (struct audio_pcm_info *info, DWORD millis)
+static uint64_t usecs_to_bytes(struct audio_pcm_info *info, uint32_t usecs)
 {
-return (millis * info->bytes_per_second) / 1000;
+return muldiv64(usecs, info->bytes_per_second, 100);
 }
 
 #ifdef DEBUG_DSOUND
@@ -478,7 +473,7 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
 LPVOID p1, p2;
 int bufsize;
 dsound *s = ds->s;
-DSoundConf *conf = >conf;
+

[Qemu-devel] [PATCH v3 41/50] audio: add mixeng option (documentation)

2019-01-16 Thread Kővágó, Zoltán
This will allow us to disable mixeng when we use a decent backend.

Disabling mixeng have a few advantages:
* we no longer convert the audio output from one format to another, when
  the underlying audio system would just convert it to a third format.
  We no longer convert, only the underlying system, when needed.
* the underlying system probably has better resampling and sample format
  converting methods anyway...
* we may support formats that the mixeng currently does not support (S24
  or float samples, more than two channels)
* when using an audio server (like pulseaudio) different sound card
  outputs will show up as separate streams, even if we use only one
  backend

Disadvantages:
* audio capturing no longer works (wavcapture, and vnc audio extension)
* some backends only support a single playback stream or very picky
  about the audio format.  In this case we can't disable mixeng.

However mixeng is not removed, only made optional, so this shouldn't be
a big concern.

Signed-off-by: Kővágó, Zoltán 
---

Notes:
Changes from v2:
* removed #optional

 qapi/audio.json | 5 +
 qemu-options.hx | 6 ++
 2 files changed, 11 insertions(+)

diff --git a/qapi/audio.json b/qapi/audio.json
index bd6e2494bd..7bcea6240f 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -172,6 +172,10 @@
 #
 # General audio backend options that are used for both playback and recording.
 #
+# @mixeng: use QEMU's mixing engine to mix all streams inside QEMU. When set to
+#  off, fixed-settings must be also off. Not every backend compatible
+#  with the off setting (default on)
+#
 # @fixed-settings: use fixed settings for host input/output. When off,
 #  frequency, channels and format must not be specified
 #  (default on)
@@ -192,6 +196,7 @@
 ##
 { 'struct': 'AudiodevPerDirectionOptions',
   'data': {
+'*mixeng': 'bool',
 '*fixed-settings': 'bool',
 '*frequency':  'uint32',
 '*channels':   'uint32',
diff --git a/qemu-options.hx b/qemu-options.hx
index 098508ce09..53fc5ef453 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -432,6 +432,7 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev,
 "specifies the audio backend to use\n"
 "id= identifier of the backend\n"
 "timer-period= timer period in microseconds\n"
+"in|out.mixeng= use mixeng to mix streams inside QEMU\n"
 "in|out.fixed-settings= use fixed settings for host 
audio\n"
 "in|out.frequency= frequency to use with fixed settings\n"
 "in|out.channels= number of channels to use with fixed 
settings\n"
@@ -500,6 +501,11 @@ Identifies the audio backend.
 Sets the timer @var{period} used by the audio subsystem in microseconds.
 Default is 1 (10 ms).
 
+@item in|out.mixeng=on|off
+Use QEMU's mixing engine to mix all streams inside QEMU.  When off,
+@var{fixed-settings} must be off too.  Not every backend is fully
+compatible with the off setting.  Default is on.
+
 @item in|out.fixed-settings=on|off
 Use fixed settings for host audio.  When off, it will change based on
 how the guest opens the sound card.  In this case you must not specify
-- 
2.20.1




[Qemu-devel] [PATCH v3 32/50] paaudio: port to the new audio backend api

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 configure|   5 -
 audio/audio_pt_int.h |  22 ---
 audio/audio_pt_int.c | 174 
 audio/paaudio.c  | 372 ++-
 audio/Makefile.objs  |   1 -
 5 files changed, 45 insertions(+), 529 deletions(-)
 delete mode 100644 audio/audio_pt_int.h
 delete mode 100644 audio/audio_pt_int.c

diff --git a/configure b/configure
index 3eee3fcf70..e24e233458 100755
--- a/configure
+++ b/configure
@@ -286,7 +286,6 @@ block_drv_ro_whitelist=""
 host_cc="cc"
 libs_softmmu=""
 libs_tools=""
-audio_pt_int=""
 audio_win_int=""
 libs_qga=""
 debug_info="yes"
@@ -3329,7 +3328,6 @@ for drv in $audio_drv_list; do
 audio_drv_probe $drv pulse/pulseaudio.h "-lpulse" \
 "pa_context_set_source_output_volume(NULL, 0, NULL, NULL, NULL); 
return 0;"
 pulse_libs="-lpulse"
-audio_pt_int="yes"
 ;;
 
 sdl)
@@ -6310,9 +6308,6 @@ echo "PULSE_LIBS=$pulse_libs" >> $config_host_mak
 echo "COREAUDIO_LIBS=$coreaudio_libs" >> $config_host_mak
 echo "DSOUND_LIBS=$dsound_libs" >> $config_host_mak
 echo "OSS_LIBS=$oss_libs" >> $config_host_mak
-if test "$audio_pt_int" = "yes" ; then
-  echo "CONFIG_AUDIO_PT_INT=y" >> $config_host_mak
-fi
 if test "$audio_win_int" = "yes" ; then
   echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak
 fi
diff --git a/audio/audio_pt_int.h b/audio/audio_pt_int.h
deleted file mode 100644
index 4c0c15b9af..00
--- a/audio/audio_pt_int.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef QEMU_AUDIO_PT_INT_H
-#define QEMU_AUDIO_PT_INT_H
-
-#include 
-
-struct audio_pt {
-const char *drv;
-pthread_t thread;
-pthread_cond_t cond;
-pthread_mutex_t mutex;
-};
-
-int audio_pt_init (struct audio_pt *, void *(*) (void *), void *,
-   const char *, const char *);
-int audio_pt_fini (struct audio_pt *, const char *);
-int audio_pt_lock (struct audio_pt *, const char *);
-int audio_pt_unlock (struct audio_pt *, const char *);
-int audio_pt_wait (struct audio_pt *, const char *);
-int audio_pt_unlock_and_signal (struct audio_pt *, const char *);
-int audio_pt_join (struct audio_pt *, void **, const char *);
-
-#endif /* QEMU_AUDIO_PT_INT_H */
diff --git a/audio/audio_pt_int.c b/audio/audio_pt_int.c
deleted file mode 100644
index 3fe56d8514..00
--- a/audio/audio_pt_int.c
+++ /dev/null
@@ -1,174 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "audio.h"
-
-#define AUDIO_CAP "audio-pt"
-
-#include "audio_int.h"
-#include "audio_pt_int.h"
-
-static void GCC_FMT_ATTR(3, 4) logerr (struct audio_pt *pt, int err,
-   const char *fmt, ...)
-{
-va_list ap;
-
-va_start (ap, fmt);
-AUD_vlog (pt->drv, fmt, ap);
-va_end (ap);
-
-AUD_log (NULL, "\n");
-AUD_log (pt->drv, "Reason: %s\n", strerror (err));
-}
-
-int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
-   void *opaque, const char *drv, const char *cap)
-{
-int err, err2;
-const char *efunc;
-sigset_t set, old_set;
-
-p->drv = drv;
-
-err = sigfillset ();
-if (err) {
-logerr(p, errno, "%s(%s): sigfillset failed", cap, __func__);
-return -1;
-}
-
-err = pthread_mutex_init (>mutex, NULL);
-if (err) {
-efunc = "pthread_mutex_init";
-goto err0;
-}
-
-err = pthread_cond_init (>cond, NULL);
-if (err) {
-efunc = "pthread_cond_init";
-goto err1;
-}
-
-err = pthread_sigmask (SIG_BLOCK, , _set);
-if (err) {
-efunc = "pthread_sigmask";
-goto err2;
-}
-
-err = pthread_create (>thread, NULL, func, opaque);
-
-err2 = pthread_sigmask (SIG_SETMASK, _set, NULL);
-if (err2) {
-logerr(p, err2, "%s(%s): pthread_sigmask (restore) failed",
-   cap, __func__);
-/* We have failed to restore original signal mask, all bets are off,
-   so terminate the process */
-exit (EXIT_FAILURE);
-}
-
-if (err) {
-efunc = "pthread_create";
-goto err2;
-}
-
-return 0;
-
- err2:
-err2 = pthread_cond_destroy (>cond);
-if (err2) {
-logerr(p, err2, "%s(%s): pthread_cond_destroy failed", cap, __func__);
-}
-
- err1:
-err2 = pthread_mutex_destroy (>mutex);
-if (err2) {
-logerr(p, err2, "%s(%s): pthread_mutex_destroy failed", cap, __func__);
-}
-
- err0:
-logerr(p, err, "%s(%s): %s failed", cap, __func__, efunc);
-return -1;
-}
-
-int audio_pt_fini (struct audio_pt *p, const char *cap)
-{
-int err, ret = 0;
-
-err = pthread_cond_destroy (>cond);
-if (err) {
-logerr(p, err, "%s(%s): pthread_cond_destroy failed", cap, __func__);
-ret = -1;
-}
-
-err = pthread_mutex_destroy (>mutex);
-if (err) {
-logerr(p, err, "%s(%s): pthread_mutex_destroy failed", cap, __func__);
-ret = -1;
-}
-return ret;
-}
-
-int audio_pt_lock (struct audio_pt *p, const char *cap)
-{

[Qemu-devel] [PATCH v3 14/50] audio: -audiodev command line option: cleanup

2019-01-16 Thread Kővágó, Zoltán
Remove no longer needed code.

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h |  17 
 audio/audio.c | 201 +-
 2 files changed, 4 insertions(+), 214 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 353467b505..66214199f0 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -33,22 +33,6 @@
 
 struct audio_pcm_ops;
 
-typedef enum {
-AUD_OPT_INT,
-AUD_OPT_FMT,
-AUD_OPT_STR,
-AUD_OPT_BOOL
-} audio_option_tag_e;
-
-struct audio_option {
-const char *name;
-audio_option_tag_e tag;
-void *valp;
-const char *descr;
-int *overriddenp;
-int overridden;
-};
-
 struct audio_callback {
 void *opaque;
 audio_callback_fn fn;
@@ -145,7 +129,6 @@ typedef struct audio_driver audio_driver;
 struct audio_driver {
 const char *name;
 const char *descr;
-struct audio_option *options;
 void *(*init) (Audiodev *);
 void (*fini) (void *);
 struct audio_pcm_ops *pcm_ops;
diff --git a/audio/audio.c b/audio/audio.c
index 159b049ceb..77bd8386d0 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -172,113 +172,6 @@ void *audio_calloc (const char *funcname, int nmemb, 
size_t size)
 return g_malloc0 (len);
 }
 
-static const char *audio_audfmt_to_string (AudioFormat fmt)
-{
-switch (fmt) {
-case AUDIO_FORMAT_U8:
-return "U8";
-
-case AUDIO_FORMAT_U16:
-return "U16";
-
-case AUDIO_FORMAT_S8:
-return "S8";
-
-case AUDIO_FORMAT_S16:
-return "S16";
-
-case AUDIO_FORMAT_U32:
-return "U32";
-
-case AUDIO_FORMAT_S32:
-return "S32";
-
-default:
-abort();
-}
-
-dolog ("Bogus audfmt %d returning S16\n", fmt);
-return "S16";
-}
-
-static AudioFormat audio_string_to_audfmt (const char *s, AudioFormat defval,
-int *defaultp)
-{
-if (!strcasecmp (s, "u8")) {
-*defaultp = 0;
-return AUDIO_FORMAT_U8;
-}
-else if (!strcasecmp (s, "u16")) {
-*defaultp = 0;
-return AUDIO_FORMAT_U16;
-}
-else if (!strcasecmp (s, "u32")) {
-*defaultp = 0;
-return AUDIO_FORMAT_U32;
-}
-else if (!strcasecmp (s, "s8")) {
-*defaultp = 0;
-return AUDIO_FORMAT_S8;
-}
-else if (!strcasecmp (s, "s16")) {
-*defaultp = 0;
-return AUDIO_FORMAT_S16;
-}
-else if (!strcasecmp (s, "s32")) {
-*defaultp = 0;
-return AUDIO_FORMAT_S32;
-}
-else {
-dolog ("Bogus audio format `%s' using %s\n",
-   s, audio_audfmt_to_string (defval));
-*defaultp = 1;
-return defval;
-}
-}
-
-static AudioFormat audio_get_conf_fmt (const char *envname,
-AudioFormat defval,
-int *defaultp)
-{
-const char *var = getenv (envname);
-if (!var) {
-*defaultp = 1;
-return defval;
-}
-return audio_string_to_audfmt (var, defval, defaultp);
-}
-
-static int audio_get_conf_int (const char *key, int defval, int *defaultp)
-{
-int val;
-char *strval;
-
-strval = getenv (key);
-if (strval && !qemu_strtoi(strval, NULL, 10, )) {
-*defaultp = 0;
-return val;
-}
-else {
-*defaultp = 1;
-return defval;
-}
-}
-
-static const char *audio_get_conf_str (const char *key,
-   const char *defval,
-   int *defaultp)
-{
-const char *val = getenv (key);
-if (!val) {
-*defaultp = 1;
-return defval;
-}
-else {
-*defaultp = 0;
-return val;
-}
-}
-
 void AUD_vlog (const char *cap, const char *fmt, va_list ap)
 {
 if (cap) {
@@ -297,89 +190,6 @@ void AUD_log (const char *cap, const char *fmt, ...)
 va_end (ap);
 }
 
-static void audio_process_options (const char *prefix,
-   struct audio_option *opt)
-{
-char *optname;
-const char qemu_prefix[] = "QEMU_";
-size_t preflen, optlen;
-
-if (audio_bug(__func__, !prefix)) {
-dolog ("prefix = NULL\n");
-return;
-}
-
-if (audio_bug(__func__, !opt)) {
-dolog ("opt = NULL\n");
-return;
-}
-
-preflen = strlen (prefix);
-
-for (; opt->name; opt++) {
-size_t len, i;
-int def;
-
-if (!opt->valp) {
-dolog ("Option value pointer for `%s' is not set\n",
-   opt->name);
-continue;
-}
-
-len = strlen (opt->name);
-/* len of opt->name + len of prefix + size of qemu_prefix
- * (includes trailing zero) + zero + underscore (on behalf of
- * sizeof) */
-optlen = len + preflen + sizeof (qemu_prefix) + 1;
-optname = g_malloc (optlen);
-
-pstrcpy (optname, optlen, qemu_prefix);
-
-/* copy while upper-casing, including 

[Qemu-devel] [PATCH v3 35/50] wavaudio: port to the new audio backend api

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/wavaudio.c | 54 
 1 file changed, 9 insertions(+), 45 deletions(-)

diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index a805e5e94b..31db03aadb 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -34,52 +34,28 @@ typedef struct WAVVoiceOut {
 HWVoiceOut hw;
 FILE *f;
 int64_t old_ticks;
-void *pcm_buf;
 int total_samples;
 } WAVVoiceOut;
 
-static size_t wav_run_out(HWVoiceOut *hw, size_t live)
+static size_t wav_write_out(HWVoiceOut *hw, void *buf, size_t len)
 {
 WAVVoiceOut *wav = (WAVVoiceOut *) hw;
-size_t rpos, decr, samples;
-uint8_t *dst;
-struct st_sample *src;
 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 int64_t ticks = now - wav->old_ticks;
 int64_t bytes =
 muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND);
 
-if (bytes > INT_MAX) {
-samples = INT_MAX >> hw->info.shift;
-}
-else {
-samples = bytes >> hw->info.shift;
-}
-
+bytes = MIN(bytes, len);
+bytes = bytes >> hw->info.shift << hw->info.shift;
 wav->old_ticks = now;
-decr = MIN (live, samples);
-samples = decr;
-rpos = hw->rpos;
-while (samples) {
-int left_till_end_samples = hw->samples - rpos;
-int convert_samples = MIN (samples, left_till_end_samples);
 
-src = hw->mix_buf + rpos;
-dst = advance (wav->pcm_buf, rpos << hw->info.shift);
-
-hw->clip (dst, src, convert_samples);
-if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) {
-dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n",
-   convert_samples << hw->info.shift, strerror (errno));
-}
-
-rpos = (rpos + convert_samples) % hw->samples;
-samples -= convert_samples;
-wav->total_samples += convert_samples;
+if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) {
+dolog("wav_write_out: fwrite of %zu bytes failed\nReaons: %s\n",
+  bytes, strerror(errno));
 }
 
-hw->rpos = rpos;
-return decr;
+wav->total_samples += bytes >> hw->info.shift;
+return bytes;
 }
 
 /* VICE code: Store number as little endian. */
@@ -135,13 +111,6 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings 
*as,
 audio_pcm_init_info (>info, _as);
 
 hw->samples = 1024;
-wav->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
-if (!wav->pcm_buf) {
-dolog("Could not allocate buffer (%zu bytes)\n",
-  hw->samples << hw->info.shift);
-return -1;
-}
-
 le_store (hdr + 22, hw->info.nchannels, 2);
 le_store (hdr + 24, hw->info.freq, 4);
 le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
@@ -151,8 +120,6 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings 
*as,
 if (!wav->f) {
 dolog ("Failed to open wave file `%s'\nReason: %s\n",
wav_path, strerror(errno));
-g_free (wav->pcm_buf);
-wav->pcm_buf = NULL;
 return -1;
 }
 
@@ -206,9 +173,6 @@ static void wav_fini_out (HWVoiceOut *hw)
wav->f, strerror (errno));
 }
 wav->f = NULL;
-
-g_free (wav->pcm_buf);
-wav->pcm_buf = NULL;
 }
 
 static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
@@ -232,7 +196,7 @@ static void wav_audio_fini (void *opaque)
 static struct audio_pcm_ops wav_pcm_ops = {
 .init_out = wav_init_out,
 .fini_out = wav_fini_out,
-.run_out  = wav_run_out,
+.write= wav_write_out,
 .ctl_out  = wav_ctl_out,
 };
 
-- 
2.20.1




[Qemu-devel] [PATCH v3 21/50] audio: remove audio_MIN, audio_MAX

2019-01-16 Thread Kővágó, Zoltán
There's already a MIN and MAX macro in include/qemu/osdep.h, use them
instead.

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio.h | 17 -
 audio/alsaaudio.c |  6 +++---
 audio/audio.c | 20 ++--
 audio/coreaudio.c |  2 +-
 audio/dsoundaudio.c   |  2 +-
 audio/noaudio.c   | 10 +-
 audio/ossaudio.c  |  6 +++---
 audio/paaudio.c   | 12 ++--
 audio/sdlaudio.c  |  6 +++---
 audio/spiceaudio.c| 10 +-
 audio/wavaudio.c  |  4 ++--
 hw/audio/ac97.c   | 10 +-
 hw/audio/adlib.c  |  4 ++--
 hw/audio/cs4231a.c|  4 ++--
 hw/audio/es1370.c |  6 +++---
 hw/audio/gus.c|  6 +++---
 hw/audio/hda-codec.c  | 16 
 hw/audio/milkymist-ac97.c |  8 
 hw/audio/pcspk.c  |  2 +-
 hw/audio/sb16.c   |  2 +-
 hw/audio/wm8750.c |  4 ++--
 21 files changed, 70 insertions(+), 87 deletions(-)

diff --git a/audio/audio.h b/audio/audio.h
index c0722a5cda..4a95758516 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -146,23 +146,6 @@ static inline void *advance (void *p, int incr)
 return (d + incr);
 }
 
-#ifdef __GNUC__
-#define audio_MIN(a, b) ( __extension__ ({  \
-__typeof (a) ta = a;\
-__typeof (b) tb = b;\
-((ta)>(tb)?(tb):(ta));  \
-}))
-
-#define audio_MAX(a, b) ( __extension__ ({  \
-__typeof (a) ta = a;\
-__typeof (b) tb = b;\
-((ta)<(tb)?(tb):(ta));  \
-}))
-#else
-#define audio_MIN(a, b) ((a)>(b)?(b):(a))
-#define audio_MAX(a, b) ((a)<(b)?(b):(a))
-#endif
-
 int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
   int freq, int bits, int nchannels);
 
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 6b43a06180..c68bd6bf8a 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -641,7 +641,7 @@ static void alsa_write_pending (ALSAVoiceOut *alsa)
 
 while (alsa->pending) {
 int left_till_end_samples = hw->samples - alsa->wpos;
-int len = audio_MIN (alsa->pending, left_till_end_samples);
+int len = MIN (alsa->pending, left_till_end_samples);
 char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
 
 while (len) {
@@ -704,7 +704,7 @@ static int alsa_run_out (HWVoiceOut *hw, int live)
 return 0;
 }
 
-decr = audio_MIN (live, avail);
+decr = MIN (live, avail);
 decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
 alsa->pending += decr;
 alsa_write_pending (alsa);
@@ -922,7 +922,7 @@ static int alsa_run_in (HWVoiceIn *hw)
 }
 }
 
-decr = audio_MIN (dead, avail);
+decr = MIN (dead, avail);
 if (!decr) {
 return 0;
 }
diff --git a/audio/audio.c b/audio/audio.c
index f768a6059d..5f809d13f4 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -536,7 +536,7 @@ static int audio_pcm_hw_find_min_in (HWVoiceIn *hw)
 
 for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
 if (sw->active) {
-m = audio_MIN (m, sw->total_hw_samples_acquired);
+m = MIN (m, sw->total_hw_samples_acquired);
 }
 }
 return m;
@@ -556,14 +556,14 @@ int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
int live, int pending)
 {
 int left = hw->samples - pending;
-int len = audio_MIN (left, live);
+int len = MIN (left, live);
 int clipped = 0;
 
 while (len) {
 struct st_sample *src = hw->mix_buf + hw->rpos;
 uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift);
 int samples_till_end_of_buf = hw->samples - hw->rpos;
-int samples_to_clip = audio_MIN (len, samples_till_end_of_buf);
+int samples_to_clip = MIN (len, samples_till_end_of_buf);
 
 hw->clip (dst, src, samples_to_clip);
 
@@ -617,7 +617,7 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
 }
 
 swlim = (live * sw->ratio) >> 32;
-swlim = audio_MIN (swlim, samples);
+swlim = MIN (swlim, samples);
 
 while (swlim) {
 src = hw->conv_buf + rpos;
@@ -665,7 +665,7 @@ static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int 
*nb_livep)
 
 for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
 if (sw->active || !sw->empty) {
-m = audio_MIN (m, sw->total_hw_samples_mixed);
+m = MIN (m, sw->total_hw_samples_mixed);
 nb_live += 1;
 }
 }
@@ -728,7 +728,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
 
 dead = hwsamples - live;
 swlim = ((int64_t) dead << 32) / sw->ratio;
-swlim = audio_MIN (swlim, samples);
+swlim = MIN (swlim, samples);
 if (swlim) {
 sw->conv (sw->buf, buf, swlim);
 
@@ -740,7 +740,7 @@ 

[Qemu-devel] [PATCH v3 18/50] audio: audiodev= parameters no longer optional when -audiodev present

2019-01-16 Thread Kővágó, Zoltán
This means you should probably stop using -soundhw (as it doesn't allow
you to specify any options) and add the device manually with -device.
The exception is pcspk, it's currently not possible to manually add it.
To use it with audiodev, use something like this:

-audiodev id=foo,... -global isa-pcspk.audiodev=foo -soundhw pcspk

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio.c   |  24 ++--
 audio/paaudio.c | 304 
 2 files changed, 190 insertions(+), 138 deletions(-)

diff --git a/audio/audio.c b/audio/audio.c
index 2f9f37afb8..f768a6059d 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -99,6 +99,8 @@ const struct mixeng_volume nominal_volume = {
 #endif
 };
 
+static bool legacy_config = true;
+
 #ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
 #error No its not
 #else
@@ -1393,7 +1395,7 @@ static AudiodevListEntry *audiodev_find(
  * if dev == NULL => legacy implicit initialization, return the already created
  *   state or create a new one
  */
-static AudioState *audio_init(Audiodev *dev)
+static AudioState *audio_init(Audiodev *dev, const char *name)
 {
 static bool atexit_registered;
 size_t i;
@@ -1407,12 +1409,13 @@ static AudioState *audio_init(Audiodev *dev)
 
 if (dev) {
 /* -audiodev option */
+legacy_config = false;
 drvname = AudiodevDriver_str(dev->driver);
 } else if (!QTAILQ_EMPTY(_states)) {
-/*
- * todo: check for -audiodev once we have normal audiodev selection
- * support
- */
+if (!legacy_config) {
+dolog("You must specify an audiodev= for the device %s\n", name);
+exit(1);
+}
 return QTAILQ_FIRST(_states);
 } else {
 /* legacy implicit initialization */
@@ -1518,7 +1521,7 @@ void audio_free_audiodev_list(AudiodevListHead *head)
 void AUD_register_card (const char *name, QEMUSoundCard *card)
 {
 if (!card->state) {
-card->state = audio_init(NULL);
+card->state = audio_init(NULL, name);
 }
 
 card->name = g_strdup (name);
@@ -1544,8 +1547,11 @@ CaptureVoiceOut *AUD_add_capture(
 struct capture_callback *cb;
 
 if (!s) {
-/* todo: remove when we have normal audiodev selection support */
-s = audio_init(NULL);
+if (!legacy_config) {
+dolog("You must specify audiodev when trying to capture\n");
+goto err0;
+}
+s = audio_init(NULL, NULL);
 }
 
 if (audio_validate_settings (as)) {
@@ -1778,7 +1784,7 @@ void audio_init_audiodevs(void)
 AudiodevListEntry *e;
 
 QSIMPLEQ_FOREACH(e, , next) {
-audio_init(e->dev);
+audio_init(e->dev, NULL);
 }
 }
 
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 33e0e5d9be..1c20f8a7aa 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -10,10 +10,21 @@
 #include "audio_int.h"
 #include "audio_pt_int.h"
 
-typedef struct {
-Audiodev *dev;
+typedef struct PAConnection {
+char *server;
+int refcount;
+QTAILQ_ENTRY(PAConnection) list;
+
 pa_threaded_mainloop *mainloop;
 pa_context *context;
+} PAConnection;
+
+static QTAILQ_HEAD(PAConnectionHead, PAConnection) pa_conns =
+QTAILQ_HEAD_INITIALIZER(pa_conns);
+
+typedef struct {
+Audiodev *dev;
+PAConnection *conn;
 } paaudio;
 
 typedef struct {
@@ -44,7 +55,7 @@ typedef struct {
 int samples;
 } PAVoiceIn;
 
-static void qpa_audio_fini(void *opaque);
+static void qpa_conn_fini(PAConnection *c);
 
 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
 {
@@ -107,11 +118,11 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
 
 static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int 
*rerror)
 {
-paaudio *g = p->g;
+PAConnection *c = p->g->conn;
 
-pa_threaded_mainloop_lock (g->mainloop);
+pa_threaded_mainloop_lock(c->mainloop);
 
-CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
 
 while (length > 0) {
 size_t l;
@@ -120,11 +131,11 @@ static int qpa_simple_read (PAVoiceIn *p, void *data, 
size_t length, int *rerror
 int r;
 
 r = pa_stream_peek (p->stream, >read_data, >read_length);
-CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
+CHECK_SUCCESS_GOTO(c, rerror, r == 0, unlock_and_fail);
 
 if (!p->read_data) {
-pa_threaded_mainloop_wait (g->mainloop);
-CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
+pa_threaded_mainloop_wait(c->mainloop);
+CHECK_DEAD_GOTO(c, p->stream, rerror, unlock_and_fail);
 } else {
 p->read_index = 0;
 }
@@ -147,53 +158,53 @@ static int qpa_simple_read (PAVoiceIn *p, void *data, 
size_t length, int *rerror
 p->read_length = 0;
 p->read_index = 0;
 
-CHECK_SUCCESS_GOTO 

[Qemu-devel] [PATCH v3 28/50] coreaudio: port to the new audio backend api

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/coreaudio.c | 130 --
 1 file changed, 69 insertions(+), 61 deletions(-)

diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 646aea06a0..e32c5b62fd 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -43,9 +43,6 @@ typedef struct coreaudioVoiceOut {
 UInt32 audioDevicePropertyBufferFrameSize;
 AudioStreamBasicDescription outputStreamBasicDescription;
 AudioDeviceIOProcID ioprocid;
-size_t live;
-size_t decr;
-size_t rpos;
 } coreaudioVoiceOut;
 
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
@@ -397,31 +394,29 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, 
const char *fn_name)
 return 0;
 }
 
-static size_t coreaudio_run_out(HWVoiceOut *hw, size_t live)
-{
-size_t decr;
-coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
-
-if (coreaudio_lock (core, "coreaudio_run_out")) {
-return 0;
+#define COREAUDIO_WRAPPER_FUNC(name, ret_type, args_decl, args) \
+static ret_type glue(coreaudio_, name)args_decl \
+{   \
+coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; \
+ret_type ret;   \
+\
+if (coreaudio_lock(core, "coreaudio_" #name)) { \
+return 0;   \
+}   \
+\
+ret = glue(audio_generic_, name)args;   \
+\
+coreaudio_unlock(core, "coreaudio_" #name); \
+return ret; \
 }
-
-if (core->decr > live) {
-ldebug ("core->decr %d live %d core->live %d\n",
-core->decr,
-live,
-core->live);
-}
-
-decr = MIN (core->decr, live);
-core->decr -= decr;
-
-core->live = live - decr;
-hw->rpos = core->rpos;
-
-coreaudio_unlock (core, "coreaudio_run_out");
-return decr;
-}
+COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
+   (hw, size))
+COREAUDIO_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
+   (HWVoiceOut *hw, void *buf, size_t size),
+   (hw, buf, size))
+COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
+   (hw, buf, size))
+#undef COREAUDIO_WRAPPER_FUNC
 
 /* callback to feed audiooutput buffer */
 static OSStatus audioDeviceIOProc(
@@ -433,19 +428,11 @@ static OSStatus audioDeviceIOProc(
 const AudioTimeStamp* inOutputTime,
 void* hwptr)
 {
-UInt32 frame, frameCount;
-float *out = outOutputData->mBuffers[0].mData;
+UInt32 frameCount, pending_frames;
+void *out = outOutputData->mBuffers[0].mData;
 HWVoiceOut *hw = hwptr;
 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
-int rpos, live;
-struct st_sample *src;
-#ifndef FLOAT_MIXENG
-#ifdef RECIPROCAL
-const float scale = 1.f / UINT_MAX;
-#else
-const float scale = UINT_MAX;
-#endif
-#endif
+size_t len;
 
 if (coreaudio_lock (core, "audioDeviceIOProc")) {
 inInputTime = 0;
@@ -453,42 +440,51 @@ static OSStatus audioDeviceIOProc(
 }
 
 frameCount = core->audioDevicePropertyBufferFrameSize;
-live = core->live;
+pending_frames = hw->pending_emul >> hw->info.shift;
 
 /* if there are not enough samples, set signal and return */
-if (live < frameCount) {
+if (pending_frames < frameCount) {
 inInputTime = 0;
 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
 return 0;
 }
 
-rpos = core->rpos;
-src = hw->mix_buf + rpos;
+len = frameCount << hw->info.shift;
+while (len) {
+size_t write_len;
+ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+if (start < 0) {
+start += hw->size_emul;
+}
+assert(start >= 0 && start < hw->size_emul);
 
-/* fill buffer */
-for (frame = 0; frame < frameCount; frame++) {
-#ifdef FLOAT_MIXENG
-*out++ = src[frame].l; /* left channel */
-*out++ = src[frame].r; /* right channel */
-#else
-#ifdef RECIPROCAL
-*out++ = src[frame].l * scale; /* left channel */
-*out++ = src[frame].r * scale; /* right channel */
-#else
-*out++ = src[frame].l / scale; /* left channel */
-*out++ = src[frame].r / scale; /* right channel */
-#endif
-#endif
+write_len = MIN(MIN(hw->pending_emul, len),
+hw->size_emul - start);
+
+memcpy(out, hw->buf_emul + start, write_len);
+hw->pending_emul -= write_len;
+len -= write_len;
+out 

[Qemu-devel] [PATCH v3 05/50] alsaaudio: port to -audiodev config

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/alsaaudio.c| 330 ++-
 audio/audio_legacy.c |  94 +++-
 2 files changed, 198 insertions(+), 226 deletions(-)

diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 8302f3e882..6b43a06180 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -33,28 +33,9 @@
 #define AUDIO_CAP "alsa"
 #include "audio_int.h"
 
-typedef struct ALSAConf {
-int size_in_usec_in;
-int size_in_usec_out;
-const char *pcm_name_in;
-const char *pcm_name_out;
-unsigned int buffer_size_in;
-unsigned int period_size_in;
-unsigned int buffer_size_out;
-unsigned int period_size_out;
-unsigned int threshold;
-
-int buffer_size_in_overridden;
-int period_size_in_overridden;
-
-int buffer_size_out_overridden;
-int period_size_out_overridden;
-} ALSAConf;
-
 struct pollhlp {
 snd_pcm_t *handle;
 struct pollfd *pfds;
-ALSAConf *conf;
 int count;
 int mask;
 };
@@ -66,6 +47,7 @@ typedef struct ALSAVoiceOut {
 void *pcm_buf;
 snd_pcm_t *handle;
 struct pollhlp pollhlp;
+Audiodev *dev;
 } ALSAVoiceOut;
 
 typedef struct ALSAVoiceIn {
@@ -73,16 +55,13 @@ typedef struct ALSAVoiceIn {
 snd_pcm_t *handle;
 void *pcm_buf;
 struct pollhlp pollhlp;
+Audiodev *dev;
 } ALSAVoiceIn;
 
 struct alsa_params_req {
 int freq;
 snd_pcm_format_t fmt;
 int nchannels;
-int size_in_usec;
-int override_mask;
-unsigned int buffer_size;
-unsigned int period_size;
 };
 
 struct alsa_params_obt {
@@ -408,7 +387,8 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, 
AudioFormat *fmt,
 
 static void alsa_dump_info (struct alsa_params_req *req,
 struct alsa_params_obt *obt,
-snd_pcm_format_t obtfmt)
+snd_pcm_format_t obtfmt,
+AudiodevPerDirectionOptions *pdo)
 {
 dolog ("parameter | requested value | obtained value\n");
 dolog ("format|  %10d | %10d\n", req->fmt, obtfmt);
@@ -416,8 +396,9 @@ static void alsa_dump_info (struct alsa_params_req *req,
req->nchannels, obt->nchannels);
 dolog ("frequency |  %10d | %10d\n", req->freq, obt->freq);
 dolog ("\n");
-dolog ("requested: buffer size %d period size %d\n",
-   req->buffer_size, req->period_size);
+dolog ("requested: buffer len %" PRId32 " buffer count %" PRId32 "\n",
+   pdo->has_buffer_len ? pdo->buffer_len : 0,
+   pdo->has_buffer_count ? pdo->buffer_count : 0);
 dolog ("obtained: samples %ld\n", obt->samples);
 }
 
@@ -451,23 +432,25 @@ static void alsa_set_threshold (snd_pcm_t *handle, 
snd_pcm_uframes_t threshold)
 }
 }
 
-static int alsa_open (int in, struct alsa_params_req *req,
-  struct alsa_params_obt *obt, snd_pcm_t **handlep,
-  ALSAConf *conf)
+static int alsa_open(bool in, struct alsa_params_req *req,
+ struct alsa_params_obt *obt, snd_pcm_t **handlep,
+ Audiodev *dev)
 {
+AudiodevPerDirectionOptions *pdo = in ? dev->in : dev->out;
+AudiodevAlsaOptions *aopts = >u.alsa;
+AudiodevAlsaPerDirectionOptions *apdo =
+in ? aopts->alsa_in : aopts->alsa_out;
 snd_pcm_t *handle;
 snd_pcm_hw_params_t *hw_params;
 int err;
-int size_in_usec;
 unsigned int freq, nchannels;
-const char *pcm_name = in ? conf->pcm_name_in : conf->pcm_name_out;
+const char *pcm_name = apdo->has_dev ? apdo->dev : "default";
 snd_pcm_uframes_t obt_buffer_size;
 const char *typ = in ? "ADC" : "DAC";
 snd_pcm_format_t obtfmt;
 
 freq = req->freq;
 nchannels = req->nchannels;
-size_in_usec = req->size_in_usec;
 
 snd_pcm_hw_params_alloca (_params);
 
@@ -527,79 +510,49 @@ static int alsa_open (int in, struct alsa_params_req *req,
 goto err;
 }
 
-if (req->buffer_size) {
-unsigned long obt;
+if (pdo->buffer_count) {
+if (pdo->buffer_len) {
+int64_t req = pdo->buffer_len * pdo->buffer_count;
 
-if (size_in_usec) {
 int dir = 0;
-unsigned int btime = req->buffer_size;
+unsigned int btime = req;
 
-err = snd_pcm_hw_params_set_buffer_time_near (
-handle,
-hw_params,
-,
-
-);
-obt = btime;
-}
-else {
-snd_pcm_uframes_t bsize = req->buffer_size;
+err = snd_pcm_hw_params_set_buffer_time_near(
+handle, hw_params, , );
 
-err = snd_pcm_hw_params_set_buffer_size_near (
-handle,
-hw_params,
-
-);
-obt = bsize;
-}
-if (err < 0) {
-alsa_logerr2 (err, typ, "Failed to set buffer 

[Qemu-devel] [PATCH v3 20/50] paaudio: properly disconnect streams in fini_*

2019-01-16 Thread Kővágó, Zoltán
Currently this needs a workaround due to bug #74624 in pulseaudio.

Reviewed-by: Marc-André Lureau 
Signed-off-by: Kővágó, Zoltán 
---
 audio/paaudio.c | 25 +++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index 108d3158a6..428c848863 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -680,6 +680,27 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings 
*as, void *drv_opaque)
 return -1;
 }
 
+static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
+{
+int err;
+
+pa_threaded_mainloop_lock(c->mainloop);
+/*
+ * wait until actually connects. workaround pa bug #74624
+ * https://bugs.freedesktop.org/show_bug.cgi?id=74624
+ */
+while (pa_stream_get_state(stream) == PA_STREAM_CREATING) {
+pa_threaded_mainloop_wait(c->mainloop);
+}
+
+err = pa_stream_disconnect(stream);
+if (err != 0) {
+dolog("Failed to dissconnect! err=%d\n", err);
+}
+pa_stream_unref(stream);
+pa_threaded_mainloop_unlock(c->mainloop);
+}
+
 static void qpa_fini_out (HWVoiceOut *hw)
 {
 void *ret;
@@ -691,7 +712,7 @@ static void qpa_fini_out (HWVoiceOut *hw)
 audio_pt_join(>pt, , __func__);
 
 if (pa->stream) {
-pa_stream_unref (pa->stream);
+qpa_simple_disconnect(pa->g->conn, pa->stream);
 pa->stream = NULL;
 }
 
@@ -711,7 +732,7 @@ static void qpa_fini_in (HWVoiceIn *hw)
 audio_pt_join(>pt, , __func__);
 
 if (pa->stream) {
-pa_stream_unref (pa->stream);
+qpa_simple_disconnect(pa->g->conn, pa->stream);
 pa->stream = NULL;
 }
 
-- 
2.20.1




[Qemu-devel] [PATCH v3 23/50] paaudio: fix playback glitches

2019-01-16 Thread Kővágó, Zoltán
Pulseaudio normally assumes that when the server wants it, the client
can generate the audio samples and send it right away.  Unfortunately
this is not the case with QEMU -- it's up to the emulated system when
does it generate the samples.  Buffering the samples and sending them
from a background thread is just a workaround, that doesn't work too
well.  Instead enable pa's compatibility support and let pa worry about
the details.

Signed-off-by: Kővágó, Zoltán 
---
 audio/paaudio.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index 0a770fa57d..7758d304ca 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -511,10 +511,8 @@ static pa_stream *qpa_simple_new (
 
 flags =
 PA_STREAM_INTERPOLATE_TIMING
-#ifdef PA_STREAM_ADJUST_LATENCY
-|PA_STREAM_ADJUST_LATENCY
-#endif
-|PA_STREAM_AUTO_TIMING_UPDATE;
+|PA_STREAM_AUTO_TIMING_UPDATE
+|PA_STREAM_EARLY_REQUESTS;
 
 if (dev) {
 /* don't move the stream if the user specified a sink/source */
-- 
2.20.1




[Qemu-devel] [PATCH v3 22/50] audio: do not run each backend in audio_run

2019-01-16 Thread Kővágó, Zoltán
audio_run is called manually by alsa and oss backends when polling.
In this case only the requesting backend should be run, not all of them.

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h |  2 +-
 audio/alsaaudio.c |  7 +--
 audio/audio.c | 14 +-
 audio/ossaudio.c  | 12 ++--
 4 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 5ceea76eda..02ec6ea738 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -220,7 +220,7 @@ int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
 int audio_bug (const char *funcname, int cond);
 void *audio_calloc (const char *funcname, int nmemb, size_t size);
 
-void audio_run (const char *msg);
+void audio_run(AudioState *s, const char *msg);
 
 #define VOICE_ENABLE 1
 #define VOICE_DISABLE 2
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index c68bd6bf8a..9dfd5fd26f 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -38,6 +38,7 @@ struct pollhlp {
 struct pollfd *pfds;
 int count;
 int mask;
+AudioState *s;
 };
 
 typedef struct ALSAVoiceOut {
@@ -198,11 +199,11 @@ static void alsa_poll_handler (void *opaque)
 break;
 
 case SND_PCM_STATE_PREPARED:
-audio_run ("alsa run (prepared)");
+audio_run(hlp->s, "alsa run (prepared)");
 break;
 
 case SND_PCM_STATE_RUNNING:
-audio_run ("alsa run (running)");
+audio_run (hlp->s, "alsa run (running)");
 break;
 
 default:
@@ -756,6 +757,7 @@ static int alsa_init_out(HWVoiceOut *hw, struct audsettings 
*as,
 return -1;
 }
 
+alsa->pollhlp.s = hw->s;
 alsa->handle = handle;
 alsa->dev = dev;
 return 0;
@@ -857,6 +859,7 @@ static int alsa_init_in(HWVoiceIn *hw, struct audsettings 
*as, void *drv_opaque)
 return -1;
 }
 
+alsa->pollhlp.s = hw->s;
 alsa->handle = handle;
 alsa->dev = dev;
 return 0;
diff --git a/audio/audio.c b/audio/audio.c
index 5f809d13f4..4d0d316ce3 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -838,7 +838,7 @@ static void audio_timer (void *opaque)
 }
 s->timer_last = now;
 
-audio_run("timer");
+audio_run(s, "timer");
 audio_reset_timer(s);
 }
 
@@ -1240,15 +1240,11 @@ static void audio_run_capture (AudioState *s)
 }
 }
 
-void audio_run (const char *msg)
+void audio_run(AudioState *s, const char *msg)
 {
-AudioState *s;
-
-QTAILQ_FOREACH(s, _states, list) {
-audio_run_out (s);
-audio_run_in (s);
-audio_run_capture (s);
-}
+audio_run_out(s);
+audio_run_in(s);
+audio_run_capture(s);
 
 #ifdef DEBUG_POLL
 {
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index b6ab3e83ef..bbcc44129d 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -109,28 +109,28 @@ static void oss_anal_close (int *fdp)
 
 static void oss_helper_poll_out (void *opaque)
 {
-(void) opaque;
-audio_run ("oss_poll_out");
+AudioState *s = opaque;
+audio_run(s, "oss_poll_out");
 }
 
 static void oss_helper_poll_in (void *opaque)
 {
-(void) opaque;
-audio_run ("oss_poll_in");
+AudioState *s = opaque;
+audio_run(s, "oss_poll_in");
 }
 
 static void oss_poll_out (HWVoiceOut *hw)
 {
 OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 
-qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
+qemu_set_fd_handler(oss->fd, NULL, oss_helper_poll_out, hw->s);
 }
 
 static void oss_poll_in (HWVoiceIn *hw)
 {
 OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 
-qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
+qemu_set_fd_handler(oss->fd, oss_helper_poll_in, NULL, hw->s);
 }
 
 static int oss_write (SWVoiceOut *sw, void *buf, int len)
-- 
2.20.1




[Qemu-devel] [PATCH v3 16/50] audio: basic support for multi backend audio

2019-01-16 Thread Kővágó, Zoltán
Audio functions no longer access glob_audio_state, instead they get an
AudioState as a parameter.  This is required in order to support
multiple backends.

glob_audio_state is also gone, and replaced with a tailq so we can store
more than one states.

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio.h  |  12 +++--
 audio/audio_int.h  |   2 +
 audio/audio_template.h |   2 +-
 ui/vnc.h   |   2 +
 audio/audio.c  | 102 +++--
 audio/wavcapture.c |   6 +--
 monitor.c  |  12 -
 ui/vnc.c   |  15 +-
 hmp-commands.hx|  11 +++--
 qemu-options.hx|   5 ++
 10 files changed, 131 insertions(+), 38 deletions(-)

diff --git a/audio/audio.h b/audio/audio.h
index 64b0f761bc..ad2457f4de 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -78,8 +78,10 @@ typedef struct SWVoiceOut SWVoiceOut;
 typedef struct CaptureVoiceOut CaptureVoiceOut;
 typedef struct SWVoiceIn SWVoiceIn;
 
+typedef struct AudioState AudioState;
 typedef struct QEMUSoundCard {
 char *name;
+AudioState *state;
 QLIST_ENTRY (QEMUSoundCard) entries;
 } QEMUSoundCard;
 
@@ -92,7 +94,8 @@ void AUD_log (const char *cap, const char *fmt, ...) 
GCC_FMT_ATTR(2, 3);
 
 void AUD_register_card (const char *name, QEMUSoundCard *card);
 void AUD_remove_card (QEMUSoundCard *card);
-CaptureVoiceOut *AUD_add_capture (
+CaptureVoiceOut *AUD_add_capture(
+AudioState *s,
 struct audsettings *as,
 struct audio_capture_ops *ops,
 void *opaque
@@ -160,8 +163,8 @@ static inline void *advance (void *p, int incr)
 #define audio_MAX(a, b) ((a)<(b)?(b):(a))
 #endif
 
-int wav_start_capture (CaptureState *s, const char *path, int freq,
-   int bits, int nchannels);
+int wav_start_capture(AudioState *state, CaptureState *s, const char *path,
+  int freq, int bits, int nchannels);
 
 bool audio_is_cleaning_up(void);
 void audio_cleanup(void);
@@ -175,4 +178,7 @@ void audio_parse_option(const char *opt);
 void audio_init_audiodevs(void);
 void audio_legacy_help(void);
 
+AudioState *audio_state_by_name(const char *name);
+const char *audio_get_id(QEMUSoundCard *card);
+
 #endif /* QEMU_AUDIO_H */
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 2a7556d113..5ceea76eda 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -195,6 +195,8 @@ struct AudioState {
 
 bool timer_running;
 uint64_t timer_last;
+
+QTAILQ_ENTRY(AudioState) list;
 };
 
 extern const struct mixeng_volume nominal_volume;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index ccf6d810f7..ce1e5d6559 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -399,7 +399,7 @@ SW *glue (AUD_open_, TYPE) (
 struct audsettings *as
 )
 {
-AudioState *s = _audio_state;
+AudioState *s = card->state;
 AudiodevPerDirectionOptions *pdo = s->dev->TYPE;
 
 if (audio_bug(__func__, !card || !name || !callback_fn || !as)) {
diff --git a/ui/vnc.h b/ui/vnc.h
index a86e0610e8..0c9a2d82e0 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -181,6 +181,8 @@ struct VncDisplay
 #ifdef CONFIG_VNC_SASL
 VncDisplaySASL sasl;
 #endif
+
+AudioState *audio_state;
 };
 
 typedef struct VncTight {
diff --git a/audio/audio.c b/audio/audio.c
index ef8ce3b91d..2f9f37afb8 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -85,7 +85,8 @@ audio_driver *audio_driver_lookup(const char *name)
 return NULL;
 }
 
-static AudioState glob_audio_state;
+static QTAILQ_HEAD(AudioStateHead, AudioState) audio_states =
+QTAILQ_HEAD_INITIALIZER(audio_states);
 
 const struct mixeng_volume nominal_volume = {
 .mute = 0,
@@ -1239,11 +1240,14 @@ static void audio_run_capture (AudioState *s)
 
 void audio_run (const char *msg)
 {
-AudioState *s = _audio_state;
+AudioState *s;
+
+QTAILQ_FOREACH(s, _states, list) {
+audio_run_out (s);
+audio_run_in (s);
+audio_run_capture (s);
+}
 
-audio_run_out (s);
-audio_run_in (s);
-audio_run_capture (s);
 #ifdef DEBUG_POLL
 {
 static double prevtime;
@@ -1305,13 +1309,11 @@ bool audio_is_cleaning_up(void)
 return is_cleaning_up;
 }
 
-void audio_cleanup(void)
+static void free_audio_state(AudioState *s)
 {
-AudioState *s = _audio_state;
 HWVoiceOut *hwo, *hwon;
 HWVoiceIn *hwi, *hwin;
 
-is_cleaning_up = true;
 QLIST_FOREACH_SAFE(hwo, >hw_head_out, entries, hwon) {
 SWVoiceCap *sc;
 
@@ -1348,6 +1350,17 @@ void audio_cleanup(void)
 qapi_free_Audiodev(s->dev);
 s->dev = NULL;
 }
+g_free(s);
+}
+
+void audio_cleanup(void)
+{
+is_cleaning_up = true;
+while (!QTAILQ_EMPTY(_states)) {
+AudioState *s = QTAILQ_FIRST(_states);
+QTAILQ_REMOVE(_states, s, list);
+free_audio_state(s);
+}
 }
 
 static const VMStateDescription vmstate_audio = {
@@ -1374,28 +1387,33 @@ static AudiodevListEntry *audiodev_find(
 return NULL;
 }
 
-static 

[Qemu-devel] [PATCH v3 17/50] audio: add audiodev properties to frontends

2019-01-16 Thread Kővágó, Zoltán
Finally add audiodev= options to audio frontends so users can specify
which backend to use when multiple backends exist.  Not specifying an
audiodev= option currently causes the first audiodev to be used, this is
fixed in the next commit.

Example usage: -audiodev pa,id=foo -device AC97,audiodev=foo

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio.h|  3 ++
 include/hw/qdev-properties.h |  3 ++
 hw/audio/ac97.c  |  1 +
 hw/audio/adlib.c |  1 +
 hw/audio/cs4231a.c   |  1 +
 hw/audio/es1370.c|  7 +++-
 hw/audio/gus.c   |  1 +
 hw/audio/hda-codec.c |  1 +
 hw/audio/milkymist-ac97.c|  6 
 hw/audio/pcspk.c |  1 +
 hw/audio/pl041.c |  1 +
 hw/audio/sb16.c  |  1 +
 hw/audio/wm8750.c|  6 
 hw/core/qdev-properties-system.c | 57 
 hw/usb/dev-audio.c   |  1 +
 15 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/audio/audio.h b/audio/audio.h
index ad2457f4de..c0722a5cda 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -181,4 +181,7 @@ void audio_legacy_help(void);
 AudioState *audio_state_by_name(const char *name);
 const char *audio_get_id(QEMUSoundCard *card);
 
+#define DEFINE_AUDIO_PROPERTIES(_s, _f) \
+DEFINE_PROP_AUDIODEV("audiodev", _s, _f)
+
 #endif /* QEMU_AUDIO_H */
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index b6758c852e..6156409062 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -34,6 +34,7 @@ extern const PropertyInfo qdev_prop_blocksize;
 extern const PropertyInfo qdev_prop_pci_host_devaddr;
 extern const PropertyInfo qdev_prop_uuid;
 extern const PropertyInfo qdev_prop_arraylen;
+extern const PropertyInfo qdev_prop_audiodev;
 extern const PropertyInfo qdev_prop_link;
 extern const PropertyInfo qdev_prop_off_auto_pcibar;
 extern const PropertyInfo qdev_prop_pcie_link_speed;
@@ -233,6 +234,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
 + type_check(QemuUUID, typeof_field(_state, _field)),  \
 .set_default = true,   \
 }
+#define DEFINE_PROP_AUDIODEV(_n, _s, _f) \
+DEFINE_PROP(_n, _s, _f, qdev_prop_audiodev, QEMUSoundCard)
 
 #define DEFINE_PROP_END_OF_LIST()   \
 {}
diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c
index 2265622d44..03e3da4f31 100644
--- a/hw/audio/ac97.c
+++ b/hw/audio/ac97.c
@@ -1408,6 +1408,7 @@ static int ac97_init (PCIBus *bus)
 }
 
 static Property ac97_properties[] = {
+DEFINE_AUDIO_PROPERTIES(AC97LinkState, card),
 DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
 DEFINE_PROP_END_OF_LIST (),
 };
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index 0957780a3d..0d01cd07c5 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -298,6 +298,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
 }
 
 static Property adlib_properties[] = {
+DEFINE_AUDIO_PROPERTIES(AdlibState, card),
 DEFINE_PROP_UINT32 ("iobase",  AdlibState, port, 0x220),
 DEFINE_PROP_UINT32 ("freq",AdlibState, freq,  44100),
 DEFINE_PROP_END_OF_LIST (),
diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c
index 62da75eefe..d25a120b0f 100644
--- a/hw/audio/cs4231a.c
+++ b/hw/audio/cs4231a.c
@@ -687,6 +687,7 @@ static int cs4231a_init (ISABus *bus)
 }
 
 static Property cs4231a_properties[] = {
+DEFINE_AUDIO_PROPERTIES(CSState, card),
 DEFINE_PROP_UINT32 ("iobase",  CSState, port, 0x534),
 DEFINE_PROP_UINT32 ("irq", CSState, irq,  9),
 DEFINE_PROP_UINT32 ("dma", CSState, dma,  3),
diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index a5314d66fd..8c63912a82 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -886,6 +886,11 @@ static int es1370_init (PCIBus *bus)
 return 0;
 }
 
+static Property es1370_properties[] = {
+DEFINE_AUDIO_PROPERTIES(ES1370State, card),
+DEFINE_PROP_END_OF_LIST(),
+};
+
 static void es1370_class_init (ObjectClass *klass, void *data)
 {
 DeviceClass *dc = DEVICE_CLASS (klass);
@@ -902,6 +907,7 @@ static void es1370_class_init (ObjectClass *klass, void 
*data)
 dc->desc = "ENSONIQ AudioPCI ES1370";
 dc->vmsd = _es1370;
 dc->reset = es1370_on_reset;
+dc->props = es1370_properties;
 }
 
 static const TypeInfo es1370_info = {
@@ -922,4 +928,3 @@ static void es1370_register_types (void)
 }
 
 type_init (es1370_register_types)
-
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
index b3e2a7fdd5..dfb74cf0d3 100644
--- a/hw/audio/gus.c
+++ b/hw/audio/gus.c
@@ -295,6 +295,7 @@ static int GUS_init (ISABus *bus)
 }
 
 static Property gus_properties[] = {
+DEFINE_AUDIO_PROPERTIES(GUSState, card),
 DEFINE_PROP_UINT32 ("freq",GUSState, freq,44100),
 DEFINE_PROP_UINT32 ("iobase",  GUSState, port,0x240),
 DEFINE_PROP_UINT32 ("irq", 

[Qemu-devel] [PATCH v3 10/50] paaudio: port to -audiodev config

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_legacy.c | 39 +++
 audio/paaudio.c  | 90 
 2 files changed, 79 insertions(+), 50 deletions(-)

diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c
index 70b46cbcc1..d173ff042e 100644
--- a/audio/audio_legacy.c
+++ b/audio/audio_legacy.c
@@ -127,6 +127,16 @@ static uint32_t samples_to_usecs(uint32_t samples,
 return frames_to_usecs(samples / channels, pdo);
 }
 
+static void get_samples_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
+ AudiodevPerDirectionOptions *pdo)
+{
+const char *val = getenv(env);
+if (val) {
+*dst = samples_to_usecs(toui32(val), pdo);
+*has_dst = true;
+}
+}
+
 static uint32_t bytes_to_usecs(uint32_t bytes, AudiodevPerDirectionOptions 
*pdo)
 {
 AudioFormat fmt = pdo->has_format ? pdo->format : AUDIO_FORMAT_S16;
@@ -250,6 +260,31 @@ static void handle_oss(Audiodev *dev)
 get_int("QEMU_OSS_POLICY", >dsp_policy, >has_dsp_policy);
 }
 
+/* pulseaudio */
+static void handle_pa_per_direction(
+AudiodevPaPerDirectionOptions **ppdo, bool *has_ppdo, const char *env)
+{
+*ppdo = g_malloc0(sizeof(AudiodevPaPerDirectionOptions));
+*has_ppdo = true;
+
+get_str(env, &(*ppdo)->name, &(*ppdo)->has_name);
+}
+
+static void handle_pa(Audiodev *dev)
+{
+handle_pa_per_direction(>u.pa.sink, >u.pa.has_sink,
+"QEMU_PA_SINK");
+handle_pa_per_direction(>u.pa.source, >u.pa.has_source,
+"QEMU_PA_SOURCE");
+
+get_samples_to_usecs("QEMU_PA_SAMPLES", >in->buffer_len,
+ >in->has_buffer_len, dev->in);
+get_samples_to_usecs("QEMU_PA_SAMPLES", >out->buffer_len,
+ >out->has_buffer_len, dev->out);
+
+get_str("QEMU_PA_SERVER", >u.pa.server, >u.pa.has_server);
+}
+
 /* general */
 static void handle_per_direction(
 AudiodevPerDirectionOptions *pdo, const char *prefix)
@@ -309,6 +344,10 @@ static AudiodevListEntry *legacy_opt(const char *drvname)
 handle_oss(e->dev);
 break;
 
+case AUDIODEV_DRIVER_PA:
+handle_pa(e->dev);
+break;
+
 default:
 break;
 }
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 0981f010c9..33e0e5d9be 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -2,6 +2,7 @@
 #include "qemu/osdep.h"
 #include "qemu-common.h"
 #include "audio.h"
+#include "qapi/opts-visitor.h"
 
 #include 
 
@@ -10,14 +11,7 @@
 #include "audio_pt_int.h"
 
 typedef struct {
-int samples;
-char *server;
-char *sink;
-char *source;
-} PAConf;
-
-typedef struct {
-PAConf conf;
+Audiodev *dev;
 pa_threaded_mainloop *mainloop;
 pa_context *context;
 } paaudio;
@@ -32,6 +26,7 @@ typedef struct {
 void *pcm_buf;
 struct audio_pt pt;
 paaudio *g;
+int samples;
 } PAVoiceOut;
 
 typedef struct {
@@ -46,6 +41,7 @@ typedef struct {
 const void *read_data;
 size_t read_index, read_length;
 paaudio *g;
+int samples;
 } PAVoiceIn;
 
 static void qpa_audio_fini(void *opaque);
@@ -227,7 +223,7 @@ static void *qpa_thread_out (void *arg)
 }
 }
 
-decr = to_mix = audio_MIN(pa->live, pa->g->conf.samples >> 5);
+decr = to_mix = audio_MIN(pa->live, pa->samples >> 5);
 rpos = pa->rpos;
 
 if (audio_pt_unlock(>pt, __func__)) {
@@ -319,7 +315,7 @@ static void *qpa_thread_in (void *arg)
 }
 }
 
-incr = to_grab = audio_MIN(pa->dead, pa->g->conf.samples >> 5);
+incr = to_grab = audio_MIN(pa->dead, pa->samples >> 5);
 wpos = pa->wpos;
 
 if (audio_pt_unlock(>pt, __func__)) {
@@ -546,6 +542,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings 
*as,
 struct audsettings obt_as = *as;
 PAVoiceOut *pa = (PAVoiceOut *) hw;
 paaudio *g = pa->g = drv_opaque;
+AudiodevPaOptions *popts = >dev->u.pa;
+AudiodevPaPerDirectionOptions *ppdo = popts->sink;
 
 ss.format = audfmt_to_pa (as->fmt, as->endianness);
 ss.channels = as->nchannels;
@@ -566,7 +564,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings 
*as,
 g,
 "qemu",
 PA_STREAM_PLAYBACK,
-g->conf.sink,
+ppdo->has_name ? ppdo->name : NULL,
 ,
 NULL,   /* channel map */
 ,/* buffering attributes */
@@ -578,7 +576,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings 
*as,
 }
 
 audio_pcm_init_info (>info, _as);
-hw->samples = g->conf.samples;
+hw->samples = pa->samples = audio_buffer_samples(g->dev->out, _as,
+ 46440);
 pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
 pa->rpos = hw->rpos;
 if (!pa->pcm_buf) {
@@ -612,6 +611,8 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings 
*as, void 

[Qemu-devel] [PATCH v3 12/50] spiceaudio: port to -audiodev config

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/spiceaudio.c | 5 -
 1 file changed, 5 deletions(-)

diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index affc3df17f..4f7873af5a 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -373,10 +373,6 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
 return 0;
 }
 
-static struct audio_option audio_options[] = {
-{ /* end of list */ },
-};
-
 static struct audio_pcm_ops audio_callbacks = {
 .init_out = line_out_init,
 .fini_out = line_out_fini,
@@ -394,7 +390,6 @@ static struct audio_pcm_ops audio_callbacks = {
 static struct audio_driver spice_audio_driver = {
 .name   = "spice",
 .descr  = "spice audio driver",
-.options= audio_options,
 .init   = spice_audio_init,
 .fini   = spice_audio_fini,
 .pcm_ops= _callbacks,
-- 
2.20.1




[Qemu-devel] [PATCH v3 15/50] audio: reduce glob_audio_state usage

2019-01-16 Thread Kővágó, Zoltán
Remove glob_audio_state from functions, where possible without breaking
the API.  This means that most static functions in audio.c now take an
AudioState pointer instead of implicitly using glob_audio_state.  Also
included a pointer in SWVoice*, HWVoice* structs, so that functions
dealing them can know the audio state without having to pass it around
separately.

This is required in order to support multiple simultaneous audio
backends (added in a later commit).

Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_int.h  |  7 +
 audio/audio_template.h | 46 
 audio/audio.c  | 59 +++---
 3 files changed, 56 insertions(+), 56 deletions(-)

diff --git a/audio/audio_int.h b/audio/audio_int.h
index 66214199f0..2a7556d113 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -52,6 +52,7 @@ struct audio_pcm_info {
 typedef struct SWVoiceCap SWVoiceCap;
 
 typedef struct HWVoiceOut {
+AudioState *s;
 int enabled;
 int poll_mode;
 int pending_disable;
@@ -73,6 +74,7 @@ typedef struct HWVoiceOut {
 } HWVoiceOut;
 
 typedef struct HWVoiceIn {
+AudioState *s;
 int enabled;
 int poll_mode;
 struct audio_pcm_info info;
@@ -94,6 +96,7 @@ typedef struct HWVoiceIn {
 
 struct SWVoiceOut {
 QEMUSoundCard *card;
+AudioState *s;
 struct audio_pcm_info info;
 t_sample *conv;
 int64_t ratio;
@@ -111,6 +114,7 @@ struct SWVoiceOut {
 
 struct SWVoiceIn {
 QEMUSoundCard *card;
+AudioState *s;
 int active;
 struct audio_pcm_info info;
 int64_t ratio;
@@ -188,6 +192,9 @@ struct AudioState {
 int nb_hw_voices_in;
 int vm_running;
 int64_t period_ticks;
+
+bool timer_running;
+uint64_t timer_last;
 };
 
 extern const struct mixeng_volume nominal_volume;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index c1d7207abd..ccf6d810f7 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -36,9 +36,9 @@
 #define HWBUF hw->conv_buf
 #endif
 
-static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv)
+static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
+  struct audio_driver *drv)
 {
-AudioState *s = _audio_state;
 int max_voices = glue (drv->max_voices_, TYPE);
 int voice_size = glue (drv->voice_size_, TYPE);
 
@@ -183,8 +183,8 @@ static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
 
 static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
 {
-AudioState *s = _audio_state;
 HW *hw = *hwp;
+AudioState *s = hw->s;
 
 if (!hw->sw_head.lh_first) {
 #ifdef DAC
@@ -199,15 +199,14 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
 }
 }
 
-static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
+static HW *glue(audio_pcm_hw_find_any_, TYPE)(AudioState *s, HW *hw)
 {
-AudioState *s = _audio_state;
 return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first;
 }
 
-static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw)
+static HW *glue(audio_pcm_hw_find_any_enabled_, TYPE)(AudioState *s, HW *hw)
 {
-while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
+while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
 if (hw->enabled) {
 return hw;
 }
@@ -215,12 +214,10 @@ static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) 
(HW *hw)
 return NULL;
 }
 
-static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
-HW *hw,
-struct audsettings *as
-)
+static HW *glue(audio_pcm_hw_find_specific_, TYPE)(AudioState *s, HW *hw,
+   struct audsettings *as)
 {
-while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) {
+while ((hw = glue(audio_pcm_hw_find_any_, TYPE)(s, hw))) {
 if (audio_pcm_info_eq (>info, as)) {
 return hw;
 }
@@ -228,10 +225,10 @@ static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
 return NULL;
 }
 
-static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
+static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
+ struct audsettings *as)
 {
 HW *hw;
-AudioState *s = _audio_state;
 struct audio_driver *drv = s->drv;
 
 if (!glue (s->nb_hw_voices_, TYPE)) {
@@ -255,6 +252,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct 
audsettings *as)
 return NULL;
 }
 
+hw->s = s;
 hw->pcm_ops = drv->pcm_ops;
 hw->ctl_caps = drv->ctl_caps;
 
@@ -299,33 +297,33 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct 
audsettings *as)
 return NULL;
 }
 
-static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as)
+static HW *glue(audio_pcm_hw_add_, TYPE)(AudioState *s, struct audsettings *as)
 {
 HW *hw;
-AudioState *s = _audio_state;
 AudiodevPerDirectionOptions *pdo = s->dev->TYPE;
 
 if (pdo->fixed_settings) {
-hw = glue (audio_pcm_hw_add_new_, 

[Qemu-devel] [PATCH v3 03/50] audio: -audiodev command line option: documentation

2019-01-16 Thread Kővágó, Zoltán
This patch adds documentation of an -audiodev command line option, that
deprecates the old QEMU_* environment variables for audio backend
configuration.  It's syntax is similar to existing options (-netdev,
-device, etc):

  -audiodev driver_name,property=value,...

Although now it's possible to specify multiple -audiodev options on
command line, multiple audio backends are not supported yet.

Signed-off-by: Kővágó, Zoltán 
---
 qemu-options.hx | 222 +++-
 1 file changed, 219 insertions(+), 3 deletions(-)

diff --git a/qemu-options.hx b/qemu-options.hx
index 521511ec13..a12931899b 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -416,14 +416,230 @@ The default is @code{en-us}.
 ETEXI
 
 
+HXCOMM Deprecated by -audiodev
 DEF("audio-help", 0, QEMU_OPTION_audio_help,
-"-audio-help print list of audio drivers and their options\n",
+"-audio-help show -audiodev equivalent of the currently specified 
audio settings\n",
 QEMU_ARCH_ALL)
 STEXI
 @item -audio-help
 @findex -audio-help
-Will show the audio subsystem help: list of drivers, tunable
-parameters.
+Will show the -audiodev equivalent of the currently specified
+(deprecated) environment variables.
+ETEXI
+
+DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev,
+"-audiodev [driver=]driver,id=id[,prop[=value][,...]]\n"
+"specifies the audio backend to use\n"
+"id= identifier of the backend\n"
+"timer-period= timer period in microseconds\n"
+"in|out.fixed-settings= use fixed settings for host 
audio\n"
+"in|out.frequency= frequency to use with fixed settings\n"
+"in|out.channels= number of channels to use with fixed 
settings\n"
+"in|out.format= sample format to use with fixed settings\n"
+"valid values: s8, s16, s32, u8, u16, u32\n"
+"in|out.voices= number of voices to use\n"
+"in|out.buffer-len= size of buffer in microseconds\n"
+"in|out.buffer-count= number of buffers\n"
+"-audiodev none,id=id,[,prop[=value][,...]]\n"
+"dummy driver that discards all output\n"
+#ifdef CONFIG_ALSA
+"-audiodev alsa,id=id[,prop[=value][,...]]\n"
+"alsa-in|alsa-out.dev= name of the audio device to use\n"
+"alsa-in|alsa-out.try-poll= attempt to use poll mode\n"
+"threshold= threshold (in microseconds) when playback 
starts\n"
+#endif
+#ifdef CONFIG_COREAUDIO
+"-audiodev coreaudio,id=id[,prop[=value][,...]]\n"
+#endif
+#ifdef CONFIG_DSOUND
+"-audiodev dsound,id=id[,prop[=value][,...]]\n"
+"latency= add extra latency to playback in microseconds\n"
+#endif
+#ifdef CONFIG_OSS
+"-audiodev oss,id=id[,prop[=value][,...]]\n"
+"oss-in|oss-out.dev= path of the audio device to use\n"
+"oss-in|oss-out.try-poll= attempt to use poll mode\n"
+"try-mmap= try using memory mapped access\n"
+"exclusive= open device in exclusive mode\n"
+"dsp-policy= set timing policy (0..10), -1 to use fragment 
mode\n"
+#endif
+#ifdef CONFIG_PA
+"-audiodev pa,id=id[,prop[=value][,...]]\n"
+"server= PulseAudio server address\n"
+"sink|source.name= sink/source device name\n"
+#endif
+#ifdef CONFIG_SDL
+"-audiodev sdl,id=id[,prop[=value][,...]]\n"
+#endif
+#ifdef CONFIG_SPICE
+"-audiodev spice,id=id[,prop[=value][,...]]\n"
+#endif
+"-audiodev wav,id=id[,prop[=value][,...]]\n"
+"path= path of wav file to record\n",
+QEMU_ARCH_ALL)
+STEXI
+@item -audiodev 
[driver=]@var{driver},id=@var{id}[,@var{prop}[=@var{value}][,...]]
+@findex -audiodev
+Adds a new audio backend @var{driver} identified by @var{id}.  There are
+global and driver specific properties.  Some values can be set
+differently for input and output, they're marked with @code{in|out.}.
+You can set the input's property with @code{in.@var{prop}} and the
+output's property with @code{out.@var{prop}}. For example:
+@example
+-audiodev alsa,id=example,in.frequency=44110,out.frequency=8000
+-audiodev alsa,id=example,out.channels=1 # leaves in.channels unspecified
+@end example
+
+Valid global options are:
+
+@table @option
+@item id=@var{identifier}
+Identifies the audio backend.
+
+@item timer-period=@var{period}
+Sets the timer @var{period} used by the audio subsystem in microseconds.
+Default is 1 (10 ms).
+
+@item in|out.fixed-settings=on|off
+Use fixed settings for host audio.  When off, it will change based on
+how the guest opens the sound card.  In this case you must not specify
+@var{frequency}, @var{channels} or @var{format}.  Default is on.
+
+@item in|out.frequency=@var{frequency}
+Specify the @var{frequency} to use when using @var{fixed-settings}.
+Default is 44100Hz.
+

[Qemu-devel] [PATCH v3 13/50] wavaudio: port to -audiodev config

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_legacy.c | 15 
 audio/wavaudio.c | 58 +++-
 2 files changed, 24 insertions(+), 49 deletions(-)

diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c
index aa6c789096..cf0fc4df90 100644
--- a/audio/audio_legacy.c
+++ b/audio/audio_legacy.c
@@ -293,6 +293,17 @@ static void handle_sdl(Audiodev *dev)
  >out->has_buffer_len, dev->out);
 }
 
+/* wav */
+static void handle_wav(Audiodev *dev)
+{
+get_int("QEMU_WAV_FREQUENCY",
+>out->frequency, >out->has_frequency);
+get_fmt("QEMU_WAV_FORMAT", >out->format, >out->has_format);
+get_int("QEMU_WAV_DAC_FIXED_CHANNELS",
+>out->channels, >out->has_channels);
+get_str("QEMU_WAV_PATH", >u.wav.path, >u.wav.has_path);
+}
+
 /* general */
 static void handle_per_direction(
 AudiodevPerDirectionOptions *pdo, const char *prefix)
@@ -360,6 +371,10 @@ static AudiodevListEntry *legacy_opt(const char *drvname)
 handle_sdl(e->dev);
 break;
 
+case AUDIODEV_DRIVER_WAV:
+handle_wav(e->dev);
+break;
+
 default:
 break;
 }
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index 9eff3555b3..214e30ccd9 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -24,6 +24,7 @@
 #include "qemu/osdep.h"
 #include "qemu/host-utils.h"
 #include "qemu/timer.h"
+#include "qapi/opts-visitor.h"
 #include "audio.h"
 
 #define AUDIO_CAP "wav"
@@ -37,11 +38,6 @@ typedef struct WAVVoiceOut {
 int total_samples;
 } WAVVoiceOut;
 
-typedef struct {
-struct audsettings settings;
-const char *wav_path;
-} WAVConf;
-
 static int wav_run_out (HWVoiceOut *hw, int live)
 {
 WAVVoiceOut *wav = (WAVVoiceOut *) hw;
@@ -112,8 +108,10 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings 
*as,
 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
 };
-WAVConf *conf = drv_opaque;
-struct audsettings wav_as = conf->settings;
+Audiodev *dev = drv_opaque;
+AudiodevWavOptions *wopts = >u.wav;
+struct audsettings wav_as = audiodev_to_audsettings(dev->out);
+const char *wav_path = wopts->has_path ? wopts->path : "qemu.wav";
 
 stereo = wav_as.nchannels == 2;
 switch (wav_as.fmt) {
@@ -154,10 +152,10 @@ static int wav_init_out(HWVoiceOut *hw, struct 
audsettings *as,
 le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
 le_store (hdr + 32, 1 << (bits16 + stereo), 2);
 
-wav->f = fopen (conf->wav_path, "wb");
+wav->f = fopen(wav_path, "wb");
 if (!wav->f) {
 dolog ("Failed to open wave file `%s'\nReason: %s\n",
-   conf->wav_path, strerror (errno));
+   wav_path, strerror(errno));
 g_free (wav->pcm_buf);
 wav->pcm_buf = NULL;
 return -1;
@@ -225,54 +223,17 @@ static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
 return 0;
 }
 
-static WAVConf glob_conf = {
-.settings.freq  = 44100,
-.settings.nchannels = 2,
-.settings.fmt   = AUDIO_FORMAT_S16,
-.wav_path   = "qemu.wav"
-};
-
 static void *wav_audio_init(Audiodev *dev)
 {
-WAVConf *conf = g_malloc(sizeof(WAVConf));
-*conf = glob_conf;
-return conf;
+assert(dev->driver == AUDIODEV_DRIVER_WAV);
+return dev;
 }
 
 static void wav_audio_fini (void *opaque)
 {
 ldebug ("wav_fini");
-g_free(opaque);
 }
 
-static struct audio_option wav_options[] = {
-{
-.name  = "FREQUENCY",
-.tag   = AUD_OPT_INT,
-.valp  = _conf.settings.freq,
-.descr = "Frequency"
-},
-{
-.name  = "FORMAT",
-.tag   = AUD_OPT_FMT,
-.valp  = _conf.settings.fmt,
-.descr = "Format"
-},
-{
-.name  = "DAC_FIXED_CHANNELS",
-.tag   = AUD_OPT_INT,
-.valp  = _conf.settings.nchannels,
-.descr = "Number of channels (1 - mono, 2 - stereo)"
-},
-{
-.name  = "PATH",
-.tag   = AUD_OPT_STR,
-.valp  = _conf.wav_path,
-.descr = "Path to wave file"
-},
-{ /* End of list */ }
-};
-
 static struct audio_pcm_ops wav_pcm_ops = {
 .init_out = wav_init_out,
 .fini_out = wav_fini_out,
@@ -284,7 +245,6 @@ static struct audio_pcm_ops wav_pcm_ops = {
 static struct audio_driver wav_audio_driver = {
 .name   = "wav",
 .descr  = "WAV renderer http://wikipedia.org/wiki/WAV;,
-.options= wav_options,
 .init   = wav_audio_init,
 .fini   = wav_audio_fini,
 .pcm_ops= _pcm_ops,
-- 
2.20.1




[Qemu-devel] [PATCH v3 09/50] ossaudio: port to -audiodev config

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_legacy.c |  33 +
 audio/ossaudio.c | 167 +++
 2 files changed, 90 insertions(+), 110 deletions(-)

diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c
index 601a68fab6..70b46cbcc1 100644
--- a/audio/audio_legacy.c
+++ b/audio/audio_legacy.c
@@ -221,6 +221,35 @@ static void handle_dsound(Audiodev *dev)
>in->has_buffer_len, dev->in);
 }
 
+/* OSS */
+static void handle_oss_per_direction(
+AudiodevPerDirectionOptions *pdo, AudiodevOssPerDirectionOptions **opdo,
+bool *has_opdo, const char *try_poll_env, const char *dev_env)
+{
+*opdo = g_malloc0(sizeof(AudiodevOssPerDirectionOptions));
+*has_opdo = true;
+
+get_bool(try_poll_env, &(*opdo)->try_poll, &(*opdo)->has_try_poll);
+get_str(dev_env, &(*opdo)->dev, &(*opdo)->has_dev);
+
+get_bytes_to_usecs("QEMU_OSS_FRAGSIZE",
+   >buffer_len, >has_buffer_len, pdo);
+   get_int("QEMU_OSS_NFRAGS", >buffer_count, >has_buffer_count);
+}
+
+static void handle_oss(Audiodev *dev)
+{
+AudiodevOssOptions *oopt = >u.oss;
+handle_oss_per_direction(dev->in, >oss_in, >has_oss_in,
+ "QEMU_AUDIO_ADC_TRY_POLL", "QEMU_OSS_ADC_DEV");
+handle_oss_per_direction(dev->out, >oss_out, >has_oss_out,
+ "QEMU_AUDIO_DAC_TRY_POLL", "QEMU_OSS_DAC_DEV");
+
+get_bool("QEMU_OSS_MMAP", >try_mmap, >has_try_mmap);
+get_bool("QEMU_OSS_EXCLUSIVE", >exclusive, >has_exclusive);
+get_int("QEMU_OSS_POLICY", >dsp_policy, >has_dsp_policy);
+}
+
 /* general */
 static void handle_per_direction(
 AudiodevPerDirectionOptions *pdo, const char *prefix)
@@ -276,6 +305,10 @@ static AudiodevListEntry *legacy_opt(const char *drvname)
 handle_dsound(e->dev);
 break;
 
+case AUDIODEV_DRIVER_OSS:
+handle_oss(e->dev);
+break;
+
 default:
 break;
 }
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index e0cadbef29..d56c705dc0 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -37,16 +37,6 @@
 #define USE_DSP_POLICY
 #endif
 
-typedef struct OSSConf {
-int try_mmap;
-int nfrags;
-int fragsize;
-const char *devpath_out;
-const char *devpath_in;
-int exclusive;
-int policy;
-} OSSConf;
-
 typedef struct OSSVoiceOut {
 HWVoiceOut hw;
 void *pcm_buf;
@@ -56,7 +46,7 @@ typedef struct OSSVoiceOut {
 int fragsize;
 int mmapped;
 int pending;
-OSSConf *conf;
+Audiodev *dev;
 } OSSVoiceOut;
 
 typedef struct OSSVoiceIn {
@@ -65,12 +55,12 @@ typedef struct OSSVoiceIn {
 int fd;
 int nfrags;
 int fragsize;
-OSSConf *conf;
+Audiodev *dev;
 } OSSVoiceIn;
 
 struct oss_params {
 int freq;
-AudioFormat fmt;
+int fmt;
 int nchannels;
 int nfrags;
 int fragsize;
@@ -262,19 +252,26 @@ static int oss_get_version (int fd, int *version, const 
char *typ)
 }
 #endif
 
-static int oss_open (int in, struct oss_params *req,
- struct oss_params *obt, int *pfd, OSSConf* conf)
+static int oss_open(int in, struct oss_params *req, audsettings *as,
+struct oss_params *obt, int *pfd, Audiodev *dev)
 {
+AudiodevOssOptions *oopts = >u.oss;
+AudiodevOssPerDirectionOptions *opdo = in ? oopts->oss_in : oopts->oss_out;
+AudiodevPerDirectionOptions *pdo = in ? dev->in : dev->out;
 int fd;
-int oflags = conf->exclusive ? O_EXCL : 0;
+int oflags = (oopts->has_exclusive && oopts->exclusive) ? O_EXCL : 0;
 audio_buf_info abinfo;
 int fmt, freq, nchannels;
 int setfragment = 1;
-const char *dspname = in ? conf->devpath_in : conf->devpath_out;
+const char *dspname = opdo->has_dev ? opdo->dev : "/dev/dsp";
 const char *typ = in ? "ADC" : "DAC";
+#ifdef USE_DSP_POLICY
+int policy = oopts->has_dsp_policy ? oopts->dsp_policy : 5;
+#endif
 
 /* Kludge needed to have working mmap on Linux */
-oflags |= conf->try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
+oflags |= (oopts->has_try_mmap && oopts->try_mmap) ?
+O_RDWR : (in ? O_RDONLY : O_WRONLY);
 
 fd = open (dspname, oflags | O_NONBLOCK);
 if (-1 == fd) {
@@ -285,6 +282,8 @@ static int oss_open (int in, struct oss_params *req,
 freq = req->freq;
 nchannels = req->nchannels;
 fmt = req->fmt;
+req->nfrags = pdo->has_buffer_count ? pdo->buffer_count : 4;
+req->fragsize = audio_buffer_bytes(pdo, as, 23220);
 
 if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, )) {
 oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
@@ -308,18 +307,18 @@ static int oss_open (int in, struct oss_params *req,
 }
 
 #ifdef USE_DSP_POLICY
-if (conf->policy >= 0) {
+if (policy >= 0) {
 int version;
 
 if (!oss_get_version (fd, , typ)) {
 trace_oss_version(version);
 
 if (version >= 0x04) {
-int policy = 

[Qemu-devel] [PATCH v3 19/50] paaudio: do not move stream when sink/source name is specified

2019-01-16 Thread Kővágó, Zoltán
Unless we disable stream moving, pulseaudio can easily move the stream
on connect, effectively ignoring the source/sink specified by the user.

Signed-off-by: Kővágó, Zoltán 
---
 audio/paaudio.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/audio/paaudio.c b/audio/paaudio.c
index 1c20f8a7aa..108d3158a6 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -516,6 +516,11 @@ static pa_stream *qpa_simple_new (
 #endif
 |PA_STREAM_AUTO_TIMING_UPDATE;
 
+if (dev) {
+/* don't move the stream if the user specified a sink/source */
+flags |= PA_STREAM_DONT_MOVE;
+}
+
 if (dir == PA_STREAM_PLAYBACK) {
 r = pa_stream_connect_playback(stream, dev, attr, flags, NULL, NULL);
 } else {
-- 
2.20.1




[Qemu-devel] [PATCH v3 11/50] sdlaudio: port to -audiodev config

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/audio_legacy.c | 12 
 audio/sdlaudio.c | 22 --
 2 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c
index d173ff042e..aa6c789096 100644
--- a/audio/audio_legacy.c
+++ b/audio/audio_legacy.c
@@ -285,6 +285,14 @@ static void handle_pa(Audiodev *dev)
 get_str("QEMU_PA_SERVER", >u.pa.server, >u.pa.has_server);
 }
 
+/* SDL */
+static void handle_sdl(Audiodev *dev)
+{
+/* SDL is output only */
+get_samples_to_usecs("QEMU_SDL_SAMPLES", >out->buffer_len,
+ >out->has_buffer_len, dev->out);
+}
+
 /* general */
 static void handle_per_direction(
 AudiodevPerDirectionOptions *pdo, const char *prefix)
@@ -348,6 +356,10 @@ static AudiodevListEntry *legacy_opt(const char *drvname)
 handle_pa(e->dev);
 break;
 
+case AUDIODEV_DRIVER_SDL:
+handle_sdl(e->dev);
+break;
+
 default:
 break;
 }
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index 097841fde1..cf6ac19927 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -49,12 +49,6 @@ typedef struct SDLVoiceOut {
 int decr;
 } SDLVoiceOut;
 
-static struct {
-int nb_samples;
-} conf = {
-.nb_samples = 1024
-};
-
 static struct SDLAudioState {
 int exit;
 #if USE_SEMAPHORE
@@ -63,6 +57,7 @@ static struct SDLAudioState {
 #endif
 int initialized;
 bool driver_created;
+Audiodev *dev;
 } glob_sdl;
 typedef struct SDLAudioState SDLAudioState;
 
@@ -392,7 +387,7 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings 
*as,
 req.freq = as->freq;
 req.format = aud_to_sdlfmt (as->fmt);
 req.channels = as->nchannels;
-req.samples = conf.nb_samples;
+req.samples = audio_buffer_samples(s->dev->out, as, 11610);
 req.callback = sdl_callback;
 req.userdata = sdl;
 
@@ -467,6 +462,7 @@ static void *sdl_audio_init(Audiodev *dev)
 #endif
 
 s->driver_created = true;
+s->dev = dev;
 return s;
 }
 
@@ -480,18 +476,9 @@ static void sdl_audio_fini (void *opaque)
 #endif
 SDL_QuitSubSystem (SDL_INIT_AUDIO);
 s->driver_created = false;
+s->dev = NULL;
 }
 
-static struct audio_option sdl_options[] = {
-{
-.name  = "SAMPLES",
-.tag   = AUD_OPT_INT,
-.valp  = _samples,
-.descr = "Size of SDL buffer in samples"
-},
-{ /* End of list */ }
-};
-
 static struct audio_pcm_ops sdl_pcm_ops = {
 .init_out = sdl_init_out,
 .fini_out = sdl_fini_out,
@@ -503,7 +490,6 @@ static struct audio_pcm_ops sdl_pcm_ops = {
 static struct audio_driver sdl_audio_driver = {
 .name   = "sdl",
 .descr  = "SDL http://www.libsdl.org;,
-.options= sdl_options,
 .init   = sdl_audio_init,
 .fini   = sdl_audio_fini,
 .pcm_ops= _pcm_ops,
-- 
2.20.1




[Qemu-devel] [PATCH v3 01/50] qapi: qapi for audio backends

2019-01-16 Thread Kővágó, Zoltán
This patch adds structures into qapi to replace the existing
configuration structures used by audio backends currently. This qapi
will be the base of the -audiodev command line parameter (that replaces
the old environment variables based config).

This is not a 1:1 translation of the old options, I've tried to make
them much more consistent (e.g. almost every backend had an option to
specify buffer size, but the name was different for every backend, and
some backends required usecs, while some other required frames, samples
or bytes). Also tried to reduce the number of abbreviations used by the
config keys.

Some of the more important changes:
* use `in` and `out` instead of `ADC` and `DAC`, as the former is more
  user friendly imho
* moved buffer settings into the global setting area (so it's the same
  for all backends that support it. Backends that can't change buffer
  size will simply ignore them). Also using usecs, as it's probably more
  user friendly than samples or bytes.
* try-poll is now an alsa backend specific option (as all other backends
  currently ignore it)

Signed-off-by: Kővágó, Zoltán 
---

Notes:
Changes from v2:
* update copyright, version numbers
* remove #optional
* per-direction options are now optional (needed for 
qobject_object_visitor_new_str)
* removed unnecessary AudiodevNoOptions
* changed integers to unsigned

 Makefile.objs |   6 +-
 qapi/audio.json   | 233 ++
 qapi/qapi-schema.json |   1 +
 3 files changed, 237 insertions(+), 3 deletions(-)
 create mode 100644 qapi/audio.json

diff --git a/Makefile.objs b/Makefile.objs
index 456115992a..e830cdbafc 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -1,6 +1,6 @@
-QAPI_MODULES = block-core block char common crypto introspect job migration
-QAPI_MODULES += misc net rdma rocker run-state sockets tpm trace transaction
-QAPI_MODULES += ui
+QAPI_MODULES = audio block-core block char common crypto introspect job
+QAPI_MODULES += migration misc net rdma rocker run-state sockets tpm trace
+QAPI_MODULES += transaction ui
 
 ###
 # Common libraries for tools and emulators
diff --git a/qapi/audio.json b/qapi/audio.json
new file mode 100644
index 00..bd6e2494bd
--- /dev/null
+++ b/qapi/audio.json
@@ -0,0 +1,233 @@
+# -*- mode: python -*-
+#
+# Copyright (C) 2015-2019 Zoltán Kővágó 
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+##
+# @AudiodevAlsaPerDirectionOptions:
+#
+# Options of the alsa backend that are used for both playback and recording.
+#
+# @dev: the name of the alsa device to use (default 'default')
+#
+# @try-poll: attempt to use poll mode, falling back to non polling access on
+#failure (default on)
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevAlsaPerDirectionOptions',
+  'data': {
+'*dev':  'str',
+'*try-poll': 'bool' } }
+
+##
+# @AudiodevAlsaOptions:
+#
+# Options of the alsa audio backend.
+#
+# @alsa-in: options of the capture stream
+#
+# @alsa-out: options of the playback stream
+#
+# @threshold: set the threshold (in microseconds) when playback starts
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevAlsaOptions',
+  'data': {
+'*alsa-in':   'AudiodevAlsaPerDirectionOptions',
+'*alsa-out':  'AudiodevAlsaPerDirectionOptions',
+'*threshold': 'uint32' } }
+
+##
+# @AudiodevDsoundOptions:
+#
+# Options of the dsound audio backend.
+#
+# @latency: add extra latency to playback in microseconds (default 1)
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevDsoundOptions',
+  'data': {
+'*latency': 'uint32' } }
+
+##
+# @AudiodevOssPerDirectionOptions:
+#
+# Options of the oss backend that are used for both playback and recording.
+#
+# @dev: file name of the oss device (default '/dev/dsp')
+#
+# @try-poll: attempt to use poll mode, falling back to non polling access on
+#failure (default on)
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevOssPerDirectionOptions',
+  'data': {
+'*dev':  'str',
+'*try-poll': 'bool' } }
+
+##
+# @AudiodevOssOptions:
+#
+# Options of the oss audio backend.
+#
+# @oss-in: options of the capture stream
+#
+# @oss-out: options of the playback stream
+#
+# @try-mmap: try using memory mapped access, falling back to non
+#memory mapped access on failure (default off)
+#
+# @exclusive: open device in exclusive mode (vmix won't work) (default off)
+#
+# @dsp-policy: set the timing policy of the device (between 0 and 10, where
+#  smaller number means smaller latency but higher CPU usage) or -1
+#  to use fragment mode (option ignored on some platforms)
+#  (default 5)
+#
+# Since: 4.0
+##
+{ 'struct': 'AudiodevOssOptions',
+  'data': {
+'*oss-in': 'AudiodevOssPerDirectionOptions',
+'*oss-out':'AudiodevOssPerDirectionOptions',
+'*try-mmap':   'bool',

[Qemu-devel] [PATCH v3 08/50] noaudio: port to -audiodev config

2019-01-16 Thread Kővágó, Zoltán
Signed-off-by: Kővágó, Zoltán 
---
 audio/noaudio.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/audio/noaudio.c b/audio/noaudio.c
index 79690af1ea..ccc611fc84 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -163,7 +163,6 @@ static struct audio_pcm_ops no_pcm_ops = {
 static struct audio_driver no_audio_driver = {
 .name   = "none",
 .descr  = "Timer based audio emulation",
-.options= NULL,
 .init   = no_audio_init,
 .fini   = no_audio_fini,
 .pcm_ops= _pcm_ops,
-- 
2.20.1




  1   2   3   4   >