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

[UNIKRAFT PATCH RFCv3 18/32] 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   | 204 ++++++++++++++++++++++++++++++
 plat/common/include/pci/pci_bus.h |   5 +
 2 files changed, 209 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..1dfaeb3
--- /dev/null
+++ b/plat/common/arm/pci_bus_arm64.c
@@ -0,0 +1,204 @@
+/* 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 inline 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);
+
+       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 a15d663..58ad292 100644
--- a/plat/common/include/pci/pci_bus.h
+++ b/plat/common/include/pci/pci_bus.h
@@ -255,6 +255,11 @@ static struct pci_bus_handler ph;
 #define PCI_BAR0_ADDR        0x10
 #define PCI_CONFIG_SECONDARY_BUS   0x19
 #define PCI_CAPABILITIES_PTR   0x34
+/* 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 */
 
 #define PCI_COMMAND            0x04    /* 16 bits */
 #define  PCI_COMMAND_IO                0x1     /* Enable response in I/O space 
*/
-- 
2.17.1




 


Rackspace

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