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

[UNIKRAFT PATCH RFCv3 12/32] plat/platform_bus: Add probe/match interface for platform devices



There is no hardware ID for platform device on arm64 device-tree,
thus it introduces an ID match interface to identify the device id.
device id should be registered as a constant value.

Also it introduces probe interface to parse the neccessary resource
(irq, base/size) in device-tree.

Signed-off-by: Jia He <justin.he@xxxxxxx>
---
 plat/common/include/platform_bus.h |  26 ++++-
 plat/common/platform_bus.c         | 148 +++++++++++++++--------------
 2 files changed, 96 insertions(+), 78 deletions(-)

diff --git a/plat/common/include/platform_bus.h 
b/plat/common/include/platform_bus.h
index efc21a0..ad56e0e 100644
--- a/plat/common/include/platform_bus.h
+++ b/plat/common/include/platform_bus.h
@@ -43,8 +43,10 @@
  * table of these IDs for each device that it supports.
  */
 #define PLATFORM_DEVICE_ID_START (0x100)
-#define VIRTIO_MMIO_ID PLATFORM_DEVICE_ID_START
-#define PLATFORM_DEVICE_ID_END (PLATFORM_DEVICE_ID_START + 0x100)
+#define VIRTIO_MMIO_ID         (PLATFORM_DEVICE_ID_START)
+#define GEN_PCI_ID             (PLATFORM_DEVICE_ID_START + 1)
+
+#define PLATFORM_DEVICE_ID_END (GEN_PCI_ID + 1)
 
 #define UK_MAX_VIRTIO_MMIO_DEVICE (0x2)
 
@@ -52,16 +54,25 @@ struct pf_device_id {
        uint16_t device_id;
 };
 
+struct device_match_table {
+       const char              *compatible;
+       struct pf_device_id     *id;
+};
+
 struct pf_device;
 
-typedef int (*pf_driver_add_func_t)(struct pf_device *);
 typedef int (*pf_driver_init_func_t)(struct uk_alloc *a);
+typedef int (*pf_driver_add_func_t)(struct pf_device *);
+typedef int (*pf_driver_probe_func_t)(struct pf_device *);
+typedef int (*pf_driver_match_func_t)(const char *);
 
 struct pf_driver {
        UK_TAILQ_ENTRY(struct pf_driver) next;
        const struct pf_device_id *device_ids;
        pf_driver_init_func_t init; /* optional */
+       pf_driver_probe_func_t probe;
        pf_driver_add_func_t add_dev;
+       pf_driver_match_func_t match;
 };
 UK_TAILQ_HEAD(pf_driver_list, struct pf_driver);
 
@@ -76,6 +87,7 @@ struct pf_device {
        struct pf_driver     *drv;
        enum pf_device_state state;
 
+       int fdt_offset; /* The start offset of fdt node for device */
        uint64_t base;
        unsigned long irq;
 };
@@ -87,12 +99,16 @@ UK_TAILQ_HEAD(pf_device_list, struct pf_device);
 
 #define _PF_REGFNNAME(x, y)      x##y
 
+#define PF_REGISTER_CTOR(CTOR)                         \
+               UK_CTOR_FUNC(1, CTOR)
+
 #define _PF_REGISTER_DRIVER(libname, b)                                \
-       static void __constructor_prio(105)                             \
+       static void                                             \
        _PF_REGFNNAME(libname, _pf_register_driver)(void)               \
        {                                                               \
                _pf_register_driver((b));                               \
-       }
+       }                                                               \
+       PF_REGISTER_CTOR(_PF_REGFNNAME(libname, _pf_register_driver))
 
 /* Do not use this function directly: */
 void _pf_register_driver(struct pf_driver *drv);
diff --git a/plat/common/platform_bus.c b/plat/common/platform_bus.c
index 1410e71..fecb389 100644
--- a/plat/common/platform_bus.c
+++ b/plat/common/platform_bus.c
@@ -52,8 +52,10 @@ struct pf_bus_handler {
 };
 static struct pf_bus_handler pfh;
 
-static const char * const pf_device_list[] = {
+static const char *pf_device_compatilbe_list[] = {
        "virtio,mmio",
+       "pci-host-ecam-generic",
+       NULL
 };
 
 static inline int pf_device_id_match(const struct pf_device_id *id0,
@@ -67,14 +69,22 @@ static inline int pf_device_id_match(const struct 
pf_device_id *id0,
        return rc;
 }
 
-static inline struct pf_driver *pf_find_driver(struct pf_device_id *id)
+static inline struct pf_driver *pf_find_driver(const char *compatible)
 {
        struct pf_driver *drv;
+       struct pf_device_id id;
 
        UK_TAILQ_FOREACH(drv, &pfh.drv_list, next) {
-               if (pf_device_id_match(id, drv->device_ids)) {
-                       uk_pr_debug("pf driver found devid=%d\n", 
drv->device_ids->device_id);
-                       return drv; /* driver found */
+               if (!drv->match)
+                       continue;
+
+               id.device_id = (uint16_t)drv->match(compatible);
+               if (id.device_id) {
+                       if (pf_device_id_match(&id, drv->device_ids)) {
+                               uk_pr_debug("pf driver found  devid(0x%x)\n", 
id.device_id);
+
+                               return drv;
+                       }
                }
        }
 
@@ -84,104 +94,96 @@ static inline struct pf_driver *pf_find_driver(struct 
pf_device_id *id)
 }
 
 static inline int pf_driver_add_device(struct pf_driver *drv,
-                                       struct pf_device_id *devid,
-                                       __u64 dev_base,
-                                       int dev_irq)
+                                       struct pf_device *dev)
 {
-       struct pf_device *dev;
        int ret;
 
        UK_ASSERT(drv != NULL);
        UK_ASSERT(drv->add_dev != NULL);
+       UK_ASSERT(dev != NULL);
 
-       dev = (struct pf_device *) uk_calloc(pfh.a, 1, sizeof(*dev));
-       if (!dev) {
-               uk_pr_err("Platform : Failed to initialize: Out of memory!\n");
-               return -ENOMEM;
-       }
-
-       memcpy(&dev->id, devid, sizeof(dev->id));
-       uk_pr_debug("pf_driver_add_device dev->id=%d\n", dev->id.device_id);
-
-       dev->base = dev_base;
-       dev->irq = dev_irq;
+       uk_pr_debug("pf_driver_add_device devid=%d\n", dev->id.device_id);
 
        ret = drv->add_dev(dev);
        if (ret < 0) {
                uk_pr_err("Platform Failed to initialize device driver\n");
-               uk_free(pfh.a, dev);
        }
 
        return ret;
 }
 
+static inline int pf_driver_probe_device(struct pf_driver *drv,
+                                       struct pf_device *dev)
+{
+       int ret;
+
+       UK_ASSERT(drv != NULL && dev != NULL);
+       UK_ASSERT(drv->probe != NULL);
+
+       uk_pr_info("pf_driver_probe_device devid=%d\n", dev->id.device_id);
+
+       ret = drv->probe(dev);
+       if (ret < 0) {
+               uk_pr_err("Platform Failed to probe device driver\n");
+
+               return ret;
+       }
+
+       return 0;
+}
+
 static int pf_probe(void)
 {
-       struct pf_device_id devid;
        struct pf_driver *drv;
-       int i;
-       int end_offset = -1;
+       int idx = 0;
        int ret = -ENODEV;
-       const fdt32_t *prop;
-       int type, hwirq, prop_len;
-       __u64 reg_base;
-       __phys_addr dev_base;
-       int dev_irq;
+       struct pf_device *dev;
+       int fdt_pf = -1;
 
        uk_pr_info("Probe PF\n");
 
-       /* We only support virtio_mmio as a platform device here.
-        * A loop here is needed for finding drivers if more devices
-        */
-       devid.device_id = VIRTIO_MMIO_ID;
+       /* Search all the platform bus devices provided by fdt */
+       do {
+               fdt_pf = 
fdt_node_offset_idx_by_compatible_list(_libkvmplat_cfg.dtb,
+                                               fdt_pf, 
pf_device_compatilbe_list, &idx);
+               if (fdt_pf < 0) {
+                       uk_pr_info("End of searching platform devices\n");
+                       break;
+               }
 
-       drv = pf_find_driver(&devid);
-       if (!drv) {
-               uk_pr_info("<no driver>\n");
-               return -ENODEV;
-       }
+               /* Alloc dev */
+               dev = (struct pf_device *) uk_calloc(pfh.a, 1, sizeof(*dev));
+               if (!dev) {
+                       uk_pr_err("Platform : Failed to initialize: Out of 
memory!\n");
+                       return -ENOMEM;
+               }
 
-       uk_pr_info("driver %p\n", drv);
-
-       /* qemu creates virtio devices in reverse order */
-       for (i = 0; i < UK_MAX_VIRTIO_MMIO_DEVICE; i++) {
-               end_offset = fdt_node_offset_by_compatible_list(fdt_start,
-                                                       end_offset,
-                                                       pf_device_list);
-               if (end_offset == -FDT_ERR_NOTFOUND) {
-                       uk_pr_info("device not found in fdt\n");
-                       goto error_exit;
-               } else {
-                       prop = fdt_getprop(fdt_start, end_offset, "interrupts", 
&prop_len);
-                       if (!prop) {
-                               uk_pr_err("irq of device not found in fdt\n");
-                               goto error_exit;
-                       }
+               dev->fdt_offset = fdt_pf;
 
-                       type = fdt32_to_cpu(prop[0]);
-                       hwirq = fdt32_to_cpu(prop[1]);
+               /* Find drv with compatible-id match table */
+               drv = pf_find_driver(pf_device_compatilbe_list[idx]);
+               if (!drv) {
+                       uk_free(pfh.a, dev);
+                       continue;
+               }
 
-                       prop = fdt_getprop(fdt_start, end_offset, "reg", 
&prop_len);
-                       if (!prop) {
-                               uk_pr_err("reg of device not found in fdt\n");
-                               goto error_exit;
-                       }
+               dev->id = *(struct pf_device_id *)drv->device_ids;
+               uk_pr_info("driver %p\n", drv);
 
-                       /* only care about base addr, ignore the size */
-                       reg_base = fdt32_to_cpu(prop[0]);
-                       reg_base = reg_base << 32 | fdt32_to_cpu(prop[1]);
+               ret = pf_driver_probe_device(drv, dev);
+               if (ret < 0) {
+                       uk_free(pfh.a, dev);
+                       continue;
                }
 
-               dev_base = reg_base;
-               dev_irq = gic_irq_translate(type, hwirq);
-
-               ret = pf_driver_add_device(drv, &devid, dev_base, dev_irq);
-       }
+               ret = pf_driver_add_device(drv, dev);
+               if (ret < 0) {
+                       uk_pr_err("Platform Failed to initialize device driver, 
ret(%d)\n",ret);
+                       uk_free(pfh.a, dev);
+               }
+       } while (1);
 
        return ret;
-
-error_exit:
-       return -ENODEV;
 }
 
 
@@ -232,4 +234,4 @@ static struct pf_bus_handler pfh = {
        .b.init = pf_init,
        .b.probe = pf_probe
 };
-UK_BUS_REGISTER(&pfh.b);
+UK_BUS_REGISTER_PRIORITY(&pfh.b, 1);
-- 
2.17.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.