From 69ed5bb67de73adae50c3e3afbab34f944eb14a2 Mon Sep 17 00:00:00 2001 From: Brennan Ashton Date: Thu, 7 May 2020 02:59:29 -0700 Subject: [PATCH] Various fixes for PCI work Squashed commits: 1. Porting prior PCI work in place of jailhouse code At this point the PCI enumeration works for x86_64 including over pci-pci bridges. Running QEMU with this configuration we see the bridge and the device on the bridge. It also detected the qemu test device qemu-system-x86_64 \ -cpu host,+pcid,+x2apic,+tsc-deadline,+xsave,+rdrand \ --enable-kvm -smp 1 -m 2G -cdrom boot.iso --nographic -no-reboot \ -device pci-testdev \ -device pci-bridge,id=bridge0,chassis_nr=2 \ -device e1000,bus=bridge0,addr=0x3 qemu_pci_init: Initializing PCI Bus pci_probe_device: [00:00.0] Found 8086:1237, class/revision 06000002 pci_probe_device: [00:01.1] Found 8086:7010, class/revision 01018000 pci_probe_device: [00:01.2] Found ffff:ffff, class/revision ffffffff pci_probe_device: [00:01.3] Found 8086:7113, class/revision 06800003 pci_probe_device: [00:01.4] Found ffff:ffff, class/revision ffffffff pci_probe_device: [00:01.5] Found ffff:ffff, class/revision ffffffff pci_probe_device: [00:01.6] Found ffff:ffff, class/revision ffffffff pci_probe_device: [00:01.7] Found ffff:ffff, class/revision ffffffff pci_probe_device: [00:02.0] Found 1234:1111, class/revision 03000002 pci_probe_device: [00:03.0] Found 8086:100e, class/revision 02000003 pci_probe_device: [00:04.0] Found 1b36:0005, class/revision 00ff0000 pci_probe_device: [00:04.0] Probing pci_check_pci_bridge: [00:05.0] Found Bridge pci_probe_device: [01:03.0] Found 8086:100e, class/revision 02000003 pci_probe_device: [00:05.0] Found 1b36:0001, class/revision 06040000 2. Remove unused CONFIG_PCI_MAX_BDF option 3. Add a workaround for Jailhouse pci scanning 4. Extend BAR parsing and handle PIO and MMIO for pci-testdev Signed-off-by: Brennan Ashton 5. PCI: Add initial support for QEMU 'edu' test device Signed-off-by: Brennan Ashton 6. Bring up PCI later in boot process Signed-off-by: Brennan Ashton 7. Add ISR and DMA support to QEMU edu test pci device Signed-off-by: Brennan Ashton 8. Fix bad function prototype definition in qemu_edu 9. intel64: Add a pci test configuration and instructions Signed-off-by: Brennan Ashton 10. PCI: Fix issue in identification of 64bit bar Signed-off-by: Brennan Ashton --- .../x86_64/qemu/boards/qemu-intel64/index.rst | 8 + Kconfig | 31 +- boards/x86_64/intel64/qemu-intel64/Kconfig | 8 +- .../qemu-intel64/configs/pcitest/defconfig | 76 ++ .../intel64/qemu-intel64/include/board.h | 2 - .../x86_64/intel64/qemu-intel64/src/Makefile | 4 +- .../intel64/qemu-intel64/src/qemu_boot.c | 6 - .../intel64/qemu-intel64/src/qemu_bringup.c | 5 + .../intel64/qemu-intel64/src/qemu_intel64.h | 2 + .../intel64/qemu-intel64/src/qemu_pci.c | 226 +++++ .../intel64/qemu-intel64/src/qemu_pcie.c | 398 --------- .../qemu-intel64/src/qemu_pcie_readwrite.h | 240 ------ drivers/Kconfig | 2 +- drivers/Makefile | 2 +- drivers/pci/Kconfig | 11 + drivers/{pcie => pci}/Make.defs | 14 +- drivers/pci/pci.c | 792 ++++++++++++++++++ drivers/pcie/Kconfig | 20 - drivers/pcie/pcie_root.c | 446 ---------- drivers/virt/Kconfig | 9 +- drivers/virt/Make.defs | 8 +- drivers/virt/qemu_edu.c | 448 ++++++++++ drivers/virt/qemu_pci_test.c | 209 ++++- include/debug.h | 6 +- include/nuttx/pci/pci.h | 458 ++++++++++ include/nuttx/pcie/pcie.h | 352 -------- include/nuttx/virt/qemu_pci.h | 6 +- 27 files changed, 2247 insertions(+), 1542 deletions(-) create mode 100644 boards/x86_64/intel64/qemu-intel64/configs/pcitest/defconfig create mode 100644 boards/x86_64/intel64/qemu-intel64/src/qemu_pci.c delete mode 100644 boards/x86_64/intel64/qemu-intel64/src/qemu_pcie.c delete mode 100644 boards/x86_64/intel64/qemu-intel64/src/qemu_pcie_readwrite.h create mode 100644 drivers/pci/Kconfig rename drivers/{pcie => pci}/Make.defs (85%) create mode 100644 drivers/pci/pci.c delete mode 100644 drivers/pcie/Kconfig delete mode 100644 drivers/pcie/pcie_root.c create mode 100644 drivers/virt/qemu_edu.c create mode 100644 include/nuttx/pci/pci.h delete mode 100644 include/nuttx/pcie/pcie.h diff --git a/Documentation/platforms/x86_64/qemu/boards/qemu-intel64/index.rst b/Documentation/platforms/x86_64/qemu/boards/qemu-intel64/index.rst index 74c4349133..d1fe76186d 100644 --- a/Documentation/platforms/x86_64/qemu/boards/qemu-intel64/index.rst +++ b/Documentation/platforms/x86_64/qemu/boards/qemu-intel64/index.rst @@ -71,6 +71,14 @@ Use control-a x to terminate the emulation. P.S. Make sure that you CPU supports the mandatory features. Look at Real machine section for more information. +For testing the PCI bus and driver layers. This QEMU configuration can be used +with the pcitest NuttX configuration:: + + qemu-system-x86_64 -cpu host,+pcid,+x2apic,+tsc-deadline,+xsave,+rdrand --enable-kvm -smp 1 -m 2G -cdrom boot.iso --nographic -s -no-reboot -device edu -device pci-testdev + +This will enable the QEMU pci-test and edu PCI test devices which test PIO, MMIO, IRQ, and DMA +functions. Additionally it will show detailed information about the enumeration of the PCI bus. + Bochs ===== diff --git a/Kconfig b/Kconfig index a0d8b941c5..69c13823d9 100644 --- a/Kconfig +++ b/Kconfig @@ -2196,41 +2196,40 @@ config DEBUG_IPC_INFO endif # DEBUG_IPC -======= -config DEBUG_PCIE - bool "PCI-E Debug Features" +config DEBUG_PCI + bool "PCI Debug Features" default n - depends on PCIE + depends on PCI ---help--- - Enable PCIE driver debug features. + Enable PCI driver debug features. Support for this debug option is architecture-specific and may not be available for some MCUs. -if DEBUG_PCIE +if DEBUG_PCI -config DEBUG_PCIE_ERROR - bool "PCI-E Error Output" +config DEBUG_PCI_ERROR + bool "PCI Error Output" default n depends on DEBUG_ERROR ---help--- - Enable PCI-E driver error output to SYSLOG. + Enable PCI driver error output to SYSLOG. -config DEBUG_PCIE_WARN - bool "PCI-E Warnings Output" +config DEBUG_PCI_WARN + bool "PCI Warnings Output" default n depends on DEBUG_WARN ---help--- - Enable PCI-E driver warning output to SYSLOG. + Enable PCI driver warning output to SYSLOG. -config DEBUG_PCIE_INFO - bool "PCI-E Informational Output" +config DEBUG_PCI_INFO + bool "PCI Informational Output" default n depends on DEBUG_INFO ---help--- - Enable PCI-E driver informational output to SYSLOG. + Enable PCI driver informational output to SYSLOG. -endif # DEBUG_PCIE +endif # DEBUG_PCI endif # DEBUG_FEATURES config ARCH_HAVE_STACKCHECK diff --git a/boards/x86_64/intel64/qemu-intel64/Kconfig b/boards/x86_64/intel64/qemu-intel64/Kconfig index 595127192b..c9c77b73a4 100644 --- a/boards/x86_64/intel64/qemu-intel64/Kconfig +++ b/boards/x86_64/intel64/qemu-intel64/Kconfig @@ -3,10 +3,10 @@ # see the file kconfig-language.txt in the NuttX tools repository. # # -config QEMU_PCIE - bool "Initialize and enumerate PCI-E Bus" +config QEMU_PCI + bool "Initialize and enumerate PCI Bus" default n - select PCIE + select PCI ---help--- - Enables initialization and scaning of standard x86-64 pcie bus. + Enables initialization and scanning of standard x86-64 pci bus. diff --git a/boards/x86_64/intel64/qemu-intel64/configs/pcitest/defconfig b/boards/x86_64/intel64/qemu-intel64/configs/pcitest/defconfig new file mode 100644 index 0000000000..61e33fb0eb --- /dev/null +++ b/boards/x86_64/intel64/qemu-intel64/configs/pcitest/defconfig @@ -0,0 +1,76 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +CONFIG_16550_ADDRWIDTH=16 +CONFIG_16550_UART0=y +CONFIG_16550_UART0_BASE=0x3f8 +CONFIG_16550_UART0_CLOCK=1843200 +CONFIG_16550_UART0_IRQ=36 +CONFIG_16550_UART0_RXBUFSIZE=16 +CONFIG_16550_UART0_SERIAL_CONSOLE=y +CONFIG_16550_UART0_TXBUFSIZE=16 +CONFIG_16550_UART=y +CONFIG_ARCH="x86_64" +CONFIG_ARCH_BOARD="qemu-intel64" +CONFIG_ARCH_BOARD_INTEL64_QEMU=y +CONFIG_ARCH_CHIP="intel64" +CONFIG_ARCH_INTEL64_CORE_FREQ_KHZ=2600000 +CONFIG_ARCH_SIZET_LONG=y +CONFIG_ARCH_X86_64=y +CONFIG_BOARD_LOOPSPERMSEC=999 +CONFIG_BOOT_RUNFROMEXTSRAM=y +CONFIG_BUILTIN=y +CONFIG_CLOCK_MONOTONIC=y +CONFIG_CONSOLE_SYSLOG=y +CONFIG_DEBUG_ERROR=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_PCI=y +CONFIG_DEBUG_PCI_ERROR=y +CONFIG_DEBUG_PCI_INFO=y +CONFIG_DEBUG_PCI_WARN=y +CONFIG_DEBUG_WARN=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_HELLO_STACKSIZE=4194304 +CONFIG_FS_PROCFS=y +CONFIG_IDLETHREAD_STACKSIZE=4194304 +CONFIG_LIBM=y +CONFIG_MAX_TASKS=64 +CONFIG_NFILE_DESCRIPTORS=32 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_IFCONFIG=y +CONFIG_NSH_DISABLE_IFUPDOWN=y +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_CHILDSTATUS=16 +CONFIG_PRIORITY_INHERITANCE=y +CONFIG_PTHREAD_MUTEX_TYPES=y +CONFIG_PTHREAD_STACK_DEFAULT=4194304 +CONFIG_PTHREAD_STACK_MIN=4194304 +CONFIG_QEMU_PCI=y +CONFIG_RAM_SIZE=268435456 +CONFIG_SCHED_CHILD_STATUS=y +CONFIG_SCHED_HAVE_PARENT=y +CONFIG_SCHED_IRQMONITOR=y +CONFIG_SCHED_TICKLESS=y +CONFIG_SCHED_TICKLESS_ALARM=y +CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP=y +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_SIG_DEFAULT=y +CONFIG_START_DAY=3 +CONFIG_START_MONTH=3 +CONFIG_START_YEAR=2011 +CONFIG_SYSTEM_CLE=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_TIME64=y +CONFIG_USEC_PER_TICK=1 +CONFIG_USERMAIN_STACKSIZE=4194304 +CONFIG_USER_ENTRYPOINT="nsh_main" +CONFIG_VIRT=y +CONFIG_VIRT_QEMU_EDU=y +CONFIG_VIRT_QEMU_PCI_TEST=y diff --git a/boards/x86_64/intel64/qemu-intel64/include/board.h b/boards/x86_64/intel64/qemu-intel64/include/board.h index ae7b588407..9cb23e995b 100644 --- a/boards/x86_64/intel64/qemu-intel64/include/board.h +++ b/boards/x86_64/intel64/qemu-intel64/include/board.h @@ -66,8 +66,6 @@ extern "C" * Public Function Prototypes ****************************************************************************/ -void qemu_pcie_init(void); - #undef EXTERN #if defined(__cplusplus) } diff --git a/boards/x86_64/intel64/qemu-intel64/src/Makefile b/boards/x86_64/intel64/qemu-intel64/src/Makefile index 9ab32d1766..3441ce24e8 100644 --- a/boards/x86_64/intel64/qemu-intel64/src/Makefile +++ b/boards/x86_64/intel64/qemu-intel64/src/Makefile @@ -26,8 +26,8 @@ ifeq ($(CONFIG_BOARDCTL),y) CSRCS += qemu_appinit.c endif -ifeq ($(CONFIG_QEMU_PCIE),y) - CSRCS += qemu_pcie.c +ifeq ($(CONFIG_QEMU_PCI),y) + CSRCS += qemu_pci.c endif include $(TOPDIR)/boards/Board.mk diff --git a/boards/x86_64/intel64/qemu-intel64/src/qemu_boot.c b/boards/x86_64/intel64/qemu-intel64/src/qemu_boot.c index d4b02b1926..32cdcb33ec 100644 --- a/boards/x86_64/intel64/qemu-intel64/src/qemu_boot.c +++ b/boards/x86_64/intel64/qemu-intel64/src/qemu_boot.c @@ -66,12 +66,6 @@ void x86_64_boardinitialize(void) uart_putreg(CONFIG_16550_UART1_BASE, UART_MCR_OFFSET, UART_MCR_OUT2); #endif -#ifdef CONFIG_QEMU_PCIE - /* Initialization of system */ - - qemu_pcie_init(); -#endif - /* Configure on-board LEDs if LED support has been selected. */ #ifdef CONFIG_ARCH_LEDS diff --git a/boards/x86_64/intel64/qemu-intel64/src/qemu_bringup.c b/boards/x86_64/intel64/qemu-intel64/src/qemu_bringup.c index 7cd5d55137..bf0112a4e5 100644 --- a/boards/x86_64/intel64/qemu-intel64/src/qemu_bringup.c +++ b/boards/x86_64/intel64/qemu-intel64/src/qemu_bringup.c @@ -57,5 +57,10 @@ int qemu_bringup(void) } #endif +#ifdef CONFIG_QEMU_PCI + /* Initialization of system */ + + qemu_pci_init(); +#endif return ret; } diff --git a/boards/x86_64/intel64/qemu-intel64/src/qemu_intel64.h b/boards/x86_64/intel64/qemu-intel64/src/qemu_intel64.h index 9a711ee577..75989d0e25 100644 --- a/boards/x86_64/intel64/qemu-intel64/src/qemu_intel64.h +++ b/boards/x86_64/intel64/qemu-intel64/src/qemu_intel64.h @@ -48,6 +48,8 @@ * Public Function Prototypes ****************************************************************************/ +void qemu_pci_init(void); + int qemu_bringup(void); #endif /* __ASSEMBLY__ */ diff --git a/boards/x86_64/intel64/qemu-intel64/src/qemu_pci.c b/boards/x86_64/intel64/qemu-intel64/src/qemu_pci.c new file mode 100644 index 0000000000..d2bbd79102 --- /dev/null +++ b/boards/x86_64/intel64/qemu-intel64/src/qemu_pci.c @@ -0,0 +1,226 @@ +/**************************************************************************** + * boards/x86_64/intel64/qemu-intel64/src/qemu_pci.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "up_arch.h" +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PCI_CFG_ADDR 0xcf8 +#define PCI_DATA_ADDR 0xcfc +#define PCI_CFG_EN (1 << 31) + +/**************************************************************************** + * Private Functions Definitions + ****************************************************************************/ + +static void qemu_pci_cfg_write(FAR struct pci_dev_s *dev, int reg, + uint32_t val, int width); + +static uint32_t qemu_pci_cfg_read(FAR struct pci_dev_s *dev, int reg, + int width); + +static int qemu_pci_map_bar(uint64_t addr, uint64_t len); + +static uint32_t qemu_pci_io_read(FAR const volatile void *addr, int width); + +static void qemu_pci_io_write(FAR const volatile void *addr, uint32_t val, + int width); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct pci_bus_ops_s qemu_pci_bus_ops = +{ + .pci_cfg_write = qemu_pci_cfg_write, + .pci_cfg_read = qemu_pci_cfg_read, + .pci_map_bar = qemu_pci_map_bar, + .pci_io_read = qemu_pci_io_read, + .pci_io_write = qemu_pci_io_write, +}; + +struct pci_bus_s qemu_pci_bus = +{ + .ops = &qemu_pci_bus_ops, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: qemu_pci_cfg_write + * + * Description: + * Write 8, 16, 32, 64 bits data to PCI-E configuration space of device + * specified by dev + * + * Input Parameters: + * bdf - Device private data + * reg - A pointer to the read-only buffer of data to be written + * size - The number of bytes to send from the buffer + * + * Returned Value: + * 0: success, <0: A negated errno + * + ****************************************************************************/ + +static void qemu_pci_cfg_write(FAR struct pci_dev_s *dev, int reg, + uint32_t val, int width) +{ + uint8_t offset_mask = (4 - width); + outl(PCI_CFG_EN | (dev->bdf << 8) | reg, PCI_CFG_ADDR); + switch (width) + { + case 1: + outb(val, PCI_DATA_ADDR + (reg & offset_mask)); + return; + case 2: + outw(val, PCI_DATA_ADDR + (reg & offset_mask)); + return; + case 4: + outl(val, PCI_DATA_ADDR); + return; + default: + pcierr("Invalid cfg write width %d\n", width); + } +} + +/**************************************************************************** + * Name: qemu_pci_cfg_read + * + * Description: + * Read 8, 16, 32, 64 bits data from PCI-E configuration space of device + * specified by dev + * + * Input Parameters: + * dev - Device private data + * buffer - A pointer to a buffer to receive the data from the device + * size - The requested number of bytes to be read + * + * Returned Value: + * 0: success, <0: A negated errno + * + ****************************************************************************/ + +static uint32_t qemu_pci_cfg_read(FAR struct pci_dev_s *dev, int reg, + int width) +{ + uint32_t ret; + uint8_t offset_mask = 4 - width; + outl(PCI_CFG_EN | (dev->bdf << 8) | reg, PCI_CFG_ADDR); + + switch (width) + { + case 1: + ret = inb(PCI_DATA_ADDR + (reg & offset_mask)); + return ret; + + case 2: + ret = inw(PCI_DATA_ADDR + (reg & offset_mask)); + return ret; + case 4: + ret = inl(PCI_DATA_ADDR); + return ret; + default: + pcierr("Invalid cfg read width %d\n", width); + } + + return 0; +} + +static uint32_t qemu_pci_io_read(FAR const volatile void *addr, int width) +{ + uint16_t portaddr = (uint16_t)(intptr_t)addr; + switch (width) + { + case 1: + return (uint32_t)inb(portaddr); + case 2: + return (uint32_t)inw(portaddr); + case 4: + return (uint32_t)inl(portaddr); + default: + pcierr("Invalid read width %d\n", width); + DEBUGPANIC(); + } + + return 0; +} + +static void qemu_pci_io_write(FAR const volatile void *addr, uint32_t val, + int width) +{ + uint16_t portaddr = (uint16_t)(intptr_t)addr; + switch (width) + { + case 1: + outb((uint8_t)val, portaddr); + return; + case 2: + outw((uint8_t)val, portaddr); + return; + case 4: + outl((uint8_t)val, portaddr); + return; + default: + pcierr("Invalid write width %d\n", width); + DEBUGPANIC(); + } +} + +static int qemu_pci_map_bar(uint64_t addr, uint64_t len) +{ + up_map_region((void *)(uintptr_t)addr, len, + X86_PAGE_WR | X86_PAGE_PRESENT | X86_PAGE_NOCACHE | X86_PAGE_GLOBAL); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: qemu_pci_init + * + * Description: + * Initialize the PCI-E bus * + * + ****************************************************************************/ + +void qemu_pci_init(void) +{ + pciinfo("Initializing PCI Bus\n"); + pci_initialize(&qemu_pci_bus); +} diff --git a/boards/x86_64/intel64/qemu-intel64/src/qemu_pcie.c b/boards/x86_64/intel64/qemu-intel64/src/qemu_pcie.c deleted file mode 100644 index 0580593fad..0000000000 --- a/boards/x86_64/intel64/qemu-intel64/src/qemu_pcie.c +++ /dev/null @@ -1,398 +0,0 @@ -/**************************************************************************** - * boards/x86_64/intel64/qemu-intel64/src/qemu_pcie.c - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/* The MSI and MSI-X vector setup function are taken from Jailhouse inmate - * library - * - * Jailhouse, a Linux-based partitioning hypervisor - * - * Copyright (c) Siemens AG, 2014 - * - * Authors: - * Jan Kiszka - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Alternatively, you can use or redistribute this file under the following - * BSD license: - * - * 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. - * - * 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. - */ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include - -#include "qemu_pcie_readwrite.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Functions Definitions - ****************************************************************************/ - -static int qemu_pci_cfg_write(FAR struct pcie_dev_s *dev, uintptr_t addr, - FAR const void *buffer, unsigned int size); - -static int qemu_pci_cfg_read(FAR struct pcie_dev_s *dev, uintptr_t addr, - FAR void *buffer, unsigned int size); - -static int qemu_pci_map_bar(FAR struct pcie_dev_s *dev, uint32_t addr, - unsigned long length); - -static int qemu_pci_map_bar64(FAR struct pcie_dev_s *dev, uint64_t addr, - unsigned long length); - -static int qemu_pci_msix_register(FAR struct pcie_dev_s *dev, - uint32_t vector, uint32_t index); - -static int qemu_pci_msi_register(FAR struct pcie_dev_s *dev, - uint16_t vector); - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -struct pcie_bus_ops_s qemu_pcie_bus_ops = -{ - .pci_cfg_write = qemu_pci_cfg_write, - .pci_cfg_read = qemu_pci_cfg_read, - .pci_map_bar = qemu_pci_map_bar, - .pci_map_bar64 = qemu_pci_map_bar64, - .pci_msix_register = qemu_pci_msix_register, - .pci_msi_register = qemu_pci_msi_register, -}; - -struct pcie_bus_s qemu_pcie_bus = -{ - .ops = &qemu_pcie_bus_ops, -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: qemu_pci_cfg_write - * - * Description: - * Write 8, 16, 32, 64 bits data to PCI-E configuration space of device - * specified by dev - * - * Input Parameters: - * bdf - Device private data - * buffer - A pointer to the read-only buffer of data to be written - * size - The number of bytes to send from the buffer - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -static int qemu_pci_cfg_write(FAR struct pcie_dev_s *dev, uintptr_t addr, - FAR const void *buffer, unsigned int size) -{ - if (!buffer) - return -EINVAL; - - switch (size) - { - case 1: - case 2: - case 4: - return __qemu_pci_cfg_write(dev->bdf, addr, buffer, size); - case 8: - return __qemu_pci_cfg_write(dev->bdf, addr, buffer, size); - default: - return -EINVAL; - } -} - -/**************************************************************************** - * Name: qemu_pci_cfg_read - * - * Description: - * Read 8, 16, 32, 64 bits data from PCI-E configuration space of device - * specified by dev - * - * Input Parameters: - * dev - Device private data - * buffer - A pointer to a buffer to receive the data from the device - * size - The requested number of bytes to be read - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -static int qemu_pci_cfg_read(FAR struct pcie_dev_s *dev, uintptr_t addr, - FAR void *buffer, unsigned int size) -{ - if (!buffer) - return -EINVAL; - - switch (size) - { - case 1: - case 2: - case 4: - return __qemu_pci_cfg_read(dev->bdf, addr, buffer, size); - case 8: - return __qemu_pci_cfg_read64(dev->bdf, addr, buffer, size); - default: - return -EINVAL; - } -} - -/**************************************************************************** - * Name: qemu_pci_map_bar - * - * Description: - * Map address in a 32 bits bar in the memory address space - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * length - Map length, multiple of PAGE_SIZE - * ret - Bar Content - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -static int qemu_pci_map_bar(FAR struct pcie_dev_s *dev, uint32_t addr, - unsigned long length) -{ - up_map_region((void *)((uintptr_t)addr), length, - X86_PAGE_WR | X86_PAGE_PRESENT | X86_PAGE_NOCACHE | X86_PAGE_GLOBAL); - - return OK; -} - -/**************************************************************************** - * Name: qemu_pci_map_bar64 - * - * Description: - * Map address in a 64 bits bar in the memory address space - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * length - Map length, multiple of PAGE_SIZE - * ret - Bar Content - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -static int qemu_pci_map_bar64(FAR struct pcie_dev_s *dev, uint64_t addr, - unsigned long length) -{ - up_map_region((void *)((uintptr_t)addr), length, - X86_PAGE_WR | X86_PAGE_PRESENT | X86_PAGE_NOCACHE | X86_PAGE_GLOBAL); - - return OK; -} - -/**************************************************************************** - * Name: qemu_pci_msix_register - * - * Description: - * Map a device MSI-X vector to a platform IRQ vector - * - * Input Parameters: - * dev - Device - * vector - IRQ number of the platform - * index - Device MSI-X vector number - * - * Returned Value: - * <0: Mapping failed - * 0: Mapping succeed - * - ****************************************************************************/ - -static int qemu_pci_msix_register(FAR struct pcie_dev_s *dev, - uint32_t vector, uint32_t index) -{ - unsigned int bar; - uint16_t message_control; - uint32_t table_bar_ind; - uint32_t table_addr_32; - uint64_t msix_table_addr = 0; - - int cap = pci_find_cap(dev, PCI_CAP_MSIX); - if (cap < 0) - return -EINVAL; - - __qemu_pci_cfg_read(dev->bdf, cap + PCI_MSIX_MCR, - &message_control, PCI_MSIX_MCR_SIZE); - - /* bounds check */ - - if (index > (message_control & PCI_MSIX_MCR_TBL_MASK)) - return -EINVAL; - - __qemu_pci_cfg_read(dev->bdf, cap + PCI_MSIX_TBL, - &table_bar_ind, PCI_MSIX_TBL_SIZE); - - bar = (table_bar_ind & PCI_MSIX_BIR_MASK); - - if (!pci_get_bar(dev, bar, &table_addr_32)) - { - /* 32 bit bar */ - - msix_table_addr = table_addr_32; - } - else - { - pci_get_bar64(dev, bar, &msix_table_addr); - } - - msix_table_addr &= ~0xf; - msix_table_addr += table_bar_ind & ~PCI_MSIX_BIR_MASK; - - /* enable and mask */ - - message_control |= (PCI_MSIX_MCR_EN | PCI_MSIX_MCR_FMASK); - __qemu_pci_cfg_write(dev->bdf, cap + PCI_MSIX_MCR, - &message_control, PCI_MSIX_MCR_SIZE); - - msix_table_addr += PCI_MSIX_TBL_ENTRY_SIZE * index; - mmio_write32((uint32_t *)(msix_table_addr + PCI_MSIX_TBL_LO_ADDR), - 0xfee00000 | up_apic_cpu_id() << PCI_MSIX_APIC_ID_OFFSET); - mmio_write32((uint32_t *)(msix_table_addr + PCI_MSIX_TBL_HI_ADDR), - 0); - mmio_write32((uint32_t *)(msix_table_addr + PCI_MSIX_TBL_MSG_DATA), - vector); - mmio_write32((uint32_t *)(msix_table_addr + PCI_MSIX_TBL_VEC_CTL), - 0); - - /* enable and unmask */ - - message_control &= ~PCI_MSIX_MCR_FMASK; - - __qemu_pci_cfg_write(dev->bdf, cap + PCI_MSIX_MCR, - &message_control, PCI_MSIX_MCR_SIZE); - - return 0; -} - -/**************************************************************************** - * Name: qemu_pci_msi_register - * - * Description: - * Map device MSI vectors to a platform IRQ vector - * - * Input Parameters: - * dev - Device - * vector - IRQ number of the platform - * - * Returned Value: - * <0: Mapping failed - * 0: Mapping succeed - * - ****************************************************************************/ - -static int qemu_pci_msi_register(FAR struct pcie_dev_s *dev, uint16_t vector) -{ - uint16_t ctl; - uint16_t data; - - int cap = pci_find_cap(dev, PCI_CAP_MSI); - if (cap < 0) - return -1; - - uint32_t dest = 0xfee00000 | (up_apic_cpu_id() << PCI_MSI_APIC_ID_OFFSET); - __qemu_pci_cfg_write(dev->bdf, cap + PCI_MSI_MAR, &dest, PCI_MSI_MAR_SIZE); - - __qemu_pci_cfg_read(dev->bdf, cap + PCI_MSI_MCR, &ctl, PCI_MSI_MCR_SIZE); - if ((ctl & PCI_MSI_MCR_64) == PCI_MSI_MCR_64) - { - uint32_t tmp = 0; - __qemu_pci_cfg_write(dev->bdf, - cap + PCI_MSI_MAR64_HI, &tmp, - PCI_MSI_MAR64_HI_SIZE); - data = cap + PCI_MSI_MDR64; - } - else - { - data = cap + PCI_MSI_MDR; - } - - __qemu_pci_cfg_write(dev->bdf, data, &vector, PCI_MSI_MDR_SIZE); - - __qemu_pci_cfg_write(dev->bdf, cap + PCI_MSI_MCR, &vector, - PCI_MSI_MCR_SIZE); - - uint16_t tmp = PCI_MSI_MCR_EN; - - __qemu_pci_cfg_write(dev->bdf, cap + PCI_MSI_MCR, &tmp, PCI_MSI_MCR_SIZE); - - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: qemu_pcie_init - * - * Description: - * Initialize the PCI-E bus * - * - ****************************************************************************/ - -void qemu_pcie_init(void) -{ - pcie_initialize(&qemu_pcie_bus); -} diff --git a/boards/x86_64/intel64/qemu-intel64/src/qemu_pcie_readwrite.h b/boards/x86_64/intel64/qemu-intel64/src/qemu_pcie_readwrite.h deleted file mode 100644 index 01fc2712fe..0000000000 --- a/boards/x86_64/intel64/qemu-intel64/src/qemu_pcie_readwrite.h +++ /dev/null @@ -1,240 +0,0 @@ -/**************************************************************************** - * boards/x86_64/intel64/qemu-intel64/src/qemu_pcie_readwrite.h - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/* The PCI-E Definitions and part of the access routines are taken from - * Jailhouse inmate library - * - * Jailhouse, a Linux-based partitioning hypervisor - * - * Copyright (c) Siemens AG, 2014 - * - * Authors: - * Jan Kiszka - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Alternatively, you can use or redistribute this file under the following - * BSD license: - * - * 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. - * - * 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 __INCLUDE_NUTTX_PCIE_PCIE_READWRITE_H -#define __INCLUDE_NUTTX_PCIE_PCIE_READWRITE_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include - -#include -#include - -#include "up_arch.h" -#include "up_internal.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define PCI_REG_ADDR_PORT 0xcf8 -#define PCI_REG_DATA_PORT 0xcfc - -#define PCI_CONE (1 << 31) - -/**************************************************************************** - * Name: __qemu_pci_cfg_write - * - * Description: - * Write 8, 16, 32 bits data to PCI-E configuration space of device - * specified by dev - * - * Input Parameters: - * bfd - Device private data - * buffer - A pointer to the read-only buffer of data to be written - * size - The number of bytes to send from the buffer - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -static inline int __qemu_pci_cfg_write(uint16_t bfd, uintptr_t addr, - FAR const void *buffer, - unsigned int size) -{ - if (!buffer) - return -EINVAL; - - outl(PCI_CONE | ((uint32_t)bfd << 8) | (addr & 0xfc), PCI_REG_ADDR_PORT); - - switch (size) - { - case 1: - outb(*(uint8_t *)(buffer), PCI_REG_DATA_PORT + (addr & 0x3)); - break; - case 2: - outw(*(uint16_t *)(buffer), PCI_REG_DATA_PORT + (addr & 0x3)); - break; - case 4: - outl(*(uint32_t *)(buffer), PCI_REG_DATA_PORT); - break; - default: - return -EINVAL; - } - return OK; -} - -/**************************************************************************** - * Name: __qemu_pci_cfg_write64 - * - * Description: - * Write 64 bits data to PCI-E configuration space of device - * specified by dev - * - * Input Parameters: - * bfd - Device private data - * buffer - A pointer to the read-only buffer of data to be written - * size - The number of bytes to send from the buffer - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -static inline int __qemu_pci_cfg_write64(uint16_t bfd, uintptr_t addr, - FAR const void *buffer, - unsigned int size) -{ - int ret; - - if (!buffer) - return -EINVAL; - - ret = __qemu_pci_cfg_write(bfd, addr + 4, buffer + 4, 4); - ret |= __qemu_pci_cfg_write(bfd, addr, buffer, 4); - - return ret; -} - -/**************************************************************************** - * Name: __qemu_pci_cfg_read - * - * Description: - * Read 8, 16, 32 bits data from PCI-E configuration space of device - * specified by dev - * - * Input Parameters: - * dev - Device private data - * buffer - A pointer to a buffer to receive the data from the device - * size - The requested number of bytes to be read - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -static inline int __qemu_pci_cfg_read(uint16_t bfd, uintptr_t addr, - FAR void *buffer, unsigned int size) -{ - if (!buffer) - return -EINVAL; - - outl(PCI_CONE | ((uint32_t)bfd << 8) | (addr & 0xfc), PCI_REG_ADDR_PORT); - - switch (size) - { - case 1: - *(uint8_t *)(buffer) = inb(PCI_REG_DATA_PORT + (addr & 0x3)); - break; - case 2: - *(uint16_t *)(buffer) = inw(PCI_REG_DATA_PORT + (addr & 0x3)); - break; - case 4: - *(uint32_t *)(buffer) = inl(PCI_REG_DATA_PORT); - break; - default: - return -EINVAL; - } - - return OK; -} - -/**************************************************************************** - * Name: __qemu_pci_cfg_read - * - * Description: - * Read 64 bits data from PCI-E configuration space of device - * specified by dev - * - * Input Parameters: - * dev - Device private data - * buffer - A pointer to a buffer to receive the data from the device - * size - The requested number of bytes to be read - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -static inline int __qemu_pci_cfg_read64(uint16_t bfd, - uintptr_t addr, - FAR void *buffer, - unsigned int size) -{ - int ret; - - if (!buffer) - return -EINVAL; - - ret = __qemu_pci_cfg_read(bfd, addr + 4, buffer + 4, 4); - ret |= __qemu_pci_cfg_read(bfd, addr, buffer, 4); - - return ret; -} - -#endif /* __INCLUDE_NUTTX_PCIE_PCIE_READWRITE_H */ diff --git a/drivers/Kconfig b/drivers/Kconfig index da93ca190f..22603be331 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -59,5 +59,5 @@ source "drivers/usrsock/Kconfig" source "drivers/dma/Kconfig" source "drivers/devicetree/Kconfig" source "drivers/reset/Kconfig" -source "drivers/pcie/Kconfig" +source "drivers/pci/Kconfig" source "drivers/virt/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index f5584c5370..40ed2d38af 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -77,7 +77,7 @@ include rc/Make.defs include segger/Make.defs include usrsock/Make.defs include reset/Make.defs -include pcie/Make.defs +include pci/Make.defs include virt/Make.defs ifeq ($(CONFIG_SPECIFIC_DRIVERS),y) diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig new file mode 100644 index 0000000000..85aa4a7988 --- /dev/null +++ b/drivers/pci/Kconfig @@ -0,0 +1,11 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menuconfig PCI + bool "Support for PCI Bus" + default n + ---help--- + Enables support for the PCI bus. + Backend bust be provided by per-arch or per-board implementation. diff --git a/drivers/pcie/Make.defs b/drivers/pci/Make.defs similarity index 85% rename from drivers/pcie/Make.defs rename to drivers/pci/Make.defs index 68efee8123..d890993e62 100644 --- a/drivers/pcie/Make.defs +++ b/drivers/pci/Make.defs @@ -1,5 +1,5 @@ ############################################################################ -# drivers/pcie/Make.defs +# drivers/pci/Make.defs # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with @@ -20,13 +20,13 @@ # Don't build anything if there is no CAN support -ifeq ($(CONFIG_PCIE),y) +ifeq ($(CONFIG_PCI),y) -CSRCS += pcie_root.c +CSRCS += pci.c -# Include PCIE device driver build support +# Include PCI device driver build support -DEPPATH += --dep-path pcie -VPATH += :pcie -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)pcie} +DEPPATH += --dep-path pci +VPATH += :pci +CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)pci} endif diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c new file mode 100644 index 0000000000..0ae67a515d --- /dev/null +++ b/drivers/pci/pci.c @@ -0,0 +1,792 @@ +/**************************************************************************** + * nuttx/drivers/pci/pci.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* For now hard code jailhouse as a flag. In the future we can determine this + * by looking at the CPUID base for "Jailhouse\0\0\0" + */ + +#define JAILHOUSE_ENABLED 1 + +#define PCI_BDF(bus, slot, func) (((uint32_t)bus << 8) | \ + ((uint32_t)slot << 3) | \ + func) + +/**************************************************************************** + * Private Functions Definitions + ****************************************************************************/ + +static void pci_probe_device(FAR struct pci_bus_s *root_bus, + uint8_t bus_idx, uint8_t slot_idx, uint8_t func, + FAR struct pci_dev_type_s **types); + +static uint8_t pci_check_pci_bridge(FAR struct pci_bus_s *root_bus, + uint8_t bus_idx, uint8_t slot_idx, + uint8_t dev_func); + +static void pci_scan_device(FAR struct pci_bus_s *root_bus, + uint8_t bus_idx, uint8_t slot_idx, + FAR struct pci_dev_type_s **types); + +static void pci_scan_bus(FAR struct pci_bus_s *root_bus, + uint8_t bus_idx, + FAR struct pci_dev_type_s **types); + +static void pci_set_cmd_bit(FAR struct pci_dev_s *dev, uint16_t bitmask); + +static void pci_clear_cmd_bit(FAR struct pci_dev_s *dev, uint16_t bitmask); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +struct pci_dev_type_s *pci_device_types[] = +{ +#ifdef CONFIG_VIRT_QEMU_PCI_TEST + &pci_type_qemu_pci_test, +#endif /* CONFIG_VIRT_QEMU_PCI_TEST */ +#ifdef CONFIG_VIRT_QEMU_EDU + &pci_type_qemu_edu, +#endif /* CONFIG_VIRT_QEMU_EDU */ + NULL, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pci_probe + * + * Description: + * Checks if the specified device is supported and if so calls probe on it + * + * Input Parameters: + * root_bus - The root bus device that lets us address the whole tree + * bus - Bus ID + * slot - Device Slot + * func - Device Function + * types - List of pointers to devices types recognized, NULL terminated + * + ****************************************************************************/ + +static void pci_probe_device(FAR struct pci_bus_s *root_bus, + uint8_t bus_idx, uint8_t slot_idx, uint8_t func, + FAR struct pci_dev_type_s **types) +{ + struct pci_dev_s tmp_dev; + uint16_t vid; + uint16_t id; + uint32_t class_rev; + + tmp_dev.bus = root_bus; + tmp_dev.bdf = PCI_BDF(bus_idx, slot_idx, func); + + vid = root_bus->ops->pci_cfg_read(&tmp_dev, PCI_CONFIG_VENDOR, 2); + id = root_bus->ops->pci_cfg_read(&tmp_dev, PCI_CONFIG_DEVICE, 2); + + /* This is reading rev prog_if subclass and class */ + + class_rev = root_bus->ops->pci_cfg_read(&tmp_dev, PCI_CONFIG_REV_ID, 4); + + pci_dev_dump(&tmp_dev); + + for (int i = 0; types[i] != NULL; i++) + { + if (types[i]->vendor == PCI_ID_ANY || + types[i]->vendor == vid) + { + if (types[i]->device == PCI_ID_ANY || + types[i]->device == id) + { + if (types[i]->class_rev == PCI_ID_ANY || + types[i]->class_rev == class_rev) + { + pciinfo("Found: %s\n", types[i]->name); + if (types[i]->probe) + { + pciinfo("[%02x:%02x.%x] Probing\n", + bus_idx, slot_idx, func); + types[i]->probe(root_bus, types[i], tmp_dev.bdf); + } + else + { + pcierr("[%02x:%02x.%x] Error: Invalid \ + device probe function\n", + bus_idx, slot_idx, func); + } + break; + } + } + } + } +} + +/**************************************************************************** + * Name: pci_check_pci_bridge + * + * Description: + * Checks if the specified device is PCI bridge and return the sub-bridge + * idx if found. Otherwise return 0. + * + * Input Parameters: + * root_bus - The root bus device that lets us address the whole tree + * bus - Bus ID + * slot - Device Slot + * func - Device Function + * + ****************************************************************************/ + +static uint8_t pci_check_pci_bridge(FAR struct pci_bus_s *root_bus, + uint8_t bus_idx, uint8_t slot_idx, + uint8_t dev_func) +{ + struct pci_dev_s tmp_dev; + uint8_t base_class; + uint8_t sub_class; + uint8_t secondary_bus; + + tmp_dev.bus = root_bus; + tmp_dev.bdf = PCI_BDF(bus_idx, slot_idx, dev_func); + + /* Check if this is a PCI-PCI bridge device */ + + base_class = root_bus->ops->pci_cfg_read(&tmp_dev, PCI_CONFIG_CLASS, 1); + sub_class = root_bus->ops->pci_cfg_read(&tmp_dev, PCI_CONFIG_SUBCLASS, 1); + + if ((base_class == PCI_CLASS_BASE_BRG_DEV) && \ + (sub_class == PCI_CLASS_SUB_PCI_BRG)) + { + /* This is a bridge device we need to determin the bus idx and + * enumerate it just like we do the root. + */ + + pciinfo("[%02x:%02x.%x] Found Bridge\n", + bus_idx, slot_idx, dev_func); + + secondary_bus = root_bus->ops->pci_cfg_read( + &tmp_dev, PCI_CONFIG_SEC_BUS, 1); + return secondary_bus; + } + + return 0; +} + +/**************************************************************************** + * Name: pci_scan_device + * + * Description: + * Checks if the specified device is a bus and iterates over it or + * if it is a real device initializes it if recognized. + * + * Input Parameters: + * root_bus - The root bus device that lets us address the whole tree + * bus - Bus ID + * slot - Device Slot + * types - List of pointers to devices types recognized, NULL terminated + * + ****************************************************************************/ + +static void pci_scan_device(FAR struct pci_bus_s *root_bus, + uint8_t bus_idx, uint8_t slot_idx, + FAR struct pci_dev_type_s **types) +{ + struct pci_dev_s tmp_dev; + uint8_t dev_func = 0; + uint16_t vid; + uint8_t sec_bus; + uint8_t multi_function; + + tmp_dev.bus = root_bus; + tmp_dev.bdf = PCI_BDF(bus_idx, slot_idx, dev_func); + vid = root_bus->ops->pci_cfg_read(&tmp_dev, PCI_CONFIG_VENDOR, 2); + if (vid == 0xffff) + return; + + /* Check if this is a PCI-PCI bridge device */ + + sec_bus = pci_check_pci_bridge(root_bus, bus_idx, slot_idx, dev_func); + if (sec_bus) + pci_scan_bus(root_bus, sec_bus, types); + + multi_function = root_bus->ops->pci_cfg_read( + &tmp_dev, PCI_CONFIG_HEADER_TYPE, 1) & PCI_HEADER_MASK_MULTI; + + /* Jailhouse breaks the PCI spec by allowing you to pass individual + * functions of a multi-function device. In this case we need to + * scan each of the functions not just function 0. + */ + + if (multi_function || JAILHOUSE_ENABLED) + { + /* This is a multi-function device that we need to iterate over */ + + for (dev_func = 0; dev_func < 8; dev_func++) + { + tmp_dev.bdf = PCI_BDF(bus_idx, slot_idx, dev_func); + vid = root_bus->ops->pci_cfg_read(&tmp_dev, PCI_CONFIG_VENDOR, 2); + if (vid != 0xffff) + { + sec_bus = pci_check_pci_bridge( + root_bus, bus_idx, slot_idx, dev_func); + if (sec_bus) + { + pci_scan_bus(root_bus, sec_bus, types); + continue; + } + + pci_probe_device(root_bus, bus_idx, slot_idx, dev_func, types); + } + } + } + else + { + pci_probe_device(root_bus, bus_idx, slot_idx, dev_func, types); + } +} + +/**************************************************************************** + * Name: pci_scan_bus + * + * Description: + * Iterates over all slots on bus looking for devices and buses to + * enumerate. + * + * Input Parameters: + * root_bus - The root bus device that lets us address the whole tree + * bus - Bus ID + * types - List of pointers to devices types recognized, NULL terminated + * + ****************************************************************************/ + +static void pci_scan_bus(FAR struct pci_bus_s *root_bus, + uint8_t bus_idx, + FAR struct pci_dev_type_s **types) +{ + uint8_t slot_idx; + + for (slot_idx = 0; slot_idx < 32; slot_idx++) + { + pci_scan_device(root_bus, bus_idx, slot_idx, types); + } + + return; +} + +/**************************************************************************** + * Name: pci_set_cmd_bit + * + * Description: + * This sets an individual bit in the command register for a device. + * + * Input Parameters: + * dev - device + * bit - Bit to set + * + ****************************************************************************/ + +static void pci_set_cmd_bit(FAR struct pci_dev_s *dev, uint16_t bitmask) +{ + uint16_t cmd; + + cmd = dev->bus->ops->pci_cfg_read(dev, PCI_CONFIG_COMMAND, 2); + dev->bus->ops->pci_cfg_write(dev, PCI_CONFIG_COMMAND, + (cmd | bitmask), 2); +} + +/**************************************************************************** + * Name: pci_clear_cmd_bit + * + * Description: + * This clears an individual bit in the command register for a device. + * + * Input Parameters: + * dev - device + * bit - Bit to set + * + ****************************************************************************/ + +static void pci_clear_cmd_bit(FAR struct pci_dev_s *dev, uint16_t bitmask) +{ + uint16_t cmd; + + cmd = dev->bus->ops->pci_cfg_read(dev, PCI_CONFIG_COMMAND, 2); + dev->bus->ops->pci_cfg_write(dev, PCI_CONFIG_COMMAND, + (cmd & ~bitmask), 2); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pci_enumerate + * + * Description: + * Scan the PCI bus and enumerate the devices. + * Initialize any recognized devices, given in types. + * + * Input Parameters: + * bus - PCI-E bus structure + * types - List of pointers to devices types recognized, NULL terminated + * + * Returned Value: + * 0: success, <0: A negated errno + * + ****************************************************************************/ + +int pci_enumerate(FAR struct pci_bus_s *bus, + FAR struct pci_dev_type_s **types) +{ + if (!bus) + return -EINVAL; + if (!types) + return -EINVAL; + + pci_scan_bus(bus, 0, types); + return OK; +} + +/**************************************************************************** + * Name: pci_initialize + * + * Description: + * Initialize the PCI-E bus and enumerate the devices with give devices + * type array + * + * Input Parameters: + * bus - An PCIE bus + * types - A array of PCIE device types + * num - Number of device types + * + * Returned Value: + * OK if the driver was successfully register; A negated errno value is + * returned on any failure. + * + ****************************************************************************/ + +int pci_initialize(FAR struct pci_bus_s *bus) +{ + return pci_enumerate(bus, pci_device_types); +} + +/**************************************************************************** + * Name: pci_enable_io + * + * Description: + * Enable MMIO or IOPORT + * + * Input Parameters: + * dev - device + * space - which resource is being enabled + * PCI_SYS_RES_IOPORT for io port address decoding or + * PCI_SYS_RES_MEM for memory + * + * Return value: + * -EINVAL: error + * OK: OK + * + ****************************************************************************/ + +int pci_enable_io(FAR struct pci_dev_s *dev, int res) +{ + switch (res) + { + case PCI_SYS_RES_IOPORT: + pci_set_cmd_bit(dev, PCI_CMD_IO_SPACE); + return OK; + case PCI_SYS_RES_MEM: + pci_set_cmd_bit(dev, PCI_CMD_MEM_SPACE); + return OK; + } + + return -EINVAL; +} + +/**************************************************************************** + * Name: pci_disable_io + * + * Description: + * Enable MMIO or IOPORT + * + * Input Parameters: + * dev - device + * space - which resource is being disabled + * PCI_SYS_RES_IOPORT for io port address decoding or + * PCI_SYS_RES_MEM for memory + * + * Return value: + * -EINVAL: error + * OK: OK + * + ****************************************************************************/ + +int pci_disable_io(FAR struct pci_dev_s *dev, int res) +{ + switch (res) + { + case PCI_SYS_RES_IOPORT: + pci_clear_cmd_bit(dev, PCI_CMD_IO_SPACE); + return OK; + case PCI_SYS_RES_MEM: + pci_clear_cmd_bit(dev, PCI_CMD_MEM_SPACE); + return OK; + } + + return -EINVAL; +} + +/**************************************************************************** + * Name: pci_enable_bus_master + * + * Description: + * Enable bus mastering for device so it can perform PCI accesses + * + * Input Parameters: + * dev - device + * + * Return value: + * -EINVAL: error + * OK: OK + * + ****************************************************************************/ + +int pci_enable_bus_master(FAR struct pci_dev_s *dev) +{ + pci_set_cmd_bit(dev, PCI_CMD_BUS_MSTR); + return OK; +} + +/**************************************************************************** + * Name: pci_disable_bus_master + * + * Description: + * Disable bus mastering for device + * + * Input Parameters: + * dev - device + * + * Return value: + * -EINVAL: error + * OK: OK + * + ****************************************************************************/ + +int pci_disable_bus_master(FAR struct pci_dev_s *dev) +{ + pci_clear_cmd_bit(dev, PCI_CMD_BUS_MSTR); + return OK; +} + +/**************************************************************************** + * Name: pci_bar_valid + * + * Description: + * Determine in if the address in the BAR is valid + * + * Input Parameters: + * dev - device + * bar_id - bar number + * + * Return value: + * -EINVAL: error + * OK: OK + * + ****************************************************************************/ + +int pci_bar_valid(FAR struct pci_dev_s *dev, uint8_t bar_id) +{ + uint32_t bar = dev->bus->ops->pci_cfg_read(dev, + PCI_HEADER_NORM_BAR0 + (bar_id * 4), 4); + + if (bar == PCI_BAR_INVALID) + { + return -EINVAL; + } + + return OK; +} + +/**************************************************************************** + * Name: pci_bar_is_64 + * + * Description: + * Determine in if the bar address is 64 bit. If it is the address includes + * the address in the next bar location. + * + * Input Parameters: + * dev - device + * bar_id - bar number + * + * Return value: + * true: 64bit address + * + ****************************************************************************/ + +bool pci_bar_is_64(FAR struct pci_dev_s *dev, uint8_t bar_id) +{ + uint32_t bar = dev->bus->ops->pci_cfg_read(dev, + PCI_HEADER_NORM_BAR0 + (bar_id * 4), 4); + + /* Check that it is memory and not io port */ + + if ((bar & PCI_BAR_LAYOUT_MASK) != PCI_BAR_LAYOUT_MEM) + return false; + + if (((bar & PCI_BAR_TYPE_MASK) >> PCI_BAR_TYPE_OFFSET) == PCI_BAR_TYPE_64) + { + return true; + } + + return false; +} + +/**************************************************************************** + * Name: pci_bar_size + * + * Description: + * Determine the size of the address space required by the BAR + * + * Input Parameters: + * dev - device + * bar_id - bar number + * + * Return value: + * Size of address space + * + ****************************************************************************/ + +uint64_t pci_bar_size(FAR struct pci_dev_s *dev, uint8_t bar_id) +{ + uint32_t bar; + uint32_t size; + uint64_t full_size; + uint8_t bar_offset = PCI_HEADER_NORM_BAR0 + (bar_id * 4); + const struct pci_bus_ops_s *dev_ops = dev->bus->ops; + + bar = dev_ops->pci_cfg_read(dev, bar_offset, 4); + + /* Write all 1 to the BAR. We are looking for which bits will change */ + + dev_ops->pci_cfg_write(dev, bar_offset, 0xffffffff, 4); + full_size = dev_ops->pci_cfg_read(dev, bar_offset, 4); + + /* Resore BAR to original values */ + + dev_ops->pci_cfg_write(dev, bar_offset, bar, 4); + + if (full_size == 0) + { + /* This is not a valid bar */ + + return 0; + } + + if ((bar & PCI_BAR_LAYOUT_MASK) == PCI_BAR_LAYOUT_MEM) + { + full_size &= PCI_BAR_MEM_BASE_MASK; + } + else + { + full_size &= PCI_BAR_IO_BASE_MASK; + } + + /* If it is 64 bit address check the next bar as well */ + + if (pci_bar_is_64(dev, bar_id)) + { + bar_offset += 4; + bar = dev_ops->pci_cfg_read(dev, bar_offset, 4); + dev_ops->pci_cfg_write(dev, bar_offset, 0xffffffff, 4); + size = dev_ops->pci_cfg_read(dev, bar_offset, 4); + dev_ops->pci_cfg_write(dev, bar_offset, bar, 4); + full_size |= ((uint64_t)size << 32); + } + else + { + full_size |= (uint64_t)(0xffffffff) << 32; + } + + return ~full_size + 1; +} + +/**************************************************************************** + * Name: pci_bar_addr + * + * Description: + * Determine the size of the address space required by the BAR + * + * Input Parameters: + * dev - device + * bar_id - bar number + * + * Return value: + * full bar address + * + ****************************************************************************/ + +uint64_t pci_bar_addr(FAR struct pci_dev_s *dev, uint8_t bar_id) +{ + uint64_t addr; + uint8_t bar_offset = PCI_HEADER_NORM_BAR0 + (bar_id * 4); + const struct pci_bus_ops_s *dev_ops = dev->bus->ops; + + addr = dev_ops->pci_cfg_read(dev, bar_offset, 4); + + if ((addr & PCI_BAR_LAYOUT_MASK) == PCI_BAR_LAYOUT_MEM) + { + addr &= PCI_BAR_MEM_BASE_MASK; + } + else + { + addr &= PCI_BAR_IO_BASE_MASK; + } + + /* If it is 64 bit address check the next bar as well */ + + if (pci_bar_is_64(dev, bar_id)) + { + bar_offset += 4; + addr |= (uint64_t)(dev_ops->pci_cfg_read(dev, bar_offset, 4)) << 32; + } + + return addr; +} + +/**************************************************************************** + * Name: pci_dev_dump + * + * Description: + * Dump the configuration information for the device + * + * Input Parameters: + * dev - device + * + ****************************************************************************/ + +void pci_dev_dump(FAR struct pci_dev_s *dev) +{ + uint8_t bar_id; + uint8_t bar_mem_type = 0; + uint32_t bar; + uint64_t bar_size; + uint64_t bar_addr; + + uint8_t cap_id; + uint8_t cap_offset; + + const struct pci_bus_ops_s *dev_ops = dev->bus->ops; + uint32_t bdf = dev->bdf; + uint16_t vid = dev_ops->pci_cfg_read(dev, PCI_CONFIG_VENDOR, 2); + uint16_t pid = dev_ops->pci_cfg_read(dev, PCI_CONFIG_DEVICE, 2); + uint8_t header = dev_ops->pci_cfg_read(dev, PCI_CONFIG_HEADER_TYPE, 1); + uint8_t progif = dev_ops->pci_cfg_read(dev, PCI_CONFIG_PROG_IF, 1); + uint8_t subclass = dev_ops->pci_cfg_read(dev, PCI_CONFIG_SUBCLASS, 1); + uint8_t class = dev_ops->pci_cfg_read(dev, PCI_CONFIG_CLASS, 1); + uint8_t int_pin; + uint8_t int_line; + + pciinfo("[%02x:%02x.%x] %04x:%04x\n", + bdf >> 8, (bdf & 0xff) >> 3, bdf & 0x7, vid, pid); + pciinfo("\ttype %02x Prog IF %02x Class %02x Subclass %02x\n", + header, progif, class, subclass); + + cap_offset = dev_ops->pci_cfg_read(dev, PCI_HEADER_NORM_CAP, 1); + while (cap_offset) + { + cap_id = dev_ops->pci_cfg_read(dev, cap_offset, 1); + if (cap_id > PCI_CAP_ID_END) + { + pcierr("Invalid PCI Capability Found, Skipping. %d\n", cap_id); + DEBUGPANIC(); + break; + } + + pciinfo("\tCAP %02x\n", cap_id); + cap_offset = dev_ops->pci_cfg_read(dev, cap_offset + 1, 1); + } + + if ((header & PCI_HEADER_TYPE_MASK) != PCI_HEADER_NORMAL) + return; + + int_pin = dev_ops->pci_cfg_read(dev, PCI_HEADER_NORM_INT_PIN, 1); + int_line = dev_ops->pci_cfg_read(dev, PCI_HEADER_NORM_INT_LINE, 1); + pciinfo("\tINT Pin %02x Line %02x\n", int_pin, int_line); + + for (bar_id = 0; bar_id < PCI_BAR_CNT; bar_id++) + { + if (pci_bar_valid(dev, bar_id) != OK) + continue; + + bar = dev_ops->pci_cfg_read(dev, + PCI_HEADER_NORM_BAR0 + (bar_id * 4), 4); + + bar_size = pci_bar_size(dev, bar_id); + bar_addr = pci_bar_addr(dev, bar_id); + if ((bar & PCI_BAR_LAYOUT_MASK) == PCI_BAR_LAYOUT_MEM) + { + switch ((bar & PCI_BAR_TYPE_MASK) >> PCI_BAR_TYPE_OFFSET) + { + case PCI_BAR_TYPE_64: + bar_mem_type = 64; + break; + case PCI_BAR_TYPE_32: + bar_mem_type = 32; + break; + case PCI_BAR_TYPE_16: + bar_mem_type = 16; + break; + default: + bar_mem_type = 0; + } + + pciinfo("\tBAR [%d] MEM %db range %p-%p (%p)\n", + bar_id, bar_mem_type, + bar_addr, bar_addr + bar_size - 1, bar_size); + } + else + { + pciinfo("\tBAR [%d] PIO range %p-%p (%p)\n", + bar_id, + bar_addr, bar_addr + bar_size - 1, bar_size); + } + + /* Skip next bar if this one was 64bit */ + + if (bar_mem_type == 64) + bar_id++; + } +} diff --git a/drivers/pcie/Kconfig b/drivers/pcie/Kconfig deleted file mode 100644 index 7ac9db568b..0000000000 --- a/drivers/pcie/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see the file kconfig-language.txt in the NuttX tools repository. -# - -menuconfig PCIE - bool "Support for PCI-E Bus" - default n - ---help--- - Enables support for the PCI-E bus. - Backend bust be provided by per-arch or per-board implementation.. - -if PCIE -config PCIE_MAX_BDF - hex "Maximum bdf to scan on PCI-E bus" - default 0x10000 - ---help--- - The maximum bdf number to be scaned on PCI-E bus - -endif diff --git a/drivers/pcie/pcie_root.c b/drivers/pcie/pcie_root.c deleted file mode 100644 index b85c5862fa..0000000000 --- a/drivers/pcie/pcie_root.c +++ /dev/null @@ -1,446 +0,0 @@ -/**************************************************************************** - * nuttx/drivers/pcie/pcie_root.c - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include - -#include -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -struct pcie_dev_type_s *pci_device_types[] = -{ -#ifdef CONFIG_VIRT_QEMU_PCI_TEST - &pcie_type_qemu_pci_test, -#endif /* CONFIG_VIRT_QEMU_PCI_TEST */ - NULL, -}; - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: pci_enumerate - * - * Description: - * Scan the PCI bus and enumerate the devices. - * Initialize any recognized devices, given in types. - * - * Input Parameters: - * bus - PCI-E bus structure - * type - List of pointers to devices types recognized, NULL terminated - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_enumerate(FAR struct pcie_bus_s *bus, - FAR struct pcie_dev_type_s **types) -{ - unsigned int bdf; - uint16_t vid; - uint16_t id; - uint16_t rev; - struct pcie_dev_s tmp_dev; - struct pcie_dev_type_s tmp_type = - { - .name = "Unknown", - .vendor = PCI_ID_ANY, - .device = PCI_ID_ANY, - .class_rev = PCI_ID_ANY, - .probe = NULL, - }; - - if (!bus) - return -EINVAL; - if (!types) - return -EINVAL; - - for (bdf = 0; bdf < CONFIG_PCIE_MAX_BDF; bdf++) - { - tmp_dev.bus = bus; - tmp_dev.type = &tmp_type; - tmp_dev.bdf = bdf; - - bus->ops->pci_cfg_read(&tmp_dev, PCI_CFG_VENDOR_ID, &vid, 2); - bus->ops->pci_cfg_read(&tmp_dev, PCI_CFG_DEVICE_ID, &id, 2); - bus->ops->pci_cfg_read(&tmp_dev, PCI_CFG_REVERSION, &rev, 2); - - if (vid == PCI_ID_ANY) - continue; - - pciinfo("[%02x:%02x.%x] Found %04x:%04x, class/reversion %08x\n", - bdf >> 8, (bdf >> 3) & 0x1f, bdf & 0x3, - vid, id, rev); - - for (int i = 0; types[i] != NULL; i++) - { - if (types[i]->vendor == PCI_ID_ANY || - types[i]->vendor == vid) - { - if (types[i]->device == PCI_ID_ANY || - types[i]->device == id) - { - if (types[i]->class_rev == PCI_ID_ANY || - types[i]->class_rev == rev) - { - if (types[i]->probe) - { - pciinfo("[%02x:%02x.%x] %s\n", - bdf >> 8, (bdf >> 3) & 0x1f, bdf & 0x3, - types[i]->name); - types[i]->probe(bus, types[i], bdf); - } - else - { - pcierr("[%02x:%02x.%x] Error: Invalid \ - device probe function\n", - bdf >> 8, (bdf >> 3) & 0x1f, bdf & 0x3); - } - break; - } - } - } - } - } - - return OK; -} - -/**************************************************************************** - * Name: pcie_initialize - * - * Description: - * Initialize the PCI-E bus and enumerate the devices with give devices - * type array - * - * Input Parameters: - * bus - An PCIE bus - * types - A array of PCIE device types - * num - Number of device types - * - * Returned Value: - * OK if the driver was successfully register; A negated errno value is - * returned on any failure. - * - ****************************************************************************/ - -int pcie_initialize(FAR struct pcie_bus_s *bus) -{ - return pci_enumerate(bus, pci_device_types); -} - -/**************************************************************************** - * Name: pci_enable_device - * - * Description: - * Enable device with MMIO - * - * Input Parameters: - * dev - device - * - * Return value: - * -EINVAL: error - * OK: OK - * - ****************************************************************************/ - -int pci_enable_device(FAR struct pcie_dev_s *dev) -{ - uint16_t old_cmd; - uint16_t cmd; - - dev->bus->ops->pci_cfg_read(dev, PCI_CFG_COMMAND, &old_cmd, 2); - - cmd = old_cmd | (PCI_CMD_MASTER | PCI_CMD_MEM); - - dev->bus->ops->pci_cfg_write(dev, PCI_CFG_COMMAND, &cmd, 2); - - pciinfo("%02x:%02x.%x, CMD: %x -> %x\n", - dev->bdf >> 8, (dev->bdf >> 3) & 0x1f, dev->bdf & 0x3, - old_cmd, cmd); - - return OK; -} - -/**************************************************************************** - * Name: pci_find_cap - * - * Description: - * Search through the PCI-e device capability list to find given capability. - * - * Input Parameters: - * dev - Device - * cap - Bitmask of capability - * - * Returned Value: - * -1: Capability not supported - * other: the offset in PCI configuration space to the capability structure - * - ****************************************************************************/ - -int pci_find_cap(FAR struct pcie_dev_s *dev, uint16_t cap) -{ - uint8_t pos = PCI_CFG_CAP_PTR - 1; - uint16_t status; - uint8_t rcap; - - dev->bus->ops->pci_cfg_read(dev, PCI_CFG_STATUS, &status, 2); - - if (!(status & PCI_STS_CAPS)) - return -EINVAL; - - while (1) - { - dev->bus->ops->pci_cfg_read(dev, pos + 1, &pos, 1); - if (pos == 0) - return -EINVAL; - - dev->bus->ops->pci_cfg_read(dev, pos, &rcap, 1); - - if (rcap == cap) - return pos; - } -} - -/**************************************************************************** - * Name: pci_get_bar - * - * Description: - * Get a 32 bits bar - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * ret - Bar Content - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_get_bar(FAR struct pcie_dev_s *dev, uint32_t bar, - uint32_t *ret) -{ - if (bar > 5) - return -EINVAL; - - dev->bus->ops->pci_cfg_read(dev, PCI_CFG_BAR + bar * 4, ret, 4); - - return OK; -} - -/**************************************************************************** - * Name: pci_get_bar64 - * - * Description: - * Get a 64 bits bar - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * ret - Bar Content - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_get_bar64(FAR struct pcie_dev_s *dev, uint32_t bar, - uint64_t *ret) -{ - if (bar > 4 || ((bar % 2) != 0)) - return -EINVAL; - - uint32_t barmem1; - uint32_t barmem2; - - dev->bus->ops->pci_cfg_read(dev, PCI_CFG_BAR + bar * 4, &barmem1, 4); - dev->bus->ops->pci_cfg_read(dev, PCI_CFG_BAR + bar * 4 + 4, &barmem2, 4); - - *ret = ((uint64_t)barmem2 << 32) | barmem1; - - return OK; -} - -/**************************************************************************** - * Name: pci_set_bar - * - * Description: - * Set a 32 bits bar - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * val - Bar Content - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_set_bar(FAR struct pcie_dev_s *dev, uint32_t bar, - uint32_t val) -{ - if (bar > 5) - return -EINVAL; - - dev->bus->ops->pci_cfg_write(dev, PCI_CFG_BAR + bar * 4, &val, 4); - - return OK; -} - -/**************************************************************************** - * Name: pci_set_bar64 - * - * Description: - * Set a 64 bits bar - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * val - Bar Content - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_set_bar64(FAR struct pcie_dev_s *dev, uint32_t bar, - uint64_t val) -{ - if (bar > 4 || ((bar % 2) != 0)) - return -EINVAL; - - uint32_t barmem1 = (uint32_t)val; - uint32_t barmem2 = (uint32_t)(val >> 32); - - dev->bus->ops->pci_cfg_write(dev, PCI_CFG_BAR + bar * 4, &barmem1, 4); - dev->bus->ops->pci_cfg_write(dev, PCI_CFG_BAR + bar * 4 + 4, &barmem2, 4); - - return OK; -} - -/**************************************************************************** - * Name: pci_map_bar - * - * Description: - * Map address in a 32 bits bar in the flat memory address space - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * length - Map length, multiple of PAGE_SIZE - * ret - Bar Content if not NULL - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_map_bar(FAR struct pcie_dev_s *dev, uint32_t bar, - unsigned long length, uint32_t *ret) -{ - if (bar > 5) - return -EINVAL; - - uint32_t barmem; - - dev->bus->ops->pci_cfg_read(dev, PCI_CFG_BAR + bar * 4, &barmem, 4); - - if (((bar % 2) == 0 && - (barmem & PCI_BAR_64BIT) == PCI_BAR_64BIT) || - (barmem & PCI_BAR_IO) == PCI_BAR_IO) - return -EINVAL; - - if (!dev->bus->ops->pci_map_bar) - return -EINVAL; - - dev->bus->ops->pci_map_bar(dev, barmem, length); - - if (ret) - *ret = barmem; - - return OK; -} - -/**************************************************************************** - * Name: pci_map_bar64 - * - * Description: - * Map address in a 64 bits bar in the flat memory address space - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * length - Map length, multiple of PAGE_SIZE - * ret - Bar Content if not NULL - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_map_bar64(FAR struct pcie_dev_s *dev, uint32_t bar, - unsigned long length, uint64_t *ret) -{ - if (bar > 4 || ((bar % 2) != 0)) - return -EINVAL; - - uint32_t barmem1; - uint32_t barmem2; - uint64_t barmem; - - dev->bus->ops->pci_cfg_read(dev, PCI_CFG_BAR + bar * 4, &barmem1, 4); - - if ((barmem1 & PCI_BAR_64BIT) != PCI_BAR_64BIT || - (barmem1 & PCI_BAR_IO) == PCI_BAR_IO) - return -EINVAL; - - dev->bus->ops->pci_cfg_read(dev, PCI_CFG_BAR + bar * 4 + 4, &barmem2, 4); - - barmem = ((uint64_t)barmem2 << 32) | barmem1; - - if (!dev->bus->ops->pci_map_bar64) - return -EINVAL; - - dev->bus->ops->pci_map_bar64(dev, barmem, length); - - if (ret) - *ret = barmem; - - return OK; -} diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig index bf8fb8591c..6eee0ff10d 100644 --- a/drivers/virt/Kconfig +++ b/drivers/virt/Kconfig @@ -15,8 +15,15 @@ if VIRT config VIRT_QEMU_PCI_TEST bool "Driver for QEMU PCI test device" default n - select PCIE + select PCI ---help--- Driver for QEMU PCI test device +config VIRT_QEMU_EDU + bool "Driver for QEMU EDU test device" + default n + select PCI + ---help--- + Driver for QEMU EDU test device + endif # VIRT diff --git a/drivers/virt/Make.defs b/drivers/virt/Make.defs index 8ccfbe06c5..a65cce26f4 100644 --- a/drivers/virt/Make.defs +++ b/drivers/virt/Make.defs @@ -1,5 +1,5 @@ ############################################################################ -# drivers/pcie/Make.defs +# drivers/pci/Make.defs # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with @@ -26,6 +26,12 @@ CSRCS += qemu_pci_test.c endif +ifeq ($(CONFIG_VIRT_QEMU_EDU),y) + +CSRCS += qemu_edu.c + +endif + # Include virt device driver build support # ifeq ($(CONFIG_VIRT),y) diff --git a/drivers/virt/qemu_edu.c b/drivers/virt/qemu_edu.c new file mode 100644 index 0000000000..953d161a52 --- /dev/null +++ b/drivers/virt/qemu_edu.c @@ -0,0 +1,448 @@ +/***************************************************************************** + * drivers/virt/qemu_edu.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + *****************************************************************************/ + +/***************************************************************************** + * Included Files + *****************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/***************************************************************************** + * Pre-processor Definitions + *****************************************************************************/ + +/* Registers defined for device. Size 4 for < 0x80. Size 8 for >= 0x80. */ + +#define EDU_REG_ID 0x00 /* Identification */ +#define EDU_REG_LIVE 0x04 /* Liveness Check */ +#define EDU_REG_FAC 0x08 /* Factorial Computation */ +#define EDU_REG_STATUS 0x20 /* Status */ +#define EDU_REG_INT_STATUS 0x24 /* Interupt Status */ +#define EDU_REG_INT_RAISE 0x60 /* Raise an interrupt */ +#define EDU_REG_INT_ACK 0x64 /* Acknowledge interrupt */ +#define EDU_REG_DMA_SOURCE 0x80 /* Source address for DMA transfer */ +#define EDU_REG_DMA_DEST 0x88 /* Destination address for DMA transfer */ +#define EDU_REG_DMA_COUNT 0x90 /* Size of area to transfer with DMA */ +#define EDU_REG_DMA_CMD 0x98 /* Control DMA tranfer */ + +#define EDU_CONTROL_BAR_ID 0 +#define EDU_CONTROL_BAR_OFFSET PCI_HEADER_NORM_BAR0 + +/***************************************************************************** + * Private Types + *****************************************************************************/ + +struct qemu_edu_priv_s +{ + uintptr_t base_addr; + sem_t isr_done; + uint32_t test_result; +}; + +/***************************************************************************** + * Private Functions Definitions + *****************************************************************************/ + +static void qemu_edu_write_reg32(uintptr_t addr, uint32_t val); + +static uint32_t qemu_edu_read_reg32(uintptr_t addr); + +static void qemu_edu_write_reg64(uintptr_t addr, uint64_t val); + +static void qemu_edu_test_poll(FAR struct pci_dev_s *dev, + uintptr_t base_addr); + +static void qemu_edu_test_intx(FAR struct pci_dev_s *dev, + struct qemu_edu_priv_s *drv_priv); + +static int qemu_edu_interrupt(int irq, void *context, FAR void *arg); + +/***************************************************************************** + * Private Data + *****************************************************************************/ + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: qemu_edu_write_reg32 + * + * Description: + * Provide a write interface for 32bit mapped registers + * + * Input Parameters: + * addr - Register address + * val - Value to assign to register + * + *****************************************************************************/ + +static void qemu_edu_write_reg32(uintptr_t addr, uint32_t val) +{ + *(volatile uint32_t *)addr = val; +} + +/***************************************************************************** + * Name: qemu_edu_read_reg32 + * + * Description: + * Provide a read interface for 32bit mapped registers + * + * Returned Value: + * Register value + * + *****************************************************************************/ + +static uint32_t qemu_edu_read_reg32(uintptr_t addr) +{ + return *(volatile uint32_t *)addr; +} + +/***************************************************************************** + * Name: qemu_edu_write_reg64 + * + * Description: + * Provide a write interface for 64bit mapped registers + * + * Input Parameters: + * addr - Register address + * val - Value to assign to register + * + *****************************************************************************/ + +static void qemu_edu_write_reg64(uintptr_t addr, uint64_t val) +{ + *(volatile uint64_t *)addr = val; +} + +/***************************************************************************** + * Name: qemu_edu_test_poll + * + * Description: + * Performs basic functional test of PCI device and MMIO using polling + * of mapped register interfaces. + * + * Input Parameters: + * bus - An PCI device + * base_addr - Base address of device register space + * + *****************************************************************************/ + +static void qemu_edu_test_poll(FAR struct pci_dev_s *dev, uintptr_t base_addr) +{ + uint32_t test_value; + uint32_t test_read; + + pciinfo("Identification: 0x%08xu\n", + qemu_edu_read_reg32(base_addr + EDU_REG_ID)); + + /* Test Live Check */ + + test_value = 0xdeadbeef; + qemu_edu_write_reg32(base_addr + EDU_REG_LIVE, test_value); + test_read = qemu_edu_read_reg32(base_addr + EDU_REG_LIVE); + pciinfo("Live Check: Wrote: 0x%08x Read: 0x%08x Error Bits 0x%08x\n", + test_value, test_read, test_read ^ ~test_value); + pciinfo("TEST %s\n", ((test_read ^ ~test_value) == 0) ? "PASS" : "FAIL"); + + /* Test Factorial */ + + test_value = 10; + qemu_edu_write_reg32(base_addr + EDU_REG_STATUS, 0); + qemu_edu_write_reg32(base_addr + EDU_REG_FAC, test_value); + while (qemu_edu_read_reg32(base_addr + EDU_REG_STATUS) & 0x01) + { + pciinfo("Waiting to compute factorial..."); + usleep(10000); + } + + test_read = qemu_edu_read_reg32(base_addr + EDU_REG_FAC); + pciinfo("Computed factorial of %d as %d\n", test_value, test_read); + pciinfo("TEST %s\n", (test_read == 3628800) ? "PASS" : "FAIL"); +} + +/***************************************************************************** + * Name: qemu_edu_test_intx + * + * Description: + * Performs basic functional test of PCI device and MMIO using INTx + * + * Input Parameters: + * bus - An PCI device + * drv_priv - Struct containing internal state of driver + * + *****************************************************************************/ + +static void qemu_edu_test_intx(FAR struct pci_dev_s *dev, + struct qemu_edu_priv_s *drv_priv) +{ + uintptr_t base_addr = drv_priv->base_addr; + uint32_t test_value; + + pciinfo("Identification: 0x%08xu\n", + qemu_edu_read_reg32(base_addr + EDU_REG_ID)); + + /* Test Read/Write */ + + test_value = 0xdeadbeef; + pciinfo("Triggering interrupt with value 0x%08x\n", test_value); + qemu_edu_write_reg32(base_addr + EDU_REG_INT_RAISE, test_value); + sem_wait(&drv_priv->isr_done); + pciinfo("TEST %s\n", + (drv_priv->test_result == test_value) ? "PASS" : "FAIL"); + + /* Test Factorial */ + + test_value = 5; + pciinfo("Computing factorial of %d\n", test_value); + qemu_edu_write_reg32(base_addr + EDU_REG_STATUS, 0x80); + qemu_edu_write_reg32(base_addr + EDU_REG_FAC, test_value); + sem_wait(&drv_priv->isr_done); + pciinfo("TEST %s\n", (drv_priv->test_result == 120) ? "PASS" : "FAIL"); + + /* Test ISR Status Cleanup */ + + qemu_edu_write_reg32(base_addr + EDU_REG_INT_RAISE, test_value); + sem_wait(&drv_priv->isr_done); + pciinfo("TEST %s\n", + (drv_priv->test_result == test_value) ? "PASS" : "FAIL"); +} + +/***************************************************************************** + * Name: qemu_edu_test_dma + * + * Description: + * Performs dma functional test of PCI device + * + * Input Parameters: + * bus - An PCI device + * drv_priv - Struct containing internal state of driver + * + *****************************************************************************/ + +static void qemu_edu_test_dma(FAR struct pci_dev_s *dev, + struct qemu_edu_priv_s *drv_priv) +{ + uintptr_t base_addr = drv_priv->base_addr; + void *test_block; + size_t block_size = 2048; + int i; + uint32_t psrand; + uint32_t tx_checksum; + uint32_t rx_checksum; + uint32_t dev_addr = 0x40000; + + pciinfo("Identification: 0x%08xu\n", + qemu_edu_read_reg32(base_addr + EDU_REG_ID)); + + test_block = kmm_malloc(block_size); + for (i = 0; i < block_size; i++) + { + *((uint8_t *)test_block + i) = i & 0xff; + } + + tx_checksum = 0; + psrand = 0x0011223344; + for (i = 0; i < (block_size / 4); i++) + { + /* Fill the memory block with "random" data */ + + psrand ^= psrand << 13; + psrand ^= psrand >> 17; + psrand ^= psrand << 5; + *((uint32_t *)test_block + i) = psrand; + tx_checksum += psrand; + } + + pciinfo("Test block checksum 0x%08x\n", tx_checksum); + qemu_edu_write_reg64(base_addr + EDU_REG_DMA_SOURCE, (uint64_t)test_block); + qemu_edu_write_reg64(base_addr + EDU_REG_DMA_DEST, (uint64_t)dev_addr); + qemu_edu_write_reg64(base_addr + EDU_REG_DMA_COUNT, (uint64_t)block_size); + qemu_edu_write_reg32(base_addr + EDU_REG_STATUS, 0x00); + qemu_edu_write_reg64(base_addr + EDU_REG_DMA_CMD, 0x01 | 0x04); + sem_wait(&drv_priv->isr_done); + + pciinfo("DMA transfer to device complete.\n"); + + qemu_edu_write_reg64(base_addr + EDU_REG_DMA_DEST, (uint64_t)test_block); + qemu_edu_write_reg64(base_addr + EDU_REG_DMA_SOURCE, (uint64_t)dev_addr); + qemu_edu_write_reg64(base_addr + EDU_REG_DMA_COUNT, (uint64_t)block_size); + qemu_edu_write_reg32(base_addr + EDU_REG_STATUS, 0x00); + qemu_edu_write_reg64(base_addr + EDU_REG_DMA_CMD, 0x01 | 0x02 | 0x04); + sem_wait(&drv_priv->isr_done); + + pciinfo("DMA transfer from device complete.\n"); + rx_checksum = 0; + for (i = 0; i < block_size / 4; i++) + { + rx_checksum += *((uint32_t *)test_block + i); + } + + pciinfo("Received block checksum 0x%08x\n", rx_checksum); + pciinfo("TEST %s\n", (rx_checksum == tx_checksum) ? "PASS" : "FAIL"); +} + +/***************************************************************************** + * Name: qemu_edu_interrupt + * + * Description: + * EDU interrupt handler + * + *****************************************************************************/ + +static int qemu_edu_interrupt(int irq, void *context, FAR void *arg) +{ + struct qemu_edu_priv_s *drv_priv = (struct qemu_edu_priv_s *)arg; + uintptr_t base_addr = drv_priv->base_addr; + + uint32_t status = qemu_edu_read_reg32(base_addr + EDU_REG_INT_STATUS); + + qemu_edu_write_reg32(base_addr + EDU_REG_INT_ACK, ~0U); + switch (status) + { + case 0x1: /* Factorial triggered */ + drv_priv->test_result = qemu_edu_read_reg32(base_addr + EDU_REG_FAC); + pciinfo("Computed factorial: %d\n", + drv_priv->test_result); + break; + case 0x100: /* DMA triggered */ + pciinfo("DMA transfer complete\n"); + break; + default: /* Generic write */ + drv_priv->test_result = status; + pciinfo("Received value: 0x%08x\n", status); + } + + sem_post(&drv_priv->isr_done); + return OK; +} + +/***************************************************************************** + * Public Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: qemu_edu_probe + * + * Description: + * Initialize device + *****************************************************************************/ + +int qemu_edu_probe(FAR struct pci_bus_s *bus, + FAR struct pci_dev_type_s *type, uint16_t bdf) +{ + uint32_t bar; + uintptr_t bar_addr; + struct pci_dev_s dev = + { + .bus = bus, + .type = type, + .bdf = bdf, + }; + + uint8_t irq; + struct qemu_edu_priv_s drv_priv; + + pci_enable_bus_master(&dev); + pciinfo("Enabled bus mastering\n"); + pci_enable_io(&dev, PCI_SYS_RES_MEM); + pciinfo("Enabled memory resources\n"); + + if (pci_bar_valid(&dev, EDU_CONTROL_BAR_ID) != OK) + { + pcierr("Control BAR is not valid\n"); + DEBUGPANIC(); + return -EINVAL; + } + + bar_addr = pci_bar_addr(&dev, EDU_CONTROL_BAR_ID); + bar = bus->ops->pci_cfg_read(&dev, EDU_CONTROL_BAR_OFFSET, 4); + if ((bar & PCI_BAR_LAYOUT_MASK) != PCI_BAR_LAYOUT_MEM) + { + pcierr("Control bar expected to be MMIO\n"); + DEBUGPANIC(); + return -EINVAL; + } + + if (bus->ops->pci_map_bar(bar_addr, + pci_bar_size(&dev, EDU_CONTROL_BAR_ID)) != OK) + { + pcierr("Failed to map address space\n"); + DEBUGPANIC(); + return -EINVAL; + } + + pciinfo("Device Initialized\n"); + + /* Run Poll Tests */ + + qemu_edu_test_poll(&dev, bar_addr); + + /* Run IRQ Tests */ + + drv_priv.base_addr = bar_addr; + sem_init(&drv_priv.isr_done, 0, 0); + sem_setprotocol(&drv_priv.isr_done, SEM_PRIO_NONE); + + irq = IRQ0 + bus->ops->pci_cfg_read(&dev, PCI_HEADER_NORM_INT_LINE, 1); + pciinfo("Attaching IRQ %d to %p\n", irq, qemu_edu_interrupt); + irq_attach(irq, (xcpt_t)qemu_edu_interrupt, (void *)&drv_priv); + up_enable_irq(irq); + + qemu_edu_test_intx(&dev, &drv_priv); + qemu_edu_test_dma(&dev, &drv_priv); + + up_disable_irq(irq); + irq_detach(irq); + sem_destroy(&drv_priv.isr_done); + + /* Run MSI Tests */ + + /* Really should be cleaning up the mapped memory */ + + return OK; +} + +/***************************************************************************** + * Public Data + *****************************************************************************/ + +struct pci_dev_type_s pci_type_qemu_edu = +{ + .vendor = 0x1234, + .device = 0x11e8, + .class_rev = PCI_ID_ANY, + .name = "Qemu PCI EDU device", + .probe = qemu_edu_probe +}; diff --git a/drivers/virt/qemu_pci_test.c b/drivers/virt/qemu_pci_test.c index d0df753121..b0556b4d9f 100644 --- a/drivers/virt/qemu_pci_test.c +++ b/drivers/virt/qemu_pci_test.c @@ -33,30 +33,133 @@ #include #include -#include +#include #include /***************************************************************************** * Pre-processor Definitions *****************************************************************************/ +/***************************************************************************** + * Private Functions Definitions + *****************************************************************************/ + +static uint32_t mem_read(FAR const volatile void *addr, int width); + +static void mem_write(FAR const volatile void *addr, uint32_t val, int width); + /***************************************************************************** * Private Types *****************************************************************************/ struct pci_test_dev_hdr_s { - volatile uint8_t test; /* write-only, starts a given test number */ - volatile uint8_t width_type; /* read-only, type and width of access for a given test. - * 1,2,4 for byte,word or long write. - * any other value if test not supported on this BAR */ - volatile uint8_t pad0[2]; - volatile uint32_t offset; /* read-only, offset in this BAR for a given test */ - volatile uint32_t data; /* read-only, data to use for a given test */ - volatile uint32_t count; /* for debugging. number of writes detected. */ - volatile uint8_t name[]; /* for debugging. 0-terminated ASCII string. */ + uint8_t test; /* write-only, starts a given test number */ + uint8_t width; /* read-only, type and width of access for a test */ + uint8_t pad0[2]; + uint32_t offset; /* read-only, offset in this BAR for a given test */ + uint32_t data; /* read-only, data to use for a given test */ + uint32_t count; /* for debugging. number of writes detected. */ + uint8_t name[]; /* for debugging. 0-terminated ASCII string. */ }; +/* Structure the read and write helpers */ + +struct pci_test_dev_ops_s +{ + uint32_t (*read)(FAR const volatile void *addr, int width); + void (*write)(FAR const volatile void *addr, uint32_t val, int width); +}; + +/***************************************************************************** + * Private Data + *****************************************************************************/ + +static struct pci_test_dev_ops_s mem_ops = +{ + .read = mem_read, + .write = mem_write +}; + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +static uint32_t mem_read(FAR const volatile void *addr, int unused) +{ + return *(volatile uint32_t *)addr; +} + +static void mem_write(FAR const volatile void *addr, uint32_t val, int unused) +{ + *(volatile uint32_t *)addr = val; +} + +static bool qemu_pci_test_bar(FAR struct pci_test_dev_ops_s *test_ops, + FAR struct pci_test_dev_hdr_s *test_hdr, + uint16_t test_num) +{ + uint32_t count; + uint32_t data; + uint32_t offset; + uint8_t width; + const int write_limit = 8; + int write_cnt; + int i; + char testname[32]; + + pciinfo("WRITING Test# %d %p\n", test_num, &test_hdr->test); + test_ops->write(&test_hdr->test, test_num, 1); + + /* Reading of the string is a little ugly to handle the case where + * we must use the port access methods. For memory map we would + * be able to just read directly. + */ + + testname[sizeof(testname) - 1] = 0; + for (i = 0; i < sizeof(testname); i++) + { + testname[i] = (char)test_ops->read((void *)&test_hdr->name + i, 1); + if (testname[i] == 0) + break; + } + + pciinfo("Running test: %s\n", testname); + + count = test_ops->read(&test_hdr->count, 4); + pciinfo("COUNT: %04x\n", count); + if (count != 0) + return false; + + width = test_ops->read(&test_hdr->width, 1); + pciinfo("Width: %d\n", width); + + if (width == 0 || width > 4) + return false; + + data = test_ops->read(&test_hdr->data, 4); + pciinfo("Data: %04x\n", data); + + offset = test_ops->read(&test_hdr->offset, 4); + pciinfo("Offset: %04x\n", offset); + + for (write_cnt = 0; write_cnt < write_limit; write_cnt++) + { + pciinfo("Issuing WRITE to %p %x %d\n", + (void *)test_hdr + offset, + data, width); + test_ops->write((void *)test_hdr + offset, data, width); + } + + count = test_ops->read(&test_hdr->count, 4); + pciinfo("COUNT: %04x\n", count); + + if (!count) + return true; + + return (int)count == write_cnt; +} + /***************************************************************************** * Public Functions *****************************************************************************/ @@ -68,49 +171,73 @@ struct pci_test_dev_hdr_s * Initialize device *****************************************************************************/ -int qemu_pci_test_probe(FAR struct pcie_bus_s *bus, - FAR struct pcie_dev_type_s *type, uint16_t bdf) +int qemu_pci_test_probe(FAR struct pci_bus_s *bus, + FAR struct pci_dev_type_s *type, uint16_t bdf) { - uint32_t bar[2]; - struct pcie_dev_s dev = + uint8_t bar_id; + uint32_t bar; + uint64_t bar_addr; + struct pci_test_dev_hdr_s *test_hdr; + struct pci_dev_s dev = { .bus = bus, .type = type, .bdf = bdf, }; - pci_enable_device(&dev); - - for (int ii = 0; ii < 2; ii++) + struct pci_test_dev_ops_s io_ops = { - pci_get_bar(&dev, ii, bar + ii); + .read = bus->ops->pci_io_read, + .write = bus->ops->pci_io_write + }; - if ((bar[ii] & PCI_BAR_IO) != PCI_BAR_IO) + struct pci_test_dev_ops_s *test_ops; + + uint16_t test_cnt; + + pci_enable_bus_master(&dev); + pciinfo("Enabled bus mastering\n"); + pci_enable_io(&dev, PCI_SYS_RES_MEM); + pci_enable_io(&dev, PCI_SYS_RES_IOPORT); + pciinfo("Enabled i/o port and memory resources\n"); + + for (bar_id = 0; bar_id < PCI_BAR_CNT; bar_id++) + { + /* Need to query the BAR for IO vs MEM + * Also handle if the bar is 64bit address + */ + + if (pci_bar_valid(&dev, bar_id) != OK) + continue; + + bar = bus->ops->pci_cfg_read(&dev, + PCI_HEADER_NORM_BAR0 + (bar_id * 4), 4); + + bar_addr = pci_bar_addr(&dev, bar_id); + test_hdr = (struct pci_test_dev_hdr_s *)bar_addr; + + if ((bar & PCI_BAR_LAYOUT_MASK) == PCI_BAR_LAYOUT_MEM) { - pciinfo("Mapping BAR%d: %x\n", ii, bar[ii]); + test_ops = &mem_ops; - pci_map_bar(&dev, ii, 0x1000, NULL); + /* If the BAR is MMIO the it must be mapped */ - struct pci_test_dev_hdr_s *ptr = - (struct pci_test_dev_hdr_s *)(uintptr_t)bar[ii]; - - int i = 0; - while (1) - { - ptr->test = i; - - if (ptr->width_type != 1 && - ptr->width_type != 2 && - ptr->width_type != 4) - break; - - pciinfo("Test[%d] Size:%d %s\n", - i, ptr->width_type, - ptr->name); - - i++; - } + bus->ops->pci_map_bar(bar_addr, pci_bar_size(&dev, bar_id)); } + else + { + test_ops = &io_ops; + } + + for (test_cnt = 0; test_cnt < 0xffff; test_cnt++) + { + if (!qemu_pci_test_bar(test_ops, test_hdr, test_cnt)) + break; + pciinfo("Test Completed BAR [%d] TEST [%d]\n", bar_id, test_cnt); + } + + if (pci_bar_is_64(&dev, bar_id)) + bar_id++; } return OK; @@ -120,7 +247,7 @@ int qemu_pci_test_probe(FAR struct pcie_bus_s *bus, * Public Data *****************************************************************************/ -struct pcie_dev_type_s pcie_type_qemu_pci_test = +struct pci_dev_type_s pci_type_qemu_pci_test = { .vendor = 0x1b36, .device = 0x0005, diff --git a/include/debug.h b/include/debug.h index 955ddf6e2c..94b5448b32 100644 --- a/include/debug.h +++ b/include/debug.h @@ -920,19 +920,19 @@ # define ipcinfo _none #endif -#ifdef CONFIG_DEBUG_PCIE_ERROR +#ifdef CONFIG_DEBUG_PCI_ERROR # define pcierr _err #else # define pcierr _none #endif -#ifdef CONFIG_DEBUG_PCIE_WARN +#ifdef CONFIG_DEBUG_PCI_WARN # define pciwarn _warn #else # define pciwarn _none #endif -#ifdef CONFIG_DEBUG_PCIE_INFO +#ifdef CONFIG_DEBUG_PCI_INFO # define pciinfo _info #else # define pciinfo _none diff --git a/include/nuttx/pci/pci.h b/include/nuttx/pci/pci.h new file mode 100644 index 0000000000..0b420a04c0 --- /dev/null +++ b/include/nuttx/pci/pci.h @@ -0,0 +1,458 @@ +/**************************************************************************** + * include/nuttx/pci/pci.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_PCI_PCI_H +#define __INCLUDE_NUTTX_PCI_PCI_H + +#ifdef CONFIG_PCI + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* PCI config common registers */ + +#define PCI_CONFIG_VENDOR 0x00 +#define PCI_CONFIG_DEVICE 0x02 +#define PCI_CONFIG_COMMAND 0x04 +#define PCI_CONFIG_REV_ID 0x08 +#define PCI_CONFIG_PROG_IF 0x09 +#define PCI_CONFIG_SUBCLASS 0x0A +#define PCI_CONFIG_CLASS 0x0B +#define PCI_CONFIG_CACHE_LINE_SIZE 0x0C +#define PCI_CONFIG_LATENCY_TIMER 0x0D +#define PCI_CONFIG_HEADER_TYPE 0x0E +#define PCI_CONFIG_BIST 0x0F + +/* PCI config header types */ + +#define PCI_HEADER_NORMAL 0x00 +#define PCI_HEADER_BRIDGE 0x01 +#define PCI_HEADER_CARDBUS 0x02 +#define PCI_HEADER_TYPE_MASK 0x3F +#define PCI_HEADER_MASK_MULTI 0x80 + +/* PCI config registers type 0 (Normal devices) */ + +#define PCI_HEADER_NORM_BAR0 0x10 +#define PCI_HEADER_NORM_BAR1 0x14 +#define PCI_HEADER_NORM_BAR2 0x18 +#define PCI_HEADER_NORM_BAR3 0x1C +#define PCI_HEADER_NORM_BAR4 0x20 +#define PCI_HEADER_NORM_BAR5 0x24 +#define PCI_HEADER_NORM_CB_CIS 0x28 +#define PCI_HEADER_NORM_SUB_VID 0x2C +#define PCI_HEADER_NORM_SUB_ID 0x2E +#define PCI_HEADER_NORM_EXP_ROM 0x30 +#define PCI_HEADER_NORM_CAP 0x34 +#define PCI_HEADER_NORM_INT_LINE 0x3C +#define PCI_HEADER_NORM_INT_PIN 0x3D +#define PCI_HEADER_NORM_MIN_GRANT 0x3E +#define PCI_HEADER_NORM_MAX_LAT 0x3E + +/* PCI config registers type 1 (PCI-PCI bridge) */ + +#define PCI_CONFIG_SEC_BUS 0x19 + +/* PCI config registers type 2 (CardBus) */ + +/* PCI Base Class Codes */ + +#define PCI_CLASS_BASE_UNCLASSIFIED 0x00 +#define PCI_CLASS_BASE_MASS_STORAGE_CTRL 0x01 +#define PCI_CLASS_BASE_NETWORK_CTRL 0x02 +#define PCI_CLASS_BASE_DISPLAY_CTRL 0x03 +#define PCI_CLASS_BASE_MULTIMEDIA_CTRL 0x04 +#define PCI_CLASS_BASE_MEM_CTRL 0x05 +#define PCI_CLASS_BASE_BRG_DEV 0x06 +#define PCI_CLASS_BASE_SMPL_COM_CTRL 0x07 +#define PCI_CLASS_BASE_BSP 0x08 +#define PCI_CLASS_BASE_INPUT_DEV_CTRL 0x09 +#define PCI_CLASS_BASE_DOCK_STN 0x0A +#define PCI_CLASS_BASE_PROCESSOR 0x0B +#define PCI_CLASS_BASE_SBC 0x0C +#define PCI_CLASS_BASE_WIRELESS_CTRL 0x0D +#define PCI_CLASS_BASE_INTL_CTRL 0x0E +#define PCI_CLASS_BASE_SAT_COM_CTRL 0x0F +#define PCI_CLASS_BASE_ENCRYPT_CTRL 0x10 +#define PCI_CLASS_BASE_SPC 0x11 +#define PCI_CLASS_BASE_PROC_ACCEL 0x12 +#define PCI_CLASS_BASE_NON_ES_INST 0x13 + +/* Reserved 0x14-0x3F */ + +#define PCI_CLASS_BASE_CO_PROC 0x40 + +/* Reserved 0x41-0xFE */ + +#define PCI_CLASS_BASE_UNASSIGNED 0xFF + +/* PCI Sub Class Codes (most missing) */ + +/* Bridge Class */ + +#define PCI_CLASS_SUB_HOST_BRG 0x00 +#define PCI_CLASS_SUB_ISA_BRG 0x01 +#define PCI_CLASS_SUB_EISA_BRG 0x02 +#define PCI_CLASS_SUB_MCA_BRG 0x03 +#define PCI_CLASS_SUB_PCI_BRG 0x04 +#define PCI_CLASS_SUB_PCMCIA_BRG 0x05 +#define PCI_CLASS_SUB_NUBUS_BRG 0x06 +#define PCI_CLASS_SUB_CARDBUS_BRG 0x07 +#define PCI_CLASS_SUB_RACEWAY_BRG 0x08 +#define PCI_CLASS_SUB_PCI_TRNSP_BRG 0x09 +#define PCI_CLASS_SUB_INFINI_BRG 0x0A +#define PCI_CLASS_SUB_NUBUS_BRG 0x80 + +#define PCI_ID_ANY 0xffff + +/* PCI Command Register Bitmasks */ + +#define PCI_CMD_IO_SPACE 0x0001 +#define PCI_CMD_MEM_SPACE 0x0002 +#define PCI_CMD_BUS_MSTR 0x0004 +#define PCI_CMD_SPECIAL_CYC 0x0008 +#define PCI_CMD_MEM_INV 0x0030 +#define PCI_CMD_VGA_PLT 0x0040 +#define PCI_CMD_PAR_ERR 0x0080 +#define PCI_CMD_SERR 0x0100 +#define PCI_CMD_FST_B2B 0x0200 +#define PCI_CMD_INT 0x0400 + +/* PCI BAR Bitmasks */ + +#define PCI_BAR_LAYOUT_MASK 0x00000001 +#define PCI_BAR_TYPE_MASK 0x00000006 +#define PCI_BAR_MEM_PF_MASK 0x00000008 +#define PCI_BAR_MEM_BASE_MASK 0xfffffff0 +#define PCI_BAR_IO_BASE_MASK 0xfffffffc + +/* PCI BAR OFFSETS */ + +#define PCI_BAR_LAYOUT_OFFSET 0 +#define PCI_BAR_TYPE_OFFSET 1 +#define PCI_BAR_MEM_PF_OFFSET 3 +#define PCI_BAR_MEM_BASE_OFFSET 4 +#define PCI_BAR_IO_BASE_OFFSET 2 + +/* PCI BAR */ + +#define PCI_BAR_CNT 6 +#define PCI_BAR_INVALID 0 +#define PCI_BAR_LAYOUT_MEM 0 +#define PCI_BAR_LAYOUT_IO 1 +#define PCI_BAR_TYPE_32 0x00 +#define PCI_BAR_TYPE_16 0x01 /* This mode is not used */ +#define PCI_BAR_TYPE_64 0x02 + +/* PCI CAP */ + +#define PCI_CAP_ID_PM 0x01 /* Power Management */ +#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics */ +#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ +#define PCI_CAP_ID_SLOT 0x04 /* Slot ID */ +#define PCI_CAP_ID_MSI 0x05 /* MSI */ +#define PCI_CAP_ID_CHP 0x06 /* CompactPCI Hot-Swap */ +#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor */ +#define PCI_CAP_ID_DBG 0x0A /* Debug */ +#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ +#define PCI_CAP_ID_HOT 0x0C /* Hot-Plug Controller */ +#define PCI_CAP_ID_BRG_VID 0x0D /* Bridge Vendor/Device ID */ +#define PCI_CAP_ID_AGP_BRG 0x0E /* AGP PCI-PCI Bridge */ +#define PCI_CAP_ID_SEC_DEV 0x0F /* Secure Device */ +#define PCI_CAP_ID_PCIE 0x10 /* PCIe */ +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define PCI_CAP_ID_SATA 0x12 /* SATA */ +#define PCI_CAP_ID_ADVF 0x13 /* Advanced Features */ + +#define PCI_CAP_ID_END PCI_CAP_ID_ADVF + +/* Resource types used by PCI devices */ + +#define PCI_SYS_RES_IOPORT 0x00 +#define PCI_SYS_RES_MEM 0x01 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* The PCI driver interface */ + +struct pci_bus_s; +struct pci_dev_type_s; +struct pci_dev_s; + +/* Bus related operations */ + +struct pci_bus_ops_s +{ + CODE void (*pci_cfg_write)(FAR struct pci_dev_s *dev, int reg, + uint32_t val, int width); + + CODE uint32_t (*pci_cfg_read)(FAR struct pci_dev_s *dev, int reg, + int width); + + CODE int (*pci_map_bar)(uint64_t addr, uint64_t len); + + CODE uint32_t (*pci_io_read)(FAR const volatile void *addr, int width); + + CODE void (*pci_io_write)(FAR const volatile void *addr, uint32_t val, + int width); +}; + +/* PCI bus private data. */ + +struct pci_bus_s +{ + FAR const struct pci_bus_ops_s *ops; /* operations */ +}; + +/* PCI device type, defines by vendor ID and device ID */ + +struct pci_dev_type_s +{ + uint16_t vendor; /* Device vendor ID */ + uint16_t device; /* Device ID */ + uint32_t class_rev; /* Device reversion */ + const char *name; /* Human readable name */ + + /* Call back function when a device is probed */ + + CODE int (*probe)(FAR struct pci_bus_s *bus, + FAR struct pci_dev_type_s *type, uint16_t bdf); +}; + +/* PCI device private data. */ + +struct pci_dev_s +{ + FAR struct pci_bus_s *bus; + FAR struct pci_dev_type_s *type; + uint32_t bdf; +}; + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: pci_initialize + * + * Description: + * Initialize the PCI bus and enumerate the devices with give devices + * type array + * + * Input Parameters: + * bus - An PCI bus + * types - A array of PCI device types + * + * Returned Value: + * OK if the driver was successfully register; A negated errno value is + * returned on any failure. + * + ****************************************************************************/ + +int pci_initialize(FAR struct pci_bus_s *bus); + +/**************************************************************************** + * Name: pci_enable_io + * + * Description: + * Enable MMIO or IOPORT + * + * Input Parameters: + * dev - device + * space - which resource is being enabled + * PCI_SYS_RES_IOPORT for io port address decoding or + * PCI_RES_MEM for memory + * + * Return value: + * -EINVAL: error + * OK: OK + * + ****************************************************************************/ + +int pci_enable_io(FAR struct pci_dev_s *dev, int res); + +/**************************************************************************** + * Name: pci_disable_io + * + * Description: + * Enable MMIO or IOPORT + * + * Input Parameters: + * dev - device + * space - which resource is being disabled + * PCI_SYS_RES_IOPORT for io port address decoding or + * PCI_SYS_RES_MEM for memory + * + * Return value: + * -EINVAL: error + * OK: OK + * + ****************************************************************************/ + +int pci_disable_io(FAR struct pci_dev_s *dev, int res); + +/**************************************************************************** + * Name: pci_enable_bus_master + * + * Description: + * Enable bus mastering for device so it can perform PCI accesses + * + * Input Parameters: + * dev - device + * + * Return value: + * -EINVAL: error + * OK: OK + * + ****************************************************************************/ + +int pci_enable_bus_master(FAR struct pci_dev_s *dev); + +/**************************************************************************** + * Name: pci_disable_bus_master + * + * Description: + * Disable bus mastering for device + * + * Input Parameters: + * dev - device + * + * Return value: + * -EINVAL: error + * OK: OK + * + ****************************************************************************/ + +int pci_disable_bus_master(FAR struct pci_dev_s *dev); + +/**************************************************************************** + * Name: pci_bar_valid + * + * Description: + * Determine in if the address in the BAR is valid + * + * Input Parameters: + * dev - device + * bar_id - bar number + * + * Return value: + * -EINVAL: error + * OK: OK + * + ****************************************************************************/ + +int pci_bar_valid(FAR struct pci_dev_s *dev, uint8_t bar_id); + +/**************************************************************************** + * Name: pci_bar_is_64 + * + * Description: + * Determine in if the bar address is 64 bit. If it is the address includes + * the address in the next bar location. + * + * Input Parameters: + * dev - device + * bar_id - bar number + * + * Return value: + * true: 64bit address + * + ****************************************************************************/ + +bool pci_bar_is_64(FAR struct pci_dev_s *dev, uint8_t bar_id); + +/**************************************************************************** + * Name: pci_bar_size + * + * Description: + * Determine the size of the address space required by the BAR + * + * Input Parameters: + * dev - device + * bar_id - bar number + * + * Return value: + * Size of address space + * + ****************************************************************************/ + +uint64_t pci_bar_size(FAR struct pci_dev_s *dev, uint8_t bar_id); + +/**************************************************************************** + * Name: pci_bar_addr + * + * Description: + * Determine the size of the address space required by the BAR + * + * Input Parameters: + * dev - device + * bar_id - bar number + * + * Return value: + * full bar address + * + ****************************************************************************/ + +uint64_t pci_bar_addr(FAR struct pci_dev_s *dev, uint8_t bar_id); + +/**************************************************************************** + * Name: pci_dev_dump + * + * Description: + * Dump the configuration information for the device + * + * Input Parameters: + * dev - device + * + ****************************************************************************/ + +void pci_dev_dump(FAR struct pci_dev_s *dev); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif +#endif /* __INCLUDE_NUTTX_PCI_PCI_H */ diff --git a/include/nuttx/pcie/pcie.h b/include/nuttx/pcie/pcie.h deleted file mode 100644 index fffc791a2d..0000000000 --- a/include/nuttx/pcie/pcie.h +++ /dev/null @@ -1,352 +0,0 @@ -/**************************************************************************** - * include/nuttx/pcie/pcie.h - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -#ifndef __INCLUDE_NUTTX_PCIE_PCIE_H -#define __INCLUDE_NUTTX_PCIE_PCIE_H - -#ifdef CONFIG_PCIE - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define PCI_CFG_VENDOR_ID 0x000 -#define PCI_CFG_DEVICE_ID 0x002 -#define PCI_CFG_COMMAND 0x004 -# define PCI_CMD_IO (1 << 0) -# define PCI_CMD_MEM (1 << 1) -# define PCI_CMD_MASTER (1 << 2) -# define PCI_CMD_INTX_OFF (1 << 10) -#define PCI_CFG_STATUS 0x006 -# define PCI_STS_INT (1 << 3) -# define PCI_STS_CAPS (1 << 4) -#define PCI_CFG_REVERSION 0x008 -#define PCI_CFG_BAR 0x010 -# define PCI_BAR_IO 0x1 -# define PCI_BAR_1M 0x2 -# define PCI_BAR_64BIT 0x4 -#define PCI_CFG_CAP_PTR 0x034 - -#define PCI_ID_ANY 0xffff -#define PCI_DEV_CLASS_OTHER 0xff - -#define PCI_CAP_PM 0x01 - -#define PCI_CAP_MSI 0x05 -# define PCI_MSI_MCR 0x02 -# define PCI_MSI_MCR_SIZE 2 -# define PCI_MSI_MCR_EN (1 << 0) -# define PCI_MSI_MCR_64 (1 << 7) -# define PCI_MSI_MAR 0x04 -# define PCI_MSI_MAR_SIZE 4 -# define PCI_MSI_MDR 0x08 -# define PCI_MSI_MDR_SIZE 2 -# define PCI_MSI_MAR64_HI 0x08 -# define PCI_MSI_MAR64_HI_SIZE 4 -# define PCI_MSI_MDR64 0x0c -# define PCI_MSI_MDR64_SIZE 2 -# define PCI_MSI_APIC_ID_OFFSET 0xc - -#define PCI_CAP_MSIX 0x11 -# define PCI_MSIX_MCR 0x02 -# define PCI_MSIX_MCR_SIZE 2 -# define PCI_MSIX_MCR_EN (1 << 15) -# define PCI_MSIX_MCR_FMASK 0x4000 -# define PCI_MSIX_MCR_TBL_MASK 0x03ff -# define PCI_MSIX_TBL 0x04 -# define PCI_MSIX_TBL_SIZE 4 -# define PCI_MSIX_PBA 0x08 -# define PCI_MSIX_PBA_SIZE 4 -# define PCI_MSIX_BIR_MASK 0x07 -# define PCI_MSIX_TBL_ENTRY_SIZE 0x10 -# define PCI_MSIX_TBL_LO_ADDR 0x0 -# define PCI_MSIX_TBL_HI_ADDR 0x4 -# define PCI_MSIX_TBL_MSG_DATA 0x8 -# define PCI_MSIX_TBL_VEC_CTL 0xc -# define PCI_MSIX_APIC_ID_OFFSET 0xc - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/* The PCIE driver interface */ - -struct pcie_bus_s; -struct pcie_dev_type_s; -struct pcie_dev_s; - -/* Bus related operations */ - -struct pcie_bus_ops_s -{ - CODE int (*pcie_enumerate)(FAR struct pcie_bus_s *bus, - FAR struct pcie_dev_type_s **types); - - CODE int (*pci_cfg_write)(FAR struct pcie_dev_s *dev, uintptr_t addr, - FAR const void *buffer, unsigned int size); - - CODE int (*pci_cfg_read)(FAR struct pcie_dev_s *dev, uintptr_t addr, - FAR void *buffer, unsigned int size); - - CODE int (*pci_map_bar)(FAR struct pcie_dev_s *dev, uint32_t addr, - unsigned long length); - - CODE int (*pci_map_bar64)(FAR struct pcie_dev_s *dev, uint64_t addr, - unsigned long length); - - CODE int (*pci_msi_register)(FAR struct pcie_dev_s *dev, - uint16_t vector); - - CODE int (*pci_msix_register)(FAR struct pcie_dev_s *dev, - uint32_t vector, uint32_t index); -}; - -/* PCIE bus private data. */ - -struct pcie_bus_s -{ - FAR const struct pcie_bus_ops_s *ops; /* operations */ -}; - -/* PCIE device type, defines by vendor ID and device ID */ - -struct pcie_dev_type_s -{ - uint16_t vendor; /* Device vendor ID */ - uint16_t device; /* Device ID */ - uint32_t class_rev; /* Device reversion */ - const char *name; /* Human readable name */ - - /* Call back function when a device is probed */ - - CODE int (*probe)(FAR struct pcie_bus_s *bus, - FAR struct pcie_dev_type_s *type, uint16_t bdf); -}; - -/* PCIE device private data. */ - -struct pcie_dev_s -{ - FAR struct pcie_bus_s *bus; - FAR struct pcie_dev_type_s *type; - uint16_t bdf; -}; - -/**************************************************************************** - * Public Functions Prototypes - ****************************************************************************/ - -#undef EXTERN -#if defined(__cplusplus) -#define EXTERN extern "C" -extern "C" -{ -#else -#define EXTERN extern -#endif - -/**************************************************************************** - * Name: pcie_initialize - * - * Description: - * Initialize the PCI-E bus and enumerate the devices with give devices - * type array - * - * Input Parameters: - * bus - An PCIE bus - * types - A array of PCIE device types - * num - Number of device types - * - * Returned Value: - * OK if the driver was successfully register; A negated errno value is - * returned on any failure. - * - ****************************************************************************/ - -int pcie_initialize(FAR struct pcie_bus_s *bus); - -/**************************************************************************** - * Name: pci_enable_device - * - * Description: - * Enable device with MMIO - * - * Input Parameters: - * dev - device - * - * Return value: - * -EINVAL: error - * OK: OK - * - ****************************************************************************/ - -int pci_enable_device(FAR struct pcie_dev_s *dev); - -/**************************************************************************** - * Name: pci_find_cap - * - * Description: - * Search through the PCI-e device capability list to find given capability. - * - * Input Parameters: - * dev - Device - * cap - Bitmask of capability - * - * Returned Value: - * -1: Capability not supported - * other: the offset in PCI configuration space to the capability structure - * - ****************************************************************************/ - -int pci_find_cap(FAR struct pcie_dev_s *dev, uint16_t cap); - -/**************************************************************************** - * Name: pci_map_bar - * - * Description: - * Map address in a 32 bits bar in the flat memory address space - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * length - Map length, multiple of PAGE_SIZE - * ret - Bar Contentif not NULL - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_map_bar(FAR struct pcie_dev_s *dev, uint32_t bar, - unsigned long length, uint32_t *ret); - -/**************************************************************************** - * Name: pci_map_bar64 - * - * Description: - * Map address in a 64 bits bar in the flat memory address space - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * length - Map length, multiple of PAGE_SIZE - * ret - Bar Content if not NULL - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_map_bar64(FAR struct pcie_dev_s *dev, uint32_t bar, - unsigned long length, uint64_t *ret); - -/**************************************************************************** - * Name: pci_get_bar - * - * Description: - * Get a 32 bits bar - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * ret - Bar Content - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_get_bar(FAR struct pcie_dev_s *dev, uint32_t bar, - uint32_t *ret); - -/**************************************************************************** - * Name: pci_get_bar64 - * - * Description: - * Get a 64 bits bar - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * ret - Bar Content - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_get_bar64(FAR struct pcie_dev_s *dev, uint32_t bar, - uint64_t *ret); - -/**************************************************************************** - * Name: pci_set_bar - * - * Description: - * Set a 32 bits bar - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * val - Bar Content - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_set_bar(FAR struct pcie_dev_s *dev, uint32_t bar, - uint32_t val); - -/**************************************************************************** - * Name: pci_set_bar64 - * - * Description: - * Set a 64 bits bar - * - * Input Parameters: - * dev - Device private data - * bar - Bar number - * val - Bar Content - * - * Returned Value: - * 0: success, <0: A negated errno - * - ****************************************************************************/ - -int pci_set_bar64(FAR struct pcie_dev_s *dev, uint32_t bar, - uint64_t val); - -#undef EXTERN -#if defined(__cplusplus) -} -#endif -#endif -#endif /* __INCLUDE_NUTTX_I2C_I2C_MASTER_H */ diff --git a/include/nuttx/virt/qemu_pci.h b/include/nuttx/virt/qemu_pci.h index f8e38f9241..3c3379ed00 100644 --- a/include/nuttx/virt/qemu_pci.h +++ b/include/nuttx/virt/qemu_pci.h @@ -42,9 +42,13 @@ extern "C" #endif #ifdef CONFIG_VIRT_QEMU_PCI_TEST -extern struct pcie_dev_type_s pcie_type_qemu_pci_test; +extern struct pci_dev_type_s pci_type_qemu_pci_test; #endif /* CONFIG_VIRT_QEMU_PCI_TEST */ +#ifdef CONFIG_VIRT_QEMU_EDU +extern struct pci_dev_type_s pci_type_qemu_edu; +#endif /* CONFIG_VIRT_QEMU_EDU */ + #undef EXTERN #ifdef __cplusplus }