diff options
Diffstat (limited to 'hw')
554 files changed, 9437 insertions, 36439 deletions
diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c index 3d77594f9..894041488 100644 --- a/hw/9pfs/9p-handle.c +++ b/hw/9pfs/9p-handle.c @@ -112,7 +112,7 @@ static int handle_close(FsContext *ctx, V9fsFidOpenState *fs) static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs) { - return closedir(fs->dir.stream); + return closedir(fs->dir); } static int handle_open(FsContext *ctx, V9fsPath *fs_path, @@ -132,8 +132,8 @@ static int handle_opendir(FsContext *ctx, if (ret < 0) { return -1; } - fs->dir.stream = fdopendir(ret); - if (!fs->dir.stream) { + fs->dir = fdopendir(ret); + if (!fs->dir) { return -1; } return 0; @@ -141,22 +141,24 @@ static int handle_opendir(FsContext *ctx, static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) { - rewinddir(fs->dir.stream); + rewinddir(fs->dir); } static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs) { - return telldir(fs->dir.stream); + return telldir(fs->dir); } -static struct dirent *handle_readdir(FsContext *ctx, V9fsFidOpenState *fs) +static int handle_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, + struct dirent *entry, + struct dirent **result) { - return readdir(fs->dir.stream); + return readdir_r(fs->dir, entry, result); } static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) { - seekdir(fs->dir.stream, off); + seekdir(fs->dir, off); } static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs, @@ -260,7 +262,7 @@ static int handle_fstat(FsContext *fs_ctx, int fid_type, int fd; if (fid_type == P9_FID_DIR) { - fd = dirfd(fs->dir.stream); + fd = dirfd(fs->dir); } else { fd = fs->fd; } @@ -407,7 +409,7 @@ static int handle_fsync(FsContext *ctx, int fid_type, int fd; if (fid_type == P9_FID_DIR) { - fd = dirfd(fs->dir.stream); + fd = dirfd(fs->dir); } else { fd = fs->fd; } @@ -679,7 +681,7 @@ FileOperations handle_ops = { .opendir = handle_opendir, .rewinddir = handle_rewinddir, .telldir = handle_telldir, - .readdir = handle_readdir, + .readdir_r = handle_readdir_r, .seekdir = handle_seekdir, .preadv = handle_preadv, .pwritev = handle_pwritev, diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 3f271fcbd..16f45f485 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -348,7 +348,7 @@ static int local_close(FsContext *ctx, V9fsFidOpenState *fs) static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs) { - return closedir(fs->dir.stream); + return closedir(fs->dir); } static int local_open(FsContext *ctx, V9fsPath *fs_path, @@ -370,9 +370,9 @@ static int local_opendir(FsContext *ctx, char *path = fs_path->data; buffer = rpath(ctx, path); - fs->dir.stream = opendir(buffer); + fs->dir = opendir(buffer); g_free(buffer); - if (!fs->dir.stream) { + if (!fs->dir) { return -1; } return 0; @@ -380,40 +380,38 @@ static int local_opendir(FsContext *ctx, static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) { - rewinddir(fs->dir.stream); + rewinddir(fs->dir); } static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs) { - return telldir(fs->dir.stream); + return telldir(fs->dir); } -static struct dirent *local_readdir(FsContext *ctx, V9fsFidOpenState *fs) +static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, + struct dirent *entry, + struct dirent **result) { - struct dirent *entry; + int ret; again: - entry = readdir(fs->dir.stream); - if (!entry) { - return NULL; - } - + ret = readdir_r(fs->dir, entry, result); if (ctx->export_flags & V9FS_SM_MAPPED) { entry->d_type = DT_UNKNOWN; } else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) { - if (!strcmp(entry->d_name, VIRTFS_META_DIR)) { + if (!ret && *result != NULL && + !strcmp(entry->d_name, VIRTFS_META_DIR)) { /* skp the meta data directory */ goto again; } entry->d_type = DT_UNKNOWN; } - - return entry; + return ret; } static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) { - seekdir(fs->dir.stream, off); + seekdir(fs->dir, off); } static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs, @@ -612,7 +610,7 @@ static int local_fstat(FsContext *fs_ctx, int fid_type, int err, fd; if (fid_type == P9_FID_DIR) { - fd = dirfd(fs->dir.stream); + fd = dirfd(fs->dir); } else { fd = fs->fd; } @@ -1000,7 +998,7 @@ static int local_fsync(FsContext *ctx, int fid_type, int fd; if (fid_type == P9_FID_DIR) { - fd = dirfd(fs->dir.stream); + fd = dirfd(fs->dir); } else { fd = fs->fd; } @@ -1256,7 +1254,7 @@ FileOperations local_ops = { .opendir = local_opendir, .rewinddir = local_rewinddir, .telldir = local_telldir, - .readdir = local_readdir, + .readdir_r = local_readdir_r, .seekdir = local_seekdir, .preadv = local_preadv, .pwritev = local_pwritev, diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index f265501ea..00a4eb2a7 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -633,7 +633,7 @@ static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs) static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs) { - return closedir(fs->dir.stream); + return closedir(fs->dir); } static int proxy_open(FsContext *ctx, V9fsPath *fs_path, @@ -652,14 +652,14 @@ static int proxy_opendir(FsContext *ctx, { int serrno, fd; - fs->dir.stream = NULL; + fs->dir = NULL; fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, O_DIRECTORY); if (fd < 0) { errno = -fd; return -1; } - fs->dir.stream = fdopendir(fd); - if (!fs->dir.stream) { + fs->dir = fdopendir(fd); + if (!fs->dir) { serrno = errno; close(fd); errno = serrno; @@ -670,22 +670,24 @@ static int proxy_opendir(FsContext *ctx, static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) { - rewinddir(fs->dir.stream); + rewinddir(fs->dir); } static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs) { - return telldir(fs->dir.stream); + return telldir(fs->dir); } -static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs) +static int proxy_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, + struct dirent *entry, + struct dirent **result) { - return readdir(fs->dir.stream); + return readdir_r(fs->dir, entry, result); } static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) { - seekdir(fs->dir.stream, off); + seekdir(fs->dir, off); } static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs, @@ -789,7 +791,7 @@ static int proxy_fstat(FsContext *fs_ctx, int fid_type, int fd; if (fid_type == P9_FID_DIR) { - fd = dirfd(fs->dir.stream); + fd = dirfd(fs->dir); } else { fd = fs->fd; } @@ -934,7 +936,7 @@ static int proxy_fsync(FsContext *ctx, int fid_type, int fd; if (fid_type == P9_FID_DIR) { - fd = dirfd(fs->dir.stream); + fd = dirfd(fs->dir); } else { fd = fs->fd; } @@ -1190,7 +1192,7 @@ FileOperations proxy_ops = { .opendir = proxy_opendir, .rewinddir = proxy_rewinddir, .telldir = proxy_telldir, - .readdir = proxy_readdir, + .readdir_r = proxy_readdir_r, .seekdir = proxy_seekdir, .preadv = proxy_preadv, .pwritev = proxy_pwritev, diff --git a/hw/9pfs/9p-proxy.h b/hw/9pfs/9p-proxy.h index b84301d00..ba9ca203d 100644 --- a/hw/9pfs/9p-proxy.h +++ b/hw/9pfs/9p-proxy.h @@ -9,9 +9,8 @@ * This work is licensed under the terms of the GNU GPL, version 2. See * the COPYING file in the top-level directory. */ - -#ifndef QEMU_9P_PROXY_H -#define QEMU_9P_PROXY_H +#ifndef _QEMU_9P_PROXY_H +#define _QEMU_9P_PROXY_H #define PROXY_MAX_IO_SZ (64 * 1024) #define V9FS_FD_VALID INT_MAX diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index 4b6d4e6a3..f1475dfd6 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -1,5 +1,5 @@ /* - * 9p synthetic file system support + * Virtio 9p synthetic file system support * * Copyright IBM, Corp. 2011 * @@ -13,7 +13,9 @@ */ #include "qemu/osdep.h" +#include "hw/virtio/virtio.h" #include "9p.h" +#include "9p-xattr.h" #include "fsdev/qemu-fsdev.h" #include "9p-synth.h" #include "qemu/rcu.h" @@ -21,19 +23,19 @@ #include "qemu/cutils.h" /* Root node for synth file system */ -static V9fsSynthNode synth_root = { +static V9fsSynthNode v9fs_synth_root = { .name = "/", .actual_attr = { .mode = 0555 | S_IFDIR, .nlink = 1, }, - .attr = &synth_root.actual_attr, + .attr = &v9fs_synth_root.actual_attr, }; -static QemuMutex synth_mutex; -static int synth_node_count; +static QemuMutex v9fs_synth_mutex; +static int v9fs_synth_node_count; /* set to 1 when the synth fs is ready */ -static int synth_fs; +static int v9fs_synth_fs; static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode, const char *name, @@ -69,16 +71,16 @@ int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, int ret; V9fsSynthNode *node, *tmp; - if (!synth_fs) { + if (!v9fs_synth_fs) { return EAGAIN; } if (!name || (strlen(name) >= NAME_MAX)) { return EINVAL; } if (!parent) { - parent = &synth_root; + parent = &v9fs_synth_root; } - qemu_mutex_lock(&synth_mutex); + qemu_mutex_lock(&v9fs_synth_mutex); QLIST_FOREACH(tmp, &parent->child, sibling) { if (!strcmp(tmp->name, name)) { ret = EEXIST; @@ -86,7 +88,7 @@ int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, } } /* Add the name */ - node = v9fs_add_dir_node(parent, mode, name, NULL, synth_node_count++); + node = v9fs_add_dir_node(parent, mode, name, NULL, v9fs_synth_node_count++); v9fs_add_dir_node(node, parent->attr->mode, "..", parent->attr, parent->attr->inode); v9fs_add_dir_node(node, node->attr->mode, ".", @@ -94,7 +96,7 @@ int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, *result = node; ret = 0; err_out: - qemu_mutex_unlock(&synth_mutex); + qemu_mutex_unlock(&v9fs_synth_mutex); return ret; } @@ -105,17 +107,17 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, int ret; V9fsSynthNode *node, *tmp; - if (!synth_fs) { + if (!v9fs_synth_fs) { return EAGAIN; } if (!name || (strlen(name) >= NAME_MAX)) { return EINVAL; } if (!parent) { - parent = &synth_root; + parent = &v9fs_synth_root; } - qemu_mutex_lock(&synth_mutex); + qemu_mutex_lock(&v9fs_synth_mutex); QLIST_FOREACH(tmp, &parent->child, sibling) { if (!strcmp(tmp->name, name)) { ret = EEXIST; @@ -126,7 +128,7 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, mode = ((mode & 0777) | S_IFREG); node = g_malloc0(sizeof(V9fsSynthNode)); node->attr = &node->actual_attr; - node->attr->inode = synth_node_count++; + node->attr->inode = v9fs_synth_node_count++; node->attr->nlink = 1; node->attr->read = read; node->attr->write = write; @@ -136,11 +138,11 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling); ret = 0; err_out: - qemu_mutex_unlock(&synth_mutex); + qemu_mutex_unlock(&v9fs_synth_mutex); return ret; } -static void synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf) +static void v9fs_synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf) { stbuf->st_dev = 0; stbuf->st_ino = node->attr->inode; @@ -157,24 +159,24 @@ static void synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf) stbuf->st_ctime = 0; } -static int synth_lstat(FsContext *fs_ctx, +static int v9fs_synth_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) { V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data; - synth_fill_statbuf(node, stbuf); + v9fs_synth_fill_statbuf(node, stbuf); return 0; } -static int synth_fstat(FsContext *fs_ctx, int fid_type, +static int v9fs_synth_fstat(FsContext *fs_ctx, int fid_type, V9fsFidOpenState *fs, struct stat *stbuf) { V9fsSynthOpenState *synth_open = fs->private; - synth_fill_statbuf(synth_open->node, stbuf); + v9fs_synth_fill_statbuf(synth_open->node, stbuf); return 0; } -static int synth_opendir(FsContext *ctx, +static int v9fs_synth_opendir(FsContext *ctx, V9fsPath *fs_path, V9fsFidOpenState *fs) { V9fsSynthOpenState *synth_open; @@ -187,7 +189,7 @@ static int synth_opendir(FsContext *ctx, return 0; } -static int synth_closedir(FsContext *ctx, V9fsFidOpenState *fs) +static int v9fs_synth_closedir(FsContext *ctx, V9fsFidOpenState *fs) { V9fsSynthOpenState *synth_open = fs->private; V9fsSynthNode *node = synth_open->node; @@ -198,24 +200,24 @@ static int synth_closedir(FsContext *ctx, V9fsFidOpenState *fs) return 0; } -static off_t synth_telldir(FsContext *ctx, V9fsFidOpenState *fs) +static off_t v9fs_synth_telldir(FsContext *ctx, V9fsFidOpenState *fs) { V9fsSynthOpenState *synth_open = fs->private; return synth_open->offset; } -static void synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) +static void v9fs_synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) { V9fsSynthOpenState *synth_open = fs->private; synth_open->offset = off; } -static void synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) +static void v9fs_synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) { - synth_seekdir(ctx, fs, 0); + v9fs_synth_seekdir(ctx, fs, 0); } -static void synth_direntry(V9fsSynthNode *node, +static void v9fs_synth_direntry(V9fsSynthNode *node, struct dirent *entry, off_t off) { strcpy(entry->d_name, node->name); @@ -223,8 +225,8 @@ static void synth_direntry(V9fsSynthNode *node, entry->d_off = off + 1; } -static struct dirent *synth_get_dentry(V9fsSynthNode *dir, - struct dirent *entry, off_t off) +static int v9fs_synth_get_dentry(V9fsSynthNode *dir, struct dirent *entry, + struct dirent **result, off_t off) { int i = 0; V9fsSynthNode *node; @@ -240,25 +242,28 @@ static struct dirent *synth_get_dentry(V9fsSynthNode *dir, rcu_read_unlock(); if (!node) { /* end of directory */ - return NULL; + *result = NULL; + return 0; } - synth_direntry(node, entry, off); - return entry; + v9fs_synth_direntry(node, entry, off); + *result = entry; + return 0; } -static struct dirent *synth_readdir(FsContext *ctx, V9fsFidOpenState *fs) +static int v9fs_synth_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, + struct dirent *entry, struct dirent **result) { - struct dirent *entry; + int ret; V9fsSynthOpenState *synth_open = fs->private; V9fsSynthNode *node = synth_open->node; - entry = synth_get_dentry(node, &synth_open->dent, synth_open->offset); - if (entry) { + ret = v9fs_synth_get_dentry(node, entry, result, synth_open->offset); + if (!ret && *result != NULL) { synth_open->offset++; } - return entry; + return ret; } -static int synth_open(FsContext *ctx, V9fsPath *fs_path, +static int v9fs_synth_open(FsContext *ctx, V9fsPath *fs_path, int flags, V9fsFidOpenState *fs) { V9fsSynthOpenState *synth_open; @@ -271,7 +276,7 @@ static int synth_open(FsContext *ctx, V9fsPath *fs_path, return 0; } -static int synth_open2(FsContext *fs_ctx, V9fsPath *dir_path, +static int v9fs_synth_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, int flags, FsCred *credp, V9fsFidOpenState *fs) { @@ -279,7 +284,7 @@ static int synth_open2(FsContext *fs_ctx, V9fsPath *dir_path, return -1; } -static int synth_close(FsContext *ctx, V9fsFidOpenState *fs) +static int v9fs_synth_close(FsContext *ctx, V9fsFidOpenState *fs) { V9fsSynthOpenState *synth_open = fs->private; V9fsSynthNode *node = synth_open->node; @@ -290,7 +295,7 @@ static int synth_close(FsContext *ctx, V9fsFidOpenState *fs) return 0; } -static ssize_t synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs, +static ssize_t v9fs_synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs, const struct iovec *iov, int iovcnt, off_t offset) { @@ -314,7 +319,7 @@ static ssize_t synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs, return count; } -static ssize_t synth_preadv(FsContext *ctx, V9fsFidOpenState *fs, +static ssize_t v9fs_synth_preadv(FsContext *ctx, V9fsFidOpenState *fs, const struct iovec *iov, int iovcnt, off_t offset) { @@ -338,112 +343,112 @@ static ssize_t synth_preadv(FsContext *ctx, V9fsFidOpenState *fs, return count; } -static int synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset) +static int v9fs_synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset) { errno = ENOSYS; return -1; } -static int synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp) +static int v9fs_synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp) { errno = EPERM; return -1; } -static int synth_mknod(FsContext *fs_ctx, V9fsPath *path, +static int v9fs_synth_mknod(FsContext *fs_ctx, V9fsPath *path, const char *buf, FsCred *credp) { errno = EPERM; return -1; } -static int synth_mkdir(FsContext *fs_ctx, V9fsPath *path, +static int v9fs_synth_mkdir(FsContext *fs_ctx, V9fsPath *path, const char *buf, FsCred *credp) { errno = EPERM; return -1; } -static ssize_t synth_readlink(FsContext *fs_ctx, V9fsPath *path, +static ssize_t v9fs_synth_readlink(FsContext *fs_ctx, V9fsPath *path, char *buf, size_t bufsz) { errno = ENOSYS; return -1; } -static int synth_symlink(FsContext *fs_ctx, const char *oldpath, +static int v9fs_synth_symlink(FsContext *fs_ctx, const char *oldpath, V9fsPath *newpath, const char *buf, FsCred *credp) { errno = EPERM; return -1; } -static int synth_link(FsContext *fs_ctx, V9fsPath *oldpath, +static int v9fs_synth_link(FsContext *fs_ctx, V9fsPath *oldpath, V9fsPath *newpath, const char *buf) { errno = EPERM; return -1; } -static int synth_rename(FsContext *ctx, const char *oldpath, +static int v9fs_synth_rename(FsContext *ctx, const char *oldpath, const char *newpath) { errno = EPERM; return -1; } -static int synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp) +static int v9fs_synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp) { errno = EPERM; return -1; } -static int synth_utimensat(FsContext *fs_ctx, V9fsPath *path, +static int v9fs_synth_utimensat(FsContext *fs_ctx, V9fsPath *path, const struct timespec *buf) { errno = EPERM; return 0; } -static int synth_remove(FsContext *ctx, const char *path) +static int v9fs_synth_remove(FsContext *ctx, const char *path) { errno = EPERM; return -1; } -static int synth_fsync(FsContext *ctx, int fid_type, +static int v9fs_synth_fsync(FsContext *ctx, int fid_type, V9fsFidOpenState *fs, int datasync) { errno = ENOSYS; return 0; } -static int synth_statfs(FsContext *s, V9fsPath *fs_path, +static int v9fs_synth_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) { stbuf->f_type = 0xABCD; stbuf->f_bsize = 512; stbuf->f_blocks = 0; - stbuf->f_files = synth_node_count; + stbuf->f_files = v9fs_synth_node_count; stbuf->f_namelen = NAME_MAX; return 0; } -static ssize_t synth_lgetxattr(FsContext *ctx, V9fsPath *path, +static ssize_t v9fs_synth_lgetxattr(FsContext *ctx, V9fsPath *path, const char *name, void *value, size_t size) { errno = ENOTSUP; return -1; } -static ssize_t synth_llistxattr(FsContext *ctx, V9fsPath *path, +static ssize_t v9fs_synth_llistxattr(FsContext *ctx, V9fsPath *path, void *value, size_t size) { errno = ENOTSUP; return -1; } -static int synth_lsetxattr(FsContext *ctx, V9fsPath *path, +static int v9fs_synth_lsetxattr(FsContext *ctx, V9fsPath *path, const char *name, void *value, size_t size, int flags) { @@ -451,14 +456,14 @@ static int synth_lsetxattr(FsContext *ctx, V9fsPath *path, return -1; } -static int synth_lremovexattr(FsContext *ctx, +static int v9fs_synth_lremovexattr(FsContext *ctx, V9fsPath *path, const char *name) { errno = ENOTSUP; return -1; } -static int synth_name_to_path(FsContext *ctx, V9fsPath *dir_path, +static int v9fs_synth_name_to_path(FsContext *ctx, V9fsPath *dir_path, const char *name, V9fsPath *target) { V9fsSynthNode *node; @@ -471,7 +476,7 @@ static int synth_name_to_path(FsContext *ctx, V9fsPath *dir_path, } if (!dir_path) { - dir_node = &synth_root; + dir_node = &v9fs_synth_root; } else { dir_node = *(V9fsSynthNode **)dir_path->data; } @@ -500,7 +505,7 @@ out: return 0; } -static int synth_renameat(FsContext *ctx, V9fsPath *olddir, +static int v9fs_synth_renameat(FsContext *ctx, V9fsPath *olddir, const char *old_name, V9fsPath *newdir, const char *new_name) { @@ -508,62 +513,62 @@ static int synth_renameat(FsContext *ctx, V9fsPath *olddir, return -1; } -static int synth_unlinkat(FsContext *ctx, V9fsPath *dir, +static int v9fs_synth_unlinkat(FsContext *ctx, V9fsPath *dir, const char *name, int flags) { errno = EPERM; return -1; } -static int synth_init(FsContext *ctx) +static int v9fs_synth_init(FsContext *ctx) { - QLIST_INIT(&synth_root.child); - qemu_mutex_init(&synth_mutex); + QLIST_INIT(&v9fs_synth_root.child); + qemu_mutex_init(&v9fs_synth_mutex); /* Add "." and ".." entries for root */ - v9fs_add_dir_node(&synth_root, synth_root.attr->mode, - "..", synth_root.attr, synth_root.attr->inode); - v9fs_add_dir_node(&synth_root, synth_root.attr->mode, - ".", synth_root.attr, synth_root.attr->inode); + v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode, + "..", v9fs_synth_root.attr, v9fs_synth_root.attr->inode); + v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode, + ".", v9fs_synth_root.attr, v9fs_synth_root.attr->inode); /* Mark the subsystem is ready for use */ - synth_fs = 1; + v9fs_synth_fs = 1; return 0; } FileOperations synth_ops = { - .init = synth_init, - .lstat = synth_lstat, - .readlink = synth_readlink, - .close = synth_close, - .closedir = synth_closedir, - .open = synth_open, - .opendir = synth_opendir, - .rewinddir = synth_rewinddir, - .telldir = synth_telldir, - .readdir = synth_readdir, - .seekdir = synth_seekdir, - .preadv = synth_preadv, - .pwritev = synth_pwritev, - .chmod = synth_chmod, - .mknod = synth_mknod, - .mkdir = synth_mkdir, - .fstat = synth_fstat, - .open2 = synth_open2, - .symlink = synth_symlink, - .link = synth_link, - .truncate = synth_truncate, - .rename = synth_rename, - .chown = synth_chown, - .utimensat = synth_utimensat, - .remove = synth_remove, - .fsync = synth_fsync, - .statfs = synth_statfs, - .lgetxattr = synth_lgetxattr, - .llistxattr = synth_llistxattr, - .lsetxattr = synth_lsetxattr, - .lremovexattr = synth_lremovexattr, - .name_to_path = synth_name_to_path, - .renameat = synth_renameat, - .unlinkat = synth_unlinkat, + .init = v9fs_synth_init, + .lstat = v9fs_synth_lstat, + .readlink = v9fs_synth_readlink, + .close = v9fs_synth_close, + .closedir = v9fs_synth_closedir, + .open = v9fs_synth_open, + .opendir = v9fs_synth_opendir, + .rewinddir = v9fs_synth_rewinddir, + .telldir = v9fs_synth_telldir, + .readdir_r = v9fs_synth_readdir_r, + .seekdir = v9fs_synth_seekdir, + .preadv = v9fs_synth_preadv, + .pwritev = v9fs_synth_pwritev, + .chmod = v9fs_synth_chmod, + .mknod = v9fs_synth_mknod, + .mkdir = v9fs_synth_mkdir, + .fstat = v9fs_synth_fstat, + .open2 = v9fs_synth_open2, + .symlink = v9fs_synth_symlink, + .link = v9fs_synth_link, + .truncate = v9fs_synth_truncate, + .rename = v9fs_synth_rename, + .chown = v9fs_synth_chown, + .utimensat = v9fs_synth_utimensat, + .remove = v9fs_synth_remove, + .fsync = v9fs_synth_fsync, + .statfs = v9fs_synth_statfs, + .lgetxattr = v9fs_synth_lgetxattr, + .llistxattr = v9fs_synth_llistxattr, + .lsetxattr = v9fs_synth_lsetxattr, + .lremovexattr = v9fs_synth_lremovexattr, + .name_to_path = v9fs_synth_name_to_path, + .renameat = v9fs_synth_renameat, + .unlinkat = v9fs_synth_unlinkat, }; diff --git a/hw/9pfs/9p-synth.h b/hw/9pfs/9p-synth.h index 6bcb44ace..82962512a 100644 --- a/hw/9pfs/9p-synth.h +++ b/hw/9pfs/9p-synth.h @@ -10,9 +10,9 @@ * the COPYING file in the top-level directory. * */ +#ifndef HW_9PFS_SYNTH_H +#define HW_9PFS_SYNTH_H 1 -#ifndef QEMU_9P_SYNTH_H -#define QEMU_9P_SYNTH_H typedef struct V9fsSynthNode V9fsSynthNode; typedef ssize_t (*v9fs_synth_read)(void *buf, int len, off_t offset, @@ -40,7 +40,6 @@ struct V9fsSynthNode { typedef struct V9fsSynthOpenState { off_t offset; V9fsSynthNode *node; - struct dirent dent; } V9fsSynthOpenState; extern int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, diff --git a/hw/9pfs/9p-xattr.h b/hw/9pfs/9p-xattr.h index a853ea641..4d39a2026 100644 --- a/hw/9pfs/9p-xattr.h +++ b/hw/9pfs/9p-xattr.h @@ -10,9 +10,8 @@ * the COPYING file in the top-level directory. * */ - -#ifndef QEMU_9P_XATTR_H -#define QEMU_9P_XATTR_H +#ifndef _QEMU_9P_XATTR_H +#define _QEMU_9P_XATTR_H #include "qemu/xattr.h" diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index dfe293d11..f5e30125f 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "hw/virtio/virtio.h" +#include "hw/i386/pc.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/iov.h" @@ -231,7 +232,7 @@ static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f) } while (err == -EINTR && !pdu->cancelled); } } else if (f->fid_type == P9_FID_DIR) { - if (f->fs.dir.stream == NULL) { + if (f->fs.dir == NULL) { do { err = v9fs_co_opendir(pdu, f); } while (err == -EINTR && !pdu->cancelled); @@ -300,9 +301,6 @@ static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid) f->next = s->fid_list; s->fid_list = f; - v9fs_readdir_init(&f->fs.dir); - v9fs_readdir_init(&f->fs_reclaim.dir); - return f; } @@ -348,7 +346,7 @@ static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp) retval = v9fs_co_close(pdu, &fidp->fs); } } else if (fidp->fid_type == P9_FID_DIR) { - if (fidp->fs.dir.stream != NULL) { + if (fidp->fs.dir != NULL) { retval = v9fs_co_closedir(pdu, &fidp->fs); } } else if (fidp->fid_type == P9_FID_XATTR) { @@ -446,7 +444,7 @@ void v9fs_reclaim_fd(V9fsPDU *pdu) reclaim_count++; } } else if (f->fid_type == P9_FID_DIR) { - if (f->fs.dir.stream != NULL) { + if (f->fs.dir != NULL) { /* * Up the reference count so that * a clunk request won't free this fid @@ -454,8 +452,8 @@ void v9fs_reclaim_fd(V9fsPDU *pdu) f->ref++; f->rclm_lst = reclaim_list; reclaim_list = f; - f->fs_reclaim.dir.stream = f->fs.dir.stream; - f->fs.dir.stream = NULL; + f->fs_reclaim.dir = f->fs.dir; + f->fs.dir = NULL; reclaim_count++; } } @@ -1010,7 +1008,6 @@ static void v9fs_attach(void *opaque) goto out; } err += offset; - memcpy(&s->root_qid, &qid, sizeof(qid)); trace_v9fs_attach_return(pdu->tag, pdu->id, qid.type, qid.version, qid.path); /* @@ -1257,19 +1254,6 @@ static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids) return offset; } -static bool name_is_illegal(const char *name) -{ - return !*name || strchr(name, '/') != NULL; -} - -static bool not_same_qid(const V9fsQID *qid1, const V9fsQID *qid2) -{ - return - qid1->type != qid2->type || - qid1->version != qid2->version || - qid1->path != qid2->path; -} - static void v9fs_walk(void *opaque) { int name_idx; @@ -1285,7 +1269,6 @@ static void v9fs_walk(void *opaque) V9fsFidState *newfidp = NULL; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; - V9fsQID qid; err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames); if (err < 0) { @@ -1304,10 +1287,6 @@ static void v9fs_walk(void *opaque) if (err < 0) { goto out_nofid; } - if (name_is_illegal(wnames[i].data)) { - err = -ENOENT; - goto out_nofid; - } offset += err; } } else if (nwnames > P9_MAXWELEM) { @@ -1319,12 +1298,6 @@ static void v9fs_walk(void *opaque) err = -ENOENT; goto out_nofid; } - - err = fid_to_qid(pdu, fidp, &qid); - if (err < 0) { - goto out; - } - v9fs_path_init(&dpath); v9fs_path_init(&path); /* @@ -1334,22 +1307,16 @@ static void v9fs_walk(void *opaque) v9fs_path_copy(&dpath, &fidp->path); v9fs_path_copy(&path, &fidp->path); for (name_idx = 0; name_idx < nwnames; name_idx++) { - if (not_same_qid(&pdu->s->root_qid, &qid) || - strcmp("..", wnames[name_idx].data)) { - err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, - &path); - if (err < 0) { - goto out; - } - - err = v9fs_co_lstat(pdu, &path, &stbuf); - if (err < 0) { - goto out; - } - stat_to_qid(&stbuf, &qid); - v9fs_path_copy(&dpath, &path); + err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path); + if (err < 0) { + goto out; } - memcpy(&qids[name_idx], &qid, sizeof(qid)); + err = v9fs_co_lstat(pdu, &path, &stbuf); + if (err < 0) { + goto out; + } + stat_to_qid(&stbuf, &qids[name_idx]); + v9fs_path_copy(&dpath, &path); } if (fid == newfid) { BUG_ON(fidp->fid_type != P9_FID_NONE); @@ -1514,16 +1481,6 @@ static void v9fs_lcreate(void *opaque) } trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid); - if (name_is_illegal(name.data)) { - err = -ENOENT; - goto out_nofid; - } - - if (!strcmp(".", name.data) || !strcmp("..", name.data)) { - err = -EEXIST; - goto out_nofid; - } - fidp = get_fid(pdu, dfid); if (fidp == NULL) { err = -ENOENT; @@ -1668,7 +1625,7 @@ static int v9fs_do_readdir_with_stat(V9fsPDU *pdu, int32_t count = 0; struct stat stbuf; off_t saved_dir_pos; - struct dirent *dent; + struct dirent *dent, *result; /* save the directory position */ saved_dir_pos = v9fs_co_telldir(pdu, fidp); @@ -1676,37 +1633,34 @@ static int v9fs_do_readdir_with_stat(V9fsPDU *pdu, return saved_dir_pos; } + dent = g_malloc(sizeof(struct dirent)); + while (1) { v9fs_path_init(&path); - - v9fs_readdir_lock(&fidp->fs.dir); - - err = v9fs_co_readdir(pdu, fidp, &dent); - if (err || !dent) { + err = v9fs_co_readdir_r(pdu, fidp, dent, &result); + if (err || !result) { break; } err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path); if (err < 0) { - break; + goto out; } err = v9fs_co_lstat(pdu, &path, &stbuf); if (err < 0) { - break; + goto out; } err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat); if (err < 0) { - break; + goto out; } /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */ len = pdu_marshal(pdu, 11 + count, "S", &v9stat); - - v9fs_readdir_unlock(&fidp->fs.dir); - if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) { /* Ran out of buffer. Set dir back to old position and return */ v9fs_co_seekdir(pdu, fidp, saved_dir_pos); v9fs_stat_free(&v9stat); v9fs_path_free(&path); + g_free(dent); return count; } count += len; @@ -1714,9 +1668,8 @@ static int v9fs_do_readdir_with_stat(V9fsPDU *pdu, v9fs_path_free(&path); saved_dir_pos = dent->d_off; } - - v9fs_readdir_unlock(&fidp->fs.dir); - +out: + g_free(dent); v9fs_path_free(&path); if (err < 0) { return err; @@ -1852,7 +1805,7 @@ static int v9fs_do_readdir(V9fsPDU *pdu, int len, err = 0; int32_t count = 0; off_t saved_dir_pos; - struct dirent *dent; + struct dirent *dent, *result; /* save the directory position */ saved_dir_pos = v9fs_co_telldir(pdu, fidp); @@ -1860,21 +1813,20 @@ static int v9fs_do_readdir(V9fsPDU *pdu, return saved_dir_pos; } - while (1) { - v9fs_readdir_lock(&fidp->fs.dir); + dent = g_malloc(sizeof(struct dirent)); - err = v9fs_co_readdir(pdu, fidp, &dent); - if (err || !dent) { + while (1) { + err = v9fs_co_readdir_r(pdu, fidp, dent, &result); + if (err || !result) { break; } v9fs_string_init(&name); v9fs_string_sprintf(&name, "%s", dent->d_name); if ((count + v9fs_readdir_data_size(&name)) > max_count) { - v9fs_readdir_unlock(&fidp->fs.dir); - /* Ran out of buffer. Set dir back to old position and return */ v9fs_co_seekdir(pdu, fidp, saved_dir_pos); v9fs_string_free(&name); + g_free(dent); return count; } /* @@ -1892,21 +1844,17 @@ static int v9fs_do_readdir(V9fsPDU *pdu, len = pdu_marshal(pdu, 11 + count, "Qqbs", &qid, dent->d_off, dent->d_type, &name); - - v9fs_readdir_unlock(&fidp->fs.dir); - if (len < 0) { v9fs_co_seekdir(pdu, fidp, saved_dir_pos); v9fs_string_free(&name); + g_free(dent); return len; } count += len; v9fs_string_free(&name); saved_dir_pos = dent->d_off; } - - v9fs_readdir_unlock(&fidp->fs.dir); - + g_free(dent); if (err < 0) { return err; } @@ -1936,7 +1884,7 @@ static void v9fs_readdir(void *opaque) retval = -EINVAL; goto out_nofid; } - if (!fidp->fs.dir.stream) { + if (!fidp->fs.dir) { retval = -EINVAL; goto out; } @@ -2118,16 +2066,6 @@ static void v9fs_create(void *opaque) } trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode); - if (name_is_illegal(name.data)) { - err = -ENOENT; - goto out_nofid; - } - - if (!strcmp(".", name.data) || !strcmp("..", name.data)) { - err = -EEXIST; - goto out_nofid; - } - fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -EINVAL; @@ -2293,16 +2231,6 @@ static void v9fs_symlink(void *opaque) } trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid); - if (name_is_illegal(name.data)) { - err = -ENOENT; - goto out_nofid; - } - - if (!strcmp(".", name.data) || !strcmp("..", name.data)) { - err = -EEXIST; - goto out_nofid; - } - dfidp = get_fid(pdu, dfid); if (dfidp == NULL) { err = -EINVAL; @@ -2377,16 +2305,6 @@ static void v9fs_link(void *opaque) } trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data); - if (name_is_illegal(name.data)) { - err = -ENOENT; - goto out_nofid; - } - - if (!strcmp(".", name.data) || !strcmp("..", name.data)) { - err = -EEXIST; - goto out_nofid; - } - dfidp = get_fid(pdu, dfid); if (dfidp == NULL) { err = -ENOENT; @@ -2469,22 +2387,6 @@ static void v9fs_unlinkat(void *opaque) if (err < 0) { goto out_nofid; } - - if (name_is_illegal(name.data)) { - err = -ENOENT; - goto out_nofid; - } - - if (!strcmp(".", name.data)) { - err = -EINVAL; - goto out_nofid; - } - - if (!strcmp("..", name.data)) { - err = -ENOTEMPTY; - goto out_nofid; - } - dfidp = get_fid(pdu, dfid); if (dfidp == NULL) { err = -EINVAL; @@ -2591,17 +2493,6 @@ static void v9fs_rename(void *opaque) if (err < 0) { goto out_nofid; } - - if (name_is_illegal(name.data)) { - err = -ENOENT; - goto out_nofid; - } - - if (!strcmp(".", name.data) || !strcmp("..", name.data)) { - err = -EISDIR; - goto out_nofid; - } - fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -2714,17 +2605,6 @@ static void v9fs_renameat(void *opaque) goto out_err; } - if (name_is_illegal(old_name.data) || name_is_illegal(new_name.data)) { - err = -ENOENT; - goto out_err; - } - - if (!strcmp(".", old_name.data) || !strcmp("..", old_name.data) || - !strcmp(".", new_name.data) || !strcmp("..", new_name.data)) { - err = -EISDIR; - goto out_err; - } - v9fs_path_write_lock(s); err = v9fs_complete_renameat(pdu, olddirfid, &old_name, newdirfid, &new_name); @@ -2935,16 +2815,6 @@ static void v9fs_mknod(void *opaque) } trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor); - if (name_is_illegal(name.data)) { - err = -ENOENT; - goto out_nofid; - } - - if (!strcmp(".", name.data) || !strcmp("..", name.data)) { - err = -EEXIST; - goto out_nofid; - } - fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -3096,16 +2966,6 @@ static void v9fs_mkdir(void *opaque) } trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid); - if (name_is_illegal(name.data)) { - err = -ENOENT; - goto out_nofid; - } - - if (!strcmp(".", name.data) || !strcmp("..", name.data)) { - err = -EEXIST; - goto out_nofid; - } - fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -3407,8 +3267,8 @@ void pdu_submit(V9fsPDU *pdu) if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) { handler = v9fs_fs_ro; } - co = qemu_coroutine_create(handler, pdu); - qemu_coroutine_enter(co); + co = qemu_coroutine_create(handler); + qemu_coroutine_enter(co, pdu); } /* Returns 0 on success, 1 on failure. */ diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index a38603398..1a19418a8 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -1,9 +1,12 @@ -#ifndef QEMU_9P_H -#define QEMU_9P_H +#ifndef _QEMU_9P_H +#define _QEMU_9P_H #include <dirent.h> #include <utime.h> #include <sys/resource.h> +#include <glib.h> +#include "standard-headers/linux/virtio_9p.h" +#include "hw/virtio/virtio.h" #include "fsdev/file-op-9p.h" #include "fsdev/9p-iov-marshal.h" #include "qemu/thread.h" @@ -166,33 +169,13 @@ typedef struct V9fsXattr int flags; } V9fsXattr; -typedef struct V9fsDir { - DIR *stream; - QemuMutex readdir_mutex; -} V9fsDir; - -static inline void v9fs_readdir_lock(V9fsDir *dir) -{ - qemu_mutex_lock(&dir->readdir_mutex); -} - -static inline void v9fs_readdir_unlock(V9fsDir *dir) -{ - qemu_mutex_unlock(&dir->readdir_mutex); -} - -static inline void v9fs_readdir_init(V9fsDir *dir) -{ - qemu_mutex_init(&dir->readdir_mutex); -} - /* * Filled by fs driver on open and other * calls. */ union V9fsFidOpenState { int fd; - V9fsDir dir; + DIR *dir; V9fsXattr xattr; /* * private pointer for fs drivers, that @@ -236,7 +219,6 @@ typedef struct V9fsState int32_t root_fid; Error *migration_blocker; V9fsConf fsconf; - V9fsQID root_qid; } V9fsState; /* 9p2000.L open flags */ diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index d91f9ad6e..91df7f7a7 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -1,5 +1,6 @@ + /* - * 9p backend + * Virtio 9p backend * * Copyright IBM, Corp. 2011 * @@ -17,7 +18,8 @@ #include "qemu/coroutine.h" #include "coth.h" -int v9fs_co_readdir(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent **dent) +int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent, + struct dirent **result) { int err; V9fsState *s = pdu->s; @@ -27,14 +29,11 @@ int v9fs_co_readdir(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent **dent) } v9fs_co_run_in_worker( { - struct dirent *entry; - errno = 0; - entry = s->ops->readdir(&s->ctx, &fidp->fs); - if (!entry && errno) { + err = s->ops->readdir_r(&s->ctx, &fidp->fs, dent, result); + if (!*result && errno) { err = -errno; } else { - *dent = entry; err = 0; } }); diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 10343c0a9..293483e0c 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -1,5 +1,6 @@ + /* - * 9p backend + * Virtio 9p backend * * Copyright IBM, Corp. 2011 * diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 70f584fcb..18c81cb3d 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -1,5 +1,6 @@ + /* - * 9p backend + * Virtio 9p backend * * Copyright IBM, Corp. 2011 * diff --git a/hw/9pfs/coth.c b/hw/9pfs/coth.c index 89018de6b..464293ef2 100644 --- a/hw/9pfs/coth.c +++ b/hw/9pfs/coth.c @@ -16,20 +16,21 @@ #include "qemu-common.h" #include "block/thread-pool.h" #include "qemu/coroutine.h" +#include "qemu/main-loop.h" #include "coth.h" /* Called from QEMU I/O thread. */ static void coroutine_enter_cb(void *opaque, int ret) { Coroutine *co = opaque; - qemu_coroutine_enter(co); + qemu_coroutine_enter(co, NULL); } /* Called from worker thread. */ static int coroutine_enter_func(void *arg) { Coroutine *co = arg; - qemu_coroutine_enter(co); + qemu_coroutine_enter(co, NULL); return 0; } diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h index 3c7424e42..209fc6a9a 100644 --- a/hw/9pfs/coth.h +++ b/hw/9pfs/coth.h @@ -12,13 +12,12 @@ * */ -#ifndef QEMU_9P_COTH_H -#define QEMU_9P_COTH_H +#ifndef _QEMU_9P_COTH_H +#define _QEMU_9P_COTH_H #include "qemu/thread.h" #include "qemu/coroutine.h" -#include "qemu/main-loop.h" -#include "9p.h" +#include "virtio-9p.h" /* * we want to use bottom half because we want to make sure the below @@ -48,8 +47,10 @@ } while (0) extern void co_run_in_worker_bh(void *); +extern int v9fs_init_worker_threads(void); extern int v9fs_co_readlink(V9fsPDU *, V9fsPath *, V9fsString *); -extern int v9fs_co_readdir(V9fsPDU *, V9fsFidState *, struct dirent **); +extern int v9fs_co_readdir_r(V9fsPDU *, V9fsFidState *, + struct dirent *, struct dirent **result); extern off_t v9fs_co_telldir(V9fsPDU *, V9fsFidState *); extern void v9fs_co_seekdir(V9fsPDU *, V9fsFidState *, off_t); extern void v9fs_co_rewinddir(V9fsPDU *, V9fsFidState *); diff --git a/hw/9pfs/coxattr.c b/hw/9pfs/coxattr.c index 133c4ead3..6ad96ea9f 100644 --- a/hw/9pfs/coxattr.c +++ b/hw/9pfs/coxattr.c @@ -1,5 +1,6 @@ + /* - * 9p backend + * Virtio 9p backend * * Copyright IBM, Corp. 2011 * diff --git a/hw/9pfs/trace-events b/hw/9pfs/trace-events deleted file mode 100644 index 48d3d8abe..000000000 --- a/hw/9pfs/trace-events +++ /dev/null @@ -1,47 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/9pfs/virtio-9p.c -v9fs_rerror(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d" -v9fs_version(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s" -v9fs_version_return(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s" -v9fs_attach(uint16_t tag, uint8_t id, int32_t fid, int32_t afid, char* uname, char* aname) "tag %u id %u fid %d afid %d uname %s aname %s" -v9fs_attach_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d type %d version %d path %"PRId64 -v9fs_stat(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d" -v9fs_stat_return(uint16_t tag, uint8_t id, int32_t mode, int32_t atime, int32_t mtime, int64_t length) "tag %d id %d stat={mode %d atime %d mtime %d length %"PRId64"}" -v9fs_getattr(uint16_t tag, uint8_t id, int32_t fid, uint64_t request_mask) "tag %d id %d fid %d request_mask %"PRIu64 -v9fs_getattr_return(uint16_t tag, uint8_t id, uint64_t result_mask, uint32_t mode, uint32_t uid, uint32_t gid) "tag %d id %d getattr={result_mask %"PRId64" mode %u uid %u gid %u}" -v9fs_walk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, uint16_t nwnames) "tag %d id %d fid %d newfid %d nwnames %d" -v9fs_walk_return(uint16_t tag, uint8_t id, uint16_t nwnames, void* qids) "tag %d id %d nwnames %d qids %p" -v9fs_open(uint16_t tag, uint8_t id, int32_t fid, int32_t mode) "tag %d id %d fid %d mode %d" -v9fs_open_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d" -v9fs_lcreate(uint16_t tag, uint8_t id, int32_t dfid, int32_t flags, int32_t mode, uint32_t gid) "tag %d id %d dfid %d flags %d mode %d gid %u" -v9fs_lcreate_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int32_t iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d" -v9fs_fsync(uint16_t tag, uint8_t id, int32_t fid, int datasync) "tag %d id %d fid %d datasync %d" -v9fs_clunk(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d" -v9fs_read(uint16_t tag, uint8_t id, int32_t fid, uint64_t off, uint32_t max_count) "tag %d id %d fid %d off %"PRIu64" max_count %u" -v9fs_read_return(uint16_t tag, uint8_t id, int32_t count, ssize_t err) "tag %d id %d count %d err %zd" -v9fs_readdir(uint16_t tag, uint8_t id, int32_t fid, uint64_t offset, uint32_t max_count) "tag %d id %d fid %d offset %"PRIu64" max_count %u" -v9fs_readdir_return(uint16_t tag, uint8_t id, uint32_t count, ssize_t retval) "tag %d id %d count %u retval %zd" -v9fs_write(uint16_t tag, uint8_t id, int32_t fid, uint64_t off, uint32_t count, int cnt) "tag %d id %d fid %d off %"PRIu64" count %u cnt %d" -v9fs_write_return(uint16_t tag, uint8_t id, int32_t total, ssize_t err) "tag %d id %d total %d err %zd" -v9fs_create(uint16_t tag, uint8_t id, int32_t fid, char* name, int32_t perm, int8_t mode) "tag %d id %d fid %d name %s perm %d mode %d" -v9fs_create_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d" -v9fs_symlink(uint16_t tag, uint8_t id, int32_t fid, char* name, char* symname, uint32_t gid) "tag %d id %d fid %d name %s symname %s gid %u" -v9fs_symlink_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d qid={type %d version %d path %"PRId64"}" -v9fs_flush(uint16_t tag, uint8_t id, int16_t flush_tag) "tag %d id %d flush_tag %d" -v9fs_link(uint16_t tag, uint8_t id, int32_t dfid, int32_t oldfid, char* name) "tag %d id %d dfid %d oldfid %d name %s" -v9fs_remove(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d" -v9fs_wstat(uint16_t tag, uint8_t id, int32_t fid, int32_t mode, int32_t atime, int32_t mtime) "tag %u id %u fid %d stat={mode %d atime %d mtime %d}" -v9fs_mknod(uint16_t tag, uint8_t id, int32_t fid, int mode, int major, int minor) "tag %d id %d fid %d mode %d major %d minor %d" -v9fs_mknod_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path) "tag %d id %d qid={type %d version %d path %"PRId64"}" -v9fs_lock(uint16_t tag, uint8_t id, int32_t fid, uint8_t type, uint64_t start, uint64_t length) "tag %d id %d fid %d type %d start %"PRIu64" length %"PRIu64 -v9fs_lock_return(uint16_t tag, uint8_t id, int8_t status) "tag %d id %d status %d" -v9fs_getlock(uint16_t tag, uint8_t id, int32_t fid, uint8_t type, uint64_t start, uint64_t length)"tag %d id %d fid %d type %d start %"PRIu64" length %"PRIu64 -v9fs_getlock_return(uint16_t tag, uint8_t id, uint8_t type, uint64_t start, uint64_t length, uint32_t proc_id) "tag %d id %d type %d start %"PRIu64" length %"PRIu64" proc_id %u" -v9fs_mkdir(uint16_t tag, uint8_t id, int32_t fid, char* name, int mode, uint32_t gid) "tag %u id %u fid %d name %s mode %d gid %u" -v9fs_mkdir_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int err) "tag %u id %u qid={type %d version %d path %"PRId64"} err %d" -v9fs_xattrwalk(uint16_t tag, uint8_t id, int32_t fid, int32_t newfid, char* name) "tag %d id %d fid %d newfid %d name %s" -v9fs_xattrwalk_return(uint16_t tag, uint8_t id, int64_t size) "tag %d id %d size %"PRId64 -v9fs_xattrcreate(uint16_t tag, uint8_t id, int32_t fid, char* name, int64_t size, int flags) "tag %d id %d fid %d name %s size %"PRId64" flags %d" -v9fs_readlink(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d" -v9fs_readlink_return(uint16_t tag, uint8_t id, char* target) "tag %d id %d name %s" diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 009b43f6d..a38850ee8 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -13,9 +13,11 @@ #include "qemu/osdep.h" #include "hw/virtio/virtio.h" +#include "hw/i386/pc.h" #include "qemu/sockets.h" #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" +#include "9p-xattr.h" #include "coth.h" #include "hw/virtio/virtio-access.h" #include "qemu/iov.h" @@ -97,9 +99,14 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config) g_free(cfg); } -static int virtio_9p_load(QEMUFile *f, void *opaque, size_t size) +static void virtio_9p_save(QEMUFile *f, void *opaque) { - return virtio_load(VIRTIO_DEVICE(opaque), f, 1); + virtio_save(VIRTIO_DEVICE(opaque), f); +} + +static int virtio_9p_load(QEMUFile *f, void *opaque, int version_id) +{ + return virtio_load(VIRTIO_DEVICE(opaque), f, version_id); } static void virtio_9p_device_realize(DeviceState *dev, Error **errp) @@ -115,6 +122,7 @@ static void virtio_9p_device_realize(DeviceState *dev, Error **errp) v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag); virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size); v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); + register_savevm(dev, "virtio-9p", -1, 1, virtio_9p_save, virtio_9p_load, v); out: return; @@ -127,6 +135,7 @@ static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp) V9fsState *s = &v->state; virtio_cleanup(vdev); + unregister_savevm(dev, "virtio-9p", v); v9fs_device_unrealize_common(s, errp); } @@ -168,8 +177,6 @@ void virtio_init_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, /* virtio-9p device */ -VMSTATE_VIRTIO_DEVICE(9p, 1, virtio_9p_load, virtio_vmstate_save); - static Property virtio_9p_properties[] = { DEFINE_PROP_STRING("mount_tag", V9fsVirtioState, state.fsconf.tag), DEFINE_PROP_STRING("fsdev", V9fsVirtioState, state.fsconf.fsdev_id), @@ -182,7 +189,6 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->props = virtio_9p_properties; - dc->vmsd = &vmstate_virtio_9p; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->realize = virtio_9p_device_realize; vdc->unrealize = virtio_9p_device_unrealize; diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 7586b792d..7f6d88553 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -1,5 +1,5 @@ -#ifndef QEMU_VIRTIO_9P_H -#define QEMU_VIRTIO_9P_H +#ifndef _QEMU_VIRTIO_9P_H +#define _QEMU_VIRTIO_9P_H #include "standard-headers/linux/virtio_9p.h" #include "hw/virtio/virtio.h" diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs index 4b7da6639..faee86c5c 100644 --- a/hw/acpi/Makefile.objs +++ b/hw/acpi/Makefile.objs @@ -1,10 +1,8 @@ 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_CPU_HOTPLUG) += cpu_hotplug.o cpu_hotplug_acpi_table.o common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o memory_hotplug_acpi_table.o -common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o common-obj-$(CONFIG_ACPI) += acpi_interface.o common-obj-$(CONFIG_ACPI) += bios-linker-loader.o common-obj-$(CONFIG_ACPI) += aml-build.o -common-obj-$(call land,$(CONFIG_ACPI),$(CONFIG_IPMI)) += ipmi.o diff --git a/hw/acpi/acpi_interface.c b/hw/acpi/acpi_interface.c index 6583917b8..d82131326 100644 --- a/hw/acpi/acpi_interface.c +++ b/hw/acpi/acpi_interface.c @@ -2,15 +2,6 @@ #include "hw/acpi/acpi_dev_interface.h" #include "qemu/module.h" -void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event) -{ - AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(dev); - if (adevc->send_event) { - AcpiDeviceIf *adev = ACPI_DEVICE_IF(dev); - adevc->send_event(adev, event); - } -} - static void register_types(void) { static const TypeInfo acpi_dev_if_info = { diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index db3e914fb..ab89ca638 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -24,6 +24,7 @@ #include "hw/acpi/aml-build.h" #include "qemu/bswap.h" #include "qemu/bitops.h" +#include "hw/acpi/bios-linker-loader.h" static GArray *build_alloc_array(void) { @@ -324,9 +325,12 @@ static void aml_free(gpointer data, gpointer user_data) Aml *init_aml_allocator(void) { + Aml *var; + assert(!alloc_list); alloc_list = g_ptr_array_new(); - return aml_alloc(); + var = aml_alloc(); + return var; } void free_aml_allocator(void) @@ -402,15 +406,6 @@ Aml *aml_return(Aml *val) return var; } -/* ACPI 1.0b: 16.2.6.3 Debug Objects Encoding: DebugObj */ -Aml *aml_debug(void) -{ - Aml *var = aml_alloc(); - build_append_byte(var->buf, 0x5B); /* ExtOpPrefix */ - build_append_byte(var->buf, 0x31); /* DebugOp */ - return var; -} - /* * ACPI 1.0b: 16.2.3 Data Objects Encoding: * encodes: ByteConst, WordConst, DWordConst, QWordConst, ZeroOp, OneOp @@ -448,10 +443,12 @@ Aml *aml_name_decl(const char *name, Aml *val) /* ACPI 1.0b: 16.2.6.1 Arg Objects Encoding */ Aml *aml_arg(int pos) { + Aml *var; uint8_t op = 0x68 /* ARG0 op */ + pos; assert(pos <= 6); - return aml_opcode(op); + var = aml_opcode(op); + return var; } /* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToInteger */ @@ -660,20 +657,6 @@ Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4) return var; } -/* helper to call method with 5 arguments */ -Aml *aml_call5(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4, - Aml *arg5) -{ - Aml *var = aml_alloc(); - build_append_namestring(var->buf, "%s", method); - aml_append(var, arg1); - aml_append(var, arg2); - aml_append(var, arg3); - aml_append(var, arg4); - aml_append(var, arg5); - return var; -} - /* * ACPI 5.0: 6.4.3.8.1 GPIO Connection Descriptor * Type 1, Large Item Name 0xC @@ -1091,10 +1074,12 @@ Aml *aml_string(const char *name_format, ...) /* ACPI 1.0b: 16.2.6.2 Local Objects Encoding */ Aml *aml_local(int num) { + Aml *var; uint8_t op = 0x60 /* Local0Op */ + num; assert(num <= 7); - return aml_opcode(op); + var = aml_opcode(op); + return var; } /* ACPI 2.0a: 17.2.2 Data Objects Encoding: DefVarPackage */ @@ -1422,14 +1407,6 @@ Aml *aml_unicode(const char *str) return var; } -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefRefOf */ -Aml *aml_refof(Aml *arg) -{ - Aml *var = aml_opcode(0x71 /* RefOfOp */); - aml_append(var, arg); - return var; -} - /* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefDerefOf */ Aml *aml_derefof(Aml *arg) { @@ -1495,21 +1472,11 @@ Aml *aml_concatenate(Aml *source1, Aml *source2, Aml *target) target); } -/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefObjectType */ -Aml *aml_object_type(Aml *object) -{ - Aml *var = aml_opcode(0x8E /* ObjectTypeOp */); - aml_append(var, object); - return var; -} - void -build_header(BIOSLinker *linker, GArray *table_data, +build_header(GArray *linker, GArray *table_data, AcpiTableHeader *h, const char *sig, int len, uint8_t rev, const char *oem_id, const char *oem_table_id) { - unsigned tbl_offset = (char *)h - table_data->data; - unsigned checksum_offset = (char *)&h->checksum - table_data->data; memcpy(&h->signature, sig, 4); h->length = cpu_to_le32(len); h->revision = rev; @@ -1530,9 +1497,10 @@ build_header(BIOSLinker *linker, GArray *table_data, h->oem_revision = cpu_to_le32(1); memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4); h->asl_compiler_revision = cpu_to_le32(1); + h->checksum = 0; /* Checksum to be filled in by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE, - tbl_offset, len, checksum_offset); + table_data, h, len, &h->checksum); } void *acpi_data_push(GArray *table_data, unsigned size) @@ -1550,7 +1518,7 @@ unsigned acpi_data_len(GArray *table) void acpi_add_table(GArray *table_offsets, GArray *table_data) { - uint32_t offset = table_data->len; + uint32_t offset = cpu_to_le32(table_data->len); g_array_append_val(table_offsets, offset); } @@ -1564,7 +1532,8 @@ void acpi_build_tables_init(AcpiBuildTables *tables) void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre) { - bios_linker_loader_cleanup(tables->linker); + void *linker_data = bios_linker_loader_cleanup(tables->linker); + g_free(linker_data); g_array_free(tables->rsdp, true); g_array_free(tables->table_data, true); g_array_free(tables->tcpalog, mfre); @@ -1572,38 +1541,25 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre) /* Build rsdt table */ void -build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets, +build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets, const char *oem_id, const char *oem_table_id) { - int i; - unsigned rsdt_entries_offset; AcpiRsdtDescriptorRev1 *rsdt; - const unsigned table_data_len = (sizeof(uint32_t) * table_offsets->len); - const unsigned rsdt_entry_size = sizeof(rsdt->table_offset_entry[0]); - const size_t rsdt_len = sizeof(*rsdt) + table_data_len; + size_t rsdt_len; + int i; + const int table_data_len = (sizeof(uint32_t) * table_offsets->len); + rsdt_len = sizeof(*rsdt) + table_data_len; rsdt = acpi_data_push(table_data, rsdt_len); - rsdt_entries_offset = (char *)rsdt->table_offset_entry - table_data->data; + memcpy(rsdt->table_offset_entry, table_offsets->data, table_data_len); for (i = 0; i < table_offsets->len; ++i) { - uint32_t ref_tbl_offset = g_array_index(table_offsets, uint32_t, i); - uint32_t rsdt_entry_offset = rsdt_entries_offset + rsdt_entry_size * i; - /* rsdt->table_offset_entry to be filled by Guest linker */ bios_linker_loader_add_pointer(linker, - ACPI_BUILD_TABLE_FILE, rsdt_entry_offset, rsdt_entry_size, - ACPI_BUILD_TABLE_FILE, ref_tbl_offset); + ACPI_BUILD_TABLE_FILE, + ACPI_BUILD_TABLE_FILE, + table_data, &rsdt->table_offset_entry[i], + sizeof(uint32_t)); } build_header(linker, table_data, (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id); } - -void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base, - uint64_t len, int node, MemoryAffinityFlags flags) -{ - numamem->type = ACPI_SRAT_MEMORY; - numamem->length = sizeof(*numamem); - numamem->proximity = cpu_to_le32(node); - numamem->flags = cpu_to_le32(flags); - numamem->base_addr = cpu_to_le64(base); - numamem->range_length = cpu_to_le64(len); -} diff --git a/hw/acpi/bios-linker-loader.c b/hw/acpi/bios-linker-loader.c index d963ebe24..5153ab151 100644 --- a/hw/acpi/bios-linker-loader.c +++ b/hw/acpi/bios-linker-loader.c @@ -96,170 +96,134 @@ enum { }; /* - * BiosLinkerFileEntry: - * - * An internal type used for book-keeping file entries - */ -typedef struct BiosLinkerFileEntry { - char *name; /* file name */ - GArray *blob; /* data accosiated with @name */ -} BiosLinkerFileEntry; - -/* - * bios_linker_loader_init: allocate a new linker object instance. + * bios_linker_loader_init: allocate a new linker file blob array. * * After initialization, linker commands can be added, and will - * be stored in the linker.cmd_blob array. + * be stored in the array. */ -BIOSLinker *bios_linker_loader_init(void) +GArray *bios_linker_loader_init(void) { - BIOSLinker *linker = g_new(BIOSLinker, 1); - - linker->cmd_blob = g_array_new(false, true /* clear */, 1); - linker->file_list = g_array_new(false, true /* clear */, - sizeof(BiosLinkerFileEntry)); - return linker; + return g_array_new(false, true /* clear */, 1); } -/* Free linker wrapper */ -void bios_linker_loader_cleanup(BIOSLinker *linker) +/* Free linker wrapper and return the linker array. */ +void *bios_linker_loader_cleanup(GArray *linker) { - int i; - BiosLinkerFileEntry *entry; - - g_array_free(linker->cmd_blob, true); - - for (i = 0; i < linker->file_list->len; i++) { - entry = &g_array_index(linker->file_list, BiosLinkerFileEntry, i); - g_free(entry->name); - } - g_array_free(linker->file_list, true); - g_free(linker); -} - -static const BiosLinkerFileEntry * -bios_linker_find_file(const BIOSLinker *linker, const char *name) -{ - int i; - BiosLinkerFileEntry *entry; - - for (i = 0; i < linker->file_list->len; i++) { - entry = &g_array_index(linker->file_list, BiosLinkerFileEntry, i); - if (!strcmp(entry->name, name)) { - return entry; - } - } - return NULL; + return g_array_free(linker, false); } /* * bios_linker_loader_alloc: ask guest to load file into guest memory. * - * @linker: linker object instance - * @file_name: name of the file blob to be loaded - * @file_blob: pointer to blob corresponding to @file_name + * @linker: linker file blob array + * @file: file to be loaded * @alloc_align: required minimal alignment in bytes. Must be a power of 2. * @alloc_fseg: request allocation in FSEG zone (useful for the RSDP ACPI table) * * Note: this command must precede any other linker command using this file. */ -void bios_linker_loader_alloc(BIOSLinker *linker, - const char *file_name, - GArray *file_blob, +void bios_linker_loader_alloc(GArray *linker, + const char *file, uint32_t alloc_align, bool alloc_fseg) { BiosLinkerLoaderEntry entry; - BiosLinkerFileEntry file = { g_strdup(file_name), file_blob}; assert(!(alloc_align & (alloc_align - 1))); - assert(!bios_linker_find_file(linker, file_name)); - g_array_append_val(linker->file_list, file); - memset(&entry, 0, sizeof entry); - strncpy(entry.alloc.file, file_name, sizeof entry.alloc.file - 1); + strncpy(entry.alloc.file, file, sizeof entry.alloc.file - 1); entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ALLOCATE); entry.alloc.align = cpu_to_le32(alloc_align); entry.alloc.zone = alloc_fseg ? BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG : BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH; /* Alloc entries must come first, so prepend them */ - g_array_prepend_vals(linker->cmd_blob, &entry, sizeof entry); + g_array_prepend_vals(linker, &entry, sizeof entry); } /* - * bios_linker_loader_add_checksum: ask guest to add checksum of ACPI - * table in the specified file at the specified offset. + * bios_linker_loader_add_checksum: ask guest to add checksum of file data + * into (same) file at the specified pointer. * * Checksum calculation simply sums -X for each byte X in the range * using 8-bit math (i.e. ACPI checksum). * - * @linker: linker object instance + * @linker: linker file blob array * @file: file that includes the checksum to be calculated * and the data to be checksummed - * @start_offset, @size: range of data in the file to checksum, - * relative to the start of file blob - * @checksum_offset: location of the checksum to be patched within file blob, - * relative to the start of file blob + * @table: @file blob contents + * @start, @size: range of data to checksum + * @checksum: location of the checksum to be patched within file blob + * + * Notes: + * - checksum byte initial value must have been pushed into @table + * and reside at address @checksum. + * - @size bytes must have been pushed into @table and reside at address + * @start. + * - Guest calculates checksum of specified range of data, result is added to + * initial value at @checksum into copy of @file in Guest memory. + * - Range might include the checksum itself. + * - To avoid confusion, caller must always put 0x0 at @checksum. + * - @file must be loaded into Guest memory using bios_linker_loader_alloc */ -void bios_linker_loader_add_checksum(BIOSLinker *linker, const char *file_name, - unsigned start_offset, unsigned size, - unsigned checksum_offset) +void bios_linker_loader_add_checksum(GArray *linker, const char *file, + GArray *table, + void *start, unsigned size, + uint8_t *checksum) { BiosLinkerLoaderEntry entry; - const BiosLinkerFileEntry *file = bios_linker_find_file(linker, file_name); + ptrdiff_t checksum_offset = (gchar *)checksum - table->data; + ptrdiff_t start_offset = (gchar *)start - table->data; - assert(file); - assert(start_offset < file->blob->len); - assert(start_offset + size <= file->blob->len); - assert(checksum_offset >= start_offset); - assert(checksum_offset + 1 <= start_offset + size); + assert(checksum_offset >= 0); + assert(start_offset >= 0); + assert(checksum_offset + 1 <= table->len); + assert(start_offset + size <= table->len); + assert(*checksum == 0x0); - *(file->blob->data + checksum_offset) = 0; memset(&entry, 0, sizeof entry); - strncpy(entry.cksum.file, file_name, sizeof entry.cksum.file - 1); + strncpy(entry.cksum.file, file, sizeof entry.cksum.file - 1); entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM); entry.cksum.offset = cpu_to_le32(checksum_offset); entry.cksum.start = cpu_to_le32(start_offset); entry.cksum.length = cpu_to_le32(size); - g_array_append_vals(linker->cmd_blob, &entry, sizeof entry); + g_array_append_vals(linker, &entry, sizeof entry); } /* - * bios_linker_loader_add_pointer: ask guest to patch address in - * destination file with a pointer to source file + * bios_linker_loader_add_pointer: ask guest to add address of source file + * into destination file at the specified pointer. * - * @linker: linker object instance + * @linker: linker file blob array * @dest_file: destination file that must be changed - * @dst_patched_offset: location within destination file blob to be patched - * with the pointer to @src_file+@src_offset (i.e. source - * blob allocated in guest memory + @src_offset), in bytes - * @dst_patched_offset_size: size of the pointer to be patched - * at @dst_patched_offset in @dest_file blob, in bytes * @src_file: source file who's address must be taken - * @src_offset: location within source file blob to which - * @dest_file+@dst_patched_offset will point to after - * firmware's executed ADD_POINTER command + * @table: @dest_file blob contents array + * @pointer: location of the pointer to be patched within destination file blob + * @pointer_size: size of pointer to be patched, in bytes + * + * Notes: + * - @pointer_size bytes must have been pushed into @table + * and reside at address @pointer. + * - Guest address is added to initial value at @pointer + * into copy of @dest_file in Guest memory. + * e.g. to get start of src_file in guest memory, put 0x0 there + * to get address of a field at offset 0x10 in src_file, put 0x10 there + * - Both @dest_file and @src_file must be + * loaded into Guest memory using bios_linker_loader_alloc */ -void bios_linker_loader_add_pointer(BIOSLinker *linker, +void bios_linker_loader_add_pointer(GArray *linker, const char *dest_file, - uint32_t dst_patched_offset, - uint8_t dst_patched_size, const char *src_file, - uint32_t src_offset) + GArray *table, void *pointer, + uint8_t pointer_size) { - uint64_t le_src_offset; BiosLinkerLoaderEntry entry; - const BiosLinkerFileEntry *dst_file = - bios_linker_find_file(linker, dest_file); - const BiosLinkerFileEntry *source_file = - bios_linker_find_file(linker, src_file); + ptrdiff_t offset = (gchar *)pointer - table->data; - assert(dst_patched_offset < dst_file->blob->len); - assert(dst_patched_offset + dst_patched_size <= dst_file->blob->len); - assert(src_offset < source_file->blob->len); + assert(offset >= 0); + assert(offset + pointer_size <= table->len); memset(&entry, 0, sizeof entry); strncpy(entry.pointer.dest_file, dest_file, @@ -267,14 +231,10 @@ void bios_linker_loader_add_pointer(BIOSLinker *linker, strncpy(entry.pointer.src_file, src_file, sizeof entry.pointer.src_file - 1); entry.command = cpu_to_le32(BIOS_LINKER_LOADER_COMMAND_ADD_POINTER); - entry.pointer.offset = cpu_to_le32(dst_patched_offset); - entry.pointer.size = dst_patched_size; - assert(dst_patched_size == 1 || dst_patched_size == 2 || - dst_patched_size == 4 || dst_patched_size == 8); - - le_src_offset = cpu_to_le64(src_offset); - memcpy(dst_file->blob->data + dst_patched_offset, - &le_src_offset, dst_patched_size); + entry.pointer.offset = cpu_to_le32(offset); + entry.pointer.size = pointer_size; + assert(pointer_size == 1 || pointer_size == 2 || + pointer_size == 4 || pointer_size == 8); - g_array_append_vals(linker->cmd_blob, &entry, sizeof entry); + g_array_append_vals(linker, &entry, sizeof entry); } diff --git a/hw/acpi/core.c b/hw/acpi/core.c index e890a5d67..6a2f45214 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -239,11 +239,11 @@ void acpi_table_add(const QemuOpts *opts, Error **errp) char unsigned *blob = NULL; { - Visitor *v; + OptsVisitor *ov; - v = opts_visitor_new(opts); - visit_type_AcpiTableOptions(v, NULL, &hdrs, &err); - visit_free(v); + ov = opts_visitor_new(opts); + visit_type_AcpiTableOptions(opts_get_visitor(ov), NULL, &hdrs, &err); + opts_visitor_cleanup(ov); } if (err) { @@ -491,12 +491,6 @@ void acpi_pm_tmr_update(ACPIREGS *ar, bool enable) } } -static inline int64_t acpi_pm_tmr_get_clock(void) -{ - return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY, - NANOSECONDS_PER_SECOND); -} - void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar) { int64_t d = acpi_pm_tmr_get_clock(); @@ -698,7 +692,7 @@ uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr) } void acpi_send_gpe_event(ACPIREGS *ar, qemu_irq irq, - AcpiEventStatusBits status) + AcpiGPEStatusBits status) { ar->gpe.sts[0] |= status; acpi_update_sci(ar, irq); diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c deleted file mode 100644 index c13b65c2c..000000000 --- a/hw/acpi/cpu.c +++ /dev/null @@ -1,561 +0,0 @@ -#include "qemu/osdep.h" -#include "hw/boards.h" -#include "hw/acpi/cpu.h" -#include "qapi/error.h" -#include "qapi-event.h" -#include "trace.h" - -#define ACPI_CPU_HOTPLUG_REG_LEN 12 -#define ACPI_CPU_SELECTOR_OFFSET_WR 0 -#define ACPI_CPU_FLAGS_OFFSET_RW 4 -#define ACPI_CPU_CMD_OFFSET_WR 5 -#define ACPI_CPU_CMD_DATA_OFFSET_RW 8 - -enum { - CPHP_GET_NEXT_CPU_WITH_EVENT_CMD = 0, - CPHP_OST_EVENT_CMD = 1, - CPHP_OST_STATUS_CMD = 2, - CPHP_CMD_MAX -}; - -static ACPIOSTInfo *acpi_cpu_device_status(int idx, AcpiCpuStatus *cdev) -{ - ACPIOSTInfo *info = g_new0(ACPIOSTInfo, 1); - - info->slot_type = ACPI_SLOT_TYPE_CPU; - info->slot = g_strdup_printf("%d", idx); - info->source = cdev->ost_event; - info->status = cdev->ost_status; - if (cdev->cpu) { - DeviceState *dev = DEVICE(cdev->cpu); - if (dev->id) { - info->device = g_strdup(dev->id); - info->has_device = true; - } - } - return info; -} - -void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list) -{ - int i; - - for (i = 0; i < cpu_st->dev_count; i++) { - ACPIOSTInfoList *elem = g_new0(ACPIOSTInfoList, 1); - elem->value = acpi_cpu_device_status(i, &cpu_st->devs[i]); - elem->next = NULL; - **list = elem; - *list = &elem->next; - } -} - -static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size) -{ - uint64_t val = 0; - CPUHotplugState *cpu_st = opaque; - AcpiCpuStatus *cdev; - - if (cpu_st->selector >= cpu_st->dev_count) { - return val; - } - - cdev = &cpu_st->devs[cpu_st->selector]; - switch (addr) { - case ACPI_CPU_FLAGS_OFFSET_RW: /* pack and return is_* fields */ - val |= cdev->cpu ? 1 : 0; - val |= cdev->is_inserting ? 2 : 0; - val |= cdev->is_removing ? 4 : 0; - trace_cpuhp_acpi_read_flags(cpu_st->selector, val); - break; - case ACPI_CPU_CMD_DATA_OFFSET_RW: - switch (cpu_st->command) { - case CPHP_GET_NEXT_CPU_WITH_EVENT_CMD: - val = cpu_st->selector; - break; - default: - break; - } - trace_cpuhp_acpi_read_cmd_data(cpu_st->selector, val); - break; - default: - break; - } - return val; -} - -static void cpu_hotplug_wr(void *opaque, hwaddr addr, uint64_t data, - unsigned int size) -{ - CPUHotplugState *cpu_st = opaque; - AcpiCpuStatus *cdev; - ACPIOSTInfo *info; - - assert(cpu_st->dev_count); - - if (addr) { - if (cpu_st->selector >= cpu_st->dev_count) { - trace_cpuhp_acpi_invalid_idx_selected(cpu_st->selector); - return; - } - } - - switch (addr) { - case ACPI_CPU_SELECTOR_OFFSET_WR: /* current CPU selector */ - cpu_st->selector = data; - trace_cpuhp_acpi_write_idx(cpu_st->selector); - break; - case ACPI_CPU_FLAGS_OFFSET_RW: /* set is_* fields */ - cdev = &cpu_st->devs[cpu_st->selector]; - if (data & 2) { /* clear insert event */ - cdev->is_inserting = false; - trace_cpuhp_acpi_clear_inserting_evt(cpu_st->selector); - } else if (data & 4) { /* clear remove event */ - cdev->is_removing = false; - trace_cpuhp_acpi_clear_remove_evt(cpu_st->selector); - } else if (data & 8) { - DeviceState *dev = NULL; - HotplugHandler *hotplug_ctrl = NULL; - - if (!cdev->cpu) { - trace_cpuhp_acpi_ejecting_invalid_cpu(cpu_st->selector); - break; - } - - trace_cpuhp_acpi_ejecting_cpu(cpu_st->selector); - dev = DEVICE(cdev->cpu); - hotplug_ctrl = qdev_get_hotplug_handler(dev); - hotplug_handler_unplug(hotplug_ctrl, dev, NULL); - } - break; - case ACPI_CPU_CMD_OFFSET_WR: - trace_cpuhp_acpi_write_cmd(cpu_st->selector, data); - if (data < CPHP_CMD_MAX) { - cpu_st->command = data; - if (cpu_st->command == CPHP_GET_NEXT_CPU_WITH_EVENT_CMD) { - uint32_t iter = cpu_st->selector; - - do { - cdev = &cpu_st->devs[iter]; - if (cdev->is_inserting || cdev->is_removing) { - cpu_st->selector = iter; - trace_cpuhp_acpi_cpu_has_events(cpu_st->selector, - cdev->is_inserting, cdev->is_removing); - break; - } - iter = iter + 1 < cpu_st->dev_count ? iter + 1 : 0; - } while (iter != cpu_st->selector); - } - } - break; - case ACPI_CPU_CMD_DATA_OFFSET_RW: - switch (cpu_st->command) { - case CPHP_OST_EVENT_CMD: { - cdev = &cpu_st->devs[cpu_st->selector]; - cdev->ost_event = data; - trace_cpuhp_acpi_write_ost_ev(cpu_st->selector, cdev->ost_event); - break; - } - case CPHP_OST_STATUS_CMD: { - cdev = &cpu_st->devs[cpu_st->selector]; - cdev->ost_status = data; - info = acpi_cpu_device_status(cpu_st->selector, cdev); - qapi_event_send_acpi_device_ost(info, &error_abort); - qapi_free_ACPIOSTInfo(info); - trace_cpuhp_acpi_write_ost_status(cpu_st->selector, - cdev->ost_status); - break; - } - default: - break; - } - break; - default: - break; - } -} - -static const MemoryRegionOps cpu_hotplug_ops = { - .read = cpu_hotplug_rd, - .write = cpu_hotplug_wr, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, - CPUHotplugState *state, hwaddr base_addr) -{ - MachineState *machine = MACHINE(qdev_get_machine()); - MachineClass *mc = MACHINE_GET_CLASS(machine); - CPUArchIdList *id_list; - int i; - - assert(mc->possible_cpu_arch_ids); - id_list = mc->possible_cpu_arch_ids(machine); - state->dev_count = id_list->len; - state->devs = g_new0(typeof(*state->devs), state->dev_count); - for (i = 0; i < id_list->len; i++) { - state->devs[i].cpu = id_list->cpus[i].cpu; - state->devs[i].arch_id = id_list->cpus[i].arch_id; - } - g_free(id_list); - memory_region_init_io(&state->ctrl_reg, owner, &cpu_hotplug_ops, state, - "acpi-mem-hotplug", ACPI_CPU_HOTPLUG_REG_LEN); - memory_region_add_subregion(as, base_addr, &state->ctrl_reg); -} - -static AcpiCpuStatus *get_cpu_status(CPUHotplugState *cpu_st, DeviceState *dev) -{ - CPUClass *k = CPU_GET_CLASS(dev); - uint64_t cpu_arch_id = k->get_arch_id(CPU(dev)); - int i; - - for (i = 0; i < cpu_st->dev_count; i++) { - if (cpu_arch_id == cpu_st->devs[i].arch_id) { - return &cpu_st->devs[i]; - } - } - return NULL; -} - -void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev, - CPUHotplugState *cpu_st, DeviceState *dev, Error **errp) -{ - AcpiCpuStatus *cdev; - - cdev = get_cpu_status(cpu_st, dev); - if (!cdev) { - return; - } - - cdev->cpu = CPU(dev); - if (dev->hotplugged) { - cdev->is_inserting = true; - acpi_send_event(DEVICE(hotplug_dev), ACPI_CPU_HOTPLUG_STATUS); - } -} - -void acpi_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, - CPUHotplugState *cpu_st, - DeviceState *dev, Error **errp) -{ - AcpiCpuStatus *cdev; - - cdev = get_cpu_status(cpu_st, dev); - if (!cdev) { - return; - } - - cdev->is_removing = true; - acpi_send_event(DEVICE(hotplug_dev), ACPI_CPU_HOTPLUG_STATUS); -} - -void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st, - DeviceState *dev, Error **errp) -{ - AcpiCpuStatus *cdev; - - cdev = get_cpu_status(cpu_st, dev); - if (!cdev) { - return; - } - - cdev->cpu = NULL; -} - -static const VMStateDescription vmstate_cpuhp_sts = { - .name = "CPU hotplug device state", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_BOOL(is_inserting, AcpiCpuStatus), - VMSTATE_BOOL(is_removing, AcpiCpuStatus), - VMSTATE_UINT32(ost_event, AcpiCpuStatus), - VMSTATE_UINT32(ost_status, AcpiCpuStatus), - VMSTATE_END_OF_LIST() - } -}; - -const VMStateDescription vmstate_cpu_hotplug = { - .name = "CPU hotplug state", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(selector, CPUHotplugState), - VMSTATE_UINT8(command, CPUHotplugState), - VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, CPUHotplugState, dev_count, - vmstate_cpuhp_sts, AcpiCpuStatus), - VMSTATE_END_OF_LIST() - } -}; - -#define CPU_NAME_FMT "C%.03X" -#define CPUHP_RES_DEVICE "PRES" -#define CPU_LOCK "CPLK" -#define CPU_STS_METHOD "CSTA" -#define CPU_SCAN_METHOD "CSCN" -#define CPU_NOTIFY_METHOD "CTFY" -#define CPU_EJECT_METHOD "CEJ0" -#define CPU_OST_METHOD "COST" - -#define CPU_ENABLED "CPEN" -#define CPU_SELECTOR "CSEL" -#define CPU_COMMAND "CCMD" -#define CPU_DATA "CDAT" -#define CPU_INSERT_EVENT "CINS" -#define CPU_REMOVE_EVENT "CRMV" -#define CPU_EJECT_EVENT "CEJ0" - -void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts, - hwaddr io_base, - const char *res_root, - const char *event_handler_method) -{ - Aml *ifctx; - Aml *field; - Aml *method; - Aml *cpu_ctrl_dev; - Aml *cpus_dev; - Aml *zero = aml_int(0); - Aml *one = aml_int(1); - Aml *sb_scope = aml_scope("_SB"); - MachineClass *mc = MACHINE_GET_CLASS(machine); - CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine); - char *cphp_res_path = g_strdup_printf("%s." CPUHP_RES_DEVICE, res_root); - Object *obj = object_resolve_path_type("", TYPE_ACPI_DEVICE_IF, NULL); - AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj); - AcpiDeviceIf *adev = ACPI_DEVICE_IF(obj); - - cpu_ctrl_dev = aml_device("%s", cphp_res_path); - { - Aml *crs; - - aml_append(cpu_ctrl_dev, - aml_name_decl("_HID", aml_eisaid("PNP0A06"))); - aml_append(cpu_ctrl_dev, - aml_name_decl("_UID", aml_string("CPU Hotplug resources"))); - aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0)); - - crs = aml_resource_template(); - aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1, - ACPI_CPU_HOTPLUG_REG_LEN)); - aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs)); - - /* declare CPU hotplug MMIO region with related access fields */ - aml_append(cpu_ctrl_dev, - aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base), - ACPI_CPU_HOTPLUG_REG_LEN)); - - field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, - AML_WRITE_AS_ZEROS); - aml_append(field, aml_reserved_field(ACPI_CPU_FLAGS_OFFSET_RW * 8)); - /* 1 if enabled, read only */ - aml_append(field, aml_named_field(CPU_ENABLED, 1)); - /* (read) 1 if has a insert event. (write) 1 to clear event */ - aml_append(field, aml_named_field(CPU_INSERT_EVENT, 1)); - /* (read) 1 if has a remove event. (write) 1 to clear event */ - aml_append(field, aml_named_field(CPU_REMOVE_EVENT, 1)); - /* initiates device eject, write only */ - aml_append(field, aml_named_field(CPU_EJECT_EVENT, 1)); - aml_append(field, aml_reserved_field(4)); - aml_append(field, aml_named_field(CPU_COMMAND, 8)); - aml_append(cpu_ctrl_dev, field); - - field = aml_field("PRST", AML_DWORD_ACC, AML_NOLOCK, AML_PRESERVE); - /* CPU selector, write only */ - aml_append(field, aml_named_field(CPU_SELECTOR, 32)); - /* flags + cmd + 2byte align */ - aml_append(field, aml_reserved_field(4 * 8)); - aml_append(field, aml_named_field(CPU_DATA, 32)); - aml_append(cpu_ctrl_dev, field); - - if (opts.has_legacy_cphp) { - method = aml_method("_INI", 0, AML_SERIALIZED); - /* switch off legacy CPU hotplug HW and use new one, - * on reboot system is in new mode and writing 0 - * in CPU_SELECTOR selects BSP, which is NOP at - * the time _INI is called */ - aml_append(method, aml_store(zero, aml_name(CPU_SELECTOR))); - aml_append(cpu_ctrl_dev, method); - } - } - aml_append(sb_scope, cpu_ctrl_dev); - - cpus_dev = aml_device("\\_SB.CPUS"); - { - int i; - Aml *ctrl_lock = aml_name("%s.%s", cphp_res_path, CPU_LOCK); - Aml *cpu_selector = aml_name("%s.%s", cphp_res_path, CPU_SELECTOR); - Aml *is_enabled = aml_name("%s.%s", cphp_res_path, CPU_ENABLED); - Aml *cpu_cmd = aml_name("%s.%s", cphp_res_path, CPU_COMMAND); - Aml *cpu_data = aml_name("%s.%s", cphp_res_path, CPU_DATA); - Aml *ins_evt = aml_name("%s.%s", cphp_res_path, CPU_INSERT_EVENT); - Aml *rm_evt = aml_name("%s.%s", cphp_res_path, CPU_REMOVE_EVENT); - Aml *ej_evt = aml_name("%s.%s", cphp_res_path, CPU_EJECT_EVENT); - - aml_append(cpus_dev, aml_name_decl("_HID", aml_string("ACPI0010"))); - aml_append(cpus_dev, aml_name_decl("_CID", aml_eisaid("PNP0A05"))); - - method = aml_method(CPU_NOTIFY_METHOD, 2, AML_NOTSERIALIZED); - for (i = 0; i < arch_ids->len; i++) { - Aml *cpu = aml_name(CPU_NAME_FMT, i); - Aml *uid = aml_arg(0); - Aml *event = aml_arg(1); - - ifctx = aml_if(aml_equal(uid, aml_int(i))); - { - aml_append(ifctx, aml_notify(cpu, event)); - } - aml_append(method, ifctx); - } - aml_append(cpus_dev, method); - - method = aml_method(CPU_STS_METHOD, 1, AML_SERIALIZED); - { - Aml *idx = aml_arg(0); - Aml *sta = aml_local(0); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(idx, cpu_selector)); - aml_append(method, aml_store(zero, sta)); - ifctx = aml_if(aml_equal(is_enabled, one)); - { - aml_append(ifctx, aml_store(aml_int(0xF), sta)); - } - aml_append(method, ifctx); - aml_append(method, aml_release(ctrl_lock)); - aml_append(method, aml_return(sta)); - } - aml_append(cpus_dev, method); - - method = aml_method(CPU_EJECT_METHOD, 1, AML_SERIALIZED); - { - Aml *idx = aml_arg(0); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(idx, cpu_selector)); - aml_append(method, aml_store(one, ej_evt)); - aml_append(method, aml_release(ctrl_lock)); - } - aml_append(cpus_dev, method); - - method = aml_method(CPU_SCAN_METHOD, 0, AML_SERIALIZED); - { - Aml *else_ctx; - Aml *while_ctx; - Aml *has_event = aml_local(0); - Aml *dev_chk = aml_int(1); - Aml *eject_req = aml_int(3); - Aml *next_cpu_cmd = aml_int(CPHP_GET_NEXT_CPU_WITH_EVENT_CMD); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(one, has_event)); - while_ctx = aml_while(aml_equal(has_event, one)); - { - /* clear loop exit condition, ins_evt/rm_evt checks - * will set it to 1 while next_cpu_cmd returns a CPU - * with events */ - aml_append(while_ctx, aml_store(zero, has_event)); - aml_append(while_ctx, aml_store(next_cpu_cmd, cpu_cmd)); - ifctx = aml_if(aml_equal(ins_evt, one)); - { - aml_append(ifctx, - aml_call2(CPU_NOTIFY_METHOD, cpu_data, dev_chk)); - aml_append(ifctx, aml_store(one, ins_evt)); - aml_append(ifctx, aml_store(one, has_event)); - } - aml_append(while_ctx, ifctx); - else_ctx = aml_else(); - ifctx = aml_if(aml_equal(rm_evt, one)); - { - aml_append(ifctx, - aml_call2(CPU_NOTIFY_METHOD, cpu_data, eject_req)); - aml_append(ifctx, aml_store(one, rm_evt)); - aml_append(ifctx, aml_store(one, has_event)); - } - aml_append(else_ctx, ifctx); - aml_append(while_ctx, else_ctx); - } - aml_append(method, while_ctx); - aml_append(method, aml_release(ctrl_lock)); - } - aml_append(cpus_dev, method); - - method = aml_method(CPU_OST_METHOD, 4, AML_SERIALIZED); - { - Aml *uid = aml_arg(0); - Aml *ev_cmd = aml_int(CPHP_OST_EVENT_CMD); - Aml *st_cmd = aml_int(CPHP_OST_STATUS_CMD); - - aml_append(method, aml_acquire(ctrl_lock, 0xFFFF)); - aml_append(method, aml_store(uid, cpu_selector)); - aml_append(method, aml_store(ev_cmd, cpu_cmd)); - aml_append(method, aml_store(aml_arg(1), cpu_data)); - aml_append(method, aml_store(st_cmd, cpu_cmd)); - aml_append(method, aml_store(aml_arg(2), cpu_data)); - aml_append(method, aml_release(ctrl_lock)); - } - aml_append(cpus_dev, method); - - /* build Processor object for each processor */ - for (i = 0; i < arch_ids->len; i++) { - Aml *dev; - Aml *uid = aml_int(i); - GArray *madt_buf = g_array_new(0, 1, 1); - int arch_id = arch_ids->cpus[i].arch_id; - - if (opts.apci_1_compatible && arch_id < 255) { - dev = aml_processor(i, 0, 0, CPU_NAME_FMT, i); - } else { - dev = aml_device(CPU_NAME_FMT, i); - aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007"))); - aml_append(dev, aml_name_decl("_UID", uid)); - } - - method = aml_method("_STA", 0, AML_SERIALIZED); - aml_append(method, aml_return(aml_call1(CPU_STS_METHOD, uid))); - aml_append(dev, method); - - /* build _MAT object */ - assert(adevc && adevc->madt_cpu); - adevc->madt_cpu(adev, i, arch_ids, madt_buf); - switch (madt_buf->data[0]) { - case ACPI_APIC_PROCESSOR: { - AcpiMadtProcessorApic *apic = (void *)madt_buf->data; - apic->flags = cpu_to_le32(1); - break; - } - default: - assert(0); - } - aml_append(dev, aml_name_decl("_MAT", - aml_buffer(madt_buf->len, (uint8_t *)madt_buf->data))); - g_array_free(madt_buf, true); - - method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - aml_append(method, aml_call1(CPU_EJECT_METHOD, uid)); - aml_append(dev, method); - - method = aml_method("_OST", 3, AML_SERIALIZED); - aml_append(method, - aml_call4(CPU_OST_METHOD, uid, aml_arg(0), - aml_arg(1), aml_arg(2)) - ); - aml_append(dev, method); - aml_append(cpus_dev, dev); - } - } - aml_append(sb_scope, cpus_dev); - aml_append(table, sb_scope); - - method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED); - aml_append(method, aml_call0("\\_SB.CPUS." CPU_SCAN_METHOD)); - aml_append(table, method); - - g_free(cphp_res_path); - g_free(arch_ids); -} diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c index e19d90206..4d86743fd 100644 --- a/hw/acpi/cpu_hotplug.c +++ b/hw/acpi/cpu_hotplug.c @@ -14,14 +14,6 @@ #include "hw/acpi/cpu_hotplug.h" #include "qapi/error.h" #include "qom/cpu.h" -#include "hw/i386/pc.h" - -#define CPU_EJECT_METHOD "CPEJ" -#define CPU_MAT_METHOD "CPMA" -#define CPU_ON_BITMAP "CPON" -#define CPU_STATUS_METHOD "CPST" -#define CPU_STATUS_MAP "PRS" -#define CPU_SCAN_METHOD "PRSC" static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size) { @@ -34,15 +26,7 @@ static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size) static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data, unsigned int size) { - /* firmware never used to write in CPU present bitmap so use - this fact as means to switch QEMU into modern CPU hotplug - mode by writing 0 at the beginning of legacy CPU bitmap - */ - if (addr == 0 && data == 0) { - AcpiCpuHotplug *cpus = opaque; - object_property_set_bool(cpus->device, false, "cpu-hotplug-legacy", - &error_abort); - } + /* TODO: implement VCPU removal on guest signal that CPU can be removed */ } static const MemoryRegionOps AcpiCpuHotplug_ops = { @@ -70,18 +54,19 @@ static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu, g->sts[cpu_id / 8] |= (1 << (cpu_id % 8)); } -void legacy_acpi_cpu_plug_cb(HotplugHandler *hotplug_dev, - AcpiCpuHotplug *g, DeviceState *dev, Error **errp) +void acpi_cpu_plug_cb(ACPIREGS *ar, qemu_irq irq, + AcpiCpuHotplug *g, DeviceState *dev, Error **errp) { acpi_set_cpu_present_bit(g, CPU(dev), errp); if (*errp != NULL) { return; } - acpi_send_event(DEVICE(hotplug_dev), ACPI_CPU_HOTPLUG_STATUS); + + acpi_send_gpe_event(ar, irq, ACPI_CPU_HOTPLUG_STATUS); } -void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner, - AcpiCpuHotplug *gpe_cpu, uint16_t base) +void acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner, + AcpiCpuHotplug *gpe_cpu, uint16_t base) { CPUState *cpu; @@ -91,242 +76,4 @@ void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner, memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops, gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN); memory_region_add_subregion(parent, base, &gpe_cpu->io); - gpe_cpu->device = owner; -} - -void acpi_switch_to_modern_cphp(AcpiCpuHotplug *gpe_cpu, - CPUHotplugState *cpuhp_state, - uint16_t io_port) -{ - MemoryRegion *parent = pci_address_space_io(PCI_DEVICE(gpe_cpu->device)); - - memory_region_del_subregion(parent, &gpe_cpu->io); - cpu_hotplug_hw_init(parent, gpe_cpu->device, cpuhp_state, io_port); -} - -void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine, - uint16_t io_base) -{ - Aml *dev; - Aml *crs; - Aml *pkg; - Aml *field; - Aml *method; - Aml *if_ctx; - Aml *else_ctx; - int i, apic_idx; - Aml *sb_scope = aml_scope("_SB"); - uint8_t madt_tmpl[8] = {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}; - Aml *cpu_id = aml_arg(1); - Aml *apic_id = aml_arg(0); - Aml *cpu_on = aml_local(0); - Aml *madt = aml_local(1); - Aml *cpus_map = aml_name(CPU_ON_BITMAP); - Aml *zero = aml_int(0); - Aml *one = aml_int(1); - MachineClass *mc = MACHINE_GET_CLASS(machine); - CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(machine); - PCMachineState *pcms = PC_MACHINE(machine); - - /* - * _MAT method - creates an madt apic buffer - * apic_id = Arg0 = Local APIC ID - * cpu_id = Arg1 = Processor ID - * cpu_on = Local0 = CPON flag for this cpu - * madt = Local1 = Buffer (in madt apic form) to return - */ - method = aml_method(CPU_MAT_METHOD, 2, AML_NOTSERIALIZED); - aml_append(method, - aml_store(aml_derefof(aml_index(cpus_map, apic_id)), cpu_on)); - aml_append(method, - aml_store(aml_buffer(sizeof(madt_tmpl), madt_tmpl), madt)); - /* Update the processor id, lapic id, and enable/disable status */ - aml_append(method, aml_store(cpu_id, aml_index(madt, aml_int(2)))); - aml_append(method, aml_store(apic_id, aml_index(madt, aml_int(3)))); - aml_append(method, aml_store(cpu_on, aml_index(madt, aml_int(4)))); - aml_append(method, aml_return(madt)); - aml_append(sb_scope, method); - - /* - * _STA method - return ON status of cpu - * apic_id = Arg0 = Local APIC ID - * cpu_on = Local0 = CPON flag for this cpu - */ - method = aml_method(CPU_STATUS_METHOD, 1, AML_NOTSERIALIZED); - aml_append(method, - aml_store(aml_derefof(aml_index(cpus_map, apic_id)), cpu_on)); - if_ctx = aml_if(cpu_on); - { - aml_append(if_ctx, aml_return(aml_int(0xF))); - } - aml_append(method, if_ctx); - else_ctx = aml_else(); - { - aml_append(else_ctx, aml_return(zero)); - } - aml_append(method, else_ctx); - aml_append(sb_scope, method); - - method = aml_method(CPU_EJECT_METHOD, 2, AML_NOTSERIALIZED); - aml_append(method, aml_sleep(200)); - aml_append(sb_scope, method); - - method = aml_method(CPU_SCAN_METHOD, 0, AML_NOTSERIALIZED); - { - Aml *while_ctx, *if_ctx2, *else_ctx2; - Aml *bus_check_evt = aml_int(1); - Aml *remove_evt = aml_int(3); - Aml *status_map = aml_local(5); /* Local5 = active cpu bitmap */ - Aml *byte = aml_local(2); /* Local2 = last read byte from bitmap */ - Aml *idx = aml_local(0); /* Processor ID / APIC ID iterator */ - Aml *is_cpu_on = aml_local(1); /* Local1 = CPON flag for cpu */ - Aml *status = aml_local(3); /* Local3 = active state for cpu */ - - aml_append(method, aml_store(aml_name(CPU_STATUS_MAP), status_map)); - aml_append(method, aml_store(zero, byte)); - aml_append(method, aml_store(zero, idx)); - - /* While (idx < SizeOf(CPON)) */ - while_ctx = aml_while(aml_lless(idx, aml_sizeof(cpus_map))); - aml_append(while_ctx, - aml_store(aml_derefof(aml_index(cpus_map, idx)), is_cpu_on)); - - if_ctx = aml_if(aml_and(idx, aml_int(0x07), NULL)); - { - /* Shift down previously read bitmap byte */ - aml_append(if_ctx, aml_shiftright(byte, one, byte)); - } - aml_append(while_ctx, if_ctx); - - else_ctx = aml_else(); - { - /* Read next byte from cpu bitmap */ - aml_append(else_ctx, aml_store(aml_derefof(aml_index(status_map, - aml_shiftright(idx, aml_int(3), NULL))), byte)); - } - aml_append(while_ctx, else_ctx); - - aml_append(while_ctx, aml_store(aml_and(byte, one, NULL), status)); - if_ctx = aml_if(aml_lnot(aml_equal(is_cpu_on, status))); - { - /* State change - update CPON with new state */ - aml_append(if_ctx, aml_store(status, aml_index(cpus_map, idx))); - if_ctx2 = aml_if(aml_equal(status, one)); - { - aml_append(if_ctx2, - aml_call2(AML_NOTIFY_METHOD, idx, bus_check_evt)); - } - aml_append(if_ctx, if_ctx2); - else_ctx2 = aml_else(); - { - aml_append(else_ctx2, - aml_call2(AML_NOTIFY_METHOD, idx, remove_evt)); - } - } - aml_append(if_ctx, else_ctx2); - aml_append(while_ctx, if_ctx); - - aml_append(while_ctx, aml_increment(idx)); /* go to next cpu */ - aml_append(method, while_ctx); - } - aml_append(sb_scope, method); - - /* The current AML generator can cover the APIC ID range [0..255], - * inclusive, for VCPU hotplug. */ - QEMU_BUILD_BUG_ON(ACPI_CPU_HOTPLUG_ID_LIMIT > 256); - g_assert(pcms->apic_id_limit <= ACPI_CPU_HOTPLUG_ID_LIMIT); - - /* create PCI0.PRES device and its _CRS to reserve CPU hotplug MMIO */ - dev = aml_device("PCI0." stringify(CPU_HOTPLUG_RESOURCE_DEVICE)); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A06"))); - aml_append(dev, - aml_name_decl("_UID", aml_string("CPU Hotplug resources")) - ); - /* device present, functioning, decoding, not shown in UI */ - aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); - crs = aml_resource_template(); - aml_append(crs, - aml_io(AML_DECODE16, io_base, io_base, 1, ACPI_GPE_PROC_LEN) - ); - aml_append(dev, aml_name_decl("_CRS", crs)); - aml_append(sb_scope, dev); - /* declare CPU hotplug MMIO region and PRS field to access it */ - aml_append(sb_scope, aml_operation_region( - "PRST", AML_SYSTEM_IO, aml_int(io_base), ACPI_GPE_PROC_LEN)); - field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); - aml_append(field, aml_named_field("PRS", 256)); - aml_append(sb_scope, field); - - /* build Processor object for each processor */ - for (i = 0; i < apic_ids->len; i++) { - int apic_id = apic_ids->cpus[i].arch_id; - - assert(apic_id < ACPI_CPU_HOTPLUG_ID_LIMIT); - - dev = aml_processor(i, 0, 0, "CP%.02X", apic_id); - - method = aml_method("_MAT", 0, AML_NOTSERIALIZED); - aml_append(method, - aml_return(aml_call2(CPU_MAT_METHOD, aml_int(apic_id), aml_int(i)) - )); - aml_append(dev, method); - - method = aml_method("_STA", 0, AML_NOTSERIALIZED); - aml_append(method, - aml_return(aml_call1(CPU_STATUS_METHOD, aml_int(apic_id)))); - aml_append(dev, method); - - method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - aml_append(method, - aml_return(aml_call2(CPU_EJECT_METHOD, aml_int(apic_id), - aml_arg(0))) - ); - aml_append(dev, method); - - aml_append(sb_scope, dev); - } - - /* build this code: - * Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...} - */ - /* Arg0 = APIC ID */ - method = aml_method(AML_NOTIFY_METHOD, 2, AML_NOTSERIALIZED); - for (i = 0; i < apic_ids->len; i++) { - int apic_id = apic_ids->cpus[i].arch_id; - - if_ctx = aml_if(aml_equal(aml_arg(0), aml_int(apic_id))); - aml_append(if_ctx, - aml_notify(aml_name("CP%.02X", apic_id), aml_arg(1)) - ); - aml_append(method, if_ctx); - } - aml_append(sb_scope, method); - - /* build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })" - * - * Note: The ability to create variable-sized packages was first - * introduced in ACPI 2.0. ACPI 1.0 only allowed fixed-size packages - * ith up to 255 elements. Windows guests up to win2k8 fail when - * VarPackageOp is used. - */ - pkg = pcms->apic_id_limit <= 255 ? aml_package(pcms->apic_id_limit) : - aml_varpackage(pcms->apic_id_limit); - - for (i = 0, apic_idx = 0; i < apic_ids->len; i++) { - int apic_id = apic_ids->cpus[i].arch_id; - - for (; apic_idx < apic_id; apic_idx++) { - aml_append(pkg, aml_int(0)); - } - aml_append(pkg, aml_int(apic_ids->cpus[i].cpu ? 1 : 0)); - apic_idx = apic_id + 1; - } - aml_append(sb_scope, aml_name_decl(CPU_ON_BITMAP, pkg)); - g_free(apic_ids); - - aml_append(ctx, sb_scope); - - method = aml_method("\\_GPE._E02", 0, AML_NOTSERIALIZED); - aml_append(method, aml_call0("\\_SB." CPU_SCAN_METHOD)); - aml_append(ctx, method); } diff --git a/hw/acpi/cpu_hotplug_acpi_table.c b/hw/acpi/cpu_hotplug_acpi_table.c new file mode 100644 index 000000000..97bb1092a --- /dev/null +++ b/hw/acpi/cpu_hotplug_acpi_table.c @@ -0,0 +1,136 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/acpi/cpu_hotplug.h" + +void build_cpu_hotplug_aml(Aml *ctx) +{ + Aml *method; + Aml *if_ctx; + Aml *else_ctx; + Aml *sb_scope = aml_scope("_SB"); + uint8_t madt_tmpl[8] = {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}; + Aml *cpu_id = aml_arg(0); + Aml *cpu_on = aml_local(0); + Aml *madt = aml_local(1); + Aml *cpus_map = aml_name(CPU_ON_BITMAP); + Aml *zero = aml_int(0); + Aml *one = aml_int(1); + + /* + * _MAT method - creates an madt apic buffer + * cpu_id = Arg0 = Processor ID = Local APIC ID + * cpu_on = Local0 = CPON flag for this cpu + * madt = Local1 = Buffer (in madt apic form) to return + */ + method = aml_method(CPU_MAT_METHOD, 1, AML_NOTSERIALIZED); + aml_append(method, + aml_store(aml_derefof(aml_index(cpus_map, cpu_id)), cpu_on)); + aml_append(method, + aml_store(aml_buffer(sizeof(madt_tmpl), madt_tmpl), madt)); + /* Update the processor id, lapic id, and enable/disable status */ + aml_append(method, aml_store(cpu_id, aml_index(madt, aml_int(2)))); + aml_append(method, aml_store(cpu_id, aml_index(madt, aml_int(3)))); + aml_append(method, aml_store(cpu_on, aml_index(madt, aml_int(4)))); + aml_append(method, aml_return(madt)); + aml_append(sb_scope, method); + + /* + * _STA method - return ON status of cpu + * cpu_id = Arg0 = Processor ID = Local APIC ID + * cpu_on = Local0 = CPON flag for this cpu + */ + method = aml_method(CPU_STATUS_METHOD, 1, AML_NOTSERIALIZED); + aml_append(method, + aml_store(aml_derefof(aml_index(cpus_map, cpu_id)), cpu_on)); + if_ctx = aml_if(cpu_on); + { + aml_append(if_ctx, aml_return(aml_int(0xF))); + } + aml_append(method, if_ctx); + else_ctx = aml_else(); + { + aml_append(else_ctx, aml_return(zero)); + } + aml_append(method, else_ctx); + aml_append(sb_scope, method); + + method = aml_method(CPU_EJECT_METHOD, 2, AML_NOTSERIALIZED); + aml_append(method, aml_sleep(200)); + aml_append(sb_scope, method); + + method = aml_method(CPU_SCAN_METHOD, 0, AML_NOTSERIALIZED); + { + Aml *while_ctx, *if_ctx2, *else_ctx2; + Aml *bus_check_evt = aml_int(1); + Aml *remove_evt = aml_int(3); + Aml *status_map = aml_local(5); /* Local5 = active cpu bitmap */ + Aml *byte = aml_local(2); /* Local2 = last read byte from bitmap */ + Aml *idx = aml_local(0); /* Processor ID / APIC ID iterator */ + Aml *is_cpu_on = aml_local(1); /* Local1 = CPON flag for cpu */ + Aml *status = aml_local(3); /* Local3 = active state for cpu */ + + aml_append(method, aml_store(aml_name(CPU_STATUS_MAP), status_map)); + aml_append(method, aml_store(zero, byte)); + aml_append(method, aml_store(zero, idx)); + + /* While (idx < SizeOf(CPON)) */ + while_ctx = aml_while(aml_lless(idx, aml_sizeof(cpus_map))); + aml_append(while_ctx, + aml_store(aml_derefof(aml_index(cpus_map, idx)), is_cpu_on)); + + if_ctx = aml_if(aml_and(idx, aml_int(0x07), NULL)); + { + /* Shift down previously read bitmap byte */ + aml_append(if_ctx, aml_shiftright(byte, one, byte)); + } + aml_append(while_ctx, if_ctx); + + else_ctx = aml_else(); + { + /* Read next byte from cpu bitmap */ + aml_append(else_ctx, aml_store(aml_derefof(aml_index(status_map, + aml_shiftright(idx, aml_int(3), NULL))), byte)); + } + aml_append(while_ctx, else_ctx); + + aml_append(while_ctx, aml_store(aml_and(byte, one, NULL), status)); + if_ctx = aml_if(aml_lnot(aml_equal(is_cpu_on, status))); + { + /* State change - update CPON with new state */ + aml_append(if_ctx, aml_store(status, aml_index(cpus_map, idx))); + if_ctx2 = aml_if(aml_equal(status, one)); + { + aml_append(if_ctx2, + aml_call2(AML_NOTIFY_METHOD, idx, bus_check_evt)); + } + aml_append(if_ctx, if_ctx2); + else_ctx2 = aml_else(); + { + aml_append(else_ctx2, + aml_call2(AML_NOTIFY_METHOD, idx, remove_evt)); + } + } + aml_append(if_ctx, else_ctx2); + aml_append(while_ctx, if_ctx); + + aml_append(while_ctx, aml_increment(idx)); /* go to next cpu */ + aml_append(method, while_ctx); + } + aml_append(sb_scope, method); + + aml_append(ctx, sb_scope); +} diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index e5a3c18e5..27e978f5f 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -189,33 +189,6 @@ static const VMStateDescription vmstate_tco_io_state = { } }; -static bool vmstate_test_use_cpuhp(void *opaque) -{ - ICH9LPCPMRegs *s = opaque; - return !s->cpu_hotplug_legacy; -} - -static int vmstate_cpuhp_pre_load(void *opaque) -{ - ICH9LPCPMRegs *s = opaque; - Object *obj = OBJECT(s->gpe_cpu.device); - object_property_set_bool(obj, false, "cpu-hotplug-legacy", &error_abort); - return 0; -} - -static const VMStateDescription vmstate_cpuhp_state = { - .name = "ich9_pm/cpuhp", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .needed = vmstate_test_use_cpuhp, - .pre_load = vmstate_cpuhp_pre_load, - .fields = (VMStateField[]) { - VMSTATE_CPU_HOTPLUG(cpuhp_state, ICH9LPCPMRegs), - VMSTATE_END_OF_LIST() - } -}; - const VMStateDescription vmstate_ich9_pm = { .name = "ich9_pm", .version_id = 1, @@ -236,7 +209,6 @@ const VMStateDescription vmstate_ich9_pm = { .subsections = (const VMStateDescription*[]) { &vmstate_memhp_state, &vmstate_tco_io_state, - &vmstate_cpuhp_state, NULL } }; @@ -301,8 +273,8 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, pm->powerdown_notifier.notify = pm_powerdown_req; qemu_register_powerdown_notifier(&pm->powerdown_notifier); - legacy_acpi_cpu_hotplug_init(pci_address_space_io(lpc_pci), - OBJECT(lpc_pci), &pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE); + acpi_cpu_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci), + &pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE); if (pm->acpi_memory_hotplug.is_enabled) { acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci), @@ -334,26 +306,6 @@ static void ich9_pm_set_memory_hotplug_support(Object *obj, bool value, s->pm.acpi_memory_hotplug.is_enabled = value; } -static bool ich9_pm_get_cpu_hotplug_legacy(Object *obj, Error **errp) -{ - ICH9LPCState *s = ICH9_LPC_DEVICE(obj); - - return s->pm.cpu_hotplug_legacy; -} - -static void ich9_pm_set_cpu_hotplug_legacy(Object *obj, bool value, - Error **errp) -{ - ICH9LPCState *s = ICH9_LPC_DEVICE(obj); - - assert(!value); - if (s->pm.cpu_hotplug_legacy && value == false) { - acpi_switch_to_modern_cphp(&s->pm.gpe_cpu, &s->pm.cpuhp_state, - ICH9_CPU_HOTPLUG_IO_BASE); - } - s->pm.cpu_hotplug_legacy = value; -} - static void ich9_pm_get_disable_s3(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -445,7 +397,6 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) { static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN; pm->acpi_memory_hotplug.is_enabled = true; - pm->cpu_hotplug_legacy = true; pm->disable_s3 = 0; pm->disable_s4 = 0; pm->s4_val = 2; @@ -461,10 +412,6 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) ich9_pm_get_memory_hotplug_support, ich9_pm_set_memory_hotplug_support, NULL); - object_property_add_bool(obj, "cpu-hotplug-legacy", - ich9_pm_get_cpu_hotplug_legacy, - ich9_pm_set_cpu_hotplug_legacy, - NULL); object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8", ich9_pm_get_disable_s3, ich9_pm_set_disable_s3, @@ -483,58 +430,39 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) NULL); } -void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) +void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp) { - ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); - - if (lpc->pm.acpi_memory_hotplug.is_enabled && + if (pm->acpi_memory_hotplug.is_enabled && object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_plug_cb(hotplug_dev, &lpc->pm.acpi_memory_hotplug, + acpi_memory_plug_cb(&pm->acpi_regs, pm->irq, &pm->acpi_memory_hotplug, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - if (lpc->pm.cpu_hotplug_legacy) { - legacy_acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.gpe_cpu, dev, errp); - } else { - acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp); - } + acpi_cpu_plug_cb(&pm->acpi_regs, pm->irq, &pm->gpe_cpu, dev, errp); } else { error_setg(errp, "acpi: device plug request for not supported device" " type: %s", object_get_typename(OBJECT(dev))); } } -void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) +void ich9_pm_device_unplug_request_cb(ICH9LPCPMRegs *pm, DeviceState *dev, + Error **errp) { - ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); - - if (lpc->pm.acpi_memory_hotplug.is_enabled && + if (pm->acpi_memory_hotplug.is_enabled && object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_unplug_request_cb(hotplug_dev, - &lpc->pm.acpi_memory_hotplug, dev, - errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && - !lpc->pm.cpu_hotplug_legacy) { - acpi_cpu_unplug_request_cb(hotplug_dev, &lpc->pm.cpuhp_state, - dev, errp); + acpi_memory_unplug_request_cb(&pm->acpi_regs, pm->irq, + &pm->acpi_memory_hotplug, dev, errp); } else { error_setg(errp, "acpi: device unplug request for not supported device" " type: %s", object_get_typename(OBJECT(dev))); } } -void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, +void ich9_pm_device_unplug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp) { - ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); - - if (lpc->pm.acpi_memory_hotplug.is_enabled && + if (pm->acpi_memory_hotplug.is_enabled && object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_unplug_cb(&lpc->pm.acpi_memory_hotplug, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && - !lpc->pm.cpu_hotplug_legacy) { - acpi_cpu_unplug_cb(&lpc->pm.cpuhp_state, dev, errp); + acpi_memory_unplug_cb(&pm->acpi_memory_hotplug, dev, errp); } else { error_setg(errp, "acpi: device unplug for not supported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -546,7 +474,4 @@ void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) ICH9LPCState *s = ICH9_LPC_DEVICE(adev); acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list); - if (!s->pm.cpu_hotplug_legacy) { - acpi_cpu_ospm_status(&s->pm.cpuhp_state, list); - } } diff --git a/hw/acpi/ipmi.c b/hw/acpi/ipmi.c deleted file mode 100644 index 7e74ce446..000000000 --- a/hw/acpi/ipmi.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * IPMI ACPI firmware handling - * - * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC - * - * 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/ipmi/ipmi.h" -#include "hw/acpi/aml-build.h" -#include "hw/acpi/acpi.h" -#include "hw/acpi/ipmi.h" - -static Aml *aml_ipmi_crs(IPMIFwInfo *info) -{ - Aml *crs = aml_resource_template(); - - /* - * The base address is fixed and cannot change. That may be different - * if someone does PCI, but we aren't there yet. - */ - switch (info->memspace) { - case IPMI_MEMSPACE_IO: - aml_append(crs, aml_io(AML_DECODE16, info->base_address, - info->base_address + info->register_length - 1, - info->register_spacing, info->register_length)); - break; - case IPMI_MEMSPACE_MEM32: - aml_append(crs, - aml_dword_memory(AML_POS_DECODE, - AML_MIN_FIXED, AML_MAX_FIXED, - AML_NON_CACHEABLE, AML_READ_WRITE, - 0xffffffff, - info->base_address, - info->base_address + info->register_length - 1, - info->register_spacing, info->register_length)); - break; - case IPMI_MEMSPACE_MEM64: - aml_append(crs, - aml_qword_memory(AML_POS_DECODE, - AML_MIN_FIXED, AML_MAX_FIXED, - AML_NON_CACHEABLE, AML_READ_WRITE, - 0xffffffffffffffffULL, - info->base_address, - info->base_address + info->register_length - 1, - info->register_spacing, info->register_length)); - break; - case IPMI_MEMSPACE_SMBUS: - aml_append(crs, aml_return(aml_int(info->base_address))); - break; - default: - abort(); - } - - if (info->interrupt_number) { - aml_append(crs, aml_irq_no_flags(info->interrupt_number)); - } - - return crs; -} - -static Aml *aml_ipmi_device(IPMIFwInfo *info) -{ - Aml *dev; - uint16_t version = ((info->ipmi_spec_major_revision << 8) - | (info->ipmi_spec_minor_revision << 4)); - - assert(info->ipmi_spec_minor_revision <= 15); - - dev = aml_device("MI%d", info->uuid); - aml_append(dev, aml_name_decl("_HID", aml_eisaid("IPI0001"))); - aml_append(dev, aml_name_decl("_STR", aml_string("ipmi_%s", - info->interface_name))); - aml_append(dev, aml_name_decl("_UID", aml_int(info->uuid))); - aml_append(dev, aml_name_decl("_CRS", aml_ipmi_crs(info))); - aml_append(dev, aml_name_decl("_IFT", aml_int(info->interface_type))); - aml_append(dev, aml_name_decl("_SRV", aml_int(version))); - - return dev; -} - -void build_acpi_ipmi_devices(Aml *scope, BusState *bus) -{ - - BusChild *kid; - - QTAILQ_FOREACH(kid, &bus->children, sibling) { - IPMIInterface *ii; - IPMIInterfaceClass *iic; - IPMIFwInfo info; - Object *obj = object_dynamic_cast(OBJECT(kid->child), - TYPE_IPMI_INTERFACE); - - if (!obj) { - continue; - } - - ii = IPMI_INTERFACE(obj); - iic = IPMI_INTERFACE_GET_CLASS(obj); - iic->get_fwinfo(ii, &info); - aml_append(scope, aml_ipmi_device(&info)); - } -} diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index ec4e64b36..f65a3a21e 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -228,7 +228,7 @@ acpi_memory_slot_status(MemHotplugState *mem_st, return &mem_st->devs[slot]; } -void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st, +void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st, DeviceState *dev, Error **errp) { MemStatus *mdev; @@ -247,11 +247,13 @@ void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st, mdev->is_enabled = true; if (dev->hotplugged) { mdev->is_inserting = true; - acpi_send_event(DEVICE(hotplug_dev), ACPI_MEMORY_HOTPLUG_STATUS); + + /* do ACPI magic */ + acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS); } } -void acpi_memory_unplug_request_cb(HotplugHandler *hotplug_dev, +void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st, DeviceState *dev, Error **errp) { @@ -263,7 +265,9 @@ void acpi_memory_unplug_request_cb(HotplugHandler *hotplug_dev, } mdev->is_removing = true; - acpi_send_event(DEVICE(hotplug_dev), ACPI_MEMORY_HOTPLUG_STATUS); + + /* Do ACPI magic */ + acpi_send_gpe_event(ar, irq, ACPI_MEMORY_HOTPLUG_STATUS); } void acpi_memory_unplug_cb(MemHotplugState *mem_st, diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c index e486128aa..9531340e5 100644 --- a/hw/acpi/nvdimm.c +++ b/hw/acpi/nvdimm.c @@ -216,26 +216,6 @@ static uint32_t nvdimm_slot_to_dcr_index(int slot) return nvdimm_slot_to_spa_index(slot) + 1; } -static NVDIMMDevice *nvdimm_get_device_by_handle(uint32_t handle) -{ - NVDIMMDevice *nvdimm = NULL; - GSList *list, *device_list = nvdimm_get_plugged_device_list(); - - for (list = device_list; list; list = list->next) { - NVDIMMDevice *nvd = list->data; - int slot = object_property_get_int(OBJECT(nvd), PC_DIMM_SLOT_PROP, - NULL); - - if (nvdimm_slot_to_handle(slot) == handle) { - nvdimm = nvd; - break; - } - } - - g_slist_free(device_list); - return nvdimm; -} - /* ACPI 6.0: 5.2.25.1 System Physical Address Range Structure */ static void nvdimm_build_structure_spa(GArray *structures, DeviceState *dev) @@ -373,7 +353,7 @@ static GArray *nvdimm_build_device_structure(GSList *device_list) } static void nvdimm_build_nfit(GSList *device_list, GArray *table_offsets, - GArray *table_data, BIOSLinker *linker) + GArray *table_data, GArray *linker) { GArray *structures = nvdimm_build_device_structure(device_list); unsigned int header; @@ -398,19 +378,17 @@ struct NvdimmDsmIn { uint32_t function; /* the remaining size in the page is used by arg3. */ union { - uint8_t arg3[4084]; + uint8_t arg3[0]; }; } QEMU_PACKED; typedef struct NvdimmDsmIn NvdimmDsmIn; -QEMU_BUILD_BUG_ON(sizeof(NvdimmDsmIn) != 4096); struct NvdimmDsmOut { /* the size of buffer filled by QEMU. */ uint32_t len; - uint8_t data[4092]; + uint8_t data[0]; } QEMU_PACKED; typedef struct NvdimmDsmOut NvdimmDsmOut; -QEMU_BUILD_BUG_ON(sizeof(NvdimmDsmOut) != 4096); struct NvdimmDsmFunc0Out { /* the size of buffer filled by QEMU. */ @@ -426,282 +404,6 @@ struct NvdimmDsmFuncNoPayloadOut { } QEMU_PACKED; typedef struct NvdimmDsmFuncNoPayloadOut NvdimmDsmFuncNoPayloadOut; -struct NvdimmFuncGetLabelSizeOut { - /* the size of buffer filled by QEMU. */ - uint32_t len; - uint32_t func_ret_status; /* return status code. */ - uint32_t label_size; /* the size of label data area. */ - /* - * Maximum size of the namespace label data length supported by - * the platform in Get/Set Namespace Label Data functions. - */ - uint32_t max_xfer; -} QEMU_PACKED; -typedef struct NvdimmFuncGetLabelSizeOut NvdimmFuncGetLabelSizeOut; -QEMU_BUILD_BUG_ON(sizeof(NvdimmFuncGetLabelSizeOut) > 4096); - -struct NvdimmFuncGetLabelDataIn { - uint32_t offset; /* the offset in the namespace label data area. */ - uint32_t length; /* the size of data is to be read via the function. */ -} QEMU_PACKED; -typedef struct NvdimmFuncGetLabelDataIn NvdimmFuncGetLabelDataIn; -QEMU_BUILD_BUG_ON(sizeof(NvdimmFuncGetLabelDataIn) + - offsetof(NvdimmDsmIn, arg3) > 4096); - -struct NvdimmFuncGetLabelDataOut { - /* the size of buffer filled by QEMU. */ - uint32_t len; - uint32_t func_ret_status; /* return status code. */ - uint8_t out_buf[0]; /* the data got via Get Namesapce Label function. */ -} QEMU_PACKED; -typedef struct NvdimmFuncGetLabelDataOut NvdimmFuncGetLabelDataOut; -QEMU_BUILD_BUG_ON(sizeof(NvdimmFuncGetLabelDataOut) > 4096); - -struct NvdimmFuncSetLabelDataIn { - uint32_t offset; /* the offset in the namespace label data area. */ - uint32_t length; /* the size of data is to be written via the function. */ - uint8_t in_buf[0]; /* the data written to label data area. */ -} QEMU_PACKED; -typedef struct NvdimmFuncSetLabelDataIn NvdimmFuncSetLabelDataIn; -QEMU_BUILD_BUG_ON(sizeof(NvdimmFuncSetLabelDataIn) + - offsetof(NvdimmDsmIn, arg3) > 4096); - -static void -nvdimm_dsm_function0(uint32_t supported_func, hwaddr dsm_mem_addr) -{ - NvdimmDsmFunc0Out func0 = { - .len = cpu_to_le32(sizeof(func0)), - .supported_func = cpu_to_le32(supported_func), - }; - cpu_physical_memory_write(dsm_mem_addr, &func0, sizeof(func0)); -} - -static void -nvdimm_dsm_no_payload(uint32_t func_ret_status, hwaddr dsm_mem_addr) -{ - NvdimmDsmFuncNoPayloadOut out = { - .len = cpu_to_le32(sizeof(out)), - .func_ret_status = cpu_to_le32(func_ret_status), - }; - cpu_physical_memory_write(dsm_mem_addr, &out, sizeof(out)); -} - -static void nvdimm_dsm_root(NvdimmDsmIn *in, hwaddr dsm_mem_addr) -{ - /* - * function 0 is called to inquire which functions are supported by - * OSPM - */ - if (!in->function) { - nvdimm_dsm_function0(0 /* No function supported other than - function 0 */, dsm_mem_addr); - return; - } - - /* No function except function 0 is supported yet. */ - nvdimm_dsm_no_payload(1 /* Not Supported */, dsm_mem_addr); -} - -/* - * the max transfer size is the max size transferred by both a - * 'Get Namespace Label Data' function and a 'Set Namespace Label Data' - * function. - */ -static uint32_t nvdimm_get_max_xfer_label_size(void) -{ - uint32_t max_get_size, max_set_size, dsm_memory_size = 4096; - - /* - * the max data ACPI can read one time which is transferred by - * the response of 'Get Namespace Label Data' function. - */ - max_get_size = dsm_memory_size - sizeof(NvdimmFuncGetLabelDataOut); - - /* - * the max data ACPI can write one time which is transferred by - * 'Set Namespace Label Data' function. - */ - max_set_size = dsm_memory_size - offsetof(NvdimmDsmIn, arg3) - - sizeof(NvdimmFuncSetLabelDataIn); - - return MIN(max_get_size, max_set_size); -} - -/* - * DSM Spec Rev1 4.4 Get Namespace Label Size (Function Index 4). - * - * It gets the size of Namespace Label data area and the max data size - * that Get/Set Namespace Label Data functions can transfer. - */ -static void nvdimm_dsm_label_size(NVDIMMDevice *nvdimm, hwaddr dsm_mem_addr) -{ - NvdimmFuncGetLabelSizeOut label_size_out = { - .len = cpu_to_le32(sizeof(label_size_out)), - }; - uint32_t label_size, mxfer; - - label_size = nvdimm->label_size; - mxfer = nvdimm_get_max_xfer_label_size(); - - nvdimm_debug("label_size %#x, max_xfer %#x.\n", label_size, mxfer); - - label_size_out.func_ret_status = cpu_to_le32(0 /* Success */); - label_size_out.label_size = cpu_to_le32(label_size); - label_size_out.max_xfer = cpu_to_le32(mxfer); - - cpu_physical_memory_write(dsm_mem_addr, &label_size_out, - sizeof(label_size_out)); -} - -static uint32_t nvdimm_rw_label_data_check(NVDIMMDevice *nvdimm, - uint32_t offset, uint32_t length) -{ - uint32_t ret = 3 /* Invalid Input Parameters */; - - if (offset + length < offset) { - nvdimm_debug("offset %#x + length %#x is overflow.\n", offset, - length); - return ret; - } - - if (nvdimm->label_size < offset + length) { - nvdimm_debug("position %#x is beyond label data (len = %" PRIx64 ").\n", - offset + length, nvdimm->label_size); - return ret; - } - - if (length > nvdimm_get_max_xfer_label_size()) { - nvdimm_debug("length (%#x) is larger than max_xfer (%#x).\n", - length, nvdimm_get_max_xfer_label_size()); - return ret; - } - - return 0 /* Success */; -} - -/* - * DSM Spec Rev1 4.5 Get Namespace Label Data (Function Index 5). - */ -static void nvdimm_dsm_get_label_data(NVDIMMDevice *nvdimm, NvdimmDsmIn *in, - hwaddr dsm_mem_addr) -{ - NVDIMMClass *nvc = NVDIMM_GET_CLASS(nvdimm); - NvdimmFuncGetLabelDataIn *get_label_data; - NvdimmFuncGetLabelDataOut *get_label_data_out; - uint32_t status; - int size; - - get_label_data = (NvdimmFuncGetLabelDataIn *)in->arg3; - le32_to_cpus(&get_label_data->offset); - le32_to_cpus(&get_label_data->length); - - nvdimm_debug("Read Label Data: offset %#x length %#x.\n", - get_label_data->offset, get_label_data->length); - - status = nvdimm_rw_label_data_check(nvdimm, get_label_data->offset, - get_label_data->length); - if (status != 0 /* Success */) { - nvdimm_dsm_no_payload(status, dsm_mem_addr); - return; - } - - size = sizeof(*get_label_data_out) + get_label_data->length; - assert(size <= 4096); - get_label_data_out = g_malloc(size); - - get_label_data_out->len = cpu_to_le32(size); - get_label_data_out->func_ret_status = cpu_to_le32(0 /* Success */); - nvc->read_label_data(nvdimm, get_label_data_out->out_buf, - get_label_data->length, get_label_data->offset); - - cpu_physical_memory_write(dsm_mem_addr, get_label_data_out, size); - g_free(get_label_data_out); -} - -/* - * DSM Spec Rev1 4.6 Set Namespace Label Data (Function Index 6). - */ -static void nvdimm_dsm_set_label_data(NVDIMMDevice *nvdimm, NvdimmDsmIn *in, - hwaddr dsm_mem_addr) -{ - NVDIMMClass *nvc = NVDIMM_GET_CLASS(nvdimm); - NvdimmFuncSetLabelDataIn *set_label_data; - uint32_t status; - - set_label_data = (NvdimmFuncSetLabelDataIn *)in->arg3; - - le32_to_cpus(&set_label_data->offset); - le32_to_cpus(&set_label_data->length); - - nvdimm_debug("Write Label Data: offset %#x length %#x.\n", - set_label_data->offset, set_label_data->length); - - status = nvdimm_rw_label_data_check(nvdimm, set_label_data->offset, - set_label_data->length); - if (status != 0 /* Success */) { - nvdimm_dsm_no_payload(status, dsm_mem_addr); - return; - } - - assert(sizeof(*in) + sizeof(*set_label_data) + set_label_data->length <= - 4096); - - nvc->write_label_data(nvdimm, set_label_data->in_buf, - set_label_data->length, set_label_data->offset); - nvdimm_dsm_no_payload(0 /* Success */, dsm_mem_addr); -} - -static void nvdimm_dsm_device(NvdimmDsmIn *in, hwaddr dsm_mem_addr) -{ - NVDIMMDevice *nvdimm = nvdimm_get_device_by_handle(in->handle); - - /* See the comments in nvdimm_dsm_root(). */ - if (!in->function) { - uint32_t supported_func = 0; - - if (nvdimm && nvdimm->label_size) { - supported_func |= 0x1 /* Bit 0 indicates whether there is - support for any functions other - than function 0. */ | - 1 << 4 /* Get Namespace Label Size */ | - 1 << 5 /* Get Namespace Label Data */ | - 1 << 6 /* Set Namespace Label Data */; - } - nvdimm_dsm_function0(supported_func, dsm_mem_addr); - return; - } - - if (!nvdimm) { - nvdimm_dsm_no_payload(2 /* Non-Existing Memory Device */, - dsm_mem_addr); - return; - } - - /* Encode DSM function according to DSM Spec Rev1. */ - switch (in->function) { - case 4 /* Get Namespace Label Size */: - if (nvdimm->label_size) { - nvdimm_dsm_label_size(nvdimm, dsm_mem_addr); - return; - } - break; - case 5 /* Get Namespace Label Data */: - if (nvdimm->label_size) { - nvdimm_dsm_get_label_data(nvdimm, in, dsm_mem_addr); - return; - } - break; - case 0x6 /* Set Namespace Label Data */: - if (nvdimm->label_size) { - nvdimm_dsm_set_label_data(nvdimm, in, dsm_mem_addr); - return; - } - break; - } - - nvdimm_dsm_no_payload(1 /* Not Supported */, dsm_mem_addr); -} - static uint64_t nvdimm_dsm_read(void *opaque, hwaddr addr, unsigned size) { @@ -722,8 +424,8 @@ nvdimm_dsm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) * can change its content while we are doing DSM emulation. Avoid * this by copying DSM memory to QEMU local memory. */ - in = g_new(NvdimmDsmIn, 1); - cpu_physical_memory_read(dsm_mem_addr, in, sizeof(*in)); + in = g_malloc(TARGET_PAGE_SIZE); + cpu_physical_memory_read(dsm_mem_addr, in, TARGET_PAGE_SIZE); le32_to_cpus(&in->revision); le32_to_cpus(&in->function); @@ -732,22 +434,26 @@ nvdimm_dsm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) nvdimm_debug("Revision %#x Handler %#x Function %#x.\n", in->revision, in->handle, in->function); - if (in->revision != 0x1 /* Currently we only support DSM Spec Rev1. */) { - nvdimm_debug("Revision %#x is not supported, expect %#x.\n", - in->revision, 0x1); - nvdimm_dsm_no_payload(1 /* Not Supported */, dsm_mem_addr); - goto exit; - } - - /* Handle 0 is reserved for NVDIMM Root Device. */ - if (!in->handle) { - nvdimm_dsm_root(in, dsm_mem_addr); - goto exit; + /* + * function 0 is called to inquire which functions are supported by + * OSPM + */ + if (in->function == 0) { + NvdimmDsmFunc0Out func0 = { + .len = cpu_to_le32(sizeof(func0)), + /* No function supported other than function 0 */ + .supported_func = cpu_to_le32(0), + }; + cpu_physical_memory_write(dsm_mem_addr, &func0, sizeof func0); + } else { + /* No function except function 0 is supported yet. */ + NvdimmDsmFuncNoPayloadOut out = { + .len = cpu_to_le32(sizeof(out)), + .func_ret_status = cpu_to_le32(1) /* Not Supported */, + }; + cpu_physical_memory_write(dsm_mem_addr, &out, sizeof(out)); } - nvdimm_dsm_device(in, dsm_mem_addr); - -exit: g_free(in); } @@ -769,7 +475,7 @@ void nvdimm_init_acpi_state(AcpiNVDIMMState *state, MemoryRegion *io, memory_region_add_subregion(io, NVDIMM_ACPI_IO_BASE, &state->io_mr); state->dsm_mem = g_array_new(false, true /* clear */, 1); - acpi_data_push(state->dsm_mem, sizeof(NvdimmDsmIn)); + acpi_data_push(state->dsm_mem, TARGET_PAGE_SIZE); fw_cfg_add_file(fw_cfg, NVDIMM_DSM_MEM_FILE, state->dsm_mem->data, state->dsm_mem->len); } @@ -779,39 +485,18 @@ void nvdimm_init_acpi_state(AcpiNVDIMMState *state, MemoryRegion *io, static void nvdimm_build_common_dsm(Aml *dev) { - Aml *method, *ifctx, *function, *handle, *uuid, *dsm_mem, *result_size; - Aml *elsectx, *unsupport, *unpatched, *expected_uuid, *uuid_invalid; - Aml *pckg, *pckg_index, *pckg_buf; + Aml *method, *ifctx, *function, *dsm_mem, *unpatched, *result_size; uint8_t byte_list[1]; - method = aml_method(NVDIMM_COMMON_DSM, 5, AML_SERIALIZED); - uuid = aml_arg(0); + method = aml_method(NVDIMM_COMMON_DSM, 4, AML_SERIALIZED); function = aml_arg(2); - handle = aml_arg(4); dsm_mem = aml_name(NVDIMM_ACPI_MEM_ADDR); /* * do not support any method if DSM memory address has not been * patched. */ - unpatched = aml_equal(dsm_mem, aml_int(0x0)); - - expected_uuid = aml_local(0); - - ifctx = aml_if(aml_equal(handle, aml_int(0x0))); - aml_append(ifctx, aml_store( - aml_touuid("2F10E7A4-9E91-11E4-89D3-123B93F75CBA") - /* UUID for NVDIMM Root Device */, expected_uuid)); - aml_append(method, ifctx); - elsectx = aml_else(); - aml_append(elsectx, aml_store( - aml_touuid("4309AC30-0D11-11E4-9191-0800200C9A66") - /* UUID for NVDIMM Devices */, expected_uuid)); - aml_append(method, elsectx); - - uuid_invalid = aml_lnot(aml_equal(uuid, expected_uuid)); - - unsupport = aml_if(aml_or(unpatched, uuid_invalid, NULL)); + unpatched = aml_if(aml_equal(dsm_mem, aml_int(0x0))); /* * function 0 is called to inquire what functions are supported by @@ -820,42 +505,24 @@ static void nvdimm_build_common_dsm(Aml *dev) ifctx = aml_if(aml_equal(function, aml_int(0))); byte_list[0] = 0 /* No function Supported */; aml_append(ifctx, aml_return(aml_buffer(1, byte_list))); - aml_append(unsupport, ifctx); + aml_append(unpatched, ifctx); /* No function is supported yet. */ byte_list[0] = 1 /* Not Supported */; - aml_append(unsupport, aml_return(aml_buffer(1, byte_list))); - aml_append(method, unsupport); + aml_append(unpatched, aml_return(aml_buffer(1, byte_list))); + aml_append(method, unpatched); /* * The HDLE indicates the DSM function is issued from which device, - * it reserves 0 for root device and is the handle for NVDIMM devices. - * See the comments in nvdimm_slot_to_handle(). + * it is not used at this time as no function is supported yet. + * Currently we make it always be 0 for all the devices and will set + * the appropriate value once real function is implemented. */ - aml_append(method, aml_store(handle, aml_name("HDLE"))); + aml_append(method, aml_store(aml_int(0x0), aml_name("HDLE"))); aml_append(method, aml_store(aml_arg(1), aml_name("REVS"))); aml_append(method, aml_store(aml_arg(2), aml_name("FUNC"))); /* - * The fourth parameter (Arg3) of _DSM is a package which contains - * a buffer, the layout of the buffer is specified by UUID (Arg0), - * Revision ID (Arg1) and Function Index (Arg2) which are documented - * in the DSM Spec. - */ - pckg = aml_arg(3); - ifctx = aml_if(aml_and(aml_equal(aml_object_type(pckg), - aml_int(4 /* Package */)) /* It is a Package? */, - aml_equal(aml_sizeof(pckg), aml_int(1)) /* 1 element? */, - NULL)); - - pckg_index = aml_local(2); - pckg_buf = aml_local(3); - aml_append(ifctx, aml_store(aml_index(pckg, aml_int(0)), pckg_index)); - aml_append(ifctx, aml_store(aml_derefof(pckg_index), pckg_buf)); - aml_append(ifctx, aml_store(pckg_buf, aml_name("ARG3"))); - aml_append(method, ifctx); - - /* * tell QEMU about the real address of DSM memory, then QEMU * gets the control and fills the result in DSM memory. */ @@ -873,14 +540,13 @@ static void nvdimm_build_common_dsm(Aml *dev) aml_append(dev, method); } -static void nvdimm_build_device_dsm(Aml *dev, uint32_t handle) +static void nvdimm_build_device_dsm(Aml *dev) { Aml *method; method = aml_method("_DSM", 4, AML_NOTSERIALIZED); - aml_append(method, aml_return(aml_call5(NVDIMM_COMMON_DSM, aml_arg(0), - aml_arg(1), aml_arg(2), aml_arg(3), - aml_int(handle)))); + aml_append(method, aml_return(aml_call4(NVDIMM_COMMON_DSM, aml_arg(0), + aml_arg(1), aml_arg(2), aml_arg(3)))); aml_append(dev, method); } @@ -905,14 +571,13 @@ static void nvdimm_build_nvdimm_devices(GSList *device_list, Aml *root_dev) */ aml_append(nvdimm_dev, aml_name_decl("_ADR", aml_int(handle))); - nvdimm_build_device_dsm(nvdimm_dev, handle); + nvdimm_build_device_dsm(nvdimm_dev); aml_append(root_dev, nvdimm_dev); } } static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets, - GArray *table_data, BIOSLinker *linker, - GArray *dsm_dma_arrea) + GArray *table_data, GArray *linker) { Aml *ssdt, *sb_scope, *dev, *field; int mem_addr_offset, nvdimm_ssdt; @@ -943,7 +608,7 @@ static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets, aml_append(dev, aml_operation_region("NPIO", AML_SYSTEM_IO, aml_int(NVDIMM_ACPI_IO_BASE), NVDIMM_ACPI_IO_LEN)); aml_append(dev, aml_operation_region("NRAM", AML_SYSTEM_MEMORY, - aml_name(NVDIMM_ACPI_MEM_ADDR), sizeof(NvdimmDsmIn))); + aml_name(NVDIMM_ACPI_MEM_ADDR), TARGET_PAGE_SIZE)); /* * DSM notifier: @@ -977,7 +642,8 @@ static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets, aml_append(field, aml_named_field("FUNC", sizeof(typeof_field(NvdimmDsmIn, function)) * BITS_PER_BYTE)); aml_append(field, aml_named_field("ARG3", - (sizeof(NvdimmDsmIn) - offsetof(NvdimmDsmIn, arg3)) * BITS_PER_BYTE)); + (TARGET_PAGE_SIZE - offsetof(NvdimmDsmIn, arg3)) * + BITS_PER_BYTE)); aml_append(dev, field); /* @@ -993,13 +659,12 @@ static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets, aml_append(field, aml_named_field("RLEN", sizeof(typeof_field(NvdimmDsmOut, len)) * BITS_PER_BYTE)); aml_append(field, aml_named_field("ODAT", - (sizeof(NvdimmDsmOut) - offsetof(NvdimmDsmOut, data)) * BITS_PER_BYTE)); + (TARGET_PAGE_SIZE - offsetof(NvdimmDsmOut, data)) * + BITS_PER_BYTE)); aml_append(dev, field); nvdimm_build_common_dsm(dev); - - /* 0 is reserved for root device. */ - nvdimm_build_device_dsm(dev, 0); + nvdimm_build_device_dsm(dev); nvdimm_build_nvdimm_devices(device_list, dev); @@ -1013,12 +678,12 @@ static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets, mem_addr_offset = build_append_named_dword(table_data, NVDIMM_ACPI_MEM_ADDR); - bios_linker_loader_alloc(linker, - NVDIMM_DSM_MEM_FILE, dsm_dma_arrea, - sizeof(NvdimmDsmIn), false /* high memory */); - bios_linker_loader_add_pointer(linker, - ACPI_BUILD_TABLE_FILE, mem_addr_offset, sizeof(uint32_t), - NVDIMM_DSM_MEM_FILE, 0); + bios_linker_loader_alloc(linker, NVDIMM_DSM_MEM_FILE, TARGET_PAGE_SIZE, + false /* high memory */); + bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, + NVDIMM_DSM_MEM_FILE, table_data, + table_data->data + mem_addr_offset, + sizeof(uint32_t)); build_header(linker, table_data, (void *)(table_data->data + nvdimm_ssdt), "SSDT", table_data->len - nvdimm_ssdt, 1, NULL, "NVDIMM"); @@ -1026,7 +691,7 @@ static void nvdimm_build_ssdt(GSList *device_list, GArray *table_offsets, } void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data, - BIOSLinker *linker, GArray *dsm_dma_arrea) + GArray *linker) { GSList *device_list; @@ -1036,7 +701,6 @@ void nvdimm_build_acpi(GArray *table_offsets, GArray *table_data, return; } nvdimm_build_nfit(device_list, table_offsets, table_data, linker); - nvdimm_build_ssdt(device_list, table_offsets, table_data, linker, - dsm_dma_arrea); + nvdimm_build_ssdt(device_list, table_offsets, table_data, linker); g_slist_free(device_list); } diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index d957d1e30..71f4c4e14 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -182,7 +182,7 @@ void acpi_pcihp_reset(AcpiPciHpState *s) acpi_pcihp_update(s); } -void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, +void acpi_pcihp_device_plug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s, DeviceState *dev, Error **errp) { PCIDevice *pdev = PCI_DEVICE(dev); @@ -202,10 +202,11 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, } s->acpi_pcihp_pci_status[bsel].up |= (1U << slot); - acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS); + + acpi_send_gpe_event(ar, irq, ACPI_PCI_HOTPLUG_STATUS); } -void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, +void acpi_pcihp_device_unplug_cb(ACPIREGS *ar, qemu_irq irq, AcpiPciHpState *s, DeviceState *dev, Error **errp) { PCIDevice *pdev = PCI_DEVICE(dev); @@ -218,7 +219,8 @@ void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, } s->acpi_pcihp_pci_status[bsel].down |= (1U << slot); - acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS); + + acpi_send_gpe_event(ar, irq, ACPI_PCI_HOTPLUG_STATUS); } static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size) diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 2adc246b0..16abdf162 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -34,13 +34,11 @@ #include "hw/acpi/piix4.h" #include "hw/acpi/pcihp.h" #include "hw/acpi/cpu_hotplug.h" -#include "hw/acpi/cpu.h" #include "hw/hotplug.h" #include "hw/mem/pc-dimm.h" #include "hw/acpi/memory_hotplug.h" #include "hw/acpi/acpi_dev_interface.h" #include "hw/xen/xen.h" -#include "qom/cpu.h" //#define DEBUG @@ -87,9 +85,7 @@ typedef struct PIIX4PMState { uint8_t disable_s4; uint8_t s4_val; - bool cpu_hotplug_legacy; AcpiCpuHotplug gpe_cpu; - CPUHotplugState cpuhp_state; MemHotplugState acpi_memory_hotplug; } PIIX4PMState; @@ -276,32 +272,6 @@ static const VMStateDescription vmstate_memhp_state = { } }; -static bool vmstate_test_use_cpuhp(void *opaque) -{ - PIIX4PMState *s = opaque; - return !s->cpu_hotplug_legacy; -} - -static int vmstate_cpuhp_pre_load(void *opaque) -{ - Object *obj = OBJECT(opaque); - object_property_set_bool(obj, false, "cpu-hotplug-legacy", &error_abort); - return 0; -} - -static const VMStateDescription vmstate_cpuhp_state = { - .name = "piix4_pm/cpuhp", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .needed = vmstate_test_use_cpuhp, - .pre_load = vmstate_cpuhp_pre_load, - .fields = (VMStateField[]) { - VMSTATE_CPU_HOTPLUG(cpuhp_state, PIIX4PMState), - VMSTATE_END_OF_LIST() - } -}; - /* qemu-kvm 1.2 uses version 3 but advertised as 2 * To support incoming qemu-kvm 1.2 migration, change version_id * and minimum_version_id to 2 below (which breaks migration from @@ -336,7 +306,6 @@ static const VMStateDescription vmstate_acpi = { }, .subsections = (const VMStateDescription*[]) { &vmstate_memhp_state, - &vmstate_cpuhp_state, NULL } }; @@ -378,15 +347,12 @@ static void piix4_device_plug_cb(HotplugHandler *hotplug_dev, if (s->acpi_memory_hotplug.is_enabled && object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_plug_cb(hotplug_dev, &s->acpi_memory_hotplug, dev, errp); + acpi_memory_plug_cb(&s->ar, s->irq, &s->acpi_memory_hotplug, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { - acpi_pcihp_device_plug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev, errp); + acpi_pcihp_device_plug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev, + errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - if (s->cpu_hotplug_legacy) { - legacy_acpi_cpu_plug_cb(hotplug_dev, &s->gpe_cpu, dev, errp); - } else { - acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp); - } + acpi_cpu_plug_cb(&s->ar, s->irq, &s->gpe_cpu, dev, errp); } else { error_setg(errp, "acpi: device plug request for not supported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -400,14 +366,11 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev, if (s->acpi_memory_hotplug.is_enabled && object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { - acpi_memory_unplug_request_cb(hotplug_dev, &s->acpi_memory_hotplug, + acpi_memory_unplug_request_cb(&s->ar, s->irq, &s->acpi_memory_hotplug, dev, errp); } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { - acpi_pcihp_device_unplug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev, + acpi_pcihp_device_unplug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && - !s->cpu_hotplug_legacy) { - acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp); } else { error_setg(errp, "acpi: device unplug request for not supported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -422,9 +385,6 @@ static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev, if (s->acpi_memory_hotplug.is_enabled && object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && - !s->cpu_hotplug_legacy) { - acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp); } else { error_setg(errp, "acpi: device unplug for not supported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -600,26 +560,6 @@ static const MemoryRegionOps piix4_gpe_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; - -static bool piix4_get_cpu_hotplug_legacy(Object *obj, Error **errp) -{ - PIIX4PMState *s = PIIX4_PM(obj); - - return s->cpu_hotplug_legacy; -} - -static void piix4_set_cpu_hotplug_legacy(Object *obj, bool value, Error **errp) -{ - PIIX4PMState *s = PIIX4_PM(obj); - - assert(!value); - if (s->cpu_hotplug_legacy && value == false) { - acpi_switch_to_modern_cphp(&s->gpe_cpu, &s->cpuhp_state, - PIIX4_CPU_HOTPLUG_IO_BASE); - } - s->cpu_hotplug_legacy = value; -} - static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, PCIBus *bus, PIIX4PMState *s) { @@ -630,13 +570,8 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent, s->use_acpi_pci_hotplug); - s->cpu_hotplug_legacy = true; - object_property_add_bool(OBJECT(s), "cpu-hotplug-legacy", - piix4_get_cpu_hotplug_legacy, - piix4_set_cpu_hotplug_legacy, - NULL); - legacy_acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu, - PIIX4_CPU_HOTPLUG_IO_BASE); + acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu, + PIIX4_CPU_HOTPLUG_IO_BASE); if (s->acpi_memory_hotplug.is_enabled) { acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug); @@ -648,16 +583,6 @@ static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) PIIX4PMState *s = PIIX4_PM(adev); acpi_memory_ospm_status(&s->acpi_memory_hotplug, list); - if (!s->cpu_hotplug_legacy) { - acpi_cpu_ospm_status(&s->cpuhp_state, list); - } -} - -static void piix4_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) -{ - PIIX4PMState *s = PIIX4_PM(adev); - - acpi_send_gpe_event(&s->ar, s->irq, ev); } static Property piix4_pm_properties[] = { @@ -698,8 +623,6 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data) hc->unplug_request = piix4_device_unplug_request_cb; hc->unplug = piix4_device_unplug_cb; adevc->ospm_status = piix4_ospm_status; - adevc->send_event = piix4_send_gpe; - adevc->madt_cpu = pc_madt_cpu_entry; } static const TypeInfo piix4_pm_info = { diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events deleted file mode 100644 index c379607a3..000000000 --- a/hw/acpi/trace-events +++ /dev/null @@ -1,32 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/acpi/memory_hotplug.c -mhp_acpi_invalid_slot_selected(uint32_t slot) "0x%"PRIx32 -mhp_acpi_ejecting_invalid_slot(uint32_t slot) "0x%"PRIx32 -mhp_acpi_read_addr_lo(uint32_t slot, uint32_t addr) "slot[0x%"PRIx32"] addr lo: 0x%"PRIx32 -mhp_acpi_read_addr_hi(uint32_t slot, uint32_t addr) "slot[0x%"PRIx32"] addr hi: 0x%"PRIx32 -mhp_acpi_read_size_lo(uint32_t slot, uint32_t size) "slot[0x%"PRIx32"] size lo: 0x%"PRIx32 -mhp_acpi_read_size_hi(uint32_t slot, uint32_t size) "slot[0x%"PRIx32"] size hi: 0x%"PRIx32 -mhp_acpi_read_pxm(uint32_t slot, uint32_t pxm) "slot[0x%"PRIx32"] proximity: 0x%"PRIx32 -mhp_acpi_read_flags(uint32_t slot, uint32_t flags) "slot[0x%"PRIx32"] flags: 0x%"PRIx32 -mhp_acpi_write_slot(uint32_t slot) "set active slot: 0x%"PRIx32 -mhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "slot[0x%"PRIx32"] OST EVENT: 0x%"PRIx32 -mhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "slot[0x%"PRIx32"] OST STATUS: 0x%"PRIx32 -mhp_acpi_clear_insert_evt(uint32_t slot) "slot[0x%"PRIx32"] clear insert event" -mhp_acpi_clear_remove_evt(uint32_t slot) "slot[0x%"PRIx32"] clear remove event" -mhp_acpi_pc_dimm_deleted(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm deleted" -mhp_acpi_pc_dimm_delete_failed(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm delete failed" - -# hw/acpi/cpu.c -cpuhp_acpi_invalid_idx_selected(uint32_t idx) "0x%"PRIx32 -cpuhp_acpi_read_flags(uint32_t idx, uint8_t flags) "idx[0x%"PRIx32"] flags: 0x%"PRIx8 -cpuhp_acpi_write_idx(uint32_t idx) "set active cpu idx: 0x%"PRIx32 -cpuhp_acpi_write_cmd(uint32_t idx, uint8_t cmd) "idx[0x%"PRIx32"] cmd: 0x%"PRIx8 -cpuhp_acpi_read_cmd_data(uint32_t idx, uint32_t data) "idx[0x%"PRIx32"] data: 0x%"PRIx32 -cpuhp_acpi_cpu_has_events(uint32_t idx, bool ins, bool rm) "idx[0x%"PRIx32"] inserting: %d, removing: %d" -cpuhp_acpi_clear_inserting_evt(uint32_t idx) "idx[0x%"PRIx32"]" -cpuhp_acpi_clear_remove_evt(uint32_t idx) "idx[0x%"PRIx32"]" -cpuhp_acpi_ejecting_invalid_cpu(uint32_t idx) "0x%"PRIx32 -cpuhp_acpi_ejecting_cpu(uint32_t idx) "0x%"PRIx32 -cpuhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "idx[0x%"PRIx32"] OST EVENT: 0x%"PRIx32 -cpuhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "idx[0x%"PRIx32"] OST STATUS: 0x%"PRIx32 diff --git a/hw/alpha/alpha_sys.h b/hw/alpha/alpha_sys.h index ed911f22a..e11025b4b 100644 --- a/hw/alpha/alpha_sys.h +++ b/hw/alpha/alpha_sys.h @@ -1,9 +1,8 @@ /* Alpha cores and system support chips. */ -#ifndef HW_ALPHA_SYS_H -#define HW_ALPHA_SYS_H +#ifndef HW_ALPHA_H +#define HW_ALPHA_H 1 -#include "target-alpha/cpu-qom.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" #include "hw/ide.h" diff --git a/hw/alpha/pci.c b/hw/alpha/pci.c index 8dde637bf..5baa0eaf1 100644 --- a/hw/alpha/pci.c +++ b/hw/alpha/pci.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" +#include "cpu.h" #include "alpha_sys.h" #include "qemu/log.h" #include "sysemu/sysemu.h" diff --git a/hw/alpha/trace-events b/hw/alpha/trace-events deleted file mode 100644 index e44ff01a0..000000000 --- a/hw/alpha/trace-events +++ /dev/null @@ -1,4 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/alpha/pci.c -alpha_pci_iack_write(void) "" diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index 883db13f9..97721b535 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -824,6 +824,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, int i; dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE); + qdev_init_nofail(dev); s = TYPHOON_PCI_HOST_BRIDGE(dev); phb = PCI_HOST_BRIDGE(dev); @@ -888,7 +889,6 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, &s->pchip.reg_mem, &s->pchip.reg_io, 0, 64, TYPE_PCI_BUS); phb->bus = b; - qdev_init_nofail(dev); /* Host memory as seen from the PCI side, via the IOMMU. */ memory_region_init_iommu(&s->pchip.iommu, OBJECT(s), &typhoon_iommu_ops, diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 12764ef2b..954c9fe15 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -16,5 +16,4 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o -obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 49d30782c..bb2a22d96 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -132,14 +132,14 @@ typedef struct { uint32_t base; } BitBandState; -static void bitband_init(Object *obj) +static int bitband_init(SysBusDevice *dev) { - BitBandState *s = BITBAND(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + BitBandState *s = BITBAND(dev); - memory_region_init_io(&s->iomem, obj, &bitband_ops, &s->base, + memory_region_init_io(&s->iomem, OBJECT(s), &bitband_ops, &s->base, "bitband", 0x02000000); sysbus_init_mmio(dev, &s->iomem); + return 0; } static void armv7m_bitband_init(void) @@ -244,7 +244,9 @@ static Property bitband_properties[] = { static void bitband_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = bitband_init; dc->props = bitband_properties; } @@ -252,7 +254,6 @@ static const TypeInfo bitband_info = { .name = TYPE_BITBAND, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(BitBandState), - .instance_init = bitband_init, .class_init = bitband_class_init, }; diff --git a/hw/arm/ast2400.c b/hw/arm/ast2400.c index 326fdb36e..03f993863 100644 --- a/hw/arm/ast2400.c +++ b/hw/arm/ast2400.c @@ -17,22 +17,12 @@ #include "exec/address-spaces.h" #include "hw/arm/ast2400.h" #include "hw/char/serial.h" -#include "qemu/log.h" -#include "hw/i2c/aspeed_i2c.h" #define AST2400_UART_5_BASE 0x00184000 #define AST2400_IOMEM_SIZE 0x00200000 #define AST2400_IOMEM_BASE 0x1E600000 -#define AST2400_SMC_BASE AST2400_IOMEM_BASE /* Legacy SMC */ -#define AST2400_FMC_BASE 0X1E620000 -#define AST2400_SPI_BASE 0X1E630000 #define AST2400_VIC_BASE 0x1E6C0000 -#define AST2400_SCU_BASE 0x1E6E2000 #define AST2400_TIMER_BASE 0x1E782000 -#define AST2400_I2C_BASE 0x1E78A000 - -#define AST2400_FMC_FLASH_BASE 0x20000000 -#define AST2400_SPI_FLASH_BASE 0x30000000 static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; @@ -75,35 +65,13 @@ static void ast2400_init(Object *obj) object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER); object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL); qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default()); - - object_initialize(&s->i2c, sizeof(s->i2c), TYPE_ASPEED_I2C); - object_property_add_child(obj, "i2c", OBJECT(&s->i2c), NULL); - qdev_set_parent_bus(DEVICE(&s->i2c), sysbus_get_default()); - - object_initialize(&s->scu, sizeof(s->scu), TYPE_ASPEED_SCU); - object_property_add_child(obj, "scu", OBJECT(&s->scu), NULL); - qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default()); - qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", - AST2400_A0_SILICON_REV); - object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), - "hw-strap1", &error_abort); - object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), - "hw-strap2", &error_abort); - - object_initialize(&s->smc, sizeof(s->smc), "aspeed.smc.fmc"); - object_property_add_child(obj, "smc", OBJECT(&s->smc), NULL); - qdev_set_parent_bus(DEVICE(&s->smc), sysbus_get_default()); - - object_initialize(&s->spi, sizeof(s->spi), "aspeed.smc.spi"); - object_property_add_child(obj, "spi", OBJECT(&s->spi), NULL); - qdev_set_parent_bus(DEVICE(&s->spi), sysbus_get_default()); } static void ast2400_realize(DeviceState *dev, Error **errp) { int i; AST2400State *s = AST2400(dev); - Error *err = NULL, *local_err = NULL; + Error *err = NULL; /* IO space */ memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL, @@ -135,54 +103,12 @@ static void ast2400_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); } - /* SCU */ - object_property_set_bool(OBJECT(&s->scu), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, AST2400_SCU_BASE); - /* UART - attach an 8250 to the IO space as our UART5 */ if (serial_hds[0]) { qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]); serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2, uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN); } - - /* I2C */ - object_property_set_bool(OBJECT(&s->i2c), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, - qdev_get_gpio_in(DEVICE(&s->vic), 12)); - - /* SMC */ - object_property_set_int(OBJECT(&s->smc), 1, "num-cs", &err); - object_property_set_bool(OBJECT(&s->smc), true, "realized", &local_err); - error_propagate(&err, local_err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, AST2400_FMC_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, AST2400_FMC_FLASH_BASE); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->smc), 0, - qdev_get_gpio_in(DEVICE(&s->vic), 19)); - - /* SPI */ - object_property_set_int(OBJECT(&s->spi), 1, "num-cs", &err); - object_property_set_bool(OBJECT(&s->spi), true, "realized", &local_err); - error_propagate(&err, local_err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, AST2400_SPI_BASE); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, AST2400_SPI_FLASH_BASE); } static void ast2400_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index 2e641a398..234d51843 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -14,7 +14,6 @@ #include "hw/misc/bcm2835_mbox_defs.h" #include "hw/arm/raspi_platform.h" #include "sysemu/char.h" -#include "sysemu/sysemu.h" /* Peripheral base address on the VC (GPU) system bus */ #define BCM2835_VC_PERI_BASE 0x7e000000 @@ -107,6 +106,7 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) MemoryRegion *ram; Error *err = NULL; uint32_t ram_size, vcram_size; + CharDriverState *chr; int n; obj = object_property_get_link(OBJECT(dev), "ram", &err); @@ -147,7 +147,6 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic)); /* UART0 */ - qdev_prop_set_chr(DEVICE(s->uart0), "chardev", serial_hds[0]); object_property_set_bool(OBJECT(s->uart0), true, "realized", &err); if (err) { error_propagate(errp, err); @@ -159,8 +158,17 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(s->uart0, 0, qdev_get_gpio_in_named(DEVICE(&s->ic), BCM2835_IC_GPU_IRQ, INTERRUPT_UART)); + /* AUX / UART1 */ - qdev_prop_set_chr(DEVICE(&s->aux), "chardev", serial_hds[1]); + /* TODO: don't call qemu_char_get_next_serial() here, instead set + * chardev properties for each uart at the board level, once pl011 + * (uart0) has been updated to avoid qemu_char_get_next_serial() + */ + chr = qemu_char_get_next_serial(); + if (chr == NULL) { + chr = qemu_chr_new("bcm2835.uart1", "null", NULL); + } + qdev_prop_set_chr(DEVICE(&s->aux), "chardev", chr); object_property_set_bool(OBJECT(&s->aux), true, "realized", &err); if (err) { @@ -284,6 +292,8 @@ static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = bcm2835_peripherals_realize; + /* Reason: realize() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo bcm2835_peripherals_type_info = { diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 1b913a43c..587694557 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -14,7 +14,6 @@ #include "hw/arm/linux-boot-if.h" #include "sysemu/kvm.h" #include "sysemu/sysemu.h" -#include "sysemu/numa.h" #include "hw/boards.h" #include "hw/loader.h" #include "elf.h" @@ -406,9 +405,6 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, void *fdt = NULL; int size, rc; uint32_t acells, scells; - char *nodename; - unsigned int i; - hwaddr mem_base, mem_len; if (binfo->dtb_filename) { char *filename; @@ -460,39 +456,12 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, goto fail; } - if (nb_numa_nodes > 0) { - /* - * Turn the /memory node created before into a NOP node, then create - * /memory@addr nodes for all numa nodes respectively. - */ - qemu_fdt_nop_node(fdt, "/memory"); - mem_base = binfo->loader_start; - for (i = 0; i < nb_numa_nodes; i++) { - mem_len = numa_info[i].node_mem; - nodename = g_strdup_printf("/memory@%" PRIx64, mem_base); - qemu_fdt_add_subnode(fdt, nodename); - qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory"); - rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", - acells, mem_base, - scells, mem_len); - if (rc < 0) { - fprintf(stderr, "couldn't set %s/reg for node %d\n", nodename, - i); - goto fail; - } - - qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id", i); - mem_base += mem_len; - g_free(nodename); - } - } else { - rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg", - acells, binfo->loader_start, - scells, binfo->ram_size); - if (rc < 0) { - fprintf(stderr, "couldn't set /memory/reg\n"); - goto fail; - } + rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg", + acells, binfo->loader_start, + scells, binfo->ram_size); + if (rc < 0) { + fprintf(stderr, "couldn't set /memory/reg\n"); + goto fail; } if (binfo->kernel_cmdline && *binfo->kernel_cmdline) { diff --git a/hw/arm/collie.c b/hw/arm/collie.c index 2e6953128..8bb308a42 100644 --- a/hw/arm/collie.c +++ b/hw/arm/collie.c @@ -18,7 +18,6 @@ #include "hw/block/flash.h" #include "sysemu/block-backend.h" #include "exec/address-spaces.h" -#include "qom/cpu.h" static struct arm_boot_info collie_binfo = { .loader_start = SA_SDCS0, diff --git a/hw/arm/digic.c b/hw/arm/digic.c index d60ea395f..e0f973032 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/arm/digic.h" -#include "sysemu/sysemu.h" #define DIGIC4_TIMER_BASE(n) (0xc0210000 + (n) * 0x100) @@ -85,7 +84,6 @@ static void digic_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(sbd, 0, DIGIC4_TIMER_BASE(i)); } - qdev_prop_set_chr(DEVICE(&s->uart), "chardev", serial_hds[0]); object_property_set_bool(OBJECT(&s->uart), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index b4e358db6..2f878b935 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -51,7 +51,7 @@ static void fsl_imx25_init(Object *obj) } for (i = 0; i < FSL_IMX25_NUM_GPTS; i++) { - object_initialize(&s->gpt[i], sizeof(s->gpt[i]), TYPE_IMX25_GPT); + object_initialize(&s->gpt[i], sizeof(s->gpt[i]), TYPE_IMX_GPT); qdev_set_parent_bus(DEVICE(&s->gpt[i]), sysbus_get_default()); } @@ -191,7 +191,6 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) } qdev_set_nic_properties(DEVICE(&s->fec), &nd_table[0]); - object_property_set_bool(OBJECT(&s->fec), true, "realized", &err); if (err) { error_propagate(errp, err); @@ -249,16 +248,16 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp) } /* initialize 2 x 16 KB ROM */ - memory_region_init_rom(&s->rom[0], NULL, - "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err); + memory_region_init_rom_device(&s->rom[0], NULL, NULL, NULL, + "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err); if (err) { error_propagate(errp, err); return; } memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR, &s->rom[0]); - memory_region_init_rom(&s->rom[1], NULL, - "imx25.rom1", FSL_IMX25_ROM1_SIZE, &err); + memory_region_init_rom_device(&s->rom[1], NULL, NULL, NULL, + "imx25.rom1", FSL_IMX25_ROM1_SIZE, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index fe204ace6..31a3a8791 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -47,7 +47,7 @@ static void fsl_imx31_init(Object *obj) qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default()); } - object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX31_GPT); + object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX_GPT); qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default()); for (i = 0; i < FSL_IMX31_NUM_EPITS; i++) { @@ -219,8 +219,9 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) } /* On a real system, the first 16k is a `secure boot rom' */ - memory_region_init_rom(&s->secure_rom, NULL, "imx31.secure_rom", - FSL_IMX31_SECURE_ROM_SIZE, &err); + memory_region_init_rom_device(&s->secure_rom, NULL, NULL, NULL, + "imx31.secure_rom", + FSL_IMX31_SECURE_ROM_SIZE, &err); if (err) { error_propagate(errp, err); return; @@ -229,8 +230,8 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) &s->secure_rom); /* There is also a 16k ROM */ - memory_region_init_rom(&s->rom, NULL, "imx31.rom", - FSL_IMX31_ROM_SIZE, &err); + memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx31.rom", + FSL_IMX31_ROM_SIZE, &err); if (err) { error_propagate(errp, err); return; diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c deleted file mode 100644 index 6a1bf263a..000000000 --- a/hw/arm/fsl-imx6.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net> - * - * i.MX6 SOC emulation. - * - * Based on hw/arm/fsl-imx31.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "hw/arm/fsl-imx6.h" -#include "sysemu/sysemu.h" -#include "sysemu/char.h" -#include "qemu/error-report.h" - -#define NAME_SIZE 20 - -static void fsl_imx6_init(Object *obj) -{ - FslIMX6State *s = FSL_IMX6(obj); - char name[NAME_SIZE]; - int i; - - if (smp_cpus > FSL_IMX6_NUM_CPUS) { - error_report("%s: Only %d CPUs are supported (%d requested)", - TYPE_FSL_IMX6, FSL_IMX6_NUM_CPUS, smp_cpus); - exit(1); - } - - for (i = 0; i < smp_cpus; i++) { - object_initialize(&s->cpu[i], sizeof(s->cpu[i]), - "cortex-a9-" TYPE_ARM_CPU); - snprintf(name, NAME_SIZE, "cpu%d", i); - object_property_add_child(obj, name, OBJECT(&s->cpu[i]), NULL); - } - - object_initialize(&s->a9mpcore, sizeof(s->a9mpcore), TYPE_A9MPCORE_PRIV); - qdev_set_parent_bus(DEVICE(&s->a9mpcore), sysbus_get_default()); - object_property_add_child(obj, "a9mpcore", OBJECT(&s->a9mpcore), NULL); - - object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX6_CCM); - qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default()); - object_property_add_child(obj, "ccm", OBJECT(&s->ccm), NULL); - - object_initialize(&s->src, sizeof(s->src), TYPE_IMX6_SRC); - qdev_set_parent_bus(DEVICE(&s->src), sysbus_get_default()); - object_property_add_child(obj, "src", OBJECT(&s->src), NULL); - - for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) { - object_initialize(&s->uart[i], sizeof(s->uart[i]), TYPE_IMX_SERIAL); - qdev_set_parent_bus(DEVICE(&s->uart[i]), sysbus_get_default()); - snprintf(name, NAME_SIZE, "uart%d", i + 1); - object_property_add_child(obj, name, OBJECT(&s->uart[i]), NULL); - } - - object_initialize(&s->gpt, sizeof(s->gpt), TYPE_IMX6_GPT); - qdev_set_parent_bus(DEVICE(&s->gpt), sysbus_get_default()); - object_property_add_child(obj, "gpt", OBJECT(&s->gpt), NULL); - - for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) { - object_initialize(&s->epit[i], sizeof(s->epit[i]), TYPE_IMX_EPIT); - qdev_set_parent_bus(DEVICE(&s->epit[i]), sysbus_get_default()); - snprintf(name, NAME_SIZE, "epit%d", i + 1); - object_property_add_child(obj, name, OBJECT(&s->epit[i]), NULL); - } - - for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) { - object_initialize(&s->i2c[i], sizeof(s->i2c[i]), TYPE_IMX_I2C); - qdev_set_parent_bus(DEVICE(&s->i2c[i]), sysbus_get_default()); - snprintf(name, NAME_SIZE, "i2c%d", i + 1); - object_property_add_child(obj, name, OBJECT(&s->i2c[i]), NULL); - } - - for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) { - object_initialize(&s->gpio[i], sizeof(s->gpio[i]), TYPE_IMX_GPIO); - qdev_set_parent_bus(DEVICE(&s->gpio[i]), sysbus_get_default()); - snprintf(name, NAME_SIZE, "gpio%d", i + 1); - object_property_add_child(obj, name, OBJECT(&s->gpio[i]), NULL); - } - - for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) { - object_initialize(&s->esdhc[i], sizeof(s->esdhc[i]), TYPE_SYSBUS_SDHCI); - qdev_set_parent_bus(DEVICE(&s->esdhc[i]), sysbus_get_default()); - snprintf(name, NAME_SIZE, "sdhc%d", i + 1); - object_property_add_child(obj, name, OBJECT(&s->esdhc[i]), NULL); - } - - for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) { - object_initialize(&s->spi[i], sizeof(s->spi[i]), TYPE_IMX_SPI); - qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); - snprintf(name, NAME_SIZE, "spi%d", i + 1); - object_property_add_child(obj, name, OBJECT(&s->spi[i]), NULL); - } - - object_initialize(&s->eth, sizeof(s->eth), TYPE_IMX_ENET); - qdev_set_parent_bus(DEVICE(&s->eth), sysbus_get_default()); - object_property_add_child(obj, "eth", OBJECT(&s->eth), NULL); -} - -static void fsl_imx6_realize(DeviceState *dev, Error **errp) -{ - FslIMX6State *s = FSL_IMX6(dev); - uint16_t i; - Error *err = NULL; - - for (i = 0; i < smp_cpus; i++) { - - /* On uniprocessor, the CBAR is set to 0 */ - if (smp_cpus > 1) { - object_property_set_int(OBJECT(&s->cpu[i]), FSL_IMX6_A9MPCORE_ADDR, - "reset-cbar", &error_abort); - } - - /* All CPU but CPU 0 start in power off mode */ - if (i) { - object_property_set_bool(OBJECT(&s->cpu[i]), true, - "start-powered-off", &error_abort); - } - - object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - } - - object_property_set_int(OBJECT(&s->a9mpcore), smp_cpus, "num-cpu", - &error_abort); - - object_property_set_int(OBJECT(&s->a9mpcore), - FSL_IMX6_MAX_IRQ + GIC_INTERNAL, "num-irq", - &error_abort); - - object_property_set_bool(OBJECT(&s->a9mpcore), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->a9mpcore), 0, FSL_IMX6_A9MPCORE_ADDR); - - for (i = 0; i < smp_cpus; i++) { - sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i, - qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_IRQ)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->a9mpcore), i + smp_cpus, - qdev_get_gpio_in(DEVICE(&s->cpu[i]), ARM_CPU_FIQ)); - } - - object_property_set_bool(OBJECT(&s->ccm), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0, FSL_IMX6_CCM_ADDR); - - object_property_set_bool(OBJECT(&s->src), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->src), 0, FSL_IMX6_SRC_ADDR); - - /* Initialize all UARTs */ - for (i = 0; i < FSL_IMX6_NUM_UARTS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } serial_table[FSL_IMX6_NUM_UARTS] = { - { FSL_IMX6_UART1_ADDR, FSL_IMX6_UART1_IRQ }, - { FSL_IMX6_UART2_ADDR, FSL_IMX6_UART2_IRQ }, - { FSL_IMX6_UART3_ADDR, FSL_IMX6_UART3_IRQ }, - { FSL_IMX6_UART4_ADDR, FSL_IMX6_UART4_IRQ }, - { FSL_IMX6_UART5_ADDR, FSL_IMX6_UART5_IRQ }, - }; - - if (i < MAX_SERIAL_PORTS) { - CharDriverState *chr; - - chr = serial_hds[i]; - - if (!chr) { - char *label = g_strdup_printf("imx6.uart%d", i + 1); - chr = qemu_chr_new(label, "null", NULL); - g_free(label); - serial_hds[i] = chr; - } - - qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr); - } - - object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, - qdev_get_gpio_in(DEVICE(&s->a9mpcore), - serial_table[i].irq)); - } - - s->gpt.ccm = IMX_CCM(&s->ccm); - - object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt), 0, FSL_IMX6_GPT_ADDR); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt), 0, - qdev_get_gpio_in(DEVICE(&s->a9mpcore), - FSL_IMX6_GPT_IRQ)); - - /* Initialize all EPIT timers */ - for (i = 0; i < FSL_IMX6_NUM_EPITS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } epit_table[FSL_IMX6_NUM_EPITS] = { - { FSL_IMX6_EPIT1_ADDR, FSL_IMX6_EPIT1_IRQ }, - { FSL_IMX6_EPIT2_ADDR, FSL_IMX6_EPIT2_IRQ }, - }; - - s->epit[i].ccm = IMX_CCM(&s->ccm); - - object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->epit[i]), 0, epit_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->epit[i]), 0, - qdev_get_gpio_in(DEVICE(&s->a9mpcore), - epit_table[i].irq)); - } - - /* Initialize all I2C */ - for (i = 0; i < FSL_IMX6_NUM_I2CS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } i2c_table[FSL_IMX6_NUM_I2CS] = { - { FSL_IMX6_I2C1_ADDR, FSL_IMX6_I2C1_IRQ }, - { FSL_IMX6_I2C2_ADDR, FSL_IMX6_I2C2_IRQ }, - { FSL_IMX6_I2C3_ADDR, FSL_IMX6_I2C3_IRQ } - }; - - object_property_set_bool(OBJECT(&s->i2c[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0, - qdev_get_gpio_in(DEVICE(&s->a9mpcore), - i2c_table[i].irq)); - } - - /* Initialize all GPIOs */ - for (i = 0; i < FSL_IMX6_NUM_GPIOS; i++) { - static const struct { - hwaddr addr; - unsigned int irq_low; - unsigned int irq_high; - } gpio_table[FSL_IMX6_NUM_GPIOS] = { - { - FSL_IMX6_GPIO1_ADDR, - FSL_IMX6_GPIO1_LOW_IRQ, - FSL_IMX6_GPIO1_HIGH_IRQ - }, - { - FSL_IMX6_GPIO2_ADDR, - FSL_IMX6_GPIO2_LOW_IRQ, - FSL_IMX6_GPIO2_HIGH_IRQ - }, - { - FSL_IMX6_GPIO3_ADDR, - FSL_IMX6_GPIO3_LOW_IRQ, - FSL_IMX6_GPIO3_HIGH_IRQ - }, - { - FSL_IMX6_GPIO4_ADDR, - FSL_IMX6_GPIO4_LOW_IRQ, - FSL_IMX6_GPIO4_HIGH_IRQ - }, - { - FSL_IMX6_GPIO5_ADDR, - FSL_IMX6_GPIO5_LOW_IRQ, - FSL_IMX6_GPIO5_HIGH_IRQ - }, - { - FSL_IMX6_GPIO6_ADDR, - FSL_IMX6_GPIO6_LOW_IRQ, - FSL_IMX6_GPIO6_HIGH_IRQ - }, - { - FSL_IMX6_GPIO7_ADDR, - FSL_IMX6_GPIO7_LOW_IRQ, - FSL_IMX6_GPIO7_HIGH_IRQ - }, - }; - - object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-edge-sel", - &error_abort); - object_property_set_bool(OBJECT(&s->gpio[i]), true, "has-upper-pin-irq", - &error_abort); - object_property_set_bool(OBJECT(&s->gpio[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0, - qdev_get_gpio_in(DEVICE(&s->a9mpcore), - gpio_table[i].irq_low)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1, - qdev_get_gpio_in(DEVICE(&s->a9mpcore), - gpio_table[i].irq_high)); - } - - /* Initialize all SDHC */ - for (i = 0; i < FSL_IMX6_NUM_ESDHCS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } esdhc_table[FSL_IMX6_NUM_ESDHCS] = { - { FSL_IMX6_uSDHC1_ADDR, FSL_IMX6_uSDHC1_IRQ }, - { FSL_IMX6_uSDHC2_ADDR, FSL_IMX6_uSDHC2_IRQ }, - { FSL_IMX6_uSDHC3_ADDR, FSL_IMX6_uSDHC3_IRQ }, - { FSL_IMX6_uSDHC4_ADDR, FSL_IMX6_uSDHC4_IRQ }, - }; - - object_property_set_bool(OBJECT(&s->esdhc[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->esdhc[i]), 0, esdhc_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->esdhc[i]), 0, - qdev_get_gpio_in(DEVICE(&s->a9mpcore), - esdhc_table[i].irq)); - } - - /* Initialize all ECSPI */ - for (i = 0; i < FSL_IMX6_NUM_ECSPIS; i++) { - static const struct { - hwaddr addr; - unsigned int irq; - } spi_table[FSL_IMX6_NUM_ECSPIS] = { - { FSL_IMX6_eCSPI1_ADDR, FSL_IMX6_ECSPI1_IRQ }, - { FSL_IMX6_eCSPI2_ADDR, FSL_IMX6_ECSPI2_IRQ }, - { FSL_IMX6_eCSPI3_ADDR, FSL_IMX6_ECSPI3_IRQ }, - { FSL_IMX6_eCSPI4_ADDR, FSL_IMX6_ECSPI4_IRQ }, - { FSL_IMX6_eCSPI5_ADDR, FSL_IMX6_ECSPI5_IRQ }, - }; - - /* Initialize the SPI */ - object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0, - qdev_get_gpio_in(DEVICE(&s->a9mpcore), - spi_table[i].irq)); - } - - object_property_set_bool(OBJECT(&s->eth), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->eth), 0, FSL_IMX6_ENET_ADDR); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth), 0, - qdev_get_gpio_in(DEVICE(&s->a9mpcore), - FSL_IMX6_ENET_MAC_IRQ)); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->eth), 1, - qdev_get_gpio_in(DEVICE(&s->a9mpcore), - FSL_IMX6_ENET_MAC_1588_IRQ)); - - /* ROM memory */ - memory_region_init_rom(&s->rom, NULL, "imx6.rom", - FSL_IMX6_ROM_SIZE, &err); - if (err) { - error_propagate(errp, err); - return; - } - memory_region_add_subregion(get_system_memory(), FSL_IMX6_ROM_ADDR, - &s->rom); - - /* CAAM memory */ - memory_region_init_rom(&s->caam, NULL, "imx6.caam", - FSL_IMX6_CAAM_MEM_SIZE, &err); - if (err) { - error_propagate(errp, err); - return; - } - memory_region_add_subregion(get_system_memory(), FSL_IMX6_CAAM_MEM_ADDR, - &s->caam); - - /* OCRAM memory */ - memory_region_init_ram(&s->ocram, NULL, "imx6.ocram", FSL_IMX6_OCRAM_SIZE, - &err); - if (err) { - error_propagate(errp, err); - return; - } - memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ADDR, - &s->ocram); - vmstate_register_ram_global(&s->ocram); - - /* internal OCRAM (256 KB) is aliased over 1 MB */ - memory_region_init_alias(&s->ocram_alias, NULL, "imx6.ocram_alias", - &s->ocram, 0, FSL_IMX6_OCRAM_ALIAS_SIZE); - memory_region_add_subregion(get_system_memory(), FSL_IMX6_OCRAM_ALIAS_ADDR, - &s->ocram_alias); -} - -static void fsl_imx6_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = fsl_imx6_realize; - - /* - * Reason: creates an ARM CPU, thus use after free(), see - * arm_cpu_class_init() - */ - dc->cannot_destroy_with_object_finalize_yet = true; - dc->desc = "i.MX6 SOC"; -} - -static const TypeInfo fsl_imx6_type_info = { - .name = TYPE_FSL_IMX6, - .parent = TYPE_DEVICE, - .instance_size = sizeof(FslIMX6State), - .instance_init = fsl_imx6_init, - .class_init = fsl_imx6_class_init, -}; - -static void fsl_imx6_register_types(void) -{ - type_register_static(&fsl_imx6_type_info); -} - -type_init(fsl_imx6_register_types) diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 80e5fd458..d9930c0d3 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -30,7 +30,6 @@ #include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "qemu/error-report.h" -#include "hw/char/pl011.h" #define SMP_BOOT_ADDR 0x100 #define SMP_BOOT_REG 0x40 @@ -169,20 +168,23 @@ static void highbank_regs_reset(DeviceState *dev) s->regs[0x43] = 0x05F40121; } -static void highbank_regs_init(Object *obj) +static int highbank_regs_init(SysBusDevice *dev) { - HighbankRegsState *s = HIGHBANK_REGISTERS(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + HighbankRegsState *s = HIGHBANK_REGISTERS(dev); - memory_region_init_io(&s->iomem, obj, &hb_mem_ops, s->regs, + memory_region_init_io(&s->iomem, OBJECT(s), &hb_mem_ops, s->regs, "highbank_regs", 0x1000); sysbus_init_mmio(dev, &s->iomem); + + return 0; } static void highbank_regs_class_init(ObjectClass *klass, void *data) { + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); + sbc->init = highbank_regs_init; dc->desc = "Calxeda Highbank registers"; dc->vmsd = &vmstate_highbank_regs; dc->reset = highbank_regs_reset; @@ -192,7 +194,6 @@ static const TypeInfo highbank_regs_info = { .name = TYPE_HIGHBANK_REGISTERS, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(HighbankRegsState), - .instance_init = highbank_regs_init, .class_init = highbank_regs_class_init, }; @@ -327,7 +328,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff34000); sysbus_connect_irq(busdev, 0, pic[18]); - pl011_create(0xfff36000, pic[20], serial_hds[0]); + sysbus_create_simple("pl011", 0xfff36000, pic[20]); dev = qdev_create(NULL, "highbank-regs"); qdev_init_nofail(dev); diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 96dc15002..e31bca6e7 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -20,7 +20,6 @@ #include "exec/address-spaces.h" #include "sysemu/sysemu.h" #include "qemu/error-report.h" -#include "hw/char/pl011.h" #define TYPE_INTEGRATOR_CM "integrator_core" #define INTEGRATOR_CM(obj) \ @@ -243,10 +242,9 @@ static const MemoryRegionOps integratorcm_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void integratorcm_init(Object *obj) +static int integratorcm_init(SysBusDevice *dev) { - IntegratorCMState *s = INTEGRATOR_CM(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + IntegratorCMState *s = INTEGRATOR_CM(dev); s->cm_osc = 0x01000048; /* ??? What should the high bits of this value be? */ @@ -271,16 +269,17 @@ static void integratorcm_init(Object *obj) s->cm_init = 0x00000112; s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24, 1000); - memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000, + memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000, &error_fatal); vmstate_register_ram_global(&s->flash); - memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s, "integratorcm", 0x00800000); sysbus_init_mmio(dev, &s->iomem); integratorcm_do_remap(s); /* ??? Save/restore. */ + return 0; } /* Integrator/CP hardware emulation. */ @@ -395,18 +394,18 @@ static const MemoryRegionOps icp_pic_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void icp_pic_init(Object *obj) +static int icp_pic_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - icp_pic_state *s = INTEGRATOR_PIC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + icp_pic_state *s = INTEGRATOR_PIC(dev); qdev_init_gpio_in(dev, icp_pic_set_irq, 32); sysbus_init_irq(sbd, &s->parent_irq); sysbus_init_irq(sbd, &s->parent_fiq); - memory_region_init_io(&s->iomem, obj, &icp_pic_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s, "icp-pic", 0x00800000); sysbus_init_mmio(sbd, &s->iomem); + return 0; } /* CP control registers. */ @@ -589,8 +588,8 @@ static void integratorcp_init(MachineState *machine) sysbus_create_varargs("integrator_pit", 0x13000000, pic[5], pic[6], pic[7], NULL); sysbus_create_simple("pl031", 0x15000000, pic[8]); - pl011_create(0x16000000, pic[1], serial_hds[0]); - pl011_create(0x17000000, pic[2], serial_hds[1]); + sysbus_create_simple("pl011", 0x16000000, pic[1]); + sysbus_create_simple("pl011", 0x17000000, pic[2]); icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000, qdev_get_gpio_in(sic, 3)); sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]); @@ -631,7 +630,9 @@ static Property core_properties[] = { static void core_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = integratorcm_init; dc->props = core_properties; } @@ -639,15 +640,21 @@ static const TypeInfo core_info = { .name = TYPE_INTEGRATOR_CM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IntegratorCMState), - .instance_init = integratorcm_init, .class_init = core_class_init, }; +static void icp_pic_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = icp_pic_init; +} + static const TypeInfo icp_pic_info = { .name = TYPE_INTEGRATOR_PIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(icp_pic_state), - .instance_init = icp_pic_init, + .class_init = icp_pic_class_init, }; static const TypeInfo icp_ctrl_regs_info = { diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index cc50ace13..7a4cc07dd 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -378,7 +378,7 @@ static void eth_cleanup(NetClientState *nc) } static NetClientInfo net_mv88w8618_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = eth_receive, .cleanup = eth_cleanup, diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index fea911e3e..538250555 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -20,9 +20,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "qemu/cutils.h" -#include "qemu/bswap.h" #include "sysemu/sysemu.h" #include "hw/arm/omap.h" #include "hw/arm/arm.h" @@ -37,7 +35,6 @@ #include "hw/loader.h" #include "sysemu/block-backend.h" #include "hw/sysbus.h" -#include "qemu/log.h" #include "exec/address-spaces.h" /* Nokia N8x0 support */ @@ -1351,7 +1348,7 @@ static void n8x0_init(MachineState *machine, n8x0_dss_setup(s); n8x0_cbus_setup(s); n8x0_uart_setup(s); - if (machine_usb(machine)) { + if (usb_enabled()) { n8x0_usb_setup(s); } @@ -1367,7 +1364,7 @@ static void n8x0_init(MachineState *machine, if (option_rom[0].name && (machine->boot_order[0] == 'n' || !machine->kernel_filename)) { - uint8_t *nolo_tags = g_new(uint8_t, 0x10000); + uint8_t nolo_tags[0x10000]; /* No, wait, better start at the ROM. */ s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000; @@ -1386,7 +1383,6 @@ static void n8x0_init(MachineState *machine, n800_setup_nolo_tags(nolo_tags); cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000); - g_free(nolo_tags); } } diff --git a/hw/arm/palmetto-bmc.c b/hw/arm/palmetto-bmc.c index 54e29a865..89ebd92b9 100644 --- a/hw/arm/palmetto-bmc.c +++ b/hw/arm/palmetto-bmc.c @@ -17,9 +17,6 @@ #include "hw/arm/arm.h" #include "hw/arm/ast2400.h" #include "hw/boards.h" -#include "qemu/log.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" static struct arm_boot_info palmetto_bmc_binfo = { .loader_start = AST2400_SDRAM_BASE, @@ -32,32 +29,6 @@ typedef struct PalmettoBMCState { MemoryRegion ram; } PalmettoBMCState; -static void palmetto_bmc_init_flashes(AspeedSMCState *s, const char *flashtype, - Error **errp) -{ - int i ; - - for (i = 0; i < s->num_cs; ++i) { - AspeedSMCFlash *fl = &s->flashes[i]; - DriveInfo *dinfo = drive_get_next(IF_MTD); - qemu_irq cs_line; - - /* - * FIXME: check that we are not using a flash module exceeding - * the controller segment size - */ - fl->flash = ssi_create_slave_no_init(s->spi, flashtype); - if (dinfo) { - qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo), - errp); - } - qdev_init_nofail(fl->flash); - - cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0); - sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line); - } -} - static void palmetto_bmc_init(MachineState *machine) { PalmettoBMCState *bmc; @@ -72,14 +43,9 @@ static void palmetto_bmc_init(MachineState *machine) &bmc->ram); object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram), &error_abort); - object_property_set_int(OBJECT(&bmc->soc), 0x120CE416, "hw-strap1", - &error_abort); object_property_set_bool(OBJECT(&bmc->soc), true, "realized", &error_abort); - palmetto_bmc_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort); - palmetto_bmc_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort); - palmetto_bmc_binfo.kernel_filename = machine->kernel_filename; palmetto_bmc_binfo.initrd_filename = machine->initrd_filename; palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline; diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index cb5570468..1a8c36033 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1107,10 +1107,9 @@ static const MemoryRegionOps pxa2xx_rtc_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void pxa2xx_rtc_init(Object *obj) +static int pxa2xx_rtc_init(SysBusDevice *dev) { - PXA2xxRTCState *s = PXA2XX_RTC(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + PXA2xxRTCState *s = PXA2XX_RTC(dev); struct tm tm; int wom; @@ -1139,9 +1138,11 @@ static void pxa2xx_rtc_init(Object *obj) sysbus_init_irq(dev, &s->rtc_irq); - memory_region_init_io(&s->iomem, obj, &pxa2xx_rtc_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_rtc_ops, s, "pxa2xx-rtc", 0x10000); sysbus_init_mmio(dev, &s->iomem); + + return 0; } static void pxa2xx_rtc_pre_save(void *opaque) @@ -1194,7 +1195,9 @@ static const VMStateDescription vmstate_pxa2xx_rtc_regs = { static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = pxa2xx_rtc_init; dc->desc = "PXA2xx RTC Controller"; dc->vmsd = &vmstate_pxa2xx_rtc_regs; } @@ -1203,7 +1206,6 @@ static const TypeInfo pxa2xx_rtc_sysbus_info = { .name = TYPE_PXA2XX_RTC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxRTCState), - .instance_init = pxa2xx_rtc_init, .class_init = pxa2xx_rtc_sysbus_class_init, }; @@ -1499,18 +1501,19 @@ PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base, return s; } -static void pxa2xx_i2c_initfn(Object *obj) +static int pxa2xx_i2c_initfn(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - PXA2xxI2CState *s = PXA2XX_I2C(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + PXA2xxI2CState *s = PXA2XX_I2C(dev); s->bus = i2c_init_bus(dev, "i2c"); - memory_region_init_io(&s->iomem, obj, &pxa2xx_i2c_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_i2c_ops, s, "pxa2xx-i2c", s->region_size); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); + + return 0; } I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s) @@ -1527,7 +1530,9 @@ static Property pxa2xx_i2c_properties[] = { static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = pxa2xx_i2c_initfn; dc->desc = "PXA2xx I2C Bus Controller"; dc->vmsd = &vmstate_pxa2xx_i2c; dc->props = pxa2xx_i2c_properties; @@ -1537,7 +1542,6 @@ static const TypeInfo pxa2xx_i2c_info = { .name = TYPE_PXA2XX_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxI2CState), - .instance_init = pxa2xx_i2c_initfn, .class_init = pxa2xx_i2c_class_init, }; @@ -2165,8 +2169,10 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space, s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); } - sysbus_create_simple("sysbus-ohci", 0x4c000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); + if (usb_enabled()) { + sysbus_create_simple("sysbus-ohci", 0x4c000000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); + } s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000); s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000); @@ -2296,8 +2302,10 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi"); } - sysbus_create_simple("sysbus-ohci", 0x4c000000, - qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); + if (usb_enabled()) { + sysbus_create_simple("sysbus-ohci", 0x4c000000, + qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1)); + } s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000); s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000); diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c index 576a8eb91..67e7e7094 100644 --- a/hw/arm/pxa2xx_gpio.c +++ b/hw/arm/pxa2xx_gpio.c @@ -8,11 +8,9 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "hw/hw.h" #include "hw/sysbus.h" #include "hw/arm/pxa.h" -#include "qemu/log.h" #define PXA2XX_GPIO_BANKS 4 diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index b516ced8c..7e51532cd 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -310,10 +310,17 @@ static VMStateDescription vmstate_pxa2xx_pic_regs = { }, }; +static int pxa2xx_pic_initfn(SysBusDevice *dev) +{ + return 0; +} + static void pxa2xx_pic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = pxa2xx_pic_initfn; dc->desc = "PXA2xx PIC"; dc->vmsd = &vmstate_pxa2xx_pic_regs; } diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 8eafccaf1..3222b360e 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -23,7 +23,6 @@ #include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "qemu/error-report.h" -#include "hw/char/pl011.h" #define SMP_BOOT_ADDR 0xe0000000 #define SMP_BOOTREG_ADDR 0x10000030 @@ -203,10 +202,10 @@ static void realview_init(MachineState *machine, sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]); sysbus_create_simple("pl050_mouse", 0x10007000, pic[21]); - pl011_create(0x10009000, pic[12], serial_hds[0]); - pl011_create(0x1000a000, pic[13], serial_hds[1]); - pl011_create(0x1000b000, pic[14], serial_hds[2]); - pl011_create(0x1000c000, pic[15], serial_hds[3]); + sysbus_create_simple("pl011", 0x10009000, pic[12]); + sysbus_create_simple("pl011", 0x1000a000, pic[13]); + sysbus_create_simple("pl011", 0x1000b000, pic[14]); + sysbus_create_simple("pl011", 0x1000c000, pic[15]); /* DMA controller is optional, apparently. */ sysbus_create_simple("pl081", 0x10030000, pic[24]); @@ -254,7 +253,7 @@ static void realview_init(MachineState *machine, sysbus_connect_irq(busdev, 2, pic[50]); sysbus_connect_irq(busdev, 3, pic[51]); pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); - if (machine_usb(machine)) { + if (usb_enabled()) { pci_create_simple(pci_bus, -1, "pci-ohci"); } n = drive_get_max_bus(IF_SCSI); diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c deleted file mode 100644 index 4e7ac8cc4..000000000 --- a/hw/arm/sabrelite.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * SABRELITE Board System emulation. - * - * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net> - * - * This code is licensed under the GPL, version 2 or later. - * See the file `COPYING' in the top level directory. - * - * It (partially) emulates a sabrelite board, with a Freescale - * i.MX6 SoC - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "hw/arm/fsl-imx6.h" -#include "hw/boards.h" -#include "sysemu/sysemu.h" -#include "qemu/error-report.h" -#include "sysemu/qtest.h" - -typedef struct IMX6Sabrelite { - FslIMX6State soc; - MemoryRegion ram; -} IMX6Sabrelite; - -static struct arm_boot_info sabrelite_binfo = { - /* DDR memory start */ - .loader_start = FSL_IMX6_MMDC_ADDR, - /* No board ID, we boot from DT tree */ - .board_id = -1, -}; - -/* No need to do any particular setup for secondary boot */ -static void sabrelite_write_secondary(ARMCPU *cpu, - const struct arm_boot_info *info) -{ -} - -/* Secondary cores are reset through SRC device */ -static void sabrelite_reset_secondary(ARMCPU *cpu, - const struct arm_boot_info *info) -{ -} - -static void sabrelite_init(MachineState *machine) -{ - IMX6Sabrelite *s = g_new0(IMX6Sabrelite, 1); - Error *err = NULL; - - /* Check the amount of memory is compatible with the SOC */ - if (machine->ram_size > FSL_IMX6_MMDC_SIZE) { - error_report("RAM size " RAM_ADDR_FMT " above max supported (%08x)", - machine->ram_size, FSL_IMX6_MMDC_SIZE); - exit(1); - } - - object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX6); - object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), - &error_abort); - - object_property_set_bool(OBJECT(&s->soc), true, "realized", &err); - if (err != NULL) { - error_report("%s", error_get_pretty(err)); - exit(1); - } - - memory_region_allocate_system_memory(&s->ram, NULL, "sabrelite.ram", - machine->ram_size); - memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR, - &s->ram); - - { - /* - * TODO: Ideally we would expose the chip select and spi bus on the - * SoC object using alias properties; then we would not need to - * directly access the underlying spi device object. - */ - /* Add the sst25vf016b NOR FLASH memory to first SPI */ - Object *spi_dev; - - spi_dev = object_resolve_path_component(OBJECT(&s->soc), "spi1"); - if (spi_dev) { - SSIBus *spi_bus; - - spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi"); - if (spi_bus) { - DeviceState *flash_dev; - qemu_irq cs_line; - DriveInfo *dinfo = drive_get_next(IF_MTD); - - flash_dev = ssi_create_slave_no_init(spi_bus, "sst25vf016b"); - if (dinfo) { - qdev_prop_set_drive(flash_dev, "drive", - blk_by_legacy_dinfo(dinfo), - &error_fatal); - } - qdev_init_nofail(flash_dev); - - cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); - sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line); - } - } - } - - sabrelite_binfo.ram_size = machine->ram_size; - sabrelite_binfo.kernel_filename = machine->kernel_filename; - sabrelite_binfo.kernel_cmdline = machine->kernel_cmdline; - sabrelite_binfo.initrd_filename = machine->initrd_filename; - sabrelite_binfo.nb_cpus = smp_cpus; - sabrelite_binfo.secure_boot = true; - sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary; - sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary; - - if (!qtest_enabled()) { - arm_load_kernel(&s->soc.cpu[0], &sabrelite_binfo); - } -} - -static void sabrelite_machine_init(MachineClass *mc) -{ - mc->desc = "Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)"; - mc->init = sabrelite_init; - mc->max_cpus = FSL_IMX6_NUM_CPUS; -} - -DEFINE_MACHINE("sabrelite", sabrelite_machine_init) diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 41cc2eeeb..bf61d63b5 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -164,10 +164,9 @@ static void sl_flash_register(PXA2xxState *cpu, int size) sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE); } -static void sl_nand_init(Object *obj) +static int sl_nand_init(SysBusDevice *dev) { - SLNANDState *s = SL_NAND(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + SLNANDState *s = SL_NAND(dev); DriveInfo *nand; s->ctl = 0; @@ -176,8 +175,10 @@ static void sl_nand_init(Object *obj) s->nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL, s->manf_id, s->chip_id); - memory_region_init_io(&s->iomem, obj, &sl_ops, s, "sl", 0x40); + memory_region_init_io(&s->iomem, OBJECT(s), &sl_ops, s, "sl", 0x40); sysbus_init_mmio(dev, &s->iomem); + + return 0; } /* Spitz Keyboard */ @@ -500,10 +501,10 @@ static void spitz_keyboard_register(PXA2xxState *cpu) qemu_add_kbd_event_handler(spitz_keyboard_handler, s); } -static void spitz_keyboard_init(Object *obj) +static int spitz_keyboard_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - SpitzKeyboardState *s = SPITZ_KEYBOARD(obj); + DeviceState *dev = DEVICE(sbd); + SpitzKeyboardState *s = SPITZ_KEYBOARD(dev); int i, j; for (i = 0; i < 0x80; i ++) @@ -518,6 +519,8 @@ static void spitz_keyboard_init(Object *obj) s->kbdtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, spitz_keyboard_tick, s); qdev_init_gpio_in(dev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM); qdev_init_gpio_out(dev, s->sense, SPITZ_KEY_SENSE_NUM); + + return 0; } /* LCD backlight controller */ @@ -598,13 +601,15 @@ static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value) return 0; } -static void spitz_lcdtg_realize(SSISlave *dev, Error **errp) +static int spitz_lcdtg_init(SSISlave *dev) { SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev); spitz_lcdtg = s; s->bl_power = 0; s->bl_intensity = 0x20; + + return 0; } /* SSP devices */ @@ -664,7 +669,7 @@ static void spitz_adc_temp_on(void *opaque, int line, int level) max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); } -static void corgi_ssp_realize(SSISlave *d, Error **errp) +static int corgi_ssp_init(SSISlave *d) { DeviceState *dev = DEVICE(d); CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d); @@ -673,6 +678,8 @@ static void corgi_ssp_realize(SSISlave *d, Error **errp) s->bus[0] = ssi_create_bus(dev, "ssi0"); s->bus[1] = ssi_create_bus(dev, "ssi1"); s->bus[2] = ssi_create_bus(dev, "ssi2"); + + return 0; } static void spitz_ssp_attach(PXA2xxState *cpu) @@ -1058,7 +1065,9 @@ static Property sl_nand_properties[] = { static void sl_nand_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = sl_nand_init; dc->vmsd = &vmstate_sl_nand_info; dc->props = sl_nand_properties; /* Reason: init() method uses drive_get() */ @@ -1069,7 +1078,6 @@ static const TypeInfo sl_nand_info = { .name = TYPE_SL_NAND, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLNANDState), - .instance_init = sl_nand_init, .class_init = sl_nand_class_init, }; @@ -1089,7 +1097,9 @@ static VMStateDescription vmstate_spitz_kbd = { static void spitz_keyboard_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = spitz_keyboard_init; dc->vmsd = &vmstate_spitz_kbd; } @@ -1097,7 +1107,6 @@ static const TypeInfo spitz_keyboard_info = { .name = TYPE_SPITZ_KEYBOARD, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SpitzKeyboardState), - .instance_init = spitz_keyboard_init, .class_init = spitz_keyboard_class_init, }; @@ -1117,7 +1126,7 @@ static void corgi_ssp_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->realize = corgi_ssp_realize; + k->init = corgi_ssp_init; k->transfer = corgi_ssp_transfer; dc->vmsd = &vmstate_corgi_ssp_regs; } @@ -1146,7 +1155,7 @@ static void spitz_lcdtg_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->realize = spitz_lcdtg_realize; + k->init = spitz_lcdtg_init; k->transfer = spitz_lcdtg_transfer; dc->vmsd = &vmstate_spitz_lcdtg_regs; } diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 794a3ada7..c1766f856 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -17,10 +17,8 @@ #include "hw/i2c/i2c.h" #include "net/net.h" #include "hw/boards.h" -#include "qemu/log.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" -#include "hw/char/pl011.h" #define GPIO_A 0 #define GPIO_B 1 @@ -318,22 +316,23 @@ static const VMStateDescription vmstate_stellaris_gptm = { } }; -static void stellaris_gptm_init(Object *obj) +static int stellaris_gptm_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - gptm_state *s = STELLARIS_GPTM(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + gptm_state *s = STELLARIS_GPTM(dev); sysbus_init_irq(sbd, &s->irq); qdev_init_gpio_out(dev, &s->trigger, 1); - memory_region_init_io(&s->iomem, obj, &gptm_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &gptm_ops, s, "gptm", 0x1000); sysbus_init_mmio(sbd, &s->iomem); s->opaque[0] = s->opaque[1] = s; s->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[0]); s->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[1]); + vmstate_register(dev, -1, &vmstate_stellaris_gptm, s); + return 0; } @@ -874,22 +873,23 @@ static const VMStateDescription vmstate_stellaris_i2c = { } }; -static void stellaris_i2c_init(Object *obj) +static int stellaris_i2c_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - stellaris_i2c_state *s = STELLARIS_I2C(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + stellaris_i2c_state *s = STELLARIS_I2C(dev); I2CBus *bus; sysbus_init_irq(sbd, &s->irq); bus = i2c_init_bus(dev, "i2c"); s->bus = bus; - memory_region_init_io(&s->iomem, obj, &stellaris_i2c_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &stellaris_i2c_ops, s, "i2c", 0x1000); sysbus_init_mmio(sbd, &s->iomem); /* ??? For now we only implement the master interface. */ stellaris_i2c_reset(s); + vmstate_register(dev, -1, &vmstate_stellaris_i2c, s); + return 0; } /* Analogue to Digital Converter. This is only partially implemented, @@ -1160,22 +1160,23 @@ static const VMStateDescription vmstate_stellaris_adc = { } }; -static void stellaris_adc_init(Object *obj) +static int stellaris_adc_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - stellaris_adc_state *s = STELLARIS_ADC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + stellaris_adc_state *s = STELLARIS_ADC(dev); int n; for (n = 0; n < 4; n++) { sysbus_init_irq(sbd, &s->irq[n]); } - memory_region_init_io(&s->iomem, obj, &stellaris_adc_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &stellaris_adc_ops, s, "adc", 0x1000); sysbus_init_mmio(sbd, &s->iomem); stellaris_adc_reset(s); qdev_init_gpio_in(dev, stellaris_adc_trigger, 1); + vmstate_register(dev, -1, &vmstate_stellaris_adc, s); + return 0; } static @@ -1304,9 +1305,8 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, for (i = 0; i < 4; i++) { if (board->dc2 & (1 << i)) { - pl011_luminary_create(0x4000c000 + i * 0x1000, - qdev_get_gpio_in(nvic, uart_irq[i]), - serial_hds[i]); + sysbus_create_simple("pl011_luminary", 0x4000c000 + i * 0x1000, + qdev_get_gpio_in(nvic, uart_irq[i])); } } if (board->dc2 & (1 << 4)) { @@ -1425,46 +1425,43 @@ type_init(stellaris_machine_init) static void stellaris_i2c_class_init(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - dc->vmsd = &vmstate_stellaris_i2c; + sdc->init = stellaris_i2c_init; } static const TypeInfo stellaris_i2c_info = { .name = TYPE_STELLARIS_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_i2c_state), - .instance_init = stellaris_i2c_init, .class_init = stellaris_i2c_class_init, }; static void stellaris_gptm_class_init(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - dc->vmsd = &vmstate_stellaris_gptm; + sdc->init = stellaris_gptm_init; } static const TypeInfo stellaris_gptm_info = { .name = TYPE_STELLARIS_GPTM, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(gptm_state), - .instance_init = stellaris_gptm_init, .class_init = stellaris_gptm_class_init, }; static void stellaris_adc_class_init(ObjectClass *klass, void *data) { - DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); - dc->vmsd = &vmstate_stellaris_adc; + sdc->init = stellaris_adc_init; } static const TypeInfo stellaris_adc_info = { .name = TYPE_STELLARIS_ADC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(stellaris_adc_state), - .instance_init = stellaris_adc_init, .class_init = stellaris_adc_class_init, }; diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index de26b8caf..a5ea1e237 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" +#include "cpu.h" #include "hw/arm/arm.h" #include "exec/address-spaces.h" #include "hw/arm/stm32f205_soc.h" @@ -107,7 +108,6 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) /* Attach UART (uses USART registers) and USART controllers */ for (i = 0; i < STM_NUM_USARTS; i++) { usartdev = DEVICE(&(s->usart[i])); - qdev_prop_set_chr(usartdev, "chardev", i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL); object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err); if (err != NULL) { error_propagate(errp, err); diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index f1b2c6c96..1eeb1ab39 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -38,7 +38,6 @@ #include "sysemu/sysemu.h" #include "hw/ssi/ssi.h" #include "qemu/cutils.h" -#include "qemu/log.h" //#define DEBUG @@ -180,18 +179,19 @@ static const MemoryRegionOps strongarm_pic_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void strongarm_pic_initfn(Object *obj) +static int strongarm_pic_initfn(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - StrongARMPICState *s = STRONGARM_PIC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + StrongARMPICState *s = STRONGARM_PIC(dev); qdev_init_gpio_in(dev, strongarm_pic_set_irq, SA_PIC_SRCS); - memory_region_init_io(&s->iomem, obj, &strongarm_pic_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_pic_ops, s, "pic", 0x1000); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); sysbus_init_irq(sbd, &s->fiq); + + return 0; } static int strongarm_pic_post_load(void *opaque, int version_id) @@ -217,7 +217,9 @@ static VMStateDescription vmstate_strongarm_pic_regs = { static void strongarm_pic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = strongarm_pic_initfn; dc->desc = "StrongARM PIC"; dc->vmsd = &vmstate_strongarm_pic_regs; } @@ -226,7 +228,6 @@ static const TypeInfo strongarm_pic_info = { .name = TYPE_STRONGARM_PIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMPICState), - .instance_init = strongarm_pic_initfn, .class_init = strongarm_pic_class_init, }; @@ -380,10 +381,9 @@ static const MemoryRegionOps strongarm_rtc_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void strongarm_rtc_init(Object *obj) +static int strongarm_rtc_init(SysBusDevice *dev) { - StrongARMRTCState *s = STRONGARM_RTC(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + StrongARMRTCState *s = STRONGARM_RTC(dev); struct tm tm; s->rttr = 0x0; @@ -400,9 +400,11 @@ static void strongarm_rtc_init(Object *obj) sysbus_init_irq(dev, &s->rtc_irq); sysbus_init_irq(dev, &s->rtc_hz_irq); - memory_region_init_io(&s->iomem, obj, &strongarm_rtc_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_rtc_ops, s, "rtc", 0x10000); sysbus_init_mmio(dev, &s->iomem); + + return 0; } static void strongarm_rtc_pre_save(void *opaque) @@ -441,7 +443,9 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = { static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = strongarm_rtc_init; dc->desc = "StrongARM RTC Controller"; dc->vmsd = &vmstate_strongarm_rtc_regs; } @@ -450,7 +454,6 @@ static const TypeInfo strongarm_rtc_sysbus_info = { .name = TYPE_STRONGARM_RTC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMRTCState), - .instance_init = strongarm_rtc_init, .class_init = strongarm_rtc_sysbus_class_init, }; @@ -643,17 +646,16 @@ static DeviceState *strongarm_gpio_init(hwaddr base, return dev; } -static void strongarm_gpio_initfn(Object *obj) +static int strongarm_gpio_initfn(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - StrongARMGPIOInfo *s = STRONGARM_GPIO(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + StrongARMGPIOInfo *s = STRONGARM_GPIO(dev); int i; qdev_init_gpio_in(dev, strongarm_gpio_set, 28); qdev_init_gpio_out(dev, s->handler, 28); - memory_region_init_io(&s->iomem, obj, &strongarm_gpio_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_gpio_ops, s, "gpio", 0x1000); sysbus_init_mmio(sbd, &s->iomem); @@ -661,6 +663,8 @@ static void strongarm_gpio_initfn(Object *obj) sysbus_init_irq(sbd, &s->irqs[i]); } sysbus_init_irq(sbd, &s->irqX); + + return 0; } static const VMStateDescription vmstate_strongarm_gpio_regs = { @@ -683,7 +687,9 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = { static void strongarm_gpio_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = strongarm_gpio_initfn; dc->desc = "StrongARM GPIO controller"; dc->vmsd = &vmstate_strongarm_gpio_regs; } @@ -692,7 +698,6 @@ static const TypeInfo strongarm_gpio_info = { .name = TYPE_STRONGARM_GPIO, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMGPIOInfo), - .instance_init = strongarm_gpio_initfn, .class_init = strongarm_gpio_class_init, }; @@ -819,19 +824,20 @@ static const MemoryRegionOps strongarm_ppc_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void strongarm_ppc_init(Object *obj) +static int strongarm_ppc_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - StrongARMPPCInfo *s = STRONGARM_PPC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + StrongARMPPCInfo *s = STRONGARM_PPC(dev); qdev_init_gpio_in(dev, strongarm_ppc_set, 22); qdev_init_gpio_out(dev, s->handler, 22); - memory_region_init_io(&s->iomem, obj, &strongarm_ppc_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_ppc_ops, s, "ppc", 0x1000); sysbus_init_mmio(sbd, &s->iomem); + + return 0; } static const VMStateDescription vmstate_strongarm_ppc_regs = { @@ -853,7 +859,9 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = { static void strongarm_ppc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = strongarm_ppc_init; dc->desc = "StrongARM PPC controller"; dc->vmsd = &vmstate_strongarm_ppc_regs; } @@ -862,7 +870,6 @@ static const TypeInfo strongarm_ppc_info = { .name = TYPE_STRONGARM_PPC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMPPCInfo), - .instance_init = strongarm_ppc_init, .class_init = strongarm_ppc_class_init, }; @@ -1224,12 +1231,11 @@ static const MemoryRegionOps strongarm_uart_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void strongarm_uart_init(Object *obj) +static int strongarm_uart_init(SysBusDevice *dev) { - StrongARMUARTState *s = STRONGARM_UART(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + StrongARMUARTState *s = STRONGARM_UART(dev); - memory_region_init_io(&s->iomem, obj, &strongarm_uart_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &strongarm_uart_ops, s, "uart", 0x10000); sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); @@ -1244,6 +1250,8 @@ static void strongarm_uart_init(Object *obj) strongarm_uart_event, s); } + + return 0; } static void strongarm_uart_reset(DeviceState *dev) @@ -1313,7 +1321,9 @@ static Property strongarm_uart_properties[] = { static void strongarm_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = strongarm_uart_init; dc->desc = "StrongARM UART controller"; dc->reset = strongarm_uart_reset; dc->vmsd = &vmstate_strongarm_uart_regs; @@ -1324,7 +1334,6 @@ static const TypeInfo strongarm_uart_info = { .name = TYPE_STRONGARM_UART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(StrongARMUARTState), - .instance_init = strongarm_uart_init, .class_init = strongarm_uart_class_init, }; diff --git a/hw/arm/strongarm.h b/hw/arm/strongarm.h index 1470eac4f..2893f9444 100644 --- a/hw/arm/strongarm.h +++ b/hw/arm/strongarm.h @@ -1,8 +1,7 @@ -#ifndef STRONGARM_H -#define STRONGARM_H +#ifndef _STRONGARM_H +#define _STRONGARM_H #include "exec/memory.h" -#include "target-arm/cpu-qom.h" #define SA_CS0 0x00000000 #define SA_CS1 0x08000000 diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c index 2db66508b..4e9494f94 100644 --- a/hw/arm/tosa.c +++ b/hw/arm/tosa.c @@ -127,9 +127,10 @@ static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value) return 0; } -static void tosa_ssp_realize(SSISlave *dev, Error **errp) +static int tosa_ssp_init(SSISlave *dev) { /* Nothing to do. */ + return 0; } #define TYPE_TOSA_DAC "tosa_dac" @@ -282,7 +283,7 @@ static void tosa_ssp_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->realize = tosa_ssp_realize; + k->init = tosa_ssp_init; k->transfer = tosa_ssp_tansfer; } diff --git a/hw/arm/trace-events b/hw/arm/trace-events deleted file mode 100644 index d5f33a2a0..000000000 --- a/hw/arm/trace-events +++ /dev/null @@ -1,4 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/arm/virt-acpi-build.c -virt_acpi_setup(void) "No fw cfg or ACPI disabled. Bailing out." diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 8ae5392bc..e5a80c2d2 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -23,7 +23,6 @@ #include "exec/address-spaces.h" #include "hw/block/flash.h" #include "qemu/error-report.h" -#include "hw/char/pl011.h" #define VERSATILE_FLASH_ADDR 0x34000000 #define VERSATILE_FLASH_SIZE (64 * 1024 * 1024) @@ -154,11 +153,10 @@ static const MemoryRegionOps vpb_sic_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void vpb_sic_init(Object *obj) +static int vpb_sic_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - vpb_sic_state *s = VERSATILE_PB_SIC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + vpb_sic_state *s = VERSATILE_PB_SIC(dev); int i; qdev_init_gpio_in(dev, vpb_sic_set_irq, 32); @@ -166,9 +164,10 @@ static void vpb_sic_init(Object *obj) sysbus_init_irq(sbd, &s->parent[i]); } s->irq = 31; - memory_region_init_io(&s->iomem, obj, &vpb_sic_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &vpb_sic_ops, s, "vpb-sic", 0x1000); sysbus_init_mmio(sbd, &s->iomem); + return 0; } /* Board init. */ @@ -276,7 +275,7 @@ static void versatile_init(MachineState *machine, int board_id) pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL); } } - if (machine_usb(machine)) { + if (usb_enabled()) { pci_create_simple(pci_bus, -1, "pci-ohci"); } n = drive_get_max_bus(IF_SCSI); @@ -285,10 +284,10 @@ static void versatile_init(MachineState *machine, int board_id) n--; } - pl011_create(0x101f1000, pic[12], serial_hds[0]); - pl011_create(0x101f2000, pic[13], serial_hds[1]); - pl011_create(0x101f3000, pic[14], serial_hds[2]); - pl011_create(0x10009000, sic[6], serial_hds[3]); + sysbus_create_simple("pl011", 0x101f1000, pic[12]); + sysbus_create_simple("pl011", 0x101f2000, pic[13]); + sysbus_create_simple("pl011", 0x101f3000, pic[14]); + sysbus_create_simple("pl011", 0x10009000, sic[6]); sysbus_create_simple("pl080", 0x10130000, pic[17]); sysbus_create_simple("sp804", 0x101e2000, pic[4]); @@ -428,7 +427,9 @@ type_init(versatile_machine_init) static void vpb_sic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = vpb_sic_init; dc->vmsd = &vmstate_vpb_sic; } @@ -436,7 +437,6 @@ static const TypeInfo vpb_sic_info = { .name = TYPE_VERSATILE_PB_SIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(vpb_sic_state), - .instance_init = vpb_sic_init, .class_init = vpb_sic_class_init, }; diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 58760f40c..70b3e701e 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -39,7 +39,6 @@ #include "sysemu/device_tree.h" #include "qemu/error-report.h" #include <libfdt.h> -#include "hw/char/pl011.h" #define VEXPRESS_BOARD_ID 0x8e0 #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) @@ -632,10 +631,10 @@ static void vexpress_common_init(MachineState *machine) sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]); sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]); - pl011_create(map[VE_UART0], pic[5], serial_hds[0]); - pl011_create(map[VE_UART1], pic[6], serial_hds[1]); - pl011_create(map[VE_UART2], pic[7], serial_hds[2]); - pl011_create(map[VE_UART3], pic[8], serial_hds[3]); + sysbus_create_simple("pl011", map[VE_UART0], pic[5]); + sysbus_create_simple("pl011", map[VE_UART1], pic[6]); + sysbus_create_simple("pl011", map[VE_UART2], pic[7]); + sysbus_create_simple("pl011", map[VE_UART3], pic[8]); sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]); sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]); diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 28fc59c66..f51fe396c 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -43,7 +43,6 @@ #include "hw/acpi/aml-build.h" #include "hw/pci/pcie_host.h" #include "hw/pci/pci.h" -#include "sysemu/numa.h" #define ARM_SPI_BASE 32 #define ACPI_POWER_BUTTON_DEVICE "PWRB" @@ -231,8 +230,7 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, aml_append(rbuf, aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, - base_mmio_high, - base_mmio_high + size_mmio_high - 1, 0x0000, + base_mmio_high, base_mmio_high, 0x0000, size_mmio_high)); } @@ -354,14 +352,11 @@ static void acpi_dsdt_add_power_button(Aml *scope) /* RSDP */ static GArray * -build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset) +build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) { AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp); - unsigned rsdt_pa_size = sizeof(rsdp->rsdt_physical_address); - unsigned rsdt_pa_offset = - (char *)&rsdp->rsdt_physical_address - rsdp_table->data; - bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, rsdp_table, 16, + bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16, true /* fseg memory */); memcpy(&rsdp->signature, "RSD PTR ", sizeof(rsdp->signature)); @@ -369,21 +364,24 @@ build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset) rsdp->length = cpu_to_le32(sizeof(*rsdp)); rsdp->revision = 0x02; + /* Point to RSDT */ + rsdp->rsdt_physical_address = cpu_to_le32(rsdt); /* Address to be filled by Guest linker */ - bios_linker_loader_add_pointer(linker, - ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size, - ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset); - + bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE, + ACPI_BUILD_TABLE_FILE, + rsdp_table, &rsdp->rsdt_physical_address, + sizeof rsdp->rsdt_physical_address); + rsdp->checksum = 0; /* Checksum to be filled by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, - (char *)rsdp - rsdp_table->data, sizeof *rsdp, - (char *)&rsdp->checksum - rsdp_table->data); + rsdp_table, rsdp, sizeof *rsdp, + &rsdp->checksum); return rsdp_table; } static void -build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) { AcpiSerialPortConsoleRedirection *spcr; const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART]; @@ -416,52 +414,7 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) } static void -build_srat(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) -{ - 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)); - - for (i = 0; i < guest_info->smp_cpus; i++) { - for (j = 0; j < nb_numa_nodes; j++) { - if (test_bit(i, numa_info[j].node_cpu)) { - cpu_node[i] = j; - break; - } - } - } - - srat_start = table_data->len; - srat = acpi_data_push(table_data, sizeof(*srat)); - srat->reserved1 = cpu_to_le32(1); - - for (i = 0; i < guest_info->smp_cpus; ++i) { - core = acpi_data_push(table_data, sizeof(*core)); - core->type = ACPI_SRAT_PROCESSOR_GICC; - core->length = sizeof(*core); - core->proximity = cpu_to_le32(cpu_node[i]); - core->acpi_processor_uid = cpu_to_le32(i); - core->flags = cpu_to_le32(1); - } - g_free(cpu_node); - - mem_base = guest_info->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, - MEM_AFFINITY_ENABLED); - mem_base += numa_info[i].node_mem; - } - - build_header(linker, table_data, (void *)srat, "SRAT", - table_data->len - srat_start, 3, NULL, NULL); -} - -static void -build_mcfg(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) +build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) { AcpiTableMcfg *mcfg; const MemMapEntry *memmap = guest_info->memmap; @@ -481,7 +434,7 @@ 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, GArray *linker) { int gtdt_start = table_data->len; AcpiGenericTimerTable *gtdt; @@ -507,7 +460,7 @@ 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, GArray *linker, VirtGuestInfo *guest_info) { int madt_start = table_data->len; const MemMapEntry *memmap = guest_info->memmap; @@ -523,7 +476,6 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR; gicd->length = sizeof(*gicd); gicd->base_address = memmap[VIRT_GIC_DIST].base; - gicd->version = guest_info->gic_version; for (i = 0; i < guest_info->smp_cpus; i++) { AcpiMadtGenericInterrupt *gicc = acpi_data_push(table_data, @@ -539,10 +491,6 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) gicc->arm_mpidr = armcpu->mp_affinity; gicc->uid = i; gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED); - - if (armcpu->has_pmu) { - gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ)); - } } if (guest_info->gic_version == 3) { @@ -571,10 +519,9 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info) /* FADT */ static void -build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset) +build_fadt(GArray *table_data, GArray *linker, unsigned dsdt) { AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt)); - unsigned dsdt_entry_offset = (char *)&fadt->dsdt - table_data->data; /* Hardware Reduced = 1 and use PSCI 0.2+ and with HVC */ fadt->flags = cpu_to_le32(1 << ACPI_FADT_F_HW_REDUCED_ACPI); @@ -584,10 +531,12 @@ build_fadt(GArray *table_data, BIOSLinker *linker, unsigned dsdt_tbl_offset) /* ACPI v5.1 (fadt->revision.fadt->minor_revision) */ fadt->minor_revision = 0x1; + fadt->dsdt = cpu_to_le32(dsdt); /* DSDT address to be filled by Guest linker */ - bios_linker_loader_add_pointer(linker, - ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt), - ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset); + bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, + ACPI_BUILD_TABLE_FILE, + table_data, &fadt->dsdt, + sizeof fadt->dsdt); build_header(linker, table_data, (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL); @@ -595,7 +544,7 @@ 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, GArray *linker, VirtGuestInfo *guest_info) { Aml *scope, *dsdt; const MemMapEntry *memmap = guest_info->memmap; @@ -655,8 +604,7 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); - bios_linker_loader_alloc(tables->linker, - ACPI_BUILD_TABLE_FILE, tables_blob, + bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE, 64, false /* high memory */); /* @@ -690,11 +638,6 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_spcr(tables_blob, tables->linker, guest_info); - if (nb_numa_nodes > 0) { - acpi_add_table(table_offsets, tables_blob); - build_srat(tables_blob, tables->linker, guest_info); - } - /* RSDT is pointed to by RSDP */ rsdt = tables_blob->len; build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL); @@ -735,7 +678,7 @@ static void virt_acpi_build_update(void *build_opaque) 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_ram_update(build_state->linker_mr, tables.linker); acpi_build_tables_cleanup(&tables, true); @@ -793,8 +736,7 @@ void virt_acpi_setup(VirtGuestInfo *guest_info) assert(build_state->table_mr != NULL); build_state->linker_mr = - acpi_add_rom_blob(build_state, tables.linker->cmd_blob, - "etc/table-loader", 0); + acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0); fw_cfg_add_file(guest_info->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, acpi_data_len(tables.tcpalog)); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index a193b5a95..a535285e4 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -38,11 +38,9 @@ #include "net/net.h" #include "sysemu/block-backend.h" #include "sysemu/device_tree.h" -#include "sysemu/numa.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "hw/boards.h" -#include "hw/compat.h" #include "hw/loader.h" #include "exec/address-spaces.h" #include "qemu/bitops.h" @@ -52,8 +50,7 @@ #include "hw/arm/sysbus-fdt.h" #include "hw/platform-bus.h" #include "hw/arm/fdt.h" -#include "hw/intc/arm_gic.h" -#include "hw/intc/arm_gicv3_common.h" +#include "hw/intc/arm_gic_common.h" #include "kvm_arm.h" #include "hw/smbios/smbios.h" #include "qapi/visitor.h" @@ -83,7 +80,6 @@ typedef struct VirtBoardInfo { typedef struct { MachineClass parent; VirtBoardInfo *daughterboard; - bool disallow_affinity_adjustment; } VirtMachineClass; typedef struct { @@ -101,36 +97,6 @@ typedef struct { #define VIRT_MACHINE_CLASS(klass) \ OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE) - -#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \ - static void virt_##major##_##minor##_class_init(ObjectClass *oc, \ - void *data) \ - { \ - MachineClass *mc = MACHINE_CLASS(oc); \ - virt_machine_##major##_##minor##_options(mc); \ - mc->desc = "QEMU " # major "." # minor " ARM Virtual Machine"; \ - if (latest) { \ - mc->alias = "virt"; \ - } \ - } \ - static const TypeInfo machvirt_##major##_##minor##_info = { \ - .name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \ - .parent = TYPE_VIRT_MACHINE, \ - .instance_init = virt_##major##_##minor##_instance_init, \ - .class_init = virt_##major##_##minor##_class_init, \ - }; \ - static void machvirt_machine_##major##_##minor##_init(void) \ - { \ - type_register_static(&machvirt_##major##_##minor##_info); \ - } \ - type_init(machvirt_machine_##major##_##minor##_init); - -#define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \ - DEFINE_VIRT_MACHINE_LATEST(major, minor, true) -#define DEFINE_VIRT_MACHINE(major, minor) \ - DEFINE_VIRT_MACHINE_LATEST(major, minor, false) - - /* RAM limit in GB. Since VIRT_MEM starts at the 1GB mark, this means * RAM can go up to the 256GB mark, leaving 256GB of the physical * address space unallocated and free for future use between 256G and 512G. @@ -363,7 +329,6 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) { int cpu; int addr_cells = 1; - unsigned int i; /* * From Documentation/devicetree/bindings/arm/cpus.txt @@ -413,12 +378,6 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) armcpu->mp_affinity); } - for (i = 0; i < nb_numa_nodes; i++) { - if (test_bit(cpu, numa_info[i].node_cpu)) { - qemu_fdt_setprop_cell(vbi->fdt, nodename, "numa-node-id", i); - } - } - g_free(nodename); } } @@ -469,37 +428,6 @@ static void fdt_add_gic_node(VirtBoardInfo *vbi, int type) qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle); } -static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype) -{ - CPUState *cpu; - ARMCPU *armcpu; - uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI; - - CPU_FOREACH(cpu) { - armcpu = ARM_CPU(cpu); - if (!armcpu->has_pmu || - !kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ))) { - return; - } - } - - if (gictype == 2) { - irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START, - GIC_FDT_IRQ_PPI_CPU_WIDTH, - (1 << vbi->smp_cpus) - 1); - } - - armcpu = ARM_CPU(qemu_get_cpu(0)); - qemu_fdt_add_subnode(vbi->fdt, "/pmu"); - if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) { - const char compat[] = "arm,armv8-pmuv3"; - qemu_fdt_setprop(vbi->fdt, "/pmu", "compatible", - compat, sizeof(compat)); - qemu_fdt_setprop_cells(vbi->fdt, "/pmu", "interrupts", - GIC_FDT_IRQ_TYPE_PPI, VIRTUAL_PMU_IRQ, irqflags); - } -} - static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) { int i; @@ -589,7 +517,7 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure) } static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart, - MemoryRegion *mem, CharDriverState *chr) + MemoryRegion *mem) { char *nodename; hwaddr base = vbi->memmap[uart].base; @@ -600,7 +528,6 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart, DeviceState *dev = qdev_create(NULL, "pl011"); SysBusDevice *s = SYS_BUS_DEVICE(dev); - qdev_prop_set_chr(dev, "chardev", chr); qdev_init_nofail(dev); memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0)); @@ -1023,7 +950,6 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2); qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, nr_pcie_buses - 1); - qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0); if (vbi->v2m_phandle) { qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", @@ -1167,7 +1093,6 @@ void virt_guest_info_machine_done(Notifier *notifier, void *data) static void machvirt_init(MachineState *machine) { VirtMachineState *vms = VIRT_MACHINE(machine); - VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine); qemu_irq pic[NUM_IRQS]; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *secure_sysmem = NULL; @@ -1179,12 +1104,7 @@ static void machvirt_init(MachineState *machine) VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state); VirtGuestInfo *guest_info = &guest_info_state->info; char **cpustr; - ObjectClass *oc; - const char *typename; - CPUClass *cc; - Error *err = NULL; bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0); - uint8_t clustersz; if (!cpu_model) { cpu_model = "cortex-a15"; @@ -1230,10 +1150,8 @@ static void machvirt_init(MachineState *machine) */ if (gic_version == 3) { virt_max_cpus = vbi->memmap[VIRT_GIC_REDIST].size / 0x20000; - clustersz = GICV3_TARGETLIST_BITS; } else { virt_max_cpus = GIC_NCPU; - clustersz = GIC_TARGETLIST_BITS; } if (max_cpus > virt_max_cpus) { @@ -1269,37 +1187,25 @@ static void machvirt_init(MachineState *machine) create_fdt(vbi); - oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]); - if (!oc) { - error_report("Unable to find CPU definition"); - exit(1); - } - typename = object_class_get_name(oc); - - /* convert -smp CPU options specified by the user into global props */ - cc = CPU_CLASS(oc); - cc->parse_features(typename, cpustr[1], &err); - g_strfreev(cpustr); - if (err) { - error_report_err(err); - exit(1); - } - for (n = 0; n < smp_cpus; n++) { - Object *cpuobj = object_new(typename); - if (!vmc->disallow_affinity_adjustment) { - /* Adjust MPIDR like 64-bit KVM hosts, which incorporate the - * GIC's target-list limitations. 32-bit KVM hosts currently - * always create clusters of 4 CPUs, but that is expected to - * change when they gain support for gicv3. When KVM is enabled - * it will override the changes we make here, therefore our - * purposes are to make TCG consistent (with 64-bit KVM hosts) - * and to improve SGI efficiency. - */ - uint8_t aff1 = n / clustersz; - uint8_t aff0 = n % clustersz; - object_property_set_int(cpuobj, (aff1 << ARM_AFF1_SHIFT) | aff0, - "mp-affinity", NULL); + ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]); + CPUClass *cc = CPU_CLASS(oc); + Object *cpuobj; + Error *err = NULL; + char *cpuopts = g_strdup(cpustr[1]); + + if (!oc) { + error_report("Unable to find CPU definition"); + exit(1); + } + cpuobj = object_new(object_class_get_name(oc)); + + /* Handle any CPU options specified by the user */ + cc->parse_features(CPU(cpuobj), cpuopts, &err); + g_free(cpuopts); + if (err) { + error_report_err(err); + exit(1); } if (!vms->secure) { @@ -1331,6 +1237,7 @@ static void machvirt_init(MachineState *machine) object_property_set_bool(cpuobj, true, "realized", NULL); } + g_strfreev(cpustr); fdt_add_timer_nodes(vbi, gic_version); fdt_add_cpu_nodes(vbi); fdt_add_psci_node(vbi); @@ -1343,13 +1250,11 @@ static void machvirt_init(MachineState *machine) create_gic(vbi, pic, gic_version, vms->secure); - fdt_add_pmu_nodes(vbi, gic_version); - - create_uart(vbi, pic, VIRT_UART, sysmem, serial_hds[0]); + create_uart(vbi, pic, VIRT_UART, sysmem); if (vms->secure) { create_secure_ram(vbi, secure_sysmem); - create_uart(vbi, pic, VIRT_SECURE_UART, secure_sysmem, serial_hds[1]); + create_uart(vbi, pic, VIRT_SECURE_UART, secure_sysmem); } create_rtc(vbi, pic); @@ -1473,13 +1378,7 @@ static const TypeInfo virt_machine_info = { .class_init = virt_machine_class_init, }; -static void machvirt_machine_init(void) -{ - type_register_static(&virt_machine_info); -} -type_init(machvirt_machine_init); - -static void virt_2_7_instance_init(Object *obj) +static void virt_2_6_instance_init(Object *obj) { VirtMachineState *vms = VIRT_MACHINE(obj); @@ -1512,25 +1411,29 @@ static void virt_2_7_instance_init(Object *obj) "Valid values are 2, 3 and host", NULL); } -static void virt_machine_2_7_options(MachineClass *mc) +static void virt_2_6_class_init(ObjectClass *oc, void *data) { + MachineClass *mc = MACHINE_CLASS(oc); + static GlobalProperty compat_props[] = { + { /* end of list */ } + }; + + mc->desc = "QEMU 2.6 ARM Virtual Machine"; + mc->alias = "virt"; + mc->compat_props = compat_props; } -DEFINE_VIRT_MACHINE_AS_LATEST(2, 7) -#define VIRT_COMPAT_2_6 \ - HW_COMPAT_2_6 +static const TypeInfo machvirt_info = { + .name = MACHINE_TYPE_NAME("virt-2.6"), + .parent = TYPE_VIRT_MACHINE, + .instance_init = virt_2_6_instance_init, + .class_init = virt_2_6_class_init, +}; -static void virt_2_6_instance_init(Object *obj) +static void machvirt_machine_init(void) { - virt_2_7_instance_init(obj); + type_register_static(&virt_machine_info); + type_register_static(&machvirt_info); } -static void virt_machine_2_6_options(MachineClass *mc) -{ - VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc)); - - virt_machine_2_7_options(mc); - SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_6); - vmc->disallow_affinity_adjustment = true; -} -DEFINE_VIRT_MACHINE(2, 6) +type_init(machvirt_machine_init); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 7dac20d67..98b17c9ae 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -32,7 +32,6 @@ #include "hw/ssi/ssi.h" #include "qemu/error-report.h" #include "hw/sd/sd.h" -#include "hw/char/cadence_uart.h" #define NUM_SPI_FLASHES 4 #define NUM_QSPI_FLASHES 2 @@ -138,13 +137,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, spi = (SSIBus *)qdev_get_child_bus(dev, bus_name); for (j = 0; j < num_ss; ++j) { - DriveInfo *dinfo = drive_get_next(IF_MTD); - flash_dev = ssi_create_slave_no_init(spi, "n25q128"); - if (dinfo) { - qdev_prop_set_drive(flash_dev, "drive", - blk_by_legacy_dinfo(dinfo), &error_fatal); - } - qdev_init_nofail(flash_dev); + flash_dev = ssi_create_slave(spi, "n25q128"); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line); @@ -242,8 +235,8 @@ static void zynq_init(MachineState *machine) sysbus_create_simple("xlnx,ps7-usb", 0xE0002000, pic[53-IRQ_OFFSET]); sysbus_create_simple("xlnx,ps7-usb", 0xE0003000, pic[76-IRQ_OFFSET]); - cadence_uart_create(0xE0000000, pic[59 - IRQ_OFFSET], serial_hds[0]); - cadence_uart_create(0xE0001000, pic[82 - IRQ_OFFSET], serial_hds[1]); + sysbus_create_simple("cadence_uart", 0xE0000000, pic[59-IRQ_OFFSET]); + sysbus_create_simple("cadence_uart", 0xE0001000, pic[82-IRQ_OFFSET]); sysbus_create_varargs("cadence_ttc", 0xF8001000, pic[42-IRQ_OFFSET], pic[43-IRQ_OFFSET], pic[44-IRQ_OFFSET], NULL); @@ -300,12 +293,6 @@ static void zynq_init(MachineState *machine) sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]); } - dev = qdev_create(NULL, "xlnx.ps7-dev-cfg"); - qdev_init_nofail(dev); - busdev = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(busdev, 0, pic[40 - IRQ_OFFSET]); - sysbus_mmio_map(busdev, 0, 0xF8007000); - zynq_binfo.ram_size = ram_size; zynq_binfo.kernel_filename = kernel_filename; zynq_binfo.kernel_cmdline = kernel_cmdline; diff --git a/hw/arm/xlnx-ep108.c b/hw/arm/xlnx-ep108.c index 4ec590a25..5f480182b 100644 --- a/hw/arm/xlnx-ep108.c +++ b/hw/arm/xlnx-ep108.c @@ -23,7 +23,6 @@ #include "hw/boards.h" #include "qemu/error-report.h" #include "exec/address-spaces.h" -#include "qemu/log.h" typedef struct XlnxEP108 { XlnxZynqMPState soc; @@ -88,19 +87,12 @@ static void xlnx_ep108_init(MachineState *machine) SSIBus *spi_bus; DeviceState *flash_dev; qemu_irq cs_line; - DriveInfo *dinfo = drive_get_next(IF_MTD); gchar *bus_name = g_strdup_printf("spi%d", i); spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name); g_free(bus_name); - flash_dev = ssi_create_slave_no_init(spi_bus, "sst25wf080"); - if (dinfo) { - qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); - } - qdev_init_nofail(flash_dev); - + flash_dev = ssi_create_slave(spi_bus, "sst25wf080"); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line); @@ -121,11 +113,3 @@ static void xlnx_ep108_machine_init(MachineClass *mc) } DEFINE_MACHINE("xlnx-ep108", xlnx_ep108_machine_init) - -static void xlnx_zcu102_machine_init(MachineClass *mc) -{ - mc->desc = "Xilinx ZynqMP ZCU102 board"; - mc->init = xlnx_ep108_init; -} - -DEFINE_MACHINE("xlnx-zcu102", xlnx_zcu102_machine_init) diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 23c719986..4d504da64 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -22,8 +22,6 @@ #include "hw/arm/xlnx-zynqmp.h" #include "hw/intc/arm_gic_common.h" #include "exec/address-spaces.h" -#include "sysemu/kvm.h" -#include "kvm_arm.h" #define GIC_NUM_SPI_INTR 160 @@ -38,12 +36,6 @@ #define SATA_ADDR 0xFD0C0000 #define SATA_NUM_PORTS 2 -#define DP_ADDR 0xfd4a0000 -#define DP_IRQ 113 - -#define DPDMA_ADDR 0xfd4c0000 -#define DPDMA_IRQ 116 - static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = { 0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000, }; @@ -91,41 +83,6 @@ static inline int arm_gic_ppi_index(int cpu_nr, int ppi_index) return GIC_NUM_SPI_INTR + cpu_nr * GIC_INTERNAL + ppi_index; } -static void xlnx_zynqmp_create_rpu(XlnxZynqMPState *s, const char *boot_cpu, - Error **errp) -{ - Error *err = NULL; - int i; - - for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) { - char *name; - - object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]), - "cortex-r5-" TYPE_ARM_CPU); - object_property_add_child(OBJECT(s), "rpu-cpu[*]", - OBJECT(&s->rpu_cpu[i]), &error_abort); - - name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i])); - if (strcmp(name, boot_cpu)) { - /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, - "start-powered-off", &error_abort); - } else { - s->boot_cpu_ptr = &s->rpu_cpu[i]; - } - g_free(name); - - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs", - &error_abort); - object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized", - &err); - if (err) { - error_propagate(errp, err); - return; - } - } -} - static void xlnx_zynqmp_init(Object *obj) { XlnxZynqMPState *s = XLNX_ZYNQMP(obj); @@ -138,12 +95,19 @@ static void xlnx_zynqmp_init(Object *obj) &error_abort); } + for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) { + object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]), + "cortex-r5-" TYPE_ARM_CPU); + object_property_add_child(obj, "rpu-cpu[*]", OBJECT(&s->rpu_cpu[i]), + &error_abort); + } + object_property_add_link(obj, "ddr-ram", TYPE_MEMORY_REGION, (Object **)&s->ddr_ram, qdev_prop_allow_set_link_before_realize, OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); - object_initialize(&s->gic, sizeof(s->gic), gic_class_name()); + object_initialize(&s->gic, sizeof(s->gic), TYPE_ARM_GIC); qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default()); for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) { @@ -171,12 +135,6 @@ static void xlnx_zynqmp_init(Object *obj) TYPE_XILINX_SPIPS); qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); } - - object_initialize(&s->dp, sizeof(s->dp), TYPE_XLNX_DP); - qdev_set_parent_bus(DEVICE(&s->dp), sysbus_get_default()); - - object_initialize(&s->dpdma, sizeof(s->dpdma), TYPE_XLNX_DPDMA); - qdev_set_parent_bus(DEVICE(&s->dpdma), sysbus_get_default()); } static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) @@ -238,42 +196,11 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", GIC_NUM_SPI_INTR + 32); qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2); qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", XLNX_ZYNQMP_NUM_APU_CPUS); - - /* Realize APUs before realizing the GIC. KVM requires this. */ - for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) { - char *name; - - object_property_set_int(OBJECT(&s->apu_cpu[i]), QEMU_PSCI_CONDUIT_SMC, - "psci-conduit", &error_abort); - - name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i])); - if (strcmp(name, boot_cpu)) { - /* Secondary CPUs start in PSCI powered-down state */ - object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, - "start-powered-off", &error_abort); - } else { - s->boot_cpu_ptr = &s->apu_cpu[i]; - } - g_free(name); - - object_property_set_bool(OBJECT(&s->apu_cpu[i]), - s->secure, "has_el3", NULL); - object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR, - "reset-cbar", &error_abort); - object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized", - &err); - if (err) { - error_propagate(errp, err); - return; - } - } - object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); if (err) { error_propagate(errp, err); return; } - assert(ARRAY_SIZE(xlnx_zynqmp_gic_regions) == XLNX_ZYNQMP_GIC_REGIONS); for (i = 0; i < XLNX_ZYNQMP_GIC_REGIONS; i++) { SysBusDevice *gic = SYS_BUS_DEVICE(&s->gic); @@ -296,6 +223,29 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) for (i = 0; i < XLNX_ZYNQMP_NUM_APU_CPUS; i++) { qemu_irq irq; + char *name; + + object_property_set_int(OBJECT(&s->apu_cpu[i]), QEMU_PSCI_CONDUIT_SMC, + "psci-conduit", &error_abort); + + name = object_get_canonical_path_component(OBJECT(&s->apu_cpu[i])); + if (strcmp(name, boot_cpu)) { + /* Secondary CPUs start in PSCI powered-down state */ + object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, + "start-powered-off", &error_abort); + } else { + s->boot_cpu_ptr = &s->apu_cpu[i]; + } + g_free(name); + + object_property_set_int(OBJECT(&s->apu_cpu[i]), GIC_BASE_ADDR, + "reset-cbar", &error_abort); + object_property_set_bool(OBJECT(&s->apu_cpu[i]), true, "realized", + &err); + if (err) { + error_propagate(errp, err); + return; + } sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i, qdev_get_gpio_in(DEVICE(&s->apu_cpu[i]), @@ -308,8 +258,23 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) qdev_connect_gpio_out(DEVICE(&s->apu_cpu[i]), 1, irq); } - if (s->has_rpu) { - xlnx_zynqmp_create_rpu(s, boot_cpu, &err); + for (i = 0; i < XLNX_ZYNQMP_NUM_RPU_CPUS; i++) { + char *name; + + name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i])); + if (strcmp(name, boot_cpu)) { + /* Secondary CPUs start in PSCI powered-down state */ + object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, + "start-powered-off", &error_abort); + } else { + s->boot_cpu_ptr = &s->rpu_cpu[i]; + } + g_free(name); + + object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "reset-hivecs", + &error_abort); + object_property_set_bool(OBJECT(&s->rpu_cpu[i]), true, "realized", + &err); if (err) { error_propagate(errp, err); return; @@ -343,7 +308,6 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) } for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) { - qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hds[i]); object_property_set_bool(OBJECT(&s->uart[i]), true, "realized", &err); if (err) { error_propagate(errp, err); @@ -400,32 +364,12 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) object_property_add_alias(OBJECT(s), bus_name, OBJECT(&s->spi[i]), "spi0", &error_abort); - g_free(bus_name); - } - - object_property_set_bool(OBJECT(&s->dp), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - sysbus_mmio_map(SYS_BUS_DEVICE(&s->dp), 0, DP_ADDR); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->dp), 0, gic_spi[DP_IRQ]); - - object_property_set_bool(OBJECT(&s->dpdma), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; + g_free(bus_name); } - object_property_set_link(OBJECT(&s->dp), OBJECT(&s->dpdma), "dpdma", - &error_abort); - sysbus_mmio_map(SYS_BUS_DEVICE(&s->dpdma), 0, DPDMA_ADDR); - sysbus_connect_irq(SYS_BUS_DEVICE(&s->dpdma), 0, gic_spi[DPDMA_IRQ]); } static Property xlnx_zynqmp_props[] = { DEFINE_PROP_STRING("boot-cpu", XlnxZynqMPState, boot_cpu), - DEFINE_PROP_BOOL("secure", XlnxZynqMPState, secure, false), - DEFINE_PROP_BOOL("has_rpu", XlnxZynqMPState, has_rpu, false), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 68a92f318..aea895a50 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -151,12 +151,14 @@ static void z2_lcd_cs(void *opaque, int line, int level) z2_lcd->selected = !level; } -static void zipit_lcd_realize(SSISlave *dev, Error **errp) +static int zipit_lcd_init(SSISlave *dev) { ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev); z->selected = 0; z->enabled = 0; z->pos = 0; + + return 0; } static VMStateDescription vmstate_zipit_lcd_state = { @@ -179,7 +181,7 @@ static void zipit_lcd_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->realize = zipit_lcd_realize; + k->init = zipit_lcd_init; k->transfer = zipit_lcd_transfer; dc->vmsd = &vmstate_zipit_lcd_state; } diff --git a/hw/audio/cs4231.c b/hw/audio/cs4231.c index 30690f96a..caf97c169 100644 --- a/hw/audio/cs4231.c +++ b/hw/audio/cs4231.c @@ -145,15 +145,16 @@ static const VMStateDescription vmstate_cs4231 = { } }; -static void cs4231_init(Object *obj) +static int cs4231_init1(SysBusDevice *dev) { - CSState *s = CS4231(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + CSState *s = CS4231(dev); - memory_region_init_io(&s->iomem, obj, &cs_mem_ops, s, "cs4321", + memory_region_init_io(&s->iomem, OBJECT(s), &cs_mem_ops, s, "cs4321", CS_SIZE); sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); + + return 0; } static Property cs4231_properties[] = { @@ -163,7 +164,9 @@ static Property cs4231_properties[] = { static void cs4231_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = cs4231_init1; dc->reset = cs_reset; dc->vmsd = &vmstate_cs4231; dc->props = cs4231_properties; @@ -173,7 +176,6 @@ static const TypeInfo cs4231_info = { .name = TYPE_CS4231, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(CSState), - .instance_init = cs4231_init, .class_init = cs4231_class_init, }; diff --git a/hw/audio/fmopl.h b/hw/audio/fmopl.h index fdda7f9f5..24ba5f480 100644 --- a/hw/audio/fmopl.h +++ b/hw/audio/fmopl.h @@ -1,5 +1,5 @@ -#ifndef FMOPL_H -#define FMOPL_H +#ifndef __FMOPL_H_ +#define __FMOPL_H_ /* --- select emulation chips --- */ #define BUILD_YM3812 (HAS_YM3812) diff --git a/hw/audio/gus.c b/hw/audio/gus.c index 6c0264677..9dd6947be 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -144,7 +144,7 @@ static void GUS_callback (void *opaque, int free) s->left = samples; reset: - gus_irqgen (&s->emu, (uint64_t)net * 1000000 / s->freq); + gus_irqgen (&s->emu, muldiv64 (net, 1000000, s->freq)); } int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n) diff --git a/hw/audio/gusemu.h b/hw/audio/gusemu.h index 9aec7bf8e..b7f075126 100644 --- a/hw/audio/gusemu.h +++ b/hw/audio/gusemu.h @@ -101,4 +101,4 @@ void gus_irqgen(GUSEmuState *state, unsigned int elapsed_time); /* lower values won´t provide any benefit at all, higher values can cause audible timing delays */ /* note: masked timers are also calculated by this function, thus it might be needed even without any IRQs in use! */ -#endif /* GUSEMU_H */ +#endif /* gusemu.h */ diff --git a/hw/audio/gustate.h b/hw/audio/gustate.h index d16297110..ece903abb 100644 --- a/hw/audio/gustate.h +++ b/hw/audio/gustate.h @@ -129,4 +129,4 @@ #define gusdataend (VSRegsEnd+4) -#endif /* GUSTATE_H */ +#endif /* gustate.h */ diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index cd95340cd..d372d4ab9 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -26,7 +26,6 @@ #include "intel-hda.h" #include "intel-hda-defs.h" #include "sysemu/dma.h" -#include "qapi/error.h" /* --------------------------------------------------------------------- */ /* hda bus */ @@ -51,28 +50,25 @@ void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, size_t bus_size, bus->xfer = xfer; } -static void hda_codec_dev_realize(DeviceState *qdev, Error **errp) +static int hda_codec_dev_init(DeviceState *qdev) { - HDACodecBus *bus = HDA_BUS(qdev->parent_bus); - HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev); + HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus); + HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev); HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev); if (dev->cad == -1) { dev->cad = bus->next_cad; } if (dev->cad >= 15) { - error_setg(errp, "HDA audio codec address is full"); - return; + return -1; } bus->next_cad = dev->cad + 1; - if (cdc->init(dev) != 0) { - error_setg(errp, "HDA audio init failed"); - } + return cdc->init(dev); } static int hda_codec_dev_exit(DeviceState *qdev) { - HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev); + HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev); HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev); if (cdc->exit) { @@ -88,7 +84,7 @@ HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad) QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { DeviceState *qdev = kid->child; - cdev = HDA_CODEC_DEVICE(qdev); + cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); if (cdev->cad == cad) { return cdev; } @@ -98,14 +94,14 @@ HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad) void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response) { - HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); + HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); bus->response(dev, solicited, response); } bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, uint8_t *buf, uint32_t len) { - HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); + HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); return bus->xfer(dev, stnr, output, buf, len); } @@ -191,7 +187,7 @@ struct IntelHDAState { /* properties */ uint32_t debug; - OnOffAuto msi; + uint32_t msi; bool old_msi_addr; }; @@ -219,7 +215,10 @@ static void intel_hda_reset(DeviceState *dev); static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase) { - return ((uint64_t)ubase << 32) | lbase; + hwaddr addr; + + addr = ((uint64_t)ubase << 32) | lbase; + return addr; } static void intel_hda_update_int_sts(IntelHDAState *d) @@ -256,7 +255,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d) static void intel_hda_update_irq(IntelHDAState *d) { - bool msi = msi_enabled(&d->pci); + int msi = d->msi && msi_enabled(&d->pci); int level; intel_hda_update_int_sts(d); @@ -338,7 +337,7 @@ static void intel_hda_corb_run(IntelHDAState *d) static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response) { - HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); + HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); IntelHDAState *d = container_of(bus, IntelHDAState, codecs); hwaddr addr; uint32_t wp, ex; @@ -387,7 +386,7 @@ static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t res static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, uint8_t *buf, uint32_t len) { - HDACodecBus *bus = HDA_BUS(dev->qdev.parent_bus); + HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); IntelHDAState *d = container_of(bus, IntelHDAState, codecs); hwaddr addr; uint32_t s, copy, left; @@ -494,7 +493,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn DeviceState *qdev = kid->child; HDACodecDeviceClass *cdc; - cdev = HDA_CODEC_DEVICE(qdev); + cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev); if (cdc->stream) { cdc->stream(cdev, stream, running, output); @@ -1121,7 +1120,7 @@ static void intel_hda_reset(DeviceState *dev) /* reset codecs */ QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) { DeviceState *qdev = kid->child; - cdev = HDA_CODEC_DEVICE(qdev); + cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); device_reset(DEVICE(cdev)); d->state_sts |= (1 << cdev->cad); } @@ -1132,8 +1131,6 @@ static void intel_hda_realize(PCIDevice *pci, Error **errp) { IntelHDAState *d = INTEL_HDA(pci); uint8_t *conf = d->pci.config; - Error *err = NULL; - int ret; d->name = object_get_typename(OBJECT(d)); @@ -1142,27 +1139,12 @@ static void intel_hda_realize(PCIDevice *pci, Error **errp) /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */ conf[0x40] = 0x01; - if (d->msi != ON_OFF_AUTO_OFF) { - ret = msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, - 1, true, false, &err); - /* Any error other than -ENOTSUP(board's MSI support is broken) - * is a programming error */ - assert(!ret || ret == -ENOTSUP); - if (ret && d->msi == ON_OFF_AUTO_ON) { - /* Can't satisfy user's explicit msi=on request, fail */ - error_append_hint(&err, "You have to use msi=auto (default) or " - "msi=off with this machine type.\n"); - error_propagate(errp, err); - return; - } - assert(!err || d->msi == ON_OFF_AUTO_AUTO); - /* With msi=auto, we fall back to MSI off silently */ - error_free(err); - } - memory_region_init_io(&d->mmio, OBJECT(d), &intel_hda_mmio_ops, d, "intel-hda", 0x4000); pci_register_bar(&d->pci, 0, 0, &d->mmio); + if (d->msi) { + msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, 1, true, false); + } hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs), intel_hda_response, intel_hda_xfer); @@ -1252,7 +1234,7 @@ static const VMStateDescription vmstate_intel_hda = { static Property intel_hda_properties[] = { DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0), - DEFINE_PROP_ON_OFF_AUTO("msi", IntelHDAState, msi, ON_OFF_AUTO_AUTO), + DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1), DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false), DEFINE_PROP_END_OF_LIST(), }; @@ -1316,7 +1298,7 @@ static const TypeInfo intel_hda_info_ich9 = { static void hda_codec_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); - k->realize = hda_codec_dev_realize; + k->init = hda_codec_dev_init; k->exit = hda_codec_dev_exit; set_bit(DEVICE_CATEGORY_SOUND, k->categories); k->bus_type = TYPE_HDA_BUS; diff --git a/hw/audio/lm4549.h b/hw/audio/lm4549.h index 74c3ee893..812a7a444 100644 --- a/hw/audio/lm4549.h +++ b/hw/audio/lm4549.h @@ -40,4 +40,4 @@ uint32_t lm4549_read(lm4549_state *s, hwaddr offset); void lm4549_write(lm4549_state *s, hwaddr offset, uint32_t value); uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right); -#endif /* HW_LM4549_H */ +#endif /* #ifndef HW_LM4549_H */ diff --git a/hw/audio/milkymist-ac97.c b/hw/audio/milkymist-ac97.c index bc8db71ae..6a3b53674 100644 --- a/hw/audio/milkymist-ac97.c +++ b/hw/audio/milkymist-ac97.c @@ -18,7 +18,7 @@ * * * Specification available at: - * http://milkymist.walle.cc/socdoc/ac97.pdf + * http://www.milkymist.org/socdoc/ac97.pdf */ #include "qemu/osdep.h" @@ -284,26 +284,16 @@ static int ac97_post_load(void *opaque, int version_id) return 0; } -static void milkymist_ac97_init(Object *obj) +static int milkymist_ac97_init(SysBusDevice *dev) { - MilkymistAC97State *s = MILKYMIST_AC97(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + MilkymistAC97State *s = MILKYMIST_AC97(dev); + struct audsettings as; sysbus_init_irq(dev, &s->crrequest_irq); sysbus_init_irq(dev, &s->crreply_irq); sysbus_init_irq(dev, &s->dmar_irq); sysbus_init_irq(dev, &s->dmaw_irq); - memory_region_init_io(&s->regs_region, obj, &ac97_mmio_ops, s, - "milkymist-ac97", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); -} - -static void milkymist_ac97_realize(DeviceState *dev, Error **errp) -{ - MilkymistAC97State *s = MILKYMIST_AC97(dev); - struct audsettings as; - AUD_register_card("Milkymist AC'97", &s->card); as.freq = 48000; @@ -315,6 +305,12 @@ static void milkymist_ac97_realize(DeviceState *dev, Error **errp) "mm_ac97.in", s, ac97_in_cb, &as); s->voice_out = AUD_open_out(&s->card, s->voice_out, "mm_ac97.out", s, ac97_out_cb, &as); + + memory_region_init_io(&s->regs_region, OBJECT(s), &ac97_mmio_ops, s, + "milkymist-ac97", R_MAX * 4); + sysbus_init_mmio(dev, &s->regs_region); + + return 0; } static const VMStateDescription vmstate_milkymist_ac97 = { @@ -331,8 +327,9 @@ static const VMStateDescription vmstate_milkymist_ac97 = { static void milkymist_ac97_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - dc->realize = milkymist_ac97_realize; + k->init = milkymist_ac97_init; dc->reset = milkymist_ac97_reset; dc->vmsd = &vmstate_milkymist_ac97; } @@ -341,7 +338,6 @@ static const TypeInfo milkymist_ac97_info = { .name = TYPE_MILKYMIST_AC97, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistAC97State), - .instance_init = milkymist_ac97_init, .class_init = milkymist_ac97_class_init, }; diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index 42a6f4885..f9afc8eda 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -31,12 +31,11 @@ #include "qemu/timer.h" #include "hw/timer/i8254.h" #include "hw/audio/pcspk.h" -#include "qapi/error.h" #define PCSPK_BUF_LEN 1792 #define PCSPK_SAMPLE_RATE 32000 #define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1) -#define PCSPK_MIN_COUNT DIV_ROUND_UP(PIT_FREQ, PCSPK_MAX_FREQ) +#define PCSPK_MIN_COUNT ((PIT_FREQ + PCSPK_MAX_FREQ - 1) / PCSPK_MAX_FREQ) #define PC_SPEAKER(obj) OBJECT_CHECK(PCSpkState, (obj), TYPE_PC_SPEAKER) @@ -170,11 +169,6 @@ static void pcspk_initfn(Object *obj) PCSpkState *s = PC_SPEAKER(obj); memory_region_init_io(&s->ioport, OBJECT(s), &pcspk_io_ops, s, "pcspk", 1); - - object_property_add_link(obj, "pit", TYPE_PIT_COMMON, - (Object **)&s->pit, - qdev_prop_allow_set_link_before_realize, - 0, &error_abort); } static void pcspk_realizefn(DeviceState *dev, Error **errp) @@ -189,6 +183,7 @@ static void pcspk_realizefn(DeviceState *dev, Error **errp) static Property pcspk_properties[] = { DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1), + DEFINE_PROP_PTR("pit", PCSpkState, pit), DEFINE_PROP_END_OF_LIST(), }; @@ -199,7 +194,7 @@ static void pcspk_class_initfn(ObjectClass *klass, void *data) dc->realize = pcspk_realizefn; set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->props = pcspk_properties; - /* Reason: realize sets global pcspk_state */ + /* Reason: pointer property "pit", realize sets global pcspk_state */ dc->cannot_instantiate_with_device_add_yet = true; } diff --git a/hw/audio/pl041.c b/hw/audio/pl041.c index 6e9c10401..4717bc9b9 100644 --- a/hw/audio/pl041.c +++ b/hw/audio/pl041.c @@ -22,7 +22,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" -#include "qemu/log.h" #include "pl041.h" #include "lm4549.h" diff --git a/hw/audio/pl041.h b/hw/audio/pl041.h index 515db4756..427ab6d6f 100644 --- a/hw/audio/pl041.h +++ b/hw/audio/pl041.h @@ -132,4 +132,4 @@ enum { #define RXTOFEC3 (1 << 11) #define RXTOFEC4 (1 << 12) -#endif /* HW_PL041_H */ +#endif /* #ifndef HW_PL041_H */ diff --git a/hw/audio/trace-events b/hw/audio/trace-events deleted file mode 100644 index 3210386e8..000000000 --- a/hw/audio/trace-events +++ /dev/null @@ -1,19 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/audio/cs4231.c -cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x" -cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x" -cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x" -cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x" - -# hw/audio/milkymist-ac97.c -milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request" -milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply" -milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write" -milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read" -milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u" -milkymist_ac97_in_cb_transferred(int transferred) "transferred %d" -milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u" -milkymist_ac97_out_cb_transferred(int transferred) "transferred %d" diff --git a/hw/block/block.c b/hw/block/block.c index 8dc9d84a3..97a59d4fa 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -51,34 +51,6 @@ void blkconf_blocksizes(BlockConf *conf) } } -void blkconf_apply_backend_options(BlockConf *conf) -{ - BlockBackend *blk = conf->blk; - BlockdevOnError rerror, werror; - bool wce; - - switch (conf->wce) { - case ON_OFF_AUTO_ON: wce = true; break; - case ON_OFF_AUTO_OFF: wce = false; break; - case ON_OFF_AUTO_AUTO: wce = blk_enable_write_cache(blk); break; - default: - abort(); - } - - rerror = conf->rerror; - if (rerror == BLOCKDEV_ON_ERROR_AUTO) { - rerror = blk_get_on_error(blk, true); - } - - werror = conf->werror; - if (werror == BLOCKDEV_ON_ERROR_AUTO) { - werror = blk_get_on_error(blk, false); - } - - blk_set_enable_write_cache(blk, wce); - blk_set_on_error(blk, rerror, werror); -} - void blkconf_geometry(BlockConf *conf, int *ptrans, unsigned cyls_max, unsigned heads_max, unsigned secs_max, Error **errp) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 704a76360..3cb97c9a2 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -31,9 +31,13 @@ struct VirtIOBlockDataPlane { bool stopping; VirtIOBlkConf *conf; + VirtIODevice *vdev; + VirtQueue *vq; /* virtqueue vring */ + EventNotifier *guest_notifier; /* irq */ QEMUBH *bh; /* bh for guest notification */ - unsigned long *batch_notify_vqs; + + Notifier insert_notifier, remove_notifier; /* Note that these EventNotifiers are assigned by value. This is * fine as long as you do not call event_notifier_cleanup on them @@ -42,41 +46,76 @@ struct VirtIOBlockDataPlane { */ IOThread *iothread; AioContext *ctx; + + /* Operation blocker on BDS */ + Error *blocker; }; /* Raise an interrupt to signal guest, if necessary */ -void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s, VirtQueue *vq) +void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s) { - set_bit(virtio_get_queue_index(vq), s->batch_notify_vqs); qemu_bh_schedule(s->bh); } static void notify_guest_bh(void *opaque) { VirtIOBlockDataPlane *s = opaque; - unsigned nvqs = s->conf->num_queues; - unsigned long bitmap[BITS_TO_LONGS(nvqs)]; - unsigned j; - - memcpy(bitmap, s->batch_notify_vqs, sizeof(bitmap)); - memset(s->batch_notify_vqs, 0, sizeof(bitmap)); - for (j = 0; j < nvqs; j += BITS_PER_LONG) { - unsigned long bits = bitmap[j]; + if (!virtio_should_notify(s->vdev, s->vq)) { + return; + } - while (bits != 0) { - unsigned i = j + ctzl(bits); - VirtQueue *vq = virtio_get_queue(s->vdev, i); + event_notifier_set(s->guest_notifier); +} - if (virtio_should_notify(s->vdev, vq)) { - event_notifier_set(virtio_queue_get_guest_notifier(vq)); - } +static void data_plane_set_up_op_blockers(VirtIOBlockDataPlane *s) +{ + assert(!s->blocker); + error_setg(&s->blocker, "block device is in use by data plane"); + blk_op_block_all(s->conf->conf.blk, s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, + s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, + s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE, + s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_MIRROR_SOURCE, s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker); + blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker); +} - bits &= bits - 1; /* clear right-most bit */ - } +static void data_plane_remove_op_blockers(VirtIOBlockDataPlane *s) +{ + if (s->blocker) { + blk_op_unblock_all(s->conf->conf.blk, s->blocker); + error_free(s->blocker); + s->blocker = NULL; } } +static void data_plane_blk_insert_notifier(Notifier *n, void *data) +{ + VirtIOBlockDataPlane *s = container_of(n, VirtIOBlockDataPlane, + insert_notifier); + assert(s->conf->conf.blk == data); + data_plane_set_up_op_blockers(s); +} + +static void data_plane_blk_remove_notifier(Notifier *n, void *data) +{ + VirtIOBlockDataPlane *s = container_of(n, VirtIOBlockDataPlane, + remove_notifier); + assert(s->conf->conf.blk == data); + data_plane_remove_op_blockers(s); +} + /* Context: QEMU global mutex held */ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, VirtIOBlockDataPlane **dataplane, @@ -93,7 +132,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, } /* Don't try if transport does not support notifiers. */ - if (!k->set_guest_notifiers || !k->ioeventfd_started) { + if (!k->set_guest_notifiers || !k->set_host_notifier) { error_setg(errp, "device is incompatible with dataplane " "(transport does not support notifiers)"); @@ -112,11 +151,19 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, s->vdev = vdev; s->conf = conf; - s->iothread = conf->iothread; - object_ref(OBJECT(s->iothread)); + if (conf->iothread) { + s->iothread = conf->iothread; + object_ref(OBJECT(s->iothread)); + } s->ctx = iothread_get_aio_context(s->iothread); s->bh = aio_bh_new(s->ctx, notify_guest_bh, s); - s->batch_notify_vqs = bitmap_new(conf->num_queues); + + s->insert_notifier.notify = data_plane_blk_insert_notifier; + s->remove_notifier.notify = data_plane_blk_remove_notifier; + blk_add_insert_bs_notifier(conf->conf.blk, &s->insert_notifier); + blk_add_remove_bs_notifier(conf->conf.blk, &s->remove_notifier); + + data_plane_set_up_op_blockers(s); *dataplane = s; } @@ -129,7 +176,9 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) } virtio_blk_data_plane_stop(s); - g_free(s->batch_notify_vqs); + data_plane_remove_op_blockers(s); + notifier_remove(&s->insert_notifier); + notifier_remove(&s->remove_notifier); qemu_bh_delete(s->bh); object_unref(OBJECT(s->iothread)); g_free(s); @@ -152,8 +201,6 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); - unsigned i; - unsigned nvqs = s->conf->num_queues; int r; if (vblk->dataplane_started || s->starting) { @@ -161,25 +208,22 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) } s->starting = true; + s->vq = virtio_get_queue(s->vdev, 0); /* Set up guest notifier (irq) */ - r = k->set_guest_notifiers(qbus->parent, nvqs, true); + r = k->set_guest_notifiers(qbus->parent, 1, true); if (r != 0) { fprintf(stderr, "virtio-blk failed to set guest notifier (%d), " "ensure -enable-kvm is set\n", r); goto fail_guest_notifiers; } + s->guest_notifier = virtio_queue_get_guest_notifier(s->vq); /* Set up virtqueue notify */ - for (i = 0; i < nvqs; i++) { - r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, true); - if (r != 0) { - fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r); - while (i--) { - virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); - } - goto fail_guest_notifiers; - } + r = k->set_host_notifier(qbus->parent, 0, true); + if (r != 0) { + fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r); + goto fail_host_notifier; } s->starting = false; @@ -189,23 +233,17 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) blk_set_aio_context(s->conf->conf.blk, s->ctx); /* Kick right away to begin processing requests already in vring */ - for (i = 0; i < nvqs; i++) { - VirtQueue *vq = virtio_get_queue(s->vdev, i); - - event_notifier_set(virtio_queue_get_host_notifier(vq)); - } + event_notifier_set(virtio_queue_get_host_notifier(s->vq)); /* Get this show started by hooking up our callbacks */ aio_context_acquire(s->ctx); - for (i = 0; i < nvqs; i++) { - VirtQueue *vq = virtio_get_queue(s->vdev, i); - - virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, - virtio_blk_data_plane_handle_output); - } + virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, + virtio_blk_data_plane_handle_output); aio_context_release(s->ctx); return; + fail_host_notifier: + k->set_guest_notifiers(qbus->parent, 1, false); fail_guest_notifiers: vblk->dataplane_disabled = true; s->starting = false; @@ -218,8 +256,6 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); - unsigned i; - unsigned nvqs = s->conf->num_queues; if (!vblk->dataplane_started || s->stopping) { return; @@ -237,23 +273,17 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) aio_context_acquire(s->ctx); /* Stop notifications for new requests from guest */ - for (i = 0; i < nvqs; i++) { - VirtQueue *vq = virtio_get_queue(s->vdev, i); - - virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, NULL); - } + virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, NULL); /* Drain and switch bs back to the QEMU main loop */ blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context()); aio_context_release(s->ctx); - for (i = 0; i < nvqs; i++) { - virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); - } + k->set_host_notifier(qbus->parent, 0, false); /* Clean up guest notifier (irq) */ - k->set_guest_notifiers(qbus->parent, nvqs, false); + k->set_guest_notifiers(qbus->parent, 1, false); vblk->dataplane_started = false; s->stopping = false; diff --git a/hw/block/dataplane/virtio-blk.h b/hw/block/dataplane/virtio-blk.h index b1f0b95b3..0714c11a2 100644 --- a/hw/block/dataplane/virtio-blk.h +++ b/hw/block/dataplane/virtio-blk.h @@ -26,6 +26,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s); -void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s, VirtQueue *vq); +void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s); #endif /* HW_DATAPLANE_VIRTIO_BLK_H */ diff --git a/hw/block/fdc.c b/hw/block/fdc.c index f73af7db4..372227569 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -223,13 +223,6 @@ static int fd_sector(FDrive *drv) NUM_SIDES(drv)); } -/* Returns current position, in bytes, for given drive */ -static int fd_offset(FDrive *drv) -{ - g_assert(fd_sector(drv) < INT_MAX >> BDRV_SECTOR_BITS); - return fd_sector(drv) << BDRV_SECTOR_BITS; -} - /* Seek to a new position: * returns 0 if already on right track * returns 1 if track changed @@ -1636,8 +1629,8 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, if (fdctrl->data_dir != FD_DIR_WRITE || len < FD_SECTOR_LEN || rel_pos != 0) { /* READ & SCAN commands and realign to a sector for WRITE */ - if (blk_pread(cur_drv->blk, fd_offset(cur_drv), - fdctrl->fifo, BDRV_SECTOR_SIZE) < 0) { + if (blk_read(cur_drv->blk, fd_sector(cur_drv), + fdctrl->fifo, 1) < 0) { FLOPPY_DPRINTF("Floppy: error getting sector %d\n", fd_sector(cur_drv)); /* Sure, image size is too small... */ @@ -1664,8 +1657,8 @@ static int fdctrl_transfer_handler (void *opaque, int nchan, k->read_memory(fdctrl->dma, nchan, fdctrl->fifo + rel_pos, fdctrl->data_pos, len); - if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv), - fdctrl->fifo, BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_write(cur_drv->blk, fd_sector(cur_drv), + fdctrl->fifo, 1) < 0) { FLOPPY_DPRINTF("error writing sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); @@ -1748,8 +1741,7 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl) fd_sector(cur_drv)); return 0; } - if (blk_pread(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo, - BDRV_SECTOR_SIZE) + if (blk_read(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { FLOPPY_DPRINTF("error getting sector %d\n", fd_sector(cur_drv)); @@ -1828,8 +1820,7 @@ static void fdctrl_format_sector(FDCtrl *fdctrl) } memset(fdctrl->fifo, 0, FD_SECTOR_LEN); if (cur_drv->blk == NULL || - blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo, - BDRV_SECTOR_SIZE, 0) < 0) { + blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv)); fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00); } else { @@ -2252,8 +2243,8 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value) if (pos == FD_SECTOR_LEN - 1 || fdctrl->data_pos == fdctrl->data_len) { cur_drv = get_cur_drv(fdctrl); - if (blk_pwrite(cur_drv->blk, fd_offset(cur_drv), fdctrl->fifo, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1) + < 0) { FLOPPY_DPRINTF("error writing sector %d\n", fd_sector(cur_drv)); break; diff --git a/hw/block/hd-geometry.c b/hw/block/hd-geometry.c index 57ad5012a..6d02192db 100644 --- a/hw/block/hd-geometry.c +++ b/hw/block/hd-geometry.c @@ -32,7 +32,6 @@ #include "qemu/osdep.h" #include "sysemu/block-backend.h" -#include "qemu/bswap.h" #include "hw/block/block.h" #include "trace.h" @@ -67,7 +66,7 @@ static int guess_disk_lchs(BlockBackend *blk, * but also in async I/O mode. So the I/O throttling function has to * be disabled temporarily here, not permanently. */ - if (blk_pread_unthrottled(blk, 0, buf, BDRV_SECTOR_SIZE) < 0) { + if (blk_read_unthrottled(blk, 0, buf, 1) < 0) { return -1; } /* test msdos magic */ diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 9828ee61d..906b71257 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -27,8 +27,6 @@ #include "sysemu/blockdev.h" #include "hw/ssi/ssi.h" #include "qemu/bitops.h" -#include "qemu/log.h" -#include "qapi/error.h" #ifndef M25P80_ERR_DEBUG #define M25P80_ERR_DEBUG 0 @@ -54,17 +52,12 @@ /* 16 MiB max in 3 byte address mode */ #define MAX_3BYTES_SIZE 0x1000000 -#define SPI_NOR_MAX_ID_LEN 6 - typedef struct FlashPartInfo { const char *part_name; - /* - * This array stores the ID bytes. - * The first three bytes are the JEDIC ID. - * JEDEC ID zero means "no ID" (mostly older chips). - */ - uint8_t id[SPI_NOR_MAX_ID_LEN]; - uint8_t id_len; + /* jedec code. (jedec >> 16) & 0xff is the 1st byte, >> 8 the 2nd etc */ + uint32_t jedec; + /* extended jedec code */ + uint16_t ext_jedec; /* there is confusion between manufacturers as to what a sector is. In this * device model, a "sector" is the size that is erased by the ERASE_SECTOR * command (opcode 0xd8). @@ -76,33 +69,11 @@ typedef struct FlashPartInfo { } FlashPartInfo; /* adapted from linux */ -/* Used when the "_ext_id" is two bytes at most */ -#define INFO(_part_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags)\ - .part_name = _part_name,\ - .id = {\ - ((_jedec_id) >> 16) & 0xff,\ - ((_jedec_id) >> 8) & 0xff,\ - (_jedec_id) & 0xff,\ - ((_ext_id) >> 8) & 0xff,\ - (_ext_id) & 0xff,\ - },\ - .id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))),\ - .sector_size = (_sector_size),\ - .n_sectors = (_n_sectors),\ - .page_size = 256,\ - .flags = (_flags), - -#define INFO6(_part_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags)\ - .part_name = _part_name,\ - .id = {\ - ((_jedec_id) >> 16) & 0xff,\ - ((_jedec_id) >> 8) & 0xff,\ - (_jedec_id) & 0xff,\ - ((_ext_id) >> 16) & 0xff,\ - ((_ext_id) >> 8) & 0xff,\ - (_ext_id) & 0xff,\ - },\ - .id_len = 6,\ + +#define INFO(_part_name, _jedec, _ext_jedec, _sector_size, _n_sectors, _flags)\ + .part_name = (_part_name),\ + .jedec = (_jedec),\ + .ext_jedec = (_ext_jedec),\ .sector_size = (_sector_size),\ .n_sectors = (_n_sectors),\ .page_size = 256,\ @@ -130,27 +101,12 @@ typedef struct FlashPartInfo { #define EVCFG_QUAD_IO_ENABLED (1 << 7) #define NVCFG_4BYTE_ADDR_MASK (1 << 0) #define NVCFG_LOWER_SEGMENT_MASK (1 << 1) +#define CFG_UPPER_128MB_SEG_ENABLED 0x3 /* Numonyx (Micron) Flag Status Register macros */ #define FSR_4BYTE_ADDR_MODE_ENABLED 0x1 #define FSR_FLASH_READY (1 << 7) -/* Spansion configuration registers macros. */ -#define SPANSION_QUAD_CFG_POS 0 -#define SPANSION_QUAD_CFG_LEN 1 -#define SPANSION_DUMMY_CLK_POS 0 -#define SPANSION_DUMMY_CLK_LEN 4 -#define SPANSION_ADDR_LEN_POS 7 -#define SPANSION_ADDR_LEN_LEN 1 - -/* - * Spansion read mode command length in bytes, - * the mode is currently not supported. -*/ - -#define SPANSION_CONTINUOUS_READ_MODE_CMD_LEN 1 -#define WINBOND_CONTINUOUS_READ_MODE_CMD_LEN 1 - static const FlashPartInfo known_devices[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ { INFO("at25fs010", 0x1f6601, 0, 32 << 10, 4, ER_4K) }, @@ -201,8 +157,6 @@ static const FlashPartInfo known_devices[] = { { INFO("mx25l12855e", 0xc22618, 0, 64 << 10, 256, 0) }, { INFO("mx25l25635e", 0xc22019, 0, 64 << 10, 512, 0) }, { INFO("mx25l25655e", 0xc22619, 0, 64 << 10, 512, 0) }, - { INFO("mx66u51235f", 0xc2253a, 0, 64 << 10, 1024, ER_4K | ER_32K) }, - { INFO("mx66u1g45g", 0xc2253b, 0, 64 << 10, 2048, ER_4K | ER_32K) }, /* Micron */ { INFO("n25q032a11", 0x20bb16, 0, 64 << 10, 64, ER_4K) }, @@ -213,11 +167,6 @@ static const FlashPartInfo known_devices[] = { { INFO("n25q128a13", 0x20ba18, 0, 64 << 10, 256, ER_4K) }, { INFO("n25q256a11", 0x20bb19, 0, 64 << 10, 512, ER_4K) }, { INFO("n25q256a13", 0x20ba19, 0, 64 << 10, 512, ER_4K) }, - { INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) }, - { INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) }, - { INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) }, - { INFO("mt25ql01g", 0x20ba21, 0, 64 << 10, 2048, ER_4K) }, - { INFO("mt25qu01g", 0x20bb21, 0, 64 << 10, 2048, ER_4K) }, /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). @@ -226,8 +175,8 @@ static const FlashPartInfo known_devices[] = { { INFO("s25sl064p", 0x010216, 0x4d00, 64 << 10, 128, ER_4K) }, { INFO("s25fl256s0", 0x010219, 0x4d00, 256 << 10, 128, 0) }, { INFO("s25fl256s1", 0x010219, 0x4d01, 64 << 10, 512, 0) }, - { INFO6("s25fl512s", 0x010220, 0x4d0080, 256 << 10, 256, 0) }, - { INFO6("s70fl01gs", 0x010221, 0x4d0080, 256 << 10, 512, 0) }, + { INFO("s25fl512s", 0x010220, 0x4d00, 256 << 10, 256, 0) }, + { INFO("s70fl01gs", 0x010221, 0x4d00, 256 << 10, 256, 0) }, { INFO("s25sl12800", 0x012018, 0x0300, 256 << 10, 64, 0) }, { INFO("s25sl12801", 0x012018, 0x0301, 64 << 10, 256, 0) }, { INFO("s25fl129p0", 0x012018, 0x4d00, 256 << 10, 64, 0) }, @@ -240,10 +189,6 @@ static const FlashPartInfo known_devices[] = { { INFO("s25fl016k", 0xef4015, 0, 64 << 10, 32, ER_4K | ER_32K) }, { INFO("s25fl064k", 0xef4017, 0, 64 << 10, 128, ER_4K | ER_32K) }, - /* Spansion -- boot sectors support */ - { INFO6("s25fs512s", 0x010220, 0x4d0081, 256 << 10, 256, 0) }, - { INFO6("s70fs01gs", 0x010221, 0x4d0081, 256 << 10, 512, 0) }, - /* SST -- large erase sizes are "overlays", "sectors" are 4<< 10 */ { INFO("sst25vf040b", 0xbf258d, 0, 64 << 10, 8, ER_4K) }, { INFO("sst25vf080b", 0xbf258e, 0, 64 << 10, 16, ER_4K) }, @@ -294,6 +239,10 @@ static const FlashPartInfo known_devices[] = { { INFO("w25q80", 0xef5014, 0, 64 << 10, 16, ER_4K) }, { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) }, { INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K) }, + + { INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) }, + { INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) }, + { INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) }, }; typedef enum { @@ -305,7 +254,6 @@ typedef enum { JEDEC_READ = 0x9f, BULK_ERASE = 0xc7, READ_FSR = 0x70, - RDCR = 0x15, READ = 0x03, READ4 = 0x13, @@ -322,14 +270,12 @@ typedef enum { PP = 0x02, PP4 = 0x12, - PP4_4 = 0x3e, DPP = 0xa2, QPP = 0x32, ERASE_4K = 0x20, ERASE4_4K = 0x21, ERASE_32K = 0x52, - ERASE4_32K = 0x5c, ERASE_SECTOR = 0xd8, ERASE4_SECTOR = 0xdc, @@ -342,13 +288,6 @@ typedef enum { RESET_ENABLE = 0x66, RESET_MEMORY = 0x99, - /* - * Micron: 0x35 - enable QPI - * Spansion: 0x35 - read control register - */ - RDCR_EQIO = 0x35, - RSTQIO = 0xf5, - RNVCR = 0xB5, WNVCR = 0xB1, @@ -364,18 +303,9 @@ typedef enum { STATE_PAGE_PROGRAM, STATE_READ, STATE_COLLECTING_DATA, - STATE_COLLECTING_VAR_LEN_DATA, STATE_READING_DATA, } CMDState; -typedef enum { - MAN_SPANSION, - MAN_MACRONIX, - MAN_NUMONYX, - MAN_WINBOND, - MAN_GENERIC, -} Manufacturer; - typedef struct Flash { SSISlave parent_obj; @@ -391,24 +321,13 @@ typedef struct Flash { uint32_t pos; uint8_t needed_bytes; uint8_t cmd_in_progress; - uint32_t cur_addr; + uint64_t cur_addr; uint32_t nonvolatile_cfg; - /* Configuration register for Macronix */ uint32_t volatile_cfg; uint32_t enh_volatile_cfg; - /* Spansion cfg registers. */ - uint8_t spansion_cr1nv; - uint8_t spansion_cr2nv; - uint8_t spansion_cr3nv; - uint8_t spansion_cr4nv; - uint8_t spansion_cr1v; - uint8_t spansion_cr2v; - uint8_t spansion_cr3v; - uint8_t spansion_cr4v; bool write_enable; bool four_bytes_address_mode; bool reset_enable; - bool quad_enable; uint8_t ear; int64_t dirty_page; @@ -430,29 +349,8 @@ typedef struct M25P80Class { #define M25P80_GET_CLASS(obj) \ OBJECT_GET_CLASS(M25P80Class, (obj), TYPE_M25P80) -static inline Manufacturer get_man(Flash *s) -{ - switch (s->pi->id[0]) { - case 0x20: - return MAN_NUMONYX; - case 0xEF: - return MAN_WINBOND; - case 0x01: - return MAN_SPANSION; - case 0xC2: - return MAN_MACRONIX; - default: - return MAN_GENERIC; - } -} - static void blk_sync_complete(void *opaque, int ret) { - QEMUIOVector *iov = opaque; - - qemu_iovec_destroy(iov); - g_free(iov); - /* do nothing. Masters do not directly interact with the backing store, * only the working copy so no mutexing required. */ @@ -460,33 +358,39 @@ static void blk_sync_complete(void *opaque, int ret) static void flash_sync_page(Flash *s, int page) { - QEMUIOVector *iov; + int blk_sector, nb_sectors; + QEMUIOVector iov; if (!s->blk || blk_is_read_only(s->blk)) { return; } - iov = g_new(QEMUIOVector, 1); - qemu_iovec_init(iov, 1); - qemu_iovec_add(iov, s->storage + page * s->pi->page_size, - s->pi->page_size); - blk_aio_pwritev(s->blk, page * s->pi->page_size, iov, 0, - blk_sync_complete, iov); + blk_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE; + nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE); + qemu_iovec_init(&iov, 1); + qemu_iovec_add(&iov, s->storage + blk_sector * BDRV_SECTOR_SIZE, + nb_sectors * BDRV_SECTOR_SIZE); + blk_aio_writev(s->blk, blk_sector, &iov, nb_sectors, blk_sync_complete, + NULL); } static inline void flash_sync_area(Flash *s, int64_t off, int64_t len) { - QEMUIOVector *iov; + int64_t start, end, nb_sectors; + QEMUIOVector iov; if (!s->blk || blk_is_read_only(s->blk)) { return; } assert(!(len % BDRV_SECTOR_SIZE)); - iov = g_new(QEMUIOVector, 1); - qemu_iovec_init(iov, 1); - qemu_iovec_add(iov, s->storage + off, len); - blk_aio_pwritev(s->blk, off, iov, 0, blk_sync_complete, iov); + start = off / BDRV_SECTOR_SIZE; + end = (off + len) / BDRV_SECTOR_SIZE; + nb_sectors = end - start; + qemu_iovec_init(&iov, 1); + qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE), + nb_sectors * BDRV_SECTOR_SIZE); + blk_aio_writev(s->blk, start, &iov, nb_sectors, blk_sync_complete, NULL); } static void flash_erase(Flash *s, int offset, FlashCMD cmd) @@ -501,7 +405,6 @@ static void flash_erase(Flash *s, int offset, FlashCMD cmd) capa_to_assert = ER_4K; break; case ERASE_32K: - case ERASE4_32K: len = 32 << 10; capa_to_assert = ER_32K; break; @@ -539,9 +442,9 @@ static inline void flash_sync_dirty(Flash *s, int64_t newpage) } static inline -void flash_write8(Flash *s, uint32_t addr, uint8_t data) +void flash_write8(Flash *s, uint64_t addr, uint8_t data) { - uint32_t page = addr / s->pi->page_size; + int64_t page = addr / s->pi->page_size; uint8_t prev = s->storage[s->cur_addr]; if (!s->write_enable) { @@ -549,7 +452,7 @@ void flash_write8(Flash *s, uint32_t addr, uint8_t data) } if ((prev ^ data) & data) { - DB_PRINT_L(1, "programming zero to one! addr=%" PRIx32 " %" PRIx8 + DB_PRINT_L(1, "programming zero to one! addr=%" PRIx64 " %" PRIx8 " -> %" PRIx8 "\n", addr, prev, data); } @@ -572,11 +475,9 @@ static inline int get_addr_length(Flash *s) switch (s->cmd_in_progress) { case PP4: - case PP4_4: case READ4: case QIOR4: case ERASE4_4K: - case ERASE4_32K: case ERASE4_SECTOR: case FAST_READ4: case DOR4: @@ -590,16 +491,18 @@ static inline int get_addr_length(Flash *s) static void complete_collecting_data(Flash *s) { - int i, n; + int i; + + s->cur_addr = 0; - n = get_addr_length(s); - s->cur_addr = (n == 3 ? s->ear : 0); - for (i = 0; i < n; ++i) { + for (i = 0; i < get_addr_length(s); ++i) { s->cur_addr <<= 8; s->cur_addr |= s->data[i]; } - s->cur_addr &= s->size - 1; + if (get_addr_length(s) == 3) { + s->cur_addr += (s->ear & 0x3) * MAX_3BYTES_SIZE; + } s->state = STATE_IDLE; @@ -608,7 +511,6 @@ static void complete_collecting_data(Flash *s) case QPP: case PP: case PP4: - case PP4_4: s->state = STATE_PAGE_PROGRAM; break; case READ: @@ -628,25 +530,11 @@ static void complete_collecting_data(Flash *s) case ERASE_4K: case ERASE4_4K: case ERASE_32K: - case ERASE4_32K: case ERASE_SECTOR: case ERASE4_SECTOR: flash_erase(s, s->cur_addr, s->cmd_in_progress); break; case WRSR: - switch (get_man(s)) { - case MAN_SPANSION: - s->quad_enable = !!(s->data[1] & 0x02); - break; - case MAN_MACRONIX: - s->quad_enable = extract32(s->data[0], 6, 1); - if (s->len > 1) { - s->four_bytes_address_mode = extract32(s->data[1], 5, 1); - } - break; - default: - break; - } if (s->write_enable) { s->write_enable = false; } @@ -680,10 +568,8 @@ static void reset_memory(Flash *s) s->state = STATE_IDLE; s->write_enable = false; s->reset_enable = false; - s->quad_enable = false; - switch (get_man(s)) { - case MAN_NUMONYX: + if (((s->pi->jedec >> 16) & 0xFF) == JEDEC_NUMONYX) { s->volatile_cfg = 0; s->volatile_cfg |= VCFG_DUMMY; s->volatile_cfg |= VCFG_WRAP_SEQUENTIAL; @@ -713,148 +599,16 @@ static void reset_memory(Flash *s) s->four_bytes_address_mode = true; } if (!(s->nonvolatile_cfg & NVCFG_LOWER_SEGMENT_MASK)) { - s->ear = s->size / MAX_3BYTES_SIZE - 1; + s->ear = CFG_UPPER_128MB_SEG_ENABLED; } - break; - case MAN_MACRONIX: - s->volatile_cfg = 0x7; - break; - case MAN_SPANSION: - s->spansion_cr1v = s->spansion_cr1nv; - s->spansion_cr2v = s->spansion_cr2nv; - s->spansion_cr3v = s->spansion_cr3nv; - s->spansion_cr4v = s->spansion_cr4nv; - s->quad_enable = extract32(s->spansion_cr1v, - SPANSION_QUAD_CFG_POS, - SPANSION_QUAD_CFG_LEN - ); - s->four_bytes_address_mode = extract32(s->spansion_cr2v, - SPANSION_ADDR_LEN_POS, - SPANSION_ADDR_LEN_LEN - ); - break; - default: - break; } DB_PRINT_L(0, "Reset done.\n"); } -static void decode_fast_read_cmd(Flash *s) -{ - s->needed_bytes = get_addr_length(s); - switch (get_man(s)) { - /* Dummy cycles - modeled with bytes writes instead of bits */ - case MAN_WINBOND: - s->needed_bytes += 8; - break; - case MAN_NUMONYX: - s->needed_bytes += extract32(s->volatile_cfg, 4, 4); - break; - case MAN_MACRONIX: - if (extract32(s->volatile_cfg, 6, 2) == 1) { - s->needed_bytes += 6; - } else { - s->needed_bytes += 8; - } - break; - case MAN_SPANSION: - s->needed_bytes += extract32(s->spansion_cr2v, - SPANSION_DUMMY_CLK_POS, - SPANSION_DUMMY_CLK_LEN - ); - break; - default: - break; - } - s->pos = 0; - s->len = 0; - s->state = STATE_COLLECTING_DATA; -} - -static void decode_dio_read_cmd(Flash *s) -{ - s->needed_bytes = get_addr_length(s); - /* Dummy cycles modeled with bytes writes instead of bits */ - switch (get_man(s)) { - case MAN_WINBOND: - s->needed_bytes += WINBOND_CONTINUOUS_READ_MODE_CMD_LEN; - break; - case MAN_SPANSION: - s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN; - s->needed_bytes += extract32(s->spansion_cr2v, - SPANSION_DUMMY_CLK_POS, - SPANSION_DUMMY_CLK_LEN - ); - break; - case MAN_NUMONYX: - s->needed_bytes += extract32(s->volatile_cfg, 4, 4); - break; - case MAN_MACRONIX: - switch (extract32(s->volatile_cfg, 6, 2)) { - case 1: - s->needed_bytes += 6; - break; - case 2: - s->needed_bytes += 8; - break; - default: - s->needed_bytes += 4; - break; - } - break; - default: - break; - } - s->pos = 0; - s->len = 0; - s->state = STATE_COLLECTING_DATA; -} - -static void decode_qio_read_cmd(Flash *s) -{ - s->needed_bytes = get_addr_length(s); - /* Dummy cycles modeled with bytes writes instead of bits */ - switch (get_man(s)) { - case MAN_WINBOND: - s->needed_bytes += WINBOND_CONTINUOUS_READ_MODE_CMD_LEN; - s->needed_bytes += 4; - break; - case MAN_SPANSION: - s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN; - s->needed_bytes += extract32(s->spansion_cr2v, - SPANSION_DUMMY_CLK_POS, - SPANSION_DUMMY_CLK_LEN - ); - break; - case MAN_NUMONYX: - s->needed_bytes += extract32(s->volatile_cfg, 4, 4); - break; - case MAN_MACRONIX: - switch (extract32(s->volatile_cfg, 6, 2)) { - case 1: - s->needed_bytes += 4; - break; - case 2: - s->needed_bytes += 8; - break; - default: - s->needed_bytes += 6; - break; - } - break; - default: - break; - } - s->pos = 0; - s->len = 0; - s->state = STATE_COLLECTING_DATA; -} - static void decode_new_cmd(Flash *s, uint32_t value) { s->cmd_in_progress = value; - int i; DB_PRINT_L(0, "decoded new command:%x\n", value); if (value != RESET_MEMORY) { @@ -866,7 +620,6 @@ static void decode_new_cmd(Flash *s, uint32_t value) case ERASE_4K: case ERASE4_4K: case ERASE_32K: - case ERASE4_32K: case ERASE_SECTOR: case ERASE4_SECTOR: case READ: @@ -875,7 +628,6 @@ static void decode_new_cmd(Flash *s, uint32_t value) case QPP: case PP: case PP4: - case PP4_4: s->needed_bytes = get_addr_length(s); s->pos = 0; s->len = 0; @@ -888,35 +640,56 @@ static void decode_new_cmd(Flash *s, uint32_t value) case DOR4: case QOR: case QOR4: - decode_fast_read_cmd(s); + s->needed_bytes = get_addr_length(s); + if (((s->pi->jedec >> 16) & 0xFF) == JEDEC_NUMONYX) { + /* Dummy cycles modeled with bytes writes instead of bits */ + s->needed_bytes += extract32(s->volatile_cfg, 4, 4); + } + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; break; case DIOR: case DIOR4: - decode_dio_read_cmd(s); + switch ((s->pi->jedec >> 16) & 0xFF) { + case JEDEC_WINBOND: + case JEDEC_SPANSION: + s->needed_bytes = 4; + break; + default: + s->needed_bytes = get_addr_length(s); + /* Dummy cycles modeled with bytes writes instead of bits */ + s->needed_bytes += extract32(s->volatile_cfg, 4, 4); + } + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; break; case QIOR: case QIOR4: - decode_qio_read_cmd(s); + switch ((s->pi->jedec >> 16) & 0xFF) { + case JEDEC_WINBOND: + case JEDEC_SPANSION: + s->needed_bytes = 6; + break; + default: + s->needed_bytes = get_addr_length(s); + /* Dummy cycles modeled with bytes writes instead of bits */ + s->needed_bytes += extract32(s->volatile_cfg, 4, 4); + } + s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; break; case WRSR: if (s->write_enable) { - switch (get_man(s)) { - case MAN_SPANSION: - s->needed_bytes = 2; - s->state = STATE_COLLECTING_DATA; - break; - case MAN_MACRONIX: - s->needed_bytes = 2; - s->state = STATE_COLLECTING_VAR_LEN_DATA; - break; - default: - s->needed_bytes = 1; - s->state = STATE_COLLECTING_DATA; - } + s->needed_bytes = 1; s->pos = 0; + s->len = 0; + s->state = STATE_COLLECTING_DATA; } break; @@ -929,9 +702,6 @@ static void decode_new_cmd(Flash *s, uint32_t value) case RDSR: s->data[0] = (!!s->write_enable) << 1; - if (get_man(s) == MAN_MACRONIX) { - s->data[0] |= (!!s->quad_enable) << 6; - } s->pos = 0; s->len = 1; s->state = STATE_READING_DATA; @@ -949,20 +719,17 @@ static void decode_new_cmd(Flash *s, uint32_t value) case JEDEC_READ: DB_PRINT_L(0, "populated jedec code\n"); - for (i = 0; i < s->pi->id_len; i++) { - s->data[i] = s->pi->id[i]; + s->data[0] = (s->pi->jedec >> 16) & 0xff; + s->data[1] = (s->pi->jedec >> 8) & 0xff; + s->data[2] = s->pi->jedec & 0xff; + if (s->pi->ext_jedec) { + s->data[3] = (s->pi->ext_jedec >> 8) & 0xff; + s->data[4] = s->pi->ext_jedec & 0xff; + s->len = 5; + } else { + s->len = 3; } - - s->len = s->pi->id_len; - s->pos = 0; - s->state = STATE_READING_DATA; - break; - - case RDCR: - s->data[0] = s->volatile_cfg & 0xFF; - s->data[0] |= (!!s->four_bytes_address_mode) << 5; s->pos = 0; - s->len = 1; s->state = STATE_READING_DATA; break; @@ -1005,7 +772,7 @@ static void decode_new_cmd(Flash *s, uint32_t value) s->state = STATE_READING_DATA; break; case WNVCR: - if (s->write_enable && get_man(s) == MAN_NUMONYX) { + if (s->write_enable) { s->needed_bytes = 2; s->pos = 0; s->len = 0; @@ -1048,24 +815,6 @@ static void decode_new_cmd(Flash *s, uint32_t value) reset_memory(s); } break; - case RDCR_EQIO: - switch (get_man(s)) { - case MAN_SPANSION: - s->data[0] = (!!s->quad_enable) << 1; - s->pos = 0; - s->len = 1; - s->state = STATE_READING_DATA; - break; - case MAN_MACRONIX: - s->quad_enable = true; - break; - default: - break; - } - break; - case RSTQIO: - s->quad_enable = false; - break; default: qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value); break; @@ -1077,9 +826,6 @@ static int m25p80_cs(SSISlave *ss, bool select) Flash *s = M25P80(ss); if (select) { - if (s->state == STATE_COLLECTING_VAR_LEN_DATA) { - complete_collecting_data(s); - } s->len = 0; s->pos = 0; s->state = STATE_IDLE; @@ -1099,21 +845,20 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) switch (s->state) { case STATE_PAGE_PROGRAM: - DB_PRINT_L(1, "page program cur_addr=%#" PRIx32 " data=%" PRIx8 "\n", + DB_PRINT_L(1, "page program cur_addr=%#" PRIx64 " data=%" PRIx8 "\n", s->cur_addr, (uint8_t)tx); flash_write8(s, s->cur_addr, (uint8_t)tx); - s->cur_addr = (s->cur_addr + 1) & (s->size - 1); + s->cur_addr++; break; case STATE_READ: r = s->storage[s->cur_addr]; - DB_PRINT_L(1, "READ 0x%" PRIx32 "=%" PRIx8 "\n", s->cur_addr, + DB_PRINT_L(1, "READ 0x%" PRIx64 "=%" PRIx8 "\n", s->cur_addr, (uint8_t)r); - s->cur_addr = (s->cur_addr + 1) & (s->size - 1); + s->cur_addr = (s->cur_addr + 1) % s->size; break; case STATE_COLLECTING_DATA: - case STATE_COLLECTING_VAR_LEN_DATA: s->data[s->len] = (uint8_t)tx; s->len++; @@ -1140,8 +885,9 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) return r; } -static void m25p80_realize(SSISlave *ss, Error **errp) +static int m25p80_init(SSISlave *ss) { + DriveInfo *dinfo; Flash *s = M25P80(ss); M25P80Class *mc = M25P80_GET_CLASS(s); @@ -1150,19 +896,29 @@ static void m25p80_realize(SSISlave *ss, Error **errp) s->size = s->pi->sector_size * s->pi->n_sectors; s->dirty_page = -1; - if (s->blk) { + /* FIXME use a qdev drive property instead of drive_get_next() */ + dinfo = drive_get_next(IF_MTD); + + if (dinfo) { DB_PRINT_L(0, "Binding to IF_MTD drive\n"); + s->blk = blk_by_legacy_dinfo(dinfo); + blk_attach_dev_nofail(s->blk, s); + s->storage = blk_blockalign(s->blk, s->size); - if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) { - error_setg(errp, "failed to read the initial flash content"); - return; + /* FIXME: Move to late init */ + if (blk_read(s->blk, 0, s->storage, + DIV_ROUND_UP(s->size, BDRV_SECTOR_SIZE))) { + fprintf(stderr, "Failed to initialize SPI flash!\n"); + return 1; } } else { DB_PRINT_L(0, "No BDRV - binding to RAM\n"); s->storage = blk_blockalign(NULL, s->size); memset(s->storage, 0xFF, s->size); } + + return 0; } static void m25p80_reset(DeviceState *d) @@ -1178,19 +934,13 @@ static void m25p80_pre_save(void *opaque) } static Property m25p80_properties[] = { - /* This is default value for Micron flash */ DEFINE_PROP_UINT32("nonvolatile-cfg", Flash, nonvolatile_cfg, 0x8FFF), - DEFINE_PROP_UINT8("spansion-cr1nv", Flash, spansion_cr1nv, 0x0), - DEFINE_PROP_UINT8("spansion-cr2nv", Flash, spansion_cr2nv, 0x8), - DEFINE_PROP_UINT8("spansion-cr3nv", Flash, spansion_cr3nv, 0x2), - DEFINE_PROP_UINT8("spansion-cr4nv", Flash, spansion_cr4nv, 0x10), - DEFINE_PROP_DRIVE("drive", Flash, blk), DEFINE_PROP_END_OF_LIST(), }; static const VMStateDescription vmstate_m25p80 = { .name = "xilinx_spi", - .version_id = 3, + .version_id = 2, .minimum_version_id = 1, .pre_save = m25p80_pre_save, .fields = (VMStateField[]) { @@ -1200,8 +950,7 @@ static const VMStateDescription vmstate_m25p80 = { VMSTATE_UINT32(pos, Flash), VMSTATE_UINT8(needed_bytes, Flash), VMSTATE_UINT8(cmd_in_progress, Flash), - VMSTATE_UNUSED(4), - VMSTATE_UINT32(cur_addr, Flash), + VMSTATE_UINT64(cur_addr, Flash), VMSTATE_BOOL(write_enable, Flash), VMSTATE_BOOL_V(reset_enable, Flash, 2), VMSTATE_UINT8_V(ear, Flash, 2), @@ -1209,11 +958,6 @@ static const VMStateDescription vmstate_m25p80 = { VMSTATE_UINT32_V(nonvolatile_cfg, Flash, 2), VMSTATE_UINT32_V(volatile_cfg, Flash, 2), VMSTATE_UINT32_V(enh_volatile_cfg, Flash, 2), - VMSTATE_BOOL_V(quad_enable, Flash, 3), - VMSTATE_UINT8_V(spansion_cr1nv, Flash, 3), - VMSTATE_UINT8_V(spansion_cr2nv, Flash, 3), - VMSTATE_UINT8_V(spansion_cr3nv, Flash, 3), - VMSTATE_UINT8_V(spansion_cr4nv, Flash, 3), VMSTATE_END_OF_LIST() } }; @@ -1224,7 +968,7 @@ static void m25p80_class_init(ObjectClass *klass, void *data) SSISlaveClass *k = SSI_SLAVE_CLASS(klass); M25P80Class *mc = M25P80_CLASS(klass); - k->realize = m25p80_realize; + k->init = m25p80_init; k->transfer = m25p80_transfer8; k->set_cs = m25p80_cs; k->cs_polarity = SSI_CS_LOW; diff --git a/hw/block/nand.c b/hw/block/nand.c index c69e6755d..29c659681 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -663,8 +663,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s) sector = SECTOR(s->addr); off = (s->addr & PAGE_MASK) + s->offset; soff = SECTOR_OFFSET(s->addr); - if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, iobuf, - PAGE_SECTORS << BDRV_SECTOR_BITS) < 0) { + if (blk_read(s->blk, sector, iobuf, PAGE_SECTORS) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, sector); return; } @@ -676,24 +675,21 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s) MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE)); } - if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, iobuf, - PAGE_SECTORS << BDRV_SECTOR_BITS, 0) < 0) { + if (blk_write(s->blk, sector, iobuf, PAGE_SECTORS) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, sector); } } else { off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset; sector = off >> 9; soff = off & 0x1ff; - if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, iobuf, - (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) { + if (blk_read(s->blk, sector, iobuf, PAGE_SECTORS + 2) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, sector); return; } mem_and(iobuf + soff, s->io, s->iolen); - if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, iobuf, - (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, 0) < 0) { + if (blk_write(s->blk, sector, iobuf, PAGE_SECTORS + 2) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, sector); } } @@ -720,20 +716,17 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s) i = SECTOR(addr); page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift))); for (; i < page; i ++) - if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS, iobuf, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_write(s->blk, i, iobuf, 1) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, i); } } else { addr = PAGE_START(addr); page = addr >> 9; - if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, iobuf, - BDRV_SECTOR_SIZE) < 0) { + if (blk_read(s->blk, page, iobuf, 1) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, page); } memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1); - if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, iobuf, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_write(s->blk, page, iobuf, 1) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, page); } @@ -741,20 +734,18 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s) i = (addr & ~0x1ff) + 0x200; for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200; i < addr; i += 0x200) { - if (blk_pwrite(s->blk, i, iobuf, BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_write(s->blk, i >> 9, iobuf, 1) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, i >> 9); } } page = i >> 9; - if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, iobuf, - BDRV_SECTOR_SIZE) < 0) { + if (blk_read(s->blk, page, iobuf, 1) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, page); } memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1); - if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, iobuf, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_write(s->blk, page, iobuf, 1) < 0) { printf("%s: write error in sector %" PRIu64 "\n", __func__, page); } } @@ -769,8 +760,7 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s, if (s->blk) { if (s->mem_oob) { - if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS, s->io, - PAGE_SECTORS << BDRV_SECTOR_BITS) < 0) { + if (blk_read(s->blk, SECTOR(addr), s->io, PAGE_SECTORS) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, SECTOR(addr)); } @@ -779,8 +769,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s, OOB_SIZE); s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset; } else { - if (blk_pread(s->blk, PAGE_START(addr), s->io, - (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS) < 0) { + if (blk_read(s->blk, PAGE_START(addr) >> 9, + s->io, (PAGE_SECTORS + 2)) < 0) { printf("%s: read error in sector %" PRIu64 "\n", __func__, PAGE_START(addr) >> 9); } diff --git a/hw/block/nvme.c b/hw/block/nvme.c index cef3bb42f..173988ee8 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -21,10 +21,10 @@ */ #include "qemu/osdep.h" -#include "hw/block/block.h" -#include "hw/hw.h" -#include "hw/pci/msix.h" -#include "hw/pci/pci.h" +#include <hw/block/block.h> +#include <hw/hw.h> +#include <hw/pci/msix.h> +#include <hw/pci/pci.h> #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qapi/visitor.h" @@ -239,7 +239,7 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd, uint8_t lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas); uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds; uint64_t data_size = (uint64_t)nlb << data_shift; - uint64_t data_offset = slba << data_shift; + uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS); int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0; enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ; @@ -258,8 +258,8 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd, req->has_sg = true; dma_acct_start(n->conf.blk, &req->acct, &req->qsg, acct); req->aiocb = is_write ? - dma_blk_write(n->conf.blk, &req->qsg, data_offset, nvme_rw_cb, req) : - dma_blk_read(n->conf.blk, &req->qsg, data_offset, nvme_rw_cb, req); + dma_blk_write(n->conf.blk, &req->qsg, aio_slba, nvme_rw_cb, req) : + dma_blk_read(n->conf.blk, &req->qsg, aio_slba, nvme_rw_cb, req); return NVME_NO_COMPLETE; } @@ -469,22 +469,19 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) return NVME_SUCCESS; } -static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeIdentify *c) -{ - uint64_t prp1 = le64_to_cpu(c->prp1); - uint64_t prp2 = le64_to_cpu(c->prp2); - - return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl), - prp1, prp2); -} - -static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c) +static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd) { NvmeNamespace *ns; + NvmeIdentify *c = (NvmeIdentify *)cmd; + uint32_t cns = le32_to_cpu(c->cns); uint32_t nsid = le32_to_cpu(c->nsid); uint64_t prp1 = le64_to_cpu(c->prp1); uint64_t prp2 = le64_to_cpu(c->prp2); + if (cns) { + return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl), + prp1, prp2); + } if (nsid == 0 || nsid > n->num_namespaces) { return NVME_INVALID_NSID | NVME_DNR; } @@ -494,48 +491,6 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c) prp1, prp2); } -static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c) -{ - static const int data_len = 4096; - uint32_t min_nsid = le32_to_cpu(c->nsid); - uint64_t prp1 = le64_to_cpu(c->prp1); - uint64_t prp2 = le64_to_cpu(c->prp2); - uint32_t *list; - uint16_t ret; - int i, j = 0; - - list = g_malloc0(data_len); - for (i = 0; i < n->num_namespaces; i++) { - if (i < min_nsid) { - continue; - } - list[j++] = cpu_to_le32(i + 1); - if (j == data_len / sizeof(uint32_t)) { - break; - } - } - ret = nvme_dma_read_prp(n, (uint8_t *)list, data_len, prp1, prp2); - g_free(list); - return ret; -} - - -static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd) -{ - NvmeIdentify *c = (NvmeIdentify *)cmd; - - switch (le32_to_cpu(c->cns)) { - case 0x00: - return nvme_identify_ns(n, c); - case 0x01: - return nvme_identify_ctrl(n, c); - case 0x02: - return nvme_identify_nslist(n, c); - default: - return NVME_INVALID_FIELD | NVME_DNR; - } -} - static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) { uint32_t dw10 = le32_to_cpu(cmd->cdw10); @@ -848,7 +803,6 @@ static int nvme_init(PCIDevice *pci_dev) return -1; } blkconf_blocksizes(&n->conf); - blkconf_apply_backend_options(&n->conf); pci_conf = pci_dev->config; pci_conf[PCI_INTERRUPT_PIN] = 1; @@ -954,7 +908,7 @@ static void nvme_class_init(ObjectClass *oc, void *data) pc->class_id = PCI_CLASS_STORAGE_EXPRESS; pc->vendor_id = PCI_VENDOR_ID_INTEL; pc->device_id = 0x5845; - pc->revision = 2; + pc->revision = 1; pc->is_express = 1; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); diff --git a/hw/block/onenand.c b/hw/block/onenand.c index 8d8422739..883f4b1fa 100644 --- a/hw/block/onenand.c +++ b/hw/block/onenand.c @@ -224,8 +224,7 @@ static void onenand_reset(OneNANDState *s, int cold) /* Lock the whole flash */ memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks); - if (s->blk_cur && blk_pread(s->blk_cur, 0, s->boot[0], - 8 << BDRV_SECTOR_BITS) < 0) { + if (s->blk_cur && blk_read(s->blk_cur, 0, s->boot[0], 8) < 0) { hw_error("%s: Loading the BootRAM failed.\n", __func__); } } @@ -241,11 +240,8 @@ static void onenand_system_reset(DeviceState *dev) static inline int onenand_load_main(OneNANDState *s, int sec, int secn, void *dest) { - assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec); - assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn); if (s->blk_cur) { - return blk_pread(s->blk_cur, sec << BDRV_SECTOR_BITS, dest, - secn << BDRV_SECTOR_BITS) < 0; + return blk_read(s->blk_cur, sec, dest, secn) < 0; } else if (sec + secn > s->secs_cur) { return 1; } @@ -261,22 +257,19 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn, int result = 0; if (secn > 0) { - uint32_t size = secn << BDRV_SECTOR_BITS; - uint32_t offset = sec << BDRV_SECTOR_BITS; - assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec); - assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn); + uint32_t size = (uint32_t)secn * 512; const uint8_t *sp = (const uint8_t *)src; uint8_t *dp = 0; if (s->blk_cur) { dp = g_malloc(size); - if (!dp || blk_pread(s->blk_cur, offset, dp, size) < 0) { + if (!dp || blk_read(s->blk_cur, sec, dp, secn) < 0) { result = 1; } } else { if (sec + secn > s->secs_cur) { result = 1; } else { - dp = (uint8_t *)s->current + offset; + dp = (uint8_t *)s->current + (sec << 9); } } if (!result) { @@ -285,7 +278,7 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn, dp[i] &= sp[i]; } if (s->blk_cur) { - result = blk_pwrite(s->blk_cur, offset, dp, size, 0) < 0; + result = blk_write(s->blk_cur, sec, dp, secn) < 0; } } if (dp && s->blk_cur) { @@ -302,8 +295,7 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn, uint8_t buf[512]; if (s->blk_cur) { - uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS; - if (blk_pread(s->blk_cur, offset, buf, BDRV_SECTOR_SIZE) < 0) { + if (blk_read(s->blk_cur, s->secs_cur + (sec >> 5), buf, 1) < 0) { return 1; } memcpy(dest, buf + ((sec & 31) << 4), secn << 4); @@ -312,7 +304,7 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn, } else { memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4); } - + return 0; } @@ -323,12 +315,10 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn, if (secn > 0) { const uint8_t *sp = (const uint8_t *)src; uint8_t *dp = 0, *dpp = 0; - uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS; - assert(UINT32_MAX >> BDRV_SECTOR_BITS > s->secs_cur + (sec >> 5)); if (s->blk_cur) { dp = g_malloc(512); if (!dp - || blk_pread(s->blk_cur, offset, dp, BDRV_SECTOR_SIZE) < 0) { + || blk_read(s->blk_cur, s->secs_cur + (sec >> 5), dp, 1) < 0) { result = 1; } else { dpp = dp + ((sec & 31) << 4); @@ -346,8 +336,8 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn, dpp[i] &= sp[i]; } if (s->blk_cur) { - result = blk_pwrite(s->blk_cur, offset, dp, - BDRV_SECTOR_SIZE, 0) < 0; + result = blk_write(s->blk_cur, s->secs_cur + (sec >> 5), + dp, 1) < 0; } } g_free(dp); @@ -365,17 +355,14 @@ static inline int onenand_erase(OneNANDState *s, int sec, int num) for (; num > 0; num--, sec++) { if (s->blk_cur) { int erasesec = s->secs_cur + (sec >> 5); - if (blk_pwrite(s->blk_cur, sec << BDRV_SECTOR_BITS, blankbuf, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_write(s->blk_cur, sec, blankbuf, 1) < 0) { goto fail; } - if (blk_pread(s->blk_cur, erasesec << BDRV_SECTOR_BITS, tmpbuf, - BDRV_SECTOR_SIZE) < 0) { + if (blk_read(s->blk_cur, erasesec, tmpbuf, 1) < 0) { goto fail; } memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4); - if (blk_pwrite(s->blk_cur, erasesec << BDRV_SECTOR_BITS, tmpbuf, - BDRV_SECTOR_SIZE, 0) < 0) { + if (blk_write(s->blk_cur, erasesec, tmpbuf, 1) < 0) { goto fail; } } else { diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 62d7a5661..106a77523 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -45,7 +45,6 @@ #include "qemu/bitops.h" #include "exec/address-spaces.h" #include "qemu/host-utils.h" -#include "qemu/log.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" @@ -65,6 +64,7 @@ do { \ #define DPRINTF(fmt, ...) do { } while (0) #endif +#define TYPE_CFI_PFLASH01 "cfi.pflash01" #define CFI_PFLASH01(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH01) #define PFLASH_BE 0 @@ -413,11 +413,11 @@ static void pflash_update(pflash_t *pfl, int offset, int offset_end; if (pfl->blk) { offset_end = offset + size; - /* widen to sector boundaries */ - offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE); - offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE); - blk_pwrite(pfl->blk, offset, pfl->storage + offset, - offset_end - offset, 0); + /* round to sectors */ + offset = offset >> 9; + offset_end = (offset_end + 511) >> 9; + blk_write(pfl->blk, offset, pfl->storage + (offset << 9), + offset_end - offset); } } @@ -739,7 +739,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) if (pfl->blk) { /* read the initial flash content */ - ret = blk_pread(pfl->blk, 0, pfl->storage, total_len); + ret = blk_read(pfl->blk, 0, pfl->storage, total_len >> 9); if (ret < 0) { vmstate_unregister_ram(&pfl->mem, DEVICE(pfl)); diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 4f6105cc5..b13172c6e 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -57,6 +57,7 @@ do { \ #define PFLASH_LAZY_ROMD_THRESHOLD 42 +#define TYPE_CFI_PFLASH02 "cfi.pflash02" #define CFI_PFLASH02(obj) OBJECT_CHECK(pflash_t, (obj), TYPE_CFI_PFLASH02) struct pflash_t { @@ -252,11 +253,11 @@ static void pflash_update(pflash_t *pfl, int offset, int offset_end; if (pfl->blk) { offset_end = offset + size; - /* widen to sector boundaries */ - offset = QEMU_ALIGN_DOWN(offset, BDRV_SECTOR_SIZE); - offset_end = QEMU_ALIGN_UP(offset_end, BDRV_SECTOR_SIZE); - blk_pwrite(pfl->blk, offset, pfl->storage + offset, - offset_end - offset, 0); + /* round to sectors */ + offset = offset >> 9; + offset_end = (offset_end + 511) >> 9; + blk_write(pfl->blk, offset, pfl->storage + (offset << 9), + offset_end - offset); } } @@ -621,7 +622,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) pfl->chip_len = chip_len; if (pfl->blk) { /* read the initial flash content */ - ret = blk_pread(pfl->blk, 0, pfl->storage, chip_len); + ret = blk_read(pfl->blk, 0, pfl->storage, chip_len >> 9); if (ret < 0) { vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl)); error_setg(errp, "failed to read the initial flash content"); diff --git a/hw/block/tc58128.c b/hw/block/tc58128.c index 1d9f7ee00..7909d5041 100644 --- a/hw/block/tc58128.c +++ b/hw/block/tc58128.c @@ -45,7 +45,7 @@ static void init_dev(tc58128_dev * dev, const char *filename) } } else { /* Build first block with number of blocks */ - blocks = DIV_ROUND_UP(ret, 528 * 32); + blocks = (ret + 528 * 32 - 1) / (528 * 32); dev->flash_contents[0] = blocks & 0xff; dev->flash_contents[1] = (blocks >> 8) & 0xff; dev->flash_contents[2] = (blocks >> 16) & 0xff; diff --git a/hw/block/trace-events b/hw/block/trace-events deleted file mode 100644 index d0dd94ff0..000000000 --- a/hw/block/trace-events +++ /dev/null @@ -1,17 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/block/virtio-blk.c -virtio_blk_req_complete(void *req, int status) "req %p status %d" -virtio_blk_rw_complete(void *req, int ret) "req %p ret %d" -virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" -virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu" -virtio_blk_submit_multireq(void *mrb, int start, int num_reqs, uint64_t offset, size_t size, bool is_write) "mrb %p start %d num_reqs %d offset %"PRIu64" size %zu is_write %d" - -# hw/block/dataplane/virtio-blk.c -virtio_blk_data_plane_start(void *s) "dataplane %p" -virtio_blk_data_plane_stop(void *s) "dataplane %p" -virtio_blk_data_plane_process_request(void *s, unsigned int out_num, unsigned int in_num, unsigned int head) "dataplane %p out_num %u in_num %u head %u" - -# hw/block/hd-geometry.c -hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d" -hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d" diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 331d7667e..3f88f8cf5 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -29,11 +29,9 @@ #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" -void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq, - VirtIOBlockReq *req) +void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req) { req->dev = s; - req->vq = vq; req->qiov.size = 0; req->in_len = 0; req->next = NULL; @@ -55,11 +53,11 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) trace_virtio_blk_req_complete(req, status); stb_p(&req->in->status, status); - virtqueue_push(req->vq, &req->elem, req->in_len); + virtqueue_push(s->vq, &req->elem, req->in_len); if (s->dataplane_started && !s->dataplane_disabled) { - virtio_blk_data_plane_notify(s->dataplane, req->vq); + virtio_blk_data_plane_notify(s->dataplane); } else { - virtio_notify(vdev, req->vq); + virtio_notify(vdev, s->vq); } } @@ -189,12 +187,12 @@ out: #endif -static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s, VirtQueue *vq) +static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) { - VirtIOBlockReq *req = virtqueue_pop(vq, sizeof(VirtIOBlockReq)); + VirtIOBlockReq *req = virtqueue_pop(s->vq, sizeof(VirtIOBlockReq)); if (req) { - virtio_blk_init_request(s, vq, req); + virtio_blk_init_request(s, req); } return req; } @@ -324,6 +322,7 @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb, { QEMUIOVector *qiov = &mrb->reqs[start]->qiov; int64_t sector_num = mrb->reqs[start]->sector_num; + int nb_sectors = mrb->reqs[start]->qiov.size / BDRV_SECTOR_SIZE; bool is_write = mrb->is_write; if (num_reqs > 1) { @@ -332,7 +331,7 @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb, int tmp_niov = qiov->niov; /* mrb->reqs[start]->qiov was initialized from external so we can't - * modify it here. We need to initialize it locally and then add the + * modifiy it here. We need to initialize it locally and then add the * external iovecs. */ qemu_iovec_init(qiov, niov); @@ -344,22 +343,23 @@ static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb, qemu_iovec_concat(qiov, &mrb->reqs[i]->qiov, 0, mrb->reqs[i]->qiov.size); mrb->reqs[i - 1]->mr_next = mrb->reqs[i]; + nb_sectors += mrb->reqs[i]->qiov.size / BDRV_SECTOR_SIZE; } + assert(nb_sectors == qiov->size / BDRV_SECTOR_SIZE); - trace_virtio_blk_submit_multireq(mrb, start, num_reqs, - sector_num << BDRV_SECTOR_BITS, - qiov->size, is_write); + trace_virtio_blk_submit_multireq(mrb, start, num_reqs, sector_num, + nb_sectors, is_write); block_acct_merge_done(blk_get_stats(blk), is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ, num_reqs - 1); } if (is_write) { - blk_aio_pwritev(blk, sector_num << BDRV_SECTOR_BITS, qiov, 0, - virtio_blk_rw_complete, mrb->reqs[start]); - } else { - blk_aio_preadv(blk, sector_num << BDRV_SECTOR_BITS, qiov, 0, + blk_aio_writev(blk, sector_num, qiov, nb_sectors, virtio_blk_rw_complete, mrb->reqs[start]); + } else { + blk_aio_readv(blk, sector_num, qiov, nb_sectors, + virtio_blk_rw_complete, mrb->reqs[start]); } } @@ -384,7 +384,7 @@ static int multireq_compare(const void *a, const void *b) void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb) { int i = 0, start = 0, num_reqs = 0, niov = 0, nb_sectors = 0; - uint32_t max_transfer; + int max_xfer_len = 0; int64_t sector_num = 0; if (mrb->num_reqs == 1) { @@ -393,7 +393,8 @@ void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb) return; } - max_transfer = blk_get_max_transfer(mrb->reqs[0]->dev->blk); + max_xfer_len = blk_get_max_transfer_length(mrb->reqs[0]->dev->blk); + max_xfer_len = MIN_NON_ZERO(max_xfer_len, BDRV_REQUEST_MAX_SECTORS); qsort(mrb->reqs, mrb->num_reqs, sizeof(*mrb->reqs), &multireq_compare); @@ -409,9 +410,8 @@ void virtio_blk_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb) */ if (sector_num + nb_sectors != req->sector_num || niov > blk_get_max_iov(blk) - req->qiov.niov || - req->qiov.size > max_transfer || - nb_sectors > (max_transfer - - req->qiov.size) / BDRV_SECTOR_SIZE) { + req->qiov.size / BDRV_SECTOR_SIZE > max_xfer_len || + nb_sectors > max_xfer_len - req->qiov.size / BDRV_SECTOR_SIZE) { submit_requests(blk, mrb, start, num_reqs, niov); num_reqs = 0; } @@ -585,7 +585,7 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) blk_io_plug(s->blk); - while ((req = virtio_blk_get_request(s, vq))) { + while ((req = virtio_blk_get_request(s))) { virtio_blk_handle_request(req, &mrb); } @@ -654,20 +654,15 @@ static void virtio_blk_reset(VirtIODevice *vdev) { VirtIOBlock *s = VIRTIO_BLK(vdev); AioContext *ctx; - VirtIOBlockReq *req; + /* + * This should cancel pending requests, but can't do nicely until there + * are per-device request lists. + */ ctx = blk_get_aio_context(s->blk); aio_context_acquire(ctx); blk_drain(s->blk); - /* We drop queued requests after blk_drain() because blk_drain() itself can - * produce them. */ - while (s->rq) { - req = s->rq; - s->rq = req->next; - virtio_blk_free_request(req); - } - if (s->dataplane) { virtio_blk_data_plane_stop(s->dataplane); } @@ -715,7 +710,6 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) blkcfg.physical_block_exp = get_physical_block_exp(conf); blkcfg.alignment_offset = 0; blkcfg.wce = blk_enable_write_cache(s->blk); - virtio_stw_p(vdev, &blkcfg.num_queues, s->conf.num_queues); memcpy(config, &blkcfg, sizeof(struct virtio_blk_config)); } @@ -759,9 +753,6 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features, if (blk_is_read_only(s->blk)) { virtio_add_feature(&features, VIRTIO_BLK_F_RO); } - if (s->conf.num_queues > 1) { - virtio_add_feature(&features, VIRTIO_BLK_F_MQ); - } return features; } @@ -803,9 +794,14 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) } } -static void virtio_blk_save(QEMUFile *f, void *opaque, size_t size) +static void virtio_blk_save(QEMUFile *f, void *opaque) { VirtIODevice *vdev = VIRTIO_DEVICE(opaque); + VirtIOBlock *s = VIRTIO_BLK(vdev); + + if (s->dataplane) { + virtio_blk_data_plane_stop(s->dataplane); + } virtio_save(vdev, f); } @@ -817,23 +813,21 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f) while (req) { qemu_put_sbyte(f, 1); - - if (s->conf.num_queues > 1) { - qemu_put_be32(f, virtio_get_queue_index(req->vq)); - } - qemu_put_virtqueue_element(f, &req->elem); req = req->next; } qemu_put_sbyte(f, 0); } -static int virtio_blk_load(QEMUFile *f, void *opaque, size_t size) +static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) { VirtIOBlock *s = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(s); - return virtio_load(vdev, f, 2); + if (version_id != 2) + return -EINVAL; + + return virtio_load(vdev, f, version_id); } static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f, @@ -842,22 +836,9 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f, VirtIOBlock *s = VIRTIO_BLK(vdev); while (qemu_get_sbyte(f)) { - unsigned nvqs = s->conf.num_queues; - unsigned vq_idx = 0; VirtIOBlockReq *req; - - if (nvqs > 1) { - vq_idx = qemu_get_be32(f); - - if (vq_idx >= nvqs) { - error_report("Invalid virtqueue index in request list: %#x", - vq_idx); - return -EINVAL; - } - } - req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq)); - virtio_blk_init_request(s, virtio_get_queue(vdev, vq_idx), req); + virtio_blk_init_request(s, req); req->next = s->rq; s->rq = req; } @@ -882,7 +863,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) VirtIOBlock *s = VIRTIO_BLK(dev); VirtIOBlkConf *conf = &s->conf; Error *err = NULL; - unsigned i; + static int virtio_blk_id; if (!conf->conf.blk) { error_setg(errp, "drive property not set"); @@ -892,13 +873,8 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) error_setg(errp, "Device needs media, but drive is empty"); return; } - if (!conf->num_queues) { - error_setg(errp, "num-queues property must be larger than 0"); - return; - } blkconf_serial(&conf->conf, &conf->serial); - blkconf_apply_backend_options(&conf->conf); s->original_wce = blk_enable_write_cache(conf->conf.blk); blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err); if (err) { @@ -914,9 +890,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) s->rq = NULL; s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1; - for (i = 0; i < conf->num_queues; i++) { - virtio_add_queue_aio(vdev, 128, virtio_blk_handle_output); - } + s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output); virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err); if (err != NULL) { error_propagate(errp, err); @@ -925,6 +899,8 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) } s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); + register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, + virtio_blk_save, virtio_blk_load, s); blk_set_dev_ops(s->blk, &virtio_block_ops, s); blk_set_guest_block_size(s->blk, s->conf.conf.logical_block_size); @@ -939,6 +915,7 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp) virtio_blk_data_plane_destroy(s->dataplane); s->dataplane = NULL; qemu_del_vm_change_state_handler(s->change); + unregister_savevm(dev, "virtio-blk", s); blockdev_mark_auto_del(s->blk); virtio_cleanup(vdev); } @@ -956,11 +933,8 @@ static void virtio_blk_instance_init(Object *obj) DEVICE(obj), NULL); } -VMSTATE_VIRTIO_DEVICE(blk, 2, virtio_blk_load, virtio_blk_save); - static Property virtio_blk_properties[] = { DEFINE_BLOCK_PROPERTIES(VirtIOBlock, conf.conf), - DEFINE_BLOCK_ERROR_PROPERTIES(VirtIOBlock, conf.conf), DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, conf.conf), DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial), DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true), @@ -969,7 +943,6 @@ static Property virtio_blk_properties[] = { #endif DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0, true), - DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1), DEFINE_PROP_END_OF_LIST(), }; @@ -979,7 +952,6 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->props = virtio_blk_properties; - dc->vmsd = &vmstate_virtio_blk; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->realize = virtio_blk_device_realize; vdc->unrealize = virtio_blk_device_unrealize; diff --git a/hw/block/xen_blkif.h b/hw/block/xen_blkif.h index 3300b6fc0..c68487cb3 100644 --- a/hw/block/xen_blkif.h +++ b/hw/block/xen_blkif.h @@ -1,45 +1,35 @@ -#ifndef XEN_BLKIF_H -#define XEN_BLKIF_H +#ifndef __XEN_BLKIF_H__ +#define __XEN_BLKIF_H__ #include <xen/io/ring.h> #include <xen/io/blkif.h> #include <xen/io/protocols.h> -/* - * Not a real protocol. Used to generate ring structs which contain +/* Not a real protocol. Used to generate ring structs which contain * the elements common to all protocols only. This way we get a * compiler-checkable way to use common struct elements, so we can - * avoid using switch(protocol) in a number of places. - */ + * avoid using switch(protocol) in a number of places. */ struct blkif_common_request { - char dummy; + char dummy; }; struct blkif_common_response { - char dummy; + char dummy; }; /* i386 protocol version */ #pragma pack(push, 4) struct blkif_x86_32_request { - uint8_t operation; /* BLKIF_OP_??? */ - uint8_t nr_segments; /* number of segments */ - blkif_vdev_t handle; /* only for read/write requests */ - uint64_t id; /* private guest value, echoed in resp */ - blkif_sector_t sector_number; /* start sector idx on disk (r/w only) */ - struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; -}; -struct blkif_x86_32_request_discard { - uint8_t operation; /* BLKIF_OP_DISCARD */ - uint8_t flag; /* nr_segments in request struct */ - blkif_vdev_t handle; /* only for read/write requests */ - uint64_t id; /* private guest value, echoed in resp */ - blkif_sector_t sector_number; /* start sector idx on disk (r/w only) */ - uint64_t nr_sectors; /* # of contiguous sectors to discard */ + uint8_t operation; /* BLKIF_OP_??? */ + uint8_t nr_segments; /* number of segments */ + blkif_vdev_t handle; /* only for read/write requests */ + uint64_t id; /* private guest value, echoed in resp */ + blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ + struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; }; struct blkif_x86_32_response { - uint64_t id; /* copied from request */ - uint8_t operation; /* copied from request */ - int16_t status; /* BLKIF_RSP_??? */ + uint64_t id; /* copied from request */ + uint8_t operation; /* copied from request */ + int16_t status; /* BLKIF_RSP_??? */ }; typedef struct blkif_x86_32_request blkif_x86_32_request_t; typedef struct blkif_x86_32_response blkif_x86_32_response_t; @@ -47,100 +37,83 @@ typedef struct blkif_x86_32_response blkif_x86_32_response_t; /* x86_64 protocol version */ struct blkif_x86_64_request { - uint8_t operation; /* BLKIF_OP_??? */ - uint8_t nr_segments; /* number of segments */ - blkif_vdev_t handle; /* only for read/write requests */ - uint64_t __attribute__((__aligned__(8))) id; - blkif_sector_t sector_number; /* start sector idx on disk (r/w only) */ - struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; -}; -struct blkif_x86_64_request_discard { - uint8_t operation; /* BLKIF_OP_DISCARD */ - uint8_t flag; /* nr_segments in request struct */ - blkif_vdev_t handle; /* only for read/write requests */ - uint64_t __attribute__((__aligned__(8))) id; - blkif_sector_t sector_number; /* start sector idx on disk (r/w only) */ - uint64_t nr_sectors; /* # of contiguous sectors to discard */ + uint8_t operation; /* BLKIF_OP_??? */ + uint8_t nr_segments; /* number of segments */ + blkif_vdev_t handle; /* only for read/write requests */ + uint64_t __attribute__((__aligned__(8))) id; + blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ + struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; }; struct blkif_x86_64_response { - uint64_t __attribute__((__aligned__(8))) id; - uint8_t operation; /* copied from request */ - int16_t status; /* BLKIF_RSP_??? */ + uint64_t __attribute__((__aligned__(8))) id; + uint8_t operation; /* copied from request */ + int16_t status; /* BLKIF_RSP_??? */ }; typedef struct blkif_x86_64_request blkif_x86_64_request_t; typedef struct blkif_x86_64_response blkif_x86_64_response_t; -DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, - struct blkif_common_response); -DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, - struct blkif_x86_32_response); -DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, - struct blkif_x86_64_response); +DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response); +DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response); +DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response); union blkif_back_rings { - blkif_back_ring_t native; - blkif_common_back_ring_t common; - blkif_x86_32_back_ring_t x86_32_part; - blkif_x86_64_back_ring_t x86_64_part; + blkif_back_ring_t native; + blkif_common_back_ring_t common; + blkif_x86_32_back_ring_t x86_32_part; + blkif_x86_64_back_ring_t x86_64_part; }; typedef union blkif_back_rings blkif_back_rings_t; enum blkif_protocol { - BLKIF_PROTOCOL_NATIVE = 1, - BLKIF_PROTOCOL_X86_32 = 2, - BLKIF_PROTOCOL_X86_64 = 3, + BLKIF_PROTOCOL_NATIVE = 1, + BLKIF_PROTOCOL_X86_32 = 2, + BLKIF_PROTOCOL_X86_64 = 3, }; -static inline void blkif_get_x86_32_req(blkif_request_t *dst, - blkif_x86_32_request_t *src) +static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src) { - int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; + int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; - dst->operation = src->operation; - dst->nr_segments = src->nr_segments; - dst->handle = src->handle; - dst->id = src->id; - dst->sector_number = src->sector_number; - /* Prevent the compiler from using src->... instead. */ - barrier(); - if (dst->operation == BLKIF_OP_DISCARD) { - struct blkif_x86_32_request_discard *s = (void *)src; - struct blkif_request_discard *d = (void *)dst; - d->nr_sectors = s->nr_sectors; - return; - } - if (n > dst->nr_segments) { - n = dst->nr_segments; - } - for (i = 0; i < n; i++) { - dst->seg[i] = src->seg[i]; - } + dst->operation = src->operation; + dst->nr_segments = src->nr_segments; + dst->handle = src->handle; + dst->id = src->id; + dst->sector_number = src->sector_number; + if (src->operation == BLKIF_OP_DISCARD) { + struct blkif_request_discard *s = (void *)src; + struct blkif_request_discard *d = (void *)dst; + d->nr_sectors = s->nr_sectors; + return; + } + /* prevent the compiler from optimizing the code and using src->nr_segments instead */ + barrier(); + if (n > dst->nr_segments) + n = dst->nr_segments; + for (i = 0; i < n; i++) + dst->seg[i] = src->seg[i]; } -static inline void blkif_get_x86_64_req(blkif_request_t *dst, - blkif_x86_64_request_t *src) +static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src) { - int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; + int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; - dst->operation = src->operation; - dst->nr_segments = src->nr_segments; - dst->handle = src->handle; - dst->id = src->id; - dst->sector_number = src->sector_number; - /* Prevent the compiler from using src->... instead. */ - barrier(); - if (dst->operation == BLKIF_OP_DISCARD) { - struct blkif_x86_64_request_discard *s = (void *)src; - struct blkif_request_discard *d = (void *)dst; - d->nr_sectors = s->nr_sectors; - return; - } - if (n > dst->nr_segments) { - n = dst->nr_segments; - } - for (i = 0; i < n; i++) { - dst->seg[i] = src->seg[i]; - } + dst->operation = src->operation; + dst->nr_segments = src->nr_segments; + dst->handle = src->handle; + dst->id = src->id; + dst->sector_number = src->sector_number; + if (src->operation == BLKIF_OP_DISCARD) { + struct blkif_request_discard *s = (void *)src; + struct blkif_request_discard *d = (void *)dst; + d->nr_sectors = s->nr_sectors; + return; + } + /* prevent the compiler from optimizing the code and using src->nr_segments instead */ + barrier(); + if (n > dst->nr_segments) + n = dst->nr_segments; + for (i = 0; i < n; i++) + dst->seg[i] = src->seg[i]; } -#endif /* XEN_BLKIF_H */ +#endif /* __XEN_BLKIF_H__ */ diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index 3b8ad33fc..d4ce380fe 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include <sys/ioctl.h> +#include <sys/mman.h> #include <sys/uio.h> #include "hw/hw.h" @@ -553,8 +554,9 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct, ioreq->v.size, BLOCK_ACCT_READ); ioreq->aio_inflight++; - blk_aio_preadv(blkdev->blk, ioreq->start, &ioreq->v, 0, - qemu_aio_complete, ioreq); + blk_aio_readv(blkdev->blk, ioreq->start / BLOCK_SIZE, + &ioreq->v, ioreq->v.size / BLOCK_SIZE, + qemu_aio_complete, ioreq); break; case BLKIF_OP_WRITE: case BLKIF_OP_FLUSH_DISKCACHE: @@ -567,17 +569,17 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq) ioreq->req.operation == BLKIF_OP_WRITE ? BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH); ioreq->aio_inflight++; - blk_aio_pwritev(blkdev->blk, ioreq->start, &ioreq->v, 0, - qemu_aio_complete, ioreq); + blk_aio_writev(blkdev->blk, ioreq->start / BLOCK_SIZE, + &ioreq->v, ioreq->v.size / BLOCK_SIZE, + qemu_aio_complete, ioreq); break; case BLKIF_OP_DISCARD: { struct blkif_request_discard *discard_req = (void *)&ioreq->req; ioreq->aio_inflight++; - blk_aio_pdiscard(blkdev->blk, - discard_req->sector_number << BDRV_SECTOR_BITS, - discard_req->nr_sectors << BDRV_SECTOR_BITS, - qemu_aio_complete, ioreq); + blk_aio_discard(blkdev->blk, + discard_req->sector_number, discard_req->nr_sectors, + qemu_aio_complete, ioreq); break; } default: @@ -679,8 +681,6 @@ static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_I RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc)); break; } - /* Prevent the compiler from accessing the on-ring fields instead. */ - barrier(); return 0; } diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c index d688372ca..2e970b656 100644 --- a/hw/bt/hci-csr.c +++ b/hw/bt/hci-csr.c @@ -22,7 +22,6 @@ #include "qemu-common.h" #include "sysemu/char.h" #include "qemu/timer.h" -#include "qemu/bswap.h" #include "hw/irq.h" #include "sysemu/bt.h" #include "hw/bt.h" @@ -39,14 +38,9 @@ struct csrhci_s { int out_size; uint8_t outfifo[FIFO_LEN * 2]; uint8_t inpkt[FIFO_LEN]; - enum { - CSR_HDR_LEN, - CSR_DATA_LEN, - CSR_DATA - } in_state; int in_len; int in_hdr; - int in_needed; + int in_data; QEMUTimer *out_tm; int64_t baud_delay; @@ -301,60 +295,38 @@ static int csrhci_data_len(const uint8_t *pkt) exit(-1); } -static void csrhci_ready_for_next_inpkt(struct csrhci_s *s) -{ - s->in_state = CSR_HDR_LEN; - s->in_len = 0; - s->in_needed = 2; - s->in_hdr = INT_MAX; -} - static int csrhci_write(struct CharDriverState *chr, const uint8_t *buf, int len) { struct csrhci_s *s = (struct csrhci_s *) chr->opaque; - int total = 0; + int plen = s->in_len; if (!s->enable) return 0; - for (;;) { - int cnt = MIN(len, s->in_needed - s->in_len); - if (cnt) { - memcpy(s->inpkt + s->in_len, buf, cnt); - s->in_len += cnt; - buf += cnt; - len -= cnt; - total += cnt; - } - - if (s->in_len < s->in_needed) { - break; - } + s->in_len += len; + memcpy(s->inpkt + plen, buf, len); - if (s->in_state == CSR_HDR_LEN) { + while (1) { + if (s->in_len >= 2 && plen < 2) s->in_hdr = csrhci_header_len(s->inpkt) + 1; - assert(s->in_hdr >= s->in_needed); - s->in_needed = s->in_hdr; - s->in_state = CSR_DATA_LEN; - continue; - } - if (s->in_state == CSR_DATA_LEN) { - s->in_needed += csrhci_data_len(s->inpkt); - /* hci_acl_hdr could specify more than 4096 bytes, so assert. */ - assert(s->in_needed <= sizeof(s->inpkt)); - s->in_state = CSR_DATA; - continue; - } + if (s->in_len >= s->in_hdr && plen < s->in_hdr) + s->in_data = csrhci_data_len(s->inpkt) + s->in_hdr; - if (s->in_state == CSR_DATA) { + if (s->in_len >= s->in_data) { csrhci_in_packet(s, s->inpkt); - csrhci_ready_for_next_inpkt(s); - } + + memmove(s->inpkt, s->inpkt + s->in_len, s->in_len - s->in_data); + s->in_len -= s->in_data; + s->in_hdr = INT_MAX; + s->in_data = INT_MAX; + plen = 0; + } else + break; } - return total; + return len; } static void csrhci_out_hci_packet_event(void *opaque, @@ -416,9 +388,11 @@ static void csrhci_reset(struct csrhci_s *s) { s->out_len = 0; s->out_size = FIFO_LEN; - csrhci_ready_for_next_inpkt(s); + s->in_len = 0; s->baud_delay = NANOSECONDS_PER_SECOND; s->enable = 0; + s->in_hdr = INT_MAX; + s->in_data = INT_MAX; s->modem_state = 0; /* After a while... (but sooner than 10ms) */ diff --git a/hw/bt/hci.c b/hw/bt/hci.c index 351123fab..7d5220509 100644 --- a/hw/bt/hci.c +++ b/hw/bt/hci.c @@ -426,7 +426,11 @@ static void bt_submit_raw_acl(struct bt_piconet_s *net, int length, uint8_t *dat * be continuously allocated. We do it though, to preserve similar * behaviour between hosts. Some things, like the BD_ADDR cannot be * preserved though (for example if a real hci is used). */ -#define HNDL(raw) cpu_to_le16(raw) +#ifdef HOST_WORDS_BIGENDIAN +# define HNDL(raw) bswap16(raw) +#else +# define HNDL(raw) (raw) +#endif static const uint8_t bt_event_reserved_mask[8] = { 0xff, 0x9f, 0xfb, 0xff, 0x07, 0x18, 0x00, 0x00, @@ -1500,8 +1504,8 @@ static void bt_submit_hci(struct HCIInfo *info, return; #define PARAM(cmd, param) (((cmd##_cp *) data)->param) -#define PARAM16(cmd, param) lduw_le_p(&PARAM(cmd, param)) -#define PARAMHANDLE(cmd) PARAM16(cmd, handle) +#define PARAM16(cmd, param) le16_to_cpup(&PARAM(cmd, param)) +#define PARAMHANDLE(cmd) HNDL(PARAM(cmd, handle)) #define LENGTH_CHECK(cmd) if (length < sizeof(cmd##_cp)) goto short_hci /* Note: the supported commands bitmask in bt_hci_read_local_commands_rp * needs to be updated every time a command is implemented here! */ diff --git a/hw/bt/l2cap.c b/hw/bt/l2cap.c index e34204514..806525194 100644 --- a/hw/bt/l2cap.c +++ b/hw/bt/l2cap.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/timer.h" -#include "qemu/bswap.h" #include "hw/bt.h" #define L2CAP_CID_MAX 0x100 /* Between 0x40 and 0x10000 */ @@ -526,9 +525,9 @@ static int l2cap_channel_config(struct l2cap_instance_s *l2cap, } /* MTU */ - val = lduw_le_p(opt->val); + val = le16_to_cpup((void *) opt->val); if (val < ch->min_mtu) { - stw_le_p(opt->val, ch->min_mtu); + cpu_to_le16w((void *) opt->val, ch->min_mtu); result = L2CAP_CONF_UNACCEPT; break; } @@ -543,7 +542,7 @@ static int l2cap_channel_config(struct l2cap_instance_s *l2cap, } /* Flush Timeout */ - val = lduw_le_p(opt->val); + val = le16_to_cpup((void *) opt->val); if (val < 0x0001) { opt->val[0] = 0xff; opt->val[1] = 0xff; @@ -987,7 +986,7 @@ static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid, static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, const l2cap_hdr *hdr, int len) { - uint16_t fcs = lduw_le_p(hdr->data + len - 2); + uint16_t fcs = le16_to_cpup((void *) (hdr->data + len - 2)); if (len < 4) goto len_error; @@ -1002,7 +1001,7 @@ static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, /* TODO: Signal an error? */ return; } - l2cap_sframe_in(ch, lduw_le_p(hdr->data)); + l2cap_sframe_in(ch, le16_to_cpup((void *) hdr->data)); return; } @@ -1022,7 +1021,7 @@ static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid, if (len - 6 > ch->mps) goto len_error; - ch->len_total = lduw_le_p(hdr->data + 2); + ch->len_total = le16_to_cpup((void *) (hdr->data + 2)); if (len >= 6 + ch->len_total) goto seg_error; diff --git a/hw/bt/sdp.c b/hw/bt/sdp.c index f67b3b89c..be26009b0 100644 --- a/hw/bt/sdp.c +++ b/hw/bt/sdp.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "qemu/host-utils.h" #include "hw/bt.h" struct bt_l2cap_sdp_state_s { diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c index 319f1652f..0394d11a8 100644 --- a/hw/char/bcm2835_aux.c +++ b/hw/char/bcm2835_aux.c @@ -22,7 +22,6 @@ #include "qemu/osdep.h" #include "hw/char/bcm2835_aux.h" -#include "qemu/log.h" #define AUX_IRQ 0x0 #define AUX_ENABLES 0x4 diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index e3bc52f7d..797787823 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -17,10 +17,6 @@ */ #include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "sysemu/char.h" -#include "qemu/timer.h" -#include "qemu/log.h" #include "hw/char/cadence_uart.h" #ifdef CADENCE_UART_ERR_DEBUG @@ -288,19 +284,13 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond, } ret = qemu_chr_fe_write(s->chr, s->tx_fifo, s->tx_count); - - if (ret >= 0) { - s->tx_count -= ret; - memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_count); - } + s->tx_count -= ret; + memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_count); if (s->tx_count) { - guint r = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, - cadence_uart_xmit, s); - if (!r) { - s->tx_count = 0; - return FALSE; - } + int r = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, + cadence_uart_xmit, s); + assert(r); } uart_update_status(s); @@ -474,6 +464,9 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp) s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, fifo_trigger_update, s); + /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ + s->chr = qemu_char_get_next_serial(); + if (s->chr) { qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive, uart_event, s); @@ -520,11 +513,6 @@ static const VMStateDescription vmstate_cadence_uart = { } }; -static Property cadence_uart_properties[] = { - DEFINE_PROP_CHR("chardev", CadenceUARTState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - static void cadence_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -532,8 +520,9 @@ static void cadence_uart_class_init(ObjectClass *klass, void *data) dc->realize = cadence_uart_realize; dc->vmsd = &vmstate_cadence_uart; dc->reset = cadence_uart_reset; - dc->props = cadence_uart_properties; - } + /* Reason: realize() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; +} static const TypeInfo cadence_uart_info = { .name = TYPE_CADENCE_UART, diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c index c7604e676..d3bc533d7 100644 --- a/hw/char/digic-uart.c +++ b/hw/char/digic-uart.c @@ -30,7 +30,6 @@ #include "hw/hw.h" #include "hw/sysbus.h" #include "sysemu/char.h" -#include "qemu/log.h" #include "hw/char/digic-uart.h" @@ -145,6 +144,8 @@ static void digic_uart_realize(DeviceState *dev, Error **errp) { DigicUartState *s = DIGIC_UART(dev); + /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ + s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); } @@ -170,11 +171,6 @@ static const VMStateDescription vmstate_digic_uart = { } }; -static Property digic_uart_properties[] = { - DEFINE_PROP_CHR("chardev", DigicUartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - static void digic_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -182,7 +178,8 @@ static void digic_uart_class_init(ObjectClass *klass, void *data) dc->realize = digic_uart_realize; dc->reset = digic_uart_reset; dc->vmsd = &vmstate_digic_uart; - dc->props = digic_uart_properties; + /* Reason: realize() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo digic_uart_info = { diff --git a/hw/char/escc.c b/hw/char/escc.c index 31a5f902f..7bf09a007 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -983,40 +983,28 @@ void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq, sysbus_mmio_map(s, 0, base); } -static void escc_init1(Object *obj) -{ - ESCCState *s = ESCC(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - unsigned int i; - - for (i = 0; i < 2; i++) { - sysbus_init_irq(dev, &s->chn[i].irq); - s->chn[i].chn = 1 - i; - } - s->chn[0].otherchn = &s->chn[1]; - s->chn[1].otherchn = &s->chn[0]; - - sysbus_init_mmio(dev, &s->mmio); -} - -static void escc_realize(DeviceState *dev, Error **errp) +static int escc_init1(SysBusDevice *dev) { ESCCState *s = ESCC(dev); unsigned int i; s->chn[0].disabled = s->disabled; s->chn[1].disabled = s->disabled; - - memory_region_init_io(&s->mmio, OBJECT(dev), &escc_mem_ops, s, "escc", - ESCC_SIZE << s->it_shift); - for (i = 0; i < 2; i++) { + sysbus_init_irq(dev, &s->chn[i].irq); + s->chn[i].chn = 1 - i; + s->chn[i].clock = s->frequency / 2; if (s->chn[i].chr) { - s->chn[i].clock = s->frequency / 2; qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, serial_receive1, serial_event, &s->chn[i]); } } + s->chn[0].otherchn = &s->chn[1]; + s->chn[1].otherchn = &s->chn[0]; + + memory_region_init_io(&s->mmio, OBJECT(s), &escc_mem_ops, s, "escc", + ESCC_SIZE << s->it_shift); + sysbus_init_mmio(dev, &s->mmio); if (s->chn[0].type == mouse) { qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, @@ -1026,6 +1014,8 @@ static void escc_realize(DeviceState *dev, Error **errp) s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]), &sunkbd_handler); } + + return 0; } static Property escc_properties[] = { @@ -1042,9 +1032,10 @@ static Property escc_properties[] = { static void escc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = escc_init1; dc->reset = escc_reset; - dc->realize = escc_realize; dc->vmsd = &vmstate_escc; dc->props = escc_properties; set_bit(DEVICE_CATEGORY_INPUT, dc->categories); @@ -1054,7 +1045,6 @@ static const TypeInfo escc_info = { .name = TYPE_ESCC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ESCCState), - .instance_init = escc_init1, .class_init = escc_class_init, }; diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c index 04ca04fe2..146b387e7 100644 --- a/hw/char/etraxfs_ser.c +++ b/hw/char/etraxfs_ser.c @@ -159,11 +159,6 @@ static const MemoryRegionOps ser_ops = { } }; -static Property etraxfs_ser_properties[] = { - DEFINE_PROP_CHR("chardev", ETRAXSerial, chr), - DEFINE_PROP_END_OF_LIST(), -}; - static void serial_receive(void *opaque, const uint8_t *buf, int size) { ETRAXSerial *s = opaque; @@ -214,42 +209,40 @@ static void etraxfs_ser_reset(DeviceState *d) } -static void etraxfs_ser_init(Object *obj) +static int etraxfs_ser_init(SysBusDevice *dev) { - ETRAXSerial *s = ETRAX_SERIAL(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + ETRAXSerial *s = ETRAX_SERIAL(dev); sysbus_init_irq(dev, &s->irq); - memory_region_init_io(&s->mmio, obj, &ser_ops, s, + memory_region_init_io(&s->mmio, OBJECT(s), &ser_ops, s, "etraxfs-serial", R_MAX * 4); sysbus_init_mmio(dev, &s->mmio); -} - -static void etraxfs_ser_realize(DeviceState *dev, Error **errp) -{ - ETRAXSerial *s = ETRAX_SERIAL(dev); + /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ + s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, serial_can_receive, serial_receive, serial_event, s); } + return 0; } static void etraxfs_ser_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = etraxfs_ser_init; dc->reset = etraxfs_ser_reset; - dc->props = etraxfs_ser_properties; - dc->realize = etraxfs_ser_realize; + /* Reason: init() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo etraxfs_ser_info = { .name = TYPE_ETRAX_FS_SERIAL, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ETRAXSerial), - .instance_init = etraxfs_ser_init, .class_init = etraxfs_ser_class_init, }; diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index 44856d671..6df74ac7c 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -22,7 +22,6 @@ #include "hw/char/imx_serial.h" #include "sysemu/sysemu.h" #include "sysemu/char.h" -#include "qemu/log.h" #ifndef DEBUG_IMX_UART #define DEBUG_IMX_UART 0 diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c index 9ead32af6..bc0ae4980 100644 --- a/hw/char/ipoctal232.c +++ b/hw/char/ipoctal232.c @@ -2,7 +2,7 @@ * QEMU GE IP-Octal 232 IndustryPack emulation * * Copyright (C) 2012 Igalia, S.L. - * Author: Alberto Garcia <berto@igalia.com> + * Author: Alberto Garcia <agarcia@igalia.com> * * This code is licensed under the GNU GPL v2 or (at your option) any * later version. diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c index 28c2cf702..5bf8acfe8 100644 --- a/hw/char/lm32_juart.c +++ b/hw/char/lm32_juart.c @@ -114,13 +114,17 @@ static void juart_reset(DeviceState *d) s->jrx = 0; } -static void lm32_juart_realize(DeviceState *dev, Error **errp) +static int lm32_juart_init(SysBusDevice *dev) { LM32JuartState *s = LM32_JUART(dev); + /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ + s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s); } + + return 0; } static const VMStateDescription vmstate_lm32_juart = { @@ -134,19 +138,16 @@ static const VMStateDescription vmstate_lm32_juart = { } }; -static Property lm32_juart_properties[] = { - DEFINE_PROP_CHR("chardev", LM32JuartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - static void lm32_juart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = lm32_juart_init; dc->reset = juart_reset; dc->vmsd = &vmstate_lm32_juart; - dc->props = lm32_juart_properties; - dc->realize = lm32_juart_realize; + /* Reason: init() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo lm32_juart_info = { diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c index b5c760dda..036813d0f 100644 --- a/hw/char/lm32_uart.c +++ b/hw/char/lm32_uart.c @@ -249,25 +249,23 @@ static void uart_reset(DeviceState *d) s->regs[R_LSR] = LSR_THRE | LSR_TEMT; } -static void lm32_uart_init(Object *obj) +static int lm32_uart_init(SysBusDevice *dev) { - LM32UartState *s = LM32_UART(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + LM32UartState *s = LM32_UART(dev); sysbus_init_irq(dev, &s->irq); - memory_region_init_io(&s->iomem, obj, &uart_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &uart_ops, s, "uart", R_MAX * 4); sysbus_init_mmio(dev, &s->iomem); -} - -static void lm32_uart_realize(DeviceState *dev, Error **errp) -{ - LM32UartState *s = LM32_UART(dev); + /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ + s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); } + + return 0; } static const VMStateDescription vmstate_lm32_uart = { @@ -280,26 +278,22 @@ static const VMStateDescription vmstate_lm32_uart = { } }; -static Property lm32_uart_properties[] = { - DEFINE_PROP_CHR("chardev", LM32UartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - static void lm32_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = lm32_uart_init; dc->reset = uart_reset; dc->vmsd = &vmstate_lm32_uart; - dc->props = lm32_uart_properties; - dc->realize = lm32_uart_realize; + /* Reason: init() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo lm32_uart_info = { .name = TYPE_LM32_UART, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32UartState), - .instance_init = lm32_uart_init, .class_init = lm32_uart_class_init, }; diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c index baddb3764..03b36b223 100644 --- a/hw/char/milkymist-uart.c +++ b/hw/char/milkymist-uart.c @@ -18,7 +18,7 @@ * * * Specification available at: - * http://milkymist.walle.cc/socdoc/uart.pdf + * http://www.milkymist.org/socdoc/uart.pdf */ #include "qemu/osdep.h" @@ -200,6 +200,8 @@ static void milkymist_uart_realize(DeviceState *dev, Error **errp) { MilkymistUartState *s = MILKYMIST_UART(dev); + /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ + s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); } @@ -227,11 +229,6 @@ static const VMStateDescription vmstate_milkymist_uart = { } }; -static Property milkymist_uart_properties[] = { - DEFINE_PROP_CHR("chardev", MilkymistUartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - static void milkymist_uart_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -239,7 +236,8 @@ static void milkymist_uart_class_init(ObjectClass *klass, void *data) dc->realize = milkymist_uart_realize; dc->reset = milkymist_uart_reset; dc->vmsd = &vmstate_milkymist_uart; - dc->props = milkymist_uart_properties; + /* Reason: realize() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo milkymist_uart_info = { diff --git a/hw/char/pl011.c b/hw/char/pl011.c index c0fbf8a87..210c87b4c 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "sysemu/char.h" -#include "qemu/log.h" #define TYPE_PL011 "pl011" #define PL011(obj) OBJECT_CHECK(PL011State, (obj), TYPE_PL011) @@ -274,11 +273,6 @@ static const VMStateDescription vmstate_pl011 = { } }; -static Property pl011_properties[] = { - DEFINE_PROP_CHR("chardev", PL011State, chr), - DEFINE_PROP_END_OF_LIST(), -}; - static void pl011_init(Object *obj) { SysBusDevice *sbd = SYS_BUS_DEVICE(obj); @@ -300,6 +294,9 @@ static void pl011_realize(DeviceState *dev, Error **errp) { PL011State *s = PL011(dev); + /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ + s->chr = qemu_char_get_next_serial(); + if (s->chr) { qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, pl011_event, s); @@ -312,7 +309,8 @@ static void pl011_class_init(ObjectClass *oc, void *data) dc->realize = pl011_realize; dc->vmsd = &vmstate_pl011; - dc->props = pl011_properties; + /* Reason: realize() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo pl011_arm_info = { diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c index a22ad8d01..7d4ff8120 100644 --- a/hw/char/sclpconsole-lm.c +++ b/hw/char/sclpconsole-lm.c @@ -44,10 +44,6 @@ typedef struct SCLPConsoleLM { uint8_t buf[SIZE_CONSOLE_BUFFER]; } SCLPConsoleLM; -#define TYPE_SCLPLM_CONSOLE "sclplmconsole" -#define SCLPLM_CONSOLE(obj) \ - OBJECT_CHECK(SCLPConsoleLM, (obj), TYPE_SCLPLM_CONSOLE) - /* * Character layer call-back functions * @@ -120,7 +116,7 @@ static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, { int len; - SCLPConsoleLM *cons = SCLPLM_CONSOLE(event); + SCLPConsoleLM *cons = DO_UPCAST(SCLPConsoleLM, event, event); len = cons->length; /* data need to fit into provided SCLP buffer */ @@ -194,7 +190,7 @@ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len) int ret = 0; const uint8_t *buf_offset; - SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); + SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); if (!scon->chr) { /* If there's no backend, we can just say we consumed all data. */ @@ -248,7 +244,7 @@ static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh) int errors = 0; MDBO *mdbo; SclpMsg *data = (SclpMsg *) ebh; - SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); + SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); len = be16_to_cpu(data->mdb.header.length); if (len < sizeof(data->mdb.header)) { @@ -317,7 +313,7 @@ static int console_init(SCLPEvent *event) { static bool console_available; - SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); + SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); if (console_available) { error_report("Multiple line-mode operator consoles are not supported"); @@ -340,7 +336,7 @@ static int console_exit(SCLPEvent *event) static void console_reset(DeviceState *dev) { SCLPEvent *event = SCLP_EVENT(dev); - SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); + SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); event->event_pending = false; scon->length = 0; diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index d22464826..45997ff4a 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -13,7 +13,7 @@ */ #include "qemu/osdep.h" -#include "hw/qdev.h" +#include <hw/qdev.h> #include "qemu/thread.h" #include "qemu/error-report.h" @@ -40,10 +40,6 @@ typedef struct SCLPConsole { bool notify; /* qemu_notify_event() req'd if true */ } SCLPConsole; -#define TYPE_SCLP_CONSOLE "sclpconsole" -#define SCLP_CONSOLE(obj) \ - OBJECT_CHECK(SCLPConsole, (obj), TYPE_SCLP_CONSOLE) - /* character layer call-back functions */ /* Return number of bytes that fit into iov buffer */ @@ -99,7 +95,7 @@ static unsigned int receive_mask(void) static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, int avail) { - SCLPConsole *cons = SCLP_CONSOLE(event); + SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event); /* first byte is hex 0 saying an ascii string follows */ *buf++ = '\0'; @@ -161,7 +157,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf, size_t len) { - SCLPConsole *scon = SCLP_CONSOLE(event); + SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); if (!scon->chr) { /* If there's no backend, we can just say we consumed all data. */ @@ -218,7 +214,7 @@ static int console_init(SCLPEvent *event) { static bool console_available; - SCLPConsole *scon = SCLP_CONSOLE(event); + SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); if (console_available) { error_report("Multiple VT220 operator consoles are not supported"); @@ -236,7 +232,7 @@ static int console_init(SCLPEvent *event) static void console_reset(DeviceState *dev) { SCLPEvent *event = SCLP_EVENT(dev); - SCLPConsole *scon = SCLP_CONSOLE(event); + SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); event->event_pending = false; scon->iov_sclp = 0; diff --git a/hw/char/serial.c b/hw/char/serial.c index 3442f47d3..6d815b5c6 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -106,7 +106,6 @@ do {} while (0) #endif static void serial_receive1(void *opaque, const uint8_t *buf, int size); -static void serial_xmit(SerialState *s); static inline void recv_fifo_put(SerialState *s, uint8_t chr) { @@ -224,20 +223,13 @@ static void serial_update_msl(SerialState *s) } } -static gboolean serial_watch_cb(GIOChannel *chan, GIOCondition cond, - void *opaque) +static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) { SerialState *s = opaque; - s->watch_tag = 0; - serial_xmit(s); - return FALSE; -} -static void serial_xmit(SerialState *s) -{ do { assert(!(s->lsr & UART_LSR_TEMT)); - if (s->tsr_retry == 0) { + if (s->tsr_retry <= 0) { assert(!(s->lsr & UART_LSR_THRE)); if (s->fcr & UART_FCR_FE) { @@ -259,17 +251,17 @@ static void serial_xmit(SerialState *s) if (s->mcr & UART_MCR_LOOP) { /* in loopback mode, say that we just received a char */ serial_receive1(s, &s->tsr, 1); - } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1 && - s->tsr_retry < MAX_XMIT_RETRY) { - assert(s->watch_tag == 0); - s->watch_tag = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, - serial_watch_cb, s); - if (s->watch_tag > 0) { + } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { + if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY && + qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, + serial_xmit, s) > 0) { s->tsr_retry++; - return; + return FALSE; } + s->tsr_retry = 0; + } else { + s->tsr_retry = 0; } - s->tsr_retry = 0; /* Transmit another byte if it is already available. It is only possible when FIFO is enabled and not empty. */ @@ -277,8 +269,11 @@ static void serial_xmit(SerialState *s) s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->lsr |= UART_LSR_TEMT; + + return FALSE; } + /* Setter for FCR. is_load flag means, that value is set while loading VM state and interrupt should not be invoked */ @@ -335,8 +330,8 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, s->lsr &= ~UART_LSR_THRE; s->lsr &= ~UART_LSR_TEMT; serial_update_irq(s); - if (s->tsr_retry == 0) { - serial_xmit(s); + if (s->tsr_retry <= 0) { + serial_xmit(NULL, G_IO_OUT, s); } } break; @@ -644,31 +639,6 @@ static int serial_post_load(void *opaque, int version_id) if (s->thr_ipending == -1) { s->thr_ipending = ((s->iir & UART_IIR_ID) == UART_IIR_THRI); } - - if (s->tsr_retry > 0) { - /* tsr_retry > 0 implies LSR.TEMT = 0 (transmitter not empty). */ - if (s->lsr & UART_LSR_TEMT) { - error_report("inconsistent state in serial device " - "(tsr empty, tsr_retry=%d", s->tsr_retry); - return -1; - } - - if (s->tsr_retry > MAX_XMIT_RETRY) { - s->tsr_retry = MAX_XMIT_RETRY; - } - - assert(s->watch_tag == 0); - s->watch_tag = qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, - serial_watch_cb, s); - } else { - /* tsr_retry == 0 implies LSR.TEMT = 1 (transmitter empty). */ - if (!(s->lsr & UART_LSR_TEMT)) { - error_report("inconsistent state in serial device " - "(tsr not empty, tsr_retry=0"); - return -1; - } - } - s->last_break_enable = (s->lcr >> 6) & 1; /* Initialize fcr via setter to perform essential side-effects */ serial_write_fcr(s, s->fcr_vmstate); @@ -715,7 +685,7 @@ static const VMStateDescription vmstate_serial_tsr = { .minimum_version_id = 1, .needed = serial_tsr_needed, .fields = (VMStateField[]) { - VMSTATE_UINT32(tsr_retry, SerialState), + VMSTATE_INT32(tsr_retry, SerialState), VMSTATE_UINT8(thr, SerialState), VMSTATE_UINT8(tsr, SerialState), VMSTATE_END_OF_LIST() @@ -845,11 +815,6 @@ static void serial_reset(void *opaque) { SerialState *s = opaque; - if (s->watch_tag > 0) { - g_source_remove(s->watch_tag); - s->watch_tag = 0; - } - s->rbr = 0; s->ier = 0; s->iir = UART_IIR_NO_INT; diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c index 15657abda..a94d61ceb 100644 --- a/hw/char/stm32f2xx_usart.c +++ b/hw/char/stm32f2xx_usart.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "hw/char/stm32f2xx_usart.h" -#include "qemu/log.h" #ifndef STM_USART_ERR_DEBUG #define STM_USART_ERR_DEBUG 0 @@ -190,11 +189,6 @@ static const MemoryRegionOps stm32f2xx_usart_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static Property stm32f2xx_usart_properties[] = { - DEFINE_PROP_CHR("chardev", STM32F2XXUsartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - static void stm32f2xx_usart_init(Object *obj) { STM32F2XXUsartState *s = STM32F2XX_USART(obj); @@ -204,11 +198,9 @@ static void stm32f2xx_usart_init(Object *obj) memory_region_init_io(&s->mmio, obj, &stm32f2xx_usart_ops, s, TYPE_STM32F2XX_USART, 0x2000); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); -} -static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp) -{ - STM32F2XXUsartState *s = STM32F2XX_USART(dev); + /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ + s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive, @@ -221,8 +213,8 @@ static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->reset = stm32f2xx_usart_reset; - dc->props = stm32f2xx_usart_properties; - dc->realize = stm32f2xx_usart_realize; + /* Reason: instance_init() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo stm32f2xx_usart_info = { diff --git a/hw/char/trace-events b/hw/char/trace-events deleted file mode 100644 index d53577c99..000000000 --- a/hw/char/trace-events +++ /dev/null @@ -1,49 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/char/virtio-serial-bus.c -virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u" -virtio_serial_throttle_port(unsigned int port, bool throttle) "port %u, throttle %d" -virtio_serial_handle_control_message(uint16_t event, uint16_t value) "event %u, value %u" -virtio_serial_handle_control_message_port(unsigned int port) "port %u" - -# hw/char/virtio-console.c -virtio_console_flush_buf(unsigned int port, size_t len, ssize_t ret) "port %u, in_len %zu, out_len %zd" -virtio_console_chr_read(unsigned int port, int size) "port %u, size %d" -virtio_console_chr_event(unsigned int port, int event) "port %u, event %d" - -# hw/char/grlib_apbuart.c -grlib_apbuart_event(int event) "event:%d" -grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x" -grlib_apbuart_readl_unknown(uint64_t addr) "addr 0x%"PRIx64 - -# hw/char/lm32_juart.c -lm32_juart_get_jtx(uint32_t value) "jtx 0x%08x" -lm32_juart_set_jtx(uint32_t value) "jtx 0x%08x" -lm32_juart_get_jrx(uint32_t value) "jrx 0x%08x" -lm32_juart_set_jrx(uint32_t value) "jrx 0x%08x" - -# hw/char/lm32_uart.c -lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_uart_irq_state(int level) "irq state %d" - -# hw/char/milkymist-uart.c -milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_uart_raise_irq(void) "Raise IRQ" -milkymist_uart_lower_irq(void) "Lower IRQ" - -# hw/char/escc.c -escc_put_queue(char channel, int b) "channel %c put: 0x%02x" -escc_get_queue(char channel, int val) "channel %c get 0x%02x" -escc_update_irq(int irq) "IRQ = %d" -escc_update_parameters(char channel, int speed, int parity, int data_bits, int stop_bits) "channel %c: speed=%d parity=%c data=%d stop=%d" -escc_mem_writeb_ctrl(char channel, uint32_t reg, uint32_t val) "Write channel %c, reg[%d] = %2.2x" -escc_mem_writeb_data(char channel, uint32_t val) "Write channel %c, ch %d" -escc_mem_readb_ctrl(char channel, uint32_t reg, uint8_t val) "Read channel %c, reg[%d] = %2.2x" -escc_mem_readb_data(char channel, uint32_t ret) "Read channel %c, ch %d" -escc_serial_receive_byte(char channel, int ch) "channel %c put ch %d" -escc_sunkbd_event_in(int ch, const char *name, int down) "QKeyCode 0x%2.2x [%s], down %d" -escc_sunkbd_event_out(int ch) "Translated keycode 0x%2.2x" -escc_kbd_command(int val) "Command %d" -escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x" diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index 4f0e03d3b..2e36481a7 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -85,9 +85,8 @@ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected) { VirtConsole *vcon = VIRTIO_CONSOLE(port); DeviceState *dev = DEVICE(port); - VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); - if (vcon->chr && !k->is_console) { + if (vcon->chr) { qemu_chr_fe_set_open(vcon->chr, guest_connected); } @@ -157,25 +156,9 @@ static void virtconsole_realize(DeviceState *dev, Error **errp) } if (vcon->chr) { - /* - * For consoles we don't block guest data transfer just - * because nothing is connected - we'll just let it go - * whetherever the chardev wants - /dev/null probably. - * - * For serial ports we need 100% reliable data transfer - * so we use the opened/closed signals from chardev to - * trigger open/close of the device - */ - if (k->is_console) { - vcon->chr->explicit_fe_open = 0; - qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, - NULL, vcon); - virtio_serial_open(port); - } else { - vcon->chr->explicit_fe_open = 1; - qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, - chr_event, vcon); - } + vcon->chr->explicit_fe_open = 1; + qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, + vcon); } } diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index db57a3854..6e5de6dec 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -594,6 +594,12 @@ static void vser_reset(VirtIODevice *vdev) guest_reset(vser); } +static void virtio_serial_save(QEMUFile *f, void *opaque) +{ + /* The virtio device */ + virtio_save(VIRTIO_DEVICE(opaque), f); +} + static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f) { VirtIOSerial *s = VIRTIO_SERIAL(vdev); @@ -679,7 +685,7 @@ static void virtio_serial_post_load_timer_cb(void *opaque) s->post_load = NULL; } -static int fetch_active_ports_list(QEMUFile *f, +static int fetch_active_ports_list(QEMUFile *f, int version_id, VirtIOSerial *s, uint32_t nr_active_ports) { uint32_t i; @@ -696,7 +702,6 @@ static int fetch_active_ports_list(QEMUFile *f, /* Items in struct VirtIOSerialPort */ for (i = 0; i < nr_active_ports; i++) { VirtIOSerialPort *port; - uint32_t elem_popped; uint32_t id; id = qemu_get_be32(f); @@ -709,29 +714,37 @@ static int fetch_active_ports_list(QEMUFile *f, s->post_load->connected[i].port = port; s->post_load->connected[i].host_connected = qemu_get_byte(f); - qemu_get_be32s(f, &elem_popped); - if (elem_popped) { - qemu_get_be32s(f, &port->iov_idx); - qemu_get_be64s(f, &port->iov_offset); + if (version_id > 2) { + uint32_t elem_popped; - port->elem = - qemu_get_virtqueue_element(f, sizeof(VirtQueueElement)); + qemu_get_be32s(f, &elem_popped); + if (elem_popped) { + qemu_get_be32s(f, &port->iov_idx); + qemu_get_be64s(f, &port->iov_offset); - /* - * Port was throttled on source machine. Let's - * unthrottle it here so data starts flowing again. - */ - virtio_serial_throttle_port(port, false); + port->elem = + qemu_get_virtqueue_element(f, sizeof(VirtQueueElement)); + + /* + * Port was throttled on source machine. Let's + * unthrottle it here so data starts flowing again. + */ + virtio_serial_throttle_port(port, false); + } } } timer_mod(s->post_load->timer, 1); return 0; } -static int virtio_serial_load(QEMUFile *f, void *opaque, size_t size) +static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) { + if (version_id > 3) { + return -EINVAL; + } + /* The virtio device */ - return virtio_load(VIRTIO_DEVICE(opaque), f, 3); + return virtio_load(VIRTIO_DEVICE(opaque), f, version_id); } static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f, @@ -743,6 +756,10 @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f, int ret; uint32_t tmp; + if (version_id < 2) { + return 0; + } + /* Unused */ qemu_get_be16s(f, (uint16_t *) &tmp); qemu_get_be16s(f, (uint16_t *) &tmp); @@ -764,7 +781,7 @@ static int virtio_serial_load_device(VirtIODevice *vdev, QEMUFile *f, qemu_get_be32s(f, &nr_active_ports); if (nr_active_ports) { - ret = fetch_active_ports_list(f, s, nr_active_ports); + ret = fetch_active_ports_list(f, version_id, s, nr_active_ports); if (ret) { return ret; } @@ -1032,6 +1049,13 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) vser->post_load = NULL; + /* + * Register for the savevm section with the virtio-console name + * to preserve backward compat + */ + register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save, + virtio_serial_load, vser); + QLIST_INSERT_HEAD(&vserdevices.devices, vser, next); } @@ -1062,6 +1086,8 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp) QLIST_REMOVE(vser, next); + unregister_savevm(dev, "virtio-console", vser); + g_free(vser->ivqs); g_free(vser->ovqs); g_free(vser->ports_map); @@ -1074,9 +1100,6 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp) virtio_cleanup(vdev); } -/* Note: 'console' is used for backwards compatibility */ -VMSTATE_VIRTIO_DEVICE(console, 3, virtio_serial_load, virtio_vmstate_save); - static Property virtio_serial_properties[] = { DEFINE_PROP_UINT32("max_ports", VirtIOSerial, serial.max_virtserial_ports, 31), @@ -1092,7 +1115,6 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data) QLIST_INIT(&vserdevices.devices); dc->props = virtio_serial_properties; - dc->vmsd = &vmstate_virtio_console; set_bit(DEVICE_CATEGORY_INPUT, dc->categories); vdc->realize = virtio_serial_device_realize; vdc->unrealize = virtio_serial_device_unrealize; diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c index 83108b0bd..cbf1dccbb 100644 --- a/hw/char/xen_console.c +++ b/hw/char/xen_console.c @@ -22,6 +22,7 @@ #include "qemu/osdep.h" #include <sys/select.h> #include <termios.h> +#include <sys/mman.h> #include "hw/hw.h" #include "sysemu/char.h" diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c index 4847efb29..911af4a0d 100644 --- a/hw/char/xilinx_uartlite.c +++ b/hw/char/xilinx_uartlite.c @@ -172,11 +172,6 @@ static const MemoryRegionOps uart_ops = { } }; -static Property xilinx_uartlite_properties[] = { - DEFINE_PROP_CHR("chardev", XilinxUARTLite, chr), - DEFINE_PROP_END_OF_LIST(), -}; - static void uart_rx(void *opaque, const uint8_t *buf, int size) { XilinxUARTLite *s = opaque; @@ -211,6 +206,8 @@ static void xilinx_uartlite_realize(DeviceState *dev, Error **errp) { XilinxUARTLite *s = XILINX_UARTLITE(dev); + /* FIXME use a qdev chardev prop instead of qemu_char_get_next_serial() */ + s->chr = qemu_char_get_next_serial(); if (s->chr) qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); } @@ -232,7 +229,8 @@ static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) dc->reset = xilinx_uartlite_reset; dc->realize = xilinx_uartlite_realize; - dc->props = xilinx_uartlite_properties; + /* Reason: realize() method uses qemu_char_get_next_serial() */ + dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo xilinx_uartlite_info = { diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index cfd484039..abb3560be 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -1,11 +1,10 @@ # core qdev-related obj files, also used by *-user: common-obj-y += qdev.o qdev-properties.o -common-obj-y += bus.o common-obj-y += fw-path-provider.o # irq.o needed for qdev GPIO handling: common-obj-y += irq.o common-obj-y += hotplug.o -obj-y += nmi.o +common-obj-y += nmi.o common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o common-obj-$(CONFIG_XILINX_AXI) += stream.o @@ -15,5 +14,4 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o common-obj-$(CONFIG_SOFTMMU) += null-machine.o common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o -common-obj-$(CONFIG_SOFTMMU) += register.o common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o diff --git a/hw/core/bus.c b/hw/core/bus.c deleted file mode 100644 index 3e3f8ac74..000000000 --- a/hw/core/bus.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Dynamic device configuration and creation -- buses. - * - * Copyright (c) 2009 CodeSourcery - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "hw/qdev.h" -#include "qapi/error.h" - -static void qbus_set_hotplug_handler_internal(BusState *bus, Object *handler, - Error **errp) -{ - - object_property_set_link(OBJECT(bus), OBJECT(handler), - QDEV_HOTPLUG_HANDLER_PROPERTY, errp); -} - -void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler, Error **errp) -{ - qbus_set_hotplug_handler_internal(bus, OBJECT(handler), errp); -} - -void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp) -{ - qbus_set_hotplug_handler_internal(bus, OBJECT(bus), errp); -} - -int qbus_walk_children(BusState *bus, - qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, - qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, - void *opaque) -{ - BusChild *kid; - int err; - - if (pre_busfn) { - err = pre_busfn(bus, opaque); - if (err) { - return err; - } - } - - QTAILQ_FOREACH(kid, &bus->children, sibling) { - err = qdev_walk_children(kid->child, - pre_devfn, pre_busfn, - post_devfn, post_busfn, opaque); - if (err < 0) { - return err; - } - } - - if (post_busfn) { - err = post_busfn(bus, opaque); - if (err) { - return err; - } - } - - return 0; -} - -static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) -{ - const char *typename = object_get_typename(OBJECT(bus)); - BusClass *bc; - char *buf; - int i, len, bus_id; - - bus->parent = parent; - - if (name) { - bus->name = g_strdup(name); - } else if (bus->parent && bus->parent->id) { - /* parent device has id -> use it plus parent-bus-id for bus name */ - bus_id = bus->parent->num_child_bus; - - len = strlen(bus->parent->id) + 16; - buf = g_malloc(len); - snprintf(buf, len, "%s.%d", bus->parent->id, bus_id); - bus->name = buf; - } else { - /* no id -> use lowercase bus type plus global bus-id for bus name */ - bc = BUS_GET_CLASS(bus); - bus_id = bc->automatic_ids++; - - len = strlen(typename) + 16; - buf = g_malloc(len); - len = snprintf(buf, len, "%s.%d", typename, bus_id); - for (i = 0; i < len; i++) { - buf[i] = qemu_tolower(buf[i]); - } - bus->name = buf; - } - - if (bus->parent) { - QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); - bus->parent->num_child_bus++; - object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); - object_unref(OBJECT(bus)); - } else if (bus != sysbus_get_default()) { - /* TODO: once all bus devices are qdevified, - only reset handler for main_system_bus should be registered here. */ - qemu_register_reset(qbus_reset_all_fn, bus); - } -} - -static void bus_unparent(Object *obj) -{ - BusState *bus = BUS(obj); - BusChild *kid; - - while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { - DeviceState *dev = kid->child; - object_unparent(OBJECT(dev)); - } - if (bus->parent) { - QLIST_REMOVE(bus, sibling); - bus->parent->num_child_bus--; - bus->parent = NULL; - } else { - assert(bus != sysbus_get_default()); /* main_system_bus is never freed */ - qemu_unregister_reset(qbus_reset_all_fn, bus); - } -} - -void qbus_create_inplace(void *bus, size_t size, const char *typename, - DeviceState *parent, const char *name) -{ - object_initialize(bus, size, typename); - qbus_realize(bus, parent, name); -} - -BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) -{ - BusState *bus; - - bus = BUS(object_new(typename)); - qbus_realize(bus, parent, name); - - return bus; -} - -static bool bus_get_realized(Object *obj, Error **errp) -{ - BusState *bus = BUS(obj); - - return bus->realized; -} - -static void bus_set_realized(Object *obj, bool value, Error **errp) -{ - BusState *bus = BUS(obj); - BusClass *bc = BUS_GET_CLASS(bus); - BusChild *kid; - Error *local_err = NULL; - - if (value && !bus->realized) { - if (bc->realize) { - bc->realize(bus, &local_err); - } - - /* TODO: recursive realization */ - } else if (!value && bus->realized) { - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - object_property_set_bool(OBJECT(dev), false, "realized", - &local_err); - if (local_err != NULL) { - break; - } - } - if (bc->unrealize && local_err == NULL) { - bc->unrealize(bus, &local_err); - } - } - - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - bus->realized = value; -} - -static void qbus_initfn(Object *obj) -{ - BusState *bus = BUS(obj); - - QTAILQ_INIT(&bus->children); - object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY, - TYPE_HOTPLUG_HANDLER, - (Object **)&bus->hotplug_handler, - object_property_allow_set_link, - OBJ_PROP_LINK_UNREF_ON_RELEASE, - NULL); - object_property_add_bool(obj, "realized", - bus_get_realized, bus_set_realized, NULL); -} - -static char *default_bus_get_fw_dev_path(DeviceState *dev) -{ - return g_strdup(object_get_typename(OBJECT(dev))); -} - -static void bus_class_init(ObjectClass *class, void *data) -{ - BusClass *bc = BUS_CLASS(class); - - class->unparent = bus_unparent; - bc->get_fw_dev_path = default_bus_get_fw_dev_path; -} - -static void qbus_finalize(Object *obj) -{ - BusState *bus = BUS(obj); - - g_free((char *)bus->name); -} - -static const TypeInfo bus_info = { - .name = TYPE_BUS, - .parent = TYPE_OBJECT, - .instance_size = sizeof(BusState), - .abstract = true, - .class_size = sizeof(BusClass), - .instance_init = qbus_initfn, - .instance_finalize = qbus_finalize, - .class_init = bus_class_init, -}; - -static void bus_register_types(void) -{ - type_register_static(&bus_info); -} - -type_init(bus_register_types) diff --git a/hw/core/hotplug.c b/hw/core/hotplug.c index 17ac98668..645cfca1b 100644 --- a/hw/core/hotplug.c +++ b/hw/core/hotplug.c @@ -13,17 +13,6 @@ #include "hw/hotplug.h" #include "qemu/module.h" -void hotplug_handler_pre_plug(HotplugHandler *plug_handler, - DeviceState *plugged_dev, - Error **errp) -{ - HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler); - - if (hdc->pre_plug) { - hdc->pre_plug(plug_handler, plugged_dev, errp); - } -} - void hotplug_handler_plug(HotplugHandler *plug_handler, DeviceState *plugged_dev, Error **errp) diff --git a/hw/core/loader.c b/hw/core/loader.c index 53e0e4155..c0499571c 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -914,16 +914,10 @@ int rom_add_file(const char *file, const char *fw_dir, err: if (fd != -1) close(fd); - g_free(rom->data); g_free(rom->path); g_free(rom->name); - if (fw_dir) { - g_free(rom->fw_dir); - g_free(rom->fw_file); - } g_free(rom); - return -1; } diff --git a/hw/core/machine.c b/hw/core/machine.c index e5a456f21..6dbbc85b9 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -65,9 +65,6 @@ static void machine_set_kernel_irqchip(Object *obj, Visitor *v, ms->kernel_irqchip_split = true; break; default: - /* The value was checked in visit_type_OnOffSplit() above. If - * we get here, then something is wrong in QEMU. - */ abort(); } } @@ -260,47 +257,47 @@ static void machine_set_usb(Object *obj, bool value, Error **errp) ms->usb_disabled = !value; } -static bool machine_get_graphics(Object *obj, Error **errp) +static bool machine_get_igd_gfx_passthru(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); - return ms->enable_graphics; + return ms->igd_gfx_passthru; } -static void machine_set_graphics(Object *obj, bool value, Error **errp) +static void machine_set_igd_gfx_passthru(Object *obj, bool value, Error **errp) { MachineState *ms = MACHINE(obj); - ms->enable_graphics = value; + ms->igd_gfx_passthru = value; } -static bool machine_get_igd_gfx_passthru(Object *obj, Error **errp) +static char *machine_get_firmware(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); - return ms->igd_gfx_passthru; + return g_strdup(ms->firmware); } -static void machine_set_igd_gfx_passthru(Object *obj, bool value, Error **errp) +static void machine_set_firmware(Object *obj, const char *value, Error **errp) { MachineState *ms = MACHINE(obj); - ms->igd_gfx_passthru = value; + g_free(ms->firmware); + ms->firmware = g_strdup(value); } -static char *machine_get_firmware(Object *obj, Error **errp) +static bool machine_get_iommu(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); - return g_strdup(ms->firmware); + return ms->iommu; } -static void machine_set_firmware(Object *obj, const char *value, Error **errp) +static void machine_set_iommu(Object *obj, bool value, Error **errp) { MachineState *ms = MACHINE(obj); - g_free(ms->firmware); - ms->firmware = g_strdup(value); + ms->iommu = value; } static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) @@ -385,7 +382,6 @@ static void machine_initfn(Object *obj) ms->kvm_shadow_mem = -1; ms->dump_guest_core = true; ms->mem_merge = true; - ms->enable_graphics = true; object_property_add_str(obj, "accel", machine_get_accel, machine_set_accel, NULL); @@ -464,12 +460,6 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "usb", "Set on/off to enable/disable usb", NULL); - object_property_add_bool(obj, "graphics", - machine_get_graphics, - machine_set_graphics, NULL); - object_property_set_description(obj, "graphics", - "Set on/off to enable/disable graphics emulation", - NULL); object_property_add_bool(obj, "igd-passthru", machine_get_igd_gfx_passthru, machine_set_igd_gfx_passthru, NULL); @@ -482,6 +472,12 @@ static void machine_initfn(Object *obj) object_property_set_description(obj, "firmware", "Firmware image", NULL); + object_property_add_bool(obj, "iommu", + machine_get_iommu, + machine_set_iommu, NULL); + object_property_set_description(obj, "iommu", + "Set on/off to enable/disable Intel IOMMU (VT-d)", + NULL); object_property_add_bool(obj, "suppress-vmdesc", machine_get_suppress_vmdesc, machine_set_suppress_vmdesc, NULL); @@ -554,33 +550,6 @@ bool machine_mem_merge(MachineState *machine) return machine->mem_merge; } -static void machine_class_finalize(ObjectClass *klass, void *data) -{ - MachineClass *mc = MACHINE_CLASS(klass); - - if (mc->compat_props) { - g_array_free(mc->compat_props, true); - } -} - -void machine_register_compat_props(MachineState *machine) -{ - MachineClass *mc = MACHINE_GET_CLASS(machine); - int i; - GlobalProperty *p; - - if (!mc->compat_props) { - return; - } - - for (i = 0; i < mc->compat_props->len; i++) { - p = g_array_index(mc->compat_props, GlobalProperty *, i); - /* Machine compat_props must never cause errors: */ - p->errp = &error_abort; - qdev_prop_register_global(p); - } -} - static const TypeInfo machine_info = { .name = TYPE_MACHINE, .parent = TYPE_OBJECT, @@ -588,7 +557,6 @@ static const TypeInfo machine_info = { .class_size = sizeof(MachineClass), .class_init = machine_class_init, .class_base_init = machine_class_base_init, - .class_finalize = machine_class_finalize, .instance_size = sizeof(MachineState), .instance_init = machine_initfn, .instance_finalize = machine_finalize, diff --git a/hw/core/nmi.c b/hw/core/nmi.c index bfd0896da..e8bcc4177 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -73,6 +73,25 @@ void nmi_monitor_handle(int cpu_index, Error **errp) } } +void inject_nmi(void) +{ +#if defined(TARGET_I386) + CPUState *cs; + + CPU_FOREACH(cs) { + X86CPU *cpu = X86_CPU(cs); + + if (!cpu->apic_state) { + cpu_interrupt(cs, CPU_INTERRUPT_NMI); + } else { + apic_deliver_nmi(cpu->apic_state); + } + } +#else + nmi_monitor_handle(0, NULL); +#endif +} + static const TypeInfo nmi_info = { .name = TYPE_NMI, .parent = TYPE_INTERFACE, diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 30829ee97..153c83513 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -35,9 +35,6 @@ static void ptimer_trigger(ptimer_state *s) static void ptimer_reload(ptimer_state *s) { - uint32_t period_frac = s->period_frac; - uint64_t period = s->period; - if (s->delta == 0) { ptimer_trigger(s); s->delta = s->limit; @@ -48,24 +45,10 @@ static void ptimer_reload(ptimer_state *s) return; } - /* - * Artificially limit timeout rate to something - * achievable under QEMU. Otherwise, QEMU spends all - * its time generating timer interrupts, and there - * is no forward progress. - * About ten microseconds is the fastest that really works - * on the current generation of host machines. - */ - - if (s->enabled == 1 && (s->delta * period < 10000) && !use_icount) { - period = 10000 / s->delta; - period_frac = 0; - } - s->last_event = s->next_event; - s->next_event = s->last_event + s->delta * period; - if (period_frac) { - s->next_event += ((int64_t)period_frac * s->delta) >> 32; + s->next_event = s->last_event + s->delta * s->period; + if (s->period_frac) { + s->next_event += ((int64_t)s->period_frac * s->delta) >> 32; } timer_mod(s->timer, s->next_event); } @@ -84,16 +67,14 @@ static void ptimer_tick(void *opaque) uint64_t ptimer_get_count(ptimer_state *s) { + int64_t now; uint64_t counter; if (s->enabled) { - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int64_t next = s->next_event; - bool expired = (now - next >= 0); - bool oneshot = (s->enabled == 2); - + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); /* Figure out the current counter value. */ - if (expired) { + if (now - s->next_event > 0 + || s->period == 0) { /* Prevent timer underflowing if it should already have triggered. */ counter = 0; @@ -102,13 +83,6 @@ uint64_t ptimer_get_count(ptimer_state *s) uint64_t div; int clz1, clz2; int shift; - uint32_t period_frac = s->period_frac; - uint64_t period = s->period; - - if (!oneshot && (s->delta * period < 10000) && !use_icount) { - period = 10000 / s->delta; - period_frac = 0; - } /* We need to divide time by period, where time is stored in rem (64-bit integer) and period is stored in period/period_frac @@ -120,8 +94,8 @@ uint64_t ptimer_get_count(ptimer_state *s) backwards. */ - rem = next - now; - div = period; + rem = s->next_event - now; + div = s->period; clz1 = clz64(rem); clz2 = clz64(div); @@ -130,13 +104,13 @@ uint64_t ptimer_get_count(ptimer_state *s) rem <<= shift; div <<= shift; if (shift >= 32) { - div |= ((uint64_t)period_frac << (shift - 32)); + div |= ((uint64_t)s->period_frac << (shift - 32)); } else { if (shift != 0) - div |= (period_frac >> (32 - shift)); + div |= (s->period_frac >> (32 - shift)); /* Look at remaining bits of period_frac and round div up if necessary. */ - if ((uint32_t)(period_frac << shift)) + if ((uint32_t)(s->period_frac << shift)) div += 1; } counter = rem / div; @@ -158,17 +132,16 @@ void ptimer_set_count(ptimer_state *s, uint64_t count) void ptimer_run(ptimer_state *s, int oneshot) { - bool was_disabled = !s->enabled; - - if (was_disabled && s->period == 0) { + if (s->enabled) { + return; + } + if (s->period == 0) { fprintf(stderr, "Timer with period zero, disabling\n"); return; } s->enabled = oneshot ? 2 : 1; - if (was_disabled) { - s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s); - } + s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + ptimer_reload(s); } /* Pause a timer. Note that this may cause it to "lose" time, even if it @@ -186,7 +159,6 @@ void ptimer_stop(ptimer_state *s) /* Set counter increment interval in nanoseconds. */ void ptimer_set_period(ptimer_state *s, int64_t period) { - s->delta = ptimer_get_count(s); s->period = period; s->period_frac = 0; if (s->enabled) { @@ -198,7 +170,6 @@ void ptimer_set_period(ptimer_state *s, int64_t period) /* Set counter frequency in Hz. */ void ptimer_set_freq(ptimer_state *s, uint32_t freq) { - s->delta = ptimer_get_count(s); s->period = 1000000000ll / freq; s->period_frac = (1000000000ll << 32) / freq; if (s->enabled) { @@ -211,6 +182,19 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq) count = limit. */ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) { + /* + * Artificially limit timeout rate to something + * achievable under QEMU. Otherwise, QEMU spends all + * its time generating timer interrupts, and there + * is no forward progress. + * About ten microseconds is the fastest that really works + * on the current generation of host machines. + */ + + if (!use_icount && limit * s->period < 10000 && s->period) { + limit = 10000 / s->period; + } + s->limit = limit; if (reload) s->delta = limit; @@ -220,11 +204,6 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) } } -uint64_t ptimer_get_limit(ptimer_state *s) -{ - return s->limit; -} - const VMStateDescription vmstate_ptimer = { .name = "ptimer", .version_id = 1, diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index e55afe6bf..891219ae0 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -1,5 +1,5 @@ /* - * qdev property parsing + * qdev property parsing and global properties * (parts specific for qemu-system-*) * * This file is based on code from hw/qdev-properties.c from @@ -72,26 +72,17 @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr, const char *propname, Error **errp) { BlockBackend *blk; - bool blk_created = false; blk = blk_by_name(str); if (!blk) { - BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL); - if (bs) { - blk = blk_new(); - blk_insert_bs(blk, bs); - blk_created = true; - } - } - if (!blk) { error_setg(errp, "Property '%s.%s' can't find value '%s'", object_get_typename(OBJECT(dev)), propname, str); - goto fail; + return; } if (blk_attach_dev(blk, dev) < 0) { DriveInfo *dinfo = blk_legacy_dinfo(blk); - if (dinfo && dinfo->type != IF_NONE) { + if (dinfo->type != IF_NONE) { error_setg(errp, "Drive '%s' is already in use because " "it has been automatically connected to another " "device (did you need 'if=none' in the drive options?)", @@ -100,16 +91,9 @@ static void parse_drive(DeviceState *dev, const char *str, void **ptr, error_setg(errp, "Drive '%s' is already in use by another device", str); } - goto fail; + return; } - *ptr = blk; - -fail: - if (blk_created) { - /* If we need to keep a reference, blk_attach_dev() took it */ - blk_unref(blk); - } } static void release_drive(Object *obj, const char *name, void *opaque) @@ -119,23 +103,14 @@ static void release_drive(Object *obj, const char *name, void *opaque) BlockBackend **ptr = qdev_get_prop_ptr(dev, prop); if (*ptr) { - blockdev_auto_del(*ptr); blk_detach_dev(*ptr, dev); + blockdev_auto_del(*ptr); } } static char *print_drive(void *ptr) { - const char *name; - - name = blk_name(ptr); - if (!*name) { - BlockDriverState *bs = blk_bs(ptr); - if (bs) { - name = bdrv_get_node_name(bs); - } - } - return g_strdup(name); + return g_strdup(blk_name(ptr)); } static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque, @@ -152,7 +127,7 @@ static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque, PropertyInfo qdev_prop_drive = { .name = "str", - .description = "Node name or ID of a block device to use as a backend", + .description = "ID of a drive to use as a backend", .get = get_drive, .set = set_drive, .release = release_drive, @@ -256,7 +231,7 @@ static void set_netdev(Object *obj, Visitor *v, const char *name, } queues = qemu_find_net_clients_except(str, peers, - NET_CLIENT_DRIVER_NIC, + NET_CLIENT_OPTIONS_KIND_NIC, MAX_QUEUE_NUM); if (queues == 0) { err = -ENOENT; @@ -387,19 +362,8 @@ PropertyInfo qdev_prop_vlan = { void qdev_prop_set_drive(DeviceState *dev, const char *name, BlockBackend *value, Error **errp) { - const char *ref = ""; - - if (value) { - ref = blk_name(value); - if (!*ref) { - BlockDriverState *bs = blk_bs(value); - if (bs) { - ref = bdrv_get_node_name(bs); - } - } - } - - object_property_set_str(OBJECT(dev), ref, name, errp); + object_property_set_str(OBJECT(dev), value ? blk_name(value) : "", + name, errp); } void qdev_prop_set_chr(DeviceState *dev, const char *name, @@ -430,3 +394,22 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) } nd->instantiated = 1; } + +static int qdev_add_one_global(void *opaque, QemuOpts *opts, Error **errp) +{ + GlobalProperty *g; + + g = g_malloc0(sizeof(*g)); + g->driver = qemu_opt_get(opts, "driver"); + g->property = qemu_opt_get(opts, "property"); + g->value = qemu_opt_get(opts, "value"); + g->user_provided = true; + qdev_prop_register_global(g); + return 0; +} + +void qemu_add_globals(void) +{ + qemu_opts_foreach(qemu_find_opts("global"), + qdev_add_one_global, NULL, NULL); +} diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 311af6da7..737d29c63 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -539,19 +539,6 @@ PropertyInfo qdev_prop_losttickpolicy = { .set = set_enum, }; -/* --- Block device error handling policy --- */ - -QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int)); - -PropertyInfo qdev_prop_blockdev_on_error = { - .name = "BlockdevOnError", - .description = "Error handling policy, " - "report/ignore/enospc/stop/auto", - .enum_table = BlockdevOnError_lookup, - .get = get_enum, - .set = set_enum, -}; - /* --- BIOS CHS translation */ QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int)); @@ -1033,11 +1020,12 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) *ptr = value; } -static GList *global_props; +static QTAILQ_HEAD(, GlobalProperty) global_props = + QTAILQ_HEAD_INITIALIZER(global_props); void qdev_prop_register_global(GlobalProperty *prop) { - global_props = g_list_append(global_props, prop); + QTAILQ_INSERT_TAIL(&global_props, prop, next); } void qdev_prop_register_global_list(GlobalProperty *props) @@ -1051,11 +1039,10 @@ void qdev_prop_register_global_list(GlobalProperty *props) int qdev_prop_check_globals(void) { - GList *l; + GlobalProperty *prop; int ret = 0; - for (l = global_props; l; l = l->next) { - GlobalProperty *prop = l->data; + QTAILQ_FOREACH(prop, &global_props, next) { ObjectClass *oc; DeviceClass *dc; if (prop->used) { @@ -1084,12 +1071,11 @@ int qdev_prop_check_globals(void) } static void qdev_prop_set_globals_for_type(DeviceState *dev, - const char *typename) + const char *typename) { - GList *l; + GlobalProperty *prop; - for (l = global_props; l; l = l->next) { - GlobalProperty *prop = l->data; + QTAILQ_FOREACH(prop, &global_props, next) { Error *err = NULL; if (strcmp(typename, prop->driver) != 0) { @@ -1098,14 +1084,10 @@ static void qdev_prop_set_globals_for_type(DeviceState *dev, prop->used = true; object_property_parse(OBJECT(dev), prop->value, prop->property, &err); if (err != NULL) { - error_prepend(&err, "can't apply global %s.%s=%s: ", - prop->driver, prop->property, prop->value); - if (!dev->hotplugged && prop->errp) { - error_propagate(prop->errp, err); - } else { - assert(prop->user_provided); - error_reportf_err(err, "Warning: "); - } + assert(prop->user_provided); + error_reportf_err(err, "Warning: global %s.%s=%s ignored: ", + prop->driver, prop->property, prop->value); + return; } } } diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 57834423b..db41aa1f2 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -35,7 +35,6 @@ #include "qemu/error-report.h" #include "hw/hotplug.h" #include "hw/boards.h" -#include "hw/sysbus.h" #include "qapi-event.h" int qdev_hotplug = 0; @@ -59,6 +58,9 @@ const char *qdev_fw_name(DeviceState *dev) return object_get_typename(OBJECT(dev)); } +static void qdev_property_add_legacy(DeviceState *dev, Property *prop, + Error **errp); + static void bus_remove_child(BusState *bus, DeviceState *child) { BusChild *kid; @@ -107,6 +109,24 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus) bus_add_child(bus, dev); } +static void qbus_set_hotplug_handler_internal(BusState *bus, Object *handler, + Error **errp) +{ + + object_property_set_link(OBJECT(bus), OBJECT(handler), + QDEV_HOTPLUG_HANDLER_PROPERTY, errp); +} + +void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler, Error **errp) +{ + qbus_set_hotplug_handler_internal(bus, OBJECT(handler), errp); +} + +void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp) +{ + qbus_set_hotplug_handler_internal(bus, OBJECT(bus), errp); +} + /* Create a new device. This only initializes the device state structure and allows properties to be set. The device still needs to be realized. See qdev-core.h. */ @@ -141,12 +161,6 @@ DeviceState *qdev_try_create(BusState *bus, const char *type) } if (!bus) { - /* Assert that the device really is a SysBusDevice before - * we put it onto the sysbus. Non-sysbus devices which aren't - * being put onto a bus should be created with object_new(TYPE_FOO), - * not qdev_create(NULL, TYPE_FOO). - */ - g_assert(object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)); bus = sysbus_get_default(); } @@ -354,14 +368,12 @@ void qdev_init_nofail(DeviceState *dev) assert(!dev->realized); - object_ref(OBJECT(dev)); object_property_set_bool(OBJECT(dev), true, "realized", &err); if (err) { error_reportf_err(err, "Initialization of device %s failed: ", object_get_typename(OBJECT(dev))); exit(1); } - object_unref(OBJECT(dev)); } void qdev_machine_creation_done(void) @@ -583,6 +595,40 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name) return NULL; } +int qbus_walk_children(BusState *bus, + qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, + qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, + void *opaque) +{ + BusChild *kid; + int err; + + if (pre_busfn) { + err = pre_busfn(bus, opaque); + if (err) { + return err; + } + } + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + err = qdev_walk_children(kid->child, + pre_devfn, pre_busfn, + post_devfn, post_busfn, opaque); + if (err < 0) { + return err; + } + } + + if (post_busfn) { + err = post_busfn(bus, opaque); + if (err) { + return err; + } + } + + return 0; +} + int qdev_walk_children(DeviceState *dev, qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, @@ -639,6 +685,129 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id) return NULL; } +static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) +{ + const char *typename = object_get_typename(OBJECT(bus)); + BusClass *bc; + char *buf; + int i, len, bus_id; + + bus->parent = parent; + + if (name) { + bus->name = g_strdup(name); + } else if (bus->parent && bus->parent->id) { + /* parent device has id -> use it plus parent-bus-id for bus name */ + bus_id = bus->parent->num_child_bus; + + len = strlen(bus->parent->id) + 16; + buf = g_malloc(len); + snprintf(buf, len, "%s.%d", bus->parent->id, bus_id); + bus->name = buf; + } else { + /* no id -> use lowercase bus type plus global bus-id for bus name */ + bc = BUS_GET_CLASS(bus); + bus_id = bc->automatic_ids++; + + len = strlen(typename) + 16; + buf = g_malloc(len); + len = snprintf(buf, len, "%s.%d", typename, bus_id); + for (i = 0; i < len; i++) { + buf[i] = qemu_tolower(buf[i]); + } + bus->name = buf; + } + + if (bus->parent) { + QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); + bus->parent->num_child_bus++; + object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); + object_unref(OBJECT(bus)); + } else if (bus != sysbus_get_default()) { + /* TODO: once all bus devices are qdevified, + only reset handler for main_system_bus should be registered here. */ + qemu_register_reset(qbus_reset_all_fn, bus); + } +} + +static void bus_unparent(Object *obj) +{ + BusState *bus = BUS(obj); + BusChild *kid; + + while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { + DeviceState *dev = kid->child; + object_unparent(OBJECT(dev)); + } + if (bus->parent) { + QLIST_REMOVE(bus, sibling); + bus->parent->num_child_bus--; + bus->parent = NULL; + } else { + assert(bus != sysbus_get_default()); /* main_system_bus is never freed */ + qemu_unregister_reset(qbus_reset_all_fn, bus); + } +} + +static bool bus_get_realized(Object *obj, Error **errp) +{ + BusState *bus = BUS(obj); + + return bus->realized; +} + +static void bus_set_realized(Object *obj, bool value, Error **errp) +{ + BusState *bus = BUS(obj); + BusClass *bc = BUS_GET_CLASS(bus); + BusChild *kid; + Error *local_err = NULL; + + if (value && !bus->realized) { + if (bc->realize) { + bc->realize(bus, &local_err); + } + + /* TODO: recursive realization */ + } else if (!value && bus->realized) { + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + object_property_set_bool(OBJECT(dev), false, "realized", + &local_err); + if (local_err != NULL) { + break; + } + } + if (bc->unrealize && local_err == NULL) { + bc->unrealize(bus, &local_err); + } + } + + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + + bus->realized = value; +} + +void qbus_create_inplace(void *bus, size_t size, const char *typename, + DeviceState *parent, const char *name) +{ + object_initialize(bus, size, typename); + qbus_realize(bus, parent, name); +} + +BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) +{ + BusState *bus; + + bus = BUS(object_new(typename)); + qbus_realize(bus, parent, name); + + return bus; +} + static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) { BusClass *bc = BUS_GET_CLASS(bus); @@ -739,20 +908,13 @@ static void qdev_get_legacy_property(Object *obj, Visitor *v, } /** - * qdev_property_add_legacy: - * @dev: Device to add the property to. - * @prop: The qdev property definition. - * @errp: location to store error information. + * @qdev_add_legacy_property - adds a legacy property * - * Add a legacy QOM property to @dev for qdev property @prop. - * On error, store error in @errp. + * Do not use this is new code! Properties added through this interface will + * be given names and types in the "legacy" namespace. * - * Legacy properties are string versions of QOM properties. The format of - * the string depends on the property type. Legacy properties are only - * needed for "info qtree". - * - * Do not use this is new code! QOM Properties added through this interface - * will be given names in the "legacy" namespace. + * Legacy properties are string versions of other OOM properties. The format + * of the string depends on the property type. */ static void qdev_property_add_legacy(DeviceState *dev, Property *prop, Error **errp) @@ -775,14 +937,10 @@ static void qdev_property_add_legacy(DeviceState *dev, Property *prop, } /** - * qdev_property_add_static: - * @dev: Device to add the property to. - * @prop: The qdev property definition. - * @errp: location to store error information. + * @qdev_property_add_static - add a @Property to a device. * - * Add a static QOM property to @dev for qdev property @prop. - * On error, store error in @errp. Static properties access data in a struct. - * The type of the QOM property is derived from prop->info. + * Static properties access data in a struct. The actual type of the + * property and the field depends on the property type. */ void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp) @@ -887,8 +1045,6 @@ static void device_set_realized(Object *obj, bool value, Error **errp) HotplugHandler *hotplug_ctrl; BusState *bus; Error *local_err = NULL; - bool unattached_parent = false; - static int unattached_count; if (dev->hotplugged && !dc->hotpluggable) { error_setg(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj)); @@ -897,23 +1053,15 @@ static void device_set_realized(Object *obj, bool value, Error **errp) if (value && !dev->realized) { if (!obj->parent) { + static int unattached_count; gchar *name = g_strdup_printf("device[%d]", unattached_count++); object_property_add_child(container_get(qdev_get_machine(), "/unattached"), name, obj, &error_abort); - unattached_parent = true; g_free(name); } - hotplug_ctrl = qdev_get_hotplug_handler(dev); - if (hotplug_ctrl) { - hotplug_handler_pre_plug(hotplug_ctrl, dev, &local_err); - if (local_err != NULL) { - goto fail; - } - } - if (dc->realize) { dc->realize(dev, &local_err); } @@ -924,6 +1072,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp) DEVICE_LISTENER_CALL(realize, Forward, dev); + hotplug_ctrl = qdev_get_hotplug_handler(dev); if (hotplug_ctrl) { hotplug_handler_plug(hotplug_ctrl, dev, &local_err); } @@ -991,10 +1140,6 @@ post_realize_fail: fail: error_propagate(errp, local_err); - if (unattached_parent) { - object_unparent(OBJECT(dev)); - unattached_count--; - } } static bool device_get_hotpluggable(Object *obj, Error **errp) @@ -1170,8 +1315,55 @@ static const TypeInfo device_type_info = { .class_size = sizeof(DeviceClass), }; +static void qbus_initfn(Object *obj) +{ + BusState *bus = BUS(obj); + + QTAILQ_INIT(&bus->children); + object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY, + TYPE_HOTPLUG_HANDLER, + (Object **)&bus->hotplug_handler, + object_property_allow_set_link, + OBJ_PROP_LINK_UNREF_ON_RELEASE, + NULL); + object_property_add_bool(obj, "realized", + bus_get_realized, bus_set_realized, NULL); +} + +static char *default_bus_get_fw_dev_path(DeviceState *dev) +{ + return g_strdup(object_get_typename(OBJECT(dev))); +} + +static void bus_class_init(ObjectClass *class, void *data) +{ + BusClass *bc = BUS_CLASS(class); + + class->unparent = bus_unparent; + bc->get_fw_dev_path = default_bus_get_fw_dev_path; +} + +static void qbus_finalize(Object *obj) +{ + BusState *bus = BUS(obj); + + g_free((char *)bus->name); +} + +static const TypeInfo bus_info = { + .name = TYPE_BUS, + .parent = TYPE_OBJECT, + .instance_size = sizeof(BusState), + .abstract = true, + .class_size = sizeof(BusClass), + .instance_init = qbus_initfn, + .instance_finalize = qbus_finalize, + .class_init = bus_class_init, +}; + static void qdev_register_types(void) { + type_register_static(&bus_info); type_register_static(&device_type_info); } diff --git a/hw/core/register.c b/hw/core/register.c deleted file mode 100644 index 4bfbc508d..000000000 --- a/hw/core/register.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Register Definition API - * - * Copyright (c) 2016 Xilinx Inc. - * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "qemu/osdep.h" -#include "hw/register.h" -#include "hw/qdev.h" -#include "qemu/log.h" - -static inline void register_write_val(RegisterInfo *reg, uint64_t val) -{ - g_assert(reg->data); - - switch (reg->data_size) { - case 1: - *(uint8_t *)reg->data = val; - break; - case 2: - *(uint16_t *)reg->data = val; - break; - case 4: - *(uint32_t *)reg->data = val; - break; - case 8: - *(uint64_t *)reg->data = val; - break; - default: - g_assert_not_reached(); - } -} - -static inline uint64_t register_read_val(RegisterInfo *reg) -{ - switch (reg->data_size) { - case 1: - return *(uint8_t *)reg->data; - case 2: - return *(uint16_t *)reg->data; - case 4: - return *(uint32_t *)reg->data; - case 8: - return *(uint64_t *)reg->data; - default: - g_assert_not_reached(); - } - return 0; /* unreachable */ -} - -void register_write(RegisterInfo *reg, uint64_t val, uint64_t we, - const char *prefix, bool debug) -{ - uint64_t old_val, new_val, test, no_w_mask; - const RegisterAccessInfo *ac; - - assert(reg); - - ac = reg->access; - - if (!ac || !ac->name) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state " - "(written value: %#" PRIx64 ")\n", prefix, val); - return; - } - - old_val = reg->data ? register_read_val(reg) : ac->reset; - - test = (old_val ^ val) & ac->rsvd; - if (test) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: change of value in reserved bit" - "fields: %#" PRIx64 ")\n", prefix, test); - } - - test = val & ac->unimp; - if (test) { - qemu_log_mask(LOG_UNIMP, - "%s:%s writing %#" PRIx64 " to unimplemented bits:" \ - " %#" PRIx64 "", - prefix, reg->access->name, val, ac->unimp); - } - - /* Create the no write mask based on the read only, write to clear and - * reserved bit masks. - */ - no_w_mask = ac->ro | ac->w1c | ac->rsvd | ~we; - new_val = (val & ~no_w_mask) | (old_val & no_w_mask); - new_val &= ~(val & ac->w1c); - - if (ac->pre_write) { - new_val = ac->pre_write(reg, new_val); - } - - if (debug) { - qemu_log("%s:%s: write of value %#" PRIx64 "\n", prefix, ac->name, - new_val); - } - - register_write_val(reg, new_val); - - if (ac->post_write) { - ac->post_write(reg, new_val); - } -} - -uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix, - bool debug) -{ - uint64_t ret; - const RegisterAccessInfo *ac; - - assert(reg); - - ac = reg->access; - if (!ac || !ac->name) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: read from undefined device state\n", - prefix); - return 0; - } - - ret = reg->data ? register_read_val(reg) : ac->reset; - - register_write_val(reg, ret & ~(ac->cor & re)); - - /* Mask based on the read enable size */ - ret &= re; - - if (ac->post_read) { - ret = ac->post_read(reg, ret); - } - - if (debug) { - qemu_log("%s:%s: read of value %#" PRIx64 "\n", prefix, - ac->name, ret); - } - - return ret; -} - -void register_reset(RegisterInfo *reg) -{ - g_assert(reg); - - if (!reg->data || !reg->access) { - return; - } - - register_write_val(reg, reg->access->reset); -} - -void register_init(RegisterInfo *reg) -{ - assert(reg); - - if (!reg->data || !reg->access) { - return; - } - - object_initialize((void *)reg, sizeof(*reg), TYPE_REGISTER); -} - -void register_write_memory(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - RegisterInfoArray *reg_array = opaque; - RegisterInfo *reg = NULL; - uint64_t we; - int i; - - for (i = 0; i < reg_array->num_elements; i++) { - if (reg_array->r[i]->access->addr == addr) { - reg = reg_array->r[i]; - break; - } - } - - if (!reg) { - qemu_log_mask(LOG_GUEST_ERROR, "Write to unimplemented register at " \ - "address: %#" PRIx64 "\n", addr); - return; - } - - /* Generate appropriate write enable mask */ - if (reg->data_size < size) { - we = MAKE_64BIT_MASK(0, reg->data_size * 8); - } else { - we = MAKE_64BIT_MASK(0, size * 8); - } - - register_write(reg, value, we, reg_array->prefix, - reg_array->debug); -} - -uint64_t register_read_memory(void *opaque, hwaddr addr, - unsigned size) -{ - RegisterInfoArray *reg_array = opaque; - RegisterInfo *reg = NULL; - uint64_t read_val; - int i; - - for (i = 0; i < reg_array->num_elements; i++) { - if (reg_array->r[i]->access->addr == addr) { - reg = reg_array->r[i]; - break; - } - } - - if (!reg) { - qemu_log_mask(LOG_GUEST_ERROR, "Read to unimplemented register at " \ - "address: %#" PRIx64 "\n", addr); - return 0; - } - - read_val = register_read(reg, size * 8, reg_array->prefix, - reg_array->debug); - - return extract64(read_val, 0, size * 8); -} - -RegisterInfoArray *register_init_block32(DeviceState *owner, - const RegisterAccessInfo *rae, - int num, RegisterInfo *ri, - uint32_t *data, - const MemoryRegionOps *ops, - bool debug_enabled, - uint64_t memory_size) -{ - const char *device_prefix = object_get_typename(OBJECT(owner)); - RegisterInfoArray *r_array = g_new0(RegisterInfoArray, 1); - int i; - - r_array->r = g_new0(RegisterInfo *, num); - r_array->num_elements = num; - r_array->debug = debug_enabled; - r_array->prefix = device_prefix; - - for (i = 0; i < num; i++) { - int index = rae[i].addr / 4; - RegisterInfo *r = &ri[index]; - - *r = (RegisterInfo) { - .data = &data[index], - .data_size = sizeof(uint32_t), - .access = &rae[i], - .opaque = owner, - }; - register_init(r); - - r_array->r[i] = r; - } - - memory_region_init_io(&r_array->mem, OBJECT(owner), ops, r_array, - device_prefix, memory_size); - - return r_array; -} - -void register_finalize_block(RegisterInfoArray *r_array) -{ - object_unparent(OBJECT(&r_array->mem)); - g_free(r_array->r); - g_free(r_array); -} - -static const TypeInfo register_info = { - .name = TYPE_REGISTER, - .parent = TYPE_DEVICE, -}; - -static void register_register_types(void) -{ - type_register_static(®ister_info); -} - -type_init(register_register_types) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index c0f560b28..a7dbe2b32 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -190,9 +190,9 @@ MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n) return dev->mmio[n].memory; } -void sysbus_init_ioports(SysBusDevice *dev, uint32_t ioport, uint32_t size) +void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size) { - uint32_t i; + pio_addr_t i; for (i = 0; i < size; i++) { assert(dev->num_pio < QDEV_MAX_PIO); diff --git a/hw/core/uboot_image.h b/hw/core/uboot_image.h index 34c11a70a..9fc2760b5 100644 --- a/hw/core/uboot_image.h +++ b/hw/core/uboot_image.h @@ -26,8 +26,8 @@ ******************************************************************** */ -#ifndef UBOOT_IMAGE_H -#define UBOOT_IMAGE_H +#ifndef __UBOOT_IMAGE_H__ +#define __UBOOT_IMAGE_H__ /* * Operating System Codes @@ -155,4 +155,4 @@ typedef struct uboot_image_header { } uboot_image_header_t; -#endif /* UBOOT_IMAGE_H */ +#endif /* __IMAGE_H__ */ diff --git a/hw/cpu/Makefile.objs b/hw/cpu/Makefile.objs index 942a4bb82..0954a1872 100644 --- a/hw/cpu/Makefile.objs +++ b/hw/cpu/Makefile.objs @@ -2,5 +2,4 @@ obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o obj-$(CONFIG_REALVIEW) += realview_mpcore.o obj-$(CONFIG_A9MPCORE) += a9mpcore.o obj-$(CONFIG_A15MPCORE) += a15mpcore.o -obj-y += core.o diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c index f17f29209..5459ae8c1 100644 --- a/hw/cpu/a9mpcore.c +++ b/hw/cpu/a9mpcore.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/cpu/a9mpcore.h" -#include "qom/cpu.h" static void a9mp_priv_set_irq(void *opaque, int irq, int level) { diff --git a/hw/cpu/core.c b/hw/cpu/core.c deleted file mode 100644 index eff90c12b..000000000 --- a/hw/cpu/core.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * CPU core abstract device - * - * Copyright (C) 2016 Bharata B Rao <bharata@linux.vnet.ibm.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 "hw/cpu/core.h" -#include "qapi/visitor.h" -#include "qapi/error.h" -#include "sysemu/cpus.h" - -static void core_prop_get_core_id(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - CPUCore *core = CPU_CORE(obj); - int64_t value = core->core_id; - - visit_type_int(v, name, &value, errp); -} - -static void core_prop_set_core_id(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - CPUCore *core = CPU_CORE(obj); - Error *local_err = NULL; - int64_t value; - - visit_type_int(v, name, &value, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - core->core_id = value; -} - -static void core_prop_get_nr_threads(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - CPUCore *core = CPU_CORE(obj); - int64_t value = core->nr_threads; - - visit_type_int(v, name, &value, errp); -} - -static void core_prop_set_nr_threads(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - CPUCore *core = CPU_CORE(obj); - Error *local_err = NULL; - int64_t value; - - visit_type_int(v, name, &value, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - core->nr_threads = value; -} - -static void cpu_core_instance_init(Object *obj) -{ - CPUCore *core = CPU_CORE(obj); - - object_property_add(obj, "core-id", "int", core_prop_get_core_id, - core_prop_set_core_id, NULL, NULL, NULL); - object_property_add(obj, "nr-threads", "int", core_prop_get_nr_threads, - core_prop_set_nr_threads, NULL, NULL, NULL); - core->nr_threads = smp_threads; -} - -static const TypeInfo cpu_core_type_info = { - .name = TYPE_CPU_CORE, - .parent = TYPE_DEVICE, - .abstract = true, - .instance_size = sizeof(CPUCore), - .instance_init = cpu_core_instance_init, -}; - -static void cpu_core_register_types(void) -{ - type_register_static(&cpu_core_type_info); -} - -type_init(cpu_core_register_types) diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c index 60df8877c..9f5865874 100644 --- a/hw/cris/axis_dev88.c +++ b/hw/cris/axis_dev88.c @@ -37,7 +37,6 @@ #include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" -#include "sysemu/sysemu.h" #define D(x) #define DNAND(x) @@ -342,7 +341,8 @@ void axisdev88_init(MachineState *machine) sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL); for (i = 0; i < 4; i++) { - etraxfs_ser_create(0x30026000 + i * 0x2000, irq[0x14 + i], serial_hds[i]); + sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000, + irq[0x14 + i]); } if (kernel_filename) { diff --git a/hw/cris/boot.h b/hw/cris/boot.h index 218854e5d..c4d3fa6f6 100644 --- a/hw/cris/boot.h +++ b/hw/cris/boot.h @@ -1,5 +1,5 @@ -#ifndef HW_CRIS_BOOT_H -#define HW_CRIS_BOOT_H +#ifndef _CRIS_BOOT_H +#define HW_CRIS_BOOT_H 1 struct cris_load_info { diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs index 063889bea..d99780eeb 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -43,5 +43,3 @@ virtio-gpu.o-cflags := $(VIRGL_CFLAGS) virtio-gpu.o-libs += $(VIRGL_LIBS) virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS) virtio-gpu-3d.o-libs += $(VIRGL_LIBS) -obj-$(CONFIG_DPCD) += dpcd.o -obj-$(CONFIG_XLNX_ZYNQMP) += xlnx_dp.o diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c index 166edade7..05aa2d1e6 100644 --- a/hw/display/ads7846.c +++ b/hw/display/ads7846.c @@ -133,7 +133,7 @@ static const VMStateDescription vmstate_ads7846 = { } }; -static void ads7846_realize(SSISlave *d, Error **errp) +static int ads7846_init(SSISlave *d) { DeviceState *dev = DEVICE(d); ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, d); @@ -152,13 +152,14 @@ static void ads7846_realize(SSISlave *d, Error **errp) ads7846_int_update(s); vmstate_register(NULL, -1, &vmstate_ads7846, s); + return 0; } static void ads7846_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->realize = ads7846_realize; + k->init = ads7846_init; k->transfer = ads7846_transfer; } diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c index 7eab92765..506f1d3d9 100644 --- a/hw/display/bcm2835_fb.c +++ b/hw/display/bcm2835_fb.c @@ -29,7 +29,6 @@ #include "hw/display/framebuffer.h" #include "ui/pixel_ops.h" #include "hw/misc/bcm2835_mbox_defs.h" -#include "qemu/log.h" #define DEFAULT_VCRAM_SIZE 0x4000000 #define BCM2835_FB_OFFSET 0x00100000 diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c index cbf07d14d..c231960d9 100644 --- a/hw/display/blizzard.c +++ b/hw/display/blizzard.c @@ -925,83 +925,16 @@ static void blizzard_update_display(void *opaque) s->my[1] = 0; } -static void blizzard_draw_line16_32(uint32_t *dest, - const uint16_t *src, unsigned int width) -{ - uint16_t data; - unsigned int r, g, b; - const uint16_t *end = (const void *) src + width; - while (src < end) { - data = *src ++; - b = (data & 0x1f) << 3; - data >>= 5; - g = (data & 0x3f) << 2; - data >>= 6; - r = (data & 0x1f) << 3; - data >>= 5; - *dest++ = rgb_to_pixel32(r, g, b); - } -} - -static void blizzard_draw_line24mode1_32(uint32_t *dest, - const uint8_t *src, unsigned int width) -{ - /* TODO: check if SDL 24-bit planes are not in the same format and - * if so, use memcpy */ - unsigned int r[2], g[2], b[2]; - const uint8_t *end = src + width; - while (src < end) { - g[0] = *src ++; - r[0] = *src ++; - r[1] = *src ++; - b[0] = *src ++; - *dest++ = rgb_to_pixel32(r[0], g[0], b[0]); - b[1] = *src ++; - g[1] = *src ++; - *dest++ = rgb_to_pixel32(r[1], g[1], b[1]); - } -} - -static void blizzard_draw_line24mode2_32(uint32_t *dest, - const uint8_t *src, unsigned int width) -{ - unsigned int r, g, b; - const uint8_t *end = src + width; - while (src < end) { - r = *src ++; - src ++; - b = *src ++; - g = *src ++; - *dest++ = rgb_to_pixel32(r, g, b); - } -} - -/* No rotation */ -static blizzard_fn_t blizzard_draw_fn_32[0x10] = { - NULL, - /* RGB 5:6:5*/ - (blizzard_fn_t) blizzard_draw_line16_32, - /* RGB 6:6:6 mode 1 */ - (blizzard_fn_t) blizzard_draw_line24mode1_32, - /* RGB 8:8:8 mode 1 */ - (blizzard_fn_t) blizzard_draw_line24mode1_32, - NULL, NULL, - /* RGB 6:6:6 mode 2 */ - (blizzard_fn_t) blizzard_draw_line24mode2_32, - /* RGB 8:8:8 mode 2 */ - (blizzard_fn_t) blizzard_draw_line24mode2_32, - /* YUV 4:2:2 */ - NULL, - /* YUV 4:2:0 */ - NULL, - NULL, NULL, NULL, NULL, NULL, NULL, -}; - -/* 90deg, 180deg and 270deg rotation */ -static blizzard_fn_t blizzard_draw_fn_r_32[0x10] = { - /* TODO */ - [0 ... 0xf] = NULL, -}; +#define DEPTH 8 +#include "blizzard_template.h" +#define DEPTH 15 +#include "blizzard_template.h" +#define DEPTH 16 +#include "blizzard_template.h" +#define DEPTH 24 +#include "blizzard_template.h" +#define DEPTH 32 +#include "blizzard_template.h" static const GraphicHwOps blizzard_ops = { .invalidate = blizzard_invalidate_display, @@ -1018,10 +951,35 @@ void *s1d13745_init(qemu_irq gpio_int) s->con = graphic_console_init(NULL, 0, &blizzard_ops, s); surface = qemu_console_surface(s->con); - assert(surface_bits_per_pixel(surface) == 32); - - s->line_fn_tab[0] = blizzard_draw_fn_32; - s->line_fn_tab[1] = blizzard_draw_fn_r_32; + switch (surface_bits_per_pixel(surface)) { + case 0: + s->line_fn_tab[0] = s->line_fn_tab[1] = + g_malloc0(sizeof(blizzard_fn_t) * 0x10); + break; + case 8: + s->line_fn_tab[0] = blizzard_draw_fn_8; + s->line_fn_tab[1] = blizzard_draw_fn_r_8; + break; + case 15: + s->line_fn_tab[0] = blizzard_draw_fn_15; + s->line_fn_tab[1] = blizzard_draw_fn_r_15; + break; + case 16: + s->line_fn_tab[0] = blizzard_draw_fn_16; + s->line_fn_tab[1] = blizzard_draw_fn_r_16; + break; + case 24: + s->line_fn_tab[0] = blizzard_draw_fn_24; + s->line_fn_tab[1] = blizzard_draw_fn_r_24; + break; + case 32: + s->line_fn_tab[0] = blizzard_draw_fn_32; + s->line_fn_tab[1] = blizzard_draw_fn_r_32; + break; + default: + fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__); + exit(1); + } blizzard_reset(s); diff --git a/hw/display/blizzard_template.h b/hw/display/blizzard_template.h new file mode 100644 index 000000000..b7ef27c80 --- /dev/null +++ b/hw/display/blizzard_template.h @@ -0,0 +1,146 @@ +/* + * QEMU Epson S1D13744/S1D13745 templates + * + * Copyright (C) 2008 Nokia Corporation + * Written by Andrzej Zaborowski <andrew@openedhand.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#define SKIP_PIXEL(to) (to += deststep) +#if DEPTH == 8 +# define PIXEL_TYPE uint8_t +# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0) +# define COPY_PIXEL1(to, from) (*to++ = from) +#elif DEPTH == 15 || DEPTH == 16 +# define PIXEL_TYPE uint16_t +# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0) +# define COPY_PIXEL1(to, from) (*to++ = from) +#elif DEPTH == 24 +# define PIXEL_TYPE uint8_t +# define COPY_PIXEL(to, from) \ + do { \ + to[0] = from; \ + to[1] = (from) >> 8; \ + to[2] = (from) >> 16; \ + SKIP_PIXEL(to); \ + } while (0) + +# define COPY_PIXEL1(to, from) \ + do { \ + *to++ = from; \ + *to++ = (from) >> 8; \ + *to++ = (from) >> 16; \ + } while (0) +#elif DEPTH == 32 +# define PIXEL_TYPE uint32_t +# define COPY_PIXEL(to, from) do { *to = from; SKIP_PIXEL(to); } while (0) +# define COPY_PIXEL1(to, from) (*to++ = from) +#else +# error unknown bit depth +#endif + +#ifdef HOST_WORDS_BIGENDIAN +# define SWAP_WORDS 1 +#endif + +static void glue(blizzard_draw_line16_, DEPTH)(PIXEL_TYPE *dest, + const uint16_t *src, unsigned int width) +{ +#if !defined(SWAP_WORDS) && DEPTH == 16 + memcpy(dest, src, width); +#else + uint16_t data; + unsigned int r, g, b; + const uint16_t *end = (const void *) src + width; + while (src < end) { + data = *src ++; + b = (data & 0x1f) << 3; + data >>= 5; + g = (data & 0x3f) << 2; + data >>= 6; + r = (data & 0x1f) << 3; + data >>= 5; + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b)); + } +#endif +} + +static void glue(blizzard_draw_line24mode1_, DEPTH)(PIXEL_TYPE *dest, + const uint8_t *src, unsigned int width) +{ + /* TODO: check if SDL 24-bit planes are not in the same format and + * if so, use memcpy */ + unsigned int r[2], g[2], b[2]; + const uint8_t *end = src + width; + while (src < end) { + g[0] = *src ++; + r[0] = *src ++; + r[1] = *src ++; + b[0] = *src ++; + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[0], g[0], b[0])); + b[1] = *src ++; + g[1] = *src ++; + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[1], g[1], b[1])); + } +} + +static void glue(blizzard_draw_line24mode2_, DEPTH)(PIXEL_TYPE *dest, + const uint8_t *src, unsigned int width) +{ + unsigned int r, g, b; + const uint8_t *end = src + width; + while (src < end) { + r = *src ++; + src ++; + b = *src ++; + g = *src ++; + COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b)); + } +} + +/* No rotation */ +static blizzard_fn_t glue(blizzard_draw_fn_, DEPTH)[0x10] = { + NULL, + /* RGB 5:6:5*/ + (blizzard_fn_t) glue(blizzard_draw_line16_, DEPTH), + /* RGB 6:6:6 mode 1 */ + (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH), + /* RGB 8:8:8 mode 1 */ + (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH), + NULL, NULL, + /* RGB 6:6:6 mode 2 */ + (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH), + /* RGB 8:8:8 mode 2 */ + (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH), + /* YUV 4:2:2 */ + NULL, + /* YUV 4:2:0 */ + NULL, + NULL, NULL, NULL, NULL, NULL, NULL, +}; + +/* 90deg, 180deg and 270deg rotation */ +static blizzard_fn_t glue(blizzard_draw_fn_r_, DEPTH)[0x10] = { + /* TODO */ + [0 ... 0xf] = NULL, +}; + +#undef DEPTH +#undef SKIP_PIXEL +#undef COPY_PIXEL +#undef COPY_PIXEL1 +#undef PIXEL_TYPE + +#undef SWAP_WORDS diff --git a/hw/display/cg3.c b/hw/display/cg3.c index 117422039..fc0d97fa4 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -26,12 +26,10 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" -#include "cpu.h" #include "qemu/error-report.h" #include "ui/console.h" #include "hw/sysbus.h" #include "hw/loader.h" -#include "qemu/log.h" /* Change to 1 to enable debugging */ #define DEBUG_CG3 0 diff --git a/hw/display/dpcd.c b/hw/display/dpcd.c deleted file mode 100644 index ce92ff6e2..000000000 --- a/hw/display/dpcd.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * dpcd.c - * - * Copyright (C) 2015 : GreenSocs Ltd - * http://www.greensocs.com/ , email: info@greensocs.com - * - * Developed by : - * Frederic Konrad <fred.konrad@greensocs.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option)any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - * - */ - -/* - * This is a simple AUX slave which emulates a connected screen. - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "hw/misc/auxbus.h" -#include "hw/display/dpcd.h" - -#ifndef DEBUG_DPCD -#define DEBUG_DPCD 0 -#endif - -#define DPRINTF(fmt, ...) do { \ - if (DEBUG_DPCD) { \ - qemu_log("dpcd: " fmt, ## __VA_ARGS__); \ - } \ -} while (0); - -#define DPCD_READABLE_AREA 0x600 - -struct DPCDState { - /*< private >*/ - AUXSlave parent_obj; - - /*< public >*/ - /* - * The DCPD is 0x7FFFF length but read as 0 after offset 0x5FF. - */ - uint8_t dpcd_info[DPCD_READABLE_AREA]; - - MemoryRegion iomem; -}; - -static uint64_t dpcd_read(void *opaque, hwaddr offset, unsigned size) -{ - uint8_t ret; - DPCDState *e = DPCD(opaque); - - if (offset < DPCD_READABLE_AREA) { - ret = e->dpcd_info[offset]; - } else { - qemu_log_mask(LOG_GUEST_ERROR, "dpcd: Bad offset 0x%" HWADDR_PRIX "\n", - offset); - ret = 0; - } - - DPRINTF("read 0x%" PRIX8 " @0x%" HWADDR_PRIX "\n", ret, offset); - return ret; -} - -static void dpcd_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - DPCDState *e = DPCD(opaque); - - DPRINTF("write 0x%" PRIX8 " @0x%" HWADDR_PRIX "\n", (uint8_t)value, offset); - - if (offset < DPCD_READABLE_AREA) { - e->dpcd_info[offset] = value; - } else { - qemu_log_mask(LOG_GUEST_ERROR, "dpcd: Bad offset 0x%" HWADDR_PRIX "\n", - offset); - } -} - -static const MemoryRegionOps aux_ops = { - .read = dpcd_read, - .write = dpcd_write, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static void dpcd_reset(DeviceState *dev) -{ - DPCDState *s = DPCD(dev); - - memset(&(s->dpcd_info), 0, sizeof(s->dpcd_info)); - - s->dpcd_info[DPCD_REVISION] = DPCD_REV_1_0; - s->dpcd_info[DPCD_MAX_LINK_RATE] = DPCD_5_4GBPS; - s->dpcd_info[DPCD_MAX_LANE_COUNT] = DPCD_FOUR_LANES; - s->dpcd_info[DPCD_RECEIVE_PORT0_CAP_0] = DPCD_EDID_PRESENT; - /* buffer size */ - s->dpcd_info[DPCD_RECEIVE_PORT0_CAP_1] = 0xFF; - - s->dpcd_info[DPCD_LANE0_1_STATUS] = DPCD_LANE0_CR_DONE - | DPCD_LANE0_CHANNEL_EQ_DONE - | DPCD_LANE0_SYMBOL_LOCKED - | DPCD_LANE1_CR_DONE - | DPCD_LANE1_CHANNEL_EQ_DONE - | DPCD_LANE1_SYMBOL_LOCKED; - s->dpcd_info[DPCD_LANE2_3_STATUS] = DPCD_LANE2_CR_DONE - | DPCD_LANE2_CHANNEL_EQ_DONE - | DPCD_LANE2_SYMBOL_LOCKED - | DPCD_LANE3_CR_DONE - | DPCD_LANE3_CHANNEL_EQ_DONE - | DPCD_LANE3_SYMBOL_LOCKED; - - s->dpcd_info[DPCD_LANE_ALIGN_STATUS_UPDATED] = DPCD_INTERLANE_ALIGN_DONE; - s->dpcd_info[DPCD_SINK_STATUS] = DPCD_RECEIVE_PORT_0_STATUS; -} - -static void dpcd_init(Object *obj) -{ - DPCDState *s = DPCD(obj); - - memory_region_init_io(&s->iomem, obj, &aux_ops, s, TYPE_DPCD, 0x7FFFF); - aux_init_mmio(AUX_SLAVE(obj), &s->iomem); -} - -static const VMStateDescription vmstate_dpcd = { - .name = TYPE_DPCD, - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT8_ARRAY_V(dpcd_info, DPCDState, DPCD_READABLE_AREA, 0), - VMSTATE_END_OF_LIST() - } -}; - -static void dpcd_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->reset = dpcd_reset; - dc->vmsd = &vmstate_dpcd; -} - -static const TypeInfo dpcd_info = { - .name = TYPE_DPCD, - .parent = TYPE_AUX_SLAVE, - .instance_size = sizeof(DPCDState), - .class_init = dpcd_class_init, - .instance_init = dpcd_init, -}; - -static void dpcd_register_types(void) -{ - type_register_static(&dpcd_info); -} - -type_init(dpcd_register_types) diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index e5be71340..728eb214a 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -1909,10 +1909,9 @@ static const GraphicHwOps exynos4210_fimd_ops = { .gfx_update = exynos4210_fimd_update, }; -static void exynos4210_fimd_init(Object *obj) +static int exynos4210_fimd_init(SysBusDevice *dev) { - Exynos4210fimdState *s = EXYNOS4210_FIMD(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + Exynos4210fimdState *s = EXYNOS4210_FIMD(dev); s->ifb = NULL; @@ -1920,32 +1919,28 @@ static void exynos4210_fimd_init(Object *obj) sysbus_init_irq(dev, &s->irq[1]); sysbus_init_irq(dev, &s->irq[2]); - memory_region_init_io(&s->iomem, obj, &exynos4210_fimd_mmio_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s, "exynos4210.fimd", FIMD_REGS_SIZE); sysbus_init_mmio(dev, &s->iomem); -} - -static void exynos4210_fimd_realize(DeviceState *dev, Error **errp) -{ - Exynos4210fimdState *s = EXYNOS4210_FIMD(dev); + s->console = graphic_console_init(DEVICE(dev), 0, &exynos4210_fimd_ops, s); - s->console = graphic_console_init(dev, 0, &exynos4210_fimd_ops, s); + return 0; } static void exynos4210_fimd_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); dc->vmsd = &exynos4210_fimd_vmstate; dc->reset = exynos4210_fimd_reset; - dc->realize = exynos4210_fimd_realize; + k->init = exynos4210_fimd_init; } static const TypeInfo exynos4210_fimd_info = { .name = TYPE_EXYNOS4210_FIMD, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210fimdState), - .instance_init = exynos4210_fimd_init, .class_init = exynos4210_fimd_class_init, }; diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c index b72fdb171..09dcdb46a 100644 --- a/hw/display/jazz_led.c +++ b/hw/display/jazz_led.c @@ -267,20 +267,16 @@ static const GraphicHwOps jazz_led_ops = { .text_update = jazz_led_text_update, }; -static void jazz_led_init(Object *obj) +static int jazz_led_init(SysBusDevice *dev) { - LedState *s = JAZZ_LED(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + LedState *s = JAZZ_LED(dev); - memory_region_init_io(&s->iomem, obj, &led_ops, s, "led", 1); + memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1); sysbus_init_mmio(dev, &s->iomem); -} -static void jazz_led_realize(DeviceState *dev, Error **errp) -{ - LedState *s = JAZZ_LED(dev); + s->con = graphic_console_init(DEVICE(dev), 0, &jazz_led_ops, s); - s->con = graphic_console_init(dev, 0, &jazz_led_ops, s); + return 0; } static void jazz_led_reset(DeviceState *d) @@ -295,18 +291,18 @@ static void jazz_led_reset(DeviceState *d) static void jazz_led_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = jazz_led_init; dc->desc = "Jazz LED display", dc->vmsd = &vmstate_jazz_led; dc->reset = jazz_led_reset; - dc->realize = jazz_led_realize; } static const TypeInfo jazz_led_info = { .name = TYPE_JAZZ_LED, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LedState), - .instance_init = jazz_led_init, .class_init = jazz_led_class_init, }; diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c index 9c0018448..9bc88f93b 100644 --- a/hw/display/milkymist-tmu2.c +++ b/hw/display/milkymist-tmu2.c @@ -20,7 +20,7 @@ * * * Specification available at: - * http://milkymist.walle.cc/socdoc/tmu2.pdf + * http://www.milkymist.org/socdoc/tmu2.pdf * */ @@ -29,7 +29,6 @@ #include "hw/sysbus.h" #include "trace.h" #include "qemu/error-report.h" -#include "qapi/error.h" #include <X11/Xlib.h> #include <epoxy/gl.h> @@ -444,25 +443,21 @@ static void milkymist_tmu2_reset(DeviceState *d) } } -static void milkymist_tmu2_init(Object *obj) +static int milkymist_tmu2_init(SysBusDevice *dev) { - MilkymistTMU2State *s = MILKYMIST_TMU2(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + MilkymistTMU2State *s = MILKYMIST_TMU2(dev); + + if (tmu2_glx_init(s)) { + return 1; + } sysbus_init_irq(dev, &s->irq); - memory_region_init_io(&s->regs_region, obj, &tmu2_mmio_ops, s, + memory_region_init_io(&s->regs_region, OBJECT(s), &tmu2_mmio_ops, s, "milkymist-tmu2", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); -} -static void milkymist_tmu2_realize(DeviceState *dev, Error **errp) -{ - MilkymistTMU2State *s = MILKYMIST_TMU2(dev); - - if (tmu2_glx_init(s)) { - error_setg(errp, "tmu2_glx_init failed"); - } + return 0; } static const VMStateDescription vmstate_milkymist_tmu2 = { @@ -478,8 +473,9 @@ static const VMStateDescription vmstate_milkymist_tmu2 = { static void milkymist_tmu2_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - dc->realize = milkymist_tmu2_realize; + k->init = milkymist_tmu2_init; dc->reset = milkymist_tmu2_reset; dc->vmsd = &vmstate_milkymist_tmu2; } @@ -488,7 +484,6 @@ static const TypeInfo milkymist_tmu2_info = { .name = TYPE_MILKYMIST_TMU2, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistTMU2State), - .instance_init = milkymist_tmu2_init, .class_init = milkymist_tmu2_class_init, }; diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c index 177fdac7d..19ca25647 100644 --- a/hw/display/milkymist-vgafb.c +++ b/hw/display/milkymist-vgafb.c @@ -19,7 +19,7 @@ * * * Specification available at: - * http://milkymist.walle.cc/socdoc/vgafb.pdf + * http://www.milkymist.org/socdoc/vgafb.pdf */ #include "qemu/osdep.h" @@ -292,21 +292,17 @@ static const GraphicHwOps vgafb_ops = { .gfx_update = vgafb_update_display, }; -static void milkymist_vgafb_init(Object *obj) +static int milkymist_vgafb_init(SysBusDevice *dev) { - MilkymistVgafbState *s = MILKYMIST_VGAFB(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + MilkymistVgafbState *s = MILKYMIST_VGAFB(dev); memory_region_init_io(&s->regs_region, OBJECT(s), &vgafb_mmio_ops, s, "milkymist-vgafb", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); -} -static void milkymist_vgafb_realize(DeviceState *dev, Error **errp) -{ - MilkymistVgafbState *s = MILKYMIST_VGAFB(dev); + s->con = graphic_console_init(DEVICE(dev), 0, &vgafb_ops, s); - s->con = graphic_console_init(dev, 0, &vgafb_ops, s); + return 0; } static int vgafb_post_load(void *opaque, int version_id) @@ -335,18 +331,18 @@ static Property milkymist_vgafb_properties[] = { static void milkymist_vgafb_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = milkymist_vgafb_init; dc->reset = milkymist_vgafb_reset; dc->vmsd = &vmstate_milkymist_vgafb; dc->props = milkymist_vgafb_properties; - dc->realize = milkymist_vgafb_realize; } static const TypeInfo milkymist_vgafb_info = { .name = TYPE_MILKYMIST_VGAFB, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistVgafbState), - .instance_init = milkymist_vgafb_init, .class_init = milkymist_vgafb_class_init, }; diff --git a/hw/display/omap_lcd_template.h b/hw/display/omap_lcd_template.h index 1025ff382..f0ce71fd6 100644 --- a/hw/display/omap_lcd_template.h +++ b/hw/display/omap_lcd_template.h @@ -27,7 +27,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if DEPTH == 32 +#if DEPTH == 8 +# define BPP 1 +# define PIXEL_TYPE uint8_t +#elif DEPTH == 15 || DEPTH == 16 +# define BPP 2 +# define PIXEL_TYPE uint16_t +#elif DEPTH == 32 # define BPP 4 # define PIXEL_TYPE uint32_t #else @@ -146,7 +152,7 @@ static void glue(draw_line12_, DEPTH)(void *opaque, static void glue(draw_line16_, DEPTH)(void *opaque, uint8_t *d, const uint8_t *s, int width, int deststep) { -#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) +#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) memcpy(d, s, width * 2); #else uint16_t v; diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c index 07a5effe0..ce1058bf8 100644 --- a/hw/display/omap_lcdc.c +++ b/hw/display/omap_lcdc.c @@ -71,9 +71,47 @@ static void omap_lcd_interrupts(struct omap_lcd_panel_s *s) #define draw_line_func drawfn +#define DEPTH 8 +#include "omap_lcd_template.h" +#define DEPTH 15 +#include "omap_lcd_template.h" +#define DEPTH 16 +#include "omap_lcd_template.h" #define DEPTH 32 #include "omap_lcd_template.h" +static draw_line_func draw_line_table2[33] = { + [0 ... 32] = NULL, + [8] = draw_line2_8, + [15] = draw_line2_15, + [16] = draw_line2_16, + [32] = draw_line2_32, +}, draw_line_table4[33] = { + [0 ... 32] = NULL, + [8] = draw_line4_8, + [15] = draw_line4_15, + [16] = draw_line4_16, + [32] = draw_line4_32, +}, draw_line_table8[33] = { + [0 ... 32] = NULL, + [8] = draw_line8_8, + [15] = draw_line8_15, + [16] = draw_line8_16, + [32] = draw_line8_32, +}, draw_line_table12[33] = { + [0 ... 32] = NULL, + [8] = draw_line12_8, + [15] = draw_line12_15, + [16] = draw_line12_16, + [32] = draw_line12_32, +}, draw_line_table16[33] = { + [0 ... 32] = NULL, + [8] = draw_line16_8, + [15] = draw_line16_15, + [16] = draw_line16_16, + [32] = draw_line16_32, +}; + static void omap_update_display(void *opaque) { struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque; @@ -105,25 +143,25 @@ static void omap_update_display(void *opaque) /* Colour depth */ switch ((omap_lcd->palette[0] >> 12) & 7) { case 1: - draw_line = draw_line2_32; + draw_line = draw_line_table2[surface_bits_per_pixel(surface)]; bpp = 2; break; case 2: - draw_line = draw_line4_32; + draw_line = draw_line_table4[surface_bits_per_pixel(surface)]; bpp = 4; break; case 3: - draw_line = draw_line8_32; + draw_line = draw_line_table8[surface_bits_per_pixel(surface)]; bpp = 8; break; case 4 ... 7: if (!omap_lcd->tft) - draw_line = draw_line12_32; + draw_line = draw_line_table12[surface_bits_per_pixel(surface)]; else - draw_line = draw_line16_32; + draw_line = draw_line_table16[surface_bits_per_pixel(surface)]; bpp = 16; break; diff --git a/hw/display/pl110.c b/hw/display/pl110.c index c069c0b7f..d589959f1 100644 --- a/hw/display/pl110.c +++ b/hw/display/pl110.c @@ -12,7 +12,6 @@ #include "ui/console.h" #include "framebuffer.h" #include "ui/pixel_ops.h" -#include "qemu/log.h" #define PL110_CR_EN 0x001 #define PL110_CR_BGR 0x100 diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 0e2682d28..919dc5cd3 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -504,7 +504,6 @@ static void interface_set_compression_level(QXLInstance *sin, int level) qxl_rom_set_dirty(qxl); } -#if SPICE_NEEDS_SET_MM_TIME static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) { PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); @@ -518,7 +517,6 @@ static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) qxl->rom->mm_clock = cpu_to_le32(mm_time); qxl_rom_set_dirty(qxl); } -#endif static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) { @@ -895,8 +893,7 @@ static void interface_update_area_complete(QXLInstance *sin, int qxl_i; qemu_mutex_lock(&qxl->ssd.lock); - if (surface_id != 0 || !num_updated_rects || - !qxl->render_update_cookie_num) { + if (surface_id != 0 || !qxl->render_update_cookie_num) { qemu_mutex_unlock(&qxl->ssd.lock); return; } @@ -1071,9 +1068,7 @@ static const QXLInterface qxl_interface = { .attache_worker = interface_attach_worker, .set_compression_level = interface_set_compression_level, -#if SPICE_NEEDS_SET_MM_TIME .set_mm_time = interface_set_mm_time, -#endif .get_init_info = interface_get_init_info, /* the callbacks below are called from spice server thread context */ @@ -1248,7 +1243,6 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, int pci_region; pcibus_t pci_start; pcibus_t pci_end; - MemoryRegion *mr; intptr_t virt_start; QXLDevMemSlot memslot; int i; @@ -1295,11 +1289,11 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, switch (pci_region) { case QXL_RAM_RANGE_INDEX: - mr = &d->vga.vram; + virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram); break; case QXL_VRAM_RANGE_INDEX: case 4 /* vram 64bit */: - mr = &d->vram_bar; + virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar); break; default: /* should not happen */ @@ -1307,7 +1301,6 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, return 1; } - virt_start = (intptr_t)memory_region_get_ram_ptr(mr); memslot.slot_id = slot_id; memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */ memslot.virt_start = virt_start + (guest_start - pci_start); @@ -1317,8 +1310,7 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, qxl_rom_set_dirty(d); qemu_spice_add_memslot(&d->ssd, &memslot, async); - d->guest_slots[slot_id].mr = mr; - d->guest_slots[slot_id].offset = memslot.virt_start - virt_start; + d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; d->guest_slots[slot_id].delta = delta; d->guest_slots[slot_id].active = 1; @@ -1345,60 +1337,39 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) } /* can be also called from spice server thread context */ -static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, - uint32_t *s, uint64_t *o) +void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) { uint64_t phys = le64_to_cpu(pqxl); uint32_t slot = (phys >> (64 - 8)) & 0xff; uint64_t offset = phys & 0xffffffffffff; - if (slot >= NUM_MEMSLOTS) { - qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot, - NUM_MEMSLOTS); - return false; - } - if (!qxl->guest_slots[slot].active) { - qxl_set_guest_bug(qxl, "inactive slot %d\n", slot); - return false; - } - if (offset < qxl->guest_slots[slot].delta) { - qxl_set_guest_bug(qxl, - "slot %d offset %"PRIu64" < delta %"PRIu64"\n", - slot, offset, qxl->guest_slots[slot].delta); - return false; - } - offset -= qxl->guest_slots[slot].delta; - if (offset > qxl->guest_slots[slot].size) { - qxl_set_guest_bug(qxl, - "slot %d offset %"PRIu64" > size %"PRIu64"\n", - slot, offset, qxl->guest_slots[slot].size); - return false; - } - - *s = slot; - *o = offset; - return true; -} - -/* can be also called from spice server thread context */ -void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) -{ - uint64_t offset; - uint32_t slot; - void *ptr; - switch (group_id) { case MEMSLOT_GROUP_HOST: - offset = le64_to_cpu(pqxl) & 0xffffffffffff; return (void *)(intptr_t)offset; case MEMSLOT_GROUP_GUEST: - if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset)) { + if (slot >= NUM_MEMSLOTS) { + qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot, + NUM_MEMSLOTS); + return NULL; + } + if (!qxl->guest_slots[slot].active) { + qxl_set_guest_bug(qxl, "inactive slot %d\n", slot); return NULL; } - ptr = memory_region_get_ram_ptr(qxl->guest_slots[slot].mr); - ptr += qxl->guest_slots[slot].offset; - ptr += offset; - return ptr; + if (offset < qxl->guest_slots[slot].delta) { + qxl_set_guest_bug(qxl, + "slot %d offset %"PRIu64" < delta %"PRIu64"\n", + slot, offset, qxl->guest_slots[slot].delta); + return NULL; + } + offset -= qxl->guest_slots[slot].delta; + if (offset > qxl->guest_slots[slot].size) { + qxl_set_guest_bug(qxl, + "slot %d offset %"PRIu64" > size %"PRIu64"\n", + slot, offset, qxl->guest_slots[slot].size); + return NULL; + } + return qxl->guest_slots[slot].ptr + offset; } return NULL; } @@ -1813,24 +1784,9 @@ static void qxl_hw_update(void *opaque) qxl_render_update(qxl); } -static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, - uint32_t height, int32_t stride) -{ - uint64_t offset, size; - uint32_t slot; - bool rc; - - rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset); - assert(rc == true); - size = (uint64_t)height * abs(stride); - trace_qxl_surfaces_dirty(qxl->id, offset, size); - qxl_set_dirty(qxl->guest_slots[slot].mr, - qxl->guest_slots[slot].offset + offset, - qxl->guest_slots[slot].offset + offset + size); -} - static void qxl_dirty_surfaces(PCIQXLDevice *qxl) { + uintptr_t vram_start; int i; if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) { @@ -1838,13 +1794,16 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) } /* dirty the primary surface */ - qxl_dirty_one_surface(qxl, qxl->guest_primary.surface.mem, - qxl->guest_primary.surface.height, - qxl->guest_primary.surface.stride); + qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, + qxl->shadow_rom.surface0_area_size); + + vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); /* dirty the off-screen surfaces */ for (i = 0; i < qxl->ssd.num_surfaces; i++) { QXLSurfaceCmd *cmd; + intptr_t surface_offset; + int surface_size; if (qxl->guest_surfaces.cmds[i] == 0) { continue; @@ -1854,9 +1813,15 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) MEMSLOT_GROUP_GUEST); assert(cmd); assert(cmd->type == QXL_SURFACE_CMD_CREATE); - qxl_dirty_one_surface(qxl, cmd->u.surface_create.data, - cmd->u.surface_create.height, - cmd->u.surface_create.stride); + surface_offset = (intptr_t)qxl_phys2virt(qxl, + cmd->u.surface_create.data, + MEMSLOT_GROUP_GUEST); + assert(surface_offset); + surface_offset -= vram_start; + surface_size = cmd->u.surface_create.height * + abs(cmd->u.surface_create.stride); + trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size); + qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size); } } @@ -1949,7 +1914,7 @@ static void qxl_init_ramsize(PCIQXLDevice *qxl) /* vram (surfaces, 64bit, bar 4+5) */ if (qxl->vram_size_mb != -1) { - qxl->vram_size = (uint64_t)qxl->vram_size_mb * 1024 * 1024; + qxl->vram_size = qxl->vram_size_mb * 1024 * 1024; } if (qxl->vram_size < qxl->vram32_size) { qxl->vram_size = qxl->vram32_size; @@ -2055,9 +2020,9 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp) dprint(qxl, 1, "ram/%s: %d MB [region 0]\n", qxl->id == 0 ? "pri" : "sec", qxl->vga.vram_size / (1024*1024)); - dprint(qxl, 1, "vram/32: %" PRIx64 "d MB [region 1]\n", + dprint(qxl, 1, "vram/32: %d MB [region 1]\n", qxl->vram32_size / (1024*1024)); - dprint(qxl, 1, "vram/64: %" PRIx64 "d MB %s\n", + dprint(qxl, 1, "vram/64: %d MB %s\n", qxl->vram_size / (1024*1024), qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]"); @@ -2311,7 +2276,7 @@ static VMStateDescription qxl_vmstate = { static Property qxl_properties[] = { DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024), - DEFINE_PROP_UINT64("vram_size", PCIQXLDevice, vram32_size, + DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size, 64 * 1024 * 1024), DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, QXL_DEFAULT_REVISION), diff --git a/hw/display/qxl.h b/hw/display/qxl.h index d2d49dd93..2ddf065e1 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -1,5 +1,5 @@ #ifndef HW_QXL_H -#define HW_QXL_H +#define HW_QXL_H 1 #include "qemu-common.h" @@ -53,8 +53,7 @@ typedef struct PCIQXLDevice { struct guest_slots { QXLMemSlot slot; - MemoryRegion *mr; - uint64_t offset; + void *ptr; uint64_t size; uint64_t delta; uint32_t active; @@ -105,9 +104,9 @@ typedef struct PCIQXLDevice { #endif /* vram pci bar */ - uint64_t vram_size; + uint32_t vram_size; MemoryRegion vram_bar; - uint64_t vram32_size; + uint32_t vram32_size; MemoryRegion vram32_bar; /* io bar */ diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index 6d1faf44a..14c1bf339 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -361,7 +361,7 @@ static const GraphicHwOps ssd0323_ops = { .gfx_update = ssd0323_update_display, }; -static void ssd0323_realize(SSISlave *d, Error **errp) +static int ssd0323_init(SSISlave *d) { DeviceState *dev = DEVICE(d); ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, d); @@ -375,13 +375,14 @@ static void ssd0323_realize(SSISlave *d, Error **errp) register_savevm(dev, "ssd0323_oled", -1, 1, ssd0323_save, ssd0323_load, s); + return 0; } static void ssd0323_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->realize = ssd0323_realize; + k->init = ssd0323_init; k->transfer = ssd0323_transfer; k->cs_polarity = SSI_CS_HIGH; } diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c index 92f7120ac..da3ceceb0 100644 --- a/hw/display/tc6393xb.c +++ b/hw/display/tc6393xb.c @@ -12,7 +12,6 @@ */ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu/host-utils.h" #include "hw/hw.h" #include "hw/devices.h" #include "hw/block/flash.h" diff --git a/hw/display/trace-events b/hw/display/trace-events deleted file mode 100644 index 332ababd8..000000000 --- a/hw/display/trace-events +++ /dev/null @@ -1,122 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/display/jazz_led.c -jazz_led_read(uint64_t addr, uint8_t val) "read addr=0x%"PRIx64": 0x%x" -jazz_led_write(uint64_t addr, uint8_t new) "write addr=0x%"PRIx64": 0x%x" - -# hw/display/xenfb.c -xenfb_mouse_event(void *opaque, int dx, int dy, int dz, int button_state, int abs_pointer_wanted) "%p x %d y %d z %d bs %#x abs %d" -xenfb_input_connected(void *xendev, int abs_pointer_wanted) "%p abs %d" - -# hw/display/g364fb.c -g364fb_read(uint64_t addr, uint32_t val) "read addr=0x%"PRIx64": 0x%x" -g364fb_write(uint64_t addr, uint32_t new) "write addr=0x%"PRIx64": 0x%x" - -# hw/display/milkymist-tmu2.c -milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_tmu2_start(void) "Start TMU" -milkymist_tmu2_pulse_irq(void) "Pulse IRQ" - -# hw/display/milkymist-vgafb.c -milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" - -# hw/display/vmware_vga.c -vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x" -vmware_value_write(uint32_t index, uint32_t value) "index %d, value 0x%x" -vmware_palette_read(uint32_t index, uint32_t value) "index %d, value 0x%x" -vmware_palette_write(uint32_t index, uint32_t value) "index %d, value 0x%x" -vmware_scratch_read(uint32_t index, uint32_t value) "index %d, value 0x%x" -vmware_scratch_write(uint32_t index, uint32_t value) "index %d, value 0x%x" -vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp" - -# hw/display/virtio-gpu.c -virtio_gpu_features(bool virgl) "virgl %d" -virtio_gpu_cmd_get_display_info(void) "" -virtio_gpu_cmd_get_caps(void) "" -virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d" -virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d" -virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d" -virtio_gpu_cmd_res_unref(uint32_t res) "res 0x%x" -virtio_gpu_cmd_res_back_attach(uint32_t res) "res 0x%x" -virtio_gpu_cmd_res_back_detach(uint32_t res) "res 0x%x" -virtio_gpu_cmd_res_xfer_toh_2d(uint32_t res) "res 0x%x" -virtio_gpu_cmd_res_xfer_toh_3d(uint32_t res) "res 0x%x" -virtio_gpu_cmd_res_xfer_fromh_3d(uint32_t res) "res 0x%x" -virtio_gpu_cmd_res_flush(uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "res 0x%x, w %d, h %d, x %d, y %d" -virtio_gpu_cmd_ctx_create(uint32_t ctx, const char *name) "ctx 0x%x, name %s" -virtio_gpu_cmd_ctx_destroy(uint32_t ctx) "ctx 0x%x" -virtio_gpu_cmd_ctx_res_attach(uint32_t ctx, uint32_t res) "ctx 0x%x, res 0x%x" -virtio_gpu_cmd_ctx_res_detach(uint32_t ctx, uint32_t res) "ctx 0x%x, res 0x%x" -virtio_gpu_cmd_ctx_submit(uint32_t ctx, uint32_t size) "ctx 0x%x, size %d" -virtio_gpu_update_cursor(uint32_t scanout, uint32_t x, uint32_t y, const char *type, uint32_t res) "scanout %d, x %d, y %d, %s, res 0x%x" -virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type 0x%x" -virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64 - -# hw/display/qxl.c -disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d" -disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u" -qxl_create_guest_primary(int qid, uint32_t width, uint32_t height, uint64_t mem, uint32_t format, uint32_t position) "%d %ux%u mem=%" PRIx64 " %u,%u" -qxl_create_guest_primary_rest(int qid, int32_t stride, uint32_t type, uint32_t flags) "%d %d,%d,%d" -qxl_destroy_primary(int qid) "%d" -qxl_enter_vga_mode(int qid) "%d" -qxl_exit_vga_mode(int qid) "%d" -qxl_hard_reset(int qid, int64_t loadvm) "%d loadvm=%"PRId64 -qxl_interface_async_complete_io(int qid, uint32_t current_async, void *cookie) "%d current=%d cookie=%p" -qxl_interface_attach_worker(int qid) "%d" -qxl_interface_get_init_info(int qid) "%d" -qxl_interface_set_compression_level(int qid, int64_t level) "%d %"PRId64 -qxl_interface_update_area_complete(int qid, uint32_t surface_id, uint32_t dirty_left, uint32_t dirty_right, uint32_t dirty_top, uint32_t dirty_bottom) "%d surface=%d [%d,%d,%d,%d]" -qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d #=%d" -qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" -qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" -qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" -qxl_io_log(int qid, const uint8_t *log_buf) "%d %s" -qxl_io_read_unexpected(int qid) "%d" -qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" -qxl_io_write(int qid, const char *mode, uint64_t addr, const char *aname, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " (%s) val=%"PRIu64" size=%u async=%d" -qxl_memslot_add_guest(int qid, uint32_t slot_id, uint64_t guest_start, uint64_t guest_end) "%d %u: guest phys 0x%"PRIx64 " - 0x%" PRIx64 -qxl_post_load(int qid, const char *mode) "%d %s" -qxl_pre_load(int qid) "%d" -qxl_pre_save(int qid) "%d" -qxl_reset_surfaces(int qid) "%d" -qxl_ring_command_check(int qid, const char *mode) "%d %s" -qxl_ring_command_get(int qid, const char *mode) "%d %s" -qxl_ring_command_req_notification(int qid) "%d" -qxl_ring_cursor_check(int qid, const char *mode) "%d %s" -qxl_ring_cursor_get(int qid, const char *mode) "%d %s" -qxl_ring_cursor_req_notification(int qid) "%d" -qxl_ring_res_push(int qid, const char *mode, uint32_t surface_count, uint32_t free_res, void *last_release, const char *notify) "%d %s s#=%d res#=%d last=%p notify=%s" -qxl_ring_res_push_rest(int qid, uint32_t ring_has, uint32_t ring_size, uint32_t prod, uint32_t cons) "%d ring %d/%d [%d,%d]" -qxl_ring_res_put(int qid, uint32_t free_res) "%d #res=%d" -qxl_set_mode(int qid, int modenr, uint32_t x_res, uint32_t y_res, uint32_t bits, uint64_t devmem) "%d mode=%d [ x=%d y=%d @ bpp=%d devmem=0x%" PRIx64 " ]" -qxl_soft_reset(int qid) "%d" -qxl_spice_destroy_surfaces_complete(int qid) "%d" -qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d" -qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d" -qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d" -qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d" -qxl_spice_monitors_config(int qid) "%d" -qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d" -qxl_spice_oom(int qid) "%d" -qxl_spice_reset_cursor(int qid) "%d" -qxl_spice_reset_image_cache(int qid) "%d" -qxl_spice_reset_memslots(int qid) "%d" -qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" -qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" -qxl_surfaces_dirty(int qid, uint64_t offset, uint64_t size) "%d offset=0x%"PRIx64" size=0x%"PRIx64 -qxl_send_events(int qid, uint32_t events) "%d %d" -qxl_send_events_vm_stopped(int qid, uint32_t events) "%d %d" -qxl_set_guest_bug(int qid) "%d" -qxl_interrupt_client_monitors_config(int qid, int num_heads, void *heads) "%d %d %p" -qxl_client_monitors_config_unsupported_by_guest(int qid, uint32_t int_mask, void *client_monitors_config) "%d %X %p" -qxl_client_monitors_config_unsupported_by_device(int qid, int revision) "%d revision=%d" -qxl_client_monitors_config_capped(int qid, int requested, int limit) "%d %d %d" -qxl_client_monitors_config_crc(int qid, unsigned size, uint32_t crc32) "%d %u %u" -qxl_set_client_capabilities_unsupported_by_revision(int qid, int revision) "%d revision=%d" - -# hw/display/qxl-render.c -qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]" -qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d" -qxl_render_update_area_done(void *cookie) "%p" diff --git a/hw/display/vga.c b/hw/display/vga.c index 2a88b3c1b..9ebc54f22 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -700,7 +700,9 @@ static void vbe_update_vgaregs(VGACommonState *s) static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) { VGACommonState *s = opaque; - return s->vbe_index; + uint32_t val; + val = s->vbe_index; + return val; } uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) diff --git a/hw/display/vga.h b/hw/display/vga.h index 16886f5ee..d917046da 100644 --- a/hw/display/vga.h +++ b/hw/display/vga.h @@ -14,8 +14,8 @@ * */ -#ifndef LINUX_VIDEO_VGA_H -#define LINUX_VIDEO_VGA_H +#ifndef __linux_video_vga_h__ +#define __linux_video_vga_h__ /* Some of the code below is taken from SVGAlib. The original, unmodified copyright notice for that code is below. */ @@ -156,4 +156,4 @@ /* VGA graphics controller bit masks */ #define VGA_GR06_GRAPHICS_MODE 0x01 -#endif /* LINUX_VIDEO_VGA_H */ +#endif /* __linux_video_vga_h__ */ diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index dd6c958da..3ce5544ef 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -21,11 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - #ifndef HW_VGA_INT_H -#define HW_VGA_INT_H +#define HW_VGA_INT_H 1 -#include "hw/hw.h" +#include <hw/hw.h> #include "exec/memory.h" #define ST01_V_RETRACE 0x08 diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c index 758d33a09..fa192946a 100644 --- a/hw/display/virtio-gpu-3d.c +++ b/hw/display/virtio-gpu-3d.c @@ -17,11 +17,10 @@ #include "trace.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" -#include "qapi/error.h" #ifdef CONFIG_VIRGL -#include <virglrenderer.h> +#include "virglrenderer.h" static struct virgl_renderer_callbacks virtio_gpu_3d_cbs; @@ -128,7 +127,7 @@ static void virgl_cmd_resource_flush(VirtIOGPU *g, trace_virtio_gpu_cmd_res_flush(rf.resource_id, rf.r.width, rf.r.height, rf.r.x, rf.r.y); - for (i = 0; i < g->conf.max_outputs; i++) { + for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) { if (g->scanout[i].resource_id != rf.resource_id) { continue; } @@ -147,7 +146,7 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g, trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, ss.r.width, ss.r.height, ss.r.x, ss.r.y); - if (ss.scanout_id >= g->conf.max_outputs) { + if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT) { qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", __func__, ss.scanout_id); cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; @@ -171,14 +170,13 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g, virgl_renderer_force_ctx_0(); dpy_gl_scanout(g->scanout[ss.scanout_id].con, info.tex_id, info.flags & 1 /* FIXME: Y_0_TOP */, - info.width, info.height, ss.r.x, ss.r.y, ss.r.width, ss.r.height); } else { if (ss.scanout_id != 0) { dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL); } dpy_gl_scanout(g->scanout[ss.scanout_id].con, 0, false, - 0, 0, 0, 0, 0, 0); + 0, 0, 0, 0); } g->scanout[ss.scanout_id].resource_id = ss.resource_id; } @@ -285,7 +283,7 @@ static void virgl_resource_attach_backing(VirtIOGPU *g, VIRTIO_GPU_FILL_CMD(att_rb); trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id); - ret = virtio_gpu_create_mapping_iov(&att_rb, cmd, NULL, &res_iovs); + ret = virtio_gpu_create_mapping_iov(&att_rb, cmd, &res_iovs); if (ret != 0) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; return; @@ -581,7 +579,7 @@ void virtio_gpu_virgl_reset(VirtIOGPU *g) if (i != 0) { dpy_gfx_replace_surface(g->scanout[i].con, NULL); } - dpy_gl_scanout(g->scanout[i].con, 0, false, 0, 0, 0, 0, 0, 0); + dpy_gl_scanout(g->scanout[i].con, 0, false, 0, 0, 0, 0); } } diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index 34a724c75..a71b230d3 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -30,7 +30,9 @@ static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) int i; qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - virtio_pci_force_virtio_1(vpci_dev); + /* force virtio-1.0 */ + vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN; + vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY; object_property_set_bool(OBJECT(vdev), true, "realized", errp); for (i = 0; i < g->conf.max_outputs; i++) { diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 7fe6ed8bf..c181fb364 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -19,17 +19,12 @@ #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-bus.h" -#include "migration/migration.h" -#include "qemu/log.h" -#include "qapi/error.h" - -#define VIRTIO_GPU_VM_VERSION 1 static struct virtio_gpu_simple_resource* virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); #ifdef CONFIG_VIRGL -#include <virglrenderer.h> +#include "virglrenderer.h" #define VIRGL(_g, _virgl, _simple, ...) \ do { \ if (_g->use_virgl_renderer) { \ @@ -97,7 +92,7 @@ static void update_cursor_data_virgl(VirtIOGPU *g, static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) { struct virtio_gpu_scanout *s; - bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR; + bool move = cursor->hdr.type != VIRTIO_GPU_CMD_MOVE_CURSOR; if (cursor->pos.scanout_id >= g->conf.max_outputs) { return; @@ -110,7 +105,7 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) move ? "move" : "update", cursor->resource_id); - if (!move) { + if (move) { if (!s->current_cursor) { s->current_cursor = cursor_alloc(64, 64); } @@ -123,11 +118,6 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) g, s, cursor->resource_id); } dpy_cursor_define(s->con, s->current_cursor); - - s->cursor = *cursor; - } else { - s->cursor.pos.x = cursor->pos.x; - s->cursor.pos.y = cursor->pos.y; } dpy_mouse_set(s->con, cursor->pos.x, cursor->pos.y, cursor->resource_id ? 1 : 0); @@ -474,7 +464,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, pixman_region_init_rect(&flush_region, rf.r.x, rf.r.y, rf.r.width, rf.r.height); - for (i = 0; i < g->conf.max_outputs; i++) { + for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) { struct virtio_gpu_scanout *scanout; pixman_region16_t region, finalregion; pixman_box16_t *extents; @@ -503,11 +493,6 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, pixman_region_fini(&flush_region); } -static void virtio_unref_resource(pixman_image_t *image, void *data) -{ - pixman_image_unref(data); -} - static void virtio_gpu_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -522,13 +507,6 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, ss.r.width, ss.r.height, ss.r.x, ss.r.y); - if (ss.scanout_id >= g->conf.max_outputs) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", - __func__, ss.scanout_id); - cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; - return; - } - g->enable = 1; if (ss.resource_id == 0) { scanout = &g->scanout[ss.scanout_id]; @@ -538,7 +516,8 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, res->scanout_bitmask &= ~(1 << ss.scanout_id); } } - if (ss.scanout_id == 0) { + if (ss.scanout_id == 0 || + ss.scanout_id >= g->conf.max_outputs) { qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", __func__, ss.scanout_id); @@ -553,6 +532,14 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, } /* create a surface for this scanout */ + if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT || + ss.scanout_id >= g->conf.max_outputs) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d", + __func__, ss.scanout_id); + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID; + return; + } + res = virtio_gpu_find_resource(g, ss.resource_id); if (!res) { qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n", @@ -584,15 +571,8 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, != ((uint8_t *)pixman_image_get_data(res->image) + offset) || scanout->width != ss.r.width || scanout->height != ss.r.height) { - pixman_image_t *rect; - void *ptr = (uint8_t *)pixman_image_get_data(res->image) + offset; - rect = pixman_image_create_bits(format, ss.r.width, ss.r.height, ptr, - pixman_image_get_stride(res->image)); - pixman_image_ref(res->image); - pixman_image_set_destroy_function(rect, virtio_unref_resource, - res->image); /* realloc the surface ptr */ - scanout->ds = qemu_create_displaysurface_pixman(rect); + scanout->ds = qemu_create_displaysurface_pixman(res->image); if (!scanout->ds) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; return; @@ -610,7 +590,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, struct virtio_gpu_ctrl_command *cmd, - uint64_t **addr, struct iovec **iov) + struct iovec **iov) { struct virtio_gpu_mem_entry *ents; size_t esize, s; @@ -636,16 +616,10 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, } *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries); - if (addr) { - *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries); - } for (i = 0; i < ab->nr_entries; i++) { hwaddr len = ents[i].length; (*iov)[i].iov_len = ents[i].length; (*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1); - if (addr) { - (*addr)[i] = ents[i].addr; - } if (!(*iov)[i].iov_base || len != ents[i].length) { qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" " resource %d element %d\n", @@ -653,10 +627,6 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, virtio_gpu_cleanup_mapping_iov(*iov, i); g_free(ents); *iov = NULL; - if (addr) { - g_free(*addr); - *addr = NULL; - } return -1; } } @@ -680,8 +650,6 @@ static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res) virtio_gpu_cleanup_mapping_iov(res->iov, res->iov_cnt); res->iov = NULL; res->iov_cnt = 0; - g_free(res->addrs); - res->addrs = NULL; } static void @@ -703,7 +671,7 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g, return; } - ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->addrs, &res->iov); + ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->iov); if (ret != 0) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; return; @@ -911,7 +879,7 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) { VirtIOGPU *g = opaque; - if (idx >= g->conf.max_outputs) { + if (idx > g->conf.max_outputs) { return -1; } @@ -935,14 +903,8 @@ static void virtio_gpu_gl_block(void *opaque, bool block) { VirtIOGPU *g = opaque; - if (block) { - g->renderer_blocked++; - } else { - g->renderer_blocked--; - } - assert(g->renderer_blocked >= 0); - - if (g->renderer_blocked == 0) { + g->renderer_blocked = block; + if (!block) { virtio_gpu_process_cmdq(g); } } @@ -955,154 +917,11 @@ const GraphicHwOps virtio_gpu_ops = { .gl_block = virtio_gpu_gl_block, }; -static const VMStateDescription vmstate_virtio_gpu_scanout = { - .name = "virtio-gpu-one-scanout", - .version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(resource_id, struct virtio_gpu_scanout), - VMSTATE_UINT32(width, struct virtio_gpu_scanout), - VMSTATE_UINT32(height, struct virtio_gpu_scanout), - VMSTATE_INT32(x, struct virtio_gpu_scanout), - VMSTATE_INT32(y, struct virtio_gpu_scanout), - VMSTATE_UINT32(cursor.resource_id, struct virtio_gpu_scanout), - VMSTATE_UINT32(cursor.hot_x, struct virtio_gpu_scanout), - VMSTATE_UINT32(cursor.hot_y, struct virtio_gpu_scanout), - VMSTATE_UINT32(cursor.pos.x, struct virtio_gpu_scanout), - VMSTATE_UINT32(cursor.pos.y, struct virtio_gpu_scanout), - VMSTATE_END_OF_LIST() - }, +static const VMStateDescription vmstate_virtio_gpu_unmigratable = { + .name = "virtio-gpu", + .unmigratable = 1, }; -static const VMStateDescription vmstate_virtio_gpu_scanouts = { - .name = "virtio-gpu-scanouts", - .version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(enable, struct VirtIOGPU), - VMSTATE_UINT32_EQUAL(conf.max_outputs, struct VirtIOGPU), - VMSTATE_STRUCT_VARRAY_UINT32(scanout, struct VirtIOGPU, - conf.max_outputs, 1, - vmstate_virtio_gpu_scanout, - struct virtio_gpu_scanout), - VMSTATE_END_OF_LIST() - }, -}; - -static void virtio_gpu_save(QEMUFile *f, void *opaque, size_t size) -{ - VirtIOGPU *g = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(g); - struct virtio_gpu_simple_resource *res; - int i; - - virtio_save(vdev, f); - - /* in 2d mode we should never find unprocessed commands here */ - assert(QTAILQ_EMPTY(&g->cmdq)); - - QTAILQ_FOREACH(res, &g->reslist, next) { - qemu_put_be32(f, res->resource_id); - qemu_put_be32(f, res->width); - qemu_put_be32(f, res->height); - qemu_put_be32(f, res->format); - qemu_put_be32(f, res->iov_cnt); - for (i = 0; i < res->iov_cnt; i++) { - qemu_put_be64(f, res->addrs[i]); - qemu_put_be32(f, res->iov[i].iov_len); - } - qemu_put_buffer(f, (void *)pixman_image_get_data(res->image), - pixman_image_get_stride(res->image) * res->height); - } - qemu_put_be32(f, 0); /* end of list */ - - vmstate_save_state(f, &vmstate_virtio_gpu_scanouts, g, NULL); -} - -static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size) -{ - VirtIOGPU *g = opaque; - VirtIODevice *vdev = VIRTIO_DEVICE(g); - struct virtio_gpu_simple_resource *res; - struct virtio_gpu_scanout *scanout; - uint32_t resource_id, pformat; - int i, ret; - - ret = virtio_load(vdev, f, VIRTIO_GPU_VM_VERSION); - if (ret) { - return ret; - } - - resource_id = qemu_get_be32(f); - while (resource_id != 0) { - res = g_new0(struct virtio_gpu_simple_resource, 1); - res->resource_id = resource_id; - res->width = qemu_get_be32(f); - res->height = qemu_get_be32(f); - res->format = qemu_get_be32(f); - res->iov_cnt = qemu_get_be32(f); - - /* allocate */ - pformat = get_pixman_format(res->format); - if (!pformat) { - return -EINVAL; - } - res->image = pixman_image_create_bits(pformat, - res->width, res->height, - NULL, 0); - if (!res->image) { - return -EINVAL; - } - - res->addrs = g_new(uint64_t, res->iov_cnt); - res->iov = g_new(struct iovec, res->iov_cnt); - - /* read data */ - for (i = 0; i < res->iov_cnt; i++) { - res->addrs[i] = qemu_get_be64(f); - res->iov[i].iov_len = qemu_get_be32(f); - } - qemu_get_buffer(f, (void *)pixman_image_get_data(res->image), - pixman_image_get_stride(res->image) * res->height); - - /* restore mapping */ - for (i = 0; i < res->iov_cnt; i++) { - hwaddr len = res->iov[i].iov_len; - res->iov[i].iov_base = - cpu_physical_memory_map(res->addrs[i], &len, 1); - if (!res->iov[i].iov_base || len != res->iov[i].iov_len) { - return -EINVAL; - } - } - - QTAILQ_INSERT_HEAD(&g->reslist, res, next); - - resource_id = qemu_get_be32(f); - } - - /* load & apply scanout state */ - vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1); - for (i = 0; i < g->conf.max_outputs; i++) { - scanout = &g->scanout[i]; - if (!scanout->resource_id) { - continue; - } - res = virtio_gpu_find_resource(g, scanout->resource_id); - if (!res) { - return -EINVAL; - } - scanout->ds = qemu_create_displaysurface_pixman(res->image); - if (!scanout->ds) { - return -EINVAL; - } - - dpy_gfx_replace_surface(scanout->con, scanout->ds); - dpy_gfx_update(scanout->con, 0, 0, scanout->width, scanout->height); - update_cursor(g, &scanout->cursor); - res->scanout_bitmask |= (1 << i); - } - - return 0; -} - static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(qdev); @@ -1110,11 +929,6 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) bool have_virgl; int i; - if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) { - error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS); - return; - } - g->config_size = sizeof(struct virtio_gpu_config); g->virtio_config.num_scanouts = g->conf.max_outputs; virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, @@ -1160,19 +974,7 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) } } - if (virtio_gpu_virgl_enabled(g->conf)) { - error_setg(&g->migration_blocker, "virgl is not yet migratable"); - migrate_add_blocker(g->migration_blocker); - } -} - -static void virtio_gpu_device_unrealize(DeviceState *qdev, Error **errp) -{ - VirtIOGPU *g = VIRTIO_GPU(qdev); - if (g->migration_blocker) { - migrate_del_blocker(g->migration_blocker); - error_free(g->migration_blocker); - } + vmstate_register(qdev, -1, &vmstate_virtio_gpu_unmigratable, g); } static void virtio_gpu_instance_init(Object *obj) @@ -1219,9 +1021,6 @@ static void virtio_gpu_reset(VirtIODevice *vdev) #endif } -VMSTATE_VIRTIO_DEVICE(gpu, VIRTIO_GPU_VM_VERSION, virtio_gpu_load, - virtio_gpu_save); - static Property virtio_gpu_properties[] = { DEFINE_PROP_UINT32("max_outputs", VirtIOGPU, conf.max_outputs, 1), #ifdef CONFIG_VIRGL @@ -1239,7 +1038,6 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); vdc->realize = virtio_gpu_device_realize; - vdc->unrealize = virtio_gpu_device_unrealize; vdc->get_config = virtio_gpu_get_config; vdc->set_config = virtio_gpu_set_config; vdc->get_features = virtio_gpu_get_features; @@ -1248,7 +1046,6 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data) vdc->reset = virtio_gpu_reset; dc->props = virtio_gpu_properties; - dc->vmsd = &vmstate_virtio_gpu; } static const TypeInfo virtio_gpu_info = { diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index 5b510a17f..e58b165ae 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -4,7 +4,6 @@ #include "ui/console.h" #include "vga_int.h" #include "hw/virtio/virtio-pci.h" -#include "qapi/error.h" /* * virtio-vga: This extends VirtioPCIProxy. @@ -84,24 +83,12 @@ static const GraphicHwOps virtio_vga_ops = { .gl_block = virtio_vga_gl_block, }; -static const VMStateDescription vmstate_virtio_vga = { - .name = "virtio-vga", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - /* no pci stuff here, saving the virtio device will handle that */ - VMSTATE_STRUCT(vga, VirtIOVGA, 0, vmstate_vga_common, VGACommonState), - VMSTATE_END_OF_LIST() - } -}; - /* VGA device wrapper around PCI device around virtio GPU */ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp) { VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev); VirtIOGPU *g = &vvga->vdev; VGACommonState *vga = &vvga->vga; - Error *err = NULL; uint32_t offset; int i; @@ -134,12 +121,10 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp) /* init virtio bits */ qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus)); - virtio_pci_force_virtio_1(vpci_dev); - object_property_set_bool(OBJECT(g), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } + /* force virtio-1.0 */ + vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN; + vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY; + object_property_set_bool(OBJECT(g), true, "realized", errp); /* add stdvga mmio regions */ pci_std_vga_mmio_region_init(vga, &vpci_dev->modern_bar, @@ -177,7 +162,6 @@ static void virtio_vga_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->props = virtio_vga_properties; dc->reset = virtio_vga_reset; - dc->vmsd = &vmstate_virtio_vga; dc->hotpluggable = false; k->realize = virtio_vga_realize; diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 46b7d5ede..9866dfda5 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -25,6 +25,7 @@ */ #include "qemu/osdep.h" +#include <sys/mman.h> #include "hw/hw.h" #include "ui/console.h" @@ -471,9 +472,9 @@ static int xenfb_map_fb(struct XenFB *xenfb) xenfb->pixels = NULL; } - xenfb->fbpages = DIV_ROUND_UP(xenfb->fb_len, XC_PAGE_SIZE); + xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; n_fbdirs = xenfb->fbpages * mode / 8; - n_fbdirs = DIV_ROUND_UP(n_fbdirs, XC_PAGE_SIZE); + n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; pgmfns = g_malloc0(sizeof(xen_pfn_t) * n_fbdirs); fbmfns = g_malloc0(sizeof(xen_pfn_t) * xenfb->fbpages); diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c deleted file mode 100644 index f43eb0930..000000000 --- a/hw/display/xlnx_dp.c +++ /dev/null @@ -1,1338 +0,0 @@ -/* - * xlnx_dp.c - * - * Copyright (C) 2015 : GreenSocs Ltd - * http://www.greensocs.com/ , email: info@greensocs.com - * - * Developed by : - * Frederic Konrad <fred.konrad@greensocs.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option)any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "hw/display/xlnx_dp.h" - -#ifndef DEBUG_DP -#define DEBUG_DP 0 -#endif - -#define DPRINTF(fmt, ...) do { \ - if (DEBUG_DP) { \ - qemu_log("xlnx_dp: " fmt , ## __VA_ARGS__); \ - } \ -} while (0); - -/* - * Register offset for DP. - */ -#define DP_LINK_BW_SET (0x0000 >> 2) -#define DP_LANE_COUNT_SET (0x0004 >> 2) -#define DP_ENHANCED_FRAME_EN (0x0008 >> 2) -#define DP_TRAINING_PATTERN_SET (0x000C >> 2) -#define DP_LINK_QUAL_PATTERN_SET (0x0010 >> 2) -#define DP_SCRAMBLING_DISABLE (0x0014 >> 2) -#define DP_DOWNSPREAD_CTRL (0x0018 >> 2) -#define DP_SOFTWARE_RESET (0x001C >> 2) -#define DP_TRANSMITTER_ENABLE (0x0080 >> 2) -#define DP_MAIN_STREAM_ENABLE (0x0084 >> 2) -#define DP_FORCE_SCRAMBLER_RESET (0x00C0 >> 2) -#define DP_VERSION_REGISTER (0x00F8 >> 2) -#define DP_CORE_ID (0x00FC >> 2) - -#define DP_AUX_COMMAND_REGISTER (0x0100 >> 2) -#define AUX_ADDR_ONLY_MASK (0x1000) -#define AUX_COMMAND_MASK (0x0F00) -#define AUX_COMMAND_SHIFT (8) -#define AUX_COMMAND_NBYTES (0x000F) - -#define DP_AUX_WRITE_FIFO (0x0104 >> 2) -#define DP_AUX_ADDRESS (0x0108 >> 2) -#define DP_AUX_CLOCK_DIVIDER (0x010C >> 2) -#define DP_TX_USER_FIFO_OVERFLOW (0x0110 >> 2) -#define DP_INTERRUPT_SIGNAL_STATE (0x0130 >> 2) -#define DP_AUX_REPLY_DATA (0x0134 >> 2) -#define DP_AUX_REPLY_CODE (0x0138 >> 2) -#define DP_AUX_REPLY_COUNT (0x013C >> 2) -#define DP_REPLY_DATA_COUNT (0x0148 >> 2) -#define DP_REPLY_STATUS (0x014C >> 2) -#define DP_HPD_DURATION (0x0150 >> 2) -#define DP_MAIN_STREAM_HTOTAL (0x0180 >> 2) -#define DP_MAIN_STREAM_VTOTAL (0x0184 >> 2) -#define DP_MAIN_STREAM_POLARITY (0x0188 >> 2) -#define DP_MAIN_STREAM_HSWIDTH (0x018C >> 2) -#define DP_MAIN_STREAM_VSWIDTH (0x0190 >> 2) -#define DP_MAIN_STREAM_HRES (0x0194 >> 2) -#define DP_MAIN_STREAM_VRES (0x0198 >> 2) -#define DP_MAIN_STREAM_HSTART (0x019C >> 2) -#define DP_MAIN_STREAM_VSTART (0x01A0 >> 2) -#define DP_MAIN_STREAM_MISC0 (0x01A4 >> 2) -#define DP_MAIN_STREAM_MISC1 (0x01A8 >> 2) -#define DP_MAIN_STREAM_M_VID (0x01AC >> 2) -#define DP_MSA_TRANSFER_UNIT_SIZE (0x01B0 >> 2) -#define DP_MAIN_STREAM_N_VID (0x01B4 >> 2) -#define DP_USER_DATA_COUNT_PER_LANE (0x01BC >> 2) -#define DP_MIN_BYTES_PER_TU (0x01C4 >> 2) -#define DP_FRAC_BYTES_PER_TU (0x01C8 >> 2) -#define DP_INIT_WAIT (0x01CC >> 2) -#define DP_PHY_RESET (0x0200 >> 2) -#define DP_PHY_VOLTAGE_DIFF_LANE_0 (0x0220 >> 2) -#define DP_PHY_VOLTAGE_DIFF_LANE_1 (0x0224 >> 2) -#define DP_TRANSMIT_PRBS7 (0x0230 >> 2) -#define DP_PHY_CLOCK_SELECT (0x0234 >> 2) -#define DP_TX_PHY_POWER_DOWN (0x0238 >> 2) -#define DP_PHY_PRECURSOR_LANE_0 (0x023C >> 2) -#define DP_PHY_PRECURSOR_LANE_1 (0x0240 >> 2) -#define DP_PHY_POSTCURSOR_LANE_0 (0x024C >> 2) -#define DP_PHY_POSTCURSOR_LANE_1 (0x0250 >> 2) -#define DP_PHY_STATUS (0x0280 >> 2) - -#define DP_TX_AUDIO_CONTROL (0x0300 >> 2) -#define DP_TX_AUD_CTRL (1) - -#define DP_TX_AUDIO_CHANNELS (0x0304 >> 2) -#define DP_TX_AUDIO_INFO_DATA(n) ((0x0308 + 4 * n) >> 2) -#define DP_TX_M_AUD (0x0328 >> 2) -#define DP_TX_N_AUD (0x032C >> 2) -#define DP_TX_AUDIO_EXT_DATA(n) ((0x0330 + 4 * n) >> 2) -#define DP_INT_STATUS (0x03A0 >> 2) -#define DP_INT_MASK (0x03A4 >> 2) -#define DP_INT_EN (0x03A8 >> 2) -#define DP_INT_DS (0x03AC >> 2) - -/* - * Registers offset for Audio Video Buffer configuration. - */ -#define V_BLEND_OFFSET (0xA000) -#define V_BLEND_BG_CLR_0 (0x0000 >> 2) -#define V_BLEND_BG_CLR_1 (0x0004 >> 2) -#define V_BLEND_BG_CLR_2 (0x0008 >> 2) -#define V_BLEND_SET_GLOBAL_ALPHA_REG (0x000C >> 2) -#define V_BLEND_OUTPUT_VID_FORMAT (0x0014 >> 2) -#define V_BLEND_LAYER0_CONTROL (0x0018 >> 2) -#define V_BLEND_LAYER1_CONTROL (0x001C >> 2) - -#define V_BLEND_RGB2YCBCR_COEFF(n) ((0x0020 + 4 * n) >> 2) -#define V_BLEND_IN1CSC_COEFF(n) ((0x0044 + 4 * n) >> 2) - -#define V_BLEND_LUMA_IN1CSC_OFFSET (0x0068 >> 2) -#define V_BLEND_CR_IN1CSC_OFFSET (0x006C >> 2) -#define V_BLEND_CB_IN1CSC_OFFSET (0x0070 >> 2) -#define V_BLEND_LUMA_OUTCSC_OFFSET (0x0074 >> 2) -#define V_BLEND_CR_OUTCSC_OFFSET (0x0078 >> 2) -#define V_BLEND_CB_OUTCSC_OFFSET (0x007C >> 2) - -#define V_BLEND_IN2CSC_COEFF(n) ((0x0080 + 4 * n) >> 2) - -#define V_BLEND_LUMA_IN2CSC_OFFSET (0x00A4 >> 2) -#define V_BLEND_CR_IN2CSC_OFFSET (0x00A8 >> 2) -#define V_BLEND_CB_IN2CSC_OFFSET (0x00AC >> 2) -#define V_BLEND_CHROMA_KEY_ENABLE (0x01D0 >> 2) -#define V_BLEND_CHROMA_KEY_COMP1 (0x01D4 >> 2) -#define V_BLEND_CHROMA_KEY_COMP2 (0x01D8 >> 2) -#define V_BLEND_CHROMA_KEY_COMP3 (0x01DC >> 2) - -/* - * Registers offset for Audio Video Buffer configuration. - */ -#define AV_BUF_MANAGER_OFFSET (0xB000) -#define AV_BUF_FORMAT (0x0000 >> 2) -#define AV_BUF_NON_LIVE_LATENCY (0x0008 >> 2) -#define AV_CHBUF0 (0x0010 >> 2) -#define AV_CHBUF1 (0x0014 >> 2) -#define AV_CHBUF2 (0x0018 >> 2) -#define AV_CHBUF3 (0x001C >> 2) -#define AV_CHBUF4 (0x0020 >> 2) -#define AV_CHBUF5 (0x0024 >> 2) -#define AV_BUF_STC_CONTROL (0x002C >> 2) -#define AV_BUF_STC_INIT_VALUE0 (0x0030 >> 2) -#define AV_BUF_STC_INIT_VALUE1 (0x0034 >> 2) -#define AV_BUF_STC_ADJ (0x0038 >> 2) -#define AV_BUF_STC_VIDEO_VSYNC_TS_REG0 (0x003C >> 2) -#define AV_BUF_STC_VIDEO_VSYNC_TS_REG1 (0x0040 >> 2) -#define AV_BUF_STC_EXT_VSYNC_TS_REG0 (0x0044 >> 2) -#define AV_BUF_STC_EXT_VSYNC_TS_REG1 (0x0048 >> 2) -#define AV_BUF_STC_CUSTOM_EVENT_TS_REG0 (0x004C >> 2) -#define AV_BUF_STC_CUSTOM_EVENT_TS_REG1 (0x0050 >> 2) -#define AV_BUF_STC_CUSTOM_EVENT2_TS_REG0 (0x0054 >> 2) -#define AV_BUF_STC_CUSTOM_EVENT2_TS_REG1 (0x0058 >> 2) -#define AV_BUF_STC_SNAPSHOT0 (0x0060 >> 2) -#define AV_BUF_STC_SNAPSHOT1 (0x0064 >> 2) -#define AV_BUF_OUTPUT_AUDIO_VIDEO_SELECT (0x0070 >> 2) -#define AV_BUF_HCOUNT_VCOUNT_INT0 (0x0074 >> 2) -#define AV_BUF_HCOUNT_VCOUNT_INT1 (0x0078 >> 2) -#define AV_BUF_DITHER_CONFIG (0x007C >> 2) -#define AV_BUF_DITHER_CONFIG_MAX (0x008C >> 2) -#define AV_BUF_DITHER_CONFIG_MIN (0x0090 >> 2) -#define AV_BUF_PATTERN_GEN_SELECT (0x0100 >> 2) -#define AV_BUF_AUD_VID_CLK_SOURCE (0x0120 >> 2) -#define AV_BUF_SRST_REG (0x0124 >> 2) -#define AV_BUF_AUDIO_RDY_INTERVAL (0x0128 >> 2) -#define AV_BUF_AUDIO_CH_CONFIG (0x012C >> 2) - -#define AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(n)((0x0200 + 4 * n) >> 2) - -#define AV_BUF_VIDEO_COMP_SCALE_FACTOR(n) ((0x020C + 4 * n) >> 2) - -#define AV_BUF_LIVE_VIDEO_COMP_SF(n) ((0x0218 + 4 * n) >> 2) - -#define AV_BUF_LIVE_VID_CONFIG (0x0224 >> 2) - -#define AV_BUF_LIVE_GFX_COMP_SF(n) ((0x0228 + 4 * n) >> 2) - -#define AV_BUF_LIVE_GFX_CONFIG (0x0234 >> 2) - -#define AUDIO_MIXER_REGISTER_OFFSET (0xC000) -#define AUDIO_MIXER_VOLUME_CONTROL (0x0000 >> 2) -#define AUDIO_MIXER_META_DATA (0x0004 >> 2) -#define AUD_CH_STATUS_REG(n) ((0x0008 + 4 * n) >> 2) -#define AUD_CH_A_DATA_REG(n) ((0x0020 + 4 * n) >> 2) -#define AUD_CH_B_DATA_REG(n) ((0x0038 + 4 * n) >> 2) - -#define DP_AUDIO_DMA_CHANNEL(n) (4 + n) -#define DP_GRAPHIC_DMA_CHANNEL (3) -#define DP_VIDEO_DMA_CHANNEL (0) - -enum DPGraphicFmt { - DP_GRAPHIC_RGBA8888 = 0 << 8, - DP_GRAPHIC_ABGR8888 = 1 << 8, - DP_GRAPHIC_RGB888 = 2 << 8, - DP_GRAPHIC_BGR888 = 3 << 8, - DP_GRAPHIC_RGBA5551 = 4 << 8, - DP_GRAPHIC_RGBA4444 = 5 << 8, - DP_GRAPHIC_RGB565 = 6 << 8, - DP_GRAPHIC_8BPP = 7 << 8, - DP_GRAPHIC_4BPP = 8 << 8, - DP_GRAPHIC_2BPP = 9 << 8, - DP_GRAPHIC_1BPP = 10 << 8, - DP_GRAPHIC_MASK = 0xF << 8 -}; - -enum DPVideoFmt { - DP_NL_VID_CB_Y0_CR_Y1 = 0, - DP_NL_VID_CR_Y0_CB_Y1 = 1, - DP_NL_VID_Y0_CR_Y1_CB = 2, - DP_NL_VID_Y0_CB_Y1_CR = 3, - DP_NL_VID_YV16 = 4, - DP_NL_VID_YV24 = 5, - DP_NL_VID_YV16CL = 6, - DP_NL_VID_MONO = 7, - DP_NL_VID_YV16CL2 = 8, - DP_NL_VID_YUV444 = 9, - DP_NL_VID_RGB888 = 10, - DP_NL_VID_RGBA8880 = 11, - DP_NL_VID_RGB888_10BPC = 12, - DP_NL_VID_YUV444_10BPC = 13, - DP_NL_VID_YV16CL2_10BPC = 14, - DP_NL_VID_YV16CL_10BPC = 15, - DP_NL_VID_YV16_10BPC = 16, - DP_NL_VID_YV24_10BPC = 17, - DP_NL_VID_Y_ONLY_10BPC = 18, - DP_NL_VID_YV16_420 = 19, - DP_NL_VID_YV16CL_420 = 20, - DP_NL_VID_YV16CL2_420 = 21, - DP_NL_VID_YV16_420_10BPC = 22, - DP_NL_VID_YV16CL_420_10BPC = 23, - DP_NL_VID_YV16CL2_420_10BPC = 24, - DP_NL_VID_FMT_MASK = 0x1F -}; - -typedef enum DPGraphicFmt DPGraphicFmt; -typedef enum DPVideoFmt DPVideoFmt; - -static const VMStateDescription vmstate_dp = { - .name = TYPE_XLNX_DP, - .version_id = 1, - .fields = (VMStateField[]){ - VMSTATE_UINT32_ARRAY(core_registers, XlnxDPState, - DP_CORE_REG_ARRAY_SIZE), - VMSTATE_UINT32_ARRAY(avbufm_registers, XlnxDPState, - DP_AVBUF_REG_ARRAY_SIZE), - VMSTATE_UINT32_ARRAY(vblend_registers, XlnxDPState, - DP_VBLEND_REG_ARRAY_SIZE), - VMSTATE_UINT32_ARRAY(audio_registers, XlnxDPState, - DP_AUDIO_REG_ARRAY_SIZE), - VMSTATE_END_OF_LIST() - } -}; - -static void xlnx_dp_update_irq(XlnxDPState *s); - -static uint64_t xlnx_dp_audio_read(void *opaque, hwaddr offset, unsigned size) -{ - XlnxDPState *s = XLNX_DP(opaque); - - offset = offset >> 2; - return s->audio_registers[offset]; -} - -static void xlnx_dp_audio_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - XlnxDPState *s = XLNX_DP(opaque); - - offset = offset >> 2; - - switch (offset) { - case AUDIO_MIXER_META_DATA: - s->audio_registers[offset] = value & 0x00000001; - break; - default: - s->audio_registers[offset] = value; - break; - } -} - -static const MemoryRegionOps audio_ops = { - .read = xlnx_dp_audio_read, - .write = xlnx_dp_audio_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static inline uint32_t xlnx_dp_audio_get_volume(XlnxDPState *s, - uint8_t channel) -{ - switch (channel) { - case 0: - return extract32(s->audio_registers[AUDIO_MIXER_VOLUME_CONTROL], 0, 16); - case 1: - return extract32(s->audio_registers[AUDIO_MIXER_VOLUME_CONTROL], 16, - 16); - default: - return 0; - } -} - -static inline void xlnx_dp_audio_activate(XlnxDPState *s) -{ - bool activated = ((s->core_registers[DP_TX_AUDIO_CONTROL] - & DP_TX_AUD_CTRL) != 0); - AUD_set_active_out(s->amixer_output_stream, activated); - xlnx_dpdma_set_host_data_location(s->dpdma, DP_AUDIO_DMA_CHANNEL(0), - &s->audio_buffer_0); - xlnx_dpdma_set_host_data_location(s->dpdma, DP_AUDIO_DMA_CHANNEL(1), - &s->audio_buffer_1); -} - -static inline void xlnx_dp_audio_mix_buffer(XlnxDPState *s) -{ - /* - * Audio packets are signed and have this shape: - * | 16 | 16 | 16 | 16 | 16 | 16 | 16 | 16 | - * | R3 | L3 | R2 | L2 | R1 | L1 | R0 | L0 | - * - * Output audio is 16bits saturated. - */ - int i; - - if ((s->audio_data_available[0]) && (xlnx_dp_audio_get_volume(s, 0))) { - for (i = 0; i < s->audio_data_available[0] / 2; i++) { - s->temp_buffer[i] = (int64_t)(s->audio_buffer_0[i]) - * xlnx_dp_audio_get_volume(s, 0) / 8192; - } - s->byte_left = s->audio_data_available[0]; - } else { - memset(s->temp_buffer, 0, s->audio_data_available[1] / 2); - } - - if ((s->audio_data_available[1]) && (xlnx_dp_audio_get_volume(s, 1))) { - if ((s->audio_data_available[0] == 0) - || (s->audio_data_available[1] == s->audio_data_available[0])) { - for (i = 0; i < s->audio_data_available[1] / 2; i++) { - s->temp_buffer[i] += (int64_t)(s->audio_buffer_1[i]) - * xlnx_dp_audio_get_volume(s, 1) / 8192; - } - s->byte_left = s->audio_data_available[1]; - } - } - - for (i = 0; i < s->byte_left / 2; i++) { - s->out_buffer[i] = MAX(-32767, MIN(s->temp_buffer[i], 32767)); - } - - s->data_ptr = 0; -} - -static void xlnx_dp_audio_callback(void *opaque, int avail) -{ - /* - * Get some data from the DPDMA and compute these datas. - * Then wait for QEMU's audio subsystem to call this callback. - */ - XlnxDPState *s = XLNX_DP(opaque); - size_t written = 0; - - /* If there are already some data don't get more data. */ - if (s->byte_left == 0) { - s->audio_data_available[0] = xlnx_dpdma_start_operation(s->dpdma, 4, - true); - s->audio_data_available[1] = xlnx_dpdma_start_operation(s->dpdma, 5, - true); - xlnx_dp_audio_mix_buffer(s); - } - - /* Send the buffer through the audio. */ - if (s->byte_left <= MAX_QEMU_BUFFER_SIZE) { - if (s->byte_left != 0) { - written = AUD_write(s->amixer_output_stream, - &s->out_buffer[s->data_ptr], s->byte_left); - } else { - /* - * There is nothing to play.. We don't have any data! Fill the - * buffer with zero's and send it. - */ - written = 0; - memset(s->out_buffer, 0, 1024); - AUD_write(s->amixer_output_stream, s->out_buffer, 1024); - } - } else { - written = AUD_write(s->amixer_output_stream, - &s->out_buffer[s->data_ptr], MAX_QEMU_BUFFER_SIZE); - } - s->byte_left -= written; - s->data_ptr += written; -} - -/* - * AUX channel related function. - */ -static void xlnx_dp_aux_clear_rx_fifo(XlnxDPState *s) -{ - fifo8_reset(&s->rx_fifo); -} - -static void xlnx_dp_aux_push_rx_fifo(XlnxDPState *s, uint8_t *buf, size_t len) -{ - DPRINTF("Push %u data in rx_fifo\n", (unsigned)len); - fifo8_push_all(&s->rx_fifo, buf, len); -} - -static uint8_t xlnx_dp_aux_pop_rx_fifo(XlnxDPState *s) -{ - uint8_t ret; - - if (fifo8_is_empty(&s->rx_fifo)) { - DPRINTF("rx_fifo underflow..\n"); - abort(); - } - ret = fifo8_pop(&s->rx_fifo); - DPRINTF("pop 0x%" PRIX8 " from rx_fifo.\n", ret); - return ret; -} - -static void xlnx_dp_aux_clear_tx_fifo(XlnxDPState *s) -{ - fifo8_reset(&s->tx_fifo); -} - -static void xlnx_dp_aux_push_tx_fifo(XlnxDPState *s, uint8_t *buf, size_t len) -{ - DPRINTF("Push %u data in tx_fifo\n", (unsigned)len); - fifo8_push_all(&s->tx_fifo, buf, len); -} - -static uint8_t xlnx_dp_aux_pop_tx_fifo(XlnxDPState *s) -{ - uint8_t ret; - - if (fifo8_is_empty(&s->tx_fifo)) { - DPRINTF("tx_fifo underflow..\n"); - abort(); - } - ret = fifo8_pop(&s->tx_fifo); - DPRINTF("pop 0x%2.2X from tx_fifo.\n", ret); - return ret; -} - -static uint32_t xlnx_dp_aux_get_address(XlnxDPState *s) -{ - return s->core_registers[DP_AUX_ADDRESS]; -} - -/* - * Get command from the register. - */ -static void xlnx_dp_aux_set_command(XlnxDPState *s, uint32_t value) -{ - bool address_only = (value & AUX_ADDR_ONLY_MASK) != 0; - AUXCommand cmd = (value & AUX_COMMAND_MASK) >> AUX_COMMAND_SHIFT; - uint8_t nbytes = (value & AUX_COMMAND_NBYTES) + 1; - uint8_t buf[16]; - int i; - - /* - * When an address_only command is executed nothing happen to the fifo, so - * just make nbytes = 0. - */ - if (address_only) { - nbytes = 0; - } - - switch (cmd) { - case READ_AUX: - case READ_I2C: - case READ_I2C_MOT: - s->core_registers[DP_AUX_REPLY_CODE] = aux_request(s->aux_bus, cmd, - xlnx_dp_aux_get_address(s), - nbytes, buf); - s->core_registers[DP_REPLY_DATA_COUNT] = nbytes; - - if (s->core_registers[DP_AUX_REPLY_CODE] == AUX_I2C_ACK) { - xlnx_dp_aux_push_rx_fifo(s, buf, nbytes); - } - break; - case WRITE_AUX: - case WRITE_I2C: - case WRITE_I2C_MOT: - for (i = 0; i < nbytes; i++) { - buf[i] = xlnx_dp_aux_pop_tx_fifo(s); - } - s->core_registers[DP_AUX_REPLY_CODE] = aux_request(s->aux_bus, cmd, - xlnx_dp_aux_get_address(s), - nbytes, buf); - xlnx_dp_aux_clear_tx_fifo(s); - break; - case WRITE_I2C_STATUS: - qemu_log_mask(LOG_UNIMP, "xlnx_dp: Write i2c status not implemented\n"); - break; - default: - abort(); - } - - s->core_registers[DP_INTERRUPT_SIGNAL_STATE] |= 0x04; -} - -static void xlnx_dp_set_dpdma(Object *obj, const char *name, Object *val, - Error **errp) -{ - XlnxDPState *s = XLNX_DP(obj); - if (s->console) { - DisplaySurface *surface = qemu_console_surface(s->console); - XlnxDPDMAState *dma = XLNX_DPDMA(val); - xlnx_dpdma_set_host_data_location(dma, DP_GRAPHIC_DMA_CHANNEL, - surface_data(surface)); - } -} - -static inline uint8_t xlnx_dp_global_alpha_value(XlnxDPState *s) -{ - return (s->vblend_registers[V_BLEND_SET_GLOBAL_ALPHA_REG] & 0x1FE) >> 1; -} - -static inline bool xlnx_dp_global_alpha_enabled(XlnxDPState *s) -{ - /* - * If the alpha is totally opaque (255) we consider the alpha is disabled to - * reduce CPU consumption. - */ - return ((xlnx_dp_global_alpha_value(s) != 0xFF) && - ((s->vblend_registers[V_BLEND_SET_GLOBAL_ALPHA_REG] & 0x01) != 0)); -} - -static void xlnx_dp_recreate_surface(XlnxDPState *s) -{ - /* - * Two possibilities, if blending is enabled the console displays - * bout_plane, if not g_plane is displayed. - */ - uint16_t width = s->core_registers[DP_MAIN_STREAM_HRES]; - uint16_t height = s->core_registers[DP_MAIN_STREAM_VRES]; - DisplaySurface *current_console_surface = qemu_console_surface(s->console); - - if ((width != 0) && (height != 0)) { - /* - * As dpy_gfx_replace_surface calls qemu_free_displaysurface on the - * surface we need to be carefull and don't free the surface associated - * to the console or double free will happen. - */ - if (s->bout_plane.surface != current_console_surface) { - qemu_free_displaysurface(s->bout_plane.surface); - } - if (s->v_plane.surface != current_console_surface) { - qemu_free_displaysurface(s->v_plane.surface); - } - if (s->g_plane.surface != current_console_surface) { - qemu_free_displaysurface(s->g_plane.surface); - } - - s->g_plane.surface - = qemu_create_displaysurface_from(width, height, - s->g_plane.format, 0, NULL); - s->v_plane.surface - = qemu_create_displaysurface_from(width, height, - s->v_plane.format, 0, NULL); - if (xlnx_dp_global_alpha_enabled(s)) { - s->bout_plane.surface = - qemu_create_displaysurface_from(width, - height, - s->g_plane.format, - 0, NULL); - dpy_gfx_replace_surface(s->console, s->bout_plane.surface); - } else { - s->bout_plane.surface = NULL; - dpy_gfx_replace_surface(s->console, s->g_plane.surface); - } - - xlnx_dpdma_set_host_data_location(s->dpdma, DP_GRAPHIC_DMA_CHANNEL, - surface_data(s->g_plane.surface)); - xlnx_dpdma_set_host_data_location(s->dpdma, DP_VIDEO_DMA_CHANNEL, - surface_data(s->v_plane.surface)); - } -} - -/* - * Change the graphic format of the surface. - */ -static void xlnx_dp_change_graphic_fmt(XlnxDPState *s) -{ - switch (s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK) { - case DP_GRAPHIC_RGBA8888: - s->g_plane.format = PIXMAN_r8g8b8a8; - break; - case DP_GRAPHIC_ABGR8888: - s->g_plane.format = PIXMAN_a8b8g8r8; - break; - case DP_GRAPHIC_RGB565: - s->g_plane.format = PIXMAN_r5g6b5; - break; - case DP_GRAPHIC_RGB888: - s->g_plane.format = PIXMAN_r8g8b8; - break; - case DP_GRAPHIC_BGR888: - s->g_plane.format = PIXMAN_b8g8r8; - break; - default: - DPRINTF("error: unsupported graphic format %u.\n", - s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK); - abort(); - } - - switch (s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK) { - case 0: - s->v_plane.format = PIXMAN_x8b8g8r8; - break; - case DP_NL_VID_RGBA8880: - s->v_plane.format = PIXMAN_x8b8g8r8; - break; - default: - DPRINTF("error: unsupported video format %u.\n", - s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK); - abort(); - } - - xlnx_dp_recreate_surface(s); -} - -static void xlnx_dp_update_irq(XlnxDPState *s) -{ - uint32_t flags; - - flags = s->core_registers[DP_INT_STATUS] & ~s->core_registers[DP_INT_MASK]; - DPRINTF("update IRQ value = %" PRIx32 "\n", flags); - qemu_set_irq(s->irq, flags != 0); -} - -static uint64_t xlnx_dp_read(void *opaque, hwaddr offset, unsigned size) -{ - XlnxDPState *s = XLNX_DP(opaque); - uint64_t ret = 0; - - offset = offset >> 2; - - switch (offset) { - case DP_TX_USER_FIFO_OVERFLOW: - /* This register is cleared after a read */ - ret = s->core_registers[DP_TX_USER_FIFO_OVERFLOW]; - s->core_registers[DP_TX_USER_FIFO_OVERFLOW] = 0; - break; - case DP_AUX_REPLY_DATA: - ret = xlnx_dp_aux_pop_rx_fifo(s); - break; - case DP_INTERRUPT_SIGNAL_STATE: - /* - * XXX: Not sure it is the right thing to do actually. - * The register is not written by the device driver so it's stuck - * to 0x04. - */ - ret = s->core_registers[DP_INTERRUPT_SIGNAL_STATE]; - s->core_registers[DP_INTERRUPT_SIGNAL_STATE] &= ~0x04; - break; - case DP_AUX_WRITE_FIFO: - case DP_TX_AUDIO_INFO_DATA(0): - case DP_TX_AUDIO_INFO_DATA(1): - case DP_TX_AUDIO_INFO_DATA(2): - case DP_TX_AUDIO_INFO_DATA(3): - case DP_TX_AUDIO_INFO_DATA(4): - case DP_TX_AUDIO_INFO_DATA(5): - case DP_TX_AUDIO_INFO_DATA(6): - case DP_TX_AUDIO_INFO_DATA(7): - case DP_TX_AUDIO_EXT_DATA(0): - case DP_TX_AUDIO_EXT_DATA(1): - case DP_TX_AUDIO_EXT_DATA(2): - case DP_TX_AUDIO_EXT_DATA(3): - case DP_TX_AUDIO_EXT_DATA(4): - case DP_TX_AUDIO_EXT_DATA(5): - case DP_TX_AUDIO_EXT_DATA(6): - case DP_TX_AUDIO_EXT_DATA(7): - case DP_TX_AUDIO_EXT_DATA(8): - /* write only registers */ - ret = 0; - break; - default: - assert(offset <= (0x3AC >> 2)); - ret = s->core_registers[offset]; - break; - } - - DPRINTF("core read @%" PRIx64 " = 0x%8.8" PRIX64 "\n", offset << 2, ret); - return ret; -} - -static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - XlnxDPState *s = XLNX_DP(opaque); - - DPRINTF("core write @%" PRIx64 " = 0x%8.8" PRIX64 "\n", offset, value); - - offset = offset >> 2; - - switch (offset) { - /* - * Only special write case are handled. - */ - case DP_LINK_BW_SET: - s->core_registers[offset] = value & 0x000000FF; - break; - case DP_LANE_COUNT_SET: - case DP_MAIN_STREAM_MISC0: - s->core_registers[offset] = value & 0x0000000F; - break; - case DP_TRAINING_PATTERN_SET: - case DP_LINK_QUAL_PATTERN_SET: - case DP_MAIN_STREAM_POLARITY: - case DP_PHY_VOLTAGE_DIFF_LANE_0: - case DP_PHY_VOLTAGE_DIFF_LANE_1: - s->core_registers[offset] = value & 0x00000003; - break; - case DP_ENHANCED_FRAME_EN: - case DP_SCRAMBLING_DISABLE: - case DP_DOWNSPREAD_CTRL: - case DP_MAIN_STREAM_ENABLE: - case DP_TRANSMIT_PRBS7: - s->core_registers[offset] = value & 0x00000001; - break; - case DP_PHY_CLOCK_SELECT: - s->core_registers[offset] = value & 0x00000007; - break; - case DP_SOFTWARE_RESET: - /* - * No need to update this bit as it's read '0'. - */ - /* - * TODO: reset IP. - */ - break; - case DP_TRANSMITTER_ENABLE: - s->core_registers[offset] = value & 0x01; - break; - case DP_FORCE_SCRAMBLER_RESET: - /* - * No need to update this bit as it's read '0'. - */ - /* - * TODO: force a scrambler reset?? - */ - break; - case DP_AUX_COMMAND_REGISTER: - s->core_registers[offset] = value & 0x00001F0F; - xlnx_dp_aux_set_command(s, s->core_registers[offset]); - break; - case DP_MAIN_STREAM_HTOTAL: - case DP_MAIN_STREAM_VTOTAL: - case DP_MAIN_STREAM_HSTART: - case DP_MAIN_STREAM_VSTART: - s->core_registers[offset] = value & 0x0000FFFF; - break; - case DP_MAIN_STREAM_HRES: - case DP_MAIN_STREAM_VRES: - s->core_registers[offset] = value & 0x0000FFFF; - xlnx_dp_recreate_surface(s); - break; - case DP_MAIN_STREAM_HSWIDTH: - case DP_MAIN_STREAM_VSWIDTH: - s->core_registers[offset] = value & 0x00007FFF; - break; - case DP_MAIN_STREAM_MISC1: - s->core_registers[offset] = value & 0x00000086; - break; - case DP_MAIN_STREAM_M_VID: - case DP_MAIN_STREAM_N_VID: - s->core_registers[offset] = value & 0x00FFFFFF; - break; - case DP_MSA_TRANSFER_UNIT_SIZE: - case DP_MIN_BYTES_PER_TU: - case DP_INIT_WAIT: - s->core_registers[offset] = value & 0x00000007; - break; - case DP_USER_DATA_COUNT_PER_LANE: - s->core_registers[offset] = value & 0x0003FFFF; - break; - case DP_FRAC_BYTES_PER_TU: - s->core_registers[offset] = value & 0x000003FF; - break; - case DP_PHY_RESET: - s->core_registers[offset] = value & 0x00010003; - /* - * TODO: Reset something? - */ - break; - case DP_TX_PHY_POWER_DOWN: - s->core_registers[offset] = value & 0x0000000F; - /* - * TODO: Power down things? - */ - break; - case DP_AUX_WRITE_FIFO: { - uint8_t c = value; - xlnx_dp_aux_push_tx_fifo(s, &c, 1); - break; - } - case DP_AUX_CLOCK_DIVIDER: - break; - case DP_AUX_REPLY_COUNT: - /* - * Writing to this register clear the counter. - */ - s->core_registers[offset] = 0x00000000; - break; - case DP_AUX_ADDRESS: - s->core_registers[offset] = value & 0x000FFFFF; - break; - case DP_VERSION_REGISTER: - case DP_CORE_ID: - case DP_TX_USER_FIFO_OVERFLOW: - case DP_AUX_REPLY_DATA: - case DP_AUX_REPLY_CODE: - case DP_REPLY_DATA_COUNT: - case DP_REPLY_STATUS: - case DP_HPD_DURATION: - /* - * Write to read only location.. - */ - break; - case DP_TX_AUDIO_CONTROL: - s->core_registers[offset] = value & 0x00000001; - xlnx_dp_audio_activate(s); - break; - case DP_TX_AUDIO_CHANNELS: - s->core_registers[offset] = value & 0x00000007; - xlnx_dp_audio_activate(s); - break; - case DP_INT_STATUS: - s->core_registers[DP_INT_STATUS] &= ~value; - xlnx_dp_update_irq(s); - break; - case DP_INT_EN: - s->core_registers[DP_INT_MASK] &= ~value; - xlnx_dp_update_irq(s); - break; - case DP_INT_DS: - s->core_registers[DP_INT_MASK] |= ~value; - xlnx_dp_update_irq(s); - break; - default: - assert(offset <= (0x504C >> 2)); - s->core_registers[offset] = value; - break; - } -} - -static const MemoryRegionOps dp_ops = { - .read = xlnx_dp_read, - .write = xlnx_dp_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -/* - * This is to handle Read/Write to the Video Blender. - */ -static void xlnx_dp_vblend_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - XlnxDPState *s = XLNX_DP(opaque); - bool alpha_was_enabled; - - DPRINTF("vblend: write @0x%" HWADDR_PRIX " = 0x%" PRIX32 "\n", offset, - (uint32_t)value); - offset = offset >> 2; - - switch (offset) { - case V_BLEND_BG_CLR_0: - case V_BLEND_BG_CLR_1: - case V_BLEND_BG_CLR_2: - s->vblend_registers[offset] = value & 0x00000FFF; - break; - case V_BLEND_SET_GLOBAL_ALPHA_REG: - /* - * A write to this register can enable or disable blending. Thus we need - * to recreate the surfaces. - */ - alpha_was_enabled = xlnx_dp_global_alpha_enabled(s); - s->vblend_registers[offset] = value & 0x000001FF; - if (xlnx_dp_global_alpha_enabled(s) != alpha_was_enabled) { - xlnx_dp_recreate_surface(s); - } - break; - case V_BLEND_OUTPUT_VID_FORMAT: - s->vblend_registers[offset] = value & 0x00000017; - break; - case V_BLEND_LAYER0_CONTROL: - case V_BLEND_LAYER1_CONTROL: - s->vblend_registers[offset] = value & 0x00000103; - break; - case V_BLEND_RGB2YCBCR_COEFF(0): - case V_BLEND_RGB2YCBCR_COEFF(1): - case V_BLEND_RGB2YCBCR_COEFF(2): - case V_BLEND_RGB2YCBCR_COEFF(3): - case V_BLEND_RGB2YCBCR_COEFF(4): - case V_BLEND_RGB2YCBCR_COEFF(5): - case V_BLEND_RGB2YCBCR_COEFF(6): - case V_BLEND_RGB2YCBCR_COEFF(7): - case V_BLEND_RGB2YCBCR_COEFF(8): - case V_BLEND_IN1CSC_COEFF(0): - case V_BLEND_IN1CSC_COEFF(1): - case V_BLEND_IN1CSC_COEFF(2): - case V_BLEND_IN1CSC_COEFF(3): - case V_BLEND_IN1CSC_COEFF(4): - case V_BLEND_IN1CSC_COEFF(5): - case V_BLEND_IN1CSC_COEFF(6): - case V_BLEND_IN1CSC_COEFF(7): - case V_BLEND_IN1CSC_COEFF(8): - case V_BLEND_IN2CSC_COEFF(0): - case V_BLEND_IN2CSC_COEFF(1): - case V_BLEND_IN2CSC_COEFF(2): - case V_BLEND_IN2CSC_COEFF(3): - case V_BLEND_IN2CSC_COEFF(4): - case V_BLEND_IN2CSC_COEFF(5): - case V_BLEND_IN2CSC_COEFF(6): - case V_BLEND_IN2CSC_COEFF(7): - case V_BLEND_IN2CSC_COEFF(8): - s->vblend_registers[offset] = value & 0x0000FFFF; - break; - case V_BLEND_LUMA_IN1CSC_OFFSET: - case V_BLEND_CR_IN1CSC_OFFSET: - case V_BLEND_CB_IN1CSC_OFFSET: - case V_BLEND_LUMA_IN2CSC_OFFSET: - case V_BLEND_CR_IN2CSC_OFFSET: - case V_BLEND_CB_IN2CSC_OFFSET: - case V_BLEND_LUMA_OUTCSC_OFFSET: - case V_BLEND_CR_OUTCSC_OFFSET: - case V_BLEND_CB_OUTCSC_OFFSET: - s->vblend_registers[offset] = value & 0x3FFF7FFF; - break; - case V_BLEND_CHROMA_KEY_ENABLE: - s->vblend_registers[offset] = value & 0x00000003; - break; - case V_BLEND_CHROMA_KEY_COMP1: - case V_BLEND_CHROMA_KEY_COMP2: - case V_BLEND_CHROMA_KEY_COMP3: - s->vblend_registers[offset] = value & 0x0FFF0FFF; - break; - default: - s->vblend_registers[offset] = value; - break; - } -} - -static uint64_t xlnx_dp_vblend_read(void *opaque, hwaddr offset, - unsigned size) -{ - XlnxDPState *s = XLNX_DP(opaque); - - DPRINTF("vblend: read @0x%" HWADDR_PRIX " = 0x%" PRIX32 "\n", offset, - s->vblend_registers[offset >> 2]); - return s->vblend_registers[offset >> 2]; -} - -static const MemoryRegionOps vblend_ops = { - .read = xlnx_dp_vblend_read, - .write = xlnx_dp_vblend_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -/* - * This is to handle Read/Write to the Audio Video buffer manager. - */ -static void xlnx_dp_avbufm_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - XlnxDPState *s = XLNX_DP(opaque); - - DPRINTF("avbufm: write @0x%" HWADDR_PRIX " = 0x%" PRIX32 "\n", offset, - (uint32_t)value); - offset = offset >> 2; - - switch (offset) { - case AV_BUF_FORMAT: - s->avbufm_registers[offset] = value & 0x00000FFF; - xlnx_dp_change_graphic_fmt(s); - break; - case AV_CHBUF0: - case AV_CHBUF1: - case AV_CHBUF2: - case AV_CHBUF3: - case AV_CHBUF4: - case AV_CHBUF5: - s->avbufm_registers[offset] = value & 0x0000007F; - break; - case AV_BUF_OUTPUT_AUDIO_VIDEO_SELECT: - s->avbufm_registers[offset] = value & 0x0000007F; - break; - case AV_BUF_DITHER_CONFIG: - s->avbufm_registers[offset] = value & 0x000007FF; - break; - case AV_BUF_DITHER_CONFIG_MAX: - case AV_BUF_DITHER_CONFIG_MIN: - s->avbufm_registers[offset] = value & 0x00000FFF; - break; - case AV_BUF_PATTERN_GEN_SELECT: - s->avbufm_registers[offset] = value & 0xFFFFFF03; - break; - case AV_BUF_AUD_VID_CLK_SOURCE: - s->avbufm_registers[offset] = value & 0x00000007; - break; - case AV_BUF_SRST_REG: - s->avbufm_registers[offset] = value & 0x00000002; - break; - case AV_BUF_AUDIO_CH_CONFIG: - s->avbufm_registers[offset] = value & 0x00000003; - break; - case AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(0): - case AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(1): - case AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(2): - case AV_BUF_VIDEO_COMP_SCALE_FACTOR(0): - case AV_BUF_VIDEO_COMP_SCALE_FACTOR(1): - case AV_BUF_VIDEO_COMP_SCALE_FACTOR(2): - s->avbufm_registers[offset] = value & 0x0000FFFF; - break; - case AV_BUF_LIVE_VIDEO_COMP_SF(0): - case AV_BUF_LIVE_VIDEO_COMP_SF(1): - case AV_BUF_LIVE_VIDEO_COMP_SF(2): - case AV_BUF_LIVE_VID_CONFIG: - case AV_BUF_LIVE_GFX_COMP_SF(0): - case AV_BUF_LIVE_GFX_COMP_SF(1): - case AV_BUF_LIVE_GFX_COMP_SF(2): - case AV_BUF_LIVE_GFX_CONFIG: - case AV_BUF_NON_LIVE_LATENCY: - case AV_BUF_STC_CONTROL: - case AV_BUF_STC_INIT_VALUE0: - case AV_BUF_STC_INIT_VALUE1: - case AV_BUF_STC_ADJ: - case AV_BUF_STC_VIDEO_VSYNC_TS_REG0: - case AV_BUF_STC_VIDEO_VSYNC_TS_REG1: - case AV_BUF_STC_EXT_VSYNC_TS_REG0: - case AV_BUF_STC_EXT_VSYNC_TS_REG1: - case AV_BUF_STC_CUSTOM_EVENT_TS_REG0: - case AV_BUF_STC_CUSTOM_EVENT_TS_REG1: - case AV_BUF_STC_CUSTOM_EVENT2_TS_REG0: - case AV_BUF_STC_CUSTOM_EVENT2_TS_REG1: - case AV_BUF_STC_SNAPSHOT0: - case AV_BUF_STC_SNAPSHOT1: - case AV_BUF_HCOUNT_VCOUNT_INT0: - case AV_BUF_HCOUNT_VCOUNT_INT1: - qemu_log_mask(LOG_UNIMP, "avbufm: unimplmented"); - break; - default: - s->avbufm_registers[offset] = value; - break; - } -} - -static uint64_t xlnx_dp_avbufm_read(void *opaque, hwaddr offset, - unsigned size) -{ - XlnxDPState *s = XLNX_DP(opaque); - - offset = offset >> 2; - return s->avbufm_registers[offset]; -} - -static const MemoryRegionOps avbufm_ops = { - .read = xlnx_dp_avbufm_read, - .write = xlnx_dp_avbufm_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -/* - * This is a global alpha blending using pixman. - * Both graphic and video planes are multiplied with the global alpha - * coefficient and added. - */ -static inline void xlnx_dp_blend_surface(XlnxDPState *s) -{ - pixman_fixed_t alpha1[] = { pixman_double_to_fixed(1), - pixman_double_to_fixed(1), - pixman_double_to_fixed(1.0) }; - pixman_fixed_t alpha2[] = { pixman_double_to_fixed(1), - pixman_double_to_fixed(1), - pixman_double_to_fixed(1.0) }; - - if ((surface_width(s->g_plane.surface) - != surface_width(s->v_plane.surface)) || - (surface_height(s->g_plane.surface) - != surface_height(s->v_plane.surface))) { - return; - } - - alpha1[2] = pixman_double_to_fixed((double)(xlnx_dp_global_alpha_value(s)) - / 256.0); - alpha2[2] = pixman_double_to_fixed((255.0 - - (double)xlnx_dp_global_alpha_value(s)) - / 256.0); - - pixman_image_set_filter(s->g_plane.surface->image, - PIXMAN_FILTER_CONVOLUTION, alpha1, 3); - pixman_image_composite(PIXMAN_OP_SRC, s->g_plane.surface->image, 0, - s->bout_plane.surface->image, 0, 0, 0, 0, 0, 0, - surface_width(s->g_plane.surface), - surface_height(s->g_plane.surface)); - pixman_image_set_filter(s->v_plane.surface->image, - PIXMAN_FILTER_CONVOLUTION, alpha2, 3); - pixman_image_composite(PIXMAN_OP_ADD, s->v_plane.surface->image, 0, - s->bout_plane.surface->image, 0, 0, 0, 0, 0, 0, - surface_width(s->g_plane.surface), - surface_height(s->g_plane.surface)); -} - -static void xlnx_dp_update_display(void *opaque) -{ - XlnxDPState *s = XLNX_DP(opaque); - - if ((s->core_registers[DP_TRANSMITTER_ENABLE] & 0x01) == 0) { - return; - } - - s->core_registers[DP_INT_STATUS] |= (1 << 13); - xlnx_dp_update_irq(s); - - xlnx_dpdma_trigger_vsync_irq(s->dpdma); - - /* - * Trigger the DMA channel. - */ - if (!xlnx_dpdma_start_operation(s->dpdma, 3, false)) { - /* - * An error occured don't do anything with the data.. - * Trigger an underflow interrupt. - */ - s->core_registers[DP_INT_STATUS] |= (1 << 21); - xlnx_dp_update_irq(s); - return; - } - - if (xlnx_dp_global_alpha_enabled(s)) { - if (!xlnx_dpdma_start_operation(s->dpdma, 0, false)) { - s->core_registers[DP_INT_STATUS] |= (1 << 21); - xlnx_dp_update_irq(s); - return; - } - xlnx_dp_blend_surface(s); - } - - /* - * XXX: We might want to update only what changed. - */ - dpy_gfx_update(s->console, 0, 0, surface_width(s->g_plane.surface), - surface_height(s->g_plane.surface)); -} - -static const GraphicHwOps xlnx_dp_gfx_ops = { - .gfx_update = xlnx_dp_update_display, -}; - -static void xlnx_dp_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - XlnxDPState *s = XLNX_DP(obj); - - memory_region_init(&s->container, obj, TYPE_XLNX_DP, 0xC050); - - memory_region_init_io(&s->core_iomem, obj, &dp_ops, s, TYPE_XLNX_DP - ".core", 0x3AF); - memory_region_add_subregion(&s->container, 0x0000, &s->core_iomem); - - memory_region_init_io(&s->vblend_iomem, obj, &vblend_ops, s, TYPE_XLNX_DP - ".v_blend", 0x1DF); - memory_region_add_subregion(&s->container, 0xA000, &s->vblend_iomem); - - memory_region_init_io(&s->avbufm_iomem, obj, &avbufm_ops, s, TYPE_XLNX_DP - ".av_buffer_manager", 0x238); - memory_region_add_subregion(&s->container, 0xB000, &s->avbufm_iomem); - - memory_region_init_io(&s->audio_iomem, obj, &audio_ops, s, TYPE_XLNX_DP - ".audio", sizeof(s->audio_registers)); - memory_region_add_subregion(&s->container, 0xC000, &s->audio_iomem); - - sysbus_init_mmio(sbd, &s->container); - sysbus_init_irq(sbd, &s->irq); - - object_property_add_link(obj, "dpdma", TYPE_XLNX_DPDMA, - (Object **) &s->dpdma, - xlnx_dp_set_dpdma, - OBJ_PROP_LINK_UNREF_ON_RELEASE, - &error_abort); - - /* - * Initialize AUX Bus. - */ - s->aux_bus = aux_init_bus(DEVICE(obj), "aux"); - - /* - * Initialize DPCD and EDID.. - */ - s->dpcd = DPCD(aux_create_slave(s->aux_bus, "dpcd", 0x00000)); - s->edid = I2CDDC(qdev_create(BUS(aux_get_i2c_bus(s->aux_bus)), "i2c-ddc")); - i2c_set_slave_address(I2C_SLAVE(s->edid), 0x50); - - fifo8_create(&s->rx_fifo, 16); - fifo8_create(&s->tx_fifo, 16); -} - -static void xlnx_dp_realize(DeviceState *dev, Error **errp) -{ - XlnxDPState *s = XLNX_DP(dev); - DisplaySurface *surface; - struct audsettings as; - - s->console = graphic_console_init(dev, 0, &xlnx_dp_gfx_ops, s); - surface = qemu_console_surface(s->console); - xlnx_dpdma_set_host_data_location(s->dpdma, DP_GRAPHIC_DMA_CHANNEL, - surface_data(surface)); - - as.freq = 44100; - as.nchannels = 2; - as.fmt = AUD_FMT_S16; - as.endianness = 0; - - AUD_register_card("xlnx_dp.audio", &s->aud_card); - - s->amixer_output_stream = AUD_open_out(&s->aud_card, - s->amixer_output_stream, - "xlnx_dp.audio.out", - s, - xlnx_dp_audio_callback, - &as); - AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255); - xlnx_dp_audio_activate(s); -} - -static void xlnx_dp_reset(DeviceState *dev) -{ - XlnxDPState *s = XLNX_DP(dev); - - memset(s->core_registers, 0, sizeof(s->core_registers)); - s->core_registers[DP_VERSION_REGISTER] = 0x04010000; - s->core_registers[DP_CORE_ID] = 0x01020000; - s->core_registers[DP_REPLY_STATUS] = 0x00000010; - s->core_registers[DP_MSA_TRANSFER_UNIT_SIZE] = 0x00000040; - s->core_registers[DP_INIT_WAIT] = 0x00000020; - s->core_registers[DP_PHY_RESET] = 0x00010003; - s->core_registers[DP_INT_MASK] = 0xFFFFF03F; - s->core_registers[DP_PHY_STATUS] = 0x00000043; - s->core_registers[DP_INTERRUPT_SIGNAL_STATE] = 0x00000001; - - s->vblend_registers[V_BLEND_RGB2YCBCR_COEFF(0)] = 0x00001000; - s->vblend_registers[V_BLEND_RGB2YCBCR_COEFF(4)] = 0x00001000; - s->vblend_registers[V_BLEND_RGB2YCBCR_COEFF(8)] = 0x00001000; - s->vblend_registers[V_BLEND_IN1CSC_COEFF(0)] = 0x00001000; - s->vblend_registers[V_BLEND_IN1CSC_COEFF(4)] = 0x00001000; - s->vblend_registers[V_BLEND_IN1CSC_COEFF(8)] = 0x00001000; - s->vblend_registers[V_BLEND_IN2CSC_COEFF(0)] = 0x00001000; - s->vblend_registers[V_BLEND_IN2CSC_COEFF(4)] = 0x00001000; - s->vblend_registers[V_BLEND_IN2CSC_COEFF(8)] = 0x00001000; - - s->avbufm_registers[AV_BUF_NON_LIVE_LATENCY] = 0x00000180; - s->avbufm_registers[AV_BUF_OUTPUT_AUDIO_VIDEO_SELECT] = 0x00000008; - s->avbufm_registers[AV_BUF_DITHER_CONFIG_MAX] = 0x00000FFF; - s->avbufm_registers[AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(0)] = 0x00010101; - s->avbufm_registers[AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(1)] = 0x00010101; - s->avbufm_registers[AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(2)] = 0x00010101; - s->avbufm_registers[AV_BUF_VIDEO_COMP_SCALE_FACTOR(0)] = 0x00010101; - s->avbufm_registers[AV_BUF_VIDEO_COMP_SCALE_FACTOR(1)] = 0x00010101; - s->avbufm_registers[AV_BUF_VIDEO_COMP_SCALE_FACTOR(2)] = 0x00010101; - s->avbufm_registers[AV_BUF_LIVE_VIDEO_COMP_SF(0)] = 0x00010101; - s->avbufm_registers[AV_BUF_LIVE_VIDEO_COMP_SF(1)] = 0x00010101; - s->avbufm_registers[AV_BUF_LIVE_VIDEO_COMP_SF(2)] = 0x00010101; - s->avbufm_registers[AV_BUF_LIVE_GFX_COMP_SF(0)] = 0x00010101; - s->avbufm_registers[AV_BUF_LIVE_GFX_COMP_SF(1)] = 0x00010101; - s->avbufm_registers[AV_BUF_LIVE_GFX_COMP_SF(2)] = 0x00010101; - - memset(s->audio_registers, 0, sizeof(s->audio_registers)); - s->byte_left = 0; - - xlnx_dp_aux_clear_rx_fifo(s); - xlnx_dp_change_graphic_fmt(s); - xlnx_dp_update_irq(s); -} - -static void xlnx_dp_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->realize = xlnx_dp_realize; - dc->vmsd = &vmstate_dp; - dc->reset = xlnx_dp_reset; -} - -static const TypeInfo xlnx_dp_info = { - .name = TYPE_XLNX_DP, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(XlnxDPState), - .instance_init = xlnx_dp_init, - .class_init = xlnx_dp_class_init, -}; - -static void xlnx_dp_register_types(void) -{ - type_register_static(&xlnx_dp_info); -} - -type_init(xlnx_dp_register_types) diff --git a/hw/dma/Makefile.objs b/hw/dma/Makefile.objs index 087c8e685..a1abbcf74 100644 --- a/hw/dma/Makefile.objs +++ b/hw/dma/Makefile.objs @@ -5,11 +5,9 @@ common-obj-$(CONFIG_PL330) += pl330.o common-obj-$(CONFIG_I82374) += i82374.o common-obj-$(CONFIG_I8257) += i8257.o common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o -common-obj-$(CONFIG_ZYNQ_DEVCFG) += xlnx-zynq-devcfg.o common-obj-$(CONFIG_ETRAXFS) += etraxfs_dma.o common-obj-$(CONFIG_STP2000) += sparc32_dma.o common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o -obj-$(CONFIG_XLNX_ZYNQMP) += xlnx_dpdma.o obj-$(CONFIG_OMAP) += omap_dma.o soc_dma.o obj-$(CONFIG_PXA2XX) += pxa2xx_dma.o diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c index 5d144a263..542117599 100644 --- a/hw/dma/bcm2835_dma.c +++ b/hw/dma/bcm2835_dma.c @@ -6,7 +6,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/dma/bcm2835_dma.h" -#include "qemu/log.h" /* DMA CS Control and Status bits */ #define BCM2708_DMA_ACTIVE (1 << 0) diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c index 3bed5c339..9318108b8 100644 --- a/hw/dma/pl080.c +++ b/hw/dma/pl080.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" -#include "qemu/log.h" #define PL080_MAX_CHANNELS 8 #define PL080_CONF_E 0x1 diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c index c0bd9fec3..ea89ecb00 100644 --- a/hw/dma/pl330.c +++ b/hw/dma/pl330.c @@ -19,7 +19,6 @@ #include "qapi/error.h" #include "qemu/timer.h" #include "sysemu/dma.h" -#include "qemu/log.h" #ifndef PL330_ERR_DEBUG #define PL330_ERR_DEBUG 0 diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c index 634a4328f..2306abc35 100644 --- a/hw/dma/pxa2xx_dma.c +++ b/hw/dma/pxa2xx_dma.c @@ -12,7 +12,6 @@ #include "hw/hw.h" #include "hw/arm/pxa.h" #include "hw/sysbus.h" -#include "qapi/error.h" #define PXA255_DMA_NUM_CHANNELS 16 #define PXA27X_DMA_NUM_CHANNELS 32 @@ -451,36 +450,31 @@ static void pxa2xx_dma_request(void *opaque, int req_num, int on) } } -static void pxa2xx_dma_init(Object *obj) -{ - DeviceState *dev = DEVICE(obj); - PXA2xxDMAState *s = PXA2XX_DMA(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - - memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS); - - qdev_init_gpio_in(dev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS); - - memory_region_init_io(&s->iomem, obj, &pxa2xx_dma_ops, s, - "pxa2xx.dma", 0x00010000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); -} - -static void pxa2xx_dma_realize(DeviceState *dev, Error **errp) +static int pxa2xx_dma_init(SysBusDevice *sbd) { + DeviceState *dev = DEVICE(sbd); PXA2xxDMAState *s = PXA2XX_DMA(dev); int i; if (s->channels <= 0) { - error_setg(errp, "channels value invalid"); - return; + return -1; } s->chan = g_new0(PXA2xxDMAChannel, s->channels); for (i = 0; i < s->channels; i ++) s->chan[i].state = DCSR_STOPINTR; + + memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS); + + qdev_init_gpio_in(dev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS); + + memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_dma_ops, s, + "pxa2xx.dma", 0x00010000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + + return 0; } DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq) @@ -559,18 +553,18 @@ static Property pxa2xx_dma_properties[] = { static void pxa2xx_dma_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = pxa2xx_dma_init; dc->desc = "PXA2xx DMA controller"; dc->vmsd = &vmstate_pxa2xx_dma; dc->props = pxa2xx_dma_properties; - dc->realize = pxa2xx_dma_realize; } static const TypeInfo pxa2xx_dma_info = { .name = TYPE_PXA2XX_DMA, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PXA2xxDMAState), - .instance_init = pxa2xx_dma_init, .class_init = pxa2xx_dma_class_init, }; diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index 2f2576faf..a06c2359a 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -27,7 +27,6 @@ #include "hw/mips/mips.h" #include "hw/sysbus.h" #include "qemu/timer.h" -#include "qemu/log.h" #include "exec/address-spaces.h" #include "trace.h" diff --git a/hw/dma/trace-events b/hw/dma/trace-events deleted file mode 100644 index 22878dfdb..000000000 --- a/hw/dma/trace-events +++ /dev/null @@ -1,32 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/dma/rc4030.c -jazzio_read(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x" -jazzio_write(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x" -rc4030_read(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x" -rc4030_write(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x" - -# hw/dma/sparc32_dma.c -ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64 -ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64 -sparc32_dma_set_irq_raise(void) "Raise IRQ" -sparc32_dma_set_irq_lower(void) "Lower IRQ" -espdma_memory_read(uint32_t addr) "DMA read addr 0x%08x" -espdma_memory_write(uint32_t addr) "DMA write addr 0x%08x" -sparc32_dma_mem_readl(uint64_t addr, uint32_t ret) "read dmareg %"PRIx64": 0x%08x" -sparc32_dma_mem_writel(uint64_t addr, uint32_t old, uint32_t val) "write dmareg %"PRIx64": 0x%08x -> 0x%08x" -sparc32_dma_enable_raise(void) "Raise DMA enable" -sparc32_dma_enable_lower(void) "Lower DMA enable" - -# hw/dma/sun4m_iommu.c -sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[%"PRIx64"] = %x" -sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[%"PRIx64"] = %x" -sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = %"PRIx64 -sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush %x" -sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush %x" -sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr %"PRIx64" => pte %"PRIx64", *pte = %x" -sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x" -sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64 - -# hw/dma/i8257.c -i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d" diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c deleted file mode 100644 index 3b1052343..000000000 --- a/hw/dma/xlnx-zynq-devcfg.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * QEMU model of the Xilinx Zynq Devcfg Interface - * - * (C) 2011 PetaLogix Pty Ltd - * (C) 2014 Xilinx Inc. - * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "hw/dma/xlnx-zynq-devcfg.h" -#include "qemu/bitops.h" -#include "sysemu/sysemu.h" -#include "sysemu/dma.h" -#include "qemu/log.h" - -#define FREQ_HZ 900000000 - -#define BTT_MAX 0x400 - -#ifndef XLNX_ZYNQ_DEVCFG_ERR_DEBUG -#define XLNX_ZYNQ_DEVCFG_ERR_DEBUG 0 -#endif - -#define DB_PRINT(fmt, args...) do { \ - if (XLNX_ZYNQ_DEVCFG_ERR_DEBUG) { \ - qemu_log("%s: " fmt, __func__, ## args); \ - } \ -} while (0); - -REG32(CTRL, 0x00) - FIELD(CTRL, FORCE_RST, 31, 1) /* Not supported, wr ignored */ - FIELD(CTRL, PCAP_PR, 27, 1) /* Forced to 0 on bad unlock */ - FIELD(CTRL, PCAP_MODE, 26, 1) - FIELD(CTRL, MULTIBOOT_EN, 24, 1) - FIELD(CTRL, USER_MODE, 15, 1) - FIELD(CTRL, PCFG_AES_FUSE, 12, 1) - FIELD(CTRL, PCFG_AES_EN, 9, 3) - FIELD(CTRL, SEU_EN, 8, 1) - FIELD(CTRL, SEC_EN, 7, 1) - FIELD(CTRL, SPNIDEN, 6, 1) - FIELD(CTRL, SPIDEN, 5, 1) - FIELD(CTRL, NIDEN, 4, 1) - FIELD(CTRL, DBGEN, 3, 1) - FIELD(CTRL, DAP_EN, 0, 3) - -REG32(LOCK, 0x04) -#define AES_FUSE_LOCK 4 -#define AES_EN_LOCK 3 -#define SEU_LOCK 2 -#define SEC_LOCK 1 -#define DBG_LOCK 0 - -/* mapping bits in R_LOCK to what they lock in R_CTRL */ -static const uint32_t lock_ctrl_map[] = { - [AES_FUSE_LOCK] = R_CTRL_PCFG_AES_FUSE_MASK, - [AES_EN_LOCK] = R_CTRL_PCFG_AES_EN_MASK, - [SEU_LOCK] = R_CTRL_SEU_EN_MASK, - [SEC_LOCK] = R_CTRL_SEC_EN_MASK, - [DBG_LOCK] = R_CTRL_SPNIDEN_MASK | R_CTRL_SPIDEN_MASK | - R_CTRL_NIDEN_MASK | R_CTRL_DBGEN_MASK | - R_CTRL_DAP_EN_MASK, -}; - -REG32(CFG, 0x08) - FIELD(CFG, RFIFO_TH, 10, 2) - FIELD(CFG, WFIFO_TH, 8, 2) - FIELD(CFG, RCLK_EDGE, 7, 1) - FIELD(CFG, WCLK_EDGE, 6, 1) - FIELD(CFG, DISABLE_SRC_INC, 5, 1) - FIELD(CFG, DISABLE_DST_INC, 4, 1) -#define R_CFG_RESET 0x50B - -REG32(INT_STS, 0x0C) - FIELD(INT_STS, PSS_GTS_USR_B, 31, 1) - FIELD(INT_STS, PSS_FST_CFG_B, 30, 1) - FIELD(INT_STS, PSS_CFG_RESET_B, 27, 1) - FIELD(INT_STS, RX_FIFO_OV, 18, 1) - FIELD(INT_STS, WR_FIFO_LVL, 17, 1) - FIELD(INT_STS, RD_FIFO_LVL, 16, 1) - FIELD(INT_STS, DMA_CMD_ERR, 15, 1) - FIELD(INT_STS, DMA_Q_OV, 14, 1) - FIELD(INT_STS, DMA_DONE, 13, 1) - FIELD(INT_STS, DMA_P_DONE, 12, 1) - FIELD(INT_STS, P2D_LEN_ERR, 11, 1) - FIELD(INT_STS, PCFG_DONE, 2, 1) -#define R_INT_STS_RSVD ((0x7 << 24) | (0x1 << 19) | (0xF < 7)) - -REG32(INT_MASK, 0x10) - -REG32(STATUS, 0x14) - FIELD(STATUS, DMA_CMD_Q_F, 31, 1) - FIELD(STATUS, DMA_CMD_Q_E, 30, 1) - FIELD(STATUS, DMA_DONE_CNT, 28, 2) - FIELD(STATUS, RX_FIFO_LVL, 20, 5) - FIELD(STATUS, TX_FIFO_LVL, 12, 7) - FIELD(STATUS, PSS_GTS_USR_B, 11, 1) - FIELD(STATUS, PSS_FST_CFG_B, 10, 1) - FIELD(STATUS, PSS_CFG_RESET_B, 5, 1) - -REG32(DMA_SRC_ADDR, 0x18) -REG32(DMA_DST_ADDR, 0x1C) -REG32(DMA_SRC_LEN, 0x20) -REG32(DMA_DST_LEN, 0x24) -REG32(ROM_SHADOW, 0x28) -REG32(SW_ID, 0x30) -REG32(UNLOCK, 0x34) - -#define R_UNLOCK_MAGIC 0x757BDF0D - -REG32(MCTRL, 0x80) - FIELD(MCTRL, PS_VERSION, 28, 4) - FIELD(MCTRL, PCFG_POR_B, 8, 1) - FIELD(MCTRL, INT_PCAP_LPBK, 4, 1) - FIELD(MCTRL, QEMU, 3, 1) - -static void xlnx_zynq_devcfg_update_ixr(XlnxZynqDevcfg *s) -{ - qemu_set_irq(s->irq, ~s->regs[R_INT_MASK] & s->regs[R_INT_STS]); -} - -static void xlnx_zynq_devcfg_reset(DeviceState *dev) -{ - XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(dev); - int i; - - for (i = 0; i < XLNX_ZYNQ_DEVCFG_R_MAX; ++i) { - register_reset(&s->regs_info[i]); - } -} - -static void xlnx_zynq_devcfg_dma_go(XlnxZynqDevcfg *s) -{ - do { - uint8_t buf[BTT_MAX]; - XlnxZynqDevcfgDMACmd *dmah = s->dma_cmd_fifo; - uint32_t btt = BTT_MAX; - bool loopback = s->regs[R_MCTRL] & R_MCTRL_INT_PCAP_LPBK_MASK; - - btt = MIN(btt, dmah->src_len); - if (loopback) { - btt = MIN(btt, dmah->dest_len); - } - DB_PRINT("reading %x bytes from %x\n", btt, dmah->src_addr); - dma_memory_read(&address_space_memory, dmah->src_addr, buf, btt); - dmah->src_len -= btt; - dmah->src_addr += btt; - if (loopback && (dmah->src_len || dmah->dest_len)) { - DB_PRINT("writing %x bytes from %x\n", btt, dmah->dest_addr); - dma_memory_write(&address_space_memory, dmah->dest_addr, buf, btt); - dmah->dest_len -= btt; - dmah->dest_addr += btt; - } - if (!dmah->src_len && !dmah->dest_len) { - DB_PRINT("dma operation finished\n"); - s->regs[R_INT_STS] |= R_INT_STS_DMA_DONE_MASK | - R_INT_STS_DMA_P_DONE_MASK; - s->dma_cmd_fifo_num--; - memmove(s->dma_cmd_fifo, &s->dma_cmd_fifo[1], - sizeof(s->dma_cmd_fifo) - sizeof(s->dma_cmd_fifo[0])); - } - xlnx_zynq_devcfg_update_ixr(s); - } while (s->dma_cmd_fifo_num); -} - -static void r_ixr_post_write(RegisterInfo *reg, uint64_t val) -{ - XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); - - xlnx_zynq_devcfg_update_ixr(s); -} - -static uint64_t r_ctrl_pre_write(RegisterInfo *reg, uint64_t val) -{ - XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); - int i; - - for (i = 0; i < ARRAY_SIZE(lock_ctrl_map); ++i) { - if (s->regs[R_LOCK] & 1 << i) { - val &= ~lock_ctrl_map[i]; - val |= lock_ctrl_map[i] & s->regs[R_CTRL]; - } - } - return val; -} - -static void r_ctrl_post_write(RegisterInfo *reg, uint64_t val) -{ - const char *device_prefix = object_get_typename(OBJECT(reg->opaque)); - uint32_t aes_en = FIELD_EX32(val, CTRL, PCFG_AES_EN); - - if (aes_en != 0 && aes_en != 7) { - qemu_log_mask(LOG_UNIMP, "%s: warning, aes-en bits inconsistent," - "unimplemented security reset should happen!\n", - device_prefix); - } -} - -static void r_unlock_post_write(RegisterInfo *reg, uint64_t val) -{ - XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); - const char *device_prefix = object_get_typename(OBJECT(s)); - - if (val == R_UNLOCK_MAGIC) { - DB_PRINT("successful unlock\n"); - s->regs[R_CTRL] |= R_CTRL_PCAP_PR_MASK; - s->regs[R_CTRL] |= R_CTRL_PCFG_AES_EN_MASK; - memory_region_set_enabled(&s->iomem, true); - } else { /* bad unlock attempt */ - qemu_log_mask(LOG_GUEST_ERROR, "%s: failed unlock\n", device_prefix); - s->regs[R_CTRL] &= ~R_CTRL_PCAP_PR_MASK; - s->regs[R_CTRL] &= ~R_CTRL_PCFG_AES_EN_MASK; - /* core becomes inaccessible */ - memory_region_set_enabled(&s->iomem, false); - } -} - -static uint64_t r_lock_pre_write(RegisterInfo *reg, uint64_t val) -{ - XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); - - /* once bits are locked they stay locked */ - return s->regs[R_LOCK] | val; -} - -static void r_dma_dst_len_post_write(RegisterInfo *reg, uint64_t val) -{ - XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque); - - s->dma_cmd_fifo[s->dma_cmd_fifo_num] = (XlnxZynqDevcfgDMACmd) { - .src_addr = s->regs[R_DMA_SRC_ADDR] & ~0x3UL, - .dest_addr = s->regs[R_DMA_DST_ADDR] & ~0x3UL, - .src_len = s->regs[R_DMA_SRC_LEN] << 2, - .dest_len = s->regs[R_DMA_DST_LEN] << 2, - }; - s->dma_cmd_fifo_num++; - DB_PRINT("dma transfer started; %d total transfers pending\n", - s->dma_cmd_fifo_num); - xlnx_zynq_devcfg_dma_go(s); -} - -static const RegisterAccessInfo xlnx_zynq_devcfg_regs_info[] = { - { .name = "CTRL", .addr = A_CTRL, - .reset = R_CTRL_PCAP_PR_MASK | R_CTRL_PCAP_MODE_MASK | 0x3 << 13, - .rsvd = 0x1 << 28 | 0x3ff << 13 | 0x3 << 13, - .pre_write = r_ctrl_pre_write, - .post_write = r_ctrl_post_write, - }, - { .name = "LOCK", .addr = A_LOCK, - .rsvd = MAKE_64BIT_MASK(5, 64 - 5), - .pre_write = r_lock_pre_write, - }, - { .name = "CFG", .addr = A_CFG, - .reset = R_CFG_RESET, - .rsvd = 0xfffff00f, - }, - { .name = "INT_STS", .addr = A_INT_STS, - .w1c = ~R_INT_STS_RSVD, - .reset = R_INT_STS_PSS_GTS_USR_B_MASK | - R_INT_STS_PSS_CFG_RESET_B_MASK | - R_INT_STS_WR_FIFO_LVL_MASK, - .rsvd = R_INT_STS_RSVD, - .post_write = r_ixr_post_write, - }, - { .name = "INT_MASK", .addr = A_INT_MASK, - .reset = ~0, - .rsvd = R_INT_STS_RSVD, - .post_write = r_ixr_post_write, - }, - { .name = "STATUS", .addr = A_STATUS, - .reset = R_STATUS_DMA_CMD_Q_E_MASK | - R_STATUS_PSS_GTS_USR_B_MASK | - R_STATUS_PSS_CFG_RESET_B_MASK, - .ro = ~0, - }, - { .name = "DMA_SRC_ADDR", .addr = A_DMA_SRC_ADDR, }, - { .name = "DMA_DST_ADDR", .addr = A_DMA_DST_ADDR, }, - { .name = "DMA_SRC_LEN", .addr = A_DMA_SRC_LEN, - .ro = MAKE_64BIT_MASK(27, 64 - 27) }, - { .name = "DMA_DST_LEN", .addr = A_DMA_DST_LEN, - .ro = MAKE_64BIT_MASK(27, 64 - 27), - .post_write = r_dma_dst_len_post_write, - }, - { .name = "ROM_SHADOW", .addr = A_ROM_SHADOW, - .rsvd = ~0ull, - }, - { .name = "SW_ID", .addr = A_SW_ID, }, - { .name = "UNLOCK", .addr = A_UNLOCK, - .post_write = r_unlock_post_write, - }, - { .name = "MCTRL", .addr = R_MCTRL * 4, - /* Silicon 3.0 for version field, the mysterious reserved bit 23 - * and QEMU platform identifier. - */ - .reset = 0x2 << R_MCTRL_PS_VERSION_SHIFT | 1 << 23 | R_MCTRL_QEMU_MASK, - .ro = ~R_MCTRL_INT_PCAP_LPBK_MASK, - .rsvd = 0x00f00303, - }, -}; - -static const MemoryRegionOps xlnx_zynq_devcfg_reg_ops = { - .read = register_read_memory, - .write = register_write_memory, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - } -}; - -static const VMStateDescription vmstate_xlnx_zynq_devcfg_dma_cmd = { - .name = "xlnx_zynq_devcfg_dma_cmd", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(src_addr, XlnxZynqDevcfgDMACmd), - VMSTATE_UINT32(dest_addr, XlnxZynqDevcfgDMACmd), - VMSTATE_UINT32(src_len, XlnxZynqDevcfgDMACmd), - VMSTATE_UINT32(dest_len, XlnxZynqDevcfgDMACmd), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_xlnx_zynq_devcfg = { - .name = "xlnx_zynq_devcfg", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT_ARRAY(dma_cmd_fifo, XlnxZynqDevcfg, - XLNX_ZYNQ_DEVCFG_DMA_CMD_FIFO_LEN, 0, - vmstate_xlnx_zynq_devcfg_dma_cmd, - XlnxZynqDevcfgDMACmd), - VMSTATE_UINT8(dma_cmd_fifo_num, XlnxZynqDevcfg), - VMSTATE_UINT32_ARRAY(regs, XlnxZynqDevcfg, XLNX_ZYNQ_DEVCFG_R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void xlnx_zynq_devcfg_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(obj); - RegisterInfoArray *reg_array; - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init(&s->iomem, obj, "devcfg", XLNX_ZYNQ_DEVCFG_R_MAX * 4); - reg_array = - register_init_block32(DEVICE(obj), xlnx_zynq_devcfg_regs_info, - ARRAY_SIZE(xlnx_zynq_devcfg_regs_info), - s->regs_info, s->regs, - &xlnx_zynq_devcfg_reg_ops, - XLNX_ZYNQ_DEVCFG_ERR_DEBUG, - XLNX_ZYNQ_DEVCFG_R_MAX); - memory_region_add_subregion(&s->iomem, - A_CTRL, - ®_array->mem); - - sysbus_init_mmio(sbd, &s->iomem); -} - -static void xlnx_zynq_devcfg_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = xlnx_zynq_devcfg_reset; - dc->vmsd = &vmstate_xlnx_zynq_devcfg; -} - -static const TypeInfo xlnx_zynq_devcfg_info = { - .name = TYPE_XLNX_ZYNQ_DEVCFG, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(XlnxZynqDevcfg), - .instance_init = xlnx_zynq_devcfg_init, - .class_init = xlnx_zynq_devcfg_class_init, -}; - -static void xlnx_zynq_devcfg_register_types(void) -{ - type_register_static(&xlnx_zynq_devcfg_info); -} - -type_init(xlnx_zynq_devcfg_register_types) diff --git a/hw/dma/xlnx_dpdma.c b/hw/dma/xlnx_dpdma.c deleted file mode 100644 index 8ceb21ddb..000000000 --- a/hw/dma/xlnx_dpdma.c +++ /dev/null @@ -1,786 +0,0 @@ -/* - * xlnx_dpdma.c - * - * Copyright (C) 2015 : GreenSocs Ltd - * http://www.greensocs.com/ , email: info@greensocs.com - * - * Developed by : - * Frederic Konrad <fred.konrad@greensocs.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "hw/dma/xlnx_dpdma.h" - -#ifndef DEBUG_DPDMA -#define DEBUG_DPDMA 0 -#endif - -#define DPRINTF(fmt, ...) do { \ - if (DEBUG_DPDMA) { \ - qemu_log("xlnx_dpdma: " fmt , ## __VA_ARGS__); \ - } \ -} while (0); - -/* - * Registers offset for DPDMA. - */ -#define DPDMA_ERR_CTRL (0x0000) -#define DPDMA_ISR (0x0004 >> 2) -#define DPDMA_IMR (0x0008 >> 2) -#define DPDMA_IEN (0x000C >> 2) -#define DPDMA_IDS (0x0010 >> 2) -#define DPDMA_EISR (0x0014 >> 2) -#define DPDMA_EIMR (0x0018 >> 2) -#define DPDMA_EIEN (0x001C >> 2) -#define DPDMA_EIDS (0x0020 >> 2) -#define DPDMA_CNTL (0x0100 >> 2) - -#define DPDMA_GBL (0x0104 >> 2) -#define DPDMA_GBL_TRG_CH(n) (1 << n) -#define DPDMA_GBL_RTRG_CH(n) (1 << 6 << n) - -#define DPDMA_ALC0_CNTL (0x0108 >> 2) -#define DPDMA_ALC0_STATUS (0x010C >> 2) -#define DPDMA_ALC0_MAX (0x0110 >> 2) -#define DPDMA_ALC0_MIN (0x0114 >> 2) -#define DPDMA_ALC0_ACC (0x0118 >> 2) -#define DPDMA_ALC0_ACC_TRAN (0x011C >> 2) -#define DPDMA_ALC1_CNTL (0x0120 >> 2) -#define DPDMA_ALC1_STATUS (0x0124 >> 2) -#define DPDMA_ALC1_MAX (0x0128 >> 2) -#define DPDMA_ALC1_MIN (0x012C >> 2) -#define DPDMA_ALC1_ACC (0x0130 >> 2) -#define DPDMA_ALC1_ACC_TRAN (0x0134 >> 2) - -#define DPDMA_DSCR_STRT_ADDRE_CH(n) ((0x0200 + n * 0x100) >> 2) -#define DPDMA_DSCR_STRT_ADDR_CH(n) ((0x0204 + n * 0x100) >> 2) -#define DPDMA_DSCR_NEXT_ADDRE_CH(n) ((0x0208 + n * 0x100) >> 2) -#define DPDMA_DSCR_NEXT_ADDR_CH(n) ((0x020C + n * 0x100) >> 2) -#define DPDMA_PYLD_CUR_ADDRE_CH(n) ((0x0210 + n * 0x100) >> 2) -#define DPDMA_PYLD_CUR_ADDR_CH(n) ((0x0214 + n * 0x100) >> 2) - -#define DPDMA_CNTL_CH(n) ((0x0218 + n * 0x100) >> 2) -#define DPDMA_CNTL_CH_EN (1) -#define DPDMA_CNTL_CH_PAUSED (1 << 1) - -#define DPDMA_STATUS_CH(n) ((0x021C + n * 0x100) >> 2) -#define DPDMA_STATUS_BURST_TYPE (1 << 4) -#define DPDMA_STATUS_MODE (1 << 5) -#define DPDMA_STATUS_EN_CRC (1 << 6) -#define DPDMA_STATUS_LAST_DSCR (1 << 7) -#define DPDMA_STATUS_LDSCR_FRAME (1 << 8) -#define DPDMA_STATUS_IGNR_DONE (1 << 9) -#define DPDMA_STATUS_DSCR_DONE (1 << 10) -#define DPDMA_STATUS_EN_DSCR_UP (1 << 11) -#define DPDMA_STATUS_EN_DSCR_INTR (1 << 12) -#define DPDMA_STATUS_PREAMBLE_OFF (13) - -#define DPDMA_VDO_CH(n) ((0x0220 + n * 0x100) >> 2) -#define DPDMA_PYLD_SZ_CH(n) ((0x0224 + n * 0x100) >> 2) -#define DPDMA_DSCR_ID_CH(n) ((0x0228 + n * 0x100) >> 2) - -/* - * Descriptor control field. - */ -#define CONTROL_PREAMBLE_VALUE 0xA5 - -#define DSCR_CTRL_PREAMBLE 0xFF -#define DSCR_CTRL_EN_DSCR_DONE_INTR (1 << 8) -#define DSCR_CTRL_EN_DSCR_UPDATE (1 << 9) -#define DSCR_CTRL_IGNORE_DONE (1 << 10) -#define DSCR_CTRL_AXI_BURST_TYPE (1 << 11) -#define DSCR_CTRL_AXCACHE (0x0F << 12) -#define DSCR_CTRL_AXPROT (0x2 << 16) -#define DSCR_CTRL_DESCRIPTOR_MODE (1 << 18) -#define DSCR_CTRL_LAST_DESCRIPTOR (1 << 19) -#define DSCR_CTRL_ENABLE_CRC (1 << 20) -#define DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME (1 << 21) - -/* - * Descriptor timestamp field. - */ -#define STATUS_DONE (1 << 31) - -#define DPDMA_FRAG_MAX_SZ (4096) - -enum DPDMABurstType { - DPDMA_INCR = 0, - DPDMA_FIXED = 1 -}; - -enum DPDMAMode { - DPDMA_CONTIGOUS = 0, - DPDMA_FRAGMENTED = 1 -}; - -struct DPDMADescriptor { - uint32_t control; - uint32_t descriptor_id; - /* transfer size in byte. */ - uint32_t xfer_size; - uint32_t line_size_stride; - uint32_t timestamp_lsb; - uint32_t timestamp_msb; - /* contains extension for both descriptor and source. */ - uint32_t address_extension; - uint32_t next_descriptor; - uint32_t source_address; - uint32_t address_extension_23; - uint32_t address_extension_45; - uint32_t source_address2; - uint32_t source_address3; - uint32_t source_address4; - uint32_t source_address5; - uint32_t crc; -}; - -typedef enum DPDMABurstType DPDMABurstType; -typedef enum DPDMAMode DPDMAMode; -typedef struct DPDMADescriptor DPDMADescriptor; - -static bool xlnx_dpdma_desc_is_last(DPDMADescriptor *desc) -{ - return ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR) != 0); -} - -static bool xlnx_dpdma_desc_is_last_of_frame(DPDMADescriptor *desc) -{ - return ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME) != 0); -} - -static uint64_t xlnx_dpdma_desc_get_source_address(DPDMADescriptor *desc, - uint8_t frag) -{ - uint64_t addr = 0; - assert(frag < 5); - - switch (frag) { - case 0: - addr = desc->source_address - + (extract32(desc->address_extension, 16, 12) << 20); - break; - case 1: - addr = desc->source_address2 - + (extract32(desc->address_extension_23, 0, 12) << 8); - break; - case 2: - addr = desc->source_address3 - + (extract32(desc->address_extension_23, 16, 12) << 20); - break; - case 3: - addr = desc->source_address4 - + (extract32(desc->address_extension_45, 0, 12) << 8); - break; - case 4: - addr = desc->source_address5 - + (extract32(desc->address_extension_45, 16, 12) << 20); - break; - default: - addr = 0; - break; - } - - return addr; -} - -static uint32_t xlnx_dpdma_desc_get_transfer_size(DPDMADescriptor *desc) -{ - return desc->xfer_size; -} - -static uint32_t xlnx_dpdma_desc_get_line_size(DPDMADescriptor *desc) -{ - return extract32(desc->line_size_stride, 0, 18); -} - -static uint32_t xlnx_dpdma_desc_get_line_stride(DPDMADescriptor *desc) -{ - return extract32(desc->line_size_stride, 18, 14) * 16; -} - -static inline bool xlnx_dpdma_desc_crc_enabled(DPDMADescriptor *desc) -{ - return (desc->control & DSCR_CTRL_ENABLE_CRC) != 0; -} - -static inline bool xlnx_dpdma_desc_check_crc(DPDMADescriptor *desc) -{ - uint32_t *p = (uint32_t *)desc; - uint32_t crc = 0; - uint8_t i; - - /* - * CRC is calculated on the whole descriptor except the last 32bits word - * using 32bits addition. - */ - for (i = 0; i < 15; i++) { - crc += p[i]; - } - - return crc == desc->crc; -} - -static inline bool xlnx_dpdma_desc_completion_interrupt(DPDMADescriptor *desc) -{ - return (desc->control & DSCR_CTRL_EN_DSCR_DONE_INTR) != 0; -} - -static inline bool xlnx_dpdma_desc_is_valid(DPDMADescriptor *desc) -{ - return (desc->control & DSCR_CTRL_PREAMBLE) == CONTROL_PREAMBLE_VALUE; -} - -static inline bool xlnx_dpdma_desc_is_contiguous(DPDMADescriptor *desc) -{ - return (desc->control & DSCR_CTRL_DESCRIPTOR_MODE) == 0; -} - -static inline bool xlnx_dpdma_desc_update_enabled(DPDMADescriptor *desc) -{ - return (desc->control & DSCR_CTRL_EN_DSCR_UPDATE) != 0; -} - -static inline void xlnx_dpdma_desc_set_done(DPDMADescriptor *desc) -{ - desc->timestamp_msb |= STATUS_DONE; -} - -static inline bool xlnx_dpdma_desc_is_already_done(DPDMADescriptor *desc) -{ - return (desc->timestamp_msb & STATUS_DONE) != 0; -} - -static inline bool xlnx_dpdma_desc_ignore_done_bit(DPDMADescriptor *desc) -{ - return (desc->control & DSCR_CTRL_IGNORE_DONE) != 0; -} - -static const VMStateDescription vmstate_xlnx_dpdma = { - .name = TYPE_XLNX_DPDMA, - .version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(registers, XlnxDPDMAState, - XLNX_DPDMA_REG_ARRAY_SIZE), - VMSTATE_BOOL_ARRAY(operation_finished, XlnxDPDMAState, 6), - VMSTATE_END_OF_LIST() - } -}; - -static void xlnx_dpdma_update_irq(XlnxDPDMAState *s) -{ - bool flags; - - flags = ((s->registers[DPDMA_ISR] & (~s->registers[DPDMA_IMR])) - || (s->registers[DPDMA_EISR] & (~s->registers[DPDMA_EIMR]))); - qemu_set_irq(s->irq, flags); -} - -static uint64_t xlnx_dpdma_descriptor_start_address(XlnxDPDMAState *s, - uint8_t channel) -{ - return (s->registers[DPDMA_DSCR_STRT_ADDRE_CH(channel)] << 16) - + s->registers[DPDMA_DSCR_STRT_ADDR_CH(channel)]; -} - -static uint64_t xlnx_dpdma_descriptor_next_address(XlnxDPDMAState *s, - uint8_t channel) -{ - return ((uint64_t)s->registers[DPDMA_DSCR_NEXT_ADDRE_CH(channel)] << 32) - + s->registers[DPDMA_DSCR_NEXT_ADDR_CH(channel)]; -} - -static bool xlnx_dpdma_is_channel_enabled(XlnxDPDMAState *s, - uint8_t channel) -{ - return (s->registers[DPDMA_CNTL_CH(channel)] & DPDMA_CNTL_CH_EN) != 0; -} - -static bool xlnx_dpdma_is_channel_paused(XlnxDPDMAState *s, - uint8_t channel) -{ - return (s->registers[DPDMA_CNTL_CH(channel)] & DPDMA_CNTL_CH_PAUSED) != 0; -} - -static inline bool xlnx_dpdma_is_channel_retriggered(XlnxDPDMAState *s, - uint8_t channel) -{ - /* Clear the retriggered bit after reading it. */ - bool channel_is_retriggered = s->registers[DPDMA_GBL] - & DPDMA_GBL_RTRG_CH(channel); - s->registers[DPDMA_GBL] &= ~DPDMA_GBL_RTRG_CH(channel); - return channel_is_retriggered; -} - -static inline bool xlnx_dpdma_is_channel_triggered(XlnxDPDMAState *s, - uint8_t channel) -{ - return s->registers[DPDMA_GBL] & DPDMA_GBL_TRG_CH(channel); -} - -static void xlnx_dpdma_update_desc_info(XlnxDPDMAState *s, uint8_t channel, - DPDMADescriptor *desc) -{ - s->registers[DPDMA_DSCR_NEXT_ADDRE_CH(channel)] = - extract32(desc->address_extension, 0, 16); - s->registers[DPDMA_DSCR_NEXT_ADDR_CH(channel)] = desc->next_descriptor; - s->registers[DPDMA_PYLD_CUR_ADDRE_CH(channel)] = - extract32(desc->address_extension, 16, 16); - s->registers[DPDMA_PYLD_CUR_ADDR_CH(channel)] = desc->source_address; - s->registers[DPDMA_VDO_CH(channel)] = - extract32(desc->line_size_stride, 18, 14) - + (extract32(desc->line_size_stride, 0, 18) - << 14); - s->registers[DPDMA_PYLD_SZ_CH(channel)] = desc->xfer_size; - s->registers[DPDMA_DSCR_ID_CH(channel)] = desc->descriptor_id; - - /* Compute the status register with the descriptor information. */ - s->registers[DPDMA_STATUS_CH(channel)] = - extract32(desc->control, 0, 8) << 13; - if ((desc->control & DSCR_CTRL_EN_DSCR_DONE_INTR) != 0) { - s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_DSCR_INTR; - } - if ((desc->control & DSCR_CTRL_EN_DSCR_UPDATE) != 0) { - s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_DSCR_UP; - } - if ((desc->timestamp_msb & STATUS_DONE) != 0) { - s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_DSCR_DONE; - } - if ((desc->control & DSCR_CTRL_IGNORE_DONE) != 0) { - s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_IGNR_DONE; - } - if ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME) != 0) { - s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_LDSCR_FRAME; - } - if ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR) != 0) { - s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_LAST_DSCR; - } - if ((desc->control & DSCR_CTRL_ENABLE_CRC) != 0) { - s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_CRC; - } - if ((desc->control & DSCR_CTRL_DESCRIPTOR_MODE) != 0) { - s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_MODE; - } - if ((desc->control & DSCR_CTRL_AXI_BURST_TYPE) != 0) { - s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_BURST_TYPE; - } -} - -static void xlnx_dpdma_dump_descriptor(DPDMADescriptor *desc) -{ - if (DEBUG_DPDMA) { - qemu_log("DUMP DESCRIPTOR:\n"); - qemu_hexdump((char *)desc, stdout, "", sizeof(DPDMADescriptor)); - } -} - -static uint64_t xlnx_dpdma_read(void *opaque, hwaddr offset, - unsigned size) -{ - XlnxDPDMAState *s = XLNX_DPDMA(opaque); - - DPRINTF("read @%" HWADDR_PRIx "\n", offset); - offset = offset >> 2; - - switch (offset) { - /* - * Trying to read a write only register. - */ - case DPDMA_GBL: - return 0; - default: - assert(offset <= (0xFFC >> 2)); - return s->registers[offset]; - } - return 0; -} - -static void xlnx_dpdma_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - XlnxDPDMAState *s = XLNX_DPDMA(opaque); - - DPRINTF("write @%" HWADDR_PRIx " = %" PRIx64 "\n", offset, value); - offset = offset >> 2; - - switch (offset) { - case DPDMA_ISR: - s->registers[DPDMA_ISR] &= ~value; - xlnx_dpdma_update_irq(s); - break; - case DPDMA_IEN: - s->registers[DPDMA_IMR] &= ~value; - break; - case DPDMA_IDS: - s->registers[DPDMA_IMR] |= value; - break; - case DPDMA_EISR: - s->registers[DPDMA_EISR] &= ~value; - xlnx_dpdma_update_irq(s); - break; - case DPDMA_EIEN: - s->registers[DPDMA_EIMR] &= ~value; - break; - case DPDMA_EIDS: - s->registers[DPDMA_EIMR] |= value; - break; - case DPDMA_IMR: - case DPDMA_EIMR: - case DPDMA_DSCR_NEXT_ADDRE_CH(0): - case DPDMA_DSCR_NEXT_ADDRE_CH(1): - case DPDMA_DSCR_NEXT_ADDRE_CH(2): - case DPDMA_DSCR_NEXT_ADDRE_CH(3): - case DPDMA_DSCR_NEXT_ADDRE_CH(4): - case DPDMA_DSCR_NEXT_ADDRE_CH(5): - case DPDMA_DSCR_NEXT_ADDR_CH(0): - case DPDMA_DSCR_NEXT_ADDR_CH(1): - case DPDMA_DSCR_NEXT_ADDR_CH(2): - case DPDMA_DSCR_NEXT_ADDR_CH(3): - case DPDMA_DSCR_NEXT_ADDR_CH(4): - case DPDMA_DSCR_NEXT_ADDR_CH(5): - case DPDMA_PYLD_CUR_ADDRE_CH(0): - case DPDMA_PYLD_CUR_ADDRE_CH(1): - case DPDMA_PYLD_CUR_ADDRE_CH(2): - case DPDMA_PYLD_CUR_ADDRE_CH(3): - case DPDMA_PYLD_CUR_ADDRE_CH(4): - case DPDMA_PYLD_CUR_ADDRE_CH(5): - case DPDMA_PYLD_CUR_ADDR_CH(0): - case DPDMA_PYLD_CUR_ADDR_CH(1): - case DPDMA_PYLD_CUR_ADDR_CH(2): - case DPDMA_PYLD_CUR_ADDR_CH(3): - case DPDMA_PYLD_CUR_ADDR_CH(4): - case DPDMA_PYLD_CUR_ADDR_CH(5): - case DPDMA_STATUS_CH(0): - case DPDMA_STATUS_CH(1): - case DPDMA_STATUS_CH(2): - case DPDMA_STATUS_CH(3): - case DPDMA_STATUS_CH(4): - case DPDMA_STATUS_CH(5): - case DPDMA_VDO_CH(0): - case DPDMA_VDO_CH(1): - case DPDMA_VDO_CH(2): - case DPDMA_VDO_CH(3): - case DPDMA_VDO_CH(4): - case DPDMA_VDO_CH(5): - case DPDMA_PYLD_SZ_CH(0): - case DPDMA_PYLD_SZ_CH(1): - case DPDMA_PYLD_SZ_CH(2): - case DPDMA_PYLD_SZ_CH(3): - case DPDMA_PYLD_SZ_CH(4): - case DPDMA_PYLD_SZ_CH(5): - case DPDMA_DSCR_ID_CH(0): - case DPDMA_DSCR_ID_CH(1): - case DPDMA_DSCR_ID_CH(2): - case DPDMA_DSCR_ID_CH(3): - case DPDMA_DSCR_ID_CH(4): - case DPDMA_DSCR_ID_CH(5): - /* - * Trying to write to a read only register.. - */ - break; - case DPDMA_GBL: - /* - * This is a write only register so it's read as zero in the read - * callback. - * We store the value anyway so we can know if the channel is - * enabled. - */ - s->registers[offset] |= value & 0x00000FFF; - break; - case DPDMA_DSCR_STRT_ADDRE_CH(0): - case DPDMA_DSCR_STRT_ADDRE_CH(1): - case DPDMA_DSCR_STRT_ADDRE_CH(2): - case DPDMA_DSCR_STRT_ADDRE_CH(3): - case DPDMA_DSCR_STRT_ADDRE_CH(4): - case DPDMA_DSCR_STRT_ADDRE_CH(5): - value &= 0x0000FFFF; - s->registers[offset] = value; - break; - case DPDMA_CNTL_CH(0): - s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(0); - value &= 0x3FFFFFFF; - s->registers[offset] = value; - break; - case DPDMA_CNTL_CH(1): - s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(1); - value &= 0x3FFFFFFF; - s->registers[offset] = value; - break; - case DPDMA_CNTL_CH(2): - s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(2); - value &= 0x3FFFFFFF; - s->registers[offset] = value; - break; - case DPDMA_CNTL_CH(3): - s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(3); - value &= 0x3FFFFFFF; - s->registers[offset] = value; - break; - case DPDMA_CNTL_CH(4): - s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(4); - value &= 0x3FFFFFFF; - s->registers[offset] = value; - break; - case DPDMA_CNTL_CH(5): - s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(5); - value &= 0x3FFFFFFF; - s->registers[offset] = value; - break; - default: - assert(offset <= (0xFFC >> 2)); - s->registers[offset] = value; - break; - } -} - -static const MemoryRegionOps dma_ops = { - .read = xlnx_dpdma_read, - .write = xlnx_dpdma_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static void xlnx_dpdma_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - XlnxDPDMAState *s = XLNX_DPDMA(obj); - - memory_region_init_io(&s->iomem, obj, &dma_ops, s, - TYPE_XLNX_DPDMA, 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); -} - -static void xlnx_dpdma_reset(DeviceState *dev) -{ - XlnxDPDMAState *s = XLNX_DPDMA(dev); - size_t i; - - memset(s->registers, 0, sizeof(s->registers)); - s->registers[DPDMA_IMR] = 0x07FFFFFF; - s->registers[DPDMA_EIMR] = 0xFFFFFFFF; - s->registers[DPDMA_ALC0_MIN] = 0x0000FFFF; - s->registers[DPDMA_ALC1_MIN] = 0x0000FFFF; - - for (i = 0; i < 6; i++) { - s->data[i] = NULL; - s->operation_finished[i] = true; - } -} - -static void xlnx_dpdma_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->vmsd = &vmstate_xlnx_dpdma; - dc->reset = xlnx_dpdma_reset; -} - -static const TypeInfo xlnx_dpdma_info = { - .name = TYPE_XLNX_DPDMA, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(XlnxDPDMAState), - .instance_init = xlnx_dpdma_init, - .class_init = xlnx_dpdma_class_init, -}; - -static void xlnx_dpdma_register_types(void) -{ - type_register_static(&xlnx_dpdma_info); -} - -size_t xlnx_dpdma_start_operation(XlnxDPDMAState *s, uint8_t channel, - bool one_desc) -{ - uint64_t desc_addr; - uint64_t source_addr[6]; - DPDMADescriptor desc; - bool done = false; - size_t ptr = 0; - - assert(channel <= 5); - - DPRINTF("start dpdma channel 0x%" PRIX8 "\n", channel); - - if (!xlnx_dpdma_is_channel_triggered(s, channel)) { - DPRINTF("Channel isn't triggered..\n"); - return 0; - } - - if (!xlnx_dpdma_is_channel_enabled(s, channel)) { - DPRINTF("Channel isn't enabled..\n"); - return 0; - } - - if (xlnx_dpdma_is_channel_paused(s, channel)) { - DPRINTF("Channel is paused..\n"); - return 0; - } - - do { - if ((s->operation_finished[channel]) - || xlnx_dpdma_is_channel_retriggered(s, channel)) { - desc_addr = xlnx_dpdma_descriptor_start_address(s, channel); - s->operation_finished[channel] = false; - } else { - desc_addr = xlnx_dpdma_descriptor_next_address(s, channel); - } - - if (dma_memory_read(&address_space_memory, desc_addr, &desc, - sizeof(DPDMADescriptor))) { - s->registers[DPDMA_EISR] |= ((1 << 1) << channel); - xlnx_dpdma_update_irq(s); - s->operation_finished[channel] = true; - DPRINTF("Can't get the descriptor.\n"); - break; - } - - xlnx_dpdma_update_desc_info(s, channel, &desc); - -#ifdef DEBUG_DPDMA - xlnx_dpdma_dump_descriptor(&desc); -#endif - - DPRINTF("location of the descriptor: %" PRIx64 "\n", desc_addr); - if (!xlnx_dpdma_desc_is_valid(&desc)) { - s->registers[DPDMA_EISR] |= ((1 << 7) << channel); - xlnx_dpdma_update_irq(s); - s->operation_finished[channel] = true; - DPRINTF("Invalid descriptor..\n"); - break; - } - - if (xlnx_dpdma_desc_crc_enabled(&desc) - && !xlnx_dpdma_desc_check_crc(&desc)) { - s->registers[DPDMA_EISR] |= ((1 << 13) << channel); - xlnx_dpdma_update_irq(s); - s->operation_finished[channel] = true; - DPRINTF("Bad CRC for descriptor..\n"); - break; - } - - if (xlnx_dpdma_desc_is_already_done(&desc) - && !xlnx_dpdma_desc_ignore_done_bit(&desc)) { - /* We are trying to process an already processed descriptor. */ - s->registers[DPDMA_EISR] |= ((1 << 25) << channel); - xlnx_dpdma_update_irq(s); - s->operation_finished[channel] = true; - DPRINTF("Already processed descriptor..\n"); - break; - } - - done = xlnx_dpdma_desc_is_last(&desc) - || xlnx_dpdma_desc_is_last_of_frame(&desc); - - s->operation_finished[channel] = done; - if (s->data[channel]) { - int64_t transfer_len = xlnx_dpdma_desc_get_transfer_size(&desc); - uint32_t line_size = xlnx_dpdma_desc_get_line_size(&desc); - uint32_t line_stride = xlnx_dpdma_desc_get_line_stride(&desc); - if (xlnx_dpdma_desc_is_contiguous(&desc)) { - source_addr[0] = xlnx_dpdma_desc_get_source_address(&desc, 0); - while (transfer_len != 0) { - if (dma_memory_read(&address_space_memory, - source_addr[0], - &s->data[channel][ptr], - line_size)) { - s->registers[DPDMA_ISR] |= ((1 << 12) << channel); - xlnx_dpdma_update_irq(s); - DPRINTF("Can't get data.\n"); - break; - } - ptr += line_size; - transfer_len -= line_size; - source_addr[0] += line_stride; - } - } else { - DPRINTF("Source address:\n"); - int frag; - for (frag = 0; frag < 5; frag++) { - source_addr[frag] = - xlnx_dpdma_desc_get_source_address(&desc, frag); - DPRINTF("Fragment %u: %" PRIx64 "\n", frag + 1, - source_addr[frag]); - } - - frag = 0; - while ((transfer_len < 0) && (frag < 5)) { - size_t fragment_len = DPDMA_FRAG_MAX_SZ - - (source_addr[frag] % DPDMA_FRAG_MAX_SZ); - - if (dma_memory_read(&address_space_memory, - source_addr[frag], - &(s->data[channel][ptr]), - fragment_len)) { - s->registers[DPDMA_ISR] |= ((1 << 12) << channel); - xlnx_dpdma_update_irq(s); - DPRINTF("Can't get data.\n"); - break; - } - ptr += fragment_len; - transfer_len -= fragment_len; - frag += 1; - } - } - } - - if (xlnx_dpdma_desc_update_enabled(&desc)) { - /* The descriptor need to be updated when it's completed. */ - DPRINTF("update the descriptor with the done flag set.\n"); - xlnx_dpdma_desc_set_done(&desc); - dma_memory_write(&address_space_memory, desc_addr, &desc, - sizeof(DPDMADescriptor)); - } - - if (xlnx_dpdma_desc_completion_interrupt(&desc)) { - DPRINTF("completion interrupt enabled!\n"); - s->registers[DPDMA_ISR] |= (1 << channel); - xlnx_dpdma_update_irq(s); - } - - } while (!done && !one_desc); - - return ptr; -} - -void xlnx_dpdma_set_host_data_location(XlnxDPDMAState *s, uint8_t channel, - void *p) -{ - if (!s) { - qemu_log_mask(LOG_UNIMP, "DPDMA client not attached to valid DPDMA" - " instance\n"); - return; - } - - assert(channel <= 5); - s->data[channel] = p; -} - -void xlnx_dpdma_trigger_vsync_irq(XlnxDPDMAState *s) -{ - s->registers[DPDMA_ISR] |= (1 << 27); - xlnx_dpdma_update_irq(s); -} - -type_init(xlnx_dpdma_register_types) diff --git a/hw/gpio/gpio_key.c b/hw/gpio/gpio_key.c index b34aa49df..ef287727b 100644 --- a/hw/gpio/gpio_key.c +++ b/hw/gpio/gpio_key.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" -#include "qemu/timer.h" #define TYPE_GPIOKEY "gpio-key" #define GPIOKEY(obj) OBJECT_CHECK(GPIOKEYState, (obj), TYPE_GPIOKEY) diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c index f3574aa8f..ed7e247f5 100644 --- a/hw/gpio/imx_gpio.c +++ b/hw/gpio/imx_gpio.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "hw/gpio/imx_gpio.h" -#include "qemu/log.h" #ifndef DEBUG_IMX_GPIO #define DEBUG_IMX_GPIO 0 diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c index dabef4a11..9b1b004fc 100644 --- a/hw/gpio/omap_gpio.c +++ b/hw/gpio/omap_gpio.c @@ -23,7 +23,6 @@ #include "hw/arm/omap.h" #include "hw/sysbus.h" #include "qemu/error-report.h" -#include "qapi/error.h" struct omap_gpio_s { qemu_irq irq; @@ -679,46 +678,48 @@ static const MemoryRegionOps omap2_gpif_top_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void omap_gpio_init(Object *obj) +static int omap_gpio_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - struct omap_gpif_s *s = OMAP1_GPIO(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + struct omap_gpif_s *s = OMAP1_GPIO(dev); + if (!s->clk) { + error_report("omap-gpio: clk not connected"); + return -1; + } qdev_init_gpio_in(dev, omap_gpio_set, 16); qdev_init_gpio_out(dev, s->omap1.handler, 16); sysbus_init_irq(sbd, &s->omap1.irq); - memory_region_init_io(&s->iomem, obj, &omap_gpio_ops, &s->omap1, + memory_region_init_io(&s->iomem, OBJECT(s), &omap_gpio_ops, &s->omap1, "omap.gpio", 0x1000); sysbus_init_mmio(sbd, &s->iomem); + return 0; } -static void omap_gpio_realize(DeviceState *dev, Error **errp) -{ - struct omap_gpif_s *s = OMAP1_GPIO(dev); - - if (!s->clk) { - error_setg(errp, "omap-gpio: clk not connected"); - } -} - -static void omap2_gpio_realize(DeviceState *dev, Error **errp) +static int omap2_gpio_init(SysBusDevice *sbd) { + DeviceState *dev = DEVICE(sbd); struct omap2_gpif_s *s = OMAP2_GPIO(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); int i; if (!s->iclk) { - error_setg(errp, "omap2-gpio: iclk not connected"); - return; + error_report("omap2-gpio: iclk not connected"); + return -1; } s->modulecount = s->mpu_model < omap2430 ? 4 - : s->mpu_model < omap3430 ? 5 - : 6; + : s->mpu_model < omap3430 ? 5 + : 6; + + for (i = 0; i < s->modulecount; i++) { + if (!s->fclk[i]) { + error_report("omap2-gpio: fclk%d not connected", i); + return -1; + } + } if (s->mpu_model < omap3430) { - memory_region_init_io(&s->iomem, OBJECT(dev), &omap2_gpif_top_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &omap2_gpif_top_ops, s, "omap2.gpio", 0x1000); sysbus_init_mmio(sbd, &s->iomem); } @@ -731,20 +732,17 @@ static void omap2_gpio_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->modulecount; i++) { struct omap2_gpio_s *m = &s->modules[i]; - if (!s->fclk[i]) { - error_setg(errp, "omap2-gpio: fclk%d not connected", i); - return; - } - m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25; m->handler = &s->handler[i * 32]; sysbus_init_irq(sbd, &m->irq[0]); /* mpu irq */ sysbus_init_irq(sbd, &m->irq[1]); /* dsp irq */ sysbus_init_irq(sbd, &m->wkup); - memory_region_init_io(&m->iomem, OBJECT(dev), &omap2_gpio_module_ops, m, + memory_region_init_io(&m->iomem, OBJECT(s), &omap2_gpio_module_ops, m, "omap.gpio-module", 0x1000); sysbus_init_mmio(sbd, &m->iomem); } + + return 0; } /* Using qdev pointer properties for the clocks is not ideal. @@ -768,8 +766,9 @@ static Property omap_gpio_properties[] = { static void omap_gpio_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - dc->realize = omap_gpio_realize; + k->init = omap_gpio_init; dc->reset = omap_gpif_reset; dc->props = omap_gpio_properties; /* Reason: pointer property "clk" */ @@ -780,7 +779,6 @@ static const TypeInfo omap_gpio_info = { .name = TYPE_OMAP1_GPIO, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct omap_gpif_s), - .instance_init = omap_gpio_init, .class_init = omap_gpio_class_init, }; @@ -799,8 +797,9 @@ static Property omap2_gpio_properties[] = { static void omap2_gpio_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - dc->realize = omap2_gpio_realize; + k->init = omap2_gpio_init; dc->reset = omap2_gpif_reset; dc->props = omap2_gpio_properties; /* Reason: pointer properties "iclk", "fclk0", ..., "fclk5" */ diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index 4ae2aa156..29dc7fc38 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" -#include "qemu/log.h" //#define DEBUG_PL061 1 @@ -341,6 +340,20 @@ static const MemoryRegionOps pl061_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static int pl061_initfn(SysBusDevice *sbd) +{ + DeviceState *dev = DEVICE(sbd); + PL061State *s = PL061(dev); + + memory_region_init_io(&s->iomem, OBJECT(s), &pl061_ops, s, "pl061", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + qdev_init_gpio_in(dev, pl061_set_irq, 8); + qdev_init_gpio_out(dev, s->out, 8); + + return 0; +} + static void pl061_luminary_init(Object *obj) { PL061State *s = PL061(obj); @@ -352,23 +365,17 @@ static void pl061_luminary_init(Object *obj) static void pl061_init(Object *obj) { PL061State *s = PL061(obj); - DeviceState *dev = DEVICE(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); s->id = pl061_id; s->rsvd_start = 0x424; - - memory_region_init_io(&s->iomem, obj, &pl061_ops, s, "pl061", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - qdev_init_gpio_in(dev, pl061_set_irq, 8); - qdev_init_gpio_out(dev, s->out, 8); } static void pl061_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = pl061_initfn; dc->vmsd = &vmstate_pl061; dc->reset = &pl061_reset; } diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c index 15865e108..555da281c 100644 --- a/hw/gpio/zaurus.c +++ b/hw/gpio/zaurus.c @@ -167,18 +167,19 @@ static void scoop_gpio_set(void *opaque, int line, int level) s->gpio_level &= ~(1 << line); } -static void scoop_init(Object *obj) +static int scoop_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - ScoopInfo *s = SCOOP(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + ScoopInfo *s = SCOOP(dev); s->status = 0x02; qdev_init_gpio_out(dev, s->handler, 16); qdev_init_gpio_in(dev, scoop_gpio_set, 16); - memory_region_init_io(&s->iomem, obj, &scoop_ops, s, "scoop", 0x1000); + memory_region_init_io(&s->iomem, OBJECT(s), &scoop_ops, s, "scoop", 0x1000); sysbus_init_mmio(sbd, &s->iomem); + + return 0; } static int scoop_post_load(void *opaque, int version_id) @@ -238,7 +239,9 @@ static const VMStateDescription vmstate_scoop_regs = { static void scoop_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = scoop_init; dc->desc = "Scoop2 Sharp custom ASIC"; dc->vmsd = &vmstate_scoop_regs; } @@ -247,7 +250,6 @@ static const TypeInfo scoop_sysbus_info = { .name = TYPE_SCOOP, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ScoopInfo), - .instance_init = scoop_init, .class_init = scoop_sysbus_class_init, }; diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs index a081b8ef2..aeb8f38d7 100644 --- a/hw/i2c/Makefile.objs +++ b/hw/i2c/Makefile.objs @@ -1,10 +1,8 @@ common-obj-y += core.o smbus.o smbus_eeprom.o -common-obj-$(CONFIG_DDC) += i2c-ddc.o common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o common-obj-$(CONFIG_APM) += pm_smbus.o common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o -common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o obj-$(CONFIG_OMAP) += omap_i2c.o diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c deleted file mode 100644 index ce5b1f0fa..000000000 --- a/hw/i2c/aspeed_i2c.c +++ /dev/null @@ -1,440 +0,0 @@ -/* - * ARM Aspeed I2C controller - * - * Copyright (C) 2016 IBM Corp. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qemu/log.h" -#include "hw/i2c/aspeed_i2c.h" - -/* I2C Global Register */ - -#define I2C_CTRL_STATUS 0x00 /* Device Interrupt Status */ -#define I2C_CTRL_ASSIGN 0x08 /* Device Interrupt Target - Assignment */ - -/* I2C Device (Bus) Register */ - -#define I2CD_FUN_CTRL_REG 0x00 /* I2CD Function Control */ -#define I2CD_BUFF_SEL_MASK (0x7 << 20) -#define I2CD_BUFF_SEL(x) (x << 20) -#define I2CD_M_SDA_LOCK_EN (0x1 << 16) -#define I2CD_MULTI_MASTER_DIS (0x1 << 15) -#define I2CD_M_SCL_DRIVE_EN (0x1 << 14) -#define I2CD_MSB_STS (0x1 << 9) -#define I2CD_SDA_DRIVE_1T_EN (0x1 << 8) -#define I2CD_M_SDA_DRIVE_1T_EN (0x1 << 7) -#define I2CD_M_HIGH_SPEED_EN (0x1 << 6) -#define I2CD_DEF_ADDR_EN (0x1 << 5) -#define I2CD_DEF_ALERT_EN (0x1 << 4) -#define I2CD_DEF_ARP_EN (0x1 << 3) -#define I2CD_DEF_GCALL_EN (0x1 << 2) -#define I2CD_SLAVE_EN (0x1 << 1) -#define I2CD_MASTER_EN (0x1) - -#define I2CD_AC_TIMING_REG1 0x04 /* Clock and AC Timing Control #1 */ -#define I2CD_AC_TIMING_REG2 0x08 /* Clock and AC Timing Control #1 */ -#define I2CD_INTR_CTRL_REG 0x0c /* I2CD Interrupt Control */ -#define I2CD_INTR_STS_REG 0x10 /* I2CD Interrupt Status */ -#define I2CD_INTR_SDA_DL_TIMEOUT (0x1 << 14) -#define I2CD_INTR_BUS_RECOVER_DONE (0x1 << 13) -#define I2CD_INTR_SMBUS_ALERT (0x1 << 12) /* Bus [0-3] only */ -#define I2CD_INTR_SMBUS_ARP_ADDR (0x1 << 11) /* Removed */ -#define I2CD_INTR_SMBUS_DEV_ALERT_ADDR (0x1 << 10) /* Removed */ -#define I2CD_INTR_SMBUS_DEF_ADDR (0x1 << 9) /* Removed */ -#define I2CD_INTR_GCALL_ADDR (0x1 << 8) /* Removed */ -#define I2CD_INTR_SLAVE_MATCH (0x1 << 7) /* use RX_DONE */ -#define I2CD_INTR_SCL_TIMEOUT (0x1 << 6) -#define I2CD_INTR_ABNORMAL (0x1 << 5) -#define I2CD_INTR_NORMAL_STOP (0x1 << 4) -#define I2CD_INTR_ARBIT_LOSS (0x1 << 3) -#define I2CD_INTR_RX_DONE (0x1 << 2) -#define I2CD_INTR_TX_NAK (0x1 << 1) -#define I2CD_INTR_TX_ACK (0x1 << 0) - -#define I2CD_CMD_REG 0x14 /* I2CD Command/Status */ -#define I2CD_SDA_OE (0x1 << 28) -#define I2CD_SDA_O (0x1 << 27) -#define I2CD_SCL_OE (0x1 << 26) -#define I2CD_SCL_O (0x1 << 25) -#define I2CD_TX_TIMING (0x1 << 24) -#define I2CD_TX_STATUS (0x1 << 23) - -#define I2CD_TX_STATE_SHIFT 19 /* Tx State Machine */ -#define I2CD_TX_STATE_MASK 0xf -#define I2CD_IDLE 0x0 -#define I2CD_MACTIVE 0x8 -#define I2CD_MSTART 0x9 -#define I2CD_MSTARTR 0xa -#define I2CD_MSTOP 0xb -#define I2CD_MTXD 0xc -#define I2CD_MRXACK 0xd -#define I2CD_MRXD 0xe -#define I2CD_MTXACK 0xf -#define I2CD_SWAIT 0x1 -#define I2CD_SRXD 0x4 -#define I2CD_STXACK 0x5 -#define I2CD_STXD 0x6 -#define I2CD_SRXACK 0x7 -#define I2CD_RECOVER 0x3 - -#define I2CD_SCL_LINE_STS (0x1 << 18) -#define I2CD_SDA_LINE_STS (0x1 << 17) -#define I2CD_BUS_BUSY_STS (0x1 << 16) -#define I2CD_SDA_OE_OUT_DIR (0x1 << 15) -#define I2CD_SDA_O_OUT_DIR (0x1 << 14) -#define I2CD_SCL_OE_OUT_DIR (0x1 << 13) -#define I2CD_SCL_O_OUT_DIR (0x1 << 12) -#define I2CD_BUS_RECOVER_CMD_EN (0x1 << 11) -#define I2CD_S_ALT_EN (0x1 << 10) -#define I2CD_RX_DMA_ENABLE (0x1 << 9) -#define I2CD_TX_DMA_ENABLE (0x1 << 8) - -/* Command Bit */ -#define I2CD_M_STOP_CMD (0x1 << 5) -#define I2CD_M_S_RX_CMD_LAST (0x1 << 4) -#define I2CD_M_RX_CMD (0x1 << 3) -#define I2CD_S_TX_CMD (0x1 << 2) -#define I2CD_M_TX_CMD (0x1 << 1) -#define I2CD_M_START_CMD (0x1) - -#define I2CD_DEV_ADDR_REG 0x18 /* Slave Device Address */ -#define I2CD_BUF_CTRL_REG 0x1c /* Pool Buffer Control */ -#define I2CD_BYTE_BUF_REG 0x20 /* Transmit/Receive Byte Buffer */ -#define I2CD_BYTE_BUF_TX_SHIFT 0 -#define I2CD_BYTE_BUF_TX_MASK 0xff -#define I2CD_BYTE_BUF_RX_SHIFT 8 -#define I2CD_BYTE_BUF_RX_MASK 0xff - - -static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus) -{ - return bus->ctrl & I2CD_MASTER_EN; -} - -static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus) -{ - return bus->ctrl & (I2CD_MASTER_EN | I2CD_SLAVE_EN); -} - -static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus) -{ - bus->intr_status &= bus->intr_ctrl; - if (bus->intr_status) { - bus->controller->intr_status |= 1 << bus->id; - qemu_irq_raise(bus->controller->irq); - } -} - -static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset, - unsigned size) -{ - AspeedI2CBus *bus = opaque; - - switch (offset) { - case I2CD_FUN_CTRL_REG: - return bus->ctrl; - case I2CD_AC_TIMING_REG1: - return bus->timing[0]; - case I2CD_AC_TIMING_REG2: - return bus->timing[1]; - case I2CD_INTR_CTRL_REG: - return bus->intr_ctrl; - case I2CD_INTR_STS_REG: - return bus->intr_status; - case I2CD_BYTE_BUF_REG: - return bus->buf; - case I2CD_CMD_REG: - return bus->cmd | (i2c_bus_busy(bus->bus) << 16); - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); - return -1; - } -} - -static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) -{ - bus->cmd |= value & 0xFFFF; - bus->intr_status = 0; - - if (bus->cmd & I2CD_M_START_CMD) { - if (i2c_start_transfer(bus->bus, extract32(bus->buf, 1, 7), - extract32(bus->buf, 0, 1))) { - bus->intr_status |= I2CD_INTR_TX_NAK; - } else { - bus->intr_status |= I2CD_INTR_TX_ACK; - } - - } else if (bus->cmd & I2CD_M_TX_CMD) { - if (i2c_send(bus->bus, bus->buf)) { - bus->intr_status |= (I2CD_INTR_TX_NAK | I2CD_INTR_ABNORMAL); - i2c_end_transfer(bus->bus); - } else { - bus->intr_status |= I2CD_INTR_TX_ACK; - } - - } else if (bus->cmd & I2CD_M_RX_CMD) { - int ret = i2c_recv(bus->bus); - if (ret < 0) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: read failed\n", __func__); - ret = 0xff; - } else { - bus->intr_status |= I2CD_INTR_RX_DONE; - } - bus->buf = (ret & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT; - } - - if (bus->cmd & (I2CD_M_STOP_CMD | I2CD_M_S_RX_CMD_LAST)) { - if (!i2c_bus_busy(bus->bus)) { - bus->intr_status |= I2CD_INTR_ABNORMAL; - } else { - i2c_end_transfer(bus->bus); - bus->intr_status |= I2CD_INTR_NORMAL_STOP; - } - } - - /* command is handled, reset it and check for interrupts */ - bus->cmd &= ~0xFFFF; - aspeed_i2c_bus_raise_interrupt(bus); -} - -static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - AspeedI2CBus *bus = opaque; - - switch (offset) { - case I2CD_FUN_CTRL_REG: - if (value & I2CD_SLAVE_EN) { - qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", - __func__); - break; - } - bus->ctrl = value & 0x0071C3FF; - break; - case I2CD_AC_TIMING_REG1: - bus->timing[0] = value & 0xFFFFF0F; - break; - case I2CD_AC_TIMING_REG2: - bus->timing[1] = value & 0x7; - break; - case I2CD_INTR_CTRL_REG: - bus->intr_ctrl = value & 0x7FFF; - break; - case I2CD_INTR_STS_REG: - bus->intr_status &= ~(value & 0x7FFF); - bus->controller->intr_status &= ~(1 << bus->id); - qemu_irq_lower(bus->controller->irq); - break; - case I2CD_DEV_ADDR_REG: - qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", - __func__); - break; - case I2CD_BYTE_BUF_REG: - bus->buf = (value & I2CD_BYTE_BUF_TX_MASK) << I2CD_BYTE_BUF_TX_SHIFT; - break; - case I2CD_CMD_REG: - if (!aspeed_i2c_bus_is_enabled(bus)) { - break; - } - - if (!aspeed_i2c_bus_is_master(bus)) { - qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", - __func__); - break; - } - - aspeed_i2c_bus_handle_cmd(bus, value); - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - } -} - -static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset, - unsigned size) -{ - AspeedI2CState *s = opaque; - - switch (offset) { - case I2C_CTRL_STATUS: - return s->intr_status; - default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - break; - } - - return -1; -} - -static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - switch (offset) { - case I2C_CTRL_STATUS: - default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - break; - } -} - -static const MemoryRegionOps aspeed_i2c_bus_ops = { - .read = aspeed_i2c_bus_read, - .write = aspeed_i2c_bus_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static const MemoryRegionOps aspeed_i2c_ctrl_ops = { - .read = aspeed_i2c_ctrl_read, - .write = aspeed_i2c_ctrl_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static const VMStateDescription aspeed_i2c_bus_vmstate = { - .name = TYPE_ASPEED_I2C, - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(id, AspeedI2CBus), - VMSTATE_UINT32(ctrl, AspeedI2CBus), - VMSTATE_UINT32_ARRAY(timing, AspeedI2CBus, 2), - VMSTATE_UINT32(intr_ctrl, AspeedI2CBus), - VMSTATE_UINT32(intr_status, AspeedI2CBus), - VMSTATE_UINT32(cmd, AspeedI2CBus), - VMSTATE_UINT32(buf, AspeedI2CBus), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription aspeed_i2c_vmstate = { - .name = TYPE_ASPEED_I2C, - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(intr_status, AspeedI2CState), - VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState, - ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate, - AspeedI2CBus), - VMSTATE_END_OF_LIST() - } -}; - -static void aspeed_i2c_reset(DeviceState *dev) -{ - int i; - AspeedI2CState *s = ASPEED_I2C(dev); - - s->intr_status = 0; - - for (i = 0; i < ASPEED_I2C_NR_BUSSES; i++) { - s->busses[i].intr_ctrl = 0; - s->busses[i].intr_status = 0; - s->busses[i].cmd = 0; - s->busses[i].buf = 0; - i2c_end_transfer(s->busses[i].bus); - } -} - -/* - * Address Definitions - * - * 0x000 ... 0x03F: Global Register - * 0x040 ... 0x07F: Device 1 - * 0x080 ... 0x0BF: Device 2 - * 0x0C0 ... 0x0FF: Device 3 - * 0x100 ... 0x13F: Device 4 - * 0x140 ... 0x17F: Device 5 - * 0x180 ... 0x1BF: Device 6 - * 0x1C0 ... 0x1FF: Device 7 - * 0x200 ... 0x2FF: Buffer Pool (unused in linux driver) - * 0x300 ... 0x33F: Device 8 - * 0x340 ... 0x37F: Device 9 - * 0x380 ... 0x3BF: Device 10 - * 0x3C0 ... 0x3FF: Device 11 - * 0x400 ... 0x43F: Device 12 - * 0x440 ... 0x47F: Device 13 - * 0x480 ... 0x4BF: Device 14 - * 0x800 ... 0xFFF: Buffer Pool (unused in linux driver) - */ -static void aspeed_i2c_realize(DeviceState *dev, Error **errp) -{ - int i; - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - AspeedI2CState *s = ASPEED_I2C(dev); - - sysbus_init_irq(sbd, &s->irq); - memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s, - "aspeed.i2c", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - - for (i = 0; i < ASPEED_I2C_NR_BUSSES; i++) { - char name[16]; - int offset = i < 7 ? 1 : 5; - snprintf(name, sizeof(name), "aspeed.i2c.%d", i); - s->busses[i].controller = s; - s->busses[i].id = i; - s->busses[i].bus = i2c_init_bus(dev, name); - memory_region_init_io(&s->busses[i].mr, OBJECT(dev), - &aspeed_i2c_bus_ops, &s->busses[i], name, 0x40); - memory_region_add_subregion(&s->iomem, 0x40 * (i + offset), - &s->busses[i].mr); - } -} - -static void aspeed_i2c_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->vmsd = &aspeed_i2c_vmstate; - dc->reset = aspeed_i2c_reset; - dc->realize = aspeed_i2c_realize; - dc->desc = "Aspeed I2C Controller"; -} - -static const TypeInfo aspeed_i2c_info = { - .name = TYPE_ASPEED_I2C, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AspeedI2CState), - .class_init = aspeed_i2c_class_init, -}; - -static void aspeed_i2c_register_types(void) -{ - type_register_static(&aspeed_i2c_info); -} - -type_init(aspeed_i2c_register_types) - - -I2CBus *aspeed_i2c_get_bus(DeviceState *dev, int busnr) -{ - AspeedI2CState *s = ASPEED_I2C(dev); - I2CBus *bus = NULL; - - if (busnr >= 0 && busnr < ASPEED_I2C_NR_BUSSES) { - bus = s->busses[busnr].bus; - } - - return bus; -} diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c index d3a29891f..6ed206020 100644 --- a/hw/i2c/bitbang_i2c.c +++ b/hw/i2c/bitbang_i2c.c @@ -210,14 +210,13 @@ static void bitbang_i2c_gpio_set(void *opaque, int irq, int level) } } -static void gpio_i2c_init(Object *obj) +static int gpio_i2c_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - GPIOI2CState *s = GPIO_I2C(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + GPIOI2CState *s = GPIO_I2C(dev); I2CBus *bus; - memory_region_init(&s->dummy_iomem, obj, "gpio_i2c", 0); + memory_region_init(&s->dummy_iomem, OBJECT(s), "gpio_i2c", 0); sysbus_init_mmio(sbd, &s->dummy_iomem); bus = i2c_init_bus(dev, "i2c"); @@ -225,12 +224,16 @@ static void gpio_i2c_init(Object *obj) qdev_init_gpio_in(dev, bitbang_i2c_gpio_set, 2); qdev_init_gpio_out(dev, &s->out, 1); + + return 0; } static void gpio_i2c_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = gpio_i2c_init; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "Virtual GPIO to I2C bridge"; } @@ -239,7 +242,6 @@ static const TypeInfo gpio_i2c_info = { .name = TYPE_GPIO_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(GPIOI2CState), - .instance_init = gpio_i2c_init, .class_init = gpio_i2c_class_init, }; diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 4afbe0bde..ba22104af 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -10,21 +10,12 @@ #include "qemu/osdep.h" #include "hw/i2c/i2c.h" -typedef struct I2CNode I2CNode; - -struct I2CNode { - I2CSlave *elt; - QLIST_ENTRY(I2CNode) next; -}; - -#define I2C_BROADCAST 0x00 - struct I2CBus { BusState qbus; - QLIST_HEAD(, I2CNode) current_devs; + I2CSlave *current_dev; + I2CSlave *dev; uint8_t saved_address; - bool broadcast; }; static Property i2c_props[] = { @@ -45,14 +36,17 @@ static void i2c_bus_pre_save(void *opaque) { I2CBus *bus = opaque; - bus->saved_address = -1; - if (!QLIST_EMPTY(&bus->current_devs)) { - if (!bus->broadcast) { - bus->saved_address = QLIST_FIRST(&bus->current_devs)->elt->address; - } else { - bus->saved_address = I2C_BROADCAST; - } - } + bus->saved_address = bus->current_dev ? bus->current_dev->address : -1; +} + +static int i2c_bus_post_load(void *opaque, int version_id) +{ + I2CBus *bus = opaque; + + /* The bus is loaded before attached devices, so load and save the + current device id. Devices will check themselves as loaded. */ + bus->current_dev = NULL; + return 0; } static const VMStateDescription vmstate_i2c_bus = { @@ -60,6 +54,7 @@ static const VMStateDescription vmstate_i2c_bus = { .version_id = 1, .minimum_version_id = 1, .pre_save = i2c_bus_pre_save, + .post_load = i2c_bus_post_load, .fields = (VMStateField[]) { VMSTATE_UINT8(saved_address, I2CBus), VMSTATE_END_OF_LIST() @@ -72,7 +67,6 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name) I2CBus *bus; bus = I2C_BUS(qbus_create(TYPE_I2C_BUS, parent, name)); - QLIST_INIT(&bus->current_devs); vmstate_register(NULL, -1, &vmstate_i2c_bus, bus); return bus; } @@ -85,7 +79,7 @@ void i2c_set_slave_address(I2CSlave *dev, uint8_t address) /* Return nonzero if bus is busy. */ int i2c_bus_busy(I2CBus *bus) { - return !QLIST_EMPTY(&bus->current_devs); + return bus->current_dev != NULL; } /* Returns non-zero if the address is not valid. */ @@ -93,127 +87,95 @@ int i2c_bus_busy(I2CBus *bus) int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) { BusChild *kid; + I2CSlave *slave = NULL; I2CSlaveClass *sc; - I2CNode *node; - - if (address == I2C_BROADCAST) { - /* - * This is a broadcast, the current_devs will be all the devices of the - * bus. - */ - bus->broadcast = true; - } QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { DeviceState *qdev = kid->child; I2CSlave *candidate = I2C_SLAVE(qdev); - if ((candidate->address == address) || (bus->broadcast)) { - node = g_malloc(sizeof(struct I2CNode)); - node->elt = candidate; - QLIST_INSERT_HEAD(&bus->current_devs, node, next); - if (!bus->broadcast) { - break; - } + if (candidate->address == address) { + slave = candidate; + break; } } - if (QLIST_EMPTY(&bus->current_devs)) { + if (!slave) { return 1; } - QLIST_FOREACH(node, &bus->current_devs, next) { - 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); - } + sc = I2C_SLAVE_GET_CLASS(slave); + /* If the bus is already busy, assume this is a repeated + start condition. */ + bus->current_dev = slave; + if (sc->event) { + sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND); } return 0; } void i2c_end_transfer(I2CBus *bus) { + I2CSlave *dev = bus->current_dev; I2CSlaveClass *sc; - I2CNode *node, *next; - if (QLIST_EMPTY(&bus->current_devs)) { + if (!dev) { return; } - QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) { - sc = I2C_SLAVE_GET_CLASS(node->elt); - if (sc->event) { - sc->event(node->elt, I2C_FINISH); - } - QLIST_REMOVE(node, next); - g_free(node); + sc = I2C_SLAVE_GET_CLASS(dev); + if (sc->event) { + sc->event(dev, I2C_FINISH); } - bus->broadcast = false; + + bus->current_dev = NULL; } -int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send) +int i2c_send(I2CBus *bus, uint8_t data) { + I2CSlave *dev = bus->current_dev; I2CSlaveClass *sc; - I2CNode *node; - int ret = 0; - - if (send) { - QLIST_FOREACH(node, &bus->current_devs, next) { - sc = I2C_SLAVE_GET_CLASS(node->elt); - if (sc->send) { - ret = ret || sc->send(node->elt, *data); - } else { - ret = -1; - } - } - return ret ? -1 : 0; - } else { - if ((QLIST_EMPTY(&bus->current_devs)) || (bus->broadcast)) { - return -1; - } - sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt); - if (sc->recv) { - ret = sc->recv(QLIST_FIRST(&bus->current_devs)->elt); - if (ret < 0) { - return ret; - } else { - *data = ret; - return 0; - } - } + if (!dev) { return -1; } -} -int i2c_send(I2CBus *bus, uint8_t data) -{ - return i2c_send_recv(bus, &data, true); + sc = I2C_SLAVE_GET_CLASS(dev); + if (sc->send) { + return sc->send(dev, data); + } + + return -1; } int i2c_recv(I2CBus *bus) { - uint8_t data; - int ret = i2c_send_recv(bus, &data, false); + I2CSlave *dev = bus->current_dev; + I2CSlaveClass *sc; + + if (!dev) { + return -1; + } - return ret < 0 ? ret : data; + sc = I2C_SLAVE_GET_CLASS(dev); + if (sc->recv) { + return sc->recv(dev); + } + + return -1; } void i2c_nack(I2CBus *bus) { + I2CSlave *dev = bus->current_dev; I2CSlaveClass *sc; - I2CNode *node; - if (QLIST_EMPTY(&bus->current_devs)) { + if (!dev) { return; } - QLIST_FOREACH(node, &bus->current_devs, next) { - sc = I2C_SLAVE_GET_CLASS(node->elt); - if (sc->event) { - sc->event(node->elt, I2C_NACK); - } + sc = I2C_SLAVE_GET_CLASS(dev); + if (sc->event) { + sc->event(dev, I2C_NACK); } } @@ -221,14 +183,9 @@ static int i2c_slave_post_load(void *opaque, int version_id) { I2CSlave *dev = opaque; I2CBus *bus; - I2CNode *node; - bus = I2C_BUS(qdev_get_parent_bus(DEVICE(dev))); - if ((bus->saved_address == dev->address) || - (bus->saved_address == I2C_BROADCAST)) { - node = g_malloc(sizeof(struct I2CNode)); - node->elt = dev; - QLIST_INSERT_HEAD(&bus->current_devs, node, next); + if (bus->saved_address == dev->address) { + bus->current_dev = dev; } return 0; } diff --git a/hw/i2c/exynos4210_i2c.c b/hw/i2c/exynos4210_i2c.c index c96fa7d7b..8c2a2c163 100644 --- a/hw/i2c/exynos4210_i2c.c +++ b/hw/i2c/exynos4210_i2c.c @@ -299,32 +299,33 @@ static void exynos4210_i2c_reset(DeviceState *d) s->scl_free = true; } -static void exynos4210_i2c_init(Object *obj) +static int exynos4210_i2c_realize(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - Exynos4210I2CState *s = EXYNOS4_I2C(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + Exynos4210I2CState *s = EXYNOS4_I2C(dev); - memory_region_init_io(&s->iomem, obj, &exynos4210_i2c_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_i2c_ops, s, TYPE_EXYNOS4_I2C, EXYNOS4_I2C_MEM_SIZE); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); s->bus = i2c_init_bus(dev, "i2c"); + return 0; } static void exynos4210_i2c_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass); dc->vmsd = &exynos4210_i2c_vmstate; dc->reset = exynos4210_i2c_reset; + sbdc->init = exynos4210_i2c_realize; } static const TypeInfo exynos4210_i2c_type_info = { .name = TYPE_EXYNOS4_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210I2CState), - .instance_init = exynos4210_i2c_init, .class_init = exynos4210_i2c_class_init, }; diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c deleted file mode 100644 index 122721293..000000000 --- a/hw/i2c/i2c-ddc.c +++ /dev/null @@ -1,308 +0,0 @@ -/* A simple I2C slave for returning monitor EDID data via DDC. - * - * Copyright (c) 2011 Linaro Limited - * Written by Peter Maydell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "hw/i2c/i2c.h" -#include "hw/i2c/i2c-ddc.h" - -#ifndef DEBUG_I2CDDC -#define DEBUG_I2CDDC 0 -#endif - -#define DPRINTF(fmt, ...) do { \ - if (DEBUG_I2CDDC) { \ - qemu_log("i2c-ddc: " fmt , ## __VA_ARGS__); \ - } \ -} while (0); - -/* Structure defining a monitor's characteristics in a - * readable format: this should be passed to build_edid_blob() - * to convert it into the 128 byte binary EDID blob. - * Not all bits of the EDID are customisable here. - */ -struct EDIDData { - char manuf_id[3]; /* three upper case letters */ - uint16_t product_id; - uint32_t serial_no; - uint8_t manuf_week; - int manuf_year; - uint8_t h_cm; - uint8_t v_cm; - uint8_t gamma; - char monitor_name[14]; - char serial_no_string[14]; - /* Range limits */ - uint8_t vmin; /* Hz */ - uint8_t vmax; /* Hz */ - uint8_t hmin; /* kHz */ - uint8_t hmax; /* kHz */ - uint8_t pixclock; /* MHz / 10 */ - uint8_t timing_data[18]; -}; - -typedef struct EDIDData EDIDData; - -/* EDID data for a simple LCD monitor */ -static const EDIDData lcd_edid = { - /* The manuf_id ought really to be an assigned EISA ID */ - .manuf_id = "QMU", - .product_id = 0, - .serial_no = 1, - .manuf_week = 1, - .manuf_year = 2011, - .h_cm = 40, - .v_cm = 30, - .gamma = 0x78, - .monitor_name = "QEMU monitor", - .serial_no_string = "1", - .vmin = 40, - .vmax = 120, - .hmin = 30, - .hmax = 100, - .pixclock = 18, - .timing_data = { - /* Borrowed from a 21" LCD */ - 0x48, 0x3f, 0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, - 0xc0, 0x13, 0x00, 0x98, 0x32, 0x11, 0x00, 0x00, 0x1e - } -}; - -static uint8_t manuf_char_to_int(char c) -{ - return (c - 'A') & 0x1f; -} - -static void write_ascii_descriptor_block(uint8_t *descblob, uint8_t blocktype, - const char *string) -{ - /* Write an EDID Descriptor Block of the "ascii string" type */ - int i; - descblob[0] = descblob[1] = descblob[2] = descblob[4] = 0; - descblob[3] = blocktype; - /* The rest is 13 bytes of ASCII; if less then the rest must - * be filled with newline then spaces - */ - for (i = 5; i < 19; i++) { - descblob[i] = string[i - 5]; - if (!descblob[i]) { - break; - } - } - if (i < 19) { - descblob[i++] = '\n'; - } - for ( ; i < 19; i++) { - descblob[i] = ' '; - } -} - -static void write_range_limits_descriptor(const EDIDData *edid, - uint8_t *descblob) -{ - int i; - descblob[0] = descblob[1] = descblob[2] = descblob[4] = 0; - descblob[3] = 0xfd; - descblob[5] = edid->vmin; - descblob[6] = edid->vmax; - descblob[7] = edid->hmin; - descblob[8] = edid->hmax; - descblob[9] = edid->pixclock; - descblob[10] = 0; - descblob[11] = 0xa; - for (i = 12; i < 19; i++) { - descblob[i] = 0x20; - } -} - -static void build_edid_blob(const EDIDData *edid, uint8_t *blob) -{ - /* Write an EDID 1.3 format blob (128 bytes) based - * on the EDIDData structure. - */ - int i; - uint8_t cksum; - - /* 00-07 : header */ - blob[0] = blob[7] = 0; - for (i = 1 ; i < 7; i++) { - blob[i] = 0xff; - } - /* 08-09 : manufacturer ID */ - blob[8] = (manuf_char_to_int(edid->manuf_id[0]) << 2) - | (manuf_char_to_int(edid->manuf_id[1]) >> 3); - blob[9] = (manuf_char_to_int(edid->manuf_id[1]) << 5) - | manuf_char_to_int(edid->manuf_id[2]); - /* 10-11 : product ID code */ - blob[10] = edid->product_id; - blob[11] = edid->product_id >> 8; - blob[12] = edid->serial_no; - blob[13] = edid->serial_no >> 8; - blob[14] = edid->serial_no >> 16; - blob[15] = edid->serial_no >> 24; - /* 16 : week of manufacture */ - blob[16] = edid->manuf_week; - /* 17 : year of manufacture - 1990 */ - blob[17] = edid->manuf_year - 1990; - /* 18, 19 : EDID version and revision */ - blob[18] = 1; - blob[19] = 3; - /* 20 - 24 : basic display parameters */ - /* We are always a digital display */ - blob[20] = 0x80; - /* 21, 22 : max h/v size in cm */ - blob[21] = edid->h_cm; - blob[22] = edid->v_cm; - /* 23 : gamma (divide by 100 then add 1 for actual value) */ - blob[23] = edid->gamma; - /* 24 feature support: no power management, RGB, preferred timing mode, - * standard colour space - */ - blob[24] = 0x0e; - /* 25 - 34 : chromaticity coordinates. These are the - * standard sRGB chromaticity values - */ - blob[25] = 0xee; - blob[26] = 0x91; - blob[27] = 0xa3; - blob[28] = 0x54; - blob[29] = 0x4c; - blob[30] = 0x99; - blob[31] = 0x26; - blob[32] = 0x0f; - blob[33] = 0x50; - blob[34] = 0x54; - /* 35, 36 : Established timings: claim to support everything */ - blob[35] = blob[36] = 0xff; - /* 37 : manufacturer's reserved timing: none */ - blob[37] = 0; - /* 38 - 53 : standard timing identification - * don't claim anything beyond what the 'established timings' - * already provide. Unused slots must be (0x1, 0x1) - */ - for (i = 38; i < 54; i++) { - blob[i] = 0x1; - } - /* 54 - 71 : descriptor block 1 : must be preferred timing data */ - memcpy(blob + 54, edid->timing_data, 18); - /* 72 - 89, 90 - 107, 108 - 125 : descriptor block 2, 3, 4 - * Order not important, but we must have a monitor name and a - * range limits descriptor. - */ - write_range_limits_descriptor(edid, blob + 72); - write_ascii_descriptor_block(blob + 90, 0xfc, edid->monitor_name); - write_ascii_descriptor_block(blob + 108, 0xff, edid->serial_no_string); - - /* 126 : extension flag */ - blob[126] = 0; - - cksum = 0; - for (i = 0; i < 127; i++) { - cksum += blob[i]; - } - /* 127 : checksum */ - blob[127] = -cksum; - if (DEBUG_I2CDDC) { - qemu_hexdump((char *)blob, stdout, "", 128); - } -} - -static void i2c_ddc_reset(DeviceState *ds) -{ - I2CDDCState *s = I2CDDC(ds); - - s->firstbyte = false; - s->reg = 0; -} - -static void i2c_ddc_event(I2CSlave *i2c, enum i2c_event event) -{ - I2CDDCState *s = I2CDDC(i2c); - - if (event == I2C_START_SEND) { - s->firstbyte = true; - } -} - -static int i2c_ddc_rx(I2CSlave *i2c) -{ - I2CDDCState *s = I2CDDC(i2c); - - int value; - value = s->edid_blob[s->reg]; - s->reg++; - return value; -} - -static int i2c_ddc_tx(I2CSlave *i2c, uint8_t data) -{ - I2CDDCState *s = I2CDDC(i2c); - if (s->firstbyte) { - s->reg = data; - s->firstbyte = false; - DPRINTF("[EDID] Written new pointer: %u\n", data); - return 1; - } - - /* Ignore all writes */ - s->reg++; - return 1; -} - -static void i2c_ddc_init(Object *obj) -{ - I2CDDCState *s = I2CDDC(obj); - build_edid_blob(&lcd_edid, s->edid_blob); -} - -static const VMStateDescription vmstate_i2c_ddc = { - .name = TYPE_I2CDDC, - .version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_BOOL(firstbyte, I2CDDCState), - VMSTATE_UINT8(reg, I2CDDCState), - VMSTATE_END_OF_LIST() - } -}; - -static void i2c_ddc_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc); - - dc->reset = i2c_ddc_reset; - dc->vmsd = &vmstate_i2c_ddc; - isc->event = i2c_ddc_event; - isc->recv = i2c_ddc_rx; - isc->send = i2c_ddc_tx; -} - -static TypeInfo i2c_ddc_info = { - .name = TYPE_I2CDDC, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(I2CDDCState), - .instance_init = i2c_ddc_init, - .class_init = i2c_ddc_class_init -}; - -static void ddc_register_devices(void) -{ - type_register_static(&i2c_ddc_info); -} - -type_init(ddc_register_devices); diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c index 37e5a62ce..e19d4fa74 100644 --- a/hw/i2c/imx_i2c.c +++ b/hw/i2c/imx_i2c.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "hw/i2c/imx_i2c.h" #include "hw/i2c/i2c.h" -#include "qemu/log.h" #ifndef DEBUG_IMX_I2C #define DEBUG_IMX_I2C 0 diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c index f7c92ea00..67fbbff8e 100644 --- a/hw/i2c/omap_i2c.c +++ b/hw/i2c/omap_i2c.c @@ -22,7 +22,6 @@ #include "hw/arm/omap.h" #include "hw/sysbus.h" #include "qemu/error-report.h" -#include "qapi/error.h" #define TYPE_OMAP_I2C "omap_i2c" #define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C) @@ -446,35 +445,29 @@ static const MemoryRegionOps omap_i2c_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void omap_i2c_init(Object *obj) -{ - DeviceState *dev = DEVICE(obj); - OMAPI2CState *s = OMAP_I2C(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(sbd, &s->irq); - sysbus_init_irq(sbd, &s->drq[0]); - sysbus_init_irq(sbd, &s->drq[1]); - sysbus_init_mmio(sbd, &s->iomem); - s->bus = i2c_init_bus(dev, NULL); -} - -static void omap_i2c_realize(DeviceState *dev, Error **errp) +static int omap_i2c_init(SysBusDevice *sbd) { + DeviceState *dev = DEVICE(sbd); OMAPI2CState *s = OMAP_I2C(dev); - memory_region_init_io(&s->iomem, OBJECT(dev), &omap_i2c_ops, s, "omap.i2c", - (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000); - if (!s->fclk) { - error_setg(errp, "omap_i2c: fclk not connected"); - return; + error_report("omap_i2c: fclk not connected"); + return -1; } if (s->revision >= OMAP2_INTR_REV && !s->iclk) { /* Note that OMAP1 doesn't have a separate interface clock */ - error_setg(errp, "omap_i2c: iclk not connected"); - return; + error_report("omap_i2c: iclk not connected"); + return -1; } + + sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->drq[0]); + sysbus_init_irq(sbd, &s->drq[1]); + memory_region_init_io(&s->iomem, OBJECT(s), &omap_i2c_ops, s, "omap.i2c", + (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + s->bus = i2c_init_bus(dev, NULL); + return 0; } static Property omap_i2c_properties[] = { @@ -487,19 +480,18 @@ static Property omap_i2c_properties[] = { static void omap_i2c_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = omap_i2c_init; dc->props = omap_i2c_properties; dc->reset = omap_i2c_reset; /* Reason: pointer properties "iclk", "fclk" */ dc->cannot_instantiate_with_device_add_yet = true; - dc->realize = omap_i2c_realize; } static const TypeInfo omap_i2c_info = { .name = TYPE_OMAP_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(OMAPI2CState), - .instance_init = omap_i2c_init, .class_init = omap_i2c_class_init, }; diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index 48fab2262..498f03e83 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -35,6 +35,7 @@ #include "hw/i386/ich9.h" +#define TYPE_ICH9_SMB_DEVICE "ICH9 SMB" #define ICH9_SMB_DEVICE(obj) \ OBJECT_CHECK(ICH9SMBState, (obj), TYPE_ICH9_SMB_DEVICE) diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index da9f298ee..fee3bc761 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "bitbang_i2c.h" -#include "qemu/log.h" #define TYPE_VERSATILE_I2C "versatile_i2c" #define VERSATILE_I2C(obj) \ @@ -79,25 +78,32 @@ static const MemoryRegionOps versatile_i2c_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void versatile_i2c_init(Object *obj) +static int versatile_i2c_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - VersatileI2CState *s = VERSATILE_I2C(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + VersatileI2CState *s = VERSATILE_I2C(dev); I2CBus *bus; bus = i2c_init_bus(dev, "i2c"); s->bitbang = bitbang_i2c_init(bus); - memory_region_init_io(&s->iomem, obj, &versatile_i2c_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &versatile_i2c_ops, s, "versatile_i2c", 0x1000); sysbus_init_mmio(sbd, &s->iomem); + return 0; +} + +static void versatile_i2c_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = versatile_i2c_init; } static const TypeInfo versatile_i2c_info = { .name = TYPE_VERSATILE_I2C, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(VersatileI2CState), - .instance_init = versatile_i2c_init, + .class_init = versatile_i2c_class_init, }; static void versatile_i2c_register_types(void) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 90e94ffef..b52d5b875 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -2,7 +2,7 @@ obj-$(CONFIG_KVM) += kvm/ obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o -obj-y += x86-iommu.o intel_iommu.o +obj-y += intel_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index a26a4bb03..64770034f 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -23,6 +23,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "acpi-build.h" +#include <glib.h> #include "qemu-common.h" #include "qemu/bitmap.h" #include "qemu/error-report.h" @@ -33,7 +34,6 @@ #include "hw/timer/hpet.h" #include "hw/acpi/acpi-defs.h" #include "hw/acpi/acpi.h" -#include "hw/acpi/cpu.h" #include "hw/nvram/fw_cfg.h" #include "hw/acpi/bios-linker-loader.h" #include "hw/loader.h" @@ -44,7 +44,6 @@ #include "hw/acpi/tpm.h" #include "sysemu/tpm_backend.h" #include "hw/timer/mc146818rtc_regs.h" -#include "sysemu/numa.h" /* Supported chipsets: */ #include "hw/acpi/piix4.h" @@ -52,16 +51,13 @@ #include "hw/i386/ich9.h" #include "hw/pci/pci_bus.h" #include "hw/pci-host/q35.h" -#include "hw/i386/x86-iommu.h" +#include "hw/i386/intel_iommu.h" #include "hw/timer/hpet.h" #include "hw/acpi/aml-build.h" #include "qapi/qmp/qint.h" #include "qom/qom-qobject.h" -#include "hw/i386/x86-iommu.h" - -#include "hw/acpi/ipmi.h" /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows @@ -81,9 +77,6 @@ #define ACPI_BUILD_DPRINTF(fmt, ...) #endif -/* Default IOAPIC ID */ -#define ACPI_BUILD_IOAPIC_ID 0x0 - typedef struct AcpiMcfgInfo { uint64_t mcfg_base; uint32_t mcfg_size; @@ -101,6 +94,7 @@ typedef struct AcpiPmInfo { uint32_t gpe0_blk_len; uint32_t io_base; uint16_t cpu_hp_io_base; + uint16_t cpu_hp_io_len; uint16_t mem_hp_io_base; uint16_t mem_hp_io_len; uint16_t pcihp_io_base; @@ -148,6 +142,7 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) } assert(obj); + pm->cpu_hp_io_len = ACPI_GPE_PROC_LEN; pm->mem_hp_io_base = ACPI_MEMORY_HOTPLUG_BASE; pm->mem_hp_io_len = ACPI_MEMORY_HOTPLUG_IO_LEN; @@ -233,27 +228,26 @@ static Object *acpi_get_i386_pci_host(void) return OBJECT(host); } -static void acpi_get_pci_holes(Range *hole, Range *hole64) +static void acpi_get_pci_info(PcPciInfo *info) { Object *pci_host; + pci_host = acpi_get_i386_pci_host(); g_assert(pci_host); - range_set_bounds1(hole, - object_property_get_int(pci_host, + info->w32.begin = object_property_get_int(pci_host, PCI_HOST_PROP_PCI_HOLE_START, - NULL), - object_property_get_int(pci_host, - PCI_HOST_PROP_PCI_HOLE_END, - NULL)); - range_set_bounds1(hole64, - object_property_get_int(pci_host, + NULL); + info->w32.end = object_property_get_int(pci_host, + PCI_HOST_PROP_PCI_HOLE_END, + NULL); + info->w64.begin = object_property_get_int(pci_host, PCI_HOST_PROP_PCI_HOLE64_START, - NULL), - object_property_get_int(pci_host, - PCI_HOST_PROP_PCI_HOLE64_END, - NULL)); + NULL); + info->w64.end = object_property_get_int(pci_host, + PCI_HOST_PROP_PCI_HOLE64_END, + NULL); } #define ACPI_PORT_SMI_CMD 0x00b2 /* TODO: this is APM_CNT_IOPORT */ @@ -268,7 +262,7 @@ static void acpi_align_size(GArray *blob, unsigned align) /* FACS */ static void -build_facs(GArray *table_data, BIOSLinker *linker) +build_facs(GArray *table_data, GArray *linker) { AcpiFacsDescriptorRev1 *facs = acpi_data_push(table_data, sizeof *facs); memcpy(&facs->signature, "FACS", 4); @@ -313,61 +307,38 @@ static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm) /* FADT */ static void -build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm, - unsigned facs_tbl_offset, unsigned dsdt_tbl_offset, +build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, + unsigned facs, unsigned dsdt, const char *oem_id, const char *oem_table_id) { AcpiFadtDescriptorRev1 *fadt = acpi_data_push(table_data, sizeof(*fadt)); - unsigned fw_ctrl_offset = (char *)&fadt->firmware_ctrl - table_data->data; - unsigned dsdt_entry_offset = (char *)&fadt->dsdt - table_data->data; + fadt->firmware_ctrl = cpu_to_le32(facs); /* FACS address to be filled by Guest linker */ - bios_linker_loader_add_pointer(linker, - ACPI_BUILD_TABLE_FILE, fw_ctrl_offset, sizeof(fadt->firmware_ctrl), - ACPI_BUILD_TABLE_FILE, facs_tbl_offset); + bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, + ACPI_BUILD_TABLE_FILE, + table_data, &fadt->firmware_ctrl, + sizeof fadt->firmware_ctrl); + fadt->dsdt = cpu_to_le32(dsdt); /* DSDT address to be filled by Guest linker */ + bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, + ACPI_BUILD_TABLE_FILE, + table_data, &fadt->dsdt, + sizeof fadt->dsdt); + fadt_setup(fadt, pm); - bios_linker_loader_add_pointer(linker, - ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt), - ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset); build_header(linker, table_data, (void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id); } -void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - CPUArchIdList *apic_ids, GArray *entry) -{ - int apic_id; - AcpiMadtProcessorApic *apic = acpi_data_push(entry, sizeof *apic); - - apic_id = apic_ids->cpus[uid].arch_id; - apic->type = ACPI_APIC_PROCESSOR; - apic->length = sizeof(*apic); - apic->processor_id = uid; - apic->local_apic_id = apic_id; - if (apic_ids->cpus[uid].cpu != NULL) { - apic->flags = cpu_to_le32(1); - } else { - /* ACPI spec says that LAPIC entry for non present - * CPU may be omitted from MADT or it must be marked - * as disabled. However omitting non present CPU from - * MADT breaks hotplug on linux. So possible CPUs - * should be put in MADT but kept disabled. - */ - apic->flags = cpu_to_le32(0); - } -} - static void -build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms) +build_madt(GArray *table_data, GArray *linker, PCMachineState *pcms) { MachineClass *mc = MACHINE_GET_CLASS(pcms); CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(pcms)); int madt_start = table_data->len; - AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(pcms->acpi_dev); - AcpiDeviceIf *adev = ACPI_DEVICE_IF(pcms->acpi_dev); AcpiMultipleApicTable *madt; AcpiMadtIoApic *io_apic; @@ -380,13 +351,31 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms) madt->flags = cpu_to_le32(1); for (i = 0; i < apic_ids->len; i++) { - adevc->madt_cpu(adev, i, apic_ids, table_data); + AcpiMadtProcessorApic *apic = acpi_data_push(table_data, sizeof *apic); + int apic_id = apic_ids->cpus[i].arch_id; + + apic->type = ACPI_APIC_PROCESSOR; + apic->length = sizeof(*apic); + apic->processor_id = apic_id; + apic->local_apic_id = apic_id; + if (apic_ids->cpus[i].cpu != NULL) { + apic->flags = cpu_to_le32(1); + } else { + /* ACPI spec says that LAPIC entry for non present + * CPU may be omitted from MADT or it must be marked + * as disabled. However omitting non present CPU from + * MADT breaks hotplug on linux. So possible CPUs + * should be put in MADT but kept disabled. + */ + apic->flags = cpu_to_le32(0); + } } g_free(apic_ids); io_apic = acpi_data_push(table_data, sizeof *io_apic); io_apic->type = ACPI_APIC_IO; io_apic->length = sizeof(*io_apic); +#define ACPI_BUILD_IOAPIC_ID 0x0 io_apic->io_apic_id = ACPI_BUILD_IOAPIC_ID; io_apic->address = cpu_to_le32(IO_APIC_DEFAULT_ADDRESS); io_apic->interrupt = cpu_to_le32(0); @@ -600,10 +589,6 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, QLIST_FOREACH(sec, &bus->child, sibling) { int32_t devfn = sec->parent_dev->devfn; - if (pci_bus_is_root(sec) || pci_bus_is_express(sec)) { - continue; - } - aml_append(method, aml_name("^S%.02X.PCNT", devfn)); } } @@ -751,27 +736,6 @@ static void crs_range_free(gpointer data) g_free(entry); } -typedef struct CrsRangeSet { - GPtrArray *io_ranges; - GPtrArray *mem_ranges; - GPtrArray *mem_64bit_ranges; - } CrsRangeSet; - -static void crs_range_set_init(CrsRangeSet *range_set) -{ - range_set->io_ranges = g_ptr_array_new_with_free_func(crs_range_free); - range_set->mem_ranges = g_ptr_array_new_with_free_func(crs_range_free); - range_set->mem_64bit_ranges = - g_ptr_array_new_with_free_func(crs_range_free); -} - -static void crs_range_set_free(CrsRangeSet *range_set) -{ - g_ptr_array_free(range_set->io_ranges, true); - g_ptr_array_free(range_set->mem_ranges, true); - g_ptr_array_free(range_set->mem_64bit_ranges, true); -} - static gint crs_range_compare(gconstpointer a, gconstpointer b) { CrsRangeEntry *entry_a = *(CrsRangeEntry **)a; @@ -856,17 +820,18 @@ static void crs_range_merge(GPtrArray *range) g_ptr_array_free(tmp, true); } -static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set) +static Aml *build_crs(PCIHostState *host, + GPtrArray *io_ranges, GPtrArray *mem_ranges) { Aml *crs = aml_resource_template(); - CrsRangeSet temp_range_set; + GPtrArray *host_io_ranges = g_ptr_array_new_with_free_func(crs_range_free); + GPtrArray *host_mem_ranges = g_ptr_array_new_with_free_func(crs_range_free); CrsRangeEntry *entry; uint8_t max_bus = pci_bus_num(host->bus); uint8_t type; int devfn; int i; - crs_range_set_init(&temp_range_set); for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) { uint64_t range_base, range_limit; PCIDevice *dev = host->bus->devices[devfn]; @@ -890,11 +855,9 @@ static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set) } if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { - crs_range_insert(temp_range_set.io_ranges, - range_base, range_limit); + crs_range_insert(host_io_ranges, range_base, range_limit); } else { /* "memory" */ - crs_range_insert(temp_range_set.mem_ranges, - range_base, range_limit); + crs_range_insert(host_mem_ranges, range_base, range_limit); } } @@ -913,8 +876,7 @@ static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set) * that do not support multiple root buses */ if (range_base && range_base <= range_limit) { - crs_range_insert(temp_range_set.io_ranges, - range_base, range_limit); + crs_range_insert(host_io_ranges, range_base, range_limit); } range_base = @@ -927,14 +889,7 @@ static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set) * that do not support multiple root buses */ if (range_base && range_base <= range_limit) { - uint64_t length = range_limit - range_base + 1; - if (range_limit <= UINT32_MAX && length <= UINT32_MAX) { - crs_range_insert(temp_range_set.mem_ranges, - range_base, range_limit); - } else { - crs_range_insert(temp_range_set.mem_64bit_ranges, - range_base, range_limit); - } + crs_range_insert(host_mem_ranges, range_base, range_limit); } range_base = @@ -947,55 +902,35 @@ static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set) * that do not support multiple root buses */ if (range_base && range_base <= range_limit) { - uint64_t length = range_limit - range_base + 1; - if (range_limit <= UINT32_MAX && length <= UINT32_MAX) { - crs_range_insert(temp_range_set.mem_ranges, - range_base, range_limit); - } else { - crs_range_insert(temp_range_set.mem_64bit_ranges, - range_base, range_limit); - } + crs_range_insert(host_mem_ranges, range_base, range_limit); } } } - crs_range_merge(temp_range_set.io_ranges); - for (i = 0; i < temp_range_set.io_ranges->len; i++) { - entry = g_ptr_array_index(temp_range_set.io_ranges, i); + crs_range_merge(host_io_ranges); + for (i = 0; i < host_io_ranges->len; i++) { + entry = g_ptr_array_index(host_io_ranges, i); aml_append(crs, aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, AML_ENTIRE_RANGE, 0, entry->base, entry->limit, 0, entry->limit - entry->base + 1)); - crs_range_insert(range_set->io_ranges, entry->base, entry->limit); + crs_range_insert(io_ranges, entry->base, entry->limit); } + g_ptr_array_free(host_io_ranges, true); - crs_range_merge(temp_range_set.mem_ranges); - for (i = 0; i < temp_range_set.mem_ranges->len; i++) { - entry = g_ptr_array_index(temp_range_set.mem_ranges, i); + crs_range_merge(host_mem_ranges); + for (i = 0; i < host_mem_ranges->len; i++) { + entry = g_ptr_array_index(host_mem_ranges, i); aml_append(crs, aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, AML_NON_CACHEABLE, AML_READ_WRITE, 0, entry->base, entry->limit, 0, entry->limit - entry->base + 1)); - crs_range_insert(range_set->mem_ranges, entry->base, entry->limit); - } - - crs_range_merge(temp_range_set.mem_64bit_ranges); - for (i = 0; i < temp_range_set.mem_64bit_ranges->len; i++) { - entry = g_ptr_array_index(temp_range_set.mem_64bit_ranges, i); - aml_append(crs, - aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, - AML_MAX_FIXED, AML_NON_CACHEABLE, - AML_READ_WRITE, - 0, entry->base, entry->limit, 0, - entry->limit - entry->base + 1)); - crs_range_insert(range_set->mem_64bit_ranges, - entry->base, entry->limit); + crs_range_insert(mem_ranges, entry->base, entry->limit); } - - crs_range_set_free(&temp_range_set); + g_ptr_array_free(host_mem_ranges, true); aml_append(crs, aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, @@ -1008,6 +943,114 @@ static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set) return crs; } +static void build_processor_devices(Aml *sb_scope, MachineState *machine, + AcpiPmInfo *pm) +{ + int i, apic_idx; + Aml *dev; + Aml *crs; + Aml *pkg; + Aml *field; + Aml *ifctx; + Aml *method; + MachineClass *mc = MACHINE_GET_CLASS(machine); + CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(machine); + PCMachineState *pcms = PC_MACHINE(machine); + + /* The current AML generator can cover the APIC ID range [0..255], + * inclusive, for VCPU hotplug. */ + QEMU_BUILD_BUG_ON(ACPI_CPU_HOTPLUG_ID_LIMIT > 256); + g_assert(pcms->apic_id_limit <= ACPI_CPU_HOTPLUG_ID_LIMIT); + + /* create PCI0.PRES device and its _CRS to reserve CPU hotplug MMIO */ + dev = aml_device("PCI0." stringify(CPU_HOTPLUG_RESOURCE_DEVICE)); + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A06"))); + aml_append(dev, + aml_name_decl("_UID", aml_string("CPU Hotplug resources")) + ); + /* device present, functioning, decoding, not shown in UI */ + aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); + crs = aml_resource_template(); + aml_append(crs, + aml_io(AML_DECODE16, pm->cpu_hp_io_base, pm->cpu_hp_io_base, 1, + pm->cpu_hp_io_len) + ); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(sb_scope, dev); + /* declare CPU hotplug MMIO region and PRS field to access it */ + aml_append(sb_scope, aml_operation_region( + "PRST", AML_SYSTEM_IO, aml_int(pm->cpu_hp_io_base), pm->cpu_hp_io_len)); + field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE); + aml_append(field, aml_named_field("PRS", 256)); + aml_append(sb_scope, field); + + /* build Processor object for each processor */ + for (i = 0; i < apic_ids->len; i++) { + int apic_id = apic_ids->cpus[i].arch_id; + + assert(apic_id < ACPI_CPU_HOTPLUG_ID_LIMIT); + + dev = aml_processor(apic_id, 0, 0, "CP%.02X", apic_id); + + method = aml_method("_MAT", 0, AML_NOTSERIALIZED); + aml_append(method, + aml_return(aml_call1(CPU_MAT_METHOD, aml_int(apic_id)))); + aml_append(dev, method); + + method = aml_method("_STA", 0, AML_NOTSERIALIZED); + aml_append(method, + aml_return(aml_call1(CPU_STATUS_METHOD, aml_int(apic_id)))); + aml_append(dev, method); + + method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); + aml_append(method, + aml_return(aml_call2(CPU_EJECT_METHOD, aml_int(apic_id), + aml_arg(0))) + ); + aml_append(dev, method); + + aml_append(sb_scope, dev); + } + + /* build this code: + * Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...} + */ + /* Arg0 = Processor ID = APIC ID */ + method = aml_method(AML_NOTIFY_METHOD, 2, AML_NOTSERIALIZED); + for (i = 0; i < apic_ids->len; i++) { + int apic_id = apic_ids->cpus[i].arch_id; + + ifctx = aml_if(aml_equal(aml_arg(0), aml_int(apic_id))); + aml_append(ifctx, + aml_notify(aml_name("CP%.02X", apic_id), aml_arg(1)) + ); + aml_append(method, ifctx); + } + aml_append(sb_scope, method); + + /* build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })" + * + * Note: The ability to create variable-sized packages was first + * introduced in ACPI 2.0. ACPI 1.0 only allowed fixed-size packages + * ith up to 255 elements. Windows guests up to win2k8 fail when + * VarPackageOp is used. + */ + pkg = pcms->apic_id_limit <= 255 ? aml_package(pcms->apic_id_limit) : + aml_varpackage(pcms->apic_id_limit); + + for (i = 0, apic_idx = 0; i < apic_ids->len; i++) { + int apic_id = apic_ids->cpus[i].arch_id; + + for (; apic_idx < apic_id; apic_idx++) { + aml_append(pkg, aml_int(0)); + } + aml_append(pkg, aml_int(apic_ids->cpus[i].cpu ? 1 : 0)); + apic_idx = apic_id + 1; + } + aml_append(sb_scope, aml_name_decl(CPU_ON_BITMAP, pkg)); + g_free(apic_ids); +} + static void build_memory_devices(Aml *sb_scope, int nr_mem, uint16_t io_base, uint16_t io_len) { @@ -1405,10 +1448,8 @@ static Aml *build_com_device_aml(uint8_t uid) static void build_isa_devices_aml(Aml *table) { ISADevice *fdc = pc_find_fdc0(); - bool ambiguous; Aml *scope = aml_scope("_SB.PCI0.ISA"); - Object *obj = object_resolve_path_type("", TYPE_ISA_BUS, &ambiguous); aml_append(scope, build_rtc_device_aml()); aml_append(scope, build_kbd_device_aml()); @@ -1420,14 +1461,6 @@ static void build_isa_devices_aml(Aml *table) aml_append(scope, build_com_device_aml(1)); aml_append(scope, build_com_device_aml(2)); - if (ambiguous) { - error_report("Multiple ISA busses, unable to define IPMI ACPI data"); - } else if (!obj) { - error_report("No ISA bus, unable to define IPMI ACPI data"); - } else { - build_acpi_ipmi_devices(scope, BUS(obj)); - } - aml_append(table, scope); } @@ -1946,15 +1979,15 @@ static Aml *build_q35_osc_method(void) } static void -build_dsdt(GArray *table_data, BIOSLinker *linker, +build_dsdt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, AcpiMiscInfo *misc, - Range *pci_hole, Range *pci_hole64, MachineState *machine) + PcPciInfo *pci, MachineState *machine) { CrsRangeEntry *entry; Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs; - CrsRangeSet crs_range_set; + GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free); + GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free); PCMachineState *pcms = PC_MACHINE(machine); - PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(machine); uint32_t nr_mem = machine->ram_slots; int root_bus_limit = 0xFF; PCIBus *bus = NULL; @@ -2010,15 +2043,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, build_q35_pci0_int(dsdt); } - if (pcmc->legacy_cpu_hotplug) { - build_legacy_cpu_hotplug_aml(dsdt, machine, pm->cpu_hp_io_base); - } else { - CPUHotplugFeatures opts = { - .apci_1_compatible = true, .has_legacy_cphp = true - }; - build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base, - "\\_SB.PCI0", "\\_GPE._E02"); - } + build_cpu_hotplug_aml(dsdt); build_memory_hotplug_aml(dsdt, nr_mem, pm->mem_hp_io_base, pm->mem_hp_io_len); @@ -2026,6 +2051,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, { aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006"))); + aml_append(scope, aml_method("_L00", 0, AML_NOTSERIALIZED)); + if (misc->is_piix4) { method = aml_method("_E01", 0, AML_NOTSERIALIZED); aml_append(method, @@ -2033,15 +2060,33 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); aml_append(scope, method); + } else { + aml_append(scope, aml_method("_L01", 0, AML_NOTSERIALIZED)); } + method = aml_method("_E02", 0, AML_NOTSERIALIZED); + aml_append(method, aml_call0("\\_SB." CPU_SCAN_METHOD)); + aml_append(scope, method); + method = aml_method("_E03", 0, AML_NOTSERIALIZED); aml_append(method, aml_call0(MEMORY_HOTPLUG_HANDLER_PATH)); aml_append(scope, method); + + aml_append(scope, aml_method("_L04", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L05", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L06", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L07", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L08", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L09", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0A", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0B", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0C", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0D", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0E", 0, AML_NOTSERIALIZED)); + aml_append(scope, aml_method("_L0F", 0, AML_NOTSERIALIZED)); } aml_append(dsdt, scope); - crs_range_set_init(&crs_range_set); bus = PC_MACHINE(machine)->bus; if (bus) { QLIST_FOREACH(bus, &bus->child, sibling) { @@ -2068,7 +2113,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } aml_append(dev, build_prt(false)); - crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent), &crs_range_set); + crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent), + io_ranges, mem_ranges); aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(scope, dev); aml_append(dsdt, scope); @@ -2089,9 +2135,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, AML_POS_DECODE, AML_ENTIRE_RANGE, 0x0000, 0x0000, 0x0CF7, 0x0000, 0x0CF8)); - crs_replace_with_free_ranges(crs_range_set.io_ranges, 0x0D00, 0xFFFF); - for (i = 0; i < crs_range_set.io_ranges->len; i++) { - entry = g_ptr_array_index(crs_range_set.io_ranges, i); + crs_replace_with_free_ranges(io_ranges, 0x0D00, 0xFFFF); + for (i = 0; i < io_ranges->len; i++) { + entry = g_ptr_array_index(io_ranges, i); aml_append(crs, aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, AML_ENTIRE_RANGE, @@ -2104,11 +2150,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, AML_CACHEABLE, AML_READ_WRITE, 0, 0x000A0000, 0x000BFFFF, 0, 0x00020000)); - crs_replace_with_free_ranges(crs_range_set.mem_ranges, - range_lob(pci_hole), - range_upb(pci_hole)); - for (i = 0; i < crs_range_set.mem_ranges->len; i++) { - entry = g_ptr_array_index(crs_range_set.mem_ranges, i); + crs_replace_with_free_ranges(mem_ranges, pci->w32.begin, pci->w32.end - 1); + for (i = 0; i < mem_ranges->len; i++) { + entry = g_ptr_array_index(mem_ranges, i); aml_append(crs, aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, AML_NON_CACHEABLE, AML_READ_WRITE, @@ -2116,19 +2160,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, 0, entry->limit - entry->base + 1)); } - if (!range_is_empty(pci_hole64)) { - crs_replace_with_free_ranges(crs_range_set.mem_64bit_ranges, - range_lob(pci_hole64), - range_upb(pci_hole64)); - for (i = 0; i < crs_range_set.mem_64bit_ranges->len; i++) { - entry = g_ptr_array_index(crs_range_set.mem_64bit_ranges, i); - aml_append(crs, - aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, - AML_MAX_FIXED, - AML_CACHEABLE, AML_READ_WRITE, - 0, entry->base, entry->limit, - 0, entry->limit - entry->base + 1)); - } + if (pci->w64.begin) { + aml_append(crs, + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, + AML_CACHEABLE, AML_READ_WRITE, + 0, pci->w64.begin, pci->w64.end - 1, 0, + pci->w64.end - pci->w64.begin)); } if (misc->tpm_version != TPM_VERSION_UNSPEC) { @@ -2150,7 +2187,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dev, aml_name_decl("_CRS", crs)); aml_append(scope, dev); - crs_range_set_free(&crs_range_set); + g_ptr_array_free(io_ranges, true); + g_ptr_array_free(mem_ranges, true); /* reserve PCIHP resources */ if (pm->pcihp_io_len) { @@ -2284,6 +2322,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, sb_scope = aml_scope("\\_SB"); { + build_processor_devices(sb_scope, machine, pm); + build_memory_devices(sb_scope, nr_mem, pm->mem_hp_io_base, pm->mem_hp_io_len); @@ -2333,7 +2373,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } static void -build_hpet(GArray *table_data, BIOSLinker *linker) +build_hpet(GArray *table_data, GArray *linker) { Acpi20Hpet *hpet; @@ -2348,31 +2388,32 @@ build_hpet(GArray *table_data, BIOSLinker *linker) } static void -build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) +build_tpm_tcpa(GArray *table_data, GArray *linker, GArray *tcpalog) { Acpi20Tcpa *tcpa = acpi_data_push(table_data, sizeof *tcpa); - unsigned log_addr_size = sizeof(tcpa->log_area_start_address); - unsigned log_addr_offset = - (char *)&tcpa->log_area_start_address - table_data->data; + uint64_t log_area_start_address = acpi_data_len(tcpalog); tcpa->platform_class = cpu_to_le16(TPM_TCPA_ACPI_CLASS_CLIENT); tcpa->log_area_minimum_length = cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE); - acpi_data_push(tcpalog, le32_to_cpu(tcpa->log_area_minimum_length)); + tcpa->log_area_start_address = cpu_to_le64(log_area_start_address); - bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, tcpalog, 1, + bios_linker_loader_alloc(linker, ACPI_BUILD_TPMLOG_FILE, 1, false /* high memory */); /* log area start address to be filled by Guest linker */ - bios_linker_loader_add_pointer(linker, - ACPI_BUILD_TABLE_FILE, log_addr_offset, log_addr_size, - ACPI_BUILD_TPMLOG_FILE, 0); + bios_linker_loader_add_pointer(linker, ACPI_BUILD_TABLE_FILE, + ACPI_BUILD_TPMLOG_FILE, + table_data, &tcpa->log_area_start_address, + sizeof(tcpa->log_area_start_address)); build_header(linker, table_data, (void *)tcpa, "TCPA", sizeof(*tcpa), 2, NULL, NULL); + + acpi_data_push(tcpalog, TPM_LOG_AREA_MINIMUM_SIZE); } static void -build_tpm2(GArray *table_data, BIOSLinker *linker) +build_tpm2(GArray *table_data, GArray *linker) { Acpi20TPM2 *tpm2_ptr; @@ -2386,14 +2427,35 @@ build_tpm2(GArray *table_data, BIOSLinker *linker) (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL); } +typedef enum { + MEM_AFFINITY_NOFLAGS = 0, + MEM_AFFINITY_ENABLED = (1 << 0), + MEM_AFFINITY_HOTPLUGGABLE = (1 << 1), + MEM_AFFINITY_NON_VOLATILE = (1 << 2), +} MemoryAffinityFlags; + +static void +acpi_build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base, + uint64_t len, int node, MemoryAffinityFlags flags) +{ + numamem->type = ACPI_SRAT_MEMORY; + numamem->length = sizeof(*numamem); + memset(numamem->proximity, 0, 4); + numamem->proximity[0] = node; + numamem->flags = cpu_to_le32(flags); + numamem->base_addr = cpu_to_le64(base); + numamem->range_length = cpu_to_le64(len); +} + static void -build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) +build_srat(GArray *table_data, GArray *linker, MachineState *machine) { AcpiSystemResourceAffinityTable *srat; AcpiSratProcessorAffinity *core; AcpiSratMemoryAffinity *numamem; int i; + uint64_t curnode; int srat_start, numa_start, slots; uint64_t mem_len, mem_base, next_base; MachineClass *mc = MACHINE_GET_CLASS(machine); @@ -2409,19 +2471,14 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) srat->reserved1 = cpu_to_le32(1); for (i = 0; i < apic_ids->len; i++) { - int j; int apic_id = apic_ids->cpus[i].arch_id; core = acpi_data_push(table_data, sizeof *core); - core->type = ACPI_SRAT_PROCESSOR_APIC; + core->type = ACPI_SRAT_PROCESSOR; core->length = sizeof(*core); core->local_apic_id = apic_id; - for (j = 0; j < nb_numa_nodes; j++) { - if (test_bit(i, numa_info[j].node_cpu)) { - core->proximity_lo = j; - break; - } - } + curnode = pcms->node_cpu[apic_id]; + core->proximity_lo = curnode; memset(core->proximity_hi, 0, 3); core->local_sapic_eid = 0; core->flags = cpu_to_le32(1); @@ -2435,7 +2492,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) numa_start = table_data->len; numamem = acpi_data_push(table_data, sizeof *numamem); - build_srat_memory(numamem, 0, 640 * 1024, 0, MEM_AFFINITY_ENABLED); + acpi_build_srat_memory(numamem, 0, 640*1024, 0, MEM_AFFINITY_ENABLED); next_base = 1024 * 1024; for (i = 1; i < pcms->numa_nodes + 1; ++i) { mem_base = next_base; @@ -2451,21 +2508,21 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) mem_len -= next_base - pcms->below_4g_mem_size; if (mem_len > 0) { numamem = acpi_data_push(table_data, sizeof *numamem); - build_srat_memory(numamem, mem_base, mem_len, i - 1, - MEM_AFFINITY_ENABLED); + acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1, + MEM_AFFINITY_ENABLED); } mem_base = 1ULL << 32; mem_len = next_base - pcms->below_4g_mem_size; next_base += (1ULL << 32) - pcms->below_4g_mem_size; } numamem = acpi_data_push(table_data, sizeof *numamem); - build_srat_memory(numamem, mem_base, mem_len, i - 1, - MEM_AFFINITY_ENABLED); + acpi_build_srat_memory(numamem, mem_base, mem_len, i - 1, + MEM_AFFINITY_ENABLED); } slots = (table_data->len - numa_start) / sizeof *numamem; for (; slots < pcms->numa_nodes + 2; slots++) { numamem = acpi_data_push(table_data, sizeof *numamem); - build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS); + acpi_build_srat_memory(numamem, 0, 0, 0, MEM_AFFINITY_NOFLAGS); } /* @@ -2475,9 +2532,10 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) */ if (hotplugabble_address_space_size) { numamem = acpi_data_push(table_data, sizeof *numamem); - build_srat_memory(numamem, pcms->hotplug_memory.base, - hotplugabble_address_space_size, 0, - MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); + acpi_build_srat_memory(numamem, pcms->hotplug_memory.base, + hotplugabble_address_space_size, 0, + MEM_AFFINITY_HOTPLUGGABLE | + MEM_AFFINITY_ENABLED); } build_header(linker, table_data, @@ -2488,7 +2546,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) } static void -build_mcfg_q35(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info) +build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info) { AcpiTableMcfg *mcfg; const char *sig; @@ -2516,75 +2574,51 @@ build_mcfg_q35(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info) build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL, NULL); } -/* - * VT-d spec 8.1 DMA Remapping Reporting Structure - * (version Oct. 2014 or later) - */ static void -build_dmar_q35(GArray *table_data, BIOSLinker *linker) +build_dmar_q35(GArray *table_data, GArray *linker) { int dmar_start = table_data->len; AcpiTableDmar *dmar; AcpiDmarHardwareUnit *drhd; - uint8_t dmar_flags = 0; - X86IOMMUState *iommu = x86_iommu_get_default(); - AcpiDmarDeviceScope *scope = NULL; - /* Root complex IOAPIC use one path[0] only */ - size_t ioapic_scope_size = sizeof(*scope) + sizeof(scope->path[0]); - - assert(iommu); - if (iommu->intr_supported) { - dmar_flags |= 0x1; /* Flags: 0x1: INT_REMAP */ - } dmar = acpi_data_push(table_data, sizeof(*dmar)); dmar->host_address_width = VTD_HOST_ADDRESS_WIDTH - 1; - dmar->flags = dmar_flags; + dmar->flags = 0; /* No intr_remap for now */ /* DMAR Remapping Hardware Unit Definition structure */ - drhd = acpi_data_push(table_data, sizeof(*drhd) + ioapic_scope_size); + drhd = acpi_data_push(table_data, sizeof(*drhd)); drhd->type = cpu_to_le16(ACPI_DMAR_TYPE_HARDWARE_UNIT); - drhd->length = cpu_to_le16(sizeof(*drhd) + ioapic_scope_size); + drhd->length = cpu_to_le16(sizeof(*drhd)); /* No device scope now */ drhd->flags = ACPI_DMAR_INCLUDE_PCI_ALL; drhd->pci_segment = cpu_to_le16(0); drhd->address = cpu_to_le64(Q35_HOST_BRIDGE_IOMMU_ADDR); - /* Scope definition for the root-complex IOAPIC. See VT-d spec - * 8.3.1 (version Oct. 2014 or later). */ - scope = &drhd->scope[0]; - scope->entry_type = 0x03; /* Type: 0x03 for IOAPIC */ - scope->length = ioapic_scope_size; - scope->enumeration_id = ACPI_BUILD_IOAPIC_ID; - scope->bus = Q35_PSEUDO_BUS_PLATFORM; - scope->path[0] = cpu_to_le16(Q35_PSEUDO_DEVFN_IOAPIC); - build_header(linker, table_data, (void *)(table_data->data + dmar_start), "DMAR", table_data->len - dmar_start, 1, NULL, NULL); } static GArray * -build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset) +build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) { AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp); - unsigned rsdt_pa_size = sizeof(rsdp->rsdt_physical_address); - unsigned rsdt_pa_offset = - (char *)&rsdp->rsdt_physical_address - rsdp_table->data; - bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, rsdp_table, 16, + bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16, true /* fseg memory */); memcpy(&rsdp->signature, "RSD PTR ", 8); memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, 6); + rsdp->rsdt_physical_address = cpu_to_le32(rsdt); /* Address to be filled by Guest linker */ - bios_linker_loader_add_pointer(linker, - ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size, - ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset); - + bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE, + ACPI_BUILD_TABLE_FILE, + rsdp_table, &rsdp->rsdt_physical_address, + sizeof rsdp->rsdt_physical_address); + rsdp->checksum = 0; /* Checksum to be filled by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, - (char *)rsdp - rsdp_table->data, sizeof *rsdp, - (char *)&rsdp->checksum - rsdp_table->data); + rsdp_table, rsdp, sizeof *rsdp, + &rsdp->checksum); return rsdp_table; } @@ -2624,7 +2658,12 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg) static bool acpi_has_iommu(void) { - return !!x86_iommu_get_default(); + bool ambiguous; + Object *intel_iommu; + + intel_iommu = object_resolve_path_type("", TYPE_INTEL_IOMMU_DEVICE, + &ambiguous); + return intel_iommu && !ambiguous; } static @@ -2637,7 +2676,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) AcpiPmInfo pm; AcpiMiscInfo misc; AcpiMcfgInfo mcfg; - Range pci_hole, pci_hole64; + PcPciInfo pci; uint8_t *u; size_t aml_len = 0; GArray *tables_blob = tables->table_data; @@ -2645,15 +2684,14 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_get_pm_info(&pm); acpi_get_misc_info(&misc); - acpi_get_pci_holes(&pci_hole, &pci_hole64); + acpi_get_pci_info(&pci); acpi_get_slic_oem(&slic_oem); table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); ACPI_BUILD_DPRINTF("init ACPI tables\n"); - bios_linker_loader_alloc(tables->linker, - ACPI_BUILD_TABLE_FILE, tables_blob, + bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE, 64 /* Ensure FACS is aligned */, false /* high memory */); @@ -2667,8 +2705,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) /* DSDT is pointed to by FADT */ dsdt = tables_blob->len; - build_dsdt(tables_blob, tables->linker, &pm, &misc, - &pci_hole, &pci_hole64, machine); + build_dsdt(tables_blob, tables->linker, &pm, &misc, &pci, machine); /* Count the size of the DSDT and SSDT, we will need it for legacy * sizing of ACPI tables. @@ -2711,8 +2748,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) build_dmar_q35(tables_blob, tables->linker); } if (pcms->acpi_nvdimm_state.is_enabled) { - nvdimm_build_acpi(table_offsets, tables_blob, tables->linker, - pcms->acpi_nvdimm_state.dsm_mem); + nvdimm_build_acpi(table_offsets, tables_blob, tables->linker); } /* Add tables supplied by user (if any) */ @@ -2775,7 +2811,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE); } - acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE); + acpi_align_size(tables->linker, ACPI_BUILD_ALIGN_SIZE); /* Cleanup memory that's no longer used. */ g_array_free(table_offsets, true); @@ -2815,7 +2851,7 @@ static void acpi_build_update(void *build_opaque) acpi_ram_update(build_state->rsdp_mr, tables.rsdp); } - acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); + acpi_ram_update(build_state->linker_mr, tables.linker); acpi_build_tables_cleanup(&tables, true); } @@ -2879,8 +2915,7 @@ void acpi_setup(void) assert(build_state->table_mr != NULL); build_state->linker_mr = - acpi_add_rom_blob(build_state, tables.linker->cmd_blob, - "etc/table-loader", 0); + acpi_add_rom_blob(build_state, tables.linker, "etc/table-loader", 0); fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data, acpi_data_len(tables.tcpalog)); diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 28c31a2cd..347718f93 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -20,23 +20,16 @@ */ #include "qemu/osdep.h" -#include "qemu/error-report.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" #include "intel_iommu_internal.h" #include "hw/pci/pci.h" -#include "hw/pci/pci_bus.h" -#include "hw/i386/pc.h" -#include "hw/boards.h" -#include "hw/i386/x86-iommu.h" -#include "hw/pci-host/q35.h" -#include "sysemu/kvm.h" /*#define DEBUG_INTEL_IOMMU*/ #ifdef DEBUG_INTEL_IOMMU enum { DEBUG_GENERAL, DEBUG_CSR, DEBUG_INV, DEBUG_MMU, DEBUG_FLOG, - DEBUG_CACHE, DEBUG_IR, + DEBUG_CACHE, }; #define VTD_DBGBIT(x) (1 << DEBUG_##x) static int vtd_dbgflags = VTD_DBGBIT(GENERAL) | VTD_DBGBIT(CSR); @@ -197,7 +190,7 @@ static void vtd_reset_context_cache(IntelIOMMUState *s) VTD_DPRINTF(CACHE, "global context_cache_gen=1"); while (g_hash_table_iter_next (&bus_it, NULL, (void**)&vtd_bus)) { - for (devfn_it = 0; devfn_it < X86_IOMMU_PCI_DEVFN_MAX; ++devfn_it) { + for (devfn_it = 0; devfn_it < VTD_PCI_DEVFN_MAX; ++devfn_it) { vtd_as = vtd_bus->dev_as[devfn_it]; if (!vtd_as) { continue; @@ -906,27 +899,6 @@ static void vtd_root_table_setup(IntelIOMMUState *s) (s->root_extended ? "(extended)" : "")); } -static void vtd_iec_notify_all(IntelIOMMUState *s, bool global, - uint32_t index, uint32_t mask) -{ - x86_iommu_iec_notify_all(X86_IOMMU_DEVICE(s), global, index, mask); -} - -static void vtd_interrupt_remap_table_setup(IntelIOMMUState *s) -{ - uint64_t value = 0; - value = vtd_get_quad_raw(s, DMAR_IRTA_REG); - s->intr_size = 1UL << ((value & VTD_IRTA_SIZE_MASK) + 1); - s->intr_root = value & VTD_IRTA_ADDR_MASK; - s->intr_eime = value & VTD_IRTA_EIME; - - /* Notify global invalidation */ - vtd_iec_notify_all(s, true, 0, 0); - - VTD_DPRINTF(CSR, "int remap table addr 0x%"PRIx64 " size %"PRIu32, - s->intr_root, s->intr_size); -} - static void vtd_context_global_invalidate(IntelIOMMUState *s) { s->context_cache_gen++; @@ -990,7 +962,7 @@ static void vtd_context_device_invalidate(IntelIOMMUState *s, vtd_bus = vtd_find_as_from_bus_num(s, VTD_SID_TO_BUS(source_id)); if (vtd_bus) { devfn = VTD_SID_TO_DEVFN(source_id); - for (devfn_it = 0; devfn_it < X86_IOMMU_PCI_DEVFN_MAX; ++devfn_it) { + for (devfn_it = 0; devfn_it < VTD_PCI_DEVFN_MAX; ++devfn_it) { vtd_as = vtd_bus->dev_as[devfn_it]; if (vtd_as && ((devfn_it & mask) == (devfn & mask))) { VTD_DPRINTF(INV, "invalidate context-cahce of devfn 0x%"PRIx16, @@ -1165,16 +1137,6 @@ static void vtd_handle_gcmd_srtp(IntelIOMMUState *s) vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_RTPS); } -/* Set Interrupt Remap Table Pointer */ -static void vtd_handle_gcmd_sirtp(IntelIOMMUState *s) -{ - VTD_DPRINTF(CSR, "set Interrupt Remap Table Pointer"); - - vtd_interrupt_remap_table_setup(s); - /* Ok - report back to driver */ - vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_IRTPS); -} - /* Handle Translation Enable/Disable */ static void vtd_handle_gcmd_te(IntelIOMMUState *s, bool en) { @@ -1194,22 +1156,6 @@ static void vtd_handle_gcmd_te(IntelIOMMUState *s, bool en) } } -/* Handle Interrupt Remap Enable/Disable */ -static void vtd_handle_gcmd_ire(IntelIOMMUState *s, bool en) -{ - VTD_DPRINTF(CSR, "Interrupt Remap Enable %s", (en ? "on" : "off")); - - if (en) { - s->intr_enabled = true; - /* Ok - report back to driver */ - vtd_set_clear_mask_long(s, DMAR_GSTS_REG, 0, VTD_GSTS_IRES); - } else { - s->intr_enabled = false; - /* Ok - report back to driver */ - vtd_set_clear_mask_long(s, DMAR_GSTS_REG, VTD_GSTS_IRES, 0); - } -} - /* Handle write to Global Command Register */ static void vtd_handle_gcmd_write(IntelIOMMUState *s) { @@ -1230,14 +1176,6 @@ static void vtd_handle_gcmd_write(IntelIOMMUState *s) /* Queued Invalidation Enable */ vtd_handle_gcmd_qie(s, val & VTD_GCMD_QIE); } - if (val & VTD_GCMD_SIRTP) { - /* Set/update the interrupt remapping root-table pointer */ - vtd_handle_gcmd_sirtp(s); - } - if (changed & VTD_GCMD_IRE) { - /* Interrupt remap enable/disable */ - vtd_handle_gcmd_ire(s, val & VTD_GCMD_IRE); - } } /* Handle write to Context Command Register */ @@ -1423,21 +1361,6 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc) return true; } -static bool vtd_process_inv_iec_desc(IntelIOMMUState *s, - VTDInvDesc *inv_desc) -{ - VTD_DPRINTF(INV, "inv ir glob %d index %d mask %d", - inv_desc->iec.granularity, - inv_desc->iec.index, - inv_desc->iec.index_mask); - - vtd_iec_notify_all(s, !inv_desc->iec.granularity, - inv_desc->iec.index, - inv_desc->iec.index_mask); - - return true; -} - static bool vtd_process_inv_desc(IntelIOMMUState *s) { VTDInvDesc inv_desc; @@ -1477,15 +1400,6 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s) } break; - case VTD_INV_DESC_IEC: - VTD_DPRINTF(INV, "Invalidation Interrupt Entry Cache " - "Descriptor hi 0x%"PRIx64 " lo 0x%"PRIx64, - inv_desc.hi, inv_desc.lo); - if (!vtd_process_inv_iec_desc(s, &inv_desc)) { - return false; - } - break; - default: VTD_DPRINTF(GENERAL, "error: unkonw Invalidation Descriptor type " "hi 0x%"PRIx64 " lo 0x%"PRIx64 " type %"PRIu8, @@ -1914,23 +1828,6 @@ static void vtd_mem_write(void *opaque, hwaddr addr, vtd_update_fsts_ppf(s); break; - case DMAR_IRTA_REG: - VTD_DPRINTF(IR, "DMAR_IRTA_REG write addr 0x%"PRIx64 - ", size %d, val 0x%"PRIx64, addr, size, val); - if (size == 4) { - vtd_set_long(s, addr, val); - } else { - vtd_set_quad(s, addr, val); - } - break; - - case DMAR_IRTA_REG_HI: - VTD_DPRINTF(IR, "DMAR_IRTA_REG_HI write addr 0x%"PRIx64 - ", size %d, val 0x%"PRIx64, addr, size, val); - assert(size == 4); - vtd_set_long(s, addr, val); - break; - default: VTD_DPRINTF(GENERAL, "error: unhandled reg write addr 0x%"PRIx64 ", size %d, val 0x%"PRIx64, addr, size, val); @@ -1974,16 +1871,6 @@ static IOMMUTLBEntry vtd_iommu_translate(MemoryRegion *iommu, hwaddr addr, return ret; } -static void vtd_iommu_notify_started(MemoryRegion *iommu) -{ - VTDAddressSpace *vtd_as = container_of(iommu, VTDAddressSpace, iommu); - - hw_error("Device at bus %s addr %02x.%d requires iommu notifier which " - "is currently not supported by intel-iommu emulation", - vtd_as->bus->qbus.name, PCI_SLOT(vtd_as->devfn), - PCI_FUNC(vtd_as->devfn)); -} - static const VMStateDescription vtd_vmstate = { .name = "iommu-intel", .unmigratable = 1, @@ -2008,295 +1895,6 @@ static Property vtd_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -/* Read IRTE entry with specific index */ -static int vtd_irte_get(IntelIOMMUState *iommu, uint16_t index, - VTD_IR_TableEntry *entry, uint16_t sid) -{ - static const uint16_t vtd_svt_mask[VTD_SQ_MAX] = \ - {0xffff, 0xfffb, 0xfff9, 0xfff8}; - dma_addr_t addr = 0x00; - uint16_t mask, source_id; - uint8_t bus, bus_max, bus_min; - - addr = iommu->intr_root + index * sizeof(*entry); - if (dma_memory_read(&address_space_memory, addr, entry, - sizeof(*entry))) { - VTD_DPRINTF(GENERAL, "error: fail to access IR root at 0x%"PRIx64 - " + %"PRIu16, iommu->intr_root, index); - return -VTD_FR_IR_ROOT_INVAL; - } - - if (!entry->irte.present) { - VTD_DPRINTF(GENERAL, "error: present flag not set in IRTE" - " entry index %u value 0x%"PRIx64 " 0x%"PRIx64, - index, le64_to_cpu(entry->data[1]), - le64_to_cpu(entry->data[0])); - return -VTD_FR_IR_ENTRY_P; - } - - if (entry->irte.__reserved_0 || entry->irte.__reserved_1 || - entry->irte.__reserved_2) { - VTD_DPRINTF(GENERAL, "error: IRTE entry index %"PRIu16 - " reserved fields non-zero: 0x%"PRIx64 " 0x%"PRIx64, - index, le64_to_cpu(entry->data[1]), - le64_to_cpu(entry->data[0])); - return -VTD_FR_IR_IRTE_RSVD; - } - - if (sid != X86_IOMMU_SID_INVALID) { - /* Validate IRTE SID */ - source_id = le32_to_cpu(entry->irte.source_id); - switch (entry->irte.sid_vtype) { - case VTD_SVT_NONE: - VTD_DPRINTF(IR, "No SID validation for IRTE index %d", index); - break; - - case VTD_SVT_ALL: - mask = vtd_svt_mask[entry->irte.sid_q]; - if ((source_id & mask) != (sid & mask)) { - VTD_DPRINTF(GENERAL, "SID validation for IRTE index " - "%d failed (reqid 0x%04x sid 0x%04x)", index, - sid, source_id); - return -VTD_FR_IR_SID_ERR; - } - break; - - case VTD_SVT_BUS: - bus_max = source_id >> 8; - bus_min = source_id & 0xff; - bus = sid >> 8; - if (bus > bus_max || bus < bus_min) { - VTD_DPRINTF(GENERAL, "SID validation for IRTE index %d " - "failed (bus %d outside %d-%d)", index, bus, - bus_min, bus_max); - return -VTD_FR_IR_SID_ERR; - } - break; - - default: - VTD_DPRINTF(GENERAL, "Invalid SVT bits (0x%x) in IRTE index " - "%d", entry->irte.sid_vtype, index); - /* Take this as verification failure. */ - return -VTD_FR_IR_SID_ERR; - break; - } - } - - return 0; -} - -/* Fetch IRQ information of specific IR index */ -static int vtd_remap_irq_get(IntelIOMMUState *iommu, uint16_t index, - VTDIrq *irq, uint16_t sid) -{ - VTD_IR_TableEntry irte = {}; - int ret = 0; - - ret = vtd_irte_get(iommu, index, &irte, sid); - if (ret) { - return ret; - } - - irq->trigger_mode = irte.irte.trigger_mode; - irq->vector = irte.irte.vector; - irq->delivery_mode = irte.irte.delivery_mode; - irq->dest = le32_to_cpu(irte.irte.dest_id); - if (!iommu->intr_eime) { -#define VTD_IR_APIC_DEST_MASK (0xff00ULL) -#define VTD_IR_APIC_DEST_SHIFT (8) - irq->dest = (irq->dest & VTD_IR_APIC_DEST_MASK) >> - VTD_IR_APIC_DEST_SHIFT; - } - irq->dest_mode = irte.irte.dest_mode; - irq->redir_hint = irte.irte.redir_hint; - - VTD_DPRINTF(IR, "remapping interrupt index %d: trig:%u,vec:%u," - "deliver:%u,dest:%u,dest_mode:%u", index, - irq->trigger_mode, irq->vector, irq->delivery_mode, - irq->dest, irq->dest_mode); - - return 0; -} - -/* Generate one MSI message from VTDIrq info */ -static void vtd_generate_msi_message(VTDIrq *irq, MSIMessage *msg_out) -{ - VTD_MSIMessage msg = {}; - - /* Generate address bits */ - msg.dest_mode = irq->dest_mode; - msg.redir_hint = irq->redir_hint; - msg.dest = irq->dest; - msg.__addr_head = cpu_to_le32(0xfee); - /* Keep this from original MSI address bits */ - msg.__not_used = irq->msi_addr_last_bits; - - /* Generate data bits */ - msg.vector = irq->vector; - msg.delivery_mode = irq->delivery_mode; - msg.level = 1; - msg.trigger_mode = irq->trigger_mode; - - msg_out->address = msg.msi_addr; - msg_out->data = msg.msi_data; -} - -/* Interrupt remapping for MSI/MSI-X entry */ -static int vtd_interrupt_remap_msi(IntelIOMMUState *iommu, - MSIMessage *origin, - MSIMessage *translated, - uint16_t sid) -{ - int ret = 0; - VTD_IR_MSIAddress addr; - uint16_t index; - VTDIrq irq = {}; - - assert(origin && translated); - - if (!iommu || !iommu->intr_enabled) { - goto do_not_translate; - } - - if (origin->address & VTD_MSI_ADDR_HI_MASK) { - VTD_DPRINTF(GENERAL, "error: MSI addr high 32 bits nonzero" - " during interrupt remapping: 0x%"PRIx32, - (uint32_t)((origin->address & VTD_MSI_ADDR_HI_MASK) >> \ - VTD_MSI_ADDR_HI_SHIFT)); - return -VTD_FR_IR_REQ_RSVD; - } - - addr.data = origin->address & VTD_MSI_ADDR_LO_MASK; - if (le16_to_cpu(addr.addr.__head) != 0xfee) { - VTD_DPRINTF(GENERAL, "error: MSI addr low 32 bits invalid: " - "0x%"PRIx32, addr.data); - return -VTD_FR_IR_REQ_RSVD; - } - - /* This is compatible mode. */ - if (addr.addr.int_mode != VTD_IR_INT_FORMAT_REMAP) { - goto do_not_translate; - } - - index = addr.addr.index_h << 15 | le16_to_cpu(addr.addr.index_l); - -#define VTD_IR_MSI_DATA_SUBHANDLE (0x0000ffff) -#define VTD_IR_MSI_DATA_RESERVED (0xffff0000) - - if (addr.addr.sub_valid) { - /* See VT-d spec 5.1.2.2 and 5.1.3 on subhandle */ - index += origin->data & VTD_IR_MSI_DATA_SUBHANDLE; - } - - ret = vtd_remap_irq_get(iommu, index, &irq, sid); - if (ret) { - return ret; - } - - if (addr.addr.sub_valid) { - VTD_DPRINTF(IR, "received MSI interrupt"); - if (origin->data & VTD_IR_MSI_DATA_RESERVED) { - VTD_DPRINTF(GENERAL, "error: MSI data bits non-zero for " - "interrupt remappable entry: 0x%"PRIx32, - origin->data); - return -VTD_FR_IR_REQ_RSVD; - } - } else { - uint8_t vector = origin->data & 0xff; - VTD_DPRINTF(IR, "received IOAPIC interrupt"); - /* IOAPIC entry vector should be aligned with IRTE vector - * (see vt-d spec 5.1.5.1). */ - if (vector != irq.vector) { - VTD_DPRINTF(GENERAL, "IOAPIC vector inconsistent: " - "entry: %d, IRTE: %d, index: %d", - vector, irq.vector, index); - } - } - - /* - * We'd better keep the last two bits, assuming that guest OS - * might modify it. Keep it does not hurt after all. - */ - irq.msi_addr_last_bits = addr.addr.__not_care; - - /* Translate VTDIrq to MSI message */ - vtd_generate_msi_message(&irq, translated); - - VTD_DPRINTF(IR, "mapping MSI 0x%"PRIx64":0x%"PRIx32 " -> " - "0x%"PRIx64":0x%"PRIx32, origin->address, origin->data, - translated->address, translated->data); - return 0; - -do_not_translate: - memcpy(translated, origin, sizeof(*origin)); - return 0; -} - -static int vtd_int_remap(X86IOMMUState *iommu, MSIMessage *src, - MSIMessage *dst, uint16_t sid) -{ - return vtd_interrupt_remap_msi(INTEL_IOMMU_DEVICE(iommu), - src, dst, sid); -} - -static MemTxResult vtd_mem_ir_read(void *opaque, hwaddr addr, - uint64_t *data, unsigned size, - MemTxAttrs attrs) -{ - return MEMTX_OK; -} - -static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size, - MemTxAttrs attrs) -{ - int ret = 0; - MSIMessage from = {}, to = {}; - uint16_t sid = X86_IOMMU_SID_INVALID; - - from.address = (uint64_t) addr + VTD_INTERRUPT_ADDR_FIRST; - from.data = (uint32_t) value; - - if (!attrs.unspecified) { - /* We have explicit Source ID */ - sid = attrs.requester_id; - } - - ret = vtd_interrupt_remap_msi(opaque, &from, &to, sid); - if (ret) { - /* TODO: report error */ - VTD_DPRINTF(GENERAL, "int remap fail for addr 0x%"PRIx64 - " data 0x%"PRIx32, from.address, from.data); - /* Drop this interrupt */ - return MEMTX_ERROR; - } - - VTD_DPRINTF(IR, "delivering MSI 0x%"PRIx64":0x%"PRIx32 - " for device sid 0x%04x", - to.address, to.data, sid); - - if (dma_memory_write(&address_space_memory, to.address, - &to.data, size)) { - VTD_DPRINTF(GENERAL, "error: fail to write 0x%"PRIx64 - " value 0x%"PRIx32, to.address, to.data); - } - - return MEMTX_OK; -} - -static const MemoryRegionOps vtd_mem_ir_ops = { - .read_with_attrs = vtd_mem_ir_read, - .write_with_attrs = vtd_mem_ir_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) { @@ -2306,8 +1904,7 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) if (!vtd_bus) { /* No corresponding free() */ - vtd_bus = g_malloc0(sizeof(VTDBus) + sizeof(VTDAddressSpace *) * \ - X86_IOMMU_PCI_DEVFN_MAX); + vtd_bus = g_malloc0(sizeof(VTDBus) + sizeof(VTDAddressSpace *) * VTD_PCI_DEVFN_MAX); vtd_bus->bus = bus; key = (uintptr_t)bus; g_hash_table_insert(s->vtd_as_by_busptr, &key, vtd_bus); @@ -2324,11 +1921,6 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) vtd_dev_as->context_cache_entry.context_cache_gen = 0; memory_region_init_iommu(&vtd_dev_as->iommu, OBJECT(s), &s->iommu_ops, "intel_iommu", UINT64_MAX); - memory_region_init_io(&vtd_dev_as->iommu_ir, OBJECT(s), - &vtd_mem_ir_ops, s, "intel_iommu_ir", - VTD_INTERRUPT_ADDR_SIZE); - 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"); } @@ -2340,15 +1932,12 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, int devfn) */ static void vtd_init(IntelIOMMUState *s) { - X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); - memset(s->csr, 0, DMAR_REG_SIZE); memset(s->wmask, 0, DMAR_REG_SIZE); memset(s->w1cmask, 0, DMAR_REG_SIZE); memset(s->womask, 0, DMAR_REG_SIZE); s->iommu_ops.translate = vtd_iommu_translate; - s->iommu_ops.notify_started = vtd_iommu_notify_started; s->root = 0; s->root_extended = false; s->dmar_enabled = false; @@ -2363,10 +1952,6 @@ static void vtd_init(IntelIOMMUState *s) VTD_CAP_SAGAW | VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS; s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO; - if (x86_iommu->intr_supported) { - s->ecap |= VTD_ECAP_IR | VTD_ECAP_EIM | VTD_ECAP_MHMV; - } - vtd_reset_context_cache(s); vtd_reset_iotlb(s); @@ -2416,11 +2001,6 @@ static void vtd_init(IntelIOMMUState *s) /* Fault Recording Registers, 128-bit */ vtd_define_quad(s, DMAR_FRCD_REG_0_0, 0, 0, 0); vtd_define_quad(s, DMAR_FRCD_REG_0_2, 0, 0, 0x8000000000000000ULL); - - /* - * Interrupt remapping registers. - */ - vtd_define_quad(s, DMAR_IRTA_REG, 0, 0xfffffffffffff80fULL, 0); } /* Should not reset address_spaces when reset because devices will still use @@ -2434,23 +2014,9 @@ static void vtd_reset(DeviceState *dev) vtd_init(s); } -static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) -{ - IntelIOMMUState *s = opaque; - VTDAddressSpace *vtd_as; - - assert(0 <= devfn && devfn <= X86_IOMMU_PCI_DEVFN_MAX); - - vtd_as = vtd_find_add_as(s, bus, devfn); - return &vtd_as->as; -} - static void vtd_realize(DeviceState *dev, Error **errp) { - PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); - PCIBus *bus = pcms->bus; IntelIOMMUState *s = INTEL_IOMMU_DEVICE(dev); - X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev); VTD_DPRINTF(GENERAL, ""); memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num)); @@ -2463,36 +2029,21 @@ static void vtd_realize(DeviceState *dev, Error **errp) s->vtd_as_by_busptr = g_hash_table_new_full(vtd_uint64_hash, vtd_uint64_equal, g_free, g_free); vtd_init(s); - sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, Q35_HOST_BRIDGE_IOMMU_ADDR); - pci_setup_iommu(bus, vtd_host_dma_iommu, dev); - /* Pseudo address space under root PCI bus. */ - pcms->ioapic_as = vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC); - - /* Currently Intel IOMMU IR only support "kernel-irqchip={off|split}" */ - if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() && - !kvm_irqchip_is_split()) { - error_report("Intel Interrupt Remapping cannot work with " - "kernel-irqchip=on, please use 'split|off'."); - exit(1); - } } static void vtd_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - X86IOMMUClass *x86_class = X86_IOMMU_CLASS(klass); dc->reset = vtd_reset; + dc->realize = vtd_realize; dc->vmsd = &vtd_vmstate; dc->props = vtd_properties; - dc->hotpluggable = false; - x86_class->realize = vtd_realize; - x86_class->int_remap = vtd_int_remap; } static const TypeInfo vtd_info = { .name = TYPE_INTEL_IOMMU_DEVICE, - .parent = TYPE_X86_IOMMU_DEVICE, + .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IntelIOMMUState), .class_init = vtd_class_init, }; diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h index 0829a5064..e5f514c6e 100644 --- a/hw/i386/intel_iommu_internal.h +++ b/hw/i386/intel_iommu_internal.h @@ -110,8 +110,6 @@ /* Interrupt Address Range */ #define VTD_INTERRUPT_ADDR_FIRST 0xfee00000ULL #define VTD_INTERRUPT_ADDR_LAST 0xfeefffffULL -#define VTD_INTERRUPT_ADDR_SIZE (VTD_INTERRUPT_ADDR_LAST - \ - VTD_INTERRUPT_ADDR_FIRST + 1) /* The shift of source_id in the key of IOTLB hash table */ #define VTD_IOTLB_SID_SHIFT 36 @@ -174,19 +172,10 @@ #define VTD_RTADDR_RTT (1ULL << 11) #define VTD_RTADDR_ADDR_MASK (VTD_HAW_MASK ^ 0xfffULL) -/* IRTA_REG */ -#define VTD_IRTA_ADDR_MASK (VTD_HAW_MASK ^ 0xfffULL) -#define VTD_IRTA_EIME (1ULL << 11) -#define VTD_IRTA_SIZE_MASK (0xfULL) - /* ECAP_REG */ /* (offset >> 4) << 8 */ #define VTD_ECAP_IRO (DMAR_IOTLB_REG_OFFSET << 4) #define VTD_ECAP_QI (1ULL << 1) -/* Interrupt Remapping support */ -#define VTD_ECAP_IR (1ULL << 3) -#define VTD_ECAP_EIM (1ULL << 4) -#define VTD_ECAP_MHMV (15ULL << 20) /* CAP_REG */ /* (offset >> 4) << 24 */ @@ -276,19 +265,6 @@ typedef enum VTDFaultReason { * context-entry. */ VTD_FR_CONTEXT_ENTRY_TT, - - /* Interrupt remapping transition faults */ - VTD_FR_IR_REQ_RSVD = 0x20, /* One or more IR request reserved - * fields set */ - VTD_FR_IR_INDEX_OVER = 0x21, /* Index value greater than max */ - VTD_FR_IR_ENTRY_P = 0x22, /* Present (P) not set in IRTE */ - VTD_FR_IR_ROOT_INVAL = 0x23, /* IR Root table invalid */ - VTD_FR_IR_IRTE_RSVD = 0x24, /* IRTE Rsvd field non-zero with - * Present flag set */ - VTD_FR_IR_REQ_COMPAT = 0x25, /* Encountered compatible IR - * request while disabled */ - VTD_FR_IR_SID_ERR = 0x26, /* Invalid Source-ID */ - /* This is not a normal fault reason. We use this to indicate some faults * that are not referenced by the VT-d specification. * Fault event with such reason should not be recorded. @@ -299,35 +275,17 @@ typedef enum VTDFaultReason { #define VTD_CONTEXT_CACHE_GEN_MAX 0xffffffffUL -/* Interrupt Entry Cache Invalidation Descriptor: VT-d 6.5.2.7. */ -struct VTDInvDescIEC { - uint32_t type:4; /* Should always be 0x4 */ - uint32_t granularity:1; /* If set, it's global IR invalidation */ - uint32_t resved_1:22; - uint32_t index_mask:5; /* 2^N for continuous int invalidation */ - uint32_t index:16; /* Start index to invalidate */ - uint32_t reserved_2:16; -}; -typedef struct VTDInvDescIEC VTDInvDescIEC; - /* Queued Invalidation Descriptor */ -union VTDInvDesc { - struct { - uint64_t lo; - uint64_t hi; - }; - union { - VTDInvDescIEC iec; - }; +struct VTDInvDesc { + uint64_t lo; + uint64_t hi; }; -typedef union VTDInvDesc VTDInvDesc; +typedef struct VTDInvDesc VTDInvDesc; /* Masks for struct 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_IEC 0x4 /* Interrupt Entry Cache - Invalidate Descriptor */ #define VTD_INV_DESC_WAIT 0x5 /* Invalidation Wait Descriptor */ #define VTD_INV_DESC_NONE 0 /* Not an Invalidate Descriptor */ diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index 2bd0de82b..3c7c8fa00 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -10,8 +10,6 @@ * See the COPYING file in the top-level directory. */ #include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" #include "hw/i386/apic_internal.h" #include "hw/pci/msi.h" #include "sysemu/kvm.h" @@ -184,24 +182,19 @@ static void kvm_apic_realize(DeviceState *dev, Error **errp) { APICCommonState *s = APIC_COMMON(dev); - memory_region_init_io(&s->io_memory, OBJECT(s), &kvm_apic_io_ops, s, - "kvm-apic-msi", APIC_SPACE_SIZE); + memory_region_init_io(&s->io_memory, NULL, &kvm_apic_io_ops, s, "kvm-apic-msi", + APIC_SPACE_SIZE); if (kvm_has_gsi_routing()) { msi_nonbroken = true; } } -static void kvm_apic_unrealize(DeviceState *dev, Error **errp) -{ -} - static void kvm_apic_class_init(ObjectClass *klass, void *data) { APICCommonClass *k = APIC_COMMON_CLASS(klass); k->realize = kvm_apic_realize; - k->unrealize = kvm_apic_unrealize; k->reset = kvm_apic_reset; k->set_base = kvm_apic_set_base; k->set_tpr = kvm_apic_set_tpr; diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 0f75dd385..a3b300cad 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -15,7 +15,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "cpu.h" #include "qemu/host-utils.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c index 521a58498..a4462e5ca 100644 --- a/hw/i386/kvm/i8254.c +++ b/hw/i386/kvm/i8254.c @@ -22,9 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - #include "qemu/osdep.h" -#include <linux/kvm.h> #include "qapi/error.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c index 8238fbc63..8abce52b7 100644 --- a/hw/i386/kvm/pci-assign.c +++ b/hw/i386/kvm/pci-assign.c @@ -20,10 +20,9 @@ * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) */ - #include "qemu/osdep.h" -#include <linux/kvm.h> #include "qapi/error.h" +#include <sys/mman.h> #include "hw/hw.h" #include "hw/i386/pc.h" #include "qemu/error-report.h" @@ -37,6 +36,8 @@ #include "kvm_i386.h" #include "hw/pci/pci-assign.h" +#define MSIX_PAGE_SIZE 0x1000 + /* From linux/ioport.h */ #define IORESOURCE_IO 0x00000100 /* Resource type */ #define IORESOURCE_MEM 0x00000200 @@ -121,7 +122,6 @@ typedef struct AssignedDevice { int *msi_virq; MSIXTableEntry *msix_table; hwaddr msix_table_addr; - uint16_t msix_table_size; uint16_t msix_max; MemoryRegion mmio; char *configfd_name; @@ -974,9 +974,10 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev) } if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) { + MSIMessage msg = msi_get_message(pci_dev, 0); int virq; - virq = kvm_irqchip_add_msi_route(kvm_state, 0, pci_dev); + virq = kvm_irqchip_add_msi_route(kvm_state, msg, pci_dev); if (virq < 0) { perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route"); return; @@ -1015,7 +1016,6 @@ static void assigned_dev_update_msi_msg(PCIDevice *pci_dev) kvm_irqchip_update_msi_route(kvm_state, assigned_dev->msi_virq[0], msi_get_message(pci_dev, 0), pci_dev); - kvm_irqchip_commit_routes(kvm_state); } static bool assigned_dev_msix_masked(MSIXTableEntry *entry) @@ -1042,6 +1042,7 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev) uint16_t entries_nr = 0; int i, r = 0; MSIXTableEntry *entry = adev->msix_table; + MSIMessage msg; /* Get the usable entry number for allocating */ for (i = 0; i < adev->msix_max; i++, entry++) { @@ -1078,7 +1079,9 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev) continue; } - r = kvm_irqchip_add_msi_route(kvm_state, i, pci_dev); + msg.address = entry->addr_lo | ((uint64_t)entry->addr_hi << 32); + msg.data = entry->data; + r = kvm_irqchip_add_msi_route(kvm_state, msg, pci_dev); if (r < 0) { return r; } @@ -1307,7 +1310,6 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK; msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK; dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry; - dev->msix_table_size = msix_max * sizeof(MSIXTableEntry); dev->msix_max = msix_max; } @@ -1479,7 +1481,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp) * error bits, leave the rest. */ status = pci_get_long(pci_dev->config + pos + PCI_X_STATUS); status &= ~(PCI_X_STATUS_BUS | PCI_X_STATUS_DEVFN); - status |= pci_get_bdf(pci_dev); + status |= pci_requester_id(pci_dev); status &= ~(PCI_X_STATUS_SPL_DISC | PCI_X_STATUS_UNX_SPL | PCI_X_STATUS_SPL_ERR); pci_set_long(pci_dev->config + pos + PCI_X_STATUS, status); @@ -1603,7 +1605,6 @@ static void assigned_dev_msix_mmio_write(void *opaque, hwaddr addr, if (ret) { error_report("Error updating irq routing entry (%d)", ret); } - kvm_irqchip_commit_routes(kvm_state); } } } @@ -1632,7 +1633,7 @@ static void assigned_dev_msix_reset(AssignedDevice *dev) return; } - memset(dev->msix_table, 0, dev->msix_table_size); + memset(dev->msix_table, 0, MSIX_PAGE_SIZE); for (i = 0, entry = dev->msix_table; i < dev->msix_max; i++, entry++) { entry->ctrl = cpu_to_le32(0x1); /* Masked */ @@ -1641,8 +1642,8 @@ static void assigned_dev_msix_reset(AssignedDevice *dev) static void assigned_dev_register_msix_mmio(AssignedDevice *dev, Error **errp) { - dev->msix_table = mmap(NULL, dev->msix_table_size, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + dev->msix_table = mmap(NULL, MSIX_PAGE_SIZE, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); if (dev->msix_table == MAP_FAILED) { error_setg_errno(errp, errno, "failed to allocate msix_table"); dev->msix_table = NULL; @@ -1652,7 +1653,7 @@ static void assigned_dev_register_msix_mmio(AssignedDevice *dev, Error **errp) assigned_dev_msix_reset(dev); memory_region_init_io(&dev->mmio, OBJECT(dev), &assigned_dev_msix_mmio_ops, - dev, "assigned-dev-msix", dev->msix_table_size); + dev, "assigned-dev-msix", MSIX_PAGE_SIZE); } static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev) @@ -1661,7 +1662,7 @@ static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev) return; } - if (munmap(dev->msix_table, dev->msix_table_size) == -1) { + if (munmap(dev->msix_table, MSIX_PAGE_SIZE) == -1) { error_report("error unmapping msix_table! %s", strerror(errno)); } dev->msix_table = NULL; diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c index 3bf1ddd97..ff1e31a4d 100644 --- a/hw/i386/kvmvapic.c +++ b/hw/i386/kvmvapic.c @@ -9,9 +9,6 @@ * top-level directory. */ #include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" -#include "exec/exec-all.h" #include "sysemu/sysemu.h" #include "sysemu/cpus.h" #include "sysemu/kvm.h" @@ -400,7 +397,7 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip) uint32_t imm32 = 0; target_ulong current_pc = 0; target_ulong current_cs_base = 0; - uint32_t current_flags = 0; + int current_flags = 0; if (smp_cpus == 1) { handlers = &s->rom_state.up; @@ -449,8 +446,9 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip) resume_all_vcpus(); if (!kvm_enabled()) { + cs->current_tb = NULL; tb_gen_code(cs, current_pc, current_cs_base, current_flags, 1); - cpu_loop_exit_noexc(cs); + cpu_resume_from_signal(cs, NULL); } } diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 022dd1b20..99437e0b7 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -67,7 +67,6 @@ #include "qapi/visitor.h" #include "qapi-visit.h" #include "qom/cpu.h" -#include "hw/nmi.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -381,7 +380,7 @@ ISADevice *pc_find_fdc0(void) error_report("warning: multiple floppy disk controllers with " "iobase=0x3f0 have been found"); error_printf("the one being picked for CMOS setup might not reflect " - "your intent\n"); + "your intent"); } return state.floppy; @@ -471,6 +470,9 @@ void pc_cmos_init(PCMachineState *pcms, rtc_set_memory(s, 0x5c, val >> 8); rtc_set_memory(s, 0x5d, val >> 16); + /* set the number of CPU */ + rtc_set_memory(s, 0x5f, smp_cpus - 1); + object_property_add_link(OBJECT(pcms), "rtc_state", TYPE_ISA_DEVICE, (Object **)&pcms->rtc, @@ -502,7 +504,7 @@ typedef struct Port92State { MemoryRegion io; uint8_t outport; - qemu_irq a20_out; + qemu_irq *a20_out; } Port92State; static void port92_write(void *opaque, hwaddr addr, uint64_t val, @@ -513,7 +515,7 @@ static void port92_write(void *opaque, hwaddr addr, uint64_t val, DPRINTF("port92: write 0x%02" PRIx64 "\n", val); s->outport = val; - qemu_set_irq(s->a20_out, (val >> 1) & 1); + qemu_set_irq(*s->a20_out, (val >> 1) & 1); if ((val & 1) && !(oldval & 1)) { qemu_system_reset_request(); } @@ -532,7 +534,9 @@ static uint64_t port92_read(void *opaque, hwaddr addr, static void port92_init(ISADevice *dev, qemu_irq *a20_out) { - qdev_connect_gpio_out_named(DEVICE(dev), PORT92_A20_LINE, 0, *a20_out); + Port92State *s = PORT92(dev); + + s->a20_out = a20_out; } static const VMStateDescription vmstate_port92_isa = { @@ -569,8 +573,6 @@ static void port92_initfn(Object *obj) memory_region_init_io(&s->io, OBJECT(s), &port92_ops, s, "port92", 1); s->outport = 0; - - qdev_init_gpio_out_named(DEVICE(obj), &s->a20_out, PORT92_A20_LINE, 1); } static void port92_realizefn(DeviceState *dev, Error **errp) @@ -762,6 +764,8 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PCMachineState *pcms) acpi_tables, acpi_tables_len); fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override()); + pc_build_smbios(fw_cfg); + fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, &e820_reserve, sizeof(e820_reserve)); fw_cfg_add_file(fw_cfg, "etc/e820", e820_table, @@ -809,26 +813,11 @@ static long get_file_size(FILE *f) return size; } -/* setup_data types */ -#define SETUP_NONE 0 -#define SETUP_E820_EXT 1 -#define SETUP_DTB 2 -#define SETUP_PCI 3 -#define SETUP_EFI 4 - -struct setup_data { - uint64_t next; - uint32_t type; - uint32_t len; - uint8_t data[0]; -} __attribute__((packed)); - static void load_linux(PCMachineState *pcms, FWCfgState *fw_cfg) { uint16_t protocol; int setup_size, kernel_size, initrd_size = 0, cmdline_size; - int dtb_size, setup_data_offset; uint32_t initrd_max; uint8_t header[8192], *setup, *kernel, *initrd_data; hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0; @@ -836,10 +825,8 @@ static void load_linux(PCMachineState *pcms, char *vmode; MachineState *machine = MACHINE(pcms); PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms); - struct setup_data *setup_data; const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; - const char *dtb_filename = machine->dtb; const char *kernel_cmdline = machine->kernel_cmdline; /* Align to 16 bytes as a paranoia measure */ @@ -1002,35 +989,6 @@ static void load_linux(PCMachineState *pcms, exit(1); } fclose(f); - - /* append dtb to kernel */ - if (dtb_filename) { - if (protocol < 0x209) { - fprintf(stderr, "qemu: Linux kernel too old to load a dtb\n"); - exit(1); - } - - dtb_size = get_image_size(dtb_filename); - if (dtb_size <= 0) { - fprintf(stderr, "qemu: error reading dtb %s: %s\n", - dtb_filename, strerror(errno)); - exit(1); - } - - setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); - kernel_size = setup_data_offset + sizeof(struct setup_data) + dtb_size; - kernel = g_realloc(kernel, kernel_size); - - stq_p(header+0x250, prot_addr + setup_data_offset); - - setup_data = (struct setup_data *)(kernel + setup_data_offset); - setup_data->next = 0; - setup_data->type = cpu_to_le32(SETUP_DTB); - setup_data->len = cpu_to_le32(dtb_size); - - load_image_size(dtb_filename, setup_data->data, dtb_size); - } - memcpy(setup, header, MIN(sizeof(header), setup_size)); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); @@ -1041,13 +999,8 @@ static void load_linux(PCMachineState *pcms, fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size); fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size); - if (fw_cfg_dma_enabled(fw_cfg)) { - option_rom[nb_option_roms].name = "linuxboot_dma.bin"; - option_rom[nb_option_roms].bootindex = 0; - } else { - option_rom[nb_option_roms].name = "linuxboot.bin"; - option_rom[nb_option_roms].bootindex = 0; - } + option_rom[nb_option_roms].name = "linuxboot.bin"; + option_rom[nb_option_roms].bootindex = 0; nb_option_roms++; } @@ -1087,28 +1040,21 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) } } -static int pc_present_cpus_count(PCMachineState *pcms) -{ - int i, boot_cpus = 0; - for (i = 0; i < pcms->possible_cpus->len; i++) { - if (pcms->possible_cpus->cpus[i].cpu) { - boot_cpus++; - } - } - return boot_cpus; -} - -static X86CPU *pc_new_cpu(const char *typename, int64_t apic_id, +static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id, Error **errp) { X86CPU *cpu = NULL; Error *local_err = NULL; - cpu = X86_CPU(object_new(typename)); + cpu = cpu_x86_create(cpu_model, &local_err); + if (local_err != NULL) { + goto out; + } object_property_set_int(OBJECT(cpu), apic_id, "apic-id", &local_err); object_property_set_bool(OBJECT(cpu), true, "realized", &local_err); +out: if (local_err) { error_propagate(errp, local_err); object_unref(OBJECT(cpu)); @@ -1120,8 +1066,7 @@ static X86CPU *pc_new_cpu(const char *typename, int64_t apic_id, void pc_hot_add_cpu(const int64_t id, Error **errp) { X86CPU *cpu; - ObjectClass *oc; - PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); + MachineState *machine = MACHINE(qdev_get_machine()); int64_t apic_id = x86_cpu_apic_id_from_index(id); Error *local_err = NULL; @@ -1130,6 +1075,18 @@ void pc_hot_add_cpu(const int64_t id, Error **errp) return; } + if (cpu_exists(apic_id)) { + error_setg(errp, "Unable to add CPU: %" PRIi64 + ", it already exists", id); + return; + } + + if (id >= max_cpus) { + error_setg(errp, "Unable to add CPU: %" PRIi64 + ", max allowed: %d", id, max_cpus - 1); + return; + } + if (apic_id >= ACPI_CPU_HOTPLUG_ID_LIMIT) { error_setg(errp, "Unable to add CPU: %" PRIi64 ", resulting APIC ID (%" PRIi64 ") is too large", @@ -1137,9 +1094,7 @@ void pc_hot_add_cpu(const int64_t id, Error **errp) return; } - assert(pcms->possible_cpus->cpus[0].cpu); /* BSP is always present */ - oc = OBJECT_CLASS(CPU_GET_CLASS(pcms->possible_cpus->cpus[0].cpu)); - cpu = pc_new_cpu(object_class_get_name(oc), apic_id, &local_err); + cpu = pc_new_cpu(machine->cpu_model, apic_id, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -1150,10 +1105,6 @@ void pc_hot_add_cpu(const int64_t id, Error **errp) void pc_cpus_init(PCMachineState *pcms) { int i; - CPUClass *cc; - ObjectClass *oc; - const char *typename; - gchar **model_pieces; X86CPU *cpu = NULL; MachineState *machine = MACHINE(pcms); @@ -1166,22 +1117,6 @@ void pc_cpus_init(PCMachineState *pcms) #endif } - model_pieces = g_strsplit(machine->cpu_model, ",", 2); - if (!model_pieces[0]) { - error_report("Invalid/empty CPU model name"); - exit(1); - } - - oc = cpu_class_by_name(TYPE_X86_CPU, model_pieces[0]); - if (oc == NULL) { - error_report("Unable to find CPU definition: %s", model_pieces[0]); - exit(1); - } - typename = object_class_get_name(oc); - cc = CPU_CLASS(oc); - cc->parse_features(typename, model_pieces[1], &error_fatal); - g_strfreev(model_pieces); - /* Calculates the limit to CPU APIC ID values * * Limit for the APIC ID value, so that all @@ -1202,8 +1137,9 @@ void pc_cpus_init(PCMachineState *pcms) pcms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(i); pcms->possible_cpus->len++; if (i < smp_cpus) { - cpu = pc_new_cpu(typename, x86_cpu_apic_id_from_index(i), + cpu = pc_new_cpu(machine->cpu_model, x86_cpu_apic_id_from_index(i), &error_fatal); + pcms->possible_cpus->cpus[i].cpu = CPU(cpu); object_unref(OBJECT(cpu)); } } @@ -1212,33 +1148,13 @@ void pc_cpus_init(PCMachineState *pcms) smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]); } -static void pc_build_feature_control_file(PCMachineState *pcms) -{ - X86CPU *cpu = X86_CPU(pcms->possible_cpus->cpus[0].cpu); - CPUX86State *env = &cpu->env; - uint32_t unused, ecx, edx; - uint64_t feature_control_bits = 0; - uint64_t *val; - - cpu_x86_cpuid(env, 1, 0, &unused, &unused, &ecx, &edx); - if (ecx & CPUID_EXT_VMX) { - feature_control_bits |= FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; - } - - if ((edx & (CPUID_EXT2_MCE | CPUID_EXT2_MCA)) == - (CPUID_EXT2_MCE | CPUID_EXT2_MCA) && - (env->mcg_cap & MCG_LMCE_P)) { - feature_control_bits |= FEATURE_CONTROL_LMCE; - } - - if (!feature_control_bits) { - return; - } - - val = g_malloc(sizeof(*val)); - *val = cpu_to_le64(feature_control_bits | FEATURE_CONTROL_LOCKED); - fw_cfg_add_file(pcms->fw_cfg, "etc/msr_feature_control", val, sizeof(*val)); -} +/* pci-info ROM file. Little endian format */ +typedef struct PcRomPciInfo { + uint64_t w32_min; + uint64_t w32_max; + uint64_t w64_min; + uint64_t w64_max; +} PcRomPciInfo; static void pc_machine_done(Notifier *notifier, void *data) @@ -1247,9 +1163,6 @@ void pc_machine_done(Notifier *notifier, void *data) PCMachineState, machine_done); PCIBus *bus = pcms->bus; - /* set the number of CPUs */ - rtc_set_memory(pcms->rtc, 0x5f, pc_present_cpus_count(pcms) - 1); - if (bus) { int extra_hosts = 0; @@ -1268,15 +1181,11 @@ void pc_machine_done(Notifier *notifier, void *data) } acpi_setup(); - if (pcms->fw_cfg) { - pc_build_smbios(pcms->fw_cfg); - pc_build_feature_control_file(pcms); - } } void pc_guest_info_init(PCMachineState *pcms) { - int i; + int i, j; pcms->apic_xrupt_override = kvm_allows_irq0_override(); pcms->numa_nodes = nb_numa_nodes; @@ -1286,6 +1195,20 @@ void pc_guest_info_init(PCMachineState *pcms) pcms->node_mem[i] = numa_info[i].node_mem; } + pcms->node_cpu = g_malloc0(pcms->apic_id_limit * + sizeof *pcms->node_cpu); + + for (i = 0; i < max_cpus; i++) { + unsigned int apic_id = x86_cpu_apic_id_from_index(i); + assert(apic_id < pcms->apic_id_limit); + for (j = 0; j < nb_numa_nodes; j++) { + if (test_bit(i, numa_info[j].node_cpu)) { + pcms->node_cpu[apic_id] = j; + break; + } + } + } + pcms->machine_done.notify = pc_machine_done; qemu_add_machine_init_done_notifier(&pcms->machine_done); } @@ -1340,7 +1263,6 @@ void xen_load_linux(PCMachineState *pcms) load_linux(pcms, fw_cfg); for (i = 0; i < nb_option_roms; i++) { assert(!strcmp(option_rom[i].name, "linuxboot.bin") || - !strcmp(option_rom[i].name, "linuxboot_dma.bin") || !strcmp(option_rom[i].name, "multiboot.bin")); rom_add_option(option_rom[i].name, option_rom[i].bootindex); } @@ -1473,9 +1395,6 @@ void pc_memory_init(PCMachineState *pcms, rom_add_option(option_rom[i].name, option_rom[i].bootindex); } pcms->fw_cfg = fw_cfg; - - /* Init default IOAPIC address space */ - pcms->ioapic_as = &address_space_memory; } qemu_irq pc_allocate_cpu_irq(void) @@ -1757,204 +1676,44 @@ static int pc_apic_cmp(const void *a, const void *b) return apic_a->arch_id - apic_b->arch_id; } -/* returns pointer to CPUArchId descriptor that matches CPU's apic_id - * in pcms->possible_cpus->cpus, if pcms->possible_cpus->cpus has no - * entry correponding to CPU's apic_id returns NULL. - */ -static CPUArchId *pc_find_cpu_slot(PCMachineState *pcms, CPUState *cpu, - int *idx) -{ - CPUClass *cc = CPU_GET_CLASS(cpu); - CPUArchId apic_id, *found_cpu; - - apic_id.arch_id = cc->get_arch_id(CPU(cpu)); - found_cpu = bsearch(&apic_id, pcms->possible_cpus->cpus, - pcms->possible_cpus->len, sizeof(*pcms->possible_cpus->cpus), - pc_apic_cmp); - if (found_cpu && idx) { - *idx = found_cpu - pcms->possible_cpus->cpus; - } - return found_cpu; -} - static void pc_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - CPUArchId *found_cpu; - HotplugHandlerClass *hhc; - Error *local_err = NULL; - PCMachineState *pcms = PC_MACHINE(hotplug_dev); - - if (pcms->acpi_dev) { - hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev); - hhc->plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); - if (local_err) { - goto out; - } - } - - if (dev->hotplugged) { - /* increment the number of CPUs */ - rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) + 1); - } - - found_cpu = pc_find_cpu_slot(pcms, CPU(dev), NULL); - found_cpu->cpu = CPU(dev); -out: - error_propagate(errp, local_err); -} -static void pc_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - int idx = -1; + CPUClass *cc = CPU_GET_CLASS(dev); + CPUArchId apic_id, *found_cpu; HotplugHandlerClass *hhc; Error *local_err = NULL; PCMachineState *pcms = PC_MACHINE(hotplug_dev); - pc_find_cpu_slot(pcms, CPU(dev), &idx); - assert(idx != -1); - if (idx == 0) { - error_setg(&local_err, "Boot CPU is unpluggable"); + if (!dev->hotplugged) { goto out; } - hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev); - hhc->unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); - - if (local_err) { + if (!pcms->acpi_dev) { + error_setg(&local_err, + "cpu hotplug is not enabled: missing acpi device"); goto out; } - out: - error_propagate(errp, local_err); - -} - -static void pc_cpu_unplug_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - CPUArchId *found_cpu; - HotplugHandlerClass *hhc; - Error *local_err = NULL; - PCMachineState *pcms = PC_MACHINE(hotplug_dev); - hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev); - hhc->unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); - + hhc->plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err); if (local_err) { goto out; } - found_cpu = pc_find_cpu_slot(pcms, CPU(dev), NULL); - found_cpu->cpu = NULL; - object_unparent(OBJECT(dev)); + /* increment the number of CPUs */ + rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) + 1); - rtc_set_memory(pcms->rtc, 0x5f, rtc_get_memory(pcms->rtc, 0x5f) - 1); - out: + apic_id.arch_id = cc->get_arch_id(CPU(dev)); + found_cpu = bsearch(&apic_id, pcms->possible_cpus->cpus, + pcms->possible_cpus->len, sizeof(*pcms->possible_cpus->cpus), + pc_apic_cmp); + assert(found_cpu); + found_cpu->cpu = CPU(dev); +out: error_propagate(errp, local_err); } -static void pc_cpu_pre_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - int idx; - CPUState *cs; - CPUArchId *cpu_slot; - X86CPUTopoInfo topo; - X86CPU *cpu = X86_CPU(dev); - PCMachineState *pcms = PC_MACHINE(hotplug_dev); - - /* if APIC ID is not set, set it based on socket/core/thread properties */ - if (cpu->apic_id == UNASSIGNED_APIC_ID) { - int max_socket = (max_cpus - 1) / smp_threads / smp_cores; - - if (cpu->socket_id < 0) { - error_setg(errp, "CPU socket-id is not set"); - return; - } else if (cpu->socket_id > max_socket) { - error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u", - cpu->socket_id, max_socket); - return; - } - if (cpu->core_id < 0) { - error_setg(errp, "CPU core-id is not set"); - return; - } else if (cpu->core_id > (smp_cores - 1)) { - error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u", - cpu->core_id, smp_cores - 1); - return; - } - if (cpu->thread_id < 0) { - error_setg(errp, "CPU thread-id is not set"); - return; - } else if (cpu->thread_id > (smp_threads - 1)) { - error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u", - cpu->thread_id, smp_threads - 1); - return; - } - - topo.pkg_id = cpu->socket_id; - topo.core_id = cpu->core_id; - topo.smt_id = cpu->thread_id; - cpu->apic_id = apicid_from_topo_ids(smp_cores, smp_threads, &topo); - } - - cpu_slot = pc_find_cpu_slot(pcms, CPU(dev), &idx); - if (!cpu_slot) { - x86_topo_ids_from_apicid(cpu->apic_id, smp_cores, smp_threads, &topo); - error_setg(errp, "Invalid CPU [socket: %u, core: %u, thread: %u] with" - " APIC ID %" PRIu32 ", valid index range 0:%d", - topo.pkg_id, topo.core_id, topo.smt_id, cpu->apic_id, - pcms->possible_cpus->len - 1); - return; - } - - if (cpu_slot->cpu) { - error_setg(errp, "CPU[%d] with APIC ID %" PRIu32 " exists", - idx, cpu->apic_id); - return; - } - - /* if 'address' properties socket-id/core-id/thread-id are not set, set them - * so that query_hotpluggable_cpus would show correct values - */ - /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizefn() - * once -smp refactoring is complete and there will be CPU private - * CPUState::nr_cores and CPUState::nr_threads fields instead of globals */ - x86_topo_ids_from_apicid(cpu->apic_id, smp_cores, smp_threads, &topo); - if (cpu->socket_id != -1 && cpu->socket_id != topo.pkg_id) { - error_setg(errp, "property socket-id: %u doesn't match set apic-id:" - " 0x%x (socket-id: %u)", cpu->socket_id, cpu->apic_id, topo.pkg_id); - return; - } - cpu->socket_id = topo.pkg_id; - - if (cpu->core_id != -1 && cpu->core_id != topo.core_id) { - error_setg(errp, "property core-id: %u doesn't match set apic-id:" - " 0x%x (core-id: %u)", cpu->core_id, cpu->apic_id, topo.core_id); - return; - } - cpu->core_id = topo.core_id; - - if (cpu->thread_id != -1 && cpu->thread_id != topo.smt_id) { - error_setg(errp, "property thread-id: %u doesn't match set apic-id:" - " 0x%x (thread-id: %u)", cpu->thread_id, cpu->apic_id, topo.smt_id); - return; - } - cpu->thread_id = topo.smt_id; - - cs = CPU(cpu); - cs->cpu_index = idx; -} - -static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - pc_cpu_pre_plug(hotplug_dev, dev, errp); - } -} - static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -1970,8 +1729,6 @@ static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev, { if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { pc_dimm_unplug_request(hotplug_dev, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - pc_cpu_unplug_request_cb(hotplug_dev, dev, errp); } else { error_setg(errp, "acpi: device unplug request for not supported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -1983,8 +1740,6 @@ static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev, { if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { pc_dimm_unplug(hotplug_dev, dev, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - pc_cpu_unplug_cb(hotplug_dev, dev, errp); } else { error_setg(errp, "acpi: device unplug for not supported device" " type: %s", object_get_typename(OBJECT(dev))); @@ -2137,7 +1892,7 @@ static void pc_machine_initfn(Object *obj) pc_machine_get_hotplug_memory_region_size, NULL, NULL, NULL, &error_abort); - pcms->max_ram_below_4g = 0; /* use default */ + pcms->max_ram_below_4g = 1ULL << 32; /* 4G */ object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size", pc_machine_get_max_ram_below_4g, pc_machine_set_max_ram_below_4g, @@ -2208,72 +1963,11 @@ static CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *machine) return list; } -static HotpluggableCPUList *pc_query_hotpluggable_cpus(MachineState *machine) -{ - int i; - CPUState *cpu; - HotpluggableCPUList *head = NULL; - PCMachineState *pcms = PC_MACHINE(machine); - const char *cpu_type; - - cpu = pcms->possible_cpus->cpus[0].cpu; - assert(cpu); /* BSP is always present */ - cpu_type = object_class_get_name(OBJECT_CLASS(CPU_GET_CLASS(cpu))); - - for (i = 0; i < pcms->possible_cpus->len; i++) { - X86CPUTopoInfo topo; - HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1); - HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1); - CpuInstanceProperties *cpu_props = g_new0(typeof(*cpu_props), 1); - const uint32_t apic_id = pcms->possible_cpus->cpus[i].arch_id; - - x86_topo_ids_from_apicid(apic_id, smp_cores, smp_threads, &topo); - - cpu_item->type = g_strdup(cpu_type); - cpu_item->vcpus_count = 1; - cpu_props->has_socket_id = true; - cpu_props->socket_id = topo.pkg_id; - cpu_props->has_core_id = true; - cpu_props->core_id = topo.core_id; - cpu_props->has_thread_id = true; - cpu_props->thread_id = topo.smt_id; - cpu_item->props = cpu_props; - - cpu = pcms->possible_cpus->cpus[i].cpu; - if (cpu) { - cpu_item->has_qom_path = true; - cpu_item->qom_path = object_get_canonical_path(OBJECT(cpu)); - } - - list_item->value = cpu_item; - list_item->next = head; - head = list_item; - } - return head; -} - -static void x86_nmi(NMIState *n, int cpu_index, Error **errp) -{ - /* cpu index isn't used */ - CPUState *cs; - - CPU_FOREACH(cs) { - X86CPU *cpu = X86_CPU(cs); - - if (!cpu->apic_state) { - cpu_interrupt(cs, CPU_INTERRUPT_NMI); - } else { - apic_deliver_nmi(cpu->apic_state); - } - } -} - static void pc_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); PCMachineClass *pcmc = PC_MACHINE_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); - NMIClass *nc = NMI_CLASS(oc); pcmc->get_hotplug_handler = mc->get_hotplug_handler; pcmc->pci_enabled = true; @@ -2292,16 +1986,13 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) mc->get_hotplug_handler = pc_get_hotpug_handler; mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id; mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids; - mc->query_hotpluggable_cpus = pc_query_hotpluggable_cpus; mc->default_boot_order = "cad"; mc->hot_add_cpu = pc_hot_add_cpu; mc->max_cpus = 255; mc->reset = pc_machine_reset; - hc->pre_plug = pc_machine_device_pre_plug_cb; hc->plug = pc_machine_device_plug_cb; hc->unplug_request = pc_machine_device_unplug_request_cb; hc->unplug = pc_machine_device_unplug_cb; - nc->nmi_monitor_handler = x86_nmi; } static const TypeInfo pc_machine_info = { @@ -2314,7 +2005,6 @@ static const TypeInfo pc_machine_info = { .class_init = pc_machine_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, - { TYPE_NMI }, { } }, }; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index a07dc816b..7f50116bc 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -23,6 +23,7 @@ */ #include "qemu/osdep.h" +#include <glib.h> #include "hw/hw.h" #include "hw/loader.h" @@ -86,65 +87,42 @@ static void pc_init1(MachineState *machine, MemoryRegion *rom_memory; ram_addr_t lowmem; - /* - * Calculate ram split, for memory below and above 4G. It's a bit - * complicated for backward compatibility reasons ... - * - * - Traditional split is 3.5G (lowmem = 0xe0000000). This is the - * default value for max_ram_below_4g now. - * - * - Then, to gigabyte align the memory, we move the split to 3G - * (lowmem = 0xc0000000). But only in case we have to split in - * the first place, i.e. ram_size is larger than (traditional) - * lowmem. And for new machine types (gigabyte_align = true) - * only, for live migration compatibility reasons. - * - * - Next the max-ram-below-4g option was added, which allowed to - * reduce lowmem to a smaller value, to allow a larger PCI I/O - * window below 4G. qemu doesn't enforce gigabyte alignment here, - * but prints a warning. - * - * - Finally max-ram-below-4g got updated to also allow raising lowmem, - * so legacy non-PAE guests can get as much memory as possible in - * the 32bit address space below 4G. - * - * - Note that Xen has its own ram setp code in xen_ram_init(), - * called via xen_hvm_init(). - * - * Examples: - * qemu -M pc-1.7 -m 4G (old default) -> 3584M low, 512M high - * qemu -M pc -m 4G (new default) -> 3072M low, 1024M high - * qemu -M pc,max-ram-below-4g=2G -m 4G -> 2048M low, 2048M high - * qemu -M pc,max-ram-below-4g=4G -m 3968M -> 3968M low (=4G-128M) + /* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory). + * If it doesn't, we need to split it in chunks below and above 4G. + * In any case, try to make sure that guest addresses aligned at + * 1G boundaries get mapped to host addresses aligned at 1G boundaries. + * For old machine types, use whatever split we used historically to avoid + * breaking migration. */ - if (xen_enabled()) { - xen_hvm_init(pcms, &ram_memory); + if (machine->ram_size >= 0xe0000000) { + lowmem = pcmc->gigabyte_align ? 0xc0000000 : 0xe0000000; } else { - if (!pcms->max_ram_below_4g) { - pcms->max_ram_below_4g = 0xe0000000; /* default: 3.5G */ - } + lowmem = 0xe0000000; + } + + /* Handle the machine opt max-ram-below-4g. It is basically doing + * min(qemu limit, user limit). + */ + if (lowmem > pcms->max_ram_below_4g) { lowmem = pcms->max_ram_below_4g; - if (machine->ram_size >= pcms->max_ram_below_4g) { - if (pcmc->gigabyte_align) { - if (lowmem > 0xc0000000) { - lowmem = 0xc0000000; - } - if (lowmem & ((1ULL << 30) - 1)) { - error_report("Warning: Large machine and max_ram_below_4g " - "(%" PRIu64 ") not a multiple of 1G; " - "possible bad performance.", - pcms->max_ram_below_4g); - } - } + if (machine->ram_size - lowmem > lowmem && + lowmem & ((1ULL << 30) - 1)) { + error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64 + ") not a multiple of 1G; possible bad performance.", + pcms->max_ram_below_4g); } + } - if (machine->ram_size >= lowmem) { - pcms->above_4g_mem_size = machine->ram_size - lowmem; - pcms->below_4g_mem_size = lowmem; - } else { - pcms->above_4g_mem_size = 0; - pcms->below_4g_mem_size = machine->ram_size; - } + if (machine->ram_size >= lowmem) { + pcms->above_4g_mem_size = machine->ram_size - lowmem; + pcms->below_4g_mem_size = lowmem; + } else { + pcms->above_4g_mem_size = 0; + pcms->below_4g_mem_size = machine->ram_size; + } + + if (xen_enabled()) { + xen_hvm_init(pcms, &ram_memory); } pc_cpus_init(pcms); @@ -268,7 +246,7 @@ static void pc_init1(MachineState *machine, pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); - if (pcmc->pci_enabled && machine_usb(machine)) { + if (pcmc->pci_enabled && usb_enabled()) { pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); } @@ -438,27 +416,13 @@ static void pc_i440fx_machine_options(MachineClass *m) m->default_display = "std"; } -static void pc_i440fx_2_7_machine_options(MachineClass *m) +static void pc_i440fx_2_6_machine_options(MachineClass *m) { pc_i440fx_machine_options(m); m->alias = "pc"; m->is_default = 1; } -DEFINE_I440FX_MACHINE(v2_7, "pc-i440fx-2.7", NULL, - pc_i440fx_2_7_machine_options); - - -static void pc_i440fx_2_6_machine_options(MachineClass *m) -{ - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pc_i440fx_2_7_machine_options(m); - m->is_default = 0; - m->alias = NULL; - pcmc->legacy_cpu_hotplug = true; - SET_MACHINE_COMPAT(m, PC_COMPAT_2_6); -} - DEFINE_I440FX_MACHINE(v2_6, "pc-i440fx-2.6", NULL, pc_i440fx_2_6_machine_options); @@ -467,6 +431,8 @@ static void pc_i440fx_2_5_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_2_6_machine_options(m); + m->alias = NULL; + m->is_default = 0; pcmc->save_tsc_khz = false; m->legacy_fw_cfg_order = 1; SET_MACHINE_COMPAT(m, PC_COMPAT_2_5); @@ -616,7 +582,7 @@ DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4, #define PC_COMPAT_1_3 \ - PC_CPU_MODEL_IDS("1.3.0") \ + PC_COMPAT_1_4 \ {\ .driver = "usb-tablet",\ .property = "usb_version",\ @@ -648,7 +614,7 @@ DEFINE_I440FX_MACHINE(v1_3, "pc-1.3", pc_compat_1_3, #define PC_COMPAT_1_2 \ - PC_CPU_MODEL_IDS("1.2.0") \ + PC_COMPAT_1_3 \ {\ .driver = "nec-usb-xhci",\ .property = "msi",\ @@ -687,7 +653,7 @@ DEFINE_I440FX_MACHINE(v1_2, "pc-1.2", pc_compat_1_2, #define PC_COMPAT_1_1 \ - PC_CPU_MODEL_IDS("1.1.0") \ + PC_COMPAT_1_2 \ {\ .driver = "virtio-scsi-pci",\ .property = "hotplug",\ @@ -730,7 +696,7 @@ DEFINE_I440FX_MACHINE(v1_1, "pc-1.1", pc_compat_1_2, #define PC_COMPAT_1_0 \ - PC_CPU_MODEL_IDS("1.0") \ + PC_COMPAT_1_1 \ {\ .driver = TYPE_ISA_FDC,\ .property = "check_media_rate",\ @@ -761,7 +727,7 @@ DEFINE_I440FX_MACHINE(v1_0, "pc-1.0", pc_compat_1_2, #define PC_COMPAT_0_15 \ - PC_CPU_MODEL_IDS("0.15") + PC_COMPAT_1_0 static void pc_i440fx_0_15_machine_options(MachineClass *m) { @@ -775,7 +741,7 @@ DEFINE_I440FX_MACHINE(v0_15, "pc-0.15", pc_compat_1_2, #define PC_COMPAT_0_14 \ - PC_CPU_MODEL_IDS("0.14") \ + PC_COMPAT_0_15 \ {\ .driver = "virtio-blk-pci",\ .property = "event_idx",\ @@ -814,7 +780,7 @@ DEFINE_I440FX_MACHINE(v0_14, "pc-0.14", pc_compat_1_2, #define PC_COMPAT_0_13 \ - PC_CPU_MODEL_IDS("0.13") \ + PC_COMPAT_0_14 \ {\ .driver = TYPE_PCI_DEVICE,\ .property = "command_serr_enable",\ @@ -851,7 +817,7 @@ DEFINE_I440FX_MACHINE(v0_13, "pc-0.13", pc_compat_0_13, #define PC_COMPAT_0_12 \ - PC_CPU_MODEL_IDS("0.12") \ + PC_COMPAT_0_13 \ {\ .driver = "virtio-serial-pci",\ .property = "max_ports",\ @@ -886,7 +852,7 @@ DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13, #define PC_COMPAT_0_11 \ - PC_CPU_MODEL_IDS("0.11") \ + PC_COMPAT_0_12 \ {\ .driver = "virtio-blk-pci",\ .property = "vectors",\ @@ -917,7 +883,7 @@ DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13, #define PC_COMPAT_0_10 \ - PC_CPU_MODEL_IDS("0.10") \ + PC_COMPAT_0_11 \ {\ .driver = "virtio-blk-pci",\ .property = "class",\ diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index c0b996192..04aae8958 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -60,7 +60,6 @@ static void pc_q35_init(MachineState *machine) PCIHostState *phb; PCIBus *host_bus; PCIDevice *lpc; - DeviceState *lpc_dev; BusState *idebus[MAX_SATA_PORTS]; ISADevice *rtc_state; MemoryRegion *system_io = get_system_io(); @@ -94,9 +93,6 @@ static void pc_q35_init(MachineState *machine) /* Handle the machine opt max-ram-below-4g. It is basically doing * min(qemu limit, user limit). */ - if (!pcms->max_ram_below_4g) { - pcms->max_ram_below_4g = 1ULL << 32; /* default: 4G */; - } if (lowmem > pcms->max_ram_below_4g) { lowmem = pcms->max_ram_below_4g; if (machine->ram_size - lowmem > lowmem && @@ -163,22 +159,17 @@ static void pc_q35_init(MachineState *machine) q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE)); object_property_add_child(qdev_get_machine(), "q35", OBJECT(q35_host), NULL); - object_property_set_link(OBJECT(q35_host), OBJECT(ram_memory), - MCH_HOST_PROP_RAM_MEM, NULL); - object_property_set_link(OBJECT(q35_host), OBJECT(pci_memory), - MCH_HOST_PROP_PCI_MEM, NULL); - object_property_set_link(OBJECT(q35_host), OBJECT(get_system_memory()), - MCH_HOST_PROP_SYSTEM_MEM, NULL); - object_property_set_link(OBJECT(q35_host), OBJECT(system_io), - MCH_HOST_PROP_IO_MEM, NULL); - object_property_set_int(OBJECT(q35_host), pcms->below_4g_mem_size, - PCI_HOST_BELOW_4G_MEM_SIZE, NULL); - object_property_set_int(OBJECT(q35_host), pcms->above_4g_mem_size, - PCI_HOST_ABOVE_4G_MEM_SIZE, NULL); + q35_host->mch.ram_memory = ram_memory; + q35_host->mch.pci_address_space = pci_memory; + q35_host->mch.system_memory = get_system_memory(); + q35_host->mch.address_space_io = system_io; + q35_host->mch.below_4g_mem_size = pcms->below_4g_mem_size; + q35_host->mch.above_4g_mem_size = pcms->above_4g_mem_size; /* pci */ qdev_init_nofail(DEVICE(q35_host)); phb = PCI_HOST_BRIDGE(q35_host); host_bus = phb->bus; + pcms->bus = phb->bus; /* create ISA bus */ lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC), true, @@ -193,15 +184,16 @@ static void pc_q35_init(MachineState *machine) PC_MACHINE_ACPI_DEVICE_PROP, &error_abort); ich9_lpc = ICH9_LPC_DEVICE(lpc); - lpc_dev = DEVICE(lpc); - for (i = 0; i < GSI_NUM_PINS; i++) { - qdev_connect_gpio_out_named(lpc_dev, ICH9_GPIO_GSI, i, gsi[i]); - } + ich9_lpc->pic = gsi; + ich9_lpc->ioapic = gsi_state->ioapic_irq; pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc, ICH9_LPC_NB_PIRQS); pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq); isa_bus = ich9_lpc->isa_bus; + /*end early*/ + isa_bus_irqs(isa_bus, gsi); + if (kvm_pic_in_kernel()) { i8259 = kvm_i8259_init(isa_bus); } else if (xen_enabled()) { @@ -242,7 +234,7 @@ static void pc_q35_init(MachineState *machine) ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports); ahci_ide_create_devs(ahci, hd); - if (machine_usb(machine)) { + if (usb_enabled()) { /* Should we create 6 UHCI according to ich9 spec? */ ehci_create_ich9_with_companions(host_bus, 0x1d); } @@ -289,27 +281,14 @@ static void pc_q35_machine_options(MachineClass *m) m->default_machine_opts = "firmware=bios-256k.bin"; m->default_display = "std"; m->no_floppy = 1; - m->has_dynamic_sysbus = true; } -static void pc_q35_2_7_machine_options(MachineClass *m) +static void pc_q35_2_6_machine_options(MachineClass *m) { pc_q35_machine_options(m); m->alias = "q35"; } -DEFINE_Q35_MACHINE(v2_7, "pc-q35-2.7", NULL, - pc_q35_2_7_machine_options); - -static void pc_q35_2_6_machine_options(MachineClass *m) -{ - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - pc_q35_2_7_machine_options(m); - m->alias = NULL; - pcmc->legacy_cpu_hotplug = true; - SET_MACHINE_COMPAT(m, PC_COMPAT_2_6); -} - DEFINE_Q35_MACHINE(v2_6, "pc-q35-2.6", NULL, pc_q35_2_6_machine_options); @@ -317,6 +296,7 @@ static void pc_q35_2_5_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_2_6_machine_options(m); + m->alias = NULL; pcmc->save_tsc_khz = false; m->legacy_fw_cfg_order = 1; SET_MACHINE_COMPAT(m, PC_COMPAT_2_5); diff --git a/hw/i386/trace-events b/hw/i386/trace-events deleted file mode 100644 index 7735e46ea..000000000 --- a/hw/i386/trace-events +++ /dev/null @@ -1,15 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/i386/xen/xen_platform.c -xen_platform_log(char *s) "xen platform: %s" - -# hw/i386/xen/xen_pvdevice.c -xen_pv_mmio_read(uint64_t addr) "WARNING: read from Xen PV Device MMIO space (address %"PRIx64")" -xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (address %"PRIx64")" - -# hw/i386/pc.c -mhp_pc_dimm_assigned_slot(int slot) "0x%d" -mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64 - -# hw/i386/x86-iommu.c -x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC invalidation: global=%d index=%" PRIu32 " mask=%" PRIu32 diff --git a/hw/i386/x86-iommu.c b/hw/i386/x86-iommu.c deleted file mode 100644 index ce26b2a71..000000000 --- a/hw/i386/x86-iommu.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * QEMU emulation of common X86 IOMMU - * - * Copyright (C) 2016 Peter Xu, Red Hat <peterx@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "hw/boards.h" -#include "hw/i386/x86-iommu.h" -#include "qemu/error-report.h" -#include "trace.h" - -void x86_iommu_iec_register_notifier(X86IOMMUState *iommu, - iec_notify_fn fn, void *data) -{ - IEC_Notifier *notifier = g_new0(IEC_Notifier, 1); - - notifier->iec_notify = fn; - notifier->private = data; - - QLIST_INSERT_HEAD(&iommu->iec_notifiers, notifier, list); -} - -void x86_iommu_iec_notify_all(X86IOMMUState *iommu, bool global, - uint32_t index, uint32_t mask) -{ - IEC_Notifier *notifier; - - trace_x86_iommu_iec_notify(global, index, mask); - - QLIST_FOREACH(notifier, &iommu->iec_notifiers, list) { - if (notifier->iec_notify) { - notifier->iec_notify(notifier->private, global, - index, mask); - } - } -} - -/* Default X86 IOMMU device */ -static X86IOMMUState *x86_iommu_default = NULL; - -static void x86_iommu_set_default(X86IOMMUState *x86_iommu) -{ - assert(x86_iommu); - - if (x86_iommu_default) { - error_report("QEMU does not support multiple vIOMMUs " - "for x86 yet."); - exit(1); - } - - x86_iommu_default = x86_iommu; -} - -X86IOMMUState *x86_iommu_get_default(void) -{ - return x86_iommu_default; -} - -static void x86_iommu_realize(DeviceState *dev, Error **errp) -{ - X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(dev); - X86IOMMUClass *x86_class = X86_IOMMU_GET_CLASS(dev); - QLIST_INIT(&x86_iommu->iec_notifiers); - if (x86_class->realize) { - x86_class->realize(dev, errp); - } - x86_iommu_set_default(X86_IOMMU_DEVICE(dev)); -} - -static void x86_iommu_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = x86_iommu_realize; -} - -static bool x86_iommu_intremap_prop_get(Object *o, Error **errp) -{ - X86IOMMUState *s = X86_IOMMU_DEVICE(o); - return s->intr_supported; -} - -static void x86_iommu_intremap_prop_set(Object *o, bool value, Error **errp) -{ - X86IOMMUState *s = X86_IOMMU_DEVICE(o); - s->intr_supported = value; -} - -static void x86_iommu_instance_init(Object *o) -{ - X86IOMMUState *s = X86_IOMMU_DEVICE(o); - - /* By default, do not support IR */ - s->intr_supported = false; - object_property_add_bool(o, "intremap", x86_iommu_intremap_prop_get, - x86_iommu_intremap_prop_set, NULL); -} - -static const TypeInfo x86_iommu_info = { - .name = TYPE_X86_IOMMU_DEVICE, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_init = x86_iommu_instance_init, - .instance_size = sizeof(X86IOMMUState), - .class_init = x86_iommu_class_init, - .class_size = sizeof(X86IOMMUClass), - .abstract = true, -}; - -static void x86_iommu_register_types(void) -{ - type_register_static(&x86_iommu_info); -} - -type_init(x86_iommu_register_types) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index f3438ad78..a1e651635 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -22,17 +22,17 @@ */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/pci/msi.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci.h" +#include <hw/hw.h> +#include <hw/pci/msi.h> +#include <hw/i386/pc.h> +#include <hw/pci/pci.h> #include "qemu/error-report.h" #include "sysemu/block-backend.h" #include "sysemu/dma.h" -#include "hw/ide/internal.h" -#include "hw/ide/pci.h" -#include "hw/ide/ahci.h" +#include "internal.h" +#include <hw/ide/pci.h> +#include <hw/ide/ahci.h> #define DEBUG_AHCI 0 @@ -1007,8 +1007,7 @@ static void execute_ncq_command(NCQTransferState *ncq_tfs) dma_acct_start(ide_state->blk, &ncq_tfs->acct, &ncq_tfs->sglist, BLOCK_ACCT_READ); ncq_tfs->aiocb = dma_blk_read(ide_state->blk, &ncq_tfs->sglist, - ncq_tfs->lba << BDRV_SECTOR_BITS, - ncq_cb, ncq_tfs); + ncq_tfs->lba, ncq_cb, ncq_tfs); break; case WRITE_FPDMA_QUEUED: DPRINTF(port, "NCQ writing %d sectors to LBA %"PRId64", tag %d\n", @@ -1020,8 +1019,7 @@ static void execute_ncq_command(NCQTransferState *ncq_tfs) dma_acct_start(ide_state->blk, &ncq_tfs->acct, &ncq_tfs->sglist, BLOCK_ACCT_WRITE); ncq_tfs->aiocb = dma_blk_write(ide_state->blk, &ncq_tfs->sglist, - ncq_tfs->lba << BDRV_SECTOR_BITS, - ncq_cb, ncq_tfs); + ncq_tfs->lba, ncq_cb, ncq_tfs); break; default: DPRINTF(port, "error: unsupported NCQ command (0x%02x) received\n", diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h new file mode 100644 index 000000000..bc777ed5c --- /dev/null +++ b/hw/ide/ahci.h @@ -0,0 +1,405 @@ +/* + * QEMU AHCI Emulation + * + * Copyright (c) 2010 qiaochong@loongson.cn + * Copyright (c) 2010 Roland Elek <elek.roland@gmail.com> + * Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de> + * Copyright (c) 2010 Alexander Graf <agraf@suse.de> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef HW_IDE_AHCI_H +#define HW_IDE_AHCI_H + +#include <hw/sysbus.h> + +#define AHCI_MEM_BAR_SIZE 0x1000 +#define AHCI_MAX_PORTS 32 +#define AHCI_MAX_SG 168 /* hardware max is 64K */ +#define AHCI_DMA_BOUNDARY 0xffffffff +#define AHCI_USE_CLUSTERING 0 +#define AHCI_MAX_CMDS 32 +#define AHCI_CMD_SZ 32 +#define AHCI_CMD_SLOT_SZ (AHCI_MAX_CMDS * AHCI_CMD_SZ) +#define AHCI_RX_FIS_SZ 256 +#define AHCI_CMD_TBL_CDB 0x40 +#define AHCI_CMD_TBL_HDR_SZ 0x80 +#define AHCI_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16)) +#define AHCI_CMD_TBL_AR_SZ (AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS) +#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ + \ + AHCI_RX_FIS_SZ) + +#define AHCI_IRQ_ON_SG (1U << 31) +#define AHCI_CMD_ATAPI (1 << 5) +#define AHCI_CMD_WRITE (1 << 6) +#define AHCI_CMD_PREFETCH (1 << 7) +#define AHCI_CMD_RESET (1 << 8) +#define AHCI_CMD_CLR_BUSY (1 << 10) + +#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */ +#define RX_FIS_SDB 0x58 /* offset of SDB FIS data */ +#define RX_FIS_UNK 0x60 /* offset of Unknown FIS data */ + +/* global controller registers */ +#define HOST_CAP 0x00 /* host capabilities */ +#define HOST_CTL 0x04 /* global host control */ +#define HOST_IRQ_STAT 0x08 /* interrupt status */ +#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */ +#define HOST_VERSION 0x10 /* AHCI spec. version compliancy */ + +/* HOST_CTL bits */ +#define HOST_CTL_RESET (1 << 0) /* reset controller; self-clear */ +#define HOST_CTL_IRQ_EN (1 << 1) /* global IRQ enable */ +#define HOST_CTL_AHCI_EN (1U << 31) /* AHCI enabled */ + +/* HOST_CAP bits */ +#define HOST_CAP_SSC (1 << 14) /* Slumber capable */ +#define HOST_CAP_AHCI (1 << 18) /* AHCI only */ +#define HOST_CAP_CLO (1 << 24) /* Command List Override support */ +#define HOST_CAP_SSS (1 << 27) /* Staggered Spin-up */ +#define HOST_CAP_NCQ (1 << 30) /* Native Command Queueing */ +#define HOST_CAP_64 (1U << 31) /* PCI DAC (64-bit DMA) support */ + +/* registers for each SATA port */ +#define PORT_LST_ADDR 0x00 /* command list DMA addr */ +#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */ +#define PORT_FIS_ADDR 0x08 /* FIS rx buf addr */ +#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */ +#define PORT_IRQ_STAT 0x10 /* interrupt status */ +#define PORT_IRQ_MASK 0x14 /* interrupt enable/disable mask */ +#define PORT_CMD 0x18 /* port command */ +#define PORT_TFDATA 0x20 /* taskfile data */ +#define PORT_SIG 0x24 /* device TF signature */ +#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */ +#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */ +#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */ +#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */ +#define PORT_CMD_ISSUE 0x38 /* command issue */ +#define PORT_RESERVED 0x3c /* reserved */ + +/* PORT_IRQ_{STAT,MASK} bits */ +#define PORT_IRQ_COLD_PRES (1U << 31) /* cold presence detect */ +#define PORT_IRQ_TF_ERR (1 << 30) /* task file error */ +#define PORT_IRQ_HBUS_ERR (1 << 29) /* host bus fatal error */ +#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */ +#define PORT_IRQ_IF_ERR (1 << 27) /* interface fatal error */ +#define PORT_IRQ_IF_NONFATAL (1 << 26) /* interface non-fatal error */ +#define PORT_IRQ_OVERFLOW (1 << 24) /* xfer exhausted available S/G */ +#define PORT_IRQ_BAD_PMP (1 << 23) /* incorrect port multiplier */ + +#define PORT_IRQ_PHYRDY (1 << 22) /* PhyRdy changed */ +#define PORT_IRQ_DEV_ILCK (1 << 7) /* device interlock */ +#define PORT_IRQ_CONNECT (1 << 6) /* port connect change status */ +#define PORT_IRQ_SG_DONE (1 << 5) /* descriptor processed */ +#define PORT_IRQ_UNK_FIS (1 << 4) /* unknown FIS rx'd */ +#define PORT_IRQ_SDB_FIS (1 << 3) /* Set Device Bits FIS rx'd */ +#define PORT_IRQ_DMAS_FIS (1 << 2) /* DMA Setup FIS rx'd */ +#define PORT_IRQ_PIOS_FIS (1 << 1) /* PIO Setup FIS rx'd */ +#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */ + +#define PORT_IRQ_FREEZE (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | \ + PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY | \ + PORT_IRQ_UNK_FIS) +#define PORT_IRQ_ERROR (PORT_IRQ_FREEZE | PORT_IRQ_TF_ERR | \ + PORT_IRQ_HBUS_DATA_ERR) +#define DEF_PORT_IRQ (PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | \ + PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | \ + PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS) + +/* PORT_CMD bits */ +#define PORT_CMD_ATAPI (1 << 24) /* Device is ATAPI */ +#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */ +#define PORT_CMD_FIS_ON (1 << 14) /* FIS DMA engine running */ +#define PORT_CMD_FIS_RX (1 << 4) /* Enable FIS receive DMA engine */ +#define PORT_CMD_CLO (1 << 3) /* Command list override */ +#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */ +#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */ +#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */ + +#define PORT_CMD_ICC_MASK (0xfU << 28) /* i/f ICC state mask */ +#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */ +#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */ +#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */ + +#define PORT_CMD_RO_MASK 0x007dffe0 /* Which CMD bits are read only? */ + +/* ap->flags bits */ +#define AHCI_FLAG_NO_NCQ (1 << 24) +#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */ +#define AHCI_FLAG_HONOR_PI (1 << 26) /* honor PORTS_IMPL */ +#define AHCI_FLAG_IGN_SERR_INTERNAL (1 << 27) /* ignore SERR_INTERNAL */ +#define AHCI_FLAG_32BIT_ONLY (1 << 28) /* force 32bit */ + +#define ATA_SRST (1 << 2) /* software reset */ + +#define STATE_RUN 0 +#define STATE_RESET 1 + +#define SATA_SCR_SSTATUS_DET_NODEV 0x0 +#define SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP 0x3 + +#define SATA_SCR_SSTATUS_SPD_NODEV 0x00 +#define SATA_SCR_SSTATUS_SPD_GEN1 0x10 + +#define SATA_SCR_SSTATUS_IPM_NODEV 0x000 +#define SATA_SCR_SSTATUS_IPM_ACTIVE 0X100 + +#define AHCI_SCR_SCTL_DET 0xf + +#define SATA_FIS_TYPE_REGISTER_H2D 0x27 +#define SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER 0x80 +#define SATA_FIS_TYPE_REGISTER_D2H 0x34 +#define SATA_FIS_TYPE_PIO_SETUP 0x5f +#define SATA_FIS_TYPE_SDB 0xA1 + +#define AHCI_CMD_HDR_CMD_FIS_LEN 0x1f +#define AHCI_CMD_HDR_PRDT_LEN 16 + +#define SATA_SIGNATURE_CDROM 0xeb140101 +#define SATA_SIGNATURE_DISK 0x00000101 + +#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20 + /* Shouldn't this be 0x2c? */ + +#define AHCI_PORT_REGS_START_ADDR 0x100 +#define AHCI_PORT_ADDR_OFFSET_MASK 0x7f +#define AHCI_PORT_ADDR_OFFSET_LEN 0x80 + +#define AHCI_NUM_COMMAND_SLOTS 31 +#define AHCI_SUPPORTED_SPEED 20 +#define AHCI_SUPPORTED_SPEED_GEN1 1 +#define AHCI_VERSION_1_0 0x10000 + +#define AHCI_PROGMODE_MAJOR_REV_1 1 + +#define AHCI_COMMAND_TABLE_ACMD 0x40 + +#define AHCI_PRDT_SIZE_MASK 0x3fffff + +#define IDE_FEATURE_DMA 1 + +#define READ_FPDMA_QUEUED 0x60 +#define WRITE_FPDMA_QUEUED 0x61 +#define NCQ_NON_DATA 0x63 +#define RECEIVE_FPDMA_QUEUED 0x65 +#define SEND_FPDMA_QUEUED 0x64 + +#define NCQ_FIS_FUA_MASK 0x80 +#define NCQ_FIS_RARC_MASK 0x01 + +#define RES_FIS_DSFIS 0x00 +#define RES_FIS_PSFIS 0x20 +#define RES_FIS_RFIS 0x40 +#define RES_FIS_SDBFIS 0x58 +#define RES_FIS_UFIS 0x60 + +#define SATA_CAP_SIZE 0x8 +#define SATA_CAP_REV 0x2 +#define SATA_CAP_BAR 0x4 + +typedef struct AHCIControlRegs { + uint32_t cap; + uint32_t ghc; + uint32_t irqstatus; + uint32_t impl; + uint32_t version; +} AHCIControlRegs; + +typedef struct AHCIPortRegs { + uint32_t lst_addr; + uint32_t lst_addr_hi; + uint32_t fis_addr; + uint32_t fis_addr_hi; + uint32_t irq_stat; + uint32_t irq_mask; + uint32_t cmd; + uint32_t unused0; + uint32_t tfdata; + uint32_t sig; + uint32_t scr_stat; + uint32_t scr_ctl; + uint32_t scr_err; + uint32_t scr_act; + uint32_t cmd_issue; + uint32_t reserved; +} AHCIPortRegs; + +typedef struct AHCICmdHdr { + uint16_t opts; + uint16_t prdtl; + uint32_t status; + uint64_t tbl_addr; + uint32_t reserved[4]; +} QEMU_PACKED AHCICmdHdr; + +typedef struct AHCI_SG { + uint64_t addr; + uint32_t reserved; + uint32_t flags_size; +} QEMU_PACKED AHCI_SG; + +typedef struct AHCIDevice AHCIDevice; + +typedef struct NCQTransferState { + AHCIDevice *drive; + BlockAIOCB *aiocb; + AHCICmdHdr *cmdh; + QEMUSGList sglist; + BlockAcctCookie acct; + uint32_t sector_count; + uint64_t lba; + uint8_t tag; + uint8_t cmd; + uint8_t slot; + bool used; + bool halt; +} NCQTransferState; + +struct AHCIDevice { + IDEDMA dma; + IDEBus port; + int port_no; + uint32_t port_state; + uint32_t finished; + AHCIPortRegs port_regs; + struct AHCIState *hba; + QEMUBH *check_bh; + uint8_t *lst; + uint8_t *res_fis; + bool done_atapi_packet; + int32_t busy_slot; + bool init_d2h_sent; + AHCICmdHdr *cur_cmd; + NCQTransferState ncq_tfs[AHCI_MAX_CMDS]; +}; + +typedef struct AHCIState { + DeviceState *container; + + AHCIDevice *dev; + AHCIControlRegs control_regs; + MemoryRegion mem; + MemoryRegion idp; /* Index-Data Pair I/O port space */ + unsigned idp_offset; /* Offset of index in I/O port space */ + uint32_t idp_index; /* Current IDP index */ + int32_t ports; + qemu_irq irq; + AddressSpace *as; +} AHCIState; + +typedef struct AHCIPCIState { + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + + AHCIState ahci; +} AHCIPCIState; + +#define TYPE_ICH9_AHCI "ich9-ahci" + +#define ICH_AHCI(obj) \ + OBJECT_CHECK(AHCIPCIState, (obj), TYPE_ICH9_AHCI) + +extern const VMStateDescription vmstate_ahci; + +#define VMSTATE_AHCI(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(AHCIState), \ + .vmsd = &vmstate_ahci, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, AHCIState), \ +} + +/** + * NCQFrame is the same as a Register H2D FIS (described in SATA 3.2), + * but some fields have been re-mapped and re-purposed, as seen in + * SATA 3.2 section 13.6.4.1 ("READ FPDMA QUEUED") + * + * cmd_fis[3], feature 7:0, becomes sector count 7:0. + * cmd_fis[7], device 7:0, uses bit 7 as the Force Unit Access bit. + * cmd_fis[11], feature 15:8, becomes sector count 15:8. + * cmd_fis[12], count 7:0, becomes the NCQ TAG (7:3) and RARC bit (0) + * cmd_fis[13], count 15:8, becomes the priority value (7:6) + * bytes 16-19 become an le32 "auxiliary" field. + */ +typedef struct NCQFrame { + uint8_t fis_type; + uint8_t c; + uint8_t command; + uint8_t sector_count_low; /* (feature 7:0) */ + uint8_t lba0; + uint8_t lba1; + uint8_t lba2; + uint8_t fua; /* (device 7:0) */ + uint8_t lba3; + uint8_t lba4; + uint8_t lba5; + uint8_t sector_count_high; /* (feature 15:8) */ + uint8_t tag; /* (count 0:7) */ + uint8_t prio; /* (count 15:8) */ + uint8_t icc; + uint8_t control; + uint8_t aux0; + uint8_t aux1; + uint8_t aux2; + uint8_t aux3; +} QEMU_PACKED NCQFrame; + +typedef struct SDBFIS { + uint8_t type; + uint8_t flags; + uint8_t status; + uint8_t error; + uint32_t payload; +} QEMU_PACKED SDBFIS; + +void ahci_realize(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports); +void ahci_init(AHCIState *s, DeviceState *qdev); +void ahci_uninit(AHCIState *s); + +void ahci_reset(AHCIState *s); + +void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd); + +#define TYPE_SYSBUS_AHCI "sysbus-ahci" +#define SYSBUS_AHCI(obj) OBJECT_CHECK(SysbusAHCIState, (obj), TYPE_SYSBUS_AHCI) + +typedef struct SysbusAHCIState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + AHCIState ahci; + uint32_t num_ports; +} SysbusAHCIState; + +#define TYPE_ALLWINNER_AHCI "allwinner-ahci" +#define ALLWINNER_AHCI(obj) OBJECT_CHECK(AllwinnerAHCIState, (obj), \ + TYPE_ALLWINNER_AHCI) + +#define ALLWINNER_AHCI_MMIO_OFF 0x80 +#define ALLWINNER_AHCI_MMIO_SIZE 0x80 + +struct AllwinnerAHCIState { + /*< private >*/ + SysbusAHCIState parent_obj; + /*< public >*/ + + MemoryRegion mmio; + uint32_t regs[ALLWINNER_AHCI_MMIO_SIZE/4]; +}; + +#endif /* HW_IDE_AHCI_H */ diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 618967503..8592a4ae1 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -28,9 +28,6 @@ #include "hw/scsi/scsi.h" #include "sysemu/block-backend.h" -#define ATAPI_SECTOR_BITS (2 + BDRV_SECTOR_BITS) -#define ATAPI_SECTOR_SIZE (1 << ATAPI_SECTOR_BITS) - static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret); static void padstr8(uint8_t *buf, int buf_size, const char *src) @@ -114,7 +111,7 @@ cd_read_sector_sync(IDEState *s) { int ret; block_acct_start(blk_get_stats(s->blk), &s->acct, - ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ); + 4 * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ); #ifdef DEBUG_IDE_ATAPI printf("cd_read_sector_sync: lba=%d\n", s->lba); @@ -122,12 +119,12 @@ cd_read_sector_sync(IDEState *s) switch (s->cd_sector_size) { case 2048: - ret = blk_pread(s->blk, (int64_t)s->lba << ATAPI_SECTOR_BITS, - s->io_buffer, ATAPI_SECTOR_SIZE); + ret = blk_read(s->blk, (int64_t)s->lba << 2, + s->io_buffer, 4); break; case 2352: - ret = blk_pread(s->blk, (int64_t)s->lba << ATAPI_SECTOR_BITS, - s->io_buffer + 16, ATAPI_SECTOR_SIZE); + ret = blk_read(s->blk, (int64_t)s->lba << 2, + s->io_buffer + 16, 4); if (ret >= 0) { cd_data_to_raw(s->io_buffer, s->lba); } @@ -185,7 +182,7 @@ static int cd_read_sector(IDEState *s) s->iov.iov_base = (s->cd_sector_size == 2352) ? s->io_buffer + 16 : s->io_buffer; - s->iov.iov_len = ATAPI_SECTOR_SIZE; + s->iov.iov_len = 4 * BDRV_SECTOR_SIZE; qemu_iovec_init_external(&s->qiov, &s->iov, 1); #ifdef DEBUG_IDE_ATAPI @@ -193,7 +190,7 @@ static int cd_read_sector(IDEState *s) #endif block_acct_start(blk_get_stats(s->blk), &s->acct, - ATAPI_SECTOR_SIZE, BLOCK_ACCT_READ); + 4 * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ); ide_buffered_readv(s, (int64_t)s->lba << 2, &s->qiov, 4, cd_read_sector_cb, s); @@ -439,7 +436,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) #endif s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset); - s->bus->dma->iov.iov_len = n * ATAPI_SECTOR_SIZE; + s->bus->dma->iov.iov_len = n * 4 * 512; qemu_iovec_init_external(&s->bus->dma->qiov, &s->bus->dma->iov, 1); s->bus->dma->aiocb = ide_buffered_readv(s, (int64_t)s->lba << 2, diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 9ebb8d4fb..49294a531 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -23,15 +23,15 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci.h" -#include "hw/isa/isa.h" +#include <hw/hw.h> +#include <hw/i386/pc.h> +#include <hw/pci/pci.h> +#include <hw/isa/isa.h> #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" -#include "hw/ide/pci.h" +#include <hw/ide/pci.h> /* CMD646 specific */ #define CFR 0x50 diff --git a/hw/ide/core.c b/hw/ide/core.c index 45b6df132..aa11f134d 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -23,10 +23,10 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci.h" -#include "hw/isa/isa.h" +#include <hw/hw.h> +#include <hw/i386/pc.h> +#include <hw/pci/pci.h> +#include <hw/isa/isa.h> #include "qemu/error-report.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" @@ -35,7 +35,7 @@ #include "sysemu/block-backend.h" #include "qemu/cutils.h" -#include "hw/ide/internal.h" +#include <hw/ide/internal.h> /* These values were based on a Seagate ST3500418AS but have been modified to make more sense in QEMU */ @@ -423,10 +423,8 @@ static void ide_issue_trim_cb(void *opaque, int ret) } /* Got an entry! Submit and exit. */ - iocb->aiocb = blk_aio_pdiscard(iocb->blk, - sector << BDRV_SECTOR_BITS, - count << BDRV_SECTOR_BITS, - ide_issue_trim_cb, opaque); + iocb->aiocb = blk_aio_discard(iocb->blk, sector, count, + ide_issue_trim_cb, opaque); return; } @@ -443,14 +441,13 @@ static void ide_issue_trim_cb(void *opaque, int ret) } } -BlockAIOCB *ide_issue_trim( - int64_t offset, QEMUIOVector *qiov, - BlockCompletionFunc *cb, void *cb_opaque, void *opaque) +BlockAIOCB *ide_issue_trim(BlockBackend *blk, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockCompletionFunc *cb, void *opaque) { - BlockBackend *blk = opaque; TrimAIOCB *iocb; - iocb = blk_aio_get(&trim_aiocb_info, blk, cb, cb_opaque); + iocb = blk_aio_get(&trim_aiocb_info, blk, cb, opaque); iocb->blk = blk; iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); iocb->ret = 0; @@ -468,20 +465,6 @@ void ide_abort_command(IDEState *s) s->error = ABRT_ERR; } -static void ide_set_retry(IDEState *s) -{ - s->bus->retry_unit = s->unit; - s->bus->retry_sector_num = ide_get_sector(s); - s->bus->retry_nsector = s->nsector; -} - -static void ide_clear_retry(IDEState *s) -{ - s->bus->retry_unit = -1; - s->bus->retry_sector_num = 0; - s->bus->retry_nsector = 0; -} - /* prepare data transfer and tell what to do after */ void ide_transfer_start(IDEState *s, uint8_t *buf, int size, EndTransferFunc *end_transfer_func) @@ -489,7 +472,6 @@ void ide_transfer_start(IDEState *s, uint8_t *buf, int size, s->end_transfer_func = end_transfer_func; s->data_ptr = buf; s->data_end = buf + size; - ide_set_retry(s); if (!(s->status & ERR_STAT)) { s->status |= DRQ_STAT; } @@ -634,8 +616,8 @@ BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num, req->iov.iov_len = iov->size; qemu_iovec_init_external(&req->qiov, &req->iov, 1); - aioreq = blk_aio_preadv(s->blk, sector_num << BDRV_SECTOR_BITS, - &req->qiov, 0, ide_buffered_readv_cb, req); + aioreq = blk_aio_readv(s->blk, sector_num, &req->qiov, nb_sectors, + ide_buffered_readv_cb, req); QLIST_INSERT_HEAD(&s->buffered_requests, req, list); return aioreq; @@ -773,7 +755,9 @@ void dma_buf_commit(IDEState *s, uint32_t tx_bytes) void ide_set_inactive(IDEState *s, bool more) { s->bus->dma->aiocb = NULL; - ide_clear_retry(s); + s->bus->retry_unit = -1; + s->bus->retry_sector_num = 0; + s->bus->retry_nsector = 0; if (s->bus->dma->ops->set_inactive) { s->bus->dma->ops->set_inactive(s->bus->dma, more); } @@ -815,7 +799,6 @@ static void ide_dma_cb(void *opaque, int ret) IDEState *s = opaque; int n; int64_t sector_num; - uint64_t offset; bool stay_active = false; if (ret == -ECANCELED) { @@ -878,20 +861,18 @@ static void ide_dma_cb(void *opaque, int ret) return; } - offset = sector_num << BDRV_SECTOR_BITS; switch (s->dma_cmd) { case IDE_DMA_READ: - s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, offset, + s->bus->dma->aiocb = dma_blk_read(s->blk, &s->sg, sector_num, ide_dma_cb, s); break; case IDE_DMA_WRITE: - s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, offset, + s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, sector_num, ide_dma_cb, s); break; case IDE_DMA_TRIM: - s->bus->dma->aiocb = dma_blk_io(blk_get_aio_context(s->blk), - &s->sg, offset, - ide_issue_trim, s->blk, ide_dma_cb, s, + s->bus->dma->aiocb = dma_blk_io(s->blk, &s->sg, sector_num, + ide_issue_trim, ide_dma_cb, s, DMA_DIRECTION_TO_DEVICE); break; default: @@ -931,7 +912,9 @@ static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd) void ide_start_dma(IDEState *s, BlockCompletionFunc *cb) { s->io_buffer_index = 0; - ide_set_retry(s); + s->bus->retry_unit = s->unit; + s->bus->retry_sector_num = ide_get_sector(s); + s->bus->retry_nsector = s->nsector; if (s->bus->dma->ops->start_dma) { s->bus->dma->ops->start_dma(s->bus->dma, s, cb); } @@ -1025,8 +1008,8 @@ static void ide_sector_write(IDEState *s) block_acct_start(blk_get_stats(s->blk), &s->acct, n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE); - s->pio_aiocb = blk_aio_pwritev(s->blk, sector_num << BDRV_SECTOR_BITS, - &s->qiov, 0, ide_sector_write_cb, s); + s->pio_aiocb = blk_aio_writev(s->blk, sector_num, &s->qiov, n, + ide_sector_write_cb, s); } static void ide_flush_cb(void *opaque, int ret) @@ -1061,7 +1044,6 @@ static void ide_flush_cache(IDEState *s) } s->status |= BUSY_STAT; - ide_set_retry(s); block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH); s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s); } diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 459916977..0a13334ba 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -61,15 +61,16 @@ */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/pci/msi.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci.h" -#include "hw/isa/isa.h" +#include <hw/hw.h> +#include <hw/pci/msi.h> +#include <hw/i386/pc.h> +#include <hw/pci/pci.h> +#include <hw/isa/isa.h> #include "sysemu/block-backend.h" #include "sysemu/dma.h" -#include "hw/ide/pci.h" -#include "hw/ide/ahci.h" + +#include <hw/ide/pci.h> +#include <hw/ide/ahci.h> #define ICH9_MSI_CAP_OFFSET 0x80 #define ICH9_SATA_CAP_OFFSET 0xA8 @@ -110,7 +111,6 @@ static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp) int sata_cap_offset; uint8_t *sata_cap; d = ICH_AHCI(dev); - int ret; ahci_realize(&d->ahci, DEVICE(dev), pci_get_address_space(dev), 6); @@ -146,10 +146,7 @@ static void pci_ich9_ahci_realize(PCIDevice *dev, Error **errp) /* Although the AHCI 1.3 specification states that the first capability * should be PMCAP, the Intel ICH9 data sheet specifies that the ICH9 * AHCI device puts the MSI capability first, pointing to 0x80. */ - ret = msi_init(dev, ICH9_MSI_CAP_OFFSET, 1, true, false, NULL); - /* Any error other than -ENOTSUP(board's MSI support is broken) - * is a programming error. Fall back to INTx silently on -ENOTSUP */ - assert(!ret || ret == -ENOTSUP); + msi_init(dev, ICH9_MSI_CAP_OFFSET, 1, true, false); } static void pci_ich9_uninit(PCIDevice *dev) diff --git a/hw/ide/internal.h b/hw/ide/internal.h new file mode 100644 index 000000000..d2c458f57 --- /dev/null +++ b/hw/ide/internal.h @@ -0,0 +1,635 @@ +#ifndef HW_IDE_INTERNAL_H +#define HW_IDE_INTERNAL_H + +/* + * QEMU IDE Emulation -- internal header file + * only files in hw/ide/ are supposed to include this file. + * non-internal declarations are in hw/ide.h + */ +#include <hw/ide.h> +#include <hw/isa/isa.h> +#include "sysemu/dma.h" +#include "sysemu/sysemu.h" +#include "hw/block/block.h" +#include "block/scsi.h" + +/* debug IDE devices */ +//#define DEBUG_IDE +//#define DEBUG_IDE_ATAPI +//#define DEBUG_AIO +#define USE_DMA_CDROM + +typedef struct IDEBus IDEBus; +typedef struct IDEDevice IDEDevice; +typedef struct IDEState IDEState; +typedef struct IDEDMA IDEDMA; +typedef struct IDEDMAOps IDEDMAOps; + +#define TYPE_IDE_BUS "IDE" +#define IDE_BUS(obj) OBJECT_CHECK(IDEBus, (obj), TYPE_IDE_BUS) + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define SRV_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* media change request */ +#define ID_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ +#define ECC_ERR 0x40 /* Uncorrectable ECC error */ +#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ +#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ + +/* Bits of HD_NSECTOR */ +#define CD 0x01 +#define IO 0x02 +#define REL 0x04 +#define TAG_MASK 0xf8 + +#define IDE_CMD_RESET 0x04 +#define IDE_CMD_DISABLE_IRQ 0x02 + +/* ACS-2 T13/2015-D Table B.2 Command codes */ +#define WIN_NOP 0x00 +/* reserved 0x01..0x02 */ +#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ +/* reserved 0x04..0x05 */ +#define WIN_DSM 0x06 +/* reserved 0x07 */ +#define WIN_DEVICE_RESET 0x08 +/* reserved 0x09..0x0a */ +/* REQUEST SENSE DATA EXT 0x0B */ +/* reserved 0x0C..0x0F */ +#define WIN_RECAL 0x10 /* obsolete since ATA4 */ +/* obsolete since ATA3, retired in ATA4 0x11..0x1F */ +#define WIN_READ 0x20 /* 28-Bit */ +#define WIN_READ_ONCE 0x21 /* 28-Bit w/o retries, obsolete since ATA5 */ +/* obsolete since ATA4 0x22..0x23 */ +#define WIN_READ_EXT 0x24 /* 48-Bit */ +#define WIN_READDMA_EXT 0x25 /* 48-Bit */ +#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit, obsolete since ACS2 */ +#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ +/* reserved 0x28 */ +#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ +/* READ STREAM DMA EXT 0x2A */ +/* READ STREAM EXT 0x2B */ +/* reserved 0x2C..0x2E */ +/* READ LOG EXT 0x2F */ +#define WIN_WRITE 0x30 /* 28-Bit */ +#define WIN_WRITE_ONCE 0x31 /* 28-Bit w/o retries, obsolete since ATA5 */ +/* obsolete since ATA4 0x32..0x33 */ +#define WIN_WRITE_EXT 0x34 /* 48-Bit */ +#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ +#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ +#define WIN_SET_MAX_EXT 0x37 /* 48-Bit, obsolete since ACS2 */ +#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ +#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ +#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ +/* WRITE STREAM DMA EXT 0x3A */ +/* WRITE STREAM EXT 0x3B */ +#define WIN_WRITE_VERIFY 0x3C /* 28-Bit, obsolete since ATA4 */ +/* WRITE DMA FUA EXT 0x3D */ +/* obsolete since ACS2 0x3E */ +/* WRITE LOG EXT 0x3F */ +#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ +#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - w/o retries, obsolete since ATA5 */ +#define WIN_VERIFY_EXT 0x42 /* 48-Bit */ +/* reserved 0x43..0x44 */ +/* WRITE UNCORRECTABLE EXT 0x45 */ +/* reserved 0x46 */ +/* READ LOG DMA EXT 0x47 */ +/* reserved 0x48..0x4F */ +/* obsolete since ATA4 0x50 */ +/* CONFIGURE STREAM 0x51 */ +/* reserved 0x52..0x56 */ +/* WRITE LOG DMA EXT 0x57 */ +/* reserved 0x58..0x5A */ +/* TRUSTED NON DATA 0x5B */ +/* TRUSTED RECEIVE 0x5C */ +/* TRUSTED RECEIVE DMA 0x5D */ +/* TRUSTED SEND 0x5E */ +/* TRUSTED SEND DMA 0x5F */ +/* READ FPDMA QUEUED 0x60 */ +/* WRITE FPDMA QUEUED 0x61 */ +/* reserved 0x62->0x6F */ +#define WIN_SEEK 0x70 /* obsolete since ATA7 */ +/* reserved 0x71-0x7F */ +/* vendor specific 0x80-0x86 */ +#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ +/* vendor specific 0x88-0x8F */ +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 /* set drive geometry translation, obsolete since ATA6 */ +#define WIN_DOWNLOAD_MICROCODE 0x92 +/* DOWNLOAD MICROCODE DMA 0x93 */ +#define WIN_STANDBYNOW2 0x94 /* retired in ATA4 */ +#define WIN_IDLEIMMEDIATE2 0x95 /* force drive to become "ready", retired in ATA4 */ +#define WIN_STANDBY2 0x96 /* retired in ATA4 */ +#define WIN_SETIDLE2 0x97 /* retired in ATA4 */ +#define WIN_CHECKPOWERMODE2 0x98 /* retired in ATA4 */ +#define WIN_SLEEPNOW2 0x99 /* retired in ATA4 */ +/* vendor specific 0x9A */ +/* reserved 0x9B..0x9F */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ +#define WIN_QUEUED_SERVICE 0xA2 /* obsolete since ACS2 */ +/* reserved 0xA3..0xAF */ +#define WIN_SMART 0xB0 /* self-monitoring and reporting */ +/* Device Configuration Overlay 0xB1 */ +/* reserved 0xB2..0xB3 */ +/* Sanitize Device 0xB4 */ +/* reserved 0xB5 */ +/* NV Cache 0xB6 */ +/* reserved for CFA 0xB7..0xBB */ +#define CFA_ACCESS_METADATA_STORAGE 0xB8 +/* reserved 0xBC..0xBF */ +#define CFA_ERASE_SECTORS 0xC0 /* microdrives implement as NOP */ +/* vendor specific 0xC1..0xC3 */ +#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ +#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ +#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ +#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers, obsolete since ACS2 */ +#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ +#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - w/o retries, obsolete since ATA5 */ +#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ +#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - w/o retries, obsolete since ATA5 */ +#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers, obsolete since ACS2 */ +#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ +/* WRITE MULTIPLE FUA EXT 0xCE */ +/* reserved 0xCF..0xDO */ +/* CHECK MEDIA CARD TYPE 0xD1 */ +/* reserved for media card pass through 0xD2..0xD4 */ +/* reserved 0xD5..0xD9 */ +#define WIN_GETMEDIASTATUS 0xDA /* obsolete since ATA8 */ +/* obsolete since ATA3, retired in ATA4 0xDB..0xDD */ +#define WIN_DOORLOCK 0xDE /* lock door on removable drives, obsolete since ATA8 */ +#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives, obsolete since ATA8 */ +#define WIN_STANDBYNOW1 0xE0 +#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ +#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */ +#define WIN_SETIDLE1 0xE3 +#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ +#define WIN_CHECKPOWERMODE1 0xE5 +#define WIN_SLEEPNOW1 0xE6 +#define WIN_FLUSH_CACHE 0xE7 +#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ +/* READ BUFFER DMA 0xE9 */ +#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ +/* WRITE BUFFER DMA 0xEB */ +#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ +#define WIN_MEDIAEJECT 0xED /* obsolete since ATA8 */ +/* obsolete since ATA4 0xEE */ +#define WIN_SETFEATURES 0xEF /* set special drive features */ +#define IBM_SENSE_CONDITION 0xF0 /* measure disk temperature, vendor specific */ +#define WIN_SECURITY_SET_PASS 0xF1 +#define WIN_SECURITY_UNLOCK 0xF2 +#define WIN_SECURITY_ERASE_PREPARE 0xF3 +#define WIN_SECURITY_ERASE_UNIT 0xF4 +#define WIN_SECURITY_FREEZE_LOCK 0xF5 +#define CFA_WEAR_LEVEL 0xF5 /* microdrives implement as NOP; not specified in T13! */ +#define WIN_SECURITY_DISABLE 0xF6 +/* vendor specific 0xF7 */ +#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ +#define WIN_SET_MAX 0xF9 +/* vendor specific 0xFA..0xFF */ + +/* set to 1 set disable mult support */ +#define MAX_MULT_SECTORS 16 + +#define IDE_DMA_BUF_SECTORS 256 + +/* feature values for Data Set Management */ +#define DSM_TRIM 0x01 + +#if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS) +#error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS" +#endif + +/* ATAPI defines */ + +#define ATAPI_PACKET_SIZE 12 + +/* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +#define GPCMD_BLANK 0xa1 +#define GPCMD_CLOSE_TRACK 0x5b +#define GPCMD_FLUSH_CACHE 0x35 +#define GPCMD_FORMAT_UNIT 0x04 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_GET_PERFORMANCE 0xac +#define GPCMD_INQUIRY 0x12 +#define GPCMD_LOAD_UNLOAD 0xa6 +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_AUDIO_TI 0x48 +#define GPCMD_PLAY_CD 0xbc +#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define GPCMD_READ_10 0x28 +#define GPCMD_READ_12 0xa8 +#define GPCMD_READ_CDVD_CAPACITY 0x25 +#define GPCMD_READ_CD 0xbe +#define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_READ_DISC_INFO 0x51 +#define GPCMD_READ_DVD_STRUCTURE 0xad +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_READ_TRACK_RZONE_INFO 0x52 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_REPAIR_RZONE_TRACK 0x58 +#define GPCMD_REPORT_KEY 0xa4 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_RESERVE_RZONE_TRACK 0x53 +#define GPCMD_SCAN 0xba +#define GPCMD_SEEK 0x2b +#define GPCMD_SEND_DVD_STRUCTURE 0xad +#define GPCMD_SEND_EVENT 0xa2 +#define GPCMD_SEND_KEY 0xa3 +#define GPCMD_SEND_OPC 0x54 +#define GPCMD_SET_READ_AHEAD 0xa7 +#define GPCMD_SET_STREAMING 0xb6 +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_VERIFY_10 0x2f +#define GPCMD_WRITE_10 0x2a +#define GPCMD_WRITE_AND_VERIFY_10 0x2e +/* This is listed as optional in ATAPI 2.6, but is (curiously) + * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji + * Table 377 as an MMC command for SCSi devices though... Most ATAPI + * drives support it. */ +#define GPCMD_SET_SPEED 0xbb +/* This seems to be a SCSI specific CD-ROM opcode + * to play data at track/index */ +#define GPCMD_PLAYAUDIO_TI 0x48 +/* + * From MS Media Status Notification Support Specification. For + * older drives only. + */ +#define GPCMD_GET_MEDIA_STATUS 0xda +#define GPCMD_MODE_SENSE_6 0x1a + +#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ +#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ +#define ATAPI_INT_REASON_REL 0x04 +#define ATAPI_INT_REASON_TAG 0xf8 + +/* same constants as bochs */ +#define ASC_NO_SEEK_COMPLETE 0x02 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LOGICAL_BLOCK_OOR 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_INCOMPATIBLE_FORMAT 0x30 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_MEDIA_REMOVAL_PREVENTED 0x53 + +#define CFA_NO_ERROR 0x00 +#define CFA_MISC_ERROR 0x09 +#define CFA_INVALID_COMMAND 0x20 +#define CFA_INVALID_ADDRESS 0x21 +#define CFA_ADDRESS_OVERFLOW 0x2f + +#define SMART_READ_DATA 0xd0 +#define SMART_READ_THRESH 0xd1 +#define SMART_ATTR_AUTOSAVE 0xd2 +#define SMART_SAVE_ATTR 0xd3 +#define SMART_EXECUTE_OFFLINE 0xd4 +#define SMART_READ_LOG 0xd5 +#define SMART_WRITE_LOG 0xd6 +#define SMART_ENABLE 0xd8 +#define SMART_DISABLE 0xd9 +#define SMART_STATUS 0xda + +typedef enum { IDE_HD, IDE_CD, IDE_CFATA } IDEDriveKind; + +typedef void EndTransferFunc(IDEState *); + +typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockCompletionFunc *); +typedef void DMAVoidFunc(IDEDMA *); +typedef int DMAIntFunc(IDEDMA *, int); +typedef int32_t DMAInt32Func(IDEDMA *, int32_t len); +typedef void DMAu32Func(IDEDMA *, uint32_t); +typedef void DMAStopFunc(IDEDMA *, bool); +typedef void DMARestartFunc(void *, int, RunState); + +struct unreported_events { + bool eject_request; + bool new_media; +}; + +enum ide_dma_cmd { + IDE_DMA_READ, + IDE_DMA_WRITE, + IDE_DMA_TRIM, + IDE_DMA_ATAPI, +}; + +#define ide_cmd_is_read(s) \ + ((s)->dma_cmd == IDE_DMA_READ) + +typedef struct IDEBufferedRequest { + QLIST_ENTRY(IDEBufferedRequest) list; + struct iovec iov; + QEMUIOVector qiov; + QEMUIOVector *original_qiov; + BlockCompletionFunc *original_cb; + void *original_opaque; + bool orphaned; +} IDEBufferedRequest; + +/* NOTE: IDEState represents in fact one drive */ +struct IDEState { + IDEBus *bus; + uint8_t unit; + /* ide config */ + IDEDriveKind drive_kind; + int cylinders, heads, sectors, chs_trans; + int64_t nb_sectors; + int mult_sectors; + int identify_set; + uint8_t identify_data[512]; + int drive_serial; + char drive_serial_str[21]; + char drive_model_str[41]; + uint64_t wwn; + /* ide regs */ + uint8_t feature; + uint8_t error; + uint32_t nsector; + uint8_t sector; + uint8_t lcyl; + uint8_t hcyl; + /* other part of tf for lba48 support */ + uint8_t hob_feature; + uint8_t hob_nsector; + uint8_t hob_sector; + uint8_t hob_lcyl; + uint8_t hob_hcyl; + + uint8_t select; + uint8_t status; + + /* set for lba48 access */ + uint8_t lba48; + BlockBackend *blk; + char version[9]; + /* ATAPI specific */ + struct unreported_events events; + uint8_t sense_key; + uint8_t asc; + bool tray_open; + bool tray_locked; + uint8_t cdrom_changed; + int packet_transfer_size; + int elementary_transfer_size; + int32_t io_buffer_index; + int lba; + int cd_sector_size; + int atapi_dma; /* true if dma is requested for the packet cmd */ + BlockAcctCookie acct; + BlockAIOCB *pio_aiocb; + struct iovec iov; + QEMUIOVector qiov; + QLIST_HEAD(, IDEBufferedRequest) buffered_requests; + /* ATA DMA state */ + uint64_t io_buffer_offset; + int32_t io_buffer_size; + QEMUSGList sg; + /* PIO transfer handling */ + int req_nb_sectors; /* number of sectors per interrupt */ + EndTransferFunc *end_transfer_func; + uint8_t *data_ptr; + uint8_t *data_end; + uint8_t *io_buffer; + /* PIO save/restore */ + int32_t io_buffer_total_len; + int32_t cur_io_buffer_offset; + int32_t cur_io_buffer_len; + uint8_t end_transfer_fn_idx; + QEMUTimer *sector_write_timer; /* only used for win2k install hack */ + uint32_t irq_count; /* counts IRQs when using win2k install hack */ + /* CF-ATA extended error */ + uint8_t ext_error; + /* CF-ATA metadata storage */ + uint32_t mdata_size; + uint8_t *mdata_storage; + int media_changed; + enum ide_dma_cmd dma_cmd; + /* SMART */ + uint8_t smart_enabled; + uint8_t smart_autosave; + int smart_errors; + uint8_t smart_selftest_count; + uint8_t *smart_selftest_data; + /* AHCI */ + int ncq_queues; +}; + +struct IDEDMAOps { + DMAStartFunc *start_dma; + DMAVoidFunc *start_transfer; + DMAInt32Func *prepare_buf; + DMAu32Func *commit_buf; + DMAIntFunc *rw_buf; + DMAVoidFunc *restart; + DMAVoidFunc *restart_dma; + DMAStopFunc *set_inactive; + DMAVoidFunc *cmd_done; + DMAVoidFunc *reset; +}; + +struct IDEDMA { + const struct IDEDMAOps *ops; + struct iovec iov; + QEMUIOVector qiov; + BlockAIOCB *aiocb; +}; + +struct IDEBus { + BusState qbus; + IDEDevice *master; + IDEDevice *slave; + IDEState ifs[2]; + QEMUBH *bh; + + int bus_id; + int max_units; + IDEDMA *dma; + uint8_t unit; + uint8_t cmd; + qemu_irq irq; + + int error_status; + uint8_t retry_unit; + int64_t retry_sector_num; + uint32_t retry_nsector; +}; + +#define TYPE_IDE_DEVICE "ide-device" +#define IDE_DEVICE(obj) \ + OBJECT_CHECK(IDEDevice, (obj), TYPE_IDE_DEVICE) +#define IDE_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(IDEDeviceClass, (klass), TYPE_IDE_DEVICE) +#define IDE_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(IDEDeviceClass, (obj), TYPE_IDE_DEVICE) + +typedef struct IDEDeviceClass { + DeviceClass parent_class; + int (*init)(IDEDevice *dev); +} IDEDeviceClass; + +struct IDEDevice { + DeviceState qdev; + uint32_t unit; + BlockConf conf; + int chs_trans; + char *version; + char *serial; + char *model; + uint64_t wwn; +}; + +/* These are used for the error_status field of IDEBus */ +#define IDE_RETRY_MASK 0xf8 +#define IDE_RETRY_DMA 0x08 +#define IDE_RETRY_PIO 0x10 +#define IDE_RETRY_ATAPI 0x20 /* reused IDE_RETRY_READ bit */ +#define IDE_RETRY_READ 0x20 +#define IDE_RETRY_FLUSH 0x40 +#define IDE_RETRY_TRIM 0x80 +#define IDE_RETRY_HBA 0x100 + +#define IS_IDE_RETRY_DMA(_status) \ + ((_status) & IDE_RETRY_DMA) + +#define IS_IDE_RETRY_PIO(_status) \ + ((_status) & IDE_RETRY_PIO) + +/* + * The method of the IDE_RETRY_ATAPI determination is to use a previously + * impossible bit combination as a new status value. + */ +#define IS_IDE_RETRY_ATAPI(_status) \ + (((_status) & IDE_RETRY_MASK) == IDE_RETRY_ATAPI) + +static inline uint8_t ide_dma_cmd_to_retry(uint8_t dma_cmd) +{ + switch (dma_cmd) { + case IDE_DMA_READ: + return IDE_RETRY_DMA | IDE_RETRY_READ; + case IDE_DMA_WRITE: + return IDE_RETRY_DMA; + case IDE_DMA_TRIM: + return IDE_RETRY_DMA | IDE_RETRY_TRIM; + case IDE_DMA_ATAPI: + return IDE_RETRY_ATAPI; + default: + break; + } + return 0; +} + +static inline IDEState *idebus_active_if(IDEBus *bus) +{ + return bus->ifs + bus->unit; +} + +static inline void ide_set_irq(IDEBus *bus) +{ + if (!(bus->cmd & IDE_CMD_DISABLE_IRQ)) { + qemu_irq_raise(bus->irq); + } +} + +/* hw/ide/core.c */ +extern const VMStateDescription vmstate_ide_bus; + +#define VMSTATE_IDE_BUS(_field, _state) \ + VMSTATE_STRUCT(_field, _state, 1, vmstate_ide_bus, IDEBus) + +#define VMSTATE_IDE_BUS_ARRAY(_field, _state, _num) \ + VMSTATE_STRUCT_ARRAY(_field, _state, _num, 1, vmstate_ide_bus, IDEBus) + +extern const VMStateDescription vmstate_ide_drive; + +#define VMSTATE_IDE_DRIVES(_field, _state) \ + VMSTATE_STRUCT_ARRAY(_field, _state, 2, 3, vmstate_ide_drive, IDEState) + +#define VMSTATE_IDE_DRIVE(_field, _state) \ + VMSTATE_STRUCT(_field, _state, 1, vmstate_ide_drive, IDEState) + +void ide_bus_reset(IDEBus *bus); +int64_t ide_get_sector(IDEState *s); +void ide_set_sector(IDEState *s, int64_t sector_num); + +void ide_start_dma(IDEState *s, BlockCompletionFunc *cb); +void dma_buf_commit(IDEState *s, uint32_t tx_bytes); +void ide_dma_error(IDEState *s); +void ide_abort_command(IDEState *s); + +void ide_atapi_cmd_ok(IDEState *s); +void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc); +void ide_atapi_dma_restart(IDEState *s); +void ide_atapi_io_error(IDEState *s, int ret); + +void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val); +uint32_t ide_ioport_read(void *opaque, uint32_t addr1); +uint32_t ide_status_read(void *opaque, uint32_t addr); +void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val); +void ide_data_writew(void *opaque, uint32_t addr, uint32_t val); +uint32_t ide_data_readw(void *opaque, uint32_t addr); +void ide_data_writel(void *opaque, uint32_t addr, uint32_t val); +uint32_t ide_data_readl(void *opaque, uint32_t addr); + +int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind, + const char *version, const char *serial, const char *model, + uint64_t wwn, + uint32_t cylinders, uint32_t heads, uint32_t secs, + int chs_trans); +void ide_init2(IDEBus *bus, qemu_irq irq); +void ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2); +void ide_register_restart_cb(IDEBus *bus); + +void ide_exec_cmd(IDEBus *bus, uint32_t val); + +void ide_transfer_start(IDEState *s, uint8_t *buf, int size, + EndTransferFunc *end_transfer_func); +void ide_transfer_stop(IDEState *s); +void ide_set_inactive(IDEState *s, bool more); +BlockAIOCB *ide_issue_trim(BlockBackend *blk, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockCompletionFunc *cb, void *opaque); +BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num, + QEMUIOVector *iov, int nb_sectors, + BlockCompletionFunc *cb, void *opaque); +void ide_cancel_dma_sync(IDEState *s); + +/* hw/ide/atapi.c */ +void ide_atapi_cmd(IDEState *s); +void ide_atapi_cmd_reply_end(IDEState *s); + +/* hw/ide/qdev.c */ +void ide_bus_new(IDEBus *idebus, size_t idebus_size, DeviceState *dev, + int bus_id, int max_units); +IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive); + +int ide_handle_rw_error(IDEState *s, int error, int op); + +#endif /* HW_IDE_INTERNAL_H */ diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 40213d662..eba567c87 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -23,13 +23,13 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/isa/isa.h" +#include <hw/hw.h> +#include <hw/i386/pc.h> +#include <hw/isa/isa.h> #include "sysemu/block-backend.h" #include "sysemu/dma.h" -#include "hw/ide/internal.h" +#include <hw/ide/internal.h> /***********************************************************/ /* ISA IDE definitions */ diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 76f97c253..664328d17 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -29,7 +29,7 @@ #include "sysemu/block-backend.h" #include "sysemu/dma.h" -#include "hw/ide/internal.h" +#include <hw/ide/internal.h> /* debug MACIO */ // #define DEBUG_MACIO @@ -55,8 +55,8 @@ static const int debug_macio = 0; /* * Unaligned DMA read/write access functions required for OS X/Darwin which * don't perform DMA transactions on sector boundaries. These functions are - * modelled on bdrv_co_preadv()/bdrv_co_pwritev() and so should be easy to - * remove if the unaligned block APIs are ever exposed. + * modelled on bdrv_co_do_preadv()/bdrv_co_do_pwritev() and so should be + * easy to remove if the unaligned block APIs are ever exposed. */ static void pmac_dma_read(BlockBackend *blk, @@ -66,7 +66,8 @@ static void pmac_dma_read(BlockBackend *blk, DBDMA_io *io = opaque; MACIOIDEState *m = io->opaque; IDEState *s = idebus_active_if(&m->bus); - dma_addr_t dma_addr; + dma_addr_t dma_addr, dma_len; + void *mem; int64_t sector_num; int nsector; uint64_t align = BDRV_SECTOR_SIZE; @@ -83,10 +84,9 @@ static void pmac_dma_read(BlockBackend *blk, sector_num, nsector); dma_addr = io->addr; - io->dir = DMA_DIRECTION_FROM_DEVICE; - io->dma_len = io->len; - io->dma_mem = dma_memory_map(&address_space_memory, dma_addr, &io->dma_len, - io->dir); + dma_len = io->len; + mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len, + DMA_DIRECTION_FROM_DEVICE); if (offset & (align - 1)) { head_bytes = offset & (align - 1); @@ -100,7 +100,7 @@ static void pmac_dma_read(BlockBackend *blk, offset = offset & ~(align - 1); } - qemu_iovec_add(&io->iov, io->dma_mem, io->len); + qemu_iovec_add(&io->iov, mem, io->len); if ((offset + bytes) & (align - 1)) { tail_bytes = (offset + bytes) & (align - 1); @@ -120,7 +120,8 @@ static void pmac_dma_read(BlockBackend *blk, MACIO_DPRINTF("--- Block read transfer - sector_num: %" PRIx64 " " "nsector: %x\n", (offset >> 9), (bytes >> 9)); - s->bus->dma->aiocb = blk_aio_preadv(blk, offset, &io->iov, 0, cb, io); + s->bus->dma->aiocb = blk_aio_readv(blk, (offset >> 9), &io->iov, + (bytes >> 9), cb, io); } static void pmac_dma_write(BlockBackend *blk, @@ -130,7 +131,8 @@ static void pmac_dma_write(BlockBackend *blk, DBDMA_io *io = opaque; MACIOIDEState *m = io->opaque; IDEState *s = idebus_active_if(&m->bus); - dma_addr_t dma_addr; + dma_addr_t dma_addr, dma_len; + void *mem; int64_t sector_num; int nsector; uint64_t align = BDRV_SECTOR_SIZE; @@ -148,10 +150,9 @@ static void pmac_dma_write(BlockBackend *blk, sector_num, nsector); dma_addr = io->addr; - io->dir = DMA_DIRECTION_TO_DEVICE; - io->dma_len = io->len; - io->dma_mem = dma_memory_map(&address_space_memory, dma_addr, &io->dma_len, - io->dir); + dma_len = io->len; + mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len, + DMA_DIRECTION_TO_DEVICE); if (offset & (align - 1)) { head_bytes = offset & (align - 1); @@ -163,7 +164,7 @@ static void pmac_dma_write(BlockBackend *blk, blk_pread(s->blk, (sector_num << 9), &io->head_remainder, align); qemu_iovec_add(&io->iov, &io->head_remainder, head_bytes); - qemu_iovec_add(&io->iov, io->dma_mem, io->len); + qemu_iovec_add(&io->iov, mem, io->len); bytes += offset & (align - 1); offset = offset & ~(align - 1); @@ -181,7 +182,7 @@ static void pmac_dma_write(BlockBackend *blk, blk_pread(s->blk, (sector_num << 9), &io->tail_remainder, align); if (!unaligned_head) { - qemu_iovec_add(&io->iov, io->dma_mem, io->len); + qemu_iovec_add(&io->iov, mem, io->len); } qemu_iovec_add(&io->iov, &io->tail_remainder + tail_bytes, @@ -193,7 +194,7 @@ static void pmac_dma_write(BlockBackend *blk, } if (!unaligned_head && !unaligned_tail) { - qemu_iovec_add(&io->iov, io->dma_mem, io->len); + qemu_iovec_add(&io->iov, mem, io->len); } s->io_buffer_size -= io->len; @@ -204,7 +205,8 @@ static void pmac_dma_write(BlockBackend *blk, MACIO_DPRINTF("--- Block write transfer - sector_num: %" PRIx64 " " "nsector: %x\n", (offset >> 9), (bytes >> 9)); - s->bus->dma->aiocb = blk_aio_pwritev(blk, offset, &io->iov, 0, cb, io); + s->bus->dma->aiocb = blk_aio_writev(blk, (offset >> 9), &io->iov, + (bytes >> 9), cb, io); } static void pmac_dma_trim(BlockBackend *blk, @@ -214,23 +216,24 @@ static void pmac_dma_trim(BlockBackend *blk, DBDMA_io *io = opaque; MACIOIDEState *m = io->opaque; IDEState *s = idebus_active_if(&m->bus); - dma_addr_t dma_addr; + dma_addr_t dma_addr, dma_len; + void *mem; qemu_iovec_destroy(&io->iov); qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1); dma_addr = io->addr; - io->dir = DMA_DIRECTION_TO_DEVICE; - io->dma_len = io->len; - io->dma_mem = dma_memory_map(&address_space_memory, dma_addr, &io->dma_len, - io->dir); + dma_len = io->len; + mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len, + DMA_DIRECTION_TO_DEVICE); - qemu_iovec_add(&io->iov, io->dma_mem, io->len); + qemu_iovec_add(&io->iov, mem, io->len); s->io_buffer_size -= io->len; s->io_buffer_index += io->len; io->len = 0; - s->bus->dma->aiocb = ide_issue_trim(offset, &io->iov, cb, io, blk); + s->bus->dma->aiocb = ide_issue_trim(blk, (offset >> 9), &io->iov, + (bytes >> 9), cb, io); } static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) @@ -271,8 +274,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) if (s->lba == -1) { /* Non-block ATAPI transfer - just copy to RAM */ s->io_buffer_size = MIN(s->io_buffer_size, io->len); - dma_memory_write(&address_space_memory, io->addr, s->io_buffer, - s->io_buffer_size); + cpu_physical_memory_write(io->addr, s->io_buffer, s->io_buffer_size); io->len = 0; ide_atapi_cmd_ok(s); m->dma_active = false; @@ -286,9 +288,6 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) return; done: - dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len, - io->dir, io->dma_len); - if (ret < 0) { block_acct_failed(blk_get_stats(s->blk), &s->acct); } else { @@ -355,9 +354,6 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) return; done: - dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len, - io->dir, io->dma_len); - if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) { if (ret < 0) { block_acct_failed(blk_get_stats(s->blk), &s->acct); @@ -407,7 +403,7 @@ static void pmac_ide_flush(DBDMA_io *io) IDEState *s = idebus_active_if(&m->bus); if (s->bus->dma->aiocb) { - blk_drain(s->blk); + blk_drain_all(); } } diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index e3fd30e45..5c9db8047 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -23,13 +23,13 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/pcmcia.h" +#include <hw/hw.h> +#include <hw/i386/pc.h> +#include <hw/pcmcia.h> #include "sysemu/block-backend.h" #include "sysemu/dma.h" -#include "hw/ide/internal.h" +#include <hw/ide/internal.h> #define TYPE_MICRODRIVE "microdrive" #define MICRODRIVE(obj) OBJECT_CHECK(MicroDriveState, (obj), TYPE_MICRODRIVE) diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 6f12f456e..493f65a1d 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -28,7 +28,7 @@ #include "sysemu/block-backend.h" #include "sysemu/dma.h" -#include "hw/ide/internal.h" +#include <hw/ide/internal.h> /***********************************************************/ /* MMIO based ide port diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 3cfb510af..8d56a00b1 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -23,14 +23,14 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci.h" -#include "hw/isa/isa.h" +#include <hw/hw.h> +#include <hw/i386/pc.h> +#include <hw/pci/pci.h> +#include <hw/isa/isa.h> #include "sysemu/block-backend.h" #include "sysemu/dma.h" #include "qemu/error-report.h" -#include "hw/ide/pci.h" +#include <hw/ide/pci.h> #define BMDMA_PAGE_SIZE 4096 diff --git a/hw/ide/pci.h b/hw/ide/pci.h new file mode 100644 index 000000000..0f2d4b91a --- /dev/null +++ b/hw/ide/pci.h @@ -0,0 +1,76 @@ +#ifndef HW_IDE_PCI_H +#define HW_IDE_PCI_H + +#include <hw/ide/internal.h> + +#define BM_STATUS_DMAING 0x01 +#define BM_STATUS_ERROR 0x02 +#define BM_STATUS_INT 0x04 + +#define BM_CMD_START 0x01 +#define BM_CMD_READ 0x08 + +typedef struct BMDMAState { + IDEDMA dma; + uint8_t cmd; + uint8_t status; + uint32_t addr; + + IDEBus *bus; + /* current transfer state */ + uint32_t cur_addr; + uint32_t cur_prd_last; + uint32_t cur_prd_addr; + uint32_t cur_prd_len; + BlockCompletionFunc *dma_cb; + MemoryRegion addr_ioport; + MemoryRegion extra_io; + qemu_irq irq; + + /* Bit 0-2 and 7: BM status register + * Bit 3-6: bus->error_status */ + uint8_t migration_compat_status; + uint8_t migration_retry_unit; + int64_t migration_retry_sector_num; + uint32_t migration_retry_nsector; + + struct PCIIDEState *pci_dev; +} BMDMAState; + +typedef struct CMD646BAR { + MemoryRegion cmd; + MemoryRegion data; + IDEBus *bus; + struct PCIIDEState *pci_dev; +} CMD646BAR; + +#define TYPE_PCI_IDE "pci-ide" +#define PCI_IDE(obj) OBJECT_CHECK(PCIIDEState, (obj), TYPE_PCI_IDE) + +typedef struct PCIIDEState { + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ + + IDEBus bus[2]; + BMDMAState bmdma[2]; + uint32_t secondary; /* used only for cmd646 */ + MemoryRegion bmdma_bar; + CMD646BAR cmd646_bar[2]; /* used only for cmd646 */ +} PCIIDEState; + + +static inline IDEState *bmdma_active_if(BMDMAState *bmdma) +{ + assert(bmdma->bus->retry_unit != (uint8_t)-1); + return bmdma->bus->ifs + bmdma->bus->retry_unit; +} + + +void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d); +void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val); +extern MemoryRegionOps bmdma_addr_ioport_ops; +void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table); + +extern const VMStateDescription vmstate_ide_pci; +#endif diff --git a/hw/ide/piix.c b/hw/ide/piix.c index c190fcaa3..6d76ce980 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -24,15 +24,15 @@ */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci.h" -#include "hw/isa/isa.h" +#include <hw/hw.h> +#include <hw/i386/pc.h> +#include <hw/pci/pci.h> +#include <hw/isa/isa.h> #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" -#include "hw/ide/pci.h" +#include <hw/ide/pci.h> static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size) { diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 67c76bfcd..4bc74a32d 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -17,11 +17,11 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu/osdep.h" -#include "hw/hw.h" +#include <hw/hw.h> #include "sysemu/dma.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "hw/ide/internal.h" +#include <hw/ide/internal.h> #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "hw/block/block.h" @@ -180,7 +180,6 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind) return -1; } } - blkconf_apply_backend_options(&dev->conf); if (ide_init_drive(s, dev->conf.blk, kind, dev->version, dev->serial, dev->model, dev->wwn, @@ -234,7 +233,9 @@ static void ide_dev_set_bootindex(Object *obj, Visitor *v, const char *name, d->unit ? "/disk@1" : "/disk@0"); } out: - error_propagate(errp, local_err); + if (local_err) { + error_propagate(errp, local_err); + } } static void ide_dev_instance_init(Object *obj) @@ -264,7 +265,6 @@ static int ide_drive_initfn(IDEDevice *dev) #define DEFINE_IDE_DEV_PROPERTIES() \ DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf), \ - DEFINE_BLOCK_ERROR_PROPERTIES(IDEDrive, dev.conf), \ DEFINE_PROP_STRING("ver", IDEDrive, dev.version), \ DEFINE_PROP_UINT64("wwn", IDEDrive, dev.wwn, 0), \ DEFINE_PROP_STRING("serial", IDEDrive, dev.serial),\ diff --git a/hw/ide/via.c b/hw/ide/via.c index 5b32ecb38..d3f72267a 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -24,15 +24,15 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci.h" -#include "hw/isa/isa.h" +#include <hw/hw.h> +#include <hw/i386/pc.h> +#include <hw/pci/pci.h> +#include <hw/isa/isa.h> #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" -#include "hw/ide/pci.h" +#include <hw/ide/pci.h> static uint64_t bmdma_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/input/hid.c b/hw/input/hid.c index 5e2850e65..d92c7463b 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -27,7 +27,6 @@ #include "ui/console.h" #include "qemu/timer.h" #include "hw/input/hid.h" -#include "trace.h" #define HID_USAGE_ERROR_ROLLOVER 0x01 #define HID_USAGE_POSTFAIL 0x02 @@ -235,7 +234,7 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src, key->down, scancodes); if (hs->n + count > QUEUE_LENGTH) { - trace_hid_kbd_queue_full(); + fprintf(stderr, "usb-kbd: warning: key event queue full\n"); return; } for (i = 0; i < count; i++) { diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index dc57e2c76..1d932ec19 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -146,7 +146,7 @@ typedef struct KBDState { qemu_irq irq_kbd; qemu_irq irq_mouse; - qemu_irq a20_out; + qemu_irq *a20_out; hwaddr mask; } KBDState; @@ -224,7 +224,9 @@ static void outport_write(KBDState *s, uint32_t val) { DPRINTF("kbd: write outport=0x%02x\n", val); s->outport = val; - qemu_set_irq(s->a20_out, (val >> 1) & 1); + if (s->a20_out) { + qemu_set_irq(*s->a20_out, (val >> 1) & 1); + } if (!(val & 1)) { qemu_system_reset_request(); } @@ -293,11 +295,15 @@ static void kbd_write_command(void *opaque, hwaddr addr, kbd_queue(s, s->outport, 0); break; case KBD_CCMD_ENABLE_A20: - qemu_irq_raise(s->a20_out); + if (s->a20_out) { + qemu_irq_raise(*s->a20_out); + } s->outport |= KBD_OUT_A20; break; case KBD_CCMD_DISABLE_A20: - qemu_irq_lower(s->a20_out); + if (s->a20_out) { + qemu_irq_lower(*s->a20_out); + } s->outport &= ~KBD_OUT_A20; break; case KBD_CCMD_RESET: @@ -501,7 +507,10 @@ void i8042_isa_mouse_fake_event(void *opaque) void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out) { - qdev_connect_gpio_out_named(DEVICE(dev), I8042_A20_LINE, 0, *a20_out); + ISAKBDState *isa = I8042(dev); + KBDState *s = &isa->kbd; + + s->a20_out = a20_out; } static const VMStateDescription vmstate_kbd_isa = { @@ -543,8 +552,6 @@ static void i8042_initfn(Object *obj) "i8042-data", 1); memory_region_init_io(isa_s->io + 1, obj, &i8042_cmd_ops, s, "i8042-cmd", 1); - - qdev_init_gpio_out_named(DEVICE(obj), &s->a20_out, I8042_A20_LINE, 1); } static void i8042_realizefn(DeviceState *dev, Error **errp) diff --git a/hw/input/pl050.c b/hw/input/pl050.c index be9cd57b1..3092b0fe3 100644 --- a/hw/input/pl050.c +++ b/hw/input/pl050.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "hw/input/ps2.h" -#include "qemu/log.h" #define TYPE_PL050 "pl050" #define PL050(obj) OBJECT_CHECK(PL050State, (obj), TYPE_PL050) diff --git a/hw/input/trace-events b/hw/input/trace-events deleted file mode 100644 index 8c4003f36..000000000 --- a/hw/input/trace-events +++ /dev/null @@ -1,31 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/input/ps2.c -ps2_put_keycode(void *opaque, int keycode) "%p keycode %d" -ps2_read_data(void *opaque) "%p" -ps2_set_ledstate(void *s, int ledstate) "%p ledstate %d" -ps2_reset_keyboard(void *s) "%p" -ps2_write_keyboard(void *opaque, int val) "%p val %d" -ps2_keyboard_set_translation(void *opaque, int mode) "%p mode %d" -ps2_mouse_send_packet(void *s, int dx1, int dy1, int dz1, int b) "%p x %d y %d z %d bs %#x" -ps2_mouse_event_disabled(void *opaque, int dx, int dy, int dz, int buttons_state, int mouse_dx, int mouse_dy, int mouse_dz) "%p x %d y %d z %d bs %#x mx %d my %d mz %d " -ps2_mouse_event(void *opaque, int dx, int dy, int dz, int buttons_state, int mouse_dx, int mouse_dy, int mouse_dz) "%p x %d y %d z %d bs %#x mx %d my %d mz %d " -ps2_mouse_fake_event(void *opaque) "%p" -ps2_write_mouse(void *opaque, int val) "%p val %d" -ps2_kbd_reset(void *opaque) "%p" -ps2_mouse_reset(void *opaque) "%p" -ps2_kbd_init(void *s) "%p" -ps2_mouse_init(void *s) "%p" - -# hw/input/milkymist-softusb.c -milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_softusb_mevt(uint8_t m) "m %d" -milkymist_softusb_kevt(uint8_t m) "m %d" -milkymist_softusb_pulse_irq(void) "Pulse IRQ" - -# hw/input/hid.c -hid_kbd_queue_full(void) "queue full" - -# hw/input/virtio -virtio_input_queue_full(void) "queue full" diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index ccdf7308a..f59749a94 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -7,7 +7,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/iov.h" -#include "trace.h" #include "hw/qdev.h" #include "hw/virtio/virtio.h" @@ -48,7 +47,7 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) virtqueue_get_avail_bytes(vinput->evt, &have, NULL, need, 0); if (have < need) { vinput->qindex = 0; - trace_virtio_input_queue_full(); + fprintf(stderr, "%s: ENOSPC in vq, dropping events\n", __func__); return; } @@ -217,14 +216,26 @@ static void virtio_input_reset(VirtIODevice *vdev) } } -static int virtio_input_load(QEMUFile *f, void *opaque, size_t size) +static void virtio_input_save(QEMUFile *f, void *opaque) +{ + VirtIOInput *vinput = opaque; + VirtIODevice *vdev = VIRTIO_DEVICE(vinput); + + virtio_save(vdev, f); +} + +static int virtio_input_load(QEMUFile *f, void *opaque, int version_id) { VirtIOInput *vinput = opaque; VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vinput); VirtIODevice *vdev = VIRTIO_DEVICE(vinput); int ret; - ret = virtio_load(vdev, f, VIRTIO_INPUT_VM_VERSION); + if (version_id != VIRTIO_INPUT_VM_VERSION) { + return -EINVAL; + } + + ret = virtio_load(vdev, f, version_id); if (ret) { return ret; } @@ -268,24 +279,20 @@ static void virtio_input_device_realize(DeviceState *dev, Error **errp) vinput->cfg_size); vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt); vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts); -} - -static void virtio_input_finalize(Object *obj) -{ - VirtIOInput *vinput = VIRTIO_INPUT(obj); - VirtIOInputConfig *cfg, *next; - QTAILQ_FOREACH_SAFE(cfg, &vinput->cfg_list, node, next) { - QTAILQ_REMOVE(&vinput->cfg_list, cfg, node); - g_free(cfg); - } + register_savevm(dev, "virtio-input", -1, VIRTIO_INPUT_VM_VERSION, + virtio_input_save, virtio_input_load, vinput); } + static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) { VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOInput *vinput = VIRTIO_INPUT(dev); Error *local_err = NULL; + unregister_savevm(dev, "virtio-input", vinput); + if (vic->unrealize) { vic->unrealize(dev, &local_err); if (local_err) { @@ -296,9 +303,6 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) virtio_cleanup(vdev); } -VMSTATE_VIRTIO_DEVICE(input, VIRTIO_INPUT_VM_VERSION, virtio_input_load, - virtio_vmstate_save); - static Property virtio_input_properties[] = { DEFINE_PROP_STRING("serial", VirtIOInput, serial), DEFINE_PROP_END_OF_LIST(), @@ -310,7 +314,6 @@ static void virtio_input_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->props = virtio_input_properties; - dc->vmsd = &vmstate_virtio_input; set_bit(DEVICE_CATEGORY_INPUT, dc->categories); vdc->realize = virtio_input_device_realize; vdc->unrealize = virtio_input_device_unrealize; @@ -328,7 +331,6 @@ static const TypeInfo virtio_input_info = { .class_size = sizeof(VirtIOInputClass), .class_init = virtio_input_class_init, .abstract = true, - .instance_finalize = virtio_input_finalize, }; /* ----------------------------------------------------------------- */ diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 05ec21b21..0e47f0f9e 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -13,9 +13,6 @@ common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o common-obj-$(CONFIG_ARM_GIC) += arm_gic.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_common.o -common-obj-$(CONFIG_ARM_GIC) += arm_gicv3.o -common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o -common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o common-obj-$(CONFIG_OPENPIC) += openpic.o obj-$(CONFIG_APIC) += apic.o apic_common.o @@ -30,11 +27,8 @@ obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o obj-$(CONFIG_RASPI) += bcm2835_ic.o bcm2836_control.o obj-$(CONFIG_SH4) += sh_intc.o obj-$(CONFIG_XICS) += xics.o -obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.o obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o obj-$(CONFIG_ASPEED_SOC) += aspeed_vic.o -obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o -obj-$(CONFIG_MIPS_CPS) += mips_gic.o diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c index 11f13663c..dc971a160 100644 --- a/hw/intc/allwinner-a10-pic.c +++ b/hw/intc/allwinner-a10-pic.c @@ -20,7 +20,6 @@ #include "hw/devices.h" #include "sysemu/sysemu.h" #include "hw/intc/allwinner-a10-pic.h" -#include "qemu/log.h" static void aw_a10_pic_update(AwA10PICState *s) { diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 45887d99c..28c2ea540 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -17,8 +17,6 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/> */ #include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" #include "qemu/thread.h" #include "hw/i386/apic_internal.h" #include "hw/i386/apic.h" @@ -28,9 +26,7 @@ #include "trace.h" #include "hw/i386/pc.h" #include "hw/i386/apic-msidef.h" -#include "qapi/error.h" -#define MAX_APICS 255 #define MAX_APIC_WORDS 8 #define SYNC_FROM_VAPIC 0x1 @@ -421,7 +417,7 @@ static int apic_find_dest(uint8_t dest) int i; if (apic && apic->id == dest) - return dest; /* shortcut in case apic->id == local_apics[dest]->id */ + return dest; /* shortcut in case apic->id == apic->idx */ for (i = 0; i < MAX_APICS; i++) { apic = local_apics[i]; @@ -504,14 +500,14 @@ static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode, break; case 1: memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask)); - apic_set_bit(deliver_bitmask, s->id); + apic_set_bit(deliver_bitmask, s->idx); break; case 2: memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); break; case 3: memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); - apic_reset_bit(deliver_bitmask, s->id); + apic_reset_bit(deliver_bitmask, s->idx); break; } @@ -872,36 +868,20 @@ static void apic_realize(DeviceState *dev, Error **errp) { APICCommonState *s = APIC_COMMON(dev); - if (s->id >= MAX_APICS) { - error_setg(errp, "%s initialization failed. APIC ID %d is invalid", - object_get_typename(OBJECT(dev)), s->id); - return; - } - memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi", APIC_SPACE_SIZE); s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s); - local_apics[s->id] = s; + local_apics[s->idx] = s; msi_nonbroken = true; } -static void apic_unrealize(DeviceState *dev, Error **errp) -{ - APICCommonState *s = APIC_COMMON(dev); - - timer_del(s->timer); - timer_free(s->timer); - local_apics[s->id] = NULL; -} - static void apic_class_init(ObjectClass *klass, void *data) { APICCommonClass *k = APIC_COMMON_CLASS(klass); k->realize = apic_realize; - k->unrealize = apic_unrealize; k->set_base = apic_set_base; k->set_tpr = apic_set_tpr; k->get_tpr = apic_get_tpr; diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 14ac43c18..4abe145c6 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -19,8 +19,6 @@ */ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" #include "hw/i386/apic.h" #include "hw/i386/apic_internal.h" #include "trace.h" @@ -294,14 +292,19 @@ static int apic_load_old(QEMUFile *f, void *opaque, int version_id) return 0; } -static const VMStateDescription vmstate_apic_common; - static void apic_common_realize(DeviceState *dev, Error **errp) { APICCommonState *s = APIC_COMMON(dev); APICCommonClass *info; static DeviceState *vapic; - int instance_id = s->id; + static int apic_no; + + if (apic_no >= MAX_APICS) { + error_setg(errp, "%s initialization failed.", + object_get_typename(OBJECT(dev))); + return; + } + s->idx = apic_no++; info = APIC_COMMON_GET_CLASS(s); info->realize(dev, errp); @@ -316,24 +319,6 @@ static void apic_common_realize(DeviceState *dev, Error **errp) info->enable_tpr_reporting(s, true); } - if (s->legacy_instance_id) { - instance_id = -1; - } - vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common, - s, -1, 0); -} - -static void apic_common_unrealize(DeviceState *dev, Error **errp) -{ - APICCommonState *s = APIC_COMMON(dev); - APICCommonClass *info = APIC_COMMON_GET_CLASS(s); - - vmstate_unregister(NULL, &vmstate_apic_common, s); - info->unrealize(dev, errp); - - if (apic_report_tpr_access && info->enable_tpr_reporting) { - info->enable_tpr_reporting(s, false); - } } static int apic_pre_load(void *opaque) @@ -431,8 +416,6 @@ static Property apic_properties_common[] = { DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14), DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT, true), - DEFINE_PROP_BOOL("legacy-instance-id", APICCommonState, legacy_instance_id, - false), DEFINE_PROP_END_OF_LIST(), }; @@ -440,10 +423,10 @@ static void apic_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->vmsd = &vmstate_apic_common; dc->reset = apic_reset_common; dc->props = apic_properties_common; dc->realize = apic_common_realize; - dc->unrealize = apic_common_unrealize; /* * Reason: APIC and CPU need to be wired up by * x86_cpu_apic_create() diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index b30cc9174..f55124174 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -23,8 +23,6 @@ #include "gic_internal.h" #include "qapi/error.h" #include "qom/cpu.h" -#include "qemu/log.h" -#include "trace.h" //#define DEBUG_GIC @@ -95,11 +93,6 @@ void gic_update(GICState *s) } } - if (best_irq != 1023) { - trace_gic_update_bestirq(cpu, best_irq, best_prio, - s->priority_mask[cpu], s->running_priority[cpu]); - } - irq_level = fiq_level = 0; if (best_prio < s->priority_mask[cpu]) { @@ -113,12 +106,10 @@ void gic_update(GICState *s) DPRINTF("Raised pending FIQ %d (cpu %d)\n", best_irq, cpu); fiq_level = 1; - trace_gic_update_set_irq(cpu, "fiq", fiq_level); } else { DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu); irq_level = 1; - trace_gic_update_set_irq(cpu, "irq", irq_level); } } } @@ -206,7 +197,6 @@ static void gic_set_irq(void *opaque, int irq, int level) } else { gic_set_irq_generic(s, irq, level, cm, target); } - trace_gic_set_irq(irq, level, cm, target); gic_update(s); } @@ -342,7 +332,6 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu, MemTxAttrs attrs) * is in the wrong group. */ irq = gic_get_current_pending_irq(s, cpu, attrs); - trace_gic_acknowledge_irq(cpu, irq); if (irq >= GIC_MAXIRQ) { DPRINTF("ACK, no pending interrupt or it is hidden: %d\n", irq); @@ -661,11 +650,6 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) goto bad_reg; res = 0; for (i = 0; i < 8; i++) { - if (s->security_extn && !attrs.secure && - !GIC_TEST_GROUP(irq + i, 1 << cpu)) { - continue; /* Ignore Non-secure access of Group0 IRQ */ - } - if (GIC_TEST_ENABLED(irq + i, cm)) { res |= (1 << i); } @@ -682,11 +666,6 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) res = 0; mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; for (i = 0; i < 8; i++) { - if (s->security_extn && !attrs.secure && - !GIC_TEST_GROUP(irq + i, 1 << cpu)) { - continue; /* Ignore Non-secure access of Group0 IRQ */ - } - if (gic_test_pending(s, irq + i, mask)) { res |= (1 << i); } @@ -699,11 +678,6 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) res = 0; mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; for (i = 0; i < 8; i++) { - if (s->security_extn && !attrs.secure && - !GIC_TEST_GROUP(irq + i, 1 << cpu)) { - continue; /* Ignore Non-secure access of Group0 IRQ */ - } - if (GIC_TEST_ACTIVE(irq + i, mask)) { res |= (1 << i); } @@ -737,11 +711,6 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) goto bad_reg; res = 0; for (i = 0; i < 4; i++) { - if (s->security_extn && !attrs.secure && - !GIC_TEST_GROUP(irq + i, 1 << cpu)) { - continue; /* Ignore Non-secure access of Group0 IRQ */ - } - if (GIC_TEST_MODEL(irq + i)) res |= (1 << (i * 2)); if (GIC_TEST_EDGE_TRIGGER(irq + i)) @@ -762,12 +731,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) /* GICD_SPENDSGIRn */ } - if (s->security_extn && !attrs.secure && - !GIC_TEST_GROUP(irq, 1 << cpu)) { - res = 0; /* Ignore Non-secure access of Group0 IRQ */ - } else { - res = s->sgi_pending[irq][cpu]; - } + res = s->sgi_pending[irq][cpu]; } else if (offset < 0xfd0) { goto bad_reg; } else if (offset < 0x1000) { @@ -887,14 +851,8 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; - if (s->security_extn && !attrs.secure && - !GIC_TEST_GROUP(irq + i, 1 << cpu)) { - continue; /* Ignore Non-secure access of Group0 IRQ */ - } - if (!GIC_TEST_ENABLED(irq + i, cm)) { DPRINTF("Enabled IRQ %d\n", irq + i); - trace_gic_enable_irq(irq + i); } GIC_SET_ENABLED(irq + i, cm); /* If a raised level triggered IRQ enabled then mark @@ -919,14 +877,8 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, if (value & (1 << i)) { int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; - if (s->security_extn && !attrs.secure && - !GIC_TEST_GROUP(irq + i, 1 << cpu)) { - continue; /* Ignore Non-secure access of Group0 IRQ */ - } - if (GIC_TEST_ENABLED(irq + i, cm)) { DPRINTF("Disabled IRQ %d\n", irq + i); - trace_gic_disable_irq(irq + i); } GIC_CLEAR_ENABLED(irq + i, cm); } @@ -942,11 +894,6 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, for (i = 0; i < 8; i++) { if (value & (1 << i)) { - if (s->security_extn && !attrs.secure && - !GIC_TEST_GROUP(irq + i, 1 << cpu)) { - continue; /* Ignore Non-secure access of Group0 IRQ */ - } - GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); } } @@ -960,11 +907,6 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } for (i = 0; i < 8; i++) { - if (s->security_extn && !attrs.secure && - !GIC_TEST_GROUP(irq + i, 1 << cpu)) { - continue; /* Ignore Non-secure access of Group0 IRQ */ - } - /* ??? This currently clears the pending bit for all CPUs, even for per-CPU interrupts. It's unclear whether this is the corect behavior. */ @@ -1005,11 +947,6 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, if (irq < GIC_NR_SGIS) value |= 0xaa; for (i = 0; i < 4; i++) { - if (s->security_extn && !attrs.secure && - !GIC_TEST_GROUP(irq + i, 1 << cpu)) { - continue; /* Ignore Non-secure access of Group0 IRQ */ - } - if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { if (value & (1 << (i * 2))) { GIC_SET_MODEL(irq + i); @@ -1033,12 +970,9 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } irq = (offset - 0xf10); - if (!s->security_extn || attrs.secure || - GIC_TEST_GROUP(irq, 1 << cpu)) { - s->sgi_pending[irq][cpu] &= ~value; - if (s->sgi_pending[irq][cpu] == 0) { - GIC_CLEAR_PENDING(irq, 1 << cpu); - } + s->sgi_pending[irq][cpu] &= ~value; + if (s->sgi_pending[irq][cpu] == 0) { + GIC_CLEAR_PENDING(irq, 1 << cpu); } } else if (offset < 0xf30) { /* GICD_SPENDSGIRn */ @@ -1047,11 +981,8 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } irq = (offset - 0xf20); - if (!s->security_extn || attrs.secure || - GIC_TEST_GROUP(irq, 1 << cpu)) { - GIC_SET_PENDING(irq, 1 << cpu); - s->sgi_pending[irq][cpu] |= value; - } + GIC_SET_PENDING(irq, 1 << cpu); + s->sgi_pending[irq][cpu] |= value; } else { goto bad_reg; } diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 5593cdb3e..bc85ab769 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -21,8 +21,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" #include "hw/sysbus.h" #include "migration/migration.h" #include "sysemu/kvm.h" diff --git a/hw/intc/arm_gicv2m.c b/hw/intc/arm_gicv2m.c index 3922fbc1c..e8b5177dc 100644 --- a/hw/intc/arm_gicv2m.c +++ b/hw/intc/arm_gicv2m.c @@ -29,8 +29,6 @@ #include "qapi/error.h" #include "hw/sysbus.h" #include "hw/pci/msi.h" -#include "sysemu/kvm.h" -#include "qemu/log.h" #define TYPE_ARM_GICV2M "arm-gicv2m" #define ARM_GICV2M(obj) OBJECT_CHECK(ARMGICv2mState, (obj), TYPE_ARM_GICV2M) diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c deleted file mode 100644 index 8a6c64721..000000000 --- a/hw/intc/arm_gicv3.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * ARM Generic Interrupt Controller v3 - * - * Copyright (c) 2015 Huawei. - * Copyright (c) 2016 Linaro Limited - * Written by Shlomo Pongratz, Peter Maydell - * - * This code is licensed under the GPL, version 2 or (at your option) - * any later version. - */ - -/* This file contains implementation code for an interrupt controller - * which implements the GICv3 architecture. Specifically this is where - * the device class itself and the functions for handling interrupts - * coming in and going out live. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/sysbus.h" -#include "hw/intc/arm_gicv3.h" -#include "gicv3_internal.h" - -static bool irqbetter(GICv3CPUState *cs, int irq, uint8_t prio) -{ - /* Return true if this IRQ at this priority should take - * precedence over the current recorded highest priority - * pending interrupt for this CPU. We also return true if - * the current recorded highest priority pending interrupt - * is the same as this one (a property which the calling code - * relies on). - */ - if (prio < cs->hppi.prio) { - return true; - } - /* If multiple pending interrupts have the same priority then it is an - * IMPDEF choice which of them to signal to the CPU. We choose to - * signal the one with the lowest interrupt number. - */ - if (prio == cs->hppi.prio && irq <= cs->hppi.irq) { - return true; - } - return false; -} - -static uint32_t gicd_int_pending(GICv3State *s, int irq) -{ - /* Recalculate which distributor interrupts are actually pending - * in the group of 32 interrupts starting at irq (which should be a multiple - * of 32), and return a 32-bit integer which has a bit set for each - * interrupt that is eligible to be signaled to the CPU interface. - * - * An interrupt is pending if: - * + the PENDING latch is set OR it is level triggered and the input is 1 - * + its ENABLE bit is set - * + the GICD enable bit for its group is set - * Conveniently we can bulk-calculate this with bitwise operations. - */ - uint32_t pend, grpmask; - uint32_t pending = *gic_bmp_ptr32(s->pending, irq); - uint32_t edge_trigger = *gic_bmp_ptr32(s->edge_trigger, irq); - uint32_t level = *gic_bmp_ptr32(s->level, irq); - uint32_t group = *gic_bmp_ptr32(s->group, irq); - uint32_t grpmod = *gic_bmp_ptr32(s->grpmod, irq); - uint32_t enable = *gic_bmp_ptr32(s->enabled, irq); - - pend = pending | (~edge_trigger & level); - pend &= enable; - - if (s->gicd_ctlr & GICD_CTLR_DS) { - grpmod = 0; - } - - grpmask = 0; - if (s->gicd_ctlr & GICD_CTLR_EN_GRP1NS) { - grpmask |= group; - } - if (s->gicd_ctlr & GICD_CTLR_EN_GRP1S) { - grpmask |= (~group & grpmod); - } - if (s->gicd_ctlr & GICD_CTLR_EN_GRP0) { - grpmask |= (~group & ~grpmod); - } - pend &= grpmask; - - return pend; -} - -static uint32_t gicr_int_pending(GICv3CPUState *cs) -{ - /* Recalculate which redistributor interrupts are actually pending, - * and return a 32-bit integer which has a bit set for each interrupt - * that is eligible to be signaled to the CPU interface. - * - * An interrupt is pending if: - * + the PENDING latch is set OR it is level triggered and the input is 1 - * + its ENABLE bit is set - * + the GICD enable bit for its group is set - * Conveniently we can bulk-calculate this with bitwise operations. - */ - uint32_t pend, grpmask, grpmod; - - pend = cs->gicr_ipendr0 | (~cs->edge_trigger & cs->level); - pend &= cs->gicr_ienabler0; - - if (cs->gic->gicd_ctlr & GICD_CTLR_DS) { - grpmod = 0; - } else { - grpmod = cs->gicr_igrpmodr0; - } - - grpmask = 0; - if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) { - grpmask |= cs->gicr_igroupr0; - } - if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1S) { - grpmask |= (~cs->gicr_igroupr0 & grpmod); - } - if (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP0) { - grpmask |= (~cs->gicr_igroupr0 & ~grpmod); - } - pend &= grpmask; - - return pend; -} - -/* Update the interrupt status after state in a redistributor - * or CPU interface has changed, but don't tell the CPU i/f. - */ -static void gicv3_redist_update_noirqset(GICv3CPUState *cs) -{ - /* Find the highest priority pending interrupt among the - * redistributor interrupts (SGIs and PPIs). - */ - bool seenbetter = false; - uint8_t prio; - int i; - uint32_t pend; - - /* Find out which redistributor interrupts are eligible to be - * signaled to the CPU interface. - */ - pend = gicr_int_pending(cs); - - if (pend) { - for (i = 0; i < GIC_INTERNAL; i++) { - if (!(pend & (1 << i))) { - continue; - } - prio = cs->gicr_ipriorityr[i]; - if (irqbetter(cs, i, prio)) { - cs->hppi.irq = i; - cs->hppi.prio = prio; - seenbetter = true; - } - } - } - - if (seenbetter) { - cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq); - } - - /* If the best interrupt we just found would preempt whatever - * was the previous best interrupt before this update, then - * we know it's definitely the best one now. - * If we didn't find an interrupt that would preempt the previous - * best, and the previous best is outside our range (or there was no - * previous pending interrupt at all), then that is still valid, and - * we leave it as the best. - * Otherwise, we need to do a full update (because the previous best - * interrupt has reduced in priority and any other interrupt could - * now be the new best one). - */ - if (!seenbetter && cs->hppi.prio != 0xff && cs->hppi.irq < GIC_INTERNAL) { - gicv3_full_update_noirqset(cs->gic); - } -} - -/* Update the GIC status after state in a redistributor or - * CPU interface has changed, and inform the CPU i/f of - * its new highest priority pending interrupt. - */ -void gicv3_redist_update(GICv3CPUState *cs) -{ - gicv3_redist_update_noirqset(cs); - gicv3_cpuif_update(cs); -} - -/* Update the GIC status after state in the distributor has - * changed affecting @len interrupts starting at @start, - * but don't tell the CPU i/f. - */ -static void gicv3_update_noirqset(GICv3State *s, int start, int len) -{ - int i; - uint8_t prio; - uint32_t pend = 0; - - assert(start >= GIC_INTERNAL); - assert(len > 0); - - for (i = 0; i < s->num_cpu; i++) { - s->cpu[i].seenbetter = false; - } - - /* Find the highest priority pending interrupt in this range. */ - for (i = start; i < start + len; i++) { - GICv3CPUState *cs; - - if (i == start || (i & 0x1f) == 0) { - /* Calculate the next 32 bits worth of pending status */ - pend = gicd_int_pending(s, i & ~0x1f); - } - - if (!(pend & (1 << (i & 0x1f)))) { - continue; - } - cs = s->gicd_irouter_target[i]; - if (!cs) { - /* Interrupts targeting no implemented CPU should remain pending - * and not be forwarded to any CPU. - */ - continue; - } - prio = s->gicd_ipriority[i]; - if (irqbetter(cs, i, prio)) { - cs->hppi.irq = i; - cs->hppi.prio = prio; - cs->seenbetter = true; - } - } - - /* If the best interrupt we just found would preempt whatever - * was the previous best interrupt before this update, then - * we know it's definitely the best one now. - * If we didn't find an interrupt that would preempt the previous - * best, and the previous best is outside our range (or there was - * no previous pending interrupt at all), then that - * is still valid, and we leave it as the best. - * Otherwise, we need to do a full update (because the previous best - * interrupt has reduced in priority and any other interrupt could - * now be the new best one). - */ - for (i = 0; i < s->num_cpu; i++) { - GICv3CPUState *cs = &s->cpu[i]; - - if (cs->seenbetter) { - cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq); - } - - if (!cs->seenbetter && cs->hppi.prio != 0xff && - cs->hppi.irq >= start && cs->hppi.irq < start + len) { - gicv3_full_update_noirqset(s); - break; - } - } -} - -void gicv3_update(GICv3State *s, int start, int len) -{ - int i; - - gicv3_update_noirqset(s, start, len); - for (i = 0; i < s->num_cpu; i++) { - gicv3_cpuif_update(&s->cpu[i]); - } -} - -void gicv3_full_update_noirqset(GICv3State *s) -{ - /* Completely recalculate the GIC status from scratch, but - * don't update any outbound IRQ lines. - */ - int i; - - for (i = 0; i < s->num_cpu; i++) { - s->cpu[i].hppi.prio = 0xff; - } - - /* Note that we can guarantee that these functions will not - * recursively call back into gicv3_full_update(), because - * at each point the "previous best" is always outside the - * range we ask them to update. - */ - gicv3_update_noirqset(s, GIC_INTERNAL, s->num_irq - GIC_INTERNAL); - - for (i = 0; i < s->num_cpu; i++) { - gicv3_redist_update_noirqset(&s->cpu[i]); - } -} - -void gicv3_full_update(GICv3State *s) -{ - /* Completely recalculate the GIC status from scratch, including - * updating outbound IRQ lines. - */ - int i; - - gicv3_full_update_noirqset(s); - for (i = 0; i < s->num_cpu; i++) { - gicv3_cpuif_update(&s->cpu[i]); - } -} - -/* Process a change in an external IRQ input. */ -static void gicv3_set_irq(void *opaque, int irq, int level) -{ - /* Meaning of the 'irq' parameter: - * [0..N-1] : external interrupts - * [N..N+31] : PPI (internal) interrupts for CPU 0 - * [N+32..N+63] : PPI (internal interrupts for CPU 1 - * ... - */ - GICv3State *s = opaque; - - if (irq < (s->num_irq - GIC_INTERNAL)) { - /* external interrupt (SPI) */ - gicv3_dist_set_irq(s, irq + GIC_INTERNAL, level); - } else { - /* per-cpu interrupt (PPI) */ - int cpu; - - irq -= (s->num_irq - GIC_INTERNAL); - cpu = irq / GIC_INTERNAL; - irq %= GIC_INTERNAL; - assert(cpu < s->num_cpu); - /* Raising SGIs via this function would be a bug in how the board - * model wires up interrupts. - */ - assert(irq >= GIC_NR_SGIS); - gicv3_redist_set_irq(&s->cpu[cpu], irq, level); - } -} - -static void arm_gicv3_post_load(GICv3State *s) -{ - /* Recalculate our cached idea of the current highest priority - * pending interrupt, but don't set IRQ or FIQ lines. - */ - gicv3_full_update_noirqset(s); - /* Repopulate the cache of GICv3CPUState pointers for target CPUs */ - gicv3_cache_all_target_cpustates(s); -} - -static const MemoryRegionOps gic_ops[] = { - { - .read_with_attrs = gicv3_dist_read, - .write_with_attrs = gicv3_dist_write, - .endianness = DEVICE_NATIVE_ENDIAN, - }, - { - .read_with_attrs = gicv3_redist_read, - .write_with_attrs = gicv3_redist_write, - .endianness = DEVICE_NATIVE_ENDIAN, - } -}; - -static void arm_gic_realize(DeviceState *dev, Error **errp) -{ - /* Device instance realize function for the GIC sysbus device */ - GICv3State *s = ARM_GICV3(dev); - ARMGICv3Class *agc = ARM_GICV3_GET_CLASS(s); - Error *local_err = NULL; - - agc->parent_realize(dev, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - gicv3_init_irqs_and_mmio(s, gicv3_set_irq, gic_ops); - - gicv3_init_cpuif(s); -} - -static void arm_gicv3_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); - ARMGICv3Class *agc = ARM_GICV3_CLASS(klass); - - agcc->post_load = arm_gicv3_post_load; - agc->parent_realize = dc->realize; - dc->realize = arm_gic_realize; -} - -static const TypeInfo arm_gicv3_info = { - .name = TYPE_ARM_GICV3, - .parent = TYPE_ARM_GICV3_COMMON, - .instance_size = sizeof(GICv3State), - .class_init = arm_gicv3_class_init, - .class_size = sizeof(ARMGICv3Class), -}; - -static void arm_gicv3_register_types(void) -{ - type_register_static(&arm_gicv3_info); -} - -type_init(arm_gicv3_register_types) diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 0f8c4b86e..b9d3824f2 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -3,9 +3,8 @@ * * Copyright (c) 2012 Linaro Limited * Copyright (c) 2015 Huawei. - * Copyright (c) 2015 Samsung Electronics Co., Ltd. * Written by Peter Maydell - * Reworked for GICv3 by Shlomo Pongratz and Pavel Fedin + * Extended to 64 cores by Shlomo Pongratz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,10 +22,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qom/cpu.h" #include "hw/intc/arm_gicv3_common.h" -#include "gicv3_internal.h" -#include "hw/arm/linux-boot-if.h" static void gicv3_pre_save(void *opaque) { @@ -49,59 +45,11 @@ static int gicv3_post_load(void *opaque, int version_id) return 0; } -static const VMStateDescription vmstate_gicv3_cpu = { - .name = "arm_gicv3_cpu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(level, GICv3CPUState), - VMSTATE_UINT32(gicr_ctlr, GICv3CPUState), - VMSTATE_UINT32_ARRAY(gicr_statusr, GICv3CPUState, 2), - VMSTATE_UINT32(gicr_waker, GICv3CPUState), - VMSTATE_UINT64(gicr_propbaser, GICv3CPUState), - VMSTATE_UINT64(gicr_pendbaser, GICv3CPUState), - VMSTATE_UINT32(gicr_igroupr0, GICv3CPUState), - VMSTATE_UINT32(gicr_ienabler0, GICv3CPUState), - VMSTATE_UINT32(gicr_ipendr0, GICv3CPUState), - VMSTATE_UINT32(gicr_iactiver0, GICv3CPUState), - VMSTATE_UINT32(edge_trigger, GICv3CPUState), - VMSTATE_UINT32(gicr_igrpmodr0, GICv3CPUState), - VMSTATE_UINT32(gicr_nsacr, GICv3CPUState), - VMSTATE_UINT8_ARRAY(gicr_ipriorityr, GICv3CPUState, GIC_INTERNAL), - VMSTATE_UINT64_ARRAY(icc_ctlr_el1, GICv3CPUState, 2), - VMSTATE_UINT64(icc_pmr_el1, GICv3CPUState), - VMSTATE_UINT64_ARRAY(icc_bpr, GICv3CPUState, 3), - VMSTATE_UINT64_2DARRAY(icc_apr, GICv3CPUState, 3, 4), - VMSTATE_UINT64_ARRAY(icc_igrpen, GICv3CPUState, 3), - VMSTATE_UINT64(icc_ctlr_el3, GICv3CPUState), - VMSTATE_END_OF_LIST() - } -}; - static const VMStateDescription vmstate_gicv3 = { .name = "arm_gicv3", - .version_id = 1, - .minimum_version_id = 1, + .unmigratable = 1, .pre_save = gicv3_pre_save, .post_load = gicv3_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(gicd_ctlr, GICv3State), - VMSTATE_UINT32_ARRAY(gicd_statusr, GICv3State, 2), - VMSTATE_UINT32_ARRAY(group, GICv3State, GICV3_BMP_SIZE), - VMSTATE_UINT32_ARRAY(grpmod, GICv3State, GICV3_BMP_SIZE), - VMSTATE_UINT32_ARRAY(enabled, GICv3State, GICV3_BMP_SIZE), - VMSTATE_UINT32_ARRAY(pending, GICv3State, GICV3_BMP_SIZE), - VMSTATE_UINT32_ARRAY(active, GICv3State, GICV3_BMP_SIZE), - VMSTATE_UINT32_ARRAY(level, GICv3State, GICV3_BMP_SIZE), - VMSTATE_UINT32_ARRAY(edge_trigger, GICv3State, GICV3_BMP_SIZE), - VMSTATE_UINT8_ARRAY(gicd_ipriority, GICv3State, GICV3_MAXIRQ), - VMSTATE_UINT64_ARRAY(gicd_irouter, GICv3State, GICV3_MAXIRQ), - VMSTATE_UINT32_ARRAY(gicd_nsacr, GICv3State, - DIV_ROUND_UP(GICV3_MAXIRQ, 16)), - VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, GICv3State, num_cpu, - vmstate_gicv3_cpu, GICv3CPUState), - VMSTATE_END_OF_LIST() - } }; void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, @@ -120,11 +68,14 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, i = s->num_irq - GIC_INTERNAL + GIC_INTERNAL * s->num_cpu; qdev_init_gpio_in(DEVICE(s), handler, i); + s->parent_irq = g_malloc(s->num_cpu * sizeof(qemu_irq)); + s->parent_fiq = g_malloc(s->num_cpu * sizeof(qemu_irq)); + for (i = 0; i < s->num_cpu; i++) { - sysbus_init_irq(sbd, &s->cpu[i].parent_irq); + sysbus_init_irq(sbd, &s->parent_irq[i]); } for (i = 0; i < s->num_cpu; i++) { - sysbus_init_irq(sbd, &s->cpu[i].parent_fiq); + sysbus_init_irq(sbd, &s->parent_fiq[i]); } memory_region_init_io(&s->iomem_dist, OBJECT(s), ops, s, @@ -139,7 +90,6 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler, static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) { GICv3State *s = ARM_GICV3_COMMON(dev); - int i; /* revision property is actually reserved and currently used only in order * to keep the interface compatible with GICv2 code, avoiding extra @@ -150,164 +100,11 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp) error_setg(errp, "unsupported GIC revision %d", s->revision); return; } - - if (s->num_irq > GICV3_MAXIRQ) { - error_setg(errp, - "requested %u interrupt lines exceeds GIC maximum %d", - s->num_irq, GICV3_MAXIRQ); - return; - } - if (s->num_irq < GIC_INTERNAL) { - error_setg(errp, - "requested %u interrupt lines is below GIC minimum %d", - s->num_irq, GIC_INTERNAL); - return; - } - - /* ITLinesNumber is represented as (N / 32) - 1, so this is an - * implementation imposed restriction, not an architectural one, - * so we don't have to deal with bitfields where only some of the - * bits in a 32-bit word should be valid. - */ - if (s->num_irq % 32) { - error_setg(errp, - "%d interrupt lines unsupported: not divisible by 32", - s->num_irq); - return; - } - - s->cpu = g_new0(GICv3CPUState, s->num_cpu); - - for (i = 0; i < s->num_cpu; i++) { - CPUState *cpu = qemu_get_cpu(i); - uint64_t cpu_affid; - int last; - - s->cpu[i].cpu = cpu; - s->cpu[i].gic = s; - - /* Pre-construct the GICR_TYPER: - * For our implementation: - * Top 32 bits are the affinity value of the associated CPU - * CommonLPIAff == 01 (redistributors with same Aff3 share LPI table) - * Processor_Number == CPU index starting from 0 - * DPGS == 0 (GICR_CTLR.DPG* not supported) - * Last == 1 if this is the last redistributor in a series of - * contiguous redistributor pages - * DirectLPI == 0 (direct injection of LPIs not supported) - * VLPIS == 0 (virtual LPIs not supported) - * PLPIS == 0 (physical LPIs not supported) - */ - cpu_affid = object_property_get_int(OBJECT(cpu), "mp-affinity", NULL); - last = (i == s->num_cpu - 1); - - /* The CPU mp-affinity property is in MPIDR register format; squash - * the affinity bytes into 32 bits as the GICR_TYPER has them. - */ - cpu_affid = (cpu_affid & 0xFF00000000ULL >> 8) | (cpu_affid & 0xFFFFFF); - s->cpu[i].gicr_typer = (cpu_affid << 32) | - (1 << 24) | - (i << 8) | - (last << 4); - } } static void arm_gicv3_common_reset(DeviceState *dev) { - GICv3State *s = ARM_GICV3_COMMON(dev); - int i; - - for (i = 0; i < s->num_cpu; i++) { - GICv3CPUState *cs = &s->cpu[i]; - - cs->level = 0; - cs->gicr_ctlr = 0; - cs->gicr_statusr[GICV3_S] = 0; - cs->gicr_statusr[GICV3_NS] = 0; - cs->gicr_waker = GICR_WAKER_ProcessorSleep | GICR_WAKER_ChildrenAsleep; - cs->gicr_propbaser = 0; - cs->gicr_pendbaser = 0; - /* If we're resetting a TZ-aware GIC as if secure firmware - * had set it up ready to start a kernel in non-secure, we - * need to set interrupts to group 1 so the kernel can use them. - * Otherwise they reset to group 0 like the hardware. - */ - if (s->irq_reset_nonsecure) { - cs->gicr_igroupr0 = 0xffffffff; - } else { - cs->gicr_igroupr0 = 0; - } - - cs->gicr_ienabler0 = 0; - cs->gicr_ipendr0 = 0; - cs->gicr_iactiver0 = 0; - cs->edge_trigger = 0xffff; - cs->gicr_igrpmodr0 = 0; - cs->gicr_nsacr = 0; - memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr)); - - cs->hppi.prio = 0xff; - - /* State in the CPU interface must *not* be reset here, because it - * is part of the CPU's reset domain, not the GIC device's. - */ - } - - /* For our implementation affinity routing is always enabled */ - if (s->security_extn) { - s->gicd_ctlr = GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS; - } else { - s->gicd_ctlr = GICD_CTLR_DS | GICD_CTLR_ARE; - } - - s->gicd_statusr[GICV3_S] = 0; - s->gicd_statusr[GICV3_NS] = 0; - - memset(s->group, 0, sizeof(s->group)); - memset(s->grpmod, 0, sizeof(s->grpmod)); - memset(s->enabled, 0, sizeof(s->enabled)); - memset(s->pending, 0, sizeof(s->pending)); - memset(s->active, 0, sizeof(s->active)); - memset(s->level, 0, sizeof(s->level)); - memset(s->edge_trigger, 0, sizeof(s->edge_trigger)); - memset(s->gicd_ipriority, 0, sizeof(s->gicd_ipriority)); - memset(s->gicd_irouter, 0, sizeof(s->gicd_irouter)); - memset(s->gicd_nsacr, 0, sizeof(s->gicd_nsacr)); - /* GICD_IROUTER are UNKNOWN at reset so in theory the guest must - * write these to get sane behaviour and we need not populate the - * pointer cache here; however having the cache be different for - * "happened to be 0 from reset" and "guest wrote 0" would be - * too confusing. - */ - gicv3_cache_all_target_cpustates(s); - - if (s->irq_reset_nonsecure) { - /* If we're resetting a TZ-aware GIC as if secure firmware - * had set it up ready to start a kernel in non-secure, we - * need to set interrupts to group 1 so the kernel can use them. - * Otherwise they reset to group 0 like the hardware. - */ - for (i = GIC_INTERNAL; i < s->num_irq; i++) { - gicv3_gicd_group_set(s, i); - } - } -} - -static void arm_gic_common_linux_init(ARMLinuxBootIf *obj, - bool secure_boot) -{ - GICv3State *s = ARM_GICV3_COMMON(obj); - - if (s->security_extn && !secure_boot) { - /* We're directly booting a kernel into NonSecure. If this GIC - * implements the security extensions then we must configure it - * to have all the interrupts be NonSecure (this is a job that - * is done by the Secure boot firmware in real hardware, and in - * this mode QEMU is acting as a minimalist firmware-and-bootloader - * equivalent). - */ - s->irq_reset_nonsecure = true; - } + /* TODO */ } static Property arm_gicv3_common_properties[] = { @@ -321,13 +118,11 @@ static Property arm_gicv3_common_properties[] = { static void arm_gicv3_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - ARMLinuxBootIfClass *albifc = ARM_LINUX_BOOT_IF_CLASS(klass); dc->reset = arm_gicv3_common_reset; dc->realize = arm_gicv3_common_realize; dc->props = arm_gicv3_common_properties; dc->vmsd = &vmstate_gicv3; - albifc->arm_linux_init = arm_gic_common_linux_init; } static const TypeInfo arm_gicv3_common_type = { @@ -337,10 +132,6 @@ static const TypeInfo arm_gicv3_common_type = { .class_size = sizeof(ARMGICv3CommonClass), .class_init = arm_gicv3_common_class_init, .abstract = true, - .interfaces = (InterfaceInfo []) { - { TYPE_ARM_LINUX_BOOT_IF }, - { }, - }, }; static void register_types(void) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c deleted file mode 100644 index 4633172be..000000000 --- a/hw/intc/arm_gicv3_cpuif.c +++ /dev/null @@ -1,1348 +0,0 @@ -/* - * ARM Generic Interrupt Controller v3 - * - * Copyright (c) 2016 Linaro Limited - * Written by Peter Maydell - * - * This code is licensed under the GPL, version 2 or (at your option) - * any later version. - */ - -/* This file contains the code for the system register interface - * portions of the GICv3. - */ - -#include "qemu/osdep.h" -#include "trace.h" -#include "gicv3_internal.h" -#include "cpu.h" - -static GICv3CPUState *icc_cs_from_env(CPUARMState *env) -{ - /* Given the CPU, find the right GICv3CPUState struct. - * Since we registered the CPU interface with the EL change hook as - * the opaque pointer, we can just directly get from the CPU to it. - */ - return arm_get_el_change_hook_opaque(arm_env_get_cpu(env)); -} - -static bool gicv3_use_ns_bank(CPUARMState *env) -{ - /* Return true if we should use the NonSecure bank for a banked GIC - * CPU interface register. Note that this differs from the - * access_secure_reg() function because GICv3 banked registers are - * banked even for AArch64, unlike the other CPU system registers. - */ - return !arm_is_secure_below_el3(env); -} - -static int icc_highest_active_prio(GICv3CPUState *cs) -{ - /* Calculate the current running priority based on the set bits - * in the Active Priority Registers. - */ - int i; - - for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) { - uint32_t apr = cs->icc_apr[GICV3_G0][i] | - cs->icc_apr[GICV3_G1][i] | cs->icc_apr[GICV3_G1NS][i]; - - if (!apr) { - continue; - } - return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1); - } - /* No current active interrupts: return idle priority */ - return 0xff; -} - -static uint32_t icc_gprio_mask(GICv3CPUState *cs, int group) -{ - /* Return a mask word which clears the subpriority bits from - * a priority value for an interrupt in the specified group. - * This depends on the BPR value: - * a BPR of 0 means the group priority bits are [7:1]; - * a BPR of 1 means they are [7:2], and so on down to - * a BPR of 7 meaning no group priority bits at all. - * Which BPR to use depends on the group of the interrupt and - * the current ICC_CTLR.CBPR settings. - */ - if ((group == GICV3_G1 && cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR) || - (group == GICV3_G1NS && - cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) { - group = GICV3_G0; - } - - return ~0U << ((cs->icc_bpr[group] & 7) + 1); -} - -static bool icc_no_enabled_hppi(GICv3CPUState *cs) -{ - /* Return true if there is no pending interrupt, or the - * highest priority pending interrupt is in a group which has been - * disabled at the CPU interface by the ICC_IGRPEN* register enable bits. - */ - return cs->hppi.prio == 0xff || (cs->icc_igrpen[cs->hppi.grp] == 0); -} - -static bool icc_hppi_can_preempt(GICv3CPUState *cs) -{ - /* Return true if we have a pending interrupt of sufficient - * priority to preempt. - */ - int rprio; - uint32_t mask; - - if (icc_no_enabled_hppi(cs)) { - return false; - } - - if (cs->hppi.prio >= cs->icc_pmr_el1) { - /* Priority mask masks this interrupt */ - return false; - } - - rprio = icc_highest_active_prio(cs); - if (rprio == 0xff) { - /* No currently running interrupt so we can preempt */ - return true; - } - - mask = icc_gprio_mask(cs, cs->hppi.grp); - - /* We only preempt a running interrupt if the pending interrupt's - * group priority is sufficient (the subpriorities are not considered). - */ - if ((cs->hppi.prio & mask) < (rprio & mask)) { - return true; - } - - return false; -} - -void gicv3_cpuif_update(GICv3CPUState *cs) -{ - /* Tell the CPU about its highest priority pending interrupt */ - int irqlevel = 0; - int fiqlevel = 0; - ARMCPU *cpu = ARM_CPU(cs->cpu); - CPUARMState *env = &cpu->env; - - trace_gicv3_cpuif_update(gicv3_redist_affid(cs), cs->hppi.irq, - cs->hppi.grp, cs->hppi.prio); - - if (cs->hppi.grp == GICV3_G1 && !arm_feature(env, ARM_FEATURE_EL3)) { - /* If a Security-enabled GIC sends a G1S interrupt to a - * Security-disabled CPU, we must treat it as if it were G0. - */ - cs->hppi.grp = GICV3_G0; - } - - if (icc_hppi_can_preempt(cs)) { - /* We have an interrupt: should we signal it as IRQ or FIQ? - * This is described in the GICv3 spec section 4.6.2. - */ - bool isfiq; - - switch (cs->hppi.grp) { - case GICV3_G0: - isfiq = true; - break; - case GICV3_G1: - isfiq = (!arm_is_secure(env) || - (arm_current_el(env) == 3 && arm_el_is_aa64(env, 3))); - break; - case GICV3_G1NS: - isfiq = arm_is_secure(env); - break; - default: - g_assert_not_reached(); - } - - if (isfiq) { - fiqlevel = 1; - } else { - irqlevel = 1; - } - } - - trace_gicv3_cpuif_set_irqs(gicv3_redist_affid(cs), fiqlevel, irqlevel); - - qemu_set_irq(cs->parent_fiq, fiqlevel); - qemu_set_irq(cs->parent_irq, irqlevel); -} - -static uint64_t icc_pmr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - uint32_t value = cs->icc_pmr_el1; - - if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env) && - (env->cp15.scr_el3 & SCR_FIQ)) { - /* NS access and Group 0 is inaccessible to NS: return the - * NS view of the current priority - */ - if (value & 0x80) { - /* Secure priorities not visible to NS */ - value = 0; - } else if (value != 0xff) { - value = (value << 1) & 0xff; - } - } - - trace_gicv3_icc_pmr_read(gicv3_redist_affid(cs), value); - - return value; -} - -static void icc_pmr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - - trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value); - - value &= 0xff; - - if (arm_feature(env, ARM_FEATURE_EL3) && !arm_is_secure(env) && - (env->cp15.scr_el3 & SCR_FIQ)) { - /* NS access and Group 0 is inaccessible to NS: return the - * NS view of the current priority - */ - if (!(cs->icc_pmr_el1 & 0x80)) { - /* Current PMR in the secure range, don't allow NS to change it */ - return; - } - value = (value >> 1) & 0x80; - } - cs->icc_pmr_el1 = value; - gicv3_cpuif_update(cs); -} - -static void icc_activate_irq(GICv3CPUState *cs, int irq) -{ - /* Move the interrupt from the Pending state to Active, and update - * the Active Priority Registers - */ - uint32_t mask = icc_gprio_mask(cs, cs->hppi.grp); - int prio = cs->hppi.prio & mask; - int aprbit = prio >> 1; - int regno = aprbit / 32; - int regbit = aprbit % 32; - - cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit); - - if (irq < GIC_INTERNAL) { - cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 1); - cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 0); - gicv3_redist_update(cs); - } else { - gicv3_gicd_active_set(cs->gic, irq); - gicv3_gicd_pending_clear(cs->gic, irq); - gicv3_update(cs->gic, irq, 1); - } -} - -static uint64_t icc_hppir0_value(GICv3CPUState *cs, CPUARMState *env) -{ - /* Return the highest priority pending interrupt register value - * for group 0. - */ - bool irq_is_secure; - - if (cs->hppi.prio == 0xff) { - return INTID_SPURIOUS; - } - - /* Check whether we can return the interrupt or if we should return - * a special identifier, as per the CheckGroup0ForSpecialIdentifiers - * pseudocode. (We can simplify a little because for us ICC_SRE_EL1.RM - * is always zero.) - */ - irq_is_secure = (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) && - (cs->hppi.grp != GICV3_G1NS)); - - if (cs->hppi.grp != GICV3_G0 && !arm_is_el3_or_mon(env)) { - return INTID_SPURIOUS; - } - if (irq_is_secure && !arm_is_secure(env)) { - /* Secure interrupts not visible to Nonsecure */ - return INTID_SPURIOUS; - } - - if (cs->hppi.grp != GICV3_G0) { - /* Indicate to EL3 that there's a Group 1 interrupt for the other - * state pending. - */ - return irq_is_secure ? INTID_SECURE : INTID_NONSECURE; - } - - return cs->hppi.irq; -} - -static uint64_t icc_hppir1_value(GICv3CPUState *cs, CPUARMState *env) -{ - /* Return the highest priority pending interrupt register value - * for group 1. - */ - bool irq_is_secure; - - if (cs->hppi.prio == 0xff) { - return INTID_SPURIOUS; - } - - /* Check whether we can return the interrupt or if we should return - * a special identifier, as per the CheckGroup1ForSpecialIdentifiers - * pseudocode. (We can simplify a little because for us ICC_SRE_EL1.RM - * is always zero.) - */ - irq_is_secure = (!(cs->gic->gicd_ctlr & GICD_CTLR_DS) && - (cs->hppi.grp != GICV3_G1NS)); - - if (cs->hppi.grp == GICV3_G0) { - /* Group 0 interrupts not visible via HPPIR1 */ - return INTID_SPURIOUS; - } - if (irq_is_secure) { - if (!arm_is_secure(env)) { - /* Secure interrupts not visible in Non-secure */ - return INTID_SPURIOUS; - } - } else if (!arm_is_el3_or_mon(env) && arm_is_secure(env)) { - /* Group 1 non-secure interrupts not visible in Secure EL1 */ - return INTID_SPURIOUS; - } - - return cs->hppi.irq; -} - -static uint64_t icc_iar0_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - uint64_t intid; - - if (!icc_hppi_can_preempt(cs)) { - intid = INTID_SPURIOUS; - } else { - intid = icc_hppir0_value(cs, env); - } - - if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) { - icc_activate_irq(cs, intid); - } - - trace_gicv3_icc_iar0_read(gicv3_redist_affid(cs), intid); - return intid; -} - -static uint64_t icc_iar1_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - uint64_t intid; - - if (!icc_hppi_can_preempt(cs)) { - intid = INTID_SPURIOUS; - } else { - intid = icc_hppir1_value(cs, env); - } - - if (!(intid >= INTID_SECURE && intid <= INTID_SPURIOUS)) { - icc_activate_irq(cs, intid); - } - - trace_gicv3_icc_iar1_read(gicv3_redist_affid(cs), intid); - return intid; -} - -static void icc_drop_prio(GICv3CPUState *cs, int grp) -{ - /* Drop the priority of the currently active interrupt in - * the specified group. - * - * Note that we can guarantee (because of the requirement to nest - * ICC_IAR reads [which activate an interrupt and raise priority] - * with ICC_EOIR writes [which drop the priority for the interrupt]) - * that the interrupt we're being called for is the highest priority - * active interrupt, meaning that it has the lowest set bit in the - * APR registers. - * - * If the guest does not honour the ordering constraints then the - * behaviour of the GIC is UNPREDICTABLE, which for us means that - * the values of the APR registers might become incorrect and the - * running priority will be wrong, so interrupts that should preempt - * might not do so, and interrupts that should not preempt might do so. - */ - int i; - - for (i = 0; i < ARRAY_SIZE(cs->icc_apr[grp]); i++) { - uint64_t *papr = &cs->icc_apr[grp][i]; - - if (!*papr) { - continue; - } - /* Clear the lowest set bit */ - *papr &= *papr - 1; - break; - } - - /* running priority change means we need an update for this cpu i/f */ - gicv3_cpuif_update(cs); -} - -static bool icc_eoi_split(CPUARMState *env, GICv3CPUState *cs) -{ - /* Return true if we should split priority drop and interrupt - * deactivation, ie whether the relevant EOIMode bit is set. - */ - if (arm_is_el3_or_mon(env)) { - return cs->icc_ctlr_el3 & ICC_CTLR_EL3_EOIMODE_EL3; - } - if (arm_is_secure_below_el3(env)) { - return cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_EOIMODE; - } else { - return cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_EOIMODE; - } -} - -static int icc_highest_active_group(GICv3CPUState *cs) -{ - /* Return the group with the highest priority active interrupt. - * We can do this by just comparing the APRs to see which one - * has the lowest set bit. - * (If more than one group is active at the same priority then - * we're in UNPREDICTABLE territory.) - */ - int i; - - for (i = 0; i < ARRAY_SIZE(cs->icc_apr[0]); i++) { - int g0ctz = ctz32(cs->icc_apr[GICV3_G0][i]); - int g1ctz = ctz32(cs->icc_apr[GICV3_G1][i]); - int g1nsctz = ctz32(cs->icc_apr[GICV3_G1NS][i]); - - if (g1nsctz < g0ctz && g1nsctz < g1ctz) { - return GICV3_G1NS; - } - if (g1ctz < g0ctz) { - return GICV3_G1; - } - if (g0ctz < 32) { - return GICV3_G0; - } - } - /* No set active bits? UNPREDICTABLE; return -1 so the caller - * ignores the spurious EOI attempt. - */ - return -1; -} - -static void icc_deactivate_irq(GICv3CPUState *cs, int irq) -{ - if (irq < GIC_INTERNAL) { - cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 0); - gicv3_redist_update(cs); - } else { - gicv3_gicd_active_clear(cs->gic, irq); - gicv3_update(cs->gic, irq, 1); - } -} - -static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - /* End of Interrupt */ - GICv3CPUState *cs = icc_cs_from_env(env); - int irq = value & 0xffffff; - int grp; - - trace_gicv3_icc_eoir_write(gicv3_redist_affid(cs), value); - - if (ri->crm == 8) { - /* EOIR0 */ - grp = GICV3_G0; - } else { - /* EOIR1 */ - if (arm_is_secure(env)) { - grp = GICV3_G1; - } else { - grp = GICV3_G1NS; - } - } - - if (irq >= cs->gic->num_irq) { - /* This handles two cases: - * 1. If software writes the ID of a spurious interrupt [ie 1020-1023] - * to the GICC_EOIR, the GIC ignores that write. - * 2. If software writes the number of a non-existent interrupt - * this must be a subcase of "value written does not match the last - * valid interrupt value read from the Interrupt Acknowledge - * register" and so this is UNPREDICTABLE. We choose to ignore it. - */ - return; - } - - if (icc_highest_active_group(cs) != grp) { - return; - } - - icc_drop_prio(cs, grp); - - if (!icc_eoi_split(env, cs)) { - /* Priority drop and deactivate not split: deactivate irq now */ - icc_deactivate_irq(cs, irq); - } -} - -static uint64_t icc_hppir0_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - uint64_t value = icc_hppir0_value(cs, env); - - trace_gicv3_icc_hppir0_read(gicv3_redist_affid(cs), value); - return value; -} - -static uint64_t icc_hppir1_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - uint64_t value = icc_hppir1_value(cs, env); - - trace_gicv3_icc_hppir1_read(gicv3_redist_affid(cs), value); - return value; -} - -static uint64_t icc_bpr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - int grp = (ri->crm == 8) ? GICV3_G0 : GICV3_G1; - bool satinc = false; - uint64_t bpr; - - if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { - grp = GICV3_G1NS; - } - - if (grp == GICV3_G1 && !arm_is_el3_or_mon(env) && - (cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR)) { - /* CBPR_EL1S means secure EL1 or AArch32 EL3 !Mon BPR1 accesses - * modify BPR0 - */ - grp = GICV3_G0; - } - - if (grp == GICV3_G1NS && arm_current_el(env) < 3 && - (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) { - /* reads return bpr0 + 1 sat to 7, writes ignored */ - grp = GICV3_G0; - satinc = true; - } - - bpr = cs->icc_bpr[grp]; - if (satinc) { - bpr++; - bpr = MIN(bpr, 7); - } - - trace_gicv3_icc_bpr_read(gicv3_redist_affid(cs), bpr); - - return bpr; -} - -static void icc_bpr_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - int grp = (ri->crm == 8) ? GICV3_G0 : GICV3_G1; - - trace_gicv3_icc_pmr_write(gicv3_redist_affid(cs), value); - - if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { - grp = GICV3_G1NS; - } - - if (grp == GICV3_G1 && !arm_is_el3_or_mon(env) && - (cs->icc_ctlr_el1[GICV3_S] & ICC_CTLR_EL1_CBPR)) { - /* CBPR_EL1S means secure EL1 or AArch32 EL3 !Mon BPR1 accesses - * modify BPR0 - */ - grp = GICV3_G0; - } - - if (grp == GICV3_G1NS && arm_current_el(env) < 3 && - (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR)) { - /* reads return bpr0 + 1 sat to 7, writes ignored */ - return; - } - - cs->icc_bpr[grp] = value & 7; - gicv3_cpuif_update(cs); -} - -static uint64_t icc_ap_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - uint64_t value; - - int regno = ri->opc2 & 3; - int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1; - - if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { - grp = GICV3_G1NS; - } - - value = cs->icc_apr[grp][regno]; - - trace_gicv3_icc_ap_read(regno, gicv3_redist_affid(cs), value); - return value; -} - -static void icc_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - - int regno = ri->opc2 & 3; - int grp = ri->crm & 1 ? GICV3_G0 : GICV3_G1; - - trace_gicv3_icc_ap_write(regno, gicv3_redist_affid(cs), value); - - if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { - grp = GICV3_G1NS; - } - - /* It's not possible to claim that a Non-secure interrupt is active - * at a priority outside the Non-secure range (128..255), since this - * would otherwise allow malicious NS code to block delivery of S interrupts - * by writing a bad value to these registers. - */ - if (grp == GICV3_G1NS && regno < 2 && arm_feature(env, ARM_FEATURE_EL3)) { - return; - } - - cs->icc_apr[grp][regno] = value & 0xFFFFFFFFU; - gicv3_cpuif_update(cs); -} - -static void icc_dir_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - /* Deactivate interrupt */ - GICv3CPUState *cs = icc_cs_from_env(env); - int irq = value & 0xffffff; - bool irq_is_secure, single_sec_state, irq_is_grp0; - bool route_fiq_to_el3, route_irq_to_el3, route_fiq_to_el2, route_irq_to_el2; - - trace_gicv3_icc_dir_write(gicv3_redist_affid(cs), value); - - if (irq >= cs->gic->num_irq) { - /* Also catches special interrupt numbers and LPIs */ - return; - } - - if (!icc_eoi_split(env, cs)) { - return; - } - - int grp = gicv3_irq_group(cs->gic, cs, irq); - - single_sec_state = cs->gic->gicd_ctlr & GICD_CTLR_DS; - irq_is_secure = !single_sec_state && (grp != GICV3_G1NS); - irq_is_grp0 = grp == GICV3_G0; - - /* Check whether we're allowed to deactivate this interrupt based - * on its group and the current CPU state. - * These checks are laid out to correspond to the spec's pseudocode. - */ - route_fiq_to_el3 = env->cp15.scr_el3 & SCR_FIQ; - route_irq_to_el3 = env->cp15.scr_el3 & SCR_IRQ; - /* No need to include !IsSecure in route_*_to_el2 as it's only - * tested in cases where we know !IsSecure is true. - */ - route_fiq_to_el2 = env->cp15.hcr_el2 & HCR_FMO; - route_irq_to_el2 = env->cp15.hcr_el2 & HCR_FMO; - - switch (arm_current_el(env)) { - case 3: - break; - case 2: - if (single_sec_state && irq_is_grp0 && !route_fiq_to_el3) { - break; - } - if (!irq_is_secure && !irq_is_grp0 && !route_irq_to_el3) { - break; - } - return; - case 1: - if (!arm_is_secure_below_el3(env)) { - if (single_sec_state && irq_is_grp0 && - !route_fiq_to_el3 && !route_fiq_to_el2) { - break; - } - if (!irq_is_secure && !irq_is_grp0 && - !route_irq_to_el3 && !route_irq_to_el2) { - break; - } - } else { - if (irq_is_grp0 && !route_fiq_to_el3) { - break; - } - if (!irq_is_grp0 && - (!irq_is_secure || !single_sec_state) && - !route_irq_to_el3) { - break; - } - } - return; - default: - g_assert_not_reached(); - } - - icc_deactivate_irq(cs, irq); -} - -static uint64_t icc_rpr_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - int prio = icc_highest_active_prio(cs); - - if (arm_feature(env, ARM_FEATURE_EL3) && - !arm_is_secure(env) && (env->cp15.scr_el3 & SCR_FIQ)) { - /* NS GIC access and Group 0 is inaccessible to NS */ - if (prio & 0x80) { - /* NS mustn't see priorities in the Secure half of the range */ - prio = 0; - } else if (prio != 0xff) { - /* Non-idle priority: show the Non-secure view of it */ - prio = (prio << 1) & 0xff; - } - } - - trace_gicv3_icc_rpr_read(gicv3_redist_affid(cs), prio); - return prio; -} - -static void icc_generate_sgi(CPUARMState *env, GICv3CPUState *cs, - uint64_t value, int grp, bool ns) -{ - GICv3State *s = cs->gic; - - /* Extract Aff3/Aff2/Aff1 and shift into the bottom 24 bits */ - uint64_t aff = extract64(value, 48, 8) << 16 | - extract64(value, 32, 8) << 8 | - extract64(value, 16, 8); - uint32_t targetlist = extract64(value, 0, 16); - uint32_t irq = extract64(value, 24, 4); - bool irm = extract64(value, 40, 1); - int i; - - if (grp == GICV3_G1 && s->gicd_ctlr & GICD_CTLR_DS) { - /* If GICD_CTLR.DS == 1, the Distributor treats Secure Group 1 - * interrupts as Group 0 interrupts and must send Secure Group 0 - * interrupts to the target CPUs. - */ - grp = GICV3_G0; - } - - trace_gicv3_icc_generate_sgi(gicv3_redist_affid(cs), irq, irm, - aff, targetlist); - - for (i = 0; i < s->num_cpu; i++) { - GICv3CPUState *ocs = &s->cpu[i]; - - if (irm) { - /* IRM == 1 : route to all CPUs except self */ - if (cs == ocs) { - continue; - } - } else { - /* IRM == 0 : route to Aff3.Aff2.Aff1.n for all n in [0..15] - * where the corresponding bit is set in targetlist - */ - int aff0; - - if (ocs->gicr_typer >> 40 != aff) { - continue; - } - aff0 = extract64(ocs->gicr_typer, 32, 8); - if (aff0 > 15 || extract32(targetlist, aff0, 1) == 0) { - continue; - } - } - - /* The redistributor will check against its own GICR_NSACR as needed */ - gicv3_redist_send_sgi(ocs, grp, irq, ns); - } -} - -static void icc_sgi0r_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - /* Generate Secure Group 0 SGI. */ - GICv3CPUState *cs = icc_cs_from_env(env); - bool ns = !arm_is_secure(env); - - icc_generate_sgi(env, cs, value, GICV3_G0, ns); -} - -static void icc_sgi1r_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - /* Generate Group 1 SGI for the current Security state */ - GICv3CPUState *cs = icc_cs_from_env(env); - int grp; - bool ns = !arm_is_secure(env); - - grp = ns ? GICV3_G1NS : GICV3_G1; - icc_generate_sgi(env, cs, value, grp, ns); -} - -static void icc_asgi1r_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - /* Generate Group 1 SGI for the Security state that is not - * the current state - */ - GICv3CPUState *cs = icc_cs_from_env(env); - int grp; - bool ns = !arm_is_secure(env); - - grp = ns ? GICV3_G1 : GICV3_G1NS; - icc_generate_sgi(env, cs, value, grp, ns); -} - -static uint64_t icc_igrpen_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - int grp = ri->opc2 & 1 ? GICV3_G1 : GICV3_G0; - uint64_t value; - - if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { - grp = GICV3_G1NS; - } - - value = cs->icc_igrpen[grp]; - trace_gicv3_icc_igrpen_read(gicv3_redist_affid(cs), value); - return value; -} - -static void icc_igrpen_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - int grp = ri->opc2 & 1 ? GICV3_G1 : GICV3_G0; - - trace_gicv3_icc_igrpen_write(gicv3_redist_affid(cs), value); - - if (grp == GICV3_G1 && gicv3_use_ns_bank(env)) { - grp = GICV3_G1NS; - } - - cs->icc_igrpen[grp] = value & ICC_IGRPEN_ENABLE; - gicv3_cpuif_update(cs); -} - -static uint64_t icc_igrpen1_el3_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - - /* IGRPEN1_EL3 bits 0 and 1 are r/w aliases into IGRPEN1_EL1 NS and S */ - return cs->icc_igrpen[GICV3_G1NS] | (cs->icc_igrpen[GICV3_G1] << 1); -} - -static void icc_igrpen1_el3_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - - trace_gicv3_icc_igrpen1_el3_write(gicv3_redist_affid(cs), value); - - /* IGRPEN1_EL3 bits 0 and 1 are r/w aliases into IGRPEN1_EL1 NS and S */ - cs->icc_igrpen[GICV3_G1NS] = extract32(value, 0, 1); - cs->icc_igrpen[GICV3_G1] = extract32(value, 1, 1); - gicv3_cpuif_update(cs); -} - -static uint64_t icc_ctlr_el1_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - int bank = gicv3_use_ns_bank(env) ? GICV3_NS : GICV3_S; - uint64_t value; - - value = cs->icc_ctlr_el1[bank]; - trace_gicv3_icc_ctlr_read(gicv3_redist_affid(cs), value); - return value; -} - -static void icc_ctlr_el1_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - int bank = gicv3_use_ns_bank(env) ? GICV3_NS : GICV3_S; - uint64_t mask; - - trace_gicv3_icc_ctlr_write(gicv3_redist_affid(cs), value); - - /* Only CBPR and EOIMODE can be RW; - * for us PMHE is RAZ/WI (we don't implement 1-of-N interrupts or - * the asseciated priority-based routing of them); - * if EL3 is implemented and GICD_CTLR.DS == 0, then PMHE and CBPR are RO. - */ - if (arm_feature(env, ARM_FEATURE_EL3) && - ((cs->gic->gicd_ctlr & GICD_CTLR_DS) == 0)) { - mask = ICC_CTLR_EL1_EOIMODE; - } else { - mask = ICC_CTLR_EL1_CBPR | ICC_CTLR_EL1_EOIMODE; - } - - cs->icc_ctlr_el1[bank] &= ~mask; - cs->icc_ctlr_el1[bank] |= (value & mask); - gicv3_cpuif_update(cs); -} - - -static uint64_t icc_ctlr_el3_read(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - uint64_t value; - - value = cs->icc_ctlr_el3; - if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_EOIMODE) { - value |= ICC_CTLR_EL3_EOIMODE_EL1NS; - } - if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR) { - value |= ICC_CTLR_EL3_CBPR_EL1NS; - } - if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_EOIMODE) { - value |= ICC_CTLR_EL3_EOIMODE_EL1S; - } - if (cs->icc_ctlr_el1[GICV3_NS] & ICC_CTLR_EL1_CBPR) { - value |= ICC_CTLR_EL3_CBPR_EL1S; - } - - trace_gicv3_icc_ctlr_el3_read(gicv3_redist_affid(cs), value); - return value; -} - -static void icc_ctlr_el3_write(CPUARMState *env, const ARMCPRegInfo *ri, - uint64_t value) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - uint64_t mask; - - trace_gicv3_icc_ctlr_el3_write(gicv3_redist_affid(cs), value); - - /* *_EL1NS and *_EL1S bits are aliases into the ICC_CTLR_EL1 bits. */ - cs->icc_ctlr_el1[GICV3_NS] &= (ICC_CTLR_EL1_CBPR | ICC_CTLR_EL1_EOIMODE); - if (value & ICC_CTLR_EL3_EOIMODE_EL1NS) { - cs->icc_ctlr_el1[GICV3_NS] |= ICC_CTLR_EL1_EOIMODE; - } - if (value & ICC_CTLR_EL3_CBPR_EL1NS) { - cs->icc_ctlr_el1[GICV3_NS] |= ICC_CTLR_EL1_CBPR; - } - - cs->icc_ctlr_el1[GICV3_S] &= (ICC_CTLR_EL1_CBPR | ICC_CTLR_EL1_EOIMODE); - if (value & ICC_CTLR_EL3_EOIMODE_EL1S) { - cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_EOIMODE; - } - if (value & ICC_CTLR_EL3_CBPR_EL1S) { - cs->icc_ctlr_el1[GICV3_S] |= ICC_CTLR_EL1_CBPR; - } - - /* The only bit stored in icc_ctlr_el3 which is writeable is EOIMODE_EL3: */ - mask = ICC_CTLR_EL3_EOIMODE_EL3; - - cs->icc_ctlr_el3 &= ~mask; - cs->icc_ctlr_el3 |= (value & mask); - gicv3_cpuif_update(cs); -} - -static CPAccessResult gicv3_irqfiq_access(CPUARMState *env, - const ARMCPRegInfo *ri, bool isread) -{ - CPAccessResult r = CP_ACCESS_OK; - - if ((env->cp15.scr_el3 & (SCR_FIQ | SCR_IRQ)) == (SCR_FIQ | SCR_IRQ)) { - switch (arm_current_el(env)) { - case 1: - if (arm_is_secure_below_el3(env) || - ((env->cp15.hcr_el2 & (HCR_IMO | HCR_FMO)) == 0)) { - r = CP_ACCESS_TRAP_EL3; - } - break; - case 2: - r = CP_ACCESS_TRAP_EL3; - break; - case 3: - if (!is_a64(env) && !arm_is_el3_or_mon(env)) { - r = CP_ACCESS_TRAP_EL3; - } - break; - default: - g_assert_not_reached(); - } - } - - if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) { - r = CP_ACCESS_TRAP; - } - return r; -} - -static CPAccessResult gicv3_fiq_access(CPUARMState *env, - const ARMCPRegInfo *ri, bool isread) -{ - CPAccessResult r = CP_ACCESS_OK; - - if (env->cp15.scr_el3 & SCR_FIQ) { - switch (arm_current_el(env)) { - case 1: - if (arm_is_secure_below_el3(env) || - ((env->cp15.hcr_el2 & HCR_FMO) == 0)) { - r = CP_ACCESS_TRAP_EL3; - } - break; - case 2: - r = CP_ACCESS_TRAP_EL3; - break; - case 3: - if (!is_a64(env) && !arm_is_el3_or_mon(env)) { - r = CP_ACCESS_TRAP_EL3; - } - break; - default: - g_assert_not_reached(); - } - } - - if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) { - r = CP_ACCESS_TRAP; - } - return r; -} - -static CPAccessResult gicv3_irq_access(CPUARMState *env, - const ARMCPRegInfo *ri, bool isread) -{ - CPAccessResult r = CP_ACCESS_OK; - - if (env->cp15.scr_el3 & SCR_IRQ) { - switch (arm_current_el(env)) { - case 1: - if (arm_is_secure_below_el3(env) || - ((env->cp15.hcr_el2 & HCR_IMO) == 0)) { - r = CP_ACCESS_TRAP_EL3; - } - break; - case 2: - r = CP_ACCESS_TRAP_EL3; - break; - case 3: - if (!is_a64(env) && !arm_is_el3_or_mon(env)) { - r = CP_ACCESS_TRAP_EL3; - } - break; - default: - g_assert_not_reached(); - } - } - - if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) { - r = CP_ACCESS_TRAP; - } - return r; -} - -static void icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) -{ - GICv3CPUState *cs = icc_cs_from_env(env); - - cs->icc_ctlr_el1[GICV3_S] = ICC_CTLR_EL1_A3V | - (1 << ICC_CTLR_EL1_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL1_PRIBITS_SHIFT); - cs->icc_ctlr_el1[GICV3_NS] = ICC_CTLR_EL1_A3V | - (1 << ICC_CTLR_EL1_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL1_PRIBITS_SHIFT); - cs->icc_pmr_el1 = 0; - cs->icc_bpr[GICV3_G0] = GIC_MIN_BPR; - cs->icc_bpr[GICV3_G1] = GIC_MIN_BPR; - if (arm_feature(env, ARM_FEATURE_EL3)) { - cs->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR_NS; - } else { - cs->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR; - } - memset(cs->icc_apr, 0, sizeof(cs->icc_apr)); - memset(cs->icc_igrpen, 0, sizeof(cs->icc_igrpen)); - cs->icc_ctlr_el3 = ICC_CTLR_EL3_NDS | ICC_CTLR_EL3_A3V | - (1 << ICC_CTLR_EL3_IDBITS_SHIFT) | - (7 << ICC_CTLR_EL3_PRIBITS_SHIFT); -} - -static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { - { .name = "ICC_PMR_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 6, .opc2 = 0, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irqfiq_access, - .readfn = icc_pmr_read, - .writefn = icc_pmr_write, - /* We hang the whole cpu interface reset routine off here - * rather than parcelling it out into one little function - * per register - */ - .resetfn = icc_reset, - }, - { .name = "ICC_IAR0_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 0, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_R, .accessfn = gicv3_fiq_access, - .readfn = icc_iar0_read, - }, - { .name = "ICC_EOIR0_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 1, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_W, .accessfn = gicv3_fiq_access, - .writefn = icc_eoir_write, - }, - { .name = "ICC_HPPIR0_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 2, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_R, .accessfn = gicv3_fiq_access, - .readfn = icc_hppir0_read, - }, - { .name = "ICC_BPR0_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 3, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_bpr[GICV3_G0]), - .writefn = icc_bpr_write, - }, - { .name = "ICC_AP0R0_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 4, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][0]), - .writefn = icc_ap_write, - }, - { .name = "ICC_AP0R1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 5, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][1]), - .writefn = icc_ap_write, - }, - { .name = "ICC_AP0R2_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 6, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][2]), - .writefn = icc_ap_write, - }, - { .name = "ICC_AP0R3_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 8, .opc2 = 7, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_apr[GICV3_G0][3]), - .writefn = icc_ap_write, - }, - /* All the ICC_AP1R*_EL1 registers are banked */ - { .name = "ICC_AP1R0_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 0, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP1R1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 1, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP1R2_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 2, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_AP1R3_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 9, .opc2 = 3, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_ap_read, - .writefn = icc_ap_write, - }, - { .name = "ICC_DIR_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 1, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_W, .accessfn = gicv3_irqfiq_access, - .writefn = icc_dir_write, - }, - { .name = "ICC_RPR_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 3, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_R, .accessfn = gicv3_irqfiq_access, - .readfn = icc_rpr_read, - }, - { .name = "ICC_SGI1R_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 5, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_W, .accessfn = gicv3_irqfiq_access, - .writefn = icc_sgi1r_write, - }, - { .name = "ICC_SGI1R", - .cp = 15, .opc1 = 0, .crm = 12, - .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_W, .accessfn = gicv3_irqfiq_access, - .writefn = icc_sgi1r_write, - }, - { .name = "ICC_ASGI1R_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 6, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_W, .accessfn = gicv3_irqfiq_access, - .writefn = icc_asgi1r_write, - }, - { .name = "ICC_ASGI1R", - .cp = 15, .opc1 = 1, .crm = 12, - .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_W, .accessfn = gicv3_irqfiq_access, - .writefn = icc_asgi1r_write, - }, - { .name = "ICC_SGI0R_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 11, .opc2 = 7, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_W, .accessfn = gicv3_irqfiq_access, - .writefn = icc_sgi0r_write, - }, - { .name = "ICC_SGI0R", - .cp = 15, .opc1 = 2, .crm = 12, - .type = ARM_CP_64BIT | ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_W, .accessfn = gicv3_irqfiq_access, - .writefn = icc_sgi0r_write, - }, - { .name = "ICC_IAR1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 0, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_R, .accessfn = gicv3_irq_access, - .readfn = icc_iar1_read, - }, - { .name = "ICC_EOIR1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 1, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_W, .accessfn = gicv3_irq_access, - .writefn = icc_eoir_write, - }, - { .name = "ICC_HPPIR1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 2, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_R, .accessfn = gicv3_irq_access, - .readfn = icc_hppir1_read, - }, - /* This register is banked */ - { .name = "ICC_BPR1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 3, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_bpr_read, - .writefn = icc_bpr_write, - }, - /* This register is banked */ - { .name = "ICC_CTLR_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 4, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irqfiq_access, - .readfn = icc_ctlr_el1_read, - .writefn = icc_ctlr_el1_write, - }, - { .name = "ICC_SRE_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 5, - .type = ARM_CP_NO_RAW | ARM_CP_CONST, - .access = PL1_RW, - /* We don't support IRQ/FIQ bypass and system registers are - * always enabled, so all our bits are RAZ/WI or RAO/WI. - * This register is banked but since it's constant we don't - * need to do anything special. - */ - .resetvalue = 0x7, - }, - { .name = "ICC_IGRPEN0_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 6, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_fiq_access, - .fieldoffset = offsetof(GICv3CPUState, icc_igrpen[GICV3_G0]), - .writefn = icc_igrpen_write, - }, - /* This register is banked */ - { .name = "ICC_IGRPEN1_EL1", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 7, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL1_RW, .accessfn = gicv3_irq_access, - .readfn = icc_igrpen_read, - .writefn = icc_igrpen_write, - }, - { .name = "ICC_SRE_EL2", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 9, .opc2 = 5, - .type = ARM_CP_NO_RAW | ARM_CP_CONST, - .access = PL2_RW, - /* We don't support IRQ/FIQ bypass and system registers are - * always enabled, so all our bits are RAZ/WI or RAO/WI. - */ - .resetvalue = 0xf, - }, - { .name = "ICC_CTLR_EL3", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 12, .opc2 = 4, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL3_RW, - .fieldoffset = offsetof(GICv3CPUState, icc_ctlr_el3), - .readfn = icc_ctlr_el3_read, - .writefn = icc_ctlr_el3_write, - }, - { .name = "ICC_SRE_EL3", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 12, .opc2 = 5, - .type = ARM_CP_NO_RAW | ARM_CP_CONST, - .access = PL3_RW, - /* We don't support IRQ/FIQ bypass and system registers are - * always enabled, so all our bits are RAZ/WI or RAO/WI. - */ - .resetvalue = 0xf, - }, - { .name = "ICC_IGRPEN1_EL3", .state = ARM_CP_STATE_BOTH, - .opc0 = 3, .opc1 = 6, .crn = 12, .crm = 12, .opc2 = 7, - .type = ARM_CP_IO | ARM_CP_NO_RAW, - .access = PL3_RW, - .readfn = icc_igrpen1_el3_read, - .writefn = icc_igrpen1_el3_write, - }, - REGINFO_SENTINEL -}; - -static void gicv3_cpuif_el_change_hook(ARMCPU *cpu, void *opaque) -{ - GICv3CPUState *cs = opaque; - - gicv3_cpuif_update(cs); -} - -void gicv3_init_cpuif(GICv3State *s) -{ - /* Called from the GICv3 realize function; register our system - * registers with the CPU - */ - int i; - - for (i = 0; i < s->num_cpu; i++) { - ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); - GICv3CPUState *cs = &s->cpu[i]; - - /* Note that we can't just use the GICv3CPUState as an opaque pointer - * in define_arm_cp_regs_with_opaque(), because when we're called back - * it might be with code translated by CPU 0 but run by CPU 1, in - * which case we'd get the wrong value. - * So instead we define the regs with no ri->opaque info, and - * get back to the GICv3CPUState from the ARMCPU by reading back - * the opaque pointer from the el_change_hook, which we're going - * to need to register anyway. - */ - define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); - arm_register_el_change_hook(cpu, gicv3_cpuif_el_change_hook, cs); - } -} diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c deleted file mode 100644 index 3ea3dd0d4..000000000 --- a/hw/intc/arm_gicv3_dist.c +++ /dev/null @@ -1,880 +0,0 @@ -/* - * ARM GICv3 emulation: Distributor - * - * Copyright (c) 2015 Huawei. - * Copyright (c) 2016 Linaro Limited. - * Written by Shlomo Pongratz, Peter Maydell - * - * This code is licensed under the GPL, version 2 or (at your option) - * any later version. - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "trace.h" -#include "gicv3_internal.h" - -/* The GICD_NSACR registers contain a two bit field for each interrupt which - * allows the guest to give NonSecure code access to registers controlling - * Secure interrupts: - * 0b00: no access (NS accesses to bits for Secure interrupts will RAZ/WI) - * 0b01: NS r/w accesses permitted to ISPENDR, SETSPI_NSR, SGIR - * 0b10: as 0b01, and also r/w to ICPENDR, r/o to ISACTIVER/ICACTIVER, - * and w/o to CLRSPI_NSR - * 0b11: as 0b10, and also r/w to IROUTER and ITARGETSR - * - * Given a (multiple-of-32) interrupt number, these mask functions return - * a mask word where each bit is 1 if the NSACR settings permit access - * to the interrupt. The mask returned can then be ORed with the GICD_GROUP - * word for this set of interrupts to give an overall mask. - */ - -typedef uint32_t maskfn(GICv3State *s, int irq); - -static uint32_t mask_nsacr_ge1(GICv3State *s, int irq) -{ - /* Return a mask where each bit is set if the NSACR field is >= 1 */ - uint64_t raw_nsacr = s->gicd_nsacr[irq / 16 + 1]; - - raw_nsacr = raw_nsacr << 32 | s->gicd_nsacr[irq / 16]; - raw_nsacr = (raw_nsacr >> 1) | raw_nsacr; - return half_unshuffle64(raw_nsacr); -} - -static uint32_t mask_nsacr_ge2(GICv3State *s, int irq) -{ - /* Return a mask where each bit is set if the NSACR field is >= 2 */ - uint64_t raw_nsacr = s->gicd_nsacr[irq / 16 + 1]; - - raw_nsacr = raw_nsacr << 32 | s->gicd_nsacr[irq / 16]; - raw_nsacr = raw_nsacr >> 1; - return half_unshuffle64(raw_nsacr); -} - -/* We don't need a mask_nsacr_ge3() because IROUTER<n> isn't a bitmap register, - * but it would be implemented using: - * raw_nsacr = (raw_nsacr >> 1) & raw_nsacr; - */ - -static uint32_t mask_group_and_nsacr(GICv3State *s, MemTxAttrs attrs, - maskfn *maskfn, int irq) -{ - /* Return a 32-bit mask which should be applied for this set of 32 - * interrupts; each bit is 1 if access is permitted by the - * combination of attrs.secure, GICD_GROUPR and GICD_NSACR. - */ - uint32_t mask; - - if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { - /* bits for Group 0 or Secure Group 1 interrupts are RAZ/WI - * unless the NSACR bits permit access. - */ - mask = *gic_bmp_ptr32(s->group, irq); - if (maskfn) { - mask |= maskfn(s, irq); - } - return mask; - } - return 0xFFFFFFFFU; -} - -static int gicd_ns_access(GICv3State *s, int irq) -{ - /* Return the 2 bit NS_access<x> field from GICD_NSACR<n> for the - * specified interrupt. - */ - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return 0; - } - return extract32(s->gicd_nsacr[irq / 16], (irq % 16) * 2, 2); -} - -static void gicd_write_set_bitmap_reg(GICv3State *s, MemTxAttrs attrs, - uint32_t *bmp, - maskfn *maskfn, - int offset, uint32_t val) -{ - /* Helper routine to implement writing to a "set-bitmap" register - * (GICD_ISENABLER, GICD_ISPENDR, etc). - * Semantics implemented here: - * RAZ/WI for SGIs, PPIs, unimplemented IRQs - * Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI. - * Writing 1 means "set bit in bitmap"; writing 0 is ignored. - * offset should be the offset in bytes of the register from the start - * of its group. - */ - int irq = offset * 8; - - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return; - } - val &= mask_group_and_nsacr(s, attrs, maskfn, irq); - *gic_bmp_ptr32(bmp, irq) |= val; - gicv3_update(s, irq, 32); -} - -static void gicd_write_clear_bitmap_reg(GICv3State *s, MemTxAttrs attrs, - uint32_t *bmp, - maskfn *maskfn, - int offset, uint32_t val) -{ - /* Helper routine to implement writing to a "clear-bitmap" register - * (GICD_ICENABLER, GICD_ICPENDR, etc). - * Semantics implemented here: - * RAZ/WI for SGIs, PPIs, unimplemented IRQs - * Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI. - * Writing 1 means "clear bit in bitmap"; writing 0 is ignored. - * offset should be the offset in bytes of the register from the start - * of its group. - */ - int irq = offset * 8; - - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return; - } - val &= mask_group_and_nsacr(s, attrs, maskfn, irq); - *gic_bmp_ptr32(bmp, irq) &= ~val; - gicv3_update(s, irq, 32); -} - -static uint32_t gicd_read_bitmap_reg(GICv3State *s, MemTxAttrs attrs, - uint32_t *bmp, - maskfn *maskfn, - int offset) -{ - /* Helper routine to implement reading a "set/clear-bitmap" register - * (GICD_ICENABLER, GICD_ISENABLER, GICD_ICPENDR, etc). - * Semantics implemented here: - * RAZ/WI for SGIs, PPIs, unimplemented IRQs - * Bits corresponding to Group 0 or Secure Group 1 interrupts RAZ/WI. - * offset should be the offset in bytes of the register from the start - * of its group. - */ - int irq = offset * 8; - uint32_t val; - - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return 0; - } - val = *gic_bmp_ptr32(bmp, irq); - if (bmp == s->pending) { - /* The PENDING register is a special case -- for level triggered - * interrupts, the PENDING state is the logical OR of the state of - * the PENDING latch with the input line level. - */ - uint32_t edge = *gic_bmp_ptr32(s->edge_trigger, irq); - uint32_t level = *gic_bmp_ptr32(s->level, irq); - val |= (~edge & level); - } - val &= mask_group_and_nsacr(s, attrs, maskfn, irq); - return val; -} - -static uint8_t gicd_read_ipriorityr(GICv3State *s, MemTxAttrs attrs, int irq) -{ - /* Read the value of GICD_IPRIORITYR<n> for the specified interrupt, - * honouring security state (these are RAZ/WI for Group 0 or Secure - * Group 1 interrupts). - */ - uint32_t prio; - - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return 0; - } - - prio = s->gicd_ipriority[irq]; - - if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { - if (!gicv3_gicd_group_test(s, irq)) { - /* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */ - return 0; - } - /* NS view of the interrupt priority */ - prio = (prio << 1) & 0xff; - } - return prio; -} - -static void gicd_write_ipriorityr(GICv3State *s, MemTxAttrs attrs, int irq, - uint8_t value) -{ - /* Write the value of GICD_IPRIORITYR<n> for the specified interrupt, - * honouring security state (these are RAZ/WI for Group 0 or Secure - * Group 1 interrupts). - */ - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return; - } - - if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { - if (!gicv3_gicd_group_test(s, irq)) { - /* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */ - return; - } - /* NS view of the interrupt priority */ - value = 0x80 | (value >> 1); - } - s->gicd_ipriority[irq] = value; -} - -static uint64_t gicd_read_irouter(GICv3State *s, MemTxAttrs attrs, int irq) -{ - /* Read the value of GICD_IROUTER<n> for the specified interrupt, - * honouring security state. - */ - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return 0; - } - - if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { - /* RAZ/WI for NS accesses to secure interrupts */ - if (!gicv3_gicd_group_test(s, irq)) { - if (gicd_ns_access(s, irq) != 3) { - return 0; - } - } - } - - return s->gicd_irouter[irq]; -} - -static void gicd_write_irouter(GICv3State *s, MemTxAttrs attrs, int irq, - uint64_t val) -{ - /* Write the value of GICD_IROUTER<n> for the specified interrupt, - * honouring security state. - */ - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return; - } - - if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { - /* RAZ/WI for NS accesses to secure interrupts */ - if (!gicv3_gicd_group_test(s, irq)) { - if (gicd_ns_access(s, irq) != 3) { - return; - } - } - } - - s->gicd_irouter[irq] = val; - gicv3_cache_target_cpustate(s, irq); - gicv3_update(s, irq, 1); -} - -static MemTxResult gicd_readb(GICv3State *s, hwaddr offset, - uint64_t *data, MemTxAttrs attrs) -{ - /* Most GICv3 distributor registers do not support byte accesses. */ - switch (offset) { - case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf: - case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: - case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff: - /* This GIC implementation always has affinity routing enabled, - * so these registers are all RAZ/WI. - */ - return MEMTX_OK; - case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: - *data = gicd_read_ipriorityr(s, attrs, offset - GICD_IPRIORITYR); - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -static MemTxResult gicd_writeb(GICv3State *s, hwaddr offset, - uint64_t value, MemTxAttrs attrs) -{ - /* Most GICv3 distributor registers do not support byte accesses. */ - switch (offset) { - case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf: - case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: - case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff: - /* This GIC implementation always has affinity routing enabled, - * so these registers are all RAZ/WI. - */ - return MEMTX_OK; - case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: - { - int irq = offset - GICD_IPRIORITYR; - - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return MEMTX_OK; - } - gicd_write_ipriorityr(s, attrs, irq, value); - gicv3_update(s, irq, 1); - return MEMTX_OK; - } - default: - return MEMTX_ERROR; - } -} - -static MemTxResult gicd_readw(GICv3State *s, hwaddr offset, - uint64_t *data, MemTxAttrs attrs) -{ - /* Only GICD_SETSPI_NSR, GICD_CLRSPI_NSR, GICD_SETSPI_SR and GICD_SETSPI_NSR - * support 16 bit accesses, and those registers are all part of the - * optional message-based SPI feature which this GIC does not currently - * implement (ie for us GICD_TYPER.MBIS == 0), so for us they are - * reserved. - */ - return MEMTX_ERROR; -} - -static MemTxResult gicd_writew(GICv3State *s, hwaddr offset, - uint64_t value, MemTxAttrs attrs) -{ - /* Only GICD_SETSPI_NSR, GICD_CLRSPI_NSR, GICD_SETSPI_SR and GICD_SETSPI_NSR - * support 16 bit accesses, and those registers are all part of the - * optional message-based SPI feature which this GIC does not currently - * implement (ie for us GICD_TYPER.MBIS == 0), so for us they are - * reserved. - */ - return MEMTX_ERROR; -} - -static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, - uint64_t *data, MemTxAttrs attrs) -{ - /* Almost all GICv3 distributor registers are 32-bit. - * Note that WO registers must return an UNKNOWN value on reads, - * not an abort. - */ - - switch (offset) { - case GICD_CTLR: - if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { - /* The NS view of the GICD_CTLR sees only certain bits: - * + bit [31] (RWP) is an alias of the Secure bit [31] - * + bit [4] (ARE_NS) is an alias of Secure bit [5] - * + bit [1] (EnableGrp1A) is an alias of Secure bit [1] if - * NS affinity routing is enabled, otherwise RES0 - * + bit [0] (EnableGrp1) is an alias of Secure bit [1] if - * NS affinity routing is not enabled, otherwise RES0 - * Since for QEMU affinity routing is always enabled - * for both S and NS this means that bits [4] and [5] are - * both always 1, and we can simply make the NS view - * be bits 31, 4 and 1 of the S view. - */ - *data = s->gicd_ctlr & (GICD_CTLR_ARE_S | - GICD_CTLR_EN_GRP1NS | - GICD_CTLR_RWP); - } else { - *data = s->gicd_ctlr; - } - return MEMTX_OK; - case GICD_TYPER: - { - /* For this implementation: - * No1N == 1 (1-of-N SPI interrupts not supported) - * A3V == 1 (non-zero values of Affinity level 3 supported) - * IDbits == 0xf (we support 16-bit interrupt identifiers) - * DVIS == 0 (Direct virtual LPI injection not supported) - * LPIS == 0 (LPIs not supported) - * MBIS == 0 (message-based SPIs not supported) - * SecurityExtn == 1 if security extns supported - * CPUNumber == 0 since for us ARE is always 1 - * ITLinesNumber == (num external irqs / 32) - 1 - */ - int itlinesnumber = ((s->num_irq - GIC_INTERNAL) / 32) - 1; - - *data = (1 << 25) | (1 << 24) | (s->security_extn << 10) | - (0xf << 19) | itlinesnumber; - return MEMTX_OK; - } - case GICD_IIDR: - /* We claim to be an ARM r0p0 with a zero ProductID. - * This is the same as an r0p0 GIC-500. - */ - *data = gicv3_iidr(); - return MEMTX_OK; - case GICD_STATUSR: - /* RAZ/WI for us (this is an optional register and our implementation - * does not track RO/WO/reserved violations to report them to the guest) - */ - *data = 0; - return MEMTX_OK; - case GICD_IGROUPR ... GICD_IGROUPR + 0x7f: - { - int irq; - - if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { - *data = 0; - return MEMTX_OK; - } - /* RAZ/WI for SGIs, PPIs, unimplemented irqs */ - irq = (offset - GICD_IGROUPR) * 8; - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - *data = 0; - return MEMTX_OK; - } - *data = *gic_bmp_ptr32(s->group, irq); - return MEMTX_OK; - } - case GICD_ISENABLER ... GICD_ISENABLER + 0x7f: - *data = gicd_read_bitmap_reg(s, attrs, s->enabled, NULL, - offset - GICD_ISENABLER); - return MEMTX_OK; - case GICD_ICENABLER ... GICD_ICENABLER + 0x7f: - *data = gicd_read_bitmap_reg(s, attrs, s->enabled, NULL, - offset - GICD_ICENABLER); - return MEMTX_OK; - case GICD_ISPENDR ... GICD_ISPENDR + 0x7f: - *data = gicd_read_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge1, - offset - GICD_ISPENDR); - return MEMTX_OK; - case GICD_ICPENDR ... GICD_ICPENDR + 0x7f: - *data = gicd_read_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge2, - offset - GICD_ICPENDR); - return MEMTX_OK; - case GICD_ISACTIVER ... GICD_ISACTIVER + 0x7f: - *data = gicd_read_bitmap_reg(s, attrs, s->active, mask_nsacr_ge2, - offset - GICD_ISACTIVER); - return MEMTX_OK; - case GICD_ICACTIVER ... GICD_ICACTIVER + 0x7f: - *data = gicd_read_bitmap_reg(s, attrs, s->active, mask_nsacr_ge2, - offset - GICD_ICACTIVER); - return MEMTX_OK; - case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: - { - int i, irq = offset - GICD_IPRIORITYR; - uint32_t value = 0; - - for (i = irq + 3; i >= irq; i--, value <<= 8) { - value |= gicd_read_ipriorityr(s, attrs, i); - } - *data = value; - return MEMTX_OK; - } - case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff: - /* RAZ/WI since affinity routing is always enabled */ - *data = 0; - return MEMTX_OK; - case GICD_ICFGR ... GICD_ICFGR + 0xff: - { - /* Here only the even bits are used; odd bits are RES0 */ - int irq = (offset - GICD_ICFGR) * 4; - uint32_t value = 0; - - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - *data = 0; - return MEMTX_OK; - } - - /* Since our edge_trigger bitmap is one bit per irq, we only need - * half of the 32-bit word, which we can then spread out - * into the odd bits. - */ - value = *gic_bmp_ptr32(s->edge_trigger, irq & ~0x1f); - value &= mask_group_and_nsacr(s, attrs, NULL, irq & ~0x1f); - value = extract32(value, (irq & 0x1f) ? 16 : 0, 16); - value = half_shuffle32(value) << 1; - *data = value; - return MEMTX_OK; - } - case GICD_IGRPMODR ... GICD_IGRPMODR + 0xff: - { - int irq; - - if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { - /* RAZ/WI if security disabled, or if - * security enabled and this is an NS access - */ - *data = 0; - return MEMTX_OK; - } - /* RAZ/WI for SGIs, PPIs, unimplemented irqs */ - irq = (offset - GICD_IGRPMODR) * 8; - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - *data = 0; - return MEMTX_OK; - } - *data = *gic_bmp_ptr32(s->grpmod, irq); - return MEMTX_OK; - } - case GICD_NSACR ... GICD_NSACR + 0xff: - { - /* Two bits per interrupt */ - int irq = (offset - GICD_NSACR) * 4; - - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - *data = 0; - return MEMTX_OK; - } - - if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { - /* RAZ/WI if security disabled, or if - * security enabled and this is an NS access - */ - *data = 0; - return MEMTX_OK; - } - - *data = s->gicd_nsacr[irq / 16]; - return MEMTX_OK; - } - case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf: - case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: - /* RAZ/WI since affinity routing is always enabled */ - *data = 0; - return MEMTX_OK; - case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: - { - uint64_t r; - int irq = (offset - GICD_IROUTER) / 8; - - r = gicd_read_irouter(s, attrs, irq); - if (offset & 7) { - *data = r >> 32; - } else { - *data = (uint32_t)r; - } - return MEMTX_OK; - } - case GICD_IDREGS ... GICD_IDREGS + 0x1f: - /* ID registers */ - *data = gicv3_idreg(offset - GICD_IDREGS); - return MEMTX_OK; - case GICD_SGIR: - /* WO registers, return unknown value */ - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest read from WO register at offset " - TARGET_FMT_plx "\n", __func__, offset); - *data = 0; - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, - uint64_t value, MemTxAttrs attrs) -{ - /* Almost all GICv3 distributor registers are 32-bit. Note that - * RO registers must ignore writes, not abort. - */ - - switch (offset) { - case GICD_CTLR: - { - uint32_t mask; - /* GICv3 5.3.20 */ - if (s->gicd_ctlr & GICD_CTLR_DS) { - /* With only one security state, E1NWF is RAZ/WI, DS is RAO/WI, - * ARE is RAO/WI (affinity routing always on), and only - * bits 0 and 1 (group enables) are writable. - */ - mask = GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1NS; - } else { - if (attrs.secure) { - /* for secure access: - * ARE_NS and ARE_S are RAO/WI (affinity routing always on) - * E1NWF is RAZ/WI (we don't support enable-1-of-n-wakeup) - * - * We can only modify bits[2:0] (the group enables). - */ - mask = GICD_CTLR_DS | GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1_ALL; - } else { - /* For non secure access ARE_NS is RAO/WI and EnableGrp1 - * is RES0. The only writable bit is [1] (EnableGrp1A), which - * is an alias of the Secure bit [1]. - */ - mask = GICD_CTLR_EN_GRP1NS; - } - } - s->gicd_ctlr = (s->gicd_ctlr & ~mask) | (value & mask); - if (value & mask & GICD_CTLR_DS) { - /* We just set DS, so the ARE_NS and EnG1S bits are now RES0. - * Note that this is a one-way transition because if DS is set - * then it's not writeable, so it can only go back to 0 with a - * hardware reset. - */ - s->gicd_ctlr &= ~(GICD_CTLR_EN_GRP1S | GICD_CTLR_ARE_NS); - } - gicv3_full_update(s); - return MEMTX_OK; - } - case GICD_STATUSR: - /* RAZ/WI for our implementation */ - return MEMTX_OK; - case GICD_IGROUPR ... GICD_IGROUPR + 0x7f: - { - int irq; - - if (!attrs.secure && !(s->gicd_ctlr & GICD_CTLR_DS)) { - return MEMTX_OK; - } - /* RAZ/WI for SGIs, PPIs, unimplemented irqs */ - irq = (offset - GICD_IGROUPR) * 8; - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return MEMTX_OK; - } - *gic_bmp_ptr32(s->group, irq) = value; - gicv3_update(s, irq, 32); - return MEMTX_OK; - } - case GICD_ISENABLER ... GICD_ISENABLER + 0x7f: - gicd_write_set_bitmap_reg(s, attrs, s->enabled, NULL, - offset - GICD_ISENABLER, value); - return MEMTX_OK; - case GICD_ICENABLER ... GICD_ICENABLER + 0x7f: - gicd_write_clear_bitmap_reg(s, attrs, s->enabled, NULL, - offset - GICD_ICENABLER, value); - return MEMTX_OK; - case GICD_ISPENDR ... GICD_ISPENDR + 0x7f: - gicd_write_set_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge1, - offset - GICD_ISPENDR, value); - return MEMTX_OK; - case GICD_ICPENDR ... GICD_ICPENDR + 0x7f: - gicd_write_clear_bitmap_reg(s, attrs, s->pending, mask_nsacr_ge2, - offset - GICD_ICPENDR, value); - return MEMTX_OK; - case GICD_ISACTIVER ... GICD_ISACTIVER + 0x7f: - gicd_write_set_bitmap_reg(s, attrs, s->active, NULL, - offset - GICD_ISACTIVER, value); - return MEMTX_OK; - case GICD_ICACTIVER ... GICD_ICACTIVER + 0x7f: - gicd_write_clear_bitmap_reg(s, attrs, s->active, NULL, - offset - GICD_ICACTIVER, value); - return MEMTX_OK; - case GICD_IPRIORITYR ... GICD_IPRIORITYR + 0x3ff: - { - int i, irq = offset - GICD_IPRIORITYR; - - if (irq < GIC_INTERNAL || irq + 3 >= s->num_irq) { - return MEMTX_OK; - } - - for (i = irq; i < irq + 4; i++, value >>= 8) { - gicd_write_ipriorityr(s, attrs, i, value); - } - gicv3_update(s, irq, 4); - return MEMTX_OK; - } - case GICD_ITARGETSR ... GICD_ITARGETSR + 0x3ff: - /* RAZ/WI since affinity routing is always enabled */ - return MEMTX_OK; - case GICD_ICFGR ... GICD_ICFGR + 0xff: - { - /* Here only the odd bits are used; even bits are RES0 */ - int irq = (offset - GICD_ICFGR) * 4; - uint32_t mask, oldval; - - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return MEMTX_OK; - } - - /* Since our edge_trigger bitmap is one bit per irq, our input - * 32-bits will compress down into 16 bits which we need - * to write into the bitmap. - */ - value = half_unshuffle32(value >> 1); - mask = mask_group_and_nsacr(s, attrs, NULL, irq & ~0x1f); - if (irq & 0x1f) { - value <<= 16; - mask &= 0xffff0000U; - } else { - mask &= 0xffff; - } - oldval = *gic_bmp_ptr32(s->edge_trigger, (irq & ~0x1f)); - value = (oldval & ~mask) | (value & mask); - *gic_bmp_ptr32(s->edge_trigger, irq & ~0x1f) = value; - return MEMTX_OK; - } - case GICD_IGRPMODR ... GICD_IGRPMODR + 0xff: - { - int irq; - - if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { - /* RAZ/WI if security disabled, or if - * security enabled and this is an NS access - */ - return MEMTX_OK; - } - /* RAZ/WI for SGIs, PPIs, unimplemented irqs */ - irq = (offset - GICD_IGRPMODR) * 8; - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return MEMTX_OK; - } - *gic_bmp_ptr32(s->grpmod, irq) = value; - gicv3_update(s, irq, 32); - return MEMTX_OK; - } - case GICD_NSACR ... GICD_NSACR + 0xff: - { - /* Two bits per interrupt */ - int irq = (offset - GICD_NSACR) * 4; - - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return MEMTX_OK; - } - - if ((s->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { - /* RAZ/WI if security disabled, or if - * security enabled and this is an NS access - */ - return MEMTX_OK; - } - - s->gicd_nsacr[irq / 16] = value; - /* No update required as this only affects access permission checks */ - return MEMTX_OK; - } - case GICD_SGIR: - /* RES0 if affinity routing is enabled */ - return MEMTX_OK; - case GICD_CPENDSGIR ... GICD_CPENDSGIR + 0xf: - case GICD_SPENDSGIR ... GICD_SPENDSGIR + 0xf: - /* RAZ/WI since affinity routing is always enabled */ - return MEMTX_OK; - case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: - { - uint64_t r; - int irq = (offset - GICD_IROUTER) / 8; - - if (irq < GIC_INTERNAL || irq >= s->num_irq) { - return MEMTX_OK; - } - - /* Write half of the 64-bit register */ - r = gicd_read_irouter(s, attrs, irq); - r = deposit64(r, (offset & 7) ? 32 : 0, 32, value); - gicd_write_irouter(s, attrs, irq, r); - return MEMTX_OK; - } - case GICD_IDREGS ... GICD_IDREGS + 0x1f: - case GICD_TYPER: - case GICD_IIDR: - /* RO registers, ignore the write */ - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -static MemTxResult gicd_writell(GICv3State *s, hwaddr offset, - uint64_t value, MemTxAttrs attrs) -{ - /* Our only 64-bit registers are GICD_IROUTER<n> */ - int irq; - - switch (offset) { - case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: - irq = (offset - GICD_IROUTER) / 8; - gicd_write_irouter(s, attrs, irq, value); - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -static MemTxResult gicd_readll(GICv3State *s, hwaddr offset, - uint64_t *data, MemTxAttrs attrs) -{ - /* Our only 64-bit registers are GICD_IROUTER<n> */ - int irq; - - switch (offset) { - case GICD_IROUTER ... GICD_IROUTER + 0x1fdf: - irq = (offset - GICD_IROUTER) / 8; - *data = gicd_read_irouter(s, attrs, irq); - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, - unsigned size, MemTxAttrs attrs) -{ - GICv3State *s = (GICv3State *)opaque; - MemTxResult r; - - switch (size) { - case 1: - r = gicd_readb(s, offset, data, attrs); - break; - case 2: - r = gicd_readw(s, offset, data, attrs); - break; - case 4: - r = gicd_readl(s, offset, data, attrs); - break; - case 8: - r = gicd_readll(s, offset, data, attrs); - break; - default: - r = MEMTX_ERROR; - break; - } - - if (r == MEMTX_ERROR) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest read at offset " TARGET_FMT_plx - "size %u\n", __func__, offset, size); - trace_gicv3_dist_badread(offset, size, attrs.secure); - } else { - trace_gicv3_dist_read(offset, *data, size, attrs.secure); - } - return r; -} - -MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data, - unsigned size, MemTxAttrs attrs) -{ - GICv3State *s = (GICv3State *)opaque; - MemTxResult r; - - switch (size) { - case 1: - r = gicd_writeb(s, offset, data, attrs); - break; - case 2: - r = gicd_writew(s, offset, data, attrs); - break; - case 4: - r = gicd_writel(s, offset, data, attrs); - break; - case 8: - r = gicd_writell(s, offset, data, attrs); - break; - default: - r = MEMTX_ERROR; - break; - } - - if (r == MEMTX_ERROR) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest write at offset " TARGET_FMT_plx - "size %u\n", __func__, offset, size); - trace_gicv3_dist_badwrite(offset, data, size, attrs.secure); - } else { - trace_gicv3_dist_write(offset, data, size, attrs.secure); - } - return r; -} - -void gicv3_dist_set_irq(GICv3State *s, int irq, int level) -{ - /* Update distributor state for a change in an external SPI input line */ - if (level == gicv3_gicd_level_test(s, irq)) { - return; - } - - trace_gicv3_dist_set_irq(irq, level); - - gicv3_gicd_level_replace(s, irq, level); - - if (level) { - /* 0->1 edges latch the pending bit for edge-triggered interrupts */ - if (gicv3_gicd_edge_trigger_test(s, irq)) { - gicv3_gicd_pending_set(s, irq); - } - } - - gicv3_update(s, irq, 1); -} diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 711fde38f..acc173004 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -26,7 +26,6 @@ #include "sysemu/kvm.h" #include "kvm_arm.h" #include "vgic_common.h" -#include "migration/migration.h" #ifdef DEBUG_GICV3_KVM #define DPRINTF(fmt, ...) \ @@ -120,13 +119,6 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd); kvm_arm_register_device(&s->iomem_redist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd); - - /* Block migration of a KVM GICv3 device: the API for saving and restoring - * the state in the kernel is not yet finalised in the kernel or - * implemented in QEMU. - */ - error_setg(&s->migration_blocker, "vGICv3 migration is not implemented"); - migrate_add_blocker(s->migration_blocker); } static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c deleted file mode 100644 index 77e5cfa32..000000000 --- a/hw/intc/arm_gicv3_redist.c +++ /dev/null @@ -1,567 +0,0 @@ -/* - * ARM GICv3 emulation: Redistributor - * - * Copyright (c) 2015 Huawei. - * Copyright (c) 2016 Linaro Limited. - * Written by Shlomo Pongratz, Peter Maydell - * - * This code is licensed under the GPL, version 2 or (at your option) - * any later version. - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "trace.h" -#include "gicv3_internal.h" - -static uint32_t mask_group(GICv3CPUState *cs, MemTxAttrs attrs) -{ - /* Return a 32-bit mask which should be applied for this set of 32 - * interrupts; each bit is 1 if access is permitted by the - * combination of attrs.secure and GICR_GROUPR. (GICR_NSACR does - * not affect config register accesses, unlike GICD_NSACR.) - */ - if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { - /* bits for Group 0 or Secure Group 1 interrupts are RAZ/WI */ - return cs->gicr_igroupr0; - } - return 0xFFFFFFFFU; -} - -static int gicr_ns_access(GICv3CPUState *cs, int irq) -{ - /* Return the 2 bit NSACR.NS_access field for this SGI */ - assert(irq < 16); - return extract32(cs->gicr_nsacr, irq * 2, 2); -} - -static void gicr_write_set_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs, - uint32_t *reg, uint32_t val) -{ - /* Helper routine to implement writing to a "set-bitmap" register */ - val &= mask_group(cs, attrs); - *reg |= val; - gicv3_redist_update(cs); -} - -static void gicr_write_clear_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs, - uint32_t *reg, uint32_t val) -{ - /* Helper routine to implement writing to a "clear-bitmap" register */ - val &= mask_group(cs, attrs); - *reg &= ~val; - gicv3_redist_update(cs); -} - -static uint32_t gicr_read_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs, - uint32_t reg) -{ - reg &= mask_group(cs, attrs); - return reg; -} - -static uint8_t gicr_read_ipriorityr(GICv3CPUState *cs, MemTxAttrs attrs, - int irq) -{ - /* Read the value of GICR_IPRIORITYR<n> for the specified interrupt, - * honouring security state (these are RAZ/WI for Group 0 or Secure - * Group 1 interrupts). - */ - uint32_t prio; - - prio = cs->gicr_ipriorityr[irq]; - - if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { - if (!(cs->gicr_igroupr0 & (1U << irq))) { - /* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */ - return 0; - } - /* NS view of the interrupt priority */ - prio = (prio << 1) & 0xff; - } - return prio; -} - -static void gicr_write_ipriorityr(GICv3CPUState *cs, MemTxAttrs attrs, int irq, - uint8_t value) -{ - /* Write the value of GICD_IPRIORITYR<n> for the specified interrupt, - * honouring security state (these are RAZ/WI for Group 0 or Secure - * Group 1 interrupts). - */ - if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { - if (!(cs->gicr_igroupr0 & (1U << irq))) { - /* Fields for Group 0 or Secure Group 1 interrupts are RAZ/WI */ - return; - } - /* NS view of the interrupt priority */ - value = 0x80 | (value >> 1); - } - cs->gicr_ipriorityr[irq] = value; -} - -static MemTxResult gicr_readb(GICv3CPUState *cs, hwaddr offset, - uint64_t *data, MemTxAttrs attrs) -{ - switch (offset) { - case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f: - *data = gicr_read_ipriorityr(cs, attrs, offset - GICR_IPRIORITYR); - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -static MemTxResult gicr_writeb(GICv3CPUState *cs, hwaddr offset, - uint64_t value, MemTxAttrs attrs) -{ - switch (offset) { - case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f: - gicr_write_ipriorityr(cs, attrs, offset - GICR_IPRIORITYR, value); - gicv3_redist_update(cs); - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -static MemTxResult gicr_readl(GICv3CPUState *cs, hwaddr offset, - uint64_t *data, MemTxAttrs attrs) -{ - switch (offset) { - case GICR_CTLR: - *data = cs->gicr_ctlr; - return MEMTX_OK; - case GICR_IIDR: - *data = gicv3_iidr(); - return MEMTX_OK; - case GICR_TYPER: - *data = extract64(cs->gicr_typer, 0, 32); - return MEMTX_OK; - case GICR_TYPER + 4: - *data = extract64(cs->gicr_typer, 32, 32); - return MEMTX_OK; - case GICR_STATUSR: - /* RAZ/WI for us (this is an optional register and our implementation - * does not track RO/WO/reserved violations to report them to the guest) - */ - *data = 0; - return MEMTX_OK; - case GICR_WAKER: - *data = cs->gicr_waker; - return MEMTX_OK; - case GICR_PROPBASER: - *data = extract64(cs->gicr_propbaser, 0, 32); - return MEMTX_OK; - case GICR_PROPBASER + 4: - *data = extract64(cs->gicr_propbaser, 32, 32); - return MEMTX_OK; - case GICR_PENDBASER: - *data = extract64(cs->gicr_pendbaser, 0, 32); - return MEMTX_OK; - case GICR_PENDBASER + 4: - *data = extract64(cs->gicr_pendbaser, 32, 32); - return MEMTX_OK; - case GICR_IGROUPR0: - if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { - *data = 0; - return MEMTX_OK; - } - *data = cs->gicr_igroupr0; - return MEMTX_OK; - case GICR_ISENABLER0: - case GICR_ICENABLER0: - *data = gicr_read_bitmap_reg(cs, attrs, cs->gicr_ienabler0); - return MEMTX_OK; - case GICR_ISPENDR0: - case GICR_ICPENDR0: - { - /* The pending register reads as the logical OR of the pending - * latch and the input line level for level-triggered interrupts. - */ - uint32_t val = cs->gicr_ipendr0 | (~cs->edge_trigger & cs->level); - *data = gicr_read_bitmap_reg(cs, attrs, val); - return MEMTX_OK; - } - case GICR_ISACTIVER0: - case GICR_ICACTIVER0: - *data = gicr_read_bitmap_reg(cs, attrs, cs->gicr_iactiver0); - return MEMTX_OK; - case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f: - { - int i, irq = offset - GICR_IPRIORITYR; - uint32_t value = 0; - - for (i = irq + 3; i >= irq; i--, value <<= 8) { - value |= gicr_read_ipriorityr(cs, attrs, i); - } - *data = value; - return MEMTX_OK; - } - case GICR_ICFGR0: - case GICR_ICFGR1: - { - /* Our edge_trigger bitmap is one bit per irq; take the correct - * half of it, and spread it out into the odd bits. - */ - uint32_t value; - - value = cs->edge_trigger & mask_group(cs, attrs); - value = extract32(value, (offset == GICR_ICFGR1) ? 16 : 0, 16); - value = half_shuffle32(value) << 1; - *data = value; - return MEMTX_OK; - } - case GICR_IGRPMODR0: - if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { - /* RAZ/WI if security disabled, or if - * security enabled and this is an NS access - */ - *data = 0; - return MEMTX_OK; - } - *data = cs->gicr_igrpmodr0; - return MEMTX_OK; - case GICR_NSACR: - if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { - /* RAZ/WI if security disabled, or if - * security enabled and this is an NS access - */ - *data = 0; - return MEMTX_OK; - } - *data = cs->gicr_nsacr; - return MEMTX_OK; - case GICR_IDREGS ... GICR_IDREGS + 0x1f: - *data = gicv3_idreg(offset - GICR_IDREGS); - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, - uint64_t value, MemTxAttrs attrs) -{ - switch (offset) { - case GICR_CTLR: - /* For our implementation, GICR_TYPER.DPGS is 0 and so all - * the DPG bits are RAZ/WI. We don't do anything asynchronously, - * so UWP and RWP are RAZ/WI. And GICR_TYPER.LPIS is 0 (we don't - * implement LPIs) so Enable_LPIs is RES0. So there are no writable - * bits for us. - */ - return MEMTX_OK; - case GICR_STATUSR: - /* RAZ/WI for our implementation */ - return MEMTX_OK; - case GICR_WAKER: - /* Only the ProcessorSleep bit is writeable. When the guest sets - * it it requests that we transition the channel between the - * redistributor and the cpu interface to quiescent, and that - * we set the ChildrenAsleep bit once the inteface has reached the - * quiescent state. - * Setting the ProcessorSleep to 0 reverses the quiescing, and - * ChildrenAsleep is cleared once the transition is complete. - * Since our interface is not asynchronous, we complete these - * transitions instantaneously, so we set ChildrenAsleep to the - * same value as ProcessorSleep here. - */ - value &= GICR_WAKER_ProcessorSleep; - if (value & GICR_WAKER_ProcessorSleep) { - value |= GICR_WAKER_ChildrenAsleep; - } - cs->gicr_waker = value; - return MEMTX_OK; - case GICR_PROPBASER: - cs->gicr_propbaser = deposit64(cs->gicr_propbaser, 0, 32, value); - return MEMTX_OK; - case GICR_PROPBASER + 4: - cs->gicr_propbaser = deposit64(cs->gicr_propbaser, 32, 32, value); - return MEMTX_OK; - case GICR_PENDBASER: - cs->gicr_pendbaser = deposit64(cs->gicr_pendbaser, 0, 32, value); - return MEMTX_OK; - case GICR_PENDBASER + 4: - cs->gicr_pendbaser = deposit64(cs->gicr_pendbaser, 32, 32, value); - return MEMTX_OK; - case GICR_IGROUPR0: - if (!attrs.secure && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { - return MEMTX_OK; - } - cs->gicr_igroupr0 = value; - gicv3_redist_update(cs); - return MEMTX_OK; - case GICR_ISENABLER0: - gicr_write_set_bitmap_reg(cs, attrs, &cs->gicr_ienabler0, value); - return MEMTX_OK; - case GICR_ICENABLER0: - gicr_write_clear_bitmap_reg(cs, attrs, &cs->gicr_ienabler0, value); - return MEMTX_OK; - case GICR_ISPENDR0: - gicr_write_set_bitmap_reg(cs, attrs, &cs->gicr_ipendr0, value); - return MEMTX_OK; - case GICR_ICPENDR0: - gicr_write_clear_bitmap_reg(cs, attrs, &cs->gicr_ipendr0, value); - return MEMTX_OK; - case GICR_ISACTIVER0: - gicr_write_set_bitmap_reg(cs, attrs, &cs->gicr_iactiver0, value); - return MEMTX_OK; - case GICR_ICACTIVER0: - gicr_write_clear_bitmap_reg(cs, attrs, &cs->gicr_iactiver0, value); - return MEMTX_OK; - case GICR_IPRIORITYR ... GICR_IPRIORITYR + 0x1f: - { - int i, irq = offset - GICR_IPRIORITYR; - - for (i = irq; i < irq + 4; i++, value >>= 8) { - gicr_write_ipriorityr(cs, attrs, i, value); - } - gicv3_redist_update(cs); - return MEMTX_OK; - } - case GICR_ICFGR0: - /* Register is all RAZ/WI or RAO/WI bits */ - return MEMTX_OK; - case GICR_ICFGR1: - { - uint32_t mask; - - /* Since our edge_trigger bitmap is one bit per irq, our input - * 32-bits will compress down into 16 bits which we need - * to write into the bitmap. - */ - value = half_unshuffle32(value >> 1) << 16; - mask = mask_group(cs, attrs) & 0xffff0000U; - - cs->edge_trigger &= ~mask; - cs->edge_trigger |= (value & mask); - - gicv3_redist_update(cs); - return MEMTX_OK; - } - case GICR_IGRPMODR0: - if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { - /* RAZ/WI if security disabled, or if - * security enabled and this is an NS access - */ - return MEMTX_OK; - } - cs->gicr_igrpmodr0 = value; - gicv3_redist_update(cs); - return MEMTX_OK; - case GICR_NSACR: - if ((cs->gic->gicd_ctlr & GICD_CTLR_DS) || !attrs.secure) { - /* RAZ/WI if security disabled, or if - * security enabled and this is an NS access - */ - return MEMTX_OK; - } - cs->gicr_nsacr = value; - /* no update required as this only affects access permission checks */ - return MEMTX_OK; - case GICR_IIDR: - case GICR_TYPER: - case GICR_IDREGS ... GICR_IDREGS + 0x1f: - /* RO registers, ignore the write */ - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -static MemTxResult gicr_readll(GICv3CPUState *cs, hwaddr offset, - uint64_t *data, MemTxAttrs attrs) -{ - switch (offset) { - case GICR_TYPER: - *data = cs->gicr_typer; - return MEMTX_OK; - case GICR_PROPBASER: - *data = cs->gicr_propbaser; - return MEMTX_OK; - case GICR_PENDBASER: - *data = cs->gicr_pendbaser; - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -static MemTxResult gicr_writell(GICv3CPUState *cs, hwaddr offset, - uint64_t value, MemTxAttrs attrs) -{ - switch (offset) { - case GICR_PROPBASER: - cs->gicr_propbaser = value; - return MEMTX_OK; - case GICR_PENDBASER: - cs->gicr_pendbaser = value; - return MEMTX_OK; - case GICR_TYPER: - /* RO register, ignore the write */ - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest write to RO register at offset " - TARGET_FMT_plx "\n", __func__, offset); - return MEMTX_OK; - default: - return MEMTX_ERROR; - } -} - -MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data, - unsigned size, MemTxAttrs attrs) -{ - GICv3State *s = opaque; - GICv3CPUState *cs; - MemTxResult r; - int cpuidx; - - assert((offset & (size - 1)) == 0); - - /* This region covers all the redistributor pages; there are - * (for GICv3) two 64K pages per CPU. At the moment they are - * all contiguous (ie in this one region), though we might later - * want to allow splitting of redistributor pages into several - * blocks so we can support more CPUs. - */ - cpuidx = offset / 0x20000; - offset %= 0x20000; - assert(cpuidx < s->num_cpu); - - cs = &s->cpu[cpuidx]; - - switch (size) { - case 1: - r = gicr_readb(cs, offset, data, attrs); - break; - case 4: - r = gicr_readl(cs, offset, data, attrs); - break; - case 8: - r = gicr_readll(cs, offset, data, attrs); - break; - default: - r = MEMTX_ERROR; - break; - } - - if (r == MEMTX_ERROR) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest read at offset " TARGET_FMT_plx - "size %u\n", __func__, offset, size); - trace_gicv3_redist_badread(gicv3_redist_affid(cs), offset, - size, attrs.secure); - } else { - trace_gicv3_redist_read(gicv3_redist_affid(cs), offset, *data, - size, attrs.secure); - } - return r; -} - -MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, - unsigned size, MemTxAttrs attrs) -{ - GICv3State *s = opaque; - GICv3CPUState *cs; - MemTxResult r; - int cpuidx; - - assert((offset & (size - 1)) == 0); - - /* This region covers all the redistributor pages; there are - * (for GICv3) two 64K pages per CPU. At the moment they are - * all contiguous (ie in this one region), though we might later - * want to allow splitting of redistributor pages into several - * blocks so we can support more CPUs. - */ - cpuidx = offset / 0x20000; - offset %= 0x20000; - assert(cpuidx < s->num_cpu); - - cs = &s->cpu[cpuidx]; - - switch (size) { - case 1: - r = gicr_writeb(cs, offset, data, attrs); - break; - case 4: - r = gicr_writel(cs, offset, data, attrs); - break; - case 8: - r = gicr_writell(cs, offset, data, attrs); - break; - default: - r = MEMTX_ERROR; - break; - } - - if (r == MEMTX_ERROR) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid guest write at offset " TARGET_FMT_plx - "size %u\n", __func__, offset, size); - trace_gicv3_redist_badwrite(gicv3_redist_affid(cs), offset, data, - size, attrs.secure); - } else { - trace_gicv3_redist_write(gicv3_redist_affid(cs), offset, data, - size, attrs.secure); - } - return r; -} - -void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level) -{ - /* Update redistributor state for a change in an external PPI input line */ - if (level == extract32(cs->level, irq, 1)) { - return; - } - - trace_gicv3_redist_set_irq(gicv3_redist_affid(cs), irq, level); - - cs->level = deposit32(cs->level, irq, 1, level); - - if (level) { - /* 0->1 edges latch the pending bit for edge-triggered interrupts */ - if (extract32(cs->edge_trigger, irq, 1)) { - cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 1); - } - } - - gicv3_redist_update(cs); -} - -void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns) -{ - /* Update redistributor state for a generated SGI */ - int irqgrp = gicv3_irq_group(cs->gic, cs, irq); - - /* If we are asked for a Secure Group 1 SGI and it's actually - * configured as Secure Group 0 this is OK (subject to the usual - * NSACR checks). - */ - if (grp == GICV3_G1 && irqgrp == GICV3_G0) { - grp = GICV3_G0; - } - - if (grp != irqgrp) { - return; - } - - if (ns && !(cs->gic->gicd_ctlr & GICD_CTLR_DS)) { - /* If security is enabled we must test the NSACR bits */ - int nsaccess = gicr_ns_access(cs, irq); - - if ((irqgrp == GICV3_G0 && nsaccess < 1) || - (irqgrp == GICV3_G1 && nsaccess < 2)) { - return; - } - } - - /* OK, we can accept the SGI */ - trace_gicv3_redist_send_sgi(gicv3_redist_affid(cs), irq); - cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 1); - gicv3_redist_update(cs); -} diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 06d8db6bd..669e82adf 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -13,13 +13,11 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" -#include "cpu.h" #include "hw/sysbus.h" #include "qemu/timer.h" #include "hw/arm/arm.h" #include "exec/address-spaces.h" #include "gic_internal.h" -#include "qemu/log.h" typedef struct { GICState gic; @@ -187,11 +185,11 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) case 0x1c: /* SysTick Calibration Value. */ return 10000; case 0xd00: /* CPUID Base. */ - cpu = ARM_CPU(qemu_get_cpu(0)); + cpu = ARM_CPU(current_cpu); return cpu->midr; case 0xd04: /* Interrupt Control State. */ /* VECTACTIVE */ - cpu = ARM_CPU(qemu_get_cpu(0)); + cpu = ARM_CPU(current_cpu); val = cpu->env.v7m.exception; if (val == 1023) { val = 0; @@ -222,7 +220,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) val |= (1 << 31); return val; case 0xd08: /* Vector Table Offset. */ - cpu = ARM_CPU(qemu_get_cpu(0)); + cpu = ARM_CPU(current_cpu); return cpu->env.v7m.vecbase; case 0xd0c: /* Application Interrupt/Reset Control. */ return 0xfa050000; @@ -349,7 +347,7 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) } break; case 0xd08: /* Vector Table Offset. */ - cpu = ARM_CPU(qemu_get_cpu(0)); + cpu = ARM_CPU(current_cpu); cpu->env.v7m.vecbase = value & 0xffffff80; break; case 0xd0c: /* Application Interrupt/Reset Control. */ diff --git a/hw/intc/aspeed_vic.c b/hw/intc/aspeed_vic.c index 2370e7485..19a0ff748 100644 --- a/hw/intc/aspeed_vic.c +++ b/hw/intc/aspeed_vic.c @@ -28,9 +28,9 @@ */ #include "qemu/osdep.h" +#include <inttypes.h> #include "hw/intc/aspeed_vic.h" #include "qemu/bitops.h" -#include "qemu/log.h" #include "trace.h" #define AVIC_NEW_BASE_OFFSET 0x80 diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c index 00d25306f..80513b28f 100644 --- a/hw/intc/bcm2835_ic.c +++ b/hw/intc/bcm2835_ic.c @@ -14,7 +14,6 @@ #include "qemu/osdep.h" #include "hw/intc/bcm2835_ic.h" -#include "qemu/log.h" #define GPU_IRQS 64 #define ARM_IRQS 8 diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c index cfa5bc736..d0271810c 100644 --- a/hw/intc/bcm2836_control.c +++ b/hw/intc/bcm2836_control.c @@ -15,7 +15,6 @@ #include "qemu/osdep.h" #include "hw/intc/bcm2836_control.h" -#include "qemu/log.h" #define REG_GPU_ROUTE 0x0c #define REG_TIMERCONTROL 0x40 diff --git a/hw/intc/etraxfs_pic.c b/hw/intc/etraxfs_pic.c index 64a6f4b4b..48f947706 100644 --- a/hw/intc/etraxfs_pic.c +++ b/hw/intc/etraxfs_pic.c @@ -146,19 +146,19 @@ static void irq_handler(void *opaque, int irq, int level) pic_update(fs); } -static void etraxfs_pic_init(Object *obj) +static int etraxfs_pic_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - struct etrax_pic *s = ETRAX_FS_PIC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + struct etrax_pic *s = ETRAX_FS_PIC(dev); qdev_init_gpio_in(dev, irq_handler, 32); sysbus_init_irq(sbd, &s->parent_irq); sysbus_init_irq(sbd, &s->parent_nmi); - memory_region_init_io(&s->mmio, obj, &pic_ops, s, + memory_region_init_io(&s->mmio, OBJECT(s), &pic_ops, s, "etraxfs-pic", R_MAX * 4); sysbus_init_mmio(sbd, &s->mmio); + return 0; } static Property etraxfs_pic_properties[] = { @@ -169,7 +169,9 @@ static Property etraxfs_pic_properties[] = { static void etraxfs_pic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = etraxfs_pic_init; dc->props = etraxfs_pic_properties; /* * Note: pointer property "interrupt_vector" may remain null, thus @@ -181,7 +183,6 @@ static const TypeInfo etraxfs_pic_info = { .name = TYPE_ETRAX_FS_PIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(struct etrax_pic), - .instance_init = etraxfs_pic_init, .class_init = etraxfs_pic_class_init, }; diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c index f19a7062b..dc0c90326 100644 --- a/hw/intc/exynos4210_combiner.c +++ b/hw/intc/exynos4210_combiner.c @@ -406,11 +406,10 @@ static const MemoryRegionOps exynos4210_combiner_ops = { /* * Internal Combiner initialization. */ -static void exynos4210_combiner_init(Object *obj) +static int exynos4210_combiner_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - Exynos4210CombinerState *s = EXYNOS4210_COMBINER(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + Exynos4210CombinerState *s = EXYNOS4210_COMBINER(dev); unsigned int i; /* Allocate general purpose input signals and connect a handler to each of @@ -422,9 +421,11 @@ static void exynos4210_combiner_init(Object *obj) sysbus_init_irq(sbd, &s->output_irq[i]); } - memory_region_init_io(&s->iomem, obj, &exynos4210_combiner_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_combiner_ops, s, "exynos4210-combiner", IIC_REGION_SIZE); sysbus_init_mmio(sbd, &s->iomem); + + return 0; } static Property exynos4210_combiner_properties[] = { @@ -435,7 +436,9 @@ static Property exynos4210_combiner_properties[] = { static void exynos4210_combiner_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = exynos4210_combiner_init; dc->reset = exynos4210_combiner_reset; dc->props = exynos4210_combiner_properties; dc->vmsd = &vmstate_exynos4210_combiner; @@ -445,7 +448,6 @@ static const TypeInfo exynos4210_combiner_info = { .name = TYPE_EXYNOS4210_COMBINER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210CombinerState), - .instance_init = exynos4210_combiner_init, .class_init = exynos4210_combiner_class_init, }; diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index fd7a8f305..4f7e89f7b 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -281,11 +281,10 @@ static void exynos4210_gic_set_irq(void *opaque, int irq, int level) qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level); } -static void exynos4210_gic_init(Object *obj) +static int exynos4210_gic_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - Exynos4210GicState *s = EXYNOS4210_GIC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + Exynos4210GicState *s = EXYNOS4210_GIC(dev); uint32_t i; const char cpu_prefix[] = "exynos4210-gic-alias_cpu"; const char dist_prefix[] = "exynos4210-gic-alias_dist"; @@ -306,15 +305,15 @@ static void exynos4210_gic_init(Object *obj) qdev_init_gpio_in(dev, exynos4210_gic_set_irq, EXYNOS4210_GIC_NIRQ - 32); - memory_region_init(&s->cpu_container, obj, "exynos4210-cpu-container", + memory_region_init(&s->cpu_container, OBJECT(s), "exynos4210-cpu-container", EXYNOS4210_EXT_GIC_CPU_REGION_SIZE); - memory_region_init(&s->dist_container, obj, "exynos4210-dist-container", + memory_region_init(&s->dist_container, OBJECT(s), "exynos4210-dist-container", EXYNOS4210_EXT_GIC_DIST_REGION_SIZE); for (i = 0; i < s->num_cpu; i++) { /* Map CPU interface per SMP Core */ sprintf(cpu_alias_name, "%s%x", cpu_prefix, i); - memory_region_init_alias(&s->cpu_alias[i], obj, + memory_region_init_alias(&s->cpu_alias[i], OBJECT(s), cpu_alias_name, sysbus_mmio_get_region(busdev, 1), 0, @@ -324,7 +323,7 @@ static void exynos4210_gic_init(Object *obj) /* Map Distributor per SMP Core */ sprintf(dist_alias_name, "%s%x", dist_prefix, i); - memory_region_init_alias(&s->dist_alias[i], obj, + memory_region_init_alias(&s->dist_alias[i], OBJECT(s), dist_alias_name, sysbus_mmio_get_region(busdev, 0), 0, @@ -335,6 +334,8 @@ static void exynos4210_gic_init(Object *obj) sysbus_init_mmio(sbd, &s->cpu_container); sysbus_init_mmio(sbd, &s->dist_container); + + return 0; } static Property exynos4210_gic_properties[] = { @@ -345,7 +346,9 @@ static Property exynos4210_gic_properties[] = { static void exynos4210_gic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = exynos4210_gic_init; dc->props = exynos4210_gic_properties; } @@ -353,7 +356,6 @@ static const TypeInfo exynos4210_gic_info = { .name = TYPE_EXYNOS4210_GIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210GicState), - .instance_init = exynos4210_gic_init, .class_init = exynos4210_gic_class_init, }; @@ -428,16 +430,9 @@ static void exynos4210_irq_gate_reset(DeviceState *d) /* * IRQ Gate initialization. */ -static void exynos4210_irq_gate_init(Object *obj) -{ - Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(sbd, &s->out); -} - -static void exynos4210_irq_gate_realize(DeviceState *dev, Error **errp) +static int exynos4210_irq_gate_init(SysBusDevice *sbd) { + DeviceState *dev = DEVICE(sbd); Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(dev); /* Allocate general purpose input signals and connect a handler to each of @@ -445,23 +440,27 @@ static void exynos4210_irq_gate_realize(DeviceState *dev, Error **errp) qdev_init_gpio_in(dev, exynos4210_irq_gate_handler, s->n_in); s->level = g_malloc0(s->n_in * sizeof(*s->level)); + + sysbus_init_irq(sbd, &s->out); + + return 0; } static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = exynos4210_irq_gate_init; dc->reset = exynos4210_irq_gate_reset; dc->vmsd = &vmstate_exynos4210_irq_gate; dc->props = exynos4210_irq_gate_properties; - dc->realize = exynos4210_irq_gate_realize; } static const TypeInfo exynos4210_irq_gate_info = { .name = TYPE_EXYNOS4210_IRQ_GATE, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210IRQGateState), - .instance_init = exynos4210_irq_gate_init, .class_init = exynos4210_irq_gate_class_init, }; diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 3f311740d..20c1e8a24 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -100,4 +100,4 @@ static inline bool gic_test_pending(GICState *s, int irq, int cm) } } -#endif /* QEMU_ARM_GIC_INTERNAL_H */ +#endif /* !QEMU_ARM_GIC_INTERNAL_H */ diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h deleted file mode 100644 index 8f3567eda..000000000 --- a/hw/intc/gicv3_internal.h +++ /dev/null @@ -1,331 +0,0 @@ -/* - * ARM GICv3 support - internal interfaces - * - * Copyright (c) 2012 Linaro Limited - * Copyright (c) 2015 Huawei. - * Copyright (c) 2015 Samsung Electronics Co., Ltd. - * Written by Peter Maydell - * Reworked for GICv3 by Shlomo Pongratz and Pavel Fedin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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_ARM_GICV3_INTERNAL_H -#define QEMU_ARM_GICV3_INTERNAL_H - -#include "hw/intc/arm_gicv3_common.h" - -/* Distributor registers, as offsets from the distributor base address */ -#define GICD_CTLR 0x0000 -#define GICD_TYPER 0x0004 -#define GICD_IIDR 0x0008 -#define GICD_STATUSR 0x0010 -#define GICD_SETSPI_NSR 0x0040 -#define GICD_CLRSPI_NSR 0x0048 -#define GICD_SETSPI_SR 0x0050 -#define GICD_CLRSPI_SR 0x0058 -#define GICD_SEIR 0x0068 -#define GICD_IGROUPR 0x0080 -#define GICD_ISENABLER 0x0100 -#define GICD_ICENABLER 0x0180 -#define GICD_ISPENDR 0x0200 -#define GICD_ICPENDR 0x0280 -#define GICD_ISACTIVER 0x0300 -#define GICD_ICACTIVER 0x0380 -#define GICD_IPRIORITYR 0x0400 -#define GICD_ITARGETSR 0x0800 -#define GICD_ICFGR 0x0C00 -#define GICD_IGRPMODR 0x0D00 -#define GICD_NSACR 0x0E00 -#define GICD_SGIR 0x0F00 -#define GICD_CPENDSGIR 0x0F10 -#define GICD_SPENDSGIR 0x0F20 -#define GICD_IROUTER 0x6000 -#define GICD_IDREGS 0xFFD0 - -/* GICD_CTLR fields */ -#define GICD_CTLR_EN_GRP0 (1U << 0) -#define GICD_CTLR_EN_GRP1NS (1U << 1) /* GICv3 5.3.20 */ -#define GICD_CTLR_EN_GRP1S (1U << 2) -#define GICD_CTLR_EN_GRP1_ALL (GICD_CTLR_EN_GRP1NS | GICD_CTLR_EN_GRP1S) -/* Bit 4 is ARE if the system doesn't support TrustZone, ARE_S otherwise */ -#define GICD_CTLR_ARE (1U << 4) -#define GICD_CTLR_ARE_S (1U << 4) -#define GICD_CTLR_ARE_NS (1U << 5) -#define GICD_CTLR_DS (1U << 6) -#define GICD_CTLR_E1NWF (1U << 7) -#define GICD_CTLR_RWP (1U << 31) - -/* - * Redistributor frame offsets from RD_base - */ -#define GICR_SGI_OFFSET 0x10000 - -/* - * Redistributor registers, offsets from RD_base - */ -#define GICR_CTLR 0x0000 -#define GICR_IIDR 0x0004 -#define GICR_TYPER 0x0008 -#define GICR_STATUSR 0x0010 -#define GICR_WAKER 0x0014 -#define GICR_SETLPIR 0x0040 -#define GICR_CLRLPIR 0x0048 -#define GICR_PROPBASER 0x0070 -#define GICR_PENDBASER 0x0078 -#define GICR_INVLPIR 0x00A0 -#define GICR_INVALLR 0x00B0 -#define GICR_SYNCR 0x00C0 -#define GICR_IDREGS 0xFFD0 - -/* SGI and PPI Redistributor registers, offsets from RD_base */ -#define GICR_IGROUPR0 (GICR_SGI_OFFSET + 0x0080) -#define GICR_ISENABLER0 (GICR_SGI_OFFSET + 0x0100) -#define GICR_ICENABLER0 (GICR_SGI_OFFSET + 0x0180) -#define GICR_ISPENDR0 (GICR_SGI_OFFSET + 0x0200) -#define GICR_ICPENDR0 (GICR_SGI_OFFSET + 0x0280) -#define GICR_ISACTIVER0 (GICR_SGI_OFFSET + 0x0300) -#define GICR_ICACTIVER0 (GICR_SGI_OFFSET + 0x0380) -#define GICR_IPRIORITYR (GICR_SGI_OFFSET + 0x0400) -#define GICR_ICFGR0 (GICR_SGI_OFFSET + 0x0C00) -#define GICR_ICFGR1 (GICR_SGI_OFFSET + 0x0C04) -#define GICR_IGRPMODR0 (GICR_SGI_OFFSET + 0x0D00) -#define GICR_NSACR (GICR_SGI_OFFSET + 0x0E00) - -#define GICR_CTLR_ENABLE_LPIS (1U << 0) -#define GICR_CTLR_RWP (1U << 3) -#define GICR_CTLR_DPG0 (1U << 24) -#define GICR_CTLR_DPG1NS (1U << 25) -#define GICR_CTLR_DPG1S (1U << 26) -#define GICR_CTLR_UWP (1U << 31) - -#define GICR_TYPER_PLPIS (1U << 0) -#define GICR_TYPER_VLPIS (1U << 1) -#define GICR_TYPER_DIRECTLPI (1U << 3) -#define GICR_TYPER_LAST (1U << 4) -#define GICR_TYPER_DPGS (1U << 5) -#define GICR_TYPER_PROCNUM (0xFFFFU << 8) -#define GICR_TYPER_COMMONLPIAFF (0x3 << 24) -#define GICR_TYPER_AFFINITYVALUE (0xFFFFFFFFULL << 32) - -#define GICR_WAKER_ProcessorSleep (1U << 1) -#define GICR_WAKER_ChildrenAsleep (1U << 2) - -#define GICR_PROPBASER_OUTER_CACHEABILITY_MASK (7ULL << 56) -#define GICR_PROPBASER_ADDR_MASK (0xfffffffffULL << 12) -#define GICR_PROPBASER_SHAREABILITY_MASK (3U << 10) -#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7) -#define GICR_PROPBASER_IDBITS_MASK (0x1f) - -#define GICR_PENDBASER_PTZ (1ULL << 62) -#define GICR_PENDBASER_OUTER_CACHEABILITY_MASK (7ULL << 56) -#define GICR_PENDBASER_ADDR_MASK (0xffffffffULL << 16) -#define GICR_PENDBASER_SHAREABILITY_MASK (3U << 10) -#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7) - -#define ICC_CTLR_EL1_CBPR (1U << 0) -#define ICC_CTLR_EL1_EOIMODE (1U << 1) -#define ICC_CTLR_EL1_PMHE (1U << 6) -#define ICC_CTLR_EL1_PRIBITS_SHIFT 8 -#define ICC_CTLR_EL1_IDBITS_SHIFT 11 -#define ICC_CTLR_EL1_SEIS (1U << 14) -#define ICC_CTLR_EL1_A3V (1U << 15) - -#define ICC_PMR_PRIORITY_MASK 0xff -#define ICC_BPR_BINARYPOINT_MASK 0x07 -#define ICC_IGRPEN_ENABLE 0x01 - -#define ICC_CTLR_EL3_CBPR_EL1S (1U << 0) -#define ICC_CTLR_EL3_CBPR_EL1NS (1U << 1) -#define ICC_CTLR_EL3_EOIMODE_EL3 (1U << 2) -#define ICC_CTLR_EL3_EOIMODE_EL1S (1U << 3) -#define ICC_CTLR_EL3_EOIMODE_EL1NS (1U << 4) -#define ICC_CTLR_EL3_RM (1U << 5) -#define ICC_CTLR_EL3_PMHE (1U << 6) -#define ICC_CTLR_EL3_PRIBITS_SHIFT 8 -#define ICC_CTLR_EL3_IDBITS_SHIFT 11 -#define ICC_CTLR_EL3_SEIS (1U << 14) -#define ICC_CTLR_EL3_A3V (1U << 15) -#define ICC_CTLR_EL3_NDS (1U << 17) - -/* Special interrupt IDs */ -#define INTID_SECURE 1020 -#define INTID_NONSECURE 1021 -#define INTID_SPURIOUS 1023 - -/* Functions internal to the emulated GICv3 */ - -/** - * gicv3_redist_update: - * @cs: GICv3CPUState for this redistributor - * - * Recalculate the highest priority pending interrupt after a - * change to redistributor state, and inform the CPU accordingly. - */ -void gicv3_redist_update(GICv3CPUState *cs); - -/** - * gicv3_update: - * @s: GICv3State - * @start: first interrupt whose state changed - * @len: length of the range of interrupts whose state changed - * - * Recalculate the highest priority pending interrupts after a - * change to the distributor state affecting @len interrupts - * starting at @start, and inform the CPUs accordingly. - */ -void gicv3_update(GICv3State *s, int start, int len); - -/** - * gicv3_full_update_noirqset: - * @s: GICv3State - * - * Recalculate the cached information about highest priority - * pending interrupts, but don't inform the CPUs. This should be - * called after an incoming migration has loaded new state. - */ -void gicv3_full_update_noirqset(GICv3State *s); - -/** - * gicv3_full_update: - * @s: GICv3State - * - * Recalculate the highest priority pending interrupts after - * a change that could affect the status of all interrupts, - * and inform the CPUs accordingly. - */ -void gicv3_full_update(GICv3State *s); -MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, - unsigned size, MemTxAttrs attrs); -MemTxResult gicv3_dist_write(void *opaque, hwaddr addr, uint64_t data, - unsigned size, MemTxAttrs attrs); -MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data, - unsigned size, MemTxAttrs attrs); -MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, - unsigned size, MemTxAttrs attrs); -void gicv3_dist_set_irq(GICv3State *s, int irq, int level); -void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level); -void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns); -void gicv3_init_cpuif(GICv3State *s); - -/** - * gicv3_cpuif_update: - * @cs: GICv3CPUState for the CPU to update - * - * Recalculate whether to assert the IRQ or FIQ lines after a change - * to the current highest priority pending interrupt, the CPU's - * current running priority or the CPU's current exception level or - * security state. - */ -void gicv3_cpuif_update(GICv3CPUState *cs); - -static inline uint32_t gicv3_iidr(void) -{ - /* Return the Implementer Identification Register value - * for the emulated GICv3, as reported in GICD_IIDR and GICR_IIDR. - * - * We claim to be an ARM r0p0 with a zero ProductID. - * This is the same as an r0p0 GIC-500. - */ - return 0x43b; -} - -static inline uint32_t gicv3_idreg(int regoffset) -{ - /* Return the value of the CoreSight ID register at the specified - * offset from the first ID register (as found in the distributor - * and redistributor register banks). - * These values indicate an ARM implementation of a GICv3. - */ - static const uint8_t gicd_ids[] = { - 0x44, 0x00, 0x00, 0x00, 0x92, 0xB4, 0x3B, 0x00, 0x0D, 0xF0, 0x05, 0xB1 - }; - return gicd_ids[regoffset / 4]; -} - -/** - * gicv3_irq_group: - * - * Return the group which this interrupt is configured as (GICV3_G0, - * GICV3_G1 or GICV3_G1NS). - */ -static inline int gicv3_irq_group(GICv3State *s, GICv3CPUState *cs, int irq) -{ - bool grpbit, grpmodbit; - - if (irq < GIC_INTERNAL) { - grpbit = extract32(cs->gicr_igroupr0, irq, 1); - grpmodbit = extract32(cs->gicr_igrpmodr0, irq, 1); - } else { - grpbit = gicv3_gicd_group_test(s, irq); - grpmodbit = gicv3_gicd_grpmod_test(s, irq); - } - if (grpbit) { - return GICV3_G1NS; - } - if (s->gicd_ctlr & GICD_CTLR_DS) { - return GICV3_G0; - } - return grpmodbit ? GICV3_G1 : GICV3_G0; -} - -/** - * gicv3_redist_affid: - * - * Return the 32-bit affinity ID of the CPU connected to this redistributor - */ -static inline uint32_t gicv3_redist_affid(GICv3CPUState *cs) -{ - return cs->gicr_typer >> 32; -} - -/** - * gicv3_cache_target_cpustate: - * - * Update the cached CPU state corresponding to the target for this interrupt - * (which is kept in s->gicd_irouter_target[]). - */ -static inline void gicv3_cache_target_cpustate(GICv3State *s, int irq) -{ - GICv3CPUState *cs = NULL; - int i; - uint32_t tgtaff = extract64(s->gicd_irouter[irq], 0, 24) | - extract64(s->gicd_irouter[irq], 32, 8) << 24; - - for (i = 0; i < s->num_cpu; i++) { - if (s->cpu[i].gicr_typer >> 32 == tgtaff) { - cs = &s->cpu[i]; - break; - } - } - - s->gicd_irouter_target[irq] = cs; -} - -/** - * gicv3_cache_all_target_cpustates: - * - * Populate the entire cache of CPU state pointers for interrupt targets - * (eg after inbound migration or CPU reset) - */ -static inline void gicv3_cache_all_target_cpustates(GICv3State *s) -{ - int irq; - - for (irq = GIC_INTERNAL; irq < GICV3_MAXIRQ; irq++) { - gicv3_cache_target_cpustate(s, irq); - } -} - -#endif /* QEMU_ARM_GICV3_INTERNAL_H */ diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c index ac7e63f38..f5ca8f752 100644 --- a/hw/intc/grlib_irqmp.c +++ b/hw/intc/grlib_irqmp.c @@ -31,7 +31,6 @@ #include "hw/sparc/grlib.h" #include "trace.h" -#include "qapi/error.h" #define IRQMP_MAX_CPU 16 #define IRQMP_REG_SIZE 256 /* Size of memory mapped registers */ @@ -324,27 +323,23 @@ static void grlib_irqmp_reset(DeviceState *d) irqmp->state->parent = irqmp; } -static void grlib_irqmp_init(Object *obj) +static int grlib_irqmp_init(SysBusDevice *dev) { - IRQMP *irqmp = GRLIB_IRQMP(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + IRQMP *irqmp = GRLIB_IRQMP(dev); + + /* Check parameters */ + if (irqmp->set_pil_in == NULL) { + return -1; + } - memory_region_init_io(&irqmp->iomem, obj, &grlib_irqmp_ops, irqmp, + memory_region_init_io(&irqmp->iomem, OBJECT(dev), &grlib_irqmp_ops, irqmp, "irqmp", IRQMP_REG_SIZE); irqmp->state = g_malloc0(sizeof *irqmp->state); sysbus_init_mmio(dev, &irqmp->iomem); -} -static void grlib_irqmp_realize(DeviceState *dev, Error **errp) -{ - IRQMP *irqmp = GRLIB_IRQMP(dev); - - /* Check parameters */ - if (irqmp->set_pil_in == NULL) { - error_setg(errp, "set_pil_in cannot be NULL."); - } + return 0; } static Property grlib_irqmp_properties[] = { @@ -356,19 +351,19 @@ static Property grlib_irqmp_properties[] = { static void grlib_irqmp_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = grlib_irqmp_init; dc->reset = grlib_irqmp_reset; dc->props = grlib_irqmp_properties; /* Reason: pointer properties "set_pil_in", "set_pil_in_opaque" */ dc->cannot_instantiate_with_device_add_yet = true; - dc->realize = grlib_irqmp_realize; } static const TypeInfo grlib_irqmp_info = { .name = TYPE_GRLIB_IRQMP, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IRQMP), - .instance_init = grlib_irqmp_init, .class_init = grlib_irqmp_class_init, }; diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index c2607a586..bb43669b9 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -27,7 +27,6 @@ #include "hw/isa/isa.h" #include "monitor/monitor.h" #include "qemu/timer.h" -#include "qemu/log.h" #include "hw/isa/i8259_internal.h" /* debug PIC */ diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c index 813e587a6..702765577 100644 --- a/hw/intc/imx_avic.c +++ b/hw/intc/imx_avic.c @@ -17,7 +17,6 @@ #include "qemu/osdep.h" #include "hw/intc/imx_avic.h" -#include "qemu/log.h" #ifndef DEBUG_IMX_AVIC #define DEBUG_IMX_AVIC 0 @@ -322,26 +321,28 @@ static void imx_avic_reset(DeviceState *dev) memset(s->prio, 0, sizeof s->prio); } -static void imx_avic_init(Object *obj) +static int imx_avic_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - IMXAVICState *s = IMX_AVIC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IMXAVICState *s = IMX_AVIC(dev); - memory_region_init_io(&s->iomem, obj, &imx_avic_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &imx_avic_ops, s, TYPE_IMX_AVIC, 0x1000); sysbus_init_mmio(sbd, &s->iomem); qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS); sysbus_init_irq(sbd, &s->irq); sysbus_init_irq(sbd, &s->fiq); + + return 0; } static void imx_avic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = imx_avic_init; dc->vmsd = &vmstate_imx_avic; dc->reset = imx_avic_reset; dc->desc = "i.MX Advanced Vector Interrupt Controller"; @@ -351,7 +352,6 @@ static const TypeInfo imx_avic_info = { .name = TYPE_IMX_AVIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IMXAVICState), - .instance_init = imx_avic_init, .class_init = imx_avic_class_init, }; diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 31791b098..378e663f6 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -21,18 +21,13 @@ */ #include "qemu/osdep.h" -#include "qemu/error-report.h" #include "monitor/monitor.h" #include "hw/hw.h" #include "hw/i386/pc.h" -#include "hw/i386/apic.h" #include "hw/i386/ioapic.h" #include "hw/i386/ioapic_internal.h" #include "include/hw/pci/msi.h" #include "sysemu/kvm.h" -#include "target-i386/cpu.h" -#include "hw/i386/apic-msidef.h" -#include "hw/i386/x86-iommu.h" //#define DEBUG_IOAPIC @@ -52,56 +47,16 @@ static IOAPICCommonState *ioapics[MAX_IOAPICS]; /* global variable from ioapic_common.c */ extern int ioapic_no; -struct ioapic_entry_info { - /* fields parsed from IOAPIC entries */ - uint8_t masked; - uint8_t trig_mode; - uint16_t dest_idx; - uint8_t dest_mode; - uint8_t delivery_mode; - uint8_t vector; - - /* MSI message generated from above parsed fields */ - uint32_t addr; - uint32_t data; -}; - -static void ioapic_entry_parse(uint64_t entry, struct ioapic_entry_info *info) -{ - memset(info, 0, sizeof(*info)); - info->masked = (entry >> IOAPIC_LVT_MASKED_SHIFT) & 1; - info->trig_mode = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1; - /* - * By default, this would be dest_id[8] + reserved[8]. When IR - * is enabled, this would be interrupt_index[15] + - * interrupt_format[1]. This field never means anything, but - * only used to generate corresponding MSI. - */ - info->dest_idx = (entry >> IOAPIC_LVT_DEST_IDX_SHIFT) & 0xffff; - info->dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; - info->delivery_mode = (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) \ - & IOAPIC_DM_MASK; - if (info->delivery_mode == IOAPIC_DM_EXTINT) { - info->vector = pic_read_irq(isa_pic); - } else { - info->vector = entry & IOAPIC_VECTOR_MASK; - } - - info->addr = APIC_DEFAULT_ADDRESS | \ - (info->dest_idx << MSI_ADDR_DEST_IDX_SHIFT) | \ - (info->dest_mode << MSI_ADDR_DEST_MODE_SHIFT); - info->data = (info->vector << MSI_DATA_VECTOR_SHIFT) | \ - (info->trig_mode << MSI_DATA_TRIGGER_SHIFT) | \ - (info->delivery_mode << MSI_DATA_DELIVERY_MODE_SHIFT); -} - static void ioapic_service(IOAPICCommonState *s) { - AddressSpace *ioapic_as = PC_MACHINE(qdev_get_machine())->ioapic_as; - struct ioapic_entry_info info; uint8_t i; + uint8_t trig_mode; + uint8_t vector; + uint8_t delivery_mode; uint32_t mask; uint64_t entry; + uint8_t dest; + uint8_t dest_mode; for (i = 0; i < IOAPIC_NUM_PINS; i++) { mask = 1 << i; @@ -109,39 +64,40 @@ static void ioapic_service(IOAPICCommonState *s) int coalesce = 0; entry = s->ioredtbl[i]; - ioapic_entry_parse(entry, &info); - if (!info.masked) { - if (info.trig_mode == IOAPIC_TRIGGER_EDGE) { + if (!(entry & IOAPIC_LVT_MASKED)) { + trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); + dest = entry >> IOAPIC_LVT_DEST_SHIFT; + dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; + delivery_mode = + (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; + if (trig_mode == IOAPIC_TRIGGER_EDGE) { s->irr &= ~mask; } else { coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR; s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR; } - - if (coalesce) { - /* We are level triggered interrupts, and the - * guest should be still working on previous one, - * so skip it. */ - continue; + if (delivery_mode == IOAPIC_DM_EXTINT) { + vector = pic_read_irq(isa_pic); + } else { + vector = entry & IOAPIC_VECTOR_MASK; } - #ifdef CONFIG_KVM if (kvm_irqchip_is_split()) { - if (info.trig_mode == IOAPIC_TRIGGER_EDGE) { + if (trig_mode == IOAPIC_TRIGGER_EDGE) { kvm_set_irq(kvm_state, i, 1); kvm_set_irq(kvm_state, i, 0); } else { - kvm_set_irq(kvm_state, i, 1); + if (!coalesce) { + kvm_set_irq(kvm_state, i, 1); + } } continue; } +#else + (void)coalesce; #endif - - /* No matter whether IR is enabled, we translate - * the IOAPIC message into a MSI one, and its - * address space will decide whether we need a - * translation. */ - stl_le_phys(ioapic_as, info.addr, info.data); + apic_deliver_irq(dest, dest_mode, delivery_mode, vector, + trig_mode); } } } @@ -192,11 +148,30 @@ static void ioapic_update_kvm_routes(IOAPICCommonState *s) if (kvm_irqchip_is_split()) { for (i = 0; i < IOAPIC_NUM_PINS; i++) { + uint64_t entry = s->ioredtbl[i]; + uint8_t trig_mode; + uint8_t delivery_mode; + uint8_t dest; + uint8_t dest_mode; + uint64_t pin_polarity; MSIMessage msg; - struct ioapic_entry_info info; - ioapic_entry_parse(s->ioredtbl[i], &info); - msg.address = info.addr; - msg.data = info.data; + + trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); + dest = entry >> IOAPIC_LVT_DEST_SHIFT; + dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; + pin_polarity = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1; + delivery_mode = + (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; + + msg.address = APIC_DEFAULT_ADDRESS; + msg.address |= dest_mode << 2; + msg.address |= dest << 12; + + msg.data = entry & IOAPIC_VECTOR_MASK; + msg.data |= delivery_mode << APIC_DELIVERY_MODE_SHIFT; + msg.data |= pin_polarity << APIC_POLARITY_SHIFT; + msg.data |= trig_mode << APIC_TRIG_MODE_SHIFT; + kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL); } kvm_irqchip_commit_routes(kvm_state); @@ -204,16 +179,6 @@ static void ioapic_update_kvm_routes(IOAPICCommonState *s) #endif } -#ifdef CONFIG_KVM -static void ioapic_iec_notifier(void *private, bool global, - uint32_t index, uint32_t mask) -{ - IOAPICCommonState *s = (IOAPICCommonState *)private; - /* For simplicity, we just update all the routes */ - ioapic_update_kvm_routes(s); -} -#endif - void ioapic_eoi_broadcast(int vector) { IOAPICCommonState *s; @@ -270,7 +235,7 @@ ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size) val = s->id << IOAPIC_ID_SHIFT; break; case IOAPIC_REG_VER: - val = s->version | + val = IOAPIC_VERSION | ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT); break; default: @@ -289,34 +254,6 @@ ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size) return val; } -/* - * This is to satisfy the hack in Linux kernel. One hack of it is to - * simulate clearing the Remote IRR bit of IOAPIC entry using the - * following: - * - * "For IO-APIC's with EOI register, we use that to do an explicit EOI. - * Otherwise, we simulate the EOI message manually by changing the trigger - * mode to edge and then back to level, with RTE being masked during - * this." - * - * (See linux kernel __eoi_ioapic_pin() comment in commit c0205701) - * - * This is based on the assumption that, Remote IRR bit will be - * cleared by IOAPIC hardware when configured as edge-triggered - * interrupts. - * - * Without this, level-triggered interrupts in IR mode might fail to - * work correctly. - */ -static inline void -ioapic_fix_edge_remote_irr(uint64_t *entry) -{ - if (!(*entry & IOAPIC_LVT_TRIGGER_MODE)) { - /* Edge-triggered interrupts, make sure remote IRR is zero */ - *entry &= ~((uint64_t)IOAPIC_LVT_REMOTE_IRR); - } -} - static void ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) @@ -343,7 +280,6 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, default: index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; if (index >= 0 && index < IOAPIC_NUM_PINS) { - uint64_t ro_bits = s->ioredtbl[index] & IOAPIC_RO_BITS; if (s->ioregsel & 1) { s->ioredtbl[index] &= 0xffffffff; s->ioredtbl[index] |= (uint64_t)val << 32; @@ -351,21 +287,10 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, s->ioredtbl[index] &= ~0xffffffffULL; s->ioredtbl[index] |= val; } - /* restore RO bits */ - s->ioredtbl[index] &= IOAPIC_RW_BITS; - s->ioredtbl[index] |= ro_bits; - ioapic_fix_edge_remote_irr(&s->ioredtbl[index]); ioapic_service(s); } } break; - case IOAPIC_EOI: - /* Explicit EOI is only supported for IOAPIC version 0x20 */ - if (size != 4 || s->version != 0x20) { - break; - } - ioapic_eoi_broadcast(val); - break; } ioapic_update_kvm_routes(s); @@ -377,49 +302,18 @@ static const MemoryRegionOps ioapic_io_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void ioapic_machine_done_notify(Notifier *notifier, void *data) -{ -#ifdef CONFIG_KVM - IOAPICCommonState *s = container_of(notifier, IOAPICCommonState, - machine_done); - - if (kvm_irqchip_is_split()) { - X86IOMMUState *iommu = x86_iommu_get_default(); - if (iommu) { - /* Register this IOAPIC with IOMMU IEC notifier, so that - * when there are IR invalidates, we can be notified to - * update kernel IR cache. */ - x86_iommu_iec_register_notifier(iommu, ioapic_iec_notifier, s); - } - } -#endif -} - static void ioapic_realize(DeviceState *dev, Error **errp) { IOAPICCommonState *s = IOAPIC_COMMON(dev); - if (s->version != 0x11 && s->version != 0x20) { - error_report("IOAPIC only supports version 0x11 or 0x20 " - "(default: 0x11)."); - exit(1); - } - memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s, "ioapic", 0x1000); qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS); ioapics[ioapic_no] = s; - s->machine_done.notify = ioapic_machine_done_notify; - qemu_add_machine_init_done_notifier(&s->machine_done); } -static Property ioapic_properties[] = { - DEFINE_PROP_UINT8("version", IOAPICCommonState, version, 0x11), - DEFINE_PROP_END_OF_LIST(), -}; - static void ioapic_class_init(ObjectClass *klass, void *data) { IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); @@ -427,7 +321,6 @@ static void ioapic_class_init(ObjectClass *klass, void *data) k->realize = ioapic_realize; dc->reset = ioapic_reset_common; - dc->props = ioapic_properties; } static const TypeInfo ioapic_info = { diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c index 3dad01c5b..edc08f184 100644 --- a/hw/intc/lm32_pic.c +++ b/hw/intc/lm32_pic.c @@ -152,16 +152,17 @@ static void pic_reset(DeviceState *d) } } -static void lm32_pic_init(Object *obj) +static int lm32_pic_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - LM32PicState *s = LM32_PIC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + LM32PicState *s = LM32_PIC(dev); qdev_init_gpio_in(dev, irq_handler, 32); sysbus_init_irq(sbd, &s->parent_irq); pic = s; + + return 0; } static const VMStateDescription vmstate_lm32_pic = { @@ -180,7 +181,9 @@ static const VMStateDescription vmstate_lm32_pic = { static void lm32_pic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = lm32_pic_init; dc->reset = pic_reset; dc->vmsd = &vmstate_lm32_pic; } @@ -189,7 +192,6 @@ static const TypeInfo lm32_pic_info = { .name = TYPE_LM32_PIC, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32PicState), - .instance_init = lm32_pic_init, .class_init = lm32_pic_class_init, }; diff --git a/hw/intc/mips_gic.c b/hw/intc/mips_gic.c deleted file mode 100644 index 6e257730f..000000000 --- a/hw/intc/mips_gic.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. - * Authors: Sanjay Lal <sanjayl@kymasys.com> - * - * Copyright (C) 2016 Imagination Technologies - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "exec/memory.h" -#include "sysemu/sysemu.h" -#include "sysemu/kvm.h" -#include "kvm_mips.h" -#include "hw/intc/mips_gic.h" - -static void mips_gic_set_vp_irq(MIPSGICState *gic, int vp, int pin, int level) -{ - int ored_level = level; - int i; - - /* ORing pending registers sharing same pin */ - if (!ored_level) { - for (i = 0; i < gic->num_irq; i++) { - if ((gic->irq_state[i].map_pin & GIC_MAP_MSK) == pin && - gic->irq_state[i].map_vp == vp && - gic->irq_state[i].enabled) { - ored_level |= gic->irq_state[i].pending; - } - if (ored_level) { - /* no need to iterate all interrupts */ - break; - } - } - if (((gic->vps[vp].compare_map & GIC_MAP_MSK) == pin) && - (gic->vps[vp].mask & GIC_VP_MASK_CMP_MSK)) { - /* ORing with local pending register (count/compare) */ - ored_level |= (gic->vps[vp].pend & GIC_VP_MASK_CMP_MSK) >> - GIC_VP_MASK_CMP_SHF; - } - } - if (kvm_enabled()) { - kvm_mips_set_ipi_interrupt(mips_env_get_cpu(gic->vps[vp].env), - pin + GIC_CPU_PIN_OFFSET, - ored_level); - } else { - qemu_set_irq(gic->vps[vp].env->irq[pin + GIC_CPU_PIN_OFFSET], - ored_level); - } -} - -static void gic_set_irq(void *opaque, int n_IRQ, int level) -{ - MIPSGICState *gic = (MIPSGICState *) opaque; - int vp = gic->irq_state[n_IRQ].map_vp; - int pin = gic->irq_state[n_IRQ].map_pin & GIC_MAP_MSK; - - gic->irq_state[n_IRQ].pending = (uint8_t) level; - if (!gic->irq_state[n_IRQ].enabled) { - /* GIC interrupt source disabled */ - return; - } - if (vp < 0 || vp >= gic->num_vps) { - return; - } - mips_gic_set_vp_irq(gic, vp, pin, level); -} - -#define OFFSET_CHECK(c) \ - do { \ - if (!(c)) { \ - goto bad_offset; \ - } \ - } while (0) - -/* GIC Read VP Local/Other Registers */ -static uint64_t gic_read_vp(MIPSGICState *gic, uint32_t vp_index, hwaddr addr, - unsigned size) -{ - switch (addr) { - case GIC_VP_CTL_OFS: - return gic->vps[vp_index].ctl; - case GIC_VP_PEND_OFS: - mips_gictimer_get_sh_count(gic->gic_timer); - return gic->vps[vp_index].pend; - case GIC_VP_MASK_OFS: - return gic->vps[vp_index].mask; - case GIC_VP_COMPARE_MAP_OFS: - return gic->vps[vp_index].compare_map; - case GIC_VP_OTHER_ADDR_OFS: - return gic->vps[vp_index].other_addr; - case GIC_VP_IDENT_OFS: - return vp_index; - case GIC_VP_COMPARE_LO_OFS: - return mips_gictimer_get_vp_compare(gic->gic_timer, vp_index); - case GIC_VP_COMPARE_HI_OFS: - return 0; - default: - qemu_log_mask(LOG_UNIMP, "Read %d bytes at GIC offset LOCAL/OTHER 0x%" - PRIx64 "\n", size, addr); - break; - } - return 0; -} - -static uint64_t gic_read(void *opaque, hwaddr addr, unsigned size) -{ - MIPSGICState *gic = (MIPSGICState *) opaque; - uint32_t vp_index = current_cpu->cpu_index; - uint64_t ret = 0; - int i, base, irq_src; - uint32_t other_index; - - switch (addr) { - case GIC_SH_CONFIG_OFS: - ret = gic->sh_config | (mips_gictimer_get_countstop(gic->gic_timer) << - GIC_SH_CONFIG_COUNTSTOP_SHF); - break; - case GIC_SH_COUNTERLO_OFS: - ret = mips_gictimer_get_sh_count(gic->gic_timer); - break; - case GIC_SH_COUNTERHI_OFS: - ret = 0; - break; - case GIC_SH_PEND_OFS ... GIC_SH_PEND_LAST_OFS: - /* each bit represents pending status for an interrupt pin */ - base = (addr - GIC_SH_PEND_OFS) * 8; - OFFSET_CHECK((base + size * 8) <= gic->num_irq); - for (i = 0; i < size * 8; i++) { - ret |= (uint64_t) (gic->irq_state[base + i].pending) << i; - } - break; - case GIC_SH_MASK_OFS ... GIC_SH_MASK_LAST_OFS: - /* each bit represents status for an interrupt pin */ - base = (addr - GIC_SH_MASK_OFS) * 8; - OFFSET_CHECK((base + size * 8) <= gic->num_irq); - for (i = 0; i < size * 8; i++) { - ret |= (uint64_t) (gic->irq_state[base + i].enabled) << i; - } - break; - case GIC_SH_MAP0_PIN_OFS ... GIC_SH_MAP255_PIN_OFS: - /* 32 bits per a pin */ - irq_src = (addr - GIC_SH_MAP0_PIN_OFS) / 4; - OFFSET_CHECK(irq_src < gic->num_irq); - ret = gic->irq_state[irq_src].map_pin; - break; - case GIC_SH_MAP0_VP_OFS ... GIC_SH_MAP255_VP_LAST_OFS: - /* up to 32 bytes per a pin */ - irq_src = (addr - GIC_SH_MAP0_VP_OFS) / 32; - OFFSET_CHECK(irq_src < gic->num_irq); - if ((gic->irq_state[irq_src].map_vp) >= 0) { - ret = (uint64_t) 1 << (gic->irq_state[irq_src].map_vp); - } else { - ret = 0; - } - break; - /* VP-Local Register */ - case VP_LOCAL_SECTION_OFS ... (VP_LOCAL_SECTION_OFS + GIC_VL_BRK_GROUP): - ret = gic_read_vp(gic, vp_index, addr - VP_LOCAL_SECTION_OFS, size); - break; - /* VP-Other Register */ - case VP_OTHER_SECTION_OFS ... (VP_OTHER_SECTION_OFS + GIC_VL_BRK_GROUP): - other_index = gic->vps[vp_index].other_addr; - ret = gic_read_vp(gic, other_index, addr - VP_OTHER_SECTION_OFS, size); - break; - /* User-Mode Visible section */ - case USM_VISIBLE_SECTION_OFS + GIC_USER_MODE_COUNTERLO: - ret = mips_gictimer_get_sh_count(gic->gic_timer); - break; - case USM_VISIBLE_SECTION_OFS + GIC_USER_MODE_COUNTERHI: - ret = 0; - break; - default: - qemu_log_mask(LOG_UNIMP, "Read %d bytes at GIC offset 0x%" PRIx64 "\n", - size, addr); - break; - } - return ret; -bad_offset: - qemu_log_mask(LOG_GUEST_ERROR, "Wrong GIC offset at 0x%" PRIx64 "\n", addr); - return 0; -} - -static void gic_timer_expire_cb(void *opaque, uint32_t vp_index) -{ - MIPSGICState *gic = opaque; - - gic->vps[vp_index].pend |= (1 << GIC_LOCAL_INT_COMPARE); - if (gic->vps[vp_index].pend & - (gic->vps[vp_index].mask & GIC_VP_MASK_CMP_MSK)) { - if (gic->vps[vp_index].compare_map & GIC_MAP_TO_PIN_MSK) { - /* it is safe to set the irq high regardless of other GIC IRQs */ - uint32_t pin = (gic->vps[vp_index].compare_map & GIC_MAP_MSK); - qemu_irq_raise(gic->vps[vp_index].env->irq - [pin + GIC_CPU_PIN_OFFSET]); - } - } -} - -static void gic_timer_store_vp_compare(MIPSGICState *gic, uint32_t vp_index, - uint64_t compare) -{ - gic->vps[vp_index].pend &= ~(1 << GIC_LOCAL_INT_COMPARE); - if (gic->vps[vp_index].compare_map & GIC_MAP_TO_PIN_MSK) { - uint32_t pin = (gic->vps[vp_index].compare_map & GIC_MAP_MSK); - mips_gic_set_vp_irq(gic, vp_index, pin, 0); - } - mips_gictimer_store_vp_compare(gic->gic_timer, vp_index, compare); -} - -/* GIC Write VP Local/Other Registers */ -static void gic_write_vp(MIPSGICState *gic, uint32_t vp_index, hwaddr addr, - uint64_t data, unsigned size) -{ - switch (addr) { - case GIC_VP_CTL_OFS: - /* EIC isn't supported */ - break; - case GIC_VP_RMASK_OFS: - gic->vps[vp_index].mask &= ~(data & GIC_VP_SET_RESET_MSK) & - GIC_VP_SET_RESET_MSK; - break; - case GIC_VP_SMASK_OFS: - gic->vps[vp_index].mask |= data & GIC_VP_SET_RESET_MSK; - break; - case GIC_VP_COMPARE_MAP_OFS: - /* EIC isn't supported */ - OFFSET_CHECK((data & GIC_MAP_MSK) <= GIC_CPU_INT_MAX); - gic->vps[vp_index].compare_map = data & GIC_MAP_TO_PIN_REG_MSK; - break; - case GIC_VP_OTHER_ADDR_OFS: - OFFSET_CHECK(data < gic->num_vps); - gic->vps[vp_index].other_addr = data; - break; - case GIC_VP_COMPARE_LO_OFS: - gic_timer_store_vp_compare(gic, vp_index, data); - break; - default: - qemu_log_mask(LOG_UNIMP, "Write %d bytes at GIC offset LOCAL/OTHER " - "0x%" PRIx64" 0x%08" PRIx64 "\n", size, addr, data); - break; - } - return; -bad_offset: - qemu_log_mask(LOG_GUEST_ERROR, "Wrong GIC offset at 0x%" PRIx64 "\n", addr); - return; -} - -static void gic_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) -{ - int intr; - MIPSGICState *gic = (MIPSGICState *) opaque; - uint32_t vp_index = current_cpu->cpu_index; - int i, base, irq_src; - uint32_t other_index; - - switch (addr) { - case GIC_SH_CONFIG_OFS: - { - uint32_t pre_cntstop = mips_gictimer_get_countstop(gic->gic_timer); - uint32_t new_cntstop = (data & GIC_SH_CONFIG_COUNTSTOP_MSK) >> - GIC_SH_CONFIG_COUNTSTOP_SHF; - if (pre_cntstop != new_cntstop) { - if (new_cntstop == 1) { - mips_gictimer_stop_count(gic->gic_timer); - } else { - mips_gictimer_start_count(gic->gic_timer); - } - } - } - break; - case GIC_SH_COUNTERLO_OFS: - if (mips_gictimer_get_countstop(gic->gic_timer)) { - mips_gictimer_store_sh_count(gic->gic_timer, data); - } - break; - case GIC_SH_RMASK_OFS ... GIC_SH_RMASK_LAST_OFS: - /* up to 64 bits per a pin */ - base = (addr - GIC_SH_RMASK_OFS) * 8; - OFFSET_CHECK((base + size * 8) <= gic->num_irq); - for (i = 0; i < size * 8; i++) { - gic->irq_state[base + i].enabled &= !((data >> i) & 1); - } - break; - case GIC_SH_WEDGE_OFS: - /* Figure out which VP/HW Interrupt this maps to */ - intr = data & ~GIC_SH_WEDGE_RW_MSK; - /* Mask/Enabled Checks */ - OFFSET_CHECK(intr < gic->num_irq); - if (data & GIC_SH_WEDGE_RW_MSK) { - gic_set_irq(gic, intr, 1); - } else { - gic_set_irq(gic, intr, 0); - } - break; - case GIC_SH_SMASK_OFS ... GIC_SH_SMASK_LAST_OFS: - /* up to 64 bits per a pin */ - base = (addr - GIC_SH_SMASK_OFS) * 8; - OFFSET_CHECK((base + size * 8) <= gic->num_irq); - for (i = 0; i < size * 8; i++) { - gic->irq_state[base + i].enabled |= (data >> i) & 1; - } - break; - case GIC_SH_MAP0_PIN_OFS ... GIC_SH_MAP255_PIN_OFS: - /* 32 bits per a pin */ - irq_src = (addr - GIC_SH_MAP0_PIN_OFS) / 4; - OFFSET_CHECK(irq_src < gic->num_irq); - /* EIC isn't supported */ - OFFSET_CHECK((data & GIC_MAP_MSK) <= GIC_CPU_INT_MAX); - gic->irq_state[irq_src].map_pin = data & GIC_MAP_TO_PIN_REG_MSK; - break; - case GIC_SH_MAP0_VP_OFS ... GIC_SH_MAP255_VP_LAST_OFS: - /* up to 32 bytes per a pin */ - irq_src = (addr - GIC_SH_MAP0_VP_OFS) / 32; - OFFSET_CHECK(irq_src < gic->num_irq); - data = data ? ctz64(data) : -1; - OFFSET_CHECK(data < gic->num_vps); - gic->irq_state[irq_src].map_vp = data; - break; - case VP_LOCAL_SECTION_OFS ... (VP_LOCAL_SECTION_OFS + GIC_VL_BRK_GROUP): - gic_write_vp(gic, vp_index, addr - VP_LOCAL_SECTION_OFS, data, size); - break; - case VP_OTHER_SECTION_OFS ... (VP_OTHER_SECTION_OFS + GIC_VL_BRK_GROUP): - other_index = gic->vps[vp_index].other_addr; - gic_write_vp(gic, other_index, addr - VP_OTHER_SECTION_OFS, data, size); - break; - case USM_VISIBLE_SECTION_OFS + GIC_USER_MODE_COUNTERLO: - case USM_VISIBLE_SECTION_OFS + GIC_USER_MODE_COUNTERHI: - /* do nothing. Read-only section */ - break; - default: - qemu_log_mask(LOG_UNIMP, "Write %d bytes at GIC offset 0x%" PRIx64 - " 0x%08" PRIx64 "\n", size, addr, data); - break; - } - return; -bad_offset: - qemu_log_mask(LOG_GUEST_ERROR, "Wrong GIC offset at 0x%" PRIx64 "\n", addr); -} - -static void gic_reset(void *opaque) -{ - int i; - MIPSGICState *gic = (MIPSGICState *) opaque; - int numintrs = (gic->num_irq / 8) - 1; - - gic->sh_config = /* COUNTSTOP = 0 it is accessible via MIPSGICTimer*/ - /* CounterHi not implemented */ - (0 << GIC_SH_CONFIG_COUNTBITS_SHF) | - (numintrs << GIC_SH_CONFIG_NUMINTRS_SHF) | - (gic->num_vps << GIC_SH_CONFIG_PVPS_SHF); - for (i = 0; i < gic->num_vps; i++) { - gic->vps[i].ctl = 0x0; - gic->vps[i].pend = 0x0; - /* PERFCNT, TIMER and WD not implemented */ - gic->vps[i].mask = 0x32; - gic->vps[i].compare_map = GIC_MAP_TO_PIN_MSK; - mips_gictimer_store_vp_compare(gic->gic_timer, i, 0xffffffff); - gic->vps[i].other_addr = 0x0; - } - for (i = 0; i < gic->num_irq; i++) { - gic->irq_state[i].enabled = 0; - gic->irq_state[i].pending = 0; - gic->irq_state[i].map_pin = GIC_MAP_TO_PIN_MSK; - gic->irq_state[i].map_vp = -1; - } - mips_gictimer_store_sh_count(gic->gic_timer, 0); - /* COUNTSTOP = 0 */ - mips_gictimer_start_count(gic->gic_timer); -} - -static const MemoryRegionOps gic_ops = { - .read = gic_read, - .write = gic_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .impl = { - .max_access_size = 8, - }, -}; - -static void mips_gic_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - MIPSGICState *s = MIPS_GIC(obj); - - memory_region_init_io(&s->mr, OBJECT(s), &gic_ops, s, - "mips-gic", GIC_ADDRSPACE_SZ); - sysbus_init_mmio(sbd, &s->mr); - qemu_register_reset(gic_reset, s); -} - -static void mips_gic_realize(DeviceState *dev, Error **errp) -{ - MIPSGICState *s = MIPS_GIC(dev); - CPUState *cs = first_cpu; - int i; - - if (s->num_vps > GIC_MAX_VPS) { - error_setg(errp, "Exceeded maximum CPUs %d", s->num_vps); - return; - } - if ((s->num_irq > GIC_MAX_INTRS) || (s->num_irq % 8) || (s->num_irq <= 0)) { - error_setg(errp, "GIC supports up to %d external interrupts in " - "multiples of 8 : %d", GIC_MAX_INTRS, s->num_irq); - return; - } - s->vps = g_new(MIPSGICVPState, s->num_vps); - s->irq_state = g_new(MIPSGICIRQState, s->num_irq); - /* Register the env for all VPs with the GIC */ - for (i = 0; i < s->num_vps; i++) { - if (cs != NULL) { - s->vps[i].env = cs->env_ptr; - cs = CPU_NEXT(cs); - } else { - error_setg(errp, - "Unable to initialize GIC, CPUState for CPU#%d not valid.", i); - return; - } - } - s->gic_timer = mips_gictimer_init(s, s->num_vps, gic_timer_expire_cb); - qdev_init_gpio_in(dev, gic_set_irq, s->num_irq); - for (i = 0; i < s->num_irq; i++) { - s->irq_state[i].irq = qdev_get_gpio_in(dev, i); - } -} - -static Property mips_gic_properties[] = { - DEFINE_PROP_INT32("num-vp", MIPSGICState, num_vps, 1), - DEFINE_PROP_INT32("num-irq", MIPSGICState, num_irq, 256), - DEFINE_PROP_END_OF_LIST(), -}; - -static void mips_gic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->props = mips_gic_properties; - dc->realize = mips_gic_realize; -} - -static const TypeInfo mips_gic_info = { - .name = TYPE_MIPS_GIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MIPSGICState), - .instance_init = mips_gic_init, - .class_init = mips_gic_class_init, -}; - -static void mips_gic_register_types(void) -{ - type_register_static(&mips_gic_info); -} - -type_init(mips_gic_register_types) diff --git a/hw/intc/omap_intc.c b/hw/intc/omap_intc.c index 877be6797..336882510 100644 --- a/hw/intc/omap_intc.c +++ b/hw/intc/omap_intc.c @@ -22,7 +22,6 @@ #include "hw/arm/omap.h" #include "hw/sysbus.h" #include "qemu/error-report.h" -#include "qapi/error.h" /* Interrupt Handlers */ struct omap_intr_handler_bank_s { @@ -364,28 +363,23 @@ static void omap_inth_reset(DeviceState *dev) qemu_set_irq(s->parent_intr[1], 0); } -static void omap_intc_init(Object *obj) +static int omap_intc_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - struct omap_intr_handler_s *s = OMAP_INTC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + struct omap_intr_handler_s *s = OMAP_INTC(dev); + if (!s->iclk) { + error_report("omap-intc: clk not connected"); + return -1; + } s->nbanks = 1; sysbus_init_irq(sbd, &s->parent_intr[0]); sysbus_init_irq(sbd, &s->parent_intr[1]); qdev_init_gpio_in(dev, omap_set_intr, s->nbanks * 32); - memory_region_init_io(&s->mmio, obj, &omap_inth_mem_ops, s, + memory_region_init_io(&s->mmio, OBJECT(s), &omap_inth_mem_ops, s, "omap-intc", s->size); sysbus_init_mmio(sbd, &s->mmio); -} - -static void omap_intc_realize(DeviceState *dev, Error **errp) -{ - struct omap_intr_handler_s *s = OMAP_INTC(dev); - - if (!s->iclk) { - error_setg(errp, "omap-intc: clk not connected"); - } + return 0; } static Property omap_intc_properties[] = { @@ -397,18 +391,18 @@ static Property omap_intc_properties[] = { static void omap_intc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = omap_intc_init; dc->reset = omap_inth_reset; dc->props = omap_intc_properties; /* Reason: pointer property "clk" */ dc->cannot_instantiate_with_device_add_yet = true; - dc->realize = omap_intc_realize; } static const TypeInfo omap_intc_info = { .name = "omap-intc", .parent = TYPE_OMAP_INTC, - .instance_init = omap_intc_init, .class_init = omap_intc_class_init, }; @@ -611,34 +605,28 @@ static const MemoryRegionOps omap2_inth_mem_ops = { }, }; -static void omap2_intc_init(Object *obj) +static int omap2_intc_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - struct omap_intr_handler_s *s = OMAP_INTC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + struct omap_intr_handler_s *s = OMAP_INTC(dev); + if (!s->iclk) { + error_report("omap2-intc: iclk not connected"); + return -1; + } + if (!s->fclk) { + error_report("omap2-intc: fclk not connected"); + return -1; + } s->level_only = 1; s->nbanks = 3; sysbus_init_irq(sbd, &s->parent_intr[0]); sysbus_init_irq(sbd, &s->parent_intr[1]); qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32); - memory_region_init_io(&s->mmio, obj, &omap2_inth_mem_ops, s, + memory_region_init_io(&s->mmio, OBJECT(s), &omap2_inth_mem_ops, s, "omap2-intc", 0x1000); sysbus_init_mmio(sbd, &s->mmio); -} - -static void omap2_intc_realize(DeviceState *dev, Error **errp) -{ - struct omap_intr_handler_s *s = OMAP_INTC(dev); - - if (!s->iclk) { - error_setg(errp, "omap2-intc: iclk not connected"); - return; - } - if (!s->fclk) { - error_setg(errp, "omap2-intc: fclk not connected"); - return; - } + return 0; } static Property omap2_intc_properties[] = { @@ -652,18 +640,18 @@ static Property omap2_intc_properties[] = { static void omap2_intc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = omap2_intc_init; dc->reset = omap_inth_reset; dc->props = omap2_intc_properties; /* Reason: pointer property "iclk", "fclk" */ dc->cannot_instantiate_with_device_add_yet = true; - dc->realize = omap2_intc_realize; } static const TypeInfo omap2_intc_info = { .name = "omap2-intc", .parent = TYPE_OMAP_INTC, - .instance_init = omap2_intc_init, .class_init = omap2_intc_class_init, }; diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index 4349e45e0..2d3769310 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -44,7 +44,6 @@ #include "qapi/error.h" #include "qemu/bitops.h" #include "qapi/qmp/qerror.h" -#include "qemu/log.h" //#define DEBUG_OPENPIC diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c index 0518e017c..e47e94f2c 100644 --- a/hw/intc/openpic_kvm.c +++ b/hw/intc/openpic_kvm.c @@ -24,8 +24,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" -#include "cpu.h" #include <sys/ioctl.h> #include "exec/address-spaces.h" #include "hw/hw.h" diff --git a/hw/intc/pl190.c b/hw/intc/pl190.c index 55ea15de7..5ecbc4a48 100644 --- a/hw/intc/pl190.c +++ b/hw/intc/pl190.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" -#include "qemu/log.h" /* The number of virtual priority levels. 16 user vectors plus the unvectored IRQ. Chained interrupts would require an additional level @@ -237,17 +236,17 @@ static void pl190_reset(DeviceState *d) pl190_update_vectors(s); } -static void pl190_init(Object *obj) +static int pl190_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - PL190State *s = PL190(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + PL190State *s = PL190(dev); - memory_region_init_io(&s->iomem, obj, &pl190_ops, s, "pl190", 0x1000); + memory_region_init_io(&s->iomem, OBJECT(s), &pl190_ops, s, "pl190", 0x1000); sysbus_init_mmio(sbd, &s->iomem); qdev_init_gpio_in(dev, pl190_set_irq, 32); sysbus_init_irq(sbd, &s->irq); sysbus_init_irq(sbd, &s->fiq); + return 0; } static const VMStateDescription vmstate_pl190 = { @@ -272,7 +271,9 @@ static const VMStateDescription vmstate_pl190 = { static void pl190_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = pl190_init; dc->reset = pl190_reset; dc->vmsd = &vmstate_pl190; } @@ -281,7 +282,6 @@ static const TypeInfo pl190_info = { .name = TYPE_PL190, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PL190State), - .instance_init = pl190_init, .class_init = pl190_class_init, }; diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index 6ab29efc6..bc75fa7d9 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -67,13 +67,6 @@ static void qemu_s390_release_adapter_routes(S390FLICState *fs, { } -static int qemu_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id, - uint16_t subchannel_nr) -{ - /* Fixme TCG */ - return -ENOSYS; -} - static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) { S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc); @@ -82,7 +75,6 @@ static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) fsc->io_adapter_map = qemu_s390_io_adapter_map; fsc->add_adapter_routes = qemu_s390_add_adapter_routes; fsc->release_adapter_routes = qemu_s390_release_adapter_routes; - fsc->clear_io_irq = qemu_s390_clear_io_flic; } static const TypeInfo qemu_s390_flic_info = { diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index fef808011..02449b390 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -11,8 +11,6 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" -#include "cpu.h" #include <sys/ioctl.h> #include "qemu/error-report.h" #include "hw/sysbus.h" @@ -30,7 +28,6 @@ typedef struct KVMS390FLICState { S390FLICState parent_obj; uint32_t fd; - bool clear_io_supported; } KVMS390FLICState; DeviceState *s390_flic_kvm_create(void) @@ -131,24 +128,6 @@ int kvm_s390_inject_flic(struct kvm_s390_irq *irq) return flic_enqueue_irqs(irq, sizeof(*irq), flic); } -static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id, - uint16_t subchannel_nr) -{ - KVMS390FLICState *flic = KVM_S390_FLIC(fs); - int rc; - uint32_t sid = subchannel_id << 16 | subchannel_nr; - struct kvm_device_attr attr = { - .group = KVM_DEV_FLIC_CLEAR_IO_IRQ, - .addr = (uint64_t) &sid, - .attr = sizeof(sid), - }; - if (unlikely(!flic->clear_io_supported)) { - return -ENOSYS; - } - rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); - return rc ? -errno : 0; -} - /** * __get_all_irqs - store all pending irqs in buffer * @flic: pointer to flic device state @@ -195,7 +174,7 @@ static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id, .swap = swap, }; KVMS390FLICState *flic = KVM_S390_FLIC(fs); - int r; + int r, ret; struct kvm_device_attr attr = { .group = KVM_DEV_FLIC_ADAPTER_REGISTER, .addr = (uint64_t)&adapter, @@ -208,7 +187,8 @@ static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id, r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); - return r ? -errno : 0; + ret = r ? -errno : 0; + return ret; } static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id, @@ -376,7 +356,6 @@ static void kvm_s390_flic_realize(DeviceState *dev, Error **errp) { KVMS390FLICState *flic_state = KVM_S390_FLIC(dev); struct kvm_create_device cd = {0}; - struct kvm_device_attr test_attr = {0}; int ret; flic_state->fd = -1; @@ -393,11 +372,6 @@ static void kvm_s390_flic_realize(DeviceState *dev, Error **errp) } flic_state->fd = cd.fd; - /* Check clear_io_irq support */ - test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ; - flic_state->clear_io_supported = !ioctl(flic_state->fd, - KVM_HAS_DEVICE_ATTR, test_attr); - /* Register savevm handler for floating interrupts */ register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save, kvm_flic_load, (void *) flic_state); @@ -444,7 +418,6 @@ static void kvm_s390_flic_class_init(ObjectClass *oc, void *data) fsc->io_adapter_map = kvm_s390_io_adapter_map; fsc->add_adapter_routes = kvm_s390_add_adapter_routes; fsc->release_adapter_routes = kvm_s390_release_adapter_routes; - fsc->clear_io_irq = kvm_s390_clear_io_flic; } static const TypeInfo kvm_s390_flic_info = { diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c index e82e89362..c9486ed99 100644 --- a/hw/intc/slavio_intctl.c +++ b/hw/intc/slavio_intctl.c @@ -418,16 +418,15 @@ static void slavio_intctl_reset(DeviceState *d) slavio_check_interrupts(s, 0); } -static void slavio_intctl_init(Object *obj) +static int slavio_intctl_init1(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - SLAVIO_INTCTLState *s = SLAVIO_INTCTL(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + SLAVIO_INTCTLState *s = SLAVIO_INTCTL(dev); unsigned int i, j; char slave_name[45]; qdev_init_gpio_in(dev, slavio_set_irq_all, 32 + MAX_CPUS); - memory_region_init_io(&s->iomem, obj, &slavio_intctlm_mem_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &slavio_intctlm_mem_ops, s, "master-interrupt-controller", INTCTLM_SIZE); sysbus_init_mmio(sbd, &s->iomem); @@ -444,12 +443,16 @@ static void slavio_intctl_init(Object *obj) s->slaves[i].cpu = i; s->slaves[i].master = s; } + + return 0; } static void slavio_intctl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = slavio_intctl_init1; dc->reset = slavio_intctl_reset; dc->vmsd = &vmstate_intctl; } @@ -458,7 +461,6 @@ static const TypeInfo slavio_intctl_info = { .name = TYPE_SLAVIO_INTCTL, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(SLAVIO_INTCTLState), - .instance_init = slavio_intctl_init, .class_init = slavio_intctl_class_init, }; diff --git a/hw/intc/trace-events b/hw/intc/trace-events deleted file mode 100644 index f12192c08..000000000 --- a/hw/intc/trace-events +++ /dev/null @@ -1,123 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/intc/apic_common.c -cpu_set_apic_base(uint64_t val) "%016"PRIx64 -cpu_get_apic_base(uint64_t val) "%016"PRIx64 -# coalescing -apic_report_irq_delivered(int apic_irq_delivered) "coalescing %d" -apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d" -apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d" - -# hw/intc/apic.c -apic_local_deliver(int vector, uint32_t lvt) "vector %d delivery mode %d" -apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) "dest %d dest_mode %d delivery_mode %d vector %d trigger_mode %d" -apic_mem_readl(uint64_t addr, uint32_t val) "%"PRIx64" = %08x" -apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x" - -# hw/intc/slavio_intctl.c -slavio_intctl_mem_readl(uint32_t cpu, uint64_t addr, uint32_t ret) "read cpu %d reg 0x%"PRIx64" = %x" -slavio_intctl_mem_writel(uint32_t cpu, uint64_t addr, uint32_t val) "write cpu %d reg 0x%"PRIx64" = %x" -slavio_intctl_mem_writel_clear(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Cleared cpu %d irq mask %x, curmask %x" -slavio_intctl_mem_writel_set(uint32_t cpu, uint32_t val, uint32_t intreg_pending) "Set cpu %d irq mask %x, curmask %x" -slavio_intctlm_mem_readl(uint64_t addr, uint32_t ret) "read system reg 0x%"PRIx64" = %x" -slavio_intctlm_mem_writel(uint64_t addr, uint32_t val) "write system reg 0x%"PRIx64" = %x" -slavio_intctlm_mem_writel_enable(uint32_t val, uint32_t intregm_disabled) "Enabled master irq mask %x, curmask %x" -slavio_intctlm_mem_writel_disable(uint32_t val, uint32_t intregm_disabled) "Disabled master irq mask %x, curmask %x" -slavio_intctlm_mem_writel_target(uint32_t cpu) "Set master irq cpu %d" -slavio_check_interrupts(uint32_t pending, uint32_t intregm_disabled) "pending %x disabled %x" -slavio_set_irq(uint32_t target_cpu, int irq, uint32_t pil, int level) "Set cpu %d irq %d -> pil %d level %d" -slavio_set_timer_irq_cpu(int cpu, int level) "Set cpu %d local timer level %d" - -# hw/intc/grlib_irqmp.c -grlib_irqmp_check_irqs(uint32_t pend, uint32_t force, uint32_t mask, uint32_t lvl1, uint32_t lvl2) "pend:0x%04x force:0x%04x mask:0x%04x lvl1:0x%04x lvl0:0x%04x" -grlib_irqmp_ack(int intno) "interrupt:%d" -grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d" -grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64 -grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x" - -# hw/intc/lm32_pic.c -lm32_pic_raise_irq(void) "Raise CPU interrupt" -lm32_pic_lower_irq(void) "Lower CPU interrupt" -lm32_pic_interrupt(int irq, int level) "Set IRQ%d %d" -lm32_pic_set_im(uint32_t im) "im 0x%08x" -lm32_pic_set_ip(uint32_t ip) "ip 0x%08x" -lm32_pic_get_im(uint32_t im) "im 0x%08x" -lm32_pic_get_ip(uint32_t ip) "ip 0x%08x" - -# hw/intc/xics.c -xics_icp_check_ipi(int server, uint8_t mfrr) "CPU %d can take IPI mfrr=%#x" -xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR %#"PRIx32"->%#"PRIx32 -xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR %#"PRIx32" new XIRR %#"PRIx32 -xics_icp_irq(int server, int nr, uint8_t priority) "cpu %d trying to deliver irq %#"PRIx32" priority %#x" -xics_icp_raise(uint32_t xirr, uint8_t pending_priority) "raising IRQ new XIRR=%#x new pending priority=%#x" -xics_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq %#x]" -xics_masked_pending(void) "set_irq_msi: masked pending" -xics_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq %#x]" -xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq %#x [src %d] server %#x prio %#x" -xics_ics_reject(int nr, int srcno) "reject irq %#x [src %d]" -xics_ics_eoi(int nr) "ics_eoi: irq %#x" -xics_alloc(int src, int irq) "source#%d, irq %d" -xics_alloc_block(int src, int first, int num, bool lsi, int align) "source#%d, first irq %d, %d irqs, lsi=%d, alignnum %d" -xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs" -xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free" - -# hw/intc/s390_flic_kvm.c -flic_create_device(int err) "flic: create device failed %d" -flic_no_device_api(int err) "flic: no Device Contral API support %d" -flic_reset_failed(int err) "flic: reset failed %d" - -# hw/intc/aspeed_vic.c -aspeed_vic_set_irq(int irq, int level) "Enabling IRQ %d: %d" -aspeed_vic_update_fiq(int flags) "Raising FIQ: %d" -aspeed_vic_update_irq(int flags) "Raising IRQ: %d" -aspeed_vic_read(uint64_t offset, unsigned size, uint32_t value) "From 0x%" PRIx64 " of size %u: 0x%" PRIx32 -aspeed_vic_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32 - -# hw/intc/arm_gic.c -gic_enable_irq(int irq) "irq %d enabled" -gic_disable_irq(int irq) "irq %d disabled" -gic_set_irq(int irq, int level, int cpumask, int target) "irq %d level %d cpumask 0x%x target 0x%x" -gic_update_bestirq(int cpu, int irq, int prio, int priority_mask, int running_priority) "cpu %d irq %d priority %d cpu priority mask %d cpu running priority %d" -gic_update_set_irq(int cpu, const char *name, int level) "cpu[%d]: %s = %d" -gic_acknowledge_irq(int cpu, int irq) "cpu %d acknowledged irq %d" - -# hw/intc/arm_gicv3_cpuif.c -gicv3_icc_pmr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_PMR read cpu %x value 0x%" PRIx64 -gicv3_icc_pmr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_PMR write cpu %x value 0x%" PRIx64 -gicv3_icc_bpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_BPR read cpu %x value 0x%" PRIx64 -gicv3_icc_bpr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_BPR write cpu %x value 0x%" PRIx64 -gicv3_icc_ap_read(int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR read cpu %x value 0x%" PRIx64 -gicv3_icc_ap_write(int regno, uint32_t cpu, uint64_t val) "GICv3 ICC_AP%dR write cpu %x value 0x%" PRIx64 -gicv3_icc_igrpen_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN read cpu %x value 0x%" PRIx64 -gicv3_icc_igrpen_write(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN write cpu %x value 0x%" PRIx64 -gicv3_icc_igrpen1_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN1_EL3 read cpu %x value 0x%" PRIx64 -gicv3_icc_igrpen1_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_IGRPEN1_EL3 write cpu %x value 0x%" PRIx64 -gicv3_icc_ctlr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR read cpu %x value 0x%" PRIx64 -gicv3_icc_ctlr_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR write cpu %x value 0x%" PRIx64 -gicv3_icc_ctlr_el3_read(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 read cpu %x value 0x%" PRIx64 -gicv3_icc_ctlr_el3_write(uint32_t cpu, uint64_t val) "GICv3 ICC_CTLR_EL3 write cpu %x value 0x%" PRIx64 -gicv3_cpuif_update(uint32_t cpuid, int irq, int grp, int prio) "GICv3 CPU i/f %x HPPI update: irq %d group %d prio %d" -gicv3_cpuif_set_irqs(uint32_t cpuid, int fiqlevel, int irqlevel) "GICv3 CPU i/f %x HPPI update: setting FIQ %d IRQ %d" -gicv3_icc_generate_sgi(uint32_t cpuid, int irq, int irm, uint32_t aff, uint32_t targetlist) "GICv3 CPU i/f %x generating SGI %d IRM %d target affinity 0x%xxx targetlist 0x%x" -gicv3_icc_iar0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR0 read cpu %x value 0x%" PRIx64 -gicv3_icc_iar1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_IAR1 read cpu %x value 0x%" PRIx64 -gicv3_icc_eoir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_EOIR write cpu %x value 0x%" PRIx64 -gicv3_icc_hppir0_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR0 read cpu %x value 0x%" PRIx64 -gicv3_icc_hppir1_read(uint32_t cpu, uint64_t val) "GICv3 ICC_HPPIR1 read cpu %x value 0x%" PRIx64 -gicv3_icc_dir_write(uint32_t cpu, uint64_t val) "GICv3 ICC_DIR write cpu %x value 0x%" PRIx64 -gicv3_icc_rpr_read(uint32_t cpu, uint64_t val) "GICv3 ICC_RPR read cpu %x value 0x%" PRIx64 - -# hw/intc/arm_gicv3_dist.c -gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d" -gicv3_dist_badread(uint64_t offset, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " size %u secure %d: error" -gicv3_dist_write(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d" -gicv3_dist_badwrite(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error" -gicv3_dist_set_irq(int irq, int level) "GICv3 distributor interrupt %d level changed to %d" - -# hw/intc/arm_gicv3_redist.c -gicv3_redist_read(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d" -gicv3_redist_badread(uint32_t cpu, uint64_t offset, unsigned size, bool secure) "GICv3 redistributor %x read: offset 0x%" PRIx64 " size %u secure %d: error" -gicv3_redist_write(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d" -gicv3_redist_badwrite(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error" -gicv3_redist_set_irq(uint32_t cpu, int irq, int level) "GICv3 redistributor %x interrupt %d level changed to %d" -gicv3_redist_send_sgi(uint32_t cpu, int irq) "GICv3 redistributor %x pending SGI %d" diff --git a/hw/intc/xics.c b/hw/intc/xics.c index cd48f4204..8659be017 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -32,11 +32,12 @@ #include "hw/hw.h" #include "trace.h" #include "qemu/timer.h" +#include "hw/ppc/spapr.h" #include "hw/ppc/xics.h" #include "qemu/error-report.h" #include "qapi/visitor.h" -int xics_get_cpu_index_by_dt_id(int cpu_dt_id) +static int get_cpu_index_by_dt_id(int cpu_dt_id) { PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id); @@ -47,31 +48,17 @@ int xics_get_cpu_index_by_dt_id(int cpu_dt_id) return -1; } -void xics_cpu_destroy(XICSState *xics, PowerPCCPU *cpu) -{ - CPUState *cs = CPU(cpu); - ICPState *ss = &xics->ss[cs->cpu_index]; - - assert(cs->cpu_index < xics->nr_servers); - assert(cs == ss->cs); - - ss->output = NULL; - ss->cs = NULL; -} - -void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu) +void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - ICPState *ss = &xics->ss[cs->cpu_index]; - XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); + ICPState *ss = &icp->ss[cs->cpu_index]; + XICSStateClass *info = XICS_COMMON_GET_CLASS(icp); - assert(cs->cpu_index < xics->nr_servers); - - ss->cs = cs; + assert(cs->cpu_index < icp->nr_servers); if (info->cpu_setup) { - info->cpu_setup(xics, cpu); + info->cpu_setup(icp, cpu); } switch (PPC_INPUT(env)) { @@ -95,21 +82,21 @@ void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu) */ static void xics_common_reset(DeviceState *d) { - XICSState *xics = XICS_COMMON(d); + XICSState *icp = XICS_COMMON(d); int i; - for (i = 0; i < xics->nr_servers; i++) { - device_reset(DEVICE(&xics->ss[i])); + for (i = 0; i < icp->nr_servers; i++) { + device_reset(DEVICE(&icp->ss[i])); } - device_reset(DEVICE(xics->ics)); + device_reset(DEVICE(icp->ics)); } static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - XICSState *xics = XICS_COMMON(obj); - int64_t value = xics->nr_irqs; + XICSState *icp = XICS_COMMON(obj); + int64_t value = icp->nr_irqs; visit_type_int(v, name, &value, errp); } @@ -117,8 +104,8 @@ static void xics_prop_get_nr_irqs(Object *obj, Visitor *v, const char *name, static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - XICSState *xics = XICS_COMMON(obj); - XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); + XICSState *icp = XICS_COMMON(obj); + XICSStateClass *info = XICS_COMMON_GET_CLASS(icp); Error *error = NULL; int64_t value; @@ -127,23 +114,23 @@ static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, const char *name, error_propagate(errp, error); return; } - if (xics->nr_irqs) { + if (icp->nr_irqs) { error_setg(errp, "Number of interrupts is already set to %u", - xics->nr_irqs); + icp->nr_irqs); return; } assert(info->set_nr_irqs); - assert(xics->ics); - info->set_nr_irqs(xics, value, errp); + assert(icp->ics); + info->set_nr_irqs(icp, value, errp); } static void xics_prop_get_nr_servers(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - XICSState *xics = XICS_COMMON(obj); - int64_t value = xics->nr_servers; + XICSState *icp = XICS_COMMON(obj); + int64_t value = icp->nr_servers; visit_type_int(v, name, &value, errp); } @@ -152,8 +139,8 @@ static void xics_prop_set_nr_servers(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - XICSState *xics = XICS_COMMON(obj); - XICSStateClass *info = XICS_COMMON_GET_CLASS(xics); + XICSState *icp = XICS_COMMON(obj); + XICSStateClass *info = XICS_COMMON_GET_CLASS(icp); Error *error = NULL; int64_t value; @@ -162,14 +149,14 @@ static void xics_prop_set_nr_servers(Object *obj, Visitor *v, error_propagate(errp, error); return; } - if (xics->nr_servers) { + if (icp->nr_servers) { error_setg(errp, "Number of servers is already set to %u", - xics->nr_servers); + icp->nr_servers); return; } assert(info->set_nr_servers); - info->set_nr_servers(xics, value, errp); + info->set_nr_servers(icp, value, errp); } static void xics_common_initfn(Object *obj) @@ -212,9 +199,9 @@ static void ics_reject(ICSState *ics, int nr); static void ics_resend(ICSState *ics); static void ics_eoi(ICSState *ics, int nr); -static void icp_check_ipi(XICSState *xics, int server) +static void icp_check_ipi(XICSState *icp, int server) { - ICPState *ss = xics->ss + server; + ICPState *ss = icp->ss + server; if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { return; @@ -223,7 +210,7 @@ static void icp_check_ipi(XICSState *xics, int server) trace_xics_icp_check_ipi(server, ss->mfrr); if (XISR(ss)) { - ics_reject(xics->ics, XISR(ss)); + ics_reject(icp->ics, XISR(ss)); } ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI; @@ -231,19 +218,19 @@ static void icp_check_ipi(XICSState *xics, int server) qemu_irq_raise(ss->output); } -static void icp_resend(XICSState *xics, int server) +static void icp_resend(XICSState *icp, int server) { - ICPState *ss = xics->ss + server; + ICPState *ss = icp->ss + server; if (ss->mfrr < CPPR(ss)) { - icp_check_ipi(xics, server); + icp_check_ipi(icp, server); } - ics_resend(xics->ics); + ics_resend(icp->ics); } -void icp_set_cppr(XICSState *xics, int server, uint8_t cppr) +static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) { - ICPState *ss = xics->ss + server; + ICPState *ss = icp->ss + server; uint8_t old_cppr; uint32_t old_xisr; @@ -256,26 +243,26 @@ void icp_set_cppr(XICSState *xics, int server, uint8_t cppr) ss->xirr &= ~XISR_MASK; /* Clear XISR */ ss->pending_priority = 0xff; qemu_irq_lower(ss->output); - ics_reject(xics->ics, old_xisr); + ics_reject(icp->ics, old_xisr); } } else { if (!XISR(ss)) { - icp_resend(xics, server); + icp_resend(icp, server); } } } -void icp_set_mfrr(XICSState *xics, int server, uint8_t mfrr) +static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr) { - ICPState *ss = xics->ss + server; + ICPState *ss = icp->ss + server; ss->mfrr = mfrr; if (mfrr < CPPR(ss)) { - icp_check_ipi(xics, server); + icp_check_ipi(icp, server); } } -uint32_t icp_accept(ICPState *ss) +static uint32_t icp_accept(ICPState *ss) { uint32_t xirr = ss->xirr; @@ -288,39 +275,31 @@ uint32_t icp_accept(ICPState *ss) return xirr; } -uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr) -{ - if (mfrr) { - *mfrr = ss->mfrr; - } - return ss->xirr; -} - -void icp_eoi(XICSState *xics, int server, uint32_t xirr) +static void icp_eoi(XICSState *icp, int server, uint32_t xirr) { - ICPState *ss = xics->ss + server; + ICPState *ss = icp->ss + server; /* Send EOI -> ICS */ ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); trace_xics_icp_eoi(server, xirr, ss->xirr); - ics_eoi(xics->ics, xirr & XISR_MASK); + ics_eoi(icp->ics, xirr & XISR_MASK); if (!XISR(ss)) { - icp_resend(xics, server); + icp_resend(icp, server); } } -static void icp_irq(XICSState *xics, int server, int nr, uint8_t priority) +static void icp_irq(XICSState *icp, int server, int nr, uint8_t priority) { - ICPState *ss = xics->ss + server; + ICPState *ss = icp->ss + server; trace_xics_icp_irq(server, nr, priority); if ((priority >= CPPR(ss)) || (XISR(ss) && (ss->pending_priority <= priority))) { - ics_reject(xics->ics, nr); + ics_reject(icp->ics, nr); } else { if (XISR(ss)) { - ics_reject(xics->ics, XISR(ss)); + ics_reject(icp->ics, XISR(ss)); } ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK); ss->pending_priority = priority; @@ -397,6 +376,12 @@ static const TypeInfo icp_info = { /* * ICS: Source layer */ +static int ics_valid_irq(ICSState *ics, uint32_t nr) +{ + return (nr >= ics->offset) + && (nr < (ics->offset + ics->nr_irqs)); +} + static void resend_msi(ICSState *ics, int srcno) { ICSIRQState *irq = ics->irqs + srcno; @@ -405,7 +390,7 @@ static void resend_msi(ICSState *ics, int srcno) if (irq->status & XICS_STATUS_REJECTED) { irq->status &= ~XICS_STATUS_REJECTED; if (irq->priority != 0xff) { - icp_irq(ics->xics, irq->server, srcno + ics->offset, + icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } } @@ -419,7 +404,7 @@ static void resend_lsi(ICSState *ics, int srcno) && (irq->status & XICS_STATUS_ASSERTED) && !(irq->status & XICS_STATUS_SENT)) { irq->status |= XICS_STATUS_SENT; - icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority); + icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } } @@ -434,7 +419,7 @@ static void set_irq_msi(ICSState *ics, int srcno, int val) irq->status |= XICS_STATUS_MASKED_PENDING; trace_xics_masked_pending(); } else { - icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority); + icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } } } @@ -473,7 +458,7 @@ static void write_xive_msi(ICSState *ics, int srcno) } irq->status &= ~XICS_STATUS_MASKED_PENDING; - icp_irq(ics->xics, irq->server, srcno + ics->offset, irq->priority); + icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } static void write_xive_lsi(ICSState *ics, int srcno) @@ -481,8 +466,8 @@ static void write_xive_lsi(ICSState *ics, int srcno) resend_lsi(ics, srcno); } -void ics_write_xive(ICSState *ics, int nr, int server, - uint8_t priority, uint8_t saved_priority) +static void ics_write_xive(ICSState *ics, int nr, int server, + uint8_t priority, uint8_t saved_priority) { int srcno = nr - ics->offset; ICSIRQState *irq = ics->irqs + srcno; @@ -558,8 +543,8 @@ static int ics_post_load(ICSState *ics, int version_id) { int i; - for (i = 0; i < ics->xics->nr_servers; i++) { - icp_resend(ics->xics, i); + for (i = 0; i < ics->icp->nr_servers; i++) { + icp_resend(ics->icp, i); } return 0; @@ -659,14 +644,14 @@ static const TypeInfo ics_info = { /* * Exported functions */ -int xics_find_source(XICSState *xics, int irq) +static int xics_find_source(XICSState *icp, int irq) { int sources = 1; int src; /* FIXME: implement multiple sources */ for (src = 0; src < sources; ++src) { - ICSState *ics = &xics->ics[src]; + ICSState *ics = &icp->ics[src]; if (ics_valid_irq(ics, irq)) { return src; } @@ -675,19 +660,19 @@ int xics_find_source(XICSState *xics, int irq) return -1; } -qemu_irq xics_get_qirq(XICSState *xics, int irq) +qemu_irq xics_get_qirq(XICSState *icp, int irq) { - int src = xics_find_source(xics, irq); + int src = xics_find_source(icp, irq); if (src >= 0) { - ICSState *ics = &xics->ics[src]; + ICSState *ics = &icp->ics[src]; return ics->qirqs[irq - ics->offset]; } return NULL; } -void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) +static void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) { assert(!(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK)); @@ -695,9 +680,412 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI; } +void xics_set_irq_type(XICSState *icp, int irq, bool lsi) +{ + int src = xics_find_source(icp, irq); + ICSState *ics; + + assert(src >= 0); + + ics = &icp->ics[src]; + ics_set_irq_type(ics, irq - ics->offset, lsi); +} + +#define ICS_IRQ_FREE(ics, srcno) \ + (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) + +static int ics_find_free_block(ICSState *ics, int num, int alignnum) +{ + int first, i; + + for (first = 0; first < ics->nr_irqs; first += alignnum) { + if (num > (ics->nr_irqs - first)) { + return -1; + } + for (i = first; i < first + num; ++i) { + if (!ICS_IRQ_FREE(ics, i)) { + break; + } + } + if (i == (first + num)) { + return first; + } + } + + return -1; +} + +int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi, Error **errp) +{ + ICSState *ics = &icp->ics[src]; + int irq; + + if (irq_hint) { + assert(src == xics_find_source(icp, irq_hint)); + if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) { + error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint); + return -1; + } + irq = irq_hint; + } else { + irq = ics_find_free_block(ics, 1, 1); + if (irq < 0) { + error_setg(errp, "can't allocate IRQ: no IRQ left"); + return -1; + } + irq += ics->offset; + } + + ics_set_irq_type(ics, irq - ics->offset, lsi); + trace_xics_alloc(src, irq); + + return irq; +} + +/* + * Allocate block of consecutive IRQs, and return the number of the first IRQ in the block. + * If align==true, aligns the first IRQ number to num. + */ +int xics_alloc_block(XICSState *icp, int src, int num, bool lsi, bool align, + Error **errp) +{ + int i, first = -1; + ICSState *ics = &icp->ics[src]; + + assert(src == 0); + /* + * MSIMesage::data is used for storing VIRQ so + * it has to be aligned to num to support multiple + * MSI vectors. MSI-X is not affected by this. + * The hint is used for the first IRQ, the rest should + * be allocated continuously. + */ + if (align) { + assert((num == 1) || (num == 2) || (num == 4) || + (num == 8) || (num == 16) || (num == 32)); + first = ics_find_free_block(ics, num, num); + } else { + first = ics_find_free_block(ics, num, 1); + } + if (first < 0) { + error_setg(errp, "can't find a free %d-IRQ block", num); + return -1; + } + + if (first >= 0) { + for (i = first; i < first + num; ++i) { + ics_set_irq_type(ics, i, lsi); + } + } + first += ics->offset; + + trace_xics_alloc_block(src, first, num, lsi, align); + + return first; +} + +static void ics_free(ICSState *ics, int srcno, int num) +{ + int i; + + for (i = srcno; i < srcno + num; ++i) { + if (ICS_IRQ_FREE(ics, i)) { + trace_xics_ics_free_warn(ics - ics->icp->ics, i + ics->offset); + } + memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); + } +} + +void xics_free(XICSState *icp, int irq, int num) +{ + int src = xics_find_source(icp, irq); + + if (src >= 0) { + ICSState *ics = &icp->ics[src]; + + /* FIXME: implement multiple sources */ + assert(src == 0); + + trace_xics_ics_free(ics - icp->ics, irq, num); + ics_free(ics, irq - ics->offset, num); + } +} + +/* + * Guest interfaces + */ + +static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + target_ulong cppr = args[0]; + + icp_set_cppr(spapr->icp, cs->cpu_index, cppr); + return H_SUCCESS; +} + +static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + target_ulong server = get_cpu_index_by_dt_id(args[0]); + target_ulong mfrr = args[1]; + + if (server >= spapr->icp->nr_servers) { + return H_PARAMETER; + } + + icp_set_mfrr(spapr->icp, server, mfrr); + return H_SUCCESS; +} + +static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + uint32_t xirr = icp_accept(spapr->icp->ss + cs->cpu_index); + + args[0] = xirr; + return H_SUCCESS; +} + +static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + ICPState *ss = &spapr->icp->ss[cs->cpu_index]; + uint32_t xirr = icp_accept(ss); + + args[0] = xirr; + args[1] = cpu_get_host_ticks(); + return H_SUCCESS; +} + +static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + target_ulong xirr = args[0]; + + icp_eoi(spapr->icp, cs->cpu_index, xirr); + return H_SUCCESS; +} + +static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + CPUState *cs = CPU(cpu); + ICPState *ss = &spapr->icp->ss[cs->cpu_index]; + + args[0] = ss->xirr; + args[1] = ss->mfrr; + + return H_SUCCESS; +} + +static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, + uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + ICSState *ics = spapr->icp->ics; + uint32_t nr, server, priority; + + if ((nargs != 3) || (nret != 1)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + nr = rtas_ld(args, 0); + server = get_cpu_index_by_dt_id(rtas_ld(args, 1)); + priority = rtas_ld(args, 2); + + if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers) + || (priority > 0xff)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + ics_write_xive(ics, nr, server, priority, priority); + + rtas_st(rets, 0, RTAS_OUT_SUCCESS); +} + +static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, + uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + ICSState *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 3)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + rtas_st(rets, 0, RTAS_OUT_SUCCESS); + rtas_st(rets, 1, ics->irqs[nr - ics->offset].server); + rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); +} + +static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr, + uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + ICSState *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 1)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, + ics->irqs[nr - ics->offset].priority); + + rtas_st(rets, 0, RTAS_OUT_SUCCESS); +} + +static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, + uint32_t token, + uint32_t nargs, target_ulong args, + uint32_t nret, target_ulong rets) +{ + ICSState *ics = spapr->icp->ics; + uint32_t nr; + + if ((nargs != 1) || (nret != 1)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + nr = rtas_ld(args, 0); + + if (!ics_valid_irq(ics, nr)) { + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } + + ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, + ics->irqs[nr - ics->offset].saved_priority, + ics->irqs[nr - ics->offset].saved_priority); + + rtas_st(rets, 0, RTAS_OUT_SUCCESS); +} + +/* + * XICS + */ + +static void xics_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp) +{ + icp->nr_irqs = icp->ics->nr_irqs = nr_irqs; +} + +static void xics_set_nr_servers(XICSState *icp, uint32_t nr_servers, + Error **errp) +{ + int i; + + icp->nr_servers = nr_servers; + + icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState)); + for (i = 0; i < icp->nr_servers; i++) { + char buffer[32]; + object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_ICP); + snprintf(buffer, sizeof(buffer), "icp[%d]", i); + object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), + errp); + } +} + +static void xics_realize(DeviceState *dev, Error **errp) +{ + XICSState *icp = XICS(dev); + Error *error = NULL; + int i; + + if (!icp->nr_servers) { + error_setg(errp, "Number of servers needs to be greater 0"); + return; + } + + /* Registration of global state belongs into realize */ + spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive); + spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive); + spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off); + spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on); + + spapr_register_hypercall(H_CPPR, h_cppr); + spapr_register_hypercall(H_IPI, h_ipi); + spapr_register_hypercall(H_XIRR, h_xirr); + spapr_register_hypercall(H_XIRR_X, h_xirr_x); + spapr_register_hypercall(H_EOI, h_eoi); + spapr_register_hypercall(H_IPOLL, h_ipoll); + + object_property_set_bool(OBJECT(icp->ics), true, "realized", &error); + if (error) { + error_propagate(errp, error); + return; + } + + for (i = 0; i < icp->nr_servers; i++) { + object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error); + if (error) { + error_propagate(errp, error); + return; + } + } +} + +static void xics_initfn(Object *obj) +{ + XICSState *xics = XICS(obj); + + xics->ics = ICS(object_new(TYPE_ICS)); + object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); + xics->ics->icp = xics; +} + +static void xics_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + XICSStateClass *xsc = XICS_CLASS(oc); + + dc->realize = xics_realize; + xsc->set_nr_irqs = xics_set_nr_irqs; + xsc->set_nr_servers = xics_set_nr_servers; +} + +static const TypeInfo xics_info = { + .name = TYPE_XICS, + .parent = TYPE_XICS_COMMON, + .instance_size = sizeof(XICSState), + .class_size = sizeof(XICSStateClass), + .class_init = xics_class_init, + .instance_init = xics_initfn, +}; + static void xics_register_types(void) { type_register_static(&xics_common_info); + type_register_static(&xics_info); type_register_static(&ics_info); type_register_static(&icp_info); } diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index edbd62fd1..9029d9ee0 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -31,7 +31,6 @@ #include "cpu.h" #include "hw/hw.h" #include "trace.h" -#include "sysemu/kvm.h" #include "hw/ppc/spapr.h" #include "hw/ppc/xics.h" #include "kvm_ppc.h" @@ -114,10 +113,8 @@ static void icp_kvm_reset(DeviceState *dev) icp->pending_priority = 0xff; icp->mfrr = 0xff; - /* Make all outputs as deasserted only if the CPU thread is in use */ - if (icp->output) { - qemu_set_irq(icp->output, 0); - } + /* Make all outputs are deasserted */ + qemu_set_irq(icp->output, 0); icp_set_kvm_state(icp, 1); } @@ -145,7 +142,7 @@ static const TypeInfo icp_kvm_info = { */ static void ics_get_kvm_state(ICSState *ics) { - KVMXICSState *xicskvm = XICS_SPAPR_KVM(ics->xics); + KVMXICSState *icpkvm = KVM_XICS(ics->icp); uint64_t state; struct kvm_device_attr attr = { .flags = 0, @@ -160,7 +157,7 @@ static void ics_get_kvm_state(ICSState *ics) attr.attr = i + ics->offset; - ret = ioctl(xicskvm->kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr); + ret = ioctl(icpkvm->kernel_xics_fd, KVM_GET_DEVICE_ATTR, &attr); if (ret != 0) { error_report("Unable to retrieve KVM interrupt controller state" " for IRQ %d: %s", i + ics->offset, strerror(errno)); @@ -204,7 +201,7 @@ static void ics_get_kvm_state(ICSState *ics) static int ics_set_kvm_state(ICSState *ics, int version_id) { - KVMXICSState *xicskvm = XICS_SPAPR_KVM(ics->xics); + KVMXICSState *icpkvm = KVM_XICS(ics->icp); uint64_t state; struct kvm_device_attr attr = { .flags = 0, @@ -238,7 +235,7 @@ static int ics_set_kvm_state(ICSState *ics, int version_id) } } - ret = ioctl(xicskvm->kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr); + ret = ioctl(icpkvm->kernel_xics_fd, KVM_SET_DEVICE_ATTR, &attr); if (ret != 0) { error_report("Unable to restore KVM interrupt controller state" " for IRQs %d: %s", i + ics->offset, strerror(errno)); @@ -324,17 +321,17 @@ static const TypeInfo ics_kvm_info = { /* * XICS-KVM */ -static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu) +static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu) { CPUState *cs; ICPState *ss; - KVMXICSState *xicskvm = XICS_SPAPR_KVM(xics); + KVMXICSState *icpkvm = KVM_XICS(icp); cs = CPU(cpu); - ss = &xics->ss[cs->cpu_index]; + ss = &icp->ss[cs->cpu_index]; - assert(cs->cpu_index < xics->nr_servers); - if (xicskvm->kernel_xics_fd == -1) { + assert(cs->cpu_index < icp->nr_servers); + if (icpkvm->kernel_xics_fd == -1) { abort(); } @@ -347,12 +344,13 @@ static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu) return; } - if (xicskvm->kernel_xics_fd != -1) { + if (icpkvm->kernel_xics_fd != -1) { int ret; + ss->cs = cs; + ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, - xicskvm->kernel_xics_fd, - kvm_arch_vcpu_id(cs)); + icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs)); if (ret < 0) { error_report("Unable to connect CPU%ld to kernel XICS: %s", kvm_arch_vcpu_id(cs), strerror(errno)); @@ -362,25 +360,24 @@ static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu) } } -static void xics_kvm_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, - Error **errp) +static void xics_kvm_set_nr_irqs(XICSState *icp, uint32_t nr_irqs, Error **errp) { - xics->nr_irqs = xics->ics->nr_irqs = nr_irqs; + icp->nr_irqs = icp->ics->nr_irqs = nr_irqs; } -static void xics_kvm_set_nr_servers(XICSState *xics, uint32_t nr_servers, +static void xics_kvm_set_nr_servers(XICSState *icp, uint32_t nr_servers, Error **errp) { int i; - xics->nr_servers = nr_servers; + icp->nr_servers = nr_servers; - xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState)); - for (i = 0; i < xics->nr_servers; i++) { + icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState)); + for (i = 0; i < icp->nr_servers; i++) { char buffer[32]; - object_initialize(&xics->ss[i], sizeof(xics->ss[i]), TYPE_KVM_ICP); + object_initialize(&icp->ss[i], sizeof(icp->ss[i]), TYPE_KVM_ICP); snprintf(buffer, sizeof(buffer), "icp[%d]", i); - object_property_add_child(OBJECT(xics), buffer, OBJECT(&xics->ss[i]), + object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), errp); } } @@ -396,8 +393,8 @@ static void rtas_dummy(PowerPCCPU *cpu, sPAPRMachineState *spapr, static void xics_kvm_realize(DeviceState *dev, Error **errp) { - KVMXICSState *xicskvm = XICS_SPAPR_KVM(dev); - XICSState *xics = XICS_COMMON(dev); + KVMXICSState *icpkvm = KVM_XICS(dev); + XICSState *icp = XICS_COMMON(dev); int i, rc; Error *error = NULL; struct kvm_create_device xics_create_device = { @@ -447,18 +444,17 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp) goto fail; } - xicskvm->kernel_xics_fd = xics_create_device.fd; + icpkvm->kernel_xics_fd = xics_create_device.fd; - object_property_set_bool(OBJECT(xics->ics), true, "realized", &error); + object_property_set_bool(OBJECT(icp->ics), true, "realized", &error); if (error) { error_propagate(errp, error); goto fail; } - assert(xics->nr_servers); - for (i = 0; i < xics->nr_servers; i++) { - object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized", - &error); + assert(icp->nr_servers); + for (i = 0; i < icp->nr_servers; i++) { + object_property_set_bool(OBJECT(&icp->ss[i]), true, "realized", &error); if (error) { error_propagate(errp, error); goto fail; @@ -484,7 +480,7 @@ static void xics_kvm_initfn(Object *obj) xics->ics = ICS(object_new(TYPE_KVM_ICS)); object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); - xics->ics->xics = xics; + xics->ics->icp = xics; } static void xics_kvm_class_init(ObjectClass *oc, void *data) @@ -498,8 +494,8 @@ static void xics_kvm_class_init(ObjectClass *oc, void *data) xsc->set_nr_servers = xics_kvm_set_nr_servers; } -static const TypeInfo xics_spapr_kvm_info = { - .name = TYPE_XICS_SPAPR_KVM, +static const TypeInfo xics_kvm_info = { + .name = TYPE_KVM_XICS, .parent = TYPE_XICS_COMMON, .instance_size = sizeof(KVMXICSState), .class_init = xics_kvm_class_init, @@ -508,7 +504,7 @@ static const TypeInfo xics_spapr_kvm_info = { static void xics_kvm_register_types(void) { - type_register_static(&xics_spapr_kvm_info); + type_register_static(&xics_kvm_info); type_register_static(&ics_kvm_info); type_register_static(&icp_kvm_info); } diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c deleted file mode 100644 index 618826dac..000000000 --- a/hw/intc/xics_spapr.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator - * - * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics - * - * Copyright (c) 2010,2011 David Gibson, IBM Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "hw/hw.h" -#include "trace.h" -#include "qemu/timer.h" -#include "hw/ppc/spapr.h" -#include "hw/ppc/xics.h" -#include "qapi/visitor.h" -#include "qapi/error.h" - -/* - * Guest interfaces - */ - -static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - target_ulong cppr = args[0]; - - icp_set_cppr(spapr->xics, cs->cpu_index, cppr); - return H_SUCCESS; -} - -static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong server = xics_get_cpu_index_by_dt_id(args[0]); - target_ulong mfrr = args[1]; - - if (server >= spapr->xics->nr_servers) { - return H_PARAMETER; - } - - icp_set_mfrr(spapr->xics, server, mfrr); - return H_SUCCESS; -} - -static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - uint32_t xirr = icp_accept(spapr->xics->ss + cs->cpu_index); - - args[0] = xirr; - return H_SUCCESS; -} - -static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - ICPState *ss = &spapr->xics->ss[cs->cpu_index]; - uint32_t xirr = icp_accept(ss); - - args[0] = xirr; - args[1] = cpu_get_host_ticks(); - return H_SUCCESS; -} - -static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - target_ulong xirr = args[0]; - - icp_eoi(spapr->xics, cs->cpu_index, xirr); - return H_SUCCESS; -} - -static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr, - target_ulong opcode, target_ulong *args) -{ - CPUState *cs = CPU(cpu); - uint32_t mfrr; - uint32_t xirr = icp_ipoll(spapr->xics->ss + cs->cpu_index, &mfrr); - - args[0] = xirr; - args[1] = mfrr; - - return H_SUCCESS; -} - -static void rtas_set_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, - uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - ICSState *ics = spapr->xics->ics; - uint32_t nr, server, priority; - - if ((nargs != 3) || (nret != 1)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - nr = rtas_ld(args, 0); - server = xics_get_cpu_index_by_dt_id(rtas_ld(args, 1)); - priority = rtas_ld(args, 2); - - if (!ics_valid_irq(ics, nr) || (server >= ics->xics->nr_servers) - || (priority > 0xff)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - ics_write_xive(ics, nr, server, priority, priority); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); -} - -static void rtas_get_xive(PowerPCCPU *cpu, sPAPRMachineState *spapr, - uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - ICSState *ics = spapr->xics->ics; - uint32_t nr; - - if ((nargs != 1) || (nret != 3)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - nr = rtas_ld(args, 0); - - if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); - rtas_st(rets, 1, ics->irqs[nr - ics->offset].server); - rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority); -} - -static void rtas_int_off(PowerPCCPU *cpu, sPAPRMachineState *spapr, - uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - ICSState *ics = spapr->xics->ics; - uint32_t nr; - - if ((nargs != 1) || (nret != 1)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - nr = rtas_ld(args, 0); - - if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, 0xff, - ics->irqs[nr - ics->offset].priority); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); -} - -static void rtas_int_on(PowerPCCPU *cpu, sPAPRMachineState *spapr, - uint32_t token, - uint32_t nargs, target_ulong args, - uint32_t nret, target_ulong rets) -{ - ICSState *ics = spapr->xics->ics; - uint32_t nr; - - if ((nargs != 1) || (nret != 1)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - nr = rtas_ld(args, 0); - - if (!ics_valid_irq(ics, nr)) { - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); - return; - } - - ics_write_xive(ics, nr, ics->irqs[nr - ics->offset].server, - ics->irqs[nr - ics->offset].saved_priority, - ics->irqs[nr - ics->offset].saved_priority); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); -} - -static void xics_spapr_set_nr_irqs(XICSState *xics, uint32_t nr_irqs, - Error **errp) -{ - xics->nr_irqs = xics->ics->nr_irqs = nr_irqs; -} - -static void xics_spapr_set_nr_servers(XICSState *xics, uint32_t nr_servers, - Error **errp) -{ - int i; - - xics->nr_servers = nr_servers; - - xics->ss = g_malloc0(xics->nr_servers * sizeof(ICPState)); - for (i = 0; i < xics->nr_servers; i++) { - char buffer[32]; - object_initialize(&xics->ss[i], sizeof(xics->ss[i]), TYPE_ICP); - snprintf(buffer, sizeof(buffer), "icp[%d]", i); - object_property_add_child(OBJECT(xics), buffer, OBJECT(&xics->ss[i]), - errp); - } -} - -static void xics_spapr_realize(DeviceState *dev, Error **errp) -{ - XICSState *xics = XICS_SPAPR(dev); - Error *error = NULL; - int i; - - if (!xics->nr_servers) { - error_setg(errp, "Number of servers needs to be greater 0"); - return; - } - - /* Registration of global state belongs into realize */ - spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive); - spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive); - spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off); - spapr_rtas_register(RTAS_IBM_INT_ON, "ibm,int-on", rtas_int_on); - - spapr_register_hypercall(H_CPPR, h_cppr); - spapr_register_hypercall(H_IPI, h_ipi); - spapr_register_hypercall(H_XIRR, h_xirr); - spapr_register_hypercall(H_XIRR_X, h_xirr_x); - spapr_register_hypercall(H_EOI, h_eoi); - spapr_register_hypercall(H_IPOLL, h_ipoll); - - object_property_set_bool(OBJECT(xics->ics), true, "realized", &error); - if (error) { - error_propagate(errp, error); - return; - } - - for (i = 0; i < xics->nr_servers; i++) { - object_property_set_bool(OBJECT(&xics->ss[i]), true, "realized", - &error); - if (error) { - error_propagate(errp, error); - return; - } - } -} - -static void xics_spapr_initfn(Object *obj) -{ - XICSState *xics = XICS_SPAPR(obj); - - xics->ics = ICS(object_new(TYPE_ICS)); - object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); - xics->ics->xics = xics; -} - -static void xics_spapr_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - XICSStateClass *xsc = XICS_SPAPR_CLASS(oc); - - dc->realize = xics_spapr_realize; - xsc->set_nr_irqs = xics_spapr_set_nr_irqs; - xsc->set_nr_servers = xics_spapr_set_nr_servers; -} - -static const TypeInfo xics_spapr_info = { - .name = TYPE_XICS_SPAPR, - .parent = TYPE_XICS_COMMON, - .instance_size = sizeof(XICSState), - .class_size = sizeof(XICSStateClass), - .class_init = xics_spapr_class_init, - .instance_init = xics_spapr_initfn, -}; - -#define ICS_IRQ_FREE(ics, srcno) \ - (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) - -static int ics_find_free_block(ICSState *ics, int num, int alignnum) -{ - int first, i; - - for (first = 0; first < ics->nr_irqs; first += alignnum) { - if (num > (ics->nr_irqs - first)) { - return -1; - } - for (i = first; i < first + num; ++i) { - if (!ICS_IRQ_FREE(ics, i)) { - break; - } - } - if (i == (first + num)) { - return first; - } - } - - return -1; -} - -int xics_spapr_alloc(XICSState *xics, int src, int irq_hint, bool lsi, - Error **errp) -{ - ICSState *ics = &xics->ics[src]; - int irq; - - if (irq_hint) { - assert(src == xics_find_source(xics, irq_hint)); - if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) { - error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint); - return -1; - } - irq = irq_hint; - } else { - irq = ics_find_free_block(ics, 1, 1); - if (irq < 0) { - error_setg(errp, "can't allocate IRQ: no IRQ left"); - return -1; - } - irq += ics->offset; - } - - ics_set_irq_type(ics, irq - ics->offset, lsi); - trace_xics_alloc(src, irq); - - return irq; -} - -/* - * Allocate block of consecutive IRQs, and return the number of the first IRQ in - * the block. If align==true, aligns the first IRQ number to num. - */ -int xics_spapr_alloc_block(XICSState *xics, int src, int num, bool lsi, - bool align, Error **errp) -{ - int i, first = -1; - ICSState *ics = &xics->ics[src]; - - assert(src == 0); - /* - * MSIMesage::data is used for storing VIRQ so - * it has to be aligned to num to support multiple - * MSI vectors. MSI-X is not affected by this. - * The hint is used for the first IRQ, the rest should - * be allocated continuously. - */ - if (align) { - assert((num == 1) || (num == 2) || (num == 4) || - (num == 8) || (num == 16) || (num == 32)); - first = ics_find_free_block(ics, num, num); - } else { - first = ics_find_free_block(ics, num, 1); - } - if (first < 0) { - error_setg(errp, "can't find a free %d-IRQ block", num); - return -1; - } - - if (first >= 0) { - for (i = first; i < first + num; ++i) { - ics_set_irq_type(ics, i, lsi); - } - } - first += ics->offset; - - trace_xics_alloc_block(src, first, num, lsi, align); - - return first; -} - -static void ics_free(ICSState *ics, int srcno, int num) -{ - int i; - - for (i = srcno; i < srcno + num; ++i) { - if (ICS_IRQ_FREE(ics, i)) { - trace_xics_ics_free_warn(ics - ics->xics->ics, i + ics->offset); - } - memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); - } -} - -void xics_spapr_free(XICSState *xics, int irq, int num) -{ - int src = xics_find_source(xics, irq); - - if (src >= 0) { - ICSState *ics = &xics->ics[src]; - - /* FIXME: implement multiple sources */ - assert(src == 0); - - trace_xics_ics_free(ics - xics->ics, irq, num); - ics_free(ics, irq - ics->offset, num); - } -} - -static void xics_spapr_register_types(void) -{ - type_register_static(&xics_spapr_info); -} - -type_init(xics_spapr_register_types) diff --git a/hw/ipack/ipack.c b/hw/ipack/ipack.c index 6021e6d13..5f99ed9a7 100644 --- a/hw/ipack/ipack.c +++ b/hw/ipack/ipack.c @@ -2,7 +2,7 @@ * QEMU IndustryPack emulation * * Copyright (C) 2012 Igalia, S.L. - * Author: Alberto Garcia <berto@igalia.com> + * Author: Alberto Garcia <agarcia@igalia.com> * * This code is licensed under the GNU GPL v2 or (at your option) any * later version. diff --git a/hw/ipack/tpci200.c b/hw/ipack/tpci200.c index 4dfa6b33f..fdda6f414 100644 --- a/hw/ipack/tpci200.c +++ b/hw/ipack/tpci200.c @@ -2,7 +2,7 @@ * QEMU TEWS TPCI200 IndustryPack carrier emulation * * Copyright (C) 2012 Igalia, S.L. - * Author: Alberto Garcia <berto@igalia.com> + * Author: Alberto Garcia <agarcia@igalia.com> * * This code is licensed under the GNU GPL v2 or (at your option) any * later version. diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c index f09f217e7..6adec1e99 100644 --- a/hw/ipmi/ipmi.c +++ b/hw/ipmi/ipmi.c @@ -30,13 +30,6 @@ #include "qom/object_interfaces.h" #include "qapi/visitor.h" -static uint32_t ipmi_current_uuid = 1; - -uint32_t ipmi_next_uuid(void) -{ - return ipmi_current_uuid++; -} - static int ipmi_do_hw_op(IPMIInterface *s, enum ipmi_op op, int checkonly) { switch (op) { @@ -129,3 +122,30 @@ static void ipmi_register_types(void) } type_init(ipmi_register_types) + +static IPMIFwInfo *ipmi_fw_info; +static unsigned int ipmi_fw_info_len; + +static uint32_t current_uuid = 1; + +void ipmi_add_fwinfo(IPMIFwInfo *info, Error **errp) +{ + info->uuid = current_uuid++; + ipmi_fw_info = g_realloc(ipmi_fw_info, + sizeof(*ipmi_fw_info) * (ipmi_fw_info_len + 1)); + ipmi_fw_info[ipmi_fw_info_len] = *info; +} + +IPMIFwInfo *ipmi_first_fwinfo(void) +{ + return ipmi_fw_info; +} + +IPMIFwInfo *ipmi_next_fwinfo(IPMIFwInfo *current) +{ + current++; + if (current >= &ipmi_fw_info[ipmi_fw_info_len]) { + return NULL; + } + return current; +} diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c index 157879e17..fe12112a2 100644 --- a/hw/ipmi/ipmi_bmc_extern.c +++ b/hw/ipmi/ipmi_bmc_extern.c @@ -190,7 +190,7 @@ static void ipmi_bmc_extern_handle_command(IPMIBmc *b, if (ibe->outlen) { /* We already have a command queued. Shouldn't ever happen. */ fprintf(stderr, "IPMI KCS: Got command when not finished with the" - " previous command\n"); + " previous commmand\n"); abort(); } diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c index f03661715..aaea12ecd 100644 --- a/hw/ipmi/isa_ipmi_bt.c +++ b/hw/ipmi/isa_ipmi_bt.c @@ -390,6 +390,16 @@ static void ipmi_bt_init(IPMIInterface *ii, Error **errp) memory_region_init_io(&ib->io, NULL, &ipmi_bt_io_ops, ii, "ipmi-bt", 3); } +static void ipmi_bt_class_init(IPMIInterfaceClass *iic) +{ + iic->init = ipmi_bt_init; + iic->set_atn = ipmi_bt_set_atn; + iic->handle_rsp = ipmi_bt_handle_rsp; + iic->handle_if_event = ipmi_bt_handle_event; + iic->set_irq_enable = ipmi_bt_set_irq_enable; + iic->reset = ipmi_bt_handle_reset; +} + #define TYPE_ISA_IPMI_BT "isa-ipmi-bt" #define ISA_IPMI_BT(obj) OBJECT_CHECK(ISAIPMIBTDevice, (obj), \ @@ -399,38 +409,9 @@ typedef struct ISAIPMIBTDevice { ISADevice dev; int32_t isairq; IPMIBT bt; - uint32_t uuid; + IPMIFwInfo fwinfo; } ISAIPMIBTDevice; -static void ipmi_bt_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info) -{ - ISAIPMIBTDevice *iib = ISA_IPMI_BT(ii); - - info->interface_name = "bt"; - info->interface_type = IPMI_SMBIOS_BT; - info->ipmi_spec_major_revision = 2; - info->ipmi_spec_minor_revision = 0; - info->base_address = iib->bt.io_base; - info->register_length = iib->bt.io_length; - info->register_spacing = 1; - info->memspace = IPMI_MEMSPACE_IO; - info->irq_type = IPMI_LEVEL_IRQ; - info->interrupt_number = iib->isairq; - info->i2c_slave_address = iib->bt.bmc->slave_addr; - info->uuid = iib->uuid; -} - -static void ipmi_bt_class_init(IPMIInterfaceClass *iic) -{ - iic->init = ipmi_bt_init; - iic->set_atn = ipmi_bt_set_atn; - iic->handle_rsp = ipmi_bt_handle_rsp; - iic->handle_if_event = ipmi_bt_handle_event; - iic->set_irq_enable = ipmi_bt_set_irq_enable; - iic->reset = ipmi_bt_handle_reset; - iic->get_fwinfo = ipmi_bt_get_fwinfo; -} - static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp) { ISADevice *isadev = ISA_DEVICE(dev); @@ -443,8 +424,6 @@ static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp) return; } - iib->uuid = ipmi_next_uuid(); - iib->bt.bmc->intf = ii; iic->init(ii, errp); @@ -459,6 +438,20 @@ static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp) qdev_set_legacy_instance_id(dev, iib->bt.io_base, iib->bt.io_length); isa_register_ioport(isadev, &iib->bt.io, iib->bt.io_base); + + iib->fwinfo.interface_name = "bt"; + iib->fwinfo.interface_type = IPMI_SMBIOS_BT; + iib->fwinfo.ipmi_spec_major_revision = 2; + iib->fwinfo.ipmi_spec_minor_revision = 0; + iib->fwinfo.base_address = iib->bt.io_base; + iib->fwinfo.register_length = iib->bt.io_length; + iib->fwinfo.register_spacing = 1; + iib->fwinfo.memspace = IPMI_MEMSPACE_IO; + iib->fwinfo.irq_type = IPMI_LEVEL_IRQ; + iib->fwinfo.interrupt_number = iib->isairq; + iib->fwinfo.acpi_parent = "\\_SB.PCI0.ISA"; + iib->fwinfo.i2c_slave_address = iib->bt.bmc->slave_addr; + ipmi_add_fwinfo(&iib->fwinfo, errp); } static const VMStateDescription vmstate_ISAIPMIBTDevice = { diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c index 9a38f8a28..2742ce06c 100644 --- a/hw/ipmi/isa_ipmi_kcs.c +++ b/hw/ipmi/isa_ipmi_kcs.c @@ -354,6 +354,16 @@ static void ipmi_kcs_init(IPMIInterface *ii, Error **errp) memory_region_init_io(&ik->io, NULL, &ipmi_kcs_io_ops, ii, "ipmi-kcs", 2); } +static void ipmi_kcs_class_init(IPMIInterfaceClass *iic) +{ + iic->init = ipmi_kcs_init; + iic->set_atn = ipmi_kcs_set_atn; + iic->handle_rsp = ipmi_kcs_handle_rsp; + iic->handle_if_event = ipmi_kcs_handle_event; + iic->set_irq_enable = ipmi_kcs_set_irq_enable; +} + + #define TYPE_ISA_IPMI_KCS "isa-ipmi-kcs" #define ISA_IPMI_KCS(obj) OBJECT_CHECK(ISAIPMIKCSDevice, (obj), \ TYPE_ISA_IPMI_KCS) @@ -362,37 +372,9 @@ typedef struct ISAIPMIKCSDevice { ISADevice dev; int32_t isairq; IPMIKCS kcs; - uint32_t uuid; + IPMIFwInfo fwinfo; } ISAIPMIKCSDevice; -static void ipmi_kcs_get_fwinfo(IPMIInterface *ii, IPMIFwInfo *info) -{ - ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(ii); - - info->interface_name = "kcs"; - info->interface_type = IPMI_SMBIOS_KCS; - info->ipmi_spec_major_revision = 2; - info->ipmi_spec_minor_revision = 0; - info->base_address = iik->kcs.io_base; - info->i2c_slave_address = iik->kcs.bmc->slave_addr; - info->register_length = iik->kcs.io_length; - info->register_spacing = 1; - info->memspace = IPMI_MEMSPACE_IO; - info->irq_type = IPMI_LEVEL_IRQ; - info->interrupt_number = iik->isairq; - info->uuid = iik->uuid; -} - -static void ipmi_kcs_class_init(IPMIInterfaceClass *iic) -{ - iic->init = ipmi_kcs_init; - iic->set_atn = ipmi_kcs_set_atn; - iic->handle_rsp = ipmi_kcs_handle_rsp; - iic->handle_if_event = ipmi_kcs_handle_event; - iic->set_irq_enable = ipmi_kcs_set_irq_enable; - iic->get_fwinfo = ipmi_kcs_get_fwinfo; -} - static void ipmi_isa_realize(DeviceState *dev, Error **errp) { ISADevice *isadev = ISA_DEVICE(dev); @@ -405,8 +387,6 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp) return; } - iik->uuid = ipmi_next_uuid(); - iik->kcs.bmc->intf = ii; iic->init(ii, errp); @@ -421,6 +401,20 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp) qdev_set_legacy_instance_id(dev, iik->kcs.io_base, iik->kcs.io_length); isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base); + + iik->fwinfo.interface_name = "kcs"; + iik->fwinfo.interface_type = IPMI_SMBIOS_KCS; + iik->fwinfo.ipmi_spec_major_revision = 2; + iik->fwinfo.ipmi_spec_minor_revision = 0; + iik->fwinfo.base_address = iik->kcs.io_base; + iik->fwinfo.i2c_slave_address = iik->kcs.bmc->slave_addr; + iik->fwinfo.register_length = iik->kcs.io_length; + iik->fwinfo.register_spacing = 1; + iik->fwinfo.memspace = IPMI_MEMSPACE_IO; + iik->fwinfo.irq_type = IPMI_LEVEL_IRQ; + iik->fwinfo.interrupt_number = iik->isairq; + iik->fwinfo.acpi_parent = "\\_SB.PCI0.ISA"; + ipmi_add_fwinfo(&iik->fwinfo, errp); } const VMStateDescription vmstate_ISAIPMIKCSDevice = { diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index ce74db232..7aa115caf 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -97,13 +97,6 @@ void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq) dev->nirqs++; } -void isa_connect_gpio_out(ISADevice *isadev, int gpioirq, int isairq) -{ - qemu_irq irq; - isa_init_irq(isadev, &irq, isairq); - qdev_connect_gpio_out(DEVICE(isadev), gpioirq, irq); -} - void isa_bus_dma(ISABus *bus, IsaDma *dma8, IsaDma *dma16) { assert(bus && dma8 && dma16); diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 10d1ee8b9..99cd3ba9e 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -47,7 +47,8 @@ #include "hw/pci/pci_bus.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" -#include "qom/cpu.h" + +static int ich9_lpc_sci_irq(ICH9LPCState *lpc); /*****************************************************************************/ /* ICH9 LPC PCI to ISA bridge */ @@ -95,8 +96,8 @@ static void ich9_cc_update(ICH9LPCState *lpc) /* * D30: DMI2PCI bridge - * It is arbitrarily decided how INTx lines of PCI devices behind - * the bridge are connected to pirq lines. Our choice is PIRQ[E-H]. + * It is arbitrarily decided how INTx lines of PCI devicesbehind the bridge + * are connected to pirq lines. Our choice is PIRQ[E-H]. * INT[A-D] are connected to PIRQ[E-H] */ for (pci_intx = 0; pci_intx < PCI_NUM_PINS; pci_intx++) { @@ -202,28 +203,41 @@ static void ich9_lpc_pic_irq(ICH9LPCState *lpc, int pirq_num, abort(); } -/* gsi: i8259+ioapic irq 0-15, otherwise assert */ -static void ich9_lpc_update_pic(ICH9LPCState *lpc, int gsi) +/* pic_irq: i8254 irq 0-15 */ +static void ich9_lpc_update_pic(ICH9LPCState *lpc, int pic_irq) { int i, pic_level; - assert(gsi < ICH9_LPC_PIC_NUM_PINS); - /* The pic level is the logical OR of all the PCI irqs mapped to it */ pic_level = 0; for (i = 0; i < ICH9_LPC_NB_PIRQS; i++) { int tmp_irq; int tmp_dis; ich9_lpc_pic_irq(lpc, i, &tmp_irq, &tmp_dis); - if (!tmp_dis && tmp_irq == gsi) { + if (!tmp_dis && pic_irq == tmp_irq) { pic_level |= pci_bus_get_irq_level(lpc->d.bus, i); } } - if (gsi == lpc->sci_gsi) { + if (pic_irq == ich9_lpc_sci_irq(lpc)) { pic_level |= lpc->sci_level; } - qemu_set_irq(lpc->gsi[gsi], pic_level); + qemu_set_irq(lpc->pic[pic_irq], pic_level); +} + +/* pirq: pirq[A-H] 0-7*/ +static void ich9_lpc_update_by_pirq(ICH9LPCState *lpc, int pirq) +{ + int pic_irq; + int pic_dis; + + ich9_lpc_pic_irq(lpc, pirq, &pic_irq, &pic_dis); + assert(pic_irq < ICH9_LPC_PIC_NUM_PINS); + if (pic_dis) { + return; + } + + ich9_lpc_update_pic(lpc, pic_irq); } /* APIC mode: GSIx: PIRQ[A-H] -> GSI 16, ... no pirq shares same APIC pins. */ @@ -237,32 +251,29 @@ static int ich9_gsi_to_pirq(int gsi) return gsi - ICH9_LPC_PIC_NUM_PINS; } -/* gsi: ioapic irq 16-23, otherwise assert */ static void ich9_lpc_update_apic(ICH9LPCState *lpc, int gsi) { int level = 0; - assert(gsi >= ICH9_LPC_PIC_NUM_PINS); - - level |= pci_bus_get_irq_level(lpc->d.bus, ich9_gsi_to_pirq(gsi)); - if (gsi == lpc->sci_gsi) { + if (gsi >= ICH9_LPC_PIC_NUM_PINS) { + level |= pci_bus_get_irq_level(lpc->d.bus, ich9_gsi_to_pirq(gsi)); + } + if (gsi == ich9_lpc_sci_irq(lpc)) { level |= lpc->sci_level; } - qemu_set_irq(lpc->gsi[gsi], level); + qemu_set_irq(lpc->ioapic[gsi], level); } void ich9_lpc_set_irq(void *opaque, int pirq, int level) { ICH9LPCState *lpc = opaque; - int pic_irq, pic_dis; assert(0 <= pirq); assert(pirq < ICH9_LPC_NB_PIRQS); ich9_lpc_update_apic(lpc, ich9_pirq_to_gsi(pirq)); - ich9_lpc_pic_irq(lpc, pirq, &pic_irq, &pic_dis); - ich9_lpc_update_pic(lpc, pic_irq); + ich9_lpc_update_by_pirq(lpc, pirq); } /* return the pirq number (PIRQ[A-H]:0-7) corresponding to @@ -348,14 +359,13 @@ static void ich9_set_sci(void *opaque, int irq_num, int level) } lpc->sci_level = level; - irq = lpc->sci_gsi; + irq = ich9_lpc_sci_irq(lpc); if (irq < 0) { return; } - if (irq >= ICH9_LPC_PIC_NUM_PINS) { - ich9_lpc_update_apic(lpc, irq); - } else { + ich9_lpc_update_apic(lpc, irq); + if (irq < ICH9_LPC_PIC_NUM_PINS) { ich9_lpc_update_pic(lpc, irq); } } @@ -392,27 +402,12 @@ static void ich9_apm_ctrl_changed(uint32_t val, void *arg) /* config:PMBASE */ static void -ich9_lpc_pmbase_sci_update(ICH9LPCState *lpc) +ich9_lpc_pmbase_update(ICH9LPCState *lpc) { uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE); - uint8_t acpi_cntl = pci_get_long(lpc->d.config + ICH9_LPC_ACPI_CTRL); - uint8_t new_gsi; - - if (acpi_cntl & ICH9_LPC_ACPI_CTRL_ACPI_EN) { - pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK; - } else { - pm_io_base = 0; - } + pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK; ich9_pm_iospace_update(&lpc->pm, pm_io_base); - - new_gsi = ich9_lpc_sci_irq(lpc); - if (lpc->sci_level && new_gsi != lpc->sci_gsi) { - qemu_set_irq(lpc->pm.irq, 0); - lpc->sci_gsi = new_gsi; - qemu_set_irq(lpc->pm.irq, 1); - } - lpc->sci_gsi = new_gsi; } /* config:RCBA */ @@ -449,7 +444,7 @@ static int ich9_lpc_post_load(void *opaque, int version_id) { ICH9LPCState *lpc = opaque; - ich9_lpc_pmbase_sci_update(lpc); + ich9_lpc_pmbase_update(lpc); ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RCBA_EN */); ich9_lpc_pmcon_update(lpc); return 0; @@ -462,9 +457,8 @@ static void ich9_lpc_config_write(PCIDevice *d, uint32_t rcba_old = pci_get_long(d->config + ICH9_LPC_RCBA); pci_default_write_config(d, addr, val, len); - if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4) || - ranges_overlap(addr, len, ICH9_LPC_ACPI_CTRL, 1)) { - ich9_lpc_pmbase_sci_update(lpc); + if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4)) { + ich9_lpc_pmbase_update(lpc); } if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) { ich9_lpc_rcba_update(lpc, rcba_old); @@ -502,7 +496,7 @@ static void ich9_lpc_reset(DeviceState *qdev) ich9_cc_reset(lpc); - ich9_lpc_pmbase_sci_update(lpc); + ich9_lpc_pmbase_update(lpc); ich9_lpc_rcba_update(lpc, rcba_old); lpc->sci_level = 0; @@ -582,7 +576,7 @@ static void ich9_lpc_get_sci_int(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { ICH9LPCState *lpc = ICH9_LPC_DEVICE(obj); - uint32_t value = lpc->sci_gsi; + uint32_t value = ich9_lpc_sci_irq(lpc); visit_type_uint32(v, name, &value, errp); } @@ -613,7 +607,6 @@ static void ich9_lpc_initfn(Object *obj) static void ich9_lpc_realize(PCIDevice *d, Error **errp) { ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); - DeviceState *dev = DEVICE(d); ISABus *isa_bus; isa_bus = isa_bus_new(DEVICE(d), get_system_memory(), get_system_io(), @@ -624,9 +617,6 @@ static void ich9_lpc_realize(PCIDevice *d, Error **errp) pci_set_long(d->wmask + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_BASE_ADDRESS_MASK); - pci_set_byte(d->wmask + ICH9_LPC_PMBASE, - ICH9_LPC_ACPI_CTRL_ACPI_EN | - ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK); memory_region_init_io(&lpc->rcrb_mem, OBJECT(d), &rcrb_mmio_ops, lpc, "lpc-rcrb-mmio", ICH9_CC_SIZE); @@ -644,10 +634,30 @@ static void ich9_lpc_realize(PCIDevice *d, Error **errp) memory_region_add_subregion_overlap(pci_address_space_io(d), ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem, 1); +} + +static void ich9_device_plug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); + + ich9_pm_device_plug_cb(&lpc->pm, dev, errp); +} - qdev_init_gpio_out_named(dev, lpc->gsi, ICH9_GPIO_GSI, GSI_NUM_PINS); +static void ich9_device_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); + + ich9_pm_device_unplug_request_cb(&lpc->pm, dev, errp); +} + +static void ich9_device_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); - isa_bus_irqs(isa_bus, lpc->gsi); + ich9_pm_device_unplug_cb(&lpc->pm, dev, errp); } static bool ich9_rst_cnt_needed(void *opaque) @@ -692,13 +702,6 @@ static Property ich9_lpc_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void ich9_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) -{ - ICH9LPCState *s = ICH9_LPC_DEVICE(adev); - - acpi_send_gpe_event(&s->pm.acpi_regs, s->pm.irq, ev); -} - static void ich9_lpc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -722,12 +725,10 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) * pc_q35_init() */ dc->cannot_instantiate_with_device_add_yet = true; - hc->plug = ich9_pm_device_plug_cb; - hc->unplug_request = ich9_pm_device_unplug_request_cb; - hc->unplug = ich9_pm_device_unplug_cb; + hc->plug = ich9_device_plug_cb; + hc->unplug_request = ich9_device_unplug_request_cb; + hc->unplug = ich9_device_unplug_cb; adevc->ospm_status = ich9_pm_ospm_status; - adevc->send_event = ich9_send_gpe; - adevc->madt_cpu = pc_madt_cpu_entry; } static const TypeInfo ich9_lpc_info = { diff --git a/hw/isa/trace-events b/hw/isa/trace-events deleted file mode 100644 index 9faca41a9..000000000 --- a/hw/isa/trace-events +++ /dev/null @@ -1,9 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/isa/pc87312.c -pc87312_io_read(uint32_t addr, uint32_t val) "read addr=%x val=%x" -pc87312_io_write(uint32_t addr, uint32_t val) "write addr=%x val=%x" -pc87312_info_floppy(uint32_t base) "base 0x%x" -pc87312_info_ide(uint32_t base) "base 0x%x" -pc87312_info_parallel(uint32_t base, uint32_t irq) "base 0x%x, irq %u" -pc87312_info_serial(int n, uint32_t base, uint32_t irq) "id=%d, base 0x%x, irq %u" diff --git a/hw/lm32/lm32.h b/hw/lm32/lm32.h index db9eb29ea..18aa6fdc1 100644 --- a/hw/lm32/lm32.h +++ b/hw/lm32/lm32.h @@ -1,5 +1,5 @@ #ifndef HW_LM32_H -#define HW_LM32_H +#define HW_LM32_H 1 #include "hw/char/lm32_juart.h" @@ -16,31 +16,14 @@ static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq) return dev; } -static inline DeviceState *lm32_juart_init(CharDriverState *chr) +static inline DeviceState *lm32_juart_init(void) { DeviceState *dev; dev = qdev_create(NULL, TYPE_LM32_JUART); - qdev_prop_set_chr(dev, "chardev", chr); qdev_init_nofail(dev); return dev; } -static inline DeviceState *lm32_uart_create(hwaddr addr, - qemu_irq irq, - CharDriverState *chr) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_create(NULL, "lm32-uart"); - s = SYS_BUS_DEVICE(dev); - qdev_prop_set_chr(dev, "chardev", chr); - qdev_init_nofail(dev); - sysbus_mmio_map(s, 0, addr); - sysbus_connect_irq(s, 0, irq); - return dev; -} - #endif diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c index 8f0c3079d..c0290560f 100644 --- a/hw/lm32/lm32_boards.c +++ b/hw/lm32/lm32_boards.c @@ -31,7 +31,6 @@ #include "lm32_hwsetup.h" #include "lm32.h" #include "exec/address-spaces.h" -#include "sysemu/sysemu.h" typedef struct { LM32CPU *cpu; @@ -132,12 +131,12 @@ static void lm32_evr_init(MachineState *machine) irq[i] = qdev_get_gpio_in(env->pic_state, i); } - lm32_uart_create(uart0_base, irq[uart0_irq], serial_hds[0]); + sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]); sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(serial_hds[1]); + env->juart_state = lm32_juart_init(); reset_info->bootstrap_pc = flash_base; @@ -233,13 +232,13 @@ static void lm32_uclinux_init(MachineState *machine) irq[i] = qdev_get_gpio_in(env->pic_state, i); } - lm32_uart_create(uart0_base, irq[uart0_irq], serial_hds[0]); + sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]); sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]); /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(serial_hds[1]); + env->juart_state = lm32_juart_init(); reset_info->bootstrap_pc = flash_base; diff --git a/hw/lm32/milkymist-hw.h b/hw/lm32/milkymist-hw.h index 4418b44ca..c8dfb4d2d 100644 --- a/hw/lm32/milkymist-hw.h +++ b/hw/lm32/milkymist-hw.h @@ -1,17 +1,15 @@ -#ifndef QEMU_HW_MILKYMIST_HW_H -#define QEMU_HW_MILKYMIST_HW_H +#ifndef QEMU_HW_MILKYMIST_H +#define QEMU_HW_MILKYMIST_H #include "hw/qdev.h" #include "net/net.h" static inline DeviceState *milkymist_uart_create(hwaddr base, - qemu_irq irq, - CharDriverState *chr) + qemu_irq irq) { DeviceState *dev; dev = qdev_create(NULL, "milkymist-uart"); - qdev_prop_set_chr(dev, "chardev", chr); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); @@ -110,6 +108,10 @@ static inline DeviceState *milkymist_tmu2_create(hwaddr base, int nelements; int ver_major, ver_minor; + if (display_type == DT_NOGRAPHIC) { + return NULL; + } + /* check that GLX will work */ d = XOpenDisplay(NULL); if (d == NULL) { @@ -203,4 +205,4 @@ static inline DeviceState *milkymist_softusb_create(hwaddr base, return dev; } -#endif /* QEMU_HW_MILKYMIST_HW_H */ +#endif /* QEMU_HW_MILKYMIST_H */ diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c index 5cae0f19d..96e6f4dc2 100644 --- a/hw/lm32/milkymist.c +++ b/hw/lm32/milkymist.c @@ -159,7 +159,7 @@ milkymist_init(MachineState *machine) } g_free(bios_filename); - milkymist_uart_create(0x60000000, irq[0], serial_hds[0]); + milkymist_uart_create(0x60000000, irq[0]); milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3], 80000000, 0x10014d31, 0x0000041f, 0x00000001); milkymist_hpdmc_create(0x60002000); @@ -167,15 +167,13 @@ milkymist_init(MachineState *machine) milkymist_memcard_create(0x60004000); milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]); milkymist_pfpu_create(0x60006000, irq[8]); - if (machine->enable_graphics) { - milkymist_tmu2_create(0x60007000, irq[9]); - } + milkymist_tmu2_create(0x60007000, irq[9]); milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]); milkymist_softusb_create(0x6000f000, irq[15], 0x20000000, 0x1000, 0x20020000, 0x2000); /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(serial_hds[1]); + env->juart_state = lm32_juart_init(); if (kernel_filename) { uint64_t entry; diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index 7895805a2..0a602f28b 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -23,153 +23,20 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" -#include "qapi/visitor.h" #include "hw/mem/nvdimm.h" -static void nvdimm_get_label_size(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - NVDIMMDevice *nvdimm = NVDIMM(obj); - uint64_t value = nvdimm->label_size; - - visit_type_size(v, name, &value, errp); -} - -static void nvdimm_set_label_size(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - NVDIMMDevice *nvdimm = NVDIMM(obj); - Error *local_err = NULL; - uint64_t value; - - if (memory_region_size(&nvdimm->nvdimm_mr)) { - error_setg(&local_err, "cannot change property value"); - goto out; - } - - visit_type_size(v, name, &value, &local_err); - if (local_err) { - goto out; - } - if (value < MIN_NAMESPACE_LABEL_SIZE) { - error_setg(&local_err, "Property '%s.%s' (0x%" PRIx64 ") is required" - " at least 0x%lx", object_get_typename(obj), - name, value, MIN_NAMESPACE_LABEL_SIZE); - goto out; - } - - nvdimm->label_size = value; -out: - error_propagate(errp, local_err); -} - -static void nvdimm_init(Object *obj) -{ - object_property_add(obj, "label-size", "int", - nvdimm_get_label_size, nvdimm_set_label_size, NULL, - NULL, NULL); -} - -static MemoryRegion *nvdimm_get_memory_region(PCDIMMDevice *dimm) -{ - NVDIMMDevice *nvdimm = NVDIMM(dimm); - - return &nvdimm->nvdimm_mr; -} - -static void nvdimm_realize(PCDIMMDevice *dimm, Error **errp) -{ - MemoryRegion *mr = host_memory_backend_get_memory(dimm->hostmem, errp); - NVDIMMDevice *nvdimm = NVDIMM(dimm); - uint64_t align, pmem_size, size = memory_region_size(mr); - - align = memory_region_get_alignment(mr); - - pmem_size = size - nvdimm->label_size; - nvdimm->label_data = memory_region_get_ram_ptr(mr) + pmem_size; - pmem_size = QEMU_ALIGN_DOWN(pmem_size, align); - - if (size <= nvdimm->label_size || !pmem_size) { - HostMemoryBackend *hostmem = dimm->hostmem; - char *path = object_get_canonical_path_component(OBJECT(hostmem)); - - error_setg(errp, "the size of memdev %s (0x%" PRIx64 ") is too " - "small to contain nvdimm label (0x%" PRIx64 ") and " - "aligned PMEM (0x%" PRIx64 ")", - path, memory_region_size(mr), nvdimm->label_size, align); - g_free(path); - return; - } - - memory_region_init_alias(&nvdimm->nvdimm_mr, OBJECT(dimm), - "nvdimm-memory", mr, 0, pmem_size); - nvdimm->nvdimm_mr.align = align; -} - -/* - * the caller should check the input parameters before calling - * label read/write functions. - */ -static void nvdimm_validate_rw_label_data(NVDIMMDevice *nvdimm, uint64_t size, - uint64_t offset) -{ - assert((nvdimm->label_size >= size + offset) && (offset + size > offset)); -} - -static void nvdimm_read_label_data(NVDIMMDevice *nvdimm, void *buf, - uint64_t size, uint64_t offset) -{ - nvdimm_validate_rw_label_data(nvdimm, size, offset); - - memcpy(buf, nvdimm->label_data + offset, size); -} - -static void nvdimm_write_label_data(NVDIMMDevice *nvdimm, const void *buf, - uint64_t size, uint64_t offset) -{ - MemoryRegion *mr; - PCDIMMDevice *dimm = PC_DIMM(nvdimm); - uint64_t backend_offset; - - nvdimm_validate_rw_label_data(nvdimm, size, offset); - - memcpy(nvdimm->label_data + offset, buf, size); - - mr = host_memory_backend_get_memory(dimm->hostmem, &error_abort); - backend_offset = memory_region_size(mr) - nvdimm->label_size + offset; - memory_region_set_dirty(mr, backend_offset, size); -} - -static MemoryRegion *nvdimm_get_vmstate_memory_region(PCDIMMDevice *dimm) -{ - return host_memory_backend_get_memory(dimm->hostmem, &error_abort); -} - static void nvdimm_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc); - NVDIMMClass *nvc = NVDIMM_CLASS(oc); /* nvdimm hotplug has not been supported yet. */ dc->hotpluggable = false; - - ddc->realize = nvdimm_realize; - ddc->get_memory_region = nvdimm_get_memory_region; - ddc->get_vmstate_memory_region = nvdimm_get_vmstate_memory_region; - - nvc->read_label_data = nvdimm_read_label_data; - nvc->write_label_data = nvdimm_write_label_data; } static TypeInfo nvdimm_info = { .name = TYPE_NVDIMM, .parent = TYPE_PC_DIMM, - .class_size = sizeof(NVDIMMClass), .class_init = nvdimm_class_init, - .instance_size = sizeof(NVDIMMDevice), - .instance_init = nvdimm_init, }; static void nvdimm_register_types(void) diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 9e8dab0e8..9e7de5682 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -40,8 +40,6 @@ void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms, int slot; MachineState *machine = MACHINE(qdev_get_machine()); PCDIMMDevice *dimm = PC_DIMM(dev); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm); Error *local_err = NULL; uint64_t existing_dimms_capacity = 0; uint64_t addr; @@ -107,7 +105,7 @@ void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms, } memory_region_add_subregion(&hpms->mr, addr - hpms->base, mr); - vmstate_register_ram(vmstate_mr, dev); + vmstate_register_ram(mr, dev); numa_set_mem_node_id(addr, memory_region_size(mr), dimm->node); out: @@ -118,12 +116,10 @@ void pc_dimm_memory_unplug(DeviceState *dev, MemoryHotplugState *hpms, MemoryRegion *mr) { PCDIMMDevice *dimm = PC_DIMM(dev); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm); numa_unset_mem_node_id(dimm->addr, memory_region_size(mr), dimm->node); memory_region_del_subregion(&hpms->mr, mr); - vmstate_unregister_ram(vmstate_mr, dev); + vmstate_unregister_ram(mr, dev); } static int pc_existing_dimms_capacity_internal(Object *obj, void *opaque) @@ -358,9 +354,8 @@ static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name, int64_t value; MemoryRegion *mr; PCDIMMDevice *dimm = PC_DIMM(obj); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(obj); - mr = ddc->get_memory_region(dimm); + mr = host_memory_backend_get_memory(dimm->hostmem, errp); value = memory_region_size(mr); visit_type_int(v, name, &value, errp); @@ -369,9 +364,14 @@ static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name, static void pc_dimm_check_memdev_is_busy(Object *obj, const char *name, Object *val, Error **errp) { + MemoryRegion *mr; Error *local_err = NULL; - if (host_memory_backend_is_mapped(MEMORY_BACKEND(val))) { + mr = host_memory_backend_get_memory(MEMORY_BACKEND(val), &local_err); + if (local_err) { + goto out; + } + if (memory_region_is_mapped(mr)) { char *path = object_get_canonical_path_component(val); error_setg(&local_err, "can't use already busy memdev: %s", path); g_free(path); @@ -379,6 +379,7 @@ static void pc_dimm_check_memdev_is_busy(Object *obj, const char *name, qdev_prop_allow_set_link_before_realize(obj, name, val, &local_err); } +out: error_propagate(errp, local_err); } @@ -398,7 +399,6 @@ static void pc_dimm_init(Object *obj) static void pc_dimm_realize(DeviceState *dev, Error **errp) { PCDIMMDevice *dimm = PC_DIMM(dev); - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); if (!dimm->hostmem) { error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set"); @@ -411,19 +411,6 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp) dimm->node, nb_numa_nodes ? nb_numa_nodes : 1); return; } - - if (ddc->realize) { - ddc->realize(dimm, errp); - } - - host_memory_backend_set_mapped(dimm->hostmem, true); -} - -static void pc_dimm_unrealize(DeviceState *dev, Error **errp) -{ - PCDIMMDevice *dimm = PC_DIMM(dev); - - host_memory_backend_set_mapped(dimm->hostmem, false); } static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm) @@ -431,23 +418,16 @@ static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm) return host_memory_backend_get_memory(dimm->hostmem, &error_abort); } -static MemoryRegion *pc_dimm_get_vmstate_memory_region(PCDIMMDevice *dimm) -{ - return host_memory_backend_get_memory(dimm->hostmem, &error_abort); -} - static void pc_dimm_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc); dc->realize = pc_dimm_realize; - dc->unrealize = pc_dimm_unrealize; dc->props = pc_dimm_properties; dc->desc = "DIMM memory module"; ddc->get_memory_region = pc_dimm_get_memory_region; - ddc->get_vmstate_memory_region = pc_dimm_get_vmstate_memory_region; } static TypeInfo pc_dimm_info = { diff --git a/hw/microblaze/boot.h b/hw/microblaze/boot.h index dd1090d8b..0eb7f8e4f 100644 --- a/hw/microblaze/boot.h +++ b/hw/microblaze/boot.h @@ -1,5 +1,5 @@ -#ifndef MICROBLAZE_BOOT_H -#define MICROBLAZE_BOOT_H +#ifndef __MICROBLAZE_BOOT__ +#define __MICROBLAZE_BOOT__ #include "hw/hw.h" @@ -9,4 +9,4 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base, const char *dtb_filename, void (*machine_cpu_reset)(MicroBlazeCPU *)); -#endif /* MICROBLAZE_BOOT_H */ +#endif /* __MICROBLAZE_BOOT __ */ diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index 4968bdbb2..07527b677 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -191,16 +191,9 @@ petalogix_ml605_init(MachineState *machine) spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); for (i = 0; i < NUM_SPI_FLASHES; i++) { - DriveInfo *dinfo = drive_get_next(IF_MTD); qemu_irq cs_line; - dev = ssi_create_slave_no_init(spi, "n25q128"); - if (dinfo) { - qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); - } - qdev_init_nofail(dev); - + dev = ssi_create_slave(spi, "n25q128"); cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); sysbus_connect_irq(busdev, i+1, cs_line); } diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index 423bcd7f6..f821e1cfe 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -36,7 +36,6 @@ #include "hw/boards.h" #include "sysemu/block-backend.h" #include "exec/address-spaces.h" -#include "hw/char/xilinx_uartlite.h" #include "boot.h" @@ -104,8 +103,8 @@ petalogix_s3adsp1800_init(MachineState *machine) irq[i] = qdev_get_gpio_in(dev, i); } - xilinx_uartlite_create(UARTLITE_BASEADDR, irq[UARTLITE_IRQ], - serial_hds[0]); + sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR, + irq[UARTLITE_IRQ]); /* 2 timers at irq 2 @ 62 Mhz. */ dev = qdev_create(NULL, "xlnx.xps-timer"); diff --git a/hw/mips/cps.c b/hw/mips/cps.c index 4ef337d5c..1bafbbb27 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -26,8 +26,13 @@ qemu_irq get_cps_irq(MIPSCPSState *s, int pin_number) { + MIPSCPU *cpu = MIPS_CPU(first_cpu); + CPUMIPSState *env = &cpu->env; + assert(pin_number < s->num_irq); - return s->gic.irq_state[pin_number].irq; + + /* TODO: return GIC pins once implemented */ + return env->irq[pin_number]; } static void mips_cps_init(Object *obj) @@ -73,15 +78,14 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->num_vp; i++) { cpu = cpu_mips_init(s->cpu_model); if (cpu == NULL) { - error_setg(errp, "%s: CPU initialization failed", __func__); + error_setg(errp, "%s: CPU initialization failed\n", __func__); return; } + env = &cpu->env; /* Init internal devices */ - cpu_mips_irq_init_cpu(cpu); - cpu_mips_clock_init(cpu); - - env = &cpu->env; + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); if (cpu_mips_itu_supported(env)) { itu_present = true; /* Attach ITC Tag to the VP */ @@ -125,21 +129,6 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->container, 0, sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cpc), 0)); - /* Global Interrupt Controller */ - object_initialize(&s->gic, sizeof(s->gic), TYPE_MIPS_GIC); - qdev_set_parent_bus(DEVICE(&s->gic), sysbus_get_default()); - - object_property_set_int(OBJECT(&s->gic), s->num_vp, "num-vp", &err); - object_property_set_int(OBJECT(&s->gic), 128, "num-irq", &err); - object_property_set_bool(OBJECT(&s->gic), true, "realized", &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } - - memory_region_add_subregion(&s->container, 0, - sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gic), 0)); - /* Global Configuration Registers */ gcr_base = env->CP0_CMGCRBase << 4; @@ -149,7 +138,6 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) object_property_set_int(OBJECT(&s->gcr), s->num_vp, "num-vp", &err); object_property_set_int(OBJECT(&s->gcr), 0x800, "gcr-rev", &err); object_property_set_int(OBJECT(&s->gcr), gcr_base, "gcr-base", &err); - object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->gic.mr), "gic", &err); object_property_set_link(OBJECT(&s->gcr), OBJECT(&s->cpc.mr), "cpc", &err); object_property_set_bool(OBJECT(&s->gcr), true, "realized", &err); if (err != NULL) { @@ -163,7 +151,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp) static Property mips_cps_properties[] = { DEFINE_PROP_UINT32("num-vp", MIPSCPSState, num_vp, 1), - DEFINE_PROP_UINT32("num-irq", MIPSCPSState, num_irq, 256), + DEFINE_PROP_UINT32("num-irq", MIPSCPSState, num_irq, 8), DEFINE_PROP_STRING("cpu-model", MIPSCPSState, cpu_model), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/mips/cputimer.c b/hw/mips/cputimer.c index 8a166b3ea..efb227d06 100644 --- a/hw/mips/cputimer.c +++ b/hw/mips/cputimer.c @@ -151,10 +151,8 @@ static void mips_timer_cb (void *opaque) env->CP0_Count--; } -void cpu_mips_clock_init (MIPSCPU *cpu) +void cpu_mips_clock_init (CPUMIPSState *env) { - CPUMIPSState *env = &cpu->env; - /* * If we're in KVM mode, don't create the periodic timer, that is handled in * kernel. diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 4811843ab..3f4523df2 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -1167,6 +1167,7 @@ PCIBus *gt64120_register(qemu_irq *pic) DeviceState *dev; dev = qdev_create(NULL, TYPE_GT64120_PCI_HOST_BRIDGE); + qdev_init_nofail(dev); d = GT64120_PCI_HOST_BRIDGE(dev); phb = PCI_HOST_BRIDGE(dev); memory_region_init(&d->pci0_mem, OBJECT(dev), "pci0-mem", UINT32_MAX); @@ -1177,7 +1178,6 @@ PCIBus *gt64120_register(qemu_irq *pic) &d->pci0_mem, get_system_io(), PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS); - qdev_init_nofail(dev); memory_region_init_io(&d->ISD_mem, OBJECT(dev), &isd_mem_ops, d, "isd-mem", 0x1000); pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci"); diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 889cdc7ca..bdb716e72 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -334,8 +334,8 @@ static void mips_fulong2e_init(MachineState *machine) } /* Init internal devices */ - cpu_mips_irq_init_cpu(cpu); - cpu_mips_clock_init(cpu); + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); /* North bridge, Bonito --> IP2 */ pci_bus = bonito_init((qemu_irq *)&(env->irq[2])); diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index 48192d22f..59081f9d1 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -58,9 +58,8 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level) } } -void cpu_mips_irq_init_cpu(MIPSCPU *cpu) +void cpu_mips_irq_init_cpu(CPUMIPSState *env) { - CPUMIPSState *env = &cpu->env; qemu_irq *qi; int i; diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 73f6c9fac..ac7c64125 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -201,8 +201,8 @@ static void mips_jazz_init(MachineState *machine, } /* Init CPU internal devices */ - cpu_mips_irq_init_cpu(cpu); - cpu_mips_clock_init(cpu); + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); /* Chipset */ rc4030 = rc4030_init(&dmas, &rc4030_dma_mr); diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index e90857ee0..fa769e5c0 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -727,7 +727,7 @@ static void write_bootloader(uint8_t *base, int64_t run_addr, stl_p(p++, 0x00000000); /* nop */ stl_p(p++, 0x0ff0021c); /* jal 870 */ stl_p(p++, 0x00000000); /* nop */ - stl_p(p++, 0x1000fff9); /* b 814 */ + stl_p(p++, 0x08000205); /* j 814 */ stl_p(p++, 0x00000000); /* nop */ stl_p(p++, 0x01a00009); /* jalr t5 */ stl_p(p++, 0x01602021); /* move a0,t3 */ @@ -923,10 +923,11 @@ static void create_cpu_without_cps(const char *cpu_model, fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } + env = &cpu->env; /* Init internal devices */ - cpu_mips_irq_init_cpu(cpu); - cpu_mips_clock_init(cpu); + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); qemu_register_reset(main_cpu_reset, cpu); } @@ -955,7 +956,9 @@ static void create_cps(MaltaState *s, const char *cpu_model, sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1); - *i8259_irq = get_cps_irq(s->cps, 3); + /* FIXME: When GIC is present then we should use GIC's IRQ 3. + Until then CPS exposes CPU's IRQs thus use the default IRQ 2. */ + *i8259_irq = get_cps_irq(s->cps, 2); *cbus_irq = NULL; } diff --git a/hw/mips/mips_mipssim.c b/hw/mips/mips_mipssim.c index 1b9119500..a2c2a1646 100644 --- a/hw/mips/mips_mipssim.c +++ b/hw/mips/mips_mipssim.c @@ -216,8 +216,8 @@ mips_mipssim_init(MachineState *machine) } /* Init CPU internal devices. */ - cpu_mips_irq_init_cpu(cpu); - cpu_mips_clock_init(cpu); + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); /* Register 64 KB of ISA IO space at 0x1fd00000. */ memory_region_init_alias(isa, NULL, "isa_mmio", diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index 16a59c779..21aca981c 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -267,8 +267,8 @@ void mips_r4k_init(MachineState *machine) } /* Init CPU internal devices */ - cpu_mips_irq_init_cpu(cpu); - cpu_mips_clock_init(cpu); + cpu_mips_irq_init_cpu(env); + cpu_mips_clock_init(env); /* ISA bus: IO space at 0x14000000, mem space at 0x10000000 */ memory_region_init_alias(isa_io, NULL, "isa-io", diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 4cfbd1024..93f952880 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -29,7 +29,6 @@ obj-$(CONFIG_IMX) += imx_ccm.o obj-$(CONFIG_IMX) += imx31_ccm.o obj-$(CONFIG_IMX) += imx25_ccm.o obj-$(CONFIG_IMX) += imx6_ccm.o -obj-$(CONFIG_IMX) += imx6_src.o obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o obj-$(CONFIG_MAINSTONE) += mst_fpga.o @@ -51,5 +50,3 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_EDU) += edu.o obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o -obj-$(CONFIG_AUX) += auxbus.o -obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o diff --git a/hw/misc/arm11scu.c b/hw/misc/arm11scu.c index 7042ce11e..5e54b494b 100644 --- a/hw/misc/arm11scu.c +++ b/hw/misc/arm11scu.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "hw/misc/arm11scu.h" -#include "qemu/log.h" static uint64_t mpcore_scu_read(void *opaque, hwaddr offset, unsigned size) diff --git a/hw/misc/arm_integrator_debug.c b/hw/misc/arm_integrator_debug.c index 8a5f29559..902605fef 100644 --- a/hw/misc/arm_integrator_debug.c +++ b/hw/misc/arm_integrator_debug.c @@ -19,7 +19,6 @@ #include "hw/sysbus.h" #include "exec/address-spaces.h" #include "hw/misc/arm_integrator_debug.h" -#include "qemu/log.h" #define INTEGRATOR_DEBUG(obj) \ OBJECT_CHECK(IntegratorDebugState, (obj), TYPE_INTEGRATOR_DEBUG) diff --git a/hw/misc/arm_l2x0.c b/hw/misc/arm_l2x0.c index 66a0787c4..7e179f1a4 100644 --- a/hw/misc/arm_l2x0.c +++ b/hw/misc/arm_l2x0.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" -#include "qemu/log.h" /* L2C-310 r3p2 */ #define CACHE_ID 0x410000c8 @@ -159,14 +158,14 @@ static const MemoryRegionOps l2x0_mem_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void l2x0_priv_init(Object *obj) +static int l2x0_priv_init(SysBusDevice *dev) { - L2x0State *s = ARM_L2X0(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + L2x0State *s = ARM_L2X0(dev); - memory_region_init_io(&s->iomem, obj, &l2x0_mem_ops, s, + memory_region_init_io(&s->iomem, OBJECT(dev), &l2x0_mem_ops, s, "l2x0_cc", 0x1000); sysbus_init_mmio(dev, &s->iomem); + return 0; } static Property l2x0_properties[] = { @@ -176,8 +175,10 @@ static Property l2x0_properties[] = { static void l2x0_class_init(ObjectClass *klass, void *data) { + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); + k->init = l2x0_priv_init; dc->vmsd = &vmstate_l2x0; dc->props = l2x0_properties; dc->reset = l2x0_priv_reset; @@ -187,7 +188,6 @@ static const TypeInfo l2x0_info = { .name = TYPE_ARM_L2X0, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(L2x0State), - .instance_init = l2x0_priv_init, .class_init = l2x0_class_init, }; diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c index 852400870..34d90d523 100644 --- a/hw/misc/arm_sysctl.c +++ b/hw/misc/arm_sysctl.c @@ -14,7 +14,6 @@ #include "hw/sysbus.h" #include "hw/arm/primecell.h" #include "sysemu/sysemu.h" -#include "qemu/log.h" #define LOCK_VALUE 0xa05f diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c deleted file mode 100644 index c7e2c8263..000000000 --- a/hw/misc/aspeed_scu.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * ASPEED System Control Unit - * - * Andrew Jeffery <andrew@aj.id.au> - * - * Copyright 2016 IBM Corp. - * - * This code is licensed under the GPL version 2 or later. See - * the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/misc/aspeed_scu.h" -#include "hw/qdev-properties.h" -#include "qapi/error.h" -#include "qapi/visitor.h" -#include "qemu/bitops.h" -#include "qemu/log.h" -#include "trace.h" - -#define TO_REG(offset) ((offset) >> 2) - -#define PROT_KEY TO_REG(0x00) -#define SYS_RST_CTRL TO_REG(0x04) -#define CLK_SEL TO_REG(0x08) -#define CLK_STOP_CTRL TO_REG(0x0C) -#define FREQ_CNTR_CTRL TO_REG(0x10) -#define FREQ_CNTR_EVAL TO_REG(0x14) -#define IRQ_CTRL TO_REG(0x18) -#define D2PLL_PARAM TO_REG(0x1C) -#define MPLL_PARAM TO_REG(0x20) -#define HPLL_PARAM TO_REG(0x24) -#define FREQ_CNTR_RANGE TO_REG(0x28) -#define MISC_CTRL1 TO_REG(0x2C) -#define PCI_CTRL1 TO_REG(0x30) -#define PCI_CTRL2 TO_REG(0x34) -#define PCI_CTRL3 TO_REG(0x38) -#define SYS_RST_STATUS TO_REG(0x3C) -#define SOC_SCRATCH1 TO_REG(0x40) -#define SOC_SCRATCH2 TO_REG(0x44) -#define MAC_CLK_DELAY TO_REG(0x48) -#define MISC_CTRL2 TO_REG(0x4C) -#define VGA_SCRATCH1 TO_REG(0x50) -#define VGA_SCRATCH2 TO_REG(0x54) -#define VGA_SCRATCH3 TO_REG(0x58) -#define VGA_SCRATCH4 TO_REG(0x5C) -#define VGA_SCRATCH5 TO_REG(0x60) -#define VGA_SCRATCH6 TO_REG(0x64) -#define VGA_SCRATCH7 TO_REG(0x68) -#define VGA_SCRATCH8 TO_REG(0x6C) -#define HW_STRAP1 TO_REG(0x70) -#define RNG_CTRL TO_REG(0x74) -#define RNG_DATA TO_REG(0x78) -#define SILICON_REV TO_REG(0x7C) -#define PINMUX_CTRL1 TO_REG(0x80) -#define PINMUX_CTRL2 TO_REG(0x84) -#define PINMUX_CTRL3 TO_REG(0x88) -#define PINMUX_CTRL4 TO_REG(0x8C) -#define PINMUX_CTRL5 TO_REG(0x90) -#define PINMUX_CTRL6 TO_REG(0x94) -#define WDT_RST_CTRL TO_REG(0x9C) -#define PINMUX_CTRL7 TO_REG(0xA0) -#define PINMUX_CTRL8 TO_REG(0xA4) -#define PINMUX_CTRL9 TO_REG(0xA8) -#define WAKEUP_EN TO_REG(0xC0) -#define WAKEUP_CTRL TO_REG(0xC4) -#define HW_STRAP2 TO_REG(0xD0) -#define FREE_CNTR4 TO_REG(0xE0) -#define FREE_CNTR4_EXT TO_REG(0xE4) -#define CPU2_CTRL TO_REG(0x100) -#define CPU2_BASE_SEG1 TO_REG(0x104) -#define CPU2_BASE_SEG2 TO_REG(0x108) -#define CPU2_BASE_SEG3 TO_REG(0x10C) -#define CPU2_BASE_SEG4 TO_REG(0x110) -#define CPU2_BASE_SEG5 TO_REG(0x114) -#define CPU2_CACHE_CTRL TO_REG(0x118) -#define UART_HPLL_CLK TO_REG(0x160) -#define PCIE_CTRL TO_REG(0x180) -#define BMC_MMIO_CTRL TO_REG(0x184) -#define RELOC_DECODE_BASE1 TO_REG(0x188) -#define RELOC_DECODE_BASE2 TO_REG(0x18C) -#define MAILBOX_DECODE_BASE TO_REG(0x190) -#define SRAM_DECODE_BASE1 TO_REG(0x194) -#define SRAM_DECODE_BASE2 TO_REG(0x198) -#define BMC_REV TO_REG(0x19C) -#define BMC_DEV_ID TO_REG(0x1A4) - -#define PROT_KEY_UNLOCK 0x1688A8A8 -#define SCU_IO_REGION_SIZE 0x20000 - -static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = { - [SYS_RST_CTRL] = 0xFFCFFEDCU, - [CLK_SEL] = 0xF3F40000U, - [CLK_STOP_CTRL] = 0x19FC3E8BU, - [D2PLL_PARAM] = 0x00026108U, - [MPLL_PARAM] = 0x00030291U, - [HPLL_PARAM] = 0x00000291U, - [MISC_CTRL1] = 0x00000010U, - [PCI_CTRL1] = 0x20001A03U, - [PCI_CTRL2] = 0x20001A03U, - [PCI_CTRL3] = 0x04000030U, - [SYS_RST_STATUS] = 0x00000001U, - [SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */ - [MISC_CTRL2] = 0x00000023U, - [RNG_CTRL] = 0x0000000EU, - [PINMUX_CTRL2] = 0x0000F000U, - [PINMUX_CTRL3] = 0x01000000U, - [PINMUX_CTRL4] = 0x000000FFU, - [PINMUX_CTRL5] = 0x0000A000U, - [WDT_RST_CTRL] = 0x003FFFF3U, - [PINMUX_CTRL8] = 0xFFFF0000U, - [PINMUX_CTRL9] = 0x000FFFFFU, - [FREE_CNTR4] = 0x000000FFU, - [FREE_CNTR4_EXT] = 0x000000FFU, - [CPU2_BASE_SEG1] = 0x80000000U, - [CPU2_BASE_SEG4] = 0x1E600000U, - [CPU2_BASE_SEG5] = 0xC0000000U, - [UART_HPLL_CLK] = 0x00001903U, - [PCIE_CTRL] = 0x0000007BU, - [BMC_DEV_ID] = 0x00002402U -}; - -static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size) -{ - AspeedSCUState *s = ASPEED_SCU(opaque); - int reg = TO_REG(offset); - - if (reg >= ARRAY_SIZE(s->regs)) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - return 0; - } - - switch (reg) { - case WAKEUP_EN: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Read of write-only offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - break; - } - - return s->regs[reg]; -} - -static void aspeed_scu_write(void *opaque, hwaddr offset, uint64_t data, - unsigned size) -{ - AspeedSCUState *s = ASPEED_SCU(opaque); - int reg = TO_REG(offset); - - if (reg >= ARRAY_SIZE(s->regs)) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - return; - } - - if (reg > PROT_KEY && reg < CPU2_BASE_SEG1 && - s->regs[PROT_KEY] != PROT_KEY_UNLOCK) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__); - return; - } - - trace_aspeed_scu_write(offset, size, data); - - switch (reg) { - case FREQ_CNTR_EVAL: - case VGA_SCRATCH1 ... VGA_SCRATCH8: - case RNG_DATA: - case SILICON_REV: - case FREE_CNTR4: - case FREE_CNTR4_EXT: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - return; - } - - s->regs[reg] = data; -} - -static const MemoryRegionOps aspeed_scu_ops = { - .read = aspeed_scu_read, - .write = aspeed_scu_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid.min_access_size = 4, - .valid.max_access_size = 4, - .valid.unaligned = false, -}; - -static void aspeed_scu_reset(DeviceState *dev) -{ - AspeedSCUState *s = ASPEED_SCU(dev); - const uint32_t *reset; - - switch (s->silicon_rev) { - case AST2400_A0_SILICON_REV: - reset = ast2400_a0_resets; - break; - default: - g_assert_not_reached(); - } - - memcpy(s->regs, reset, sizeof(s->regs)); - s->regs[SILICON_REV] = s->silicon_rev; - s->regs[HW_STRAP1] = s->hw_strap1; - s->regs[HW_STRAP2] = s->hw_strap2; -} - -static uint32_t aspeed_silicon_revs[] = { AST2400_A0_SILICON_REV, }; - -bool is_supported_silicon_rev(uint32_t silicon_rev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(aspeed_silicon_revs); i++) { - if (silicon_rev == aspeed_silicon_revs[i]) { - return true; - } - } - - return false; -} - -static void aspeed_scu_realize(DeviceState *dev, Error **errp) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - AspeedSCUState *s = ASPEED_SCU(dev); - - if (!is_supported_silicon_rev(s->silicon_rev)) { - error_setg(errp, "Unknown silicon revision: 0x%" PRIx32, - s->silicon_rev); - return; - } - - memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_scu_ops, s, - TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE); - - sysbus_init_mmio(sbd, &s->iomem); -} - -static const VMStateDescription vmstate_aspeed_scu = { - .name = "aspeed.scu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_SCU_NR_REGS), - VMSTATE_END_OF_LIST() - } -}; - -static Property aspeed_scu_properties[] = { - DEFINE_PROP_UINT32("silicon-rev", AspeedSCUState, silicon_rev, 0), - DEFINE_PROP_UINT32("hw-strap1", AspeedSCUState, hw_strap1, 0), - DEFINE_PROP_UINT32("hw-strap2", AspeedSCUState, hw_strap2, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void aspeed_scu_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = aspeed_scu_realize; - dc->reset = aspeed_scu_reset; - dc->desc = "ASPEED System Control Unit"; - dc->vmsd = &vmstate_aspeed_scu; - dc->props = aspeed_scu_properties; -} - -static const TypeInfo aspeed_scu_info = { - .name = TYPE_ASPEED_SCU, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AspeedSCUState), - .class_init = aspeed_scu_class_init, -}; - -static void aspeed_scu_register_types(void) -{ - type_register_static(&aspeed_scu_info); -} - -type_init(aspeed_scu_register_types); diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c deleted file mode 100644 index e4a7ba41d..000000000 --- a/hw/misc/auxbus.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * auxbus.c - * - * Copyright 2015 : GreenSocs Ltd - * http://www.greensocs.com/ , email: info@greensocs.com - * - * Developed by : - * Frederic Konrad <fred.konrad@greensocs.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option)any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - * - */ - -/* - * This is an implementation of the AUX bus for VESA Display Port v1.1a. - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "hw/misc/auxbus.h" -#include "hw/i2c/i2c.h" -#include "monitor/monitor.h" - -#ifndef DEBUG_AUX -#define DEBUG_AUX 0 -#endif - -#define DPRINTF(fmt, ...) do { \ - if (DEBUG_AUX) { \ - qemu_log("aux: " fmt , ## __VA_ARGS__); \ - } \ -} while (0); - -#define TYPE_AUXTOI2C "aux-to-i2c-bridge" -#define AUXTOI2C(obj) OBJECT_CHECK(AUXTOI2CState, (obj), TYPE_AUXTOI2C) - -static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent); -static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge); - -/* aux-bus implementation (internal not public) */ -static void aux_bus_class_init(ObjectClass *klass, void *data) -{ - BusClass *k = BUS_CLASS(klass); - - /* AUXSlave has an MMIO so we need to change the way we print information - * in monitor. - */ - k->print_dev = aux_slave_dev_print; -} - -AUXBus *aux_init_bus(DeviceState *parent, const char *name) -{ - AUXBus *bus; - - bus = AUX_BUS(qbus_create(TYPE_AUX_BUS, parent, name)); - bus->bridge = AUXTOI2C(qdev_create(BUS(bus), TYPE_AUXTOI2C)); - - /* Memory related. */ - bus->aux_io = g_malloc(sizeof(*bus->aux_io)); - memory_region_init(bus->aux_io, OBJECT(bus), "aux-io", (1 << 20)); - address_space_init(&bus->aux_addr_space, bus->aux_io, "aux-io"); - return bus; -} - -static void aux_bus_map_device(AUXBus *bus, AUXSlave *dev, hwaddr addr) -{ - memory_region_add_subregion(bus->aux_io, addr, dev->mmio); -} - -static bool aux_bus_is_bridge(AUXBus *bus, DeviceState *dev) -{ - return (dev == DEVICE(bus->bridge)); -} - -I2CBus *aux_get_i2c_bus(AUXBus *bus) -{ - return aux_bridge_get_i2c_bus(bus->bridge); -} - -AUXReply aux_request(AUXBus *bus, AUXCommand cmd, uint32_t address, - uint8_t len, uint8_t *data) -{ - AUXReply ret = AUX_NACK; - I2CBus *i2c_bus = aux_get_i2c_bus(bus); - size_t i; - bool is_write = false; - - DPRINTF("request at address 0x%" PRIX32 ", command %u, len %u\n", address, - cmd, len); - - switch (cmd) { - /* - * Forward the request on the AUX bus.. - */ - case WRITE_AUX: - case READ_AUX: - is_write = cmd == READ_AUX ? false : true; - for (i = 0; i < len; i++) { - if (!address_space_rw(&bus->aux_addr_space, address++, - MEMTXATTRS_UNSPECIFIED, data++, 1, - is_write)) { - ret = AUX_I2C_ACK; - } else { - ret = AUX_NACK; - break; - } - } - break; - /* - * Classic I2C transactions.. - */ - case READ_I2C: - case WRITE_I2C: - is_write = cmd == READ_I2C ? false : true; - if (i2c_bus_busy(i2c_bus)) { - i2c_end_transfer(i2c_bus); - } - - if (i2c_start_transfer(i2c_bus, address, is_write)) { - ret = AUX_I2C_NACK; - break; - } - - ret = AUX_I2C_ACK; - while (len > 0) { - if (i2c_send_recv(i2c_bus, data++, is_write) < 0) { - ret = AUX_I2C_NACK; - break; - } - len--; - } - i2c_end_transfer(i2c_bus); - break; - /* - * I2C MOT transactions. - * - * Here we send a start when: - * - We didn't start transaction yet. - * - We had a READ and we do a WRITE. - * - We changed the address. - */ - case WRITE_I2C_MOT: - case READ_I2C_MOT: - is_write = cmd == READ_I2C_MOT ? false : true; - ret = AUX_I2C_NACK; - if (!i2c_bus_busy(i2c_bus)) { - /* - * No transactions started.. - */ - if (i2c_start_transfer(i2c_bus, address, is_write)) { - break; - } - } else if ((address != bus->last_i2c_address) || - (bus->last_transaction != cmd)) { - /* - * Transaction started but we need to restart.. - */ - i2c_end_transfer(i2c_bus); - if (i2c_start_transfer(i2c_bus, address, is_write)) { - break; - } - } - - bus->last_transaction = cmd; - bus->last_i2c_address = address; - while (len > 0) { - if (i2c_send_recv(i2c_bus, data++, is_write) < 0) { - i2c_end_transfer(i2c_bus); - break; - } - len--; - } - if (len == 0) { - ret = AUX_I2C_ACK; - } - break; - default: - DPRINTF("Not implemented!\n"); - return AUX_NACK; - } - - DPRINTF("reply: %u\n", ret); - return ret; -} - -static const TypeInfo aux_bus_info = { - .name = TYPE_AUX_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(AUXBus), - .class_init = aux_bus_class_init -}; - -/* aux-i2c implementation (internal not public) */ -struct AUXTOI2CState { - /*< private >*/ - DeviceState parent_obj; - - /*< public >*/ - I2CBus *i2c_bus; -}; - -static void aux_bridge_init(Object *obj) -{ - AUXTOI2CState *s = AUXTOI2C(obj); - - s->i2c_bus = i2c_init_bus(DEVICE(obj), "aux-i2c"); -} - -static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge) -{ - return bridge->i2c_bus; -} - -static const TypeInfo aux_to_i2c_type_info = { - .name = TYPE_AUXTOI2C, - .parent = TYPE_DEVICE, - .instance_size = sizeof(AUXTOI2CState), - .instance_init = aux_bridge_init -}; - -/* aux-slave implementation */ -static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent) -{ - AUXBus *bus = AUX_BUS(qdev_get_parent_bus(dev)); - AUXSlave *s; - - /* Don't print anything if the device is I2C "bridge". */ - if (aux_bus_is_bridge(bus, dev)) { - return; - } - - s = AUX_SLAVE(dev); - - monitor_printf(mon, "%*smemory " TARGET_FMT_plx "/" TARGET_FMT_plx "\n", - indent, "", - object_property_get_int(OBJECT(s->mmio), "addr", NULL), - memory_region_size(s->mmio)); -} - -DeviceState *aux_create_slave(AUXBus *bus, const char *type, uint32_t addr) -{ - DeviceState *dev; - - dev = DEVICE(object_new(type)); - assert(dev); - qdev_set_parent_bus(dev, &bus->qbus); - qdev_init_nofail(dev); - aux_bus_map_device(AUX_BUS(qdev_get_parent_bus(dev)), AUX_SLAVE(dev), addr); - return dev; -} - -void aux_init_mmio(AUXSlave *aux_slave, MemoryRegion *mmio) -{ - assert(!aux_slave->mmio); - aux_slave->mmio = mmio; -} - -static void aux_slave_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *k = DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_MISC, k->categories); - k->bus_type = TYPE_AUX_BUS; -} - -static const TypeInfo aux_slave_type_info = { - .name = TYPE_AUX_SLAVE, - .parent = TYPE_DEVICE, - .instance_size = sizeof(AUXSlave), - .abstract = true, - .class_init = aux_slave_class_init, -}; - -static void aux_register_types(void) -{ - type_register_static(&aux_bus_info); - type_register_static(&aux_slave_type_info); - type_register_static(&aux_to_i2c_type_info); -} - -type_init(aux_register_types) diff --git a/hw/misc/bcm2835_mbox.c b/hw/misc/bcm2835_mbox.c index e97cc814a..263280fd4 100644 --- a/hw/misc/bcm2835_mbox.c +++ b/hw/misc/bcm2835_mbox.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/misc/bcm2835_mbox.h" -#include "qemu/log.h" #define MAIL0_PEEK 0x90 #define MAIL0_SENDER 0x94 diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index 70eaafd32..530411f84 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -8,7 +8,6 @@ #include "hw/misc/bcm2835_property.h" #include "hw/misc/bcm2835_mbox_defs.h" #include "sysemu/dma.h" -#include "qemu/log.h" /* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ @@ -22,8 +21,6 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) int n; uint32_t offset, length, color; uint32_t xres, yres, xoffset, yoffset, bpp, pixo, alpha; - uint32_t tmp_xres, tmp_yres, tmp_xoffset, tmp_yoffset; - uint32_t tmp_bpp, tmp_pixo, tmp_alpha; uint32_t *newxres = NULL, *newyres = NULL, *newxoffset = NULL, *newyoffset = NULL, *newbpp = NULL, *newpixo = NULL, *newalpha = NULL; @@ -142,11 +139,7 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) case 0x00040001: /* Allocate buffer */ stl_le_phys(&s->dma_as, value + 12, s->fbdev->base); - tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres; - tmp_yres = newyres != NULL ? *newyres : s->fbdev->yres; - tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp; - stl_le_phys(&s->dma_as, value + 16, - tmp_xres * tmp_yres * tmp_bpp / 8); + stl_le_phys(&s->dma_as, value + 16, s->fbdev->size); resplen = 8; break; case 0x00048001: /* Release buffer */ @@ -157,10 +150,8 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) break; case 0x00040003: /* Get display width/height */ case 0x00040004: - tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres; - tmp_yres = newyres != NULL ? *newyres : s->fbdev->yres; - stl_le_phys(&s->dma_as, value + 12, tmp_xres); - stl_le_phys(&s->dma_as, value + 16, tmp_yres); + stl_le_phys(&s->dma_as, value + 12, s->fbdev->xres); + stl_le_phys(&s->dma_as, value + 16, s->fbdev->yres); resplen = 8; break; case 0x00044003: /* Test display width/height */ @@ -176,8 +167,7 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) resplen = 8; break; case 0x00040005: /* Get depth */ - tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp; - stl_le_phys(&s->dma_as, value + 12, tmp_bpp); + stl_le_phys(&s->dma_as, value + 12, s->fbdev->bpp); resplen = 4; break; case 0x00044005: /* Test depth */ @@ -189,8 +179,7 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) resplen = 4; break; case 0x00040006: /* Get pixel order */ - tmp_pixo = newpixo != NULL ? *newpixo : s->fbdev->pixo; - stl_le_phys(&s->dma_as, value + 12, tmp_pixo); + stl_le_phys(&s->dma_as, value + 12, s->fbdev->pixo); resplen = 4; break; case 0x00044006: /* Test pixel order */ @@ -202,8 +191,7 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) resplen = 4; break; case 0x00040007: /* Get alpha */ - tmp_alpha = newalpha != NULL ? *newalpha : s->fbdev->alpha; - stl_le_phys(&s->dma_as, value + 12, tmp_alpha); + stl_le_phys(&s->dma_as, value + 12, s->fbdev->alpha); resplen = 4; break; case 0x00044007: /* Test pixel alpha */ @@ -215,16 +203,12 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) resplen = 4; break; case 0x00040008: /* Get pitch */ - tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres; - tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp; - stl_le_phys(&s->dma_as, value + 12, tmp_xres * tmp_bpp / 8); + stl_le_phys(&s->dma_as, value + 12, s->fbdev->pitch); resplen = 4; break; case 0x00040009: /* Get virtual offset */ - tmp_xoffset = newxoffset != NULL ? *newxoffset : s->fbdev->xoffset; - tmp_yoffset = newyoffset != NULL ? *newyoffset : s->fbdev->yoffset; - stl_le_phys(&s->dma_as, value + 12, tmp_xoffset); - stl_le_phys(&s->dma_as, value + 16, tmp_yoffset); + stl_le_phys(&s->dma_as, value + 12, s->fbdev->xoffset); + stl_le_phys(&s->dma_as, value + 16, s->fbdev->yoffset); resplen = 8; break; case 0x00044009: /* Test virtual offset */ diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c index e30dbc7d3..889abadfe 100644 --- a/hw/misc/exynos4210_pmu.c +++ b/hw/misc/exynos4210_pmu.c @@ -457,15 +457,15 @@ static void exynos4210_pmu_reset(DeviceState *dev) } } -static void exynos4210_pmu_init(Object *obj) +static int exynos4210_pmu_init(SysBusDevice *dev) { - Exynos4210PmuState *s = EXYNOS4210_PMU(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + Exynos4210PmuState *s = EXYNOS4210_PMU(dev); /* memory mapping */ - memory_region_init_io(&s->iomem, obj, &exynos4210_pmu_ops, s, + memory_region_init_io(&s->iomem, OBJECT(dev), &exynos4210_pmu_ops, s, "exynos4210.pmu", EXYNOS4210_PMU_REGS_MEM_SIZE); sysbus_init_mmio(dev, &s->iomem); + return 0; } static const VMStateDescription exynos4210_pmu_vmstate = { @@ -481,7 +481,9 @@ static const VMStateDescription exynos4210_pmu_vmstate = { static void exynos4210_pmu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = exynos4210_pmu_init; dc->reset = exynos4210_pmu_reset; dc->vmsd = &exynos4210_pmu_vmstate; } @@ -490,7 +492,6 @@ static const TypeInfo exynos4210_pmu_info = { .name = TYPE_EXYNOS4210_PMU, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(Exynos4210PmuState), - .instance_init = exynos4210_pmu_init, .class_init = exynos4210_pmu_class_init, }; diff --git a/hw/misc/hyperv_testdev.c b/hw/misc/hyperv_testdev.c index 6cae9e901..1883fd7f2 100644 --- a/hw/misc/hyperv_testdev.c +++ b/hw/misc/hyperv_testdev.c @@ -12,11 +12,11 @@ */ #include "qemu/osdep.h" -#include <linux/kvm.h> #include "hw/hw.h" #include "hw/qdev.h" #include "hw/isa/isa.h" #include "sysemu/kvm.h" +#include "linux/kvm.h" #include "target-i386/hyperv.h" #include "kvm_i386.h" diff --git a/hw/misc/imx25_ccm.c b/hw/misc/imx25_ccm.c index 5cd8c0a9a..225604d82 100644 --- a/hw/misc/imx25_ccm.c +++ b/hw/misc/imx25_ccm.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "hw/misc/imx25_ccm.h" -#include "qemu/log.h" #ifndef DEBUG_IMX25_CCM #define DEBUG_IMX25_CCM 0 diff --git a/hw/misc/imx31_ccm.c b/hw/misc/imx31_ccm.c index 1c03e52c4..80c164716 100644 --- a/hw/misc/imx31_ccm.c +++ b/hw/misc/imx31_ccm.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "hw/misc/imx31_ccm.h" -#include "qemu/log.h" #define CKIH_FREQ 26000000 /* 26MHz crystal input */ diff --git a/hw/misc/imx6_ccm.c b/hw/misc/imx6_ccm.c index 17e15d4c9..4e1d49da6 100644 --- a/hw/misc/imx6_ccm.c +++ b/hw/misc/imx6_ccm.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "hw/misc/imx6_ccm.h" -#include "qemu/log.h" #ifndef DEBUG_IMX6_CCM #define DEBUG_IMX6_CCM 0 @@ -371,12 +370,6 @@ static uint32_t imx6_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) case CLK_32k: freq = CKIL_FREQ; break; - case CLK_HIGH: - freq = 24000000; - break; - case CLK_HIGH_DIV: - freq = 24000000 / 8; - break; default: qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n", TYPE_IMX6_CCM, __func__, clock); diff --git a/hw/misc/imx6_src.c b/hw/misc/imx6_src.c deleted file mode 100644 index 8bb682957..000000000 --- a/hw/misc/imx6_src.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * IMX6 System Reset Controller - * - * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net> - * - * 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/misc/imx6_src.h" -#include "sysemu/sysemu.h" -#include "qemu/bitops.h" -#include "qemu/log.h" -#include "arm-powerctl.h" - -#ifndef DEBUG_IMX6_SRC -#define DEBUG_IMX6_SRC 0 -#endif - -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX6_SRC) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX6_SRC, \ - __func__, ##args); \ - } \ - } while (0) - -static char const *imx6_src_reg_name(uint32_t reg) -{ - static char unknown[20]; - - switch (reg) { - case SRC_SCR: - return "SRC_SCR"; - case SRC_SBMR1: - return "SRC_SBMR1"; - case SRC_SRSR: - return "SRC_SRSR"; - case SRC_SISR: - return "SRC_SISR"; - case SRC_SIMR: - return "SRC_SIMR"; - case SRC_SBMR2: - return "SRC_SBMR2"; - case SRC_GPR1: - return "SRC_GPR1"; - case SRC_GPR2: - return "SRC_GPR2"; - case SRC_GPR3: - return "SRC_GPR3"; - case SRC_GPR4: - return "SRC_GPR4"; - case SRC_GPR5: - return "SRC_GPR5"; - case SRC_GPR6: - return "SRC_GPR6"; - case SRC_GPR7: - return "SRC_GPR7"; - case SRC_GPR8: - return "SRC_GPR8"; - case SRC_GPR9: - return "SRC_GPR9"; - case SRC_GPR10: - return "SRC_GPR10"; - default: - sprintf(unknown, "%d ?", reg); - return unknown; - } -} - -static const VMStateDescription vmstate_imx6_src = { - .name = TYPE_IMX6_SRC, - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, IMX6SRCState, SRC_MAX), - VMSTATE_END_OF_LIST() - }, -}; - -static void imx6_src_reset(DeviceState *dev) -{ - IMX6SRCState *s = IMX6_SRC(dev); - - DPRINTF("\n"); - - memset(s->regs, 0, sizeof(s->regs)); - - /* Set reset values */ - s->regs[SRC_SCR] = 0x521; - s->regs[SRC_SRSR] = 0x1; - s->regs[SRC_SIMR] = 0x1F; -} - -static uint64_t imx6_src_read(void *opaque, hwaddr offset, unsigned size) -{ - uint32_t value = 0; - IMX6SRCState *s = (IMX6SRCState *)opaque; - uint32_t index = offset >> 2; - - if (index < SRC_MAX) { - value = s->regs[index]; - } else { - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX6_SRC, __func__, offset); - - } - - DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx6_src_reg_name(index), value); - - return value; -} - -static void imx6_src_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - IMX6SRCState *s = (IMX6SRCState *)opaque; - uint32_t index = offset >> 2; - unsigned long change_mask; - unsigned long current_value = value; - - if (index >= SRC_MAX) { - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX6_SRC, __func__, offset); - return; - } - - DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx6_src_reg_name(index), - (uint32_t)current_value); - - change_mask = s->regs[index] ^ (uint32_t)current_value; - - switch (index) { - case SRC_SCR: - /* - * On real hardware when the system reset controller starts a - * secondary CPU it runs through some boot ROM code which reads - * the SRC_GPRX registers controlling the start address and branches - * to it. - * Here we are taking a short cut and branching directly to the - * requested address (we don't want to run the boot ROM code inside - * QEMU) - */ - if (EXTRACT(change_mask, CORE3_ENABLE)) { - if (EXTRACT(current_value, CORE3_ENABLE)) { - /* CORE 3 is brought up */ - arm_set_cpu_on(3, s->regs[SRC_GPR7], s->regs[SRC_GPR8], - 3, false); - } else { - /* CORE 3 is shut down */ - arm_set_cpu_off(3); - } - /* We clear the reset bits as the processor changed state */ - clear_bit(CORE3_RST_SHIFT, ¤t_value); - clear_bit(CORE3_RST_SHIFT, &change_mask); - } - if (EXTRACT(change_mask, CORE2_ENABLE)) { - if (EXTRACT(current_value, CORE2_ENABLE)) { - /* CORE 2 is brought up */ - arm_set_cpu_on(2, s->regs[SRC_GPR5], s->regs[SRC_GPR6], - 3, false); - } else { - /* CORE 3 is shut down */ - arm_set_cpu_off(2); - } - /* We clear the reset bits as the processor changed state */ - clear_bit(CORE2_RST_SHIFT, ¤t_value); - clear_bit(CORE2_RST_SHIFT, &change_mask); - } - if (EXTRACT(change_mask, CORE1_ENABLE)) { - if (EXTRACT(current_value, CORE1_ENABLE)) { - /* CORE 1 is brought up */ - arm_set_cpu_on(1, s->regs[SRC_GPR3], s->regs[SRC_GPR4], - 3, false); - } else { - /* CORE 3 is shut down */ - arm_set_cpu_off(1); - } - /* We clear the reset bits as the processor changed state */ - clear_bit(CORE1_RST_SHIFT, ¤t_value); - clear_bit(CORE1_RST_SHIFT, &change_mask); - } - if (EXTRACT(change_mask, CORE0_RST)) { - arm_reset_cpu(0); - clear_bit(CORE0_RST_SHIFT, ¤t_value); - } - if (EXTRACT(change_mask, CORE1_RST)) { - arm_reset_cpu(1); - clear_bit(CORE1_RST_SHIFT, ¤t_value); - } - if (EXTRACT(change_mask, CORE2_RST)) { - arm_reset_cpu(2); - clear_bit(CORE2_RST_SHIFT, ¤t_value); - } - if (EXTRACT(change_mask, CORE3_RST)) { - arm_reset_cpu(3); - clear_bit(CORE3_RST_SHIFT, ¤t_value); - } - if (EXTRACT(change_mask, SW_IPU2_RST)) { - /* We pretend the IPU2 is reset */ - clear_bit(SW_IPU2_RST_SHIFT, ¤t_value); - } - if (EXTRACT(change_mask, SW_IPU1_RST)) { - /* We pretend the IPU1 is reset */ - clear_bit(SW_IPU1_RST_SHIFT, ¤t_value); - } - s->regs[index] = current_value; - break; - default: - s->regs[index] = current_value; - break; - } -} - -static const struct MemoryRegionOps imx6_src_ops = { - .read = imx6_src_read, - .write = imx6_src_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - /* - * Our device would not work correctly if the guest was doing - * unaligned access. This might not be a limitation on the real - * device but in practice there is no reason for a guest to access - * this device unaligned. - */ - .min_access_size = 4, - .max_access_size = 4, - .unaligned = false, - }, -}; - -static void imx6_src_realize(DeviceState *dev, Error **errp) -{ - IMX6SRCState *s = IMX6_SRC(dev); - - memory_region_init_io(&s->iomem, OBJECT(dev), &imx6_src_ops, s, - TYPE_IMX6_SRC, 0x1000); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); -} - -static void imx6_src_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = imx6_src_realize; - dc->reset = imx6_src_reset; - dc->vmsd = &vmstate_imx6_src; - dc->desc = "i.MX6 System Reset Controller"; -} - -static const TypeInfo imx6_src_info = { - .name = TYPE_IMX6_SRC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IMX6SRCState), - .class_init = imx6_src_class_init, -}; - -static void imx6_src_register_types(void) -{ - type_register_static(&imx6_src_info); -} - -type_init(imx6_src_register_types) diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c index 7f239a41d..986d890ca 100644 --- a/hw/misc/imx_ccm.c +++ b/hw/misc/imx_ccm.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "hw/misc/imx_ccm.h" -#include "qemu/log.h" #ifndef DEBUG_IMX_CCM #define DEBUG_IMX_CCM 0 diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 40a2ebca2..e40f23bfc 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -33,9 +33,12 @@ #include "sysemu/hostmem.h" #include "sysemu/qtest.h" #include "qapi/visitor.h" +#include "exec/ram_addr.h" #include "hw/misc/ivshmem.h" +#include <sys/mman.h> + #define PCI_VENDOR_ID_IVSHMEM PCI_VENDOR_ID_REDHAT_QUMRANET #define PCI_DEVICE_ID_IVSHMEM 0x1110 @@ -322,7 +325,6 @@ static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector, if (ret < 0) { return ret; } - kvm_irqchip_commit_routes(kvm_state); return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, v->virq); } @@ -442,12 +444,13 @@ static void ivshmem_add_kvm_msi_virq(IVShmemState *s, int vector, Error **errp) { PCIDevice *pdev = PCI_DEVICE(s); + MSIMessage msg = msix_get_message(pdev, vector); int ret; IVSHMEM_DPRINTF("ivshmem_add_kvm_msi_virq vector:%d\n", vector); assert(!s->msi_vectors[vector].pdev); - ret = kvm_irqchip_add_msi_route(kvm_state, vector, pdev); + ret = kvm_irqchip_add_msi_route(kvm_state, msg, pdev); if (ret < 0) { error_setg(errp, "kvm_irqchip_add_msi_route failed"); return; @@ -530,7 +533,7 @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp) } memory_region_init_ram_ptr(&s->server_bar2, OBJECT(s), "ivshmem.bar2", size, ptr); - memory_region_set_fd(&s->server_bar2, fd); + qemu_set_ram_fd(memory_region_get_ram_addr(&s->server_bar2), fd); s->ivshmem_bar2 = &s->server_bar2; } @@ -937,7 +940,7 @@ static void ivshmem_exit(PCIDevice *dev) strerror(errno)); } - fd = memory_region_get_fd(s->ivshmem_bar2); + fd = qemu_get_ram_fd(memory_region_get_ram_addr(s->ivshmem_bar2)); close(fd); } @@ -1008,7 +1011,10 @@ static const TypeInfo ivshmem_common_info = { static void ivshmem_check_memdev_is_busy(Object *obj, const char *name, Object *val, Error **errp) { - if (host_memory_backend_is_mapped(MEMORY_BACKEND(val))) { + MemoryRegion *mr; + + mr = host_memory_backend_get_memory(MEMORY_BACKEND(val), &error_abort); + if (memory_region_is_mapped(mr)) { char *path = object_get_canonical_path_component(val); error_setg(errp, "can't use already busy memdev: %s", path); g_free(path); @@ -1057,14 +1063,6 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp) } ivshmem_common_realize(dev, errp); - host_memory_backend_set_mapped(s->hostmem, true); -} - -static void ivshmem_plain_exit(PCIDevice *pci_dev) -{ - IVShmemState *s = IVSHMEM_COMMON(pci_dev); - - host_memory_backend_set_mapped(s->hostmem, false); } static void ivshmem_plain_class_init(ObjectClass *klass, void *data) @@ -1073,7 +1071,6 @@ static void ivshmem_plain_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); k->realize = ivshmem_plain_realize; - k->exit = ivshmem_plain_exit; dc->props = ivshmem_plain_properties; dc->vmsd = &ivshmem_plain_vmsd; } diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 05c02fb3a..f15f30110 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -29,7 +29,6 @@ #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "qemu/cutils.h" -#include "qemu/log.h" /* XXX: implement all timer modes */ diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c index 15452b9a2..6051f17db 100644 --- a/hw/misc/macio/mac_dbdma.c +++ b/hw/misc/macio/mac_dbdma.c @@ -41,26 +41,16 @@ #include "hw/isa/isa.h" #include "hw/ppc/mac_dbdma.h" #include "qemu/main-loop.h" -#include "qemu/log.h" -#include "sysemu/dma.h" /* debug DBDMA */ -#define DEBUG_DBDMA 0 -#define DEBUG_DBDMA_CHANMASK ((1ull << DBDMA_CHANNELS) - 1) - -#define DBDMA_DPRINTF(fmt, ...) do { \ - if (DEBUG_DBDMA) { \ - printf("DBDMA: " fmt , ## __VA_ARGS__); \ - } \ -} while (0); - -#define DBDMA_DPRINTFCH(ch, fmt, ...) do { \ - if (DEBUG_DBDMA) { \ - if ((1ul << (ch)->channel) & DEBUG_DBDMA_CHANMASK) { \ - printf("DBDMA[%02x]: " fmt , (ch)->channel, ## __VA_ARGS__); \ - } \ - } \ -} while (0); +//#define DEBUG_DBDMA + +#ifdef DEBUG_DBDMA +#define DBDMA_DPRINTF(fmt, ...) \ + do { printf("DBDMA: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DBDMA_DPRINTF(fmt, ...) +#endif /* */ @@ -70,7 +60,7 @@ static DBDMAState *dbdma_from_ch(DBDMA_channel *ch) return container_of(ch, DBDMAState, channels[ch->channel]); } -#if DEBUG_DBDMA +#ifdef DEBUG_DBDMA static void dump_dbdma_cmd(dbdma_cmd *cmd) { printf("dbdma_cmd %p\n", cmd); @@ -88,26 +78,26 @@ static void dump_dbdma_cmd(dbdma_cmd *cmd) #endif static void dbdma_cmdptr_load(DBDMA_channel *ch) { - DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_load 0x%08x\n", - ch->regs[DBDMA_CMDPTR_LO]); - dma_memory_read(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO], - &ch->current, sizeof(dbdma_cmd)); + DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n", + ch->regs[DBDMA_CMDPTR_LO]); + cpu_physical_memory_read(ch->regs[DBDMA_CMDPTR_LO], + &ch->current, sizeof(dbdma_cmd)); } static void dbdma_cmdptr_save(DBDMA_channel *ch) { - DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_save 0x%08x\n", - ch->regs[DBDMA_CMDPTR_LO]); - DBDMA_DPRINTFCH(ch, "xfer_status 0x%08x res_count 0x%04x\n", - le16_to_cpu(ch->current.xfer_status), - le16_to_cpu(ch->current.res_count)); - dma_memory_write(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO], - &ch->current, sizeof(dbdma_cmd)); + DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n", + ch->regs[DBDMA_CMDPTR_LO]); + DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n", + le16_to_cpu(ch->current.xfer_status), + le16_to_cpu(ch->current.res_count)); + cpu_physical_memory_write(ch->regs[DBDMA_CMDPTR_LO], + &ch->current, sizeof(dbdma_cmd)); } static void kill_channel(DBDMA_channel *ch) { - DBDMA_DPRINTFCH(ch, "kill_channel\n"); + DBDMA_DPRINTF("kill_channel\n"); ch->regs[DBDMA_STATUS] |= DEAD; ch->regs[DBDMA_STATUS] &= ~ACTIVE; @@ -123,7 +113,7 @@ static void conditional_interrupt(DBDMA_channel *ch) uint32_t status; int cond; - DBDMA_DPRINTFCH(ch, "%s\n", __func__); + DBDMA_DPRINTF("%s\n", __func__); intr = le16_to_cpu(current->command) & INTR_MASK; @@ -132,7 +122,7 @@ static void conditional_interrupt(DBDMA_channel *ch) return; case INTR_ALWAYS: /* always interrupt */ qemu_irq_raise(ch->irq); - DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__); + DBDMA_DPRINTF("%s: raise\n", __func__); return; } @@ -147,13 +137,13 @@ static void conditional_interrupt(DBDMA_channel *ch) case INTR_IFSET: /* intr if condition bit is 1 */ if (cond) { qemu_irq_raise(ch->irq); - DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__); + DBDMA_DPRINTF("%s: raise\n", __func__); } return; case INTR_IFCLR: /* intr if condition bit is 0 */ if (!cond) { qemu_irq_raise(ch->irq); - DBDMA_DPRINTFCH(ch, "%s: raise\n", __func__); + DBDMA_DPRINTF("%s: raise\n", __func__); } return; } @@ -167,7 +157,7 @@ static int conditional_wait(DBDMA_channel *ch) uint32_t status; int cond; - DBDMA_DPRINTFCH(ch, "conditional_wait\n"); + DBDMA_DPRINTF("conditional_wait\n"); wait = le16_to_cpu(current->command) & WAIT_MASK; @@ -213,7 +203,7 @@ static void branch(DBDMA_channel *ch) { dbdma_cmd *current = &ch->current; - ch->regs[DBDMA_CMDPTR_LO] = le32_to_cpu(current->cmd_dep); + ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep; ch->regs[DBDMA_STATUS] |= BT; dbdma_cmdptr_load(ch); } @@ -226,7 +216,7 @@ static void conditional_branch(DBDMA_channel *ch) uint32_t status; int cond; - DBDMA_DPRINTFCH(ch, "conditional_branch\n"); + DBDMA_DPRINTF("conditional_branch\n"); /* check if we must branch */ @@ -271,7 +261,7 @@ static void dbdma_end(DBDMA_io *io) DBDMA_channel *ch = io->channel; dbdma_cmd *current = &ch->current; - DBDMA_DPRINTFCH(ch, "%s\n", __func__); + DBDMA_DPRINTF("%s\n", __func__); if (conditional_wait(ch)) goto wait; @@ -297,13 +287,13 @@ wait: static void start_output(DBDMA_channel *ch, int key, uint32_t addr, uint16_t req_count, int is_last) { - DBDMA_DPRINTFCH(ch, "start_output\n"); + DBDMA_DPRINTF("start_output\n"); /* KEY_REGS, KEY_DEVICE and KEY_STREAM * are not implemented in the mac-io chip */ - DBDMA_DPRINTFCH(ch, "addr 0x%x key 0x%x\n", addr, key); + DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key); if (!addr || key > KEY_STREAM3) { kill_channel(ch); return; @@ -323,13 +313,13 @@ static void start_output(DBDMA_channel *ch, int key, uint32_t addr, static void start_input(DBDMA_channel *ch, int key, uint32_t addr, uint16_t req_count, int is_last) { - DBDMA_DPRINTFCH(ch, "start_input\n"); + DBDMA_DPRINTF("start_input\n"); /* KEY_REGS, KEY_DEVICE and KEY_STREAM * are not implemented in the mac-io chip */ - DBDMA_DPRINTFCH(ch, "addr 0x%x key 0x%x\n", addr, key); + DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key); if (!addr || key > KEY_STREAM3) { kill_channel(ch); return; @@ -350,8 +340,9 @@ static void load_word(DBDMA_channel *ch, int key, uint32_t addr, uint16_t len) { dbdma_cmd *current = &ch->current; + uint32_t val; - DBDMA_DPRINTFCH(ch, "load_word %d bytes, addr=%08x\n", len, addr); + DBDMA_DPRINTF("load_word\n"); /* only implements KEY_SYSTEM */ @@ -361,7 +352,14 @@ static void load_word(DBDMA_channel *ch, int key, uint32_t addr, return; } - dma_memory_read(&address_space_memory, addr, ¤t->cmd_dep, len); + cpu_physical_memory_read(addr, &val, len); + + if (len == 2) + val = (val << 16) | (current->cmd_dep & 0x0000ffff); + else if (len == 1) + val = (val << 24) | (current->cmd_dep & 0x00ffffff); + + current->cmd_dep = val; if (conditional_wait(ch)) goto wait; @@ -381,9 +379,9 @@ static void store_word(DBDMA_channel *ch, int key, uint32_t addr, uint16_t len) { dbdma_cmd *current = &ch->current; + uint32_t val; - DBDMA_DPRINTFCH(ch, "store_word %d bytes, addr=%08x pa=%x\n", - len, addr, le32_to_cpu(current->cmd_dep)); + DBDMA_DPRINTF("store_word\n"); /* only implements KEY_SYSTEM */ @@ -393,7 +391,13 @@ static void store_word(DBDMA_channel *ch, int key, uint32_t addr, return; } - dma_memory_write(&address_space_memory, addr, ¤t->cmd_dep, len); + val = current->cmd_dep; + if (len == 2) + val >>= 16; + else if (len == 1) + val >>= 24; + + cpu_physical_memory_write(addr, &val, len); if (conditional_wait(ch)) goto wait; @@ -440,7 +444,7 @@ static void channel_run(DBDMA_channel *ch) uint16_t req_count; uint32_t phy_addr; - DBDMA_DPRINTFCH(ch, "channel_run\n"); + DBDMA_DPRINTF("channel_run\n"); dump_dbdma_cmd(current); /* clear WAKE flag at command fetch */ @@ -534,9 +538,9 @@ static void DBDMA_run_bh(void *opaque) { DBDMAState *s = opaque; - DBDMA_DPRINTF("-> DBDMA_run_bh\n"); + DBDMA_DPRINTF("DBDMA_run_bh\n"); + DBDMA_run(s); - DBDMA_DPRINTF("<- DBDMA_run_bh\n"); } void DBDMA_kick(DBDMAState *dbdma) @@ -551,7 +555,7 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, DBDMAState *s = dbdma; DBDMA_channel *ch = &s->channels[nchan]; - DBDMA_DPRINTFCH(ch, "DBDMA_register_channel 0x%x\n", nchan); + DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan); assert(rw); assert(flush); @@ -595,7 +599,7 @@ dbdma_control_write(DBDMA_channel *ch) status &= ~FLUSH; } - DBDMA_DPRINTFCH(ch, " status 0x%08x\n", status); + DBDMA_DPRINTF(" status 0x%08x\n", status); ch->regs[DBDMA_STATUS] = status; @@ -612,10 +616,10 @@ static void dbdma_write(void *opaque, hwaddr addr, DBDMA_channel *ch = &s->channels[channel]; int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; - DBDMA_DPRINTFCH(ch, "writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n", - addr, value); - DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n", - (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); + DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n", + addr, value); + DBDMA_DPRINTF("channel 0x%x reg 0x%x\n", + (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); /* cmdptr cannot be modified if channel is ACTIVE */ @@ -666,9 +670,9 @@ static uint64_t dbdma_read(void *opaque, hwaddr addr, value = ch->regs[reg]; - DBDMA_DPRINTFCH(ch, "readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value); - DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n", - (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); + DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value); + DBDMA_DPRINTF("channel 0x%x reg 0x%x\n", + (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); switch(reg) { case DBDMA_CONTROL: @@ -778,24 +782,13 @@ static void dbdma_unassigned_rw(DBDMA_io *io) DBDMA_channel *ch = io->channel; qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n", __func__, ch->channel); - ch->io.processing = false; } static void dbdma_unassigned_flush(DBDMA_io *io) { DBDMA_channel *ch = io->channel; - dbdma_cmd *current = &ch->current; - uint16_t cmd; qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n", __func__, ch->channel); - - cmd = le16_to_cpu(current->command) & COMMAND_MASK; - if (cmd == OUTPUT_MORE || cmd == OUTPUT_LAST || - cmd == INPUT_MORE || cmd == INPUT_LAST) { - current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS] | FLUSH); - current->res_count = cpu_to_le16(io->len); - dbdma_cmdptr_save(ch); - } } void* DBDMA_init (MemoryRegion **dbdma_mem) diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c index 2a277bdb8..9014f0f70 100644 --- a/hw/misc/max111x.c +++ b/hw/misc/max111x.c @@ -147,14 +147,14 @@ static int max111x_init(SSISlave *d, int inputs) return 0; } -static void max1110_realize(SSISlave *dev, Error **errp) +static int max1110_init(SSISlave *dev) { - max111x_init(dev, 8); + return max111x_init(dev, 8); } -static void max1111_realize(SSISlave *dev, Error **errp) +static int max1111_init(SSISlave *dev) { - max111x_init(dev, 4); + return max111x_init(dev, 4); } void max111x_set_input(DeviceState *dev, int line, uint8_t value) @@ -183,7 +183,7 @@ static void max1110_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->realize = max1110_realize; + k->init = max1110_init; } static const TypeInfo max1110_info = { @@ -196,7 +196,7 @@ static void max1111_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->realize = max1111_realize; + k->init = max1111_init; } static const TypeInfo max1111_info = { diff --git a/hw/misc/milkymist-hpdmc.c b/hw/misc/milkymist-hpdmc.c index e6140eec6..b97000fc4 100644 --- a/hw/misc/milkymist-hpdmc.c +++ b/hw/misc/milkymist-hpdmc.c @@ -18,7 +18,7 @@ * * * Specification available at: - * http://milkymist.walle.cc/socdoc/hpdmc.pdf + * http://www.milkymist.org/socdoc/hpdmc.pdf */ #include "qemu/osdep.h" diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c index 1da21a643..57acd7b36 100644 --- a/hw/misc/milkymist-pfpu.c +++ b/hw/misc/milkymist-pfpu.c @@ -18,7 +18,7 @@ * * * Specification available at: - * http://milkymist.walle.cc/socdoc/pfpu.pdf + * http://www.milkymist.org/socdoc/pfpu.pdf * */ diff --git a/hw/misc/mips_cmgcr.c b/hw/misc/mips_cmgcr.c index b3ba16694..37be23995 100644 --- a/hw/misc/mips_cmgcr.c +++ b/hw/misc/mips_cmgcr.c @@ -11,24 +11,17 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu/log.h" #include "hw/hw.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "hw/misc/mips_cmgcr.h" #include "hw/misc/mips_cpc.h" -#include "hw/intc/mips_gic.h" static inline bool is_cpc_connected(MIPSGCRState *s) { return s->cpc_mr != NULL; } -static inline bool is_gic_connected(MIPSGCRState *s) -{ - return s->gic_mr != NULL; -} - static inline void update_cpc_base(MIPSGCRState *gcr, uint64_t val) { if (is_cpc_connected(gcr)) { @@ -42,25 +35,10 @@ static inline void update_cpc_base(MIPSGCRState *gcr, uint64_t val) } } -static inline void update_gic_base(MIPSGCRState *gcr, uint64_t val) -{ - if (is_gic_connected(gcr)) { - gcr->gic_base = val & GCR_GIC_BASE_MSK; - memory_region_transaction_begin(); - memory_region_set_address(gcr->gic_mr, - gcr->gic_base & GCR_GIC_BASE_GICBASE_MSK); - memory_region_set_enabled(gcr->gic_mr, - gcr->gic_base & GCR_GIC_BASE_GICEN_MSK); - memory_region_transaction_commit(); - } -} - /* Read GCR registers */ static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size) { MIPSGCRState *gcr = (MIPSGCRState *) opaque; - MIPSGCRVPState *current_vps = &gcr->vps[current_cpu->cpu_index]; - MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other]; switch (addr) { /* Global Control Block Register */ @@ -71,12 +49,8 @@ static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size) return gcr->gcr_base; case GCR_REV_OFS: return gcr->gcr_rev; - case GCR_GIC_BASE_OFS: - return gcr->gic_base; case GCR_CPC_BASE_OFS: return gcr->cpc_base; - case GCR_GIC_STATUS_OFS: - return is_gic_connected(gcr); case GCR_CPC_STATUS_OFS: return is_cpc_connected(gcr); case GCR_L2_CONFIG_OFS: @@ -87,14 +61,8 @@ static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size) case MIPS_COCB_OFS + GCR_CL_CONFIG_OFS: /* Set PVP to # of VPs - 1 */ return gcr->num_vps - 1; - case MIPS_CLCB_OFS + GCR_CL_RESETBASE_OFS: - return current_vps->reset_base; - case MIPS_COCB_OFS + GCR_CL_RESETBASE_OFS: - return other_vps->reset_base; case MIPS_CLCB_OFS + GCR_CL_OTHER_OFS: - return current_vps->other; - case MIPS_COCB_OFS + GCR_CL_OTHER_OFS: - return other_vps->other; + return 0; default: qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx "\n", size, addr); @@ -103,46 +71,15 @@ static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size) return 0; } -static inline target_ulong get_exception_base(MIPSGCRVPState *vps) -{ - /* TODO: BEV_BASE and SELECT_BEV */ - return (int32_t)(vps->reset_base & GCR_CL_RESET_BASE_RESETBASE_MSK); -} - /* Write GCR registers */ static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { MIPSGCRState *gcr = (MIPSGCRState *)opaque; - MIPSGCRVPState *current_vps = &gcr->vps[current_cpu->cpu_index]; - MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other]; switch (addr) { - case GCR_GIC_BASE_OFS: - update_gic_base(gcr, data); - break; case GCR_CPC_BASE_OFS: update_cpc_base(gcr, data); break; - case MIPS_CLCB_OFS + GCR_CL_RESETBASE_OFS: - current_vps->reset_base = data & GCR_CL_RESET_BASE_MSK; - cpu_set_exception_base(current_cpu->cpu_index, - get_exception_base(current_vps)); - break; - case MIPS_COCB_OFS + GCR_CL_RESETBASE_OFS: - other_vps->reset_base = data & GCR_CL_RESET_BASE_MSK; - cpu_set_exception_base(current_vps->other, - get_exception_base(other_vps)); - break; - case MIPS_CLCB_OFS + GCR_CL_OTHER_OFS: - if ((data & GCR_CL_OTHER_MSK) < gcr->num_vps) { - current_vps->other = data & GCR_CL_OTHER_MSK; - } - break; - case MIPS_COCB_OFS + GCR_CL_OTHER_OFS: - if ((data & GCR_CL_OTHER_MSK) < gcr->num_vps) { - other_vps->other = data & GCR_CL_OTHER_MSK; - } - break; default: qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx " 0x%" PRIx64 "\n", size, addr, data); @@ -164,12 +101,6 @@ static void mips_gcr_init(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); MIPSGCRState *s = MIPS_GCR(obj); - object_property_add_link(obj, "gic", TYPE_MEMORY_REGION, - (Object **)&s->gic_mr, - qdev_prop_allow_set_link_before_realize, - OBJ_PROP_LINK_UNREF_ON_RELEASE, - &error_abort); - object_property_add_link(obj, "cpc", TYPE_MEMORY_REGION, (Object **)&s->cpc_mr, qdev_prop_allow_set_link_before_realize, @@ -184,16 +115,8 @@ static void mips_gcr_init(Object *obj) static void mips_gcr_reset(DeviceState *dev) { MIPSGCRState *s = MIPS_GCR(dev); - int i; - update_gic_base(s, 0); update_cpc_base(s, 0); - - for (i = 0; i < s->num_vps; i++) { - s->vps[i].other = 0; - s->vps[i].reset_base = 0xBFC00000 & GCR_CL_RESET_BASE_MSK; - cpu_set_exception_base(i, get_exception_base(&s->vps[i])); - } } static const VMStateDescription vmstate_mips_gcr = { @@ -213,21 +136,12 @@ static Property mips_gcr_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void mips_gcr_realize(DeviceState *dev, Error **errp) -{ - MIPSGCRState *s = MIPS_GCR(dev); - - /* Create local set of registers for each VP */ - s->vps = g_new(MIPSGCRVPState, s->num_vps); -} - static void mips_gcr_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->props = mips_gcr_properties; dc->vmsd = &vmstate_mips_gcr; dc->reset = mips_gcr_reset; - dc->realize = mips_gcr_realize; } static const TypeInfo mips_gcr_info = { diff --git a/hw/misc/mips_cpc.c b/hw/misc/mips_cpc.c index 6d345745f..d2b8e42da 100644 --- a/hw/misc/mips_cpc.c +++ b/hw/misc/mips_cpc.c @@ -19,8 +19,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" -#include "qemu/log.h" #include "hw/sysbus.h" #include "hw/misc/mips_cpc.h" @@ -37,7 +35,7 @@ static void cpc_run_vp(MIPSCPCState *cpc, uint64_t vp_run) CPU_FOREACH(cs) { uint64_t i = 1ULL << cs->cpu_index; if (i & vp_run & ~cpc->vp_running) { - cpu_reset(cs); + cpu_interrupt(cs, CPU_INTERRUPT_WAKE); cpc->vp_running |= i; } } @@ -50,7 +48,8 @@ static void cpc_stop_vp(MIPSCPCState *cpc, uint64_t vp_stop) CPU_FOREACH(cs) { uint64_t i = 1ULL << cs->cpu_index; if (i & vp_stop & cpc->vp_running) { - cpu_interrupt(cs, CPU_INTERRUPT_HALT); + cs->halted = 1; + cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); cpc->vp_running &= ~i; } } diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c index ef935b51a..da5455062 100644 --- a/hw/misc/mips_itu.c +++ b/hw/misc/mips_itu.c @@ -19,9 +19,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" -#include "qemu/log.h" -#include "exec/exec-all.h" #include "hw/hw.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c index a10f0496f..48d7dfb2d 100644 --- a/hw/misc/mst_fpga.c +++ b/hw/misc/mst_fpga.c @@ -200,11 +200,10 @@ static int mst_fpga_post_load(void *opaque, int version_id) return 0; } -static void mst_fpga_init(Object *obj) +static int mst_fpga_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - mst_irq_state *s = MAINSTONE_FPGA(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + mst_irq_state *s = MAINSTONE_FPGA(dev); s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD; s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD; @@ -214,9 +213,10 @@ static void mst_fpga_init(Object *obj) /* alloc the external 16 irqs */ qdev_init_gpio_in(dev, mst_fpga_set_irq, MST_NUM_IRQS); - memory_region_init_io(&s->iomem, obj, &mst_fpga_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &mst_fpga_ops, s, "fpga", 0x00100000); sysbus_init_mmio(sbd, &s->iomem); + return 0; } static VMStateDescription vmstate_mst_fpga_regs = { @@ -245,7 +245,9 @@ static VMStateDescription vmstate_mst_fpga_regs = { static void mst_fpga_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + k->init = mst_fpga_init; dc->desc = "Mainstone II FPGA"; dc->vmsd = &vmstate_mst_fpga_regs; } @@ -254,7 +256,6 @@ static const TypeInfo mst_fpga_info = { .name = TYPE_MAINSTONE_FPGA, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(mst_irq_state), - .instance_init = mst_fpga_init, .class_init = mst_fpga_class_init, }; diff --git a/hw/misc/pc-testdev.c b/hw/misc/pc-testdev.c index b81d82008..086893dcc 100644 --- a/hw/misc/pc-testdev.c +++ b/hw/misc/pc-testdev.c @@ -36,6 +36,9 @@ */ #include "qemu/osdep.h" +#if defined(CONFIG_POSIX) +#include <sys/mman.h> +#endif #include "hw/hw.h" #include "hw/qdev.h" #include "hw/isa/isa.h" diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c index 7d5990213..2f2e98977 100644 --- a/hw/misc/pci-testdev.c +++ b/hw/misc/pci-testdev.c @@ -21,7 +21,6 @@ #include "hw/hw.h" #include "hw/pci/pci.h" #include "qemu/event_notifier.h" -#include "sysemu/kvm.h" typedef struct PCITestDevHdr { uint8_t test; diff --git a/hw/misc/stm32f2xx_syscfg.c b/hw/misc/stm32f2xx_syscfg.c index 7c45833d0..d0d7076ef 100644 --- a/hw/misc/stm32f2xx_syscfg.c +++ b/hw/misc/stm32f2xx_syscfg.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "hw/misc/stm32f2xx_syscfg.h" -#include "qemu/log.h" #ifndef STM_SYSCFG_ERR_DEBUG #define STM_SYSCFG_ERR_DEBUG 0 diff --git a/hw/misc/trace-events b/hw/misc/trace-events deleted file mode 100644 index 0cc556ca9..000000000 --- a/hw/misc/trace-events +++ /dev/null @@ -1,55 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/misc/eccmemctl.c -ecc_mem_writel_mer(uint32_t val) "Write memory enable %08x" -ecc_mem_writel_mdr(uint32_t val) "Write memory delay %08x" -ecc_mem_writel_mfsr(uint32_t val) "Write memory fault status %08x" -ecc_mem_writel_vcr(uint32_t val) "Write slot configuration %08x" -ecc_mem_writel_dr(uint32_t val) "Write diagnostic %08x" -ecc_mem_writel_ecr0(uint32_t val) "Write event count 1 %08x" -ecc_mem_writel_ecr1(uint32_t val) "Write event count 2 %08x" -ecc_mem_readl_mer(uint32_t ret) "Read memory enable %08x" -ecc_mem_readl_mdr(uint32_t ret) "Read memory delay %08x" -ecc_mem_readl_mfsr(uint32_t ret) "Read memory fault status %08x" -ecc_mem_readl_vcr(uint32_t ret) "Read slot configuration %08x" -ecc_mem_readl_mfar0(uint32_t ret) "Read memory fault address 0 %08x" -ecc_mem_readl_mfar1(uint32_t ret) "Read memory fault address 1 %08x" -ecc_mem_readl_dr(uint32_t ret) "Read diagnostic %08x" -ecc_mem_readl_ecr0(uint32_t ret) "Read event count 1 %08x" -ecc_mem_readl_ecr1(uint32_t ret) "Read event count 2 %08x" -ecc_diag_mem_writeb(uint64_t addr, uint32_t val) "Write diagnostic %"PRId64" = %02x" -ecc_diag_mem_readb(uint64_t addr, uint32_t ret) "Read diagnostic %"PRId64"= %02x" - -# hw/misc/slavio_misc.c -slavio_misc_update_irq_raise(void) "Raise IRQ" -slavio_misc_update_irq_lower(void) "Lower IRQ" -slavio_set_power_fail(int power_failing, uint8_t config) "Power fail: %d, config: %d" -slavio_cfg_mem_writeb(uint32_t val) "Write config %02x" -slavio_cfg_mem_readb(uint32_t ret) "Read config %02x" -slavio_diag_mem_writeb(uint32_t val) "Write diag %02x" -slavio_diag_mem_readb(uint32_t ret) "Read diag %02x" -slavio_mdm_mem_writeb(uint32_t val) "Write modem control %02x" -slavio_mdm_mem_readb(uint32_t ret) "Read modem control %02x" -slavio_aux1_mem_writeb(uint32_t val) "Write aux1 %02x" -slavio_aux1_mem_readb(uint32_t ret) "Read aux1 %02x" -slavio_aux2_mem_writeb(uint32_t val) "Write aux2 %02x" -slavio_aux2_mem_readb(uint32_t ret) "Read aux2 %02x" -apc_mem_writeb(uint32_t val) "Write power management %02x" -apc_mem_readb(uint32_t ret) "Read power management %02x" -slavio_sysctrl_mem_writel(uint32_t val) "Write system control %08x" -slavio_sysctrl_mem_readl(uint32_t ret) "Read system control %08x" -slavio_led_mem_writew(uint32_t val) "Write diagnostic LED %04x" -slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED %04x" - -# hw/misc/milkymist-hpdmc.c -milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x" -milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x" - -# hw/misc/milkymist-pfpu.c -milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a %08x b %08x dma_ptr %08x" -milkymist_pfpu_pulse_irq(void) "Pulse IRQ" - -# hw/misc/aspeed_scu.c -aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32 diff --git a/hw/misc/vmport.c b/hw/misc/vmport.c index c763811a9..689678980 100644 --- a/hw/misc/vmport.c +++ b/hw/misc/vmport.c @@ -36,6 +36,7 @@ #define VMPORT_ENTRIES 0x2c #define VMPORT_MAGIC 0x564D5868 +#define TYPE_VMPORT "vmport" #define VMPORT(obj) OBJECT_CHECK(VMPortState, (obj), TYPE_VMPORT) typedef struct VMPortState diff --git a/hw/misc/zynq-xadc.c b/hw/misc/zynq-xadc.c index 14906103c..71fbccd79 100644 --- a/hw/misc/zynq-xadc.c +++ b/hw/misc/zynq-xadc.c @@ -18,7 +18,6 @@ #include "hw/misc/zynq-xadc.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" -#include "qemu/log.h" enum { CFG = 0x000 / 4, diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index 789121900..b1b7591ef 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -19,7 +19,6 @@ #include "qemu/timer.h" #include "hw/sysbus.h" #include "sysemu/sysemu.h" -#include "qemu/log.h" #ifndef ZYNQ_SLCR_ERR_DEBUG #define ZYNQ_SLCR_ERR_DEBUG 0 diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs index 610ed3e7a..64d044923 100644 --- a/hw/net/Makefile.objs +++ b/hw/net/Makefile.objs @@ -6,11 +6,9 @@ common-obj-$(CONFIG_NE2000_PCI) += ne2000.o common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o common-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o common-obj-$(CONFIG_PCNET_COMMON) += pcnet.o -common-obj-$(CONFIG_E1000_PCI) += e1000.o e1000x_common.o -common-obj-$(CONFIG_E1000E_PCI) += net_tx_pkt.o net_rx_pkt.o -common-obj-$(CONFIG_E1000E_PCI) += e1000e.o e1000e_core.o e1000x_common.o +common-obj-$(CONFIG_E1000_PCI) += e1000.o common-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o -common-obj-$(CONFIG_VMXNET3_PCI) += net_tx_pkt.o net_rx_pkt.o +common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet_tx_pkt.o vmxnet_rx_pkt.o common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet3.o common-obj-$(CONFIG_SMC91C111) += smc91c111.o diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c index 50e8361e5..16d4b63ba 100644 --- a/hw/net/allwinner_emac.c +++ b/hw/net/allwinner_emac.c @@ -21,7 +21,6 @@ #include "net/net.h" #include "qemu/fifo8.h" #include "hw/net/allwinner_emac.h" -#include "qemu/log.h" #include <zlib.h> static uint8_t padding[60]; @@ -424,7 +423,7 @@ static const MemoryRegionOps aw_emac_mem_ops = { }; static NetClientInfo net_aw_emac_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = aw_emac_can_receive, .receive = aw_emac_receive, diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index db1b301e7..0346f3e33 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -274,11 +274,6 @@ static inline unsigned tx_desc_get_last(unsigned *desc) return (desc[1] & DESC_1_TX_LAST) ? 1 : 0; } -static inline void tx_desc_set_last(unsigned *desc) -{ - desc[1] |= DESC_1_TX_LAST; -} - static inline unsigned tx_desc_get_length(unsigned *desc) { return desc[1] & DESC_1_LENGTH; @@ -669,13 +664,6 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size) GEM_DMACFG_RBUFSZ_S) * GEM_DMACFG_RBUFSZ_MUL; bytes_to_copy = size; - /* Hardware allows a zero value here but warns against it. To avoid QEMU - * indefinite loops we enforce a minimum value here - */ - if (rxbufsize < GEM_DMACFG_RBUFSZ_MUL) { - rxbufsize = GEM_DMACFG_RBUFSZ_MUL; - } - /* Pad to minimum length. Assume FCS field is stripped, logic * below will increment it to the real minimum of 64 when * not FCS stripping @@ -944,7 +932,6 @@ static void gem_transmit(CadenceGEMState *s) /* read next descriptor */ if (tx_desc_get_wrap(desc)) { - tx_desc_set_last(desc); packet_desc_addr = s->regs[GEM_TXQBASE]; } else { packet_desc_addr += 8; @@ -1207,7 +1194,7 @@ static void gem_set_link(NetClientState *nc) } static NetClientInfo net_gem_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = gem_can_receive, .receive = gem_receive, diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index 17f0338d1..0fa652c39 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -812,7 +812,7 @@ static void dp8393x_reset(DeviceState *dev) } static NetClientInfo net_dp83932_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = dp8393x_can_receive, .receive = dp8393x_receive, diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 93249497f..8e79b550e 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -36,7 +36,7 @@ #include "qemu/iov.h" #include "qemu/range.h" -#include "e1000x_common.h" +#include "e1000_regs.h" static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -64,6 +64,11 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); #define PNPMMIO_SIZE 0x20000 #define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */ +/* this is the size past which hardware will drop packets when setting LPE=0 */ +#define MAXIMUM_ETHERNET_VLAN_SIZE 1522 +/* this is the size past which hardware will drop packets when setting LPE=1 */ +#define MAXIMUM_ETHERNET_LPE_SIZE 16384 + #define MAXIMUM_ETHERNET_HDR_LEN (14+4) /* @@ -97,9 +102,22 @@ typedef struct E1000State_st { unsigned char vlan[4]; unsigned char data[0x10000]; uint16_t size; + unsigned char sum_needed; unsigned char vlan_needed; - e1000x_txd_props props; + uint8_t ipcss; + uint8_t ipcso; + uint16_t ipcse; + uint8_t tucss; + uint8_t tucso; + uint16_t tucse; + uint8_t hdr_len; + uint16_t mss; + uint32_t paylen; uint16_t tso_frames; + char tse; + int8_t ip; + int8_t tcp; + char cptse; // current packet tse bit } tx; struct { @@ -144,19 +162,52 @@ typedef struct E1000BaseClass { #define E1000_DEVICE_GET_CLASS(obj) \ OBJECT_GET_CLASS(E1000BaseClass, (obj), TYPE_E1000_BASE) +#define defreg(x) x = (E1000_##x>>2) +enum { + defreg(CTRL), defreg(EECD), defreg(EERD), defreg(GPRC), + defreg(GPTC), defreg(ICR), defreg(ICS), defreg(IMC), + defreg(IMS), defreg(LEDCTL), defreg(MANC), defreg(MDIC), + defreg(MPC), defreg(PBA), defreg(RCTL), defreg(RDBAH), + defreg(RDBAL), defreg(RDH), defreg(RDLEN), defreg(RDT), + defreg(STATUS), defreg(SWSM), defreg(TCTL), defreg(TDBAH), + defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT), + defreg(TORH), defreg(TORL), defreg(TOTH), defreg(TOTL), + defreg(TPR), defreg(TPT), defreg(TXDCTL), defreg(WUFC), + defreg(RA), defreg(MTA), defreg(CRCERRS), defreg(VFTA), + defreg(VET), defreg(RDTR), defreg(RADV), defreg(TADV), + defreg(ITR), defreg(FCRUC), defreg(TDFH), defreg(TDFT), + defreg(TDFHS), defreg(TDFTS), defreg(TDFPC), defreg(RDFH), + defreg(RDFT), defreg(RDFHS), defreg(RDFTS), defreg(RDFPC), + defreg(IPAV), defreg(WUC), defreg(WUS), defreg(AIT), + defreg(IP6AT), defreg(IP4AT), defreg(FFLT), defreg(FFMT), + defreg(FFVT), defreg(WUPM), defreg(PBM), defreg(SCC), + defreg(ECOL), defreg(MCC), defreg(LATECOL), defreg(COLC), + defreg(DC), defreg(TNCRS), defreg(SEC), defreg(CEXTERR), + defreg(RLEC), defreg(XONRXC), defreg(XONTXC), defreg(XOFFRXC), + defreg(XOFFTXC), defreg(RFC), defreg(RJC), defreg(RNBC), + defreg(TSCTFC), defreg(MGTPRC), defreg(MGTPDC), defreg(MGTPTC), + defreg(RUC), defreg(ROC), defreg(GORCL), defreg(GORCH), + defreg(GOTCL), defreg(GOTCH), defreg(BPRC), defreg(MPRC), + defreg(TSCTC), defreg(PRC64), defreg(PRC127), defreg(PRC255), + defreg(PRC511), defreg(PRC1023), defreg(PRC1522), defreg(PTC64), + defreg(PTC127), defreg(PTC255), defreg(PTC511), defreg(PTC1023), + defreg(PTC1522), defreg(MPTC), defreg(BPTC) +}; + static void -e1000_link_up(E1000State *s) +e1000_link_down(E1000State *s) { - e1000x_update_regs_on_link_up(s->mac_reg, s->phy_reg); - - /* E1000_STATUS_LU is tested by e1000_can_receive() */ - qemu_flush_queued_packets(qemu_get_queue(s->nic)); + s->mac_reg[STATUS] &= ~E1000_STATUS_LU; + s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS; + s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE; + s->phy_reg[PHY_LP_ABILITY] &= ~MII_LPAR_LPACK; } static void -e1000_autoneg_done(E1000State *s) +e1000_link_up(E1000State *s) { - e1000x_update_regs_on_autoneg_done(s->mac_reg, s->phy_reg); + s->mac_reg[STATUS] |= E1000_STATUS_LU; + s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS; /* E1000_STATUS_LU is tested by e1000_can_receive() */ qemu_flush_queued_packets(qemu_get_queue(s->nic)); @@ -182,7 +233,10 @@ set_phy_ctrl(E1000State *s, int index, uint16_t val) * down. */ if (have_autoneg(s) && (val & MII_CR_RESTART_AUTO_NEG)) { - e1000x_restart_autoneg(s->mac_reg, s->phy_reg, s->autoneg_timer); + e1000_link_down(s); + DBGOUT(PHY, "Start link auto negotiation\n"); + timer_mod(s->autoneg_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500); } } @@ -311,9 +365,11 @@ set_interrupt_cause(E1000State *s, int index, uint32_t val) */ mit_delay = (mit_delay < 500) ? 500 : mit_delay; - s->mit_timer_on = 1; - timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - mit_delay * 256); + if (mit_delay) { + s->mit_timer_on = 1; + timer_mod(s->mit_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + mit_delay * 256); + } s->mit_ide = 0; } } @@ -345,16 +401,43 @@ e1000_autoneg_timer(void *opaque) { E1000State *s = opaque; if (!qemu_get_queue(s->nic)->link_down) { - e1000_autoneg_done(s); + e1000_link_up(s); + s->phy_reg[PHY_LP_ABILITY] |= MII_LPAR_LPACK; + s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; + DBGOUT(PHY, "Auto negotiation is completed\n"); set_ics(s, 0, E1000_ICS_LSC); /* signal link status change to guest */ } } +static int +rxbufsize(uint32_t v) +{ + v &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 | + E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 | + E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256; + switch (v) { + case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384: + return 16384; + case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192: + return 8192; + case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096: + return 4096; + case E1000_RCTL_SZ_1024: + return 1024; + case E1000_RCTL_SZ_512: + return 512; + case E1000_RCTL_SZ_256: + return 256; + } + return 2048; +} + static void e1000_reset(void *opaque) { E1000State *d = opaque; E1000BaseClass *edc = E1000_DEVICE_GET_CLASS(d); uint8_t *macaddr = d->conf.macaddr.a; + int i; timer_del(d->autoneg_timer); timer_del(d->mit_timer); @@ -370,10 +453,17 @@ static void e1000_reset(void *opaque) memset(&d->tx, 0, sizeof d->tx); if (qemu_get_queue(d->nic)->link_down) { - e1000x_update_regs_on_link_down(d->mac_reg, d->phy_reg); + e1000_link_down(d); } - e1000x_reset_mac_addr(d->nic, d->mac_reg, macaddr); + /* Some guests expect pre-initialized RAH/RAL (AddrValid flag + MACaddr) */ + d->mac_reg[RA] = 0; + d->mac_reg[RA + 1] = E1000_RAH_AV; + for (i = 0; i < 4; i++) { + d->mac_reg[RA] |= macaddr[i] << (8 * i); + d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0; + } + qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr); } static void @@ -387,7 +477,7 @@ static void set_rx_control(E1000State *s, int index, uint32_t val) { s->mac_reg[RCTL] = val; - s->rxbuf_size = e1000x_rxbufsize(val); + s->rxbuf_size = rxbufsize(val); s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], s->mac_reg[RCTL]); @@ -508,15 +598,89 @@ putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse) } static inline void +inc_reg_if_not_full(E1000State *s, int index) +{ + if (s->mac_reg[index] != 0xffffffff) { + s->mac_reg[index]++; + } +} + +static inline void inc_tx_bcast_or_mcast_count(E1000State *s, const unsigned char *arr) { if (!memcmp(arr, bcast, sizeof bcast)) { - e1000x_inc_reg_if_not_full(s->mac_reg, BPTC); + inc_reg_if_not_full(s, BPTC); } else if (arr[0] & 1) { - e1000x_inc_reg_if_not_full(s->mac_reg, MPTC); + inc_reg_if_not_full(s, MPTC); + } +} + +static void +grow_8reg_if_not_full(E1000State *s, int index, int size) +{ + uint64_t sum = s->mac_reg[index] | (uint64_t)s->mac_reg[index+1] << 32; + + if (sum + size < sum) { + sum = ~0ULL; + } else { + sum += size; + } + s->mac_reg[index] = sum; + s->mac_reg[index+1] = sum >> 32; +} + +static void +increase_size_stats(E1000State *s, const int *size_regs, int size) +{ + if (size > 1023) { + inc_reg_if_not_full(s, size_regs[5]); + } else if (size > 511) { + inc_reg_if_not_full(s, size_regs[4]); + } else if (size > 255) { + inc_reg_if_not_full(s, size_regs[3]); + } else if (size > 127) { + inc_reg_if_not_full(s, size_regs[2]); + } else if (size > 64) { + inc_reg_if_not_full(s, size_regs[1]); + } else if (size == 64) { + inc_reg_if_not_full(s, size_regs[0]); } } +static inline int +vlan_enabled(E1000State *s) +{ + return ((s->mac_reg[CTRL] & E1000_CTRL_VME) != 0); +} + +static inline int +vlan_rx_filter_enabled(E1000State *s) +{ + return ((s->mac_reg[RCTL] & E1000_RCTL_VFE) != 0); +} + +static inline int +is_vlan_packet(E1000State *s, const uint8_t *buf) +{ + return (be16_to_cpup((uint16_t *)(buf + 12)) == + le16_to_cpu(s->mac_reg[VET])); +} + +static inline int +is_vlan_txd(uint32_t txd_lower) +{ + return ((txd_lower & E1000_TXD_CMD_VLE) != 0); +} + +/* FCS aka Ethernet CRC-32. We don't get it from backends and can't + * fill it in, just pad descriptor length by 4 bytes unless guest + * told us to strip it off the packet. */ +static inline int +fcs_len(E1000State *s) +{ + return (s->mac_reg[RCTL] & E1000_RCTL_SECRC) ? 0 : 4; +} + static void e1000_send_packet(E1000State *s, const uint8_t *buf, int size) { @@ -530,60 +694,55 @@ e1000_send_packet(E1000State *s, const uint8_t *buf, int size) qemu_send_packet(nc, buf, size); } inc_tx_bcast_or_mcast_count(s, buf); - e1000x_increase_size_stats(s->mac_reg, PTCregs, size); + increase_size_stats(s, PTCregs, size); } static void xmit_seg(E1000State *s) { - uint16_t len; + uint16_t len, *sp; unsigned int frames = s->tx.tso_frames, css, sofar; struct e1000_tx *tp = &s->tx; - if (tp->props.tse && tp->props.cptse) { - css = tp->props.ipcss; + if (tp->tse && tp->cptse) { + css = tp->ipcss; DBGOUT(TXSUM, "frames %d size %d ipcss %d\n", frames, tp->size, css); - if (tp->props.ip) { /* IPv4 */ + if (tp->ip) { /* IPv4 */ stw_be_p(tp->data+css+2, tp->size - css); stw_be_p(tp->data+css+4, - lduw_be_p(tp->data + css + 4) + frames); + be16_to_cpup((uint16_t *)(tp->data+css+4))+frames); } else { /* IPv6 */ stw_be_p(tp->data+css+4, tp->size - css); } - css = tp->props.tucss; + css = tp->tucss; len = tp->size - css; - DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->props.tcp, css, len); - if (tp->props.tcp) { - sofar = frames * tp->props.mss; + DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len); + if (tp->tcp) { + sofar = frames * tp->mss; stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* seq */ - if (tp->props.paylen - sofar > tp->props.mss) { + if (tp->paylen - sofar > tp->mss) { tp->data[css + 13] &= ~9; /* PSH, FIN */ } else if (frames) { - e1000x_inc_reg_if_not_full(s->mac_reg, TSCTC); + inc_reg_if_not_full(s, TSCTC); } } else /* UDP */ stw_be_p(tp->data+css+4, len); - if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) { + if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { unsigned int phsum; // add pseudo-header length before checksum calculation - void *sp = tp->data + tp->props.tucso; - - phsum = lduw_be_p(sp) + len; + sp = (uint16_t *)(tp->data + tp->tucso); + phsum = be16_to_cpup(sp) + len; phsum = (phsum >> 16) + (phsum & 0xffff); stw_be_p(sp, phsum); } tp->tso_frames++; } - if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) { - putsum(tp->data, tp->size, tp->props.tucso, - tp->props.tucss, tp->props.tucse); - } - if (tp->props.sum_needed & E1000_TXD_POPTS_IXSM) { - putsum(tp->data, tp->size, tp->props.ipcso, - tp->props.ipcss, tp->props.ipcse); - } + if (tp->sum_needed & E1000_TXD_POPTS_TXSM) + putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse); + if (tp->sum_needed & E1000_TXD_POPTS_IXSM) + putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse); if (tp->vlan_needed) { memmove(tp->vlan, tp->data, 4); memmove(tp->data, tp->data + 4, 8); @@ -593,8 +752,8 @@ xmit_seg(E1000State *s) e1000_send_packet(s, tp->data, tp->size); } - e1000x_inc_reg_if_not_full(s->mac_reg, TPT); - e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size); + inc_reg_if_not_full(s, TPT); + grow_8reg_if_not_full(s, TOTL, s->tx.size); s->mac_reg[GPTC] = s->mac_reg[TPT]; s->mac_reg[GOTCL] = s->mac_reg[TOTL]; s->mac_reg[GOTCH] = s->mac_reg[TOTH]; @@ -606,7 +765,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) PCIDevice *d = PCI_DEVICE(s); uint32_t txd_lower = le32_to_cpu(dp->lower.data); uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D); - unsigned int split_size = txd_lower & 0xffff, bytes, sz; + unsigned int split_size = txd_lower & 0xffff, bytes, sz, op; unsigned int msh = 0xfffff; uint64_t addr; struct e1000_context_desc *xp = (struct e1000_context_desc *)dp; @@ -614,27 +773,38 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE); if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */ - e1000x_read_tx_ctx_descr(xp, &tp->props); + op = le32_to_cpu(xp->cmd_and_length); + tp->ipcss = xp->lower_setup.ip_fields.ipcss; + tp->ipcso = xp->lower_setup.ip_fields.ipcso; + tp->ipcse = le16_to_cpu(xp->lower_setup.ip_fields.ipcse); + tp->tucss = xp->upper_setup.tcp_fields.tucss; + tp->tucso = xp->upper_setup.tcp_fields.tucso; + tp->tucse = le16_to_cpu(xp->upper_setup.tcp_fields.tucse); + tp->paylen = op & 0xfffff; + tp->hdr_len = xp->tcp_seg_setup.fields.hdr_len; + tp->mss = le16_to_cpu(xp->tcp_seg_setup.fields.mss); + tp->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0; + tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0; + tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0; tp->tso_frames = 0; - if (tp->props.tucso == 0) { /* this is probably wrong */ + if (tp->tucso == 0) { /* this is probably wrong */ DBGOUT(TXSUM, "TCP/UDP: cso 0!\n"); - tp->props.tucso = tp->props.tucss + (tp->props.tcp ? 16 : 6); + tp->tucso = tp->tucss + (tp->tcp ? 16 : 6); } return; } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { // data descriptor if (tp->size == 0) { - tp->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8; + tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8; } - tp->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; + tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0; } else { // legacy descriptor - tp->props.cptse = 0; + tp->cptse = 0; } - if (e1000x_vlan_enabled(s->mac_reg) && - e1000x_is_vlan_txd(txd_lower) && - (tp->props.cptse || txd_lower & E1000_TXD_CMD_EOP)) { + if (vlan_enabled(s) && is_vlan_txd(txd_lower) && + (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) { tp->vlan_needed = 1; stw_be_p(tp->vlan_header, le16_to_cpu(s->mac_reg[VET])); @@ -643,8 +813,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } addr = le64_to_cpu(dp->buffer_addr); - if (tp->props.tse && tp->props.cptse) { - msh = tp->props.hdr_len + tp->props.mss; + if (tp->tse && tp->cptse) { + msh = tp->hdr_len + tp->mss; do { bytes = split_size; if (tp->size + bytes > msh) @@ -653,19 +823,19 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) bytes = MIN(sizeof(tp->data) - tp->size, bytes); pci_dma_read(d, addr, tp->data + tp->size, bytes); sz = tp->size + bytes; - if (sz >= tp->props.hdr_len && tp->size < tp->props.hdr_len) { - memmove(tp->header, tp->data, tp->props.hdr_len); + if (sz >= tp->hdr_len && tp->size < tp->hdr_len) { + memmove(tp->header, tp->data, tp->hdr_len); } tp->size = sz; addr += bytes; if (sz == msh) { xmit_seg(s); - memmove(tp->data, tp->header, tp->props.hdr_len); - tp->size = tp->props.hdr_len; + memmove(tp->data, tp->header, tp->hdr_len); + tp->size = tp->hdr_len; } split_size -= bytes; } while (bytes && split_size); - } else if (!tp->props.tse && tp->props.cptse) { + } else if (!tp->tse && tp->cptse) { // context descriptor TSE is not set, while data descriptor TSE is set DBGOUT(TXERR, "TCP segmentation error\n"); } else { @@ -676,14 +846,14 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) if (!(txd_lower & E1000_TXD_CMD_EOP)) return; - if (!(tp->props.tse && tp->props.cptse && tp->size < tp->props.hdr_len)) { + if (!(tp->tse && tp->cptse && tp->size < tp->hdr_len)) { xmit_seg(s); } tp->tso_frames = 0; - tp->props.sum_needed = 0; + tp->sum_needed = 0; tp->vlan_needed = 0; tp->size = 0; - tp->props.cptse = 0; + tp->cptse = 0; } static uint32_t @@ -755,14 +925,14 @@ start_xmit(E1000State *s) static int receive_filter(E1000State *s, const uint8_t *buf, int size) { - uint32_t rctl = s->mac_reg[RCTL]; + static const int mta_shift[] = {4, 3, 2, 0}; + uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp; int isbcast = !memcmp(buf, bcast, sizeof bcast), ismcast = (buf[0] & 1); - if (e1000x_is_vlan_packet(buf, le16_to_cpu(s->mac_reg[VET])) && - e1000x_vlan_rx_filter_enabled(s->mac_reg)) { - uint16_t vid = lduw_be_p(buf + 14); - uint32_t vfta = ldl_le_p((uint32_t*)(s->mac_reg + VFTA) + - ((vid >> 5) & 0x7f)); + if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) { + uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14)); + uint32_t vfta = le32_to_cpup((uint32_t *)(s->mac_reg + VFTA) + + ((vid >> 5) & 0x7f)); if ((vfta & (1 << (vid & 0x1f))) == 0) return 0; } @@ -772,16 +942,44 @@ receive_filter(E1000State *s, const uint8_t *buf, int size) } if (ismcast && (rctl & E1000_RCTL_MPE)) { /* promiscuous mcast */ - e1000x_inc_reg_if_not_full(s->mac_reg, MPRC); + inc_reg_if_not_full(s, MPRC); return 1; } if (isbcast && (rctl & E1000_RCTL_BAM)) { /* broadcast enabled */ - e1000x_inc_reg_if_not_full(s->mac_reg, BPRC); + inc_reg_if_not_full(s, BPRC); + return 1; + } + + for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) { + if (!(rp[1] & E1000_RAH_AV)) + continue; + ra[0] = cpu_to_le32(rp[0]); + ra[1] = cpu_to_le32(rp[1]); + if (!memcmp(buf, (uint8_t *)ra, 6)) { + DBGOUT(RXFILTER, + "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n", + (int)(rp - s->mac_reg - RA)/2, + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + return 1; + } + } + DBGOUT(RXFILTER, "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3]; + f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff; + if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f))) { + inc_reg_if_not_full(s, MPRC); return 1; } + DBGOUT(RXFILTER, + "dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + (rctl >> E1000_RCTL_MO_SHIFT) & 3, f >> 5, + s->mac_reg[MTA + (f >> 5)]); - return e1000x_rx_group_filter(s->mac_reg, buf); + return 0; } static void @@ -791,11 +989,13 @@ e1000_set_link_status(NetClientState *nc) uint32_t old_status = s->mac_reg[STATUS]; if (nc->link_down) { - e1000x_update_regs_on_link_down(s->mac_reg, s->phy_reg); + e1000_link_down(s); } else { if (have_autoneg(s) && !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) { - e1000x_restart_autoneg(s->mac_reg, s->phy_reg, s->autoneg_timer); + /* emulate auto-negotiation if supported */ + timer_mod(s->autoneg_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500); } else { e1000_link_up(s); } @@ -828,7 +1028,9 @@ e1000_can_receive(NetClientState *nc) { E1000State *s = qemu_get_nic_opaque(nc); - return e1000x_rx_ready(&s->parent_obj, s->mac_reg) && + return (s->mac_reg[STATUS] & E1000_STATUS_LU) && + (s->mac_reg[RCTL] & E1000_RCTL_EN) && + (s->parent_obj.config[PCI_COMMAND] & PCI_COMMAND_MASTER) && e1000_has_rxbufs(s, 1); } @@ -859,8 +1061,14 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) size_t desc_offset; size_t desc_size; size_t total_size; + static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511, + PRC1023, PRC1522 }; + + if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) { + return -1; + } - if (!e1000x_hw_rx_enabled(s->mac_reg)) { + if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) { return -1; } @@ -868,7 +1076,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) if (size < sizeof(min_buf)) { iov_to_buf(iov, iovcnt, 0, min_buf, size); memset(&min_buf[size], 0, sizeof(min_buf) - size); - e1000x_inc_reg_if_not_full(s->mac_reg, RUC); + inc_reg_if_not_full(s, RUC); min_iov.iov_base = filter_buf = min_buf; min_iov.iov_len = size = sizeof(min_buf); iovcnt = 1; @@ -880,7 +1088,11 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) } /* Discard oversized packets if !LPE and !SBP. */ - if (e1000x_is_oversized(s->mac_reg, size)) { + if ((size > MAXIMUM_ETHERNET_LPE_SIZE || + (size > MAXIMUM_ETHERNET_VLAN_SIZE + && !(s->mac_reg[RCTL] & E1000_RCTL_LPE))) + && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) { + inc_reg_if_not_full(s, ROC); return size; } @@ -888,9 +1100,9 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) return size; } - if (e1000x_vlan_enabled(s->mac_reg) && - e1000x_is_vlan_packet(filter_buf, le16_to_cpu(s->mac_reg[VET]))) { - vlan_special = cpu_to_le16(lduw_be_p(filter_buf + 14)); + if (vlan_enabled(s) && is_vlan_packet(s, filter_buf)) { + vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(filter_buf + + 14))); iov_ofs = 4; if (filter_buf == iov->iov_base) { memmove(filter_buf + 4, filter_buf, 12); @@ -907,7 +1119,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) rdh_start = s->mac_reg[RDH]; desc_offset = 0; - total_size = size + e1000x_fcs_len(s->mac_reg); + total_size = size + fcs_len(s); if (!e1000_has_rxbufs(s, total_size)) { set_ics(s, 0, E1000_ICS_RXO); return -1; @@ -967,7 +1179,17 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) } } while (desc_offset < total_size); - e1000x_update_rx_total_stats(s->mac_reg, size, total_size); + increase_size_stats(s, PRCregs, total_size); + inc_reg_if_not_full(s, TPR); + s->mac_reg[GPRC] = s->mac_reg[TPR]; + /* TOR - Total Octets Received: + * This register includes bytes received in a packet from the <Destination + * Address> field through the <CRC> field, inclusively. + * Always include FCS length (4) in size. + */ + grow_8reg_if_not_full(s, TORL, size+4); + s->mac_reg[GORCL] = s->mac_reg[TORL]; + s->mac_reg[GORCH] = s->mac_reg[TORH]; n = E1000_ICS_RXT0; if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH]) @@ -1448,20 +1670,20 @@ static const VMStateDescription vmstate_e1000 = { VMSTATE_UINT16(eecd_state.bitnum_out, E1000State), VMSTATE_UINT16(eecd_state.reading, E1000State), VMSTATE_UINT32(eecd_state.old_eecd, E1000State), - VMSTATE_UINT8(tx.props.ipcss, E1000State), - VMSTATE_UINT8(tx.props.ipcso, E1000State), - VMSTATE_UINT16(tx.props.ipcse, E1000State), - VMSTATE_UINT8(tx.props.tucss, E1000State), - VMSTATE_UINT8(tx.props.tucso, E1000State), - VMSTATE_UINT16(tx.props.tucse, E1000State), - VMSTATE_UINT32(tx.props.paylen, E1000State), - VMSTATE_UINT8(tx.props.hdr_len, E1000State), - VMSTATE_UINT16(tx.props.mss, E1000State), + VMSTATE_UINT8(tx.ipcss, E1000State), + VMSTATE_UINT8(tx.ipcso, E1000State), + VMSTATE_UINT16(tx.ipcse, E1000State), + VMSTATE_UINT8(tx.tucss, E1000State), + VMSTATE_UINT8(tx.tucso, E1000State), + VMSTATE_UINT16(tx.tucse, E1000State), + VMSTATE_UINT32(tx.paylen, E1000State), + VMSTATE_UINT8(tx.hdr_len, E1000State), + VMSTATE_UINT16(tx.mss, E1000State), VMSTATE_UINT16(tx.size, E1000State), VMSTATE_UINT16(tx.tso_frames, E1000State), - VMSTATE_UINT8(tx.props.sum_needed, E1000State), - VMSTATE_INT8(tx.props.ip, E1000State), - VMSTATE_INT8(tx.props.tcp, E1000State), + VMSTATE_UINT8(tx.sum_needed, E1000State), + VMSTATE_INT8(tx.ip, E1000State), + VMSTATE_INT8(tx.tcp, E1000State), VMSTATE_BUFFER(tx.header, E1000State), VMSTATE_BUFFER(tx.data, E1000State), VMSTATE_UINT16_ARRAY(eeprom_data, E1000State, 64), @@ -1563,7 +1785,7 @@ pci_e1000_uninit(PCIDevice *dev) } static NetClientInfo net_e1000_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = e1000_can_receive, .receive = e1000_receive, @@ -1584,11 +1806,15 @@ static void e1000_write_config(PCIDevice *pci_dev, uint32_t address, } } + static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp) { DeviceState *dev = DEVICE(pci_dev); E1000State *d = E1000(pci_dev); + PCIDeviceClass *pdc = PCI_DEVICE_GET_CLASS(pci_dev); uint8_t *pci_conf; + uint16_t checksum = 0; + int i; uint8_t *macaddr; pci_dev->config_write = e1000_write_config; @@ -1606,14 +1832,17 @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp) pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io); + memmove(d->eeprom_data, e1000_eeprom_template, + sizeof e1000_eeprom_template); qemu_macaddr_default_if_unset(&d->conf.macaddr); macaddr = d->conf.macaddr.a; - - e1000x_core_prepare_eeprom(d->eeprom_data, - e1000_eeprom_template, - sizeof(e1000_eeprom_template), - PCI_DEVICE_GET_CLASS(pci_dev)->device_id, - macaddr); + for (i = 0; i < 3; i++) + d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i]; + d->eeprom_data[11] = d->eeprom_data[13] = pdc->device_id; + for (i = 0; i < EEPROM_CHECKSUM_REG; i++) + checksum += d->eeprom_data[i]; + checksum = (uint16_t) EEPROM_SUM - checksum; + d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum; d->nic = qemu_new_nic(&net_e1000_info, &d->conf, object_get_typename(OBJECT(d)), dev->id, d); diff --git a/hw/net/e1000_regs.h b/hw/net/e1000_regs.h index 23eed50b9..1c40244ab 100644 --- a/hw/net/e1000_regs.h +++ b/hw/net/e1000_regs.h @@ -29,8 +29,9 @@ * Structures, enums, and macros for the MAC */ -#ifndef HW_E1000_REGS_H -#define HW_E1000_REGS_H +#ifndef _E1000_HW_H_ +#define _E1000_HW_H_ + /* PCI Device IDs */ #define E1000_DEV_ID_82542 0x1000 @@ -84,7 +85,6 @@ #define E1000_DEV_ID_82573E 0x108B #define E1000_DEV_ID_82573E_IAMT 0x108C #define E1000_DEV_ID_82573L 0x109A -#define E1000_DEV_ID_82574L 0x10D3 #define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5 #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 @@ -104,7 +104,6 @@ #define E1000_PHY_ID2_82544x 0xC30 #define E1000_PHY_ID2_8254xx_DEFAULT 0xC20 /* 82540x, 82545x, and 82546x */ #define E1000_PHY_ID2_82573x 0xCC0 -#define E1000_PHY_ID2_82574x 0xCB1 /* Register Set. (82543, 82544) * @@ -136,11 +135,8 @@ #define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ #define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ #define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ -#define E1000_EIAC 0x000DC /* Ext. Interrupt Auto Clear - RW */ #define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ #define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ -#define E1000_IVAR 0x000E4 /* Interrupt Vector Allocation Register - RW */ -#define E1000_EITR 0x000E8 /* Extended Interrupt Throttling Rate - RW */ #define E1000_RCTL 0x00100 /* RX Control - RW */ #define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */ #define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */ @@ -149,7 +145,6 @@ #define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */ #define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */ #define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ -#define E1000_FCRTV 0x05F40 /* Flow Control Refresh Timer Value - RW */ #define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ #define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ #define E1000_TCTL 0x00400 /* TX Control - RW */ @@ -166,10 +161,6 @@ #define E1000_PBM 0x10000 /* Packet Buffer Memory - RW */ #define E1000_PBS 0x01008 /* Packet Buffer Size - RW */ #define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ -#define E1000_EEMNGDATA 0x01014 /* MNG EEPROM Read/Write data */ -#define E1000_FLMNGCTL 0x01018 /* MNG Flash Control */ -#define E1000_FLMNGDATA 0x0101C /* MNG FLASH Read data */ -#define E1000_FLMNGCNT 0x01020 /* MNG FLASH Read Counter */ #define E1000_FLASH_UPDATES 1000 #define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */ #define E1000_FLASHT 0x01028 /* FLASH Timer Register */ @@ -178,12 +169,9 @@ #define E1000_FLSWDATA 0x01034 /* FLASH data register */ #define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */ #define E1000_FLOP 0x0103C /* FLASH Opcode Register */ -#define E1000_FLOL 0x01050 /* FEEP Auto Load */ #define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ #define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ -#define E1000_FCRTL_A 0x00168 /* Alias to FCRTL */ #define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ -#define E1000_FCRTH_A 0x00160 /* Alias to FCRTH */ #define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */ #define E1000_RDBAL 0x02800 /* RX Descriptor Base Address Low - RW */ #define E1000_RDBAH 0x02804 /* RX Descriptor Base Address High - RW */ @@ -191,17 +179,11 @@ #define E1000_RDH 0x02810 /* RX Descriptor Head - RW */ #define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */ #define E1000_RDTR 0x02820 /* RX Delay Timer - RW */ -#define E1000_RDTR_A 0x00108 /* Alias to RDTR */ #define E1000_RDBAL0 E1000_RDBAL /* RX Desc Base Address Low (0) - RW */ -#define E1000_RDBAL0_A 0x00110 /* Alias to RDBAL0 */ #define E1000_RDBAH0 E1000_RDBAH /* RX Desc Base Address High (0) - RW */ -#define E1000_RDBAH0_A 0x00114 /* Alias to RDBAH0 */ #define E1000_RDLEN0 E1000_RDLEN /* RX Desc Length (0) - RW */ -#define E1000_RDLEN0_A 0x00118 /* Alias to RDLEN0 */ #define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */ -#define E1000_RDH0_A 0x00120 /* Alias to RDH0 */ #define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */ -#define E1000_RDT0_A 0x00128 /* Alias to RDT0 */ #define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */ #define E1000_RXDCTL 0x02828 /* RX Descriptor Control queue 0 - RW */ #define E1000_RXDCTL1 0x02928 /* RX Descriptor Control queue 1 - RW */ @@ -210,33 +192,22 @@ #define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ #define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */ #define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */ -#define E1000_POEMB 0x00F10 /* PHY OEM Bits Register - RW */ #define E1000_RDFH 0x02410 /* Receive Data FIFO Head Register - RW */ -#define E1000_RDFH_A 0x08000 /* Alias to RDFH */ #define E1000_RDFT 0x02418 /* Receive Data FIFO Tail Register - RW */ -#define E1000_RDFT_A 0x08008 /* Alias to RDFT */ #define E1000_RDFHS 0x02420 /* Receive Data FIFO Head Saved Register - RW */ #define E1000_RDFTS 0x02428 /* Receive Data FIFO Tail Saved Register - RW */ #define E1000_RDFPC 0x02430 /* Receive Data FIFO Packet Count - RW */ #define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */ -#define E1000_TDFH_A 0x08010 /* Alias to TDFH */ #define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */ -#define E1000_TDFT_A 0x08018 /* Alias to TDFT */ #define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */ #define E1000_TDFTS 0x03428 /* TX Data FIFO Tail Saved - RW */ #define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */ #define E1000_TDBAL 0x03800 /* TX Descriptor Base Address Low - RW */ -#define E1000_TDBAL_A 0x00420 /* Alias to TDBAL */ #define E1000_TDBAH 0x03804 /* TX Descriptor Base Address High - RW */ -#define E1000_TDBAH_A 0x00424 /* Alias to TDBAH */ #define E1000_TDLEN 0x03808 /* TX Descriptor Length - RW */ -#define E1000_TDLEN_A 0x00428 /* Alias to TDLEN */ #define E1000_TDH 0x03810 /* TX Descriptor Head - RW */ -#define E1000_TDH_A 0x00430 /* Alias to TDH */ #define E1000_TDT 0x03818 /* TX Descripotr Tail - RW */ -#define E1000_TDT_A 0x00438 /* Alias to TDT */ #define E1000_TIDV 0x03820 /* TX Interrupt Delay Value - RW */ -#define E1000_TIDV_A 0x00440 /* Alias to TIDV */ #define E1000_TXDCTL 0x03828 /* TX Descriptor Control - RW */ #define E1000_TADV 0x0382C /* TX Interrupt Absolute Delay Val - RW */ #define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ @@ -317,15 +288,9 @@ #define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ #define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ #define E1000_RFCTL 0x05008 /* Receive Filter Control*/ -#define E1000_MAVTV0 0x05010 /* Management VLAN TAG Value 0 */ -#define E1000_MAVTV1 0x05014 /* Management VLAN TAG Value 1 */ -#define E1000_MAVTV2 0x05018 /* Management VLAN TAG Value 2 */ -#define E1000_MAVTV3 0x0501c /* Management VLAN TAG Value 3 */ #define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ #define E1000_RA 0x05400 /* Receive Address - RW Array */ -#define E1000_RA_A 0x00040 /* Alias to RA */ #define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ -#define E1000_VFTA_A 0x00600 /* Alias to VFTA */ #define E1000_WUC 0x05800 /* Wakeup Control - RW */ #define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ #define E1000_WUS 0x05810 /* Wakeup Status - RO */ @@ -335,57 +300,27 @@ #define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ #define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ #define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ -#define E1000_MFUTP01 0x05828 /* Management Flex UDP/TCP Ports 0/1 - RW */ -#define E1000_MFUTP23 0x05830 /* Management Flex UDP/TCP Ports 2/3 - RW */ -#define E1000_MFVAL 0x05824 /* Manageability Filters Valid - RW */ -#define E1000_MDEF 0x05890 /* Manageability Decision Filters - RW Array */ #define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ #define E1000_HOST_IF 0x08800 /* Host Interface */ #define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ -#define E1000_FTFT 0x09400 /* Flexible TCO Filter Table - RW Array */ #define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ #define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */ -#define E1000_MDPHYA 0x0003C /* PHY address - RW */ -#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ +#define E1000_MDPHYA 0x0003C /* PHY address - RW */ +#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ #define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ #define E1000_GCR 0x05B00 /* PCI-Ex Control */ -#define E1000_FUNCTAG 0x05B08 /* Function-Tag Register */ #define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ #define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ #define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */ #define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */ -#define E1000_GSCN_0 0x05B20 /* 3GIO Statistic Counter Register #0 */ -#define E1000_GSCN_1 0x05B24 /* 3GIO Statistic Counter Register #1 */ -#define E1000_GSCN_2 0x05B28 /* 3GIO Statistic Counter Register #2 */ -#define E1000_GSCN_3 0x05B2C /* 3GIO Statistic Counter Register #3 */ #define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ #define E1000_SWSM 0x05B50 /* SW Semaphore */ -#define E1000_GCR2 0x05B64 /* 3GIO Control Register 2 */ #define E1000_FWSM 0x05B54 /* FW Semaphore */ -#define E1000_PBACLR 0x05B68 /* MSI-X PBA Clear */ #define E1000_FFLT_DBG 0x05F04 /* Debug Register */ #define E1000_HICR 0x08F00 /* Host Inteface Control */ -#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */ -#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */ -#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */ -#define E1000_RXSTMPL 0x0B624 /* Rx timestamp Low - RO */ -#define E1000_RXSTMPH 0x0B628 /* Rx timestamp High - RO */ -#define E1000_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */ -#define E1000_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */ -#define E1000_SYSTIML 0x0B600 /* System time register Low - RO */ -#define E1000_SYSTIMH 0x0B604 /* System time register High - RO */ -#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */ -#define E1000_RXMTRL 0x0B634 /* Time sync Rx EtherType and Msg Type - RW */ -#define E1000_RXUDP 0x0B638 /* Time Sync Rx UDP Port - RW */ -#define E1000_RXSATRL 0x0B62C /* Rx timestamp attribute low - RO */ -#define E1000_RXSATRH 0x0B630 /* Rx timestamp attribute high - RO */ -#define E1000_TIMADJL 0x0B60C /* Time Adjustment Offset register Low - RW */ -#define E1000_TIMADJH 0x0B610 /* Time Adjustment Offset register High - RW */ -#define E1000_RXCFGL 0x0B634 /* RX Ethertype and Message Type - RW*/ - /* RSS registers */ #define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ #define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ @@ -394,85 +329,6 @@ #define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ #define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ -#define E1000_MRQC_ENABLED(mrqc) (((mrqc) & (BIT(0) | BIT(1))) == BIT(0)) - -#define E1000_RETA_IDX(hash) ((hash) & (BIT(7) - 1)) -#define E1000_RETA_VAL(reta, hash) (((uint8_t *)(reta))[E1000_RETA_IDX(hash)]) -#define E1000_RSS_QUEUE(reta, hash) ((E1000_RETA_VAL(reta, hash) & BIT(7)) >> 7) - -#define E1000_MRQC_EN_TCPIPV4(mrqc) ((mrqc) & BIT(16)) -#define E1000_MRQC_EN_IPV4(mrqc) ((mrqc) & BIT(17)) -#define E1000_MRQC_EN_TCPIPV6(mrqc) ((mrqc) & BIT(18)) -#define E1000_MRQC_EN_IPV6EX(mrqc) ((mrqc) & BIT(19)) -#define E1000_MRQC_EN_IPV6(mrqc) ((mrqc) & BIT(20)) - -#define E1000_MRQ_RSS_TYPE_NONE (0) -#define E1000_MRQ_RSS_TYPE_IPV4TCP (1) -#define E1000_MRQ_RSS_TYPE_IPV4 (2) -#define E1000_MRQ_RSS_TYPE_IPV6TCP (3) -#define E1000_MRQ_RSS_TYPE_IPV6EX (4) -#define E1000_MRQ_RSS_TYPE_IPV6 (5) - -#define E1000_ICR_ASSERTED BIT(31) -#define E1000_EIAC_MASK 0x01F00000 - -/* [TR]DBAL and [TR]DLEN masks */ -#define E1000_XDBAL_MASK (~(BIT(4) - 1)) -#define E1000_XDLEN_MASK ((BIT(20) - 1) & (~(BIT(7) - 1))) - -/* IVAR register parsing helpers */ -#define E1000_IVAR_INT_ALLOC_VALID (0x8) - -#define E1000_IVAR_RXQ0_SHIFT (0) -#define E1000_IVAR_RXQ1_SHIFT (4) -#define E1000_IVAR_TXQ0_SHIFT (8) -#define E1000_IVAR_TXQ1_SHIFT (12) -#define E1000_IVAR_OTHER_SHIFT (16) - -#define E1000_IVAR_ENTRY_MASK (0xF) -#define E1000_IVAR_ENTRY_VALID_MASK E1000_IVAR_INT_ALLOC_VALID -#define E1000_IVAR_ENTRY_VEC_MASK (0x7) - -#define E1000_IVAR_RXQ0(x) ((x) >> E1000_IVAR_RXQ0_SHIFT) -#define E1000_IVAR_RXQ1(x) ((x) >> E1000_IVAR_RXQ1_SHIFT) -#define E1000_IVAR_TXQ0(x) ((x) >> E1000_IVAR_TXQ0_SHIFT) -#define E1000_IVAR_TXQ1(x) ((x) >> E1000_IVAR_TXQ1_SHIFT) -#define E1000_IVAR_OTHER(x) ((x) >> E1000_IVAR_OTHER_SHIFT) - -#define E1000_IVAR_ENTRY_VALID(x) ((x) & E1000_IVAR_ENTRY_VALID_MASK) -#define E1000_IVAR_ENTRY_VEC(x) ((x) & E1000_IVAR_ENTRY_VEC_MASK) - -#define E1000_IVAR_TX_INT_EVERY_WB BIT(31) - -/* RFCTL register bits */ -#define E1000_RFCTL_ISCSI_DIS 0x00000001 -#define E1000_RFCTL_NFSW_DIS 0x00000040 -#define E1000_RFCTL_NFSR_DIS 0x00000080 -#define E1000_RFCTL_IPV6_DIS 0x00000400 -#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800 -#define E1000_RFCTL_ACK_DIS 0x00001000 -#define E1000_RFCTL_ACK_DATA_DIS 0x00002000 -#define E1000_RFCTL_IPFRSP_DIS 0x00004000 -#define E1000_RFCTL_EXTEN 0x00008000 -#define E1000_RFCTL_IPV6_EX_DIS 0x00010000 -#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 - -/* PSRCTL parsing */ -#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F -#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 -#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 -#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000 - -#define E1000_PSRCTL_BSIZE0_SHIFT 0 -#define E1000_PSRCTL_BSIZE1_SHIFT 8 -#define E1000_PSRCTL_BSIZE2_SHIFT 16 -#define E1000_PSRCTL_BSIZE3_SHIFT 24 - -#define E1000_PSRCTL_BUFFS_PER_DESC 4 - -/* TARC* parsing */ -#define E1000_TARC_ENABLE BIT(10) - /* PHY 1000 MII Register/Bit Definitions */ /* PHY Registers defined by IEEE */ #define PHY_CTRL 0x00 /* Control Register */ @@ -488,40 +344,6 @@ #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ #define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ -/* 82574-specific registers */ -#define PHY_COPPER_CTRL1 0x10 /* Copper Specific Control Register 1 */ -#define PHY_COPPER_STAT1 0x11 /* Copper Specific Status Register 1 */ -#define PHY_COPPER_INT_ENABLE 0x12 /* Interrupt Enable Register */ -#define PHY_COPPER_STAT2 0x13 /* Copper Specific Status Register 2 */ -#define PHY_COPPER_CTRL3 0x14 /* Copper Specific Control Register 3 */ -#define PHY_COPPER_CTRL2 0x1A /* Copper Specific Control Register 2 */ -#define PHY_RX_ERR_CNTR 0x15 /* Receive Error Counter */ -#define PHY_PAGE 0x16 /* Page Address (Any page) */ -#define PHY_OEM_BITS 0x19 /* OEM Bits (Page 0) */ -#define PHY_BIAS_1 0x1d /* Bias Setting Register */ -#define PHY_BIAS_2 0x1e /* Bias Setting Register */ - -/* 82574-specific registers - page 2 */ -#define PHY_MAC_CTRL1 0x10 /* MAC Specific Control Register 1 */ -#define PHY_MAC_INT_ENABLE 0x12 /* MAC Interrupt Enable Register */ -#define PHY_MAC_STAT 0x13 /* MAC Specific Status Register */ -#define PHY_MAC_CTRL2 0x15 /* MAC Specific Control Register 2 */ - -/* 82574-specific registers - page 3 */ -#define PHY_LED_03_FUNC_CTRL1 0x10 /* LED[3:0] Function Control */ -#define PHY_LED_03_POL_CTRL 0x11 /* LED[3:0] Polarity Control */ -#define PHY_LED_TIMER_CTRL 0x12 /* LED Timer Control */ -#define PHY_LED_45_CTRL 0x13 /* LED[5:4] Function Control and Polarity */ - -/* 82574-specific registers - page 5 */ -#define PHY_1000T_SKEW 0x14 /* 1000 BASE - T Pair Skew Register */ -#define PHY_1000T_SWAP 0x15 /* 1000 BASE - T Pair Swap and Polarity */ - -/* 82574-specific registers - page 6 */ -#define PHY_CRC_COUNTERS 0x11 /* CRC Counters */ - -#define PHY_PAGE_RW_MASK 0x7F /* R/W part of page address register */ - #define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ #define MAX_PHY_MULTI_PAGE_REG 0xF /* Registers equal on all pages */ @@ -601,18 +423,6 @@ #define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */ #define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */ #define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */ -#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */ -#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */ -#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */ -#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ -#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ - -#define E1000_ICR_OTHER_CAUSES (E1000_ICR_LSC | \ - E1000_ICR_RXO | \ - E1000_ICR_MDAC | \ - E1000_ICR_SRPD | \ - E1000_ICR_ACK | \ - E1000_ICR_MNG) /* Interrupt Cause Set */ #define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -661,11 +471,6 @@ #define E1000_IMS_SRPD E1000_ICR_SRPD #define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ #define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ -#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 -#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 -#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 -#define E1000_IMS_TXQ1 E1000_ICR_TXQ1 -#define E1000_IMS_OTHER E1000_ICR_OTHER #define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ #define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ #define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ @@ -757,15 +562,6 @@ #define E1000_EEPROM_RW_ADDR_SHIFT 8 /* Shift to the address bits */ #define E1000_EEPROM_POLL_WRITE 1 /* Flag for polling for write complete */ #define E1000_EEPROM_POLL_READ 0 /* Flag for polling for read complete */ - -/* 82574 EERD/EEWR registers layout */ -#define E1000_EERW_START BIT(0) -#define E1000_EERW_DONE BIT(1) -#define E1000_EERW_ADDR_SHIFT 2 -#define E1000_EERW_ADDR_MASK ((1L << 14) - 1) -#define E1000_EERW_DATA_SHIFT 16 -#define E1000_EERW_DATA_MASK ((1L << 16) - 1) - /* Register Bit Masks */ /* Device Control */ #define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ @@ -788,17 +584,7 @@ #define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ #define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ #define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */ -#define E1000_CTRL_SPD_SHIFT 8 /* Speed Select Shift */ - -#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* auto speed detection check */ -#define E1000_CTRL_EXT_EE_RST 0x00002000 /* EEPROM reset */ #define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */ -#define E1000_CTRL_EXT_EIAME 0x01000000 -#define E1000_CTRL_EXT_IAME 0x08000000 /* Int ACK Auto-mask */ -#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ -#define E1000_CTRL_EXT_INT_TIMERS_CLEAR_ENA 0x20000000 -#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ - #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ #define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ @@ -807,7 +593,6 @@ #define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ #define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ #define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ -#define E1000_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */ #define E1000_CTRL_RST 0x04000000 /* Global reset */ #define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ #define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ @@ -832,13 +617,9 @@ #define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by EEPROM/Flash */ #define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ -#define E1000_STATUS_ASDV_10 0x00000000 /* ASDV 10Mb */ -#define E1000_STATUS_ASDV_100 0x00000100 /* ASDV 100Mb */ -#define E1000_STATUS_ASDV_1000 0x00000200 /* ASDV 1Gb */ #define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */ #define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */ #define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ -#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */ #define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ #define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ #define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ @@ -853,8 +634,6 @@ #define E1000_STATUS_FUSE_9 0x08000000 #define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */ #define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */ -#define E1000_STATUS_SPEED_SHIFT 6 -#define E1000_STATUS_ASDV_SHIFT 8 /* EEPROM/Flash Control */ #define E1000_EECD_SK 0x00000001 /* EEPROM Clock */ @@ -885,8 +664,6 @@ #define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ #define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ #define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ - - #define E1000_EECD_SECVAL_SHIFT 22 #define E1000_STM_OPCODE 0xDB00 #define E1000_HICR_FW_RESET 0xC0 @@ -907,18 +684,6 @@ #define E1000_MDIC_INT_EN 0x20000000 #define E1000_MDIC_ERROR 0x40000000 -/* Rx Interrupt Delay Timer */ -#define E1000_RDTR_FPD BIT(31) - -/* Tx Interrupt Delay Timer */ -#define E1000_TIDV_FPD BIT(31) - -/* Delay increments in nanoseconds for delayed interrupts registers */ -#define E1000_INTR_DELAY_NS_RES (1024) - -/* Delay increments in nanoseconds for interrupt throttling registers */ -#define E1000_INTR_THROTTLING_NS_RES (256) - /* EEPROM Commands - Microwire */ #define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */ #define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */ @@ -946,21 +711,6 @@ #define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */ #define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */ -/* PCI Express Control */ -/* 3GIO Control Register - GCR (0x05B00; RW) */ -#define E1000_L0S_ADJUST (1 << 9) -#define E1000_L1_ENTRY_LATENCY_MSB (1 << 23) -#define E1000_L1_ENTRY_LATENCY_LSB (1 << 25 | 1 << 26) - -#define E1000_L0S_ADJUST (1 << 9) -#define E1000_L1_ENTRY_LATENCY_MSB (1 << 23) -#define E1000_L1_ENTRY_LATENCY_LSB (1 << 25 | 1 << 26) - -#define E1000_GCR_RO_BITS (1 << 23 | 1 << 25 | 1 << 26) - -/* MSI-X PBA Clear register */ -#define E1000_PBACLR_VALID_MASK (BIT(5) - 1) - /* Transmit Descriptor */ struct e1000_tx_desc { uint64_t buffer_addr; /* Address of the descriptor's data buffer */ @@ -1002,9 +752,7 @@ struct e1000_tx_desc { #define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ #define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ #define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ -#define E1000_TXD_CMD_SNAP 0x40000000 /* Update SNAP header */ #define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ -#define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */ /* Transmit Control */ #define E1000_TCTL_RST 0x00000001 /* software reset */ @@ -1019,7 +767,7 @@ struct e1000_tx_desc { #define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ #define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ -/* Legacy Receive Descriptor */ +/* Receive Descriptor */ struct e1000_rx_desc { uint64_t buffer_addr; /* Address of the descriptor's data buffer */ uint16_t length; /* Length of data DMAed into data buffer */ @@ -1029,78 +777,6 @@ struct e1000_rx_desc { uint16_t special; }; -/* Extended Receive Descriptor */ -union e1000_rx_desc_extended { - struct { - uint64_t buffer_addr; - uint64_t reserved; - } read; - struct { - struct { - uint32_t mrq; /* Multiple Rx Queues */ - union { - uint32_t rss; /* RSS Hash */ - struct { - uint16_t ip_id; /* IP id */ - uint16_t csum; /* Packet Checksum */ - } csum_ip; - } hi_dword; - } lower; - struct { - uint32_t status_error; /* ext status/error */ - uint16_t length; - uint16_t vlan; /* VLAN tag */ - } upper; - } wb; /* writeback */ -}; - -#define MAX_PS_BUFFERS 4 - -/* Number of packet split data buffers (not including the header buffer) */ -#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) - -/* Receive Descriptor - Packet Split */ -union e1000_rx_desc_packet_split { - struct { - /* one buffer for protocol header(s), three data buffers */ - uint64_t buffer_addr[MAX_PS_BUFFERS]; - } read; - struct { - struct { - uint32_t mrq; /* Multiple Rx Queues */ - union { - uint32_t rss; /* RSS Hash */ - struct { - uint16_t ip_id; /* IP id */ - uint16_t csum; /* Packet Checksum */ - } csum_ip; - } hi_dword; - } lower; - struct { - uint32_t status_error; /* ext status/error */ - uint16_t length0; /* length of buffer 0 */ - uint16_t vlan; /* VLAN tag */ - } middle; - struct { - uint16_t header_status; - /* length of buffers 1-3 */ - uint16_t length[PS_PAGE_BUFFERS]; - } upper; - uint64_t reserved; - } wb; /* writeback */ -}; - -/* Receive Checksum Control bits */ -#define E1000_RXCSUM_IPOFLD 0x100 /* IP Checksum Offload Enable */ -#define E1000_RXCSUM_TUOFLD 0x200 /* TCP/UDP Checksum Offload Enable */ -#define E1000_RXCSUM_PCSD 0x2000 /* Packet Checksum Disable */ - -#define E1000_RING_DESC_LEN (16) -#define E1000_RING_DESC_LEN_SHIFT (4) - -#define E1000_MIN_RX_DESC_LEN E1000_RING_DESC_LEN -#define E1000_MAX_RX_DESC_LEN (sizeof(union e1000_rx_desc_packet_split)) - /* Receive Descriptor bit definitions */ #define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ #define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ @@ -1126,15 +802,6 @@ union e1000_rx_desc_packet_split { #define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ #define E1000_RXD_SPC_CFI_SHIFT 12 -/* RX packet types */ -#define E1000_RXD_PKT_MAC (0) -#define E1000_RXD_PKT_IP4 (1) -#define E1000_RXD_PKT_IP4_XDP (2) -#define E1000_RXD_PKT_IP6 (5) -#define E1000_RXD_PKT_IP6_XDP (6) - -#define E1000_RXD_PKT_TYPE(t) ((t) << 16) - #define E1000_RXDEXT_STATERR_CE 0x01000000 #define E1000_RXDEXT_STATERR_SE 0x02000000 #define E1000_RXDEXT_STATERR_SEQ 0x04000000 @@ -1212,8 +879,6 @@ struct e1000_data_desc { #define E1000_MANC_NEIGHBOR_EN 0x00004000 /* Enable Neighbor Discovery * Filtering */ #define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */ -#define E1000_MANC_DIS_IP_CHK_ARP 0x10000000 /* Disable IP address chacking */ - /*for ARP packets - in 82574 */ #define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ #define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ #define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ @@ -1237,14 +902,7 @@ struct e1000_data_desc { #define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ #define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ -/* FACTPS Control */ -#define E1000_FACTPS_LAN0_ON 0x00000004 /* Lan 0 enable */ - /* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */ #define EEPROM_SUM 0xBABA -/* I/O-Mapped Access to Internal Registers, Memories, and Flash */ -#define E1000_IOADDR 0x00 -#define E1000_IODATA 0x04 - -#endif /* HW_E1000_REGS_H */ +#endif /* _E1000_HW_H_ */ diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c deleted file mode 100644 index bad43f474..000000000 --- a/hw/net/e1000e.c +++ /dev/null @@ -1,711 +0,0 @@ -/* -* QEMU INTEL 82574 GbE NIC emulation -* -* Software developer's manuals: -* http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf -* -* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com) -* Developed by Daynix Computing LTD (http://www.daynix.com) -* -* Authors: -* Dmitry Fleytman <dmitry@daynix.com> -* Leonid Bloch <leonid@daynix.com> -* Yan Vugenfirer <yan@daynix.com> -* -* Based on work done by: -* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc. -* Copyright (c) 2008 Qumranet -* Based on work done by: -* Copyright (c) 2007 Dan Aloni -* Copyright (c) 2004 Antony T Curtis -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "qemu/osdep.h" -#include "net/net.h" -#include "net/tap.h" -#include "qemu/range.h" -#include "sysemu/sysemu.h" -#include "hw/pci/msi.h" -#include "hw/pci/msix.h" - -#include "hw/net/e1000_regs.h" - -#include "e1000x_common.h" -#include "e1000e_core.h" - -#include "trace.h" - -#define TYPE_E1000E "e1000e" -#define E1000E(obj) OBJECT_CHECK(E1000EState, (obj), TYPE_E1000E) - -typedef struct E1000EState { - PCIDevice parent_obj; - NICState *nic; - NICConf conf; - - MemoryRegion mmio; - MemoryRegion flash; - MemoryRegion io; - MemoryRegion msix; - - uint32_t ioaddr; - - uint16_t subsys_ven; - uint16_t subsys; - - uint16_t subsys_ven_used; - uint16_t subsys_used; - - bool disable_vnet; - - E1000ECore core; - -} E1000EState; - -#define E1000E_MMIO_IDX 0 -#define E1000E_FLASH_IDX 1 -#define E1000E_IO_IDX 2 -#define E1000E_MSIX_IDX 3 - -#define E1000E_MMIO_SIZE (128 * 1024) -#define E1000E_FLASH_SIZE (128 * 1024) -#define E1000E_IO_SIZE (32) -#define E1000E_MSIX_SIZE (16 * 1024) - -#define E1000E_MSIX_TABLE (0x0000) -#define E1000E_MSIX_PBA (0x2000) - -static uint64_t -e1000e_mmio_read(void *opaque, hwaddr addr, unsigned size) -{ - E1000EState *s = opaque; - return e1000e_core_read(&s->core, addr, size); -} - -static void -e1000e_mmio_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - E1000EState *s = opaque; - e1000e_core_write(&s->core, addr, val, size); -} - -static bool -e1000e_io_get_reg_index(E1000EState *s, uint32_t *idx) -{ - if (s->ioaddr < 0x1FFFF) { - *idx = s->ioaddr; - return true; - } - - if (s->ioaddr < 0x7FFFF) { - trace_e1000e_wrn_io_addr_undefined(s->ioaddr); - return false; - } - - if (s->ioaddr < 0xFFFFF) { - trace_e1000e_wrn_io_addr_flash(s->ioaddr); - return false; - } - - trace_e1000e_wrn_io_addr_unknown(s->ioaddr); - return false; -} - -static uint64_t -e1000e_io_read(void *opaque, hwaddr addr, unsigned size) -{ - E1000EState *s = opaque; - uint32_t idx = 0; - uint64_t val; - - switch (addr) { - case E1000_IOADDR: - trace_e1000e_io_read_addr(s->ioaddr); - return s->ioaddr; - case E1000_IODATA: - if (e1000e_io_get_reg_index(s, &idx)) { - val = e1000e_core_read(&s->core, idx, sizeof(val)); - trace_e1000e_io_read_data(idx, val); - return val; - } - return 0; - default: - trace_e1000e_wrn_io_read_unknown(addr); - return 0; - } -} - -static void -e1000e_io_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - E1000EState *s = opaque; - uint32_t idx = 0; - - switch (addr) { - case E1000_IOADDR: - trace_e1000e_io_write_addr(val); - s->ioaddr = (uint32_t) val; - return; - case E1000_IODATA: - if (e1000e_io_get_reg_index(s, &idx)) { - trace_e1000e_io_write_data(idx, val); - e1000e_core_write(&s->core, idx, val, sizeof(val)); - } - return; - default: - trace_e1000e_wrn_io_write_unknown(addr); - return; - } -} - -static const MemoryRegionOps mmio_ops = { - .read = e1000e_mmio_read, - .write = e1000e_mmio_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static const MemoryRegionOps io_ops = { - .read = e1000e_io_read, - .write = e1000e_io_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static int -e1000e_nc_can_receive(NetClientState *nc) -{ - E1000EState *s = qemu_get_nic_opaque(nc); - return e1000e_can_receive(&s->core); -} - -static ssize_t -e1000e_nc_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) -{ - E1000EState *s = qemu_get_nic_opaque(nc); - return e1000e_receive_iov(&s->core, iov, iovcnt); -} - -static ssize_t -e1000e_nc_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - E1000EState *s = qemu_get_nic_opaque(nc); - return e1000e_receive(&s->core, buf, size); -} - -static void -e1000e_set_link_status(NetClientState *nc) -{ - E1000EState *s = qemu_get_nic_opaque(nc); - e1000e_core_set_link_status(&s->core); -} - -static NetClientInfo net_e1000e_info = { - .type = NET_CLIENT_DRIVER_NIC, - .size = sizeof(NICState), - .can_receive = e1000e_nc_can_receive, - .receive = e1000e_nc_receive, - .receive_iov = e1000e_nc_receive_iov, - .link_status_changed = e1000e_set_link_status, -}; - -/* -* EEPROM (NVM) contents documented in Table 36, section 6.1 -* and generally 6.1.2 Software accessed words. -*/ -static const uint16_t e1000e_eeprom_template[64] = { - /* Address | Compat. | ImVer | Compat. */ - 0x0000, 0x0000, 0x0000, 0x0420, 0xf746, 0x2010, 0xffff, 0xffff, - /* PBA |ICtrl1 | SSID | SVID | DevID |-------|ICtrl2 */ - 0x0000, 0x0000, 0x026b, 0x0000, 0x8086, 0x0000, 0x0000, 0x8058, - /* NVM words 1,2,3 |-------------------------------|PCI-EID*/ - 0x0000, 0x2001, 0x7e7c, 0xffff, 0x1000, 0x00c8, 0x0000, 0x2704, - /* PCIe Init. Conf 1,2,3 |PCICtrl|PHY|LD1|-------| RevID | LD0,2 */ - 0x6cc9, 0x3150, 0x070e, 0x460b, 0x2d84, 0x0100, 0xf000, 0x0706, - /* FLPAR |FLANADD|LAN-PWR|FlVndr |ICtrl3 |APTSMBA|APTRxEP|APTSMBC*/ - 0x6000, 0x0080, 0x0f04, 0x7fff, 0x4f01, 0xc600, 0x0000, 0x20ff, - /* APTIF | APTMC |APTuCP |LSWFWID|MSWFWID|NC-SIMC|NC-SIC | VPDP */ - 0x0028, 0x0003, 0x0000, 0x0000, 0x0000, 0x0003, 0x0000, 0xffff, - /* SW Section */ - 0x0100, 0xc000, 0x121c, 0xc007, 0xffff, 0xffff, 0xffff, 0xffff, - /* SW Section |CHKSUM */ - 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0120, 0xffff, 0x0000, -}; - -static void e1000e_core_realize(E1000EState *s) -{ - s->core.owner = &s->parent_obj; - s->core.owner_nic = s->nic; -} - -static void -e1000e_unuse_msix_vectors(E1000EState *s, int num_vectors) -{ - int i; - for (i = 0; i < num_vectors; i++) { - msix_vector_unuse(PCI_DEVICE(s), i); - } -} - -static bool -e1000e_use_msix_vectors(E1000EState *s, int num_vectors) -{ - int i; - for (i = 0; i < num_vectors; i++) { - int res = msix_vector_use(PCI_DEVICE(s), i); - if (res < 0) { - trace_e1000e_msix_use_vector_fail(i, res); - e1000e_unuse_msix_vectors(s, i); - return false; - } - } - return true; -} - -static void -e1000e_init_msix(E1000EState *s) -{ - PCIDevice *d = PCI_DEVICE(s); - int res = msix_init(PCI_DEVICE(s), E1000E_MSIX_VEC_NUM, - &s->msix, - E1000E_MSIX_IDX, E1000E_MSIX_TABLE, - &s->msix, - E1000E_MSIX_IDX, E1000E_MSIX_PBA, - 0xA0); - - if (res < 0) { - trace_e1000e_msix_init_fail(res); - } else { - if (!e1000e_use_msix_vectors(s, E1000E_MSIX_VEC_NUM)) { - msix_uninit(d, &s->msix, &s->msix); - } - } -} - -static void -e1000e_cleanup_msix(E1000EState *s) -{ - if (msix_enabled(PCI_DEVICE(s))) { - e1000e_unuse_msix_vectors(s, E1000E_MSIX_VEC_NUM); - msix_uninit(PCI_DEVICE(s), &s->msix, &s->msix); - } -} - -static void -e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr) -{ - DeviceState *dev = DEVICE(pci_dev); - NetClientState *nc; - int i; - - s->nic = qemu_new_nic(&net_e1000e_info, &s->conf, - object_get_typename(OBJECT(s)), dev->id, s); - - s->core.max_queue_num = s->conf.peers.queues - 1; - - trace_e1000e_mac_set_permanent(MAC_ARG(macaddr)); - memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac)); - - qemu_format_nic_info_str(qemu_get_queue(s->nic), macaddr); - - /* Setup virtio headers */ - if (s->disable_vnet) { - s->core.has_vnet = false; - trace_e1000e_cfg_support_virtio(false); - return; - } else { - s->core.has_vnet = true; - } - - for (i = 0; i < s->conf.peers.queues; i++) { - nc = qemu_get_subqueue(s->nic, i); - if (!nc->peer || !qemu_has_vnet_hdr(nc->peer)) { - s->core.has_vnet = false; - trace_e1000e_cfg_support_virtio(false); - return; - } - } - - trace_e1000e_cfg_support_virtio(true); - - for (i = 0; i < s->conf.peers.queues; i++) { - nc = qemu_get_subqueue(s->nic, i); - qemu_set_vnet_hdr_len(nc->peer, sizeof(struct virtio_net_hdr)); - qemu_using_vnet_hdr(nc->peer, true); - } -} - -static inline uint64_t -e1000e_gen_dsn(uint8_t *mac) -{ - return (uint64_t)(mac[5]) | - (uint64_t)(mac[4]) << 8 | - (uint64_t)(mac[3]) << 16 | - (uint64_t)(0x00FF) << 24 | - (uint64_t)(0x00FF) << 32 | - (uint64_t)(mac[2]) << 40 | - (uint64_t)(mac[1]) << 48 | - (uint64_t)(mac[0]) << 56; -} - -static int -e1000e_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc) -{ - int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset, PCI_PM_SIZEOF); - - if (ret >= 0) { - pci_set_word(pdev->config + offset + PCI_PM_PMC, - PCI_PM_CAP_VER_1_1 | - pmc); - - pci_set_word(pdev->wmask + offset + PCI_PM_CTRL, - PCI_PM_CTRL_STATE_MASK | - PCI_PM_CTRL_PME_ENABLE | - PCI_PM_CTRL_DATA_SEL_MASK); - - pci_set_word(pdev->w1cmask + offset + PCI_PM_CTRL, - PCI_PM_CTRL_PME_STATUS); - } - - return ret; -} - -static void e1000e_write_config(PCIDevice *pci_dev, uint32_t address, - uint32_t val, int len) -{ - E1000EState *s = E1000E(pci_dev); - - pci_default_write_config(pci_dev, address, val, len); - - if (range_covers_byte(address, len, PCI_COMMAND) && - (pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { - qemu_flush_queued_packets(qemu_get_queue(s->nic)); - } -} - -static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp) -{ - static const uint16_t e1000e_pmrb_offset = 0x0C8; - static const uint16_t e1000e_pcie_offset = 0x0E0; - static const uint16_t e1000e_aer_offset = 0x100; - static const uint16_t e1000e_dsn_offset = 0x140; - E1000EState *s = E1000E(pci_dev); - uint8_t *macaddr; - int ret; - - trace_e1000e_cb_pci_realize(); - - pci_dev->config_write = e1000e_write_config; - - pci_dev->config[PCI_CACHE_LINE_SIZE] = 0x10; - pci_dev->config[PCI_INTERRUPT_PIN] = 1; - - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, s->subsys_ven); - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, s->subsys); - - s->subsys_ven_used = s->subsys_ven; - s->subsys_used = s->subsys; - - /* Define IO/MMIO regions */ - memory_region_init_io(&s->mmio, OBJECT(s), &mmio_ops, s, - "e1000e-mmio", E1000E_MMIO_SIZE); - pci_register_bar(pci_dev, E1000E_MMIO_IDX, - PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio); - - /* - * We provide a dummy implementation for the flash BAR - * for drivers that may theoretically probe for its presence. - */ - memory_region_init(&s->flash, OBJECT(s), - "e1000e-flash", E1000E_FLASH_SIZE); - pci_register_bar(pci_dev, E1000E_FLASH_IDX, - PCI_BASE_ADDRESS_SPACE_MEMORY, &s->flash); - - memory_region_init_io(&s->io, OBJECT(s), &io_ops, s, - "e1000e-io", E1000E_IO_SIZE); - pci_register_bar(pci_dev, E1000E_IO_IDX, - PCI_BASE_ADDRESS_SPACE_IO, &s->io); - - memory_region_init(&s->msix, OBJECT(s), "e1000e-msix", - E1000E_MSIX_SIZE); - pci_register_bar(pci_dev, E1000E_MSIX_IDX, - PCI_BASE_ADDRESS_SPACE_MEMORY, &s->msix); - - /* Create networking backend */ - qemu_macaddr_default_if_unset(&s->conf.macaddr); - macaddr = s->conf.macaddr.a; - - e1000e_init_msix(s); - - if (pcie_endpoint_cap_v1_init(pci_dev, e1000e_pcie_offset) < 0) { - hw_error("Failed to initialize PCIe capability"); - } - - ret = msi_init(PCI_DEVICE(s), 0xD0, 1, true, false, NULL); - if (ret) { - trace_e1000e_msi_init_fail(ret); - } - - if (e1000e_add_pm_capability(pci_dev, e1000e_pmrb_offset, - PCI_PM_CAP_DSI) < 0) { - hw_error("Failed to initialize PM capability"); - } - - if (pcie_aer_init(pci_dev, e1000e_aer_offset, PCI_ERR_SIZEOF) < 0) { - hw_error("Failed to initialize AER capability"); - } - - pcie_dev_ser_num_init(pci_dev, e1000e_dsn_offset, - e1000e_gen_dsn(macaddr)); - - e1000e_init_net_peer(s, pci_dev, macaddr); - - /* Initialize core */ - e1000e_core_realize(s); - - e1000e_core_pci_realize(&s->core, - e1000e_eeprom_template, - sizeof(e1000e_eeprom_template), - macaddr); -} - -static void e1000e_pci_uninit(PCIDevice *pci_dev) -{ - E1000EState *s = E1000E(pci_dev); - - trace_e1000e_cb_pci_uninit(); - - e1000e_core_pci_uninit(&s->core); - - pcie_aer_exit(pci_dev); - pcie_cap_exit(pci_dev); - - qemu_del_nic(s->nic); - - e1000e_cleanup_msix(s); - msi_uninit(pci_dev); -} - -static void e1000e_qdev_reset(DeviceState *dev) -{ - E1000EState *s = E1000E(dev); - - trace_e1000e_cb_qdev_reset(); - - e1000e_core_reset(&s->core); -} - -static void e1000e_pre_save(void *opaque) -{ - E1000EState *s = opaque; - - trace_e1000e_cb_pre_save(); - - e1000e_core_pre_save(&s->core); -} - -static int e1000e_post_load(void *opaque, int version_id) -{ - E1000EState *s = opaque; - - trace_e1000e_cb_post_load(); - - if ((s->subsys != s->subsys_used) || - (s->subsys_ven != s->subsys_ven_used)) { - fprintf(stderr, - "ERROR: Cannot migrate while device properties " - "(subsys/subsys_ven) differ"); - return -1; - } - - return e1000e_core_post_load(&s->core); -} - -static const VMStateDescription e1000e_vmstate_tx = { - .name = "e1000e-tx", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(props.sum_needed, struct e1000e_tx), - VMSTATE_UINT8(props.ipcss, struct e1000e_tx), - VMSTATE_UINT8(props.ipcso, struct e1000e_tx), - VMSTATE_UINT16(props.ipcse, struct e1000e_tx), - VMSTATE_UINT8(props.tucss, struct e1000e_tx), - VMSTATE_UINT8(props.tucso, struct e1000e_tx), - VMSTATE_UINT16(props.tucse, struct e1000e_tx), - VMSTATE_UINT8(props.hdr_len, struct e1000e_tx), - VMSTATE_UINT16(props.mss, struct e1000e_tx), - VMSTATE_UINT32(props.paylen, struct e1000e_tx), - VMSTATE_INT8(props.ip, struct e1000e_tx), - VMSTATE_INT8(props.tcp, struct e1000e_tx), - VMSTATE_BOOL(props.tse, struct e1000e_tx), - VMSTATE_BOOL(props.cptse, struct e1000e_tx), - VMSTATE_BOOL(skip_cp, struct e1000e_tx), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription e1000e_vmstate_intr_timer = { - .name = "e1000e-intr-timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_TIMER_PTR(timer, E1000IntrDelayTimer), - VMSTATE_BOOL(running, E1000IntrDelayTimer), - VMSTATE_END_OF_LIST() - } -}; - -#define VMSTATE_E1000E_INTR_DELAY_TIMER(_f, _s) \ - VMSTATE_STRUCT(_f, _s, 0, \ - e1000e_vmstate_intr_timer, E1000IntrDelayTimer) - -#define VMSTATE_E1000E_INTR_DELAY_TIMER_ARRAY(_f, _s, _num) \ - VMSTATE_STRUCT_ARRAY(_f, _s, _num, 0, \ - e1000e_vmstate_intr_timer, E1000IntrDelayTimer) - -static const VMStateDescription e1000e_vmstate = { - .name = "e1000e", - .version_id = 1, - .minimum_version_id = 1, - .pre_save = e1000e_pre_save, - .post_load = e1000e_post_load, - .fields = (VMStateField[]) { - VMSTATE_PCIE_DEVICE(parent_obj, E1000EState), - VMSTATE_MSIX(parent_obj, E1000EState), - - VMSTATE_UINT32(ioaddr, E1000EState), - VMSTATE_UINT32(core.rxbuf_min_shift, E1000EState), - VMSTATE_UINT8(core.rx_desc_len, E1000EState), - VMSTATE_UINT32_ARRAY(core.rxbuf_sizes, E1000EState, - E1000_PSRCTL_BUFFS_PER_DESC), - VMSTATE_UINT32(core.rx_desc_buf_size, E1000EState), - VMSTATE_UINT16_ARRAY(core.eeprom, E1000EState, E1000E_EEPROM_SIZE), - VMSTATE_UINT16_2DARRAY(core.phy, E1000EState, - E1000E_PHY_PAGES, E1000E_PHY_PAGE_SIZE), - VMSTATE_UINT32_ARRAY(core.mac, E1000EState, E1000E_MAC_SIZE), - VMSTATE_UINT8_ARRAY(core.permanent_mac, E1000EState, ETH_ALEN), - - VMSTATE_UINT32(core.delayed_causes, E1000EState), - - VMSTATE_UINT16(subsys, E1000EState), - VMSTATE_UINT16(subsys_ven, E1000EState), - - VMSTATE_E1000E_INTR_DELAY_TIMER(core.rdtr, E1000EState), - VMSTATE_E1000E_INTR_DELAY_TIMER(core.radv, E1000EState), - VMSTATE_E1000E_INTR_DELAY_TIMER(core.raid, E1000EState), - VMSTATE_E1000E_INTR_DELAY_TIMER(core.tadv, E1000EState), - VMSTATE_E1000E_INTR_DELAY_TIMER(core.tidv, E1000EState), - - VMSTATE_E1000E_INTR_DELAY_TIMER(core.itr, E1000EState), - VMSTATE_BOOL(core.itr_intr_pending, E1000EState), - - VMSTATE_E1000E_INTR_DELAY_TIMER_ARRAY(core.eitr, E1000EState, - E1000E_MSIX_VEC_NUM), - VMSTATE_BOOL_ARRAY(core.eitr_intr_pending, E1000EState, - E1000E_MSIX_VEC_NUM), - - VMSTATE_UINT32(core.itr_guest_value, E1000EState), - VMSTATE_UINT32_ARRAY(core.eitr_guest_value, E1000EState, - E1000E_MSIX_VEC_NUM), - - VMSTATE_UINT16(core.vet, E1000EState), - - VMSTATE_STRUCT_ARRAY(core.tx, E1000EState, E1000E_NUM_QUEUES, 0, - e1000e_vmstate_tx, struct e1000e_tx), - VMSTATE_END_OF_LIST() - } -}; - -static PropertyInfo e1000e_prop_disable_vnet, - e1000e_prop_subsys_ven, - e1000e_prop_subsys; - -static Property e1000e_properties[] = { - DEFINE_NIC_PROPERTIES(E1000EState, conf), - DEFINE_PROP_DEFAULT("disable_vnet_hdr", E1000EState, disable_vnet, false, - e1000e_prop_disable_vnet, bool), - DEFINE_PROP_DEFAULT("subsys_ven", E1000EState, subsys_ven, - PCI_VENDOR_ID_INTEL, - e1000e_prop_subsys_ven, uint16_t), - DEFINE_PROP_DEFAULT("subsys", E1000EState, subsys, 0, - e1000e_prop_subsys, uint16_t), - DEFINE_PROP_END_OF_LIST(), -}; - -static void e1000e_class_init(ObjectClass *class, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(class); - PCIDeviceClass *c = PCI_DEVICE_CLASS(class); - - c->realize = e1000e_pci_realize; - c->exit = e1000e_pci_uninit; - c->vendor_id = PCI_VENDOR_ID_INTEL; - c->device_id = E1000_DEV_ID_82574L; - c->revision = 0; - c->romfile = "efi-e1000e.rom"; - c->class_id = PCI_CLASS_NETWORK_ETHERNET; - c->is_express = 1; - - dc->desc = "Intel 82574L GbE Controller"; - dc->reset = e1000e_qdev_reset; - dc->vmsd = &e1000e_vmstate; - dc->props = e1000e_properties; - - e1000e_prop_disable_vnet = qdev_prop_uint8; - e1000e_prop_disable_vnet.description = "Do not use virtio headers, " - "perform SW offloads emulation " - "instead"; - - e1000e_prop_subsys_ven = qdev_prop_uint16; - e1000e_prop_subsys_ven.description = "PCI device Subsystem Vendor ID"; - - e1000e_prop_subsys = qdev_prop_uint16; - e1000e_prop_subsys.description = "PCI device Subsystem ID"; - - set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); -} - -static void e1000e_instance_init(Object *obj) -{ - E1000EState *s = E1000E(obj); - device_add_bootindex_property(obj, &s->conf.bootindex, - "bootindex", "/ethernet-phy@0", - DEVICE(obj), NULL); -} - -static const TypeInfo e1000e_info = { - .name = TYPE_E1000E, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(E1000EState), - .class_init = e1000e_class_init, - .instance_init = e1000e_instance_init, -}; - -static void e1000e_register_types(void) -{ - type_register_static(&e1000e_info); -} - -type_init(e1000e_register_types) diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c deleted file mode 100644 index badb1feb7..000000000 --- a/hw/net/e1000e_core.c +++ /dev/null @@ -1,3483 +0,0 @@ -/* -* Core code for QEMU e1000e emulation -* -* Software developer's manuals: -* http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf -* -* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com) -* Developed by Daynix Computing LTD (http://www.daynix.com) -* -* Authors: -* Dmitry Fleytman <dmitry@daynix.com> -* Leonid Bloch <leonid@daynix.com> -* Yan Vugenfirer <yan@daynix.com> -* -* Based on work done by: -* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc. -* Copyright (c) 2008 Qumranet -* Based on work done by: -* Copyright (c) 2007 Dan Aloni -* Copyright (c) 2004 Antony T Curtis -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "qemu/osdep.h" -#include "sysemu/sysemu.h" -#include "net/net.h" -#include "net/tap.h" -#include "hw/pci/msi.h" -#include "hw/pci/msix.h" - -#include "net_tx_pkt.h" -#include "net_rx_pkt.h" - -#include "e1000x_common.h" -#include "e1000e_core.h" - -#include "trace.h" - -#define E1000E_MIN_XITR (500) /* No more then 7813 interrupts per - second according to spec 10.2.4.2 */ -#define E1000E_MAX_TX_FRAGS (64) - -static void -e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val); - -static inline void -e1000e_process_ts_option(E1000ECore *core, struct e1000_tx_desc *dp) -{ - if (le32_to_cpu(dp->upper.data) & E1000_TXD_EXTCMD_TSTAMP) { - trace_e1000e_wrn_no_ts_support(); - } -} - -static inline void -e1000e_process_snap_option(E1000ECore *core, uint32_t cmd_and_length) -{ - if (cmd_and_length & E1000_TXD_CMD_SNAP) { - trace_e1000e_wrn_no_snap_support(); - } -} - -static inline void -e1000e_raise_legacy_irq(E1000ECore *core) -{ - trace_e1000e_irq_legacy_notify(true); - e1000x_inc_reg_if_not_full(core->mac, IAC); - pci_set_irq(core->owner, 1); -} - -static inline void -e1000e_lower_legacy_irq(E1000ECore *core) -{ - trace_e1000e_irq_legacy_notify(false); - pci_set_irq(core->owner, 0); -} - -static inline void -e1000e_intrmgr_rearm_timer(E1000IntrDelayTimer *timer) -{ - int64_t delay_ns = (int64_t) timer->core->mac[timer->delay_reg] * - timer->delay_resolution_ns; - - trace_e1000e_irq_rearm_timer(timer->delay_reg << 2, delay_ns); - - timer_mod(timer->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + delay_ns); - - timer->running = true; -} - -static void -e1000e_intmgr_timer_resume(E1000IntrDelayTimer *timer) -{ - if (timer->running) { - e1000e_intrmgr_rearm_timer(timer); - } -} - -static void -e1000e_intmgr_timer_pause(E1000IntrDelayTimer *timer) -{ - if (timer->running) { - timer_del(timer->timer); - } -} - -static inline void -e1000e_intrmgr_stop_timer(E1000IntrDelayTimer *timer) -{ - if (timer->running) { - timer_del(timer->timer); - timer->running = false; - } -} - -static inline void -e1000e_intrmgr_fire_delayed_interrupts(E1000ECore *core) -{ - trace_e1000e_irq_fire_delayed_interrupts(); - e1000e_set_interrupt_cause(core, 0); -} - -static void -e1000e_intrmgr_on_timer(void *opaque) -{ - E1000IntrDelayTimer *timer = opaque; - - trace_e1000e_irq_throttling_timer(timer->delay_reg << 2); - - timer->running = false; - e1000e_intrmgr_fire_delayed_interrupts(timer->core); -} - -static void -e1000e_intrmgr_on_throttling_timer(void *opaque) -{ - E1000IntrDelayTimer *timer = opaque; - - assert(!msix_enabled(timer->core->owner)); - - timer->running = false; - - if (!timer->core->itr_intr_pending) { - trace_e1000e_irq_throttling_no_pending_interrupts(); - return; - } - - if (msi_enabled(timer->core->owner)) { - trace_e1000e_irq_msi_notify_postponed(); - e1000e_set_interrupt_cause(timer->core, 0); - } else { - trace_e1000e_irq_legacy_notify_postponed(); - e1000e_set_interrupt_cause(timer->core, 0); - } -} - -static void -e1000e_intrmgr_on_msix_throttling_timer(void *opaque) -{ - E1000IntrDelayTimer *timer = opaque; - int idx = timer - &timer->core->eitr[0]; - - assert(msix_enabled(timer->core->owner)); - - timer->running = false; - - if (!timer->core->eitr_intr_pending[idx]) { - trace_e1000e_irq_throttling_no_pending_vec(idx); - return; - } - - trace_e1000e_irq_msix_notify_postponed_vec(idx); - msix_notify(timer->core->owner, idx); -} - -static void -e1000e_intrmgr_initialize_all_timers(E1000ECore *core, bool create) -{ - int i; - - core->radv.delay_reg = RADV; - core->rdtr.delay_reg = RDTR; - core->raid.delay_reg = RAID; - core->tadv.delay_reg = TADV; - core->tidv.delay_reg = TIDV; - - core->radv.delay_resolution_ns = E1000_INTR_DELAY_NS_RES; - core->rdtr.delay_resolution_ns = E1000_INTR_DELAY_NS_RES; - core->raid.delay_resolution_ns = E1000_INTR_DELAY_NS_RES; - core->tadv.delay_resolution_ns = E1000_INTR_DELAY_NS_RES; - core->tidv.delay_resolution_ns = E1000_INTR_DELAY_NS_RES; - - core->radv.core = core; - core->rdtr.core = core; - core->raid.core = core; - core->tadv.core = core; - core->tidv.core = core; - - core->itr.core = core; - core->itr.delay_reg = ITR; - core->itr.delay_resolution_ns = E1000_INTR_THROTTLING_NS_RES; - - for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) { - core->eitr[i].core = core; - core->eitr[i].delay_reg = EITR + i; - core->eitr[i].delay_resolution_ns = E1000_INTR_THROTTLING_NS_RES; - } - - if (!create) { - return; - } - - core->radv.timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->radv); - core->rdtr.timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->rdtr); - core->raid.timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->raid); - - core->tadv.timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->tadv); - core->tidv.timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->tidv); - - core->itr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - e1000e_intrmgr_on_throttling_timer, - &core->itr); - - for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) { - core->eitr[i].timer = - timer_new_ns(QEMU_CLOCK_VIRTUAL, - e1000e_intrmgr_on_msix_throttling_timer, - &core->eitr[i]); - } -} - -static inline void -e1000e_intrmgr_stop_delay_timers(E1000ECore *core) -{ - e1000e_intrmgr_stop_timer(&core->radv); - e1000e_intrmgr_stop_timer(&core->rdtr); - e1000e_intrmgr_stop_timer(&core->raid); - e1000e_intrmgr_stop_timer(&core->tidv); - e1000e_intrmgr_stop_timer(&core->tadv); -} - -static bool -e1000e_intrmgr_delay_rx_causes(E1000ECore *core, uint32_t *causes) -{ - uint32_t delayable_causes; - uint32_t rdtr = core->mac[RDTR]; - uint32_t radv = core->mac[RADV]; - uint32_t raid = core->mac[RAID]; - - if (msix_enabled(core->owner)) { - return false; - } - - delayable_causes = E1000_ICR_RXQ0 | - E1000_ICR_RXQ1 | - E1000_ICR_RXT0; - - if (!(core->mac[RFCTL] & E1000_RFCTL_ACK_DIS)) { - delayable_causes |= E1000_ICR_ACK; - } - - /* Clean up all causes that may be delayed */ - core->delayed_causes |= *causes & delayable_causes; - *causes &= ~delayable_causes; - - /* Check if delayed RX interrupts disabled by client - or if there are causes that cannot be delayed */ - if ((rdtr == 0) || (*causes != 0)) { - return false; - } - - /* Check if delayed RX ACK interrupts disabled by client - and there is an ACK packet received */ - if ((raid == 0) && (core->delayed_causes & E1000_ICR_ACK)) { - return false; - } - - /* All causes delayed */ - e1000e_intrmgr_rearm_timer(&core->rdtr); - - if (!core->radv.running && (radv != 0)) { - e1000e_intrmgr_rearm_timer(&core->radv); - } - - if (!core->raid.running && (core->delayed_causes & E1000_ICR_ACK)) { - e1000e_intrmgr_rearm_timer(&core->raid); - } - - return true; -} - -static bool -e1000e_intrmgr_delay_tx_causes(E1000ECore *core, uint32_t *causes) -{ - static const uint32_t delayable_causes = E1000_ICR_TXQ0 | - E1000_ICR_TXQ1 | - E1000_ICR_TXQE | - E1000_ICR_TXDW; - - if (msix_enabled(core->owner)) { - return false; - } - - /* Clean up all causes that may be delayed */ - core->delayed_causes |= *causes & delayable_causes; - *causes &= ~delayable_causes; - - /* If there are causes that cannot be delayed */ - if (*causes != 0) { - return false; - } - - /* All causes delayed */ - e1000e_intrmgr_rearm_timer(&core->tidv); - - if (!core->tadv.running && (core->mac[TADV] != 0)) { - e1000e_intrmgr_rearm_timer(&core->tadv); - } - - return true; -} - -static uint32_t -e1000e_intmgr_collect_delayed_causes(E1000ECore *core) -{ - uint32_t res; - - if (msix_enabled(core->owner)) { - assert(core->delayed_causes == 0); - return 0; - } - - res = core->delayed_causes; - core->delayed_causes = 0; - - e1000e_intrmgr_stop_delay_timers(core); - - return res; -} - -static void -e1000e_intrmgr_fire_all_timers(E1000ECore *core) -{ - int i; - uint32_t val = e1000e_intmgr_collect_delayed_causes(core); - - trace_e1000e_irq_adding_delayed_causes(val, core->mac[ICR]); - core->mac[ICR] |= val; - - if (core->itr.running) { - timer_del(core->itr.timer); - e1000e_intrmgr_on_throttling_timer(&core->itr); - } - - for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) { - if (core->eitr[i].running) { - timer_del(core->eitr[i].timer); - e1000e_intrmgr_on_msix_throttling_timer(&core->eitr[i]); - } - } -} - -static void -e1000e_intrmgr_resume(E1000ECore *core) -{ - int i; - - e1000e_intmgr_timer_resume(&core->radv); - e1000e_intmgr_timer_resume(&core->rdtr); - e1000e_intmgr_timer_resume(&core->raid); - e1000e_intmgr_timer_resume(&core->tidv); - e1000e_intmgr_timer_resume(&core->tadv); - - e1000e_intmgr_timer_resume(&core->itr); - - for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) { - e1000e_intmgr_timer_resume(&core->eitr[i]); - } -} - -static void -e1000e_intrmgr_pause(E1000ECore *core) -{ - int i; - - e1000e_intmgr_timer_pause(&core->radv); - e1000e_intmgr_timer_pause(&core->rdtr); - e1000e_intmgr_timer_pause(&core->raid); - e1000e_intmgr_timer_pause(&core->tidv); - e1000e_intmgr_timer_pause(&core->tadv); - - e1000e_intmgr_timer_pause(&core->itr); - - for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) { - e1000e_intmgr_timer_pause(&core->eitr[i]); - } -} - -static void -e1000e_intrmgr_reset(E1000ECore *core) -{ - int i; - - core->delayed_causes = 0; - - e1000e_intrmgr_stop_delay_timers(core); - - e1000e_intrmgr_stop_timer(&core->itr); - - for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) { - e1000e_intrmgr_stop_timer(&core->eitr[i]); - } -} - -static void -e1000e_intrmgr_pci_unint(E1000ECore *core) -{ - int i; - - timer_del(core->radv.timer); - timer_free(core->radv.timer); - timer_del(core->rdtr.timer); - timer_free(core->rdtr.timer); - timer_del(core->raid.timer); - timer_free(core->raid.timer); - - timer_del(core->tadv.timer); - timer_free(core->tadv.timer); - timer_del(core->tidv.timer); - timer_free(core->tidv.timer); - - timer_del(core->itr.timer); - timer_free(core->itr.timer); - - for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) { - timer_del(core->eitr[i].timer); - timer_free(core->eitr[i].timer); - } -} - -static void -e1000e_intrmgr_pci_realize(E1000ECore *core) -{ - e1000e_intrmgr_initialize_all_timers(core, true); -} - -static inline bool -e1000e_rx_csum_enabled(E1000ECore *core) -{ - return (core->mac[RXCSUM] & E1000_RXCSUM_PCSD) ? false : true; -} - -static inline bool -e1000e_rx_use_legacy_descriptor(E1000ECore *core) -{ - return (core->mac[RFCTL] & E1000_RFCTL_EXTEN) ? false : true; -} - -static inline bool -e1000e_rx_use_ps_descriptor(E1000ECore *core) -{ - return !e1000e_rx_use_legacy_descriptor(core) && - (core->mac[RCTL] & E1000_RCTL_DTYP_PS); -} - -static inline bool -e1000e_rss_enabled(E1000ECore *core) -{ - return E1000_MRQC_ENABLED(core->mac[MRQC]) && - !e1000e_rx_csum_enabled(core) && - !e1000e_rx_use_legacy_descriptor(core); -} - -typedef struct E1000E_RSSInfo_st { - bool enabled; - uint32_t hash; - uint32_t queue; - uint32_t type; -} E1000E_RSSInfo; - -static uint32_t -e1000e_rss_get_hash_type(E1000ECore *core, struct NetRxPkt *pkt) -{ - bool isip4, isip6, isudp, istcp; - - assert(e1000e_rss_enabled(core)); - - net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); - - if (isip4) { - bool fragment = net_rx_pkt_get_ip4_info(pkt)->fragment; - - trace_e1000e_rx_rss_ip4(fragment, istcp, core->mac[MRQC], - E1000_MRQC_EN_TCPIPV4(core->mac[MRQC]), - E1000_MRQC_EN_IPV4(core->mac[MRQC])); - - if (!fragment && istcp && E1000_MRQC_EN_TCPIPV4(core->mac[MRQC])) { - return E1000_MRQ_RSS_TYPE_IPV4TCP; - } - - if (E1000_MRQC_EN_IPV4(core->mac[MRQC])) { - return E1000_MRQ_RSS_TYPE_IPV4; - } - } else if (isip6) { - eth_ip6_hdr_info *ip6info = net_rx_pkt_get_ip6_info(pkt); - - bool ex_dis = core->mac[RFCTL] & E1000_RFCTL_IPV6_EX_DIS; - bool new_ex_dis = core->mac[RFCTL] & E1000_RFCTL_NEW_IPV6_EXT_DIS; - - /* - * Following two traces must not be combined because resulting - * event will have 11 arguments totally and some trace backends - * (at least "ust") have limitation of maximum 10 arguments per - * event. Events with more arguments fail to compile for - * backends like these. - */ - trace_e1000e_rx_rss_ip6_rfctl(core->mac[RFCTL]); - trace_e1000e_rx_rss_ip6(ex_dis, new_ex_dis, istcp, - ip6info->has_ext_hdrs, - ip6info->rss_ex_dst_valid, - ip6info->rss_ex_src_valid, - core->mac[MRQC], - E1000_MRQC_EN_TCPIPV6(core->mac[MRQC]), - E1000_MRQC_EN_IPV6EX(core->mac[MRQC]), - E1000_MRQC_EN_IPV6(core->mac[MRQC])); - - if ((!ex_dis || !ip6info->has_ext_hdrs) && - (!new_ex_dis || !(ip6info->rss_ex_dst_valid || - ip6info->rss_ex_src_valid))) { - - if (istcp && !ip6info->fragment && - E1000_MRQC_EN_TCPIPV6(core->mac[MRQC])) { - return E1000_MRQ_RSS_TYPE_IPV6TCP; - } - - if (E1000_MRQC_EN_IPV6EX(core->mac[MRQC])) { - return E1000_MRQ_RSS_TYPE_IPV6EX; - } - - } - - if (E1000_MRQC_EN_IPV6(core->mac[MRQC])) { - return E1000_MRQ_RSS_TYPE_IPV6; - } - - } - - return E1000_MRQ_RSS_TYPE_NONE; -} - -static uint32_t -e1000e_rss_calc_hash(E1000ECore *core, - struct NetRxPkt *pkt, - E1000E_RSSInfo *info) -{ - NetRxPktRssType type; - - assert(e1000e_rss_enabled(core)); - - switch (info->type) { - case E1000_MRQ_RSS_TYPE_IPV4: - type = NetPktRssIpV4; - break; - case E1000_MRQ_RSS_TYPE_IPV4TCP: - type = NetPktRssIpV4Tcp; - break; - case E1000_MRQ_RSS_TYPE_IPV6TCP: - type = NetPktRssIpV6Tcp; - break; - case E1000_MRQ_RSS_TYPE_IPV6: - type = NetPktRssIpV6; - break; - case E1000_MRQ_RSS_TYPE_IPV6EX: - type = NetPktRssIpV6Ex; - break; - default: - assert(false); - return 0; - } - - return net_rx_pkt_calc_rss_hash(pkt, type, (uint8_t *) &core->mac[RSSRK]); -} - -static void -e1000e_rss_parse_packet(E1000ECore *core, - struct NetRxPkt *pkt, - E1000E_RSSInfo *info) -{ - trace_e1000e_rx_rss_started(); - - if (!e1000e_rss_enabled(core)) { - info->enabled = false; - info->hash = 0; - info->queue = 0; - info->type = 0; - trace_e1000e_rx_rss_disabled(); - return; - } - - info->enabled = true; - - info->type = e1000e_rss_get_hash_type(core, pkt); - - trace_e1000e_rx_rss_type(info->type); - - if (info->type == E1000_MRQ_RSS_TYPE_NONE) { - info->hash = 0; - info->queue = 0; - return; - } - - info->hash = e1000e_rss_calc_hash(core, pkt, info); - info->queue = E1000_RSS_QUEUE(&core->mac[RETA], info->hash); -} - -static void -e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx) -{ - if (tx->props.tse && tx->props.cptse) { - net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->props.mss); - net_tx_pkt_update_ip_checksums(tx->tx_pkt); - e1000x_inc_reg_if_not_full(core->mac, TSCTC); - return; - } - - if (tx->props.sum_needed & E1000_TXD_POPTS_TXSM) { - net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0); - } - - if (tx->props.sum_needed & E1000_TXD_POPTS_IXSM) { - net_tx_pkt_update_ip_hdr_checksum(tx->tx_pkt); - } -} - -static bool -e1000e_tx_pkt_send(E1000ECore *core, struct e1000e_tx *tx, int queue_index) -{ - int target_queue = MIN(core->max_queue_num, queue_index); - NetClientState *queue = qemu_get_subqueue(core->owner_nic, target_queue); - - e1000e_setup_tx_offloads(core, tx); - - net_tx_pkt_dump(tx->tx_pkt); - - if ((core->phy[0][PHY_CTRL] & MII_CR_LOOPBACK) || - ((core->mac[RCTL] & E1000_RCTL_LBM_MAC) == E1000_RCTL_LBM_MAC)) { - return net_tx_pkt_send_loopback(tx->tx_pkt, queue); - } else { - return net_tx_pkt_send(tx->tx_pkt, queue); - } -} - -static void -e1000e_on_tx_done_update_stats(E1000ECore *core, struct NetTxPkt *tx_pkt) -{ - static const int PTCregs[6] = { PTC64, PTC127, PTC255, PTC511, - PTC1023, PTC1522 }; - - size_t tot_len = net_tx_pkt_get_total_len(tx_pkt); - - e1000x_increase_size_stats(core->mac, PTCregs, tot_len); - e1000x_inc_reg_if_not_full(core->mac, TPT); - e1000x_grow_8reg_if_not_full(core->mac, TOTL, tot_len); - - switch (net_tx_pkt_get_packet_type(tx_pkt)) { - case ETH_PKT_BCAST: - e1000x_inc_reg_if_not_full(core->mac, BPTC); - break; - case ETH_PKT_MCAST: - e1000x_inc_reg_if_not_full(core->mac, MPTC); - break; - case ETH_PKT_UCAST: - break; - default: - g_assert_not_reached(); - } - - core->mac[GPTC] = core->mac[TPT]; - core->mac[GOTCL] = core->mac[TOTL]; - core->mac[GOTCH] = core->mac[TOTH]; -} - -static void -e1000e_process_tx_desc(E1000ECore *core, - struct e1000e_tx *tx, - struct e1000_tx_desc *dp, - int queue_index) -{ - uint32_t txd_lower = le32_to_cpu(dp->lower.data); - uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D); - unsigned int split_size = txd_lower & 0xffff; - uint64_t addr; - struct e1000_context_desc *xp = (struct e1000_context_desc *)dp; - bool eop = txd_lower & E1000_TXD_CMD_EOP; - - if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */ - e1000x_read_tx_ctx_descr(xp, &tx->props); - e1000e_process_snap_option(core, le32_to_cpu(xp->cmd_and_length)); - return; - } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { - /* data descriptor */ - tx->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8; - tx->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; - e1000e_process_ts_option(core, dp); - } else { - /* legacy descriptor */ - e1000e_process_ts_option(core, dp); - tx->props.cptse = 0; - } - - addr = le64_to_cpu(dp->buffer_addr); - - if (!tx->skip_cp) { - if (!net_tx_pkt_add_raw_fragment(tx->tx_pkt, addr, split_size)) { - tx->skip_cp = true; - } - } - - if (eop) { - if (!tx->skip_cp && net_tx_pkt_parse(tx->tx_pkt)) { - if (e1000x_vlan_enabled(core->mac) && - e1000x_is_vlan_txd(txd_lower)) { - net_tx_pkt_setup_vlan_header_ex(tx->tx_pkt, - le16_to_cpu(dp->upper.fields.special), core->vet); - } - if (e1000e_tx_pkt_send(core, tx, queue_index)) { - e1000e_on_tx_done_update_stats(core, tx->tx_pkt); - } - } - - tx->skip_cp = false; - net_tx_pkt_reset(tx->tx_pkt); - - tx->props.sum_needed = 0; - tx->props.cptse = 0; - } -} - -static inline uint32_t -e1000e_tx_wb_interrupt_cause(E1000ECore *core, int queue_idx) -{ - if (!msix_enabled(core->owner)) { - return E1000_ICR_TXDW; - } - - return (queue_idx == 0) ? E1000_ICR_TXQ0 : E1000_ICR_TXQ1; -} - -static inline uint32_t -e1000e_rx_wb_interrupt_cause(E1000ECore *core, int queue_idx, - bool min_threshold_hit) -{ - if (!msix_enabled(core->owner)) { - return E1000_ICS_RXT0 | (min_threshold_hit ? E1000_ICS_RXDMT0 : 0); - } - - return (queue_idx == 0) ? E1000_ICR_RXQ0 : E1000_ICR_RXQ1; -} - -static uint32_t -e1000e_txdesc_writeback(E1000ECore *core, dma_addr_t base, - struct e1000_tx_desc *dp, bool *ide, int queue_idx) -{ - uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data); - - if (!(txd_lower & E1000_TXD_CMD_RS) && - !(core->mac[IVAR] & E1000_IVAR_TX_INT_EVERY_WB)) { - return 0; - } - - *ide = (txd_lower & E1000_TXD_CMD_IDE) ? true : false; - - txd_upper = le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD; - - dp->upper.data = cpu_to_le32(txd_upper); - pci_dma_write(core->owner, base + ((char *)&dp->upper - (char *)dp), - &dp->upper, sizeof(dp->upper)); - return e1000e_tx_wb_interrupt_cause(core, queue_idx); -} - -typedef struct E1000E_RingInfo_st { - int dbah; - int dbal; - int dlen; - int dh; - int dt; - int idx; -} E1000E_RingInfo; - -static inline bool -e1000e_ring_empty(E1000ECore *core, const E1000E_RingInfo *r) -{ - return core->mac[r->dh] == core->mac[r->dt]; -} - -static inline uint64_t -e1000e_ring_base(E1000ECore *core, const E1000E_RingInfo *r) -{ - uint64_t bah = core->mac[r->dbah]; - uint64_t bal = core->mac[r->dbal]; - - return (bah << 32) + bal; -} - -static inline uint64_t -e1000e_ring_head_descr(E1000ECore *core, const E1000E_RingInfo *r) -{ - return e1000e_ring_base(core, r) + E1000_RING_DESC_LEN * core->mac[r->dh]; -} - -static inline void -e1000e_ring_advance(E1000ECore *core, const E1000E_RingInfo *r, uint32_t count) -{ - core->mac[r->dh] += count; - - if (core->mac[r->dh] * E1000_RING_DESC_LEN >= core->mac[r->dlen]) { - core->mac[r->dh] = 0; - } -} - -static inline uint32_t -e1000e_ring_free_descr_num(E1000ECore *core, const E1000E_RingInfo *r) -{ - trace_e1000e_ring_free_space(r->idx, core->mac[r->dlen], - core->mac[r->dh], core->mac[r->dt]); - - if (core->mac[r->dh] <= core->mac[r->dt]) { - return core->mac[r->dt] - core->mac[r->dh]; - } - - if (core->mac[r->dh] > core->mac[r->dt]) { - return core->mac[r->dlen] / E1000_RING_DESC_LEN + - core->mac[r->dt] - core->mac[r->dh]; - } - - g_assert_not_reached(); - return 0; -} - -static inline bool -e1000e_ring_enabled(E1000ECore *core, const E1000E_RingInfo *r) -{ - return core->mac[r->dlen] > 0; -} - -static inline uint32_t -e1000e_ring_len(E1000ECore *core, const E1000E_RingInfo *r) -{ - return core->mac[r->dlen]; -} - -typedef struct E1000E_TxRing_st { - const E1000E_RingInfo *i; - struct e1000e_tx *tx; -} E1000E_TxRing; - -static inline int -e1000e_mq_queue_idx(int base_reg_idx, int reg_idx) -{ - return (reg_idx - base_reg_idx) / (0x100 >> 2); -} - -static inline void -e1000e_tx_ring_init(E1000ECore *core, E1000E_TxRing *txr, int idx) -{ - static const E1000E_RingInfo i[E1000E_NUM_QUEUES] = { - { TDBAH, TDBAL, TDLEN, TDH, TDT, 0 }, - { TDBAH1, TDBAL1, TDLEN1, TDH1, TDT1, 1 } - }; - - assert(idx < ARRAY_SIZE(i)); - - txr->i = &i[idx]; - txr->tx = &core->tx[idx]; -} - -typedef struct E1000E_RxRing_st { - const E1000E_RingInfo *i; -} E1000E_RxRing; - -static inline void -e1000e_rx_ring_init(E1000ECore *core, E1000E_RxRing *rxr, int idx) -{ - static const E1000E_RingInfo i[E1000E_NUM_QUEUES] = { - { RDBAH0, RDBAL0, RDLEN0, RDH0, RDT0, 0 }, - { RDBAH1, RDBAL1, RDLEN1, RDH1, RDT1, 1 } - }; - - assert(idx < ARRAY_SIZE(i)); - - rxr->i = &i[idx]; -} - -static void -e1000e_start_xmit(E1000ECore *core, const E1000E_TxRing *txr) -{ - dma_addr_t base; - struct e1000_tx_desc desc; - bool ide = false; - const E1000E_RingInfo *txi = txr->i; - uint32_t cause = E1000_ICS_TXQE; - - if (!(core->mac[TCTL] & E1000_TCTL_EN)) { - trace_e1000e_tx_disabled(); - return; - } - - while (!e1000e_ring_empty(core, txi)) { - base = e1000e_ring_head_descr(core, txi); - - pci_dma_read(core->owner, base, &desc, sizeof(desc)); - - trace_e1000e_tx_descr((void *)(intptr_t)desc.buffer_addr, - desc.lower.data, desc.upper.data); - - e1000e_process_tx_desc(core, txr->tx, &desc, txi->idx); - cause |= e1000e_txdesc_writeback(core, base, &desc, &ide, txi->idx); - - e1000e_ring_advance(core, txi, 1); - } - - if (!ide || !e1000e_intrmgr_delay_tx_causes(core, &cause)) { - e1000e_set_interrupt_cause(core, cause); - } -} - -static bool -e1000e_has_rxbufs(E1000ECore *core, const E1000E_RingInfo *r, - size_t total_size) -{ - uint32_t bufs = e1000e_ring_free_descr_num(core, r); - - trace_e1000e_rx_has_buffers(r->idx, bufs, total_size, - core->rx_desc_buf_size); - - return total_size <= bufs / (core->rx_desc_len / E1000_MIN_RX_DESC_LEN) * - core->rx_desc_buf_size; -} - -static inline void -e1000e_start_recv(E1000ECore *core) -{ - int i; - - trace_e1000e_rx_start_recv(); - - for (i = 0; i <= core->max_queue_num; i++) { - qemu_flush_queued_packets(qemu_get_subqueue(core->owner_nic, i)); - } -} - -int -e1000e_can_receive(E1000ECore *core) -{ - int i; - - if (!e1000x_rx_ready(core->owner, core->mac)) { - return false; - } - - for (i = 0; i < E1000E_NUM_QUEUES; i++) { - E1000E_RxRing rxr; - - e1000e_rx_ring_init(core, &rxr, i); - if (e1000e_ring_enabled(core, rxr.i) && - e1000e_has_rxbufs(core, rxr.i, 1)) { - trace_e1000e_rx_can_recv(); - return true; - } - } - - trace_e1000e_rx_can_recv_rings_full(); - return false; -} - -ssize_t -e1000e_receive(E1000ECore *core, const uint8_t *buf, size_t size) -{ - const struct iovec iov = { - .iov_base = (uint8_t *)buf, - .iov_len = size - }; - - return e1000e_receive_iov(core, &iov, 1); -} - -static inline bool -e1000e_rx_l3_cso_enabled(E1000ECore *core) -{ - return !!(core->mac[RXCSUM] & E1000_RXCSUM_IPOFLD); -} - -static inline bool -e1000e_rx_l4_cso_enabled(E1000ECore *core) -{ - return !!(core->mac[RXCSUM] & E1000_RXCSUM_TUOFLD); -} - -static bool -e1000e_receive_filter(E1000ECore *core, const uint8_t *buf, int size) -{ - uint32_t rctl = core->mac[RCTL]; - - if (e1000x_is_vlan_packet(buf, core->vet) && - e1000x_vlan_rx_filter_enabled(core->mac)) { - uint16_t vid = lduw_be_p(buf + 14); - uint32_t vfta = ldl_le_p((uint32_t *)(core->mac + VFTA) + - ((vid >> 5) & 0x7f)); - if ((vfta & (1 << (vid & 0x1f))) == 0) { - trace_e1000e_rx_flt_vlan_mismatch(vid); - return false; - } else { - trace_e1000e_rx_flt_vlan_match(vid); - } - } - - switch (net_rx_pkt_get_packet_type(core->rx_pkt)) { - case ETH_PKT_UCAST: - if (rctl & E1000_RCTL_UPE) { - return true; /* promiscuous ucast */ - } - break; - - case ETH_PKT_BCAST: - if (rctl & E1000_RCTL_BAM) { - return true; /* broadcast enabled */ - } - break; - - case ETH_PKT_MCAST: - if (rctl & E1000_RCTL_MPE) { - return true; /* promiscuous mcast */ - } - break; - - default: - g_assert_not_reached(); - } - - return e1000x_rx_group_filter(core->mac, buf); -} - -static inline void -e1000e_read_lgcy_rx_descr(E1000ECore *core, uint8_t *desc, hwaddr *buff_addr) -{ - struct e1000_rx_desc *d = (struct e1000_rx_desc *) desc; - *buff_addr = le64_to_cpu(d->buffer_addr); -} - -static inline void -e1000e_read_ext_rx_descr(E1000ECore *core, uint8_t *desc, hwaddr *buff_addr) -{ - union e1000_rx_desc_extended *d = (union e1000_rx_desc_extended *) desc; - *buff_addr = le64_to_cpu(d->read.buffer_addr); -} - -static inline void -e1000e_read_ps_rx_descr(E1000ECore *core, uint8_t *desc, - hwaddr (*buff_addr)[MAX_PS_BUFFERS]) -{ - int i; - union e1000_rx_desc_packet_split *d = - (union e1000_rx_desc_packet_split *) desc; - - for (i = 0; i < MAX_PS_BUFFERS; i++) { - (*buff_addr)[i] = le64_to_cpu(d->read.buffer_addr[i]); - } - - trace_e1000e_rx_desc_ps_read((*buff_addr)[0], (*buff_addr)[1], - (*buff_addr)[2], (*buff_addr)[3]); -} - -static inline void -e1000e_read_rx_descr(E1000ECore *core, uint8_t *desc, - hwaddr (*buff_addr)[MAX_PS_BUFFERS]) -{ - if (e1000e_rx_use_legacy_descriptor(core)) { - e1000e_read_lgcy_rx_descr(core, desc, &(*buff_addr)[0]); - (*buff_addr)[1] = (*buff_addr)[2] = (*buff_addr)[3] = 0; - } else { - if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) { - e1000e_read_ps_rx_descr(core, desc, buff_addr); - } else { - e1000e_read_ext_rx_descr(core, desc, &(*buff_addr)[0]); - (*buff_addr)[1] = (*buff_addr)[2] = (*buff_addr)[3] = 0; - } - } -} - -static void -e1000e_verify_csum_in_sw(E1000ECore *core, - struct NetRxPkt *pkt, - uint32_t *status_flags, - bool istcp, bool isudp) -{ - bool csum_valid; - uint32_t csum_error; - - if (e1000e_rx_l3_cso_enabled(core)) { - if (!net_rx_pkt_validate_l3_csum(pkt, &csum_valid)) { - trace_e1000e_rx_metadata_l3_csum_validation_failed(); - } else { - csum_error = csum_valid ? 0 : E1000_RXDEXT_STATERR_IPE; - *status_flags |= E1000_RXD_STAT_IPCS | csum_error; - } - } else { - trace_e1000e_rx_metadata_l3_cso_disabled(); - } - - if (!e1000e_rx_l4_cso_enabled(core)) { - trace_e1000e_rx_metadata_l4_cso_disabled(); - return; - } - - if (!net_rx_pkt_validate_l4_csum(pkt, &csum_valid)) { - trace_e1000e_rx_metadata_l4_csum_validation_failed(); - return; - } - - csum_error = csum_valid ? 0 : E1000_RXDEXT_STATERR_TCPE; - - if (istcp) { - *status_flags |= E1000_RXD_STAT_TCPCS | - csum_error; - } else if (isudp) { - *status_flags |= E1000_RXD_STAT_TCPCS | - E1000_RXD_STAT_UDPCS | - csum_error; - } -} - -static inline bool -e1000e_is_tcp_ack(E1000ECore *core, struct NetRxPkt *rx_pkt) -{ - if (!net_rx_pkt_is_tcp_ack(rx_pkt)) { - return false; - } - - if (core->mac[RFCTL] & E1000_RFCTL_ACK_DATA_DIS) { - return !net_rx_pkt_has_tcp_data(rx_pkt); - } - - return true; -} - -static void -e1000e_build_rx_metadata(E1000ECore *core, - struct NetRxPkt *pkt, - bool is_eop, - const E1000E_RSSInfo *rss_info, - uint32_t *rss, uint32_t *mrq, - uint32_t *status_flags, - uint16_t *ip_id, - uint16_t *vlan_tag) -{ - struct virtio_net_hdr *vhdr; - bool isip4, isip6, istcp, isudp; - uint32_t pkt_type; - - *status_flags = E1000_RXD_STAT_DD; - - /* No additional metadata needed for non-EOP descriptors */ - if (!is_eop) { - goto func_exit; - } - - *status_flags |= E1000_RXD_STAT_EOP; - - net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); - trace_e1000e_rx_metadata_protocols(isip4, isip6, isudp, istcp); - - /* VLAN state */ - if (net_rx_pkt_is_vlan_stripped(pkt)) { - *status_flags |= E1000_RXD_STAT_VP; - *vlan_tag = cpu_to_le16(net_rx_pkt_get_vlan_tag(pkt)); - trace_e1000e_rx_metadata_vlan(*vlan_tag); - } - - /* Packet parsing results */ - if ((core->mac[RXCSUM] & E1000_RXCSUM_PCSD) != 0) { - if (rss_info->enabled) { - *rss = cpu_to_le32(rss_info->hash); - *mrq = cpu_to_le32(rss_info->type | (rss_info->queue << 8)); - trace_e1000e_rx_metadata_rss(*rss, *mrq); - } - } else if (isip4) { - *status_flags |= E1000_RXD_STAT_IPIDV; - *ip_id = cpu_to_le16(net_rx_pkt_get_ip_id(pkt)); - trace_e1000e_rx_metadata_ip_id(*ip_id); - } - - if (istcp && e1000e_is_tcp_ack(core, pkt)) { - *status_flags |= E1000_RXD_STAT_ACK; - trace_e1000e_rx_metadata_ack(); - } - - if (isip6 && (core->mac[RFCTL] & E1000_RFCTL_IPV6_DIS)) { - trace_e1000e_rx_metadata_ipv6_filtering_disabled(); - pkt_type = E1000_RXD_PKT_MAC; - } else if (istcp || isudp) { - pkt_type = isip4 ? E1000_RXD_PKT_IP4_XDP : E1000_RXD_PKT_IP6_XDP; - } else if (isip4 || isip6) { - pkt_type = isip4 ? E1000_RXD_PKT_IP4 : E1000_RXD_PKT_IP6; - } else { - pkt_type = E1000_RXD_PKT_MAC; - } - - *status_flags |= E1000_RXD_PKT_TYPE(pkt_type); - trace_e1000e_rx_metadata_pkt_type(pkt_type); - - /* RX CSO information */ - if (isip6 && (core->mac[RFCTL] & E1000_RFCTL_IPV6_XSUM_DIS)) { - trace_e1000e_rx_metadata_ipv6_sum_disabled(); - goto func_exit; - } - - if (!net_rx_pkt_has_virt_hdr(pkt)) { - trace_e1000e_rx_metadata_no_virthdr(); - e1000e_verify_csum_in_sw(core, pkt, status_flags, istcp, isudp); - goto func_exit; - } - - vhdr = net_rx_pkt_get_vhdr(pkt); - - if (!(vhdr->flags & VIRTIO_NET_HDR_F_DATA_VALID) && - !(vhdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) { - trace_e1000e_rx_metadata_virthdr_no_csum_info(); - e1000e_verify_csum_in_sw(core, pkt, status_flags, istcp, isudp); - goto func_exit; - } - - if (e1000e_rx_l3_cso_enabled(core)) { - *status_flags |= isip4 ? E1000_RXD_STAT_IPCS : 0; - } else { - trace_e1000e_rx_metadata_l3_cso_disabled(); - } - - if (e1000e_rx_l4_cso_enabled(core)) { - if (istcp) { - *status_flags |= E1000_RXD_STAT_TCPCS; - } else if (isudp) { - *status_flags |= E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS; - } - } else { - trace_e1000e_rx_metadata_l4_cso_disabled(); - } - - trace_e1000e_rx_metadata_status_flags(*status_flags); - -func_exit: - *status_flags = cpu_to_le32(*status_flags); -} - -static inline void -e1000e_write_lgcy_rx_descr(E1000ECore *core, uint8_t *desc, - struct NetRxPkt *pkt, - const E1000E_RSSInfo *rss_info, - uint16_t length) -{ - uint32_t status_flags, rss, mrq; - uint16_t ip_id; - - struct e1000_rx_desc *d = (struct e1000_rx_desc *) desc; - - memset(d, 0, sizeof(*d)); - - assert(!rss_info->enabled); - - d->length = cpu_to_le16(length); - - e1000e_build_rx_metadata(core, pkt, pkt != NULL, - rss_info, - &rss, &mrq, - &status_flags, &ip_id, - &d->special); - d->errors = (uint8_t) (le32_to_cpu(status_flags) >> 24); - d->status = (uint8_t) le32_to_cpu(status_flags); -} - -static inline void -e1000e_write_ext_rx_descr(E1000ECore *core, uint8_t *desc, - struct NetRxPkt *pkt, - const E1000E_RSSInfo *rss_info, - uint16_t length) -{ - union e1000_rx_desc_extended *d = (union e1000_rx_desc_extended *) desc; - - memset(d, 0, sizeof(*d)); - - d->wb.upper.length = cpu_to_le16(length); - - e1000e_build_rx_metadata(core, pkt, pkt != NULL, - rss_info, - &d->wb.lower.hi_dword.rss, - &d->wb.lower.mrq, - &d->wb.upper.status_error, - &d->wb.lower.hi_dword.csum_ip.ip_id, - &d->wb.upper.vlan); -} - -static inline void -e1000e_write_ps_rx_descr(E1000ECore *core, uint8_t *desc, - struct NetRxPkt *pkt, - const E1000E_RSSInfo *rss_info, - size_t ps_hdr_len, - uint16_t(*written)[MAX_PS_BUFFERS]) -{ - int i; - union e1000_rx_desc_packet_split *d = - (union e1000_rx_desc_packet_split *) desc; - - memset(d, 0, sizeof(*d)); - - d->wb.middle.length0 = cpu_to_le16((*written)[0]); - - for (i = 0; i < PS_PAGE_BUFFERS; i++) { - d->wb.upper.length[i] = cpu_to_le16((*written)[i + 1]); - } - - e1000e_build_rx_metadata(core, pkt, pkt != NULL, - rss_info, - &d->wb.lower.hi_dword.rss, - &d->wb.lower.mrq, - &d->wb.middle.status_error, - &d->wb.lower.hi_dword.csum_ip.ip_id, - &d->wb.middle.vlan); - - d->wb.upper.header_status = - cpu_to_le16(ps_hdr_len | (ps_hdr_len ? E1000_RXDPS_HDRSTAT_HDRSP : 0)); - - trace_e1000e_rx_desc_ps_write((*written)[0], (*written)[1], - (*written)[2], (*written)[3]); -} - -static inline void -e1000e_write_rx_descr(E1000ECore *core, uint8_t *desc, -struct NetRxPkt *pkt, const E1000E_RSSInfo *rss_info, - size_t ps_hdr_len, uint16_t(*written)[MAX_PS_BUFFERS]) -{ - if (e1000e_rx_use_legacy_descriptor(core)) { - assert(ps_hdr_len == 0); - e1000e_write_lgcy_rx_descr(core, desc, pkt, rss_info, (*written)[0]); - } else { - if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) { - e1000e_write_ps_rx_descr(core, desc, pkt, rss_info, - ps_hdr_len, written); - } else { - assert(ps_hdr_len == 0); - e1000e_write_ext_rx_descr(core, desc, pkt, rss_info, - (*written)[0]); - } - } -} - -typedef struct e1000e_ba_state_st { - uint16_t written[MAX_PS_BUFFERS]; - uint8_t cur_idx; -} e1000e_ba_state; - -static inline void -e1000e_write_hdr_to_rx_buffers(E1000ECore *core, - hwaddr (*ba)[MAX_PS_BUFFERS], - e1000e_ba_state *bastate, - const char *data, - dma_addr_t data_len) -{ - assert(data_len <= core->rxbuf_sizes[0] - bastate->written[0]); - - pci_dma_write(core->owner, (*ba)[0] + bastate->written[0], data, data_len); - bastate->written[0] += data_len; - - bastate->cur_idx = 1; -} - -static void -e1000e_write_to_rx_buffers(E1000ECore *core, - hwaddr (*ba)[MAX_PS_BUFFERS], - e1000e_ba_state *bastate, - const char *data, - dma_addr_t data_len) -{ - while (data_len > 0) { - uint32_t cur_buf_len = core->rxbuf_sizes[bastate->cur_idx]; - uint32_t cur_buf_bytes_left = cur_buf_len - - bastate->written[bastate->cur_idx]; - uint32_t bytes_to_write = MIN(data_len, cur_buf_bytes_left); - - trace_e1000e_rx_desc_buff_write(bastate->cur_idx, - (*ba)[bastate->cur_idx], - bastate->written[bastate->cur_idx], - data, - bytes_to_write); - - pci_dma_write(core->owner, - (*ba)[bastate->cur_idx] + bastate->written[bastate->cur_idx], - data, bytes_to_write); - - bastate->written[bastate->cur_idx] += bytes_to_write; - data += bytes_to_write; - data_len -= bytes_to_write; - - if (bastate->written[bastate->cur_idx] == cur_buf_len) { - bastate->cur_idx++; - } - - assert(bastate->cur_idx < MAX_PS_BUFFERS); - } -} - -static void -e1000e_update_rx_stats(E1000ECore *core, - size_t data_size, - size_t data_fcs_size) -{ - e1000x_update_rx_total_stats(core->mac, data_size, data_fcs_size); - - switch (net_rx_pkt_get_packet_type(core->rx_pkt)) { - case ETH_PKT_BCAST: - e1000x_inc_reg_if_not_full(core->mac, BPRC); - break; - - case ETH_PKT_MCAST: - e1000x_inc_reg_if_not_full(core->mac, MPRC); - break; - - default: - break; - } -} - -static inline bool -e1000e_rx_descr_threshold_hit(E1000ECore *core, const E1000E_RingInfo *rxi) -{ - return e1000e_ring_free_descr_num(core, rxi) == - e1000e_ring_len(core, rxi) >> core->rxbuf_min_shift; -} - -static bool -e1000e_do_ps(E1000ECore *core, struct NetRxPkt *pkt, size_t *hdr_len) -{ - bool isip4, isip6, isudp, istcp; - bool fragment; - - if (!e1000e_rx_use_ps_descriptor(core)) { - return false; - } - - net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); - - if (isip4) { - fragment = net_rx_pkt_get_ip4_info(pkt)->fragment; - } else if (isip6) { - fragment = net_rx_pkt_get_ip6_info(pkt)->fragment; - } else { - return false; - } - - if (fragment && (core->mac[RFCTL] & E1000_RFCTL_IPFRSP_DIS)) { - return false; - } - - if (!fragment && (isudp || istcp)) { - *hdr_len = net_rx_pkt_get_l5_hdr_offset(pkt); - } else { - *hdr_len = net_rx_pkt_get_l4_hdr_offset(pkt); - } - - if ((*hdr_len > core->rxbuf_sizes[0]) || - (*hdr_len > net_rx_pkt_get_total_len(pkt))) { - return false; - } - - return true; -} - -static void -e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, - const E1000E_RxRing *rxr, - const E1000E_RSSInfo *rss_info) -{ - PCIDevice *d = core->owner; - dma_addr_t base; - uint8_t desc[E1000_MAX_RX_DESC_LEN]; - size_t desc_size; - size_t desc_offset = 0; - size_t iov_ofs = 0; - - struct iovec *iov = net_rx_pkt_get_iovec(pkt); - size_t size = net_rx_pkt_get_total_len(pkt); - size_t total_size = size + e1000x_fcs_len(core->mac); - const E1000E_RingInfo *rxi; - size_t ps_hdr_len = 0; - bool do_ps = e1000e_do_ps(core, pkt, &ps_hdr_len); - - rxi = rxr->i; - - do { - hwaddr ba[MAX_PS_BUFFERS]; - e1000e_ba_state bastate = { { 0 } }; - bool is_last = false; - bool is_first = true; - - desc_size = total_size - desc_offset; - - if (desc_size > core->rx_desc_buf_size) { - desc_size = core->rx_desc_buf_size; - } - - base = e1000e_ring_head_descr(core, rxi); - - pci_dma_read(d, base, &desc, core->rx_desc_len); - - trace_e1000e_rx_descr(rxi->idx, base, core->rx_desc_len); - - e1000e_read_rx_descr(core, desc, &ba); - - if (ba[0]) { - if (desc_offset < size) { - static const uint32_t fcs_pad; - size_t iov_copy; - size_t copy_size = size - desc_offset; - if (copy_size > core->rx_desc_buf_size) { - copy_size = core->rx_desc_buf_size; - } - - /* For PS mode copy the packet header first */ - if (do_ps) { - if (is_first) { - size_t ps_hdr_copied = 0; - do { - iov_copy = MIN(ps_hdr_len - ps_hdr_copied, - iov->iov_len - iov_ofs); - - e1000e_write_hdr_to_rx_buffers(core, &ba, &bastate, - iov->iov_base, iov_copy); - - copy_size -= iov_copy; - ps_hdr_copied += iov_copy; - - iov_ofs += iov_copy; - if (iov_ofs == iov->iov_len) { - iov++; - iov_ofs = 0; - } - } while (ps_hdr_copied < ps_hdr_len); - - is_first = false; - } else { - /* Leave buffer 0 of each descriptor except first */ - /* empty as per spec 7.1.5.1 */ - e1000e_write_hdr_to_rx_buffers(core, &ba, &bastate, - NULL, 0); - } - } - - /* Copy packet payload */ - while (copy_size) { - iov_copy = MIN(copy_size, iov->iov_len - iov_ofs); - - e1000e_write_to_rx_buffers(core, &ba, &bastate, - iov->iov_base + iov_ofs, iov_copy); - - copy_size -= iov_copy; - iov_ofs += iov_copy; - if (iov_ofs == iov->iov_len) { - iov++; - iov_ofs = 0; - } - } - - if (desc_offset + desc_size >= total_size) { - /* Simulate FCS checksum presence in the last descriptor */ - e1000e_write_to_rx_buffers(core, &ba, &bastate, - (const char *) &fcs_pad, e1000x_fcs_len(core->mac)); - } - } - desc_offset += desc_size; - if (desc_offset >= total_size) { - is_last = true; - } - } else { /* as per intel docs; skip descriptors with null buf addr */ - trace_e1000e_rx_null_descriptor(); - } - - e1000e_write_rx_descr(core, desc, is_last ? core->rx_pkt : NULL, - rss_info, do_ps ? ps_hdr_len : 0, &bastate.written); - pci_dma_write(d, base, &desc, core->rx_desc_len); - - e1000e_ring_advance(core, rxi, - core->rx_desc_len / E1000_MIN_RX_DESC_LEN); - - } while (desc_offset < total_size); - - e1000e_update_rx_stats(core, size, total_size); -} - -static inline void -e1000e_rx_fix_l4_csum(E1000ECore *core, struct NetRxPkt *pkt) -{ - if (net_rx_pkt_has_virt_hdr(pkt)) { - struct virtio_net_hdr *vhdr = net_rx_pkt_get_vhdr(pkt); - - if (vhdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { - net_rx_pkt_fix_l4_csum(pkt); - } - } -} - -ssize_t -e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt) -{ - static const int maximum_ethernet_hdr_len = (14 + 4); - /* Min. octets in an ethernet frame sans FCS */ - static const int min_buf_size = 60; - - uint32_t n = 0; - uint8_t min_buf[min_buf_size]; - struct iovec min_iov; - uint8_t *filter_buf; - size_t size, orig_size; - size_t iov_ofs = 0; - E1000E_RxRing rxr; - E1000E_RSSInfo rss_info; - size_t total_size; - ssize_t retval; - bool rdmts_hit; - - trace_e1000e_rx_receive_iov(iovcnt); - - if (!e1000x_hw_rx_enabled(core->mac)) { - return -1; - } - - /* Pull virtio header in */ - if (core->has_vnet) { - net_rx_pkt_set_vhdr_iovec(core->rx_pkt, iov, iovcnt); - iov_ofs = sizeof(struct virtio_net_hdr); - } - - filter_buf = iov->iov_base + iov_ofs; - orig_size = iov_size(iov, iovcnt); - size = orig_size - iov_ofs; - - /* Pad to minimum Ethernet frame length */ - if (size < sizeof(min_buf)) { - iov_to_buf(iov, iovcnt, iov_ofs, min_buf, size); - memset(&min_buf[size], 0, sizeof(min_buf) - size); - e1000x_inc_reg_if_not_full(core->mac, RUC); - min_iov.iov_base = filter_buf = min_buf; - min_iov.iov_len = size = sizeof(min_buf); - iovcnt = 1; - iov = &min_iov; - iov_ofs = 0; - } else if (iov->iov_len < maximum_ethernet_hdr_len) { - /* This is very unlikely, but may happen. */ - iov_to_buf(iov, iovcnt, iov_ofs, min_buf, maximum_ethernet_hdr_len); - filter_buf = min_buf; - } - - /* Discard oversized packets if !LPE and !SBP. */ - if (e1000x_is_oversized(core->mac, size)) { - return orig_size; - } - - net_rx_pkt_set_packet_type(core->rx_pkt, - get_eth_packet_type(PKT_GET_ETH_HDR(filter_buf))); - - if (!e1000e_receive_filter(core, filter_buf, size)) { - trace_e1000e_rx_flt_dropped(); - return orig_size; - } - - net_rx_pkt_attach_iovec_ex(core->rx_pkt, iov, iovcnt, iov_ofs, - e1000x_vlan_enabled(core->mac), core->vet); - - e1000e_rss_parse_packet(core, core->rx_pkt, &rss_info); - e1000e_rx_ring_init(core, &rxr, rss_info.queue); - - trace_e1000e_rx_rss_dispatched_to_queue(rxr.i->idx); - - total_size = net_rx_pkt_get_total_len(core->rx_pkt) + - e1000x_fcs_len(core->mac); - - if (e1000e_has_rxbufs(core, rxr.i, total_size)) { - e1000e_rx_fix_l4_csum(core, core->rx_pkt); - - e1000e_write_packet_to_guest(core, core->rx_pkt, &rxr, &rss_info); - - retval = orig_size; - - /* Perform small receive detection (RSRPD) */ - if (total_size < core->mac[RSRPD]) { - n |= E1000_ICS_SRPD; - } - - /* Perform ACK receive detection */ - if (e1000e_is_tcp_ack(core, core->rx_pkt)) { - n |= E1000_ICS_ACK; - } - - /* Check if receive descriptor minimum threshold hit */ - rdmts_hit = e1000e_rx_descr_threshold_hit(core, rxr.i); - n |= e1000e_rx_wb_interrupt_cause(core, rxr.i->idx, rdmts_hit); - - trace_e1000e_rx_written_to_guest(n); - } else { - n |= E1000_ICS_RXO; - retval = 0; - - trace_e1000e_rx_not_written_to_guest(n); - } - - if (!e1000e_intrmgr_delay_rx_causes(core, &n)) { - trace_e1000e_rx_interrupt_set(n); - e1000e_set_interrupt_cause(core, n); - } else { - trace_e1000e_rx_interrupt_delayed(n); - } - - return retval; -} - -static inline bool -e1000e_have_autoneg(E1000ECore *core) -{ - return core->phy[0][PHY_CTRL] & MII_CR_AUTO_NEG_EN; -} - -static void e1000e_update_flowctl_status(E1000ECore *core) -{ - if (e1000e_have_autoneg(core) && - core->phy[0][PHY_STATUS] & MII_SR_AUTONEG_COMPLETE) { - trace_e1000e_link_autoneg_flowctl(true); - core->mac[CTRL] |= E1000_CTRL_TFCE | E1000_CTRL_RFCE; - } else { - trace_e1000e_link_autoneg_flowctl(false); - } -} - -static inline void -e1000e_link_down(E1000ECore *core) -{ - e1000x_update_regs_on_link_down(core->mac, core->phy[0]); - e1000e_update_flowctl_status(core); -} - -static inline void -e1000e_set_phy_ctrl(E1000ECore *core, int index, uint16_t val) -{ - /* bits 0-5 reserved; MII_CR_[RESTART_AUTO_NEG,RESET] are self clearing */ - core->phy[0][PHY_CTRL] = val & ~(0x3f | - MII_CR_RESET | - MII_CR_RESTART_AUTO_NEG); - - if ((val & MII_CR_RESTART_AUTO_NEG) && - e1000e_have_autoneg(core)) { - e1000x_restart_autoneg(core->mac, core->phy[0], core->autoneg_timer); - } -} - -static void -e1000e_set_phy_oem_bits(E1000ECore *core, int index, uint16_t val) -{ - core->phy[0][PHY_OEM_BITS] = val & ~BIT(10); - - if (val & BIT(10)) { - e1000x_restart_autoneg(core->mac, core->phy[0], core->autoneg_timer); - } -} - -static void -e1000e_set_phy_page(E1000ECore *core, int index, uint16_t val) -{ - core->phy[0][PHY_PAGE] = val & PHY_PAGE_RW_MASK; -} - -void -e1000e_core_set_link_status(E1000ECore *core) -{ - NetClientState *nc = qemu_get_queue(core->owner_nic); - uint32_t old_status = core->mac[STATUS]; - - trace_e1000e_link_status_changed(nc->link_down ? false : true); - - if (nc->link_down) { - e1000x_update_regs_on_link_down(core->mac, core->phy[0]); - } else { - if (e1000e_have_autoneg(core) && - !(core->phy[0][PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) { - e1000x_restart_autoneg(core->mac, core->phy[0], - core->autoneg_timer); - } else { - e1000x_update_regs_on_link_up(core->mac, core->phy[0]); - } - } - - if (core->mac[STATUS] != old_status) { - e1000e_set_interrupt_cause(core, E1000_ICR_LSC); - } -} - -static void -e1000e_set_ctrl(E1000ECore *core, int index, uint32_t val) -{ - trace_e1000e_core_ctrl_write(index, val); - - /* RST is self clearing */ - core->mac[CTRL] = val & ~E1000_CTRL_RST; - core->mac[CTRL_DUP] = core->mac[CTRL]; - - trace_e1000e_link_set_params( - !!(val & E1000_CTRL_ASDE), - (val & E1000_CTRL_SPD_SEL) >> E1000_CTRL_SPD_SHIFT, - !!(val & E1000_CTRL_FRCSPD), - !!(val & E1000_CTRL_FRCDPX), - !!(val & E1000_CTRL_RFCE), - !!(val & E1000_CTRL_TFCE)); - - if (val & E1000_CTRL_RST) { - trace_e1000e_core_ctrl_sw_reset(); - e1000x_reset_mac_addr(core->owner_nic, core->mac, core->permanent_mac); - } - - if (val & E1000_CTRL_PHY_RST) { - trace_e1000e_core_ctrl_phy_reset(); - core->mac[STATUS] |= E1000_STATUS_PHYRA; - } -} - -static void -e1000e_set_rfctl(E1000ECore *core, int index, uint32_t val) -{ - trace_e1000e_rx_set_rfctl(val); - - if (!(val & E1000_RFCTL_ISCSI_DIS)) { - trace_e1000e_wrn_iscsi_filtering_not_supported(); - } - - if (!(val & E1000_RFCTL_NFSW_DIS)) { - trace_e1000e_wrn_nfsw_filtering_not_supported(); - } - - if (!(val & E1000_RFCTL_NFSR_DIS)) { - trace_e1000e_wrn_nfsr_filtering_not_supported(); - } - - core->mac[RFCTL] = val; -} - -static void -e1000e_calc_per_desc_buf_size(E1000ECore *core) -{ - int i; - core->rx_desc_buf_size = 0; - - for (i = 0; i < ARRAY_SIZE(core->rxbuf_sizes); i++) { - core->rx_desc_buf_size += core->rxbuf_sizes[i]; - } -} - -static void -e1000e_parse_rxbufsize(E1000ECore *core) -{ - uint32_t rctl = core->mac[RCTL]; - - memset(core->rxbuf_sizes, 0, sizeof(core->rxbuf_sizes)); - - if (rctl & E1000_RCTL_DTYP_MASK) { - uint32_t bsize; - - bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE0_MASK; - core->rxbuf_sizes[0] = (bsize >> E1000_PSRCTL_BSIZE0_SHIFT) * 128; - - bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE1_MASK; - core->rxbuf_sizes[1] = (bsize >> E1000_PSRCTL_BSIZE1_SHIFT) * 1024; - - bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE2_MASK; - core->rxbuf_sizes[2] = (bsize >> E1000_PSRCTL_BSIZE2_SHIFT) * 1024; - - bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE3_MASK; - core->rxbuf_sizes[3] = (bsize >> E1000_PSRCTL_BSIZE3_SHIFT) * 1024; - } else if (rctl & E1000_RCTL_FLXBUF_MASK) { - int flxbuf = rctl & E1000_RCTL_FLXBUF_MASK; - core->rxbuf_sizes[0] = (flxbuf >> E1000_RCTL_FLXBUF_SHIFT) * 1024; - } else { - core->rxbuf_sizes[0] = e1000x_rxbufsize(rctl); - } - - trace_e1000e_rx_desc_buff_sizes(core->rxbuf_sizes[0], core->rxbuf_sizes[1], - core->rxbuf_sizes[2], core->rxbuf_sizes[3]); - - e1000e_calc_per_desc_buf_size(core); -} - -static void -e1000e_calc_rxdesclen(E1000ECore *core) -{ - if (e1000e_rx_use_legacy_descriptor(core)) { - core->rx_desc_len = sizeof(struct e1000_rx_desc); - } else { - if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) { - core->rx_desc_len = sizeof(union e1000_rx_desc_packet_split); - } else { - core->rx_desc_len = sizeof(union e1000_rx_desc_extended); - } - } - trace_e1000e_rx_desc_len(core->rx_desc_len); -} - -static void -e1000e_set_rx_control(E1000ECore *core, int index, uint32_t val) -{ - core->mac[RCTL] = val; - trace_e1000e_rx_set_rctl(core->mac[RCTL]); - - if (val & E1000_RCTL_EN) { - e1000e_parse_rxbufsize(core); - e1000e_calc_rxdesclen(core); - core->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1 + - E1000_RING_DESC_LEN_SHIFT; - - e1000e_start_recv(core); - } -} - -static -void(*e1000e_phyreg_writeops[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE]) -(E1000ECore *, int, uint16_t) = { - [0] = { - [PHY_CTRL] = e1000e_set_phy_ctrl, - [PHY_PAGE] = e1000e_set_phy_page, - [PHY_OEM_BITS] = e1000e_set_phy_oem_bits - } -}; - -static inline void -e1000e_clear_ims_bits(E1000ECore *core, uint32_t bits) -{ - trace_e1000e_irq_clear_ims(bits, core->mac[IMS], core->mac[IMS] & ~bits); - core->mac[IMS] &= ~bits; -} - -static inline bool -e1000e_postpone_interrupt(bool *interrupt_pending, - E1000IntrDelayTimer *timer) -{ - if (timer->running) { - trace_e1000e_irq_postponed_by_xitr(timer->delay_reg << 2); - - *interrupt_pending = true; - return true; - } - - if (timer->core->mac[timer->delay_reg] != 0) { - e1000e_intrmgr_rearm_timer(timer); - } - - return false; -} - -static inline bool -e1000e_itr_should_postpone(E1000ECore *core) -{ - return e1000e_postpone_interrupt(&core->itr_intr_pending, &core->itr); -} - -static inline bool -e1000e_eitr_should_postpone(E1000ECore *core, int idx) -{ - return e1000e_postpone_interrupt(&core->eitr_intr_pending[idx], - &core->eitr[idx]); -} - -static void -e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg) -{ - uint32_t effective_eiac; - - if (E1000_IVAR_ENTRY_VALID(int_cfg)) { - uint32_t vec = E1000_IVAR_ENTRY_VEC(int_cfg); - if (vec < E1000E_MSIX_VEC_NUM) { - if (!e1000e_eitr_should_postpone(core, vec)) { - trace_e1000e_irq_msix_notify_vec(vec); - msix_notify(core->owner, vec); - } - } else { - trace_e1000e_wrn_msix_vec_wrong(cause, int_cfg); - } - } else { - trace_e1000e_wrn_msix_invalid(cause, int_cfg); - } - - if (core->mac[CTRL_EXT] & E1000_CTRL_EXT_EIAME) { - trace_e1000e_irq_ims_clear_eiame(core->mac[IAM], cause); - e1000e_clear_ims_bits(core, core->mac[IAM] & cause); - } - - trace_e1000e_irq_icr_clear_eiac(core->mac[ICR], core->mac[EIAC]); - - if (core->mac[EIAC] & E1000_ICR_OTHER) { - effective_eiac = (core->mac[EIAC] & E1000_EIAC_MASK) | - E1000_ICR_OTHER_CAUSES; - } else { - effective_eiac = core->mac[EIAC] & E1000_EIAC_MASK; - } - core->mac[ICR] &= ~effective_eiac; -} - -static void -e1000e_msix_notify(E1000ECore *core, uint32_t causes) -{ - if (causes & E1000_ICR_RXQ0) { - e1000e_msix_notify_one(core, E1000_ICR_RXQ0, - E1000_IVAR_RXQ0(core->mac[IVAR])); - } - - if (causes & E1000_ICR_RXQ1) { - e1000e_msix_notify_one(core, E1000_ICR_RXQ1, - E1000_IVAR_RXQ1(core->mac[IVAR])); - } - - if (causes & E1000_ICR_TXQ0) { - e1000e_msix_notify_one(core, E1000_ICR_TXQ0, - E1000_IVAR_TXQ0(core->mac[IVAR])); - } - - if (causes & E1000_ICR_TXQ1) { - e1000e_msix_notify_one(core, E1000_ICR_TXQ1, - E1000_IVAR_TXQ1(core->mac[IVAR])); - } - - if (causes & E1000_ICR_OTHER) { - e1000e_msix_notify_one(core, E1000_ICR_OTHER, - E1000_IVAR_OTHER(core->mac[IVAR])); - } -} - -static void -e1000e_msix_clear_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg) -{ - if (E1000_IVAR_ENTRY_VALID(int_cfg)) { - uint32_t vec = E1000_IVAR_ENTRY_VEC(int_cfg); - if (vec < E1000E_MSIX_VEC_NUM) { - trace_e1000e_irq_msix_pending_clearing(cause, int_cfg, vec); - msix_clr_pending(core->owner, vec); - } else { - trace_e1000e_wrn_msix_vec_wrong(cause, int_cfg); - } - } else { - trace_e1000e_wrn_msix_invalid(cause, int_cfg); - } -} - -static void -e1000e_msix_clear(E1000ECore *core, uint32_t causes) -{ - if (causes & E1000_ICR_RXQ0) { - e1000e_msix_clear_one(core, E1000_ICR_RXQ0, - E1000_IVAR_RXQ0(core->mac[IVAR])); - } - - if (causes & E1000_ICR_RXQ1) { - e1000e_msix_clear_one(core, E1000_ICR_RXQ1, - E1000_IVAR_RXQ1(core->mac[IVAR])); - } - - if (causes & E1000_ICR_TXQ0) { - e1000e_msix_clear_one(core, E1000_ICR_TXQ0, - E1000_IVAR_TXQ0(core->mac[IVAR])); - } - - if (causes & E1000_ICR_TXQ1) { - e1000e_msix_clear_one(core, E1000_ICR_TXQ1, - E1000_IVAR_TXQ1(core->mac[IVAR])); - } - - if (causes & E1000_ICR_OTHER) { - e1000e_msix_clear_one(core, E1000_ICR_OTHER, - E1000_IVAR_OTHER(core->mac[IVAR])); - } -} - -static inline void -e1000e_fix_icr_asserted(E1000ECore *core) -{ - core->mac[ICR] &= ~E1000_ICR_ASSERTED; - if (core->mac[ICR]) { - core->mac[ICR] |= E1000_ICR_ASSERTED; - } - - trace_e1000e_irq_fix_icr_asserted(core->mac[ICR]); -} - -static void -e1000e_send_msi(E1000ECore *core, bool msix) -{ - uint32_t causes = core->mac[ICR] & core->mac[IMS] & ~E1000_ICR_ASSERTED; - - if (msix) { - e1000e_msix_notify(core, causes); - } else { - if (!e1000e_itr_should_postpone(core)) { - trace_e1000e_irq_msi_notify(causes); - msi_notify(core->owner, 0); - } - } -} - -static void -e1000e_update_interrupt_state(E1000ECore *core) -{ - bool interrupts_pending; - bool is_msix = msix_enabled(core->owner); - - /* Set ICR[OTHER] for MSI-X */ - if (is_msix) { - if (core->mac[ICR] & core->mac[IMS] & E1000_ICR_OTHER_CAUSES) { - core->mac[ICR] |= E1000_ICR_OTHER; - trace_e1000e_irq_add_msi_other(core->mac[ICR]); - } - } - - e1000e_fix_icr_asserted(core); - - /* - * Make sure ICR and ICS registers have the same value. - * The spec says that the ICS register is write-only. However in practice, - * on real hardware ICS is readable, and for reads it has the same value as - * ICR (except that ICS does not have the clear on read behaviour of ICR). - * - * The VxWorks PRO/1000 driver uses this behaviour. - */ - core->mac[ICS] = core->mac[ICR]; - - interrupts_pending = (core->mac[IMS] & core->mac[ICR]) ? true : false; - - trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS], - core->mac[ICR], core->mac[IMS]); - - if (is_msix || msi_enabled(core->owner)) { - if (interrupts_pending) { - e1000e_send_msi(core, is_msix); - } - } else { - if (interrupts_pending) { - if (!e1000e_itr_should_postpone(core)) { - e1000e_raise_legacy_irq(core); - } - } else { - e1000e_lower_legacy_irq(core); - } - } -} - -static inline void -e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val) -{ - trace_e1000e_irq_set_cause_entry(val, core->mac[ICR]); - - val |= e1000e_intmgr_collect_delayed_causes(core); - core->mac[ICR] |= val; - - trace_e1000e_irq_set_cause_exit(val, core->mac[ICR]); - - e1000e_update_interrupt_state(core); -} - -static inline void -e1000e_autoneg_timer(void *opaque) -{ - E1000ECore *core = opaque; - if (!qemu_get_queue(core->owner_nic)->link_down) { - e1000x_update_regs_on_autoneg_done(core->mac, core->phy[0]); - e1000e_update_flowctl_status(core); - /* signal link status change to the guest */ - e1000e_set_interrupt_cause(core, E1000_ICR_LSC); - } -} - -static inline uint16_t -e1000e_get_reg_index_with_offset(const uint16_t *mac_reg_access, hwaddr addr) -{ - uint16_t index = (addr & 0x1ffff) >> 2; - return index + (mac_reg_access[index] & 0xfffe); -} - -static const char e1000e_phy_regcap[E1000E_PHY_PAGES][0x20] = { - [0] = { - [PHY_CTRL] = PHY_ANYPAGE | PHY_RW, - [PHY_STATUS] = PHY_ANYPAGE | PHY_R, - [PHY_ID1] = PHY_ANYPAGE | PHY_R, - [PHY_ID2] = PHY_ANYPAGE | PHY_R, - [PHY_AUTONEG_ADV] = PHY_ANYPAGE | PHY_RW, - [PHY_LP_ABILITY] = PHY_ANYPAGE | PHY_R, - [PHY_AUTONEG_EXP] = PHY_ANYPAGE | PHY_R, - [PHY_NEXT_PAGE_TX] = PHY_ANYPAGE | PHY_RW, - [PHY_LP_NEXT_PAGE] = PHY_ANYPAGE | PHY_R, - [PHY_1000T_CTRL] = PHY_ANYPAGE | PHY_RW, - [PHY_1000T_STATUS] = PHY_ANYPAGE | PHY_R, - [PHY_EXT_STATUS] = PHY_ANYPAGE | PHY_R, - [PHY_PAGE] = PHY_ANYPAGE | PHY_RW, - - [PHY_COPPER_CTRL1] = PHY_RW, - [PHY_COPPER_STAT1] = PHY_R, - [PHY_COPPER_CTRL3] = PHY_RW, - [PHY_RX_ERR_CNTR] = PHY_R, - [PHY_OEM_BITS] = PHY_RW, - [PHY_BIAS_1] = PHY_RW, - [PHY_BIAS_2] = PHY_RW, - [PHY_COPPER_INT_ENABLE] = PHY_RW, - [PHY_COPPER_STAT2] = PHY_R, - [PHY_COPPER_CTRL2] = PHY_RW - }, - [2] = { - [PHY_MAC_CTRL1] = PHY_RW, - [PHY_MAC_INT_ENABLE] = PHY_RW, - [PHY_MAC_STAT] = PHY_R, - [PHY_MAC_CTRL2] = PHY_RW - }, - [3] = { - [PHY_LED_03_FUNC_CTRL1] = PHY_RW, - [PHY_LED_03_POL_CTRL] = PHY_RW, - [PHY_LED_TIMER_CTRL] = PHY_RW, - [PHY_LED_45_CTRL] = PHY_RW - }, - [5] = { - [PHY_1000T_SKEW] = PHY_R, - [PHY_1000T_SWAP] = PHY_R - }, - [6] = { - [PHY_CRC_COUNTERS] = PHY_R - } -}; - -static bool -e1000e_phy_reg_check_cap(E1000ECore *core, uint32_t addr, - char cap, uint8_t *page) -{ - *page = - (e1000e_phy_regcap[0][addr] & PHY_ANYPAGE) ? 0 - : core->phy[0][PHY_PAGE]; - - if (*page >= E1000E_PHY_PAGES) { - return false; - } - - return e1000e_phy_regcap[*page][addr] & cap; -} - -static void -e1000e_phy_reg_write(E1000ECore *core, uint8_t page, - uint32_t addr, uint16_t data) -{ - assert(page < E1000E_PHY_PAGES); - assert(addr < E1000E_PHY_PAGE_SIZE); - - if (e1000e_phyreg_writeops[page][addr]) { - e1000e_phyreg_writeops[page][addr](core, addr, data); - } else { - core->phy[page][addr] = data; - } -} - -static void -e1000e_set_mdic(E1000ECore *core, int index, uint32_t val) -{ - uint32_t data = val & E1000_MDIC_DATA_MASK; - uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT); - uint8_t page; - - if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) { /* phy # */ - val = core->mac[MDIC] | E1000_MDIC_ERROR; - } else if (val & E1000_MDIC_OP_READ) { - if (!e1000e_phy_reg_check_cap(core, addr, PHY_R, &page)) { - trace_e1000e_core_mdic_read_unhandled(page, addr); - val |= E1000_MDIC_ERROR; - } else { - val = (val ^ data) | core->phy[page][addr]; - trace_e1000e_core_mdic_read(page, addr, val); - } - } else if (val & E1000_MDIC_OP_WRITE) { - if (!e1000e_phy_reg_check_cap(core, addr, PHY_W, &page)) { - trace_e1000e_core_mdic_write_unhandled(page, addr); - val |= E1000_MDIC_ERROR; - } else { - trace_e1000e_core_mdic_write(page, addr, data); - e1000e_phy_reg_write(core, page, addr, data); - } - } - core->mac[MDIC] = val | E1000_MDIC_READY; - - if (val & E1000_MDIC_INT_EN) { - e1000e_set_interrupt_cause(core, E1000_ICR_MDAC); - } -} - -static void -e1000e_set_rdt(E1000ECore *core, int index, uint32_t val) -{ - core->mac[index] = val & 0xffff; - trace_e1000e_rx_set_rdt(e1000e_mq_queue_idx(RDT0, index), val); - e1000e_start_recv(core); -} - -static void -e1000e_set_status(E1000ECore *core, int index, uint32_t val) -{ - if ((val & E1000_STATUS_PHYRA) == 0) { - core->mac[index] &= ~E1000_STATUS_PHYRA; - } -} - -static void -e1000e_set_ctrlext(E1000ECore *core, int index, uint32_t val) -{ - trace_e1000e_link_set_ext_params(!!(val & E1000_CTRL_EXT_ASDCHK), - !!(val & E1000_CTRL_EXT_SPD_BYPS)); - - /* Zero self-clearing bits */ - val &= ~(E1000_CTRL_EXT_ASDCHK | E1000_CTRL_EXT_EE_RST); - core->mac[CTRL_EXT] = val; -} - -static void -e1000e_set_pbaclr(E1000ECore *core, int index, uint32_t val) -{ - int i; - - core->mac[PBACLR] = val & E1000_PBACLR_VALID_MASK; - - if (msix_enabled(core->owner)) { - return; - } - - for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) { - if (core->mac[PBACLR] & BIT(i)) { - msix_clr_pending(core->owner, i); - } - } -} - -static void -e1000e_set_fcrth(E1000ECore *core, int index, uint32_t val) -{ - core->mac[FCRTH] = val & 0xFFF8; -} - -static void -e1000e_set_fcrtl(E1000ECore *core, int index, uint32_t val) -{ - core->mac[FCRTL] = val & 0x8000FFF8; -} - -static inline void -e1000e_set_16bit(E1000ECore *core, int index, uint32_t val) -{ - core->mac[index] = val & 0xffff; -} - -static void -e1000e_set_12bit(E1000ECore *core, int index, uint32_t val) -{ - core->mac[index] = val & 0xfff; -} - -static void -e1000e_set_vet(E1000ECore *core, int index, uint32_t val) -{ - core->mac[VET] = val & 0xffff; - core->vet = le16_to_cpu(core->mac[VET]); - trace_e1000e_vlan_vet(core->vet); -} - -static void -e1000e_set_dlen(E1000ECore *core, int index, uint32_t val) -{ - core->mac[index] = val & E1000_XDLEN_MASK; -} - -static void -e1000e_set_dbal(E1000ECore *core, int index, uint32_t val) -{ - core->mac[index] = val & E1000_XDBAL_MASK; -} - -static void -e1000e_set_tctl(E1000ECore *core, int index, uint32_t val) -{ - E1000E_TxRing txr; - core->mac[index] = val; - - if (core->mac[TARC0] & E1000_TARC_ENABLE) { - e1000e_tx_ring_init(core, &txr, 0); - e1000e_start_xmit(core, &txr); - } - - if (core->mac[TARC1] & E1000_TARC_ENABLE) { - e1000e_tx_ring_init(core, &txr, 1); - e1000e_start_xmit(core, &txr); - } -} - -static void -e1000e_set_tdt(E1000ECore *core, int index, uint32_t val) -{ - E1000E_TxRing txr; - int qidx = e1000e_mq_queue_idx(TDT, index); - uint32_t tarc_reg = (qidx == 0) ? TARC0 : TARC1; - - core->mac[index] = val & 0xffff; - - if (core->mac[tarc_reg] & E1000_TARC_ENABLE) { - e1000e_tx_ring_init(core, &txr, qidx); - e1000e_start_xmit(core, &txr); - } -} - -static void -e1000e_set_ics(E1000ECore *core, int index, uint32_t val) -{ - trace_e1000e_irq_write_ics(val); - e1000e_set_interrupt_cause(core, val); -} - -static void -e1000e_set_icr(E1000ECore *core, int index, uint32_t val) -{ - if ((core->mac[ICR] & E1000_ICR_ASSERTED) && - (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) { - trace_e1000e_irq_icr_process_iame(); - e1000e_clear_ims_bits(core, core->mac[IAM]); - } - - trace_e1000e_irq_icr_write(val, core->mac[ICR], core->mac[ICR] & ~val); - core->mac[ICR] &= ~val; - e1000e_update_interrupt_state(core); -} - -static void -e1000e_set_imc(E1000ECore *core, int index, uint32_t val) -{ - trace_e1000e_irq_ims_clear_set_imc(val); - e1000e_clear_ims_bits(core, val); - e1000e_update_interrupt_state(core); -} - -static void -e1000e_set_ims(E1000ECore *core, int index, uint32_t val) -{ - static const uint32_t ims_ext_mask = - E1000_IMS_RXQ0 | E1000_IMS_RXQ1 | - E1000_IMS_TXQ0 | E1000_IMS_TXQ1 | - E1000_IMS_OTHER; - - static const uint32_t ims_valid_mask = - E1000_IMS_TXDW | E1000_IMS_TXQE | E1000_IMS_LSC | - E1000_IMS_RXDMT0 | E1000_IMS_RXO | E1000_IMS_RXT0 | - E1000_IMS_MDAC | E1000_IMS_TXD_LOW | E1000_IMS_SRPD | - E1000_IMS_ACK | E1000_IMS_MNG | E1000_IMS_RXQ0 | - E1000_IMS_RXQ1 | E1000_IMS_TXQ0 | E1000_IMS_TXQ1 | - E1000_IMS_OTHER; - - uint32_t valid_val = val & ims_valid_mask; - - trace_e1000e_irq_set_ims(val, core->mac[IMS], core->mac[IMS] | valid_val); - core->mac[IMS] |= valid_val; - - if ((valid_val & ims_ext_mask) && - (core->mac[CTRL_EXT] & E1000_CTRL_EXT_PBA_CLR) && - msix_enabled(core->owner)) { - e1000e_msix_clear(core, valid_val); - } - - if ((valid_val == ims_valid_mask) && - (core->mac[CTRL_EXT] & E1000_CTRL_EXT_INT_TIMERS_CLEAR_ENA)) { - trace_e1000e_irq_fire_all_timers(val); - e1000e_intrmgr_fire_all_timers(core); - } - - e1000e_update_interrupt_state(core); -} - -static void -e1000e_set_rdtr(E1000ECore *core, int index, uint32_t val) -{ - e1000e_set_16bit(core, index, val); - - if ((val & E1000_RDTR_FPD) && (core->rdtr.running)) { - trace_e1000e_irq_rdtr_fpd_running(); - e1000e_intrmgr_fire_delayed_interrupts(core); - } else { - trace_e1000e_irq_rdtr_fpd_not_running(); - } -} - -static void -e1000e_set_tidv(E1000ECore *core, int index, uint32_t val) -{ - e1000e_set_16bit(core, index, val); - - if ((val & E1000_TIDV_FPD) && (core->tidv.running)) { - trace_e1000e_irq_tidv_fpd_running(); - e1000e_intrmgr_fire_delayed_interrupts(core); - } else { - trace_e1000e_irq_tidv_fpd_not_running(); - } -} - -static uint32_t -e1000e_mac_readreg(E1000ECore *core, int index) -{ - return core->mac[index]; -} - -static uint32_t -e1000e_mac_ics_read(E1000ECore *core, int index) -{ - trace_e1000e_irq_read_ics(core->mac[ICS]); - return core->mac[ICS]; -} - -static uint32_t -e1000e_mac_ims_read(E1000ECore *core, int index) -{ - trace_e1000e_irq_read_ims(core->mac[IMS]); - return core->mac[IMS]; -} - -#define E1000E_LOW_BITS_READ_FUNC(num) \ - static uint32_t \ - e1000e_mac_low##num##_read(E1000ECore *core, int index) \ - { \ - return core->mac[index] & (BIT(num) - 1); \ - } \ - -#define E1000E_LOW_BITS_READ(num) \ - e1000e_mac_low##num##_read - -E1000E_LOW_BITS_READ_FUNC(4); -E1000E_LOW_BITS_READ_FUNC(6); -E1000E_LOW_BITS_READ_FUNC(11); -E1000E_LOW_BITS_READ_FUNC(13); -E1000E_LOW_BITS_READ_FUNC(16); - -static uint32_t -e1000e_mac_swsm_read(E1000ECore *core, int index) -{ - uint32_t val = core->mac[SWSM]; - core->mac[SWSM] = val | 1; - return val; -} - -static uint32_t -e1000e_mac_itr_read(E1000ECore *core, int index) -{ - return core->itr_guest_value; -} - -static uint32_t -e1000e_mac_eitr_read(E1000ECore *core, int index) -{ - return core->eitr_guest_value[index - EITR]; -} - -static uint32_t -e1000e_mac_icr_read(E1000ECore *core, int index) -{ - uint32_t ret = core->mac[ICR]; - trace_e1000e_irq_icr_read_entry(ret); - - if (core->mac[IMS] == 0) { - trace_e1000e_irq_icr_clear_zero_ims(); - core->mac[ICR] = 0; - } - - if ((core->mac[ICR] & E1000_ICR_ASSERTED) && - (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) { - trace_e1000e_irq_icr_clear_iame(); - core->mac[ICR] = 0; - trace_e1000e_irq_icr_process_iame(); - e1000e_clear_ims_bits(core, core->mac[IAM]); - } - - trace_e1000e_irq_icr_read_exit(core->mac[ICR]); - e1000e_update_interrupt_state(core); - return ret; -} - -static uint32_t -e1000e_mac_read_clr4(E1000ECore *core, int index) -{ - uint32_t ret = core->mac[index]; - - core->mac[index] = 0; - return ret; -} - -static uint32_t -e1000e_mac_read_clr8(E1000ECore *core, int index) -{ - uint32_t ret = core->mac[index]; - - core->mac[index] = 0; - core->mac[index - 1] = 0; - return ret; -} - -static uint32_t -e1000e_get_ctrl(E1000ECore *core, int index) -{ - uint32_t val = core->mac[CTRL]; - - trace_e1000e_link_read_params( - !!(val & E1000_CTRL_ASDE), - (val & E1000_CTRL_SPD_SEL) >> E1000_CTRL_SPD_SHIFT, - !!(val & E1000_CTRL_FRCSPD), - !!(val & E1000_CTRL_FRCDPX), - !!(val & E1000_CTRL_RFCE), - !!(val & E1000_CTRL_TFCE)); - - return val; -} - -static uint32_t -e1000e_get_status(E1000ECore *core, int index) -{ - uint32_t res = core->mac[STATUS]; - - if (!(core->mac[CTRL] & E1000_CTRL_GIO_MASTER_DISABLE)) { - res |= E1000_STATUS_GIO_MASTER_ENABLE; - } - - if (core->mac[CTRL] & E1000_CTRL_FRCDPX) { - res |= (core->mac[CTRL] & E1000_CTRL_FD) ? E1000_STATUS_FD : 0; - } else { - res |= E1000_STATUS_FD; - } - - if ((core->mac[CTRL] & E1000_CTRL_FRCSPD) || - (core->mac[CTRL_EXT] & E1000_CTRL_EXT_SPD_BYPS)) { - switch (core->mac[CTRL] & E1000_CTRL_SPD_SEL) { - case E1000_CTRL_SPD_10: - res |= E1000_STATUS_SPEED_10; - break; - case E1000_CTRL_SPD_100: - res |= E1000_STATUS_SPEED_100; - break; - case E1000_CTRL_SPD_1000: - default: - res |= E1000_STATUS_SPEED_1000; - break; - } - } else { - res |= E1000_STATUS_SPEED_1000; - } - - trace_e1000e_link_status( - !!(res & E1000_STATUS_LU), - !!(res & E1000_STATUS_FD), - (res & E1000_STATUS_SPEED_MASK) >> E1000_STATUS_SPEED_SHIFT, - (res & E1000_STATUS_ASDV) >> E1000_STATUS_ASDV_SHIFT); - - return res; -} - -static uint32_t -e1000e_get_tarc(E1000ECore *core, int index) -{ - return core->mac[index] & ((BIT(11) - 1) | - BIT(27) | - BIT(28) | - BIT(29) | - BIT(30)); -} - -static void -e1000e_mac_writereg(E1000ECore *core, int index, uint32_t val) -{ - core->mac[index] = val; -} - -static void -e1000e_mac_setmacaddr(E1000ECore *core, int index, uint32_t val) -{ - uint32_t macaddr[2]; - - core->mac[index] = val; - - macaddr[0] = cpu_to_le32(core->mac[RA]); - macaddr[1] = cpu_to_le32(core->mac[RA + 1]); - qemu_format_nic_info_str(qemu_get_queue(core->owner_nic), - (uint8_t *) macaddr); - - trace_e1000e_mac_set_sw(MAC_ARG(macaddr)); -} - -static void -e1000e_set_eecd(E1000ECore *core, int index, uint32_t val) -{ - static const uint32_t ro_bits = E1000_EECD_PRES | - E1000_EECD_AUTO_RD | - E1000_EECD_SIZE_EX_MASK; - - core->mac[EECD] = (core->mac[EECD] & ro_bits) | (val & ~ro_bits); -} - -static void -e1000e_set_eerd(E1000ECore *core, int index, uint32_t val) -{ - uint32_t addr = (val >> E1000_EERW_ADDR_SHIFT) & E1000_EERW_ADDR_MASK; - uint32_t flags = 0; - uint32_t data = 0; - - if ((addr < E1000E_EEPROM_SIZE) && (val & E1000_EERW_START)) { - data = core->eeprom[addr]; - flags = E1000_EERW_DONE; - } - - core->mac[EERD] = flags | - (addr << E1000_EERW_ADDR_SHIFT) | - (data << E1000_EERW_DATA_SHIFT); -} - -static void -e1000e_set_eewr(E1000ECore *core, int index, uint32_t val) -{ - uint32_t addr = (val >> E1000_EERW_ADDR_SHIFT) & E1000_EERW_ADDR_MASK; - uint32_t data = (val >> E1000_EERW_DATA_SHIFT) & E1000_EERW_DATA_MASK; - uint32_t flags = 0; - - if ((addr < E1000E_EEPROM_SIZE) && (val & E1000_EERW_START)) { - core->eeprom[addr] = data; - flags = E1000_EERW_DONE; - } - - core->mac[EERD] = flags | - (addr << E1000_EERW_ADDR_SHIFT) | - (data << E1000_EERW_DATA_SHIFT); -} - -static void -e1000e_set_rxdctl(E1000ECore *core, int index, uint32_t val) -{ - core->mac[RXDCTL] = core->mac[RXDCTL1] = val; -} - -static void -e1000e_set_itr(E1000ECore *core, int index, uint32_t val) -{ - uint32_t interval = val & 0xffff; - - trace_e1000e_irq_itr_set(val); - - core->itr_guest_value = interval; - core->mac[index] = MAX(interval, E1000E_MIN_XITR); -} - -static void -e1000e_set_eitr(E1000ECore *core, int index, uint32_t val) -{ - uint32_t interval = val & 0xffff; - uint32_t eitr_num = index - EITR; - - trace_e1000e_irq_eitr_set(eitr_num, val); - - core->eitr_guest_value[eitr_num] = interval; - core->mac[index] = MAX(interval, E1000E_MIN_XITR); -} - -static void -e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val) -{ - if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) { - hw_error("e1000e: PSRCTL.BSIZE0 cannot be zero"); - } - - if ((val & E1000_PSRCTL_BSIZE1_MASK) == 0) { - hw_error("e1000e: PSRCTL.BSIZE1 cannot be zero"); - } - - core->mac[PSRCTL] = val; -} - -static void -e1000e_update_rx_offloads(E1000ECore *core) -{ - int cso_state = e1000e_rx_l4_cso_enabled(core); - - trace_e1000e_rx_set_cso(cso_state); - - if (core->has_vnet) { - qemu_set_offload(qemu_get_queue(core->owner_nic)->peer, - cso_state, 0, 0, 0, 0); - } -} - -static void -e1000e_set_rxcsum(E1000ECore *core, int index, uint32_t val) -{ - core->mac[RXCSUM] = val; - e1000e_update_rx_offloads(core); -} - -static void -e1000e_set_gcr(E1000ECore *core, int index, uint32_t val) -{ - uint32_t ro_bits = core->mac[GCR] & E1000_GCR_RO_BITS; - core->mac[GCR] = (val & ~E1000_GCR_RO_BITS) | ro_bits; -} - -#define e1000e_getreg(x) [x] = e1000e_mac_readreg -static uint32_t (*e1000e_macreg_readops[])(E1000ECore *, int) = { - e1000e_getreg(PBA), - e1000e_getreg(WUFC), - e1000e_getreg(MANC), - e1000e_getreg(TOTL), - e1000e_getreg(RDT0), - e1000e_getreg(RDBAH0), - e1000e_getreg(TDBAL1), - e1000e_getreg(RDLEN0), - e1000e_getreg(RDH1), - e1000e_getreg(LATECOL), - e1000e_getreg(SEC), - e1000e_getreg(XONTXC), - e1000e_getreg(WUS), - e1000e_getreg(GORCL), - e1000e_getreg(MGTPRC), - e1000e_getreg(EERD), - e1000e_getreg(EIAC), - e1000e_getreg(PSRCTL), - e1000e_getreg(MANC2H), - e1000e_getreg(RXCSUM), - e1000e_getreg(GSCL_3), - e1000e_getreg(GSCN_2), - e1000e_getreg(RSRPD), - e1000e_getreg(RDBAL1), - e1000e_getreg(FCAH), - e1000e_getreg(FCRTH), - e1000e_getreg(FLOP), - e1000e_getreg(FLASHT), - e1000e_getreg(RXSTMPH), - e1000e_getreg(TXSTMPL), - e1000e_getreg(TIMADJL), - e1000e_getreg(TXDCTL), - e1000e_getreg(RDH0), - e1000e_getreg(TDT1), - e1000e_getreg(TNCRS), - e1000e_getreg(RJC), - e1000e_getreg(IAM), - e1000e_getreg(GSCL_2), - e1000e_getreg(RDBAH1), - e1000e_getreg(FLSWDATA), - e1000e_getreg(RXSATRH), - e1000e_getreg(TIPG), - e1000e_getreg(FLMNGCTL), - e1000e_getreg(FLMNGCNT), - e1000e_getreg(TSYNCTXCTL), - e1000e_getreg(EXTCNF_SIZE), - e1000e_getreg(EXTCNF_CTRL), - e1000e_getreg(EEMNGDATA), - e1000e_getreg(CTRL_EXT), - e1000e_getreg(SYSTIMH), - e1000e_getreg(EEMNGCTL), - e1000e_getreg(FLMNGDATA), - e1000e_getreg(TSYNCRXCTL), - e1000e_getreg(TDH), - e1000e_getreg(LEDCTL), - e1000e_getreg(STATUS), - e1000e_getreg(TCTL), - e1000e_getreg(TDBAL), - e1000e_getreg(TDLEN), - e1000e_getreg(TDH1), - e1000e_getreg(RADV), - e1000e_getreg(ECOL), - e1000e_getreg(DC), - e1000e_getreg(RLEC), - e1000e_getreg(XOFFTXC), - e1000e_getreg(RFC), - e1000e_getreg(RNBC), - e1000e_getreg(MGTPTC), - e1000e_getreg(TIMINCA), - e1000e_getreg(RXCFGL), - e1000e_getreg(MFUTP01), - e1000e_getreg(FACTPS), - e1000e_getreg(GSCL_1), - e1000e_getreg(GSCN_0), - e1000e_getreg(GCR2), - e1000e_getreg(RDT1), - e1000e_getreg(PBACLR), - e1000e_getreg(FCTTV), - e1000e_getreg(EEWR), - e1000e_getreg(FLSWCTL), - e1000e_getreg(RXDCTL1), - e1000e_getreg(RXSATRL), - e1000e_getreg(SYSTIML), - e1000e_getreg(RXUDP), - e1000e_getreg(TORL), - e1000e_getreg(TDLEN1), - e1000e_getreg(MCC), - e1000e_getreg(WUC), - e1000e_getreg(EECD), - e1000e_getreg(MFUTP23), - e1000e_getreg(RAID), - e1000e_getreg(FCRTV), - e1000e_getreg(TXDCTL1), - e1000e_getreg(RCTL), - e1000e_getreg(TDT), - e1000e_getreg(MDIC), - e1000e_getreg(FCRUC), - e1000e_getreg(VET), - e1000e_getreg(RDBAL0), - e1000e_getreg(TDBAH1), - e1000e_getreg(RDTR), - e1000e_getreg(SCC), - e1000e_getreg(COLC), - e1000e_getreg(CEXTERR), - e1000e_getreg(XOFFRXC), - e1000e_getreg(IPAV), - e1000e_getreg(GOTCL), - e1000e_getreg(MGTPDC), - e1000e_getreg(GCR), - e1000e_getreg(IVAR), - e1000e_getreg(POEMB), - e1000e_getreg(MFVAL), - e1000e_getreg(FUNCTAG), - e1000e_getreg(GSCL_4), - e1000e_getreg(GSCN_3), - e1000e_getreg(MRQC), - e1000e_getreg(RDLEN1), - e1000e_getreg(FCT), - e1000e_getreg(FLA), - e1000e_getreg(FLOL), - e1000e_getreg(RXDCTL), - e1000e_getreg(RXSTMPL), - e1000e_getreg(TXSTMPH), - e1000e_getreg(TIMADJH), - e1000e_getreg(FCRTL), - e1000e_getreg(TDBAH), - e1000e_getreg(TADV), - e1000e_getreg(XONRXC), - e1000e_getreg(TSCTFC), - e1000e_getreg(RFCTL), - e1000e_getreg(GSCN_1), - e1000e_getreg(FCAL), - e1000e_getreg(FLSWCNT), - - [TOTH] = e1000e_mac_read_clr8, - [GOTCH] = e1000e_mac_read_clr8, - [PRC64] = e1000e_mac_read_clr4, - [PRC255] = e1000e_mac_read_clr4, - [PRC1023] = e1000e_mac_read_clr4, - [PTC64] = e1000e_mac_read_clr4, - [PTC255] = e1000e_mac_read_clr4, - [PTC1023] = e1000e_mac_read_clr4, - [GPRC] = e1000e_mac_read_clr4, - [TPT] = e1000e_mac_read_clr4, - [RUC] = e1000e_mac_read_clr4, - [BPRC] = e1000e_mac_read_clr4, - [MPTC] = e1000e_mac_read_clr4, - [IAC] = e1000e_mac_read_clr4, - [ICR] = e1000e_mac_icr_read, - [RDFH] = E1000E_LOW_BITS_READ(13), - [RDFHS] = E1000E_LOW_BITS_READ(13), - [RDFPC] = E1000E_LOW_BITS_READ(13), - [TDFH] = E1000E_LOW_BITS_READ(13), - [TDFHS] = E1000E_LOW_BITS_READ(13), - [STATUS] = e1000e_get_status, - [TARC0] = e1000e_get_tarc, - [PBS] = E1000E_LOW_BITS_READ(6), - [ICS] = e1000e_mac_ics_read, - [AIT] = E1000E_LOW_BITS_READ(16), - [TORH] = e1000e_mac_read_clr8, - [GORCH] = e1000e_mac_read_clr8, - [PRC127] = e1000e_mac_read_clr4, - [PRC511] = e1000e_mac_read_clr4, - [PRC1522] = e1000e_mac_read_clr4, - [PTC127] = e1000e_mac_read_clr4, - [PTC511] = e1000e_mac_read_clr4, - [PTC1522] = e1000e_mac_read_clr4, - [GPTC] = e1000e_mac_read_clr4, - [TPR] = e1000e_mac_read_clr4, - [ROC] = e1000e_mac_read_clr4, - [MPRC] = e1000e_mac_read_clr4, - [BPTC] = e1000e_mac_read_clr4, - [TSCTC] = e1000e_mac_read_clr4, - [ITR] = e1000e_mac_itr_read, - [RDFT] = E1000E_LOW_BITS_READ(13), - [RDFTS] = E1000E_LOW_BITS_READ(13), - [TDFPC] = E1000E_LOW_BITS_READ(13), - [TDFT] = E1000E_LOW_BITS_READ(13), - [TDFTS] = E1000E_LOW_BITS_READ(13), - [CTRL] = e1000e_get_ctrl, - [TARC1] = e1000e_get_tarc, - [SWSM] = e1000e_mac_swsm_read, - [IMS] = e1000e_mac_ims_read, - - [CRCERRS ... MPC] = e1000e_mac_readreg, - [IP6AT ... IP6AT + 3] = e1000e_mac_readreg, - [IP4AT ... IP4AT + 6] = e1000e_mac_readreg, - [RA ... RA + 31] = e1000e_mac_readreg, - [WUPM ... WUPM + 31] = e1000e_mac_readreg, - [MTA ... MTA + 127] = e1000e_mac_readreg, - [VFTA ... VFTA + 127] = e1000e_mac_readreg, - [FFMT ... FFMT + 254] = E1000E_LOW_BITS_READ(4), - [FFVT ... FFVT + 254] = e1000e_mac_readreg, - [MDEF ... MDEF + 7] = e1000e_mac_readreg, - [FFLT ... FFLT + 10] = E1000E_LOW_BITS_READ(11), - [FTFT ... FTFT + 254] = e1000e_mac_readreg, - [PBM ... PBM + 10239] = e1000e_mac_readreg, - [RETA ... RETA + 31] = e1000e_mac_readreg, - [RSSRK ... RSSRK + 31] = e1000e_mac_readreg, - [MAVTV0 ... MAVTV3] = e1000e_mac_readreg, - [EITR...EITR + E1000E_MSIX_VEC_NUM - 1] = e1000e_mac_eitr_read -}; -enum { E1000E_NREADOPS = ARRAY_SIZE(e1000e_macreg_readops) }; - -#define e1000e_putreg(x) [x] = e1000e_mac_writereg -static void (*e1000e_macreg_writeops[])(E1000ECore *, int, uint32_t) = { - e1000e_putreg(PBA), - e1000e_putreg(SWSM), - e1000e_putreg(WUFC), - e1000e_putreg(RDBAH1), - e1000e_putreg(TDBAH), - e1000e_putreg(TXDCTL), - e1000e_putreg(RDBAH0), - e1000e_putreg(LEDCTL), - e1000e_putreg(FCAL), - e1000e_putreg(FCRUC), - e1000e_putreg(AIT), - e1000e_putreg(TDFH), - e1000e_putreg(TDFT), - e1000e_putreg(TDFHS), - e1000e_putreg(TDFTS), - e1000e_putreg(TDFPC), - e1000e_putreg(WUC), - e1000e_putreg(WUS), - e1000e_putreg(RDFH), - e1000e_putreg(RDFT), - e1000e_putreg(RDFHS), - e1000e_putreg(RDFTS), - e1000e_putreg(RDFPC), - e1000e_putreg(IPAV), - e1000e_putreg(TDBAH1), - e1000e_putreg(TIMINCA), - e1000e_putreg(IAM), - e1000e_putreg(EIAC), - e1000e_putreg(IVAR), - e1000e_putreg(TARC0), - e1000e_putreg(TARC1), - e1000e_putreg(FLSWDATA), - e1000e_putreg(POEMB), - e1000e_putreg(PBS), - e1000e_putreg(MFUTP01), - e1000e_putreg(MFUTP23), - e1000e_putreg(MANC), - e1000e_putreg(MANC2H), - e1000e_putreg(MFVAL), - e1000e_putreg(EXTCNF_CTRL), - e1000e_putreg(FACTPS), - e1000e_putreg(FUNCTAG), - e1000e_putreg(GSCL_1), - e1000e_putreg(GSCL_2), - e1000e_putreg(GSCL_3), - e1000e_putreg(GSCL_4), - e1000e_putreg(GSCN_0), - e1000e_putreg(GSCN_1), - e1000e_putreg(GSCN_2), - e1000e_putreg(GSCN_3), - e1000e_putreg(GCR2), - e1000e_putreg(MRQC), - e1000e_putreg(FLOP), - e1000e_putreg(FLOL), - e1000e_putreg(FLSWCTL), - e1000e_putreg(FLSWCNT), - e1000e_putreg(FLA), - e1000e_putreg(RXDCTL1), - e1000e_putreg(TXDCTL1), - e1000e_putreg(TIPG), - e1000e_putreg(RXSTMPH), - e1000e_putreg(RXSTMPL), - e1000e_putreg(RXSATRL), - e1000e_putreg(RXSATRH), - e1000e_putreg(TXSTMPL), - e1000e_putreg(TXSTMPH), - e1000e_putreg(SYSTIML), - e1000e_putreg(SYSTIMH), - e1000e_putreg(TIMADJL), - e1000e_putreg(TIMADJH), - e1000e_putreg(RXUDP), - e1000e_putreg(RXCFGL), - e1000e_putreg(TSYNCRXCTL), - e1000e_putreg(TSYNCTXCTL), - e1000e_putreg(FLSWDATA), - e1000e_putreg(EXTCNF_SIZE), - e1000e_putreg(EEMNGCTL), - e1000e_putreg(RA), - - [TDH1] = e1000e_set_16bit, - [TDT1] = e1000e_set_tdt, - [TCTL] = e1000e_set_tctl, - [TDT] = e1000e_set_tdt, - [MDIC] = e1000e_set_mdic, - [ICS] = e1000e_set_ics, - [TDH] = e1000e_set_16bit, - [RDH0] = e1000e_set_16bit, - [RDT0] = e1000e_set_rdt, - [IMC] = e1000e_set_imc, - [IMS] = e1000e_set_ims, - [ICR] = e1000e_set_icr, - [EECD] = e1000e_set_eecd, - [RCTL] = e1000e_set_rx_control, - [CTRL] = e1000e_set_ctrl, - [RDTR] = e1000e_set_rdtr, - [RADV] = e1000e_set_16bit, - [TADV] = e1000e_set_16bit, - [ITR] = e1000e_set_itr, - [EERD] = e1000e_set_eerd, - [GCR] = e1000e_set_gcr, - [PSRCTL] = e1000e_set_psrctl, - [RXCSUM] = e1000e_set_rxcsum, - [RAID] = e1000e_set_16bit, - [RSRPD] = e1000e_set_12bit, - [TIDV] = e1000e_set_tidv, - [TDLEN1] = e1000e_set_dlen, - [TDLEN] = e1000e_set_dlen, - [RDLEN0] = e1000e_set_dlen, - [RDLEN1] = e1000e_set_dlen, - [TDBAL] = e1000e_set_dbal, - [TDBAL1] = e1000e_set_dbal, - [RDBAL0] = e1000e_set_dbal, - [RDBAL1] = e1000e_set_dbal, - [RDH1] = e1000e_set_16bit, - [RDT1] = e1000e_set_rdt, - [STATUS] = e1000e_set_status, - [PBACLR] = e1000e_set_pbaclr, - [CTRL_EXT] = e1000e_set_ctrlext, - [FCAH] = e1000e_set_16bit, - [FCT] = e1000e_set_16bit, - [FCTTV] = e1000e_set_16bit, - [FCRTV] = e1000e_set_16bit, - [FCRTH] = e1000e_set_fcrth, - [FCRTL] = e1000e_set_fcrtl, - [VET] = e1000e_set_vet, - [RXDCTL] = e1000e_set_rxdctl, - [FLASHT] = e1000e_set_16bit, - [EEWR] = e1000e_set_eewr, - [CTRL_DUP] = e1000e_set_ctrl, - [RFCTL] = e1000e_set_rfctl, - [RA + 1] = e1000e_mac_setmacaddr, - - [IP6AT ... IP6AT + 3] = e1000e_mac_writereg, - [IP4AT ... IP4AT + 6] = e1000e_mac_writereg, - [RA + 2 ... RA + 31] = e1000e_mac_writereg, - [WUPM ... WUPM + 31] = e1000e_mac_writereg, - [MTA ... MTA + 127] = e1000e_mac_writereg, - [VFTA ... VFTA + 127] = e1000e_mac_writereg, - [FFMT ... FFMT + 254] = e1000e_mac_writereg, - [FFVT ... FFVT + 254] = e1000e_mac_writereg, - [PBM ... PBM + 10239] = e1000e_mac_writereg, - [MDEF ... MDEF + 7] = e1000e_mac_writereg, - [FFLT ... FFLT + 10] = e1000e_mac_writereg, - [FTFT ... FTFT + 254] = e1000e_mac_writereg, - [RETA ... RETA + 31] = e1000e_mac_writereg, - [RSSRK ... RSSRK + 31] = e1000e_mac_writereg, - [MAVTV0 ... MAVTV3] = e1000e_mac_writereg, - [EITR...EITR + E1000E_MSIX_VEC_NUM - 1] = e1000e_set_eitr -}; -enum { E1000E_NWRITEOPS = ARRAY_SIZE(e1000e_macreg_writeops) }; - -enum { MAC_ACCESS_PARTIAL = 1 }; - -/* The array below combines alias offsets of the index values for the - * MAC registers that have aliases, with the indication of not fully - * implemented registers (lowest bit). This combination is possible - * because all of the offsets are even. */ -static const uint16_t mac_reg_access[E1000E_MAC_SIZE] = { - /* Alias index offsets */ - [FCRTL_A] = 0x07fe, [FCRTH_A] = 0x0802, - [RDH0_A] = 0x09bc, [RDT0_A] = 0x09bc, [RDTR_A] = 0x09c6, - [RDFH_A] = 0xe904, [RDFT_A] = 0xe904, - [TDH_A] = 0x0cf8, [TDT_A] = 0x0cf8, [TIDV_A] = 0x0cf8, - [TDFH_A] = 0xed00, [TDFT_A] = 0xed00, - [RA_A ... RA_A + 31] = 0x14f0, - [VFTA_A ... VFTA_A + 127] = 0x1400, - [RDBAL0_A ... RDLEN0_A] = 0x09bc, - [TDBAL_A ... TDLEN_A] = 0x0cf8, - /* Access options */ - [RDFH] = MAC_ACCESS_PARTIAL, [RDFT] = MAC_ACCESS_PARTIAL, - [RDFHS] = MAC_ACCESS_PARTIAL, [RDFTS] = MAC_ACCESS_PARTIAL, - [RDFPC] = MAC_ACCESS_PARTIAL, - [TDFH] = MAC_ACCESS_PARTIAL, [TDFT] = MAC_ACCESS_PARTIAL, - [TDFHS] = MAC_ACCESS_PARTIAL, [TDFTS] = MAC_ACCESS_PARTIAL, - [TDFPC] = MAC_ACCESS_PARTIAL, [EECD] = MAC_ACCESS_PARTIAL, - [PBM] = MAC_ACCESS_PARTIAL, [FLA] = MAC_ACCESS_PARTIAL, - [FCAL] = MAC_ACCESS_PARTIAL, [FCAH] = MAC_ACCESS_PARTIAL, - [FCT] = MAC_ACCESS_PARTIAL, [FCTTV] = MAC_ACCESS_PARTIAL, - [FCRTV] = MAC_ACCESS_PARTIAL, [FCRTL] = MAC_ACCESS_PARTIAL, - [FCRTH] = MAC_ACCESS_PARTIAL, [TXDCTL] = MAC_ACCESS_PARTIAL, - [TXDCTL1] = MAC_ACCESS_PARTIAL, - [MAVTV0 ... MAVTV3] = MAC_ACCESS_PARTIAL -}; - -void -e1000e_core_write(E1000ECore *core, hwaddr addr, uint64_t val, unsigned size) -{ - uint16_t index = e1000e_get_reg_index_with_offset(mac_reg_access, addr); - - if (index < E1000E_NWRITEOPS && e1000e_macreg_writeops[index]) { - if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) { - trace_e1000e_wrn_regs_write_trivial(index << 2); - } - trace_e1000e_core_write(index << 2, size, val); - e1000e_macreg_writeops[index](core, index, val); - } else if (index < E1000E_NREADOPS && e1000e_macreg_readops[index]) { - trace_e1000e_wrn_regs_write_ro(index << 2, size, val); - } else { - trace_e1000e_wrn_regs_write_unknown(index << 2, size, val); - } -} - -uint64_t -e1000e_core_read(E1000ECore *core, hwaddr addr, unsigned size) -{ - uint64_t val; - uint16_t index = e1000e_get_reg_index_with_offset(mac_reg_access, addr); - - if (index < E1000E_NREADOPS && e1000e_macreg_readops[index]) { - if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) { - trace_e1000e_wrn_regs_read_trivial(index << 2); - } - val = e1000e_macreg_readops[index](core, index); - trace_e1000e_core_read(index << 2, size, val); - return val; - } else { - trace_e1000e_wrn_regs_read_unknown(index << 2, size); - } - return 0; -} - -static inline void -e1000e_autoneg_pause(E1000ECore *core) -{ - timer_del(core->autoneg_timer); -} - -static void -e1000e_autoneg_resume(E1000ECore *core) -{ - if (e1000e_have_autoneg(core) && - !(core->phy[0][PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) { - qemu_get_queue(core->owner_nic)->link_down = false; - timer_mod(core->autoneg_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500); - } -} - -static void -e1000e_vm_state_change(void *opaque, int running, RunState state) -{ - E1000ECore *core = opaque; - - if (running) { - trace_e1000e_vm_state_running(); - e1000e_intrmgr_resume(core); - e1000e_autoneg_resume(core); - } else { - trace_e1000e_vm_state_stopped(); - e1000e_autoneg_pause(core); - e1000e_intrmgr_pause(core); - } -} - -void -e1000e_core_pci_realize(E1000ECore *core, - const uint16_t *eeprom_templ, - uint32_t eeprom_size, - const uint8_t *macaddr) -{ - int i; - - core->autoneg_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, - e1000e_autoneg_timer, core); - e1000e_intrmgr_pci_realize(core); - - core->vmstate = - qemu_add_vm_change_state_handler(e1000e_vm_state_change, core); - - for (i = 0; i < E1000E_NUM_QUEUES; i++) { - net_tx_pkt_init(&core->tx[i].tx_pkt, core->owner, - E1000E_MAX_TX_FRAGS, core->has_vnet); - } - - net_rx_pkt_init(&core->rx_pkt, core->has_vnet); - - e1000x_core_prepare_eeprom(core->eeprom, - eeprom_templ, - eeprom_size, - PCI_DEVICE_GET_CLASS(core->owner)->device_id, - macaddr); - e1000e_update_rx_offloads(core); -} - -void -e1000e_core_pci_uninit(E1000ECore *core) -{ - int i; - - timer_del(core->autoneg_timer); - timer_free(core->autoneg_timer); - - e1000e_intrmgr_pci_unint(core); - - qemu_del_vm_change_state_handler(core->vmstate); - - for (i = 0; i < E1000E_NUM_QUEUES; i++) { - net_tx_pkt_reset(core->tx[i].tx_pkt); - net_tx_pkt_uninit(core->tx[i].tx_pkt); - } - - net_rx_pkt_uninit(core->rx_pkt); -} - -static const uint16_t -e1000e_phy_reg_init[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE] = { - [0] = { - [PHY_CTRL] = MII_CR_SPEED_SELECT_MSB | - MII_CR_FULL_DUPLEX | - MII_CR_AUTO_NEG_EN, - - [PHY_STATUS] = MII_SR_EXTENDED_CAPS | - MII_SR_LINK_STATUS | - MII_SR_AUTONEG_CAPS | - MII_SR_PREAMBLE_SUPPRESS | - MII_SR_EXTENDED_STATUS | - MII_SR_10T_HD_CAPS | - MII_SR_10T_FD_CAPS | - MII_SR_100X_HD_CAPS | - MII_SR_100X_FD_CAPS, - - [PHY_ID1] = 0x141, - [PHY_ID2] = E1000_PHY_ID2_82574x, - [PHY_AUTONEG_ADV] = 0xde1, - [PHY_LP_ABILITY] = 0x7e0, - [PHY_AUTONEG_EXP] = BIT(2), - [PHY_NEXT_PAGE_TX] = BIT(0) | BIT(13), - [PHY_1000T_CTRL] = BIT(8) | BIT(9) | BIT(10) | BIT(11), - [PHY_1000T_STATUS] = 0x3c00, - [PHY_EXT_STATUS] = BIT(12) | BIT(13), - - [PHY_COPPER_CTRL1] = BIT(5) | BIT(6) | BIT(8) | BIT(9) | - BIT(12) | BIT(13), - [PHY_COPPER_STAT1] = BIT(3) | BIT(10) | BIT(11) | BIT(13) | BIT(15) - }, - [2] = { - [PHY_MAC_CTRL1] = BIT(3) | BIT(7), - [PHY_MAC_CTRL2] = BIT(1) | BIT(2) | BIT(6) | BIT(12) - }, - [3] = { - [PHY_LED_TIMER_CTRL] = BIT(0) | BIT(2) | BIT(14) - } -}; - -static const uint32_t e1000e_mac_reg_init[] = { - [PBA] = 0x00140014, - [LEDCTL] = BIT(1) | BIT(8) | BIT(9) | BIT(15) | BIT(17) | BIT(18), - [EXTCNF_CTRL] = BIT(3), - [EEMNGCTL] = BIT(31), - [FLASHT] = 0x2, - [FLSWCTL] = BIT(30) | BIT(31), - [FLOL] = BIT(0), - [RXDCTL] = BIT(16), - [RXDCTL1] = BIT(16), - [TIPG] = 0x8 | (0x8 << 10) | (0x6 << 20), - [RXCFGL] = 0x88F7, - [RXUDP] = 0x319, - [CTRL] = E1000_CTRL_FD | E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 | - E1000_CTRL_SPD_1000 | E1000_CTRL_SLU | - E1000_CTRL_ADVD3WUC, - [STATUS] = E1000_STATUS_ASDV_1000 | E1000_STATUS_LU, - [PSRCTL] = (2 << E1000_PSRCTL_BSIZE0_SHIFT) | - (4 << E1000_PSRCTL_BSIZE1_SHIFT) | - (4 << E1000_PSRCTL_BSIZE2_SHIFT), - [TARC0] = 0x3 | E1000_TARC_ENABLE, - [TARC1] = 0x3 | E1000_TARC_ENABLE, - [EECD] = E1000_EECD_AUTO_RD | E1000_EECD_PRES, - [EERD] = E1000_EERW_DONE, - [EEWR] = E1000_EERW_DONE, - [GCR] = E1000_L0S_ADJUST | - E1000_L1_ENTRY_LATENCY_MSB | - E1000_L1_ENTRY_LATENCY_LSB, - [TDFH] = 0x600, - [TDFT] = 0x600, - [TDFHS] = 0x600, - [TDFTS] = 0x600, - [POEMB] = 0x30D, - [PBS] = 0x028, - [MANC] = E1000_MANC_DIS_IP_CHK_ARP, - [FACTPS] = E1000_FACTPS_LAN0_ON | 0x20000000, - [SWSM] = 1, - [RXCSUM] = E1000_RXCSUM_IPOFLD | E1000_RXCSUM_TUOFLD, - [ITR] = E1000E_MIN_XITR, - [EITR...EITR + E1000E_MSIX_VEC_NUM - 1] = E1000E_MIN_XITR, -}; - -void -e1000e_core_reset(E1000ECore *core) -{ - int i; - - timer_del(core->autoneg_timer); - - e1000e_intrmgr_reset(core); - - memset(core->phy, 0, sizeof core->phy); - memmove(core->phy, e1000e_phy_reg_init, sizeof e1000e_phy_reg_init); - memset(core->mac, 0, sizeof core->mac); - memmove(core->mac, e1000e_mac_reg_init, sizeof e1000e_mac_reg_init); - - core->rxbuf_min_shift = 1 + E1000_RING_DESC_LEN_SHIFT; - - if (qemu_get_queue(core->owner_nic)->link_down) { - e1000e_link_down(core); - } - - e1000x_reset_mac_addr(core->owner_nic, core->mac, core->permanent_mac); - - for (i = 0; i < ARRAY_SIZE(core->tx); i++) { - net_tx_pkt_reset(core->tx[i].tx_pkt); - memset(&core->tx[i].props, 0, sizeof(core->tx[i].props)); - core->tx[i].skip_cp = false; - } -} - -void e1000e_core_pre_save(E1000ECore *core) -{ - int i; - NetClientState *nc = qemu_get_queue(core->owner_nic); - - /* - * If link is down and auto-negotiation is supported and ongoing, - * complete auto-negotiation immediately. This allows us to look - * at MII_SR_AUTONEG_COMPLETE to infer link status on load. - */ - if (nc->link_down && e1000e_have_autoneg(core)) { - core->phy[0][PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; - e1000e_update_flowctl_status(core); - } - - for (i = 0; i < ARRAY_SIZE(core->tx); i++) { - if (net_tx_pkt_has_fragments(core->tx[i].tx_pkt)) { - core->tx[i].skip_cp = true; - } - } -} - -int -e1000e_core_post_load(E1000ECore *core) -{ - NetClientState *nc = qemu_get_queue(core->owner_nic); - - /* nc.link_down can't be migrated, so infer link_down according - * to link status bit in core.mac[STATUS]. - */ - nc->link_down = (core->mac[STATUS] & E1000_STATUS_LU) == 0; - - return 0; -} diff --git a/hw/net/e1000e_core.h b/hw/net/e1000e_core.h deleted file mode 100644 index 5f413a9e0..000000000 --- a/hw/net/e1000e_core.h +++ /dev/null @@ -1,146 +0,0 @@ -/* -* Core code for QEMU e1000e emulation -* -* Software developer's manuals: -* http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf -* -* Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com) -* Developed by Daynix Computing LTD (http://www.daynix.com) -* -* Authors: -* Dmitry Fleytman <dmitry@daynix.com> -* Leonid Bloch <leonid@daynix.com> -* Yan Vugenfirer <yan@daynix.com> -* -* Based on work done by: -* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc. -* Copyright (c) 2008 Qumranet -* Based on work done by: -* Copyright (c) 2007 Dan Aloni -* Copyright (c) 2004 Antony T Curtis -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#define E1000E_PHY_PAGE_SIZE (0x20) -#define E1000E_PHY_PAGES (0x07) -#define E1000E_MAC_SIZE (0x8000) -#define E1000E_EEPROM_SIZE (64) -#define E1000E_MSIX_VEC_NUM (5) -#define E1000E_NUM_QUEUES (2) - -typedef struct E1000Core E1000ECore; - -enum { PHY_R = BIT(0), - PHY_W = BIT(1), - PHY_RW = PHY_R | PHY_W, - PHY_ANYPAGE = BIT(2) }; - -typedef struct E1000IntrDelayTimer_st { - QEMUTimer *timer; - bool running; - uint32_t delay_reg; - uint32_t delay_resolution_ns; - E1000ECore *core; -} E1000IntrDelayTimer; - -struct E1000Core { - uint32_t mac[E1000E_MAC_SIZE]; - uint16_t phy[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE]; - uint16_t eeprom[E1000E_EEPROM_SIZE]; - - uint32_t rxbuf_sizes[E1000_PSRCTL_BUFFS_PER_DESC]; - uint32_t rx_desc_buf_size; - uint32_t rxbuf_min_shift; - uint8_t rx_desc_len; - - QEMUTimer *autoneg_timer; - - struct e1000e_tx { - e1000x_txd_props props; - - bool skip_cp; - struct NetTxPkt *tx_pkt; - } tx[E1000E_NUM_QUEUES]; - - struct NetRxPkt *rx_pkt; - - bool has_vnet; - int max_queue_num; - - /* Interrupt moderation management */ - uint32_t delayed_causes; - - E1000IntrDelayTimer radv; - E1000IntrDelayTimer rdtr; - E1000IntrDelayTimer raid; - - E1000IntrDelayTimer tadv; - E1000IntrDelayTimer tidv; - - E1000IntrDelayTimer itr; - bool itr_intr_pending; - - E1000IntrDelayTimer eitr[E1000E_MSIX_VEC_NUM]; - bool eitr_intr_pending[E1000E_MSIX_VEC_NUM]; - - VMChangeStateEntry *vmstate; - - uint32_t itr_guest_value; - uint32_t eitr_guest_value[E1000E_MSIX_VEC_NUM]; - - uint16_t vet; - - uint8_t permanent_mac[ETH_ALEN]; - - NICState *owner_nic; - PCIDevice *owner; - void (*owner_start_recv)(PCIDevice *d); -}; - -void -e1000e_core_write(E1000ECore *core, hwaddr addr, uint64_t val, unsigned size); - -uint64_t -e1000e_core_read(E1000ECore *core, hwaddr addr, unsigned size); - -void -e1000e_core_pci_realize(E1000ECore *regs, - const uint16_t *eeprom_templ, - uint32_t eeprom_size, - const uint8_t *macaddr); - -void -e1000e_core_reset(E1000ECore *core); - -void -e1000e_core_pre_save(E1000ECore *core); - -int -e1000e_core_post_load(E1000ECore *core); - -void -e1000e_core_set_link_status(E1000ECore *core); - -void -e1000e_core_pci_uninit(E1000ECore *core); - -int -e1000e_can_receive(E1000ECore *core); - -ssize_t -e1000e_receive(E1000ECore *core, const uint8_t *buf, size_t size); - -ssize_t -e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt); diff --git a/hw/net/e1000x_common.c b/hw/net/e1000x_common.c deleted file mode 100644 index eb0e09713..000000000 --- a/hw/net/e1000x_common.c +++ /dev/null @@ -1,267 +0,0 @@ -/* -* QEMU e1000(e) emulation - shared code -* -* Copyright (c) 2008 Qumranet -* -* Based on work done by: -* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc. -* Copyright (c) 2007 Dan Aloni -* Copyright (c) 2004 Antony T Curtis -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/pci/pci.h" -#include "net/net.h" - -#include "e1000x_common.h" - -#include "trace.h" - -bool e1000x_rx_ready(PCIDevice *d, uint32_t *mac) -{ - bool link_up = mac[STATUS] & E1000_STATUS_LU; - bool rx_enabled = mac[RCTL] & E1000_RCTL_EN; - bool pci_master = d->config[PCI_COMMAND] & PCI_COMMAND_MASTER; - - if (!link_up || !rx_enabled || !pci_master) { - trace_e1000x_rx_can_recv_disabled(link_up, rx_enabled, pci_master); - return false; - } - - return true; -} - -bool e1000x_is_vlan_packet(const uint8_t *buf, uint16_t vet) -{ - uint16_t eth_proto = lduw_be_p(buf + 12); - bool res = (eth_proto == vet); - - trace_e1000x_vlan_is_vlan_pkt(res, eth_proto, vet); - - return res; -} - -bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf) -{ - static const int mta_shift[] = { 4, 3, 2, 0 }; - uint32_t f, ra[2], *rp, rctl = mac[RCTL]; - - for (rp = mac + RA; rp < mac + RA + 32; rp += 2) { - if (!(rp[1] & E1000_RAH_AV)) { - continue; - } - ra[0] = cpu_to_le32(rp[0]); - ra[1] = cpu_to_le32(rp[1]); - if (!memcmp(buf, (uint8_t *)ra, 6)) { - trace_e1000x_rx_flt_ucast_match((int)(rp - mac - RA) / 2, - MAC_ARG(buf)); - return true; - } - } - trace_e1000x_rx_flt_ucast_mismatch(MAC_ARG(buf)); - - f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3]; - f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff; - if (mac[MTA + (f >> 5)] & (1 << (f & 0x1f))) { - e1000x_inc_reg_if_not_full(mac, MPRC); - return true; - } - - trace_e1000x_rx_flt_inexact_mismatch(MAC_ARG(buf), - (rctl >> E1000_RCTL_MO_SHIFT) & 3, - f >> 5, - mac[MTA + (f >> 5)]); - - return false; -} - -bool e1000x_hw_rx_enabled(uint32_t *mac) -{ - if (!(mac[STATUS] & E1000_STATUS_LU)) { - trace_e1000x_rx_link_down(mac[STATUS]); - return false; - } - - if (!(mac[RCTL] & E1000_RCTL_EN)) { - trace_e1000x_rx_disabled(mac[RCTL]); - return false; - } - - return true; -} - -bool e1000x_is_oversized(uint32_t *mac, size_t size) -{ - /* this is the size past which hardware will - drop packets when setting LPE=0 */ - static const int maximum_ethernet_vlan_size = 1522; - /* this is the size past which hardware will - drop packets when setting LPE=1 */ - static const int maximum_ethernet_lpe_size = 16384; - - if ((size > maximum_ethernet_lpe_size || - (size > maximum_ethernet_vlan_size - && !(mac[RCTL] & E1000_RCTL_LPE))) - && !(mac[RCTL] & E1000_RCTL_SBP)) { - e1000x_inc_reg_if_not_full(mac, ROC); - trace_e1000x_rx_oversized(size); - return true; - } - - return false; -} - -void e1000x_restart_autoneg(uint32_t *mac, uint16_t *phy, QEMUTimer *timer) -{ - e1000x_update_regs_on_link_down(mac, phy); - trace_e1000x_link_negotiation_start(); - timer_mod(timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500); -} - -void e1000x_reset_mac_addr(NICState *nic, uint32_t *mac_regs, - uint8_t *mac_addr) -{ - int i; - - mac_regs[RA] = 0; - mac_regs[RA + 1] = E1000_RAH_AV; - for (i = 0; i < 4; i++) { - mac_regs[RA] |= mac_addr[i] << (8 * i); - mac_regs[RA + 1] |= - (i < 2) ? mac_addr[i + 4] << (8 * i) : 0; - } - - qemu_format_nic_info_str(qemu_get_queue(nic), mac_addr); - trace_e1000x_mac_indicate(MAC_ARG(mac_addr)); -} - -void e1000x_update_regs_on_autoneg_done(uint32_t *mac, uint16_t *phy) -{ - e1000x_update_regs_on_link_up(mac, phy); - phy[PHY_LP_ABILITY] |= MII_LPAR_LPACK; - phy[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; - trace_e1000x_link_negotiation_done(); -} - -void -e1000x_core_prepare_eeprom(uint16_t *eeprom, - const uint16_t *templ, - uint32_t templ_size, - uint16_t dev_id, - const uint8_t *macaddr) -{ - uint16_t checksum = 0; - int i; - - memmove(eeprom, templ, templ_size); - - for (i = 0; i < 3; i++) { - eeprom[i] = (macaddr[2 * i + 1] << 8) | macaddr[2 * i]; - } - - eeprom[11] = eeprom[13] = dev_id; - - for (i = 0; i < EEPROM_CHECKSUM_REG; i++) { - checksum += eeprom[i]; - } - - checksum = (uint16_t) EEPROM_SUM - checksum; - - eeprom[EEPROM_CHECKSUM_REG] = checksum; -} - -uint32_t -e1000x_rxbufsize(uint32_t rctl) -{ - rctl &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 | - E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 | - E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256; - switch (rctl) { - case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384: - return 16384; - case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192: - return 8192; - case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096: - return 4096; - case E1000_RCTL_SZ_1024: - return 1024; - case E1000_RCTL_SZ_512: - return 512; - case E1000_RCTL_SZ_256: - return 256; - } - return 2048; -} - -void -e1000x_update_rx_total_stats(uint32_t *mac, - size_t data_size, - size_t data_fcs_size) -{ - static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511, - PRC1023, PRC1522 }; - - e1000x_increase_size_stats(mac, PRCregs, data_fcs_size); - e1000x_inc_reg_if_not_full(mac, TPR); - mac[GPRC] = mac[TPR]; - /* TOR - Total Octets Received: - * This register includes bytes received in a packet from the <Destination - * Address> field through the <CRC> field, inclusively. - * Always include FCS length (4) in size. - */ - e1000x_grow_8reg_if_not_full(mac, TORL, data_size + 4); - mac[GORCL] = mac[TORL]; - mac[GORCH] = mac[TORH]; -} - -void -e1000x_increase_size_stats(uint32_t *mac, const int *size_regs, int size) -{ - if (size > 1023) { - e1000x_inc_reg_if_not_full(mac, size_regs[5]); - } else if (size > 511) { - e1000x_inc_reg_if_not_full(mac, size_regs[4]); - } else if (size > 255) { - e1000x_inc_reg_if_not_full(mac, size_regs[3]); - } else if (size > 127) { - e1000x_inc_reg_if_not_full(mac, size_regs[2]); - } else if (size > 64) { - e1000x_inc_reg_if_not_full(mac, size_regs[1]); - } else if (size == 64) { - e1000x_inc_reg_if_not_full(mac, size_regs[0]); - } -} - -void -e1000x_read_tx_ctx_descr(struct e1000_context_desc *d, - e1000x_txd_props *props) -{ - uint32_t op = le32_to_cpu(d->cmd_and_length); - - props->ipcss = d->lower_setup.ip_fields.ipcss; - props->ipcso = d->lower_setup.ip_fields.ipcso; - props->ipcse = le16_to_cpu(d->lower_setup.ip_fields.ipcse); - props->tucss = d->upper_setup.tcp_fields.tucss; - props->tucso = d->upper_setup.tcp_fields.tucso; - props->tucse = le16_to_cpu(d->upper_setup.tcp_fields.tucse); - props->paylen = op & 0xfffff; - props->hdr_len = d->tcp_seg_setup.fields.hdr_len; - props->mss = le16_to_cpu(d->tcp_seg_setup.fields.mss); - props->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0; - props->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0; - props->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0; -} diff --git a/hw/net/e1000x_common.h b/hw/net/e1000x_common.h deleted file mode 100644 index 21bf28e0c..000000000 --- a/hw/net/e1000x_common.h +++ /dev/null @@ -1,213 +0,0 @@ -/* -* QEMU e1000(e) emulation - shared code -* -* Copyright (c) 2008 Qumranet -* -* Based on work done by: -* Nir Peleg, Tutis Systems Ltd. for Qumranet Inc. -* Copyright (c) 2007 Dan Aloni -* Copyright (c) 2004 Antony T Curtis -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "e1000_regs.h" - -#define defreg(x) x = (E1000_##x >> 2) -enum { - defreg(CTRL), defreg(EECD), defreg(EERD), defreg(GPRC), - defreg(GPTC), defreg(ICR), defreg(ICS), defreg(IMC), - defreg(IMS), defreg(LEDCTL), defreg(MANC), defreg(MDIC), - defreg(MPC), defreg(PBA), defreg(RCTL), defreg(RDBAH0), - defreg(RDBAL0), defreg(RDH0), defreg(RDLEN0), defreg(RDT0), - defreg(STATUS), defreg(SWSM), defreg(TCTL), defreg(TDBAH), - defreg(TDBAL), defreg(TDH), defreg(TDLEN), defreg(TDT), - defreg(TDLEN1), defreg(TDBAL1), defreg(TDBAH1), defreg(TDH1), - defreg(TDT1), defreg(TORH), defreg(TORL), defreg(TOTH), - defreg(TOTL), defreg(TPR), defreg(TPT), defreg(TXDCTL), - defreg(WUFC), defreg(RA), defreg(MTA), defreg(CRCERRS), - defreg(VFTA), defreg(VET), defreg(RDTR), defreg(RADV), - defreg(TADV), defreg(ITR), defreg(SCC), defreg(ECOL), - defreg(MCC), defreg(LATECOL), defreg(COLC), defreg(DC), - defreg(TNCRS), defreg(SEC), defreg(CEXTERR), defreg(RLEC), - defreg(XONRXC), defreg(XONTXC), defreg(XOFFRXC), defreg(XOFFTXC), - defreg(FCRUC), defreg(AIT), defreg(TDFH), defreg(TDFT), - defreg(TDFHS), defreg(TDFTS), defreg(TDFPC), defreg(WUC), - defreg(WUS), defreg(POEMB), defreg(PBS), defreg(RDFH), - defreg(RDFT), defreg(RDFHS), defreg(RDFTS), defreg(RDFPC), - defreg(PBM), defreg(IPAV), defreg(IP4AT), defreg(IP6AT), - defreg(WUPM), defreg(FFLT), defreg(FFMT), defreg(FFVT), - defreg(TARC0), defreg(TARC1), defreg(IAM), defreg(EXTCNF_CTRL), - defreg(GCR), defreg(TIMINCA), defreg(EIAC), defreg(CTRL_EXT), - defreg(IVAR), defreg(MFUTP01), defreg(MFUTP23), defreg(MANC2H), - defreg(MFVAL), defreg(MDEF), defreg(FACTPS), defreg(FTFT), - defreg(RUC), defreg(ROC), defreg(RFC), defreg(RJC), - defreg(PRC64), defreg(PRC127), defreg(PRC255), defreg(PRC511), - defreg(PRC1023), defreg(PRC1522), defreg(PTC64), defreg(PTC127), - defreg(PTC255), defreg(PTC511), defreg(PTC1023), defreg(PTC1522), - defreg(GORCL), defreg(GORCH), defreg(GOTCL), defreg(GOTCH), - defreg(RNBC), defreg(BPRC), defreg(MPRC), defreg(RFCTL), - defreg(PSRCTL), defreg(MPTC), defreg(BPTC), defreg(TSCTFC), - defreg(IAC), defreg(MGTPRC), defreg(MGTPDC), defreg(MGTPTC), - defreg(TSCTC), defreg(RXCSUM), defreg(FUNCTAG), defreg(GSCL_1), - defreg(GSCL_2), defreg(GSCL_3), defreg(GSCL_4), defreg(GSCN_0), - defreg(GSCN_1), defreg(GSCN_2), defreg(GSCN_3), defreg(GCR2), - defreg(RAID), defreg(RSRPD), defreg(TIDV), defreg(EITR), - defreg(MRQC), defreg(RETA), defreg(RSSRK), defreg(RDBAH1), - defreg(RDBAL1), defreg(RDLEN1), defreg(RDH1), defreg(RDT1), - defreg(PBACLR), defreg(FCAL), defreg(FCAH), defreg(FCT), - defreg(FCRTH), defreg(FCRTL), defreg(FCTTV), defreg(FCRTV), - defreg(FLA), defreg(EEWR), defreg(FLOP), defreg(FLOL), - defreg(FLSWCTL), defreg(FLSWCNT), defreg(RXDCTL), defreg(RXDCTL1), - defreg(MAVTV0), defreg(MAVTV1), defreg(MAVTV2), defreg(MAVTV3), - defreg(TXSTMPL), defreg(TXSTMPH), defreg(SYSTIML), defreg(SYSTIMH), - defreg(RXCFGL), defreg(RXUDP), defreg(TIMADJL), defreg(TIMADJH), - defreg(RXSTMPH), defreg(RXSTMPL), defreg(RXSATRL), defreg(RXSATRH), - defreg(FLASHT), defreg(TIPG), defreg(RDH), defreg(RDT), - defreg(RDLEN), defreg(RDBAH), defreg(RDBAL), - defreg(TXDCTL1), - defreg(FLSWDATA), - defreg(CTRL_DUP), - defreg(EXTCNF_SIZE), - defreg(EEMNGCTL), - defreg(EEMNGDATA), - defreg(FLMNGCTL), - defreg(FLMNGDATA), - defreg(FLMNGCNT), - defreg(TSYNCRXCTL), - defreg(TSYNCTXCTL), - - /* Aliases */ - defreg(RDH0_A), defreg(RDT0_A), defreg(RDTR_A), defreg(RDFH_A), - defreg(RDFT_A), defreg(TDH_A), defreg(TDT_A), defreg(TIDV_A), - defreg(TDFH_A), defreg(TDFT_A), defreg(RA_A), defreg(RDBAL0_A), - defreg(TDBAL_A), defreg(TDLEN_A), defreg(VFTA_A), defreg(RDLEN0_A), - defreg(FCRTL_A), defreg(FCRTH_A) -}; - -static inline void -e1000x_inc_reg_if_not_full(uint32_t *mac, int index) -{ - if (mac[index] != 0xffffffff) { - mac[index]++; - } -} - -static inline void -e1000x_grow_8reg_if_not_full(uint32_t *mac, int index, int size) -{ - uint64_t sum = mac[index] | (uint64_t)mac[index + 1] << 32; - - if (sum + size < sum) { - sum = ~0ULL; - } else { - sum += size; - } - mac[index] = sum; - mac[index + 1] = sum >> 32; -} - -static inline int -e1000x_vlan_enabled(uint32_t *mac) -{ - return ((mac[CTRL] & E1000_CTRL_VME) != 0); -} - -static inline int -e1000x_is_vlan_txd(uint32_t txd_lower) -{ - return ((txd_lower & E1000_TXD_CMD_VLE) != 0); -} - -static inline int -e1000x_vlan_rx_filter_enabled(uint32_t *mac) -{ - return ((mac[RCTL] & E1000_RCTL_VFE) != 0); -} - -static inline int -e1000x_fcs_len(uint32_t *mac) -{ - /* FCS aka Ethernet CRC-32. We don't get it from backends and can't - * fill it in, just pad descriptor length by 4 bytes unless guest - * told us to strip it off the packet. */ - return (mac[RCTL] & E1000_RCTL_SECRC) ? 0 : 4; -} - -static inline void -e1000x_update_regs_on_link_down(uint32_t *mac, uint16_t *phy) -{ - mac[STATUS] &= ~E1000_STATUS_LU; - phy[PHY_STATUS] &= ~MII_SR_LINK_STATUS; - phy[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE; - phy[PHY_LP_ABILITY] &= ~MII_LPAR_LPACK; -} - -static inline void -e1000x_update_regs_on_link_up(uint32_t *mac, uint16_t *phy) -{ - mac[STATUS] |= E1000_STATUS_LU; - phy[PHY_STATUS] |= MII_SR_LINK_STATUS; -} - -void e1000x_update_rx_total_stats(uint32_t *mac, - size_t data_size, - size_t data_fcs_size); - -void e1000x_core_prepare_eeprom(uint16_t *eeprom, - const uint16_t *templ, - uint32_t templ_size, - uint16_t dev_id, - const uint8_t *macaddr); - -uint32_t e1000x_rxbufsize(uint32_t rctl); - -bool e1000x_rx_ready(PCIDevice *d, uint32_t *mac); - -bool e1000x_is_vlan_packet(const uint8_t *buf, uint16_t vet); - -bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf); - -bool e1000x_hw_rx_enabled(uint32_t *mac); - -bool e1000x_is_oversized(uint32_t *mac, size_t size); - -void e1000x_restart_autoneg(uint32_t *mac, uint16_t *phy, QEMUTimer *timer); - -void e1000x_reset_mac_addr(NICState *nic, uint32_t *mac_regs, - uint8_t *mac_addr); - -void e1000x_update_regs_on_autoneg_done(uint32_t *mac, uint16_t *phy); - -void e1000x_increase_size_stats(uint32_t *mac, const int *size_regs, int size); - -typedef struct e1000x_txd_props { - unsigned char sum_needed; - uint8_t ipcss; - uint8_t ipcso; - uint16_t ipcse; - uint8_t tucss; - uint8_t tucso; - uint16_t tucse; - uint32_t paylen; - uint8_t hdr_len; - uint16_t mss; - int8_t ip; - int8_t tcp; - bool tse; - bool cptse; -} e1000x_txd_props; - -void e1000x_read_tx_ctx_descr(struct e1000_context_desc *d, - e1000x_txd_props *props); diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index bab4dbfc9..9b4b9b59d 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -352,14 +352,14 @@ static unsigned e100_compute_mcast_idx(const uint8_t *ep) static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr) { assert(!((uintptr_t)&s->mem[addr] & 1)); - return lduw_le_p(&s->mem[addr]); + return le16_to_cpup((uint16_t *)&s->mem[addr]); } /* Read a 32 bit control/status (CSR) register. */ static uint32_t e100_read_reg4(EEPRO100State *s, E100RegisterOffset addr) { assert(!((uintptr_t)&s->mem[addr] & 3)); - return ldl_le_p(&s->mem[addr]); + return le32_to_cpup((uint32_t *)&s->mem[addr]); } /* Write a 16 bit control/status (CSR) register. */ @@ -367,7 +367,7 @@ static void e100_write_reg2(EEPRO100State *s, E100RegisterOffset addr, uint16_t val) { assert(!((uintptr_t)&s->mem[addr] & 1)); - stw_le_p(&s->mem[addr], val); + cpu_to_le16w((uint16_t *)&s->mem[addr], val); } /* Read a 32 bit control/status (CSR) register. */ @@ -375,7 +375,7 @@ static void e100_write_reg4(EEPRO100State *s, E100RegisterOffset addr, uint32_t val) { assert(!((uintptr_t)&s->mem[addr] & 3)); - stl_le_p(&s->mem[addr], val); + cpu_to_le32w((uint32_t *)&s->mem[addr], val); } #if defined(DEBUG_EEPRO100) @@ -1848,7 +1848,7 @@ static void pci_nic_uninit(PCIDevice *pci_dev) } static NetClientInfo net_eepro100_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = nic_receive, }; diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c index efaa49faa..05495ec40 100644 --- a/hw/net/etraxfs_eth.c +++ b/hw/net/etraxfs_eth.c @@ -578,7 +578,7 @@ static const MemoryRegionOps eth_ops = { }; static NetClientInfo net_etraxfs_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = eth_receive, .link_status_changed = eth_set_link, diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index b5c777fbf..1e35f7f8c 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -33,7 +33,6 @@ #include "hw/ptimer.h" #include "etsec.h" #include "registers.h" -#include "qemu/log.h" /* #define HEX_DUMP */ /* #define DEBUG_REGISTER */ @@ -371,7 +370,7 @@ static void etsec_set_link_status(NetClientState *nc) } static NetClientInfo net_etsec_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = etsec_receive, .link_status_changed = etsec_set_link_status, diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h index 30c828e24..e7dc0a4b9 100644 --- a/hw/net/fsl_etsec/etsec.h +++ b/hw/net/fsl_etsec/etsec.h @@ -21,9 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - -#ifndef ETSEC_H -#define ETSEC_H +#ifndef _ETSEC_H_ +#define _ETSEC_H_ #include "hw/qdev.h" #include "hw/sysbus.h" @@ -174,4 +173,4 @@ void etsec_write_miim(eTSEC *etsec, void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc); -#endif /* ETSEC_H */ +#endif /* ! _ETSEC_H_ */ diff --git a/hw/net/fsl_etsec/registers.h b/hw/net/fsl_etsec/registers.h index c4ed2b9d6..6fb96842b 100644 --- a/hw/net/fsl_etsec/registers.h +++ b/hw/net/fsl_etsec/registers.h @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#ifndef _ETSEC_REGISTERS_H_ +#define _ETSEC_REGISTERS_H_ -#ifndef ETSEC_REGISTERS_H -#define ETSEC_REGISTERS_H enum eTSEC_Register_Access_Type { ACC_RW = 1, /* Read/Write */ @@ -316,4 +316,4 @@ extern const eTSEC_Register_Definition eTSEC_registers_def[]; #define TMR_ETTS2_H (0xEA8 / 4) #define TMR_ETTS2_L (0xEAC / 4) -#endif /* ETSEC_REGISTERS_H */ +#endif /* ! _ETSEC_REGISTERS_H_ */ diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c index 79d2f14dd..ed1de7da9 100644 --- a/hw/net/fsl_etsec/rings.c +++ b/hw/net/fsl_etsec/rings.c @@ -23,7 +23,7 @@ */ #include "qemu/osdep.h" #include "net/checksum.h" -#include "qemu/log.h" + #include "etsec.h" #include "registers.h" diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 1c415ab3b..e60e3380e 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -24,9 +24,6 @@ #include "qemu/osdep.h" #include "hw/net/imx_fec.h" #include "sysemu/dma.h" -#include "qemu/log.h" -#include "net/checksum.h" -#include "net/eth.h" /* For crc32 */ #include <zlib.h> @@ -55,153 +52,30 @@ } \ } while (0) -static const char *imx_default_reg_name(IMXFECState *s, uint32_t index) -{ - static char tmp[20]; - sprintf(tmp, "index %d", index); - return tmp; -} - -static const char *imx_fec_reg_name(IMXFECState *s, uint32_t index) -{ - switch (index) { - case ENET_FRBR: - return "FRBR"; - case ENET_FRSR: - return "FRSR"; - case ENET_MIIGSK_CFGR: - return "MIIGSK_CFGR"; - case ENET_MIIGSK_ENR: - return "MIIGSK_ENR"; - default: - return imx_default_reg_name(s, index); - } -} - -static const char *imx_enet_reg_name(IMXFECState *s, uint32_t index) -{ - switch (index) { - case ENET_RSFL: - return "RSFL"; - case ENET_RSEM: - return "RSEM"; - case ENET_RAEM: - return "RAEM"; - case ENET_RAFL: - return "RAFL"; - case ENET_TSEM: - return "TSEM"; - case ENET_TAEM: - return "TAEM"; - case ENET_TAFL: - return "TAFL"; - case ENET_TIPG: - return "TIPG"; - case ENET_FTRL: - return "FTRL"; - case ENET_TACC: - return "TACC"; - case ENET_RACC: - return "RACC"; - case ENET_ATCR: - return "ATCR"; - case ENET_ATVR: - return "ATVR"; - case ENET_ATOFF: - return "ATOFF"; - case ENET_ATPER: - return "ATPER"; - case ENET_ATCOR: - return "ATCOR"; - case ENET_ATINC: - return "ATINC"; - case ENET_ATSTMP: - return "ATSTMP"; - case ENET_TGSR: - return "TGSR"; - case ENET_TCSR0: - return "TCSR0"; - case ENET_TCCR0: - return "TCCR0"; - case ENET_TCSR1: - return "TCSR1"; - case ENET_TCCR1: - return "TCCR1"; - case ENET_TCSR2: - return "TCSR2"; - case ENET_TCCR2: - return "TCCR2"; - case ENET_TCSR3: - return "TCSR3"; - case ENET_TCCR3: - return "TCCR3"; - default: - return imx_default_reg_name(s, index); - } -} - -static const char *imx_eth_reg_name(IMXFECState *s, uint32_t index) -{ - switch (index) { - case ENET_EIR: - return "EIR"; - case ENET_EIMR: - return "EIMR"; - case ENET_RDAR: - return "RDAR"; - case ENET_TDAR: - return "TDAR"; - case ENET_ECR: - return "ECR"; - case ENET_MMFR: - return "MMFR"; - case ENET_MSCR: - return "MSCR"; - case ENET_MIBC: - return "MIBC"; - case ENET_RCR: - return "RCR"; - case ENET_TCR: - return "TCR"; - case ENET_PALR: - return "PALR"; - case ENET_PAUR: - return "PAUR"; - case ENET_OPD: - return "OPD"; - case ENET_IAUR: - return "IAUR"; - case ENET_IALR: - return "IALR"; - case ENET_GAUR: - return "GAUR"; - case ENET_GALR: - return "GALR"; - case ENET_TFWR: - return "TFWR"; - case ENET_RDSR: - return "RDSR"; - case ENET_TDSR: - return "TDSR"; - case ENET_MRBR: - return "MRBR"; - default: - if (s->is_fec) { - return imx_fec_reg_name(s, index); - } else { - return imx_enet_reg_name(s, index); - } - } -} - -static const VMStateDescription vmstate_imx_eth = { +static const VMStateDescription vmstate_imx_fec = { .name = TYPE_IMX_FEC, - .version_id = 2, - .minimum_version_id = 2, + .version_id = 1, + .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX), + VMSTATE_UINT32(irq_state, IMXFECState), + VMSTATE_UINT32(eir, IMXFECState), + VMSTATE_UINT32(eimr, IMXFECState), + VMSTATE_UINT32(rx_enabled, IMXFECState), VMSTATE_UINT32(rx_descriptor, IMXFECState), VMSTATE_UINT32(tx_descriptor, IMXFECState), + VMSTATE_UINT32(ecr, IMXFECState), + VMSTATE_UINT32(mmfr, IMXFECState), + VMSTATE_UINT32(mscr, IMXFECState), + VMSTATE_UINT32(mibc, IMXFECState), + VMSTATE_UINT32(rcr, IMXFECState), + VMSTATE_UINT32(tcr, IMXFECState), + VMSTATE_UINT32(tfwr, IMXFECState), + VMSTATE_UINT32(frsr, IMXFECState), + VMSTATE_UINT32(erdsr, IMXFECState), + VMSTATE_UINT32(etdsr, IMXFECState), + VMSTATE_UINT32(emrbr, IMXFECState), + VMSTATE_UINT32(miigsk_cfgr, IMXFECState), + VMSTATE_UINT32(miigsk_enr, IMXFECState), VMSTATE_UINT32(phy_status, IMXFECState), VMSTATE_UINT32(phy_control, IMXFECState), @@ -220,7 +94,7 @@ static const VMStateDescription vmstate_imx_eth = { #define PHY_INT_PARFAULT (1 << 2) #define PHY_INT_AUTONEG_PAGE (1 << 1) -static void imx_eth_update(IMXFECState *s); +static void imx_fec_update(IMXFECState *s); /* * The MII phy could raise a GPIO to the processor which in turn @@ -230,7 +104,7 @@ static void imx_eth_update(IMXFECState *s); */ static void phy_update_irq(IMXFECState *s) { - imx_eth_update(s); + imx_fec_update(s); } static void phy_update_link(IMXFECState *s) @@ -249,7 +123,7 @@ static void phy_update_link(IMXFECState *s) phy_update_irq(s); } -static void imx_eth_set_link(NetClientState *nc) +static void imx_fec_set_link(NetClientState *nc) { phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc))); } @@ -375,35 +249,23 @@ static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr) dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd)); } -static void imx_enet_read_bd(IMXENETBufDesc *bd, dma_addr_t addr) +static void imx_fec_update(IMXFECState *s) { - dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd)); -} + uint32_t active; + uint32_t changed; -static void imx_enet_write_bd(IMXENETBufDesc *bd, dma_addr_t addr) -{ - dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd)); -} - -static void imx_eth_update(IMXFECState *s) -{ - if (s->regs[ENET_EIR] & s->regs[ENET_EIMR] & ENET_INT_TS_TIMER) { - qemu_set_irq(s->irq[1], 1); - } else { - qemu_set_irq(s->irq[1], 0); - } - - if (s->regs[ENET_EIR] & s->regs[ENET_EIMR] & ENET_INT_MAC) { - qemu_set_irq(s->irq[0], 1); - } else { - qemu_set_irq(s->irq[0], 0); + active = s->eir & s->eimr; + changed = active ^ s->irq_state; + if (changed) { + qemu_set_irq(s->irq, active); } + s->irq_state = active; } static void imx_fec_do_tx(IMXFECState *s) { int frame_size = 0; - uint8_t frame[ENET_MAX_FRAME_SIZE]; + uint8_t frame[FEC_MAX_FRAME_SIZE]; uint8_t *ptr = frame; uint32_t addr = s->tx_descriptor; @@ -414,521 +276,272 @@ static void imx_fec_do_tx(IMXFECState *s) imx_fec_read_bd(&bd, addr); FEC_PRINTF("tx_bd %x flags %04x len %d data %08x\n", addr, bd.flags, bd.length, bd.data); - if ((bd.flags & ENET_BD_R) == 0) { + if ((bd.flags & FEC_BD_R) == 0) { /* Run out of descriptors to transmit. */ - FEC_PRINTF("tx_bd ran out of descriptors to transmit\n"); break; } len = bd.length; - if (frame_size + len > ENET_MAX_FRAME_SIZE) { - len = ENET_MAX_FRAME_SIZE - frame_size; - s->regs[ENET_EIR] |= ENET_INT_BABT; + if (frame_size + len > FEC_MAX_FRAME_SIZE) { + len = FEC_MAX_FRAME_SIZE - frame_size; + s->eir |= FEC_INT_BABT; } dma_memory_read(&address_space_memory, bd.data, ptr, len); ptr += len; frame_size += len; - if (bd.flags & ENET_BD_L) { + if (bd.flags & FEC_BD_L) { /* Last buffer in frame. */ qemu_send_packet(qemu_get_queue(s->nic), frame, len); ptr = frame; frame_size = 0; - s->regs[ENET_EIR] |= ENET_INT_TXF; + s->eir |= FEC_INT_TXF; } - s->regs[ENET_EIR] |= ENET_INT_TXB; - bd.flags &= ~ENET_BD_R; + s->eir |= FEC_INT_TXB; + bd.flags &= ~FEC_BD_R; /* Write back the modified descriptor. */ imx_fec_write_bd(&bd, addr); /* Advance to the next descriptor. */ - if ((bd.flags & ENET_BD_W) != 0) { - addr = s->regs[ENET_TDSR]; + if ((bd.flags & FEC_BD_W) != 0) { + addr = s->etdsr; } else { - addr += sizeof(bd); + addr += 8; } } s->tx_descriptor = addr; - imx_eth_update(s); + imx_fec_update(s); } -static void imx_enet_do_tx(IMXFECState *s) -{ - int frame_size = 0; - uint8_t frame[ENET_MAX_FRAME_SIZE]; - uint8_t *ptr = frame; - uint32_t addr = s->tx_descriptor; - - while (1) { - IMXENETBufDesc bd; - int len; - - imx_enet_read_bd(&bd, addr); - FEC_PRINTF("tx_bd %x flags %04x len %d data %08x option %04x " - "status %04x\n", addr, bd.flags, bd.length, bd.data, - bd.option, bd.status); - if ((bd.flags & ENET_BD_R) == 0) { - /* Run out of descriptors to transmit. */ - break; - } - len = bd.length; - if (frame_size + len > ENET_MAX_FRAME_SIZE) { - len = ENET_MAX_FRAME_SIZE - frame_size; - s->regs[ENET_EIR] |= ENET_INT_BABT; - } - dma_memory_read(&address_space_memory, bd.data, ptr, len); - ptr += len; - frame_size += len; - if (bd.flags & ENET_BD_L) { - if (bd.option & ENET_BD_PINS) { - struct ip_header *ip_hd = PKT_GET_IP_HDR(frame); - if (IP_HEADER_VERSION(ip_hd) == 4) { - net_checksum_calculate(frame, frame_size); - } - } - if (bd.option & ENET_BD_IINS) { - struct ip_header *ip_hd = PKT_GET_IP_HDR(frame); - /* We compute checksum only for IPv4 frames */ - if (IP_HEADER_VERSION(ip_hd) == 4) { - uint16_t csum; - ip_hd->ip_sum = 0; - csum = net_raw_checksum((uint8_t *)ip_hd, sizeof(*ip_hd)); - ip_hd->ip_sum = cpu_to_be16(csum); - } - } - /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), frame, len); - ptr = frame; - frame_size = 0; - if (bd.option & ENET_BD_TX_INT) { - s->regs[ENET_EIR] |= ENET_INT_TXF; - } - } - if (bd.option & ENET_BD_TX_INT) { - s->regs[ENET_EIR] |= ENET_INT_TXB; - } - bd.flags &= ~ENET_BD_R; - /* Write back the modified descriptor. */ - imx_enet_write_bd(&bd, addr); - /* Advance to the next descriptor. */ - if ((bd.flags & ENET_BD_W) != 0) { - addr = s->regs[ENET_TDSR]; - } else { - addr += sizeof(bd); - } - } - - s->tx_descriptor = addr; - - imx_eth_update(s); -} - -static void imx_eth_do_tx(IMXFECState *s) -{ - if (!s->is_fec && (s->regs[ENET_ECR] & ENET_ECR_EN1588)) { - imx_enet_do_tx(s); - } else { - imx_fec_do_tx(s); - } -} - -static void imx_eth_enable_rx(IMXFECState *s) +static void imx_fec_enable_rx(IMXFECState *s) { IMXFECBufDesc bd; - bool tmp; + uint32_t tmp; imx_fec_read_bd(&bd, s->rx_descriptor); - tmp = ((bd.flags & ENET_BD_E) != 0); + tmp = ((bd.flags & FEC_BD_E) != 0); if (!tmp) { FEC_PRINTF("RX buffer full\n"); - } else if (!s->regs[ENET_RDAR]) { + } else if (!s->rx_enabled) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } - s->regs[ENET_RDAR] = tmp ? ENET_RDAR_RDAR : 0; + s->rx_enabled = tmp; } -static void imx_eth_reset(DeviceState *d) +static void imx_fec_reset(DeviceState *d) { IMXFECState *s = IMX_FEC(d); - /* Reset the Device */ - memset(s->regs, 0, sizeof(s->regs)); - s->regs[ENET_ECR] = 0xf0000000; - s->regs[ENET_MIBC] = 0xc0000000; - s->regs[ENET_RCR] = 0x05ee0001; - s->regs[ENET_OPD] = 0x00010000; - - s->regs[ENET_PALR] = (s->conf.macaddr.a[0] << 24) - | (s->conf.macaddr.a[1] << 16) - | (s->conf.macaddr.a[2] << 8) - | s->conf.macaddr.a[3]; - s->regs[ENET_PAUR] = (s->conf.macaddr.a[4] << 24) - | (s->conf.macaddr.a[5] << 16) - | 0x8808; - - if (s->is_fec) { - s->regs[ENET_FRBR] = 0x00000600; - s->regs[ENET_FRSR] = 0x00000500; - s->regs[ENET_MIIGSK_ENR] = 0x00000006; - } else { - s->regs[ENET_RAEM] = 0x00000004; - s->regs[ENET_RAFL] = 0x00000004; - s->regs[ENET_TAEM] = 0x00000004; - s->regs[ENET_TAFL] = 0x00000008; - s->regs[ENET_TIPG] = 0x0000000c; - s->regs[ENET_FTRL] = 0x000007ff; - s->regs[ENET_ATPER] = 0x3b9aca00; - } - - s->rx_descriptor = 0; - s->tx_descriptor = 0; + /* Reset the FEC */ + s->eir = 0; + s->eimr = 0; + s->rx_enabled = 0; + s->ecr = 0; + s->mscr = 0; + s->mibc = 0xc0000000; + s->rcr = 0x05ee0001; + s->tcr = 0; + s->tfwr = 0; + s->frsr = 0x500; + s->miigsk_cfgr = 0; + s->miigsk_enr = 0x6; /* We also reset the PHY */ phy_reset(s); } -static uint32_t imx_default_read(IMXFECState *s, uint32_t index) -{ - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - PRIx32 "\n", TYPE_IMX_FEC, __func__, index * 4); - return 0; -} - -static uint32_t imx_fec_read(IMXFECState *s, uint32_t index) -{ - switch (index) { - case ENET_FRBR: - case ENET_FRSR: - case ENET_MIIGSK_CFGR: - case ENET_MIIGSK_ENR: - return s->regs[index]; - default: - return imx_default_read(s, index); - } -} - -static uint32_t imx_enet_read(IMXFECState *s, uint32_t index) +static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size) { - switch (index) { - case ENET_RSFL: - case ENET_RSEM: - case ENET_RAEM: - case ENET_RAFL: - case ENET_TSEM: - case ENET_TAEM: - case ENET_TAFL: - case ENET_TIPG: - case ENET_FTRL: - case ENET_TACC: - case ENET_RACC: - case ENET_ATCR: - case ENET_ATVR: - case ENET_ATOFF: - case ENET_ATPER: - case ENET_ATCOR: - case ENET_ATINC: - case ENET_ATSTMP: - case ENET_TGSR: - case ENET_TCSR0: - case ENET_TCCR0: - case ENET_TCSR1: - case ENET_TCCR1: - case ENET_TCSR2: - case ENET_TCCR2: - case ENET_TCSR3: - case ENET_TCCR3: - return s->regs[index]; - default: - return imx_default_read(s, index); - } -} - -static uint64_t imx_eth_read(void *opaque, hwaddr offset, unsigned size) -{ - uint32_t value = 0; IMXFECState *s = IMX_FEC(opaque); - uint32_t index = offset >> 2; - - switch (index) { - case ENET_EIR: - case ENET_EIMR: - case ENET_RDAR: - case ENET_TDAR: - case ENET_ECR: - case ENET_MMFR: - case ENET_MSCR: - case ENET_MIBC: - case ENET_RCR: - case ENET_TCR: - case ENET_PALR: - case ENET_PAUR: - case ENET_OPD: - case ENET_IAUR: - case ENET_IALR: - case ENET_GAUR: - case ENET_GALR: - case ENET_TFWR: - case ENET_RDSR: - case ENET_TDSR: - case ENET_MRBR: - value = s->regs[index]; - break; - default: - if (s->is_fec) { - value = imx_fec_read(s, index); - } else { - value = imx_enet_read(s, index); - } - break; - } - - FEC_PRINTF("reg[%s] => 0x%" PRIx32 "\n", imx_eth_reg_name(s, index), - value); - - return value; -} - -static void imx_default_write(IMXFECState *s, uint32_t index, uint32_t value) -{ - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" - PRIx32 "\n", TYPE_IMX_FEC, __func__, index * 4); - return; -} - -static void imx_fec_write(IMXFECState *s, uint32_t index, uint32_t value) -{ - switch (index) { - case ENET_FRBR: - /* FRBR is read only */ - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Register FRBR is read only\n", - TYPE_IMX_FEC, __func__); - break; - case ENET_FRSR: - s->regs[index] = (value & 0x000003fc) | 0x00000400; - break; - case ENET_MIIGSK_CFGR: - s->regs[index] = value & 0x00000053; - break; - case ENET_MIIGSK_ENR: - s->regs[index] = (value & 0x00000002) ? 0x00000006 : 0; - break; - default: - imx_default_write(s, index, value); - break; - } -} -static void imx_enet_write(IMXFECState *s, uint32_t index, uint32_t value) -{ - switch (index) { - case ENET_RSFL: - case ENET_RSEM: - case ENET_RAEM: - case ENET_RAFL: - case ENET_TSEM: - case ENET_TAEM: - case ENET_TAFL: - s->regs[index] = value & 0x000001ff; - break; - case ENET_TIPG: - s->regs[index] = value & 0x0000001f; - break; - case ENET_FTRL: - s->regs[index] = value & 0x00003fff; - break; - case ENET_TACC: - s->regs[index] = value & 0x00000019; - break; - case ENET_RACC: - s->regs[index] = value & 0x000000C7; - break; - case ENET_ATCR: - s->regs[index] = value & 0x00002a9d; - break; - case ENET_ATVR: - case ENET_ATOFF: - case ENET_ATPER: - s->regs[index] = value; - break; - case ENET_ATSTMP: - /* ATSTMP is read only */ - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Register ATSTMP is read only\n", - TYPE_IMX_FEC, __func__); - break; - case ENET_ATCOR: - s->regs[index] = value & 0x7fffffff; - break; - case ENET_ATINC: - s->regs[index] = value & 0x00007f7f; - break; - case ENET_TGSR: - /* implement clear timer flag */ - value = value & 0x0000000f; - break; - case ENET_TCSR0: - case ENET_TCSR1: - case ENET_TCSR2: - case ENET_TCSR3: - value = value & 0x000000fd; - break; - case ENET_TCCR0: - case ENET_TCCR1: - case ENET_TCCR2: - case ENET_TCCR3: - s->regs[index] = value; - break; + FEC_PRINTF("reading from @ 0x%" HWADDR_PRIx "\n", addr); + + switch (addr & 0x3ff) { + case 0x004: + return s->eir; + case 0x008: + return s->eimr; + case 0x010: + return s->rx_enabled ? (1 << 24) : 0; /* RDAR */ + case 0x014: + return 0; /* TDAR */ + case 0x024: + return s->ecr; + case 0x040: + return s->mmfr; + case 0x044: + return s->mscr; + case 0x064: + return s->mibc; /* MIBC */ + case 0x084: + return s->rcr; + case 0x0c4: + return s->tcr; + case 0x0e4: /* PALR */ + return (s->conf.macaddr.a[0] << 24) + | (s->conf.macaddr.a[1] << 16) + | (s->conf.macaddr.a[2] << 8) + | s->conf.macaddr.a[3]; + break; + case 0x0e8: /* PAUR */ + return (s->conf.macaddr.a[4] << 24) + | (s->conf.macaddr.a[5] << 16) + | 0x8808; + case 0x0ec: + return 0x10000; /* OPD */ + case 0x118: + return 0; + case 0x11c: + return 0; + case 0x120: + return 0; + case 0x124: + return 0; + case 0x144: + return s->tfwr; + case 0x14c: + return 0x600; + case 0x150: + return s->frsr; + case 0x180: + return s->erdsr; + case 0x184: + return s->etdsr; + case 0x188: + return s->emrbr; + case 0x300: + return s->miigsk_cfgr; + case 0x308: + return s->miigsk_enr; default: - imx_default_write(s, index, value); - break; + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr); + return 0; } } -static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) +static void imx_fec_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) { IMXFECState *s = IMX_FEC(opaque); - uint32_t index = offset >> 2; - FEC_PRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_eth_reg_name(s, index), - (uint32_t)value); + FEC_PRINTF("writing 0x%08x @ 0x%" HWADDR_PRIx "\n", (int)value, addr); - switch (index) { - case ENET_EIR: - s->regs[index] &= ~value; + switch (addr & 0x3ff) { + case 0x004: /* EIR */ + s->eir &= ~value; break; - case ENET_EIMR: - s->regs[index] = value; + case 0x008: /* EIMR */ + s->eimr = value; break; - case ENET_RDAR: - if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) { - if (!s->regs[index]) { - s->regs[index] = ENET_RDAR_RDAR; - imx_eth_enable_rx(s); - } - } else { - s->regs[index] = 0; + case 0x010: /* RDAR */ + if ((s->ecr & FEC_EN) && !s->rx_enabled) { + imx_fec_enable_rx(s); } break; - case ENET_TDAR: - if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) { - s->regs[index] = ENET_TDAR_TDAR; - imx_eth_do_tx(s); + case 0x014: /* TDAR */ + if (s->ecr & FEC_EN) { + imx_fec_do_tx(s); } - s->regs[index] = 0; break; - case ENET_ECR: - if (value & ENET_ECR_RESET) { - return imx_eth_reset(DEVICE(s)); + case 0x024: /* ECR */ + s->ecr = value; + if (value & FEC_RESET) { + imx_fec_reset(DEVICE(s)); } - s->regs[index] = value; - if ((s->regs[index] & ENET_ECR_ETHEREN) == 0) { - s->regs[ENET_RDAR] = 0; - s->rx_descriptor = s->regs[ENET_RDSR]; - s->regs[ENET_TDAR] = 0; - s->tx_descriptor = s->regs[ENET_TDSR]; + if ((s->ecr & FEC_EN) == 0) { + s->rx_enabled = 0; } break; - case ENET_MMFR: - s->regs[index] = value; - if (extract32(value, 29, 1)) { - /* This is a read operation */ - s->regs[ENET_MMFR] = deposit32(s->regs[ENET_MMFR], 0, 16, - do_phy_read(s, - extract32(value, - 18, 10))); + case 0x040: /* MMFR */ + /* store the value */ + s->mmfr = value; + if (extract32(value, 28, 1)) { + do_phy_write(s, extract32(value, 18, 9), extract32(value, 0, 16)); } else { - /* This a write operation */ - do_phy_write(s, extract32(value, 18, 10), extract32(value, 0, 16)); + s->mmfr = do_phy_read(s, extract32(value, 18, 9)); } /* raise the interrupt as the PHY operation is done */ - s->regs[ENET_EIR] |= ENET_INT_MII; + s->eir |= FEC_INT_MII; break; - case ENET_MSCR: - s->regs[index] = value & 0xfe; + case 0x044: /* MSCR */ + s->mscr = value & 0xfe; break; - case ENET_MIBC: + case 0x064: /* MIBC */ /* TODO: Implement MIB. */ - s->regs[index] = (value & 0x80000000) ? 0xc0000000 : 0; + s->mibc = (value & 0x80000000) ? 0xc0000000 : 0; break; - case ENET_RCR: - s->regs[index] = value & 0x07ff003f; + case 0x084: /* RCR */ + s->rcr = value & 0x07ff003f; /* TODO: Implement LOOP mode. */ break; - case ENET_TCR: + case 0x0c4: /* TCR */ /* We transmit immediately, so raise GRA immediately. */ - s->regs[index] = value; + s->tcr = value; if (value & 1) { - s->regs[ENET_EIR] |= ENET_INT_GRA; + s->eir |= FEC_INT_GRA; } break; - case ENET_PALR: - s->regs[index] = value; + case 0x0e4: /* PALR */ s->conf.macaddr.a[0] = value >> 24; s->conf.macaddr.a[1] = value >> 16; s->conf.macaddr.a[2] = value >> 8; s->conf.macaddr.a[3] = value; break; - case ENET_PAUR: - s->regs[index] = (value | 0x0000ffff) & 0xffff8808; + case 0x0e8: /* PAUR */ s->conf.macaddr.a[4] = value >> 24; s->conf.macaddr.a[5] = value >> 16; break; - case ENET_OPD: - s->regs[index] = (value & 0x0000ffff) | 0x00010000; + case 0x0ec: /* OPDR */ break; - case ENET_IAUR: - case ENET_IALR: - case ENET_GAUR: - case ENET_GALR: + case 0x118: /* IAUR */ + case 0x11c: /* IALR */ + case 0x120: /* GAUR */ + case 0x124: /* GALR */ /* TODO: implement MAC hash filtering. */ break; - case ENET_TFWR: - if (s->is_fec) { - s->regs[index] = value & 0x3; - } else { - s->regs[index] = value & 0x13f; - } + case 0x144: /* TFWR */ + s->tfwr = value & 3; break; - case ENET_RDSR: - if (s->is_fec) { - s->regs[index] = value & ~3; - } else { - s->regs[index] = value & ~7; - } - s->rx_descriptor = s->regs[index]; + case 0x14c: /* FRBR */ + /* FRBR writes ignored. */ break; - case ENET_TDSR: - if (s->is_fec) { - s->regs[index] = value & ~3; - } else { - s->regs[index] = value & ~7; - } - s->tx_descriptor = s->regs[index]; + case 0x150: /* FRSR */ + s->frsr = (value & 0x3fc) | 0x400; + break; + case 0x180: /* ERDSR */ + s->erdsr = value & ~3; + s->rx_descriptor = s->erdsr; break; - case ENET_MRBR: - s->regs[index] = value & 0x00003ff0; + case 0x184: /* ETDSR */ + s->etdsr = value & ~3; + s->tx_descriptor = s->etdsr; + break; + case 0x188: /* EMRBR */ + s->emrbr = value & 0x7f0; + break; + case 0x300: /* MIIGSK_CFGR */ + s->miigsk_cfgr = value & 0x53; + break; + case 0x308: /* MIIGSK_ENR */ + s->miigsk_enr = (value & 0x2) ? 0x6 : 0; break; default: - if (s->is_fec) { - imx_fec_write(s, index, value); - } else { - imx_enet_write(s, index, value); - } - return; + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr); + break; } - imx_eth_update(s); + imx_fec_update(s); } -static int imx_eth_can_receive(NetClientState *nc) +static int imx_fec_can_receive(NetClientState *nc) { IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); - FEC_PRINTF("\n"); - - return s->regs[ENET_RDAR] ? 1 : 0; + return s->rx_enabled; } static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, @@ -946,7 +559,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, FEC_PRINTF("len %d\n", (int)size); - if (!s->regs[ENET_RDAR]) { + if (!s->rx_enabled) { qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Unexpected packet\n", TYPE_IMX_FEC, __func__); return 0; @@ -957,21 +570,21 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, crc = cpu_to_be32(crc32(~0, buf, size)); crc_ptr = (uint8_t *) &crc; - /* Huge frames are truncated. */ - if (size > ENET_MAX_FRAME_SIZE) { - size = ENET_MAX_FRAME_SIZE; - flags |= ENET_BD_TR | ENET_BD_LG; + /* Huge frames are truncted. */ + if (size > FEC_MAX_FRAME_SIZE) { + size = FEC_MAX_FRAME_SIZE; + flags |= FEC_BD_TR | FEC_BD_LG; } /* Frames larger than the user limit just set error flags. */ - if (size > (s->regs[ENET_RCR] >> 16)) { - flags |= ENET_BD_LG; + if (size > (s->rcr >> 16)) { + flags |= FEC_BD_LG; } addr = s->rx_descriptor; while (size > 0) { imx_fec_read_bd(&bd, addr); - if ((bd.flags & ENET_BD_E) == 0) { + if ((bd.flags & FEC_BD_E) == 0) { /* No descriptors available. Bail out. */ /* * FIXME: This is wrong. We should probably either @@ -982,7 +595,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, TYPE_IMX_FEC, __func__); break; } - buf_len = (size <= s->regs[ENET_MRBR]) ? size : s->regs[ENET_MRBR]; + buf_len = (size <= s->emrbr) ? size : s->emrbr; bd.length = buf_len; size -= buf_len; @@ -1000,232 +613,99 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, crc_ptr, 4 - size); crc_ptr += 4 - size; } - bd.flags &= ~ENET_BD_E; + bd.flags &= ~FEC_BD_E; if (size == 0) { /* Last buffer in frame. */ - bd.flags |= flags | ENET_BD_L; + bd.flags |= flags | FEC_BD_L; FEC_PRINTF("rx frame flags %04x\n", bd.flags); - s->regs[ENET_EIR] |= ENET_INT_RXF; + s->eir |= FEC_INT_RXF; } else { - s->regs[ENET_EIR] |= ENET_INT_RXB; + s->eir |= FEC_INT_RXB; } imx_fec_write_bd(&bd, addr); /* Advance to the next descriptor. */ - if ((bd.flags & ENET_BD_W) != 0) { - addr = s->regs[ENET_RDSR]; - } else { - addr += sizeof(bd); - } - } - s->rx_descriptor = addr; - imx_eth_enable_rx(s); - imx_eth_update(s); - return len; -} - -static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, - size_t len) -{ - IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); - IMXENETBufDesc bd; - uint32_t flags = 0; - uint32_t addr; - uint32_t crc; - uint32_t buf_addr; - uint8_t *crc_ptr; - unsigned int buf_len; - size_t size = len; - - FEC_PRINTF("len %d\n", (int)size); - - if (!s->regs[ENET_RDAR]) { - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Unexpected packet\n", - TYPE_IMX_FEC, __func__); - return 0; - } - - /* 4 bytes for the CRC. */ - size += 4; - crc = cpu_to_be32(crc32(~0, buf, size)); - crc_ptr = (uint8_t *) &crc; - - /* Huge frames are truncted. */ - if (size > ENET_MAX_FRAME_SIZE) { - size = ENET_MAX_FRAME_SIZE; - flags |= ENET_BD_TR | ENET_BD_LG; - } - - /* Frames larger than the user limit just set error flags. */ - if (size > (s->regs[ENET_RCR] >> 16)) { - flags |= ENET_BD_LG; - } - - addr = s->rx_descriptor; - while (size > 0) { - imx_enet_read_bd(&bd, addr); - if ((bd.flags & ENET_BD_E) == 0) { - /* No descriptors available. Bail out. */ - /* - * FIXME: This is wrong. We should probably either - * save the remainder for when more RX buffers are - * available, or flag an error. - */ - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Lost end of frame\n", - TYPE_IMX_FEC, __func__); - break; - } - buf_len = (size <= s->regs[ENET_MRBR]) ? size : s->regs[ENET_MRBR]; - bd.length = buf_len; - size -= buf_len; - - FEC_PRINTF("rx_bd 0x%x length %d\n", addr, bd.length); - - /* The last 4 bytes are the CRC. */ - if (size < 4) { - buf_len += size - 4; - } - buf_addr = bd.data; - dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); - buf += buf_len; - if (size < 4) { - dma_memory_write(&address_space_memory, buf_addr + buf_len, - crc_ptr, 4 - size); - crc_ptr += 4 - size; - } - bd.flags &= ~ENET_BD_E; - if (size == 0) { - /* Last buffer in frame. */ - bd.flags |= flags | ENET_BD_L; - FEC_PRINTF("rx frame flags %04x\n", bd.flags); - if (bd.option & ENET_BD_RX_INT) { - s->regs[ENET_EIR] |= ENET_INT_RXF; - } - } else { - if (bd.option & ENET_BD_RX_INT) { - s->regs[ENET_EIR] |= ENET_INT_RXB; - } - } - imx_enet_write_bd(&bd, addr); - /* Advance to the next descriptor. */ - if ((bd.flags & ENET_BD_W) != 0) { - addr = s->regs[ENET_RDSR]; + if ((bd.flags & FEC_BD_W) != 0) { + addr = s->erdsr; } else { - addr += sizeof(bd); + addr += 8; } } s->rx_descriptor = addr; - imx_eth_enable_rx(s); - imx_eth_update(s); + imx_fec_enable_rx(s); + imx_fec_update(s); return len; } -static ssize_t imx_eth_receive(NetClientState *nc, const uint8_t *buf, - size_t len) -{ - IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); - - if (!s->is_fec && (s->regs[ENET_ECR] & ENET_ECR_EN1588)) { - return imx_enet_receive(nc, buf, len); - } else { - return imx_fec_receive(nc, buf, len); - } -} - -static const MemoryRegionOps imx_eth_ops = { - .read = imx_eth_read, - .write = imx_eth_write, +static const MemoryRegionOps imx_fec_ops = { + .read = imx_fec_read, + .write = imx_fec_write, .valid.min_access_size = 4, .valid.max_access_size = 4, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_NATIVE_ENDIAN, }; -static void imx_eth_cleanup(NetClientState *nc) +static void imx_fec_cleanup(NetClientState *nc) { IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); s->nic = NULL; } -static NetClientInfo imx_eth_net_info = { - .type = NET_CLIENT_DRIVER_NIC, - .size = sizeof(NICState), - .can_receive = imx_eth_can_receive, - .receive = imx_eth_receive, - .cleanup = imx_eth_cleanup, - .link_status_changed = imx_eth_set_link, +static NetClientInfo net_imx_fec_info = { + .type = NET_CLIENT_OPTIONS_KIND_NIC, + .size = sizeof(NICState), + .can_receive = imx_fec_can_receive, + .receive = imx_fec_receive, + .cleanup = imx_fec_cleanup, + .link_status_changed = imx_fec_set_link, }; -static void imx_eth_realize(DeviceState *dev, Error **errp) +static void imx_fec_realize(DeviceState *dev, Error **errp) { IMXFECState *s = IMX_FEC(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - memory_region_init_io(&s->iomem, OBJECT(dev), &imx_eth_ops, s, + memory_region_init_io(&s->iomem, OBJECT(dev), &imx_fec_ops, s, TYPE_IMX_FEC, 0x400); sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq[0]); - sysbus_init_irq(sbd, &s->irq[1]); - + sysbus_init_irq(sbd, &s->irq); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->conf.peers.ncs[0] = nd_table[0].netdev; - s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf, - object_get_typename(OBJECT(dev)), - DEVICE(dev)->id, s); - + s->nic = qemu_new_nic(&net_imx_fec_info, &s->conf, + object_get_typename(OBJECT(dev)), DEVICE(dev)->id, + s); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); } -static Property imx_eth_properties[] = { +static Property imx_fec_properties[] = { DEFINE_NIC_PROPERTIES(IMXFECState, conf), DEFINE_PROP_END_OF_LIST(), }; -static void imx_eth_class_init(ObjectClass *klass, void *data) +static void imx_fec_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->vmsd = &vmstate_imx_eth; - dc->reset = imx_eth_reset; - dc->props = imx_eth_properties; - dc->realize = imx_eth_realize; - dc->desc = "i.MX FEC/ENET Ethernet Controller"; -} - -static void imx_fec_init(Object *obj) -{ - IMXFECState *s = IMX_FEC(obj); - - s->is_fec = true; -} - -static void imx_enet_init(Object *obj) -{ - IMXFECState *s = IMX_FEC(obj); - - s->is_fec = false; + dc->vmsd = &vmstate_imx_fec; + dc->reset = imx_fec_reset; + dc->props = imx_fec_properties; + dc->realize = imx_fec_realize; + dc->desc = "i.MX FEC Ethernet Controller"; } static const TypeInfo imx_fec_info = { - .name = TYPE_IMX_FEC, - .parent = TYPE_SYS_BUS_DEVICE, + .name = TYPE_IMX_FEC, + .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IMXFECState), - .instance_init = imx_fec_init, - .class_init = imx_eth_class_init, -}; - -static const TypeInfo imx_enet_info = { - .name = TYPE_IMX_ENET, - .parent = TYPE_IMX_FEC, - .instance_init = imx_enet_init, + .class_init = imx_fec_class_init, }; -static void imx_eth_register_types(void) +static void imx_fec_register_types(void) { type_register_static(&imx_fec_info); - type_register_static(&imx_enet_info); } -type_init(imx_eth_register_types) +type_init(imx_fec_register_types) diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 4615d873b..08dc474d6 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -16,7 +16,6 @@ #include "hw/devices.h" #include "sysemu/sysemu.h" #include "hw/ptimer.h" -#include "qemu/log.h" /* For crc32 */ #include <zlib.h> @@ -1313,7 +1312,7 @@ static const MemoryRegionOps lan9118_16bit_mem_ops = { }; static NetClientInfo net_lan9118_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = lan9118_receive, .link_status_changed = lan9118_set_link, diff --git a/hw/net/lance.c b/hw/net/lance.c index 573d724bc..6253d2103 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -93,7 +93,7 @@ static const MemoryRegionOps lance_mem_ops = { }; static NetClientInfo net_lance_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = pcnet_receive, .link_status_changed = pcnet_set_link_status, diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index 0ee8ad9d6..7c0398ed9 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -507,7 +507,7 @@ static const MemoryRegionOps mcf_fec_ops = { }; static NetClientInfo net_mcf_fec_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = mcf_fec_receive, }; diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c index c3a12e119..1e147c33c 100644 --- a/hw/net/milkymist-minimac2.c +++ b/hw/net/milkymist-minimac2.c @@ -447,7 +447,7 @@ static void milkymist_minimac2_reset(DeviceState *d) } static NetClientInfo net_milkymist_minimac2_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = minimac2_rx, }; diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c index 5a63df7cc..cf8b8236d 100644 --- a/hw/net/mipsnet.c +++ b/hw/net/mipsnet.c @@ -183,12 +183,10 @@ static void mipsnet_ioport_write(void *opaque, hwaddr addr, break; case MIPSNET_TX_DATA_BUFFER: s->tx_buffer[s->tx_written++] = val; - if ((s->tx_written >= MAX_ETH_FRAME_SIZE) - || (s->tx_written == s->tx_count)) { + if (s->tx_written == s->tx_count) { /* Send buffer. */ - trace_mipsnet_send(s->tx_written); - qemu_send_packet(qemu_get_queue(s->nic), - s->tx_buffer, s->tx_written); + trace_mipsnet_send(s->tx_count); + qemu_send_packet(qemu_get_queue(s->nic), s->tx_buffer, s->tx_count); s->tx_count = s->tx_written = 0; s->intctl |= MIPSNET_INTCTL_TXDONE; s->busy = 1; @@ -224,7 +222,7 @@ static const VMStateDescription vmstate_mipsnet = { }; static NetClientInfo net_mipsnet_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = mipsnet_receive, }; diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index f3455339e..a7f5a9464 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -44,7 +44,7 @@ typedef struct ISANE2000State { } ISANE2000State; static NetClientInfo net_ne2000_isa_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = ne2000_receive, }; @@ -127,7 +127,9 @@ static void isa_ne2000_set_bootindex(Object *obj, Visitor *v, s->c.bootindex = boot_index; out: - error_propagate(errp, local_err); + if (local_err) { + error_propagate(errp, local_err); + } } static void isa_ne2000_instance_init(Object *obj) diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 798d681e2..f0feaf96b 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -712,7 +712,7 @@ void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size) } static NetClientInfo net_ne2000_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = ne2000_receive, }; diff --git a/hw/net/ne2000.h b/hw/net/ne2000.h index d213dccae..d022b28fc 100644 --- a/hw/net/ne2000.h +++ b/hw/net/ne2000.h @@ -1,5 +1,5 @@ #ifndef HW_NE2000_H -#define HW_NE2000_H +#define HW_NE2000_H 1 #define NE2000_PMEM_SIZE (32*1024) #define NE2000_PMEM_START (16*1024) diff --git a/hw/net/net_rx_pkt.c b/hw/net/net_rx_pkt.c deleted file mode 100644 index 1019b50c1..000000000 --- a/hw/net/net_rx_pkt.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * QEMU RX packets abstractions - * - * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) - * - * Developed by Daynix Computing LTD (http://www.daynix.com) - * - * Authors: - * Dmitry Fleytman <dmitry@daynix.com> - * Tamir Shomer <tamirs@daynix.com> - * Yan Vugenfirer <yan@daynix.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 "trace.h" -#include "net_rx_pkt.h" -#include "net/checksum.h" -#include "net/tap.h" - -struct NetRxPkt { - struct virtio_net_hdr virt_hdr; - uint8_t ehdr_buf[sizeof(struct eth_header)]; - struct iovec *vec; - uint16_t vec_len_total; - uint16_t vec_len; - uint32_t tot_len; - uint16_t tci; - bool vlan_stripped; - bool has_virt_hdr; - eth_pkt_types_e packet_type; - - /* Analysis results */ - bool isip4; - bool isip6; - bool isudp; - bool istcp; - - size_t l3hdr_off; - size_t l4hdr_off; - size_t l5hdr_off; - - eth_ip6_hdr_info ip6hdr_info; - eth_ip4_hdr_info ip4hdr_info; - eth_l4_hdr_info l4hdr_info; -}; - -void net_rx_pkt_init(struct NetRxPkt **pkt, bool has_virt_hdr) -{ - struct NetRxPkt *p = g_malloc0(sizeof *p); - p->has_virt_hdr = has_virt_hdr; - p->vec = NULL; - p->vec_len_total = 0; - *pkt = p; -} - -void net_rx_pkt_uninit(struct NetRxPkt *pkt) -{ - if (pkt->vec_len_total != 0) { - g_free(pkt->vec); - } - - g_free(pkt); -} - -struct virtio_net_hdr *net_rx_pkt_get_vhdr(struct NetRxPkt *pkt) -{ - assert(pkt); - return &pkt->virt_hdr; -} - -static inline void -net_rx_pkt_iovec_realloc(struct NetRxPkt *pkt, - int new_iov_len) -{ - if (pkt->vec_len_total < new_iov_len) { - g_free(pkt->vec); - pkt->vec = g_malloc(sizeof(*pkt->vec) * new_iov_len); - pkt->vec_len_total = new_iov_len; - } -} - -static void -net_rx_pkt_pull_data(struct NetRxPkt *pkt, - const struct iovec *iov, int iovcnt, - size_t ploff) -{ - if (pkt->vlan_stripped) { - net_rx_pkt_iovec_realloc(pkt, iovcnt + 1); - - pkt->vec[0].iov_base = pkt->ehdr_buf; - pkt->vec[0].iov_len = sizeof(pkt->ehdr_buf); - - pkt->tot_len = - iov_size(iov, iovcnt) - ploff + sizeof(struct eth_header); - - pkt->vec_len = iov_copy(pkt->vec + 1, pkt->vec_len_total - 1, - iov, iovcnt, ploff, pkt->tot_len); - } else { - net_rx_pkt_iovec_realloc(pkt, iovcnt); - - pkt->tot_len = iov_size(iov, iovcnt) - ploff; - pkt->vec_len = iov_copy(pkt->vec, pkt->vec_len_total, - iov, iovcnt, ploff, pkt->tot_len); - } - - eth_get_protocols(pkt->vec, pkt->vec_len, &pkt->isip4, &pkt->isip6, - &pkt->isudp, &pkt->istcp, - &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, - &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); - - trace_net_rx_pkt_parsed(pkt->isip4, pkt->isip6, pkt->isudp, pkt->istcp, - pkt->l3hdr_off, pkt->l4hdr_off, pkt->l5hdr_off); -} - -void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt, - const struct iovec *iov, int iovcnt, - size_t iovoff, bool strip_vlan) -{ - uint16_t tci = 0; - uint16_t ploff = iovoff; - assert(pkt); - pkt->vlan_stripped = false; - - if (strip_vlan) { - pkt->vlan_stripped = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf, - &ploff, &tci); - } - - pkt->tci = tci; - - net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff); -} - -void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt, - const struct iovec *iov, int iovcnt, - size_t iovoff, bool strip_vlan, - uint16_t vet) -{ - uint16_t tci = 0; - uint16_t ploff = iovoff; - assert(pkt); - pkt->vlan_stripped = false; - - if (strip_vlan) { - pkt->vlan_stripped = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet, - pkt->ehdr_buf, - &ploff, &tci); - } - - pkt->tci = tci; - - net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff); -} - -void net_rx_pkt_dump(struct NetRxPkt *pkt) -{ -#ifdef NET_RX_PKT_DEBUG - NetRxPkt *pkt = (NetRxPkt *)pkt; - assert(pkt); - - printf("RX PKT: tot_len: %d, vlan_stripped: %d, vlan_tag: %d\n", - pkt->tot_len, pkt->vlan_stripped, pkt->tci); -#endif -} - -void net_rx_pkt_set_packet_type(struct NetRxPkt *pkt, - eth_pkt_types_e packet_type) -{ - assert(pkt); - - pkt->packet_type = packet_type; - -} - -eth_pkt_types_e net_rx_pkt_get_packet_type(struct NetRxPkt *pkt) -{ - assert(pkt); - - return pkt->packet_type; -} - -size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt) -{ - assert(pkt); - - return pkt->tot_len; -} - -void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data, - size_t len) -{ - const struct iovec iov = { - .iov_base = (void *)data, - .iov_len = len - }; - - assert(pkt); - - eth_get_protocols(&iov, 1, &pkt->isip4, &pkt->isip6, - &pkt->isudp, &pkt->istcp, - &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, - &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); -} - -void net_rx_pkt_get_protocols(struct NetRxPkt *pkt, - bool *isip4, bool *isip6, - bool *isudp, bool *istcp) -{ - assert(pkt); - - *isip4 = pkt->isip4; - *isip6 = pkt->isip6; - *isudp = pkt->isudp; - *istcp = pkt->istcp; -} - -size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt) -{ - assert(pkt); - return pkt->l3hdr_off; -} - -size_t net_rx_pkt_get_l4_hdr_offset(struct NetRxPkt *pkt) -{ - assert(pkt); - return pkt->l4hdr_off; -} - -size_t net_rx_pkt_get_l5_hdr_offset(struct NetRxPkt *pkt) -{ - assert(pkt); - return pkt->l5hdr_off; -} - -eth_ip6_hdr_info *net_rx_pkt_get_ip6_info(struct NetRxPkt *pkt) -{ - return &pkt->ip6hdr_info; -} - -eth_ip4_hdr_info *net_rx_pkt_get_ip4_info(struct NetRxPkt *pkt) -{ - return &pkt->ip4hdr_info; -} - -eth_l4_hdr_info *net_rx_pkt_get_l4_info(struct NetRxPkt *pkt) -{ - return &pkt->l4hdr_info; -} - -static inline void -_net_rx_rss_add_chunk(uint8_t *rss_input, size_t *bytes_written, - void *ptr, size_t size) -{ - memcpy(&rss_input[*bytes_written], ptr, size); - trace_net_rx_pkt_rss_add_chunk(ptr, size, *bytes_written); - *bytes_written += size; -} - -static inline void -_net_rx_rss_prepare_ip4(uint8_t *rss_input, - struct NetRxPkt *pkt, - size_t *bytes_written) -{ - struct ip_header *ip4_hdr = &pkt->ip4hdr_info.ip4_hdr; - - _net_rx_rss_add_chunk(rss_input, bytes_written, - &ip4_hdr->ip_src, sizeof(uint32_t)); - - _net_rx_rss_add_chunk(rss_input, bytes_written, - &ip4_hdr->ip_dst, sizeof(uint32_t)); -} - -static inline void -_net_rx_rss_prepare_ip6(uint8_t *rss_input, - struct NetRxPkt *pkt, - bool ipv6ex, size_t *bytes_written) -{ - eth_ip6_hdr_info *ip6info = &pkt->ip6hdr_info; - - _net_rx_rss_add_chunk(rss_input, bytes_written, - (ipv6ex && ip6info->rss_ex_src_valid) ? &ip6info->rss_ex_src - : &ip6info->ip6_hdr.ip6_src, - sizeof(struct in6_address)); - - _net_rx_rss_add_chunk(rss_input, bytes_written, - (ipv6ex && ip6info->rss_ex_dst_valid) ? &ip6info->rss_ex_dst - : &ip6info->ip6_hdr.ip6_dst, - sizeof(struct in6_address)); -} - -static inline void -_net_rx_rss_prepare_tcp(uint8_t *rss_input, - struct NetRxPkt *pkt, - size_t *bytes_written) -{ - struct tcp_header *tcphdr = &pkt->l4hdr_info.hdr.tcp; - - _net_rx_rss_add_chunk(rss_input, bytes_written, - &tcphdr->th_sport, sizeof(uint16_t)); - - _net_rx_rss_add_chunk(rss_input, bytes_written, - &tcphdr->th_dport, sizeof(uint16_t)); -} - -uint32_t -net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt, - NetRxPktRssType type, - uint8_t *key) -{ - uint8_t rss_input[36]; - size_t rss_length = 0; - uint32_t rss_hash = 0; - net_toeplitz_key key_data; - - switch (type) { - case NetPktRssIpV4: - assert(pkt->isip4); - trace_net_rx_pkt_rss_ip4(); - _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); - break; - case NetPktRssIpV4Tcp: - assert(pkt->isip4); - assert(pkt->istcp); - trace_net_rx_pkt_rss_ip4_tcp(); - _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); - _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); - break; - case NetPktRssIpV6Tcp: - assert(pkt->isip6); - assert(pkt->istcp); - trace_net_rx_pkt_rss_ip6_tcp(); - _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); - _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); - break; - case NetPktRssIpV6: - assert(pkt->isip6); - trace_net_rx_pkt_rss_ip6(); - _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); - break; - case NetPktRssIpV6Ex: - assert(pkt->isip6); - trace_net_rx_pkt_rss_ip6_ex(); - _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); - break; - default: - assert(false); - break; - } - - net_toeplitz_key_init(&key_data, key); - net_toeplitz_add(&rss_hash, rss_input, rss_length, &key_data); - - trace_net_rx_pkt_rss_hash(rss_length, rss_hash); - - return rss_hash; -} - -uint16_t net_rx_pkt_get_ip_id(struct NetRxPkt *pkt) -{ - assert(pkt); - - if (pkt->isip4) { - return be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_id); - } - - return 0; -} - -bool net_rx_pkt_is_tcp_ack(struct NetRxPkt *pkt) -{ - assert(pkt); - - if (pkt->istcp) { - return TCP_HEADER_FLAGS(&pkt->l4hdr_info.hdr.tcp) & TCP_FLAG_ACK; - } - - return false; -} - -bool net_rx_pkt_has_tcp_data(struct NetRxPkt *pkt) -{ - assert(pkt); - - if (pkt->istcp) { - return pkt->l4hdr_info.has_tcp_data; - } - - return false; -} - -struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt) -{ - assert(pkt); - - return pkt->vec; -} - -uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt) -{ - assert(pkt); - - return pkt->vec_len; -} - -void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt, - struct virtio_net_hdr *vhdr) -{ - assert(pkt); - - memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr); -} - -void net_rx_pkt_set_vhdr_iovec(struct NetRxPkt *pkt, - const struct iovec *iov, int iovcnt) -{ - assert(pkt); - - iov_to_buf(iov, iovcnt, 0, &pkt->virt_hdr, sizeof pkt->virt_hdr); -} - -bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt) -{ - assert(pkt); - - return pkt->vlan_stripped; -} - -bool net_rx_pkt_has_virt_hdr(struct NetRxPkt *pkt) -{ - assert(pkt); - - return pkt->has_virt_hdr; -} - -uint16_t net_rx_pkt_get_vlan_tag(struct NetRxPkt *pkt) -{ - assert(pkt); - - return pkt->tci; -} - -bool net_rx_pkt_validate_l3_csum(struct NetRxPkt *pkt, bool *csum_valid) -{ - uint32_t cntr; - uint16_t csum; - uint32_t csl; - - trace_net_rx_pkt_l3_csum_validate_entry(); - - if (!pkt->isip4) { - trace_net_rx_pkt_l3_csum_validate_not_ip4(); - return false; - } - - csl = pkt->l4hdr_off - pkt->l3hdr_off; - - cntr = net_checksum_add_iov(pkt->vec, pkt->vec_len, - pkt->l3hdr_off, - csl, 0); - - csum = net_checksum_finish(cntr); - - *csum_valid = (csum == 0); - - trace_net_rx_pkt_l3_csum_validate_csum(pkt->l3hdr_off, csl, - cntr, csum, *csum_valid); - - return true; -} - -static uint16_t -_net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt) -{ - uint32_t cntr; - uint16_t csum; - uint16_t csl; - uint32_t cso; - - trace_net_rx_pkt_l4_csum_calc_entry(); - - if (pkt->isip4) { - if (pkt->isudp) { - csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen); - trace_net_rx_pkt_l4_csum_calc_ip4_udp(); - } else { - csl = be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_len) - - IP_HDR_GET_LEN(&pkt->ip4hdr_info.ip4_hdr); - trace_net_rx_pkt_l4_csum_calc_ip4_tcp(); - } - - cntr = eth_calc_ip4_pseudo_hdr_csum(&pkt->ip4hdr_info.ip4_hdr, - csl, &cso); - trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl); - } else { - if (pkt->isudp) { - csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen); - trace_net_rx_pkt_l4_csum_calc_ip6_udp(); - } else { - struct ip6_header *ip6hdr = &pkt->ip6hdr_info.ip6_hdr; - size_t full_ip6hdr_len = pkt->l4hdr_off - pkt->l3hdr_off; - size_t ip6opts_len = full_ip6hdr_len - sizeof(struct ip6_header); - - csl = be16_to_cpu(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_plen) - - ip6opts_len; - trace_net_rx_pkt_l4_csum_calc_ip6_tcp(); - } - - cntr = eth_calc_ip6_pseudo_hdr_csum(&pkt->ip6hdr_info.ip6_hdr, csl, - pkt->ip6hdr_info.l4proto, &cso); - trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl); - } - - cntr += net_checksum_add_iov(pkt->vec, pkt->vec_len, - pkt->l4hdr_off, csl, cso); - - csum = net_checksum_finish(cntr); - - trace_net_rx_pkt_l4_csum_calc_csum(pkt->l4hdr_off, csl, cntr, csum); - - return csum; -} - -bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid) -{ - uint16_t csum; - - trace_net_rx_pkt_l4_csum_validate_entry(); - - if (!pkt->istcp && !pkt->isudp) { - trace_net_rx_pkt_l4_csum_validate_not_xxp(); - return false; - } - - if (pkt->isudp && (pkt->l4hdr_info.hdr.udp.uh_sum == 0)) { - trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum(); - return false; - } - - if (pkt->isip4 && pkt->ip4hdr_info.fragment) { - trace_net_rx_pkt_l4_csum_validate_ip4_fragment(); - return false; - } - - csum = _net_rx_pkt_calc_l4_csum(pkt); - - *csum_valid = ((csum == 0) || (csum == 0xFFFF)); - - trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid); - - return true; -} - -bool net_rx_pkt_fix_l4_csum(struct NetRxPkt *pkt) -{ - uint16_t csum = 0; - uint32_t l4_cso; - - trace_net_rx_pkt_l4_csum_fix_entry(); - - if (pkt->istcp) { - l4_cso = offsetof(struct tcp_header, th_sum); - trace_net_rx_pkt_l4_csum_fix_tcp(l4_cso); - } else if (pkt->isudp) { - if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) { - trace_net_rx_pkt_l4_csum_fix_udp_with_no_checksum(); - return false; - } - l4_cso = offsetof(struct udp_header, uh_sum); - trace_net_rx_pkt_l4_csum_fix_udp(l4_cso); - } else { - trace_net_rx_pkt_l4_csum_fix_not_xxp(); - return false; - } - - if (pkt->isip4 && pkt->ip4hdr_info.fragment) { - trace_net_rx_pkt_l4_csum_fix_ip4_fragment(); - return false; - } - - /* Set zero to checksum word */ - iov_from_buf(pkt->vec, pkt->vec_len, - pkt->l4hdr_off + l4_cso, - &csum, sizeof(csum)); - - /* Calculate L4 checksum */ - csum = cpu_to_be16(_net_rx_pkt_calc_l4_csum(pkt)); - - /* Set calculated checksum to checksum word */ - iov_from_buf(pkt->vec, pkt->vec_len, - pkt->l4hdr_off + l4_cso, - &csum, sizeof(csum)); - - trace_net_rx_pkt_l4_csum_fix_csum(pkt->l4hdr_off + l4_cso, csum); - - return true; -} diff --git a/hw/net/net_rx_pkt.h b/hw/net/net_rx_pkt.h deleted file mode 100644 index 7adf0fad5..000000000 --- a/hw/net/net_rx_pkt.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - * QEMU RX packets abstraction - * - * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) - * - * Developed by Daynix Computing LTD (http://www.daynix.com) - * - * Authors: - * Dmitry Fleytman <dmitry@daynix.com> - * Tamir Shomer <tamirs@daynix.com> - * Yan Vugenfirer <yan@daynix.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 NET_RX_PKT_H -#define NET_RX_PKT_H - -#include "net/eth.h" - -/* defines to enable packet dump functions */ -/*#define NET_RX_PKT_DEBUG*/ - -struct NetRxPkt; - -/** - * Clean all rx packet resources - * - * @pkt: packet - * - */ -void net_rx_pkt_uninit(struct NetRxPkt *pkt); - -/** - * Init function for rx packet functionality - * - * @pkt: packet pointer - * @has_virt_hdr: device uses virtio header - * - */ -void net_rx_pkt_init(struct NetRxPkt **pkt, bool has_virt_hdr); - -/** - * returns total length of data attached to rx context - * - * @pkt: packet - * - * Return: nothing - * - */ -size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt); - -/** - * parse and set packet analysis results - * - * @pkt: packet - * @data: pointer to the data buffer to be parsed - * @len: data length - * - */ -void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data, - size_t len); - -/** - * fetches packet analysis results - * - * @pkt: packet - * @isip4: whether the packet given is IPv4 - * @isip6: whether the packet given is IPv6 - * @isudp: whether the packet given is UDP - * @istcp: whether the packet given is TCP - * - */ -void net_rx_pkt_get_protocols(struct NetRxPkt *pkt, - bool *isip4, bool *isip6, - bool *isudp, bool *istcp); - -/** -* fetches L3 header offset -* -* @pkt: packet -* -*/ -size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt); - -/** -* fetches L4 header offset -* -* @pkt: packet -* -*/ -size_t net_rx_pkt_get_l4_hdr_offset(struct NetRxPkt *pkt); - -/** -* fetches L5 header offset -* -* @pkt: packet -* -*/ -size_t net_rx_pkt_get_l5_hdr_offset(struct NetRxPkt *pkt); - -/** - * fetches IP6 header analysis results - * - * Return: pointer to analysis results structure which is stored in internal - * packet area. - * - */ -eth_ip6_hdr_info *net_rx_pkt_get_ip6_info(struct NetRxPkt *pkt); - -/** - * fetches IP4 header analysis results - * - * Return: pointer to analysis results structure which is stored in internal - * packet area. - * - */ -eth_ip4_hdr_info *net_rx_pkt_get_ip4_info(struct NetRxPkt *pkt); - -/** - * fetches L4 header analysis results - * - * Return: pointer to analysis results structure which is stored in internal - * packet area. - * - */ -eth_l4_hdr_info *net_rx_pkt_get_l4_info(struct NetRxPkt *pkt); - -typedef enum { - NetPktRssIpV4, - NetPktRssIpV4Tcp, - NetPktRssIpV6Tcp, - NetPktRssIpV6, - NetPktRssIpV6Ex -} NetRxPktRssType; - -/** -* calculates RSS hash for packet -* -* @pkt: packet -* @type: RSS hash type -* -* Return: Toeplitz RSS hash. -* -*/ -uint32_t -net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt, - NetRxPktRssType type, - uint8_t *key); - -/** -* fetches IP identification for the packet -* -* @pkt: packet -* -*/ -uint16_t net_rx_pkt_get_ip_id(struct NetRxPkt *pkt); - -/** -* check if given packet is a TCP ACK packet -* -* @pkt: packet -* -*/ -bool net_rx_pkt_is_tcp_ack(struct NetRxPkt *pkt); - -/** -* check if given packet contains TCP data -* -* @pkt: packet -* -*/ -bool net_rx_pkt_has_tcp_data(struct NetRxPkt *pkt); - -/** - * returns virtio header stored in rx context - * - * @pkt: packet - * @ret: virtio header - * - */ -struct virtio_net_hdr *net_rx_pkt_get_vhdr(struct NetRxPkt *pkt); - -/** - * returns packet type - * - * @pkt: packet - * @ret: packet type - * - */ -eth_pkt_types_e net_rx_pkt_get_packet_type(struct NetRxPkt *pkt); - -/** - * returns vlan tag - * - * @pkt: packet - * @ret: VLAN tag - * - */ -uint16_t net_rx_pkt_get_vlan_tag(struct NetRxPkt *pkt); - -/** - * tells whether vlan was stripped from the packet - * - * @pkt: packet - * @ret: VLAN stripped sign - * - */ -bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt); - -/** - * notifies caller if the packet has virtio header - * - * @pkt: packet - * @ret: true if packet has virtio header, false otherwize - * - */ -bool net_rx_pkt_has_virt_hdr(struct NetRxPkt *pkt); - -/** -* attach scatter-gather data to rx packet -* -* @pkt: packet -* @iov: received data scatter-gather list -* @iovcnt number of elements in iov -* @iovoff data start offset in the iov -* @strip_vlan: should the module strip vlan from data -* -*/ -void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt, - const struct iovec *iov, - int iovcnt, size_t iovoff, - bool strip_vlan); - -/** -* attach scatter-gather data to rx packet -* -* @pkt: packet -* @iov: received data scatter-gather list -* @iovcnt number of elements in iov -* @iovoff data start offset in the iov -* @strip_vlan: should the module strip vlan from data -* @vet: VLAN tag Ethernet type -* -*/ -void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt, - const struct iovec *iov, int iovcnt, - size_t iovoff, bool strip_vlan, - uint16_t vet); - -/** - * attach data to rx packet - * - * @pkt: packet - * @data: pointer to the data buffer - * @len: data length - * @strip_vlan: should the module strip vlan from data - * - */ -static inline void -net_rx_pkt_attach_data(struct NetRxPkt *pkt, const void *data, - size_t len, bool strip_vlan) -{ - const struct iovec iov = { - .iov_base = (void *) data, - .iov_len = len - }; - - net_rx_pkt_attach_iovec(pkt, &iov, 1, 0, strip_vlan); -} - -/** - * returns io vector that holds the attached data - * - * @pkt: packet - * @ret: pointer to IOVec - * - */ -struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt); - -/** -* returns io vector length that holds the attached data -* -* @pkt: packet -* @ret: IOVec length -* -*/ -uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt); - -/** - * prints rx packet data if debug is enabled - * - * @pkt: packet - * - */ -void net_rx_pkt_dump(struct NetRxPkt *pkt); - -/** - * copy passed vhdr data to packet context - * - * @pkt: packet - * @vhdr: VHDR buffer - * - */ -void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt, - struct virtio_net_hdr *vhdr); - -/** -* copy passed vhdr data to packet context -* -* @pkt: packet -* @iov: VHDR iov -* @iovcnt: VHDR iov array size -* -*/ -void net_rx_pkt_set_vhdr_iovec(struct NetRxPkt *pkt, - const struct iovec *iov, int iovcnt); - -/** - * save packet type in packet context - * - * @pkt: packet - * @packet_type: the packet type - * - */ -void net_rx_pkt_set_packet_type(struct NetRxPkt *pkt, - eth_pkt_types_e packet_type); - -/** -* validate TCP/UDP checksum of the packet -* -* @pkt: packet -* @csum_valid: checksum validation result -* @ret: true if validation was performed, false in case packet is -* not TCP/UDP or checksum validation is not possible -* -*/ -bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid); - -/** -* validate IPv4 checksum of the packet -* -* @pkt: packet -* @csum_valid: checksum validation result -* @ret: true if validation was performed, false in case packet is -* not TCP/UDP or checksum validation is not possible -* -*/ -bool net_rx_pkt_validate_l3_csum(struct NetRxPkt *pkt, bool *csum_valid); - -/** -* fix IPv4 checksum of the packet -* -* @pkt: packet -* @ret: true if checksum was fixed, false in case packet is -* not TCP/UDP or checksum correction is not possible -* -*/ -bool net_rx_pkt_fix_l4_csum(struct NetRxPkt *pkt); - -#endif diff --git a/hw/net/net_tx_pkt.h b/hw/net/net_tx_pkt.h deleted file mode 100644 index 212ecc62f..000000000 --- a/hw/net/net_tx_pkt.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * QEMU TX packets abstraction - * - * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) - * - * Developed by Daynix Computing LTD (http://www.daynix.com) - * - * Authors: - * Dmitry Fleytman <dmitry@daynix.com> - * Tamir Shomer <tamirs@daynix.com> - * Yan Vugenfirer <yan@daynix.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 NET_TX_PKT_H -#define NET_TX_PKT_H - -#include "net/eth.h" -#include "exec/hwaddr.h" - -/* define to enable packet dump functions */ -/*#define NET_TX_PKT_DEBUG*/ - -struct NetTxPkt; - -/** - * Init function for tx packet functionality - * - * @pkt: packet pointer - * @pci_dev: PCI device processing this packet - * @max_frags: max tx ip fragments - * @has_virt_hdr: device uses virtio header. - */ -void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev, - uint32_t max_frags, bool has_virt_hdr); - -/** - * Clean all tx packet resources. - * - * @pkt: packet. - */ -void net_tx_pkt_uninit(struct NetTxPkt *pkt); - -/** - * get virtio header - * - * @pkt: packet - * @ret: virtio header - */ -struct virtio_net_hdr *net_tx_pkt_get_vhdr(struct NetTxPkt *pkt); - -/** - * build virtio header (will be stored in module context) - * - * @pkt: packet - * @tso_enable: TSO enabled - * @csum_enable: CSO enabled - * @gso_size: MSS size for TSO - * - */ -void net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable, - bool csum_enable, uint32_t gso_size); - -/** -* updates vlan tag, and adds vlan header with custom ethernet type -* in case it is missing. -* -* @pkt: packet -* @vlan: VLAN tag -* @vlan_ethtype: VLAN header Ethernet type -* -*/ -void net_tx_pkt_setup_vlan_header_ex(struct NetTxPkt *pkt, - uint16_t vlan, uint16_t vlan_ethtype); - -/** -* updates vlan tag, and adds vlan header in case it is missing -* -* @pkt: packet -* @vlan: VLAN tag -* -*/ -static inline void -net_tx_pkt_setup_vlan_header(struct NetTxPkt *pkt, uint16_t vlan) -{ - net_tx_pkt_setup_vlan_header_ex(pkt, vlan, ETH_P_VLAN); -} - -/** - * populate data fragment into pkt context. - * - * @pkt: packet - * @pa: physical address of fragment - * @len: length of fragment - * - */ -bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, - size_t len); - -/** - * Fix ip header fields and calculate IP header and pseudo header checksums. - * - * @pkt: packet - * - */ -void net_tx_pkt_update_ip_checksums(struct NetTxPkt *pkt); - -/** - * Calculate the IP header checksum. - * - * @pkt: packet - * - */ -void net_tx_pkt_update_ip_hdr_checksum(struct NetTxPkt *pkt); - -/** - * get length of all populated data. - * - * @pkt: packet - * @ret: total data length - * - */ -size_t net_tx_pkt_get_total_len(struct NetTxPkt *pkt); - -/** - * get packet type - * - * @pkt: packet - * @ret: packet type - * - */ -eth_pkt_types_e net_tx_pkt_get_packet_type(struct NetTxPkt *pkt); - -/** - * prints packet data if debug is enabled - * - * @pkt: packet - * - */ -void net_tx_pkt_dump(struct NetTxPkt *pkt); - -/** - * reset tx packet private context (needed to be called between packets) - * - * @pkt: packet - * - */ -void net_tx_pkt_reset(struct NetTxPkt *pkt); - -/** - * Send packet to qemu. handles sw offloads if vhdr is not supported. - * - * @pkt: packet - * @nc: NetClientState - * @ret: operation result - * - */ -bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc); - -/** -* Redirect packet directly to receive path (emulate loopback phy). -* Handles sw offloads if vhdr is not supported. -* -* @pkt: packet -* @nc: NetClientState -* @ret: operation result -* -*/ -bool net_tx_pkt_send_loopback(struct NetTxPkt *pkt, NetClientState *nc); - -/** - * parse raw packet data and analyze offload requirements. - * - * @pkt: packet - * - */ -bool net_tx_pkt_parse(struct NetTxPkt *pkt); - -/** -* indicates if there are data fragments held by this packet object. -* -* @pkt: packet -* -*/ -bool net_tx_pkt_has_fragments(struct NetTxPkt *pkt); - -#endif diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c index 268d6a789..c6094fbb5 100644 --- a/hw/net/opencores_eth.c +++ b/hw/net/opencores_eth.c @@ -33,7 +33,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/net/mii.h" #include "hw/sysbus.h" #include "net/net.h" #include "sysemu/sysemu.h" @@ -56,6 +55,12 @@ /* PHY MII registers */ enum { + MII_BMCR, + MII_BMSR, + MII_PHYIDR1, + MII_PHYIDR2, + MII_ANAR, + MII_ANLPAR, MII_REG_MAX = 16, }; @@ -67,11 +72,10 @@ typedef struct Mii { static void mii_set_link(Mii *s, bool link_ok) { if (link_ok) { - s->regs[MII_BMSR] |= MII_BMSR_LINK_ST; - s->regs[MII_ANLPAR] |= MII_ANLPAR_TXFD | MII_ANLPAR_TX | - MII_ANLPAR_10FD | MII_ANLPAR_10 | MII_ANLPAR_CSMACD; + s->regs[MII_BMSR] |= 0x4; + s->regs[MII_ANLPAR] |= 0x01e1; } else { - s->regs[MII_BMSR] &= ~MII_BMSR_LINK_ST; + s->regs[MII_BMSR] &= ~0x4; s->regs[MII_ANLPAR] &= 0x01ff; } s->link_ok = link_ok; @@ -80,14 +84,11 @@ static void mii_set_link(Mii *s, bool link_ok) static void mii_reset(Mii *s) { memset(s->regs, 0, sizeof(s->regs)); - s->regs[MII_BMCR] = MII_BMCR_AUTOEN; - s->regs[MII_BMSR] = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | - MII_BMSR_10T_FD | MII_BMSR_10T_HD | MII_BMSR_MFPS | - MII_BMSR_AN_COMP | MII_BMSR_AUTONEG; - s->regs[MII_PHYID1] = 0x2000; - s->regs[MII_PHYID2] = 0x5c90; - s->regs[MII_ANAR] = MII_ANAR_TXFD | MII_ANAR_TX | - MII_ANAR_10FD | MII_ANAR_10 | MII_ANAR_CSMACD; + s->regs[MII_BMCR] = 0x1000; + s->regs[MII_BMSR] = 0x7868; /* no ext regs */ + s->regs[MII_PHYIDR1] = 0x2000; + s->regs[MII_PHYIDR2] = 0x5c90; + s->regs[MII_ANAR] = 0x01e1; mii_set_link(s, s->link_ok); } @@ -97,7 +98,7 @@ static void mii_ro(Mii *s, uint16_t v) static void mii_write_bmcr(Mii *s, uint16_t v) { - if (v & MII_BMCR_RESET) { + if (v & 0x8000) { mii_reset(s); } else { s->regs[MII_BMCR] = v; @@ -109,8 +110,8 @@ static void mii_write_host(Mii *s, unsigned idx, uint16_t v) static void (*reg_write[MII_REG_MAX])(Mii *s, uint16_t v) = { [MII_BMCR] = mii_write_bmcr, [MII_BMSR] = mii_ro, - [MII_PHYID1] = mii_ro, - [MII_PHYID2] = mii_ro, + [MII_PHYIDR1] = mii_ro, + [MII_PHYIDR2] = mii_ro, }; if (idx < MII_REG_MAX) { @@ -473,7 +474,7 @@ static ssize_t open_eth_receive(NetClientState *nc, } static NetClientInfo net_open_eth_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = open_eth_can_receive, .receive = open_eth_receive, @@ -482,8 +483,7 @@ static NetClientInfo net_open_eth_info = { static void open_eth_start_xmit(OpenEthState *s, desc *tx) { - uint8_t *buf = NULL; - uint8_t buffer[0x600]; + uint8_t buf[65536]; unsigned len = GET_FIELD(tx->len_flags, TXD_LEN); unsigned tx_len = len; @@ -498,11 +498,6 @@ static void open_eth_start_xmit(OpenEthState *s, desc *tx) trace_open_eth_start_xmit(tx->buf_ptr, len, tx_len); - if (tx_len > sizeof(buffer)) { - buf = g_new(uint8_t, tx_len); - } else { - buf = buffer; - } if (len > tx_len) { len = tx_len; } @@ -511,9 +506,6 @@ static void open_eth_start_xmit(OpenEthState *s, desc *tx) memset(buf + len, 0, tx_len - len); } qemu_send_packet(qemu_get_queue(s->nic), buf, tx_len); - if (tx_len > sizeof(buffer)) { - g_free(buf); - } if (tx->len_flags & TXD_WR) { s->tx_desc = 0; diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index 0acf8a487..595439a65 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -272,7 +272,7 @@ static void pci_pcnet_uninit(PCIDevice *dev) } static NetClientInfo net_pci_pcnet_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = pcnet_receive, .link_status_changed = pcnet_set_link_status, diff --git a/hw/net/pcnet.h b/hw/net/pcnet.h index 40831a784..dec8de834 100644 --- a/hw/net/pcnet.h +++ b/hw/net/pcnet.h @@ -1,5 +1,5 @@ #ifndef HW_PCNET_H -#define HW_PCNET_H +#define HW_PCNET_H 1 #define PCNET_IOPORT_SIZE 0x20 #define PCNET_PNPMMIO_SIZE 0x20 diff --git a/hw/net/rocker/rocker.h b/hw/net/rocker/rocker.h index 7ae0495d9..f9c80f801 100644 --- a/hw/net/rocker/rocker.h +++ b/hw/net/rocker/rocker.h @@ -16,8 +16,8 @@ * GNU General Public License for more details. */ -#ifndef ROCKER_H -#define ROCKER_H +#ifndef _ROCKER_H_ +#define _ROCKER_H_ #include "qemu/sockets.h" @@ -81,4 +81,4 @@ int rx_produce(World *world, uint32_t pport, int rocker_port_eg(Rocker *r, uint32_t pport, const struct iovec *iov, int iovcnt); -#endif /* ROCKER_H */ +#endif /* _ROCKER_H_ */ diff --git a/hw/net/rocker/rocker_desc.h b/hw/net/rocker/rocker_desc.h index 1dec33561..d4041f5c4 100644 --- a/hw/net/rocker/rocker_desc.h +++ b/hw/net/rocker/rocker_desc.h @@ -14,8 +14,9 @@ * GNU General Public License for more details. */ -#ifndef ROCKER_DESC_H -#define ROCKER_DESC_H + +#ifndef _ROCKER_DESC_H_ +#define _ROCKER_DESC_H_ #include "rocker_hw.h" diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c index 1305ac36c..0149899c6 100644 --- a/hw/net/rocker/rocker_fp.c +++ b/hw/net/rocker/rocker_fp.c @@ -167,7 +167,7 @@ static void fp_port_set_link_status(NetClientState *nc) } static NetClientInfo fp_port_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = fp_port_receive, .receive_iov = fp_port_receive_iov, diff --git a/hw/net/rocker/rocker_fp.h b/hw/net/rocker/rocker_fp.h index dbe1dd329..04592bbfd 100644 --- a/hw/net/rocker/rocker_fp.h +++ b/hw/net/rocker/rocker_fp.h @@ -14,8 +14,8 @@ * GNU General Public License for more details. */ -#ifndef ROCKER_FP_H -#define ROCKER_FP_H +#ifndef _ROCKER_FP_H_ +#define _ROCKER_FP_H_ #include "net/net.h" #include "qemu/iov.h" @@ -51,4 +51,4 @@ FpPort *fp_port_alloc(Rocker *r, char *sw_name, void fp_port_free(FpPort *port); void fp_port_reset(FpPort *port); -#endif /* ROCKER_FP_H */ +#endif /* _ROCKER_FP_H_ */ diff --git a/hw/net/rocker/rocker_hw.h b/hw/net/rocker/rocker_hw.h index 1786323fa..8c5083032 100644 --- a/hw/net/rocker/rocker_hw.h +++ b/hw/net/rocker/rocker_hw.h @@ -6,8 +6,8 @@ * */ -#ifndef ROCKER_HW_H -#define ROCKER_HW_H +#ifndef _ROCKER_HW_ +#define _ROCKER_HW_ #define __le16 uint16_t #define __le32 uint32_t @@ -490,4 +490,4 @@ enum rocker_of_dpa_overlay_type { */ #define ROCKER_CONTROL_RESET (1 << 0) -#endif /* ROCKER_HW_H */ +#endif /* _ROCKER_HW_ */ diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c index 9b1e0d244..0a134ebca 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -103,8 +103,9 @@ typedef struct of_dpa_flow_key { /* Width of key which includes field 'f' in u64s, rounded up */ #define FLOW_KEY_WIDTH(f) \ - DIV_ROUND_UP(offsetof(OfDpaFlowKey, f) + sizeof(((OfDpaFlowKey *)0)->f), \ - sizeof(uint64_t)) + ((offsetof(OfDpaFlowKey, f) + \ + sizeof(((OfDpaFlowKey *)0)->f) + \ + sizeof(uint64_t) - 1) / sizeof(uint64_t)) typedef struct of_dpa_flow_action { uint32_t goto_tbl; diff --git a/hw/net/rocker/rocker_of_dpa.h b/hw/net/rocker/rocker_of_dpa.h index 01c7a97d0..f3f6d7780 100644 --- a/hw/net/rocker/rocker_of_dpa.h +++ b/hw/net/rocker/rocker_of_dpa.h @@ -14,9 +14,9 @@ * GNU General Public License for more details. */ -#ifndef ROCKER_OF_DPA_H -#define ROCKER_OF_DPA_H +#ifndef _ROCKER_OF_DPA_H_ +#define _ROCKER_OF_DPA_H_ World *of_dpa_world_alloc(Rocker *r); -#endif /* ROCKER_OF_DPA_H */ +#endif /* _ROCKER_OF_DPA_H_ */ diff --git a/hw/net/rocker/rocker_tlv.h b/hw/net/rocker/rocker_tlv.h index dd28d0844..e3c4ab679 100644 --- a/hw/net/rocker/rocker_tlv.h +++ b/hw/net/rocker/rocker_tlv.h @@ -14,8 +14,8 @@ * GNU General Public License for more details. */ -#ifndef ROCKER_TLV_H -#define ROCKER_TLV_H +#ifndef _ROCKER_TLV_H_ +#define _ROCKER_TLV_H_ #define ROCKER_TLV_ALIGNTO 8U #define ROCKER_TLV_ALIGN(len) \ @@ -106,17 +106,17 @@ static inline uint64_t rocker_tlv_get_u64(const RockerTlv *tlv) static inline uint16_t rocker_tlv_get_le16(const RockerTlv *tlv) { - return lduw_le_p(rocker_tlv_data(tlv)); + return le16_to_cpup((uint16_t *) rocker_tlv_data(tlv)); } static inline uint32_t rocker_tlv_get_le32(const RockerTlv *tlv) { - return ldl_le_p(rocker_tlv_data(tlv)); + return le32_to_cpup((uint32_t *) rocker_tlv_data(tlv)); } static inline uint64_t rocker_tlv_get_le64(const RockerTlv *tlv) { - return ldq_le_p(rocker_tlv_data(tlv)); + return le64_to_cpup((uint64_t *) rocker_tlv_data(tlv)); } static inline void rocker_tlv_parse(RockerTlv **tb, int maxtype, diff --git a/hw/net/rocker/rocker_world.h b/hw/net/rocker/rocker_world.h index 44f1fe3e1..58ade4733 100644 --- a/hw/net/rocker/rocker_world.h +++ b/hw/net/rocker/rocker_world.h @@ -14,8 +14,8 @@ * GNU General Public License for more details. */ -#ifndef ROCKER_WORLD_H -#define ROCKER_WORLD_H +#ifndef _ROCKER_WORLD_H_ +#define _ROCKER_WORLD_H_ #include "rocker_hw.h" @@ -58,4 +58,4 @@ const char *world_name(World *world); World *rocker_get_world(Rocker *r, enum rocker_world_type type); -#endif /* ROCKER_WORLD_H */ +#endif /* _ROCKER_WORLD_H_ */ diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 3345bc6b5..1e5ec149f 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -1013,8 +1013,8 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; /* write VLAN info to descriptor variables. */ - if (s->CpCmd & CPlusRxVLAN && - lduw_be_p(&buf[ETH_ALEN * 2]) == ETH_P_VLAN) { + if (s->CpCmd & CPlusRxVLAN && be16_to_cpup((uint16_t *) + &buf[ETH_ALEN * 2]) == ETH_P_VLAN) { dot1q_buf = &buf[ETH_ALEN * 2]; size -= VLAN_HLEN; /* if too small buffer, use the tailroom added duing expansion */ @@ -1024,10 +1024,11 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t rxdw1 &= ~CP_RX_VLAN_TAG_MASK; /* BE + ~le_to_cpu()~ + cpu_to_le() = BE */ - rxdw1 |= CP_RX_TAVA | lduw_le_p(&dot1q_buf[ETHER_TYPE_LEN]); + rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *) + &dot1q_buf[ETHER_TYPE_LEN]); DPRINTF("C+ Rx mode : extracted vlan tag with tci: ""%u\n", - lduw_be_p(&dot1q_buf[ETHER_TYPE_LEN])); + be16_to_cpup((uint16_t *)&dot1q_buf[ETHER_TYPE_LEN])); } else { /* reset VLAN tag flag */ rxdw1 &= ~CP_RX_TAVA; @@ -1351,6 +1352,29 @@ static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr) pci_dma_write(d, tc_addr + 62, (uint8_t *)&val16, 2); } +/* Loads values of tally counters from VM state file */ + +static const VMStateDescription vmstate_tally_counters = { + .name = "tally_counters", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(TxOk, RTL8139TallyCounters), + VMSTATE_UINT64(RxOk, RTL8139TallyCounters), + VMSTATE_UINT64(TxERR, RTL8139TallyCounters), + VMSTATE_UINT32(RxERR, RTL8139TallyCounters), + VMSTATE_UINT16(MissPkt, RTL8139TallyCounters), + VMSTATE_UINT16(FAE, RTL8139TallyCounters), + VMSTATE_UINT32(Tx1Col, RTL8139TallyCounters), + VMSTATE_UINT32(TxMCol, RTL8139TallyCounters), + VMSTATE_UINT64(RxOkPhy, RTL8139TallyCounters), + VMSTATE_UINT64(RxOkBrd, RTL8139TallyCounters), + VMSTATE_UINT16(TxAbt, RTL8139TallyCounters), + VMSTATE_UINT16(TxUndrn, RTL8139TallyCounters), + VMSTATE_END_OF_LIST() + } +}; + static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) { DeviceState *d = DEVICE(s); @@ -1843,6 +1867,11 @@ static int rtl8139_transmit_one(RTL8139State *s, int descriptor) return 1; } +/* structures and macros for task offloading */ +#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2) +#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f) +#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags)) + #define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off))) /* produces ones' complement sum of data */ @@ -3198,7 +3227,7 @@ static void rtl8139_pre_save(void *opaque) static const VMStateDescription vmstate_rtl8139 = { .name = "rtl8139", - .version_id = 5, + .version_id = 4, .minimum_version_id = 3, .post_load = rtl8139_post_load, .pre_save = rtl8139_pre_save, @@ -3269,19 +3298,8 @@ static const VMStateDescription vmstate_rtl8139 = { VMSTATE_UINT32(TimerInt, RTL8139State), VMSTATE_INT64(TCTR_base, RTL8139State), - VMSTATE_UINT64(tally_counters.TxOk, RTL8139State), - VMSTATE_UINT64(tally_counters.RxOk, RTL8139State), - VMSTATE_UINT64(tally_counters.TxERR, RTL8139State), - VMSTATE_UINT32(tally_counters.RxERR, RTL8139State), - VMSTATE_UINT16(tally_counters.MissPkt, RTL8139State), - VMSTATE_UINT16(tally_counters.FAE, RTL8139State), - VMSTATE_UINT32(tally_counters.Tx1Col, RTL8139State), - VMSTATE_UINT32(tally_counters.TxMCol, RTL8139State), - VMSTATE_UINT64(tally_counters.RxOkPhy, RTL8139State), - VMSTATE_UINT64(tally_counters.RxOkBrd, RTL8139State), - VMSTATE_UINT32_V(tally_counters.RxOkMul, RTL8139State, 5), - VMSTATE_UINT16(tally_counters.TxAbt, RTL8139State), - VMSTATE_UINT16(tally_counters.TxUndrn, RTL8139State), + VMSTATE_STRUCT(tally_counters, RTL8139State, 0, + vmstate_tally_counters, RTL8139TallyCounters), VMSTATE_UINT32_V(cplus_enabled, RTL8139State, 4), VMSTATE_END_OF_LIST() @@ -3393,7 +3411,7 @@ static void rtl8139_set_link_status(NetClientState *nc) } static NetClientInfo net_rtl8139_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = rtl8139_can_receive, .receive = rtl8139_receive, diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c index 3b16dcf5a..21c1b8f54 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -755,7 +755,7 @@ static const MemoryRegionOps smc91c111_mem_ops = { }; static NetClientInfo net_smc91c111_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = smc91c111_can_receive_nc, .receive = smc91c111_receive, diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index b273eda93..a647f25d9 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -28,7 +28,6 @@ #include "qemu-common.h" #include "cpu.h" #include "hw/hw.h" -#include "qemu/log.h" #include "net/net.h" #include "hw/qdev.h" #include "hw/ppc/spapr.h" @@ -107,10 +106,9 @@ typedef struct VIOsPAPRVLANDevice { NICConf nicconf; NICState *nic; bool isopen; - hwaddr buf_list; + target_ulong buf_list; uint32_t add_buf_ptr, use_buf_ptr, rx_bufs; - hwaddr rxq_ptr; - QEMUTimer *rxp_timer; + target_ulong rxq_ptr; uint32_t compat_flags; /* Compatability flags for migration */ RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */ } VIOsPAPRVLANDevice; @@ -123,21 +121,6 @@ static int spapr_vlan_can_receive(NetClientState *nc) } /** - * The last 8 bytes of the receive buffer list page (that has been - * supplied by the guest with the H_REGISTER_LOGICAL_LAN call) contain - * a counter for frames that have been dropped because there was no - * suitable receive buffer available. This function is used to increase - * this counter by one. - */ -static void spapr_vlan_record_dropped_rx_frame(VIOsPAPRVLANDevice *dev) -{ - uint64_t cnt; - - cnt = vio_ldq(&dev->sdev, dev->buf_list + 4096 - 8); - vio_stq(&dev->sdev, dev->buf_list + 4096 - 8, cnt + 1); -} - -/** * Get buffer descriptor from one of our receive buffer pools */ static vlan_bd_t spapr_vlan_get_rx_bd_from_pool(VIOsPAPRVLANDevice *dev, @@ -222,8 +205,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, } if (!dev->rx_bufs) { - spapr_vlan_record_dropped_rx_frame(dev); - return 0; + return -1; } if (dev->compat_flags & SPAPRVLAN_FLAG_RX_BUF_POOLS) { @@ -232,8 +214,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, bd = spapr_vlan_get_rx_bd_from_page(dev, size); } if (!bd) { - spapr_vlan_record_dropped_rx_frame(dev); - return 0; + return -1; } dev->rx_bufs--; @@ -278,19 +259,12 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, } static NetClientInfo net_spapr_vlan_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = spapr_vlan_can_receive, .receive = spapr_vlan_receive, }; -static void spapr_vlan_flush_rx_queue(void *opaque) -{ - VIOsPAPRVLANDevice *dev = opaque; - - qemu_flush_queued_packets(qemu_get_queue(dev->nic)); -} - static void spapr_vlan_reset_rx_pool(RxBufPool *rxp) { /* @@ -327,9 +301,6 @@ static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp) dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf, object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev); qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a); - - dev->rxp_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, spapr_vlan_flush_rx_queue, - dev); } static void spapr_vlan_instance_init(Object *obj) @@ -360,11 +331,6 @@ static void spapr_vlan_instance_finalize(Object *obj) dev->rx_pool[i] = NULL; } } - - if (dev->rxp_timer) { - timer_del(dev->rxp_timer); - timer_free(dev->rxp_timer); - } } void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd) @@ -662,13 +628,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu, dev->rx_bufs++; - /* - * Give guest some more time to add additional RX buffers before we - * flush the receive queue, so that e.g. fragmented IP packets can - * be passed to the guest in one go later (instead of passing single - * fragments if there is only one receive buffer available). - */ - timer_mod(dev->rxp_timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 500); + qemu_flush_queued_packets(qemu_get_queue(dev->nic)); return H_SUCCESS; } @@ -805,11 +765,11 @@ static const VMStateDescription vmstate_spapr_llan = { VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVLANDevice), /* LLAN state */ VMSTATE_BOOL(isopen, VIOsPAPRVLANDevice), - VMSTATE_UINT64(buf_list, VIOsPAPRVLANDevice), + VMSTATE_UINTTL(buf_list, VIOsPAPRVLANDevice), VMSTATE_UINT32(add_buf_ptr, VIOsPAPRVLANDevice), VMSTATE_UINT32(use_buf_ptr, VIOsPAPRVLANDevice), VMSTATE_UINT32(rx_bufs, VIOsPAPRVLANDevice), - VMSTATE_UINT64(rxq_ptr, VIOsPAPRVLANDevice), + VMSTATE_UINTTL(rxq_ptr, VIOsPAPRVLANDevice), VMSTATE_END_OF_LIST() }, diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index 957730e02..688089494 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -460,7 +460,7 @@ static void stellaris_enet_reset(stellaris_enet_state *s) } static NetClientInfo net_stellaris_enet_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = stellaris_enet_receive, }; diff --git a/hw/net/trace-events b/hw/net/trace-events deleted file mode 100644 index 8d38d7724..000000000 --- a/hw/net/trace-events +++ /dev/null @@ -1,272 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/net/lance.c -lance_mem_readw(uint64_t addr, uint32_t ret) "addr=%"PRIx64"val=0x%04x" -lance_mem_writew(uint64_t addr, uint32_t val) "addr=%"PRIx64"val=0x%04x" - -# hw/net/milkymist-minimac2.c -milkymist_minimac2_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_minimac2_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x" -milkymist_minimac2_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr %02x addr %02x value %04x" -milkymist_minimac2_tx_frame(uint32_t length) "length %u" -milkymist_minimac2_rx_frame(const void *buf, uint32_t length) "buf %p length %u" -milkymist_minimac2_rx_transfer(const void *buf, uint32_t length) "buf %p length %d" -milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX" -milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX" -milkymist_minimac2_pulse_irq_tx(void) "Pulse IRQ TX" - -# hw/net/mipsnet.c -mipsnet_send(uint32_t size) "sending len=%u" -mipsnet_receive(uint32_t size) "receiving len=%u" -mipsnet_read(uint64_t addr, uint32_t val) "read addr=0x%" PRIx64 " val=0x%x" -mipsnet_write(uint64_t addr, uint64_t val) "write addr=0x%" PRIx64 " val=0x%" PRIx64 -mipsnet_irq(uint32_t isr, uint32_t intctl) "set irq to %d (%02x)" - -# hw/net/opencores_eth.c -open_eth_mii_write(unsigned idx, uint16_t v) "MII[%02x] <- %04x" -open_eth_mii_read(unsigned idx, uint16_t v) "MII[%02x] -> %04x" -open_eth_update_irq(uint32_t v) "IRQ <- %x" -open_eth_receive(unsigned len) "RX: len: %u" -open_eth_receive_mcast(unsigned idx, uint32_t h0, uint32_t h1) "MCAST: idx = %u, hash: %08x:%08x" -open_eth_receive_reject(void) "RX: rejected" -open_eth_receive_desc(uint32_t addr, uint32_t len_flags) "RX: %08x, len_flags: %08x" -open_eth_start_xmit(uint32_t addr, unsigned len, unsigned tx_len) "TX: %08x, len: %u, tx_len: %u" -open_eth_reg_read(uint32_t addr, uint32_t v) "MAC[%02x] -> %08x" -open_eth_reg_write(uint32_t addr, uint32_t v) "MAC[%02x] <- %08x" -open_eth_desc_read(uint32_t addr, uint32_t v) "DESC[%04x] -> %08x" -open_eth_desc_write(uint32_t addr, uint32_t v) "DESC[%04x] <- %08x" - -# hw/net/pcnet.c -pcnet_s_reset(void *s) "s=%p" -pcnet_user_int(void *s) "s=%p" -pcnet_isr_change(void *s, uint32_t isr, uint32_t isr_old) "s=%p INTA=%d<=%d" -pcnet_init(void *s, uint64_t init_addr) "s=%p init_addr=%#"PRIx64 -pcnet_rlen_tlen(void *s, uint32_t rlen, uint32_t tlen) "s=%p rlen=%d tlen=%d" -pcnet_ss32_rdra_tdra(void *s, uint32_t ss32, uint32_t rdra, uint32_t rcvrl, uint32_t tdra, uint32_t xmtrl) "s=%p ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]" - -# hw/net/pcnet-pci.c -pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) "opaque=%p addr=0x%08x val=0x%02x" -pcnet_aprom_readb(void *opaque, uint32_t addr, uint32_t val) "opaque=%p addr=0x%08x val=0x%02x" -pcnet_ioport_read(void *opaque, uint64_t addr, unsigned size) "opaque=%p addr=%#"PRIx64" size=%d" -pcnet_ioport_write(void *opaque, uint64_t addr, uint64_t data, unsigned size) "opaque=%p addr=%#"PRIx64" data=%#"PRIx64" size=%d" -pcnet_mmio_writeb(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=%#"PRIx64" val=0x%x" -pcnet_mmio_writew(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=%#"PRIx64" val=0x%x" -pcnet_mmio_writel(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=%#"PRIx64" val=0x%x" -pcnet_mmio_readb(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=%#"PRIx64" val=0x%x" -pcnet_mmio_readw(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=%#"PRIx64" val=0x%x" -pcnet_mmio_readl(void *opaque, uint64_t addr, uint32_t val) "opaque=%p addr=%#"PRIx64" val=0x%x" - -# hw/net/net_rx_pkt.c -net_rx_pkt_parsed(bool ip4, bool ip6, bool udp, bool tcp, size_t l3o, size_t l4o, size_t l5o) "RX packet parsed: ip4: %d, ip6: %d, udp: %d, tcp: %d, l3 offset: %zu, l4 offset: %zu, l5 offset: %zu" -net_rx_pkt_l4_csum_validate_entry(void) "Starting L4 checksum validation" -net_rx_pkt_l4_csum_validate_not_xxp(void) "Not a TCP/UDP packet" -net_rx_pkt_l4_csum_validate_udp_with_no_checksum(void) "UDP packet without checksum" -net_rx_pkt_l4_csum_validate_ip4_fragment(void) "IP4 fragment" -net_rx_pkt_l4_csum_validate_ip4_udp(void) "IP4/UDP packet" -net_rx_pkt_l4_csum_validate_ip4_tcp(void) "IP4/TCP packet" -net_rx_pkt_l4_csum_validate_ip6_udp(void) "IP6/UDP packet" -net_rx_pkt_l4_csum_validate_ip6_tcp(void) "IP6/TCP packet" -net_rx_pkt_l4_csum_validate_csum(bool csum_valid) "Checksum valid: %d" - -net_rx_pkt_l4_csum_calc_entry(void) "Starting L4 checksum calculation" -net_rx_pkt_l4_csum_calc_ip4_udp(void) "IP4/UDP packet" -net_rx_pkt_l4_csum_calc_ip4_tcp(void) "IP4/TCP packet" -net_rx_pkt_l4_csum_calc_ip6_udp(void) "IP6/UDP packet" -net_rx_pkt_l4_csum_calc_ip6_tcp(void) "IP6/TCP packet" -net_rx_pkt_l4_csum_calc_ph_csum(uint32_t cntr, uint16_t csl) "Pseudo-header: checksum counter %u, length %u" -net_rx_pkt_l4_csum_calc_csum(size_t l4hdr_off, uint16_t csl, uint32_t cntr, uint16_t csum) "L4 Checksum: L4 header offset: %zu, length: %u, counter: 0x%X, final checksum: 0x%X" - -net_rx_pkt_l4_csum_fix_entry(void) "Starting L4 checksum correction" -net_rx_pkt_l4_csum_fix_tcp(uint32_t l4_cso) "TCP packet, L4 cso: %u" -net_rx_pkt_l4_csum_fix_udp(uint32_t l4_cso) "UDP packet, L4 cso: %u" -net_rx_pkt_l4_csum_fix_not_xxp(void) "Not an IP4 packet" -net_rx_pkt_l4_csum_fix_ip4_fragment(void) "IP4 fragment" -net_rx_pkt_l4_csum_fix_udp_with_no_checksum(void) "UDP packet without checksum" -net_rx_pkt_l4_csum_fix_csum(uint32_t cso, uint16_t csum) "L4 Checksum: Offset: %u, value 0x%X" - -net_rx_pkt_l3_csum_validate_entry(void) "Starting L3 checksum validation" -net_rx_pkt_l3_csum_validate_not_ip4(void) "Not an IP4 packet" -net_rx_pkt_l3_csum_validate_csum(size_t l3hdr_off, uint32_t csl, uint32_t cntr, uint16_t csum, bool csum_valid) "L3 Checksum: L3 header offset: %zu, length: %u, counter: 0x%X, final checksum: 0x%X, valid: %d" - -net_rx_pkt_rss_ip4(void) "Calculating IPv4 RSS hash" -net_rx_pkt_rss_ip4_tcp(void) "Calculating IPv4/TCP RSS hash" -net_rx_pkt_rss_ip6_tcp(void) "Calculating IPv6/TCP RSS hash" -net_rx_pkt_rss_ip6(void) "Calculating IPv6 RSS hash" -net_rx_pkt_rss_ip6_ex(void) "Calculating IPv6/EX RSS hash" -net_rx_pkt_rss_hash(size_t rss_length, uint32_t rss_hash) "RSS hash for %zu bytes: 0x%X" -net_rx_pkt_rss_add_chunk(void* ptr, size_t size, size_t input_offset) "Add RSS chunk %p, %zu bytes, RSS input offset %zu bytes" - -# hw/net/e1000x_common.c -e1000x_rx_can_recv_disabled(bool link_up, bool rx_enabled, bool pci_master) "link_up: %d, rx_enabled %d, pci_master %d" -e1000x_vlan_is_vlan_pkt(bool is_vlan_pkt, uint16_t eth_proto, uint16_t vet) "Is VLAN packet: %d, ETH proto: 0x%X, VET: 0x%X" -e1000x_rx_flt_ucast_match(uint32_t idx, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x" -e1000x_rx_flt_ucast_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x" -e1000x_rx_flt_inexact_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint32_t mo, uint32_t mta, uint32_t mta_val) "inexact mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x" -e1000x_rx_link_down(uint32_t status_reg) "Received packet dropped because the link is down STATUS = %u" -e1000x_rx_disabled(uint32_t rctl_reg) "Received packet dropped because receive is disabled RCTL = %u" -e1000x_rx_oversized(size_t size) "Received packet dropped because it was oversized (%zu bytes)" -e1000x_mac_indicate(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "Indicating MAC to guest: %02x:%02x:%02x:%02x:%02x:%02x" -e1000x_link_negotiation_start(void) "Start link auto negotiation" -e1000x_link_negotiation_done(void) "Auto negotiation is completed" - -# hw/net/e1000e_core.c -e1000e_core_write(uint64_t index, uint32_t size, uint64_t val) "Write to register 0x%"PRIx64", %d byte(s), value: 0x%"PRIx64 -e1000e_core_read(uint64_t index, uint32_t size, uint64_t val) "Read from register 0x%"PRIx64", %d byte(s), value: 0x%"PRIx64 -e1000e_core_mdic_read(uint8_t page, uint32_t addr, uint32_t data) "MDIC READ: PHY[%u][%u] = 0x%x" -e1000e_core_mdic_read_unhandled(uint8_t page, uint32_t addr) "MDIC READ: PHY[%u][%u] UNHANDLED" -e1000e_core_mdic_write(uint8_t page, uint32_t addr, uint32_t data) "MDIC WRITE: PHY[%u][%u] = 0x%x" -e1000e_core_mdic_write_unhandled(uint8_t page, uint32_t addr) "MDIC WRITE: PHY[%u][%u] UNHANDLED" -e1000e_core_eeeprom_write(uint16_t bit_in, uint16_t bit_out, uint16_t reading) "eeprom bitnum in %d out %d, reading %d" -e1000e_core_ctrl_write(uint64_t index, uint32_t val) "Write CTRL register 0x%"PRIx64", value: 0x%X" -e1000e_core_ctrl_sw_reset(void) "Doing SW reset" -e1000e_core_ctrl_phy_reset(void) "Doing PHY reset" - -e1000e_link_autoneg_flowctl(bool enabled) "Auto-negotiated flow control state is %d" -e1000e_link_set_params(bool autodetect, uint32_t speed, bool force_spd, bool force_dplx, bool rx_fctl, bool tx_fctl) "Set link params: Autodetect: %d, Speed: %d, Force speed: %d, Force duplex: %d, RX flow control %d, TX flow control %d" -e1000e_link_read_params(bool autodetect, uint32_t speed, bool force_spd, bool force_dplx, bool rx_fctl, bool tx_fctl) "Get link params: Autodetect: %d, Speed: %d, Force speed: %d, Force duplex: %d, RX flow control %d, TX flow control %d" -e1000e_link_set_ext_params(bool asd_check, bool speed_select_bypass) "Set extended link params: ASD check: %d, Speed select bypass: %d" -e1000e_link_status(bool link_up, bool full_dplx, uint32_t speed, uint32_t asdv) "Link up: %d, Duplex: %d, Speed: %d, ASDV: %d" -e1000e_link_status_changed(bool status) "New link status: %d" - -e1000e_wrn_regs_write_ro(uint64_t index, uint32_t size, uint64_t val) "WARNING: Write to RO register 0x%"PRIx64", %d byte(s), value: 0x%"PRIx64 -e1000e_wrn_regs_write_unknown(uint64_t index, uint32_t size, uint64_t val) "WARNING: Write to unknown register 0x%"PRIx64", %d byte(s), value: 0x%"PRIx64 -e1000e_wrn_regs_read_unknown(uint64_t index, uint32_t size) "WARNING: Read from unknown register 0x%"PRIx64", %d byte(s)" -e1000e_wrn_regs_read_trivial(uint32_t index) "WARNING: Reading register at offset: 0x%05x. It is not fully implemented." -e1000e_wrn_regs_write_trivial(uint32_t index) "WARNING: Writing to register at offset: 0x%05x. It is not fully implemented." -e1000e_wrn_no_ts_support(void) "WARNING: Guest requested TX timestamping which is not supported" -e1000e_wrn_no_snap_support(void) "WARNING: Guest requested TX SNAP header update which is not supported" -e1000e_wrn_iscsi_filtering_not_supported(void) "WARNING: Guest requested iSCSI filtering which is not supported" -e1000e_wrn_nfsw_filtering_not_supported(void) "WARNING: Guest requested NFS write filtering which is not supported" -e1000e_wrn_nfsr_filtering_not_supported(void) "WARNING: Guest requested NFS read filtering which is not supported" - -e1000e_tx_disabled(void) "TX Disabled" -e1000e_tx_descr(void *addr, uint32_t lower, uint32_t upper) "%p : %x %x" - -e1000e_ring_free_space(int ridx, uint32_t rdlen, uint32_t rdh, uint32_t rdt) "ring #%d: LEN: %u, DH: %u, DT: %u" - -e1000e_rx_can_recv_rings_full(void) "Cannot receive: all rings are full" -e1000e_rx_can_recv(void) "Can receive" -e1000e_rx_has_buffers(int ridx, uint32_t free_desc, size_t total_size, uint32_t desc_buf_size) "ring #%d: free descr: %u, packet size %zu, descr buffer size %u" -e1000e_rx_null_descriptor(void) "Null RX descriptor!!" -e1000e_rx_flt_vlan_mismatch(uint16_t vid) "VID mismatch: 0x%X" -e1000e_rx_flt_vlan_match(uint16_t vid) "VID match: 0x%X" -e1000e_rx_desc_ps_read(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) "buffers: [0x%"PRIx64", 0x%"PRIx64", 0x%"PRIx64", 0x%"PRIx64"]" -e1000e_rx_desc_ps_write(uint16_t a0, uint16_t a1, uint16_t a2, uint16_t a3) "bytes written: [%u, %u, %u, %u]" -e1000e_rx_desc_buff_sizes(uint32_t b0, uint32_t b1, uint32_t b2, uint32_t b3) "buffer sizes: [%u, %u, %u, %u]" -e1000e_rx_desc_len(uint8_t rx_desc_len) "RX descriptor length: %u" -e1000e_rx_desc_buff_write(uint8_t idx, uint64_t addr, uint16_t offset, const void* source, uint32_t len) "buffer #%u, addr: 0x%"PRIx64", offset: %u, from: %p, length: %u" -e1000e_rx_descr(int ridx, uint64_t base, uint8_t len) "Next RX descriptor: ring #%d, PA: 0x%"PRIx64", length: %u" -e1000e_rx_set_rctl(uint32_t rctl) "RCTL = 0x%x" -e1000e_rx_receive_iov(int iovcnt) "Received vector of %d fragments" -e1000e_rx_packet_size(size_t full, size_t vhdr, size_t data) "Received packet of %zu bytes total, %zu virt header, %zu data" -e1000e_rx_flt_dropped(void) "Received packet dropped by RX filter" -e1000e_rx_written_to_guest(uint32_t causes) "Received packet written to guest (ICR causes %u)" -e1000e_rx_not_written_to_guest(uint32_t causes) "Received packet NOT written to guest (ICR causes %u)" -e1000e_rx_interrupt_set(uint32_t causes) "Receive interrupt set (ICR causes %u)" -e1000e_rx_interrupt_delayed(uint32_t causes) "Receive interrupt delayed (ICR causes %u)" -e1000e_rx_set_cso(int cso_state) "RX CSO state set to %d" -e1000e_rx_set_rdt(int queue_idx, uint32_t val) "Setting RDT[%d] = %u" -e1000e_rx_set_rfctl(uint32_t val) "Setting RFCTL = 0x%X" -e1000e_rx_start_recv(void) - -e1000e_rx_rss_started(void) "Starting RSS processing" -e1000e_rx_rss_disabled(void) "RSS is disabled" -e1000e_rx_rss_type(uint32_t type) "RSS type is %u" -e1000e_rx_rss_ip4(bool isfragment, bool istcp, uint32_t mrqc, bool tcpipv4_enabled, bool ipv4_enabled) "RSS IPv4: fragment %d, tcp %d, mrqc 0x%X, tcpipv4 enabled %d, ipv4 enabled %d" -e1000e_rx_rss_ip6_rfctl(uint32_t rfctl) "RSS IPv6: rfctl 0x%X" -e1000e_rx_rss_ip6(bool ex_dis, bool new_ex_dis, bool istcp, bool has_ext_headers, bool ex_dst_valid, bool ex_src_valid, uint32_t mrqc, bool tcpipv6_enabled, bool ipv6ex_enabled, bool ipv6_enabled) "RSS IPv6: ex_dis: %d, new_ex_dis: %d, tcp %d, has_ext_headers %d, ex_dst_valid %d, ex_src_valid %d, mrqc 0x%X, tcpipv6 enabled %d, ipv6ex enabled %d, ipv6 enabled %d" -e1000e_rx_rss_dispatched_to_queue(int queue_idx) "Packet being dispatched to queue %d" - -e1000e_rx_metadata_protocols(bool isip4, bool isip6, bool isudp, bool istcp) "protocols: ip4: %d, ip6: %d, udp: %d, tcp: %d" -e1000e_rx_metadata_vlan(uint16_t vlan_tag) "VLAN tag is 0x%X" -e1000e_rx_metadata_rss(uint32_t rss, uint32_t mrq) "RSS data: rss: 0x%X, mrq: 0x%X" -e1000e_rx_metadata_ip_id(uint16_t ip_id) "the IPv4 ID is 0x%X" -e1000e_rx_metadata_ack(void) "the packet is TCP ACK" -e1000e_rx_metadata_pkt_type(uint32_t pkt_type) "the packet type is %u" -e1000e_rx_metadata_no_virthdr(void) "the packet has no virt-header" -e1000e_rx_metadata_virthdr_no_csum_info(void) "virt-header does not contain checksum info" -e1000e_rx_metadata_l3_cso_disabled(void) "IP4 CSO is disabled" -e1000e_rx_metadata_l4_cso_disabled(void) "TCP/UDP CSO is disabled" -e1000e_rx_metadata_l3_csum_validation_failed(void) "Cannot validate L3 checksum" -e1000e_rx_metadata_l4_csum_validation_failed(void) "Cannot validate L4 checksum" -e1000e_rx_metadata_status_flags(uint32_t status_flags) "status_flags is 0x%X" -e1000e_rx_metadata_ipv6_sum_disabled(void) "IPv6 RX checksummimg disabled by RFCTL" -e1000e_rx_metadata_ipv6_filtering_disabled(void) "IPv6 RX filtering disabled by RFCTL" - -e1000e_vlan_vet(uint16_t vet) "Setting VLAN ethernet type 0x%X" - -e1000e_irq_set_cause(uint32_t cause) "IRQ cause set 0x%x" -e1000e_irq_msi_notify(uint32_t cause) "MSI notify 0x%x" -e1000e_irq_throttling_no_pending_interrupts(void) "No pending interrupts to notify" -e1000e_irq_msi_notify_postponed(void) "Sending MSI postponed by ITR" -e1000e_irq_legacy_notify_postponed(void) "Raising legacy IRQ postponed by ITR" -e1000e_irq_throttling_no_pending_vec(int idx) "No pending interrupts for vector %d" -e1000e_irq_msix_notify_postponed_vec(int idx) "Sending MSI-X postponed by EITR[%d]" -e1000e_irq_msix_notify(uint32_t cause) "MSI-X notify 0x%x" -e1000e_irq_legacy_notify(bool level) "IRQ line state: %d" -e1000e_irq_msix_notify_vec(uint32_t vector) "MSI-X notify vector 0x%x" -e1000e_irq_postponed_by_xitr(uint32_t reg) "Interrupt postponed by [E]ITR register 0x%x" -e1000e_irq_clear_ims(uint32_t bits, uint32_t old_ims, uint32_t new_ims) "Clearing IMS bits 0x%x: 0x%x --> 0x%x" -e1000e_irq_set_ims(uint32_t bits, uint32_t old_ims, uint32_t new_ims) "Setting IMS bits 0x%x: 0x%x --> 0x%x" -e1000e_irq_fix_icr_asserted(uint32_t new_val) "ICR_ASSERTED bit fixed: 0x%x" -e1000e_irq_add_msi_other(uint32_t new_val) "ICR_OTHER bit added: 0x%x" -e1000e_irq_pending_interrupts(uint32_t pending, uint32_t icr, uint32_t ims) "ICR PENDING: 0x%x (ICR: 0x%x, IMS: 0x%x)" -e1000e_irq_set_cause_entry(uint32_t val, uint32_t icr) "Going to set IRQ cause 0x%x, ICR: 0x%x" -e1000e_irq_set_cause_exit(uint32_t val, uint32_t icr) "Set IRQ cause 0x%x, ICR: 0x%x" -e1000e_irq_icr_write(uint32_t bits, uint32_t old_icr, uint32_t new_icr) "Clearing ICR bits 0x%x: 0x%x --> 0x%x" -e1000e_irq_write_ics(uint32_t val) "Adding ICR bits 0x%x" -e1000e_irq_icr_process_iame(void) "Clearing IMS bits due to IAME" -e1000e_irq_read_ics(uint32_t ics) "Current ICS: 0x%x" -e1000e_irq_read_ims(uint32_t ims) "Current IMS: 0x%x" -e1000e_irq_icr_read_entry(uint32_t icr) "Starting ICR read. Current ICR: 0x%x" -e1000e_irq_icr_read_exit(uint32_t icr) "Ending ICR read. Current ICR: 0x%x" -e1000e_irq_icr_clear_zero_ims(void) "Clearing ICR on read due to zero IMS" -e1000e_irq_icr_clear_iame(void) "Clearing ICR on read due to IAME" -e1000e_irq_ims_clear_eiame(uint32_t iam, uint32_t cause) "Clearing IMS due to EIAME, IAM: 0x%X, cause: 0x%X" -e1000e_irq_icr_clear_eiac(uint32_t icr, uint32_t eiac) "Clearing ICR bits due to EIAC, ICR: 0x%X, EIAC: 0x%X" -e1000e_irq_ims_clear_set_imc(uint32_t val) "Clearing IMS bits due to IMC write 0x%x" -e1000e_irq_fire_delayed_interrupts(void) "Firing delayed interrupts" -e1000e_irq_rearm_timer(uint32_t reg, int64_t delay_ns) "Mitigation timer armed for register 0x%X, delay %"PRId64" ns" -e1000e_irq_throttling_timer(uint32_t reg) "Mitigation timer shot for register 0x%X" -e1000e_irq_rdtr_fpd_running(void) "FPD written while RDTR was running" -e1000e_irq_rdtr_fpd_not_running(void) "FPD written while RDTR was not running" -e1000e_irq_tidv_fpd_running(void) "FPD written while TIDV was running" -e1000e_irq_tidv_fpd_not_running(void) "FPD written while TIDV was not running" -e1000e_irq_eitr_set(uint32_t eitr_num, uint32_t val) "EITR[%u] = %u" -e1000e_irq_itr_set(uint32_t val) "ITR = %u" -e1000e_irq_fire_all_timers(uint32_t val) "Firing all delay/throttling timers on all interrupts enable (0x%X written to IMS)" -e1000e_irq_adding_delayed_causes(uint32_t val, uint32_t icr) "Merging delayed causes 0x%X to ICR 0x%X" -e1000e_irq_msix_pending_clearing(uint32_t cause, uint32_t int_cfg, uint32_t vec) "Clearing MSI-X pending bit for cause 0x%x, IVAR config 0x%x, vector %u" - -e1000e_wrn_msix_vec_wrong(uint32_t cause, uint32_t cfg) "Invalid configuration for cause 0x%x: 0x%x" -e1000e_wrn_msix_invalid(uint32_t cause, uint32_t cfg) "Invalid entry for cause 0x%x: 0x%x" - -e1000e_mac_set_permanent(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "Set permanent MAC: %02x:%02x:%02x:%02x:%02x:%02x" -e1000e_mac_set_sw(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "Set SW MAC: %02x:%02x:%02x:%02x:%02x:%02x" - -# hw/net/e1000e.c -e1000e_cb_pci_realize(void) "E1000E PCI realize entry" -e1000e_cb_pci_uninit(void) "E1000E PCI unit entry" -e1000e_cb_qdev_reset(void) "E1000E qdev reset entry" -e1000e_cb_pre_save(void) "E1000E pre save entry" -e1000e_cb_post_load(void) "E1000E post load entry" - -e1000e_io_write_addr(uint64_t addr) "IOADDR write 0x%"PRIx64 -e1000e_io_write_data(uint64_t addr, uint64_t val) "IODATA write 0x%"PRIx64", value: 0x%"PRIx64 -e1000e_io_read_addr(uint64_t addr) "IOADDR read 0x%"PRIx64 -e1000e_io_read_data(uint64_t addr, uint64_t val) "IODATA read 0x%"PRIx64", value: 0x%"PRIx64 -e1000e_wrn_io_write_unknown(uint64_t addr) "IO write unknown address 0x%"PRIx64 -e1000e_wrn_io_read_unknown(uint64_t addr) "IO read unknown address 0x%"PRIx64 -e1000e_wrn_io_addr_undefined(uint64_t addr) "IO undefined register 0x%"PRIx64 -e1000e_wrn_io_addr_flash(uint64_t addr) "IO flash access (0x%"PRIx64") not implemented" -e1000e_wrn_io_addr_unknown(uint64_t addr) "IO unknown register 0x%"PRIx64 - -e1000e_msi_init_fail(int32_t res) "Failed to initialize MSI, error %d" -e1000e_msix_init_fail(int32_t res) "Failed to initialize MSI-X, error %d" -e1000e_msix_use_vector_fail(uint32_t vec, int32_t res) "Failed to use MSI-X vector %d, error %d" - -e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d" - -e1000e_vm_state_running(void) "VM state is running" -e1000e_vm_state_stopped(void) "VM state is stopped" diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index f2d49ad7e..6e1032fc1 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -88,10 +88,10 @@ static const int *vhost_net_get_feature_bits(struct vhost_net *net) const int *feature_bits = 0; switch (net->nc->info->type) { - case NET_CLIENT_DRIVER_TAP: + case NET_CLIENT_OPTIONS_KIND_TAP: feature_bits = kernel_feature_bits; break; - case NET_CLIENT_DRIVER_VHOST_USER: + case NET_CLIENT_OPTIONS_KIND_VHOST_USER: feature_bits = user_feature_bits; break; default: @@ -120,15 +120,10 @@ uint64_t vhost_net_get_max_queues(VHostNetState *net) return net->dev.max_queues; } -uint64_t vhost_net_get_acked_features(VHostNetState *net) -{ - return net->dev.acked_features; -} - static int vhost_net_get_fd(NetClientState *backend) { switch (backend->info->type) { - case NET_CLIENT_DRIVER_TAP: + case NET_CLIENT_OPTIONS_KIND_TAP: return tap_get_fd(backend); default: fprintf(stderr, "vhost-net requires tap backend\n"); @@ -140,8 +135,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) { int r; bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL; - struct vhost_net *net = g_new0(struct vhost_net, 1); - uint64_t features = 0; + struct vhost_net *net = g_malloc(sizeof *net); if (!options->net_backend) { fprintf(stderr, "vhost-net requires net backend to be setup\n"); @@ -172,7 +166,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) } r = vhost_dev_init(&net->dev, options->opaque, - options->backend_type, options->busyloop_timeout); + options->backend_type); if (r < 0) { goto fail; } @@ -185,27 +179,14 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n", (uint64_t)(~net->dev.features & net->dev.backend_features)); + vhost_dev_cleanup(&net->dev); goto fail; } } - /* Set sane init value. Override when guest acks. */ - if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { - features = vhost_user_get_acked_features(net->nc); - if (~net->dev.features & features) { - fprintf(stderr, "vhost lacks feature mask %" PRIu64 - " for backend\n", - (uint64_t)(~net->dev.features & features)); - goto fail; - } - } - - vhost_net_ack_features(net, features); - + vhost_net_ack_features(net, 0); return net; - fail: - vhost_dev_cleanup(&net->dev); g_free(net); return NULL; } @@ -238,11 +219,12 @@ static int vhost_net_start_one(struct vhost_net *net, net->nc->info->poll(net->nc, false); } - if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { + if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) { qemu_set_fd_handler(net->backend, NULL, NULL, NULL); file.fd = net->backend; for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { - r = vhost_net_set_backend(&net->dev, &file); + const VhostOps *vhost_ops = net->dev.vhost_ops; + r = vhost_ops->vhost_net_set_backend(&net->dev, &file); if (r < 0) { r = -errno; goto fail; @@ -252,9 +234,10 @@ static int vhost_net_start_one(struct vhost_net *net, return 0; fail: file.fd = -1; - if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { + if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) { while (file.index-- > 0) { - int r = vhost_net_set_backend(&net->dev, &file); + const VhostOps *vhost_ops = net->dev.vhost_ops; + int r = vhost_ops->vhost_net_set_backend(&net->dev, &file); assert(r >= 0); } } @@ -273,9 +256,10 @@ static void vhost_net_stop_one(struct vhost_net *net, { struct vhost_vring_file file = { .fd = -1 }; - if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) { + if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) { for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { - int r = vhost_net_set_backend(&net->dev, &file); + const VhostOps *vhost_ops = net->dev.vhost_ops; + int r = vhost_ops->vhost_net_set_backend(&net->dev, &file); assert(r >= 0); } } @@ -309,8 +293,8 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, * because vhost user doesn't interrupt masking/unmasking * properly. */ - if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) { - dev->use_guest_notifier_mask = false; + if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) { + dev->use_guest_notifier_mask = false; } } @@ -326,15 +310,6 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, if (r < 0) { goto err_start; } - - if (ncs[i].peer->vring_enable) { - /* restore vring enable state */ - r = vhost_set_vring_enable(ncs[i].peer, ncs[i].peer->vring_enable); - - if (r < 0) { - goto err_start; - } - } } return 0; @@ -375,16 +350,19 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, void vhost_net_cleanup(struct vhost_net *net) { vhost_dev_cleanup(&net->dev); + g_free(net); } int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr) { const VhostOps *vhost_ops = net->dev.vhost_ops; + int r = -1; - assert(vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); - assert(vhost_ops->vhost_migration_done); + if (vhost_ops->vhost_migration_done) { + r = vhost_ops->vhost_migration_done(&net->dev, mac_addr); + } - return vhost_ops->vhost_migration_done(&net->dev, mac_addr); + return r; } bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) @@ -407,12 +385,11 @@ VHostNetState *get_vhost_net(NetClientState *nc) } switch (nc->info->type) { - case NET_CLIENT_DRIVER_TAP: + case NET_CLIENT_OPTIONS_KIND_TAP: vhost_net = tap_get_vhost_net(nc); break; - case NET_CLIENT_DRIVER_VHOST_USER: + case NET_CLIENT_OPTIONS_KIND_VHOST_USER: vhost_net = vhost_user_get_vhost_net(nc); - assert(vhost_net); break; default: break; @@ -426,9 +403,7 @@ int vhost_set_vring_enable(NetClientState *nc, int enable) VHostNetState *net = get_vhost_net(nc); const VhostOps *vhost_ops = net->dev.vhost_ops; - nc->vring_enable = enable; - - if (vhost_ops && vhost_ops->vhost_set_vring_enable) { + if (vhost_ops->vhost_set_vring_enable) { return vhost_ops->vhost_set_vring_enable(&net->dev, enable); } @@ -467,16 +442,10 @@ uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) { return features; } - void vhost_net_ack_features(struct vhost_net *net, uint64_t features) { } -uint64_t vhost_net_get_acked_features(VHostNetState *net) -{ - return 0; -} - bool vhost_net_virtqueue_pending(VHostNetState *net, int idx) { return false; diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 01f135155..8aaa10380 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -468,11 +468,11 @@ static int peer_attach(VirtIONet *n, int index) return 0; } - if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) { + if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) { vhost_set_vring_enable(nc->peer, 1); } - if (nc->peer->info->type != NET_CLIENT_DRIVER_TAP) { + if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { return 0; } @@ -487,11 +487,11 @@ static int peer_detach(VirtIONet *n, int index) return 0; } - if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) { + if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) { vhost_set_vring_enable(nc->peer, 0); } - if (nc->peer->info->type != NET_CLIENT_DRIVER_TAP) { + if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) { return 0; } @@ -1051,7 +1051,7 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) ptr += n->host_hdr_len; if (!memcmp(&ptr[12], vlan, sizeof(vlan))) { - int vid = lduw_be_p(ptr + 14) & 0xfff; + int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff; if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f)))) return 0; } @@ -1492,7 +1492,7 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) virtio_net_set_queues(n); } -static void virtio_net_save(QEMUFile *f, void *opaque, size_t size) +static void virtio_net_save(QEMUFile *f, void *opaque) { VirtIONet *n = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(n); @@ -1538,12 +1538,15 @@ static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f) } } -static int virtio_net_load(QEMUFile *f, void *opaque, size_t size) +static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) { VirtIONet *n = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(n); - return virtio_load(vdev, f, VIRTIO_NET_VM_VERSION); + if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) + return -EINVAL; + + return virtio_load(vdev, f, version_id); } static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, @@ -1559,49 +1562,68 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)); - n->status = qemu_get_be16(f); - - n->promisc = qemu_get_byte(f); - n->allmulti = qemu_get_byte(f); + if (version_id >= 3) + n->status = qemu_get_be16(f); - n->mac_table.in_use = qemu_get_be32(f); - /* MAC_TABLE_ENTRIES may be different from the saved image */ - if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) { - qemu_get_buffer(f, n->mac_table.macs, - n->mac_table.in_use * ETH_ALEN); - } else { - int64_t i; + if (version_id >= 4) { + if (version_id < 8) { + n->promisc = qemu_get_be32(f); + n->allmulti = qemu_get_be32(f); + } else { + n->promisc = qemu_get_byte(f); + n->allmulti = qemu_get_byte(f); + } + } - /* Overflow detected - can happen if source has a larger MAC table. - * We simply set overflow flag so there's no need to maintain the - * table of addresses, discard them all. - * Note: 64 bit math to avoid integer overflow. - */ - for (i = 0; i < (int64_t)n->mac_table.in_use * ETH_ALEN; ++i) { - qemu_get_byte(f); + if (version_id >= 5) { + n->mac_table.in_use = qemu_get_be32(f); + /* MAC_TABLE_ENTRIES may be different from the saved image */ + if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) { + qemu_get_buffer(f, n->mac_table.macs, + n->mac_table.in_use * ETH_ALEN); + } else { + int64_t i; + + /* Overflow detected - can happen if source has a larger MAC table. + * We simply set overflow flag so there's no need to maintain the + * table of addresses, discard them all. + * Note: 64 bit math to avoid integer overflow. + */ + for (i = 0; i < (int64_t)n->mac_table.in_use * ETH_ALEN; ++i) { + qemu_get_byte(f); + } + n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1; + n->mac_table.in_use = 0; } - n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1; - n->mac_table.in_use = 0; } - qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); + if (version_id >= 6) + qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); - if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) { - error_report("virtio-net: saved image requires vnet_hdr=on"); - return -1; + if (version_id >= 7) { + if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) { + error_report("virtio-net: saved image requires vnet_hdr=on"); + return -1; + } } - n->mac_table.multi_overflow = qemu_get_byte(f); - n->mac_table.uni_overflow = qemu_get_byte(f); + if (version_id >= 9) { + n->mac_table.multi_overflow = qemu_get_byte(f); + n->mac_table.uni_overflow = qemu_get_byte(f); + } - n->alluni = qemu_get_byte(f); - n->nomulti = qemu_get_byte(f); - n->nouni = qemu_get_byte(f); - n->nobcast = qemu_get_byte(f); + if (version_id >= 10) { + n->alluni = qemu_get_byte(f); + n->nomulti = qemu_get_byte(f); + n->nouni = qemu_get_byte(f); + n->nobcast = qemu_get_byte(f); + } - if (qemu_get_byte(f) && !peer_has_ufo(n)) { - error_report("virtio-net: saved image requires TUN_F_UFO support"); - return -1; + if (version_id >= 11) { + if (qemu_get_byte(f) && !peer_has_ufo(n)) { + error_report("virtio-net: saved image requires TUN_F_UFO support"); + return -1; + } } if (n->max_queues > 1) { @@ -1658,7 +1680,7 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f, } static NetClientInfo net_virtio_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = virtio_net_can_receive, .receive = virtio_net_receive, @@ -1787,6 +1809,8 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) nc->rxfilter_notify_enabled = 1; n->qdev = dev; + register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION, + virtio_net_save, virtio_net_load, n); } static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) @@ -1798,6 +1822,8 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) /* This will stop vhost backend if appropriate. */ virtio_net_set_status(vdev, 0); + unregister_savevm(dev, "virtio-net", n); + g_free(n->netclient_name); n->netclient_name = NULL; g_free(n->netclient_type); @@ -1832,9 +1858,6 @@ static void virtio_net_instance_init(Object *obj) DEVICE(n), NULL); } -VMSTATE_VIRTIO_DEVICE(net, VIRTIO_NET_VM_VERSION, virtio_net_load, - virtio_net_save); - static Property virtio_net_properties[] = { DEFINE_PROP_BIT("csum", VirtIONet, host_features, VIRTIO_NET_F_CSUM, true), DEFINE_PROP_BIT("guest_csum", VirtIONet, host_features, @@ -1889,7 +1912,6 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->props = virtio_net_properties; - dc->vmsd = &vmstate_virtio_net; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); vdc->realize = virtio_net_device_realize; vdc->unrealize = virtio_net_device_unrealize; diff --git a/hw/net/vmware_utils.h b/hw/net/vmware_utils.h index 550060170..c0dbb2ff4 100644 --- a/hw/net/vmware_utils.h +++ b/hw/net/vmware_utils.h @@ -26,104 +26,97 @@ * */ static inline void -vmw_shmem_read(PCIDevice *d, hwaddr addr, void *buf, int len) +vmw_shmem_read(hwaddr addr, void *buf, int len) { VMW_SHPRN("SHMEM r: %" PRIx64 ", len: %d to %p", addr, len, buf); - pci_dma_read(d, addr, buf, len); + cpu_physical_memory_read(addr, buf, len); } static inline void -vmw_shmem_write(PCIDevice *d, hwaddr addr, void *buf, int len) +vmw_shmem_write(hwaddr addr, void *buf, int len) { VMW_SHPRN("SHMEM w: %" PRIx64 ", len: %d to %p", addr, len, buf); - pci_dma_write(d, addr, buf, len); + cpu_physical_memory_write(addr, buf, len); } static inline void -vmw_shmem_rw(PCIDevice *d, hwaddr addr, void *buf, int len, int is_write) +vmw_shmem_rw(hwaddr addr, void *buf, int len, int is_write) { VMW_SHPRN("SHMEM r/w: %" PRIx64 ", len: %d (to %p), is write: %d", addr, len, buf, is_write); - if (is_write) - pci_dma_write(d, addr, buf, len); - else - pci_dma_read(d, addr, buf, len); + cpu_physical_memory_rw(addr, buf, len, is_write); } static inline void -vmw_shmem_set(PCIDevice *d, hwaddr addr, uint8_t val, int len) +vmw_shmem_set(hwaddr addr, uint8_t val, int len) { int i; VMW_SHPRN("SHMEM set: %" PRIx64 ", len: %d (value 0x%X)", addr, len, val); for (i = 0; i < len; i++) { - pci_dma_write(d, addr + i, &val, 1); + cpu_physical_memory_write(addr + i, &val, 1); } } static inline uint32_t -vmw_shmem_ld8(PCIDevice *d, hwaddr addr) +vmw_shmem_ld8(hwaddr addr) { - uint8_t res; - pci_dma_read(d, addr, &res, 1); + uint8_t res = ldub_phys(&address_space_memory, addr); VMW_SHPRN("SHMEM load8: %" PRIx64 " (value 0x%X)", addr, res); return res; } static inline void -vmw_shmem_st8(PCIDevice *d, hwaddr addr, uint8_t value) +vmw_shmem_st8(hwaddr addr, uint8_t value) { VMW_SHPRN("SHMEM store8: %" PRIx64 " (value 0x%X)", addr, value); - pci_dma_write(d, addr, &value, 1); + stb_phys(&address_space_memory, addr, value); } static inline uint32_t -vmw_shmem_ld16(PCIDevice *d, hwaddr addr) +vmw_shmem_ld16(hwaddr addr) { - uint16_t res; - pci_dma_read(d, addr, &res, 2); + uint16_t res = lduw_le_phys(&address_space_memory, addr); VMW_SHPRN("SHMEM load16: %" PRIx64 " (value 0x%X)", addr, res); return res; } static inline void -vmw_shmem_st16(PCIDevice *d, hwaddr addr, uint16_t value) +vmw_shmem_st16(hwaddr addr, uint16_t value) { VMW_SHPRN("SHMEM store16: %" PRIx64 " (value 0x%X)", addr, value); - pci_dma_write(d, addr, &value, 2); + stw_le_phys(&address_space_memory, addr, value); } static inline uint32_t -vmw_shmem_ld32(PCIDevice *d, hwaddr addr) +vmw_shmem_ld32(hwaddr addr) { - uint32_t res; - pci_dma_read(d, addr, &res, 4); + uint32_t res = ldl_le_phys(&address_space_memory, addr); VMW_SHPRN("SHMEM load32: %" PRIx64 " (value 0x%X)", addr, res); return res; } static inline void -vmw_shmem_st32(PCIDevice *d, hwaddr addr, uint32_t value) +vmw_shmem_st32(hwaddr addr, uint32_t value) { VMW_SHPRN("SHMEM store32: %" PRIx64 " (value 0x%X)", addr, value); - pci_dma_write(d, addr, &value, 4); + stl_le_phys(&address_space_memory, addr, value); } static inline uint64_t -vmw_shmem_ld64(PCIDevice *d, hwaddr addr) +vmw_shmem_ld64(hwaddr addr) { - uint64_t res; - pci_dma_read(d, addr, &res, 8); + uint64_t res = ldq_le_phys(&address_space_memory, addr); VMW_SHPRN("SHMEM load64: %" PRIx64 " (value %" PRIx64 ")", addr, res); return res; } static inline void -vmw_shmem_st64(PCIDevice *d, hwaddr addr, uint64_t value) +vmw_shmem_st64(hwaddr addr, uint64_t value) { VMW_SHPRN("SHMEM store64: %" PRIx64 " (value %" PRIx64 ")", addr, value); - pci_dma_write(d, addr, &value, 8); + stq_le_phys(&address_space_memory, addr, value); } /* Macros for simplification of operations on array-style registers */ diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 90f694366..20f26b7d8 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -30,8 +30,8 @@ #include "vmxnet3.h" #include "vmxnet_debug.h" #include "vmware_utils.h" -#include "net_tx_pkt.h" -#include "net_rx_pkt.h" +#include "vmxnet_tx_pkt.h" +#include "vmxnet_rx_pkt.h" #define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1 #define VMXNET3_MSIX_BAR_SIZE 0x2000 @@ -74,54 +74,54 @@ #define VMXNET3_MAX_NMSIX_INTRS (1) /* Macros for rings descriptors access */ -#define VMXNET3_READ_TX_QUEUE_DESCR8(_d, dpa, field) \ - (vmw_shmem_ld8(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) +#define VMXNET3_READ_TX_QUEUE_DESCR8(dpa, field) \ + (vmw_shmem_ld8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) -#define VMXNET3_WRITE_TX_QUEUE_DESCR8(_d, dpa, field, value) \ - (vmw_shmem_st8(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field, value))) +#define VMXNET3_WRITE_TX_QUEUE_DESCR8(dpa, field, value) \ + (vmw_shmem_st8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field, value))) -#define VMXNET3_READ_TX_QUEUE_DESCR32(_d, dpa, field) \ - (vmw_shmem_ld32(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) +#define VMXNET3_READ_TX_QUEUE_DESCR32(dpa, field) \ + (vmw_shmem_ld32(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) -#define VMXNET3_WRITE_TX_QUEUE_DESCR32(_d, dpa, field, value) \ - (vmw_shmem_st32(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value)) +#define VMXNET3_WRITE_TX_QUEUE_DESCR32(dpa, field, value) \ + (vmw_shmem_st32(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value)) -#define VMXNET3_READ_TX_QUEUE_DESCR64(_d, dpa, field) \ - (vmw_shmem_ld64(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) +#define VMXNET3_READ_TX_QUEUE_DESCR64(dpa, field) \ + (vmw_shmem_ld64(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field))) -#define VMXNET3_WRITE_TX_QUEUE_DESCR64(_d, dpa, field, value) \ - (vmw_shmem_st64(_d, dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value)) +#define VMXNET3_WRITE_TX_QUEUE_DESCR64(dpa, field, value) \ + (vmw_shmem_st64(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value)) -#define VMXNET3_READ_RX_QUEUE_DESCR64(_d, dpa, field) \ - (vmw_shmem_ld64(_d, dpa + offsetof(struct Vmxnet3_RxQueueDesc, field))) +#define VMXNET3_READ_RX_QUEUE_DESCR64(dpa, field) \ + (vmw_shmem_ld64(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field))) -#define VMXNET3_READ_RX_QUEUE_DESCR32(_d, dpa, field) \ - (vmw_shmem_ld32(_d, dpa + offsetof(struct Vmxnet3_RxQueueDesc, field))) +#define VMXNET3_READ_RX_QUEUE_DESCR32(dpa, field) \ + (vmw_shmem_ld32(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field))) -#define VMXNET3_WRITE_RX_QUEUE_DESCR64(_d, dpa, field, value) \ - (vmw_shmem_st64(_d, dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value)) +#define VMXNET3_WRITE_RX_QUEUE_DESCR64(dpa, field, value) \ + (vmw_shmem_st64(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value)) -#define VMXNET3_WRITE_RX_QUEUE_DESCR8(_d, dpa, field, value) \ - (vmw_shmem_st8(_d, dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value)) +#define VMXNET3_WRITE_RX_QUEUE_DESCR8(dpa, field, value) \ + (vmw_shmem_st8(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value)) /* Macros for guest driver shared area access */ -#define VMXNET3_READ_DRV_SHARED64(_d, shpa, field) \ - (vmw_shmem_ld64(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field))) +#define VMXNET3_READ_DRV_SHARED64(shpa, field) \ + (vmw_shmem_ld64(shpa + offsetof(struct Vmxnet3_DriverShared, field))) -#define VMXNET3_READ_DRV_SHARED32(_d, shpa, field) \ - (vmw_shmem_ld32(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field))) +#define VMXNET3_READ_DRV_SHARED32(shpa, field) \ + (vmw_shmem_ld32(shpa + offsetof(struct Vmxnet3_DriverShared, field))) -#define VMXNET3_WRITE_DRV_SHARED32(_d, shpa, field, val) \ - (vmw_shmem_st32(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field), val)) +#define VMXNET3_WRITE_DRV_SHARED32(shpa, field, val) \ + (vmw_shmem_st32(shpa + offsetof(struct Vmxnet3_DriverShared, field), val)) -#define VMXNET3_READ_DRV_SHARED16(_d, shpa, field) \ - (vmw_shmem_ld16(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field))) +#define VMXNET3_READ_DRV_SHARED16(shpa, field) \ + (vmw_shmem_ld16(shpa + offsetof(struct Vmxnet3_DriverShared, field))) -#define VMXNET3_READ_DRV_SHARED8(_d, shpa, field) \ - (vmw_shmem_ld8(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field))) +#define VMXNET3_READ_DRV_SHARED8(shpa, field) \ + (vmw_shmem_ld8(shpa + offsetof(struct Vmxnet3_DriverShared, field))) -#define VMXNET3_READ_DRV_SHARED(_d, shpa, field, b, l) \ - (vmw_shmem_read(_d, shpa + offsetof(struct Vmxnet3_DriverShared, field), b, l)) +#define VMXNET3_READ_DRV_SHARED(shpa, field, b, l) \ + (vmw_shmem_read(shpa + offsetof(struct Vmxnet3_DriverShared, field), b, l)) #define VMXNET_FLAG_IS_SET(field, flag) (((field) & (flag)) == (flag)) @@ -147,8 +147,7 @@ typedef struct { uint8_t gen; } Vmxnet3Ring; -static inline void vmxnet3_ring_init(PCIDevice *d, - Vmxnet3Ring *ring, +static inline void vmxnet3_ring_init(Vmxnet3Ring *ring, hwaddr pa, size_t size, size_t cell_size, @@ -161,7 +160,7 @@ static inline void vmxnet3_ring_init(PCIDevice *d, ring->next = 0; if (zero_region) { - vmw_shmem_set(d, pa, 0, size * cell_size); + vmw_shmem_set(pa, 0, size * cell_size); } } @@ -191,16 +190,14 @@ static inline hwaddr vmxnet3_ring_curr_cell_pa(Vmxnet3Ring *ring) return ring->pa + ring->next * ring->cell_size; } -static inline void vmxnet3_ring_read_curr_cell(PCIDevice *d, Vmxnet3Ring *ring, - void *buff) +static inline void vmxnet3_ring_read_curr_cell(Vmxnet3Ring *ring, void *buff) { - vmw_shmem_read(d, vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size); + vmw_shmem_read(vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size); } -static inline void vmxnet3_ring_write_curr_cell(PCIDevice *d, Vmxnet3Ring *ring, - void *buff) +static inline void vmxnet3_ring_write_curr_cell(Vmxnet3Ring *ring, void *buff) { - vmw_shmem_write(d, vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size); + vmw_shmem_write(vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size); } static inline size_t vmxnet3_ring_curr_cell_idx(Vmxnet3Ring *ring) @@ -283,6 +280,8 @@ typedef struct { /* Whether MSI-X support was installed successfully */ bool msix_used; + /* Whether MSI support was installed successfully */ + bool msi_used; hwaddr drv_shmem; hwaddr temp_shared_guest_driver_memory; @@ -315,13 +314,13 @@ typedef struct { bool peer_has_vhdr; /* TX packets to QEMU interface */ - struct NetTxPkt *tx_pkt; + struct VmxnetTxPkt *tx_pkt; uint32_t offload_mode; uint32_t cso_or_gso_size; uint16_t tci; bool needs_vlan; - struct NetRxPkt *rx_pkt; + struct VmxnetRxPkt *rx_pkt; bool tx_sop; bool skip_current_tx_pkt; @@ -349,7 +348,7 @@ typedef struct { /* Interrupt management */ /* - * This function returns sign whether interrupt line is in asserted state + *This function returns sign whether interrupt line is in asserted state * This depends on the type of interrupt used. For INTX interrupt line will * be asserted until explicit deassertion, for MSI(X) interrupt line will * be deasserted automatically due to notification semantics of the MSI(X) @@ -364,7 +363,7 @@ static bool _vmxnet3_assert_interrupt_line(VMXNET3State *s, uint32_t int_idx) msix_notify(d, int_idx); return false; } - if (msi_enabled(d)) { + if (s->msi_used && msi_enabled(d)) { VMW_IRPRN("Sending MSI notification for vector %u", int_idx); msi_notify(d, int_idx); return false; @@ -388,7 +387,7 @@ static void _vmxnet3_deassert_interrupt_line(VMXNET3State *s, int lidx) * This function should never be called for MSI(X) interrupts * because deassertion never required for message interrupts */ - assert(!msi_enabled(d)); + assert(!s->msi_used || !msi_enabled(d)); VMW_IRPRN("Deasserting line for interrupt %u", lidx); pci_irq_deassert(d); @@ -425,7 +424,7 @@ static void vmxnet3_trigger_interrupt(VMXNET3State *s, int lidx) goto do_automask; } - if (msi_enabled(d) && s->auto_int_masking) { + if (s->msi_used && msi_enabled(d) && s->auto_int_masking) { goto do_automask; } @@ -457,9 +456,9 @@ vmxnet3_on_interrupt_mask_changed(VMXNET3State *s, int lidx, bool is_masked) vmxnet3_update_interrupt_line_state(s, lidx); } -static bool vmxnet3_verify_driver_magic(PCIDevice *d, hwaddr dshmem) +static bool vmxnet3_verify_driver_magic(hwaddr dshmem) { - return (VMXNET3_READ_DRV_SHARED32(d, dshmem, magic) == VMXNET3_REV1_MAGIC); + return (VMXNET3_READ_DRV_SHARED32(dshmem, magic) == VMXNET3_REV1_MAGIC); } #define VMXNET3_GET_BYTE(x, byte_num) (((x) >> (byte_num)*8) & 0xFF) @@ -475,7 +474,7 @@ static void vmxnet3_set_variable_mac(VMXNET3State *s, uint32_t h, uint32_t l) s->conf.macaddr.a[4] = VMXNET3_GET_BYTE(h, 0); s->conf.macaddr.a[5] = VMXNET3_GET_BYTE(h, 1); - VMW_CFPRN("Variable MAC: " MAC_FMT, MAC_ARG(s->conf.macaddr.a)); + VMW_CFPRN("Variable MAC: " VMXNET_MF, VMXNET_MA(s->conf.macaddr.a)); qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); } @@ -527,14 +526,13 @@ vmxnet3_dec_rx_completion_counter(VMXNET3State *s, int qidx) static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32_t tx_ridx) { struct Vmxnet3_TxCompDesc txcq_descr; - PCIDevice *d = PCI_DEVICE(s); VMXNET3_RING_DUMP(VMW_RIPRN, "TXC", qidx, &s->txq_descr[qidx].comp_ring); txcq_descr.txdIdx = tx_ridx; txcq_descr.gen = vmxnet3_ring_curr_gen(&s->txq_descr[qidx].comp_ring); - vmxnet3_ring_write_curr_cell(d, &s->txq_descr[qidx].comp_ring, &txcq_descr); + vmxnet3_ring_write_curr_cell(&s->txq_descr[qidx].comp_ring, &txcq_descr); /* Flush changes in TX descriptor before changing the counter value */ smp_wmb(); @@ -548,18 +546,18 @@ vmxnet3_setup_tx_offloads(VMXNET3State *s) { switch (s->offload_mode) { case VMXNET3_OM_NONE: - net_tx_pkt_build_vheader(s->tx_pkt, false, false, 0); + vmxnet_tx_pkt_build_vheader(s->tx_pkt, false, false, 0); break; case VMXNET3_OM_CSUM: - net_tx_pkt_build_vheader(s->tx_pkt, false, true, 0); + vmxnet_tx_pkt_build_vheader(s->tx_pkt, false, true, 0); VMW_PKPRN("L4 CSO requested\n"); break; case VMXNET3_OM_TSO: - net_tx_pkt_build_vheader(s->tx_pkt, true, true, + vmxnet_tx_pkt_build_vheader(s->tx_pkt, true, true, s->cso_or_gso_size); - net_tx_pkt_update_ip_checksums(s->tx_pkt); + vmxnet_tx_pkt_update_ip_checksums(s->tx_pkt); VMW_PKPRN("GSO offload requested."); break; @@ -592,12 +590,12 @@ static void vmxnet3_on_tx_done_update_stats(VMXNET3State *s, int qidx, Vmxnet3PktStatus status) { - size_t tot_len = net_tx_pkt_get_total_len(s->tx_pkt); + size_t tot_len = vmxnet_tx_pkt_get_total_len(s->tx_pkt); struct UPT1_TxStats *stats = &s->txq_descr[qidx].txq_stats; switch (status) { case VMXNET3_PKT_STATUS_OK: - switch (net_tx_pkt_get_packet_type(s->tx_pkt)) { + switch (vmxnet_tx_pkt_get_packet_type(s->tx_pkt)) { case ETH_PKT_BCAST: stats->bcastPktsTxOK++; stats->bcastBytesTxOK += tot_len; @@ -645,7 +643,7 @@ vmxnet3_on_rx_done_update_stats(VMXNET3State *s, Vmxnet3PktStatus status) { struct UPT1_RxStats *stats = &s->rxq_descr[qidx].rxq_stats; - size_t tot_len = net_rx_pkt_get_total_len(s->rx_pkt); + size_t tot_len = vmxnet_rx_pkt_get_total_len(s->rx_pkt); switch (status) { case VMXNET3_PKT_STATUS_OUT_OF_BUF: @@ -656,7 +654,7 @@ vmxnet3_on_rx_done_update_stats(VMXNET3State *s, stats->pktsRxError++; break; case VMXNET3_PKT_STATUS_OK: - switch (net_rx_pkt_get_packet_type(s->rx_pkt)) { + switch (vmxnet_rx_pkt_get_packet_type(s->rx_pkt)) { case ETH_PKT_BCAST: stats->bcastPktsRxOK++; stats->bcastBytesRxOK += tot_len; @@ -690,14 +688,13 @@ vmxnet3_pop_next_tx_descr(VMXNET3State *s, uint32_t *descr_idx) { Vmxnet3Ring *ring = &s->txq_descr[qidx].tx_ring; - PCIDevice *d = PCI_DEVICE(s); - vmxnet3_ring_read_curr_cell(d, ring, txd); + vmxnet3_ring_read_curr_cell(ring, txd); if (txd->gen == vmxnet3_ring_curr_gen(ring)) { /* Only read after generation field verification */ smp_rmb(); /* Re-read to be sure we got the latest version */ - vmxnet3_ring_read_curr_cell(d, ring, txd); + vmxnet3_ring_read_curr_cell(ring, txd); VMXNET3_RING_DUMP(VMW_RIPRN, "TX", qidx, ring); *descr_idx = vmxnet3_ring_curr_cell_idx(ring); vmxnet3_inc_tx_consumption_counter(s, qidx); @@ -718,10 +715,10 @@ vmxnet3_send_packet(VMXNET3State *s, uint32_t qidx) } /* debug prints */ - vmxnet3_dump_virt_hdr(net_tx_pkt_get_vhdr(s->tx_pkt)); - net_tx_pkt_dump(s->tx_pkt); + vmxnet3_dump_virt_hdr(vmxnet_tx_pkt_get_vhdr(s->tx_pkt)); + vmxnet_tx_pkt_dump(s->tx_pkt); - if (!net_tx_pkt_send(s->tx_pkt, qemu_get_queue(s->nic))) { + if (!vmxnet_tx_pkt_send(s->tx_pkt, qemu_get_queue(s->nic))) { status = VMXNET3_PKT_STATUS_DISCARD; goto func_exit; } @@ -749,7 +746,7 @@ static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx) data_len = (txd.len > 0) ? txd.len : VMXNET3_MAX_TX_BUF_SIZE; data_pa = le64_to_cpu(txd.addr); - if (!net_tx_pkt_add_raw_fragment(s->tx_pkt, + if (!vmxnet_tx_pkt_add_raw_fragment(s->tx_pkt, data_pa, data_len)) { s->skip_current_tx_pkt = true; @@ -762,9 +759,9 @@ static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx) } if (txd.eop) { - if (!s->skip_current_tx_pkt && net_tx_pkt_parse(s->tx_pkt)) { + if (!s->skip_current_tx_pkt && vmxnet_tx_pkt_parse(s->tx_pkt)) { if (s->needs_vlan) { - net_tx_pkt_setup_vlan_header(s->tx_pkt, s->tci); + vmxnet_tx_pkt_setup_vlan_header(s->tx_pkt, s->tci); } vmxnet3_send_packet(s, qidx); @@ -776,7 +773,7 @@ static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx) vmxnet3_complete_packet(s, qidx, txd_idx); s->tx_sop = true; s->skip_current_tx_pkt = false; - net_tx_pkt_reset(s->tx_pkt); + vmxnet_tx_pkt_reset(s->tx_pkt); } } } @@ -785,11 +782,9 @@ static inline void vmxnet3_read_next_rx_descr(VMXNET3State *s, int qidx, int ridx, struct Vmxnet3_RxDesc *dbuf, uint32_t *didx) { - PCIDevice *d = PCI_DEVICE(s); - Vmxnet3Ring *ring = &s->rxq_descr[qidx].rx_ring[ridx]; *didx = vmxnet3_ring_curr_cell_idx(ring); - vmxnet3_ring_read_curr_cell(d, ring, dbuf); + vmxnet3_ring_read_curr_cell(ring, dbuf); } static inline uint8_t @@ -807,8 +802,7 @@ vmxnet3_pop_rxc_descr(VMXNET3State *s, int qidx, uint32_t *descr_gen) hwaddr daddr = vmxnet3_ring_curr_cell_pa(&s->rxq_descr[qidx].comp_ring); - pci_dma_read(PCI_DEVICE(s), - daddr, &rxcd, sizeof(struct Vmxnet3_RxCompDesc)); + cpu_physical_memory_read(daddr, &rxcd, sizeof(struct Vmxnet3_RxCompDesc)); ring_gen = vmxnet3_ring_curr_gen(&s->rxq_descr[qidx].comp_ring); if (rxcd.gen != ring_gen) { @@ -934,7 +928,7 @@ vmxnet3_get_next_rx_descr(VMXNET3State *s, bool is_head, * in the case the host OS performs forwarding, it will forward an * incorrectly checksummed packet. */ -static void vmxnet3_rx_need_csum_calculate(struct NetRxPkt *pkt, +static void vmxnet3_rx_need_csum_calculate(struct VmxnetRxPkt *pkt, const void *pkt_data, size_t pkt_len) { @@ -943,16 +937,16 @@ static void vmxnet3_rx_need_csum_calculate(struct NetRxPkt *pkt, uint8_t *data; int len; - if (!net_rx_pkt_has_virt_hdr(pkt)) { + if (!vmxnet_rx_pkt_has_virt_hdr(pkt)) { return; } - vhdr = net_rx_pkt_get_vhdr(pkt); + vhdr = vmxnet_rx_pkt_get_vhdr(pkt); if (!VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_NEEDS_CSUM)) { return; } - net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); + vmxnet_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); if (!(isip4 || isip6) || !(istcp || isudp)) { return; } @@ -976,7 +970,7 @@ static void vmxnet3_rx_need_csum_calculate(struct NetRxPkt *pkt, vhdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID; } -static void vmxnet3_rx_update_descr(struct NetRxPkt *pkt, +static void vmxnet3_rx_update_descr(struct VmxnetRxPkt *pkt, struct Vmxnet3_RxCompDesc *rxcd) { int csum_ok, is_gso; @@ -984,16 +978,16 @@ static void vmxnet3_rx_update_descr(struct NetRxPkt *pkt, struct virtio_net_hdr *vhdr; uint8_t offload_type; - if (net_rx_pkt_is_vlan_stripped(pkt)) { + if (vmxnet_rx_pkt_is_vlan_stripped(pkt)) { rxcd->ts = 1; - rxcd->tci = net_rx_pkt_get_vlan_tag(pkt); + rxcd->tci = vmxnet_rx_pkt_get_vlan_tag(pkt); } - if (!net_rx_pkt_has_virt_hdr(pkt)) { + if (!vmxnet_rx_pkt_has_virt_hdr(pkt)) { goto nocsum; } - vhdr = net_rx_pkt_get_vhdr(pkt); + vhdr = vmxnet_rx_pkt_get_vhdr(pkt); /* * Checksum is valid when lower level tell so or when lower level * requires checksum offload telling that packet produced/bridged @@ -1010,7 +1004,7 @@ static void vmxnet3_rx_update_descr(struct NetRxPkt *pkt, goto nocsum; } - net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); + vmxnet_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp); if ((!istcp && !isudp) || (!isip4 && !isip6)) { goto nocsum; } @@ -1029,11 +1023,10 @@ nocsum: } static void -vmxnet3_pci_dma_writev(PCIDevice *pci_dev, - const struct iovec *iov, - size_t start_iov_off, - hwaddr target_addr, - size_t bytes_to_copy) +vmxnet3_physical_memory_writev(const struct iovec *iov, + size_t start_iov_off, + hwaddr target_addr, + size_t bytes_to_copy) { size_t curr_off = 0; size_t copied = 0; @@ -1043,9 +1036,9 @@ vmxnet3_pci_dma_writev(PCIDevice *pci_dev, size_t chunk_len = MIN((curr_off + iov->iov_len) - start_iov_off, bytes_to_copy); - pci_dma_write(pci_dev, target_addr + copied, - iov->iov_base + start_iov_off - curr_off, - chunk_len); + cpu_physical_memory_write(target_addr + copied, + iov->iov_base + start_iov_off - curr_off, + chunk_len); copied += chunk_len; start_iov_off += chunk_len; @@ -1062,7 +1055,6 @@ static bool vmxnet3_indicate_packet(VMXNET3State *s) { struct Vmxnet3_RxDesc rxd; - PCIDevice *d = PCI_DEVICE(s); bool is_head = true; uint32_t rxd_idx; uint32_t rx_ridx = 0; @@ -1071,13 +1063,13 @@ vmxnet3_indicate_packet(VMXNET3State *s) uint32_t new_rxcd_gen = VMXNET3_INIT_GEN; hwaddr new_rxcd_pa = 0; hwaddr ready_rxcd_pa = 0; - struct iovec *data = net_rx_pkt_get_iovec(s->rx_pkt); + struct iovec *data = vmxnet_rx_pkt_get_iovec(s->rx_pkt); size_t bytes_copied = 0; - size_t bytes_left = net_rx_pkt_get_total_len(s->rx_pkt); + size_t bytes_left = vmxnet_rx_pkt_get_total_len(s->rx_pkt); uint16_t num_frags = 0; size_t chunk_size; - net_rx_pkt_dump(s->rx_pkt); + vmxnet_rx_pkt_dump(s->rx_pkt); while (bytes_left > 0) { @@ -1096,15 +1088,15 @@ vmxnet3_indicate_packet(VMXNET3State *s) } chunk_size = MIN(bytes_left, rxd.len); - vmxnet3_pci_dma_writev(d, data, bytes_copied, - le64_to_cpu(rxd.addr), chunk_size); + vmxnet3_physical_memory_writev(data, bytes_copied, + le64_to_cpu(rxd.addr), chunk_size); bytes_copied += chunk_size; bytes_left -= chunk_size; vmxnet3_dump_rx_descr(&rxd); if (ready_rxcd_pa != 0) { - pci_dma_write(d, ready_rxcd_pa, &rxcd, sizeof(rxcd)); + cpu_physical_memory_write(ready_rxcd_pa, &rxcd, sizeof(rxcd)); } memset(&rxcd, 0, sizeof(struct Vmxnet3_RxCompDesc)); @@ -1135,8 +1127,7 @@ vmxnet3_indicate_packet(VMXNET3State *s) if (ready_rxcd_pa != 0) { rxcd.eop = 1; rxcd.err = (bytes_left != 0); - - pci_dma_write(d, ready_rxcd_pa, &rxcd, sizeof(rxcd)); + cpu_physical_memory_write(ready_rxcd_pa, &rxcd, sizeof(rxcd)); /* Flush RX descriptor changes */ smp_wmb(); @@ -1167,10 +1158,6 @@ vmxnet3_io_bar0_write(void *opaque, hwaddr addr, { VMXNET3State *s = opaque; - if (!s->device_active) { - return; - } - if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_TXPROD, VMXNET3_DEVICE_MAX_TX_QUEUES, VMXNET3_REG_ALIGN)) { int tx_queue_idx = @@ -1232,16 +1219,16 @@ static void vmxnet3_reset_interrupt_states(VMXNET3State *s) static void vmxnet3_reset_mac(VMXNET3State *s) { memcpy(&s->conf.macaddr.a, &s->perm_mac.a, sizeof(s->perm_mac.a)); - VMW_CFPRN("MAC address set to: " MAC_FMT, MAC_ARG(s->conf.macaddr.a)); + VMW_CFPRN("MAC address set to: " VMXNET_MF, VMXNET_MA(s->conf.macaddr.a)); } static void vmxnet3_deactivate_device(VMXNET3State *s) { if (s->device_active) { VMW_CBPRN("Deactivating vmxnet3..."); - net_tx_pkt_reset(s->tx_pkt); - net_tx_pkt_uninit(s->tx_pkt); - net_rx_pkt_uninit(s->rx_pkt); + vmxnet_tx_pkt_reset(s->tx_pkt); + vmxnet_tx_pkt_uninit(s->tx_pkt); + vmxnet_rx_pkt_uninit(s->rx_pkt); s->device_active = false; } } @@ -1259,9 +1246,7 @@ static void vmxnet3_reset(VMXNET3State *s) static void vmxnet3_update_rx_mode(VMXNET3State *s) { - PCIDevice *d = PCI_DEVICE(s); - - s->rx_mode = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, + s->rx_mode = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.rxFilterConf.rxMode); VMW_CFPRN("RX mode: 0x%08X", s->rx_mode); } @@ -1269,10 +1254,9 @@ static void vmxnet3_update_rx_mode(VMXNET3State *s) static void vmxnet3_update_vlan_filters(VMXNET3State *s) { int i; - PCIDevice *d = PCI_DEVICE(s); /* Copy configuration from shared memory */ - VMXNET3_READ_DRV_SHARED(d, s->drv_shmem, + VMXNET3_READ_DRV_SHARED(s->drv_shmem, devRead.rxFilterConf.vfTable, s->vlan_table, sizeof(s->vlan_table)); @@ -1293,10 +1277,8 @@ static void vmxnet3_update_vlan_filters(VMXNET3State *s) static void vmxnet3_update_mcast_filters(VMXNET3State *s) { - PCIDevice *d = PCI_DEVICE(s); - uint16_t list_bytes = - VMXNET3_READ_DRV_SHARED16(d, s->drv_shmem, + VMXNET3_READ_DRV_SHARED16(s->drv_shmem, devRead.rxFilterConf.mfTableLen); s->mcast_list_len = list_bytes / sizeof(s->mcast_list[0]); @@ -1313,14 +1295,13 @@ static void vmxnet3_update_mcast_filters(VMXNET3State *s) } else { int i; hwaddr mcast_list_pa = - VMXNET3_READ_DRV_SHARED64(d, s->drv_shmem, + VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.rxFilterConf.mfTablePA); - pci_dma_read(d, mcast_list_pa, s->mcast_list, list_bytes); - + cpu_physical_memory_read(mcast_list_pa, s->mcast_list, list_bytes); VMW_CFPRN("Current multicast list len is %d:", s->mcast_list_len); for (i = 0; i < s->mcast_list_len; i++) { - VMW_CFPRN("\t" MAC_FMT, MAC_ARG(s->mcast_list[i].a)); + VMW_CFPRN("\t" VMXNET_MF, VMXNET_MA(s->mcast_list[i].a)); } } } @@ -1342,32 +1323,28 @@ static uint32_t vmxnet3_get_interrupt_config(VMXNET3State *s) static void vmxnet3_fill_stats(VMXNET3State *s) { int i; - PCIDevice *d = PCI_DEVICE(s); if (!s->device_active) return; for (i = 0; i < s->txq_num; i++) { - pci_dma_write(d, - s->txq_descr[i].tx_stats_pa, - &s->txq_descr[i].txq_stats, - sizeof(s->txq_descr[i].txq_stats)); + cpu_physical_memory_write(s->txq_descr[i].tx_stats_pa, + &s->txq_descr[i].txq_stats, + sizeof(s->txq_descr[i].txq_stats)); } for (i = 0; i < s->rxq_num; i++) { - pci_dma_write(d, - s->rxq_descr[i].rx_stats_pa, - &s->rxq_descr[i].rxq_stats, - sizeof(s->rxq_descr[i].rxq_stats)); + cpu_physical_memory_write(s->rxq_descr[i].rx_stats_pa, + &s->rxq_descr[i].rxq_stats, + sizeof(s->rxq_descr[i].rxq_stats)); } } static void vmxnet3_adjust_by_guest_type(VMXNET3State *s) { struct Vmxnet3_GOSInfo gos; - PCIDevice *d = PCI_DEVICE(s); - VMXNET3_READ_DRV_SHARED(d, s->drv_shmem, devRead.misc.driverInfo.gos, + VMXNET3_READ_DRV_SHARED(s->drv_shmem, devRead.misc.driverInfo.gos, &gos, sizeof(gos)); s->rx_packets_compound = (gos.gosType == VMXNET3_GOS_TYPE_WIN) ? false : true; @@ -1387,14 +1364,13 @@ vmxnet3_dump_conf_descr(const char *name, static void vmxnet3_update_pm_state(VMXNET3State *s) { struct Vmxnet3_VariableLenConfDesc pm_descr; - PCIDevice *d = PCI_DEVICE(s); pm_descr.confLen = - VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.pmConfDesc.confLen); + VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.pmConfDesc.confLen); pm_descr.confVer = - VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.pmConfDesc.confVer); + VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.pmConfDesc.confVer); pm_descr.confPA = - VMXNET3_READ_DRV_SHARED64(d, s->drv_shmem, devRead.pmConfDesc.confPA); + VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.pmConfDesc.confPA); vmxnet3_dump_conf_descr("PM State", &pm_descr); } @@ -1403,9 +1379,8 @@ static void vmxnet3_update_features(VMXNET3State *s) { uint32_t guest_features; int rxcso_supported; - PCIDevice *d = PCI_DEVICE(s); - guest_features = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, + guest_features = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.misc.uptFeatures); rxcso_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXCSUM); @@ -1427,8 +1402,8 @@ static void vmxnet3_update_features(VMXNET3State *s) static bool vmxnet3_verify_intx(VMXNET3State *s, int intx) { - return s->msix_used || msi_enabled(PCI_DEVICE(s)) - || intx == pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1; + return s->msix_used || s->msi_used || (intx == + (pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1)); } static void vmxnet3_validate_interrupt_idx(bool is_msix, int idx) @@ -1480,13 +1455,12 @@ static void vmxnet3_activate_device(VMXNET3State *s) { int i; static const uint32_t VMXNET3_DEF_TX_THRESHOLD = 1; - PCIDevice *d = PCI_DEVICE(s); hwaddr qdescr_table_pa; uint64_t pa; uint32_t size; /* Verify configuration consistency */ - if (!vmxnet3_verify_driver_magic(d, s->drv_shmem)) { + if (!vmxnet3_verify_driver_magic(s->drv_shmem)) { VMW_ERPRN("Device configuration received from driver is invalid"); return; } @@ -1502,11 +1476,11 @@ static void vmxnet3_activate_device(VMXNET3State *s) vmxnet3_update_pm_state(s); vmxnet3_setup_rx_filtering(s); /* Cache fields from shared memory */ - s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu); + s->mtu = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.misc.mtu); VMW_CFPRN("MTU is %u", s->mtu); s->max_rx_frags = - VMXNET3_READ_DRV_SHARED16(d, s->drv_shmem, devRead.misc.maxNumRxSG); + VMXNET3_READ_DRV_SHARED16(s->drv_shmem, devRead.misc.maxNumRxSG); if (s->max_rx_frags == 0) { s->max_rx_frags = 1; @@ -1515,24 +1489,24 @@ static void vmxnet3_activate_device(VMXNET3State *s) VMW_CFPRN("Max RX fragments is %u", s->max_rx_frags); s->event_int_idx = - VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.intrConf.eventIntrIdx); + VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.intrConf.eventIntrIdx); assert(vmxnet3_verify_intx(s, s->event_int_idx)); VMW_CFPRN("Events interrupt line is %u", s->event_int_idx); s->auto_int_masking = - VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.intrConf.autoMask); + VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.intrConf.autoMask); VMW_CFPRN("Automatic interrupt masking is %d", (int)s->auto_int_masking); s->txq_num = - VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.misc.numTxQueues); + VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numTxQueues); s->rxq_num = - VMXNET3_READ_DRV_SHARED8(d, s->drv_shmem, devRead.misc.numRxQueues); + VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numRxQueues); VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num); vmxnet3_validate_queues(s); qdescr_table_pa = - VMXNET3_READ_DRV_SHARED64(d, s->drv_shmem, devRead.misc.queueDescPA); + VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.misc.queueDescPA); VMW_CFPRN("TX queues descriptors table is at 0x%" PRIx64, qdescr_table_pa); /* @@ -1548,25 +1522,25 @@ static void vmxnet3_activate_device(VMXNET3State *s) /* Read interrupt number for this TX queue */ s->txq_descr[i].intr_idx = - VMXNET3_READ_TX_QUEUE_DESCR8(d, qdescr_pa, conf.intrIdx); + VMXNET3_READ_TX_QUEUE_DESCR8(qdescr_pa, conf.intrIdx); assert(vmxnet3_verify_intx(s, s->txq_descr[i].intr_idx)); VMW_CFPRN("TX Queue %d interrupt: %d", i, s->txq_descr[i].intr_idx); /* Read rings memory locations for TX queues */ - pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.txRingBasePA); - size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.txRingSize); + pa = VMXNET3_READ_TX_QUEUE_DESCR64(qdescr_pa, conf.txRingBasePA); + size = VMXNET3_READ_TX_QUEUE_DESCR32(qdescr_pa, conf.txRingSize); - vmxnet3_ring_init(d, &s->txq_descr[i].tx_ring, pa, size, + vmxnet3_ring_init(&s->txq_descr[i].tx_ring, pa, size, sizeof(struct Vmxnet3_TxDesc), false); VMXNET3_RING_DUMP(VMW_CFPRN, "TX", i, &s->txq_descr[i].tx_ring); s->max_tx_frags += size; /* TXC ring */ - pa = VMXNET3_READ_TX_QUEUE_DESCR64(d, qdescr_pa, conf.compRingBasePA); - size = VMXNET3_READ_TX_QUEUE_DESCR32(d, qdescr_pa, conf.compRingSize); - vmxnet3_ring_init(d, &s->txq_descr[i].comp_ring, pa, size, + pa = VMXNET3_READ_TX_QUEUE_DESCR64(qdescr_pa, conf.compRingBasePA); + size = VMXNET3_READ_TX_QUEUE_DESCR32(qdescr_pa, conf.compRingSize); + vmxnet3_ring_init(&s->txq_descr[i].comp_ring, pa, size, sizeof(struct Vmxnet3_TxCompDesc), true); VMXNET3_RING_DUMP(VMW_CFPRN, "TXC", i, &s->txq_descr[i].comp_ring); @@ -1577,16 +1551,15 @@ static void vmxnet3_activate_device(VMXNET3State *s) sizeof(s->txq_descr[i].txq_stats)); /* Fill device-managed parameters for queues */ - VMXNET3_WRITE_TX_QUEUE_DESCR32(d, qdescr_pa, + VMXNET3_WRITE_TX_QUEUE_DESCR32(qdescr_pa, ctrl.txThreshold, VMXNET3_DEF_TX_THRESHOLD); } /* Preallocate TX packet wrapper */ VMW_CFPRN("Max TX fragments is %u", s->max_tx_frags); - net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), - s->max_tx_frags, s->peer_has_vhdr); - net_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr); + vmxnet_tx_pkt_init(&s->tx_pkt, s->max_tx_frags, s->peer_has_vhdr); + vmxnet_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr); /* Read rings memory locations for RX queues */ for (i = 0; i < s->rxq_num; i++) { @@ -1597,7 +1570,7 @@ static void vmxnet3_activate_device(VMXNET3State *s) /* Read interrupt number for this RX queue */ s->rxq_descr[i].intr_idx = - VMXNET3_READ_TX_QUEUE_DESCR8(d, qd_pa, conf.intrIdx); + VMXNET3_READ_TX_QUEUE_DESCR8(qd_pa, conf.intrIdx); assert(vmxnet3_verify_intx(s, s->rxq_descr[i].intr_idx)); VMW_CFPRN("RX Queue %d interrupt: %d", i, s->rxq_descr[i].intr_idx); @@ -1605,18 +1578,18 @@ static void vmxnet3_activate_device(VMXNET3State *s) /* Read rings memory locations */ for (j = 0; j < VMXNET3_RX_RINGS_PER_QUEUE; j++) { /* RX rings */ - pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.rxRingBasePA[j]); - size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.rxRingSize[j]); - vmxnet3_ring_init(d, &s->rxq_descr[i].rx_ring[j], pa, size, + pa = VMXNET3_READ_RX_QUEUE_DESCR64(qd_pa, conf.rxRingBasePA[j]); + size = VMXNET3_READ_RX_QUEUE_DESCR32(qd_pa, conf.rxRingSize[j]); + vmxnet3_ring_init(&s->rxq_descr[i].rx_ring[j], pa, size, sizeof(struct Vmxnet3_RxDesc), false); VMW_CFPRN("RX queue %d:%d: Base: %" PRIx64 ", Size: %d", i, j, pa, size); } /* RXC ring */ - pa = VMXNET3_READ_RX_QUEUE_DESCR64(d, qd_pa, conf.compRingBasePA); - size = VMXNET3_READ_RX_QUEUE_DESCR32(d, qd_pa, conf.compRingSize); - vmxnet3_ring_init(d, &s->rxq_descr[i].comp_ring, pa, size, + pa = VMXNET3_READ_RX_QUEUE_DESCR64(qd_pa, conf.compRingBasePA); + size = VMXNET3_READ_RX_QUEUE_DESCR32(qd_pa, conf.compRingSize); + vmxnet3_ring_init(&s->rxq_descr[i].comp_ring, pa, size, sizeof(struct Vmxnet3_RxCompDesc), true); VMW_CFPRN("RXC queue %d: Base: %" PRIx64 ", Size: %d", i, pa, size); @@ -1783,21 +1756,19 @@ static uint64_t vmxnet3_get_command_status(VMXNET3State *s) static void vmxnet3_set_events(VMXNET3State *s, uint32_t val) { uint32_t events; - PCIDevice *d = PCI_DEVICE(s); VMW_CBPRN("Setting events: 0x%x", val); - events = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, ecr) | val; - VMXNET3_WRITE_DRV_SHARED32(d, s->drv_shmem, ecr, events); + events = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, ecr) | val; + VMXNET3_WRITE_DRV_SHARED32(s->drv_shmem, ecr, events); } static void vmxnet3_ack_events(VMXNET3State *s, uint32_t val) { - PCIDevice *d = PCI_DEVICE(s); uint32_t events; VMW_CBPRN("Clearing events: 0x%x", val); - events = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, ecr) & ~val; - VMXNET3_WRITE_DRV_SHARED32(d, s->drv_shmem, ecr, events); + events = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, ecr) & ~val; + VMXNET3_WRITE_DRV_SHARED32(s->drv_shmem, ecr, events); } static void @@ -1994,7 +1965,7 @@ vmxnet3_rx_filter_may_indicate(VMXNET3State *s, const void *data, return false; } - switch (net_rx_pkt_get_packet_type(s->rx_pkt)) { + switch (vmxnet_rx_pkt_get_packet_type(s->rx_pkt)) { case ETH_PKT_UCAST: if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_UCAST)) { return false; @@ -2042,7 +2013,7 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size) } if (s->peer_has_vhdr) { - net_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf); + vmxnet_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf); buf += sizeof(struct virtio_net_hdr); size -= sizeof(struct virtio_net_hdr); } @@ -2055,13 +2026,13 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size) size = sizeof(min_buf); } - net_rx_pkt_set_packet_type(s->rx_pkt, + vmxnet_rx_pkt_set_packet_type(s->rx_pkt, get_eth_packet_type(PKT_GET_ETH_HDR(buf))); if (vmxnet3_rx_filter_may_indicate(s, buf, size)) { - net_rx_pkt_set_protocols(s->rx_pkt, buf, size); + vmxnet_rx_pkt_set_protocols(s->rx_pkt, buf, size); vmxnet3_rx_need_csum_calculate(s->rx_pkt, buf, size); - net_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping); + vmxnet_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping); bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1; if (bytes_indicated < size) { VMW_PKPRN("RX: %zu of %zu bytes indicated", bytes_indicated, size); @@ -2091,7 +2062,7 @@ static void vmxnet3_set_link_status(NetClientState *nc) } static NetClientInfo net_vmxnet3_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = vmxnet3_receive, .link_status_changed = vmxnet3_set_link_status, @@ -2131,7 +2102,7 @@ static void vmxnet3_net_init(VMXNET3State *s) s->link_status_and_speed = VMXNET3_LINK_SPEED | VMXNET3_LINK_STATUS_UP; - VMW_CFPRN("Permanent MAC: " MAC_FMT, MAC_ARG(s->perm_mac.a)); + VMW_CFPRN("Permanent MAC: " VMXNET_MF, VMXNET_MA(s->perm_mac.a)); s->nic = qemu_new_nic(&net_vmxnet3_info, &s->conf, object_get_typename(OBJECT(s)), @@ -2218,12 +2189,35 @@ vmxnet3_cleanup_msix(VMXNET3State *s) } } +#define VMXNET3_USE_64BIT (true) +#define VMXNET3_PER_VECTOR_MASK (false) + +static bool +vmxnet3_init_msi(VMXNET3State *s) +{ + PCIDevice *d = PCI_DEVICE(s); + int res; + + res = msi_init(d, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS, + VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK); + if (0 > res) { + VMW_WRPRN("Failed to initialize MSI, error %d", res); + s->msi_used = false; + } else { + s->msi_used = true; + } + + return s->msi_used; +} + static void vmxnet3_cleanup_msi(VMXNET3State *s) { PCIDevice *d = PCI_DEVICE(s); - msi_uninit(d); + if (s->msi_used) { + msi_uninit(d); + } } static void @@ -2261,9 +2255,9 @@ static const MemoryRegionOps b1_ops = { }, }; -static uint64_t vmxnet3_device_serial_num(VMXNET3State *s) +static uint8_t *vmxnet3_device_serial_num(VMXNET3State *s) { - uint64_t dsn_payload; + static uint64_t dsn_payload; uint8_t *dsnp = (uint8_t *)&dsn_payload; dsnp[0] = 0xfe; @@ -2274,18 +2268,13 @@ static uint64_t vmxnet3_device_serial_num(VMXNET3State *s) dsnp[5] = s->conf.macaddr.a[1]; dsnp[6] = s->conf.macaddr.a[2]; dsnp[7] = 0xff; - return dsn_payload; + return dsnp; } - -#define VMXNET3_USE_64BIT (true) -#define VMXNET3_PER_VECTOR_MASK (false) - static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) { DeviceState *dev = DEVICE(pci_dev); VMXNET3State *s = VMXNET3(pci_dev); - int ret; VMW_CBPRN("Starting init..."); @@ -2309,16 +2298,14 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) /* Interrupt pin A */ pci_dev->config[PCI_INTERRUPT_PIN] = 0x01; - ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS, - VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK, NULL); - /* Any error other than -ENOTSUP(board's MSI support is broken) - * is a programming error. Fall back to INTx silently on -ENOTSUP */ - assert(!ret || ret == -ENOTSUP); - if (!vmxnet3_init_msix(s)) { VMW_WRPRN("Failed to initialize MSI-X, configuration is inconsistent."); } + if (!vmxnet3_init_msi(s)) { + VMW_WRPRN("Failed to initialize MSI, configuration is inconsistent."); + } + vmxnet3_net_init(s); if (pci_is_express(pci_dev)) { @@ -2326,8 +2313,10 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) pcie_endpoint_cap_init(pci_dev, VMXNET3_EXP_EP_OFFSET); } - pcie_dev_ser_num_init(pci_dev, VMXNET3_DSN_OFFSET, - vmxnet3_device_serial_num(s)); + pcie_add_capability(pci_dev, PCI_EXT_CAP_ID_DSN, 0x1, + VMXNET3_DSN_OFFSET, PCI_EXT_CAP_DSN_SIZEOF); + memcpy(pci_dev->config + VMXNET3_DSN_OFFSET + 4, + vmxnet3_device_serial_num(s), sizeof(uint64_t)); } register_savevm(dev, "vmxnet3-msix", -1, 1, @@ -2549,9 +2538,8 @@ static int vmxnet3_post_load(void *opaque, int version_id) VMXNET3State *s = opaque; PCIDevice *d = PCI_DEVICE(s); - net_tx_pkt_init(&s->tx_pkt, PCI_DEVICE(s), - s->max_tx_frags, s->peer_has_vhdr); - net_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr); + vmxnet_tx_pkt_init(&s->tx_pkt, s->max_tx_frags, s->peer_has_vhdr); + vmxnet_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr); if (s->msix_used) { if (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) { @@ -2705,7 +2693,6 @@ static void vmxnet3_class_init(ObjectClass *class, void *data) c->vendor_id = PCI_VENDOR_ID_VMWARE; c->device_id = PCI_DEVICE_ID_VMWARE_VMXNET3; c->revision = PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION; - c->romfile = "efi-vmxnet3.rom"; c->class_id = PCI_CLASS_NETWORK_ETHERNET; c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE; c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3; diff --git a/hw/net/vmxnet3.h b/hw/net/vmxnet3.h index f9352c4a2..f7006afe9 100644 --- a/hw/net/vmxnet3.h +++ b/hw/net/vmxnet3.h @@ -15,8 +15,8 @@ * */ -#ifndef QEMU_VMXNET3_H -#define QEMU_VMXNET3_H +#ifndef _QEMU_VMXNET3_H +#define _QEMU_VMXNET3_H #define VMXNET3_DEVICE_MAX_TX_QUEUES 8 #define VMXNET3_DEVICE_MAX_RX_QUEUES 8 /* Keep this value as a power of 2 */ diff --git a/hw/net/vmxnet_debug.h b/hw/net/vmxnet_debug.h index cb50aa95d..96495dbb1 100644 --- a/hw/net/vmxnet_debug.h +++ b/hw/net/vmxnet_debug.h @@ -15,8 +15,8 @@ * */ -#ifndef QEMU_VMXNET_DEBUG_H -#define QEMU_VMXNET_DEBUG_H +#ifndef _QEMU_VMXNET_DEBUG_H +#define _QEMU_VMXNET_DEBUG_H #define VMXNET_DEVICE_NAME "vmxnet3" @@ -142,4 +142,7 @@ } \ } while (0) -#endif /* QEMU_VMXNET_DEBUG_H */ +#define VMXNET_MF "%02X:%02X:%02X:%02X:%02X:%02X" +#define VMXNET_MA(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] + +#endif /* _QEMU_VMXNET3_DEBUG_H */ diff --git a/hw/net/vmxnet_rx_pkt.c b/hw/net/vmxnet_rx_pkt.c new file mode 100644 index 000000000..21bb46e68 --- /dev/null +++ b/hw/net/vmxnet_rx_pkt.c @@ -0,0 +1,187 @@ +/* + * QEMU VMWARE VMXNET* paravirtual NICs - RX packets abstractions + * + * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) + * + * Developed by Daynix Computing LTD (http://www.daynix.com) + * + * Authors: + * Dmitry Fleytman <dmitry@daynix.com> + * Tamir Shomer <tamirs@daynix.com> + * Yan Vugenfirer <yan@daynix.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 "vmxnet_rx_pkt.h" +#include "net/eth.h" +#include "qemu-common.h" +#include "qemu/iov.h" +#include "net/checksum.h" +#include "net/tap.h" + +/* + * RX packet may contain up to 2 fragments - rebuilt eth header + * in case of VLAN tag stripping + * and payload received from QEMU - in any case + */ +#define VMXNET_MAX_RX_PACKET_FRAGMENTS (2) + +struct VmxnetRxPkt { + struct virtio_net_hdr virt_hdr; + uint8_t ehdr_buf[ETH_MAX_L2_HDR_LEN]; + struct iovec vec[VMXNET_MAX_RX_PACKET_FRAGMENTS]; + uint16_t vec_len; + uint32_t tot_len; + uint16_t tci; + bool vlan_stripped; + bool has_virt_hdr; + eth_pkt_types_e packet_type; + + /* Analysis results */ + bool isip4; + bool isip6; + bool isudp; + bool istcp; +}; + +void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr) +{ + struct VmxnetRxPkt *p = g_malloc0(sizeof *p); + p->has_virt_hdr = has_virt_hdr; + *pkt = p; +} + +void vmxnet_rx_pkt_uninit(struct VmxnetRxPkt *pkt) +{ + g_free(pkt); +} + +struct virtio_net_hdr *vmxnet_rx_pkt_get_vhdr(struct VmxnetRxPkt *pkt) +{ + assert(pkt); + return &pkt->virt_hdr; +} + +void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data, + size_t len, bool strip_vlan) +{ + uint16_t tci = 0; + uint16_t ploff; + assert(pkt); + pkt->vlan_stripped = false; + + if (strip_vlan) { + pkt->vlan_stripped = eth_strip_vlan(data, pkt->ehdr_buf, &ploff, &tci); + } + + if (pkt->vlan_stripped) { + pkt->vec[0].iov_base = pkt->ehdr_buf; + pkt->vec[0].iov_len = ploff - sizeof(struct vlan_header); + pkt->vec[1].iov_base = (uint8_t *) data + ploff; + pkt->vec[1].iov_len = len - ploff; + pkt->vec_len = 2; + pkt->tot_len = len - ploff + sizeof(struct eth_header); + } else { + pkt->vec[0].iov_base = (void *)data; + pkt->vec[0].iov_len = len; + pkt->vec_len = 1; + pkt->tot_len = len; + } + + pkt->tci = tci; +} + +void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt) +{ +#ifdef VMXNET_RX_PKT_DEBUG + VmxnetRxPkt *pkt = (VmxnetRxPkt *)pkt; + assert(pkt); + + printf("RX PKT: tot_len: %d, vlan_stripped: %d, vlan_tag: %d\n", + pkt->tot_len, pkt->vlan_stripped, pkt->tci); +#endif +} + +void vmxnet_rx_pkt_set_packet_type(struct VmxnetRxPkt *pkt, + eth_pkt_types_e packet_type) +{ + assert(pkt); + + pkt->packet_type = packet_type; + +} + +eth_pkt_types_e vmxnet_rx_pkt_get_packet_type(struct VmxnetRxPkt *pkt) +{ + assert(pkt); + + return pkt->packet_type; +} + +size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt) +{ + assert(pkt); + + return pkt->tot_len; +} + +void vmxnet_rx_pkt_set_protocols(struct VmxnetRxPkt *pkt, const void *data, + size_t len) +{ + assert(pkt); + + eth_get_protocols(data, len, &pkt->isip4, &pkt->isip6, + &pkt->isudp, &pkt->istcp); +} + +void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt, + bool *isip4, bool *isip6, + bool *isudp, bool *istcp) +{ + assert(pkt); + + *isip4 = pkt->isip4; + *isip6 = pkt->isip6; + *isudp = pkt->isudp; + *istcp = pkt->istcp; +} + +struct iovec *vmxnet_rx_pkt_get_iovec(struct VmxnetRxPkt *pkt) +{ + assert(pkt); + + return pkt->vec; +} + +void vmxnet_rx_pkt_set_vhdr(struct VmxnetRxPkt *pkt, + struct virtio_net_hdr *vhdr) +{ + assert(pkt); + + memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr); +} + +bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt) +{ + assert(pkt); + + return pkt->vlan_stripped; +} + +bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt) +{ + assert(pkt); + + return pkt->has_virt_hdr; +} + +uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt) +{ + assert(pkt); + + return pkt->tci; +} diff --git a/hw/net/vmxnet_rx_pkt.h b/hw/net/vmxnet_rx_pkt.h new file mode 100644 index 000000000..0a45c1ba0 --- /dev/null +++ b/hw/net/vmxnet_rx_pkt.h @@ -0,0 +1,174 @@ +/* + * QEMU VMWARE VMXNET* paravirtual NICs - RX packets abstraction + * + * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) + * + * Developed by Daynix Computing LTD (http://www.daynix.com) + * + * Authors: + * Dmitry Fleytman <dmitry@daynix.com> + * Tamir Shomer <tamirs@daynix.com> + * Yan Vugenfirer <yan@daynix.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 VMXNET_RX_PKT_H +#define VMXNET_RX_PKT_H + +#include "net/eth.h" + +/* defines to enable packet dump functions */ +/*#define VMXNET_RX_PKT_DEBUG*/ + +struct VmxnetRxPkt; + +/** + * Clean all rx packet resources + * + * @pkt: packet + * + */ +void vmxnet_rx_pkt_uninit(struct VmxnetRxPkt *pkt); + +/** + * Init function for rx packet functionality + * + * @pkt: packet pointer + * @has_virt_hdr: device uses virtio header + * + */ +void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr); + +/** + * returns total length of data attached to rx context + * + * @pkt: packet + * + * Return: nothing + * + */ +size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt); + +/** + * parse and set packet analysis results + * + * @pkt: packet + * @data: pointer to the data buffer to be parsed + * @len: data length + * + */ +void vmxnet_rx_pkt_set_protocols(struct VmxnetRxPkt *pkt, const void *data, + size_t len); + +/** + * fetches packet analysis results + * + * @pkt: packet + * @isip4: whether the packet given is IPv4 + * @isip6: whether the packet given is IPv6 + * @isudp: whether the packet given is UDP + * @istcp: whether the packet given is TCP + * + */ +void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt, + bool *isip4, bool *isip6, + bool *isudp, bool *istcp); + +/** + * returns virtio header stored in rx context + * + * @pkt: packet + * @ret: virtio header + * + */ +struct virtio_net_hdr *vmxnet_rx_pkt_get_vhdr(struct VmxnetRxPkt *pkt); + +/** + * returns packet type + * + * @pkt: packet + * @ret: packet type + * + */ +eth_pkt_types_e vmxnet_rx_pkt_get_packet_type(struct VmxnetRxPkt *pkt); + +/** + * returns vlan tag + * + * @pkt: packet + * @ret: VLAN tag + * + */ +uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt); + +/** + * tells whether vlan was stripped from the packet + * + * @pkt: packet + * @ret: VLAN stripped sign + * + */ +bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt); + +/** + * notifies caller if the packet has virtio header + * + * @pkt: packet + * @ret: true if packet has virtio header, false otherwize + * + */ +bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt); + +/** + * attach data to rx packet + * + * @pkt: packet + * @data: pointer to the data buffer + * @len: data length + * @strip_vlan: should the module strip vlan from data + * + */ +void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data, + size_t len, bool strip_vlan); + +/** + * returns io vector that holds the attached data + * + * @pkt: packet + * @ret: pointer to IOVec + * + */ +struct iovec *vmxnet_rx_pkt_get_iovec(struct VmxnetRxPkt *pkt); + +/** + * prints rx packet data if debug is enabled + * + * @pkt: packet + * + */ +void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt); + +/** + * copy passed vhdr data to packet context + * + * @pkt: packet + * @vhdr: VHDR buffer + * + */ +void vmxnet_rx_pkt_set_vhdr(struct VmxnetRxPkt *pkt, + struct virtio_net_hdr *vhdr); + +/** + * save packet type in packet context + * + * @pkt: packet + * @packet_type: the packet type + * + */ +void vmxnet_rx_pkt_set_packet_type(struct VmxnetRxPkt *pkt, + eth_pkt_types_e packet_type); + +#endif diff --git a/hw/net/net_tx_pkt.c b/hw/net/vmxnet_tx_pkt.c index 20b25496e..91e1e08fd 100644 --- a/hw/net/net_tx_pkt.c +++ b/hw/net/vmxnet_tx_pkt.c @@ -1,5 +1,5 @@ /* - * QEMU TX packets abstractions + * QEMU VMWARE VMXNET* paravirtual NICs - TX packets abstractions * * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) * @@ -16,24 +16,24 @@ */ #include "qemu/osdep.h" -#include "net_tx_pkt.h" +#include "hw/hw.h" +#include "vmxnet_tx_pkt.h" #include "net/eth.h" +#include "qemu-common.h" +#include "qemu/iov.h" #include "net/checksum.h" #include "net/tap.h" #include "net/net.h" -#include "hw/pci/pci.h" enum { - NET_TX_PKT_VHDR_FRAG = 0, - NET_TX_PKT_L2HDR_FRAG, - NET_TX_PKT_L3HDR_FRAG, - NET_TX_PKT_PL_START_FRAG + VMXNET_TX_PKT_VHDR_FRAG = 0, + VMXNET_TX_PKT_L2HDR_FRAG, + VMXNET_TX_PKT_L3HDR_FRAG, + VMXNET_TX_PKT_PL_START_FRAG }; /* TX packet private context */ -struct NetTxPkt { - PCIDevice *pci_dev; - +struct VmxnetTxPkt { struct virtio_net_hdr virt_hdr; bool has_virt_hdr; @@ -44,7 +44,6 @@ struct NetTxPkt { struct iovec *vec; uint8_t l2_hdr[ETH_MAX_L2_HDR_LEN]; - uint8_t l3_hdr[ETH_MAX_IP_DGRAM_LEN]; uint32_t payload_len; @@ -54,34 +53,32 @@ struct NetTxPkt { uint16_t hdr_len; eth_pkt_types_e packet_type; uint8_t l4proto; - - bool is_loopback; }; -void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev, - uint32_t max_frags, bool has_virt_hdr) +void vmxnet_tx_pkt_init(struct VmxnetTxPkt **pkt, uint32_t max_frags, + bool has_virt_hdr) { - struct NetTxPkt *p = g_malloc0(sizeof *p); - - p->pci_dev = pci_dev; + struct VmxnetTxPkt *p = g_malloc0(sizeof *p); - p->vec = g_new(struct iovec, max_frags + NET_TX_PKT_PL_START_FRAG); + p->vec = g_malloc((sizeof *p->vec) * + (max_frags + VMXNET_TX_PKT_PL_START_FRAG)); - p->raw = g_new(struct iovec, max_frags); + p->raw = g_malloc((sizeof *p->raw) * max_frags); p->max_payload_frags = max_frags; p->max_raw_frags = max_frags; p->has_virt_hdr = has_virt_hdr; - p->vec[NET_TX_PKT_VHDR_FRAG].iov_base = &p->virt_hdr; - p->vec[NET_TX_PKT_VHDR_FRAG].iov_len = + p->vec[VMXNET_TX_PKT_VHDR_FRAG].iov_base = &p->virt_hdr; + p->vec[VMXNET_TX_PKT_VHDR_FRAG].iov_len = p->has_virt_hdr ? sizeof p->virt_hdr : 0; - p->vec[NET_TX_PKT_L2HDR_FRAG].iov_base = &p->l2_hdr; - p->vec[NET_TX_PKT_L3HDR_FRAG].iov_base = &p->l3_hdr; + p->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base = &p->l2_hdr; + p->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base = NULL; + p->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len = 0; *pkt = p; } -void net_tx_pkt_uninit(struct NetTxPkt *pkt) +void vmxnet_tx_pkt_uninit(struct VmxnetTxPkt *pkt) { if (pkt) { g_free(pkt->vec); @@ -90,63 +87,49 @@ void net_tx_pkt_uninit(struct NetTxPkt *pkt) } } -void net_tx_pkt_update_ip_hdr_checksum(struct NetTxPkt *pkt) +void vmxnet_tx_pkt_update_ip_checksums(struct VmxnetTxPkt *pkt) { uint16_t csum; + uint32_t ph_raw_csum; assert(pkt); + uint8_t gso_type = pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN; struct ip_header *ip_hdr; - ip_hdr = pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base; - ip_hdr->ip_len = cpu_to_be16(pkt->payload_len + - pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len); - - ip_hdr->ip_sum = 0; - csum = net_raw_checksum((uint8_t *)ip_hdr, - pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len); - ip_hdr->ip_sum = cpu_to_be16(csum); -} + if (VIRTIO_NET_HDR_GSO_TCPV4 != gso_type && + VIRTIO_NET_HDR_GSO_UDP != gso_type) { + return; + } -void net_tx_pkt_update_ip_checksums(struct NetTxPkt *pkt) -{ - uint16_t csum; - uint32_t cntr, cso; - assert(pkt); - uint8_t gso_type = pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN; - void *ip_hdr = pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base; + ip_hdr = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base; - if (pkt->payload_len + pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len > + if (pkt->payload_len + pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len > ETH_MAX_IP_DGRAM_LEN) { return; } - if (gso_type == VIRTIO_NET_HDR_GSO_TCPV4 || - gso_type == VIRTIO_NET_HDR_GSO_UDP) { - /* Calculate IP header checksum */ - net_tx_pkt_update_ip_hdr_checksum(pkt); - - /* Calculate IP pseudo header checksum */ - cntr = eth_calc_ip4_pseudo_hdr_csum(ip_hdr, pkt->payload_len, &cso); - csum = cpu_to_be16(~net_checksum_finish(cntr)); - } else if (gso_type == VIRTIO_NET_HDR_GSO_TCPV6) { - /* Calculate IP pseudo header checksum */ - cntr = eth_calc_ip6_pseudo_hdr_csum(ip_hdr, pkt->payload_len, - IP_PROTO_TCP, &cso); - csum = cpu_to_be16(~net_checksum_finish(cntr)); - } else { - return; - } + ip_hdr->ip_len = cpu_to_be16(pkt->payload_len + + pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len); - iov_from_buf(&pkt->vec[NET_TX_PKT_PL_START_FRAG], pkt->payload_frags, + /* Calculate IP header checksum */ + ip_hdr->ip_sum = 0; + csum = net_raw_checksum((uint8_t *)ip_hdr, + pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len); + ip_hdr->ip_sum = cpu_to_be16(csum); + + /* Calculate IP pseudo header checksum */ + ph_raw_csum = eth_calc_pseudo_hdr_csum(ip_hdr, pkt->payload_len); + csum = cpu_to_be16(~net_checksum_finish(ph_raw_csum)); + iov_from_buf(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG], pkt->payload_frags, pkt->virt_hdr.csum_offset, &csum, sizeof(csum)); } -static void net_tx_pkt_calculate_hdr_len(struct NetTxPkt *pkt) +static void vmxnet_tx_pkt_calculate_hdr_len(struct VmxnetTxPkt *pkt) { - pkt->hdr_len = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len + - pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len; + pkt->hdr_len = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len + + pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len; } -static bool net_tx_pkt_parse_headers(struct NetTxPkt *pkt) +static bool vmxnet_tx_pkt_parse_headers(struct VmxnetTxPkt *pkt) { struct iovec *l2_hdr, *l3_hdr; size_t bytes_read; @@ -155,8 +138,8 @@ static bool net_tx_pkt_parse_headers(struct NetTxPkt *pkt) assert(pkt); - l2_hdr = &pkt->vec[NET_TX_PKT_L2HDR_FRAG]; - l3_hdr = &pkt->vec[NET_TX_PKT_L3HDR_FRAG]; + l2_hdr = &pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG]; + l3_hdr = &pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG]; bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, 0, l2_hdr->iov_base, ETH_MAX_L2_HDR_LEN); @@ -177,19 +160,15 @@ static bool net_tx_pkt_parse_headers(struct NetTxPkt *pkt) if (bytes_read < l2_hdr->iov_len) { l2_hdr->iov_len = 0; - l3_hdr->iov_len = 0; - pkt->packet_type = ETH_PKT_UCAST; return false; - } else { - l2_hdr->iov_len = ETH_MAX_L2_HDR_LEN; - l2_hdr->iov_len = eth_get_l2_hdr_length(l2_hdr->iov_base); - pkt->packet_type = get_eth_packet_type(l2_hdr->iov_base); } - l3_proto = eth_get_l3_proto(l2_hdr, 1, l2_hdr->iov_len); + l3_proto = eth_get_l3_proto(l2_hdr->iov_base, l2_hdr->iov_len); switch (l3_proto) { case ETH_P_IP: + l3_hdr->iov_base = g_malloc(ETH_MAX_IP4_HDR_LEN); + bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len, l3_hdr->iov_base, sizeof(struct ip_header)); @@ -199,45 +178,27 @@ static bool net_tx_pkt_parse_headers(struct NetTxPkt *pkt) } l3_hdr->iov_len = IP_HDR_GET_LEN(l3_hdr->iov_base); + pkt->l4proto = ((struct ip_header *) l3_hdr->iov_base)->ip_p; - if (l3_hdr->iov_len < sizeof(struct ip_header)) { + /* copy optional IPv4 header data */ + bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, + l2_hdr->iov_len + sizeof(struct ip_header), + l3_hdr->iov_base + sizeof(struct ip_header), + l3_hdr->iov_len - sizeof(struct ip_header)); + if (bytes_read < l3_hdr->iov_len - sizeof(struct ip_header)) { l3_hdr->iov_len = 0; return false; } - - pkt->l4proto = ((struct ip_header *) l3_hdr->iov_base)->ip_p; - - if (IP_HDR_GET_LEN(l3_hdr->iov_base) != sizeof(struct ip_header)) { - /* copy optional IPv4 header data if any*/ - bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, - l2_hdr->iov_len + sizeof(struct ip_header), - l3_hdr->iov_base + sizeof(struct ip_header), - l3_hdr->iov_len - sizeof(struct ip_header)); - if (bytes_read < l3_hdr->iov_len - sizeof(struct ip_header)) { - l3_hdr->iov_len = 0; - return false; - } - } - break; case ETH_P_IPV6: - { - eth_ip6_hdr_info hdrinfo; - if (!eth_parse_ipv6_hdr(pkt->raw, pkt->raw_frags, l2_hdr->iov_len, - &hdrinfo)) { + &pkt->l4proto, &full_ip6hdr_len)) { l3_hdr->iov_len = 0; return false; } - pkt->l4proto = hdrinfo.l4proto; - full_ip6hdr_len = hdrinfo.full_hdr_len; - - if (full_ip6hdr_len > ETH_MAX_IP_DGRAM_LEN) { - l3_hdr->iov_len = 0; - return false; - } + l3_hdr->iov_base = g_malloc(full_ip6hdr_len); bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len, l3_hdr->iov_base, full_ip6hdr_len); @@ -249,62 +210,67 @@ static bool net_tx_pkt_parse_headers(struct NetTxPkt *pkt) l3_hdr->iov_len = full_ip6hdr_len; } break; - } + default: l3_hdr->iov_len = 0; break; } - net_tx_pkt_calculate_hdr_len(pkt); + vmxnet_tx_pkt_calculate_hdr_len(pkt); + pkt->packet_type = get_eth_packet_type(l2_hdr->iov_base); return true; } -static void net_tx_pkt_rebuild_payload(struct NetTxPkt *pkt) +static bool vmxnet_tx_pkt_rebuild_payload(struct VmxnetTxPkt *pkt) { - pkt->payload_len = iov_size(pkt->raw, pkt->raw_frags) - pkt->hdr_len; - pkt->payload_frags = iov_copy(&pkt->vec[NET_TX_PKT_PL_START_FRAG], + size_t payload_len = iov_size(pkt->raw, pkt->raw_frags) - pkt->hdr_len; + + pkt->payload_frags = iov_copy(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG], pkt->max_payload_frags, pkt->raw, pkt->raw_frags, - pkt->hdr_len, pkt->payload_len); -} + pkt->hdr_len, payload_len); -bool net_tx_pkt_parse(struct NetTxPkt *pkt) -{ - if (net_tx_pkt_parse_headers(pkt)) { - net_tx_pkt_rebuild_payload(pkt); + if (pkt->payload_frags != (uint32_t) -1) { + pkt->payload_len = payload_len; return true; } else { return false; } } -struct virtio_net_hdr *net_tx_pkt_get_vhdr(struct NetTxPkt *pkt) +bool vmxnet_tx_pkt_parse(struct VmxnetTxPkt *pkt) +{ + return vmxnet_tx_pkt_parse_headers(pkt) && + vmxnet_tx_pkt_rebuild_payload(pkt); +} + +struct virtio_net_hdr *vmxnet_tx_pkt_get_vhdr(struct VmxnetTxPkt *pkt) { assert(pkt); return &pkt->virt_hdr; } -static uint8_t net_tx_pkt_get_gso_type(struct NetTxPkt *pkt, +static uint8_t vmxnet_tx_pkt_get_gso_type(struct VmxnetTxPkt *pkt, bool tso_enable) { uint8_t rc = VIRTIO_NET_HDR_GSO_NONE; uint16_t l3_proto; - l3_proto = eth_get_l3_proto(&pkt->vec[NET_TX_PKT_L2HDR_FRAG], 1, - pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len); + l3_proto = eth_get_l3_proto(pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base, + pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len); if (!tso_enable) { goto func_exit; } - rc = eth_get_gso_type(l3_proto, pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base, + rc = eth_get_gso_type(l3_proto, pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base, pkt->l4proto); func_exit: return rc; } -void net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable, +void vmxnet_tx_pkt_build_vheader(struct VmxnetTxPkt *pkt, bool tso_enable, bool csum_enable, uint32_t gso_size) { struct tcp_hdr l4hdr; @@ -313,7 +279,7 @@ void net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable, /* csum has to be enabled if tso is. */ assert(csum_enable || !tso_enable); - pkt->virt_hdr.gso_type = net_tx_pkt_get_gso_type(pkt, tso_enable); + pkt->virt_hdr.gso_type = vmxnet_tx_pkt_get_gso_type(pkt, tso_enable); switch (pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { case VIRTIO_NET_HDR_GSO_NONE: @@ -322,16 +288,16 @@ void net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable, break; case VIRTIO_NET_HDR_GSO_UDP: - pkt->virt_hdr.gso_size = gso_size; + pkt->virt_hdr.gso_size = IP_FRAG_ALIGN_SIZE(gso_size); pkt->virt_hdr.hdr_len = pkt->hdr_len + sizeof(struct udp_header); break; case VIRTIO_NET_HDR_GSO_TCPV4: case VIRTIO_NET_HDR_GSO_TCPV6: - iov_to_buf(&pkt->vec[NET_TX_PKT_PL_START_FRAG], pkt->payload_frags, + iov_to_buf(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG], pkt->payload_frags, 0, &l4hdr, sizeof(l4hdr)); pkt->virt_hdr.hdr_len = pkt->hdr_len + l4hdr.th_off * sizeof(uint32_t); - pkt->virt_hdr.gso_size = gso_size; + pkt->virt_hdr.gso_size = IP_FRAG_ALIGN_SIZE(gso_size); break; default: @@ -356,24 +322,23 @@ void net_tx_pkt_build_vheader(struct NetTxPkt *pkt, bool tso_enable, } } -void net_tx_pkt_setup_vlan_header_ex(struct NetTxPkt *pkt, - uint16_t vlan, uint16_t vlan_ethtype) +void vmxnet_tx_pkt_setup_vlan_header(struct VmxnetTxPkt *pkt, uint16_t vlan) { bool is_new; assert(pkt); - eth_setup_vlan_headers_ex(pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_base, - vlan, vlan_ethtype, &is_new); + eth_setup_vlan_headers(pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base, + vlan, &is_new); /* update l2hdrlen */ if (is_new) { pkt->hdr_len += sizeof(struct vlan_header); - pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len += + pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len += sizeof(struct vlan_header); } } -bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, +bool vmxnet_tx_pkt_add_raw_fragment(struct VmxnetTxPkt *pkt, hwaddr pa, size_t len) { hwaddr mapped_len = 0; @@ -388,50 +353,44 @@ bool net_tx_pkt_add_raw_fragment(struct NetTxPkt *pkt, hwaddr pa, ventry = &pkt->raw[pkt->raw_frags]; mapped_len = len; - ventry->iov_base = pci_dma_map(pkt->pci_dev, pa, - &mapped_len, DMA_DIRECTION_TO_DEVICE); + ventry->iov_base = cpu_physical_memory_map(pa, &mapped_len, false); + ventry->iov_len = mapped_len; + pkt->raw_frags += !!ventry->iov_base; - if ((ventry->iov_base != NULL) && (len == mapped_len)) { - ventry->iov_len = mapped_len; - pkt->raw_frags++; - return true; - } else { + if ((ventry->iov_base == NULL) || (len != mapped_len)) { return false; } -} -bool net_tx_pkt_has_fragments(struct NetTxPkt *pkt) -{ - return pkt->raw_frags > 0; + return true; } -eth_pkt_types_e net_tx_pkt_get_packet_type(struct NetTxPkt *pkt) +eth_pkt_types_e vmxnet_tx_pkt_get_packet_type(struct VmxnetTxPkt *pkt) { assert(pkt); return pkt->packet_type; } -size_t net_tx_pkt_get_total_len(struct NetTxPkt *pkt) +size_t vmxnet_tx_pkt_get_total_len(struct VmxnetTxPkt *pkt) { assert(pkt); return pkt->hdr_len + pkt->payload_len; } -void net_tx_pkt_dump(struct NetTxPkt *pkt) +void vmxnet_tx_pkt_dump(struct VmxnetTxPkt *pkt) { -#ifdef NET_TX_PKT_DEBUG +#ifdef VMXNET_TX_PKT_DEBUG assert(pkt); printf("TX PKT: hdr_len: %d, pkt_type: 0x%X, l2hdr_len: %lu, " "l3hdr_len: %lu, payload_len: %u\n", pkt->hdr_len, pkt->packet_type, - pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len, - pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len, pkt->payload_len); + pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len, + pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len, pkt->payload_len); #endif } -void net_tx_pkt_reset(struct NetTxPkt *pkt) +void vmxnet_tx_pkt_reset(struct VmxnetTxPkt *pkt) { int i; @@ -442,31 +401,38 @@ void net_tx_pkt_reset(struct NetTxPkt *pkt) memset(&pkt->virt_hdr, 0, sizeof(pkt->virt_hdr)); - assert(pkt->vec); + g_free(pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base); + pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base = NULL; + assert(pkt->vec); + for (i = VMXNET_TX_PKT_L2HDR_FRAG; + i < pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG; i++) { + pkt->vec[i].iov_len = 0; + } pkt->payload_len = 0; pkt->payload_frags = 0; assert(pkt->raw); for (i = 0; i < pkt->raw_frags; i++) { assert(pkt->raw[i].iov_base); - pci_dma_unmap(pkt->pci_dev, pkt->raw[i].iov_base, pkt->raw[i].iov_len, - DMA_DIRECTION_TO_DEVICE, 0); + cpu_physical_memory_unmap(pkt->raw[i].iov_base, pkt->raw[i].iov_len, + false, pkt->raw[i].iov_len); + pkt->raw[i].iov_len = 0; } pkt->raw_frags = 0; pkt->hdr_len = 0; + pkt->packet_type = 0; pkt->l4proto = 0; } -static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt) +static void vmxnet_tx_pkt_do_sw_csum(struct VmxnetTxPkt *pkt) { - struct iovec *iov = &pkt->vec[NET_TX_PKT_L2HDR_FRAG]; + struct iovec *iov = &pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG]; uint32_t csum_cntr; uint16_t csum = 0; - uint32_t cso; /* num of iovec without vhdr */ - uint32_t iov_len = pkt->payload_frags + NET_TX_PKT_PL_START_FRAG - 1; + uint32_t iov_len = pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG - 1; uint16_t csl; struct ip_header *iphdr; size_t csum_offset = pkt->virt_hdr.csum_start + pkt->virt_hdr.csum_offset; @@ -477,13 +443,12 @@ static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt) /* Calculate L4 TCP/UDP checksum */ csl = pkt->payload_len; - /* add pseudo header to csum */ - iphdr = pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base; - csum_cntr = eth_calc_ip4_pseudo_hdr_csum(iphdr, csl, &cso); - /* data checksum */ - csum_cntr += - net_checksum_add_iov(iov, iov_len, pkt->virt_hdr.csum_start, csl, cso); + csum_cntr = + net_checksum_add_iov(iov, iov_len, pkt->virt_hdr.csum_start, csl); + /* add pseudo header to csum */ + iphdr = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base; + csum_cntr += eth_calc_pseudo_hdr_csum(iphdr, csl); /* Put the checksum obtained into the packet */ csum = cpu_to_be16(net_checksum_finish(csum_cntr)); @@ -491,37 +456,37 @@ static void net_tx_pkt_do_sw_csum(struct NetTxPkt *pkt) } enum { - NET_TX_PKT_FRAGMENT_L2_HDR_POS = 0, - NET_TX_PKT_FRAGMENT_L3_HDR_POS, - NET_TX_PKT_FRAGMENT_HEADER_NUM + VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS = 0, + VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS, + VMXNET_TX_PKT_FRAGMENT_HEADER_NUM }; -#define NET_MAX_FRAG_SG_LIST (64) +#define VMXNET_MAX_FRAG_SG_LIST (64) -static size_t net_tx_pkt_fetch_fragment(struct NetTxPkt *pkt, +static size_t vmxnet_tx_pkt_fetch_fragment(struct VmxnetTxPkt *pkt, int *src_idx, size_t *src_offset, struct iovec *dst, int *dst_idx) { size_t fetched = 0; struct iovec *src = pkt->vec; - *dst_idx = NET_TX_PKT_FRAGMENT_HEADER_NUM; + *dst_idx = VMXNET_TX_PKT_FRAGMENT_HEADER_NUM; - while (fetched < IP_FRAG_ALIGN_SIZE(pkt->virt_hdr.gso_size)) { + while (fetched < pkt->virt_hdr.gso_size) { /* no more place in fragment iov */ - if (*dst_idx == NET_MAX_FRAG_SG_LIST) { + if (*dst_idx == VMXNET_MAX_FRAG_SG_LIST) { break; } /* no more data in iovec */ - if (*src_idx == (pkt->payload_frags + NET_TX_PKT_PL_START_FRAG)) { + if (*src_idx == (pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG)) { break; } dst[*dst_idx].iov_base = src[*src_idx].iov_base + *src_offset; dst[*dst_idx].iov_len = MIN(src[*src_idx].iov_len - *src_offset, - IP_FRAG_ALIGN_SIZE(pkt->virt_hdr.gso_size) - fetched); + pkt->virt_hdr.gso_size - fetched); *src_offset += dst[*dst_idx].iov_len; fetched += dst[*dst_idx].iov_len; @@ -537,45 +502,35 @@ static size_t net_tx_pkt_fetch_fragment(struct NetTxPkt *pkt, return fetched; } -static inline void net_tx_pkt_sendv(struct NetTxPkt *pkt, - NetClientState *nc, const struct iovec *iov, int iov_cnt) -{ - if (pkt->is_loopback) { - nc->info->receive_iov(nc, iov, iov_cnt); - } else { - qemu_sendv_packet(nc, iov, iov_cnt); - } -} - -static bool net_tx_pkt_do_sw_fragmentation(struct NetTxPkt *pkt, +static bool vmxnet_tx_pkt_do_sw_fragmentation(struct VmxnetTxPkt *pkt, NetClientState *nc) { - struct iovec fragment[NET_MAX_FRAG_SG_LIST]; + struct iovec fragment[VMXNET_MAX_FRAG_SG_LIST]; size_t fragment_len = 0; bool more_frags = false; /* some pointers for shorter code */ void *l2_iov_base, *l3_iov_base; size_t l2_iov_len, l3_iov_len; - int src_idx = NET_TX_PKT_PL_START_FRAG, dst_idx; + int src_idx = VMXNET_TX_PKT_PL_START_FRAG, dst_idx; size_t src_offset = 0; size_t fragment_offset = 0; - l2_iov_base = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_base; - l2_iov_len = pkt->vec[NET_TX_PKT_L2HDR_FRAG].iov_len; - l3_iov_base = pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_base; - l3_iov_len = pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len; + l2_iov_base = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base; + l2_iov_len = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len; + l3_iov_base = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base; + l3_iov_len = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len; /* Copy headers */ - fragment[NET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_base = l2_iov_base; - fragment[NET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_len = l2_iov_len; - fragment[NET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_base = l3_iov_base; - fragment[NET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_len = l3_iov_len; + fragment[VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_base = l2_iov_base; + fragment[VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_len = l2_iov_len; + fragment[VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_base = l3_iov_base; + fragment[VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_len = l3_iov_len; /* Put as much data as possible and send */ do { - fragment_len = net_tx_pkt_fetch_fragment(pkt, &src_idx, &src_offset, + fragment_len = vmxnet_tx_pkt_fetch_fragment(pkt, &src_idx, &src_offset, fragment, &dst_idx); more_frags = (fragment_offset + fragment_len < pkt->payload_len); @@ -585,22 +540,22 @@ static bool net_tx_pkt_do_sw_fragmentation(struct NetTxPkt *pkt, eth_fix_ip4_checksum(l3_iov_base, l3_iov_len); - net_tx_pkt_sendv(pkt, nc, fragment, dst_idx); + qemu_sendv_packet(nc, fragment, dst_idx); fragment_offset += fragment_len; - } while (fragment_len && more_frags); + } while (more_frags); return true; } -bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc) +bool vmxnet_tx_pkt_send(struct VmxnetTxPkt *pkt, NetClientState *nc) { assert(pkt); if (!pkt->has_virt_hdr && pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { - net_tx_pkt_do_sw_csum(pkt); + vmxnet_tx_pkt_do_sw_csum(pkt); } /* @@ -610,28 +565,17 @@ bool net_tx_pkt_send(struct NetTxPkt *pkt, NetClientState *nc) if (VIRTIO_NET_HDR_GSO_NONE != pkt->virt_hdr.gso_type) { if (pkt->payload_len > ETH_MAX_IP_DGRAM_LEN - - pkt->vec[NET_TX_PKT_L3HDR_FRAG].iov_len) { + pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len) { return false; } } if (pkt->has_virt_hdr || pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) { - net_tx_pkt_sendv(pkt, nc, pkt->vec, - pkt->payload_frags + NET_TX_PKT_PL_START_FRAG); + qemu_sendv_packet(nc, pkt->vec, + pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG); return true; } - return net_tx_pkt_do_sw_fragmentation(pkt, nc); -} - -bool net_tx_pkt_send_loopback(struct NetTxPkt *pkt, NetClientState *nc) -{ - bool res; - - pkt->is_loopback = true; - res = net_tx_pkt_send(pkt, nc); - pkt->is_loopback = false; - - return res; + return vmxnet_tx_pkt_do_sw_fragmentation(pkt, nc); } diff --git a/hw/net/vmxnet_tx_pkt.h b/hw/net/vmxnet_tx_pkt.h new file mode 100644 index 000000000..f51e98ad9 --- /dev/null +++ b/hw/net/vmxnet_tx_pkt.h @@ -0,0 +1,146 @@ +/* + * QEMU VMWARE VMXNET* paravirtual NICs - TX packets abstraction + * + * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) + * + * Developed by Daynix Computing LTD (http://www.daynix.com) + * + * Authors: + * Dmitry Fleytman <dmitry@daynix.com> + * Tamir Shomer <tamirs@daynix.com> + * Yan Vugenfirer <yan@daynix.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 VMXNET_TX_PKT_H +#define VMXNET_TX_PKT_H + +#include "net/eth.h" +#include "exec/hwaddr.h" + +/* define to enable packet dump functions */ +/*#define VMXNET_TX_PKT_DEBUG*/ + +struct VmxnetTxPkt; + +/** + * Init function for tx packet functionality + * + * @pkt: packet pointer + * @max_frags: max tx ip fragments + * @has_virt_hdr: device uses virtio header. + */ +void vmxnet_tx_pkt_init(struct VmxnetTxPkt **pkt, uint32_t max_frags, + bool has_virt_hdr); + +/** + * Clean all tx packet resources. + * + * @pkt: packet. + */ +void vmxnet_tx_pkt_uninit(struct VmxnetTxPkt *pkt); + +/** + * get virtio header + * + * @pkt: packet + * @ret: virtio header + */ +struct virtio_net_hdr *vmxnet_tx_pkt_get_vhdr(struct VmxnetTxPkt *pkt); + +/** + * build virtio header (will be stored in module context) + * + * @pkt: packet + * @tso_enable: TSO enabled + * @csum_enable: CSO enabled + * @gso_size: MSS size for TSO + * + */ +void vmxnet_tx_pkt_build_vheader(struct VmxnetTxPkt *pkt, bool tso_enable, + bool csum_enable, uint32_t gso_size); + +/** + * updates vlan tag, and adds vlan header in case it is missing + * + * @pkt: packet + * @vlan: VLAN tag + * + */ +void vmxnet_tx_pkt_setup_vlan_header(struct VmxnetTxPkt *pkt, uint16_t vlan); + +/** + * populate data fragment into pkt context. + * + * @pkt: packet + * @pa: physical address of fragment + * @len: length of fragment + * + */ +bool vmxnet_tx_pkt_add_raw_fragment(struct VmxnetTxPkt *pkt, hwaddr pa, + size_t len); + +/** + * fix ip header fields and calculate checksums needed. + * + * @pkt: packet + * + */ +void vmxnet_tx_pkt_update_ip_checksums(struct VmxnetTxPkt *pkt); + +/** + * get length of all populated data. + * + * @pkt: packet + * @ret: total data length + * + */ +size_t vmxnet_tx_pkt_get_total_len(struct VmxnetTxPkt *pkt); + +/** + * get packet type + * + * @pkt: packet + * @ret: packet type + * + */ +eth_pkt_types_e vmxnet_tx_pkt_get_packet_type(struct VmxnetTxPkt *pkt); + +/** + * prints packet data if debug is enabled + * + * @pkt: packet + * + */ +void vmxnet_tx_pkt_dump(struct VmxnetTxPkt *pkt); + +/** + * reset tx packet private context (needed to be called between packets) + * + * @pkt: packet + * + */ +void vmxnet_tx_pkt_reset(struct VmxnetTxPkt *pkt); + +/** + * Send packet to qemu. handles sw offloads if vhdr is not supported. + * + * @pkt: packet + * @nc: NetClientState + * @ret: operation result + * + */ +bool vmxnet_tx_pkt_send(struct VmxnetTxPkt *pkt, NetClientState *nc); + +/** + * parse raw packet data and analyze offload requirements. + * + * @pkt: packet + * + */ +bool vmxnet_tx_pkt_parse(struct VmxnetTxPkt *pkt); + +#endif diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c index 6856b5299..7281730d9 100644 --- a/hw/net/xen_nic.c +++ b/hw/net/xen_nic.c @@ -22,6 +22,7 @@ #include "qemu/osdep.h" #include <sys/socket.h> #include <sys/ioctl.h> +#include <sys/mman.h> #include <sys/wait.h> #include "hw/hw.h" @@ -269,7 +270,7 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size /* ------------------------------------------------------------- */ static NetClientInfo net_xen_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = net_rx_packet, }; diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index 46b1aa17f..0c5f793bd 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -371,7 +371,7 @@ out: } static NetClientInfo net_xgmac_enet_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = eth_rx, }; diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index b6701844d..de23ab5dc 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -935,7 +935,7 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size) } static NetClientInfo net_xilinx_enet_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = eth_rx, }; diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c index 35de353b7..bc846e709 100644 --- a/hw/net/xilinx_ethlite.c +++ b/hw/net/xilinx_ethlite.c @@ -197,10 +197,6 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) } D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase)); - if (size > (R_MAX - R_RX_BUF0 - rxbase) * 4) { - D(qemu_log("ethlite packet is too big, size=%x\n", size)); - return -1; - } memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size); s->regs[rxbase + R_RX_CTRL0] |= CTRL_S; @@ -221,7 +217,7 @@ static void xilinx_ethlite_reset(DeviceState *dev) } static NetClientInfo net_xilinx_ethlite_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .can_receive = eth_can_rx, .receive = eth_rx, diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 6a68e594d..999f48028 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -25,7 +25,6 @@ #include "hw/hw.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" -#include "hw/boards.h" #include "hw/isa/isa.h" #include "hw/nvram/fw_cfg.h" #include "hw/sysbus.h" @@ -552,7 +551,7 @@ static bool is_version_1(void *opaque, int version_id) return version_id == 1; } -bool fw_cfg_dma_enabled(void *opaque) +static bool fw_cfg_dma_enabled(void *opaque) { FWCfgState *s = opaque; @@ -729,22 +728,17 @@ static int get_fw_cfg_order(FWCfgState *s, const char *name) { int i; - if (s->fw_cfg_order_override > 0) { - return s->fw_cfg_order_override; - } + if (s->fw_cfg_order_override > 0) + return s->fw_cfg_order_override; for (i = 0; i < ARRAY_SIZE(fw_cfg_order); i++) { - if (fw_cfg_order[i].name == NULL) { - continue; - } - - if (strcmp(name, fw_cfg_order[i].name) == 0) { - return fw_cfg_order[i].order; - } + if (fw_cfg_order[i].name == NULL) + continue; + if (strcmp(name, fw_cfg_order[i].name) == 0) + return fw_cfg_order[i].order; } - /* Stick unknown stuff at the end. */ - error_report("warning: Unknown firmware file in legacy mode: %s", name); + error_report("warning: Unknown firmware file in legacy mode: %s\n", name); return FW_CFG_ORDER_OVERRIDE_LAST; } @@ -874,17 +868,16 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data) static void fw_cfg_init1(DeviceState *dev) { FWCfgState *s = FW_CFG(dev); - MachineState *machine = MACHINE(qdev_get_machine()); assert(!object_resolve_path(FW_CFG_PATH, NULL)); - object_property_add_child(OBJECT(machine), FW_CFG_NAME, OBJECT(s), NULL); + object_property_add_child(qdev_get_machine(), FW_CFG_NAME, OBJECT(s), NULL); qdev_init_nofail(dev); fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4); fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16); - fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)!machine->enable_graphics); + fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC)); fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu); fw_cfg_bootsplash(s); @@ -990,7 +983,6 @@ static void fw_cfg_class_init(ObjectClass *klass, void *data) static const TypeInfo fw_cfg_info = { .name = TYPE_FW_CFG, .parent = TYPE_SYS_BUS_DEVICE, - .abstract = true, .instance_size = sizeof(FWCfgState), .class_init = fw_cfg_class_init, }; diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index 4de5f705d..802636ef3 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -39,7 +39,6 @@ typedef struct sPAPRNVRAM { uint32_t size; uint8_t *buf; BlockBackend *blk; - VMChangeStateEntry *vmstate; } sPAPRNVRAM; #define TYPE_VIO_SPAPR_NVRAM "spapr-nvram" @@ -125,7 +124,7 @@ static void rtas_nvram_store(PowerPCCPU *cpu, sPAPRMachineState *spapr, alen = len; if (nvram->blk) { - alen = blk_pwrite(nvram->blk, offset, membuf, len, 0); + alen = blk_pwrite(nvram->blk, offset, membuf, len); } assert(nvram->buf); @@ -186,25 +185,19 @@ static int spapr_nvram_pre_load(void *opaque) return 0; } -static void postload_update_cb(void *opaque, int running, RunState state) -{ - sPAPRNVRAM *nvram = opaque; - - /* This is called after bdrv_invalidate_cache_all. */ - - qemu_del_vm_change_state_handler(nvram->vmstate); - nvram->vmstate = NULL; - - blk_pwrite(nvram->blk, 0, nvram->buf, nvram->size, 0); -} - static int spapr_nvram_post_load(void *opaque, int version_id) { sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(opaque); if (nvram->blk) { - nvram->vmstate = qemu_add_vm_change_state_handler(postload_update_cb, - nvram); + int alen = blk_pwrite(nvram->blk, 0, nvram->buf, nvram->size); + + if (alen < 0) { + return alen; + } + if (alen != nvram->size) { + return -1; + } } return 0; diff --git a/hw/nvram/trace-events b/hw/nvram/trace-events deleted file mode 100644 index 1f1e05ab6..000000000 --- a/hw/nvram/trace-events +++ /dev/null @@ -1,10 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/nvram/ds1225y.c -nvram_read(uint32_t addr, uint32_t ret) "read addr %d: 0x%02x" -nvram_write(uint32_t addr, uint32_t old, uint32_t val) "write addr %d: 0x%02x -> 0x%02x" - -# hw/nvram/fw_cfg.c -fw_cfg_select(void *s, uint16_t key, int ret) "%p key %d = %d" -fw_cfg_read(void *s, uint64_t ret) "%p = %"PRIx64 -fw_cfg_add_file(void *s, int index, char *name, size_t len) "%p #%d: %s (%zd bytes)" diff --git a/hw/pci-bridge/dec.h b/hw/pci-bridge/dec.h index ae17ca736..17dc0c2b0 100644 --- a/hw/pci-bridge/dec.h +++ b/hw/pci-bridge/dec.h @@ -1,5 +1,5 @@ -#ifndef HW_PCI_BRIDGE_DEC_H -#define HW_PCI_BRIDGE_DEC_H +#ifndef DEC_PCI_H +#define DEC_PCI_H #include "qemu-common.h" diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index c8b5ac420..0937fa34b 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -25,7 +25,6 @@ #include "hw/pci/msi.h" #include "hw/pci/pcie.h" #include "ioh3420.h" -#include "qapi/error.h" #define PCI_DEVICE_ID_IOH_EPORT 0x3420 /* D0:F0 express mode */ #define PCI_DEVICE_ID_IOH_REV 0x2 @@ -98,9 +97,7 @@ static int ioh3420_initfn(PCIDevice *d) PCIEPort *p = PCIE_PORT(d); PCIESlot *s = PCIE_SLOT(d); int rc; - Error *err = NULL; - pci_config_set_interrupt_pin(d->config, 1); pci_bridge_initfn(d, TYPE_PCIE_BUS); pcie_port_init_reg(d); @@ -109,16 +106,12 @@ static int ioh3420_initfn(PCIDevice *d) if (rc < 0) { goto err_bridge; } - rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR, IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, - IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err); + IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT); if (rc < 0) { - assert(rc == -ENOTSUP); - error_report_err(err); goto err_bridge; } - rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port); if (rc < 0) { goto err_msi; @@ -127,21 +120,18 @@ static int ioh3420_initfn(PCIDevice *d) pcie_cap_arifwd_init(d); pcie_cap_deverr_init(d); pcie_cap_slot_init(d, s->slot); - pcie_cap_root_init(d); - pcie_chassis_create(s->chassis); rc = pcie_chassis_add_slot(s); if (rc < 0) { goto err_pcie_cap; } - + pcie_cap_root_init(d); rc = pcie_aer_init(d, IOH_EP_AER_OFFSET, PCI_ERR_SIZEOF); if (rc < 0) { goto err; } pcie_aer_root_init(d); ioh3420_aer_vector_update(d); - return 0; err: @@ -217,3 +207,12 @@ static void ioh3420_register_types(void) } type_init(ioh3420_register_types) + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * indent-tab-mode: nil + * End: + */ diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 5dbd933cc..7b582e96a 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -42,10 +42,9 @@ struct PCIBridgeDev { MemoryRegion bar; uint8_t chassis_nr; -#define PCI_BRIDGE_DEV_F_SHPC_REQ 0 +#define PCI_BRIDGE_DEV_F_MSI_REQ 0 +#define PCI_BRIDGE_DEV_F_SHPC_REQ 1 uint32_t flags; - - OnOffAuto msi; }; typedef struct PCIBridgeDev PCIBridgeDev; @@ -54,7 +53,6 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) PCIBridge *br = PCI_BRIDGE(dev); PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev); int err; - Error *local_err = NULL; pci_bridge_initfn(dev, TYPE_PCI_BUS); @@ -68,33 +66,19 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) } } else { /* MSI is not applicable without SHPC */ - bridge_dev->msi = ON_OFF_AUTO_OFF; + bridge_dev->flags &= ~(1 << PCI_BRIDGE_DEV_F_MSI_REQ); } - err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0); if (err) { goto slotid_error; } - - if (bridge_dev->msi != ON_OFF_AUTO_OFF) { - /* it means SHPC exists, because MSI is needed by SHPC */ - - err = msi_init(dev, 0, 1, true, true, &local_err); - /* Any error other than -ENOTSUP(board's MSI support is broken) - * is a programming error */ - assert(!err || err == -ENOTSUP); - if (err && bridge_dev->msi == ON_OFF_AUTO_ON) { - /* Can't satisfy user's explicit msi=on request, fail */ - error_append_hint(&local_err, "You have to use msi=auto (default) " - "or msi=off with this machine type.\n"); - error_report_err(local_err); + if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) && + msi_nonbroken) { + err = msi_init(dev, 0, 1, true, true); + if (err < 0) { goto msi_error; } - assert(!local_err || bridge_dev->msi == ON_OFF_AUTO_AUTO); - /* With msi=auto, we fall back to MSI off silently */ - error_free(local_err); } - if (shpc_present(dev)) { /* TODO: spec recommends using 64 bit prefetcheable BAR. * Check whether that works well. */ @@ -102,7 +86,6 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar); } return 0; - msi_error: slotid_cap_cleanup(dev); slotid_error: @@ -160,8 +143,8 @@ static Property pci_bridge_dev_properties[] = { /* Note: 0 is not a legal chassis number. */ DEFINE_PROP_UINT8(PCI_BRIDGE_DEV_PROP_CHASSIS_NR, PCIBridgeDev, chassis_nr, 0), - DEFINE_PROP_ON_OFF_AUTO(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, msi, - ON_OFF_AUTO_AUTO), + DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, flags, + PCI_BRIDGE_DEV_F_MSI_REQ, true), DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_SHPC, PCIBridgeDev, flags, PCI_BRIDGE_DEV_F_SHPC_REQ, true), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 1cc598f7e..ba320bd85 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" @@ -150,8 +149,6 @@ static void pxb_host_class_init(ObjectClass *class, void *data) PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class); dc->fw_name = "pci"; - /* Reason: Internal part of the pxb/pxb-pcie device, not usable by itself */ - dc->cannot_instantiate_with_device_add_yet = true; sbc->explicit_ofw_unit_address = pxb_host_ofw_unit_address; hc->root_bus_path = pxb_host_root_bus_path; } @@ -163,25 +160,30 @@ static const TypeInfo pxb_host_info = { }; /* - * Registers the PXB bus as a child of pci host root bus. + * Registers the PXB bus as a child of the i440fx root bus. + * + * Returns 0 on successs, -1 if i440fx host was not + * found or the bus number is already in use. */ -static void pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus, Error **errp) +static int pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus) { PCIBus *bus = dev->bus; int pxb_bus_num = pci_bus_num(pxb_bus); if (bus->parent_dev) { - error_setg(errp, "PXB devices can be attached only to root bus"); - return; + error_report("PXB devices can be attached only to root bus."); + return -1; } QLIST_FOREACH(bus, &bus->child, sibling) { if (pci_bus_num(bus) == pxb_bus_num) { - error_setg(errp, "Bus %d is already in use", pxb_bus_num); - return; + error_report("Bus %d is already in use.", pxb_bus_num); + return -1; } } QLIST_INSERT_HEAD(&dev->bus->child, pxb_bus, sibling); + + return 0; } static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin) @@ -211,18 +213,17 @@ static gint pxb_compare(gconstpointer a, gconstpointer b) 0; } -static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) +static int pxb_dev_init_common(PCIDevice *dev, bool pcie) { PXBDev *pxb = convert_to_pxb(dev); DeviceState *ds, *bds = NULL; PCIBus *bus; const char *dev_name = NULL; - Error *local_err = NULL; if (pxb->numa_node != NUMA_NODE_UNASSIGNED && pxb->numa_node >= nb_numa_nodes) { - error_setg(errp, "Illegal numa node %d", pxb->numa_node); - return; + error_report("Illegal numa node %d.", pxb->numa_node); + return -EINVAL; } if (dev->qdev.id && *dev->qdev.id) { @@ -247,9 +248,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) PCI_HOST_BRIDGE(ds)->bus = bus; - pxb_register_bus(dev, bus, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (pxb_register_bus(dev, bus)) { goto err_register_bus; } @@ -263,22 +262,23 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp) pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST); pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare); - return; + return 0; err_register_bus: object_unref(OBJECT(bds)); object_unparent(OBJECT(bus)); object_unref(OBJECT(ds)); + return -EINVAL; } -static void pxb_dev_realize(PCIDevice *dev, Error **errp) +static int pxb_dev_initfn(PCIDevice *dev) { if (pci_bus_is_express(dev->bus)) { - error_setg(errp, "pxb devices cannot reside on a PCIe bus"); - return; + error_report("pxb devices cannot reside on a PCIe bus!"); + return -EINVAL; } - pxb_dev_realize_common(dev, false, errp); + return pxb_dev_init_common(dev, false); } static void pxb_dev_exitfn(PCIDevice *pci_dev) @@ -300,7 +300,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->realize = pxb_dev_realize; + k->init = pxb_dev_initfn; k->exit = pxb_dev_exitfn; k->vendor_id = PCI_VENDOR_ID_REDHAT; k->device_id = PCI_DEVICE_ID_REDHAT_PXB; @@ -308,7 +308,6 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data) dc->desc = "PCI Expander Bridge"; dc->props = pxb_dev_properties; - dc->hotpluggable = false; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } @@ -319,14 +318,14 @@ static const TypeInfo pxb_dev_info = { .class_init = pxb_dev_class_init, }; -static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp) +static int pxb_pcie_dev_initfn(PCIDevice *dev) { if (!pci_bus_is_express(dev->bus)) { - error_setg(errp, "pxb-pcie devices cannot reside on a PCI bus"); - return; + error_report("pxb-pcie devices cannot reside on a PCI bus!"); + return -EINVAL; } - pxb_dev_realize_common(dev, true, errp); + return pxb_dev_init_common(dev, true); } static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data) @@ -334,7 +333,7 @@ static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->realize = pxb_pcie_dev_realize; + k->init = pxb_pcie_dev_initfn; k->exit = pxb_dev_exitfn; k->vendor_id = PCI_VENDOR_ID_REDHAT; k->device_id = PCI_DEVICE_ID_REDHAT_PXB_PCIE; @@ -342,7 +341,6 @@ static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data) dc->desc = "PCI Express Expander Bridge"; dc->props = pxb_dev_properties; - dc->hotpluggable = false; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index cef6e1325..cf1ee63ab 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -24,7 +24,6 @@ #include "hw/pci/msi.h" #include "hw/pci/pcie.h" #include "xio3130_downstream.h" -#include "qapi/error.h" #define PCI_DEVICE_ID_TI_XIO3130D 0x8233 /* downstream port */ #define XIO3130_REVISION 0x1 @@ -61,26 +60,21 @@ static int xio3130_downstream_initfn(PCIDevice *d) PCIEPort *p = PCIE_PORT(d); PCIESlot *s = PCIE_SLOT(d); int rc; - Error *err = NULL; pci_bridge_initfn(d, TYPE_PCIE_BUS); pcie_port_init_reg(d); rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR, XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, - XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err); + XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT); if (rc < 0) { - assert(rc == -ENOTSUP); - error_report_err(err); goto err_bridge; } - rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET, XIO3130_SSVID_SVID, XIO3130_SSVID_SSID); if (rc < 0) { goto err_bridge; } - rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM, p->port); if (rc < 0) { @@ -89,14 +83,12 @@ static int xio3130_downstream_initfn(PCIDevice *d) pcie_cap_flr_init(d); pcie_cap_deverr_init(d); pcie_cap_slot_init(d, s->slot); - pcie_cap_arifwd_init(d); - pcie_chassis_create(s->chassis); rc = pcie_chassis_add_slot(s); if (rc < 0) { goto err_pcie_cap; } - + pcie_cap_arifwd_init(d); rc = pcie_aer_init(d, XIO3130_AER_OFFSET, PCI_ERR_SIZEOF); if (rc < 0) { goto err; @@ -203,3 +195,12 @@ static void xio3130_downstream_register_types(void) } type_init(xio3130_downstream_register_types) + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * indent-tab-mode: nil + * End: + */ diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index 4ad0440aa..164ef58c4 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -24,7 +24,6 @@ #include "hw/pci/msi.h" #include "hw/pci/pcie.h" #include "xio3130_upstream.h" -#include "qapi/error.h" #define PCI_DEVICE_ID_TI_XIO3130U 0x8232 /* upstream port */ #define XIO3130_REVISION 0x2 @@ -57,26 +56,21 @@ static int xio3130_upstream_initfn(PCIDevice *d) { PCIEPort *p = PCIE_PORT(d); int rc; - Error *err = NULL; pci_bridge_initfn(d, TYPE_PCIE_BUS); pcie_port_init_reg(d); rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR, XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT, - XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT, &err); + XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT); if (rc < 0) { - assert(rc == -ENOTSUP); - error_report_err(err); goto err_bridge; } - rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET, XIO3130_SSVID_SVID, XIO3130_SSVID_SSID); if (rc < 0) { goto err_bridge; } - rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM, p->port); if (rc < 0) { @@ -84,7 +78,6 @@ 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); if (rc < 0) { goto err; @@ -174,3 +167,13 @@ static void xio3130_upstream_register_types(void) } type_init(xio3130_upstream_register_types) + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 8 + * indent-tab-mode: nil + * End: + */ diff --git a/hw/pci-bridge/xio3130_upstream.h b/hw/pci-bridge/xio3130_upstream.h index d0ab7577e..08c1d5f75 100644 --- a/hw/pci-bridge/xio3130_upstream.h +++ b/hw/pci-bridge/xio3130_upstream.h @@ -7,4 +7,4 @@ PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction, const char *bus_name, pci_map_irq_fn map_irq, uint8_t port); -#endif /* QEMU_XIO3130_UPSTREAM_H */ +#endif /* QEMU_XIO3130_H */ diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 653e71112..aaef7bb3a 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -36,7 +36,6 @@ #include "hw/pci-host/apb.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" -#include "qemu/log.h" /* debug APB */ //#define DEBUG_APB @@ -634,7 +633,7 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level) } } -static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) +static int apb_pci_bridge_initfn(PCIDevice *dev) { pci_bridge_initfn(dev, TYPE_PCI_BUS); @@ -652,6 +651,7 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) pci_set_word(dev->config + PCI_STATUS, PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM); + return 0; } PCIBus *pci_apb_init(hwaddr special_base, @@ -669,13 +669,6 @@ PCIBus *pci_apb_init(hwaddr special_base, /* Ultrasparc PBM main bus */ dev = qdev_create(NULL, TYPE_APB); - d = APB_DEVICE(dev); - phb = PCI_HOST_BRIDGE(dev); - phb->bus = pci_register_bus(DEVICE(phb), "pci", - pci_apb_set_irq, pci_pbm_map_irq, d, - &d->pci_mmio, - get_system_io(), - 0, 32, TYPE_PCI_BUS); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); /* apb_config */ @@ -684,10 +677,18 @@ PCIBus *pci_apb_init(hwaddr special_base, sysbus_mmio_map(s, 1, special_base + 0x1000000ULL); /* pci_ioport */ sysbus_mmio_map(s, 2, special_base + 0x2000000ULL); + d = APB_DEVICE(dev); memory_region_init(&d->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL); memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio); + phb = PCI_HOST_BRIDGE(dev); + phb->bus = pci_register_bus(DEVICE(phb), "pci", + pci_apb_set_irq, pci_pbm_map_irq, d, + &d->pci_mmio, + get_system_io(), + 0, 32, TYPE_PCI_BUS); + *pbm_irqs = d->pbm_irqs; d->ivec_irqs = ivec_irqs; @@ -842,7 +843,7 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->realize = apb_pci_bridge_realize; + k->init = apb_pci_bridge_initfn; k->exit = pci_bridge_exitfn; k->vendor_id = PCI_VENDOR_ID_SUN; k->device_id = PCI_DEVICE_ID_SUN_SIMBA; diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c index 2c8acdaac..8f9121615 100644 --- a/hw/pci-host/grackle.c +++ b/hw/pci-host/grackle.c @@ -72,6 +72,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, GrackleState *d; dev = qdev_create(NULL, TYPE_GRACKLE_PCI_HOST_BRIDGE); + qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); phb = PCI_HOST_BRIDGE(dev); d = GRACKLE_PCI_HOST_BRIDGE(dev); @@ -91,7 +92,6 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, 0, 4, TYPE_PCI_BUS); pci_create_simple(phb->bus, 0, "grackle"); - qdev_init_nofail(dev); sysbus_mmio_map(s, 0, base); sysbus_mmio_map(s, 1, base + 0x00200000); diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index f9218aa95..df2b0e26f 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -48,7 +48,7 @@ typedef struct I440FXState { PCIHostState parent_obj; - Range pci_hole; + PcPciInfo pci_info; uint64_t pci_hole64_size; uint32_t short_root_bus; } I440FXState; @@ -221,12 +221,8 @@ static void i440fx_pcihost_get_pci_hole_start(Object *obj, Visitor *v, Error **errp) { I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); - uint64_t val64; - uint32_t value; + uint32_t value = s->pci_info.w32.begin; - val64 = range_is_empty(&s->pci_hole) ? 0 : range_lob(&s->pci_hole); - value = val64; - assert(value == val64); visit_type_uint32(v, name, &value, errp); } @@ -235,12 +231,8 @@ static void i440fx_pcihost_get_pci_hole_end(Object *obj, Visitor *v, Error **errp) { I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj); - uint64_t val64; - uint32_t value; + uint32_t value = s->pci_info.w32.end; - val64 = range_is_empty(&s->pci_hole) ? 0 : range_upb(&s->pci_hole) + 1; - value = val64; - assert(value == val64); visit_type_uint32(v, name, &value, errp); } @@ -250,11 +242,10 @@ static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v, { PCIHostState *h = PCI_HOST_BRIDGE(obj); Range w64; - uint64_t value; pci_bus_get_w64_range(h->bus, &w64); - value = range_is_empty(&w64) ? 0 : range_lob(&w64); - visit_type_uint64(v, name, &value, errp); + + visit_type_uint64(v, name, &w64.begin, errp); } static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v, @@ -263,16 +254,16 @@ static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v, { PCIHostState *h = PCI_HOST_BRIDGE(obj); Range w64; - uint64_t value; pci_bus_get_w64_range(h->bus, &w64); - value = range_is_empty(&w64) ? 0 : range_upb(&w64) + 1; - visit_type_uint64(v, name, &value, errp); + + visit_type_uint64(v, name, &w64.end, errp); } static void i440fx_pcihost_initfn(Object *obj) { PCIHostState *s = PCI_HOST_BRIDGE(obj); + I440FXState *d = I440FX_PCI_HOST_BRIDGE(obj); memory_region_init_io(&s->conf_mem, obj, &pci_host_conf_le_ops, s, "pci-conf-idx", 4); @@ -294,6 +285,8 @@ static void i440fx_pcihost_initfn(Object *obj) object_property_add(obj, PCI_HOST_PROP_PCI_HOLE64_END, "int", i440fx_pcihost_get_pci_hole64_end, NULL, NULL, NULL, NULL); + + d->pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS; } static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) @@ -354,8 +347,7 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type, f->ram_memory = ram_memory; i440fx = I440FX_PCI_HOST_BRIDGE(dev); - range_set_bounds(&i440fx->pci_hole, below_4g_mem_size, - IO_APIC_DEFAULT_ADDRESS - 1); + i440fx->pci_info.w32.begin = below_4g_mem_size; /* setup pci memory mapping */ pc_pci_as_mapping_init(OBJECT(f), f->system_memory, @@ -873,8 +865,6 @@ static void i440fx_pcihost_class_init(ObjectClass *klass, void *data) dc->realize = i440fx_pcihost_realize; dc->fw_name = "pci"; dc->props = i440fx_props; - /* Reason: needs to be wired up by pc_init1 */ - dc->cannot_instantiate_with_device_add_yet = true; } static const TypeInfo i440fx_pcihost_info = { diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index 5580293f9..487e32ecb 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -247,7 +247,6 @@ static void raven_pcihost_realizefn(DeviceState *d, Error **errp) memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->pci_intack); /* TODO Remove once realize propagates to child devices. */ - object_property_set_bool(OBJECT(&s->pci_bus), true, "realized", errp); object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp); } diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 344f77b10..70f897e3a 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -52,7 +52,6 @@ static void q35_host_realize(DeviceState *dev, Error **errp) pci->bus = pci_bus_new(DEVICE(s), "pcie.0", s->mch.pci_address_space, s->mch.address_space_io, 0, TYPE_PCIE_BUS); - PC_MACHINE(qdev_get_machine())->bus = pci->bus; qdev_set_parent_bus(DEVICE(&s->mch), BUS(pci->bus)); qdev_init_nofail(DEVICE(&s->mch)); } @@ -74,13 +73,8 @@ static void q35_host_get_pci_hole_start(Object *obj, Visitor *v, Error **errp) { Q35PCIHost *s = Q35_HOST_DEVICE(obj); - uint64_t val64; - uint32_t value; + uint32_t value = s->mch.pci_info.w32.begin; - val64 = range_is_empty(&s->mch.pci_hole) - ? 0 : range_lob(&s->mch.pci_hole); - value = val64; - assert(value == val64); visit_type_uint32(v, name, &value, errp); } @@ -89,13 +83,8 @@ static void q35_host_get_pci_hole_end(Object *obj, Visitor *v, Error **errp) { Q35PCIHost *s = Q35_HOST_DEVICE(obj); - uint64_t val64; - uint32_t value; + uint32_t value = s->mch.pci_info.w32.end; - val64 = range_is_empty(&s->mch.pci_hole) - ? 0 : range_upb(&s->mch.pci_hole) + 1; - value = val64; - assert(value == val64); visit_type_uint32(v, name, &value, errp); } @@ -105,11 +94,10 @@ static void q35_host_get_pci_hole64_start(Object *obj, Visitor *v, { PCIHostState *h = PCI_HOST_BRIDGE(obj); Range w64; - uint64_t value; pci_bus_get_w64_range(h->bus, &w64); - value = range_is_empty(&w64) ? 0 : range_lob(&w64); - visit_type_uint64(v, name, &value, errp); + + visit_type_uint64(v, name, &w64.begin, errp); } static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v, @@ -118,11 +106,10 @@ static void q35_host_get_pci_hole64_end(Object *obj, Visitor *v, { PCIHostState *h = PCI_HOST_BRIDGE(obj); Range w64; - uint64_t value; pci_bus_get_w64_range(h->bus, &w64); - value = range_is_empty(&w64) ? 0 : range_upb(&w64) + 1; - visit_type_uint64(v, name, &value, errp); + + visit_type_uint64(v, name, &w64.end, errp); } static void q35_host_get_mmcfg_size(Object *obj, Visitor *v, const char *name, @@ -140,10 +127,6 @@ static Property mch_props[] = { DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, Q35PCIHost, mch.pci_hole64_size, DEFAULT_PCI_HOLE64_SIZE), DEFINE_PROP_UINT32("short_root_bus", Q35PCIHost, mch.short_root_bus, 0), - DEFINE_PROP_SIZE(PCI_HOST_BELOW_4G_MEM_SIZE, Q35PCIHost, - mch.below_4g_mem_size, 0), - DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MEM_SIZE, Q35PCIHost, - mch.above_4g_mem_size, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -155,8 +138,6 @@ static void q35_host_class_init(ObjectClass *klass, void *data) hc->root_bus_path = q35_host_root_bus_path; dc->realize = q35_host_realize; dc->props = mch_props; - /* Reason: needs to be wired up by pc_q35_init */ - dc->cannot_instantiate_with_device_add_yet = true; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->fw_name = "pci"; } @@ -196,30 +177,14 @@ static void q35_host_initfn(Object *obj) q35_host_get_mmcfg_size, NULL, NULL, NULL, NULL); - object_property_add_link(obj, MCH_HOST_PROP_RAM_MEM, TYPE_MEMORY_REGION, - (Object **) &s->mch.ram_memory, - qdev_prop_allow_set_link_before_realize, 0, NULL); - - object_property_add_link(obj, MCH_HOST_PROP_PCI_MEM, TYPE_MEMORY_REGION, - (Object **) &s->mch.pci_address_space, - qdev_prop_allow_set_link_before_realize, 0, NULL); - - object_property_add_link(obj, MCH_HOST_PROP_SYSTEM_MEM, TYPE_MEMORY_REGION, - (Object **) &s->mch.system_memory, - qdev_prop_allow_set_link_before_realize, 0, NULL); - - object_property_add_link(obj, MCH_HOST_PROP_IO_MEM, TYPE_MEMORY_REGION, - (Object **) &s->mch.address_space_io, - qdev_prop_allow_set_link_before_realize, 0, NULL); - /* Leave enough space for the biggest MCFG BAR */ /* TODO: this matches current bios behaviour, but * it's not a power of two, which means an MTRR * can't cover it exactly. */ - range_set_bounds(&s->mch.pci_hole, - MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT + MCH_HOST_BRIDGE_PCIEXBAR_MAX, - IO_APIC_DEFAULT_ADDRESS - 1); + s->mch.pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT + + MCH_HOST_BRIDGE_PCIEXBAR_MAX; + s->mch.pci_info.w32.end = IO_APIC_DEFAULT_ADDRESS; } static const TypeInfo q35_host_info = { @@ -287,7 +252,10 @@ static void mch_update_pciexbar(MCHPCIState *mch) break; case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD: default: + enable = 0; + length = 0; abort(); + break; } addr = pciexbar & addr_mask; pcie_host_mmcfg_update(pehb, enable, addr, length); @@ -297,13 +265,9 @@ static void mch_update_pciexbar(MCHPCIState *mch) * which means an MTRR can't cover it exactly. */ if (enable) { - range_set_bounds(&mch->pci_hole, - addr + length, - IO_APIC_DEFAULT_ADDRESS - 1); + mch->pci_info.w32.begin = addr + length; } else { - range_set_bounds(&mch->pci_hole, - MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT, - IO_APIC_DEFAULT_ADDRESS - 1); + mch->pci_info.w32.begin = MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT; } } @@ -460,6 +424,30 @@ static void mch_reset(DeviceState *qdev) mch_update(mch); } +static AddressSpace *q35_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) +{ + IntelIOMMUState *s = opaque; + VTDAddressSpace *vtd_as; + + assert(0 <= devfn && devfn <= VTD_PCI_DEVFN_MAX); + + vtd_as = vtd_find_add_as(s, bus, devfn); + return &vtd_as->as; +} + +static void mch_init_dmar(MCHPCIState *mch) +{ + PCIBus *pci_bus = PCI_BUS(qdev_get_parent_bus(DEVICE(mch))); + + mch->iommu = INTEL_IOMMU_DEVICE(qdev_create(NULL, TYPE_INTEL_IOMMU_DEVICE)); + object_property_add_child(OBJECT(mch), "intel-iommu", + OBJECT(mch->iommu), NULL); + qdev_init_nofail(DEVICE(mch->iommu)); + sysbus_mmio_map(SYS_BUS_DEVICE(mch->iommu), 0, Q35_HOST_BRIDGE_IOMMU_ADDR); + + pci_setup_iommu(pci_bus, q35_host_dma_iommu, mch->iommu); +} + static void mch_realize(PCIDevice *d, Error **errp) { int i; @@ -518,6 +506,10 @@ static void mch_realize(PCIDevice *d, Error **errp) mch->pci_address_space, &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE); } + /* Intel IOMMU (VT-d) */ + if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) { + mch_init_dmar(mch); + } } uint64_t mch_mcfg_base(void) diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index 7aac4d67a..15b105423 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -62,9 +62,12 @@ typedef struct UNINState { static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num) { + int retval; int devfn = pci_dev->devfn & 0x00FFFFFF; - return (((devfn >> 11) & 0x1F) + irq_num) & 3; + retval = (((devfn >> 11) & 0x1F) + irq_num) & 3; + + return retval; } static void pci_unin_set_irq(void *opaque, int irq_num, int level) diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c index 467cbb9cb..339ec2c50 100644 --- a/hw/pci-host/versatile.c +++ b/hw/pci-host/versatile.c @@ -13,7 +13,6 @@ #include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" #include "exec/address-spaces.h" -#include "qemu/log.h" /* Old and buggy versions of QEMU used the wrong mapping from * PCI IRQs to system interrupt lines. Unfortunately the Linux @@ -455,7 +454,6 @@ static void pci_vpb_realize(DeviceState *dev, Error **errp) } /* TODO Remove once realize propagates to child devices. */ - object_property_set_bool(OBJECT(&s->pci_bus), true, "realized", errp); object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp); } diff --git a/hw/pci/msi.c b/hw/pci/msi.c index a87b2278a..a87ef4d75 100644 --- a/hw/pci/msi.c +++ b/hw/pci/msi.c @@ -22,7 +22,6 @@ #include "hw/pci/msi.h" #include "hw/xen/xen.h" #include "qemu/range.h" -#include "qapi/error.h" /* PCI_MSI_ADDRESS_LO */ #define PCI_MSI_ADDRESS_LO_MASK (~0x3) @@ -166,25 +165,8 @@ bool msi_enabled(const PCIDevice *dev) PCI_MSI_FLAGS_ENABLE); } -/* - * Make PCI device @dev MSI-capable. - * Non-zero @offset puts capability MSI at that offset in PCI config - * space. - * @nr_vectors is the number of MSI vectors (1, 2, 4, 8, 16 or 32). - * If @msi64bit, make the device capable of sending a 64-bit message - * address. - * If @msi_per_vector_mask, make the device support per-vector masking. - * @errp is for returning errors. - * Return 0 on success; set @errp and return -errno on error. - * - * -ENOTSUP means lacking msi support for a msi-capable platform. - * -EINVAL means capability overlap, happens when @offset is non-zero, - * also means a programming error, except device assignment, which can check - * if a real HW is broken. - */ int msi_init(struct PCIDevice *dev, uint8_t offset, - unsigned int nr_vectors, bool msi64bit, - bool msi_per_vector_mask, Error **errp) + unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask) { unsigned int vectors_order; uint16_t flags; @@ -192,7 +174,6 @@ int msi_init(struct PCIDevice *dev, uint8_t offset, int config_offset; if (!msi_nonbroken) { - error_setg(errp, "MSI is not supported by interrupt controller"); return -ENOTSUP; } @@ -216,8 +197,7 @@ int msi_init(struct PCIDevice *dev, uint8_t offset, } cap_size = msi_cap_sizeof(flags); - config_offset = pci_add_capability2(dev, PCI_CAP_ID_MSI, offset, - cap_size, errp); + config_offset = pci_add_capability(dev, PCI_CAP_ID_MSI, offset, cap_size); if (config_offset < 0) { return config_offset; } @@ -240,8 +220,7 @@ int msi_init(struct PCIDevice *dev, uint8_t offset, pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit), 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors)); } - - return 0; + return config_offset; } void msi_uninit(struct PCIDevice *dev) diff --git a/hw/pci/msix.c b/hw/pci/msix.c index 0ec1cb14f..b75f0e9c4 100644 --- a/hw/pci/msix.c +++ b/hw/pci/msix.c @@ -72,7 +72,7 @@ void msix_set_pending(PCIDevice *dev, unsigned int vector) *msix_pending_byte(dev, vector) |= msix_pending_mask(vector); } -void msix_clr_pending(PCIDevice *dev, int vector) +static void msix_clr_pending(PCIDevice *dev, int vector) { *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector); } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 24fae1689..616f04c1f 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -80,37 +80,10 @@ static const VMStateDescription vmstate_pcibus = { } }; -static void pci_init_bus_master(PCIDevice *pci_dev) -{ - AddressSpace *dma_as = pci_device_iommu_address_space(pci_dev); - - memory_region_init_alias(&pci_dev->bus_master_enable_region, - OBJECT(pci_dev), "bus master", - dma_as->root, 0, memory_region_size(dma_as->root)); - memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); - address_space_init(&pci_dev->bus_master_as, - &pci_dev->bus_master_enable_region, pci_dev->name); -} - -static void pcibus_machine_done(Notifier *notifier, void *data) -{ - PCIBus *bus = container_of(notifier, PCIBus, machine_done); - int i; - - for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { - if (bus->devices[i]) { - pci_init_bus_master(bus->devices[i]); - } - } -} - static void pci_bus_realize(BusState *qbus, Error **errp) { PCIBus *bus = PCI_BUS(qbus); - bus->machine_done.notify = pcibus_machine_done; - qemu_add_machine_init_done_notifier(&bus->machine_done); - vmstate_register(NULL, -1, &vmstate_pcibus, bus); } @@ -118,8 +91,6 @@ static void pci_bus_unrealize(BusState *qbus, Error **errp) { PCIBus *bus = PCI_BUS(qbus); - qemu_remove_machine_init_done_notifier(&bus->machine_done); - vmstate_unregister(NULL, &vmstate_pcibus, bus); } @@ -867,81 +838,6 @@ static void do_pci_unregister_device(PCIDevice *pci_dev) address_space_destroy(&pci_dev->bus_master_as); } -/* Extract PCIReqIDCache into BDF format */ -static uint16_t pci_req_id_cache_extract(PCIReqIDCache *cache) -{ - uint8_t bus_n; - uint16_t result; - - switch (cache->type) { - case PCI_REQ_ID_BDF: - result = pci_get_bdf(cache->dev); - break; - case PCI_REQ_ID_SECONDARY_BUS: - bus_n = pci_bus_num(cache->dev->bus); - result = PCI_BUILD_BDF(bus_n, 0); - break; - default: - error_printf("Invalid PCI requester ID cache type: %d\n", - cache->type); - exit(1); - break; - } - - return result; -} - -/* Parse bridges up to the root complex and return requester ID - * cache for specific device. For full PCIe topology, the cache - * result would be exactly the same as getting BDF of the device. - * However, several tricks are required when system mixed up with - * legacy PCI devices and PCIe-to-PCI bridges. - * - * Here we cache the proxy device (and type) not requester ID since - * bus number might change from time to time. - */ -static PCIReqIDCache pci_req_id_cache_get(PCIDevice *dev) -{ - PCIDevice *parent; - PCIReqIDCache cache = { - .dev = dev, - .type = PCI_REQ_ID_BDF, - }; - - while (!pci_bus_is_root(dev->bus)) { - /* We are under PCI/PCIe bridges */ - parent = dev->bus->parent_dev; - if (pci_is_express(parent)) { - if (pcie_cap_get_type(parent) == PCI_EXP_TYPE_PCI_BRIDGE) { - /* When we pass through PCIe-to-PCI/PCIX bridges, we - * override the requester ID using secondary bus - * number of parent bridge with zeroed devfn - * (pcie-to-pci bridge spec chap 2.3). */ - cache.type = PCI_REQ_ID_SECONDARY_BUS; - cache.dev = dev; - } - } else { - /* Legacy PCI, override requester ID with the bridge's - * BDF upstream. When the root complex connects to - * legacy PCI devices (including buses), it can only - * obtain requester ID info from directly attached - * devices. If devices are attached under bridges, only - * the requester ID of the bridge that is directly - * attached to the root complex can be recognized. */ - cache.type = PCI_REQ_ID_BDF; - cache.dev = parent; - } - dev = parent; - } - - return cache; -} - -uint16_t pci_requester_id(PCIDevice *dev) -{ - return pci_req_id_cache_extract(&dev->requester_id_cache); -} - /* -1 for devfn means auto assign */ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, const char *name, int devfn, @@ -951,6 +847,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, PCIConfigReadFunc *config_read = pc->config_read; PCIConfigWriteFunc *config_write = pc->config_write; Error *local_err = NULL; + AddressSpace *dma_as; DeviceState *dev = DEVICE(pci_dev); pci_dev->bus = bus; @@ -990,11 +887,15 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, } pci_dev->devfn = devfn; - pci_dev->requester_id_cache = pci_req_id_cache_get(pci_dev); + dma_as = pci_device_iommu_address_space(pci_dev); + + memory_region_init_alias(&pci_dev->bus_master_enable_region, + OBJECT(pci_dev), "bus master", + dma_as->root, 0, memory_region_size(dma_as->root)); + memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); + address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region, + name); - if (qdev_hotplug) { - pci_init_bus_master(pci_dev); - } pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); pci_dev->irq_state = 0; pci_config_alloc(pci_dev); @@ -1076,7 +977,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, uint8_t type, MemoryRegion *memory) { PCIIORegion *r; - uint32_t addr; /* offset in pci config space */ + uint32_t addr; uint64_t wmask; pcibus_t size = memory_region_size(memory); @@ -1092,20 +993,15 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, r->addr = PCI_BAR_UNMAPPED; r->size = size; r->type = type; - r->memory = memory; - r->address_space = type & PCI_BASE_ADDRESS_SPACE_IO - ? pci_dev->bus->address_space_io - : pci_dev->bus->address_space_mem; + r->memory = NULL; wmask = ~(size - 1); + addr = pci_bar(pci_dev, region_num); if (region_num == PCI_ROM_SLOT) { /* ROM enable bit is writable */ wmask |= PCI_ROM_ADDRESS_ENABLE; } - - addr = pci_bar(pci_dev, region_num); pci_set_long(pci_dev->config + addr, type); - if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { pci_set_quad(pci_dev->wmask + addr, wmask); @@ -1114,6 +1010,11 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); pci_set_long(pci_dev->cmask + addr, 0xffffffff); } + pci_dev->io_regions[region_num].memory = memory; + pci_dev->io_regions[region_num].address_space + = type & PCI_BASE_ADDRESS_SPACE_IO + ? pci_dev->bus->address_space_io + : pci_dev->bus->address_space_mem; } static void pci_update_vga(PCIDevice *pci_dev) @@ -2253,8 +2154,10 @@ int pci_add_capability2(PCIDevice *pdev, uint8_t cap_id, if (!offset) { offset = pci_find_space(pdev, size); - /* out of PCI config space is programming error */ - assert(offset); + if (!offset) { + error_setg(errp, "out of PCI config space"); + return -ENOSPC; + } } else { /* Verify that capabilities don't overlap. Note: device assignment * depends on this check to verify that the device is not broken. @@ -2535,13 +2438,13 @@ static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque) if (limit >= base) { Range pref_range; - range_set_bounds(&pref_range, base, limit); + pref_range.begin = base; + pref_range.end = limit + 1; range_extend(range, &pref_range); } } for (i = 0; i < PCI_NUM_REGIONS; ++i) { PCIIORegion *r = &dev->io_regions[i]; - pcibus_t lob, upb; Range region_range; if (!r->size || @@ -2549,17 +2452,16 @@ static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque) !(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64)) { continue; } + region_range.begin = pci_bar_address(dev, i, r->type, r->size); + region_range.end = region_range.begin + r->size; - lob = pci_bar_address(dev, i, r->type, r->size); - upb = lob + r->size - 1; - if (lob == PCI_BAR_UNMAPPED) { + if (region_range.begin == PCI_BAR_UNMAPPED) { continue; } - lob = MAX(lob, 0x1ULL << 32); + region_range.begin = MAX(region_range.begin, 0x1ULL << 32); - if (upb >= lob) { - range_set_bounds(®ion_range, lob, upb); + if (region_range.end - 1 >= region_range.begin) { range_extend(range, ®ion_range); } } @@ -2567,7 +2469,7 @@ static void pci_dev_get_w64(PCIBus *b, PCIDevice *dev, void *opaque) void pci_bus_get_w64_range(PCIBus *bus, Range *range) { - range_make_empty(range); + range->begin = range->end = 0; pci_for_each_device_under_bus(bus, pci_dev_get_w64, range); } @@ -2598,21 +2500,6 @@ PCIDevice *pci_get_function_0(PCIDevice *pci_dev) } } -MSIMessage pci_get_msi_message(PCIDevice *dev, int vector) -{ - MSIMessage msg; - if (msix_enabled(dev)) { - msg = msix_get_message(dev, vector); - } else if (msi_enabled(dev)) { - msg = msi_get_message(dev, vector); - } else { - /* Should never happen */ - error_report("%s: unknown interrupt type", __func__); - abort(); - } - return msg; -} - static const TypeInfo pci_device_type_info = { .name = TYPE_PCI_DEVICE, .parent = TYPE_DEVICE, diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 99cfb4561..c85b4f7ae 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -43,18 +43,28 @@ /*************************************************************************** * pci express capability helper functions */ - -static void -pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version) +int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) { - uint8_t *exp_cap = dev->config + dev->exp.exp_cap; - uint8_t *cmask = dev->cmask + dev->exp.exp_cap; + int pos; + uint8_t *exp_cap; + uint8_t *cmask; + + assert(pci_is_express(dev)); + + pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, + PCI_EXP_VER2_SIZEOF); + if (pos < 0) { + return pos; + } + dev->exp.exp_cap = pos; + exp_cap = dev->config + pos; + cmask = dev->cmask + pos; /* capability register - interrupt message number defaults to 0 */ + interrupt message number defaults to 0 */ pci_set_word(exp_cap + PCI_EXP_FLAGS, ((type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE) | - version); + PCI_EXP_FLAGS_VER2); /* device capability register * table 7-12: @@ -84,27 +94,7 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version) * Let's not bother checking. */ pci_set_word(cmask + PCI_EXP_LNKSTA, 0); -} -int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) -{ - /* PCIe cap v2 init */ - int pos; - uint8_t *exp_cap; - - assert(pci_is_express(dev)); - - pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, PCI_EXP_VER2_SIZEOF); - if (pos < 0) { - return pos; - } - dev->exp.exp_cap = pos; - exp_cap = dev->config + pos; - - /* Filling values common with v1 */ - pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER2); - - /* Filling v2 specific values */ pci_set_long(exp_cap + PCI_EXP_DEVCAP2, PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP); @@ -112,27 +102,7 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) return pos; } -int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset, uint8_t type, - uint8_t port) -{ - /* PCIe cap v1 init */ - int pos; - - assert(pci_is_express(dev)); - - pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, PCI_EXP_VER1_SIZEOF); - if (pos < 0) { - return pos; - } - dev->exp.exp_cap = pos; - - pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER1); - - return pos; -} - -static int -pcie_endpoint_cap_common_init(PCIDevice *dev, uint8_t offset, uint8_t cap_size) +int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset) { uint8_t type = PCI_EXP_TYPE_ENDPOINT; @@ -145,19 +115,7 @@ pcie_endpoint_cap_common_init(PCIDevice *dev, uint8_t offset, uint8_t cap_size) type = PCI_EXP_TYPE_RC_END; } - return (cap_size == PCI_EXP_VER1_SIZEOF) - ? pcie_cap_v1_init(dev, offset, type, 0) - : pcie_cap_init(dev, offset, type, 0); -} - -int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset) -{ - return pcie_endpoint_cap_common_init(dev, offset, PCI_EXP_VER2_SIZEOF); -} - -int pcie_endpoint_cap_v1_init(PCIDevice *dev, uint8_t offset) -{ - return pcie_endpoint_cap_common_init(dev, offset, PCI_EXP_VER1_SIZEOF); + return pcie_cap_init(dev, offset, type, 0); } void pcie_cap_exit(PCIDevice *dev) @@ -165,11 +123,6 @@ void pcie_cap_exit(PCIDevice *dev) pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF); } -void pcie_cap_v1_exit(PCIDevice *dev) -{ - pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER1_SIZEOF); -} - uint8_t pcie_cap_get_type(const PCIDevice *dev) { uint32_t pos = dev->exp.exp_cap; @@ -707,13 +660,3 @@ void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn) offset, PCI_ARI_SIZEOF); pci_set_long(dev->config + offset + PCI_ARI_CAP, (nextfn & 0xff) << 8); } - -void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num) -{ - static const int pci_dsn_ver = 1; - static const int pci_dsn_cap = 4; - - pcie_add_capability(dev, PCI_EXT_CAP_ID_DSN, pci_dsn_ver, offset, - PCI_EXT_CAP_DSN_SIZEOF); - pci_set_quad(dev->config + offset + pci_dsn_cap, ser_num); -} diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c index 048ce6a42..e2d4e68ba 100644 --- a/hw/pci/pcie_aer.c +++ b/hw/pci/pcie_aer.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "sysemu/sysemu.h" #include "qapi/qmp/types.h" -#include "qapi/qmp/qjson.h" #include "monitor/monitor.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pcie.h" diff --git a/hw/pci/trace-events b/hw/pci/trace-events deleted file mode 100644 index 2b9cf2440..000000000 --- a/hw/pci/trace-events +++ /dev/null @@ -1,9 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/pci/pci.c -pci_update_mappings_del(void *d, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,%#"PRIx64"+%#"PRIx64 -pci_update_mappings_add(void *d, uint32_t bus, uint32_t slot, uint32_t func, int bar, uint64_t addr, uint64_t size) "d=%p %02x:%02x.%x %d,%#"PRIx64"+%#"PRIx64 - -# hw/pci/pci_host.c -pci_cfg_read(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x -> 0x%x" -pci_cfg_write(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x <- 0x%x" diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 91a3420f4..c1ffc7771 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -4,11 +4,9 @@ obj-y += ppc.o ppc_booke.o obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o -obj-$(CONFIG_PSERIES) += spapr_cpu_core.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) obj-y += spapr_pci_vfio.o endif -obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o # PowerPC 4xx boards obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o obj-y += ppc4xx_pci.o diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 0cd534df5..ee1c60b82 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -601,7 +601,7 @@ static int ppce500_prep_device_tree(MachineState *machine, } /* Create -kernel TLB entries for BookE. */ -hwaddr booke206_page_size_to_tlb(uint64_t size) +static inline hwaddr booke206_page_size_to_tlb(uint64_t size) { return 63 - clz64(size >> 10); } diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index 70ba1d8f4..ef224ea5e 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -26,6 +26,4 @@ typedef struct PPCE500Params { void ppce500_init(MachineState *machine, PPCE500Params *params); -hwaddr booke206_page_size_to_tlb(uint64_t size); - #endif diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 94b454551..b00565c3d 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -14,7 +14,6 @@ #include "e500.h" #include "hw/boards.h" #include "sysemu/device_tree.h" -#include "sysemu/kvm.h" #include "hw/pci/pci.h" #include "hw/ppc/openpic.h" #include "kvm_ppc.h" diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 20cbddb4e..5764b86c2 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -22,9 +22,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - -#ifndef PPC_MAC_H -#define PPC_MAC_H +#if !defined(__PPC_MAC_H__) +#define __PPC_MAC_H__ #include "exec/memory.h" #include "hw/sysbus.h" @@ -185,4 +184,4 @@ typedef struct MacIONVRAMState { } MacIONVRAMState; void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); -#endif /* PPC_MAC_H */ +#endif /* !defined(__PPC_MAC_H__) */ diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 7d2510658..32e88b378 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -380,7 +380,6 @@ static void ppc_core99_init(MachineState *machine) pci_bus = pci_pmac_init(pic, get_system_memory(), get_system_io()); machine_arch = ARCH_MAC99; } - object_property_set_bool(OBJECT(pci_bus), true, "realized", &error_abort); machine->usb |= defaults_enabled() && !machine->usb_disabled; diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 447948746..a9bb1c27d 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -309,7 +309,7 @@ static void ppc_heathrow_init(MachineState *machine) dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); qdev_init_nofail(dev); - if (machine_usb(machine)) { + if (usb_enabled()) { pci_create_simple(pci_bus, -1, "pci-ohci"); } diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 894586900..38ff2e159 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -33,7 +33,6 @@ #include "hw/timer/m48t59.h" #include "qemu/log.h" #include "qemu/error-report.h" -#include "qapi/error.h" #include "hw/loader.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" @@ -165,9 +164,9 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level) } } -void ppc6xx_irq_init(PowerPCCPU *cpu) +void ppc6xx_irq_init(CPUPPCState *env) { - CPUPPCState *env = &cpu->env; + PowerPCCPU *cpu = ppc_env_get_cpu(env); env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu, PPC6xx_INPUT_NB); @@ -252,9 +251,9 @@ static void ppc970_set_irq(void *opaque, int pin, int level) } } -void ppc970_irq_init(PowerPCCPU *cpu) +void ppc970_irq_init(CPUPPCState *env) { - CPUPPCState *env = &cpu->env; + PowerPCCPU *cpu = ppc_env_get_cpu(env); env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu, PPC970_INPUT_NB); @@ -288,9 +287,9 @@ static void power7_set_irq(void *opaque, int pin, int level) } } -void ppcPOWER7_irq_init(PowerPCCPU *cpu) +void ppcPOWER7_irq_init(CPUPPCState *env) { - CPUPPCState *env = &cpu->env; + PowerPCCPU *cpu = ppc_env_get_cpu(env); env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu, POWER7_INPUT_NB); @@ -373,9 +372,9 @@ static void ppc40x_set_irq(void *opaque, int pin, int level) } } -void ppc40x_irq_init(PowerPCCPU *cpu) +void ppc40x_irq_init(CPUPPCState *env) { - CPUPPCState *env = &cpu->env; + PowerPCCPU *cpu = ppc_env_get_cpu(env); env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, cpu, PPC40x_INPUT_NB); @@ -437,9 +436,9 @@ static void ppce500_set_irq(void *opaque, int pin, int level) } } -void ppce500_irq_init(PowerPCCPU *cpu) +void ppce500_irq_init(CPUPPCState *env) { - CPUPPCState *env = &cpu->env; + PowerPCCPU *cpu = ppc_env_get_cpu(env); env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq, cpu, PPCE500_INPUT_NB); @@ -700,18 +699,9 @@ static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu) static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) { - CPUPPCState *env = &cpu->env; - /* Raise it */ - LOG_TB("raise hv decrementer exception\n"); - - /* The architecture specifies that we don't deliver HDEC - * interrupts in a PM state. Not only they don't cause a - * wakeup but they also get effectively discarded. - */ - if (!env->in_pm_state) { - ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); - } + LOG_TB("raise decrementer exception\n"); + ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1); } static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu) @@ -890,7 +880,7 @@ static int timebase_post_load(void *opaque, int version_id) host_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST); ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns); migration_duration_ns = MIN(NANOSECONDS_PER_SECOND, ns_diff); - migration_duration_tb = muldiv64(freq, migration_duration_ns, + migration_duration_tb = muldiv64(migration_duration_ns, freq, NANOSECONDS_PER_SECOND); guest_tb = tb_remote->guest_timebase + MIN(0, migration_duration_tb); @@ -938,7 +928,9 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq) } /* Create new timer */ tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu); - if (env->has_hv_mode) { + if (0) { + /* XXX: find a suitable condition to enable the hypervisor decrementer + */ tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb, cpu); } else { @@ -1351,28 +1343,3 @@ PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id) return NULL; } - -void ppc_cpu_parse_features(const char *cpu_model) -{ - CPUClass *cc; - ObjectClass *oc; - const char *typename; - gchar **model_pieces; - - model_pieces = g_strsplit(cpu_model, ",", 2); - if (!model_pieces[0]) { - error_report("Invalid/empty CPU model name"); - exit(1); - } - - oc = cpu_class_by_name(TYPE_POWERPC_CPU, model_pieces[0]); - if (oc == NULL) { - error_report("Unable to find CPU definition: %s", model_pieces[0]); - exit(1); - } - - typename = object_class_get_name(oc); - cc = CPU_CLASS(oc); - cc->parse_features(typename, model_pieces[1], &error_fatal); - g_strfreev(model_pieces); -} diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h index c67febca2..1c5f04fae 100644 --- a/hw/ppc/ppc405.h +++ b/hw/ppc/ppc405.h @@ -22,8 +22,8 @@ * THE SOFTWARE. */ -#ifndef PPC405_H -#define PPC405_H +#if !defined(PPC_405_H) +#define PPC_405_H #include "hw/ppc/ppc4xx.h" @@ -78,4 +78,4 @@ CPUPPCState *ppc_stb025_init (MemoryRegion ram_memories[2], uint32_t sysclk, qemu_irq **picp, ram_addr_t *offsetp); -#endif /* PPC405_H */ +#endif /* !defined(PPC_405_H) */ diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index e7f413e49..7d59018fc 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "cpu.h" #include "hw/hw.h" #include "hw/ppc/ppc.h" #include "hw/ppc/ppc4xx.h" diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c index 22c584eb8..76bd78bfd 100644 --- a/hw/ppc/ppce500_spin.c +++ b/hw/ppc/ppce500_spin.c @@ -32,7 +32,6 @@ #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "sysemu/kvm.h" -#include "e500.h" #define MAX_CPUS 32 @@ -73,6 +72,12 @@ static void spin_reset(void *opaque) } } +/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ +static inline hwaddr booke206_page_size_to_tlb(uint64_t size) +{ + return ctz32(size >> 10) >> 1; +} + static void mmubooke_create_initial_mapping(CPUPPCState *env, target_ulong va, hwaddr pa, @@ -99,7 +104,7 @@ static void spin_kick(void *data) hwaddr map_start; cpu_synchronize_state(cpu); - stl_p(&curspin->pir, env->spr[SPR_BOOKE_PIR]); + stl_p(&curspin->pir, env->spr[SPR_PIR]); env->nip = ldq_p(&curspin->addr) & (map_size - 1); env->gpr[3] = ldq_p(&curspin->r3); env->gpr[4] = 0; diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 054af1e8b..3ffb85e60 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "cpu.h" #include "hw/hw.h" #include "hw/timer/m48t59.h" #include "hw/i386/pc.h" @@ -649,7 +648,7 @@ static void ppc_prep_init(MachineState *machine) memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr); #endif - if (machine_usb(machine)) { + if (usb_enabled()) { pci_create_simple(pci_bus, -1, "pci-ohci"); } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 30d6800ab..b69995e0d 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -29,7 +29,6 @@ #include "sysemu/sysemu.h" #include "sysemu/numa.h" #include "hw/hw.h" -#include "qemu/log.h" #include "hw/fw-path-provider.h" #include "elf.h" #include "net/net.h" @@ -66,8 +65,6 @@ #include "hw/compat.h" #include "qemu/cutils.h" -#include "hw/ppc/spapr_cpu_core.h" -#include "qmp-commands.h" #include <libfdt.h> @@ -91,6 +88,8 @@ #define MIN_RMA_SLOF 128UL +#define TIMEBASE_FREQ 512000000ULL + #define PHANDLE_XICP 0x00001111 #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) @@ -116,16 +115,15 @@ static XICSState *try_create_xics(const char *type, int nr_servers, static XICSState *xics_system_init(MachineState *machine, int nr_servers, int nr_irqs, Error **errp) { - XICSState *xics = NULL; + XICSState *icp = NULL; if (kvm_enabled()) { Error *err = NULL; if (machine_kernel_irqchip_allowed(machine)) { - xics = try_create_xics(TYPE_XICS_SPAPR_KVM, nr_servers, nr_irqs, - &err); + icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs, &err); } - if (machine_kernel_irqchip_required(machine) && !xics) { + if (machine_kernel_irqchip_required(machine) && !icp) { error_reportf_err(err, "kernel_irqchip requested but unavailable: "); } else { @@ -133,11 +131,11 @@ static XICSState *xics_system_init(MachineState *machine, } } - if (!xics) { - xics = try_create_xics(TYPE_XICS_SPAPR, nr_servers, nr_irqs, errp); + if (!icp) { + icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs, errp); } - return xics; + return icp; } static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, @@ -340,9 +338,6 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base, add_str(hypertas, "hcall-splpar"); add_str(hypertas, "hcall-bulk"); add_str(hypertas, "hcall-set-mode"); - add_str(hypertas, "hcall-sprg0"); - add_str(hypertas, "hcall-copy"); - add_str(hypertas, "hcall-debug"); add_str(qemu_hypertas, "hcall-memop1"); fdt = g_malloc0(FDT_MAX_SIZE); @@ -603,23 +598,12 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, int index = ppc_get_vcpu_dt_id(cpu); uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 0xffffffff, 0xffffffff}; - uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() - : SPAPR_TIMEBASE_FREQ; + uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ; uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000; uint32_t page_sizes_prop[64]; size_t page_sizes_prop_size; uint32_t vcpus_per_socket = smp_threads * smp_cores; uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; - sPAPRDRConnector *drc; - sPAPRDRConnectorClass *drck; - int drc_index; - - drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index); - if (drc) { - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - drc_index = drck->get_index(drc); - _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index))); - } /* Note: we keep CI large pages off for now because a 64K capable guest * provisioned with large pages might otherwise try to map a qemu @@ -777,17 +761,14 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) int ret, i, offset; uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE; uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)}; - uint32_t hotplug_lmb_start = spapr->hotplug_memory.base / lmb_size; - uint32_t nr_lmbs = (spapr->hotplug_memory.base + - memory_region_size(&spapr->hotplug_memory.mr)) / - lmb_size; + uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size; uint32_t *int_buf, *cur_index, buf_len; int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1; /* - * Don't create the node if there is no hotpluggable memory + * Don't create the node if there are no DR LMBs. */ - if (machine->ram_size == machine->maxram_size) { + if (!nr_lmbs) { return 0; } @@ -821,40 +802,26 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) int_buf[0] = cpu_to_be32(nr_lmbs); cur_index++; for (i = 0; i < nr_lmbs; i++) { - uint64_t addr = i * lmb_size; + sPAPRDRConnector *drc; + sPAPRDRConnectorClass *drck; + uint64_t addr = i * lmb_size + spapr->hotplug_memory.base;; uint32_t *dynamic_memory = cur_index; - if (i >= hotplug_lmb_start) { - sPAPRDRConnector *drc; - sPAPRDRConnectorClass *drck; - - drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB, i); - g_assert(drc); - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - - dynamic_memory[0] = cpu_to_be32(addr >> 32); - dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff); - dynamic_memory[2] = cpu_to_be32(drck->get_index(drc)); - dynamic_memory[3] = cpu_to_be32(0); /* reserved */ - dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL)); - if (memory_region_present(get_system_memory(), addr)) { - dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED); - } else { - dynamic_memory[5] = cpu_to_be32(0); - } + drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB, + addr/lmb_size); + g_assert(drc); + drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); + + dynamic_memory[0] = cpu_to_be32(addr >> 32); + dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff); + dynamic_memory[2] = cpu_to_be32(drck->get_index(drc)); + dynamic_memory[3] = cpu_to_be32(0); /* reserved */ + dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL)); + if (addr < machine->ram_size || + memory_region_present(get_system_memory(), addr)) { + dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED); } else { - /* - * LMB information for RMA, boot time RAM and gap b/n RAM and - * hotplug memory region -- all these are marked as reserved - * and as having no valid DRC. - */ - dynamic_memory[0] = cpu_to_be32(addr >> 32); - dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff); - dynamic_memory[2] = cpu_to_be32(0); - dynamic_memory[3] = cpu_to_be32(0); /* reserved */ - dynamic_memory[4] = cpu_to_be32(-1); - dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED | - SPAPR_LMB_FLAGS_DRC_INVALID); + dynamic_memory[5] = cpu_to_be32(0); } cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE; @@ -938,7 +905,6 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr, hwaddr rtas_size) { MachineState *machine = MACHINE(qdev_get_machine()); - MachineClass *mc = MACHINE_GET_CLASS(machine); sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); const char *boot_device = machine->boot_order; int ret, i; @@ -1021,16 +987,6 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr, _FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB)); } - if (mc->query_hotpluggable_cpus) { - int offset = fdt_path_offset(fdt, "/cpus"); - ret = spapr_drc_populate_dt(fdt, offset, NULL, - SPAPR_DR_CONNECTOR_TYPE_CPU); - if (ret < 0) { - error_report("Couldn't set up CPU DR device tree properties"); - exit(1); - } - } - _FDT((fdt_pack(fdt))); if (fdt_totalsize(fdt) > FDT_MAX_SIZE) { @@ -1224,6 +1180,26 @@ static void ppc_spapr_reset(void) } +static void spapr_cpu_reset(void *opaque) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); + PowerPCCPU *cpu = opaque; + CPUState *cs = CPU(cpu); + CPUPPCState *env = &cpu->env; + + cpu_reset(cs); + + /* All CPUs start halted. CPU0 is unhalted from the machine level + * reset code and the rest are explicitly started up by the guest + * using an RTAS call */ + cs->halted = 1; + + env->spr[SPR_HIOR] = 0; + + ppc_hash64_set_external_hpt(cpu, spapr->htab, spapr->htab_shift, + &error_fatal); +} + static void spapr_create_nvram(sPAPRMachineState *spapr) { DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); @@ -1513,6 +1489,7 @@ static int htab_save_complete(QEMUFile *f, void *opaque) if (rc < 0) { return rc; } + close_htab_fd(spapr); } else { if (spapr->htab_first_pass) { htab_save_first_pass(f, spapr, -1); @@ -1614,18 +1591,10 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void htab_cleanup(void *opaque) -{ - sPAPRMachineState *spapr = opaque; - - close_htab_fd(spapr); -} - static SaveVMHandlers savevm_htab_handlers = { .save_live_setup = htab_save_setup, .save_live_iterate = htab_save_iterate, .save_live_complete_precopy = htab_save_complete, - .cleanup = htab_cleanup, .load_state = htab_load, }; @@ -1636,6 +1605,32 @@ static void spapr_boot_set(void *opaque, const char *boot_device, machine->boot_order = g_strdup(boot_device); } +static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, + Error **errp) +{ + CPUPPCState *env = &cpu->env; + + /* Set time-base frequency to 512 MHz */ + cpu_ppc_tb_init(env, TIMEBASE_FREQ); + + /* Enable PAPR mode in TCG or KVM */ + cpu_ppc_set_papr(cpu); + + if (cpu->max_compat) { + Error *local_err = NULL; + + ppc_set_compat(cpu, cpu->max_compat, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + } + + xics_cpu_setup(spapr->icp, cpu); + + qemu_register_reset(spapr_cpu_reset, cpu); +} + /* * Reset routine for LMB DR devices. * @@ -1713,11 +1708,11 @@ static void spapr_validate_node_memory(MachineState *machine, Error **errp) static void ppc_spapr_init(MachineState *machine) { sPAPRMachineState *spapr = SPAPR_MACHINE(machine); - MachineClass *mc = MACHINE_GET_CLASS(machine); sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; + PowerPCCPU *cpu; PCIHostState *phb; int i; MemoryRegion *sysmem = get_system_memory(); @@ -1731,22 +1726,6 @@ static void ppc_spapr_init(MachineState *machine) long load_limit, fw_size; bool kernel_le = false; char *filename; - int smt = kvmppc_smt_threads(); - int spapr_cores = smp_cpus / smp_threads; - int spapr_max_cores = max_cpus / smp_threads; - - if (mc->query_hotpluggable_cpus) { - if (smp_cpus % smp_threads) { - error_report("smp_cpus (%u) must be multiple of threads (%u)", - smp_cpus, smp_threads); - exit(1); - } - if (max_cpus % smp_threads) { - error_report("max_cpus (%u) must be multiple of threads (%u)", - max_cpus, smp_threads); - exit(1); - } - } msi_nonbroken = true; @@ -1780,13 +1759,6 @@ static void ppc_spapr_init(MachineState *machine) spapr->vrma_adjust = 1; spapr->rma_size = MIN(spapr->rma_size, 0x10000000); } - - /* Actually we don't support unbounded RMA anymore since we - * added proper emulation of HV mode. The max we can get is - * 16G which also happens to be what we configure for PAPR - * mode so make sure we don't do anything bigger than that - */ - spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull); } if (spapr->rma_size > node0_size) { @@ -1799,9 +1771,10 @@ static void ppc_spapr_init(MachineState *machine) load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD; /* Set up Interrupt Controller before we create the VCPUs */ - spapr->xics = xics_system_init(machine, - DIV_ROUND_UP(max_cpus * smt, smp_threads), - XICS_IRQS_SPAPR, &error_fatal); + spapr->icp = xics_system_init(machine, + DIV_ROUND_UP(max_cpus * kvmppc_smt_threads(), + smp_threads), + XICS_IRQS, &error_fatal); if (smc->dr_lmb_enabled) { spapr_validate_node_memory(machine, &error_fatal); @@ -1811,46 +1784,13 @@ static void ppc_spapr_init(MachineState *machine) if (machine->cpu_model == NULL) { machine->cpu_model = kvm_enabled() ? "host" : "POWER7"; } - - ppc_cpu_parse_features(machine->cpu_model); - - if (mc->query_hotpluggable_cpus) { - char *type = spapr_get_cpu_core_type(machine->cpu_model); - - if (type == NULL) { - error_report("Unable to find sPAPR CPU Core definition"); + for (i = 0; i < smp_cpus; i++) { + cpu = cpu_ppc_init(machine->cpu_model); + if (cpu == NULL) { + error_report("Unable to find PowerPC CPU definition"); exit(1); } - - spapr->cores = g_new0(Object *, spapr_max_cores); - for (i = 0; i < spapr_max_cores; i++) { - int core_id = i * smp_threads; - sPAPRDRConnector *drc = - spapr_dr_connector_new(OBJECT(spapr), - SPAPR_DR_CONNECTOR_TYPE_CPU, - (core_id / smp_threads) * smt); - - qemu_register_reset(spapr_drc_reset, drc); - - if (i < spapr_cores) { - Object *core = object_new(type); - object_property_set_int(core, smp_threads, "nr-threads", - &error_fatal); - object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID, - &error_fatal); - object_property_set_bool(core, true, "realized", &error_fatal); - } - } - g_free(type); - } else { - for (i = 0; i < smp_cpus; i++) { - PowerPCCPU *cpu = cpu_ppc_init(machine->cpu_model); - if (cpu == NULL) { - error_report("Unable to find PowerPC CPU definition"); - exit(1); - } - spapr_cpu_init(spapr, cpu, &error_fatal); - } + spapr_cpu_init(spapr, cpu, &error_fatal); } if (kvm_enabled()) { @@ -1875,21 +1815,11 @@ static void ppc_spapr_init(MachineState *machine) /* initialize hotplug memory address space */ if (machine->ram_size < machine->maxram_size) { ram_addr_t hotplug_mem_size = machine->maxram_size - machine->ram_size; - /* - * Limit the number of hotpluggable memory slots to half the number - * slots that KVM supports, leaving the other half for PCI and other - * devices. However ensure that number of slots doesn't drop below 32. - */ - int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 : - SPAPR_MAX_RAM_SLOTS; - if (max_memslots < SPAPR_MAX_RAM_SLOTS) { - max_memslots = SPAPR_MAX_RAM_SLOTS; - } - if (machine->ram_slots > max_memslots) { + if (machine->ram_slots > SPAPR_MAX_RAM_SLOTS) { error_report("Specified number of memory slots %" PRIu64" exceeds max supported %d", - machine->ram_slots, max_memslots); + machine->ram_slots, SPAPR_MAX_RAM_SLOTS); exit(1); } @@ -1911,10 +1841,6 @@ static void ppc_spapr_init(MachineState *machine) exit(1); } spapr->rtas_size = get_image_size(filename); - if (spapr->rtas_size < 0) { - error_report("Could not get size of LPAR rtas '%s'", filename); - exit(1); - } spapr->rtas_blob = g_malloc(spapr->rtas_size); if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) { error_report("Could not load LPAR rtas '%s'", filename); @@ -2205,6 +2131,15 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr, uint64_t size, int i, fdt_offset, fdt_size; void *fdt; + /* + * Check for DRC connectors and send hotplug notification to the + * guest only in case of hotplugged memory. This allows cold plugged + * memory to be specified at boot time. + */ + if (!dev->hotplugged) { + return; + } + for (i = 0; i < nr_lmbs; i++) { drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB, addr/SPAPR_MEMORY_BLOCK_SIZE); @@ -2218,12 +2153,7 @@ static void spapr_add_lmbs(DeviceState *dev, uint64_t addr, uint64_t size, drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp); addr += SPAPR_MEMORY_BLOCK_SIZE; } - /* send hotplug notification to the - * guest only in case of hotplugged memory - */ - if (dev->hotplugged) { - spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs); - } + spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs); } static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, @@ -2261,27 +2191,6 @@ out: error_propagate(errp, local_err); } -void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset, - sPAPRMachineState *spapr) -{ - PowerPCCPU *cpu = POWERPC_CPU(cs); - DeviceClass *dc = DEVICE_GET_CLASS(cs); - int id = ppc_get_vcpu_dt_id(cpu); - void *fdt; - int offset, fdt_size; - char *nodename; - - fdt = create_device_tree(&fdt_size); - nodename = g_strdup_printf("%s@%x", dc->fw_name, id); - offset = fdt_add_subnode(fdt, 0, nodename); - - spapr_populate_cpu_dt(cs, fdt, offset, spapr); - g_free(nodename); - - *fdt_offset = offset; - return fdt; -} - static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -2326,40 +2235,21 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, } spapr_memory_plug(hotplug_dev, dev, node, errp); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { - spapr_core_plug(hotplug_dev, dev, errp); } } static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { error_setg(errp, "Memory hot unplug not supported by sPAPR"); - } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { - if (!mc->query_hotpluggable_cpus) { - error_setg(errp, "CPU hot unplug not supported on this machine"); - return; - } - spapr_core_unplug(hotplug_dev, dev, errp); - } -} - -static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { - spapr_core_pre_plug(hotplug_dev, dev, errp); } } static HotplugHandler *spapr_get_hotpug_handler(MachineState *machine, DeviceState *dev) { - if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) || - object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) { + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { return HOTPLUG_HANDLER(machine); } return NULL; @@ -2372,37 +2262,6 @@ static unsigned spapr_cpu_index_to_socket_id(unsigned cpu_index) return cpu_index / smp_threads / smp_cores; } -static HotpluggableCPUList *spapr_query_hotpluggable_cpus(MachineState *machine) -{ - int i; - HotpluggableCPUList *head = NULL; - sPAPRMachineState *spapr = SPAPR_MACHINE(machine); - int spapr_max_cores = max_cpus / smp_threads; - - for (i = 0; i < spapr_max_cores; i++) { - HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1); - HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1); - CpuInstanceProperties *cpu_props = g_new0(typeof(*cpu_props), 1); - - cpu_item->type = spapr_get_cpu_core_type(machine->cpu_model); - cpu_item->vcpus_count = smp_threads; - cpu_props->has_core_id = true; - cpu_props->core_id = i * smp_threads; - /* TODO: add 'has_node/node' here to describe - to which node core belongs */ - - cpu_item->props = cpu_props; - if (spapr->cores[i]) { - cpu_item->has_qom_path = true; - cpu_item->qom_path = object_get_canonical_path(spapr->cores[i]); - } - list_item->value = cpu_item; - list_item->next = head; - head = list_item; - } - return head; -} - static void spapr_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -2429,13 +2288,11 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->has_dynamic_sysbus = true; mc->pci_allow_0_address = true; mc->get_hotplug_handler = spapr_get_hotpug_handler; - hc->pre_plug = spapr_machine_device_pre_plug; hc->plug = spapr_machine_device_plug; hc->unplug = spapr_machine_device_unplug; mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id; smc->dr_lmb_enabled = true; - mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; } @@ -2486,42 +2343,18 @@ static const TypeInfo spapr_machine_info = { type_init(spapr_machine_register_##suffix) /* - * pseries-2.7 - */ -static void spapr_machine_2_7_instance_options(MachineState *machine) -{ -} - -static void spapr_machine_2_7_class_options(MachineClass *mc) -{ - /* Defaults for the latest behaviour inherited from the base class */ -} - -DEFINE_SPAPR_MACHINE(2_7, "2.7", true); - -/* * pseries-2.6 */ -#define SPAPR_COMPAT_2_6 \ - HW_COMPAT_2_6 \ - { \ - .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\ - .property = "ddw",\ - .value = stringify(off),\ - }, - static void spapr_machine_2_6_instance_options(MachineState *machine) { } static void spapr_machine_2_6_class_options(MachineClass *mc) { - spapr_machine_2_7_class_options(mc); - mc->query_hotpluggable_cpus = NULL; - SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_6); + /* Defaults for the latest behaviour inherited from the base class */ } -DEFINE_SPAPR_MACHINE(2_6, "2.6", false); +DEFINE_SPAPR_MACHINE(2_6, "2.6", true); /* * pseries-2.5 @@ -2553,6 +2386,7 @@ DEFINE_SPAPR_MACHINE(2_5, "2.5", false); * pseries-2.4 */ #define SPAPR_COMPAT_2_4 \ + SPAPR_COMPAT_2_5 \ HW_COMPAT_2_4 static void spapr_machine_2_4_instance_options(MachineState *machine) @@ -2575,6 +2409,7 @@ DEFINE_SPAPR_MACHINE(2_4, "2.4", false); * pseries-2.3 */ #define SPAPR_COMPAT_2_3 \ + SPAPR_COMPAT_2_4 \ HW_COMPAT_2_3 \ {\ .driver = "spapr-pci-host-bridge",\ @@ -2602,6 +2437,7 @@ DEFINE_SPAPR_MACHINE(2_3, "2.3", false); */ #define SPAPR_COMPAT_2_2 \ + SPAPR_COMPAT_2_3 \ HW_COMPAT_2_2 \ {\ .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\ @@ -2626,6 +2462,7 @@ DEFINE_SPAPR_MACHINE(2_2, "2.2", false); * pseries-2.1 */ #define SPAPR_COMPAT_2_1 \ + SPAPR_COMPAT_2_2 \ HW_COMPAT_2_1 static void spapr_machine_2_1_instance_options(MachineState *machine) diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c deleted file mode 100644 index bcb483dbe..000000000 --- a/hw/ppc/spapr_cpu_core.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * sPAPR CPU core device, acts as container of CPU thread devices. - * - * Copyright (C) 2016 Bharata B Rao <bharata@linux.vnet.ibm.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 "hw/cpu/core.h" -#include "hw/ppc/spapr_cpu_core.h" -#include "target-ppc/cpu.h" -#include "hw/ppc/spapr.h" -#include "hw/boards.h" -#include "qapi/error.h" -#include "sysemu/cpus.h" -#include "target-ppc/kvm_ppc.h" -#include "hw/ppc/ppc.h" -#include "target-ppc/mmu-hash64.h" -#include "sysemu/numa.h" - -static void spapr_cpu_reset(void *opaque) -{ - sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - PowerPCCPU *cpu = opaque; - CPUState *cs = CPU(cpu); - CPUPPCState *env = &cpu->env; - - cpu_reset(cs); - - /* All CPUs start halted. CPU0 is unhalted from the machine level - * reset code and the rest are explicitly started up by the guest - * using an RTAS call */ - cs->halted = 1; - - env->spr[SPR_HIOR] = 0; - - ppc_hash64_set_external_hpt(cpu, spapr->htab, spapr->htab_shift, - &error_fatal); -} - -static void spapr_cpu_destroy(PowerPCCPU *cpu) -{ - sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - - xics_cpu_destroy(spapr->xics, cpu); - qemu_unregister_reset(spapr_cpu_reset, cpu); -} - -void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, Error **errp) -{ - CPUPPCState *env = &cpu->env; - CPUState *cs = CPU(cpu); - int i; - - /* Set time-base frequency to 512 MHz */ - cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); - - /* Enable PAPR mode in TCG or KVM */ - cpu_ppc_set_papr(cpu); - - if (cpu->max_compat) { - Error *local_err = NULL; - - ppc_set_compat(cpu, cpu->max_compat, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } - - /* Set NUMA node for the added CPUs */ - for (i = 0; i < nb_numa_nodes; i++) { - if (test_bit(cs->cpu_index, numa_info[i].node_cpu)) { - cs->numa_node = i; - break; - } - } - - xics_cpu_setup(spapr->xics, cpu); - - qemu_register_reset(spapr_cpu_reset, cpu); - spapr_cpu_reset(cpu); -} - -/* - * Return the sPAPR CPU core type for @model which essentially is the CPU - * model specified with -cpu cmdline option. - */ -char *spapr_get_cpu_core_type(const char *model) -{ - char *core_type; - gchar **model_pieces = g_strsplit(model, ",", 2); - - core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE); - g_strfreev(model_pieces); - - /* Check whether it exists or whether we have to look up an alias name */ - if (!object_class_by_name(core_type)) { - const char *realmodel; - - g_free(core_type); - realmodel = ppc_cpu_lookup_alias(model); - if (realmodel) { - return spapr_get_cpu_core_type(realmodel); - } - return NULL; - } - - return core_type; -} - -static void spapr_core_release(DeviceState *dev, void *opaque) -{ - sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); - const char *typename = object_class_get_name(sc->cpu_class); - size_t size = object_type_get_instance_size(typename); - sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - CPUCore *cc = CPU_CORE(dev); - int i; - - for (i = 0; i < cc->nr_threads; i++) { - void *obj = sc->threads + i * size; - DeviceState *dev = DEVICE(obj); - CPUState *cs = CPU(dev); - PowerPCCPU *cpu = POWERPC_CPU(cs); - - spapr_cpu_destroy(cpu); - cpu_remove_sync(cs); - object_unparent(obj); - } - - spapr->cores[cc->core_id / smp_threads] = NULL; - - g_free(sc->threads); - object_unparent(OBJECT(dev)); -} - -void spapr_core_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) -{ - CPUCore *cc = CPU_CORE(dev); - int smt = kvmppc_smt_threads(); - int index = cc->core_id / smp_threads; - sPAPRDRConnector *drc = - spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt); - sPAPRDRConnectorClass *drck; - Error *local_err = NULL; - - if (index == 0) { - error_setg(errp, "Boot CPU core may not be unplugged"); - return; - } - - g_assert(drc); - - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - drck->detach(drc, dev, spapr_core_release, NULL, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_hotplug_req_remove_by_index(drc); -} - -void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) -{ - sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); - sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); - CPUCore *cc = CPU_CORE(dev); - CPUState *cs = CPU(core->threads); - sPAPRDRConnector *drc; - sPAPRDRConnectorClass *drck; - Error *local_err = NULL; - void *fdt = NULL; - int fdt_offset = 0; - int index = cc->core_id / smp_threads; - int smt = kvmppc_smt_threads(); - - drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index * smt); - spapr->cores[index] = OBJECT(dev); - - g_assert(drc); - - /* - * Setup CPU DT entries only for hotplugged CPUs. For boot time or - * coldplugged CPUs DT entries are setup in spapr_finalize_fdt(). - */ - if (dev->hotplugged) { - fdt = spapr_populate_hotplug_cpu_dt(cs, &fdt_offset, spapr); - } - - drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); - drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, &local_err); - if (local_err) { - g_free(fdt); - spapr->cores[index] = NULL; - error_propagate(errp, local_err); - return; - } - - if (dev->hotplugged) { - /* - * Send hotplug notification interrupt to the guest only in case - * of hotplugged CPUs. - */ - spapr_hotplug_req_add_by_index(drc); - } else { - /* - * Set the right DRC states for cold plugged CPU. - */ - drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_USABLE); - drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_UNISOLATED); - } -} - -void spapr_core_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev, - Error **errp) -{ - MachineState *machine = MACHINE(OBJECT(hotplug_dev)); - MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev); - sPAPRMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev)); - int spapr_max_cores = max_cpus / smp_threads; - int index; - Error *local_err = NULL; - CPUCore *cc = CPU_CORE(dev); - char *base_core_type = spapr_get_cpu_core_type(machine->cpu_model); - const char *type = object_get_typename(OBJECT(dev)); - - if (!mc->query_hotpluggable_cpus) { - error_setg(&local_err, "CPU hotplug not supported for this machine"); - goto out; - } - - if (strcmp(base_core_type, type)) { - error_setg(&local_err, "CPU core type should be %s", base_core_type); - goto out; - } - - if (cc->nr_threads != smp_threads) { - error_setg(&local_err, "threads must be %d", smp_threads); - goto out; - } - - if (cc->core_id % smp_threads) { - error_setg(&local_err, "invalid core id %d", cc->core_id); - goto out; - } - - index = cc->core_id / smp_threads; - if (index < 0 || index >= spapr_max_cores) { - error_setg(&local_err, "core id %d out of range", cc->core_id); - goto out; - } - - if (spapr->cores[index]) { - error_setg(&local_err, "core %d already populated", cc->core_id); - goto out; - } - -out: - g_free(base_core_type); - error_propagate(errp, local_err); -} - -static void spapr_cpu_core_realize_child(Object *child, Error **errp) -{ - Error *local_err = NULL; - sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - CPUState *cs = CPU(child); - PowerPCCPU *cpu = POWERPC_CPU(cs); - - object_property_set_bool(child, true, "realized", &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - spapr_cpu_init(spapr, cpu, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } -} - -static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) -{ - sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); - CPUCore *cc = CPU_CORE(OBJECT(dev)); - const char *typename = object_class_get_name(sc->cpu_class); - size_t size = object_type_get_instance_size(typename); - Error *local_err = NULL; - void *obj; - int i, j; - - sc->threads = g_malloc0(size * cc->nr_threads); - for (i = 0; i < cc->nr_threads; i++) { - char id[32]; - CPUState *cs; - - obj = sc->threads + i * size; - - object_initialize(obj, size, typename); - cs = CPU(obj); - cs->cpu_index = cc->core_id + i; - snprintf(id, sizeof(id), "thread[%d]", i); - object_property_add_child(OBJECT(sc), id, obj, &local_err); - if (local_err) { - goto err; - } - object_unref(obj); - } - - for (j = 0; j < cc->nr_threads; j++) { - obj = sc->threads + j * size; - - spapr_cpu_core_realize_child(obj, &local_err); - if (local_err) { - goto err; - } - } - return; - -err: - while (--i >= 0) { - obj = sc->threads + i * size; - object_unparent(obj); - } - g_free(sc->threads); - error_propagate(errp, local_err); -} - -static void spapr_cpu_core_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - dc->realize = spapr_cpu_core_realize; -} - -/* - * instance_init routines from different flavours of sPAPR CPU cores. - */ -#define SPAPR_CPU_CORE_INITFN(_type, _fname) \ -static void glue(glue(spapr_cpu_core_, _fname), _initfn(Object *obj)) \ -{ \ - sPAPRCPUCore *core = SPAPR_CPU_CORE(obj); \ - char *name = g_strdup_printf("%s-" TYPE_POWERPC_CPU, stringify(_type)); \ - ObjectClass *oc = object_class_by_name(name); \ - g_assert(oc); \ - g_free((void *)name); \ - core->cpu_class = oc; \ -} - -SPAPR_CPU_CORE_INITFN(970mp_v1.0, 970MP_v10); -SPAPR_CPU_CORE_INITFN(970mp_v1.1, 970MP_v11); -SPAPR_CPU_CORE_INITFN(970_v2.2, 970); -SPAPR_CPU_CORE_INITFN(POWER5+_v2.1, POWER5plus); -SPAPR_CPU_CORE_INITFN(POWER7_v2.3, POWER7); -SPAPR_CPU_CORE_INITFN(POWER7+_v2.1, POWER7plus); -SPAPR_CPU_CORE_INITFN(POWER8_v2.0, POWER8); -SPAPR_CPU_CORE_INITFN(POWER8E_v2.1, POWER8E); -SPAPR_CPU_CORE_INITFN(POWER8NVL_v1.0, POWER8NVL); - -typedef struct SPAPRCoreInfo { - const char *name; - void (*initfn)(Object *obj); -} SPAPRCoreInfo; - -static const SPAPRCoreInfo spapr_cores[] = { - /* 970 */ - { .name = "970_v2.2", .initfn = spapr_cpu_core_970_initfn }, - - /* 970MP variants */ - { .name = "970MP_v1.0", .initfn = spapr_cpu_core_970MP_v10_initfn }, - { .name = "970mp_v1.0", .initfn = spapr_cpu_core_970MP_v10_initfn }, - { .name = "970MP_v1.1", .initfn = spapr_cpu_core_970MP_v11_initfn }, - { .name = "970mp_v1.1", .initfn = spapr_cpu_core_970MP_v11_initfn }, - - /* POWER5+ */ - { .name = "POWER5+_v2.1", .initfn = spapr_cpu_core_POWER5plus_initfn }, - - /* POWER7 */ - { .name = "POWER7_v2.3", .initfn = spapr_cpu_core_POWER7_initfn }, - - /* POWER7+ */ - { .name = "POWER7+_v2.1", .initfn = spapr_cpu_core_POWER7plus_initfn }, - - /* POWER8 */ - { .name = "POWER8_v2.0", .initfn = spapr_cpu_core_POWER8_initfn }, - - /* POWER8E */ - { .name = "POWER8E_v2.1", .initfn = spapr_cpu_core_POWER8E_initfn }, - - /* POWER8NVL */ - { .name = "POWER8NVL_v1.0", .initfn = spapr_cpu_core_POWER8NVL_initfn }, - - { .name = NULL } -}; - -static void spapr_cpu_core_register(const SPAPRCoreInfo *info) -{ - TypeInfo type_info = { - .parent = TYPE_SPAPR_CPU_CORE, - .instance_size = sizeof(sPAPRCPUCore), - .instance_init = info->initfn, - }; - - type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, info->name); - type_register(&type_info); - g_free((void *)type_info.name); -} - -static const TypeInfo spapr_cpu_core_type_info = { - .name = TYPE_SPAPR_CPU_CORE, - .parent = TYPE_CPU_CORE, - .abstract = true, - .instance_size = sizeof(sPAPRCPUCore), - .class_init = spapr_cpu_core_class_init, -}; - -static void spapr_cpu_core_register_types(void) -{ - const SPAPRCoreInfo *info = spapr_cores; - - type_register_static(&spapr_cpu_core_type_info); - while (info->name) { - spapr_cpu_core_register(info); - info++; - } -} - -type_init(spapr_cpu_core_register_types) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 26a067951..1f5f1d790 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -140,8 +140,6 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc, DPRINTFN("finalizing device removal"); drck->detach(drc, DEVICE(drc->dev), drc->detach_cb, drc->detach_cb_opaque, NULL); - } else if (drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE) { - drc->awaiting_allocation = false; } } return RTAS_OUT_SUCCESS; @@ -271,7 +269,11 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, void *fdt; if (!drc->fdt) { - visit_type_null(v, NULL, errp); + visit_start_struct(v, name, NULL, 0, &err); + if (!err) { + visit_end_struct(v, &err); + } + error_propagate(errp, err); return; } @@ -299,8 +301,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, case FDT_END_NODE: /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */ g_assert(fdt_depth > 0); - visit_check_struct(v, &err); - visit_end_struct(v, NULL); + visit_end_struct(v, &err); if (err) { error_propagate(errp, err); return; @@ -311,7 +312,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, int i; prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len); name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - visit_start_list(v, name, NULL, 0, &err); + visit_start_list(v, name, &err); if (err) { error_propagate(errp, err); return; @@ -323,7 +324,7 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name, return; } } - visit_end_list(v, NULL); + visit_end_list(v); break; } default: @@ -375,10 +376,6 @@ static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt, drc->signalled = (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) ? true : coldplug; - if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) { - drc->awaiting_allocation = true; - } - object_property_add_link(OBJECT(drc), "device", object_get_typename(OBJECT(drc->dev)), (Object **)(&drc->dev), @@ -427,12 +424,6 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d, return; } - if (drc->awaiting_allocation) { - drc->awaiting_release = true; - DPRINTFN("awaiting allocation to complete before removal"); - return; - } - drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE; if (drc->detach_cb) { diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index b0668b34a..049fb1b32 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -386,7 +386,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque) rtas_event_log_queue(RTAS_LOG_TYPE_EPOW, new_epow, true); - qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq)); + qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq)); } static void spapr_hotplug_set_signalled(uint32_t drc_index) @@ -449,9 +449,6 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, case SPAPR_DR_CONNECTOR_TYPE_LMB: hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_MEMORY; break; - case SPAPR_DR_CONNECTOR_TYPE_CPU: - hp->hotplug_type = RTAS_LOG_V6_HP_TYPE_CPU; - break; default: /* we shouldn't be signaling hotplug events for resources * that don't support them @@ -468,7 +465,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true); - qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq)); + qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq)); } void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc) @@ -551,7 +548,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr, * interrupts. */ if (rtas_event_log_contains(mask, true)) { - qemu_irq_pulse(xics_get_qirq(spapr->xics, spapr->check_exception_irq)); + qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq)); } return; @@ -603,7 +600,7 @@ out_no_events: void spapr_events_init(sPAPRMachineState *spapr) { QTAILQ_INIT(&spapr->pending_events); - spapr->check_exception_irq = xics_spapr_alloc(spapr->xics, 0, 0, false, + spapr->check_exception_irq = xics_alloc(spapr->icp, 0, 0, false, &error_fatal); spapr->epow_notifier.notify = spapr_powerdown_req; qemu_register_powerdown_notifier(&spapr->epow_notifier); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 73af112e1..8f40602a5 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1,15 +1,12 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "sysemu/sysemu.h" -#include "qemu/log.h" #include "cpu.h" -#include "exec/exec-all.h" #include "helper_regs.h" #include "hw/ppc/spapr.h" #include "mmu-hash64.h" #include "cpu-models.h" #include "trace.h" -#include "sysemu/kvm.h" #include "kvm_ppc.h" struct SPRSyncState { @@ -83,12 +80,12 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong pte_index = args[1]; target_ulong pteh = args[2]; target_ulong ptel = args[3]; - unsigned apshift; + unsigned apshift, spshift; target_ulong raddr; target_ulong index; uint64_t token; - apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel); + apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel, &spshift); if (!apshift) { /* Bad page size encoding */ return H_PARAMETER; @@ -102,15 +99,11 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPRMachineState *spapr, return H_PARAMETER; } } else { - target_ulong wimg_flags; /* Looks like an IO address */ /* FIXME: What WIMG combinations could be sensible for IO? * For now we allow WIMG=010x, but are there others? */ /* FIXME: Should we check against registered IO addresses? */ - wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)); - - if (wimg_flags != HPTE64_R_I && - wimg_flags != (HPTE64_R_I | HPTE64_R_M)) { + if ((ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)) != HPTE64_R_I) { return H_PARAMETER; } } @@ -190,7 +183,6 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu, target_ulong ptex, static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; target_ulong flags = args[0]; target_ulong pte_index = args[1]; target_ulong avpn = args[2]; @@ -201,7 +193,6 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, switch (ret) { case REMOVE_SUCCESS: - check_tlb_flush(env); return H_SUCCESS; case REMOVE_NOT_FOUND: @@ -238,9 +229,7 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { - CPUPPCState *env = &cpu->env; int i; - target_ulong rc = H_SUCCESS; for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { target_ulong *tsh = &args[i*2]; @@ -273,18 +262,14 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, break; case REMOVE_PARM: - rc = H_PARAMETER; - goto exit; + return H_PARAMETER; case REMOVE_HW: - rc = H_HARDWARE; - goto exit; + return H_HARDWARE; } } - exit: - check_tlb_flush(env); - return rc; + return H_SUCCESS; } static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr, @@ -926,41 +911,6 @@ static void do_set_compat(void *arg) ((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \ ((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0) -static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr, - unsigned max_lvl, unsigned *compat_lvl, - unsigned *cpu_version) -{ - unsigned lvl = get_compat_level(pvr); - bool is205, is206, is207; - - if (!lvl) { - return; - } - - /* If it is a logical PVR, try to determine the highest level */ - is205 = (pcc->pcr_supported & PCR_COMPAT_2_05) && - (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05)); - is206 = (pcc->pcr_supported & PCR_COMPAT_2_06) && - ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) || - (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS))); - is207 = (pcc->pcr_supported & PCR_COMPAT_2_07) && - (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_07)); - - if (is205 || is206 || is207) { - if (!max_lvl) { - /* User did not set the level, choose the highest */ - if (*compat_lvl <= lvl) { - *compat_lvl = lvl; - *cpu_version = pvr; - } - } else if (max_lvl >= lvl) { - /* User chose the level, don't set higher than this */ - *compat_lvl = lvl; - *cpu_version = pvr; - } - } -} - #define OV5_DRCONF_MEMORY 0x20 static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, @@ -970,7 +920,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, { target_ulong list = ppc64_phys_to_real(args[0]); target_ulong ov_table, ov5; - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_); + PowerPCCPUClass *pcc_ = POWERPC_CPU_GET_CLASS(cpu_); CPUState *cs; bool cpu_match = false, cpu_update = true, memory_update = false; unsigned old_cpu_version = cpu_->cpu_version; @@ -997,7 +947,29 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, cpu_match = true; cpu_version = cpu_->cpu_version; } else if (!cpu_match) { - cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &cpu_version); + /* If it is a logical PVR, try to determine the highest level */ + unsigned lvl = get_compat_level(pvr); + if (lvl) { + bool is205 = (pcc_->pcr_mask & PCR_COMPAT_2_05) && + (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05)); + bool is206 = (pcc_->pcr_mask & PCR_COMPAT_2_06) && + ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) || + (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS))); + + if (is205 || is206) { + if (!max_lvl) { + /* User did not set the level, choose the highest */ + if (compat_lvl <= lvl) { + compat_lvl = lvl; + cpu_version = pvr; + } + } else if (max_lvl >= lvl) { + /* User chose the level, don't set higher than this */ + compat_lvl = lvl; + cpu_version = pvr; + } + } + } } /* Terminator record */ if (~pvr_mask & pvr) { @@ -1007,7 +979,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu_, /* Parsing finished */ trace_spapr_cas_pvr(cpu_->cpu_version, cpu_match, - cpu_version, pcc->pcr_mask); + cpu_version, pcc_->pcr_mask); /* Update CPUs */ if (old_cpu_version != cpu_version) { diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 6bc4d4db3..7dd458846 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -17,9 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include "qemu/osdep.h" -#include "qemu/error-report.h" #include "hw/hw.h" -#include "qemu/log.h" #include "sysemu/kvm.h" #include "hw/qdev.h" #include "kvm_ppc.h" @@ -77,37 +75,6 @@ static IOMMUAccessFlags spapr_tce_iommu_access_flags(uint64_t tce) } } -static uint64_t *spapr_tce_alloc_table(uint32_t liobn, - uint32_t page_shift, - uint32_t nb_table, - int *fd, - bool need_vfio) -{ - uint64_t *table = NULL; - uint64_t window_size = (uint64_t)nb_table << page_shift; - - if (kvm_enabled() && !(window_size >> 32)) { - table = kvmppc_create_spapr_tce(liobn, window_size, fd, need_vfio); - } - - if (!table) { - *fd = -1; - table = g_malloc0(nb_table * sizeof(uint64_t)); - } - - trace_spapr_iommu_new_table(liobn, table, *fd); - - return table; -} - -static void spapr_tce_free_table(uint64_t *table, int fd, uint32_t nb_table) -{ - if (!kvm_enabled() || - (kvmppc_remove_spapr_tce(table, fd, nb_table) != 0)) { - g_free(table); - } -} - /* Called from RCU critical section */ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr, bool is_write) @@ -138,131 +105,61 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr, return ret; } -static void spapr_tce_table_pre_save(void *opaque) -{ - sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque); - - tcet->mig_table = tcet->table; - tcet->mig_nb_table = tcet->nb_table; - - trace_spapr_iommu_pre_save(tcet->liobn, tcet->mig_nb_table, - tcet->bus_offset, tcet->page_shift); -} - -static uint64_t spapr_tce_get_min_page_size(MemoryRegion *iommu) -{ - sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu); - - return 1ULL << tcet->page_shift; -} - -static void spapr_tce_notify_started(MemoryRegion *iommu) -{ - spapr_tce_set_need_vfio(container_of(iommu, sPAPRTCETable, iommu), true); -} - -static void spapr_tce_notify_stopped(MemoryRegion *iommu) -{ - spapr_tce_set_need_vfio(container_of(iommu, sPAPRTCETable, iommu), false); -} - static int spapr_tce_table_post_load(void *opaque, int version_id) { sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque); - uint32_t old_nb_table = tcet->nb_table; - uint64_t old_bus_offset = tcet->bus_offset; - uint32_t old_page_shift = tcet->page_shift; if (tcet->vdev) { spapr_vio_set_bypass(tcet->vdev, tcet->bypass); } - if (tcet->mig_nb_table != tcet->nb_table) { - spapr_tce_table_disable(tcet); - } - - if (tcet->mig_nb_table) { - if (!tcet->nb_table) { - spapr_tce_table_enable(tcet, old_page_shift, old_bus_offset, - tcet->mig_nb_table); - } - - memcpy(tcet->table, tcet->mig_table, - tcet->nb_table * sizeof(tcet->table[0])); - - free(tcet->mig_table); - tcet->mig_table = NULL; - } - - trace_spapr_iommu_post_load(tcet->liobn, old_nb_table, tcet->nb_table, - tcet->bus_offset, tcet->page_shift); - return 0; } -static bool spapr_tce_table_ex_needed(void *opaque) -{ - sPAPRTCETable *tcet = opaque; - - return tcet->bus_offset || tcet->page_shift != 0xC; -} - -static const VMStateDescription vmstate_spapr_tce_table_ex = { - .name = "spapr_iommu_ex", - .version_id = 1, - .minimum_version_id = 1, - .needed = spapr_tce_table_ex_needed, - .fields = (VMStateField[]) { - VMSTATE_UINT64(bus_offset, sPAPRTCETable), - VMSTATE_UINT32(page_shift, sPAPRTCETable), - VMSTATE_END_OF_LIST() - }, -}; - static const VMStateDescription vmstate_spapr_tce_table = { .name = "spapr_iommu", .version_id = 2, .minimum_version_id = 2, - .pre_save = spapr_tce_table_pre_save, .post_load = spapr_tce_table_post_load, .fields = (VMStateField []) { /* Sanity check */ VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable), + VMSTATE_UINT32_EQUAL(nb_table, sPAPRTCETable), /* IOMMU state */ - VMSTATE_UINT32(mig_nb_table, sPAPRTCETable), VMSTATE_BOOL(bypass, sPAPRTCETable), - VMSTATE_VARRAY_UINT32_ALLOC(mig_table, sPAPRTCETable, mig_nb_table, 0, - vmstate_info_uint64, uint64_t), + VMSTATE_VARRAY_UINT32(table, sPAPRTCETable, nb_table, 0, vmstate_info_uint64, uint64_t), VMSTATE_END_OF_LIST() }, - .subsections = (const VMStateDescription*[]) { - &vmstate_spapr_tce_table_ex, - NULL - } }; static MemoryRegionIOMMUOps spapr_iommu_ops = { .translate = spapr_tce_translate_iommu, - .get_min_page_size = spapr_tce_get_min_page_size, - .notify_started = spapr_tce_notify_started, - .notify_stopped = spapr_tce_notify_stopped, }; static int spapr_tce_table_realize(DeviceState *dev) { sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev); - Object *tcetobj = OBJECT(tcet); - char tmp[32]; + uint64_t window_size = (uint64_t)tcet->nb_table << tcet->page_shift; - tcet->fd = -1; - tcet->need_vfio = false; - snprintf(tmp, sizeof(tmp), "tce-root-%x", tcet->liobn); - memory_region_init(&tcet->root, tcetobj, tmp, UINT64_MAX); + if (kvm_enabled() && !(window_size >> 32)) { + tcet->table = kvmppc_create_spapr_tce(tcet->liobn, + window_size, + &tcet->fd, + tcet->need_vfio); + } + + if (!tcet->table) { + size_t table_size = tcet->nb_table * sizeof(uint64_t); + tcet->table = g_malloc0(table_size); + } - snprintf(tmp, sizeof(tmp), "tce-iommu-%x", tcet->liobn); - memory_region_init_iommu(&tcet->iommu, tcetobj, &spapr_iommu_ops, tmp, 0); + trace_spapr_iommu_new_table(tcet->liobn, tcet, tcet->table, tcet->fd); + + memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops, + "iommu-spapr", + (uint64_t)tcet->nb_table << tcet->page_shift); QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list); @@ -304,10 +201,14 @@ void spapr_tce_set_need_vfio(sPAPRTCETable *tcet, bool need_vfio) tcet->table = newtable; } -sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn) +sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, + uint64_t bus_offset, + uint32_t page_shift, + uint32_t nb_table, + bool need_vfio) { sPAPRTCETable *tcet; - char tmp[32]; + char tmp[64]; if (spapr_tce_find_by_liobn(liobn)) { fprintf(stderr, "Attempted to create TCE table with duplicate" @@ -315,8 +216,16 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn) return NULL; } + if (!nb_table) { + return NULL; + } + tcet = SPAPR_TCE_TABLE(object_new(TYPE_SPAPR_TCE_TABLE)); tcet->liobn = liobn; + tcet->bus_offset = bus_offset; + tcet->page_shift = page_shift; + tcet->nb_table = nb_table; + tcet->need_vfio = need_vfio; snprintf(tmp, sizeof(tmp), "tce-table-%x", liobn); object_property_add_child(OBJECT(owner), tmp, OBJECT(tcet), NULL); @@ -326,58 +235,22 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn) return tcet; } -void spapr_tce_table_enable(sPAPRTCETable *tcet, - uint32_t page_shift, uint64_t bus_offset, - uint32_t nb_table) -{ - if (tcet->nb_table) { - error_report("Warning: trying to enable already enabled TCE table"); - return; - } - - tcet->bus_offset = bus_offset; - tcet->page_shift = page_shift; - tcet->nb_table = nb_table; - tcet->table = spapr_tce_alloc_table(tcet->liobn, - tcet->page_shift, - tcet->nb_table, - &tcet->fd, - tcet->need_vfio); - - memory_region_set_size(&tcet->iommu, - (uint64_t)tcet->nb_table << tcet->page_shift); - memory_region_add_subregion(&tcet->root, tcet->bus_offset, &tcet->iommu); -} - -void spapr_tce_table_disable(sPAPRTCETable *tcet) -{ - if (!tcet->nb_table) { - return; - } - - memory_region_del_subregion(&tcet->root, &tcet->iommu); - memory_region_set_size(&tcet->iommu, 0); - - spapr_tce_free_table(tcet->table, tcet->fd, tcet->nb_table); - tcet->fd = -1; - tcet->table = NULL; - tcet->bus_offset = 0; - tcet->page_shift = 0; - tcet->nb_table = 0; -} - static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp) { sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev); QLIST_REMOVE(tcet, list); - spapr_tce_table_disable(tcet); + if (!kvm_enabled() || + (kvmppc_remove_spapr_tce(tcet->table, tcet->fd, + tcet->nb_table) != 0)) { + g_free(tcet->table); + } } MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet) { - return &tcet->root; + return &tcet->iommu; } static void spapr_tce_reset(DeviceState *dev) @@ -385,9 +258,7 @@ static void spapr_tce_reset(DeviceState *dev) sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev); size_t table_size = tcet->nb_table * sizeof(uint64_t); - if (tcet->nb_table) { - memset(tcet->table, 0, table_size); - } + memset(tcet->table, 0, table_size); } static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, @@ -406,7 +277,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, tcet->table[index] = tce; entry.target_as = &address_space_memory, - entry.iova = (ioba - tcet->bus_offset) & page_mask; + entry.iova = ioba & page_mask; entry.translated_addr = tce & page_mask; entry.addr_mask = ~page_mask; entry.perm = spapr_tce_iommu_access_flags(tce); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 949c44fec..573e635bf 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -35,7 +35,6 @@ #include "hw/ppc/spapr.h" #include "hw/pci-host/spapr.h" #include "exec/address-spaces.h" -#include "exec/ram_addr.h" #include <libfdt.h> #include "trace.h" #include "qemu/error-report.h" @@ -45,8 +44,6 @@ #include "hw/pci/pci_bus.h" #include "hw/ppc/spapr_drc.h" #include "sysemu/device_tree.h" -#include "sysemu/kvm.h" -#include "sysemu/hostmem.h" #include "hw/vfio/vfio.h" @@ -324,7 +321,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, return; } - xics_spapr_free(spapr->xics, msi->first_irq, msi->num); + xics_free(spapr->icp, msi->first_irq, msi->num); if (msi_present(pdev)) { spapr_msi_setmsg(pdev, 0, false, 0, 0); } @@ -362,7 +359,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, } /* Allocate MSIs */ - irq = xics_spapr_alloc_block(spapr->xics, 0, req_num, false, + irq = xics_alloc_block(spapr->icp, 0, req_num, false, ret_intr_type == RTAS_TYPE_MSI, &err); if (err) { error_reportf_err(err, "Can't allocate MSIs for device %x: ", @@ -373,7 +370,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, /* Release previous MSIs */ if (msi) { - xics_spapr_free(spapr->xics, msi->first_irq, msi->num); + xics_free(spapr->icp, msi->first_irq, msi->num); g_hash_table_remove(phb->msi, &config_addr); } @@ -735,7 +732,7 @@ static void spapr_msi_write(void *opaque, hwaddr addr, trace_spapr_pci_msi_write(addr, data, irq); - qemu_irq_pulse(xics_get_qirq(spapr->xics, irq)); + qemu_irq_pulse(xics_get_qirq(spapr->icp, irq)); } static const MemoryRegionOps spapr_msi_ops = { @@ -1089,11 +1086,19 @@ static void spapr_phb_add_pci_device(sPAPRDRConnector *drc, void *fdt = NULL; int fdt_start_offset = 0, fdt_size; - fdt = create_device_tree(&fdt_size); - fdt_start_offset = spapr_create_pci_child_dt(phb, pdev, fdt, 0); - if (!fdt_start_offset) { - error_setg(errp, "Failed to create pci child device tree node"); - goto out; + if (object_dynamic_cast(OBJECT(pdev), "vfio-pci")) { + sPAPRTCETable *tcet = spapr_tce_find_by_liobn(phb->dma_liobn); + + spapr_tce_set_need_vfio(tcet, true); + } + + if (dev->hotplugged) { + fdt = create_device_tree(&fdt_size); + fdt_start_offset = spapr_create_pci_child_dt(phb, pdev, fdt, 0); + if (!fdt_start_offset) { + error_setg(errp, "Failed to create pci child device tree node"); + goto out; + } } drck->attach(drc, DEVICE(pdev), @@ -1306,14 +1311,12 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) PCIBus *bus; uint64_t msi_window_size = 4096; sPAPRTCETable *tcet; - const unsigned windows_supported = - sphb->ddw_enabled ? SPAPR_PCI_DMA_MAX_WINDOWS : 1; + uint32_t nb_table; if (sphb->index != (uint32_t)-1) { hwaddr windows_base; - if ((sphb->buid != (uint64_t)-1) || (sphb->dma_liobn[0] != (uint32_t)-1) - || (sphb->dma_liobn[1] != (uint32_t)-1 && windows_supported == 2) + if ((sphb->buid != (uint64_t)-1) || (sphb->dma_liobn != (uint32_t)-1) || (sphb->mem_win_addr != (hwaddr)-1) || (sphb->io_win_addr != (hwaddr)-1)) { error_setg(errp, "Either \"index\" or other parameters must" @@ -1328,9 +1331,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) } sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index; - for (i = 0; i < windows_supported; ++i) { - sphb->dma_liobn[i] = SPAPR_PCI_LIOBN(sphb->index, i); - } + sphb->dma_liobn = SPAPR_PCI_LIOBN(sphb->index, 0); windows_base = SPAPR_PCI_WINDOW_BASE + sphb->index * SPAPR_PCI_WINDOW_SPACING; @@ -1343,9 +1344,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) return; } - if ((sphb->dma_liobn[0] == (uint32_t)-1) || - ((sphb->dma_liobn[1] == (uint32_t)-1) && (windows_supported > 1))) { - error_setg(errp, "LIOBN(s) not specified for PHB"); + if (sphb->dma_liobn == (uint32_t)-1) { + error_setg(errp, "LIOBN not specified for PHB"); return; } @@ -1444,8 +1444,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) uint32_t irq; Error *local_err = NULL; - irq = xics_spapr_alloc_block(spapr->xics, 0, 1, true, false, - &local_err); + irq = xics_alloc_block(spapr->icp, 0, 1, true, false, &local_err); if (local_err) { error_propagate(errp, local_err); error_prepend(errp, "can't allocate LSIs: "); @@ -1464,18 +1463,19 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) } } - /* DMA setup */ - for (i = 0; i < windows_supported; ++i) { - tcet = spapr_tce_new_table(DEVICE(sphb), sphb->dma_liobn[i]); - if (!tcet) { - error_setg(errp, "Creating window#%d failed for %s", - i, sphb->dtbusname); - return; - } - memory_region_add_subregion_overlap(&sphb->iommu_root, 0, - spapr_tce_get_iommu(tcet), 0); + nb_table = sphb->dma_win_size >> SPAPR_TCE_PAGE_SHIFT; + tcet = spapr_tce_new_table(DEVICE(sphb), sphb->dma_liobn, + 0, SPAPR_TCE_PAGE_SHIFT, nb_table, false); + if (!tcet) { + error_setg(errp, "Unable to create TCE table for %s", + sphb->dtbusname); + return; } + /* Register default 32bit DMA window */ + memory_region_add_subregion(&sphb->iommu_root, sphb->dma_win_addr, + spapr_tce_get_iommu(tcet)); + sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); } @@ -1490,31 +1490,8 @@ static int spapr_phb_children_reset(Object *child, void *opaque) return 0; } -void spapr_phb_dma_reset(sPAPRPHBState *sphb) -{ - int i; - sPAPRTCETable *tcet; - - for (i = 0; i < SPAPR_PCI_DMA_MAX_WINDOWS; ++i) { - tcet = spapr_tce_find_by_liobn(sphb->dma_liobn[i]); - - if (tcet && tcet->nb_table) { - spapr_tce_table_disable(tcet); - } - } - - /* Register default 32bit DMA window */ - tcet = spapr_tce_find_by_liobn(sphb->dma_liobn[0]); - spapr_tce_table_enable(tcet, SPAPR_TCE_PAGE_SHIFT, sphb->dma_win_addr, - sphb->dma_win_size >> SPAPR_TCE_PAGE_SHIFT); -} - static void spapr_phb_reset(DeviceState *qdev) { - sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(qdev); - - spapr_phb_dma_reset(sphb); - /* Reset the IOMMU state */ object_child_foreach(OBJECT(qdev), spapr_phb_children_reset, NULL); @@ -1526,8 +1503,7 @@ static void spapr_phb_reset(DeviceState *qdev) static Property spapr_phb_properties[] = { DEFINE_PROP_UINT32("index", sPAPRPHBState, index, -1), DEFINE_PROP_UINT64("buid", sPAPRPHBState, buid, -1), - DEFINE_PROP_UINT32("liobn", sPAPRPHBState, dma_liobn[0], -1), - DEFINE_PROP_UINT32("liobn64", sPAPRPHBState, dma_liobn[1], -1), + DEFINE_PROP_UINT32("liobn", sPAPRPHBState, dma_liobn, -1), DEFINE_PROP_UINT64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1), DEFINE_PROP_UINT64("mem_win_size", sPAPRPHBState, mem_win_size, SPAPR_PCI_MMIO_WIN_SIZE), @@ -1539,11 +1515,6 @@ static Property spapr_phb_properties[] = { /* Default DMA window is 0..1GB */ DEFINE_PROP_UINT64("dma_win_addr", sPAPRPHBState, dma_win_addr, 0), DEFINE_PROP_UINT64("dma_win_size", sPAPRPHBState, dma_win_size, 0x40000000), - DEFINE_PROP_UINT64("dma64_win_addr", sPAPRPHBState, dma64_win_addr, - 0x800000000000000ULL), - DEFINE_PROP_BOOL("ddw", sPAPRPHBState, ddw_enabled, true), - DEFINE_PROP_UINT64("pgsz", sPAPRPHBState, page_size_mask, - (1ULL << 12) | (1ULL << 16)), DEFINE_PROP_END_OF_LIST(), }; @@ -1620,7 +1591,7 @@ static const VMStateDescription vmstate_spapr_pci = { .post_load = spapr_pci_post_load, .fields = (VMStateField[]) { VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState), - VMSTATE_UINT32_EQUAL(dma_liobn[0], sPAPRPHBState), + VMSTATE_UINT32_EQUAL(dma_liobn, sPAPRPHBState), VMSTATE_UINT64_EQUAL(mem_win_addr, sPAPRPHBState), VMSTATE_UINT64_EQUAL(mem_win_size, sPAPRPHBState), VMSTATE_UINT64_EQUAL(io_win_addr, sPAPRPHBState), @@ -1654,6 +1625,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data) dc->reset = spapr_phb_reset; dc->vmsd = &vmstate_spapr_pci; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + dc->cannot_instantiate_with_device_add_yet = false; hp->plug = spapr_phb_hot_plug_child; hp->unplug = spapr_phb_hot_unplug_child; } @@ -1796,15 +1768,6 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t interrupt_map_mask[] = { cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)}; uint32_t interrupt_map[PCI_SLOT_MAX * PCI_NUM_PINS][7]; - uint32_t ddw_applicable[] = { - cpu_to_be32(RTAS_IBM_QUERY_PE_DMA_WINDOW), - cpu_to_be32(RTAS_IBM_CREATE_PE_DMA_WINDOW), - cpu_to_be32(RTAS_IBM_REMOVE_PE_DMA_WINDOW) - }; - uint32_t ddw_extensions[] = { - cpu_to_be32(1), - cpu_to_be32(RTAS_IBM_RESET_PE_DMA_WINDOW) - }; sPAPRTCETable *tcet; PCIBus *bus = PCI_HOST_BRIDGE(phb)->bus; sPAPRFDT s_fdt; @@ -1827,15 +1790,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof_ranges)); _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg))); _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1)); - _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS_SPAPR)); - - /* Dynamic DMA window */ - if (phb->ddw_enabled) { - _FDT(fdt_setprop(fdt, bus_off, "ibm,ddw-applicable", &ddw_applicable, - sizeof(ddw_applicable))); - _FDT(fdt_setprop(fdt, bus_off, "ibm,ddw-extensions", - &ddw_extensions, sizeof(ddw_extensions))); - } + _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS)); /* Build the interrupt-map, this must matches what is done * in pci_spapr_map_irq @@ -1860,7 +1815,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map, sizeof(interrupt_map))); - tcet = spapr_tce_find_by_liobn(phb->dma_liobn[0]); + tcet = spapr_tce_find_by_liobn(SPAPR_PCI_LIOBN(phb->index, 0)); if (!tcet) { return -1; } diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index 8448e0b02..cbd3d23c9 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -18,16 +18,15 @@ */ #include "qemu/osdep.h" -#include <linux/vfio.h> #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" #include "hw/ppc/spapr.h" #include "hw/pci-host/spapr.h" #include "hw/pci/msix.h" +#include "linux/vfio.h" #include "hw/vfio/vfio.h" #include "qemu/error-report.h" -#include "sysemu/qtest.h" #define TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE "spapr-pci-vfio-host-bridge" @@ -49,9 +48,7 @@ static Property spapr_phb_vfio_properties[] = { static void spapr_phb_vfio_instance_init(Object *obj) { - if (!qtest_enabled()) { - error_report("spapr-pci-vfio-host-bridge is deprecated"); - } + error_report("spapr-pci-vfio-host-bridge is deprecated"); } bool spapr_phb_eeh_available(sPAPRPHBState *sphb) diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index dc058e512..f07325831 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -26,17 +26,14 @@ */ #include "qemu/osdep.h" #include "cpu.h" -#include "qemu/log.h" #include "sysemu/sysemu.h" #include "sysemu/char.h" #include "hw/qdev.h" #include "sysemu/device_tree.h" #include "sysemu/cpus.h" -#include "sysemu/kvm.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" -#include "hw/ppc/ppc.h" #include "qapi-event.h" #include "hw/boards.h" @@ -165,27 +162,6 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); } -/* - * Set the timebase offset of the CPU to that of first CPU. - * This helps hotplugged CPU to have the correct timebase offset. - */ -static void spapr_cpu_update_tb_offset(PowerPCCPU *cpu) -{ - PowerPCCPU *fcpu = POWERPC_CPU(first_cpu); - - cpu->env.tb_env->tb_offset = fcpu->env.tb_env->tb_offset; -} - -static void spapr_cpu_set_endianness(PowerPCCPU *cpu) -{ - PowerPCCPU *fcpu = POWERPC_CPU(first_cpu); - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(fcpu); - - if (!pcc->interrupts_big_endian(fcpu)) { - cpu->env.spr[SPR_LPCR] |= LPCR_ILE; - } -} - static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, uint32_t token, uint32_t nargs, target_ulong args, @@ -222,8 +198,6 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, env->nip = start; env->gpr[3] = r3; cs->halted = 0; - spapr_cpu_set_endianness(cpu); - spapr_cpu_update_tb_offset(cpu); qemu_cpu_kick(cs); diff --git a/hw/ppc/spapr_rtas_ddw.c b/hw/ppc/spapr_rtas_ddw.c deleted file mode 100644 index 177dcffc9..000000000 --- a/hw/ppc/spapr_rtas_ddw.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * QEMU sPAPR Dynamic DMA windows support - * - * Copyright (c) 2015 Alexey Kardashevskiy, IBM Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, - * or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "qemu/error-report.h" -#include "hw/ppc/spapr.h" -#include "hw/pci-host/spapr.h" -#include "trace.h" - -static int spapr_phb_get_active_win_num_cb(Object *child, void *opaque) -{ - sPAPRTCETable *tcet; - - tcet = (sPAPRTCETable *) object_dynamic_cast(child, TYPE_SPAPR_TCE_TABLE); - if (tcet && tcet->nb_table) { - ++*(unsigned *)opaque; - } - return 0; -} - -static unsigned spapr_phb_get_active_win_num(sPAPRPHBState *sphb) -{ - unsigned ret = 0; - - object_child_foreach(OBJECT(sphb), spapr_phb_get_active_win_num_cb, &ret); - - return ret; -} - -static int spapr_phb_get_free_liobn_cb(Object *child, void *opaque) -{ - sPAPRTCETable *tcet; - - tcet = (sPAPRTCETable *) object_dynamic_cast(child, TYPE_SPAPR_TCE_TABLE); - if (tcet && !tcet->nb_table) { - *(uint32_t *)opaque = tcet->liobn; - return 1; - } - return 0; -} - -static unsigned spapr_phb_get_free_liobn(sPAPRPHBState *sphb) -{ - uint32_t liobn = 0; - - object_child_foreach(OBJECT(sphb), spapr_phb_get_free_liobn_cb, &liobn); - - return liobn; -} - -static uint32_t spapr_page_mask_to_query_mask(uint64_t page_mask) -{ - int i; - uint32_t mask = 0; - const struct { int shift; uint32_t mask; } masks[] = { - { 12, RTAS_DDW_PGSIZE_4K }, - { 16, RTAS_DDW_PGSIZE_64K }, - { 24, RTAS_DDW_PGSIZE_16M }, - { 25, RTAS_DDW_PGSIZE_32M }, - { 26, RTAS_DDW_PGSIZE_64M }, - { 27, RTAS_DDW_PGSIZE_128M }, - { 28, RTAS_DDW_PGSIZE_256M }, - { 34, RTAS_DDW_PGSIZE_16G }, - }; - - for (i = 0; i < ARRAY_SIZE(masks); ++i) { - if (page_mask & (1ULL << masks[i].shift)) { - mask |= masks[i].mask; - } - } - - return mask; -} - -static void rtas_ibm_query_pe_dma_window(PowerPCCPU *cpu, - sPAPRMachineState *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - sPAPRPHBState *sphb; - uint64_t buid, max_window_size; - uint32_t avail, addr, pgmask = 0; - MachineState *machine = MACHINE(spapr); - - if ((nargs != 3) || (nret != 5)) { - goto param_error_exit; - } - - buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); - addr = rtas_ld(args, 0); - sphb = spapr_pci_find_phb(spapr, buid); - if (!sphb || !sphb->ddw_enabled) { - goto param_error_exit; - } - - /* Translate page mask to LoPAPR format */ - pgmask = spapr_page_mask_to_query_mask(sphb->page_size_mask); - - /* - * This is "Largest contiguous block of TCEs allocated specifically - * for (that is, are reserved for) this PE". - * Return the maximum number as maximum supported RAM size was in 4K pages. - */ - if (machine->ram_size == machine->maxram_size) { - max_window_size = machine->ram_size; - } else { - MemoryHotplugState *hpms = &spapr->hotplug_memory; - - max_window_size = hpms->base + memory_region_size(&hpms->mr); - } - - avail = SPAPR_PCI_DMA_MAX_WINDOWS - spapr_phb_get_active_win_num(sphb); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); - rtas_st(rets, 1, avail); - rtas_st(rets, 2, max_window_size >> SPAPR_TCE_PAGE_SHIFT); - rtas_st(rets, 3, pgmask); - rtas_st(rets, 4, 0); /* DMA migration mask, not supported */ - - trace_spapr_iommu_ddw_query(buid, addr, avail, max_window_size, pgmask); - return; - -param_error_exit: - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); -} - -static void rtas_ibm_create_pe_dma_window(PowerPCCPU *cpu, - sPAPRMachineState *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - sPAPRPHBState *sphb; - sPAPRTCETable *tcet = NULL; - uint32_t addr, page_shift, window_shift, liobn; - uint64_t buid, win_addr; - int windows; - - if ((nargs != 5) || (nret != 4)) { - goto param_error_exit; - } - - buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); - addr = rtas_ld(args, 0); - sphb = spapr_pci_find_phb(spapr, buid); - if (!sphb || !sphb->ddw_enabled) { - goto param_error_exit; - } - - page_shift = rtas_ld(args, 3); - window_shift = rtas_ld(args, 4); - liobn = spapr_phb_get_free_liobn(sphb); - windows = spapr_phb_get_active_win_num(sphb); - - if (!(sphb->page_size_mask & (1ULL << page_shift)) || - (window_shift < page_shift)) { - goto param_error_exit; - } - - if (!liobn || !sphb->ddw_enabled || windows == SPAPR_PCI_DMA_MAX_WINDOWS) { - goto hw_error_exit; - } - - tcet = spapr_tce_find_by_liobn(liobn); - if (!tcet) { - goto hw_error_exit; - } - - win_addr = (windows == 0) ? sphb->dma_win_addr : sphb->dma64_win_addr; - spapr_tce_table_enable(tcet, page_shift, win_addr, - 1ULL << (window_shift - page_shift)); - if (!tcet->nb_table) { - goto hw_error_exit; - } - - trace_spapr_iommu_ddw_create(buid, addr, 1ULL << page_shift, - 1ULL << window_shift, tcet->bus_offset, liobn); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); - rtas_st(rets, 1, liobn); - rtas_st(rets, 2, tcet->bus_offset >> 32); - rtas_st(rets, 3, tcet->bus_offset & ((uint32_t) -1)); - - return; - -hw_error_exit: - rtas_st(rets, 0, RTAS_OUT_HW_ERROR); - return; - -param_error_exit: - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); -} - -static void rtas_ibm_remove_pe_dma_window(PowerPCCPU *cpu, - sPAPRMachineState *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - sPAPRPHBState *sphb; - sPAPRTCETable *tcet; - uint32_t liobn; - - if ((nargs != 1) || (nret != 1)) { - goto param_error_exit; - } - - liobn = rtas_ld(args, 0); - tcet = spapr_tce_find_by_liobn(liobn); - if (!tcet) { - goto param_error_exit; - } - - sphb = SPAPR_PCI_HOST_BRIDGE(OBJECT(tcet)->parent); - if (!sphb || !sphb->ddw_enabled || !tcet->nb_table) { - goto param_error_exit; - } - - spapr_tce_table_disable(tcet); - trace_spapr_iommu_ddw_remove(liobn); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); - return; - -param_error_exit: - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); -} - -static void rtas_ibm_reset_pe_dma_window(PowerPCCPU *cpu, - sPAPRMachineState *spapr, - uint32_t token, uint32_t nargs, - target_ulong args, - uint32_t nret, target_ulong rets) -{ - sPAPRPHBState *sphb; - uint64_t buid; - uint32_t addr; - - if ((nargs != 3) || (nret != 1)) { - goto param_error_exit; - } - - buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2); - addr = rtas_ld(args, 0); - sphb = spapr_pci_find_phb(spapr, buid); - if (!sphb || !sphb->ddw_enabled) { - goto param_error_exit; - } - - spapr_phb_dma_reset(sphb); - trace_spapr_iommu_ddw_reset(buid, addr); - - rtas_st(rets, 0, RTAS_OUT_SUCCESS); - - return; - -param_error_exit: - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); -} - -static void spapr_rtas_ddw_init(void) -{ - spapr_rtas_register(RTAS_IBM_QUERY_PE_DMA_WINDOW, - "ibm,query-pe-dma-window", - rtas_ibm_query_pe_dma_window); - spapr_rtas_register(RTAS_IBM_CREATE_PE_DMA_WINDOW, - "ibm,create-pe-dma-window", - rtas_ibm_create_pe_dma_window); - spapr_rtas_register(RTAS_IBM_REMOVE_PE_DMA_WINDOW, - "ibm,remove-pe-dma-window", - rtas_ibm_remove_pe_dma_window); - spapr_rtas_register(RTAS_IBM_RESET_PE_DMA_WINDOW, - "ibm,reset-pe-dma-window", - rtas_ibm_reset_pe_dma_window); -} - -type_init(spapr_rtas_ddw_init) diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index f93244d7c..8aa021fde 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -22,7 +22,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/hw.h" -#include "qemu/log.h" #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/loader.h" @@ -57,9 +56,12 @@ static char *spapr_vio_get_dev_name(DeviceState *qdev) { VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev); VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + char *name; /* Device tree style name device@reg */ - return g_strdup_printf("%s@%x", pc->dt_name, dev->reg); + name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg); + + return name; } static void spapr_vio_bus_class_init(ObjectClass *klass, void *data) @@ -463,7 +465,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq = xics_spapr_alloc(spapr->xics, 0, dev->irq, false, &local_err); + dev->irq = xics_alloc(spapr->icp, 0, dev->irq, false, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -480,9 +482,11 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) memory_region_add_subregion_overlap(&dev->mrroot, 0, &dev->mrbypass, 1); address_space_init(&dev->as, &dev->mrroot, qdev->id); - dev->tcet = spapr_tce_new_table(qdev, liobn); - spapr_tce_table_enable(dev->tcet, SPAPR_TCE_PAGE_SHIFT, 0, - pc->rtce_window_size >> SPAPR_TCE_PAGE_SHIFT); + dev->tcet = spapr_tce_new_table(qdev, liobn, + 0, + SPAPR_TCE_PAGE_SHIFT, + pc->rtce_window_size >> + SPAPR_TCE_PAGE_SHIFT, false); dev->tcet->vdev = dev; memory_region_add_subregion_overlap(&dev->mrroot, 0, spapr_tce_get_iommu(dev->tcet), 2); @@ -580,7 +584,7 @@ const VMStateDescription vmstate_spapr_vio = { VMSTATE_UINT32_EQUAL(irq, VIOsPAPRDevice), /* General VIO device state */ - VMSTATE_UINT64(signal_state, VIOsPAPRDevice), + VMSTATE_UINTTL(signal_state, VIOsPAPRDevice), VMSTATE_UINT64(crq.qladdr, VIOsPAPRDevice), VMSTATE_UINT32(crq.qsize, VIOsPAPRDevice), VMSTATE_UINT32(crq.qnext, VIOsPAPRDevice), diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events deleted file mode 100644 index dfeab9308..000000000 --- a/hw/ppc/trace-events +++ /dev/null @@ -1,43 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/ppc/spapr_pci.c -spapr_pci_msi(const char *msg, uint32_t ca) "%s (cfg=%x)" -spapr_pci_msi_setup(const char *name, unsigned vector, uint64_t addr) "dev\"%s\" vector %u, addr=%"PRIx64 -spapr_pci_rtas_ibm_change_msi(unsigned cfg, unsigned func, unsigned req, unsigned first) "cfgaddr %x func %u, requested %u, first irq %u" -spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "queries for #%u, IRQ%u" -spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u" -spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u" -spapr_pci_msi_retry(unsigned config_addr, unsigned req_num, unsigned max_irqs) "Guest device at %x asked %u, have only %u" - -# hw/ppc/spapr.c -spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes" -spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes" - -# hw/ppc/spapr_hcall.c -spapr_cas_pvr_try(uint32_t pvr) "%x" -spapr_cas_pvr(uint32_t cur_pvr, bool cpu_match, uint32_t new_pvr, uint64_t pcr) "current=%x, cpu_match=%u, new=%x, compat flags=%"PRIx64 - -# hw/ppc/spapr_iommu.c -spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64 -spapr_iommu_get(uint64_t liobn, uint64_t ioba, uint64_t ret, uint64_t tce) "liobn=%"PRIx64" ioba=0x%"PRIx64" ret=%"PRId64" tce=0x%"PRIx64 -spapr_iommu_indirect(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t iobaN, uint64_t tceN, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tcelist=0x%"PRIx64" iobaN=0x%"PRIx64" tceN=0x%"PRIx64" ret=%"PRId64 -spapr_iommu_stuff(uint64_t liobn, uint64_t ioba, uint64_t tce_value, uint64_t npages, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tcevalue=0x%"PRIx64" npages=%"PRId64" ret=%"PRId64 -spapr_iommu_pci_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64 -spapr_iommu_pci_get(uint64_t liobn, uint64_t ioba, uint64_t ret, uint64_t tce) "liobn=%"PRIx64" ioba=0x%"PRIx64" ret=%"PRId64" tce=0x%"PRIx64 -spapr_iommu_pci_indirect(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t iobaN, uint64_t tceN, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tcelist=0x%"PRIx64" iobaN=0x%"PRIx64" tceN=0x%"PRIx64" ret=%"PRId64 -spapr_iommu_pci_stuff(uint64_t liobn, uint64_t ioba, uint64_t tce_value, uint64_t npages, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tcevalue=0x%"PRIx64" npages=%"PRId64" ret=%"PRId64 -spapr_iommu_xlate(uint64_t liobn, uint64_t ioba, uint64_t tce, unsigned perm, unsigned pgsize) "liobn=%"PRIx64" 0x%"PRIx64" -> 0x%"PRIx64" perm=%u mask=%x" -spapr_iommu_new_table(uint64_t liobn, void *table, int fd) "liobn=%"PRIx64" table=%p fd=%d" -spapr_iommu_pre_save(uint64_t liobn, uint32_t nb, uint64_t offs, uint32_t ps) "liobn=%"PRIx64" %"PRIx32" bus_offset=%"PRIx64" ps=%"PRIu32 -spapr_iommu_post_load(uint64_t liobn, uint32_t pre_nb, uint32_t post_nb, uint64_t offs, uint32_t ps) "liobn=%"PRIx64" %"PRIx32" => %"PRIx32" bus_offset=%"PRIx64" ps=%"PRIu32 -spapr_iommu_ddw_query(uint64_t buid, uint32_t cfgaddr, unsigned wa, uint64_t win_size, uint32_t pgmask) "buid=%"PRIx64" addr=%"PRIx32", %u windows available, max window size=%"PRIx64", mask=%"PRIx32 -spapr_iommu_ddw_create(uint64_t buid, uint32_t cfgaddr, uint64_t pg_size, uint64_t req_size, uint64_t start, uint32_t liobn) "buid=%"PRIx64" addr=%"PRIx32", page size=0x%"PRIx64", requested=0x%"PRIx64", start addr=%"PRIx64", liobn=%"PRIx32 -spapr_iommu_ddw_remove(uint32_t liobn) "liobn=%"PRIx32 -spapr_iommu_ddw_reset(uint64_t buid, uint32_t cfgaddr) "buid=%"PRIx64" addr=%"PRIx32 - -# hw/ppc/ppc.c -ppc_tb_adjust(uint64_t offs1, uint64_t offs2, int64_t diff, int64_t seconds) "adjusted from 0x%"PRIx64" to 0x%"PRIx64", diff %"PRId64" (%"PRId64"s)" - -# hw/ppc/prep.c -prep_io_800_writeb(uint32_t addr, uint32_t val) "0x%08" PRIx32 " => 0x%02" PRIx32 -prep_io_800_readb(uint32_t addr, uint32_t retval) "0x%08" PRIx32 " <= 0x%02" PRIx32 diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index b97d96685..b807a08c2 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "hw/sysbus.h" #include "hw/hw.h" #include "hw/char/serial.h" diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index 41ac4ec32..220361782 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -8,8 +8,6 @@ obj-y += ipl.o obj-y += css.o obj-y += s390-virtio-ccw.o obj-y += virtio-ccw.o -obj-y += css-bridge.o -obj-y += ccw-device.o obj-y += s390-pci-bus.o s390-pci-inst.o obj-y += s390-skeys.o obj-$(CONFIG_KVM) += s390-skeys-kvm.o diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c deleted file mode 100644 index 28ea20440..000000000 --- a/hw/s390x/ccw-device.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Common device infrastructure for devices in the virtual css - * - * Copyright 2016 IBM Corp. - * Author(s): Jing Liu <liujbjl@linux.vnet.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or (at - * your option) any later version. See the COPYING file in the top-level - * directory. - */ -#include "qemu/osdep.h" -#include "ccw-device.h" - -static const TypeInfo ccw_device_info = { - .name = TYPE_CCW_DEVICE, - .parent = TYPE_DEVICE, - .instance_size = sizeof(CcwDevice), - .class_size = sizeof(CCWDeviceClass), - .abstract = true, -}; - -static void ccw_device_register(void) -{ - type_register_static(&ccw_device_info); -} - -type_init(ccw_device_register) diff --git a/hw/s390x/ccw-device.h b/hw/s390x/ccw-device.h deleted file mode 100644 index 59ba01b6c..000000000 --- a/hw/s390x/ccw-device.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Common device infrastructure for devices in the virtual css - * - * Copyright 2016 IBM Corp. - * Author(s): Jing Liu <liujbjl@linux.vnet.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or (at - * your option) any later version. See the COPYING file in the top-level - * directory. - */ - -#ifndef HW_S390X_CCW_DEVICE_H -#define HW_S390X_CCW_DEVICE_H -#include "qom/object.h" -#include "hw/qdev-core.h" -#include "hw/s390x/css.h" - -typedef struct CcwDevice { - DeviceState parent_obj; - SubchDev *sch; - /* <cssid>.<ssid>.<device number> */ - CssDevId bus_id; -} CcwDevice; - -typedef struct CCWDeviceClass { - DeviceClass parent_class; - void (*unplug)(HotplugHandler *, DeviceState *, Error **); -} CCWDeviceClass; - -static inline CcwDevice *to_ccw_dev_fast(DeviceState *d) -{ - return container_of(d, CcwDevice, parent_obj); -} - -#define TYPE_CCW_DEVICE "ccw-device" - -#define CCW_DEVICE(obj) OBJECT_CHECK(CcwDevice, (obj), TYPE_CCW_DEVICE) -#define CCW_DEVICE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(CCWDeviceClass, (obj), TYPE_CCW_DEVICE) -#define CCW_DEVICE_CLASS(klass) \ - OBJECT_CLASS_CHECK(CCWDeviceClass, (klass), TYPE_CCW_DEVICE) - -#endif diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c deleted file mode 100644 index 9a7f7ee60..000000000 --- a/hw/s390x/css-bridge.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * css bridge implementation - * - * Copyright 2012,2016 IBM Corp. - * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> - * Pierre Morel <pmorel@linux.vnet.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or (at - * your option) any later version. See the COPYING file in the top-level - * directory. - */ -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hotplug.h" -#include "hw/sysbus.h" -#include "qemu/bitops.h" -#include "hw/s390x/css.h" -#include "ccw-device.h" -#include "hw/s390x/css-bridge.h" - -/* - * Invoke device-specific unplug handler, disable the subchannel - * (including sending a channel report to the guest) and remove the - * device from the virtual css bus. - */ -static void ccw_device_unplug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - CcwDevice *ccw_dev = CCW_DEVICE(dev); - CCWDeviceClass *k = CCW_DEVICE_GET_CLASS(ccw_dev); - SubchDev *sch = ccw_dev->sch; - Error *err = NULL; - - if (k->unplug) { - k->unplug(hotplug_dev, dev, &err); - if (err) { - error_propagate(errp, err); - return; - } - } - - /* - * We should arrive here only for device_del, since we don't support - * direct hot(un)plug of channels. - */ - assert(sch != NULL); - /* Subchannel is now disabled and no longer valid. */ - sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA | - PMCW_FLAGS_MASK_DNV); - - css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); - - object_unparent(OBJECT(dev)); -} - -static void virtual_css_bus_reset(BusState *qbus) -{ - /* This should actually be modelled via the generic css */ - css_reset(); -} - -static char *virtual_css_bus_get_dev_path(DeviceState *dev) -{ - CcwDevice *ccw_dev = CCW_DEVICE(dev); - SubchDev *sch = ccw_dev->sch; - VirtualCssBridge *bridge = - VIRTUAL_CSS_BRIDGE(qdev_get_parent_bus(dev)->parent); - - /* - * We can't provide a dev path for backward compatibility on - * older machines, as it is visible in the migration stream. - */ - return bridge->css_dev_path ? - g_strdup_printf("/%02x.%1x.%04x", sch->cssid, sch->ssid, sch->devno) : - NULL; -} - -static void virtual_css_bus_class_init(ObjectClass *klass, void *data) -{ - BusClass *k = BUS_CLASS(klass); - - k->reset = virtual_css_bus_reset; - k->get_dev_path = virtual_css_bus_get_dev_path; -} - -static const TypeInfo virtual_css_bus_info = { - .name = TYPE_VIRTUAL_CSS_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(VirtualCssBus), - .class_init = virtual_css_bus_class_init, -}; - -VirtualCssBus *virtual_css_bus_init(void) -{ - VirtualCssBus *cbus; - BusState *bus; - DeviceState *dev; - - /* Create bridge device */ - dev = qdev_create(NULL, TYPE_VIRTUAL_CSS_BRIDGE); - qdev_init_nofail(dev); - - /* Create bus on bridge device */ - bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); - cbus = VIRTUAL_CSS_BUS(bus); - - /* Enable hotplugging */ - qbus_set_hotplug_handler(bus, dev, &error_abort); - - return cbus; - } - -/***************** Virtual-css Bus Bridge Device ********************/ - -static Property virtual_css_bridge_properties[] = { - DEFINE_PROP_BOOL("css_dev_path", VirtualCssBridge, css_dev_path, - true), - DEFINE_PROP_END_OF_LIST(), -}; - -static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) -{ - HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - - hc->unplug = ccw_device_unplug; - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->props = virtual_css_bridge_properties; -} - -static const TypeInfo virtual_css_bridge_info = { - .name = TYPE_VIRTUAL_CSS_BRIDGE, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(VirtualCssBridge), - .class_init = virtual_css_bridge_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, - { } - } -}; - -static void virtual_css_register(void) -{ - type_register_static(&virtual_css_bridge_info); - type_register_static(&virtual_css_bus_info); -} - -type_init(virtual_css_register) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index bb8e4be33..3a1d91958 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -10,14 +10,12 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" -#include "qapi/visitor.h" -#include "hw/qdev.h" +#include <hw/qdev.h> #include "qemu/bitops.h" #include "exec/address-spaces.h" #include "cpu.h" -#include "hw/s390x/ioinst.h" -#include "hw/s390x/css.h" +#include "ioinst.h" +#include "css.h" #include "trace.h" #include "hw/s390x/s390_flic.h" @@ -194,46 +192,12 @@ out: return ret; } -static void css_clear_io_interrupt(uint16_t subchannel_id, - uint16_t subchannel_nr) -{ - Error *err = NULL; - static bool no_clear_irq; - S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); - int r; - - if (unlikely(no_clear_irq)) { - return; - } - r = fsc->clear_io_irq(fs, subchannel_id, subchannel_nr); - switch (r) { - case 0: - break; - case -ENOSYS: - no_clear_irq = true; - /* - * Ignore unavailability, as the user can't do anything - * about it anyway. - */ - break; - default: - error_setg_errno(&err, -r, "unexpected error condition"); - error_propagate(&error_abort, err); - } -} - -static inline uint16_t css_do_build_subchannel_id(uint8_t cssid, uint8_t ssid) +uint16_t css_build_subchannel_id(SubchDev *sch) { if (channel_subsys.max_cssid > 0) { - return (cssid << 8) | (1 << 3) | (ssid << 1) | 1; + return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1; } - return (ssid << 1) | 1; -} - -uint16_t css_build_subchannel_id(SubchDev *sch) -{ - return css_do_build_subchannel_id(sch->cssid, sch->ssid); + return (sch->ssid << 1) | 1; } static void css_inject_io_interrupt(SubchDev *sch) @@ -511,7 +475,6 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb) path = 0x80; if (!(s->ctrl & SCSW_ACTL_SUSP)) { - /* Start Function triggered via ssch, i.e. we have an ORB */ s->cstat = 0; s->dstat = 0; /* Look at the orb and try to execute the channel program. */ @@ -525,12 +488,9 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb) return; } sch->ccw_fmt_1 = !!(orb->ctrl0 & ORB_CTRL0_MASK_FMT); - s->flags |= (sch->ccw_fmt_1) ? SCSW_FLAGS_MASK_FMT : 0; sch->ccw_no_data_cnt = 0; suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND); } else { - /* Start Function resumed via rsch, i.e. we don't have an - * ORB */ s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND); /* The channel program had been suspended before. */ suspend_allowed = true; @@ -613,7 +573,6 @@ static void do_subchannel_work(SubchDev *sch, ORB *orb) } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) { sch_handle_halt_func(sch); } else if (s->ctrl & SCSW_FCTL_START_FUNC) { - /* Triggered by both ssch and rsch. */ sch_handle_start_func(sch, orb); } else { /* Cannot happen. */ @@ -1345,116 +1304,6 @@ SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid) return channel_subsys.css[real_cssid]->sch_set[ssid]->sch[schid]; } -/** - * Return free device number in subchannel set. - * - * Return index of the first free device number in the subchannel set - * identified by @p cssid and @p ssid, beginning the search at @p - * start and wrapping around at MAX_DEVNO. Return a value exceeding - * MAX_SCHID if there are no free device numbers in the subchannel - * set. - */ -static uint32_t css_find_free_devno(uint8_t cssid, uint8_t ssid, - uint16_t start) -{ - uint32_t round; - - for (round = 0; round <= MAX_DEVNO; round++) { - uint16_t devno = (start + round) % MAX_DEVNO; - - if (!css_devno_used(cssid, ssid, devno)) { - return devno; - } - } - return MAX_DEVNO + 1; -} - -/** - * Return first free subchannel (id) in subchannel set. - * - * Return index of the first free subchannel in the subchannel set - * identified by @p cssid and @p ssid, if there is any. Return a value - * exceeding MAX_SCHID if there are no free subchannels in the - * subchannel set. - */ -static uint32_t css_find_free_subch(uint8_t cssid, uint8_t ssid) -{ - uint32_t schid; - - for (schid = 0; schid <= MAX_SCHID; schid++) { - if (!css_find_subch(1, cssid, ssid, schid)) { - return schid; - } - } - return MAX_SCHID + 1; -} - -/** - * Return first free subchannel (id) in subchannel set for a device number - * - * Verify the device number @p devno is not used yet in the subchannel - * set identified by @p cssid and @p ssid. Set @p schid to the index - * of the first free subchannel in the subchannel set, if there is - * any. Return true if everything succeeded and false otherwise. - */ -static bool css_find_free_subch_for_devno(uint8_t cssid, uint8_t ssid, - uint16_t devno, uint16_t *schid, - Error **errp) -{ - uint32_t free_schid; - - assert(schid); - if (css_devno_used(cssid, ssid, devno)) { - error_setg(errp, "Device %x.%x.%04x already exists", - cssid, ssid, devno); - return false; - } - free_schid = css_find_free_subch(cssid, ssid); - if (free_schid > MAX_SCHID) { - error_setg(errp, "No free subchannel found for %x.%x.%04x", - cssid, ssid, devno); - return false; - } - *schid = free_schid; - return true; -} - -/** - * Return first free subchannel (id) and device number - * - * Locate the first free subchannel and first free device number in - * any of the subchannel sets of the channel subsystem identified by - * @p cssid. Return false if no free subchannel / device number could - * be found. Otherwise set @p ssid, @p devno and @p schid to identify - * the available subchannel and device number and return true. - * - * May modify @p ssid, @p devno and / or @p schid even if no free - * subchannel / device number could be found. - */ -static bool css_find_free_subch_and_devno(uint8_t cssid, uint8_t *ssid, - uint16_t *devno, uint16_t *schid, - Error **errp) -{ - uint32_t free_schid, free_devno; - - assert(ssid && devno && schid); - for (*ssid = 0; *ssid <= MAX_SSID; (*ssid)++) { - free_schid = css_find_free_subch(cssid, *ssid); - if (free_schid > MAX_SCHID) { - continue; - } - free_devno = css_find_free_devno(cssid, *ssid, free_schid); - if (free_devno > MAX_DEVNO) { - continue; - } - *schid = free_schid; - *devno = free_devno; - return true; - } - error_setg(errp, "Virtual channel subsystem is full!"); - return false; -} - bool css_subch_visible(SubchDev *sch) { if (sch->ssid > channel_subsys.max_ssid) { @@ -1580,8 +1429,6 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0, (guest_cssid << 8) | (ssid << 4)); } - /* RW_ERC_IPI --> clear pending interrupts */ - css_clear_io_interrupt(css_do_build_subchannel_id(cssid, ssid), schid); } void css_generate_chp_crws(uint8_t cssid, uint8_t chpid) @@ -1797,116 +1644,3 @@ void css_reset(void) channel_subsys.max_cssid = 0; channel_subsys.max_ssid = 0; } - -static void get_css_devid(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - CssDevId *dev_id = qdev_get_prop_ptr(dev, prop); - char buffer[] = "xx.x.xxxx"; - char *p = buffer; - int r; - - if (dev_id->valid) { - - r = snprintf(buffer, sizeof(buffer), "%02x.%1x.%04x", dev_id->cssid, - dev_id->ssid, dev_id->devid); - assert(r == sizeof(buffer) - 1); - - /* drop leading zero */ - if (dev_id->cssid <= 0xf) { - p++; - } - } else { - snprintf(buffer, sizeof(buffer), "<unset>"); - } - - visit_type_str(v, name, &p, errp); -} - -/* - * parse <cssid>.<ssid>.<devid> and assert valid range for cssid/ssid - */ -static void set_css_devid(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - CssDevId *dev_id = qdev_get_prop_ptr(dev, prop); - Error *local_err = NULL; - char *str; - int num, n1, n2; - unsigned int cssid, ssid, devid; - - if (dev->realized) { - qdev_prop_set_after_realize(dev, name, errp); - return; - } - - visit_type_str(v, name, &str, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - num = sscanf(str, "%2x.%1x%n.%4x%n", &cssid, &ssid, &n1, &devid, &n2); - if (num != 3 || (n2 - n1) != 5 || strlen(str) != n2) { - error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); - goto out; - } - if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) { - error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x", - cssid, ssid); - goto out; - } - - dev_id->cssid = cssid; - dev_id->ssid = ssid; - dev_id->devid = devid; - dev_id->valid = true; - -out: - g_free(str); -} - -PropertyInfo css_devid_propinfo = { - .name = "str", - .description = "Identifier of an I/O device in the channel " - "subsystem, example: fe.1.23ab", - .get = get_css_devid, - .set = set_css_devid, -}; - -SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp) -{ - uint16_t schid = 0; - SubchDev *sch; - - if (bus_id.valid) { - /* Enforce use of virtual cssid. */ - if (bus_id.cssid != VIRTUAL_CSSID) { - error_setg(errp, "cssid %hhx not valid for virtual devices", - bus_id.cssid); - return NULL; - } - if (!css_find_free_subch_for_devno(bus_id.cssid, bus_id.ssid, - bus_id.devid, &schid, errp)) { - return NULL; - } - } else { - bus_id.cssid = VIRTUAL_CSSID; - if (!css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid, - &bus_id.devid, &schid, errp)) { - return NULL; - } - } - - sch = g_malloc0(sizeof(*sch)); - sch->cssid = bus_id.cssid; - sch->ssid = bus_id.ssid; - sch->devno = bus_id.devid; - sch->schid = schid; - css_subch_assign(sch->cssid, sch->ssid, schid, sch->devno, sch); - return sch; -} diff --git a/hw/s390x/css.h b/hw/s390x/css.h new file mode 100644 index 000000000..a320eea59 --- /dev/null +++ b/hw/s390x/css.h @@ -0,0 +1,126 @@ +/* + * Channel subsystem structures and definitions. + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef CSS_H +#define CSS_H + +#include "hw/s390x/adapter.h" +#include "hw/s390x/s390_flic.h" +#include "ioinst.h" + +/* Channel subsystem constants. */ +#define MAX_SCHID 65535 +#define MAX_SSID 3 +#define MAX_CSSID 254 /* 255 is reserved */ +#define MAX_CHPID 255 + +#define MAX_CIWS 62 + +typedef struct CIW { + uint8_t type; + uint8_t command; + uint16_t count; +} QEMU_PACKED CIW; + +typedef struct SenseId { + /* common part */ + uint8_t reserved; /* always 0x'FF' */ + uint16_t cu_type; /* control unit type */ + uint8_t cu_model; /* control unit model */ + uint16_t dev_type; /* device type */ + uint8_t dev_model; /* device model */ + uint8_t unused; /* padding byte */ + /* extended part */ + CIW ciw[MAX_CIWS]; /* variable # of CIWs */ +} QEMU_PACKED SenseId; + +/* Channel measurements, from linux/drivers/s390/cio/cmf.c. */ +typedef struct CMB { + uint16_t ssch_rsch_count; + uint16_t sample_count; + uint32_t device_connect_time; + uint32_t function_pending_time; + uint32_t device_disconnect_time; + uint32_t control_unit_queuing_time; + uint32_t device_active_only_time; + uint32_t reserved[2]; +} QEMU_PACKED CMB; + +typedef struct CMBE { + uint32_t ssch_rsch_count; + uint32_t sample_count; + uint32_t device_connect_time; + uint32_t function_pending_time; + uint32_t device_disconnect_time; + uint32_t control_unit_queuing_time; + uint32_t device_active_only_time; + uint32_t device_busy_time; + uint32_t initial_command_response_time; + uint32_t reserved[7]; +} QEMU_PACKED CMBE; + +struct SubchDev { + /* channel-subsystem related things: */ + uint8_t cssid; + uint8_t ssid; + uint16_t schid; + uint16_t devno; + SCHIB curr_status; + uint8_t sense_data[32]; + hwaddr channel_prog; + CCW1 last_cmd; + bool last_cmd_valid; + bool ccw_fmt_1; + bool thinint_active; + uint8_t ccw_no_data_cnt; + /* transport-provided data: */ + int (*ccw_cb) (SubchDev *, CCW1); + void (*disable_cb)(SubchDev *); + SenseId id; + void *driver_data; +}; + +typedef struct IndAddr { + hwaddr addr; + uint64_t map; + unsigned long refcnt; + int len; + QTAILQ_ENTRY(IndAddr) sibling; +} IndAddr; + +IndAddr *get_indicator(hwaddr ind_addr, int len); +void release_indicator(AdapterInfo *adapter, IndAddr *indicator); +int map_indicator(AdapterInfo *adapter, IndAddr *indicator); + +typedef SubchDev *(*css_subch_cb_func)(uint8_t m, uint8_t cssid, uint8_t ssid, + uint16_t schid); +void subch_device_save(SubchDev *s, QEMUFile *f); +int subch_device_load(SubchDev *s, QEMUFile *f); +int css_create_css_image(uint8_t cssid, bool default_image); +bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno); +void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, + uint16_t devno, SubchDev *sch); +void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type); +uint16_t css_build_subchannel_id(SubchDev *sch); +void css_reset(void); +void css_reset_sch(SubchDev *sch); +void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid); +void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, + int hotplugged, int add); +void css_generate_chp_crws(uint8_t cssid, uint8_t chpid); +void css_generate_css_crws(uint8_t cssid); +void css_clear_sei_pending(void); +void css_adapter_interrupt(uint8_t isc); + +#define CSS_IO_ADAPTER_VIRTIO 1 +int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap, + bool maskable, uint32_t *id); +#endif diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 2e2664f22..3173dcfdf 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -30,24 +30,6 @@ #define ZIPL_IMAGE_START 0x009000UL #define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64) -static bool iplb_extended_needed(void *opaque) -{ - S390IPLState *ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL)); - - return ipl->iplbext_migration; -} - -static const VMStateDescription vmstate_iplb_extended = { - .name = "ipl/iplb_extended", - .version_id = 0, - .minimum_version_id = 0, - .needed = iplb_extended_needed, - .fields = (VMStateField[]) { - VMSTATE_UINT8_ARRAY(reserved_ext, IplParameterBlock, 4096 - 200), - VMSTATE_END_OF_LIST() - } -}; - static const VMStateDescription vmstate_iplb = { .name = "ipl/iplb", .version_id = 0, @@ -57,10 +39,6 @@ static const VMStateDescription vmstate_iplb = { VMSTATE_UINT16(devno, IplParameterBlock), VMSTATE_UINT8_ARRAY(reserved2, IplParameterBlock, 88), VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &vmstate_iplb_extended, - NULL } }; @@ -129,7 +107,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) /* Adjust ELF start address to final location */ ipl->bios_start_addr += fwbase; } else { - /* Try to load non-ELF file */ + /* Try to load non-ELF file (e.g. s390-ccw.img) */ bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START, 4096); ipl->bios_start_addr = ZIPL_IMAGE_START; @@ -210,52 +188,46 @@ static Property s390_ipl_properties[] = { DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline), DEFINE_PROP_STRING("firmware", S390IPLState, firmware), DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false), - DEFINE_PROP_BOOL("iplbext_migration", S390IPLState, iplbext_migration, - true), DEFINE_PROP_END_OF_LIST(), }; -static bool s390_gen_initial_iplb(S390IPLState *ipl) +/* + * In addition to updating the iplstate, this function returns: + * - 0 if system was ipled with external kernel + * - -1 if no valid boot device was found + * - ccw id of the boot device otherwise + */ +static uint64_t s390_update_iplstate(S390IPLState *ipl) { DeviceState *dev_st; + if (ipl->iplb_valid) { + ipl->cssid = 0; + ipl->ssid = 0; + ipl->devno = ipl->iplb.devno; + goto out; + } + + if (ipl->kernel) { + return 0; + } + dev_st = get_boot_device(0); if (dev_st) { - VirtioCcwDevice *virtio_ccw_dev = (VirtioCcwDevice *) - object_dynamic_cast(OBJECT(qdev_get_parent_bus(dev_st)->parent), + VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast( + OBJECT(qdev_get_parent_bus(dev_st)->parent), TYPE_VIRTIO_CCW_DEVICE); - SCSIDevice *sd = (SCSIDevice *) object_dynamic_cast(OBJECT(dev_st), - TYPE_SCSI_DEVICE); - if (virtio_ccw_dev) { - CcwDevice *ccw_dev = CCW_DEVICE(virtio_ccw_dev); - - ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN); - ipl->iplb.blk0_len = - cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN); - ipl->iplb.pbt = S390_IPL_TYPE_CCW; - ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno); - ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3; - return true; - } else if (sd) { - SCSIBus *bus = scsi_bus_from_device(sd); - VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus); - VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev); - CcwDevice *ccw_dev = CCW_DEVICE(scsi_ccw); - - ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN); - ipl->iplb.blk0_len = - cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN); - ipl->iplb.pbt = S390_IPL_TYPE_QEMU_SCSI; - ipl->iplb.scsi.lun = cpu_to_be32(sd->lun); - ipl->iplb.scsi.target = cpu_to_be16(sd->id); - ipl->iplb.scsi.channel = cpu_to_be16(sd->channel); - ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno); - ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3; - return true; + if (ccw_dev) { + ipl->cssid = ccw_dev->sch->cssid; + ipl->ssid = ccw_dev->sch->ssid; + ipl->devno = ccw_dev->sch->devno; + goto out; } } - return false; + return -1; +out: + return (uint32_t) (ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno); } void s390_ipl_update_diag308(IplParameterBlock *iplb) @@ -293,9 +265,7 @@ void s390_ipl_prepare_cpu(S390CPU *cpu) if (!ipl->kernel || ipl->iplb_valid) { cpu->env.psw.addr = ipl->bios_start_addr; - if (!ipl->iplb_valid) { - ipl->iplb_valid = s390_gen_initial_iplb(ipl); - } + cpu->env.regs[7] = s390_update_iplstate(ipl); } } @@ -305,7 +275,6 @@ static void s390_ipl_reset(DeviceState *dev) if (!ipl->reipl_requested) { ipl->iplb_valid = false; - memset(&ipl->iplb, 0, sizeof(IplParameterBlock)); } ipl->reipl_requested = false; } diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index c89109585..0bfb72b71 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -15,71 +15,11 @@ #include "hw/qdev.h" #include "cpu.h" -struct IplBlockCcw { - uint8_t reserved0[85]; - uint8_t ssid; - uint16_t devno; - uint8_t vm_flags; - uint8_t reserved3[3]; - uint32_t vm_parm_len; - uint8_t nss_name[8]; - uint8_t vm_parm[64]; - uint8_t reserved4[8]; -} QEMU_PACKED; -typedef struct IplBlockCcw IplBlockCcw; - -struct IplBlockFcp { - uint8_t reserved1[305 - 1]; - uint8_t opt; - uint8_t reserved2[3]; - uint16_t reserved3; - uint16_t devno; - uint8_t reserved4[4]; - uint64_t wwpn; - uint64_t lun; - uint32_t bootprog; - uint8_t reserved5[12]; - uint64_t br_lba; - uint32_t scp_data_len; - uint8_t reserved6[260]; - uint8_t scp_data[]; -} QEMU_PACKED; -typedef struct IplBlockFcp IplBlockFcp; - -struct IplBlockQemuScsi { - uint32_t lun; - uint16_t target; - uint16_t channel; - uint8_t reserved0[77]; - uint8_t ssid; - uint16_t devno; -} QEMU_PACKED; -typedef struct IplBlockQemuScsi IplBlockQemuScsi; - -union IplParameterBlock { - struct { - uint32_t len; - uint8_t reserved0[3]; - uint8_t version; - uint32_t blk0_len; - uint8_t pbt; - uint8_t flags; - uint16_t reserved01; - uint8_t loadparm[8]; - union { - IplBlockCcw ccw; - IplBlockFcp fcp; - IplBlockQemuScsi scsi; - }; - } QEMU_PACKED; - struct { - uint8_t reserved1[110]; - uint16_t devno; - uint8_t reserved2[88]; - uint8_t reserved_ext[4096 - 200]; - } QEMU_PACKED; -} QEMU_PACKED; -typedef union IplParameterBlock IplParameterBlock; +typedef struct IplParameterBlock { + uint8_t reserved1[110]; + uint16_t devno; + uint8_t reserved2[88]; +} IplParameterBlock; void s390_ipl_update_diag308(IplParameterBlock *iplb); void s390_ipl_prepare_cpu(S390CPU *cpu); @@ -109,34 +49,7 @@ struct S390IPLState { uint8_t cssid; uint8_t ssid; uint16_t devno; - bool iplbext_migration; }; typedef struct S390IPLState S390IPLState; -#define S390_IPL_TYPE_FCP 0x00 -#define S390_IPL_TYPE_CCW 0x02 -#define S390_IPL_TYPE_QEMU_SCSI 0xff - -#define S390_IPLB_HEADER_LEN 8 -#define S390_IPLB_MIN_CCW_LEN 200 -#define S390_IPLB_MIN_FCP_LEN 384 -#define S390_IPLB_MIN_QEMU_SCSI_LEN 200 - -static inline bool iplb_valid_len(IplParameterBlock *iplb) -{ - return be32_to_cpu(iplb->len) <= sizeof(IplParameterBlock); -} - -static inline bool iplb_valid_ccw(IplParameterBlock *iplb) -{ - return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN && - iplb->pbt == S390_IPL_TYPE_CCW; -} - -static inline bool iplb_valid_fcp(IplParameterBlock *iplb) -{ - return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN && - iplb->pbt == S390_IPL_TYPE_FCP; -} - #endif diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 9c1c04e59..918b58543 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -12,15 +12,12 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" -#include "qapi/visitor.h" #include "qemu-common.h" #include "cpu.h" #include "s390-pci-bus.h" -#include "s390-pci-inst.h" -#include "hw/pci/pci_bus.h" -#include "hw/pci/msi.h" -#include "qemu/error-report.h" +#include <hw/pci/pci_bus.h> +#include <hw/pci/msi.h> +#include <qemu/error-report.h> /* #define DEBUG_S390PCI_BUS */ #ifdef DEBUG_S390PCI_BUS @@ -31,19 +28,6 @@ do { } while (0) #endif -static S390pciState *s390_get_phb(void) -{ - static S390pciState *phb; - - if (!phb) { - phb = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - assert(phb != NULL); - } - - return phb; -} - int chsc_sei_nt2_get_event(void *res) { ChscSeiNt2Res *nt2_res = (ChscSeiNt2Res *)res; @@ -51,7 +35,12 @@ int chsc_sei_nt2_get_event(void *res) PciCcdfErr *eccdf; int rc = 1; SeiContainer *sei_cont; - S390pciState *s = s390_get_phb(); + S390pciState *s = S390_PCI_HOST_BRIDGE( + object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); + + if (!s) { + return rc; + } sei_cont = QTAILQ_FIRST(&s->pending_sei); if (sei_cont) { @@ -86,40 +75,30 @@ int chsc_sei_nt2_get_event(void *res) int chsc_sei_nt2_have_event(void) { - S390pciState *s = s390_get_phb(); - - return !QTAILQ_EMPTY(&s->pending_sei); -} + S390pciState *s = S390_PCI_HOST_BRIDGE( + object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); -S390PCIBusDevice *s390_pci_find_next_avail_dev(S390PCIBusDevice *pbdev) -{ - int idx = 0; - S390PCIBusDevice *dev = NULL; - S390pciState *s = s390_get_phb(); - - if (pbdev) { - idx = (pbdev->fh & FH_MASK_INDEX) + 1; - } - - for (; idx < PCI_SLOT_MAX; idx++) { - dev = s->pbdev[idx]; - if (dev && dev->state != ZPCI_FS_RESERVED) { - return dev; - } + if (!s) { + return 0; } - return NULL; + return !QTAILQ_EMPTY(&s->pending_sei); } S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid) { S390PCIBusDevice *pbdev; int i; - S390pciState *s = s390_get_phb(); + S390pciState *s = S390_PCI_HOST_BRIDGE( + object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); + + if (!s) { + return NULL; + } for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = s->pbdev[i]; - if (pbdev && pbdev->fid == fid) { + pbdev = &s->pbdev[i]; + if ((pbdev->fh != 0) && (pbdev->fid == fid)) { return pbdev; } } @@ -127,139 +106,82 @@ S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid) return NULL; } -void s390_pci_sclp_configure(SCCB *sccb) +void s390_pci_sclp_configure(int configure, SCCB *sccb) { PciCfgSccb *psccb = (PciCfgSccb *)sccb; S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid)); uint16_t rc; - if (be16_to_cpu(sccb->h.length) < 16) { - rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH; - goto out; - } - - if (!pbdev) { - DPRINTF("sclp config no dev found\n"); + if (pbdev) { + if ((configure == 1 && pbdev->configured == true) || + (configure == 0 && pbdev->configured == false)) { + rc = SCLP_RC_NO_ACTION_REQUIRED; + } else { + pbdev->configured = !pbdev->configured; + rc = SCLP_RC_NORMAL_COMPLETION; + } + } else { + DPRINTF("sclp config %d no dev found\n", configure); rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED; - goto out; } - switch (pbdev->state) { - case ZPCI_FS_RESERVED: - rc = SCLP_RC_ADAPTER_IN_RESERVED_STATE; - break; - case ZPCI_FS_STANDBY: - pbdev->state = ZPCI_FS_DISABLED; - rc = SCLP_RC_NORMAL_COMPLETION; - break; - default: - rc = SCLP_RC_NO_ACTION_REQUIRED; - } -out: psccb->header.response_code = cpu_to_be16(rc); } -void s390_pci_sclp_deconfigure(SCCB *sccb) +static uint32_t s390_pci_get_pfid(PCIDevice *pdev) { - PciCfgSccb *psccb = (PciCfgSccb *)sccb; - S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid)); - uint16_t rc; - - if (be16_to_cpu(sccb->h.length) < 16) { - rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH; - goto out; - } - - if (!pbdev) { - DPRINTF("sclp deconfig no dev found\n"); - rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED; - goto out; - } - - switch (pbdev->state) { - case ZPCI_FS_RESERVED: - rc = SCLP_RC_ADAPTER_IN_RESERVED_STATE; - break; - case ZPCI_FS_STANDBY: - rc = SCLP_RC_NO_ACTION_REQUIRED; - break; - default: - if (pbdev->summary_ind) { - pci_dereg_irqs(pbdev); - } - if (pbdev->iommu_enabled) { - pci_dereg_ioat(pbdev); - } - pbdev->state = ZPCI_FS_STANDBY; - rc = SCLP_RC_NORMAL_COMPLETION; - - if (pbdev->release_timer) { - qdev_unplug(DEVICE(pbdev->pdev), NULL); - } - } -out: - psccb->header.response_code = cpu_to_be16(rc); + return PCI_SLOT(pdev->devfn); } -static S390PCIBusDevice *s390_pci_find_dev_by_uid(uint16_t uid) +static uint32_t s390_pci_get_pfh(PCIDevice *pdev) { - int i; - S390PCIBusDevice *pbdev; - S390pciState *s = s390_get_phb(); - - for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = s->pbdev[i]; - if (!pbdev) { - continue; - } - - if (pbdev->uid == uid) { - return pbdev; - } - } - - return NULL; + return PCI_SLOT(pdev->devfn) | FH_VIRT; } -static S390PCIBusDevice *s390_pci_find_dev_by_target(const char *target) +S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx) { - int i; S390PCIBusDevice *pbdev; - S390pciState *s = s390_get_phb(); + int i; + int j = 0; + S390pciState *s = S390_PCI_HOST_BRIDGE( + object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - if (!target) { + if (!s) { return NULL; } for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = s->pbdev[i]; - if (!pbdev) { + pbdev = &s->pbdev[i]; + + if (pbdev->fh == 0) { continue; } - if (!strcmp(pbdev->target, target)) { + if (j == idx) { return pbdev; } + j++; } return NULL; } -S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx) -{ - S390pciState *s = s390_get_phb(); - - return s->pbdev[idx & FH_MASK_INDEX]; -} - S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh) { - S390pciState *s = s390_get_phb(); S390PCIBusDevice *pbdev; + int i; + S390pciState *s = S390_PCI_HOST_BRIDGE( + object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - pbdev = s->pbdev[fh & FH_MASK_INDEX]; - if (pbdev && pbdev->fh == fh) { - return pbdev; + if (!s || !fh) { + return NULL; + } + + for (i = 0; i < PCI_SLOT_MAX; i++) { + pbdev = &s->pbdev[i]; + if (pbdev->fh == fh) { + return pbdev; + } } return NULL; @@ -269,7 +191,12 @@ static void s390_pci_generate_event(uint8_t cc, uint16_t pec, uint32_t fh, uint32_t fid, uint64_t faddr, uint32_t e) { SeiContainer *sei_cont; - S390pciState *s = s390_get_phb(); + S390pciState *s = S390_PCI_HOST_BRIDGE( + object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); + + if (!s) { + return; + } sei_cont = g_malloc0(sizeof(SeiContainer)); sei_cont->fh = fh; @@ -289,8 +216,9 @@ static void s390_pci_generate_plug_event(uint16_t pec, uint32_t fh, s390_pci_generate_event(2, pec, fh, fid, 0, 0); } -void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, - uint64_t faddr, uint32_t e) +static void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, + uint32_t fid, uint64_t faddr, + uint32_t e) { s390_pci_generate_event(1, pec, fh, fid, faddr, e); } @@ -392,14 +320,7 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr, .perm = IOMMU_NONE, }; - switch (pbdev->state) { - case ZPCI_FS_ENABLED: - case ZPCI_FS_BLOCKED: - if (!pbdev->iommu_enabled) { - return ret; - } - break; - default: + if (!pbdev->configured || !pbdev->pdev || !(pbdev->fh & FH_ENABLED)) { return ret; } @@ -418,13 +339,30 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr, return ret; } + if (!pbdev->g_iota) { + pbdev->error_state = true; + pbdev->lgstg_blocked = true; + s390_pci_generate_error_event(ERR_EVENT_INVALAS, pbdev->fh, pbdev->fid, + addr, 0); + return ret; + } + if (addr < pbdev->pba || addr > pbdev->pal) { + pbdev->error_state = true; + pbdev->lgstg_blocked = true; + s390_pci_generate_error_event(ERR_EVENT_OORANGE, pbdev->fh, pbdev->fid, + addr, 0); return ret; } pte = s390_guest_io_table_walk(s390_pci_get_table_origin(pbdev->g_iota), addr); + if (!pte) { + pbdev->error_state = true; + pbdev->lgstg_blocked = true; + s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid, + addr, ERR_EVENT_Q_BIT); return ret; } @@ -450,7 +388,7 @@ static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) { S390pciState *s = opaque; - return &s->iommu[PCI_SLOT(devfn)]->as; + return &s->pbdev[PCI_SLOT(devfn)].as; } static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) @@ -478,22 +416,22 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data, { S390PCIBusDevice *pbdev; uint32_t io_int_word; - uint32_t idx = data >> ZPCI_MSI_VEC_BITS; + uint32_t fid = data >> ZPCI_MSI_VEC_BITS; uint32_t vec = data & ZPCI_MSI_VEC_MASK; uint64_t ind_bit; uint32_t sum_bit; uint32_t e = 0; - DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data, idx, vec); + DPRINTF("write_msix data 0x%" PRIx64 " fid %d vec 0x%x\n", data, fid, vec); - pbdev = s390_pci_find_dev_by_idx(idx); + pbdev = s390_pci_find_dev_by_fid(fid); if (!pbdev) { e |= (vec << ERR_EVENT_MVN_OFFSET); - s390_pci_generate_error_event(ERR_EVENT_NOMSI, idx, 0, addr, e); + s390_pci_generate_error_event(ERR_EVENT_NOMSI, 0, fid, addr, e); return; } - if (pbdev->state != ZPCI_FS_ENABLED) { + if (!(pbdev->fh & FH_ENABLED)) { return; } @@ -520,33 +458,32 @@ static const MemoryRegionOps s390_msi_ctrl_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) +void s390_pcihost_iommu_configure(S390PCIBusDevice *pbdev, bool enable) { - memory_region_init_iommu(&pbdev->iommu_mr, OBJECT(&pbdev->iommu->mr), - &s390_iommu_ops, "iommu-s390", pbdev->pal + 1); - memory_region_add_subregion(&pbdev->iommu->mr, 0, &pbdev->iommu_mr); - pbdev->iommu_enabled = true; -} + pbdev->configured = false; -void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) -{ - memory_region_del_subregion(&pbdev->iommu->mr, &pbdev->iommu_mr); - object_unparent(OBJECT(&pbdev->iommu_mr)); - pbdev->iommu_enabled = false; + if (enable) { + uint64_t size = pbdev->pal - pbdev->pba + 1; + memory_region_init_iommu(&pbdev->iommu_mr, OBJECT(&pbdev->mr), + &s390_iommu_ops, "iommu-s390", size); + memory_region_add_subregion(&pbdev->mr, pbdev->pba, &pbdev->iommu_mr); + } else { + memory_region_del_subregion(&pbdev->mr, &pbdev->iommu_mr); + } + + pbdev->configured = true; } static void s390_pcihost_init_as(S390pciState *s) { int i; - S390PCIIOMMU *iommu; + S390PCIBusDevice *pbdev; for (i = 0; i < PCI_SLOT_MAX; i++) { - iommu = g_malloc0(sizeof(S390PCIIOMMU)); - memory_region_init(&iommu->mr, OBJECT(s), + pbdev = &s->pbdev[i]; + memory_region_init(&pbdev->mr, OBJECT(s), "iommu-root-s390", UINT64_MAX); - address_space_init(&iommu->as, &iommu->mr, "iommu-pci"); - - s->iommu[i] = iommu; + address_space_init(&pbdev->as, &pbdev->mr, "iommu-pci"); } memory_region_init_io(&s->msix_notify_mr, OBJECT(s), @@ -573,10 +510,6 @@ static int s390_pcihost_init(SysBusDevice *dev) bus = BUS(b); qbus_set_hotplug_handler(bus, DEVICE(dev), NULL); phb->bus = b; - - s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, DEVICE(s), NULL)); - qbus_set_hotplug_handler(BUS(s->bus), DEVICE(s), NULL); - QTAILQ_INIT(&s->pending_sei); return 0; } @@ -609,155 +542,51 @@ static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev) return 0; } -static S390PCIBusDevice *s390_pci_device_new(const char *target) -{ - DeviceState *dev = NULL; - S390pciState *s = s390_get_phb(); - - dev = qdev_try_create(BUS(s->bus), TYPE_S390_PCI_DEVICE); - if (!dev) { - return NULL; - } - - qdev_prop_set_string(dev, "target", target); - qdev_init_nofail(dev); - - return S390_PCI_DEVICE(dev); -} - static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - PCIDevice *pdev = NULL; - S390PCIBusDevice *pbdev = NULL; - S390pciState *s = s390_get_phb(); - - if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { - pdev = PCI_DEVICE(dev); - - if (!dev->id) { - /* In the case the PCI device does not define an id */ - /* we generate one based on the PCI address */ - dev->id = g_strdup_printf("auto_%02x:%02x.%01x", - pci_bus_num(pdev->bus), - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); - } - - pbdev = s390_pci_find_dev_by_target(dev->id); - if (!pbdev) { - pbdev = s390_pci_device_new(dev->id); - if (!pbdev) { - error_setg(errp, "create zpci device failed"); - } - } - - if (object_dynamic_cast(OBJECT(dev), "vfio-pci")) { - pbdev->fh |= FH_SHM_VFIO; - } else { - pbdev->fh |= FH_SHM_EMUL; - } + PCIDevice *pci_dev = PCI_DEVICE(dev); + S390PCIBusDevice *pbdev; + S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev) + ->qbus.parent); - pbdev->pdev = pdev; - pbdev->iommu = s->iommu[PCI_SLOT(pdev->devfn)]; - pbdev->state = ZPCI_FS_STANDBY; - s390_pcihost_setup_msix(pbdev); + pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)]; - if (dev->hotplugged) { - s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY, - pbdev->fh, pbdev->fid); - } - } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) { - int idx; - - pbdev = S390_PCI_DEVICE(dev); - for (idx = 0; idx < PCI_SLOT_MAX; idx++) { - if (!s->pbdev[idx]) { - s->pbdev[idx] = pbdev; - pbdev->fh = idx; - return; - } - } + pbdev->fid = s390_pci_get_pfid(pci_dev); + pbdev->pdev = pci_dev; + pbdev->configured = true; + pbdev->fh = s390_pci_get_pfh(pci_dev); - error_setg(errp, "no slot for plugging zpci device"); - } -} - -static void s390_pcihost_timer_cb(void *opaque) -{ - S390PCIBusDevice *pbdev = opaque; + s390_pcihost_setup_msix(pbdev); - if (pbdev->summary_ind) { - pci_dereg_irqs(pbdev); - } - if (pbdev->iommu_enabled) { - pci_dereg_ioat(pbdev); + if (dev->hotplugged) { + s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY, + pbdev->fh, pbdev->fid); + s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED, + pbdev->fh, pbdev->fid); } - - pbdev->state = ZPCI_FS_STANDBY; - s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES, - pbdev->fh, pbdev->fid); - qdev_unplug(DEVICE(pbdev), NULL); } static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - int i; - PCIDevice *pci_dev = NULL; - S390PCIBusDevice *pbdev = NULL; - S390pciState *s = s390_get_phb(); - - if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { - pci_dev = PCI_DEVICE(dev); - - for (i = 0 ; i < PCI_SLOT_MAX; i++) { - if (s->pbdev[i] && s->pbdev[i]->pdev == pci_dev) { - pbdev = s->pbdev[i]; - break; - } - } + PCIDevice *pci_dev = PCI_DEVICE(dev); + S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev) + ->qbus.parent); + S390PCIBusDevice *pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)]; - if (!pbdev) { - object_unparent(OBJECT(pci_dev)); - return; - } - } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) { - pbdev = S390_PCI_DEVICE(dev); - pci_dev = pbdev->pdev; - } - - switch (pbdev->state) { - case ZPCI_FS_RESERVED: - goto out; - case ZPCI_FS_STANDBY: - break; - default: - s390_pci_generate_plug_event(HP_EVENT_DECONFIGURE_REQUEST, + if (pbdev->configured) { + pbdev->configured = false; + s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES, pbdev->fh, pbdev->fid); - pbdev->release_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - s390_pcihost_timer_cb, - pbdev); - timer_mod(pbdev->release_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + HOT_UNPLUG_TIMEOUT); - return; - } - - if (pbdev->release_timer && timer_pending(pbdev->release_timer)) { - timer_del(pbdev->release_timer); - timer_free(pbdev->release_timer); - pbdev->release_timer = NULL; } s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED, pbdev->fh, pbdev->fid); - object_unparent(OBJECT(pci_dev)); - pbdev->pdev = NULL; - pbdev->state = ZPCI_FS_RESERVED; -out: + pbdev->fh = 0; pbdev->fid = 0; - s->pbdev[pbdev->fh & FH_MASK_INDEX] = NULL; - object_unparent(OBJECT(pbdev)); + pbdev->pdev = NULL; + object_unparent(OBJECT(pci_dev)); } static void s390_pcihost_class_init(ObjectClass *klass, void *data) @@ -784,178 +613,9 @@ static const TypeInfo s390_pcihost_info = { } }; -static const TypeInfo s390_pcibus_info = { - .name = TYPE_S390_PCI_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(S390PCIBus), -}; - -static uint16_t s390_pci_generate_uid(void) -{ - uint16_t uid = 0; - - do { - uid++; - if (!s390_pci_find_dev_by_uid(uid)) { - return uid; - } - } while (uid < ZPCI_MAX_UID); - - return UID_UNDEFINED; -} - -static uint32_t s390_pci_generate_fid(Error **errp) -{ - uint32_t fid = 0; - - while (fid <= ZPCI_MAX_FID) { - if (!s390_pci_find_dev_by_fid(fid)) { - return fid; - } - - if (fid == ZPCI_MAX_FID) { - break; - } - - fid++; - } - - error_setg(errp, "no free fid could be found"); - return 0; -} - -static void s390_pci_device_realize(DeviceState *dev, Error **errp) -{ - S390PCIBusDevice *zpci = S390_PCI_DEVICE(dev); - - if (!zpci->target) { - error_setg(errp, "target must be defined"); - return; - } - - if (s390_pci_find_dev_by_target(zpci->target)) { - error_setg(errp, "target %s already has an associated zpci device", - zpci->target); - return; - } - - if (zpci->uid == UID_UNDEFINED) { - zpci->uid = s390_pci_generate_uid(); - if (!zpci->uid) { - error_setg(errp, "no free uid could be found"); - return; - } - } else if (s390_pci_find_dev_by_uid(zpci->uid)) { - error_setg(errp, "uid %u already in use", zpci->uid); - return; - } - - if (!zpci->fid_defined) { - Error *local_error = NULL; - - zpci->fid = s390_pci_generate_fid(&local_error); - if (local_error) { - error_propagate(errp, local_error); - return; - } - } else if (s390_pci_find_dev_by_fid(zpci->fid)) { - error_setg(errp, "fid %u already in use", zpci->fid); - return; - } - - zpci->state = ZPCI_FS_RESERVED; -} - -static void s390_pci_device_reset(DeviceState *dev) -{ - S390PCIBusDevice *pbdev = S390_PCI_DEVICE(dev); - - switch (pbdev->state) { - case ZPCI_FS_RESERVED: - return; - case ZPCI_FS_STANDBY: - break; - default: - pbdev->fh &= ~FH_MASK_ENABLE; - pbdev->state = ZPCI_FS_DISABLED; - break; - } - - if (pbdev->summary_ind) { - pci_dereg_irqs(pbdev); - } - if (pbdev->iommu_enabled) { - pci_dereg_ioat(pbdev); - } - - pbdev->fmb_addr = 0; -} - -static void s390_pci_get_fid(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - Property *prop = opaque; - uint32_t *ptr = qdev_get_prop_ptr(DEVICE(obj), prop); - - visit_type_uint32(v, name, ptr, errp); -} - -static void s390_pci_set_fid(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - DeviceState *dev = DEVICE(obj); - S390PCIBusDevice *zpci = S390_PCI_DEVICE(obj); - Property *prop = opaque; - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - - if (dev->realized) { - qdev_prop_set_after_realize(dev, name, errp); - return; - } - - visit_type_uint32(v, name, ptr, errp); - zpci->fid_defined = true; -} - -static PropertyInfo s390_pci_fid_propinfo = { - .name = "zpci_fid", - .get = s390_pci_get_fid, - .set = s390_pci_set_fid, -}; - -#define DEFINE_PROP_S390_PCI_FID(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, s390_pci_fid_propinfo, uint32_t) - -static Property s390_pci_device_properties[] = { - DEFINE_PROP_UINT16("uid", S390PCIBusDevice, uid, UID_UNDEFINED), - DEFINE_PROP_S390_PCI_FID("fid", S390PCIBusDevice, fid), - DEFINE_PROP_STRING("target", S390PCIBusDevice, target), - DEFINE_PROP_END_OF_LIST(), -}; - -static void s390_pci_device_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->desc = "zpci device"; - dc->reset = s390_pci_device_reset; - dc->bus_type = TYPE_S390_PCI_BUS; - dc->realize = s390_pci_device_realize; - dc->props = s390_pci_device_properties; -} - -static const TypeInfo s390_pci_device_info = { - .name = TYPE_S390_PCI_DEVICE, - .parent = TYPE_DEVICE, - .instance_size = sizeof(S390PCIBusDevice), - .class_init = s390_pci_device_class_init, -}; - static void s390_pci_register_types(void) { type_register_static(&s390_pcihost_info); - type_register_static(&s390_pcibus_info); - type_register_static(&s390_pci_device_info); } type_init(s390_pci_register_types) diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index 4f564e02f..59fd5c958 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -14,38 +14,23 @@ #ifndef HW_S390_PCI_BUS_H #define HW_S390_PCI_BUS_H -#include "hw/pci/pci.h" -#include "hw/pci/pci_host.h" +#include <hw/pci/pci.h> +#include <hw/pci/pci_host.h> #include "hw/s390x/sclp.h" #include "hw/s390x/s390_flic.h" #include "hw/s390x/css.h" #define TYPE_S390_PCI_HOST_BRIDGE "s390-pcihost" -#define TYPE_S390_PCI_BUS "s390-pcibus" -#define TYPE_S390_PCI_DEVICE "zpci" -#define FH_MASK_ENABLE 0x80000000 -#define FH_MASK_INSTANCE 0x7f000000 -#define FH_MASK_SHM 0x00ff0000 -#define FH_MASK_INDEX 0x0000001f -#define FH_SHM_VFIO 0x00010000 -#define FH_SHM_EMUL 0x00020000 +#define FH_VIRT 0x00ff0000 +#define ENABLE_BIT_OFFSET 31 +#define FH_ENABLED (1 << ENABLE_BIT_OFFSET) #define S390_PCIPT_ADAPTER 2 -#define ZPCI_MAX_FID 0xffffffff -#define ZPCI_MAX_UID 0xffff -#define UID_UNDEFINED 0 -#define UID_CHECKING_ENABLED 0x01 -#define HOT_UNPLUG_TIMEOUT (NANOSECONDS_PER_SECOND * 60 * 5) #define S390_PCI_HOST_BRIDGE(obj) \ OBJECT_CHECK(S390pciState, (obj), TYPE_S390_PCI_HOST_BRIDGE) -#define S390_PCI_BUS(obj) \ - OBJECT_CHECK(S390PCIBus, (obj), TYPE_S390_PCI_BUS) -#define S390_PCI_DEVICE(obj) \ - OBJECT_CHECK(S390PCIBusDevice, (obj), TYPE_S390_PCI_DEVICE) #define HP_EVENT_TO_CONFIGURED 0x0301 #define HP_EVENT_RESERVED_TO_STANDBY 0x0302 -#define HP_EVENT_DECONFIGURE_REQUEST 0x0303 #define HP_EVENT_CONFIGURED_TO_STBRES 0x0304 #define HP_EVENT_STANDBY_TO_RESERVED 0x0308 @@ -165,34 +150,6 @@ enum ZpciIoatDtype { #define ZPCI_TABLE_VALID_MASK 0x20 #define ZPCI_TABLE_PROT_MASK 0x200 -/* PCI Function States - * - * reserved: default; device has just been plugged or is in progress of being - * unplugged - * standby: device is present but not configured; transition from any - * configured state/to this state via sclp configure/deconfigure - * - * The following states make up the "configured" meta-state: - * disabled: device is configured but not enabled; transition between this - * state and enabled via clp enable/disable - * enbaled: device is ready for use; transition to disabled via clp disable; - * may enter an error state - * blocked: ignore all DMA and interrupts; transition back to enabled or from - * error state via mpcifc - * error: an error occured; transition back to enabled via mpcifc - * permanent error: an unrecoverable error occured; transition to standby via - * sclp deconfigure - */ -typedef enum { - ZPCI_FS_RESERVED, - ZPCI_FS_STANDBY, - ZPCI_FS_DISABLED, - ZPCI_FS_ENABLED, - ZPCI_FS_BLOCKED, - ZPCI_FS_ERROR, - ZPCI_FS_PERMANENT_ERROR, -} ZpciState; - typedef struct SeiContainer { QTAILQ_ENTRY(SeiContainer) link; uint32_t fid; @@ -241,11 +198,11 @@ typedef struct ChscSeiNt2Res { } QEMU_PACKED ChscSeiNt2Res; typedef struct PciCfgSccb { - SCCBHeader header; - uint8_t atype; - uint8_t reserved1; - uint16_t reserved2; - uint32_t aid; + SCCBHeader header; + uint8_t atype; + uint8_t reserved1; + uint16_t reserved2; + uint32_t aid; } QEMU_PACKED PciCfgSccb; typedef struct S390MsixInfo { @@ -257,21 +214,13 @@ typedef struct S390MsixInfo { uint32_t pba_offset; } S390MsixInfo; -typedef struct S390PCIIOMMU { - AddressSpace as; - MemoryRegion mr; -} S390PCIIOMMU; - typedef struct S390PCIBusDevice { - DeviceState qdev; PCIDevice *pdev; - ZpciState state; - bool iommu_enabled; - char *target; - uint16_t uid; + bool configured; + bool error_state; + bool lgstg_blocked; uint32_t fh; uint32_t fid; - bool fid_defined; uint64_t g_iota; uint64_t pba; uint64_t pal; @@ -281,22 +230,16 @@ typedef struct S390PCIBusDevice { uint8_t sum; S390MsixInfo msix; AdapterRoutes routes; - S390PCIIOMMU *iommu; + AddressSpace as; + MemoryRegion mr; MemoryRegion iommu_mr; IndAddr *summary_ind; IndAddr *indicator; - QEMUTimer *release_timer; } S390PCIBusDevice; -typedef struct S390PCIBus { - BusState qbus; -} S390PCIBus; - typedef struct S390pciState { PCIHostState parent_obj; - S390PCIBus *bus; - S390PCIBusDevice *pbdev[PCI_SLOT_MAX]; - S390PCIIOMMU *iommu[PCI_SLOT_MAX]; + S390PCIBusDevice pbdev[PCI_SLOT_MAX]; AddressSpace msix_notify_as; MemoryRegion msix_notify_mr; QTAILQ_HEAD(, SeiContainer) pending_sei; @@ -304,15 +247,10 @@ typedef struct S390pciState { int chsc_sei_nt2_get_event(void *res); int chsc_sei_nt2_have_event(void); -void s390_pci_sclp_configure(SCCB *sccb); -void s390_pci_sclp_deconfigure(SCCB *sccb); -void s390_pci_iommu_enable(S390PCIBusDevice *pbdev); -void s390_pci_iommu_disable(S390PCIBusDevice *pbdev); -void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, - uint64_t faddr, uint32_t e); +void s390_pci_sclp_configure(int configure, SCCB *sccb); +void s390_pcihost_iommu_configure(S390PCIBusDevice *pbdev, bool enable); S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx); S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh); S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid); -S390PCIBusDevice *s390_pci_find_next_avail_dev(S390PCIBusDevice *pbdev); #endif diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index f069b110b..b28e7d14f 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -16,8 +16,8 @@ #include "cpu.h" #include "s390-pci-inst.h" #include "s390-pci-bus.h" -#include "exec/memory-internal.h" -#include "qemu/error-report.h" +#include <exec/memory-internal.h> +#include <qemu/error-report.h> /* #define DEBUG_S390PCI_INST */ #ifdef DEBUG_S390PCI_INST @@ -37,9 +37,9 @@ static void s390_set_status_code(CPUS390XState *env, static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc) { - S390PCIBusDevice *pbdev = NULL; - uint32_t res_code, initial_l2, g_l2; - int rc, i; + S390PCIBusDevice *pbdev; + uint32_t res_code, initial_l2, g_l2, finish; + int rc, idx; uint64_t resume_token; rc = 0; @@ -56,7 +56,8 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc) } if ((ldl_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 || - ldq_p(&rrb->request.reserved1) != 0) { + ldq_p(&rrb->request.reserved1) != 0 || + ldq_p(&rrb->request.reserved2) != 0) { res_code = CLP_RC_RESNOT0; rc = -EINVAL; goto out; @@ -71,8 +72,6 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc) rc = -EINVAL; goto out; } - } else { - pbdev = s390_pci_find_next_avail_dev(NULL); } if (lduw_p(&rrb->response.hdr.len) < 48) { @@ -92,40 +91,43 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc) stl_p(&rrb->response.fmt, 0); stq_p(&rrb->response.reserved1, 0); - stl_p(&rrb->response.mdd, FH_MASK_SHM); + stq_p(&rrb->response.reserved2, 0); + stl_p(&rrb->response.mdd, FH_VIRT); stw_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS); - rrb->response.flags = UID_CHECKING_ENABLED; rrb->response.entry_size = sizeof(ClpFhListEntry); - - i = 0; + finish = 0; + idx = resume_token; g_l2 = LIST_PCI_HDR_LEN; - while (g_l2 < initial_l2 && pbdev) { - stw_p(&rrb->response.fh_list[i].device_id, + do { + pbdev = s390_pci_find_dev_by_idx(idx); + if (!pbdev) { + finish = 1; + break; + } + stw_p(&rrb->response.fh_list[idx - resume_token].device_id, pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID)); - stw_p(&rrb->response.fh_list[i].vendor_id, + stw_p(&rrb->response.fh_list[idx - resume_token].vendor_id, pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID)); - /* Ignore RESERVED devices. */ - stl_p(&rrb->response.fh_list[i].config, - pbdev->state == ZPCI_FS_STANDBY ? 0 : 1 << 31); - stl_p(&rrb->response.fh_list[i].fid, pbdev->fid); - stl_p(&rrb->response.fh_list[i].fh, pbdev->fh); + stl_p(&rrb->response.fh_list[idx - resume_token].config, + pbdev->configured << 31); + stl_p(&rrb->response.fh_list[idx - resume_token].fid, pbdev->fid); + stl_p(&rrb->response.fh_list[idx - resume_token].fh, pbdev->fh); g_l2 += sizeof(ClpFhListEntry); /* Add endian check for DPRINTF? */ DPRINTF("g_l2 %d vendor id 0x%x device id 0x%x fid 0x%x fh 0x%x\n", - g_l2, - lduw_p(&rrb->response.fh_list[i].vendor_id), - lduw_p(&rrb->response.fh_list[i].device_id), - ldl_p(&rrb->response.fh_list[i].fid), - ldl_p(&rrb->response.fh_list[i].fh)); - pbdev = s390_pci_find_next_avail_dev(pbdev); - i++; - } - - if (!pbdev) { + g_l2, + lduw_p(&rrb->response.fh_list[idx - resume_token].vendor_id), + lduw_p(&rrb->response.fh_list[idx - resume_token].device_id), + ldl_p(&rrb->response.fh_list[idx - resume_token].fid), + ldl_p(&rrb->response.fh_list[idx - resume_token].fh)); + idx++; + } while (g_l2 < initial_l2); + + if (finish == 1) { resume_token = 0; } else { - resume_token = pbdev->fh & FH_MASK_INDEX; + resume_token = idx; } stq_p(&rrb->response.resume_token, resume_token); stw_p(&rrb->response.hdr.len, g_l2); @@ -210,35 +212,14 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) switch (reqsetpci->oc) { case CLP_SET_ENABLE_PCI_FN: - switch (reqsetpci->ndas) { - case 0: - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_DMAAS); - goto out; - case 1: - break; - default: - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_RES); - goto out; - } - - if (pbdev->fh & FH_MASK_ENABLE) { - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP); - goto out; - } - - pbdev->fh |= FH_MASK_ENABLE; - pbdev->state = ZPCI_FS_ENABLED; + pbdev->fh = pbdev->fh | FH_ENABLED; stl_p(&ressetpci->fh, pbdev->fh); stw_p(&ressetpci->hdr.rsp, CLP_RC_OK); break; case CLP_SET_DISABLE_PCI_FN: - if (!(pbdev->fh & FH_MASK_ENABLE)) { - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP); - goto out; - } - device_reset(DEVICE(pbdev)); - pbdev->fh &= ~FH_MASK_ENABLE; - pbdev->state = ZPCI_FS_DISABLED; + pbdev->fh = pbdev->fh & ~FH_ENABLED; + pbdev->error_state = false; + pbdev->lgstg_blocked = false; stl_p(&ressetpci->fh, pbdev->fh); stw_p(&ressetpci->hdr.rsp, CLP_RC_OK); break; @@ -275,10 +256,9 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) stq_p(&resquery->sdma, ZPCI_SDMA_ADDR); stq_p(&resquery->edma, ZPCI_EDMA_ADDR); - stl_p(&resquery->fid, pbdev->fid); stw_p(&resquery->pchid, 0); stw_p(&resquery->ug, 1); - stl_p(&resquery->uid, pbdev->uid); + stl_p(&resquery->uid, pbdev->fid); stw_p(&resquery->hdr.rsp, CLP_RC_OK); break; } @@ -337,25 +317,16 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) offset = env->regs[r2 + 1]; pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev) { + if (!pbdev || !(pbdev->fh & FH_ENABLED)) { DPRINTF("pcilg no pci dev\n"); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); return 0; } - switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: - case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - case ZPCI_FS_ERROR: + if (pbdev->lgstg_blocked) { setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED); return 0; - default: - break; } if (pcias < 6) { @@ -419,8 +390,7 @@ static void update_msix_table_msg_data(S390PCIBusDevice *pbdev, uint64_t offset, msg_data = (uint8_t *)data - offset % PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; - val = pci_get_long(msg_data) | - ((pbdev->fh & FH_MASK_INDEX) << ZPCI_MSI_VEC_BITS); + val = pci_get_long(msg_data) | (pbdev->fid << ZPCI_MSI_VEC_BITS); pci_set_long(msg_data, val); DPRINTF("update msix msg_data to 0x%" PRIx64 "\n", *data); } @@ -464,25 +434,16 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) offset = env->regs[r2 + 1]; pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev) { + if (!pbdev || !(pbdev->fh & FH_ENABLED)) { DPRINTF("pcistg no pci dev\n"); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); return 0; } - switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: - case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - case ZPCI_FS_ERROR: + if (pbdev->lgstg_blocked) { setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED); return 0; - default: - break; } data = env->regs[r1]; @@ -564,55 +525,18 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) end = start + env->regs[r2 + 1]; pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev) { + if (!pbdev || !(pbdev->fh & FH_ENABLED)) { DPRINTF("rpcit no pci dev\n"); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); goto out; } - switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: - case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - case ZPCI_FS_ERROR: - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_MOD_ST_ERROR_RECOVER); - return 0; - default: - break; - } - - if (!pbdev->g_iota) { - pbdev->state = ZPCI_FS_ERROR; - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES); - s390_pci_generate_error_event(ERR_EVENT_INVALAS, pbdev->fh, pbdev->fid, - start, 0); - goto out; - } - - if (end < pbdev->pba || start > pbdev->pal) { - pbdev->state = ZPCI_FS_ERROR; - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES); - s390_pci_generate_error_event(ERR_EVENT_OORANGE, pbdev->fh, pbdev->fid, - start, 0); - goto out; - } - mr = &pbdev->iommu_mr; while (start < end) { entry = mr->iommu_ops->translate(mr, start, 0); if (!entry.translated_addr) { - pbdev->state = ZPCI_FS_ERROR; setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_PCI_ST_INSUF_RES); - s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid, - start, ERR_EVENT_Q_BIT); goto out; } @@ -665,25 +589,16 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, } pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev) { + if (!pbdev || !(pbdev->fh & FH_ENABLED)) { DPRINTF("pcistb no pci dev fh 0x%x\n", fh); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); return 0; } - switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: - case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - case ZPCI_FS_ERROR: + if (pbdev->lgstg_blocked) { setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED); return 0; - default: - break; } mr = pbdev->pdev->io_regions[pcias].memory; @@ -719,15 +634,8 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib) len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long); pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len); - ret = map_indicator(&pbdev->routes.adapter, pbdev->summary_ind); - if (ret) { - goto out; - } - - ret = map_indicator(&pbdev->routes.adapter, pbdev->indicator); - if (ret) { - goto out; - } + map_indicator(&pbdev->routes.adapter, pbdev->summary_ind); + map_indicator(&pbdev->routes.adapter, pbdev->indicator); pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb); pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data)); @@ -739,15 +647,9 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib) DPRINTF("reg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id); return 0; -out: - release_indicator(&pbdev->routes.adapter, pbdev->summary_ind); - release_indicator(&pbdev->routes.adapter, pbdev->indicator); - pbdev->summary_ind = NULL; - pbdev->indicator = NULL; - return ret; } -int pci_dereg_irqs(S390PCIBusDevice *pbdev) +static int dereg_irqs(S390PCIBusDevice *pbdev) { release_indicator(&pbdev->routes.adapter, pbdev->summary_ind); release_indicator(&pbdev->routes.adapter, pbdev->indicator); @@ -790,23 +692,24 @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib) pbdev->pal = pal; pbdev->g_iota = g_iota; - s390_pci_iommu_enable(pbdev); + s390_pcihost_iommu_configure(pbdev, true); return 0; } -void pci_dereg_ioat(S390PCIBusDevice *pbdev) +static void dereg_ioat(S390PCIBusDevice *pbdev) { - s390_pci_iommu_disable(pbdev); pbdev->pba = 0; pbdev->pal = 0; pbdev->g_iota = 0; + + s390_pcihost_iommu_configure(pbdev, false); } int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) { CPUS390XState *env = &cpu->env; - uint8_t oc, dmaas; + uint8_t oc; uint32_t fh; ZpciFib fib; S390PCIBusDevice *pbdev; @@ -818,7 +721,6 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) } oc = env->regs[r1] & 0xff; - dmaas = (env->regs[r1] >> 16) & 0xff; fh = env->regs[r1] >> 32; if (fiba & 0x7) { @@ -827,108 +729,45 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) } pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev) { + if (!pbdev || !(pbdev->fh & FH_ENABLED)) { DPRINTF("mpcifc no pci dev fh 0x%x\n", fh); setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); return 0; } - switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: - case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - default: - break; - } - if (s390_cpu_virt_mem_read(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) { return 0; } - if (fib.fmt != 0) { - program_interrupt(env, PGM_OPERAND, 6); - return 0; - } - switch (oc) { case ZPCI_MOD_FC_REG_INT: - if (pbdev->summary_ind) { + if (reg_irqs(env, pbdev, fib)) { cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); - } else if (reg_irqs(env, pbdev, fib)) { - cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_RES_NOT_AVAIL); } break; case ZPCI_MOD_FC_DEREG_INT: - if (!pbdev->summary_ind) { - cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); - } else { - pci_dereg_irqs(pbdev); - } + dereg_irqs(pbdev); break; case ZPCI_MOD_FC_REG_IOAT: - if (dmaas != 0) { + if (reg_ioat(env, pbdev, fib)) { cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); - } else if (pbdev->iommu_enabled) { - cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); - } else if (reg_ioat(env, pbdev, fib)) { - cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES); } break; case ZPCI_MOD_FC_DEREG_IOAT: - if (dmaas != 0) { - cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); - } else if (!pbdev->iommu_enabled) { - cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); - } else { - pci_dereg_ioat(pbdev); - } + dereg_ioat(pbdev); break; case ZPCI_MOD_FC_REREG_IOAT: - if (dmaas != 0) { + dereg_ioat(pbdev); + if (reg_ioat(env, pbdev, fib)) { cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); - } else if (!pbdev->iommu_enabled) { - cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); - } else { - pci_dereg_ioat(pbdev); - if (reg_ioat(env, pbdev, fib)) { - cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES); - } } break; case ZPCI_MOD_FC_RESET_ERROR: - switch (pbdev->state) { - case ZPCI_FS_BLOCKED: - case ZPCI_FS_ERROR: - pbdev->state = ZPCI_FS_ENABLED; - break; - default: - cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); - } + pbdev->error_state = false; + pbdev->lgstg_blocked = false; break; case ZPCI_MOD_FC_RESET_BLOCK: - switch (pbdev->state) { - case ZPCI_FS_ERROR: - pbdev->state = ZPCI_FS_BLOCKED; - break; - default: - cc = ZPCI_PCI_LS_ERR; - s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); - } + pbdev->lgstg_blocked = false; break; case ZPCI_MOD_FC_SET_MEASURE: pbdev->fmb_addr = ldq_p(&fib.fmb_addr); @@ -945,7 +784,6 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) { CPUS390XState *env = &cpu->env; - uint8_t dmaas; uint32_t fh; ZpciFib fib; S390PCIBusDevice *pbdev; @@ -958,59 +796,19 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) } fh = env->regs[r1] >> 32; - dmaas = (env->regs[r1] >> 16) & 0xff; - - if (dmaas) { - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_STPCIFC_ST_INVAL_DMAAS); - return 0; - } if (fiba & 0x7) { program_interrupt(env, PGM_SPECIFICATION, 6); return 0; } - pbdev = s390_pci_find_dev_by_idx(fh & FH_MASK_INDEX); + pbdev = s390_pci_find_dev_by_fh(fh); if (!pbdev) { setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); return 0; } memset(&fib, 0, sizeof(fib)); - - switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - case ZPCI_FS_DISABLED: - if (fh & FH_MASK_ENABLE) { - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - } - goto out; - /* BLOCKED bit is set to one coincident with the setting of ERROR bit. - * FH Enabled bit is set to one in states of ENABLED, BLOCKED or ERROR. */ - case ZPCI_FS_ERROR: - fib.fc |= 0x20; - case ZPCI_FS_BLOCKED: - fib.fc |= 0x40; - case ZPCI_FS_ENABLED: - fib.fc |= 0x80; - if (pbdev->iommu_enabled) { - fib.fc |= 0x10; - } - if (!(fh & FH_MASK_ENABLE)) { - env->regs[r1] |= 1ULL << 63; - } - break; - case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_STPCIFC_ST_PERM_ERROR); - return 0; - } - stq_p(&fib.pba, pbdev->pba); stq_p(&fib.pal, pbdev->pal); stq_p(&fib.iota, pbdev->g_iota); @@ -1023,7 +821,22 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) ((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset; stl_p(&fib.data, data); -out: + if (pbdev->fh & FH_ENABLED) { + fib.fc |= 0x80; + } + + if (pbdev->error_state) { + fib.fc |= 0x40; + } + + if (pbdev->lgstg_blocked) { + fib.fc |= 0x20; + } + + if (pbdev->g_iota) { + fib.fc |= 0x10; + } + if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) { return 0; } diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h index 23f4bfa0e..70fa71395 100644 --- a/hw/s390x/s390-pci-inst.h +++ b/hw/s390x/s390-pci-inst.h @@ -14,8 +14,7 @@ #ifndef HW_S390_PCI_INST_H #define HW_S390_PCI_INST_H -#include "s390-pci-bus.h" -#include "sysemu/dma.h" +#include <sysemu/dma.h> /* CLP common request & response block size */ #define CLP_BLK_SIZE 4096 @@ -104,7 +103,7 @@ typedef struct ClpRspListPci { uint64_t resume_token; uint32_t mdd; uint16_t max_fn; - uint8_t flags; + uint8_t reserved2; uint8_t entry_size; ClpFhListEntry fh_list[CLP_FH_LIST_NR_ENTRIES]; } QEMU_PACKED ClpRspListPci; @@ -231,14 +230,6 @@ typedef struct ClpReqRspQueryPciGrp { #define ZPCI_PCI_LS_BUSY 2 #define ZPCI_PCI_LS_INVAL_HANDLE 3 -/* Modify PCI status codes */ -#define ZPCI_MOD_ST_RES_NOT_AVAIL 4 -#define ZPCI_MOD_ST_INSUF_RES 16 -#define ZPCI_MOD_ST_SEQUENCE 24 -#define ZPCI_MOD_ST_DMAAS_INVAL 28 -#define ZPCI_MOD_ST_FRAME_INVAL 32 -#define ZPCI_MOD_ST_ERROR_RECOVER 40 - /* Modify PCI Function Controls */ #define ZPCI_MOD_FC_REG_INT 2 #define ZPCI_MOD_FC_DEREG_INT 3 @@ -249,11 +240,6 @@ typedef struct ClpReqRspQueryPciGrp { #define ZPCI_MOD_FC_RESET_BLOCK 9 #define ZPCI_MOD_FC_SET_MEASURE 10 -/* Store PCI Function Controls status codes */ -#define ZPCI_STPCIFC_ST_PERM_ERROR 8 -#define ZPCI_STPCIFC_ST_INVAL_DMAAS 28 -#define ZPCI_STPCIFC_ST_ERROR_RECOVER 40 - /* FIB function controls */ #define ZPCI_FIB_FC_ENABLED 0x80 #define ZPCI_FIB_FC_ERROR 0x40 @@ -291,8 +277,6 @@ typedef struct ZpciFib { uint32_t gd; } QEMU_PACKED ZpciFib; -int pci_dereg_irqs(S390PCIBusDevice *pbdev); -void pci_dereg_ioat(S390PCIBusDevice *pbdev); int clp_service_call(S390CPU *cpu, uint8_t r2); int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index e2d4e1af7..6528ffed1 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -15,7 +15,6 @@ #include "migration/qemu-file.h" #include "hw/s390x/storage-keys.h" #include "qemu/error-report.h" -#include "sysemu/kvm.h" #define S390_SKEYS_BUFFER_SIZE 131072 /* Room for 128k storage keys */ #define S390_SKEYS_SAVE_FLAG_EOS 0x01 @@ -47,11 +46,15 @@ void s390_skeys_init(void) qdev_init_nofail(DEVICE(obj)); } -static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn, +static void write_keys(QEMUFile *f, uint8_t *keys, uint64_t startgfn, uint64_t count, Error **errp) { uint64_t curpage = startgfn; uint64_t maxpage = curpage + count - 1; + const char *fmt = "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d," + " ch=%d, reserved=%d\n"; + char buf[128]; + int len; for (; curpage <= maxpage; curpage++) { uint8_t acc = (*keys & 0xF0) >> 4; @@ -60,9 +63,10 @@ static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn, int ch = (*keys & 0x02); int res = (*keys & 0x01); - fprintf(f, "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d," - " ch=%d, reserved=%d\n", - curpage, *keys, acc, fp, ref, ch, res); + len = snprintf(buf, sizeof(buf), fmt, curpage, + *keys, acc, fp, ref, ch, res); + assert(len < sizeof(buf)); + qemu_put_buffer(f, (uint8_t *)buf, len); keys++; } } @@ -111,8 +115,7 @@ void qmp_dump_skeys(const char *filename, Error **errp) vaddr cur_gfn = 0; uint8_t *buf; int ret; - int fd; - FILE *f; + QEMUFile *f; /* Quick check to see if guest is using storage keys*/ if (!skeyclass->skeys_enabled(ss)) { @@ -121,14 +124,8 @@ void qmp_dump_skeys(const char *filename, Error **errp) return; } - fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (fd < 0) { - error_setg_file_open(errp, errno, filename); - return; - } - f = fdopen(fd, "wb"); + f = qemu_fopen(filename, "wb"); if (!f) { - close(fd); error_setg_file_open(errp, errno, filename); return; } @@ -164,7 +161,7 @@ out_free: error_propagate(errp, lerr); g_free(buf); out: - fclose(f); + qemu_fclose(f); } static void qemu_s390_skeys_init(Object *obj) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 91d9cefbb..e3df9c78b 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -18,19 +18,17 @@ #include "s390-virtio.h" #include "hw/s390x/sclp.h" #include "hw/s390x/s390_flic.h" -#include "hw/s390x/ioinst.h" -#include "hw/s390x/css.h" +#include "ioinst.h" +#include "css.h" #include "virtio-ccw.h" #include "qemu/config-file.h" #include "s390-pci-bus.h" #include "hw/s390x/storage-keys.h" #include "hw/compat.h" -#include "ipl.h" #include "hw/s390x/s390-virtio-ccw.h" -#include "hw/s390x/css-bridge.h" static const char *const reset_dev_types[] = { - TYPE_VIRTUAL_CSS_BRIDGE, + "virtual-css-bridge", "s390-sclp-event-facility", "s390-flic", "diag288", @@ -181,8 +179,10 @@ static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, static void s390_hot_add_cpu(const int64_t id, Error **errp) { MachineState *machine = MACHINE(qdev_get_machine()); + Error *err = NULL; - s390x_new_cpu(machine->cpu_model, id, errp); + s390x_new_cpu(machine->cpu_model, id, &err); + error_propagate(errp, err); } static void ccw_machine_class_init(ObjectClass *oc, void *data) @@ -190,9 +190,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) MachineClass *mc = MACHINE_CLASS(oc); NMIClass *nc = NMI_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); - S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); - s390mc->ri_allowed = true; mc->init = ccw_init; mc->reset = s390_machine_reset; mc->hot_add_cpu = s390_hot_add_cpu; @@ -203,7 +201,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) mc->no_parallel = 1; mc->no_sdcard = 1; mc->use_sclp = 1; - mc->max_cpus = 248; + mc->max_cpus = 255; mc->get_hotplug_handler = s390_get_hotplug_handler; hc->plug = s390_machine_device_plug; nc->nmi_monitor_handler = s390_nmi; @@ -239,20 +237,6 @@ static inline void machine_set_dea_key_wrap(Object *obj, bool value, ms->dea_key_wrap = value; } -bool ri_allowed(void) -{ - if (kvm_enabled()) { - MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); - if (object_class_dynamic_cast(OBJECT_CLASS(mc), - TYPE_S390_CCW_MACHINE)) { - S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); - - return s390mc->ri_allowed; - } - } - return 0; -} - static inline void s390_machine_initfn(Object *obj) { object_property_add_bool(obj, "aes-key-wrap", @@ -278,7 +262,6 @@ static const TypeInfo ccw_machine_info = { .abstract = true, .instance_size = sizeof(S390CcwMachineState), .instance_init = s390_machine_initfn, - .class_size = sizeof(S390CcwMachineClass), .class_init = ccw_machine_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_NMI }, @@ -316,23 +299,11 @@ static const TypeInfo ccw_machine_info = { } \ type_init(ccw_machine_register_##suffix) -#define CCW_COMPAT_2_6 \ - HW_COMPAT_2_6 \ - {\ - .driver = TYPE_S390_IPL,\ - .property = "iplbext_migration",\ - .value = "off",\ - }, {\ - .driver = TYPE_VIRTUAL_CSS_BRIDGE,\ - .property = "css_dev_path",\ - .value = "off",\ - }, - #define CCW_COMPAT_2_5 \ - CCW_COMPAT_2_6 \ HW_COMPAT_2_5 #define CCW_COMPAT_2_4 \ + CCW_COMPAT_2_5 \ HW_COMPAT_2_4 \ {\ .driver = TYPE_S390_SKEYS,\ @@ -372,38 +343,21 @@ static const TypeInfo ccw_machine_info = { .value = "0",\ }, -static void ccw_machine_2_7_instance_options(MachineState *machine) -{ -} - -static void ccw_machine_2_7_class_options(MachineClass *mc) -{ -} -DEFINE_CCW_MACHINE(2_7, "2.7", true); - static void ccw_machine_2_6_instance_options(MachineState *machine) { - ccw_machine_2_7_instance_options(machine); } static void ccw_machine_2_6_class_options(MachineClass *mc) { - S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); - - s390mc->ri_allowed = false; - ccw_machine_2_7_class_options(mc); - SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6); } -DEFINE_CCW_MACHINE(2_6, "2.6", false); +DEFINE_CCW_MACHINE(2_6, "2.6", true); static void ccw_machine_2_5_instance_options(MachineState *machine) { - ccw_machine_2_6_instance_options(machine); } static void ccw_machine_2_5_class_options(MachineClass *mc) { - ccw_machine_2_6_class_options(mc); SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5); } DEFINE_CCW_MACHINE(2_5, "2.5", false); @@ -415,7 +369,6 @@ static void ccw_machine_2_4_instance_options(MachineState *machine) static void ccw_machine_2_4_class_options(MachineClass *mc) { - ccw_machine_2_5_class_options(mc); SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4); } DEFINE_CCW_MACHINE(2_4, "2.4", false); diff --git a/hw/s390x/s390-virtio.h b/hw/s390x/s390-virtio.h index f588b80a6..ffd014cb5 100644 --- a/hw/s390x/s390-virtio.h +++ b/hw/s390x/s390-virtio.h @@ -10,7 +10,7 @@ */ #ifndef HW_S390_VIRTIO_H -#define HW_S390_VIRTIO_H +#define HW_S390_VIRTIO_H 1 #include "hw/nmi.h" #include "standard-headers/asm-s390/kvm_virtio.h" diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index fca37f511..85dbe1b60 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -357,10 +357,10 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code) sclp_c->unassign_storage(sclp, sccb); break; case SCLP_CMDW_CONFIGURE_PCI: - s390_pci_sclp_configure(sccb); + s390_pci_sclp_configure(1, sccb); break; case SCLP_CMDW_DECONFIGURE_PCI: - s390_pci_sclp_deconfigure(sccb); + s390_pci_sclp_configure(0, sccb); break; default: efc->command_handler(ef, sccb, code); diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 762cb184a..c0ecab9c3 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -12,7 +12,7 @@ * */ #include "qemu/osdep.h" -#include "hw/qdev.h" +#include <hw/qdev.h> #include "sysemu/sysemu.h" #include "hw/s390x/sclp.h" #include "hw/s390x/event-facility.h" diff --git a/hw/s390x/trace-events b/hw/s390x/trace-events deleted file mode 100644 index 84ea96487..000000000 --- a/hw/s390x/trace-events +++ /dev/null @@ -1,15 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/s390x/css.c -css_enable_facility(const char *facility) "CSS: enable %s" -css_crw(uint8_t rsc, uint8_t erc, uint16_t rsid, const char *chained) "CSS: queueing crw: rsc=%x, erc=%x, rsid=%x %s" -css_chpid_add(uint8_t cssid, uint8_t chpid, uint8_t type) "CSS: add chpid %x.%02x (type %02x)" -css_new_image(uint8_t cssid, const char *default_cssid) "CSS: add css image %02x %s" -css_assign_subch(const char *do_assign, uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno) "CSS: %s %x.%x.%04x (devno %04x)" -css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc, const char *conditional) "CSS: I/O interrupt on sch %x.%x.%04x (intparm %08x, isc %x) %s" -css_adapter_interrupt(uint8_t isc) "CSS: adapter I/O interrupt (isc %x)" - -# hw/s390x/virtio-ccw.c -virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x" -virtio_ccw_new_device(int cssid, int ssid, int schid, int devno, const char *devno_mode) "VIRTIO-CCW: add subchannel %x.%x.%04x, devno %04x (%s)" -virtio_ccw_set_ind(uint64_t ind_loc, uint8_t ind_old, uint8_t ind_new) "VIRTIO-CCW: indicator at %" PRIu64 ": %x->%x" diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index a554a24d0..d51642db0 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -16,7 +16,6 @@ #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" -#include "sysemu/kvm.h" #include "net/net.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-serial.h" @@ -29,15 +28,35 @@ #include "hw/s390x/adapter.h" #include "hw/s390x/s390_flic.h" -#include "hw/s390x/ioinst.h" -#include "hw/s390x/css.h" +#include "ioinst.h" +#include "css.h" #include "virtio-ccw.h" #include "trace.h" -#include "hw/s390x/css-bridge.h" static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, VirtioCcwDevice *dev); +static void virtual_css_bus_reset(BusState *qbus) +{ + /* This should actually be modelled via the generic css */ + css_reset(); +} + + +static void virtual_css_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->reset = virtual_css_bus_reset; +} + +static const TypeInfo virtual_css_bus_info = { + .name = TYPE_VIRTUAL_CSS_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(VirtualCssBus), + .class_init = virtual_css_bus_class_init, +}; + VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) { VirtIODevice *vdev = NULL; @@ -49,59 +68,112 @@ VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) return vdev; } -static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) +static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n, + bool assign, bool set_handler) { - virtio_bus_start_ioeventfd(&dev->bus); -} + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + VirtQueue *vq = virtio_get_queue(vdev, n); + EventNotifier *notifier = virtio_queue_get_host_notifier(vq); + int r = 0; + SubchDev *sch = dev->sch; + uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid; -static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev) -{ - virtio_bus_stop_ioeventfd(&dev->bus); + if (assign) { + r = event_notifier_init(notifier, 1); + if (r < 0) { + error_report("%s: unable to init event notifier: %d", __func__, r); + return r; + } + virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler); + r = s390_assign_subch_ioeventfd(notifier, sch_id, n, assign); + if (r < 0) { + error_report("%s: unable to assign ioeventfd: %d", __func__, r); + virtio_queue_set_host_notifier_fd_handler(vq, false, false); + event_notifier_cleanup(notifier); + return r; + } + } else { + virtio_queue_set_host_notifier_fd_handler(vq, false, false); + s390_assign_subch_ioeventfd(notifier, sch_id, n, assign); + event_notifier_cleanup(notifier); + } + return r; } -static bool virtio_ccw_ioeventfd_started(DeviceState *d) +static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) { - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - - return dev->ioeventfd_started; -} + VirtIODevice *vdev; + int n, r; -static void virtio_ccw_ioeventfd_set_started(DeviceState *d, bool started, - bool err) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) || + dev->ioeventfd_disabled || + dev->ioeventfd_started) { + return; + } + vdev = virtio_bus_get_device(&dev->bus); + for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + r = virtio_ccw_set_guest2host_notifier(dev, n, true, true); + if (r < 0) { + goto assign_error; + } + } + dev->ioeventfd_started = true; + return; - dev->ioeventfd_started = started; - if (err) { - /* Disable ioeventfd for this device. */ - dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD; + assign_error: + while (--n >= 0) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + r = virtio_ccw_set_guest2host_notifier(dev, n, false, false); + assert(r >= 0); } + dev->ioeventfd_started = false; + /* Disable ioeventfd for this device. */ + dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD; + error_report("%s: failed. Fallback to userspace (slower).", __func__); } -static bool virtio_ccw_ioeventfd_disabled(DeviceState *d) +static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev) { - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + VirtIODevice *vdev; + int n, r; - return dev->ioeventfd_disabled || - !(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD); + if (!dev->ioeventfd_started) { + return; + } + vdev = virtio_bus_get_device(&dev->bus); + for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + r = virtio_ccw_set_guest2host_notifier(dev, n, false, false); + assert(r >= 0); + } + dev->ioeventfd_started = false; } -static void virtio_ccw_ioeventfd_set_disabled(DeviceState *d, bool disabled) +VirtualCssBus *virtual_css_bus_init(void) { - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + VirtualCssBus *cbus; + BusState *bus; + DeviceState *dev; - dev->ioeventfd_disabled = disabled; -} + /* Create bridge device */ + dev = qdev_create(NULL, "virtual-css-bridge"); + qdev_init_nofail(dev); -static int virtio_ccw_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, - int n, bool assign) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - CcwDevice *ccw_dev = CCW_DEVICE(dev); - SubchDev *sch = ccw_dev->sch; - uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid; + /* Create bus on bridge device */ + bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); + cbus = VIRTUAL_CSS_BUS(bus); + + /* Enable hotplugging */ + qbus_set_hotplug_handler(bus, dev, &error_abort); - return s390_assign_subch_ioeventfd(notifier, sch_id, n, assign); + return cbus; } /* Communication blocks used by several channel commands. */ @@ -195,8 +267,6 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info, static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev) { - CcwDevice *ccw_dev = CCW_DEVICE(dev); - virtio_ccw_stop_ioeventfd(dev); virtio_reset(vdev); if (dev->indicators) { @@ -211,7 +281,7 @@ static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev) release_indicator(&dev->routes.adapter, dev->summary_indicator); dev->summary_indicator = NULL; } - ccw_dev->sch->thinint_active = false; + dev->sch->thinint_active = false; } static int virtio_ccw_handle_set_vq(SubchDev *sch, CCW1 ccw, bool check_len, @@ -666,44 +736,151 @@ static void virtio_sch_disable_cb(SubchDev *sch) static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) { - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev); - CcwDevice *ccw_dev = CCW_DEVICE(dev); - SubchDev *sch = css_create_virtual_sch(ccw_dev->bus_id, errp); + unsigned int cssid = 0; + unsigned int ssid = 0; + unsigned int schid; + unsigned int devno; + bool have_devno = false; + bool found = false; + SubchDev *sch; + int num; Error *err = NULL; + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev); - if (!sch) { - return; - } + sch = g_malloc0(sizeof(SubchDev)); sch->driver_data = dev; + dev->sch = sch; + + dev->indicators = NULL; + + /* Initialize subchannel structure. */ + sch->channel_prog = 0x0; + sch->last_cmd_valid = false; + sch->thinint_active = false; + /* + * Use a device number if provided. Otherwise, fall back to subchannel + * number. + */ + if (dev->bus_id) { + num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno); + if (num == 3) { + if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) { + error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x", + cssid, ssid); + goto out_err; + } + /* Enforce use of virtual cssid. */ + if (cssid != VIRTUAL_CSSID) { + error_setg(errp, "cssid %x not valid for virtio devices", + cssid); + goto out_err; + } + if (css_devno_used(cssid, ssid, devno)) { + error_setg(errp, "Device %x.%x.%04x already exists", + cssid, ssid, devno); + goto out_err; + } + sch->cssid = cssid; + sch->ssid = ssid; + sch->devno = devno; + have_devno = true; + } else { + error_setg(errp, "Malformed devno parameter '%s'", dev->bus_id); + goto out_err; + } + } + + /* Find the next free id. */ + if (have_devno) { + for (schid = 0; schid <= MAX_SCHID; schid++) { + if (!css_find_subch(1, cssid, ssid, schid)) { + sch->schid = schid; + css_subch_assign(cssid, ssid, schid, devno, sch); + found = true; + break; + } + } + if (!found) { + error_setg(errp, "No free subchannel found for %x.%x.%04x", + cssid, ssid, devno); + goto out_err; + } + trace_virtio_ccw_new_device(cssid, ssid, schid, devno, + "user-configured"); + } else { + cssid = VIRTUAL_CSSID; + for (ssid = 0; ssid <= MAX_SSID; ssid++) { + for (schid = 0; schid <= MAX_SCHID; schid++) { + if (!css_find_subch(1, cssid, ssid, schid)) { + sch->cssid = cssid; + sch->ssid = ssid; + sch->schid = schid; + devno = schid; + /* + * If the devno is already taken, look further in this + * subchannel set. + */ + while (css_devno_used(cssid, ssid, devno)) { + if (devno == MAX_SCHID) { + devno = 0; + } else if (devno == schid - 1) { + error_setg(errp, "No free devno found"); + goto out_err; + } else { + devno++; + } + } + sch->devno = devno; + css_subch_assign(cssid, ssid, schid, devno, sch); + found = true; + break; + } + } + if (found) { + break; + } + } + if (!found) { + error_setg(errp, "Virtual channel subsystem is full!"); + goto out_err; + } + trace_virtio_ccw_new_device(cssid, ssid, schid, devno, + "auto-configured"); + } + + /* Build initial schib. */ + css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE); + sch->ccw_cb = virtio_ccw_cb; sch->disable_cb = virtio_sch_disable_cb; + + /* Build senseid data. */ + memset(&sch->id, 0, sizeof(SenseId)); sch->id.reserved = 0xff; sch->id.cu_type = VIRTIO_CCW_CU_TYPE; - ccw_dev->sch = sch; - dev->indicators = NULL; - dev->revision = -1; - css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE); - trace_virtio_ccw_new_device( - sch->cssid, sch->ssid, sch->schid, sch->devno, - ccw_dev->bus_id.valid ? "user-configured" : "auto-configured"); + dev->revision = -1; if (k->realize) { k->realize(dev, &err); } if (err) { error_propagate(errp, err); - css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); - ccw_dev->sch = NULL; - g_free(sch); + css_subch_assign(cssid, ssid, schid, devno, NULL); + goto out_err; } + + return; + +out_err: + dev->sch = NULL; + g_free(sch); } static int virtio_ccw_exit(VirtioCcwDevice *dev) { - CcwDevice *ccw_dev = CCW_DEVICE(dev); - SubchDev *sch = ccw_dev->sch; + SubchDev *sch = dev->sch; if (sch) { css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); @@ -721,11 +898,15 @@ static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp) DeviceState *qdev = DEVICE(ccw_dev); VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); + Error *err = NULL; virtio_net_set_netclient_name(&dev->vdev, qdev->id, object_get_typename(OBJECT(qdev))); qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void virtio_ccw_net_instance_init(Object *obj) @@ -742,9 +923,13 @@ static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp) { VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); + Error *err = NULL; qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void virtio_ccw_blk_instance_init(Object *obj) @@ -764,6 +949,7 @@ static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp) VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *proxy = DEVICE(ccw_dev); + Error *err = NULL; char *bus_name; /* @@ -777,7 +963,10 @@ static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp) } qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } @@ -793,9 +982,13 @@ static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp) { VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); + Error *err = NULL; qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void virtio_ccw_balloon_instance_init(Object *obj) @@ -816,6 +1009,7 @@ static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); DeviceState *qdev = DEVICE(ccw_dev); + Error *err = NULL; char *bus_name; /* @@ -829,7 +1023,10 @@ static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) } qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void virtio_ccw_scsi_instance_init(Object *obj) @@ -847,9 +1044,13 @@ static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) { VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); + Error *err = NULL; qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void vhost_ccw_scsi_instance_init(Object *obj) @@ -884,9 +1085,7 @@ static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) */ static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d) { - CcwDevice *ccw_dev = to_ccw_dev_fast(d); - - return container_of(ccw_dev, VirtioCcwDevice, parent_obj); + return container_of(d, VirtioCcwDevice, parent_obj); } static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, @@ -906,7 +1105,6 @@ static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, ind_old = *ind_addr; ind_new = ind_old | to_be_set; } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old); - trace_virtio_ccw_set_ind(ind_loc, ind_old, ind_new); cpu_physical_memory_unmap(ind_addr, len, 1, len); return ind_old; @@ -915,8 +1113,7 @@ static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, static void virtio_ccw_notify(DeviceState *d, uint16_t vector) { VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d); - CcwDevice *ccw_dev = to_ccw_dev_fast(d); - SubchDev *sch = ccw_dev->sch; + SubchDev *sch = dev->sch; uint64_t indicators; /* queue indicators + secondary indicators */ @@ -974,10 +1171,9 @@ static void virtio_ccw_reset(DeviceState *d) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - CcwDevice *ccw_dev = CCW_DEVICE(d); virtio_ccw_reset_virtio(dev, vdev); - css_reset_sch(ccw_dev->sch); + css_reset_sch(dev->sch); } static void virtio_ccw_vmstate_change(DeviceState *d, bool running) @@ -993,17 +1189,29 @@ static void virtio_ccw_vmstate_change(DeviceState *d, bool running) static bool virtio_ccw_query_guest_notifiers(DeviceState *d) { - CcwDevice *dev = CCW_DEVICE(d); + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); return !!(dev->sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA); } +static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + + /* Stop using the generic ioeventfd, we are doing eventfd handling + * ourselves below */ + dev->ioeventfd_disabled = assign; + if (assign) { + virtio_ccw_stop_ioeventfd(dev); + } + return virtio_ccw_set_guest2host_notifier(dev, n, assign, false); +} + static int virtio_ccw_get_mappings(VirtioCcwDevice *dev) { int r; - CcwDevice *ccw_dev = CCW_DEVICE(dev); - if (!ccw_dev->sch->thinint_active) { + if (!dev->sch->thinint_active) { return -EINVAL; } @@ -1125,8 +1333,7 @@ static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs, { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - CcwDevice *ccw_dev = CCW_DEVICE(d); - bool with_irqfd = ccw_dev->sch->thinint_active && kvm_irqfds_enabled(); + bool with_irqfd = dev->sch->thinint_active && kvm_irqfds_enabled(); int r, n; if (with_irqfd && assigned) { @@ -1185,8 +1392,7 @@ static int virtio_ccw_load_queue(DeviceState *d, int n, QEMUFile *f) static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - CcwDevice *ccw_dev = CCW_DEVICE(d); - SubchDev *s = ccw_dev->sch; + SubchDev *s = dev->sch; VirtIODevice *vdev = virtio_ccw_get_vdev(s); subch_device_save(s, f); @@ -1220,8 +1426,7 @@ static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f) static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - CcwDevice *ccw_dev = CCW_DEVICE(d); - SubchDev *s = ccw_dev->sch; + SubchDev *s = dev->sch; VirtIODevice *vdev = virtio_ccw_get_vdev(s); int len; @@ -1266,12 +1471,11 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - CcwDevice *ccw_dev = CCW_DEVICE(d); - SubchDev *sch = ccw_dev->sch; + SubchDev *sch = dev->sch; int n = virtio_get_num_queues(vdev); if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) { - error_setg(errp, "The number of virtqueues %d " + error_setg(errp, "The nubmer of virtqueues %d " "exceeds ccw limit %d", n, VIRTIO_CCW_QUEUE_MAX); return; @@ -1311,7 +1515,7 @@ static void virtio_ccw_device_unplugged(DeviceState *d) /**************** Virtio-ccw Bus Device Descriptions *******************/ static Property virtio_ccw_net_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1340,7 +1544,7 @@ static const TypeInfo virtio_ccw_net = { }; static Property virtio_ccw_blk_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1369,7 +1573,7 @@ static const TypeInfo virtio_ccw_blk = { }; static Property virtio_ccw_serial_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1398,7 +1602,7 @@ static const TypeInfo virtio_ccw_serial = { }; static Property virtio_ccw_balloon_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1427,7 +1631,7 @@ static const TypeInfo virtio_ccw_balloon = { }; static Property virtio_ccw_scsi_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1457,7 +1661,7 @@ static const TypeInfo virtio_ccw_scsi = { #ifdef CONFIG_VHOST_SCSI static Property vhost_ccw_scsi_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, VIRTIO_CCW_MAX_REV), DEFINE_PROP_END_OF_LIST(), @@ -1495,7 +1699,7 @@ static void virtio_ccw_rng_instance_init(Object *obj) } static Property virtio_ccw_rng_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1542,17 +1746,29 @@ static int virtio_ccw_busdev_exit(DeviceState *dev) static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - VirtioCcwDevice *_dev = to_virtio_ccw_dev_fast(dev); + VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; + SubchDev *sch = _dev->sch; virtio_ccw_stop_ioeventfd(_dev); + + /* + * We should arrive here only for device_del, since we don't support + * direct hot(un)plug of channels, but only through virtio. + */ + assert(sch != NULL); + /* Subchannel is now disabled and no longer valid. */ + sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA | + PMCW_FLAGS_MASK_DNV); + + css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); + + object_unparent(OBJECT(dev)); } static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - CCWDeviceClass *k = CCW_DEVICE_CLASS(dc); - k->unplug = virtio_ccw_busdev_unplug; dc->realize = virtio_ccw_busdev_realize; dc->exit = virtio_ccw_busdev_exit; dc->bus_type = TYPE_VIRTUAL_CSS_BUS; @@ -1560,13 +1776,44 @@ static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) static const TypeInfo virtio_ccw_device_info = { .name = TYPE_VIRTIO_CCW_DEVICE, - .parent = TYPE_CCW_DEVICE, + .parent = TYPE_DEVICE, .instance_size = sizeof(VirtioCcwDevice), .class_init = virtio_ccw_device_class_init, .class_size = sizeof(VirtIOCCWDeviceClass), .abstract = true, }; +/***************** Virtual-css Bus Bridge Device ********************/ +/* Only required to have the virtio bus as child in the system bus */ + +static int virtual_css_bridge_init(SysBusDevice *dev) +{ + /* nothing */ + return 0; +} + +static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = virtual_css_bridge_init; + hc->unplug = virtio_ccw_busdev_unplug; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); +} + +static const TypeInfo virtual_css_bridge_info = { + .name = "virtual-css-bridge", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = virtual_css_bridge_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + } +}; + /* virtio-ccw-bus */ static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, @@ -1588,6 +1835,7 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) k->notify = virtio_ccw_notify; k->vmstate_change = virtio_ccw_vmstate_change; k->query_guest_notifiers = virtio_ccw_query_guest_notifiers; + k->set_host_notifier = virtio_ccw_set_host_notifier; k->set_guest_notifiers = virtio_ccw_set_guest_notifiers; k->save_queue = virtio_ccw_save_queue; k->load_queue = virtio_ccw_load_queue; @@ -1596,11 +1844,6 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) k->device_plugged = virtio_ccw_device_plugged; k->post_plugged = virtio_ccw_post_plugged; k->device_unplugged = virtio_ccw_device_unplugged; - k->ioeventfd_started = virtio_ccw_ioeventfd_started; - k->ioeventfd_set_started = virtio_ccw_ioeventfd_set_started; - k->ioeventfd_disabled = virtio_ccw_ioeventfd_disabled; - k->ioeventfd_set_disabled = virtio_ccw_ioeventfd_set_disabled; - k->ioeventfd_assign = virtio_ccw_ioeventfd_assign; } static const TypeInfo virtio_ccw_bus_info = { @@ -1612,7 +1855,7 @@ static const TypeInfo virtio_ccw_bus_info = { #ifdef CONFIG_VIRTFS static Property virtio_ccw_9p_properties[] = { - DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, parent_obj.bus_id), + DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, @@ -1624,9 +1867,13 @@ static void virtio_ccw_9p_realize(VirtioCcwDevice *ccw_dev, Error **errp) { V9fsCCWState *dev = VIRTIO_9P_CCW(ccw_dev); DeviceState *vdev = DEVICE(&dev->vdev); + Error *err = NULL; qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", errp); + object_property_set_bool(OBJECT(vdev), true, "realized", &err); + if (err) { + error_propagate(errp, err); + } } static void virtio_ccw_9p_class_init(ObjectClass *klass, void *data) @@ -1661,6 +1908,7 @@ static const TypeInfo virtio_ccw_9p_info = { static void virtio_ccw_register(void) { type_register_static(&virtio_ccw_bus_info); + type_register_static(&virtual_css_bus_info); type_register_static(&virtio_ccw_device_info); type_register_static(&virtio_ccw_serial); type_register_static(&virtio_ccw_blk); @@ -1671,6 +1919,7 @@ static void virtio_ccw_register(void) type_register_static(&vhost_ccw_scsi); #endif type_register_static(&virtio_ccw_rng); + type_register_static(&virtual_css_bridge_info); #ifdef CONFIG_VIRTFS type_register_static(&virtio_ccw_9p_info); #endif diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 1c6bc8631..66c831ba8 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -13,21 +13,20 @@ #ifndef HW_S390X_VIRTIO_CCW_H #define HW_S390X_VIRTIO_CCW_H -#include "hw/virtio/virtio-blk.h" -#include "hw/virtio/virtio-net.h" -#include "hw/virtio/virtio-serial.h" -#include "hw/virtio/virtio-scsi.h" +#include <hw/virtio/virtio-blk.h> +#include <hw/virtio/virtio-net.h> +#include <hw/virtio/virtio-serial.h> +#include <hw/virtio/virtio-scsi.h> #ifdef CONFIG_VHOST_SCSI -#include "hw/virtio/vhost-scsi.h" +#include <hw/virtio/vhost-scsi.h> #endif -#include "hw/virtio/virtio-balloon.h" -#include "hw/virtio/virtio-rng.h" -#include "hw/virtio/virtio-bus.h" +#include <hw/virtio/virtio-balloon.h> +#include <hw/virtio/virtio-rng.h> +#include <hw/virtio/virtio-bus.h> -#include "hw/s390x/s390_flic.h" -#include "hw/s390x/css.h" -#include "ccw-device.h" -#include "hw/s390x/css-bridge.h" +#include "css.h" + +#define VIRTUAL_CSSID 0xfe #define VIRTIO_CCW_CU_TYPE 0x3832 #define VIRTIO_CCW_CHPID_TYPE 0x32 @@ -67,7 +66,7 @@ typedef struct VirtioBusClass VirtioCcwBusClass; typedef struct VirtioCcwDevice VirtioCcwDevice; typedef struct VirtIOCCWDeviceClass { - CCWDeviceClass parent_class; + DeviceClass parent_class; void (*realize)(VirtioCcwDevice *dev, Error **errp); int (*exit)(VirtioCcwDevice *dev); } VirtIOCCWDeviceClass; @@ -78,7 +77,9 @@ typedef struct VirtIOCCWDeviceClass { #define VIRTIO_CCW_FLAG_USE_IOEVENTFD (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT) struct VirtioCcwDevice { - CcwDevice parent_obj; + DeviceState parent_obj; + SubchDev *sch; + char *bus_id; int revision; uint32_t max_rev; VirtioBusState bus; @@ -101,6 +102,15 @@ static inline int virtio_ccw_rev_max(VirtioCcwDevice *dev) return dev->max_rev; } +/* virtual css bus type */ +typedef struct VirtualCssBus { + BusState parent_obj; +} VirtualCssBus; + +#define TYPE_VIRTUAL_CSS_BUS "virtual-css-bus" +#define VIRTUAL_CSS_BUS(obj) \ + OBJECT_CHECK(VirtualCssBus, (obj), TYPE_VIRTUAL_CSS_BUS) + /* virtio-scsi-ccw */ #define TYPE_VIRTIO_SCSI_CCW "virtio-scsi-ccw" @@ -180,6 +190,7 @@ typedef struct VirtIORNGCcw { VirtIORNG vdev; } VirtIORNGCcw; +VirtualCssBus *virtual_css_bus_init(void); void virtio_ccw_device_update_status(SubchDev *sch); VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch); diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 1f2f2d33d..baa0a2cfd 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -574,7 +574,7 @@ static bool esp_mem_accepts(void *opaque, hwaddr addr, const VMStateDescription vmstate_esp = { .name ="esp", - .version_id = 4, + .version_id = 3, .minimum_version_id = 3, .fields = (VMStateField[]) { VMSTATE_BUFFER(rregs, ESPState), @@ -585,8 +585,7 @@ const VMStateDescription vmstate_esp = { VMSTATE_BUFFER(ti_buf, ESPState), VMSTATE_UINT32(status, ESPState), VMSTATE_UINT32(dma, ESPState), - VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16), - VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4), + VMSTATE_BUFFER(cmdbuf, ESPState), VMSTATE_UINT32(cmdlen, ESPState), VMSTATE_UINT32(do_cmd, ESPState), VMSTATE_UINT32(dma_left, ESPState), diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index e968302fd..a9ffc3268 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -29,7 +29,7 @@ #include "hw/scsi/scsi.h" #include "block/scsi.h" #include "trace.h" -#include "qapi/error.h" + #include "mfi.h" #define MEGASAS_VERSION_GEN1 "1.70" @@ -48,7 +48,11 @@ #define MEGASAS_FLAG_USE_JBOD 0 #define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD) -#define MEGASAS_FLAG_USE_QUEUE64 1 +#define MEGASAS_FLAG_USE_MSI 1 +#define MEGASAS_MASK_USE_MSI (1 << MEGASAS_FLAG_USE_MSI) +#define MEGASAS_FLAG_USE_MSIX 2 +#define MEGASAS_MASK_USE_MSIX (1 << MEGASAS_FLAG_USE_MSIX) +#define MEGASAS_FLAG_USE_QUEUE64 3 #define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64) static const char *mfi_frame_desc[] = { @@ -92,8 +96,6 @@ typedef struct MegasasState { int busy; int diag; int adp_reset; - OnOffAuto msi; - OnOffAuto msix; MegasasCmd *event_cmd; int event_locale; @@ -155,9 +157,14 @@ static bool megasas_use_queue64(MegasasState *s) return s->flags & MEGASAS_MASK_USE_QUEUE64; } +static bool megasas_use_msi(MegasasState *s) +{ + return s->flags & MEGASAS_MASK_USE_MSI; +} + static bool megasas_use_msix(MegasasState *s) { - return s->msix != ON_OFF_AUTO_OFF; + return s->flags & MEGASAS_MASK_USE_MSIX; } static bool megasas_is_jbod(MegasasState *s) @@ -403,14 +410,17 @@ static void megasas_encode_lba(uint8_t *cdb, uint64_t lba, static uint64_t megasas_fw_time(void) { struct tm curtime; + uint64_t bcd_time; qemu_get_timedate(&curtime, 0); - return ((uint64_t)curtime.tm_sec & 0xff) << 48 | + bcd_time = ((uint64_t)curtime.tm_sec & 0xff) << 48 | ((uint64_t)curtime.tm_min & 0xff) << 40 | ((uint64_t)curtime.tm_hour & 0xff) << 32 | ((uint64_t)curtime.tm_mday & 0xff) << 24 | ((uint64_t)curtime.tm_mon & 0xff) << 16 | ((uint64_t)(curtime.tm_year + 1900) & 0xffff); + + return bcd_time; } /* @@ -1981,7 +1991,11 @@ static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr, break; } if (frame_status != MFI_STAT_INVALID_STATUS) { - cmd->frame->header.cmd_status = frame_status; + if (cmd->frame) { + cmd->frame->header.cmd_status = frame_status; + } else { + megasas_frame_set_cmd_status(s, frame_addr, frame_status); + } megasas_unmap_frame(s, cmd); megasas_complete_frame(s, cmd->context); } @@ -2298,7 +2312,9 @@ static void megasas_scsi_uninit(PCIDevice *d) if (megasas_use_msix(s)) { msix_uninit(d, &s->mmio_io, &s->mmio_io); } - msi_uninit(d); + if (megasas_use_msi(s)) { + msi_uninit(d); + } } static const struct SCSIBusInfo megasas_scsi_info = { @@ -2319,8 +2335,6 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp) MegasasBaseClass *b = MEGASAS_DEVICE_GET_CLASS(s); uint8_t *pci_conf; int i, bar_type; - Error *err = NULL; - int ret; pci_conf = dev->config; @@ -2329,24 +2343,6 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp) /* Interrupt pin 1 */ pci_conf[PCI_INTERRUPT_PIN] = 0x01; - if (s->msi != ON_OFF_AUTO_OFF) { - ret = msi_init(dev, 0x50, 1, true, false, &err); - /* Any error other than -ENOTSUP(board's MSI support is broken) - * is a programming error */ - assert(!ret || ret == -ENOTSUP); - if (ret && s->msi == ON_OFF_AUTO_ON) { - /* Can't satisfy user's explicit msi=on request, fail */ - error_append_hint(&err, "You have to use msi=auto (default) or " - "msi=off with this machine type.\n"); - error_propagate(errp, err); - return; - } else if (ret) { - /* With msi=auto, we fall back to MSI off silently */ - s->msi = ON_OFF_AUTO_OFF; - error_free(err); - } - } - memory_region_init_io(&s->mmio_io, OBJECT(s), &megasas_mmio_ops, s, "megasas-mmio", 0x4000); memory_region_init_io(&s->port_io, OBJECT(s), &megasas_port_ops, s, @@ -2354,10 +2350,14 @@ static void megasas_scsi_realize(PCIDevice *dev, Error **errp) memory_region_init_io(&s->queue_io, OBJECT(s), &megasas_queue_ops, s, "megasas-queue", 0x40000); + if (megasas_use_msi(s) && + msi_init(dev, 0x50, 1, true, false)) { + s->flags &= ~MEGASAS_MASK_USE_MSI; + } if (megasas_use_msix(s) && msix_init(dev, 15, &s->mmio_io, b->mmio_bar, 0x2000, &s->mmio_io, b->mmio_bar, 0x3800, 0x68)) { - s->msix = ON_OFF_AUTO_OFF; + s->flags &= ~MEGASAS_MASK_USE_MSIX; } if (pci_is_express(dev)) { pcie_endpoint_cap_init(dev, 0xa0); @@ -2425,8 +2425,10 @@ static Property megasas_properties_gen1[] = { MEGASAS_DEFAULT_FRAMES), DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial), DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0), - DEFINE_PROP_ON_OFF_AUTO("msi", MegasasState, msi, ON_OFF_AUTO_AUTO), - DEFINE_PROP_ON_OFF_AUTO("msix", MegasasState, msix, ON_OFF_AUTO_AUTO), + DEFINE_PROP_BIT("use_msi", MegasasState, flags, + MEGASAS_FLAG_USE_MSI, false), + DEFINE_PROP_BIT("use_msix", MegasasState, flags, + MEGASAS_FLAG_USE_MSIX, false), DEFINE_PROP_BIT("use_jbod", MegasasState, flags, MEGASAS_FLAG_USE_JBOD, false), DEFINE_PROP_END_OF_LIST(), @@ -2439,8 +2441,10 @@ static Property megasas_properties_gen2[] = { MEGASAS_GEN2_DEFAULT_FRAMES), DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial), DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0), - DEFINE_PROP_ON_OFF_AUTO("msi", MegasasState, msi, ON_OFF_AUTO_AUTO), - DEFINE_PROP_ON_OFF_AUTO("msix", MegasasState, msix, ON_OFF_AUTO_AUTO), + DEFINE_PROP_BIT("use_msi", MegasasState, flags, + MEGASAS_FLAG_USE_MSI, true), + DEFINE_PROP_BIT("use_msix", MegasasState, flags, + MEGASAS_FLAG_USE_MSIX, true), DEFINE_PROP_BIT("use_jbod", MegasasState, flags, MEGASAS_FLAG_USE_JBOD, false), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h index e67a5c0b4..29d41775d 100644 --- a/hw/scsi/mfi.h +++ b/hw/scsi/mfi.h @@ -30,8 +30,8 @@ * SUCH DAMAGE. */ -#ifndef SCSI_MFI_H -#define SCSI_MFI_H +#ifndef MFI_REG_H +#define MFI_REG_H /* * MegaRAID SAS MFI firmware definitions @@ -1269,4 +1269,4 @@ struct mfi_config_data { #define MFI_SCSI_MAX_CMDS 8 #define MFI_SCSI_MAX_CDB_LEN 16 -#endif /* SCSI_MFI_H */ +#endif /* MFI_REG_H */ diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index 0e0a22f69..be88e161a 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -32,7 +32,7 @@ #include "hw/scsi/scsi.h" #include "block/scsi.h" #include "trace.h" -#include "qapi/error.h" + #include "mptsas.h" #include "mpi.h" @@ -63,7 +63,7 @@ static void mptsas_update_interrupt(MPTSASState *s) PCIDevice *pci = (PCIDevice *) s; uint32_t state = s->intr_status & ~(s->intr_mask | MPI_HIS_IOP_DOORBELL_STATUS); - if (msi_enabled(pci)) { + if (s->msi_in_use && msi_enabled(pci)) { if (state) { trace_mptsas_irq_msi(s); msi_notify(pci, 0); @@ -1273,32 +1273,10 @@ static void mptsas_scsi_init(PCIDevice *dev, Error **errp) { DeviceState *d = DEVICE(dev); MPTSASState *s = MPT_SAS(dev); - Error *err = NULL; - int ret; dev->config[PCI_LATENCY_TIMER] = 0; dev->config[PCI_INTERRUPT_PIN] = 0x01; - if (s->msi != ON_OFF_AUTO_OFF) { - ret = msi_init(dev, 0, 1, true, false, &err); - /* Any error other than -ENOTSUP(board's MSI support is broken) - * is a programming error */ - assert(!ret || ret == -ENOTSUP); - if (ret && s->msi == ON_OFF_AUTO_ON) { - /* Can't satisfy user's explicit msi=on request, fail */ - error_append_hint(&err, "You have to use msi=auto (default) or " - "msi=off with this machine type.\n"); - error_propagate(errp, err); - return; - } - assert(!err || s->msi == ON_OFF_AUTO_AUTO); - /* With msi=auto, we fall back to MSI off silently */ - error_free(err); - - /* Only used for migration. */ - s->msi_in_use = (ret == 0); - } - memory_region_init_io(&s->mmio_io, OBJECT(s), &mptsas_mmio_ops, s, "mptsas-mmio", 0x4000); memory_region_init_io(&s->port_io, OBJECT(s), &mptsas_port_ops, s, @@ -1306,6 +1284,11 @@ static void mptsas_scsi_init(PCIDevice *dev, Error **errp) memory_region_init_io(&s->diag_io, OBJECT(s), &mptsas_diag_ops, s, "mptsas-diag", 0x10000); + if (s->msi_available && + msi_init(dev, 0, 1, true, false) >= 0) { + s->msi_in_use = true; + } + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io); pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32, &s->mmio_io); @@ -1336,7 +1319,9 @@ static void mptsas_scsi_uninit(PCIDevice *dev) MPTSASState *s = MPT_SAS(dev); qemu_bh_delete(s->request_bh); - msi_uninit(dev); + if (s->msi_in_use) { + msi_uninit(dev); + } } static void mptsas_reset(DeviceState *dev) @@ -1373,6 +1358,7 @@ static const VMStateDescription vmstate_mptsas = { .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(dev, MPTSASState), VMSTATE_BOOL(msi_in_use, MPTSASState), + VMSTATE_UINT32(state, MPTSASState), VMSTATE_UINT8(who_init, MPTSASState), VMSTATE_UINT8(doorbell_state, MPTSASState), @@ -1417,7 +1403,7 @@ static const VMStateDescription vmstate_mptsas = { static Property mptsas_properties[] = { DEFINE_PROP_UINT64("sas_address", MPTSASState, sas_addr, 0), /* TODO: test MSI support under Windows */ - DEFINE_PROP_ON_OFF_AUTO("msi", MPTSASState, msi, ON_OFF_AUTO_AUTO), + DEFINE_PROP_BIT("msi", MPTSASState, msi_available, 0, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/scsi/mptsas.h b/hw/scsi/mptsas.h index 0436a3391..595f81fb5 100644 --- a/hw/scsi/mptsas.h +++ b/hw/scsi/mptsas.h @@ -27,8 +27,7 @@ struct MPTSASState { MemoryRegion diag_io; QEMUBH *request_bh; - /* properties */ - OnOffAuto msi; + uint32_t msi_available; uint64_t sas_addr; bool msi_in_use; diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 297216dfc..ad6f398c3 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -461,14 +461,6 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r) return true; } -static size_t scsi_sense_len(SCSIRequest *req) -{ - if (req->dev->type == TYPE_SCANNER) - return SCSI_SENSE_LEN_SCANNER; - else - return SCSI_SENSE_LEN; -} - static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) { SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req); @@ -485,7 +477,7 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) } break; case REQUEST_SENSE: - scsi_target_alloc_buf(&r->req, scsi_sense_len(req)); + scsi_target_alloc_buf(&r->req, SCSI_SENSE_LEN); r->len = scsi_device_get_sense(r->req.dev, r->buf, MIN(req->cmd.xfer, r->buf_len), (req->cmd.buf[1] & 1) == 0); @@ -1140,29 +1132,6 @@ static int scsi_req_medium_changer_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8 return 0; } -static int scsi_req_scanner_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) -{ - switch (buf[0]) { - /* Scanner commands */ - case OBJECT_POSITION: - cmd->xfer = 0; - break; - case SCAN: - cmd->xfer = buf[4]; - break; - case READ_10: - case SEND: - case GET_WINDOW: - case SET_WINDOW: - cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16); - break; - default: - /* GET_DATA_BUFFER_STATUS xfer handled by scsi_req_xfer */ - return scsi_req_xfer(cmd, dev, buf); - } - - return 0; -} static void scsi_cmd_xfer_mode(SCSICommand *cmd) { @@ -1209,11 +1178,6 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd) case SEND_DVD_STRUCTURE: case PERSISTENT_RESERVE_OUT: case MAINTENANCE_OUT: - case SET_WINDOW: - case SCAN: - /* SCAN conflicts with START_STOP. START_STOP has cmd->xfer set to 0 for - * non-scanner devices, so we only get here for SCAN and not for START_STOP. - */ cmd->mode = SCSI_XFER_TO_DEV; break; case ATA_PASSTHROUGH_12: @@ -1294,9 +1258,6 @@ int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf) case TYPE_MEDIUM_CHANGER: rc = scsi_req_medium_changer_xfer(cmd, dev, buf); break; - case TYPE_SCANNER: - rc = scsi_req_scanner_length(cmd, dev, buf); - break; default: rc = scsi_req_xfer(cmd, dev, buf); break; diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 836a1553e..c3ce54a20 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -53,21 +53,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #define DEFAULT_MAX_UNMAP_SIZE (1 << 30) /* 1 GB */ #define DEFAULT_MAX_IO_SIZE INT_MAX /* 2 GB - 1 block */ -#define TYPE_SCSI_DISK_BASE "scsi-disk-base" - -#define SCSI_DISK_BASE(obj) \ - OBJECT_CHECK(SCSIDiskState, (obj), TYPE_SCSI_DISK_BASE) -#define SCSI_DISK_BASE_CLASS(klass) \ - OBJECT_CLASS_CHECK(SCSIDiskClass, (klass), TYPE_SCSI_DISK_BASE) -#define SCSI_DISK_BASE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(SCSIDiskClass, (obj), TYPE_SCSI_DISK_BASE) - -typedef struct SCSIDiskClass { - SCSIDeviceClass parent_class; - DMAIOFunc *dma_readv; - DMAIOFunc *dma_writev; - bool (*need_fua_emulation)(SCSICommand *cmd); -} SCSIDiskClass; +typedef struct SCSIDiskState SCSIDiskState; typedef struct SCSIDiskReq { SCSIRequest req; @@ -76,18 +62,16 @@ typedef struct SCSIDiskReq { uint32_t sector_count; uint32_t buflen; bool started; - bool need_fua_emulation; struct iovec iov; QEMUIOVector qiov; BlockAcctCookie acct; - unsigned char *status; } SCSIDiskReq; #define SCSI_DISK_F_REMOVABLE 0 #define SCSI_DISK_F_DPOFUA 1 #define SCSI_DISK_F_NO_REMOVABLE_DEVOPS 2 -typedef struct SCSIDiskState +struct SCSIDiskState { SCSIDevice qdev; uint32_t features; @@ -104,7 +88,7 @@ typedef struct SCSIDiskState char *product; bool tray_open; bool tray_locked; -} SCSIDiskState; +}; static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed); @@ -124,7 +108,7 @@ static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense) scsi_req_complete(&r->req, CHECK_CONDITION); } -static void scsi_init_iovec(SCSIDiskReq *r, size_t size) +static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); @@ -134,6 +118,7 @@ static void scsi_init_iovec(SCSIDiskReq *r, size_t size) } r->iov.iov_len = MIN(r->sector_count * 512, r->buflen); qemu_iovec_init_external(&r->qiov, &r->iov, 1); + return r->qiov.size / 512; } static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req) @@ -177,29 +162,6 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) qemu_iovec_init_external(&r->qiov, &r->iov, 1); } -static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) -{ - if (r->req.io_canceled) { - scsi_req_cancel_complete(&r->req); - return true; - } - - if (ret < 0) { - return scsi_handle_rw_error(r, -ret, acct_failed); - } - - if (r->status && *r->status) { - if (acct_failed) { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); - } - scsi_req_complete(&r->req, *r->status); - return true; - } - - return false; -} - static void scsi_aio_complete(void *opaque, int ret) { SCSIDiskReq *r = (SCSIDiskReq *)opaque; @@ -207,10 +169,17 @@ static void scsi_aio_complete(void *opaque, int ret) assert(r->req.aiocb != NULL); r->req.aiocb = NULL; - if (scsi_disk_req_check_error(r, ret, true)) { + if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret, true)) { + goto done; + } + } + block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct); scsi_req_complete(&r->req, GOOD); @@ -249,9 +218,13 @@ static void scsi_write_do_fua(SCSIDiskReq *r) SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); assert(r->req.aiocb == NULL); - assert(!r->req.io_canceled); - if (r->need_fua_emulation) { + if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); + goto done; + } + + if (scsi_is_cmd_fua(&r->req.cmd)) { block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0, BLOCK_ACCT_FLUSH); r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r); @@ -259,16 +232,26 @@ static void scsi_write_do_fua(SCSIDiskReq *r) } scsi_req_complete(&r->req, GOOD); + +done: scsi_req_unref(&r->req); } static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret) { assert(r->req.aiocb == NULL); - if (scsi_disk_req_check_error(r, ret, false)) { + + if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret, false)) { + goto done; + } + } + r->sector += r->sector_count; r->sector_count = 0; if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { @@ -306,10 +289,17 @@ static void scsi_read_complete(void * opaque, int ret) assert(r->req.aiocb != NULL); r->req.aiocb = NULL; - if (scsi_disk_req_check_error(r, ret, true)) { + if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret, true)) { + goto done; + } + } + block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct); DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size); @@ -326,29 +316,35 @@ done: static void scsi_do_read(SCSIDiskReq *r, int ret) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); + uint32_t n; assert (r->req.aiocb == NULL); - if (scsi_disk_req_check_error(r, ret, false)) { + + if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret, false)) { + goto done; + } + } + /* The request is used as the AIO opaque value, so add a ref. */ scsi_req_ref(&r->req); if (r->req.sg) { dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_READ); r->req.resid -= r->req.sg->size; - r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk), - r->req.sg, r->sector << BDRV_SECTOR_BITS, - sdc->dma_readv, r, scsi_dma_complete, r, - DMA_DIRECTION_FROM_DEVICE); + r->req.aiocb = dma_blk_read(s->qdev.conf.blk, r->req.sg, r->sector, + scsi_dma_complete, r); } else { - scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); + n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, - r->qiov.size, BLOCK_ACCT_READ); - r->req.aiocb = sdc->dma_readv(r->sector << BDRV_SECTOR_BITS, &r->qiov, - scsi_read_complete, r, r); + n * BDRV_SECTOR_SIZE, BLOCK_ACCT_READ); + r->req.aiocb = blk_aio_readv(s->qdev.conf.blk, r->sector, &r->qiov, n, + scsi_read_complete, r); } done: @@ -403,7 +399,7 @@ static void scsi_read_data(SCSIRequest *req) first = !r->started; r->started = true; - if (first && r->need_fua_emulation) { + if (first && scsi_is_cmd_fua(&r->req.cmd)) { block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0, BLOCK_ACCT_FLUSH); r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read_cb, r); @@ -460,10 +456,18 @@ static void scsi_write_complete_noio(SCSIDiskReq *r, int ret) uint32_t n; assert (r->req.aiocb == NULL); - if (scsi_disk_req_check_error(r, ret, false)) { + + if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret, false)) { + goto done; + } + } + n = r->qiov.size / 512; r->sector += n; r->sector_count -= n; @@ -500,7 +504,7 @@ static void scsi_write_data(SCSIRequest *req) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); + uint32_t n; /* No data transfer may already be in progress */ assert(r->req.aiocb == NULL); @@ -537,15 +541,14 @@ static void scsi_write_data(SCSIRequest *req) if (r->req.sg) { dma_acct_start(s->qdev.conf.blk, &r->acct, r->req.sg, BLOCK_ACCT_WRITE); r->req.resid -= r->req.sg->size; - r->req.aiocb = dma_blk_io(blk_get_aio_context(s->qdev.conf.blk), - r->req.sg, r->sector << BDRV_SECTOR_BITS, - sdc->dma_writev, r, scsi_dma_complete, r, - DMA_DIRECTION_TO_DEVICE); + r->req.aiocb = dma_blk_write(s->qdev.conf.blk, r->req.sg, r->sector, + scsi_dma_complete, r); } else { + n = r->qiov.size / 512; block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, - r->qiov.size, BLOCK_ACCT_WRITE); - r->req.aiocb = sdc->dma_writev(r->sector << BDRV_SECTOR_BITS, &r->qiov, - scsi_write_complete, r, r); + n * BDRV_SECTOR_SIZE, BLOCK_ACCT_WRITE); + r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, r->sector, &r->qiov, n, + scsi_write_complete, r); } } @@ -1597,10 +1600,18 @@ static void scsi_unmap_complete_noio(UnmapCBData *data, int ret) uint32_t nb_sectors; assert(r->req.aiocb == NULL); - if (scsi_disk_req_check_error(r, ret, false)) { + + if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret, false)) { + goto done; + } + } + if (data->count > 0) { sector_num = ldq_be_p(&data->inbuf[0]); nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL; @@ -1609,10 +1620,10 @@ static void scsi_unmap_complete_noio(UnmapCBData *data, int ret) goto done; } - r->req.aiocb = blk_aio_pdiscard(s->qdev.conf.blk, - sector_num * s->qdev.blocksize, - nb_sectors * s->qdev.blocksize, - scsi_unmap_complete, data); + r->req.aiocb = blk_aio_discard(s->qdev.conf.blk, + sector_num * (s->qdev.blocksize / 512), + nb_sectors * (s->qdev.blocksize / 512), + scsi_unmap_complete, data); data->count--; data->inbuf += 16; return; @@ -1700,10 +1711,17 @@ static void scsi_write_same_complete(void *opaque, int ret) assert(r->req.aiocb != NULL); r->req.aiocb = NULL; - if (scsi_disk_req_check_error(r, ret, true)) { + if (r->req.io_canceled) { + scsi_req_cancel_complete(&r->req); goto done; } + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret, true)) { + goto done; + } + } + block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct); data->nb_sectors -= data->iov.iov_len / 512; @@ -1712,13 +1730,13 @@ static void scsi_write_same_complete(void *opaque, int ret) if (data->iov.iov_len) { block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, data->iov.iov_len, BLOCK_ACCT_WRITE); - /* Reinitialize qiov, to handle unaligned WRITE SAME request - * where final qiov may need smaller size */ + /* blk_aio_write doesn't like the qiov size being different from + * nb_sectors, make sure they match. + */ qemu_iovec_init_external(&data->qiov, &data->iov, 1); - r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk, - data->sector << BDRV_SECTOR_BITS, - &data->qiov, 0, - scsi_write_same_complete, data); + r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, data->sector, + &data->qiov, data->iov.iov_len / 512, + scsi_write_same_complete, data); return; } @@ -1762,9 +1780,9 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, nb_sectors * s->qdev.blocksize, BLOCK_ACCT_WRITE); - r->req.aiocb = blk_aio_pwrite_zeroes(s->qdev.conf.blk, - r->req.cmd.lba * s->qdev.blocksize, - nb_sectors * s->qdev.blocksize, + r->req.aiocb = blk_aio_write_zeroes(s->qdev.conf.blk, + r->req.cmd.lba * (s->qdev.blocksize / 512), + nb_sectors * (s->qdev.blocksize / 512), flags, scsi_aio_complete, r); return; } @@ -1785,10 +1803,9 @@ static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) scsi_req_ref(&r->req); block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, data->iov.iov_len, BLOCK_ACCT_WRITE); - r->req.aiocb = blk_aio_pwritev(s->qdev.conf.blk, - data->sector << BDRV_SECTOR_BITS, - &data->qiov, 0, - scsi_write_same_complete, data); + r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, data->sector, + &data->qiov, data->iov.iov_len / 512, + scsi_write_same_complete, data); } static void scsi_disk_emulate_write_data(SCSIRequest *req) @@ -2060,13 +2077,13 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) } break; case MODE_SELECT: - DPRINTF("Mode Select(6) (len %lu)\n", (unsigned long)r->req.cmd.xfer); + DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer); break; case MODE_SELECT_10: - DPRINTF("Mode Select(10) (len %lu)\n", (unsigned long)r->req.cmd.xfer); + DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer); break; case UNMAP: - DPRINTF("Unmap (len %lu)\n", (unsigned long)r->req.cmd.xfer); + DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer); break; case VERIFY_10: case VERIFY_12: @@ -2080,7 +2097,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) case WRITE_SAME_16: DPRINTF("WRITE SAME %d (len %lu)\n", req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16, - (unsigned long)r->req.cmd.xfer); + (long)r->req.cmd.xfer); break; default: DPRINTF("Unknown SCSI command (%2.2x=%s)\n", buf[0], @@ -2120,7 +2137,6 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) { SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); - SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); uint32_t len; uint8_t command; @@ -2179,7 +2195,6 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); return 0; } - r->need_fua_emulation = sdc->need_fua_emulation(&r->req.cmd); if (r->sector_count == 0) { scsi_req_complete(&r->req, GOOD); } @@ -2309,7 +2324,6 @@ static void scsi_realize(SCSIDevice *dev, Error **errp) return; } } - blkconf_apply_backend_options(&dev->conf); if (s->qdev.conf.discard_granularity == -1) { s->qdev.conf.discard_granularity = @@ -2563,145 +2577,16 @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) scsi_generic_read_device_identification(&s->qdev); } -typedef struct SCSIBlockReq { - SCSIDiskReq req; - sg_io_hdr_t io_header; - - /* Selected bytes of the original CDB, copied into our own CDB. */ - uint8_t cmd, cdb1, group_number; - - /* CDB passed to SG_IO. */ - uint8_t cdb[16]; -} SCSIBlockReq; - -static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req, - int64_t offset, QEMUIOVector *iov, - int direction, - BlockCompletionFunc *cb, void *opaque) -{ - sg_io_hdr_t *io_header = &req->io_header; - SCSIDiskReq *r = &req->req; - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - int nb_logical_blocks; - uint64_t lba; - BlockAIOCB *aiocb; - - /* This is not supported yet. It can only happen if the guest does - * reads and writes that are not aligned to one logical sectors - * _and_ cover multiple MemoryRegions. - */ - assert(offset % s->qdev.blocksize == 0); - assert(iov->size % s->qdev.blocksize == 0); - - io_header->interface_id = 'S'; - - /* The data transfer comes from the QEMUIOVector. */ - io_header->dxfer_direction = direction; - io_header->dxfer_len = iov->size; - io_header->dxferp = (void *)iov->iov; - io_header->iovec_count = iov->niov; - assert(io_header->iovec_count == iov->niov); /* no overflow! */ - - /* Build a new CDB with the LBA and length patched in, in case - * DMA helpers split the transfer in multiple segments. Do not - * build a CDB smaller than what the guest wanted, and only build - * a larger one if strictly necessary. - */ - io_header->cmdp = req->cdb; - lba = offset / s->qdev.blocksize; - nb_logical_blocks = io_header->dxfer_len / s->qdev.blocksize; - - if ((req->cmd >> 5) == 0 && lba <= 0x1ffff) { - /* 6-byte CDB */ - stl_be_p(&req->cdb[0], lba | (req->cmd << 24)); - req->cdb[4] = nb_logical_blocks; - req->cdb[5] = 0; - io_header->cmd_len = 6; - } else if ((req->cmd >> 5) <= 1 && lba <= 0xffffffffULL) { - /* 10-byte CDB */ - req->cdb[0] = (req->cmd & 0x1f) | 0x20; - req->cdb[1] = req->cdb1; - stl_be_p(&req->cdb[2], lba); - req->cdb[6] = req->group_number; - stw_be_p(&req->cdb[7], nb_logical_blocks); - req->cdb[9] = 0; - io_header->cmd_len = 10; - } else if ((req->cmd >> 5) != 4 && lba <= 0xffffffffULL) { - /* 12-byte CDB */ - req->cdb[0] = (req->cmd & 0x1f) | 0xA0; - req->cdb[1] = req->cdb1; - stl_be_p(&req->cdb[2], lba); - stl_be_p(&req->cdb[6], nb_logical_blocks); - req->cdb[10] = req->group_number; - req->cdb[11] = 0; - io_header->cmd_len = 12; - } else { - /* 16-byte CDB */ - req->cdb[0] = (req->cmd & 0x1f) | 0x80; - req->cdb[1] = req->cdb1; - stq_be_p(&req->cdb[2], lba); - stl_be_p(&req->cdb[10], nb_logical_blocks); - req->cdb[14] = req->group_number; - req->cdb[15] = 0; - io_header->cmd_len = 16; - } - - /* The rest is as in scsi-generic.c. */ - io_header->mx_sb_len = sizeof(r->req.sense); - io_header->sbp = r->req.sense; - io_header->timeout = UINT_MAX; - io_header->usr_ptr = r; - io_header->flags |= SG_FLAG_DIRECT_IO; - - aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, cb, opaque); - assert(aiocb != NULL); - return aiocb; -} - -static bool scsi_block_no_fua(SCSICommand *cmd) -{ - return false; -} - -static BlockAIOCB *scsi_block_dma_readv(int64_t offset, - QEMUIOVector *iov, - BlockCompletionFunc *cb, void *cb_opaque, - void *opaque) -{ - SCSIBlockReq *r = opaque; - return scsi_block_do_sgio(r, offset, iov, - SG_DXFER_FROM_DEV, cb, cb_opaque); -} - -static BlockAIOCB *scsi_block_dma_writev(int64_t offset, - QEMUIOVector *iov, - BlockCompletionFunc *cb, void *cb_opaque, - void *opaque) -{ - SCSIBlockReq *r = opaque; - return scsi_block_do_sgio(r, offset, iov, - SG_DXFER_TO_DEV, cb, cb_opaque); -} - static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) { switch (buf[0]) { - case VERIFY_10: - case VERIFY_12: - case VERIFY_16: - /* Check if BYTCHK == 0x01 (data-out buffer contains data - * for the number of logical blocks specified in the length - * field). For other modes, do not use scatter/gather operation. - */ - if ((buf[1] & 6) != 2) { - return false; - } - break; - case READ_6: case READ_10: case READ_12: case READ_16: + case VERIFY_10: + case VERIFY_12: + case VERIFY_16: case WRITE_6: case WRITE_10: case WRITE_12: @@ -2709,8 +2594,21 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) case WRITE_VERIFY_10: case WRITE_VERIFY_12: case WRITE_VERIFY_16: - /* MMC writing cannot be done via DMA helpers, because it sometimes + /* If we are not using O_DIRECT, we might read stale data from the + * host cache if writes were made using other commands than these + * ones (such as WRITE SAME or EXTENDED COPY, etc.). So, without + * O_DIRECT everything must go through SG_IO. + */ + if (!(blk_get_flags(s->qdev.conf.blk) & BDRV_O_NOCACHE)) { + break; + } + + /* MMC writing cannot be done via pread/pwrite, because it sometimes * involves writing beyond the maximum LBA or to negative LBA (lead-in). + * And once you do these writes, reading from the block device is + * unreliable, too. It is even possible that reads deliver random data + * from the host page cache (this is probably a Linux bug). + * * We might use scsi_disk_dma_reqops as long as no writing commands are * seen, but performance usually isn't paramount on optical media. So, * just make scsi-block operate the same as scsi-generic for them. @@ -2728,55 +2626,6 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf) } -static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf) -{ - SCSIBlockReq *r = (SCSIBlockReq *)req; - r->cmd = req->cmd.buf[0]; - switch (r->cmd >> 5) { - case 0: - /* 6-byte CDB. */ - r->cdb1 = r->group_number = 0; - break; - case 1: - /* 10-byte CDB. */ - r->cdb1 = req->cmd.buf[1]; - r->group_number = req->cmd.buf[6]; - break; - case 4: - /* 12-byte CDB. */ - r->cdb1 = req->cmd.buf[1]; - r->group_number = req->cmd.buf[10]; - break; - case 5: - /* 16-byte CDB. */ - r->cdb1 = req->cmd.buf[1]; - r->group_number = req->cmd.buf[14]; - break; - default: - abort(); - } - - if (r->cdb1 & 0xe0) { - /* Protection information is not supported. */ - scsi_check_condition(&r->req, SENSE_CODE(INVALID_FIELD)); - return 0; - } - - r->req.status = &r->io_header.status; - return scsi_disk_dma_command(req, buf); -} - -static const SCSIReqOps scsi_block_dma_reqops = { - .size = sizeof(SCSIBlockReq), - .free_req = scsi_free_request, - .send_command = scsi_block_dma_command, - .read_data = scsi_read_data, - .write_data = scsi_write_data, - .get_buf = scsi_get_buf, - .load_request = scsi_disk_load_request, - .save_request = scsi_disk_save_request, -}; - static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *buf, void *hba_private) @@ -2787,7 +2636,7 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun, hba_private); } else { - return scsi_req_alloc(&scsi_block_dma_reqops, &s->qdev, tag, lun, + return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun, hba_private); } } @@ -2806,50 +2655,8 @@ static int scsi_block_parse_cdb(SCSIDevice *d, SCSICommand *cmd, #endif -static -BlockAIOCB *scsi_dma_readv(int64_t offset, QEMUIOVector *iov, - BlockCompletionFunc *cb, void *cb_opaque, - void *opaque) -{ - SCSIDiskReq *r = opaque; - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - return blk_aio_preadv(s->qdev.conf.blk, offset, iov, 0, cb, cb_opaque); -} - -static -BlockAIOCB *scsi_dma_writev(int64_t offset, QEMUIOVector *iov, - BlockCompletionFunc *cb, void *cb_opaque, - void *opaque) -{ - SCSIDiskReq *r = opaque; - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - return blk_aio_pwritev(s->qdev.conf.blk, offset, iov, 0, cb, cb_opaque); -} - -static void scsi_disk_base_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SCSIDiskClass *sdc = SCSI_DISK_BASE_CLASS(klass); - - dc->fw_name = "disk"; - dc->reset = scsi_disk_reset; - sdc->dma_readv = scsi_dma_readv; - sdc->dma_writev = scsi_dma_writev; - sdc->need_fua_emulation = scsi_is_cmd_fua; -} - -static const TypeInfo scsi_disk_base_info = { - .name = TYPE_SCSI_DISK_BASE, - .parent = TYPE_SCSI_DEVICE, - .class_init = scsi_disk_base_class_initfn, - .instance_size = sizeof(SCSIDiskState), - .class_size = sizeof(SCSIDiskClass), - .abstract = true, -}; - #define DEFINE_SCSI_DISK_PROPERTIES() \ DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf), \ - DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \ DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \ DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \ @@ -2895,14 +2702,17 @@ static void scsi_hd_class_initfn(ObjectClass *klass, void *data) sc->realize = scsi_hd_realize; sc->alloc_req = scsi_new_request; sc->unit_attention_reported = scsi_disk_unit_attention_reported; + dc->fw_name = "disk"; dc->desc = "virtual SCSI disk"; + dc->reset = scsi_disk_reset; dc->props = scsi_hd_properties; dc->vmsd = &vmstate_scsi_disk_state; } static const TypeInfo scsi_hd_info = { .name = "scsi-hd", - .parent = TYPE_SCSI_DISK_BASE, + .parent = TYPE_SCSI_DEVICE, + .instance_size = sizeof(SCSIDiskState), .class_init = scsi_hd_class_initfn, }; @@ -2924,14 +2734,17 @@ static void scsi_cd_class_initfn(ObjectClass *klass, void *data) sc->realize = scsi_cd_realize; sc->alloc_req = scsi_new_request; sc->unit_attention_reported = scsi_disk_unit_attention_reported; + dc->fw_name = "disk"; dc->desc = "virtual SCSI CD-ROM"; + dc->reset = scsi_disk_reset; dc->props = scsi_cd_properties; dc->vmsd = &vmstate_scsi_disk_state; } static const TypeInfo scsi_cd_info = { .name = "scsi-cd", - .parent = TYPE_SCSI_DISK_BASE, + .parent = TYPE_SCSI_DEVICE, + .instance_size = sizeof(SCSIDiskState), .class_init = scsi_cd_class_initfn, }; @@ -2945,22 +2758,21 @@ static void scsi_block_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); - SCSIDiskClass *sdc = SCSI_DISK_BASE_CLASS(klass); sc->realize = scsi_block_realize; sc->alloc_req = scsi_block_new_request; sc->parse_cdb = scsi_block_parse_cdb; - sdc->dma_readv = scsi_block_dma_readv; - sdc->dma_writev = scsi_block_dma_writev; - sdc->need_fua_emulation = scsi_block_no_fua; + dc->fw_name = "disk"; dc->desc = "SCSI block device passthrough"; + dc->reset = scsi_disk_reset; dc->props = scsi_block_properties; dc->vmsd = &vmstate_scsi_disk_state; } static const TypeInfo scsi_block_info = { .name = "scsi-block", - .parent = TYPE_SCSI_DISK_BASE, + .parent = TYPE_SCSI_DEVICE, + .instance_size = sizeof(SCSIDiskState), .class_init = scsi_block_class_initfn, }; #endif @@ -2998,13 +2810,13 @@ static void scsi_disk_class_initfn(ObjectClass *klass, void *data) static const TypeInfo scsi_disk_info = { .name = "scsi-disk", - .parent = TYPE_SCSI_DISK_BASE, + .parent = TYPE_SCSI_DEVICE, + .instance_size = sizeof(SCSIDiskState), .class_init = scsi_disk_class_initfn, }; static void scsi_disk_register_types(void) { - type_register_static(&scsi_disk_base_info); type_register_static(&scsi_hd_info); type_register_static(&scsi_cd_info); #ifdef __linux__ diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 7a588a7ad..c4ba9a485 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -225,14 +225,14 @@ static void scsi_read_complete(void * opaque, int ret) if (s->type == TYPE_DISK && r->req.cmd.buf[0] == INQUIRY && r->req.cmd.buf[2] == 0xb0) { - uint32_t max_transfer = - blk_get_max_transfer(s->conf.blk) / s->blocksize; - - assert(max_transfer); - stl_be_p(&r->buf[8], max_transfer); - /* Also take care of the opt xfer len. */ - if (ldl_be_p(&r->buf[12]) > max_transfer) { - stl_be_p(&r->buf[12], max_transfer); + uint32_t max_xfer_len = blk_get_max_transfer_length(s->conf.blk) / + (s->blocksize / BDRV_SECTOR_SIZE); + if (max_xfer_len) { + stl_be_p(&r->buf[8], max_xfer_len); + /* Also take care of the opt xfer len. */ + if (ldl_be_p(&r->buf[12]) > max_xfer_len) { + stl_be_p(&r->buf[12], max_xfer_len); + } } } scsi_req_data(&r->req, len); @@ -580,7 +580,10 @@ const SCSIReqOps scsi_generic_req_ops = { static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, uint8_t *buf, void *hba_private) { - return scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private); + SCSIRequest *req; + + req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private); + return req; } static Property scsi_generic_properties[] = { diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events deleted file mode 100644 index ed64858fe..000000000 --- a/hw/scsi/trace-events +++ /dev/null @@ -1,204 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/scsi/scsi-bus.c -scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d" -scsi_req_cancel(int target, int lun, int tag) "target %d lun %d tag %d" -scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d" -scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d" -scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d" -scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d" -scsi_req_continue_canceled(int target, int lun, int tag) "target %d lun %d tag %d" -scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d" -scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64 -scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d" -scsi_req_build_sense(int target, int lun, int tag, int key, int asc, int ascq) "target %d lun %d tag %d key %#02x asc %#02x ascq %#02x" -scsi_device_set_ua(int target, int lun, int key, int asc, int ascq) "target %d lun %d key %#02x asc %#02x ascq %#02x" -scsi_report_luns(int target, int lun, int tag) "target %d lun %d tag %d" -scsi_inquiry(int target, int lun, int tag, int cdb1, int cdb2) "target %d lun %d tag %d page %#02x/%#02x" -scsi_test_unit_ready(int target, int lun, int tag) "target %d lun %d tag %d" -scsi_request_sense(int target, int lun, int tag) "target %d lun %d tag %d" - -# hw/scsi/mptsas.c -mptsas_command_complete(void *dev, uint32_t ctx, uint32_t status, uint32_t resid) "dev %p context 0x%08x status %x resid %d" -mptsas_diag_read(void *dev, uint32_t addr, uint32_t val) "dev %p addr 0x%08x value 0x%08x" -mptsas_diag_write(void *dev, uint32_t addr, uint32_t val) "dev %p addr 0x%08x value 0x%08x" -mptsas_irq_intx(void *dev, int level) "dev %p level %d" -mptsas_irq_msi(void *dev) "dev %p " -mptsas_mmio_read(void *dev, uint32_t addr, uint32_t val) "dev %p addr 0x%08x value 0x%x" -mptsas_mmio_unhandled_read(void *dev, uint32_t addr) "dev %p addr 0x%08x" -mptsas_mmio_unhandled_write(void *dev, uint32_t addr, uint32_t val) "dev %p addr 0x%08x value 0x%x" -mptsas_mmio_write(void *dev, uint32_t addr, uint32_t val) "dev %p addr 0x%08x value 0x%x" -mptsas_process_message(void *dev, int msg, uint32_t ctx) "dev %p cmd %d context 0x%08x\n" -mptsas_process_scsi_io_request(void *dev, int bus, int target, int lun, uint64_t len) "dev %p dev %d:%d:%d length %"PRIu64"" -mptsas_reset(void *dev) "dev %p " -mptsas_scsi_overflow(void *dev, uint32_t ctx, uint64_t req, uint64_t found) "dev %p context 0x%08x: %"PRIu64"/%"PRIu64"" -mptsas_sgl_overflow(void *dev, uint32_t ctx, uint64_t req, uint64_t found) "dev %p context 0x%08x: %"PRIu64"/%"PRIu64"" -mptsas_unhandled_cmd(void *dev, uint32_t ctx, uint8_t msg_cmd) "dev %p context 0x%08x: Unhandled cmd %x" -mptsas_unhandled_doorbell_cmd(void *dev, int cmd) "dev %p value 0x%08x" - -# hw/scsi/mptconfig.c -mptsas_config_sas_device(void *dev, int address, int port, int phy_handle, int dev_handle, int page) "dev %p address %d (port %d, handles: phy %d dev %d) page %d" -mptsas_config_sas_phy(void *dev, int address, int port, int phy_handle, int dev_handle, int page) "dev %p address %d (port %d, handles: phy %d dev %d) page %d" - -# hw/scsi/megasas.c -megasas_init_firmware(uint64_t pa) "pa %" PRIx64 " " -megasas_init_queue(uint64_t queue_pa, int queue_len, uint64_t head, uint64_t tail, uint32_t flags) "queue at %" PRIx64 " len %d head %" PRIx64 " tail %" PRIx64 " flags %x" -megasas_initq_map_failed(int frame) "scmd %d: failed to map queue" -megasas_initq_mapped(uint64_t pa) "queue already mapped at %" PRIx64 -megasas_initq_mismatch(int queue_len, int fw_cmds) "queue size %d max fw cmds %d" -megasas_qf_mapped(unsigned int index) "skip mapped frame %x" -megasas_qf_new(unsigned int index, uint64_t frame) "frame %x addr %" PRIx64 -megasas_qf_busy(unsigned long pa) "all frames busy for frame %lx" -megasas_qf_enqueue(unsigned int index, unsigned int count, uint64_t context, unsigned int head, unsigned int tail, int busy) "frame %x count %d context %" PRIx64 " head %x tail %x busy %d" -megasas_qf_update(unsigned int head, unsigned int tail, unsigned int busy) "head %x tail %x busy %d" -megasas_qf_map_failed(int cmd, unsigned long frame) "scmd %d: frame %lu" -megasas_qf_complete_noirq(uint64_t context) "context %" PRIx64 " " -megasas_qf_complete(uint64_t context, unsigned int head, unsigned int tail, int busy) "context %" PRIx64 " head %x tail %x busy %d" -megasas_frame_busy(uint64_t addr) "frame %" PRIx64 " busy" -megasas_unhandled_frame_cmd(int cmd, uint8_t frame_cmd) "scmd %d: MFI cmd %x" -megasas_handle_scsi(const char *frame, int bus, int dev, int lun, void *sdev, unsigned long size) "%s dev %x/%x/%x sdev %p xfer %lu" -megasas_scsi_target_not_present(const char *frame, int bus, int dev, int lun) "%s dev %x/%x/%x" -megasas_scsi_invalid_cdb_len(const char *frame, int bus, int dev, int lun, int len) "%s dev %x/%x/%x invalid cdb len %d" -megasas_iov_read_overflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes" -megasas_iov_write_overflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes" -megasas_iov_read_underflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes" -megasas_iov_write_underflow(int cmd, int bytes, int len) "scmd %d: %d/%d bytes" -megasas_scsi_req_alloc_failed(const char *frame, int dev, int lun) "%s dev %x/%x" -megasas_scsi_read_start(int cmd, int len) "scmd %d: transfer %d bytes of data" -megasas_scsi_write_start(int cmd, int len) "scmd %d: transfer %d bytes of data" -megasas_scsi_nodata(int cmd) "scmd %d: no data to be transferred" -megasas_scsi_complete(int cmd, uint32_t status, int len, int xfer) "scmd %d: status %x, len %u/%u" -megasas_command_complete(int cmd, uint32_t status, uint32_t resid) "scmd %d: status %x, residual %d" -megasas_handle_io(int cmd, const char *frame, int dev, int lun, unsigned long lba, unsigned long count) "scmd %d: %s dev %x/%x lba %lx count %lu" -megasas_io_target_not_present(int cmd, const char *frame, int dev, int lun) "scmd %d: %s dev 1/%x/%x LUN not present" -megasas_io_read_start(int cmd, unsigned long lba, unsigned long count, unsigned long len) "scmd %d: start LBA %lx %lu blocks (%lu bytes)" -megasas_io_write_start(int cmd, unsigned long lba, unsigned long count, unsigned long len) "scmd %d: start LBA %lx %lu blocks (%lu bytes)" -megasas_io_complete(int cmd, uint32_t len) "scmd %d: %d bytes" -megasas_iovec_sgl_overflow(int cmd, int index, int limit) "scmd %d: iovec count %d limit %d" -megasas_iovec_sgl_underflow(int cmd, int index) "scmd %d: iovec count %d" -megasas_iovec_sgl_invalid(int cmd, int index, uint64_t pa, uint32_t len) "scmd %d: element %d pa %" PRIx64 " len %u" -megasas_iovec_overflow(int cmd, int len, int limit) "scmd %d: len %d limit %d" -megasas_iovec_underflow(int cmd, int len, int limit) "scmd %d: len %d limit %d" -megasas_handle_dcmd(int cmd, int opcode) "scmd %d: MFI DCMD opcode %x" -megasas_finish_dcmd(int cmd, int size) "scmd %d: MFI DCMD wrote %d bytes" -megasas_dcmd_req_alloc_failed(int cmd, const char *desc) "scmd %d: %s" -megasas_dcmd_internal_submit(int cmd, const char *desc, int dev) "scmd %d: %s to dev %d" -megasas_dcmd_internal_finish(int cmd, int opcode, int lun) "scmd %d: cmd %x lun %d" -megasas_dcmd_internal_invalid(int cmd, int opcode) "scmd %d: DCMD %x" -megasas_dcmd_unhandled(int cmd, int opcode, int len) "scmd %d: opcode %x, len %d" -megasas_dcmd_zero_sge(int cmd) "scmd %d: zero DCMD sge count" -megasas_dcmd_invalid_sge(int cmd, int count) "scmd %d: DCMD sge count %d" -megasas_dcmd_invalid_xfer_len(int cmd, unsigned long size, unsigned long max) "scmd %d: xfer len %ld, max %ld" -megasas_dcmd_enter(int cmd, const char *dcmd, int len) "scmd %d: DCMD %s len %d" -megasas_dcmd_dummy(int cmd, unsigned long size) "scmd %d: xfer len %ld" -megasas_dcmd_set_fw_time(int cmd, unsigned long time) "scmd %d: Set FW time %lx" -megasas_dcmd_pd_get_list(int cmd, int num, int max, int offset) "scmd %d: DCMD PD get list: %d / %d PDs, size %d" -megasas_dcmd_ld_get_list(int cmd, int num, int max) "scmd %d: DCMD LD get list: found %d / %d LDs" -megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: dev %d" -megasas_dcmd_ld_list_query(int cmd, int flags) "scmd %d: query flags %x" -megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: dev %d" -megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: query flags %x" -megasas_dcmd_reset_ld(int cmd, int target_id) "scmd %d: dev %d" -megasas_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties len %ld" -megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: frame %x" -megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 -megasas_abort_invalid_context(int cmd, uint64_t context, int abort_cmd) "scmd %d: invalid frame context %" PRIx64 " for abort frame %x" -megasas_reset(int fw_state) "firmware state %x" -megasas_init(int sges, int cmds, const char *mode) "Using %d sges, %d cmds, %s mode" -megasas_msix_raise(int vector) "vector %d" -megasas_msi_raise(int vector) "vector %d" -megasas_irq_lower(void) "INTx" -megasas_irq_raise(void) "INTx" -megasas_intr_enabled(void) "Interrupts enabled" -megasas_intr_disabled(void) "Interrupts disabled" -megasas_msix_enabled(int vector) "vector %d" -megasas_msi_enabled(int vector) "vector %d" -megasas_mmio_readl(const char *reg, uint32_t val) "reg %s: 0x%x" -megasas_mmio_invalid_readl(unsigned long addr) "addr 0x%lx" -megasas_mmio_writel(const char *reg, uint32_t val) "reg %s: 0x%x" -megasas_mmio_invalid_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x" - -# hw/scsi/vmw_pvscsi.c -pvscsi_ring_init_data(uint32_t txr_len_log2, uint32_t rxr_len_log2) "TX/RX rings logarithms set to %d/%d" -pvscsi_ring_init_msg(uint32_t len_log2) "MSG ring logarithm set to %d" -pvscsi_ring_flush_cmp(uint64_t filled_cmp_ptr) "new production counter of completion ring is 0x%"PRIx64 -pvscsi_ring_flush_msg(uint64_t filled_cmp_ptr) "new production counter of message ring is 0x%"PRIx64 -pvscsi_update_irq_level(bool raise, uint64_t mask, uint64_t status) "interrupt level set to %d (MASK: 0x%"PRIx64", STATUS: 0x%"PRIx64")" -pvscsi_update_irq_msi(void) "sending MSI notification" -pvscsi_cmp_ring_put(unsigned long addr) "got completion descriptor 0x%lx" -pvscsi_msg_ring_put(unsigned long addr) "got message descriptor 0x%lx" -pvscsi_complete_request(uint64_t context, uint64_t len, uint8_t sense_key) "completion: ctx: 0x%"PRIx64", len: 0x%"PRIx64", sense key: %u" -pvscsi_get_sg_list(int nsg, size_t size) "get SG list: depth: %u, size: %zu" -pvscsi_get_next_sg_elem(uint32_t flags) "unknown flags in SG element (val: 0x%x)" -pvscsi_command_complete_not_found(uint32_t tag) "can't find request for tag 0x%x" -pvscsi_command_complete_data_run(void) "not all data required for command transferred" -pvscsi_command_complete_sense_len(int len) "sense information length is %d bytes" -pvscsi_convert_sglist(uint64_t context, unsigned long addr, uint32_t resid) "element: ctx: 0x%"PRIx64" addr: 0x%lx, len: %ul" -pvscsi_process_req_descr(uint8_t cmd, uint64_t ctx) "SCSI cmd 0x%x, ctx: 0x%"PRIx64 -pvscsi_process_req_descr_unknown_device(void) "command directed to unknown device rejected" -pvscsi_process_req_descr_invalid_dir(void) "command with invalid transfer direction rejected" -pvscsi_process_io(unsigned long addr) "got descriptor 0x%lx" -pvscsi_on_cmd_noimpl(const char* cmd) "unimplemented command %s ignored" -pvscsi_on_cmd_reset_dev(uint32_t tgt, int lun, void* dev) "PVSCSI_CMD_RESET_DEVICE[target %u lun %d (dev 0x%p)]" -pvscsi_on_cmd_arrived(const char* cmd) "command %s arrived" -pvscsi_on_cmd_abort(uint64_t ctx, uint32_t tgt) "command PVSCSI_CMD_ABORT_CMD for ctx 0x%"PRIx64", target %u" -pvscsi_on_cmd_unknown(uint64_t cmd_id) "unknown command %"PRIx64 -pvscsi_on_cmd_unknown_data(uint32_t data) "data for unknown command 0x:%x" -pvscsi_io_write(const char* cmd, uint64_t val) "%s write: %"PRIx64 -pvscsi_io_write_unknown(unsigned long addr, unsigned sz, uint64_t val) "unknown write address: 0x%lx size: %u bytes value: 0x%"PRIx64 -pvscsi_io_read(const char* cmd, uint64_t status) "%s read: 0x%"PRIx64 -pvscsi_io_read_unknown(unsigned long addr, unsigned sz) "unknown read address: 0x%lx size: %u bytes" -pvscsi_init_msi_fail(int res) "failed to initialize MSI, error %d" -pvscsi_state(const char* state) "starting %s ..." -pvscsi_tx_rings_ppn(const char* label, uint64_t ppn) "%s page: %"PRIx64 -pvscsi_tx_rings_num_pages(const char* label, uint32_t num) "Number of %s pages: %u" - -# hw/scsi/esp.c -esp_error_fifo_overrun(void) "FIFO overrun" -esp_error_unhandled_command(uint32_t val) "unhandled command (%2.2x)" -esp_error_invalid_write(uint32_t val, uint32_t addr) "invalid write of 0x%02x at [0x%x]" -esp_raise_irq(void) "Raise IRQ" -esp_lower_irq(void) "Lower IRQ" -esp_dma_enable(void) "Raise enable" -esp_dma_disable(void) "Lower enable" -esp_get_cmd(uint32_t dmalen, int target) "len %d target %d" -esp_do_busid_cmd(uint8_t busid) "busid 0x%x" -esp_handle_satn_stop(uint32_t cmdlen) "cmdlen %d" -esp_write_response(uint32_t status) "Transfer status (status=%d)" -esp_do_dma(uint32_t cmdlen, uint32_t len) "command len %d + %d" -esp_command_complete(void) "SCSI Command complete" -esp_command_complete_unexpected(void) "SCSI command completed unexpectedly" -esp_command_complete_fail(void) "Command failed" -esp_transfer_data(uint32_t dma_left, int32_t ti_size) "transfer %d/%d" -esp_handle_ti(uint32_t minlen) "Transfer Information len %d" -esp_handle_ti_cmd(uint32_t cmdlen) "command len %d" -esp_mem_readb(uint32_t saddr, uint8_t reg) "reg[%d]: 0x%2.2x" -esp_mem_writeb(uint32_t saddr, uint8_t reg, uint32_t val) "reg[%d]: 0x%2.2x -> 0x%2.2x" -esp_mem_writeb_cmd_nop(uint32_t val) "NOP (%2.2x)" -esp_mem_writeb_cmd_flush(uint32_t val) "Flush FIFO (%2.2x)" -esp_mem_writeb_cmd_reset(uint32_t val) "Chip reset (%2.2x)" -esp_mem_writeb_cmd_bus_reset(uint32_t val) "Bus reset (%2.2x)" -esp_mem_writeb_cmd_iccs(uint32_t val) "Initiator Command Complete Sequence (%2.2x)" -esp_mem_writeb_cmd_msgacc(uint32_t val) "Message Accepted (%2.2x)" -esp_mem_writeb_cmd_pad(uint32_t val) "Transfer padding (%2.2x)" -esp_mem_writeb_cmd_satn(uint32_t val) "Set ATN (%2.2x)" -esp_mem_writeb_cmd_rstatn(uint32_t val) "Reset ATN (%2.2x)" -esp_mem_writeb_cmd_sel(uint32_t val) "Select without ATN (%2.2x)" -esp_mem_writeb_cmd_selatn(uint32_t val) "Select with ATN (%2.2x)" -esp_mem_writeb_cmd_selatns(uint32_t val) "Select with ATN & stop (%2.2x)" -esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (%2.2x)" -esp_mem_writeb_cmd_dissel(uint32_t val) "Disable selection (%2.2x)" - -# hw/scsi/esp-pci.c -esp_pci_error_invalid_dma_direction(void) "invalid DMA transfer direction" -esp_pci_error_invalid_read(uint32_t reg) "read access outside bounds (reg 0x%x)" -esp_pci_error_invalid_write(uint32_t reg) "write access outside bounds (reg 0x%x)" -esp_pci_error_invalid_write_dma(uint32_t val, uint32_t addr) "invalid write of 0x%02x at [0x%x]" -esp_pci_dma_read(uint32_t saddr, uint32_t reg) "reg[%d]: 0x%8.8x" -esp_pci_dma_write(uint32_t saddr, uint32_t reg, uint32_t val) "reg[%d]: 0x%8.8x -> 0x%8.8x" -esp_pci_dma_idle(uint32_t val) "IDLE (%.8x)" -esp_pci_dma_blast(uint32_t val) "BLAST (%.8x)" -esp_pci_dma_abort(uint32_t val) "ABORT (%.8x)" -esp_pci_dma_start(uint32_t val) "START (%.8x)" -esp_pci_sbac_read(uint32_t reg) "sbac: 0x%8.8x" -esp_pci_sbac_write(uint32_t reg, uint32_t val) "sbac: 0x%8.8x -> 0x%8.8x" diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 5b2694615..9261d51da 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -15,9 +15,8 @@ */ #include "qemu/osdep.h" -#include <linux/vhost.h> -#include <sys/ioctl.h> #include "qapi/error.h" +#include <sys/ioctl.h> #include "qemu/error-report.h" #include "qemu/queue.h" #include "monitor/monitor.h" @@ -28,6 +27,7 @@ #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" #include "hw/fw-path-provider.h" +#include "linux/vhost.h" #include "qemu/cutils.h" /* Features supported by host kernel. */ @@ -248,7 +248,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) s->dev.backend_features = 0; ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd, - VHOST_BACKEND_TYPE_KERNEL, 0); + VHOST_BACKEND_TYPE_KERNEL); if (ret < 0) { error_setg(errp, "vhost-scsi: vhost initialization failed: %s", strerror(-ret)); diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index b173b9494..1a49f1e4b 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -15,9 +15,9 @@ #include "hw/virtio/virtio-scsi.h" #include "qemu/error-report.h" #include "sysemu/block-backend.h" -#include "hw/scsi/scsi.h" -#include "block/scsi.h" -#include "hw/virtio/virtio-bus.h" +#include <hw/scsi/scsi.h> +#include <block/scsi.h> +#include <hw/virtio/virtio-bus.h> #include "hw/virtio/virtio-access.h" /* Context: QEMU global mutex held */ @@ -31,7 +31,7 @@ void virtio_scsi_set_iothread(VirtIOSCSI *s, IOThread *iothread) s->ctx = iothread_get_aio_context(vs->conf.iothread); /* Don't try if transport does not support notifiers. */ - if (!k->set_guest_notifiers || !k->ioeventfd_started) { + if (!k->set_guest_notifiers || !k->set_host_notifier) { fprintf(stderr, "virtio-scsi: Failed to set iothread " "(transport does not support notifiers)"); exit(1); @@ -69,10 +69,11 @@ static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n, void (*fn)(VirtIODevice *vdev, VirtQueue *vq)) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); int rc; /* Set up virtqueue notify */ - rc = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), n, true); + rc = k->set_host_notifier(qbus->parent, n, true); if (rc != 0) { fprintf(stderr, "virtio-scsi: Failed to set host notifier (%d)\n", rc); @@ -158,7 +159,7 @@ fail_vrings: virtio_scsi_clear_aio(s); aio_context_release(s->ctx); for (i = 0; i < vs->conf.num_queues + 2; i++) { - virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + k->set_host_notifier(qbus->parent, i, false); } k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false); fail_guest_notifiers: @@ -197,7 +198,7 @@ void virtio_scsi_dataplane_stop(VirtIOSCSI *s) aio_context_release(s->ctx); for (i = 0; i < vs->conf.num_queues + 2; i++) { - virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + k->set_host_notifier(qbus->parent, i, false); } /* Clean up guest notifier (irq) */ diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index ce57ef624..30415c6a9 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -20,9 +20,9 @@ #include "qemu/error-report.h" #include "qemu/iov.h" #include "sysemu/block-backend.h" -#include "hw/scsi/scsi.h" -#include "block/scsi.h" -#include "hw/virtio/virtio-bus.h" +#include <hw/scsi/scsi.h> +#include <block/scsi.h> +#include <hw/virtio/virtio-bus.h> #include "hw/virtio/virtio-access.h" static inline int virtio_scsi_get_lun(uint8_t *lun) @@ -185,7 +185,7 @@ static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq) { VirtIOSCSIReq *req = sreq->hba_private; VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(req->dev); - uint32_t n = virtio_get_queue_index(req->vq) - 2; + uint32_t n = virtio_queue_get_id(req->vq) - 2; assert(n < vs->conf.num_queues); qemu_put_be32s(f, &n); @@ -663,17 +663,27 @@ static void virtio_scsi_reset(VirtIODevice *vdev) /* The device does not have anything to save beyond the virtio data. * Request data is saved with callbacks from SCSI devices. */ -static void virtio_scsi_save(QEMUFile *f, void *opaque, size_t size) +static void virtio_scsi_save(QEMUFile *f, void *opaque) { VirtIODevice *vdev = VIRTIO_DEVICE(opaque); + VirtIOSCSI *s = VIRTIO_SCSI(vdev); + + if (s->dataplane_started) { + virtio_scsi_dataplane_stop(s); + } virtio_save(vdev, f); } -static int virtio_scsi_load(QEMUFile *f, void *opaque, size_t size) +static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) { VirtIODevice *vdev = VIRTIO_DEVICE(opaque); + int ret; - return virtio_load(vdev, f, 1); + ret = virtio_load(vdev, f, version_id); + if (ret) { + return ret; + } + return 0; } void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, @@ -763,6 +773,22 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense) } } +static void virtio_scsi_blk_insert_notifier(Notifier *n, void *data) +{ + VirtIOSCSIBlkChangeNotifier *cn = DO_UPCAST(VirtIOSCSIBlkChangeNotifier, + n, n); + assert(cn->sd->conf.blk == data); + blk_op_block_all(cn->sd->conf.blk, cn->s->blocker); +} + +static void virtio_scsi_blk_remove_notifier(Notifier *n, void *data) +{ + VirtIOSCSIBlkChangeNotifier *cn = DO_UPCAST(VirtIOSCSIBlkChangeNotifier, + n, n); + assert(cn->sd->conf.blk == data); + blk_op_unblock_all(cn->sd->conf.blk, cn->s->blocker); +} + static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -771,13 +797,29 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, SCSIDevice *sd = SCSI_DEVICE(dev); if (s->ctx && !s->dataplane_fenced) { + VirtIOSCSIBlkChangeNotifier *insert_notifier, *remove_notifier; + if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { return; } + blk_op_block_all(sd->conf.blk, s->blocker); aio_context_acquire(s->ctx); blk_set_aio_context(sd->conf.blk, s->ctx); aio_context_release(s->ctx); + insert_notifier = g_new0(VirtIOSCSIBlkChangeNotifier, 1); + insert_notifier->n.notify = virtio_scsi_blk_insert_notifier; + insert_notifier->s = s; + insert_notifier->sd = sd; + blk_add_insert_bs_notifier(sd->conf.blk, &insert_notifier->n); + QTAILQ_INSERT_TAIL(&s->insert_notifiers, insert_notifier, next); + + remove_notifier = g_new0(VirtIOSCSIBlkChangeNotifier, 1); + remove_notifier->n.notify = virtio_scsi_blk_remove_notifier; + remove_notifier->s = s; + remove_notifier->sd = sd; + blk_add_remove_bs_notifier(sd->conf.blk, &remove_notifier->n); + QTAILQ_INSERT_TAIL(&s->remove_notifiers, remove_notifier, next); } if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { @@ -793,6 +835,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev); VirtIOSCSI *s = VIRTIO_SCSI(vdev); SCSIDevice *sd = SCSI_DEVICE(dev); + VirtIOSCSIBlkChangeNotifier *insert_notifier, *remove_notifier; if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) { virtio_scsi_push_event(s, sd, @@ -800,6 +843,28 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, VIRTIO_SCSI_EVT_RESET_REMOVED); } + if (s->ctx) { + blk_op_unblock_all(sd->conf.blk, s->blocker); + } + + QTAILQ_FOREACH(insert_notifier, &s->insert_notifiers, next) { + if (insert_notifier->sd == sd) { + notifier_remove(&insert_notifier->n); + QTAILQ_REMOVE(&s->insert_notifiers, insert_notifier, next); + g_free(insert_notifier); + break; + } + } + + QTAILQ_FOREACH(remove_notifier, &s->remove_notifiers, next) { + if (remove_notifier->sd == sd) { + notifier_remove(&remove_notifier->n); + QTAILQ_REMOVE(&s->remove_notifiers, remove_notifier, next); + g_free(remove_notifier); + break; + } + } + qdev_simple_device_unplug_cb(hotplug_dev, dev, errp); } @@ -819,9 +884,8 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = { }; void virtio_scsi_common_realize(DeviceState *dev, Error **errp, - VirtIOHandleOutput ctrl, - VirtIOHandleOutput evt, - VirtIOHandleOutput cmd) + HandleOutput ctrl, HandleOutput evt, + HandleOutput cmd) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev); @@ -842,10 +906,13 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp, s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE; s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE; - s->ctrl_vq = virtio_add_queue_aio(vdev, VIRTIO_SCSI_VQ_SIZE, ctrl); - s->event_vq = virtio_add_queue_aio(vdev, VIRTIO_SCSI_VQ_SIZE, evt); + s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, + ctrl); + s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, + evt); for (i = 0; i < s->conf.num_queues; i++) { - s->cmd_vqs[i] = virtio_add_queue_aio(vdev, VIRTIO_SCSI_VQ_SIZE, cmd); + s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, + cmd); } if (s->conf.iothread) { @@ -857,6 +924,7 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOSCSI *s = VIRTIO_SCSI(dev); + static int virtio_scsi_id; Error *err = NULL; virtio_scsi_common_realize(dev, &err, virtio_scsi_handle_ctrl, @@ -879,6 +947,14 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) return; } } + + register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1, + virtio_scsi_save, virtio_scsi_load, s); + + error_setg(&s->blocker, "block device is in use by data plane"); + + QTAILQ_INIT(&s->insert_notifiers); + QTAILQ_INIT(&s->remove_notifiers); } static void virtio_scsi_instance_init(Object *obj) @@ -902,6 +978,11 @@ void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp) static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) { + VirtIOSCSI *s = VIRTIO_SCSI(dev); + + error_free(s->blocker); + + unregister_savevm(dev, "virtio-scsi", s); virtio_scsi_common_unrealize(dev, errp); } @@ -918,8 +999,6 @@ static Property virtio_scsi_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -VMSTATE_VIRTIO_DEVICE(scsi, 1, virtio_scsi_load, virtio_scsi_save); - static void virtio_scsi_common_class_init(ObjectClass *klass, void *data) { VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); @@ -936,7 +1015,6 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data) HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); dc->props = virtio_scsi_properties; - dc->vmsd = &vmstate_virtio_scsi; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->realize = virtio_scsi_device_realize; vdc->unrealize = virtio_scsi_device_unrealize; diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 5116f4ad6..2d7528d1d 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -28,7 +28,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/scsi/scsi.h" -#include "block/scsi.h" +#include <block/scsi.h> #include "hw/pci/msi.h" #include "vmw_pvscsi.h" #include "trace.h" @@ -121,7 +121,8 @@ typedef struct { uint8_t msg_ring_info_valid; /* Whether message ring initialized */ uint8_t use_msg; /* Whether to use message ring */ - uint8_t msi_used; /* For migration compatibility */ + uint8_t msi_used; /* Whether MSI support was installed successfully */ + PVSCSIRingInfo rings; /* Data transfer rings manager */ uint32_t resetting; /* Reset in progress */ @@ -361,7 +362,7 @@ pvscsi_update_irq_status(PVSCSIState *s) trace_pvscsi_update_irq_level(should_raise, s->reg_interrupt_enabled, s->reg_interrupt_status); - if (msi_enabled(d)) { + if (s->msi_used && msi_enabled(d)) { if (should_raise) { trace_pvscsi_update_irq_msi(); msi_notify(d, PVSCSI_VECTOR_COMPLETION); @@ -1055,20 +1056,22 @@ pvscsi_io_read(void *opaque, hwaddr addr, unsigned size) } -static void +static bool pvscsi_init_msi(PVSCSIState *s) { int res; PCIDevice *d = PCI_DEVICE(s); res = msi_init(d, PVSCSI_MSI_OFFSET(s), PVSCSI_MSIX_NUM_VECTORS, - PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK, NULL); + PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK); if (res < 0) { trace_pvscsi_init_msi_fail(res); s->msi_used = false; } else { s->msi_used = true; } + + return s->msi_used; } static void @@ -1076,7 +1079,9 @@ pvscsi_cleanup_msi(PVSCSIState *s) { PCIDevice *d = PCI_DEVICE(s); - msi_uninit(d); + if (s->msi_used) { + msi_uninit(d); + } } static const MemoryRegionOps pvscsi_ops = { diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c index 1f2f0ed44..c04ff02fa 100644 --- a/hw/sd/milkymist-memcard.c +++ b/hw/sd/milkymist-memcard.c @@ -18,7 +18,7 @@ * * * Specification available at: - * http://milkymist.walle.cc/socdoc/memcard.pdf + * http://www.milkymist.org/socdoc/memcard.pdf */ #include "qemu/osdep.h" diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c index 82c63a4fb..e87abb205 100644 --- a/hw/sd/pl181.c +++ b/hw/sd/pl181.c @@ -12,8 +12,6 @@ #include "sysemu/blockdev.h" #include "hw/sysbus.h" #include "hw/sd/sd.h" -#include "qemu/log.h" -#include "qapi/error.h" //#define DEBUG_PL181 1 @@ -482,48 +480,43 @@ static void pl181_reset(DeviceState *d) sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]); } -static void pl181_init(Object *obj) +static int pl181_init(SysBusDevice *sbd) { - DeviceState *dev = DEVICE(obj); - PL181State *s = PL181(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + PL181State *s = PL181(dev); + DriveInfo *dinfo; - memory_region_init_io(&s->iomem, obj, &pl181_ops, s, "pl181", 0x1000); + memory_region_init_io(&s->iomem, OBJECT(s), &pl181_ops, s, "pl181", 0x1000); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq[0]); sysbus_init_irq(sbd, &s->irq[1]); qdev_init_gpio_out(dev, s->cardstatus, 2); -} - -static void pl181_realize(DeviceState *dev, Error **errp) -{ - PL181State *s = PL181(dev); - DriveInfo *dinfo; - /* FIXME use a qdev drive property instead of drive_get_next() */ dinfo = drive_get_next(IF_SD); s->card = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, false); if (s->card == NULL) { - error_setg(errp, "sd_init failed"); + return -1; } + + return 0; } static void pl181_class_init(ObjectClass *klass, void *data) { + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *k = DEVICE_CLASS(klass); + sdc->init = pl181_init; k->vmsd = &vmstate_pl181; k->reset = pl181_reset; /* Reason: init() method uses drive_get_next() */ k->cannot_instantiate_with_device_add_yet = true; - k->realize = pl181_realize; } static const TypeInfo pl181_info = { .name = TYPE_PL181, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PL181State), - .instance_init = pl181_init, .class_init = pl181_class_init, }; diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 87c6dc108..b66e5d2db 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -39,7 +39,6 @@ #include "hw/qdev-properties.h" #include "qemu/error-report.h" #include "qemu/timer.h" -#include "qemu/log.h" //#define DEBUG_SD 1 @@ -124,6 +123,7 @@ struct SDState { qemu_irq readonly_cb; qemu_irq inserted_cb; BlockBackend *blk; + uint8_t *buf; bool enable; }; @@ -551,7 +551,7 @@ static const VMStateDescription sd_vmstate = { VMSTATE_UINT64(data_start, SDState), VMSTATE_UINT32(data_offset, SDState), VMSTATE_UINT8_ARRAY(data, SDState, 512), - VMSTATE_UNUSED_V(1, 512), + VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512), VMSTATE_BOOL(enable, SDState), VMSTATE_END_OF_LIST() }, @@ -1577,17 +1577,57 @@ send_response: static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len) { + uint64_t end = addr + len; + DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n", (unsigned long long) addr, len); - if (!sd->blk || blk_pread(sd->blk, addr, sd->data, len) < 0) { + if (!sd->blk || blk_read(sd->blk, addr >> 9, sd->buf, 1) < 0) { fprintf(stderr, "sd_blk_read: read error on host side\n"); + return; } + + if (end > (addr & ~511) + 512) { + memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511)); + + if (blk_read(sd->blk, end >> 9, sd->buf, 1) < 0) { + fprintf(stderr, "sd_blk_read: read error on host side\n"); + return; + } + memcpy(sd->data + 512 - (addr & 511), sd->buf, end & 511); + } else + memcpy(sd->data, sd->buf + (addr & 511), len); } static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len) { - if (!sd->blk || blk_pwrite(sd->blk, addr, sd->data, len, 0) < 0) { - fprintf(stderr, "sd_blk_write: write error on host side\n"); + uint64_t end = addr + len; + + if ((addr & 511) || len < 512) + if (!sd->blk || blk_read(sd->blk, addr >> 9, sd->buf, 1) < 0) { + fprintf(stderr, "sd_blk_write: read error on host side\n"); + return; + } + + if (end > (addr & ~511) + 512) { + memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511)); + if (blk_write(sd->blk, addr >> 9, sd->buf, 1) < 0) { + fprintf(stderr, "sd_blk_write: write error on host side\n"); + return; + } + + if (blk_read(sd->blk, end >> 9, sd->buf, 1) < 0) { + fprintf(stderr, "sd_blk_write: read error on host side\n"); + return; + } + memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511); + if (blk_write(sd->blk, end >> 9, sd->buf, 1) < 0) { + fprintf(stderr, "sd_blk_write: write error on host side\n"); + } + } else { + memcpy(sd->buf + (addr & 511), sd->data, len); + if (!sd->blk || blk_write(sd->blk, addr >> 9, sd->buf, 1) < 0) { + fprintf(stderr, "sd_blk_write: write error on host side\n"); + } } } @@ -1885,6 +1925,8 @@ static void sd_realize(DeviceState *dev, Error **errp) return; } + sd->buf = blk_blockalign(sd->blk, 512); + if (sd->blk) { blk_set_dev_ops(sd->blk, &sd_block_ops, sd); } diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 01fbf228b..d28b5871f 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -30,7 +30,6 @@ #include "qemu/timer.h" #include "qemu/bitops.h" #include "sdhci-internal.h" -#include "qemu/log.h" /* host controller debug messages */ #ifndef SDHC_DEBUG diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 3ff0886dd..075e4ed5d 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -15,7 +15,6 @@ #include "sysemu/blockdev.h" #include "hw/ssi/ssi.h" #include "hw/sd/sd.h" -#include "qapi/error.h" //#define DEBUG_SSI_SD 1 @@ -250,7 +249,7 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void ssi_sd_realize(SSISlave *d, Error **errp) +static int ssi_sd_init(SSISlave *d) { DeviceState *dev = DEVICE(d); ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d); @@ -261,17 +260,17 @@ static void ssi_sd_realize(SSISlave *d, Error **errp) dinfo = drive_get_next(IF_SD); s->sd = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, true); if (s->sd == NULL) { - error_setg(errp, "Device initialization failed."); - return; + return -1; } register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); + return 0; } static void ssi_sd_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->realize = ssi_sd_realize; + k->init = ssi_sd_init; k->transfer = ssi_sd_transfer; k->cs_polarity = SSI_CS_LOW; } diff --git a/hw/sd/trace-events b/hw/sd/trace-events deleted file mode 100644 index b17e7ba44..000000000 --- a/hw/sd/trace-events +++ /dev/null @@ -1,5 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/sd/milkymist-memcard.c -milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c index 3132d559d..a1ea760f6 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -30,7 +30,6 @@ #include "sh7750_regnames.h" #include "hw/sh4/sh_intc.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/address-spaces.h" #define NB_DEVICES 4 diff --git a/hw/sh4/sh7750_regnames.h b/hw/sh4/sh7750_regnames.h index e3ba88636..7463709b4 100644 --- a/hw/sh4/sh7750_regnames.h +++ b/hw/sh4/sh7750_regnames.h @@ -1,6 +1,6 @@ -#ifndef SH7750_REGNAMES_H -#define SH7750_REGNAMES_H +#ifndef _SH7750_REGNAMES_H +#define _SH7750_REGNAMES_H const char *regname(uint32_t addr); -#endif /* SH7750_REGNAMES_H */ +#endif /* _SH7750_REGNAMES_H */ diff --git a/hw/sh4/sh7750_regs.h b/hw/sh4/sh7750_regs.h index 3e4554af3..534aa4840 100644 --- a/hw/sh4/sh7750_regs.h +++ b/hw/sh4/sh7750_regs.h @@ -16,8 +16,8 @@ * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp */ -#ifndef SH7750_REGS_H -#define SH7750_REGS_H +#ifndef __SH7750_REGS_H__ +#define __SH7750_REGS_H__ /* * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address) and diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c index 1747628f3..e820a3230 100644 --- a/hw/sh4/sh_pci.c +++ b/hw/sh4/sh_pci.c @@ -55,7 +55,7 @@ static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val, switch(addr) { case 0 ... 0xfc: - stl_le_p(pcic->dev->config + addr, val); + cpu_to_le32w((uint32_t*)(pcic->dev->config + addr), val); break; case 0x1c0: pcic->par = val; @@ -85,7 +85,7 @@ static uint64_t sh_pci_reg_read (void *p, hwaddr addr, switch(addr) { case 0 ... 0xfc: - return ldl_le_p(pcic->dev->config + addr); + return le32_to_cpup((uint32_t*)(pcic->dev->config + addr)); case 0x1c0: return pcic->par; case 0x1c4: diff --git a/hw/smbios/Makefile.objs b/hw/smbios/Makefile.objs index c3d375360..f69a92f96 100644 --- a/hw/smbios/Makefile.objs +++ b/hw/smbios/Makefile.objs @@ -1,2 +1 @@ common-obj-$(CONFIG_SMBIOS) += smbios.o -common-obj-$(call land,$(CONFIG_SMBIOS),$(CONFIG_IPMI)) += smbios_type_38.o diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index 74c710292..cb8a11110 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -24,8 +24,6 @@ #include "hw/smbios/smbios.h" #include "hw/loader.h" #include "exec/cpu-common.h" -#include "smbios_build.h" -#include "hw/smbios/ipmi.h" /* legacy structures and constants for <= 2.0 machines */ struct smbios_header { @@ -55,10 +53,10 @@ static bool smbios_uuid_encoded = true; /* end: legacy structures & constants for <= 2.0 machines */ -uint8_t *smbios_tables; -size_t smbios_tables_len; -unsigned smbios_table_max; -unsigned smbios_table_cnt; +static uint8_t *smbios_tables; +static size_t smbios_tables_len; +static unsigned smbios_table_max; +static unsigned smbios_table_cnt; static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_21; static SmbiosEntryPoint ep; @@ -431,7 +429,7 @@ uint8_t *smbios_get_table_legacy(size_t *length) /* end: legacy setup functions for <= 2.0 machines */ -bool smbios_skip_table(uint8_t type, bool required_table) +static bool smbios_skip_table(uint8_t type, bool required_table) { if (test_bit(type, have_binfile_bitmap)) { return true; /* user provided their own binary blob(s) */ @@ -445,6 +443,65 @@ bool smbios_skip_table(uint8_t type, bool required_table) return true; } +#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \ + struct smbios_type_##tbl_type *t; \ + size_t t_off; /* table offset into smbios_tables */ \ + int str_index = 0; \ + do { \ + /* should we skip building this table ? */ \ + if (smbios_skip_table(tbl_type, tbl_required)) { \ + return; \ + } \ + \ + /* use offset of table t within smbios_tables */ \ + /* (pointer must be updated after each realloc) */ \ + t_off = smbios_tables_len; \ + smbios_tables_len += sizeof(*t); \ + smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \ + t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ + \ + t->header.type = tbl_type; \ + t->header.length = sizeof(*t); \ + t->header.handle = cpu_to_le16(tbl_handle); \ + } while (0) + +#define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \ + do { \ + int len = (value != NULL) ? strlen(value) + 1 : 0; \ + if (len > 1) { \ + smbios_tables = g_realloc(smbios_tables, \ + smbios_tables_len + len); \ + memcpy(smbios_tables + smbios_tables_len, value, len); \ + smbios_tables_len += len; \ + /* update pointer post-realloc */ \ + t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ + t->field = ++str_index; \ + } else { \ + t->field = 0; \ + } \ + } while (0) + +#define SMBIOS_BUILD_TABLE_POST \ + do { \ + size_t term_cnt, t_size; \ + \ + /* add '\0' terminator (add two if no strings defined) */ \ + term_cnt = (str_index == 0) ? 2 : 1; \ + smbios_tables = g_realloc(smbios_tables, \ + smbios_tables_len + term_cnt); \ + memset(smbios_tables + smbios_tables_len, 0, term_cnt); \ + smbios_tables_len += term_cnt; \ + \ + /* update smbios max. element size */ \ + t_size = smbios_tables_len - t_off; \ + if (t_size > smbios_table_max) { \ + smbios_table_max = t_size; \ + } \ + \ + /* update smbios element count */ \ + smbios_table_cnt++; \ + } while (0) + static void smbios_build_type_0_table(void) { SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */ @@ -849,7 +906,6 @@ void smbios_get_tables(const struct smbios_phys_mem_area *mem_array, } smbios_build_type_32_table(); - smbios_build_type_38_table(); smbios_build_type_127_table(); smbios_validate_table(); diff --git a/hw/smbios/smbios_build.h b/hw/smbios/smbios_build.h deleted file mode 100644 index 68b8b72e0..000000000 --- a/hw/smbios/smbios_build.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * SMBIOS Support - * - * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - * Copyright (C) 2013 Red Hat, Inc. - * - * Authors: - * Alex Williamson <alex.williamson@hp.com> - * Markus Armbruster <armbru@redhat.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#ifndef QEMU_SMBIOS_BUILD_H -#define QEMU_SMBIOS_BUILD_H - -bool smbios_skip_table(uint8_t type, bool required_table); - -extern uint8_t *smbios_tables; -extern size_t smbios_tables_len; -extern unsigned smbios_table_max; -extern unsigned smbios_table_cnt; - -#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \ - struct smbios_type_##tbl_type *t; \ - size_t t_off; /* table offset into smbios_tables */ \ - int str_index = 0; \ - do { \ - /* should we skip building this table ? */ \ - if (smbios_skip_table(tbl_type, tbl_required)) { \ - return; \ - } \ - \ - /* use offset of table t within smbios_tables */ \ - /* (pointer must be updated after each realloc) */ \ - t_off = smbios_tables_len; \ - smbios_tables_len += sizeof(*t); \ - smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \ - t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ - \ - t->header.type = tbl_type; \ - t->header.length = sizeof(*t); \ - t->header.handle = cpu_to_le16(tbl_handle); \ - } while (0) - -#define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \ - do { \ - int len = (value != NULL) ? strlen(value) + 1 : 0; \ - if (len > 1) { \ - smbios_tables = g_realloc(smbios_tables, \ - smbios_tables_len + len); \ - memcpy(smbios_tables + smbios_tables_len, value, len); \ - smbios_tables_len += len; \ - /* update pointer post-realloc */ \ - t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ - t->field = ++str_index; \ - } else { \ - t->field = 0; \ - } \ - } while (0) - -#define SMBIOS_BUILD_TABLE_POST \ - do { \ - size_t term_cnt, t_size; \ - \ - /* add '\0' terminator (add two if no strings defined) */ \ - term_cnt = (str_index == 0) ? 2 : 1; \ - smbios_tables = g_realloc(smbios_tables, \ - smbios_tables_len + term_cnt); \ - memset(smbios_tables + smbios_tables_len, 0, term_cnt); \ - smbios_tables_len += term_cnt; \ - \ - /* update smbios max. element size */ \ - t_size = smbios_tables_len - t_off; \ - if (t_size > smbios_table_max) { \ - smbios_table_max = t_size; \ - } \ - \ - /* update smbios element count */ \ - smbios_table_cnt++; \ - } while (0) - -#endif /* QEMU_SMBIOS_BUILD_H */ diff --git a/hw/smbios/smbios_type_38.c b/hw/smbios/smbios_type_38.c deleted file mode 100644 index 56e8609c0..000000000 --- a/hw/smbios/smbios_type_38.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * IPMI SMBIOS firmware handling - * - * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC - * - * 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/ipmi/ipmi.h" -#include "hw/smbios/ipmi.h" -#include "hw/smbios/smbios.h" -#include "qemu/error-report.h" -#include "smbios_build.h" - -/* SMBIOS type 38 - IPMI */ -struct smbios_type_38 { - struct smbios_structure_header header; - uint8_t interface_type; - uint8_t ipmi_spec_revision; - uint8_t i2c_slave_address; - uint8_t nv_storage_device_address; - uint64_t base_address; - uint8_t base_address_modifier; - uint8_t interrupt_number; -} QEMU_PACKED; - -static void smbios_build_one_type_38(IPMIFwInfo *info) -{ - uint64_t baseaddr = info->base_address; - SMBIOS_BUILD_TABLE_PRE(38, 0x3000, true); - - t->interface_type = info->interface_type; - t->ipmi_spec_revision = ((info->ipmi_spec_major_revision << 4) - | info->ipmi_spec_minor_revision); - t->i2c_slave_address = info->i2c_slave_address; - t->nv_storage_device_address = 0; - - assert(info->ipmi_spec_minor_revision <= 15); - assert(info->ipmi_spec_major_revision <= 15); - - /* or 1 to set it to I/O space */ - switch (info->memspace) { - case IPMI_MEMSPACE_IO: - baseaddr |= 1; - break; - case IPMI_MEMSPACE_MEM32: - case IPMI_MEMSPACE_MEM64: - break; - case IPMI_MEMSPACE_SMBUS: - baseaddr <<= 1; - break; - } - - t->base_address = cpu_to_le64(baseaddr); - - t->base_address_modifier = 0; - if (info->irq_type == IPMI_LEVEL_IRQ) { - t->base_address_modifier |= 1; - } - switch (info->register_spacing) { - case 1: - break; - case 4: - t->base_address_modifier |= 1 << 6; - break; - case 16: - t->base_address_modifier |= 2 << 6; - break; - default: - error_report("IPMI register spacing %d is not compatible with" - " SMBIOS, ignoring this entry.", info->register_spacing); - return; - } - t->interrupt_number = info->interrupt_number; - - SMBIOS_BUILD_TABLE_POST; -} - -static void smbios_add_ipmi_devices(BusState *bus) -{ - BusChild *kid; - - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - Object *obj = object_dynamic_cast(OBJECT(dev), TYPE_IPMI_INTERFACE); - BusState *childbus; - - if (obj) { - IPMIInterface *ii; - IPMIInterfaceClass *iic; - IPMIFwInfo info; - - ii = IPMI_INTERFACE(obj); - iic = IPMI_INTERFACE_GET_CLASS(obj); - memset(&info, 0, sizeof(info)); - iic->get_fwinfo(ii, &info); - smbios_build_one_type_38(&info); - continue; - } - - QLIST_FOREACH(childbus, &dev->child_bus, sibling) { - smbios_add_ipmi_devices(childbus); - } - } -} - -void smbios_build_type_38_table(void) -{ - BusState *bus; - - bus = sysbus_get_default(); - if (bus) { - smbios_add_ipmi_devices(bus); - } -} diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index 6e1647841..dbae41f3a 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -171,11 +171,7 @@ static void leon3_generic_hw_init(MachineState *machine) } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size = get_image_size(filename); - } else { - bios_size = -1; - } + bios_size = get_image_size(filename); if (bios_size > prom_size) { fprintf(stderr, "qemu: could not load prom '%s': file too big\n", diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 478fda820..7bfc00abc 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -1000,7 +1000,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus); slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[14], - !machine->enable_graphics, ESCC_CLOCK, 1); + display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1); /* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */ escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15], diff --git a/hw/sparc/trace-events b/hw/sparc/trace-events deleted file mode 100644 index 30fb0373e..000000000 --- a/hw/sparc/trace-events +++ /dev/null @@ -1,11 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/sparc/sun4m.c -sun4m_cpu_interrupt(unsigned int level) "Set CPU IRQ %d" -sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d" -sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d" -sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d" - -# hw/sparc/leon3.c -leon3_set_irq(int intno) "Set CPU IRQ %d" -leon3_reset_irq(int intno) "Reset CPU IRQ %d" diff --git a/hw/ssi/Makefile.objs b/hw/ssi/Makefile.objs index c79a8dcd8..9555825ac 100644 --- a/hw/ssi/Makefile.objs +++ b/hw/ssi/Makefile.objs @@ -2,7 +2,5 @@ common-obj-$(CONFIG_PL022) += pl022.o common-obj-$(CONFIG_SSI) += ssi.o common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o -common-obj-$(CONFIG_ASPEED_SOC) += aspeed_smc.o obj-$(CONFIG_OMAP) += omap_spi.o -obj-$(CONFIG_IMX) += imx_spi.o diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c deleted file mode 100644 index d319e04a2..000000000 --- a/hw/ssi/aspeed_smc.c +++ /dev/null @@ -1,469 +0,0 @@ -/* - * ASPEED AST2400 SMC Controller (SPI Flash Only) - * - * Copyright (C) 2016 IBM Corp. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "sysemu/sysemu.h" -#include "qemu/log.h" -#include "include/qemu/error-report.h" -#include "exec/address-spaces.h" - -#include "hw/ssi/aspeed_smc.h" - -/* CE Type Setting Register */ -#define R_CONF (0x00 / 4) -#define CONF_LEGACY_DISABLE (1 << 31) -#define CONF_ENABLE_W4 20 -#define CONF_ENABLE_W3 19 -#define CONF_ENABLE_W2 18 -#define CONF_ENABLE_W1 17 -#define CONF_ENABLE_W0 16 -#define CONF_FLASH_TYPE4 9 -#define CONF_FLASH_TYPE3 7 -#define CONF_FLASH_TYPE2 5 -#define CONF_FLASH_TYPE1 3 -#define CONF_FLASH_TYPE0 1 - -/* CE Control Register */ -#define R_CE_CTRL (0x04 / 4) -#define CTRL_EXTENDED4 4 /* 32 bit addressing for SPI */ -#define CTRL_EXTENDED3 3 /* 32 bit addressing for SPI */ -#define CTRL_EXTENDED2 2 /* 32 bit addressing for SPI */ -#define CTRL_EXTENDED1 1 /* 32 bit addressing for SPI */ -#define CTRL_EXTENDED0 0 /* 32 bit addressing for SPI */ - -/* Interrupt Control and Status Register */ -#define R_INTR_CTRL (0x08 / 4) -#define INTR_CTRL_DMA_STATUS (1 << 11) -#define INTR_CTRL_CMD_ABORT_STATUS (1 << 10) -#define INTR_CTRL_WRITE_PROTECT_STATUS (1 << 9) -#define INTR_CTRL_DMA_EN (1 << 3) -#define INTR_CTRL_CMD_ABORT_EN (1 << 2) -#define INTR_CTRL_WRITE_PROTECT_EN (1 << 1) - -/* CEx Control Register */ -#define R_CTRL0 (0x10 / 4) -#define CTRL_CMD_SHIFT 16 -#define CTRL_CMD_MASK 0xff -#define CTRL_CE_STOP_ACTIVE (1 << 2) -#define CTRL_CMD_MODE_MASK 0x3 -#define CTRL_READMODE 0x0 -#define CTRL_FREADMODE 0x1 -#define CTRL_WRITEMODE 0x2 -#define CTRL_USERMODE 0x3 -#define R_CTRL1 (0x14 / 4) -#define R_CTRL2 (0x18 / 4) -#define R_CTRL3 (0x1C / 4) -#define R_CTRL4 (0x20 / 4) - -/* CEx Segment Address Register */ -#define R_SEG_ADDR0 (0x30 / 4) -#define SEG_SIZE_SHIFT 24 /* 8MB units */ -#define SEG_SIZE_MASK 0x7f -#define SEG_START_SHIFT 16 /* address bit [A29-A23] */ -#define SEG_START_MASK 0x7f -#define R_SEG_ADDR1 (0x34 / 4) -#define R_SEG_ADDR2 (0x38 / 4) -#define R_SEG_ADDR3 (0x3C / 4) -#define R_SEG_ADDR4 (0x40 / 4) - -/* Misc Control Register #1 */ -#define R_MISC_CTRL1 (0x50 / 4) - -/* Misc Control Register #2 */ -#define R_MISC_CTRL2 (0x54 / 4) - -/* DMA Control/Status Register */ -#define R_DMA_CTRL (0x80 / 4) -#define DMA_CTRL_DELAY_MASK 0xf -#define DMA_CTRL_DELAY_SHIFT 8 -#define DMA_CTRL_FREQ_MASK 0xf -#define DMA_CTRL_FREQ_SHIFT 4 -#define DMA_CTRL_MODE (1 << 3) -#define DMA_CTRL_CKSUM (1 << 2) -#define DMA_CTRL_DIR (1 << 1) -#define DMA_CTRL_EN (1 << 0) - -/* DMA Flash Side Address */ -#define R_DMA_FLASH_ADDR (0x84 / 4) - -/* DMA DRAM Side Address */ -#define R_DMA_DRAM_ADDR (0x88 / 4) - -/* DMA Length Register */ -#define R_DMA_LEN (0x8C / 4) - -/* Checksum Calculation Result */ -#define R_DMA_CHECKSUM (0x90 / 4) - -/* Misc Control Register #2 */ -#define R_TIMINGS (0x94 / 4) - -/* SPI controller registers and bits */ -#define R_SPI_CONF (0x00 / 4) -#define SPI_CONF_ENABLE_W0 0 -#define R_SPI_CTRL0 (0x4 / 4) -#define R_SPI_MISC_CTRL (0x10 / 4) -#define R_SPI_TIMINGS (0x14 / 4) - -/* - * Default segments mapping addresses and size for each slave per - * controller. These can be changed when board is initialized with the - * Segment Address Registers but they don't seem do be used on the - * field. - */ -static const AspeedSegments aspeed_segments_legacy[] = { - { 0x10000000, 32 * 1024 * 1024 }, -}; - -static const AspeedSegments aspeed_segments_fmc[] = { - { 0x20000000, 64 * 1024 * 1024 }, - { 0x24000000, 32 * 1024 * 1024 }, - { 0x26000000, 32 * 1024 * 1024 }, - { 0x28000000, 32 * 1024 * 1024 }, - { 0x2A000000, 32 * 1024 * 1024 } -}; - -static const AspeedSegments aspeed_segments_spi[] = { - { 0x30000000, 64 * 1024 * 1024 }, -}; - -static const AspeedSMCController controllers[] = { - { "aspeed.smc.smc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, - CONF_ENABLE_W0, 5, aspeed_segments_legacy, 0x6000000 }, - { "aspeed.smc.fmc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS, - CONF_ENABLE_W0, 5, aspeed_segments_fmc, 0x10000000 }, - { "aspeed.smc.spi", R_SPI_CONF, 0xff, R_SPI_CTRL0, R_SPI_TIMINGS, - SPI_CONF_ENABLE_W0, 1, aspeed_segments_spi, 0x10000000 }, -}; - -static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr, - unsigned size) -{ - qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u" - PRIx64 "\n", __func__, addr, size); - return 0; -} - -static void aspeed_smc_flash_default_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u: 0x%" - PRIx64 "\n", __func__, addr, size, data); -} - -static const MemoryRegionOps aspeed_smc_flash_default_ops = { - .read = aspeed_smc_flash_default_read, - .write = aspeed_smc_flash_default_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -static inline int aspeed_smc_flash_mode(const AspeedSMCState *s, int cs) -{ - return s->regs[s->r_ctrl0 + cs] & CTRL_CMD_MODE_MASK; -} - -static inline bool aspeed_smc_is_usermode(const AspeedSMCState *s, int cs) -{ - return aspeed_smc_flash_mode(s, cs) == CTRL_USERMODE; -} - -static inline bool aspeed_smc_is_writable(const AspeedSMCState *s, int cs) -{ - return s->regs[s->r_conf] & (1 << (s->conf_enable_w0 + cs)); -} - -static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size) -{ - AspeedSMCFlash *fl = opaque; - const AspeedSMCState *s = fl->controller; - uint64_t ret = 0; - int i; - - if (aspeed_smc_is_usermode(s, fl->id)) { - for (i = 0; i < size; i++) { - ret |= ssi_transfer(s->spi, 0x0) << (8 * i); - } - } else { - qemu_log_mask(LOG_UNIMP, "%s: usermode not implemented\n", - __func__); - ret = -1; - } - - return ret; -} - -static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data, - unsigned size) -{ - AspeedSMCFlash *fl = opaque; - const AspeedSMCState *s = fl->controller; - int i; - - if (!aspeed_smc_is_writable(s, fl->id)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: flash is not writable at 0x%" - HWADDR_PRIx "\n", __func__, addr); - return; - } - - if (!aspeed_smc_is_usermode(s, fl->id)) { - qemu_log_mask(LOG_UNIMP, "%s: usermode not implemented\n", - __func__); - return; - } - - for (i = 0; i < size; i++) { - ssi_transfer(s->spi, (data >> (8 * i)) & 0xff); - } -} - -static const MemoryRegionOps aspeed_smc_flash_ops = { - .read = aspeed_smc_flash_read, - .write = aspeed_smc_flash_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 4, - }, -}; - -static bool aspeed_smc_is_ce_stop_active(const AspeedSMCState *s, int cs) -{ - return s->regs[s->r_ctrl0 + cs] & CTRL_CE_STOP_ACTIVE; -} - -static void aspeed_smc_update_cs(const AspeedSMCState *s) -{ - int i; - - for (i = 0; i < s->num_cs; ++i) { - qemu_set_irq(s->cs_lines[i], aspeed_smc_is_ce_stop_active(s, i)); - } -} - -static void aspeed_smc_reset(DeviceState *d) -{ - AspeedSMCState *s = ASPEED_SMC(d); - int i; - - memset(s->regs, 0, sizeof s->regs); - - /* Pretend DMA is done (u-boot initialization) */ - s->regs[R_INTR_CTRL] = INTR_CTRL_DMA_STATUS; - - /* Unselect all slaves */ - for (i = 0; i < s->num_cs; ++i) { - s->regs[s->r_ctrl0 + i] |= CTRL_CE_STOP_ACTIVE; - } - - aspeed_smc_update_cs(s); -} - -static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) -{ - AspeedSMCState *s = ASPEED_SMC(opaque); - - addr >>= 2; - - if (addr >= ARRAY_SIZE(s->regs)) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Out-of-bounds read at 0x%" HWADDR_PRIx "\n", - __func__, addr); - return 0; - } - - if (addr == s->r_conf || - addr == s->r_timings || - addr == s->r_ce_ctrl || - addr == R_INTR_CTRL || - (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs)) { - return s->regs[addr]; - } else { - qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", - __func__, addr); - return 0; - } -} - -static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, - unsigned int size) -{ - AspeedSMCState *s = ASPEED_SMC(opaque); - uint32_t value = data; - - addr >>= 2; - - if (addr >= ARRAY_SIZE(s->regs)) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Out-of-bounds write at 0x%" HWADDR_PRIx "\n", - __func__, addr); - return; - } - - if (addr == s->r_conf || - addr == s->r_timings || - addr == s->r_ce_ctrl) { - s->regs[addr] = value; - } else if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) { - s->regs[addr] = value; - aspeed_smc_update_cs(s); - } else { - qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", - __func__, addr); - return; - } -} - -static const MemoryRegionOps aspeed_smc_ops = { - .read = aspeed_smc_read, - .write = aspeed_smc_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid.unaligned = true, -}; - -static void aspeed_smc_realize(DeviceState *dev, Error **errp) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - AspeedSMCState *s = ASPEED_SMC(dev); - AspeedSMCClass *mc = ASPEED_SMC_GET_CLASS(s); - int i; - char name[32]; - hwaddr offset = 0; - - s->ctrl = mc->ctrl; - - /* keep a copy under AspeedSMCState to speed up accesses */ - s->r_conf = s->ctrl->r_conf; - s->r_ce_ctrl = s->ctrl->r_ce_ctrl; - s->r_ctrl0 = s->ctrl->r_ctrl0; - s->r_timings = s->ctrl->r_timings; - s->conf_enable_w0 = s->ctrl->conf_enable_w0; - - /* Enforce some real HW limits */ - if (s->num_cs > s->ctrl->max_slaves) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: num_cs cannot exceed: %d\n", - __func__, s->ctrl->max_slaves); - s->num_cs = s->ctrl->max_slaves; - } - - s->spi = ssi_create_bus(dev, "spi"); - - /* Setup cs_lines for slaves */ - sysbus_init_irq(sbd, &s->irq); - s->cs_lines = g_new0(qemu_irq, s->num_cs); - ssi_auto_connect_slaves(dev, s->cs_lines, s->spi); - - for (i = 0; i < s->num_cs; ++i) { - sysbus_init_irq(sbd, &s->cs_lines[i]); - } - - aspeed_smc_reset(dev); - - memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_ops, s, - s->ctrl->name, ASPEED_SMC_R_MAX * 4); - sysbus_init_mmio(sbd, &s->mmio); - - /* - * Memory region where flash modules are remapped - */ - snprintf(name, sizeof(name), "%s.flash", s->ctrl->name); - - memory_region_init_io(&s->mmio_flash, OBJECT(s), - &aspeed_smc_flash_default_ops, s, name, - s->ctrl->mapping_window_size); - sysbus_init_mmio(sbd, &s->mmio_flash); - - s->flashes = g_new0(AspeedSMCFlash, s->num_cs); - - for (i = 0; i < s->num_cs; ++i) { - AspeedSMCFlash *fl = &s->flashes[i]; - - snprintf(name, sizeof(name), "%s.%d", s->ctrl->name, i); - - fl->id = i; - fl->controller = s; - fl->size = s->ctrl->segments[i].size; - memory_region_init_io(&fl->mmio, OBJECT(s), &aspeed_smc_flash_ops, - fl, name, fl->size); - memory_region_add_subregion(&s->mmio_flash, offset, &fl->mmio); - offset += fl->size; - } -} - -static const VMStateDescription vmstate_aspeed_smc = { - .name = "aspeed.smc", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property aspeed_smc_properties[] = { - DEFINE_PROP_UINT32("num-cs", AspeedSMCState, num_cs, 1), - DEFINE_PROP_END_OF_LIST(), -}; - -static void aspeed_smc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - AspeedSMCClass *mc = ASPEED_SMC_CLASS(klass); - - dc->realize = aspeed_smc_realize; - dc->reset = aspeed_smc_reset; - dc->props = aspeed_smc_properties; - dc->vmsd = &vmstate_aspeed_smc; - mc->ctrl = data; -} - -static const TypeInfo aspeed_smc_info = { - .name = TYPE_ASPEED_SMC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(AspeedSMCState), - .class_size = sizeof(AspeedSMCClass), - .abstract = true, -}; - -static void aspeed_smc_register_types(void) -{ - int i; - - type_register_static(&aspeed_smc_info); - for (i = 0; i < ARRAY_SIZE(controllers); ++i) { - TypeInfo ti = { - .name = controllers[i].name, - .parent = TYPE_ASPEED_SMC, - .class_init = aspeed_smc_class_init, - .class_data = (void *)&controllers[i], - }; - type_register(&ti); - } -} - -type_init(aspeed_smc_register_types) diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c deleted file mode 100644 index 422619981..000000000 --- a/hw/ssi/imx_spi.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * IMX SPI Controller - * - * Copyright (c) 2016 Jean-Christophe Dubois <jcd@tribudubois.net> - * - * 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/ssi/imx_spi.h" -#include "sysemu/sysemu.h" -#include "qemu/log.h" - -#ifndef DEBUG_IMX_SPI -#define DEBUG_IMX_SPI 0 -#endif - -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX_SPI) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_SPI, \ - __func__, ##args); \ - } \ - } while (0) - -static char const *imx_spi_reg_name(uint32_t reg) -{ - static char unknown[20]; - - switch (reg) { - case ECSPI_RXDATA: - return "ECSPI_RXDATA"; - case ECSPI_TXDATA: - return "ECSPI_TXDATA"; - case ECSPI_CONREG: - return "ECSPI_CONREG"; - case ECSPI_CONFIGREG: - return "ECSPI_CONFIGREG"; - case ECSPI_INTREG: - return "ECSPI_INTREG"; - case ECSPI_DMAREG: - return "ECSPI_DMAREG"; - case ECSPI_STATREG: - return "ECSPI_STATREG"; - case ECSPI_PERIODREG: - return "ECSPI_PERIODREG"; - case ECSPI_TESTREG: - return "ECSPI_TESTREG"; - case ECSPI_MSGDATA: - return "ECSPI_MSGDATA"; - default: - sprintf(unknown, "%d ?", reg); - return unknown; - } -} - -static const VMStateDescription vmstate_imx_spi = { - .name = TYPE_IMX_SPI, - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_FIFO32(tx_fifo, IMXSPIState), - VMSTATE_FIFO32(rx_fifo, IMXSPIState), - VMSTATE_INT16(burst_length, IMXSPIState), - VMSTATE_UINT32_ARRAY(regs, IMXSPIState, ECSPI_MAX), - VMSTATE_END_OF_LIST() - }, -}; - -static void imx_spi_txfifo_reset(IMXSPIState *s) -{ - fifo32_reset(&s->tx_fifo); - s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TE; - s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TF; -} - -static void imx_spi_rxfifo_reset(IMXSPIState *s) -{ - fifo32_reset(&s->rx_fifo); - s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RR; - s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RF; - s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RO; -} - -static void imx_spi_update_irq(IMXSPIState *s) -{ - int level; - - if (fifo32_is_empty(&s->rx_fifo)) { - s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RR; - } else { - s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RR; - } - - if (fifo32_is_full(&s->rx_fifo)) { - s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RF; - } else { - s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_RF; - } - - if (fifo32_is_empty(&s->tx_fifo)) { - s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TE; - } else { - s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TE; - } - - if (fifo32_is_full(&s->tx_fifo)) { - s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TF; - } else { - s->regs[ECSPI_STATREG] &= ~ECSPI_STATREG_TF; - } - - level = s->regs[ECSPI_STATREG] & s->regs[ECSPI_INTREG] ? 1 : 0; - - qemu_set_irq(s->irq, level); - - DPRINTF("IRQ level is %d\n", level); -} - -static uint8_t imx_spi_selected_channel(IMXSPIState *s) -{ - return EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_CHANNEL_SELECT); -} - -static uint32_t imx_spi_burst_length(IMXSPIState *s) -{ - return EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_BURST_LENGTH) + 1; -} - -static bool imx_spi_is_enabled(IMXSPIState *s) -{ - return s->regs[ECSPI_CONREG] & ECSPI_CONREG_EN; -} - -static bool imx_spi_channel_is_master(IMXSPIState *s) -{ - uint8_t mode = EXTRACT(s->regs[ECSPI_CONREG], ECSPI_CONREG_CHANNEL_MODE); - - return (mode & (1 << imx_spi_selected_channel(s))) ? true : false; -} - -static bool imx_spi_is_multiple_master_burst(IMXSPIState *s) -{ - uint8_t wave = EXTRACT(s->regs[ECSPI_CONFIGREG], ECSPI_CONFIGREG_SS_CTL); - - return imx_spi_channel_is_master(s) && - !(s->regs[ECSPI_CONREG] & ECSPI_CONREG_SMC) && - ((wave & (1 << imx_spi_selected_channel(s))) ? true : false); -} - -static void imx_spi_flush_txfifo(IMXSPIState *s) -{ - uint32_t tx; - uint32_t rx; - - DPRINTF("Begin: TX Fifo Size = %d, RX Fifo Size = %d\n", - fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo)); - - while (!fifo32_is_empty(&s->tx_fifo)) { - int tx_burst = 0; - int index = 0; - - if (s->burst_length <= 0) { - s->burst_length = imx_spi_burst_length(s); - - DPRINTF("Burst length = %d\n", s->burst_length); - - if (imx_spi_is_multiple_master_burst(s)) { - s->regs[ECSPI_CONREG] |= ECSPI_CONREG_XCH; - } - } - - tx = fifo32_pop(&s->tx_fifo); - - DPRINTF("data tx:0x%08x\n", tx); - - tx_burst = MIN(s->burst_length, 32); - - rx = 0; - - while (tx_burst) { - uint8_t byte = tx & 0xff; - - DPRINTF("writing 0x%02x\n", (uint32_t)byte); - - /* We need to write one byte at a time */ - byte = ssi_transfer(s->bus, byte); - - DPRINTF("0x%02x read\n", (uint32_t)byte); - - tx = tx >> 8; - rx |= (byte << (index * 8)); - - /* Remove 8 bits from the actual burst */ - tx_burst -= 8; - s->burst_length -= 8; - index++; - } - - DPRINTF("data rx:0x%08x\n", rx); - - if (fifo32_is_full(&s->rx_fifo)) { - s->regs[ECSPI_STATREG] |= ECSPI_STATREG_RO; - } else { - fifo32_push(&s->rx_fifo, (uint8_t)rx); - } - - if (s->burst_length <= 0) { - s->regs[ECSPI_CONREG] &= ~ECSPI_CONREG_XCH; - - if (!imx_spi_is_multiple_master_burst(s)) { - s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TC; - break; - } - } - } - - if (fifo32_is_empty(&s->tx_fifo)) { - s->regs[ECSPI_STATREG] |= ECSPI_STATREG_TC; - } - - /* TODO: We should also use TDR and RDR bits */ - - DPRINTF("End: TX Fifo Size = %d, RX Fifo Size = %d\n", - fifo32_num_used(&s->tx_fifo), fifo32_num_used(&s->rx_fifo)); -} - -static void imx_spi_reset(DeviceState *dev) -{ - IMXSPIState *s = IMX_SPI(dev); - - DPRINTF("\n"); - - memset(s->regs, 0, sizeof(s->regs)); - - s->regs[ECSPI_STATREG] = 0x00000003; - - imx_spi_rxfifo_reset(s); - imx_spi_txfifo_reset(s); - - imx_spi_update_irq(s); - - s->burst_length = 0; -} - -static uint64_t imx_spi_read(void *opaque, hwaddr offset, unsigned size) -{ - uint32_t value = 0; - IMXSPIState *s = opaque; - uint32_t index = offset >> 2; - - if (index >= ECSPI_MAX) { - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX_SPI, __func__, offset); - return 0; - } - - switch (index) { - case ECSPI_RXDATA: - if (!imx_spi_is_enabled(s)) { - value = 0; - } else if (fifo32_is_empty(&s->rx_fifo)) { - /* value is undefined */ - value = 0xdeadbeef; - } else { - /* read from the RX FIFO */ - value = fifo32_pop(&s->rx_fifo); - } - - break; - case ECSPI_TXDATA: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read from TX FIFO\n", - TYPE_IMX_SPI, __func__); - - /* Reading from TXDATA gives 0 */ - - break; - case ECSPI_MSGDATA: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read from MSG FIFO\n", - TYPE_IMX_SPI, __func__); - - /* Reading from MSGDATA gives 0 */ - - break; - default: - value = s->regs[index]; - break; - } - - DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx_spi_reg_name(index), value); - - imx_spi_update_irq(s); - - return (uint64_t)value; -} - -static void imx_spi_write(void *opaque, hwaddr offset, uint64_t value, - unsigned size) -{ - IMXSPIState *s = opaque; - uint32_t index = offset >> 2; - uint32_t change_mask; - - if (index >= ECSPI_MAX) { - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX_SPI, __func__, offset); - return; - } - - DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_spi_reg_name(index), - (uint32_t)value); - - change_mask = s->regs[index] ^ value; - - switch (index) { - case ECSPI_RXDATA: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to write to RX FIFO\n", - 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; - } else if (fifo32_is_full(&s->tx_fifo)) { - /* Ignore writes if queue is full */ - break; - } - - fifo32_push(&s->tx_fifo, (uint32_t)value); - - if (imx_spi_channel_is_master(s) && - (s->regs[ECSPI_CONREG] & ECSPI_CONREG_SMC)) { - /* - * Start emitting if current channel is master and SMC bit is - * set. - */ - imx_spi_flush_txfifo(s); - } - - break; - case ECSPI_STATREG: - /* the RO and TC bits are write-one-to-clear */ - value &= ECSPI_STATREG_RO | ECSPI_STATREG_TC; - s->regs[ECSPI_STATREG] &= ~value; - - break; - case ECSPI_CONREG: - s->regs[ECSPI_CONREG] = value; - - if (!imx_spi_is_enabled(s)) { - /* device is disabled, so this is a reset */ - imx_spi_reset(DEVICE(s)); - return; - } - - if (imx_spi_channel_is_master(s)) { - int i; - - /* We are in master mode */ - - for (i = 0; i < 4; i++) { - qemu_set_irq(s->cs_lines[i], - i == imx_spi_selected_channel(s) ? 0 : 1); - } - - if ((value & change_mask & ECSPI_CONREG_SMC) && - !fifo32_is_empty(&s->tx_fifo)) { - /* SMC bit is set and TX FIFO has some slots filled in */ - imx_spi_flush_txfifo(s); - } else if ((value & change_mask & ECSPI_CONREG_XCH) && - !(value & ECSPI_CONREG_SMC)) { - /* This is a request to start emitting */ - imx_spi_flush_txfifo(s); - } - } - - break; - default: - s->regs[index] = value; - - break; - } - - imx_spi_update_irq(s); -} - -static const struct MemoryRegionOps imx_spi_ops = { - .read = imx_spi_read, - .write = imx_spi_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - /* - * Our device would not work correctly if the guest was doing - * unaligned access. This might not be a limitation on the real - * device but in practice there is no reason for a guest to access - * this device unaligned. - */ - .min_access_size = 4, - .max_access_size = 4, - .unaligned = false, - }, -}; - -static void imx_spi_realize(DeviceState *dev, Error **errp) -{ - IMXSPIState *s = IMX_SPI(dev); - int i; - - s->bus = ssi_create_bus(dev, "spi"); - - memory_region_init_io(&s->iomem, OBJECT(dev), &imx_spi_ops, s, - TYPE_IMX_SPI, 0x1000); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); - sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); - - ssi_auto_connect_slaves(dev, s->cs_lines, s->bus); - - for (i = 0; i < 4; ++i) { - sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]); - } - - s->burst_length = 0; - - fifo32_create(&s->tx_fifo, ECSPI_FIFO_SIZE); - fifo32_create(&s->rx_fifo, ECSPI_FIFO_SIZE); -} - -static void imx_spi_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = imx_spi_realize; - dc->vmsd = &vmstate_imx_spi; - dc->reset = imx_spi_reset; - dc->desc = "i.MX SPI Controller"; -} - -static const TypeInfo imx_spi_info = { - .name = TYPE_IMX_SPI, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IMXSPIState), - .class_init = imx_spi_class_init, -}; - -static void imx_spi_register_types(void) -{ - type_register_static(&imx_spi_info); -} - -type_init(imx_spi_register_types) diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c index c1368018e..564a0d36e 100644 --- a/hw/ssi/pl022.c +++ b/hw/ssi/pl022.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "hw/ssi/ssi.h" -#include "qemu/log.h" //#define DEBUG_PL022 1 diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 7eaaf565f..9791c0d94 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -54,7 +54,7 @@ static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val) return 0; } -static void ssi_slave_realize(DeviceState *dev, Error **errp) +static int ssi_slave_init(DeviceState *dev) { SSISlave *s = SSI_SLAVE(dev); SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s); @@ -64,7 +64,7 @@ static void ssi_slave_realize(DeviceState *dev, Error **errp) qdev_init_gpio_in_named(dev, ssi_cs_default, SSI_GPIO_CS, 1); } - ssc->realize(s, errp); + return ssc->init(s); } static void ssi_slave_class_init(ObjectClass *klass, void *data) @@ -72,7 +72,7 @@ static void ssi_slave_class_init(ObjectClass *klass, void *data) SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = ssi_slave_realize; + dc->init = ssi_slave_init; dc->bus_type = TYPE_SSI_BUS; if (!ssc->transfer_raw) { ssc->transfer_raw = ssi_transfer_raw_default; diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index 7ba8c23c7..003c14fa2 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -26,7 +26,6 @@ obj-$(CONFIG_OMAP) += omap_synctimer.o obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o obj-$(CONFIG_SH4) += sh_timer.o obj-$(CONFIG_DIGIC) += digic-timer.o -obj-$(CONFIG_MIPS_CPS) += mips_gictimer.o obj-$(CONFIG_MC146818RTC) += mc146818rtc.o diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c index 3385e5dc3..51cdc98f3 100644 --- a/hw/timer/allwinner-a10-pit.c +++ b/hw/timer/allwinner-a10-pit.c @@ -19,7 +19,6 @@ #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "hw/timer/allwinner-a10-pit.h" -#include "qemu/log.h" static void a10_pit_update_irq(AwA10PITState *s) { diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index 111a16db3..f1ede5f53 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -14,7 +14,6 @@ #include "hw/qdev.h" #include "hw/ptimer.h" #include "qemu/main-loop.h" -#include "qemu/log.h" /* Common timer implementation. */ diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index 9b70ee09b..ebec35935 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -10,12 +10,13 @@ */ #include "qemu/osdep.h" +#include "hw/ptimer.h" #include "hw/sysbus.h" #include "hw/timer/aspeed_timer.h" #include "qemu-common.h" #include "qemu/bitops.h" +#include "qemu/main-loop.h" #include "qemu/timer.h" -#include "qemu/log.h" #include "trace.h" #define TIMER_NR_REGS 4 @@ -75,96 +76,21 @@ static inline bool timer_can_pulse(AspeedTimer *t) return t->id >= TIMER_FIRST_CAP_PULSE; } -static inline bool timer_external_clock(AspeedTimer *t) -{ - return timer_ctrl_status(t, op_external_clock); -} - -static uint32_t clock_rates[] = { TIMER_CLOCK_APB_HZ, TIMER_CLOCK_EXT_HZ }; - -static inline uint32_t calculate_rate(struct AspeedTimer *t) -{ - return clock_rates[timer_external_clock(t)]; -} - -static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t now_ns) -{ - uint64_t delta_ns = now_ns - MIN(now_ns, t->start); - uint32_t rate = calculate_rate(t); - uint64_t ticks = muldiv64(delta_ns, rate, NANOSECONDS_PER_SECOND); - - return t->reload - MIN(t->reload, ticks); -} - -static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks) -{ - uint64_t delta_ns; - uint64_t delta_ticks; - - delta_ticks = t->reload - MIN(t->reload, ticks); - delta_ns = muldiv64(delta_ticks, NANOSECONDS_PER_SECOND, calculate_rate(t)); - - return t->start + delta_ns; -} - -static uint64_t calculate_next(struct AspeedTimer *t) -{ - uint64_t next = 0; - uint32_t rate = calculate_rate(t); - - while (!next) { - /* We don't know the relationship between the values in the match - * registers, so sort using MAX/MIN/zero. We sort in that order as the - * timer counts down to zero. */ - uint64_t seq[] = { - calculate_time(t, MAX(t->match[0], t->match[1])), - calculate_time(t, MIN(t->match[0], t->match[1])), - calculate_time(t, 0), - }; - uint64_t reload_ns; - uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - - if (now < seq[0]) { - next = seq[0]; - } else if (now < seq[1]) { - next = seq[1]; - } else if (now < seq[2]) { - next = seq[2]; - } else { - reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate); - t->start = now - ((now - t->start) % reload_ns); - } - } - - return next; -} - static void aspeed_timer_expire(void *opaque) { AspeedTimer *t = opaque; - bool interrupt = false; - uint32_t ticks; - - if (!timer_enabled(t)) { - return; - } - - ticks = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); - if (!ticks) { - interrupt = timer_overflow_interrupt(t) || !t->match[0] || !t->match[1]; - } else if (ticks <= MIN(t->match[0], t->match[1])) { - interrupt = true; - } else if (ticks <= MAX(t->match[0], t->match[1])) { - interrupt = true; - } - - if (interrupt) { + /* Only support interrupts on match values of zero for the moment - this is + * sufficient to boot an aspeed_defconfig Linux kernel. + * + * TODO: matching on arbitrary values (see e.g. hw/timer/a9gtimer.c) + */ + bool match = !(t->match[0] && t->match[1]); + bool interrupt = timer_overflow_interrupt(t) || match; + if (timer_enabled(t) && interrupt) { t->level = !t->level; qemu_set_irq(t->irq, t->level); } - - timer_mod(&t->timer, calculate_next(t)); } static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg) @@ -173,7 +99,7 @@ static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg) switch (reg) { case TIMER_REG_STATUS: - value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); + value = ptimer_get_count(t->timer); break; case TIMER_REG_RELOAD: value = t->reload; @@ -233,22 +159,24 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg, switch (reg) { case TIMER_REG_STATUS: if (timer_enabled(t)) { - uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now); - uint32_t rate = calculate_rate(t); - - t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate); - timer_mod(&t->timer, calculate_next(t)); + ptimer_set_count(t->timer, value); } break; case TIMER_REG_RELOAD: t->reload = value; + ptimer_set_limit(t->timer, value, 1); break; case TIMER_REG_MATCH_FIRST: case TIMER_REG_MATCH_SECOND: - t->match[reg - 2] = value; - if (timer_enabled(t)) { - timer_mod(&t->timer, calculate_next(t)); + if (value) { + /* Non-zero match values are unsupported. As such an interrupt will + * always be triggered when the timer reaches zero even if the + * overflow interrupt control bit is clear. + */ + qemu_log_mask(LOG_UNIMP, "%s: Match value unsupported by device: " + "0x%" PRIx32 "\n", __func__, value); + } else { + t->match[reg - 2] = value; } break; default: @@ -267,16 +195,21 @@ static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable) { trace_aspeed_timer_ctrl_enable(t->id, enable); if (enable) { - t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - timer_mod(&t->timer, calculate_next(t)); + ptimer_run(t->timer, 0); } else { - timer_del(&t->timer); + ptimer_stop(t->timer); + ptimer_set_limit(t->timer, t->reload, 1); } } static void aspeed_timer_ctrl_external_clock(AspeedTimer *t, bool enable) { trace_aspeed_timer_ctrl_external_clock(t->id, enable); + if (enable) { + ptimer_set_freq(t->timer, TIMER_CLOCK_EXT_HZ); + } else { + ptimer_set_freq(t->timer, TIMER_CLOCK_APB_HZ); + } } static void aspeed_timer_ctrl_overflow_interrupt(AspeedTimer *t, bool enable) @@ -417,10 +350,12 @@ static const MemoryRegionOps aspeed_timer_ops = { static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id) { + QEMUBH *bh; AspeedTimer *t = &s->timers[id]; t->id = id; - timer_init_ns(&t->timer, QEMU_CLOCK_VIRTUAL, aspeed_timer_expire, t); + bh = qemu_bh_new(aspeed_timer_expire, t); + t->timer = ptimer_init(bh); } static void aspeed_timer_realize(DeviceState *dev, Error **errp) @@ -463,12 +398,12 @@ static void aspeed_timer_reset(DeviceState *dev) static const VMStateDescription vmstate_aspeed_timer = { .name = "aspeed.timer", - .version_id = 2, - .minimum_version_id = 2, + .version_id = 1, + .minimum_version_id = 1, .fields = (VMStateField[]) { VMSTATE_UINT8(id, AspeedTimer), VMSTATE_INT32(level, AspeedTimer), - VMSTATE_TIMER(timer, AspeedTimer), + VMSTATE_PTIMER(timer, AspeedTimer), VMSTATE_UINT32(reload, AspeedTimer), VMSTATE_UINT32_ARRAY(match, AspeedTimer, 2), VMSTATE_END_OF_LIST() @@ -483,7 +418,7 @@ static const VMStateDescription vmstate_aspeed_timer_state = { VMSTATE_UINT32(ctrl, AspeedTimerCtrlState), VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState), VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState, - ASPEED_TIMER_NR_TIMERS, 2, vmstate_aspeed_timer, + ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer, AspeedTimer), VMSTATE_END_OF_LIST() } diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index 0f21faf87..5b97e1e1a 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -30,7 +30,6 @@ #include "hw/sysbus.h" #include "hw/ptimer.h" #include "qemu/main-loop.h" -#include "qemu/log.h" #include "hw/timer/digic-timer.h" diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index eddf3481e..f5836e21f 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -16,7 +16,6 @@ #include "hw/timer/imx_epit.h" #include "hw/misc/imx_ccm.h" #include "qemu/main-loop.h" -#include "qemu/log.h" #ifndef DEBUG_IMX_EPIT #define DEBUG_IMX_EPIT 0 diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 82bc73cb8..ab2e213a1 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -14,8 +14,8 @@ #include "qemu/osdep.h" #include "hw/timer/imx_gpt.h" +#include "hw/misc/imx_ccm.h" #include "qemu/main-loop.h" -#include "qemu/log.h" #ifndef DEBUG_IMX_GPT #define DEBUG_IMX_GPT 0 @@ -80,18 +80,7 @@ static const VMStateDescription vmstate_imx_timer_gpt = { } }; -static const IMXClk imx25_gpt_clocks[] = { - CLK_NONE, /* 000 No clock source */ - CLK_IPG, /* 001 ipg_clk, 532MHz*/ - CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ - CLK_NONE, /* 011 not defined */ - CLK_32k, /* 100 ipg_clk_32k */ - CLK_32k, /* 101 ipg_clk_32k */ - CLK_32k, /* 110 ipg_clk_32k */ - CLK_32k, /* 111 ipg_clk_32k */ -}; - -static const IMXClk imx31_gpt_clocks[] = { +static const IMXClk imx_gpt_clocks[] = { CLK_NONE, /* 000 No clock source */ CLK_IPG, /* 001 ipg_clk, 532MHz*/ CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ @@ -102,23 +91,12 @@ static const IMXClk imx31_gpt_clocks[] = { CLK_NONE, /* 111 not defined */ }; -static const IMXClk imx6_gpt_clocks[] = { - CLK_NONE, /* 000 No clock source */ - CLK_IPG, /* 001 ipg_clk, 532MHz*/ - CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */ - CLK_EXT, /* 011 External clock */ - CLK_32k, /* 100 ipg_clk_32k */ - CLK_HIGH_DIV, /* 101 reference clock / 8 */ - CLK_NONE, /* 110 not defined */ - CLK_HIGH, /* 111 reference clock */ -}; - static void imx_gpt_set_freq(IMXGPTState *s) { uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); s->freq = imx_ccm_get_clock_frequency(s->ccm, - s->clocks[clksrc]) / (1 + s->pr); + imx_gpt_clocks[clksrc]) / (1 + s->pr); DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq); @@ -474,52 +452,16 @@ static void imx_gpt_class_init(ObjectClass *klass, void *data) dc->desc = "i.MX general timer"; } -static void imx25_gpt_init(Object *obj) -{ - IMXGPTState *s = IMX_GPT(obj); - - s->clocks = imx25_gpt_clocks; -} - -static void imx31_gpt_init(Object *obj) -{ - IMXGPTState *s = IMX_GPT(obj); - - s->clocks = imx31_gpt_clocks; -} - -static void imx6_gpt_init(Object *obj) -{ - IMXGPTState *s = IMX_GPT(obj); - - s->clocks = imx6_gpt_clocks; -} - -static const TypeInfo imx25_gpt_info = { - .name = TYPE_IMX25_GPT, +static const TypeInfo imx_gpt_info = { + .name = TYPE_IMX_GPT, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IMXGPTState), - .instance_init = imx25_gpt_init, .class_init = imx_gpt_class_init, }; -static const TypeInfo imx31_gpt_info = { - .name = TYPE_IMX31_GPT, - .parent = TYPE_IMX25_GPT, - .instance_init = imx31_gpt_init, -}; - -static const TypeInfo imx6_gpt_info = { - .name = TYPE_IMX6_GPT, - .parent = TYPE_IMX25_GPT, - .instance_init = imx6_gpt_init, -}; - static void imx_gpt_register_types(void) { - type_register_static(&imx25_gpt_info); - type_register_static(&imx31_gpt_info); - type_register_static(&imx6_gpt_info); + type_register_static(&imx_gpt_info); } type_init(imx_gpt_register_types) diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c index e45a65bb9..3198355aa 100644 --- a/hw/timer/lm32_timer.c +++ b/hw/timer/lm32_timer.c @@ -176,26 +176,21 @@ static void timer_reset(DeviceState *d) ptimer_stop(s->ptimer); } -static void lm32_timer_init(Object *obj) +static int lm32_timer_init(SysBusDevice *dev) { - LM32TimerState *s = LM32_TIMER(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + LM32TimerState *s = LM32_TIMER(dev); sysbus_init_irq(dev, &s->irq); s->bh = qemu_bh_new(timer_hit, s); s->ptimer = ptimer_init(s->bh); + ptimer_set_freq(s->ptimer, s->freq_hz); - memory_region_init_io(&s->iomem, obj, &timer_ops, s, + memory_region_init_io(&s->iomem, OBJECT(s), &timer_ops, s, "timer", R_MAX * 4); sysbus_init_mmio(dev, &s->iomem); -} -static void lm32_timer_realize(DeviceState *dev, Error **errp) -{ - LM32TimerState *s = LM32_TIMER(dev); - - ptimer_set_freq(s->ptimer, s->freq_hz); + return 0; } static const VMStateDescription vmstate_lm32_timer = { @@ -218,8 +213,9 @@ static Property lm32_timer_properties[] = { static void lm32_timer_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - dc->realize = lm32_timer_realize; + k->init = lm32_timer_init; dc->reset = timer_reset; dc->vmsd = &vmstate_lm32_timer; dc->props = lm32_timer_properties; @@ -229,7 +225,6 @@ static const TypeInfo lm32_timer_info = { .name = TYPE_LM32_TIMER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(LM32TimerState), - .instance_init = lm32_timer_init, .class_init = lm32_timer_class_init, }; diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index ea625f25c..2ac0fd3e4 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "config-target.h" #include "qemu/cutils.h" #include "qemu/bcd.h" #include "hw/hw.h" @@ -105,10 +106,12 @@ static inline bool rtc_running(RTCState *s) static uint64_t get_guest_rtc_ns(RTCState *s) { + uint64_t guest_rtc; uint64_t guest_clock = qemu_clock_get_ns(rtc_clock); - return s->base_rtc * NANOSECONDS_PER_SECOND + + guest_rtc = s->base_rtc * NANOSECONDS_PER_SECOND + guest_clock - s->last_update + s->offset; + return guest_rtc; } #ifdef TARGET_I386 @@ -906,8 +909,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) object_property_add_alias(qdev_get_machine(), "rtc-time", OBJECT(s), "date", NULL); - - qdev_init_gpio_out(dev, &s->irq, 1); } ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) @@ -922,9 +923,9 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) qdev_prop_set_int32(dev, "base_year", base_year); qdev_init_nofail(dev); if (intercept_irq) { - qdev_connect_gpio_out(dev, 0, intercept_irq); + s->irq = intercept_irq; } else { - isa_connect_gpio_out(isadev, 0, RTC_ISA_IRQ); + isa_init_irq(isadev, &s->irq, RTC_ISA_IRQ); } QLIST_INSERT_HEAD(&rtc_devices, s, link); diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c index 21948328c..5f2948037 100644 --- a/hw/timer/milkymist-sysctl.c +++ b/hw/timer/milkymist-sysctl.c @@ -18,7 +18,7 @@ * * * Specification available at: - * http://milkymist.walle.cc/socdoc/sysctl.pdf + * http://www.milkymist.org/socdoc/sysctl.pdf */ #include "qemu/osdep.h" @@ -270,10 +270,9 @@ static void milkymist_sysctl_reset(DeviceState *d) s->regs[R_GPIO_IN] = s->strappings; } -static void milkymist_sysctl_init(Object *obj) +static int milkymist_sysctl_init(SysBusDevice *dev) { - MilkymistSysctlState *s = MILKYMIST_SYSCTL(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); + MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev); sysbus_init_irq(dev, &s->gpio_irq); sysbus_init_irq(dev, &s->timer0_irq); @@ -283,18 +282,14 @@ static void milkymist_sysctl_init(Object *obj) s->bh1 = qemu_bh_new(timer1_hit, s); s->ptimer0 = ptimer_init(s->bh0); s->ptimer1 = ptimer_init(s->bh1); + ptimer_set_freq(s->ptimer0, s->freq_hz); + ptimer_set_freq(s->ptimer1, s->freq_hz); - memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s, + memory_region_init_io(&s->regs_region, OBJECT(s), &sysctl_mmio_ops, s, "milkymist-sysctl", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); -} -static void milkymist_sysctl_realize(DeviceState *dev, Error **errp) -{ - MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev); - - ptimer_set_freq(s->ptimer0, s->freq_hz); - ptimer_set_freq(s->ptimer1, s->freq_hz); + return 0; } static const VMStateDescription vmstate_milkymist_sysctl = { @@ -324,8 +319,9 @@ static Property milkymist_sysctl_properties[] = { static void milkymist_sysctl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - dc->realize = milkymist_sysctl_realize; + k->init = milkymist_sysctl_init; dc->reset = milkymist_sysctl_reset; dc->vmsd = &vmstate_milkymist_sysctl; dc->props = milkymist_sysctl_properties; @@ -335,7 +331,6 @@ static const TypeInfo milkymist_sysctl_info = { .name = TYPE_MILKYMIST_SYSCTL, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(MilkymistSysctlState), - .instance_init = milkymist_sysctl_init, .class_init = milkymist_sysctl_class_init, }; diff --git a/hw/timer/mips_gictimer.c b/hw/timer/mips_gictimer.c deleted file mode 100644 index 369888947..000000000 --- a/hw/timer/mips_gictimer.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2016 Imagination Technologies - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "qemu/timer.h" -#include "hw/timer/mips_gictimer.h" - -#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */ - -static void gic_vptimer_update(MIPSGICTimerState *gictimer, - uint32_t vp_index, uint64_t now) -{ - uint64_t next; - uint32_t wait; - - wait = gictimer->vptimers[vp_index].comparelo - gictimer->sh_counterlo - - (uint32_t)(now / TIMER_PERIOD); - next = now + (uint64_t)wait * TIMER_PERIOD; - - timer_mod(gictimer->vptimers[vp_index].qtimer, next); -} - -static void gic_vptimer_expire(MIPSGICTimerState *gictimer, uint32_t vp_index, - uint64_t now) -{ - if (gictimer->countstop) { - /* timer stopped */ - return; - } - gictimer->cb(gictimer->opaque, vp_index); - gic_vptimer_update(gictimer, vp_index, now); -} - -static void gic_vptimer_cb(void *opaque) -{ - MIPSGICTimerVPState *vptimer = opaque; - MIPSGICTimerState *gictimer = vptimer->gictimer; - gic_vptimer_expire(gictimer, vptimer->vp_index, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); -} - -uint32_t mips_gictimer_get_sh_count(MIPSGICTimerState *gictimer) -{ - int i; - if (gictimer->countstop) { - return gictimer->sh_counterlo; - } else { - uint64_t now; - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - for (i = 0; i < gictimer->num_vps; i++) { - if (timer_pending(gictimer->vptimers[i].qtimer) - && timer_expired(gictimer->vptimers[i].qtimer, now)) { - /* The timer has already expired. */ - gic_vptimer_expire(gictimer, i, now); - } - } - return gictimer->sh_counterlo + (uint32_t)(now / TIMER_PERIOD); - } -} - -void mips_gictimer_store_sh_count(MIPSGICTimerState *gictimer, uint64_t count) -{ - int i; - uint64_t now; - - if (gictimer->countstop || !gictimer->vptimers[0].qtimer) { - gictimer->sh_counterlo = count; - } else { - /* Store new count register */ - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - gictimer->sh_counterlo = count - (uint32_t)(now / TIMER_PERIOD); - /* Update timer timer */ - for (i = 0; i < gictimer->num_vps; i++) { - gic_vptimer_update(gictimer, i, now); - } - } -} - -uint32_t mips_gictimer_get_vp_compare(MIPSGICTimerState *gictimer, - uint32_t vp_index) -{ - return gictimer->vptimers[vp_index].comparelo; -} - -void mips_gictimer_store_vp_compare(MIPSGICTimerState *gictimer, - uint32_t vp_index, uint64_t compare) -{ - gictimer->vptimers[vp_index].comparelo = (uint32_t) compare; - gic_vptimer_update(gictimer, vp_index, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); -} - -uint8_t mips_gictimer_get_countstop(MIPSGICTimerState *gictimer) -{ - return gictimer->countstop; -} - -void mips_gictimer_start_count(MIPSGICTimerState *gictimer) -{ - gictimer->countstop = 0; - mips_gictimer_store_sh_count(gictimer, gictimer->sh_counterlo); -} - -void mips_gictimer_stop_count(MIPSGICTimerState *gictimer) -{ - int i; - - gictimer->countstop = 1; - /* Store the current value */ - gictimer->sh_counterlo += - (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD); - for (i = 0; i < gictimer->num_vps; i++) { - timer_del(gictimer->vptimers[i].qtimer); - } -} - -MIPSGICTimerState *mips_gictimer_init(void *opaque, uint32_t nvps, - MIPSGICTimerCB *cb) -{ - int i; - MIPSGICTimerState *gictimer = g_new(MIPSGICTimerState, 1); - gictimer->vptimers = g_new(MIPSGICTimerVPState, nvps); - gictimer->countstop = 1; - gictimer->num_vps = nvps; - gictimer->opaque = opaque; - gictimer->cb = cb; - for (i = 0; i < nvps; i++) { - gictimer->vptimers[i].gictimer = gictimer; - gictimer->vptimers[i].vp_index = i; - gictimer->vptimers[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - &gic_vptimer_cb, - &gictimer->vptimers[i]); - } - return gictimer; -} diff --git a/hw/timer/omap_gptimer.c b/hw/timer/omap_gptimer.c index 5e3e8a6d7..3a4386304 100644 --- a/hw/timer/omap_gptimer.c +++ b/hw/timer/omap_gptimer.c @@ -133,8 +133,8 @@ static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer) timer_mod(timer->timer, timer->time + expires); if (timer->ce && timer->match_val >= timer->val) { - matches = muldiv64(timer->ticks_per_sec, - timer->match_val - timer->val, timer->rate); + matches = muldiv64(timer->match_val - timer->val, + timer->ticks_per_sec, timer->rate); timer_mod(timer->match, timer->time + matches); } else timer_del(timer->match); diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c index dbbeb9b16..38e0cb5ad 100644 --- a/hw/timer/pl031.c +++ b/hw/timer/pl031.c @@ -16,7 +16,6 @@ #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "qemu/cutils.h" -#include "qemu/log.h" //#define DEBUG_PL031 diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c index bf0fb288c..55dacbbe3 100644 --- a/hw/timer/stm32f2xx_timer.c +++ b/hw/timer/stm32f2xx_timer.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "hw/timer/stm32f2xx_timer.h" -#include "qemu/log.h" #ifndef STM_TIMER_ERR_DEBUG #define STM_TIMER_ERR_DEBUG 0 diff --git a/hw/timer/trace-events b/hw/timer/trace-events deleted file mode 100644 index 3495c41c1..000000000 --- a/hw/timer/trace-events +++ /dev/null @@ -1,51 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/timer/slavio_timer.c -slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "limit %"PRIx64" count %x%08x" -slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count %x%08x" -slavio_timer_mem_readl_invalid(uint64_t addr) "invalid read address %"PRIx64 -slavio_timer_mem_readl(uint64_t addr, uint32_t ret) "read %"PRIx64" = %08x" -slavio_timer_mem_writel(uint64_t addr, uint32_t val) "write %"PRIx64" = %08x" -slavio_timer_mem_writel_limit(unsigned int timer_index, uint64_t count) "processor %d user timer set to %016"PRIx64 -slavio_timer_mem_writel_counter_invalid(void) "not user timer" -slavio_timer_mem_writel_status_start(unsigned int timer_index) "processor %d user timer started" -slavio_timer_mem_writel_status_stop(unsigned int timer_index) "processor %d user timer stopped" -slavio_timer_mem_writel_mode_user(unsigned int timer_index) "processor %d changed from counter to user timer" -slavio_timer_mem_writel_mode_counter(unsigned int timer_index) "processor %d changed from user timer to counter" -slavio_timer_mem_writel_mode_invalid(void) "not system timer" -slavio_timer_mem_writel_invalid(uint64_t addr) "invalid write address %"PRIx64 - -# hw/timer/grlib_gptimer.c -grlib_gptimer_enable(int id, uint32_t count) "timer:%d set count 0x%x and run" -grlib_gptimer_disabled(int id, uint32_t config) "timer:%d Timer disable config 0x%x" -grlib_gptimer_restart(int id, uint32_t reload) "timer:%d reload val: 0x%x" -grlib_gptimer_set_scaler(uint32_t scaler, uint32_t freq) "scaler:0x%x freq: 0x%x" -grlib_gptimer_hit(int id) "timer:%d HIT" -grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" -grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" - -# hw/timer/lm32_timer.c -lm32_timer_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_timer_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_timer_hit(void) "timer hit" -lm32_timer_irq_state(int level) "irq state %d" - -# hw/timer/milkymist-sysctl.c -milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr %08x value %08x" -milkymist_sysctl_icap_write(uint32_t value) "value %08x" -milkymist_sysctl_start_timer0(void) "Start timer0" -milkymist_sysctl_stop_timer0(void) "Stop timer0" -milkymist_sysctl_start_timer1(void) "Start timer1" -milkymist_sysctl_stop_timer1(void) "Stop timer1" -milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0" -milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1" - -# hw/timer/aspeed_timer.c -aspeed_timer_ctrl_enable(uint8_t i, bool enable) "Timer %" PRIu8 ": %d" -aspeed_timer_ctrl_external_clock(uint8_t i, bool enable) "Timer %" PRIu8 ": %d" -aspeed_timer_ctrl_overflow_interrupt(uint8_t i, bool enable) "Timer %" PRIu8 ": %d" -aspeed_timer_ctrl_pulse_enable(uint8_t i, bool enable) "Timer %" PRIu8 ": %d" -aspeed_timer_set_ctrl2(uint32_t value) "Value: 0x%" PRIx32 -aspeed_timer_set_value(int timer, int reg, uint32_t value) "Timer %d register %d: 0x%" PRIx32 -aspeed_timer_read(uint64_t offset, unsigned size, uint64_t value) "From 0x%" PRIx64 ": of size %u: 0x%" PRIx64 diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h index df76245e6..e7f354a52 100644 --- a/hw/tpm/tpm_util.h +++ b/hw/tpm/tpm_util.h @@ -18,12 +18,11 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/> */ - -#ifndef TPM_TPM_UTIL_H -#define TPM_TPM_UTIL_H +#ifndef TPM_TPM_UTILS_H +#define TPM_TPM_UTILS_H #include "sysemu/tpm_backend.h" int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version); -#endif /* TPM_TPM_UTIL_H */ +#endif /* TPM_TPM_UTILS_H */ diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs index 98b5c9d27..2717027d3 100644 --- a/hw/usb/Makefile.objs +++ b/hw/usb/Makefile.objs @@ -38,7 +38,3 @@ common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o # usb pass-through common-obj-y += $(patsubst %,host-%.o,$(HOST_USB)) - -ifeq ($(CONFIG_USB_LIBUSB),y) -common-obj-$(CONFIG_XEN_BACKEND) += xen-usb.o -endif diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 25913ad48..16c3461d9 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -55,9 +55,9 @@ static int usb_device_post_load(void *opaque, int version_id) USBDevice *dev = opaque; if (dev->state == USB_STATE_NOTATTACHED) { - dev->attached = false; + dev->attached = 0; } else { - dev->attached = true; + dev->attached = 1; } if (dev->setup_index < 0 || dev->setup_len < 0 || @@ -279,13 +279,6 @@ static void usb_qdev_realize(DeviceState *qdev, Error **errp) static void usb_qdev_unrealize(DeviceState *qdev, Error **errp) { USBDevice *dev = USB_DEVICE(qdev); - USBDescString *s, *next; - - QLIST_FOREACH_SAFE(s, &dev->strings, next, next) { - QLIST_REMOVE(s, next); - g_free(s->str); - g_free(s); - } if (dev->attached) { usb_device_detach(dev); @@ -540,7 +533,7 @@ void usb_device_attach(USBDevice *dev, Error **errp) return; } - dev->attached = true; + dev->attached++; usb_attach(port); } @@ -554,7 +547,7 @@ int usb_device_detach(USBDevice *dev) trace_usb_port_detach(bus->busnr, port->path); usb_detach(port); - dev->attached = false; + dev->attached--; return 0; } @@ -743,48 +736,6 @@ USBDevice *usbdevice_create(const char *cmdline) return dev; } -static bool usb_get_attached(Object *obj, Error **errp) -{ - USBDevice *dev = USB_DEVICE(obj); - - return dev->attached; -} - -static void usb_set_attached(Object *obj, bool value, Error **errp) -{ - USBDevice *dev = USB_DEVICE(obj); - Error *err = NULL; - - if (dev->attached == value) { - return; - } - - if (value) { - usb_device_attach(dev, &err); - if (err) { - error_propagate(errp, err); - } - } else { - usb_device_detach(dev); - } -} - -static void usb_device_instance_init(Object *obj) -{ - USBDevice *dev = USB_DEVICE(obj); - USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); - - if (klass->attached_settable) { - object_property_add_bool(obj, "attached", - usb_get_attached, usb_set_attached, - NULL); - } else { - object_property_add_bool(obj, "attached", - usb_get_attached, NULL, - NULL); - } -} - static void usb_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); @@ -798,7 +749,6 @@ static const TypeInfo usb_device_type_info = { .name = TYPE_USB_DEVICE, .parent = TYPE_DEVICE, .instance_size = sizeof(USBDevice), - .instance_init = usb_device_instance_init, .abstract = true, .class_size = sizeof(USBDeviceClass), .class_init = usb_device_class_init, diff --git a/hw/usb/desc.c b/hw/usb/desc.c index 5e0e1d157..adb026e43 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -574,7 +574,6 @@ void usb_desc_create_serial(USBDevice *dev) } dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", dev->port->path); usb_desc_set_string(dev, index, serial); - g_free(path); } const char *usb_desc_get_string(USBDevice *dev, uint8_t index) diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 1be85ae75..bda84a64b 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -788,8 +788,8 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c) trace_usb_mtp_op_get_device_info(s->dev.addr); usb_mtp_add_u16(d, 100); - usb_mtp_add_u32(d, 0x00000006); - usb_mtp_add_u16(d, 0x0064); + usb_mtp_add_u32(d, 0xffffffff); + usb_mtp_add_u16(d, 0x0101); usb_mtp_add_wstr(d, L""); usb_mtp_add_u16(d, 0x0000); diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index c0f1193ba..74306b58e 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -670,49 +670,48 @@ static int ndis_query(USBNetState *s, uint32_t oid, /* general oids (table 4-1) */ /* mandatory */ case OID_GEN_SUPPORTED_LIST: - for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++) { - stl_le_p(outbuf + (i * sizeof(le32)), oid_supported_list[i]); - } + for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++) + ((le32 *) outbuf)[i] = cpu_to_le32(oid_supported_list[i]); return sizeof(oid_supported_list); /* mandatory */ case OID_GEN_HARDWARE_STATUS: - stl_le_p(outbuf, 0); + *((le32 *) outbuf) = cpu_to_le32(0); return sizeof(le32); /* mandatory */ case OID_GEN_MEDIA_SUPPORTED: - stl_le_p(outbuf, s->medium); + *((le32 *) outbuf) = cpu_to_le32(s->medium); return sizeof(le32); /* mandatory */ case OID_GEN_MEDIA_IN_USE: - stl_le_p(outbuf, s->medium); + *((le32 *) outbuf) = cpu_to_le32(s->medium); return sizeof(le32); /* mandatory */ case OID_GEN_MAXIMUM_FRAME_SIZE: - stl_le_p(outbuf, ETH_FRAME_LEN); + *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN); return sizeof(le32); /* mandatory */ case OID_GEN_LINK_SPEED: - stl_le_p(outbuf, s->speed); + *((le32 *) outbuf) = cpu_to_le32(s->speed); return sizeof(le32); /* mandatory */ case OID_GEN_TRANSMIT_BLOCK_SIZE: - stl_le_p(outbuf, ETH_FRAME_LEN); + *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN); return sizeof(le32); /* mandatory */ case OID_GEN_RECEIVE_BLOCK_SIZE: - stl_le_p(outbuf, ETH_FRAME_LEN); + *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN); return sizeof(le32); /* mandatory */ case OID_GEN_VENDOR_ID: - stl_le_p(outbuf, s->vendorid); + *((le32 *) outbuf) = cpu_to_le32(s->vendorid); return sizeof(le32); /* mandatory */ @@ -721,57 +720,58 @@ static int ndis_query(USBNetState *s, uint32_t oid, return strlen((char *)outbuf) + 1; case OID_GEN_VENDOR_DRIVER_VERSION: - stl_le_p(outbuf, 1); + *((le32 *) outbuf) = cpu_to_le32(1); return sizeof(le32); /* mandatory */ case OID_GEN_CURRENT_PACKET_FILTER: - stl_le_p(outbuf, s->filter); + *((le32 *) outbuf) = cpu_to_le32(s->filter); return sizeof(le32); /* mandatory */ case OID_GEN_MAXIMUM_TOTAL_SIZE: - stl_le_p(outbuf, RNDIS_MAX_TOTAL_SIZE); + *((le32 *) outbuf) = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); return sizeof(le32); /* mandatory */ case OID_GEN_MEDIA_CONNECT_STATUS: - stl_le_p(outbuf, s->media_state); + *((le32 *) outbuf) = cpu_to_le32(s->media_state); return sizeof(le32); case OID_GEN_PHYSICAL_MEDIUM: - stl_le_p(outbuf, 0); + *((le32 *) outbuf) = cpu_to_le32(0); return sizeof(le32); case OID_GEN_MAC_OPTIONS: - stl_le_p(outbuf, NDIS_MAC_OPTION_RECEIVE_SERIALIZED | - NDIS_MAC_OPTION_FULL_DUPLEX); + *((le32 *) outbuf) = cpu_to_le32( + NDIS_MAC_OPTION_RECEIVE_SERIALIZED | + NDIS_MAC_OPTION_FULL_DUPLEX); return sizeof(le32); /* statistics OIDs (table 4-2) */ /* mandatory */ case OID_GEN_XMIT_OK: - stl_le_p(outbuf, 0); + *((le32 *) outbuf) = cpu_to_le32(0); return sizeof(le32); /* mandatory */ case OID_GEN_RCV_OK: - stl_le_p(outbuf, 0); + *((le32 *) outbuf) = cpu_to_le32(0); return sizeof(le32); /* mandatory */ case OID_GEN_XMIT_ERROR: - stl_le_p(outbuf, 0); + *((le32 *) outbuf) = cpu_to_le32(0); return sizeof(le32); /* mandatory */ case OID_GEN_RCV_ERROR: - stl_le_p(outbuf, 0); + *((le32 *) outbuf) = cpu_to_le32(0); return sizeof(le32); /* mandatory */ case OID_GEN_RCV_NO_BUFFER: - stl_le_p(outbuf, 0); + *((le32 *) outbuf) = cpu_to_le32(0); return sizeof(le32); /* ieee802.3 OIDs (table 4-3) */ @@ -787,12 +787,12 @@ static int ndis_query(USBNetState *s, uint32_t oid, /* mandatory */ case OID_802_3_MULTICAST_LIST: - stl_le_p(outbuf, 0xe0000000); + *((le32 *) outbuf) = cpu_to_le32(0xe0000000); return sizeof(le32); /* mandatory */ case OID_802_3_MAXIMUM_LIST_SIZE: - stl_le_p(outbuf, 1); + *((le32 *) outbuf) = cpu_to_le32(1); return sizeof(le32); case OID_802_3_MAC_OPTIONS: @@ -801,17 +801,17 @@ static int ndis_query(USBNetState *s, uint32_t oid, /* ieee802.3 statistics OIDs (table 4-4) */ /* mandatory */ case OID_802_3_RCV_ERROR_ALIGNMENT: - stl_le_p(outbuf, 0); + *((le32 *) outbuf) = cpu_to_le32(0); return sizeof(le32); /* mandatory */ case OID_802_3_XMIT_ONE_COLLISION: - stl_le_p(outbuf, 0); + *((le32 *) outbuf) = cpu_to_le32(0); return sizeof(le32); /* mandatory */ case OID_802_3_XMIT_MORE_COLLISIONS: - stl_le_p(outbuf, 0); + *((le32 *) outbuf) = cpu_to_le32(0); return sizeof(le32); default: @@ -826,7 +826,7 @@ static int ndis_set(USBNetState *s, uint32_t oid, { switch (oid) { case OID_GEN_CURRENT_PACKET_FILTER: - s->filter = ldl_le_p(inbuf); + s->filter = le32_to_cpup((le32 *) inbuf); if (s->filter) { s->rndis_state = RNDIS_DATA_INITIALIZED; } else { @@ -1026,7 +1026,10 @@ static void usb_net_reset_in_buf(USBNetState *s) static int rndis_parse(USBNetState *s, uint8_t *data, int length) { - uint32_t msg_type = ldl_le_p(data); + uint32_t msg_type; + le32 *tmp = (le32 *) data; + + msg_type = le32_to_cpup(tmp); switch (msg_type) { case RNDIS_INITIALIZE_MSG: @@ -1334,7 +1337,7 @@ static void usb_net_handle_destroy(USBDevice *dev) } static NetClientInfo net_usbnet_info = { - .type = NET_CLIENT_DRIVER_NIC, + .type = NET_CLIENT_OPTIONS_KIND_NIC, .size = sizeof(NICState), .receive = usbnet_receive, .cleanup = usbnet_cleanup, @@ -1396,7 +1399,7 @@ static USBDevice *usb_net_init(USBBus *bus, const char *cmdline) qemu_opt_set(opts, "type", "nic", &error_abort); qemu_opt_set(opts, "model", "usb", &error_abort); - idx = net_client_init(opts, false, &local_err); + idx = net_client_init(opts, 0, &local_err); if (local_err) { error_report_err(local_err); return NULL; diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index c607f7606..248a58045 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -556,6 +556,21 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) } } +static void usb_msd_password_cb(void *opaque, int err) +{ + MSDState *s = opaque; + Error *local_err = NULL; + + if (!err) { + usb_device_attach(&s->dev, &local_err); + } + + if (local_err) { + error_report_err(local_err); + qdev_unplug(&s->dev.qdev, NULL); + } +} + static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req) { MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); @@ -601,21 +616,37 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp) return; } + if (blk_bs(blk)) { + bdrv_add_key(blk_bs(blk), NULL, &err); + if (err) { + if (monitor_cur_is_qmp()) { + error_propagate(errp, err); + return; + } + error_free(err); + err = NULL; + if (cur_mon) { + monitor_read_bdrv_key_start(cur_mon, blk_bs(blk), + usb_msd_password_cb, s); + s->dev.auto_attach = 0; + } else { + autostart = 0; + } + } + } + blkconf_serial(&s->conf, &dev->serial); blkconf_blocksizes(&s->conf); - blkconf_apply_backend_options(&s->conf); /* * Hack alert: this pretends to be a block device, but it's really * a SCSI bus that can serve only a single device, which it * creates automatically. But first it needs to detach from its * blockdev, or else scsi_bus_legacy_add_drive() dies when it - * attaches again. We also need to take another reference so that - * blk_detach_dev() doesn't free blk while we still need it. + * attaches again. * * The hack is probably a bad idea. */ - blk_ref(blk); blk_detach_dev(blk, &s->dev.qdev); s->conf.blk = NULL; @@ -626,7 +657,6 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp) scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable, s->conf.bootindex, dev->serial, &err); - blk_unref(blk); if (!scsi_dev) { error_propagate(errp, err); return; @@ -638,14 +668,9 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp) static void usb_msd_realize_bot(USBDevice *dev, Error **errp) { MSDState *s = USB_STORAGE_DEV(dev); - DeviceState *d = DEVICE(dev); usb_desc_create_serial(dev); usb_desc_init(dev); - if (d->hotplugged) { - s->dev.auto_attach = 0; - } - scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev), &usb_msd_scsi_info_bot, NULL); usb_msd_handle_reset(dev); @@ -793,7 +818,9 @@ static void usb_msd_set_bootindex(Object *obj, Visitor *v, const char *name, } out: - error_propagate(errp, local_err); + if (local_err) { + error_propagate(errp, local_err); + } } static const TypeInfo usb_storage_dev_type_info = { @@ -815,9 +842,10 @@ static void usb_msd_instance_init(Object *obj) static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data) { USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); uc->realize = usb_msd_realize_bot; - uc->attached_settable = true; + dc->hotpluggable = false; } static const TypeInfo msd_info = { diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 3a8ff18b1..0678b1b05 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -900,13 +900,9 @@ static void usb_uas_handle_destroy(USBDevice *dev) static void usb_uas_realize(USBDevice *dev, Error **errp) { UASDevice *uas = USB_UAS(dev); - DeviceState *d = DEVICE(dev); usb_desc_create_serial(dev); usb_desc_init(dev); - if (d->hotplugged) { - uas->dev.auto_attach = 0; - } QTAILQ_INIT(&uas->results); QTAILQ_INIT(&uas->requests); @@ -944,7 +940,6 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_uas_handle_control; uc->handle_data = usb_uas_handle_data; uc->handle_destroy = usb_uas_handle_destroy; - uc->attached_settable = true; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->fw_name = "storage"; dc->vmsd = &vmstate_usb_uas; diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index b093db729..43a8f7abc 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -2206,28 +2206,29 @@ static void ehci_advance_periodic_state(EHCIState *ehci) static void ehci_update_frindex(EHCIState *ehci, int uframes) { + int i; + if (!ehci_enabled(ehci) && ehci->pstate == EST_INACTIVE) { return; } - /* Generate FLR interrupt if frame index rolls over 0x2000 */ - if ((ehci->frindex % 0x2000) + uframes >= 0x2000) { - ehci_raise_irq(ehci, USBSTS_FLR); - } + for (i = 0; i < uframes; i++) { + ehci->frindex++; - /* How many times will frindex roll over 0x4000 with this frame count? - * usbsts_frindex is decremented by 0x4000 on rollover until it reaches 0 - */ - int rollovers = (ehci->frindex + uframes) / 0x4000; - if (rollovers > 0) { - if (ehci->usbsts_frindex >= (rollovers * 0x4000)) { - ehci->usbsts_frindex -= 0x4000 * rollovers; - } else { - ehci->usbsts_frindex = 0; + if (ehci->frindex == 0x00002000) { + ehci_raise_irq(ehci, USBSTS_FLR); } - } - ehci->frindex = (ehci->frindex + uframes) % 0x4000; + if (ehci->frindex == 0x00004000) { + ehci_raise_irq(ehci, USBSTS_FLR); + ehci->frindex = 0; + if (ehci->usbsts_frindex >= 0x00004000) { + ehci->usbsts_frindex -= 0x00004000; + } else { + ehci->usbsts_frindex = 0; + } + } + } } static void ehci_frame_timer(void *opaque) diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 3fd703865..30218423c 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -14,9 +14,8 @@ * 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 HW_USB_HCD_EHCI_H -#define HW_USB_HCD_EHCI_H +#ifndef HW_USB_EHCI_H +#define HW_USB_EHCI_H 1 #include "hw/hw.h" #include "qemu/timer.h" diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index fa5703832..16d9ff7b4 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1474,7 +1474,7 @@ static uint32_t ohci_get_frame_remaining(OHCIState *ohci) if (tks >= usb_frame_time) return (ohci->frt << 31); - tks = tks / usb_bit_time; + tks = muldiv64(1, tks, usb_bit_time); fr = (uint16_t)(ohci->fi - tks); return (ohci->frt << 31) | fr; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 188f95416..43ba61599 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -26,7 +26,6 @@ #include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "trace.h" -#include "qapi/error.h" //#define DEBUG_XHCI //#define DEBUG_DATA @@ -462,8 +461,6 @@ struct XHCIState { uint32_t numslots; uint32_t flags; uint32_t max_pstreams_mask; - OnOffAuto msi; - OnOffAuto msix; /* Operational Registers */ uint32_t usbcmd; @@ -501,7 +498,9 @@ typedef struct XHCIEvRingSeg { } XHCIEvRingSeg; enum xhci_flags { - XHCI_FLAG_SS_FIRST = 1, + XHCI_FLAG_USE_MSI = 1, + XHCI_FLAG_USE_MSI_X, + XHCI_FLAG_SS_FIRST, XHCI_FLAG_FORCE_PCIE_ENDCAP, XHCI_FLAG_ENABLE_STREAMS, }; @@ -2201,9 +2200,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, xfer->trb_count = length; for (i = 0; i < length; i++) { - TRBType type; - type = xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL); - assert(type); + assert(xhci_ring_fetch(xhci, ring, &xfer->trbs[i], NULL)); } xfer->streamid = streamid; @@ -2366,8 +2363,6 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, slot->uport = uport; slot->ctx = octx; - /* Make sure device is in USB_STATE_DEFAULT state */ - usb_device_reset(dev); if (bsr) { slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT; } else { @@ -2375,6 +2370,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, uint8_t buf[1]; slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slotid; + usb_device_reset(dev); memset(&p, 0, sizeof(p)); usb_packet_addbuf(&p, buf, sizeof(buf)); usb_packet_setup(&p, USB_TOKEN_OUT, @@ -3585,7 +3581,6 @@ static void usb_xhci_init(XHCIState *xhci) static void usb_xhci_realize(struct PCIDevice *dev, Error **errp) { int i, ret; - Error *err = NULL; XHCIState *xhci = XHCI(dev); @@ -3596,23 +3591,6 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp) usb_xhci_init(xhci); - if (xhci->msi != ON_OFF_AUTO_OFF) { - ret = msi_init(dev, 0x70, xhci->numintrs, true, false, &err); - /* Any error other than -ENOTSUP(board's MSI support is broken) - * is a programming error */ - assert(!ret || ret == -ENOTSUP); - if (ret && xhci->msi == ON_OFF_AUTO_ON) { - /* Can't satisfy user's explicit msi=on request, fail */ - error_append_hint(&err, "You have to use msi=auto (default) or " - "msi=off with this machine type.\n"); - error_propagate(errp, err); - return; - } - assert(!err || xhci->msi == ON_OFF_AUTO_AUTO); - /* With msi=auto, we fall back to MSI off silently */ - error_free(err); - } - if (xhci->numintrs > MAXINTRS) { xhci->numintrs = MAXINTRS; } @@ -3670,8 +3648,10 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp) assert(ret >= 0); } - if (xhci->msix != ON_OFF_AUTO_OFF) { - /* TODO check for errors */ + if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI)) { + msi_init(dev, 0x70, xhci->numintrs, true, false); + } + if (xhci_get_flag(xhci, XHCI_FLAG_USE_MSI_X)) { msix_init(dev, xhci->numintrs, &xhci->mem, 0, OFF_MSIX_TABLE, &xhci->mem, 0, OFF_MSIX_PBA, @@ -3892,8 +3872,8 @@ static const VMStateDescription vmstate_xhci = { }; static Property xhci_properties[] = { - DEFINE_PROP_ON_OFF_AUTO("msi", XHCIState, msi, ON_OFF_AUTO_AUTO), - DEFINE_PROP_ON_OFF_AUTO("msix", XHCIState, msix, ON_OFF_AUTO_AUTO), + DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true), + DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true), DEFINE_PROP_BIT("superspeed-ports-first", XHCIState, flags, XHCI_FLAG_SS_FIRST, true), DEFINE_PROP_BIT("force-pcie-endcap", XHCIState, flags, diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index e94672c15..6458a9448 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -34,9 +34,7 @@ */ #include "qemu/osdep.h" -#ifndef CONFIG_WIN32 #include <poll.h> -#endif #include <libusb.h> #include "qapi/error.h" @@ -81,7 +79,6 @@ struct USBHostDevice { uint32_t iso_urb_frames; uint32_t options; uint32_t loglevel; - bool needs_autoscan; /* state */ QTAILQ_ENTRY(USBHostDevice) next; @@ -207,8 +204,6 @@ static const char *err_names[] = { static libusb_context *ctx; static uint32_t loglevel; -#ifndef CONFIG_WIN32 - static void usb_host_handle_fd(void *opaque) { struct timeval tv = { 0, 0 }; @@ -228,14 +223,10 @@ static void usb_host_del_fd(int fd, void *user_data) qemu_set_fd_handler(fd, NULL, NULL, NULL); } -#endif /* !CONFIG_WIN32 */ - static int usb_host_init(void) { -#ifndef CONFIG_WIN32 const struct libusb_pollfd **poll; -#endif - int rc; + int i, rc; if (ctx) { return 0; @@ -245,21 +236,17 @@ static int usb_host_init(void) return -1; } libusb_set_debug(ctx, loglevel); -#ifdef CONFIG_WIN32 - /* FIXME: add support for Windows. */ -#else + libusb_set_pollfd_notifiers(ctx, usb_host_add_fd, usb_host_del_fd, ctx); poll = libusb_get_pollfds(ctx); if (poll) { - int i; for (i = 0; poll[i] != NULL; i++) { usb_host_add_fd(poll[i]->fd, poll[i]->events, ctx); } } free(poll); -#endif return 0; } @@ -359,7 +346,7 @@ static USBHostRequest *usb_host_req_find(USBHostDevice *s, USBPacket *p) return NULL; } -static void LIBUSB_CALL usb_host_req_complete_ctrl(struct libusb_transfer *xfer) +static void usb_host_req_complete_ctrl(struct libusb_transfer *xfer) { USBHostRequest *r = xfer->user_data; USBHostDevice *s = r->host; @@ -392,7 +379,7 @@ out: } } -static void LIBUSB_CALL usb_host_req_complete_data(struct libusb_transfer *xfer) +static void usb_host_req_complete_data(struct libusb_transfer *xfer) { USBHostRequest *r = xfer->user_data; USBHostDevice *s = r->host; @@ -448,8 +435,7 @@ static void usb_host_req_abort(USBHostRequest *r) /* ------------------------------------------------------------------------ */ -static void LIBUSB_CALL -usb_host_req_complete_iso(struct libusb_transfer *transfer) +static void usb_host_req_complete_iso(struct libusb_transfer *transfer) { USBHostIsoXfer *xfer = transfer->user_data; @@ -977,32 +963,9 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data) } } -static libusb_device *usb_host_find_ref(int bus, int addr) -{ - libusb_device **devs = NULL; - libusb_device *ret = NULL; - int i, n; - - if (usb_host_init() != 0) { - return NULL; - } - n = libusb_get_device_list(ctx, &devs); - for (i = 0; i < n; i++) { - if (libusb_get_bus_number(devs[i]) == bus && - libusb_get_device_address(devs[i]) == addr) { - ret = libusb_ref_device(devs[i]); - break; - } - } - libusb_free_device_list(devs, 1); - return ret; -} - static void usb_host_realize(USBDevice *udev, Error **errp) { USBHostDevice *s = USB_HOST_DEVICE(udev); - libusb_device *ldev; - int rc; if (s->match.vendor_id > 0xffff) { error_setg(errp, "vendorid out of range"); @@ -1023,33 +986,11 @@ static void usb_host_realize(USBDevice *udev, Error **errp) QTAILQ_INIT(&s->requests); QTAILQ_INIT(&s->isorings); - if (s->match.addr && s->match.bus_num && - !s->match.vendor_id && - !s->match.product_id && - !s->match.port) { - s->needs_autoscan = false; - ldev = usb_host_find_ref(s->match.bus_num, - s->match.addr); - if (!ldev) { - error_setg(errp, "failed to find host usb device %d:%d", - s->match.bus_num, s->match.addr); - return; - } - rc = usb_host_open(s, ldev); - libusb_unref_device(ldev); - if (rc < 0) { - error_setg(errp, "failed to open host usb device %d:%d", - s->match.bus_num, s->match.addr); - return; - } - } else { - s->needs_autoscan = true; - QTAILQ_INSERT_TAIL(&hostdevs, s, next); - usb_host_auto_check(NULL); - } - s->exit.notify = usb_host_exit_notifier; qemu_add_exit_notifier(&s->exit); + + QTAILQ_INSERT_TAIL(&hostdevs, s, next); + usb_host_auto_check(NULL); } static void usb_host_instance_init(Object *obj) @@ -1067,9 +1008,7 @@ static void usb_host_handle_destroy(USBDevice *udev) USBHostDevice *s = USB_HOST_DEVICE(udev); qemu_remove_exit_notifier(&s->exit); - if (s->needs_autoscan) { - QTAILQ_REMOVE(&hostdevs, s, next); - } + QTAILQ_REMOVE(&hostdevs, s, next); usb_host_close(s); } diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 444672a00..8d8054037 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -109,7 +109,6 @@ struct USBRedirDevice { uint8_t debug; char *filter_str; int32_t bootindex; - bool enable_streams; /* Data passed from chardev the fd_read cb to the usbredirparser read cb */ const uint8_t *read_buf; int read_buf_size; @@ -543,9 +542,9 @@ static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, start_iso.pkts_per_urb = 32; } - start_iso.no_urbs = DIV_ROUND_UP( - dev->endpoint[EP2I(ep)].bufpq_target_size, - start_iso.pkts_per_urb); + start_iso.no_urbs = (dev->endpoint[EP2I(ep)].bufpq_target_size + + start_iso.pkts_per_urb - 1) / + start_iso.pkts_per_urb; /* Output endpoints pre-fill only 1/2 of the packets, keeping the rest as overflow buffer. Also see the usbredir protocol documentation */ if (!(ep & USB_DIR_IN)) { @@ -1230,9 +1229,7 @@ static void usbredir_create_parser(USBRedirDevice *dev) usbredirparser_caps_set_cap(caps, usb_redir_cap_32bits_bulk_length); usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_receiving); #if USBREDIR_VERSION >= 0x000700 - if (dev->enable_streams) { - usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams); - } + usbredirparser_caps_set_cap(caps, usb_redir_cap_bulk_streams); #endif if (runstate_check(RUN_STATE_INMIGRATE)) { @@ -2479,7 +2476,6 @@ static Property usbredir_properties[] = { DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, usbredirparser_warning), DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str), - DEFINE_PROP_BOOL("streams", USBRedirDevice, enable_streams, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/usb/trace-events b/hw/usb/trace-events deleted file mode 100644 index 2d42fd45d..000000000 --- a/hw/usb/trace-events +++ /dev/null @@ -1,268 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/usb/core.c -usb_packet_state_change(int bus, const char *port, int ep, void *p, const char *o, const char *n) "bus %d, port %s, ep %d, packet %p, state %s -> %s" -usb_packet_state_fault(int bus, const char *port, int ep, void *p, const char *o, const char *n) "bus %d, port %s, ep %d, packet %p, state %s, expected %s" - -# hw/usb/bus.c -usb_port_claim(int bus, const char *port) "bus %d, port %s" -usb_port_attach(int bus, const char *port, const char *devspeed, const char *portspeed) "bus %d, port %s, devspeed %s, portspeed %s" -usb_port_detach(int bus, const char *port) "bus %d, port %s" -usb_port_release(int bus, const char *port) "bus %d, port %s" - -# hw/usb/hcd-ohci.c -usb_ohci_iso_td_read_failed(uint32_t addr) "ISO_TD read error at %x" -usb_ohci_iso_td_head(uint32_t head, uint32_t tail, uint32_t flags, uint32_t bp, uint32_t next, uint32_t be, uint32_t framenum, uint32_t startframe, uint32_t framecount, int rel_frame_num) "ISO_TD ED head 0x%.8x tailp 0x%.8x\n0x%.8x 0x%.8x 0x%.8x 0x%.8x\nframe_number 0x%.8x starting_frame 0x%.8x\nframe_count 0x%.8x relative %d" -usb_ohci_iso_td_head_offset(uint32_t o0, uint32_t o1, uint32_t o2, uint32_t o3, uint32_t o4, uint32_t o5, uint32_t o6, uint32_t o7) "0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x" -usb_ohci_iso_td_relative_frame_number_neg(int rel) "ISO_TD R=%d < 0" -usb_ohci_iso_td_relative_frame_number_big(int rel, int count) "ISO_TD R=%d > FC=%d" -usb_ohci_iso_td_bad_direction(int dir) "Bad direction %d" -usb_ohci_iso_td_bad_bp_be(uint32_t bp, uint32_t be) "ISO_TD bp 0x%.8x be 0x%.8x" -usb_ohci_iso_td_bad_cc_not_accessed(uint32_t start, uint32_t next) "ISO_TD cc != not accessed 0x%.8x 0x%.8x" -usb_ohci_iso_td_bad_cc_overrun(uint32_t start, uint32_t next) "ISO_TD start_offset=0x%.8x > next_offset=0x%.8x" -usb_ohci_iso_td_so(uint32_t so, uint32_t eo, uint32_t s, uint32_t e, const char *str, ssize_t len, int ret) "0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d" -usb_ohci_iso_td_data_overrun(int ret, ssize_t len) "DataOverrun %d > %zu" -usb_ohci_iso_td_data_underrun(int ret) "DataUnderrun %d" -usb_ohci_iso_td_nak(int ret) "got NAK/STALL %d" -usb_ohci_iso_td_bad_response(int ret) "Bad device response %d" -usb_ohci_port_attach(int index) "port #%d" -usb_ohci_port_detach(int index) "port #%d" -usb_ohci_port_wakeup(int index) "port #%d" -usb_ohci_port_suspend(int index) "port #%d" -usb_ohci_port_reset(int index) "port #%d" -usb_ohci_remote_wakeup(const char *s) "%s: SUSPEND->RESUME" -usb_ohci_reset(const char *s) "%s" -usb_ohci_start(const char *s) "%s: USB Operational" -usb_ohci_resume(const char *s) "%s: USB Resume" -usb_ohci_stop(const char *s) "%s: USB Suspended" -usb_ohci_exit(const char *s) "%s" -usb_ohci_set_ctl(const char *s, uint32_t new_state) "%s: new state 0x%x" -usb_ohci_td_underrun(void) "" -usb_ohci_td_dev_error(void) "" -usb_ohci_td_nak(void) "" -usb_ohci_td_stall(void) "" -usb_ohci_td_babble(void) "" -usb_ohci_td_bad_device_response(int rc) "%d" -usb_ohci_td_read_error(uint32_t addr) "TD read error at %x" -usb_ohci_td_bad_direction(int dir) "Bad direction %d" -usb_ohci_td_skip_async(void) "" -usb_ohci_td_pkt_hdr(uint32_t addr, int64_t pktlen, int64_t len, const char *s, int flag_r, uint32_t cbp, uint32_t be) " TD @ 0x%.8x %" PRId64 " of %" PRId64 " bytes %s r=%d cbp=0x%.8x be=0x%.8x" -usb_ohci_td_pkt_short(const char *dir, const char *buf) "%s data: %s" -usb_ohci_td_pkt_full(const char *dir, const char *buf) "%s data: %s" -usb_ohci_td_too_many_pending(void) "" -usb_ohci_td_packet_status(int status) "status=%d" -usb_ohci_ed_read_error(uint32_t addr) "ED read error at %x" -usb_ohci_ed_pkt(uint32_t cur, int h, int c, uint32_t head, uint32_t tail, uint32_t next) "ED @ 0x%.8x h=%u c=%u\n head=0x%.8x tailp=0x%.8x next=0x%.8x" -usb_ohci_ed_pkt_flags(uint32_t fa, uint32_t en, uint32_t d, int s, int k, int f, uint32_t mps) "fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u" -usb_ohci_hcca_read_error(uint32_t addr) "HCCA read error at %x" -usb_ohci_mem_read_unaligned(uint32_t addr) "at %x" -usb_ohci_mem_read_bad_offset(uint32_t addr) "%x" -usb_ohci_mem_write_unaligned(uint32_t addr) "at %x" -usb_ohci_mem_write_bad_offset(uint32_t addr) "%x" -usb_ohci_process_lists(uint32_t head, uint32_t cur) "head %x, cur %x" -usb_ohci_bus_eof_timer_failed(const char *name) "%s: timer_new_ns failed" -usb_ohci_set_frame_interval(const char *name, uint16_t fi_x, uint16_t fi_u) "%s: FrameInterval = 0x%x (%u)" -usb_ohci_hub_power_up(void) "powered up all ports" -usb_ohci_hub_power_down(void) "powered down all ports" -usb_ohci_init_time(int64_t frametime, int64_t bittime) "usb_bit_time=%" PRId64 " usb_frame_time=%" PRId64 -usb_ohci_die(void) "" -usb_ohci_async_complete(void) "" - -# hw/usb/hcd-ehci.c -usb_ehci_reset(void) "=== RESET ===" -usb_ehci_unrealize(void) "=== UNREALIZE ===" -usb_ehci_opreg_read(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x" -usb_ehci_opreg_write(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x" -usb_ehci_opreg_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)" -usb_ehci_portsc_read(uint32_t addr, uint32_t port, uint32_t val) "rd mmio %04x [port %d] = %x" -usb_ehci_portsc_write(uint32_t addr, uint32_t port, uint32_t val) "wr mmio %04x [port %d] = %x" -usb_ehci_portsc_change(uint32_t addr, uint32_t port, uint32_t new, uint32_t old) "ch mmio %04x [port %d] = %x (old: %x)" -usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d" -usb_ehci_state(const char *schedule, const char *state) "%s schedule %s" -usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x" -usb_ehci_qh_fields(uint32_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ %08x - rl %d, mplen %d, eps %d, ep %d, dev %d" -usb_ehci_qh_bits(uint32_t addr, int c, int h, int dtc, int i) "QH @ %08x - c %d, h %d, dtc %d, i %d" -usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t altnext) "q %p - QTD @ %08x: next %08x altnext %08x" -usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ %08x - tbytes %d, cpage %d, cerr %d, pid %d" -usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ %08x - ioc %d, active %d, halt %d, babble %d, xacterr %d" -usb_ehci_itd(uint32_t addr, uint32_t nxt, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d" -usb_ehci_sitd(uint32_t addr, uint32_t nxt, uint32_t active) "ITD @ %08x: next %08x - active %d" -usb_ehci_port_attach(uint32_t port, const char *owner, const char *device) "attach port #%d, owner %s, device %s" -usb_ehci_port_detach(uint32_t port, const char *owner) "detach port #%d, owner %s" -usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d" -usb_ehci_port_suspend(uint32_t port) "port #%d" -usb_ehci_port_wakeup(uint32_t port) "port #%d" -usb_ehci_port_resume(uint32_t port) "port #%d" -usb_ehci_queue_action(void *q, const char *action) "q %p: %s" -usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s" -usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x" -usb_ehci_guest_bug(const char *reason) "%s" -usb_ehci_doorbell_ring(void) "" -usb_ehci_doorbell_ack(void) "" -usb_ehci_dma_error(void) "" - -# hw/usb/hcd-uhci.c -usb_uhci_reset(void) "=== RESET ===" -usb_uhci_exit(void) "=== EXIT ===" -usb_uhci_schedule_start(void) "" -usb_uhci_schedule_stop(void) "" -usb_uhci_frame_start(uint32_t num) "nr %d" -usb_uhci_frame_stop_bandwidth(void) "" -usb_uhci_frame_loop_stop_idle(void) "" -usb_uhci_frame_loop_continue(void) "" -usb_uhci_mmio_readw(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%04x" -usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%04x" -usb_uhci_queue_add(uint32_t token) "token 0x%x" -usb_uhci_queue_del(uint32_t token, const char *reason) "token 0x%x: %s" -usb_uhci_packet_add(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" -usb_uhci_packet_link_async(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" -usb_uhci_packet_unlink_async(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" -usb_uhci_packet_cancel(uint32_t token, uint32_t addr, int done) "token 0x%x, td 0x%x, done %d" -usb_uhci_packet_complete_success(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" -usb_uhci_packet_complete_shortxfer(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" -usb_uhci_packet_complete_stall(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" -usb_uhci_packet_complete_babble(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" -usb_uhci_packet_complete_error(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" -usb_uhci_packet_del(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" -usb_uhci_qh_load(uint32_t qh) "qh 0x%x" -usb_uhci_td_load(uint32_t qh, uint32_t td, uint32_t ctrl, uint32_t token) "qh 0x%x, td 0x%x, ctrl 0x%x, token 0x%x" -usb_uhci_td_queue(uint32_t td, uint32_t ctrl, uint32_t token) "td 0x%x, ctrl 0x%x, token 0x%x" -usb_uhci_td_nextqh(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" -usb_uhci_td_async(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" -usb_uhci_td_complete(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" - -# hw/usb/hcd-xhci.c -usb_xhci_reset(void) "=== RESET ===" -usb_xhci_exit(void) "=== EXIT ===" -usb_xhci_run(void) "" -usb_xhci_stop(void) "" -usb_xhci_cap_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" -usb_xhci_oper_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" -usb_xhci_port_read(uint32_t port, uint32_t off, uint32_t val) "port %d, off 0x%04x, ret 0x%08x" -usb_xhci_runtime_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" -usb_xhci_doorbell_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x" -usb_xhci_oper_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" -usb_xhci_port_write(uint32_t port, uint32_t off, uint32_t val) "port %d, off 0x%04x, val 0x%08x" -usb_xhci_runtime_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" -usb_xhci_doorbell_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" -usb_xhci_irq_intx(uint32_t level) "level %d" -usb_xhci_irq_msi(uint32_t nr) "nr %d" -usb_xhci_irq_msix(uint32_t nr) "nr %d" -usb_xhci_irq_msix_use(uint32_t nr) "nr %d" -usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d" -usb_xhci_queue_event(uint32_t vector, uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "v %d, idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x" -usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x" -usb_xhci_port_reset(uint32_t port, bool warm) "port %d, warm %d" -usb_xhci_port_link(uint32_t port, uint32_t pls) "port %d, pls %d" -usb_xhci_port_notify(uint32_t port, uint32_t pls) "port %d, bits %x" -usb_xhci_slot_enable(uint32_t slotid) "slotid %d" -usb_xhci_slot_disable(uint32_t slotid) "slotid %d" -usb_xhci_slot_address(uint32_t slotid, const char *port) "slotid %d, port %s" -usb_xhci_slot_configure(uint32_t slotid) "slotid %d" -usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d" -usb_xhci_slot_reset(uint32_t slotid) "slotid %d" -usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" -usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" -usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint32_t streamid, uint64_t param) "slotid %d, epid %d, streamid %d, ptr %016" PRIx64 -usb_xhci_ep_kick(uint32_t slotid, uint32_t epid, uint32_t streamid) "slotid %d, epid %d, streamid %d" -usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" -usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" -usb_xhci_ep_state(uint32_t slotid, uint32_t epid, const char *os, const char *ns) "slotid %d, epid %d, %s -> %s" -usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t streamid) "%p: slotid %d, epid %d, streamid %d" -usb_xhci_xfer_async(void *xfer) "%p" -usb_xhci_xfer_nak(void *xfer) "%p" -usb_xhci_xfer_retry(void *xfer) "%p" -usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d" -usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d" -usb_xhci_unimplemented(const char *item, int nr) "%s (0x%x)" - -# hw/usb/desc.c -usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d" -usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d" -usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" -usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" -usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d" -usb_desc_bos(int addr, int len, int ret) "dev %d bos, len %d, ret %d" -usb_desc_msos(int addr, int index, int len, int ret) "dev %d msos, index 0x%x, len %d, ret %d" -usb_set_addr(int addr) "dev %d" -usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d" -usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d, altsetting %d, ret %d" -usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d" -usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d" - -# hw/usb/dev-hub.c -usb_hub_reset(int addr) "dev %d" -usb_hub_control(int addr, int request, int value, int index, int length) "dev %d, req 0x%x, value %d, index %d, langth %d" -usb_hub_get_port_status(int addr, int nr, int status, int changed) "dev %d, port %d, status 0x%x, changed 0x%x" -usb_hub_set_port_feature(int addr, int nr, const char *f) "dev %d, port %d, feature %s" -usb_hub_clear_port_feature(int addr, int nr, const char *f) "dev %d, port %d, feature %s" -usb_hub_attach(int addr, int nr) "dev %d, port %d" -usb_hub_detach(int addr, int nr) "dev %d, port %d" -usb_hub_status_report(int addr, int status) "dev %d, status 0x%x" - -# hw/usb/dev-uas.c -usb_uas_reset(int addr) "dev %d" -usb_uas_command(int addr, uint16_t tag, int lun, uint32_t lun64_1, uint32_t lun64_2) "dev %d, tag 0x%x, lun %d, lun64 %08x-%08x" -usb_uas_response(int addr, uint16_t tag, uint8_t code) "dev %d, tag 0x%x, code 0x%x" -usb_uas_sense(int addr, uint16_t tag, uint8_t status) "dev %d, tag 0x%x, status 0x%x" -usb_uas_read_ready(int addr, uint16_t tag) "dev %d, tag 0x%x" -usb_uas_write_ready(int addr, uint16_t tag) "dev %d, tag 0x%x" -usb_uas_xfer_data(int addr, uint16_t tag, uint32_t copy, uint32_t uoff, uint32_t usize, uint32_t soff, uint32_t ssize) "dev %d, tag 0x%x, copy %d, usb-pkt %d/%d, scsi-buf %d/%d" -usb_uas_scsi_data(int addr, uint16_t tag, uint32_t bytes) "dev %d, tag 0x%x, bytes %d" -usb_uas_scsi_complete(int addr, uint16_t tag, uint32_t status, uint32_t resid) "dev %d, tag 0x%x, status 0x%x, residue %d" -usb_uas_tmf_abort_task(int addr, uint16_t tag, uint16_t task_tag) "dev %d, tag 0x%x, task-tag 0x%x" -usb_uas_tmf_logical_unit_reset(int addr, uint16_t tag, int lun) "dev %d, tag 0x%x, lun %d" -usb_uas_tmf_unsupported(int addr, uint16_t tag, uint32_t function) "dev %d, tag 0x%x, function 0x%x" - -# hw/usb/dev-mtp.c -usb_mtp_reset(int addr) "dev %d" -usb_mtp_command(int dev, uint16_t code, uint32_t trans, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) "dev %d, code 0x%x, trans 0x%x, args 0x%x, 0x%x, 0x%x, 0x%x, 0x%x" -usb_mtp_success(int dev, uint32_t trans, uint32_t arg0, uint32_t arg1) "dev %d, trans 0x%x, args 0x%x, 0x%x" -usb_mtp_error(int dev, uint16_t code, uint32_t trans, uint32_t arg0, uint32_t arg1) "dev %d, code 0x%x, trans 0x%x, args 0x%x, 0x%x" -usb_mtp_data_in(int dev, uint32_t trans, uint32_t len) "dev %d, trans 0x%x, len %d" -usb_mtp_xfer(int dev, uint32_t ep, uint32_t dlen, uint32_t plen) "dev %d, ep %d, %d/%d" -usb_mtp_nak(int dev, uint32_t ep) "dev %d, ep %d" -usb_mtp_stall(int dev, const char *reason) "dev %d, reason: %s" -usb_mtp_op_get_device_info(int dev) "dev %d" -usb_mtp_op_open_session(int dev) "dev %d" -usb_mtp_op_close_session(int dev) "dev %d" -usb_mtp_op_get_storage_ids(int dev) "dev %d" -usb_mtp_op_get_storage_info(int dev) "dev %d" -usb_mtp_op_get_num_objects(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" -usb_mtp_op_get_object_handles(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" -usb_mtp_op_get_object_info(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" -usb_mtp_op_get_object(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" -usb_mtp_op_get_partial_object(int dev, uint32_t handle, const char *path, uint32_t offset, uint32_t length) "dev %d, handle 0x%x, path %s, off %d, len %d" -usb_mtp_op_unknown(int dev, uint32_t code) "dev %d, command code 0x%x" -usb_mtp_object_alloc(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" -usb_mtp_object_free(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" -usb_mtp_add_child(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s" -usb_mtp_inotify_event(int dev, const char *path, uint32_t mask, const char *s) "dev %d, path %s mask 0x%x event %s" - -# hw/usb/host-libusb.c -usb_host_open_started(int bus, int addr) "dev %d:%d" -usb_host_open_success(int bus, int addr) "dev %d:%d" -usb_host_open_failure(int bus, int addr) "dev %d:%d" -usb_host_close(int bus, int addr) "dev %d:%d" -usb_host_attach_kernel(int bus, int addr, int interface) "dev %d:%d, if %d" -usb_host_detach_kernel(int bus, int addr, int interface) "dev %d:%d, if %d" -usb_host_set_address(int bus, int addr, int config) "dev %d:%d, address %d" -usb_host_set_config(int bus, int addr, int config) "dev %d:%d, config %d" -usb_host_set_interface(int bus, int addr, int interface, int alt) "dev %d:%d, interface %d, alt %d" -usb_host_claim_interface(int bus, int addr, int config, int interface) "dev %d:%d, config %d, if %d" -usb_host_release_interface(int bus, int addr, int interface) "dev %d:%d, if %d" -usb_host_req_control(int bus, int addr, void *p, int req, int value, int index) "dev %d:%d, packet %p, req 0x%x, value %d, index %d" -usb_host_req_data(int bus, int addr, void *p, int in, int ep, int size) "dev %d:%d, packet %p, in %d, ep %d, size %d" -usb_host_req_complete(int bus, int addr, void *p, int status, int length) "dev %d:%d, packet %p, status %d, length %d" -usb_host_req_emulated(int bus, int addr, void *p, int status) "dev %d:%d, packet %p, status %d" -usb_host_req_canceled(int bus, int addr, void *p) "dev %d:%d, packet %p" -usb_host_iso_start(int bus, int addr, int ep) "dev %d:%d, ep %d" -usb_host_iso_stop(int bus, int addr, int ep) "dev %d:%d, ep %d" -usb_host_iso_out_of_bufs(int bus, int addr, int ep) "dev %d:%d, ep %d" -usb_host_reset(int bus, int addr) "dev %d:%d" -usb_host_auto_scan_enabled(void) -usb_host_auto_scan_disabled(void) -usb_host_parse_config(int bus, int addr, int value, int active) "dev %d:%d, value %d, active %d" -usb_host_parse_interface(int bus, int addr, int num, int alt, int active) "dev %d:%d, num %d, alt %d, active %d" -usb_host_parse_endpoint(int bus, int addr, int ep, const char *dir, const char *type, int active) "dev %d:%d, ep %d, %s, %s, active %d" -usb_host_parse_error(int bus, int addr, const char *errmsg) "dev %d:%d, msg %s" diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c deleted file mode 100644 index 174d715e3..000000000 --- a/hw/usb/xen-usb.c +++ /dev/null @@ -1,1107 +0,0 @@ -/* - * xen paravirt usb device backend - * - * (c) Juergen Gross <jgross@suse.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see <http://www.gnu.org/licenses/>. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include <libusb.h> -#include <sys/user.h> - -#include "qemu-common.h" -#include "qemu/config-file.h" -#include "hw/sysbus.h" -#include "hw/usb.h" -#include "hw/xen/xen_backend.h" -#include "monitor/qdev.h" -#include "qapi/qmp/qbool.h" -#include "qapi/qmp/qint.h" -#include "qapi/qmp/qstring.h" - -#include <xen/io/ring.h> -#include <xen/io/usbif.h> - -/* - * Check for required support of usbif.h: USBIF_SHORT_NOT_OK was the last - * macro added we rely on. - */ -#ifdef USBIF_SHORT_NOT_OK - -#define TR(xendev, lvl, fmt, args...) \ - { \ - struct timeval tv; \ - \ - gettimeofday(&tv, NULL); \ - xen_be_printf(xendev, lvl, "%8ld.%06ld xen-usb(%s):" fmt, \ - tv.tv_sec, tv.tv_usec, __func__, ##args); \ - } -#define TR_BUS(xendev, fmt, args...) TR(xendev, 2, fmt, ##args) -#define TR_REQ(xendev, fmt, args...) TR(xendev, 3, fmt, ##args) - -#define USBBACK_MAXPORTS USBIF_PIPE_PORT_MASK -#define USB_DEV_ADDR_SIZE (USBIF_PIPE_DEV_MASK + 1) - -/* USB wire protocol: structure describing control request parameter. */ -struct usbif_ctrlrequest { - uint8_t bRequestType; - uint8_t bRequest; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; -}; - -struct usbback_info; -struct usbback_req; - -struct usbback_stub { - USBDevice *dev; - USBPort port; - unsigned int speed; - bool attached; - QTAILQ_HEAD(submit_q_head, usbback_req) submit_q; -}; - -struct usbback_req { - struct usbback_info *usbif; - struct usbback_stub *stub; - struct usbif_urb_request req; - USBPacket packet; - - unsigned int nr_buffer_segs; /* # of transfer_buffer segments */ - unsigned int nr_extra_segs; /* # of iso_frame_desc segments */ - - QTAILQ_ENTRY(usbback_req) q; - - void *buffer; - void *isoc_buffer; - struct libusb_transfer *xfer; - - bool cancelled; -}; - -struct usbback_hotplug { - QSIMPLEQ_ENTRY(usbback_hotplug) q; - unsigned port; -}; - -struct usbback_info { - struct XenDevice xendev; /* must be first */ - USBBus bus; - void *urb_sring; - void *conn_sring; - struct usbif_urb_back_ring urb_ring; - struct usbif_conn_back_ring conn_ring; - int num_ports; - int usb_ver; - bool ring_error; - QTAILQ_HEAD(req_free_q_head, usbback_req) req_free_q; - QSIMPLEQ_HEAD(hotplug_q_head, usbback_hotplug) hotplug_q; - struct usbback_stub ports[USBBACK_MAXPORTS]; - struct usbback_stub *addr_table[USB_DEV_ADDR_SIZE]; - QEMUBH *bh; -}; - -static struct usbback_req *usbback_get_req(struct usbback_info *usbif) -{ - struct usbback_req *usbback_req; - - if (QTAILQ_EMPTY(&usbif->req_free_q)) { - usbback_req = g_new0(struct usbback_req, 1); - } else { - usbback_req = QTAILQ_FIRST(&usbif->req_free_q); - QTAILQ_REMOVE(&usbif->req_free_q, usbback_req, q); - } - return usbback_req; -} - -static void usbback_put_req(struct usbback_req *usbback_req) -{ - struct usbback_info *usbif; - - usbif = usbback_req->usbif; - memset(usbback_req, 0, sizeof(*usbback_req)); - QTAILQ_INSERT_HEAD(&usbif->req_free_q, usbback_req, q); -} - -static int usbback_gnttab_map(struct usbback_req *usbback_req) -{ - unsigned int nr_segs, i, prot; - uint32_t ref[USBIF_MAX_SEGMENTS_PER_REQUEST]; - struct usbback_info *usbif = usbback_req->usbif; - struct XenDevice *xendev = &usbif->xendev; - struct usbif_request_segment *seg; - void *addr; - - nr_segs = usbback_req->nr_buffer_segs + usbback_req->nr_extra_segs; - if (!nr_segs) { - return 0; - } - - if (nr_segs > USBIF_MAX_SEGMENTS_PER_REQUEST) { - xen_be_printf(xendev, 0, "bad number of segments in request (%d)\n", - nr_segs); - return -EINVAL; - } - - for (i = 0; i < nr_segs; i++) { - if ((unsigned)usbback_req->req.seg[i].offset + - (unsigned)usbback_req->req.seg[i].length > PAGE_SIZE) { - xen_be_printf(xendev, 0, "segment crosses page boundary\n"); - return -EINVAL; - } - } - - if (usbback_req->nr_buffer_segs) { - prot = PROT_READ; - if (usbif_pipein(usbback_req->req.pipe)) { - prot |= PROT_WRITE; - } - for (i = 0; i < usbback_req->nr_buffer_segs; i++) { - ref[i] = usbback_req->req.seg[i].gref; - } - usbback_req->buffer = xengnttab_map_domain_grant_refs(xendev->gnttabdev, - usbback_req->nr_buffer_segs, xendev->dom, ref, prot); - - if (!usbback_req->buffer) { - return -ENOMEM; - } - - for (i = 0; i < usbback_req->nr_buffer_segs; i++) { - seg = usbback_req->req.seg + i; - addr = usbback_req->buffer + i * PAGE_SIZE + seg->offset; - qemu_iovec_add(&usbback_req->packet.iov, addr, seg->length); - } - } - - if (!usbif_pipeisoc(usbback_req->req.pipe)) { - return 0; - } - - /* - * Right now isoc requests are not supported. - * Prepare supporting those by doing the work needed on the guest - * interface side. - */ - - if (!usbback_req->nr_extra_segs) { - xen_be_printf(xendev, 0, "iso request without descriptor segments\n"); - return -EINVAL; - } - - prot = PROT_READ | PROT_WRITE; - for (i = 0; i < usbback_req->nr_extra_segs; i++) { - ref[i] = usbback_req->req.seg[i + usbback_req->req.nr_buffer_segs].gref; - } - usbback_req->isoc_buffer = xengnttab_map_domain_grant_refs( - xendev->gnttabdev, usbback_req->nr_extra_segs, xendev->dom, ref, prot); - - if (!usbback_req->isoc_buffer) { - return -ENOMEM; - } - - return 0; -} - -static int usbback_init_packet(struct usbback_req *usbback_req) -{ - struct XenDevice *xendev = &usbback_req->usbif->xendev; - USBPacket *packet = &usbback_req->packet; - USBDevice *dev = usbback_req->stub->dev; - USBEndpoint *ep; - unsigned int pid, ep_nr; - bool sok; - int ret = 0; - - qemu_iovec_init(&packet->iov, USBIF_MAX_SEGMENTS_PER_REQUEST); - pid = usbif_pipein(usbback_req->req.pipe) ? USB_TOKEN_IN : USB_TOKEN_OUT; - ep_nr = usbif_pipeendpoint(usbback_req->req.pipe); - sok = !!(usbback_req->req.transfer_flags & USBIF_SHORT_NOT_OK); - if (usbif_pipectrl(usbback_req->req.pipe)) { - ep_nr = 0; - sok = false; - } - ep = usb_ep_get(dev, pid, ep_nr); - usb_packet_setup(packet, pid, ep, 0, 1, sok, true); - - switch (usbif_pipetype(usbback_req->req.pipe)) { - case USBIF_PIPE_TYPE_ISOC: - TR_REQ(xendev, "iso transfer %s: buflen: %x, %d frames\n", - (pid == USB_TOKEN_IN) ? "in" : "out", - usbback_req->req.buffer_length, - usbback_req->req.u.isoc.nr_frame_desc_segs); - ret = -EINVAL; /* isoc not implemented yet */ - break; - - case USBIF_PIPE_TYPE_INT: - TR_REQ(xendev, "int transfer %s: buflen: %x\n", - (pid == USB_TOKEN_IN) ? "in" : "out", - usbback_req->req.buffer_length); - break; - - case USBIF_PIPE_TYPE_CTRL: - packet->parameter = *(uint64_t *)usbback_req->req.u.ctrl; - TR_REQ(xendev, "ctrl parameter: %"PRIx64", buflen: %x\n", - packet->parameter, - usbback_req->req.buffer_length); - break; - - case USBIF_PIPE_TYPE_BULK: - TR_REQ(xendev, "bulk transfer %s: buflen: %x\n", - (pid == USB_TOKEN_IN) ? "in" : "out", - usbback_req->req.buffer_length); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static void usbback_do_response(struct usbback_req *usbback_req, int32_t status, - int32_t actual_length, int32_t error_count) -{ - struct usbback_info *usbif; - struct usbif_urb_response *res; - struct XenDevice *xendev; - unsigned int notify; - - usbif = usbback_req->usbif; - xendev = &usbif->xendev; - - TR_REQ(xendev, "id %d, status %d, length %d, errcnt %d\n", - usbback_req->req.id, status, actual_length, error_count); - - if (usbback_req->packet.iov.iov) { - qemu_iovec_destroy(&usbback_req->packet.iov); - } - - if (usbback_req->buffer) { - xengnttab_unmap(xendev->gnttabdev, usbback_req->buffer, - usbback_req->nr_buffer_segs); - usbback_req->buffer = NULL; - } - - if (usbback_req->isoc_buffer) { - xengnttab_unmap(xendev->gnttabdev, usbback_req->isoc_buffer, - usbback_req->nr_extra_segs); - usbback_req->isoc_buffer = NULL; - } - - if (usbif->urb_sring) { - res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt); - res->id = usbback_req->req.id; - res->status = status; - res->actual_length = actual_length; - res->error_count = error_count; - res->start_frame = 0; - usbif->urb_ring.rsp_prod_pvt++; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify); - - if (notify) { - xen_be_send_notify(xendev); - } - } - - if (!usbback_req->cancelled) - usbback_put_req(usbback_req); -} - -static void usbback_do_response_ret(struct usbback_req *usbback_req, - int32_t status) -{ - usbback_do_response(usbback_req, status, 0, 0); -} - -static int32_t usbback_xlat_status(int status) -{ - switch (status) { - case USB_RET_SUCCESS: - return 0; - case USB_RET_NODEV: - return -ENODEV; - case USB_RET_STALL: - return -EPIPE; - case USB_RET_BABBLE: - return -EOVERFLOW; - case USB_RET_IOERROR: - return -EPROTO; - } - - return -ESHUTDOWN; -} - -static void usbback_packet_complete(USBPacket *packet) -{ - struct usbback_req *usbback_req; - int32_t status; - - usbback_req = container_of(packet, struct usbback_req, packet); - - QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); - - status = usbback_xlat_status(packet->status); - usbback_do_response(usbback_req, status, packet->actual_length, 0); -} - -static void usbback_set_address(struct usbback_info *usbif, - struct usbback_stub *stub, - unsigned int cur_addr, unsigned int new_addr) -{ - if (cur_addr) { - usbif->addr_table[cur_addr] = NULL; - } - if (new_addr) { - usbif->addr_table[new_addr] = stub; - } -} - -static void usbback_cancel_req(struct usbback_req *usbback_req) -{ - if (usb_packet_is_inflight(&usbback_req->packet)) { - usb_cancel_packet(&usbback_req->packet); - QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); - usbback_req->cancelled = true; - usbback_do_response_ret(usbback_req, -EPROTO); - } -} - -static void usbback_process_unlink_req(struct usbback_req *usbback_req) -{ - struct usbback_info *usbif; - struct usbback_req *unlink_req; - unsigned int id, devnum; - int ret; - - usbif = usbback_req->usbif; - ret = 0; - id = usbback_req->req.u.unlink.unlink_id; - TR_REQ(&usbif->xendev, "unlink id %d\n", id); - devnum = usbif_pipedevice(usbback_req->req.pipe); - if (unlikely(devnum == 0)) { - usbback_req->stub = usbif->ports + - usbif_pipeportnum(usbback_req->req.pipe) - 1; - if (unlikely(!usbback_req->stub)) { - ret = -ENODEV; - goto fail_response; - } - } else { - if (unlikely(!usbif->addr_table[devnum])) { - ret = -ENODEV; - goto fail_response; - } - usbback_req->stub = usbif->addr_table[devnum]; - } - - QTAILQ_FOREACH(unlink_req, &usbback_req->stub->submit_q, q) { - if (unlink_req->req.id == id) { - usbback_cancel_req(unlink_req); - break; - } - } - -fail_response: - usbback_do_response_ret(usbback_req, ret); -} - -/* - * Checks whether a request can be handled at once or should be forwarded - * to the usb framework. - * Return value is: - * 0 in case of usb framework is needed - * 1 in case of local handling (no error) - * The request response has been queued already if return value not 0. - */ -static int usbback_check_and_submit(struct usbback_req *usbback_req) -{ - struct usbback_info *usbif; - unsigned int devnum; - struct usbback_stub *stub; - struct usbif_ctrlrequest *ctrl; - int ret; - uint16_t wValue; - - usbif = usbback_req->usbif; - stub = NULL; - devnum = usbif_pipedevice(usbback_req->req.pipe); - ctrl = (struct usbif_ctrlrequest *)usbback_req->req.u.ctrl; - wValue = le16_to_cpu(ctrl->wValue); - - /* - * When the device is first connected or resetted, USB device has no - * address. In this initial state, following requests are sent to device - * address (#0), - * - * 1. GET_DESCRIPTOR (with Descriptor Type is "DEVICE") is sent, - * and OS knows what device is connected to. - * - * 2. SET_ADDRESS is sent, and then device has its address. - * - * In the next step, SET_CONFIGURATION is sent to addressed device, and - * then the device is finally ready to use. - */ - if (unlikely(devnum == 0)) { - stub = usbif->ports + usbif_pipeportnum(usbback_req->req.pipe) - 1; - if (!stub->dev || !stub->attached) { - ret = -ENODEV; - goto do_response; - } - - switch (ctrl->bRequest) { - case USB_REQ_GET_DESCRIPTOR: - /* - * GET_DESCRIPTOR request to device #0. - * through normal transfer. - */ - TR_REQ(&usbif->xendev, "devnum 0 GET_DESCRIPTOR\n"); - usbback_req->stub = stub; - return 0; - case USB_REQ_SET_ADDRESS: - /* - * SET_ADDRESS request to device #0. - * add attached device to addr_table. - */ - TR_REQ(&usbif->xendev, "devnum 0 SET_ADDRESS\n"); - usbback_set_address(usbif, stub, 0, wValue); - ret = 0; - break; - default: - ret = -EINVAL; - break; - } - goto do_response; - } - - if (unlikely(!usbif->addr_table[devnum])) { - ret = -ENODEV; - goto do_response; - } - usbback_req->stub = usbif->addr_table[devnum]; - - /* - * Check special request - */ - if (ctrl->bRequest != USB_REQ_SET_ADDRESS) { - return 0; - } - - /* - * SET_ADDRESS request to addressed device. - * change addr or remove from addr_table. - */ - usbback_set_address(usbif, usbback_req->stub, devnum, wValue); - ret = 0; - -do_response: - usbback_do_response_ret(usbback_req, ret); - return 1; -} - -static void usbback_dispatch(struct usbback_req *usbback_req) -{ - int ret; - unsigned int devnum; - struct usbback_info *usbif; - - usbif = usbback_req->usbif; - - TR_REQ(&usbif->xendev, "start req_id %d pipe %08x\n", usbback_req->req.id, - usbback_req->req.pipe); - - /* unlink request */ - if (unlikely(usbif_pipeunlink(usbback_req->req.pipe))) { - usbback_process_unlink_req(usbback_req); - return; - } - - if (usbif_pipectrl(usbback_req->req.pipe)) { - if (usbback_check_and_submit(usbback_req)) { - return; - } - } else { - devnum = usbif_pipedevice(usbback_req->req.pipe); - usbback_req->stub = usbif->addr_table[devnum]; - - if (!usbback_req->stub || !usbback_req->stub->attached) { - ret = -ENODEV; - goto fail_response; - } - } - - QTAILQ_INSERT_TAIL(&usbback_req->stub->submit_q, usbback_req, q); - - usbback_req->nr_buffer_segs = usbback_req->req.nr_buffer_segs; - usbback_req->nr_extra_segs = usbif_pipeisoc(usbback_req->req.pipe) ? - usbback_req->req.u.isoc.nr_frame_desc_segs : 0; - - ret = usbback_init_packet(usbback_req); - if (ret) { - xen_be_printf(&usbif->xendev, 0, "invalid request\n"); - ret = -ESHUTDOWN; - goto fail_free_urb; - } - - ret = usbback_gnttab_map(usbback_req); - if (ret) { - xen_be_printf(&usbif->xendev, 0, "invalid buffer, ret=%d\n", ret); - ret = -ESHUTDOWN; - goto fail_free_urb; - } - - usb_handle_packet(usbback_req->stub->dev, &usbback_req->packet); - if (usbback_req->packet.status != USB_RET_ASYNC) { - usbback_packet_complete(&usbback_req->packet); - } - return; - -fail_free_urb: - QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); - -fail_response: - usbback_do_response_ret(usbback_req, ret); -} - -static void usbback_hotplug_notify(struct usbback_info *usbif) -{ - struct usbif_conn_back_ring *ring = &usbif->conn_ring; - struct usbif_conn_request req; - struct usbif_conn_response *res; - struct usbback_hotplug *usb_hp; - unsigned int notify; - - if (!usbif->conn_sring) { - return; - } - - /* Check for full ring. */ - if ((RING_SIZE(ring) - ring->rsp_prod_pvt - ring->req_cons) == 0) { - xen_be_send_notify(&usbif->xendev); - return; - } - - usb_hp = QSIMPLEQ_FIRST(&usbif->hotplug_q); - QSIMPLEQ_REMOVE_HEAD(&usbif->hotplug_q, q); - - RING_COPY_REQUEST(ring, ring->req_cons, &req); - ring->req_cons++; - ring->sring->req_event = ring->req_cons + 1; - - res = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt); - res->id = req.id; - res->portnum = usb_hp->port; - res->speed = usbif->ports[usb_hp->port - 1].speed; - ring->rsp_prod_pvt++; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify); - - if (notify) { - xen_be_send_notify(&usbif->xendev); - } - - TR_BUS(&usbif->xendev, "hotplug port %d speed %d\n", usb_hp->port, - res->speed); - - g_free(usb_hp); - - if (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) { - qemu_bh_schedule(usbif->bh); - } -} - -static void usbback_bh(void *opaque) -{ - struct usbback_info *usbif; - struct usbif_urb_back_ring *urb_ring; - struct usbback_req *usbback_req; - RING_IDX rc, rp; - unsigned int more_to_do; - - usbif = opaque; - if (usbif->ring_error) { - return; - } - - if (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) { - usbback_hotplug_notify(usbif); - } - - urb_ring = &usbif->urb_ring; - rc = urb_ring->req_cons; - rp = urb_ring->sring->req_prod; - xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ - - if (RING_REQUEST_PROD_OVERFLOW(urb_ring, rp)) { - rc = urb_ring->rsp_prod_pvt; - xen_be_printf(&usbif->xendev, 0, "domU provided bogus ring requests " - "(%#x - %#x = %u). Halting ring processing.\n", - rp, rc, rp - rc); - usbif->ring_error = true; - return; - } - - while (rc != rp) { - if (RING_REQUEST_CONS_OVERFLOW(urb_ring, rc)) { - break; - } - usbback_req = usbback_get_req(usbif); - - RING_COPY_REQUEST(urb_ring, rc, &usbback_req->req); - usbback_req->usbif = usbif; - - usbback_dispatch(usbback_req); - - urb_ring->req_cons = ++rc; - } - - RING_FINAL_CHECK_FOR_REQUESTS(urb_ring, more_to_do); - if (more_to_do) { - qemu_bh_schedule(usbif->bh); - } -} - -static void usbback_hotplug_enq(struct usbback_info *usbif, unsigned port) -{ - struct usbback_hotplug *usb_hp; - - usb_hp = g_new0(struct usbback_hotplug, 1); - usb_hp->port = port; - QSIMPLEQ_INSERT_TAIL(&usbif->hotplug_q, usb_hp, q); - usbback_hotplug_notify(usbif); -} - -static void usbback_portid_drain(struct usbback_info *usbif, unsigned port) -{ - struct usbback_req *req, *tmp; - bool sched = false; - - QTAILQ_FOREACH_SAFE(req, &usbif->ports[port - 1].submit_q, q, tmp) { - usbback_cancel_req(req); - sched = true; - } - - if (sched) { - qemu_bh_schedule(usbif->bh); - } -} - -static void usbback_portid_detach(struct usbback_info *usbif, unsigned port) -{ - if (!usbif->ports[port - 1].attached) { - return; - } - - usbif->ports[port - 1].speed = USBIF_SPEED_NONE; - usbif->ports[port - 1].attached = false; - usbback_portid_drain(usbif, port); - usbback_hotplug_enq(usbif, port); -} - -static void usbback_portid_remove(struct usbback_info *usbif, unsigned port) -{ - USBPort *p; - - if (!usbif->ports[port - 1].dev) { - return; - } - - p = &(usbif->ports[port - 1].port); - snprintf(p->path, sizeof(p->path), "%d", 99); - - object_unparent(OBJECT(usbif->ports[port - 1].dev)); - usbif->ports[port - 1].dev = NULL; - usbback_portid_detach(usbif, port); - - TR_BUS(&usbif->xendev, "port %d removed\n", port); -} - -static void usbback_portid_add(struct usbback_info *usbif, unsigned port, - char *busid) -{ - unsigned speed; - char *portname; - USBPort *p; - Error *local_err = NULL; - QDict *qdict; - QemuOpts *opts; - - if (usbif->ports[port - 1].dev) { - return; - } - - portname = strchr(busid, '-'); - if (!portname) { - xen_be_printf(&usbif->xendev, 0, "device %s illegal specification\n", - busid); - return; - } - portname++; - p = &(usbif->ports[port - 1].port); - snprintf(p->path, sizeof(p->path), "%s", portname); - - qdict = qdict_new(); - qdict_put(qdict, "driver", qstring_from_str("usb-host")); - qdict_put(qdict, "hostbus", qint_from_int(atoi(busid))); - qdict_put(qdict, "hostport", qstring_from_str(portname)); - opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err); - if (local_err) { - goto err; - } - usbif->ports[port - 1].dev = USB_DEVICE(qdev_device_add(opts, &local_err)); - if (!usbif->ports[port - 1].dev) { - goto err; - } - QDECREF(qdict); - snprintf(p->path, sizeof(p->path), "%d", port); - speed = usbif->ports[port - 1].dev->speed; - switch (speed) { - case USB_SPEED_LOW: - speed = USBIF_SPEED_LOW; - break; - case USB_SPEED_FULL: - speed = USBIF_SPEED_FULL; - break; - case USB_SPEED_HIGH: - speed = (usbif->usb_ver < USB_VER_USB20) ? - USBIF_SPEED_NONE : USBIF_SPEED_HIGH; - break; - default: - speed = USBIF_SPEED_NONE; - break; - } - if (speed == USBIF_SPEED_NONE) { - xen_be_printf(&usbif->xendev, 0, "device %s wrong speed\n", busid); - object_unparent(OBJECT(usbif->ports[port - 1].dev)); - usbif->ports[port - 1].dev = NULL; - return; - } - usb_device_reset(usbif->ports[port - 1].dev); - usbif->ports[port - 1].speed = speed; - usbif->ports[port - 1].attached = true; - QTAILQ_INIT(&usbif->ports[port - 1].submit_q); - usbback_hotplug_enq(usbif, port); - - TR_BUS(&usbif->xendev, "port %d attached\n", port); - return; - -err: - QDECREF(qdict); - snprintf(p->path, sizeof(p->path), "%d", 99); - xen_be_printf(&usbif->xendev, 0, "device %s could not be opened\n", busid); -} - -static void usbback_process_port(struct usbback_info *usbif, unsigned port) -{ - char node[8]; - char *busid; - - snprintf(node, sizeof(node), "port/%d", port); - busid = xenstore_read_be_str(&usbif->xendev, node); - if (busid == NULL) { - xen_be_printf(&usbif->xendev, 0, "xenstore_read %s failed\n", node); - return; - } - - /* Remove portid, if the port is not connected. */ - if (strlen(busid) == 0) { - usbback_portid_remove(usbif, port); - } else { - usbback_portid_add(usbif, port, busid); - } - - g_free(busid); -} - -static void usbback_disconnect(struct XenDevice *xendev) -{ - struct usbback_info *usbif; - unsigned int i; - - TR_BUS(xendev, "start\n"); - - usbif = container_of(xendev, struct usbback_info, xendev); - - xen_be_unbind_evtchn(xendev); - - if (usbif->urb_sring) { - xengnttab_unmap(xendev->gnttabdev, usbif->urb_sring, 1); - usbif->urb_sring = NULL; - } - if (usbif->conn_sring) { - xengnttab_unmap(xendev->gnttabdev, usbif->conn_sring, 1); - usbif->conn_sring = NULL; - } - - for (i = 0; i < usbif->num_ports; i++) { - if (usbif->ports[i].dev) { - usbback_portid_drain(usbif, i + 1); - } - } - - TR_BUS(xendev, "finished\n"); -} - -static int usbback_connect(struct XenDevice *xendev) -{ - struct usbback_info *usbif; - struct usbif_urb_sring *urb_sring; - struct usbif_conn_sring *conn_sring; - int urb_ring_ref; - int conn_ring_ref; - unsigned int i; - - TR_BUS(xendev, "start\n"); - - usbif = container_of(xendev, struct usbback_info, xendev); - - if (xenstore_read_fe_int(xendev, "urb-ring-ref", &urb_ring_ref)) { - xen_be_printf(xendev, 0, "error reading urb-ring-ref\n"); - return -1; - } - if (xenstore_read_fe_int(xendev, "conn-ring-ref", &conn_ring_ref)) { - xen_be_printf(xendev, 0, "error reading conn-ring-ref\n"); - return -1; - } - if (xenstore_read_fe_int(xendev, "event-channel", &xendev->remote_port)) { - xen_be_printf(xendev, 0, "error reading event-channel\n"); - return -1; - } - - usbif->urb_sring = xengnttab_map_grant_ref(xendev->gnttabdev, xendev->dom, - urb_ring_ref, - PROT_READ | PROT_WRITE); - usbif->conn_sring = xengnttab_map_grant_ref(xendev->gnttabdev, xendev->dom, - conn_ring_ref, - PROT_READ | PROT_WRITE); - if (!usbif->urb_sring || !usbif->conn_sring) { - xen_be_printf(xendev, 0, "error mapping rings\n"); - usbback_disconnect(xendev); - return -1; - } - - urb_sring = usbif->urb_sring; - conn_sring = usbif->conn_sring; - BACK_RING_INIT(&usbif->urb_ring, urb_sring, XC_PAGE_SIZE); - BACK_RING_INIT(&usbif->conn_ring, conn_sring, XC_PAGE_SIZE); - - xen_be_bind_evtchn(xendev); - - xen_be_printf(xendev, 1, "urb-ring-ref %d, conn-ring-ref %d, " - "remote port %d, local port %d\n", urb_ring_ref, - conn_ring_ref, xendev->remote_port, xendev->local_port); - - for (i = 1; i <= usbif->num_ports; i++) { - if (usbif->ports[i - 1].dev) { - usbback_hotplug_enq(usbif, i); - } - } - - return 0; -} - -static void usbback_backend_changed(struct XenDevice *xendev, const char *node) -{ - struct usbback_info *usbif; - unsigned int i; - - TR_BUS(xendev, "path %s\n", node); - - usbif = container_of(xendev, struct usbback_info, xendev); - for (i = 1; i <= usbif->num_ports; i++) { - usbback_process_port(usbif, i); - } -} - -static int usbback_init(struct XenDevice *xendev) -{ - struct usbback_info *usbif; - - TR_BUS(xendev, "start\n"); - - usbif = container_of(xendev, struct usbback_info, xendev); - - if (xenstore_read_be_int(xendev, "num-ports", &usbif->num_ports) || - usbif->num_ports < 1 || usbif->num_ports > USBBACK_MAXPORTS) { - xen_be_printf(xendev, 0, "num-ports not readable or out of bounds\n"); - return -1; - } - if (xenstore_read_be_int(xendev, "usb-ver", &usbif->usb_ver) || - (usbif->usb_ver != USB_VER_USB11 && usbif->usb_ver != USB_VER_USB20)) { - xen_be_printf(xendev, 0, "usb-ver not readable or out of bounds\n"); - return -1; - } - - usbback_backend_changed(xendev, "port"); - - TR_BUS(xendev, "finished\n"); - - return 0; -} - -static void xen_bus_attach(USBPort *port) -{ - struct usbback_info *usbif; - - usbif = port->opaque; - TR_BUS(&usbif->xendev, "\n"); - usbif->ports[port->index].attached = true; - usbback_hotplug_enq(usbif, port->index + 1); -} - -static void xen_bus_detach(USBPort *port) -{ - struct usbback_info *usbif; - - usbif = port->opaque; - TR_BUS(&usbif->xendev, "\n"); - usbback_portid_detach(usbif, port->index + 1); -} - -static void xen_bus_child_detach(USBPort *port, USBDevice *child) -{ - struct usbback_info *usbif; - - usbif = port->opaque; - TR_BUS(&usbif->xendev, "\n"); -} - -static void xen_bus_complete(USBPort *port, USBPacket *packet) -{ - struct usbback_req *usbback_req; - struct usbback_info *usbif; - - usbback_req = container_of(packet, struct usbback_req, packet); - if (usbback_req->cancelled) { - g_free(usbback_req); - return; - } - - usbif = usbback_req->usbif; - TR_REQ(&usbif->xendev, "\n"); - usbback_packet_complete(packet); -} - -static USBPortOps xen_usb_port_ops = { - .attach = xen_bus_attach, - .detach = xen_bus_detach, - .child_detach = xen_bus_child_detach, - .complete = xen_bus_complete, -}; - -static USBBusOps xen_usb_bus_ops = { -}; - -static void usbback_alloc(struct XenDevice *xendev) -{ - struct usbback_info *usbif; - USBPort *p; - unsigned int i, max_grants; - - usbif = container_of(xendev, struct usbback_info, xendev); - - usb_bus_new(&usbif->bus, sizeof(usbif->bus), &xen_usb_bus_ops, xen_sysdev); - for (i = 0; i < USBBACK_MAXPORTS; i++) { - p = &(usbif->ports[i].port); - usb_register_port(&usbif->bus, p, usbif, i, &xen_usb_port_ops, - USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL | - USB_SPEED_MASK_HIGH); - snprintf(p->path, sizeof(p->path), "%d", 99); - } - - QTAILQ_INIT(&usbif->req_free_q); - QSIMPLEQ_INIT(&usbif->hotplug_q); - usbif->bh = qemu_bh_new(usbback_bh, usbif); - - /* max_grants: for each request and for the rings (request and connect). */ - max_grants = USBIF_MAX_SEGMENTS_PER_REQUEST * USB_URB_RING_SIZE + 2; - if (xengnttab_set_max_grants(xendev->gnttabdev, max_grants) < 0) { - xen_be_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n", - strerror(errno)); - } -} - -static int usbback_free(struct XenDevice *xendev) -{ - struct usbback_info *usbif; - struct usbback_req *usbback_req; - struct usbback_hotplug *usb_hp; - unsigned int i; - - TR_BUS(xendev, "start\n"); - - usbback_disconnect(xendev); - usbif = container_of(xendev, struct usbback_info, xendev); - for (i = 1; i <= usbif->num_ports; i++) { - usbback_portid_remove(usbif, i); - } - - while (!QTAILQ_EMPTY(&usbif->req_free_q)) { - usbback_req = QTAILQ_FIRST(&usbif->req_free_q); - QTAILQ_REMOVE(&usbif->req_free_q, usbback_req, q); - g_free(usbback_req); - } - while (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) { - usb_hp = QSIMPLEQ_FIRST(&usbif->hotplug_q); - QSIMPLEQ_REMOVE_HEAD(&usbif->hotplug_q, q); - g_free(usb_hp); - } - - qemu_bh_delete(usbif->bh); - - for (i = 0; i < USBBACK_MAXPORTS; i++) { - usb_unregister_port(&usbif->bus, &(usbif->ports[i].port)); - } - - usb_bus_release(&usbif->bus); - object_unparent(OBJECT(&usbif->bus)); - - TR_BUS(xendev, "finished\n"); - - return 0; -} - -static void usbback_event(struct XenDevice *xendev) -{ - struct usbback_info *usbif; - - usbif = container_of(xendev, struct usbback_info, xendev); - qemu_bh_schedule(usbif->bh); -} - -struct XenDevOps xen_usb_ops = { - .size = sizeof(struct usbback_info), - .flags = DEVOPS_FLAG_NEED_GNTDEV, - .init = usbback_init, - .alloc = usbback_alloc, - .free = usbback_free, - .backend_changed = usbback_backend_changed, - .initialise = usbback_connect, - .disconnect = usbback_disconnect, - .event = usbback_event, -}; - -#else /* USBIF_SHORT_NOT_OK */ - -static int usbback_not_supported(void) -{ - return -EINVAL; -} - -struct XenDevOps xen_usb_ops = { - .backend_register = usbback_not_supported, -}; - -#endif diff --git a/hw/vfio/Makefile.objs b/hw/vfio/Makefile.objs index c25e32b02..ceddbb8f9 100644 --- a/hw/vfio/Makefile.objs +++ b/hw/vfio/Makefile.objs @@ -4,5 +4,4 @@ obj-$(CONFIG_PCI) += pci.o pci-quirks.o obj-$(CONFIG_SOFTMMU) += platform.o obj-$(CONFIG_SOFTMMU) += calxeda-xgmac.o obj-$(CONFIG_SOFTMMU) += amd-xgbe.o -obj-$(CONFIG_SOFTMMU) += spapr.o endif diff --git a/hw/vfio/common.c b/hw/vfio/common.c index b313e7c2c..e1927a5b9 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -20,9 +20,7 @@ #include "qemu/osdep.h" #include <sys/ioctl.h> -#ifdef CONFIG_KVM -#include <linux/kvm.h> -#endif +#include <sys/mman.h> #include <linux/vfio.h> #include "hw/vfio/vfio-common.h" @@ -31,7 +29,6 @@ #include "exec/memory.h" #include "hw/hw.h" #include "qemu/error-report.h" -#include "qemu/range.h" #include "sysemu/kvm.h" #include "trace.h" @@ -242,44 +239,6 @@ static int vfio_dma_map(VFIOContainer *container, hwaddr iova, return -errno; } -static void vfio_host_win_add(VFIOContainer *container, - hwaddr min_iova, hwaddr max_iova, - uint64_t iova_pgsizes) -{ - VFIOHostDMAWindow *hostwin; - - QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { - if (ranges_overlap(hostwin->min_iova, - hostwin->max_iova - hostwin->min_iova + 1, - min_iova, - max_iova - min_iova + 1)) { - hw_error("%s: Overlapped IOMMU are not enabled", __func__); - } - } - - hostwin = g_malloc0(sizeof(*hostwin)); - - hostwin->min_iova = min_iova; - hostwin->max_iova = max_iova; - hostwin->iova_pgsizes = iova_pgsizes; - QLIST_INSERT_HEAD(&container->hostwin_list, hostwin, hostwin_next); -} - -static int vfio_host_win_del(VFIOContainer *container, hwaddr min_iova, - hwaddr max_iova) -{ - VFIOHostDMAWindow *hostwin; - - QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { - if (hostwin->min_iova == min_iova && hostwin->max_iova == max_iova) { - QLIST_REMOVE(hostwin, hostwin_next); - return 0; - } - } - - return -1; -} - static bool vfio_listener_skipped_section(MemoryRegionSection *section) { return (!memory_region_is_ram(section->mr) && @@ -298,20 +257,14 @@ static void vfio_iommu_map_notify(Notifier *n, void *data) VFIOGuestIOMMU *giommu = container_of(n, VFIOGuestIOMMU, n); VFIOContainer *container = giommu->container; IOMMUTLBEntry *iotlb = data; - hwaddr iova = iotlb->iova + giommu->iommu_offset; MemoryRegion *mr; hwaddr xlat; hwaddr len = iotlb->addr_mask + 1; void *vaddr; int ret; - trace_vfio_iommu_map_notify(iova, iova + iotlb->addr_mask); - - if (iotlb->target_as != &address_space_memory) { - error_report("Wrong target AS \"%s\", only system memory is allowed", - iotlb->target_as->name ? iotlb->target_as->name : "none"); - return; - } + trace_vfio_iommu_map_notify(iotlb->iova, + iotlb->iova + iotlb->addr_mask); /* * The IOMMU TLB entry we have just covers translation through @@ -338,21 +291,21 @@ static void vfio_iommu_map_notify(Notifier *n, void *data) if ((iotlb->perm & IOMMU_RW) != IOMMU_NONE) { vaddr = memory_region_get_ram_ptr(mr) + xlat; - ret = vfio_dma_map(container, iova, + ret = vfio_dma_map(container, iotlb->iova, iotlb->addr_mask + 1, vaddr, !(iotlb->perm & IOMMU_WO) || mr->readonly); if (ret) { error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " "0x%"HWADDR_PRIx", %p) = %d (%m)", - container, iova, + container, iotlb->iova, iotlb->addr_mask + 1, vaddr, ret); } } else { - ret = vfio_dma_unmap(container, iova, iotlb->addr_mask + 1); + ret = vfio_dma_unmap(container, iotlb->iova, iotlb->addr_mask + 1); if (ret) { error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " "0x%"HWADDR_PRIx") = %d (%m)", - container, iova, + container, iotlb->iova, iotlb->addr_mask + 1, ret); } } @@ -360,6 +313,11 @@ out: rcu_read_unlock(); } +static hwaddr vfio_container_granularity(VFIOContainer *container) +{ + return (hwaddr)1 << ctz64(container->iova_pgsizes); +} + static void vfio_listener_region_add(MemoryListener *listener, MemoryRegionSection *section) { @@ -368,8 +326,6 @@ static void vfio_listener_region_add(MemoryListener *listener, Int128 llend, llsize; void *vaddr; int ret; - VFIOHostDMAWindow *hostwin; - bool hostwin_found; if (vfio_listener_skipped_section(section)) { trace_vfio_listener_region_add_skip( @@ -395,40 +351,7 @@ static void vfio_listener_region_add(MemoryListener *listener, } end = int128_get64(int128_sub(llend, int128_one())); - if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - VFIOHostDMAWindow *hostwin; - hwaddr pgsize = 0; - - /* For now intersections are not allowed, we may relax this later */ - QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { - if (ranges_overlap(hostwin->min_iova, - hostwin->max_iova - hostwin->min_iova + 1, - section->offset_within_address_space, - int128_get64(section->size))) { - ret = -1; - goto fail; - } - } - - ret = vfio_spapr_create_window(container, section, &pgsize); - if (ret) { - goto fail; - } - - vfio_host_win_add(container, section->offset_within_address_space, - section->offset_within_address_space + - int128_get64(section->size) - 1, pgsize); - } - - hostwin_found = false; - QLIST_FOREACH(hostwin, &container->hostwin_list, hostwin_next) { - if (hostwin->min_iova <= iova && end <= hostwin->max_iova) { - hostwin_found = true; - break; - } - } - - if (!hostwin_found) { + if ((iova < container->min_iova) || (end > container->max_iova)) { error_report("vfio: IOMMU container %p can't map guest IOVA region" " 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx, container, iova, end); @@ -443,6 +366,10 @@ static void vfio_listener_region_add(MemoryListener *listener, trace_vfio_listener_region_add_iommu(iova, end); /* + * FIXME: We should do some checking to see if the + * capabilities of the host VFIO IOMMU are adequate to model + * the guest IOMMU + * * FIXME: For VFIO iommu types which have KVM acceleration to * avoid bouncing all map/unmaps through qemu this way, this * would be the right place to wire that up (tell the KVM @@ -450,14 +377,14 @@ static void vfio_listener_region_add(MemoryListener *listener, */ giommu = g_malloc0(sizeof(*giommu)); giommu->iommu = section->mr; - giommu->iommu_offset = section->offset_within_address_space - - section->offset_within_region; giommu->container = container; giommu->n.notify = vfio_iommu_map_notify; QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next); memory_region_register_iommu_notifier(giommu->iommu, &giommu->n); - memory_region_iommu_replay(giommu->iommu, &giommu->n, false); + memory_region_iommu_replay(giommu->iommu, &giommu->n, + vfio_container_granularity(container), + false); return; } @@ -503,7 +430,6 @@ static void vfio_listener_region_del(MemoryListener *listener, { VFIOContainer *container = container_of(listener, VFIOContainer, listener); hwaddr iova, end; - Int128 llend, llsize; int ret; if (vfio_listener_skipped_section(section)) { @@ -525,8 +451,7 @@ static void vfio_listener_region_del(MemoryListener *listener, QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) { if (giommu->iommu == section->mr) { - memory_region_unregister_iommu_notifier(giommu->iommu, - &giommu->n); + memory_region_unregister_iommu_notifier(&giommu->n); QLIST_REMOVE(giommu, giommu_next); g_free(giommu); break; @@ -543,37 +468,21 @@ static void vfio_listener_region_del(MemoryListener *listener, } iova = TARGET_PAGE_ALIGN(section->offset_within_address_space); - llend = int128_make64(section->offset_within_address_space); - llend = int128_add(llend, section->size); - llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK)); + end = (section->offset_within_address_space + int128_get64(section->size)) & + TARGET_PAGE_MASK; - if (int128_ge(int128_make64(iova), llend)) { + if (iova >= end) { return; } - end = int128_get64(int128_sub(llend, int128_one())); - - llsize = int128_sub(llend, int128_make64(iova)); - trace_vfio_listener_region_del(iova, end); + trace_vfio_listener_region_del(iova, end - 1); - ret = vfio_dma_unmap(container, iova, int128_get64(llsize)); + ret = vfio_dma_unmap(container, iova, end - iova); memory_region_unref(section->mr); if (ret) { error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " "0x%"HWADDR_PRIx") = %d (%m)", - container, iova, int128_get64(llsize), ret); - } - - if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - vfio_spapr_remove_window(container, - section->offset_within_address_space); - if (vfio_host_win_del(container, - section->offset_within_address_space, - section->offset_within_address_space + - int128_get64(section->size) - 1) < 0) { - hw_error("%s: Cannot delete missing window at %"HWADDR_PRIx, - __func__, section->offset_within_address_space); - } + container, iova, end - iova, ret); } } @@ -585,57 +494,6 @@ static const MemoryListener vfio_memory_listener = { static void vfio_listener_release(VFIOContainer *container) { memory_listener_unregister(&container->listener); - if (container->iommu_type == VFIO_SPAPR_TCE_v2_IOMMU) { - memory_listener_unregister(&container->prereg_listener); - } -} - -static struct vfio_info_cap_header * -vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id) -{ - struct vfio_info_cap_header *hdr; - void *ptr = info; - - if (!(info->flags & VFIO_REGION_INFO_FLAG_CAPS)) { - return NULL; - } - - for (hdr = ptr + info->cap_offset; hdr != ptr; hdr = ptr + hdr->next) { - if (hdr->id == id) { - return hdr; - } - } - - return NULL; -} - -static void vfio_setup_region_sparse_mmaps(VFIORegion *region, - struct vfio_region_info *info) -{ - struct vfio_info_cap_header *hdr; - struct vfio_region_info_cap_sparse_mmap *sparse; - int i; - - hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP); - if (!hdr) { - return; - } - - sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header); - - trace_vfio_region_sparse_mmap_header(region->vbasedev->name, - region->nr, sparse->nr_areas); - - region->nr_mmaps = sparse->nr_areas; - region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); - - for (i = 0; i < region->nr_mmaps; i++) { - region->mmaps[i].offset = sparse->areas[i].offset; - region->mmaps[i].size = sparse->areas[i].size; - trace_vfio_region_sparse_mmap_entry(i, region->mmaps[i].offset, - region->mmaps[i].offset + - region->mmaps[i].size); - } } int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, @@ -664,14 +522,11 @@ int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, region->flags & VFIO_REGION_INFO_FLAG_MMAP && !(region->size & ~qemu_real_host_page_mask)) { - vfio_setup_region_sparse_mmaps(region, info); + region->nr_mmaps = 1; + region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); - if (!region->nr_mmaps) { - region->nr_mmaps = 1; - region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); - region->mmaps[0].offset = 0; - region->mmaps[0].size = region->size; - } + region->mmaps[0].offset = 0; + region->mmaps[0].size = region->size; } } @@ -946,8 +801,8 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as) goto free_container_exit; } - container->iommu_type = v2 ? VFIO_TYPE1v2_IOMMU : VFIO_TYPE1_IOMMU; - ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type); + ret = ioctl(fd, VFIO_SET_IOMMU, + v2 ? VFIO_TYPE1v2_IOMMU : VFIO_TYPE1_IOMMU); if (ret) { error_report("vfio: failed to set iommu for container: %m"); ret = -errno; @@ -961,18 +816,19 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as) * existing Type1 IOMMUs generally support any IOVA we're * going to actually try in practice. */ + container->min_iova = 0; + container->max_iova = (hwaddr)-1; + + /* Assume just 4K IOVA page size */ + container->iova_pgsizes = 0x1000; info.argsz = sizeof(info); ret = ioctl(fd, VFIO_IOMMU_GET_INFO, &info); /* Ignore errors */ - if (ret || !(info.flags & VFIO_IOMMU_INFO_PGSIZES)) { - /* Assume 4k IOVA page size */ - info.iova_pgsizes = 4096; + if ((ret == 0) && (info.flags & VFIO_IOMMU_INFO_PGSIZES)) { + container->iova_pgsizes = info.iova_pgsizes; } - vfio_host_win_add(container, 0, (hwaddr)-1, info.iova_pgsizes); - } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU) || - ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_v2_IOMMU)) { + } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU)) { struct vfio_iommu_spapr_tce_info info; - bool v2 = !!ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_v2_IOMMU); ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd); if (ret) { @@ -980,9 +836,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as) ret = -errno; goto free_container_exit; } - container->iommu_type = - v2 ? VFIO_SPAPR_TCE_v2_IOMMU : VFIO_SPAPR_TCE_IOMMU; - ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type); + ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_SPAPR_TCE_IOMMU); if (ret) { error_report("vfio: failed to set iommu for container: %m"); ret = -errno; @@ -994,54 +848,30 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as) * when container fd is closed so we do not call it explicitly * in this file. */ - if (!v2) { - ret = ioctl(fd, VFIO_IOMMU_ENABLE); - if (ret) { - error_report("vfio: failed to enable container: %m"); - ret = -errno; - goto free_container_exit; - } - } else { - container->prereg_listener = vfio_prereg_listener; - - memory_listener_register(&container->prereg_listener, - &address_space_memory); - if (container->error) { - memory_listener_unregister(&container->prereg_listener); - error_report("vfio: RAM memory listener initialization failed for container"); - goto free_container_exit; - } + ret = ioctl(fd, VFIO_IOMMU_ENABLE); + if (ret) { + error_report("vfio: failed to enable container: %m"); + ret = -errno; + goto free_container_exit; } + /* + * This only considers the host IOMMU's 32-bit window. At + * some point we need to add support for the optional 64-bit + * window and dynamic windows + */ info.argsz = sizeof(info); ret = ioctl(fd, VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info); if (ret) { error_report("vfio: VFIO_IOMMU_SPAPR_TCE_GET_INFO failed: %m"); ret = -errno; - if (v2) { - memory_listener_unregister(&container->prereg_listener); - } goto free_container_exit; } + container->min_iova = info.dma32_window_start; + container->max_iova = container->min_iova + info.dma32_window_size - 1; - if (v2) { - /* - * There is a default window in just created container. - * To make region_add/del simpler, we better remove this - * window now and let those iommu_listener callbacks - * create/remove them when needed. - */ - ret = vfio_spapr_remove_window(container, info.dma32_window_start); - if (ret) { - goto free_container_exit; - } - } else { - /* The default table uses 4K pages */ - vfio_host_win_add(container, info.dma32_window_start, - info.dma32_window_start + - info.dma32_window_size - 1, - 0x1000); - } + /* Assume just 4K IOVA pages for now */ + container->iova_pgsizes = 0x1000; } else { error_report("vfio: No available IOMMU models"); ret = -EINVAL; @@ -1102,7 +932,7 @@ static void vfio_disconnect_container(VFIOGroup *group) QLIST_REMOVE(container, next); QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) { - memory_region_unregister_iommu_notifier(giommu->iommu, &giommu->n); + memory_region_unregister_iommu_notifier(&giommu->n); QLIST_REMOVE(giommu, giommu_next); g_free(giommu); } @@ -1256,60 +1086,16 @@ int vfio_get_region_info(VFIODevice *vbasedev, int index, *info = g_malloc0(argsz); (*info)->index = index; -retry: (*info)->argsz = argsz; if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) { g_free(*info); - *info = NULL; return -errno; } - if ((*info)->argsz > argsz) { - argsz = (*info)->argsz; - *info = g_realloc(*info, argsz); - - goto retry; - } - return 0; } -int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, - uint32_t subtype, struct vfio_region_info **info) -{ - int i; - - for (i = 0; i < vbasedev->num_regions; i++) { - struct vfio_info_cap_header *hdr; - struct vfio_region_info_cap_type *cap_type; - - if (vfio_get_region_info(vbasedev, i, info)) { - continue; - } - - hdr = vfio_get_region_info_cap(*info, VFIO_REGION_INFO_CAP_TYPE); - if (!hdr) { - g_free(*info); - continue; - } - - cap_type = container_of(hdr, struct vfio_region_info_cap_type, header); - - trace_vfio_get_dev_region(vbasedev->name, i, - cap_type->type, cap_type->subtype); - - if (cap_type->type == type && cap_type->subtype == subtype) { - return 0; - } - - g_free(*info); - } - - *info = NULL; - return -ENODEV; -} - /* * Interfaces for IBM EEH (Enhanced Error Handling) */ diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index bec694c8d..6624905e1 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -11,12 +11,9 @@ */ #include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "qemu/range.h" -#include "qapi/error.h" -#include "hw/nvram/fw_cfg.h" #include "pci.h" #include "trace.h" +#include "qemu/range.h" /* Use uin32_t for vendor & device so PCI_ANY_ID expands and cannot match hw */ static bool vfio_pci_is(VFIOPCIDevice *vdev, uint32_t vendor, uint32_t device) @@ -965,643 +962,6 @@ static void vfio_probe_rtl8168_bar2_quirk(VFIOPCIDevice *vdev, int nr) } /* - * Intel IGD support - * - * Obviously IGD is not a discrete device, this is evidenced not only by it - * being integrated into the CPU, but by the various chipset and BIOS - * dependencies that it brings along with it. Intel is trying to move away - * from this and Broadwell and newer devices can run in what Intel calls - * "Universal Pass-Through" mode, or UPT. Theoretically in UPT mode, nothing - * more is required beyond assigning the IGD device to a VM. There are - * however support limitations to this mode. It only supports IGD as a - * secondary graphics device in the VM and it doesn't officially support any - * physical outputs. - * - * The code here attempts to enable what we'll call legacy mode assignment, - * IGD retains most of the capabilities we expect for it to have on bare - * metal. To enable this mode, the IGD device must be assigned to the VM - * at PCI address 00:02.0, it must have a ROM, it very likely needs VGA - * support, we must have VM BIOS support for reserving and populating some - * of the required tables, and we need to tweak the chipset with revisions - * and IDs and an LPC/ISA bridge device. The intention is to make all of - * this happen automatically by installing the device at the correct VM PCI - * bus address. If any of the conditions are not met, we cross our fingers - * and hope the user knows better. - * - * NB - It is possible to enable physical outputs in UPT mode by supplying - * an OpRegion table. We don't do this by default because the guest driver - * behaves differently if an OpRegion is provided and no monitor is attached - * vs no OpRegion and a monitor being attached or not. Effectively, if a - * headless setup is desired, the OpRegion gets in the way of that. - */ - -/* - * This presumes the device is already known to be an Intel VGA device, so we - * take liberties in which device ID bits match which generation. This should - * not be taken as an indication that all the devices are supported, or even - * supportable, some of them don't even support VT-d. - * See linux:include/drm/i915_pciids.h for IDs. - */ -static int igd_gen(VFIOPCIDevice *vdev) -{ - if ((vdev->device_id & 0xfff) == 0xa84) { - return 8; /* Broxton */ - } - - switch (vdev->device_id & 0xff00) { - /* Old, untested, unavailable, unknown */ - case 0x0000: - case 0x2500: - case 0x2700: - case 0x2900: - case 0x2a00: - case 0x2e00: - case 0x3500: - case 0xa000: - return -1; - /* SandyBridge, IvyBridge, ValleyView, Haswell */ - case 0x0100: - case 0x0400: - case 0x0a00: - case 0x0c00: - case 0x0d00: - case 0x0f00: - return 6; - /* BroadWell, CherryView, SkyLake, KabyLake */ - case 0x1600: - case 0x1900: - case 0x2200: - case 0x5900: - return 8; - } - - return 8; /* Assume newer is compatible */ -} - -typedef struct VFIOIGDQuirk { - struct VFIOPCIDevice *vdev; - uint32_t index; -} VFIOIGDQuirk; - -#define IGD_GMCH 0x50 /* Graphics Control Register */ -#define IGD_BDSM 0x5c /* Base Data of Stolen Memory */ -#define IGD_ASLS 0xfc /* ASL Storage Register */ - -/* - * The OpRegion includes the Video BIOS Table, which seems important for - * telling the driver what sort of outputs it has. Without this, the device - * may work in the guest, but we may not get output. This also requires BIOS - * support to reserve and populate a section of guest memory sufficient for - * the table and to write the base address of that memory to the ASLS register - * of the IGD device. - */ -int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev, - struct vfio_region_info *info) -{ - int ret; - - vdev->igd_opregion = g_malloc0(info->size); - ret = pread(vdev->vbasedev.fd, vdev->igd_opregion, - info->size, info->offset); - if (ret != info->size) { - error_report("vfio: Error reading IGD OpRegion"); - g_free(vdev->igd_opregion); - vdev->igd_opregion = NULL; - return -EINVAL; - } - - /* - * Provide fw_cfg with a copy of the OpRegion which the VM firmware is to - * allocate 32bit reserved memory for, copy these contents into, and write - * the reserved memory base address to the device ASLS register at 0xFC. - * Alignment of this reserved region seems flexible, but using a 4k page - * alignment seems to work well. This interface assumes a single IGD - * device, which may be at VM address 00:02.0 in legacy mode or another - * address in UPT mode. - * - * NB, there may be future use cases discovered where the VM should have - * direct interaction with the host OpRegion, in which case the write to - * the ASLS register would trigger MemoryRegion setup to enable that. - */ - fw_cfg_add_file(fw_cfg_find(), "etc/igd-opregion", - vdev->igd_opregion, info->size); - - trace_vfio_pci_igd_opregion_enabled(vdev->vbasedev.name); - - pci_set_long(vdev->pdev.config + IGD_ASLS, 0); - pci_set_long(vdev->pdev.wmask + IGD_ASLS, ~0); - pci_set_long(vdev->emulated_config_bits + IGD_ASLS, ~0); - - return 0; -} - -/* - * The rather short list of registers that we copy from the host devices. - * The LPC/ISA bridge values are definitely needed to support the vBIOS, the - * host bridge values may or may not be needed depending on the guest OS. - * Since we're only munging revision and subsystem values on the host bridge, - * we don't require our own device. The LPC/ISA bridge needs to be our very - * own though. - */ -typedef struct { - uint8_t offset; - uint8_t len; -} IGDHostInfo; - -static const IGDHostInfo igd_host_bridge_infos[] = { - {PCI_REVISION_ID, 2}, - {PCI_SUBSYSTEM_VENDOR_ID, 2}, - {PCI_SUBSYSTEM_ID, 2}, -}; - -static const IGDHostInfo igd_lpc_bridge_infos[] = { - {PCI_VENDOR_ID, 2}, - {PCI_DEVICE_ID, 2}, - {PCI_REVISION_ID, 2}, - {PCI_SUBSYSTEM_VENDOR_ID, 2}, - {PCI_SUBSYSTEM_ID, 2}, -}; - -static int vfio_pci_igd_copy(VFIOPCIDevice *vdev, PCIDevice *pdev, - struct vfio_region_info *info, - const IGDHostInfo *list, int len) -{ - int i, ret; - - for (i = 0; i < len; i++) { - ret = pread(vdev->vbasedev.fd, pdev->config + list[i].offset, - list[i].len, info->offset + list[i].offset); - if (ret != list[i].len) { - error_report("IGD copy failed: %m"); - return -errno; - } - } - - return 0; -} - -/* - * Stuff a few values into the host bridge. - */ -static int vfio_pci_igd_host_init(VFIOPCIDevice *vdev, - struct vfio_region_info *info) -{ - PCIBus *bus; - PCIDevice *host_bridge; - int ret; - - bus = pci_device_root_bus(&vdev->pdev); - host_bridge = pci_find_device(bus, 0, PCI_DEVFN(0, 0)); - - if (!host_bridge) { - error_report("Can't find host bridge"); - return -ENODEV; - } - - ret = vfio_pci_igd_copy(vdev, host_bridge, info, igd_host_bridge_infos, - ARRAY_SIZE(igd_host_bridge_infos)); - if (!ret) { - trace_vfio_pci_igd_host_bridge_enabled(vdev->vbasedev.name); - } - - return ret; -} - -/* - * IGD LPC/ISA bridge support code. The vBIOS needs this, but we can't write - * arbitrary values into just any bridge, so we must create our own. We try - * to handle if the user has created it for us, which they might want to do - * to enable multifuction so we don't occupy the whole PCI slot. - */ -static void vfio_pci_igd_lpc_bridge_realize(PCIDevice *pdev, Error **errp) -{ - if (pdev->devfn != PCI_DEVFN(0x1f, 0)) { - error_setg(errp, "VFIO dummy ISA/LPC bridge must have address 1f.0"); - } -} - -static void vfio_pci_igd_lpc_bridge_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - dc->desc = "VFIO dummy ISA/LPC bridge for IGD assignment"; - dc->hotpluggable = false; - k->realize = vfio_pci_igd_lpc_bridge_realize; - k->class_id = PCI_CLASS_BRIDGE_ISA; -} - -static TypeInfo vfio_pci_igd_lpc_bridge_info = { - .name = "vfio-pci-igd-lpc-bridge", - .parent = TYPE_PCI_DEVICE, - .class_init = vfio_pci_igd_lpc_bridge_class_init, -}; - -static void vfio_pci_igd_register_types(void) -{ - type_register_static(&vfio_pci_igd_lpc_bridge_info); -} - -type_init(vfio_pci_igd_register_types) - -static int vfio_pci_igd_lpc_init(VFIOPCIDevice *vdev, - struct vfio_region_info *info) -{ - PCIDevice *lpc_bridge; - int ret; - - lpc_bridge = pci_find_device(pci_device_root_bus(&vdev->pdev), - 0, PCI_DEVFN(0x1f, 0)); - if (!lpc_bridge) { - lpc_bridge = pci_create_simple(pci_device_root_bus(&vdev->pdev), - PCI_DEVFN(0x1f, 0), "vfio-pci-igd-lpc-bridge"); - } - - ret = vfio_pci_igd_copy(vdev, lpc_bridge, info, igd_lpc_bridge_infos, - ARRAY_SIZE(igd_lpc_bridge_infos)); - if (!ret) { - trace_vfio_pci_igd_lpc_bridge_enabled(vdev->vbasedev.name); - } - - return ret; -} - -/* - * IGD Gen8 and newer support up to 8MB for the GTT and use a 64bit PTE - * entry, older IGDs use 2MB and 32bit. Each PTE maps a 4k page. Therefore - * we either have 2M/4k * 4 = 2k or 8M/4k * 8 = 16k as the maximum iobar index - * for programming the GTT. - * - * See linux:include/drm/i915_drm.h for shift and mask values. - */ -static int vfio_igd_gtt_max(VFIOPCIDevice *vdev) -{ - uint32_t gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, sizeof(gmch)); - int ggms, gen = igd_gen(vdev); - - gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, sizeof(gmch)); - ggms = (gmch >> (gen < 8 ? 8 : 6)) & 0x3; - if (gen > 6) { - ggms = 1 << ggms; - } - - ggms *= 1024 * 1024; - - return (ggms / (4 * 1024)) * (gen < 8 ? 4 : 8); -} - -/* - * The IGD ROM will make use of stolen memory (GGMS) for support of VESA modes. - * Somehow the host stolen memory range is used for this, but how the ROM gets - * it is a mystery, perhaps it's hardcoded into the ROM. Thankfully though, it - * reprograms the GTT through the IOBAR where we can trap it and transpose the - * programming to the VM allocated buffer. That buffer gets reserved by the VM - * firmware via the fw_cfg entry added below. Here we're just monitoring the - * IOBAR address and data registers to detect a write sequence targeting the - * GTTADR. This code is developed by observed behavior and doesn't have a - * direct spec reference, unfortunately. - */ -static uint64_t vfio_igd_quirk_data_read(void *opaque, - hwaddr addr, unsigned size) -{ - VFIOIGDQuirk *igd = opaque; - VFIOPCIDevice *vdev = igd->vdev; - - igd->index = ~0; - - return vfio_region_read(&vdev->bars[4].region, addr + 4, size); -} - -static void vfio_igd_quirk_data_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - VFIOIGDQuirk *igd = opaque; - VFIOPCIDevice *vdev = igd->vdev; - uint64_t val = data; - int gen = igd_gen(vdev); - - /* - * Programming the GGMS starts at index 0x1 and uses every 4th index (ie. - * 0x1, 0x5, 0x9, 0xd,...). For pre-Gen8 each 4-byte write is a whole PTE - * entry, with 0th bit enable set. For Gen8 and up, PTEs are 64bit, so - * entries 0x5 & 0xd are the high dword, in our case zero. Each PTE points - * to a 4k page, which we translate to a page from the VM allocated region, - * pointed to by the BDSM register. If this is not set, we fail. - * - * We trap writes to the full configured GTT size, but we typically only - * see the vBIOS writing up to (nearly) the 1MB barrier. In fact it often - * seems to miss the last entry for an even 1MB GTT. Doing a gratuitous - * write of that last entry does work, but is hopefully unnecessary since - * we clear the previous GTT on initialization. - */ - if ((igd->index % 4 == 1) && igd->index < vfio_igd_gtt_max(vdev)) { - if (gen < 8 || (igd->index % 8 == 1)) { - uint32_t base; - - base = pci_get_long(vdev->pdev.config + IGD_BDSM); - if (!base) { - hw_error("vfio-igd: Guest attempted to program IGD GTT before " - "BIOS reserved stolen memory. Unsupported BIOS?"); - } - - val = base | (data & ((1 << 20) - 1)); - } else { - val = 0; /* upper 32bits of pte, we only enable below 4G PTEs */ - } - - trace_vfio_pci_igd_bar4_write(vdev->vbasedev.name, - igd->index, data, val); - } - - vfio_region_write(&vdev->bars[4].region, addr + 4, val, size); - - igd->index = ~0; -} - -static const MemoryRegionOps vfio_igd_data_quirk = { - .read = vfio_igd_quirk_data_read, - .write = vfio_igd_quirk_data_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static uint64_t vfio_igd_quirk_index_read(void *opaque, - hwaddr addr, unsigned size) -{ - VFIOIGDQuirk *igd = opaque; - VFIOPCIDevice *vdev = igd->vdev; - - igd->index = ~0; - - return vfio_region_read(&vdev->bars[4].region, addr, size); -} - -static void vfio_igd_quirk_index_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - VFIOIGDQuirk *igd = opaque; - VFIOPCIDevice *vdev = igd->vdev; - - igd->index = data; - - vfio_region_write(&vdev->bars[4].region, addr, data, size); -} - -static const MemoryRegionOps vfio_igd_index_quirk = { - .read = vfio_igd_quirk_index_read, - .write = vfio_igd_quirk_index_write, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr) -{ - struct vfio_region_info *rom = NULL, *opregion = NULL, - *host = NULL, *lpc = NULL; - VFIOQuirk *quirk; - VFIOIGDQuirk *igd; - PCIDevice *lpc_bridge; - int i, ret, ggms_mb, gms_mb = 0, gen; - uint64_t *bdsm_size; - uint32_t gmch; - uint16_t cmd_orig, cmd; - - /* - * This must be an Intel VGA device at address 00:02.0 for us to even - * consider enabling legacy mode. The vBIOS has dependencies on the - * PCI bus address. - */ - if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) || - !vfio_is_vga(vdev) || nr != 4 || - &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev), - 0, PCI_DEVFN(0x2, 0))) { - return; - } - - /* - * We need to create an LPC/ISA bridge at PCI bus address 00:1f.0 that we - * can stuff host values into, so if there's already one there and it's not - * one we can hack on, legacy mode is no-go. Sorry Q35. - */ - lpc_bridge = pci_find_device(pci_device_root_bus(&vdev->pdev), - 0, PCI_DEVFN(0x1f, 0)); - if (lpc_bridge && !object_dynamic_cast(OBJECT(lpc_bridge), - "vfio-pci-igd-lpc-bridge")) { - error_report("IGD device %s cannot support legacy mode due to existing " - "devices at address 1f.0", vdev->vbasedev.name); - return; - } - - /* - * IGD is not a standard, they like to change their specs often. We - * only attempt to support back to SandBridge and we hope that newer - * devices maintain compatibility with generation 8. - */ - gen = igd_gen(vdev); - if (gen != 6 && gen != 8) { - error_report("IGD device %s is unsupported in legacy mode, " - "try SandyBridge or newer", vdev->vbasedev.name); - return; - } - - /* - * Most of what we're doing here is to enable the ROM to run, so if - * there's no ROM, there's no point in setting up this quirk. - * NB. We only seem to get BIOS ROMs, so a UEFI VM would need CSM support. - */ - ret = vfio_get_region_info(&vdev->vbasedev, - VFIO_PCI_ROM_REGION_INDEX, &rom); - if ((ret || !rom->size) && !vdev->pdev.romfile) { - error_report("IGD device %s has no ROM, legacy mode disabled", - vdev->vbasedev.name); - goto out; - } - - /* - * Ignore the hotplug corner case, mark the ROM failed, we can't - * create the devices we need for legacy mode in the hotplug scenario. - */ - if (vdev->pdev.qdev.hotplugged) { - error_report("IGD device %s hotplugged, ROM disabled, " - "legacy mode disabled", vdev->vbasedev.name); - vdev->rom_read_failed = true; - goto out; - } - - /* - * Check whether we have all the vfio device specific regions to - * support legacy mode (added in Linux v4.6). If not, bail. - */ - ret = vfio_get_dev_region_info(&vdev->vbasedev, - VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL, - VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, &opregion); - if (ret) { - error_report("IGD device %s does not support OpRegion access," - "legacy mode disabled", vdev->vbasedev.name); - goto out; - } - - ret = vfio_get_dev_region_info(&vdev->vbasedev, - VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL, - VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG, &host); - if (ret) { - error_report("IGD device %s does not support host bridge access," - "legacy mode disabled", vdev->vbasedev.name); - goto out; - } - - ret = vfio_get_dev_region_info(&vdev->vbasedev, - VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL, - VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG, &lpc); - if (ret) { - error_report("IGD device %s does not support LPC bridge access," - "legacy mode disabled", vdev->vbasedev.name); - goto out; - } - - gmch = vfio_pci_read_config(&vdev->pdev, IGD_GMCH, 4); - - /* - * If IGD VGA Disable is clear (expected) and VGA is not already enabled, - * try to enable it. Probably shouldn't be using legacy mode without VGA, - * but also no point in us enabling VGA if disabled in hardware. - */ - if (!(gmch & 0x2) && !vdev->vga && vfio_populate_vga(vdev)) { - error_report("IGD device %s failed to enable VGA access, " - "legacy mode disabled", vdev->vbasedev.name); - goto out; - } - - /* Create our LPC/ISA bridge */ - ret = vfio_pci_igd_lpc_init(vdev, lpc); - if (ret) { - error_report("IGD device %s failed to create LPC bridge, " - "legacy mode disabled", vdev->vbasedev.name); - goto out; - } - - /* Stuff some host values into the VM PCI host bridge */ - ret = vfio_pci_igd_host_init(vdev, host); - if (ret) { - error_report("IGD device %s failed to modify host bridge, " - "legacy mode disabled", vdev->vbasedev.name); - goto out; - } - - /* Setup OpRegion access */ - ret = vfio_pci_igd_opregion_init(vdev, opregion); - if (ret) { - error_report("IGD device %s failed to setup OpRegion, " - "legacy mode disabled", vdev->vbasedev.name); - goto out; - } - - /* Setup our quirk to munge GTT addresses to the VM allocated buffer */ - quirk = g_malloc0(sizeof(*quirk)); - quirk->mem = g_new0(MemoryRegion, 2); - quirk->nr_mem = 2; - igd = quirk->data = g_malloc0(sizeof(*igd)); - igd->vdev = vdev; - igd->index = ~0; - - memory_region_init_io(&quirk->mem[0], OBJECT(vdev), &vfio_igd_index_quirk, - igd, "vfio-igd-index-quirk", 4); - memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, - 0, &quirk->mem[0], 1); - - memory_region_init_io(&quirk->mem[1], OBJECT(vdev), &vfio_igd_data_quirk, - igd, "vfio-igd-data-quirk", 4); - memory_region_add_subregion_overlap(vdev->bars[nr].region.mem, - 4, &quirk->mem[1], 1); - - QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); - - /* Determine the size of stolen memory needed for GTT */ - ggms_mb = (gmch >> (gen < 8 ? 8 : 6)) & 0x3; - if (gen > 6) { - ggms_mb = 1 << ggms_mb; - } - - /* - * Assume we have no GMS memory, but allow it to be overrided by device - * option (experimental). The spec doesn't actually allow zero GMS when - * when IVD (IGD VGA Disable) is clear, but the claim is that it's unused, - * so let's not waste VM memory for it. - */ - gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8)); - - if (vdev->igd_gms) { - if (vdev->igd_gms <= 0x10) { - gms_mb = vdev->igd_gms * 32; - gmch |= vdev->igd_gms << (gen < 8 ? 3 : 8); - } else { - error_report("Unsupported IGD GMS value 0x%x", vdev->igd_gms); - vdev->igd_gms = 0; - } - } - - /* - * Request reserved memory for stolen memory via fw_cfg. VM firmware - * must allocate a 1MB aligned reserved memory region below 4GB with - * the requested size (in bytes) for use by the Intel PCI class VGA - * device at VM address 00:02.0. The base address of this reserved - * memory region must be written to the device BDSM regsiter at PCI - * config offset 0x5C. - */ - bdsm_size = g_malloc(sizeof(*bdsm_size)); - *bdsm_size = cpu_to_le64((ggms_mb + gms_mb) * 1024 * 1024); - fw_cfg_add_file(fw_cfg_find(), "etc/igd-bdsm-size", - bdsm_size, sizeof(*bdsm_size)); - - /* GMCH is read-only, emulated */ - pci_set_long(vdev->pdev.config + IGD_GMCH, gmch); - pci_set_long(vdev->pdev.wmask + IGD_GMCH, 0); - pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0); - - /* BDSM is read-write, emulated. The BIOS needs to be able to write it */ - pci_set_long(vdev->pdev.config + IGD_BDSM, 0); - pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0); - pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0); - - /* - * This IOBAR gives us access to GTTADR, which allows us to write to - * the GTT itself. So let's go ahead and write zero to all the GTT - * entries to avoid spurious DMA faults. Be sure I/O access is enabled - * before talking to the device. - */ - if (pread(vdev->vbasedev.fd, &cmd_orig, sizeof(cmd_orig), - vdev->config_offset + PCI_COMMAND) != sizeof(cmd_orig)) { - error_report("IGD device %s - failed to read PCI command register", - vdev->vbasedev.name); - } - - cmd = cmd_orig | PCI_COMMAND_IO; - - if (pwrite(vdev->vbasedev.fd, &cmd, sizeof(cmd), - vdev->config_offset + PCI_COMMAND) != sizeof(cmd)) { - error_report("IGD device %s - failed to write PCI command register", - vdev->vbasedev.name); - } - - for (i = 1; i < vfio_igd_gtt_max(vdev); i += 4) { - vfio_region_write(&vdev->bars[4].region, 0, i, 4); - vfio_region_write(&vdev->bars[4].region, 4, 0, 4); - } - - if (pwrite(vdev->vbasedev.fd, &cmd_orig, sizeof(cmd_orig), - vdev->config_offset + PCI_COMMAND) != sizeof(cmd_orig)) { - error_report("IGD device %s - failed to restore PCI command register", - vdev->vbasedev.name); - } - - trace_vfio_pci_igd_bdsm_enabled(vdev->vbasedev.name, ggms_mb + gms_mb); - -out: - g_free(rom); - g_free(opregion); - g_free(host); - g_free(lpc); -} - -/* * Common quirk probe entry points. */ void vfio_vga_quirk_setup(VFIOPCIDevice *vdev) @@ -1650,7 +1010,6 @@ void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr) vfio_probe_nvidia_bar5_quirk(vdev, nr); vfio_probe_nvidia_bar0_quirk(vdev, nr); vfio_probe_rtl8168_bar2_quirk(vdev, nr); - vfio_probe_igd_bar4_quirk(vdev, nr); } void vfio_bar_quirk_exit(VFIOPCIDevice *vdev, int nr) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 7bfa17ce3..d091d8cf0 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include <linux/vfio.h> #include <sys/ioctl.h> +#include <sys/mman.h> #include "hw/pci/msi.h" #include "hw/pci/msix.h" @@ -31,7 +32,6 @@ #include "sysemu/sysemu.h" #include "pci.h" #include "trace.h" -#include "qapi/error.h" #define MSIX_CAP_LENGTH 12 @@ -417,11 +417,11 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) } static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector, - int vector_n, bool msix) + MSIMessage *msg, bool msix) { int virq; - if ((msix && vdev->no_kvm_msix) || (!msix && vdev->no_kvm_msi)) { + if ((msix && vdev->no_kvm_msix) || (!msix && vdev->no_kvm_msi) || !msg) { return; } @@ -429,7 +429,7 @@ static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector, return; } - virq = kvm_irqchip_add_msi_route(kvm_state, vector_n, &vdev->pdev); + virq = kvm_irqchip_add_msi_route(kvm_state, *msg, &vdev->pdev); if (virq < 0) { event_notifier_cleanup(&vector->kvm_interrupt); return; @@ -458,7 +458,6 @@ static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg, PCIDevice *pdev) { kvm_irqchip_update_msi_route(kvm_state, vector->virq, msg, pdev); - kvm_irqchip_commit_routes(kvm_state); } static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, @@ -496,7 +495,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, vfio_update_kvm_msi_virq(vector, *msg, pdev); } } else { - vfio_add_kvm_msi_virq(vdev, vector, nr, true); + vfio_add_kvm_msi_virq(vdev, vector, msg, true); } /* @@ -640,6 +639,7 @@ retry: for (i = 0; i < vdev->nr_vectors; i++) { VFIOMSIVector *vector = &vdev->msi_vectors[i]; + MSIMessage msg = msi_get_message(&vdev->pdev, i); vector->vdev = vdev; vector->virq = -1; @@ -656,7 +656,7 @@ retry: * Attempt to enable route through KVM irqchip, * default to userspace handling if unavailable. */ - vfio_add_kvm_msi_virq(vdev, vector, i, false); + vfio_add_kvm_msi_virq(vdev, vector, &msg, false); } /* Set interrupt type prior to possible interrupts */ @@ -1171,7 +1171,6 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos) uint16_t ctrl; bool msi_64bit, msi_maskbit; int ret, entries; - Error *err = NULL; if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl), vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) { @@ -1185,13 +1184,12 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos) trace_vfio_msi_setup(vdev->vbasedev.name, pos); - ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit, &err); + ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit); if (ret < 0) { if (ret == -ENOTSUP) { return 0; } - error_prepend(&err, "vfio: msi_init failed: "); - error_report_err(err); + error_report("vfio: msi_init failed"); return ret; } vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0); @@ -1442,6 +1440,8 @@ static void vfio_bar_setup(VFIOPCIDevice *vdev, int nr) vdev->vbasedev.name, nr); } + vfio_bar_quirk_setup(vdev, nr); + pci_register_bar(&vdev->pdev, nr, type, bar->region.mem); } @@ -1452,6 +1452,29 @@ static void vfio_bars_setup(VFIOPCIDevice *vdev) for (i = 0; i < PCI_ROM_SLOT; i++) { vfio_bar_setup(vdev, i); } + + if (vdev->vga) { + memory_region_init_io(&vdev->vga->region[QEMU_PCI_VGA_MEM].mem, + OBJECT(vdev), &vfio_vga_ops, + &vdev->vga->region[QEMU_PCI_VGA_MEM], + "vfio-vga-mmio@0xa0000", + QEMU_PCI_VGA_MEM_SIZE); + memory_region_init_io(&vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem, + OBJECT(vdev), &vfio_vga_ops, + &vdev->vga->region[QEMU_PCI_VGA_IO_LO], + "vfio-vga-io@0x3b0", + QEMU_PCI_VGA_IO_LO_SIZE); + memory_region_init_io(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem, + OBJECT(vdev), &vfio_vga_ops, + &vdev->vga->region[QEMU_PCI_VGA_IO_HI], + "vfio-vga-io@0x3c0", + QEMU_PCI_VGA_IO_HI_SIZE); + + pci_register_vga(&vdev->pdev, &vdev->vga->region[QEMU_PCI_VGA_MEM].mem, + &vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem, + &vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem); + vfio_vga_quirk_setup(vdev); + } } static void vfio_bars_exit(VFIOPCIDevice *vdev) @@ -1505,21 +1528,6 @@ static uint8_t vfio_std_cap_max_size(PCIDevice *pdev, uint8_t pos) return next - pos; } - -static uint16_t vfio_ext_cap_max_size(const uint8_t *config, uint16_t pos) -{ - uint16_t tmp, next = PCIE_CONFIG_SPACE_SIZE; - - for (tmp = PCI_CONFIG_SPACE_SIZE; tmp; - tmp = PCI_EXT_CAP_NEXT(pci_get_long(config + tmp))) { - if (tmp > pos && tmp < next) { - next = tmp; - } - } - - return next - pos; -} - static void vfio_set_word_bits(uint8_t *buf, uint16_t val, uint16_t mask) { pci_set_word(buf, (pci_get_word(buf) & ~mask) | val); @@ -1767,101 +1775,16 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos) return 0; } -static int vfio_add_ext_cap(VFIOPCIDevice *vdev) -{ - PCIDevice *pdev = &vdev->pdev; - uint32_t header; - uint16_t cap_id, next, size; - uint8_t cap_ver; - uint8_t *config; - - /* Only add extended caps if we have them and the guest can see them */ - if (!pci_is_express(pdev) || !pci_bus_is_express(pdev->bus) || - !pci_get_long(pdev->config + PCI_CONFIG_SPACE_SIZE)) { - return 0; - } - - /* - * pcie_add_capability always inserts the new capability at the tail - * of the chain. Therefore to end up with a chain that matches the - * physical device, we cache the config space to avoid overwriting - * the original config space when we parse the extended capabilities. - */ - config = g_memdup(pdev->config, vdev->config_size); - - /* - * Extended capabilities are chained with each pointing to the next, so we - * can drop anything other than the head of the chain simply by modifying - * the previous next pointer. For the head of the chain, we can modify the - * capability ID to something that cannot match a valid capability. ID - * 0 is reserved for this since absence of capabilities is indicated by - * 0 for the ID, version, AND next pointer. However, pcie_add_capability() - * uses ID 0 as reserved for list management and will incorrectly match and - * assert if we attempt to pre-load the head of the chain with with this - * ID. Use ID 0xFFFF temporarily since it is also seems to be reserved in - * part for identifying absence of capabilities in a root complex register - * block. If the ID still exists after adding capabilities, switch back to - * zero. We'll mark this entire first dword as emulated for this purpose. - */ - pci_set_long(pdev->config + PCI_CONFIG_SPACE_SIZE, - PCI_EXT_CAP(0xFFFF, 0, 0)); - pci_set_long(pdev->wmask + PCI_CONFIG_SPACE_SIZE, 0); - pci_set_long(vdev->emulated_config_bits + PCI_CONFIG_SPACE_SIZE, ~0); - - for (next = PCI_CONFIG_SPACE_SIZE; next; - next = PCI_EXT_CAP_NEXT(pci_get_long(config + next))) { - header = pci_get_long(config + next); - cap_id = PCI_EXT_CAP_ID(header); - cap_ver = PCI_EXT_CAP_VER(header); - - /* - * If it becomes important to configure extended capabilities to their - * actual size, use this as the default when it's something we don't - * recognize. Since QEMU doesn't actually handle many of the config - * accesses, exact size doesn't seem worthwhile. - */ - size = vfio_ext_cap_max_size(config, next); - - /* Use emulated next pointer to allow dropping extended caps */ - pci_long_test_and_set_mask(vdev->emulated_config_bits + next, - PCI_EXT_CAP_NEXT_MASK); - - switch (cap_id) { - case PCI_EXT_CAP_ID_SRIOV: /* Read-only VF BARs confuse OVMF */ - case PCI_EXT_CAP_ID_ARI: /* XXX Needs next function virtualization */ - trace_vfio_add_ext_cap_dropped(vdev->vbasedev.name, cap_id, next); - break; - default: - pcie_add_capability(pdev, cap_id, cap_ver, next, size); - } - - } - - /* Cleanup chain head ID if necessary */ - if (pci_get_word(pdev->config + PCI_CONFIG_SPACE_SIZE) == 0xFFFF) { - pci_set_word(pdev->config + PCI_CONFIG_SPACE_SIZE, 0); - } - - g_free(config); - return 0; -} - static int vfio_add_capabilities(VFIOPCIDevice *vdev) { PCIDevice *pdev = &vdev->pdev; - int ret; if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST) || !pdev->config[PCI_CAPABILITY_LIST]) { return 0; /* Nothing to add */ } - ret = vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST]); - if (ret) { - return ret; - } - - return vfio_add_ext_cap(vdev); + return vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST]); } static void vfio_pci_pre_reset(VFIOPCIDevice *vdev) @@ -2138,61 +2061,42 @@ int vfio_populate_vga(VFIOPCIDevice *vdev) struct vfio_region_info *reg_info; int ret; - ret = vfio_get_region_info(vbasedev, VFIO_PCI_VGA_REGION_INDEX, ®_info); - if (ret) { - return ret; - } - - if (!(reg_info->flags & VFIO_REGION_INFO_FLAG_READ) || - !(reg_info->flags & VFIO_REGION_INFO_FLAG_WRITE) || - reg_info->size < 0xbffff + 1) { - error_report("vfio: Unexpected VGA info, flags 0x%lx, size 0x%lx", - (unsigned long)reg_info->flags, - (unsigned long)reg_info->size); - g_free(reg_info); - return -EINVAL; - } - - vdev->vga = g_new0(VFIOVGA, 1); - - vdev->vga->fd_offset = reg_info->offset; - vdev->vga->fd = vdev->vbasedev.fd; - - g_free(reg_info); + if (vbasedev->num_regions > VFIO_PCI_VGA_REGION_INDEX) { + ret = vfio_get_region_info(vbasedev, + VFIO_PCI_VGA_REGION_INDEX, ®_info); + if (ret) { + return ret; + } - vdev->vga->region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE; - vdev->vga->region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM; - QLIST_INIT(&vdev->vga->region[QEMU_PCI_VGA_MEM].quirks); + if (!(reg_info->flags & VFIO_REGION_INFO_FLAG_READ) || + !(reg_info->flags & VFIO_REGION_INFO_FLAG_WRITE) || + reg_info->size < 0xbffff + 1) { + error_report("vfio: Unexpected VGA info, flags 0x%lx, size 0x%lx", + (unsigned long)reg_info->flags, + (unsigned long)reg_info->size); + g_free(reg_info); + return -EINVAL; + } - memory_region_init_io(&vdev->vga->region[QEMU_PCI_VGA_MEM].mem, - OBJECT(vdev), &vfio_vga_ops, - &vdev->vga->region[QEMU_PCI_VGA_MEM], - "vfio-vga-mmio@0xa0000", - QEMU_PCI_VGA_MEM_SIZE); + vdev->vga = g_new0(VFIOVGA, 1); - vdev->vga->region[QEMU_PCI_VGA_IO_LO].offset = QEMU_PCI_VGA_IO_LO_BASE; - vdev->vga->region[QEMU_PCI_VGA_IO_LO].nr = QEMU_PCI_VGA_IO_LO; - QLIST_INIT(&vdev->vga->region[QEMU_PCI_VGA_IO_LO].quirks); + vdev->vga->fd_offset = reg_info->offset; + vdev->vga->fd = vdev->vbasedev.fd; - memory_region_init_io(&vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem, - OBJECT(vdev), &vfio_vga_ops, - &vdev->vga->region[QEMU_PCI_VGA_IO_LO], - "vfio-vga-io@0x3b0", - QEMU_PCI_VGA_IO_LO_SIZE); + g_free(reg_info); - vdev->vga->region[QEMU_PCI_VGA_IO_HI].offset = QEMU_PCI_VGA_IO_HI_BASE; - vdev->vga->region[QEMU_PCI_VGA_IO_HI].nr = QEMU_PCI_VGA_IO_HI; - QLIST_INIT(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].quirks); + vdev->vga->region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE; + vdev->vga->region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM; + QLIST_INIT(&vdev->vga->region[QEMU_PCI_VGA_MEM].quirks); - memory_region_init_io(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem, - OBJECT(vdev), &vfio_vga_ops, - &vdev->vga->region[QEMU_PCI_VGA_IO_HI], - "vfio-vga-io@0x3c0", - QEMU_PCI_VGA_IO_HI_SIZE); + vdev->vga->region[QEMU_PCI_VGA_IO_LO].offset = QEMU_PCI_VGA_IO_LO_BASE; + vdev->vga->region[QEMU_PCI_VGA_IO_LO].nr = QEMU_PCI_VGA_IO_LO; + QLIST_INIT(&vdev->vga->region[QEMU_PCI_VGA_IO_LO].quirks); - pci_register_vga(&vdev->pdev, &vdev->vga->region[QEMU_PCI_VGA_MEM].mem, - &vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem, - &vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem); + vdev->vga->region[QEMU_PCI_VGA_IO_HI].offset = QEMU_PCI_VGA_IO_HI_BASE; + vdev->vga->region[QEMU_PCI_VGA_IO_HI].nr = QEMU_PCI_VGA_IO_HI; + QLIST_INIT(&vdev->vga->region[QEMU_PCI_VGA_IO_HI].quirks); + } return 0; } @@ -2494,7 +2398,7 @@ static int vfio_initfn(PCIDevice *pdev) ssize_t len; struct stat st; int groupid; - int i, ret; + int ret; if (!vdev->vbasedev.sysfsdev) { vdev->vbasedev.sysfsdev = @@ -2656,43 +2560,6 @@ static int vfio_initfn(PCIDevice *pdev) goto out_teardown; } - if (vdev->vga) { - vfio_vga_quirk_setup(vdev); - } - - for (i = 0; i < PCI_ROM_SLOT; i++) { - vfio_bar_quirk_setup(vdev, i); - } - - if (!vdev->igd_opregion && - vdev->features & VFIO_FEATURE_ENABLE_IGD_OPREGION) { - struct vfio_region_info *opregion; - - if (vdev->pdev.qdev.hotplugged) { - error_report("Cannot support IGD OpRegion feature on hotplugged " - "device %s", vdev->vbasedev.name); - ret = -EINVAL; - goto out_teardown; - } - - ret = vfio_get_dev_region_info(&vdev->vbasedev, - VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL, - VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, &opregion); - if (ret) { - error_report("Device %s does not support requested IGD OpRegion " - "feature", vdev->vbasedev.name); - goto out_teardown; - } - - ret = vfio_pci_igd_opregion_init(vdev, opregion); - g_free(opregion); - if (ret) { - error_report("Device %s IGD OpRegion initialization failed", - vdev->vbasedev.name); - goto out_teardown; - } - } - /* QEMU emulates all of MSI & MSIX */ if (pdev->cap_present & QEMU_PCI_CAP_MSIX) { memset(vdev->emulated_config_bits + pdev->msix_cap, 0xff, @@ -2736,13 +2603,6 @@ static void vfio_instance_finalize(Object *obj) vfio_bars_finalize(vdev); g_free(vdev->emulated_config_bits); g_free(vdev->rom); - /* - * XXX Leaking igd_opregion is not an oversight, we can't remove the - * fw_cfg entry therefore leaking this allocation seems like the safest - * option. - * - * g_free(vdev->igd_opregion); - */ vfio_put_device(vdev); vfio_put_group(group); } @@ -2817,8 +2677,6 @@ static Property vfio_pci_dev_properties[] = { VFIO_FEATURE_ENABLE_VGA_BIT, false), DEFINE_PROP_BIT("x-req", VFIOPCIDevice, features, VFIO_FEATURE_ENABLE_REQ_BIT, true), - DEFINE_PROP_BIT("x-igd-opregion", VFIOPCIDevice, features, - VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT, false), DEFINE_PROP_BOOL("x-no-mmap", VFIOPCIDevice, vbasedev.no_mmap, false), DEFINE_PROP_BOOL("x-no-kvm-intx", VFIOPCIDevice, no_kvm_intx, false), DEFINE_PROP_BOOL("x-no-kvm-msi", VFIOPCIDevice, no_kvm_msi, false), @@ -2829,7 +2687,6 @@ static Property vfio_pci_dev_properties[] = { sub_vendor_id, PCI_ANY_ID), DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice, sub_device_id, PCI_ANY_ID), - DEFINE_PROP_UINT32("x-igd-gms", VFIOPCIDevice, igd_gms, 0), /* * TODO - support passed fds... is this necessary? * DEFINE_PROP_STRING("vfiofd", VFIOPCIDevice, vfiofd_name), diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 7d482d9d2..72174b3dd 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -115,7 +115,6 @@ typedef struct VFIOPCIDevice { int interrupt; /* Current interrupt type */ VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */ VFIOVGA *vga; /* 0xa0000, 0x3b0, 0x3c0 */ - void *igd_opregion; PCIHostDeviceAddress host; EventNotifier err_notifier; EventNotifier req_notifier; @@ -129,11 +128,7 @@ typedef struct VFIOPCIDevice { #define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT) #define VFIO_FEATURE_ENABLE_REQ_BIT 1 #define VFIO_FEATURE_ENABLE_REQ (1 << VFIO_FEATURE_ENABLE_REQ_BIT) -#define VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT 2 -#define VFIO_FEATURE_ENABLE_IGD_OPREGION \ - (1 << VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT) int32_t bootindex; - uint32_t igd_gms; uint8_t pm_cap; bool pci_aer; bool req_enabled; @@ -163,7 +158,4 @@ void vfio_setup_resetfn_quirk(VFIOPCIDevice *vdev); int vfio_populate_vga(VFIOPCIDevice *vdev); -int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev, - struct vfio_region_info *info); - #endif /* HW_VFIO_VFIO_PCI_H */ diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index a559e7b65..1798a00a3 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -496,7 +496,7 @@ static int vfio_populate_device(VFIODevice *vbasedev) irq.index = i; ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq); if (ret) { - error_report("vfio: error getting device %s irq info", + error_printf("vfio: error getting device %s irq info", vbasedev->name); goto irq_err; } else { diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c deleted file mode 100644 index 7443d348d..000000000 --- a/hw/vfio/spapr.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * DMA memory preregistration - * - * Authors: - * Alexey Kardashevskiy <aik@ozlabs.ru> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include <sys/ioctl.h> -#include <linux/vfio.h> - -#include "hw/vfio/vfio-common.h" -#include "hw/hw.h" -#include "qemu/error-report.h" -#include "trace.h" - -static bool vfio_prereg_listener_skipped_section(MemoryRegionSection *section) -{ - if (memory_region_is_iommu(section->mr)) { - hw_error("Cannot possibly preregister IOMMU memory"); - } - - return !memory_region_is_ram(section->mr) || - memory_region_is_skip_dump(section->mr); -} - -static void *vfio_prereg_gpa_to_vaddr(MemoryRegionSection *section, hwaddr gpa) -{ - return memory_region_get_ram_ptr(section->mr) + - section->offset_within_region + - (gpa - section->offset_within_address_space); -} - -static void vfio_prereg_listener_region_add(MemoryListener *listener, - MemoryRegionSection *section) -{ - VFIOContainer *container = container_of(listener, VFIOContainer, - prereg_listener); - const hwaddr gpa = section->offset_within_address_space; - hwaddr end; - int ret; - hwaddr page_mask = qemu_real_host_page_mask; - struct vfio_iommu_spapr_register_memory reg = { - .argsz = sizeof(reg), - .flags = 0, - }; - - if (vfio_prereg_listener_skipped_section(section)) { - trace_vfio_prereg_listener_region_add_skip( - section->offset_within_address_space, - section->offset_within_address_space + - int128_get64(int128_sub(section->size, int128_one()))); - return; - } - - if (unlikely((section->offset_within_address_space & ~page_mask) || - (section->offset_within_region & ~page_mask) || - (int128_get64(section->size) & ~page_mask))) { - error_report("%s received unaligned region", __func__); - return; - } - - end = section->offset_within_address_space + int128_get64(section->size); - if (gpa >= end) { - return; - } - - memory_region_ref(section->mr); - - reg.vaddr = (uintptr_t) vfio_prereg_gpa_to_vaddr(section, gpa); - reg.size = end - gpa; - - ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_REGISTER_MEMORY, ®); - trace_vfio_prereg_register(reg.vaddr, reg.size, ret ? -errno : 0); - if (ret) { - /* - * On the initfn path, store the first error in the container so we - * can gracefully fail. Runtime, there's not much we can do other - * than throw a hardware error. - */ - if (!container->initialized) { - if (!container->error) { - container->error = ret; - } - } else { - hw_error("vfio: Memory registering failed, unable to continue"); - } - } -} - -static void vfio_prereg_listener_region_del(MemoryListener *listener, - MemoryRegionSection *section) -{ - VFIOContainer *container = container_of(listener, VFIOContainer, - prereg_listener); - const hwaddr gpa = section->offset_within_address_space; - hwaddr end; - int ret; - hwaddr page_mask = qemu_real_host_page_mask; - struct vfio_iommu_spapr_register_memory reg = { - .argsz = sizeof(reg), - .flags = 0, - }; - - if (vfio_prereg_listener_skipped_section(section)) { - trace_vfio_prereg_listener_region_del_skip( - section->offset_within_address_space, - section->offset_within_address_space + - int128_get64(int128_sub(section->size, int128_one()))); - return; - } - - if (unlikely((section->offset_within_address_space & ~page_mask) || - (section->offset_within_region & ~page_mask) || - (int128_get64(section->size) & ~page_mask))) { - error_report("%s received unaligned region", __func__); - return; - } - - end = section->offset_within_address_space + int128_get64(section->size); - if (gpa >= end) { - return; - } - - reg.vaddr = (uintptr_t) vfio_prereg_gpa_to_vaddr(section, gpa); - reg.size = end - gpa; - - ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_UNREGISTER_MEMORY, ®); - trace_vfio_prereg_unregister(reg.vaddr, reg.size, ret ? -errno : 0); -} - -const MemoryListener vfio_prereg_listener = { - .region_add = vfio_prereg_listener_region_add, - .region_del = vfio_prereg_listener_region_del, -}; - -int vfio_spapr_create_window(VFIOContainer *container, - MemoryRegionSection *section, - hwaddr *pgsize) -{ - int ret; - unsigned pagesize = memory_region_iommu_get_min_page_size(section->mr); - unsigned entries, pages; - struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) }; - - /* - * FIXME: For VFIO iommu types which have KVM acceleration to - * avoid bouncing all map/unmaps through qemu this way, this - * would be the right place to wire that up (tell the KVM - * device emulation the VFIO iommu handles to use). - */ - create.window_size = int128_get64(section->size); - create.page_shift = ctz64(pagesize); - /* - * SPAPR host supports multilevel TCE tables, there is some - * heuristic to decide how many levels we want for our table: - * 0..64 = 1; 65..4096 = 2; 4097..262144 = 3; 262145.. = 4 - */ - entries = create.window_size >> create.page_shift; - pages = MAX((entries * sizeof(uint64_t)) / getpagesize(), 1); - pages = MAX(pow2ceil(pages) - 1, 1); /* Round up */ - create.levels = ctz64(pages) / 6 + 1; - - ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create); - if (ret) { - error_report("Failed to create a window, ret = %d (%m)", ret); - return -errno; - } - - if (create.start_addr != section->offset_within_address_space) { - vfio_spapr_remove_window(container, create.start_addr); - - error_report("Host doesn't support DMA window at %"HWADDR_PRIx", must be %"PRIx64, - section->offset_within_address_space, - (uint64_t)create.start_addr); - return -EINVAL; - } - trace_vfio_spapr_create_window(create.page_shift, - create.window_size, - create.start_addr); - *pgsize = pagesize; - - return 0; -} - -int vfio_spapr_remove_window(VFIOContainer *container, - hwaddr offset_within_address_space) -{ - struct vfio_iommu_spapr_tce_remove remove = { - .argsz = sizeof(remove), - .start_addr = offset_within_address_space, - }; - int ret; - - ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_REMOVE, &remove); - if (ret) { - error_report("Failed to remove window at %"PRIx64, - (uint64_t)remove.start_addr); - return -errno; - } - - trace_vfio_spapr_remove_window(offset_within_address_space); - - return 0; -} diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events deleted file mode 100644 index da133221d..000000000 --- a/hw/vfio/trace-events +++ /dev/null @@ -1,125 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/vfio/pci.c -vfio_intx_interrupt(const char *name, char line) " (%s) Pin %c" -vfio_intx_eoi(const char *name) " (%s) EOI" -vfio_intx_enable_kvm(const char *name) " (%s) KVM INTx accel enabled" -vfio_intx_disable_kvm(const char *name) " (%s) KVM INTx accel disabled" -vfio_intx_update(const char *name, int new_irq, int target_irq) " (%s) IRQ moved %d -> %d" -vfio_intx_enable(const char *name) " (%s)" -vfio_intx_disable(const char *name) " (%s)" -vfio_msi_interrupt(const char *name, int index, uint64_t addr, int data) " (%s) vector %d 0x%"PRIx64"/0x%x" -vfio_msix_vector_do_use(const char *name, int index) " (%s) vector %d used" -vfio_msix_vector_release(const char *name, int index) " (%s) vector %d released" -vfio_msix_enable(const char *name) " (%s)" -vfio_msix_pba_disable(const char *name) " (%s)" -vfio_msix_pba_enable(const char *name) " (%s)" -vfio_msix_disable(const char *name) " (%s)" -vfio_msix_fixup(const char *name, int bar, uint64_t start, uint64_t end) " (%s) MSI-X region %d mmap fixup [0x%"PRIx64" - 0x%"PRIx64"]" -vfio_msi_enable(const char *name, int nr_vectors) " (%s) Enabled %d MSI vectors" -vfio_msi_disable(const char *name) " (%s)" -vfio_pci_load_rom(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device %s ROM:\n size: 0x%lx, offset: 0x%lx, flags: 0x%lx" -vfio_rom_read(const char *name, uint64_t addr, int size, uint64_t data) " (%s, 0x%"PRIx64", 0x%x) = 0x%"PRIx64 -vfio_pci_size_rom(const char *name, int size) "%s ROM size 0x%x" -vfio_vga_write(uint64_t addr, uint64_t data, int size) " (0x%"PRIx64", 0x%"PRIx64", %d)" -vfio_vga_read(uint64_t addr, int size, uint64_t data) " (0x%"PRIx64", %d) = 0x%"PRIx64 -vfio_pci_read_config(const char *name, int addr, int len, int val) " (%s, @0x%x, len=0x%x) %x" -vfio_pci_write_config(const char *name, int addr, int val, int len) " (%s, @0x%x, 0x%x, len=0x%x)" -vfio_msi_setup(const char *name, int pos) "%s PCI MSI CAP @0x%x" -vfio_msix_early_setup(const char *name, int pos, int table_bar, int offset, int entries) "%s PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d" -vfio_check_pcie_flr(const char *name) "%s Supports FLR via PCIe cap" -vfio_check_pm_reset(const char *name) "%s Supports PM reset" -vfio_check_af_flr(const char *name) "%s Supports FLR via AF cap" -vfio_pci_hot_reset(const char *name, const char *type) " (%s) %s" -vfio_pci_hot_reset_has_dep_devices(const char *name) "%s: hot reset dependent devices:" -vfio_pci_hot_reset_dep_devices(int domain, int bus, int slot, int function, int group_id) "\t%04x:%02x:%02x.%x group %d" -vfio_pci_hot_reset_result(const char *name, const char *result) "%s hot reset: %s" -vfio_populate_device_config(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device %s config:\n size: 0x%lx, offset: 0x%lx, flags: 0x%lx" -vfio_populate_device_get_irq_info_failure(void) "VFIO_DEVICE_GET_IRQ_INFO failure: %m" -vfio_initfn(const char *name, int group_id) " (%s) group %d" -vfio_add_ext_cap_dropped(const char *name, uint16_t cap, uint16_t offset) "%s %x@%x" -vfio_pci_reset(const char *name) " (%s)" -vfio_pci_reset_flr(const char *name) "%s FLR/VFIO_DEVICE_RESET" -vfio_pci_reset_pm(const char *name) "%s PCI PM Reset" -vfio_pci_emulated_vendor_id(const char *name, uint16_t val) "%s %04x" -vfio_pci_emulated_device_id(const char *name, uint16_t val) "%s %04x" -vfio_pci_emulated_sub_vendor_id(const char *name, uint16_t val) "%s %04x" -vfio_pci_emulated_sub_device_id(const char *name, uint16_t val) "%s %04x" - -# hw/vfio/pci-quirks. -vfio_quirk_rom_blacklisted(const char *name, uint16_t vid, uint16_t did) "%s %04x:%04x" -vfio_quirk_generic_window_address_write(const char *name, const char * region_name, uint64_t data) "%s %s 0x%"PRIx64 -vfio_quirk_generic_window_data_read(const char *name, const char * region_name, uint64_t data) "%s %s 0x%"PRIx64 -vfio_quirk_generic_window_data_write(const char *name, const char * region_name, uint64_t data) "%s %s 0x%"PRIx64 -vfio_quirk_generic_mirror_read(const char *name, const char * region_name, uint64_t addr, uint64_t data) "%s %s 0x%"PRIx64": 0x%"PRIx64 -vfio_quirk_generic_mirror_write(const char *name, const char * region_name, uint64_t addr, uint64_t data) "%s %s 0x%"PRIx64": 0x%"PRIx64 -vfio_quirk_ati_3c3_read(const char *name, uint64_t data) "%s 0x%"PRIx64 -vfio_quirk_ati_3c3_probe(const char *name) "%s" -vfio_quirk_ati_bar4_probe(const char *name) "%s" -vfio_quirk_ati_bar2_probe(const char *name) "%s" -vfio_quirk_nvidia_3d0_state(const char *name, const char *state) "%s %s" -vfio_quirk_nvidia_3d0_read(const char *name, uint8_t offset, unsigned size, uint64_t val) " (%s, @0x%x, len=0x%x) %"PRIx64 -vfio_quirk_nvidia_3d0_write(const char *name, uint8_t offset, uint64_t data, unsigned size) "(%s, @0x%x, 0x%"PRIx64", len=0x%x)" -vfio_quirk_nvidia_3d0_probe(const char *name) "%s" -vfio_quirk_nvidia_bar5_state(const char *name, const char *state) "%s %s" -vfio_quirk_nvidia_bar5_probe(const char *name) "%s" -vfio_quirk_nvidia_bar0_msi_ack(const char *name) "%s" -vfio_quirk_nvidia_bar0_probe(const char *name) "%s" -vfio_quirk_rtl8168_fake_latch(const char *name, uint64_t val) "%s 0x%"PRIx64 -vfio_quirk_rtl8168_msix_write(const char *name, uint16_t offset, uint64_t val) "%s MSI-X table write[0x%x]: 0x%"PRIx64 -vfio_quirk_rtl8168_msix_read(const char *name, uint16_t offset, uint64_t val) "%s MSI-X table read[0x%x]: 0x%"PRIx64 -vfio_quirk_rtl8168_probe(const char *name) "%s" - -vfio_quirk_ati_bonaire_reset_skipped(const char *name) "%s" -vfio_quirk_ati_bonaire_reset_no_smc(const char *name) "%s" -vfio_quirk_ati_bonaire_reset_timeout(const char *name) "%s" -vfio_quirk_ati_bonaire_reset_done(const char *name) "%s" -vfio_quirk_ati_bonaire_reset(const char *name) "%s" -vfio_pci_igd_bar4_write(const char *name, uint32_t index, uint32_t data, uint32_t base) "%s [%03x] %08x -> %08x" -vfio_pci_igd_bdsm_enabled(const char *name, int size) "%s %dMB" -vfio_pci_igd_opregion_enabled(const char *name) "%s" -vfio_pci_igd_host_bridge_enabled(const char *name) "%s" -vfio_pci_igd_lpc_bridge_enabled(const char *name) "%s" - -# hw/vfio/common.c -vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)" -vfio_region_read(char *name, int index, uint64_t addr, unsigned size, uint64_t data) " (%s:region%d+0x%"PRIx64", %d) = 0x%"PRIx64 -vfio_iommu_map_notify(uint64_t iova_start, uint64_t iova_end) "iommu map @ %"PRIx64" - %"PRIx64 -vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add %"PRIx64" - %"PRIx64 -vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] %"PRIx64" - %"PRIx64 -vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] %"PRIx64" - %"PRIx64" [%p]" -vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del %"PRIx64" - %"PRIx64 -vfio_listener_region_del(uint64_t start, uint64_t end) "region_del %"PRIx64" - %"PRIx64 -vfio_disconnect_container(int fd) "close container->fd=%d" -vfio_put_group(int fd) "close group->fd=%d" -vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u" -vfio_put_base_device(int fd) "close vdev->fd=%d" -vfio_region_setup(const char *dev, int index, const char *name, unsigned long flags, unsigned long offset, unsigned long size) "Device %s, region %d \"%s\", flags: %lx, offset: %lx, size: %lx" -vfio_region_mmap_fault(const char *name, int index, unsigned long offset, unsigned long size, int fault) "Region %s mmaps[%d], [%lx - %lx], fault: %d" -vfio_region_mmap(const char *name, unsigned long offset, unsigned long end) "Region %s [%lx - %lx]" -vfio_region_exit(const char *name, int index) "Device %s, region %d" -vfio_region_finalize(const char *name, int index) "Device %s, region %d" -vfio_region_mmaps_set_enabled(const char *name, bool enabled) "Region %s mmaps enabled: %d" -vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Device %s region %d: %d sparse mmap entries" -vfio_region_sparse_mmap_entry(int i, unsigned long start, unsigned long end) "sparse entry %d [0x%lx - 0x%lx]" -vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%0x8" - -# hw/vfio/platform.c -vfio_platform_base_device_init(char *name, int groupid) "%s belongs to group #%d" -vfio_platform_realize(char *name, char *compat) "vfio device %s, compat = %s" -vfio_platform_eoi(int pin, int fd) "EOI IRQ pin %d (fd=%d)" -vfio_platform_intp_mmap_enable(int pin) "IRQ #%d still active, stay in slow path" -vfio_platform_intp_interrupt(int pin, int fd) "Inject IRQ #%d (fd = %d)" -vfio_platform_intp_inject_pending_lockheld(int pin, int fd) "Inject pending IRQ #%d (fd = %d)" -vfio_platform_populate_interrupts(int pin, int count, int flags) "- IRQ index %d: count %d, flags=0x%x" -vfio_intp_interrupt_set_pending(int index) "irq %d is set PENDING" -vfio_platform_start_level_irqfd_injection(int index, int fd, int resamplefd) "IRQ index=%d, fd = %d, resamplefd = %d" -vfio_platform_start_edge_irqfd_injection(int index, int fd) "IRQ index=%d, fd = %d" - -# hw/vfio/spapr.c -vfio_prereg_listener_region_add_skip(uint64_t start, uint64_t end) "%"PRIx64" - %"PRIx64 -vfio_prereg_listener_region_del_skip(uint64_t start, uint64_t end) "%"PRIx64" - %"PRIx64 -vfio_prereg_register(uint64_t va, uint64_t size, int ret) "va=%"PRIx64" size=%"PRIx64" ret=%d" -vfio_prereg_unregister(uint64_t va, uint64_t size, int ret) "va=%"PRIx64" size=%"PRIx64" ret=%d" -vfio_spapr_create_window(int ps, uint64_t ws, uint64_t off) "pageshift=0x%x winsize=0x%"PRIx64" offset=0x%"PRIx64 -vfio_spapr_remove_window(uint64_t off) "offset=%"PRIx64 diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events deleted file mode 100644 index 55184d33b..000000000 --- a/hw/virtio/trace-events +++ /dev/null @@ -1,16 +0,0 @@ -# See docs/tracing.txt for syntax documentation. - -# hw/virtio/virtio.c -virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u" -virtqueue_flush(void *vq, unsigned int count) "vq %p count %u" -virtqueue_pop(void *vq, void *elem, unsigned int in_num, unsigned int out_num) "vq %p elem %p in_num %u out_num %u" -virtio_queue_notify(void *vdev, int n, void *vq) "vdev %p n %d vq %p" -virtio_irq(void *vq) "vq %p" -virtio_notify(void *vdev, void *vq) "vdev %p vq %p" -virtio_set_status(void *vdev, uint8_t val) "vdev %p val %u" - -# hw/virtio/virtio-rng.c -virtio_rng_guest_not_ready(void *rng) "rng %p: guest not ready" -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" - diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index 7681f152f..b35890289 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -9,11 +9,12 @@ */ #include "qemu/osdep.h" -#include <linux/vhost.h> -#include <sys/ioctl.h> #include "hw/virtio/vhost.h" #include "hw/virtio/vhost-backend.h" #include "qemu/error-report.h" +#include "linux/vhost.h" + +#include <sys/ioctl.h> static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request, void *arg) @@ -137,12 +138,6 @@ static int vhost_kernel_set_vring_call(struct vhost_dev *dev, return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file); } -static int vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *dev, - struct vhost_vring_state *s) -{ - return vhost_kernel_call(dev, VHOST_SET_VRING_BUSYLOOP_TIMEOUT, s); -} - static int vhost_kernel_set_features(struct vhost_dev *dev, uint64_t features) { @@ -190,8 +185,6 @@ static const VhostOps kernel_ops = { .vhost_get_vring_base = vhost_kernel_get_vring_base, .vhost_set_vring_kick = vhost_kernel_set_vring_kick, .vhost_set_vring_call = vhost_kernel_set_vring_call, - .vhost_set_vring_busyloop_timeout = - vhost_kernel_set_vring_busyloop_timeout, .vhost_set_features = vhost_kernel_set_features, .vhost_get_features = vhost_kernel_get_features, .vhost_set_owner = vhost_kernel_set_owner, diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index b57454a4b..5914e8510 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -17,6 +17,7 @@ #include "sysemu/kvm.h" #include "qemu/error-report.h" #include "qemu/sockets.h" +#include "exec/ram_addr.h" #include "migration/migration.h" #include <sys/ioctl.h> @@ -31,7 +32,6 @@ 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_REPLY_ACK = 3, VHOST_USER_PROTOCOL_F_MAX }; @@ -85,7 +85,6 @@ typedef struct VhostUserMsg { #define VHOST_USER_VERSION_MASK (0x3) #define VHOST_USER_REPLY_MASK (0x1<<2) -#define VHOST_USER_NEED_REPLY_MASK (0x1 << 3) uint32_t flags; uint32_t size; /* the following payload size */ union { @@ -160,25 +159,6 @@ fail: return -1; } -static int process_message_reply(struct vhost_dev *dev, - VhostUserRequest request) -{ - VhostUserMsg msg; - - if (vhost_user_read(dev, &msg) < 0) { - return -1; - } - - if (msg.request != request) { - error_report("Received unexpected msg type." - "Expected %d received %d", - request, msg.request); - return -1; - } - - return msg.payload.u64 ? -1 : 0; -} - static bool vhost_user_one_time_request(VhostUserRequest request) { switch (request) { @@ -197,7 +177,7 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, int *fds, int fd_num) { CharDriverState *chr = dev->opaque; - int ret, size = VHOST_USER_HDR_SIZE + msg->size; + int size = VHOST_USER_HDR_SIZE + msg->size; /* * For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE, @@ -208,19 +188,12 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, return 0; } - if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) { - error_report("Failed to set msg fds."); - return -1; - } - - ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size); - if (ret != size) { - error_report("Failed to write msg." - " Wrote %d instead of %d.", ret, size); - return -1; + if (fd_num) { + qemu_chr_fe_set_msgfds(chr, fds, fd_num); } - return 0; + return qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size) == size ? + 0 : -1; } static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, @@ -242,14 +215,12 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base, fds[fd_num++] = log->fd; } - if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { - return -1; - } + vhost_user_write(dev, &msg, fds, fd_num); if (shmfd) { msg.size = 0; if (vhost_user_read(dev, &msg) < 0) { - return -1; + return 0; } if (msg.request != VHOST_USER_SET_LOG_BASE) { @@ -269,32 +240,25 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, int fds[VHOST_MEMORY_MAX_NREGIONS]; int i, fd; size_t fd_num = 0; - bool reply_supported = virtio_has_feature(dev->protocol_features, - VHOST_USER_PROTOCOL_F_REPLY_ACK); - VhostUserMsg msg = { .request = VHOST_USER_SET_MEM_TABLE, .flags = VHOST_USER_VERSION, }; - if (reply_supported) { - msg.flags |= VHOST_USER_NEED_REPLY_MASK; - } - for (i = 0; i < dev->mem->nregions; ++i) { struct vhost_memory_region *reg = dev->mem->regions + i; - ram_addr_t offset; - MemoryRegion *mr; + ram_addr_t ram_addr; assert((uintptr_t)reg->userspace_addr == reg->userspace_addr); - mr = memory_region_from_host((void *)(uintptr_t)reg->userspace_addr, - &offset); - fd = memory_region_get_fd(mr); + qemu_ram_addr_from_host((void *)(uintptr_t)reg->userspace_addr, + &ram_addr); + fd = qemu_get_ram_fd(ram_addr); if (fd > 0) { msg.payload.memory.regions[fd_num].userspace_addr = reg->userspace_addr; msg.payload.memory.regions[fd_num].memory_size = reg->memory_size; msg.payload.memory.regions[fd_num].guest_phys_addr = reg->guest_phys_addr; - msg.payload.memory.regions[fd_num].mmap_offset = offset; + msg.payload.memory.regions[fd_num].mmap_offset = reg->userspace_addr - + (uintptr_t) qemu_get_ram_block_host_ptr(ram_addr); assert(fd_num < VHOST_MEMORY_MAX_NREGIONS); fds[fd_num++] = fd; } @@ -312,13 +276,7 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev, msg.size += sizeof(msg.payload.memory.padding); msg.size += fd_num * sizeof(VhostUserMemoryRegion); - if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { - return -1; - } - - if (reply_supported) { - return process_message_reply(dev, msg.request); - } + vhost_user_write(dev, &msg, fds, fd_num); return 0; } @@ -333,9 +291,7 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev, .size = sizeof(msg.payload.addr), }; - if (vhost_user_write(dev, &msg, NULL, 0) < 0) { - return -1; - } + vhost_user_write(dev, &msg, NULL, 0); return 0; } @@ -358,9 +314,7 @@ static int vhost_set_vring(struct vhost_dev *dev, .size = sizeof(msg.payload.state), }; - if (vhost_user_write(dev, &msg, NULL, 0) < 0) { - return -1; - } + vhost_user_write(dev, &msg, NULL, 0); return 0; } @@ -407,12 +361,10 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev, .size = sizeof(msg.payload.state), }; - if (vhost_user_write(dev, &msg, NULL, 0) < 0) { - return -1; - } + vhost_user_write(dev, &msg, NULL, 0); if (vhost_user_read(dev, &msg) < 0) { - return -1; + return 0; } if (msg.request != VHOST_USER_GET_VRING_BASE) { @@ -450,9 +402,7 @@ static int vhost_set_vring_file(struct vhost_dev *dev, msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK; } - if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { - return -1; - } + vhost_user_write(dev, &msg, fds, fd_num); return 0; } @@ -478,9 +428,7 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64) .size = sizeof(msg.payload.u64), }; - if (vhost_user_write(dev, &msg, NULL, 0) < 0) { - return -1; - } + vhost_user_write(dev, &msg, NULL, 0); return 0; } @@ -508,12 +456,10 @@ static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) return 0; } - if (vhost_user_write(dev, &msg, NULL, 0) < 0) { - return -1; - } + vhost_user_write(dev, &msg, NULL, 0); if (vhost_user_read(dev, &msg) < 0) { - return -1; + return 0; } if (msg.request != request) { @@ -544,9 +490,7 @@ static int vhost_user_set_owner(struct vhost_dev *dev) .flags = VHOST_USER_VERSION, }; - if (vhost_user_write(dev, &msg, NULL, 0) < 0) { - return -1; - } + vhost_user_write(dev, &msg, NULL, 0); return 0; } @@ -558,9 +502,7 @@ static int vhost_user_reset_device(struct vhost_dev *dev) .flags = VHOST_USER_VERSION, }; - if (vhost_user_write(dev, &msg, NULL, 0) < 0) { - return -1; - } + vhost_user_write(dev, &msg, NULL, 0); return 0; } @@ -647,6 +589,7 @@ static bool vhost_user_requires_shm_log(struct vhost_dev *dev) static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr) { VhostUserMsg msg = { 0 }; + int err; assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); @@ -663,7 +606,8 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr) memcpy((char *)&msg.payload.u64, mac_addr, 6); msg.size = sizeof(msg.payload.u64); - return vhost_user_write(dev, &msg, NULL, 0); + err = vhost_user_write(dev, &msg, NULL, 0); + return err; } return -1; } @@ -672,15 +616,17 @@ static bool vhost_user_can_merge(struct vhost_dev *dev, uint64_t start1, uint64_t size1, uint64_t start2, uint64_t size2) { - ram_addr_t offset; + ram_addr_t ram_addr; int mfd, rfd; MemoryRegion *mr; - mr = memory_region_from_host((void *)(uintptr_t)start1, &offset); - mfd = memory_region_get_fd(mr); + mr = qemu_ram_addr_from_host((void *)(uintptr_t)start1, &ram_addr); + assert(mr); + mfd = qemu_get_ram_fd(ram_addr); - mr = memory_region_from_host((void *)(uintptr_t)start2, &offset); - rfd = memory_region_get_fd(mr); + mr = qemu_ram_addr_from_host((void *)(uintptr_t)start2, &ram_addr); + assert(mr); + rfd = qemu_get_ram_fd(ram_addr); return mfd == rfd; } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 3d0c807d0..440071815 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -27,18 +27,6 @@ #include "hw/virtio/virtio-access.h" #include "migration/migration.h" -/* enabled until disconnected backend stabilizes */ -#define _VHOST_DEBUG 1 - -#ifdef _VHOST_DEBUG -#define VHOST_OPS_DEBUG(fmt, ...) \ - do { error_report(fmt ": %s (%d)", ## __VA_ARGS__, \ - strerror(errno), errno); } while (0) -#else -#define VHOST_OPS_DEBUG(fmt, ...) \ - do { } while (0) -#endif - static struct vhost_log *vhost_log; static struct vhost_log *vhost_log_shm; @@ -374,8 +362,6 @@ static void vhost_log_put(struct vhost_dev *dev, bool sync) if (!log) { return; } - dev->log = NULL; - dev->log_size = 0; --log->refcnt; if (log->refcnt == 0) { @@ -412,10 +398,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size) /* inform backend of log switching, this must be done before releasing the current log, to ensure no logging is lost */ r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log); - if (r < 0) { - VHOST_OPS_DEBUG("vhost_set_log_base failed"); - } - + assert(r >= 0); vhost_log_put(dev, true); dev->log = log; dev->log_size = size; @@ -439,11 +422,11 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, l = vq->ring_size; p = cpu_physical_memory_map(vq->ring_phys, &l, 1); if (!p || l != vq->ring_size) { - error_report("Unable to map ring buffer for ring %d", i); + fprintf(stderr, "Unable to map ring buffer for ring %d\n", i); r = -ENOMEM; } if (p != vq->ring) { - error_report("Ring buffer relocated for ring %d", i); + fprintf(stderr, "Ring buffer relocated for ring %d\n", i); r = -EBUSY; } cpu_physical_memory_unmap(p, l, 0, 0); @@ -582,9 +565,7 @@ static void vhost_commit(MemoryListener *listener) if (!dev->log_enabled) { r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem); - if (r < 0) { - VHOST_OPS_DEBUG("vhost_set_mem_table failed"); - } + assert(r >= 0); dev->memory_changed = false; return; } @@ -597,9 +578,7 @@ static void vhost_commit(MemoryListener *listener) vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER); } r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem); - if (r < 0) { - VHOST_OPS_DEBUG("vhost_set_mem_table failed"); - } + assert(r >= 0); /* To log less, can only decrease log size after table update. */ if (dev->log_size > log_size + VHOST_LOG_BUFFER) { vhost_dev_log_resize(dev, log_size); @@ -668,7 +647,6 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev, }; int r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr); if (r < 0) { - VHOST_OPS_DEBUG("vhost_set_vring_addr failed"); return -errno; } return 0; @@ -682,15 +660,12 @@ static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log) features |= 0x1ULL << VHOST_F_LOG_ALL; } r = dev->vhost_ops->vhost_set_features(dev, features); - if (r < 0) { - VHOST_OPS_DEBUG("vhost_set_features failed"); - } return r < 0 ? -errno : 0; } static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log) { - int r, i, idx; + int r, t, i, idx; r = vhost_dev_set_features(dev, enable_log); if (r < 0) { goto err_features; @@ -707,10 +682,12 @@ static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log) err_vq: for (; i >= 0; --i) { idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i); - vhost_virtqueue_set_addr(dev, dev->vqs + i, idx, - dev->log_enabled); + t = vhost_virtqueue_set_addr(dev, dev->vqs + i, idx, + dev->log_enabled); + assert(t >= 0); } - vhost_dev_set_features(dev, dev->log_enabled); + t = vhost_dev_set_features(dev, dev->log_enabled); + assert(t >= 0); err_features: return r; } @@ -733,6 +710,8 @@ static int vhost_migration_log(MemoryListener *listener, int enable) return r; } vhost_log_put(dev, false); + dev->log = NULL; + dev->log_size = 0; } else { vhost_dev_log_resize(dev, vhost_get_log_size(dev)); r = vhost_dev_set_log(dev, true); @@ -788,11 +767,15 @@ static inline bool vhost_needs_vring_endian(VirtIODevice *vdev) if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { return false; } +#ifdef TARGET_IS_BIENDIAN #ifdef HOST_WORDS_BIGENDIAN return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_LITTLE; #else return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG; #endif +#else + return false; +#endif } static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev, @@ -808,7 +791,6 @@ static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev, return 0; } - VHOST_OPS_DEBUG("vhost_set_vring_endian failed"); if (errno == ENOTTY) { error_report("vhost does not support cross-endian"); return -ENOSYS; @@ -837,14 +819,12 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, vq->num = state.num = virtio_queue_get_num(vdev, idx); r = dev->vhost_ops->vhost_set_vring_num(dev, &state); if (r) { - VHOST_OPS_DEBUG("vhost_set_vring_num failed"); return -errno; } state.num = virtio_queue_get_last_avail_idx(vdev, idx); r = dev->vhost_ops->vhost_set_vring_base(dev, &state); if (r) { - VHOST_OPS_DEBUG("vhost_set_vring_base failed"); return -errno; } @@ -896,7 +876,6 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq)); r = dev->vhost_ops->vhost_set_vring_kick(dev, &file); if (r) { - VHOST_OPS_DEBUG("vhost_set_vring_kick failed"); r = -errno; goto fail_kick; } @@ -944,21 +923,25 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev, r = dev->vhost_ops->vhost_get_vring_base(dev, &state); if (r < 0) { - VHOST_OPS_DEBUG("vhost VQ %d ring restore failed: %d", idx, r); - } else { - virtio_queue_set_last_avail_idx(vdev, idx, state.num); + fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r); + fflush(stderr); } + virtio_queue_set_last_avail_idx(vdev, idx, state.num); virtio_queue_invalidate_signalled_used(vdev, idx); /* In the cross-endian case, we need to reset the vring endianness to * native as legacy devices expect so by default. */ if (vhost_needs_vring_endian(vdev)) { - vhost_virtqueue_set_vring_endian_legacy(dev, - !virtio_is_big_endian(vdev), - vhost_vq_index); + r = vhost_virtqueue_set_vring_endian_legacy(dev, + !virtio_is_big_endian(vdev), + vhost_vq_index); + if (r < 0) { + error_report("failed to reset vring endianness"); + } } + assert (r >= 0); cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx), 0, virtio_queue_get_ring_size(vdev, idx)); cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx), @@ -981,29 +964,6 @@ static void vhost_eventfd_del(MemoryListener *listener, { } -static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev, - int n, uint32_t timeout) -{ - int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, n); - struct vhost_vring_state state = { - .index = vhost_vq_index, - .num = timeout, - }; - int r; - - if (!dev->vhost_ops->vhost_set_vring_busyloop_timeout) { - return -EINVAL; - } - - r = dev->vhost_ops->vhost_set_vring_busyloop_timeout(dev, &state); - if (r) { - VHOST_OPS_DEBUG("vhost_set_vring_busyloop_timeout failed"); - return r; - } - - return 0; -} - static int vhost_virtqueue_init(struct vhost_dev *dev, struct vhost_virtqueue *vq, int n) { @@ -1019,7 +979,6 @@ static int vhost_virtqueue_init(struct vhost_dev *dev, file.fd = event_notifier_get_fd(&vq->masked_notifier); r = dev->vhost_ops->vhost_set_vring_call(dev, &file); if (r) { - VHOST_OPS_DEBUG("vhost_set_vring_call failed"); r = -errno; goto fail_call; } @@ -1035,57 +994,47 @@ static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq) } int vhost_dev_init(struct vhost_dev *hdev, void *opaque, - VhostBackendType backend_type, uint32_t busyloop_timeout) + VhostBackendType backend_type) { uint64_t features; - int i, r, n_initialized_vqs = 0; + int i, r; hdev->migration_blocker = NULL; - r = vhost_set_backend_type(hdev, backend_type); - assert(r >= 0); + if (vhost_set_backend_type(hdev, backend_type) < 0) { + close((uintptr_t)opaque); + return -1; + } - r = hdev->vhost_ops->vhost_backend_init(hdev, opaque); - if (r < 0) { - goto fail; + if (hdev->vhost_ops->vhost_backend_init(hdev, opaque) < 0) { + close((uintptr_t)opaque); + return -errno; } if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) { - error_report("vhost backend memory slots limit is less" - " than current number of present memory slots"); - r = -1; - goto fail; + fprintf(stderr, "vhost backend memory slots limit is less" + " than current number of present memory slots\n"); + close((uintptr_t)opaque); + return -1; } + QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); r = hdev->vhost_ops->vhost_set_owner(hdev); if (r < 0) { - VHOST_OPS_DEBUG("vhost_set_owner failed"); goto fail; } r = hdev->vhost_ops->vhost_get_features(hdev, &features); if (r < 0) { - VHOST_OPS_DEBUG("vhost_get_features failed"); goto fail; } - for (i = 0; i < hdev->nvqs; ++i, ++n_initialized_vqs) { + for (i = 0; i < hdev->nvqs; ++i) { r = vhost_virtqueue_init(hdev, hdev->vqs + i, hdev->vq_index + i); if (r < 0) { - goto fail; - } - } - - if (busyloop_timeout) { - for (i = 0; i < hdev->nvqs; ++i) { - r = vhost_virtqueue_set_busyloop_timeout(hdev, hdev->vq_index + i, - busyloop_timeout); - if (r < 0) { - goto fail_busyloop; - } + goto fail_vq; } } - hdev->features = features; hdev->memory_listener = (MemoryListener) { @@ -1127,43 +1076,33 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, hdev->started = false; hdev->memory_changed = false; memory_listener_register(&hdev->memory_listener, &address_space_memory); - QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); return 0; - -fail_busyloop: +fail_vq: while (--i >= 0) { - vhost_virtqueue_set_busyloop_timeout(hdev, hdev->vq_index + i, 0); + vhost_virtqueue_cleanup(hdev->vqs + i); } fail: - hdev->nvqs = n_initialized_vqs; - vhost_dev_cleanup(hdev); + r = -errno; + hdev->vhost_ops->vhost_backend_cleanup(hdev); + QLIST_REMOVE(hdev, entry); return r; } void vhost_dev_cleanup(struct vhost_dev *hdev) { int i; - for (i = 0; i < hdev->nvqs; ++i) { vhost_virtqueue_cleanup(hdev->vqs + i); } - if (hdev->mem) { - /* those are only safe after successful init */ - memory_listener_unregister(&hdev->memory_listener); - QLIST_REMOVE(hdev, entry); - } + memory_listener_unregister(&hdev->memory_listener); if (hdev->migration_blocker) { migrate_del_blocker(hdev->migration_blocker); error_free(hdev->migration_blocker); } g_free(hdev->mem); g_free(hdev->mem_sections); - if (hdev->vhost_ops) { - hdev->vhost_ops->vhost_backend_cleanup(hdev); - } - assert(!hdev->log); - - memset(hdev, 0, sizeof(struct vhost_dev)); + hdev->vhost_ops->vhost_backend_cleanup(hdev); + QLIST_REMOVE(hdev, entry); } /* Stop processing guest IO notifications in qemu. @@ -1175,18 +1114,16 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) VirtioBusState *vbus = VIRTIO_BUS(qbus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); int i, r, e; - - if (!k->ioeventfd_started) { - error_report("binding does not support host notifiers"); + if (!k->set_host_notifier) { + fprintf(stderr, "binding does not support host notifiers\n"); r = -ENOSYS; goto fail; } for (i = 0; i < hdev->nvqs; ++i) { - r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i, - true); + r = k->set_host_notifier(qbus->parent, hdev->vq_index + i, true); if (r < 0) { - error_report("vhost VQ %d notifier binding failed: %d", i, -r); + fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r); goto fail_vq; } } @@ -1194,10 +1131,10 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) return 0; fail_vq: while (--i >= 0) { - e = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i, - false); + e = k->set_host_notifier(qbus->parent, hdev->vq_index + i, false); if (e < 0) { - error_report("vhost VQ %d notifier cleanup error: %d", i, -r); + fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r); + fflush(stderr); } assert (e >= 0); } @@ -1213,13 +1150,15 @@ fail: void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); + VirtioBusState *vbus = VIRTIO_BUS(qbus); + VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus); int i, r; for (i = 0; i < hdev->nvqs; ++i) { - r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i, - false); + r = k->set_host_notifier(qbus->parent, hdev->vq_index + i, false); if (r < 0) { - error_report("vhost VQ %d notifier cleanup failed: %d", i, -r); + fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r); + fflush(stderr); } assert (r >= 0); } @@ -1243,9 +1182,6 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, int r, index = n - hdev->vq_index; struct vhost_vring_file file; - /* should only be called after backend is connected */ - assert(hdev->vhost_ops); - if (mask) { assert(vdev->use_guest_notifier_mask); file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier); @@ -1255,9 +1191,7 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n); r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file); - if (r < 0) { - VHOST_OPS_DEBUG("vhost_set_vring_call failed"); - } + assert(r >= 0); } uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits, @@ -1292,9 +1226,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) { int i, r; - /* should only be called after backend is connected */ - assert(hdev->vhost_ops); - hdev->started = true; r = vhost_dev_set_features(hdev, hdev->log_enabled); @@ -1303,7 +1234,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) } r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem); if (r < 0) { - VHOST_OPS_DEBUG("vhost_set_mem_table failed"); r = -errno; goto fail_mem; } @@ -1328,7 +1258,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) hdev->log_size ? log_base : 0, hdev->log); if (r < 0) { - VHOST_OPS_DEBUG("vhost_set_log_base failed"); r = -errno; goto fail_log; } @@ -1357,9 +1286,6 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) { int i; - /* should only be called after backend is connected */ - assert(hdev->vhost_ops); - for (i = 0; i < hdev->nvqs; ++i) { vhost_virtqueue_stop(hdev, vdev, @@ -1369,14 +1295,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev) vhost_log_put(hdev, true); hdev->started = false; + hdev->log = NULL; + hdev->log_size = 0; } -int vhost_net_set_backend(struct vhost_dev *hdev, - struct vhost_vring_file *file) -{ - if (hdev->vhost_ops->vhost_net_set_backend) { - return hdev->vhost_ops->vhost_net_set_backend(hdev, file); - } - - return -1; -} diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 5af429a58..9dbe68179 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -27,6 +27,10 @@ #include "qapi-event.h" #include "trace.h" +#if defined(__linux__) +#include <sys/mman.h> +#endif + #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" @@ -134,18 +138,17 @@ static void balloon_stats_get_all(Object *obj, Visitor *v, const char *name, for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) { visit_type_uint64(v, balloon_stat_names[i], &s->stats[i], &err); if (err) { - goto out_nested; + break; } } - visit_check_struct(v, &err); -out_nested: - visit_end_struct(v, NULL); + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); - if (!err) { - visit_check_struct(v, &err); - } out_end: - visit_end_struct(v, NULL); + error_propagate(errp, err); + err = NULL; + visit_end_struct(v, &err); out: error_propagate(errp, err); } @@ -396,6 +399,11 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target) trace_virtio_balloon_to_target(target, dev->num_pages); } +static void virtio_balloon_save(QEMUFile *f, void *opaque) +{ + virtio_save(VIRTIO_DEVICE(opaque), f); +} + static void virtio_balloon_save_device(VirtIODevice *vdev, QEMUFile *f) { VirtIOBalloon *s = VIRTIO_BALLOON(vdev); @@ -404,9 +412,12 @@ static void virtio_balloon_save_device(VirtIODevice *vdev, QEMUFile *f) qemu_put_be32(f, s->actual); } -static int virtio_balloon_load(QEMUFile *f, void *opaque, size_t size) +static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) { - return virtio_load(VIRTIO_DEVICE(opaque), f, 1); + if (version_id != 1) + return -EINVAL; + + return virtio_load(VIRTIO_DEVICE(opaque), f, version_id); } static int virtio_balloon_load_device(VirtIODevice *vdev, QEMUFile *f, @@ -446,6 +457,9 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats); reset_stats(s); + + register_savevm(dev, "virtio-balloon", -1, 1, + virtio_balloon_save, virtio_balloon_load, s); } static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp) @@ -455,6 +469,7 @@ static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp) balloon_stats_destroy_timer(s); qemu_remove_balloon_handler(s); + unregister_savevm(dev, "virtio-balloon", s); virtio_cleanup(vdev); } @@ -481,8 +496,6 @@ static void virtio_balloon_instance_init(Object *obj) NULL, s, NULL); } -VMSTATE_VIRTIO_DEVICE(balloon, 1, virtio_balloon_load, virtio_vmstate_save); - static Property virtio_balloon_properties[] = { DEFINE_PROP_BIT("deflate-on-oom", VirtIOBalloon, host_features, VIRTIO_BALLOON_F_DEFLATE_ON_OOM, false), @@ -495,7 +508,6 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->props = virtio_balloon_properties; - dc->vmsd = &vmstate_virtio_balloon; set_bit(DEVICE_CATEGORY_MISC, dc->categories); vdc->realize = virtio_balloon_device_realize; vdc->unrealize = virtio_balloon_device_unrealize; diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index a85b7c8ab..574f0e23f 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -146,132 +146,6 @@ void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config) } } -/* - * This function handles both assigning the ioeventfd handler and - * registering it with the kernel. - * assign: register/deregister ioeventfd with the kernel - * set_handler: use the generic ioeventfd handler - */ -static int set_host_notifier_internal(DeviceState *proxy, VirtioBusState *bus, - int n, bool assign, bool set_handler) -{ - VirtIODevice *vdev = virtio_bus_get_device(bus); - VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); - VirtQueue *vq = virtio_get_queue(vdev, n); - EventNotifier *notifier = virtio_queue_get_host_notifier(vq); - int r = 0; - - if (assign) { - r = event_notifier_init(notifier, 1); - if (r < 0) { - error_report("%s: unable to init event notifier: %d", __func__, r); - return r; - } - virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler); - r = k->ioeventfd_assign(proxy, notifier, n, assign); - if (r < 0) { - error_report("%s: unable to assign ioeventfd: %d", __func__, r); - virtio_queue_set_host_notifier_fd_handler(vq, false, false); - event_notifier_cleanup(notifier); - return r; - } - } else { - k->ioeventfd_assign(proxy, notifier, n, assign); - virtio_queue_set_host_notifier_fd_handler(vq, false, false); - event_notifier_cleanup(notifier); - } - return r; -} - -void virtio_bus_start_ioeventfd(VirtioBusState *bus) -{ - VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); - DeviceState *proxy = DEVICE(BUS(bus)->parent); - VirtIODevice *vdev; - int n, r; - - if (!k->ioeventfd_started || k->ioeventfd_started(proxy)) { - return; - } - if (k->ioeventfd_disabled(proxy)) { - return; - } - vdev = virtio_bus_get_device(bus); - for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { - if (!virtio_queue_get_num(vdev, n)) { - continue; - } - r = set_host_notifier_internal(proxy, bus, n, true, true); - if (r < 0) { - goto assign_error; - } - } - k->ioeventfd_set_started(proxy, true, false); - return; - -assign_error: - while (--n >= 0) { - if (!virtio_queue_get_num(vdev, n)) { - continue; - } - - r = set_host_notifier_internal(proxy, bus, n, false, false); - assert(r >= 0); - } - k->ioeventfd_set_started(proxy, false, true); - error_report("%s: failed. Fallback to userspace (slower).", __func__); -} - -void virtio_bus_stop_ioeventfd(VirtioBusState *bus) -{ - VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); - DeviceState *proxy = DEVICE(BUS(bus)->parent); - VirtIODevice *vdev; - int n, r; - - if (!k->ioeventfd_started || !k->ioeventfd_started(proxy)) { - return; - } - vdev = virtio_bus_get_device(bus); - for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { - if (!virtio_queue_get_num(vdev, n)) { - continue; - } - r = set_host_notifier_internal(proxy, bus, n, false, false); - assert(r >= 0); - } - k->ioeventfd_set_started(proxy, false, false); -} - -/* - * This function switches from/to the generic ioeventfd handler. - * assign==false means 'use generic ioeventfd handler'. - */ -int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign) -{ - VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus); - DeviceState *proxy = DEVICE(BUS(bus)->parent); - - if (!k->ioeventfd_started) { - return -ENOSYS; - } - k->ioeventfd_set_disabled(proxy, assign); - if (assign) { - /* - * Stop using the generic ioeventfd, we are doing eventfd handling - * ourselves below - * - * FIXME: We should just switch the handler and not deassign the - * ioeventfd. - * Otherwise, there's a window where we don't have an - * ioeventfd and we may end up with a notification where - * we don't expect one. - */ - virtio_bus_stop_ioeventfd(bus); - } - return set_host_notifier_internal(proxy, bus, n, assign, false); -} - static char *virtio_bus_get_dev_path(DeviceState *dev) { BusState *bus = qdev_get_parent_bus(dev); diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 13798b3cb..d4cd91f8c 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -91,62 +91,92 @@ typedef struct { VirtioBusState bus; bool ioeventfd_disabled; bool ioeventfd_started; - bool format_transport_address; } VirtIOMMIOProxy; -static bool virtio_mmio_ioeventfd_started(DeviceState *d) +static int virtio_mmio_set_host_notifier_internal(VirtIOMMIOProxy *proxy, + int n, bool assign, + bool set_handler) { - VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); - - return proxy->ioeventfd_started; -} - -static void virtio_mmio_ioeventfd_set_started(DeviceState *d, bool started, - bool err) -{ - VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); - - proxy->ioeventfd_started = started; -} - -static bool virtio_mmio_ioeventfd_disabled(DeviceState *d) -{ - VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); - - return !kvm_eventfds_enabled() || proxy->ioeventfd_disabled; -} - -static void virtio_mmio_ioeventfd_set_disabled(DeviceState *d, bool disabled) -{ - VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); - - proxy->ioeventfd_disabled = disabled; -} - -static int virtio_mmio_ioeventfd_assign(DeviceState *d, - EventNotifier *notifier, - int n, bool assign) -{ - VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_get_queue(vdev, n); + EventNotifier *notifier = virtio_queue_get_host_notifier(vq); + int r = 0; if (assign) { + r = event_notifier_init(notifier, 1); + if (r < 0) { + error_report("%s: unable to init event notifier: %d", + __func__, r); + return r; + } + virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler); memory_region_add_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUENOTIFY, 4, true, n, notifier); } else { memory_region_del_eventfd(&proxy->iomem, VIRTIO_MMIO_QUEUENOTIFY, 4, true, n, notifier); + virtio_queue_set_host_notifier_fd_handler(vq, false, false); + event_notifier_cleanup(notifier); } - return 0; + return r; } static void virtio_mmio_start_ioeventfd(VirtIOMMIOProxy *proxy) { - virtio_bus_start_ioeventfd(&proxy->bus); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + int n, r; + + if (!kvm_eventfds_enabled() || + proxy->ioeventfd_disabled || + proxy->ioeventfd_started) { + return; + } + + for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + + r = virtio_mmio_set_host_notifier_internal(proxy, n, true, true); + if (r < 0) { + goto assign_error; + } + } + proxy->ioeventfd_started = true; + return; + +assign_error: + while (--n >= 0) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + + r = virtio_mmio_set_host_notifier_internal(proxy, n, false, false); + assert(r >= 0); + } + proxy->ioeventfd_started = false; + error_report("%s: failed. Fallback to a userspace (slower).", __func__); } static void virtio_mmio_stop_ioeventfd(VirtIOMMIOProxy *proxy) { - virtio_bus_stop_ioeventfd(&proxy->bus); + int r; + int n; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + + if (!proxy->ioeventfd_started) { + return; + } + + for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + + r = virtio_mmio_set_host_notifier_internal(proxy, n, false, false); + assert(r >= 0); + } + proxy->ioeventfd_started = false; } static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size) @@ -468,13 +498,26 @@ assign_error: return r; } -/* virtio-mmio device */ +static int virtio_mmio_set_host_notifier(DeviceState *opaque, int n, + bool assign) +{ + VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque); -static Property virtio_mmio_properties[] = { - DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy, - format_transport_address, true), - DEFINE_PROP_END_OF_LIST(), -}; + /* Stop using ioeventfd for virtqueue kick if the device starts using host + * notifiers. This makes it easy to avoid stepping on each others' toes. + */ + proxy->ioeventfd_disabled = assign; + if (assign) { + virtio_mmio_stop_ioeventfd(proxy); + } + /* We don't need to start here: it's not needed because backend + * currently only stops on status change away from ok, + * reset, vmstop and such. If we do add code to start here, + * need to check vmstate, device state etc. */ + return virtio_mmio_set_host_notifier_internal(proxy, n, assign, false); +} + +/* virtio-mmio device */ static void virtio_mmio_realizefn(DeviceState *d, Error **errp) { @@ -496,7 +539,6 @@ static void virtio_mmio_class_init(ObjectClass *klass, void *data) dc->realize = virtio_mmio_realizefn; dc->reset = virtio_mmio_reset; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->props = virtio_mmio_properties; } static const TypeInfo virtio_mmio_info = { @@ -508,46 +550,6 @@ static const TypeInfo virtio_mmio_info = { /* virtio-mmio-bus. */ -static char *virtio_mmio_bus_get_dev_path(DeviceState *dev) -{ - BusState *virtio_mmio_bus; - VirtIOMMIOProxy *virtio_mmio_proxy; - char *proxy_path; - SysBusDevice *proxy_sbd; - char *path; - - virtio_mmio_bus = qdev_get_parent_bus(dev); - virtio_mmio_proxy = VIRTIO_MMIO(virtio_mmio_bus->parent); - proxy_path = qdev_get_dev_path(DEVICE(virtio_mmio_proxy)); - - /* - * If @format_transport_address is false, then we just perform the same as - * virtio_bus_get_dev_path(): we delegate the address formatting for the - * device on the virtio-mmio bus to the bus that the virtio-mmio proxy - * (i.e., the device that implements the virtio-mmio bus) resides on. In - * this case the base address of the virtio-mmio transport will be - * invisible. - */ - if (!virtio_mmio_proxy->format_transport_address) { - return proxy_path; - } - - /* Otherwise, we append the base address of the transport. */ - proxy_sbd = SYS_BUS_DEVICE(virtio_mmio_proxy); - assert(proxy_sbd->num_mmio == 1); - assert(proxy_sbd->mmio[0].memory == &virtio_mmio_proxy->iomem); - - if (proxy_path) { - path = g_strdup_printf("%s/virtio-mmio@" TARGET_FMT_plx, proxy_path, - proxy_sbd->mmio[0].addr); - } else { - path = g_strdup_printf("virtio-mmio@" TARGET_FMT_plx, - proxy_sbd->mmio[0].addr); - } - g_free(proxy_path); - return path; -} - static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data) { BusClass *bus_class = BUS_CLASS(klass); @@ -556,15 +558,10 @@ static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data) k->notify = virtio_mmio_update_irq; k->save_config = virtio_mmio_save_config; k->load_config = virtio_mmio_load_config; + k->set_host_notifier = virtio_mmio_set_host_notifier; k->set_guest_notifiers = virtio_mmio_set_guest_notifiers; - k->ioeventfd_started = virtio_mmio_ioeventfd_started; - k->ioeventfd_set_started = virtio_mmio_ioeventfd_set_started; - k->ioeventfd_disabled = virtio_mmio_ioeventfd_disabled; - k->ioeventfd_set_disabled = virtio_mmio_ioeventfd_set_disabled; - k->ioeventfd_assign = virtio_mmio_ioeventfd_assign; k->has_variable_vring_alignment = true; bus_class->max_dev = 1; - bus_class->get_dev_path = virtio_mmio_bus_get_dev_path; } static const TypeInfo virtio_mmio_bus_info = { diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 755f9218b..bfedbbf17 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -161,7 +161,7 @@ static bool virtio_pci_modern_state_needed(void *opaque) { VirtIOPCIProxy *proxy = opaque; - return virtio_pci_modern(proxy); + return !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN); } static const VMStateDescription vmstate_virtio_pci_modern_state = { @@ -262,46 +262,16 @@ static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) return 0; } -static bool virtio_pci_ioeventfd_started(DeviceState *d) -{ - VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); - - return proxy->ioeventfd_started; -} - -static void virtio_pci_ioeventfd_set_started(DeviceState *d, bool started, - bool err) -{ - VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); - - proxy->ioeventfd_started = started; -} - -static bool virtio_pci_ioeventfd_disabled(DeviceState *d) -{ - VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); - - return proxy->ioeventfd_disabled || - !(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD); -} - -static void virtio_pci_ioeventfd_set_disabled(DeviceState *d, bool disabled) -{ - VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); - - proxy->ioeventfd_disabled = disabled; -} - #define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000 -static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, - int n, bool assign) +static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, + int n, bool assign, bool set_handler) { - VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtQueue *vq = virtio_get_queue(vdev, n); - bool legacy = virtio_pci_legacy(proxy); - bool modern = virtio_pci_modern(proxy); + EventNotifier *notifier = virtio_queue_get_host_notifier(vq); + bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY); + bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN); bool fast_mmio = kvm_ioeventfd_any_length_enabled(); bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; MemoryRegion *modern_mr = &proxy->notify.mr; @@ -310,8 +280,16 @@ static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * virtio_get_queue_index(vq); hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY; + int r = 0; if (assign) { + r = event_notifier_init(notifier, 1); + if (r < 0) { + error_report("%s: unable to init event notifier: %d", + __func__, r); + return r; + } + virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler); if (modern) { if (fast_mmio) { memory_region_add_eventfd(modern_mr, modern_addr, 0, @@ -347,18 +325,68 @@ static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, memory_region_del_eventfd(legacy_mr, legacy_addr, 2, true, n, notifier); } + virtio_queue_set_host_notifier_fd_handler(vq, false, false); + event_notifier_cleanup(notifier); } - return 0; + return r; } static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy) { - virtio_bus_start_ioeventfd(&proxy->bus); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + int n, r; + + if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) || + proxy->ioeventfd_disabled || + proxy->ioeventfd_started) { + return; + } + + for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + + r = virtio_pci_set_host_notifier_internal(proxy, n, true, true); + if (r < 0) { + goto assign_error; + } + } + proxy->ioeventfd_started = true; + return; + +assign_error: + while (--n >= 0) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + + r = virtio_pci_set_host_notifier_internal(proxy, n, false, false); + assert(r >= 0); + } + proxy->ioeventfd_started = false; + error_report("%s: failed. Fallback to a userspace (slower).", __func__); } static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy) { - virtio_bus_stop_ioeventfd(&proxy->bus); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + int r; + int n; + + if (!proxy->ioeventfd_started) { + return; + } + + for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } + + r = virtio_pci_set_host_notifier_internal(proxy, n, false, false); + assert(r >= 0); + } + proxy->ioeventfd_started = false; } static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) @@ -699,13 +727,14 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev, static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, unsigned int queue_no, - unsigned int vector) + unsigned int vector, + MSIMessage msg) { VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; int ret; if (irqfd->users == 0) { - ret = kvm_irqchip_add_msi_route(kvm_state, vector, &proxy->pci_dev); + ret = kvm_irqchip_add_msi_route(kvm_state, msg, &proxy->pci_dev); if (ret < 0) { return ret; } @@ -732,7 +761,9 @@ static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtQueue *vq = virtio_get_queue(vdev, queue_no); EventNotifier *n = virtio_queue_get_guest_notifier(vq); - return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); + int ret; + ret = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); + return ret; } static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, @@ -756,6 +787,7 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); unsigned int vector; int ret, queue_no; + MSIMessage msg; for (queue_no = 0; queue_no < nvqs; queue_no++) { if (!virtio_queue_get_num(vdev, queue_no)) { @@ -765,7 +797,8 @@ static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) if (vector >= msix_nr_vectors_allocated(dev)) { continue; } - ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); + msg = msix_get_message(dev, vector); + ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg); if (ret < 0) { goto undo; } @@ -842,7 +875,6 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, if (ret < 0) { return ret; } - kvm_irqchip_commit_routes(kvm_state); } } @@ -1080,6 +1112,24 @@ assign_error: return r; } +static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign) +{ + VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + + /* Stop using ioeventfd for virtqueue kick if the device starts using host + * notifiers. This makes it easy to avoid stepping on each others' toes. + */ + proxy->ioeventfd_disabled = assign; + if (assign) { + virtio_pci_stop_ioeventfd(proxy); + } + /* We don't need to start here: it's not needed because backend + * currently only stops on status change away from ok, + * reset, vmstop and such. If we do add code to start here, + * need to check vmstate, device state etc. */ + return virtio_pci_set_host_notifier_internal(proxy, n, assign, false); +} + static void virtio_pci_vmstate_change(DeviceState *d, bool running) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); @@ -1574,8 +1624,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) { VirtIOPCIProxy *proxy = VIRTIO_PCI(d); VirtioBusState *bus = &proxy->bus; - bool legacy = virtio_pci_legacy(proxy); - bool modern = virtio_pci_modern(proxy); + bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY); + bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN); bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; uint8_t *config; uint32_t size; @@ -1694,7 +1744,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) static void virtio_pci_device_unplugged(DeviceState *d) { VirtIOPCIProxy *proxy = VIRTIO_PCI(d); - bool modern = virtio_pci_modern(proxy); + bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN); bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; virtio_pci_stop_ioeventfd(proxy); @@ -1714,8 +1764,6 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) { VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev); - bool pcie_port = pci_bus_is_express(pci_dev->bus) && - !pci_bus_is_root(pci_dev->bus); /* * virtio pci bar layout used by default. @@ -1766,11 +1814,8 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) address_space_init(&proxy->modern_as, &proxy->modern_cfg, "virtio-pci-cfg-as"); - if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) { - proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; - } - - if (pcie_port && pci_is_express(pci_dev)) { + if (pci_is_express(pci_dev) && pci_bus_is_express(pci_dev->bus) && + !pci_bus_is_root(pci_dev->bus)) { int pos; pos = pcie_endpoint_cap_init(pci_dev, 0); @@ -1824,9 +1869,10 @@ static void virtio_pci_reset(DeviceState *qdev) static Property virtio_pci_properties[] = { DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false), - DEFINE_PROP_ON_OFF_AUTO("disable-legacy", VirtIOPCIProxy, disable_legacy, - ON_OFF_AUTO_AUTO), - DEFINE_PROP_BOOL("disable-modern", VirtIOPCIProxy, disable_modern, false), + DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false), + DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, true), DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true), DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags, @@ -1843,7 +1889,7 @@ static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp) PCIDevice *pci_dev = &proxy->pci_dev; if (!(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_PCIE) && - virtio_pci_modern(proxy)) { + !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN)) { pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; } @@ -2305,7 +2351,9 @@ static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) DeviceState *vdev = DEVICE(&vinput->vdev); qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); - virtio_pci_force_virtio_1(vpci_dev); + /* force virtio-1.0 */ + vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN; + vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY; object_property_set_bool(OBJECT(vdev), true, "realized", errp); } @@ -2442,16 +2490,12 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) k->load_extra_state = virtio_pci_load_extra_state; k->has_extra_state = virtio_pci_has_extra_state; k->query_guest_notifiers = virtio_pci_query_guest_notifiers; + k->set_host_notifier = virtio_pci_set_host_notifier; k->set_guest_notifiers = virtio_pci_set_guest_notifiers; k->vmstate_change = virtio_pci_vmstate_change; k->device_plugged = virtio_pci_device_plugged; k->device_unplugged = virtio_pci_device_unplugged; k->query_nvectors = virtio_pci_query_nvectors; - k->ioeventfd_started = virtio_pci_ioeventfd_started; - k->ioeventfd_set_started = virtio_pci_ioeventfd_set_started; - k->ioeventfd_disabled = virtio_pci_ioeventfd_disabled; - k->ioeventfd_set_disabled = virtio_pci_ioeventfd_set_disabled; - k->ioeventfd_assign = virtio_pci_ioeventfd_assign; } static const TypeInfo virtio_pci_bus_info = { diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 25fbf8a37..e4548c2f9 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -61,6 +61,8 @@ typedef struct VirtioBusClass VirtioPCIBusClass; enum { VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, + VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, + VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, @@ -75,6 +77,8 @@ enum { #define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT) /* virtio version flags */ +#define VIRTIO_PCI_FLAG_DISABLE_LEGACY (1 << VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT) +#define VIRTIO_PCI_FLAG_DISABLE_MODERN (1 << VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT) #define VIRTIO_PCI_FLAG_DISABLE_PCIE (1 << VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT) /* migrate extra state */ @@ -140,8 +144,6 @@ struct VirtIOPCIProxy { uint32_t modern_mem_bar; int config_cap; uint32_t flags; - bool disable_modern; - OnOffAuto disable_legacy; uint32_t class_code; uint32_t nvectors; uint32_t dfselect; @@ -156,21 +158,6 @@ struct VirtIOPCIProxy { VirtioBusState bus; }; -static inline bool virtio_pci_modern(VirtIOPCIProxy *proxy) -{ - return !proxy->disable_modern; -} - -static inline bool virtio_pci_legacy(VirtIOPCIProxy *proxy) -{ - return proxy->disable_legacy == ON_OFF_AUTO_OFF; -} - -static inline void virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy) -{ - proxy->disable_modern = false; - proxy->disable_legacy = ON_OFF_AUTO_ON; -} /* * virtio-scsi-pci: This extends VirtioPCIProxy. diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index cd8ca1017..6b991a764 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -120,12 +120,22 @@ static uint64_t get_features(VirtIODevice *vdev, uint64_t f, Error **errp) return f; } -static int virtio_rng_load(QEMUFile *f, void *opaque, size_t size) +static void virtio_rng_save(QEMUFile *f, void *opaque) +{ + VirtIODevice *vdev = opaque; + + virtio_save(vdev, f); +} + +static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) { VirtIORNG *vrng = opaque; int ret; - ret = virtio_load(VIRTIO_DEVICE(vrng), f, 1); + if (version_id != 1) { + return -EINVAL; + } + ret = virtio_load(VIRTIO_DEVICE(vrng), f, version_id); if (ret != 0) { return ret; } @@ -204,6 +214,8 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp) vrng->rate_limit_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, check_rate_limit, vrng); vrng->activate_timer = true; + register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save, + virtio_rng_load, vrng); } static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp) @@ -213,11 +225,10 @@ static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp) timer_del(vrng->rate_limit_timer); timer_free(vrng->rate_limit_timer); + unregister_savevm(dev, "virtio-rng", vrng); virtio_cleanup(vdev); } -VMSTATE_VIRTIO_DEVICE(rng, 1, virtio_rng_load, virtio_vmstate_save); - static Property virtio_rng_properties[] = { /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s. If * you have an entropy source capable of generating more entropy than this @@ -235,7 +246,6 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->props = virtio_rng_properties; - dc->vmsd = &vmstate_virtio_rng; set_bit(DEVICE_CATEGORY_MISC, dc->categories); vdc->realize = virtio_rng_device_realize; vdc->unrealize = virtio_rng_device_unrealize; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 74c085c74..8ed260a61 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -95,9 +95,8 @@ struct VirtQueue int inuse; uint16_t vector; - VirtIOHandleOutput handle_output; - VirtIOHandleOutput handle_aio_output; - bool use_aio; + void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq); + void (*handle_aio_output)(VirtIODevice *vdev, VirtQueue *vq); VirtIODevice *vdev; EventNotifier guest_notifier; EventNotifier host_notifier; @@ -268,7 +267,6 @@ void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len) { vq->last_avail_idx--; - vq->inuse--; virtqueue_unmap_sg(vq, elem, len); } @@ -459,11 +457,6 @@ static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iove unsigned num_sg = *p_num_sg; assert(num_sg <= max_num_sg); - if (!sz) { - error_report("virtio: zero sized buffers are not allowed"); - exit(1); - } - while (sz) { hwaddr len = sz; @@ -1074,6 +1067,13 @@ int virtio_get_num_queues(VirtIODevice *vdev) return i; } +int virtio_queue_get_id(VirtQueue *vq) +{ + VirtIODevice *vdev = vq->vdev; + assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_QUEUE_MAX]); + return vq - &vdev->vq[0]; +} + void virtio_queue_set_align(VirtIODevice *vdev, int n, int align) { BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); @@ -1142,9 +1142,8 @@ void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector) } } -static VirtQueue *virtio_add_queue_internal(VirtIODevice *vdev, int queue_size, - VirtIOHandleOutput handle_output, - bool use_aio) +VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, + void (*handle_output)(VirtIODevice *, VirtQueue *)) { int i; @@ -1161,28 +1160,10 @@ static VirtQueue *virtio_add_queue_internal(VirtIODevice *vdev, int queue_size, vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN; vdev->vq[i].handle_output = handle_output; vdev->vq[i].handle_aio_output = NULL; - vdev->vq[i].use_aio = use_aio; return &vdev->vq[i]; } -/* Add a virt queue and mark AIO. - * An AIO queue will use the AioContext based event interface instead of the - * default IOHandler and EventNotifier interface. - */ -VirtQueue *virtio_add_queue_aio(VirtIODevice *vdev, int queue_size, - VirtIOHandleOutput handle_output) -{ - return virtio_add_queue_internal(vdev, queue_size, handle_output, true); -} - -/* Add a normal virt queue (on the contrary to the AIO version above. */ -VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, - VirtIOHandleOutput handle_output) -{ - return virtio_add_queue_internal(vdev, queue_size, handle_output, false); -} - void virtio_del_queue(VirtIODevice *vdev, int n) { if (n < 0 || n >= VIRTIO_QUEUE_MAX) { @@ -1475,12 +1456,6 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f) vmstate_save_state(f, &vmstate_virtio, vdev, NULL); } -/* A wrapper for use as a VMState .put function */ -void virtio_vmstate_save(QEMUFile *f, void *opaque, size_t size) -{ - virtio_save(VIRTIO_DEVICE(opaque), f); -} - static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val) { VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); @@ -1649,21 +1624,6 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id) } vdev->vq[i].used_idx = vring_used_idx(&vdev->vq[i]); vdev->vq[i].shadow_avail_idx = vring_avail_idx(&vdev->vq[i]); - - /* - * Some devices migrate VirtQueueElements that have been popped - * from the avail ring but not yet returned to the used ring. - */ - vdev->vq[i].inuse = 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", - i, vdev->vq[i].vring.num, - vdev->vq[i].last_avail_idx, - vdev->vq[i].used_idx); - return -1; - } } } @@ -1856,7 +1816,8 @@ static void virtio_queue_host_notifier_aio_read(EventNotifier *n) } void virtio_queue_aio_set_host_notifier_handler(VirtQueue *vq, AioContext *ctx, - VirtIOHandleOutput handle_output) + void (*handle_output)(VirtIODevice *, + VirtQueue *)) { if (handle_output) { vq->handle_aio_output = handle_output; @@ -1882,21 +1843,11 @@ static void virtio_queue_host_notifier_read(EventNotifier *n) void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign, bool set_handler) { - AioContext *ctx = qemu_get_aio_context(); if (assign && set_handler) { - if (vq->use_aio) { - aio_set_event_notifier(ctx, &vq->host_notifier, true, + event_notifier_set_handler(&vq->host_notifier, true, virtio_queue_host_notifier_read); - } else { - event_notifier_set_handler(&vq->host_notifier, true, - virtio_queue_host_notifier_read); - } } else { - if (vq->use_aio) { - aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL); - } else { - event_notifier_set_handler(&vq->host_notifier, true, NULL); - } + event_notifier_set_handler(&vq->host_notifier, true, NULL); } if (!assign) { /* Test and clear notifier before after disabling event, diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c index 2aeaf1fbc..bbf3646ba 100644 --- a/hw/watchdog/watchdog.c +++ b/hw/watchdog/watchdog.c @@ -143,7 +143,7 @@ void watchdog_perform_action(void) case WDT_NMI: qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_INJECT_NMI, &error_abort); - nmi_monitor_handle(0, NULL); + inject_nmi(); break; } } diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c index a7b64e2c4..f54a35a0e 100644 --- a/hw/watchdog/wdt_diag288.c +++ b/hw/watchdog/wdt_diag288.c @@ -16,7 +16,6 @@ #include "hw/sysbus.h" #include "qemu/timer.h" #include "hw/watchdog/wdt_diag288.h" -#include "qemu/log.h" static WatchdogTimerModel model = { .wdt_name = TYPE_WDT_DIAG288, diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h index 4d8d34ecb..6acf36e13 100644 --- a/hw/xen/xen-host-pci-device.h +++ b/hw/xen/xen-host-pci-device.h @@ -55,4 +55,4 @@ int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *s, uint32_t cap); -#endif /* XEN_HOST_PCI_DEVICE_H */ +#endif /* !XEN_HOST_PCI_DEVICE_H_ */ diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c index 69a238817..60575ad38 100644 --- a/hw/xen/xen_backend.c +++ b/hw/xen/xen_backend.c @@ -23,20 +23,16 @@ */ #include "qemu/osdep.h" +#include <sys/mman.h> #include <sys/signal.h> #include "hw/hw.h" -#include "hw/sysbus.h" #include "sysemu/char.h" #include "qemu/log.h" #include "hw/xen/xen_backend.h" #include <xen/grant_table.h> -#define TYPE_XENSYSDEV "xensysdev" - -DeviceState *xen_sysdev; - /* ------------------------------------------------------------- */ /* public */ @@ -46,36 +42,11 @@ struct xs_handle *xenstore = NULL; const char *xen_protocol; /* private */ -struct xs_dirs { - char *xs_dir; - QTAILQ_ENTRY(xs_dirs) list; -}; -static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = - QTAILQ_HEAD_INITIALIZER(xs_cleanup); - static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs); static int debug = 0; /* ------------------------------------------------------------- */ -static void xenstore_cleanup_dir(char *dir) -{ - struct xs_dirs *d; - - d = g_malloc(sizeof(*d)); - d->xs_dir = dir; - QTAILQ_INSERT_TAIL(&xs_cleanup, d, list); -} - -void xen_config_cleanup(void) -{ - struct xs_dirs *d; - - QTAILQ_FOREACH(d, &xs_cleanup, list) { - xs_rm(xenstore, 0, d->xs_dir); - } -} - int xenstore_write_str(const char *base, const char *node, const char *val) { char abspath[XEN_BUFSIZE]; @@ -104,30 +75,6 @@ char *xenstore_read_str(const char *base, const char *node) return ret; } -int xenstore_mkdir(char *path, int p) -{ - struct xs_permissions perms[2] = { - { - .id = 0, /* set owner: dom0 */ - }, { - .id = xen_domid, - .perms = p, - } - }; - - if (!xs_mkdir(xenstore, 0, path)) { - xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", path); - return -1; - } - xenstore_cleanup_dir(g_strdup(path)); - - if (!xs_set_permissions(xenstore, 0, path, perms, 2)) { - xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", path); - return -1; - } - return 0; -} - int xenstore_write_int(const char *base, const char *node, int ival) { char val[12]; @@ -321,28 +268,48 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev, /* * release xen backend device. */ -static void xen_be_del_xendev(struct XenDevice *xendev) +static struct XenDevice *xen_be_del_xendev(int dom, int dev) { - if (xendev->ops->free) { - xendev->ops->free(xendev); - } + struct XenDevice *xendev, *xnext; - if (xendev->fe) { - char token[XEN_BUFSIZE]; - snprintf(token, sizeof(token), "fe:%p", xendev); - xs_unwatch(xenstore, xendev->fe, token); - g_free(xendev->fe); - } + /* + * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but + * we save the next pointer in xnext because we might free xendev. + */ + xnext = xendevs.tqh_first; + while (xnext) { + xendev = xnext; + xnext = xendev->next.tqe_next; - if (xendev->evtchndev != NULL) { - xenevtchn_close(xendev->evtchndev); - } - if (xendev->gnttabdev != NULL) { - xengnttab_close(xendev->gnttabdev); - } + if (xendev->dom != dom) { + continue; + } + if (xendev->dev != dev && dev != -1) { + continue; + } + + if (xendev->ops->free) { + xendev->ops->free(xendev); + } - QTAILQ_REMOVE(&xendevs, xendev, next); - g_free(xendev); + if (xendev->fe) { + char token[XEN_BUFSIZE]; + snprintf(token, sizeof(token), "fe:%p", xendev); + xs_unwatch(xenstore, xendev->fe, token); + g_free(xendev->fe); + } + + if (xendev->evtchndev != NULL) { + xenevtchn_close(xendev->evtchndev); + } + if (xendev->gnttabdev != NULL) { + xengnttab_close(xendev->gnttabdev); + } + + QTAILQ_REMOVE(&xendevs, xendev, next); + g_free(xendev); + } + return NULL; } /* @@ -662,7 +629,7 @@ static void xenstore_update_be(char *watch, char *type, int dom, if (xendev != NULL) { bepath = xs_read(xenstore, 0, xendev->be, &len); if (bepath == NULL) { - xen_be_del_xendev(xendev); + xen_be_del_xendev(dom, dev); } else { free(bepath); xen_be_backend_changed(xendev, path); @@ -747,10 +714,6 @@ int xen_be_init(void) /* Check if xen_init() have been called */ goto err; } - - xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV); - qdev_init_nofail(xen_sysdev); - return 0; err: @@ -763,33 +726,9 @@ err: int xen_be_register(const char *type, struct XenDevOps *ops) { - char path[50]; - int rc; - - if (ops->backend_register) { - rc = ops->backend_register(); - if (rc) { - return rc; - } - } - - snprintf(path, sizeof(path), "device-model/%u/backends/%s", xen_domid, - type); - xenstore_mkdir(path, XS_PERM_NONE); - return xenstore_scan(type, xen_domid, ops); } -void xen_be_register_common(void) -{ - xen_be_register("console", &xen_console_ops); - xen_be_register("vkbd", &xen_kbdmouse_ops); - xen_be_register("qdisk", &xen_blkdev_ops); -#ifdef CONFIG_USB_LIBUSB - xen_be_register("qusb", &xen_usb_ops); -#endif -} - int xen_be_bind_evtchn(struct XenDevice *xendev) { if (xendev->local_port != -1) { @@ -861,35 +800,3 @@ void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ... } qemu_log_flush(); } - -static int xen_sysdev_init(SysBusDevice *dev) -{ - return 0; -} - -static Property xen_sysdev_properties[] = { - {/* end of property list */}, -}; - -static void xen_sysdev_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = xen_sysdev_init; - dc->props = xen_sysdev_properties; -} - -static const TypeInfo xensysdev_info = { - .name = TYPE_XENSYSDEV, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SysBusDevice), - .class_init = xen_sysdev_class_init, -}; - -static void xenbe_register_types(void) -{ - type_register_static(&xensysdev_info); -} - -type_init(xenbe_register_types); diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c index b7d290df6..1f30fe4f5 100644 --- a/hw/xen/xen_devconfig.c +++ b/hw/xen/xen_devconfig.c @@ -5,6 +5,54 @@ /* ------------------------------------------------------------- */ +struct xs_dirs { + char *xs_dir; + QTAILQ_ENTRY(xs_dirs) list; +}; +static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = QTAILQ_HEAD_INITIALIZER(xs_cleanup); + +static void xen_config_cleanup_dir(char *dir) +{ + struct xs_dirs *d; + + d = g_malloc(sizeof(*d)); + d->xs_dir = dir; + QTAILQ_INSERT_TAIL(&xs_cleanup, d, list); +} + +void xen_config_cleanup(void) +{ + struct xs_dirs *d; + + QTAILQ_FOREACH(d, &xs_cleanup, list) { + xs_rm(xenstore, 0, d->xs_dir); + } +} + +/* ------------------------------------------------------------- */ + +static int xen_config_dev_mkdir(char *dev, int p) +{ + struct xs_permissions perms[2] = {{ + .id = 0, /* set owner: dom0 */ + },{ + .id = xen_domid, + .perms = p, + }}; + + if (!xs_mkdir(xenstore, 0, dev)) { + xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev); + return -1; + } + xen_config_cleanup_dir(g_strdup(dev)); + + if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) { + xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev); + return -1; + } + return 0; +} + static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev, char *fe, char *be, int len) { @@ -18,8 +66,8 @@ static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev, snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev); free(dom); - xenstore_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE); - xenstore_mkdir(be, XS_PERM_READ); + xen_config_dev_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE); + xen_config_dev_mkdir(be, XS_PERM_READ); return 0; } diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index 191d9caea..c2f8e1fc2 100644 --- a/hw/xen/xen_pt.h +++ b/hw/xen/xen_pt.h @@ -332,4 +332,4 @@ int xen_pt_register_vga_regions(XenHostPCIDevice *dev); int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev); void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev, Error **errp); -#endif /* XEN_PT_H */ +#endif /* !XEN_PT_H */ diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index 6f18366f6..9869ffda0 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -2049,8 +2049,9 @@ void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp) for (j = 0; regs->size != 0; j++, regs++) { xen_pt_config_reg_init(s, reg_grp_entry, regs, &err); if (err) { - error_append_hint(&err, "Failed to init register %d" - " offsets 0x%x in grp_type = 0x%x (%d/%zu)", j, + error_append_hint(&err, "Failed to initialize %d/%zu" + " reg 0x%x in grp_type = 0x%x (%d/%zu)", + j, ARRAY_SIZE(xen_pt_emu_reg_grps[i].emu_regs), regs->offset, xen_pt_emu_reg_grps[i].grp_type, i, ARRAY_SIZE(xen_pt_emu_reg_grps)); error_propagate(errp, err); diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c index 62add0639..9a16f2bff 100644 --- a/hw/xen/xen_pt_msi.c +++ b/hw/xen/xen_pt_msi.c @@ -10,6 +10,7 @@ */ #include "qemu/osdep.h" +#include <sys/mman.h> #include "hw/xen/xen_backend.h" #include "xen_pt.h" diff --git a/hw/xenpv/xen_domainbuild.h b/hw/xenpv/xen_domainbuild.h index 652d9b410..29a91ea7b 100644 --- a/hw/xenpv/xen_domainbuild.h +++ b/hw/xenpv/xen_domainbuild.h @@ -1,5 +1,5 @@ #ifndef QEMU_HW_XEN_DOMAINBUILD_H -#define QEMU_HW_XEN_DOMAINBUILD_H +#define QEMU_HW_XEN_DOMAINBUILD_H 1 #include "hw/xen/xen_common.h" diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c index 79aef4ecc..fc1353599 100644 --- a/hw/xenpv/xen_machine_pv.c +++ b/hw/xenpv/xen_machine_pv.c @@ -67,8 +67,10 @@ static void xen_init_pv(MachineState *machine) break; } - xen_be_register_common(); + xen_be_register("console", &xen_console_ops); + xen_be_register("vkbd", &xen_kbdmouse_ops); xen_be_register("vfb", &xen_framebuffer_ops); + xen_be_register("qdisk", &xen_blkdev_ops); xen_be_register("qnic", &xen_netdev_ops); /* configure framebuffer */ diff --git a/hw/xtensa/bootparam.h b/hw/xtensa/bootparam.h index ade7891ec..955f4e86e 100644 --- a/hw/xtensa/bootparam.h +++ b/hw/xtensa/bootparam.h @@ -1,5 +1,5 @@ -#ifndef HW_XTENSA_BOOTPARAM_H -#define HW_XTENSA_BOOTPARAM_H +#ifndef HW_XTENSA_BOOTPARAM +#define HW_XTENSA_BOOTPARAM #define BP_TAG_COMMAND_LINE 0x1001 /* command line (0-terminated string)*/ #define BP_TAG_INITRD 0x1002 /* ramdisk addr and size (bp_meminfo) */ diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index 2bed64f15..c835bd009 100644 --- a/hw/xtensa/pic_cpu.c +++ b/hw/xtensa/pic_cpu.c @@ -26,7 +26,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "hw/hw.h" #include "qemu/log.h" #include "qemu/timer.h" @@ -122,8 +121,8 @@ void xtensa_rearm_ccompare_timer(CPUXtensaState *env) } env->wake_ccount = wake_ccount; timer_mod(env->ccompare_timer, env->halt_clock + - (uint64_t)(wake_ccount - env->sregs[CCOUNT]) * - 1000000 / env->config->clock_freq_khz); + muldiv64(wake_ccount - env->sregs[CCOUNT], + 1000000, env->config->clock_freq_khz)); } static void xtensa_ccompare_cb(void *opaque) diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index ac7594948..2d117369a 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -165,7 +165,7 @@ static pflash_t *xtfpga_flash_init(MemoryRegion *address_space, qdev_prop_set_uint32(dev, "num-blocks", board->flash_size / board->flash_sector_size); qdev_prop_set_uint64(dev, "sector-length", board->flash_sector_size); - qdev_prop_set_uint8(dev, "width", 2); + qdev_prop_set_uint8(dev, "width", 4); qdev_prop_set_bit(dev, "big-endian", be); qdev_prop_set_string(dev, "name", "lx60.io.flash"); qdev_init_nofail(dev); |