[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [UNIKRAFT PATCH RFCv2 17/27] plat/pci_bus: Split specific code into arch directory
There are significant difference for pci controller on arm64 and x86. On arm64, only pci ecam is supported. Hence split arch dependant codes into arch specific directory No functional changes in this patch Signed-off-by: Jia He <justin.he@xxxxxxx> --- plat/common/include/pci/pci_bus.h | 97 +++++++++++++++++ plat/common/pci_bus.c | 167 +--------------------------- plat/common/x86/pci_bus_x86.c | 174 ++++++++++++++++++++++++++++++ plat/kvm/Makefile.uk | 9 +- 4 files changed, 283 insertions(+), 164 deletions(-) create mode 100644 plat/common/x86/pci_bus_x86.c diff --git a/plat/common/include/pci/pci_bus.h b/plat/common/include/pci/pci_bus.h index db406a1..a15d663 100644 --- a/plat/common/include/pci/pci_bus.h +++ b/plat/common/include/pci/pci_bus.h @@ -174,5 +174,102 @@ struct pci_device { /* Do not use this function directly: */ void _pci_register_driver(struct pci_driver *drv); +struct pci_bus_handler { + struct uk_bus b; + struct uk_alloc *a; + struct uk_list_head drv_list; /**< List of PCI drivers */ + struct uk_list_head dev_list; /**< List of PCI devices */ +}; +static struct pci_bus_handler ph; + +#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_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_ENABLE_BIT (1 << 31) + +#define PCI_CONF_CLASS_ID (0x08) +#define PCI_CONF_CLASS_ID_SHFT (8) +#define PCI_CONF_CLASS_ID_MASK (0x00FFFFFF) + +#define PCI_CONF_VENDOR_ID (0x00) +#define PCI_CONF_VENDOR_ID_SHFT (0) +#define PCI_CONF_VENDOR_ID_MASK (0x0000FFFF) + +#define PCI_CONF_DEVICE_ID (0x00) +#define PCI_CONF_DEVICE_ID_SHFT (16) +#define PCI_CONF_DEVICE_ID_MASK (0x0000FFFF) + +#define PCI_CONF_SUBSYSVEN_ID (0x2c) +#define PCI_CONF_SUBSYSVEN_ID_SHFT (0) +#define PCI_CONF_SUBSYSVEN_ID_MASK (0xFFFF) + +#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_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) + +struct pci_driver *pci_find_driver(struct pci_device_id *id); #endif /* __UKPLAT_COMMON_PCI_BUS_H__ */ diff --git a/plat/common/pci_bus.c b/plat/common/pci_bus.c index 4077e3c..cd3874b 100644 --- a/plat/common/pci_bus.c +++ b/plat/common/pci_bus.c @@ -57,64 +57,7 @@ #include <uk/plat/common/cpu.h> #include <pci/pci_bus.h> -struct pci_bus_handler { - struct uk_bus b; - struct uk_alloc *a; - struct uk_list_head drv_list; /**< List of PCI drivers */ - struct uk_list_head dev_list; /**< List of PCI devices */ -}; -static struct pci_bus_handler ph; - -#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_CLASS_ID (0x08) -#define PCI_CONF_CLASS_ID_SHFT (8) -#define PCI_CONF_CLASS_ID_MASK (0x00FFFFFF) - -#define PCI_CONF_VENDOR_ID (0x00) -#define PCI_CONF_VENDOR_ID_SHFT (0) -#define PCI_CONF_VENDOR_ID_MASK (0x0000FFFF) - -#define PCI_CONF_DEVICE_ID (0x00) -#define PCI_CONF_DEVICE_ID_SHFT (16) -#define PCI_CONF_DEVICE_ID_MASK (0x0000FFFF) - -#define PCI_CONF_SUBSYSVEN_ID (0x2c) -#define PCI_CONF_SUBSYSVEN_ID_SHFT (0) -#define PCI_CONF_SUBSYSVEN_ID_MASK (0xFFFF) - -#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) +extern int arch_pci_probe(struct uk_alloc *pha); static inline int pci_device_id_match(const struct pci_device_id *id0, const struct pci_device_id *id1) @@ -159,7 +102,7 @@ static inline int pci_device_id_is_any(const struct pci_device_id *id) return 0; } -static inline struct pci_driver *pci_find_driver(struct pci_device_id *id) +struct pci_driver *pci_find_driver(struct pci_device_id *id) { struct pci_driver *drv; const struct pci_device_id *drv_id; @@ -172,116 +115,15 @@ static inline struct pci_driver *pci_find_driver(struct pci_device_id *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_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; - - 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_pr_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; + return NULL; /* no driver found */ } 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_pr_debug("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; - } - - PCI_CONF_READ(uint32_t, &devid.class_id, - config_addr, CLASS_ID); - PCI_CONF_READ(uint16_t, &devid.vendor_id, - config_addr, VENDOR_ID); - PCI_CONF_READ(uint16_t, &devid.device_id, - config_addr, DEVICE_ID); - PCI_CONF_READ(uint16_t, &devid.subsystem_device_id, - config_addr, SUBSYS_ID); - PCI_CONF_READ(uint16_t, &devid.subsystem_vendor_id, - config_addr, SUBSYSVEN_ID); - - uk_pr_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_pr_info("<no driver>\n"); - continue; - } - uk_pr_info("driver %p\n", drv); - pci_driver_add_device(drv, &addr, &devid); - } - } - return 0; + return arch_pci_probe(ph.a); } - static int pci_init(struct uk_alloc *a) { struct pci_driver *drv, *drv_next; @@ -301,6 +143,7 @@ static int pci_init(struct uk_alloc *a) uk_list_del_init(&drv->list); } } + return 0; } diff --git a/plat/common/x86/pci_bus_x86.c b/plat/common/x86/pci_bus_x86.c new file mode 100644 index 0000000..e07f3e5 --- /dev/null +++ b/plat/common/x86/pci_bus_x86.c @@ -0,0 +1,174 @@ +/* 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> + +#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 arch_pci_driver_add_device(struct pci_driver *drv, + struct pci_address *addr, + struct pci_device_id *devid, + struct uk_alloc *pha) +{ + 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(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; + + 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_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(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_pr_debug("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; + } + + PCI_CONF_READ(uint32_t, &devid.class_id, + config_addr, CLASS_ID); + PCI_CONF_READ(uint16_t, &devid.vendor_id, + config_addr, VENDOR_ID); + PCI_CONF_READ(uint16_t, &devid.device_id, + config_addr, DEVICE_ID); + PCI_CONF_READ(uint16_t, &devid.subsystem_device_id, + config_addr, SUBSYS_ID); + PCI_CONF_READ(uint16_t, &devid.subsystem_vendor_id, + config_addr, SUBSYSVEN_ID); + + uk_pr_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_pr_info("<no driver>\n"); + continue; + } + uk_pr_info("driver %p\n", drv); + arch_pci_driver_add_device(drv, &addr, &devid, ph.a); + } + } + return 0; +} diff --git a/plat/kvm/Makefile.uk b/plat/kvm/Makefile.uk index 7b12b1a..da2eb30 100644 --- a/plat/kvm/Makefile.uk +++ b/plat/kvm/Makefile.uk @@ -113,7 +113,12 @@ LIBKVMPCI_ASINCLUDES-$(CONFIG_ARCH_X86_64) += -I$(LIBKVMPLAT_BASE)/include LIBKVMPCI_ASINCLUDES-$(CONFIG_ARCH_X86_64) += -I$(UK_PLAT_COMMON_BASE)/include LIBKVMPCI_CINCLUDES-$(CONFIG_ARCH_X86_64) += -I$(LIBKVMPLAT_BASE)/include LIBKVMPCI_CINCLUDES-$(CONFIG_ARCH_X86_64) += -I$(UK_PLAT_COMMON_BASE)/include -LIBKVMPCI_SRCS-$(CONFIG_ARCH_X86_64) += $(UK_PLAT_COMMON_BASE)/pci_bus.c|common +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 @@ -122,7 +127,7 @@ LIBKVMPF_ASINCLUDES-$(CONFIG_ARCH_ARM_64) += -I$(UK_PLAT_COMMON_BASE)/include LIBKVMPF_CINCLUDES-$(CONFIG_ARCH_ARM_64) += -I$(UK_PLAT_COMMON_BASE)/include LIBKVMPF_CINCLUDES-$(CONFIG_ARCH_ARM_64) += -I$(LIBKVMPLAT_BASE)/include LIBKVMPF_CINCLUDES-$(CONFIG_ARCH_ARM_64) += -I$(UK_PLAT_DRIVERS_BASE)/include -LIBKVMPF_SRCS-$(CONFIG_ARCH_ARM_64) += $(UK_PLAT_COMMON_BASE)/platform_bus.c|common +LIBKVMPF_SRCS-$(CONFIG_KVM_PF) += $(UK_PLAT_COMMON_BASE)/platform_bus.c|common ## ## Virtio library definitions -- 2.17.1
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |