qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 1/9] PCI device registration helpers


From: Markus Armbruster
Subject: [Qemu-devel] [PATCH 1/9] PCI device registration helpers
Date: Thu, 22 Jan 2009 20:30:57 +0100

From: Markus Armbruster <address@hidden>

Registering a device with a PCI device address given as pci=... in the
common name=value,... option argument involves several steps: extract
the device address, parse it, find the PICBus, call
pci_register_device().  Put code for that in one place, namelt the new
helper function pci_register_device_2().  Yes, the name is stupid, and
is subject to change.

This code parses full PCI device addresses.  It then rejects domains
other than zero, because these are not supported in QEMU.
FIXME it lets you specify .func, which is most probably inappropriate.
---
 hw/pci.c |  102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pci.h |    6 ++++
 2 files changed, 108 insertions(+), 0 deletions(-)

diff --git a/hw/pci.c b/hw/pci.c
index bba50d0..a0e8562 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -26,6 +26,7 @@
 #include "console.h"
 #include "net.h"
 #include "virtio-net.h"
+#include "sysemu.h"
 
 //#define DEBUG_PCI
 
@@ -158,6 +159,97 @@ static int pci_set_default_subsystem_id(PCIDevice *pci_dev)
     return 0;
 }
 
+/*
+ * Parse [[<domain>:]<bus>:]<dev>[.<func>], return -1 on error
+ */
+int pci_parse_devaddr(const char *addr, int *domp, int *busp, int *devfnp)
+{
+    const char *p;
+    char *e;
+    unsigned long val;
+    unsigned long dom = 0, bus = 0;
+    unsigned slot;
+    unsigned func = 0;
+
+    p = addr;
+    val = strtoul(p, &e, 16);
+    if (e == p)
+       return -1;
+    if (*e == ':') {
+       bus = val;
+       p = e + 1;
+       val = strtoul(p, &e, 16);
+       if (e == p)
+           return -1;
+       if (*e == ':') {
+           dom = bus;
+           bus = val;
+           p = e + 1;
+           val = strtoul(p, &e, 16);
+           if (e == p)
+               return -1;
+       }
+    }
+
+    if (dom > 0xffff || bus > 0xff || val > 0x1f)
+       return -1;
+    slot = val;
+
+    if (*e == '.') {
+       p = e + 1;
+       val = strtoul(p, &e, 16);
+       if (e == p || val > 7 || *e != '\0')
+           return -1;
+       func = val;
+    }
+
+    if (*e)
+       return -1;
+
+    *domp = dom;
+    *busp = bus;
+    *devfnp = (slot << 3) | func;
+    return 0;
+}
+
+PCIDevice *pci_register_device_2(const char *name, const char *opts,
+                               int instance_size,
+                               PCIConfigReadFunc *config_read,
+                               PCIConfigWriteFunc *config_write)
+{
+    char devaddr[32];
+    int dom, bus_num, devfn;
+    PCIBus *bus;
+    PCIDevice *dev;
+
+    if (get_param_value(devaddr, sizeof(devaddr), "pci", opts)) {
+       if (pci_parse_devaddr(devaddr, &dom, &bus_num, &devfn) < 0) {
+           fprintf(stderr, "Bad PCI device address %s for %s",
+                   devaddr, name);
+           return NULL;
+       }
+    } else {
+       dom = bus_num = 0;
+       devfn = -1;
+    }
+
+    /* Note: QEMU doesn't implement domains other than 0 */
+    if (dom != 0 || (bus = pci_find_bus(bus_num)) == NULL) {
+       fprintf(stderr, "PCI device address %s not supported for %s",
+               devaddr, name);
+       return NULL;
+    }
+
+    dev = pci_register_device(bus, name, instance_size, devfn,
+                             config_read, config_write);
+    if (!dev) {
+       fprintf(stderr, "Could not set up PCI device %s", name);
+       return NULL;
+    }
+
+    return dev;
+}
+
 /* -1 for devfn means auto assign */
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
@@ -713,6 +805,16 @@ static void pci_bridge_write_config(PCIDevice *d,
     pci_default_write_config(d, address, val, len);
 }
 
+PCIBus *pci_find_bus(int bus_num)
+{
+    PCIBus *bus = first_bus;
+
+    while (bus && bus->bus_num != bus_num)
+        bus = bus->next;
+
+    return bus;
+}
+
 PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
                         pci_map_irq_fn map_irq, const char *name)
 {
diff --git a/hw/pci.h b/hw/pci.h
index 867e6fe..1528fc2 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -101,6 +101,10 @@ PCIDevice *pci_register_device(PCIBus *bus, const char 
*name,
                                int instance_size, int devfn,
                                PCIConfigReadFunc *config_read,
                                PCIConfigWriteFunc *config_write);
+PCIDevice *pci_register_device_2(const char *name, const char *opts,
+                               int instance_size,
+                               PCIConfigReadFunc *config_read,
+                               PCIConfigWriteFunc *config_write);
 
 void pci_register_io_region(PCIDevice *pci_dev, int region_num,
                             uint32_t size, int type,
@@ -112,6 +116,7 @@ void pci_default_write_config(PCIDevice *d,
                               uint32_t address, uint32_t val, int len);
 void pci_device_save(PCIDevice *s, QEMUFile *f);
 int pci_device_load(PCIDevice *s, QEMUFile *f);
+int pci_parse_devaddr(const char *addr, int *domain, int *bus, int *devfn);
 
 typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level);
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
@@ -124,6 +129,7 @@ void pci_data_write(void *opaque, uint32_t addr, uint32_t 
val, int len);
 uint32_t pci_data_read(void *opaque, uint32_t addr, int len);
 int pci_bus_num(PCIBus *s);
 void pci_for_each_device(int bus_num, void (*fn)(PCIDevice *d));
+PCIBus *pci_find_bus(int bus_num);
 
 void pci_info(void);
 PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint32_t id,
-- 
1.6.0.6





reply via email to

[Prev in Thread] Current Thread [Next in Thread]