[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |