Compare commits
116 Commits
pull-ui-20
...
pull-audio
Author | SHA1 | Date | |
---|---|---|---|
|
11f547e58a | ||
|
12351a91da | ||
|
069eb7b2b8 | ||
|
8becab9523 | ||
|
c025d0abce | ||
|
b44486dfb9 | ||
|
41a0e54756 | ||
|
987da7be99 | ||
|
e1a58fc05a | ||
|
80db0e7822 | ||
|
c9c0854580 | ||
|
d1957dac34 | ||
|
8b35ab271c | ||
|
8dfba500af | ||
|
75ff0f0c90 | ||
|
a2088da36e | ||
|
4462fc604a | ||
|
a93e599d4a | ||
|
45a368ad4f | ||
|
c5f048d8fb | ||
|
283e2c2adc | ||
|
54e17709ac | ||
|
aa94d52142 | ||
|
312d3b3534 | ||
|
f2fd57db36 | ||
|
e66bcc4081 | ||
|
f18c697b55 | ||
|
33848ceed7 | ||
|
02ed3e7c16 | ||
|
ef69d971cd | ||
|
b89f8c80cc | ||
|
305f5131ac | ||
|
6138dbda5a | ||
|
46fd170545 | ||
|
c159a4d1d0 | ||
|
2e41dfe152 | ||
|
12d37882f0 | ||
|
efcd38c529 | ||
|
bd2baaccd5 | ||
|
615c4ed205 | ||
|
554f5e1604 | ||
|
052c8fa998 | ||
|
2d3fc5816e | ||
|
e0a3c8ccaa | ||
|
8607f5c307 | ||
|
a08aaff811 | ||
|
8cdcf3c1e5 | ||
|
f37bc03623 | ||
|
f634151b02 | ||
|
77424a452a | ||
|
dba5c337c8 | ||
|
c1bb86cd8a | ||
|
2e6fc7eb1a | ||
|
44b6789299 | ||
|
7c3a998531 | ||
|
7c37f941d0 | ||
|
a7e159025e | ||
|
6847da3808 | ||
|
dee66e2882 | ||
|
7cd9b3964e | ||
|
0f31977d9d | ||
|
ce15dc08ef | ||
|
10c8551968 | ||
|
536fca7f7e | ||
|
4baaa8c3d8 | ||
|
8305f9bdf7 | ||
|
556899fc19 | ||
|
24cb2e0d57 | ||
|
8dd845d3c4 | ||
|
af1f60a402 | ||
|
4dad9e7478 | ||
|
da4f09a7dc | ||
|
e9a8e474fb | ||
|
a72d436387 | ||
|
d05fdab46d | ||
|
054f4dc961 | ||
|
055a7f2b0a | ||
|
0127937b20 | ||
|
8c92c6a43e | ||
|
aca4bbf4a3 | ||
|
6e2ed65f4a | ||
|
330afe0599 | ||
|
156bc9a5ea | ||
|
c8ef2bda05 | ||
|
9ac4ef77c1 | ||
|
5b982482c1 | ||
|
d307c28ca9 | ||
|
f68808c749 | ||
|
f0d703314e | ||
|
999b941633 | ||
|
98d690761a | ||
|
0973b1cff8 | ||
|
32b69707df | ||
|
2294d05dab | ||
|
7f54eaa3b7 | ||
|
0119b1927d | ||
|
57a701fc2b | ||
|
bb08afe9f0 | ||
|
ffe22bf510 | ||
|
a01b1e9a00 | ||
|
7e354ed4df | ||
|
30a3e70167 | ||
|
646c5478c0 | ||
|
48ae36c0ad | ||
|
d7a2127a4c | ||
|
eaa5740304 | ||
|
465f2fedd2 | ||
|
2858bc6870 | ||
|
d93ddfb1f8 | ||
|
d9429b84af | ||
|
e10e798c85 | ||
|
7b2e5c65f4 | ||
|
98206d4e6b | ||
|
9652f5785e | ||
|
4e4212d056 | ||
|
3d1ad18c42 |
@@ -508,7 +508,6 @@ M: Shannon Zhao <shannon.zhao@linaro.org>
|
||||
L: qemu-arm@nongnu.org
|
||||
S: Maintained
|
||||
F: hw/arm/virt-acpi-build.c
|
||||
F: include/hw/arm/virt-acpi-build.h
|
||||
|
||||
STM32F205
|
||||
M: Alistair Francis <alistair@alistair23.me>
|
||||
@@ -885,7 +884,6 @@ F: hw/acpi/*
|
||||
F: hw/smbios/*
|
||||
F: hw/i386/acpi-build.[hc]
|
||||
F: hw/arm/virt-acpi-build.c
|
||||
F: include/hw/arm/virt-acpi-build.h
|
||||
|
||||
ppc4xx
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
@@ -1720,9 +1718,9 @@ L: qemu-block@nongnu.org
|
||||
S: Supported
|
||||
F: block/linux-aio.c
|
||||
F: include/block/raw-aio.h
|
||||
F: block/raw-posix.c
|
||||
F: block/raw-win32.c
|
||||
F: block/raw_bsd.c
|
||||
F: block/raw-format.c
|
||||
F: block/file-posix.c
|
||||
F: block/file-win32.c
|
||||
F: block/win32-aio.c
|
||||
|
||||
qcow2
|
||||
|
1
Makefile
1
Makefile
@@ -149,6 +149,7 @@ dummy := $(call unnest-vars,, \
|
||||
qga-obj-y \
|
||||
ivshmem-client-obj-y \
|
||||
ivshmem-server-obj-y \
|
||||
libvhost-user-obj-y \
|
||||
qga-vss-dll-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
|
@@ -115,7 +115,7 @@ qga-vss-dll-obj-y = qga/
|
||||
# contrib
|
||||
ivshmem-client-obj-y = contrib/ivshmem-client/
|
||||
ivshmem-server-obj-y = contrib/ivshmem-server/
|
||||
|
||||
libvhost-user-obj-y = contrib/libvhost-user/
|
||||
|
||||
######################################################################
|
||||
trace-events-y = trace-events
|
||||
|
@@ -94,6 +94,8 @@ static void cryptodev_builtin_init(
|
||||
backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo);
|
||||
backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
|
||||
backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
|
||||
|
||||
cryptodev_backend_set_ready(backend, true);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -111,23 +113,42 @@ cryptodev_builtin_get_unused_session_index(
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define AES_KEYSIZE_128 16
|
||||
#define AES_KEYSIZE_192 24
|
||||
#define AES_KEYSIZE_256 32
|
||||
#define AES_KEYSIZE_128_XTS AES_KEYSIZE_256
|
||||
#define AES_KEYSIZE_256_XTS 64
|
||||
|
||||
static int
|
||||
cryptodev_builtin_get_aes_algo(uint32_t key_len, Error **errp)
|
||||
cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp)
|
||||
{
|
||||
int algo;
|
||||
|
||||
if (key_len == 128 / 8) {
|
||||
if (key_len == AES_KEYSIZE_128) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_128;
|
||||
} else if (key_len == 192 / 8) {
|
||||
} else if (key_len == AES_KEYSIZE_192) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_192;
|
||||
} else if (key_len == 256 / 8) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_256;
|
||||
} else if (key_len == AES_KEYSIZE_256) { /* equals AES_KEYSIZE_128_XTS */
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_128;
|
||||
} else {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_256;
|
||||
}
|
||||
} else if (key_len == AES_KEYSIZE_256_XTS) {
|
||||
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_256;
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
error_setg(errp, "Unsupported key length :%u", key_len);
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return algo;
|
||||
|
||||
err:
|
||||
error_setg(errp, "Unsupported key length :%u", key_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int cryptodev_builtin_create_cipher_session(
|
||||
@@ -155,32 +176,48 @@ static int cryptodev_builtin_create_cipher_session(
|
||||
|
||||
switch (sess_info->cipher_alg) {
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_ECB:
|
||||
mode = QCRYPTO_CIPHER_MODE_ECB;
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
errp);
|
||||
mode, errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
mode = QCRYPTO_CIPHER_MODE_ECB;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_CBC:
|
||||
mode = QCRYPTO_CIPHER_MODE_CBC;
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
errp);
|
||||
mode, errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
mode = QCRYPTO_CIPHER_MODE_CBC;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_CTR:
|
||||
mode = QCRYPTO_CIPHER_MODE_CTR;
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
errp);
|
||||
mode, errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
mode = QCRYPTO_CIPHER_MODE_CTR;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_DES_ECB:
|
||||
algo = QCRYPTO_CIPHER_ALG_DES_RFB;
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_XTS:
|
||||
mode = QCRYPTO_CIPHER_MODE_XTS;
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
mode, errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_3DES_ECB:
|
||||
mode = QCRYPTO_CIPHER_MODE_ECB;
|
||||
algo = QCRYPTO_CIPHER_ALG_3DES;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_3DES_CBC:
|
||||
mode = QCRYPTO_CIPHER_MODE_CBC;
|
||||
algo = QCRYPTO_CIPHER_ALG_3DES;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_3DES_CTR:
|
||||
mode = QCRYPTO_CIPHER_MODE_CTR;
|
||||
algo = QCRYPTO_CIPHER_ALG_3DES;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher alg :%u",
|
||||
@@ -331,6 +368,8 @@ static void cryptodev_builtin_cleanup(
|
||||
backend->conf.peers.ccs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cryptodev_backend_set_ready(backend, false);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -73,8 +73,6 @@ void cryptodev_backend_cleanup(
|
||||
if (bc->cleanup) {
|
||||
bc->cleanup(backend, errp);
|
||||
}
|
||||
|
||||
backend->ready = false;
|
||||
}
|
||||
|
||||
int64_t cryptodev_backend_sym_create_session(
|
||||
@@ -189,14 +187,39 @@ cryptodev_backend_complete(UserCreatable *uc, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
backend->ready = true;
|
||||
|
||||
return;
|
||||
|
||||
out:
|
||||
backend->ready = false;
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
|
||||
{
|
||||
backend->is_used = used;
|
||||
}
|
||||
|
||||
bool cryptodev_backend_is_used(CryptoDevBackend *backend)
|
||||
{
|
||||
return backend->is_used;
|
||||
}
|
||||
|
||||
void cryptodev_backend_set_ready(CryptoDevBackend *backend, bool ready)
|
||||
{
|
||||
backend->ready = ready;
|
||||
}
|
||||
|
||||
bool cryptodev_backend_is_ready(CryptoDevBackend *backend)
|
||||
{
|
||||
return backend->ready;
|
||||
}
|
||||
|
||||
static bool
|
||||
cryptodev_backend_can_be_deleted(UserCreatable *uc, Error **errp)
|
||||
{
|
||||
return !cryptodev_backend_is_used(CRYPTODEV_BACKEND(uc));
|
||||
}
|
||||
|
||||
static void cryptodev_backend_instance_init(Object *obj)
|
||||
{
|
||||
object_property_add(obj, "queues", "int",
|
||||
@@ -209,7 +232,9 @@ static void cryptodev_backend_instance_init(Object *obj)
|
||||
|
||||
static void cryptodev_backend_finalize(Object *obj)
|
||||
{
|
||||
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
|
||||
|
||||
cryptodev_backend_cleanup(backend, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -218,6 +243,7 @@ cryptodev_backend_class_init(ObjectClass *oc, void *data)
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
|
||||
ucc->complete = cryptodev_backend_complete;
|
||||
ucc->can_be_deleted = cryptodev_backend_can_be_deleted;
|
||||
|
||||
QTAILQ_INIT(&crypto_clients);
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
block-obj-y += raw_bsd.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
|
||||
block-obj-y += raw-format.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
|
||||
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
|
||||
block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
|
||||
block-obj-y += qed-check.o
|
||||
@@ -6,8 +6,8 @@ block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
|
||||
block-obj-y += quorum.o
|
||||
block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
|
||||
block-obj-y += block-backend.o snapshot.o qapi.o
|
||||
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += raw-posix.o
|
||||
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += file-posix.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
block-obj-y += null.o mirror.o commit.o io.o
|
||||
block-obj-y += throttle-groups.o
|
||||
|
@@ -58,10 +58,6 @@ typedef struct BlkdebugSuspendedReq {
|
||||
QLIST_ENTRY(BlkdebugSuspendedReq) next;
|
||||
} BlkdebugSuspendedReq;
|
||||
|
||||
static const AIOCBInfo blkdebug_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlkdebugAIOCB),
|
||||
};
|
||||
|
||||
enum {
|
||||
ACTION_INJECT_ERROR,
|
||||
ACTION_SET_STATE,
|
||||
@@ -77,7 +73,7 @@ typedef struct BlkdebugRule {
|
||||
int error;
|
||||
int immediately;
|
||||
int once;
|
||||
int64_t sector;
|
||||
int64_t offset;
|
||||
} inject;
|
||||
struct {
|
||||
int new_state;
|
||||
@@ -174,6 +170,7 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
|
||||
const char* event_name;
|
||||
BlkdebugEvent event;
|
||||
struct BlkdebugRule *rule;
|
||||
int64_t sector;
|
||||
|
||||
/* Find the right event for the rule */
|
||||
event_name = qemu_opt_get(opts, "event");
|
||||
@@ -200,7 +197,9 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
|
||||
rule->options.inject.once = qemu_opt_get_bool(opts, "once", 0);
|
||||
rule->options.inject.immediately =
|
||||
qemu_opt_get_bool(opts, "immediately", 0);
|
||||
rule->options.inject.sector = qemu_opt_get_number(opts, "sector", -1);
|
||||
sector = qemu_opt_get_number(opts, "sector", -1);
|
||||
rule->options.inject.offset =
|
||||
sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
|
||||
break;
|
||||
|
||||
case ACTION_SET_STATE:
|
||||
@@ -408,17 +407,14 @@ out:
|
||||
|
||||
static void error_callback_bh(void *opaque)
|
||||
{
|
||||
struct BlkdebugAIOCB *acb = opaque;
|
||||
acb->common.cb(acb->common.opaque, acb->ret);
|
||||
qemu_aio_unref(acb);
|
||||
Coroutine *co = opaque;
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
|
||||
static BlockAIOCB *inject_error(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
|
||||
static int inject_error(BlockDriverState *bs, BlkdebugRule *rule)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
int error = rule->options.inject.error;
|
||||
struct BlkdebugAIOCB *acb;
|
||||
bool immediately = rule->options.inject.immediately;
|
||||
|
||||
if (rule->options.inject.once) {
|
||||
@@ -426,81 +422,79 @@ static BlockAIOCB *inject_error(BlockDriverState *bs,
|
||||
remove_rule(rule);
|
||||
}
|
||||
|
||||
if (immediately) {
|
||||
return NULL;
|
||||
if (!immediately) {
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), error_callback_bh,
|
||||
qemu_coroutine_self());
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
|
||||
acb->ret = -error;
|
||||
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), error_callback_bh, acb);
|
||||
|
||||
return &acb->common;
|
||||
return -error;
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
static int coroutine_fn
|
||||
blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugRule *rule = NULL;
|
||||
|
||||
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
|
||||
if (rule->options.inject.sector == -1 ||
|
||||
(rule->options.inject.sector >= sector_num &&
|
||||
rule->options.inject.sector < sector_num + nb_sectors)) {
|
||||
uint64_t inject_offset = rule->options.inject.offset;
|
||||
|
||||
if (inject_offset == -1 ||
|
||||
(inject_offset >= offset && inject_offset < offset + bytes))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rule && rule->options.inject.error) {
|
||||
return inject_error(bs, cb, opaque, rule);
|
||||
return inject_error(bs, rule);
|
||||
}
|
||||
|
||||
return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors,
|
||||
cb, opaque);
|
||||
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
static int coroutine_fn
|
||||
blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugRule *rule = NULL;
|
||||
|
||||
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
|
||||
if (rule->options.inject.sector == -1 ||
|
||||
(rule->options.inject.sector >= sector_num &&
|
||||
rule->options.inject.sector < sector_num + nb_sectors)) {
|
||||
uint64_t inject_offset = rule->options.inject.offset;
|
||||
|
||||
if (inject_offset == -1 ||
|
||||
(inject_offset >= offset && inject_offset < offset + bytes))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rule && rule->options.inject.error) {
|
||||
return inject_error(bs, cb, opaque, rule);
|
||||
return inject_error(bs, rule);
|
||||
}
|
||||
|
||||
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
|
||||
cb, opaque);
|
||||
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
static int blkdebug_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugRule *rule = NULL;
|
||||
|
||||
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
|
||||
if (rule->options.inject.sector == -1) {
|
||||
if (rule->options.inject.offset == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rule && rule->options.inject.error) {
|
||||
return inject_error(bs, cb, opaque, rule);
|
||||
return inject_error(bs, rule);
|
||||
}
|
||||
|
||||
return bdrv_aio_flush(bs->file->bs, cb, opaque);
|
||||
return bdrv_co_flush(bs->file->bs);
|
||||
}
|
||||
|
||||
|
||||
@@ -752,9 +746,9 @@ static BlockDriver bdrv_blkdebug = {
|
||||
.bdrv_refresh_filename = blkdebug_refresh_filename,
|
||||
.bdrv_refresh_limits = blkdebug_refresh_limits,
|
||||
|
||||
.bdrv_aio_readv = blkdebug_aio_readv,
|
||||
.bdrv_aio_writev = blkdebug_aio_writev,
|
||||
.bdrv_aio_flush = blkdebug_aio_flush,
|
||||
.bdrv_co_preadv = blkdebug_co_preadv,
|
||||
.bdrv_co_pwritev = blkdebug_co_pwritev,
|
||||
.bdrv_co_flush_to_disk = blkdebug_co_flush,
|
||||
|
||||
.bdrv_debug_event = blkdebug_debug_event,
|
||||
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
|
||||
|
@@ -19,38 +19,36 @@ typedef struct {
|
||||
BdrvChild *test_file;
|
||||
} BDRVBlkverifyState;
|
||||
|
||||
typedef struct BlkverifyAIOCB BlkverifyAIOCB;
|
||||
struct BlkverifyAIOCB {
|
||||
BlockAIOCB common;
|
||||
typedef struct BlkverifyRequest {
|
||||
Coroutine *co;
|
||||
BlockDriverState *bs;
|
||||
|
||||
/* Request metadata */
|
||||
bool is_write;
|
||||
int64_t sector_num;
|
||||
int nb_sectors;
|
||||
uint64_t offset;
|
||||
uint64_t bytes;
|
||||
int flags;
|
||||
|
||||
int (*request_fn)(BdrvChild *, int64_t, unsigned int, QEMUIOVector *,
|
||||
BdrvRequestFlags);
|
||||
|
||||
int ret; /* test image result */
|
||||
int raw_ret; /* raw image result */
|
||||
|
||||
int ret; /* first completed request's result */
|
||||
unsigned int done; /* completion counter */
|
||||
|
||||
QEMUIOVector *qiov; /* user I/O vector */
|
||||
QEMUIOVector raw_qiov; /* cloned I/O vector for raw file */
|
||||
void *buf; /* buffer for raw file I/O */
|
||||
QEMUIOVector *raw_qiov; /* cloned I/O vector for raw file */
|
||||
} BlkverifyRequest;
|
||||
|
||||
void (*verify)(BlkverifyAIOCB *acb);
|
||||
};
|
||||
|
||||
static const AIOCBInfo blkverify_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlkverifyAIOCB),
|
||||
};
|
||||
|
||||
static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyAIOCB *acb,
|
||||
static void GCC_FMT_ATTR(2, 3) blkverify_err(BlkverifyRequest *r,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "blkverify: %s sector_num=%" PRId64 " nb_sectors=%d ",
|
||||
acb->is_write ? "write" : "read", acb->sector_num,
|
||||
acb->nb_sectors);
|
||||
fprintf(stderr, "blkverify: %s offset=%" PRId64 " bytes=%" PRId64 " ",
|
||||
r->is_write ? "write" : "read", r->offset, r->bytes);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
@@ -166,113 +164,106 @@ static int64_t blkverify_getlength(BlockDriverState *bs)
|
||||
return bdrv_getlength(s->test_file->bs);
|
||||
}
|
||||
|
||||
static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
|
||||
int64_t sector_num, QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static void coroutine_fn blkverify_do_test_req(void *opaque)
|
||||
{
|
||||
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
|
||||
BlkverifyRequest *r = opaque;
|
||||
BDRVBlkverifyState *s = r->bs->opaque;
|
||||
|
||||
acb->is_write = is_write;
|
||||
acb->sector_num = sector_num;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
acb->ret = -EINPROGRESS;
|
||||
acb->done = 0;
|
||||
acb->qiov = qiov;
|
||||
acb->buf = NULL;
|
||||
acb->verify = NULL;
|
||||
return acb;
|
||||
r->ret = r->request_fn(s->test_file, r->offset, r->bytes, r->qiov,
|
||||
r->flags);
|
||||
r->done++;
|
||||
qemu_coroutine_enter_if_inactive(r->co);
|
||||
}
|
||||
|
||||
static void blkverify_aio_bh(void *opaque)
|
||||
static void coroutine_fn blkverify_do_raw_req(void *opaque)
|
||||
{
|
||||
BlkverifyAIOCB *acb = opaque;
|
||||
BlkverifyRequest *r = opaque;
|
||||
|
||||
if (acb->buf) {
|
||||
qemu_iovec_destroy(&acb->raw_qiov);
|
||||
qemu_vfree(acb->buf);
|
||||
r->raw_ret = r->request_fn(r->bs->file, r->offset, r->bytes, r->raw_qiov,
|
||||
r->flags);
|
||||
r->done++;
|
||||
qemu_coroutine_enter_if_inactive(r->co);
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, QEMUIOVector *raw_qiov,
|
||||
int flags, bool is_write)
|
||||
{
|
||||
Coroutine *co_a, *co_b;
|
||||
|
||||
*r = (BlkverifyRequest) {
|
||||
.co = qemu_coroutine_self(),
|
||||
.bs = bs,
|
||||
.offset = offset,
|
||||
.bytes = bytes,
|
||||
.qiov = qiov,
|
||||
.raw_qiov = raw_qiov,
|
||||
.flags = flags,
|
||||
.is_write = is_write,
|
||||
.request_fn = is_write ? bdrv_co_pwritev : bdrv_co_preadv,
|
||||
};
|
||||
|
||||
co_a = qemu_coroutine_create(blkverify_do_test_req, r);
|
||||
co_b = qemu_coroutine_create(blkverify_do_raw_req, r);
|
||||
|
||||
qemu_coroutine_enter(co_a);
|
||||
qemu_coroutine_enter(co_b);
|
||||
|
||||
while (r->done < 2) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
acb->common.cb(acb->common.opaque, acb->ret);
|
||||
qemu_aio_unref(acb);
|
||||
}
|
||||
|
||||
static void blkverify_aio_cb(void *opaque, int ret)
|
||||
{
|
||||
BlkverifyAIOCB *acb = opaque;
|
||||
|
||||
switch (++acb->done) {
|
||||
case 1:
|
||||
acb->ret = ret;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (acb->ret != ret) {
|
||||
blkverify_err(acb, "return value mismatch %d != %d", acb->ret, ret);
|
||||
}
|
||||
|
||||
if (acb->verify) {
|
||||
acb->verify(acb);
|
||||
}
|
||||
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
|
||||
blkverify_aio_bh, acb);
|
||||
break;
|
||||
if (r->ret != r->raw_ret) {
|
||||
blkverify_err(r, "return value mismatch %d != %d", r->ret, r->raw_ret);
|
||||
}
|
||||
|
||||
return r->ret;
|
||||
}
|
||||
|
||||
static void blkverify_verify_readv(BlkverifyAIOCB *acb)
|
||||
static int coroutine_fn
|
||||
blkverify_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
ssize_t offset = qemu_iovec_compare(acb->qiov, &acb->raw_qiov);
|
||||
if (offset != -1) {
|
||||
blkverify_err(acb, "contents mismatch in sector %" PRId64,
|
||||
acb->sector_num + (int64_t)(offset / BDRV_SECTOR_SIZE));
|
||||
BlkverifyRequest r;
|
||||
QEMUIOVector raw_qiov;
|
||||
void *buf;
|
||||
ssize_t cmp_offset;
|
||||
int ret;
|
||||
|
||||
buf = qemu_blockalign(bs->file->bs, qiov->size);
|
||||
qemu_iovec_init(&raw_qiov, qiov->niov);
|
||||
qemu_iovec_clone(&raw_qiov, qiov, buf);
|
||||
|
||||
ret = blkverify_co_prwv(bs, &r, offset, bytes, qiov, &raw_qiov, flags,
|
||||
false);
|
||||
|
||||
cmp_offset = qemu_iovec_compare(qiov, &raw_qiov);
|
||||
if (cmp_offset != -1) {
|
||||
blkverify_err(&r, "contents mismatch at offset %" PRId64,
|
||||
offset + cmp_offset);
|
||||
}
|
||||
|
||||
qemu_iovec_destroy(&raw_qiov);
|
||||
qemu_vfree(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkverify_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
static int coroutine_fn
|
||||
blkverify_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
|
||||
nb_sectors, cb, opaque);
|
||||
|
||||
acb->verify = blkverify_verify_readv;
|
||||
acb->buf = qemu_blockalign(bs->file->bs, qiov->size);
|
||||
qemu_iovec_init(&acb->raw_qiov, acb->qiov->niov);
|
||||
qemu_iovec_clone(&acb->raw_qiov, qiov, acb->buf);
|
||||
|
||||
bdrv_aio_readv(s->test_file, sector_num, qiov, nb_sectors,
|
||||
blkverify_aio_cb, acb);
|
||||
bdrv_aio_readv(bs->file, sector_num, &acb->raw_qiov, nb_sectors,
|
||||
blkverify_aio_cb, acb);
|
||||
return &acb->common;
|
||||
BlkverifyRequest r;
|
||||
return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true);
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkverify_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
|
||||
nb_sectors, cb, opaque);
|
||||
|
||||
bdrv_aio_writev(s->test_file, sector_num, qiov, nb_sectors,
|
||||
blkverify_aio_cb, acb);
|
||||
bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
|
||||
blkverify_aio_cb, acb);
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockAIOCB *blkverify_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static int blkverify_co_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
|
||||
/* Only flush test file, the raw file is not important */
|
||||
return bdrv_aio_flush(s->test_file->bs, cb, opaque);
|
||||
return bdrv_co_flush(s->test_file->bs);
|
||||
}
|
||||
|
||||
static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
|
||||
@@ -332,9 +323,9 @@ static BlockDriver bdrv_blkverify = {
|
||||
.bdrv_getlength = blkverify_getlength,
|
||||
.bdrv_refresh_filename = blkverify_refresh_filename,
|
||||
|
||||
.bdrv_aio_readv = blkverify_aio_readv,
|
||||
.bdrv_aio_writev = blkverify_aio_writev,
|
||||
.bdrv_aio_flush = blkverify_aio_flush,
|
||||
.bdrv_co_preadv = blkverify_co_preadv,
|
||||
.bdrv_co_pwritev = blkverify_co_pwritev,
|
||||
.bdrv_co_flush = blkverify_co_flush,
|
||||
|
||||
.is_filter = true,
|
||||
.bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter,
|
||||
|
@@ -1253,7 +1253,7 @@ static int qemu_gluster_has_zero_init(BlockDriverState *bs)
|
||||
* If @start is in a trailing hole or beyond EOF, return -ENXIO.
|
||||
* If we can't find out, return a negative errno other than -ENXIO.
|
||||
*
|
||||
* (Shamefully copied from raw-posix.c, only miniscule adaptions.)
|
||||
* (Shamefully copied from file-posix.c, only miniscule adaptions.)
|
||||
*/
|
||||
static int find_allocation(BlockDriverState *bs, off_t start,
|
||||
off_t *data, off_t *hole)
|
||||
@@ -1349,7 +1349,7 @@ exit:
|
||||
* 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
|
||||
* beyond the end of the disk image it will be clamped.
|
||||
*
|
||||
* (Based on raw_co_get_block_status() from raw-posix.c.)
|
||||
* (Based on raw_co_get_block_status() from file-posix.c.)
|
||||
*/
|
||||
static int64_t coroutine_fn qemu_gluster_co_get_block_status(
|
||||
BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
|
||||
|
410
block/quorum.c
410
block/quorum.c
@@ -97,7 +97,7 @@ typedef struct QuorumAIOCB QuorumAIOCB;
|
||||
* $children_count QuorumChildRequest.
|
||||
*/
|
||||
typedef struct QuorumChildRequest {
|
||||
BlockAIOCB *aiocb;
|
||||
BlockDriverState *bs;
|
||||
QEMUIOVector qiov;
|
||||
uint8_t *buf;
|
||||
int ret;
|
||||
@@ -110,11 +110,12 @@ typedef struct QuorumChildRequest {
|
||||
* used to do operations on each children and track overall progress.
|
||||
*/
|
||||
struct QuorumAIOCB {
|
||||
BlockAIOCB common;
|
||||
BlockDriverState *bs;
|
||||
Coroutine *co;
|
||||
|
||||
/* Request metadata */
|
||||
uint64_t sector_num;
|
||||
int nb_sectors;
|
||||
uint64_t offset;
|
||||
uint64_t bytes;
|
||||
|
||||
QEMUIOVector *qiov; /* calling IOV */
|
||||
|
||||
@@ -133,32 +134,15 @@ struct QuorumAIOCB {
|
||||
int children_read; /* how many children have been read from */
|
||||
};
|
||||
|
||||
static bool quorum_vote(QuorumAIOCB *acb);
|
||||
|
||||
static void quorum_aio_cancel(BlockAIOCB *blockacb)
|
||||
{
|
||||
QuorumAIOCB *acb = container_of(blockacb, QuorumAIOCB, common);
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
int i;
|
||||
|
||||
/* cancel all callbacks */
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
if (acb->qcrs[i].aiocb) {
|
||||
bdrv_aio_cancel_async(acb->qcrs[i].aiocb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static AIOCBInfo quorum_aiocb_info = {
|
||||
.aiocb_size = sizeof(QuorumAIOCB),
|
||||
.cancel_async = quorum_aio_cancel,
|
||||
};
|
||||
typedef struct QuorumCo {
|
||||
QuorumAIOCB *acb;
|
||||
int idx;
|
||||
} QuorumCo;
|
||||
|
||||
static void quorum_aio_finalize(QuorumAIOCB *acb)
|
||||
{
|
||||
acb->common.cb(acb->common.opaque, acb->vote_ret);
|
||||
g_free(acb->qcrs);
|
||||
qemu_aio_unref(acb);
|
||||
g_free(acb);
|
||||
}
|
||||
|
||||
static bool quorum_sha256_compare(QuorumVoteValue *a, QuorumVoteValue *b)
|
||||
@@ -171,30 +155,26 @@ static bool quorum_64bits_compare(QuorumVoteValue *a, QuorumVoteValue *b)
|
||||
return a->l == b->l;
|
||||
}
|
||||
|
||||
static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s,
|
||||
BlockDriverState *bs,
|
||||
static QuorumAIOCB *quorum_aio_get(BlockDriverState *bs,
|
||||
QEMUIOVector *qiov,
|
||||
uint64_t sector_num,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
uint64_t offset,
|
||||
uint64_t bytes)
|
||||
{
|
||||
QuorumAIOCB *acb = qemu_aio_get(&quorum_aiocb_info, bs, cb, opaque);
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = g_new(QuorumAIOCB, 1);
|
||||
int i;
|
||||
|
||||
acb->common.bs->opaque = s;
|
||||
acb->sector_num = sector_num;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
acb->qiov = qiov;
|
||||
acb->qcrs = g_new0(QuorumChildRequest, s->num_children);
|
||||
acb->count = 0;
|
||||
acb->success_count = 0;
|
||||
acb->rewrite_count = 0;
|
||||
acb->votes.compare = quorum_sha256_compare;
|
||||
QLIST_INIT(&acb->votes.vote_list);
|
||||
acb->is_read = false;
|
||||
acb->vote_ret = 0;
|
||||
*acb = (QuorumAIOCB) {
|
||||
.co = qemu_coroutine_self(),
|
||||
.bs = bs,
|
||||
.offset = offset,
|
||||
.bytes = bytes,
|
||||
.qiov = qiov,
|
||||
.votes.compare = quorum_sha256_compare,
|
||||
.votes.vote_list = QLIST_HEAD_INITIALIZER(acb.votes.vote_list),
|
||||
};
|
||||
|
||||
acb->qcrs = g_new0(QuorumChildRequest, s->num_children);
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
acb->qcrs[i].buf = NULL;
|
||||
acb->qcrs[i].ret = 0;
|
||||
@@ -204,30 +184,37 @@ static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s,
|
||||
return acb;
|
||||
}
|
||||
|
||||
static void quorum_report_bad(QuorumOpType type, uint64_t sector_num,
|
||||
int nb_sectors, char *node_name, int ret)
|
||||
static void quorum_report_bad(QuorumOpType type, uint64_t offset,
|
||||
uint64_t bytes, char *node_name, int ret)
|
||||
{
|
||||
const char *msg = NULL;
|
||||
int64_t start_sector = offset / BDRV_SECTOR_SIZE;
|
||||
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
|
||||
|
||||
if (ret < 0) {
|
||||
msg = strerror(-ret);
|
||||
}
|
||||
|
||||
qapi_event_send_quorum_report_bad(type, !!msg, msg, node_name,
|
||||
sector_num, nb_sectors, &error_abort);
|
||||
qapi_event_send_quorum_report_bad(type, !!msg, msg, node_name, start_sector,
|
||||
end_sector - start_sector, &error_abort);
|
||||
}
|
||||
|
||||
static void quorum_report_failure(QuorumAIOCB *acb)
|
||||
{
|
||||
const char *reference = bdrv_get_device_or_node_name(acb->common.bs);
|
||||
qapi_event_send_quorum_failure(reference, acb->sector_num,
|
||||
acb->nb_sectors, &error_abort);
|
||||
const char *reference = bdrv_get_device_or_node_name(acb->bs);
|
||||
int64_t start_sector = acb->offset / BDRV_SECTOR_SIZE;
|
||||
int64_t end_sector = DIV_ROUND_UP(acb->offset + acb->bytes,
|
||||
BDRV_SECTOR_SIZE);
|
||||
|
||||
qapi_event_send_quorum_failure(reference, start_sector,
|
||||
end_sector - start_sector, &error_abort);
|
||||
}
|
||||
|
||||
static int quorum_vote_error(QuorumAIOCB *acb);
|
||||
|
||||
static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
|
||||
if (acb->success_count < s->threshold) {
|
||||
acb->vote_ret = quorum_vote_error(acb);
|
||||
@@ -238,22 +225,7 @@ static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void quorum_rewrite_aio_cb(void *opaque, int ret)
|
||||
{
|
||||
QuorumAIOCB *acb = opaque;
|
||||
|
||||
/* one less rewrite to do */
|
||||
acb->rewrite_count--;
|
||||
|
||||
/* wait until all rewrite callbacks have completed */
|
||||
if (acb->rewrite_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
quorum_aio_finalize(acb);
|
||||
}
|
||||
|
||||
static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb);
|
||||
static int read_fifo_child(QuorumAIOCB *acb);
|
||||
|
||||
static void quorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source)
|
||||
{
|
||||
@@ -272,70 +244,7 @@ static void quorum_report_bad_acb(QuorumChildRequest *sacb, int ret)
|
||||
{
|
||||
QuorumAIOCB *acb = sacb->parent;
|
||||
QuorumOpType type = acb->is_read ? QUORUM_OP_TYPE_READ : QUORUM_OP_TYPE_WRITE;
|
||||
quorum_report_bad(type, acb->sector_num, acb->nb_sectors,
|
||||
sacb->aiocb->bs->node_name, ret);
|
||||
}
|
||||
|
||||
static void quorum_fifo_aio_cb(void *opaque, int ret)
|
||||
{
|
||||
QuorumChildRequest *sacb = opaque;
|
||||
QuorumAIOCB *acb = sacb->parent;
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
|
||||
assert(acb->is_read && s->read_pattern == QUORUM_READ_PATTERN_FIFO);
|
||||
|
||||
if (ret < 0) {
|
||||
quorum_report_bad_acb(sacb, ret);
|
||||
|
||||
/* We try to read next child in FIFO order if we fail to read */
|
||||
if (acb->children_read < s->num_children) {
|
||||
read_fifo_child(acb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
acb->vote_ret = ret;
|
||||
|
||||
/* FIXME: rewrite failed children if acb->children_read > 1? */
|
||||
quorum_aio_finalize(acb);
|
||||
}
|
||||
|
||||
static void quorum_aio_cb(void *opaque, int ret)
|
||||
{
|
||||
QuorumChildRequest *sacb = opaque;
|
||||
QuorumAIOCB *acb = sacb->parent;
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
bool rewrite = false;
|
||||
int i;
|
||||
|
||||
sacb->ret = ret;
|
||||
if (ret == 0) {
|
||||
acb->success_count++;
|
||||
} else {
|
||||
quorum_report_bad_acb(sacb, ret);
|
||||
}
|
||||
acb->count++;
|
||||
assert(acb->count <= s->num_children);
|
||||
assert(acb->success_count <= s->num_children);
|
||||
if (acb->count < s->num_children) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do the vote on read */
|
||||
if (acb->is_read) {
|
||||
rewrite = quorum_vote(acb);
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
qemu_vfree(acb->qcrs[i].buf);
|
||||
qemu_iovec_destroy(&acb->qcrs[i].qiov);
|
||||
}
|
||||
} else {
|
||||
quorum_has_too_much_io_failed(acb);
|
||||
}
|
||||
|
||||
/* if no rewrite is done the code will finish right away */
|
||||
if (!rewrite) {
|
||||
quorum_aio_finalize(acb);
|
||||
}
|
||||
quorum_report_bad(type, acb->offset, acb->bytes, sacb->bs->node_name, ret);
|
||||
}
|
||||
|
||||
static void quorum_report_bad_versions(BDRVQuorumState *s,
|
||||
@@ -350,14 +259,31 @@ static void quorum_report_bad_versions(BDRVQuorumState *s,
|
||||
continue;
|
||||
}
|
||||
QLIST_FOREACH(item, &version->items, next) {
|
||||
quorum_report_bad(QUORUM_OP_TYPE_READ, acb->sector_num,
|
||||
acb->nb_sectors,
|
||||
quorum_report_bad(QUORUM_OP_TYPE_READ, acb->offset, acb->bytes,
|
||||
s->children[item->index]->bs->node_name, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb,
|
||||
static void quorum_rewrite_entry(void *opaque)
|
||||
{
|
||||
QuorumCo *co = opaque;
|
||||
QuorumAIOCB *acb = co->acb;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
|
||||
/* Ignore any errors, it's just a correction attempt for already
|
||||
* corrupted data. */
|
||||
bdrv_co_pwritev(s->children[co->idx], acb->offset, acb->bytes,
|
||||
acb->qiov, 0);
|
||||
|
||||
/* Wake up the caller after the last rewrite */
|
||||
acb->rewrite_count--;
|
||||
if (!acb->rewrite_count) {
|
||||
qemu_coroutine_enter_if_inactive(acb->co);
|
||||
}
|
||||
}
|
||||
|
||||
static bool quorum_rewrite_bad_versions(QuorumAIOCB *acb,
|
||||
QuorumVoteValue *value)
|
||||
{
|
||||
QuorumVoteVersion *version;
|
||||
@@ -376,7 +302,7 @@ static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb,
|
||||
}
|
||||
}
|
||||
|
||||
/* quorum_rewrite_aio_cb will count down this to zero */
|
||||
/* quorum_rewrite_entry will count down this to zero */
|
||||
acb->rewrite_count = count;
|
||||
|
||||
/* now fire the correcting rewrites */
|
||||
@@ -385,9 +311,14 @@ static bool quorum_rewrite_bad_versions(BDRVQuorumState *s, QuorumAIOCB *acb,
|
||||
continue;
|
||||
}
|
||||
QLIST_FOREACH(item, &version->items, next) {
|
||||
bdrv_aio_writev(s->children[item->index], acb->sector_num,
|
||||
acb->qiov, acb->nb_sectors, quorum_rewrite_aio_cb,
|
||||
acb);
|
||||
Coroutine *co;
|
||||
QuorumCo data = {
|
||||
.acb = acb,
|
||||
.idx = item->index,
|
||||
};
|
||||
|
||||
co = qemu_coroutine_create(quorum_rewrite_entry, &data);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,8 +438,8 @@ static void GCC_FMT_ATTR(2, 3) quorum_err(QuorumAIOCB *acb,
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "quorum: sector_num=%" PRId64 " nb_sectors=%d ",
|
||||
acb->sector_num, acb->nb_sectors);
|
||||
fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64 " ",
|
||||
acb->offset, acb->bytes);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
@@ -519,16 +450,15 @@ static bool quorum_compare(QuorumAIOCB *acb,
|
||||
QEMUIOVector *a,
|
||||
QEMUIOVector *b)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
ssize_t offset;
|
||||
|
||||
/* This driver will replace blkverify in this particular case */
|
||||
if (s->is_blkverify) {
|
||||
offset = qemu_iovec_compare(a, b);
|
||||
if (offset != -1) {
|
||||
quorum_err(acb, "contents mismatch in sector %" PRId64,
|
||||
acb->sector_num +
|
||||
(uint64_t)(offset / BDRV_SECTOR_SIZE));
|
||||
quorum_err(acb, "contents mismatch at offset %" PRIu64,
|
||||
acb->offset + offset);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -539,7 +469,7 @@ static bool quorum_compare(QuorumAIOCB *acb,
|
||||
/* Do a vote to get the error code */
|
||||
static int quorum_vote_error(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
QuorumVoteVersion *winner = NULL;
|
||||
QuorumVotes error_votes;
|
||||
QuorumVoteValue result_value;
|
||||
@@ -568,17 +498,16 @@ static int quorum_vote_error(QuorumAIOCB *acb)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool quorum_vote(QuorumAIOCB *acb)
|
||||
static void quorum_vote(QuorumAIOCB *acb)
|
||||
{
|
||||
bool quorum = true;
|
||||
bool rewrite = false;
|
||||
int i, j, ret;
|
||||
QuorumVoteValue hash;
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
QuorumVoteVersion *winner;
|
||||
|
||||
if (quorum_has_too_much_io_failed(acb)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the index of the first successful read */
|
||||
@@ -606,7 +535,7 @@ static bool quorum_vote(QuorumAIOCB *acb)
|
||||
/* Every successful read agrees */
|
||||
if (quorum) {
|
||||
quorum_copy_qiov(acb->qiov, &acb->qcrs[i].qiov);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* compute hashes for each successful read, also store indexes */
|
||||
@@ -641,19 +570,46 @@ static bool quorum_vote(QuorumAIOCB *acb)
|
||||
|
||||
/* corruption correction is enabled */
|
||||
if (s->rewrite_corrupted) {
|
||||
rewrite = quorum_rewrite_bad_versions(s, acb, &winner->value);
|
||||
quorum_rewrite_bad_versions(acb, &winner->value);
|
||||
}
|
||||
|
||||
free_exit:
|
||||
/* free lists */
|
||||
quorum_free_vote_list(&acb->votes);
|
||||
return rewrite;
|
||||
}
|
||||
|
||||
static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb)
|
||||
static void read_quorum_children_entry(void *opaque)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
int i;
|
||||
QuorumCo *co = opaque;
|
||||
QuorumAIOCB *acb = co->acb;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
int i = co->idx;
|
||||
QuorumChildRequest *sacb = &acb->qcrs[i];
|
||||
|
||||
sacb->bs = s->children[i]->bs;
|
||||
sacb->ret = bdrv_co_preadv(s->children[i], acb->offset, acb->bytes,
|
||||
&acb->qcrs[i].qiov, 0);
|
||||
|
||||
if (sacb->ret == 0) {
|
||||
acb->success_count++;
|
||||
} else {
|
||||
quorum_report_bad_acb(sacb, sacb->ret);
|
||||
}
|
||||
|
||||
acb->count++;
|
||||
assert(acb->count <= s->num_children);
|
||||
assert(acb->success_count <= s->num_children);
|
||||
|
||||
/* Wake up the caller after the last read */
|
||||
if (acb->count == s->num_children) {
|
||||
qemu_coroutine_enter_if_inactive(acb->co);
|
||||
}
|
||||
}
|
||||
|
||||
static int read_quorum_children(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
int i, ret;
|
||||
|
||||
acb->children_read = s->num_children;
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
@@ -663,65 +619,131 @@ static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb)
|
||||
}
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
acb->qcrs[i].aiocb = bdrv_aio_readv(s->children[i], acb->sector_num,
|
||||
&acb->qcrs[i].qiov, acb->nb_sectors,
|
||||
quorum_aio_cb, &acb->qcrs[i]);
|
||||
Coroutine *co;
|
||||
QuorumCo data = {
|
||||
.acb = acb,
|
||||
.idx = i,
|
||||
};
|
||||
|
||||
co = qemu_coroutine_create(read_quorum_children_entry, &data);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
|
||||
return &acb->common;
|
||||
while (acb->count < s->num_children) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
/* Do the vote on read */
|
||||
quorum_vote(acb);
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
qemu_vfree(acb->qcrs[i].buf);
|
||||
qemu_iovec_destroy(&acb->qcrs[i].qiov);
|
||||
}
|
||||
|
||||
while (acb->rewrite_count) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
ret = acb->vote_ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb)
|
||||
static int read_fifo_child(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
int n = acb->children_read++;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
int n, ret;
|
||||
|
||||
acb->qcrs[n].aiocb = bdrv_aio_readv(s->children[n], acb->sector_num,
|
||||
acb->qiov, acb->nb_sectors,
|
||||
quorum_fifo_aio_cb, &acb->qcrs[n]);
|
||||
/* We try to read the next child in FIFO order if we failed to read */
|
||||
do {
|
||||
n = acb->children_read++;
|
||||
acb->qcrs[n].bs = s->children[n]->bs;
|
||||
ret = bdrv_co_preadv(s->children[n], acb->offset, acb->bytes,
|
||||
acb->qiov, 0);
|
||||
if (ret < 0) {
|
||||
quorum_report_bad_acb(&acb->qcrs[n], ret);
|
||||
}
|
||||
} while (ret < 0 && acb->children_read < s->num_children);
|
||||
|
||||
return &acb->common;
|
||||
/* FIXME: rewrite failed children if acb->children_read > 1? */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockAIOCB *quorum_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static int quorum_co_preadv(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num,
|
||||
nb_sectors, cb, opaque);
|
||||
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes);
|
||||
int ret;
|
||||
|
||||
acb->is_read = true;
|
||||
acb->children_read = 0;
|
||||
|
||||
if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) {
|
||||
return read_quorum_children(acb);
|
||||
ret = read_quorum_children(acb);
|
||||
} else {
|
||||
ret = read_fifo_child(acb);
|
||||
}
|
||||
quorum_aio_finalize(acb);
|
||||
|
||||
return read_fifo_child(acb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockAIOCB *quorum_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static void write_quorum_entry(void *opaque)
|
||||
{
|
||||
QuorumCo *co = opaque;
|
||||
QuorumAIOCB *acb = co->acb;
|
||||
BDRVQuorumState *s = acb->bs->opaque;
|
||||
int i = co->idx;
|
||||
QuorumChildRequest *sacb = &acb->qcrs[i];
|
||||
|
||||
sacb->bs = s->children[i]->bs;
|
||||
sacb->ret = bdrv_co_pwritev(s->children[i], acb->offset, acb->bytes,
|
||||
acb->qiov, 0);
|
||||
if (sacb->ret == 0) {
|
||||
acb->success_count++;
|
||||
} else {
|
||||
quorum_report_bad_acb(sacb, sacb->ret);
|
||||
}
|
||||
acb->count++;
|
||||
assert(acb->count <= s->num_children);
|
||||
assert(acb->success_count <= s->num_children);
|
||||
|
||||
/* Wake up the caller after the last write */
|
||||
if (acb->count == s->num_children) {
|
||||
qemu_coroutine_enter_if_inactive(acb->co);
|
||||
}
|
||||
}
|
||||
|
||||
static int quorum_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
uint64_t bytes, QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num, nb_sectors,
|
||||
cb, opaque);
|
||||
int i;
|
||||
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes);
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < s->num_children; i++) {
|
||||
acb->qcrs[i].aiocb = bdrv_aio_writev(s->children[i], sector_num,
|
||||
qiov, nb_sectors, &quorum_aio_cb,
|
||||
&acb->qcrs[i]);
|
||||
Coroutine *co;
|
||||
QuorumCo data = {
|
||||
.acb = acb,
|
||||
.idx = i,
|
||||
};
|
||||
|
||||
co = qemu_coroutine_create(write_quorum_entry, &data);
|
||||
qemu_coroutine_enter(co);
|
||||
}
|
||||
|
||||
return &acb->common;
|
||||
while (acb->count < s->num_children) {
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
quorum_has_too_much_io_failed(acb);
|
||||
|
||||
ret = acb->vote_ret;
|
||||
quorum_aio_finalize(acb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int64_t quorum_getlength(BlockDriverState *bs)
|
||||
@@ -765,7 +787,7 @@ static coroutine_fn int quorum_co_flush(BlockDriverState *bs)
|
||||
result = bdrv_co_flush(s->children[i]->bs);
|
||||
if (result) {
|
||||
quorum_report_bad(QUORUM_OP_TYPE_FLUSH, 0,
|
||||
bdrv_nb_sectors(s->children[i]->bs),
|
||||
bdrv_getlength(s->children[i]->bs),
|
||||
s->children[i]->bs->node_name, result);
|
||||
result_value.l = result;
|
||||
quorum_count_vote(&error_votes, &result_value, i);
|
||||
@@ -1098,8 +1120,8 @@ static BlockDriver bdrv_quorum = {
|
||||
|
||||
.bdrv_getlength = quorum_getlength,
|
||||
|
||||
.bdrv_aio_readv = quorum_aio_readv,
|
||||
.bdrv_aio_writev = quorum_aio_writev,
|
||||
.bdrv_co_preadv = quorum_co_preadv,
|
||||
.bdrv_co_pwritev = quorum_co_pwritev,
|
||||
|
||||
.bdrv_add_child = quorum_add_child,
|
||||
.bdrv_del_child = quorum_del_child,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* BlockDriver implementation for "raw"
|
||||
/* BlockDriver implementation for "raw" format driver
|
||||
*
|
||||
* Copyright (C) 2010-2016 Red Hat, Inc.
|
||||
* Copyright (C) 2010, Blue Swirl <blauwirbel@gmail.com>
|
@@ -53,8 +53,8 @@ qmp_block_job_resume(void *job) "job %p"
|
||||
qmp_block_job_complete(void *job) "job %p"
|
||||
qmp_block_stream(void *bs, void *job) "bs %p job %p"
|
||||
|
||||
# block/raw-win32.c
|
||||
# block/raw-posix.c
|
||||
# block/file-win32.c
|
||||
# block/file-posix.c
|
||||
paio_submit_co(int64_t offset, int count, int type) "offset %"PRId64" count %d type %d"
|
||||
paio_submit(void *acb, void *opaque, int64_t offset, int count, int type) "acb %p opaque %p offset %"PRId64" count %d type %d"
|
||||
|
||||
|
2
configure
vendored
2
configure
vendored
@@ -2750,7 +2750,7 @@ if compile_prog "" "" ; then
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# xfsctl() probe, used for raw-posix
|
||||
# xfsctl() probe, used for file-posix.c
|
||||
if test "$xfs" != "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <stddef.h> /* NULL */
|
||||
|
1
contrib/libvhost-user/Makefile.objs
Normal file
1
contrib/libvhost-user/Makefile.objs
Normal file
@@ -0,0 +1 @@
|
||||
libvhost-user-obj-y = libvhost-user.o
|
1499
contrib/libvhost-user/libvhost-user.c
Normal file
1499
contrib/libvhost-user/libvhost-user.c
Normal file
File diff suppressed because it is too large
Load Diff
435
contrib/libvhost-user/libvhost-user.h
Normal file
435
contrib/libvhost-user/libvhost-user.h
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* Vhost User library
|
||||
*
|
||||
* Copyright (c) 2016 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Victor Kaplansky <victork@redhat.com>
|
||||
* Marc-André Lureau <mlureau@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef LIBVHOST_USER_H
|
||||
#define LIBVHOST_USER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <linux/vhost.h>
|
||||
#include "standard-headers/linux/virtio_ring.h"
|
||||
|
||||
/* Based on qemu/hw/virtio/vhost-user.c */
|
||||
#define VHOST_USER_F_PROTOCOL_FEATURES 30
|
||||
#define VHOST_LOG_PAGE 4096
|
||||
|
||||
#define VHOST_MAX_NR_VIRTQUEUE 8
|
||||
#define VIRTQUEUE_MAX_SIZE 1024
|
||||
|
||||
#define VHOST_MEMORY_MAX_NREGIONS 8
|
||||
|
||||
enum VhostUserProtocolFeature {
|
||||
VHOST_USER_PROTOCOL_F_MQ = 0,
|
||||
VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
|
||||
VHOST_USER_PROTOCOL_F_RARP = 2,
|
||||
|
||||
VHOST_USER_PROTOCOL_F_MAX
|
||||
};
|
||||
|
||||
#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1)
|
||||
|
||||
typedef enum VhostUserRequest {
|
||||
VHOST_USER_NONE = 0,
|
||||
VHOST_USER_GET_FEATURES = 1,
|
||||
VHOST_USER_SET_FEATURES = 2,
|
||||
VHOST_USER_SET_OWNER = 3,
|
||||
VHOST_USER_RESET_OWNER = 4,
|
||||
VHOST_USER_SET_MEM_TABLE = 5,
|
||||
VHOST_USER_SET_LOG_BASE = 6,
|
||||
VHOST_USER_SET_LOG_FD = 7,
|
||||
VHOST_USER_SET_VRING_NUM = 8,
|
||||
VHOST_USER_SET_VRING_ADDR = 9,
|
||||
VHOST_USER_SET_VRING_BASE = 10,
|
||||
VHOST_USER_GET_VRING_BASE = 11,
|
||||
VHOST_USER_SET_VRING_KICK = 12,
|
||||
VHOST_USER_SET_VRING_CALL = 13,
|
||||
VHOST_USER_SET_VRING_ERR = 14,
|
||||
VHOST_USER_GET_PROTOCOL_FEATURES = 15,
|
||||
VHOST_USER_SET_PROTOCOL_FEATURES = 16,
|
||||
VHOST_USER_GET_QUEUE_NUM = 17,
|
||||
VHOST_USER_SET_VRING_ENABLE = 18,
|
||||
VHOST_USER_SEND_RARP = 19,
|
||||
VHOST_USER_INPUT_GET_CONFIG = 20,
|
||||
VHOST_USER_MAX
|
||||
} VhostUserRequest;
|
||||
|
||||
typedef struct VhostUserMemoryRegion {
|
||||
uint64_t guest_phys_addr;
|
||||
uint64_t memory_size;
|
||||
uint64_t userspace_addr;
|
||||
uint64_t mmap_offset;
|
||||
} VhostUserMemoryRegion;
|
||||
|
||||
typedef struct VhostUserMemory {
|
||||
uint32_t nregions;
|
||||
uint32_t padding;
|
||||
VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS];
|
||||
} VhostUserMemory;
|
||||
|
||||
typedef struct VhostUserLog {
|
||||
uint64_t mmap_size;
|
||||
uint64_t mmap_offset;
|
||||
} VhostUserLog;
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define VU_PACKED __attribute__((gcc_struct, packed))
|
||||
#else
|
||||
# define VU_PACKED __attribute__((packed))
|
||||
#endif
|
||||
|
||||
typedef struct VhostUserMsg {
|
||||
VhostUserRequest request;
|
||||
|
||||
#define VHOST_USER_VERSION_MASK (0x3)
|
||||
#define VHOST_USER_REPLY_MASK (0x1 << 2)
|
||||
uint32_t flags;
|
||||
uint32_t size; /* the following payload size */
|
||||
|
||||
union {
|
||||
#define VHOST_USER_VRING_IDX_MASK (0xff)
|
||||
#define VHOST_USER_VRING_NOFD_MASK (0x1 << 8)
|
||||
uint64_t u64;
|
||||
struct vhost_vring_state state;
|
||||
struct vhost_vring_addr addr;
|
||||
VhostUserMemory memory;
|
||||
VhostUserLog log;
|
||||
} payload;
|
||||
|
||||
int fds[VHOST_MEMORY_MAX_NREGIONS];
|
||||
int fd_num;
|
||||
uint8_t *data;
|
||||
} VU_PACKED VhostUserMsg;
|
||||
|
||||
typedef struct VuDevRegion {
|
||||
/* Guest Physical address. */
|
||||
uint64_t gpa;
|
||||
/* Memory region size. */
|
||||
uint64_t size;
|
||||
/* QEMU virtual address (userspace). */
|
||||
uint64_t qva;
|
||||
/* Starting offset in our mmaped space. */
|
||||
uint64_t mmap_offset;
|
||||
/* Start address of mmaped space. */
|
||||
uint64_t mmap_addr;
|
||||
} VuDevRegion;
|
||||
|
||||
typedef struct VuDev VuDev;
|
||||
|
||||
typedef uint64_t (*vu_get_features_cb) (VuDev *dev);
|
||||
typedef void (*vu_set_features_cb) (VuDev *dev, uint64_t features);
|
||||
typedef int (*vu_process_msg_cb) (VuDev *dev, VhostUserMsg *vmsg,
|
||||
int *do_reply);
|
||||
typedef void (*vu_queue_set_started_cb) (VuDev *dev, int qidx, bool started);
|
||||
|
||||
typedef struct VuDevIface {
|
||||
/* called by VHOST_USER_GET_FEATURES to get the features bitmask */
|
||||
vu_get_features_cb get_features;
|
||||
/* enable vhost implementation features */
|
||||
vu_set_features_cb set_features;
|
||||
/* get the protocol feature bitmask from the underlying vhost
|
||||
* implementation */
|
||||
vu_get_features_cb get_protocol_features;
|
||||
/* enable protocol features in the underlying vhost implementation. */
|
||||
vu_set_features_cb set_protocol_features;
|
||||
/* process_msg is called for each vhost-user message received */
|
||||
/* skip libvhost-user processing if return value != 0 */
|
||||
vu_process_msg_cb process_msg;
|
||||
/* tells when queues can be processed */
|
||||
vu_queue_set_started_cb queue_set_started;
|
||||
} VuDevIface;
|
||||
|
||||
typedef void (*vu_queue_handler_cb) (VuDev *dev, int qidx);
|
||||
|
||||
typedef struct VuRing {
|
||||
unsigned int num;
|
||||
struct vring_desc *desc;
|
||||
struct vring_avail *avail;
|
||||
struct vring_used *used;
|
||||
uint64_t log_guest_addr;
|
||||
uint32_t flags;
|
||||
} VuRing;
|
||||
|
||||
typedef struct VuVirtq {
|
||||
VuRing vring;
|
||||
|
||||
/* Next head to pop */
|
||||
uint16_t last_avail_idx;
|
||||
|
||||
/* Last avail_idx read from VQ. */
|
||||
uint16_t shadow_avail_idx;
|
||||
|
||||
uint16_t used_idx;
|
||||
|
||||
/* Last used index value we have signalled on */
|
||||
uint16_t signalled_used;
|
||||
|
||||
/* Last used index value we have signalled on */
|
||||
bool signalled_used_valid;
|
||||
|
||||
/* Notification enabled? */
|
||||
bool notification;
|
||||
|
||||
int inuse;
|
||||
|
||||
vu_queue_handler_cb handler;
|
||||
|
||||
int call_fd;
|
||||
int kick_fd;
|
||||
int err_fd;
|
||||
unsigned int enable;
|
||||
bool started;
|
||||
} VuVirtq;
|
||||
|
||||
enum VuWatchCondtion {
|
||||
VU_WATCH_IN = 1 << 0,
|
||||
VU_WATCH_OUT = 1 << 1,
|
||||
VU_WATCH_PRI = 1 << 2,
|
||||
VU_WATCH_ERR = 1 << 3,
|
||||
VU_WATCH_HUP = 1 << 4,
|
||||
};
|
||||
|
||||
typedef void (*vu_panic_cb) (VuDev *dev, const char *err);
|
||||
typedef void (*vu_watch_cb) (VuDev *dev, int condition, void *data);
|
||||
typedef void (*vu_set_watch_cb) (VuDev *dev, int fd, int condition,
|
||||
vu_watch_cb cb, void *data);
|
||||
typedef void (*vu_remove_watch_cb) (VuDev *dev, int fd);
|
||||
|
||||
struct VuDev {
|
||||
int sock;
|
||||
uint32_t nregions;
|
||||
VuDevRegion regions[VHOST_MEMORY_MAX_NREGIONS];
|
||||
VuVirtq vq[VHOST_MAX_NR_VIRTQUEUE];
|
||||
int log_call_fd;
|
||||
uint64_t log_size;
|
||||
uint8_t *log_table;
|
||||
uint64_t features;
|
||||
uint64_t protocol_features;
|
||||
bool broken;
|
||||
|
||||
/* @set_watch: add or update the given fd to the watch set,
|
||||
* call cb when condition is met */
|
||||
vu_set_watch_cb set_watch;
|
||||
|
||||
/* @remove_watch: remove the given fd from the watch set */
|
||||
vu_remove_watch_cb remove_watch;
|
||||
|
||||
/* @panic: encountered an unrecoverable error, you may try to
|
||||
* re-initialize */
|
||||
vu_panic_cb panic;
|
||||
const VuDevIface *iface;
|
||||
};
|
||||
|
||||
typedef struct VuVirtqElement {
|
||||
unsigned int index;
|
||||
unsigned int out_num;
|
||||
unsigned int in_num;
|
||||
struct iovec *in_sg;
|
||||
struct iovec *out_sg;
|
||||
} VuVirtqElement;
|
||||
|
||||
/**
|
||||
* vu_init:
|
||||
* @dev: a VuDev context
|
||||
* @socket: the socket connected to vhost-user master
|
||||
* @panic: a panic callback
|
||||
* @set_watch: a set_watch callback
|
||||
* @remove_watch: a remove_watch callback
|
||||
* @iface: a VuDevIface structure with vhost-user device callbacks
|
||||
*
|
||||
* Intializes a VuDev vhost-user context.
|
||||
**/
|
||||
void vu_init(VuDev *dev,
|
||||
int socket,
|
||||
vu_panic_cb panic,
|
||||
vu_set_watch_cb set_watch,
|
||||
vu_remove_watch_cb remove_watch,
|
||||
const VuDevIface *iface);
|
||||
|
||||
|
||||
/**
|
||||
* vu_deinit:
|
||||
* @dev: a VuDev context
|
||||
*
|
||||
* Cleans up the VuDev context
|
||||
*/
|
||||
void vu_deinit(VuDev *dev);
|
||||
|
||||
/**
|
||||
* vu_dispatch:
|
||||
* @dev: a VuDev context
|
||||
*
|
||||
* Process one vhost-user message.
|
||||
*
|
||||
* Returns: TRUE on success, FALSE on failure.
|
||||
*/
|
||||
bool vu_dispatch(VuDev *dev);
|
||||
|
||||
/**
|
||||
* vu_gpa_to_va:
|
||||
* @dev: a VuDev context
|
||||
* @guest_addr: guest address
|
||||
*
|
||||
* Translate a guest address to a pointer. Returns NULL on failure.
|
||||
*/
|
||||
void *vu_gpa_to_va(VuDev *dev, uint64_t guest_addr);
|
||||
|
||||
/**
|
||||
* vu_get_queue:
|
||||
* @dev: a VuDev context
|
||||
* @qidx: queue index
|
||||
*
|
||||
* Returns the queue number @qidx.
|
||||
*/
|
||||
VuVirtq *vu_get_queue(VuDev *dev, int qidx);
|
||||
|
||||
/**
|
||||
* vu_set_queue_handler:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @handler: the queue handler callback
|
||||
*
|
||||
* Set the queue handler. This function may be called several times
|
||||
* for the same queue. If called with NULL @handler, the handler is
|
||||
* removed.
|
||||
*/
|
||||
void vu_set_queue_handler(VuDev *dev, VuVirtq *vq,
|
||||
vu_queue_handler_cb handler);
|
||||
|
||||
|
||||
/**
|
||||
* vu_queue_set_notification:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @enable: state
|
||||
*
|
||||
* Set whether the queue notifies (via event index or interrupt)
|
||||
*/
|
||||
void vu_queue_set_notification(VuDev *dev, VuVirtq *vq, int enable);
|
||||
|
||||
/**
|
||||
* vu_queue_enabled:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
*
|
||||
* Returns: whether the queue is enabled.
|
||||
*/
|
||||
bool vu_queue_enabled(VuDev *dev, VuVirtq *vq);
|
||||
|
||||
/**
|
||||
* vu_queue_enabled:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
*
|
||||
* Returns: whether the queue is empty.
|
||||
*/
|
||||
int vu_queue_empty(VuDev *dev, VuVirtq *vq);
|
||||
|
||||
/**
|
||||
* vu_queue_notify:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
*
|
||||
* Request to notify the queue via callfd (skipped if unnecessary)
|
||||
*/
|
||||
void vu_queue_notify(VuDev *dev, VuVirtq *vq);
|
||||
|
||||
/**
|
||||
* vu_queue_pop:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @sz: the size of struct to return (must be >= VuVirtqElement)
|
||||
*
|
||||
* Returns: a VuVirtqElement filled from the queue or NULL.
|
||||
*/
|
||||
void *vu_queue_pop(VuDev *dev, VuVirtq *vq, size_t sz);
|
||||
|
||||
/**
|
||||
* vu_queue_rewind:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @num: number of elements to push back
|
||||
*
|
||||
* Pretend that elements weren't popped from the virtqueue. The next
|
||||
* virtqueue_pop() will refetch the oldest element.
|
||||
*
|
||||
* Returns: true on success, false if @num is greater than the number of in use
|
||||
* elements.
|
||||
*/
|
||||
bool vu_queue_rewind(VuDev *dev, VuVirtq *vq, unsigned int num);
|
||||
|
||||
/**
|
||||
* vu_queue_fill:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @elem: a VuVirtqElement
|
||||
* @len: length in bytes to write
|
||||
* @idx: optional offset for the used ring index (0 in general)
|
||||
*
|
||||
* Fill the used ring with @elem element.
|
||||
*/
|
||||
void vu_queue_fill(VuDev *dev, VuVirtq *vq,
|
||||
const VuVirtqElement *elem,
|
||||
unsigned int len, unsigned int idx);
|
||||
|
||||
/**
|
||||
* vu_queue_push:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @elem: a VuVirtqElement
|
||||
* @len: length in bytes to write
|
||||
*
|
||||
* Helper that combines vu_queue_fill() with a vu_queue_flush().
|
||||
*/
|
||||
void vu_queue_push(VuDev *dev, VuVirtq *vq,
|
||||
const VuVirtqElement *elem, unsigned int len);
|
||||
|
||||
/**
|
||||
* vu_queue_flush:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @num: number of elements to flush
|
||||
*
|
||||
* Mark the last number of elements as done (used.idx is updated by
|
||||
* num elements).
|
||||
*/
|
||||
void vu_queue_flush(VuDev *dev, VuVirtq *vq, unsigned int num);
|
||||
|
||||
/**
|
||||
* vu_queue_get_avail_bytes:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @in_bytes: in bytes
|
||||
* @out_bytes: out bytes
|
||||
* @max_in_bytes: stop counting after max_in_bytes
|
||||
* @max_out_bytes: stop counting after max_out_bytes
|
||||
*
|
||||
* Count the number of available bytes, up to max_in_bytes/max_out_bytes.
|
||||
*/
|
||||
void vu_queue_get_avail_bytes(VuDev *vdev, VuVirtq *vq, unsigned int *in_bytes,
|
||||
unsigned int *out_bytes,
|
||||
unsigned max_in_bytes, unsigned max_out_bytes);
|
||||
|
||||
/**
|
||||
* vu_queue_avail_bytes:
|
||||
* @dev: a VuDev context
|
||||
* @vq: a VuVirtq queue
|
||||
* @in_bytes: expected in bytes
|
||||
* @out_bytes: expected out bytes
|
||||
*
|
||||
* Returns: true if in_bytes <= in_total && out_bytes <= out_total
|
||||
*/
|
||||
bool vu_queue_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int in_bytes,
|
||||
unsigned int out_bytes);
|
||||
|
||||
#endif /* LIBVHOST_USER_H */
|
@@ -110,18 +110,18 @@ Plug only PCI Express devices into PCI Express Ports.
|
||||
-device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
|
||||
-device <dev>,bus=root_port1
|
||||
2.2.2 Using multi-function PCI Express Root Ports:
|
||||
-device ioh3420,id=root_port1,multifunction=on,chassis=x,slot=y[,bus=pcie.0][,addr=z.0] \
|
||||
-device ioh3420,id=root_port2,chassis=x1,slot=y1[,bus=pcie.0][,addr=z.1] \
|
||||
-device ioh3420,id=root_port3,chassis=x2,slot=y2[,bus=pcie.0][,addr=z.2] \
|
||||
2.2.2 Plugging a PCI Express device into a Switch:
|
||||
-device ioh3420,id=root_port1,multifunction=on,chassis=x,addr=z.0[,slot=y][,bus=pcie.0] \
|
||||
-device ioh3420,id=root_port2,chassis=x1,addr=z.1[,slot=y1][,bus=pcie.0] \
|
||||
-device ioh3420,id=root_port3,chassis=x2,addr=z.2[,slot=y2][,bus=pcie.0] \
|
||||
2.2.3 Plugging a PCI Express device into a Switch:
|
||||
-device ioh3420,id=root_port1,chassis=x,slot=y[,bus=pcie.0][,addr=z] \
|
||||
-device x3130-upstream,id=upstream_port1,bus=root_port1[,addr=x] \
|
||||
-device xio3130-downstream,id=downstream_port1,bus=upstream_port1,chassis=x1,slot=y1[,addr=z1]] \
|
||||
-device <dev>,bus=downstream_port1
|
||||
|
||||
Notes:
|
||||
- (slot, chassis) pair is mandatory and must be
|
||||
unique for each PCI Express Root Port.
|
||||
- (slot, chassis) pair is mandatory and must be unique for each
|
||||
PCI Express Root Port. slot defaults to 0 when not specified.
|
||||
- 'addr' parameter can be 0 for all the examples above.
|
||||
|
||||
|
||||
|
@@ -195,3 +195,17 @@ Queue is flushed at checkpoints and information about processed requests
|
||||
is recorded to the log. In replay phase the queue is matched with
|
||||
events read from the log. Therefore block devices requests are processed
|
||||
deterministically.
|
||||
|
||||
Network devices
|
||||
---------------
|
||||
|
||||
Record and replay for network interactions is performed with the network filter.
|
||||
Each backend must have its own instance of the replay filter as follows:
|
||||
-netdev user,id=net1 -device rtl8139,netdev=net1
|
||||
-object filter-replay,id=replay,netdev=net1
|
||||
|
||||
Replay network filter is used to record and replay network packets. While
|
||||
recording the virtual machine this filter puts all packets coming from
|
||||
the outer world into the log. In replay mode packets from the log are
|
||||
injected into the network device. All interactions with network backend
|
||||
in replay mode are disabled.
|
||||
|
@@ -259,6 +259,7 @@ Protocol features
|
||||
#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1
|
||||
#define VHOST_USER_PROTOCOL_F_RARP 2
|
||||
#define VHOST_USER_PROTOCOL_F_REPLY_ACK 3
|
||||
#define VHOST_USER_PROTOCOL_F_MTU 4
|
||||
|
||||
Message types
|
||||
-------------
|
||||
@@ -470,6 +471,21 @@ Message types
|
||||
The first 6 bytes of the payload contain the mac address of the guest to
|
||||
allow the vhost user backend to construct and broadcast the fake RARP.
|
||||
|
||||
* VHOST_USER_NET_SET_MTU
|
||||
|
||||
Id: 20
|
||||
Equivalent ioctl: N/A
|
||||
Master payload: u64
|
||||
|
||||
Set host MTU value exposed to the guest.
|
||||
This request should be sent only when VIRTIO_NET_F_MTU feature has been
|
||||
successfully negotiated, VHOST_USER_F_PROTOCOL_FEATURES is present in
|
||||
VHOST_USER_GET_FEATURES and protocol feature bit
|
||||
VHOST_USER_PROTOCOL_F_NET_MTU is present in
|
||||
VHOST_USER_GET_PROTOCOL_FEATURES.
|
||||
If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated, slave must respond
|
||||
with zero in case the specified MTU is valid, or non-zero otherwise.
|
||||
|
||||
VHOST_USER_PROTOCOL_F_REPLY_ACK:
|
||||
-------------------------------
|
||||
The original vhost-user specification only demands replies for certain
|
||||
|
33
exec.c
33
exec.c
@@ -448,6 +448,39 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
|
||||
return section;
|
||||
}
|
||||
|
||||
/* Called from RCU critical section */
|
||||
IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
|
||||
bool is_write)
|
||||
{
|
||||
IOMMUTLBEntry iotlb = {0};
|
||||
MemoryRegionSection *section;
|
||||
MemoryRegion *mr;
|
||||
|
||||
for (;;) {
|
||||
AddressSpaceDispatch *d = atomic_rcu_read(&as->dispatch);
|
||||
section = address_space_lookup_region(d, addr, false);
|
||||
addr = addr - section->offset_within_address_space
|
||||
+ section->offset_within_region;
|
||||
mr = section->mr;
|
||||
|
||||
if (!mr->iommu_ops) {
|
||||
break;
|
||||
}
|
||||
|
||||
iotlb = mr->iommu_ops->translate(mr, addr, is_write);
|
||||
if (!(iotlb.perm & (1 << is_write))) {
|
||||
iotlb.target_as = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
|
||||
| (addr & iotlb.addr_mask));
|
||||
as = iotlb.target_as;
|
||||
}
|
||||
|
||||
return iotlb;
|
||||
}
|
||||
|
||||
/* Called from RCU critical section */
|
||||
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
hwaddr *xlat, hwaddr *plen,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o
|
||||
common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o
|
||||
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o
|
||||
common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o
|
||||
common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
|
||||
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
|
||||
common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
|
||||
common-obj-$(CONFIG_ACPI) += acpi_interface.o
|
||||
|
@@ -306,7 +306,8 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
||||
|
||||
if (pm->acpi_memory_hotplug.is_enabled) {
|
||||
acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
|
||||
&pm->acpi_memory_hotplug);
|
||||
&pm->acpi_memory_hotplug,
|
||||
ACPI_MEMORY_HOTPLUG_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -7,6 +7,34 @@
|
||||
#include "trace.h"
|
||||
#include "qapi-event.h"
|
||||
|
||||
#define MEMORY_SLOTS_NUMBER "MDNR"
|
||||
#define MEMORY_HOTPLUG_IO_REGION "HPMR"
|
||||
#define MEMORY_SLOT_ADDR_LOW "MRBL"
|
||||
#define MEMORY_SLOT_ADDR_HIGH "MRBH"
|
||||
#define MEMORY_SLOT_SIZE_LOW "MRLL"
|
||||
#define MEMORY_SLOT_SIZE_HIGH "MRLH"
|
||||
#define MEMORY_SLOT_PROXIMITY "MPX"
|
||||
#define MEMORY_SLOT_ENABLED "MES"
|
||||
#define MEMORY_SLOT_INSERT_EVENT "MINS"
|
||||
#define MEMORY_SLOT_REMOVE_EVENT "MRMV"
|
||||
#define MEMORY_SLOT_EJECT "MEJ"
|
||||
#define MEMORY_SLOT_SLECTOR "MSEL"
|
||||
#define MEMORY_SLOT_OST_EVENT "MOEV"
|
||||
#define MEMORY_SLOT_OST_STATUS "MOSC"
|
||||
#define MEMORY_SLOT_LOCK "MLCK"
|
||||
#define MEMORY_SLOT_STATUS_METHOD "MRST"
|
||||
#define MEMORY_SLOT_CRS_METHOD "MCRS"
|
||||
#define MEMORY_SLOT_OST_METHOD "MOST"
|
||||
#define MEMORY_SLOT_PROXIMITY_METHOD "MPXM"
|
||||
#define MEMORY_SLOT_EJECT_METHOD "MEJ0"
|
||||
#define MEMORY_SLOT_NOTIFY_METHOD "MTFY"
|
||||
#define MEMORY_SLOT_SCAN_METHOD "MSCN"
|
||||
#define MEMORY_HOTPLUG_DEVICE "MHPD"
|
||||
#define MEMORY_HOTPLUG_IO_LEN 24
|
||||
#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC"
|
||||
|
||||
static uint16_t memhp_io_base;
|
||||
|
||||
static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev)
|
||||
{
|
||||
ACPIOSTInfo *info = g_new0(ACPIOSTInfo, 1);
|
||||
@@ -178,7 +206,7 @@ static const MemoryRegionOps acpi_memory_hotplug_ops = {
|
||||
};
|
||||
|
||||
void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
|
||||
MemHotplugState *state)
|
||||
MemHotplugState *state, uint16_t io_base)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
|
||||
@@ -187,10 +215,12 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!memhp_io_base);
|
||||
memhp_io_base = io_base;
|
||||
state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count);
|
||||
memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state,
|
||||
"acpi-mem-hotplug", ACPI_MEMORY_HOTPLUG_IO_LEN);
|
||||
memory_region_add_subregion(as, ACPI_MEMORY_HOTPLUG_BASE, &state->io);
|
||||
"acpi-mem-hotplug", MEMORY_HOTPLUG_IO_LEN);
|
||||
memory_region_add_subregion(as, memhp_io_base, &state->io);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -306,3 +336,387 @@ const VMStateDescription vmstate_memory_hotplug = {
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
|
||||
const char *res_root,
|
||||
const char *event_handler_method)
|
||||
{
|
||||
int i;
|
||||
Aml *ifctx;
|
||||
Aml *method;
|
||||
Aml *dev_container;
|
||||
Aml *mem_ctrl_dev;
|
||||
char *mhp_res_path;
|
||||
|
||||
if (!memhp_io_base) {
|
||||
return;
|
||||
}
|
||||
|
||||
mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root);
|
||||
mem_ctrl_dev = aml_device("%s", mhp_res_path);
|
||||
{
|
||||
Aml *crs;
|
||||
|
||||
aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06")));
|
||||
aml_append(mem_ctrl_dev,
|
||||
aml_name_decl("_UID", aml_string("Memory hotplug resources")));
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs,
|
||||
aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0,
|
||||
MEMORY_HOTPLUG_IO_LEN)
|
||||
);
|
||||
aml_append(mem_ctrl_dev, aml_name_decl("_CRS", crs));
|
||||
|
||||
aml_append(mem_ctrl_dev, aml_operation_region(
|
||||
MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO,
|
||||
aml_int(memhp_io_base), MEMORY_HOTPLUG_IO_LEN)
|
||||
);
|
||||
|
||||
}
|
||||
aml_append(table, mem_ctrl_dev);
|
||||
|
||||
dev_container = aml_device(MEMORY_DEVICES_CONTAINER);
|
||||
{
|
||||
Aml *field;
|
||||
Aml *one = aml_int(1);
|
||||
Aml *zero = aml_int(0);
|
||||
Aml *ret_val = aml_local(0);
|
||||
Aml *slot_arg0 = aml_arg(0);
|
||||
Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER);
|
||||
Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK);
|
||||
Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR);
|
||||
char *mmio_path = g_strdup_printf("%s." MEMORY_HOTPLUG_IO_REGION,
|
||||
mhp_res_path);
|
||||
|
||||
aml_append(dev_container, aml_name_decl("_HID", aml_string("PNP0A06")));
|
||||
aml_append(dev_container,
|
||||
aml_name_decl("_UID", aml_string("DIMM devices")));
|
||||
|
||||
assert(nr_mem <= ACPI_MAX_RAM_SLOTS);
|
||||
aml_append(dev_container,
|
||||
aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem))
|
||||
);
|
||||
|
||||
field = aml_field(mmio_path, AML_DWORD_ACC,
|
||||
AML_NOLOCK, AML_PRESERVE);
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_ADDR_LOW, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_SIZE_LOW, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_PROXIMITY, 32));
|
||||
aml_append(dev_container, field);
|
||||
|
||||
field = aml_field(mmio_path, AML_BYTE_ACC,
|
||||
AML_NOLOCK, AML_WRITE_AS_ZEROS);
|
||||
aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
|
||||
aml_append(field, /* 1 if enabled, read only */
|
||||
aml_named_field(MEMORY_SLOT_ENABLED, 1));
|
||||
aml_append(field,
|
||||
/*(read) 1 if has a insert event. (write) 1 to clear event */
|
||||
aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1));
|
||||
aml_append(field,
|
||||
/* (read) 1 if has a remove event. (write) 1 to clear event */
|
||||
aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1));
|
||||
aml_append(field,
|
||||
/* initiates device eject, write only */
|
||||
aml_named_field(MEMORY_SLOT_EJECT, 1));
|
||||
aml_append(dev_container, field);
|
||||
|
||||
field = aml_field(mmio_path, AML_DWORD_ACC,
|
||||
AML_NOLOCK, AML_PRESERVE);
|
||||
aml_append(field, /* DIMM selector, write only */
|
||||
aml_named_field(MEMORY_SLOT_SLECTOR, 32));
|
||||
aml_append(field, /* _OST event code, write only */
|
||||
aml_named_field(MEMORY_SLOT_OST_EVENT, 32));
|
||||
aml_append(field, /* _OST status code, write only */
|
||||
aml_named_field(MEMORY_SLOT_OST_STATUS, 32));
|
||||
aml_append(dev_container, field);
|
||||
g_free(mmio_path);
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
ifctx = aml_if(aml_equal(slots_nr, zero));
|
||||
{
|
||||
aml_append(ifctx, aml_return(zero));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
/* present, functioning, decoding, not shown in UI */
|
||||
aml_append(method, aml_return(aml_int(0xB)));
|
||||
aml_append(dev_container, method);
|
||||
|
||||
aml_append(dev_container, aml_mutex(MEMORY_SLOT_LOCK, 0));
|
||||
|
||||
method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *else_ctx;
|
||||
Aml *while_ctx;
|
||||
Aml *idx = aml_local(0);
|
||||
Aml *eject_req = aml_int(3);
|
||||
Aml *dev_chk = aml_int(1);
|
||||
|
||||
ifctx = aml_if(aml_equal(slots_nr, zero));
|
||||
{
|
||||
aml_append(ifctx, aml_return(zero));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_store(zero, idx));
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
/* build AML that:
|
||||
* loops over all slots and Notifies DIMMs with
|
||||
* Device Check or Eject Request notifications if
|
||||
* slot has corresponding status bit set and clears
|
||||
* slot status.
|
||||
*/
|
||||
while_ctx = aml_while(aml_lless(idx, slots_nr));
|
||||
{
|
||||
Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT);
|
||||
Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT);
|
||||
|
||||
aml_append(while_ctx, aml_store(idx, slot_selector));
|
||||
ifctx = aml_if(aml_equal(ins_evt, one));
|
||||
{
|
||||
aml_append(ifctx,
|
||||
aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
|
||||
idx, dev_chk));
|
||||
aml_append(ifctx, aml_store(one, ins_evt));
|
||||
}
|
||||
aml_append(while_ctx, ifctx);
|
||||
|
||||
else_ctx = aml_else();
|
||||
ifctx = aml_if(aml_equal(rm_evt, one));
|
||||
{
|
||||
aml_append(ifctx,
|
||||
aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
|
||||
idx, eject_req));
|
||||
aml_append(ifctx, aml_store(one, rm_evt));
|
||||
}
|
||||
aml_append(else_ctx, ifctx);
|
||||
aml_append(while_ctx, else_ctx);
|
||||
|
||||
aml_append(while_ctx, aml_add(idx, one, idx));
|
||||
}
|
||||
aml_append(method, while_ctx);
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(one));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED);
|
||||
|
||||
aml_append(method, aml_store(zero, ret_val));
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method,
|
||||
aml_store(aml_to_integer(slot_arg0), slot_selector));
|
||||
|
||||
ifctx = aml_if(aml_equal(slot_enabled, one));
|
||||
{
|
||||
aml_append(ifctx, aml_store(aml_int(0xF), ret_val));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(ret_val));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED);
|
||||
{
|
||||
Aml *mr64 = aml_name("MR64");
|
||||
Aml *mr32 = aml_name("MR32");
|
||||
Aml *crs_tmpl = aml_resource_template();
|
||||
Aml *minl = aml_name("MINL");
|
||||
Aml *minh = aml_name("MINH");
|
||||
Aml *maxl = aml_name("MAXL");
|
||||
Aml *maxh = aml_name("MAXH");
|
||||
Aml *lenl = aml_name("LENL");
|
||||
Aml *lenh = aml_name("LENH");
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
|
||||
aml_append(crs_tmpl,
|
||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_CACHEABLE, AML_READ_WRITE,
|
||||
0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0,
|
||||
0xFFFFFFFFFFFFFFFFULL));
|
||||
aml_append(method, aml_name_decl("MR64", crs_tmpl));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(14), "MINL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(18), "MINH"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(38), "LENL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(42), "LENH"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(22), "MAXL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(26), "MAXH"));
|
||||
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl));
|
||||
|
||||
/* 64-bit math: MAX = MIN + LEN - 1 */
|
||||
aml_append(method, aml_add(minl, lenl, maxl));
|
||||
aml_append(method, aml_add(minh, lenh, maxh));
|
||||
ifctx = aml_if(aml_lless(maxl, minl));
|
||||
{
|
||||
aml_append(ifctx, aml_add(maxh, one, maxh));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
ifctx = aml_if(aml_lless(maxl, one));
|
||||
{
|
||||
aml_append(ifctx, aml_subtract(maxh, one, maxh));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
aml_append(method, aml_subtract(maxl, one, maxl));
|
||||
|
||||
/* return 32-bit _CRS if addr/size is in low mem */
|
||||
/* TODO: remove it since all hotplugged DIMMs are in high mem */
|
||||
ifctx = aml_if(aml_equal(maxh, zero));
|
||||
{
|
||||
crs_tmpl = aml_resource_template();
|
||||
aml_append(crs_tmpl,
|
||||
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||
AML_MAX_FIXED, AML_CACHEABLE,
|
||||
AML_READ_WRITE,
|
||||
0, 0x0, 0xFFFFFFFE, 0,
|
||||
0xFFFFFFFF));
|
||||
aml_append(ifctx, aml_name_decl("MR32", crs_tmpl));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(10), "MIN"));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(14), "MAX"));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(22), "LEN"));
|
||||
aml_append(ifctx, aml_store(minl, aml_name("MIN")));
|
||||
aml_append(ifctx, aml_store(maxl, aml_name("MAX")));
|
||||
aml_append(ifctx, aml_store(lenl, aml_name("LEN")));
|
||||
|
||||
aml_append(ifctx, aml_release(ctrl_lock));
|
||||
aml_append(ifctx, aml_return(mr32));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(mr64));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1,
|
||||
AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(proximity, ret_val));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(ret_val));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT);
|
||||
Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(aml_arg(1), ost_evt));
|
||||
aml_append(method, aml_store(aml_arg(2), ost_status));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *eject = aml_name(MEMORY_SLOT_EJECT);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(one, eject));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
|
||||
/* build memory devices */
|
||||
for (i = 0; i < nr_mem; i++) {
|
||||
Aml *dev;
|
||||
const char *s;
|
||||
|
||||
dev = aml_device("MP%02X", i);
|
||||
aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i)));
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80")));
|
||||
|
||||
method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_CRS_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_STATUS_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_PXM", 0, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_PROXIMITY_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_OST", 3, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_OST_METHOD;
|
||||
aml_append(method, aml_return(aml_call4(
|
||||
s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2)
|
||||
)));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
|
||||
s = MEMORY_SLOT_EJECT_METHOD;
|
||||
aml_append(method, aml_return(aml_call2(
|
||||
s, aml_name("_UID"), aml_arg(0))));
|
||||
aml_append(dev, method);
|
||||
|
||||
aml_append(dev_container, dev);
|
||||
}
|
||||
|
||||
/* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
|
||||
* If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... }
|
||||
*/
|
||||
method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED);
|
||||
for (i = 0; i < nr_mem; i++) {
|
||||
ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i)));
|
||||
aml_append(ifctx,
|
||||
aml_notify(aml_name("MP%.02X", i), aml_arg(1))
|
||||
);
|
||||
aml_append(method, ifctx);
|
||||
}
|
||||
aml_append(dev_container, method);
|
||||
}
|
||||
aml_append(table, dev_container);
|
||||
|
||||
method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
|
||||
aml_append(method,
|
||||
aml_call0(MEMORY_DEVICES_CONTAINER "." MEMORY_SLOT_SCAN_METHOD));
|
||||
aml_append(table, method);
|
||||
|
||||
g_free(mhp_res_path);
|
||||
}
|
||||
|
@@ -1,262 +0,0 @@
|
||||
/*
|
||||
* Memory hotplug AML code of DSDT ACPI table
|
||||
*
|
||||
* Copyright (C) 2015 Red Hat Inc
|
||||
*
|
||||
* Author: Igor Mammedov <imammedo@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/acpi/memory_hotplug.h"
|
||||
#include "include/hw/acpi/pc-hotplug.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem,
|
||||
uint16_t io_base, uint16_t io_len)
|
||||
{
|
||||
Aml *ifctx;
|
||||
Aml *method;
|
||||
Aml *pci_scope;
|
||||
Aml *mem_ctrl_dev;
|
||||
|
||||
/* scope for memory hotplug controller device node */
|
||||
pci_scope = aml_scope("_SB.PCI0");
|
||||
mem_ctrl_dev = aml_device(MEMORY_HOTPLUG_DEVICE);
|
||||
{
|
||||
Aml *one = aml_int(1);
|
||||
Aml *zero = aml_int(0);
|
||||
Aml *ret_val = aml_local(0);
|
||||
Aml *slot_arg0 = aml_arg(0);
|
||||
Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER);
|
||||
Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK);
|
||||
Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR);
|
||||
|
||||
aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06")));
|
||||
aml_append(mem_ctrl_dev,
|
||||
aml_name_decl("_UID", aml_string("Memory hotplug resources")));
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
ifctx = aml_if(aml_equal(slots_nr, zero));
|
||||
{
|
||||
aml_append(ifctx, aml_return(zero));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
/* present, functioning, decoding, not shown in UI */
|
||||
aml_append(method, aml_return(aml_int(0xB)));
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
aml_append(mem_ctrl_dev, aml_mutex(MEMORY_SLOT_LOCK, 0));
|
||||
|
||||
method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *else_ctx;
|
||||
Aml *while_ctx;
|
||||
Aml *idx = aml_local(0);
|
||||
Aml *eject_req = aml_int(3);
|
||||
Aml *dev_chk = aml_int(1);
|
||||
|
||||
ifctx = aml_if(aml_equal(slots_nr, zero));
|
||||
{
|
||||
aml_append(ifctx, aml_return(zero));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_store(zero, idx));
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
/* build AML that:
|
||||
* loops over all slots and Notifies DIMMs with
|
||||
* Device Check or Eject Request notifications if
|
||||
* slot has corresponding status bit set and clears
|
||||
* slot status.
|
||||
*/
|
||||
while_ctx = aml_while(aml_lless(idx, slots_nr));
|
||||
{
|
||||
Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT);
|
||||
Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT);
|
||||
|
||||
aml_append(while_ctx, aml_store(idx, slot_selector));
|
||||
ifctx = aml_if(aml_equal(ins_evt, one));
|
||||
{
|
||||
aml_append(ifctx,
|
||||
aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
|
||||
idx, dev_chk));
|
||||
aml_append(ifctx, aml_store(one, ins_evt));
|
||||
}
|
||||
aml_append(while_ctx, ifctx);
|
||||
|
||||
else_ctx = aml_else();
|
||||
ifctx = aml_if(aml_equal(rm_evt, one));
|
||||
{
|
||||
aml_append(ifctx,
|
||||
aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
|
||||
idx, eject_req));
|
||||
aml_append(ifctx, aml_store(one, rm_evt));
|
||||
}
|
||||
aml_append(else_ctx, ifctx);
|
||||
aml_append(while_ctx, else_ctx);
|
||||
|
||||
aml_append(while_ctx, aml_add(idx, one, idx));
|
||||
}
|
||||
aml_append(method, while_ctx);
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(one));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED);
|
||||
|
||||
aml_append(method, aml_store(zero, ret_val));
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method,
|
||||
aml_store(aml_to_integer(slot_arg0), slot_selector));
|
||||
|
||||
ifctx = aml_if(aml_equal(slot_enabled, one));
|
||||
{
|
||||
aml_append(ifctx, aml_store(aml_int(0xF), ret_val));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(ret_val));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED);
|
||||
{
|
||||
Aml *mr64 = aml_name("MR64");
|
||||
Aml *mr32 = aml_name("MR32");
|
||||
Aml *crs_tmpl = aml_resource_template();
|
||||
Aml *minl = aml_name("MINL");
|
||||
Aml *minh = aml_name("MINH");
|
||||
Aml *maxl = aml_name("MAXL");
|
||||
Aml *maxh = aml_name("MAXH");
|
||||
Aml *lenl = aml_name("LENL");
|
||||
Aml *lenh = aml_name("LENH");
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
|
||||
aml_append(crs_tmpl,
|
||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_CACHEABLE, AML_READ_WRITE,
|
||||
0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0,
|
||||
0xFFFFFFFFFFFFFFFFULL));
|
||||
aml_append(method, aml_name_decl("MR64", crs_tmpl));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(14), "MINL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(18), "MINH"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(38), "LENL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(42), "LENH"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(22), "MAXL"));
|
||||
aml_append(method,
|
||||
aml_create_dword_field(mr64, aml_int(26), "MAXH"));
|
||||
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh));
|
||||
aml_append(method,
|
||||
aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl));
|
||||
|
||||
/* 64-bit math: MAX = MIN + LEN - 1 */
|
||||
aml_append(method, aml_add(minl, lenl, maxl));
|
||||
aml_append(method, aml_add(minh, lenh, maxh));
|
||||
ifctx = aml_if(aml_lless(maxl, minl));
|
||||
{
|
||||
aml_append(ifctx, aml_add(maxh, one, maxh));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
ifctx = aml_if(aml_lless(maxl, one));
|
||||
{
|
||||
aml_append(ifctx, aml_subtract(maxh, one, maxh));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
aml_append(method, aml_subtract(maxl, one, maxl));
|
||||
|
||||
/* return 32-bit _CRS if addr/size is in low mem */
|
||||
/* TODO: remove it since all hotplugged DIMMs are in high mem */
|
||||
ifctx = aml_if(aml_equal(maxh, zero));
|
||||
{
|
||||
crs_tmpl = aml_resource_template();
|
||||
aml_append(crs_tmpl,
|
||||
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||
AML_MAX_FIXED, AML_CACHEABLE,
|
||||
AML_READ_WRITE,
|
||||
0, 0x0, 0xFFFFFFFE, 0,
|
||||
0xFFFFFFFF));
|
||||
aml_append(ifctx, aml_name_decl("MR32", crs_tmpl));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(10), "MIN"));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(14), "MAX"));
|
||||
aml_append(ifctx,
|
||||
aml_create_dword_field(mr32, aml_int(22), "LEN"));
|
||||
aml_append(ifctx, aml_store(minl, aml_name("MIN")));
|
||||
aml_append(ifctx, aml_store(maxl, aml_name("MAX")));
|
||||
aml_append(ifctx, aml_store(lenl, aml_name("LEN")));
|
||||
|
||||
aml_append(ifctx, aml_release(ctrl_lock));
|
||||
aml_append(ifctx, aml_return(mr32));
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(mr64));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1,
|
||||
AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(proximity, ret_val));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
aml_append(method, aml_return(ret_val));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT);
|
||||
Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(aml_arg(1), ost_evt));
|
||||
aml_append(method, aml_store(aml_arg(2), ost_status));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
|
||||
method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED);
|
||||
{
|
||||
Aml *eject = aml_name(MEMORY_SLOT_EJECT);
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(aml_to_integer(slot_arg0),
|
||||
slot_selector));
|
||||
aml_append(method, aml_store(one, eject));
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
}
|
||||
aml_append(mem_ctrl_dev, method);
|
||||
}
|
||||
aml_append(pci_scope, mem_ctrl_dev);
|
||||
aml_append(ctx, pci_scope);
|
||||
}
|
@@ -644,7 +644,8 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
|
||||
PIIX4_CPU_HOTPLUG_IO_BASE);
|
||||
|
||||
if (s->acpi_memory_hotplug.is_enabled) {
|
||||
acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug);
|
||||
acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug,
|
||||
ACPI_MEMORY_HOTPLUG_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1258,7 +1258,7 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s)
|
||||
}
|
||||
|
||||
/* These are only stubs now. */
|
||||
static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
|
||||
PXA2xxI2CState *s = slave->host;
|
||||
@@ -1280,6 +1280,8 @@ static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
break;
|
||||
}
|
||||
pxa2xx_i2c_update(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa2xx_i2c_rx(I2CSlave *i2c)
|
||||
|
@@ -172,7 +172,7 @@ static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
TosaDACState *s = TOSA_DAC(i2c);
|
||||
|
||||
@@ -194,6 +194,8 @@ static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tosa_dac_recv(I2CSlave *s)
|
||||
|
@@ -29,7 +29,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/arm/virt-acpi-build.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "trace.h"
|
||||
#include "qom/cpu.h"
|
||||
@@ -43,6 +42,7 @@
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/arm/virt.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "kvm_arm.h"
|
||||
|
||||
@@ -384,7 +384,7 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
|
||||
}
|
||||
|
||||
static void
|
||||
build_iort(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_iort(GArray *table_data, BIOSLinker *linker)
|
||||
{
|
||||
int iort_start = table_data->len;
|
||||
AcpiIortIdMapping *idmap;
|
||||
@@ -439,11 +439,11 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
}
|
||||
|
||||
static void
|
||||
build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
AcpiSerialPortConsoleRedirection *spcr;
|
||||
const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART];
|
||||
int irq = guest_info->irqmap[VIRT_UART] + ARM_SPI_BASE;
|
||||
const MemMapEntry *uart_memmap = &vms->memmap[VIRT_UART];
|
||||
int irq = vms->irqmap[VIRT_UART] + ARM_SPI_BASE;
|
||||
|
||||
spcr = acpi_data_push(table_data, sizeof(*spcr));
|
||||
|
||||
@@ -472,16 +472,16 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
}
|
||||
|
||||
static void
|
||||
build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
AcpiSystemResourceAffinityTable *srat;
|
||||
AcpiSratProcessorGiccAffinity *core;
|
||||
AcpiSratMemoryAffinity *numamem;
|
||||
int i, j, srat_start;
|
||||
uint64_t mem_base;
|
||||
uint32_t *cpu_node = g_malloc0(guest_info->smp_cpus * sizeof(uint32_t));
|
||||
uint32_t *cpu_node = g_malloc0(vms->smp_cpus * sizeof(uint32_t));
|
||||
|
||||
for (i = 0; i < guest_info->smp_cpus; i++) {
|
||||
for (i = 0; i < vms->smp_cpus; i++) {
|
||||
j = numa_get_node_for_cpu(i);
|
||||
if (j < nb_numa_nodes) {
|
||||
cpu_node[i] = j;
|
||||
@@ -492,7 +492,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
srat = acpi_data_push(table_data, sizeof(*srat));
|
||||
srat->reserved1 = cpu_to_le32(1);
|
||||
|
||||
for (i = 0; i < guest_info->smp_cpus; ++i) {
|
||||
for (i = 0; i < vms->smp_cpus; ++i) {
|
||||
core = acpi_data_push(table_data, sizeof(*core));
|
||||
core->type = ACPI_SRAT_PROCESSOR_GICC;
|
||||
core->length = sizeof(*core);
|
||||
@@ -502,7 +502,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
}
|
||||
g_free(cpu_node);
|
||||
|
||||
mem_base = guest_info->memmap[VIRT_MEM].base;
|
||||
mem_base = vms->memmap[VIRT_MEM].base;
|
||||
for (i = 0; i < nb_numa_nodes; ++i) {
|
||||
numamem = acpi_data_push(table_data, sizeof(*numamem));
|
||||
build_srat_memory(numamem, mem_base, numa_info[i].node_mem, i,
|
||||
@@ -515,10 +515,10 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
}
|
||||
|
||||
static void
|
||||
build_mcfg(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
AcpiTableMcfg *mcfg;
|
||||
const MemMapEntry *memmap = guest_info->memmap;
|
||||
const MemMapEntry *memmap = vms->memmap;
|
||||
int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]);
|
||||
|
||||
mcfg = acpi_data_push(table_data, len);
|
||||
@@ -535,24 +535,33 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
|
||||
/* GTDT */
|
||||
static void
|
||||
build_gtdt(GArray *table_data, BIOSLinker *linker)
|
||||
build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
|
||||
int gtdt_start = table_data->len;
|
||||
AcpiGenericTimerTable *gtdt;
|
||||
uint32_t irqflags;
|
||||
|
||||
if (vmc->claim_edge_triggered_timers) {
|
||||
irqflags = ACPI_GTDT_INTERRUPT_MODE_EDGE;
|
||||
} else {
|
||||
irqflags = ACPI_GTDT_INTERRUPT_MODE_LEVEL;
|
||||
}
|
||||
|
||||
gtdt = acpi_data_push(table_data, sizeof *gtdt);
|
||||
/* The interrupt values are the same with the device tree when adding 16 */
|
||||
gtdt->secure_el1_interrupt = ARCH_TIMER_S_EL1_IRQ + 16;
|
||||
gtdt->secure_el1_flags = ACPI_EDGE_SENSITIVE;
|
||||
gtdt->secure_el1_interrupt = cpu_to_le32(ARCH_TIMER_S_EL1_IRQ + 16);
|
||||
gtdt->secure_el1_flags = cpu_to_le32(irqflags);
|
||||
|
||||
gtdt->non_secure_el1_interrupt = ARCH_TIMER_NS_EL1_IRQ + 16;
|
||||
gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE | ACPI_GTDT_ALWAYS_ON;
|
||||
gtdt->non_secure_el1_interrupt = cpu_to_le32(ARCH_TIMER_NS_EL1_IRQ + 16);
|
||||
gtdt->non_secure_el1_flags = cpu_to_le32(irqflags |
|
||||
ACPI_GTDT_CAP_ALWAYS_ON);
|
||||
|
||||
gtdt->virtual_timer_interrupt = ARCH_TIMER_VIRT_IRQ + 16;
|
||||
gtdt->virtual_timer_flags = ACPI_EDGE_SENSITIVE;
|
||||
gtdt->virtual_timer_interrupt = cpu_to_le32(ARCH_TIMER_VIRT_IRQ + 16);
|
||||
gtdt->virtual_timer_flags = cpu_to_le32(irqflags);
|
||||
|
||||
gtdt->non_secure_el2_interrupt = ARCH_TIMER_NS_EL2_IRQ + 16;
|
||||
gtdt->non_secure_el2_flags = ACPI_EDGE_SENSITIVE;
|
||||
gtdt->non_secure_el2_interrupt = cpu_to_le32(ARCH_TIMER_NS_EL2_IRQ + 16);
|
||||
gtdt->non_secure_el2_flags = cpu_to_le32(irqflags);
|
||||
|
||||
build_header(linker, table_data,
|
||||
(void *)(table_data->data + gtdt_start), "GTDT",
|
||||
@@ -561,11 +570,12 @@ build_gtdt(GArray *table_data, BIOSLinker *linker)
|
||||
|
||||
/* MADT */
|
||||
static void
|
||||
build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
|
||||
int madt_start = table_data->len;
|
||||
const MemMapEntry *memmap = guest_info->memmap;
|
||||
const int *irqmap = guest_info->irqmap;
|
||||
const MemMapEntry *memmap = vms->memmap;
|
||||
const int *irqmap = vms->irqmap;
|
||||
AcpiMultipleApicTable *madt;
|
||||
AcpiMadtGenericDistributor *gicd;
|
||||
AcpiMadtGenericMsiFrame *gic_msi;
|
||||
@@ -576,30 +586,30 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
gicd = acpi_data_push(table_data, sizeof *gicd);
|
||||
gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR;
|
||||
gicd->length = sizeof(*gicd);
|
||||
gicd->base_address = memmap[VIRT_GIC_DIST].base;
|
||||
gicd->version = guest_info->gic_version;
|
||||
gicd->base_address = cpu_to_le64(memmap[VIRT_GIC_DIST].base);
|
||||
gicd->version = vms->gic_version;
|
||||
|
||||
for (i = 0; i < guest_info->smp_cpus; i++) {
|
||||
AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data,
|
||||
sizeof *gicc);
|
||||
for (i = 0; i < vms->smp_cpus; i++) {
|
||||
AcpiMadtGenericCpuInterface *gicc = acpi_data_push(table_data,
|
||||
sizeof(*gicc));
|
||||
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(i));
|
||||
|
||||
gicc->type = ACPI_APIC_GENERIC_INTERRUPT;
|
||||
gicc->type = ACPI_APIC_GENERIC_CPU_INTERFACE;
|
||||
gicc->length = sizeof(*gicc);
|
||||
if (guest_info->gic_version == 2) {
|
||||
gicc->base_address = memmap[VIRT_GIC_CPU].base;
|
||||
if (vms->gic_version == 2) {
|
||||
gicc->base_address = cpu_to_le64(memmap[VIRT_GIC_CPU].base);
|
||||
}
|
||||
gicc->cpu_interface_number = i;
|
||||
gicc->arm_mpidr = armcpu->mp_affinity;
|
||||
gicc->uid = i;
|
||||
gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
|
||||
gicc->cpu_interface_number = cpu_to_le32(i);
|
||||
gicc->arm_mpidr = cpu_to_le64(armcpu->mp_affinity);
|
||||
gicc->uid = cpu_to_le32(i);
|
||||
gicc->flags = cpu_to_le32(ACPI_MADT_GICC_ENABLED);
|
||||
|
||||
if (arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
|
||||
gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
|
||||
}
|
||||
}
|
||||
|
||||
if (guest_info->gic_version == 3) {
|
||||
if (vms->gic_version == 3) {
|
||||
AcpiMadtGenericTranslator *gic_its;
|
||||
AcpiMadtGenericRedistributor *gicr = acpi_data_push(table_data,
|
||||
sizeof *gicr);
|
||||
@@ -609,7 +619,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST].base);
|
||||
gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST].size);
|
||||
|
||||
if (its_class_name() && !guest_info->no_its) {
|
||||
if (its_class_name() && !vmc->no_its) {
|
||||
gic_its = acpi_data_push(table_data, sizeof *gic_its);
|
||||
gic_its->type = ACPI_APIC_GENERIC_TRANSLATOR;
|
||||
gic_its->length = sizeof(*gic_its);
|
||||
@@ -641,8 +651,8 @@ build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset)
|
||||
|
||||
/* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */
|
||||
fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI);
|
||||
fadt->arm_boot_flags = cpu_to_le16((1 << ACPI_FADT_ARM_USE_PSCI_G_0_2) |
|
||||
(1 << ACPI_FADT_ARM_PSCI_USE_HVC));
|
||||
fadt->arm_boot_flags = cpu_to_le16(ACPI_FADT_ARM_PSCI_COMPLIANT |
|
||||
ACPI_FADT_ARM_PSCI_USE_HVC);
|
||||
|
||||
/* ACPI v5.1 (fadt->revision.fadt->minor_revision) */
|
||||
fadt->minor_revision = 0x1;
|
||||
@@ -658,11 +668,11 @@ build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset)
|
||||
|
||||
/* DSDT */
|
||||
static void
|
||||
build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
{
|
||||
Aml *scope, *dsdt;
|
||||
const MemMapEntry *memmap = guest_info->memmap;
|
||||
const int *irqmap = guest_info->irqmap;
|
||||
const MemMapEntry *memmap = vms->memmap;
|
||||
const int *irqmap = vms->irqmap;
|
||||
|
||||
dsdt = init_aml_allocator();
|
||||
/* Reserve space for header */
|
||||
@@ -674,7 +684,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
* the RTC ACPI device at all when using UEFI.
|
||||
*/
|
||||
scope = aml_scope("\\_SB");
|
||||
acpi_dsdt_add_cpus(scope, guest_info->smp_cpus);
|
||||
acpi_dsdt_add_cpus(scope, vms->smp_cpus);
|
||||
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART],
|
||||
(irqmap[VIRT_UART] + ARM_SPI_BASE));
|
||||
acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]);
|
||||
@@ -682,7 +692,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
|
||||
acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO],
|
||||
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
|
||||
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
|
||||
guest_info->use_highmem);
|
||||
vms->highmem);
|
||||
acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
|
||||
(irqmap[VIRT_GPIO] + ARM_SPI_BASE));
|
||||
acpi_dsdt_add_power_button(scope);
|
||||
@@ -705,12 +715,12 @@ struct AcpiBuildState {
|
||||
MemoryRegion *linker_mr;
|
||||
/* Is table patched? */
|
||||
bool patched;
|
||||
VirtGuestInfo *guest_info;
|
||||
} AcpiBuildState;
|
||||
|
||||
static
|
||||
void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
|
||||
void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
||||
{
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
|
||||
GArray *table_offsets;
|
||||
unsigned dsdt, rsdt;
|
||||
GArray *tables_blob = tables->table_data;
|
||||
@@ -724,32 +734,32 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables)
|
||||
|
||||
/* DSDT is pointed to by FADT */
|
||||
dsdt = tables_blob->len;
|
||||
build_dsdt(tables_blob, tables->linker, guest_info);
|
||||
build_dsdt(tables_blob, tables->linker, vms);
|
||||
|
||||
/* FADT MADT GTDT MCFG SPCR pointed to by RSDT */
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_fadt(tables_blob, tables->linker, dsdt);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_madt(tables_blob, tables->linker, guest_info);
|
||||
build_madt(tables_blob, tables->linker, vms);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_gtdt(tables_blob, tables->linker);
|
||||
build_gtdt(tables_blob, tables->linker, vms);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_mcfg(tables_blob, tables->linker, guest_info);
|
||||
build_mcfg(tables_blob, tables->linker, vms);
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_spcr(tables_blob, tables->linker, guest_info);
|
||||
build_spcr(tables_blob, tables->linker, vms);
|
||||
|
||||
if (nb_numa_nodes > 0) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_srat(tables_blob, tables->linker, guest_info);
|
||||
build_srat(tables_blob, tables->linker, vms);
|
||||
}
|
||||
|
||||
if (its_class_name() && !guest_info->no_its) {
|
||||
if (its_class_name() && !vmc->no_its) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_iort(tables_blob, tables->linker, guest_info);
|
||||
build_iort(tables_blob, tables->linker);
|
||||
}
|
||||
|
||||
/* RSDT is pointed to by RSDP */
|
||||
@@ -788,13 +798,12 @@ static void virt_acpi_build_update(void *build_opaque)
|
||||
|
||||
acpi_build_tables_init(&tables);
|
||||
|
||||
virt_acpi_build(build_state->guest_info, &tables);
|
||||
virt_acpi_build(VIRT_MACHINE(qdev_get_machine()), &tables);
|
||||
|
||||
acpi_ram_update(build_state->table_mr, tables.table_data);
|
||||
acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
|
||||
acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
|
||||
|
||||
|
||||
acpi_build_tables_cleanup(&tables, true);
|
||||
}
|
||||
|
||||
@@ -822,12 +831,12 @@ static const VMStateDescription vmstate_virt_acpi_build = {
|
||||
},
|
||||
};
|
||||
|
||||
void virt_acpi_setup(VirtGuestInfo *guest_info)
|
||||
void virt_acpi_setup(VirtMachineState *vms)
|
||||
{
|
||||
AcpiBuildTables tables;
|
||||
AcpiBuildState *build_state;
|
||||
|
||||
if (!guest_info->fw_cfg) {
|
||||
if (!vms->fw_cfg) {
|
||||
trace_virt_acpi_setup();
|
||||
return;
|
||||
}
|
||||
@@ -838,10 +847,9 @@ void virt_acpi_setup(VirtGuestInfo *guest_info)
|
||||
}
|
||||
|
||||
build_state = g_malloc0(sizeof *build_state);
|
||||
build_state->guest_info = guest_info;
|
||||
|
||||
acpi_build_tables_init(&tables);
|
||||
virt_acpi_build(build_state->guest_info, &tables);
|
||||
virt_acpi_build(vms, &tables);
|
||||
|
||||
/* Now expose it all to Guest */
|
||||
build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
|
||||
@@ -853,8 +861,8 @@ void virt_acpi_setup(VirtGuestInfo *guest_info)
|
||||
acpi_add_rom_blob(build_state, tables.linker->cmd_blob,
|
||||
"etc/table-loader", 0);
|
||||
|
||||
fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
|
||||
tables.tcpalog->data, acpi_data_len(tables.tcpalog));
|
||||
fw_cfg_add_file(vms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data,
|
||||
acpi_data_len(tables.tcpalog));
|
||||
|
||||
build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
|
||||
ACPI_BUILD_RSDP_FILE, 0);
|
||||
|
687
hw/arm/virt.c
687
hw/arm/virt.c
File diff suppressed because it is too large
Load Diff
@@ -220,7 +220,7 @@ static int aer915_send(I2CSlave *i2c, uint8_t data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aer915_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int aer915_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
AER915State *s = AER915(i2c);
|
||||
|
||||
@@ -238,6 +238,8 @@ static void aer915_event(I2CSlave *i2c, enum i2c_event event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aer915_recv(I2CSlave *slave)
|
||||
|
@@ -1387,6 +1387,16 @@ static void ac97_realize(PCIDevice *dev, Error **errp)
|
||||
ac97_on_reset (&s->dev.qdev);
|
||||
}
|
||||
|
||||
static void ac97_exit(PCIDevice *dev)
|
||||
{
|
||||
AC97LinkState *s = DO_UPCAST(AC97LinkState, dev, dev);
|
||||
|
||||
AUD_close_in(&s->card, s->voice_pi);
|
||||
AUD_close_out(&s->card, s->voice_po);
|
||||
AUD_close_in(&s->card, s->voice_mc);
|
||||
AUD_remove_card(&s->card);
|
||||
}
|
||||
|
||||
static int ac97_init (PCIBus *bus)
|
||||
{
|
||||
pci_create_simple (bus, -1, "AC97");
|
||||
@@ -1404,6 +1414,7 @@ static void ac97_class_init (ObjectClass *klass, void *data)
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
|
||||
|
||||
k->realize = ac97_realize;
|
||||
k->exit = ac97_exit;
|
||||
k->vendor_id = PCI_VENDOR_ID_INTEL;
|
||||
k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5;
|
||||
k->revision = 0x01;
|
||||
|
@@ -1010,9 +1010,9 @@ static const VMStateDescription vmstate_es1370 = {
|
||||
}
|
||||
};
|
||||
|
||||
static void es1370_on_reset (void *opaque)
|
||||
static void es1370_on_reset(DeviceState *dev)
|
||||
{
|
||||
ES1370State *s = opaque;
|
||||
ES1370State *s = container_of(dev, ES1370State, dev.qdev);
|
||||
es1370_reset (s);
|
||||
}
|
||||
|
||||
@@ -1035,12 +1035,24 @@ static void es1370_realize(PCIDevice *dev, Error **errp)
|
||||
|
||||
memory_region_init_io (&s->io, OBJECT(s), &es1370_io_ops, s, "es1370", 256);
|
||||
pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
|
||||
qemu_register_reset (es1370_on_reset, s);
|
||||
|
||||
AUD_register_card ("es1370", &s->card);
|
||||
es1370_reset (s);
|
||||
}
|
||||
|
||||
static void es1370_exit(PCIDevice *dev)
|
||||
{
|
||||
ES1370State *s = ES1370(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
AUD_close_out(&s->card, s->dac_voice[i]);
|
||||
}
|
||||
|
||||
AUD_close_in(&s->card, s->adc_voice);
|
||||
AUD_remove_card(&s->card);
|
||||
}
|
||||
|
||||
static int es1370_init (PCIBus *bus)
|
||||
{
|
||||
pci_create_simple (bus, -1, TYPE_ES1370);
|
||||
@@ -1053,6 +1065,7 @@ static void es1370_class_init (ObjectClass *klass, void *data)
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
|
||||
|
||||
k->realize = es1370_realize;
|
||||
k->exit = es1370_exit;
|
||||
k->vendor_id = PCI_VENDOR_ID_ENSONIQ;
|
||||
k->device_id = PCI_DEVICE_ID_ENSONIQ_ES1370;
|
||||
k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
|
||||
@@ -1061,6 +1074,7 @@ static void es1370_class_init (ObjectClass *klass, void *data)
|
||||
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
||||
dc->desc = "ENSONIQ AudioPCI ES1370";
|
||||
dc->vmsd = &vmstate_es1370;
|
||||
dc->reset = es1370_on_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo es1370_info = {
|
||||
|
@@ -241,19 +241,23 @@ static const MemoryRegionOps mv88w8618_audio_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int mv88w8618_audio_init(SysBusDevice *dev)
|
||||
static void mv88w8618_audio_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
mv88w8618_audio_state *s = MV88W8618_AUDIO(dev);
|
||||
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
|
||||
wm8750_data_req_set(s->wm, mv88w8618_audio_callback, s);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_audio_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &mv88w8618_audio_ops, s,
|
||||
"audio", MP_AUDIO_SIZE);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
static void mv88w8618_audio_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
mv88w8618_audio_state *s = MV88W8618_AUDIO(dev);
|
||||
|
||||
wm8750_data_req_set(s->wm, mv88w8618_audio_callback, s);
|
||||
}
|
||||
|
||||
static const VMStateDescription mv88w8618_audio_vmsd = {
|
||||
@@ -282,9 +286,8 @@ static Property mv88w8618_audio_properties[] = {
|
||||
static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = mv88w8618_audio_init;
|
||||
dc->realize = mv88w8618_audio_realize;
|
||||
dc->reset = mv88w8618_audio_reset;
|
||||
dc->vmsd = &mv88w8618_audio_vmsd;
|
||||
dc->props = mv88w8618_audio_properties;
|
||||
@@ -296,6 +299,7 @@ static const TypeInfo mv88w8618_audio_info = {
|
||||
.name = TYPE_MV88W8618_AUDIO,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(mv88w8618_audio_state),
|
||||
.instance_init = mv88w8618_audio_init,
|
||||
.class_init = mv88w8618_audio_class_init,
|
||||
};
|
||||
|
||||
|
@@ -521,12 +521,23 @@ static const MemoryRegionOps pl041_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int pl041_init(SysBusDevice *dev)
|
||||
static void pl041_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
PL041State *s = PL041(dev);
|
||||
|
||||
DBG_L1("pl041_init 0x%08x\n", (uint32_t)s);
|
||||
|
||||
/* Connect the device to the sysbus */
|
||||
memory_region_init_io(&s->iomem, obj, &pl041_ops, s, "pl041", 0x1000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
}
|
||||
|
||||
static void pl041_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PL041State *s = PL041(dev);
|
||||
|
||||
/* Check the device properties */
|
||||
switch (s->fifo_depth) {
|
||||
case 8:
|
||||
@@ -545,18 +556,10 @@ static int pl041_init(SysBusDevice *dev)
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"pl041: unsupported non-compact fifo depth [%i]\n",
|
||||
s->fifo_depth);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Connect the device to the sysbus */
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &pl041_ops, s, "pl041", 0x1000);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
|
||||
/* Init the codec */
|
||||
lm4549_init(&s->codec, &pl041_request_data, (void *)s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pl041_regfile = {
|
||||
@@ -627,9 +630,8 @@ static Property pl041_device_properties[] = {
|
||||
static void pl041_device_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = pl041_init;
|
||||
dc->realize = pl041_realize;
|
||||
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
|
||||
dc->reset = pl041_device_reset;
|
||||
dc->vmsd = &vmstate_pl041;
|
||||
@@ -640,6 +642,7 @@ static const TypeInfo pl041_device_info = {
|
||||
.name = TYPE_PL041,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(PL041State),
|
||||
.instance_init = pl041_init,
|
||||
.class_init = pl041_device_class_init,
|
||||
};
|
||||
|
||||
|
@@ -303,7 +303,7 @@ static void wm8750_reset(I2CSlave *i2c)
|
||||
s->i2c_len = 0;
|
||||
}
|
||||
|
||||
static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int wm8750_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
WM8750State *s = WM8750(i2c);
|
||||
|
||||
@@ -321,6 +321,8 @@ static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WM8750_LINVOL 0x00
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#ifndef M25P80_ERR_DEBUG
|
||||
@@ -377,6 +378,8 @@ typedef enum {
|
||||
MAN_GENERIC,
|
||||
} Manufacturer;
|
||||
|
||||
#define M25P80_INTERNAL_DATA_BUFFER_SZ 16
|
||||
|
||||
typedef struct Flash {
|
||||
SSISlave parent_obj;
|
||||
|
||||
@@ -387,7 +390,7 @@ typedef struct Flash {
|
||||
int page_size;
|
||||
|
||||
uint8_t state;
|
||||
uint8_t data[16];
|
||||
uint8_t data[M25P80_INTERNAL_DATA_BUFFER_SZ];
|
||||
uint32_t len;
|
||||
uint32_t pos;
|
||||
uint8_t needed_bytes;
|
||||
@@ -1115,6 +1118,17 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
|
||||
|
||||
case STATE_COLLECTING_DATA:
|
||||
case STATE_COLLECTING_VAR_LEN_DATA:
|
||||
|
||||
if (s->len >= M25P80_INTERNAL_DATA_BUFFER_SZ) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"M25P80: Write overrun internal data buffer. "
|
||||
"SPI controller (QEMU emulator or guest driver) "
|
||||
"is misbehaving\n");
|
||||
s->len = s->pos = 0;
|
||||
s->state = STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
s->data[s->len] = (uint8_t)tx;
|
||||
s->len++;
|
||||
|
||||
@@ -1124,6 +1138,17 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
|
||||
break;
|
||||
|
||||
case STATE_READING_DATA:
|
||||
|
||||
if (s->pos >= M25P80_INTERNAL_DATA_BUFFER_SZ) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"M25P80: Read overrun internal data buffer. "
|
||||
"SPI controller (QEMU emulator or guest driver) "
|
||||
"is misbehaving\n");
|
||||
s->len = s->pos = 0;
|
||||
s->state = STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
r = s->data[s->pos];
|
||||
s->pos++;
|
||||
if (s->pos == s->len) {
|
||||
@@ -1196,7 +1221,7 @@ static const VMStateDescription vmstate_m25p80 = {
|
||||
.pre_save = m25p80_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(state, Flash),
|
||||
VMSTATE_UINT8_ARRAY(data, Flash, 16),
|
||||
VMSTATE_UINT8_ARRAY(data, Flash, M25P80_INTERNAL_DATA_BUFFER_SZ),
|
||||
VMSTATE_UINT32(len, Flash),
|
||||
VMSTATE_UINT32(pos, Flash),
|
||||
VMSTATE_UINT8(needed_bytes, Flash),
|
||||
|
@@ -863,7 +863,7 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||
}
|
||||
}
|
||||
|
||||
req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq));
|
||||
req = qemu_get_virtqueue_element(vdev, f, sizeof(VirtIOBlockReq));
|
||||
virtio_blk_init_request(s, virtio_get_queue(vdev, vq_idx), req);
|
||||
req->next = s->rq;
|
||||
s->rq = req;
|
||||
|
@@ -629,22 +629,26 @@ DeviceState *exynos4210_uart_create(hwaddr addr,
|
||||
return dev;
|
||||
}
|
||||
|
||||
static int exynos4210_uart_init(SysBusDevice *dev)
|
||||
static void exynos4210_uart_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
Exynos4210UartState *s = EXYNOS4210_UART(dev);
|
||||
|
||||
/* memory mapping */
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_uart_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &exynos4210_uart_ops, s,
|
||||
"exynos4210.uart", EXYNOS4210_UART_REGS_MEM_SIZE);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
}
|
||||
|
||||
static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
Exynos4210UartState *s = EXYNOS4210_UART(dev);
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
|
||||
exynos4210_uart_receive, exynos4210_uart_event,
|
||||
s, NULL, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property exynos4210_uart_properties[] = {
|
||||
@@ -658,9 +662,8 @@ static Property exynos4210_uart_properties[] = {
|
||||
static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = exynos4210_uart_init;
|
||||
dc->realize = exynos4210_uart_realize;
|
||||
dc->reset = exynos4210_uart_reset;
|
||||
dc->props = exynos4210_uart_properties;
|
||||
dc->vmsd = &vmstate_exynos4210_uart;
|
||||
@@ -670,6 +673,7 @@ static const TypeInfo exynos4210_uart_info = {
|
||||
.name = TYPE_EXYNOS4210_UART,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Exynos4210UartState),
|
||||
.instance_init = exynos4210_uart_init,
|
||||
.class_init = exynos4210_uart_class_init,
|
||||
};
|
||||
|
||||
|
@@ -732,6 +732,7 @@ static void virtio_serial_post_load_timer_cb(void *opaque)
|
||||
static int fetch_active_ports_list(QEMUFile *f,
|
||||
VirtIOSerial *s, uint32_t nr_active_ports)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
uint32_t i;
|
||||
|
||||
s->post_load = g_malloc0(sizeof(*s->post_load));
|
||||
@@ -765,7 +766,7 @@ static int fetch_active_ports_list(QEMUFile *f,
|
||||
qemu_get_be64s(f, &port->iov_offset);
|
||||
|
||||
port->elem =
|
||||
qemu_get_virtqueue_element(f, sizeof(VirtQueueElement));
|
||||
qemu_get_virtqueue_element(vdev, f, sizeof(VirtQueueElement));
|
||||
|
||||
/*
|
||||
* Port was throttled on source machine. Let's
|
||||
|
@@ -179,7 +179,7 @@ static int ssd0303_send(I2CSlave *i2c, uint8_t data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int ssd0303_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
ssd0303_state *s = SSD0303(i2c);
|
||||
|
||||
@@ -193,6 +193,8 @@ static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
|
||||
/* Nothing to do. */
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssd0303_update_display(void *opaque)
|
||||
|
@@ -129,7 +129,7 @@ static int max7310_tx(I2CSlave *i2c, uint8_t data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max7310_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int max7310_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
MAX7310State *s = MAX7310(i2c);
|
||||
s->len = 0;
|
||||
@@ -147,6 +147,8 @@ static void max7310_event(I2CSlave *i2c, enum i2c_event event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_max7310 = {
|
||||
|
@@ -88,18 +88,26 @@ int i2c_bus_busy(I2CBus *bus)
|
||||
return !QLIST_EMPTY(&bus->current_devs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns non-zero if the address is not valid. If this is called
|
||||
* again without an intervening i2c_end_transfer(), like in the SMBus
|
||||
* case where the operation is switched from write to read, this
|
||||
* function will not rescan the bus and thus cannot fail.
|
||||
*/
|
||||
/* TODO: Make this handle multiple masters. */
|
||||
/*
|
||||
* Start or continue an i2c transaction. When this is called for the
|
||||
* first time or after an i2c_end_transfer(), if it returns an error
|
||||
* the bus transaction is terminated (or really never started). If
|
||||
* this is called after another i2c_start_transfer() without an
|
||||
* intervening i2c_end_transfer(), and it returns an error, the
|
||||
* transaction will not be terminated. The caller must do it.
|
||||
*
|
||||
* This corresponds with the way real hardware works. The SMBus
|
||||
* protocol uses a start transfer to switch from write to read mode
|
||||
* without releasing the bus. If that fails, the bus is still
|
||||
* in a transaction.
|
||||
*/
|
||||
int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
|
||||
{
|
||||
BusChild *kid;
|
||||
I2CSlaveClass *sc;
|
||||
I2CNode *node;
|
||||
bool bus_scanned = false;
|
||||
|
||||
if (address == I2C_BROADCAST) {
|
||||
/*
|
||||
@@ -130,6 +138,7 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
|
||||
}
|
||||
}
|
||||
}
|
||||
bus_scanned = true;
|
||||
}
|
||||
|
||||
if (QLIST_EMPTY(&bus->current_devs)) {
|
||||
@@ -137,11 +146,21 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
|
||||
}
|
||||
|
||||
QLIST_FOREACH(node, &bus->current_devs, next) {
|
||||
int rv;
|
||||
|
||||
sc = I2C_SLAVE_GET_CLASS(node->elt);
|
||||
/* If the bus is already busy, assume this is a repeated
|
||||
start condition. */
|
||||
|
||||
if (sc->event) {
|
||||
sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND);
|
||||
rv = sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND);
|
||||
if (rv && !bus->broadcast) {
|
||||
if (bus_scanned) {
|
||||
/* First call, terminate the transfer. */
|
||||
i2c_end_transfer(bus);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@@ -230,13 +230,15 @@ static void i2c_ddc_reset(DeviceState *ds)
|
||||
s->reg = 0;
|
||||
}
|
||||
|
||||
static void i2c_ddc_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int i2c_ddc_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
I2CDDCState *s = I2CDDC(i2c);
|
||||
|
||||
if (event == I2C_START_SEND) {
|
||||
s->firstbyte = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_ddc_rx(I2CSlave *i2c)
|
||||
|
@@ -67,7 +67,7 @@ static void smbus_do_write(SMBusDevice *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
|
||||
static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
|
||||
{
|
||||
SMBusDevice *dev = SMBUS_DEVICE(s);
|
||||
|
||||
@@ -148,6 +148,8 @@ static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smbus_i2c_recv(I2CSlave *s)
|
||||
@@ -249,7 +251,8 @@ int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command)
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
assert(0);
|
||||
i2c_end_transfer(bus);
|
||||
return -1;
|
||||
}
|
||||
data = i2c_recv(bus);
|
||||
i2c_nack(bus);
|
||||
@@ -276,7 +279,8 @@ int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command)
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
assert(0);
|
||||
i2c_end_transfer(bus);
|
||||
return -1;
|
||||
}
|
||||
data = i2c_recv(bus);
|
||||
data |= i2c_recv(bus) << 8;
|
||||
@@ -307,7 +311,8 @@ int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data)
|
||||
}
|
||||
i2c_send(bus, command);
|
||||
if (i2c_start_transfer(bus, addr, 1)) {
|
||||
assert(0);
|
||||
i2c_end_transfer(bus);
|
||||
return -1;
|
||||
}
|
||||
len = i2c_recv(bus);
|
||||
if (len > 32) {
|
||||
|
@@ -101,8 +101,6 @@ typedef struct AcpiPmInfo {
|
||||
uint32_t gpe0_blk_len;
|
||||
uint32_t io_base;
|
||||
uint16_t cpu_hp_io_base;
|
||||
uint16_t mem_hp_io_base;
|
||||
uint16_t mem_hp_io_len;
|
||||
uint16_t pcihp_io_base;
|
||||
uint16_t pcihp_io_len;
|
||||
} AcpiPmInfo;
|
||||
@@ -148,9 +146,6 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
|
||||
}
|
||||
assert(obj);
|
||||
|
||||
pm->mem_hp_io_base = ACPI_MEMORY_HOTPLUG_BASE;
|
||||
pm->mem_hp_io_len = ACPI_MEMORY_HOTPLUG_IO_LEN;
|
||||
|
||||
/* Fill in optional s3/s4 related properties */
|
||||
o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL);
|
||||
if (o) {
|
||||
@@ -1038,130 +1033,6 @@ static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set)
|
||||
return crs;
|
||||
}
|
||||
|
||||
static void build_memory_devices(Aml *sb_scope, int nr_mem,
|
||||
uint16_t io_base, uint16_t io_len)
|
||||
{
|
||||
int i;
|
||||
Aml *scope;
|
||||
Aml *crs;
|
||||
Aml *field;
|
||||
Aml *dev;
|
||||
Aml *method;
|
||||
Aml *ifctx;
|
||||
|
||||
/* build memory devices */
|
||||
assert(nr_mem <= ACPI_MAX_RAM_SLOTS);
|
||||
scope = aml_scope("\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE);
|
||||
aml_append(scope,
|
||||
aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem))
|
||||
);
|
||||
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs,
|
||||
aml_io(AML_DECODE16, io_base, io_base, 0, io_len)
|
||||
);
|
||||
aml_append(scope, aml_name_decl("_CRS", crs));
|
||||
|
||||
aml_append(scope, aml_operation_region(
|
||||
MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO,
|
||||
aml_int(io_base), io_len)
|
||||
);
|
||||
|
||||
field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC,
|
||||
AML_NOLOCK, AML_PRESERVE);
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_ADDR_LOW, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_SIZE_LOW, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32));
|
||||
aml_append(field, /* read only */
|
||||
aml_named_field(MEMORY_SLOT_PROXIMITY, 32));
|
||||
aml_append(scope, field);
|
||||
|
||||
field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_BYTE_ACC,
|
||||
AML_NOLOCK, AML_WRITE_AS_ZEROS);
|
||||
aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
|
||||
aml_append(field, /* 1 if enabled, read only */
|
||||
aml_named_field(MEMORY_SLOT_ENABLED, 1));
|
||||
aml_append(field,
|
||||
/*(read) 1 if has a insert event. (write) 1 to clear event */
|
||||
aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1));
|
||||
aml_append(field,
|
||||
/* (read) 1 if has a remove event. (write) 1 to clear event */
|
||||
aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1));
|
||||
aml_append(field,
|
||||
/* initiates device eject, write only */
|
||||
aml_named_field(MEMORY_SLOT_EJECT, 1));
|
||||
aml_append(scope, field);
|
||||
|
||||
field = aml_field(MEMORY_HOTPLUG_IO_REGION, AML_DWORD_ACC,
|
||||
AML_NOLOCK, AML_PRESERVE);
|
||||
aml_append(field, /* DIMM selector, write only */
|
||||
aml_named_field(MEMORY_SLOT_SLECTOR, 32));
|
||||
aml_append(field, /* _OST event code, write only */
|
||||
aml_named_field(MEMORY_SLOT_OST_EVENT, 32));
|
||||
aml_append(field, /* _OST status code, write only */
|
||||
aml_named_field(MEMORY_SLOT_OST_STATUS, 32));
|
||||
aml_append(scope, field);
|
||||
aml_append(sb_scope, scope);
|
||||
|
||||
for (i = 0; i < nr_mem; i++) {
|
||||
#define BASEPATH "\\_SB.PCI0." MEMORY_HOTPLUG_DEVICE "."
|
||||
const char *s;
|
||||
|
||||
dev = aml_device("MP%02X", i);
|
||||
aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i)));
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80")));
|
||||
|
||||
method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
|
||||
s = BASEPATH MEMORY_SLOT_CRS_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
s = BASEPATH MEMORY_SLOT_STATUS_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_PXM", 0, AML_NOTSERIALIZED);
|
||||
s = BASEPATH MEMORY_SLOT_PROXIMITY_METHOD;
|
||||
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_OST", 3, AML_NOTSERIALIZED);
|
||||
s = BASEPATH MEMORY_SLOT_OST_METHOD;
|
||||
|
||||
aml_append(method, aml_return(aml_call4(
|
||||
s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2)
|
||||
)));
|
||||
aml_append(dev, method);
|
||||
|
||||
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
|
||||
s = BASEPATH MEMORY_SLOT_EJECT_METHOD;
|
||||
aml_append(method, aml_return(aml_call2(
|
||||
s, aml_name("_UID"), aml_arg(0))));
|
||||
aml_append(dev, method);
|
||||
|
||||
aml_append(sb_scope, dev);
|
||||
}
|
||||
|
||||
/* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
|
||||
* If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... }
|
||||
*/
|
||||
method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED);
|
||||
for (i = 0; i < nr_mem; i++) {
|
||||
ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i)));
|
||||
aml_append(ifctx,
|
||||
aml_notify(aml_name("MP%.02X", i), aml_arg(1))
|
||||
);
|
||||
aml_append(method, ifctx);
|
||||
}
|
||||
aml_append(sb_scope, method);
|
||||
}
|
||||
|
||||
static void build_hpet_aml(Aml *table)
|
||||
{
|
||||
Aml *crs;
|
||||
@@ -2049,8 +1920,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base,
|
||||
"\\_SB.PCI0", "\\_GPE._E02");
|
||||
}
|
||||
build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base,
|
||||
pm->mem_hp_io_len);
|
||||
build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", "\\_GPE._E03");
|
||||
|
||||
scope = aml_scope("_GPE");
|
||||
{
|
||||
@@ -2065,10 +1935,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
aml_append(scope, method);
|
||||
}
|
||||
|
||||
method = aml_method("_E03", 0, AML_NOTSERIALIZED);
|
||||
aml_append(method, aml_call0(MEMORY_HOTPLUG_HANDLER_PATH));
|
||||
aml_append(scope, method);
|
||||
|
||||
if (pcms->acpi_nvdimm_state.is_enabled) {
|
||||
method = aml_method("_E04", 0, AML_NOTSERIALIZED);
|
||||
aml_append(method, aml_notify(aml_name("\\_SB.NVDR"),
|
||||
@@ -2321,45 +2187,40 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
|
||||
sb_scope = aml_scope("\\_SB");
|
||||
{
|
||||
build_memory_devices(sb_scope, nr_mem, pm->mem_hp_io_base,
|
||||
pm->mem_hp_io_len);
|
||||
Object *pci_host;
|
||||
PCIBus *bus = NULL;
|
||||
|
||||
{
|
||||
Object *pci_host;
|
||||
PCIBus *bus = NULL;
|
||||
|
||||
pci_host = acpi_get_i386_pci_host();
|
||||
if (pci_host) {
|
||||
bus = PCI_HOST_BRIDGE(pci_host)->bus;
|
||||
}
|
||||
|
||||
if (bus) {
|
||||
Aml *scope = aml_scope("PCI0");
|
||||
/* Scan all PCI buses. Generate tables to support hotplug. */
|
||||
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
|
||||
|
||||
if (misc->tpm_version != TPM_VERSION_UNSPEC) {
|
||||
dev = aml_device("ISA.TPM");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
|
||||
TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
|
||||
/*
|
||||
FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs,
|
||||
Rewrite to take IRQ from TPM device model and
|
||||
fix default IRQ value there to use some unused IRQ
|
||||
*/
|
||||
/* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
aml_append(sb_scope, scope);
|
||||
}
|
||||
pci_host = acpi_get_i386_pci_host();
|
||||
if (pci_host) {
|
||||
bus = PCI_HOST_BRIDGE(pci_host)->bus;
|
||||
}
|
||||
|
||||
if (bus) {
|
||||
Aml *scope = aml_scope("PCI0");
|
||||
/* Scan all PCI buses. Generate tables to support hotplug. */
|
||||
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
|
||||
|
||||
if (misc->tpm_version != TPM_VERSION_UNSPEC) {
|
||||
dev = aml_device("ISA.TPM");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
|
||||
crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
|
||||
TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
|
||||
/*
|
||||
FIXME: TPM_TIS_IRQ=5 conflicts with PNP0C0F irqs,
|
||||
Rewrite to take IRQ from TPM device model and
|
||||
fix default IRQ value there to use some unused IRQ
|
||||
*/
|
||||
/* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
aml_append(sb_scope, scope);
|
||||
}
|
||||
aml_append(dsdt, sb_scope);
|
||||
}
|
||||
aml_append(dsdt, sb_scope);
|
||||
|
||||
/* copy AML table into ACPI tables blob and patch header there */
|
||||
g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
|
||||
@@ -2575,6 +2436,7 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
|
||||
|
||||
AcpiTableDmar *dmar;
|
||||
AcpiDmarHardwareUnit *drhd;
|
||||
AcpiDmarRootPortATS *atsr;
|
||||
uint8_t dmar_flags = 0;
|
||||
X86IOMMUState *iommu = x86_iommu_get_default();
|
||||
AcpiDmarDeviceScope *scope = NULL;
|
||||
@@ -2608,6 +2470,14 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
|
||||
scope->path[0].device = PCI_SLOT(Q35_PSEUDO_DEVFN_IOAPIC);
|
||||
scope->path[0].function = PCI_FUNC(Q35_PSEUDO_DEVFN_IOAPIC);
|
||||
|
||||
if (iommu->dt_supported) {
|
||||
atsr = acpi_data_push(table_data, sizeof(*atsr));
|
||||
atsr->type = cpu_to_le16(ACPI_DMAR_TYPE_ATSR);
|
||||
atsr->length = cpu_to_le16(sizeof(*atsr));
|
||||
atsr->flags = ACPI_DMAR_ATSR_ALL_PORTS;
|
||||
atsr->pci_segment = cpu_to_le16(0);
|
||||
}
|
||||
|
||||
build_header(linker, table_data, (void *)(table_data->data + dmar_start),
|
||||
"DMAR", table_data->len - dmar_start, 1, NULL, NULL);
|
||||
}
|
||||
|
@@ -562,7 +562,7 @@ static void amdvi_mmio_trace(hwaddr addr, unsigned size)
|
||||
trace_amdvi_mmio_read(amdvi_mmio_high[index], addr, size, addr & ~0x07);
|
||||
} else {
|
||||
index = index >= AMDVI_MMIO_REGS_LOW ? AMDVI_MMIO_REGS_LOW : index;
|
||||
trace_amdvi_mmio_read(amdvi_mmio_high[index], addr, size, addr & ~0x07);
|
||||
trace_amdvi_mmio_read(amdvi_mmio_low[index], addr, size, addr & ~0x07);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -49,8 +49,8 @@
|
||||
#define AMDVI_CAPAB_INIT_TYPE (3 << 16)
|
||||
|
||||
/* No. of used MMIO registers */
|
||||
#define AMDVI_MMIO_REGS_HIGH 8
|
||||
#define AMDVI_MMIO_REGS_LOW 7
|
||||
#define AMDVI_MMIO_REGS_HIGH 7
|
||||
#define AMDVI_MMIO_REGS_LOW 8
|
||||
|
||||
/* MMIO registers */
|
||||
#define AMDVI_MMIO_DEVICE_TABLE 0x0000
|
||||
|
@@ -738,11 +738,18 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
|
||||
"context-entry hi 0x%"PRIx64 " lo 0x%"PRIx64,
|
||||
ce->hi, ce->lo);
|
||||
return -VTD_FR_CONTEXT_ENTRY_INV;
|
||||
} else if (ce->lo & VTD_CONTEXT_ENTRY_TT) {
|
||||
VTD_DPRINTF(GENERAL, "error: unsupported Translation Type in "
|
||||
"context-entry hi 0x%"PRIx64 " lo 0x%"PRIx64,
|
||||
ce->hi, ce->lo);
|
||||
return -VTD_FR_CONTEXT_ENTRY_INV;
|
||||
} else {
|
||||
switch (ce->lo & VTD_CONTEXT_ENTRY_TT) {
|
||||
case VTD_CONTEXT_TT_MULTI_LEVEL:
|
||||
/* fall through */
|
||||
case VTD_CONTEXT_TT_DEV_IOTLB:
|
||||
break;
|
||||
default:
|
||||
VTD_DPRINTF(GENERAL, "error: unsupported Translation Type in "
|
||||
"context-entry hi 0x%"PRIx64 " lo 0x%"PRIx64,
|
||||
ce->hi, ce->lo);
|
||||
return -VTD_FR_CONTEXT_ENTRY_INV;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1438,7 +1445,61 @@ static bool vtd_process_inv_iec_desc(IntelIOMMUState *s,
|
||||
vtd_iec_notify_all(s, !inv_desc->iec.granularity,
|
||||
inv_desc->iec.index,
|
||||
inv_desc->iec.index_mask);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
|
||||
VTDInvDesc *inv_desc)
|
||||
{
|
||||
VTDAddressSpace *vtd_dev_as;
|
||||
IOMMUTLBEntry entry;
|
||||
struct VTDBus *vtd_bus;
|
||||
hwaddr addr;
|
||||
uint64_t sz;
|
||||
uint16_t sid;
|
||||
uint8_t devfn;
|
||||
bool size;
|
||||
uint8_t bus_num;
|
||||
|
||||
addr = VTD_INV_DESC_DEVICE_IOTLB_ADDR(inv_desc->hi);
|
||||
sid = VTD_INV_DESC_DEVICE_IOTLB_SID(inv_desc->lo);
|
||||
devfn = sid & 0xff;
|
||||
bus_num = sid >> 8;
|
||||
size = VTD_INV_DESC_DEVICE_IOTLB_SIZE(inv_desc->hi);
|
||||
|
||||
if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) ||
|
||||
(inv_desc->hi & VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI)) {
|
||||
VTD_DPRINTF(GENERAL, "error: non-zero reserved field in Device "
|
||||
"IOTLB Invalidate Descriptor hi 0x%"PRIx64 " lo 0x%"PRIx64,
|
||||
inv_desc->hi, inv_desc->lo);
|
||||
return false;
|
||||
}
|
||||
|
||||
vtd_bus = vtd_find_as_from_bus_num(s, bus_num);
|
||||
if (!vtd_bus) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
vtd_dev_as = vtd_bus->dev_as[devfn];
|
||||
if (!vtd_dev_as) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
sz = 1 << (ctz64(~(addr | (VTD_PAGE_MASK_4K - 1))) + 1);
|
||||
addr &= ~(sz - 1);
|
||||
} else {
|
||||
sz = VTD_PAGE_SIZE;
|
||||
}
|
||||
|
||||
entry.target_as = &vtd_dev_as->as;
|
||||
entry.addr_mask = sz - 1;
|
||||
entry.iova = addr;
|
||||
entry.perm = IOMMU_NONE;
|
||||
entry.translated_addr = 0;
|
||||
memory_region_notify_iommu(entry.target_as->root, entry);
|
||||
|
||||
done:
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1490,6 +1551,14 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
|
||||
}
|
||||
break;
|
||||
|
||||
case VTD_INV_DESC_DEVICE:
|
||||
VTD_DPRINTF(INV, "Device IOTLB Invalidation Descriptor hi 0x%"PRIx64
|
||||
" lo 0x%"PRIx64, inv_desc.hi, inv_desc.lo);
|
||||
if (!vtd_process_device_iotlb_desc(s, &inv_desc)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
VTD_DPRINTF(GENERAL, "error: unkonw Invalidation Descriptor type "
|
||||
"hi 0x%"PRIx64 " lo 0x%"PRIx64 " type %"PRIu8,
|
||||
@@ -1996,7 +2065,27 @@ static void vtd_iommu_notify_flag_changed(MemoryRegion *iommu,
|
||||
|
||||
static const VMStateDescription vtd_vmstate = {
|
||||
.name = "iommu-intel",
|
||||
.unmigratable = 1,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.priority = MIG_PRI_IOMMU,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(root, IntelIOMMUState),
|
||||
VMSTATE_UINT64(intr_root, IntelIOMMUState),
|
||||
VMSTATE_UINT64(iq, IntelIOMMUState),
|
||||
VMSTATE_UINT32(intr_size, IntelIOMMUState),
|
||||
VMSTATE_UINT16(iq_head, IntelIOMMUState),
|
||||
VMSTATE_UINT16(iq_tail, IntelIOMMUState),
|
||||
VMSTATE_UINT16(iq_size, IntelIOMMUState),
|
||||
VMSTATE_UINT16(next_frcd_reg, IntelIOMMUState),
|
||||
VMSTATE_UINT8_ARRAY(csr, IntelIOMMUState, DMAR_REG_SIZE),
|
||||
VMSTATE_UINT8(iq_last_desc_type, IntelIOMMUState),
|
||||
VMSTATE_BOOL(root_extended, IntelIOMMUState),
|
||||
VMSTATE_BOOL(dmar_enabled, IntelIOMMUState),
|
||||
VMSTATE_BOOL(qi_enabled, IntelIOMMUState),
|
||||
VMSTATE_BOOL(intr_enabled, IntelIOMMUState),
|
||||
VMSTATE_BOOL(intr_eime, IntelIOMMUState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const MemoryRegionOps vtd_mem_ops = {
|
||||
@@ -2324,19 +2413,22 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
|
||||
uintptr_t key = (uintptr_t)bus;
|
||||
VTDBus *vtd_bus = g_hash_table_lookup(s->vtd_as_by_busptr, &key);
|
||||
VTDAddressSpace *vtd_dev_as;
|
||||
char name[128];
|
||||
|
||||
if (!vtd_bus) {
|
||||
uintptr_t *new_key = g_malloc(sizeof(*new_key));
|
||||
*new_key = (uintptr_t)bus;
|
||||
/* No corresponding free() */
|
||||
vtd_bus = g_malloc0(sizeof(VTDBus) + sizeof(VTDAddressSpace *) * \
|
||||
X86_IOMMU_PCI_DEVFN_MAX);
|
||||
vtd_bus->bus = bus;
|
||||
key = (uintptr_t)bus;
|
||||
g_hash_table_insert(s->vtd_as_by_busptr, &key, vtd_bus);
|
||||
g_hash_table_insert(s->vtd_as_by_busptr, new_key, vtd_bus);
|
||||
}
|
||||
|
||||
vtd_dev_as = vtd_bus->dev_as[devfn];
|
||||
|
||||
if (!vtd_dev_as) {
|
||||
snprintf(name, sizeof(name), "intel_iommu_devfn_%d", devfn);
|
||||
vtd_bus->dev_as[devfn] = vtd_dev_as = g_malloc0(sizeof(VTDAddressSpace));
|
||||
|
||||
vtd_dev_as->bus = bus;
|
||||
@@ -2351,7 +2443,7 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn)
|
||||
memory_region_add_subregion(&vtd_dev_as->iommu, VTD_INTERRUPT_ADDR_FIRST,
|
||||
&vtd_dev_as->iommu_ir);
|
||||
address_space_init(&vtd_dev_as->as,
|
||||
&vtd_dev_as->iommu, "intel_iommu");
|
||||
&vtd_dev_as->iommu, name);
|
||||
}
|
||||
return vtd_dev_as;
|
||||
}
|
||||
@@ -2392,6 +2484,10 @@ static void vtd_init(IntelIOMMUState *s)
|
||||
assert(s->intr_eim != ON_OFF_AUTO_AUTO);
|
||||
}
|
||||
|
||||
if (x86_iommu->dt_supported) {
|
||||
s->ecap |= VTD_ECAP_DT;
|
||||
}
|
||||
|
||||
vtd_reset_context_cache(s);
|
||||
vtd_reset_iotlb(s);
|
||||
|
||||
|
@@ -183,6 +183,7 @@
|
||||
/* (offset >> 4) << 8 */
|
||||
#define VTD_ECAP_IRO (DMAR_IOTLB_REG_OFFSET << 4)
|
||||
#define VTD_ECAP_QI (1ULL << 1)
|
||||
#define VTD_ECAP_DT (1ULL << 2)
|
||||
/* Interrupt Remapping support */
|
||||
#define VTD_ECAP_IR (1ULL << 3)
|
||||
#define VTD_ECAP_EIM (1ULL << 4)
|
||||
@@ -326,6 +327,7 @@ typedef union VTDInvDesc VTDInvDesc;
|
||||
#define VTD_INV_DESC_TYPE 0xf
|
||||
#define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */
|
||||
#define VTD_INV_DESC_IOTLB 0x2
|
||||
#define VTD_INV_DESC_DEVICE 0x3
|
||||
#define VTD_INV_DESC_IEC 0x4 /* Interrupt Entry Cache
|
||||
Invalidate Descriptor */
|
||||
#define VTD_INV_DESC_WAIT 0x5 /* Invalidation Wait Descriptor */
|
||||
@@ -361,6 +363,13 @@ typedef union VTDInvDesc VTDInvDesc;
|
||||
#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000ff00ULL
|
||||
#define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL
|
||||
|
||||
/* Mask for Device IOTLB Invalidate Descriptor */
|
||||
#define VTD_INV_DESC_DEVICE_IOTLB_ADDR(val) ((val) & 0xfffffffffffff000ULL)
|
||||
#define VTD_INV_DESC_DEVICE_IOTLB_SIZE(val) ((val) & 0x1)
|
||||
#define VTD_INV_DESC_DEVICE_IOTLB_SID(val) (((val) >> 32) & 0xFFFFULL)
|
||||
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI 0xffeULL
|
||||
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0fff8
|
||||
|
||||
/* Information about page-selective IOTLB invalidate */
|
||||
struct VTDIOTLBPageInvInfo {
|
||||
uint16_t domain_id;
|
||||
@@ -399,8 +408,8 @@ typedef struct VTDRootEntry VTDRootEntry;
|
||||
#define VTD_CONTEXT_ENTRY_FPD (1ULL << 1) /* Fault Processing Disable */
|
||||
#define VTD_CONTEXT_ENTRY_TT (3ULL << 2) /* Translation Type */
|
||||
#define VTD_CONTEXT_TT_MULTI_LEVEL 0
|
||||
#define VTD_CONTEXT_TT_DEV_IOTLB 1
|
||||
#define VTD_CONTEXT_TT_PASS_THROUGH 2
|
||||
#define VTD_CONTEXT_TT_DEV_IOTLB (1ULL << 2)
|
||||
#define VTD_CONTEXT_TT_PASS_THROUGH (2ULL << 2)
|
||||
/* Second Level Page Translation Pointer*/
|
||||
#define VTD_CONTEXT_ENTRY_SLPTPTR (~0xfffULL)
|
||||
#define VTD_CONTEXT_ENTRY_RSVD_LO (0xff0ULL | ~VTD_HAW_MASK)
|
||||
|
@@ -106,6 +106,18 @@ static void x86_iommu_intremap_prop_set(Object *o, bool value, Error **errp)
|
||||
s->intr_supported = value;
|
||||
}
|
||||
|
||||
static bool x86_iommu_device_iotlb_prop_get(Object *o, Error **errp)
|
||||
{
|
||||
X86IOMMUState *s = X86_IOMMU_DEVICE(o);
|
||||
return s->dt_supported;
|
||||
}
|
||||
|
||||
static void x86_iommu_device_iotlb_prop_set(Object *o, bool value, Error **errp)
|
||||
{
|
||||
X86IOMMUState *s = X86_IOMMU_DEVICE(o);
|
||||
s->dt_supported = value;
|
||||
}
|
||||
|
||||
static void x86_iommu_instance_init(Object *o)
|
||||
{
|
||||
X86IOMMUState *s = X86_IOMMU_DEVICE(o);
|
||||
@@ -114,6 +126,11 @@ static void x86_iommu_instance_init(Object *o)
|
||||
s->intr_supported = false;
|
||||
object_property_add_bool(o, "intremap", x86_iommu_intremap_prop_get,
|
||||
x86_iommu_intremap_prop_set, NULL);
|
||||
s->dt_supported = false;
|
||||
object_property_add_bool(o, "device-iotlb",
|
||||
x86_iommu_device_iotlb_prop_get,
|
||||
x86_iommu_device_iotlb_prop_set,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static const TypeInfo x86_iommu_info = {
|
||||
|
@@ -383,7 +383,7 @@ static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
|
||||
}
|
||||
}
|
||||
|
||||
static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
LM823KbdState *s = LM8323(i2c);
|
||||
|
||||
@@ -397,6 +397,8 @@ static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm_i2c_rx(I2CSlave *i2c)
|
||||
|
@@ -176,7 +176,7 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int tmp105_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
TMP105State *s = TMP105(i2c);
|
||||
|
||||
@@ -185,6 +185,7 @@ static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
|
||||
}
|
||||
|
||||
s->len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tmp105_post_load(void *opaque, int version_id)
|
||||
|
@@ -472,7 +472,8 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
|
||||
hw_error("Failed to initialize PM capability");
|
||||
}
|
||||
|
||||
if (pcie_aer_init(pci_dev, e1000e_aer_offset, PCI_ERR_SIZEOF) < 0) {
|
||||
if (pcie_aer_init(pci_dev, PCI_ERR_VER, e1000e_aer_offset,
|
||||
PCI_ERR_SIZEOF, NULL) < 0) {
|
||||
hw_error("Failed to initialize AER capability");
|
||||
}
|
||||
|
||||
|
@@ -358,25 +358,24 @@ void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr)
|
||||
/* Save flags before BD update */
|
||||
bd_flags = bd.flags;
|
||||
|
||||
if (bd_flags & BD_TX_READY) {
|
||||
process_tx_bd(etsec, &bd);
|
||||
|
||||
/* Write back BD after update */
|
||||
write_buffer_descriptor(etsec, bd_addr, &bd);
|
||||
if (!(bd_flags & BD_TX_READY)) {
|
||||
break;
|
||||
}
|
||||
|
||||
process_tx_bd(etsec, &bd);
|
||||
/* Write back BD after update */
|
||||
write_buffer_descriptor(etsec, bd_addr, &bd);
|
||||
|
||||
/* Wrap or next BD */
|
||||
if (bd_flags & BD_WRAP) {
|
||||
bd_addr = ring_base;
|
||||
} else {
|
||||
bd_addr += sizeof(eTSEC_rxtx_bd);
|
||||
}
|
||||
} while (TRUE);
|
||||
|
||||
} while (bd_addr != ring_base);
|
||||
|
||||
bd_addr = ring_base;
|
||||
|
||||
/* Save the Buffer Descriptor Pointers to current bd */
|
||||
/* Save the Buffer Descriptor Pointers to last bd that was not
|
||||
* succesfully closed */
|
||||
etsec->regs[TBPTR0 + ring_nbr].value = bd_addr;
|
||||
|
||||
/* Set transmit halt THLTx */
|
||||
|
@@ -1205,6 +1205,20 @@ static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
|
||||
s->RxBufAddr = 0;
|
||||
}
|
||||
|
||||
static void rtl8139_reset_phy(RTL8139State *s)
|
||||
{
|
||||
s->BasicModeStatus = 0x7809;
|
||||
s->BasicModeStatus |= 0x0020; /* autonegotiation completed */
|
||||
/* preserve link state */
|
||||
s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04;
|
||||
|
||||
s->NWayAdvert = 0x05e1; /* all modes, full duplex */
|
||||
s->NWayLPAR = 0x05e1; /* all modes, full duplex */
|
||||
s->NWayExpansion = 0x0001; /* autonegotiation supported */
|
||||
|
||||
s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
|
||||
}
|
||||
|
||||
static void rtl8139_reset(DeviceState *d)
|
||||
{
|
||||
RTL8139State *s = RTL8139(d);
|
||||
@@ -1256,25 +1270,14 @@ static void rtl8139_reset(DeviceState *d)
|
||||
s->Config3 = 0x1; /* fast back-to-back compatible */
|
||||
s->Config5 = 0x0;
|
||||
|
||||
s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
|
||||
|
||||
s->CpCmd = 0x0; /* reset C+ mode */
|
||||
s->cplus_enabled = 0;
|
||||
|
||||
|
||||
// s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation
|
||||
// s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex
|
||||
s->BasicModeCtrl = 0x1000; // autonegotiation
|
||||
|
||||
s->BasicModeStatus = 0x7809;
|
||||
//s->BasicModeStatus |= 0x0040; /* UTP medium */
|
||||
s->BasicModeStatus |= 0x0020; /* autonegotiation completed */
|
||||
/* preserve link state */
|
||||
s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04;
|
||||
|
||||
s->NWayAdvert = 0x05e1; /* all modes, full duplex */
|
||||
s->NWayLPAR = 0x05e1; /* all modes, full duplex */
|
||||
s->NWayExpansion = 0x0001; /* autonegotiation supported */
|
||||
rtl8139_reset_phy(s);
|
||||
|
||||
/* also reset timer and disable timer interrupt */
|
||||
s->TCTR = 0;
|
||||
@@ -1469,7 +1472,7 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val)
|
||||
DPRINTF("BasicModeCtrl register write(w) val=0x%04x\n", val);
|
||||
|
||||
/* mask unwritable bits */
|
||||
uint32_t mask = 0x4cff;
|
||||
uint32_t mask = 0xccff;
|
||||
|
||||
if (1 || !rtl8139_config_writable(s))
|
||||
{
|
||||
@@ -1479,6 +1482,11 @@ static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val)
|
||||
mask |= 0x0100;
|
||||
}
|
||||
|
||||
if (val & 0x8000) {
|
||||
/* Reset PHY */
|
||||
rtl8139_reset_phy(s);
|
||||
}
|
||||
|
||||
val = SET_MASKED(val, mask, s->BasicModeCtrl);
|
||||
|
||||
s->BasicModeCtrl = val;
|
||||
|
@@ -51,6 +51,7 @@ static const int kernel_feature_bits[] = {
|
||||
VIRTIO_RING_F_EVENT_IDX,
|
||||
VIRTIO_NET_F_MRG_RXBUF,
|
||||
VIRTIO_F_VERSION_1,
|
||||
VIRTIO_NET_F_MTU,
|
||||
VHOST_INVALID_FEATURE_BIT
|
||||
};
|
||||
|
||||
@@ -74,6 +75,7 @@ static const int user_feature_bits[] = {
|
||||
VIRTIO_NET_F_HOST_ECN,
|
||||
VIRTIO_NET_F_HOST_UFO,
|
||||
VIRTIO_NET_F_MRG_RXBUF,
|
||||
VIRTIO_NET_F_MTU,
|
||||
|
||||
/* This bit implies RARP isn't sent by QEMU out of band */
|
||||
VIRTIO_NET_F_GUEST_ANNOUNCE,
|
||||
@@ -435,6 +437,17 @@ int vhost_set_vring_enable(NetClientState *nc, int enable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
|
||||
{
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
|
||||
if (!vhost_ops->vhost_net_set_mtu) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return vhost_ops->vhost_net_set_mtu(&net->dev, mtu);
|
||||
}
|
||||
|
||||
#else
|
||||
uint64_t vhost_net_get_max_queues(VHostNetState *net)
|
||||
{
|
||||
@@ -501,4 +514,9 @@ int vhost_set_vring_enable(NetClientState *nc, int enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@@ -55,6 +55,8 @@ static VirtIOFeature feature_sizes[] = {
|
||||
.end = endof(struct virtio_net_config, status)},
|
||||
{.flags = 1 << VIRTIO_NET_F_MQ,
|
||||
.end = endof(struct virtio_net_config, max_virtqueue_pairs)},
|
||||
{.flags = 1 << VIRTIO_NET_F_MTU,
|
||||
.end = endof(struct virtio_net_config, mtu)},
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -81,6 +83,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
|
||||
|
||||
virtio_stw_p(vdev, &netcfg.status, n->status);
|
||||
virtio_stw_p(vdev, &netcfg.max_virtqueue_pairs, n->max_queues);
|
||||
virtio_stw_p(vdev, &netcfg.mtu, n->net_conf.mtu);
|
||||
memcpy(netcfg.mac, n->mac, ETH_ALEN);
|
||||
memcpy(config, &netcfg, n->config_size);
|
||||
}
|
||||
@@ -152,6 +155,16 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
|
||||
qemu_net_queue_purge(qnc->incoming_queue, qnc->peer);
|
||||
}
|
||||
|
||||
if (virtio_has_feature(vdev->guest_features, VIRTIO_NET_F_MTU)) {
|
||||
r = vhost_net_set_mtu(get_vhost_net(nc->peer), n->net_conf.mtu);
|
||||
if (r < 0) {
|
||||
error_report("%uBytes MTU not supported by the backend",
|
||||
n->net_conf.mtu);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
n->vhost_started = 1;
|
||||
r = vhost_net_start(vdev, n->nic->ncs, queues);
|
||||
if (r < 0) {
|
||||
@@ -218,6 +231,14 @@ static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status)
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
unsigned int dropped = virtqueue_drop_all(vq);
|
||||
if (dropped) {
|
||||
virtio_notify(vdev, vq);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
|
||||
{
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
@@ -262,6 +283,14 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
|
||||
} else {
|
||||
qemu_bh_cancel(q->tx_bh);
|
||||
}
|
||||
if ((n->status & VIRTIO_NET_S_LINK_UP) == 0 &&
|
||||
(queue_status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
||||
/* if tx is waiting we are likely have some packets in tx queue
|
||||
* and disabled notification */
|
||||
q->tx_waiting = 0;
|
||||
virtio_queue_set_notification(q->tx_vq, 1);
|
||||
virtio_net_drop_tx_queue_data(vdev, q->tx_vq);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1323,6 +1352,11 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
|
||||
|
||||
if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) {
|
||||
virtio_net_drop_tx_queue_data(vdev, vq);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This happens when device was stopped but VCPU wasn't. */
|
||||
if (!vdev->vm_running) {
|
||||
q->tx_waiting = 1;
|
||||
@@ -1349,6 +1383,11 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
|
||||
|
||||
if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) {
|
||||
virtio_net_drop_tx_queue_data(vdev, vq);
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(q->tx_waiting)) {
|
||||
return;
|
||||
}
|
||||
@@ -1695,6 +1734,7 @@ static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features)
|
||||
{
|
||||
int i, config_size = 0;
|
||||
virtio_add_feature(&host_features, VIRTIO_NET_F_MAC);
|
||||
|
||||
for (i = 0; feature_sizes[i].flags != 0; i++) {
|
||||
if (host_features & feature_sizes[i].flags) {
|
||||
config_size = MAX(feature_sizes[i].end, config_size);
|
||||
@@ -1724,6 +1764,10 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
|
||||
NetClientState *nc;
|
||||
int i;
|
||||
|
||||
if (n->net_conf.mtu) {
|
||||
n->host_features |= (0x1 << VIRTIO_NET_F_MTU);
|
||||
}
|
||||
|
||||
virtio_net_set_config_size(n, n->host_features);
|
||||
virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
|
||||
|
||||
@@ -1922,6 +1966,7 @@ static Property virtio_net_properties[] = {
|
||||
DEFINE_PROP_STRING("tx", VirtIONet, net_conf.tx),
|
||||
DEFINE_PROP_UINT16("rx_queue_size", VirtIONet, net_conf.rx_queue_size,
|
||||
VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE),
|
||||
DEFINE_PROP_UINT16("host_mtu", VirtIONet, net_conf.mtu, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@@ -135,8 +135,10 @@ static int ioh3420_initfn(PCIDevice *d)
|
||||
goto err_pcie_cap;
|
||||
}
|
||||
|
||||
rc = pcie_aer_init(d, IOH_EP_AER_OFFSET, PCI_ERR_SIZEOF);
|
||||
rc = pcie_aer_init(d, PCI_ERR_VER, IOH_EP_AER_OFFSET,
|
||||
PCI_ERR_SIZEOF, &err);
|
||||
if (rc < 0) {
|
||||
error_report_err(err);
|
||||
goto err;
|
||||
}
|
||||
pcie_aer_root_init(d);
|
||||
|
@@ -97,8 +97,10 @@ static int xio3130_downstream_initfn(PCIDevice *d)
|
||||
goto err_pcie_cap;
|
||||
}
|
||||
|
||||
rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF);
|
||||
rc = pcie_aer_init(d, PCI_ERR_VER, XIO3130_AER_OFFSET,
|
||||
PCI_ERR_SIZEOF, &err);
|
||||
if (rc < 0) {
|
||||
error_report_err(err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@@ -85,8 +85,10 @@ static int xio3130_upstream_initfn(PCIDevice *d)
|
||||
pcie_cap_flr_init(d);
|
||||
pcie_cap_deverr_init(d);
|
||||
|
||||
rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF);
|
||||
rc = pcie_aer_init(d, PCI_ERR_VER, XIO3130_AER_OFFSET,
|
||||
PCI_ERR_SIZEOF, &err);
|
||||
if (rc < 0) {
|
||||
error_report_err(err);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@@ -982,8 +982,8 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
|
||||
pci_get_function_0(pci_dev)) {
|
||||
error_setg(errp, "PCI: slot %d function 0 already ocuppied by %s,"
|
||||
" new func %s cannot be exposed to guest.",
|
||||
PCI_SLOT(devfn),
|
||||
bus->devices[PCI_DEVFN(PCI_SLOT(devfn), 0)]->name,
|
||||
PCI_SLOT(pci_get_function_0(pci_dev)->devfn),
|
||||
pci_get_function_0(pci_dev)->name,
|
||||
name);
|
||||
|
||||
return NULL;
|
||||
|
@@ -717,3 +717,18 @@ void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num)
|
||||
PCI_EXT_CAP_DSN_SIZEOF);
|
||||
pci_set_quad(dev->config + offset + pci_dsn_cap, ser_num);
|
||||
}
|
||||
|
||||
void pcie_ats_init(PCIDevice *dev, uint16_t offset)
|
||||
{
|
||||
pcie_add_capability(dev, PCI_EXT_CAP_ID_ATS, 0x1,
|
||||
offset, PCI_EXT_CAP_ATS_SIZEOF);
|
||||
|
||||
dev->exp.ats_cap = offset;
|
||||
|
||||
/* Invalidate Queue Depth 0, Page Aligned Request 0 */
|
||||
pci_set_word(dev->config + offset + PCI_ATS_CAP, 0);
|
||||
/* STU 0, Disabled by default */
|
||||
pci_set_word(dev->config + offset + PCI_ATS_CTRL, 0);
|
||||
|
||||
pci_set_word(dev->wmask + dev->exp.ats_cap + PCI_ATS_CTRL, 0x800f);
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "hw/pci/pcie_regs.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
//#define DEBUG_PCIE
|
||||
#ifdef DEBUG_PCIE
|
||||
@@ -96,21 +97,17 @@ static void aer_log_clear_all_err(PCIEAERLog *aer_log)
|
||||
aer_log->log_num = 0;
|
||||
}
|
||||
|
||||
int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size)
|
||||
int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver, uint16_t offset,
|
||||
uint16_t size, Error **errp)
|
||||
{
|
||||
PCIExpressDevice *exp;
|
||||
|
||||
pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, PCI_ERR_VER,
|
||||
pcie_add_capability(dev, PCI_EXT_CAP_ID_ERR, cap_ver,
|
||||
offset, size);
|
||||
exp = &dev->exp;
|
||||
exp->aer_cap = offset;
|
||||
dev->exp.aer_cap = offset;
|
||||
|
||||
/* log_max is property */
|
||||
if (dev->exp.aer_log.log_max == PCIE_AER_LOG_MAX_UNSET) {
|
||||
dev->exp.aer_log.log_max = PCIE_AER_LOG_MAX_DEFAULT;
|
||||
}
|
||||
/* clip down the value to avoid unreasobale memory usage */
|
||||
/* clip down the value to avoid unreasonable memory usage */
|
||||
if (dev->exp.aer_log.log_max > PCIE_AER_LOG_MAX_LIMIT) {
|
||||
error_setg(errp, "Invalid aer_log_max %d. The max number of aer log "
|
||||
"is %d", dev->exp.aer_log.log_max, PCIE_AER_LOG_MAX_LIMIT);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev->exp.aer_log.log = g_malloc0(sizeof dev->exp.aer_log.log[0] *
|
||||
|
@@ -1098,7 +1098,7 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
|
||||
* We do not support individual masking for channel devices, so we
|
||||
* need to manually trigger any guest masking callbacks here.
|
||||
*/
|
||||
if (k->guest_notifier_mask) {
|
||||
if (k->guest_notifier_mask && vdev->use_guest_notifier_mask) {
|
||||
k->guest_notifier_mask(vdev, n, false);
|
||||
}
|
||||
/* get lost events and re-inject */
|
||||
@@ -1107,7 +1107,7 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
|
||||
event_notifier_set(notifier);
|
||||
}
|
||||
} else {
|
||||
if (k->guest_notifier_mask) {
|
||||
if (k->guest_notifier_mask && vdev->use_guest_notifier_mask) {
|
||||
k->guest_notifier_mask(vdev, n, true);
|
||||
}
|
||||
if (with_irqfd) {
|
||||
|
@@ -198,12 +198,14 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
|
||||
SCSIBus *bus = sreq->bus;
|
||||
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
VirtIOSCSIReq *req;
|
||||
uint32_t n;
|
||||
|
||||
qemu_get_be32s(f, &n);
|
||||
assert(n < vs->conf.num_queues);
|
||||
req = qemu_get_virtqueue_element(f, sizeof(VirtIOSCSIReq) + vs->cdb_size);
|
||||
req = qemu_get_virtqueue_element(vdev, f,
|
||||
sizeof(VirtIOSCSIReq) + vs->cdb_size);
|
||||
virtio_scsi_init_req(s, vs->cmd_vqs[n], req);
|
||||
|
||||
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
|
||||
|
@@ -320,9 +320,6 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
TYPE_IMX_SPI, __func__);
|
||||
break;
|
||||
case ECSPI_TXDATA:
|
||||
case ECSPI_MSGDATA:
|
||||
/* Is there any difference between TXDATA and MSGDATA ? */
|
||||
/* I'll have to look in the linux driver */
|
||||
if (!imx_spi_is_enabled(s)) {
|
||||
/* Ignore writes if device is disabled */
|
||||
break;
|
||||
@@ -380,6 +377,14 @@ static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
}
|
||||
|
||||
break;
|
||||
case ECSPI_MSGDATA:
|
||||
/* it is not clear from the spec what MSGDATA is for */
|
||||
/* Anyway it is not used by Linux driver */
|
||||
/* So for now we just ignore it */
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"[%s]%s: Trying to write to MSGDATA, ignoring\n",
|
||||
TYPE_IMX_SPI, __func__);
|
||||
break;
|
||||
default:
|
||||
s->regs[index] = value;
|
||||
|
||||
|
@@ -94,7 +94,7 @@ static void inc_regptr(DS1338State *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int ds1338_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
DS1338State *s = DS1338(i2c);
|
||||
|
||||
@@ -113,6 +113,8 @@ static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ds1338_recv(I2CSlave *i2c)
|
||||
|
@@ -713,12 +713,14 @@ static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
|
||||
}
|
||||
}
|
||||
|
||||
static void menelaus_event(I2CSlave *i2c, enum i2c_event event)
|
||||
static int menelaus_event(I2CSlave *i2c, enum i2c_event event)
|
||||
{
|
||||
MenelausState *s = TWL92230(i2c);
|
||||
|
||||
if (event == I2C_START_SEND)
|
||||
s->firstbyte = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int menelaus_tx(I2CSlave *i2c, uint8_t data)
|
||||
|
@@ -15,6 +15,8 @@ virtio_rng_pushed(void *rng, size_t len) "rng %p: %zd bytes pushed"
|
||||
virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left"
|
||||
|
||||
# hw/virtio/virtio-balloon.c
|
||||
#
|
||||
virtio_balloon_bad_addr(uint64_t gpa) "%"PRIx64
|
||||
virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s gpa: %"PRIx64
|
||||
virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d"
|
||||
virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d"
|
||||
|
@@ -32,6 +32,7 @@ enum VhostUserProtocolFeature {
|
||||
VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
|
||||
VHOST_USER_PROTOCOL_F_RARP = 2,
|
||||
VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
|
||||
VHOST_USER_PROTOCOL_F_NET_MTU = 4,
|
||||
|
||||
VHOST_USER_PROTOCOL_F_MAX
|
||||
};
|
||||
@@ -59,6 +60,7 @@ typedef enum VhostUserRequest {
|
||||
VHOST_USER_GET_QUEUE_NUM = 17,
|
||||
VHOST_USER_SET_VRING_ENABLE = 18,
|
||||
VHOST_USER_SEND_RARP = 19,
|
||||
VHOST_USER_NET_SET_MTU = 20,
|
||||
VHOST_USER_MAX
|
||||
} VhostUserRequest;
|
||||
|
||||
@@ -186,6 +188,7 @@ static bool vhost_user_one_time_request(VhostUserRequest request)
|
||||
case VHOST_USER_RESET_OWNER:
|
||||
case VHOST_USER_SET_MEM_TABLE:
|
||||
case VHOST_USER_GET_QUEUE_NUM:
|
||||
case VHOST_USER_NET_SET_MTU:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -685,6 +688,36 @@ static bool vhost_user_can_merge(struct vhost_dev *dev,
|
||||
return mfd == rfd;
|
||||
}
|
||||
|
||||
static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu)
|
||||
{
|
||||
VhostUserMsg msg;
|
||||
bool reply_supported = virtio_has_feature(dev->protocol_features,
|
||||
VHOST_USER_PROTOCOL_F_REPLY_ACK);
|
||||
|
||||
if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg.request = VHOST_USER_NET_SET_MTU;
|
||||
msg.payload.u64 = mtu;
|
||||
msg.size = sizeof(msg.payload.u64);
|
||||
msg.flags = VHOST_USER_VERSION;
|
||||
if (reply_supported) {
|
||||
msg.flags |= VHOST_USER_NEED_REPLY_MASK;
|
||||
}
|
||||
|
||||
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If reply_ack supported, slave has to ack specified MTU is valid */
|
||||
if (reply_supported) {
|
||||
return process_message_reply(dev, msg.request);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const VhostOps user_ops = {
|
||||
.backend_type = VHOST_BACKEND_TYPE_USER,
|
||||
.vhost_backend_init = vhost_user_init,
|
||||
@@ -708,4 +741,5 @@ const VhostOps user_ops = {
|
||||
.vhost_requires_shm_log = vhost_user_requires_shm_log,
|
||||
.vhost_migration_done = vhost_user_migration_done,
|
||||
.vhost_backend_can_merge = vhost_user_can_merge,
|
||||
.vhost_net_set_mtu = vhost_user_net_set_mtu,
|
||||
};
|
||||
|
@@ -993,6 +993,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
|
||||
virtio_queue_set_last_avail_idx(vdev, idx, state.num);
|
||||
}
|
||||
virtio_queue_invalidate_signalled_used(vdev, idx);
|
||||
virtio_queue_update_used_idx(vdev, idx);
|
||||
|
||||
/* In the cross-endian case, we need to reset the vring endianness to
|
||||
* native as legacy devices expect so by default.
|
||||
|
@@ -228,8 +228,13 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
|
||||
/* FIXME: remove get_system_memory(), but how? */
|
||||
section = memory_region_find(get_system_memory(), pa, 1);
|
||||
if (!int128_nz(section.size) || !memory_region_is_ram(section.mr))
|
||||
if (!int128_nz(section.size) ||
|
||||
!memory_region_is_ram(section.mr) ||
|
||||
memory_region_is_rom(section.mr) ||
|
||||
memory_region_is_romd(section.mr)) {
|
||||
trace_virtio_balloon_bad_addr(pa);
|
||||
continue;
|
||||
}
|
||||
|
||||
trace_virtio_balloon_handle_output(memory_region_name(section.mr),
|
||||
pa);
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "hw/qdev.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
/* #define DEBUG_VIRTIO_BUS */
|
||||
|
||||
@@ -61,6 +62,13 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
|
||||
if (klass->device_plugged != NULL) {
|
||||
klass->device_plugged(qbus->parent, errp);
|
||||
}
|
||||
|
||||
if (klass->get_dma_as != NULL &&
|
||||
virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
|
||||
vdev->dma_as = klass->get_dma_as(qbus->parent);
|
||||
} else {
|
||||
vdev->dma_as = &address_space_memory;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the virtio_bus */
|
||||
|
@@ -31,6 +31,11 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||
VirtIOCryptoPCI *vcrypto = VIRTIO_CRYPTO_PCI(vpci_dev);
|
||||
DeviceState *vdev = DEVICE(&vcrypto->vdev);
|
||||
|
||||
if (vcrypto->vdev.conf.cryptodev == NULL) {
|
||||
error_setg(errp, "'cryptodev' parameter expects a valid object");
|
||||
return;
|
||||
}
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
virtio_pci_force_virtio_1(vpci_dev);
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
@@ -48,7 +53,6 @@ static void virtio_crypto_pci_class_init(ObjectClass *klass, void *data)
|
||||
k->realize = virtio_crypto_pci_realize;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
dc->props = virtio_crypto_pci_properties;
|
||||
dc->hotpluggable = false;
|
||||
pcidev_k->class_id = PCI_CLASS_OTHERS;
|
||||
}
|
||||
|
||||
|
@@ -337,7 +337,18 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req)
|
||||
{
|
||||
if (req) {
|
||||
if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
|
||||
g_free(req->u.sym_op_info);
|
||||
size_t max_len;
|
||||
CryptoDevBackendSymOpInfo *op_info = req->u.sym_op_info;
|
||||
|
||||
max_len = op_info->iv_len +
|
||||
op_info->aad_len +
|
||||
op_info->src_len +
|
||||
op_info->dst_len +
|
||||
op_info->digest_result_len;
|
||||
|
||||
/* Zeroize and free request data structure */
|
||||
memset(op_info, 0, sizeof(*op_info) + max_len);
|
||||
g_free(op_info);
|
||||
}
|
||||
g_free(req);
|
||||
}
|
||||
@@ -355,7 +366,7 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev,
|
||||
return;
|
||||
}
|
||||
|
||||
len = sym_op_info->dst_len;
|
||||
len = sym_op_info->src_len;
|
||||
/* Save the cipher result */
|
||||
s = iov_from_buf(req->in_iov, req->in_num, 0, sym_op_info->dst, len);
|
||||
if (s != len) {
|
||||
@@ -416,7 +427,7 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev,
|
||||
uint32_t hash_start_src_offset = 0, len_to_hash = 0;
|
||||
uint32_t cipher_start_src_offset = 0, len_to_cipher = 0;
|
||||
|
||||
size_t max_len, curr_size = 0;
|
||||
uint64_t max_len, curr_size = 0;
|
||||
size_t s;
|
||||
|
||||
/* Plain cipher */
|
||||
@@ -441,7 +452,7 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
max_len = iv_len + aad_len + src_len + dst_len + hash_result_len;
|
||||
max_len = (uint64_t)iv_len + aad_len + src_len + dst_len + hash_result_len;
|
||||
if (unlikely(max_len > vcrypto->conf.max_size)) {
|
||||
virtio_error(vdev, "virtio-crypto too big length");
|
||||
return NULL;
|
||||
@@ -732,7 +743,7 @@ static void virtio_crypto_reset(VirtIODevice *vdev)
|
||||
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
|
||||
/* multiqueue is disabled by default */
|
||||
vcrypto->curr_queues = 1;
|
||||
if (!vcrypto->cryptodev->ready) {
|
||||
if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) {
|
||||
vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY;
|
||||
} else {
|
||||
vcrypto->status |= VIRTIO_CRYPTO_S_HW_READY;
|
||||
@@ -792,13 +803,14 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
vcrypto->ctrl_vq = virtio_add_queue(vdev, 64, virtio_crypto_handle_ctrl);
|
||||
if (!vcrypto->cryptodev->ready) {
|
||||
if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) {
|
||||
vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY;
|
||||
} else {
|
||||
vcrypto->status |= VIRTIO_CRYPTO_S_HW_READY;
|
||||
}
|
||||
|
||||
virtio_crypto_init_config(vdev);
|
||||
cryptodev_backend_set_used(vcrypto->cryptodev, true);
|
||||
}
|
||||
|
||||
static void virtio_crypto_device_unrealize(DeviceState *dev, Error **errp)
|
||||
@@ -818,6 +830,7 @@ static void virtio_crypto_device_unrealize(DeviceState *dev, Error **errp)
|
||||
g_free(vcrypto->vqs);
|
||||
|
||||
virtio_cleanup(vdev);
|
||||
cryptodev_backend_set_used(vcrypto->cryptodev, false);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_virtio_crypto = {
|
||||
@@ -875,6 +888,20 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data)
|
||||
vdc->reset = virtio_crypto_reset;
|
||||
}
|
||||
|
||||
static void
|
||||
virtio_crypto_check_cryptodev_is_used(Object *obj, const char *name,
|
||||
Object *val, Error **errp)
|
||||
{
|
||||
if (cryptodev_backend_is_used(CRYPTODEV_BACKEND(val))) {
|
||||
char *path = object_get_canonical_path_component(val);
|
||||
error_setg(errp,
|
||||
"can't use already used cryptodev backend: %s", path);
|
||||
g_free(path);
|
||||
} else {
|
||||
qdev_prop_allow_set_link_before_realize(obj, name, val, errp);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_crypto_instance_init(Object *obj)
|
||||
{
|
||||
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(obj);
|
||||
@@ -888,7 +915,7 @@ static void virtio_crypto_instance_init(Object *obj)
|
||||
object_property_add_link(obj, "cryptodev",
|
||||
TYPE_CRYPTODEV_BACKEND,
|
||||
(Object **)&vcrypto->conf.cryptodev,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
virtio_crypto_check_cryptodev_is_used,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
|
||||
}
|
||||
|
||||
|
@@ -402,7 +402,7 @@ static int virtio_mmio_set_guest_notifier(DeviceState *d, int n, bool assign,
|
||||
event_notifier_cleanup(notifier);
|
||||
}
|
||||
|
||||
if (vdc->guest_notifier_mask) {
|
||||
if (vdc->guest_notifier_mask && vdev->use_guest_notifier_mask) {
|
||||
vdc->guest_notifier_mask(vdev, n, !assign);
|
||||
}
|
||||
|
||||
|
@@ -1144,6 +1144,14 @@ static int virtio_pci_query_nvectors(DeviceState *d)
|
||||
return proxy->nvectors;
|
||||
}
|
||||
|
||||
static AddressSpace *virtio_pci_get_dma_as(DeviceState *d)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
|
||||
PCIDevice *dev = &proxy->pci_dev;
|
||||
|
||||
return pci_get_address_space(dev);
|
||||
}
|
||||
|
||||
static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
|
||||
struct virtio_pci_cap *cap)
|
||||
{
|
||||
@@ -1601,6 +1609,11 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
|
||||
}
|
||||
|
||||
if (legacy) {
|
||||
if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
|
||||
error_setg(errp, "VIRTIO_F_IOMMU_PLATFORM was supported by"
|
||||
"neither legacy nor transitional device.");
|
||||
return ;
|
||||
}
|
||||
/* legacy and transitional */
|
||||
pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
|
||||
pci_get_word(config + PCI_VENDOR_ID));
|
||||
@@ -1802,6 +1815,11 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
|
||||
* PCI Power Management Interface Specification.
|
||||
*/
|
||||
pci_set_word(pci_dev->config + pos + PCI_PM_PMC, 0x3);
|
||||
|
||||
if (proxy->flags & VIRTIO_PCI_FLAG_ATS) {
|
||||
pcie_ats_init(pci_dev, 256);
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
* make future invocations of pci_is_express() return false
|
||||
@@ -1855,6 +1873,8 @@ static Property virtio_pci_properties[] = {
|
||||
VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, false),
|
||||
DEFINE_PROP_BOOL("x-ignore-backend-features", VirtIOPCIProxy,
|
||||
ignore_backend_features, false),
|
||||
DEFINE_PROP_BIT("ats", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_ATS_BIT, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -2520,6 +2540,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
|
||||
k->query_nvectors = virtio_pci_query_nvectors;
|
||||
k->ioeventfd_enabled = virtio_pci_ioeventfd_enabled;
|
||||
k->ioeventfd_assign = virtio_pci_ioeventfd_assign;
|
||||
k->get_dma_as = virtio_pci_get_dma_as;
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_pci_bus_info = {
|
||||
|
@@ -72,6 +72,7 @@ enum {
|
||||
VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT,
|
||||
VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT,
|
||||
VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT,
|
||||
VIRTIO_PCI_FLAG_ATS_BIT,
|
||||
};
|
||||
|
||||
/* Need to activate work-arounds for buggy guests at vmstate load. */
|
||||
@@ -96,6 +97,9 @@ enum {
|
||||
#define VIRTIO_PCI_FLAG_PAGE_PER_VQ \
|
||||
(1 << VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT)
|
||||
|
||||
/* address space translation service */
|
||||
#define VIRTIO_PCI_FLAG_ATS (1 << VIRTIO_PCI_FLAG_ATS_BIT)
|
||||
|
||||
typedef struct {
|
||||
MSIMessage msg;
|
||||
int virq;
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "migration/migration.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
#include "sysemu/dma.h"
|
||||
|
||||
/*
|
||||
* The alignment to use between consumer and producer parts of vring.
|
||||
@@ -92,7 +93,7 @@ struct VirtQueue
|
||||
|
||||
uint16_t queue_index;
|
||||
|
||||
int inuse;
|
||||
unsigned int inuse;
|
||||
|
||||
uint16_t vector;
|
||||
VirtIOHandleOutput handle_output;
|
||||
@@ -121,7 +122,7 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n)
|
||||
static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc,
|
||||
hwaddr desc_pa, int i)
|
||||
{
|
||||
address_space_read(&address_space_memory, desc_pa + i * sizeof(VRingDesc),
|
||||
address_space_read(vdev->dma_as, desc_pa + i * sizeof(VRingDesc),
|
||||
MEMTXATTRS_UNSPECIFIED, (void *)desc, sizeof(VRingDesc));
|
||||
virtio_tswap64s(vdev, &desc->addr);
|
||||
virtio_tswap32s(vdev, &desc->len);
|
||||
@@ -163,7 +164,7 @@ static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem,
|
||||
virtio_tswap32s(vq->vdev, &uelem->id);
|
||||
virtio_tswap32s(vq->vdev, &uelem->len);
|
||||
pa = vq->vring.used + offsetof(VRingUsed, ring[i]);
|
||||
address_space_write(&address_space_memory, pa, MEMTXATTRS_UNSPECIFIED,
|
||||
address_space_write(vq->vdev->dma_as, pa, MEMTXATTRS_UNSPECIFIED,
|
||||
(void *)uelem, sizeof(VRingUsedElem));
|
||||
}
|
||||
|
||||
@@ -249,6 +250,7 @@ int virtio_queue_empty(VirtQueue *vq)
|
||||
static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len)
|
||||
{
|
||||
AddressSpace *dma_as = vq->vdev->dma_as;
|
||||
unsigned int offset;
|
||||
int i;
|
||||
|
||||
@@ -256,17 +258,18 @@ static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
for (i = 0; i < elem->in_num; i++) {
|
||||
size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
|
||||
|
||||
cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
|
||||
elem->in_sg[i].iov_len,
|
||||
1, size);
|
||||
dma_memory_unmap(dma_as, elem->in_sg[i].iov_base,
|
||||
elem->in_sg[i].iov_len,
|
||||
DMA_DIRECTION_FROM_DEVICE, size);
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
||||
for (i = 0; i < elem->out_num; i++)
|
||||
cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
|
||||
elem->out_sg[i].iov_len,
|
||||
0, elem->out_sg[i].iov_len);
|
||||
dma_memory_unmap(dma_as, elem->out_sg[i].iov_base,
|
||||
elem->out_sg[i].iov_len,
|
||||
DMA_DIRECTION_TO_DEVICE,
|
||||
elem->out_sg[i].iov_len);
|
||||
}
|
||||
|
||||
/* virtqueue_detach_element:
|
||||
@@ -560,7 +563,10 @@ static bool virtqueue_map_desc(VirtIODevice *vdev, unsigned int *p_num_sg,
|
||||
goto out;
|
||||
}
|
||||
|
||||
iov[num_sg].iov_base = cpu_physical_memory_map(pa, &len, is_write);
|
||||
iov[num_sg].iov_base = dma_memory_map(vdev->dma_as, pa, &len,
|
||||
is_write ?
|
||||
DMA_DIRECTION_FROM_DEVICE :
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
if (!iov[num_sg].iov_base) {
|
||||
virtio_error(vdev, "virtio: bogus descriptor or out of resources");
|
||||
goto out;
|
||||
@@ -597,9 +603,9 @@ static void virtqueue_undo_map_desc(unsigned int out_num, unsigned int in_num,
|
||||
}
|
||||
}
|
||||
|
||||
static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
|
||||
unsigned int *num_sg, unsigned int max_size,
|
||||
int is_write)
|
||||
static void virtqueue_map_iovec(VirtIODevice *vdev, struct iovec *sg,
|
||||
hwaddr *addr, unsigned int *num_sg,
|
||||
unsigned int max_size, int is_write)
|
||||
{
|
||||
unsigned int i;
|
||||
hwaddr len;
|
||||
@@ -618,7 +624,10 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
|
||||
|
||||
for (i = 0; i < *num_sg; i++) {
|
||||
len = sg[i].iov_len;
|
||||
sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
|
||||
sg[i].iov_base = dma_memory_map(vdev->dma_as,
|
||||
addr[i], &len, is_write ?
|
||||
DMA_DIRECTION_FROM_DEVICE :
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
if (!sg[i].iov_base) {
|
||||
error_report("virtio: error trying to map MMIO memory");
|
||||
exit(1);
|
||||
@@ -630,12 +639,15 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
|
||||
}
|
||||
}
|
||||
|
||||
void virtqueue_map(VirtQueueElement *elem)
|
||||
void virtqueue_map(VirtIODevice *vdev, VirtQueueElement *elem)
|
||||
{
|
||||
virtqueue_map_iovec(elem->in_sg, elem->in_addr, &elem->in_num,
|
||||
VIRTQUEUE_MAX_SIZE, 1);
|
||||
virtqueue_map_iovec(elem->out_sg, elem->out_addr, &elem->out_num,
|
||||
VIRTQUEUE_MAX_SIZE, 0);
|
||||
virtqueue_map_iovec(vdev, elem->in_sg, elem->in_addr, &elem->in_num,
|
||||
MIN(ARRAY_SIZE(elem->in_sg), ARRAY_SIZE(elem->in_addr)),
|
||||
1);
|
||||
virtqueue_map_iovec(vdev, elem->out_sg, elem->out_addr, &elem->out_num,
|
||||
MIN(ARRAY_SIZE(elem->out_sg),
|
||||
ARRAY_SIZE(elem->out_addr)),
|
||||
0);
|
||||
}
|
||||
|
||||
static void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num)
|
||||
@@ -771,6 +783,44 @@ err_undo_map:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* virtqueue_drop_all:
|
||||
* @vq: The #VirtQueue
|
||||
* Drops all queued buffers and indicates them to the guest
|
||||
* as if they are done. Useful when buffers can not be
|
||||
* processed but must be returned to the guest.
|
||||
*/
|
||||
unsigned int virtqueue_drop_all(VirtQueue *vq)
|
||||
{
|
||||
unsigned int dropped = 0;
|
||||
VirtQueueElement elem = {};
|
||||
VirtIODevice *vdev = vq->vdev;
|
||||
bool fEventIdx = virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
|
||||
|
||||
if (unlikely(vdev->broken)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!virtio_queue_empty(vq) && vq->inuse < vq->vring.num) {
|
||||
/* works similar to virtqueue_pop but does not map buffers
|
||||
* and does not allocate any memory */
|
||||
smp_rmb();
|
||||
if (!virtqueue_get_head(vq, vq->last_avail_idx, &elem.index)) {
|
||||
break;
|
||||
}
|
||||
vq->inuse++;
|
||||
vq->last_avail_idx++;
|
||||
if (fEventIdx) {
|
||||
vring_set_avail_event(vq, vq->last_avail_idx);
|
||||
}
|
||||
/* immediately push the element, nothing to unmap
|
||||
* as both in_num and out_num are set to 0 */
|
||||
virtqueue_push(vq, &elem, 0);
|
||||
dropped++;
|
||||
}
|
||||
|
||||
return dropped;
|
||||
}
|
||||
|
||||
/* Reading and writing a structure directly to QEMUFile is *awful*, but
|
||||
* it is what QEMU has always done by mistake. We can change it sooner
|
||||
* or later by bumping the version number of the affected vm states.
|
||||
@@ -788,7 +838,7 @@ typedef struct VirtQueueElementOld {
|
||||
struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
|
||||
} VirtQueueElementOld;
|
||||
|
||||
void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz)
|
||||
void *qemu_get_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, size_t sz)
|
||||
{
|
||||
VirtQueueElement *elem;
|
||||
VirtQueueElementOld data;
|
||||
@@ -819,7 +869,7 @@ void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz)
|
||||
elem->out_sg[i].iov_len = data.out_sg[i].iov_len;
|
||||
}
|
||||
|
||||
virtqueue_map(elem);
|
||||
virtqueue_map(vdev, elem);
|
||||
return elem;
|
||||
}
|
||||
|
||||
@@ -878,6 +928,11 @@ static int virtio_validate_features(VirtIODevice *vdev)
|
||||
{
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
|
||||
if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM) &&
|
||||
!virtio_vdev_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (k->validate_features) {
|
||||
return k->validate_features(vdev);
|
||||
} else {
|
||||
@@ -1861,9 +1916,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
|
||||
/*
|
||||
* Some devices migrate VirtQueueElements that have been popped
|
||||
* from the avail ring but not yet returned to the used ring.
|
||||
* Since max ring size < UINT16_MAX it's safe to use modulo
|
||||
* UINT16_MAX + 1 subtraction.
|
||||
*/
|
||||
vdev->vq[i].inuse = vdev->vq[i].last_avail_idx -
|
||||
vdev->vq[i].used_idx;
|
||||
vdev->vq[i].inuse = (uint16_t)(vdev->vq[i].last_avail_idx -
|
||||
vdev->vq[i].used_idx);
|
||||
if (vdev->vq[i].inuse > vdev->vq[i].vring.num) {
|
||||
error_report("VQ %d size 0x%x < last_avail_idx 0x%x - "
|
||||
"used_idx 0x%x",
|
||||
@@ -2001,6 +2058,11 @@ void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
|
||||
vdev->vq[n].shadow_avail_idx = idx;
|
||||
}
|
||||
|
||||
void virtio_queue_update_used_idx(VirtIODevice *vdev, int n)
|
||||
{
|
||||
vdev->vq[n].used_idx = vring_used_idx(&vdev->vq[n]);
|
||||
}
|
||||
|
||||
void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n)
|
||||
{
|
||||
vdev->vq[n].signalled_used_valid = false;
|
||||
|
@@ -184,7 +184,7 @@ struct BlockDriver {
|
||||
|
||||
/*
|
||||
* Flushes all data that was already written to the OS all the way down to
|
||||
* the disk (for example raw-posix calls fsync()).
|
||||
* the disk (for example file-posix.c calls fsync()).
|
||||
*/
|
||||
int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs);
|
||||
|
||||
|
@@ -628,6 +628,9 @@ static inline bool memory_region_is_romd(MemoryRegion *mr)
|
||||
*/
|
||||
static inline bool memory_region_is_iommu(MemoryRegion *mr)
|
||||
{
|
||||
if (mr->alias) {
|
||||
return memory_region_is_iommu(mr->alias);
|
||||
}
|
||||
return mr->iommu_ops;
|
||||
}
|
||||
|
||||
@@ -1537,6 +1540,11 @@ void stl_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val);
|
||||
void stl_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint32_t val);
|
||||
void stq_le_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val);
|
||||
void stq_be_phys_cached(MemoryRegionCache *cache, hwaddr addr, uint64_t val);
|
||||
/* address_space_get_iotlb_entry: translate an address into an IOTLB
|
||||
* entry. Should be called from an RCU critical section.
|
||||
*/
|
||||
IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
|
||||
bool is_write);
|
||||
|
||||
/* address_space_translate: translate an address range into an address space
|
||||
* into a MemoryRegion and an address range into that section. Should be
|
||||
|
@@ -191,10 +191,8 @@ struct AcpiFadtDescriptorRev5_1 {
|
||||
|
||||
typedef struct AcpiFadtDescriptorRev5_1 AcpiFadtDescriptorRev5_1;
|
||||
|
||||
enum {
|
||||
ACPI_FADT_ARM_USE_PSCI_G_0_2 = 0,
|
||||
ACPI_FADT_ARM_PSCI_USE_HVC = 1,
|
||||
};
|
||||
#define ACPI_FADT_ARM_PSCI_COMPLIANT (1 << 0)
|
||||
#define ACPI_FADT_ARM_PSCI_USE_HVC (1 << 1)
|
||||
|
||||
/*
|
||||
* Serial Port Console Redirection Table (SPCR), Rev. 1.02
|
||||
@@ -290,7 +288,7 @@ typedef struct AcpiMultipleApicTable AcpiMultipleApicTable;
|
||||
#define ACPI_APIC_XRUPT_SOURCE 8
|
||||
#define ACPI_APIC_LOCAL_X2APIC 9
|
||||
#define ACPI_APIC_LOCAL_X2APIC_NMI 10
|
||||
#define ACPI_APIC_GENERIC_INTERRUPT 11
|
||||
#define ACPI_APIC_GENERIC_CPU_INTERFACE 11
|
||||
#define ACPI_APIC_GENERIC_DISTRIBUTOR 12
|
||||
#define ACPI_APIC_GENERIC_MSI_FRAME 13
|
||||
#define ACPI_APIC_GENERIC_REDISTRIBUTOR 14
|
||||
@@ -361,7 +359,7 @@ struct AcpiMadtLocalX2ApicNmi {
|
||||
} QEMU_PACKED;
|
||||
typedef struct AcpiMadtLocalX2ApicNmi AcpiMadtLocalX2ApicNmi;
|
||||
|
||||
struct AcpiMadtGenericInterrupt {
|
||||
struct AcpiMadtGenericCpuInterface {
|
||||
ACPI_SUB_HEADER_DEF
|
||||
uint16_t reserved;
|
||||
uint32_t cpu_interface_number;
|
||||
@@ -378,7 +376,10 @@ struct AcpiMadtGenericInterrupt {
|
||||
uint64_t arm_mpidr;
|
||||
} QEMU_PACKED;
|
||||
|
||||
typedef struct AcpiMadtGenericInterrupt AcpiMadtGenericInterrupt;
|
||||
typedef struct AcpiMadtGenericCpuInterface AcpiMadtGenericCpuInterface;
|
||||
|
||||
/* GICC CPU Interface Flags */
|
||||
#define ACPI_MADT_GICC_ENABLED 1
|
||||
|
||||
struct AcpiMadtGenericDistributor {
|
||||
ACPI_SUB_HEADER_DEF
|
||||
@@ -427,21 +428,9 @@ typedef struct AcpiMadtGenericTranslator AcpiMadtGenericTranslator;
|
||||
/*
|
||||
* Generic Timer Description Table (GTDT)
|
||||
*/
|
||||
|
||||
#define ACPI_GTDT_INTERRUPT_MODE (1 << 0)
|
||||
#define ACPI_GTDT_INTERRUPT_POLARITY (1 << 1)
|
||||
#define ACPI_GTDT_ALWAYS_ON (1 << 2)
|
||||
|
||||
/* Triggering */
|
||||
|
||||
#define ACPI_LEVEL_SENSITIVE ((uint8_t) 0x00)
|
||||
#define ACPI_EDGE_SENSITIVE ((uint8_t) 0x01)
|
||||
|
||||
/* Polarity */
|
||||
|
||||
#define ACPI_ACTIVE_HIGH ((uint8_t) 0x00)
|
||||
#define ACPI_ACTIVE_LOW ((uint8_t) 0x01)
|
||||
#define ACPI_ACTIVE_BOTH ((uint8_t) 0x02)
|
||||
#define ACPI_GTDT_INTERRUPT_MODE_LEVEL (0 << 0)
|
||||
#define ACPI_GTDT_INTERRUPT_MODE_EDGE (1 << 0)
|
||||
#define ACPI_GTDT_CAP_ALWAYS_ON (1 << 2)
|
||||
|
||||
struct AcpiGenericTimerTable {
|
||||
ACPI_TABLE_HEADER_DEF
|
||||
@@ -638,8 +627,20 @@ struct AcpiDmarHardwareUnit {
|
||||
} QEMU_PACKED;
|
||||
typedef struct AcpiDmarHardwareUnit AcpiDmarHardwareUnit;
|
||||
|
||||
/* Type 2: Root Port ATS Capability Reporting Structure */
|
||||
struct AcpiDmarRootPortATS {
|
||||
uint16_t type;
|
||||
uint16_t length;
|
||||
uint8_t flags;
|
||||
uint8_t reserved;
|
||||
uint16_t pci_segment;
|
||||
AcpiDmarDeviceScope scope[0];
|
||||
} QEMU_PACKED;
|
||||
typedef struct AcpiDmarRootPortATS AcpiDmarRootPortATS;
|
||||
|
||||
/* Masks for Flags field above */
|
||||
#define ACPI_DMAR_INCLUDE_PCI_ALL 1
|
||||
#define ACPI_DMAR_ATSR_ALL_PORTS 1
|
||||
|
||||
/*
|
||||
* Input Output Remapping Table (IORT)
|
||||
|
@@ -30,7 +30,7 @@ typedef struct MemHotplugState {
|
||||
} MemHotplugState;
|
||||
|
||||
void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
|
||||
MemHotplugState *state);
|
||||
MemHotplugState *state, uint16_t io_base);
|
||||
|
||||
void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
|
||||
DeviceState *dev, Error **errp);
|
||||
@@ -47,11 +47,7 @@ extern const VMStateDescription vmstate_memory_hotplug;
|
||||
|
||||
void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list);
|
||||
|
||||
#define MEMORY_HOTPLUG_DEVICE "MHPD"
|
||||
#define MEMORY_SLOT_SCAN_METHOD "MSCN"
|
||||
#define MEMORY_HOTPLUG_HANDLER_PATH "\\_SB.PCI0." \
|
||||
MEMORY_HOTPLUG_DEVICE "." MEMORY_SLOT_SCAN_METHOD
|
||||
|
||||
void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem,
|
||||
uint16_t io_base, uint16_t io_len);
|
||||
void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
|
||||
const char *res_root,
|
||||
const char *event_handler_method);
|
||||
#endif
|
||||
|
@@ -29,29 +29,6 @@
|
||||
#define PIIX4_CPU_HOTPLUG_IO_BASE 0xaf00
|
||||
#define CPU_HOTPLUG_RESOURCE_DEVICE PRES
|
||||
|
||||
#define ACPI_MEMORY_HOTPLUG_IO_LEN 24
|
||||
#define ACPI_MEMORY_HOTPLUG_BASE 0x0a00
|
||||
|
||||
#define MEMORY_SLOTS_NUMBER "MDNR"
|
||||
#define MEMORY_HOTPLUG_IO_REGION "HPMR"
|
||||
#define MEMORY_SLOT_ADDR_LOW "MRBL"
|
||||
#define MEMORY_SLOT_ADDR_HIGH "MRBH"
|
||||
#define MEMORY_SLOT_SIZE_LOW "MRLL"
|
||||
#define MEMORY_SLOT_SIZE_HIGH "MRLH"
|
||||
#define MEMORY_SLOT_PROXIMITY "MPX"
|
||||
#define MEMORY_SLOT_ENABLED "MES"
|
||||
#define MEMORY_SLOT_INSERT_EVENT "MINS"
|
||||
#define MEMORY_SLOT_REMOVE_EVENT "MRMV"
|
||||
#define MEMORY_SLOT_EJECT "MEJ"
|
||||
#define MEMORY_SLOT_SLECTOR "MSEL"
|
||||
#define MEMORY_SLOT_OST_EVENT "MOEV"
|
||||
#define MEMORY_SLOT_OST_STATUS "MOSC"
|
||||
#define MEMORY_SLOT_LOCK "MLCK"
|
||||
#define MEMORY_SLOT_STATUS_METHOD "MRST"
|
||||
#define MEMORY_SLOT_CRS_METHOD "MCRS"
|
||||
#define MEMORY_SLOT_OST_METHOD "MOST"
|
||||
#define MEMORY_SLOT_PROXIMITY_METHOD "MPXM"
|
||||
#define MEMORY_SLOT_EJECT_METHOD "MEJ0"
|
||||
#define MEMORY_SLOT_NOTIFY_METHOD "MTFY"
|
||||
|
||||
#endif
|
||||
|
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD.
|
||||
*
|
||||
* Author: Shannon Zhao <zhaoshenglong@huawei.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_VIRT_ACPI_BUILD_H
|
||||
#define QEMU_VIRT_ACPI_BUILD_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "hw/arm/virt.h"
|
||||
#include "qemu/notify.h"
|
||||
|
||||
#define ACPI_GICC_ENABLED 1
|
||||
|
||||
typedef struct VirtGuestInfo {
|
||||
int smp_cpus;
|
||||
FWCfgState *fw_cfg;
|
||||
const MemMapEntry *memmap;
|
||||
const int *irqmap;
|
||||
bool use_highmem;
|
||||
int gic_version;
|
||||
bool no_its;
|
||||
} VirtGuestInfo;
|
||||
|
||||
|
||||
typedef struct VirtGuestInfoState {
|
||||
VirtGuestInfo info;
|
||||
Notifier machine_done;
|
||||
} VirtGuestInfoState;
|
||||
|
||||
void virt_acpi_setup(VirtGuestInfo *guest_info);
|
||||
|
||||
#endif
|
@@ -32,6 +32,9 @@
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "exec/hwaddr.h"
|
||||
#include "qemu/notify.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/arm/arm.h"
|
||||
|
||||
#define NUM_GICV2M_SPIS 64
|
||||
#define NUM_VIRTIO_TRANSPORTS 32
|
||||
@@ -74,5 +77,41 @@ typedef struct MemMapEntry {
|
||||
hwaddr size;
|
||||
} MemMapEntry;
|
||||
|
||||
typedef struct {
|
||||
MachineClass parent;
|
||||
bool disallow_affinity_adjustment;
|
||||
bool no_its;
|
||||
bool no_pmu;
|
||||
bool claim_edge_triggered_timers;
|
||||
} VirtMachineClass;
|
||||
|
||||
#endif
|
||||
typedef struct {
|
||||
MachineState parent;
|
||||
Notifier machine_done;
|
||||
FWCfgState *fw_cfg;
|
||||
bool secure;
|
||||
bool highmem;
|
||||
int32_t gic_version;
|
||||
struct arm_boot_info bootinfo;
|
||||
const MemMapEntry *memmap;
|
||||
const int *irqmap;
|
||||
int smp_cpus;
|
||||
void *fdt;
|
||||
int fdt_size;
|
||||
uint32_t clock_phandle;
|
||||
uint32_t gic_phandle;
|
||||
uint32_t msi_phandle;
|
||||
bool using_psci;
|
||||
} VirtMachineState;
|
||||
|
||||
#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
|
||||
#define VIRT_MACHINE(obj) \
|
||||
OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE)
|
||||
#define VIRT_MACHINE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE)
|
||||
#define VIRT_MACHINE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
|
||||
|
||||
void virt_acpi_setup(VirtMachineState *vms);
|
||||
|
||||
#endif /* QEMU_ARM_VIRT_H */
|
||||
|
@@ -32,14 +32,22 @@ typedef struct I2CSlaveClass
|
||||
/* Callbacks provided by the device. */
|
||||
int (*init)(I2CSlave *dev);
|
||||
|
||||
/* Master to slave. */
|
||||
/* Master to slave. Returns non-zero for a NAK, 0 for success. */
|
||||
int (*send)(I2CSlave *s, uint8_t data);
|
||||
|
||||
/* Slave to master. */
|
||||
/*
|
||||
* Slave to master. This cannot fail, the device should always
|
||||
* return something here. Negative values probably result in 0xff
|
||||
* and a possible log from the driver, and shouldn't be used.
|
||||
*/
|
||||
int (*recv)(I2CSlave *s);
|
||||
|
||||
/* Notify the slave of a bus state change. */
|
||||
void (*event)(I2CSlave *s, enum i2c_event event);
|
||||
/*
|
||||
* Notify the slave of a bus state change. For start event,
|
||||
* returns non-zero to NAK an operation. For other events the
|
||||
* return code is not used and should be zero.
|
||||
*/
|
||||
int (*event)(I2CSlave *s, enum i2c_event event);
|
||||
} I2CSlaveClass;
|
||||
|
||||
struct I2CSlave
|
||||
|
@@ -73,6 +73,7 @@ typedef struct IEC_Notifier IEC_Notifier;
|
||||
struct X86IOMMUState {
|
||||
SysBusDevice busdev;
|
||||
bool intr_supported; /* Whether vIOMMU supports IR */
|
||||
bool dt_supported; /* Whether vIOMMU supports DT */
|
||||
IommuType type; /* IOMMU type - AMD/Intel */
|
||||
QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */
|
||||
};
|
||||
|
@@ -74,6 +74,9 @@ struct PCIExpressDevice {
|
||||
/* AER */
|
||||
uint16_t aer_cap;
|
||||
PCIEAERLog aer_log;
|
||||
|
||||
/* Offset of ATS capability in config space */
|
||||
uint16_t ats_cap;
|
||||
};
|
||||
|
||||
#define COMPAT_PROP_PCP "power_controller_present"
|
||||
@@ -120,6 +123,7 @@ void pcie_add_capability(PCIDevice *dev,
|
||||
|
||||
void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
|
||||
void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
|
||||
void pcie_ats_init(PCIDevice *dev, uint16_t offset);
|
||||
|
||||
extern const VMStateDescription vmstate_pcie_device;
|
||||
|
||||
|
@@ -44,7 +44,6 @@ struct PCIEAERLog {
|
||||
*/
|
||||
#define PCIE_AER_LOG_MAX_DEFAULT 8
|
||||
#define PCIE_AER_LOG_MAX_LIMIT 128
|
||||
#define PCIE_AER_LOG_MAX_UNSET 0xffff
|
||||
uint16_t log_max;
|
||||
|
||||
/* Error log. log_max-sized array */
|
||||
@@ -87,7 +86,8 @@ struct PCIEAERErr {
|
||||
|
||||
extern const VMStateDescription vmstate_pcie_aer_log;
|
||||
|
||||
int pcie_aer_init(PCIDevice *dev, uint16_t offset, uint16_t size);
|
||||
int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver, uint16_t offset,
|
||||
uint16_t size, Error **errp);
|
||||
void pcie_aer_exit(PCIDevice *dev);
|
||||
void pcie_aer_write_config(PCIDevice *dev,
|
||||
uint32_t addr, uint32_t val, int len);
|
||||
|
@@ -32,6 +32,7 @@ typedef int (*vhost_backend_memslots_limit)(struct vhost_dev *dev);
|
||||
|
||||
typedef int (*vhost_net_set_backend_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_file *file);
|
||||
typedef int (*vhost_net_set_mtu_op)(struct vhost_dev *dev, uint16_t mtu);
|
||||
typedef int (*vhost_scsi_set_endpoint_op)(struct vhost_dev *dev,
|
||||
struct vhost_scsi_target *target);
|
||||
typedef int (*vhost_scsi_clear_endpoint_op)(struct vhost_dev *dev,
|
||||
@@ -83,6 +84,7 @@ typedef struct VhostOps {
|
||||
vhost_backend_cleanup vhost_backend_cleanup;
|
||||
vhost_backend_memslots_limit vhost_backend_memslots_limit;
|
||||
vhost_net_set_backend_op vhost_net_set_backend;
|
||||
vhost_net_set_mtu_op vhost_net_set_mtu;
|
||||
vhost_scsi_set_endpoint_op vhost_scsi_set_endpoint;
|
||||
vhost_scsi_clear_endpoint_op vhost_scsi_clear_endpoint;
|
||||
vhost_scsi_get_abi_version_op vhost_scsi_get_abi_version;
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#define QEMU_VIRTIO_ACCESS_H
|
||||
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
#if defined(TARGET_PPC64) || defined(TARGET_ARM)
|
||||
@@ -40,45 +41,55 @@ static inline bool virtio_access_is_big_endian(VirtIODevice *vdev)
|
||||
|
||||
static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa)
|
||||
{
|
||||
AddressSpace *dma_as = vdev->dma_as;
|
||||
|
||||
if (virtio_access_is_big_endian(vdev)) {
|
||||
return lduw_be_phys(&address_space_memory, pa);
|
||||
return lduw_be_phys(dma_as, pa);
|
||||
}
|
||||
return lduw_le_phys(&address_space_memory, pa);
|
||||
return lduw_le_phys(dma_as, pa);
|
||||
}
|
||||
|
||||
static inline uint32_t virtio_ldl_phys(VirtIODevice *vdev, hwaddr pa)
|
||||
{
|
||||
AddressSpace *dma_as = vdev->dma_as;
|
||||
|
||||
if (virtio_access_is_big_endian(vdev)) {
|
||||
return ldl_be_phys(&address_space_memory, pa);
|
||||
return ldl_be_phys(dma_as, pa);
|
||||
}
|
||||
return ldl_le_phys(&address_space_memory, pa);
|
||||
return ldl_le_phys(dma_as, pa);
|
||||
}
|
||||
|
||||
static inline uint64_t virtio_ldq_phys(VirtIODevice *vdev, hwaddr pa)
|
||||
{
|
||||
AddressSpace *dma_as = vdev->dma_as;
|
||||
|
||||
if (virtio_access_is_big_endian(vdev)) {
|
||||
return ldq_be_phys(&address_space_memory, pa);
|
||||
return ldq_be_phys(dma_as, pa);
|
||||
}
|
||||
return ldq_le_phys(&address_space_memory, pa);
|
||||
return ldq_le_phys(dma_as, pa);
|
||||
}
|
||||
|
||||
static inline void virtio_stw_phys(VirtIODevice *vdev, hwaddr pa,
|
||||
uint16_t value)
|
||||
{
|
||||
AddressSpace *dma_as = vdev->dma_as;
|
||||
|
||||
if (virtio_access_is_big_endian(vdev)) {
|
||||
stw_be_phys(&address_space_memory, pa, value);
|
||||
stw_be_phys(dma_as, pa, value);
|
||||
} else {
|
||||
stw_le_phys(&address_space_memory, pa, value);
|
||||
stw_le_phys(dma_as, pa, value);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void virtio_stl_phys(VirtIODevice *vdev, hwaddr pa,
|
||||
uint32_t value)
|
||||
{
|
||||
AddressSpace *dma_as = vdev->dma_as;
|
||||
|
||||
if (virtio_access_is_big_endian(vdev)) {
|
||||
stl_be_phys(&address_space_memory, pa, value);
|
||||
stl_be_phys(dma_as, pa, value);
|
||||
} else {
|
||||
stl_le_phys(&address_space_memory, pa, value);
|
||||
stl_le_phys(dma_as, pa, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -88,6 +88,7 @@ typedef struct VirtioBusClass {
|
||||
* Note that changing this will break migration for this transport.
|
||||
*/
|
||||
bool has_variable_vring_alignment;
|
||||
AddressSpace *(*get_dma_as)(DeviceState *d);
|
||||
} VirtioBusClass;
|
||||
|
||||
struct VirtioBusState {
|
||||
|
@@ -36,6 +36,7 @@ typedef struct virtio_net_conf
|
||||
int32_t txburst;
|
||||
char *tx;
|
||||
uint16_t rx_queue_size;
|
||||
uint16_t mtu;
|
||||
} virtio_net_conf;
|
||||
|
||||
/* Maximum packet size we can receive from tap device: header + 64k */
|
||||
|
@@ -92,6 +92,7 @@ struct VirtIODevice
|
||||
char *bus_name;
|
||||
uint8_t device_endian;
|
||||
bool use_guest_notifier_mask;
|
||||
AddressSpace *dma_as;
|
||||
QLIST_HEAD(, VirtQueue) *vector_queues;
|
||||
};
|
||||
|
||||
@@ -170,9 +171,10 @@ bool virtqueue_rewind(VirtQueue *vq, unsigned int num);
|
||||
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len, unsigned int idx);
|
||||
|
||||
void virtqueue_map(VirtQueueElement *elem);
|
||||
void virtqueue_map(VirtIODevice *vdev, VirtQueueElement *elem);
|
||||
void *virtqueue_pop(VirtQueue *vq, size_t sz);
|
||||
void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz);
|
||||
unsigned int virtqueue_drop_all(VirtQueue *vq);
|
||||
void *qemu_get_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, size_t sz);
|
||||
void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem);
|
||||
int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
|
||||
unsigned int out_bytes);
|
||||
@@ -255,7 +257,9 @@ typedef struct VirtIORNGConf VirtIORNGConf;
|
||||
DEFINE_PROP_BIT64("notify_on_empty", _state, _field, \
|
||||
VIRTIO_F_NOTIFY_ON_EMPTY, true), \
|
||||
DEFINE_PROP_BIT64("any_layout", _state, _field, \
|
||||
VIRTIO_F_ANY_LAYOUT, true)
|
||||
VIRTIO_F_ANY_LAYOUT, true), \
|
||||
DEFINE_PROP_BIT64("iommu_platform", _state, _field, \
|
||||
VIRTIO_F_IOMMU_PLATFORM, false)
|
||||
|
||||
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
|
||||
hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
|
||||
@@ -266,6 +270,7 @@ hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n);
|
||||
uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n);
|
||||
void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
|
||||
void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n);
|
||||
void virtio_queue_update_used_idx(VirtIODevice *vdev, int n);
|
||||
VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
|
||||
uint16_t virtio_get_queue_index(VirtQueue *vq);
|
||||
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
|
||||
|
@@ -186,6 +186,12 @@ enum VMStateFlags {
|
||||
VMS_MULTIPLY_ELEMENTS = 0x4000,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
MIG_PRI_DEFAULT = 0,
|
||||
MIG_PRI_IOMMU, /* Must happen before PCI devices */
|
||||
MIG_PRI_MAX,
|
||||
} MigrationPriority;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
size_t offset;
|
||||
@@ -207,6 +213,7 @@ struct VMStateDescription {
|
||||
int version_id;
|
||||
int minimum_version_id;
|
||||
int minimum_version_id_old;
|
||||
MigrationPriority priority;
|
||||
LoadStateHandler *load_state_old;
|
||||
int (*pre_load)(void *opaque);
|
||||
int (*post_load)(void *opaque, int version_id);
|
||||
|
@@ -35,4 +35,6 @@ int vhost_set_vring_enable(NetClientState * nc, int enable);
|
||||
|
||||
uint64_t vhost_net_get_acked_features(VHostNetState *net);
|
||||
|
||||
int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
|
||||
|
||||
#endif
|
||||
|
@@ -70,6 +70,12 @@ Coroutine *qemu_coroutine_create(CoroutineEntry *entry, void *opaque);
|
||||
*/
|
||||
void qemu_coroutine_enter(Coroutine *coroutine);
|
||||
|
||||
/**
|
||||
* Transfer control to a coroutine if it's not active (i.e. part of the call
|
||||
* stack of the running coroutine). Otherwise, do nothing.
|
||||
*/
|
||||
void qemu_coroutine_enter_if_inactive(Coroutine *co);
|
||||
|
||||
/**
|
||||
* Transfer control back to a coroutine's caller
|
||||
*
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user