diff --git a/drivers/pci/CMakeLists.txt b/drivers/pci/CMakeLists.txt index 9ea165a56e..d89e96587f 100644 --- a/drivers/pci/CMakeLists.txt +++ b/drivers/pci/CMakeLists.txt @@ -54,6 +54,10 @@ if(CONFIG_PCI_ENDPOINT) list(APPEND SRCS pci_epf_test.c) endif() # CONFIG_PCI_EPF_TEST + if(CONFIG_PCI_EP_TEST) + list(APPEND SRCS pci_ep_test.c) + endif() # CONFIG_PCI_ENDPOINT_TEST + target_sources(drivers PRIVATE ${SRCS}) endif() # CONFIG_PCI_ENDPOINT diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index ee4ed1e01b..fee521c5bc 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -95,5 +95,10 @@ config PCI_EPF_TEST ---help--- pci epf test driver +config PCI_EP_TEST + bool "PCI endpoint test" + ---help--- + pci endpoint test driver + endif # PCI_ENDPOINT diff --git a/drivers/pci/Make.defs b/drivers/pci/Make.defs index 4fad807ef9..4e40738cd3 100644 --- a/drivers/pci/Make.defs +++ b/drivers/pci/Make.defs @@ -49,6 +49,10 @@ ifeq ($(CONFIG_PCI_EPF_TEST),y) CSRCS += pci_epf_test.c endif +ifeq ($(CONFIG_PCI_EP_TEST),y) +CSRCS += pci_ep_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 e29234e372..23cc7d8808 100644 --- a/drivers/pci/pci_drivers.c +++ b/drivers/pci/pci_drivers.c @@ -132,6 +132,14 @@ int pci_register_drivers(void) } #endif +#ifdef CONFIG_PCI_EP_TEST + ret = pci_register_ep_test_driver(); + if (ret < 0) + { + pcierr("pci_register_ep_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 e4152a107d..3bacba7363 100644 --- a/drivers/pci/pci_drivers.h +++ b/drivers/pci/pci_drivers.h @@ -79,4 +79,16 @@ int pci_register_qemu_epc_driver(void); int pci_register_epf_test_driver(void); #endif +/**************************************************************************** + * Name: pci_register_ep_test_driver + * + * Description: + * Register endpoint test device pci driver + * + ****************************************************************************/ + +#ifdef CONFIG_PCI_EP_TEST +int pci_register_ep_test_driver(void); +#endif + #endif /* __DRIVERS_PCI_PCI_DRIVERS_H */ diff --git a/drivers/pci/pci_ep_test.c b/drivers/pci/pci_ep_test.c new file mode 100644 index 0000000000..7c0d64a8a4 --- /dev/null +++ b/drivers/pci/pci_ep_test.c @@ -0,0 +1,840 @@ +/**************************************************************************** + * drivers/pci/pci_ep_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 "pci_drivers.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PCI_EP_TEST_DEVICE_NAME "/dev/pci-ep-test" + +#define PCI_EP_TEST_IRQ_TYPE_UNDEFINED -1 +#define PCI_EP_TEST_IRQ_TYPE_LEGACY 0 +#define PCI_EP_TEST_IRQ_TYPE_MSI 1 +#define PCI_EP_TEST_IRQ_TYPE_MSIX 2 + +#define PCI_EP_TEST_MAGIC 0x0 + +#define PCI_EP_TEST_COMMAND 0x4 +#define PCI_EP_TEST_COMMAND_LEGACY_IRQ BIT(0) +#define PCI_EP_TEST_COMMAND_MSI_IRQ BIT(1) +#define PCI_EP_TEST_COMMAND_MSIX_IRQ BIT(2) +#define PCI_EP_TEST_COMMAND_READ BIT(3) +#define PCI_EP_TEST_COMMAND_WRITE BIT(4) +#define PCI_EP_TEST_COMMAND_COPY BIT(5) + +#define PCI_EP_TEST_STATUS 0x8 +#define PCI_EP_TEST_STATUS_READ_SUCCESS BIT(0) +#define PCI_EP_TEST_STATUS_READ_FAIL BIT(1) +#define PCI_EP_TEST_STATUS_WRITE_SUCCESS BIT(2) +#define PCI_EP_TEST_STATUS_WRITE_FAIL BIT(3) +#define PCI_EP_TEST_STATUS_COPY_SUCCESS BIT(4) +#define PCI_EP_TEST_STATUS_COPY_FAIL BIT(5) +#define PCI_EP_TEST_STATUS_IRQ_RAISED BIT(6) +#define PCI_EP_TEST_STATUS_SRC_ADDR_INVALID BIT(7) +#define PCI_EP_TEST_STATUS_DST_ADDR_INVALID BIT(8) + +#define PCI_EP_TEST_LOWER_SRC_ADDR 0x0c +#define PCI_EP_TEST_UPPER_SRC_ADDR 0x10 + +#define PCI_EP_TEST_LOWER_DST_ADDR 0x14 +#define PCI_EP_TEST_UPPER_DST_ADDR 0x18 + +#define PCI_EP_TEST_SIZE 0x1c +#define PCI_EP_TEST_CHECKSUM 0x20 + +#define PCI_EP_TEST_IRQ_TYPE 0x24 +#define PCI_EP_TEST_IRQ_NUMBER 0x28 +#define PCI_EP_TEST_FLAGS 0x2c + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct pci_ep_test_s +{ + FAR struct pci_device_s *pdev; + FAR void *base; + FAR void *bar[PCI_STD_NUM_BARS]; + sem_t irq_raise; + int irq; + int irq_type; + mutex_t mutex; + int test_bar; + size_t alignment; + char name[32]; +}; + +/**************************************************************************** + * Private Functions Definitions + ****************************************************************************/ + +static int pci_ep_test_probe(FAR struct pci_device_s *dev); + +static int pci_ep_test_open(FAR struct file *filep); +static int pci_ep_test_close(FAR struct file *filep); +static int pci_ep_test_ioctl(FAR struct file *filep, + int cmd, unsigned long arge); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct pci_device_id_s g_pci_ep_test_id_table[] = +{ + { PCI_DEVICE(0x104c, 0xb500), }, + { } +}; + +static struct pci_driver_s g_pci_ep_test_drv = +{ + .id_table = g_pci_ep_test_id_table, + .probe = pci_ep_test_probe, +}; + +static const struct file_operations g_pci_ep_test_fops = +{ + pci_ep_test_open, /* open */ + pci_ep_test_close, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* seek */ + pci_ep_test_ioctl, /* ioctl */ + NULL, /* mmap */ +}; + +static int g_pci_ep_idr = 0; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline uint32_t +pci_ep_test_read_dword(FAR struct pci_ep_test_s *test, + uint32_t offset) +{ + uint32_t value; + pci_read_mmio_dword(test->pdev, test->base + offset, &value); + return value; +} + +static inline void +pci_ep_test_write_dword(FAR struct pci_ep_test_s *test, + uint32_t offset, uint32_t value) +{ + pci_write_mmio_dword(test->pdev, test->base + offset, value); +} + +static inline uint32_t +pci_ep_test_bar_read_dword(FAR struct pci_ep_test_s *test, + int bar, uint32_t offset) +{ + uint32_t value; + pci_read_mmio_dword(test->pdev, test->bar[bar] + offset, &value); + return value; +} + +static inline void +pci_ep_test_bar_write_dword(FAR struct pci_ep_test_s *test, int bar, + uint32_t offset, uint32_t value) +{ + pci_write_mmio_dword(test->pdev, test->bar[bar] + offset, value); +} + +/**************************************************************************** + * Name: pci_ep_test_open + * + * Description: + * This function is used to open /dev/X. + * + ****************************************************************************/ + +static int pci_ep_test_open(FAR struct file *filep) +{ + FAR struct pci_ep_test_s *test; + + test = filep->f_inode->i_private; + DEBUGASSERT(test != NULL); + + filep->f_priv = test; + + return 0; +} + +/**************************************************************************** + * Name: pci_ep_test_close + * + * Description: + * This function is used to close /dev/X. + * + ****************************************************************************/ + +static int pci_ep_test_close(FAR struct file *filep) +{ + filep->f_priv = NULL; + + return 0; +} + +/**************************************************************************** + * Name: pci_ep_test_bar + * + * Description: + * This function is used to test bar access. + * + ****************************************************************************/ + +static bool pci_ep_test_bar(FAR struct pci_ep_test_s *test, + int barno) +{ + FAR struct pci_device_s *pdev = test->pdev; + int size; + int step; + + if (NULL == test->bar[barno]) + { + pcierr("bar address is null \n"); + return false; + } + + size = pci_resource_len(pdev, barno); + + if (barno == test->test_bar) + { + size = 0x4; + } + + for (step = 0; step < size; step += 4) + { + pci_ep_test_bar_write_dword(test, barno, step, 0xa0a0a0a0); + } + + for (step = 0; step < size; step += 4) + { + uint32_t val = pci_ep_test_bar_read_dword(test, barno, step); + if (val != 0xa0a0a0a0) + { + pcierr("verify value not pass!!!\n"); + return false; + } + } + + return true; +} + +/**************************************************************************** + * Name: pci_ep_test_legacy_irq + * + * Description: + * This function is used to test legacy irq + * + ****************************************************************************/ + +static bool +pci_ep_test_legacy_irq(FAR struct pci_ep_test_s *test) +{ + pci_ep_test_write_dword(test, PCI_EP_TEST_IRQ_TYPE, + PCI_EP_TEST_IRQ_TYPE_LEGACY); + pci_ep_test_write_dword(test, PCI_EP_TEST_IRQ_NUMBER, 0); + pci_ep_test_write_dword(test, PCI_EP_TEST_COMMAND, + PCI_EP_TEST_COMMAND_LEGACY_IRQ); + nxsem_wait(&test->irq_raise); + + return true; +} + +/**************************************************************************** + * Name: pci_ep_test_msi_irq + * + * Description: + * This function is used to test msi or msix irq + * + ****************************************************************************/ + +static bool pci_ep_test_msi_irq(FAR struct pci_ep_test_s *test, + uint16_t msi_num, bool msix) +{ + pci_ep_test_write_dword(test, PCI_EP_TEST_IRQ_TYPE, + msix ? PCI_EP_TEST_IRQ_TYPE_MSIX : + PCI_EP_TEST_IRQ_TYPE_MSI); + pci_ep_test_write_dword(test, PCI_EP_TEST_IRQ_NUMBER, msi_num); + pci_ep_test_write_dword(test, PCI_EP_TEST_COMMAND, + msix ? PCI_EP_TEST_COMMAND_MSIX_IRQ : + PCI_EP_TEST_COMMAND_MSI_IRQ); + nxsem_wait(&test->irq_raise); + + return true; +} + +/**************************************************************************** + * Name: pci_ep_fill_init + * + * Description: + * This function is used to fill init data. + * + ****************************************************************************/ + +static void pci_ep_fill_init(FAR void *addr, size_t size) +{ + FAR char *tmp = addr; + int idx; + + for (idx = 0; idx < size; idx++) + { + *(tmp + idx) = idx % 255; + } +} + +/**************************************************************************** + * Name: pci_ep_test_write + * + * Description: + * This function is used to test write. + * + ****************************************************************************/ + +static bool pci_ep_test_write(FAR struct pci_ep_test_s *test, + unsigned long arg) +{ + FAR struct pci_ep_test_param_s *param; + FAR void *addr; + uint64_t phys_addr; + uint32_t crc32; + + param = (FAR struct pci_ep_test_param_s *)arg; + if (param->size == 0) + { + pcierr("xfer size is zero, invalid param\n"); + return false; + } + + if (test->irq_type < PCI_EP_TEST_IRQ_TYPE_LEGACY || + test->irq_type > PCI_EP_TEST_IRQ_TYPE_MSIX) + { + pcierr("invalid IRQ type option\n"); + return false; + } + + addr = kmm_memalign(test->alignment, param->size); + if (NULL == addr) + { + pcierr("Failed to alloc origin memory addr\n"); + return false; + } + + pci_ep_fill_init(addr, param->size); + + phys_addr = up_addrenv_va_to_pa(addr); + + crc32 = crc32part(addr, param->size, ~0); + pci_ep_test_write_dword(test, PCI_EP_TEST_CHECKSUM, crc32); + pci_ep_test_write_dword(test, PCI_EP_TEST_LOWER_SRC_ADDR, + phys_addr); + pci_ep_test_write_dword(test, PCI_EP_TEST_UPPER_SRC_ADDR, + phys_addr >> 32); + + pci_ep_test_write_dword(test, PCI_EP_TEST_SIZE, param->size); + + pci_ep_test_write_dword(test, PCI_EP_TEST_FLAGS, 0); + pci_ep_test_write_dword(test, PCI_EP_TEST_IRQ_TYPE, test->irq_type); + pci_ep_test_write_dword(test, PCI_EP_TEST_IRQ_NUMBER, 1); + pci_ep_test_write_dword(test, PCI_EP_TEST_COMMAND, + PCI_EP_TEST_COMMAND_READ); + + nxsem_wait(&test->irq_raise); + kmm_free(addr); + + return !!(pci_ep_test_read_dword(test, PCI_EP_TEST_STATUS) & + PCI_EP_TEST_STATUS_READ_SUCCESS); +} + +/**************************************************************************** + * Name: pci_ep_test_read + * + * Description: + * This function is used to test read. + * + ****************************************************************************/ + +static bool pci_ep_test_read(FAR struct pci_ep_test_s *test, + unsigned long arg) +{ + FAR struct pci_ep_test_param_s *param; + FAR void *addr; + uint64_t phys_addr; + uint32_t crc32; + + param = (FAR struct pci_ep_test_param_s *)arg; + if (param->size == 0) + { + pcierr("xfer size is zero, invalid param\n"); + return false; + } + + if (test->irq_type < PCI_EP_TEST_IRQ_TYPE_LEGACY || + test->irq_type > PCI_EP_TEST_IRQ_TYPE_MSIX) + { + pcierr("invalid IRQ type option\n"); + return false; + } + + addr = kmm_memalign(test->alignment, param->size); + if (NULL == addr) + { + pcierr("Failed to alloc origin memory addr\n"); + return false; + } + + phys_addr = up_addrenv_va_to_pa(addr); + + pci_ep_test_write_dword(test, PCI_EP_TEST_LOWER_DST_ADDR, + phys_addr); + pci_ep_test_write_dword(test, PCI_EP_TEST_UPPER_DST_ADDR, + phys_addr >> 32); + + pci_ep_test_write_dword(test, PCI_EP_TEST_SIZE, param->size); + + pci_ep_test_write_dword(test, PCI_EP_TEST_FLAGS, 0); + pci_ep_test_write_dword(test, PCI_EP_TEST_IRQ_TYPE, test->irq_type); + pci_ep_test_write_dword(test, PCI_EP_TEST_IRQ_NUMBER, 1); + pci_ep_test_write_dword(test, PCI_EP_TEST_COMMAND, + PCI_EP_TEST_COMMAND_WRITE); + + nxsem_wait(&test->irq_raise); + + crc32 = crc32part(addr, param->size, ~0); + kmm_free(addr); + + return crc32 == pci_ep_test_read_dword(test, PCI_EP_TEST_CHECKSUM); +} + +/**************************************************************************** + * Name: pci_ep_test_copy + * + * Description: + * This function is used to test copy. + * + ****************************************************************************/ + +static bool +pci_ep_test_copy(struct pci_ep_test_s *test, unsigned long arg) +{ + FAR struct pci_ep_test_param_s *param; + FAR void *src_addr; + FAR void *dst_addr; + uint64_t src_phys_addr; + uint64_t dst_phys_addr; + uint32_t src_crc32; + uint32_t dst_crc32; + + param = (FAR struct pci_ep_test_param_s *)arg; + if (param->size == 0) + { + pcierr("xfer size is zero, invalid param\n"); + return false; + } + + if (test->irq_type < PCI_EP_TEST_IRQ_TYPE_LEGACY || + test->irq_type > PCI_EP_TEST_IRQ_TYPE_MSIX) + { + pcierr("invalid IRQ type option\n"); + return false; + } + + src_addr = kmm_memalign(test->alignment, param->size); + if (NULL == src_addr) + { + pcierr("Failed to alloc origin memory addr\n"); + return false; + } + + pci_ep_fill_init(src_addr, param->size); + + src_phys_addr = up_addrenv_va_to_pa(src_addr); + + pci_ep_test_write_dword(test, PCI_EP_TEST_LOWER_SRC_ADDR, + src_phys_addr); + pci_ep_test_write_dword(test, PCI_EP_TEST_UPPER_SRC_ADDR, + src_phys_addr >> 32); + + src_crc32 = crc32part(src_addr, param->size, ~0); + + dst_addr = kmm_memalign(test->alignment, param->size); + if (NULL == dst_addr) + { + pcierr("Failed to alloc origin memory addr\n"); + kmm_free(src_addr); + return false; + } + + dst_phys_addr = up_addrenv_va_to_pa(dst_addr); + + pci_ep_test_write_dword(test, PCI_EP_TEST_LOWER_DST_ADDR, + dst_phys_addr); + pci_ep_test_write_dword(test, PCI_EP_TEST_UPPER_DST_ADDR, + dst_phys_addr >> 32); + + pci_ep_test_write_dword(test, PCI_EP_TEST_SIZE, param->size); + + pci_ep_test_write_dword(test, PCI_EP_TEST_FLAGS, 0); + pci_ep_test_write_dword(test, PCI_EP_TEST_IRQ_TYPE, test->irq_type); + pci_ep_test_write_dword(test, PCI_EP_TEST_IRQ_NUMBER, 1); + pci_ep_test_write_dword(test, PCI_EP_TEST_COMMAND, + PCI_EP_TEST_COMMAND_COPY); + + nxsem_wait(&test->irq_raise); + + dst_crc32 = crc32part(dst_addr, param->size, ~0); + + kmm_free(dst_addr); + kmm_free(src_addr); + + return src_crc32 == dst_crc32; +} + +/**************************************************************************** + * Name: pci_ep_test_free_irq + * + * Description: + * This function is used to clear request irq type. + * + ****************************************************************************/ + +static bool pci_ep_test_free_irq(FAR struct pci_ep_test_s *test) +{ + up_disable_irq(test->irq); + irq_detach(test->irq); + pci_release_irq(test->pdev, &test->irq, 1); + return true; +} + +/**************************************************************************** + * Name: pci_ep_test_handler + * + * Description: + * request pci irq and register handler + * + ****************************************************************************/ + +static int pci_ep_test_handler(int irq, FAR void *context, + FAR void *args) +{ + FAR struct pci_ep_test_s *test = + (FAR struct pci_ep_test_s *)args; + uint32_t reg; + + reg = pci_ep_test_read_dword(test, PCI_EP_TEST_STATUS); + if (reg & PCI_EP_TEST_STATUS_IRQ_RAISED) + { + nxsem_post(&test->irq_raise); + reg &= ~PCI_EP_TEST_STATUS_IRQ_RAISED; + } + + pci_ep_test_write_dword(test, PCI_EP_TEST_STATUS, reg); + + return 0; +} + +/**************************************************************************** + * Name: pci_ep_test_alloc_irq + * + * Description: + * Alloc pci irq by irq type + * + ****************************************************************************/ + +static int pci_ep_test_alloc_irq(FAR struct pci_ep_test_s *test, + int irq_type) +{ + FAR struct pci_device_s *pdev = test->pdev; + int ret = -EINVAL; + + switch (irq_type) + { + case PCI_EP_TEST_IRQ_TYPE_LEGACY: + ret = test->irq = pci_get_irq(pdev); + break; + + case PCI_EP_TEST_IRQ_TYPE_MSI: + ret = pci_alloc_irq(pdev, &test->irq, 1); + break; + + case PCI_EP_TEST_IRQ_TYPE_MSIX: + ret = pci_alloc_irq(pdev, &test->irq, 1); + break; + + default: + pcierr("invalid irq type %d\n", irq_type); + break; + } + + if (ret < 0) + { + return ret; + } + + test->irq_type = irq_type; + + ret = irq_attach(test->irq, pci_ep_test_handler, test); + if (ret >= 0) + { + up_enable_irq(test->irq); + } + else + { + pci_release_irq(test->pdev, &test->irq, 1); + pcierr("error ret=%d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: pci_ep_test_set_irq + * + * Description: + * This function is used to set request irq type. + * + ****************************************************************************/ + +static bool +pci_ep_test_set_irq(struct pci_ep_test_s *test, int req_irq_type) +{ + int ret; + + if (req_irq_type < PCI_EP_TEST_IRQ_TYPE_LEGACY || + req_irq_type > PCI_EP_TEST_COMMAND_MSIX_IRQ) + { + pcierr("invaild irq option\n"); + return false; + } + + if (test->irq_type == req_irq_type) + { + return true; + } + + pci_ep_test_free_irq(test); + + ret = pci_ep_test_alloc_irq(test, req_irq_type); + if (ret < 0) + { + pcierr("alloc pci irq %d fail\n", req_irq_type); + return false; + } + + return true; +} + +/**************************************************************************** + * Name: pci_ep_test_ioctl + * + * Description: + * This function is used to respond ioctl cmd. + * + ****************************************************************************/ + +static int pci_ep_test_ioctl(FAR struct file *filep, + int cmd, unsigned long arg) +{ + FAR struct pci_ep_test_s *test; + int ret = -EINVAL; + int bar; + + test = filep->f_priv; + DEBUGASSERT(test != NULL); + + nxmutex_lock(&test->mutex); + switch (cmd) + { + case PCITEST_BAR: + bar = arg; + if (bar > PCI_STD_NUM_BARS || bar < 0) + { + pcierr("bar num %d is invaild\n", bar); + break; + } + + ret = pci_ep_test_bar(test, bar); + break; + + case PCITEST_LEGACY_IRQ: + ret = pci_ep_test_legacy_irq(test); + break; + + case PCITEST_MSI: + case PCITEST_MSIX: + ret = pci_ep_test_msi_irq(test, arg, cmd == PCITEST_MSIX); + break; + + case PCITEST_WRITE: + ret = pci_ep_test_write(test, arg); + break; + + case PCITEST_READ: + ret = pci_ep_test_read(test, arg); + break; + + case PCITEST_COPY: + ret = pci_ep_test_copy(test, arg); + break; + + case PCITEST_SET_IRQTYPE: + ret = pci_ep_test_set_irq(test, arg); + break; + + case PCITEST_GET_IRQTYPE: + ret = test->irq_type; + break; + + case PCITEST_CLEAR_IRQ: + ret = pci_ep_test_free_irq(test); + break; + + default: + pcierr("Unspported cmd!!! \n"); + break; + } + + nxmutex_unlock(&test->mutex); + return ret; +} + +/**************************************************************************** + * Name: pci_ep_test_probe + * + * Description: + * Initialize device + * + ****************************************************************************/ + +static int pci_ep_test_probe(FAR struct pci_device_s *dev) +{ + FAR struct pci_ep_test_s *test; + int bar; + int ret; + + pciinfo("Enter pci endpoint test probe.\n"); + + if (pci_is_bridge(dev)) + { + pcierr("pci device is not endpoint!!!\n"); + return -ENODEV; + } + + test = kmm_zalloc(sizeof(*test)); + if (NULL == test) + { + pcierr("malloc ptest memory faild\n"); + return -ENOMEM; + } + + test->pdev = dev; + + nxsem_init(&test->irq_raise, 0, 0); + nxmutex_init(&test->mutex); + + ret = pci_enable_device(dev); + if (ret < 0) + { + pcierr("Enable endpoint device failed, ret=%d\n", ret); + goto en_err; + } + + pci_set_master(dev); + + ret = pci_ep_test_alloc_irq(test, PCI_EP_TEST_IRQ_TYPE_LEGACY); + if (ret < 0) + { + pcierr("Fail to alloc pci irq\n"); + goto irq_err; + } + + for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) + { + if (pci_resource_flags(dev, bar) & PCI_RESOURCE_MEM) + { + test->bar[bar] = pci_map_bar(dev, bar); + if (NULL == test->bar[bar]) + { + pcierr("failed to read bar%d\n", bar); + ret = -ENOMEM; + goto bar_err; + } + } + } + + test->base = test->bar[0]; + + snprintf(test->name, sizeof(test->name), + PCI_EP_TEST_DEVICE_NAME ".%d", g_pci_ep_idr++); + register_driver(test->name, &g_pci_ep_test_fops, 0666, test); + pciinfo("pci ep test device register success.\n"); + + return 0; + +bar_err: + pci_ep_test_free_irq(test); +irq_err: + pci_clear_master(dev); + pci_disable_device(dev); +en_err: + nxmutex_destroy(&test->mutex); + nxsem_destroy(&test->irq_raise); + kmm_free(test); + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pci_register_ep_test_driver + * + * Description: + * Register a pci driver to test endpoint + * + ****************************************************************************/ + +int pci_register_ep_test_driver(void) +{ + return pci_register_driver(&g_pci_ep_test_drv); +} diff --git a/include/nuttx/pci/pci.h b/include/nuttx/pci/pci.h index c83cf76825..2c49e911e4 100644 --- a/include/nuttx/pci/pci.h +++ b/include/nuttx/pci/pci.h @@ -209,6 +209,9 @@ #define pci_map_region(dev, start, size) pci_bus_map_region((dev)->bus, start, size) +#define pci_is_bridge(dev) ((dev)->hdr_type == PCI_HEADER_TYPE_BRIDGE || \ + (dev)->hdr_type == PCI_HEADER_TYPE_CARDBUS) + /**************************************************************************** * Public Types ****************************************************************************/ diff --git a/include/nuttx/pci/pci_ep_test.h b/include/nuttx/pci/pci_ep_test.h index f985edb179..ba4ac4edfe 100644 --- a/include/nuttx/pci/pci_ep_test.h +++ b/include/nuttx/pci/pci_ep_test.h @@ -25,6 +25,8 @@ * Included Files ****************************************************************************/ +#include + /**************************************************************************** * Public Types ****************************************************************************/ @@ -42,4 +44,29 @@ int pci_register_epf_test_device(FAR const char *epc_name); #endif +#define PCITEST_BAR _PCIIOC(0x1) +#define PCITEST_LEGACY_IRQ _PCIIOC(0x2) +#define PCITEST_MSI _PCIIOC(0x3) +#define PCITEST_WRITE _PCIIOC(0x4) +#define PCITEST_READ _PCIIOC(0x5) +#define PCITEST_COPY _PCIIOC(0x6) +#define PCITEST_MSIX _PCIIOC(0x7) +#define PCITEST_SET_IRQTYPE _PCIIOC(0x8) +#define PCITEST_GET_IRQTYPE _PCIIOC(0x9) +#define PCITEST_CLEAR_IRQ _PCIIOC(0x10) + +#define PCITEST_FLAGS_USE_DMA 0x00000001 + +/* struct pci_ep_test_param_s - Params config by user + * + * size: xfer data length + * flag: xfer mode flag + */ + +struct pci_ep_test_param_s +{ + unsigned int size; + unsigned int flags; +}; + #endif /* __INCLUDE_NUTTX_PCI_EP_TEST_H */