mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
stubdom: PCI passthrough support via PV-PCI
Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
This commit is contained in:
1 parent
dac6f79804
commit
de4e084064
11 files changed
+638
-7
No files matched your search
@@ -0,0 +1,15 @@
|
||||
#include <types.h>
|
||||
#include <xen/io/pciif.h>
|
||||
struct pcifront_dev;
|
||||
struct pcifront_dev *init_pcifront(char *nodename);
|
||||
void pcifront_scan(struct pcifront_dev *dev, void (*fun)(unsigned int domain, unsigned int bus, unsigned slot, unsigned int fun));
|
||||
void pcifront_op(struct pcifront_dev *dev, struct xen_pci_op *op);
|
||||
void shutdown_pcifront(struct pcifront_dev *dev);
|
||||
int pcifront_conf_read(struct pcifront_dev *dev,
|
||||
unsigned int dom,
|
||||
unsigned int bus, unsigned int slot, unsigned long fun,
|
||||
unsigned int off, unsigned int size, unsigned int *val);
|
||||
int pcifront_conf_write(struct pcifront_dev *dev,
|
||||
unsigned int dom,
|
||||
unsigned int bus, unsigned int slot, unsigned long fun,
|
||||
unsigned int off, unsigned int size, unsigned int val);
|
||||
@@ -9,6 +9,9 @@
|
||||
#define MAP_PRIVATE 0x02
|
||||
#define MAP_ANON 0x20
|
||||
|
||||
/* Pages are always resident anyway */
|
||||
#define MAP_LOCKED 0x0
|
||||
|
||||
#define MAP_FAILED ((void*)0)
|
||||
|
||||
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <netfront.h>
|
||||
#include <blkfront.h>
|
||||
#include <fbfront.h>
|
||||
#include <pcifront.h>
|
||||
#include <fs.h>
|
||||
#include <xmalloc.h>
|
||||
#include <fcntl.h>
|
||||
@@ -431,6 +432,27 @@ static void kbdfront_thread(void *p)
|
||||
}
|
||||
}
|
||||
|
||||
static struct pcifront_dev *pci_dev;
|
||||
|
||||
static void pcifront_thread(void *p)
|
||||
{
|
||||
void print(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun)
|
||||
{
|
||||
unsigned int vendor, device, rev, class;
|
||||
|
||||
pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x00, 2, &vendor);
|
||||
pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x02, 2, &device);
|
||||
pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x08, 1, &rev);
|
||||
pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x0a, 2, &class);
|
||||
|
||||
printk("%04x:%02x:%02x.%02x %04x: %04x:%04x (rev %02x)\n", domain, bus, slot, fun, class, vendor, device, rev);
|
||||
}
|
||||
|
||||
pci_dev = init_pcifront(NULL);
|
||||
printk("PCI devices:\n");
|
||||
pcifront_scan(pci_dev, print);
|
||||
}
|
||||
|
||||
static void fs_thread(void *p)
|
||||
{
|
||||
init_fs_frontend();
|
||||
@@ -446,6 +468,7 @@ __attribute__((weak)) int app_main(start_info_t *si)
|
||||
create_thread("blkfront", blkfront_thread, si);
|
||||
create_thread("fbfront", fbfront_thread, si);
|
||||
create_thread("kbdfront", kbdfront_thread, si);
|
||||
create_thread("pcifront", pcifront_thread, si);
|
||||
create_thread("fs-frontend", fs_thread, si);
|
||||
return 0;
|
||||
}
|
||||
@@ -524,6 +547,9 @@ void stop_kernel(void)
|
||||
if (kbd_dev)
|
||||
shutdown_kbdfront(kbd_dev);
|
||||
|
||||
if (pci_dev)
|
||||
shutdown_pcifront(pci_dev);
|
||||
|
||||
/* TODO: fs import */
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
/* Minimal PCI driver for Mini-OS.
|
||||
* Copyright (c) 2007-2008 Samuel Thibault.
|
||||
* Based on blkfront.c.
|
||||
*/
|
||||
|
||||
#include <os.h>
|
||||
#include <xenbus.h>
|
||||
#include <events.h>
|
||||
#include <errno.h>
|
||||
#include <gnttab.h>
|
||||
#include <xmalloc.h>
|
||||
#include <wait.h>
|
||||
#include <pcifront.h>
|
||||
|
||||
#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
|
||||
|
||||
DECLARE_WAIT_QUEUE_HEAD(pcifront_queue);
|
||||
|
||||
struct pcifront_dev {
|
||||
domid_t dom;
|
||||
|
||||
struct xen_pci_sharedinfo *info;
|
||||
grant_ref_t info_ref;
|
||||
evtchn_port_t evtchn;
|
||||
|
||||
char *nodename;
|
||||
char *backend;
|
||||
|
||||
xenbus_event_queue events;
|
||||
};
|
||||
|
||||
void pcifront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
|
||||
{
|
||||
wake_up(&pcifront_queue);
|
||||
}
|
||||
|
||||
static void free_pcifront(struct pcifront_dev *dev)
|
||||
{
|
||||
mask_evtchn(dev->evtchn);
|
||||
|
||||
free(dev->backend);
|
||||
|
||||
gnttab_end_access(dev->info_ref);
|
||||
free_page(dev->info);
|
||||
|
||||
unbind_evtchn(dev->evtchn);
|
||||
|
||||
free(dev->nodename);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
struct pcifront_dev *init_pcifront(char *nodename)
|
||||
{
|
||||
xenbus_transaction_t xbt;
|
||||
char* err;
|
||||
char* message=NULL;
|
||||
int retry=0;
|
||||
char* msg;
|
||||
|
||||
struct pcifront_dev *dev;
|
||||
|
||||
if (!nodename)
|
||||
nodename = "device/pci/0";
|
||||
|
||||
char path[strlen(nodename) + 1 + 10 + 1];
|
||||
|
||||
printk("******************* PCIFRONT for %s **********\n\n\n", nodename);
|
||||
|
||||
dev = malloc(sizeof(*dev));
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
dev->nodename = strdup(nodename);
|
||||
|
||||
snprintf(path, sizeof(path), "%s/backend-id", nodename);
|
||||
dev->dom = xenbus_read_integer(path);
|
||||
evtchn_alloc_unbound(dev->dom, pcifront_handler, dev, &dev->evtchn);
|
||||
|
||||
dev->info = (struct xen_pci_sharedinfo*) alloc_page();
|
||||
memset(dev->info,0,PAGE_SIZE);
|
||||
|
||||
dev->info_ref = gnttab_grant_access(dev->dom,virt_to_mfn(dev->info),0);
|
||||
|
||||
dev->events = NULL;
|
||||
|
||||
again:
|
||||
err = xenbus_transaction_start(&xbt);
|
||||
if (err) {
|
||||
printk("starting transaction\n");
|
||||
}
|
||||
|
||||
err = xenbus_printf(xbt, nodename, "pci-op-ref","%u",
|
||||
dev->info_ref);
|
||||
if (err) {
|
||||
message = "writing pci-op-ref";
|
||||
goto abort_transaction;
|
||||
}
|
||||
err = xenbus_printf(xbt, nodename,
|
||||
"event-channel", "%u", dev->evtchn);
|
||||
if (err) {
|
||||
message = "writing event-channel";
|
||||
goto abort_transaction;
|
||||
}
|
||||
err = xenbus_printf(xbt, nodename,
|
||||
"magic", XEN_PCI_MAGIC);
|
||||
if (err) {
|
||||
message = "writing magic";
|
||||
goto abort_transaction;
|
||||
}
|
||||
|
||||
err = xenbus_printf(xbt, nodename, "state", "%u",
|
||||
3); /* initialised */
|
||||
|
||||
|
||||
err = xenbus_transaction_end(xbt, 0, &retry);
|
||||
if (retry) {
|
||||
goto again;
|
||||
printk("completing transaction\n");
|
||||
}
|
||||
|
||||
goto done;
|
||||
|
||||
abort_transaction:
|
||||
xenbus_transaction_end(xbt, 1, &retry);
|
||||
goto error;
|
||||
|
||||
done:
|
||||
|
||||
snprintf(path, sizeof(path), "%s/backend", nodename);
|
||||
msg = xenbus_read(XBT_NIL, path, &dev->backend);
|
||||
if (msg) {
|
||||
printk("Error %s when reading the backend path %s\n", msg, path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
printk("backend at %s\n", dev->backend);
|
||||
|
||||
{
|
||||
char path[strlen(dev->backend) + 1 + 5 + 1];
|
||||
snprintf(path, sizeof(path), "%s/state", dev->backend);
|
||||
|
||||
xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
|
||||
|
||||
xenbus_wait_for_value(path, "4", &dev->events);
|
||||
|
||||
xenbus_printf(xbt, nodename, "state", "%u", 4); /* connected */
|
||||
}
|
||||
unmask_evtchn(dev->evtchn);
|
||||
|
||||
printk("**************************\n");
|
||||
|
||||
return dev;
|
||||
|
||||
error:
|
||||
free_pcifront(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pcifront_scan(struct pcifront_dev *dev, void (*func)(unsigned int domain, unsigned int bus, unsigned slot, unsigned int fun))
|
||||
{
|
||||
char path[strlen(dev->backend) + 1 + 5 + 10 + 1];
|
||||
int i, n;
|
||||
char *s, *msg;
|
||||
unsigned int domain, bus, slot, fun;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/num_devs", dev->backend);
|
||||
n = xenbus_read_integer(path);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
snprintf(path, sizeof(path), "%s/vdev-%d", dev->backend, i);
|
||||
msg = xenbus_read(XBT_NIL, path, &s);
|
||||
if (msg) {
|
||||
printk("Error %s when reading the PCI root name at %s\n", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(s, "%x:%x:%x.%x", &domain, &bus, &slot, &fun) != 4) {
|
||||
printk("\"%s\" does not look like a PCI device address\n", s);
|
||||
free(s);
|
||||
continue;
|
||||
}
|
||||
free(s);
|
||||
|
||||
func(domain, bus, slot, fun);
|
||||
}
|
||||
}
|
||||
|
||||
void shutdown_pcifront(struct pcifront_dev *dev)
|
||||
{
|
||||
char* err;
|
||||
char *nodename = dev->nodename;
|
||||
|
||||
char path[strlen(dev->backend) + 1 + 5 + 1];
|
||||
|
||||
printk("close pci: backend at %s\n",dev->backend);
|
||||
|
||||
snprintf(path, sizeof(path), "%s/state", dev->backend);
|
||||
err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
|
||||
xenbus_wait_for_value(path, "5", &dev->events);
|
||||
|
||||
err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
|
||||
xenbus_wait_for_value(path, "6", &dev->events);
|
||||
|
||||
err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
|
||||
xenbus_wait_for_value(path, "2", &dev->events);
|
||||
|
||||
xenbus_unwatch_path(XBT_NIL, path);
|
||||
|
||||
snprintf(path, sizeof(path), "%s/info-ref", nodename);
|
||||
xenbus_rm(XBT_NIL, path);
|
||||
snprintf(path, sizeof(path), "%s/event-channel", nodename);
|
||||
xenbus_rm(XBT_NIL, path);
|
||||
|
||||
free_pcifront(dev);
|
||||
}
|
||||
|
||||
|
||||
void pcifront_op(struct pcifront_dev *dev, struct xen_pci_op *op)
|
||||
{
|
||||
dev->info->op = *op;
|
||||
/* Make sure info is written before the flag */
|
||||
wmb();
|
||||
set_bit(_XEN_PCIF_active, &dev->info->flags);
|
||||
notify_remote_via_evtchn(dev->evtchn);
|
||||
|
||||
wait_event(pcifront_queue, !test_bit(_XEN_PCIF_active, &dev->info->flags));
|
||||
|
||||
/* Make sure flag is read before info */
|
||||
rmb();
|
||||
*op = dev->info->op;
|
||||
}
|
||||
|
||||
int pcifront_conf_read(struct pcifront_dev *dev,
|
||||
unsigned int dom,
|
||||
unsigned int bus, unsigned int slot, unsigned long fun,
|
||||
unsigned int off, unsigned int size, unsigned int *val)
|
||||
{
|
||||
struct xen_pci_op op;
|
||||
|
||||
memset(&op, 0, sizeof(op));
|
||||
|
||||
op.cmd = XEN_PCI_OP_conf_read;
|
||||
op.domain = dom;
|
||||
op.bus = bus;
|
||||
op.devfn = PCI_DEVFN(slot, fun);
|
||||
op.offset = off;
|
||||
op.size = size;
|
||||
|
||||
pcifront_op(dev, &op);
|
||||
|
||||
if (op.err)
|
||||
return op.err;
|
||||
|
||||
*val = op.value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcifront_conf_write(struct pcifront_dev *dev,
|
||||
unsigned int dom,
|
||||
unsigned int bus, unsigned int slot, unsigned long fun,
|
||||
unsigned int off, unsigned int size, unsigned int val)
|
||||
{
|
||||
struct xen_pci_op op;
|
||||
|
||||
memset(&op, 0, sizeof(op));
|
||||
|
||||
op.cmd = XEN_PCI_OP_conf_write;
|
||||
op.domain = dom;
|
||||
op.bus = bus;
|
||||
op.devfn = PCI_DEVFN(slot, fun);
|
||||
op.offset = off;
|
||||
op.size = size;
|
||||
|
||||
op.value = val;
|
||||
|
||||
pcifront_op(dev, &op);
|
||||
|
||||
return op.err;
|
||||
}
|
||||
+7
-3
@@ -131,16 +131,20 @@ $(ZLIB_STAMPFILE): zlib-$(ZLIB_VERSION).tar.gz $(NEWLIB_STAMPFILE)
|
||||
pciutils-$(LIBPCI_VERSION).tar.bz2:
|
||||
$(WGET) http://www.kernel.org/pub/software/utils/pciutils/pciutils-$(LIBPCI_VERSION).tar.bz2
|
||||
|
||||
pciutils-$(LIBPCI_VERSION): pciutils-$(LIBPCI_VERSION).tar.bz2
|
||||
tar xjf $<
|
||||
patch -d $@ -p1 < pciutils.patch
|
||||
touch $@
|
||||
|
||||
LIBPCI_STAMPFILE=$(CROSS_ROOT)/$(GNU_TARGET_ARCH)-xen-elf/lib/libpci.a
|
||||
.PHONY: cross-libpci
|
||||
cross-libpci: $(LIBPCI_STAMPFILE)
|
||||
$(LIBPCI_STAMPFILE): pciutils-$(LIBPCI_VERSION).tar.bz2 $(NEWLIB_STAMPFILE) $(ZLIB_STAMPFILE)
|
||||
tar xjf $<
|
||||
$(LIBPCI_STAMPFILE): pciutils-$(LIBPCI_VERSION) $(NEWLIB_STAMPFILE) $(ZLIB_STAMPFILE)
|
||||
( cd pciutils-$(LIBPCI_VERSION) && \
|
||||
cp ../libpci.config.h lib/config.h && \
|
||||
echo '#define PCILIB_VERSION "$(LIBPCI_VERSION)"' >> lib/config.h && \
|
||||
cp ../libpci.config.mak lib/config.mk && \
|
||||
$(MAKE) CC="$(GNU_TARGET_ARCH)-xen-elf-gcc $(TARGET_CFLAGS)" lib/libpci.a && \
|
||||
$(MAKE) CC="$(GNU_TARGET_ARCH)-xen-elf-gcc $(TARGET_CFLAGS) -I$(realpath $(MINI_OS)/include)" lib/libpci.a && \
|
||||
$(INSTALL_DATA) lib/libpci.a $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/lib/ && \
|
||||
$(INSTALL_DIR) $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/include/pci && \
|
||||
$(INSTALL_DATA) lib/{config,header,pci,types}.h $(CROSS_PREFIX)/$(GNU_TARGET_ARCH)-xen-elf/include/pci/ \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#define PCI_OS_STUBDOM
|
||||
#define PCI_OS_MINIOS
|
||||
#define PCI_HAVE_STDINT_H
|
||||
#define PCI_PATH_IDS_DIR "."
|
||||
#define PCI_COMPRESSED_IDS
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
LIBZ=-lz
|
||||
LDLIBS+=$(LIBZ)
|
||||
PCI_OS_MINIOS=1
|
||||
PCI_HAVE_STDINT_H=1
|
||||
PCI_PATH_IDS_DIR=.
|
||||
PCI_COMPRESSED_IDS=1
|
||||
PCI_IDS=pci.ids.gz
|
||||
@@ -0,0 +1,299 @@
|
||||
diff -urN pciutils-2.2.9.orig/lib/access.c pciutils-2.2.9/lib/access.c
|
||||
--- pciutils-2.2.9.orig/lib/access.c 2007-02-06 11:59:43.000000000 +0000
|
||||
+++ pciutils-2.2.9/lib/access.c 2008-06-30 19:07:09.713187000 +0100
|
||||
@@ -57,6 +57,11 @@
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
+#ifdef PCI_OS_MINIOS
|
||||
+ &pm_minios,
|
||||
+#else
|
||||
+ NULL,
|
||||
+#endif
|
||||
};
|
||||
|
||||
struct pci_access *
|
||||
--- pciutils-2.2.9.orig/lib/pci.h 2006-09-09 13:46:06.000000000 +0100
|
||||
+++ pciutils-2.2.9/lib/pci.h 2008-06-30 18:56:15.350111000 +0100
|
||||
@@ -33,6 +33,7 @@
|
||||
PCI_ACCESS_NBSD_LIBPCI, /* NetBSD libpci */
|
||||
PCI_ACCESS_OBSD_DEVICE, /* OpenBSD /dev/pci */
|
||||
PCI_ACCESS_DUMP, /* Dump file (params: filename) */
|
||||
+ PCI_ACCESS_MINIOS, /* MiniOS */
|
||||
PCI_ACCESS_MAX
|
||||
};
|
||||
|
||||
@@ -63,6 +64,7 @@
|
||||
int fd_rw; /* proc: fd opened read-write */
|
||||
struct pci_dev *cached_dev; /* proc: device the fd is for */
|
||||
int fd_pos; /* proc: current position */
|
||||
+ void *minios;
|
||||
};
|
||||
|
||||
/* Initialize PCI access */
|
||||
--- pciutils-2.2.9.orig/lib/internal.h 2006-09-09 11:52:47.000000000 +0100
|
||||
+++ pciutils-2.2.9/lib/internal.h 2008-07-01 10:46:24.968202000 +0100
|
||||
@@ -37,4 +37,4 @@
|
||||
|
||||
extern struct pci_methods pm_intel_conf1, pm_intel_conf2, pm_linux_proc,
|
||||
pm_fbsd_device, pm_aix_device, pm_nbsd_libpci, pm_obsd_device,
|
||||
- pm_dump, pm_linux_sysfs;
|
||||
+ pm_dump, pm_linux_sysfs, pm_minios;
|
||||
--- pciutils-2.2.9.orig/lib/Makefile 2007-10-19 13:41:34.000000000 +0100
|
||||
+++ pciutils-2.2.9/lib/Makefile 2008-07-01 12:13:14.400525000 +0100
|
||||
@@ -46,6 +46,12 @@
|
||||
PCILIB=libpciutils.a
|
||||
endif
|
||||
|
||||
+ifdef PCI_OS_MINIOS
|
||||
+XEN_ROOT=../../..
|
||||
+include $(XEN_ROOT)/Config.mk
|
||||
+OBJS += minios.o
|
||||
+endif
|
||||
+
|
||||
all: $(PCILIB) $(PCILIBPC)
|
||||
|
||||
$(PCILIB): $(OBJS)
|
||||
--- pciutils-2.2.9.orig/lib/types.h 2007-09-03 09:44:15.000000000 +0100
|
||||
+++ pciutils-2.2.9/lib/types.h 2008-07-01 12:17:08.396156000 +0100
|
||||
@@ -17,9 +17,13 @@
|
||||
typedef DWORD u32;
|
||||
#elif defined(PCI_HAVE_STDINT_H)
|
||||
#include <stdint.h>
|
||||
+#ifdef PCI_OS_MINIOS
|
||||
+#include <types.h>
|
||||
+#else
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
+#endif
|
||||
#else
|
||||
typedef u_int8_t u8;
|
||||
typedef u_int16_t u16;
|
||||
--- pciutils-2.2.9.orig/lib/minios.c 1970-01-01 01:00:00.000000000 +0100
|
||||
+++ pciutils-2.2.9/lib/minios.c 2008-07-01 12:31:40.554260000 +0100
|
||||
@@ -0,0 +1,113 @@
|
||||
+/*
|
||||
+ * The PCI Library -- MiniOS PCI frontend access
|
||||
+ *
|
||||
+ * Samuel Thibault <samuel.thibault@eu.citrix.com>, 2008
|
||||
+ *
|
||||
+ * Can be freely distributed and used under the terms of the GNU GPL.
|
||||
+ */
|
||||
+
|
||||
+#include <os.h>
|
||||
+#include <pcifront.h>
|
||||
+#include <xenbus.h>
|
||||
+#include "internal.h"
|
||||
+
|
||||
+static int
|
||||
+minios_detect(struct pci_access *a)
|
||||
+{
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+minios_init(struct pci_access *a)
|
||||
+{
|
||||
+ a->minios = init_pcifront(NULL);
|
||||
+ if (!a->minios)
|
||||
+ a->warning("minios_init open failed");
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+minios_cleanup(struct pci_access *a)
|
||||
+{
|
||||
+ if (a->minios)
|
||||
+ shutdown_pcifront(a->minios);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+minios_scan(struct pci_access *a)
|
||||
+{
|
||||
+ if (!a->minios)
|
||||
+ return;
|
||||
+
|
||||
+ void func(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun)
|
||||
+ {
|
||||
+ struct pci_dev *d = pci_alloc_dev(a);
|
||||
+
|
||||
+ d->domain = domain;
|
||||
+ d->bus = bus;
|
||||
+ d->dev = slot;
|
||||
+ d->func = fun;
|
||||
+
|
||||
+ pci_link_dev(a, d);
|
||||
+ }
|
||||
+
|
||||
+ pcifront_scan(a->minios, func);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+minios_read(struct pci_dev *d, int pos, byte *buf, int len)
|
||||
+{
|
||||
+ unsigned int val;
|
||||
+ switch (len) {
|
||||
+ case 1:
|
||||
+ if (pcifront_conf_read(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, &val))
|
||||
+ return 0;
|
||||
+ * buf = val;
|
||||
+ return 1;
|
||||
+ case 2:
|
||||
+ if (pcifront_conf_read(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, &val))
|
||||
+ return 0;
|
||||
+ *(u16 *) buf = cpu_to_le16((u16) val);
|
||||
+ return 1;
|
||||
+ case 4:
|
||||
+ if (pcifront_conf_read(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, &val))
|
||||
+ return 0;
|
||||
+ *(u32 *) buf = cpu_to_le32((u32) val);
|
||||
+ return 1;
|
||||
+ default:
|
||||
+ return pci_generic_block_read(d, pos, buf, len);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+minios_write(struct pci_dev *d, int pos, byte *buf, int len)
|
||||
+{
|
||||
+ unsigned int val;
|
||||
+ switch (len) {
|
||||
+ case 1:
|
||||
+ val = * buf;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ val = le16_to_cpu(*(u16 *) buf);
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ val = le32_to_cpu(*(u32 *) buf);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return pci_generic_block_write(d, pos, buf, len);
|
||||
+ }
|
||||
+ return !pcifront_conf_write(d->access->minios, d->domain, d->bus, d->dev, d->func, pos, len, val);
|
||||
+}
|
||||
+
|
||||
+struct pci_methods pm_minios = {
|
||||
+ "MiniOS-device",
|
||||
+ NULL, /* config */
|
||||
+ minios_detect,
|
||||
+ minios_init,
|
||||
+ minios_cleanup,
|
||||
+ minios_scan,
|
||||
+ pci_generic_fill_info,
|
||||
+ minios_read,
|
||||
+ minios_write,
|
||||
+ NULL, /* dev_init */
|
||||
+ NULL /* dev_cleanup */
|
||||
+};
|
||||
--- pciutils-2.2.9/lib/generic.c 2007-02-06 12:00:05.000000000 +0000
|
||||
+++ pciutils-2.2.9-mine/lib/generic.c 2008-07-01 19:13:52.289949000 +0100
|
||||
@@ -74,6 +74,19 @@
|
||||
pci_generic_scan_bus(a, busmap, 0);
|
||||
}
|
||||
|
||||
+static u32 pci_size(u32 base, u32 maxbase, u32 mask)
|
||||
+{
|
||||
+ u32 size = mask & maxbase;
|
||||
+ if (!size)
|
||||
+ return 0;
|
||||
+ size = (size & ~(size-1)) - 1;
|
||||
+
|
||||
+ if (base == maxbase && ((base | size) & mask) != mask)
|
||||
+ return 0;
|
||||
+
|
||||
+ return size + 1;
|
||||
+}
|
||||
+
|
||||
int
|
||||
pci_generic_fill_info(struct pci_dev *d, int flags)
|
||||
{
|
||||
@@ -114,23 +127,61 @@
|
||||
if (!x || x == (u32) ~0)
|
||||
continue;
|
||||
if ((x & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
|
||||
- d->base_addr[i] = x;
|
||||
- else
|
||||
+ {
|
||||
+ d->base_addr[i] = x & PCI_BASE_ADDRESS_IO_MASK;
|
||||
+ if (flags & PCI_FILL_SIZES)
|
||||
+ {
|
||||
+ u32 size;
|
||||
+ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, ~0);
|
||||
+ d->size[i] = pci_size(x, pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4), PCI_BASE_ADDRESS_IO_MASK);
|
||||
+ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, x);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
{
|
||||
if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) != PCI_BASE_ADDRESS_MEM_TYPE_64)
|
||||
- d->base_addr[i] = x;
|
||||
+ {
|
||||
+ d->base_addr[i] = x & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
+ if (flags & PCI_FILL_SIZES)
|
||||
+ {
|
||||
+ u32 size;
|
||||
+ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, ~0);
|
||||
+ d->size[i] = pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4);
|
||||
+ d->size[i] = pci_size(x, pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4), PCI_BASE_ADDRESS_MEM_MASK);
|
||||
+ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, x);
|
||||
+ }
|
||||
+ }
|
||||
else if (i >= cnt-1)
|
||||
a->warning("%04x:%02x:%02x.%d: Invalid 64-bit address seen for BAR %d.", d->domain, d->bus, d->dev, d->func, i);
|
||||
else
|
||||
{
|
||||
u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4);
|
||||
#ifdef PCI_HAVE_64BIT_ADDRESS
|
||||
- d->base_addr[i-1] = x | (((pciaddr_t) y) << 32);
|
||||
+ d->base_addr[i-1] = (x | (((pciaddr_t) y) << 32)) & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
+ if (flags & PCI_FILL_SIZES)
|
||||
+ {
|
||||
+ u32 size;
|
||||
+ pci_write_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4, ~0);
|
||||
+ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, ~0);
|
||||
+ d->size[i-1] = pci_size(y, pci_read_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4) |
|
||||
+ pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4), 0xffffffff );
|
||||
+ pci_write_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4, x);
|
||||
+ pci_write_long(d, PCI_BASE_ADDRESS_0 + i*4, y);
|
||||
+ }
|
||||
#else
|
||||
if (y)
|
||||
a->warning("%04x:%02x:%02x.%d 64-bit device address ignored.", d->domain, d->bus, d->dev, d->func);
|
||||
else
|
||||
- d->base_addr[i-1] = x;
|
||||
+ {
|
||||
+ d->base_addr[i-1] = x & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
+ if (flags & PCI_FILL_SIZES)
|
||||
+ {
|
||||
+ u32 size;
|
||||
+ pci_write_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4, ~0);
|
||||
+ d->size[i-1] = pci_size(x, pci_read_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4), PCI_BASE_ADDRESS_MEM_MASK);
|
||||
+ pci_write_long(d, PCI_BASE_ADDRESS_0 + (i-1)*4, x);
|
||||
+ }
|
||||
+ }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -154,10 +205,19 @@
|
||||
{
|
||||
u32 u = pci_read_long(d, reg);
|
||||
if (u != 0xffffffff)
|
||||
- d->rom_base_addr = u;
|
||||
+ {
|
||||
+ d->rom_base_addr = u;
|
||||
+ if (flags & PCI_FILL_SIZES)
|
||||
+ {
|
||||
+ u32 size;
|
||||
+ pci_write_long(d, reg, ~0);
|
||||
+ d->rom_size = pci_read_long(d, reg);
|
||||
+ pci_write_long(d, reg, u);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
}
|
||||
- return flags & ~PCI_FILL_SIZES;
|
||||
+ return flags;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -358,7 +358,7 @@ VL_OBJS+=tap-win32.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_STUBDOM
|
||||
#CONFIG_PASSTHROUGH=1
|
||||
CONFIG_PASSTHROUGH=1
|
||||
else
|
||||
ifeq (,$(wildcard /usr/include/pci))
|
||||
$(warning *** pciutils-devl package not found - missing /usr/include/pci)
|
||||
|
||||
@@ -515,6 +515,7 @@ struct pt_dev * register_real_device(PCIBus *e_bus,
|
||||
PT_LOG("Error: couldn't locate device in libpci structures\n");
|
||||
return NULL;
|
||||
}
|
||||
pci_fill_info(pci_dev, PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES);
|
||||
|
||||
if ( e_devfn == PT_VIRT_DEVFN_AUTO ) {
|
||||
/*indicate a static assignment(not hotplug), so find a free PCI hot plug slot */
|
||||
|
||||
@@ -320,7 +320,7 @@ void xenstore_parse_domain_config(int hvm_domid)
|
||||
|
||||
/* get the pci pass-through parameter */
|
||||
if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/num_devs",
|
||||
domid, pci_devid) == -1)
|
||||
hvm_domid, pci_devid) == -1)
|
||||
goto out;
|
||||
|
||||
free(params);
|
||||
@@ -331,7 +331,7 @@ void xenstore_parse_domain_config(int hvm_domid)
|
||||
|
||||
for ( i = 0; i < num; i++ ) {
|
||||
if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/dev-%d",
|
||||
domid, pci_devid, i) != -1) {
|
||||
hvm_domid, pci_devid, i) != -1) {
|
||||
free(dev);
|
||||
dev = xs_read(xsh, XBT_NULL, buf, &len);
|
||||
|
||||
|
||||