From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
To: Anthony PERARD <anthony.perard@citrix.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>,
"Michael S. Tsirkin" <mst@redhat.com>,
Jan Kiszka <jan.kiszka@siemens.com>,
Stefano Stabellini <stefano.stabellini@eu.citrix.com>,
QEMU-devel <qemu-devel@nongnu.org>,
Xen Devel <xen-devel@lists.xen.org>
Subject: Re: [Qemu-devel] [Xen-devel] [PATCH V13 3/9] Introduce XenHostPCIDevice to access a pci device on the host.
Date: Thu, 14 Jun 2012 15:53:56 -0400 [thread overview]
Message-ID: <20120614195356.GB2175@phenom.dumpdata.com> (raw)
In-Reply-To: <1339693309-15192-4-git-send-email-anthony.perard@citrix.com>
On Thu, Jun 14, 2012 at 06:01:43PM +0100, Anthony PERARD wrote:
> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> ---
> hw/i386/Makefile.objs | 1 +
> hw/xen-host-pci-device.c | 396 ++++++++++++++++++++++++++++++++++++++++++++++
> hw/xen-host-pci-device.h | 55 +++++++
> 3 files changed, 452 insertions(+), 0 deletions(-)
> create mode 100644 hw/xen-host-pci-device.c
> create mode 100644 hw/xen-host-pci-device.h
>
> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
> index d43f1df..b719d8e 100644
> --- a/hw/i386/Makefile.objs
> +++ b/hw/i386/Makefile.objs
> @@ -7,6 +7,7 @@ obj-y += debugcon.o multiboot.o
> obj-y += pc_piix.o
> obj-y += pc_sysfw.o
> obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o
> +obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
> obj-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o kvm/i8254.o
> obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
>
> diff --git a/hw/xen-host-pci-device.c b/hw/xen-host-pci-device.c
> new file mode 100644
> index 0000000..e7ff680
> --- /dev/null
> +++ b/hw/xen-host-pci-device.c
> @@ -0,0 +1,396 @@
> +/*
> + * Copyright (C) 2011 Citrix Ltd.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "qemu-common.h"
> +#include "xen-host-pci-device.h"
> +
> +#define XEN_HOST_PCI_MAX_EXT_CAP \
> + ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4))
> +
> +#ifdef XEN_HOST_PCI_DEVICE_DEBUG
> +# define XEN_HOST_PCI_LOG(f, a...) fprintf(stderr, "%s: " f, __func__, ##a)
> +#else
> +# define XEN_HOST_PCI_LOG(f, a...) (void)0
> +#endif
> +
> +/*
> + * from linux/ioport.h
> + * IO resources have these defined flags.
> + */
> +#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */
> +
> +#define IORESOURCE_TYPE_BITS 0x00000f00 /* Resource type */
> +#define IORESOURCE_IO 0x00000100
> +#define IORESOURCE_MEM 0x00000200
> +
> +#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */
> +#define IORESOURCE_MEM_64 0x00100000
> +
> +static int xen_host_pci_sysfs_path(const XenHostPCIDevice *d,
> + const char *name, char *buf, ssize_t size)
> +{
> + int rc;
> +
> + rc = snprintf(buf, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
> + d->domain, d->bus, d->dev, d->func, name);
> +
> + if (rc >= size || rc < 0) {
> + /* The ouput is truncated or an other error is encountered */
> + return -ENODEV;
> + }
> + return 0;
> +}
> +
> +
> +/* This size should be enough to read the first 7 lines of a ressource file */
> +#define XEN_HOST_PCI_RESSOURCE_BUFFER_SIZE 400
> +static int xen_host_pci_get_resource(XenHostPCIDevice *d)
> +{
> + int i, rc, fd;
> + char path[PATH_MAX];
> + char buf[XEN_HOST_PCI_RESSOURCE_BUFFER_SIZE];
> + unsigned long long start, end, flags, size;
> + char *endptr, *s;
> + uint8_t type;
> +
> + rc = xen_host_pci_sysfs_path(d, "resource", path, sizeof (path));
> + if (rc) {
> + return rc;
> + }
> + fd = open(path, O_RDONLY);
> + if (fd == -1) {
> + XEN_HOST_PCI_LOG("Error: Can't open %s: %s\n", path, strerror(errno));
> + return -errno;
> + }
> +
> + do {
> + rc = read(fd, &buf, sizeof (buf) - 1);
> + if (rc < 0 && errno != EINTR) {
> + rc = -errno;
> + goto out;
> + }
> + } while (rc < 0);
> + buf[rc] = 0;
> + rc = 0;
> +
> + s = buf;
> + for (i = 0; i < PCI_NUM_REGIONS; i++) {
> + type = 0;
> +
> + start = strtoll(s, &endptr, 16);
> + if (*endptr != ' ' || s == endptr) {
> + break;
> + }
> + s = endptr + 1;
> + end = strtoll(s, &endptr, 16);
> + if (*endptr != ' ' || s == endptr) {
> + break;
> + }
> + s = endptr + 1;
> + flags = strtoll(s, &endptr, 16);
> + if (*endptr != '\n' || s == endptr) {
> + break;
> + }
> + s = endptr + 1;
> +
> + if (start) {
> + size = end - start + 1;
> + } else {
> + size = 0;
> + }
> +
> + if (flags & IORESOURCE_IO) {
> + type |= XEN_HOST_PCI_REGION_TYPE_IO;
> + }
> + if (flags & IORESOURCE_MEM) {
> + type |= XEN_HOST_PCI_REGION_TYPE_MEM;
> + }
> + if (flags & IORESOURCE_PREFETCH) {
> + type |= XEN_HOST_PCI_REGION_TYPE_PREFETCH;
> + }
> + if (flags & IORESOURCE_MEM_64) {
> + type |= XEN_HOST_PCI_REGION_TYPE_MEM_64;
> + }
> +
> + if (i < PCI_ROM_SLOT) {
> + d->io_regions[i].base_addr = start;
> + d->io_regions[i].size = size;
> + d->io_regions[i].type = type;
> + d->io_regions[i].bus_flags = flags & IORESOURCE_BITS;
> + } else {
> + d->rom.base_addr = start;
> + d->rom.size = size;
> + d->rom.type = type;
> + d->rom.bus_flags = flags & IORESOURCE_BITS;
> + }
> + }
> + if (i != PCI_NUM_REGIONS) {
> + /* Invalid format or input to short */
> + rc = -ENODEV;
> + }
> +
> +out:
> + close(fd);
> + return rc;
> +}
> +
> +/* This size should be enough to read a long from a file */
> +#define XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE 22
> +static int xen_host_pci_get_value(XenHostPCIDevice *d, const char *name,
> + unsigned int *pvalue, int base)
> +{
> + char path[PATH_MAX];
> + char buf[XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE];
> + int fd, rc;
> + unsigned long value;
> + char *endptr;
> +
> + rc = xen_host_pci_sysfs_path(d, name, path, sizeof (path));
> + if (rc) {
> + return rc;
> + }
> + fd = open(path, O_RDONLY);
> + if (fd == -1) {
> + XEN_HOST_PCI_LOG("Error: Can't open %s: %s\n", path, strerror(errno));
> + return -errno;
> + }
> + do {
> + rc = read(fd, &buf, sizeof (buf) - 1);
> + if (rc < 0 && errno != EINTR) {
> + rc = -errno;
> + goto out;
> + }
> + } while (rc < 0);
> + buf[rc] = 0;
> + value = strtol(buf, &endptr, base);
> + if (endptr == buf || *endptr != '\n') {
> + rc = -1;
> + } else if ((value == LONG_MIN || value == LONG_MAX) && errno == ERANGE) {
> + rc = -errno;
> + } else {
> + rc = 0;
> + *pvalue = value;
> + }
> +out:
> + close(fd);
> + return rc;
> +}
> +
> +static inline int xen_host_pci_get_hex_value(XenHostPCIDevice *d,
> + const char *name,
> + unsigned int *pvalue)
> +{
> + return xen_host_pci_get_value(d, name, pvalue, 16);
> +}
> +
> +static inline int xen_host_pci_get_dec_value(XenHostPCIDevice *d,
> + const char *name,
> + unsigned int *pvalue)
> +{
> + return xen_host_pci_get_value(d, name, pvalue, 10);
> +}
> +
> +static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d)
> +{
> + char path[PATH_MAX];
> + struct stat buf;
> +
> + if (xen_host_pci_sysfs_path(d, "physfn", path, sizeof (path))) {
> + return false;
> + }
> + return !stat(path, &buf);
> +}
> +
> +static int xen_host_pci_config_open(XenHostPCIDevice *d)
> +{
> + char path[PATH_MAX];
> + int rc;
> +
> + rc = xen_host_pci_sysfs_path(d, "config", path, sizeof (path));
> + if (rc) {
> + return rc;
> + }
> + d->config_fd = open(path, O_RDWR);
> + if (d->config_fd < 0) {
> + return -errno;
> + }
> + return 0;
> +}
> +
> +static int xen_host_pci_config_read(XenHostPCIDevice *d,
> + int pos, void *buf, int len)
> +{
> + int rc;
> +
> + do {
> + rc = pread(d->config_fd, buf, len, pos);
> + } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
> + if (rc != len) {
> + return -errno;
> + }
> + return 0;
> +}
> +
> +static int xen_host_pci_config_write(XenHostPCIDevice *d,
> + int pos, const void *buf, int len)
> +{
> + int rc;
> +
> + do {
> + rc = pwrite(d->config_fd, buf, len, pos);
> + } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
> + if (rc != len) {
> + return -errno;
> + }
> + return 0;
> +}
> +
> +
> +int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p)
> +{
> + uint8_t buf;
> + int rc = xen_host_pci_config_read(d, pos, &buf, 1);
> + if (!rc) {
> + *p = buf;
> + }
> + return rc;
> +}
> +
> +int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p)
> +{
> + uint16_t buf;
> + int rc = xen_host_pci_config_read(d, pos, &buf, 2);
> + if (!rc) {
> + *p = le16_to_cpu(buf);
> + }
> + return rc;
> +}
> +
> +int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p)
> +{
> + uint32_t buf;
> + int rc = xen_host_pci_config_read(d, pos, &buf, 4);
> + if (!rc) {
> + *p = le32_to_cpu(buf);
> + }
> + return rc;
> +}
> +
> +int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
> +{
> + return xen_host_pci_config_read(d, pos, buf, len);
> +}
> +
> +int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data)
> +{
> + return xen_host_pci_config_write(d, pos, &data, 1);
> +}
> +
> +int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data)
> +{
> + data = cpu_to_le16(data);
> + return xen_host_pci_config_write(d, pos, &data, 2);
> +}
> +
> +int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data)
> +{
> + data = cpu_to_le32(data);
> + return xen_host_pci_config_write(d, pos, &data, 4);
> +}
> +
> +int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
> +{
> + return xen_host_pci_config_write(d, pos, buf, len);
> +}
> +
> +int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *d, uint32_t cap)
> +{
> + uint32_t header = 0;
> + int max_cap = XEN_HOST_PCI_MAX_EXT_CAP;
> + int pos = PCI_CONFIG_SPACE_SIZE;
> +
> + do {
> + if (xen_host_pci_get_long(d, pos, &header)) {
> + break;
> + }
> + /*
> + * If we have no capabilities, this is indicated by cap ID,
> + * cap version and next pointer all being 0.
> + */
> + if (header == 0) {
> + break;
> + }
> +
> + if (PCI_EXT_CAP_ID(header) == cap) {
> + return pos;
> + }
> +
> + pos = PCI_EXT_CAP_NEXT(header);
> + if (pos < PCI_CONFIG_SPACE_SIZE) {
> + break;
> + }
> +
> + max_cap--;
> + } while (max_cap > 0);
> +
> + return -1;
> +}
> +
> +int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
> + uint8_t bus, uint8_t dev, uint8_t func)
> +{
> + unsigned int v;
> + int rc = 0;
> +
> + d->config_fd = -1;
> + d->domain = domain;
> + d->bus = bus;
> + d->dev = dev;
> + d->func = func;
> +
> + rc = xen_host_pci_config_open(d);
> + if (rc) {
> + goto error;
> + }
> + rc = xen_host_pci_get_resource(d);
> + if (rc) {
> + goto error;
> + }
> + rc = xen_host_pci_get_hex_value(d, "vendor", &v);
> + if (rc) {
> + goto error;
> + }
> + d->vendor_id = v;
> + rc = xen_host_pci_get_hex_value(d, "device", &v);
> + if (rc) {
> + goto error;
> + }
> + d->device_id = v;
> + rc = xen_host_pci_get_dec_value(d, "irq", &v);
> + if (rc) {
> + goto error;
> + }
> + d->irq = v;
> + d->is_virtfn = xen_host_pci_dev_is_virtfn(d);
> +
> + return 0;
> +error:
> + if (d->config_fd >= 0) {
> + close(d->config_fd);
> + d->config_fd = -1;
> + }
> + return rc;
> +}
> +
> +void xen_host_pci_device_put(XenHostPCIDevice *d)
> +{
> + if (d->config_fd >= 0) {
> + close(d->config_fd);
> + d->config_fd = -1;
> + }
> +}
> diff --git a/hw/xen-host-pci-device.h b/hw/xen-host-pci-device.h
> new file mode 100644
> index 0000000..0079dac
> --- /dev/null
> +++ b/hw/xen-host-pci-device.h
> @@ -0,0 +1,55 @@
> +#ifndef XEN_HOST_PCI_DEVICE_H
> +#define XEN_HOST_PCI_DEVICE_H
> +
> +#include "pci.h"
> +
> +enum {
> + XEN_HOST_PCI_REGION_TYPE_IO = 1 << 1,
> + XEN_HOST_PCI_REGION_TYPE_MEM = 1 << 2,
> + XEN_HOST_PCI_REGION_TYPE_PREFETCH = 1 << 3,
> + XEN_HOST_PCI_REGION_TYPE_MEM_64 = 1 << 4,
> +};
> +
> +typedef struct XenHostPCIIORegion {
> + pcibus_t base_addr;
> + pcibus_t size;
> + uint8_t type;
> + uint8_t bus_flags; /* Bus-specific bits */
> +} XenHostPCIIORegion;
> +
> +typedef struct XenHostPCIDevice {
> + uint16_t domain;
> + uint8_t bus;
> + uint8_t dev;
> + uint8_t func;
> +
> + uint16_t vendor_id;
> + uint16_t device_id;
> + int irq;
> +
> + XenHostPCIIORegion io_regions[PCI_NUM_REGIONS - 1];
> + XenHostPCIIORegion rom;
> +
> + bool is_virtfn;
> +
> + int config_fd;
> +} XenHostPCIDevice;
> +
> +int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
> + uint8_t bus, uint8_t dev, uint8_t func);
> +void xen_host_pci_device_put(XenHostPCIDevice *pci_dev);
> +
> +int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p);
> +int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p);
> +int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p);
> +int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf,
> + int len);
> +int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data);
> +int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data);
> +int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data);
> +int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf,
> + int len);
> +
> +int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *s, uint32_t cap);
> +
> +#endif /* !XEN_HOST_PCI_DEVICE_H_ */
> --
> Anthony PERARD
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
next prev parent reply other threads:[~2012-06-14 20:01 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-06-14 17:01 [Qemu-devel] [PATCH V13 0/9] Xen PCI Passthrough Anthony PERARD
2012-06-14 17:01 ` [Qemu-devel] [PATCH V13 1/9] pci_ids: Add INTEL_82599_SFP_VF id Anthony PERARD
2012-06-14 17:01 ` Anthony PERARD
2012-06-14 19:37 ` Michael S. Tsirkin
2012-06-14 19:37 ` [Qemu-devel] " Michael S. Tsirkin
2012-06-14 19:52 ` Konrad Rzeszutek Wilk
2012-06-14 19:52 ` [Qemu-devel] [Xen-devel] " Konrad Rzeszutek Wilk
2012-06-14 17:01 ` [Qemu-devel] [PATCH V13 2/9] configure: Introduce --enable-xen-pci-passthrough Anthony PERARD
2012-06-14 17:01 ` Anthony PERARD
2012-06-14 17:01 ` [Qemu-devel] [PATCH V13 3/9] Introduce XenHostPCIDevice to access a pci device on the host Anthony PERARD
2012-06-14 17:01 ` Anthony PERARD
2012-06-14 19:53 ` Konrad Rzeszutek Wilk
2012-06-14 19:53 ` Konrad Rzeszutek Wilk [this message]
2012-06-14 17:01 ` [Qemu-devel] [PATCH V13 4/9] pci.c: Add opaque argument to pci_for_each_device Anthony PERARD
2012-06-14 19:38 ` Michael S. Tsirkin
2012-06-14 19:38 ` Michael S. Tsirkin
2012-06-14 19:54 ` [Qemu-devel] [Xen-devel] " Konrad Rzeszutek Wilk
2012-06-14 19:54 ` Konrad Rzeszutek Wilk
2012-06-14 17:01 ` Anthony PERARD
2012-06-14 17:01 ` [PATCH V13 5/9] qdev-properties: Introduce pci-host-devaddr Anthony PERARD
2012-06-14 17:01 ` [Qemu-devel] " Anthony PERARD
2012-06-14 19:39 ` Michael S. Tsirkin
2012-06-14 19:39 ` Michael S. Tsirkin
2012-06-14 17:01 ` [Qemu-devel] [PATCH V13 6/9] Introduce Xen PCI Passthrough, qdevice (1/3) Anthony PERARD
2012-06-14 17:01 ` Anthony PERARD
2012-06-14 17:01 ` [Qemu-devel] [PATCH V13 7/9] Introduce Xen PCI Passthrough, PCI config space helpers (2/3) Anthony PERARD
2012-06-14 17:01 ` Anthony PERARD
2012-06-14 17:01 ` [PATCH V13 8/9] Introduce apic-msidef.h Anthony PERARD
2012-06-14 17:01 ` [Qemu-devel] " Anthony PERARD
2012-06-14 19:40 ` Michael S. Tsirkin
2012-06-14 19:40 ` Michael S. Tsirkin
2012-06-14 17:01 ` [PATCH V13 9/9] Introduce Xen PCI Passthrough, MSI (3/3) Anthony PERARD
2012-06-14 17:01 ` [Qemu-devel] " Anthony PERARD
2012-06-14 19:41 ` [PATCH V13 0/9] Xen PCI Passthrough Michael S. Tsirkin
2012-06-14 19:41 ` [Qemu-devel] " Michael S. Tsirkin
2012-06-15 11:05 ` Stefano Stabellini
2012-06-15 11:05 ` [Qemu-devel] " Stefano Stabellini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120614195356.GB2175@phenom.dumpdata.com \
--to=konrad.wilk@oracle.com \
--cc=aliguori@us.ibm.com \
--cc=anthony.perard@citrix.com \
--cc=jan.kiszka@siemens.com \
--cc=mst@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefano.stabellini@eu.citrix.com \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.