forked from nuttx/nuttx-update
pci: add pci endpoint test driver
Signed-off-by: yezhonghui <yezhonghui@xiaomi.com>
This commit is contained in:
parent
9a84484df5
commit
f6db814804
8 changed files with 903 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
840
drivers/pci/pci_ep_test.c
Normal file
840
drivers/pci/pci_ep_test.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <debug.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <nuttx/bits.h>
|
||||
#include <nuttx/crc32.h>
|
||||
#include <nuttx/mm/mm.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/pci/pci.h>
|
||||
#include <nuttx/pci/pci_regs.h>
|
||||
#include <nuttx/pci/pci_ep_test.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -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
|
||||
****************************************************************************/
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
|
||||
/****************************************************************************
|
||||
* 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 */
|
||||
|
|
Loading…
Reference in a new issue