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

Re: [Minios-devel] [UNIKRAFT PATCH v3 2/2] plat/kvm: Add initial PCI bus driver for x86_64



Reviewed-by: Yuri Volchkov <yuri.volchkov@xxxxxxxxx>

Simon Kuenzer <simon.kuenzer@xxxxxxxxx> writes:

> From: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
>
> Introduces the first & initial version of PCI bus driver.
> It is able to iterate over PCI devices and detect
> if an driver is available. It is going to call a driver
> callback function to handover initialization for each
> found device.
> Although the code is put to `plat/common` it has some
> dependency to KVM x86_64 with the I/O functions. These
> functions should be moved to the appropriate place on
> successive patches for PCI.
>
> Signed-off-by: Simon Kuenzer <simon.kuenzer@xxxxxxxxx>
> Signed-off-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
> ---
>  plat/common/include/pci/pci_bus.h | 227 ++++++++++++++++++++++++++
>  plat/common/pci_bus.c             | 324 
> ++++++++++++++++++++++++++++++++++++++
>  plat/kvm/Config.uk                |  11 +-
>  plat/kvm/Makefile.uk              |   5 +
>  4 files changed, 565 insertions(+), 2 deletions(-)
>  create mode 100644 plat/common/include/pci/pci_bus.h
>  create mode 100644 plat/common/pci_bus.c
>
> diff --git a/plat/common/include/pci/pci_bus.h 
> b/plat/common/include/pci/pci_bus.h
> new file mode 100644
> index 0000000..b03bcfd
> --- /dev/null
> +++ b/plat/common/include/pci/pci_bus.h
> @@ -0,0 +1,227 @@
> +/* SPDX-License-Identifier: BSD-3-Clause */
> +/*
> + * Authors: Simon Kuenzer <simon.kuenzer@xxxxxxxxx>
> + *
> + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. 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.
> + */
> +/*
> + * Copyright(c) 2010-2015 Intel Corporation.
> + * Copyright 2013-2014 6WIND S.A.
> + *
> + * 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.
> + */
> +
> +#ifndef __UKPLAT_COMMON_PCI_BUS_H__
> +#define __UKPLAT_COMMON_PCI_BUS_H__
> +
> +#include <uk/bus.h>
> +#include <uk/alloc.h>
> +
> +/**
> + * A structure describing an ID for a PCI driver. Each driver provides a
> + * table of these IDs for each device that it supports.
> + *  * Derived from: lib/librte_pci/rte_pci.h
> + */
> +struct pci_device_id {
> +     /**< Class ID or PCI_CLASS_ANY_ID. */
> +     uint32_t class_id;
> +     /**< Vendor ID or PCI_ANY_ID. */
> +     uint16_t vendor_id;
> +     /**< Device ID or PCI_ANY_ID. */
> +     uint16_t device_id;
> +     /**< Subsystem vendor ID or PCI_ANY_ID. */
> +     uint16_t subsystem_vendor_id;
> +     /**< Subsystem device ID or PCI_ANY_ID. */
> +     uint16_t subsystem_device_id;
> +};
> +
> +/** Any PCI device identifier (vendor, device, ...) */
> +#define PCI_ANY_ID       (0xffff)
> +#define PCI_CLASS_ANY_ID (0xffffff)
> +
> +/**
> + * Macros used to help building up tables of device IDs
> + * Derived from: lib/librte_pci/rte_pci.h
> + */
> +#define PCI_DEVICE_ID(vend, dev)           \
> +     .class_id = PCI_CLASS_ANY_ID,      \
> +     .vendor_id = (vend),               \
> +     .device_id = (dev),                \
> +     .subsystem_vendor_id = PCI_ANY_ID, \
> +     .subsystem_device_id = PCI_ANY_ID
> +
> +#define PCI_ANY_DEVICE_ID                  \
> +     .class_id = PCI_CLASS_ANY_ID,      \
> +     .vendor_id = PCI_ANY_ID,           \
> +     .device_id = PCI_ANY_ID,           \
> +     .subsystem_vendor_id = PCI_ANY_ID, \
> +     .subsystem_device_id = PCI_ANY_ID
> +
> +/**
> + * A structure describing the location of a PCI device.
> + * Derived from: lib/librte_pci/rte_pci.h
> + */
> +struct pci_address {
> +     /**< Device domain */
> +     uint32_t domain;
> +     /**< Device bus */
> +     uint8_t bus;
> +     /**< Device ID */
> +     uint8_t devid;
> +     /**< Device function. */
> +     uint8_t function;
> +};
> +
> +struct pci_device;
> +
> +typedef int (*pci_driver_add_func_t)(struct pci_device *);
> +typedef int (*pci_driver_init_func_t)(struct uk_alloc *a);
> +
> +struct pci_driver {
> +     UK_TAILQ_ENTRY(struct pci_driver) next;
> +     /**< ANY-ID terminated list of device IDs that the driver handles */
> +     const struct pci_device_id *device_ids;
> +     pci_driver_init_func_t init; /* optional */
> +     pci_driver_add_func_t add_dev;
> +};
> +UK_TAILQ_HEAD(pci_driver_list, struct pci_driver);
> +
> +enum pci_device_state {
> +     PCI_DEVICE_STATE_RESET = 0,
> +     PCI_DEVICE_STATE_RUNNING
> +};
> +
> +struct pci_device {
> +     UK_TAILQ_ENTRY(struct pci_device) next; /**< used by pci_bus_handler */
> +     struct pci_device_id  id;
> +     struct pci_address    addr;
> +     struct pci_driver     *drv;
> +     enum pci_device_state state;
> +
> +     uint16_t base;
> +     unsigned long irq;
> +};
> +UK_TAILQ_HEAD(pci_device_list, struct pci_device);
> +
> +
> +#define PCI_REGISTER_DRIVER(b)                  \
> +     _PCI_REGISTER_DRIVER(__LIBNAME__, b)
> +
> +#define _PCI_REGFNNAME(x, y)      x##y
> +
> +#define _PCI_REGISTER_DRIVER(libname, b)                             \
> +     static void __constructor_prio(103)                             \
> +     PCI_REGFNNAME(libname, _pci_register_driver)(void)              \
> +     {                                                               \
> +             _pci_register_driver((b));                              \
> +     }
> +
> +/* Do not use this function directly: */
> +void _pci_register_driver(struct pci_driver *drv);
> +
> +
> +/* TODO: Move these I/O functions to architecture/platform specific
> + *       implementation. They are used to interact with the PCI bus.
> + *       They work for x86_64 only for now
> + */
> +static inline uint8_t inb(uint16_t port)
> +{
> +     uint8_t v;
> +
> +     __asm__ __volatile__("inb %1,%0" : "=a" (v) : "dN" (port));
> +     return v;
> +}
> +static inline uint16_t inw(uint16_t port)
> +{
> +     uint16_t v;
> +
> +     __asm__ __volatile__("inw %1,%0" : "=a" (v) : "dN" (port));
> +     return v;
> +}
> +static inline uint32_t inl(uint16_t port)
> +{
> +     uint32_t v;
> +
> +     __asm__ __volatile__("inl %1,%0" : "=a" (v) : "dN" (port));
> +     return v;
> +}
> +
> +static inline uint64_t inq(uint16_t port_lo)
> +{
> +     uint16_t port_hi = port_lo + 4;
> +     uint32_t lo, hi;
> +
> +     __asm__ __volatile__("inl %1,%0" : "=a" (lo) : "dN" (port_lo));
> +     __asm__ __volatile__("inl %1,%0" : "=a" (hi) : "dN" (port_hi));
> +
> +     return ((uint64_t)lo) | ((uint64_t)hi << 32);
> +}
> +
> +static inline void outb(uint16_t port, uint8_t v)
> +{
> +     __asm__ __volatile__("outb %0,%1" : : "a" (v), "dN" (port));
> +}
> +
> +static inline void outw(uint16_t port, uint16_t v)
> +{
> +     __asm__ __volatile__("outw %0,%1" : : "a" (v), "dN" (port));
> +}
> +
> +static inline void outl(uint16_t port, uint32_t v)
> +{
> +     __asm__ __volatile__("outl %0,%1" : : "a" (v), "dN" (port));
> +}
> +
> +#endif /* __UKPLAT_COMMON_PCI_BUS_H__ */
> diff --git a/plat/common/pci_bus.c b/plat/common/pci_bus.c
> new file mode 100644
> index 0000000..c19545e
> --- /dev/null
> +++ b/plat/common/pci_bus.c
> @@ -0,0 +1,324 @@
> +/* TODO: SPDX Header */
> +/*
> + * Authors: Simon Kuenzer <simon.kuenzer@xxxxxxxxx>
> + *
> + * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. 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.
> + */
> +/* Some code was derived from Solo5: */
> +/*
> + * Copyright (c) 2015-2017 Contributors as noted in the AUTHORS file
> + *
> + * This file is part of Solo5, a unikernel base layer.
> + *
> + * Permission to use, copy, modify, and/or distribute this software
> + * for any purpose with or without fee is hereby granted, provided
> + * that the above copyright notice and this permission notice appear
> + * in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
> + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
> + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
> + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
> + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
> + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <string.h>
> +#include <uk/print.h>
> +#include <pci_bus.h>
> +
> +struct pci_bus_handler {
> +     struct uk_bus b;
> +     struct uk_alloc *a;
> +     struct pci_driver_list drv_list;  /**< List of PCI drivers */
> +     int drv_list_initialized;
> +     struct pci_device_list dev_list;  /**< List of PCI devices */
> +};
> +static struct pci_bus_handler ph;
> +
> +#define FOREACH_DRIVER(drv) \
> +     UK_TAILQ_FOREACH(drv, &ph.drv_list, next)
> +
> +#define FOREACH_DRIVER_SAFE(drv, drv_next) \
> +     UK_TAILQ_FOREACH_SAFE(drv, &ph.drv_list, next, drv_next)
> +
> +#define FOREACH_DEVICE(dev) \
> +     UK_TAILQ_FOREACH(dev, &ph.dev_list, ph_next)
> +
> +#define PCI_INVALID_ID              (0xFFFF)
> +#define PCI_DEVICE_ID_MASK          (0xFFFF)
> +
> +#define PCI_CONFIG_ADDR             (0xCF8)
> +#define PCI_CONFIG_DATA             (0xCFC)
> +
> +/* 8 bits for bus number, 5 bits for devices */
> +#define PCI_MAX_BUSES               (1 << 8)
> +#define PCI_MAX_DEVICES             (1 << 5)
> +
> +#define PCI_BUS_SHIFT               (16)
> +#define PCI_DEVICE_SHIFT            (11)
> +#define PCI_ENABLE_BIT              (1 << 31)
> +
> +#define PCI_CONF_SUBSYS_ID          (0x2c)
> +#define PCI_CONF_SUBSYS_ID_SHFT     (16)
> +#define PCI_CONF_SUBSYS_ID_MASK     (0xFFFF)
> +
> +#define PCI_CONF_IRQ                (0X3C)
> +#define PCI_CONF_IRQ_SHFT           (0x0)
> +#define PCI_CONF_IRQ_MASK           (0XFF)
> +
> +#define PCI_CONF_IOBAR              (0x10)
> +#define PCI_CONF_IOBAR_SHFT         (0x0)
> +#define PCI_CONF_IOBAR_MASK         (~0x3)
> +
> +#define PCI_CONF_READ(type, ret, a, s)                                       
> \
> +     do {                                                            \
> +             uint32_t _conf_data;                                    \
> +             outl(PCI_CONFIG_ADDR, (a) | PCI_CONF_##s);              \
> +             _conf_data = ((inl(PCI_CONFIG_DATA) >> PCI_CONF_##s##_SHFT) \
> +                           & PCI_CONF_##s##_MASK);                   \
> +             *(ret) = (type) _conf_data;                             \
> +     } while (0)
> +
> +static inline int pci_device_id_match(const struct pci_device_id *id0,
> +                                     const struct pci_device_id *id1)
> +{
> +     if ((id0->class_id != PCI_CLASS_ANY_ID) &&
> +         (id1->class_id != PCI_CLASS_ANY_ID) &&
> +         (id0->class_id != id1->class_id)) {
> +             return 0;
> +     }
> +     if ((id0->vendor_id != PCI_ANY_ID) &&
> +         (id1->vendor_id != PCI_ANY_ID) &&
> +         (id0->vendor_id != id1->vendor_id)) {
> +             return 0;
> +     }
> +     if ((id0->device_id != PCI_ANY_ID) &&
> +         (id1->device_id != PCI_ANY_ID) &&
> +         (id0->device_id != id1->device_id)) {
> +             return 0;
> +     }
> +     if ((id0->subsystem_vendor_id != PCI_ANY_ID) &&
> +         (id1->subsystem_vendor_id != PCI_ANY_ID) &&
> +         (id0->subsystem_vendor_id != id1->subsystem_vendor_id)) {
> +             return 0;
> +     }
> +     if ((id0->subsystem_device_id != PCI_ANY_ID) &&
> +         (id1->subsystem_device_id != PCI_ANY_ID) &&
> +         (id0->subsystem_device_id != id1->subsystem_device_id)) {
> +             return 0;
> +     }
> +     return 1;
> +}
> +
> +static inline int pci_device_id_is_any(const struct pci_device_id *id)
> +{
> +     if ((id->class_id == PCI_CLASS_ANY_ID) &&
> +         (id->vendor_id == PCI_ANY_ID) &&
> +         (id->device_id == PCI_ANY_ID) &&
> +         (id->subsystem_vendor_id == PCI_ANY_ID) &&
> +         (id->subsystem_device_id == PCI_ANY_ID)) {
> +             return 1;
> +     }
> +     return 0;
> +}
> +
> +static inline struct pci_driver *pci_find_driver(struct pci_device_id *id)
> +{
> +     struct pci_driver *drv;
> +     const struct pci_device_id *drv_id;
> +
> +     FOREACH_DRIVER(drv) {
> +             for (drv_id = drv->device_ids;
> +                  !pci_device_id_is_any(drv_id);
> +                  drv_id++) {
> +                     if (pci_device_id_match(id, drv_id))
> +                             return drv;
> +             }
> +     }
> +     return NULL; /* no driver found */
> +}
> +
> +static inline int pci_driver_add_device(struct pci_driver *drv,
> +                                     struct pci_address *addr,
> +                                     struct pci_device_id *devid)
> +{
> +     struct pci_device *dev;
> +     uint32_t config_addr;
> +     int ret;
> +
> +     UK_ASSERT(drv != NULL);
> +     UK_ASSERT(drv->add_dev != NULL);
> +     UK_ASSERT(addr != NULL);
> +     UK_ASSERT(devid != NULL);
> +
> +     dev = (struct pci_device *) uk_calloc(ph.a, 1, sizeof(*dev));
> +     if (!dev) {
> +             uk_printd(DLVL_ERR,
> +                             "PCI %02x:%02x.%02x: Failed to initialize: Out 
> of memory!\n",
> +                             (int) addr->bus,
> +                             (int) addr->devid,
> +                             (int) addr->function);
> +             return -ENOMEM;
> +     }
> +
> +     memcpy(&dev->id,   devid, sizeof(dev->id));
> +     memcpy(&dev->addr, addr,  sizeof(dev->addr));
> +     dev->drv = drv;
> +
> +     config_addr = (PCI_ENABLE_BIT)
> +                     | (addr->bus << PCI_BUS_SHIFT)
> +                     | (addr->devid << PCI_DEVICE_SHIFT);
> +     PCI_CONF_READ(uint16_t, &dev->base, config_addr, IOBAR);
> +     PCI_CONF_READ(uint8_t, &dev->irq, config_addr, IRQ);
> +
> +     ret = drv->add_dev(dev);
> +     if (ret < 0) {
> +             uk_printd(DLVL_ERR,
> +                       "PCI %02x:%02x.%02x: Failed to initialize device 
> driver\n",
> +                     (int) addr->bus,
> +                     (int) addr->devid,
> +                     (int) addr->function);
> +             uk_free(ph.a, dev);
> +     }
> +     return 0;
> +}
> +
> +static int pci_probe(void)
> +{
> +     struct pci_address addr;
> +     struct pci_device_id devid;
> +     struct pci_driver *drv;
> +     uint32_t config_addr, config_data;
> +     uint32_t bus;
> +     uint8_t dev;
> +
> +     uk_printd(DLVL_EXTRA, "Probe PCI\n");
> +
> +     for (bus = 0; bus < PCI_MAX_BUSES; ++bus) {
> +             for (dev = 0; dev < PCI_MAX_DEVICES; ++dev) {
> +                     config_addr = (PCI_ENABLE_BIT)
> +                                     | (bus << PCI_BUS_SHIFT)
> +                                     | (dev << PCI_DEVICE_SHIFT);
> +
> +                     outl(PCI_CONFIG_ADDR, config_addr);
> +                     config_data = inl(PCI_CONFIG_DATA);
> +
> +                     /* TODO: Retrieve the device identfier */
> +                     addr.domain   = 0x0;
> +                     addr.bus      = bus;
> +                     addr.devid    = dev;
> +                      /* TODO: Retrieve the function */
> +                     addr.function = 0x0;
> +
> +                     devid.vendor_id = config_data & PCI_DEVICE_ID_MASK;
> +                     if (devid.vendor_id == PCI_INVALID_ID) {
> +                             /* Device doesn't exist */
> +                             continue;
> +                     }
> +
> +                     /* TODO: Implement fetch more information from PCI */
> +                     devid.class_id            = PCI_CLASS_ANY_ID;
> +                     /* TODO: Implement fetch more information from PCI */
> +                     devid.device_id           = PCI_ANY_ID;
> +                     /* TODO: Implement fetch more information from PCI */
> +                     devid.subsystem_vendor_id = PCI_ANY_ID;
> +                     PCI_CONF_READ(uint16_t, &devid.subsystem_device_id,
> +                                     config_addr, SUBSYS_ID);
> +
> +                     uk_printd(DLVL_INFO, "PCI %02x:%02x.%02x (%04x 
> %04x:%04x): ",
> +                             (int) addr.bus,
> +                             (int) addr.devid,
> +                             (int) addr.function,
> +                             (int) devid.class_id,
> +                             (int) devid.vendor_id,
> +                             (int) devid.device_id);
> +                     drv = pci_find_driver(&devid);
> +                     if (!drv) {
> +                             uk_printd(DLVL_INFO, "<no driver>\n");
> +                             continue;
> +                     }
> +                     uk_printd(DLVL_INFO, "driver %p\n", drv);
> +                     pci_driver_add_device(drv, &addr, &devid);
> +             }
> +     }
> +     return 0;
> +}
> +
> +
> +static int pci_init(struct uk_alloc *a)
> +{
> +     struct pci_driver *drv, *drv_next;
> +     int ret = 0;
> +
> +     UK_ASSERT(a != NULL);
> +
> +     ph.a = a;
> +
> +     if (!ph.drv_list_initialized) {
> +             UK_TAILQ_INIT(&ph.drv_list);
> +             ph.drv_list_initialized = 1;
> +     }
> +     UK_TAILQ_INIT(&ph.dev_list);
> +
> +     FOREACH_DRIVER_SAFE(drv, drv_next) {
> +             if (drv->init) {
> +                     ret = drv->init(a);
> +                     if (ret == 0)
> +                             continue;
> +                     uk_printd(DLVL_ERR, "Failed to initialize driver %p: 
> %d\n",
> +                               drv, ret);
> +                     UK_TAILQ_REMOVE(&ph.drv_list, drv, next);
> +             }
> +     }
> +     return 0;
> +}
> +
> +void _pci_register_driver(struct pci_driver *drv)
> +{
> +     UK_ASSERT(drv != NULL);
> +
> +     if (!ph.drv_list_initialized) {
> +             UK_TAILQ_INIT(&ph.drv_list);
> +             ph.drv_list_initialized = 1;
> +     }
> +     UK_TAILQ_INSERT_TAIL(&ph.drv_list, drv, next);
> +}
> +
> +
> +/* Register this bus driver to libukbus:
> + */
> +static struct pci_bus_handler ph = {
> +     .b.init = pci_init,
> +     .b.probe = pci_probe
> +};
> +UK_BUS_REGISTER(&ph.b);
> diff --git a/plat/kvm/Config.uk b/plat/kvm/Config.uk
> index 622c4eb..967a07b 100644
> --- a/plat/kvm/Config.uk
> +++ b/plat/kvm/Config.uk
> @@ -9,5 +9,12 @@ menuconfig PLAT_KVM
>         help
>                  Create a Unikraft image that runs as a KVM guest
>  
> -#if (PLAT_KVM)
> -#endif
> +if (PLAT_KVM)
> +config KVM_PCI
> +       bool "PCI Bus Driver"
> +       default y
> +       depends on (ARCH_X86_64)
> +       select LIBUKBUS
> +       help
> +                PCI bus driver for probing and operating PCI devices
> +endif
> diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk
> index b840c2f..2705fd1 100644
> --- a/plat/kvm/Makefile.uk
> +++ b/plat/kvm/Makefile.uk
> @@ -7,14 +7,17 @@ $(eval $(call addplat_s,kvm,$(CONFIG_PLAT_KVM)))
>  ## KVM platform library registration
>  ##
>  $(eval $(call addplatlib,kvm,libkvmplat))
> +$(eval $(call addplatlib_s,kvm,libkvmpci,$(CONFIG_KVM_PCI)))
>  
>  ##
>  ## Platform library definitions
>  ##
>  LIBKVMPLAT_ASINCLUDES-y        += -I$(LIBKVMPLAT_BASE)/include
>  LIBKVMPLAT_ASINCLUDES-y        += -I$(UK_PLAT_COMMON_BASE)/include
> +LIBKVMPCI_ASINCLUDES-$(CONFIG_ARCH_X86_64)  += 
> -I$(UK_PLAT_COMMON_BASE)/include/pci
>  LIBKVMPLAT_CINCLUDES-y         += -I$(LIBKVMPLAT_BASE)/include
>  LIBKVMPLAT_CINCLUDES-y         += -I$(UK_PLAT_COMMON_BASE)/include
> +LIBKVMPCI_CINCLUDES-$(CONFIG_ARCH_X86_64)   += 
> -I$(UK_PLAT_COMMON_BASE)/include/pci
>  
>  LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += 
> $(UK_PLAT_COMMON_BASE)/x86/trace.c|common
>  LIBKVMPLAT_SRCS-$(CONFIG_ARCH_X86_64) += 
> $(UK_PLAT_COMMON_BASE)/x86/traps.c|common
> @@ -37,3 +40,5 @@ LIBKVMPLAT_SRCS-y              += $(LIBKVMPLAT_BASE)/irq.c
>  LIBKVMPLAT_SRCS-y              += $(LIBKVMPLAT_BASE)/time.c
>  LIBKVMPLAT_SRCS-y              += $(LIBKVMPLAT_BASE)/tscclock.c
>  LIBKVMPLAT_SRCS-y              += $(UK_PLAT_COMMON_BASE)/lcpu.c|common
> +
> +LIBKVMPCI_SRCS-y                     += 
> $(UK_PLAT_COMMON_BASE)/pci_bus.c|common
> -- 
> 2.7.4
>

-- 
Yuri Volchkov
Software Specialist

NEC Europe Ltd
Kurfürsten-Anlage 36
D-69115 Heidelberg

_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

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