diff options
-rw-r--r-- | driver/ioctl.c | 58 | ||||
-rw-r--r-- | driver/pciDriver.h | 50 | ||||
-rw-r--r-- | pcilib/pci.c | 49 | ||||
-rw-r--r-- | pcilib/pci.h | 5 | ||||
-rw-r--r-- | pcitool/cli.c | 93 |
5 files changed, 234 insertions, 21 deletions
diff --git a/driver/ioctl.c b/driver/ioctl.c index a78d366..e003476 100644 --- a/driver/ioctl.c +++ b/driver/ioctl.c @@ -28,6 +28,9 @@ #include <linux/interrupt.h> #include <linux/wait.h> #include <linux/sched.h> +#include <linux/iommu.h> + +#include "../pcilib/version.h" #include "config.h" /* Configuration for the driver */ #include "compat.h" /* Compatibility functions/definitions */ @@ -409,6 +412,53 @@ static int ioctl_clear_ioq(pcidriver_privdata_t *privdata, unsigned long arg) /** * + * Gets the device and API versions. + * + * @see pcilib_driver_version_t + * + */ +static int ioctl_version(pcidriver_privdata_t *privdata, unsigned long arg) +{ + int ret; + pcilib_driver_version_t info; + + info = (pcilib_driver_version_t) { + .version = PCILIB_VERSION, + .interface = PCIDRIVER_INTERFACE_VERSION, + .ioctls = PCIDRIVER_IOC_MAX + 1 + }; + + WRITE_TO_USER(pcilib_driver_version_t, info); + + return 0; +} + + +/** + * + * Gets current device and driver configuration + * + * @see pcilib_device_state_t + * + */ +static int ioctl_device_state(pcidriver_privdata_t *privdata, unsigned long arg) +{ + int ret; + pcilib_device_state_t info; + + info = (pcilib_device_state_t) { + .iommu = iommu_present(privdata->pdev->dev.bus), + .dma_mask = privdata->pdev->dma_mask + }; + + WRITE_TO_USER(pcilib_device_state_t, info); + + return 0; +} + + +/** + * * Sets DMA mask for the following DMA mappings. * * @param arg Not a pointer, but a number of bits @@ -491,8 +541,14 @@ long pcidriver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case PCIDRIVER_IOC_CLEAR_IOQ: return ioctl_clear_ioq(privdata, arg); + + case PCIDRIVER_IOC_VERSION: + return ioctl_version(privdata, arg); + + case PCIDRIVER_IOC_DEVICE_STATE: + return ioctl_device_state(privdata, arg); - case PCIDRIVER_IOC_SET_DMA_MASK: + case PCIDRIVER_IOC_DMA_MASK: return ioctl_set_dma_mask(privdata, arg); default: diff --git a/driver/pciDriver.h b/driver/pciDriver.h index 845fc15..d314952 100644 --- a/driver/pciDriver.h +++ b/driver/pciDriver.h @@ -58,6 +58,8 @@ #include <linux/ioctl.h> +#define PCIDRIVER_INTERFACE_VERSION 1 /**< Driver API version, only the pcilib with the same driver interface version is allowed */ + /* Identifies the PCI-E Xilinx ML605 */ #define PCIE_XILINX_VENDOR_ID 0x10ee #define PCIE_ML605_DEVICE_ID 0x6024 @@ -119,6 +121,19 @@ #define KMEM_FLAG_REUSED_HW PCILIB_KMEM_FLAG_HARDWARE /**< Indicates that reused buffer had a HW reference before the call */ /* Types */ + +typedef struct { + unsigned long version; /**< pcilib version */ + unsigned long interface; /**< driver interface version */ + unsigned long ioctls; /**< number of supporterd ioctls */ + unsigned long reserved[5]; /**< reserved for the future use */ +} pcilib_driver_version_t; + +typedef struct { + unsigned long iommu; + unsigned long dma_mask; +} pcilib_device_state_t; + typedef struct { unsigned short vendor_id; unsigned short device_id; @@ -193,31 +208,34 @@ typedef struct { * This type is only 8-bits wide, and half-documented in * <linux-src>/Documentation/ioctl-number.txt. * previous SHL -> 'S' definition, conflicts with several devices, - * so I changed it to be pci -> 'p', in the range 0xA0-AF + * so I changed it to be pci -> 'p', in the range 0xA0-BF */ #define PCIDRIVER_IOC_MAGIC 'p' #define PCIDRIVER_IOC_BASE 0xA0 -#define PCIDRIVER_IOC_MMAP_MODE _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 0 ) -#define PCIDRIVER_IOC_MMAP_AREA _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 1 ) -#define PCIDRIVER_IOC_KMEM_ALLOC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 2, kmem_handle_t * ) -#define PCIDRIVER_IOC_KMEM_FREE _IOW ( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 3, kmem_handle_t * ) -#define PCIDRIVER_IOC_KMEM_SYNC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 4, kmem_sync_t * ) -#define PCIDRIVER_IOC_UMEM_SGMAP _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 5, umem_handle_t * ) -#define PCIDRIVER_IOC_UMEM_SGUNMAP _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 6, umem_handle_t * ) -#define PCIDRIVER_IOC_UMEM_SGGET _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 7, umem_sglist_t * ) -#define PCIDRIVER_IOC_UMEM_SYNC _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 8, umem_handle_t * ) -#define PCIDRIVER_IOC_WAITI _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 9 ) +#define PCIDRIVER_IOC_MMAP_MODE _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 0 ) +#define PCIDRIVER_IOC_MMAP_AREA _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 1 ) +#define PCIDRIVER_IOC_KMEM_ALLOC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 2, kmem_handle_t * ) +#define PCIDRIVER_IOC_KMEM_FREE _IOW ( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 3, kmem_handle_t * ) +#define PCIDRIVER_IOC_KMEM_SYNC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 4, kmem_sync_t * ) +#define PCIDRIVER_IOC_UMEM_SGMAP _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 5, umem_handle_t * ) +#define PCIDRIVER_IOC_UMEM_SGUNMAP _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 6, umem_handle_t * ) +#define PCIDRIVER_IOC_UMEM_SGGET _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 7, umem_sglist_t * ) +#define PCIDRIVER_IOC_UMEM_SYNC _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 8, umem_handle_t * ) +#define PCIDRIVER_IOC_WAITI _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 9 ) /* And now, the methods to access the PCI configuration area */ -#define PCIDRIVER_IOC_PCI_CFG_RD _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 10, pci_cfg_cmd * ) -#define PCIDRIVER_IOC_PCI_CFG_WR _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 11, pci_cfg_cmd * ) -#define PCIDRIVER_IOC_PCI_INFO _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 12, pcilib_board_info_t * ) +#define PCIDRIVER_IOC_PCI_CFG_RD _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 10, pci_cfg_cmd * ) +#define PCIDRIVER_IOC_PCI_CFG_WR _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 11, pci_cfg_cmd * ) +#define PCIDRIVER_IOC_PCI_INFO _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 12, pcilib_board_info_t * ) /* Clear interrupt queues */ -#define PCIDRIVER_IOC_CLEAR_IOQ _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 13 ) +#define PCIDRIVER_IOC_CLEAR_IOQ _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 13 ) -#define PCIDRIVER_IOC_SET_DMA_MASK _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 14 ) +#define PCIDRIVER_IOC_VERSION _IOR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 14, pcilib_driver_version_t * ) +#define PCIDRIVER_IOC_DEVICE_STATE _IOR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 15, pcilib_device_state_t * ) +#define PCIDRIVER_IOC_DMA_MASK _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 16) +#define PCIDRIVER_IOC_MAX 16 #endif diff --git a/pcilib/pci.c b/pcilib/pci.c index e45aaba..26dfdbf 100644 --- a/pcilib/pci.c +++ b/pcilib/pci.c @@ -108,6 +108,7 @@ static int pcilib_detect_model(pcilib_t *ctx, const char *model) { pcilib_t *pcilib_open(const char *device, const char *model) { int err, xmlerr; pcilib_t *ctx = malloc(sizeof(pcilib_t)); + const pcilib_driver_version_t *drv_version; if (!model) model = getenv("PCILIB_MODEL"); @@ -123,6 +124,13 @@ pcilib_t *pcilib_open(const char *device, const char *model) { return NULL; } + drv_version = pcilib_get_driver_version(ctx); + if (!drv_version) { + pcilib_error("Driver verification has failed (%s)", device); + free(ctx); + return NULL; + } + ctx->page_mask = (uintptr_t)-1; if ((model)&&(!strcasecmp(model, "maintenance"))) { @@ -224,6 +232,34 @@ pcilib_t *pcilib_open(const char *device, const char *model) { } +const pcilib_driver_version_t *pcilib_get_driver_version(pcilib_t *ctx) { + int ret; + + if (!ctx->driver_version.version) { + ret = ioctl( ctx->handle, PCIDRIVER_IOC_VERSION, &ctx->driver_version ); + if (ret) { + pcilib_error("PCIDRIVER_IOC_DRIVER_VERSION ioctl have failed"); + return NULL; + } + + if (ctx->driver_version.interface != PCIDRIVER_INTERFACE_VERSION) { + pcilib_error("Using pcilib (version: %u.%u.%u, driver interface: 0x%lx) with incompatible driver (version: %u.%u.%u, interface: 0x%lx)", + PCILIB_VERSION_GET_MAJOR(PCILIB_VERSION), + PCILIB_VERSION_GET_MINOR(PCILIB_VERSION), + PCILIB_VERSION_GET_MICRO(PCILIB_VERSION), + PCIDRIVER_INTERFACE_VERSION, + PCILIB_VERSION_GET_MAJOR(ctx->driver_version.version), + PCILIB_VERSION_GET_MINOR(ctx->driver_version.version), + PCILIB_VERSION_GET_MICRO(ctx->driver_version.version), + ctx->driver_version.interface + ); + return NULL; + } + } + + return &ctx->driver_version; +} + const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) { int ret; @@ -236,7 +272,7 @@ const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) { ctx->page_mask = pcilib_get_page_mask(); } - + return &ctx->board_info; } @@ -432,8 +468,17 @@ const pcilib_pcie_link_info_t *pcilib_get_pcie_link_info(pcilib_t *ctx) { return &ctx->link_info; } +int pcilib_get_device_state(pcilib_t *ctx, pcilib_device_state_t *state) { + int ret = ioctl( ctx->handle, PCIDRIVER_IOC_DEVICE_STATE, state); + if (ret < 0) { + pcilib_error("PCIDRIVER_IOC_DEVICE_STATE ioctl have failed"); + return PCILIB_ERROR_FAILED; + } + return 0; +} + int pcilib_set_dma_mask(pcilib_t *ctx, int mask) { - if (ioctl( ctx->handle, PCIDRIVER_IOC_SET_DMA_MASK, mask ) < 0) + if (ioctl(ctx->handle, PCIDRIVER_IOC_DMA_MASK, mask) < 0) return PCILIB_ERROR_FAILED; return 0; diff --git a/pcilib/pci.h b/pcilib/pci.h index bf977fc..b81d295 100644 --- a/pcilib/pci.h +++ b/pcilib/pci.h @@ -48,6 +48,7 @@ struct pcilib_s { int handle; /**< file handle of device */ uintptr_t page_mask; /**< Selects bits which define offset within the page */ + pcilib_driver_version_t driver_version; /**< Version reported by the driver */ pcilib_board_info_t board_info; /**< The mandatory information about board as defined by PCI specification */ pcilib_pcie_link_info_t link_info; /**< Infomation about PCIe connection */ char *bar_space[PCILIB_MAX_BARS]; /**< Pointers to the mapped BARs in virtual address space */ @@ -112,8 +113,12 @@ extern "C" { #endif pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx); + +const pcilib_driver_version_t *pcilib_get_driver_version(pcilib_t *ctx); const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx); const pcilib_pcie_link_info_t *pcilib_get_pcie_link_info(pcilib_t *ctx); +int pcilib_get_device_state(pcilib_t *ctx, pcilib_device_state_t *state); + int pcilib_map_register_space(pcilib_t *ctx); int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr); diff --git a/pcitool/cli.c b/pcitool/cli.c index 8943347..65e24dc 100644 --- a/pcitool/cli.c +++ b/pcitool/cli.c @@ -74,6 +74,7 @@ typedef enum { typedef enum { MODE_INVALID, + MODE_VERSION, MODE_INFO, MODE_LIST, MODE_BENCHMARK, @@ -95,6 +96,7 @@ typedef enum { MODE_DISABLE_IRQ, MODE_ACK_IRQ, MODE_WAIT_IRQ, + MODE_SET_DMASK, MODE_ALLOC_KMEM, MODE_LIST_KMEM, MODE_READ_KMEM, @@ -148,7 +150,8 @@ typedef enum { OPT_GRAB = 'g', OPT_QUIETE = 'q', OPT_HELP = 'h', - OPT_RESET = 128, + OPT_VERSION = 128, + OPT_RESET, OPT_BENCHMARK, OPT_TRIGGER, OPT_DATA_TYPE, @@ -169,6 +172,7 @@ typedef enum { OPT_ACK_IRQ, OPT_WAIT_IRQ, OPT_ITERATIONS, + OPT_SET_DMASK, OPT_ALLOC_KMEM, OPT_LIST_KMEM, OPT_FREE_KMEM, @@ -222,6 +226,7 @@ static struct option long_options[] = { {"disable-irq", optional_argument, 0, OPT_DISABLE_IRQ }, {"acknowledge-irq", optional_argument, 0, OPT_ACK_IRQ }, {"wait-irq", optional_argument, 0, OPT_WAIT_IRQ }, + {"set-dma-mask", required_argument, 0, OPT_SET_DMASK }, {"list-kernel-memory", optional_argument, 0, OPT_LIST_KMEM }, {"read-kernel-memory", required_argument, 0, OPT_READ_KMEM }, {"alloc-kernel-memory", required_argument, 0, OPT_ALLOC_KMEM }, @@ -239,6 +244,7 @@ static struct option long_options[] = { {"verify", no_argument, 0, OPT_VERIFY }, {"multipacket", no_argument, 0, OPT_MULTIPACKET }, {"wait", no_argument, 0, OPT_WAIT }, + {"version", no_argument, 0, OPT_VERSION }, {"help", no_argument, 0, OPT_HELP }, { 0, 0, 0, 0 } }; @@ -268,6 +274,7 @@ void Usage(int argc, char *argv[], const char *format, ...) { " -w <addr|dmaX|reg|prop> - Write Data/Register/Property\n" " --benchmark <barX|dmaX> - Performance Evaluation\n" " --reset - Reset board\n" +" --version - Version information\n" " --help - Help message\n" "\n" " Property/Register Modes:\n" @@ -297,6 +304,7 @@ void Usage(int argc, char *argv[], const char *format, ...) { " --read-dma-buffer <dma:buf> - Read the specified buffer\n" "\n" " Kernel Modes:\n" +" --set-dma-mask [bits] - Set DMA address width (DANGEROUS)\n" " --list-kernel-memory [use] - List kernel buffers\n" " --read-kernel-memory <blk> - Read the specified block of the kernel memory\n" " block is specified as: use:block_number\n" @@ -840,6 +848,49 @@ void RegisterInfo(pcilib_t *handle, pcilib_register_t reg) { pcilib_free_register_info(handle, info); } +void Version(pcilib_t *handle, const pcilib_model_description_t *model_info) { + const pcilib_driver_version_t *driver_version; + + driver_version = pcilib_get_driver_version(handle); + + printf("pcilib version: %u.%u.%u\n", + PCILIB_VERSION_GET_MAJOR(PCILIB_VERSION), + PCILIB_VERSION_GET_MINOR(PCILIB_VERSION), + PCILIB_VERSION_GET_MICRO(PCILIB_VERSION) + ); + + printf("driver version: %lu.%lu.%lu, interface: 0x%lx, registered ioctls: %lu\n", + PCILIB_VERSION_GET_MAJOR(driver_version->version), + PCILIB_VERSION_GET_MINOR(driver_version->version), + PCILIB_VERSION_GET_MICRO(driver_version->version), + driver_version->interface, + driver_version->ioctls + ); + + if (model_info) { + pcilib_version_t version = model_info->interface_version; + printf("Model: %s", handle->model); + if (version) { + printf(", version: %u.%u.%u\n", + PCILIB_VERSION_GET_MAJOR(version), + PCILIB_VERSION_GET_MINOR(version), + PCILIB_VERSION_GET_MICRO(version) + ); + } else { + printf(" (embedded)\n"); + } + } + + if (model_info->dma) { + pcilib_version_t version = model_info->dma->api->version; + printf("DMA Engine: %s, version: %u.%u.%u\n", model_info->dma->name, + PCILIB_VERSION_GET_MAJOR(version), + PCILIB_VERSION_GET_MINOR(version), + PCILIB_VERSION_GET_MICRO(version) + ); + } +} + void Info(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *target) { int i, j; DIR *dir; @@ -850,14 +901,33 @@ void Info(pcilib_t *handle, const pcilib_model_description_t *model_info, const const pcilib_board_info_t *board_info = pcilib_get_board_info(handle); const pcilib_pcie_link_info_t *link_info = pcilib_get_pcie_link_info(handle); + int have_state; + pcilib_device_state_t state; + path = getenv("PCILIB_PLUGIN_DIR"); if (!path) path = PCILIB_PLUGIN_DIR; + have_state = !pcilib_get_device_state(handle, &state); + if (board_info) printf("Vendor: %x, Device: %x, Bus: %x, Slot: %x, Function: %x, Model: %s\n", board_info->vendor_id, board_info->device_id, board_info->bus, board_info->slot, board_info->func, handle->model); if (link_info) { - printf(" PCIe x%u (gen%u), DMA Payload: %u (of %u)\n", link_info->link_width, link_info->link_speed, 1<<link_info->payload, 1<<link_info->max_payload); + printf(" PCIe x%u (gen%u), DMA Payload: %u (of %u)", link_info->link_width, link_info->link_speed, 1<<link_info->payload, 1<<link_info->max_payload); + if (have_state) { + int bits = 0; + unsigned long mask; + + for (mask = state.dma_mask; mask&1; mask>>=1) bits++; + + printf(", DMA Mask: "); + + if (mask) printf("0x%lx", state.dma_mask); + else printf("%u bits", bits); + + printf(", IOMMU: %s", state.iommu?"on":"off"); + } + printf("\n"); } if (board_info) @@ -3018,6 +3088,8 @@ int main(int argc, char **argv) { FILE *ofile = NULL; size_t iterations = BENCHMARK_ITERATIONS; + unsigned long dma_mask = 0; + pcilib_t *handle; int size_set = 0; @@ -3032,6 +3104,10 @@ int main(int argc, char **argv) { case OPT_HELP: Usage(argc, argv, NULL); break; + case OPT_VERSION: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + mode = MODE_VERSION; + break; case OPT_INFO: if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); @@ -3207,6 +3283,13 @@ int main(int argc, char **argv) { irq_source = itmp; } break; + case OPT_SET_DMASK: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + mode = MODE_SET_DMASK; + + if ((!isnumber(optarg))||(sscanf(optarg, "%lu", &dma_mask) != 1)||(dma_mask<24)||(dma_mask>64)) + Usage(argc, argv, "Invalid DMA mask is specified (%s)", optarg); + break; case OPT_LIST_KMEM: if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); mode = MODE_LIST_KMEM; @@ -3729,6 +3812,9 @@ int main(int argc, char **argv) { } switch (mode) { + case MODE_VERSION: + Version(handle, model_info); + break; case MODE_INFO: Info(handle, model_info, info_target); break; @@ -3799,6 +3885,9 @@ int main(int argc, char **argv) { case MODE_WAIT_IRQ: WaitIRQ(handle, model_info, irq_source, timeout); break; + case MODE_SET_DMASK: + pcilib_set_dma_mask(handle, dma_mask); + break; case MODE_LIST_KMEM: if (use) DetailKMEM(handle, fpga_device, use, block); else ListKMEM(handle, fpga_device); |