summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorVaporeon2018-10-18 04:47:10 +1300
committerVaporeon2018-10-18 04:47:10 +1300
commiteaffdaad2891232bc97da72626ceadd853069c34 (patch)
tree18af3714a19ec9c8a52b46cd49482f88da824e76
parent49865f69c672b1c21e11de5b93f5667f756c7b63 (diff)
downloadaur-eaffdaad2891232bc97da72626ceadd853069c34.tar.gz
Use external source for extra patches
-rw-r--r--.SRCINFO10
-rw-r--r--PKGBUILD6
-rw-r--r--cpu-pinning.patch186
-rw-r--r--pa-fixes.patch865
-rw-r--r--pcie-nasty.patch319
5 files changed, 9 insertions, 1377 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 6688b8515691..0e54ce79aafb 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,9 +1,9 @@
# Generated by mksrcinfo v8
-# Mon Oct 15 03:27:39 UTC 2018
+# Wed Oct 17 15:24:08 UTC 2018
pkgbase = qemu-patched
pkgdesc = A generic and open source machine emulator and virtualizer - Patched for extra functionality
pkgver = 3.0.0
- pkgrel = 2
+ pkgrel = 3
url = http://wiki.qemu.org/
arch = x86_64
license = GPL2
@@ -38,9 +38,10 @@ pkgbase = qemu-patched
source = qemu-ga.service
source = 65-kvm.rules
source = allow_elf64.patch
- source = cpu-pinning.patch
- source = pa-fixes.patch
+ source = cpu-pinning.patch::https://github.com/saveriomiroddi/qemu-pinning/commit/4bdb6d0e930f6dd8473d6833a0811169f43a9f0b.patch
+ source = pa-fixes.patch::https://gist.github.com/Vaporeon/c879636f9147bd696fb888321ffd5655/raw/57fe4b41a84d46b908fcb9d8e9756e27f3b75940/pa-fixes.patch
source = fix_virtio.patch::https://github.com/qemu/qemu/commit/db812c4073c77c8a64db8d6663b3416a587c7b4a.patch
+ source = pcie-nasty.patch::https://gist.githubusercontent.com/gnif/e4c001b608347b0b86118a2647103378/raw/dd18eb6fe60f33c0609c7122d0635b666d7018b8/qemu-pcie-nasty.patch
sha256sums = 8d7af64fe8bd5ea5c3bdf17131a8b858491bcce1ee3839425a6d91fb821b5713
sha256sums = SKIP
sha256sums = c39bcde4a09165e64419fd2033b3532378bba84d509d39e2d51694d44c1f8d88
@@ -49,6 +50,7 @@ pkgbase = qemu-patched
sha256sums = 5c6baf8d171a75c342ffcc5c4259570b3d8d4f34166d7bc1f694ecf571662f2d
sha256sums = 0fd49e734ee141b90d7d41d534f5635c175734a454e61c1c7e31b9fec3e19508
sha256sums = 9d176af4506f16f2798e772151fa8595620a770510241b688980fc7f0c6970b3
+ sha256sums = 90b8e3965797d5239a73d3720348f18e81c30b548c98a800c6ea4ee121c34a3b
pkgname = qemu-patched
optdepends = qemu-patched-arch-extra: extra architectures support
diff --git a/PKGBUILD b/PKGBUILD
index 54b062d75957..b1436868fc96 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -20,8 +20,8 @@ source=("$url/download/${_pkgname}-${pkgver}.tar.xz"{,.sig}
qemu-ga.service
65-kvm.rules
allow_elf64.patch
- cpu-pinning.patch
- pa-fixes.patch
+ cpu-pinning.patch::https://github.com/saveriomiroddi/qemu-pinning/commit/4bdb6d0e930f6dd8473d6833a0811169f43a9f0b.patch
+ pa-fixes.patch::https://gist.github.com/Vaporeon/c879636f9147bd696fb888321ffd5655/raw/57fe4b41a84d46b908fcb9d8e9756e27f3b75940/pa-fixes.patch
fix_virtio.patch::https://github.com/qemu/qemu/commit/db812c4073c77c8a64db8d6663b3416a587c7b4a.patch
pcie-nasty.patch::https://gist.githubusercontent.com/gnif/e4c001b608347b0b86118a2647103378/raw/dd18eb6fe60f33c0609c7122d0635b666d7018b8/qemu-pcie-nasty.patch)
sha256sums=('8d7af64fe8bd5ea5c3bdf17131a8b858491bcce1ee3839425a6d91fb821b5713'
@@ -29,7 +29,7 @@ sha256sums=('8d7af64fe8bd5ea5c3bdf17131a8b858491bcce1ee3839425a6d91fb821b5713'
'c39bcde4a09165e64419fd2033b3532378bba84d509d39e2d51694d44c1f8d88'
'a66f0e791b16b03b91049aac61a25950d93e962e1b2ba64a38c6ad7f609b532c'
'59751f1ed26ea61b2a37ebee4be6979e584a450b611282138a0893aa9173e2e4'
- '5c6baf8d171a75c342ffcc5c4259570b3d8d4f34166d7bc1f694ecf571662f2d'
+ '0769c55299606e897b16179ebf7bfd7dfb72a836d2a8bcebdccd8586f99d3166'
'0fd49e734ee141b90d7d41d534f5635c175734a454e61c1c7e31b9fec3e19508'
'9d176af4506f16f2798e772151fa8595620a770510241b688980fc7f0c6970b3'
'90b8e3965797d5239a73d3720348f18e81c30b548c98a800c6ea4ee121c34a3b')
diff --git a/cpu-pinning.patch b/cpu-pinning.patch
deleted file mode 100644
index f3c520c1ed54..000000000000
--- a/cpu-pinning.patch
+++ /dev/null
@@ -1,186 +0,0 @@
-From 420f81563a6ff3e695f7643a1bcbbc332b9f7132 Mon Sep 17 00:00:00 2001
-From: Saverio Miroddi <saverio.pub2@gmail.com>
-Date: Tue, 31 Oct 2017 20:59:05 +0100
-Subject: [PATCH] Current pinning patch
-
-Changes 2017/10/31:
-
-- Fix: the MAX_VCPUS was arbitrary; it's now set to CPU_SETSIZE
-- Fix: the allowed vcpus were equated to the cores number, without accounting sockets and threads
-- Change: removed all the debug information, and a now unneded warning
-- Change: cleaned spacing
----
- cpus.c | 12 +++++++++++
- qemu-options.hx | 10 ++++++++++
- vl.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 84 insertions(+)
-
-diff --git a/cpus.c b/cpus.c
-index 38eba8bff33..1ff63e0d847 100644
---- a/cpus.c
-+++ b/cpus.c
-@@ -57,6 +57,9 @@
- #ifdef CONFIG_LINUX
-
- #include <sys/prctl.h>
-+#include <unistd.h>
-+#include <stdint.h>
-+#include <inttypes.h>
-
- #ifndef PR_MCE_KILL
- #define PR_MCE_KILL 33
-@@ -1919,9 +1922,11 @@ static void qemu_hax_start_vcpu(CPUState *cpu)
- #endif
- }
-
-+extern int vcpu_affinity[];
- static void qemu_kvm_start_vcpu(CPUState *cpu)
- {
- char thread_name[VCPU_THREAD_NAME_SIZE];
-+ cpu_set_t cpuset;
-
- cpu->thread = g_malloc0(sizeof(QemuThread));
- cpu->halt_cond = g_malloc0(sizeof(QemuCond));
-@@ -1930,6 +1935,13 @@ static void qemu_kvm_start_vcpu(CPUState *cpu)
- cpu->cpu_index);
- qemu_thread_create(cpu->thread, thread_name, qemu_kvm_cpu_thread_fn,
- cpu, QEMU_THREAD_JOINABLE);
-+
-+ if (vcpu_affinity[cpu->cpu_index] != -1) {
-+ CPU_ZERO(&cpuset);
-+ CPU_SET(vcpu_affinity[cpu->cpu_index], &cpuset);
-+ pthread_setaffinity_np((cpu->thread)->thread, sizeof(cpu_set_t), &cpuset);
-+ }
-+
- }
-
- static void qemu_hvf_start_vcpu(CPUState *cpu)
-diff --git a/qemu-options.hx b/qemu-options.hx
-index ca4e412f2f8..9dd6dcd93cf 100644
---- a/qemu-options.hx
-+++ b/qemu-options.hx
-@@ -169,6 +169,16 @@ given, the total number of CPUs @var{n} can be omitted. @var{maxcpus}
- specifies the maximum number of hotpluggable CPUs.
- ETEXI
-
-+DEF("vcpu", HAS_ARG, QEMU_OPTION_vcpu,
-+ "-vcpu [vcpunum=]n[,affinity=affinity]\n"
-+ "-vcpu [vcpunum=]n[,affinity=affinity]\n", QEMU_ARCH_ALL)
-+STEXI
-+@item -vcpu [vcpunum=]@var{n}[,affinity=@var{affinity}]
-+@itemx -vcpu [vcpunum=]@var{n}[,affinity=@var{affinity}]
-+@findex -vcpu
-+VCPU Affinity. If specified, specify for all the CPUs.
-+ETEXI
-+
- DEF("numa", HAS_ARG, QEMU_OPTION_numa,
- "-numa node[,mem=size][,cpus=firstcpu[-lastcpu]][,nodeid=node]\n"
- "-numa node[,memdev=id][,cpus=firstcpu[-lastcpu]][,nodeid=node]\n"
-diff --git a/vl.c b/vl.c
-index fce1fd12d8b..4e6110c5a71 100644
---- a/vl.c
-+++ b/vl.c
-@@ -135,6 +135,7 @@ int main(int argc, char **argv)
- #define MAX_VIRTIO_CONSOLES 1
- #define MAX_SCLP_CONSOLES 1
-
-+#define MAX_VCPUS CPU_SETSIZE
- static const char *data_dir[16];
- static int data_dir_idx;
- const char *bios_name = NULL;
-@@ -164,6 +165,8 @@ int smp_cpus;
- unsigned int max_cpus;
- int smp_cores = 1;
- int smp_threads = 1;
-+int vcpu_affinity[MAX_VCPUS];
-+int num_affinity = 0;
- int acpi_enabled = 1;
- int no_hpet = 0;
- int fd_bootchk = 1;
-@@ -1290,6 +1293,57 @@ static QemuOptsList qemu_smp_opts = {
- },
- };
-
-+static QemuOptsList qemu_vcpu_opts = {
-+ .name = "vcpu-opts",
-+ .implied_opt_name = "vcpunum",
-+ .head = QTAILQ_HEAD_INITIALIZER(qemu_vcpu_opts.head),
-+ .desc = {
-+ {
-+ .name = "vcpunum",
-+ .type = QEMU_OPT_NUMBER,
-+ }, {
-+ .name = "affinity",
-+ .type = QEMU_OPT_NUMBER,
-+ },
-+ { /*End of list */ }
-+ },
-+};
-+
-+static int parse_vcpu(void *opaque, QemuOpts *opts, Error **errp)
-+{
-+ if (opts) {
-+ unsigned vcpu = qemu_opt_get_number(opts, "vcpunum", 0);
-+ unsigned affinity = qemu_opt_get_number(opts,"affinity", 0);
-+
-+ if (vcpu < smp_cpus * smp_cores * smp_threads) {
-+ if (vcpu_affinity[vcpu] == -1) {
-+ vcpu_affinity[vcpu] = affinity;
-+ }
-+ else {
-+ error_report("Duplicate affinity statement for vcpu %d\n", vcpu);
-+ return -1;
-+ }
-+ num_affinity += 1;
-+ }
-+ else {
-+ error_report("VCPU %d is more than allowed %d VCPUs in the system\n", vcpu, smp_cores);
-+ return -1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static void parse_vcpu_opts(MachineClass *mc)
-+{
-+ int i;
-+ for (i = 0; i < MAX_VCPUS; i++)
-+ vcpu_affinity[i] = -1;
-+
-+ if (qemu_opts_foreach(qemu_find_opts("vcpu-opts"), parse_vcpu, NULL, NULL)) {
-+ exit(1);
-+ }
-+}
-+
- static void smp_parse(QemuOpts *opts)
- {
- if (opts) {
-@@ -3092,6 +3146,7 @@ int main(int argc, char **argv, char **envp)
- qemu_add_opts(&qemu_accel_opts);
- qemu_add_opts(&qemu_mem_opts);
- qemu_add_opts(&qemu_smp_opts);
-+ qemu_add_opts(&qemu_vcpu_opts);
- qemu_add_opts(&qemu_boot_opts);
- qemu_add_opts(&qemu_sandbox_opts);
- qemu_add_opts(&qemu_add_fd_opts);
-@@ -3771,6 +3826,12 @@ int main(int argc, char **argv, char **envp)
- exit(1);
- }
- break;
-+ case QEMU_OPTION_vcpu:
-+ if (!qemu_opts_parse_noisily(qemu_find_opts("vcpu-opts"),
-+ optarg, true)) {
-+ exit(1);
-+ }
-+ break;
- case QEMU_OPTION_vnc:
- vnc_parse(optarg, &error_fatal);
- break;
-@@ -4211,6 +4272,7 @@ int main(int argc, char **argv, char **envp)
- exit(1);
- }
-
-+ parse_vcpu_opts(machine_class);
- /*
- * Get the default machine options from the machine if it is not already
- * specified either by the configuration file or by the command line.
diff --git a/pa-fixes.patch b/pa-fixes.patch
deleted file mode 100644
index 65d046502c92..000000000000
--- a/pa-fixes.patch
+++ /dev/null
@@ -1,865 +0,0 @@
-From fa5f68de47d120b4f6a5f973f21567ef389b42ac Mon Sep 17 00:00:00 2001
-From: Geoffrey McRae <geoff@hostfission.com>
-Date: Tue, 8 May 2018 02:59:17 +1000
-Subject: [PATCH] PA fixes
-
----
- audio/audio.c | 5 +
- audio/audio_int.h | 2 +
- audio/paaudio.c | 635 +++++++++++++++++--------------------------
- hw/audio/hda-codec.c | 2 +
- 4 files changed, 264 insertions(+), 380 deletions(-)
-
-diff --git a/audio/audio.c b/audio/audio.c
-index 1ace47f510..253e470d12 100644
---- a/audio/audio.c
-+++ b/audio/audio.c
-@@ -2118,3 +2118,8 @@ void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
- }
- }
- }
-+
-+int64_t audio_get_timer_ticks(void)
-+{
-+ return conf.period.ticks;
-+}
-diff --git a/audio/audio_int.h b/audio/audio_int.h
-index 244b454012..19ba2d7aa4 100644
---- a/audio/audio_int.h
-+++ b/audio/audio_int.h
-@@ -210,6 +210,8 @@ extern const struct mixeng_volume nominal_volume;
- void audio_driver_register(audio_driver *drv);
- audio_driver *audio_driver_lookup(const char *name);
-
-+int64_t audio_get_timer_ticks(void);
-+
- void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
- void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
-
-diff --git a/audio/paaudio.c b/audio/paaudio.c
-index 949769774d..bd5a1781bf 100644
---- a/audio/paaudio.c
-+++ b/audio/paaudio.c
-@@ -1,16 +1,22 @@
- /* public domain */
- #include "qemu/osdep.h"
--#include "qemu-common.h"
-+#include "qemu/timer.h"
- #include "audio.h"
-
- #include <pulse/pulseaudio.h>
-
- #define AUDIO_CAP "pulseaudio"
-+#define DEBUG
- #include "audio_int.h"
--#include "audio_pt_int.h"
-
- typedef struct {
-- int samples;
-+ int buffer_size_out;
-+ int buffer_size_in;
-+ int tlength;
-+ int fragsize;
-+ int maxlength_in;
-+ int adjust_latency_out;
-+ int adjust_latency_in;
- char *server;
- char *sink;
- char *source;
-@@ -24,28 +30,18 @@ typedef struct {
-
- typedef struct {
- HWVoiceOut hw;
-- int done;
-- int live;
-- int decr;
-- int rpos;
- pa_stream *stream;
-- void *pcm_buf;
-- struct audio_pt pt;
- paaudio *g;
-+ pa_sample_spec ss;
-+ pa_buffer_attr ba;
- } PAVoiceOut;
-
- typedef struct {
- HWVoiceIn hw;
-- int done;
-- int dead;
-- int incr;
-- int wpos;
- pa_stream *stream;
-- void *pcm_buf;
-- struct audio_pt pt;
-- const void *read_data;
-- size_t read_index, read_length;
- paaudio *g;
-+ pa_sample_spec ss;
-+ pa_buffer_attr ba;
- } PAVoiceIn;
-
- static void qpa_audio_fini(void *opaque);
-@@ -109,182 +105,59 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
- } \
- } while (0)
-
--static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
--{
-- paaudio *g = p->g;
--
-- pa_threaded_mainloop_lock (g->mainloop);
--
-- CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
--
-- while (length > 0) {
-- size_t l;
--
-- while (!p->read_data) {
-- int r;
--
-- r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
-- CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
--
-- if (!p->read_data) {
-- pa_threaded_mainloop_wait (g->mainloop);
-- CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
-- } else {
-- p->read_index = 0;
-- }
-- }
--
-- l = p->read_length < length ? p->read_length : length;
-- memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
--
-- data = (uint8_t *) data + l;
-- length -= l;
--
-- p->read_index += l;
-- p->read_length -= l;
--
-- if (!p->read_length) {
-- int r;
--
-- r = pa_stream_drop (p->stream);
-- p->read_data = NULL;
-- p->read_length = 0;
-- p->read_index = 0;
--
-- CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
-- }
-- }
--
-- pa_threaded_mainloop_unlock (g->mainloop);
-- return 0;
--
--unlock_and_fail:
-- pa_threaded_mainloop_unlock (g->mainloop);
-- return -1;
--}
--
--static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
-+static int qpa_run_out(HWVoiceOut *hw, int live)
- {
-- paaudio *g = p->g;
--
-- pa_threaded_mainloop_lock (g->mainloop);
--
-- CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
--
-- while (length > 0) {
-- size_t l;
-- int r;
--
-- while (!(l = pa_stream_writable_size (p->stream))) {
-- pa_threaded_mainloop_wait (g->mainloop);
-- CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
-- }
--
-- CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
--
-- if (l > length) {
-- l = length;
-- }
--
-- r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
-- CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
--
-- data = (const uint8_t *) data + l;
-- length -= l;
-- }
--
-- pa_threaded_mainloop_unlock (g->mainloop);
-- return 0;
--
--unlock_and_fail:
-- pa_threaded_mainloop_unlock (g->mainloop);
-- return -1;
--}
--
--static void *qpa_thread_out (void *arg)
--{
-- PAVoiceOut *pa = arg;
-- HWVoiceOut *hw = &pa->hw;
--
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return NULL;
-- }
-+ PAVoiceOut *pa = (PAVoiceOut *) hw;
-+ int rpos, decr, samples;
-+ size_t avail_bytes, max_bytes;
-+ struct st_sample *src;
-+ void *pa_dst;
-+ int error = 0;
-+ int *rerror = &error;
-+ int r;
-
-- for (;;) {
-- int decr, to_mix, rpos;
-+ decr = 0;
-+ rpos = hw->rpos;
-
-- for (;;) {
-- if (pa->done) {
-- goto exit;
-- }
-+ pa_threaded_mainloop_lock(pa->g->mainloop);
-+ CHECK_DEAD_GOTO(pa->g, pa->stream, rerror, fail);
-
-- if (pa->live > 0) {
-- break;
-- }
-+ avail_bytes = (size_t) live << hw->info.shift;
-
-- if (audio_pt_wait(&pa->pt, __func__)) {
-- goto exit;
-- }
-- }
-+ max_bytes = pa_stream_writable_size(pa->stream);
-+ CHECK_SUCCESS_GOTO(pa->g, rerror, max_bytes != -1, fail);
-
-- decr = to_mix = audio_MIN (pa->live, pa->g->conf.samples >> 2);
-- rpos = pa->rpos;
-+ samples = (int)(audio_MIN(avail_bytes, max_bytes)) >> hw->info.shift;
-+ while (samples) {
-+ int convert_samples = audio_MIN(samples, hw->samples - rpos);
-+ size_t b_wanted = (size_t) convert_samples << hw->info.shift;
-+ size_t b_effective = b_wanted;
-
-- if (audio_pt_unlock(&pa->pt, __func__)) {
-- return NULL;
-- }
-+ r = pa_stream_begin_write(pa->stream, &pa_dst, &b_effective);
-+ CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail);
-+ CHECK_SUCCESS_GOTO(pa->g, (int *)0, b_effective == b_wanted, fail);
-
-- while (to_mix) {
-- int error;
-- int chunk = audio_MIN (to_mix, hw->samples - rpos);
-- struct st_sample *src = hw->mix_buf + rpos;
-+ src = hw->mix_buf + rpos;
-+ hw->clip(pa_dst, src, convert_samples);
-
-- hw->clip (pa->pcm_buf, src, chunk);
--
-- if (qpa_simple_write (pa, pa->pcm_buf,
-- chunk << hw->info.shift, &error) < 0) {
-- qpa_logerr (error, "pa_simple_write failed\n");
-- return NULL;
-- }
-+ r = pa_stream_write(pa->stream, pa_dst, b_effective,
-+ NULL, 0LL, PA_SEEK_RELATIVE);
-+ CHECK_SUCCESS_GOTO(pa->g, rerror, r >= 0, fail);
-
-- rpos = (rpos + chunk) % hw->samples;
-- to_mix -= chunk;
-- }
--
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return NULL;
-- }
--
-- pa->rpos = rpos;
-- pa->live -= decr;
-- pa->decr += decr;
-+ rpos = (rpos + convert_samples) % hw->samples;
-+ samples -= convert_samples;
-+ decr += convert_samples;
- }
-
-- exit:
-- audio_pt_unlock(&pa->pt, __func__);
-- return NULL;
--}
--
--static int qpa_run_out (HWVoiceOut *hw, int live)
--{
-- int decr;
-- PAVoiceOut *pa = (PAVoiceOut *) hw;
--
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return 0;
-- }
-+ bail:
-+ pa_threaded_mainloop_unlock(pa->g->mainloop);
-
-- decr = audio_MIN (live, pa->decr);
-- pa->decr -= decr;
-- pa->live = live - decr;
-- hw->rpos = pa->rpos;
-- if (pa->live > 0) {
-- audio_pt_unlock_and_signal(&pa->pt, __func__);
-- }
-- else {
-- audio_pt_unlock(&pa->pt, __func__);
-- }
-+ hw->rpos = rpos;
- return decr;
-+
-+fail:
-+ qpa_logerr(error, "qpa_run_out failed\n");
-+ goto bail;
- }
-
- static int qpa_write (SWVoiceOut *sw, void *buf, int len)
-@@ -292,92 +165,68 @@ static int qpa_write (SWVoiceOut *sw, void *buf, int len)
- return audio_pcm_sw_write (sw, buf, len);
- }
-
--/* capture */
--static void *qpa_thread_in (void *arg)
-+static int qpa_run_in(HWVoiceIn *hw)
- {
-- PAVoiceIn *pa = arg;
-- HWVoiceIn *hw = &pa->hw;
-+ PAVoiceIn *pa = (PAVoiceIn *) hw;
-+ int wpos, incr;
-+ char *pa_src;
-+ int error = 0;
-+ int *rerror = &error;
-+ int r;
-+ size_t pa_avail;
-+ incr = 0;
-+ wpos = hw->wpos;
-
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return NULL;
-- }
-+ pa_threaded_mainloop_lock(pa->g->mainloop);
-+ CHECK_DEAD_GOTO(pa->g, pa->stream, rerror, fail);
-
-- for (;;) {
-- int incr, to_grab, wpos;
-+ size_t bytes_wanted = ((unsigned int)
-+ (hw->samples - audio_pcm_hw_get_live_in(hw)) << hw->info.shift);
-
-- for (;;) {
-- if (pa->done) {
-- goto exit;
-- }
-+ if (bytes_wanted == 0) {
-+ /* no room */
-+ goto bail;
-+ }
-
-- if (pa->dead > 0) {
-- break;
-- }
-+ size_t bytes_avail = pa_stream_readable_size(pa->stream);
-
-- if (audio_pt_wait(&pa->pt, __func__)) {
-- goto exit;
-- }
-- }
-+ if (bytes_wanted > bytes_avail) {
-+ bytes_wanted = bytes_avail;
-+ }
-
-- incr = to_grab = audio_MIN (pa->dead, pa->g->conf.samples >> 2);
-- wpos = pa->wpos;
-+ while (bytes_wanted) {
-+ r = pa_stream_peek(pa->stream, (const void **)&pa_src, &pa_avail);
-+ CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail);
-
-- if (audio_pt_unlock(&pa->pt, __func__)) {
-- return NULL;
-+ if (pa_avail == 0 || pa_avail > bytes_wanted) {
-+ break;
- }
-
-- while (to_grab) {
-- int error;
-- int chunk = audio_MIN (to_grab, hw->samples - wpos);
-- void *buf = advance (pa->pcm_buf, wpos);
-+ bytes_wanted -= pa_avail;
-
-- if (qpa_simple_read (pa, buf,
-- chunk << hw->info.shift, &error) < 0) {
-- qpa_logerr (error, "pa_simple_read failed\n");
-- return NULL;
-- }
--
-- hw->conv (hw->conv_buf + wpos, buf, chunk);
-+ while (pa_avail) {
-+ int chunk = audio_MIN(
-+ (int)(pa_avail >> hw->info.shift), hw->samples - wpos);
-+ hw->conv(hw->conv_buf + wpos, pa_src, chunk);
- wpos = (wpos + chunk) % hw->samples;
-- to_grab -= chunk;
-- }
--
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return NULL;
-+ pa_src += chunk << hw->info.shift;
-+ pa_avail -= chunk << hw->info.shift;
-+ incr += chunk;
- }
-
-- pa->wpos = wpos;
-- pa->dead -= incr;
-- pa->incr += incr;
-+ r = pa_stream_drop(pa->stream);
-+ CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail);
- }
-
-- exit:
-- audio_pt_unlock(&pa->pt, __func__);
-- return NULL;
--}
--
--static int qpa_run_in (HWVoiceIn *hw)
--{
-- int live, incr, dead;
-- PAVoiceIn *pa = (PAVoiceIn *) hw;
--
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return 0;
-- }
-+bail:
-+ pa_threaded_mainloop_unlock(pa->g->mainloop);
-
-- live = audio_pcm_hw_get_live_in (hw);
-- dead = hw->samples - live;
-- incr = audio_MIN (dead, pa->incr);
-- pa->incr -= incr;
-- pa->dead = dead - incr;
-- hw->wpos = pa->wpos;
-- if (pa->dead > 0) {
-- audio_pt_unlock_and_signal(&pa->pt, __func__);
-- }
-- else {
-- audio_pt_unlock(&pa->pt, __func__);
-- }
-+ hw->wpos = wpos;
- return incr;
-+
-+fail:
-+ qpa_logerr(error, "qpa_run_in failed\n");
-+ goto bail;
- }
-
- static int qpa_read (SWVoiceIn *sw, void *buf, int len)
-@@ -470,13 +319,6 @@ 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 = userdata;
--
-- pa_threaded_mainloop_signal (g->mainloop, 0);
--}
--
- static pa_stream *qpa_simple_new (
- paaudio *g,
- const char *name,
-@@ -498,23 +340,17 @@ static pa_stream *qpa_simple_new (
- }
-
- pa_stream_set_state_callback (stream, stream_state_cb, g);
-- pa_stream_set_read_callback (stream, stream_request_cb, g);
-- pa_stream_set_write_callback (stream, stream_request_cb, g);
-
- if (dir == PA_STREAM_PLAYBACK) {
-- r = pa_stream_connect_playback (stream, dev, attr,
-- PA_STREAM_INTERPOLATE_TIMING
--#ifdef PA_STREAM_ADJUST_LATENCY
-- |PA_STREAM_ADJUST_LATENCY
--#endif
-- |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
-+ r = pa_stream_connect_playback(stream, dev, attr,
-+ PA_STREAM_INTERPOLATE_TIMING
-+ | (g->conf.adjust_latency_out ? PA_STREAM_ADJUST_LATENCY : 0)
-+ | PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
- } else {
-- r = pa_stream_connect_record (stream, dev, attr,
-- PA_STREAM_INTERPOLATE_TIMING
--#ifdef PA_STREAM_ADJUST_LATENCY
-- |PA_STREAM_ADJUST_LATENCY
--#endif
-- |PA_STREAM_AUTO_TIMING_UPDATE);
-+ r = pa_stream_connect_record(stream, dev, attr,
-+ PA_STREAM_INTERPOLATE_TIMING
-+ | (g->conf.adjust_latency_in ? PA_STREAM_ADJUST_LATENCY : 0)
-+ | PA_STREAM_AUTO_TIMING_UPDATE);
- }
-
- if (r < 0) {
-@@ -541,165 +377,167 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
- void *drv_opaque)
- {
- int error;
-- 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;
-- ss.rate = as->freq;
--
-- /*
-- * qemu audio tick runs at 100 Hz (by default), so processing
-- * data chunks worth 10 ms of sound should be a good fit.
-- */
-- ba.tlength = pa_usec_to_bytes (10 * 1000, &ss);
-- ba.minreq = pa_usec_to_bytes (5 * 1000, &ss);
-- ba.maxlength = -1;
-- ba.prebuf = -1;
--
-- obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
--
-- pa->stream = qpa_simple_new (
-- g,
-- "qemu",
-- PA_STREAM_PLAYBACK,
-- g->conf.sink,
-- &ss,
-- NULL, /* channel map */
-- &ba, /* buffering attributes */
-- &error
-- );
-+ int64_t timer_tick_duration =
-+ audio_MAX(audio_get_timer_ticks(), 1 * SCALE_MS);
-+ int64_t frames_per_tick_x1000 =
-+ ((timer_tick_duration * as->freq * 1000LL) / NANOSECONDS_PER_SECOND);
-+
-+ int64_t tlength = g->conf.tlength;
-+ if (tlength == 0) {
-+ tlength = (frames_per_tick_x1000) / 400;
-+ }
-+ int64_t buflen = g->conf.buffer_size_out;
-+ if (buflen == 0) {
-+ buflen = frames_per_tick_x1000 / 400;
-+ }
-+
-+ ldebug("tick duration: %.2f ms (%.3f frames)\n",
-+ ((float)timer_tick_duration) / SCALE_MS,
-+ (float)frames_per_tick_x1000 / 1000.0f);
-+
-+ ldebug("OUT internal buffer: %.2f ms (%"PRId64" frames)\n",
-+ buflen * (1000.0f / as->freq),
-+ buflen);
-+
-+ ldebug("OUT tlength: %.2f ms (%"PRId64" frames)\n",
-+ tlength * (1000.0f / as->freq),
-+ tlength);
-+
-+ ldebug("OUT adjust latency: %s\n",
-+ g->conf.adjust_latency_out ? "yes" : "no");
-+
-+ pa->ss.format = audfmt_to_pa(as->fmt, as->endianness);
-+ pa->ss.channels = as->nchannels;
-+ pa->ss.rate = as->freq;
-+
-+ pa->ba.tlength = tlength * pa_frame_size(&pa->ss);
-+ pa->ba.maxlength = -1;
-+ pa->ba.minreq = -1;
-+ pa->ba.prebuf = -1;
-+
-+ obt_as.fmt = pa_to_audfmt(pa->ss.format, &obt_as.endianness);
-+
-+ pa->stream = qpa_simple_new(
-+ g,
-+ "qemu",
-+ PA_STREAM_PLAYBACK,
-+ g->conf.sink,
-+ &pa->ss,
-+ NULL, /* channel map */
-+ &pa->ba, /* buffering attributes */
-+ &error
-+ );
- if (!pa->stream) {
- qpa_logerr (error, "pa_simple_new for playback failed\n");
- goto fail1;
- }
-
-- audio_pcm_init_info (&hw->info, &obt_as);
-- hw->samples = g->conf.samples;
-- pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
-- pa->rpos = hw->rpos;
-- if (!pa->pcm_buf) {
-- dolog ("Could not allocate buffer (%d bytes)\n",
-- hw->samples << hw->info.shift);
-- goto fail2;
-- }
--
-- if (audio_pt_init(&pa->pt, qpa_thread_out, hw, AUDIO_CAP, __func__)) {
-- goto fail3;
-- }
-+ audio_pcm_init_info(&hw->info, &obt_as);
-+ hw->samples = buflen;
-
- return 0;
-
-- fail3:
-- g_free (pa->pcm_buf);
-- pa->pcm_buf = NULL;
-- fail2:
-- if (pa->stream) {
-- pa_stream_unref (pa->stream);
-- pa->stream = NULL;
-- }
-- fail1:
-+fail1:
- return -1;
- }
-
- static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
- {
- int error;
-- 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;
-- ss.rate = as->freq;
--
-- obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
--
-- pa->stream = qpa_simple_new (
-- g,
-- "qemu",
-- PA_STREAM_RECORD,
-- g->conf.source,
-- &ss,
-- NULL, /* channel map */
-- NULL, /* buffering attributes */
-- &error
-- );
-+ int64_t timer_tick_duration =
-+ audio_MAX(audio_get_timer_ticks(), 1 * SCALE_MS);
-+ int64_t frames_per_tick_x1000 =
-+ ((timer_tick_duration * as->freq * 1000LL) / NANOSECONDS_PER_SECOND);
-+
-+ int64_t fragsize = g->conf.fragsize;
-+ if (fragsize == 0) {
-+ fragsize = frames_per_tick_x1000 / 1000;
-+ }
-+ int64_t buflen = g->conf.buffer_size_in;
-+ if (buflen == 0) {
-+ buflen = frames_per_tick_x1000 / 400;
-+ }
-+ int64_t maxlength = g->conf.maxlength_in;
-+ if (maxlength == 0) {
-+ maxlength = fragsize * 2;
-+ }
-+
-+ ldebug("IN internal buffer: %.2f ms (%"PRId64" frames)\n",
-+ buflen * (1000.0f / as->freq),
-+ buflen);
-+
-+ ldebug("IN fragsize: %.2f ms (%"PRId64" frames)\n",
-+ fragsize * (1000.0f / as->freq),
-+ fragsize);
-+
-+ ldebug("IN maxlength: %.2f ms (%"PRId64" frames)\n",
-+ maxlength * (1000.0f / as->freq),
-+ maxlength);
-+
-+ ldebug("IN adjust latency: %s\n",
-+ g->conf.adjust_latency_in ? "yes" : "no");
-+
-+ pa->ss.format = audfmt_to_pa(as->fmt, as->endianness);
-+ pa->ss.channels = as->nchannels;
-+ pa->ss.rate = as->freq;
-+
-+ pa->ba.fragsize = fragsize * pa_frame_size(&pa->ss);
-+ pa->ba.maxlength = maxlength * pa_frame_size(&pa->ss);
-+ pa->ba.minreq = -1;
-+ pa->ba.prebuf = -1;
-+
-+ obt_as.fmt = pa_to_audfmt(pa->ss.format, &obt_as.endianness);
-+
-+ pa->stream = qpa_simple_new(
-+ g,
-+ "qemu",
-+ PA_STREAM_RECORD,
-+ g->conf.source,
-+ &pa->ss,
-+ NULL, /* channel map */
-+ &pa->ba, /* buffering attributes */
-+ &error
-+ );
- if (!pa->stream) {
- qpa_logerr (error, "pa_simple_new for capture failed\n");
- goto fail1;
- }
-
-- audio_pcm_init_info (&hw->info, &obt_as);
-- hw->samples = g->conf.samples;
-- pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
-- pa->wpos = hw->wpos;
-- if (!pa->pcm_buf) {
-- dolog ("Could not allocate buffer (%d bytes)\n",
-- hw->samples << hw->info.shift);
-- goto fail2;
-- }
--
-- if (audio_pt_init(&pa->pt, qpa_thread_in, hw, AUDIO_CAP, __func__)) {
-- goto fail3;
-- }
-+ audio_pcm_init_info(&hw->info, &obt_as);
-+ hw->samples = buflen;
-
- return 0;
-
-- fail3:
-- g_free (pa->pcm_buf);
-- pa->pcm_buf = NULL;
-- fail2:
-- if (pa->stream) {
-- pa_stream_unref (pa->stream);
-- pa->stream = NULL;
-- }
-- fail1:
-+ fail1:
- return -1;
- }
-
- static void qpa_fini_out (HWVoiceOut *hw)
- {
-- void *ret;
- PAVoiceOut *pa = (PAVoiceOut *) hw;
-
-- audio_pt_lock(&pa->pt, __func__);
-- pa->done = 1;
-- audio_pt_unlock_and_signal(&pa->pt, __func__);
-- audio_pt_join(&pa->pt, &ret, __func__);
--
- if (pa->stream) {
- pa_stream_unref (pa->stream);
- pa->stream = NULL;
- }
--
-- audio_pt_fini(&pa->pt, __func__);
-- g_free (pa->pcm_buf);
-- pa->pcm_buf = NULL;
- }
-
- static void qpa_fini_in (HWVoiceIn *hw)
- {
-- void *ret;
- PAVoiceIn *pa = (PAVoiceIn *) hw;
-
-- audio_pt_lock(&pa->pt, __func__);
-- pa->done = 1;
-- audio_pt_unlock_and_signal(&pa->pt, __func__);
-- audio_pt_join(&pa->pt, &ret, __func__);
--
- if (pa->stream) {
- pa_stream_unref (pa->stream);
- pa->stream = NULL;
- }
--
-- audio_pt_fini(&pa->pt, __func__);
-- g_free (pa->pcm_buf);
-- pa->pcm_buf = NULL;
- }
-
- static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
-@@ -809,7 +647,8 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
-
- /* common */
- static PAConf glob_conf = {
-- .samples = 4096,
-+ .adjust_latency_out = 0,
-+ .adjust_latency_in = 1,
- };
-
- static void *qpa_audio_init (void)
-@@ -897,10 +736,46 @@ static void qpa_audio_fini (void *opaque)
-
- struct audio_option qpa_options[] = {
- {
-- .name = "SAMPLES",
-+ .name = "BUFFER_SIZE_OUT",
-+ .tag = AUD_OPT_INT,
-+ .valp = &glob_conf.buffer_size_out,
-+ .descr = "internal buffer size in frames for playback device"
-+ },
-+ {
-+ .name = "BUFFER_SIZE_IN",
-+ .tag = AUD_OPT_INT,
-+ .valp = &glob_conf.buffer_size_in,
-+ .descr = "internal buffer size in frames for recording device"
-+ },
-+ {
-+ .name = "TLENGTH",
- .tag = AUD_OPT_INT,
-- .valp = &glob_conf.samples,
-- .descr = "buffer size in samples"
-+ .valp = &glob_conf.tlength,
-+ .descr = "playback buffer target length in frames"
-+ },
-+ {
-+ .name = "FRAGSIZE",
-+ .tag = AUD_OPT_INT,
-+ .valp = &glob_conf.fragsize,
-+ .descr = "fragment length of recording device in frames"
-+ },
-+ {
-+ .name = "MAXLENGTH_IN",
-+ .tag = AUD_OPT_INT,
-+ .valp = &glob_conf.maxlength_in,
-+ .descr = "maximum length of PA recording buffer in frames"
-+ },
-+ {
-+ .name = "ADJUST_LATENCY_OUT",
-+ .tag = AUD_OPT_BOOL,
-+ .valp = &glob_conf.adjust_latency_out,
-+ .descr = "instruct PA to adjust latency for playback device"
-+ },
-+ {
-+ .name = "ADJUST_LATENCY_IN",
-+ .tag = AUD_OPT_BOOL,
-+ .valp = &glob_conf.adjust_latency_in,
-+ .descr = "instruct PA to adjust latency for recording device"
- },
- {
- .name = "SERVER",
-diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
-index 617a1c1016..6627c5cbfd 100644
---- a/hw/audio/hda-codec.c
-+++ b/hw/audio/hda-codec.c
-@@ -18,6 +18,7 @@
- */
-
- #include "qemu/osdep.h"
-+#include "qemu/atomic.h"
- #include "hw/hw.h"
- #include "hw/pci/pci.h"
- #include "intel-hda.h"
-@@ -128,6 +129,7 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
- #include "hda-codec-common.h"
-
- #define HDA_TIMER_TICKS (SCALE_MS)
-+#define MAX_CORR (SCALE_US * 100)
- #define B_SIZE sizeof(st->buf)
- #define B_MASK (sizeof(st->buf) - 1)
-
---
-2.18.0
-
diff --git a/pcie-nasty.patch b/pcie-nasty.patch
deleted file mode 100644
index 8c09546a7c9e..000000000000
--- a/pcie-nasty.patch
+++ /dev/null
@@ -1,319 +0,0 @@
-diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
-index 6c91bd44a0..f3c7b9d328 100644
---- a/hw/pci/pcie.c
-+++ b/hw/pci/pcie.c
-@@ -39,6 +39,166 @@
- #define PCIE_DEV_PRINTF(dev, fmt, ...) \
- PCIE_DPRINTF("%s:%x "fmt, (dev)->name, (dev)->devfn, ## __VA_ARGS__)
-
-+static uint16_t pcie_link_max_width(PCIDevice *dev)
-+{
-+ uint8_t *exp_cap;
-+ uint32_t lnkcap;
-+
-+ exp_cap = dev->config + dev->exp.exp_cap;
-+ lnkcap = pci_get_long(exp_cap + PCI_EXP_LNKCAP);
-+
-+ return lnkcap & PCI_EXP_LNKCAP_MLW;
-+}
-+
-+static uint16_t pcie_link_current_width(PCIDevice *dev)
-+{
-+ uint8_t *exp_cap;
-+ uint16_t lnksta;
-+
-+ exp_cap = dev->config + dev->exp.exp_cap;
-+ lnksta = pci_get_word(exp_cap + PCI_EXP_LNKSTA);
-+
-+ return lnksta & PCI_EXP_LNKCAP_MLW;
-+}
-+
-+static uint8_t pcie_link_speed_mask(PCIDevice *dev)
-+{
-+ uint8_t *exp_cap, speeds, mask;
-+ uint16_t ver;
-+ uint32_t lnkcap, lnkcap2 = 0;
-+
-+ exp_cap = dev->config + dev->exp.exp_cap;
-+ lnkcap = pci_get_long(exp_cap + PCI_EXP_LNKCAP);
-+ ver = pci_get_word(exp_cap + PCI_EXP_FLAGS) & PCI_EXP_FLAGS_VERS;
-+ if (ver >= PCI_EXP_FLAGS_VER2 &&
-+ dev->exp.exp_cap + PCI_EXP_LNKCAP2 < PCI_CONFIG_SPACE_SIZE) {
-+ lnkcap2 = pci_get_long(exp_cap + PCI_EXP_LNKCAP2);
-+ }
-+
-+ mask = (1 << (lnkcap & PCI_EXP_LNKCAP_SLS)) - 1;
-+
-+ /*
-+ * If LNKCAP2 reports supported link speeds, then LNKCAP indexes
-+ * the highest supported speed. Mask out the rest and return.
-+ */
-+ speeds = (lnkcap2 & PCI_EXP_LINKCAP2_SLSV) >> 1;
-+ if (speeds) {
-+ return speeds & mask;
-+ }
-+
-+ /*
-+ * Otherwise LNKCAP returns the maximum speed and the device supports
-+ * all speeds below it. This is really only valid for 2.5 & 5GT/s
-+ */
-+ return mask;
-+}
-+
-+static uint8_t pcie_link_current_speed(PCIDevice *dev)
-+{
-+ uint8_t *exp_cap;
-+ uint16_t lnksta;
-+
-+ exp_cap = dev->config + dev->exp.exp_cap;
-+ lnksta = pci_get_long(exp_cap + PCI_EXP_LNKSTA);
-+
-+ if (!(lnksta & PCI_EXP_LNKCAP_SLS)) {
-+ return 0;
-+ }
-+
-+ return 1 << ((lnksta & PCI_EXP_LNKCAP_SLS) - 1);
-+}
-+
-+/*
-+ * Negotiate the upstream link for PCIDevice @dev setting both the upstream
-+ * and downstream LNKSTA. If @dev already reports link width and/or speed
-+ * in LNKSTA they will be used as the preferred link parameters. LNKSTA
-+ * is always set, using the preferred parameters if possible, followed by
-+ * the best available link, followed by unknown (0) if an accurate value
-+ * is not possible. The caller can read LNKSTA from @dev to determine the
-+ * resulting link parameters.
-+ */
-+void pcie_negotiate_link(PCIDevice *dev)
-+{
-+ PCIDevice *parent;
-+ uint16_t flags, width = 0;
-+ uint8_t type, speed = 0;
-+ PCIBus *bus = pci_get_bus(dev);
-+
-+ /* Skip non-express buses and Root Complex buses. */
-+ if (!pci_bus_is_express(bus) || pci_bus_is_root(bus)) {
-+ goto unknown;
-+ }
-+
-+ /*
-+ * Downstream ports don't negotiate with upstream ports, their link
-+ * is negotiated by whatever is attached downstream to them. The
-+ * same is true of root ports, but root ports are always attached to
-+ * the root complex, so fall out above.
-+ */
-+ flags = pci_get_word(dev->config + dev->exp.exp_cap + PCI_EXP_FLAGS);
-+ type = (flags & PCI_EXP_FLAGS_TYPE) >> PCI_EXP_FLAGS_TYPE_SHIFT;
-+ if (type == PCI_EXP_TYPE_DOWNSTREAM) {
-+ goto unknown;
-+ }
-+
-+ /*
-+ * Multifunction devices don't negotiate independent speeds, let
-+ * function 0 do the negotiation and copy the results.
-+ */
-+ if (PCI_FUNC(dev->devfn)) {
-+ PCIDevice *sibling;
-+ uint16_t val;
-+
-+ sibling = pci_find_device(bus, pci_bus_num(bus),
-+ PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
-+ if (!sibling || !pci_is_express(sibling) || !sibling->exp.exp_cap) {
-+ goto unknown;
-+ }
-+
-+ val = pci_get_word(sibling->config + sibling->exp.exp_cap +
-+ PCI_EXP_LNKSTA);
-+
-+ pci_set_word_by_mask(dev->config + dev->exp.exp_cap + PCI_EXP_LNKSTA,
-+ PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS, val);
-+ return;
-+ }
-+
-+ parent = bus->parent_dev;
-+
-+ assert(pci_is_express(dev) && dev->exp.exp_cap &&
-+ pci_is_express(parent) && parent->exp.exp_cap);
-+
-+ /*
-+ * If LNKSTA reports a current/width speed and those values are actually
-+ * compatibile with the device as reported by LNKCAP, use them as the
-+ * target parameters. If the target values are incompatible, fall back
-+ * to regular negotiation.
-+ */
-+ if (pcie_link_current_width(dev) &&
-+ pcie_link_current_width(dev) <= pcie_link_max_width(dev) &&
-+ pcie_link_current_width(dev) <= pcie_link_max_width(parent)) {
-+ width = pcie_link_current_width(dev);
-+ } else {
-+ width = MIN(pcie_link_max_width(dev), pcie_link_max_width(parent));
-+ }
-+
-+ if (pcie_link_current_speed(dev) & pcie_link_speed_mask(dev)) {
-+ speed = 32 - clz32(pcie_link_current_speed(dev) &
-+ pcie_link_speed_mask(parent));
-+ }
-+ if (!speed) {
-+ speed = 32 - clz32(pcie_link_speed_mask(dev) &
-+ pcie_link_speed_mask(parent));
-+ }
-+
-+ pci_set_word_by_mask(parent->config + parent->exp.exp_cap + PCI_EXP_LNKSTA,
-+ PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS,
-+ width | speed);
-+unknown:
-+ pci_set_word_by_mask(dev->config + dev->exp.exp_cap + PCI_EXP_LNKSTA,
-+ PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS,
-+ width | speed);
-+}
-
- /***************************************************************************
- * pci express capability helper functions
-@@ -68,11 +228,11 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
- pci_set_long(exp_cap + PCI_EXP_LNKCAP,
- (port << PCI_EXP_LNKCAP_PN_SHIFT) |
- PCI_EXP_LNKCAP_ASPMS_0S |
-- PCI_EXP_LNK_MLW_1 |
-- PCI_EXP_LNK_LS_25);
-+ PCI_EXP_LNK_MLW_16 |
-+ PCI_EXP_LNK_LS_80);
-
- pci_set_word(exp_cap + PCI_EXP_LNKSTA,
-- PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
-+ PCI_EXP_LNK_MLW_16 | PCI_EXP_LNK_LS_80);
-
- if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
- pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
-@@ -111,6 +271,15 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset,
- pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
- PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
-
-+ pci_set_long(exp_cap + PCI_EXP_LNKCAP,
-+ (port << PCI_EXP_LNKCAP_PN_SHIFT) |
-+ PCI_EXP_LNKCAP_ASPMS_0S |
-+ PCI_EXP_LNK_MLW_16 |
-+ PCI_EXP_LNK_LS_80);
-+
-+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
-+ PCI_EXP_LNKCAP_ASPMS_L0S);
-+
- pci_set_word(dev->wmask + pos + PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_EETLPPB);
-
- if (dev->cap_present & QEMU_PCIE_EXTCAP_INIT) {
-@@ -118,6 +287,23 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset,
- pci_set_long(dev->wmask + PCI_CONFIG_SPACE_SIZE, 0);
- }
-
-+ if (type == PCI_EXP_TYPE_ROOT_PORT || type == PCI_EXP_TYPE_DOWNSTREAM) {
-+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP, PCI_EXP_LNKCAP_LBNC);
-+ }
-+
-+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
-+ PCI_EXP_LNK2_LS_25 |
-+ PCI_EXP_LNK2_LS_50 |
-+ PCI_EXP_LNK2_LS_80);
-+
-+ if (type == PCI_EXP_TYPE_DOWNSTREAM) {
-+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
-+ PCI_EXP_LNKCAP_DLLLARC);
-+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
-+ PCI_EXP_LNKSTA_DLLLA);
-+ }
-+
-+ pcie_negotiate_link(dev);
- return pos;
- }
-
-@@ -537,7 +723,7 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
-
- hotplug_event_notify(dev);
-
-- /*
-+ /*
- * 6.7.3.2 Command Completed Events
- *
- * Software issues a command to a hot-plug capable Downstream Port by
-@@ -763,4 +949,4 @@ void pcie_ats_init(PCIDevice *dev, uint16_t offset)
- pci_set_word(dev->config + offset + PCI_ATS_CTRL, 0);
-
- pci_set_word(dev->wmask + dev->exp.ats_cap + PCI_ATS_CTRL, 0x800f);
--}
-+}
-\ No newline at end of file
-diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
-index 6cbb8fa054..523bc81932 100644
---- a/hw/vfio/pci.c
-+++ b/hw/vfio/pci.c
-@@ -1886,6 +1886,7 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
- }
-
- } else {
-+#if 0
- /*
- * Convert Root Complex Integrated Endpoints to regular endpoints.
- * These devices don't support LNK/LNK2 capabilities, so make them up.
-@@ -1904,6 +1905,7 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
- pci_get_word(vdev->pdev.config + pos +
- PCI_EXP_LNKSTA),
- PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
-+#endif
- }
-
- /*
-@@ -3239,4 +3241,4 @@ static void register_vfio_pci_dev_type(void)
- type_register_static(&vfio_pci_dev_info);
- }
-
--type_init(register_vfio_pci_dev_type)
-+type_init(register_vfio_pci_dev_type)
-\ No newline at end of file
-diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
-index a95522a13b..bda852760f 100644
---- a/include/hw/pci/pcie_regs.h
-+++ b/include/hw/pci/pcie_regs.h
-@@ -35,13 +35,23 @@
- /* PCI_EXP_LINK{CAP, STA} */
- /* link speed */
- #define PCI_EXP_LNK_LS_25 1
-+#define PCI_EXP_LNK_LS_50 2
-+#define PCI_EXP_LNK_LS_80 3
-
- #define PCI_EXP_LNK_MLW_SHIFT ctz32(PCI_EXP_LNKCAP_MLW)
--#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT)
-+#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT)
-+#define PCI_EXP_LNK_MLW_2 (2 << PCI_EXP_LNK_MLW_SHIFT)
-+#define PCI_EXP_LNK_MLW_4 (4 << PCI_EXP_LNK_MLW_SHIFT)
-+#define PCI_EXP_LNK_MLW_8 (8 << PCI_EXP_LNK_MLW_SHIFT)
-+#define PCI_EXP_LNK_MLW_12 (12 << PCI_EXP_LNK_MLW_SHIFT)
-+#define PCI_EXP_LNK_MLW_16 (16 << PCI_EXP_LNK_MLW_SHIFT)
-
- /* PCI_EXP_LINKCAP */
- #define PCI_EXP_LNKCAP_ASPMS_SHIFT ctz32(PCI_EXP_LNKCAP_ASPMS)
- #define PCI_EXP_LNKCAP_ASPMS_0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
-+#define PCI_EXP_LNKCAP_ASPMS_L0S (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
-+#define PCI_EXP_LNKCAP_ASPMS_L1 (2 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
-+#define PCI_EXP_LNKCAP_ASPMS_L0SL1 (3 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
-
- #define PCI_EXP_LNKCAP_PN_SHIFT ctz32(PCI_EXP_LNKCAP_PN)
-
-@@ -75,6 +85,13 @@
-
- #define PCI_EXP_DEVCTL2_EETLPPB 0x8000
-
-+#define PCI_EXP_LNKCAP2 44 /* Link Capabilities 2 */
-+#define PCI_EXP_LINKCAP2_SLSV 0x000000fe /* Supported Link Speeds Vector */
-+#define PCI_EXP_LNKSTA2 50 /* Link Status 2 */
-+#define PCI_EXP_LNK2_LS_25 (1 << 1)
-+#define PCI_EXP_LNK2_LS_50 (1 << 2)
-+#define PCI_EXP_LNK2_LS_80 (1 << 3)
-+
- /* ARI */
- #define PCI_ARI_VER 1
- #define PCI_ARI_SIZEOF 8
-@@ -156,4 +173,4 @@
- PCI_ERR_COR_INTERNAL | \
- PCI_ERR_COR_HL_OVERFLOW)
-
--#endif /* QEMU_PCIE_REGS_H */
-+#endif /* QEMU_PCIE_REGS_H */
-\ No newline at end of file \ No newline at end of file