From 57d736b1498f7e75b1f821a73dcb52bac3085eeb Mon Sep 17 00:00:00 2001 From: lipengfei28 Date: Tue, 9 Jul 2024 20:26:23 +0800 Subject: [PATCH] add epf test drv Signed-off-by: lipengfei28 --- drivers/pci/CMakeLists.txt | 4 + drivers/pci/Kconfig | 5 + drivers/pci/Make.defs | 4 + drivers/pci/pci_drivers.c | 8 + drivers/pci/pci_drivers.h | 12 + drivers/pci/pci_epf_test.c | 747 ++++++++++++++++++++++++++++++++ include/nuttx/pci/pci_ep_test.h | 45 ++ 7 files changed, 825 insertions(+) create mode 100644 drivers/pci/pci_epf_test.c create mode 100644 include/nuttx/pci/pci_ep_test.h diff --git a/drivers/pci/CMakeLists.txt b/drivers/pci/CMakeLists.txt index 7a73fc07a4..9ea165a56e 100644 --- a/drivers/pci/CMakeLists.txt +++ b/drivers/pci/CMakeLists.txt @@ -50,6 +50,10 @@ if(CONFIG_PCI_ENDPOINT) list(APPEND SRCS pci_qemu_epc.c) endif() # CONFIG_PCI_QEMU_EPC + if(CONFIG_PCI_EPF_TEST) + list(APPEND SRCS pci_epf_test.c) + endif() # CONFIG_PCI_EPF_TEST + target_sources(drivers PRIVATE ${SRCS}) endif() # CONFIG_PCI_ENDPOINT diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 112e89fb31..ee4ed1e01b 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -90,5 +90,10 @@ config PCI_QEMU_EPC ---help--- Enable qemu ep controller +config PCI_EPF_TEST + bool "PCI epf test" + ---help--- + pci epf test driver + endif # PCI_ENDPOINT diff --git a/drivers/pci/Make.defs b/drivers/pci/Make.defs index f116054663..4fad807ef9 100644 --- a/drivers/pci/Make.defs +++ b/drivers/pci/Make.defs @@ -45,6 +45,10 @@ ifeq ($(CONFIG_PCI_QEMU_EPC),y) CSRCS += pci_qemu_epc.c endif +ifeq ($(CONFIG_PCI_EPF_TEST),y) +CSRCS += pci_epf_test.c +endif + # Include PCI device driver build support DEPPATH += --dep-path pci diff --git a/drivers/pci/pci_drivers.c b/drivers/pci/pci_drivers.c index 12c7052cbd..e29234e372 100644 --- a/drivers/pci/pci_drivers.c +++ b/drivers/pci/pci_drivers.c @@ -124,6 +124,14 @@ int pci_register_drivers(void) } #endif +#ifdef CONFIG_PCI_EPF_TEST + ret = pci_register_epf_test_driver(); + if (ret < 0) + { + pcierr("pci_register_epf_test_driver failed, ret=%d\n", ret); + } +#endif + /* Initialization e1000 driver */ #ifdef CONFIG_NET_E1000 diff --git a/drivers/pci/pci_drivers.h b/drivers/pci/pci_drivers.h index 91545a5fda..e4152a107d 100644 --- a/drivers/pci/pci_drivers.h +++ b/drivers/pci/pci_drivers.h @@ -67,4 +67,16 @@ int pci_register_uio_ivshmem_driver(void); int pci_register_qemu_epc_driver(void); #endif +/**************************************************************************** + * Name: pci_register_epf_test_driver + * + * Description: + * Init a epf test driver + * + ****************************************************************************/ + +#ifdef CONFIG_PCI_EPF_TEST +int pci_register_epf_test_driver(void); +#endif + #endif /* __DRIVERS_PCI_PCI_DRIVERS_H */ diff --git a/drivers/pci/pci_epf_test.c b/drivers/pci/pci_epf_test.c new file mode 100644 index 0000000000..60f23c9779 --- /dev/null +++ b/drivers/pci/pci_epf_test.c @@ -0,0 +1,747 @@ +/**************************************************************************** + * drivers/pci/pci_epf_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 +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PCI_EPF_TEST_IRQ_TYPE_LEGACY 0 +#define PCI_EPF_TEST_IRQ_TYPE_MSI 1 +#define PCI_EPF_TEST_IRQ_TYPE_MSIX 2 + +#define PCI_EPF_TEST_COMMAND_RAISE_LEGACY_IRQ BIT(0) +#define PCI_EPF_TEST_COMMAND_RAISE_MSI_IRQ BIT(1) +#define PCI_EPF_TEST_COMMAND_RAISE_MSIX_IRQ BIT(2) +#define PCI_EPF_TEST_COMMAND_READ BIT(3) +#define PCI_EPF_TEST_COMMAND_WRITE BIT(4) +#define PCI_EPF_TEST_COMMAND_COPY BIT(5) + +#define PCI_EPF_TEST_STATUS_READ_SUCCESS BIT(0) +#define PCI_EPF_TEST_STATUS_READ_FAIL BIT(1) +#define PCI_EPF_TEST_STATUS_WRITE_SUCCESS BIT(2) +#define PCI_EPF_TEST_STATUS_WRITE_FAIL BIT(3) +#define PCI_EPF_TEST_STATUS_COPY_SUCCESS BIT(4) +#define PCI_EPF_TEST_STATUS_COPY_FAIL BIT(5) +#define PCI_EPF_TEST_STATUS_IRQ_RAISED BIT(6) +#define PCI_EPF_TEST_STATUS_SRC_ADDR_INVALID BIT(7) +#define PCI_EPF_TEST_STATUS_DST_ADDR_INVALID BIT(8) + +#define PCI_EPF_TEST_WORK_PERIOD MSEC2TICK(10) + +#define ALIGN_UP(x, m) (((x) + ((m) - 1)) \ + & ~((uintptr_t)(m) - 1)) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct begin_packed_struct pci_epf_test_reg_s +{ + uint32_t magic; + uint32_t command; + uint32_t status; + uint64_t src_addr; + uint64_t dst_addr; + uint32_t size; + uint32_t checksum; + uint32_t irq_type; + uint32_t irq_number; + uint32_t flags; +} end_packed_struct; + +struct pci_epf_test_s +{ + FAR void *reg[PCI_STD_NUM_BARS]; + FAR struct pci_epf_device_s *epf; + int test_reg_bar; + size_t msix_table_offset; + struct work_s work; + struct pci_epf_header_s header; + int bar_size[PCI_STD_NUM_BARS]; +}; + +/**************************************************************************** + * Private Functions Definitions + ****************************************************************************/ + +static void pci_epf_test_unbind(FAR struct pci_epf_device_s *epf); +static int pci_epf_test_bind(FAR struct pci_epf_device_s *epf); +static int pci_epf_test_probe(FAR struct pci_epf_device_s *epf); +static int pci_epf_test_core_init(FAR struct pci_epf_device_s *epf); +static int pci_epf_test_link_up(FAR struct pci_epf_device_s *epf); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct pci_epf_ops_s g_pci_epf_test_ops = +{ + .unbind = pci_epf_test_unbind, + .bind = pci_epf_test_bind, +}; + +static const struct pci_epf_device_id_s g_pci_epf_test_id_table[] = +{ + {.name = "pci_epf_test", }, + {} +}; + +static struct pci_epf_driver_s g_pci_epf_test_driver = +{ + .id_table = g_pci_epf_test_id_table, + .probe = pci_epf_test_probe, + .ops = &g_pci_epf_test_ops, +}; + +static const struct pci_epc_event_ops_s g_pci_epf_test_event_ops = +{ + .core_init = pci_epf_test_core_init, + .link_up = pci_epf_test_link_up, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int pci_epf_test_copy(FAR struct pci_epf_test_s *test) +{ + FAR struct pci_epf_device_s *epf = test->epf; + FAR struct pci_epc_ctrl_s *epc = epf->epc; + FAR struct pci_epf_test_reg_s *reg; + FAR void *vsrc_addr; + FAR void *vdst_addr; + uintptr_t src_addr; + uintptr_t dst_addr; + int ret; + + reg = test->reg[test->test_reg_bar]; + vsrc_addr = pci_epc_mem_alloc_addr(epc, &src_addr, reg->size); + if (vsrc_addr == NULL) + { + pcierr("Failed to allocate source address\n"); + reg->status = PCI_EPF_TEST_STATUS_SRC_ADDR_INVALID; + return -ENOMEM; + } + + ret = pci_epc_map_addr(epc, epf->funcno, src_addr, + reg->src_addr, reg->size); + if (ret < 0) + { + pcierr("Failed to map source address\n"); + reg->status = PCI_EPF_TEST_STATUS_SRC_ADDR_INVALID; + goto err_src_addr; + } + + vdst_addr = pci_epc_mem_alloc_addr(epc, &dst_addr, reg->size); + if (vdst_addr == NULL) + { + pcierr("Failed to allocate destination address\n"); + reg->status = PCI_EPF_TEST_STATUS_DST_ADDR_INVALID; + ret = -ENOMEM; + goto err_src_map_addr; + } + + ret = pci_epc_map_addr(epc, epf->funcno, dst_addr, + reg->dst_addr, reg->size); + if (ret < 0) + { + pcierr("Failed to map destination address\n"); + reg->status = PCI_EPF_TEST_STATUS_DST_ADDR_INVALID; + goto err_dst_addr; + } + + memcpy(vdst_addr, vsrc_addr, reg->size); + pci_epc_unmap_addr(epc, epf->funcno, dst_addr); + +err_dst_addr: + pci_epc_mem_free_addr(epc, dst_addr, reg->size); +err_src_map_addr: + pci_epc_unmap_addr(epc, epf->funcno, src_addr); +err_src_addr: + pci_epc_mem_free_addr(epc, src_addr, reg->size); + return ret; +} + +static int pci_epf_test_read(FAR struct pci_epf_test_s *test) +{ + FAR struct pci_epf_device_s *epf = test->epf; + FAR struct pci_epc_ctrl_s *epc = epf->epc; + FAR struct pci_epf_test_reg_s *reg; + FAR void *vsrc_addr; + uintptr_t src_addr; + FAR void *buf; + int ret; + + reg = test->reg[test->test_reg_bar]; + vsrc_addr = pci_epc_mem_alloc_addr(epc, &src_addr, reg->size); + if (vsrc_addr == NULL) + { + pcierr("Failed to allocate address\n"); + reg->status = PCI_EPF_TEST_STATUS_SRC_ADDR_INVALID; + return -ENOMEM; + } + + ret = pci_epc_map_addr(epc, epf->funcno, src_addr, + reg->src_addr, reg->size); + if (ret < 0) + { + pcierr("Failed to map address\n"); + reg->status = PCI_EPF_TEST_STATUS_SRC_ADDR_INVALID; + goto err_addr; + } + + buf = kmm_zalloc(reg->size); + if (buf == NULL) + { + ret = -ENOMEM; + goto err_map_addr; + } + + memcpy(buf, vsrc_addr, reg->size); + if (reg->checksum != crc32part(buf, reg->size, ~0)) + { + ret = -EIO; + } + + kmm_free(buf); + +err_map_addr: + pci_epc_unmap_addr(epc, epf->funcno, src_addr); +err_addr: + pci_epc_mem_free_addr(epc, src_addr, reg->size); + return ret; +} + +static int pci_epf_test_write(FAR struct pci_epf_test_s *test) +{ + FAR struct pci_epf_device_s *epf = test->epf; + FAR struct pci_epc_ctrl_s *epc = epf->epc; + FAR struct pci_epf_test_reg_s *reg; + FAR void *vdst_addr; + uintptr_t dst_addr; + FAR void *buf; + int ret; + + reg = test->reg[test->test_reg_bar]; + vdst_addr = pci_epc_mem_alloc_addr(epc, &dst_addr, reg->size); + if (vdst_addr == NULL) + { + pcierr("Failed to allocate address\n"); + reg->status = PCI_EPF_TEST_STATUS_DST_ADDR_INVALID; + return -ENOMEM; + } + + ret = pci_epc_map_addr(epc, epf->funcno, dst_addr, + reg->dst_addr, reg->size); + if (ret < 0) + { + pcierr("Failed to map address\n"); + reg->status = PCI_EPF_TEST_STATUS_DST_ADDR_INVALID; + goto err_addr; + } + + buf = kmm_malloc(reg->size); + if (buf == NULL) + { + ret = -ENOMEM; + goto err_map_addr; + } + + reg->checksum = crc32part(buf, reg->size, ~0); + memcpy(vdst_addr, buf, reg->size); + kmm_free(buf); + +err_map_addr: + pci_epc_unmap_addr(epc, epf->funcno, dst_addr); +err_addr: + pci_epc_mem_free_addr(epc, dst_addr, reg->size); + return ret; +} + +static void +pci_epf_test_raise_irq(FAR struct pci_epf_test_s *test, + uint8_t irq_type, uint16_t irq) +{ + FAR struct pci_epf_device_s *epf = test->epf; + FAR struct pci_epc_ctrl_s *epc = epf->epc; + FAR struct pci_epf_test_reg_s *reg; + + reg = test->reg[test->test_reg_bar]; + reg->status |= PCI_EPF_TEST_STATUS_IRQ_RAISED; + + switch (irq_type) + { + case PCI_EPF_TEST_IRQ_TYPE_LEGACY: + pci_epc_raise_irq(epc, epf->funcno, PCI_EPC_IRQ_LEGACY, 0); + break; + case PCI_EPF_TEST_IRQ_TYPE_MSI: + pci_epc_raise_irq(epc, epf->funcno, PCI_EPC_IRQ_MSI, irq); + break; + case PCI_EPF_TEST_IRQ_TYPE_MSIX: + pci_epc_raise_irq(epc, epf->funcno, PCI_EPC_IRQ_MSIX, irq); + break; + default: + pcierr("Failed to raise IRQ, unknown type\n"); + break; + } +} + +static void pci_epf_test_cmd_handler(FAR void *arg) +{ + FAR struct pci_epf_test_s *test = arg; + FAR struct pci_epf_device_s *epf = test->epf; + FAR struct pci_epc_ctrl_s *epc = epf->epc; + FAR struct pci_epf_test_reg_s *reg; + uint32_t command; + int count; + int ret; + + reg = test->reg[test->test_reg_bar]; + command = reg->command; + if (!command) + { + goto reset_handler; + } + + reg->command = 0; + reg->status = 0; + + if (reg->irq_type > PCI_EPF_TEST_IRQ_TYPE_MSIX) + { + pcierr("Failed to detect IRQ type\n"); + goto reset_handler; + } + + if (command & PCI_EPF_TEST_COMMAND_RAISE_LEGACY_IRQ) + { + reg->status = PCI_EPF_TEST_STATUS_IRQ_RAISED; + pci_epc_raise_irq(epc, epf->funcno, + PCI_EPC_IRQ_LEGACY, 0); + } + else if (command & PCI_EPF_TEST_COMMAND_WRITE) + { + ret = pci_epf_test_write(test); + if (ret < 0) + { + reg->status |= PCI_EPF_TEST_STATUS_WRITE_FAIL; + } + else + { + reg->status |= PCI_EPF_TEST_STATUS_WRITE_SUCCESS; + } + + pci_epf_test_raise_irq(test, reg->irq_type, reg->irq_number); + } + else if (command & PCI_EPF_TEST_COMMAND_READ) + { + ret = pci_epf_test_read(test); + if (ret < 0) + { + reg->status |= PCI_EPF_TEST_STATUS_READ_FAIL; + } + else + { + reg->status |= PCI_EPF_TEST_STATUS_READ_SUCCESS; + } + + pci_epf_test_raise_irq(test, reg->irq_type, reg->irq_number); + } + else if (command & PCI_EPF_TEST_COMMAND_COPY) + { + ret = pci_epf_test_copy(test); + if (ret < 0) + { + reg->status |= PCI_EPF_TEST_STATUS_COPY_FAIL; + } + else + { + reg->status |= PCI_EPF_TEST_STATUS_COPY_SUCCESS; + } + + pci_epf_test_raise_irq(test, reg->irq_type, reg->irq_number); + } + else if (command & PCI_EPF_TEST_COMMAND_RAISE_MSI_IRQ) + { + count = pci_epc_get_msi(epc, epf->funcno); + if (reg->irq_number > count || count <= 0) + { + goto reset_handler; + } + + reg->status = PCI_EPF_TEST_STATUS_IRQ_RAISED; + pci_epc_raise_irq(epc, epf->funcno, + PCI_EPC_IRQ_MSI, reg->irq_number); + } + else if (command & PCI_EPF_TEST_COMMAND_RAISE_MSIX_IRQ) + { + count = pci_epc_get_msix(epc, epf->funcno); + if (reg->irq_number > count || count <= 0) + { + goto reset_handler; + } + + reg->status = PCI_EPF_TEST_STATUS_IRQ_RAISED; + pci_epc_raise_irq(epc, epf->funcno, + PCI_EPC_IRQ_MSIX, reg->irq_number); + } + +reset_handler: + work_queue(HPWORK, &test->work, pci_epf_test_cmd_handler, + test, PCI_EPF_TEST_WORK_PERIOD); +} + +static void pci_epf_test_unbind(FAR struct pci_epf_device_s *epf) +{ + FAR struct pci_epf_test_s *test = epf->priv; + FAR struct pci_epc_ctrl_s *epc = epf->epc; + int bar; + + work_cancel(HPWORK, &test->work); + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) + { + if (test->reg[bar]) + { + pci_epc_clear_bar(epc, epf->funcno, &epf->bar[bar]); + pci_epf_free_space(epf, bar, test->reg[bar]); + } + } +} + +static int pci_epf_test_set_bar(FAR struct pci_epf_device_s *epf) +{ + FAR const struct pci_epc_features_s *features; + FAR struct pci_epf_test_s *test = epf->priv; + FAR struct pci_epc_ctrl_s *epc = epf->epc; + int bar; + int add; + int ret; + + features = pci_epc_get_features(epc, epf->funcno); + for (bar = 0; bar < PCI_STD_NUM_BARS; bar += add) + { + /* pci_epc_set_bar() sets PCI_BASE_ADDRESS_MEM_TYPE_64 + * if the specific implementation required a 64-bit BAR, + * even if we only requested a 32-bit BAR. + */ + + add = (epf->bar[bar].flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1; + + if (!!(features->bar_reserved & (1 << bar))) + { + continue; + } + + ret = pci_epc_set_bar(epc, epf->funcno, &epf->bar[bar]); + if (ret < 0) + { + pci_epf_free_space(epf, bar, test->reg[bar]); + pcierr("Failed to set BAR%d\n", bar); + if (bar == test->test_reg_bar) + { + return ret; + } + } + } + + return 0; +} + +static int pci_epf_test_core_init(FAR struct pci_epf_device_s *epf) +{ + FAR struct pci_epf_header_s *header = epf->header; + FAR const struct pci_epc_features_s *features; + FAR struct pci_epf_test_s *test = epf->priv; + FAR struct pci_epc_ctrl_s *epc = epf->epc; + bool msix_capable = false; + bool msi_capable = false; + int ret; + + features = pci_epc_get_features(epc, epf->funcno); + if (features != NULL) + { + msix_capable = features->msix_capable; + msi_capable = features->msi_capable; + } + + ret = pci_epc_write_header(epc, epf->funcno, header); + if (ret < 0) + { + pcierr("Configuration header write failed\n"); + return ret; + } + + ret = pci_epf_test_set_bar(epf); + if (ret < 0) + { + return ret; + } + + if (msi_capable) + { + ret = pci_epc_set_msi(epc, epf->funcno, + epf->msi_interrupts); + if (ret < 0) + { + pcierr("MSI configuration failed\n"); + return ret; + } + } + + if (msix_capable) + { + ret = pci_epc_set_msix(epc, epf->funcno, + epf->msix_interrupts, + test->test_reg_bar, + test->msix_table_offset); + if (ret < 0) + { + pcierr("MSI-X configuration failed\n"); + return ret; + } + } + + return 0; +} + +static int pci_epf_test_link_up(FAR struct pci_epf_device_s *epf) +{ + FAR struct pci_epf_test_s *test = epf->priv; + + return work_queue(HPWORK, &test->work, pci_epf_test_cmd_handler, + test, PCI_EPF_TEST_WORK_PERIOD); +} + +static int +pci_epf_test_alloc_space(FAR struct pci_epf_device_s *epf) +{ + FAR const struct pci_epc_features_s *features; + FAR struct pci_epf_test_s *test = epf->priv; + FAR struct pci_epc_ctrl_s *epc = epf->epc; + int test_reg_bar = test->test_reg_bar; + size_t msix_table_size = 0; + size_t test_reg_bar_size; + size_t test_reg_size; + bool bar_fixed_64bit; + size_t pba_size = 0; + bool msix_capable; + int bar; + int add; + + features = pci_epc_get_features(epc, epf->funcno); + test_reg_bar_size = ALIGN_UP(sizeof(struct pci_epf_test_reg_s), 128); + msix_capable = features->msix_capable; + if (msix_capable) + { + msix_table_size = PCI_MSIX_ENTRY_SIZE * epf->msix_interrupts; + test->msix_table_offset = test_reg_bar_size; + + /* Align to QWORD or 8 Bytes */ + + pba_size = ALIGN_UP(div_round_up(epf->msix_interrupts, 8), 8); + } + + test_reg_size = test_reg_bar_size + msix_table_size + pba_size; + if (test_reg_size > test->bar_size[test_reg_bar]) + { + return -ENOMEM; + } + + for (bar = 0; bar < PCI_STD_NUM_BARS; bar += add) + { + bar_fixed_64bit = !!(features->bar_fixed_64bit & (1 << bar)); + if (bar_fixed_64bit) + { + epf->bar[bar].flags |= PCI_BASE_ADDRESS_MEM_TYPE_64; + } + + add = (epf->bar[bar].flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1; + if (!!(features->bar_reserved & (1 << bar))) + { + continue; + } + + test->reg[bar] = pci_epf_alloc_space(epf, bar, test->bar_size[bar], + features->align); + if (test->reg[bar] == NULL) + { + pcierr("Failed to allocate space for BAR%d\n", bar); + if (bar == test_reg_bar) + { + return -ENOMEM; + } + } + } + + return 0; +} + +static int pci_epf_test_bind(FAR struct pci_epf_device_s *epf) +{ + FAR const struct pci_epc_features_s *features; + FAR struct pci_epf_test_s *test = epf->priv; + FAR struct pci_epc_ctrl_s *epc = epf->epc; + int ret; + + features = pci_epc_get_features(epc, epf->funcno); + if (features == NULL) + { + pcierr("features not implemented\n"); + return -ENOTSUP; + } + + test->test_reg_bar = pci_epc_get_first_free_bar(features); + if (test->test_reg_bar < 0) + { + return -EINVAL; + } + + ret = pci_epf_test_alloc_space(epf); + if (ret < 0) + { + return ret; + } + + if (!features->core_init_notifier) + { + ret = pci_epf_test_core_init(epf); + if (ret < 0) + { + return ret; + } + } + + ret = pci_epc_start(epf->epc); + if (ret < 0) + { + pcierr("start error %d\n", ret); + return ret; + } + + if (!features->linkup_notifier && !features->core_init_notifier) + { + work_queue(HPWORK, &test->work, pci_epf_test_cmd_handler, + test, PCI_EPF_TEST_WORK_PERIOD); + } + + return 0; +} + +static int pci_epf_test_probe(FAR struct pci_epf_device_s *epf) +{ + FAR struct pci_epf_test_s *test = kmm_zalloc(sizeof(*test)); + + if (test == NULL) + { + return -ENOMEM; + } + + test->header.vendorid = 0x104c; + test->header.deviceid = 0xb500; + test->header.baseclass_code = PCI_CLASS_OTHERS; + test->header.interrupt_pin = PCI_INTERRUPT_INTA; + test->bar_size[0] = 512; + test->bar_size[1] = 512; + test->bar_size[2] = 1024; + test->bar_size[3] = 16384; + test->bar_size[4] = 131072; + test->bar_size[5] = 1048576; + test->epf = epf; + + epf->header = &test->header; + epf->priv = test; + epf->event_ops = &g_pci_epf_test_event_ops; + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pci_register_epf_test_device + * + * Description: + * Init a epf device test + * + ****************************************************************************/ + +int pci_register_epf_test_device(FAR const char *epc_name) +{ + FAR struct pci_epf_device_s *epf; + int ret; + + epf = kmm_zalloc(sizeof(*epf)); + if (NULL == epf) + { + pcierr("create epf error\n"); + return -ENOMEM; + } + + epf->name = "pci_epf_test"; + epf->epc_name = epc_name; + epf->msi_interrupts = 1; + nxmutex_init(&epf->lock); + ret = pci_epf_device_register(epf); + if (ret < 0) + { + pcierr("link error"); + goto err; + } + + return 0; + +err: + nxmutex_destroy(&epf->lock); + kmm_free(epf); + return ret; +} + +/**************************************************************************** + * Name: pci_register_epf_test_driver + * + * Description: + * Init a epf test driver + * + ****************************************************************************/ + +int pci_register_epf_test_driver(void) +{ + return pci_epf_register_driver(&g_pci_epf_test_driver); +} diff --git a/include/nuttx/pci/pci_ep_test.h b/include/nuttx/pci/pci_ep_test.h new file mode 100644 index 0000000000..f985edb179 --- /dev/null +++ b/include/nuttx/pci/pci_ep_test.h @@ -0,0 +1,45 @@ +/**************************************************************************** + * include/nuttx/pci/pci_ep_test.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_EP_TEST_H +#define __INCLUDE_NUTTX_PCI_EP_TEST_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifdef CONFIG_PCI_EPF_TEST + +/**************************************************************************** + * Name: pci_register_epf_test_device + * + * Description: + * Init a epf device test + * + ****************************************************************************/ + +int pci_register_epf_test_device(FAR const char *epc_name); +#endif + +#endif /* __INCLUDE_NUTTX_PCI_EP_TEST_H */