Compare commits

..

168 Commits

Author SHA1 Message Date
Kővágó, Zoltán d95d7d802c ossaudio: use trace events instead of debug config flag
Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:48 +02:00
Kővágó, Zoltán fbb7ef56d5 alsaaudio: use trace events instead of verbose
Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:48 +02:00
Kővágó, Zoltán 6dd35fd81e dsoundaudio: remove primary buffer
Enabling this option just creates a playback buffer with the specified settings,
and then ignores it. It's probably some outdated hack to set audio formats on
windows. (The first created stream dictates all other streams settings, at least
on some Windows versions). Setting DAC_FIXED_SETTINGS should have the same
effect as setting (the now removed) primary buffer.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:48 +02:00
Kővágó, Zoltán 2762955f72 dsoundaudio: remove *_retries kludges
According to MSDN this may happen when the window is not in the foreground, but
the default is 1 since a long time (which means no retries), so it should be ok.
I've found no problems during testing it on Windows 7 and wine, so this was
probably only the case with some old Windows versions.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:48 +02:00
Kővágó, Zoltán 73ad33ef7b audio: remove plive
It was useless even 3 years ago, so it can probably safely go away:
https://lists.nongnu.org/archive/html/qemu-devel/2012-03/msg02427.html

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:48 +02:00
Kővágó, Zoltán 06ac27f683 audio: remove LOG_TO_MONITOR along with default_mon
Setting QEMU_AUDIO_LOG_TO_MONITOR=1 can crash qemu (if qemu tries to log
to the monitor before it's being initialized), and also nothing else in
qemu logs to the monitor.

This log to monitor feature was the last thing that used the default_mon
variable, so I removed it too (as using it can cause problems).

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:48 +02:00
Gerd Hoffmann 65eb1e6b4c MAINTAINERS: remove malc from audio
email bounces, with a appearently permanent error:
"av1474@comtv.ru mail receiving disabled, rejecting"

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Gonglei <arei.gonglei@huawei.com>
2015-06-15 12:42:48 +02:00
Kővágó, Zoltán 81ebb07c56 sdlaudio: do not allow multiple instances
Since SDL uses a lot of global data, we can't create independent
instances of sdl audio backend.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:48 +02:00
Kővágó, Zoltán d1f52a1d70 coreaudio: do not use global variables where possible
Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:48 +02:00
Kővágó, Zoltán 191e1f0acd dsoundaudio: do not use global variables
Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:48 +02:00
Kővágó, Zoltán 49dd6d0d33 paaudio: fix possible resource leak
qpa_audio_init did not clean up resources properly if the initialization
failed. This hopefully fixes it.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:48 +02:00
Kővágó, Zoltán f2dcc6cec2 wavaudio: do not use global variables
Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:47 +02:00
Kővágó, Zoltán 4045a85ad1 ossaudio: do not use global variables
Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:47 +02:00
Kővágó, Zoltán 765b37da3f alsaaudio: do not use global variables
Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:47 +02:00
Kővágó, Zoltán 9a644c4b4d paaudio: do not use global variables
Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:47 +02:00
Kővágó, Zoltán 5706db1deb audio: expose drv_opaque to init_out and init_in
Currently the opaque pointer returned by audio_driver's init is only
exposed to the driver's fini, but not to audio_pcm_ops. This way if
someone wants to share a variable with the driver and the pcm, he must
use global variables. This patch fixes it by adding a third parameter to
audio_pcm_op's init_out and init_in.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:47 +02:00
Gerd Hoffmann 307119e7d9 only enable dsound in case the header file is present
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 12:42:47 +02:00
Kővágó, Zoltán 3cec7cc22f audio: remove winwave audio driver
DirectSound should be a superior choice on Windows.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 10:50:31 +02:00
Kővágó, Zoltán 14382605da audio: remove fmod backend
Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 10:50:31 +02:00
Kővágó, Zoltán 0bac111167 audio: remove esd backend
ESD is no longer developed and replaced by PulseAudio.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-15 10:50:31 +02:00
Peter Maydell 0a2df857a7 Merge remote-tracking branch 'remotes/stefanha/tags/net-pull-request' into staging
# gpg: Signature made Fri Jun 12 13:57:20 2015 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"

* remotes/stefanha/tags/net-pull-request:
  qmp/hmp: add rocker device support
  rocker: bring link up/down on PHY enable/disable
  rocker: update tests using hw-derived interface names
  rocker: Add support for phys name
  iohandler: Change return type of qemu_set_fd_handler to "void"
  event-notifier: Always return 0 for posix implementation
  xen_backend: Remove unused error handling of qemu_set_fd_handler
  oss: Remove unused error handling of qemu_set_fd_handler
  alsaaudio: Remove unused error handling of qemu_set_fd_handler
  main-loop: Drop qemu_set_fd_handler2
  Change qemu_set_fd_handler2(..., NULL, ...) to qemu_set_fd_handler
  tap: Drop tap_can_send
  net/socket: Drop net_socket_can_send
  netmap: Drop netmap_can_send
  l2tpv3: Drop l2tpv3_can_send
  stubs: Add qemu_set_fd_handler

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-12 15:39:05 +01:00
Peter Maydell 9faffeb777 Merge remote-tracking branch 'remotes/aurel/tags/pull-sh4-next-20150612' into staging
sh4 linux-user cpu and hwcap
misc optimizations and cleanup
convert r2d to new MMIO accessor style

# gpg: Signature made Fri Jun 12 11:28:43 2015 BST using RSA key ID 1DDD8C9B
# gpg: Good signature from "Aurelien Jarno <aurelien@aurel32.net>"
# gpg:                 aka "Aurelien Jarno <aurelien@jarno.fr>"
# gpg:                 aka "Aurelien Jarno <aurel32@debian.org>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 7746 2642 A9EF 94FD 0F77  196D BA9C 7806 1DDD 8C9B

* remotes/aurel/tags/pull-sh4-next-20150612:
  target-sh4: remove dead code
  target-sh4: factorize fmov implementation
  target-sh4: split out Q and M from of SR and optimize div1
  target-sh4: optimize negc using add2 and sub2
  target-sh4: optimize subc using sub2
  target-sh4: optimize addc using add2
  target-sh4: Split out T from SR
  target-sh4: use bit number for SR constants
  sh4/r2d: convert to new MMIO accessor style
  linux-user: Add HWCAP for SH4
  linux-user: Default sh4 to sh7785

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-12 14:31:13 +01:00
Scott Feldman fafa4d508b qmp/hmp: add rocker device support
Add QMP/HMP support for rocker devices.  This is mostly for debugging purposes
to see inside the device's tables and port configurations.  Some examples:

(qemu) info rocker sw1
name: sw1
id: 0x0000013512005452
ports: 4

(qemu) info rocker-ports sw1
            ena/    speed/ auto
      port  link    duplex neg?
     sw1.1  up     10G  FD  No
     sw1.2  up     10G  FD  No
     sw1.3  !ena   10G  FD  No
     sw1.4  !ena   10G  FD  No

(qemu) info rocker-of-dpa-flows sw1
prio tbl hits key(mask) --> actions
2    60       pport 1 vlan 1 LLDP src 00:02:00:00:02:00 dst 01:80:c2:00:00:0e
2    60       pport 1 vlan 1 ARP src 00:02:00:00:02:00 dst 00:02:00:00:03:00
2    60       pport 2 vlan 2 IPv6 src 00:02:00:00:03:00 dst 33:33:ff:00:00:02 proto 58
3    50       vlan 2 dst 33:33:ff:00:00:02 --> write group 0x32000001 goto tbl 60
2    60       pport 2 vlan 2 IPv6 src 00:02:00:00:03:00 dst 33:33:ff:00:03:00 proto 58
3    50  1    vlan 2 dst 33:33:ff:00:03:00 --> write group 0x32000001 goto tbl 60
2    60       pport 2 vlan 2 ARP src 00:02:00:00:03:00 dst 00:02:00:00:02:00
3    50  2    vlan 2 dst 00:02:00:00:02:00 --> write group 0x02000001 goto tbl 60
2    60  1    pport 2 vlan 2 IP src 00:02:00:00:03:00 dst 00:02:00:00:02:00 proto 1
3    50  2    vlan 1 dst 00:02:00:00:03:00 --> write group 0x01000002 goto tbl 60
2    60  1    pport 1 vlan 1 IP src 00:02:00:00:02:00 dst 00:02:00:00:03:00 proto 1
2    60       pport 1 vlan 1 IPv6 src 00:02:00:00:02:00 dst 33:33:ff:00:00:01 proto 58
3    50       vlan 1 dst 33:33:ff:00:00:01 --> write group 0x31000000 goto tbl 60
2    60       pport 1 vlan 1 IPv6 src 00:02:00:00:02:00 dst 33:33:ff:00:02:00 proto 58
3    50  1    vlan 1 dst 33:33:ff:00:02:00 --> write group 0x31000000 goto tbl 60
1    60  173  pport 2 vlan 2 LLDP src <any> dst 01:80:c2:00:00:0e --> write group 0x02000000
1    60  6    pport 2 vlan 2 IPv6 src <any> dst <any> --> write group 0x02000000
1    60  174  pport 1 vlan 1 LLDP src <any> dst 01:80:c2:00:00:0e --> write group 0x01000000
1    60  174  pport 2 vlan 2 IP src <any> dst <any> --> write group 0x02000000
1    60  6    pport 1 vlan 1 IPv6 src <any> dst <any> --> write group 0x01000000
1    60  181  pport 2 vlan 2 ARP src <any> dst <any> --> write group 0x02000000
1    10  715  pport 2 --> apply new vlan 2 goto tbl 20
1    60  177  pport 1 vlan 1 ARP src <any> dst <any> --> write group 0x01000000
1    60  174  pport 1 vlan 1 IP src <any> dst <any> --> write group 0x01000000
1    10  717  pport 1 --> apply new vlan 1 goto tbl 20
1    0   1432 pport 0(0xffff) --> goto tbl 10

(qemu) info rocker-of-dpa-groups sw1
id (decode) --> buckets
0x32000001 (type L2 multicast vlan 2 index 1) --> groups [0x02000001,0x02000000]
0x02000001 (type L2 interface vlan 2 pport 1) --> pop vlan out pport 1
0x01000002 (type L2 interface vlan 1 pport 2) --> pop vlan out pport 2
0x02000000 (type L2 interface vlan 2 pport 0) --> pop vlan out pport 0
0x01000000 (type L2 interface vlan 1 pport 0) --> pop vlan out pport 0
0x31000000 (type L2 multicast vlan 1 index 0) --> groups [0x01000002,0x01000000]

[Added "query-" prefixes to rocker.json commands as suggested by Eric
Blake <eblake@redhat.com>.
--Stefan]

Signed-off-by: Scott Feldman <sfeldma@gmail.com>
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
Message-id: 1433985681-56138-5-git-send-email-sfeldma@gmail.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:42:17 +01:00
Scott Feldman 5ff1547b75 rocker: bring link up/down on PHY enable/disable
When the OS driver enables/disables the port, go ahead and set the port's
link status to up/down in response to the change.  This more closely
emulates real hardware when the PHY for the port is brought up/down
and the PHY negotiates carrier (link status) with link partner.  In
the case of qemu, the virtual rocker device can't really do link
negotiation with the link partner as that requires signally over a
physical medium (the wire), so just pretend the negotiation was
successful and bring the link up when the port is enabled.

Signed-off-by: Scott Feldman <sfeldma@gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1433985681-56138-4-git-send-email-sfeldma@gmail.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:27 +01:00
Scott Feldman 73da023209 rocker: update tests using hw-derived interface names
With previous patch to support phy name attribute for each port, the OS
can name port interfaces using the hw-derived name.  So update rocker
tests to use the new hw-derived interface names.

Signed-off-by: Scott Feldman <sfeldma@gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-id: 1433985681-56138-3-git-send-email-sfeldma@gmail.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:27 +01:00
David Ahern 773495364f rocker: Add support for phys name
Add ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME to port settings. This attribute
exports the port name to the guest OS allowing it to name interfaces with
sensible defaults.

Mostly done by Scott for phys_id support; adapted to phys_name by David.

Signed-off-by: Scott Feldman <sfeldma@gmail.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
Message-id: 1433985681-56138-2-git-send-email-sfeldma@gmail.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:27 +01:00
Fam Zheng f4d248bdc3 iohandler: Change return type of qemu_set_fd_handler to "void"
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-14-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng 1e354528bd event-notifier: Always return 0 for posix implementation
qemu_set_fd_handler cannot fail, let's always return 0.

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-13-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng 6b5166f8a8 xen_backend: Remove unused error handling of qemu_set_fd_handler
The function cannot fail, so the check is superfluous.

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-12-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng b027a538c6 oss: Remove unused error handling of qemu_set_fd_handler
The function cannot fail, so the check is superfluous.

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-11-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng be93f21627 alsaaudio: Remove unused error handling of qemu_set_fd_handler
The function cannot fail, so the check is superfluous.

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-10-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng 6484e42247 main-loop: Drop qemu_set_fd_handler2
All users are converted to qemu_set_fd_handler now, drop
qemu_set_fd_handler2 and IOHandlerRecord.fd_read_poll.

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-9-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng 82e1cc4bf9 Change qemu_set_fd_handler2(..., NULL, ...) to qemu_set_fd_handler
Done with following Coccinelle semantic patch, plus manual cosmetic changes in
net/*.c.

    @@
    expression E1, E2, E3, E4;
    @@
    -   qemu_set_fd_handler2(E1, NULL, E2, E3, E4);
    +   qemu_set_fd_handler(E1, E2, E3, E4);

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-8-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng a90a7425cf tap: Drop tap_can_send
This callback is called by main loop before polling s->fd, if it returns
false, the fd will not be polled in this iteration.

This is redundant with checks inside read callback. After this patch,
the data will be sent to peer when it arrives. If the device can't
receive, it will be queued to incoming_queue, and when the device status
changes, this queue will be flushed.

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-7-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng 6e99c631f1 net/socket: Drop net_socket_can_send
This callback is called by main loop before polling s->fd, if it returns
false, the fd will not be polled in this iteration.

This is redundant with checks inside read callback. After this patch,
the data will be sent to peer when it arrives. If the device can't
receive, it will be queued to incoming_queue, and when the device status
changes, this queue will be flushed.

If the peer is not ready, disable the read poll until send completes.

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-6-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng e8dd1d9c39 netmap: Drop netmap_can_send
This callback is called by main loop before polling s->fd, if it returns
false, the fd will not be polled in this iteration.

This is redundant with checks inside read callback. After this patch,
the data will be copied from s->fd to s->iov when it arrives. If the
device can't receive, it will be queued to incoming_queue, and when the
device status changes, this queue will be flushed.

Also remove the qemu_can_send_packet() check in netmap_send. If it's
true, we are good; if it's false, the qemu_sendv_packet_async would
return 0 and read poll will be disabled until netmap_send_completed is
called.

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-5-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng 95b1416ae9 l2tpv3: Drop l2tpv3_can_send
This callback is called by main loop before polling s->fd, if it returns
false, the fd will not be polled in this iteration.

This is redundant with checks inside read callback. After this patch,
the data will be copied from s->fd to s->msgvec when it arrives. If the
device can't receive, it will be queued to incoming_queue, and when the
device status changes, this queue will be flushed.

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-4-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:21 +01:00
Fam Zheng 0bc12c4f7e stubs: Add qemu_set_fd_handler
Some qemu_set_fd_handler2 stub callers will be converted to
call qemu_set_fd_handler, add this stub for them before making the
change.

Signed-off-by: Fam Zheng <famz@redhat.com>
Message-id: 1433400324-7358-2-git-send-email-famz@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-12 13:26:20 +01:00
Peter Maydell 4cb618abc1 Merge remote-tracking branch 'remotes/lalrae/tags/mips-20150612' into staging
MIPS patches 2015-06-12

Changes:
* improve dp8393x network card and rc4030 chipset emulation
* support misaligned R6 and MSA memory accesses
* support MIPS eXtended and Large Physical Addressing
* add Config5.FRE bit and ERETNC instruction (Config5.LLB)
* support ememsize on MALTA

# gpg: Signature made Fri Jun 12 09:38:11 2015 BST using RSA key ID 0B29DA6B
# gpg: Good signature from "Leon Alrae <leon.alrae@imgtec.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 8DD3 2F98 5495 9D66 35D4  4FC0 5211 8E3C 0B29 DA6B

* remotes/lalrae/tags/mips-20150612: (29 commits)
  target-mips: enable XPA and LPA features
  target-mips: remove misleading comments in translate_init.c
  target-mips: add MTHC0 and MFHC0 instructions
  target-mips: add CP0.PageGrain.ELPA support
  target-mips: support Page Frame Number Extension field
  target-mips: extend selected CP0 registers to 64-bits in MIPS32
  target-mips: correct MFC0 for CP0.EntryLo in MIPS64
  net/dp8393x: fix hardware reset
  net/dp8393x: correctly reset in_use field
  net/dp8393x: add load/save support
  net/dp8393x: add PROM to store MAC address
  net/dp8393x: QOM'ify
  net/dp8393x: use dp8393x_ prefix for all functions
  net/dp8393x: do not use old_mmio accesses
  net/dp8393x: always calculate proper checksums
  dma/rc4030: convert to QOM
  dma/rc4030: use trace events instead of custom logging
  dma/rc4030: document register at offset 0x210
  dma/rc4030: do not use old_mmio accesses
  dma/rc4030: use AddressSpace and address_space_rw in users
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-12 12:49:40 +01:00
Peter Maydell a4ef02fd9b Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20150612' into staging
migration/next for 20150612

# gpg: Signature made Fri Jun 12 05:56:21 2015 BST using RSA key ID 5872D723
# gpg: Good signature from "Juan Quintela <quintela@redhat.com>"
# gpg:                 aka "Juan Quintela <quintela@trasno.org>"

* remotes/juanquintela/tags/migration/20150612: (21 commits)
  Remove unneeded memset
  Rename RDMA structures to make destination clear
  Teach analyze-migration.py about section footers
  Add a protective section footer
  Disable section footers on older machine types
  Merge section header writing
  Move loadvm_handlers into MigrationIncomingState
  Move copy out of qemu_peek_buffer
  Create MigrationIncomingState
  qemu_ram_foreach_block: pass up error value, and down the ramblock name
  Split header writing out of qemu_savevm_state_begin
  Add qemu_get_counted_string to read a string prefixed by a count byte
  migration: Use normal VMStateDescriptions for Subsections
  migration: create savevm_state
  migration: Remove duplicated assignment of SETUP status
  rdma: Fix qemu crash when IPv6 address is used for migration
  arch_init: Clean up the duplicate variable 'len' defining in ram_load()
  migration: reduce include files
  migration: Add myself to the copyright list of both files
  migration: move savevm.c inside migration/
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-12 11:06:03 +01:00
Aurelien Jarno d218b28d28 target-sh4: remove dead code
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:48 +02:00
Aurelien Jarno 91b4d29f4e target-sh4: factorize fmov implementation
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:48 +02:00
Aurelien Jarno 1d565b21e1 target-sh4: split out Q and M from of SR and optimize div1
Splitting Q and M out of SR, it's possible to optimize div1 by using
TCG code instead of an helper.

At the same time removed the now unused gen_copy_bit_i32 function.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:48 +02:00
Aurelien Jarno 60eb27fe49 target-sh4: optimize negc using add2 and sub2
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:48 +02:00
Aurelien Jarno d0f44a55fa target-sh4: optimize subc using sub2
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:48 +02:00
Aurelien Jarno a2368e01c9 target-sh4: optimize addc using add2
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:48 +02:00
Aurelien Jarno 3408694525 target-sh4: Split out T from SR
In preparation for more efficient setting of this field.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:48 +02:00
Aurelien Jarno 5ed9a259c1 target-sh4: use bit number for SR constants
Use the bit number for SR constants instead of using a bit mask. This
make possible to also use the constants for shifts.

Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:48 +02:00
Aurelien Jarno 563807520f sh4/r2d: convert to new MMIO accessor style
The documentation is clear to use 16-bit accesses for all registers.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:48 +02:00
Richard Henderson e42fd944f0 linux-user: Add HWCAP for SH4
Only exposing FPU and LLSC as the only features
supported by the translator.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:47 +02:00
Richard Henderson 91c45a38f2 linux-user: Default sh4 to sh7785
Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 12:02:47 +02:00
Leon Alrae 6773f9b687 target-mips: enable XPA and LPA features
Enable XPA in MIPS32R5-generic and LPA in MIPS64R6-generic.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 09:06:03 +01:00
Leon Alrae 28b027d5b6 target-mips: remove misleading comments in translate_init.c
PABITS are not hardcoded to 36 bits and we do not model 59 PABITS (which is
the architectural limit) in QEMU.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 09:05:43 +01:00
Leon Alrae 5204ea79ea target-mips: add MTHC0 and MFHC0 instructions
Implement MTHC0 and MFHC0 instructions. In MIPS32 they are used to access
upper word of extended to 64-bits CP0 registers.

In MIPS64, when CP0 destination register specified is the EntryLo0 or
EntryLo1, bits 1:0 of the GPR appear at bits 31:30 of EntryLo0 or
EntryLo1. This is to compensate for RI and XI, which were shifted to bits
63:62 by MTC0 to EntryLo0 or EntryLo1. Therefore creating separate
functions for EntryLo0 and EntryLo1.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 09:05:31 +01:00
Leon Alrae e117f52636 target-mips: add CP0.PageGrain.ELPA support
CP0.PageGrain.ELPA enables support for large physical addresses. This field
is encoded as follows:
0: Large physical address support is disabled.
1: Large physical address support is enabled.

If this bit is a 1, the following changes occur to coprocessor 0 registers:
- The PFNX field of the EntryLo0 and EntryLo1 registers is writable and
  concatenated with the PFN field to form the full page frame number.
- Access to optional COP0 registers with PA extension, LLAddr, TagLo is
  defined.

P5600 can operate in 32-bit or 40-bit Physical Address Mode. Therefore if
XPA is disabled (CP0.PageGrain.ELPA = 0) then assume 32-bit Address Mode.
In MIPS64 assume 36 as default PABITS (when CP0.PageGrain.ELPA = 0).

env->PABITS value is constant and indicates maximum PABITS available on
a core, whereas env->PAMask is calculated from env->PABITS and is also
affected by CP0.PageGrain.ELPA.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 09:05:20 +01:00
Leon Alrae cd0d45c401 target-mips: support Page Frame Number Extension field
Update tlb->PFN to contain PFN concatenated with PFNX. PFNX is 0 if large
physical address is not supported.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 09:05:14 +01:00
Leon Alrae 284b731a6a target-mips: extend selected CP0 registers to 64-bits in MIPS32
Extend EntryLo0, EntryLo1, LLAddr and TagLo from 32 to 64 bits in MIPS32.

Introduce gen_move_low32() function which moves low 32 bits from 64-bit
temp to GPR; it sign extends 32-bit value on MIPS64 and truncates on
MIPS32.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 09:05:00 +01:00
Leon Alrae b435f3f3d1 target-mips: correct MFC0 for CP0.EntryLo in MIPS64
CP0.EntryLo bits 31:30 have to be cleared.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-12 09:04:51 +01:00
Dr. David Alan Gilbert 4fa3dd17dc Remove unneeded memset
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Michael R. Hines <mrhines@us.ibm.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:02 +02:00
Dr. David Alan Gilbert a97270ad5d Rename RDMA structures to make destination clear
RDMA has two data types that are named confusingly;
   RDMALocalBlock (pointed to indirectly by local_ram_blocks)
   RDMARemoteBlock (pointed to by block in RDMAContext)

RDMALocalBlocks, as the name suggests is a data strucuture that
represents the RDMAable RAM Blocks on the current side of the migration
whichever that is.

RDMARemoteBlocks is always the shape of the RAMBlocks on the
destination, even on the destination.

Rename:
     RDMARemoteBlock -> RDMADestBlock
     context->'block' -> context->dest_blocks

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Michael R. Hines <mrhines@us.ibm.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:02 +02:00
Dr. David Alan Gilbert 73d9a7961a Teach analyze-migration.py about section footers
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:01 +02:00
Dr. David Alan Gilbert f68945d42b Add a protective section footer
Badly formatted migration streams can go undetected or produce
misleading errors due to a lock of checking at the end of sections.
In particular a section that adds an extra 0x00 at the end
causes what looks like a normal end of stream and thus doesn't produce
any errors, and something that ends in a 0x01..0x04 kind of look
like real section headers and then fail when the section parser tries
to figure out which section they are.  This is made worse by the
choice of 0x00..0x04 being small numbers that are particularly common
in normal section data.

This patch adds a section footer consisting of a marker (0x7e - ~)
followed by the section-id that was also sent in the header.  If
they mismatch then it throws an error explaining which section was
being loaded.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:01 +02:00
Dr. David Alan Gilbert 37fb569c01 Disable section footers on older machine types
The next patch adds section footers; but we don't want to
break migration compatibility so disable them on older
machine types

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:01 +02:00
Dr. David Alan Gilbert ce39bfc918 Merge section header writing
The header writing for device sections is open coded in
a few places, merge it into one.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:01 +02:00
Dr. David Alan Gilbert 1a8f46f8d6 Move loadvm_handlers into MigrationIncomingState
In postcopy we need the loadvm_handlers to be used in a couple
of different instances of the loadvm loop/routine, and thus
it can't be local any more.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:01 +02:00
Dr. David Alan Gilbert 7c1e52ba6f Move copy out of qemu_peek_buffer
qemu_peek_buffer currently copies the data it reads into a buffer,
however a future patch wants access to the buffer without the copy,
hence rework to remove the copy to the layer above.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:01 +02:00
Dr. David Alan Gilbert bca7856ae8 Create MigrationIncomingState
There are currently lots of pieces of incoming migration state scattered
around, and postcopy is adding more, and it seems better to try and keep
it together.

allocate MIS in process_incoming_migration_co

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:01 +02:00
Dr. David Alan Gilbert e3807054e2 qemu_ram_foreach_block: pass up error value, and down the ramblock name
check the return value of the function it calls and error if it's non-0
Fixup qemu_rdma_init_one_block that is the only current caller,
  and rdma_add_block the only function it calls using it.

Pass the name of the ramblock to the function; helps in debugging.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Michael R. Hines <mrhines@us.ibm.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:01 +02:00
Dr. David Alan Gilbert f796baa1b3 Split header writing out of qemu_savevm_state_begin
Split qemu_savevm_state_begin to:
  qemu_savevm_state_header   That writes the initial file header.
  qemu_savevm_state_begin    That sets up devices and does the first
                             device pass.

Used later in postcopy.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:01 +02:00
Dr. David Alan Gilbert b3af1bc9d2 Add qemu_get_counted_string to read a string prefixed by a count byte
and use it in loadvm_state and ram_load.

Where ever it's used, check the return and error if it failed.

Minor: ram_load was using a 257 byte array for its string, the
       maximum length is 255 bytes + 0 terminator, so fix to 256

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:54:01 +02:00
Juan Quintela 5cd8cadae8 migration: Use normal VMStateDescriptions for Subsections
We create optional sections with this patch.  But we already have
optional subsections.  Instead of having two mechanism that do the
same, we can just generalize it.

For subsections we just change:

- Add a needed function to VMStateDescription
- Remove VMStateSubsection (after removal of the needed function
  it is just a VMStateDescription)
- Adjust the whole tree, moving the needed function to the corresponding
  VMStateDescription

Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:53:57 +02:00
Juan Quintela 0163a2e025 migration: create savevm_state
This way, we will put savevm global state here, instead of lots of variables.

Signed-off-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
2015-06-12 06:42:34 +02:00
Juan Quintela e45a1ebfc6 migration: Remove duplicated assignment of SETUP status
We assign the MIGRATION_STATUS_SETUP status in two places.  Just in
succession.  Just remove the second one.

Signed-off-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-06-12 06:42:34 +02:00
Padmanabh Ratnakar 5b61d57521 rdma: Fix qemu crash when IPv6 address is used for migration
Qemu crashes when IPv6 address is specified for migration and access
to any RDMA uverbs device available on the system is blocked using cgroups.
Fix the crash by checking the return value of ibv_open_device routine.

Signed-off-by: Meghana Cheripady <meghana.cheripady@avagotech.com>
Signed-off-by: Padmanabh Ratnakar <padmanabh.ratnakar@avagotech.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:42:34 +02:00
zhanghailiang 5ee6926582 arch_init: Clean up the duplicate variable 'len' defining in ram_load()
There are two places that define 'len' variable, It's OK for compiling,
but makes it difficult for reading.

Remove the local one which defined in the inside 'while' loop.

Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2015-06-12 06:42:34 +02:00
Juan Quintela 7205c9ec52 migration: reduce include files
To make changes easier, with the copy, I maintained almost all include
files.  Now I remove the unnecessary ones on this patch.  This compiles
on linux x64 with all architectures configured, and cross-compiles for
windows 32 and 64 bits.

Signed-off-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-06-12 06:42:34 +02:00
Juan Quintela 76cc7b587f migration: Add myself to the copyright list of both files
If anyone feels like adding himself to the list, just sent me a patch.

Signed-off-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-06-12 06:42:34 +02:00
Juan Quintela c3049a56d6 migration: move savevm.c inside migration/
Now, everything is in place.

Signed-off-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-06-12 06:42:30 +02:00
Juan Quintela 56e93d26b8 migration: move ram stuff to migration/ram
For historic reasons, ram migration have been on arch_init.c.  Just
split it into migration/ram.c, the same that happened with block.c.

There is only code movement, no changes altogether.

Signed-off-by: Juan Quintela <quintela@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-06-12 06:40:59 +02:00
Peter Maydell d8e3b729cf Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
pc, acpi, virtio

Most notably this includes virtio 1 patches
Still not all devices converted, and not fully spec compliant,
so disabled by default.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Thu Jun 11 12:53:08 2015 BST using RSA key ID D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>"

* remotes/mst/tags/for_upstream: (42 commits)
  i386/acpi-build: fix PXB workarounds for unsupported BIOSes
  i386/acpi-build: more traditional _UID and _HID for PXB root buses
  vhost-scsi: move qdev properties into vhost-scsi.c
  virtio-9p-device: move qdev properties into virtio-9p-device.c
  virtio-serial-bus: move qdev properties into virtio-serial-bus.c
  virtio-rng: move qdev properties into virtio-rng.c
  virtio-scsi: move qdev properties into virtio-scsi.c
  virtio-net.h: Remove unsed DEFINE_VIRTIO_NET_PROPERTIES
  virtio-net: move qdev properties into virtio-net.c
  virtio-input: emulated devices [pci]
  virtio-input: core code & base class [pci]
  pci: add PCI_CLASS_INPUT_*
  virtio-pci: fill VirtIOPCIRegions early.
  virtio-pci: drop identical virtio_pci_cap
  virtio-pci: move cap type to VirtIOPCIRegion
  virtio-pci: move virtio_pci_add_mem_cap call to virtio_pci_modern_region_map
  virtio-pci: add virtio_pci_modern_region_map()
  virtio-pci: add virtio_pci_modern_regions_init()
  virtio-pci: add struct VirtIOPCIRegion for virtio-1 regions
  virtio-balloon: switch to virtio_add_feature
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-11 15:33:38 +01:00
Peter Maydell afa25c4bb5 Merge remote-tracking branch 'remotes/kraxel/tags/pull-sdl-20150611-1' into staging
sdl2: fix crash in handle_windowevent() when restoring the screen size

# gpg: Signature made Thu Jun 11 08:57:38 2015 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-sdl-20150611-1:
  sdl2: fix crash in handle_windowevent() when restoring the screen size

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-11 14:40:25 +01:00
Eric Auger 0b70743d4f hw/vfio/platform: replace g_malloc0_n by g_new0
g_malloc0_n() is introduced since glib-2.24 while QEMU currently
requires glib-2.22. This may cause a link error on some distributions.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Reviewed-by: Gonglei <arei.gonglei@huawei.com>
Acked-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-11 14:22:57 +01:00
Peter Maydell 169b71331e Merge remote-tracking branch 'remotes/spice/tags/pull-spice-20150611-1' into staging
spice: fix segfault in qemu_spice_create_update, ui_info tweaks.

# gpg: Signature made Thu Jun 11 08:48:49 2015 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/spice/tags/pull-spice-20150611-1:
  spice: ui_info tweaks
  spice-display: fix segfault in qemu_spice_create_update

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-11 12:12:58 +01:00
Laszlo Ersek 4ebc736e99 i386/acpi-build: fix PXB workarounds for unsupported BIOSes
The patch

  apci: fix PXB behaviour if used with unsupported BIOS

uses the following condition to see if a "PXB mem/IO chunk" has *not* been
configured by the BIOS:

  (!range_base || range_base > range_limit)

When this condition evaluates to true, said patch *omits* the
corresponding entry from the _CRS.

Later on the patch checks for the opposite condition (with the intent of
*adding* entries to the _CRS if the "PXB mem/IO chunks" *have* been
configured). Unfortunately, the condition was negated incorrectly: only
the first ! operator was removed, which led to the nonsensical expression

  (range_base || range_base > range_limit)

leading to bogus entries in the _CRS, and causing BSOD in Windows Server
2012 R2 when it runs on OVMF.

The correct negative of the condition seen at the top is

  (range_base && range_base <= range_limit)

Fix the expressions.

Cc: Marcel Apfelbaum <marcel@redhat.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Marcel Apfelbaum <marcel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-11 12:40:30 +02:00
Laszlo Ersek c96d9286a6 i386/acpi-build: more traditional _UID and _HID for PXB root buses
The ACPI specification permits the _HID and _UID objects to evaluate to
strings. (See "6.1.5 _HID (Hardware ID)" and "6.1.12 _UID (Unique ID)" in
the ACPI v6.0 spec.)

With regard to related standards, the UEFI specification can also express
a device address composed from string _HID and _UID identifiers, inside
the Expanded ACPI Device Path Node. (See "9.3.3 ACPI Device Path", Table
49, in the UEFI v2.5 spec.)

However, numeric (integer) contents for both _HID and _UID are more
traditional. They are recommended by the UEFI spec for size reasons:

  [...] the ACPI Device Path node is smaller and should be used if
  possible to reduce the size of device paths that may potentially be
  stored in nonvolatile storage [...]

External tools support them better (for example the --acpi_hid and
--acpi_uid options of "efibootmgr" only take numeric identifiers).
Finally, numeric _HID and _UID contents are existing practice in the QEMU
source.

This patch was tested with a Fedora 20 LiveCD and a preexistent Windows
Server 2012 R2 guest. Using "acpidump" and "iasl" in the Fedora guest, we
get, in the SSDT:

> Scope (\_SB)
> {
>   Device (PC04)
>   {
>     Name (_UID, 0x04)  // _UID: Unique ID
>     Name (_HID, EisaId ("PNP0A03") /* PCI Bus */)  // _HID: Hardware ID

Cc: Marcel Apfelbaum <marcel@redhat.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Marcel Apfelbaum <marcel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-11 12:40:30 +02:00
Peter Maydell 39e16a5b70 Merge remote-tracking branch 'remotes/kraxel/tags/pull-gtk-20150611-1' into staging
gtk: don't exit early in case gtk init fails

# gpg: Signature made Thu Jun 11 10:38:29 2015 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-gtk-20150611-1:
  gtk: don't exit early in case gtk init fails

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-11 11:18:11 +01:00
Gerd Hoffmann 060ab76356 gtk: don't exit early in case gtk init fails
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
2015-06-11 11:37:56 +02:00
Hervé Poussineau bd8f1ebce4 net/dp8393x: fix hardware reset
Documentation is not clear of what happens when doing a hardware reset,
but firmware expect all registers to be zero unless specified otherwise.

This fixes reboot on MIPS Magnum.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:30 +01:00
Hervé Poussineau 409b52bfe1 net/dp8393x: correctly reset in_use field
Don't write more than the field width, which is always 16 bit.
Fixes network in NetBSD 5.1/arc

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:30 +01:00
Hervé Poussineau 1670735dd7 net/dp8393x: add load/save support
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:30 +01:00
Hervé Poussineau 89ae0ff9b7 net/dp8393x: add PROM to store MAC address
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:30 +01:00
Hervé Poussineau 104655a5c8 net/dp8393x: QOM'ify
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:30 +01:00
Hervé Poussineau 3df5de64f0 net/dp8393x: use dp8393x_ prefix for all functions
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:29 +01:00
Hervé Poussineau 84689cbb97 net/dp8393x: do not use old_mmio accesses
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:29 +01:00
Hervé Poussineau f2f62c4db2 net/dp8393x: always calculate proper checksums
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:29 +01:00
Hervé Poussineau d791d60f1c dma/rc4030: convert to QOM
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:29 +01:00
Hervé Poussineau 95c357bc46 dma/rc4030: use trace events instead of custom logging
Remove also unneeded debug logs.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:29 +01:00
Hervé Poussineau dc6e3e1e1a dma/rc4030: document register at offset 0x210
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:29 +01:00
Hervé Poussineau b421f3f52a dma/rc4030: do not use old_mmio accesses
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:29 +01:00
Hervé Poussineau dd8205130b dma/rc4030: use AddressSpace and address_space_rw in users
Now that rc4030 internally uses an AddressSpace for DMA handling, make its root
memory region public. This is especially usefull for dp8393x netcard, which now
uses well known QEMU types and methods.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:29 +01:00
Hervé Poussineau a3d586f704 dma/rc4030: create custom DMA address space
Add a new memory region in system address space where DMA address space
definition (the 'translation table') belongs, so we can update on the fly
the DMA address space.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:29 +01:00
Hervé Poussineau 9b1d21c53b mips jazz: compile only in 64 bit
Remove now useless device models from other MIPS configurations

We're now compiling 12 files less than before.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:29 +01:00
Leon Alrae ce9782f40a target-mips: add ERETNC instruction and Config5.LLB bit
ERETNC is identical to ERET except that an ERETNC will not clear the LLbit
that is set by execution of an LL instruction, and thus when placed between
an LL and SC sequence, will never cause the SC to fail.

Presence of ERETNC is denoted by the Config5.LLB.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2015-06-11 10:13:29 +01:00
Yongbok Kim adc370a48f target-mips: Misaligned memory accesses for MSA
MIPS SIMD Architecture vector loads and stores require misalignment support.
MSA Memory access should work as an atomic operation. Therefore, it has to
check validity of all addresses for a vector store access if it is spanning
into two pages.

Separating helper functions for each data format as format is known in
translation.
To use mmu_idx from cpu_mmu_index() instead of calculating it from hflag.
Removing save_cpu_state() call in translation because it is able to use
cpu_restore_state() on fault as GETRA() is passed.

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
[leon.alrae@imgtec.com: remove unused do_* functions]
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:28 +01:00
Yongbok Kim 3b4afc9e75 softmmu: Add probe_write()
Probe for whether the specified guest write access is permitted.
If it is not permitted then an exception will be taken in the same
way as if this were a real write access (and we will not return).
Otherwise the function will return, and there will be a valid
entry in the TLB for this access.

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:28 +01:00
Yongbok Kim be3a8c53b4 target-mips: Misaligned memory accesses for R6
Release 6 requires misaligned memory access support for all ordinary memory
access instructions (for example, LW/SW, LWC1/SWC1).
However misaligned support is not provided for certain special memory accesses
such as atomics (for example, LL/SC).

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:28 +01:00
Paul Burton 71c199c81d mips_malta: provide ememsize env variable to kernels
Commit 94c2b6aff4 (mips_malta: support up to 2GiB RAM) provided
support for using over 256MB of RAM with the MIPS Malta board, including
capping the memsize variable that QEMUs pseudo-bootloader provides to
the kernel at 256MB in order to match YAMON. It didn't however provide
the ememsize variable which kernels supporting memory outside of the
unmapped address spaces (ie. EVA or highmem) may use to determine the
true size of the RAM present in the system.

Set ememsize to the size of RAM so that such kernels may use all
available memory without the user having to manually specifying its size
& location.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Cc: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:28 +01:00
Leon Alrae 7c979afd11 target-mips: add Config5.FRE support allowing Status.FR=0 emulation
This relatively small architectural feature adds the following:

FIR.FREP: Read-only. If FREP=1, then Config5.FRE and Config5.UFE are
          available.

Config5.FRE: When enabled all single-precision FP arithmetic instructions,
             LWC1/LWXC1/MTC1, SWC1/SWXC1/MFC1 cause a Reserved Instructions
             exception.

Config5.UFE: Allows user to write/read Config5.FRE using CTC1/CFC1
             instructions.

Enable the feature in MIPS64R6-generic CPU.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:28 +01:00
Leon Alrae eab9944c78 target-mips: move group of functions above gen_load_fpr32()
Move the "Tests" group of functions so that gen_load_fpr32() and
gen_store_fpr32() can use generate_exception().

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2015-06-11 10:13:28 +01:00
Gerd Hoffmann 5a9259a0b5 spice: ui_info tweaks
Use the new dpy_ui_info_supported function.
Clarifies the control flow.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-11 09:06:14 +02:00
Gerd Hoffmann c6e484707f spice-display: fix segfault in qemu_spice_create_update
Although it is pretty unusual the stride for the guest image and the
mirror image maintained by spice-display can be different.  So use
separate variables for them.

https://bugzilla.redhat.com/show_bug.cgi?id=1163047

Cc: qemu-stable@nongnu.org
Reported-by: perrier vincent <clownix@clownix.net>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-11 09:06:14 +02:00
Peter Maydell 0e12e61ff9 Merge remote-tracking branch 'remotes/kraxel/tags/pull-vga-20150610-1' into staging
stdvga: factor out mmio subregion init
virtio-gpu: add virtio gpu core code, 2d mode

# gpg: Signature made Wed Jun 10 10:03:11 2015 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-vga-20150610-1:
  virtio-gpu/2d: add virtio gpu core code
  virtio: update headers, add virtio-gpu (2d)
  stdvga: factor out mmio subregion init
  stdvga: pass VGACommonState instead of PCIVGAState
  stdvga: fix offset in pci_vga_ioport_read

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-10 18:13:58 +01:00
Shannon Zhao 21549a4642 vhost-scsi: move qdev properties into vhost-scsi.c
As only one place in vhost-scsi.c uses DEFINE_VHOST_SCSI_PROPERTIES,
there is no need to expose it. Inline it into vhost-scsi.c to avoid
wrongly use.

Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:34 +02:00
Shannon Zhao 83a84878da virtio-9p-device: move qdev properties into virtio-9p-device.c
As only one place in virtio-9p-device.c uses
DEFINE_VIRTIO_9P_PROPERTIES, there is no need to expose it. Inline it
into virtio-9p-device.c to avoid wrongly use.

Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:34 +02:00
Shannon Zhao 448777c411 virtio-serial-bus: move qdev properties into virtio-serial-bus.c
As only one place in virtio-serial-bus.c uses
DEFINE_VIRTIO_SERIAL_PROPERTIES, there is no need to expose it. Inline
it into virtio-serial-bus.c to avoid wrongly use.

Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:34 +02:00
Shannon Zhao fe704809b9 virtio-rng: move qdev properties into virtio-rng.c
As only one place in virtio-rng.c uses DEFINE_VIRTIO_RNG_PROPERTIES,
there is no need to expose it. Inline it into virtio-rng.c to avoid
wrongly use.

Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:34 +02:00
Shannon Zhao 0c63237a90 virtio-scsi: move qdev properties into virtio-scsi.c
As only one place in virtio-scsi.c uses DEFINE_VIRTIO_SCSI_PROPERTIES
and DEFINE_VIRTIO_SCSI_FEATURES, there is no need to expose them. Inline
them into virtio-scsi.c to avoid wrongly use.

Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:34 +02:00
Shannon Zhao db58c063e1 virtio-net.h: Remove unsed DEFINE_VIRTIO_NET_PROPERTIES
Remove unsed DEFINE_VIRTIO_NET_PROPERTIES in virtio-net.h and delete a
space typo.

Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:34 +02:00
Shannon Zhao 87108bb26c virtio-net: move qdev properties into virtio-net.c
As only one place in virtio-net.c uses DEFINE_VIRTIO_NET_FEATURES,
there is no need to expose it. Inline it into virtio-net.c to avoid
wrongly use.

Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:34 +02:00
Gerd Hoffmann 710e2d90da virtio-input: emulated devices [pci]
This patch adds virtio-pci support for the emulated virtio-input
devices.  Using them is as simple as adding "-device virtio-tablet-pci"
to your command line.  If you want add multiple devices but don't want
waste a pci slot for each you can compose a multifunction device this way:

qemu -device virtio-keyboard-pci,addr=0d.0,multifunction=on \
     -device virtio-tablet-pci,addr=0d.1,multifunction=on

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Gerd Hoffmann f958c8aa13 virtio-input: core code & base class [pci]
This patch adds the virtio-pci support bits for virtio-input-device.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Gerd Hoffmann ffaa050371 pci: add PCI_CLASS_INPUT_*
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Gerd Hoffmann b6ce27a593 virtio-pci: fill VirtIOPCIRegions early.
Initialize the modern bar and the VirtIOPCIRegion fields early, in
realize.  Also add a size field to VirtIOPCIRegion and variables for
pci bars to VirtIOPCIProxy.

This allows virtio-pci subclasses to change things before the
device_plugged callback applies them.  virtio-vga will use that to
arrange regions in a way that virtio-vga is compatible to both stdvga
(in vga mode) and virtio-gpu-pci (in pci mode).

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Gerd Hoffmann cc52ea90f8 virtio-pci: drop identical virtio_pci_cap
Now the three struct virtio_pci_caps are identical,
lets drop two of them ;)

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Gerd Hoffmann fc004905c5 virtio-pci: move cap type to VirtIOPCIRegion
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Gerd Hoffmann 54790d71e4 virtio-pci: move virtio_pci_add_mem_cap call to virtio_pci_modern_region_map
Also fill offset and length automatically,
from VirtIOPCIRegion->offset and region size.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Gerd Hoffmann a3cc2e8159 virtio-pci: add virtio_pci_modern_region_map()
Add function to map modern virtio regions.
Add offset to VirtIOPCIRegion.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Gerd Hoffmann 1141ce2190 virtio-pci: add virtio_pci_modern_regions_init()
Add init function for the modern pci regions,
move over the init code.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Gerd Hoffmann 588255ad50 virtio-pci: add struct VirtIOPCIRegion for virtio-1 regions
For now just place the MemoryRegion there,
following patches will add more.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Cornelia Huck 40de55affd virtio-balloon: switch to virtio_add_feature
This was missed during the conversion of feature bit manipulation.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:06 +02:00
Michael S. Tsirkin fbdc6892dd virtio_balloon: header update
add modern header

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Jason Wang 975acc0ae6 virtio-pci: correctly set host notifiers for modern bar
Currently, during host notifier set. We only add eventfd for legacy
bar, this is not correct since:

- Non-transitional device does not have legacy bar, so qemu will crash
  since proxy->bar was not initialized.
- Modern device uses modern bar and notify cap to notify the device,
  we should add eventfd for proxy->notify.

So this patch fixes the above two issues by adding eventfd based on
whether legacy or modern device were supported.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Gerd Hoffmann 4e93a68eb3 virtio-pci: make modern bar 64bit + prefetchable
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Gerd Hoffmann 23c5e39775 virtio-pci: change & document virtio pci bar layout.
This patch adds variables for the pci bars (to get rid of the magic
numbers in the code) and moves the modern virtio bar to region 4 so
regions 2+3 are kept free.  virtio-vga wants use them.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Gerd Hoffmann 8aca0d7586 virtio-pci: make QEMU_VIRTIO_PCI_QUEUE_MEM_MULT smaller
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Gerd Hoffmann e266d42149 virtio-pci: add flags to enable/disable legacy/modern
Add VIRTIO_PCI_FLAG_DISABLE_LEGACY and VIRTIO_PCI_FLAG_DISABLE_MODERN
for VirtIOPCIProxy->flags.  Also add properties for them.  They can be
used to disable modern (virtio 1.0) or legacy (virtio 0.9) modes.

By default only legacy is advertized, modern will be turned on by
default once all remaining spec compilance issues are addressed.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Michael S. Tsirkin 54c720d49d virtio-pci: switch to modern accessors for 1.0
virtio 1.0 config space is in LE format for all
devices, use modern wrappers when accessed through
the 1.0 BAR.

Reported-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Michael S. Tsirkin adfb743c90 virtio: add modern config accessors
virtio 1.0 defines config space as LE,
as opposed to pre-1.0 which was native endian.

Add API for transports to execute word/dword accesses in
little endian format - will be useful for mmio
and pci (byte access is also wrapped, for completeness).

For simplicity, we still keep config in host native
endian format, byteswap to LE on guest access.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Michael S. Tsirkin b8f059081d virtio: generation counter support
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Michael S. Tsirkin dfb8e184db virtio-pci: initial virtio 1.0 support
This is somewhat functional.  With this, and linux driver from my tree,
I was able to use virtio net as virtio 1.0 device for light browsing.

At the moment, dataplane and vhost code is
still missing.

Based on Cornelia's virtio 1.0 patchset:
    Date: Thu, 11 Dec 2014 14:25:02 +0100
    From: Cornelia Huck <cornelia.huck@de.ibm.com>
    To: virtualization@lists.linux-foundation.org, qemu-devel@nongnu.org
    Cc: rusty@rustcorp.com.au, thuth@linux.vnet.ibm.com, mst@redhat.com,
    Cornelia Huck <cornelia.huck@de.ibm.com>
    Subject: [PATCH RFC v6 00/20] qemu: towards virtio-1 host support
    Message-Id: <1418304322-7546-1-git-send-email-cornelia.huck@de.ibm.com>

which is itself still missing some core bits.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Michael S. Tsirkin c17bef3360 linux-headers: add virtio_pci
Easier than duplicating code.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:05 +02:00
Cornelia Huck 9a2ba82302 vhost: 64 bit features
Make sure that all vhost interfaces use 64 bit features, as the virtio
core does, and make sure to use ULL everywhere possible to be on the
safe side.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:04 +02:00
Michael S. Tsirkin b150613200 vhost_net: add version_1 feature
Add VERSION_1 to list of features that we should
test at the backend.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:04 +02:00
Cornelia Huck df91055db5 virtio-net: enable virtio 1.0
virtio-net (non-vhost) now should have everything in place to support
virtio 1.0: let's enable the feature bit for it.

Note that VIRTIO_F_VERSION_1 is technically a transport feature; once
every device is ready for virtio 1.0, we can move setting this
feature bit out of the individual devices.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:04 +02:00
Cornelia Huck bb9d17f831 virtio-net: support longer header
virtio-1 devices always use num_buffers in the header, even if
mergeable rx buffers have not been negotiated.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:04 +02:00
Cornelia Huck b6a3cddb22 virtio-net: no writeable mac for virtio-1
Devices operating as virtio 1.0 may not allow writes to the mac
address in config space.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:04 +02:00
Cornelia Huck 0b352fd680 virtio: allow to fail setting status
virtio-1 allow setting of the FEATURES_OK status bit to fail if
the negotiated feature bits are inconsistent: let's fail
virtio_set_status() in that case and update virtio-ccw to post an
error to the guest.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:04 +02:00
Cornelia Huck 6c0196d702 virtio: disallow late feature changes for virtio-1
For virtio-1 devices, the driver must not attempt to set feature bits
after it set FEATURES_OK in the device status. Simply reject it in
that case.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:04 +02:00
Cornelia Huck f5a5628cf0 dataplane: allow virtio-1 devices
Handle endianness conversion for virtio-1 virtqueues correctly.

Note that dataplane now needs to be built per-target.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:04 +02:00
Cornelia Huck ab223c9518 virtio: allow virtio-1 queue layout
For virtio-1 devices, we allow a more complex queue layout that doesn't
require descriptor table and rings on a physically-contigous memory area:
add virtio_queue_set_rings() to allow transports to set this up.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:04 +02:00
Cornelia Huck 3c185597c8 virtio: endianness checks for virtio 1.0 devices
Add code that checks for the VERSION_1 feature bit in order to make
decisions about the device's endianness. This allows us to support
transitional devices.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 18:15:04 +02:00
Peter Maydell 3974c9d8cc Merge remote-tracking branch 'remotes/kraxel/tags/pull-fw_cfg-20150610-1' into staging
fw_cfg: drop write support, qemu cmdline support, bugfixes.
bios-tables-test: fix smbios test.

# gpg: Signature made Wed Jun 10 07:29:53 2015 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-fw_cfg-20150610-1:
  bios-tables-test: handle false-positive smbios signature matches
  fw_cfg: insert fw_cfg file blobs via qemu cmdline
  fw_cfg: prohibit insertion of duplicate fw_cfg file names
  fw_cfg: prevent selector key conflict
  fw_cfg: remove support for guest-side data writes
  fw_cfg: fix FW_CFG_BOOT_DEVICE update on ppc and sparc
  fw_cfg: add fw_cfg_modify_i16 (update) method
  QemuOpts: increase number of vm_config_groups

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-10 16:52:35 +01:00
Peter Maydell eed8a8f572 Merge remote-tracking branch 'remotes/awilliam/tags/vfio-update-20150609.0' into staging
Initial VFIO platform device support, v2 (Eric Auger, et al.)

# gpg: Signature made Tue Jun  9 15:25:40 2015 BST using RSA key ID 3BB08B22
# gpg: Good signature from "Alex Williamson <alex.williamson@redhat.com>"
# gpg:                 aka "Alex Williamson <alex@shazbot.org>"
# gpg:                 aka "Alex Williamson <alwillia@redhat.com>"
# gpg:                 aka "Alex Williamson <alex.l.williamson@gmail.com>"

* remotes/awilliam/tags/vfio-update-20150609.0:
  hw/vfio/platform: calxeda xgmac device
  hw/vfio/platform: add irq assignment
  hw/vfio/platform: vfio-platform skeleton

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-10 15:46:39 +01:00
Peter Maydell e015fe008a Merge remote-tracking branch 'remotes/stefanha/tags/CVE-2015-3209-pcnet-tx-buffer-fix-pull-request' into staging
# gpg: Signature made Wed Jun 10 15:04:11 2015 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"

* remotes/stefanha/tags/CVE-2015-3209-pcnet-tx-buffer-fix-pull-request:
  pcnet: force the buffer access to be in bounds during tx

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2015-06-10 15:10:14 +01:00
Petr Matousek 9f7c594c00 pcnet: force the buffer access to be in bounds during tx
4096 is the maximum length per TMD and it is also currently the size of
the relay buffer pcnet driver uses for sending the packet data to QEMU
for further processing. With packet spanning multiple TMDs it can
happen that the overall packet size will be bigger than sizeof(buffer),
which results in memory corruption.

Fix this by only allowing to queue maximum sizeof(buffer) bytes.

This is CVE-2015-3209.

[Fixed 3-space indentation to QEMU's 4-space coding standard.
--Stefan]

Signed-off-by: Petr Matousek <pmatouse@redhat.com>
Reported-by: Matt Tait <matttait@google.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2015-06-10 15:03:02 +01:00
Jason Wang 24bfa207ef vhost: put log correctly in vhost_dev_start()
We allocate an dummy log even if the size is zero. So we should put it
unconditionally too.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-10 16:00:08 +02:00
Gabriel L. Somlo 5efed5a172 bios-tables-test: handle false-positive smbios signature matches
It has been reported that sometimes the .rodata section of SeaBIOS,
containing the constant string against which the SMBIOS signature
ends up being compared, also falls within the guest f-segment. In
that case, the test obviously fails, unless we continue searching
for the *real* SMBIOS entry point.

Rather than stopping at the first match for the SMBIOS signature
("_SM_") in the f-segment (0xF0000-0xFFFFF), continue scanning
until either a valid entry point table is found, or the f-segment
has been exhausted.

Reported-by: Bruce Rogers <brogers@suse.com>
Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
Tested-by: Bruce Rogers <brogers@suse.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-10 08:06:47 +02:00
Gabriel L. Somlo 81b2b81062 fw_cfg: insert fw_cfg file blobs via qemu cmdline
Allow user supplied files to be inserted into the fw_cfg
device before starting the guest. Since fw_cfg_add_file()
already disallows duplicate fw_cfg file names, qemu will
exit with an error message if the user supplies multiple
blobs with the same fw_cfg file name, or if a blob name
collides with a fw_cfg name programmatically added from
within the QEMU source code. A warning message will be
printed if the fw_cfg item name does not begin with the
prefix "opt/", which is recommended for external, user
provided blobs.

Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-10 08:06:46 +02:00
Gabriel L. Somlo 0eb973f915 fw_cfg: prohibit insertion of duplicate fw_cfg file names
Exit with an error (instead of simply logging a trace event)
whenever the same fw_cfg file name is added multiple times via
one of the fw_cfg_add_file[_callback]() host-side API calls.

Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-10 08:00:37 +02:00
Gabriel L. Somlo 0f9b214139 fw_cfg: prevent selector key conflict
Enforce a single assignment of data for each distinct selector key.

Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-10 08:00:37 +02:00
Gabriel L. Somlo 023e314856 fw_cfg: remove support for guest-side data writes
From this point forward, any guest-side writes to the fw_cfg
data register will be treated as no-ops. This patch also removes
the unused host-side API function fw_cfg_add_callback(), which
allowed the registration of a callback to be executed each time
the guest completed a full overwrite of a given fw_cfg data item.

Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-10 08:00:37 +02:00
Gabriel L. Somlo 48779e5018 fw_cfg: fix FW_CFG_BOOT_DEVICE update on ppc and sparc
On ppc, sparc, and sparc64, the value of the FW_CFG_BOOT_DEVICE 16bit
fw_cfg entry is repeatedly modified from a series of callbacks, which
currently results in the previous value's dynamically allocated memory
being leaked.

This patch switches updating to the new fw_cfg_modify_i16() call, which
does not cause memory leaks.

Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-10 08:00:37 +02:00
Gabriel L. Somlo 1edd34b638 fw_cfg: add fw_cfg_modify_i16 (update) method
Allow the ability to modify the value of an existing 16-bit integer
fw_cfg item.

Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-10 08:00:37 +02:00
Gerd Hoffmann 1ceaefbd0d QemuOpts: increase number of vm_config_groups
Adding the fw_cfg cmd line support patch by
Gabriel L. Somlo hits the limit.

Fix this by making the array larger.

Cc: Gabriel L. Somlo <somlo@cmu.edu>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-10 08:00:37 +02:00
Eric Auger 7a8d15d770 hw/vfio/platform: calxeda xgmac device
The platform device class has become abstract. This patch introduces
a calxeda xgmac device that derives from it.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
2015-06-09 08:17:17 -06:00
Alberto Garcia 08d49df0db sdl2: fix crash in handle_windowevent() when restoring the screen size
The Ctrl-Alt-u keyboard shortcut restores the screen to its original
size. In the SDL2 UI this is done by destroying the window and
creating a new one. The old window emits SDL_WINDOWEVENT_HIDDEN when
it's destroyed, but trying to call SDL_GetWindowFromID() from that
event's window ID returns a null pointer. handle_windowevent() assumes
that the pointer is never null so it results in a crash.

Cc: qemu-stable@nongnu.org
Signed-off-by: Alberto Garcia <berto@igalia.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2015-06-09 10:25:21 +02:00
Eric Auger 38559979bf hw/vfio/platform: add irq assignment
This patch adds the code requested to assign interrupts to
a guest. The interrupts are mediated through user handled
eventfds only.

Signed-off-by: Eric Auger <eric.auger@linaro.org>
Tested-by: Vikram Sethi <vikrams@codeaurora.org>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
2015-06-08 09:25:26 -06:00
Eric Auger 0ea2730bef hw/vfio/platform: vfio-platform skeleton
Minimal VFIO platform implementation supporting register space
user mapping but not IRQ assignment.

Signed-off-by: Kim Phillips <kim.phillips@linaro.org>
Signed-off-by: Eric Auger <eric.auger@linaro.org>
Tested-by: Vikram Sethi <vikrams@codeaurora.org>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
2015-06-08 09:25:25 -06:00
189 changed files with 7724 additions and 6478 deletions
-3
View File
@@ -770,7 +770,6 @@ F: hw/net/rocker/
Subsystems
----------
Audio
M: Vassili Karpov (malc) <av1474@comtv.ru>
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
F: audio/
@@ -1014,8 +1013,6 @@ M: Amit Shah <amit.shah@redhat.com>
S: Maintained
F: include/migration/
F: migration/
F: savevm.c
F: arch_init.c
F: scripts/vmstate-static-checker.py
F: tests/vmstate-static-checker-data/
+2 -1
View File
@@ -132,9 +132,10 @@ obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o
obj-y += qtest.o bootdevice.o
obj-y += hw/
obj-$(CONFIG_KVM) += kvm-all.o
obj-y += memory.o savevm.o cputlb.o
obj-y += memory.o cputlb.o
obj-y += memory_mapping.o
obj-y += dump.o
obj-y += migration/ram.o migration/savevm.o
LIBS := $(libs_softmmu) $(LIBS)
# xen support
-1611
View File
File diff suppressed because it is too large Load Diff
-4
View File
@@ -5,13 +5,9 @@ common-obj-$(CONFIG_SPICE) += spiceaudio.o
common-obj-$(CONFIG_COREAUDIO) += coreaudio.o
common-obj-$(CONFIG_ALSA) += alsaaudio.o
common-obj-$(CONFIG_DSOUND) += dsoundaudio.o
common-obj-$(CONFIG_FMOD) += fmodaudio.o
common-obj-$(CONFIG_ESD) += esdaudio.o
common-obj-$(CONFIG_PA) += paaudio.o
common-obj-$(CONFIG_WINWAVE) += winwaveaudio.o
common-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
common-obj-y += wavcapture.o
$(obj)/audio.o $(obj)/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
sdlaudio.o-cflags := $(SDL_CFLAGS)
+83 -112
View File
@@ -25,6 +25,7 @@
#include "qemu-common.h"
#include "qemu/main-loop.h"
#include "audio.h"
#include "trace.h"
#if QEMU_GNUC_PREREQ(4, 3)
#pragma GCC diagnostic ignored "-Waddress"
@@ -33,9 +34,28 @@
#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;
};
@@ -56,30 +76,6 @@ typedef struct ALSAVoiceIn {
struct pollhlp pollhlp;
} ALSAVoiceIn;
static struct {
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;
int verbose;
} conf = {
.buffer_size_out = 4096,
.period_size_out = 1024,
.pcm_name_out = "default",
.pcm_name_in = "default",
};
struct alsa_params_req {
int freq;
snd_pcm_format_t fmt;
@@ -205,9 +201,7 @@ static void alsa_poll_handler (void *opaque)
}
if (!(revents & hlp->mask)) {
if (conf.verbose) {
dolog ("revents = %d\n", revents);
}
trace_alsa_revents(revents);
return;
}
@@ -266,31 +260,14 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
for (i = 0; i < count; ++i) {
if (pfds[i].events & POLLIN) {
err = qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler,
NULL, hlp);
qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler, NULL, hlp);
}
if (pfds[i].events & POLLOUT) {
if (conf.verbose) {
dolog ("POLLOUT %d %d\n", i, pfds[i].fd);
}
err = qemu_set_fd_handler (pfds[i].fd, NULL,
alsa_poll_handler, hlp);
}
if (conf.verbose) {
dolog ("Set handler events=%#x index=%d fd=%d err=%d\n",
pfds[i].events, i, pfds[i].fd, err);
trace_alsa_pollout(i, pfds[i].fd);
qemu_set_fd_handler (pfds[i].fd, NULL, alsa_poll_handler, hlp);
}
trace_alsa_set_handler(pfds[i].events, i, pfds[i].fd, err);
if (err) {
dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n",
pfds[i].events, i, pfds[i].fd, err);
while (i--) {
qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
}
g_free (pfds);
return -1;
}
}
hlp->pfds = pfds;
hlp->count = count;
@@ -476,14 +453,15 @@ 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)
struct alsa_params_obt *obt, snd_pcm_t **handlep,
ALSAConf *conf)
{
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 = in ? conf->pcm_name_in : conf->pcm_name_out;
snd_pcm_uframes_t obt_buffer_size;
const char *typ = in ? "ADC" : "DAC";
snd_pcm_format_t obtfmt;
@@ -522,7 +500,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
}
err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
if (err < 0 && conf.verbose) {
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
}
@@ -654,7 +632,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
if (!in && conf.threshold) {
if (!in && conf->threshold) {
snd_pcm_uframes_t threshold;
int bytes_per_sec;
@@ -676,7 +654,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
break;
}
threshold = (conf.threshold * bytes_per_sec) / 1000;
threshold = (conf->threshold * bytes_per_sec) / 1000;
alsa_set_threshold (handle, threshold);
}
@@ -686,10 +664,9 @@ static int alsa_open (int in, struct alsa_params_req *req,
*handlep = handle;
if (conf.verbose &&
(obtfmt != req->fmt ||
if (obtfmt != req->fmt ||
obt->nchannels != req->nchannels ||
obt->freq != req->freq)) {
obt->freq != req->freq) {
dolog ("Audio parameters for %s\n", typ);
alsa_dump_info (req, obt, obtfmt);
}
@@ -743,9 +720,7 @@ static void alsa_write_pending (ALSAVoiceOut *alsa)
if (written <= 0) {
switch (written) {
case 0:
if (conf.verbose) {
dolog ("Failed to write %d frames (wrote zero)\n", len);
}
trace_alsa_wrote_zero(len);
return;
case -EPIPE:
@@ -754,9 +729,7 @@ static void alsa_write_pending (ALSAVoiceOut *alsa)
len);
return;
}
if (conf.verbose) {
dolog ("Recovering from playback xrun\n");
}
trace_alsa_xrun_out();
continue;
case -ESTRPIPE:
@@ -767,9 +740,7 @@ static void alsa_write_pending (ALSAVoiceOut *alsa)
len);
return;
}
if (conf.verbose) {
dolog ("Resuming suspended output stream\n");
}
trace_alsa_resume_out();
continue;
case -EAGAIN:
@@ -819,25 +790,27 @@ static void alsa_fini_out (HWVoiceOut *hw)
alsa->pcm_buf = NULL;
}
static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
struct alsa_params_req req;
struct alsa_params_obt obt;
snd_pcm_t *handle;
struct audsettings obt_as;
ALSAConf *conf = drv_opaque;
req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
req.freq = as->freq;
req.nchannels = as->nchannels;
req.period_size = conf.period_size_out;
req.buffer_size = conf.buffer_size_out;
req.size_in_usec = conf.size_in_usec_out;
req.period_size = conf->period_size_out;
req.buffer_size = conf->buffer_size_out;
req.size_in_usec = conf->size_in_usec_out;
req.override_mask =
(conf.period_size_out_overridden ? 1 : 0) |
(conf.buffer_size_out_overridden ? 2 : 0);
(conf->period_size_out_overridden ? 1 : 0) |
(conf->buffer_size_out_overridden ? 2 : 0);
if (alsa_open (0, &req, &obt, &handle)) {
if (alsa_open (0, &req, &obt, &handle, conf)) {
return -1;
}
@@ -858,6 +831,7 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
}
alsa->handle = handle;
alsa->pollhlp.conf = conf;
return 0;
}
@@ -928,25 +902,26 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
return -1;
}
static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
struct alsa_params_req req;
struct alsa_params_obt obt;
snd_pcm_t *handle;
struct audsettings obt_as;
ALSAConf *conf = drv_opaque;
req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
req.freq = as->freq;
req.nchannels = as->nchannels;
req.period_size = conf.period_size_in;
req.buffer_size = conf.buffer_size_in;
req.size_in_usec = conf.size_in_usec_in;
req.period_size = conf->period_size_in;
req.buffer_size = conf->buffer_size_in;
req.size_in_usec = conf->size_in_usec_in;
req.override_mask =
(conf.period_size_in_overridden ? 1 : 0) |
(conf.buffer_size_in_overridden ? 2 : 0);
(conf->period_size_in_overridden ? 1 : 0) |
(conf->buffer_size_in_overridden ? 2 : 0);
if (alsa_open (1, &req, &obt, &handle)) {
if (alsa_open (1, &req, &obt, &handle, conf)) {
return -1;
}
@@ -967,6 +942,7 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
}
alsa->handle = handle;
alsa->pollhlp.conf = conf;
return 0;
}
@@ -1022,14 +998,10 @@ static int alsa_run_in (HWVoiceIn *hw)
dolog ("Failed to resume suspended input stream\n");
return 0;
}
if (conf.verbose) {
dolog ("Resuming suspended input stream\n");
}
trace_alsa_resume_in();
break;
default:
if (conf.verbose) {
dolog ("No frames available and ALSA state is %d\n", state);
}
trace_alsa_no_frames(state);
return 0;
}
}
@@ -1064,9 +1036,7 @@ static int alsa_run_in (HWVoiceIn *hw)
if (nread <= 0) {
switch (nread) {
case 0:
if (conf.verbose) {
dolog ("Failed to read %ld frames (read zero)\n", len);
}
trace_alsa_read_zero(len);
goto exit;
case -EPIPE:
@@ -1074,9 +1044,7 @@ static int alsa_run_in (HWVoiceIn *hw)
alsa_logerr (nread, "Failed to read %ld frames\n", len);
goto exit;
}
if (conf.verbose) {
dolog ("Recovering from capture xrun\n");
}
trace_alsa_xrun_in();
continue;
case -EAGAIN:
@@ -1148,82 +1116,85 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
return -1;
}
static ALSAConf glob_conf = {
.buffer_size_out = 4096,
.period_size_out = 1024,
.pcm_name_out = "default",
.pcm_name_in = "default",
};
static void *alsa_audio_init (void)
{
return &conf;
ALSAConf *conf = g_malloc(sizeof(ALSAConf));
*conf = glob_conf;
return conf;
}
static void alsa_audio_fini (void *opaque)
{
(void) opaque;
g_free(opaque);
}
static struct audio_option alsa_options[] = {
{
.name = "DAC_SIZE_IN_USEC",
.tag = AUD_OPT_BOOL,
.valp = &conf.size_in_usec_out,
.valp = &glob_conf.size_in_usec_out,
.descr = "DAC period/buffer size in microseconds (otherwise in frames)"
},
{
.name = "DAC_PERIOD_SIZE",
.tag = AUD_OPT_INT,
.valp = &conf.period_size_out,
.valp = &glob_conf.period_size_out,
.descr = "DAC period size (0 to go with system default)",
.overriddenp = &conf.period_size_out_overridden
.overriddenp = &glob_conf.period_size_out_overridden
},
{
.name = "DAC_BUFFER_SIZE",
.tag = AUD_OPT_INT,
.valp = &conf.buffer_size_out,
.valp = &glob_conf.buffer_size_out,
.descr = "DAC buffer size (0 to go with system default)",
.overriddenp = &conf.buffer_size_out_overridden
.overriddenp = &glob_conf.buffer_size_out_overridden
},
{
.name = "ADC_SIZE_IN_USEC",
.tag = AUD_OPT_BOOL,
.valp = &conf.size_in_usec_in,
.valp = &glob_conf.size_in_usec_in,
.descr =
"ADC period/buffer size in microseconds (otherwise in frames)"
},
{
.name = "ADC_PERIOD_SIZE",
.tag = AUD_OPT_INT,
.valp = &conf.period_size_in,
.valp = &glob_conf.period_size_in,
.descr = "ADC period size (0 to go with system default)",
.overriddenp = &conf.period_size_in_overridden
.overriddenp = &glob_conf.period_size_in_overridden
},
{
.name = "ADC_BUFFER_SIZE",
.tag = AUD_OPT_INT,
.valp = &conf.buffer_size_in,
.valp = &glob_conf.buffer_size_in,
.descr = "ADC buffer size (0 to go with system default)",
.overriddenp = &conf.buffer_size_in_overridden
.overriddenp = &glob_conf.buffer_size_in_overridden
},
{
.name = "THRESHOLD",
.tag = AUD_OPT_INT,
.valp = &conf.threshold,
.valp = &glob_conf.threshold,
.descr = "(undocumented)"
},
{
.name = "DAC_DEV",
.tag = AUD_OPT_STR,
.valp = &conf.pcm_name_out,
.valp = &glob_conf.pcm_name_out,
.descr = "DAC device name (for instance dmix)"
},
{
.name = "ADC_DEV",
.tag = AUD_OPT_STR,
.valp = &conf.pcm_name_in,
.valp = &glob_conf.pcm_name_in,
.descr = "ADC device name"
},
{
.name = "VERBOSE",
.tag = AUD_OPT_BOOL,
.valp = &conf.verbose,
.descr = "Behave in a more verbose way"
},
{ /* End of list */ }
};
+3 -32
View File
@@ -30,7 +30,6 @@
#define AUDIO_CAP "audio"
#include "audio_int.h"
/* #define DEBUG_PLIVE */
/* #define DEBUG_LIVE */
/* #define DEBUG_OUT */
/* #define DEBUG_CAPTURE */
@@ -66,8 +65,6 @@ static struct {
int hertz;
int64_t ticks;
} period;
int plive;
int log_to_monitor;
int try_poll_in;
int try_poll_out;
} conf = {
@@ -96,8 +93,6 @@ static struct {
},
.period = { .hertz = 100 },
.plive = 0,
.log_to_monitor = 0,
.try_poll_in = 1,
.try_poll_out = 1,
};
@@ -331,20 +326,11 @@ static const char *audio_get_conf_str (const char *key,
void AUD_vlog (const char *cap, const char *fmt, va_list ap)
{
if (conf.log_to_monitor) {
if (cap) {
monitor_printf(default_mon, "%s: ", cap);
}
monitor_vprintf(default_mon, fmt, ap);
if (cap) {
fprintf(stderr, "%s: ", cap);
}
else {
if (cap) {
fprintf (stderr, "%s: ", cap);
}
vfprintf (stderr, fmt, ap);
}
vfprintf(stderr, fmt, ap);
}
void AUD_log (const char *cap, const char *fmt, ...)
@@ -1454,9 +1440,6 @@ static void audio_run_out (AudioState *s)
while (sw) {
sw1 = sw->entries.le_next;
if (!sw->active && !sw->callback.fn) {
#ifdef DEBUG_PLIVE
dolog ("Finishing with old voice\n");
#endif
audio_close_out (sw);
}
sw = sw1;
@@ -1648,18 +1631,6 @@ static struct audio_option audio_options[] = {
.valp = &conf.period.hertz,
.descr = "Timer period in HZ (0 - use lowest possible)"
},
{
.name = "PLIVE",
.tag = AUD_OPT_BOOL,
.valp = &conf.plive,
.descr = "(undocumented)"
},
{
.name = "LOG_TO_MONITOR",
.tag = AUD_OPT_BOOL,
.valp = &conf.log_to_monitor,
.descr = "Print logging messages to monitor instead of stderr"
},
{ /* End of list */ }
};
+2 -5
View File
@@ -156,13 +156,13 @@ struct audio_driver {
};
struct audio_pcm_ops {
int (*init_out)(HWVoiceOut *hw, struct audsettings *as);
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);
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);
@@ -206,14 +206,11 @@ extern struct audio_driver no_audio_driver;
extern struct audio_driver oss_audio_driver;
extern struct audio_driver sdl_audio_driver;
extern struct audio_driver wav_audio_driver;
extern struct audio_driver fmod_audio_driver;
extern struct audio_driver alsa_audio_driver;
extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern struct audio_driver esd_audio_driver;
extern struct audio_driver pa_audio_driver;
extern struct audio_driver spice_audio_driver;
extern struct audio_driver winwave_audio_driver;
extern const struct mixeng_volume nominal_volume;
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
+1 -42
View File
@@ -262,7 +262,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
#ifdef DAC
QLIST_INIT (&hw->cap_head);
#endif
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
if (glue (hw->pcm_ops->init_, TYPE) (hw, as, s->drv_opaque)) {
goto err0;
}
@@ -398,10 +398,6 @@ SW *glue (AUD_open_, TYPE) (
)
{
AudioState *s = &glob_audio_state;
#ifdef DAC
int live = 0;
SW *old_sw = NULL;
#endif
if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) {
dolog ("card=%p name=%p callback_fn=%p as=%p\n",
@@ -426,29 +422,6 @@ SW *glue (AUD_open_, TYPE) (
return sw;
}
#ifdef DAC
if (conf.plive && sw && (!sw->active && !sw->empty)) {
live = sw->total_hw_samples_mixed;
#ifdef DEBUG_PLIVE
dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live);
dolog ("Old %s freq %d, bits %d, channels %d\n",
SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels);
dolog ("New %s freq %d, bits %d, channels %d\n",
name,
as->freq,
(as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) ? 16 : 8,
as->nchannels);
#endif
if (live) {
old_sw = sw;
old_sw->callback.fn = NULL;
sw = NULL;
}
}
#endif
if (!glue (conf.fixed_, TYPE).enabled && sw) {
glue (AUD_close_, TYPE) (card, sw);
sw = NULL;
@@ -481,20 +454,6 @@ SW *glue (AUD_open_, TYPE) (
sw->callback.fn = callback_fn;
sw->callback.opaque = callback_opaque;
#ifdef DAC
if (live) {
int mixed =
(live << old_sw->info.shift)
* old_sw->info.bytes_per_second
/ sw->info.bytes_per_second;
#ifdef DEBUG_PLIVE
dolog ("Silence will be mixed %d\n", mixed);
#endif
sw->total_hw_samples_mixed += mixed;
}
#endif
#ifdef DEBUG_AUDIO
dolog ("%s\n", name);
audio_pcm_print_info ("hw", &sw->hw->info);
+26 -20
View File
@@ -32,20 +32,16 @@
#define AUDIO_CAP "coreaudio"
#include "audio_int.h"
struct {
static int isAtexit;
typedef struct {
int buffer_frames;
int nbuffers;
int isAtexit;
} conf = {
.buffer_frames = 512,
.nbuffers = 4,
.isAtexit = 0
};
} CoreaudioConf;
typedef struct coreaudioVoiceOut {
HWVoiceOut hw;
pthread_mutex_t mutex;
int isAtexit;
AudioDeviceID outputDeviceID;
UInt32 audioDevicePropertyBufferFrameSize;
AudioStreamBasicDescription outputStreamBasicDescription;
@@ -161,7 +157,7 @@ static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
static void coreaudio_atexit (void)
{
conf.isAtexit = 1;
isAtexit = 1;
}
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
@@ -287,7 +283,8 @@ 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)
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
OSStatus status;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
@@ -295,6 +292,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
int err;
const char *typ = "playback";
AudioValueRange frameRange;
CoreaudioConf *conf = drv_opaque;
/* create mutex */
err = pthread_mutex_init(&core->mutex, NULL);
@@ -336,16 +334,16 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
return -1;
}
if (frameRange.mMinimum > conf.buffer_frames) {
if (frameRange.mMinimum > conf->buffer_frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
}
else if (frameRange.mMaximum < conf.buffer_frames) {
else if (frameRange.mMaximum < conf->buffer_frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
}
else {
core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
core->audioDevicePropertyBufferFrameSize = conf->buffer_frames;
}
/* set Buffer Frame Size */
@@ -379,7 +377,7 @@ static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
"Could not get device buffer frame size\n");
return -1;
}
hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
/* get StreamFormat */
propertySize = sizeof(core->outputStreamBasicDescription);
@@ -443,7 +441,7 @@ static void coreaudio_fini_out (HWVoiceOut *hw)
int err;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
if (!conf.isAtexit) {
if (!isAtexit) {
/* stop playback */
if (isPlaying(core->outputDeviceID)) {
status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
@@ -486,7 +484,7 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
case VOICE_DISABLE:
/* stop playback */
if (!conf.isAtexit) {
if (!isAtexit) {
if (isPlaying(core->outputDeviceID)) {
status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
@@ -499,28 +497,36 @@ static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
static CoreaudioConf glob_conf = {
.buffer_frames = 512,
.nbuffers = 4,
};
static void *coreaudio_audio_init (void)
{
CoreaudioConf *conf = g_malloc(sizeof(CoreaudioConf));
*conf = glob_conf;
atexit(coreaudio_atexit);
return &coreaudio_audio_init;
return conf;
}
static void coreaudio_audio_fini (void *opaque)
{
(void) opaque;
g_free(opaque);
}
static struct audio_option coreaudio_options[] = {
{
.name = "BUFFER_SIZE",
.tag = AUD_OPT_INT,
.valp = &conf.buffer_frames,
.valp = &glob_conf.buffer_frames,
.descr = "Size of the buffer in frames"
},
{
.name = "BUFFER_COUNT",
.tag = AUD_OPT_INT,
.valp = &conf.nbuffers,
.valp = &glob_conf.nbuffers,
.descr = "Number of buffers"
},
{ /* End of list */ }
+18 -33
View File
@@ -67,11 +67,11 @@ static int glue (dsound_lock_, TYPE) (
LPVOID *p2p,
DWORD *blen1p,
DWORD *blen2p,
int entire
int entire,
dsound *s
)
{
HRESULT hr;
int i;
LPVOID p1 = NULL, p2 = NULL;
DWORD blen1 = 0, blen2 = 0;
DWORD flag;
@@ -81,37 +81,18 @@ static int glue (dsound_lock_, TYPE) (
#else
flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
#endif
for (i = 0; i < conf.lock_retries; ++i) {
hr = glue (IFACE, _Lock) (
buf,
pos,
len,
&p1,
&blen1,
&p2,
&blen2,
flag
);
hr = glue(IFACE, _Lock)(buf, pos, len, &p1, &blen1, &p2, &blen2, flag);
if (FAILED (hr)) {
if (FAILED (hr)) {
#ifndef DSBTYPE_IN
if (hr == DSERR_BUFFERLOST) {
if (glue (dsound_restore_, TYPE) (buf)) {
dsound_logerr (hr, "Could not lock " NAME "\n");
goto fail;
}
continue;
if (hr == DSERR_BUFFERLOST) {
if (glue (dsound_restore_, TYPE) (buf, s)) {
dsound_logerr (hr, "Could not lock " NAME "\n");
}
#endif
dsound_logerr (hr, "Could not lock " NAME "\n");
goto fail;
}
break;
}
if (i == conf.lock_retries) {
dolog ("%d attempts to lock " NAME " failed\n", i);
#endif
dsound_logerr (hr, "Could not lock " NAME "\n");
goto fail;
}
@@ -174,16 +155,19 @@ static void dsound_fini_out (HWVoiceOut *hw)
}
#ifdef DSBTYPE_IN
static int dsound_init_in (HWVoiceIn *hw, struct audsettings *as)
static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as,
void *drv_opaque)
#else
static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
#endif
{
int err;
HRESULT hr;
dsound *s = &glob_dsound;
dsound *s = drv_opaque;
WAVEFORMATEX wfx;
struct audsettings obt_as;
DSoundConf *conf = &s->conf;
#ifdef DSBTYPE_IN
const char *typ = "ADC";
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
@@ -210,7 +194,7 @@ static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
bd.dwSize = sizeof (bd);
bd.lpwfxFormat = &wfx;
#ifdef DSBTYPE_IN
bd.dwBufferBytes = conf.bufsize_in;
bd.dwBufferBytes = conf->bufsize_in;
hr = IDirectSoundCapture_CreateCaptureBuffer (
s->dsound_capture,
&bd,
@@ -219,7 +203,7 @@ static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
);
#else
bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
bd.dwBufferBytes = conf.bufsize_out;
bd.dwBufferBytes = conf->bufsize_out;
hr = IDirectSound_CreateSoundBuffer (
s->dsound,
&bd,
@@ -269,6 +253,7 @@ static int dsound_init_out (HWVoiceOut *hw, struct audsettings *as)
);
}
hw->samples = bc.dwBufferBytes >> hw->info.shift;
ds->s = s;
#ifdef DEBUG_DSOUND
dolog ("caps %ld, desc %ld\n",
+56 -182
View File
@@ -41,42 +41,25 @@
/* #define DEBUG_DSOUND */
static struct {
int lock_retries;
int restore_retries;
int getstatus_retries;
int set_primary;
typedef struct {
int bufsize_in;
int bufsize_out;
struct audsettings settings;
int latency_millis;
} conf = {
.lock_retries = 1,
.restore_retries = 1,
.getstatus_retries = 1,
.set_primary = 0,
.bufsize_in = 16384,
.bufsize_out = 16384,
.settings.freq = 44100,
.settings.nchannels = 2,
.settings.fmt = AUD_FMT_S16,
.latency_millis = 10
};
} DSoundConf;
typedef struct {
LPDIRECTSOUND dsound;
LPDIRECTSOUNDCAPTURE dsound_capture;
LPDIRECTSOUNDBUFFER dsound_primary_buffer;
struct audsettings settings;
DSoundConf conf;
} dsound;
static dsound glob_dsound;
typedef struct {
HWVoiceOut hw;
LPDIRECTSOUNDBUFFER dsound_buffer;
DWORD old_pos;
int first_time;
dsound *s;
#ifdef DEBUG_DSOUND
DWORD old_ppos;
DWORD played;
@@ -88,6 +71,7 @@ typedef struct {
HWVoiceIn hw;
int first_time;
LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
dsound *s;
} DSoundVoiceIn;
static void dsound_log_hresult (HRESULT hr)
@@ -281,29 +265,17 @@ static void print_wave_format (WAVEFORMATEX *wfx)
}
#endif
static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb, dsound *s)
{
HRESULT hr;
int i;
for (i = 0; i < conf.restore_retries; ++i) {
hr = IDirectSoundBuffer_Restore (dsb);
hr = IDirectSoundBuffer_Restore (dsb);
switch (hr) {
case DS_OK:
return 0;
case DSERR_BUFFERLOST:
continue;
default:
dsound_logerr (hr, "Could not restore playback buffer\n");
return -1;
}
if (hr != DS_OK) {
dsound_logerr (hr, "Could not restore playback buffer\n");
return -1;
}
dolog ("%d attempts to restore playback buffer failed\n", i);
return -1;
return 0;
}
#include "dsound_template.h"
@@ -311,25 +283,20 @@ static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
#include "dsound_template.h"
#undef DSBTYPE_IN
static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp)
static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp,
dsound *s)
{
HRESULT hr;
int i;
for (i = 0; i < conf.getstatus_retries; ++i) {
hr = IDirectSoundBuffer_GetStatus (dsb, statusp);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not get playback buffer status\n");
return -1;
}
hr = IDirectSoundBuffer_GetStatus (dsb, statusp);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not get playback buffer status\n");
return -1;
}
if (*statusp & DSERR_BUFFERLOST) {
if (dsound_restore_out (dsb)) {
return -1;
}
continue;
}
break;
if (*statusp & DSERR_BUFFERLOST) {
dsound_restore_out(dsb, s);
return -1;
}
return 0;
@@ -376,7 +343,8 @@ static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
hw->rpos = pos % hw->samples;
}
static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb)
static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb,
dsound *s)
{
int err;
LPVOID p1, p2;
@@ -389,7 +357,8 @@ static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb)
hw->samples << hw->info.shift,
&p1, &p2,
&blen1, &blen2,
1
1,
s
);
if (err) {
return;
@@ -415,25 +384,9 @@ static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb)
dsound_unlock_out (dsb, p1, p2, blen1, blen2);
}
static void dsound_close (dsound *s)
{
HRESULT hr;
if (s->dsound_primary_buffer) {
hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not release primary buffer\n");
}
s->dsound_primary_buffer = NULL;
}
}
static int dsound_open (dsound *s)
{
int err;
HRESULT hr;
WAVEFORMATEX wfx;
DSBUFFERDESC dsbd;
HWND hwnd;
hwnd = GetForegroundWindow ();
@@ -449,63 +402,7 @@ static int dsound_open (dsound *s)
return -1;
}
if (!conf.set_primary) {
return 0;
}
err = waveformat_from_audio_settings (&wfx, &conf.settings);
if (err) {
return -1;
}
memset (&dsbd, 0, sizeof (dsbd));
dsbd.dwSize = sizeof (dsbd);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = NULL;
hr = IDirectSound_CreateSoundBuffer (
s->dsound,
&dsbd,
&s->dsound_primary_buffer,
NULL
);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not create primary playback buffer\n");
return -1;
}
hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not set primary playback buffer format\n");
}
hr = IDirectSoundBuffer_GetFormat (
s->dsound_primary_buffer,
&wfx,
sizeof (wfx),
NULL
);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not get primary playback buffer format\n");
goto fail0;
}
#ifdef DEBUG_DSOUND
dolog ("Primary\n");
print_wave_format (&wfx);
#endif
err = waveformat_to_audio_settings (&wfx, &s->settings);
if (err) {
goto fail0;
}
return 0;
fail0:
dsound_close (s);
return -1;
}
static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
@@ -514,6 +411,7 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
DWORD status;
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
dsound *s = ds->s;
if (!dsb) {
dolog ("Attempt to control voice without a buffer\n");
@@ -522,7 +420,7 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
switch (cmd) {
case VOICE_ENABLE:
if (dsound_get_status_out (dsb, &status)) {
if (dsound_get_status_out (dsb, &status, s)) {
return -1;
}
@@ -531,7 +429,7 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
dsound_clear_sample (hw, dsb);
dsound_clear_sample (hw, dsb, s);
hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING);
if (FAILED (hr)) {
@@ -541,7 +439,7 @@ static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
break;
case VOICE_DISABLE:
if (dsound_get_status_out (dsb, &status)) {
if (dsound_get_status_out (dsb, &status, s)) {
return -1;
}
@@ -578,6 +476,8 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
DWORD wpos, ppos, old_pos;
LPVOID p1, p2;
int bufsize;
dsound *s = ds->s;
DSoundConf *conf = &s->conf;
if (!dsb) {
dolog ("Attempt to run empty with playback buffer\n");
@@ -600,14 +500,14 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
len = live << hwshift;
if (ds->first_time) {
if (conf.latency_millis) {
if (conf->latency_millis) {
DWORD cur_blat;
cur_blat = audio_ring_dist (wpos, ppos, bufsize);
ds->first_time = 0;
old_pos = wpos;
old_pos +=
millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat;
millis_to_bytes (&hw->info, conf->latency_millis) - cur_blat;
old_pos %= bufsize;
old_pos &= ~hw->info.align;
}
@@ -663,7 +563,8 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
len,
&p1, &p2,
&blen1, &blen2,
0
0,
s
);
if (err) {
return 0;
@@ -766,6 +667,7 @@ static int dsound_run_in (HWVoiceIn *hw)
DWORD cpos, rpos;
LPVOID p1, p2;
int hwshift;
dsound *s = ds->s;
if (!dscb) {
dolog ("Attempt to run without capture buffer\n");
@@ -820,7 +722,8 @@ static int dsound_run_in (HWVoiceIn *hw)
&p2,
&blen1,
&blen2,
0
0,
s
);
if (err) {
return 0;
@@ -843,12 +746,19 @@ static int dsound_run_in (HWVoiceIn *hw)
return decr;
}
static DSoundConf glob_conf = {
.bufsize_in = 16384,
.bufsize_out = 16384,
.latency_millis = 10
};
static void dsound_audio_fini (void *opaque)
{
HRESULT hr;
dsound *s = opaque;
if (!s->dsound) {
g_free(s);
return;
}
@@ -859,6 +769,7 @@ static void dsound_audio_fini (void *opaque)
s->dsound = NULL;
if (!s->dsound_capture) {
g_free(s);
return;
}
@@ -867,17 +778,21 @@ static void dsound_audio_fini (void *opaque)
dsound_logerr (hr, "Could not release DirectSoundCapture\n");
}
s->dsound_capture = NULL;
g_free(s);
}
static void *dsound_audio_init (void)
{
int err;
HRESULT hr;
dsound *s = &glob_dsound;
dsound *s = g_malloc0(sizeof(dsound));
s->conf = glob_conf;
hr = CoInitialize (NULL);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not initialize COM\n");
g_free(s);
return NULL;
}
@@ -890,6 +805,7 @@ static void *dsound_audio_init (void)
);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not create DirectSound instance\n");
g_free(s);
return NULL;
}
@@ -901,7 +817,7 @@ static void *dsound_audio_init (void)
if (FAILED (hr)) {
dsound_logerr (hr, "Could not release DirectSound\n");
}
s->dsound = NULL;
g_free(s);
return NULL;
}
@@ -938,64 +854,22 @@ static void *dsound_audio_init (void)
}
static struct audio_option dsound_options[] = {
{
.name = "LOCK_RETRIES",
.tag = AUD_OPT_INT,
.valp = &conf.lock_retries,
.descr = "Number of times to attempt locking the buffer"
},
{
.name = "RESTOURE_RETRIES",
.tag = AUD_OPT_INT,
.valp = &conf.restore_retries,
.descr = "Number of times to attempt restoring the buffer"
},
{
.name = "GETSTATUS_RETRIES",
.tag = AUD_OPT_INT,
.valp = &conf.getstatus_retries,
.descr = "Number of times to attempt getting status of the buffer"
},
{
.name = "SET_PRIMARY",
.tag = AUD_OPT_BOOL,
.valp = &conf.set_primary,
.descr = "Set the parameters of primary buffer"
},
{
.name = "LATENCY_MILLIS",
.tag = AUD_OPT_INT,
.valp = &conf.latency_millis,
.valp = &glob_conf.latency_millis,
.descr = "(undocumented)"
},
{
.name = "PRIMARY_FREQ",
.tag = AUD_OPT_INT,
.valp = &conf.settings.freq,
.descr = "Primary buffer frequency"
},
{
.name = "PRIMARY_CHANNELS",
.tag = AUD_OPT_INT,
.valp = &conf.settings.nchannels,
.descr = "Primary buffer number of channels (1 - mono, 2 - stereo)"
},
{
.name = "PRIMARY_FMT",
.tag = AUD_OPT_FMT,
.valp = &conf.settings.fmt,
.descr = "Primary buffer format"
},
{
.name = "BUFSIZE_OUT",
.tag = AUD_OPT_INT,
.valp = &conf.bufsize_out,
.valp = &glob_conf.bufsize_out,
.descr = "(undocumented)"
},
{
.name = "BUFSIZE_IN",
.tag = AUD_OPT_INT,
.valp = &conf.bufsize_in,
.valp = &glob_conf.bufsize_in,
.descr = "(undocumented)"
},
{ /* End of list */ }
-557
View File
@@ -1,557 +0,0 @@
/*
* QEMU ESD audio driver
*
* Copyright (c) 2006 Frederick Reeve (brushed up by malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <esd.h>
#include "qemu-common.h"
#include "audio.h"
#define AUDIO_CAP "esd"
#include "audio_int.h"
#include "audio_pt_int.h"
typedef struct {
HWVoiceOut hw;
int done;
int live;
int decr;
int rpos;
void *pcm_buf;
int fd;
struct audio_pt pt;
} ESDVoiceOut;
typedef struct {
HWVoiceIn hw;
int done;
int dead;
int incr;
int wpos;
void *pcm_buf;
int fd;
struct audio_pt pt;
} ESDVoiceIn;
static struct {
int samples;
int divisor;
char *dac_host;
char *adc_host;
} conf = {
.samples = 1024,
.divisor = 2,
};
static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
}
/* playback */
static void *qesd_thread_out (void *arg)
{
ESDVoiceOut *esd = arg;
HWVoiceOut *hw = &esd->hw;
int threshold;
threshold = conf.divisor ? hw->samples / conf.divisor : 0;
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
for (;;) {
int decr, to_mix, rpos;
for (;;) {
if (esd->done) {
goto exit;
}
if (esd->live > threshold) {
break;
}
if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
goto exit;
}
}
decr = to_mix = esd->live;
rpos = hw->rpos;
if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
while (to_mix) {
ssize_t written;
int chunk = audio_MIN (to_mix, hw->samples - rpos);
struct st_sample *src = hw->mix_buf + rpos;
hw->clip (esd->pcm_buf, src, chunk);
again:
written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
if (written == -1) {
if (errno == EINTR || errno == EAGAIN) {
goto again;
}
qesd_logerr (errno, "write failed\n");
return NULL;
}
if (written != chunk << hw->info.shift) {
int wsamples = written >> hw->info.shift;
int wbytes = wsamples << hw->info.shift;
if (wbytes != written) {
dolog ("warning: Misaligned write %d (requested %zd), "
"alignment %d\n",
wbytes, written, hw->info.align + 1);
}
to_mix -= wsamples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
rpos = (rpos + chunk) % hw->samples;
to_mix -= chunk;
}
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
esd->rpos = rpos;
esd->live -= decr;
esd->decr += decr;
}
exit:
audio_pt_unlock (&esd->pt, AUDIO_FUNC);
return NULL;
}
static int qesd_run_out (HWVoiceOut *hw, int live)
{
int decr;
ESDVoiceOut *esd = (ESDVoiceOut *) hw;
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return 0;
}
decr = audio_MIN (live, esd->decr);
esd->decr -= decr;
esd->live = live - decr;
hw->rpos = esd->rpos;
if (esd->live > 0) {
audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
}
else {
audio_pt_unlock (&esd->pt, AUDIO_FUNC);
}
return decr;
}
static int qesd_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
{
ESDVoiceOut *esd = (ESDVoiceOut *) hw;
struct audsettings obt_as = *as;
int esdfmt = ESD_STREAM | ESD_PLAY;
esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
switch (as->fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
esdfmt |= ESD_BITS8;
obt_as.fmt = AUD_FMT_U8;
break;
case AUD_FMT_S32:
case AUD_FMT_U32:
dolog ("Will use 16 instead of 32 bit samples\n");
/* fall through */
case AUD_FMT_S16:
case AUD_FMT_U16:
deffmt:
esdfmt |= ESD_BITS16;
obt_as.fmt = AUD_FMT_S16;
break;
default:
dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
goto deffmt;
}
obt_as.endianness = AUDIO_HOST_ENDIANNESS;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.samples;
esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!esd->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
return -1;
}
esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
if (esd->fd < 0) {
qesd_logerr (errno, "esd_play_stream failed\n");
goto fail1;
}
if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
goto fail2;
}
return 0;
fail2:
if (close (esd->fd)) {
qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
AUDIO_FUNC, esd->fd);
}
esd->fd = -1;
fail1:
g_free (esd->pcm_buf);
esd->pcm_buf = NULL;
return -1;
}
static void qesd_fini_out (HWVoiceOut *hw)
{
void *ret;
ESDVoiceOut *esd = (ESDVoiceOut *) hw;
audio_pt_lock (&esd->pt, AUDIO_FUNC);
esd->done = 1;
audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
if (esd->fd >= 0) {
if (close (esd->fd)) {
qesd_logerr (errno, "failed to close esd socket\n");
}
esd->fd = -1;
}
audio_pt_fini (&esd->pt, AUDIO_FUNC);
g_free (esd->pcm_buf);
esd->pcm_buf = NULL;
}
static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
/* capture */
static void *qesd_thread_in (void *arg)
{
ESDVoiceIn *esd = arg;
HWVoiceIn *hw = &esd->hw;
int threshold;
threshold = conf.divisor ? hw->samples / conf.divisor : 0;
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
for (;;) {
int incr, to_grab, wpos;
for (;;) {
if (esd->done) {
goto exit;
}
if (esd->dead > threshold) {
break;
}
if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
goto exit;
}
}
incr = to_grab = esd->dead;
wpos = hw->wpos;
if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
while (to_grab) {
ssize_t nread;
int chunk = audio_MIN (to_grab, hw->samples - wpos);
void *buf = advance (esd->pcm_buf, wpos);
again:
nread = read (esd->fd, buf, chunk << hw->info.shift);
if (nread == -1) {
if (errno == EINTR || errno == EAGAIN) {
goto again;
}
qesd_logerr (errno, "read failed\n");
return NULL;
}
if (nread != chunk << hw->info.shift) {
int rsamples = nread >> hw->info.shift;
int rbytes = rsamples << hw->info.shift;
if (rbytes != nread) {
dolog ("warning: Misaligned write %d (requested %zd), "
"alignment %d\n",
rbytes, nread, hw->info.align + 1);
}
to_grab -= rsamples;
wpos = (wpos + rsamples) % hw->samples;
break;
}
hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift);
wpos = (wpos + chunk) % hw->samples;
to_grab -= chunk;
}
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return NULL;
}
esd->wpos = wpos;
esd->dead -= incr;
esd->incr += incr;
}
exit:
audio_pt_unlock (&esd->pt, AUDIO_FUNC);
return NULL;
}
static int qesd_run_in (HWVoiceIn *hw)
{
int live, incr, dead;
ESDVoiceIn *esd = (ESDVoiceIn *) hw;
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return 0;
}
live = audio_pcm_hw_get_live_in (hw);
dead = hw->samples - live;
incr = audio_MIN (dead, esd->incr);
esd->incr -= incr;
esd->dead = dead - incr;
hw->wpos = esd->wpos;
if (esd->dead > 0) {
audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
}
else {
audio_pt_unlock (&esd->pt, AUDIO_FUNC);
}
return incr;
}
static int qesd_read (SWVoiceIn *sw, void *buf, int len)
{
return audio_pcm_sw_read (sw, buf, len);
}
static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
{
ESDVoiceIn *esd = (ESDVoiceIn *) hw;
struct audsettings obt_as = *as;
int esdfmt = ESD_STREAM | ESD_RECORD;
esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
switch (as->fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
esdfmt |= ESD_BITS8;
obt_as.fmt = AUD_FMT_U8;
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
esdfmt |= ESD_BITS16;
obt_as.fmt = AUD_FMT_S16;
break;
case AUD_FMT_S32:
case AUD_FMT_U32:
dolog ("Will use 16 instead of 32 bit samples\n");
esdfmt |= ESD_BITS16;
obt_as.fmt = AUD_FMT_S16;
break;
}
obt_as.endianness = AUDIO_HOST_ENDIANNESS;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.samples;
esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!esd->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
return -1;
}
esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
if (esd->fd < 0) {
qesd_logerr (errno, "esd_record_stream failed\n");
goto fail1;
}
if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
goto fail2;
}
return 0;
fail2:
if (close (esd->fd)) {
qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
AUDIO_FUNC, esd->fd);
}
esd->fd = -1;
fail1:
g_free (esd->pcm_buf);
esd->pcm_buf = NULL;
return -1;
}
static void qesd_fini_in (HWVoiceIn *hw)
{
void *ret;
ESDVoiceIn *esd = (ESDVoiceIn *) hw;
audio_pt_lock (&esd->pt, AUDIO_FUNC);
esd->done = 1;
audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
if (esd->fd >= 0) {
if (close (esd->fd)) {
qesd_logerr (errno, "failed to close esd socket\n");
}
esd->fd = -1;
}
audio_pt_fini (&esd->pt, AUDIO_FUNC);
g_free (esd->pcm_buf);
esd->pcm_buf = NULL;
}
static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
/* common */
static void *qesd_audio_init (void)
{
return &conf;
}
static void qesd_audio_fini (void *opaque)
{
(void) opaque;
ldebug ("esd_fini");
}
struct audio_option qesd_options[] = {
{
.name = "SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.samples,
.descr = "buffer size in samples"
},
{
.name = "DIVISOR",
.tag = AUD_OPT_INT,
.valp = &conf.divisor,
.descr = "threshold divisor"
},
{
.name = "DAC_HOST",
.tag = AUD_OPT_STR,
.valp = &conf.dac_host,
.descr = "playback host"
},
{
.name = "ADC_HOST",
.tag = AUD_OPT_STR,
.valp = &conf.adc_host,
.descr = "capture host"
},
{ /* End of list */ }
};
static struct audio_pcm_ops qesd_pcm_ops = {
.init_out = qesd_init_out,
.fini_out = qesd_fini_out,
.run_out = qesd_run_out,
.write = qesd_write,
.ctl_out = qesd_ctl_out,
.init_in = qesd_init_in,
.fini_in = qesd_fini_in,
.run_in = qesd_run_in,
.read = qesd_read,
.ctl_in = qesd_ctl_in,
};
struct audio_driver esd_audio_driver = {
.name = "esd",
.descr = "http://en.wikipedia.org/wiki/Esound",
.options = qesd_options,
.init = qesd_audio_init,
.fini = qesd_audio_fini,
.pcm_ops = &qesd_pcm_ops,
.can_be_default = 0,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (ESDVoiceOut),
.voice_size_in = sizeof (ESDVoiceIn)
};
-685
View File
@@ -1,685 +0,0 @@
/*
* QEMU FMOD audio driver
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <fmod.h>
#include <fmod_errors.h>
#include "qemu-common.h"
#include "audio.h"
#define AUDIO_CAP "fmod"
#include "audio_int.h"
typedef struct FMODVoiceOut {
HWVoiceOut hw;
unsigned int old_pos;
FSOUND_SAMPLE *fmod_sample;
int channel;
} FMODVoiceOut;
typedef struct FMODVoiceIn {
HWVoiceIn hw;
FSOUND_SAMPLE *fmod_sample;
} FMODVoiceIn;
static struct {
const char *drvname;
int nb_samples;
int freq;
int nb_channels;
int bufsize;
int broken_adc;
} conf = {
.nb_samples = 2048 * 2,
.freq = 44100,
.nb_channels = 2,
};
static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n",
FMOD_ErrorString (FSOUND_GetError ()));
}
static void GCC_FMT_ATTR (2, 3) fmod_logerr2 (
const char *typ,
const char *fmt,
...
)
{
va_list ap;
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n",
FMOD_ErrorString (FSOUND_GetError ()));
}
static int fmod_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static void fmod_clear_sample (FMODVoiceOut *fmd)
{
HWVoiceOut *hw = &fmd->hw;
int status;
void *p1 = 0, *p2 = 0;
unsigned int len1 = 0, len2 = 0;
status = FSOUND_Sample_Lock (
fmd->fmod_sample,
0,
hw->samples << hw->info.shift,
&p1,
&p2,
&len1,
&len2
);
if (!status) {
fmod_logerr ("Failed to lock sample\n");
return;
}
if ((len1 & hw->info.align) || (len2 & hw->info.align)) {
dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
len1, len2, hw->info.align + 1);
goto fail;
}
if ((len1 + len2) - (hw->samples << hw->info.shift)) {
dolog ("Lock returned incomplete length %d, %d\n",
len1 + len2, hw->samples << hw->info.shift);
goto fail;
}
audio_pcm_info_clear_buf (&hw->info, p1, hw->samples);
fail:
status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
if (!status) {
fmod_logerr ("Failed to unlock sample\n");
}
}
static void fmod_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 = dst_len - src_len1;
pos = src_len2;
}
if (src_len1) {
hw->clip (dst, src1, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
}
hw->rpos = pos % hw->samples;
}
static int fmod_unlock_sample (FSOUND_SAMPLE *sample, void *p1, void *p2,
unsigned int blen1, unsigned int blen2)
{
int status = FSOUND_Sample_Unlock (sample, p1, p2, blen1, blen2);
if (!status) {
fmod_logerr ("Failed to unlock sample\n");
return -1;
}
return 0;
}
static int fmod_lock_sample (
FSOUND_SAMPLE *sample,
struct audio_pcm_info *info,
int pos,
int len,
void **p1,
void **p2,
unsigned int *blen1,
unsigned int *blen2
)
{
int status;
status = FSOUND_Sample_Lock (
sample,
pos << info->shift,
len << info->shift,
p1,
p2,
blen1,
blen2
);
if (!status) {
fmod_logerr ("Failed to lock sample\n");
return -1;
}
if ((*blen1 & info->align) || (*blen2 & info->align)) {
dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
*blen1, *blen2, info->align + 1);
fmod_unlock_sample (sample, *p1, *p2, *blen1, *blen2);
*p1 = NULL - 1;
*p2 = NULL - 1;
*blen1 = ~0U;
*blen2 = ~0U;
return -1;
}
if (!*p1 && *blen1) {
dolog ("warning: !p1 && blen1=%d\n", *blen1);
*blen1 = 0;
}
if (!p2 && *blen2) {
dolog ("warning: !p2 && blen2=%d\n", *blen2);
*blen2 = 0;
}
return 0;
}
static int fmod_run_out (HWVoiceOut *hw, int live)
{
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
int decr;
void *p1 = 0, *p2 = 0;
unsigned int blen1 = 0, blen2 = 0;
unsigned int len1 = 0, len2 = 0;
if (!hw->pending_disable) {
return 0;
}
decr = live;
if (fmd->channel >= 0) {
int len = decr;
int old_pos = fmd->old_pos;
int ppos = FSOUND_GetCurrentPosition (fmd->channel);
if (ppos == old_pos || !ppos) {
return 0;
}
if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
len = ppos - old_pos;
}
else {
if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) {
len = hw->samples - old_pos + ppos;
}
}
decr = len;
if (audio_bug (AUDIO_FUNC, decr < 0)) {
dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n",
decr, live, ppos, old_pos, len);
return 0;
}
}
if (!decr) {
return 0;
}
if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
fmd->old_pos, decr,
&p1, &p2,
&blen1, &blen2)) {
return 0;
}
len1 = blen1 >> hw->info.shift;
len2 = blen2 >> hw->info.shift;
ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
decr = len1 + len2;
if (p1 && len1) {
fmod_write_sample (hw, p1, len1);
}
if (p2 && len2) {
fmod_write_sample (hw, p2, len2);
}
fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
return decr;
}
static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
{
int mode = FSOUND_LOOP_NORMAL;
switch (fmt) {
case AUD_FMT_S8:
mode |= FSOUND_SIGNED | FSOUND_8BITS;
break;
case AUD_FMT_U8:
mode |= FSOUND_UNSIGNED | FSOUND_8BITS;
break;
case AUD_FMT_S16:
mode |= FSOUND_SIGNED | FSOUND_16BITS;
break;
case AUD_FMT_U16:
mode |= FSOUND_UNSIGNED | FSOUND_16BITS;
break;
default:
dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_FMOD
abort ();
#endif
mode |= FSOUND_8BITS;
}
mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
return mode;
}
static void fmod_fini_out (HWVoiceOut *hw)
{
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
if (fmd->fmod_sample) {
FSOUND_Sample_Free (fmd->fmod_sample);
fmd->fmod_sample = 0;
if (fmd->channel >= 0) {
FSOUND_StopSound (fmd->channel);
}
}
}
static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
{
int mode, channel;
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
struct audsettings obt_as = *as;
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
FSOUND_FREE, /* index */
conf.nb_samples, /* length */
mode, /* mode */
as->freq, /* freq */
255, /* volume */
128, /* pan */
255 /* priority */
);
if (!fmd->fmod_sample) {
fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n");
return -1;
}
channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
if (channel < 0) {
fmod_logerr2 ("DAC", "Failed to start playing sound\n");
FSOUND_Sample_Free (fmd->fmod_sample);
return -1;
}
fmd->channel = channel;
/* FMOD always operates on little endian frames? */
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.nb_samples;
return 0;
}
static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
int status;
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
switch (cmd) {
case VOICE_ENABLE:
fmod_clear_sample (fmd);
status = FSOUND_SetPaused (fmd->channel, 0);
if (!status) {
fmod_logerr ("Failed to resume channel %d\n", fmd->channel);
}
break;
case VOICE_DISABLE:
status = FSOUND_SetPaused (fmd->channel, 1);
if (!status) {
fmod_logerr ("Failed to pause channel %d\n", fmd->channel);
}
break;
}
return 0;
}
static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
{
int mode;
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
struct audsettings obt_as = *as;
if (conf.broken_adc) {
return -1;
}
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
FSOUND_FREE, /* index */
conf.nb_samples, /* length */
mode, /* mode */
as->freq, /* freq */
255, /* volume */
128, /* pan */
255 /* priority */
);
if (!fmd->fmod_sample) {
fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
return -1;
}
/* FMOD always operates on little endian frames? */
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = conf.nb_samples;
return 0;
}
static void fmod_fini_in (HWVoiceIn *hw)
{
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
if (fmd->fmod_sample) {
FSOUND_Record_Stop ();
FSOUND_Sample_Free (fmd->fmod_sample);
fmd->fmod_sample = 0;
}
}
static int fmod_run_in (HWVoiceIn *hw)
{
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
int hwshift = hw->info.shift;
int live, dead, new_pos, len;
unsigned int blen1 = 0, blen2 = 0;
unsigned int len1, len2;
unsigned int decr;
void *p1, *p2;
live = audio_pcm_hw_get_live_in (hw);
dead = hw->samples - live;
if (!dead) {
return 0;
}
new_pos = FSOUND_Record_GetPosition ();
if (new_pos < 0) {
fmod_logerr ("Could not get recording position\n");
return 0;
}
len = audio_ring_dist (new_pos, hw->wpos, hw->samples);
if (!len) {
return 0;
}
len = audio_MIN (len, dead);
if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
hw->wpos, len,
&p1, &p2,
&blen1, &blen2)) {
return 0;
}
len1 = blen1 >> hwshift;
len2 = blen2 >> hwshift;
decr = len1 + len2;
if (p1 && blen1) {
hw->conv (hw->conv_buf + hw->wpos, p1, len1);
}
if (p2 && len2) {
hw->conv (hw->conv_buf, p2, len2);
}
fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
hw->wpos = (hw->wpos + decr) % hw->samples;
return decr;
}
static struct {
const char *name;
int type;
} drvtab[] = {
{ .name = "none", .type = FSOUND_OUTPUT_NOSOUND },
#ifdef _WIN32
{ .name = "winmm", .type = FSOUND_OUTPUT_WINMM },
{ .name = "dsound", .type = FSOUND_OUTPUT_DSOUND },
{ .name = "a3d", .type = FSOUND_OUTPUT_A3D },
{ .name = "asio", .type = FSOUND_OUTPUT_ASIO },
#endif
#ifdef __linux__
{ .name = "oss", .type = FSOUND_OUTPUT_OSS },
{ .name = "alsa", .type = FSOUND_OUTPUT_ALSA },
{ .name = "esd", .type = FSOUND_OUTPUT_ESD },
#endif
#ifdef __APPLE__
{ .name = "mac", .type = FSOUND_OUTPUT_MAC },
#endif
#if 0
{ .name = "xbox", .type = FSOUND_OUTPUT_XBOX },
{ .name = "ps2", .type = FSOUND_OUTPUT_PS2 },
{ .name = "gcube", .type = FSOUND_OUTPUT_GC },
#endif
{ .name = "none-realtime", .type = FSOUND_OUTPUT_NOSOUND_NONREALTIME }
};
static void *fmod_audio_init (void)
{
size_t i;
double ver;
int status;
int output_type = -1;
const char *drv = conf.drvname;
ver = FSOUND_GetVersion ();
if (ver < FMOD_VERSION) {
dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
return NULL;
}
#ifdef __linux__
if (ver < 3.75) {
dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
"ADC will be disabled.\n");
conf.broken_adc = 1;
}
#endif
if (drv) {
int found = 0;
for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
if (!strcmp (drv, drvtab[i].name)) {
output_type = drvtab[i].type;
found = 1;
break;
}
}
if (!found) {
dolog ("Unknown FMOD driver `%s'\n", drv);
dolog ("Valid drivers:\n");
for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
dolog (" %s\n", drvtab[i].name);
}
}
}
if (output_type != -1) {
status = FSOUND_SetOutput (output_type);
if (!status) {
fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type);
return NULL;
}
}
if (conf.bufsize) {
status = FSOUND_SetBufferSize (conf.bufsize);
if (!status) {
fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize);
}
}
status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
if (!status) {
fmod_logerr ("FSOUND_Init failed\n");
return NULL;
}
return &conf;
}
static int fmod_read (SWVoiceIn *sw, void *buf, int size)
{
return audio_pcm_sw_read (sw, buf, size);
}
static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
int status;
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
switch (cmd) {
case VOICE_ENABLE:
status = FSOUND_Record_StartSample (fmd->fmod_sample, 1);
if (!status) {
fmod_logerr ("Failed to start recording\n");
}
break;
case VOICE_DISABLE:
status = FSOUND_Record_Stop ();
if (!status) {
fmod_logerr ("Failed to stop recording\n");
}
break;
}
return 0;
}
static void fmod_audio_fini (void *opaque)
{
(void) opaque;
FSOUND_Close ();
}
static struct audio_option fmod_options[] = {
{
.name = "DRV",
.tag = AUD_OPT_STR,
.valp = &conf.drvname,
.descr = "FMOD driver"
},
{
.name = "FREQ",
.tag = AUD_OPT_INT,
.valp = &conf.freq,
.descr = "Default frequency"
},
{
.name = "SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.nb_samples,
.descr = "Buffer size in samples"
},
{
.name = "CHANNELS",
.tag = AUD_OPT_INT,
.valp = &conf.nb_channels,
.descr = "Number of default channels (1 - mono, 2 - stereo)"
},
{
.name = "BUFSIZE",
.tag = AUD_OPT_INT,
.valp = &conf.bufsize,
.descr = "(undocumented)"
},
{ /* End of list */ }
};
static struct audio_pcm_ops fmod_pcm_ops = {
.init_out = fmod_init_out,
.fini_out = fmod_fini_out,
.run_out = fmod_run_out,
.write = fmod_write,
.ctl_out = fmod_ctl_out,
.init_in = fmod_init_in,
.fini_in = fmod_fini_in,
.run_in = fmod_run_in,
.read = fmod_read,
.ctl_in = fmod_ctl_in
};
struct audio_driver fmod_audio_driver = {
.name = "fmod",
.descr = "FMOD 3.xx http://www.fmod.org",
.options = fmod_options,
.init = fmod_audio_init,
.fini = fmod_audio_fini,
.pcm_ops = &fmod_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (FMODVoiceOut),
.voice_size_in = sizeof (FMODVoiceIn)
};
+2 -2
View File
@@ -63,7 +63,7 @@ static int no_write (SWVoiceOut *sw, void *buf, int len)
return audio_pcm_sw_write (sw, buf, len);
}
static int no_init_out (HWVoiceOut *hw, struct audsettings *as)
static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
{
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
@@ -82,7 +82,7 @@ static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
static int no_init_in (HWVoiceIn *hw, struct audsettings *as)
static int no_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
{
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
+69 -71
View File
@@ -30,6 +30,7 @@
#include "qemu/main-loop.h"
#include "qemu/host-utils.h"
#include "audio.h"
#include "trace.h"
#define AUDIO_CAP "oss"
#include "audio_int.h"
@@ -38,6 +39,16 @@
#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;
@@ -47,6 +58,7 @@ typedef struct OSSVoiceOut {
int fragsize;
int mmapped;
int pending;
OSSConf *conf;
} OSSVoiceOut;
typedef struct OSSVoiceIn {
@@ -55,28 +67,9 @@ typedef struct OSSVoiceIn {
int fd;
int nfrags;
int fragsize;
OSSConf *conf;
} OSSVoiceIn;
static struct {
int try_mmap;
int nfrags;
int fragsize;
const char *devpath_out;
const char *devpath_in;
int debug;
int exclusive;
int policy;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.devpath_out = "/dev/dsp",
.devpath_in = "/dev/dsp",
.debug = 0,
.exclusive = 0,
.policy = 5
};
struct oss_params {
int freq;
audfmt_e fmt;
@@ -138,18 +131,18 @@ static void oss_helper_poll_in (void *opaque)
audio_run ("oss_poll_in");
}
static int oss_poll_out (HWVoiceOut *hw)
static void oss_poll_out (HWVoiceOut *hw)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
return qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
}
static int oss_poll_in (HWVoiceIn *hw)
static void oss_poll_in (HWVoiceIn *hw)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
return qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
}
static int oss_write (SWVoiceOut *sw, void *buf, int len)
@@ -272,18 +265,18 @@ 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)
struct oss_params *obt, int *pfd, OSSConf* conf)
{
int fd;
int oflags = conf.exclusive ? O_EXCL : 0;
int oflags = conf->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 = in ? conf->devpath_in : conf->devpath_out;
const char *typ = in ? "ADC" : "DAC";
/* Kludge needed to have working mmap on Linux */
oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
oflags |= conf->try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
fd = open (dspname, oflags | O_NONBLOCK);
if (-1 == fd) {
@@ -317,20 +310,18 @@ static int oss_open (int in, struct oss_params *req,
}
#ifdef USE_DSP_POLICY
if (conf.policy >= 0) {
if (conf->policy >= 0) {
int version;
if (!oss_get_version (fd, &version, typ)) {
if (conf.debug) {
dolog ("OSS version = %#x\n", version);
}
trace_oss_version(version);
if (version >= 0x040000) {
int policy = conf.policy;
int policy = conf->policy;
if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
oss_logerr2 (errno, typ,
"Failed to set timing policy to %d\n",
conf.policy);
conf->policy);
goto err;
}
setfragment = 0;
@@ -458,19 +449,12 @@ static int oss_run_out (HWVoiceOut *hw, int live)
}
if (abinfo.bytes > bufsize) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
"please report your OS/audio hw to av1474@comtv.ru\n",
abinfo.bytes, bufsize);
}
trace_oss_invalid_available_size(abinfo.bytes, bufsize);
abinfo.bytes = bufsize;
}
if (abinfo.bytes < 0) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
abinfo.bytes, bufsize);
}
trace_oss_invalid_available_size(abinfo.bytes, bufsize);
return 0;
}
@@ -510,7 +494,8 @@ static void oss_fini_out (HWVoiceOut *hw)
}
}
static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
struct oss_params req, obt;
@@ -519,16 +504,17 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
int fd;
audfmt_e effective_fmt;
struct audsettings obt_as;
OSSConf *conf = drv_opaque;
oss->fd = -1;
req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
req.freq = as->freq;
req.nchannels = as->nchannels;
req.fragsize = conf.fragsize;
req.nfrags = conf.nfrags;
req.fragsize = conf->fragsize;
req.nfrags = conf->nfrags;
if (oss_open (0, &req, &obt, &fd)) {
if (oss_open (0, &req, &obt, &fd, conf)) {
return -1;
}
@@ -555,7 +541,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
oss->mmapped = 0;
if (conf.try_mmap) {
if (conf->try_mmap) {
oss->pcm_buf = mmap (
NULL,
hw->samples << hw->info.shift,
@@ -615,6 +601,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
}
oss->fd = fd;
oss->conf = conf;
return 0;
}
@@ -634,7 +621,8 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
va_end (ap);
ldebug ("enabling voice\n");
if (poll_mode && oss_poll_out (hw)) {
if (poll_mode) {
oss_poll_out (hw);
poll_mode = 0;
}
hw->poll_mode = poll_mode;
@@ -676,7 +664,7 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
struct oss_params req, obt;
@@ -685,15 +673,16 @@ static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
int fd;
audfmt_e effective_fmt;
struct audsettings obt_as;
OSSConf *conf = drv_opaque;
oss->fd = -1;
req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
req.freq = as->freq;
req.nchannels = as->nchannels;
req.fragsize = conf.fragsize;
req.nfrags = conf.nfrags;
if (oss_open (1, &req, &obt, &fd)) {
req.fragsize = conf->fragsize;
req.nfrags = conf->nfrags;
if (oss_open (1, &req, &obt, &fd, conf)) {
return -1;
}
@@ -727,6 +716,7 @@ static int oss_init_in (HWVoiceIn *hw, struct audsettings *as)
}
oss->fd = fd;
oss->conf = conf;
return 0;
}
@@ -828,7 +818,8 @@ static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
poll_mode = va_arg (ap, int);
va_end (ap);
if (poll_mode && oss_poll_in (hw)) {
if (poll_mode) {
oss_poll_in (hw);
poll_mode = 0;
}
hw->poll_mode = poll_mode;
@@ -845,71 +836,78 @@ static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
return 0;
}
static OSSConf glob_conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.devpath_out = "/dev/dsp",
.devpath_in = "/dev/dsp",
.exclusive = 0,
.policy = 5
};
static void *oss_audio_init (void)
{
if (access(conf.devpath_in, R_OK | W_OK) < 0 ||
access(conf.devpath_out, R_OK | W_OK) < 0) {
OSSConf *conf = g_malloc(sizeof(OSSConf));
*conf = glob_conf;
if (access(conf->devpath_in, R_OK | W_OK) < 0 ||
access(conf->devpath_out, R_OK | W_OK) < 0) {
return NULL;
}
return &conf;
return conf;
}
static void oss_audio_fini (void *opaque)
{
(void) opaque;
g_free(opaque);
}
static struct audio_option oss_options[] = {
{
.name = "FRAGSIZE",
.tag = AUD_OPT_INT,
.valp = &conf.fragsize,
.valp = &glob_conf.fragsize,
.descr = "Fragment size in bytes"
},
{
.name = "NFRAGS",
.tag = AUD_OPT_INT,
.valp = &conf.nfrags,
.valp = &glob_conf.nfrags,
.descr = "Number of fragments"
},
{
.name = "MMAP",
.tag = AUD_OPT_BOOL,
.valp = &conf.try_mmap,
.valp = &glob_conf.try_mmap,
.descr = "Try using memory mapped access"
},
{
.name = "DAC_DEV",
.tag = AUD_OPT_STR,
.valp = &conf.devpath_out,
.valp = &glob_conf.devpath_out,
.descr = "Path to DAC device"
},
{
.name = "ADC_DEV",
.tag = AUD_OPT_STR,
.valp = &conf.devpath_in,
.valp = &glob_conf.devpath_in,
.descr = "Path to ADC device"
},
{
.name = "EXCLUSIVE",
.tag = AUD_OPT_BOOL,
.valp = &conf.exclusive,
.valp = &glob_conf.exclusive,
.descr = "Open device in exclusive mode (vmix wont work)"
},
#ifdef USE_DSP_POLICY
{
.name = "POLICY",
.tag = AUD_OPT_INT,
.valp = &conf.policy,
.valp = &glob_conf.policy,
.descr = "Set the timing policy of the device, -1 to use fragment mode",
},
#endif
{
.name = "DEBUG",
.tag = AUD_OPT_BOOL,
.valp = &conf.debug,
.descr = "Turn on some debugging messages"
},
{ /* End of list */ }
};
+58 -47
View File
@@ -8,6 +8,19 @@
#include "audio_int.h"
#include "audio_pt_int.h"
typedef struct {
int samples;
char *server;
char *sink;
char *source;
} PAConf;
typedef struct {
PAConf conf;
pa_threaded_mainloop *mainloop;
pa_context *context;
} paaudio;
typedef struct {
HWVoiceOut hw;
int done;
@@ -17,6 +30,7 @@ typedef struct {
pa_stream *stream;
void *pcm_buf;
struct audio_pt pt;
paaudio *g;
} PAVoiceOut;
typedef struct {
@@ -30,20 +44,10 @@ typedef struct {
struct audio_pt pt;
const void *read_data;
size_t read_index, read_length;
paaudio *g;
} PAVoiceIn;
typedef struct {
int samples;
char *server;
char *sink;
char *source;
pa_threaded_mainloop *mainloop;
pa_context *context;
} paaudio;
static paaudio glob_paaudio = {
.samples = 4096,
};
static void qpa_audio_fini(void *opaque);
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
{
@@ -106,7 +110,7 @@ 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 = &glob_paaudio;
paaudio *g = p->g;
pa_threaded_mainloop_lock (g->mainloop);
@@ -160,7 +164,7 @@ unlock_and_fail:
static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
{
paaudio *g = &glob_paaudio;
paaudio *g = p->g;
pa_threaded_mainloop_lock (g->mainloop);
@@ -222,7 +226,7 @@ static void *qpa_thread_out (void *arg)
}
}
decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2);
decr = to_mix = audio_MIN (pa->live, pa->g->conf.samples >> 2);
rpos = pa->rpos;
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
@@ -314,7 +318,7 @@ static void *qpa_thread_in (void *arg)
}
}
incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2);
incr = to_grab = audio_MIN (pa->dead, pa->g->conf.samples >> 2);
wpos = pa->wpos;
if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
@@ -430,7 +434,7 @@ static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
static void context_state_cb (pa_context *c, void *userdata)
{
paaudio *g = &glob_paaudio;
paaudio *g = userdata;
switch (pa_context_get_state(c)) {
case PA_CONTEXT_READY:
@@ -449,7 +453,7 @@ static void context_state_cb (pa_context *c, void *userdata)
static void stream_state_cb (pa_stream *s, void * userdata)
{
paaudio *g = &glob_paaudio;
paaudio *g = userdata;
switch (pa_stream_get_state (s)) {
@@ -467,23 +471,21 @@ static void stream_state_cb (pa_stream *s, void * userdata)
static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
{
paaudio *g = &glob_paaudio;
paaudio *g = userdata;
pa_threaded_mainloop_signal (g->mainloop, 0);
}
static pa_stream *qpa_simple_new (
const char *server,
paaudio *g,
const char *name,
pa_stream_direction_t dir,
const char *dev,
const char *stream_name,
const pa_sample_spec *ss,
const pa_channel_map *map,
const pa_buffer_attr *attr,
int *rerror)
{
paaudio *g = &glob_paaudio;
int r;
pa_stream *stream;
@@ -534,13 +536,15 @@ fail:
return NULL;
}
static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
int error;
static pa_sample_spec ss;
static pa_buffer_attr ba;
pa_sample_spec ss;
pa_buffer_attr ba;
struct audsettings obt_as = *as;
PAVoiceOut *pa = (PAVoiceOut *) hw;
paaudio *g = pa->g = drv_opaque;
ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels;
@@ -558,11 +562,10 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
pa->stream = qpa_simple_new (
glob_paaudio.server,
g,
"qemu",
PA_STREAM_PLAYBACK,
glob_paaudio.sink,
"pcm.playback",
g->conf.sink,
&ss,
NULL, /* channel map */
&ba, /* buffering attributes */
@@ -574,7 +577,7 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
}
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = glob_paaudio.samples;
hw->samples = g->conf.samples;
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
pa->rpos = hw->rpos;
if (!pa->pcm_buf) {
@@ -601,12 +604,13 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
return -1;
}
static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
{
int error;
static pa_sample_spec ss;
pa_sample_spec ss;
struct audsettings obt_as = *as;
PAVoiceIn *pa = (PAVoiceIn *) hw;
paaudio *g = pa->g = drv_opaque;
ss.format = audfmt_to_pa (as->fmt, as->endianness);
ss.channels = as->nchannels;
@@ -615,11 +619,10 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
pa->stream = qpa_simple_new (
glob_paaudio.server,
g,
"qemu",
PA_STREAM_RECORD,
glob_paaudio.source,
"pcm.capture",
g->conf.source,
&ss,
NULL, /* channel map */
NULL, /* buffering attributes */
@@ -631,7 +634,7 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
}
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = glob_paaudio.samples;
hw->samples = g->conf.samples;
pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
pa->wpos = hw->wpos;
if (!pa->pcm_buf) {
@@ -703,7 +706,7 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
PAVoiceOut *pa = (PAVoiceOut *) hw;
pa_operation *op;
pa_cvolume v;
paaudio *g = &glob_paaudio;
paaudio *g = pa->g;
#ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */
pa_cvolume_init (&v); /* function is present in 0.9.13+ */
@@ -755,7 +758,7 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
PAVoiceIn *pa = (PAVoiceIn *) hw;
pa_operation *op;
pa_cvolume v;
paaudio *g = &glob_paaudio;
paaudio *g = pa->g;
#ifdef PA_CHECK_VERSION
pa_cvolume_init (&v);
@@ -805,23 +808,31 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
}
/* common */
static PAConf glob_conf = {
.samples = 4096,
};
static void *qpa_audio_init (void)
{
paaudio *g = &glob_paaudio;
paaudio *g = g_malloc(sizeof(paaudio));
g->conf = glob_conf;
g->mainloop = NULL;
g->context = NULL;
g->mainloop = pa_threaded_mainloop_new ();
if (!g->mainloop) {
goto fail;
}
g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), glob_paaudio.server);
g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop),
g->conf.server);
if (!g->context) {
goto fail;
}
pa_context_set_state_callback (g->context, context_state_cb, g);
if (pa_context_connect (g->context, glob_paaudio.server, 0, NULL) < 0) {
if (pa_context_connect (g->context, g->conf.server, 0, NULL) < 0) {
qpa_logerr (pa_context_errno (g->context),
"pa_context_connect() failed\n");
goto fail;
@@ -854,12 +865,13 @@ static void *qpa_audio_init (void)
pa_threaded_mainloop_unlock (g->mainloop);
return &glob_paaudio;
return g;
unlock_and_fail:
pa_threaded_mainloop_unlock (g->mainloop);
fail:
AUD_log (AUDIO_CAP, "Failed to initialize PA context");
qpa_audio_fini(g);
return NULL;
}
@@ -874,39 +886,38 @@ static void qpa_audio_fini (void *opaque)
if (g->context) {
pa_context_disconnect (g->context);
pa_context_unref (g->context);
g->context = NULL;
}
if (g->mainloop) {
pa_threaded_mainloop_free (g->mainloop);
}
g->mainloop = NULL;
g_free(g);
}
struct audio_option qpa_options[] = {
{
.name = "SAMPLES",
.tag = AUD_OPT_INT,
.valp = &glob_paaudio.samples,
.valp = &glob_conf.samples,
.descr = "buffer size in samples"
},
{
.name = "SERVER",
.tag = AUD_OPT_STR,
.valp = &glob_paaudio.server,
.valp = &glob_conf.server,
.descr = "server address"
},
{
.name = "SINK",
.tag = AUD_OPT_STR,
.valp = &glob_paaudio.sink,
.valp = &glob_conf.sink,
.descr = "sink device name"
},
{
.name = "SOURCE",
.tag = AUD_OPT_STR,
.valp = &glob_paaudio.source,
.valp = &glob_conf.source,
.descr = "source device name"
},
{ /* End of list */ }
+9 -1
View File
@@ -55,6 +55,7 @@ static struct SDLAudioState {
SDL_mutex *mutex;
SDL_sem *sem;
int initialized;
bool driver_created;
} glob_sdl;
typedef struct SDLAudioState SDLAudioState;
@@ -332,7 +333,8 @@ static void sdl_fini_out (HWVoiceOut *hw)
sdl_close (&glob_sdl);
}
static int sdl_init_out (HWVoiceOut *hw, struct audsettings *as)
static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
SDLAudioState *s = &glob_sdl;
@@ -392,6 +394,10 @@ static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
static void *sdl_audio_init (void)
{
SDLAudioState *s = &glob_sdl;
if (s->driver_created) {
sdl_logerr("Can't create multiple sdl backends\n");
return NULL;
}
if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
sdl_logerr ("SDL failed to initialize audio subsystem\n");
@@ -413,6 +419,7 @@ static void *sdl_audio_init (void)
return NULL;
}
s->driver_created = true;
return s;
}
@@ -423,6 +430,7 @@ static void sdl_audio_fini (void *opaque)
SDL_DestroySemaphore (s->sem);
SDL_DestroyMutex (s->mutex);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
s->driver_created = false;
}
static struct audio_option sdl_options[] = {
+3 -2
View File
@@ -115,7 +115,8 @@ static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
/* playback */
static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
static int line_out_init(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
struct audsettings settings;
@@ -243,7 +244,7 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
/* record */
static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
static int line_in_init(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
{
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
struct audsettings settings;
+23 -19
View File
@@ -36,15 +36,10 @@ typedef struct WAVVoiceOut {
int total_samples;
} WAVVoiceOut;
static struct {
typedef struct {
struct audsettings settings;
const char *wav_path;
} conf = {
.settings.freq = 44100,
.settings.nchannels = 2,
.settings.fmt = AUD_FMT_S16,
.wav_path = "qemu.wav"
};
} WAVConf;
static int wav_run_out (HWVoiceOut *hw, int live)
{
@@ -105,7 +100,8 @@ static void le_store (uint8_t *buf, uint32_t val, int len)
}
}
static int wav_init_out (HWVoiceOut *hw, struct audsettings *as)
static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
int bits16 = 0, stereo = 0;
@@ -115,9 +111,8 @@ 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
};
struct audsettings wav_as = conf.settings;
(void) as;
WAVConf *conf = drv_opaque;
struct audsettings wav_as = conf->settings;
stereo = wav_as.nchannels == 2;
switch (wav_as.fmt) {
@@ -155,10 +150,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 (conf->wav_path, "wb");
if (!wav->f) {
dolog ("Failed to open wave file `%s'\nReason: %s\n",
conf.wav_path, strerror (errno));
conf->wav_path, strerror (errno));
g_free (wav->pcm_buf);
wav->pcm_buf = NULL;
return -1;
@@ -226,40 +221,49 @@ static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
static WAVConf glob_conf = {
.settings.freq = 44100,
.settings.nchannels = 2,
.settings.fmt = AUD_FMT_S16,
.wav_path = "qemu.wav"
};
static void *wav_audio_init (void)
{
return &conf;
WAVConf *conf = g_malloc(sizeof(WAVConf));
*conf = glob_conf;
return conf;
}
static void wav_audio_fini (void *opaque)
{
(void) opaque;
ldebug ("wav_fini");
g_free(opaque);
}
static struct audio_option wav_options[] = {
{
.name = "FREQUENCY",
.tag = AUD_OPT_INT,
.valp = &conf.settings.freq,
.valp = &glob_conf.settings.freq,
.descr = "Frequency"
},
{
.name = "FORMAT",
.tag = AUD_OPT_FMT,
.valp = &conf.settings.fmt,
.valp = &glob_conf.settings.fmt,
.descr = "Format"
},
{
.name = "DAC_FIXED_CHANNELS",
.tag = AUD_OPT_INT,
.valp = &conf.settings.nchannels,
.valp = &glob_conf.settings.nchannels,
.descr = "Number of channels (1 - mono, 2 - stereo)"
},
{
.name = "PATH",
.tag = AUD_OPT_STR,
.valp = &conf.wav_path,
.valp = &glob_conf.wav_path,
.descr = "Path to wave file"
},
{ /* End of list */ }
-717
View File
@@ -1,717 +0,0 @@
/* public domain */
#include "qemu-common.h"
#include "sysemu/sysemu.h"
#include "audio.h"
#define AUDIO_CAP "winwave"
#include "audio_int.h"
#include <windows.h>
#include <mmsystem.h>
#include "audio_win_int.h"
static struct {
int dac_headers;
int dac_samples;
int adc_headers;
int adc_samples;
} conf = {
.dac_headers = 4,
.dac_samples = 1024,
.adc_headers = 4,
.adc_samples = 1024
};
typedef struct {
HWVoiceOut hw;
HWAVEOUT hwo;
WAVEHDR *hdrs;
HANDLE event;
void *pcm_buf;
int avail;
int pending;
int curhdr;
int paused;
CRITICAL_SECTION crit_sect;
} WaveVoiceOut;
typedef struct {
HWVoiceIn hw;
HWAVEIN hwi;
WAVEHDR *hdrs;
HANDLE event;
void *pcm_buf;
int curhdr;
int paused;
int rpos;
int avail;
CRITICAL_SECTION crit_sect;
} WaveVoiceIn;
static void winwave_log_mmresult (MMRESULT mr)
{
const char *str = "BUG";
switch (mr) {
case MMSYSERR_NOERROR:
str = "Success";
break;
case MMSYSERR_INVALHANDLE:
str = "Specified device handle is invalid";
break;
case MMSYSERR_BADDEVICEID:
str = "Specified device id is out of range";
break;
case MMSYSERR_NODRIVER:
str = "No device driver is present";
break;
case MMSYSERR_NOMEM:
str = "Unable to allocate or lock memory";
break;
case WAVERR_SYNC:
str = "Device is synchronous but waveOutOpen was called "
"without using the WINWAVE_ALLOWSYNC flag";
break;
case WAVERR_UNPREPARED:
str = "The data block pointed to by the pwh parameter "
"hasn't been prepared";
break;
case WAVERR_STILLPLAYING:
str = "There are still buffers in the queue";
break;
default:
dolog ("Reason: Unknown (MMRESULT %#x)\n", mr);
return;
}
dolog ("Reason: %s\n", str);
}
static void GCC_FMT_ATTR (2, 3) winwave_logerr (
MMRESULT mr,
const char *fmt,
...
)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (NULL, " failed\n");
winwave_log_mmresult (mr);
}
static void winwave_anal_close_out (WaveVoiceOut *wave)
{
MMRESULT mr;
mr = waveOutClose (wave->hwo);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutClose");
}
wave->hwo = NULL;
}
static void CALLBACK winwave_callback_out (
HWAVEOUT hwo,
UINT msg,
DWORD_PTR dwInstance,
DWORD_PTR dwParam1,
DWORD_PTR dwParam2
)
{
WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
switch (msg) {
case WOM_DONE:
{
WAVEHDR *h = (WAVEHDR *) dwParam1;
if (!h->dwUser) {
h->dwUser = 1;
EnterCriticalSection (&wave->crit_sect);
{
wave->avail += conf.dac_samples;
}
LeaveCriticalSection (&wave->crit_sect);
if (wave->hw.poll_mode) {
if (!SetEvent (wave->event)) {
dolog ("DAC SetEvent failed %lx\n", GetLastError ());
}
}
}
}
break;
case WOM_CLOSE:
case WOM_OPEN:
break;
default:
dolog ("unknown wave out callback msg %x\n", msg);
}
}
static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
{
int i;
int err;
MMRESULT mr;
WAVEFORMATEX wfx;
WaveVoiceOut *wave;
wave = (WaveVoiceOut *) hw;
InitializeCriticalSection (&wave->crit_sect);
err = waveformat_from_audio_settings (&wfx, as);
if (err) {
goto err0;
}
mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
(DWORD_PTR) winwave_callback_out,
(DWORD_PTR) wave, CALLBACK_FUNCTION);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutOpen");
goto err1;
}
wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
sizeof (*wave->hdrs));
if (!wave->hdrs) {
goto err2;
}
audio_pcm_init_info (&hw->info, as);
hw->samples = conf.dac_samples * conf.dac_headers;
wave->avail = hw->samples;
wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
conf.dac_headers << hw->info.shift);
if (!wave->pcm_buf) {
goto err3;
}
for (i = 0; i < conf.dac_headers; ++i) {
WAVEHDR *h = &wave->hdrs[i];
h->dwUser = 0;
h->dwBufferLength = conf.dac_samples << hw->info.shift;
h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
h->dwFlags = 0;
mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutPrepareHeader(%d)", i);
goto err4;
}
}
return 0;
err4:
g_free (wave->pcm_buf);
err3:
g_free (wave->hdrs);
err2:
winwave_anal_close_out (wave);
err1:
err0:
return -1;
}
static int winwave_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int winwave_run_out (HWVoiceOut *hw, int live)
{
WaveVoiceOut *wave = (WaveVoiceOut *) hw;
int decr;
int doreset;
EnterCriticalSection (&wave->crit_sect);
{
decr = audio_MIN (live, wave->avail);
decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
wave->pending += decr;
wave->avail -= decr;
}
LeaveCriticalSection (&wave->crit_sect);
doreset = hw->poll_mode && (wave->pending >= conf.dac_samples);
if (doreset && !ResetEvent (wave->event)) {
dolog ("DAC ResetEvent failed %lx\n", GetLastError ());
}
while (wave->pending >= conf.dac_samples) {
MMRESULT mr;
WAVEHDR *h = &wave->hdrs[wave->curhdr];
h->dwUser = 0;
mr = waveOutWrite (wave->hwo, h, sizeof (*h));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
break;
}
wave->pending -= conf.dac_samples;
wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
}
return decr;
}
static void winwave_poll (void *opaque)
{
(void) opaque;
audio_run ("winwave_poll");
}
static void winwave_fini_out (HWVoiceOut *hw)
{
int i;
MMRESULT mr;
WaveVoiceOut *wave = (WaveVoiceOut *) hw;
mr = waveOutReset (wave->hwo);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutReset");
}
for (i = 0; i < conf.dac_headers; ++i) {
mr = waveOutUnprepareHeader (wave->hwo, &wave->hdrs[i],
sizeof (wave->hdrs[i]));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutUnprepareHeader(%d)", i);
}
}
winwave_anal_close_out (wave);
if (wave->event) {
qemu_del_wait_object (wave->event, winwave_poll, wave);
if (!CloseHandle (wave->event)) {
dolog ("DAC CloseHandle failed %lx\n", GetLastError ());
}
wave->event = NULL;
}
g_free (wave->pcm_buf);
wave->pcm_buf = NULL;
g_free (wave->hdrs);
wave->hdrs = NULL;
}
static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
MMRESULT mr;
WaveVoiceOut *wave = (WaveVoiceOut *) hw;
switch (cmd) {
case VOICE_ENABLE:
{
va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
if (poll_mode && !wave->event) {
wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
if (!wave->event) {
dolog ("DAC CreateEvent: %lx, poll mode will be disabled\n",
GetLastError ());
}
}
if (wave->event) {
int ret;
ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
hw->poll_mode = (ret == 0);
}
else {
hw->poll_mode = 0;
}
wave->paused = 0;
}
return 0;
case VOICE_DISABLE:
if (!wave->paused) {
mr = waveOutReset (wave->hwo);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutReset");
}
else {
wave->paused = 1;
}
}
if (wave->event) {
qemu_del_wait_object (wave->event, winwave_poll, wave);
}
return 0;
}
return -1;
}
static void winwave_anal_close_in (WaveVoiceIn *wave)
{
MMRESULT mr;
mr = waveInClose (wave->hwi);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInClose");
}
wave->hwi = NULL;
}
static void CALLBACK winwave_callback_in (
HWAVEIN *hwi,
UINT msg,
DWORD_PTR dwInstance,
DWORD_PTR dwParam1,
DWORD_PTR dwParam2
)
{
WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance;
switch (msg) {
case WIM_DATA:
{
WAVEHDR *h = (WAVEHDR *) dwParam1;
if (!h->dwUser) {
h->dwUser = 1;
EnterCriticalSection (&wave->crit_sect);
{
wave->avail += conf.adc_samples;
}
LeaveCriticalSection (&wave->crit_sect);
if (wave->hw.poll_mode) {
if (!SetEvent (wave->event)) {
dolog ("ADC SetEvent failed %lx\n", GetLastError ());
}
}
}
}
break;
case WIM_CLOSE:
case WIM_OPEN:
break;
default:
dolog ("unknown wave in callback msg %x\n", msg);
}
}
static void winwave_add_buffers (WaveVoiceIn *wave, int samples)
{
int doreset;
doreset = wave->hw.poll_mode && (samples >= conf.adc_samples);
if (doreset && !ResetEvent (wave->event)) {
dolog ("ADC ResetEvent failed %lx\n", GetLastError ());
}
while (samples >= conf.adc_samples) {
MMRESULT mr;
WAVEHDR *h = &wave->hdrs[wave->curhdr];
h->dwUser = 0;
mr = waveInAddBuffer (wave->hwi, h, sizeof (*h));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr);
}
wave->curhdr = (wave->curhdr + 1) % conf.adc_headers;
samples -= conf.adc_samples;
}
}
static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
{
int i;
int err;
MMRESULT mr;
WAVEFORMATEX wfx;
WaveVoiceIn *wave;
wave = (WaveVoiceIn *) hw;
InitializeCriticalSection (&wave->crit_sect);
err = waveformat_from_audio_settings (&wfx, as);
if (err) {
goto err0;
}
mr = waveInOpen (&wave->hwi, WAVE_MAPPER, &wfx,
(DWORD_PTR) winwave_callback_in,
(DWORD_PTR) wave, CALLBACK_FUNCTION);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInOpen");
goto err1;
}
wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
sizeof (*wave->hdrs));
if (!wave->hdrs) {
goto err2;
}
audio_pcm_init_info (&hw->info, as);
hw->samples = conf.adc_samples * conf.adc_headers;
wave->avail = 0;
wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.adc_samples,
conf.adc_headers << hw->info.shift);
if (!wave->pcm_buf) {
goto err3;
}
for (i = 0; i < conf.adc_headers; ++i) {
WAVEHDR *h = &wave->hdrs[i];
h->dwUser = 0;
h->dwBufferLength = conf.adc_samples << hw->info.shift;
h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
h->dwFlags = 0;
mr = waveInPrepareHeader (wave->hwi, h, sizeof (*h));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInPrepareHeader(%d)", i);
goto err4;
}
}
wave->paused = 1;
winwave_add_buffers (wave, hw->samples);
return 0;
err4:
g_free (wave->pcm_buf);
err3:
g_free (wave->hdrs);
err2:
winwave_anal_close_in (wave);
err1:
err0:
return -1;
}
static void winwave_fini_in (HWVoiceIn *hw)
{
int i;
MMRESULT mr;
WaveVoiceIn *wave = (WaveVoiceIn *) hw;
mr = waveInReset (wave->hwi);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInReset");
}
for (i = 0; i < conf.adc_headers; ++i) {
mr = waveInUnprepareHeader (wave->hwi, &wave->hdrs[i],
sizeof (wave->hdrs[i]));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInUnprepareHeader(%d)", i);
}
}
winwave_anal_close_in (wave);
if (wave->event) {
qemu_del_wait_object (wave->event, winwave_poll, wave);
if (!CloseHandle (wave->event)) {
dolog ("ADC CloseHandle failed %lx\n", GetLastError ());
}
wave->event = NULL;
}
g_free (wave->pcm_buf);
wave->pcm_buf = NULL;
g_free (wave->hdrs);
wave->hdrs = NULL;
}
static int winwave_run_in (HWVoiceIn *hw)
{
WaveVoiceIn *wave = (WaveVoiceIn *) hw;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
int decr, ret;
if (!dead) {
return 0;
}
EnterCriticalSection (&wave->crit_sect);
{
decr = audio_MIN (dead, wave->avail);
wave->avail -= decr;
}
LeaveCriticalSection (&wave->crit_sect);
ret = decr;
while (decr) {
int left = hw->samples - hw->wpos;
int conv = audio_MIN (left, decr);
hw->conv (hw->conv_buf + hw->wpos,
advance (wave->pcm_buf, wave->rpos << hw->info.shift),
conv);
wave->rpos = (wave->rpos + conv) % hw->samples;
hw->wpos = (hw->wpos + conv) % hw->samples;
decr -= conv;
}
winwave_add_buffers (wave, ret);
return ret;
}
static int winwave_read (SWVoiceIn *sw, void *buf, int size)
{
return audio_pcm_sw_read (sw, buf, size);
}
static int winwave_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
MMRESULT mr;
WaveVoiceIn *wave = (WaveVoiceIn *) hw;
switch (cmd) {
case VOICE_ENABLE:
{
va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
if (poll_mode && !wave->event) {
wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
if (!wave->event) {
dolog ("ADC CreateEvent: %lx, poll mode will be disabled\n",
GetLastError ());
}
}
if (wave->event) {
int ret;
ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
hw->poll_mode = (ret == 0);
}
else {
hw->poll_mode = 0;
}
if (wave->paused) {
mr = waveInStart (wave->hwi);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInStart");
}
wave->paused = 0;
}
}
return 0;
case VOICE_DISABLE:
if (!wave->paused) {
mr = waveInStop (wave->hwi);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInStop");
}
else {
wave->paused = 1;
}
}
if (wave->event) {
qemu_del_wait_object (wave->event, winwave_poll, wave);
}
return 0;
}
return 0;
}
static void *winwave_audio_init (void)
{
return &conf;
}
static void winwave_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_option winwave_options[] = {
{
.name = "DAC_HEADERS",
.tag = AUD_OPT_INT,
.valp = &conf.dac_headers,
.descr = "DAC number of headers",
},
{
.name = "DAC_SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.dac_samples,
.descr = "DAC number of samples per header",
},
{
.name = "ADC_HEADERS",
.tag = AUD_OPT_INT,
.valp = &conf.adc_headers,
.descr = "ADC number of headers",
},
{
.name = "ADC_SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.adc_samples,
.descr = "ADC number of samples per header",
},
{ /* End of list */ }
};
static struct audio_pcm_ops winwave_pcm_ops = {
.init_out = winwave_init_out,
.fini_out = winwave_fini_out,
.run_out = winwave_run_out,
.write = winwave_write,
.ctl_out = winwave_ctl_out,
.init_in = winwave_init_in,
.fini_in = winwave_fini_in,
.run_in = winwave_run_in,
.read = winwave_read,
.ctl_in = winwave_ctl_in
};
struct audio_driver winwave_audio_driver = {
.name = "winwave",
.descr = "Windows Waveform Audio http://msdn.microsoft.com",
.options = winwave_options,
.init = winwave_audio_init,
.fini = winwave_audio_fini,
.pcm_ops = &winwave_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (WaveVoiceOut),
.voice_size_in = sizeof (WaveVoiceIn)
};
+2 -2
View File
@@ -43,7 +43,7 @@ void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
server_fd = socket_listen(addr, errp);
if (server_fd != -1) {
qemu_set_fd_handler2(server_fd, NULL, nbd_accept, NULL, NULL);
qemu_set_fd_handler(server_fd, nbd_accept, NULL, NULL);
}
}
@@ -129,7 +129,7 @@ void qmp_nbd_server_stop(Error **errp)
}
if (server_fd != -1) {
qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL);
qemu_set_fd_handler(server_fd, NULL, NULL, NULL);
close(server_fd);
server_fd = -1;
}
Vendored
+23 -45
View File
@@ -285,8 +285,6 @@ sysconfdir="\${prefix}/etc"
local_statedir="\${prefix}/var"
confsuffix="/qemu"
slirp="yes"
fmod_lib=""
fmod_inc=""
oss_lib=""
bsd="no"
linux="no"
@@ -437,6 +435,14 @@ EOF
compile_object
}
check_include() {
cat > $TMPC <<EOF
#include <$1>
int main(void) { return 0; }
EOF
compile_object
}
write_c_skeleton() {
cat > $TMPC <<EOF
int main(void) { return 0; }
@@ -564,24 +570,28 @@ case $targetos in
CYGWIN*)
mingw32="yes"
QEMU_CFLAGS="-mno-cygwin $QEMU_CFLAGS"
audio_possible_drivers="winwave sdl"
audio_drv_list="winwave"
audio_possible_drivers="sdl"
audio_drv_list="sdl"
;;
MINGW32*)
mingw32="yes"
audio_possible_drivers="winwave dsound sdl fmod"
audio_drv_list="winwave"
audio_possible_drivers="dsound sdl"
if check_include dsound.h; then
audio_drv_list="dsound"
else
audio_drv_list=""
fi
;;
GNU/kFreeBSD)
bsd="yes"
audio_drv_list="oss"
audio_possible_drivers="oss sdl esd pa"
audio_possible_drivers="oss sdl pa"
;;
FreeBSD)
bsd="yes"
make="${MAKE-gmake}"
audio_drv_list="oss"
audio_possible_drivers="oss sdl esd pa"
audio_possible_drivers="oss sdl pa"
# needed for kinfo_getvmmap(3) in libutil.h
LIBS="-lutil $LIBS"
netmap="" # enable netmap autodetect
@@ -591,14 +601,14 @@ DragonFly)
bsd="yes"
make="${MAKE-gmake}"
audio_drv_list="oss"
audio_possible_drivers="oss sdl esd pa"
audio_possible_drivers="oss sdl pa"
HOST_VARIANT_DIR="dragonfly"
;;
NetBSD)
bsd="yes"
make="${MAKE-gmake}"
audio_drv_list="oss"
audio_possible_drivers="oss sdl esd"
audio_possible_drivers="oss sdl"
oss_lib="-lossaudio"
HOST_VARIANT_DIR="netbsd"
;;
@@ -606,7 +616,7 @@ OpenBSD)
bsd="yes"
make="${MAKE-gmake}"
audio_drv_list="sdl"
audio_possible_drivers="sdl esd"
audio_possible_drivers="sdl"
HOST_VARIANT_DIR="openbsd"
;;
Darwin)
@@ -619,7 +629,7 @@ Darwin)
fi
cocoa="yes"
audio_drv_list="coreaudio"
audio_possible_drivers="coreaudio sdl fmod"
audio_possible_drivers="coreaudio sdl"
LDFLAGS="-framework CoreFoundation -framework IOKit $LDFLAGS"
libs_softmmu="-F/System/Library/Frameworks -framework Cocoa -framework IOKit $libs_softmmu"
# Disable attempts to use ObjectiveC features in os/object.h since they
@@ -674,15 +684,12 @@ Haiku)
;;
*)
audio_drv_list="oss"
audio_possible_drivers="oss alsa sdl esd pa"
audio_possible_drivers="oss alsa sdl pa"
linux="yes"
linux_user="yes"
kvm="yes"
vhost_net="yes"
vhost_scsi="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" -o "$cpu" = "x32" ] ; then
audio_possible_drivers="$audio_possible_drivers fmod"
fi
QEMU_INCLUDES="-I\$(SRC_PATH)/linux-headers -I$(pwd)/linux-headers $QEMU_INCLUDES"
;;
esac
@@ -847,10 +854,6 @@ for opt do
;;
--enable-vnc) vnc="yes"
;;
--fmod-lib=*) fmod_lib="$optarg"
;;
--fmod-inc=*) fmod_inc="$optarg"
;;
--oss-lib=*) oss_lib="$optarg"
;;
--audio-drv-list=*) audio_drv_list="$optarg"
@@ -1349,8 +1352,6 @@ Advanced options (experts only):
--disable-guest-base disable GUEST_BASE support
--enable-pie build Position Independent Executables
--disable-pie do not build Position Independent Executables
--fmod-lib path to FMOD library
--fmod-inc path to FMOD includes
--oss-lib path to OSS library
--cpu=CPU Build for host CPU [$cpu]
--disable-uuid disable uuid support
@@ -2621,21 +2622,6 @@ for drv in $audio_drv_list; do
libs_softmmu="-lasound $libs_softmmu"
;;
fmod)
if test -z $fmod_lib || test -z $fmod_inc; then
error_exit "You must specify path to FMOD library and headers" \
"Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
fi
audio_drv_probe $drv fmod.h $fmod_lib "return FSOUND_GetVersion();" "-I $fmod_inc"
libs_softmmu="$fmod_lib $libs_softmmu"
;;
esd)
audio_drv_probe $drv esd.h -lesd 'return esd_play_stream(0, 0, "", 0);'
libs_softmmu="-lesd $libs_softmmu"
audio_pt_int="yes"
;;
pa)
audio_drv_probe $drv pulse/mainloop.h "-lpulse" \
"pa_mainloop *m = 0; pa_mainloop_free (m); return 0;"
@@ -2660,11 +2646,6 @@ for drv in $audio_drv_list; do
# XXX: Probes for CoreAudio, DirectSound, SDL(?)
;;
winwave)
libs_softmmu="-lwinmm $libs_softmmu"
audio_win_int="yes"
;;
*)
echo "$audio_possible_drivers" | grep -q "\<$drv\>" || {
error_exit "Unknown driver '$drv' selected" \
@@ -4629,9 +4610,6 @@ echo "CONFIG_AUDIO_DRIVERS=$audio_drv_list" >> $config_host_mak
for drv in $audio_drv_list; do
def=CONFIG_`echo $drv | LC_ALL=C tr '[a-z]' '[A-Z]'`
echo "$def=y" >> $config_host_mak
if test "$drv" = "fmod"; then
echo "FMOD_CFLAGS=-I$fmod_inc" >> $config_host_mak
fi
done
if test "$audio_pt_int" = "yes" ; then
echo "CONFIG_AUDIO_PT_INT=y" >> $config_host_mak
+4 -7
View File
@@ -480,6 +480,7 @@ static const VMStateDescription icount_vmstate_timers = {
.name = "timer/icount",
.version_id = 1,
.minimum_version_id = 1,
.needed = icount_state_needed,
.fields = (VMStateField[]) {
VMSTATE_INT64(qemu_icount_bias, TimersState),
VMSTATE_INT64(qemu_icount, TimersState),
@@ -497,13 +498,9 @@ static const VMStateDescription vmstate_timers = {
VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &icount_vmstate_timers,
.needed = icount_state_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&icount_vmstate_timers,
NULL
}
};
-5
View File
@@ -24,14 +24,9 @@ CONFIG_PIIX4=y
CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
CONFIG_MIPSNET=y
CONFIG_PFLASH_CFI01=y
CONFIG_G364FB=y
CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y
CONFIG_ISA_TESTDEV=y
CONFIG_EMPTY_SLOT=y
+1
View File
@@ -29,6 +29,7 @@ CONFIG_DP8393X=y
CONFIG_DS1225Y=y
CONFIG_MIPSNET=y
CONFIG_PFLASH_CFI01=y
CONFIG_JAZZ=y
CONFIG_G364FB=y
CONFIG_I8259=y
CONFIG_JAZZ_LED=y
+1
View File
@@ -31,6 +31,7 @@ CONFIG_DS1225Y=y
CONFIG_MIPSNET=y
CONFIG_PFLASH_CFI01=y
CONFIG_FULONG=y
CONFIG_JAZZ=y
CONFIG_G364FB=y
CONFIG_I8259=y
CONFIG_JAZZ_LED=y
-5
View File
@@ -24,14 +24,9 @@ CONFIG_PIIX4=y
CONFIG_IDE_ISA=y
CONFIG_IDE_PIIX=y
CONFIG_NE2000_ISA=y
CONFIG_RC4030=y
CONFIG_DP8393X=y
CONFIG_DS1225Y=y
CONFIG_MIPSNET=y
CONFIG_PFLASH_CFI01=y
CONFIG_G364FB=y
CONFIG_I8259=y
CONFIG_JAZZ_LED=y
CONFIG_MC146818RTC=y
CONFIG_ISA_TESTDEV=y
CONFIG_EMPTY_SLOT=y
+3
View File
@@ -2238,6 +2238,8 @@ const struct mips_opcode mips_builtin_opcodes[] =
{"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I3|I33 },
{"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D, 0, I2 },
{"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, 0, I2 },
{"mfhc0", "t,G,H", 0x40400000, 0xffe007f8, LCD|WR_t|RD_C0, 0, I33},
{"mthc0", "t,G,H", 0x40c00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, 0, I33},
{"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, 0, I1 },
{"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 },
{"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, 0, I1 },
@@ -2407,6 +2409,7 @@ const struct mips_opcode mips_builtin_opcodes[] =
{"emt", "", 0x41600be1, 0xffffffff, TRAP, 0, MT32 },
{"emt", "t", 0x41600be1, 0xffe0ffff, TRAP|WR_t, 0, MT32 },
{"eret", "", 0x42000018, 0xffffffff, 0, 0, I3|I32 },
{"eretnc", "", 0x42000058, 0xffffffff, 0, 0, I33},
{"evpe", "", 0x41600021, 0xffffffff, TRAP, 0, MT32 },
{"evpe", "t", 0x41600021, 0xffe0ffff, TRAP|WR_t, 0, MT32 },
{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, 0, I33 },
+4 -7
View File
@@ -257,6 +257,7 @@ const VMStateDescription vmstate_ide_drive_pio_state = {
.minimum_version_id = 1,
.pre_save = ide_drive_pio_pre_save,
.post_load = ide_drive_pio_post_load,
.needed = ide_drive_pio_state_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(req_nb_sectors, IDEState),
VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
@@ -279,13 +280,9 @@ const VMStateDescription vmstate_ide_drive = {
.... several fields ....
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection []) {
{
.vmsd = &vmstate_ide_drive_pio_state,
.needed = ide_drive_pio_state_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_ide_drive_pio_state,
NULL
}
};
+21
View File
@@ -203,3 +203,24 @@ completes fully overwriting the item's data.
NOTE: This function is deprecated, and will be completely removed
starting with QEMU v2.4.
== Externally Provided Items ==
As of v2.4, "file" fw_cfg items (i.e., items with selector keys above
FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file
directory structure) may be inserted via the QEMU command line, using
the following syntax:
-fw_cfg [name=]<item_name>,file=<path>
where <item_name> is the fw_cfg item name, and <path> is the location
on the host file system of a file containing the data to be inserted.
NOTE: Users *SHOULD* choose item names beginning with the prefix "opt/"
when using the "-fw_cfg" command line option, to avoid conflicting with
item names used internally by QEMU. For instance:
-fw_cfg name=opt/my_item_name,file=./my_blob.bin
Similarly, QEMU developers *SHOULD NOT* use item names prefixed with
"opt/" when inserting items programmatically, e.g. via fw_cfg_add_file().
+1
View File
@@ -420,6 +420,7 @@ Other properties for front-panel ports are available via DMA CMD descriptors:
LEARNING 1 MAC address learning on port
1 = enabled
0 = disabled
PHYS_NAME <var> Physical port name (string)
Set PORT_SETTINGS descriptor:
+12 -9
View File
@@ -454,6 +454,7 @@ static const VMStateDescription vmstate_cpu_common_exception_index = {
.name = "cpu_common/exception_index",
.version_id = 1,
.minimum_version_id = 1,
.needed = cpu_common_exception_index_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(exception_index, CPUState),
VMSTATE_END_OF_LIST()
@@ -471,13 +472,9 @@ const VMStateDescription vmstate_cpu_common = {
VMSTATE_UINT32(interrupt_request, CPUState),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_cpu_common_exception_index,
.needed = cpu_common_exception_index_needed,
} , {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_cpu_common_exception_index,
NULL
}
};
@@ -3348,14 +3345,20 @@ bool cpu_physical_memory_is_io(hwaddr phys_addr)
return res;
}
void qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)
{
RAMBlock *block;
int ret = 0;
rcu_read_lock();
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
func(block->host, block->offset, block->used_length, opaque);
ret = func(block->idstr, block->host, block->offset,
block->used_length, opaque);
if (ret) {
break;
}
}
rcu_read_unlock();
return ret;
}
#endif
+24
View File
@@ -1798,6 +1798,30 @@ STEXI
show available trace events and their state
ETEXI
STEXI
@item rocker @var{name}
@findex rocker
Show Rocker(s)
ETEXI
STEXI
@item rocker_ports @var{name}
@findex rocker_ports
Show Rocker ports
ETEXI
STEXI
@item rocker_of_dpa_flows @var{name} [@var{tbl_id}]
@findex rocker_of_dpa_flows
Show Rocker OF-DPA flow tables
ETEXI
STEXI
@item rocker_of_dpa_groups @var{name} [@var{type}]
@findex rocker_of_dpa_groups
Show Rocker OF-DPA groups
ETEXI
STEXI
@end table
ETEXI
+303
View File
@@ -15,6 +15,7 @@
#include "hmp.h"
#include "net/net.h"
#include "net/eth.h"
#include "sysemu/char.h"
#include "sysemu/block-backend.h"
#include "qemu/option.h"
@@ -1999,3 +2000,305 @@ void hmp_qom_set(Monitor *mon, const QDict *qdict)
}
hmp_handle_error(mon, &err);
}
void hmp_rocker(Monitor *mon, const QDict *qdict)
{
const char *name = qdict_get_str(qdict, "name");
RockerSwitch *rocker;
Error *errp = NULL;
rocker = qmp_query_rocker(name, &errp);
if (errp != NULL) {
hmp_handle_error(mon, &errp);
return;
}
monitor_printf(mon, "name: %s\n", rocker->name);
monitor_printf(mon, "id: 0x%" PRIx64 "\n", rocker->id);
monitor_printf(mon, "ports: %d\n", rocker->ports);
qapi_free_RockerSwitch(rocker);
}
void hmp_rocker_ports(Monitor *mon, const QDict *qdict)
{
RockerPortList *list, *port;
const char *name = qdict_get_str(qdict, "name");
Error *errp = NULL;
list = qmp_query_rocker_ports(name, &errp);
if (errp != NULL) {
hmp_handle_error(mon, &errp);
return;
}
monitor_printf(mon, " ena/ speed/ auto\n");
monitor_printf(mon, " port link duplex neg?\n");
for (port = list; port; port = port->next) {
monitor_printf(mon, "%10s %-4s %-3s %2s %-3s\n",
port->value->name,
port->value->enabled ? port->value->link_up ?
"up" : "down" : "!ena",
port->value->speed == 10000 ? "10G" : "??",
port->value->duplex ? "FD" : "HD",
port->value->autoneg ? "Yes" : "No");
}
qapi_free_RockerPortList(list);
}
void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict)
{
RockerOfDpaFlowList *list, *info;
const char *name = qdict_get_str(qdict, "name");
uint32_t tbl_id = qdict_get_try_int(qdict, "tbl_id", -1);
Error *errp = NULL;
list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &errp);
if (errp != NULL) {
hmp_handle_error(mon, &errp);
return;
}
monitor_printf(mon, "prio tbl hits key(mask) --> actions\n");
for (info = list; info; info = info->next) {
RockerOfDpaFlow *flow = info->value;
RockerOfDpaFlowKey *key = flow->key;
RockerOfDpaFlowMask *mask = flow->mask;
RockerOfDpaFlowAction *action = flow->action;
if (flow->hits) {
monitor_printf(mon, "%-4d %-3d %-4" PRIu64,
key->priority, key->tbl_id, flow->hits);
} else {
monitor_printf(mon, "%-4d %-3d ",
key->priority, key->tbl_id);
}
if (key->has_in_pport) {
monitor_printf(mon, " pport %d", key->in_pport);
if (mask->has_in_pport) {
monitor_printf(mon, "(0x%x)", mask->in_pport);
}
}
if (key->has_vlan_id) {
monitor_printf(mon, " vlan %d",
key->vlan_id & VLAN_VID_MASK);
if (mask->has_vlan_id) {
monitor_printf(mon, "(0x%x)", mask->vlan_id);
}
}
if (key->has_tunnel_id) {
monitor_printf(mon, " tunnel %d", key->tunnel_id);
if (mask->has_tunnel_id) {
monitor_printf(mon, "(0x%x)", mask->tunnel_id);
}
}
if (key->has_eth_type) {
switch (key->eth_type) {
case 0x0806:
monitor_printf(mon, " ARP");
break;
case 0x0800:
monitor_printf(mon, " IP");
break;
case 0x86dd:
monitor_printf(mon, " IPv6");
break;
case 0x8809:
monitor_printf(mon, " LACP");
break;
case 0x88cc:
monitor_printf(mon, " LLDP");
break;
default:
monitor_printf(mon, " eth type 0x%04x", key->eth_type);
break;
}
}
if (key->has_eth_src) {
if ((strcmp(key->eth_src, "01:00:00:00:00:00") == 0) &&
(mask->has_eth_src) &&
(strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) {
monitor_printf(mon, " src <any mcast/bcast>");
} else if ((strcmp(key->eth_src, "00:00:00:00:00:00") == 0) &&
(mask->has_eth_src) &&
(strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) {
monitor_printf(mon, " src <any ucast>");
} else {
monitor_printf(mon, " src %s", key->eth_src);
if (mask->has_eth_src) {
monitor_printf(mon, "(%s)", mask->eth_src);
}
}
}
if (key->has_eth_dst) {
if ((strcmp(key->eth_dst, "01:00:00:00:00:00") == 0) &&
(mask->has_eth_dst) &&
(strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) {
monitor_printf(mon, " dst <any mcast/bcast>");
} else if ((strcmp(key->eth_dst, "00:00:00:00:00:00") == 0) &&
(mask->has_eth_dst) &&
(strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) {
monitor_printf(mon, " dst <any ucast>");
} else {
monitor_printf(mon, " dst %s", key->eth_dst);
if (mask->has_eth_dst) {
monitor_printf(mon, "(%s)", mask->eth_dst);
}
}
}
if (key->has_ip_proto) {
monitor_printf(mon, " proto %d", key->ip_proto);
if (mask->has_ip_proto) {
monitor_printf(mon, "(0x%x)", mask->ip_proto);
}
}
if (key->has_ip_tos) {
monitor_printf(mon, " TOS %d", key->ip_tos);
if (mask->has_ip_tos) {
monitor_printf(mon, "(0x%x)", mask->ip_tos);
}
}
if (key->has_ip_dst) {
monitor_printf(mon, " dst %s", key->ip_dst);
}
if (action->has_goto_tbl || action->has_group_id ||
action->has_new_vlan_id) {
monitor_printf(mon, " -->");
}
if (action->has_new_vlan_id) {
monitor_printf(mon, " apply new vlan %d",
ntohs(action->new_vlan_id));
}
if (action->has_group_id) {
monitor_printf(mon, " write group 0x%08x", action->group_id);
}
if (action->has_goto_tbl) {
monitor_printf(mon, " goto tbl %d", action->goto_tbl);
}
monitor_printf(mon, "\n");
}
qapi_free_RockerOfDpaFlowList(list);
}
void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict)
{
RockerOfDpaGroupList *list, *g;
const char *name = qdict_get_str(qdict, "name");
uint8_t type = qdict_get_try_int(qdict, "type", 9);
Error *errp = NULL;
bool set = false;
list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &errp);
if (errp != NULL) {
hmp_handle_error(mon, &errp);
return;
}
monitor_printf(mon, "id (decode) --> buckets\n");
for (g = list; g; g = g->next) {
RockerOfDpaGroup *group = g->value;
monitor_printf(mon, "0x%08x", group->id);
monitor_printf(mon, " (type %s", group->type == 0 ? "L2 interface" :
group->type == 1 ? "L2 rewrite" :
group->type == 2 ? "L3 unicast" :
group->type == 3 ? "L2 multicast" :
group->type == 4 ? "L2 flood" :
group->type == 5 ? "L3 interface" :
group->type == 6 ? "L3 multicast" :
group->type == 7 ? "L3 ECMP" :
group->type == 8 ? "L2 overlay" :
"unknown");
if (group->has_vlan_id) {
monitor_printf(mon, " vlan %d", group->vlan_id);
}
if (group->has_pport) {
monitor_printf(mon, " pport %d", group->pport);
}
if (group->has_index) {
monitor_printf(mon, " index %d", group->index);
}
monitor_printf(mon, ") -->");
if (group->has_set_vlan_id && group->set_vlan_id) {
set = true;
monitor_printf(mon, " set vlan %d",
group->set_vlan_id & VLAN_VID_MASK);
}
if (group->has_set_eth_src) {
if (!set) {
set = true;
monitor_printf(mon, " set");
}
monitor_printf(mon, " src %s", group->set_eth_src);
}
if (group->has_set_eth_dst) {
if (!set) {
set = true;
monitor_printf(mon, " set");
}
monitor_printf(mon, " dst %s", group->set_eth_dst);
}
set = false;
if (group->has_ttl_check && group->ttl_check) {
monitor_printf(mon, " check TTL");
}
if (group->has_group_id && group->group_id) {
monitor_printf(mon, " group id 0x%08x", group->group_id);
}
if (group->has_pop_vlan && group->pop_vlan) {
monitor_printf(mon, " pop vlan");
}
if (group->has_out_pport) {
monitor_printf(mon, " out pport %d", group->out_pport);
}
if (group->has_group_ids) {
struct uint32List *id;
monitor_printf(mon, " groups [");
for (id = group->group_ids; id; id = id->next) {
monitor_printf(mon, "0x%08x", id->value);
if (id->next) {
monitor_printf(mon, ",");
}
}
monitor_printf(mon, "]");
}
monitor_printf(mon, "\n");
}
qapi_free_RockerOfDpaGroupList(list);
}
+4
View File
@@ -124,5 +124,9 @@ void host_net_remove_completion(ReadLineState *rs, int nb_args,
const char *str);
void delvm_completion(ReadLineState *rs, int nb_args, const char *str);
void loadvm_completion(ReadLineState *rs, int nb_args, const char *str);
void hmp_rocker(Monitor *mon, const QDict *qdict);
void hmp_rocker_ports(Monitor *mon, const QDict *qdict);
void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict);
void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict);
#endif
+2 -1
View File
@@ -140,7 +140,8 @@ out:
/* virtio-9p device */
static Property virtio_9p_properties[] = {
DEFINE_VIRTIO_9P_PROPERTIES(V9fsState, fsconf),
DEFINE_PROP_STRING("mount_tag", V9fsState, fsconf.tag),
DEFINE_PROP_STRING("fsdev", V9fsState, fsconf.fsdev_id),
DEFINE_PROP_END_OF_LIST(),
};
-4
View File
@@ -391,8 +391,4 @@ extern int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
#define VIRTIO_9P(obj) \
OBJECT_CHECK(V9fsState, (obj), TYPE_VIRTIO_9P)
#define DEFINE_VIRTIO_9P_PROPERTIES(_state, _field) \
DEFINE_PROP_STRING("mount_tag", _state, _field.tag), \
DEFINE_PROP_STRING("fsdev", _state, _field.fsdev_id)
#endif
+4 -6
View File
@@ -152,6 +152,7 @@ static const VMStateDescription vmstate_memhp_state = {
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.needed = vmstate_test_use_memhp,
.fields = (VMStateField[]) {
VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs),
VMSTATE_END_OF_LIST()
@@ -175,12 +176,9 @@ const VMStateDescription vmstate_ich9_pm = {
VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_memhp_state,
.needed = vmstate_test_use_memhp,
},
VMSTATE_END_OF_LIST()
.subsections = (const VMStateDescription*[]) {
&vmstate_memhp_state,
NULL
}
};
+4 -6
View File
@@ -260,6 +260,7 @@ static const VMStateDescription vmstate_memhp_state = {
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.needed = vmstate_test_use_memhp,
.fields = (VMStateField[]) {
VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState),
VMSTATE_END_OF_LIST()
@@ -298,12 +299,9 @@ static const VMStateDescription vmstate_acpi = {
vmstate_test_use_acpi_pci_hotplug),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_memhp_state,
.needed = vmstate_test_use_memhp,
},
VMSTATE_END_OF_LIST()
.subsections = (const VMStateDescription*[]) {
&vmstate_memhp_state,
NULL
}
};
+16 -26
View File
@@ -699,6 +699,7 @@ static const VMStateDescription vmstate_fdrive_media_changed = {
.name = "fdrive/media_changed",
.version_id = 1,
.minimum_version_id = 1,
.needed = fdrive_media_changed_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(media_changed, FDrive),
VMSTATE_END_OF_LIST()
@@ -716,6 +717,7 @@ static const VMStateDescription vmstate_fdrive_media_rate = {
.name = "fdrive/media_rate",
.version_id = 1,
.minimum_version_id = 1,
.needed = fdrive_media_rate_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(media_rate, FDrive),
VMSTATE_END_OF_LIST()
@@ -733,6 +735,7 @@ static const VMStateDescription vmstate_fdrive_perpendicular = {
.name = "fdrive/perpendicular",
.version_id = 1,
.minimum_version_id = 1,
.needed = fdrive_perpendicular_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(perpendicular, FDrive),
VMSTATE_END_OF_LIST()
@@ -756,19 +759,11 @@ static const VMStateDescription vmstate_fdrive = {
VMSTATE_UINT8(sect, FDrive),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_fdrive_media_changed,
.needed = &fdrive_media_changed_needed,
} , {
.vmsd = &vmstate_fdrive_media_rate,
.needed = &fdrive_media_rate_needed,
} , {
.vmsd = &vmstate_fdrive_perpendicular,
.needed = &fdrive_perpendicular_needed,
} , {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_fdrive_media_changed,
&vmstate_fdrive_media_rate,
&vmstate_fdrive_perpendicular,
NULL
}
};
@@ -833,6 +828,7 @@ static const VMStateDescription vmstate_fdc_reset_sensei = {
.name = "fdc/reset_sensei",
.version_id = 1,
.minimum_version_id = 1,
.needed = fdc_reset_sensei_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(reset_sensei, FDCtrl),
VMSTATE_END_OF_LIST()
@@ -850,6 +846,7 @@ static const VMStateDescription vmstate_fdc_result_timer = {
.name = "fdc/result_timer",
.version_id = 1,
.minimum_version_id = 1,
.needed = fdc_result_timer_needed,
.fields = (VMStateField[]) {
VMSTATE_TIMER_PTR(result_timer, FDCtrl),
VMSTATE_END_OF_LIST()
@@ -867,6 +864,7 @@ static const VMStateDescription vmstate_fdc_phase = {
.name = "fdc/phase",
.version_id = 1,
.minimum_version_id = 1,
.needed = fdc_phase_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(phase, FDCtrl),
VMSTATE_END_OF_LIST()
@@ -911,19 +909,11 @@ static const VMStateDescription vmstate_fdc = {
vmstate_fdrive, FDrive),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_fdc_reset_sensei,
.needed = fdc_reset_sensei_needed,
} , {
.vmsd = &vmstate_fdc_result_timer,
.needed = fdc_result_timer_needed,
} , {
.vmsd = &vmstate_fdc_phase,
.needed = fdc_phase_needed,
} , {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_fdc_reset_sensei,
&vmstate_fdc_result_timer,
&vmstate_fdc_phase,
NULL
}
};
+16 -25
View File
@@ -662,6 +662,7 @@ static const VMStateDescription vmstate_serial_thr_ipending = {
.name = "serial/thr_ipending",
.version_id = 1,
.minimum_version_id = 1,
.needed = serial_thr_ipending_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(thr_ipending, SerialState),
VMSTATE_END_OF_LIST()
@@ -678,6 +679,7 @@ static const VMStateDescription vmstate_serial_tsr = {
.name = "serial/tsr",
.version_id = 1,
.minimum_version_id = 1,
.needed = serial_tsr_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(tsr_retry, SerialState),
VMSTATE_UINT8(thr, SerialState),
@@ -697,6 +699,7 @@ static const VMStateDescription vmstate_serial_recv_fifo = {
.name = "serial/recv_fifo",
.version_id = 1,
.minimum_version_id = 1,
.needed = serial_recv_fifo_needed,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(recv_fifo, SerialState, 1, vmstate_fifo8, Fifo8),
VMSTATE_END_OF_LIST()
@@ -713,6 +716,7 @@ static const VMStateDescription vmstate_serial_xmit_fifo = {
.name = "serial/xmit_fifo",
.version_id = 1,
.minimum_version_id = 1,
.needed = serial_xmit_fifo_needed,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(xmit_fifo, SerialState, 1, vmstate_fifo8, Fifo8),
VMSTATE_END_OF_LIST()
@@ -729,6 +733,7 @@ static const VMStateDescription vmstate_serial_fifo_timeout_timer = {
.name = "serial/fifo_timeout_timer",
.version_id = 1,
.minimum_version_id = 1,
.needed = serial_fifo_timeout_timer_needed,
.fields = (VMStateField[]) {
VMSTATE_TIMER_PTR(fifo_timeout_timer, SerialState),
VMSTATE_END_OF_LIST()
@@ -745,6 +750,7 @@ static const VMStateDescription vmstate_serial_timeout_ipending = {
.name = "serial/timeout_ipending",
.version_id = 1,
.minimum_version_id = 1,
.needed = serial_timeout_ipending_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(timeout_ipending, SerialState),
VMSTATE_END_OF_LIST()
@@ -760,6 +766,7 @@ static bool serial_poll_needed(void *opaque)
static const VMStateDescription vmstate_serial_poll = {
.name = "serial/poll",
.version_id = 1,
.needed = serial_poll_needed,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT32(poll_msl, SerialState),
@@ -788,31 +795,15 @@ const VMStateDescription vmstate_serial = {
VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_serial_thr_ipending,
.needed = &serial_thr_ipending_needed,
} , {
.vmsd = &vmstate_serial_tsr,
.needed = &serial_tsr_needed,
} , {
.vmsd = &vmstate_serial_recv_fifo,
.needed = &serial_recv_fifo_needed,
} , {
.vmsd = &vmstate_serial_xmit_fifo,
.needed = &serial_xmit_fifo_needed,
} , {
.vmsd = &vmstate_serial_fifo_timeout_timer,
.needed = &serial_fifo_timeout_timer_needed,
} , {
.vmsd = &vmstate_serial_timeout_ipending,
.needed = &serial_timeout_ipending_needed,
} , {
.vmsd = &vmstate_serial_poll,
.needed = &serial_poll_needed,
} , {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_serial_thr_ipending,
&vmstate_serial_tsr,
&vmstate_serial_recv_fifo,
&vmstate_serial_xmit_fifo,
&vmstate_serial_fifo_timeout_timer,
&vmstate_serial_timeout_ipending,
&vmstate_serial_poll,
NULL
}
};
+2 -1
View File
@@ -1083,7 +1083,8 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
}
static Property virtio_serial_properties[] = {
DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerial, serial),
DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports,
31),
DEFINE_PROP_END_OF_LIST(),
};
+4 -7
View File
@@ -2220,6 +2220,7 @@ static VMStateDescription qxl_vmstate_monitors_config = {
.name = "qxl/monitors-config",
.version_id = 1,
.minimum_version_id = 1,
.needed = qxl_monitors_config_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice),
VMSTATE_END_OF_LIST()
@@ -2253,13 +2254,9 @@ static VMStateDescription qxl_vmstate = {
VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &qxl_vmstate_monitors_config,
.needed = qxl_monitors_config_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&qxl_vmstate_monitors_config,
NULL
}
};
+4 -7
View File
@@ -2035,6 +2035,7 @@ static const VMStateDescription vmstate_vga_endian = {
.name = "vga.endian",
.version_id = 1,
.minimum_version_id = 1,
.needed = vga_endian_state_needed,
.fields = (VMStateField[]) {
VMSTATE_BOOL(big_endian_fb, VGACommonState),
VMSTATE_END_OF_LIST()
@@ -2078,13 +2079,9 @@ const VMStateDescription vmstate_vga_common = {
VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection []) {
{
.vmsd = &vmstate_vga_endian,
.needed = vga_endian_state_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_vga_endian,
NULL
}
};
+242 -226
View File
@@ -1,7 +1,7 @@
/*
* QEMU JAZZ RC4030 chipset
*
* Copyright (c) 2007-2009 Herve Poussineau
* Copyright (c) 2007-2013 Hervé Poussineau
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,29 +24,16 @@
#include "hw/hw.h"
#include "hw/mips/mips.h"
#include "hw/sysbus.h"
#include "qemu/timer.h"
/********************************************************/
/* debug rc4030 */
//#define DEBUG_RC4030
//#define DEBUG_RC4030_DMA
#ifdef DEBUG_RC4030
#define DPRINTF(fmt, ...) \
do { printf("rc4030: " fmt , ## __VA_ARGS__); } while (0)
static const char* irq_names[] = { "parallel", "floppy", "sound", "video",
"network", "scsi", "keyboard", "mouse", "serial0", "serial1" };
#else
#define DPRINTF(fmt, ...)
#endif
#define RC4030_ERROR(fmt, ...) \
do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
#include "exec/address-spaces.h"
#include "trace.h"
/********************************************************/
/* rc4030 emulation */
#define MAX_TL_ENTRIES 512
typedef struct dma_pagetable_entry {
int32_t frame;
int32_t owner;
@@ -63,8 +50,14 @@ typedef struct dma_pagetable_entry {
#define DMA_FLAG_MEM_INTR 0x0200
#define DMA_FLAG_ADDR_INTR 0x0400
#define TYPE_RC4030 "rc4030"
#define RC4030(obj) \
OBJECT_CHECK(rc4030State, (obj), TYPE_RC4030)
typedef struct rc4030State
{
SysBusDevice parent;
uint32_t config; /* 0x0000: RC4030 config register */
uint32_t revision; /* 0x0008: RC4030 Revision register */
uint32_t invalid_address_register; /* 0x0010: Invalid Address register */
@@ -83,7 +76,7 @@ typedef struct rc4030State
uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */
uint32_t nmi_interrupt; /* 0x0200: interrupt source */
uint32_t offset210;
uint32_t memory_refresh_rate; /* 0x0210: memory refresh rate */
uint32_t nvram_protect; /* 0x0220: NV ram protect register */
uint32_t rem_speed[16];
uint32_t imr_jazz; /* Local bus int enable mask */
@@ -96,6 +89,16 @@ typedef struct rc4030State
qemu_irq timer_irq;
qemu_irq jazz_bus_irq;
/* biggest translation table */
MemoryRegion dma_tt;
/* translation table memory region alias, added to system RAM */
MemoryRegion dma_tt_alias;
/* whole DMA memory region, root of DMA address space */
MemoryRegion dma_mr;
/* translation table entry aliases, added to DMA memory region */
MemoryRegion dma_mrs[MAX_TL_ENTRIES];
AddressSpace dma_as;
MemoryRegion iomem_chipset;
MemoryRegion iomem_jazzio;
} rc4030State;
@@ -112,7 +115,7 @@ static void set_next_tick(rc4030State *s)
}
/* called for accesses to rc4030 */
static uint32_t rc4030_readl(void *opaque, hwaddr addr)
static uint64_t rc4030_read(void *opaque, hwaddr addr, unsigned int size)
{
rc4030State *s = opaque;
uint32_t val;
@@ -220,9 +223,9 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr)
case 0x0208:
val = 0;
break;
/* Offset 0x0210 */
/* Memory refresh rate */
case 0x0210:
val = s->offset210;
val = s->memory_refresh_rate;
break;
/* NV ram protect register */
case 0x0220:
@@ -238,39 +241,117 @@ static uint32_t rc4030_readl(void *opaque, hwaddr addr)
val = 7; /* FIXME: should be read from EISA controller */
break;
default:
RC4030_ERROR("invalid read [" TARGET_FMT_plx "]\n", addr);
qemu_log_mask(LOG_GUEST_ERROR,
"rc4030: invalid read at 0x%x", (int)addr);
val = 0;
break;
}
if ((addr & ~3) != 0x230) {
DPRINTF("read 0x%02x at " TARGET_FMT_plx "\n", val, addr);
trace_rc4030_read(addr, val);
}
return val;
}
static uint32_t rc4030_readw(void *opaque, hwaddr addr)
static void rc4030_dma_as_update_one(rc4030State *s, int index, uint32_t frame)
{
uint32_t v = rc4030_readl(opaque, addr & ~0x3);
if (addr & 0x2)
return v >> 16;
else
return v & 0xffff;
if (index < MAX_TL_ENTRIES) {
memory_region_set_enabled(&s->dma_mrs[index], false);
}
if (!frame) {
return;
}
if (index >= MAX_TL_ENTRIES) {
qemu_log_mask(LOG_UNIMP,
"rc4030: trying to use too high "
"translation table entry %d (max allowed=%d)",
index, MAX_TL_ENTRIES);
return;
}
memory_region_set_alias_offset(&s->dma_mrs[index], frame);
memory_region_set_enabled(&s->dma_mrs[index], true);
}
static uint32_t rc4030_readb(void *opaque, hwaddr addr)
{
uint32_t v = rc4030_readl(opaque, addr & ~0x3);
return (v >> (8 * (addr & 0x3))) & 0xff;
}
static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
static void rc4030_dma_tt_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
rc4030State *s = opaque;
/* write memory */
memcpy(memory_region_get_ram_ptr(&s->dma_tt) + addr, &data, size);
/* update dma address space (only if frame field has been written) */
if (addr % sizeof(dma_pagetable_entry) == 0) {
int index = addr / sizeof(dma_pagetable_entry);
memory_region_transaction_begin();
rc4030_dma_as_update_one(s, index, (uint32_t)data);
memory_region_transaction_commit();
}
}
static const MemoryRegionOps rc4030_dma_tt_ops = {
.write = rc4030_dma_tt_write,
.impl.min_access_size = 4,
.impl.max_access_size = 4,
};
static void rc4030_dma_tt_update(rc4030State *s, uint32_t new_tl_base,
uint32_t new_tl_limit)
{
int entries, i;
dma_pagetable_entry *dma_tl_contents;
if (s->dma_tl_limit) {
/* write old dma tl table to physical memory */
memory_region_del_subregion(get_system_memory(), &s->dma_tt_alias);
cpu_physical_memory_write(s->dma_tl_limit & 0x7fffffff,
memory_region_get_ram_ptr(&s->dma_tt),
memory_region_size(&s->dma_tt_alias));
}
object_unparent(OBJECT(&s->dma_tt_alias));
s->dma_tl_base = new_tl_base;
s->dma_tl_limit = new_tl_limit;
new_tl_base &= 0x7fffffff;
if (s->dma_tl_limit) {
uint64_t dma_tt_size;
if (s->dma_tl_limit <= memory_region_size(&s->dma_tt)) {
dma_tt_size = s->dma_tl_limit;
} else {
dma_tt_size = memory_region_size(&s->dma_tt);
}
memory_region_init_alias(&s->dma_tt_alias, OBJECT(s),
"dma-table-alias",
&s->dma_tt, 0, dma_tt_size);
dma_tl_contents = memory_region_get_ram_ptr(&s->dma_tt);
cpu_physical_memory_read(new_tl_base, dma_tl_contents, dma_tt_size);
memory_region_transaction_begin();
entries = dma_tt_size / sizeof(dma_pagetable_entry);
for (i = 0; i < entries; i++) {
rc4030_dma_as_update_one(s, i, dma_tl_contents[i].frame);
}
memory_region_add_subregion(get_system_memory(), new_tl_base,
&s->dma_tt_alias);
memory_region_transaction_commit();
} else {
memory_region_init(&s->dma_tt_alias, OBJECT(s),
"dma-table-alias", 0);
}
}
static void rc4030_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
rc4030State *s = opaque;
uint32_t val = data;
addr &= 0x3fff;
DPRINTF("write 0x%02x at " TARGET_FMT_plx "\n", val, addr);
trace_rc4030_write(addr, val);
switch (addr & ~0x3) {
/* Global config register */
@@ -279,11 +360,11 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
break;
/* DMA transl. table base */
case 0x0018:
s->dma_tl_base = val;
rc4030_dma_tt_update(s, val, s->dma_tl_limit);
break;
/* DMA transl. table limit */
case 0x0020:
s->dma_tl_limit = val;
rc4030_dma_tt_update(s, s->dma_tl_base, val);
break;
/* DMA transl. table invalidated */
case 0x0028:
@@ -371,9 +452,9 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
s->dma_regs[entry][idx] = val;
}
break;
/* Offset 0x0210 */
/* Memory refresh rate */
case 0x0210:
s->offset210 = val;
s->memory_refresh_rate = val;
break;
/* Interval timer reload */
case 0x0228:
@@ -385,48 +466,18 @@ static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
case 0x0238:
break;
default:
RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr);
qemu_log_mask(LOG_GUEST_ERROR,
"rc4030: invalid write of 0x%02x at 0x%x",
val, (int)addr);
break;
}
}
static void rc4030_writew(void *opaque, hwaddr addr, uint32_t val)
{
uint32_t old_val = rc4030_readl(opaque, addr & ~0x3);
if (addr & 0x2)
val = (val << 16) | (old_val & 0x0000ffff);
else
val = val | (old_val & 0xffff0000);
rc4030_writel(opaque, addr & ~0x3, val);
}
static void rc4030_writeb(void *opaque, hwaddr addr, uint32_t val)
{
uint32_t old_val = rc4030_readl(opaque, addr & ~0x3);
switch (addr & 3) {
case 0:
val = val | (old_val & 0xffffff00);
break;
case 1:
val = (val << 8) | (old_val & 0xffff00ff);
break;
case 2:
val = (val << 16) | (old_val & 0xff00ffff);
break;
case 3:
val = (val << 24) | (old_val & 0x00ffffff);
break;
}
rc4030_writel(opaque, addr & ~0x3, val);
}
static const MemoryRegionOps rc4030_ops = {
.old_mmio = {
.read = { rc4030_readb, rc4030_readw, rc4030_readl, },
.write = { rc4030_writeb, rc4030_writew, rc4030_writel, },
},
.read = rc4030_read,
.write = rc4030_write,
.impl.min_access_size = 4,
.impl.max_access_size = 4,
.endianness = DEVICE_NATIVE_ENDIAN,
};
@@ -436,22 +487,6 @@ static void update_jazz_irq(rc4030State *s)
pending = s->isr_jazz & s->imr_jazz;
#ifdef DEBUG_RC4030
if (s->isr_jazz != 0) {
uint32_t irq = 0;
DPRINTF("pending irqs:");
for (irq = 0; irq < ARRAY_SIZE(irq_names); irq++) {
if (s->isr_jazz & (1 << irq)) {
printf(" %s", irq_names[irq]);
if (!(s->imr_jazz & (1 << irq))) {
printf("(ignored)");
}
}
}
printf("\n");
}
#endif
if (pending != 0)
qemu_irq_raise(s->jazz_bus_irq);
else
@@ -479,7 +514,7 @@ static void rc4030_periodic_timer(void *opaque)
qemu_irq_raise(s->timer_irq);
}
static uint32_t jazzio_readw(void *opaque, hwaddr addr)
static uint64_t jazzio_read(void *opaque, hwaddr addr, unsigned int size)
{
rc4030State *s = opaque;
uint32_t val;
@@ -494,7 +529,6 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr)
irq = 0;
while (pending) {
if (pending & 1) {
DPRINTF("returning irq %s\n", irq_names[irq]);
val = (irq + 1) << 2;
break;
}
@@ -508,36 +542,25 @@ static uint32_t jazzio_readw(void *opaque, hwaddr addr)
val = s->imr_jazz;
break;
default:
RC4030_ERROR("(jazz io controller) invalid read [" TARGET_FMT_plx "]\n", addr);
qemu_log_mask(LOG_GUEST_ERROR,
"rc4030/jazzio: invalid read at 0x%x", (int)addr);
val = 0;
break;
}
DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_plx "\n", val, addr);
trace_jazzio_read(addr, val);
return val;
}
static uint32_t jazzio_readb(void *opaque, hwaddr addr)
{
uint32_t v;
v = jazzio_readw(opaque, addr & ~0x1);
return (v >> (8 * (addr & 0x1))) & 0xff;
}
static uint32_t jazzio_readl(void *opaque, hwaddr addr)
{
uint32_t v;
v = jazzio_readw(opaque, addr);
v |= jazzio_readw(opaque, addr + 2) << 16;
return v;
}
static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val)
static void jazzio_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
rc4030State *s = opaque;
uint32_t val = data;
addr &= 0xfff;
DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_plx "\n", val, addr);
trace_jazzio_write(addr, val);
switch (addr) {
/* Local bus int enable mask */
@@ -546,43 +569,24 @@ static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val)
update_jazz_irq(s);
break;
default:
RC4030_ERROR("(jazz io controller) invalid write of 0x%04x at [" TARGET_FMT_plx "]\n", val, addr);
qemu_log_mask(LOG_GUEST_ERROR,
"rc4030/jazzio: invalid write of 0x%02x at 0x%x",
val, (int)addr);
break;
}
}
static void jazzio_writeb(void *opaque, hwaddr addr, uint32_t val)
{
uint32_t old_val = jazzio_readw(opaque, addr & ~0x1);
switch (addr & 1) {
case 0:
val = val | (old_val & 0xff00);
break;
case 1:
val = (val << 8) | (old_val & 0x00ff);
break;
}
jazzio_writew(opaque, addr & ~0x1, val);
}
static void jazzio_writel(void *opaque, hwaddr addr, uint32_t val)
{
jazzio_writew(opaque, addr, val & 0xffff);
jazzio_writew(opaque, addr + 2, (val >> 16) & 0xffff);
}
static const MemoryRegionOps jazzio_ops = {
.old_mmio = {
.read = { jazzio_readb, jazzio_readw, jazzio_readl, },
.write = { jazzio_writeb, jazzio_writew, jazzio_writel, },
},
.read = jazzio_read,
.write = jazzio_write,
.impl.min_access_size = 2,
.impl.max_access_size = 2,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void rc4030_reset(void *opaque)
static void rc4030_reset(DeviceState *dev)
{
rc4030State *s = opaque;
rc4030State *s = RC4030(dev);
int i;
s->config = 0x410; /* some boards seem to accept 0x104 too */
@@ -590,14 +594,14 @@ static void rc4030_reset(void *opaque)
s->invalid_address_register = 0;
memset(s->dma_regs, 0, sizeof(s->dma_regs));
s->dma_tl_base = s->dma_tl_limit = 0;
rc4030_dma_tt_update(s, 0, 0);
s->remote_failed_address = s->memory_failed_address = 0;
s->cache_maint = 0;
s->cache_ptag = s->cache_ltag = 0;
s->cache_bmask = 0;
s->offset210 = 0x18186;
s->memory_refresh_rate = 0x18186;
s->nvram_protect = 7;
for (i = 0; i < 15; i++)
s->rem_speed[i] = 7;
@@ -631,7 +635,7 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
s->cache_ptag = qemu_get_be32(f);
s->cache_ltag = qemu_get_be32(f);
s->cache_bmask = qemu_get_be32(f);
s->offset210 = qemu_get_be32(f);
s->memory_refresh_rate = qemu_get_be32(f);
s->nvram_protect = qemu_get_be32(f);
for (i = 0; i < 15; i++)
s->rem_speed[i] = qemu_get_be32(f);
@@ -663,7 +667,7 @@ static void rc4030_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, s->cache_ptag);
qemu_put_be32(f, s->cache_ltag);
qemu_put_be32(f, s->cache_bmask);
qemu_put_be32(f, s->offset210);
qemu_put_be32(f, s->memory_refresh_rate);
qemu_put_be32(f, s->nvram_protect);
for (i = 0; i < 15; i++)
qemu_put_be32(f, s->rem_speed[i]);
@@ -672,44 +676,6 @@ static void rc4030_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, s->itr);
}
void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)
{
rc4030State *s = opaque;
hwaddr entry_addr;
hwaddr phys_addr;
dma_pagetable_entry entry;
int index;
int ncpy, i;
i = 0;
for (;;) {
if (i == len) {
break;
}
ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1));
if (ncpy > len - i)
ncpy = len - i;
/* Get DMA translation table entry */
index = addr / DMA_PAGESIZE;
if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) {
break;
}
entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry);
/* XXX: not sure. should we really use only lowest bits? */
entry_addr &= 0x7fffffff;
cpu_physical_memory_read(entry_addr, &entry, sizeof(entry));
/* Read/write data at right place */
phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1));
cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write);
i += ncpy;
addr += ncpy;
}
}
static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
{
rc4030State *s = opaque;
@@ -733,32 +699,11 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri
dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
/* Read/write data at right place */
rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write);
address_space_rw(&s->dma_as, dma_addr, MEMTXATTRS_UNSPECIFIED,
buf, len, is_write);
s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
s->dma_regs[n][DMA_REG_COUNT] -= len;
#ifdef DEBUG_RC4030_DMA
{
int i, j;
printf("rc4030 dma: Copying %d bytes %s host %p\n",
len, is_write ? "from" : "to", buf);
for (i = 0; i < len; i += 16) {
int n = 16;
if (n > len - i) {
n = len - i;
}
for (j = 0; j < n; j++)
printf("%02x ", buf[i + j]);
while (j++ < 16)
printf(" ");
printf("| ");
for (j = 0; j < n; j++)
printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
printf("\n");
}
}
#endif
}
struct rc4030DMAState {
@@ -795,31 +740,102 @@ static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
return s;
}
void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
qemu_irq **irqs, rc4030_dma **dmas,
MemoryRegion *sysmem)
static void rc4030_initfn(Object *obj)
{
rc4030State *s;
DeviceState *dev = DEVICE(obj);
rc4030State *s = RC4030(obj);
SysBusDevice *sysbus = SYS_BUS_DEVICE(obj);
s = g_malloc0(sizeof(rc4030State));
qdev_init_gpio_in(dev, rc4030_irq_jazz_request, 16);
*irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16);
*dmas = rc4030_allocate_dmas(s, 4);
sysbus_init_irq(sysbus, &s->timer_irq);
sysbus_init_irq(sysbus, &s->jazz_bus_irq);
s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rc4030_periodic_timer, s);
s->timer_irq = timer;
s->jazz_bus_irq = jazz_bus;
qemu_register_reset(rc4030_reset, s);
register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
rc4030_reset(s);
sysbus_init_mmio(sysbus, &s->iomem_chipset);
sysbus_init_mmio(sysbus, &s->iomem_jazzio);
}
static void rc4030_realize(DeviceState *dev, Error **errp)
{
rc4030State *s = RC4030(dev);
Object *o = OBJECT(dev);
int i;
s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
rc4030_periodic_timer, s);
memory_region_init_io(&s->iomem_chipset, NULL, &rc4030_ops, s,
"rc4030.chipset", 0x300);
memory_region_add_subregion(sysmem, 0x80000000, &s->iomem_chipset);
memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s,
"rc4030.jazzio", 0x00001000);
memory_region_add_subregion(sysmem, 0xf0000000, &s->iomem_jazzio);
return s;
memory_region_init_rom_device(&s->dma_tt, o,
&rc4030_dma_tt_ops, s, "dma-table",
MAX_TL_ENTRIES * sizeof(dma_pagetable_entry),
NULL);
memory_region_init(&s->dma_tt_alias, o, "dma-table-alias", 0);
memory_region_init(&s->dma_mr, o, "dma", INT32_MAX);
for (i = 0; i < MAX_TL_ENTRIES; ++i) {
memory_region_init_alias(&s->dma_mrs[i], o, "dma-alias",
get_system_memory(), 0, DMA_PAGESIZE);
memory_region_set_enabled(&s->dma_mrs[i], false);
memory_region_add_subregion(&s->dma_mr, i * DMA_PAGESIZE,
&s->dma_mrs[i]);
}
address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma");
}
static void rc4030_unrealize(DeviceState *dev, Error **errp)
{
rc4030State *s = RC4030(dev);
int i;
timer_free(s->periodic_timer);
address_space_destroy(&s->dma_as);
object_unparent(OBJECT(&s->dma_tt));
object_unparent(OBJECT(&s->dma_tt_alias));
object_unparent(OBJECT(&s->dma_mr));
for (i = 0; i < MAX_TL_ENTRIES; ++i) {
memory_region_del_subregion(&s->dma_mr, &s->dma_mrs[i]);
object_unparent(OBJECT(&s->dma_mrs[i]));
}
}
static void rc4030_class_init(ObjectClass *klass, void *class_data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = rc4030_realize;
dc->unrealize = rc4030_unrealize;
dc->reset = rc4030_reset;
}
static const TypeInfo rc4030_info = {
.name = TYPE_RC4030,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(rc4030State),
.instance_init = rc4030_initfn,
.class_init = rc4030_class_init,
};
static void rc4030_register_types(void)
{
type_register_static(&rc4030_info);
}
type_init(rc4030_register_types)
DeviceState *rc4030_init(rc4030_dma **dmas, MemoryRegion **dma_mr)
{
DeviceState *dev;
dev = qdev_create(NULL, TYPE_RC4030);
qdev_init_nofail(dev);
*dmas = rc4030_allocate_dmas(dev, 4);
*dma_mr = &RC4030(dev)->dma_mr;
return dev;
}
+6 -7
View File
@@ -833,7 +833,7 @@ static Aml *build_crs(PCIHostState *host,
* Work-around for old bioses
* that do not support multiple root buses
*/
if (range_base || range_base > range_limit) {
if (range_base && range_base <= range_limit) {
aml_append(crs,
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
AML_POS_DECODE, AML_ENTIRE_RANGE,
@@ -854,7 +854,7 @@ static Aml *build_crs(PCIHostState *host,
* Work-around for old bioses
* that do not support multiple root buses
*/
if (range_base || range_base > range_limit) {
if (range_base && range_base <= range_limit) {
aml_append(crs,
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
AML_MAX_FIXED, AML_NON_CACHEABLE,
@@ -865,7 +865,7 @@ static Aml *build_crs(PCIHostState *host,
0,
range_limit - range_base + 1));
crs_range_insert(mem_ranges, range_base, range_limit);
}
}
range_base =
pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH);
@@ -876,7 +876,7 @@ static Aml *build_crs(PCIHostState *host,
* Work-around for old bioses
* that do not support multiple root buses
*/
if (range_base || range_base > range_limit) {
if (range_base && range_base <= range_limit) {
aml_append(crs,
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
AML_MAX_FIXED, AML_NON_CACHEABLE,
@@ -945,9 +945,8 @@ build_ssdt(GArray *table_data, GArray *linker,
scope = aml_scope("\\_SB");
dev = aml_device("PC%.02X", bus_num);
aml_append(dev,
aml_name_decl("_UID", aml_string("PC%.02X", bus_num)));
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A03")));
aml_append(dev, aml_name_decl("_UID", aml_int(bus_num)));
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03")));
aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num)));
if (numa_node != NUMA_NODE_UNASSIGNED) {
+2
View File
@@ -52,6 +52,7 @@
#ifdef CONFIG_XEN
# include <xen/hvm/hvm_info_table.h>
#endif
#include "migration/migration.h"
#define MAX_IDE_BUS 2
@@ -305,6 +306,7 @@ static void pc_init1(MachineState *machine)
static void pc_compat_2_3(MachineState *machine)
{
savevm_skip_section_footers();
}
static void pc_compat_2_2(MachineState *machine)
+2
View File
@@ -45,6 +45,7 @@
#include "hw/usb.h"
#include "hw/cpu/icc_bus.h"
#include "qemu/error-report.h"
#include "migration/migration.h"
/* ICH9 AHCI has 6 ports */
#define MAX_SATA_PORTS 6
@@ -289,6 +290,7 @@ static void pc_q35_init(MachineState *machine)
static void pc_compat_2_3(MachineState *machine)
{
savevm_skip_section_footers();
}
static void pc_compat_2_2(MachineState *machine)
+12 -20
View File
@@ -2561,6 +2561,7 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = {
.name ="ide_drive/atapi/gesn_state",
.version_id = 1,
.minimum_version_id = 1,
.needed = ide_atapi_gesn_needed,
.fields = (VMStateField[]) {
VMSTATE_BOOL(events.new_media, IDEState),
VMSTATE_BOOL(events.eject_request, IDEState),
@@ -2572,6 +2573,7 @@ static const VMStateDescription vmstate_ide_tray_state = {
.name = "ide_drive/tray_state",
.version_id = 1,
.minimum_version_id = 1,
.needed = ide_tray_state_needed,
.fields = (VMStateField[]) {
VMSTATE_BOOL(tray_open, IDEState),
VMSTATE_BOOL(tray_locked, IDEState),
@@ -2585,6 +2587,7 @@ static const VMStateDescription vmstate_ide_drive_pio_state = {
.minimum_version_id = 1,
.pre_save = ide_drive_pio_pre_save,
.post_load = ide_drive_pio_post_load,
.needed = ide_drive_pio_state_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(req_nb_sectors, IDEState),
VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
@@ -2626,19 +2629,11 @@ const VMStateDescription vmstate_ide_drive = {
VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection []) {
{
.vmsd = &vmstate_ide_drive_pio_state,
.needed = ide_drive_pio_state_needed,
}, {
.vmsd = &vmstate_ide_tray_state,
.needed = ide_tray_state_needed,
}, {
.vmsd = &vmstate_ide_atapi_gesn_state,
.needed = ide_atapi_gesn_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_ide_drive_pio_state,
&vmstate_ide_tray_state,
&vmstate_ide_atapi_gesn_state,
NULL
}
};
@@ -2646,6 +2641,7 @@ static const VMStateDescription vmstate_ide_error_status = {
.name ="ide_bus/error",
.version_id = 2,
.minimum_version_id = 1,
.needed = ide_error_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(error_status, IDEBus),
VMSTATE_INT64_V(retry_sector_num, IDEBus, 2),
@@ -2664,13 +2660,9 @@ const VMStateDescription vmstate_ide_bus = {
VMSTATE_UINT8(unit, IDEBus),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection []) {
{
.vmsd = &vmstate_ide_error_status,
.needed = ide_error_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_ide_error_status,
NULL
}
};
+6 -10
View File
@@ -350,6 +350,7 @@ static const VMStateDescription vmstate_bmdma_current = {
.name = "ide bmdma_current",
.version_id = 1,
.minimum_version_id = 1,
.needed = ide_bmdma_current_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(cur_addr, BMDMAState),
VMSTATE_UINT32(cur_prd_last, BMDMAState),
@@ -363,6 +364,7 @@ static const VMStateDescription vmstate_bmdma_status = {
.name ="ide bmdma/status",
.version_id = 1,
.minimum_version_id = 1,
.needed = ide_bmdma_status_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(status, BMDMAState),
VMSTATE_END_OF_LIST()
@@ -383,16 +385,10 @@ static const VMStateDescription vmstate_bmdma = {
VMSTATE_UINT8(migration_retry_unit, BMDMAState),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection []) {
{
.vmsd = &vmstate_bmdma_current,
.needed = ide_bmdma_current_needed,
}, {
.vmsd = &vmstate_bmdma_status,
.needed = ide_bmdma_status_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_bmdma_current,
&vmstate_bmdma_status,
NULL
}
};
+15 -17
View File
@@ -391,23 +391,24 @@ static int kbd_outport_post_load(void *opaque, int version_id)
return 0;
}
static const VMStateDescription vmstate_kbd_outport = {
.name = "pckbd_outport",
.version_id = 1,
.minimum_version_id = 1,
.post_load = kbd_outport_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT8(outport, KBDState),
VMSTATE_END_OF_LIST()
}
};
static bool kbd_outport_needed(void *opaque)
{
KBDState *s = opaque;
return s->outport != kbd_outport_default(s);
}
static const VMStateDescription vmstate_kbd_outport = {
.name = "pckbd_outport",
.version_id = 1,
.minimum_version_id = 1,
.post_load = kbd_outport_post_load,
.needed = kbd_outport_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(outport, KBDState),
VMSTATE_END_OF_LIST()
}
};
static int kbd_post_load(void *opaque, int version_id)
{
KBDState *s = opaque;
@@ -430,12 +431,9 @@ static const VMStateDescription vmstate_kbd = {
VMSTATE_UINT8(pending, KBDState),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_kbd_outport,
.needed = kbd_outport_needed,
},
VMSTATE_END_OF_LIST()
.subsections = (const VMStateDescription*[]) {
&vmstate_kbd_outport,
NULL
}
};
+4 -7
View File
@@ -677,6 +677,7 @@ static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
.version_id = 3,
.minimum_version_id = 2,
.post_load = ps2_kbd_ledstate_post_load,
.needed = ps2_keyboard_ledstate_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(ledstate, PS2KbdState),
VMSTATE_END_OF_LIST()
@@ -717,13 +718,9 @@ static const VMStateDescription vmstate_ps2_keyboard = {
VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection []) {
{
.vmsd = &vmstate_ps2_keyboard_ledstate,
.needed = ps2_keyboard_ledstate_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_ps2_keyboard_ledstate,
NULL
}
};
+4 -6
View File
@@ -369,6 +369,7 @@ static const VMStateDescription vmstate_apic_common_sipi = {
.name = "apic_sipi",
.version_id = 1,
.minimum_version_id = 1,
.needed = apic_common_sipi_needed,
.fields = (VMStateField[]) {
VMSTATE_INT32(sipi_vector, APICCommonState),
VMSTATE_INT32(wait_for_sipi, APICCommonState),
@@ -408,12 +409,9 @@ static const VMStateDescription vmstate_apic_common = {
APICCommonState), /* open-coded timer state */
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_apic_common_sipi,
.needed = apic_common_sipi_needed,
},
VMSTATE_END_OF_LIST()
.subsections = (const VMStateDescription*[]) {
&vmstate_apic_common_sipi,
NULL
}
};
+4 -6
View File
@@ -650,6 +650,7 @@ static const VMStateDescription vmstate_ich9_rst_cnt = {
.name = "ICH9LPC/rst_cnt",
.version_id = 1,
.minimum_version_id = 1,
.needed = ich9_rst_cnt_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(rst_cnt, ICH9LPCState),
VMSTATE_END_OF_LIST()
@@ -669,12 +670,9 @@ static const VMStateDescription vmstate_ich9_lpc = {
VMSTATE_UINT32(sci_level, ICH9LPCState),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_ich9_rst_cnt,
.needed = ich9_rst_cnt_needed
},
{ 0 }
.subsections = (const VMStateDescription*[]) {
&vmstate_ich9_rst_cnt,
NULL
}
};
+2 -1
View File
@@ -1,4 +1,5 @@
obj-y += mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
obj-y += mips_r4k.o mips_malta.o mips_mipssim.o
obj-y += addr.o cputimer.o mips_int.o
obj-$(CONFIG_JAZZ) += mips_jazz.o
obj-$(CONFIG_FULONG) += mips_fulong2e.o
obj-y += gt64xxx_pci.o
+33 -20
View File
@@ -135,16 +135,16 @@ static void mips_jazz_init(MachineState *machine,
MIPSCPU *cpu;
CPUClass *cc;
CPUMIPSState *env;
qemu_irq *rc4030, *i8259;
qemu_irq *i8259;
rc4030_dma *dmas;
void* rc4030_opaque;
MemoryRegion *rc4030_dma_mr;
MemoryRegion *isa_mem = g_new(MemoryRegion, 1);
MemoryRegion *isa_io = g_new(MemoryRegion, 1);
MemoryRegion *rtc = g_new(MemoryRegion, 1);
MemoryRegion *i8042 = g_new(MemoryRegion, 1);
MemoryRegion *dma_dummy = g_new(MemoryRegion, 1);
NICInfo *nd;
DeviceState *dev;
DeviceState *dev, *rc4030;
SysBusDevice *sysbus;
ISABus *isa_bus;
ISADevice *pit;
@@ -157,12 +157,7 @@ static void mips_jazz_init(MachineState *machine,
/* init CPUs */
if (cpu_model == NULL) {
#ifdef TARGET_MIPS64
cpu_model = "R4000";
#else
/* FIXME: All wrong, this maybe should be R3000 for the older JAZZs. */
cpu_model = "24Kf";
#endif
}
cpu = cpu_mips_init(cpu_model);
if (cpu == NULL) {
@@ -218,8 +213,14 @@ static void mips_jazz_init(MachineState *machine,
cpu_mips_clock_init(env);
/* Chipset */
rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas,
address_space);
rc4030 = rc4030_init(&dmas, &rc4030_dma_mr);
sysbus = SYS_BUS_DEVICE(rc4030);
sysbus_connect_irq(sysbus, 0, env->irq[6]);
sysbus_connect_irq(sysbus, 1, env->irq[3]);
memory_region_add_subregion(address_space, 0x80000000,
sysbus_mmio_get_region(sysbus, 0));
memory_region_add_subregion(address_space, 0xf0000000,
sysbus_mmio_get_region(sysbus, 1));
memory_region_init_io(dma_dummy, NULL, &dma_dummy_ops, NULL, "dummy_dma", 0x1000);
memory_region_add_subregion(address_space, 0x8000d000, dma_dummy);
@@ -246,7 +247,7 @@ static void mips_jazz_init(MachineState *machine,
sysbus = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(sysbus, 0, 0x60080000);
sysbus_mmio_map(sysbus, 1, 0x40000000);
sysbus_connect_irq(sysbus, 0, rc4030[3]);
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 3));
{
/* Simple ROM, so user doesn't have to provide one */
MemoryRegion *rom_mr = g_new(MemoryRegion, 1);
@@ -272,8 +273,17 @@ static void mips_jazz_init(MachineState *machine,
if (!nd->model)
nd->model = g_strdup("dp83932");
if (strcmp(nd->model, "dp83932") == 0) {
dp83932_init(nd, 0x80001000, 2, get_system_memory(), rc4030[4],
rc4030_opaque, rc4030_dma_memory_rw);
qemu_check_nic_model(nd, "dp83932");
dev = qdev_create(NULL, "dp8393x");
qdev_set_nic_properties(dev, nd);
qdev_prop_set_uint8(dev, "it_shift", 2);
qdev_prop_set_ptr(dev, "dma_mr", rc4030_dma_mr);
qdev_init_nofail(dev);
sysbus = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(sysbus, 0, 0x80001000);
sysbus_mmio_map(sysbus, 1, 0x8000b000);
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 4));
break;
} else if (is_help_option(nd->model)) {
fprintf(stderr, "qemu: Supported NICs: dp83932\n");
@@ -287,7 +297,7 @@ static void mips_jazz_init(MachineState *machine,
/* SCSI adapter */
esp_init(0x80002000, 0,
rc4030_dma_read, rc4030_dma_write, dmas[0],
rc4030[5], &esp_reset, &dma_enable);
qdev_get_gpio_in(rc4030, 5), &esp_reset, &dma_enable);
/* Floppy */
if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) {
@@ -297,7 +307,7 @@ static void mips_jazz_init(MachineState *machine,
for (n = 0; n < MAX_FD; n++) {
fds[n] = drive_get(IF_FLOPPY, 0, n);
}
fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds);
fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), 0, 0x80003000, fds);
/* Real time clock */
rtc_init(isa_bus, 1980, NULL);
@@ -305,23 +315,26 @@ static void mips_jazz_init(MachineState *machine,
memory_region_add_subregion(address_space, 0x80004000, rtc);
/* Keyboard (i8042) */
i8042_mm_init(rc4030[6], rc4030[7], i8042, 0x1000, 0x1);
i8042_mm_init(qdev_get_gpio_in(rc4030, 6), qdev_get_gpio_in(rc4030, 7),
i8042, 0x1000, 0x1);
memory_region_add_subregion(address_space, 0x80005000, i8042);
/* Serial ports */
if (serial_hds[0]) {
serial_mm_init(address_space, 0x80006000, 0, rc4030[8], 8000000/16,
serial_mm_init(address_space, 0x80006000, 0,
qdev_get_gpio_in(rc4030, 8), 8000000/16,
serial_hds[0], DEVICE_NATIVE_ENDIAN);
}
if (serial_hds[1]) {
serial_mm_init(address_space, 0x80007000, 0, rc4030[9], 8000000/16,
serial_mm_init(address_space, 0x80007000, 0,
qdev_get_gpio_in(rc4030, 9), 8000000/16,
serial_hds[1], DEVICE_NATIVE_ENDIAN);
}
/* Parallel port */
if (parallel_hds[0])
parallel_mm_init(address_space, 0x80008000, 0, rc4030[0],
parallel_hds[0]);
parallel_mm_init(address_space, 0x80008000, 0,
qdev_get_gpio_in(rc4030, 0), parallel_hds[0]);
/* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
+9 -6
View File
@@ -97,7 +97,7 @@ typedef struct {
static ISADevice *pit;
static struct _loaderparams {
int ram_size;
int ram_size, ram_low_size;
const char *kernel_filename;
const char *kernel_cmdline;
const char *initrd_filename;
@@ -641,8 +641,8 @@ static void write_bootloader (CPUMIPSState *env, uint8_t *base,
stl_p(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a1, low(ENVP_ADDR) */
stl_p(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
stl_p(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
stl_p(p++, 0x3c070000 | (loaderparams.ram_size >> 16)); /* lui a3, high(ram_size) */
stl_p(p++, 0x34e70000 | (loaderparams.ram_size & 0xffff)); /* ori a3, a3, low(ram_size) */
stl_p(p++, 0x3c070000 | (loaderparams.ram_low_size >> 16)); /* lui a3, high(ram_low_size) */
stl_p(p++, 0x34e70000 | (loaderparams.ram_low_size & 0xffff)); /* ori a3, a3, low(ram_low_size) */
/* Load BAR registers as done by YAMON */
stl_p(p++, 0x3c09b400); /* lui t1, 0xb400 */
@@ -851,8 +851,10 @@ static int64_t load_kernel (void)
}
prom_set(prom_buf, prom_index++, "memsize");
prom_set(prom_buf, prom_index++, "%i",
MIN(loaderparams.ram_size, 256 << 20));
prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_low_size);
prom_set(prom_buf, prom_index++, "ememsize");
prom_set(prom_buf, prom_index++, "%u", loaderparams.ram_size);
prom_set(prom_buf, prom_index++, "modetty0");
prom_set(prom_buf, prom_index++, "38400n8r");
@@ -1054,7 +1056,8 @@ void mips_malta_init(MachineState *machine)
}
/* Write a small bootloader to the flash location. */
loaderparams.ram_size = ram_low_size;
loaderparams.ram_size = ram_size;
loaderparams.ram_low_size = ram_low_size;
loaderparams.kernel_filename = kernel_filename;
loaderparams.kernel_cmdline = kernel_cmdline;
loaderparams.initrd_filename = initrd_filename;
+1
View File
@@ -39,3 +39,4 @@ obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
common-obj-$(CONFIG_ROCKER) += rocker/rocker.o rocker/rocker_fp.o \
rocker/rocker_desc.o rocker/rocker_world.o \
rocker/rocker_of_dpa.o
obj-$(call lnot,$(CONFIG_ROCKER)) += rocker/qmp-norocker.o
+187 -188
View File
@@ -17,20 +17,15 @@
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "hw/hw.h"
#include "qemu/timer.h"
#include "hw/sysbus.h"
#include "hw/devices.h"
#include "net/net.h"
#include "hw/mips/mips.h"
#include "qemu/timer.h"
#include <zlib.h>
//#define DEBUG_SONIC
/* Calculate CRCs properly on Rx packets */
#define SONIC_CALCULATE_RXCRC
#if defined(SONIC_CALCULATE_RXCRC)
/* For crc32 */
#include <zlib.h>
#endif
#define SONIC_PROM_SIZE 0x1000
#ifdef DEBUG_SONIC
#define DPRINTF(fmt, ...) \
@@ -145,9 +140,14 @@ do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
#define SONIC_ISR_PINT 0x0800
#define SONIC_ISR_LCD 0x1000
#define TYPE_DP8393X "dp8393x"
#define DP8393X(obj) OBJECT_CHECK(dp8393xState, (obj), TYPE_DP8393X)
typedef struct dp8393xState {
SysBusDevice parent_obj;
/* Hardware */
int it_shift;
uint8_t it_shift;
qemu_irq irq;
#ifdef DEBUG_SONIC
int irq_level;
@@ -156,8 +156,8 @@ typedef struct dp8393xState {
int64_t wt_last_update;
NICConf conf;
NICState *nic;
MemoryRegion *address_space;
MemoryRegion mmio;
MemoryRegion prom;
/* Registers */
uint8_t cam[16][6];
@@ -168,8 +168,8 @@ typedef struct dp8393xState {
int loopback_packet;
/* Memory access */
void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write);
void* mem_opaque;
void *dma_mr;
AddressSpace as;
} dp8393xState;
static void dp8393x_update_irq(dp8393xState *s)
@@ -190,7 +190,7 @@ static void dp8393x_update_irq(dp8393xState *s)
qemu_set_irq(s->irq, level);
}
static void do_load_cam(dp8393xState *s)
static void dp8393x_do_load_cam(dp8393xState *s)
{
uint16_t data[8];
int width, size;
@@ -201,9 +201,9 @@ static void do_load_cam(dp8393xState *s)
while (s->regs[SONIC_CDC] & 0x1f) {
/* Fill current entry */
s->memory_rw(s->mem_opaque,
address_space_rw(&s->as,
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
(uint8_t *)data, size, 0);
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
s->cam[index][0] = data[1 * width] & 0xff;
s->cam[index][1] = data[1 * width] >> 8;
s->cam[index][2] = data[2 * width] & 0xff;
@@ -220,9 +220,9 @@ static void do_load_cam(dp8393xState *s)
}
/* Read CAM enable */
s->memory_rw(s->mem_opaque,
address_space_rw(&s->as,
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
(uint8_t *)data, size, 0);
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
s->regs[SONIC_CE] = data[0 * width];
DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
@@ -232,7 +232,7 @@ static void do_load_cam(dp8393xState *s)
dp8393x_update_irq(s);
}
static void do_read_rra(dp8393xState *s)
static void dp8393x_do_read_rra(dp8393xState *s)
{
uint16_t data[8];
int width, size;
@@ -240,9 +240,9 @@ static void do_read_rra(dp8393xState *s)
/* Read memory */
width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
size = sizeof(uint16_t) * 4 * width;
s->memory_rw(s->mem_opaque,
address_space_rw(&s->as,
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
(uint8_t *)data, size, 0);
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
/* Update SONIC registers */
s->regs[SONIC_CRBA0] = data[0 * width];
@@ -272,7 +272,7 @@ static void do_read_rra(dp8393xState *s)
s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
}
static void do_software_reset(dp8393xState *s)
static void dp8393x_do_software_reset(dp8393xState *s)
{
timer_del(s->watchdog);
@@ -280,7 +280,7 @@ static void do_software_reset(dp8393xState *s)
s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
}
static void set_next_tick(dp8393xState *s)
static void dp8393x_set_next_tick(dp8393xState *s)
{
uint32_t ticks;
int64_t delay;
@@ -296,7 +296,7 @@ static void set_next_tick(dp8393xState *s)
timer_mod(s->watchdog, s->wt_last_update + delay);
}
static void update_wt_regs(dp8393xState *s)
static void dp8393x_update_wt_regs(dp8393xState *s)
{
int64_t elapsed;
uint32_t val;
@@ -311,33 +311,33 @@ static void update_wt_regs(dp8393xState *s)
val -= elapsed / 5000000;
s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
s->regs[SONIC_WT0] = (val >> 0) & 0xffff;
set_next_tick(s);
dp8393x_set_next_tick(s);
}
static void do_start_timer(dp8393xState *s)
static void dp8393x_do_start_timer(dp8393xState *s)
{
s->regs[SONIC_CR] &= ~SONIC_CR_STP;
set_next_tick(s);
dp8393x_set_next_tick(s);
}
static void do_stop_timer(dp8393xState *s)
static void dp8393x_do_stop_timer(dp8393xState *s)
{
s->regs[SONIC_CR] &= ~SONIC_CR_ST;
update_wt_regs(s);
dp8393x_update_wt_regs(s);
}
static void do_receiver_enable(dp8393xState *s)
static void dp8393x_do_receiver_enable(dp8393xState *s)
{
s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
}
static void do_receiver_disable(dp8393xState *s)
static void dp8393x_do_receiver_disable(dp8393xState *s)
{
s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
}
static void do_transmit_packets(dp8393xState *s)
static void dp8393x_do_transmit_packets(dp8393xState *s)
{
NetClientState *nc = qemu_get_queue(s->nic);
uint16_t data[12];
@@ -353,9 +353,9 @@ static void do_transmit_packets(dp8393xState *s)
(s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
size = sizeof(uint16_t) * 6 * width;
s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
s->memory_rw(s->mem_opaque,
address_space_rw(&s->as,
((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
(uint8_t *)data, size, 0);
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
tx_len = 0;
/* Update registers */
@@ -379,18 +379,18 @@ static void do_transmit_packets(dp8393xState *s)
if (tx_len + len > sizeof(s->tx_buffer)) {
len = sizeof(s->tx_buffer) - tx_len;
}
s->memory_rw(s->mem_opaque,
address_space_rw(&s->as,
(s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
&s->tx_buffer[tx_len], len, 0);
MEMTXATTRS_UNSPECIFIED, &s->tx_buffer[tx_len], len, 0);
tx_len += len;
i++;
if (i != s->regs[SONIC_TFC]) {
/* Read next fragment details */
size = sizeof(uint16_t) * 3 * width;
s->memory_rw(s->mem_opaque,
address_space_rw(&s->as,
((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
(uint8_t *)data, size, 0);
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
s->regs[SONIC_TSA0] = data[0 * width];
s->regs[SONIC_TSA1] = data[1 * width];
s->regs[SONIC_TFS] = data[2 * width];
@@ -422,16 +422,16 @@ static void do_transmit_packets(dp8393xState *s)
/* Write status */
data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
size = sizeof(uint16_t) * width;
s->memory_rw(s->mem_opaque,
address_space_rw(&s->as,
(s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
(uint8_t *)data, size, 1);
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
/* Read footer of packet */
size = sizeof(uint16_t) * width;
s->memory_rw(s->mem_opaque,
address_space_rw(&s->as,
((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
(uint8_t *)data, size, 0);
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
if (data[0 * width] & 0x1) {
/* EOL detected */
@@ -446,12 +446,12 @@ static void do_transmit_packets(dp8393xState *s)
dp8393x_update_irq(s);
}
static void do_halt_transmission(dp8393xState *s)
static void dp8393x_do_halt_transmission(dp8393xState *s)
{
/* Nothing to do */
}
static void do_command(dp8393xState *s, uint16_t command)
static void dp8393x_do_command(dp8393xState *s, uint16_t command)
{
if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
s->regs[SONIC_CR] &= ~SONIC_CR_RST;
@@ -461,34 +461,36 @@ static void do_command(dp8393xState *s, uint16_t command)
s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
if (command & SONIC_CR_HTX)
do_halt_transmission(s);
dp8393x_do_halt_transmission(s);
if (command & SONIC_CR_TXP)
do_transmit_packets(s);
dp8393x_do_transmit_packets(s);
if (command & SONIC_CR_RXDIS)
do_receiver_disable(s);
dp8393x_do_receiver_disable(s);
if (command & SONIC_CR_RXEN)
do_receiver_enable(s);
dp8393x_do_receiver_enable(s);
if (command & SONIC_CR_STP)
do_stop_timer(s);
dp8393x_do_stop_timer(s);
if (command & SONIC_CR_ST)
do_start_timer(s);
dp8393x_do_start_timer(s);
if (command & SONIC_CR_RST)
do_software_reset(s);
dp8393x_do_software_reset(s);
if (command & SONIC_CR_RRRA)
do_read_rra(s);
dp8393x_do_read_rra(s);
if (command & SONIC_CR_LCAM)
do_load_cam(s);
dp8393x_do_load_cam(s);
}
static uint16_t read_register(dp8393xState *s, int reg)
static uint64_t dp8393x_read(void *opaque, hwaddr addr, unsigned int size)
{
dp8393xState *s = opaque;
int reg = addr >> s->it_shift;
uint16_t val = 0;
switch (reg) {
/* Update data before reading it */
case SONIC_WT0:
case SONIC_WT1:
update_wt_regs(s);
dp8393x_update_wt_regs(s);
val = s->regs[reg];
break;
/* Accept read to some registers only when in reset mode */
@@ -510,14 +512,18 @@ static uint16_t read_register(dp8393xState *s, int reg)
return val;
}
static void write_register(dp8393xState *s, int reg, uint16_t val)
static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
dp8393xState *s = opaque;
int reg = addr >> s->it_shift;
DPRINTF("write 0x%04x to reg %s\n", (uint16_t)data, reg_names[reg]);
switch (reg) {
/* Command register */
case SONIC_CR:
do_command(s, val);
dp8393x_do_command(s, data);
break;
/* Prevent write to read-only registers */
case SONIC_CAP2:
@@ -530,37 +536,37 @@ static void write_register(dp8393xState *s, int reg, uint16_t val)
/* Accept write to some registers only when in reset mode */
case SONIC_DCR:
if (s->regs[SONIC_CR] & SONIC_CR_RST) {
s->regs[reg] = val & 0xbfff;
s->regs[reg] = data & 0xbfff;
} else {
DPRINTF("writing to DCR invalid\n");
}
break;
case SONIC_DCR2:
if (s->regs[SONIC_CR] & SONIC_CR_RST) {
s->regs[reg] = val & 0xf017;
s->regs[reg] = data & 0xf017;
} else {
DPRINTF("writing to DCR2 invalid\n");
}
break;
/* 12 lower bytes are Read Only */
case SONIC_TCR:
s->regs[reg] = val & 0xf000;
s->regs[reg] = data & 0xf000;
break;
/* 9 lower bytes are Read Only */
case SONIC_RCR:
s->regs[reg] = val & 0xffe0;
s->regs[reg] = data & 0xffe0;
break;
/* Ignore most significant bit */
case SONIC_IMR:
s->regs[reg] = val & 0x7fff;
s->regs[reg] = data & 0x7fff;
dp8393x_update_irq(s);
break;
/* Clear bits by writing 1 to them */
case SONIC_ISR:
val &= s->regs[reg];
s->regs[reg] &= ~val;
if (val & SONIC_ISR_RBE) {
do_read_rra(s);
data &= s->regs[reg];
s->regs[reg] &= ~data;
if (data & SONIC_ISR_RBE) {
dp8393x_do_read_rra(s);
}
dp8393x_update_irq(s);
break;
@@ -569,24 +575,32 @@ static void write_register(dp8393xState *s, int reg, uint16_t val)
case SONIC_REA:
case SONIC_RRP:
case SONIC_RWP:
s->regs[reg] = val & 0xfffe;
s->regs[reg] = data & 0xfffe;
break;
/* Invert written value for some registers */
case SONIC_CRCT:
case SONIC_FAET:
case SONIC_MPT:
s->regs[reg] = val ^ 0xffff;
s->regs[reg] = data ^ 0xffff;
break;
/* All other registers have no special contrainst */
default:
s->regs[reg] = val;
s->regs[reg] = data;
}
if (reg == SONIC_WT0 || reg == SONIC_WT1) {
set_next_tick(s);
dp8393x_set_next_tick(s);
}
}
static const MemoryRegionOps dp8393x_ops = {
.read = dp8393x_read,
.write = dp8393x_write,
.impl.min_access_size = 2,
.impl.max_access_size = 2,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void dp8393x_watchdog(void *opaque)
{
dp8393xState *s = opaque;
@@ -597,84 +611,14 @@ static void dp8393x_watchdog(void *opaque)
s->regs[SONIC_WT1] = 0xffff;
s->regs[SONIC_WT0] = 0xffff;
set_next_tick(s);
dp8393x_set_next_tick(s);
/* Signal underflow */
s->regs[SONIC_ISR] |= SONIC_ISR_TC;
dp8393x_update_irq(s);
}
static uint32_t dp8393x_readw(void *opaque, hwaddr addr)
{
dp8393xState *s = opaque;
int reg;
if ((addr & ((1 << s->it_shift) - 1)) != 0) {
return 0;
}
reg = addr >> s->it_shift;
return read_register(s, reg);
}
static uint32_t dp8393x_readb(void *opaque, hwaddr addr)
{
uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
return (v >> (8 * (addr & 0x1))) & 0xff;
}
static uint32_t dp8393x_readl(void *opaque, hwaddr addr)
{
uint32_t v;
v = dp8393x_readw(opaque, addr);
v |= dp8393x_readw(opaque, addr + 2) << 16;
return v;
}
static void dp8393x_writew(void *opaque, hwaddr addr, uint32_t val)
{
dp8393xState *s = opaque;
int reg;
if ((addr & ((1 << s->it_shift) - 1)) != 0) {
return;
}
reg = addr >> s->it_shift;
write_register(s, reg, (uint16_t)val);
}
static void dp8393x_writeb(void *opaque, hwaddr addr, uint32_t val)
{
uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
switch (addr & 3) {
case 0:
val = val | (old_val & 0xff00);
break;
case 1:
val = (val << 8) | (old_val & 0x00ff);
break;
}
dp8393x_writew(opaque, addr & ~0x1, val);
}
static void dp8393x_writel(void *opaque, hwaddr addr, uint32_t val)
{
dp8393x_writew(opaque, addr, val & 0xffff);
dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
}
static const MemoryRegionOps dp8393x_ops = {
.old_mmio = {
.read = { dp8393x_readb, dp8393x_readw, dp8393x_readl, },
.write = { dp8393x_writeb, dp8393x_writew, dp8393x_writel, },
},
.endianness = DEVICE_NATIVE_ENDIAN,
};
static int nic_can_receive(NetClientState *nc)
static int dp8393x_can_receive(NetClientState *nc)
{
dp8393xState *s = qemu_get_nic_opaque(nc);
@@ -685,7 +629,8 @@ static int nic_can_receive(NetClientState *nc)
return 1;
}
static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf,
int size)
{
static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
int i;
@@ -723,7 +668,8 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
return -1;
}
static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
size_t size)
{
dp8393xState *s = qemu_get_nic_opaque(nc);
uint16_t data[10];
@@ -737,7 +683,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
packet_type = receive_filter(s, buf, size);
packet_type = dp8393x_receive_filter(s, buf, size);
if (packet_type < 0) {
DPRINTF("packet not for netcard\n");
return -1;
@@ -750,7 +696,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
/* Are we still in resource exhaustion? */
size = sizeof(uint16_t) * 1 * width;
address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED,
(uint8_t *)data, size, 0);
if (data[0 * width] & 0x1) {
/* Still EOL ; stop reception */
return -1;
@@ -764,18 +711,16 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
/* Calculate the ethernet checksum */
#ifdef SONIC_CALCULATE_RXCRC
checksum = cpu_to_le32(crc32(0, buf, rx_len));
#else
checksum = 0;
#endif
/* Put packet into RBA */
DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
address_space_rw(&s->as, address,
MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, rx_len, 1);
address += rx_len;
s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
address_space_rw(&s->as, address,
MEMTXATTRS_UNSPECIFIED, (uint8_t *)&checksum, 4, 1);
rx_len += 4;
s->regs[SONIC_CRBA1] = address >> 16;
s->regs[SONIC_CRBA0] = address & 0xffff;
@@ -803,29 +748,30 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
size = sizeof(uint16_t) * 5 * width;
s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
address_space_rw(&s->as, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA],
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
/* Move to next descriptor */
size = sizeof(uint16_t) * width;
s->memory_rw(s->mem_opaque,
address_space_rw(&s->as,
((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
(uint8_t *)data, size, 0);
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
s->regs[SONIC_LLFA] = data[0 * width];
if (s->regs[SONIC_LLFA] & 0x1) {
/* EOL detected */
s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
} else {
data[0 * width] = 0; /* in_use */
s->memory_rw(s->mem_opaque,
address_space_rw(&s->as,
((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
(uint8_t *)data, size, 1);
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1);
s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
/* Read next RRA */
do_read_rra(s);
dp8393x_do_read_rra(s);
}
}
@@ -835,11 +781,12 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
return size;
}
static void nic_reset(void *opaque)
static void dp8393x_reset(DeviceState *dev)
{
dp8393xState *s = opaque;
dp8393xState *s = DP8393X(dev);
timer_del(s->watchdog);
memset(s->regs, 0, sizeof(s->regs));
s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
@@ -862,39 +809,91 @@ static void nic_reset(void *opaque)
static NetClientInfo net_dp83932_info = {
.type = NET_CLIENT_OPTIONS_KIND_NIC,
.size = sizeof(NICState),
.can_receive = nic_can_receive,
.receive = nic_receive,
.can_receive = dp8393x_can_receive,
.receive = dp8393x_receive,
};
void dp83932_init(NICInfo *nd, hwaddr base, int it_shift,
MemoryRegion *address_space,
qemu_irq irq, void* mem_opaque,
void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write))
static void dp8393x_instance_init(Object *obj)
{
dp8393xState *s;
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
dp8393xState *s = DP8393X(obj);
qemu_check_nic_model(nd, "dp83932");
sysbus_init_mmio(sbd, &s->mmio);
sysbus_init_mmio(sbd, &s->prom);
sysbus_init_irq(sbd, &s->irq);
}
s = g_malloc0(sizeof(dp8393xState));
static void dp8393x_realize(DeviceState *dev, Error **errp)
{
dp8393xState *s = DP8393X(dev);
int i, checksum;
uint8_t *prom;
address_space_init(&s->as, s->dma_mr, "dp8393x");
memory_region_init_io(&s->mmio, OBJECT(dev), &dp8393x_ops, s,
"dp8393x-regs", 0x40 << s->it_shift);
s->nic = qemu_new_nic(&net_dp83932_info, &s->conf,
object_get_typename(OBJECT(dev)), dev->id, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
s->address_space = address_space;
s->mem_opaque = mem_opaque;
s->memory_rw = memory_rw;
s->it_shift = it_shift;
s->irq = irq;
s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s);
s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
s->conf.macaddr = nd->macaddr;
s->conf.peers.ncs[0] = nd->netdev;
s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
qemu_register_reset(nic_reset, s);
nic_reset(s);
memory_region_init_io(&s->mmio, NULL, &dp8393x_ops, s,
"dp8393x", 0x40 << it_shift);
memory_region_add_subregion(address_space, base, &s->mmio);
memory_region_init_rom_device(&s->prom, OBJECT(dev), NULL, NULL,
"dp8393x-prom", SONIC_PROM_SIZE, NULL);
prom = memory_region_get_ram_ptr(&s->prom);
checksum = 0;
for (i = 0; i < 6; i++) {
prom[i] = s->conf.macaddr.a[i];
checksum += prom[i];
if (checksum > 0xff) {
checksum = (checksum + 1) & 0xff;
}
}
prom[7] = 0xff - checksum;
}
static const VMStateDescription vmstate_dp8393x = {
.name = "dp8393x",
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField []) {
VMSTATE_BUFFER_UNSAFE(cam, dp8393xState, 0, 16 * 6),
VMSTATE_UINT16_ARRAY(regs, dp8393xState, 0x40),
VMSTATE_END_OF_LIST()
}
};
static Property dp8393x_properties[] = {
DEFINE_NIC_PROPERTIES(dp8393xState, conf),
DEFINE_PROP_PTR("dma_mr", dp8393xState, dma_mr),
DEFINE_PROP_UINT8("it_shift", dp8393xState, it_shift, 0),
DEFINE_PROP_END_OF_LIST(),
};
static void dp8393x_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->realize = dp8393x_realize;
dc->reset = dp8393x_reset;
dc->vmsd = &vmstate_dp8393x;
dc->props = dp8393x_properties;
}
static const TypeInfo dp8393x_info = {
.name = TYPE_DP8393X,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(dp8393xState),
.instance_init = dp8393x_instance_init,
.class_init = dp8393x_class_init,
};
static void dp8393x_register_types(void)
{
type_register_static(&dp8393x_info);
}
type_init(dp8393x_register_types)
+4 -7
View File
@@ -1370,6 +1370,7 @@ static const VMStateDescription vmstate_e1000_mit_state = {
.name = "e1000/mit_state",
.version_id = 1,
.minimum_version_id = 1,
.needed = e1000_mit_state_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(mac_reg[RDTR], E1000State),
VMSTATE_UINT32(mac_reg[RADV], E1000State),
@@ -1457,13 +1458,9 @@ static const VMStateDescription vmstate_e1000 = {
VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_e1000_mit_state,
.needed = e1000_mit_state_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_e1000_mit_state,
NULL
}
};
+8
View File
@@ -1241,6 +1241,14 @@ static void pcnet_transmit(PCNetState *s)
}
bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
/* if multi-tmd packet outsizes s->buffer then skip it silently.
Note: this is not what real hw does */
if (s->xmit_pos + bcnt > sizeof(s->buffer)) {
s->xmit_pos = -1;
goto txdone;
}
s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
s->xmit_pos += bcnt;
+50
View File
@@ -0,0 +1,50 @@
/*
* QMP Target options - Commands handled based on a target config
* versus a host config
*
* Copyright (c) 2015 David Ahern <dsahern@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "qemu-common.h"
#include "qmp-commands.h"
#include "qapi/qmp/qerror.h"
RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "rocker");
return NULL;
};
RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "rocker");
return NULL;
};
RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name,
bool has_tbl_id,
uint32_t tbl_id,
Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "rocker");
return NULL;
};
RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name,
bool has_type,
uint8_t type,
Error **errp)
{
error_set(errp, QERR_FEATURE_DISABLED, "rocker");
return NULL;
};
+67 -1
View File
@@ -94,6 +94,51 @@ World *rocker_get_world(Rocker *r, enum rocker_world_type type)
return NULL;
}
RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
{
RockerSwitch *rocker = g_malloc0(sizeof(*rocker));
Rocker *r;
r = rocker_find(name);
if (!r) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s not found", name);
return NULL;
}
rocker->name = g_strdup(r->name);
rocker->id = r->switch_id;
rocker->ports = r->fp_ports;
return rocker;
}
RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
{
RockerPortList *list = NULL;
Rocker *r;
int i;
r = rocker_find(name);
if (!r) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s not found", name);
return NULL;
}
for (i = r->fp_ports - 1; i >= 0; i--) {
RockerPortList *info = g_malloc0(sizeof(*info));
info->value = g_malloc0(sizeof(*info->value));
struct fp_port *port = r->fp_port[i];
fp_port_get_info(port, info);
info->next = list;
list = info;
}
return list;
}
uint32_t rocker_fp_ports(Rocker *r)
{
return r->fp_ports;
@@ -238,6 +283,7 @@ static int cmd_get_port_settings(Rocker *r,
uint8_t duplex;
uint8_t autoneg;
uint8_t learning;
char *phys_name;
MACAddr macaddr;
enum rocker_world_type mode;
size_t tlv_size;
@@ -265,6 +311,7 @@ static int cmd_get_port_settings(Rocker *r,
fp_port_get_macaddr(fp_port, &macaddr);
mode = world_type(fp_port_get_world(fp_port));
learning = fp_port_get_learning(fp_port);
phys_name = fp_port_get_name(fp_port);
tlv_size = rocker_tlv_total_size(0) + /* nest */
rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
@@ -273,7 +320,8 @@ static int cmd_get_port_settings(Rocker *r,
rocker_tlv_total_size(sizeof(uint8_t)) + /* autoneg */
rocker_tlv_total_size(sizeof(macaddr.a)) + /* macaddr */
rocker_tlv_total_size(sizeof(uint8_t)) + /* mode */
rocker_tlv_total_size(sizeof(uint8_t)); /* learning */
rocker_tlv_total_size(sizeof(uint8_t)) + /* learning */
rocker_tlv_total_size(strlen(phys_name));
if (tlv_size > desc_buf_size(info)) {
return -ROCKER_EMSGSIZE;
@@ -290,6 +338,8 @@ static int cmd_get_port_settings(Rocker *r,
rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MODE, mode);
rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,
learning);
rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME,
strlen(phys_name), phys_name);
rocker_tlv_nest_end(buf, &pos, nest);
return desc_set_buf(info, tlv_size);
@@ -1277,6 +1327,22 @@ static int pci_rocker_init(PCIDevice *dev)
goto err_duplicate;
}
/* Rocker name is passed in port name requests to OS with the intention
* that the name is used in interface names. Limit the length of the
* rocker name to avoid naming problems in the OS. Also, adding the
* port number as p# and unganged breakout b#, where # is at most 2
* digits, so leave room for it too (-1 for string terminator, -3 for
* p# and -3 for b#)
*/
#define ROCKER_IFNAMSIZ 16
#define MAX_ROCKER_NAME_LEN (ROCKER_IFNAMSIZ - 1 - 3 - 3)
if (strlen(r->name) > MAX_ROCKER_NAME_LEN) {
fprintf(stderr,
"rocker: name too long; please shorten to at most %d chars\n",
MAX_ROCKER_NAME_LEN);
return -EINVAL;
}
if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) {
memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt));
r->fp_start_macaddr.a[4] += (sw_index++);
+28 -1
View File
@@ -41,11 +41,26 @@ struct fp_port {
NICConf conf;
};
char *fp_port_get_name(FpPort *port)
{
return port->name;
}
bool fp_port_get_link_up(FpPort *port)
{
return !qemu_get_queue(port->nic)->link_down;
}
void fp_port_get_info(FpPort *port, RockerPortList *info)
{
info->value->name = g_strdup(port->name);
info->value->enabled = port->enabled;
info->value->link_up = fp_port_get_link_up(port);
info->value->speed = port->speed;
info->value->duplex = port->duplex;
info->value->autoneg = port->autoneg;
}
void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr)
{
memcpy(macaddr->a, port->conf.macaddr.a, sizeof(macaddr->a));
@@ -173,8 +188,19 @@ bool fp_port_enabled(FpPort *port)
return port->enabled;
}
static void fp_port_set_link(FpPort *port, bool up)
{
NetClientState *nc = qemu_get_queue(port->nic);
if (up == nc->link_down) {
nc->link_down = !up;
nc->info->link_status_changed(nc);
}
}
void fp_port_enable(FpPort *port)
{
fp_port_set_link(port, true);
port->enabled = true;
DPRINTF("port %d enabled\n", port->index);
}
@@ -182,6 +208,7 @@ void fp_port_enable(FpPort *port)
void fp_port_disable(FpPort *port)
{
port->enabled = false;
fp_port_set_link(port, false);
DPRINTF("port %d disabled\n", port->index);
}
@@ -201,7 +228,7 @@ FpPort *fp_port_alloc(Rocker *r, char *sw_name,
/* front-panel switch port names are 1-based */
port->name = g_strdup_printf("%s.%d", sw_name, port->pport);
port->name = g_strdup_printf("%sp%d", sw_name, port->pport);
memcpy(port->conf.macaddr.a, start_mac, sizeof(port->conf.macaddr.a));
port->conf.macaddr.a[5] += index;
+2
View File
@@ -26,7 +26,9 @@ typedef struct fp_port FpPort;
int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt);
char *fp_port_get_name(FpPort *port);
bool fp_port_get_link_up(FpPort *port);
void fp_port_get_info(FpPort *port, RockerPortList *info);
void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr);
void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr);
uint8_t fp_port_get_learning(FpPort *port);
+1
View File
@@ -179,6 +179,7 @@ enum {
ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR, /* binary */
ROCKER_TLV_CMD_PORT_SETTINGS_MODE, /* u8 */
ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, /* u8 */
ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, /* binary */
__ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
ROCKER_TLV_CMD_PORT_SETTINGS_MAX = __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1,
+312
View File
@@ -2302,6 +2302,318 @@ static void of_dpa_uninit(World *world)
g_hash_table_destroy(of_dpa->flow_tbl);
}
struct of_dpa_flow_fill_context {
RockerOfDpaFlowList *list;
uint32_t tbl_id;
};
static void of_dpa_flow_fill(void *cookie, void *value, void *user_data)
{
struct of_dpa_flow *flow = value;
struct of_dpa_flow_key *key = &flow->key;
struct of_dpa_flow_key *mask = &flow->mask;
struct of_dpa_flow_fill_context *flow_context = user_data;
RockerOfDpaFlowList *new;
RockerOfDpaFlow *nflow;
RockerOfDpaFlowKey *nkey;
RockerOfDpaFlowMask *nmask;
RockerOfDpaFlowAction *naction;
if (flow_context->tbl_id != -1 &&
flow_context->tbl_id != key->tbl_id) {
return;
}
new = g_malloc0(sizeof(*new));
nflow = new->value = g_malloc0(sizeof(*nflow));
nkey = nflow->key = g_malloc0(sizeof(*nkey));
nmask = nflow->mask = g_malloc0(sizeof(*nmask));
naction = nflow->action = g_malloc0(sizeof(*naction));
nflow->cookie = flow->cookie;
nflow->hits = flow->stats.hits;
nkey->priority = flow->priority;
nkey->tbl_id = key->tbl_id;
if (key->in_pport || mask->in_pport) {
nkey->has_in_pport = true;
nkey->in_pport = key->in_pport;
}
if (nkey->has_in_pport && mask->in_pport != 0xffffffff) {
nmask->has_in_pport = true;
nmask->in_pport = mask->in_pport;
}
if (key->eth.vlan_id || mask->eth.vlan_id) {
nkey->has_vlan_id = true;
nkey->vlan_id = ntohs(key->eth.vlan_id);
}
if (nkey->has_vlan_id && mask->eth.vlan_id != 0xffff) {
nmask->has_vlan_id = true;
nmask->vlan_id = ntohs(mask->eth.vlan_id);
}
if (key->tunnel_id || mask->tunnel_id) {
nkey->has_tunnel_id = true;
nkey->tunnel_id = key->tunnel_id;
}
if (nkey->has_tunnel_id && mask->tunnel_id != 0xffffffff) {
nmask->has_tunnel_id = true;
nmask->tunnel_id = mask->tunnel_id;
}
if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) ||
memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN)) {
nkey->has_eth_src = true;
nkey->eth_src = qemu_mac_strdup_printf(key->eth.src.a);
}
if (nkey->has_eth_src && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) {
nmask->has_eth_src = true;
nmask->eth_src = qemu_mac_strdup_printf(mask->eth.src.a);
}
if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) ||
memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN)) {
nkey->has_eth_dst = true;
nkey->eth_dst = qemu_mac_strdup_printf(key->eth.dst.a);
}
if (nkey->has_eth_dst && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) {
nmask->has_eth_dst = true;
nmask->eth_dst = qemu_mac_strdup_printf(mask->eth.dst.a);
}
if (key->eth.type) {
nkey->has_eth_type = true;
nkey->eth_type = ntohs(key->eth.type);
switch (ntohs(key->eth.type)) {
case 0x0800:
case 0x86dd:
if (key->ip.proto || mask->ip.proto) {
nkey->has_ip_proto = true;
nkey->ip_proto = key->ip.proto;
}
if (nkey->has_ip_proto && mask->ip.proto != 0xff) {
nmask->has_ip_proto = true;
nmask->ip_proto = mask->ip.proto;
}
if (key->ip.tos || mask->ip.tos) {
nkey->has_ip_tos = true;
nkey->ip_tos = key->ip.tos;
}
if (nkey->has_ip_tos && mask->ip.tos != 0xff) {
nmask->has_ip_tos = true;
nmask->ip_tos = mask->ip.tos;
}
break;
}
switch (ntohs(key->eth.type)) {
case 0x0800:
if (key->ipv4.addr.dst || mask->ipv4.addr.dst) {
char *dst = inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst);
int dst_len = of_dpa_mask2prefix(mask->ipv4.addr.dst);
nkey->has_ip_dst = true;
nkey->ip_dst = g_strdup_printf("%s/%d", dst, dst_len);
}
break;
}
}
if (flow->action.goto_tbl) {
naction->has_goto_tbl = true;
naction->goto_tbl = flow->action.goto_tbl;
}
if (flow->action.write.group_id) {
naction->has_group_id = true;
naction->group_id = flow->action.write.group_id;
}
if (flow->action.apply.new_vlan_id) {
naction->has_new_vlan_id = true;
naction->new_vlan_id = flow->action.apply.new_vlan_id;
}
new->next = flow_context->list;
flow_context->list = new;
}
RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name,
bool has_tbl_id,
uint32_t tbl_id,
Error **errp)
{
struct rocker *r;
struct world *w;
struct of_dpa *of_dpa;
struct of_dpa_flow_fill_context fill_context = {
.list = NULL,
.tbl_id = tbl_id,
};
r = rocker_find(name);
if (!r) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s not found", name);
return NULL;
}
w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA);
if (!w) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s doesn't have OF-DPA world", name);
return NULL;
}
of_dpa = world_private(w);
g_hash_table_foreach(of_dpa->flow_tbl, of_dpa_flow_fill, &fill_context);
return fill_context.list;
}
struct of_dpa_group_fill_context {
RockerOfDpaGroupList *list;
uint8_t type;
};
static void of_dpa_group_fill(void *key, void *value, void *user_data)
{
struct of_dpa_group *group = value;
struct of_dpa_group_fill_context *flow_context = user_data;
RockerOfDpaGroupList *new;
RockerOfDpaGroup *ngroup;
struct uint32List *id;
int i;
if (flow_context->type != 9 &&
flow_context->type != ROCKER_GROUP_TYPE_GET(group->id)) {
return;
}
new = g_malloc0(sizeof(*new));
ngroup = new->value = g_malloc0(sizeof(*ngroup));
ngroup->id = group->id;
ngroup->type = ROCKER_GROUP_TYPE_GET(group->id);
switch (ngroup->type) {
case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
ngroup->has_vlan_id = true;
ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id);
ngroup->has_pport = true;
ngroup->pport = ROCKER_GROUP_PORT_GET(group->id);
ngroup->has_out_pport = true;
ngroup->out_pport = group->l2_interface.out_pport;
ngroup->has_pop_vlan = true;
ngroup->pop_vlan = group->l2_interface.pop_vlan;
break;
case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
ngroup->has_index = true;
ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id);
ngroup->has_group_id = true;
ngroup->group_id = group->l2_rewrite.group_id;
if (group->l2_rewrite.vlan_id) {
ngroup->has_set_vlan_id = true;
ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id);
}
break;
if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) {
ngroup->has_set_eth_src = true;
ngroup->set_eth_src =
qemu_mac_strdup_printf(group->l2_rewrite.src_mac.a);
}
if (memcmp(group->l2_rewrite.dst_mac.a, zero_mac.a, ETH_ALEN)) {
ngroup->has_set_eth_dst = true;
ngroup->set_eth_dst =
qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a);
}
case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
ngroup->has_vlan_id = true;
ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id);
ngroup->has_index = true;
ngroup->index = ROCKER_GROUP_INDEX_GET(group->id);
for (i = 0; i < group->l2_flood.group_count; i++) {
ngroup->has_group_ids = true;
id = g_malloc0(sizeof(*id));
id->value = group->l2_flood.group_ids[i];
id->next = ngroup->group_ids;
ngroup->group_ids = id;
}
break;
case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
ngroup->has_index = true;
ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id);
ngroup->has_group_id = true;
ngroup->group_id = group->l3_unicast.group_id;
if (group->l3_unicast.vlan_id) {
ngroup->has_set_vlan_id = true;
ngroup->set_vlan_id = ntohs(group->l3_unicast.vlan_id);
}
if (memcmp(group->l3_unicast.src_mac.a, zero_mac.a, ETH_ALEN)) {
ngroup->has_set_eth_src = true;
ngroup->set_eth_src =
qemu_mac_strdup_printf(group->l3_unicast.src_mac.a);
}
if (memcmp(group->l3_unicast.dst_mac.a, zero_mac.a, ETH_ALEN)) {
ngroup->has_set_eth_dst = true;
ngroup->set_eth_dst =
qemu_mac_strdup_printf(group->l3_unicast.dst_mac.a);
}
if (group->l3_unicast.ttl_check) {
ngroup->has_ttl_check = true;
ngroup->ttl_check = group->l3_unicast.ttl_check;
}
break;
}
new->next = flow_context->list;
flow_context->list = new;
}
RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name,
bool has_type,
uint8_t type,
Error **errp)
{
struct rocker *r;
struct world *w;
struct of_dpa *of_dpa;
struct of_dpa_group_fill_context fill_context = {
.list = NULL,
.type = type,
};
r = rocker_find(name);
if (!r) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s not found", name);
return NULL;
}
w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA);
if (!w) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"rocker %s doesn't have OF-DPA world", name);
return NULL;
}
of_dpa = world_private(w);
g_hash_table_foreach(of_dpa->group_tbl, of_dpa_group_fill, &fill_context);
return fill_context.list;
}
static WorldOps of_dpa_ops = {
.init = of_dpa_init,
.uninit = of_dpa_uninit,
+4 -7
View File
@@ -3240,6 +3240,7 @@ static const VMStateDescription vmstate_rtl8139_hotplug_ready ={
.name = "rtl8139/hotplug_ready",
.version_id = 1,
.minimum_version_id = 1,
.needed = rtl8139_hotplug_ready_needed,
.fields = (VMStateField[]) {
VMSTATE_END_OF_LIST()
}
@@ -3335,13 +3336,9 @@ static const VMStateDescription vmstate_rtl8139 = {
VMSTATE_UINT32_V(cplus_enabled, RTL8139State, 4),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection []) {
{
.vmsd = &vmstate_rtl8139_hotplug_ready,
.needed = rtl8139_hotplug_ready_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_rtl8139_hotplug_ready,
NULL
}
};
+8 -6
View File
@@ -52,6 +52,7 @@ static const int kernel_feature_bits[] = {
VIRTIO_RING_F_INDIRECT_DESC,
VIRTIO_RING_F_EVENT_IDX,
VIRTIO_NET_F_MRG_RXBUF,
VIRTIO_F_VERSION_1,
VHOST_INVALID_FEATURE_BIT
};
@@ -62,6 +63,7 @@ static const int user_feature_bits[] = {
VIRTIO_RING_F_EVENT_IDX,
VIRTIO_F_ANY_LAYOUT,
VIRTIO_F_VERSION_1,
VIRTIO_NET_F_CSUM,
VIRTIO_NET_F_GUEST_CSUM,
VIRTIO_NET_F_GSO,
@@ -107,13 +109,13 @@ static const int *vhost_net_get_feature_bits(struct vhost_net *net)
return feature_bits;
}
unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features)
{
return vhost_get_features(&net->dev, vhost_net_get_feature_bits(net),
features);
}
void vhost_net_ack_features(struct vhost_net *net, unsigned features)
void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
{
net->dev.acked_features = net->dev.backend_features;
vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
@@ -147,7 +149,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
goto fail;
}
net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend)
? 0 : (1 << VHOST_NET_F_VIRTIO_NET_HDR);
? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR);
net->backend = r;
} else {
net->dev.backend_features = 0;
@@ -167,7 +169,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
if (backend_kernel) {
if (!qemu_has_vnet_hdr_len(options->net_backend,
sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF);
}
if (~net->dev.features & net->dev.backend_features) {
fprintf(stderr, "vhost lacks feature mask %" PRIu64
@@ -431,11 +433,11 @@ void vhost_net_cleanup(struct vhost_net *net)
{
}
unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features)
{
return features;
}
void vhost_net_ack_features(struct vhost_net *net, unsigned features)
void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
{
}
+59 -8
View File
@@ -87,6 +87,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
memcpy(&netcfg, config, n->config_size);
if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) &&
!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
memcpy(n->mac, netcfg.mac, ETH_ALEN);
qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
@@ -366,15 +367,21 @@ static int peer_has_ufo(VirtIONet *n)
return n->has_ufo;
}
static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs)
static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs,
int version_1)
{
int i;
NetClientState *nc;
n->mergeable_rx_bufs = mergeable_rx_bufs;
n->guest_hdr_len = n->mergeable_rx_bufs ?
sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
if (version_1) {
n->guest_hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
} else {
n->guest_hdr_len = n->mergeable_rx_bufs ?
sizeof(struct virtio_net_hdr_mrg_rxbuf) :
sizeof(struct virtio_net_hdr);
}
for (i = 0; i < n->max_queues; i++) {
nc = qemu_get_subqueue(n->nic, i);
@@ -463,6 +470,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features)
}
if (!get_vhost_net(nc->peer)) {
virtio_add_feature(&features, VIRTIO_F_VERSION_1);
return features;
}
return vhost_net_get_features(get_vhost_net(nc->peer), features);
@@ -521,7 +529,9 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
virtio_net_set_mrg_rx_bufs(n,
__virtio_has_feature(features,
VIRTIO_NET_F_MRG_RXBUF));
VIRTIO_NET_F_MRG_RXBUF),
__virtio_has_feature(features,
VIRTIO_F_VERSION_1));
if (n->has_vnet_hdr) {
n->curr_guest_offloads =
@@ -1374,7 +1384,8 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
qemu_get_buffer(f, n->mac, ETH_ALEN);
n->vqs[0].tx_waiting = qemu_get_be32(f);
virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f));
virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f),
virtio_has_feature(vdev, VIRTIO_F_VERSION_1));
if (version_id >= 3)
n->status = qemu_get_be16(f);
@@ -1626,7 +1637,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
n->vqs[0].tx_waiting = 0;
n->tx_burst = n->net_conf.txburst;
virtio_net_set_mrg_rx_bufs(n, 0);
virtio_net_set_mrg_rx_bufs(n, 0, 0);
n->promisc = 1; /* for compatibility */
n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
@@ -1696,10 +1707,50 @@ static void virtio_net_instance_init(Object *obj)
}
static Property virtio_net_properties[] = {
DEFINE_VIRTIO_NET_FEATURES(VirtIONet, host_features),
DEFINE_PROP_BIT("any_layout", VirtIONet, host_features,
VIRTIO_F_ANY_LAYOUT, true),
DEFINE_PROP_BIT("csum", VirtIONet, host_features, VIRTIO_NET_F_CSUM, true),
DEFINE_PROP_BIT("guest_csum", VirtIONet, host_features,
VIRTIO_NET_F_GUEST_CSUM, true),
DEFINE_PROP_BIT("gso", VirtIONet, host_features, VIRTIO_NET_F_GSO, true),
DEFINE_PROP_BIT("guest_tso4", VirtIONet, host_features,
VIRTIO_NET_F_GUEST_TSO4, true),
DEFINE_PROP_BIT("guest_tso6", VirtIONet, host_features,
VIRTIO_NET_F_GUEST_TSO6, true),
DEFINE_PROP_BIT("guest_ecn", VirtIONet, host_features,
VIRTIO_NET_F_GUEST_ECN, true),
DEFINE_PROP_BIT("guest_ufo", VirtIONet, host_features,
VIRTIO_NET_F_GUEST_UFO, true),
DEFINE_PROP_BIT("guest_announce", VirtIONet, host_features,
VIRTIO_NET_F_GUEST_ANNOUNCE, true),
DEFINE_PROP_BIT("host_tso4", VirtIONet, host_features,
VIRTIO_NET_F_HOST_TSO4, true),
DEFINE_PROP_BIT("host_tso6", VirtIONet, host_features,
VIRTIO_NET_F_HOST_TSO6, true),
DEFINE_PROP_BIT("host_ecn", VirtIONet, host_features,
VIRTIO_NET_F_HOST_ECN, true),
DEFINE_PROP_BIT("host_ufo", VirtIONet, host_features,
VIRTIO_NET_F_HOST_UFO, true),
DEFINE_PROP_BIT("mrg_rxbuf", VirtIONet, host_features,
VIRTIO_NET_F_MRG_RXBUF, true),
DEFINE_PROP_BIT("status", VirtIONet, host_features,
VIRTIO_NET_F_STATUS, true),
DEFINE_PROP_BIT("ctrl_vq", VirtIONet, host_features,
VIRTIO_NET_F_CTRL_VQ, true),
DEFINE_PROP_BIT("ctrl_rx", VirtIONet, host_features,
VIRTIO_NET_F_CTRL_RX, true),
DEFINE_PROP_BIT("ctrl_vlan", VirtIONet, host_features,
VIRTIO_NET_F_CTRL_VLAN, true),
DEFINE_PROP_BIT("ctrl_rx_extra", VirtIONet, host_features,
VIRTIO_NET_F_CTRL_RX_EXTRA, true),
DEFINE_PROP_BIT("ctrl_mac_addr", VirtIONet, host_features,
VIRTIO_NET_F_CTRL_MAC_ADDR, true),
DEFINE_PROP_BIT("ctrl_guest_offloads", VirtIONet, host_features,
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true),
DEFINE_PROP_BIT("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false),
DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf),
DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer,
TX_TIMER_INTERVAL),
TX_TIMER_INTERVAL),
DEFINE_PROP_INT32("x-txburst", VirtIONet, net_conf.txburst, TX_BURST),
DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx),
DEFINE_PROP_END_OF_LIST(),
+4 -8
View File
@@ -2226,6 +2226,7 @@ static const VMStateDescription vmxstate_vmxnet3_mcast_list = {
.version_id = 1,
.minimum_version_id = 1,
.pre_load = vmxnet3_mcast_list_pre_load,
.needed = vmxnet3_mc_list_needed,
.fields = (VMStateField[]) {
VMSTATE_VBUFFER_UINT32(mcast_list, VMXNET3State, 0, NULL, 0,
mcast_list_buff_size),
@@ -2470,14 +2471,9 @@ static const VMStateDescription vmstate_vmxnet3 = {
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmxstate_vmxnet3_mcast_list,
.needed = vmxnet3_mc_list_needed
},
{
/* empty element. */
}
.subsections = (const VMStateDescription*[]) {
&vmxstate_vmxnet3_mcast_list,
NULL
}
};
+18 -37
View File
@@ -46,7 +46,6 @@ typedef struct FWCfgEntry {
uint32_t len;
uint8_t *data;
void *callback_opaque;
FWCfgCallback callback;
FWCfgReadCallback read_callback;
} FWCfgEntry;
@@ -232,19 +231,7 @@ static void fw_cfg_reboot(FWCfgState *s)
static void fw_cfg_write(FWCfgState *s, uint8_t value)
{
int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
trace_fw_cfg_write(s, value);
if (s->cur_entry & FW_CFG_WRITE_CHANNEL && e->callback &&
s->cur_offset < e->len) {
e->data[s->cur_offset++] = value;
if (s->cur_offset == e->len) {
e->callback(e->callback_opaque, e->data);
s->cur_offset = 0;
}
}
/* nothing, write support removed in QEMU v2.4+ */
}
static int fw_cfg_select(FWCfgState *s, uint16_t key)
@@ -436,6 +423,7 @@ static void fw_cfg_add_bytes_read_callback(FWCfgState *s, uint16_t key,
key &= FW_CFG_ENTRY_MASK;
assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
assert(s->entries[arch][key].data == NULL); /* avoid key conflict */
s->entries[arch][key].data = data;
s->entries[arch][key].len = (uint32_t)len;
@@ -458,7 +446,6 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
s->entries[arch][key].data = data;
s->entries[arch][key].len = len;
s->entries[arch][key].callback_opaque = NULL;
s->entries[arch][key].callback = NULL;
return ptr;
}
@@ -484,6 +471,16 @@ void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value)
fw_cfg_add_bytes(s, key, copy, sizeof(value));
}
void fw_cfg_modify_i16(FWCfgState *s, uint16_t key, uint16_t value)
{
uint16_t *copy, *old;
copy = g_malloc(sizeof(value));
*copy = cpu_to_le16(value);
old = fw_cfg_modify_bytes_read(s, key, copy, sizeof(value));
g_free(old);
}
void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value)
{
uint32_t *copy;
@@ -502,23 +499,6 @@ void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)
fw_cfg_add_bytes(s, key, copy, sizeof(value));
}
void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
void *callback_opaque, void *data, size_t len)
{
int arch = !!(key & FW_CFG_ARCH_LOCAL);
assert(key & FW_CFG_WRITE_CHANNEL);
key &= FW_CFG_ENTRY_MASK;
assert(key < FW_CFG_MAX_ENTRY && len <= UINT32_MAX);
s->entries[arch][key].data = data;
s->entries[arch][key].len = (uint32_t)len;
s->entries[arch][key].callback_opaque = callback_opaque;
s->entries[arch][key].callback = callback;
}
void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
FWCfgReadCallback callback, void *callback_opaque,
void *data, size_t len)
@@ -535,18 +515,19 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
index = be32_to_cpu(s->files->count);
assert(index < FW_CFG_FILE_SLOTS);
fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index,
callback, callback_opaque, data, len);
pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name),
filename);
for (i = 0; i < index; i++) {
if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) {
trace_fw_cfg_add_file_dupe(s, s->files->f[index].name);
return;
error_report("duplicate fw_cfg file name: %s",
s->files->f[index].name);
exit(1);
}
}
fw_cfg_add_bytes_read_callback(s, FW_CFG_FILE_FIRST + index,
callback, callback_opaque, data, len);
s->files->f[index].size = cpu_to_be32(len);
s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
+4 -6
View File
@@ -582,6 +582,7 @@ static const VMStateDescription vmstate_piix3_rcr = {
.name = "PIIX3/rcr",
.version_id = 1,
.minimum_version_id = 1,
.needed = piix3_rcr_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(rcr, PIIX3State),
VMSTATE_END_OF_LIST()
@@ -600,12 +601,9 @@ static const VMStateDescription vmstate_piix3 = {
PIIX_NUM_PIRQS, 3),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_piix3_rcr,
.needed = piix3_rcr_needed,
},
{ 0 }
.subsections = (const VMStateDescription*[]) {
&vmstate_piix3_rcr,
NULL
}
};
+1 -1
View File
@@ -119,7 +119,7 @@ static const MemoryRegionOps unin_ops = {
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
Error **errp)
{
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
}
static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+1 -1
View File
@@ -52,7 +52,7 @@
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
Error **errp)
{
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
}
static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+12 -8
View File
@@ -498,15 +498,19 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
virtio_ccw_stop_ioeventfd(dev);
}
virtio_set_status(vdev, status);
if (vdev->status == 0) {
virtio_reset(vdev);
if (virtio_set_status(vdev, status) == 0) {
if (vdev->status == 0) {
virtio_reset(vdev);
}
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
virtio_ccw_start_ioeventfd(dev);
}
sch->curr_status.scsw.count = ccw.count - sizeof(status);
ret = 0;
} else {
/* Trigger a command reject. */
ret = -ENOSYS;
}
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
virtio_ccw_start_ioeventfd(dev);
}
sch->curr_status.scsw.count = ccw.count - sizeof(status);
ret = 0;
}
break;
case CCW_CMD_SET_IND:
+4 -7
View File
@@ -1968,6 +1968,7 @@ static const VMStateDescription vmstate_scsi_sense_state = {
.name = "SCSIDevice/sense",
.version_id = 1,
.minimum_version_id = 1,
.needed = scsi_sense_state_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8_SUB_ARRAY(sense, SCSIDevice,
SCSI_SENSE_BUF_SIZE_OLD,
@@ -1998,13 +1999,9 @@ const VMStateDescription vmstate_scsi_device = {
},
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection []) {
{
.vmsd = &vmstate_scsi_sense_state,
.needed = scsi_sense_state_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_scsi_sense_state,
NULL
}
};
+8 -1
View File
@@ -294,7 +294,14 @@ static char *vhost_scsi_get_fw_dev_path(FWPathProvider *p, BusState *bus,
}
static Property vhost_scsi_properties[] = {
DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSI, parent_obj.conf),
DEFINE_PROP_STRING("vhostfd", VHostSCSI, parent_obj.conf.vhostfd),
DEFINE_PROP_STRING("wwpn", VHostSCSI, parent_obj.conf.wwpn),
DEFINE_PROP_UINT32("boot_tpgt", VHostSCSI, parent_obj.conf.boot_tpgt, 0),
DEFINE_PROP_UINT32("num_queues", VHostSCSI, parent_obj.conf.num_queues, 1),
DEFINE_PROP_UINT32("max_sectors", VHostSCSI, parent_obj.conf.max_sectors,
0xFFFF),
DEFINE_PROP_UINT32("cmd_per_lun", VHostSCSI, parent_obj.conf.cmd_per_lun,
128),
DEFINE_PROP_END_OF_LIST(),
};
+11 -2
View File
@@ -948,8 +948,17 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
}
static Property virtio_scsi_properties[] = {
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, parent_obj.conf),
DEFINE_VIRTIO_SCSI_FEATURES(VirtIOSCSI, host_features),
DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1),
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors,
0xFFFF),
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
128),
DEFINE_PROP_BIT("any_layout", VirtIOSCSI, host_features,
VIRTIO_F_ANY_LAYOUT, true),
DEFINE_PROP_BIT("hotplug", VirtIOSCSI, host_features,
VIRTIO_SCSI_F_HOTPLUG, true),
DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features,
VIRTIO_SCSI_F_CHANGE, true),
DEFINE_PROP_END_OF_LIST(),
};
+6 -6
View File
@@ -127,7 +127,7 @@ static void r2d_fpga_irq_set(void *opaque, int n, int level)
update_irl(fpga);
}
static uint32_t r2d_fpga_read(void *opaque, hwaddr addr)
static uint64_t r2d_fpga_read(void *opaque, hwaddr addr, unsigned int size)
{
r2d_fpga_t *s = opaque;
@@ -146,7 +146,7 @@ static uint32_t r2d_fpga_read(void *opaque, hwaddr addr)
}
static void
r2d_fpga_write(void *opaque, hwaddr addr, uint32_t value)
r2d_fpga_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size)
{
r2d_fpga_t *s = opaque;
@@ -170,10 +170,10 @@ r2d_fpga_write(void *opaque, hwaddr addr, uint32_t value)
}
static const MemoryRegionOps r2d_fpga_ops = {
.old_mmio = {
.read = { r2d_fpga_read, r2d_fpga_read, NULL, },
.write = { r2d_fpga_write, r2d_fpga_write, NULL, },
},
.read = r2d_fpga_read,
.write = r2d_fpga_write,
.impl.min_access_size = 2,
.impl.max_access_size = 2,
.endianness = DEVICE_NATIVE_ENDIAN,
};
+1 -1
View File
@@ -124,7 +124,7 @@ void DMA_register_channel (int nchan,
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
Error **errp)
{
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
}
static void nvram_init(Nvram *nvram, uint8_t *macaddr,
+1 -1
View File
@@ -127,7 +127,7 @@ void DMA_register_channel (int nchan,
static void fw_cfg_boot_set(void *opaque, const char *boot_device,
Error **errp)
{
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
}
static int sun4u_NVRAM_set_params(Nvram *nvram, uint16_t NVRAM_size,
+4 -7
View File
@@ -283,6 +283,7 @@ static const VMStateDescription vmstate_hpet_rtc_irq_level = {
.name = "hpet/rtc_irq_level",
.version_id = 1,
.minimum_version_id = 1,
.needed = hpet_rtc_irq_level_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(rtc_irq_level, HPETState),
VMSTATE_END_OF_LIST()
@@ -322,13 +323,9 @@ static const VMStateDescription vmstate_hpet = {
vmstate_hpet_timer, HPETTimer),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_hpet_rtc_irq_level,
.needed = hpet_rtc_irq_level_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_hpet_rtc_irq_level,
NULL
}
};
+14 -17
View File
@@ -733,22 +733,23 @@ static int rtc_post_load(void *opaque, int version_id)
return 0;
}
static const VMStateDescription vmstate_rtc_irq_reinject_on_ack_count = {
.name = "mc146818rtc/irq_reinject_on_ack_count",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT16(irq_reinject_on_ack_count, RTCState),
VMSTATE_END_OF_LIST()
}
};
static bool rtc_irq_reinject_on_ack_count_needed(void *opaque)
{
RTCState *s = (RTCState *)opaque;
return s->irq_reinject_on_ack_count != 0;
}
static const VMStateDescription vmstate_rtc_irq_reinject_on_ack_count = {
.name = "mc146818rtc/irq_reinject_on_ack_count",
.version_id = 1,
.minimum_version_id = 1,
.needed = rtc_irq_reinject_on_ack_count_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT16(irq_reinject_on_ack_count, RTCState),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_rtc = {
.name = "mc146818rtc",
.version_id = 3,
@@ -770,13 +771,9 @@ static const VMStateDescription vmstate_rtc = {
VMSTATE_UINT64_V(next_alarm_time, RTCState, 3),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_rtc_irq_reinject_on_ack_count,
.needed = rtc_irq_reinject_on_ack_count_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_rtc_irq_reinject_on_ack_count,
NULL
}
};
+4 -7
View File
@@ -2034,6 +2034,7 @@ static const VMStateDescription vmstate_ohci_eof_timer = {
.version_id = 1,
.minimum_version_id = 1,
.pre_load = ohci_eof_timer_pre_load,
.needed = ohci_eof_timer_needed,
.fields = (VMStateField[]) {
VMSTATE_TIMER_PTR(eof_timer, OHCIState),
VMSTATE_END_OF_LIST()
@@ -2081,13 +2082,9 @@ static const VMStateDescription vmstate_ohci_state = {
VMSTATE_BOOL(async_complete, OHCIState),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection []) {
{
.vmsd = &vmstate_ohci_eof_timer,
.needed = ohci_eof_timer_needed,
} , {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&vmstate_ohci_eof_timer,
NULL
}
};
+19 -23
View File
@@ -2257,16 +2257,6 @@ static const VMStateInfo usbredir_ep_bufpq_vmstate_info = {
/* For endp_data migration */
static const VMStateDescription usbredir_bulk_receiving_vmstate = {
.name = "usb-redir-ep/bulk-receiving",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT8(bulk_receiving_started, struct endp_data),
VMSTATE_END_OF_LIST()
}
};
static bool usbredir_bulk_receiving_needed(void *priv)
{
struct endp_data *endp = priv;
@@ -2274,12 +2264,13 @@ static bool usbredir_bulk_receiving_needed(void *priv)
return endp->bulk_receiving_started;
}
static const VMStateDescription usbredir_stream_vmstate = {
.name = "usb-redir-ep/stream-state",
static const VMStateDescription usbredir_bulk_receiving_vmstate = {
.name = "usb-redir-ep/bulk-receiving",
.version_id = 1,
.minimum_version_id = 1,
.needed = usbredir_bulk_receiving_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(max_streams, struct endp_data),
VMSTATE_UINT8(bulk_receiving_started, struct endp_data),
VMSTATE_END_OF_LIST()
}
};
@@ -2291,6 +2282,17 @@ static bool usbredir_stream_needed(void *priv)
return endp->max_streams;
}
static const VMStateDescription usbredir_stream_vmstate = {
.name = "usb-redir-ep/stream-state",
.version_id = 1,
.minimum_version_id = 1,
.needed = usbredir_stream_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT32(max_streams, struct endp_data),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription usbredir_ep_vmstate = {
.name = "usb-redir-ep",
.version_id = 1,
@@ -2318,16 +2320,10 @@ static const VMStateDescription usbredir_ep_vmstate = {
VMSTATE_INT32(bufpq_target_size, struct endp_data),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &usbredir_bulk_receiving_vmstate,
.needed = usbredir_bulk_receiving_needed,
}, {
.vmsd = &usbredir_stream_vmstate,
.needed = usbredir_stream_needed,
}, {
/* empty */
}
.subsections = (const VMStateDescription*[]) {
&usbredir_bulk_receiving_vmstate,
&usbredir_stream_vmstate,
NULL
}
};
+2
View File
@@ -1,4 +1,6 @@
ifeq ($(CONFIG_LINUX), y)
obj-$(CONFIG_SOFTMMU) += common.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_SOFTMMU) += platform.o
obj-$(CONFIG_SOFTMMU) += calxeda-xgmac.o
endif
+55
View File
@@ -0,0 +1,55 @@
/*
* calxeda xgmac VFIO device
*
* Copyright Linaro Limited, 2014
*
* Authors:
* Eric Auger <eric.auger@linaro.org>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#include "hw/vfio/vfio-calxeda-xgmac.h"
static void calxeda_xgmac_realize(DeviceState *dev, Error **errp)
{
VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(dev);
VFIOCalxedaXgmacDeviceClass *k = VFIO_CALXEDA_XGMAC_DEVICE_GET_CLASS(dev);
vdev->compat = g_strdup("calxeda,hb-xgmac");
k->parent_realize(dev, errp);
}
static const VMStateDescription vfio_platform_calxeda_xgmac_vmstate = {
.name = TYPE_VFIO_CALXEDA_XGMAC,
.unmigratable = 1,
};
static void vfio_calxeda_xgmac_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VFIOCalxedaXgmacDeviceClass *vcxc =
VFIO_CALXEDA_XGMAC_DEVICE_CLASS(klass);
vcxc->parent_realize = dc->realize;
dc->realize = calxeda_xgmac_realize;
dc->desc = "VFIO Calxeda XGMAC";
dc->vmsd = &vfio_platform_calxeda_xgmac_vmstate;
}
static const TypeInfo vfio_calxeda_xgmac_dev_info = {
.name = TYPE_VFIO_CALXEDA_XGMAC,
.parent = TYPE_VFIO_PLATFORM,
.instance_size = sizeof(VFIOCalxedaXgmacDevice),
.class_init = vfio_calxeda_xgmac_class_init,
.class_size = sizeof(VFIOCalxedaXgmacDeviceClass),
};
static void register_calxeda_xgmac_dev_type(void)
{
type_register_static(&vfio_calxeda_xgmac_dev_info);
}
type_init(register_calxeda_xgmac_dev_type)
+615
View File
@@ -0,0 +1,615 @@
/*
* vfio based device assignment support - platform devices
*
* Copyright Linaro Limited, 2014
*
* Authors:
* Kim Phillips <kim.phillips@linaro.org>
* Eric Auger <eric.auger@linaro.org>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
* Based on vfio based PCI device assignment support:
* Copyright Red Hat, Inc. 2012
*/
#include <linux/vfio.h>
#include <sys/ioctl.h>
#include "hw/vfio/vfio-platform.h"
#include "qemu/error-report.h"
#include "qemu/range.h"
#include "sysemu/sysemu.h"
#include "exec/memory.h"
#include "qemu/queue.h"
#include "hw/sysbus.h"
#include "trace.h"
#include "hw/platform-bus.h"
/*
* Functions used whatever the injection method
*/
/**
* vfio_init_intp - allocate, initialize the IRQ struct pointer
* and add it into the list of IRQs
* @vbasedev: the VFIO device handle
* @info: irq info struct retrieved from VFIO driver
*/
static VFIOINTp *vfio_init_intp(VFIODevice *vbasedev,
struct vfio_irq_info info)
{
int ret;
VFIOPlatformDevice *vdev =
container_of(vbasedev, VFIOPlatformDevice, vbasedev);
SysBusDevice *sbdev = SYS_BUS_DEVICE(vdev);
VFIOINTp *intp;
intp = g_malloc0(sizeof(*intp));
intp->vdev = vdev;
intp->pin = info.index;
intp->flags = info.flags;
intp->state = VFIO_IRQ_INACTIVE;
sysbus_init_irq(sbdev, &intp->qemuirq);
/* Get an eventfd for trigger */
ret = event_notifier_init(&intp->interrupt, 0);
if (ret) {
g_free(intp);
error_report("vfio: Error: trigger event_notifier_init failed ");
return NULL;
}
QLIST_INSERT_HEAD(&vdev->intp_list, intp, next);
return intp;
}
/**
* vfio_set_trigger_eventfd - set VFIO eventfd handling
*
* @intp: IRQ struct handle
* @handler: handler to be called on eventfd signaling
*
* Setup VFIO signaling and attach an optional user-side handler
* to the eventfd
*/
static int vfio_set_trigger_eventfd(VFIOINTp *intp,
eventfd_user_side_handler_t handler)
{
VFIODevice *vbasedev = &intp->vdev->vbasedev;
struct vfio_irq_set *irq_set;
int argsz, ret;
int32_t *pfd;
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 = intp->pin;
irq_set->start = 0;
irq_set->count = 1;
pfd = (int32_t *)&irq_set->data;
*pfd = event_notifier_get_fd(&intp->interrupt);
qemu_set_fd_handler(*pfd, (IOHandler *)handler, NULL, intp);
ret = ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
g_free(irq_set);
if (ret < 0) {
error_report("vfio: Failed to set trigger eventfd: %m");
qemu_set_fd_handler(*pfd, NULL, NULL, NULL);
}
return ret;
}
/*
* Functions only used when eventfds are handled on user-side
* ie. without irqfd
*/
/**
* vfio_mmap_set_enabled - enable/disable the fast path mode
* @vdev: the VFIO platform device
* @enabled: the target mmap state
*
* enabled = true ~ fast path = MMIO region is mmaped (no KVM TRAP);
* enabled = false ~ slow path = MMIO region is trapped and region callbacks
* are called; slow path enables to trap the device IRQ status register reset
*/
static void vfio_mmap_set_enabled(VFIOPlatformDevice *vdev, bool enabled)
{
int i;
trace_vfio_platform_mmap_set_enabled(enabled);
for (i = 0; i < vdev->vbasedev.num_regions; i++) {
VFIORegion *region = vdev->regions[i];
memory_region_set_enabled(&region->mmap_mem, enabled);
}
}
/**
* vfio_intp_mmap_enable - timer function, restores the fast path
* if there is no more active IRQ
* @opaque: actually points to the VFIO platform device
*
* Called on mmap timer timout, this function checks whether the
* IRQ is still active and if not, restores the fast path.
* by construction a single eventfd is handled at a time.
* if the IRQ is still active, the timer is re-programmed.
*/
static void vfio_intp_mmap_enable(void *opaque)
{
VFIOINTp *tmp;
VFIOPlatformDevice *vdev = (VFIOPlatformDevice *)opaque;
qemu_mutex_lock(&vdev->intp_mutex);
QLIST_FOREACH(tmp, &vdev->intp_list, next) {
if (tmp->state == VFIO_IRQ_ACTIVE) {
trace_vfio_platform_intp_mmap_enable(tmp->pin);
/* re-program the timer to check active status later */
timer_mod(vdev->mmap_timer,
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
vdev->mmap_timeout);
qemu_mutex_unlock(&vdev->intp_mutex);
return;
}
}
vfio_mmap_set_enabled(vdev, true);
qemu_mutex_unlock(&vdev->intp_mutex);
}
/**
* vfio_intp_inject_pending_lockheld - Injects a pending IRQ
* @opaque: opaque pointer, in practice the VFIOINTp handle
*
* The function is called on a previous IRQ completion, from
* vfio_platform_eoi, while the intp_mutex is locked.
* Also in such situation, the slow path already is set and
* the mmap timer was already programmed.
*/
static void vfio_intp_inject_pending_lockheld(VFIOINTp *intp)
{
trace_vfio_platform_intp_inject_pending_lockheld(intp->pin,
event_notifier_get_fd(&intp->interrupt));
intp->state = VFIO_IRQ_ACTIVE;
/* trigger the virtual IRQ */
qemu_set_irq(intp->qemuirq, 1);
}
/**
* vfio_intp_interrupt - The user-side eventfd handler
* @opaque: opaque pointer which in practice is the VFIOINTp handle
*
* the function is entered in event handler context:
* the vIRQ is injected into the guest if there is no other active
* or pending IRQ.
*/
static void vfio_intp_interrupt(VFIOINTp *intp)
{
int ret;
VFIOINTp *tmp;
VFIOPlatformDevice *vdev = intp->vdev;
bool delay_handling = false;
qemu_mutex_lock(&vdev->intp_mutex);
if (intp->state == VFIO_IRQ_INACTIVE) {
QLIST_FOREACH(tmp, &vdev->intp_list, next) {
if (tmp->state == VFIO_IRQ_ACTIVE ||
tmp->state == VFIO_IRQ_PENDING) {
delay_handling = true;
break;
}
}
}
if (delay_handling) {
/*
* the new IRQ gets a pending status and is pushed in
* the pending queue
*/
intp->state = VFIO_IRQ_PENDING;
trace_vfio_intp_interrupt_set_pending(intp->pin);
QSIMPLEQ_INSERT_TAIL(&vdev->pending_intp_queue,
intp, pqnext);
ret = event_notifier_test_and_clear(&intp->interrupt);
qemu_mutex_unlock(&vdev->intp_mutex);
return;
}
trace_vfio_platform_intp_interrupt(intp->pin,
event_notifier_get_fd(&intp->interrupt));
ret = event_notifier_test_and_clear(&intp->interrupt);
if (!ret) {
error_report("Error when clearing fd=%d (ret = %d)\n",
event_notifier_get_fd(&intp->interrupt), ret);
}
intp->state = VFIO_IRQ_ACTIVE;
/* sets slow path */
vfio_mmap_set_enabled(vdev, false);
/* trigger the virtual IRQ */
qemu_set_irq(intp->qemuirq, 1);
/*
* Schedule the mmap timer which will restore fastpath when no IRQ
* is active anymore
*/
if (vdev->mmap_timeout) {
timer_mod(vdev->mmap_timer,
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
vdev->mmap_timeout);
}
qemu_mutex_unlock(&vdev->intp_mutex);
}
/**
* vfio_platform_eoi - IRQ completion routine
* @vbasedev: the VFIO device handle
*
* De-asserts the active virtual IRQ and unmasks the physical IRQ
* (effective for level sensitive IRQ auto-masked by the VFIO driver).
* Then it handles next pending IRQ if any.
* eoi function is called on the first access to any MMIO region
* after an IRQ was triggered, trapped since slow path was set.
* It is assumed this access corresponds to the IRQ status
* register reset. With such a mechanism, a single IRQ can be
* handled at a time since there is no way to know which IRQ
* was completed by the guest (we would need additional details
* about the IRQ status register mask).
*/
static void vfio_platform_eoi(VFIODevice *vbasedev)
{
VFIOINTp *intp;
VFIOPlatformDevice *vdev =
container_of(vbasedev, VFIOPlatformDevice, vbasedev);
qemu_mutex_lock(&vdev->intp_mutex);
QLIST_FOREACH(intp, &vdev->intp_list, next) {
if (intp->state == VFIO_IRQ_ACTIVE) {
trace_vfio_platform_eoi(intp->pin,
event_notifier_get_fd(&intp->interrupt));
intp->state = VFIO_IRQ_INACTIVE;
/* deassert the virtual IRQ */
qemu_set_irq(intp->qemuirq, 0);
if (intp->flags & VFIO_IRQ_INFO_AUTOMASKED) {
/* unmasks the physical level-sensitive IRQ */
vfio_unmask_single_irqindex(vbasedev, intp->pin);
}
/* a single IRQ can be active at a time */
break;
}
}
/* in case there are pending IRQs, handle the first one */
if (!QSIMPLEQ_EMPTY(&vdev->pending_intp_queue)) {
intp = QSIMPLEQ_FIRST(&vdev->pending_intp_queue);
vfio_intp_inject_pending_lockheld(intp);
QSIMPLEQ_REMOVE_HEAD(&vdev->pending_intp_queue, pqnext);
}
qemu_mutex_unlock(&vdev->intp_mutex);
}
/**
* vfio_start_eventfd_injection - starts the virtual IRQ injection using
* user-side handled eventfds
* @intp: the IRQ struct pointer
*/
static int vfio_start_eventfd_injection(VFIOINTp *intp)
{
int ret;
ret = vfio_set_trigger_eventfd(intp, vfio_intp_interrupt);
if (ret) {
error_report("vfio: Error: Failed to pass IRQ fd to the driver: %m");
}
return ret;
}
/* VFIO skeleton */
static void vfio_platform_compute_needs_reset(VFIODevice *vbasedev)
{
vbasedev->needs_reset = true;
}
/* not implemented yet */
static int vfio_platform_hot_reset_multi(VFIODevice *vbasedev)
{
return -1;
}
/**
* vfio_populate_device - Allocate and populate MMIO region
* and IRQ structs according to driver returned information
* @vbasedev: the VFIO device handle
*
*/
static int vfio_populate_device(VFIODevice *vbasedev)
{
VFIOINTp *intp, *tmp;
int i, ret = -1;
VFIOPlatformDevice *vdev =
container_of(vbasedev, VFIOPlatformDevice, vbasedev);
if (!(vbasedev->flags & VFIO_DEVICE_FLAGS_PLATFORM)) {
error_report("vfio: Um, this isn't a platform device");
return ret;
}
vdev->regions = g_new0(VFIORegion *, vbasedev->num_regions);
for (i = 0; i < vbasedev->num_regions; i++) {
struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) };
VFIORegion *ptr;
vdev->regions[i] = g_malloc0(sizeof(VFIORegion));
ptr = vdev->regions[i];
reg_info.index = i;
ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
if (ret) {
error_report("vfio: Error getting region %d info: %m", i);
goto reg_error;
}
ptr->flags = reg_info.flags;
ptr->size = reg_info.size;
ptr->fd_offset = reg_info.offset;
ptr->nr = i;
ptr->vbasedev = vbasedev;
trace_vfio_platform_populate_regions(ptr->nr,
(unsigned long)ptr->flags,
(unsigned long)ptr->size,
ptr->vbasedev->fd,
(unsigned long)ptr->fd_offset);
}
vdev->mmap_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
vfio_intp_mmap_enable, vdev);
QSIMPLEQ_INIT(&vdev->pending_intp_queue);
for (i = 0; i < vbasedev->num_irqs; i++) {
struct vfio_irq_info irq = { .argsz = sizeof(irq) };
irq.index = i;
ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
if (ret) {
error_printf("vfio: error getting device %s irq info",
vbasedev->name);
goto irq_err;
} else {
trace_vfio_platform_populate_interrupts(irq.index,
irq.count,
irq.flags);
intp = vfio_init_intp(vbasedev, irq);
if (!intp) {
error_report("vfio: Error installing IRQ %d up", i);
goto irq_err;
}
}
}
return 0;
irq_err:
timer_del(vdev->mmap_timer);
QLIST_FOREACH_SAFE(intp, &vdev->intp_list, next, tmp) {
QLIST_REMOVE(intp, next);
g_free(intp);
}
reg_error:
for (i = 0; i < vbasedev->num_regions; i++) {
g_free(vdev->regions[i]);
}
g_free(vdev->regions);
return ret;
}
/* specialized functions for VFIO Platform devices */
static VFIODeviceOps vfio_platform_ops = {
.vfio_compute_needs_reset = vfio_platform_compute_needs_reset,
.vfio_hot_reset_multi = vfio_platform_hot_reset_multi,
.vfio_eoi = vfio_platform_eoi,
};
/**
* vfio_base_device_init - perform preliminary VFIO setup
* @vbasedev: the VFIO device handle
*
* Implement the VFIO command sequence that allows to discover
* assigned device resources: group extraction, device
* fd retrieval, resource query.
* Precondition: the device name must be initialized
*/
static int vfio_base_device_init(VFIODevice *vbasedev)
{
VFIOGroup *group;
VFIODevice *vbasedev_iter;
char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name;
ssize_t len;
struct stat st;
int groupid;
int ret;
/* name must be set prior to the call */
if (!vbasedev->name || strchr(vbasedev->name, '/')) {
return -EINVAL;
}
/* Check that the host device exists */
g_snprintf(path, sizeof(path), "/sys/bus/platform/devices/%s/",
vbasedev->name);
if (stat(path, &st) < 0) {
error_report("vfio: error: no such host device: %s", path);
return -errno;
}
g_strlcat(path, "iommu_group", sizeof(path));
len = readlink(path, iommu_group_path, sizeof(iommu_group_path));
if (len < 0 || len >= sizeof(iommu_group_path)) {
error_report("vfio: error no iommu_group for device");
return len < 0 ? -errno : -ENAMETOOLONG;
}
iommu_group_path[len] = 0;
group_name = basename(iommu_group_path);
if (sscanf(group_name, "%d", &groupid) != 1) {
error_report("vfio: error reading %s: %m", path);
return -errno;
}
trace_vfio_platform_base_device_init(vbasedev->name, groupid);
group = vfio_get_group(groupid, &address_space_memory);
if (!group) {
error_report("vfio: failed to get group %d", groupid);
return -ENOENT;
}
g_snprintf(path, sizeof(path), "%s", vbasedev->name);
QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) {
error_report("vfio: error: device %s is already attached", path);
vfio_put_group(group);
return -EBUSY;
}
}
ret = vfio_get_device(group, path, vbasedev);
if (ret) {
error_report("vfio: failed to get device %s", path);
vfio_put_group(group);
return ret;
}
ret = vfio_populate_device(vbasedev);
if (ret) {
error_report("vfio: failed to populate device %s", path);
vfio_put_group(group);
}
return ret;
}
/**
* vfio_map_region - initialize the 2 memory regions for a given
* MMIO region index
* @vdev: the VFIO platform device handle
* @nr: the index of the region
*
* Init the top memory region and the mmapped memory region beneath
* VFIOPlatformDevice is used since VFIODevice is not a QOM Object
* and could not be passed to memory region functions
*/
static void vfio_map_region(VFIOPlatformDevice *vdev, int nr)
{
VFIORegion *region = vdev->regions[nr];
uint64_t size = region->size;
char name[64];
if (!size) {
return;
}
g_snprintf(name, sizeof(name), "VFIO %s region %d",
vdev->vbasedev.name, nr);
/* A "slow" read/write mapping underlies all regions */
memory_region_init_io(&region->mem, OBJECT(vdev), &vfio_region_ops,
region, name, size);
g_strlcat(name, " mmap", sizeof(name));
if (vfio_mmap_region(OBJECT(vdev), region, &region->mem,
&region->mmap_mem, &region->mmap, size, 0, name)) {
error_report("%s unsupported. Performance may be slow", name);
}
}
/**
* vfio_platform_realize - the device realize function
* @dev: device state pointer
* @errp: error
*
* initialize the device, its memory regions and IRQ structures
* IRQ are started separately
*/
static void vfio_platform_realize(DeviceState *dev, Error **errp)
{
VFIOPlatformDevice *vdev = VFIO_PLATFORM_DEVICE(dev);
SysBusDevice *sbdev = SYS_BUS_DEVICE(dev);
VFIODevice *vbasedev = &vdev->vbasedev;
VFIOINTp *intp;
int i, ret;
vbasedev->type = VFIO_DEVICE_TYPE_PLATFORM;
vbasedev->ops = &vfio_platform_ops;
trace_vfio_platform_realize(vbasedev->name, vdev->compat);
ret = vfio_base_device_init(vbasedev);
if (ret) {
error_setg(errp, "vfio: vfio_base_device_init failed for %s",
vbasedev->name);
return;
}
for (i = 0; i < vbasedev->num_regions; i++) {
vfio_map_region(vdev, i);
sysbus_init_mmio(sbdev, &vdev->regions[i]->mem);
}
QLIST_FOREACH(intp, &vdev->intp_list, next) {
vfio_start_eventfd_injection(intp);
}
}
static const VMStateDescription vfio_platform_vmstate = {
.name = TYPE_VFIO_PLATFORM,
.unmigratable = 1,
};
static Property vfio_platform_dev_properties[] = {
DEFINE_PROP_STRING("host", VFIOPlatformDevice, vbasedev.name),
DEFINE_PROP_BOOL("x-mmap", VFIOPlatformDevice, vbasedev.allow_mmap, true),
DEFINE_PROP_UINT32("mmap-timeout-ms", VFIOPlatformDevice,
mmap_timeout, 1100),
DEFINE_PROP_END_OF_LIST(),
};
static void vfio_platform_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = vfio_platform_realize;
dc->props = vfio_platform_dev_properties;
dc->vmsd = &vfio_platform_vmstate;
dc->desc = "VFIO-based platform device assignment";
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static const TypeInfo vfio_platform_dev_info = {
.name = TYPE_VFIO_PLATFORM,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(VFIOPlatformDevice),
.class_init = vfio_platform_class_init,
.class_size = sizeof(VFIOPlatformDeviceClass),
.abstract = true,
};
static void register_vfio_platform_dev_type(void)
{
type_register_static(&vfio_platform_dev_info);
}
type_init(register_vfio_platform_dev_type)
+26 -21
View File
@@ -157,15 +157,18 @@ bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
}
static int get_desc(Vring *vring, VirtQueueElement *elem,
static int get_desc(VirtIODevice *vdev, Vring *vring, VirtQueueElement *elem,
struct vring_desc *desc)
{
unsigned *num;
struct iovec *iov;
hwaddr *addr;
MemoryRegion *mr;
int is_write = virtio_tswap16(vdev, desc->flags) & VRING_DESC_F_WRITE;
uint32_t len = virtio_tswap32(vdev, desc->len);
uint64_t desc_addr = virtio_tswap64(vdev, desc->addr);
if (desc->flags & VRING_DESC_F_WRITE) {
if (is_write) {
num = &elem->in_num;
iov = &elem->in_sg[*num];
addr = &elem->in_addr[*num];
@@ -189,18 +192,17 @@ static int get_desc(Vring *vring, VirtQueueElement *elem,
}
/* TODO handle non-contiguous memory across region boundaries */
iov->iov_base = vring_map(&mr, desc->addr, desc->len,
desc->flags & VRING_DESC_F_WRITE);
iov->iov_base = vring_map(&mr, desc_addr, len, is_write);
if (!iov->iov_base) {
error_report("Failed to map descriptor addr %#" PRIx64 " len %u",
(uint64_t)desc->addr, desc->len);
(uint64_t)desc_addr, len);
return -EFAULT;
}
/* The MemoryRegion is looked up again and unref'ed later, leave the
* ref in place. */
iov->iov_len = desc->len;
*addr = desc->addr;
iov->iov_len = len;
*addr = desc_addr;
*num += 1;
return 0;
}
@@ -222,21 +224,23 @@ static int get_indirect(VirtIODevice *vdev, Vring *vring,
struct vring_desc desc;
unsigned int i = 0, count, found = 0;
int ret;
uint32_t len = virtio_tswap32(vdev, indirect->len);
uint64_t addr = virtio_tswap64(vdev, indirect->addr);
/* Sanity check */
if (unlikely(indirect->len % sizeof(desc))) {
if (unlikely(len % sizeof(desc))) {
error_report("Invalid length in indirect descriptor: "
"len %#x not multiple of %#zx",
indirect->len, sizeof(desc));
len, sizeof(desc));
vring->broken = true;
return -EFAULT;
}
count = indirect->len / sizeof(desc);
count = len / sizeof(desc);
/* Buffers are chained via a 16 bit next field, so
* we can have at most 2^16 of these. */
if (unlikely(count > USHRT_MAX + 1)) {
error_report("Indirect buffer length too big: %d", indirect->len);
error_report("Indirect buffer length too big: %d", len);
vring->broken = true;
return -EFAULT;
}
@@ -247,12 +251,12 @@ static int get_indirect(VirtIODevice *vdev, Vring *vring,
/* Translate indirect descriptor */
desc_ptr = vring_map(&mr,
indirect->addr + found * sizeof(desc),
addr + found * sizeof(desc),
sizeof(desc), false);
if (!desc_ptr) {
error_report("Failed to map indirect descriptor "
"addr %#" PRIx64 " len %zu",
(uint64_t)indirect->addr + found * sizeof(desc),
(uint64_t)addr + found * sizeof(desc),
sizeof(desc));
vring->broken = true;
return -EFAULT;
@@ -270,19 +274,20 @@ static int get_indirect(VirtIODevice *vdev, Vring *vring,
return -EFAULT;
}
if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) {
if (unlikely(virtio_tswap16(vdev, desc.flags)
& VRING_DESC_F_INDIRECT)) {
error_report("Nested indirect descriptor");
vring->broken = true;
return -EFAULT;
}
ret = get_desc(vring, elem, &desc);
ret = get_desc(vdev, vring, elem, &desc);
if (ret < 0) {
vring->broken |= (ret == -EFAULT);
return ret;
}
i = desc.next;
} while (desc.flags & VRING_DESC_F_NEXT);
i = virtio_tswap16(vdev, desc.next);
} while (virtio_tswap16(vdev, desc.flags) & VRING_DESC_F_NEXT);
return 0;
}
@@ -383,7 +388,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
/* Ensure descriptor is loaded before accessing fields */
barrier();
if (desc.flags & VRING_DESC_F_INDIRECT) {
if (virtio_tswap16(vdev, desc.flags) & VRING_DESC_F_INDIRECT) {
ret = get_indirect(vdev, vring, elem, &desc);
if (ret < 0) {
goto out;
@@ -391,13 +396,13 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
continue;
}
ret = get_desc(vring, elem, &desc);
ret = get_desc(vdev, vring, elem, &desc);
if (ret < 0) {
goto out;
}
i = desc.next;
} while (desc.flags & VRING_DESC_F_NEXT);
i = virtio_tswap16(vdev, desc.next);
} while (virtio_tswap16(vdev, desc.flags) & VRING_DESC_F_NEXT);
/* On success, increment avail index. */
vring->last_avail_idx++;
+8 -10
View File
@@ -591,7 +591,7 @@ static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
uint64_t features = dev->acked_features;
int r;
if (enable_log) {
features |= 0x1 << VHOST_F_LOG_ALL;
features |= 0x1ULL << VHOST_F_LOG_ALL;
}
r = dev->vhost_ops->vhost_call(dev, VHOST_SET_FEATURES, &features);
return r < 0 ? -errno : 0;
@@ -902,7 +902,7 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
.priority = 10
};
hdev->migration_blocker = NULL;
if (!(hdev->features & (0x1 << VHOST_F_LOG_ALL))) {
if (!(hdev->features & (0x1ULL << VHOST_F_LOG_ALL))) {
error_setg(&hdev->migration_blocker,
"Migration disabled: vhost lacks VHOST_F_LOG_ALL feature.");
migrate_add_blocker(hdev->migration_blocker);
@@ -1045,12 +1045,12 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
assert(r >= 0);
}
unsigned vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
unsigned features)
uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
uint64_t features)
{
const int *bit = feature_bits;
while (*bit != VHOST_INVALID_FEATURE_BIT) {
unsigned bit_mask = (1 << *bit);
uint64_t bit_mask = (1ULL << *bit);
if (!(hdev->features & bit_mask)) {
features &= ~bit_mask;
}
@@ -1060,11 +1060,11 @@ unsigned vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
}
void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits,
unsigned features)
uint64_t features)
{
const int *bit = feature_bits;
while (*bit != VHOST_INVALID_FEATURE_BIT) {
unsigned bit_mask = (1 << *bit);
uint64_t bit_mask = (1ULL << *bit);
if (features & bit_mask) {
hdev->acked_features |= bit_mask;
}
@@ -1114,9 +1114,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
return 0;
fail_log:
if (hdev->log_size) {
vhost_log_put(hdev, false);
}
vhost_log_put(hdev, false);
fail_vq:
while (--i >= 0) {
vhost_virtqueue_stop(hdev,
+1 -1
View File
@@ -312,7 +312,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f)
{
f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
virtio_add_feature(&f, VIRTIO_BALLOON_F_STATS_VQ);
return f;
}
+3
View File
@@ -333,8 +333,11 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
case VIRTIO_MMIO_QUEUENUM:
DPRINTF("mmio_queue write %d max %d\n", (int)value, VIRTQUEUE_MAX_SIZE);
virtio_queue_set_num(vdev, vdev->queue_sel, value);
/* Note: only call this function for legacy devices */
virtio_queue_update_rings(vdev, vdev->queue_sel);
break;
case VIRTIO_MMIO_QUEUEALIGN:
/* Note: this is only valid for legacy devices */
virtio_queue_set_align(vdev, vdev->queue_sel, value);
break;
case VIRTIO_MMIO_QUEUEPFN:
+592 -20
View File
@@ -24,6 +24,7 @@
#include "hw/virtio/virtio-serial.h"
#include "hw/virtio/virtio-scsi.h"
#include "hw/virtio/virtio-balloon.h"
#include "hw/virtio/virtio-input.h"
#include "hw/pci/pci.h"
#include "qemu/error-report.h"
#include "hw/pci/msi.h"
@@ -38,6 +39,8 @@
#define VIRTIO_PCI_REGION_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_present(dev))
#undef VIRTIO_PCI_CONFIG
/* The remaining space is defined by each driver as the per-driver
* configuration space */
#define VIRTIO_PCI_CONFIG_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_enabled(dev))
@@ -133,12 +136,21 @@ static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
return 0;
}
#define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000
static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
int n, bool assign, bool set_handler)
{
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtQueue *vq = virtio_get_queue(vdev, n);
EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
MemoryRegion *modern_mr = &proxy->notify.mr;
MemoryRegion *legacy_mr = &proxy->bar;
hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
virtio_get_queue_index(vq);
hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY;
int r = 0;
if (assign) {
@@ -149,11 +161,23 @@ static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
return r;
}
virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
true, n, notifier);
if (modern) {
memory_region_add_eventfd(modern_mr, modern_addr, 2,
true, n, notifier);
}
if (legacy) {
memory_region_add_eventfd(legacy_mr, legacy_addr, 2,
true, n, notifier);
}
} else {
memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
true, n, notifier);
if (modern) {
memory_region_del_eventfd(modern_mr, modern_addr, 2,
true, n, notifier);
}
if (legacy) {
memory_region_del_eventfd(legacy_mr, legacy_addr, 2,
true, n, notifier);
}
virtio_queue_set_host_notifier_fd_handler(vq, false, false);
event_notifier_cleanup(notifier);
}
@@ -918,11 +942,359 @@ static int virtio_pci_query_nvectors(DeviceState *d)
return proxy->nvectors;
}
static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
struct virtio_pci_cap *cap)
{
PCIDevice *dev = &proxy->pci_dev;
int offset;
offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, cap->cap_len);
assert(offset > 0);
assert(cap->cap_len >= sizeof *cap);
memcpy(dev->config + offset + PCI_CAP_FLAGS, &cap->cap_len,
cap->cap_len - PCI_CAP_FLAGS);
}
static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
unsigned size)
{
VirtIOPCIProxy *proxy = opaque;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
uint32_t val = 0;
int i;
switch (addr) {
case VIRTIO_PCI_COMMON_DFSELECT:
val = proxy->dfselect;
break;
case VIRTIO_PCI_COMMON_DF:
if (proxy->dfselect <= 1) {
val = vdev->host_features >> (32 * proxy->dfselect);
}
break;
case VIRTIO_PCI_COMMON_GFSELECT:
val = proxy->gfselect;
break;
case VIRTIO_PCI_COMMON_GF:
if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {
val = proxy->guest_features[proxy->gfselect];
}
break;
case VIRTIO_PCI_COMMON_MSIX:
val = vdev->config_vector;
break;
case VIRTIO_PCI_COMMON_NUMQ:
for (i = 0; i < VIRTIO_QUEUE_MAX; ++i) {
if (virtio_queue_get_num(vdev, i)) {
val = i + 1;
}
}
break;
case VIRTIO_PCI_COMMON_STATUS:
val = vdev->status;
break;
case VIRTIO_PCI_COMMON_CFGGENERATION:
val = vdev->generation;
break;
case VIRTIO_PCI_COMMON_Q_SELECT:
val = vdev->queue_sel;
break;
case VIRTIO_PCI_COMMON_Q_SIZE:
val = virtio_queue_get_num(vdev, vdev->queue_sel);
break;
case VIRTIO_PCI_COMMON_Q_MSIX:
val = virtio_queue_vector(vdev, vdev->queue_sel);
break;
case VIRTIO_PCI_COMMON_Q_ENABLE:
val = proxy->vqs[vdev->queue_sel].enabled;
break;
case VIRTIO_PCI_COMMON_Q_NOFF:
/* Simply map queues in order */
val = vdev->queue_sel;
break;
case VIRTIO_PCI_COMMON_Q_DESCLO:
val = proxy->vqs[vdev->queue_sel].desc[0];
break;
case VIRTIO_PCI_COMMON_Q_DESCHI:
val = proxy->vqs[vdev->queue_sel].desc[1];
break;
case VIRTIO_PCI_COMMON_Q_AVAILLO:
val = proxy->vqs[vdev->queue_sel].avail[0];
break;
case VIRTIO_PCI_COMMON_Q_AVAILHI:
val = proxy->vqs[vdev->queue_sel].avail[1];
break;
case VIRTIO_PCI_COMMON_Q_USEDLO:
val = proxy->vqs[vdev->queue_sel].used[0];
break;
case VIRTIO_PCI_COMMON_Q_USEDHI:
val = proxy->vqs[vdev->queue_sel].used[1];
break;
default:
val = 0;
}
return val;
}
static void virtio_pci_common_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
VirtIOPCIProxy *proxy = opaque;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
switch (addr) {
case VIRTIO_PCI_COMMON_DFSELECT:
proxy->dfselect = val;
break;
case VIRTIO_PCI_COMMON_GFSELECT:
proxy->gfselect = val;
break;
case VIRTIO_PCI_COMMON_GF:
if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {
proxy->guest_features[proxy->gfselect] = val;
virtio_set_features(vdev,
(((uint64_t)proxy->guest_features[1]) << 32) |
proxy->guest_features[0]);
}
break;
case VIRTIO_PCI_COMMON_MSIX:
msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
/* Make it possible for guest to discover an error took place. */
if (msix_vector_use(&proxy->pci_dev, val) < 0) {
val = VIRTIO_NO_VECTOR;
}
vdev->config_vector = val;
break;
case VIRTIO_PCI_COMMON_STATUS:
if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
virtio_pci_stop_ioeventfd(proxy);
}
virtio_set_status(vdev, val & 0xFF);
if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
virtio_pci_start_ioeventfd(proxy);
}
if (vdev->status == 0) {
virtio_reset(vdev);
msix_unuse_all_vectors(&proxy->pci_dev);
}
break;
case VIRTIO_PCI_COMMON_Q_SELECT:
if (val < VIRTIO_QUEUE_MAX) {
vdev->queue_sel = val;
}
break;
case VIRTIO_PCI_COMMON_Q_SIZE:
proxy->vqs[vdev->queue_sel].num = val;
break;
case VIRTIO_PCI_COMMON_Q_MSIX:
msix_vector_unuse(&proxy->pci_dev,
virtio_queue_vector(vdev, vdev->queue_sel));
/* Make it possible for guest to discover an error took place. */
if (msix_vector_use(&proxy->pci_dev, val) < 0) {
val = VIRTIO_NO_VECTOR;
}
virtio_queue_set_vector(vdev, vdev->queue_sel, val);
break;
case VIRTIO_PCI_COMMON_Q_ENABLE:
/* TODO: need a way to put num back on reset. */
virtio_queue_set_num(vdev, vdev->queue_sel,
proxy->vqs[vdev->queue_sel].num);
virtio_queue_set_rings(vdev, vdev->queue_sel,
((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
proxy->vqs[vdev->queue_sel].desc[0],
((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
proxy->vqs[vdev->queue_sel].avail[0],
((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
proxy->vqs[vdev->queue_sel].used[0]);
break;
case VIRTIO_PCI_COMMON_Q_DESCLO:
proxy->vqs[vdev->queue_sel].desc[0] = val;
break;
case VIRTIO_PCI_COMMON_Q_DESCHI:
proxy->vqs[vdev->queue_sel].desc[1] = val;
break;
case VIRTIO_PCI_COMMON_Q_AVAILLO:
proxy->vqs[vdev->queue_sel].avail[0] = val;
break;
case VIRTIO_PCI_COMMON_Q_AVAILHI:
proxy->vqs[vdev->queue_sel].avail[1] = val;
break;
case VIRTIO_PCI_COMMON_Q_USEDLO:
proxy->vqs[vdev->queue_sel].used[0] = val;
break;
case VIRTIO_PCI_COMMON_Q_USEDHI:
proxy->vqs[vdev->queue_sel].used[1] = val;
break;
default:
break;
}
}
static uint64_t virtio_pci_notify_read(void *opaque, hwaddr addr,
unsigned size)
{
return 0;
}
static void virtio_pci_notify_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
VirtIODevice *vdev = opaque;
unsigned queue = addr / QEMU_VIRTIO_PCI_QUEUE_MEM_MULT;
if (queue < VIRTIO_QUEUE_MAX) {
virtio_queue_notify(vdev, queue);
}
}
static uint64_t virtio_pci_isr_read(void *opaque, hwaddr addr,
unsigned size)
{
VirtIOPCIProxy *proxy = opaque;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
uint64_t val = vdev->isr;
vdev->isr = 0;
pci_irq_deassert(&proxy->pci_dev);
return val;
}
static void virtio_pci_isr_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
}
static uint64_t virtio_pci_device_read(void *opaque, hwaddr addr,
unsigned size)
{
VirtIODevice *vdev = opaque;
uint64_t val = 0;
switch (size) {
case 1:
val = virtio_config_modern_readb(vdev, addr);
break;
case 2:
val = virtio_config_modern_readw(vdev, addr);
break;
case 4:
val = virtio_config_modern_readl(vdev, addr);
break;
}
return val;
}
static void virtio_pci_device_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
VirtIODevice *vdev = opaque;
switch (size) {
case 1:
virtio_config_modern_writeb(vdev, addr, val);
break;
case 2:
virtio_config_modern_writew(vdev, addr, val);
break;
case 4:
virtio_config_modern_writel(vdev, addr, val);
break;
}
}
static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy)
{
static const MemoryRegionOps common_ops = {
.read = virtio_pci_common_read,
.write = virtio_pci_common_write,
.impl = {
.min_access_size = 1,
.max_access_size = 4,
},
.endianness = DEVICE_LITTLE_ENDIAN,
};
static const MemoryRegionOps isr_ops = {
.read = virtio_pci_isr_read,
.write = virtio_pci_isr_write,
.impl = {
.min_access_size = 1,
.max_access_size = 4,
},
.endianness = DEVICE_LITTLE_ENDIAN,
};
static const MemoryRegionOps device_ops = {
.read = virtio_pci_device_read,
.write = virtio_pci_device_write,
.impl = {
.min_access_size = 1,
.max_access_size = 4,
},
.endianness = DEVICE_LITTLE_ENDIAN,
};
static const MemoryRegionOps notify_ops = {
.read = virtio_pci_notify_read,
.write = virtio_pci_notify_write,
.impl = {
.min_access_size = 1,
.max_access_size = 4,
},
.endianness = DEVICE_LITTLE_ENDIAN,
};
memory_region_init_io(&proxy->common.mr, OBJECT(proxy),
&common_ops,
proxy,
"virtio-pci-common",
proxy->common.size);
memory_region_init_io(&proxy->isr.mr, OBJECT(proxy),
&isr_ops,
proxy,
"virtio-pci-isr",
proxy->isr.size);
memory_region_init_io(&proxy->device.mr, OBJECT(proxy),
&device_ops,
virtio_bus_get_device(&proxy->bus),
"virtio-pci-device",
proxy->device.size);
memory_region_init_io(&proxy->notify.mr, OBJECT(proxy),
&notify_ops,
virtio_bus_get_device(&proxy->bus),
"virtio-pci-notify",
proxy->notify.size);
}
static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy,
VirtIOPCIRegion *region,
struct virtio_pci_cap *cap)
{
memory_region_add_subregion(&proxy->modern_bar,
region->offset,
&region->mr);
cap->cfg_type = region->type;
cap->bar = proxy->modern_mem_bar;
cap->offset = cpu_to_le32(region->offset);
cap->length = cpu_to_le32(region->size);
virtio_pci_add_mem_cap(proxy, cap);
}
/* This is called by virtio-bus just after the device is plugged. */
static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
VirtioBusState *bus = &proxy->bus;
bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
uint8_t *config;
uint32_t size;
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
@@ -931,13 +1303,51 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
if (proxy->class_code) {
pci_config_set_class(config, proxy->class_code);
}
pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
pci_get_word(config + PCI_VENDOR_ID));
pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
if (legacy) {
/* legacy and transitional */
pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
pci_get_word(config + PCI_VENDOR_ID));
pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
} else {
/* pure virtio-1.0 */
pci_set_word(config + PCI_VENDOR_ID,
PCI_VENDOR_ID_REDHAT_QUMRANET);
pci_set_word(config + PCI_DEVICE_ID,
0x1040 + virtio_bus_get_vdev_id(bus));
pci_config_set_revision(config, 1);
}
config[PCI_INTERRUPT_PIN] = 1;
if (modern) {
struct virtio_pci_cap cap = {
.cap_len = sizeof cap,
};
struct virtio_pci_notify_cap notify = {
.cap.cap_len = sizeof notify,
.notify_off_multiplier =
cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT),
};
/* TODO: add io access for speed */
virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
virtio_pci_modern_regions_init(proxy);
virtio_pci_modern_region_map(proxy, &proxy->common, &cap);
virtio_pci_modern_region_map(proxy, &proxy->isr, &cap);
virtio_pci_modern_region_map(proxy, &proxy->device, &cap);
virtio_pci_modern_region_map(proxy, &proxy->notify, &notify.cap);
pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar,
PCI_BASE_ADDRESS_SPACE_MEMORY |
PCI_BASE_ADDRESS_MEM_PREFETCH |
PCI_BASE_ADDRESS_MEM_TYPE_64,
&proxy->modern_bar);
}
if (proxy->nvectors &&
msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors,
proxy->msix_bar)) {
error_report("unable to init msix vectors to %" PRIu32,
proxy->nvectors);
proxy->nvectors = 0;
@@ -945,16 +1355,20 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
proxy->pci_dev.config_write = virtio_write_config;
size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
+ virtio_bus_get_vdev_config_len(bus);
if (size & (size - 1)) {
size = 1 << qemu_fls(size);
}
if (legacy) {
size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
+ virtio_bus_get_vdev_config_len(bus);
if (size & (size - 1)) {
size = 1 << qemu_fls(size);
}
memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops,
proxy, "virtio-pci", size);
pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
&proxy->bar);
memory_region_init_io(&proxy->bar, OBJECT(proxy),
&virtio_pci_config_ops,
proxy, "virtio-pci", size);
pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar,
PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar);
}
if (!kvm_has_many_ioeventfds()) {
proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
@@ -972,12 +1386,47 @@ static void virtio_pci_device_unplugged(DeviceState *d)
static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
{
VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
virtio_pci_bus_new(&dev->bus, sizeof(dev->bus), dev);
/*
* virtio pci bar layout used by default.
* subclasses can re-arrange things if needed.
*
* region 0 -- virtio legacy io bar
* region 1 -- msi-x bar
* region 4+5 -- virtio modern memory (64bit) bar
*
*/
proxy->legacy_io_bar = 0;
proxy->msix_bar = 1;
proxy->modern_mem_bar = 4;
proxy->common.offset = 0x0;
proxy->common.size = 0x1000;
proxy->common.type = VIRTIO_PCI_CAP_COMMON_CFG;
proxy->isr.offset = 0x1000;
proxy->isr.size = 0x1000;
proxy->isr.type = VIRTIO_PCI_CAP_ISR_CFG;
proxy->device.offset = 0x2000;
proxy->device.size = 0x1000;
proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG;
proxy->notify.offset = 0x3000;
proxy->notify.size =
QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX;
proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG;
/* subclasses can enforce modern, so do this unconditionally */
memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci",
2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
VIRTIO_QUEUE_MAX);
virtio_pci_bus_new(&proxy->bus, sizeof(proxy->bus), proxy);
if (k->realize) {
k->realize(dev, errp);
k->realize(proxy, errp);
}
}
@@ -998,6 +1447,10 @@ static void virtio_pci_reset(DeviceState *qdev)
static Property virtio_pci_properties[] = {
DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false),
DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1445,6 +1898,120 @@ static const TypeInfo virtio_rng_pci_info = {
.class_init = virtio_rng_pci_class_init,
};
/* virtio-input-pci */
static Property virtio_input_hid_pci_properties[] = {
DEFINE_VIRTIO_INPUT_PROPERTIES(VirtIOInputPCI, vdev.input),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
DEFINE_PROP_END_OF_LIST(),
};
static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&vinput->vdev);
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
/* force virtio-1.0 */
vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
}
static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
k->realize = virtio_input_pci_realize;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
pcidev_k->class_id = PCI_CLASS_INPUT_OTHER;
}
static void virtio_input_hid_pci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = virtio_input_hid_pci_properties;
}
static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD;
}
static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass,
void *data)
{
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE;
}
static void virtio_keyboard_initfn(Object *obj)
{
VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_KEYBOARD);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
}
static void virtio_mouse_initfn(Object *obj)
{
VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_MOUSE);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
}
static void virtio_tablet_initfn(Object *obj)
{
VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_TABLET);
object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
}
static const TypeInfo virtio_input_pci_info = {
.name = TYPE_VIRTIO_INPUT_PCI,
.parent = TYPE_VIRTIO_PCI,
.instance_size = sizeof(VirtIOInputPCI),
.class_init = virtio_input_pci_class_init,
.abstract = true,
};
static const TypeInfo virtio_input_hid_pci_info = {
.name = TYPE_VIRTIO_INPUT_HID_PCI,
.parent = TYPE_VIRTIO_INPUT_PCI,
.instance_size = sizeof(VirtIOInputHIDPCI),
.class_init = virtio_input_hid_pci_class_init,
.abstract = true,
};
static const TypeInfo virtio_keyboard_pci_info = {
.name = TYPE_VIRTIO_KEYBOARD_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
.class_init = virtio_input_hid_kbd_pci_class_init,
.instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_keyboard_initfn,
};
static const TypeInfo virtio_mouse_pci_info = {
.name = TYPE_VIRTIO_MOUSE_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
.class_init = virtio_input_hid_mouse_pci_class_init,
.instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_mouse_initfn,
};
static const TypeInfo virtio_tablet_pci_info = {
.name = TYPE_VIRTIO_TABLET_PCI,
.parent = TYPE_VIRTIO_INPUT_HID_PCI,
.instance_size = sizeof(VirtIOInputHIDPCI),
.instance_init = virtio_tablet_initfn,
};
/* virtio-pci-bus */
static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
@@ -1486,6 +2053,11 @@ static const TypeInfo virtio_pci_bus_info = {
static void virtio_pci_register_types(void)
{
type_register_static(&virtio_rng_pci_info);
type_register_static(&virtio_input_pci_info);
type_register_static(&virtio_input_hid_pci_info);
type_register_static(&virtio_keyboard_pci_info);
type_register_static(&virtio_mouse_pci_info);
type_register_static(&virtio_tablet_pci_info);
type_register_static(&virtio_pci_bus_info);
type_register_static(&virtio_pci_info);
#ifdef CONFIG_VIRTFS
+59
View File
@@ -24,6 +24,7 @@
#include "hw/virtio/virtio-balloon.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-9p.h"
#include "hw/virtio/virtio-input.h"
#ifdef CONFIG_VIRTFS
#include "hw/9pfs/virtio-9p.h"
#endif
@@ -39,6 +40,8 @@ typedef struct VirtIOSerialPCI VirtIOSerialPCI;
typedef struct VirtIONetPCI VirtIONetPCI;
typedef struct VHostSCSIPCI VHostSCSIPCI;
typedef struct VirtIORngPCI VirtIORngPCI;
typedef struct VirtIOInputPCI VirtIOInputPCI;
typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
/* virtio-pci-bus */
@@ -63,6 +66,12 @@ typedef struct VirtioBusClass VirtioPCIBusClass;
#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
#define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
/* virtio version flags */
#define VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT 2
#define VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT 3
#define VIRTIO_PCI_FLAG_DISABLE_LEGACY (1 << VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT)
#define VIRTIO_PCI_FLAG_DISABLE_MODERN (1 << VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT)
typedef struct {
MSIMessage msg;
int virq;
@@ -85,12 +94,38 @@ typedef struct VirtioPCIClass {
void (*realize)(VirtIOPCIProxy *vpci_dev, Error **errp);
} VirtioPCIClass;
typedef struct VirtIOPCIRegion {
MemoryRegion mr;
uint32_t offset;
uint32_t size;
uint32_t type;
} VirtIOPCIRegion;
struct VirtIOPCIProxy {
PCIDevice pci_dev;
MemoryRegion bar;
VirtIOPCIRegion common;
VirtIOPCIRegion isr;
VirtIOPCIRegion device;
VirtIOPCIRegion notify;
MemoryRegion modern_bar;
uint32_t legacy_io_bar;
uint32_t msix_bar;
uint32_t modern_mem_bar;
uint32_t flags;
uint32_t class_code;
uint32_t nvectors;
uint32_t dfselect;
uint32_t gfselect;
uint32_t guest_features[2];
struct {
uint16_t num;
bool enabled;
uint32_t desc[2];
uint32_t avail[2];
uint32_t used[2];
} vqs[VIRTIO_QUEUE_MAX];
bool ioeventfd_disabled;
bool ioeventfd_started;
VirtIOIRQFD *vector_irqfd;
@@ -202,6 +237,30 @@ struct VirtIORngPCI {
VirtIORNG vdev;
};
/*
* virtio-input-pci: This extends VirtioPCIProxy.
*/
#define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci"
#define VIRTIO_INPUT_PCI(obj) \
OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI)
struct VirtIOInputPCI {
VirtIOPCIProxy parent_obj;
VirtIOInput vdev;
};
#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci"
#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci"
#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci"
#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci"
#define VIRTIO_INPUT_HID_PCI(obj) \
OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI)
struct VirtIOInputHIDPCI {
VirtIOPCIProxy parent_obj;
VirtIOInputHID vdev;
};
/* Virtio ABI version, if we increment this, we break the guest driver. */
#define VIRTIO_PCI_ABI_VERSION 0
+7 -1
View File
@@ -219,7 +219,13 @@ static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp)
}
static Property virtio_rng_properties[] = {
DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNG, conf),
/* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If
* you have an entropy source capable of generating more entropy than this
* and you can pass it through via virtio-rng, then hats off to you. Until
* then, this is unlimited for all practical purposes.
*/
DEFINE_PROP_UINT64("max-bytes", VirtIORNG, conf.max_bytes, INT64_MAX),
DEFINE_PROP_UINT32("period", VirtIORNG, conf.period_ms, 1 << 16),
DEFINE_PROP_END_OF_LIST(),
};
+180 -34
View File
@@ -69,7 +69,6 @@ typedef struct VRing
struct VirtQueue
{
VRing vring;
hwaddr pa;
uint16_t last_avail_idx;
/* Last used index value we have signalled on */
uint16_t signalled_used;
@@ -93,15 +92,18 @@ struct VirtQueue
};
/* virt queue functions */
static void virtqueue_init(VirtQueue *vq)
void virtio_queue_update_rings(VirtIODevice *vdev, int n)
{
hwaddr pa = vq->pa;
VRing *vring = &vdev->vq[n].vring;
vq->vring.desc = pa;
vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc);
vq->vring.used = vring_align(vq->vring.avail +
offsetof(VRingAvail, ring[vq->vring.num]),
vq->vring.align);
if (!vring->desc) {
/* not yet setup -> nothing to do */
return;
}
vring->avail = vring->desc + vring->num * sizeof(VRingDesc);
vring->used = vring_align(vring->avail +
offsetof(VRingAvail, ring[vring->num]),
vring->align);
}
static inline uint64_t vring_desc_addr(VirtIODevice *vdev, hwaddr desc_pa,
@@ -542,15 +544,37 @@ void virtio_update_irq(VirtIODevice *vdev)
virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
}
void virtio_set_status(VirtIODevice *vdev, uint8_t val)
static int virtio_validate_features(VirtIODevice *vdev)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
if (k->validate_features) {
return k->validate_features(vdev);
} else {
return 0;
}
}
int virtio_set_status(VirtIODevice *vdev, uint8_t val)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
trace_virtio_set_status(vdev, val);
if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
if (!(vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) &&
val & VIRTIO_CONFIG_S_FEATURES_OK) {
int ret = virtio_validate_features(vdev);
if (ret) {
return ret;
}
}
}
if (k->set_status) {
k->set_status(vdev, val);
}
vdev->status = val;
return 0;
}
bool target_words_bigendian(void);
@@ -605,7 +629,6 @@ void virtio_reset(void *opaque)
vdev->vq[i].vring.avail = 0;
vdev->vq[i].vring.used = 0;
vdev->vq[i].last_avail_idx = 0;
vdev->vq[i].pa = 0;
virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
vdev->vq[i].signalled_used = 0;
vdev->vq[i].signalled_used_valid = false;
@@ -706,15 +729,119 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
}
}
uint32_t virtio_config_modern_readb(VirtIODevice *vdev, uint32_t addr)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint8_t val;
if (addr + sizeof(val) > vdev->config_len) {
return (uint32_t)-1;
}
k->get_config(vdev, vdev->config);
val = ldub_p(vdev->config + addr);
return val;
}
uint32_t virtio_config_modern_readw(VirtIODevice *vdev, uint32_t addr)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint16_t val;
if (addr + sizeof(val) > vdev->config_len) {
return (uint32_t)-1;
}
k->get_config(vdev, vdev->config);
val = lduw_le_p(vdev->config + addr);
return val;
}
uint32_t virtio_config_modern_readl(VirtIODevice *vdev, uint32_t addr)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint32_t val;
if (addr + sizeof(val) > vdev->config_len) {
return (uint32_t)-1;
}
k->get_config(vdev, vdev->config);
val = ldl_le_p(vdev->config + addr);
return val;
}
void virtio_config_modern_writeb(VirtIODevice *vdev,
uint32_t addr, uint32_t data)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint8_t val = data;
if (addr + sizeof(val) > vdev->config_len) {
return;
}
stb_p(vdev->config + addr, val);
if (k->set_config) {
k->set_config(vdev, vdev->config);
}
}
void virtio_config_modern_writew(VirtIODevice *vdev,
uint32_t addr, uint32_t data)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint16_t val = data;
if (addr + sizeof(val) > vdev->config_len) {
return;
}
stw_le_p(vdev->config + addr, val);
if (k->set_config) {
k->set_config(vdev, vdev->config);
}
}
void virtio_config_modern_writel(VirtIODevice *vdev,
uint32_t addr, uint32_t data)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
uint32_t val = data;
if (addr + sizeof(val) > vdev->config_len) {
return;
}
stl_le_p(vdev->config + addr, val);
if (k->set_config) {
k->set_config(vdev, vdev->config);
}
}
void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
{
vdev->vq[n].pa = addr;
virtqueue_init(&vdev->vq[n]);
vdev->vq[n].vring.desc = addr;
virtio_queue_update_rings(vdev, n);
}
hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n)
{
return vdev->vq[n].pa;
return vdev->vq[n].vring.desc;
}
void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc,
hwaddr avail, hwaddr used)
{
vdev->vq[n].vring.desc = desc;
vdev->vq[n].vring.avail = avail;
vdev->vq[n].vring.used = used;
}
void virtio_queue_set_num(VirtIODevice *vdev, int n, int num)
@@ -728,7 +855,6 @@ void virtio_queue_set_num(VirtIODevice *vdev, int n, int num)
return;
}
vdev->vq[n].vring.num = num;
virtqueue_init(&vdev->vq[n]);
}
VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector)
@@ -771,6 +897,11 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
/* virtio-1 compliant devices cannot change the alignment */
if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
error_report("tried to modify queue alignment for virtio-1 device");
return;
}
/* Check that the transport told us it was going to do this
* (so a buggy transport will immediately assert rather than
* silently failing to migrate this state)
@@ -778,7 +909,7 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
assert(k->has_variable_vring_alignment);
vdev->vq[n].vring.align = align;
virtqueue_init(&vdev->vq[n]);
virtio_queue_update_rings(vdev, n);
}
void virtio_queue_notify_vq(VirtQueue *vq)
@@ -895,6 +1026,7 @@ void virtio_notify_config(VirtIODevice *vdev)
return;
vdev->isr |= 0x03;
vdev->generation++;
virtio_notify_vector(vdev, vdev->config_vector);
}
@@ -903,7 +1035,11 @@ static bool virtio_device_endian_needed(void *opaque)
VirtIODevice *vdev = opaque;
assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN);
return vdev->device_endian != virtio_default_endian();
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
return vdev->device_endian != virtio_default_endian();
}
/* Devices conforming to VIRTIO 1.0 or later are always LE. */
return vdev->device_endian != VIRTIO_DEVICE_ENDIAN_LITTLE;
}
static bool virtio_64bit_features_needed(void *opaque)
@@ -917,6 +1053,7 @@ static const VMStateDescription vmstate_virtio_device_endian = {
.name = "virtio/device_endian",
.version_id = 1,
.minimum_version_id = 1,
.needed = &virtio_device_endian_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(device_endian, VirtIODevice),
VMSTATE_END_OF_LIST()
@@ -927,6 +1064,7 @@ static const VMStateDescription vmstate_virtio_64bit_features = {
.name = "virtio/64bit_features",
.version_id = 1,
.minimum_version_id = 1,
.needed = &virtio_64bit_features_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT64(guest_features, VirtIODevice),
VMSTATE_END_OF_LIST()
@@ -941,16 +1079,10 @@ static const VMStateDescription vmstate_virtio = {
.fields = (VMStateField[]) {
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection[]) {
{
.vmsd = &vmstate_virtio_device_endian,
.needed = &virtio_device_endian_needed
},
{
.vmsd = &vmstate_virtio_64bit_features,
.needed = &virtio_64bit_features_needed
},
{ 0 }
.subsections = (const VMStateDescription*[]) {
&vmstate_virtio_device_endian,
&vmstate_virtio_64bit_features,
NULL
}
};
@@ -988,7 +1120,8 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
if (k->has_variable_vring_alignment) {
qemu_put_be32(f, vdev->vq[i].vring.align);
}
qemu_put_be64(f, vdev->vq[i].pa);
/* XXX virtio-1 devices */
qemu_put_be64(f, vdev->vq[i].vring.desc);
qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
if (k->save_queue) {
k->save_queue(qbus->parent, i, f);
@@ -1003,7 +1136,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
vmstate_save_state(f, &vmstate_virtio, vdev, NULL);
}
int virtio_set_features(VirtIODevice *vdev, uint64_t val)
static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
bool bad = (val & ~(vdev->host_features)) != 0;
@@ -1016,6 +1149,18 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val)
return bad ? -1 : 0;
}
int virtio_set_features(VirtIODevice *vdev, uint64_t val)
{
/*
* The driver must not attempt to set features after feature negotiation
* has finished.
*/
if (vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) {
return -EINVAL;
}
return virtio_set_features_nocheck(vdev, val);
}
int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
{
int i, ret;
@@ -1072,13 +1217,14 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
if (k->has_variable_vring_alignment) {
vdev->vq[i].vring.align = qemu_get_be32(f);
}
vdev->vq[i].pa = qemu_get_be64(f);
vdev->vq[i].vring.desc = qemu_get_be64(f);
qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
vdev->vq[i].signalled_used_valid = false;
vdev->vq[i].notification = true;
if (vdev->vq[i].pa) {
virtqueue_init(&vdev->vq[i]);
if (vdev->vq[i].vring.desc) {
/* XXX virtio-1 devices */
virtio_queue_update_rings(vdev, i);
} else if (vdev->vq[i].last_avail_idx) {
error_report("VQ %d address 0x0 "
"inconsistent with Host index 0x%x",
@@ -1118,14 +1264,14 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
* host_features.
*/
uint64_t features64 = vdev->guest_features;
if (virtio_set_features(vdev, features64) < 0) {
if (virtio_set_features_nocheck(vdev, features64) < 0) {
error_report("Features 0x%" PRIx64 " unsupported. "
"Allowed features: 0x%" PRIx64,
features64, vdev->host_features);
return -1;
}
} else {
if (virtio_set_features(vdev, features) < 0) {
if (virtio_set_features_nocheck(vdev, features) < 0) {
error_report("Features 0x%x unsupported. "
"Allowed features: 0x%" PRIx64,
features, vdev->host_features);
@@ -1134,7 +1280,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
}
for (i = 0; i < num; i++) {
if (vdev->vq[i].pa) {
if (vdev->vq[i].vring.desc) {
uint16_t nheads;
nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
/* Check it isn't doing strange things with descriptor numbers. */
+1 -3
View File
@@ -714,9 +714,7 @@ int xen_be_init(void)
return -1;
}
if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) {
goto err;
}
qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL);
if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
/* Check if xen_init() have been called */
+1 -1
View File
@@ -241,7 +241,7 @@ bool aio_dispatch(AioContext *ctx);
bool aio_poll(AioContext *ctx, bool blocking);
/* Register a file descriptor and associated callbacks. Behaves very similarly
* to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will
* to qemu_set_fd_handler. Unlike qemu_set_fd_handler, these callbacks will
* be invoked when using aio_poll().
*
* Code that invokes AIO completion functions should rely on this function
+2 -2
View File
@@ -126,10 +126,10 @@ void cpu_flush_icache_range(hwaddr start, int len);
extern struct MemoryRegion io_mem_rom;
extern struct MemoryRegion io_mem_notdirty;
typedef void (RAMBlockIterFunc)(void *host_addr,
typedef int (RAMBlockIterFunc)(const char *block_name, void *host_addr,
ram_addr_t offset, ram_addr_t length, void *opaque);
void qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque);
#endif

Some files were not shown because too many files have changed in this diff Show More