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

[UNIKRAFT PATCH RFCv4 19/35] plat/pci_bus: arm64: Implement add/probe interfaces on arm64



This implements arch specific add/probe interfaces on arm64

Signed-off-by: Jia He <justin.he@xxxxxxx>
---
 plat/common/arm/pci_bus_arm64.c   | 205 ++++++++++++++++++++++++++++++
 plat/common/include/pci/pci_bus.h |  52 ++++++++
 plat/kvm/Makefile.uk              |   2 +
 3 files changed, 259 insertions(+)
 create mode 100644 plat/common/arm/pci_bus_arm64.c

diff --git a/plat/common/arm/pci_bus_arm64.c b/plat/common/arm/pci_bus_arm64.c
new file mode 100644
index 0000000..022b3d4
--- /dev/null
+++ b/plat/common/arm/pci_bus_arm64.c
@@ -0,0 +1,205 @@
+/* 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 <uk/plat/common/cpu.h>
+#include <pci/pci_bus.h>
+#include <pci/pci_ecam.h>
+#include <libfdt_env.h>
+#include <gic/gic-v2.h>
+
+extern struct pci_config_window pcw;
+extern int gen_pci_irq_parse(const fdt32_t *addr, struct fdt_phandle_args 
*out_irq);
+
+#define DEVFN(dev, fn)   ((dev << PCI_FN_BIT_NBR) | fn)
+#define SIZE_PER_PCI_DEV 0x20  /* legacy pci device size, no msi */
+
+static int arch_pci_driver_add_device(struct pci_driver *drv,
+                                       struct pci_address *addr,
+                                       struct pci_device_id *devid,
+                                       int irq,
+                                       __u64 base,
+                                       struct uk_alloc *pha)
+{
+       struct pci_device *dev;
+       int ret;
+       __u32 val;
+
+       UK_ASSERT(drv != NULL);
+       UK_ASSERT(drv->add_dev != NULL);
+       UK_ASSERT(addr != NULL);
+       UK_ASSERT(devid != NULL);
+       UK_ASSERT(pha != NULL);
+
+       dev = (struct pci_device *) uk_calloc(pha, 1, sizeof(*dev));
+       if (!dev) {
+               uk_pr_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;
+
+       dev->base = base;
+       dev->irq = irq;
+       uk_pr_info("pci dev base(0x%llx) irq(%d)\n", dev->base, dev->irq);
+
+       if (drv->add_dev)
+               ret = drv->add_dev(dev); //virtio pci
+       if (ret < 0) {
+               uk_pr_err("PCI %02x:%02x.%02x: Failed to initialize device 
driver\n",
+                         (int) addr->bus,
+                         (int) addr->devid,
+                         (int) addr->function);
+               uk_free(pha, dev);
+       }
+
+       return 0;
+}
+
+int arch_pci_probe(struct uk_alloc *pha)
+{
+       struct pci_address addr;
+       struct pci_device_id devid;
+       struct pci_driver *drv;
+       uint32_t bus;
+       uint8_t dev;
+       int err;
+       int irq, pin = 0;
+       __u64 base;
+       int found_pci_device = 0;
+       struct fdt_phandle_args out_irq;
+       fdt32_t fdtaddr[3];
+
+       uk_pr_debug("Probe PCI\n");
+
+       for (bus = 0; bus < PCI_MAX_BUSES; ++bus) {
+               for (dev = 0; dev < PCI_MAX_DEVICES; ++dev) {
+                       /* TODO: Retrieve the device identfier */
+                       addr.domain   = 0x0;
+                       addr.bus      = bus;
+                       addr.devid    = dev;
+                        /* TODO: Retrieve the function bus, dev << 
PCI_DEV_BIT_NBR*/
+                       addr.function = 0x0;
+
+                       pci_generic_config_read(bus, DEVFN(dev, 0), 
PCI_VENDOR_ID, 2, &devid.vendor_id);
+                       if (devid.vendor_id == PCI_INVALID_ID) {
+                               /* Device doesn't exist */
+                               continue;
+                       }
+
+                       /* mark we found any pci device */
+                       found_pci_device = 1;
+
+                       pci_generic_config_read(bus, DEVFN(dev, 0), 
PCI_CLASS_REVISION, 4, &devid.class_id);
+                       pci_generic_config_read(bus, DEVFN(dev, 0), 
PCI_VENDOR_ID, 2, &devid.vendor_id);
+                       pci_generic_config_read(bus, DEVFN(dev, 0), PCI_DEV_ID, 
2, &devid.device_id);
+                       pci_generic_config_read(bus, DEVFN(dev, 0), 
PCI_SUBSYSTEM_VID, 2, &devid.subsystem_vendor_id);
+                       pci_generic_config_read(bus, DEVFN(dev, 0), 
PCI_SUBSYSTEM_ID, 2, &devid.subsystem_device_id);
+                       uk_pr_info("PCI %02x:%02x.%02x (%04x %04x:%04x): 
sb=%d,sv=%4x\n",
+                                  (int) addr.bus,
+                                  (int) addr.devid,
+                                  (int) addr.function,
+                                  (int) devid.class_id,
+                                  (int) devid.vendor_id,
+                                  (int) devid.device_id,
+                                  (int) devid.subsystem_device_id,
+                                  (int) devid.subsystem_vendor_id);
+
+                       /* TODO: gracefully judge it is a pci host bridge */
+                       if (bus == 0 && DEVFN(dev, 0) == 0) {
+                               pci_generic_config_write(bus, 0, PCI_COMMAND, 
2, PCI_COMMAND_INTX_DISABLE);
+                               pci_generic_config_write(bus, 0, PCI_COMMAND, 
2, PCI_COMMAND_IO);
+                               continue;
+                       } else {
+                               base = pcw.pci_device_base + (bus << 5 | 
dev)*SIZE_PER_PCI_DEV;
+                               pci_generic_config_write(bus, DEVFN(dev, 0), 
PCI_COMMAND, 2, PCI_COMMAND_INTX_DISABLE);
+                               pci_generic_config_write(bus, DEVFN(dev, 0), 
PCI_BASE_ADDRESS_0, 4, (bus << 5 | dev)*SIZE_PER_PCI_DEV);
+                               pci_generic_config_write(bus, DEVFN(dev, 0), 
PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_IO);
+                       }
+
+                       drv = pci_find_driver(&devid);
+                       if (!drv) {
+                               uk_pr_info("<no driver> for dev id=%d\n", 
devid);
+                               continue;
+                       }
+
+                       uk_pr_info("driver %p\n", drv);
+
+                       /* probe the irq info*/
+                       pci_generic_config_read(bus, DEVFN(dev, 0), 
PCI_INTERRUPT_PIN, 1, &pin);
+                       out_irq.args_count = 1;
+                       out_irq.args[0] = pin;
+                       fdtaddr[0] = cpu_to_fdt32((bus << 16) | (DEVFN(dev,0) 
<< 8));
+                       fdtaddr[1] = fdtaddr[2] = cpu_to_fdt32(0);
+
+                       gen_pci_irq_parse(fdtaddr, &out_irq);
+                       irq = gic_irq_translate(0, out_irq.args[1]);
+
+                       arch_pci_driver_add_device(drv, &addr, &devid, irq, 
base, pha);
+
+                       uk_pr_info("pci dev base(0x%llx) irq(%d)\n");
+               }
+       }
+
+       if (found_pci_device == 0)
+               uk_pr_info("No pci device found!\n");
+
+       return 0;
+}
diff --git a/plat/common/include/pci/pci_bus.h 
b/plat/common/include/pci/pci_bus.h
index a49e7e3..88ed949 100644
--- a/plat/common/include/pci/pci_bus.h
+++ b/plat/common/include/pci/pci_bus.h
@@ -193,6 +193,10 @@ static struct pci_bus_handler ph;
 #define PCI_MAX_DEVICES             (1 << 5)
 #define PCI_MAX_FUNCTIONS           (1 << 3)
 
+#define PCI_BUS_BIT_NBR                        (8)
+#define PCI_DEV_BIT_NBR                        (5)
+#define PCI_FN_BIT_NBR                 (3)
+
 #define PCI_BUS_SHIFT               (16)
 #define PCI_DEVICE_SHIFT            (11)
 #define PCI_FUNCTION_SHIFT          (8)
@@ -239,6 +243,54 @@ static struct pci_bus_handler ph;
 #define PCI_CONF_IOBAR_SHFT         (0x0)
 #define PCI_CONF_IOBAR_MASK         (~0x3)
 
+#define PCI_BASE_ADDRESS_0     0x10    /* 32 bits */
+#define PCI_BASE_ADDRESS_1     0x14    /* 32 bits */
+#define PCI_BASE_ADDRESS_2     0x18    /* 32 bits */
+#define PCI_BASE_ADDRESS_3     0x1c    /* 32 bits */
+#define PCI_BASE_ADDRESS_4     0x20    /* 32 bits */
+#define PCI_BASE_ADDRESS_5     0x24    /* 32 bits */
+
+#define PCI_VENDOR_ID          0x0
+#define PCI_DEV_ID                     0x02
+
+#define PCI_BUS_OFFSET       16
+#define PCI_SLOT_OFFSET      11
+#define PCI_FUNC_OFFSET      8
+#define PCI_CONFIG_ADDRESS_ENABLE   0x80000000
+#define PCI_COMMAND_OFFSET   0x4
+#define PCI_BUS_MASTER_BIT   0x2
+#define PCI_STATUS_OFFSET    0x6
+#define PCI_CLASS_REVISION   0x8
+#define PCI_CLASS_OFFSET     0xb
+#define PCI_SUBCLASS_OFFSET     0xa
+#define PCI_HEADER_TYPE      0xe
+#define PCI_SUBSYSTEM_ID     0x2e
+#define PCI_SUBSYSTEM_VID    0x2c
+#define PCI_HEADER_MULTI_FUNC   0x80
+#define PCI_BAR0_ADDR        0x10
+#define PCI_CONFIG_SECONDARY_BUS   0x19
+#define PCI_CAPABILITIES_PTR   0x34
+
+#define PCI_COMMAND            0x04    /* 16 bits */
+#define  PCI_COMMAND_IO                0x1     /* Enable response in I/O space 
*/
+#define  PCI_COMMAND_MEMORY    0x2     /* Enable response in Memory space */
+#define  PCI_COMMAND_MASTER    0x4     /* Enable bus mastering */
+#define  PCI_COMMAND_SPECIAL   0x8     /* Enable response to special cycles */
+#define  PCI_COMMAND_INVALIDATE        0x10    /* Use memory write and 
invalidate */
+#define  PCI_COMMAND_VGA_PALETTE 0x20  /* Enable palette snooping */
+#define  PCI_COMMAND_PARITY    0x40    /* Enable parity checking */
+#define  PCI_COMMAND_WAIT      0x80    /* Enable address/data stepping */
+#define  PCI_COMMAND_SERR      0x100   /* Enable SERR */
+#define  PCI_COMMAND_FAST_BACK 0x200   /* Enable back-to-back writes */
+#define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
+#define PCI_COMMAND_DECODE_ENABLE      (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)
+
+/* 0x35-0x3b are reserved */
+#define PCI_INTERRUPT_LINE     0x3c    /* 8 bits */
+#define PCI_INTERRUPT_PIN      0x3d    /* 8 bits */
+#define PCI_MIN_GNT            0x3e    /* 8 bits */
+#define PCI_MAX_LAT            0x3f    /* 8 bits */
+
 struct pci_driver *pci_find_driver(struct pci_device_id *id);
 
 #endif /* __UKPLAT_COMMON_PCI_BUS_H__ */
diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk
index 5260670..da2eb30 100644
--- a/plat/kvm/Makefile.uk
+++ b/plat/kvm/Makefile.uk
@@ -117,6 +117,8 @@ LIBKVMPCI_CINCLUDES-$(CONFIG_ARCH_ARM_64)   += 
-I$(UK_PLAT_DRIVERS_BASE)/include
 LIBKVMPCI_SRCS-y                           += 
$(UK_PLAT_COMMON_BASE)/pci_bus.c|common
 LIBKVMPCI_SRCS-$(CONFIG_ARCH_X86_64) += \
                                $(UK_PLAT_COMMON_BASE)/x86/pci_bus_x86.c|x86
+LIBKVMPCI_SRCS-$(CONFIG_ARCH_ARM_64) += \
+                               $(UK_PLAT_COMMON_BASE)/arm/pci_bus_arm64.c|arm
 
 ##
 ## Platform bus library definitions
-- 
2.17.1




 


Rackspace

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