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

[UNIKRAFT PATCH RFCv2 02/27] plat/platform: Introduce new platform bus



platform bus is a simple bus interface for many devices, including
virtio_mmio device on arm64

Signed-off-by: Jia He <justin.he@xxxxxxx>
---
 plat/common/include/platform_bus.h | 100 ++++++++++++
 plat/common/platform_bus.c         | 235 +++++++++++++++++++++++++++++
 2 files changed, 335 insertions(+)
 create mode 100644 plat/common/include/platform_bus.h
 create mode 100644 plat/common/platform_bus.c

diff --git a/plat/common/include/platform_bus.h 
b/plat/common/include/platform_bus.h
new file mode 100644
index 0000000..efc21a0
--- /dev/null
+++ b/plat/common/include/platform_bus.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Jia He <justin.he@xxxxxxx>
+ *
+ * Copyright (c) 2020, Arm Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#ifndef __UKPLAT_COMMON_PF_BUS_H__
+#define __UKPLAT_COMMON_PF_BUS_H__
+
+#include <uk/bus.h>
+#include <uk/alloc.h>
+
+/**
+ * A structure describing an ID for a Platform driver. Each driver provides a
+ * 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 UK_MAX_VIRTIO_MMIO_DEVICE (0x2)
+
+struct pf_device_id {
+       uint16_t device_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);
+
+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_add_func_t add_dev;
+};
+UK_TAILQ_HEAD(pf_driver_list, struct pf_driver);
+
+enum pf_device_state {
+       PF_DEVICE_STATE_RESET = 0,
+       PF_DEVICE_STATE_RUNNING
+};
+
+struct pf_device {
+       UK_TAILQ_ENTRY(struct pf_device) next; /**< used by pf_bus_handler */
+       struct pf_device_id  id;
+       struct pf_driver     *drv;
+       enum pf_device_state state;
+
+       uint64_t base;
+       unsigned long irq;
+};
+UK_TAILQ_HEAD(pf_device_list, struct pf_device);
+
+
+#define PF_REGISTER_DRIVER(b)                  \
+       _PF_REGISTER_DRIVER(__LIBNAME__, b)
+
+#define _PF_REGFNNAME(x, y)      x##y
+
+#define _PF_REGISTER_DRIVER(libname, b)                                \
+       static void __constructor_prio(105)                             \
+       _PF_REGFNNAME(libname, _pf_register_driver)(void)               \
+       {                                                               \
+               _pf_register_driver((b));                               \
+       }
+
+/* Do not use this function directly: */
+void _pf_register_driver(struct pf_driver *drv);
+
+#endif /* __UKPLAT_COMMON_PF_BUS_H__ */
diff --git a/plat/common/platform_bus.c b/plat/common/platform_bus.c
new file mode 100644
index 0000000..1410e71
--- /dev/null
+++ b/plat/common/platform_bus.c
@@ -0,0 +1,235 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Jia He <justin.he@xxxxxxx>
+ *
+ * Copyright (c) 2020, Arm Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#include <string.h>
+#include <uk/print.h>
+#include <uk/plat/common/cpu.h>
+#include <platform_bus.h>
+#include <libfdt.h>
+#include <kvm/config.h>
+#include <gic/gic-v2.h>
+#include <ofw/fdt.h>
+
+#define fdt_start (_libkvmplat_cfg.dtb)
+
+struct pf_bus_handler {
+       struct uk_bus b;
+       struct uk_alloc *a;
+       struct pf_driver_list drv_list;  /**< List of platform drivers */
+       int drv_list_initialized;
+       struct pf_device_list dev_list;  /**< List of platform devices */
+};
+static struct pf_bus_handler pfh;
+
+static const char * const pf_device_list[] = {
+       "virtio,mmio",
+};
+
+static inline int pf_device_id_match(const struct pf_device_id *id0,
+                                       const struct pf_device_id *id1)
+{
+       int rc = 0;
+
+       if (id0->device_id == id1->device_id)
+               rc = 1;
+
+       return rc;
+}
+
+static inline struct pf_driver *pf_find_driver(struct pf_device_id *id)
+{
+       struct pf_driver *drv;
+
+       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 */
+               }
+       }
+
+       uk_pr_info("no pf driver found\n");
+
+       return NULL; /* no driver found */
+}
+
+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;
+       int ret;
+
+       UK_ASSERT(drv != NULL);
+       UK_ASSERT(drv->add_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;
+
+       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 int pf_probe(void)
+{
+       struct pf_device_id devid;
+       struct pf_driver *drv;
+       int i;
+       int end_offset = -1;
+       int ret = -ENODEV;
+       const fdt32_t *prop;
+       int type, hwirq, prop_len;
+       __u64 reg_base;
+       __phys_addr dev_base;
+       int dev_irq;
+
+       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;
+
+       drv = pf_find_driver(&devid);
+       if (!drv) {
+               uk_pr_info("<no driver>\n");
+               return -ENODEV;
+       }
+
+       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;
+                       }
+
+                       type = fdt32_to_cpu(prop[0]);
+                       hwirq = fdt32_to_cpu(prop[1]);
+
+                       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;
+                       }
+
+                       /* 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]);
+               }
+
+               dev_base = reg_base;
+               dev_irq = gic_irq_translate(type, hwirq);
+
+               ret = pf_driver_add_device(drv, &devid, dev_base, dev_irq);
+       }
+
+       return ret;
+
+error_exit:
+       return -ENODEV;
+}
+
+
+static int pf_init(struct uk_alloc *a)
+{
+       struct pf_driver *drv, *drv_next;
+       int ret = 0;
+
+       UK_ASSERT(a != NULL);
+
+       pfh.a = a;
+
+       if (!pfh.drv_list_initialized) {
+               UK_TAILQ_INIT(&pfh.drv_list);
+               pfh.drv_list_initialized = 1;
+       }
+       UK_TAILQ_INIT(&pfh.dev_list);
+
+       UK_TAILQ_FOREACH_SAFE(drv, &pfh.drv_list, next, drv_next) {
+               if (drv->init) {
+                       ret = drv->init(a);
+                       if (ret == 0)
+                               continue;
+                       uk_pr_err("Failed to initialize pf driver %p: %d\n",
+                                 drv, ret);
+                       UK_TAILQ_REMOVE(&pfh.drv_list, drv, next);
+               }
+       }
+       return 0;
+}
+
+void _pf_register_driver(struct pf_driver *drv)
+{
+       UK_ASSERT(drv != NULL);
+       uk_pr_debug("_pf_register_driver %p\n", drv);
+
+       if (!pfh.drv_list_initialized) {
+               UK_TAILQ_INIT(&pfh.drv_list);
+               pfh.drv_list_initialized = 1;
+       }
+       UK_TAILQ_INSERT_TAIL(&pfh.drv_list, drv, next);
+}
+
+
+/* Register this bus driver to libukbus:
+ */
+static struct pf_bus_handler pfh = {
+       .b.init = pf_init,
+       .b.probe = pf_probe
+};
+UK_BUS_REGISTER(&pfh.b);
-- 
2.17.1




 


Rackspace

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