From patchwork Thu Sep 1 19:50:57 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 1120462 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p81Jq1LJ012949 for ; Thu, 1 Sep 2011 19:52:01 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757914Ab1IATv7 (ORCPT ); Thu, 1 Sep 2011 15:51:59 -0400 Received: from mx1.redhat.com ([209.132.183.28]:55219 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757909Ab1IATv5 (ORCPT ); Thu, 1 Sep 2011 15:51:57 -0400 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p81Jowhn010518 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 1 Sep 2011 15:50:59 -0400 Received: from s20.home (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p81Jov0K020566; Thu, 1 Sep 2011 15:50:57 -0400 From: Alex Williamson Subject: [RFC PATCH 5/5] VFIO: Simple test tool To: chrisw@sous-sol.org, aik@au1.ibm.com, pmac@au1.ibm.com, dwg@au1.ibm.com, joerg.roedel@amd.com, agraf@suse.de, benve@cisco.com, aafabbri@cisco.com, B08248@freescale.com, B07421@freescale.com, avi@redhat.com, kvm@vger.kernel.org, qemu-devel@nongnu.org, iommu@lists.linux-foundation.org, linux-pci@vger.kernel.org Cc: alex.williamson@redhat.com Date: Thu, 01 Sep 2011 13:50:57 -0600 Message-ID: <20110901195057.2391.60205.stgit@s20.home> In-Reply-To: <20110901194915.2391.97400.stgit@s20.home> References: <20110901194915.2391.97400.stgit@s20.home> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Thu, 01 Sep 2011 19:52:02 +0000 (UTC) Signed-off-by: Alex Williamson --- tools/testing/vfio/Makefile | 4 tools/testing/vfio/vfio_test.c | 406 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 410 insertions(+), 0 deletions(-) create mode 100644 tools/testing/vfio/Makefile create mode 100644 tools/testing/vfio/vfio_test.c -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/tools/testing/vfio/Makefile b/tools/testing/vfio/Makefile new file mode 100644 index 0000000..df1fa68 --- /dev/null +++ b/tools/testing/vfio/Makefile @@ -0,0 +1,4 @@ +vfio_test : vfio_test.c + +clean : + rm -f vfio_test diff --git a/tools/testing/vfio/vfio_test.c b/tools/testing/vfio/vfio_test.c new file mode 100644 index 0000000..66eef81 --- /dev/null +++ b/tools/testing/vfio/vfio_test.c @@ -0,0 +1,406 @@ +/* + * Simple user test program for vfio group/device/iommu framework + * + * Copyright (C) 2011 Red Hat, Inc. All rights reserved. + * Author: Alex Williamson + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../../include/linux/vfio.h" + +struct group { + int fd; + unsigned int number; + struct group *next; +}; + +struct group *group_list = NULL; + +struct device { + int fd; + char *name; + struct device *next; +}; + +struct device *device_list = NULL; + +struct iommu { + int fd; + struct device *next; +}; + +struct iommu *iommu_list = NULL; + +void print_group(unsigned int number) +{ + struct group *group = group_list; + char buf[4096]; + int ret; + + for (; group && group->number != number; group = group->next); + + if (!group) { + fprintf(stderr, "Group %u not found\n", number); + } else { + ret = pread(group->fd, buf, sizeof(buf), 0); + if (ret < 0) { + fprintf(stderr, "Error reading group %u (%s)\n", + group, strerror(errno)); + return; + } + fprintf(stdout, "---- Group %u (fd %d) begin ----\n", + number, group->fd); + fprintf(stdout, "%s", buf); + fprintf(stdout, "---- Group %u end ----\n", number); + } +} + +void print_device(struct device *device) +{ + fprintf(stdout, "---- Device %s (fd %d) ----\n", + device->name, device->fd); +} + +int do_device() +{ + char cmd[256]; + int ret; + + while (1) { + fprintf(stdout, "device command: "); + fscanf(stdin, "%s", cmd); + + if (!strcmp(cmd, "quit") || !strcmp(cmd, "exit") || + !strcmp(cmd, "q")) + return 0; + + if (!strcmp(cmd, "help") || !strcmp(cmd, "h")) { + fprintf(stdout, "[h]elp - this message\n"); + fprintf(stdout, "[o]pen - open device\n"); + fprintf(stdout, "[c]lose - close device\n"); + fprintf(stdout, "[l]ist - list devices\n"); + + } else if (!strcmp(cmd, "open") || !strcmp(cmd, "o")) { + int fd; + struct device *device; + + fprintf(stdout, "group fd #: "); + fscanf(stdin, "%d", &fd); + + fprintf(stdout, "device name: "); + fscanf(stdin, "%s", cmd); + + ret = ioctl(fd, VFIO_GROUP_GET_DEVICE_FD, cmd); + if (ret < 0) { + fprintf(stderr, "get device failed (%s)\n", + strerror(errno)); + return ret; + } + + device = malloc(sizeof(*device)); + if (!device) { + fprintf(stderr, "malloc device failed (%s)\n", + strerror(errno)); + return -1; + } + + device->fd = ret; + device->name = strdup(cmd); + device->next = device_list; + device_list = device; + print_device(device); + return 0; + + } else if (!strcmp(cmd, "close") || !strcmp(cmd, "c")) { + struct device *device; + + fprintf(stdout, "device name: "); + fscanf(stdin, "%s", cmd); + + for (device = device_list; + device && strcmp(device->name, cmd); + device = device->next); + + if (!device) { + fprintf(stderr, "device not found\n"); + return 0; + } + + ret = close(device->fd); + if (ret) { + fprintf(stderr, "Error closing device (%s)\n", + strerror(errno)); + return ret; + } + + if (device == device_list) + device_list = device->next; + else { + struct device *prev; + + for (prev = device_list; prev->next != device; + prev = prev->next); + + prev->next = device->next; + } + free(device->name); + free(device); + return 0; + + } else if (!strcmp(cmd, "list") || !strcmp(cmd, "l")) { + struct device *device; + + for (device = device_list; + device; device = device->next) + print_device(device); + + return 0; + } + } + return 0; +} + +void do_iommu() +{ + +} + +int main(int argc, char **argv) +{ + char cmd[256]; + int ret; + + while (1) { + fprintf(stdout, "command: "); + fscanf(stdin, "%s", cmd); + + if (!strcmp(cmd, "quit") || !strcmp(cmd, "exit") || + !strcmp(cmd, "q")) + return 0; + + if (!strcmp(cmd, "help") || !strcmp(cmd, "h")) { + fprintf(stdout, "[h]elp - this message\n"); + fprintf(stdout, "[p]rint - print group\n"); + fprintf(stdout, "[o]pen - open group\n"); + fprintf(stdout, "[c]lose - close group\n"); + fprintf(stdout, "close[f]d - close fd\n"); + fprintf(stdout, "[m]erge - merge group\n"); + fprintf(stdout, "[u]nmerge - unmerge group\n"); + fprintf(stdout, "[d]evice - device commands\n"); + fprintf(stdout, "[i]ommu - iommu commands\n"); + fprintf(stdout, "[l]ist - list groups\n"); + + } else if (!strcmp(cmd, "print") || !strcmp(cmd, "p")) { + unsigned int number; + + fprintf(stdout, "group #: "); + fscanf(stdin, "%u", &number); + + print_group(number); + + } else if (!strcmp(cmd, "device") || !strcmp(cmd, "d")) { + do_device(); + + } else if (!strcmp(cmd, "iommu") || !strcmp(cmd, "i")) { + do_iommu(); + + } else if (!strcmp(cmd, "list") || !strcmp(cmd, "l")) { + struct group *group; + + for (group = group_list; group; group = group->next) + print_group(group->number); + + } else if (!strcmp(cmd, "open") || !strcmp(cmd, "o")) { + unsigned int number; + struct group *group; + char path[256]; + + fprintf(stdout, "group #: "); + fscanf(stdin, "%u", &number); + + group = malloc(sizeof(*group)); + if (!group) { + fprintf(stderr, "Failed to alloc group\n"); + return -1; + } + + snprintf(path, sizeof(path), "/dev/vfio/%u", number); + group->fd = open(path, O_RDWR); + if (group->fd < 0) { + fprintf(stderr, "Failed to open %s (%s)\n", + path, strerror(errno)); + free(group); + continue; + } + group->number = number; + group->next = group_list; + group_list = group; + + print_group(number); + + } else if (!strcmp(cmd, "close") || !strcmp(cmd, "c")) { + unsigned int number; + struct group *group; + int ret; + + fprintf(stdout, "group #: "); + fscanf(stdin, "%u", &number); + + for (group = group_list; + group && group->number != number; + group = group->next); + + if (!group) { + fprintf(stderr, "group not open, open first\n"); + continue; + } + + ret = close(group->fd); + if (ret) { + fprintf(stderr, "close failed (%s)\n", + strerror(errno)); + continue; + } + + if (group == group_list) + group_list = group->next; + else { + struct group *prev; + + for (prev = group_list; prev->next != group; + prev = prev->next); + + prev->next = group->next; + } + free(group); + + } else if (!strcmp(cmd, "closefd") || !strcmp(cmd, "f")) { + int fd; + struct group *group; + int ret; + + fprintf(stdout, "fd #: "); + fscanf(stdin, "%d", &fd); + + for (group = group_list; + group && group->fd != fd; + group = group->next); + + if (!group) { + fprintf(stderr, "group not open, open first\n"); + continue; + } + + ret = close(group->fd); + if (ret) { + fprintf(stderr, "close failed (%s)\n", + strerror(errno)); + continue; + } + + if (group == group_list) + group_list = group->next; + else { + struct group *prev; + + for (prev = group_list; prev->next != group; + prev = prev->next); + + prev->next = group->next; + } + free(group); + + } else if (!strcmp(cmd, "merge") || !strcmp(cmd, "m")) { + unsigned int numberA, numberB; + struct group *groupA, *groupB; + int ret; + + fprintf(stdout, "base group #: "); + fscanf(stdin, "%u", &numberA); + + for (groupA = group_list; + groupA && groupA->number != numberA; + groupA = groupA->next); + + if (!groupA) { + fprintf(stderr, "group not open, open first\n"); + continue; + } + + fprintf(stdout, "merge group #: "); + fscanf(stdin, "%u", &numberB); + + for (groupB = group_list; + groupB && groupB->number != numberB; + groupB = groupB->next); + + if (!groupB) { + fprintf(stderr, "group not open, open first\n"); + continue; + } + + ret = ioctl(groupA->fd, VFIO_GROUP_MERGE, &groupB->fd); + if (ret) { + fprintf(stderr, "group merge failed (%s)\n", + strerror(errno)); + continue; + } + + print_group(numberA); + print_group(numberB); + + } else if (!strcmp(cmd, "unmerge") || !strcmp(cmd, "u")) { + unsigned int numberA, numberB; + struct group *groupA, *groupB; + int ret; + + fprintf(stdout, "base group #: "); + fscanf(stdin, "%u", &numberA); + + for (groupA = group_list; + groupA && groupA->number != numberA; + groupA = groupA->next); + + if (!groupA) { + fprintf(stderr, "group not open, open first\n"); + continue; + } + + fprintf(stdout, "unmerge group #: "); + fscanf(stdin, "%u", &numberB); + + for (groupB = group_list; + groupB && groupB->number != numberB; + groupB = groupB->next); + + if (!groupB) { + fprintf(stderr, "group not open, open first\n"); + continue; + } + + ret = ioctl(groupA->fd, + VFIO_GROUP_UNMERGE, &groupB->fd); + if (ret) { + fprintf(stderr, "group unmerge failed (%s)\n", + strerror(errno)); + continue; + } + + print_group(numberA); + print_group(numberB); + } + } +}