/* * ***************************************************************** * * * * * Copyright Compaq Computer Corporation, 2000 * * * * * * The software contained on this media is proprietary to * * * and embodies the confidential technology of Compaq * * * Computer Corporation. Possession, use, duplication or * * * dissemination of the software and media is authorized only * * * pursuant to a valid written license from Compaq Computer * * * Corporation. * * * * * * RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure * * * by the U.S. Government is subject to restrictions as set * * * forth in Subparagraph (c)(1)(ii) of DFARS 252.227-7013, * * * or in FAR 52.227-19, as applicable. * * * * * ***************************************************************** */ /* * HISTORY * Added software byte swap capabilites to the driver. * * Added mmap support for PCI linear space addressing. * * Example routine, dmaex_mmap_bw_test, was added to * show byte/word addressing to PCI linear space. * * Added driver ioctl commands for GET_HW_BYTE_SWAP_INFO * and GET_VBA_BUS_TYPE_INFO. These ioctl commands determine * the capabilities of the VME adapter. * * Call Tru64 UNIX getsysinfo routine to determine if * platform supports byte/word addressing. * * Two additional parameters were added to most test * routines. These parameters indicate the byte swap * mode and if software byte swap is needed. */ #pragma ident "@(#)$RCSfile: dmaex_test.c,v $ $Revision: 1.1.2.5 $ (DEC) $Date: 1997/04/16 15:36:04 $" /* * Compaq Computer Corporation supplies this software example on an * "as-is" basis for general customer use. Note that COMPAQ does * not offer any support for it, nor is it covered under any of COMPAQ's * support contracts. * * The dmaex_test.c program is used to test the various functionality of the * dmaex.c VME fictitious device driver. This program and the associated * driver have been tested on the Alpha VME 2100, the Alpha VME 4/224, * 4/288, 5/352, 5/480 and the AXPvme systems. It has not been tested * on other PCI to VME adapters. * * The driver has been tested with two of the above VME systems in the * VME backplane. One system was used to place its memory on the VMEbus, * and the other system was used to transfer data to and from its memory. * Posting of VME interrupts between the two systems was also verified. * * NOTE: It is not guaranteed that the mmap test in this program and * the mmap support in the device driver will work with other * PCI based systems that include a PCI to VME bus adapter or * future PCI systems that may include the same or new VME bus * adapter. * * The program, dmaex_test.c, includes tests for the following: * o Exercise sparse and dense mmap capabilites of the dmaex.c device driver. * o Exercise linear address mmap capabilites on byte/word capable processors. * o Transfer data using Tru64 UNIX "read" and "write" driver routines. * o transfer data using programed I/O * o transfer data using the VME adapter's hardware DMA engine to * perform Master Block DMA transfers * o transfer data using the VME device's hardware DMA engine * o Map system memory onto the VMEbus and wait for a "psignal" * from the dmaex.c driver on detection of a VMEbus interrupt. * o Perform DMA reads and writes to user space buffers using * the VME adapter's DMA engine and the dmaex.c driver's ioctl * commands. The user buffers are wired down during the DMA transfer. * o Perform DMA reads and writes to kernel physically contiguous * buffers that are "mmaped" into user space. This test uses the VME * adapter's DMA engine and the dmaex.c driver's ioctl commands and * mmap routines. * o Post an interrupt to the VMEbus and wait for the interrupt * request to be acknowledged. * o Clear a previously posted VME interrupt request * * Refer to the "main" section of this program for a description of the nine * tests and the parameters that each test expects to be passed to it. * Refer to the individual tests routines and the dmaex.c device driver * to see how the test code and driver interact and perform the designated * actions. * * Parameters for each of the tests can be requested interactively or * specified at program startup on the command line. * * If test parameters are specified on the command line, refer to the VME * definition file, /sys/include/io/dec/vme/vbareg.h, for the VME address * modifiers, data size, byte swap mode, and dense mapping values. * * If a selected test uses the VME adapter's hardware DMA engine for * block mode DMA transfers, a data size of VME_D16, VME_D32 or VME_D64 * must be specified. A data size selection of VME_D08, VME_D16, or VME_D32 * is not needed, but recommended, for mapping outbound to a VMEbus address * space or mapping system memory to the VMEbus. This is needed to maintain * compatibility with other VME adapters and possibly future VME adapters. * * To run, select the test, and specify the test parameters interactively, * type the following command at the 'csh' prompt: * * ./dmaex_test * * The dmaex_test.c program will interrogate the user for each of the * desired parameters. Once the last parameter has been specified, the * selected test will be executed. * * To run, select the test, and specify the test parameters from the * command line, type in a command line similar to what follows: * * ./dmaex_test arg1 arg2 arg3 arg4 arg5 arg6 * * - arg1 selects the test to run. A valid test number is from 1 to 9. * - arg2, arg3, arg4, arg5, and arg6 represent the data.data[0], * data.data[1], data.data[2], data.data[3] and data.data[4] arguments * that are described in the "main" section of this program before * calling the specified test. The number of arguments passed to each * test varies. * * As an example, to run the mmap test to some 1mb (0x100000) memory on * the VMEbus at address 0x200000 in A24 User Data Address Space with a * data size of D32 and a byte swap mode of VME_BS_LWORD, type in the * following command: * * ./dmaex_test 1 0x100000 0x200000 0x03b90000 * * The last argument represents the address modifier, data size, and * byte swap mode. Refer to file /sys/include/io/dec/vme/vbareg.h for * appropriate values. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dmaexreg.h" /* * Define a macro for the cpu's memory barrier instruction */ #define mb() asm("mb") /* * The byte/word macros are included for Tru64 UNIX * versions V4.0D and above. The HANDLE_LINEAR_SPACE flag * was added to io/common/devdriver.h in version Tru64 V4.0D. */ #ifdef HANDLE_LINEAR_SPACE #define stb(addr,data) (asm(".arch ev56; stb %a1, 0(%a0)",addr,data)) #define ldbu(addr) (asm(".arch ev56; ldbu %v0, 0(%a0)",addr)) #define stw(addr,data) (asm(".arch ev56; stw %a1, 0(%a0)",addr,data)) #define ldwu(addr) (asm(".arch ev56; ldwu %v0, 0(%a0)",addr)) #endif extern int errno; /* * The following data structure will be used to pass information * to and from the "/dev/dmaex0" kernel mode device driver. */ struct dmaex_ioctl_data data; /* * Forward declarations */ int dmaex_sw_byte_swap(int *, int *, int, vme_atype_t); int dmaex_mmap_test(int, struct dmaex_ioctl_data *, int, vme_atype_t); int dmaex_mmap_bw_test(int, struct dmaex_ioctl_data *, int, vme_atype_t); int dmaex_strategy_dma_block_xfer_test(int, struct dmaex_ioctl_data *, int, vme_atype_t); int dmaex_strategy_pio_xfer_test(int, struct dmaex_ioctl_data *, int, vme_atype_t); int dmaex_strategy_device_dma_xfer_test(int, struct dmaex_ioctl_data *); void dmaex_sig_catcher(int); void dmaex_sigsetup(); int dmaex_map_unmap_sys_mem_test(int, struct dmaex_ioctl_data *, int, vme_atype_t); int dmaex_dma_to_from_user_buffers(int, struct dmaex_ioctl_data *, int, vme_atype_t); int dmaex_dma_to_from_kernel_buffers(int, struct dmaex_ioctl_data *, int, vme_atype_t); void select_msg(int, struct dmaex_ioctl_data *); void request_bus_mapping_info(struct dmaex_ioctl_data *, int); int request_test_parameters(struct dmaex_ioctl_data *); /* * Define a MACRO to calculate the offset into the address returned * from mmap(), at which the specified VME address is mapped -- ie * in order to find the exact virtual address of where the VME address * is mapped to, the user must add the calculated offset to the mmap() * return address. * * For Dense space mappings, the offset into the mmap()'d address * is exactly the VME address MODULO one alpha page (8192 dec, ie 0x2000). * ie for VME_PIO_ADDRESS 0xA40140 you would add 0x140 to the * mmap() address to access byte 0 of the mapped VME address area. * * For Sparse space mappings, the offset into the mmap()'d address * is exactly the VME address MODULO 256kb (ie 0x100), * the result of which is multiplied by 32 decimal (due to the layout * of sparse mappings on an Alpha AXPvme which has one valid byte for * every 32 bytes). * ie for VME_PIO_ADDRESS 0xA40140 you would add (0x40 * 32) = 0x800 * to the mmap() address to access byte 0 of the mapped VME address * area. */ #define get_offset(vme_address,vme_am) \ ((vme_am) & VME_DENSE) ? ((vme_address) % 0x2000) : (((vme_address) % 0x100) * 32) /* * Define MACROs for manipulating mmap'd memory in sparse space * for the AXPvme platform. */ #define read_shift(address,data,width) \ { data = ( (data >> ((address & 3) << 3)) & \ ( (1 << ((8*width)-1)) + ((1L << ((8*width)-1L))-1L) ) ); } #define read_sparse_byte(base, offset, dest) { \ unsigned char *va; \ unsigned long data=0; \ va = (unsigned char *) ((((u_long)offset) << 5) + \ ((u_long)base )); \ data = (unsigned long) *(int *)va; \ read_shift(((u_long)offset & 3), data, 1); \ dest = (unsigned char) data; } #define read_sparse_word(base, offset, dest) { \ unsigned short *va; \ unsigned long data=0; \ va = (unsigned short *) ((((u_long)offset) << 5) + \ ((u_long)base ) | 8); \ data = (unsigned long) *(int *)va; \ read_shift(((u_long)offset & 3), data, 2); \ dest = (unsigned short) data; } #define read_sparse_int(base, offset, dest) { \ unsigned int *va; \ unsigned long data=0; \ va = (unsigned int *) ((((u_long)offset) << 5) + \ ((u_long)base ) | 0x18); \ data = (unsigned long) *(int *)va; \ read_shift(((u_long)offset & 3), data, 4); \ dest = (unsigned int) data; } #define write_sparse_byte(base, offset,data) { \ unsigned char *va; \ unsigned long write_data = \ (unsigned long) data << (((u_long)offset & 3) << 3); \ va = (unsigned char *) ((((u_long)offset) << 5) + \ ((u_long)base )); \ *(int *)va = write_data; \ (void)asm("mb"); } #define write_sparse_word(base,offset,data) { \ unsigned short *va; \ unsigned long write_data = \ (unsigned long) data << (((u_long)offset & 3) << 3); \ va = (unsigned short *) ((((u_long)offset) << 5) + \ ((u_long)base ) | 8); \ *(int *)va = write_data; \ (void)asm("mb"); } #define write_sparse_int(base, offset, data) { \ unsigned int *va; \ unsigned long write_data = \ (unsigned long) data << (((u_long)offset & 3) << 3); \ va = (unsigned int *) ((((u_long)offset) << 5) + \ ((u_long)base ) | 0x18); \ *(int *)va = write_data; \ (void)asm("mb"); } /* * For sparse space mapping, one byte every 32 bytes is valid. */ #define PAGE_MULT 32 /**************************************** * swap word bytes: * * * * swap_word_bytes is also provided as * * a kernel routine for use by device * * drivers. * * * * 31 0 * * +---+---+---+---+ * * start with: | a | b | c | d | * * +---+---+---+---+ * * * * 31 0 * * end with: +---+---+---+---+ * * | b | a | d | c | * * +---+---+---+---+ * * * * swap bytes within words * * * * PCI byte[0] -> VME byte[1] * * PCI byte[1] -> VME byte[0] * * PCI byte[2] -> VME byte[3] * * PCI byte[3] -> VME byte[2] * * * ****************************************/ #define swap_word_bytes(data) \ (u_int)((((u_int)data >> 8) & 0xFF) | \ (((u_int)data & 0xFF) << 8) | \ ((((u_int)data >> 16) & 0xFF) << 24) | \ ((((u_int)data >> 24) & 0xFF) << 16)) /**************************************** * swap words: * * * * swap_words is also provided as a * * kernel routine for use by device * * drivers. * * * * 31 0 * * +---+---+---+---+ * * start with: | a | b | c | d | * * +---+---+---+---+ * * * * 31 0 * * end with: +---+---+---+---+ * * | c | d | a | b | * * +---+---+---+---+ * * * * swap words within long words * * * * PCI byte[0] -> VME byte[2] * * PCI byte[1] -> VME byte[3] * * PCI byte[2] -> VME byte[0] * * PCI byte[3] -> VME byte[1] * * * ****************************************/ #define swap_words(data) \ (u_int)((((u_int)data >> 16) & 0xFFFF) | \ (((u_int)data & 0xFFFF) << 16)) /**************************************** * swap long word bytes: * * * * swap_lw_bytes is also provided as a * * kernel routine for use by device * * drivers. * * * * 31 0 * * +---+---+---+---+ * * start with: | a | b | c | d | * * +---+---+---+---+ * * * * 31 0 * * end with: +---+---+---+---+ * * | d | c | b | a | * * +---+---+---+---+ * * * * swap bytes within words and * * swap words within long word * * * * PCI byte[0] -> VME byte[3] * * PCI byte[1] -> VME byte[2] * * PCI byte[2] -> VME byte[1] * * PCI byte[3] -> VME byte[0] * * * ****************************************/ #define swap_lw_bytes(data) \ (u_int)(((((((u_int)data >> 8) & 0xFF) | \ (((u_int)data & 0xFF) << 8)) << 16) | \ (((u_int)data >> 24) & 0xFF) | \ ((((u_int)data >> 16) & 0xFF) << 8))) /******************************************************** * swap quad long word bytes: * * * * There is no corresponding kernel routine for quad * * word swap. Device drivers must use the kernel * * routine swap_lw_bytes and address manipulation to * * emulate D64 quad word swap. See example routine * * dmaex_sw_byte_swap below for software emulation of * * VME_BS_QUAD hardware swap. * * * * 63 0 * * +---+---+---+---+---+---+---+---+ * * start with: | a | b | c | d | e | f | g | h | * * +---+---+---+---+---+---+---+---+ * * * * 63 0 * * end with: +---+---+---+---+---+---+---+---+ * * | h | g | f | e | d | c | b | a | * * +---+---+---+---+---+---+---+---+ * * * * swap bytes within words * * swap words within long word * * swap long words within quad word * * * * PCI byte[0] -> VME byte[7] * * PCI byte[1] -> VME byte[6] * * PCI byte[2] -> VME byte[5] * * PCI byte[3] -> VME byte[4] * * PCI byte[4] -> VME byte[3] * * PCI byte[5] -> VME byte[2] * * PCI byte[6] -> VME byte[1] * * PCI byte[7] -> VME byte[0] * * * ********************************************************/ /***************************************************** * dmaex_sw_byte_swap * *****************************************************/ int dmaex_sw_byte_swap(int *src, int *dst, int bc, vme_atype_t byte_swap_mode) { int i,tmp1,tmp; int cnt_of_lwords = (bc/sizeof(int)); if (bc % sizeof(int)) { printf("dmaex_sw_byte_swap: byte count %d not multiple of %d\n", bc,sizeof(int)); return(0); } if (((u_long)src & 3UL) || ((u_long)dst & 3UL)) { printf("dmaex_sw_byte_swap: buffers must be long word aligned\n"); return(0); } if ((byte_swap_mode == VME_BS_QUAD) && (bc % sizeof(long))) { printf ("dmaex_sw_byte_swap: VME_BS_QUAD byte count %d not multiple of %d\n", bc,sizeof(long)); return(0); } switch (byte_swap_mode) { case VME_BS_NOSWAP: /**************************************** * exact copy of data * ****************************************/ for(i = 0; i < cnt_of_lwords; i++, src++, dst++) *dst = *src; break; case VME_BS_BYTE: /**************************************** * swap bytes within words * ****************************************/ for(i = 0; i < cnt_of_lwords; i++, src++, dst++) *dst = (int)swap_word_bytes(*(u_int *)src); break; case VME_BS_WORD: /**************************************** * swap words within long words * ****************************************/ for(i = 0; i < cnt_of_lwords; i++, src++, dst++) *dst = (int)swap_words(*(u_int *)src); break; case VME_BS_LWORD: /**************************************** * swap bytes within words and * * swap words within long word * ****************************************/ for(i = 0; i < cnt_of_lwords; i++, src++, dst++) *dst = (int)swap_lw_bytes(*(u_int *)src); break; case VME_BS_QUAD: /**************************************** * swap bytes within words and * * swap words within long word and * * swap long words within quad word * ****************************************/ for(i = 0; i < cnt_of_lwords; i += 2) { tmp1 = (int)swap_lw_bytes((u_int)src[i]); tmp = (int)swap_lw_bytes((u_int)src[i+1]); dst[i] = tmp; dst[i+1] = tmp1; } break; default: printf("Byte swap mode 0x%x invalid\n",byte_swap_mode); } return(1); } /***************************************************** * dmaex_mmap_test * *****************************************************/ int dmaex_mmap_test(int fd, struct dmaex_ioctl_data *data, int sw_byte_swap_needed, vme_atype_t byte_swap_mode) { unsigned char *read_byte_data, *write_byte_data, *byte_vaddr; unsigned short *read_word_data, *write_word_data, *word_vaddr; unsigned int *read_int_data, *write_int_data, *int_vaddr; unsigned long *read_quad_data, *write_quad_data, *quad_vaddr; int *read_buffer = NULL; int *write_buffer = NULL; int *wrt_buffer = NULL; unsigned char *wrt_byte_data = NULL; int buf_size,err,i,j; vme_addr_t vme_addr; vme_atype_t vme_am; u_int vme_size; u_int vme_access; io_handle_t vme_iohandle; u_long offset_from_base = 0; size_t len; int *mapped_va; /* address of start of mapped area */ int *bufp; /* address of start of buffer in mapped area */ caddr_t status; int byte_swap_needed = 0; /* * Use default values if byte count or VME address modifiers not specified */ if ( (!data->data[0]) || (!(data->data[2] & VME_BITS_MASK)) ) { printf("No test parameters specified\n"); return(1); } buf_size = (int)data->data[0]; /* * If software byte swap is needed, set flag. */ if ((sw_byte_swap_needed) && (byte_swap_mode != VME_BS_NOSWAP)) byte_swap_needed = 1; /* * Allocate write buffer to test the mapping */ write_buffer = (int *)malloc(buf_size); if(!(write_buffer)) { perror("write malloc failed for write_buffer"); return(1); } /* * Allocate a buffer to contain the actual * write data. If software byte swap was not * needed or selected, this buffer will contain * the same data as the write buffer, otherwise, * it will contain the byte swap data. */ wrt_buffer = (int *)malloc(buf_size); if(!(wrt_buffer)) { free(write_buffer); perror("write malloc failed for wrt_buffer"); return(1); } /* * Initialize both write buffers with same data */ write_byte_data = (unsigned char *)write_buffer; wrt_byte_data = (unsigned char *)wrt_buffer; for (i = 0, j = 0; i < buf_size; i++, j = i/256) { write_byte_data[i] = (unsigned char)(i + j); wrt_byte_data[i] = (unsigned char)(i + j); } /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the write data as 32 bit integer * values based on the specified byte swap mode. The "write_buffer" will * contain original data pattern and the "wrt_buffer" will contain the * byte swaped data. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(write_buffer, wrt_buffer, buf_size, byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); perror("Error detected swapping write data"); return(1); } } /* * Allocate read buffer to test the mapping */ read_buffer = (int *)malloc(buf_size); if (!(read_buffer)) { free(write_buffer); free(wrt_buffer); perror("read malloc failed"); return(1); } /* SETUP_VME_FOR_MMAP_PIO ioctl command does an outbound mapping to * a VMEbus adddress for the specified size with the specified * address modifiers. The driver maps outbound on the VME to the * exact buffer size, but the user then mmap's to ((32 * buf_size) + offset) * for SPARSE accesses or to the actual (buf_size + offset) for DENSE * accesses. It doesn't matter what the access type is, since the macros * does the correct manipulations for sparse space. * data->data[0] = Number of bytes to be mapped on the VMEbus * data->data[1] = Starting VMEbus address to be mapped * data->data[2] = VMEbus address modifiers (bits 32:16) * data->data[3] = Access type sparse or dense */ /* * Force access type to sparse space or dense space */ if (data->data[2] & VME_DENSE) data->data[3] = (unsigned long)(HANDLE_LONGWORD | HANDLE_DENSE_SPACE); else data->data[3] = (unsigned long)(HANDLE_LONGWORD | HANDLE_SPARSE_SPACE); if ((err = ioctl(fd, SETUP_VME_FOR_MMAP_PIO, data)) != 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("SETUP_VME_FOR_MMAP_PIO"); return(1); } printf("Successfully mapped the VME address to "); if (data->data[2] & VME_DENSE) printf("dense space\n"); else printf("sparse space\n"); if ((err = ioctl(fd, GET_VME_INFO_FOR_MMAP_PIO, data)) != 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("GET_VME_INFO_FOR_MMAP_PIO"); if ((err = ioctl(fd, UNMAP_VME_FOR_MMAP_PIO, data)) != 0) perror("UNMAP_VME_FOR_MMAP_PIO"); return(1); } printf("PIO mapping info: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" PIO Access value = 0x%x\n",(unsigned int)data->data[3]); printf(" PIO I/O handle = 0x%lx\n",data->data[4]); /* * Save VME outbound mapping information */ vme_size = (unsigned int)data->data[0]; vme_addr = (vme_addr_t)data->data[1]; vme_am = (vme_atype_t)data->data[2]; vme_access = (unsigned int)data->data[3]; vme_iohandle = data->data[4]; /* * Setup dmaex_mmap routine to manipulate the mapped VME address space */ data->data[0] = (unsigned long)MMAP_VME_TO_U_MEM; if ( ioctl(fd, SET_MMAP_MODE, data) != 0 ) perror("error in ioctl SET_MMAP_MODE"); if ( ioctl(fd, GET_MMAP_MODE, data) != 0 ) perror("error in ioctl GET_MMAP_MODE"); switch ((int)data->data[0]) { case MMAP_VME_TO_U_MEM: printf("Mmap mode = MMAP_VME_TO_U_MEM\n"); break; case MMAP_K_TO_U_MEM_WRT: printf("Mmap mode = MMAP_K_TO_U_MEM_WRT\n"); break; case MMAP_K_TO_U_MEM_RD: printf("Mmap mode = MMAP_K_TO_U_MEM_RD\n"); break; default: printf("Invalid mmap mode returned\n"); } /* mmap() will return the starting address of the mapped region, truncated * to a page boundary (See dmaex_mmap(), which returns the page frame number * only, and thus we must offset into that page from the user program). * Calculate the offset into that page where the buffer is mapped to. Use * this offset to ADD to the length of the buffer that we want to mmap(), in * order to map the entire buffer size. */ offset_from_base = (u_long)get_offset(vme_addr,vme_am); printf("*** VME base address 0x%x - sparse or dense space offset = 0x%lx\n", vme_addr,offset_from_base); /* * mmap a size of 32 times the buffer size PLUS the offset into * the mmap'd page (calculated above), for sparse space mapping. * * mmap to the size of the buffer PLUS the offset into the mmap'd * page (calculated above), for dense space mapping. */ if (vme_am & VME_DENSE) len = (vme_size + offset_from_base); else len = (vme_size * PAGE_MULT) + offset_from_base; mapped_va = (int *)mmap((caddr_t)0, len, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0); if (mapped_va == (int *)-1) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("mmap: failed"); if ((err = ioctl(fd, UNMAP_VME_FOR_MMAP_PIO, data)) != 0) perror("UNMAP_VME_FOR_MMAP_PIO"); return(1);; } printf("Successfully called mmap \n"); /* * Calculate the base address of the buffer, given the offset and the * address returned from mmap. */ (u_long)bufp = (u_long)mapped_va + (u_long)offset_from_base; printf("*** buffer address = 0x%x\n",(u_long)bufp); if (!(vme_am & VME_DENSE)) { /* * Sparse space was speified. Do sparse space testing */ printf("Writing byte data\n"); write_byte_data = (unsigned char*)wrt_buffer; read_byte_data = (unsigned char*)read_buffer; byte_vaddr = (unsigned char*)bufp; for (i = 0; i < vme_size; i++, byte_vaddr++) { read_byte_data[i] = 0; /* * Write to the mmap'd memory using the sparse space macros */ write_sparse_byte(bufp, ((u_long)byte_vaddr - (u_long)bufp), write_byte_data[i]); } printf("Reading byte data\n"); byte_vaddr = (unsigned char*)bufp; for (i = 0; i < vme_size; i++, byte_vaddr++) /* * Read the mmap'd memory using the sparse space macros */ read_sparse_byte(bufp, ((u_long)byte_vaddr - (u_long)bufp), read_byte_data[i]); /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the read data as 32 bit integer * values based on the specified byte swap mode. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(read_buffer,read_buffer, vme_size,byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("Error detected swapping read data for byte reads"); return(1); } } printf("Comparing byte data\n"); /* * Initialize write buffer pointer to the original write buffer */ write_byte_data = (unsigned char *)write_buffer; for (i = 0, j = 0; i < vme_size; i++) { if (write_byte_data[i] != read_byte_data[i]) { printf("Compare failed i = 0x%x read = 0x%x, write = 0x%x\n", i, read_byte_data[i], write_byte_data[i]); if (++j > 32) break; } } printf("Writing word data\n"); write_word_data = (unsigned short*)wrt_buffer; read_word_data = (unsigned short*)read_buffer; word_vaddr = (unsigned short*)bufp; for (i = 0; i < vme_size/2; i++, word_vaddr++) { read_word_data[i]=0; write_sparse_word(bufp, ((u_long)word_vaddr - (u_long)bufp), write_word_data[i]); } printf("Reading word data\n"); word_vaddr = (unsigned short*)bufp; for (i = 0; i < vme_size/2; i++, word_vaddr++) read_sparse_word(bufp, ((u_long)word_vaddr - (u_long)bufp), read_word_data[i]); /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the read data as 32 bit integer * values based on the specified byte swap mode. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(read_buffer,read_buffer, vme_size,byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("Error detected swapping read data for word reads"); return(1); } } printf("Comparing word data\n"); /* * Initialize write buffer pointer to the original write buffer */ write_word_data = (unsigned short *)write_buffer; for (i = 0, j = 0; i < vme_size/2; i++) { if (write_word_data[i] != read_word_data[i]) { printf("Compare failed i = 0x%x read = 0x%x, write = 0x%x\n", i, read_word_data[i], write_word_data[i]); if (++j > 32) break; } } printf("Writing integer data\n"); write_int_data = (unsigned int*)wrt_buffer; read_int_data = (unsigned int*)read_buffer; int_vaddr = (unsigned int*)bufp; for (i = 0; i < vme_size/4; i++, int_vaddr++) { read_int_data[i] = 0; write_sparse_int(bufp, ((u_long)int_vaddr - (u_long)bufp), write_int_data[i]); } printf("Reading integer data\n"); int_vaddr = (unsigned int*)bufp; for (i = 0; i < vme_size/4; i++, int_vaddr++) read_sparse_int(bufp, ((u_long)int_vaddr - (u_long)bufp), read_int_data[i]); /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the read data as 32 bit integer * values based on the specified byte swap mode. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(read_buffer,read_buffer, vme_size,byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("Error detected swapping read data for integer reads"); return(1); } } printf("Comparing integer data\n"); /* * Initialize write buffer pointer to the original write buffer */ write_int_data = (unsigned int *)write_buffer; for (i = 0, j = 0; i < vme_size/4; i++) { if (write_int_data[i] != read_int_data[i]) { printf("Compare failed i = 0x%x read = 0x%x, write = 0x%x\n", i, read_int_data[i], write_int_data[i]); if (++j > 32) break; } } } else { /* end if (!(vme_am & VME_DENSE)) */ /* * Dense space was speified. Do dense space testing * NOTE * Only interger and quadword (32 and 64 bit) accesses can * be done reliable to densely mapped memory. Byte and word * accesses will work (on AXPvme systems) but they will do a read * followed by a write operation on 32 or 64 bits only. */ printf("Writing integer data\n"); write_int_data = (unsigned int*)wrt_buffer; read_int_data = (unsigned int*)read_buffer; int_vaddr = (unsigned int*)bufp; for ( i = 0; i < vme_size/4; i++, int_vaddr++) { read_int_data[i] = 0; /* * Write directly to int_vaddr, since this is dense space */ *int_vaddr = write_int_data[i]; } printf("Reading integer data\n"); int_vaddr = (unsigned int*)bufp; for (i=0; i < vme_size/4; i++, int_vaddr++) read_int_data[i] = *int_vaddr; /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the read data as 32 bit integer * values based on the specified byte swap mode. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(read_buffer,read_buffer, vme_size,byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("Error detected swapping read data for integer reads"); return(1); } } printf("Comparing integer data\n"); /* * Initialize write buffer pointer to the original write buffer */ write_int_data = (unsigned int *)write_buffer; for (i = 0, j = 0; i < vme_size/4; i++) { if (write_int_data[i] != read_int_data[i]) { printf("Compare failed i = 0x%x read = 0x%x, write = 0x%x\n", i, read_int_data[i], write_int_data[i]); if (++j > 32) break; } } printf("Writing quad data\n"); write_quad_data = (unsigned long*)wrt_buffer; read_quad_data = (unsigned long*)read_buffer; quad_vaddr = (unsigned long*)bufp; for (i = 0; i < vme_size/8; i++, quad_vaddr++) { read_quad_data[i] = 0; /* * Write directly to quad_vaddr, since this is dense space */ *quad_vaddr = write_quad_data[i]; } printf("Reading quad data\n"); quad_vaddr = (unsigned long*)bufp; for (i = 0; i < vme_size/8; i++, quad_vaddr++) read_quad_data[i] = *quad_vaddr; /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the read data as 32 bit integer * values based on the specified byte swap mode. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(read_buffer,read_buffer, vme_size,byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("Error detected swapping read data for quad reads"); return(1); } } printf("Comparing quad data\n"); /* * Initialize write buffer pointer to the original write buffer */ write_quad_data = (unsigned long *)write_buffer; for (i = 0, j = 0; i < vme_size/8; i++) { if (write_quad_data[i] != read_quad_data[i]) { printf("Compare failed i = 0x%x read = 0x%lx, write = 0x%lx\n", i, read_quad_data[i], write_quad_data[i]); if (++j > 32) break; } } } if ((err = ioctl(fd, UNMAP_VME_FOR_MMAP_PIO, data)) != 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("UNMAP_VME_FOR_MMAP_PIO"); return(1); } /* * Unmap the user-level mapping */ status = (caddr_t) munmap((caddr_t)mapped_va,len); /* * release memory used for testing - return success */ free(write_buffer); free(wrt_buffer); free(read_buffer); return(0); } /******************* CUT HERE *************************/ /****************************************************** * * * dmaex_mmap_bw_test * * * * This test uses stb, ldbu, stw, and ldwu "C" macros * * to access the VMEbus through mmaped byte/word * * address space. The ability to access the VMEbus * * through byte/word space was added in Tru64 UNIX * * version 4.0D. The byte/word "C" macros are defined * * earlier in this file. * * * * This code could of been separated into a separate * * file and compiled with the "-arch ev56" compiler * * switch and then linked to the main test program. * * Doing this would cause all memory references and * * bus references to be compiled and accessed using * * the appropriate data size. The "C" macros could be * * left unchanged or the bus access could be modified * * to use the appropriate pointers to char or short * * data types. * * * * To do this, follow the following steps: * * o Edit dmaex_test.c (this file). * * o Move the routine dmaex_mmap_bw_test to a * * new file called dmaex_bw_test.c. Remove the * * routine from this file. See comments above * * this decriptive block "CUT HERE" and after * * the routine "END OF CUT". This is the code * * to be moved and deleted. * * o At the begining of this file, add extern to * * the forward declaration of dmaex_mmap_bw_test * * routine. * * * * This completes the changes to dmaex_test.c * * * * o Edit dmaex_bw_test.c and add the following * * lines to the start of the file: * * #include * * #include * * #include * * #include * * #include * * #include * * #include * * #include * * #include "dmaexreg.h" * * * * #define mb() asm("mb") * * * * extern dmaex_sw_byte_swap(int *, int *, int, * * vme_atype_t); * * * * o Change dmaex_mmap_bw_test code as follows: * * from * * stb(byte_vaddr,write_byte_data[i]); * * to * * *byte_vaddr = write_byte_data[i]; * * from * * read_byte_data[i] = ldbu(byte_vaddr); * * to * * read_byte_data[i] = *byte_vaddr; * * from * * stw(word_vaddr,write_word_data[i]); * * to * * *word_vaddr = write_word_data[i]; * * from * * read_word_data[i] = ldwu(word_vaddr); * * to * * read_word_data[i] = *word_vaddr; * * * * This completes the changes to dmaex_bw_test.c. * * * * o To compile and link the two files, do the * * following: * * cc -c dmaex_test.c -g2 * * cc -c dmaex_bw_test.c -g2 * * cc dmaex_test.o dmaex_bw_test.o -o dmaex_test * ******************************************************/ /* * The ability to translate a sparse or dense iohandle_t to byte/word * address space was added in Tru64 UNIX 4.0D. A new io/common/devdriver.h * flag, HANDLE_LINEAR_SPACE, was added in this release. This flag enables * the kernel routine, iohandle_to_phys, to return the appropriate * linear byte/word address for the specified iohandle_t. */ #ifdef HANDLE_LINEAR_SPACE int dmaex_mmap_bw_test(int fd, struct dmaex_ioctl_data *data, int sw_byte_swap_needed, vme_atype_t byte_swap_mode) { unsigned char *read_byte_data, *write_byte_data, *byte_vaddr; unsigned short *read_word_data, *write_word_data, *word_vaddr; unsigned int *read_int_data, *write_int_data, *int_vaddr; unsigned long *read_quad_data, *write_quad_data, *quad_vaddr; int *read_buffer = NULL; int *write_buffer = NULL; int *wrt_buffer = NULL; unsigned char *wrt_byte_data = NULL; int buf_size,err,i,j; vme_addr_t vme_addr; vme_atype_t vme_am; u_int vme_size; u_int vme_access; io_handle_t vme_iohandle; u_long offset_from_base = 0; size_t len; int *mapped_va; /* address of start of mapped area */ int *bufp; /* address of start of buffer in mapped area */ caddr_t status; int byte_swap_needed = 0; /* * Use default values if byte count or VME address modifiers not specified */ if ( (!data->data[0]) || (!(data->data[2] & VME_BITS_MASK)) ) { printf("No test parameters specified\n"); return(1); } buf_size = (int)data->data[0]; /* * If software byte swap is needed, set flag. */ if ((sw_byte_swap_needed) && (byte_swap_mode != VME_BS_NOSWAP)) byte_swap_needed = 1; /* * Allocate write buffer to test the mapping */ write_buffer = (int *)malloc(buf_size); if(!(write_buffer)) { perror("write malloc failed for write_buffer"); return(1); } /* * Allocate a buffer to contain the actual * write data. If software byte swap was not * needed or selected, this buffer will contain * the same data as the write buffer, otherwise, * it will contain the byte swap data. */ wrt_buffer = (int *)malloc(buf_size); if(!(wrt_buffer)) { free(write_buffer); perror("write malloc failed for wrt_buffer"); return(1); } /* * Initialize both write buffers with same data */ write_byte_data = (unsigned char *)write_buffer; wrt_byte_data = (unsigned char *)wrt_buffer; for (i = 0, j = 0; i < buf_size; i++, j = i/256) { write_byte_data[i] = (unsigned char)(i + j); wrt_byte_data[i] = (unsigned char)(i + j); } /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the write data as 32 bit integer * values based on the specified byte swap mode. The "write_buffer" will * contain original data pattern and the "wrt_buffer" will contain the * byte swaped data. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(write_buffer, wrt_buffer, buf_size, byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); perror("Error detected swapping write data"); return(1); } } /* * Allocate read buffer to test the mapping */ read_buffer = (int *)malloc(buf_size); if (!(read_buffer)) { free(write_buffer); free(wrt_buffer); perror("read malloc failed"); return(1); } /* SETUP_VME_FOR_MMAP_PIO ioctl command does an outbound mapping to * a VMEbus adddress for the specified size with the specified * address modifiers. The driver maps outbound on the VME to the * exact buffer size, but the user then mmap's to ((32 * buf_size) + offset) * for SPARSE accesses or to the actual (buf_size + offset) for DENSE * accesses. It doesn't matter what the access type is, since the macros * does the correct manipulations for sparse space. * data->data[0] = Number of bytes to be mapped on the VMEbus * data->data[1] = Starting VMEbus address to be mapped * data->data[2] = VMEbus address modifiers (bits 32:16) * data->data[3] = Access type HANDLE_LINEAR_SPACE */ /* * Force access type to HANDLE_LINEAR_SPACE for driver's iohandle_to_phys * routine to force byte/word cpu I/O space translation */ data->data[3] = (unsigned long)(HANDLE_LINEAR_SPACE); if ((err = ioctl(fd, SETUP_VME_FOR_MMAP_PIO, data)) != 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("SETUP_VME_FOR_MMAP_PIO"); return(1); } printf("Successfully mapped the VME address to "); if (data->data[2] & VME_DENSE) printf("dense space\n"); else printf("sparse space\n"); if ((err = ioctl(fd, GET_VME_INFO_FOR_MMAP_PIO, data)) != 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("GET_VME_INFO_FOR_MMAP_PIO"); if ((err = ioctl(fd, UNMAP_VME_FOR_MMAP_PIO, data)) != 0) perror("UNMAP_VME_FOR_MMAP_PIO"); return(1); } printf("PIO mapping info: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" PIO Access value = 0x%x\n",(unsigned int)data->data[3]); printf(" PIO I/O handle = 0x%lx\n",data->data[4]); /* * Save VME outbound mapping information */ vme_size = (unsigned int)data->data[0]; vme_addr = (vme_addr_t)data->data[1]; vme_am = (vme_atype_t)data->data[2]; vme_access = (unsigned int)data->data[3]; vme_iohandle = data->data[4]; /* * Setup dmaex_mmap routine to manipulate the mapped VME address space */ data->data[0] = (unsigned long)MMAP_VME_TO_U_MEM; if ( ioctl(fd, SET_MMAP_MODE, data) != 0 ) perror("error in ioctl SET_MMAP_MODE"); if ( ioctl(fd, GET_MMAP_MODE, data) != 0 ) perror("error in ioctl GET_MMAP_MODE"); switch ((int)data->data[0]) { case MMAP_VME_TO_U_MEM: printf("Mmap mode = MMAP_VME_TO_U_MEM\n"); break; case MMAP_K_TO_U_MEM_WRT: printf("Mmap mode = MMAP_K_TO_U_MEM_WRT\n"); break; case MMAP_K_TO_U_MEM_RD: printf("Mmap mode = MMAP_K_TO_U_MEM_RD\n"); break; default: printf("Invalid mmap mode returned\n"); } /* mmap() will return the starting address of the mapped region, truncated * to a page boundary (See dmaex_mmap(), which returns the page frame number * only, and thus we must offset into that page from the user program). * Calculate the offset into that page where the buffer is mapped to. Use * this offset to ADD to the length of the buffer that we want to mmap(), in * order to map the entire buffer size. */ offset_from_base = (u_long)(vme_addr % 0x2000); printf("*** VME base address 0x%x - byte offset = 0x%lx\n", vme_addr,offset_from_base); /* * mmap to the size of the buffer PLUS the offset into the mmap'd * page (calculated above). */ len = (vme_size + offset_from_base); mapped_va = (int *)mmap((caddr_t)0, len, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0); if (mapped_va == (int *)-1) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("mmap: failed"); if ((err = ioctl(fd, UNMAP_VME_FOR_MMAP_PIO, data)) != 0) perror("UNMAP_VME_FOR_MMAP_PIO"); return(1);; } printf("Successfully called mmap \n"); /* * Calculate the base address of the buffer, given the offset and the * address returned from mmap. */ (u_long)bufp = (u_long)mapped_va + (u_long)offset_from_base; printf("*** buffer address = 0x%x\n",(u_long)bufp); /* * Do read/write byte testing */ printf("Writing byte data\n"); write_byte_data = (unsigned char *)wrt_buffer; read_byte_data = (unsigned char *)read_buffer; byte_vaddr = (unsigned char *)bufp; /* * If software byte swap was needed, the starting VMEbus address must * be aligned on a long word boundry [1:0] = 0. */ for (i = 0; i < vme_size; i++, byte_vaddr++) { read_byte_data[i] = 0; /* * Write to the mmap'd memory using byte accesses * (if dmaex_bw_test.c) *byte_vaddr = write_byte_data[i]; */ stb(byte_vaddr,write_byte_data[i]); mb(); } printf("Reading byte data\n"); byte_vaddr = (unsigned char*)bufp; for (i = 0; i < vme_size; i++, byte_vaddr++) /* * Read the mmap'd memory using byte accesses * (if dmaex_bw_test.c) read_byte_data[i] = *byte_vaddr; */ read_byte_data[i] = ldbu(byte_vaddr); /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the read data as 32 bit integer * values based on the specified byte swap mode. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(read_buffer,read_buffer, vme_size,byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("Error detected swapping read data for byte reads"); return(1); } } printf("Comparing byte data\n"); /* * Initialize write buffer pointer to the original write buffer */ write_byte_data = (unsigned char *)write_buffer; for (i = 0, j = 0; i < vme_size; i++) { if (write_byte_data[i] != read_byte_data[i]) { printf("Byte R/W compare failed i = 0x%x read = 0x%x, write = 0x%x\n", i, read_byte_data[i], write_byte_data[i]); if (++j > 32) break; } } /* * Do read/write word testing */ printf("Writing word data\n"); write_word_data = (unsigned short *)wrt_buffer; read_word_data = (unsigned short *)read_buffer; word_vaddr = (unsigned short *)bufp; /* * If software byte swap was needed, the starting VMEbus address must * be aligned on a long word boundry [1:0 = 0]. */ for (i = 0; i < vme_size/2; i++, word_vaddr++) { read_word_data[i] = 0; /* * (if dmaex_bw_test.c) *word_vaddr = write_word_data[i]; */ stw(word_vaddr,write_word_data[i]); mb(); } printf("Reading word data\n"); word_vaddr = (unsigned short*)bufp; for (i = 0; i < vme_size/2; i++, word_vaddr++) /* * (if dmaex_bw_test.c) read_word_data[i] = *word_vaddr; */ read_word_data[i] = ldwu(word_vaddr); /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the read data as 32 bit integer * values based on the specified byte swap mode. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(read_buffer,read_buffer, vme_size,byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("Error detected swapping read data for word reads"); return(1); } } printf("Comparing word data\n"); /* * Initialize write buffer pointer to the original write buffer */ write_word_data = (unsigned short *)write_buffer; for (i = 0, j = 0; i < vme_size/2; i++) { if (write_word_data[i] != read_word_data[i]) { printf("Word R/W compare failed i = 0x%x read = 0x%x, write = 0x%x\n", i, read_word_data[i], write_word_data[i]); if (++j > 32) break; } } /* * Do read/write long testing */ printf("Writing integer data\n"); write_int_data = (unsigned int *)wrt_buffer; read_int_data = (unsigned int *)read_buffer; int_vaddr = (unsigned int *)bufp; for ( i = 0; i < vme_size/4; i++, int_vaddr++) { read_int_data[i] = 0; /* * Write directly to int_vaddr */ *int_vaddr = write_int_data[i]; } /* * Issue a mb() after all data has been written. The order that the * writes occur, is not important. */ mb(); printf("Reading integer data\n"); int_vaddr = (unsigned int*)bufp; for (i=0; i < vme_size/4; i++, int_vaddr++) read_int_data[i] = *int_vaddr; /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the read data as 32 bit integer * values based on the specified byte swap mode. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(read_buffer,read_buffer, vme_size,byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("Error detected swapping read data for integer reads"); return(1); } } printf("Comparing integer data\n"); /* * Initialize write buffer pointer to the original write buffer */ write_int_data = (unsigned int *)write_buffer; for (i = 0, j = 0; i < vme_size/4; i++) { if (write_int_data[i] != read_int_data[i]) { printf("Lword R/W compare failed i = 0x%x read = 0x%x, write = 0x%x\n", i, read_int_data[i], write_int_data[i]); if (++j > 32) break; } } /* * Do read/write quad testing */ printf("Writing quad data\n"); write_quad_data = (unsigned long *)wrt_buffer; read_quad_data = (unsigned long *)read_buffer; quad_vaddr = (unsigned long *)bufp; for (i = 0; i < vme_size/8; i++, quad_vaddr++) { read_quad_data[i] = 0; /* * Write directly to quad_vaddr */ *quad_vaddr = write_quad_data[i]; } /* * Issue a mb() after all data has been written. The order that the * writes occur, is not important. */ mb(); printf("Reading quad data\n"); quad_vaddr = (unsigned long*)bufp; for (i = 0; i < vme_size/8; i++, quad_vaddr++) read_quad_data[i] = *quad_vaddr; /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the read data as 32 bit integer * values based on the specified byte swap mode. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(read_buffer,read_buffer, vme_size,byte_swap_mode) == 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("Error detected swapping read data for quad reads"); return(1); } } printf("Comparing quad data\n"); /* * Initialize write buffer pointer to the original write buffer */ write_quad_data = (unsigned long *)write_buffer; for (i = 0, j = 0; i < vme_size/8; i++) { if (write_quad_data[i] != read_quad_data[i]) { printf("Quad R/W compare failed i = 0x%x read = 0x%lx, write = 0x%lx\n", i, read_quad_data[i], write_quad_data[i]); if (++j > 32) break; } } if ((err = ioctl(fd, UNMAP_VME_FOR_MMAP_PIO, data)) != 0) { free(write_buffer); free(wrt_buffer); free(read_buffer); perror("UNMAP_VME_FOR_MMAP_PIO"); return(1); } /* * Unmap the user-level mapping */ status = (caddr_t) munmap((caddr_t)mapped_va,len); /* * release memory used for testing - return success */ free(write_buffer); free(wrt_buffer); free(read_buffer); return(0); } #else /***************************************************** * dmaex_mmap_bw_test * *****************************************************/ int dmaex_mmap_bw_test(int fd, struct dmaex_ioctl_data *data, int sw_byte_swap_needed, vme_atype_t byte_swap_mode) { printf("Mmap byte/word addressing not supported by this version of UNIX.\n"); return(0); } #endif /******************* END OF CUT************************/ /***************************************************** * dmaex_strategy_dma_block_xfer_test * *****************************************************/ int dmaex_strategy_dma_block_xfer_test(int fd, struct dmaex_ioctl_data *data, int sw_byte_swap_needed, vme_atype_t byte_swap_mode) { int buf_size,err,i,xfer_mode; int *read_buffer, *write_buffer; int data_error = 0; int byte_swap_needed = 0; /* * Check that caller specified a VME byte count and VME address * modifiers. A VMEbus address of zero is acceptable. */ if ( (!data->data[0]) || (!(data->data[2] & VME_BITS_MASK)) ) { printf("No test parameters specified \n"); return(1); } buf_size = (int)data->data[0]; /* * If software byte swap is needed, set flag. */ if ((sw_byte_swap_needed) && (byte_swap_mode != VME_BS_NOSWAP)) { /* * In order for quad word byte swap, VME_BS_QUAD, to be supported, * a VME data size of VME_D64 must also be specified. This is a * hardware restriction imposed by the VIP/VIC64 VME adapter. * Emulate the VIP/VIC64 adapter's hardware behavior by returning * an error condition when VME_D64 is not specified with VME_BS_QAUD. */ if ((byte_swap_mode == VME_BS_QUAD) && (((vme_atype_t)data->data[2] & VME_DSIZE_MASK) != VME_D64)) { perror("VME_BS_QUAD requires VME_D64 to be specified"); return(1); } byte_swap_needed = 1; } /* * Allocate write buffer to test the mapping */ write_buffer = (int *)malloc(buf_size); if(!(write_buffer)) { perror("write malloc failed"); return(1); } /* * Allocate read buffer to test the mapping */ read_buffer = (int *)malloc(buf_size); if (!(read_buffer)) { free(write_buffer); perror("read malloc failed"); return(1); } /* The SET_STRATEGY_INFO_BLK_DMA ioctl command saves the VME * mapping information for dmaex_read, dmaex_write, and dmaex_strategy * routines. This ioctl command MUST be invoked prior to calling the * file systems read and write operations. * data->data[0] = Number of bytes to be mapped on the VMEbus * data->data[1] = Starting VMEbus address to be mapped * data->data[2] = VMEbus address modifiers (bits 32:16) */ if ( ioctl(fd, SET_STRATEGY_INFO_BLK_DMA, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl SET_STRATEGY_INFO_BLK_DMA"); return(1); } /* The SET_STRATEGY_XFER_MODE ioctl command specifies what type * of I/O operation will be performed for the read or write operations. * The types of read/write operations that are supported follows: * PIO_XFER_MODE * DEVICE_DMA_MODE * BLOCK_DMA_MODE */ data->data[0] = (unsigned long)BLOCK_DMA_MODE; if ( ioctl(fd, SET_STRATEGY_XFER_MODE, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl SET_STRATEGY_XFER_MODE"); return(1); } if ( ioctl(fd, GET_STRATEGY_INFO_BLK_DMA, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl GET_STRATEGY_INFO_BLK_DMA"); return(1); } printf("DMA mapping setup info: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" VME ending address = 0x%x\n",(unsigned int)data->data[3]); printf(" VME bytes transferred = 0x%x\n",(unsigned int)data->data[4]); if ( ioctl(fd, GET_STRATEGY_XFER_MODE, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl GET_STRATEGY_XFER_MODE"); return(1); } xfer_mode = (int)data->data[0]; switch (xfer_mode) { case PIO_XFER_MODE: printf("PIO transfer mode\n"); break; case DEVICE_DMA_MODE: printf("Device DMA transfer mode\n"); break; case BLOCK_DMA_MODE: printf("Block DMA transfer mode\n"); break; default: printf("Invalid Transfer Mode Specified\n"); } /* * Fill the write buffer with a 32 bit binary count pattern. * Clear the read buffer. */ for (i = 0; i < (buf_size/sizeof(int)); i++) { write_buffer[i] = i; read_buffer[i] = 0; } /* * The data pattern has been written to the write buffer. If software * byte swap is needed or selected and the specified byte swap mode is * not VME_BS_NOSWAP, swap the write data as 32 bit integer values based * on the specified byte swap mode. The data will be swapped back to its * original values after the read. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(write_buffer,write_buffer, buf_size,byte_swap_mode) == 0) { free(write_buffer); free(read_buffer); perror("Error detected byte swapping write buffer data"); return(1); } } /* * Write the data to the specified VMEbus address setup by * ioctl SET_STRATEGY_INFO_BLK_DMA. This will perform the * data trasfer using the VME adapters DMA engine. */ if ((err = write(fd, write_buffer, buf_size)) < 0) { free(write_buffer); free(read_buffer); perror("BLOCK_DMA_MODE write error"); } else { /* * The write has succeeded, request the starting * and ending VMEbus addresses and total bytes * transferred. */ if ( ioctl(fd, GET_STRATEGY_INFO_BLK_DMA, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl GET_STRATEGY_INFO_BLK_DMA"); return(1); } printf("DMA mapping info following write: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" VME ending address = 0x%x\n",(unsigned int)data->data[3]); printf(" VME bytes transferred = 0x%x\n",(unsigned int)data->data[4]); /* * Read the data from the specified VMEbus address setup by * ioctl SET_STRATEGY_INFO_BLK_DMA. This will perform the data * transfer using the VME adapters DMA engine. */ if ((err = read(fd, read_buffer, buf_size)) < 0) { free(write_buffer); free(read_buffer); perror("BLOCK_DMA_MODE read error"); } else { if ( ioctl(fd, GET_STRATEGY_INFO_BLK_DMA, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl GET_STRATEGY_INFO_BLK_DMA"); return(1); } printf("DMA mapping info following read: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME starting address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" VME ending address = 0x%x\n",(unsigned int)data->data[3]); printf(" VME bytes transferred = 0x%x\n",(unsigned int)data->data[4]); /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the write and read data as 32 * bit integer values based on the specified byte swap mode. The write * data will be restored to its original values. */ if (byte_swap_needed) { dmaex_sw_byte_swap(write_buffer, write_buffer, buf_size, byte_swap_mode); dmaex_sw_byte_swap(read_buffer, read_buffer, buf_size, byte_swap_mode); } /* * Check the data written against that read */ printf("Comparing data transferred using adapter's DMA engine\n"); for (i = 0; i < (buf_size/sizeof(int)); i++) { if (write_buffer[i] != read_buffer[i]) { printf ("BLOCK_DMA_MODE data error - index 0x%x good = 0x%x bad = 0x%x\n", i,write_buffer[i],read_buffer[i]); data_error++; if (data_error > 16) break; } } } } if ( ioctl(fd, CLR_STRATEGY_INFO_BLK_DMA, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl CLR_STRATEGY_INFO_BLK_DMA"); return(1); } /* * release memory used for testing - return success */ free(write_buffer); free(read_buffer); return(0); } /***************************************************** * dmaex_strategy_pio_xfer_test * *****************************************************/ int dmaex_strategy_pio_xfer_test(int fd, struct dmaex_ioctl_data *data, int sw_byte_swap_needed, vme_atype_t byte_swap_mode) { int buf_size,err,i,xfer_mode; int *read_buffer, *write_buffer; int data_error = 0; int byte_swap_needed = 0; /* * Check that caller specified a VME byte count and VME address * modifiers. A VMEbus address of zero is acceptable. */ if ( (!data->data[0]) || (!(data->data[2] & VME_BITS_MASK)) ) { printf("No test parameters specified \n"); return(1); } buf_size = (int)data->data[0]; /* * If software byte swap is needed, set flag. */ if ((sw_byte_swap_needed) && (byte_swap_mode != VME_BS_NOSWAP)) byte_swap_needed = 1; /* * Allocate write buffer to test the mapping */ write_buffer = (int *)malloc(buf_size); if(!(write_buffer)) { perror("write malloc failed"); return(1); } /* * Allocate read buffer to test the mapping */ read_buffer = (int *)malloc(buf_size); if (!(read_buffer)) { free(write_buffer); perror("read malloc failed"); return(1); } /* The SETUP_VME_FOR_STRATEGY_PIO ioctl command saves the VME * mapping inforamtion for dmaex_read, dmaex_write, and * dmaex_strategy routine. This ioctl command MUST be invoked * prior to calling the file systems read and write operations. * data->data[0] = Number of bytes to be mapped on the VMEbus * data->data[1] = Starting VMEbus address to be mapped * data->data[2] = VMEbus address modifiers (bits 32:16) */ if ( ioctl(fd, SETUP_VME_FOR_STRATEGY_PIO, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl SETUP_VME_FOR_STRATEGY_PIO"); return(1); } /* The SET_STRATEGY_XFER_MODE ioctl command specifies what type * of I/O operation will be performed for the read or write operations. * The types of read/write operations that are supported follows: * PIO_XFER_MODE * DEVICE_DMA_MODE * BLOCK_DMA_MODE */ data->data[0] = (unsigned long)PIO_XFER_MODE; if ( ioctl(fd, SET_STRATEGY_XFER_MODE, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl SET_STRATEGY_XFER_MODE"); return(1); } if ( ioctl(fd, GET_VME_INFO_FOR_STRATEGY_PIO, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl GET_VME_INFO_FOR_STRATEGY_PIO"); return(1); } printf("VME mapping setup info: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" VME I/O handle = 0x%lx\n",data->data[3]); printf(" VME ending I/O handle = 0x%lx\n",data->data[4]); printf(" VME bytes transferred = 0x%x\n",(unsigned int)data->data[5]); if ( ioctl(fd, GET_STRATEGY_XFER_MODE, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl GET_STRATEGY_XFER_MODE"); return(1); } xfer_mode = (int)data->data[0]; switch (xfer_mode) { case PIO_XFER_MODE: printf("PIO transfer mode\n"); break; case DEVICE_DMA_MODE: printf("Device DMA transfer mode\n"); break; case BLOCK_DMA_MODE: printf("Block DMA transfer mode\n"); break; default: printf("Invalid Transfer Mode Specified\n"); } /* * Fill the write buffer with a 32 bit binary count pattern. * Clear the read buffer. */ for (i = 0; i < (buf_size/sizeof(int)); i++) { write_buffer[i] = i; read_buffer[i] = 0; } /* * The data pattern has been written to the write buffer. If software * byte swap is needed or selected and the specified byte swap mode is * not VME_BS_NOSWAP, swap the write data as 32 bit integer values based * on the specified byte swap mode. The data will be swapped back to its * original values after the read. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(write_buffer,write_buffer, buf_size,byte_swap_mode) == 0) { free(write_buffer); free(read_buffer); perror("Error detected byte swapping write buffer data"); return(1); } } /* * Write the data to the specified VMEbus address setup by ioctl * SETUP_VME_FOR_STRATEGY_PIO. This will perform the data transfer * using PIO operations. */ if ((err = write(fd, write_buffer, buf_size)) < 0) { free(write_buffer); free(read_buffer); perror("PIO_XFER_MODE write error"); } else { /* * The write has succeeded, request the starting * and ending VMEbus addresses and total bytes * transferred. */ if ( ioctl(fd, GET_VME_INFO_FOR_STRATEGY_PIO, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl GET_VME_INFO_FOR_STRATEGY_PIO"); return(1); } printf("VME mapping info following write: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" VME I/O handle = 0x%lx\n",data->data[3]); printf(" VME ending I/O handle = 0x%lx\n",data->data[4]); printf(" VME bytes transferred = 0x%x\n",(unsigned int)data->data[5]); /* * Read the data from the specified VMEbus address setup by ioctl * SETUP_VME_FOR_STRATEGY_PIO. This will perform the data trasfer * using PIO operations. */ if ((err = read(fd, read_buffer, buf_size)) < 0) { free(write_buffer); free(read_buffer); perror("PIO_XFER_MODE read error"); } else { if ( ioctl(fd, GET_VME_INFO_FOR_STRATEGY_PIO, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl GET_VME_INFO_FOR_STRATEGY_PIO"); return(1); } printf("VME mapping info following read: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" VME I/O handle = 0x%lx\n",data->data[3]); printf(" VME ending I/O handle = 0x%lx\n",data->data[4]); printf(" VME bytes transferred = 0x%x\n",(unsigned int)data->data[5]); /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the write and read data as 32 * bit integer values based on the specified byte swap mode. The write * data will be restored to its original values. */ if (byte_swap_needed) { dmaex_sw_byte_swap(write_buffer, write_buffer, buf_size, byte_swap_mode); dmaex_sw_byte_swap(read_buffer, read_buffer, buf_size, byte_swap_mode); } /* * Check the data written against that read */ printf("Comparing data transferred using PIO operations.\n"); for (i = 0; i < (buf_size/sizeof(int)); i++) { if (write_buffer[i] != read_buffer[i]) { printf ("PIO_XFER_MODE data error - index 0x%x good = 0x%x bad = 0x%x\n", i,write_buffer[i],read_buffer[i]); data_error++; if (data_error > 16) break; } } } } if ( ioctl(fd, UNMAP_VME_FOR_STRATEGY_PIO, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl UNMAP_VME_FOR_STRATEGY_PIO"); return(1); } /* * release memory used for testing - return success */ free(write_buffer); free(read_buffer); return(0); } /***************************************************** * dmaex_strategy_device_dma_xfer_test * *****************************************************/ int dmaex_strategy_device_dma_xfer_test(int fd, struct dmaex_ioctl_data *data) { int buf_size,err,i,xfer_mode; int *read_buffer, *write_buffer; int data_error = 0; /* * Check that caller specified a VME byte count */ if (!data->data[0]) { printf("Size of transfer not specified.\n"); return(1); } buf_size = (int)data->data[0]; /* * Allocate write buffer to test the mapping */ write_buffer = (int *)malloc(buf_size); if(!(write_buffer)) { perror("write malloc failed"); return(1); } /* * Allocate read buffer to test the mapping */ read_buffer = (int *)malloc(buf_size); if (!(read_buffer)) { free(write_buffer); perror("read malloc failed"); return(1); } /* The SET_STRATEGY_XFER_MODE ioctl command specifies what type * of I/O operation will be performed for the read or write operations. * The types of read/write operations that are supported follows: * PIO_XFER_MODE * DEVICE_DMA_MODE * BLOCK_DMA_MODE */ data->data[0] = (unsigned long)DEVICE_DMA_MODE; if ( ioctl(fd, SET_STRATEGY_XFER_MODE, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl SET_STRATEGY_XFER_MODE"); return(1); } if ( ioctl(fd, GET_STRATEGY_XFER_MODE, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl GET_STRATEGY_XFER_MODE"); return(1); } xfer_mode = (int)data->data[0]; switch (xfer_mode) { case PIO_XFER_MODE: printf("PIO transfer mode\n"); break; case DEVICE_DMA_MODE: printf("Device DMA transfer mode\n"); break; case BLOCK_DMA_MODE: printf("Block DMA transfer mode\n"); break; default: printf("Invalid Transfer Mode Specified\n"); } /* * Fill the write buffer with a 32 bit binary count pattern. * Clear the read buffer. */ for (i = 0; i < (buf_size/sizeof(int)); i++) { write_buffer[i] = i; read_buffer[i] = 0; } /* * Request the device to DMA the data from system * memory to the device (write) using the device's DMA engine. */ if ((err = write(fd, write_buffer, buf_size)) < 0) { free(write_buffer); free(read_buffer); perror("DEVICE_DMA_MODE write error"); } else { /* * Request the device to write data from the device * to system memory (read) using the device's DMA engine. */ if ((err = read(fd, read_buffer, buf_size)) < 0) { free(write_buffer); free(read_buffer); perror("DEVICE_DMA_MODE read error"); } else { /* * Check the data written against that read */ printf("Comparing data transferred via device DMA.\n"); for (i = 0; i < (buf_size/sizeof(int)); i++) { if (write_buffer[i] != read_buffer[i]) { printf ("DEVICE_DMA_MODE data error - index 0x%x good = 0x%x bad = 0x%x\n", i,write_buffer[i],read_buffer[i]); data_error++; if (data_error > 16) break; } } } } /* * release memory used for testing - return success */ free(write_buffer); free(read_buffer); return(0); } /* * Signal handler for SIGUSR1. SIGUSR1 will be signaled by * the kernel upon detection of a VME interrupt and an * interrupt service routine installed by the ioctl routine. */ void dmaex_sig_catcher(int signo) { printf("\ndmaex_sig_catcher: received signal %d from driver\n\n",signo); } /* * Setup a signal handler for detection of SIGUSR1. This * signal is used by dmaex_map_unmap_sys_mem_test. The * test places user memory onto the VMEbus and then waits * for a VME interrupt to occur. The kernel's interrupt * service routine will then issue a psignal to SIGUSR1 * to indicate that data was been written to the users * buffer. The signal handler will also be entered by * the user typing ^C (Control-C) on the console. */ void dmaex_sigsetup() { struct sigaction newsig, oldsig; newsig.sa_handler = dmaex_sig_catcher; sigemptyset( &newsig.sa_mask ); newsig.sa_flags = 0; if (sigaction( SIGUSR1, &newsig, &oldsig )) printf("dmaex_setup: sigaction failed\n"); if (sigaction( SIGINT, &newsig, &oldsig )) printf("dmaex_setup: sigaction failed\n"); } /***************************************************** * dmaex_map_unmap_sys_mem_test * *****************************************************/ int dmaex_map_unmap_sys_mem_test(int fd, struct dmaex_ioctl_data *data, int sw_byte_swap_needed, vme_atype_t byte_swap_mode) { int buf_size,err,i; char *unaligned_buffer; unsigned long offset; int *buffer; char operator; sigset_t empty_set,new_set; struct dmaex_ioctl_data tmp_data; int byte_swap_needed = 0; /* * Check that caller specified a VME byte count and VME address * modifiers. */ if ( (!data->data[0]) || (!(data->data[2] & VME_BITS_MASK)) ) { printf("No test parameters specified \n"); return(1); } buf_size = (int)data->data[0]; if ( (!data->data[3]) || (!data->data[4]) ) { printf("No VMEbus vector or IRQ specified\n"); return(1); } /* * If software byte swap is needed, set flag. */ if ((sw_byte_swap_needed) && (byte_swap_mode != VME_BS_NOSWAP)) byte_swap_needed = 1; /* * Allocate a buffer to test the mapping */ unaligned_buffer = (char *)malloc(buf_size + 8192); if(!(unaligned_buffer)) { perror("malloc failed"); return(1); } bzero(unaligned_buffer,(buf_size + 8192)); /* * Align the allocated buffer to an Alpha page. It is not * necessary to do this, however, this will align the VMEbus * page offset and memory buffer offset to be the same. */ offset = (unsigned long)unaligned_buffer % 8192L; buffer = (int *)(&unaligned_buffer[8192 - offset]); /* * setup a signal handler for SIGUSR1. SIGUSR1 will be signaled by * the kernel mode driver upon detection of a VMEbus interrupt. */ dmaex_sigsetup(); /* * Block SIGUSR1 until ready to receive it. The routine * sigsuspend will unblock SIGUSR1. */ sigemptyset( &new_set ); sigaddset( &new_set, SIGUSR1 ); sigprocmask( SIG_BLOCK, &new_set, NULL); /* * Install a VMEbus interrupt service routine to the * specified VMEbus vector and VME interrupt request level. */ tmp_data.data[0] = data->data[3]; tmp_data.data[1] = data->data[4]; if ( ioctl(fd, SET_INT_HANDLER, &tmp_data) != 0 ) { perror("error in ioctl SET_INT_HANDLER"); free(buffer); return(1); } printf("\nVME ISI installed at vector 0x%x for VME IRQ level 0x%x\n\n", tmp_data.data[1],tmp_data.data[0]); /* * Create an empty set to receive SIGUSR1 */ sigemptyset( &empty_set ); /* * Copy the system virtual address into data buffer */ data->data[3] = (unsigned long)buffer; /* The MAP_SYS_MEM_TO_VME ioctl command maps the system memory * buffer to the VMEbus and wires the system memory down so * that it will not be swapped out. * data->data[0] = Number of bytes to be mapped on the VMEbus * data->data[1] = VMEbus address - not used * data->data[2] = VMEbus address modifiers (bits 32:16) * data->data[3] = System virtual memory address */ if ( ioctl(fd, MAP_SYS_MEM_TO_VME, data) != 0 ) { free(unaligned_buffer); perror("error in ioctl MAP_SYS_MEM_TO_VME"); if ( ioctl(fd, CLR_INT_HANDLER, &tmp_data) != 0 ) perror("error in ioctl CLR_INT_HANDLER"); return(1); } /* * Obtain the VMEbus address at which the system memory was mapped to. */ if ( ioctl(fd, GET_SYS_MEM_INFO, data) != 0 ) { free(unaligned_buffer); perror("error in ioctl GET_SYS_MEM_INFO"); if ( ioctl(fd, CLR_INT_HANDLER, &tmp_data) != 0 ) perror("error in ioctl CLR_INT_HANDLER"); return(1); } printf("Map System Memory to VME info: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" System Memory Address = 0x%lx\n",(unsigned int)data->data[3]); printf("\nSystem Memory has been mapped to VMEbus address 0x%x.\n", (unsigned int)data->data[1]); printf("Waiting for signal from kernel interrupt service - pid = %d\n", getpid()); /************************************************************** * Wait for the kernel interrupt service routine to receive * * a VMEbus interrupt to the specified interrupt vector * *************************************************************/ sigsuspend( &empty_set ); /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the read data as 32 bit integer * values based on the specified byte swap mode. */ if (byte_swap_needed) { /* * If the specified byte swap mode is VME_BS_QUAD and the data received * is not D64 SBLT, change the variable byte_swap_mode to VME_BS_LWORD. * This is the hardware behavior of the VIP/VIC64 VME adapter. */ if (dmaex_sw_byte_swap(buffer, buffer, buf_size, byte_swap_mode) == 0) perror("Error detected swapping read data"); } /* * Display the first 10 long words of the buffer */ for (i = 0; i < 10; i++) printf("index = %d value = 0x%08x\n",i, buffer[i]); if ( ioctl(fd, UNMAP_SYS_MEM_TO_VME, data) != 0 ) { free(unaligned_buffer); perror("error in ioctl UNMAP_SYS_MEM_TO_VME"); if ( ioctl(fd, CLR_INT_HANDLER, &tmp_data) != 0 ) perror("error in ioctl CLR_INT_HANDLER"); return(1); } /* * Return mapping information after system memory has been unmapped * from the VMEbus */ if ( ioctl(fd, GET_SYS_MEM_INFO, data) != 0 ) { free(unaligned_buffer); perror("error in ioctl GET_SYS_MEM_INFO"); if ( ioctl(fd, CLR_INT_HANDLER, &tmp_data) != 0 ) perror("error in ioctl CLR_INT_HANDLER"); return(1); } printf("Map System Memory to VME info: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" System Memory Address = 0x%lx\n",(unsigned int)data->data[3]); /* * release memory used for testing - return success */ free(unaligned_buffer); if ( ioctl(fd, CLR_INT_HANDLER, &tmp_data) != 0 ) { perror("error in ioctl CLR_INT_HANDLER"); return(1); } else return(0); } /***************************************************** * dmaex_dma_to_from_user_buffers * *****************************************************/ int dmaex_dma_to_from_user_buffers(int fd, struct dmaex_ioctl_data *data, int sw_byte_swap_needed, vme_atype_t byte_swap_mode) { int buf_size,err,i; int *read_buffer, *write_buffer; int data_error = 0; int error = 0; int b_count = 0; int byte_swap_needed = 0; /* * Check that caller specified a VME byte count and VME address * modifiers. A VMEbus address of zero is acceptable. */ if ( (!data->data[0]) || (!(data->data[2] & VME_BITS_MASK)) ) { printf("No test parameters specified \n"); return(1); } buf_size = (int)data->data[0]; /* * If software byte swap is needed, set flag. */ if ((sw_byte_swap_needed) && (byte_swap_mode != VME_BS_NOSWAP)) { /* * In order for quad word byte swap, VME_BS_QUAD, to be supported, * a VME data size of VME_D64 must also be specified. This is a * hardware restriction imposed by the VIP/VIC64 VME adapter. * Emulate the VIP/VIC64 adapter's hardware behavior by returning * an error condition when VME_D64 is not specified with VME_BS_QAUD. */ if ((byte_swap_mode == VME_BS_QUAD) && (((vme_atype_t)data->data[2] & VME_DSIZE_MASK) != VME_D64)) { perror("VME_BS_QUAD requires VME_D64 to be specified"); return(1); } byte_swap_needed = 1; } /* * Allocate write buffer to test the mapping */ write_buffer = (int *)malloc(buf_size); if(!(write_buffer)) { perror("write malloc failed"); return(1); } /* * Allocate read buffer to test the mapping */ read_buffer = (int *)malloc(buf_size); if (!(read_buffer)) { free(write_buffer); perror("read malloc failed"); return(1); } /* * The SETUP_DMA_BLK_WRT ioctl command sets up the appropriate DMA * mapping for the VME adapters hardware DMA block mode engine to * perform DMA block mode writes. This ioctl MUST be invoked prior * to calling the DO_DMA_BLK_WRT ioctl. * data->data[0] = Number of bytes to be mapped on the VMEbus * data->data[1] = Starting VMEbus address to be mapped * data->data[2] = VMEbus address modifiers (bits 32:16) * data->data[3] = user's write buffer */ data->data[3] = (unsigned long)write_buffer; if ( ioctl(fd, SETUP_DMA_BLK_WRT, data) != 0 ) { free(read_buffer); free(write_buffer); perror("error in ioctl SETUP_DMA_BLK_WRT"); return(1); } /* * The SETUP_DMA_BLK_RD ioctl command sets up the appropriate DMA * mapping for the VME adapters hardware DMA block mode engine to * perform DMA block mode reads. This ioctl MUST be invoked prior * to calling the DO_DMA_BLK_RD ioctl. * data->data[0] = Number of bytes to be mapped on the VMEbus * data->data[1] = Starting VMEbus address to be mapped * data->data[2] = VMEbus address modifiers (bits 32:16) * data->data[3] = user's read buffer */ data->data[3] = (unsigned long)read_buffer; if ( ioctl(fd, SETUP_DMA_BLK_RD, data) != 0 ) { perror("error in ioctl SETUP_DMA_BLK_RD"); /* * Release DMA write resources on an error condition */ if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); free(read_buffer); free(write_buffer); return(1); } /* * Now that the DMA paths for both reads and writes have been * setup, retrieve the DMA mapping information prior to performing * the actual hardware DMA. */ if ( ioctl(fd, GET_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl GET_DMA_BLK_WRT"); printf("DMA BLOCK MODE WRITE info: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" DMA handle = 0x%lx\n",(unsigned long)data->data[3]); printf(" System Memory Address = 0x%lx\n",(unsigned long)data->data[4]); if ( ioctl(fd, GET_DMA_BLK_RD, data) != 0 ) perror("error in ioctl GET_DMA_BLK_RD"); printf("DMA BLOCK MODE READ info: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" DMA handle = 0x%lx\n",(unsigned long)data->data[3]); printf(" System Memory Address = 0x%lx\n",(unsigned long)data->data[4]); /* * Fill the write buffer with a 32 bit binary count pattern. * Clear the read buffer. */ for (i = 0; i < (buf_size/sizeof(int)); i++) { write_buffer[i] = i; read_buffer[i] = 0; } /* * The data pattern has been written to the write buffer. If software * byte swap is needed or selected and the specified byte swap mode is * not VME_BS_NOSWAP, swap the write data as 32 bit integer values based * on the specified byte swap mode. The data will be swapped back to its * original values after the read. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(write_buffer,write_buffer, buf_size,byte_swap_mode) == 0) { perror("Error detected byte swapping write buffer data"); /* * Release DMA read/write resources on an error condition */ if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); if ( ioctl(fd, CLR_DMA_BLK_RD, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); free(read_buffer); free(write_buffer); return(1); } } /* * Perform the actual DMA block mode write. The number of bytes * transferred will be returned from the ioctl routine. The * user's memory will be wired down and unwired prior to and after * the DMA transfer. */ if ( ioctl(fd, DO_DMA_BLK_WRT, data) != 0 ) { perror("error in ioctl DO_DMA_BLK_WRT"); error++; } else { if ((b_count = (int)data->data[0]) != buf_size) { perror("error in ioctl DO_DMA_BLK_WRT - incorrect byte count returned"); printf("DO_DMA_BLK_WRT: expected bc = 0x%x actual bc = 0x%x\n", buf_size,b_count); error++; } } /* * If an error was detected in the Block Mode DMA write, release * the system and DMA resources */ if (error) { /* * Release DMA read/write resources on an error condition */ if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); if ( ioctl(fd, CLR_DMA_BLK_RD, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); free(read_buffer); free(write_buffer); return(1); } /* * Perform the actual DMA block mode read. The number of bytes * transferred will be returned from the ioctl routine. The * user's memory will be wired down and unwired prior to and after * the DMA transfer. */ if ( ioctl(fd, DO_DMA_BLK_RD, data) != 0 ) { perror("error in ioctl DO_DMA_BLK_RD"); error++; } else { if ((b_count = (int)data->data[0]) != buf_size) { perror("error in ioctl DO_DMA_BLK_RD - incorrect byte count returned"); printf("DO_DMA_BLK_RD: expected bc = 0x%x actual bc = 0x%x\n", buf_size,b_count); error++; } } /* * If an error was detected in the Block Mode DMA read, release * the system and DMA resources */ if (error) { /* * Release DMA read/write resources on an error condition */ if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); if ( ioctl(fd, CLR_DMA_BLK_RD, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); free(read_buffer); free(write_buffer); return(1); } /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the write and read data as 32 * bit integer values based on the specified byte swap mode. The write * data will be restored to its original values. */ if (byte_swap_needed) { dmaex_sw_byte_swap(write_buffer, write_buffer, buf_size, byte_swap_mode); dmaex_sw_byte_swap(read_buffer, read_buffer, buf_size, byte_swap_mode); } /* * Check the data written against that read */ printf("Comparing DMA data transferred using ioctl commands.\n"); for (i = 0; i < (buf_size/sizeof(int)); i++) { if (write_buffer[i] != read_buffer[i]) { printf("DMA data error - index 0x%x good = 0x%x bad = 0x%x\n", i,write_buffer[i],read_buffer[i]); data_error++; if (data_error > 16) break; } } /* * Release the DMA resources used for the DMA transfers */ if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); if ( ioctl(fd, CLR_DMA_BLK_RD, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); /* * release memory used for testing - return success */ free(write_buffer); free(read_buffer); return(0); } /***************************************************** * dmaex_dma_to_from_kernel_buffers * *****************************************************/ int dmaex_dma_to_from_kernel_buffers(int fd, struct dmaex_ioctl_data *data, int sw_byte_swap_needed, vme_atype_t byte_swap_mode) { int buf_size,err,i; int *read_buffer, *write_buffer; caddr_t status; int data_error = 0; int error = 0; int b_count = 0; int byte_swap_needed = 0; /* * Check that caller specified a VME byte count and VME address * modifiers. A VMEbus address of zero is acceptable. */ if ( (!data->data[0]) || (!(data->data[2] & VME_BITS_MASK))) { printf("No test parameters specified \n"); return(1); } buf_size = (int)data->data[0]; /* * If software byte swap is needed, set flag. */ if ((sw_byte_swap_needed) && (byte_swap_mode != VME_BS_NOSWAP)) { /* * In order for quad word byte swap, VME_BS_QUAD, to be supported, * a VME data size of VME_D64 must also be specified. This is a * hardware restriction imposed by the VIP/VIC64 VME adapter. * Emulate the VIP/VIC64 adapter's hardware behavior by returning * an error condition when VME_D64 is not specified with VME_BS_QAUD. */ if ((byte_swap_mode == VME_BS_QUAD) && (((vme_atype_t)data->data[2] & VME_DSIZE_MASK) != VME_D64)) { perror("VME_BS_QUAD requires VME_D64 to be specified"); return(1); } byte_swap_needed = 1; } /* * Check that the byte count does not exceed the number of bytes * allocated for the kernel physically contiguous memory buffer. */ if (buf_size > CONTIG_RD_WRT_BUF_SIZE) { printf("The byte count is to large. The maximum byte count can not be\n"); printf("any larger then 0x%lx when using contiguous kernel buffers\n", CONTIG_RD_WRT_BUF_SIZE); return(1); } /* * The SETUP_DMA_BLK_WRT ioctl command sets up the appropriate DMA * mapping for the VME adapters hardware DMA block mode engine to * perform DMA block mode writes. In order to use the physically * contiguous kernel memory buffer for this test, the forth data * argument must be NULL. This ioctl command MUST be invoked prior * to calling the DO_DMA_BLK_WRT ioctl and mapping the kernel memory * to user space. * data->data[0] = Number of bytes to be mapped on the VMEbus * data->data[1] = Starting VMEbus address to be mapped * data->data[2] = VMEbus address modifiers (bits 32:16) * data->data[3] = NULL */ data->data[3] = (unsigned long)0; if ( ioctl(fd, SETUP_DMA_BLK_WRT, data) != 0 ) { perror("error in ioctl SETUP_DMA_BLK_WRT"); return(1); } /* * The SETUP_DMA_BLK_RD ioctl command sets up the appropriate DMA * mapping for the VME adapters hardware DMA block mode engine to * perform DMA block mode reads. In order to use the physically * contiguous kernel memory buffer for this test, the forth data * argument must be NULL. This ioctl command MUST be invoked prior * to calling the DO_DMA_BLK_RD ioctl and mapping the kernel memory * to user space. * data->data[0] = Number of bytes to be mapped on the VMEbus * data->data[1] = Starting VMEbus address to be mapped * data->data[2] = VMEbus address modifiers (bits 32:16) * data->data[3] = NULL */ data->data[3] = (unsigned long)0; if ( ioctl(fd, SETUP_DMA_BLK_RD, data) != 0 ) { perror("error in ioctl SETUP_DMA_BLK_RD"); /* * Release DMA write resources on an error condition */ if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); return(1); } /* * Now that the DMA paths for both reads and writes have been * setup using the kernel physically contiguous buffers, retrieve * the DMA mapping information prior to performing the actual * hardware DMA. */ if ( ioctl(fd, GET_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl GET_DMA_BLK_WRT"); printf("DMA BLOCK MODE WRITE info: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" DMA handle = 0x%lx\n",(unsigned long)data->data[3]); printf(" System Memory Address = 0x%lx\n",(unsigned long)data->data[4]); if ( ioctl(fd, GET_DMA_BLK_RD, data) != 0 ) perror("error in ioctl GET_DMA_BLK_RD"); printf("DMA BLOCK MODE READ info: \n"); printf(" VME size = 0x%x\n",(unsigned int)data->data[0]); printf(" VME address = 0x%x\n",(unsigned int)data->data[1]); printf(" VME address modifiers = 0x%x\n",(unsigned int)data->data[2]); printf(" DMA handle = 0x%lx\n",(unsigned long)data->data[3]); printf(" System Memory Address = 0x%lx\n",(unsigned long)data->data[4]); /* * Set the driver's mmap mode to MMAP_K_TO_U_MEM_WRT. */ data->data[0] = (unsigned long)MMAP_K_TO_U_MEM_WRT; if ( ioctl(fd, SET_MMAP_MODE, data) != 0 ) perror("error in ioctl SET_MMAP_MODE"); /* * Mmap the kernel write buffer into user space. This will * actually be done on the buffer access. */ write_buffer = (int *)mmap((caddr_t)0, buf_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0); if (write_buffer == (int *)-1) { perror("mmap: failed to mmap kernel write buffer"); if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); if ( ioctl(fd, CLR_DMA_BLK_RD, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); return(1);; } printf("Successfully called mmap for write. Buffer = 0x%lx\n",write_buffer); /* * Fill the kernel write buffer with a 32 bit binary count pattern. * This MUST be done with the driver's mmap mode set to * MMAP_K_TO_U_MEM_WRT. The driver's mmap routine will be invoked * during the fill to wire the kernel memory buffer to user space. */ for (i = 0; i < (buf_size/sizeof(int)); i++) { write_buffer[i] = i; } /* * The data pattern has been written to the write buffer. If software * byte swap is needed or selected and the specified byte swap mode is * not VME_BS_NOSWAP, swap the write data as 32 bit integer values based * on the specified byte swap mode. The data will be swapped back to its * original values after the read. */ if (byte_swap_needed) { if (dmaex_sw_byte_swap(write_buffer,write_buffer, buf_size,byte_swap_mode) == 0) { perror("Error detected byte swapping write buffer data"); /* * Release DMA read/write resources on an error condition */ if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); if ( ioctl(fd, CLR_DMA_BLK_RD, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); return(1); } } /* * Set the driver's mmap mode to MMAP_K_TO_U_MEM_RD. */ data->data[0] = (unsigned long)MMAP_K_TO_U_MEM_RD; if ( ioctl(fd, SET_MMAP_MODE, data) != 0 ) perror("error in ioctl SET_MMAP_MODE"); /* * Mmap the kernel read buffer into user space. This will * actually be done on the buffer access. */ read_buffer = (int *)mmap((caddr_t)0, buf_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0); if (read_buffer == (int *)-1) { perror("mmap: failed to mmap kernel read buffer"); /* * release DMA resources allocated and unmap * kernel to user level mapping of write_buffer */ status = (caddr_t) munmap((caddr_t)write_buffer,buf_size); if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); if ( ioctl(fd, CLR_DMA_BLK_RD, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); return(1);; } printf("Successfully called mmap for read. Buffer = 0x%lx\n",read_buffer); /* * Clear the kernel read buffer * This MUST be done with the driver's mmap mode set to * MMAP_K_TO_U_MEM_RD. The driver's mmap routine will be invoked * during the clear to wire the kernel memory buffer to user space. */ for (i = 0; i < (buf_size/sizeof(int)); i++) { read_buffer[i] = 0; } /* * Perform the actual DMA block mode write. The number of bytes * transferred will be returned from the ioctl routine. */ if ( ioctl(fd, DO_DMA_BLK_WRT, data) != 0 ) { perror("error in ioctl DO_DMA_BLK_WRT"); error++; } else { if ((b_count = (int)data->data[0]) != buf_size) { perror("error in ioctl DO_DMA_BLK_WRT - incorrect byte count returned"); printf("DO_DMA_BLK_WRT: expected bc = 0x%x actual bc = 0x%x\n", buf_size,b_count); error++; } } /* * If an error was detected in the Block Mode DMA write, release * the system and DMA resources */ if (error) { /* * Release DMA read/write resources on an error condition */ status = (caddr_t) munmap((caddr_t)write_buffer,buf_size); status = (caddr_t) munmap((caddr_t)read_buffer,buf_size); if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); if ( ioctl(fd, CLR_DMA_BLK_RD, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); return(1); } /* * Perform the actual DMA block mode read. The number of bytes * transferred will be returned from the ioctl routine. */ if ( ioctl(fd, DO_DMA_BLK_RD, data) != 0 ) { perror("error in ioctl DO_DMA_BLK_RD"); error++; } else { if ((b_count = (int)data->data[0]) != buf_size) { perror("error in ioctl DO_DMA_BLK_RD - incorrect byte count returned"); printf("DO_DMA_BLK_RD: expected bc = 0x%x actual bc = 0x%x\n", buf_size,b_count); error++; } } /* * If an error was detected in the Block Mode DMA read, release * the system and DMA resources */ if (error) { /* * Release DMA read/write resources on an error condition */ status = (caddr_t) munmap((caddr_t)write_buffer,buf_size); status = (caddr_t) munmap((caddr_t)read_buffer,buf_size); if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); if ( ioctl(fd, CLR_DMA_BLK_RD, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); return(1); } /* * If software byte swap is needed or selected and the specified byte * swap mode is not VME_BS_NOSWAP, swap the write and read data as 32 * bit integer values based on the specified byte swap mode. The write * data will be restored to its original values. */ if (byte_swap_needed) { dmaex_sw_byte_swap(write_buffer, write_buffer, buf_size, byte_swap_mode); dmaex_sw_byte_swap(read_buffer, read_buffer, buf_size, byte_swap_mode); } /* * Check the data written against that read */ printf("Comparing DMA data transferred using ioctl commands.\n"); for (i = 0; i < (buf_size/sizeof(int)); i++) { if (write_buffer[i] != read_buffer[i]) { printf("DMA data error - index 0x%x good = 0x%x bad = 0x%x\n", i,write_buffer[i],read_buffer[i]); data_error++; if (data_error > 16) break; } } /* * Release the DMA resources used for the DMA transfers */ status = (caddr_t) munmap((caddr_t)write_buffer,buf_size); status = (caddr_t) munmap((caddr_t)read_buffer,buf_size); if ( ioctl(fd, CLR_DMA_BLK_WRT, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); if ( ioctl(fd, CLR_DMA_BLK_RD, data) != 0 ) perror("error in ioctl CLR_DMA_BLK_WRT"); /* * return success */ return(0); } vme_atype_t dmaex_vme_addr_mod[10] = { VME_A16_USER_ACC, VME_A16_SUPER_ACC, VME_A24_UDATA, VME_A24_UPROG, VME_A24_SDATA, VME_A24_SPROG, VME_A32_UDATA, VME_A32_UPROG, VME_A32_SDATA, VME_A32_SPROG }; vme_atype_t dmaex_vme_data_size[4] = { VME_D08, VME_D16, VME_D32, VME_D64 }; vme_atype_t dmaex_vme_swap_mode[5] = { VME_BS_NOSWAP, VME_BS_BYTE, VME_BS_WORD, VME_BS_LWORD, VME_BS_QUAD }; void select_msg(int msg_num, struct dmaex_ioctl_data *data) { int value; printf("\n"); switch (msg_num) { case 1: printf("Setup a PIO window to VMEbus address space. Mmap\n"); printf("this I/O space to user memory. Perform user mode\n"); printf("read and write accesses to the mmaped I/O.\n"); break; case 2: printf("Setup the drivers read and write strategy routine to\n"); printf("perform the data transfer using the VME adapter's\n"); printf("hardware DMA engine. The DMA will be performed with\n"); printf("Master Block DMA transfers\n"); break; case 3: printf("Setup the drivers read and write strategy routine to\n"); printf("perform the data transfer using PIO operations.\n"); break; case 4: printf("Setup the drivers read and write strategy routine to\n"); printf("perform the data transfer using the VME device's\n"); printf("hardware DMA engine.\n"); break; case 5: printf("Map system memory to VMEbus. Requires the receipt of a\n"); printf("VMEbus interrupt to the installed interrupt handler to\n"); printf("continue.\n"); break; case 6: printf("Perform Master Block DMA read and write transfers using\n"); printf("driver's ioctl commands and user memory buffers wired into\n"); printf("kernel address space.\n"); break; case 7: printf("Perform Master Block DMA read and write transfers using\n"); printf("driver's ioctl commands and physically contiguous kernel\n"); printf("read and write buffers mmaped into user space.\n"); break; case 8: printf("Post a VME interrupt request to the VMEbus at the specified\n"); printf("VME IRQ and vector. The driver's ioctl will wait for the\n"); printf("request to be acknowledged by the device.\n"); break; case 9: printf("Clear a previously posted VME interrupt request or clear\n"); printf("any request posted to the specified VME IRQ line.\n"); break; case 10: case 11: case 12: case 13: case 14: /* save for future use */ break; case 15: printf("Enter the number of bytes to transfer or map [hex] : "); scanf("%x", &value); data->data[0] = (unsigned long)value; break; case 16: printf("Enter the VMEbus address [hex]: "); scanf("%x", &value); data->data[1] = (unsigned long)value; break; case 17: do { printf("Select one of the following VME address modifiers\n"); printf(" 0 = VME_A16_USER_ACC 1 = VME_A16_SUPER_ACC\n"); printf(" 2 = VME_A24_UDATA 3 = VME_A24_UPROG\n"); printf(" 4 = VME_A24_SDATA 5 = VME_A24_SPROG\n"); printf(" 6 = VME_A32_UDATA 7 = VME_A32_UPROG\n"); printf(" 8 = VME_A32_SDATA 9 = VME_A32_SPROG\n"); printf("Enter the VME address modifier [0-9]: "); scanf("%d", &value); if (value > 9) printf("Invalid address modifier specified\n"); } while (value > 9); data->data[2] = (unsigned long)dmaex_vme_addr_mod[value]; break; case 18: do { printf("Select one of the following VME address modifiers\n"); printf(" 0 = VME_A24_UDATA 1 = VME_A24_UPROG\n"); printf(" 2 = VME_A24_SDATA 3 = VME_A24_SPROG\n"); printf(" 4 = VME_A32_UDATA 5 = VME_A32_UPROG\n"); printf(" 6 = VME_A32_SDATA 7 = VME_A32_SPROG\n"); printf("Enter the VME address modifier [0-7]: "); scanf("%d", &value); if (value > 7) printf("Invalid address modifier specified\n"); } while (value > 9); data->data[2] = (unsigned long)dmaex_vme_addr_mod[value + 2]; break; case 19: do { printf("Select VME data size\n"); printf(" 0 = VME_D08 1 = VME_D16 2 = VME_D32\n"); printf("Enter the data size [0-2]: "); scanf("%d", &value); if (value > 2) printf("Invalid VME data size\n"); } while (value > 2); data->data[2] |= (unsigned long)dmaex_vme_data_size[value]; break; case 20: do { printf("Select VME data size\n"); printf(" 0 = VME_D16 1 = VME_D32 2 = VME_D64\n"); printf("Enter the data size [0-2]: "); scanf("%d", &value); if (value > 2) printf("Invalid VME data size\n"); } while (value > 2); data->data[2] |= (unsigned long)dmaex_vme_data_size[value +1]; break; case 21: do { printf("Select VME swap mode\n"); printf(" 0 = VME_BS_NOSWAP 1 = VME_BS_BYTE 2 = VME_BS_WORD\n"); printf(" 3 = VME_BS_LWORD\n"); printf("Enter the swap mode [0-3]: "); scanf("%d", &value); if (value > 3) printf("Invalid VME swap mode\n"); } while (value > 3); data->data[2] |= (unsigned long)dmaex_vme_swap_mode[value]; break; case 22: do { printf("Select VME swap mode\n"); printf(" 0 = VME_BS_NOSWAP 1 = VME_BS_BYTE 2 = VME_BS_WORD\n"); printf(" 3 = VME_BS_LWORD 4 = VME_BS_QUAD\n"); printf("Enter the swap mode [0-4]: "); scanf("%d", &value); if (value > 4) printf("Invalid VME swap mode\n"); } while (value > 4); data->data[2] |= (unsigned long)dmaex_vme_swap_mode[value]; break; case 23: do { printf("Select Sparse/Dense mapping (0 = Sparse - 1 = Dense) [0-1]: "); scanf("%d", &value); } while (value > 1); if (value) data->data[2] |= VME_DENSE; break; case 24: do { printf("Enter VMEbus IRQ Level [1-7]: "); scanf("%d",&value); } while ((value < 1) || (value > 7)); data->data[0] = (unsigned long)value; printf("\n"); do { printf("Enter VMEbus vector [hex] : "); scanf("%x",&value); } while (value > 255); data->data[1] = (unsigned long)value; default: break; } } void request_bus_mapping_info(struct dmaex_ioctl_data *data, int bypass) { if (!(bypass & 0x01)) select_msg(15,data); /* request byte count */ if (!(bypass & 0x02)) select_msg(16,data); /* request VMEbus address */ if (!(bypass & 0x04)) { if (!(bypass & 0x20)) { select_msg(17,data); /* request VME address modifier for outbound */ select_msg(19,data); /* request VME data size for outbound */ select_msg(21,data); /* request VME swap mode for outbound */ } else { select_msg(18,data); /* request VME address modifier for inbound */ select_msg(20,data); /* request VME data size for inbound */ select_msg(22,data); /* request VME swap mode for outbound */ } } if (!(bypass & 0x08)) select_msg(23,data); /* request sparse or dense mapping */ if (bypass & 0x10) /* request VMEbus IRQ and Vector */ select_msg(24,data); } int request_test_parameters(struct dmaex_ioctl_data *data) { int test_num; char temp; printf("Enter a test selection from 1-9 : "); scanf("%d", &test_num); switch( test_num ) { case 0: break; case 1: /* This test will test that the VMEbus can be mmaped and accessed */ select_msg(1,data); request_bus_mapping_info(data,0); break; case 2: /* This test will perform Master Block DMA transfers using the */ /* device drivers strategy routine. */ select_msg(2,data); request_bus_mapping_info(data,0x28); break; case 3: /* This test will perform PIO transfers using the device drivers */ /* strategy routine. */ select_msg(3,data); request_bus_mapping_info(data,0); break; case 4: /* This test will request the device drivers strategy routine */ /* to use the device's DMA engine for the DMA transfer */ select_msg(4,data); request_bus_mapping_info(data,0xE); break; case 5: /* This test will install an interrupt handler. Map system memory */ /* to the VMEbus. Wait for a VME device to present an interrupt */ /* request and vector to the installed handler. The test will wait */ /* for the interrupt to be received and signaled on SIGUR1. */ select_msg(5,data); request_bus_mapping_info(data,0x2A); request_bus_mapping_info((struct dmaex_ioctl_data *)&data->data[3],0x1F); break; case 6: /* This test will use the driver's ioctl routine to perform Master */ /* Block DMA transfers to and from a user's buffer wired into kernel */ /* address space. */ select_msg(6,data); request_bus_mapping_info(data,0x28); break; case 7: /* This test will use the driver's ioctl routine to perform Master */ /* Block DMA transfers to and from a kernel buffer mmaped into user */ /* address space. The kernel buffer is the physically contiguous */ /* buffer allocated with cma_dd option and contig_malloc by the driver */ select_msg(7,data); request_bus_mapping_info(data,0x28); break; case 8: /* This test will present a VMEbus interrupt request to a device or */ /* system on the VMEbus. */ select_msg(8,data); request_bus_mapping_info(data,0x1F); break; case 9: /* This test will clear a previously posted request or any request */ /* at the specified VME IRQ line. */ select_msg(9,data); request_bus_mapping_info(data,0x1F); break; default: printf("Invalid test number specified\n"); test_num = 0; break; } /* Flush the interrogation input command line */ do { scanf("%c",&temp); } while (temp != '\n'); return(test_num); } /***************************************************** * main * *****************************************************/ main(int argc, char **argv) { int fd = 0; int test_num, i, status, xfer_mode; int byte_word_capable = 0; char operator = 'N'; int software_byte_swap_needed; vme_atype_t byte_swap_mode; int universe_adapter; /* * Open the /dev/dmaex0 device. */ if ( (fd = open("/dev/dmaex0",O_RDWR)) < 0 ) { perror("Error opening dmaex0 "); exit(1); } /* * Determine whether software byte swap is needed by the VME adapter or * selected by dmaex sysconfigtab parameters. * * This is determined by two methods: * 1. Tru64 UNIX version 4.0F or greater. * o vba_get_info returns information indicating hardware * byte swap not supported by the VME adapter. * o Or, sysconfigtab parameter "dmaex_sw_byte_swap" is set to * select software byte swap regardless of VME adapter. * 2. Tru64 UNIX version 4.0E or less. * o If either or both sysconfigtab parameters "dmaex_univ_adapter" * or "dmaex_sw_byte_swap" are set, use software byte swap. */ if ((ioctl(fd, GET_HW_BYTE_SWAP_INFO, &data)) != 0) { perror("GET_HW_BYTE_SWAP_INFO"); close(fd); exit(1); } software_byte_swap_needed = (int)data.data[0]; if (software_byte_swap_needed) printf("The application must perform software byte swap when needed.\n"); /* * Determine if the VME adapter is the Universe II. All mapping to the * VMEbus is through PCI Dense Space with the Universe II. The tests, * dmaex_mmap_test and dmaex_strategy_pio_xfer_test, need knowledge of * VMEbus mapping (Sparse or Dense). */ if ((ioctl(fd, GET_VBA_BUS_TYPE_INFO, &data)) != 0) { perror("GET_HW_BYTE_SWAP_INFO"); close(fd); exit(1); } universe_adapter = (int)data.data[0]; if (universe_adapter) printf("The Universe II PCI to VME adapter has been detected\n"); if (argc == 1) { test_num = request_test_parameters(&data); } else { test_num = atoi(argv[1]); /* get the function to perform */ for (i=2; i < argc && i < 7; i++) /* parse the data arguments */ data.data[i-2] = strtol(argv[i], NULL, 0); } if ((test_num < 1) || (test_num > 9)) { printf("Invalid test selection %d. Must specify a value from 1-9.\n", test_num); close(fd); exit(0); } /* * The following code section is executed if software byte swap is * needed by the VME adapter or selected by sysconfigtab parameters * for the driver. Byte swap modes are not specified for tests 4, 8 and 9. */ byte_swap_mode = VME_BS_NOSWAP; if ((test_num != 4) && (test_num < 8)) { /* * Save the user specified byte swap mode. */ byte_swap_mode = (vme_atype_t)(data.data[2] & (u_long)VME_BS_MASK); if ((software_byte_swap_needed) && (byte_swap_mode != VME_BS_NOSWAP)) { /* * Software byte swap is needed or selected. The variable * byte_swap_mode contains the specified byte swap selection. * Set the hardware mapping request to VME_BS_NOSWAP. The application * software will need to perform software byte swap prior to writing * and after reading the data. */ data.data[2] &= ~((u_long)VME_BS_MASK); data.data[2] |= (u_long)VME_BS_NOSWAP; } } /* * All mapping to the VMEbus with the Universe II adapter is through * PCI Dense Space regardless of the setting of VME_DENSE flag on the * vba_map_csr request. There are two PIO tests that require information * about the VMEbus mapping. The test are dmaex_mmap_test (PCI Sparse * and Dense mmap testing) and dmaex_strategy_pio_xfer_test. */ if ((universe_adapter) && ((test_num == 1) || (test_num == 3))) /* * For the Universe II, unconditionally set the VME_DENSE flag to * indicate the VMEbus mapping is through VME_DENSE space. */ data.data[2] |= VME_DENSE; switch( test_num ) { case 1: /* * This test will map outbound to a user specified VMEbus * address, address modifiers and for the number of bytes * specified. The test will then mmap the VMEbus address * space into user address space for programmed I/O. If * sparse space was specified, the test will perform byte, * word, and integer transfers using the supplied 'C' * Macro's. If VME_DENSE was specified, the test will * perform interger and quad word transfers. * * The parameters are passed to the tests in the dmaex_ioctl_data * structure. * data.data[0] = number of bytes to map and test * data.data[1] = the VMEbus address to map * data.data[2] = the VMEbus address modifiers, data size, * byte swap mode, and sparse or dense access */ if (getsysinfo(GSI_BYTEWORD_IO, (caddr_t)&byte_word_capable, sizeof(byte_word_capable), NULL, NULL) != 1) printf("getsysinfo failed requesting GSI_BYTEWORD_IO info\n"); if (byte_word_capable) { printf("This platform supports byte addressing\n"); printf("Perform mmap test using byte addressing? (y/(n)) "); scanf("%c",&operator); if ((operator == 'Y') || (operator == 'y')) { printf("Performing mmap byte addressing test\n"); dmaex_mmap_bw_test(fd, &data, software_byte_swap_needed, byte_swap_mode); break; } } printf("Performing mmap non byte addressing test\n"); dmaex_mmap_test(fd, &data, software_byte_swap_needed, byte_swap_mode); break; case 2: /* * This test will use Tru64 UNIX "read" and "write" routines * to perform Master Block DMA transfers using the VME adapters * hardware DMA engine. * * The test will call the kernel mode driver's ioctl routine to * specify the VMEbus address, address modifiers, data size, * byte swap mode and the number of bytes that will be used for * the DMA. The test will then call the driver's ioctl routine * to set the transfer mode to block mode DMA. Once this is done, * the driver will call Tru64 UNIX's read and write routines * to perform the transfer. The actual transfer is performed in * the driver's dmaex_strategy routine. The driver's dmaex_minphys * routine defines the maximum size of each DMA transfer. * * The dmaex_strategy routine will call vba_set_dma_addr * kernel routine to specify the VMEbus address, the VMEbus * address modifiers, the data size, the swap mode, and the * direction of the transfer (DMA_IN or DMA_OUT). DMA_IN or DMA_OUT * indicates that the VME adapters DMA engine will be used. * The value returned from vba_set_dma_addr will be passed to * dma_map_load. The dma_map_load routine will then allocate * resources needed for the Master BLock DMA transfer. On return * from this routine, vba_dma routine will be invoked to cause * the DMA to occur. Once the DMA has completed, the DMA resources * will be released by calling the dma_map_unload routine. * * The parameters are passed to the tests in the dmaex_ioctl_data * structure. * data.data[0] = total number of bytes to DMA * data.data[1] = the starting VMEbus address of the DMA * data.data[2] = the VMEbus address modifiers, data size, and * byte swap mode. */ dmaex_strategy_dma_block_xfer_test(fd, &data, software_byte_swap_needed, byte_swap_mode); break; case 3: /* * This test will use Tru64 UNIX "read" and "write" routines * to perform transfers using programmed I/O operations. * * The test will call the kernel mode driver's ioctl routine to * specify the VMEbus address, address modifiers, data size, * byte swap mode, the number of bytes, and whether sparse or * dense address space will be used for the transfer. The ioctl * will map a window to the VMEbus address space with the * specified parameters. The test will then call the driver's * ioctl routine to set the transfer mode to PIO. Once this is done, * the driver will call Tru64 UNIX's read and write routines * to perform the transfer. The actual transfer is performed in * the driver's dmaex_strategy routine. The driver's dmaex_minphys * routine defines the maximum size of each PIO transfer. * * The dmaex_strategy routine will perform the PIO transfer * using one of the following kernel routines: io_copyin or * read_io_port for PIO reads or io_copyout or write_io_port for * PIO writes. * * The parameters are passed to the tests in the dmaex_ioctl_data * structure. * data.data[0] = total number of bytes to DMA * data.data[1] = the starting VMEbus address of the DMA * data.data[2] = the VMEbus address modifiers, data size, * byte swap mode, and sparse or dense space. */ dmaex_strategy_pio_xfer_test(fd, &data, software_byte_swap_needed, byte_swap_mode); break; case 4: /* * This test will use Tru64 UNIX "read" and "write" routines * to perform transfers using the VME device's hardware DMA * engine. * * The test will call the driver's ioctl routine to set the * transfer mode to device DMA. Once this is done, the driver * will call Tru64 UNIX's read and write routines to perform * the transfer. The actual transfer is performed in the driver's * dmaex_strategy routine. The driver's dmaex_minphys routine * defines the maximum size of each device DMA transfer. * * The dmaex_strategy routine maps the users buffer to the VMEbus. * Obtains the VMEbus address of the mapped buffer and passes the * bus address and byte count to the device's CSRs. It then * instructs the VME device to perform the read or write DMA * transfer. It then waits for a DMA complete interrupt, an error * interrupt or a timeout to occur. The user buffer will then be * unmapped from the VMEbus. * * The parameters are passed to the tests in the dmaex_ioctl_data * structure. * data.data[0] = total number of bytes to DMA */ dmaex_strategy_device_dma_xfer_test(fd, &data); break; case 5: /* * This test will map a user's buffer to the VMEbus * for VME slave accesses. The user's buffer will * be wired down so that it will not be swapped * out while mapped to the VMEbus. This is done * through the device driver's ioctl routine. * * The test will also install an interrupt handler * to a specified VMEbus vector and IRQ. The * interrupt service routine, upon receipt of * the VMEbus interrupt will issue a psignal to * SIGUSR1. The user portion of this test, will * setup a signal catcher for SIGUSR1 and issue a * sigsuspend waiting for SIGUSR1 to be signaled. * Once SIGUSR1 has been received, the test will * unwire the system buffer, unmap the memory from * the system bus and remove the interrupt handler. * * The parameters are passed t