diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 19c948ebd4..86d9d34714 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -18,4 +18,11 @@ config PCI_ASSIGN_ALL_BUSES ---help--- Assign resources to all buses. This is required for some platforms that have multiple PCI buses. -endif + +config PCI_QEMU_TEST + bool "Driver for QEMU PCI test device" + default n + ---help--- + Driver for QEMU PCI test device + +endif # PCI diff --git a/drivers/pci/Make.defs b/drivers/pci/Make.defs index d3751ce0c5..46851a4ef8 100644 --- a/drivers/pci/Make.defs +++ b/drivers/pci/Make.defs @@ -19,12 +19,15 @@ ############################################################################ ifeq ($(CONFIG_PCI),y) +CSRCS += pci.c pci_ecam.c pci_drivers.c -CSRCS += pci.c pci_ecam.c +ifeq ($(CONFIG_PCI_QEMU_TEST),y) +CSRCS += pci_qemu_test.c +endif # Include PCI device driver build support DEPPATH += --dep-path pci VPATH += :pci CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)drivers$(DELIM)pci -endif +endif # CONFIG_PCI diff --git a/drivers/pci/pci_drivers.c b/drivers/pci/pci_drivers.c new file mode 100644 index 0000000000..6946b00271 --- /dev/null +++ b/drivers/pci/pci_drivers.c @@ -0,0 +1,58 @@ +/**************************************************************************** + * drivers/pci/pci_drivers.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 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pci_register_drivers + * + * Description: + * Register all the pci drivers to pci bus + * + ****************************************************************************/ + +int pci_register_drivers(void) +{ + int ret; + + /* Initialization pci qemu test driver */ + +#ifdef CONFIG_PCI_QEMU_TEST + ret = pci_register_qemu_test_driver(); + if (ret < 0) + { + pcierr("pci_register_qemu_test_driver failed, ret=%d\n", ret); + } +#endif + + UNUSED(ret); + return ret; +} diff --git a/drivers/pci/pci_qemu_test.c b/drivers/pci/pci_qemu_test.c new file mode 100644 index 0000000000..e2ce0972a3 --- /dev/null +++ b/drivers/pci/pci_qemu_test.c @@ -0,0 +1,350 @@ +/**************************************************************************** + * drivers/pci/pci_qemu_test.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 + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct pci_qemu_test_hdr_s +{ + 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_qemu_test_ops_s +{ + CODE uint32_t (*read)(FAR struct pci_bus_s *bus, FAR void *addr, int size); + CODE int (*write)(FAR struct pci_bus_s *bus, FAR void *addr, uint32_t val, + int size); +}; + +/**************************************************************************** + * Private Functions Definitions + ****************************************************************************/ + +static uint32_t pci_qemu_test_read_mem(FAR struct pci_bus_s *bus, + FAR void *addr, int size); +static int pci_qemu_test_write_mem(FAR struct pci_bus_s *bus, FAR void *addr, + uint32_t val, int size); +static uint32_t pci_qemu_test_read_io(FAR struct pci_bus_s *bus, + FAR void *addr, int size); +static int pci_qemu_test_write_io(FAR struct pci_bus_s *bus, FAR void *addr, + uint32_t val, int size); +static int pci_qemu_test_probe(FAR struct pci_device_s *dev); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct pci_qemu_test_ops_s g_pci_qemu_test_mem_ops = +{ + pci_qemu_test_read_mem, /* read */ + pci_qemu_test_write_mem /* write */ +}; + +static const struct pci_qemu_test_ops_s g_pci_qemu_test_io_ops = +{ + pci_qemu_test_read_io, /* read */ + pci_qemu_test_write_io /* write */ +}; + +static const struct pci_device_id_s g_pci_qemu_test_id_table[] = +{ + { PCI_DEVICE(0x1b36, 0x0005), }, + { } +}; + +static struct pci_driver_s g_pci_qemu_test_drv = +{ + .id_table = g_pci_qemu_test_id_table, + .probe = pci_qemu_test_probe, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pci_qemu_test_read_mem + * + * Description: + * This function is used to read mem register. + * + ****************************************************************************/ + +static uint32_t pci_qemu_test_read_mem(FAR struct pci_bus_s *bus, + FAR void *addr, int size) +{ + if (size == 1) + { + return *(FAR volatile uint8_t *)addr; + } + else if (size == 2) + { + return *(FAR volatile uint16_t *)addr; + } + else if (size == 4) + { + return *(FAR volatile uint32_t *)addr; + } + + DEBUGPANIC(); + return 0; +} + +/**************************************************************************** + * Name: pci_qemu_test_write_mem + * + * Description: + * This function is used to write a value to mem register. + * + ****************************************************************************/ + +static int pci_qemu_test_write_mem(FAR struct pci_bus_s *bus, FAR void *addr, + uint32_t val, int size) +{ + if (size == 1) + { + *(FAR volatile uint8_t *)addr = (uint8_t)val; + } + else if (size == 2) + { + *(FAR volatile uint16_t *)addr = (uint16_t)val; + } + else if (size == 4) + { + *(FAR volatile uint32_t *)addr = (uint32_t)val; + } + else + { + return -EINVAL; + } + + return 0; +} + +/**************************************************************************** + * Name: pci_qemu_test_read_io + ****************************************************************************/ + +static uint32_t pci_qemu_test_read_io(FAR struct pci_bus_s *bus, + FAR void *addr, int size) +{ + uint32_t val; + int ret; + + ret = bus->ctrl->ops->read_io(bus, (uintptr_t)addr, size, &val); + if (ret < 0) + { + pcierr("Read io failed, ret=%d\n", ret); + return 0; + } + + return val; +} + +/**************************************************************************** + * Name: pci_qemu_test_write_io + ****************************************************************************/ + +static int pci_qemu_test_write_io(FAR struct pci_bus_s *bus, FAR void *addr, + uint32_t val, int size) +{ + return bus->ctrl->ops->write_io(bus, (uintptr_t)addr, size, val); +} + +/**************************************************************************** + * Name: pci_qemu_test_bar + * + * Description: + * The pci bar test demo in the qemu environment + * + ****************************************************************************/ + +static bool pci_qemu_test_bar(FAR struct pci_device_s *dev, + FAR const struct pci_qemu_test_ops_s *ops, + FAR struct pci_qemu_test_hdr_s *hdr, + uint8_t num) +{ + const uint32_t write_limit = 8; + uint32_t write_cnt; + uint32_t offset; + uint32_t count; + uint32_t data; + uint8_t width; + char name[32]; + int i; + + pciinfo("WRITING Test# %u %p\n", num, &hdr->test); + ops->write(dev->bus, &hdr->test, num, sizeof(num)); + + /* 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. + */ + + name[sizeof(name) - 1] = 0; + for (i = 0; i < sizeof(name); i++) + { + name[i] = (char)ops->read(dev->bus, (FAR char *)&hdr->name + i, 1); + if (name[i] == 0) + { + break; + } + } + + pciinfo("Running test: %s\n", name); + + count = ops->read(dev->bus, &hdr->count, sizeof(count)); + pciinfo("Start Count: %04" PRIu32 "\n", count); + + if (count != 0) + { + return false; + } + + width = ops->read(dev->bus, &hdr->width, sizeof(width)); + pciinfo("Width: %d\n", width); + + if (width == 0 || width > 4) + { + return false; + } + + data = ops->read(dev->bus, &hdr->data, sizeof(data)); + offset = ops->read(dev->bus, &hdr->offset, sizeof(offset)); + pciinfo("Data: 0x%04" PRIx32 " Offset: 0x%04" PRIx32 "\n", data, offset); + + for (write_cnt = 0; write_cnt < write_limit; write_cnt++) + { + pciinfo("[%" PRIu32 "]Issuing WRITE to %p Data: 0x%04" PRIx32 + " Width: %u\n", + write_cnt, (FAR char *)hdr + offset, data, width); + ops->write(dev->bus, (FAR char *)hdr + offset, data, width); + } + + count = ops->read(dev->bus, &hdr->count, sizeof(count)); + pciinfo("End Count: %04" PRIu32 "\n", count); + + if (count == 0) + { + return true; + } + + return count == write_cnt; +} + +/**************************************************************************** + * Name: pci_qemu_test_probe + * + * Description: + * Initialize device + * + ****************************************************************************/ + +static int pci_qemu_test_probe(FAR struct pci_device_s *dev) +{ + FAR const struct pci_qemu_test_ops_s *ops; + FAR struct pci_qemu_test_hdr_s *hdr; + unsigned long flags; + uint8_t test_cnt; + int bar; + int ret; + + pciinfo("Enter pci test probe.\n"); + + ret = pci_enable_device(dev); + if (ret < 0) + { + pcierr("Enable device failed, ret=%d\n", ret); + return ret; + } + + pci_set_master(dev); + + for (bar = 0; bar < PCI_NUM_RESOURCES; bar++) + { + hdr = (FAR struct pci_qemu_test_hdr_s *)pci_map_bar(dev, bar); + if (hdr == NULL) + { + continue; + } + + flags = pci_resource_flags(dev, bar); + if ((flags & PCI_RESOURCE_MEM) == PCI_RESOURCE_MEM) + { + ops = &g_pci_qemu_test_mem_ops; + } + else if ((flags & PCI_RESOURCE_IO) == PCI_RESOURCE_IO) + { + ops = &g_pci_qemu_test_io_ops; + } + + for (test_cnt = 0; test_cnt < 0xff; test_cnt++) + { + if (!pci_qemu_test_bar(dev, ops, hdr, test_cnt)) + { + break; + } + } + } + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pci_register_qemu_test_driver + * + * Description: + * Register a pci driver + * + ****************************************************************************/ + +int pci_register_qemu_test_driver(void) +{ + return pci_register_driver(&g_pci_qemu_test_drv); +} diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig index 6eee0ff10d..5eea590508 100644 --- a/drivers/virt/Kconfig +++ b/drivers/virt/Kconfig @@ -12,13 +12,6 @@ menuconfig VIRT if VIRT -config VIRT_QEMU_PCI_TEST - bool "Driver for QEMU PCI test device" - default n - select PCI - ---help--- - Driver for QEMU PCI test device - config VIRT_QEMU_EDU bool "Driver for QEMU EDU test device" default n diff --git a/drivers/virt/Make.defs b/drivers/virt/Make.defs index 856a9db7cb..6785f7f44d 100644 --- a/drivers/virt/Make.defs +++ b/drivers/virt/Make.defs @@ -18,10 +18,6 @@ # ############################################################################ -ifeq ($(CONFIG_VIRT_QEMU_PCI_TEST),y) -CSRCS += qemu_pci_test.c -endif - ifeq ($(CONFIG_VIRT_QEMU_EDU),y) CSRCS += qemu_edu.c endif diff --git a/drivers/virt/qemu_pci_test.c b/drivers/virt/qemu_pci_test.c deleted file mode 100644 index 9ab30569b4..0000000000 --- a/drivers/virt/qemu_pci_test.c +++ /dev/null @@ -1,274 +0,0 @@ -/***************************************************************************** - * drivers/virt/qemu_pci_test.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 - -/***************************************************************************** - * 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); - -static int qemu_pci_test_probe(FAR struct pci_bus_s *bus, - FAR const struct pci_dev_type_s *type, - uint16_t bdf); - -/***************************************************************************** - * Public Data - *****************************************************************************/ - -const struct pci_dev_type_s g_pci_type_qemu_pci_test = -{ - .vendor = 0x1b36, - .device = 0x0005, - .class_rev = PCI_ID_ANY, - .name = "Qemu PCI test device", - .probe = qemu_pci_test_probe -}; - -/***************************************************************************** - * Private Types - *****************************************************************************/ - -struct pci_test_dev_hdr_s -{ - 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 g_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) -{ - const int write_limit = 8; - uint32_t count; - uint32_t data; - uint32_t offset; - uint8_t width; - 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; -} - -/***************************************************************************** - * Name: qemu_pci_test_probe - * - * Description: - * Initialize device - * - *****************************************************************************/ - -static int qemu_pci_test_probe(FAR struct pci_bus_s *bus, - FAR const struct pci_dev_type_s *type, - uint16_t bdf) -{ - struct pci_dev_s dev; - struct pci_test_dev_ops_s io_ops; - struct pci_test_dev_ops_s *test_ops; - struct pci_test_dev_hdr_s *test_hdr; - uint8_t bar_id; - uint32_t bar; - uint64_t bar_addr; - uint16_t test_cnt; - - /* Get dev */ - - dev.bus = bus; - dev.type = type; - dev.bdf = bdf; - - /* Get io ops */ - - io_ops.read = bus->ops->pci_io_read; - io_ops.write = bus->ops->pci_io_write; - - 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) - { - test_ops = &g_mem_ops; - - /* If the BAR is MMIO the it must be mapped */ - - 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; -} diff --git a/include/nuttx/virt/qemu_pci.h b/include/nuttx/pci/pci_qemu_test.h similarity index 76% rename from include/nuttx/virt/qemu_pci.h rename to include/nuttx/pci/pci_qemu_test.h index 6d5568d463..83ea97f98d 100644 --- a/include/nuttx/virt/qemu_pci.h +++ b/include/nuttx/pci/pci_qemu_test.h @@ -1,5 +1,5 @@ /**************************************************************************** - * include/nuttx/virt/qemu_pci.h + * include/nuttx/pci/pci_qemu_test.h * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -18,8 +18,8 @@ * ****************************************************************************/ -#ifndef __INCLUDE_NUTTX_VIRT_QEMU_PCI_H -#define __INCLUDE_NUTTX_VIRT_QEMU_PCI_H +#ifndef __INCLUDE_NUTTX_PCI_PCI_QEMU_TEST_H +#define __INCLUDE_NUTTX_PCI_PCI_QEMU_TEST_H /**************************************************************************** * Included Files @@ -27,8 +27,6 @@ #include -#include - /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -41,8 +39,16 @@ extern "C" #define EXTERN extern #endif -#ifdef CONFIG_VIRT_QEMU_PCI_TEST -extern const struct pci_dev_type_s g_pci_type_qemu_pci_test; +/**************************************************************************** + * Name: pci_register_qemu_test_driver + * + * Description: + * register a pci driver + * + ****************************************************************************/ + +#ifdef CONFIG_PCI_QEMU_TEST +int pci_register_qemu_test_driver(void); #endif #ifdef CONFIG_VIRT_QEMU_EDU @@ -54,4 +60,4 @@ extern const struct pci_dev_type_s g_pci_type_qemu_edu; } #endif -#endif /* __INCLUDE_NUTTX_VIRT_QEMU_PCI_H */ +#endif /* __INCLUDE_NUTTX_PCI_PCI_QEMU_TEST_H */