pax_global_header 0000666 0000000 0000000 00000000064 12326537641 0014523 g ustar 00root root 0000000 0000000 52 comment=b46de62356ed3761c9105d7a1d6d085351c0f0af
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/ 0000775 0000000 0000000 00000000000 12326537641 0017641 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/.gitignore 0000664 0000000 0000000 00000000070 12326537641 0021626 0 ustar 00root root 0000000 0000000 *~
*.swp
*.orig
*.bak
*.o
*.d
*.pyc
valgrind_report.txt
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/.gitmodules 0000664 0000000 0000000 00000000131 12326537641 0022011 0 ustar 00root root 0000000 0000000 [submodule "majordomo"]
path = majordomo
url = https://github.com/lerwys/majordomo.git
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/.ycm_extra_conf.py 0000664 0000000 0000000 00000014464 12326537641 0023302 0 ustar 00root root 0000000 0000000 # This file is NOT licensed under the GPLv3, which is the license for the rest
# of YouCompleteMe.
#
# Here's the license text for this file:
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to
import os
import ycm_core
# These are the compilation flags that will be used in case there's no
# compilation database set (by default, one is not set).
# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
flags = [
'-Wall',
'-Wextra',
'-Werror',
'-Wno-long-long',
'-fexceptions',
# THIS IS IMPORTANT! Without a "-std=" flag, clang won't know which
# language to use when compiling headers. So it will guess. Badly. So C++
# headers will be compiled as C headers. You don't want that so ALWAYS specify
# a "-std=".
# For a C project, you would set this to something like 'c99' instead of
# 'c++11'.
'-std=gnuc99',
# ...and the same thing goes for the magic -x option which specifies the
# language that the files to be compiled are written in. This is mostly
# relevant for c++ headers.
# For a C project, you would set this to 'c' instead of 'c++'.
'-x',
'c',
'-isystem',
'../BoostParts',
# This path will only work on OS X, but extra paths that don't exist are not
# harmful
'-isystem',
'../llvm/include',
'-isystem',
'../llvm/tools/clang/include',
'-I',
'.',
'-I',
'./ClangCompleter',
'-isystem',
'./tests/gmock/gtest',
'-isystem',
'./tests/gmock/gtest/include',
'-isystem',
'./tests/gmock',
'-isystem',
'./tests/gmock/include',
'-isystem',
'/usr/include',
'-isystem',
'/usr/local/include',
'-I',
'hal/include',
'-I',
'hal/dev_mngr',
'-I',
'hal/dev_io',
'-I',
'hal/debug',
'-I',
'hal/hal_utils',
'-I',
'hal/ll_io',
'-I',
'hal/ll_io/ops',
'-I',
'hal/sdb',
'-I',
'hal/sm_io',
'-I',
'hal/sm_io/modules',
'-I',
'hal/sm_io/modules/fmc130m_4ch',
'-I',
'hal/msg',
'-I',
'hal/msg/smio_thsafe_ops',
'-I',
'hal/msg/exp_ops',
'-I',
'kernel/include/pcie',
'-g',
'-DDBE_DEBUG=1',
'-lzmq',
'-lczmq',
'-lmdp',
]
# Set this to the absolute path to the folder (NOT the file!) containing the
# compile_commands.json file to use that instead of 'flags'. See here for
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
#
# Most projects will NOT need to set this to anything; you can just change the
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
compilation_database_folder = ''
if os.path.exists( compilation_database_folder ):
database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
database = None
SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
def DirectoryOfThisScript():
return os.path.dirname( os.path.abspath( __file__ ) )
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
if not working_directory:
return list( flags )
new_flags = []
make_next_absolute = False
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
for flag in flags:
new_flag = flag
if make_next_absolute:
make_next_absolute = False
if not flag.startswith( '/' ):
new_flag = os.path.join( working_directory, flag )
for path_flag in path_flags:
if flag == path_flag:
make_next_absolute = True
break
if flag.startswith( path_flag ):
path = flag[ len( path_flag ): ]
new_flag = path_flag + os.path.join( working_directory, path )
break
if new_flag:
new_flags.append( new_flag )
return new_flags
def IsHeaderFile( filename ):
extension = os.path.splitext( filename )[ 1 ]
return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
def GetCompilationInfoForFile( filename ):
# The compilation_commands.json file generated by CMake does not have entries
# for header files. So we do our best by asking the db for flags for a
# corresponding source file, if any. If one exists, the flags for that file
# should be good enough.
if IsHeaderFile( filename ):
basename = os.path.splitext( filename )[ 0 ]
for extension in SOURCE_EXTENSIONS:
replacement_file = basename + extension
if os.path.exists( replacement_file ):
compilation_info = database.GetCompilationInfoForFile(
replacement_file )
if compilation_info.compiler_flags_:
return compilation_info
return None
return database.GetCompilationInfoForFile( filename )
def FlagsForFile( filename, **kwargs ):
if database:
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
# python list, but a "list-like" StringVec object
compilation_info = GetCompilationInfoForFile( filename )
if not compilation_info:
return None
final_flags = MakeRelativePathsInFlagsAbsolute(
compilation_info.compiler_flags_,
compilation_info.compiler_working_dir_ )
# NOTE: This is just for YouCompleteMe; it's highly likely that your project
# does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR
# ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT.
try:
final_flags.remove( '-stdlib=libc++' )
except ValueError:
pass
else:
relative_to = DirectoryOfThisScript()
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
return {
'flags': final_flags,
'do_cache': True
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/COPYING 0000664 0000000 0000000 00000016743 12326537641 0020707 0 ustar 00root root 0000000 0000000 GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/Makefile 0000664 0000000 0000000 00000007336 12326537641 0021312 0 ustar 00root root 0000000 0000000 # Set your cross compile prefix with CROSS_COMPILE variable
CROSS_COMPILE ?=
CMDSEP = ;
CC = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
MAKE = make
INSTALL_DIR ?= /usr/lib
export INSTALL_DIR
# Kernel stuff (pcie driver and library) relative
# directory
KERNEL_DIR = kernel
# General C flags
CFLAGS = -std=gnu99 -O2
LOCAL_MSG_DBG ?= n
DBE_DBG ?= n
CFLAGS_DEBUG =
ifeq ($(LOCAL_MSG_DBG),y)
CFLAGS_DEBUG += -DLOCAL_MSG_DBG=1
endif
ifeq ($(DBE_DBG),y)
CFLAGS_DEBUG += -DDBE_DBG=1
endif
# Debug flags -D=
CFLAGS_DEBUG += -g
# Specific platform Flags
CFLAGS_PLATFORM = -Wall -Wextra -Werror
LDFLAGS_PLATFORM =
# Libraries
LIBS = -lzmq -lczmq -lmdp -lpcidriver
# General library flags -L
LFLAGS =
# Specific platform objects
OBJS_PLATFORM =
# Include other Makefiles as needed here
#include services/services.mk
#include clients/clients.mk
include hal/hal.mk
# Include directories
INCLUDE_DIRS = $(hal_INCLUDE_DIRS) \
-I$(KERNEL_DIR)/include/pcie
# Merge all flags. Optimize for size (-Os)
CFLAGS += $(CFLAGS_PLATFORM) $(CFLAGS_DEBUG)
#-Os
LDFLAGS = $(LDFLAGS_PLATFORM)
#-ffunction-sections -fdata-sections -Wl,--gc-sections
# Output modules
OUT = $(hal_OUT)
.SECONDEXPANSION:
# Save a git repository description
#REVISION = $(shell git describe --dirty --always)
#REVISION_NAME = revision
#OBJ_REVISION = $(addsuffix .o, $(REVISION_NAME))
OBJS_all = $(hal_OBJS) $(OBJ_REVISION)
.PHONY: all kernel_check clean mrproper install uninstall tests examples
# Avoid deletion of intermediate files, such as objects
.SECONDARY: $(OBJS_all)
# Makefile rules
all: kernel_check $(OUT)
# Output Rule
$(OUT): $$($$@_OBJS)
#$(REVISION_NAME).o
$(CC) $(LFLAGS) $(CFLAGS) $(INCLUDE_DIRS) -o $@ $^ $(LDFLAGS) $(LIBS)
#$(SIZE) $@
#$(REVISION_NAME).o: $(REVISION_NAME).c
# $(CC) $(CFLAGS) $(INCLUDE_DIRS) -DGIT_REVISION=\"$(REVISION)\" -c $<
# $(SIZE) -t $@
# Pull in dependency info for *existing* .o files and don't complain if the
# corresponding .d file is not found
-include $(OBJS_all:.o=.d)
# Autodependencies generatation by Scott McPeak, November 2001,
# from article "Autodependencies with GNU make"
%.o: %.c
$(CC) $(CFLAGS) $(INCLUDE_DIRS) -c $*.c -o $@
# create the dependency files "target: pre-requisites"
${CC} -MM $(CFLAGS) $(INCLUDE_DIRS) $*.c > $*.d
# Workaround to make objects in different folders have
# the correct target path. e.g., "dir/bar.o: dir/bar.c dir/foo.h"
# instead of "bar.o: dir/bar.c dir/foo.h"
@mv -f $*.d $*.d.tmp
@sed -e 's|.*:|$*.o:|' < $*.d.tmp > $*.d
# All prereqs listed will also become command-less,
# prereq-less targets. In this way, the prereq file will be
# treated as changed and the target will be rebuilt
# sed: strip the target (everything before colon)
# sed: remove any continuation backslashes
# fmt -1: list words one per line
# sed: strip leading spaces
# sed: add trailing colons
@sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | \
sed -e 's/^ *//' -e 's/$$/:/' >> $*.d
@rm -f $*.d.tmp
kernel_check:
# Check for libraries and issue warning!!!
# $(MAKE) -C $(KERNEL_DIR) all
tests:
$(MAKE) -C $@ all
examples:
$(MAKE) -C $@ all
#install:
# @install -m 755 $(TARGET_SHARED_VER) $(INSTALL_DIR)
# $(foreach lib,$(TARGET_SHARED),ln -sf $(lib).$(LIB_VER) $(INSTALL_DIR)/$(lib) $(CMDSEP))
#
#uninstall:
# $(foreach lib,$(TARGET_SHARED),rm -f $(INSTALL_DIR)/$(lib).$(LIB_VER) $(CMDSEP))
# $(foreach lib,$(TARGET_SHARED),rm -f $(INSTALL_DIR)/$(lib) $(CMDSEP))
clean:
rm -f $(OBJS_all) $(OBJS_all:.o=.d)
$(MAKE) -C tests clean
$(MAKE) -C examples clean
$(MAKE) -C $(KERNEL_DIR) clean
mrproper: clean
rm -f $(OUT)
$(MAKE) -C examples mrproper
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/README.md 0000664 0000000 0000000 00000015325 12326537641 0021126 0 ustar 00root root 0000000 0000000 # Beam Position Monitor Software
Software for controlling the AFC BPM boards
## Prerequisites:
Make sure you have the following libraries installed:
* zeromq-4.0.4 (http://zeromq.org/area:download)
* czmq-2.1.0 (http://czmq.zeromq.org/page:get-the-software)
Cloning this repository
git clone --recursive https://github.com/lerwys/bpm-software.git
Install the Majordomo application from this repository (autotools-based)
cd majordomo/libmdp
Execute the traditional sequence of autotools commands:
./autogen.sh && make && sudo make install
## PCIe Installation Instructions
Install linux header files
sudo apt-get install linux-headers-generic
Install the GIT package
sudo apt-get install binutils gcc
Change folder to the pcie driver location
cd kernel
Compile the PCIe driver and its tests
make
Install the PCIe drivers and libraries
sudo make install
Load the Driver module
sudo insmod /lib/modules/$(uname -r)/extra/PciDriver.ko
After this the kernel should have found the FPGA board
and initialized it. Run the following command and check its output
dmesg | tail
You should see something like the excerpt below:
[267002.495109] pciDriver - pcidriver_init :
Major 250 allocated to nodename 'fpga'
[267002.495130] pciDriver - pcidriver_probe :
Found ML605 board at 0000:01:00.0
[267002.495224] pciDriver - pcidriver_probe :
Device /dev/fpga0 added
[267002.495434] pciDriver - pcidriver_probe_irq :
Registered Interrupt Handler at pin 1, line 11, IRQ 16
[267002.495450] pciDriver - pcidriver_init :
Module loaded
## Running the PCIe self-test
After the installation of the PCIe driver (see above)
it is possible to run a self test to check if
everything is setup properly. For this run the following:
Change to the "compiled tests folder"
cd tests/pcie/bin
Run the test entitled "testPciDriverMod"
sudo ./testPciDriverMod
You should get an output like the following, if everythig is ok:
Testing OPEN DEVICE... PASSED!
Testing PCIDRIVER_IOC_MMAP_MODE... PASSED!
Testing PCIDRIVER_IOC_MMAP_AREA... PASSED!
Testing PCIDRIVER_IOC_PCI_INFO... PASSED!
Testing PCI CONFIG...
Reading PCI config area in byte mode ... PASSED!
Reading PCI config area in word mode ... PASSED!
Reading PCI config area in double-word mode ... PASSED!
Testing PCI mmap...
Reading PCI info... PASSED!
Setting mmap mode... PASSED!
Setting mmap area... PASSED!
MMAP'ing BAR0... PASSED!
Setting mmap area... PASSED!
MMAP'ing BAR2... PASSED!
Setting mmap area... PASSED!
MMAP'ing BAR4... PASSED!
Testing PCIDRIVER_IOC_KMEM_ALLOC...
alloc size 1024 : PASSED!
alloc size 2048 : PASSED!
alloc size 4096 : PASSED!
alloc size 8192 : PASSED!
alloc size 16384 : PASSED!
alloc size 32768 : PASSED!
alloc size 65536 : PASSED!
alloc size 131072 : PASSED!
alloc size 262144 : PASSED!
alloc size 524288 : PASSED!
alloc size 1048576 : PASSED!
alloc size 2097152 : PASSED!
alloc size 4194304 : PASSED!
alloc size 8388608 : FAILED (maybe size is just too big)!
Testing PCIDRIVER_IOC_KMEM_SYNC...
Setting KMEM SYNC to write mode... PASSED!
Setting KMEM SYNC to read mode... PASSED!
Setting KMEM SYNC to read/write mode... PASSED!
Testing PCIDRIVER_IOC_KMEM_FREE... PASSED!
Testing Kernel Buffer mmap...
Setting MMAP mode to KMEM... PASSED!
Allocing size 1024 : PASSED!
MMAPing size 1024 : PASSED!
Allocing size 2048 : PASSED!
MMAPing size 2048 : PASSED!
Allocing size 4096 : PASSED!
MMAPing size 4096 : PASSED!
Allocing size 8192 : PASSED!
MMAPing size 8192 : PASSED!
Allocing size 16384 : PASSED!
MMAPing size 16384 : PASSED!
Allocing size 32768 : PASSED!
MMAPing size 32768 : PASSED!
Allocing size 65536 : PASSED!
MMAPing size 65536 : PASSED!
Allocing size 131072 : PASSED!
MMAPing size 131072 : PASSED!
Allocing size 262144 : PASSED!
MMAPing size 262144 : PASSED!
Allocing size 524288 : PASSED!
MMAPing size 524288 : PASSED!
Allocing size 1048576 : PASSED!
MMAPing size 1048576 : PASSED!
Allocing size 2097152 : PASSED!
MMAPing size 2097152 : PASSED!
Allocing size 4194304 : PASSED!
MMAPing size 4194304 : PASSED!
Allocing size 8388608 : FAILED (maybe size is just too big)!
Freeing Kernel buffers...
Buffer index 0... PASSED!
Buffer index 1... PASSED!
Buffer index 2... PASSED!
Buffer index 3... PASSED!
Buffer index 4... PASSED!
Buffer index 5... PASSED!
Buffer index 6... PASSED!
Buffer index 7... PASSED!
Buffer index 8... PASSED!
Buffer index 9... PASSED!
Buffer index 10... PASSED!
Buffer index 11... PASSED!
Buffer index 12... PASSED!
Testing PCIDRIVER_IOC_UMEM_SGMAP ... PASSED!
Testing PCIDRIVER_IOC_UMEM_SGGET ... PASSED!
Testing PCIDRIVER_IOC_UMEM_SYNC ...
Setting UMEM SYNC to write mode... PASSED!
Setting UMEM SYNC to read mode... PASSED!
Setting UMEM SYNC to read/write mode... PASSED!
Testing PCIDRIVER_IOC_UMEM_SGUNMAP ... PASSED!
-------------------------------------
| All tests PASSED! |
-------------------------------------
Notice that some tests that try to evaluate the limits of a current
Linux Kernel may fail in some cases. In the example above,
two tests , due to an attempt to allocate a large buffer in kernel
space.
This is not actually an error or a failure, it is just trying to
allocate more memory than the kernel has available.
## Installation Instructions
Compile everything with debug info
make DBE_DBG=y
Compile the examples
make examples
Run the server components with the helper script, like shown below:
./init.sh
Typically, one should choose the IPC transport method
for its faster than TCP. For instance:
./init.sh ipc:///tmp/bpm/0
Now we should be good to start making transactions.
Change to the example applications folder
cd examples
Run the Example application
./client -v
Leds should be blinking in the FMC ADC board
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/examples/ 0000775 0000000 0000000 00000000000 12326537641 0021457 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/examples/Makefile 0000664 0000000 0000000 00000002175 12326537641 0023124 0 ustar 00root root 0000000 0000000 # Set your cross compile prefix with CROSS_COMPILE variable
CROSS_COMPILE ?=
CMDSEP = ;
CC = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
MAKE = make
# General C flags
CFLAGS = -std=gnu99 -O2
LOCAL_MSG_DBG ?= n
DBE_DBG ?= n
CFLAGS_DEBUG =
ifeq ($(LOCAL_MSG_DBG),y)
CFLAGS_DEBUG += -DLOCAL_MSG_DBG=1
endif
ifeq ($(DBE_DBG),y)
CFLAGS_DEBUG += -DDBE_DBG=1
endif
# Debug flags -D=
CFLAGS_DEBUG += -g
# Specific platform Flags
CFLAGS_PLATFORM = -Wall -Wextra -Werror
LDFLAGS_PLATFORM =
# Libraries
LIBS = -lzmq -lczmq -lmdp
# General library flags -L
LFLAGS =
# Include directories
INCLUDE_DIRS = -I. -Iinclude
# Merge all flags. Optimize for size (-Os)
CFLAGS += $(CFLAGS_PLATFORM) $(CFLAGS_DEBUG)
#-Os
LDFLAGS = $(LDFLAGS_PLATFORM)
#-ffunction-sections -fdata-sections -Wl,--gc-sections
OUT=client
# Makefile rules
all: $(OUT)
client: client.c
$(CC) $(LFLAGS) $(CFLAGS) $(INCLUDE_DIRS) $^ -o $@ $(LIBS)
#BAD
clean:
find . -iname "*.o" -exec rm '{}' \;
mrproper: clean
rm -f $(OUT)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/examples/client.c 0000664 0000000 0000000 00000005356 12326537641 0023112 0 ustar 00root root 0000000 0000000 /*
* Simple example demonstrating the communication between
* a client and the FPGA device
*/
#include
#include
#include
#define DFLT_BIND_FOLDER "/tmp/bpm"
#define DFLT_BIND_ADDR "0"
#define LEDS_OPERATION 0
/* Our tructure */
typedef struct _bpm_client_t {
mdp_client_t *mdp_client;
} bpm_client_t;
/* Our API */
bpm_client_t *bpm_client_new (char *broker_endp, int verbose)
{
bpm_client_t *self = zmalloc (sizeof *self);
self->mdp_client = mdp_client_new (broker_endp, verbose);
return self;
}
void bpm_client_destroy (bpm_client_t **self_p)
{
assert (self_p);
if (*self_p) {
bpm_client_t *self = *self_p;
mdp_client_destroy (&self->mdp_client);
*self_p = NULL;
}
}
int bpm_blink_leds (bpm_client_t *self, char *service, uint32_t leds)
{
uint32_t operation = LEDS_OPERATION;
zmsg_t *request = zmsg_new ();
zmsg_addmem (request, &operation, sizeof (operation));
zmsg_addmem (request, &leds, sizeof (leds));
mdp_client_send (self->mdp_client, service, &request);
return 0;
}
void print_help (char *program_name)
{
printf( "Usage: %s [options]\n"
"\t-h This help message\n"
"\t-v Verbose output\n"
"\t-b Broker endpoint\n", program_name);
}
int main (int argc, char *argv [])
{
int verbose = 0;
char *broker_endp = NULL;
char **str_p;
if (argc < 2) {
print_help (argv[0]);
exit (1);
}
/* FIXME: This is rather buggy! */
/* Simple handling of command-line options. This should be done
* with getopt, for instance*/
int i;
for (i = 1; i < argc; i++)
{
if (streq(argv[i], "-v")) {
verbose = 1;
}
else if (streq(argv[i], "-h"))
{
print_help (argv [0]);
exit (1);
}
else if (streq (argv[i], "-b")) {
str_p = &broker_endp;
}
/* Fallout for options with parameters */
else {
*str_p = strdup (argv[i]);
}
}
/* Set default broker address */
if (broker_endp == NULL) {
broker_endp = strdup ("ipc://"DFLT_BIND_FOLDER"/"DFLT_BIND_ADDR);
}
bpm_client_t *bpm_client = bpm_client_new (broker_endp, verbose);
for (i = 0; i < 32768; ++i) {
uint32_t leds = (1 << 1);
unsigned int j;
for (j = 0; j < 3; ++j) {
if (!zctx_interrupted) {
bpm_blink_leds (bpm_client, "BPM0:DEVIO:FMC130M_4CH", leds);
usleep (80000);
leds <<= 1;
}
}
}
bpm_client_destroy (&bpm_client);
str_p = &broker_endp;
free (*str_p);
broker_endp = NULL;
return 0;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ 0000775 0000000 0000000 00000000000 12326537641 0020405 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/debug/ 0000775 0000000 0000000 00000000000 12326537641 0021473 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/debug/debug.mk 0000664 0000000 0000000 00000000141 12326537641 0023106 0 ustar 00root root 0000000 0000000 debug_DIR = hal/debug
debug_OBJS = $(debug_DIR)/debug_print.o
debug_INCLUDE_DIRS = $(debug_DIR)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/debug/debug_print.c 0000664 0000000 0000000 00000000775 12326537641 0024152 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include "debug_print.h"
void debug_print (const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
vprintf (fmt, args);
va_end (args);
}
void debug_print_vec (const char *fmt, const char *data, int len)
{
int i;
for (i = 0; i < len; ++i)
printf (fmt, data[i]);
printf ("\n");
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/debug/debug_print.h 0000664 0000000 0000000 00000004744 12326537641 0024157 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
* Parts taken from lwIP debug system
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _DEBUG_PRINT_H_
#define _DEBUG_PRINT_H_
#include
#include "debug_subsys.h" /* This must come before "hal_opts.h" */
#include "hal_opts.h"
/************** Debug functions declarations **************/
void debug_print (const char *fmt, ...) __attribute__((format(printf,1,2)));
void debug_print_vec (const char *fmt, const char *data, int len);
/********************** Debug macros **********************/
#if (DBG_SUBSYS_ON & DBG_MSG)
#define LOCAL_MSG_DBG
#endif
#ifdef DBE_DBG
#define dbg_print(fmt, ...) \
debug_print(fmt, ## __VA_ARGS__)
#define dbg_print_vec(fmt, data, len) \
debug_print_vec(fmt, data, len)
#else
#define dbg_print(fmt, ...)
#define dbg_print_vec(fmt, data, len)
#endif /* DBE_DBG */
/* dbg has the following format:
* 31 - 4 3 - 1 0-0
* DBG_SUBSYS DBG_LVL DBG_HALT
*/
#ifdef DBE_DBG
#define DBE_DEBUG(dbg, fmt, ...) \
do { \
if (((dbg) & DBG_SUBSYS_ON) && \
(((dbg) & DBG_LVL_MASK) >= \
DBG_MIN_LEVEL)) { \
dbg_print(fmt, ## __VA_ARGS__); \
\
if ((dbg) & DBG_LVL_HALT) { \
while(1); \
} \
} \
} while(0)
#define DBE_DEBUG_ARRAY(dbg, fmt, data, len) \
do { \
if (((dbg) & DBG_SUBSYS_ON) && \
(((dbg) & DBG_LVL_MASK) >= \
DBG_MIN_LEVEL)) { \
dbg_print_vec(fmt, data, len); \
\
if ((dbg) & DBG_LVL_HALT) \
while(1); \
} \
} while(0)
#define DBE_ERR(...) \
do { \
dbg_print(fmt, ##__VA_ARGS__); \
} while(0)
#else
#define DBE_DEBUG(dbg, fmt, ...)
#define DBE_DEBUG_ARRAY(dbg, fmt, data, len)
#define DBE_ERR(...)
#endif /* DBE_DBG */
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/debug/debug_subsys.h 0000664 0000000 0000000 00000006115 12326537641 0024345 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _DEBUG_SUBSYS_H_
#define _DEBUG_SUBSYS_H_
/****************** Debug subsys macros ******************/
/*
* DBG_SUBSYS variable is one-hot encoded between
* the bits 31 and 4:
* bit 31 ... bit 4 bit 3 ... bit 0
* [1|0] [1|0] X X
*/
#define DBG_SUBSYS_SHIFT 4
/* Up to 28 debug subsystems (one-hot encoded) */
#define DBG_SUBSYS_MAX 28
#define DBG_SUBSYS_MASK_RAW ((1 << DBG_SUBSYS_MAX)-1)
#define DBG_SUBSYS_MASK (DBG_SUBSYS_MASK_RAW << DBG_SUBSYS_SHIFT)
#define DBG_SUBSYS_GEN(val) ((val & DBG_SUBSYS_MASK_RAW) << DBG_SUBSYS_SHIFT)
/* Debug subsys raw */
#define DBG_DEV_MNGR_RAW 0x1
#define DBG_DEV_IO_RAW 0x2
#define DBG_LL_IO_RAW 0x4
#define DBG_SM_IO_RAW 0x8
#define DBG_MSG_RAW 0x10
#define DBG_HAL_UTILS_RAW 0x20
#define DBG_DEV_MNGR DBG_SUBSYS_GEN(DBG_DEV_MNGR_RAW)
#define DBG_DEV_IO DBG_SUBSYS_GEN(DBG_DEV_IO_RAW)
#define DBG_LL_IO DBG_SUBSYS_GEN(DBG_LL_IO_RAW)
#define DBG_SM_IO DBG_SUBSYS_GEN(DBG_SM_IO_RAW)
#define DBG_MSG DBG_SUBSYS_GEN(DBG_MSG_RAW)
#define DBG_HAL_UTILS DBG_SUBSYS_GEN(DBG_HAL_UTILS_RAW)
/****************** Debug levels macros ******************/
/*
* DBG_LVL variable is binary encoded between
* the bits 3 and 1:
* bit 31 ... bit 4 bit 3 ... bit 1 bit 0
* X X [1|0] [1|0] X
*/
#define DBG_LVL_SHIFT 1
#define DBG_LVL_MAX 3
#define DBG_LVL_MASK_RAW ((1 << DBG_LVL_MAX)-1)
#define DBG_LVL_MASK (DBG_LVL_MASK_RAW << DBG_LVL_SHIFT)
/* Up to 2^3 debug levels */
#define DBG_LVL_GEN(val) ((val & DBG_LVL_MASK_RAW) << DBG_LVL_SHIFT)
/* Debug levels raw */
#define DBG_LVL_TRACE_RAW 0x1
#define DBG_LVL_INFO_RAW 0x2
#define DBG_LVL_WARN_RAW 0x3
#define DBG_LVL_ERR_RAW 0x4
#define DBG_LVL_FATAL_RAW 0x5
/* Debug levels mask'ed and shift'ed */
#define DBG_LVL_TRACE DBG_LVL_GEN(DBG_LVL_TRACE_RAW)
#define DBG_LVL_INFO DBG_LVL_GEN(DBG_LVL_INFO_RAW)
#define DBG_LVL_WARN DBG_LVL_GEN(DBG_LVL_WARN_RAW)
#define DBG_LVL_ERR DBG_LVL_GEN(DBG_LVL_ERR_RAW)
#define DBG_LVL_FATAL DBG_LVL_GEN(DBG_LVL_FATAL_RAW)
/****************** Debug halt macros ******************/
/*
* DBG_HALT variable is binary encoded in bit 0:
* bit 31 ... bit 4 bit 3 ... bit 1 bit 0
* X X X X [1|0]
*/
/* Debug halt */
#define DBG_HALT_SHIFT 0
#define DBG_HALT_MAX 1
#define DBG_HALT_MASK_RAW ((1 << DBG_HALT_SHIFT)-1)
#define DBG_HALT_MASK (DBG_HALT_MASK_RAW << DBG_HALT_SHIFT)
/* 1 halt signal */
#define DBG_HALT_GEN(val) ((val & DBG_HALT_MASK_RAW) << DBG_HALT_SHIFT)
/* Debug halt raw */
#define DBG_LVL_HALT_RAW 0x1
/* Debug halt mask'ed and shift'ed */
#define DBG_LVL_HALT DBG_HALT_GEN(DBG_LVL_HALT_RAW)
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_io/ 0000775 0000000 0000000 00000000000 12326537641 0021652 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_io/dev_io.c 0000664 0000000 0000000 00000011013 12326537641 0023257 0 ustar 00root root 0000000 0000000 #include
#include
#include /* getpid, getppid */
#include
#include "czmq.h"
#include "dev_io.h"
#include "debug_print.h"
void print_help (char *program_name)
{
printf( "Usage: %s [options]\n"
"\t-h This help message\n"
"\t-d Daemon mode.\n"
"\t-v Verbose output\n"
"\t-t Device type\n"
"\t-e Device /dev entry\n"
"\t-b Broker endpoint\n", program_name);
}
int main (int argc, char *argv[])
{
int verbose = 0;
int daemonize = 0;
char *dev_type = NULL;
char *dev_entry = NULL;
char *broker_endp = NULL;
char **str_p = &dev_type; /* default */
int i;
if (argc < 4) {
print_help (argv[0]);
exit (1);
}
/* FIXME: This is rather buggy! */
/* Simple handling of command-line options. This should be done
* with getopt, for instance*/
for (i = 1; i < argc; i++)
{
if (streq (argv[i], "-v")) {
verbose = 1;
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io] Verbose mode set\n");
}
else if (streq (argv[i], "-d")) {
daemonize = 1;
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io] Demonize mode set\n");
}
else if (streq (argv[i], "-t")) {
str_p = &dev_type;
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io] Will set dev_type parameter\n");
}
else if (streq (argv[i], "-e")) {
str_p = &dev_entry;
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io] Will set dev_entry parameter\n");
}
else if (streq (argv[i], "-b")) {
str_p = &broker_endp;
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io] Will set broker_endp parameter\n");
}
else if (streq (argv[i], "-h")) {
print_help (argv[0]);
exit (1);
}
/* Fallout for options with parameters */
else {
*str_p = strdup (argv[i]);
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io] Parameter set to \"%s\"\n", *str_p);
}
}
/* Daemonize dev_io */
if (daemonize != 0) {
int rc = daemon(0, 0);
if (rc != 0) {
perror ("[dev_io] daemon");
goto err_exit;
}
}
llio_type_e llio_type;
/* Parse command-line options */
if (streq (dev_type, "pcie")) {
llio_type = PCIE_DEV;
}
else if (streq (dev_type, "eth")) {
llio_type = ETH_DEV;
}
else {
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_FATAL, "[dev_io] Dev_type parameter is invalid\n");
goto err_exit;
}
/* We don't need it anymore */
str_p = &dev_type;
free (*str_p);
dev_type = NULL;
/* Initilialize dev_io */
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io] Creating devio instance ...\n");
devio_t *devio = devio_new ("BPM0:DEVIO", dev_entry, llio_type,
broker_endp, verbose);
/* devio_t *devio = devio_new ("BPM0:DEVIO", *str_p, llio_type,
"tcp://localhost:5555", verbose); */
if (devio == NULL) {
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_FATAL, "[dev_io] devio_new error!\n");
goto err_exit;
}
/* We don't need it anymore */
str_p = &dev_entry;
free (*str_p);
dev_entry = NULL;
str_p = &broker_endp;
free (*str_p);
broker_endp = NULL;
uint32_t fmc130m_4ch_id = 0x7085ef15;
devio_err_e err;
err = devio_register_sm (devio, fmc130m_4ch_id, NULL);
if (err != DEVIO_SUCCESS) {
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_FATAL, "[dev_io] devio_register_sm error!\n");
goto err_devio;
}
err = devio_init_poller_sm (devio);
if (err != DEVIO_SUCCESS) {
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_FATAL, "[dev_io] devio_init_poller_sm error!\n");
goto err_devio;
}
while (!zctx_interrupted) {
/* Step 1: Loop though all the SDB records and intialize (boot) the
* smio modules*/
/* Step 2: Optionally, register the necessary smio modules specifying
* its ID and calling devio_register_sm */
/* Step 3: Poll all PIPE's sockets to determine if we have something to
* handle, like messages from smios */
/* Step 3.5: If we do, call devio_handle_smio () and treat its
* request as appropriate */
devio_poll_all_sm (devio);
}
err_devio:
devio_destroy (&devio);
err_exit:
free (broker_endp);
free (dev_entry);
free (dev_type);
return 0;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_io/dev_io.h 0000664 0000000 0000000 00000000104 12326537641 0023263 0 ustar 00root root 0000000 0000000 #ifndef _DEV_IO_
#define _DEV_IO_
#include "dev_io_core.h"
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_io/dev_io.mk 0000664 0000000 0000000 00000000477 12326537641 0023460 0 ustar 00root root 0000000 0000000 dev_io_DIR = hal/dev_io
# Here we call _core_OBJS as we need to add
# more objects to this target. This is done in the hal.mk
# makefile
dev_io_core_OBJS = $(dev_io_DIR)/dev_io.o \
$(dev_io_DIR)/dev_io_core.o \
$(dev_io_DIR)/dev_io_err.o
dev_io_INCLUDE_DIRS = $(dev_io_DIR)
dev_io_OUT = dev_io
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_io/dev_io_core.c 0000664 0000000 0000000 00000043640 12326537641 0024302 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include
#include "dev_io_core.h"
#include "dev_io_err.h"
#include "hal_assert.h"
#include "sm_io_mod_dispatch.h"
#include "smio_thsafe_zmq_server.h"
#include "sm_io_thsafe_codes.h"
#include "sm_io_bootstrap.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, DEV_IO, "[dev_io_core]", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, DEV_IO, "[dev_io_core]", \
devio_err_str(DEVIO_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, DEV_IO, "[dev_io_core]", \
devio_err_str (err_type))
#define LLIO_STR ":LLIO\0"
#define DEVIO_POLLER_TIMEOUT 100 /* in msec */
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/* Do the SMIO operation */
static devio_err_e _devio_do_smio_op (devio_t *self, void *msg);
static void _devio_destroy_smio (devio_t *self, uint32_t smio_id);
static void _devio_destroy_smio_all (devio_t *self);
/* Creates a new instance of Device Information */
devio_t * devio_new (char *name, char *endpoint_dev,
llio_type_e type, char *endpoint_broker, int verbose)
{
devio_t *self = (devio_t *) zmalloc (sizeof *self);
ASSERT_ALLOC(self, err_self_alloc);
/* Initialize the sockets structure to talk to nodes */
self->pipes = zmalloc (sizeof (void *) * NODES_MAX_LEN);
ASSERT_ALLOC(self->pipes, err_pipes_alloc);
/* 0 nodes for now... */
self->nnodes = 0;
/* Nullify poller */
self->poller = zpoller_new (NULL);
ASSERT_ALLOC(self->poller, err_poller_alloc);
/* Initilize mdp_worrker last, as we need to have everything ready
* when we attemp to register in broker. Actually, we still need
* to parse the SDB strucutres and register the operations in the
* hash tables... * TODO (FIXME?): Find a better initialitazion routine before registering
* to the broker the request from clients */
self->name = strdup (name);
ASSERT_ALLOC(self->name, err_name_alloc);
self->endpoint_broker = strdup (endpoint_broker);
ASSERT_ALLOC(self->endpoint_broker, err_endp_broker_alloc);
self->verbose = verbose;
/* Concatenate recv'ed name with a llio identifier */
char *llio_name = zmalloc (sizeof (char)*(strlen(name)+strlen(LLIO_STR)+1));
ASSERT_ALLOC(llio_name, err_llio_name_alloc);
strcat (llio_name, name);
strcat (llio_name, LLIO_STR);
self->llio = llio_new (llio_name, endpoint_dev, type,
verbose);
ASSERT_ALLOC(self->llio, err_llio_alloc);
/* We try to open the device */
int err = llio_open (self->llio, NULL);
ASSERT_TEST(err==0, "Error opening device!", err_llio_open);
/* We can free llio_name now, as llio copies the string */
free (llio_name);
llio_name = NULL; /* Avoid double free error */
/* Init sm_io_thsafe_server_ops_h. For now, we assume we want zmq
* for exchanging messages between smio and devio instances */
self->thsafe_server_ops = &smio_thsafe_zmq_server_ops;
/* Init sm_io_h hash */
self->sm_io_h = zhash_new ();
ASSERT_ALLOC(self->sm_io_h, err_sm_io_h_alloc);
/* Init sm_io_thsafe_ops_h dispatch table */
self->disp_table_thsafe_ops = disp_table_new ();
ASSERT_ALLOC(self->disp_table_thsafe_ops, err_disp_table_thsafe_ops_alloc);
disp_table_func_fp *thsafe_server_fp = (disp_table_func_fp *) (self->thsafe_server_ops);
const uint32_t *thsafe_opcodes_p = thsafe_opcodes;
halutils_err_e halutils_err = disp_table_insert_all (self->disp_table_thsafe_ops,
thsafe_server_fp, thsafe_opcodes_p, THSAFE_OPCODE_END);
ASSERT_TEST(halutils_err==HALUTILS_SUCCESS, "Could not initialize dispatch table",
err_disp_table_init);
/* Finally, initialize mdp_worker with service being the BPM */
/* self->worker = mdp_worker_new (endpoint_broker, name, verbose);
ASSERT_ALLOC(self->worker, err_worker_alloc); */
/* Finally, initialize out zeroMQ context */
self->ctx = zctx_new ();
ASSERT_ALLOC(self->ctx, err_ctx_alloc);
/* Adjust linger time for Majordomo protocol (MDP) */
/* A non-zero linger value is required for DISCONNECT to be sent
* when the worker is destroyed. 100 is arbitrary but chosen to be
* sufficient for common cases without significant delay in broken ones. */
zctx_set_linger (self->ctx, 100);
return self;
err_ctx_alloc:
err_disp_table_init:
disp_table_destroy (&self->disp_table_thsafe_ops);
err_disp_table_thsafe_ops_alloc:
zhash_destroy (&self->sm_io_h);
err_sm_io_h_alloc:
llio_release (self->llio, NULL);
err_llio_open:
llio_destroy (&self->llio);
err_llio_alloc:
free (llio_name);
err_llio_name_alloc:
free (self->endpoint_broker);
err_endp_broker_alloc:
free (self->name);
err_name_alloc:
zpoller_destroy (&self->poller);
err_poller_alloc:
free (self->pipes);
err_pipes_alloc:
free (self);
err_self_alloc:
return NULL;
}
/* Destroy an instance of the Device Information */
devio_err_e devio_destroy (devio_t **self_p)
{
assert (self_p);
if (*self_p) {
devio_t *self = *self_p;
/* Destroy children threads before proceeding */
_devio_destroy_smio_all (self);
/* Starting destructing by the last resource */
/* Notice that we destroy the worker first, as to
* unregister from broker as soon as possible to avoid
* loosing requests from clients */
zctx_destroy (&self->ctx);
disp_table_destroy (&self->disp_table_thsafe_ops);
zhash_destroy (&self->sm_io_h);
self->thsafe_server_ops = NULL;
llio_release (self->llio, NULL);
llio_destroy (&self->llio);
free (self->endpoint_broker);
free (self->name);
zpoller_destroy (&self->poller);
free (self->pipes);
free (self);
*self_p = NULL;
}
return DEVIO_SUCCESS;
}
/* Read specific information about the device. Typically,
* this is stored in the SDB structure inside the device */
devio_err_e devio_print_info (devio_t *self)
{
(void) self;
return DEVIO_ERR_FUNC_NOT_IMPL;
}
/* Register an specific sm_io modules to this device */
devio_err_e devio_register_sm (devio_t *self, uint32_t smio_id, void *priv)
{
assert (self);
/* Search the sm_io_mod_dsapatch table for the smio_id and,
* if found, call the correspondent bootstrap code to initilize
* the sm_io module */
th_boot_args_t *th_args = NULL;
/* For now, just do a simple linear search. We can afford this, as
* we don't expect to insert new sm_io modules often */
unsigned int i;
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE,
"[dev_io_core:register_sm] smio_mod_dispatch table size = %ld\n",
ARRAY_SIZE(smio_mod_dispatch));
for (i = 0; i < ARRAY_SIZE(smio_mod_dispatch); ++i) {
if (smio_mod_dispatch[i].id == smio_id) {
/* Found! Call bootstrap code and insert in
* hash table */
/* FIXME: Why do I need this? smio always gets initilized
* after smio_mod_dispatch[i].bootstrap_ops->smio_boot (self); */
/* smio_t *smio = NULL; */
/* It is expected tha after the boot () call the operations
* this sm_io inscate can handle are already registered! */
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE,
"[dev_io_core:register_sm] Allocating thread args\n");
/* Alloacate thread arguments struct and pass it to the
* thread. It is the responsability of the calling thread
* to clear this structure after using it! */
th_boot_args_t *th_args = zmalloc (sizeof *th_args);
ASSERT_ALLOC (th_args, err_th_args_alloc);
th_args->parent = self;
/* FIXME: weak identifier */
th_args->smio_id = i;
th_args->broker = self->endpoint_broker;
th_args->service = self->name;
th_args->verbose = self->verbose;
th_args->priv = priv;
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE,
"[dev_io_core:register_sm] Calling boot func\n");
uint32_t pipe_idx = self->nnodes++;
self->pipes [pipe_idx] = zthread_fork (self->ctx, smio_startup,
th_args);
/* self->pipes [pipe_idx] = zthread_fork (self->ctx,
smio_mod_dispatch[i].bootstrap_ops->thread_boot, th_args); */
/*smio = smio_mod_dispatch[i].bootstrap_ops->boot (self);*/
/*ASSERT_ALLOC (smio, err_smio_alloc); */
/* Stringify ID */
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE,
"[dev_io_core:register_sm] Stringify hash ID\n");
char *key = halutils_stringify_key (smio_mod_dispatch[i].id);
ASSERT_ALLOC (key, err_key_alloc);
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE,
"[dev_io_core:register_sm] Inserting hash with key: %s\n", key);
zhash_insert (self->sm_io_h, key, self->pipes [pipe_idx]);
free (key);
/* stop on first match */
break;
}
}
//free (th_args);
return DEVIO_SUCCESS;
err_key_alloc:
free (th_args);
err_th_args_alloc:
return DEVIO_ERR_ALLOC;
}
/* Register all sm_io module that this device can handle,
* according to the device information stored in the SDB */
devio_err_e devio_register_all_sm (devio_t *self)
{
(void) self;
return DEVIO_ERR_FUNC_NOT_IMPL;
}
devio_err_e devio_unregister_sm (devio_t *self, uint32_t smio_id)
{
(void) self;
(void) smio_id;
return DEVIO_ERR_FUNC_NOT_IMPL;
}
devio_err_e devio_unregister_all_sm (devio_t *self)
{
(void) self;
return DEVIO_ERR_FUNC_NOT_IMPL;
}
devio_err_e devio_init_poller_sm (devio_t *self)
{
devio_err_e err = DEVIO_SUCCESS;
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE,
"[dev_io_core:poll_all_sm] Calling init_poller_sm\n");
/* Set-up poller */
if (self->nnodes == 0) {
err = DEVIO_ERR_NO_NODES;
goto err_no_nodes;
}
/* FIXME: From CZMQ sources: If you need a balanced poll, use
* the low level zmq_poll method directly
*/
unsigned int i;
for (i = 0; i < self->nnodes; ++i) {
int zerr = zpoller_add (self->poller, self->pipes[i]);
if (zerr < 0) {
err = DEVIO_ERR_ALLOC;
break;
}
}
err_no_nodes:
return err;
}
devio_err_e devio_poll_all_sm (devio_t *self)
{
devio_err_e err = DEVIO_SUCCESS;
if (!self->poller) {
err = DEVIO_ERR_UNINIT_POLLER;
goto err_uninitialized_poller;
}
/* Wait up to 100 ms */
void *which = zpoller_wait (self->poller, DEVIO_POLLER_TIMEOUT);
if (zpoller_expired (self->poller)) {
/*DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE,
"[dev_io_core:poll_all_sm] poller expired\n");*/
goto err_poller_expired;
}
if (zpoller_terminated (self->poller)) {
/*DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE,
"[dev_io_core:poll_all_sm] poller terminated\n");*/
err = DEVIO_ERR_TERMINATED;
goto err_poller_terminated;
}
zmsg_t *recv_msg = zmsg_recv (which);
/* Prepare the args structure */
zmq_server_args_t server_args = {.msg = &recv_msg, .reply_to = which};
err = _devio_do_smio_op (self, &server_args);
err_poller_expired:
err_poller_terminated:
err_uninitialized_poller:
return err;
}
devio_err_e devio_do_smio_op (devio_t *self, void *msg)
{
return _devio_do_smio_op (self, msg);
}
/**************** Helper Functions ***************/
static devio_err_e _devio_do_smio_op (devio_t *self, void *msg)
{
zmq_server_args_t *server_args = (zmq_server_args_t *) msg;
/* Message is:
* frame 0: opcode
* frame 1: payload */
/* Extract the first frame and determine the opcode */
zframe_t *opcode = zmsg_pop (*server_args->msg);
devio_err_e err = (opcode == NULL) ? DEVIO_ERR_BAD_MSG : DEVIO_SUCCESS;
ASSERT_TEST(opcode != NULL, "Could not receive opcode", err_null_opcode);
if (zframe_size (opcode) != THSAFE_OPCODE_SIZE) {
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_ERR,
"[dev_io_core:poll_all_sm] Invalid opcode size received\n");
err = DEVIO_ERR_BAD_MSG;
goto err_wrong_opcode_size;
}
uint32_t opcode_data = *(uint32_t *) zframe_data (opcode);
if (opcode_data > THSAFE_OPCODE_END-1) {
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_ERR,
"[dev_io_core:poll_all_sm] Invalid opcode received\n");
err = DEVIO_ERR_BAD_MSG;
goto err_invalid_opcode;
}
/* Do the actual work... */
disp_table_call (self->disp_table_thsafe_ops, opcode_data, self, server_args);
err_invalid_opcode:
err_wrong_opcode_size:
zframe_destroy (&opcode);
err_null_opcode:
return err;
}
static void _devio_destroy_smio_all (devio_t *self)
{
#if 0
unsigned i;
for (i = 0; i < self->nnodes; ++i) {
/* This cannot fail at this point... but it can */
zmsg_t *msg = zmsg_new ();
/* An empty message means to selfdestruct */
zmsg_pushstr (msg, "");
zmsg_send (&msg, self->pipes [i]);
}
#endif
/* Get all hash keys */
zlist_t *hash_keys = zhash_keys (self->sm_io_h);
ASSERT_ALLOC (hash_keys, err_hash_keys_alloc);
char *hash_item = zlist_first (hash_keys);
/* Iterate over all keys removing each of one */
for (; hash_item != NULL; hash_item = zlist_next (hash_keys)) {
/* FIXME: Usage of stroul fucntion for reconverting the string
* into a uint32_t */
_devio_destroy_smio (self, (uint32_t) strtoul (hash_item,
(char **) NULL, 16));
}
zlist_destroy (&hash_keys);
err_hash_keys_alloc:
return;
}
static void _devio_destroy_smio (devio_t *self, uint32_t smio_id)
{
assert (self);
/* Stringify ID */
char *key_c = halutils_stringify_key (smio_id);
ASSERT_ALLOC (key_c, err_key_alloc);
/* Lookup SMIO reference in hash table */
void *pipe = zhash_lookup (self->sm_io_h, key_c);
ASSERT_TEST (pipe != NULL, "Could not find SMIO registered with this ID",
err_hash_lookup);
/* Send message to SMIO informing it to destroy itself */
/* This cannot fail at this point... but it can */
zmsg_t *send_msg = zmsg_new ();
ASSERT_ALLOC (send_msg, err_msg_alloc);
/* An empty message means to selfdestruct */
zmsg_pushstr (send_msg, "");
int zerr = zmsg_send (&send_msg, pipe);
ASSERT_TEST (zerr == 0, "Could not send self-destruct message to SMIO instance",
err_send_msg);
/* Finally, remove the pipe from hash */
zhash_delete (self->sm_io_h, key_c);
err_send_msg:
zmsg_destroy (&send_msg);
err_msg_alloc:
err_hash_lookup:
free (key_c);
err_key_alloc:
return;
}
/********* Low-level generic methods API *********/
#define CHECK_FUNC(func_p) \
do { \
if(func_p == NULL) { \
DBE_DEBUG (DBG_DEV_IO | DBG_LVL_ERR, \
"[sm_io] %s\n", \
devio_err_str (DEVIO_ERR_FUNC_NOT_IMPL)); \
return NULL; \
} \
} while(0)
/* Declare wrapper for all DEVIO functions API */
#define DEVIO_FUNC_WRAPPER(func_name, ...) \
{ \
assert (owner); \
CHECK_FUNC (((devio_t *)owner)->thsafe_server_ops->func_name);\
return ((devio_t *)owner)->thsafe_server_ops->func_name (owner, ##__VA_ARGS__); \
}
/**** Open device ****/
void *smio_thsafe_server_open (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_open, args)
/**** Release device ****/
void *smio_thsafe_server_release (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_release, args)
/**** Read data from device ****/
void *smio_thsafe_server_read_16 (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_read_16, args)
void *smio_thsafe_server_read_32 (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_read_32, args)
void *smio_thsafe_server_read_64 (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_read_64, args)
/**** Write data to device ****/
void *smio_thsafe_server_write_16 (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_write_16, args)
void *smio_thsafe_server_write_32 (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_write_32, args)
void *smio_thsafe_server_write_64 (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_write_64, args)
/**** Read data block from device function pointer, size in bytes ****/
void *smio_thsafe_server_read_block (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_read_block, args)
/**** Write data block from device function pointer, size in bytes ****/
void *smio_thsafe_server_write_block (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_write_block, args)
/**** Read data block via DMA from device, size in bytes ****/
void *smio_thsafe_server_read_dma (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_read_dma, args)
/**** Write data block via DMA from device, size in bytes ****/
void *smio_thsafe_server_write_dma (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_write_dma, args)
/**** Read device information function pointer ****/
/* int smio_thsafe_server_read_info (void *owner, void *args)
DEVIO_FUNC_WRAPPER (thsafe_server_read_info, args) Moved to dev_io */
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_io/dev_io_core.h 0000664 0000000 0000000 00000014044 12326537641 0024303 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _DEV_IO_CORE_H_
#define _DEV_IO_CORE_H_
#include "czmq.h"
#include "mdp.h"
#include "hal_utils.h"
#include "dispatch_table.h"
#include "dev_io_err.h"
#include "ll_io.h"
/* #include "sm_io.h" */
/* #include "sm_io_thsafe_codes.h" */
/* #include "sm_io_bootstrap.h" */
/* SMIO hash key length in chars */
#define SMIO_HKEY_LEN 8
#define NODES_MAX_LEN 20
struct _smio_thsafe_server_ops_t;
struct _devio_t {
/* General information */
/*mdp_worker_t *worker;*/ /* zeroMQ Majordomo Worker */
zctx_t *ctx; /* zeroMQ Context */
void **pipes; /* Address nodes using this array of pipes */
zpoller_t *poller; /* Poller structure to multiplex threads messages */
unsigned int nnodes; /* Number of actual nodes */
char *name; /* Identification of this worker instance */
char *endpoint_broker; /* Broker location to connect to */
int verbose; /* Print activity to stdout */
/* ll_io instance for Low-Level operations*/
llio_t *llio;
/* Server part of the llio operations. This is the bridge between the
* smio client part of the llio operations and the de-facto
* llio operations */
const struct _smio_thsafe_server_ops_t *thsafe_server_ops;
/* Hash containg all the sm_io objects that
* this dev_io can handle. It is composed
* of key (10-char ID) / value (sm_io instance) */
zhash_t *sm_io_h;
/* Dispatch table containg all the sm_io thsafe operations
* that we need to handle. It is composed
* of key (4-char ID) / value (pointer to funtion) */
disp_table_t *disp_table_thsafe_ops;
};
struct _smio_thsafe_server_ops_t {
disp_table_func_fp thsafe_server_open; /* Open device */
disp_table_func_fp thsafe_server_release; /* Release device */
disp_table_func_fp thsafe_server_read_16; /* Read 16-bit data */
disp_table_func_fp thsafe_server_read_32; /* Read 32-bit data */
disp_table_func_fp thsafe_server_read_64; /* Read 64-bit data */
disp_table_func_fp thsafe_server_write_16; /* Write 16-bit data */
disp_table_func_fp thsafe_server_write_32; /* Write 32-bit data */
disp_table_func_fp thsafe_server_write_64; /* Write 64-bit data */
disp_table_func_fp thsafe_server_read_block; /* Read arbitrary block size data,
parameter size in bytes */
disp_table_func_fp thsafe_server_write_block; /* Write arbitrary block size data,
parameter size in bytes */
disp_table_func_fp thsafe_server_read_dma; /* Read arbitrary block size data via DMA,
parameter size in bytes */
disp_table_func_fp thsafe_server_write_dma; /* Write arbitrary block size data via DMA,
parameter size in bytes */
/*disp_table_func_fp_read_info_fp thsafe_server_read_info; Moved to dev_io */
/* Read device information data */
};
/* Opaque llio_th_safe_ops structure */
typedef struct _smio_thsafe_server_ops_t smio_thsafe_server_ops_t;
/* Opaque class structure */
typedef struct _devio_t devio_t;
/***************** Our methods *****************/
/* Creates a new instance of Device Information */
devio_t * devio_new (char *name, char *endpoint_dev,
llio_type_e type, char *endpoint_broker, int verbose);
/* Destroy an instance of the Device Information */
devio_err_e devio_destroy (devio_t **self_p);
/* Read specific information about the device. Typically,
* this is stored in the SDB structure inside the device */
devio_err_e devio_print_info (devio_t *self);
/* Register an specific sm_io module to this device */
devio_err_e devio_register_sm (devio_t *self, uint32_t smio_id, void *priv);
/* Register all sm_io module that this device can handle,
* according to the device information stored in the SDB */
devio_err_e devio_register_all_sm (devio_t *self);
devio_err_e devio_unregister_sm (devio_t *self, uint32_t smio_id);
devio_err_e devio_unregister_all_sm (devio_t *self);
/* Initilize poller with all of the initialized PIPE sockets */
devio_err_e devio_init_poller_sm (devio_t *self);
/* Poll all PIPE sockets */
devio_err_e devio_poll_all_sm (devio_t *self);
/* Router for all the opcodes registered for this dev_io */
/* devio_err_e devio_do_op (devio_t *self, uint32_t opcode, int nargs, ...); */
/* Router for all of the low-level operations for this dev_io */
devio_err_e devio_do_smio_op (devio_t *self, void *msg);
/********* Low-level generic methods API *********/
/* Open device */
void *smio_thsafe_server_open (void *owner, void *args);
/* Release device */
void *smio_thsafe_server_release (void *owner, void *args);
/* Read data from device */
void *smio_thsafe_server_read_16 (void *owner, void *args);
void *smio_thsafe_server_read_32 (void *owner, void *args);
void *smio_thsafe_server_read_64 (void *owner, void *args);
/* Write data to device */
void *smio_thsafe_server_write_16 (void *owner, void *args);
void *smio_thsafe_server_write_32 (void *owner, void *args);
void *smio_thsafe_server_write_64 (void *owner, void *args);
/* Read data block from device, size in bytes */
void *smio_thsafe_server_read_block (void *owner, void *args);
/* Write data block from device, size in bytes */
void *smio_thsafe_server_write_block (void *owner, void *args);
/* Read data block via DMA from device, size in bytes */
void *smio_thsafe_server_read_dma (void *owner, void *args);
/* Write data block via DMA from device, size in bytes */
void *smio_thsafe_server_write_dma (void *owner, void *args);
/* Read device information */
/* void *smio_thsafe_server_read_info (void *owner, void *args); */
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_io/dev_io_err.c 0000664 0000000 0000000 00000002203 12326537641 0024130 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#include "dev_io_err.h"
static const char *devio_err [DEVIO_ERR_END] =
{
[DEVIO_SUCCESS] = "Success",
[DEVIO_ERR_ALLOC] = "Could not allocate memory",
[DEVIO_ERR_FUNC_NOT_IMPL] = "Function not implemented",
[DEVIO_ERR_NO_SMIO_OP] = "No sm_io registered for this opcode",
[DEVIO_ERR_NO_SMIO_ID] = "No sm_io registered with this ID",
[DEVIO_ERR_SMIO_DO_OP] = "Error calling specific sm_io function",
[DEVIO_ERR_NO_NODES] = "No thread nodes available",
[DEVIO_ERR_UNINIT_POLLER] = "Poller uninitilized",
[DEVIO_ERR_BAD_MSG] = "Malformed message received",
[DEVIO_ERR_TERMINATED] = "Terminated devio instance"
};
/* Convert enumeration type to string */
const char * devio_err_str (devio_err_e err)
{
return devio_err [err];
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_io/dev_io_err.h 0000664 0000000 0000000 00000002414 12326537641 0024141 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#ifndef _DEVIO_ERR_H_
#define _DEVIO_ERR_H_
enum _devio_err_e
{
DEVIO_SUCCESS = 0, /* No error */
DEVIO_ERR_ALLOC, /* Could not allocate memory */
DEVIO_ERR_FUNC_NOT_IMPL, /* Function not implemented */
DEVIO_ERR_SMIO_DO_OP, /* Error calling sm_io specific function */
DEVIO_ERR_NO_SMIO_OP, /* No sm_io registered for the opcode argument */
DEVIO_ERR_NO_SMIO_ID, /* No sm_io registered with the id argument */
DEVIO_ERR_NO_NODES, /* No thread nodes available */
DEVIO_ERR_UNINIT_POLLER, /* Uninitliazed poller */
DEVIO_ERR_BAD_MSG, /* Malformed message received */
DEVIO_ERR_TERMINATED, /* Terminated devio instance */
DEVIO_ERR_END /* End of enum marker */
};
typedef enum _devio_err_e devio_err_e;
/* Convert enumeration type to string */
const char * devio_err_str (devio_err_e err);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_mngr/ 0000775 0000000 0000000 00000000000 12326537641 0022206 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_mngr/dev_mngr.c 0000664 0000000 0000000 00000021125 12326537641 0024154 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include /* sigaction */
//#include /* siginfo_t */
#include
#include
#include
#include /* perror */
#include
#include /* waitpid */
#include
#include /* chmod */
#include "dev_mngr.h"
#include "debug_print.h"
#define DFLT_BIND_FOLDER "/tmp/bpm"
#define DFLT_BIND_ADDR "0"
#define IPC_FILE_PERM 0777
/* Global variable for testing an asynchronous event */
volatile sig_atomic_t __new_dev = 0;
volatile sig_atomic_t __dev_nums = 0;
/* This signal handler emulates some device being plugged */
static void dmngr_sigusr1_h (int sig, siginfo_t *siginfo, void *context)
{
(void) sig;
(void) context;
(void) siginfo;
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] Recv'ed signal: %d\n",
siginfo->si_signo);
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] New PCIe device detected!\n");
/* Simplistic, inefficient method of handling a new_dev */
__new_dev = 1;
__dev_nums++;
}
int dmngr_wait_chld_f (void)
{
int chld_status;
pid_t chld_pid = waitpid (-1, &chld_status, WNOHANG);
/* Error or no child exists */
if (chld_pid == (pid_t) -1) {
/* Not actually an error if ECHILD. Do nothing... */
if (errno == ECHILD) {
/* DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_INFO, "[dev_mngr] no child to wait for\n"); */
return 0;
}
return -1;
}
/* Child exists but have not changed its state */
if (chld_pid == (pid_t) 0) {
/* DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_INFO, "[dev_mngr] Child has not changed its state\n"); */
return 0;
}
/* Child exists and has changed its state. Check fior the return status */
if (WIFEXITED (chld_status)) {
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_WARN, "[dev_mngr] Child exited%s with status %d\n",
WCOREDUMP(chld_status) ? " and dumped core" : "",
WEXITSTATUS(chld_status));
__dev_nums--;
}
if (WIFSTOPPED (chld_status)) {
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_WARN, "[dev_mngr] Child stopped by signal %d\n",
WSTOPSIG(chld_status));
}
if (WIFSIGNALED (chld_status)) {
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_WARN, "[dev_mngr] Child signalled by signal %d\n",
WTERMSIG(chld_status));
__dev_nums--;
}
return 0;
}
int dmngr_spawn_chld_f (const char *program, char *const argv[])
{
/* Fill the devio strucutre and create a new process
* in charge of handling it */
pid_t child = fork ();
if (child == -1) {
perror ("[dev_mngr] fork");
/* What to do in case of error? retry ? */
return -1;
}
else if (child == 0) { /* Child */
int err = execv (program, argv);
if (err < 0) {
perror ("[dev_mngr] execl");
return -1;
}
}
else { /* Parent */
}
return 0; /* Success */
}
void print_help (char *program_name)
{
printf( "Usage: %s [options]\n"
"\t-h This help message\n"
"\t-d Daemon mode.\n"
"\t-v Verbose output\n"
"\t-b Broker endpoint\n", program_name);
}
int main (int argc, char *argv[])
{
int verbose = 0;
int daemonize = 0;
char *broker_endp = NULL;
char **str_p;
int i;
if (argc < 2) {
print_help (argv[0]);
exit (1);
}
/* FIXME: This is rather buggy! */
/* Simple handling of command-line options. This should be done
* with getopt, for instance*/
for (i = 1; i < argc; i++)
{
if (streq(argv[i], "-v")) {
verbose = 1;
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] Verbose mode set\n");
}
else if (streq(argv[i], "-d")) {
daemonize = 1;
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] Demonize mode set\n");
}
else if (streq(argv[i], "-h"))
{
print_help (argv [0]);
exit (1);
}
else if (streq (argv[i], "-b")) {
str_p = &broker_endp;
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] Going to set broker_endp parameter\n");
}
/* Fallout for options with parameters */
else {
*str_p = strdup (argv[i]);
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] Parameter set to \"%s\"\n", *str_p);
}
}
/* Set default broker address */
if (broker_endp == NULL) {
broker_endp = DFLT_BIND_FOLDER"/"DFLT_BIND_ADDR;
}
/* Daemonize dev_mngr */
if (daemonize != 0) {
int rc = daemon(0, 0);
if (rc != 0) {
perror ("[dev_mngr] daemon");
goto err_daemonize;
}
}
/* See the fake promiscuous endpoint tcp*:*. To be changed soon! */
dmngr_t *dmngr = dmngr_new ("dev_mngr", "tcp://*:*", verbose);
if (dmngr == NULL) {
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_FATAL, "[dev_mngr] Fail to allocate dev_mngr instance\n");
goto err_dmngr_alloc;
}
dmngr_sig_handler_t dmngr_sigusr1_handler =
{.signal = SIGUSR1,
.dmngr_sig_h = dmngr_sigusr1_h};
/* dmngr_sigusr1_handler_t dmngr_sigkill_handler =
{.signal = SIGKILL,
.dmngr_sig_h = dmngr_sigusr1_handler};
dmngr_sigusr1_handler_t dmngr_sigterm_handler =
{.signal = SIGTERM,
.dmngr_sig_h = dmngr_sigusr1_handler}; */
dmngr_err_e err = dmngr_set_sig_handler (dmngr, &dmngr_sigusr1_handler);
if (err != DMNGR_SUCCESS) {
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_FATAL, "[dev_mngr] dmngr_set_sig_handler error!\n");
goto err_exit;
}
dmngr_set_wait_clhd_handler (dmngr, &dmngr_wait_chld_f);
dmngr_set_spawn_clhd_handler (dmngr, &dmngr_spawn_chld_f);
err = dmngr_register_sig_handlers (dmngr);
if (err != DMNGR_SUCCESS) {
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_FATAL, "[dev_mngr] dmngr_register_sig_handler error!\n");
goto err_exit;
}
/* Here we should monitor the plug of new devices, such as
* PCIe devices, by means of a udev event (or some other) and
* Ethernet ones, by using a discovery protocol based on zeroMQ
* (zbeacon should provide a sufficient infrastrucutre for that)
*/
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] Waiting for new device\n");
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] PID: %d\n", getpid());
/* Do until a C^c is pressed (daemon mode unset) or SIGTERM signal arrives */
while (!zctx_interrupted) {
/* DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] ., PID: %d\n", getpid()); */
if (__new_dev) {
__new_dev = 0;
/* Verify if the Broker is running. If not, spawn it */
if (!dmngr_is_broker_running (dmngr)) {
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] Spawing Broker\n");
char *argv_exec[] = {"mdp_broker", broker_endp, NULL};
/* char *argv_exec[] = {"mdp_broker", "-v", NULL}; */
int spawn_err = dmngr_spawn_chld (dmngr, "mdp_broker", argv_exec);
/* Just fail miserably, for now */
if (spawn_err < 0) {
perror ("spwan");
goto err_exit;
}
}
/* Argument options are "process name", "device type" and
*"dev entry" */
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE, "[dev_mngr] Spawing DEVIO worker\n");
char *argv_exec[] = {"dev_io", "-t", "pcie", "-e", "/dev/fpga0",
"-b", broker_endp, NULL};
int spawn_err = dmngr_spawn_chld (dmngr, "./dev_io", argv_exec);
/* Just fail miserably, for now */
if (spawn_err < 0) {
perror ("spwan");
goto err_exit;
}
}
/* Check the status of child processes */
/* DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_TRACE,
* "[dev_mngr] PID: %d will wait for child. # = %d\n", getpid(), __dev_nums); */
err = dmngr_wait_chld (dmngr);
if (err != DMNGR_SUCCESS) {
//perror("[dev_mngr] waitpid");
goto err_exit;
exit (1);
}
/* Do some monitoring activities */
sleep(1);
}
err_exit:
dmngr_destroy (&dmngr);
err_dmngr_alloc:
err_daemonize:
str_p = &broker_endp;
free (*str_p);
broker_endp = NULL;
return 0;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_mngr/dev_mngr.h 0000664 0000000 0000000 00000000366 12326537641 0024165 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _DEV_MNGR_H_
#define _DEV_MNGR_H_
#include "dev_mngr_core.h"
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_mngr/dev_mngr.mk 0000664 0000000 0000000 00000000535 12326537641 0024343 0 ustar 00root root 0000000 0000000 dev_mngr_DIR = hal/dev_mngr
# Here we call _core_OBJS as we need to add
# more objects to this target. This is done in the hal.mk
# makefile
dev_mngr_core_OBJS = $(dev_mngr_DIR)/dev_mngr.o \
$(dev_mngr_DIR)/dev_mngr_core.o \
$(dev_mngr_DIR)/dev_mngr_err.o
dev_mngr_INCLUDE_DIRS = $(dev_mngr_DIR)
dev_mngr_OUT = dev_mngr
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_mngr/dev_mngr_core.c 0000664 0000000 0000000 00000013457 12326537641 0025175 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include "dev_mngr_core.h"
#include "hal_assert.h"
/* Some global variables for use with signal handlers */
extern volatile sig_atomic_t __dev_nums;
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, DEV_MNGR, "dev_mngr_core",\
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, DEV_MNGR, "dev_mngr_core", \
dmngr_err_str(DMNGR_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, DEV_MNGR, "dev_mngr_core", \
dmngr_err_str (err_type))
/* Creates a new instance of the Device Manager */
dmngr_t * dmngr_new (char *name, char *endpoint, int verbose)
{
assert (name);
assert (endpoint);
dmngr_t *self = (dmngr_t *) zmalloc (sizeof *self);
ASSERT_ALLOC(self, err_self_alloc);
/* Initialize the Device Manager */
self->ctx = zctx_new ();
ASSERT_ALLOC(self->ctx, err_ctx_alloc);
/* Create Dealer for use with zbeacon */
self->dealer = zsocket_new (self->ctx, ZMQ_DEALER);
ASSERT_ALLOC(self->dealer, err_dealer_alloc);
zsocket_bind (self->dealer, endpoint);
self->name = strdup (name);
ASSERT_ALLOC(self->name, err_name_alloc);
self->endpoint = strdup (endpoint);
ASSERT_ALLOC(self->endpoint, err_endpoint_alloc);
self->verbose = verbose;
self->ops = (dmngr_ops_t *) zmalloc (sizeof *self->ops);
ASSERT_ALLOC(self->ops, err_ops_alloc);
self->ops->sig_ops = zlist_new ();
ASSERT_ALLOC(self->ops->sig_ops, err_list_alloc);
self->broker_running = false;
return self;
err_list_alloc:
free (self->ops);
err_ops_alloc:
free (self->endpoint);
err_endpoint_alloc:
free (self->name);
err_name_alloc:
zsocket_destroy (self->ctx, self->dealer);
err_dealer_alloc:
zctx_destroy (&self->ctx);
err_ctx_alloc:
free (self);
err_self_alloc:
return NULL;
}
/* Destroy an instance of the Device Manager */
dmngr_err_e dmngr_destroy (dmngr_t **self_p)
{
assert (self_p);
if (*self_p) {
dmngr_t *self = *self_p;
/* Starting destructing by the last resource */
zlist_destroy (&self->ops->sig_ops);
free (self->ops);
free (self->endpoint);
free (self->name);
zsocket_destroy (self->ctx, self->dealer);
zctx_destroy (&self->ctx);
free (self);
*self_p = NULL;
}
return DMNGR_SUCCESS;
}
dmngr_err_e dmngr_set_sig_handler (dmngr_t *self, dmngr_sig_handler_t *sig_handler)
{
assert (self);
int err = zlist_append (self->ops->sig_ops, sig_handler);
return (err == -1) ? DMNGR_ERR_ALLOC : DMNGR_SUCCESS;
}
dmngr_err_e dmngr_register_sig_handlers (dmngr_t *self)
{
assert (self);
dmngr_sig_handler_t *sig_handler =
(dmngr_sig_handler_t *) zlist_first (self->ops->sig_ops);
/* Register all signal handlers in list*/
while (sig_handler) {
struct sigaction act;
memset (&act, 0, sizeof(act));
act.sa_sigaction = sig_handler->dmngr_sig_h;
act.sa_flags = SA_SIGINFO;
int err = sigaction (sig_handler->signal, &act, NULL);
CHECK_ERR(err, DMNGR_ERR_SIGACTION);
DBE_DEBUG (DBG_DEV_MNGR | DBG_LVL_INFO, "[dev_mngr_core] registered signal %d\n", sig_handler->signal);
sig_handler = (dmngr_sig_handler_t *)
zlist_next (self->ops->sig_ops);
}
return DMNGR_SUCCESS;
}
/* Declare wrapper for all DMNGR functions API */
#define DMNGR_FUNC_WRAPPER(func_name, ops_err, ...) \
{ \
assert (self); \
CHECK_ERR(((self->ops->func_name == NULL) ? -1 : 0),\
DMNGR_ERR_FUNC_NOT_IMPL); \
int err = self->ops->func_name (##__VA_ARGS__); \
CHECK_ERR (err, ops_err); \
return DMNGR_SUCCESS; \
}
dmngr_err_e dmngr_set_wait_clhd_handler (dmngr_t *self, wait_chld_handler_fp fp)
{
assert (self);
self->ops->dmngr_wait_chld = fp;
return DMNGR_SUCCESS;
}
dmngr_err_e dmngr_wait_chld (dmngr_t *self)
DMNGR_FUNC_WRAPPER(dmngr_wait_chld, DMNGR_ERR_WAITCHLD)
/*{
assert (self);
int err = self->ops->dmngr_wait_chld ();
CHECK_ERR (err, DMNGR_ERR_WAITCHLD);
return DMNGR_SUCCESS;
}*/
/* FIXME: Use the above wrapper!!!! */
dmngr_err_e dmngr_set_spawn_clhd_handler (dmngr_t *self, spawn_chld_handler_fp fp)
{
assert (self);
self->ops->dmngr_spawn_chld = fp;
return DMNGR_SUCCESS;
}
dmngr_err_e dmngr_spawn_chld (dmngr_t *self, const char *program, char *const argv[])
{
assert (self);
int err = self->ops->dmngr_spawn_chld (program, argv);
CHECK_ERR (err, DMNGR_ERR_SPAWNCHLD);
return DMNGR_SUCCESS;
}
/* Execute function to spawn a broker process */
dmngr_err_e dmngr_spawn_broker (dmngr_t *self, const char *program, char *const argv[])
{
assert (self);
if (self->broker_running) {
return DMNGR_ERR_BROK_RUNN;
}
int err = self->ops->dmngr_spawn_chld (program, argv);
CHECK_ERR (err, DMNGR_ERR_SPAWNCHLD);
return DMNGR_SUCCESS;
}
dmngr_err_e dmngr_set_ops (dmngr_t *self, dmngr_ops_t *dmngr_ops)
{
assert (self);
assert (dmngr_ops);
self->ops = dmngr_ops;
return DMNGR_SUCCESS;
}
bool dmngr_is_broker_running (dmngr_t *self)
{
assert (self);
return self->broker_running;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_mngr/dev_mngr_core.h 0000664 0000000 0000000 00000006522 12326537641 0025175 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _DEV_MNGR_CORE_H_
#define _DEV_MNGR_CORE_H_
#include "czmq.h"
#include "dev_mngr_err.h"
/* Signal handler function pointer */
typedef void (*sig_handler_fp)(int sig, siginfo_t *siginfo, void *context);
/* Wait child handler function pointer */
typedef int (*wait_chld_handler_fp)(void);
/* Spawn child handler function pointer */
typedef int (*spawn_chld_handler_fp)(const char *program, char *const argv[]);
/* Spawn broker handler function pointer */
typedef int (*spawn_broker_handler_fp)(const char *program, char *const argv[]);
/* Node of sig_ops list */
struct _dmngr_sig_handler_t {
int signal; /* Signal identifier, e.g., SIGINT, SIGKILL, etc... */
sig_handler_fp dmngr_sig_h;
};
struct _dmngr_ops_t {
wait_chld_handler_fp dmngr_wait_chld; /* Called to wait a all child process */
spawn_chld_handler_fp dmngr_spawn_chld; /* Called to spawn a new process to handle device */
spawn_broker_handler_fp dmngr_spawn_broker; /* Called to spawn (or respawn a zeroMQ broker */
/* List of dmngr_sig_handler_t */
zlist_t *sig_ops;
};
struct _dmngr_t {
/* General information */
zctx_t *ctx; /* zeroMQ context */
void *dealer; /* zeroMQ Dealer socket */
char *name; /* Identification of this dmngr instance */
char *endpoint; /* Endpoint to connect to */
int verbose; /* Print activity to stdout */
/* General management operations */
struct _dmngr_ops_t *ops;
/* zeroMQ broker management */
bool broker_running; /* true if broker is already running */
/* Device managment */
};
/* Opaque class signal handler structure */
typedef struct _dmngr_sig_handler_t dmngr_sig_handler_t;
/* Opaque operations handler structure */
typedef struct _dmngr_ops_t dmngr_ops_t;
/* Opaque class structure */
typedef struct _dmngr_t dmngr_t;
/***************** Our methods *****************/
/* Creates a new instance of the Device Manager */
dmngr_t * dmngr_new (char *name, char * endpoint, int verbose);
/* Destroy an instance of the Device Manager */
dmngr_err_e dmngr_destroy (dmngr_t **self_p);
/* Register signals to Device Manager instance */
dmngr_err_e dmngr_set_sig_handler (dmngr_t *self, dmngr_sig_handler_t *sig_handler);
/* Register all signal handlers previously set */
dmngr_err_e dmngr_register_sig_handlers (dmngr_t *self);
/* Register function to wait a all child process */
dmngr_err_e dmngr_set_wait_clhd_handler (dmngr_t *self, wait_chld_handler_fp fp);
/* Execute function to wait a all child process */
dmngr_err_e dmngr_wait_chld (dmngr_t *self);
/* Register function to spawn a all child process */
dmngr_err_e dmngr_set_spawn_clhd_handler (dmngr_t *self, spawn_chld_handler_fp fp);
/* Execute function to spawn a all child process */
dmngr_err_e dmngr_spawn_chld (dmngr_t *self, const char *program, char *const argv[]);
/* Execute function to spawn a broker process */
dmngr_err_e dmngr_spawn_broker (dmngr_t *self, const char *program, char *const argv[]);
/* Setting all operations at once */
dmngr_err_e dmngr_set_ops (dmngr_t *self, dmngr_ops_t *dmngr_ops);
/* Is broker Running? */
bool dmngr_is_broker_running (dmngr_t *self);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_mngr/dev_mngr_err.c 0000664 0000000 0000000 00000001742 12326537641 0025027 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#include "dev_mngr_err.h"
static const char *dmngr_err [DMNGR_ERR_END] =
{
[DMNGR_SUCCESS] = "Success",
[DMNGR_ERR_ALLOC] = "Could not allocate memory",
[DMNGR_ERR_FUNC_NOT_IMPL] = "Function not implemented",
[DMNGR_ERR_SIGACTION] = "Signal registration error",
[DMNGR_ERR_WAITCHLD] = "Could not complete wait child routine",
[DMNGR_ERR_SPAWNCHLD] = "Could not complete spawn child routine",
[DMNGR_ERR_BROK_RUNN] = "Broker already running"
};
/* Convert enumeration type to string */
const char * dmngr_err_str (dmngr_err_e err)
{
return dmngr_err [err];
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/dev_mngr/dev_mngr_err.h 0000664 0000000 0000000 00000002052 12326537641 0025027 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#ifndef _DEV_MNGR_CORE_ERR_H_
#define _DEV_MNGR_CORE_ERR_H_
enum _dmngr_err_e
{
DMNGR_SUCCESS = 0, /* No error */
DMNGR_ERR_ALLOC, /* Could not allocate memory */
DMNGR_ERR_FUNC_NOT_IMPL, /* Function not implemented */
DMNGR_ERR_SIGACTION, /* Could not register signal */
DMNGR_ERR_WAITCHLD, /* Wait child routine error */
DMNGR_ERR_SPAWNCHLD, /* Spawn child routine error */
DMNGR_ERR_BROK_RUNN, /* Broker already running error */
DMNGR_ERR_END /* End of enum marker */
};
typedef enum _dmngr_err_e dmngr_err_e;
/* Convert enumeration type to string */
const char * dmngr_err_str (dmngr_err_e err);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/hal.mk 0000664 0000000 0000000 00000002315 12326537641 0021503 0 ustar 00root root 0000000 0000000 # debug.mk must be declared before dev_mngr.mk, as they are variables
# exported by the former used by the latter
include hal/debug/debug.mk
include hal/hal_utils/hal_utils.mk
include hal/ll_io/ll_io.mk
include hal/sm_io/sm_io.mk
include hal/sdb/sdb.mk
include hal/dev_mngr/dev_mngr.mk
include hal/dev_io/dev_io.mk
include hal/msg/msg.mk
std_hal_INCLUDE_DIRS = hal/include
hal_OUT += $(dev_mngr_OUT) $(dev_io_OUT)
# For each target in hal_OUT we add the necessary objects
dev_mngr_OBJS = $(dev_mngr_core_OBJS) $(debug_OBJS)
dev_io_OBJS = $(dev_io_core_OBJS) $(ll_io_OBJS) $(sm_io_OBJS) \
$(msg_OBJS) $(debug_OBJS) $(hal_utils_OBJS)
# Merge all hal objects together
hal_OBJS = $(debug_OBJS) \
$(hal_utils_OBJS) \
$(ll_io_OBJS) \
$(sm_io_OBJS) \
$(msg_OBJS) \
$(dev_mngr_core_OBJS) \
$(dev_io_core_OBJS)
# Merge all include directories together
hal_all_INCLUDE_DIRS += $(std_hal_INCLUDE_DIRS) \
$(debug_INCLUDE_DIRS) \
$(hal_utils_INCLUDE_DIRS) \
$(sdb_INCLUDE_DIRS) \
$(ll_io_INCLUDE_DIRS) \
$(sm_io_INCLUDE_DIRS) \
$(msg_INCLUDE_DIRS) \
$(dev_mngr_INCLUDE_DIRS) \
$(dev_io_INCLUDE_DIRS)
# Change the include dirs into flags
hal_INCLUDE_DIRS = $(addprefix -I, $(hal_all_INCLUDE_DIRS))
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/hal_utils/ 0000775 0000000 0000000 00000000000 12326537641 0022371 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/hal_utils/dispatch_table.c 0000664 0000000 0000000 00000012343 12326537641 0025506 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include "hal_utils.h"
#include "dispatch_table.h"
#include "hal_assert.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, HAL_UTILS, "[halultis:disp_table]",\
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, HAL_UTILS, "[halutils:disp_table]",\
halutils_err_str(HALUTILS_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, HAL_UTILS, "[halutils:disp_table]", \
halutils_err_str (err_type))
static halutils_err_e _disp_table_insert (disp_table_t *self, const uint32_t key,
disp_table_func_fp func_fp);
static void _disp_table_free_item (void *data);
disp_table_t *disp_table_new (void)
{
disp_table_t *self = zmalloc (sizeof *self);
ASSERT_ALLOC (self, err_self_alloc);
self->table_h = zhash_new ();
ASSERT_ALLOC (self->table_h, err_table_h_alloc);
/* Only work for strings
zhash_autofree (self->table_h);*/
return self;
err_table_h_alloc:
free (self);
err_self_alloc:
return NULL;
}
halutils_err_e disp_table_destroy (disp_table_t **self_p)
{
assert (self_p);
if (*self_p) {
disp_table_t *self = *self_p;
zhash_destroy (&self->table_h);
free (self);
*self_p = NULL;
}
return HALUTILS_SUCCESS;
}
halutils_err_e disp_table_insert (disp_table_t *self, uint32_t key,
disp_table_func_fp func_fp)
{
return _disp_table_insert (self, key, func_fp);
}
halutils_err_e disp_table_remove (disp_table_t *self, uint32_t key)
{
char *key_c = halutils_stringify_key (key);
ASSERT_ALLOC (key_c, err_key_c_alloc);
DBE_DEBUG (DBG_HAL_UTILS | DBG_LVL_TRACE,
"[halutils:disp_table] Removing function (key = %u) into dispatch table\n",
key);
/* This will trigger the free fucntion previously registered */
zhash_delete (self->table_h, key_c);
free (key_c);
return HALUTILS_SUCCESS;
err_key_c_alloc:
return HALUTILS_ERR_ALLOC;
}
void *disp_table_call (disp_table_t *self, uint32_t key, void *owner, void *args)
{
char *key_c = halutils_stringify_key (key);
ASSERT_ALLOC (key_c, err_key_c_alloc);
func_fp_wrapper_t *func_fp_wrapper = zhash_lookup (self->table_h, key_c);
ASSERT_ALLOC (func_fp_wrapper, err_func_p_wrapper_null);
free (key_c);
/* DBE_DEBUG (DBG_HAL_UTILS | DBG_LVL_TRACE,
"[halutils:disp_table] Calling function (key = %u, addr = %p) from dispatch table\n",
key, func_fp_wrapper->func_fp); */
/* The function pointer is never NULL */
return func_fp_wrapper->func_fp (owner, args);
err_func_p_wrapper_null:
free (key_c);
err_key_c_alloc:
return NULL;
}
halutils_err_e disp_table_insert_all (disp_table_t *self, const disp_table_func_fp *disp_table_fp,
const uint32_t *code_table, uint32_t size)
{
assert (self);
assert (disp_table_fp);
assert (code_table);
unsigned int i;
halutils_err_e err = HALUTILS_SUCCESS;
for (i = 0; i < size; ++i) {
halutils_err_e err = _disp_table_insert (self, code_table [i],
*disp_table_fp [i]);
if (err != HALUTILS_SUCCESS) {
break;
}
}
return err;
}
halutils_err_e disp_table_remove_all (disp_table_t *self)
{
assert (self);
zlist_t *hash_keys = zhash_keys (self->table_h);
void * table_item = zlist_first (hash_keys);
for (; table_item; table_item = zlist_next (hash_keys)) {
zhash_delete (self->table_h, (char *) table_item);
}
zlist_destroy (&hash_keys);
return HALUTILS_SUCCESS;
}
/**** Local helper functions ****/
static halutils_err_e _disp_table_insert (disp_table_t *self, uint32_t key,
disp_table_func_fp func_fp)
{
if (func_fp == NULL) {
return HALUTILS_ERR_NULL_POINTER;
}
DBE_DEBUG (DBG_HAL_UTILS | DBG_LVL_TRACE,
"[halutils:disp_table] Registering function (%p) opcode (%u) into dispatch table\n",
func_fp, key);
func_fp_wrapper_t *func_fp_wrapper = zmalloc (sizeof *func_fp_wrapper);
ASSERT_ALLOC (func_fp_wrapper, err_func_wrapper_alloc);
/* Initialize func_p_wrapper struct */
func_fp_wrapper->func_fp = func_fp;
char *key_c = halutils_stringify_key (key);
ASSERT_ALLOC (key_c, err_key_c_alloc);
int zerr = zhash_insert (self->table_h, key_c, func_fp_wrapper);
ASSERT_TEST(zerr == 0, "Could not insert item into dispatch table", err_insert_hash);
/* Setup free function */
zhash_freefn (self->table_h, key_c, _disp_table_free_item);
free (key_c);
return HALUTILS_SUCCESS;
err_insert_hash:
free (key_c);
err_key_c_alloc:
free (func_fp_wrapper);
err_func_wrapper_alloc:
return HALUTILS_ERR_ALLOC;
}
static void _disp_table_free_item (void *data)
{
free ((func_fp_wrapper_t *)data);
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/hal_utils/dispatch_table.h 0000664 0000000 0000000 00000002575 12326537641 0025521 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _DISPATCH_TABLE_H_
#define _DISPATCH_TABLE_H_
#include
#include "hal_utils_err.h"
struct _disp_table_t {
/* Hash containg all the sm_io thsafe operations
* that we need to handle. It is composed
* of key (4-char ID) / value (pointer to funtion) */
zhash_t *table_h;
};
/* Opaque class structure */
typedef struct _disp_table_t disp_table_t;
/* Generic function pointer */
typedef void* (*disp_table_func_fp)(void *owner, void * args);
struct _func_fp_wrapper_t {
disp_table_func_fp func_fp;
};
/* Opaque class structure */
typedef struct _func_fp_wrapper_t func_fp_wrapper_t;
/***************** Our methods *****************/
disp_table_t *disp_table_new (void);
halutils_err_e disp_table_destroy (disp_table_t **self_p);
halutils_err_e disp_table_insert (disp_table_t *self, uint32_t key,
disp_table_func_fp func_fp);
halutils_err_e disp_table_insert_all (disp_table_t *self, const disp_table_func_fp *disp_table_fp,
const uint32_t *code_table, uint32_t size);
halutils_err_e disp_table_remove (disp_table_t *self, uint32_t key);
halutils_err_e disp_table_remove_all (disp_table_t *self);
void *disp_table_call (disp_table_t *self, uint32_t key, void *owner, void *args);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/hal_utils/hal_utils.c 0000664 0000000 0000000 00000003101 12326537641 0024514 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include "hal_utils.h"
#include "hal_utils_err.h"
#include "hal_assert.h"
#include "czmq.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, HAL_UTILS, "[halultis]",\
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, HAL_UTILS, "[halutils]",\
halutils_err_str(HALUTILS_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, HAL_UTILS, "[halutils]", \
halutils_err_str (err_type))
uint32_t hex_to_str_len (uint32_t key)
{
uint32_t i = 0;
do {
key >>= 4;
++i;
} while (key > 0);
return i;
}
char *halutils_stringify_key (uint32_t key)
{
uint32_t key_len = hex_to_str_len (key) + 1; /* +1 for \0 */
char *key_c = zmalloc (key_len * sizeof (char));
ASSERT_ALLOC (key_c, err_key_c_alloc);
snprintf(key_c, key_len, "%x", key);
/* DBE_DEBUG (DBG_HAL_UTILS | DBG_LVL_TRACE,
"[halutils:stringify_key] key = %s, key_len = %u\n",
key_c, key_len); */
return key_c;
err_key_c_alloc:
return NULL;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/hal_utils/hal_utils.h 0000664 0000000 0000000 00000000511 12326537641 0024523 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _HAL_UTILS_H_
#define _HAL_UTILS_H_
#include
uint32_t num_to_str_len (uint32_t key);
char *halutils_stringify_key (uint32_t key);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/hal_utils/hal_utils.mk 0000664 0000000 0000000 00000000310 12326537641 0024700 0 ustar 00root root 0000000 0000000 hal_utils_DIR = hal/hal_utils
hal_utils_OBJS = $(hal_utils_DIR)/hal_utils.o \
$(hal_utils_DIR)/hal_utils_err.o \
$(hal_utils_DIR)/dispatch_table.o \
hal_utils_INCLUDE_DIRS = $(hal_utils_DIR)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/hal_utils/hal_utils_err.c 0000664 0000000 0000000 00000001315 12326537641 0025371 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#include "hal_utils_err.h"
static const char *halutils_err [HALUTILS_ERR_END] =
{
[HALUTILS_SUCCESS] = "Success",
[HALUTILS_ERR_ALLOC] = "Could not allocate memory",
[HALUTILS_ERR_NULL_POINTER] = "Null pointer received"
};
/* Convert enumeration type to string */
const char * halutils_err_str (halutils_err_e err)
{
return halutils_err [err];
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/hal_utils/hal_utils_err.h 0000664 0000000 0000000 00000001376 12326537641 0025405 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#ifndef _HALUTILS_ERR_H_
#define _HALUTILS_ERR_H_
enum _halutils_err_e
{
HALUTILS_SUCCESS = 0, /* No error */
HALUTILS_ERR_ALLOC, /* Could not allocate memory */
HALUTILS_ERR_NULL_POINTER, /* Null pointer received */
HALUTILS_ERR_END
};
typedef enum _halutils_err_e halutils_err_e;
/* Convert enumeration type to string */
const char * halutils_err_str (halutils_err_e err);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/include/ 0000775 0000000 0000000 00000000000 12326537641 0022030 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/include/hal_assert.h 0000664 0000000 0000000 00000003165 12326537641 0024333 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _HAL_ASSERT_H_
#define _HAL_ASSERT_H_
#include "debug_print.h"
/* Generic macros for asserting in subsystems. The
* general use case for them is to wrapp these with
* meaningful strings for differentes subsystems */
#define ASSERT_HAL_TEST(test_boolean, debug_subsys, \
debug_name, err_str, err_goto_label) \
do { \
if(!(test_boolean)) { \
DBE_DEBUG (DBG_ ##debug_subsys | DBG_LVL_FATAL, \
"["debug_name"]" " %s\n", err_str); \
goto err_goto_label; \
} \
} while(0)
#define ASSERT_HAL_ALLOC(ptr, debug_subsys, debug_name, \
err_str, err_goto_label) \
ASSERT_HAL_TEST(ptr!=NULL, debug_subsys, debug_name, \
err_str, err_goto_label)
#define CHECK_HAL_ERR(err, debug_subsys, debug_name, \
err_str) \
do { \
if (err < 0) { \
DBE_DEBUG (DBG_ ##debug_subsys | DBG_LVL_ERR, \
"["debug_name"]" " %s\n", err_str); \
return err; \
} \
} while (0)
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/include/hal_opts.h 0000664 0000000 0000000 00000002101 12326537641 0024004 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
* Parts taken from lwIP debug system
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _HAL_OPTS_
#define _HAL_OPTS_
/*
* Define the debug level here.
* Available options are, in decreasing order of verbosity:
* DBG_LVL_TRACE = super verbose
* DBG_LVL_INFO
* DBG_LVL_WARN
* DBG_LVL_ERR
* DBG_LVL_FATAL = only the critical messages are shown
*/
#define DBG_MIN_LEVEL DBG_LVL_TRACE
/* Define which subsystem will be traced. The DBG_SUBSYS_ON
* macro must be OR'ed.
* Available options are:
* DBG_DEV_MNGR
* DBG_DEV_IO
* DBG_LL_IO
* DBG_SM_IO
* DBG_MSG
* DBG_HAL_UTILS
*/
#define DBG_SUBSYS_ON (\
DBG_DEV_MNGR | \
DBG_DEV_IO | \
DBG_LL_IO | \
DBG_SM_IO | \
DBG_HAL_UTILS)
/* DBG_MSG | \ */
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ 0000775 0000000 0000000 00000000000 12326537641 0021503 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/hw/ 0000775 0000000 0000000 00000000000 12326537641 0022121 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/hw/pcie_regs.h 0000664 0000000 0000000 00000014020 12326537641 0024227 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _PCIE_REGS_H_
#define _PCIE_REGS_H_
/* Some FPGA PCIe registers. These are inside bar0 */
#define PCIE_CFG_REG_SDRAM_PG 0x1C
#define PCIE_CFG_REG_GSR 0x20
#define PCIE_CFG_GSR_BIT_DDR_RDY (0x1 << 7)
#define PCIE_CFG_REG_WB_PG 0x24
/* Some FPGA PCIe constants */
/* SDRAM is accesses via 32-bit BAR (32-bit addressing) */
#define PCIE_SDRAM_PG_SHIFT 0 /* bits */
/* #define PCIE_SDRAM_PG_MAX 19 */ /* bits */
#define PCIE_SDRAM_PG_MAX 17 /* bits */
/* #define PCIE_SDRAM_PG_SIZE (1<<16)*/ /* in Words (32-bit) */
#define PCIE_SDRAM_PG_SIZE (1<> \
PCIE_ADDR_BAR_SHIFT)
/* For use by LL_IO */
/* We divide the PCIe Wishbone addresses as:
* bits 32 to 28: BAR address (0, 2 or 4)
* bits 27 to 0: Wishbone physical address (2^28-1 to 0)*/
#define BAR4_ADDR (BAR4NO << PCIE_ADDR_BAR_SHIFT)
#define BAR2_ADDR (BAR2NO << PCIE_ADDR_BAR_SHIFT)
#define BAR0_ADDR (BAR0NO << PCIE_ADDR_BAR_SHIFT)
/********** PCIe Address LSB (generic) part extractor **********/
#define PCIE_ADDR_GEN_SHIFT 0 /* bits */
#define PCIE_ADDR_GEN_MAX 28 /* bits */
#define PCIE_ADDR_GEN_MASK (((1 << PCIE_ADDR_GEN_MAX)-1) << \
PCIE_ADDR_GEN_SHIFT)
/* PCIe LSB (generic) part extractor */
#define PCIE_ADDR_GEN(addr) ((addr & PCIE_ADDR_GEN_MASK) >> \
PCIE_ADDR_GEN_SHIFT)
/* PCIe LSB (generic) part, for use by LL_IO */
#define PCIE_ADDR_WB(addr) ((addr & PCIE_ADDR_GEN_MASK) << \
PCIE_ADDR_GEN_SHIFT)
/********** PCIe SDRAM Address Page number and offset extractor **********/
#define PCIE_ADDR_SDRAM_PG_OFFS(addr) ((addr & PCIE_SDRAM_PG_MASK) >> \
PCIE_SDRAM_PG_SHIFT)
#define PCIE_ADDR_SDRAM_PG(addr) ((addr & ~PCIE_SDRAM_PG_MASK) >> \
PCIE_SDRAM_PG_MAX)
/********** PCIe WB Address Page number and offset extractor **********/
#define PCIE_ADDR_WB_PG_OFFS(addr) ((addr & PCIE_WB_PG_MASK) >> \
PCIE_WB_PG_SHIFT)
#define PCIE_ADDR_WB_PG(addr) ((addr & ~PCIE_WB_PG_MASK) >> \
PCIE_WB_PG_MAX)
/********** Read or write to BAR **********/
#define BAR32_RW(barp, addr, datap, rw) \
do { \
(rw) ? \
(*(datap) = *((barp) + (addr))) : \
(*((barp) + (addr)) = *(datap)); \
} while (0)
/* FIXME: Figure it out another convenient way of doing this without hiding code! */
/* Macros for ease the PCIe BAR pointer verbosity. */
#define BAR_ACCESS_GEN(bar_addr) (((llio_dev_pcie_t *)self->dev_handler)->bar_addr)
#define BAR0 BAR_ACCESS_GEN(bar0)
#define BAR2 BAR_ACCESS_GEN(bar2)
#define BAR4 BAR_ACCESS_GEN(bar4)
/* Setting WB and SDRAM pages */
#define SET_PG(which, num) \
do { \
BAR0[which >> WB_DWORD_ACC] = \
num; \
} while (0)
#define SET_SDRAM_PG(num) \
SET_PG(PCIE_CFG_REG_SDRAM_PG, num)
#define SET_WB_PG(num) \
SET_PG(PCIE_CFG_REG_WB_PG, num)
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ll_io.c 0000664 0000000 0000000 00000016216 12326537641 0022753 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include
#include
#include "ll_io.h"
#include "ll_io_pcie.h"
#include "ll_io_eth.h"
#include "hal_assert.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, LL_IO, "[ll_io]", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, LL_IO, "[ll_io]", \
llio_err_str(LLIO_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, LL_IO, "[ll_io]", \
llio_err_str (err_type))
/* Register Low-level operations to llio instance. Helpper function */
static llio_err_e _llio_register_ops (llio_type_e type, const llio_ops_t **llio_ops);
/* Creates a new instance of the Low-level I/O */
llio_t * llio_new (char *name, char *endpoint, llio_type_e type, int verbose)
{
assert (name);
assert (endpoint);
llio_t *self = (llio_t *) zmalloc (sizeof *self);
ASSERT_ALLOC(self, err_self_alloc);
/* Initialize Low-level IO type */
self->type = type;
self->dev_handler = NULL; /* This is set by the device functions */
self->name = strdup (name);
ASSERT_ALLOC(self->name, err_name_alloc);
self->verbose = verbose;
/* Initilialize llio_endpoint */
self->endpoint = llio_endpoint_new (endpoint);
ASSERT_ALLOC(self->endpoint, err_endpoint_alloc);
/* Initilialize llio_dev_info */
/* self->dev_info = llio_dev_info_new ();
ASSERT_ALLOC(self->dev_info, err_dev_info_alloc); Moved to dev_io */
/* Initilialize llio_ops */
/* self->ops = (llio_ops_t *) zmalloc (sizeof *self->ops); */
/* ASSERT_ALLOC(self->ops, err_ops_alloc); */
/* Nullify every ops field to indicate a non-implemented function */
/* *self->ops = (const llio_ops_t) {0}; */
/* Attach Low-level operation to instance of llio */
_llio_register_ops (type, &self->ops);
DBE_DEBUG (DBG_LL_IO | DBG_LVL_INFO, "[ll_io] Created instance of llio\n");
return self;
/*err_ops_alloc:
zlist_destroy(&self->dev_info->sdb); */
/* err_dev_info_alloc:
llio_endpoint_destroy (&self->endpoint); */
err_endpoint_alloc:
free (self->name);
err_name_alloc:
free (self);
err_self_alloc:
return NULL;
}
/* Destroy an instance of the Low-level I/O */
llio_err_e llio_destroy (llio_t **self_p)
{
assert (self_p);
if (*self_p) {
llio_t *self = *self_p;
/* Starting destructing by the last resource */
/* We must release the device structures by calling the
* registered function */
if (self->ops->release) {
/* TODO: remove self->endpoint parameter (unused!)*/
self->ops->release (self, self->endpoint);
}
/* llio_dev_info_destroy (&self->dev_info); Moved to dev_io */
llio_endpoint_destroy (&self->endpoint);
free (self->name);
free (self);
*self_p = NULL;
}
return LLIO_SUCCESS;
}
llio_err_e llio_set_endpoint (llio_t *self, const char *name)
{
return llio_endpoint_set (self->endpoint, name);
}
llio_err_e llio_get_endpoint (llio_t *self, char **name)
{
return llio_endpoint_get (self->endpoint, name);
}
/**************** Helper Functions ***************/
/* Register Low-level operations to llio instance. Helpper function */
static llio_err_e _llio_register_ops (llio_type_e type, const llio_ops_t **ops)
{
switch (type) {
case GENERIC_DEV:
*ops = NULL;
return LLIO_ERR_INV_FUNC_PARAM;
case PCIE_DEV:
*ops = &llio_ops_pcie;
break;
case ETH_DEV:
*ops = NULL;
return LLIO_ERR_INV_FUNC_PARAM;
default:
*ops = NULL;
return LLIO_ERR_INV_FUNC_PARAM;
}
DBE_DEBUG (DBG_LL_IO | DBG_LVL_INFO, "[ll_io] Ops set\n");
return LLIO_SUCCESS;
}
/********* Low-level generic methods API *********/
#define CHECK_FUNC(func_p) \
do { \
if(func_p == NULL) { \
DBE_DEBUG (DBG_LL_IO | DBG_LVL_ERR, \
"[ll_io] %s\n", \
llio_err_str (LLIO_ERR_FUNC_NOT_IMPL)); \
return -LLIO_ERR_FUNC_NOT_IMPL; \
} \
} while(0)
/* Declare wrapper for all LLIO functions API */
#define LLIO_FUNC_WRAPPER(func_name, ...) \
{ \
assert (self); \
assert (self->ops); \
CHECK_FUNC (self->ops->func_name); \
return self->ops->func_name (self, ##__VA_ARGS__); \
}
/**** Open device ****/
int llio_open (llio_t *self, llio_endpoint_t *endpoint)
LLIO_FUNC_WRAPPER (open, endpoint)
/**** Release device ****/
int llio_release (llio_t *self, llio_endpoint_t *endpoint)
LLIO_FUNC_WRAPPER (release, endpoint)
/**** Read data from device ****/
ssize_t llio_read_16 (llio_t *self, loff_t offs, uint16_t *data)
LLIO_FUNC_WRAPPER (read_16, offs, data)
ssize_t llio_read_32 (llio_t *self, loff_t offs, uint32_t *data)
LLIO_FUNC_WRAPPER (read_32, offs, data)
ssize_t llio_read_64 (llio_t *self, loff_t offs, uint64_t *data)
LLIO_FUNC_WRAPPER (read_64, offs, data)
/**** Write data to device ****/
ssize_t llio_write_16 (llio_t *self, loff_t offs, const uint16_t *data)
LLIO_FUNC_WRAPPER (write_16, offs, data)
ssize_t llio_write_32 (llio_t *self, loff_t offs, const uint32_t *data)
LLIO_FUNC_WRAPPER (write_32, offs, data)
ssize_t llio_write_64 (llio_t *self, loff_t offs, const uint64_t *data)
LLIO_FUNC_WRAPPER (write_64, offs, data)
/**** Read data block from device function pointer, size in bytes ****/
ssize_t llio_read_block (llio_t *self, loff_t offs, size_t size, uint32_t *data)
LLIO_FUNC_WRAPPER (read_block, offs, size, data)
/**** Write data block from device function pointer, size in bytes ****/
ssize_t llio_write_block (llio_t *self, loff_t offs, size_t size, const uint32_t *data)
LLIO_FUNC_WRAPPER (write_block, offs, size, data)
/**** Read data block via DMA from device, size in bytes ****/
ssize_t llio_read_dma (llio_t *self, loff_t offs, size_t size, uint32_t *data)
LLIO_FUNC_WRAPPER (read_dma, offs, size, data)
/**** Write data block via DMA from device, size in bytes ****/
ssize_t llio_write_dma (llio_t *self, loff_t offs, size_t size, const uint32_t *data)
LLIO_FUNC_WRAPPER (write_dma, offs, size, data)
/**** Read device information function pointer ****/
/* int llio_read_info (llio_t *self, llio_dev_info_t *dev_info)
LLIO_FUNC_WRAPPER (read_info, dev_info) Moved to dev_io */
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ll_io.h 0000664 0000000 0000000 00000014272 12326537641 0022760 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _LL_IO_H_
#define _LL_IO_H_
#include
#include
#include
#include "czmq.h"
#include "ll_io_endpoint.h"
#include "ll_io_dev_info.h"
#include "ll_io_err.h"
/* Device type */
enum _llio_type_e {
GENERIC_DEV = 0,
PCIE_DEV = 1,
ETH_DEV,
INVALID_DEV
};
struct _llio_ops_t;
/* Main class object */
struct _llio_t {
enum _llio_type_e type; /* Device type (PCIe, Ethnernet, or other) */
void *dev_handler; /* Generic pointer to a device handler. This
must be cast to a specific type by the
devices functions */
char *name; /* Identification of this llio instance */
int verbose; /* Print activity to stdout */
/* Endpoint to connect to */
struct _llio_endpoint_t *endpoint;
/* SDB device info */
/* struct _llio_dev_info_t *dev_info; Moved to dev_io */
/* Device operations */
const struct _llio_ops_t *ops;
};
/* Open device function pointer */
typedef int (*open_fp)(struct _llio_t *self, struct _llio_endpoint_t *endpoint);
/* Release device function pointer */
typedef int (*release_fp)(struct _llio_t *self, struct _llio_endpoint_t *endpoint);
/* Read data from device function pointers */
typedef ssize_t (*read_16_fp)(struct _llio_t *self, loff_t offs, uint16_t *data);
typedef ssize_t (*read_32_fp)(struct _llio_t *self, loff_t offs, uint32_t *data);
typedef ssize_t (*read_64_fp)(struct _llio_t *self, loff_t offs, uint64_t *data);
/* Write data to device function pointers */
typedef ssize_t (*write_16_fp)(struct _llio_t *self, loff_t offs, const uint16_t *data);
typedef ssize_t (*write_32_fp)(struct _llio_t *self, loff_t offs, const uint32_t *data);
typedef ssize_t (*write_64_fp)(struct _llio_t *self, loff_t offs, const uint64_t *data);
/* Read data block from device function pointer, size in bytes */
typedef ssize_t (*read_block_fp)(struct _llio_t *self, loff_t offs, size_t size, uint32_t *data);
/* Write data block from device function pointer, size in bytes */
typedef ssize_t (*write_block_fp)(struct _llio_t *self, loff_t offs, size_t size, const uint32_t *data);
/* Read data block via DMA from device function pointer, size in bytes */
typedef ssize_t (*read_dma_fp)(struct _llio_t *self, loff_t offs, size_t size, uint32_t *data);
/* Write data block via DMA from device function pointer, size in bytes */
typedef ssize_t (*write_dma_fp)(struct _llio_t *self, loff_t offs, size_t size, const uint32_t *data);
/* Read device information function pointer */
/* typedef int (*read_info_fp)(struct _llio_t *self, struct _llio_dev_info_t *dev_info); moved to dev_io */
struct _llio_ops_t {
open_fp open; /* Open device */
release_fp release; /* Release device */
read_16_fp read_16; /* Read 16-bit data */
read_32_fp read_32; /* Read 32-bit data */
read_64_fp read_64; /* Read 64-bit data */
write_16_fp write_16; /* Write 16-bit data */
write_32_fp write_32; /* Write 32-bit data */
write_64_fp write_64; /* Write 64-bit data */
read_block_fp read_block; /* Read arbitrary block size data,
parameter size in bytes */
write_block_fp write_block; /* Write arbitrary block size data,
parameter size in bytes */
read_dma_fp read_dma; /* Read arbitrary block size data via DMA,
parameter size in bytes */
write_dma_fp write_dma; /* Write arbitrary block size data via DMA,
parameter size in bytes */
/*read_info_fp read_info; Moved to dev_io */ /* Read device information data */
};
/* Opaque llio_type_e enum */
typedef enum _llio_type_e llio_type_e;
/* Opaque class structure */
typedef struct _llio_t llio_t;
/* Opaque llio_ops structure */
typedef struct _llio_ops_t llio_ops_t;
/***************** Our methods *****************/
/* Creates a new instance of the Low-level I/O */
llio_t * llio_new (char *name, char *endpoint, llio_type_e type, int verbose);
/* Destroy an instance of the Low-level I/O */
llio_err_e llio_destroy (llio_t **self_p);
/* Sets an endpoint in case it was not done in llio_new() */
llio_err_e llio_set_endpoint (llio_t *self, const char *name);
/* Gets endpoint from name from instance of llio_endpoint */
llio_err_e llio_get_endpoint (llio_t *self, char **name);
/* Register Low-level operations to llio instance. This probably is not suitable
* to be part of the API */
/* llio_err_e llio_register_ops (llio_t *self, llio_ops_t *llio_ops); */
/********* Low-level generic methods API *********/
/* Open device */
int llio_open (llio_t *self, llio_endpoint_t *endpoint);
/* Release device */
int llio_release (llio_t *self, llio_endpoint_t *endpoint);
/* Read data from device */
ssize_t llio_read_16 (llio_t *self, loff_t offs, uint16_t *data);
ssize_t llio_read_32 (llio_t *self, loff_t offs, uint32_t *data);
ssize_t llio_read_64 (llio_t *self, loff_t offs, uint64_t *data);
/* Write data to device */
ssize_t llio_write_16 (llio_t *self, loff_t offs, const uint16_t *data);
ssize_t llio_write_32 (llio_t *self, loff_t offs, const uint32_t *data);
ssize_t llio_write_64 (llio_t *self, loff_t offs, const uint64_t *data);
/* Read data block from device, size in bytes */
ssize_t llio_read_block (llio_t *self, loff_t offs, size_t size, uint32_t *data);
/* Write data block from device, size in bytes */
ssize_t llio_write_block (llio_t *self, loff_t offs, size_t size, const uint32_t *data);
/* Read data block via DMA from device, size in bytes */
ssize_t llio_read_dma (llio_t *self, loff_t offs, size_t size, uint32_t *data);
/* Write data block via DMA from device, size in bytes */
ssize_t llio_write_dma (llio_t *self, loff_t offs, size_t size, const uint32_t *data);
/* Read device information */
/* int llio_read_info (llio_t *self, llio_dev_info_t *dev_info); Moved to dev_io */
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ll_io.mk 0000664 0000000 0000000 00000000620 12326537641 0023130 0 ustar 00root root 0000000 0000000 include hal/ll_io/ops/ops.mk
ll_io_DIR = hal/ll_io
# Here we call _core_OBJS as we need to add
# more objects to this target. This is done in the hal.mk
# makefile
ll_io_OBJS = $(ll_io_DIR)/ll_io.o \
$(ll_io_DIR)/ll_io_endpoint.o \
$(ll_io_DIR)/ll_io_dev_info.o \
$(ll_io_DIR)/ll_io_err.o \
$(ll_io_ops_OBJS)
ll_io_INCLUDE_DIRS = $(ll_io_DIR) $(ll_io_ops_DIR)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ll_io_dev_info.c 0000664 0000000 0000000 00000003621 12326537641 0024620 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include
#include "ll_io_dev_info.h"
#include "hal_assert.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, LL_IO, "ll_io_dev_info", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, LL_IO, "ll_io_dev_info", \
llio_err_str(LLIO_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, LL_IO, "ll_io_dev_info", \
llio_err_str (err_type))
/* Creates a new instance of Device Information */
llio_dev_info_t * llio_dev_info_new ()
{
llio_dev_info_t *self = (llio_dev_info_t *) zmalloc (sizeof *self);
ASSERT_ALLOC(self, err_self_alloc);
/* Initilialize llio_dev_info */
/* Put some default values as these are going to be filled
later by read_dev_info() */
self->sdb_addr = 0x0;
self->parsed = false;
self->sdb = zlist_new (); /* HASH!? */
ASSERT_ALLOC(self->sdb, err_sdb_alloc);
return self;
err_sdb_alloc:
free (self);
err_self_alloc:
return NULL;
}
/* Destroy an instance of the Device Information */
llio_err_e llio_dev_info_destroy (llio_dev_info_t **self_p)
{
assert (self_p);
if (*self_p) {
llio_dev_info_t *self = *self_p;
/* Starting destructing by the last resource */
zlist_destroy (&self->sdb);
free (self);
*self_p = NULL;
}
return LLIO_SUCCESS;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ll_io_dev_info.h 0000664 0000000 0000000 00000002031 12326537641 0024617 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _LL_IO_DEV_INFO_H_
#define _LL_IO_DEV_INFO_H_
#include
#include
#include
#include "czmq.h"
#include "ll_io_dev_info.h"
#include "ll_io_err.h"
/* This hold the SDB structures of the device */
struct _llio_dev_info_t {
loff_t sdb_addr; /* Location of the SDB structures in device */
bool parsed; /* True if device was already parsed */
zlist_t *sdb; /* List holding the SDB structures of the device */
};
/* Opaque llio_dev_info structure */
typedef struct _llio_dev_info_t llio_dev_info_t;
/***************** Our methods *****************/
/* Creates a new instance of Device Information */
llio_dev_info_t * llio_dev_info_new ();
/* Destroy an instance of the Device Information */
llio_err_e llio_dev_info_destroy (llio_dev_info_t **self_p);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ll_io_endpoint.c 0000664 0000000 0000000 00000006276 12326537641 0024660 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include
#include
#include "ll_io_endpoint.h"
#include "hal_assert.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, LL_IO, "ll_io_endpoint", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, LL_IO, "ll_io_endpoint", \
llio_err_str(LLIO_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, LL_IO, "ll_io_endpoint", \
llio_err_str (err_type))
static llio_err_e _llio_endpoint_set (llio_endpoint_t *self, const char *name);
static llio_err_e _llio_endpoint_get (llio_endpoint_t *self, char **endpoint);
/* Creates a new instance of the Endpoint*/
llio_endpoint_t * llio_endpoint_new (const char *endpoint)
{
llio_endpoint_t *self = (llio_endpoint_t *) zmalloc (sizeof *self);
ASSERT_ALLOC(self, err_self_alloc);
/* Initilialize llio_endpoint */
self->opened = false;
llio_err_e err = _llio_endpoint_set (self, endpoint);
ASSERT_TEST(err==LLIO_SUCCESS, llio_err_str(err), err_name_alloc);
return self;
err_name_alloc:
free (self);
err_self_alloc:
return NULL;
}
/* Destroy an instance of the Endpoint */
llio_err_e llio_endpoint_destroy (llio_endpoint_t **self_p)
{
assert (self_p);
if (*self_p) {
llio_endpoint_t *self = *self_p;
/* Starting destructing by the last resource */
free (self->name);
free (self);
*self_p = NULL;
}
return LLIO_SUCCESS;
}
/* Register endpoint to llio instance */
llio_err_e llio_endpoint_set (llio_endpoint_t *self, const char *name)
{
assert (self);
return _llio_endpoint_set (self, name);
}
/* Get endpoint from name from instance of llio_endpoint */
llio_err_e llio_endpoint_get (llio_endpoint_t *self, char **endpoint)
{
assert (self);
return _llio_endpoint_get (self, endpoint);
}
/**************** Helper Functions ***************/
static llio_err_e _llio_endpoint_set (llio_endpoint_t *self, const char *name)
{
if (self->opened) {
return LLIO_ERR_SET_ENDP;
}
if (name) {
if (self->name) {
free (self->name);
}
self->name = strdup (name);
ASSERT_ALLOC(self->name, err_name_alloc);
}
return LLIO_SUCCESS;
/* FIXME Remove goto label as it doesn't enhance anything,
* as we have only one pssible chance of error */
err_name_alloc:
return LLIO_ERR_ALLOC;
}
/* Get endpoint from name from instance of llio_endpoint */
static llio_err_e _llio_endpoint_get (llio_endpoint_t *self, char **endpoint)
{
*endpoint = strdup (self->name);
ASSERT_ALLOC(*endpoint, err_alloc);
return LLIO_SUCCESS;
err_alloc:
return LLIO_ERR_ALLOC;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ll_io_endpoint.h 0000664 0000000 0000000 00000002335 12326537641 0024655 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _LL_IO_ENDPOINT_H_
#define _LL_IO_ENDPOINT_H_
#include
#include
#include "czmq.h"
#include "ll_io_err.h"
/* Device endpoint */
struct _llio_endpoint_t {
bool opened; /* True if device if already opened */
char *name; /* Name of the endpoint, e.g., "/dev/fpga0"
and "tcp://192.168.0.100:5556" */
};
/* Opaque llio_endpoint structure */
typedef struct _llio_endpoint_t llio_endpoint_t;
/***************** Our methods *****************/
/* Creates a new instance of the Endpoint*/
llio_endpoint_t * llio_endpoint_new (const char *endpoint);
/* Destroy an instance of the Endpoint */
llio_err_e llio_endpoint_destroy (llio_endpoint_t **self_p);
/* Set endpoint to llio instance in case it was not done in llio_endpoint_new() */
llio_err_e llio_endpoint_set (llio_endpoint_t *self, const char *endpoint);
/* Get endpoint from name from instance of llio_endpoint */
llio_err_e llio_endpoint_get (llio_endpoint_t *self, char **endpoint);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ll_io_err.c 0000664 0000000 0000000 00000001604 12326537641 0023616 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#include "ll_io_err.h"
static const char *llio_err [LLIO_ERR_END] =
{
[LLIO_SUCCESS] = "Success",
[LLIO_ERR_ALLOC] = "Could not allocate memory",
[LLIO_ERR_FUNC_NOT_IMPL] = "Function not implemented",
[LLIO_ERR_INV_FUNC_PARAM] = "Invalid function parameter",
[LLIO_ERR_SET_ENDP] = "Could not change enpoint (device opened)",
[LLIO_ERR_DEV_CLOSE] = "Could not close device appropriately"
};
/* Convert enumeration type to string */
const char * llio_err_str (llio_err_e err)
{
return llio_err [err];
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ll_io_err.h 0000664 0000000 0000000 00000001737 12326537641 0023632 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#ifndef _LLIO_ERR_H_
#define _LLIO_ERR_H_
enum _llio_err_e
{
LLIO_SUCCESS = 0, /* No error */
LLIO_ERR_ALLOC, /* Could not allocate memory */
LLIO_ERR_FUNC_NOT_IMPL, /* Function not implemented */
LLIO_ERR_INV_FUNC_PARAM, /* Invalid function parameter */
LLIO_ERR_SET_ENDP, /* Could not set endpoint (device already opened)*/
LLIO_ERR_DEV_CLOSE, /* Error closing a device */
LLIO_ERR_END /* End of enum marker */
};
typedef enum _llio_err_e llio_err_e;
/* Convert enumeration type to string */
const char * llio_err_str (llio_err_e err);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ops/ 0000775 0000000 0000000 00000000000 12326537641 0022304 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ops/ll_io_eth.c 0000664 0000000 0000000 00000000277 12326537641 0024414 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include "ll_io_eth.h"
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ops/ll_io_eth.h 0000664 0000000 0000000 00000000427 12326537641 0024416 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _LL_IO_ETH_H_
#define _LL_IO_ETH_H_
#include "ll_io.h"
extern const llio_ops_t llio_ops_eth;
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ops/ll_io_pcie.c 0000664 0000000 0000000 00000024116 12326537641 0024552 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include "ll_io_pcie.h"
#include "hal_assert.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, LL_IO, "[ll_io:pcie]", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, LL_IO, "[ll_io:pcie]", \
llio_err_str(LLIO_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, LL_IO, "[ll_io:pcie]", \
llio_err_str (err_type))
#define READ_FROM_BAR 1
#define WRITE_TO_BAR 0
static ssize_t _pcie_rw_32 (llio_t *self, loff_t offs, uint32_t *data, int rw);
/************ Our methods implementation **********/
/* Creates a new instance of the dev_pcie */
llio_dev_pcie_t * llio_dev_pcie_new (char *dev_entry)
{
llio_dev_pcie_t *self = (llio_dev_pcie_t *) zmalloc (sizeof *self);
ASSERT_ALLOC (self, err_llio_dev_pcie_alloc);
self->dev = (pd_device_t *) zmalloc (sizeof *self->dev);
ASSERT_ALLOC (self->dev, err_dev_pcie_alloc);
/* FIXME: hardcoded dev number */
/* TODO: should we use llio_endpoint_get to get the endpoint name? */
int err = pd_open (0, self->dev, dev_entry);
if (err != 0) {
perror ("pd_open");
}
ASSERT_TEST(err==0, "Error opening device", err_dev_pcie_open);
/* Map all available BARs */
self->bar0 = (uint32_t *) pd_mapBAR (self->dev, BAR0NO);
ASSERT_TEST(self->bar0!=NULL, "Could not allocate bar0", err_bar0_alloc);
self->bar2 = (uint32_t *) pd_mapBAR (self->dev, BAR2NO);
ASSERT_TEST(self->bar2!=NULL, "Could not allocate bar2", err_bar2_alloc);
self->bar4 = (uint64_t *) pd_mapBAR (self->dev, BAR4NO);
ASSERT_TEST(self->bar4!=NULL, "Could not allocate bar4", err_bar4_alloc);
DBE_DEBUG (DBG_LL_IO | DBG_LVL_TRACE, "[ll_io_pcie] Created instance of llio_dev_pcie\n");
return self;
err_bar4_alloc:
pd_unmapBAR (self->dev, BAR2NO, self->bar2);
err_bar2_alloc:
pd_unmapBAR (self->dev, BAR0NO, self->bar0);
err_bar0_alloc:
pd_close (self->dev);
err_dev_pcie_open:
free (self->dev);
err_dev_pcie_alloc:
free (self);
err_llio_dev_pcie_alloc:
return NULL;
}
/* Destroy an instance of the Endpoint */
llio_err_e llio_dev_pcie_destroy (llio_dev_pcie_t **self_p)
{
if (*self_p) {
llio_dev_pcie_t *self = *self_p;
/* Unmap all bars first and then destroy the remaining structures */
pd_unmapBAR (self->dev, BAR4NO, self->bar4);
pd_unmapBAR (self->dev, BAR2NO, self->bar2);
pd_unmapBAR (self->dev, BAR0NO, self->bar0);
pd_close (self->dev);
free (self->dev);
free (self);
self_p = NULL;
}
return LLIO_SUCCESS;
}
/************ llio_ops_pcie Implementation **********/
/* Open PCIe device */
int pcie_open (llio_t *self, llio_endpoint_t *endpoint)
{
(void) endpoint;
if (self->endpoint->opened) {
return 0;
}
/* Create new private PCIe handler */
self->dev_handler = llio_dev_pcie_new (self->endpoint->name);
ASSERT_TEST(self->dev_handler!=NULL, "Could not allocate dev_handler", err_dev_handler_alloc);
/* Initialize Wishbone and SDRAM pages to 0 */
SET_SDRAM_PG(0);
SET_WB_PG(0);
/* Signal that the endpoint is opened and ready to work */
self->endpoint->opened = true;
DBE_DEBUG (DBG_LL_IO | DBG_LVL_INFO,
"[ll_io_pcie] Opened PCIe device located at %s\n",
self->endpoint->name);
return 0;
err_dev_handler_alloc:
return -1;
}
/* Release PCIe device */
int pcie_release (llio_t *self, llio_endpoint_t *endpoint)
{
(void) endpoint;
/* Nothing to close */
if (!self->endpoint->opened) {
return 0;
}
/* Deattach specific device handler to generic one */
llio_err_e err = llio_dev_pcie_destroy ((llio_dev_pcie_t **) &self->dev_handler);
ASSERT_TEST (err==LLIO_SUCCESS, "Could not close device appropriately", err_dealloc);
self->dev_handler = NULL;
/* TODO: should we use llio_endpoint_set_opened() to close the endpoint? */
self->endpoint->opened = false;
DBE_DEBUG (DBG_LL_IO | DBG_LVL_INFO,
"[ll_io_pcie] Closed PCIe device located at %s\n", self->endpoint->name);
return 0;
err_dealloc:
return -1;
}
/* NOTE: For the PCIe device, we only have up to 28 address bits, as
* the 4 MSB are reserved for selecting the BAR to operate on */
/* Read data from PCIe device */
ssize_t pcie_read_32 (llio_t *self, loff_t offs, uint32_t *data)
{
return _pcie_rw_32 (self, offs, data, READ_FROM_BAR);
}
ssize_t pcie_read_64 (llio_t *self, loff_t offs, uint64_t *data)
{
return _pcie_rw_32 (self, offs,
(uint32_t *) data, READ_FROM_BAR)
+
_pcie_rw_32 (self, offs,
(uint32_t *)((uint8_t *) data + sizeof (uint32_t)), READ_FROM_BAR);
}
/* Write data to PCIe device */
ssize_t pcie_write_32 (llio_t *self, loff_t offs, const uint32_t *data)
{
uint32_t _data = *data;
return _pcie_rw_32 (self, offs, &_data, WRITE_TO_BAR);
}
ssize_t pcie_write_64 (llio_t *self, loff_t offs, const uint64_t *data)
{
uint64_t _data = *data;
return _pcie_rw_32 (self, offs,
(uint32_t *) &_data, WRITE_TO_BAR)
+
_pcie_rw_32 (self, offs,
(uint32_t *)((uint8_t *) &_data + sizeof (uint32_t)), WRITE_TO_BAR);
}
/* Read data block from PCIe device, size in bytes */
ssize_t pcie_read_block (llio_t *self, loff_t offs, size_t size, uint32_t *data)
{
(void) self;
(void) offs;
(void) size;
(void) data;
return -1;
}
/* Write data block from PCIe device, size in bytes */
ssize_t pcie_write_block (llio_t *self, loff_t offs, size_t size, const uint32_t *data)
{
(void) self;
(void) offs;
(void) size;
(void) data;
return -1;
}
/* Read data block from PCIe device, size in bytes */
ssize_t pcie_read_dma (llio_t *self, loff_t offs, size_t size, uint32_t *data)
{
(void) self;
(void) offs;
(void) size;
(void) data;
return -1;
}
/* Write data block from PCIe device, size in bytes */
ssize_t pcie_write_dma (llio_t *self, loff_t offs, size_t size, const uint32_t *data)
{
(void) self;
(void) offs;
(void) size;
(void) data;
return -1;
}
/* Read PCIe device information */
/*int pcie_read_info (llio_t *self, llio_dev_info_t *dev_info)
{
(void) self;
(void) dev_info;
return -1;
}
*/
/************ Helper functions **********/
static ssize_t _pcie_rw_32 (llio_t *self, loff_t offs, uint32_t *data, int rw)
{
if (!self->endpoint->opened) {
return -1;
}
/* Determine which bar to operate on */
int bar_no = PCIE_ADDR_BAR (offs);
loff_t full_offs = PCIE_ADDR_GEN (offs);
int pg_num;
loff_t pg_offs;
/* FIXME: This switch is in the critical path! Remove it */
switch (bar_no) {
/* PCIe config registers */
case BAR0NO:
DBE_DEBUG (DBG_LL_IO | DBG_LVL_TRACE,
"[ll_io_pcie:_pcie_rw_32] Going to read/write in BAR0\n");
DBE_DEBUG (DBG_LL_IO | DBG_LVL_TRACE,
"[ll_io_pcie:_pcie_rw_32] bar_no = %d, full_offs = %lX\n",
bar_no, full_offs);
BAR32_RW(BAR0, full_offs, data, rw);
break;
/* FPGA SDRAM */
case BAR2NO:
DBE_DEBUG (DBG_LL_IO | DBG_LVL_TRACE,
"[ll_io_pcie:_pcie_rw_32] Going to read/write in BAR2\n");
pg_num = PCIE_ADDR_SDRAM_PG (full_offs);
pg_offs = PCIE_ADDR_SDRAM_PG_OFFS (full_offs);
SET_SDRAM_PG (pg_num);
DBE_DEBUG (DBG_LL_IO | DBG_LVL_TRACE,
"[ll_io_pcie:_pcie_rw_32] bar_no = %d, pg_num = %d,\n\tfull_offs = %lX, pg_offs = %lX\n",
bar_no, pg_num, full_offs, pg_offs);
BAR32_RW(BAR2, pg_offs, data, rw);
break;
/* FPGA Wishbone */
case BAR4NO:
DBE_DEBUG (DBG_LL_IO | DBG_LVL_TRACE,
"[ll_io_pcie:_pcie_rw_32] Going to read/write in BAR4\n");
pg_num = PCIE_ADDR_WB_PG (full_offs);
pg_offs = PCIE_ADDR_WB_PG_OFFS (full_offs);
SET_WB_PG (pg_num);
DBE_DEBUG (DBG_LL_IO | DBG_LVL_TRACE,
"[ll_io_pcie:_pcie_rw_32] bar_no = %d, pg_num = %d,\n\tfull_offs = %lX, pg_offs = %lX\n",
bar_no, pg_num, full_offs, pg_offs);
BAR32_RW(BAR4, pg_offs, data, rw);
break;
/* Invalid BAR */
default:
return -1;
}
return sizeof (*data);
}
const llio_ops_t llio_ops_pcie = {
.open = pcie_open, /* Open device */
.release = pcie_release, /* Release device */
.read_16 = NULL, /* Read 16-bit data */
.read_32 = pcie_read_32, /* Read 32-bit data */
.read_64 = pcie_read_64, /* Read 64-bit data */
.write_16 = NULL, /* Write 16-bit data */
.write_32 = pcie_write_32, /* Write 32-bit data */
.write_64 = pcie_write_64, /* Write 64-bit data */
.read_block = pcie_read_block, /* Read arbitrary block size data,
parameter size in bytes */
.write_block = pcie_write_block, /* Write arbitrary block size data,
parameter size in bytes */
.read_dma = pcie_read_dma, /* Read arbitrary block size data via DMA,
parameter size in bytes */
.write_dma = pcie_write_dma /* Write arbitrary block size data via DMA,
parameter size in bytes */
/*.read_info = pcie_read_info */ /* Read device information data */
};
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ops/ll_io_pcie.h 0000664 0000000 0000000 00000002226 12326537641 0024555 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _LL_IO_PCIE_H_
#define _LL_IO_PCIE_H_
#include "ll_io.h"
#include "hw/pcie_regs.h"
#include "lib/pciDriver.h"
/* Default value for Wishbone access granularity */
/* For our FPGA firmware, Wishbone is accesses via a 64-bit BAR */
#ifndef WB_ACC
#define WB_ACC WB_QWORD_ACC
#endif
/* For use by llio_t general structure */
extern const llio_ops_t llio_ops_pcie;
/* Device endpoint */
struct _llio_dev_pcie_t {
pd_device_t *dev; /* PCIe device handler */
uint32_t *bar0; /* PCIe BAR0 */
uint32_t *bar2; /* PCIe BAR2 */
uint64_t *bar4; /* PCIe BAR4 */
};
/* Opaque llio_dev_pcie structure */
typedef struct _llio_dev_pcie_t llio_dev_pcie_t;
/***************** Our methods *****************/
/* Creates a new instance of the Endpoint*/
llio_dev_pcie_t * llio_dev_pcie_new (char *dev_entry);
/* Destroy an instance of the Endpoint */
llio_err_e llio_dev_pcie_destroy (llio_dev_pcie_t **self_p);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/ll_io/ops/ops.mk 0000664 0000000 0000000 00000000233 12326537641 0023434 0 ustar 00root root 0000000 0000000 ll_io_ops_DIR = hal/ll_io/ops
ll_io_ops_OBJS = $(ll_io_ops_DIR)/ll_io_pcie.o \
$(ll_io_ops_DIR)/ll_io_eth.o
ll_io_ops_INCLUDE_DIRS = $(ll_io_ops_DIR)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/ 0000775 0000000 0000000 00000000000 12326537641 0021173 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/exp_ops/ 0000775 0000000 0000000 00000000000 12326537641 0022650 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/exp_ops/exp_msg_zmq.c 0000664 0000000 0000000 00000001677 12326537641 0025360 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include "exp_msg_zmq.h"
#include "hal_assert.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, MSG, "[exp_msg:zmq]", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, MSG, "[exp_msg:zmq]", \
msg_err_str(MSG_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, MSG, "[exp_msg:zmq]", \
msg_err_str (err_type))
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/exp_ops/exp_msg_zmq.h 0000664 0000000 0000000 00000000547 12326537641 0025360 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _EXP_MSG_ZMQ_H_
#define _EXP_MSG_ZMQ_H_
#include
struct _exp_msg_zmq_t {
zmsg_t **msg;
zframe_t *reply_to;
};
typedef struct _exp_msg_zmq_t exp_msg_zmq_t;
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/exp_ops/exp_ops_codes.c 0000664 0000000 0000000 00000000304 12326537641 0025643 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/exp_ops/exp_ops_codes.h 0000664 0000000 0000000 00000001323 12326537641 0025652 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _EXP_OPS_CODES_H_
#define _EXP_OPS_CODES_H_
#include
/* Messaging OPCODES */
#define EXP_OPS_OPCODE_SIZE (sizeof (uint32_t))
#define EXP_OPS_OPCODE_TYPE uint32_t
/* Messaging Reply OPCODES */
#define EXP_OPS_REPLY_SIZE (sizeof(uint32_t))
#define EXP_OPS_REPLY_TYPE uint32_t
#define EXP_OPS_REPLY_OK 0
#define EXP_OPS_REPLY_ERR 1
/* Messaging Return Codes */
#define EXP_OPS_RETURN_SIZE (sizeof(int32_t))
#define EXP_OPS_RETURN_TYPE int32_t
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/exp_ops/ops.mk 0000664 0000000 0000000 00000000162 12326537641 0024001 0 ustar 00root root 0000000 0000000 exp_ops_DIR = hal/msg/exp_ops
exp_ops_OBJS = $(exp_ops_DIR)/exp_msg_zmq.o
exp_ops_INCLUDE_DIRS = $(exp_ops_DIR)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/msg.mk 0000664 0000000 0000000 00000000423 12326537641 0022311 0 ustar 00root root 0000000 0000000 include hal/msg/exp_ops/ops.mk
include hal/msg/smio_thsafe_ops/ops.mk
msg_DIR = hal/msg
msg_OBJS = $(msg_DIR)/msg_err.o \
$(exp_ops_OBJS) \
$(smio_thsafe_ops_OBJS)
msg_INCLUDE_DIRS = $(msg_DIR) \
$(exp_ops_INCLUDE_DIRS) \
$(smio_thsafe_ops_INCLUDE_DIRS)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/msg_err.c 0000664 0000000 0000000 00000001327 12326537641 0023000 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#include "msg_err.h"
static const char *msg_err [MSG_ERR_END] =
{
[MSG_SUCCESS] = "Success",
[MSG_ERR] = "Messaging error",
[MSG_ERR_ALLOC] = "Could not allocate message",
[MSG_FUNC_NOT_IMPL] = "Function not implemented"
};
/* Convert enumeration type to string */
const char * msg_err_str (msg_err_e err)
{
return msg_err [err];
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/msg_err.h 0000664 0000000 0000000 00000001414 12326537641 0023002 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#ifndef _MSG_ERR_H_
#define _MSG_ERR_H_
enum _msg_err_e
{
MSG_SUCCESS = 0, /* No error */
MSG_ERR, /* Generic messaging error */
MSG_ERR_ALLOC, /* Could not allocate message */
MSG_FUNC_NOT_IMPL, /* Function not implemented */
MSG_ERR_END
};
typedef enum _msg_err_e msg_err_e;
/* Convert enumeration type to string */
const char * msg_err_str (msg_err_e err);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/smio_thsafe_ops/ 0000775 0000000 0000000 00000000000 12326537641 0024355 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/smio_thsafe_ops/ops.mk 0000664 0000000 0000000 00000000350 12326537641 0025505 0 ustar 00root root 0000000 0000000 smio_thsafe_ops_DIR = hal/msg/smio_thsafe_ops
smio_thsafe_ops_OBJS = $(smio_thsafe_ops_DIR)/smio_thsafe_zmq_client.o \
$(smio_thsafe_ops_DIR)/smio_thsafe_zmq_server.o
smio_thsafe_ops_INCLUDE_DIRS = $(smio_thsafe_ops_DIR)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/smio_thsafe_ops/smio_thsafe_zmq_client.c 0000664 0000000 0000000 00000037614 12326537641 0031262 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include "smio_thsafe_zmq_client.h"
#include "hal_assert.h"
#include "msg_err.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, MSG, "[smio_thsafe_client:zmq]", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, MSG, "[smio_thsafe_client:zmq]", \
msg_err_str(MSG_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, MSG, "[smio_thsafe_client:zmq]", \
msg_err_str (err_type))
static zmsg_t *_thsafe_zmq_client_recv_confirmation (smio_t *self);
int _thsafe_zmq_client_open_release (smio_t *self, llio_endpoint_t *endpoint, uint32_t opcode);
static ssize_t _thsafe_zmq_client_read_generic (smio_t *self, loff_t offs, uint8_t *data,
uint32_t size);
static ssize_t _thsafe_zmq_client_write_generic (smio_t *self, loff_t offs, const uint8_t *data,
uint32_t size);
/**** Open device ****/
int thsafe_zmq_client_open (smio_t *self, llio_endpoint_t *endpoint)
{
return _thsafe_zmq_client_open_release (self, endpoint, THSAFE_OPEN);
}
/**** Release device ****/
int thsafe_zmq_client_release (smio_t *self, llio_endpoint_t *endpoint)
{
return _thsafe_zmq_client_open_release (self, endpoint, THSAFE_RELEASE);
}
/**** Read data from device ****/
ssize_t thsafe_zmq_client_read_16 (smio_t *self, loff_t offs, uint16_t *data)
{
return _thsafe_zmq_client_read_generic (self, offs, (uint8_t *) data, THSAFE_READ_16_DSIZE);
}
ssize_t thsafe_zmq_client_read_32 (smio_t *self, loff_t offs, uint32_t *data)
{
return _thsafe_zmq_client_read_generic (self, offs, (uint8_t *) data, THSAFE_READ_32_DSIZE);
}
ssize_t thsafe_zmq_client_read_64 (smio_t *self, loff_t offs, uint64_t *data)
{
return _thsafe_zmq_client_read_generic (self, offs, (uint8_t *) data, THSAFE_READ_64_DSIZE);
}
/**** Write data to device ****/
ssize_t thsafe_zmq_client_write_16 (smio_t *self, loff_t offs, const uint16_t *data)
{
return _thsafe_zmq_client_write_generic (self, offs, (const uint8_t *) data, THSAFE_WRITE_16_DSIZE);
}
ssize_t thsafe_zmq_client_write_32 (smio_t *self, loff_t offs, const uint32_t *data)
{
return _thsafe_zmq_client_write_generic (self, offs, (const uint8_t *) data, THSAFE_WRITE_32_DSIZE);
}
ssize_t thsafe_zmq_client_write_64 (smio_t *self, loff_t offs, const uint64_t *data)
{
return _thsafe_zmq_client_write_generic (self, offs, (const uint8_t *) data, THSAFE_WRITE_64_DSIZE);
}
/**** Read data block from device function pointer, size in bytes ****/
ssize_t thsafe_zmq_client_read_block (smio_t *self, loff_t offs, size_t size, uint32_t *data)
{
(void) self;
(void) offs;
(void) size;
(void) data;
return -1;
}
/**** Write data block from device function pointer, size in bytes ****/
ssize_t thsafe_zmq_client_write_block (smio_t *self, loff_t offs, size_t size, const uint32_t *data)
{
(void) self;
(void) offs;
(void) size;
(void) data;
return -1;
}
/**** Read data block via DMA from device, size in bytes ****/
ssize_t thsafe_zmq_client_read_dma (smio_t *self, loff_t offs, size_t size, uint32_t *data)
{
(void) self;
(void) offs;
(void) size;
(void) data;
return -1;
}
/**** Write data block via DMA from device, size in bytes ****/
ssize_t thsafe_zmq_client_write_dma (smio_t *self, loff_t offs, size_t size, const uint32_t *data)
{
(void) self;
(void) offs;
(void) size;
(void) data;
return -1;
}
/**** Read device information function pointer ****/
/* int thsafe_zmq_client_read_info (smio_t *self, thsafe_dev_info_t *dev_info)
*{
* (void) self;
* (void) dev_info;
* return -1;
*} */
/*************** Helper functions **************/
int _thsafe_zmq_client_open_release (smio_t *self, llio_endpoint_t *endpoint, uint32_t opcode)
{
assert (self);
int ret = -1;
zmsg_t *send_msg = zmsg_new ();
ASSERT_ALLOC(send_msg, err_msg_alloc);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Calling thsafe_release\n");
/* Message is:
* frame 0: RELEASE opcode
* frame 1: endpopint struct (FIXME?) */
int zerr = zmsg_addmem (send_msg, &opcode, sizeof (opcode));
ASSERT_TEST(zerr == 0, "Could not add OPEN opcode in message",
err_add_opcode);
zerr = zmsg_addmem (send_msg, endpoint, sizeof (*endpoint));
ASSERT_TEST(zerr == 0, "Could not add endpoint in message",
err_add_endpoint);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Sending message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (send_msg);
#endif
zerr = zmsg_send (&send_msg, self->pipe);
ASSERT_TEST(zerr == 0, "Could not send message", err_send_msg);
/* Message is:
* frame 0: reply code
* frame 1: return code */
/* Returns NULL if confirmation was not OK or in case of error.
* Returns the original message if the confirmation was OK */
zmsg_t *recv_msg = _thsafe_zmq_client_recv_confirmation (self);
ASSERT_TEST(recv_msg != NULL, "Could not receive confirmation code", err_null_raw_data);
/* If we are here the message got a OK reply code.
* Just return the return code */
zframe_t *reply_frame = zmsg_pop (recv_msg);
zframe_destroy (&reply_frame); /* Don't do anything with the reply code */
zframe_t *ret_code_frame = zmsg_pop (recv_msg);
if (ret_code_frame == NULL) {
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Interrupted or malformed message\n");
/* Interrupted or malformed message */
goto err_recv_data;
}
/* Check if the frame has the number of bytes requested.
* For now, we consider a success only when the number of
* bytes requested is the same as the actually read*/
if (zframe_size (ret_code_frame) != THSAFE_REPLY_SIZE) {
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Frame size is wrong\n");
goto err_recv_data_size;
}
ret = *(THSAFE_REPLY_TYPE *) zframe_data (ret_code_frame);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Received return code: %08X\n", ret);
err_recv_data_size:
zframe_destroy (&ret_code_frame);
err_recv_data:
err_null_raw_data:
zmsg_destroy (&recv_msg);
err_send_msg:
err_add_endpoint:
err_add_opcode:
zmsg_destroy (&send_msg);
err_msg_alloc:
return ret;
}
static ssize_t _thsafe_zmq_client_read_generic (smio_t *self, loff_t offs, uint8_t *data,
uint32_t size)
{
assert (self);
ssize_t ret_size = -1;
zmsg_t *send_msg = zmsg_new ();
ASSERT_ALLOC(send_msg, err_msg_alloc);
uint32_t opcode;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Calling _thsafe_read_generic\n");
switch (size) {
case THSAFE_READ_16_DSIZE:
opcode = THSAFE_READ_16;
break;
case THSAFE_READ_32_DSIZE:
opcode = THSAFE_READ_32;
break;
case THSAFE_READ_64_DSIZE:
opcode = THSAFE_READ_64;
break;
default:
opcode = THSAFE_READ_32;
}
/* Message is:
* frame 0: READ opcode
* frame 1: offset */
int zerr = zmsg_addmem (send_msg, &opcode, sizeof (opcode));
ASSERT_TEST(zerr == 0, "Could not add READ opcode in message",
err_add_opcode);
zerr = zmsg_addmem (send_msg, &offs, sizeof (offs));
ASSERT_TEST(zerr == 0, "Could not add offset in message",
err_add_offset);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Sending message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (send_msg);
#endif
zerr = zmsg_send (&send_msg, self->pipe);
ASSERT_TEST(zerr == 0, "Could not send message", err_send_msg);
/* Message is:
* frame 0: reply code
* frame 1: return code
* frame 2: data */
/* Returns NULL if confirmation was not OK or in case of error.
* Returns the original message if the confirmation was OK */
zmsg_t *recv_msg = _thsafe_zmq_client_recv_confirmation (self);
ASSERT_TEST(recv_msg != NULL, "Could not receive confirmation code", err_null_recv_msg);
/* If we are here, confirmation code was OK. Check for second frame */
zframe_t *reply_frame = zmsg_pop (recv_msg);
zframe_destroy (&reply_frame); /* Don't do anything with the reply code */
zframe_t *return_frame = zmsg_pop (recv_msg);
ASSERT_TEST(return_frame != NULL, "Could not receive retrurn code", err_null_ret_code_frame);
if (zframe_size (return_frame) != THSAFE_RETURN_SIZE) {
DBE_DEBUG (DBG_MSG | DBG_LVL_ERR, "[smio_thsafe_client:zmq] Return frame size is wrong\n");
goto err_wrong_size_ret_frame;
}
zframe_t *data_frame = zmsg_pop (recv_msg);
ASSERT_TEST(data_frame != NULL, "Could not receive data", err_recv_data);
/* Check if the frame has the number of bytes requested.
* For now, we consider a success only when the number of
* bytes requested is the same as the actually read*/
if ((ssize_t) zframe_size (data_frame) != *(THSAFE_RETURN_TYPE *) zframe_data (return_frame)) {
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Data frame size is wrong\n");
goto err_recv_data;
}
uint8_t* raw_data = (uint8_t *) zframe_data (data_frame);
memcpy (data, raw_data, size);
ret_size = size;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Received data: %08X\n", *data);
zframe_destroy (&data_frame);
err_recv_data:
err_wrong_size_ret_frame:
zframe_destroy (&return_frame);
err_null_ret_code_frame:
zmsg_destroy (&recv_msg);
err_null_recv_msg:
err_send_msg:
err_add_offset:
err_add_opcode:
zmsg_destroy (&send_msg);
err_msg_alloc:
return ret_size;
}
static ssize_t _thsafe_zmq_client_write_generic (smio_t *self, loff_t offs, const uint8_t *data,
uint32_t size)
{
assert (self);
ssize_t ret_size = -1;
zmsg_t *send_msg = zmsg_new ();
ASSERT_ALLOC(send_msg, err_msg_alloc);
uint32_t opcode;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Calling _thsafe_write_generic\n");
switch (size) {
case THSAFE_WRITE_16_DSIZE:
opcode = THSAFE_WRITE_16;
break;
case THSAFE_WRITE_32_DSIZE:
opcode = THSAFE_WRITE_32;
break;
case THSAFE_WRITE_64_DSIZE:
opcode = THSAFE_WRITE_64;
break;
default:
opcode = THSAFE_WRITE_32;
}
/* Message is:
* frame 0: WRITE opcode
* frame 1: offset
* frame 2: data to be written
* */
int zerr = zmsg_addmem (send_msg, &opcode, sizeof (opcode));
ASSERT_TEST(zerr == 0, "Could not add WRITE opcode in message",
err_add_opcode);
zerr = zmsg_addmem (send_msg, &offs, sizeof (offs));
ASSERT_TEST(zerr == 0, "Could not add offset in message",
err_add_offset);
zerr = zmsg_addmem (send_msg, data, size);
ASSERT_TEST(zerr == 0, "Could not add READ opcode in message",
err_add_data);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Sending message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (send_msg);
#endif
zerr = zmsg_send (&send_msg, self->pipe);
ASSERT_TEST(zerr == 0, "Could not send message",
err_send_msg);
/* Message is:
* frame 0: reply code
* frame 1: return code */
/* Returns NULL if confirmation was not OK or in case of error.
* Returns the original message if the confirmation was OK */
zmsg_t *recv_msg = _thsafe_zmq_client_recv_confirmation (self);
ASSERT_TEST(recv_msg != NULL, "Could not receive confirmation code", err_null_recv_msg);
/* If we are here, confirmation code was OK. Check for second frame */
zframe_t *reply_frame = zmsg_pop (recv_msg);
zframe_destroy (&reply_frame); /* Don't do anything with the reply code */
zframe_t *return_frame = zmsg_pop (recv_msg);
ASSERT_TEST(return_frame != NULL, "Could not receive retrurn code", err_null_ret_code_frame);
if (zframe_size (return_frame) != THSAFE_RETURN_SIZE) {
DBE_DEBUG (DBG_MSG | DBG_LVL_ERR, "[smio_thsafe_client:zmq] Return frame size is wrong\n");
goto err_wrong_size_ret_frame;
}
ret_size = *(THSAFE_RETURN_TYPE *) zframe_data (return_frame);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Received code: %zd\n", ret_size);
err_wrong_size_ret_frame:
zframe_destroy (&return_frame);
err_null_ret_code_frame:
err_null_recv_msg:
err_send_msg:
err_add_data:
err_add_offset:
err_add_opcode:
zmsg_destroy (&recv_msg);
err_msg_alloc:
return ret_size;
}
static zmsg_t *_thsafe_zmq_client_recv_confirmation (smio_t *self)
{
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Calling _thsafe_zmq_client_recv_confirmation\n");
assert (self);
/* Wait for response */
zmsg_t *recv_msg = zmsg_recv (self->pipe);
/* Do not pop the message, just set a cursor to it */
zframe_t *reply_frame = zmsg_first (recv_msg);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Receiving message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (recv_msg);
#endif
/* Message is:
* frame 0: Reply code */
if (reply_frame == NULL) {
/* Interrupted or malformed message */
goto err_recv_data;
}
/* Check if the frame has the correct number of bytes */
if (zframe_size (reply_frame) != THSAFE_REPLY_SIZE) {
goto err_recv_data;
}
uint8_t *raw_data = (uint8_t *) zframe_data (reply_frame);
ASSERT_TEST(raw_data != NULL, "Could not receive confirmation code", err_null_raw_data);
uint32_t reply_code = *(uint32_t *) raw_data;
/* Check for confirmation */
if (reply_code != THSAFE_OK) {
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Received reply code OK\n");
goto err_reply_code_not_ok;
}
/* Caller owns the message and is its responsability to destroy it */
return recv_msg;
/* TODO: reduce code repetition */
err_reply_code_not_ok:
err_null_raw_data:
err_recv_data:
zmsg_destroy (&recv_msg);
return NULL;
}
/*************** Our constant structure **************/
const smio_thsafe_client_ops_t smio_thsafe_client_zmq_ops = {
.thsafe_client_open = thsafe_zmq_client_open, /* Open device */
.thsafe_client_release = thsafe_zmq_client_release, /* Release device */
.thsafe_client_read_16 = thsafe_zmq_client_read_16, /* Read 16-bit data */
.thsafe_client_read_32 = thsafe_zmq_client_read_32, /* Read 32-bit data */
.thsafe_client_read_64 = thsafe_zmq_client_read_64, /* Read 64-bit data */
.thsafe_client_write_16 = thsafe_zmq_client_write_16, /* Write 16-bit data */
.thsafe_client_write_32 = thsafe_zmq_client_write_32, /* Write 32-bit data */
.thsafe_client_write_64 = thsafe_zmq_client_write_64, /* Write 64-bit data */
.thsafe_client_read_block = thsafe_zmq_client_read_block, /* Read arbitrary block size data,
parameter size in bytes */
.thsafe_client_write_block = thsafe_zmq_client_write_block, /* Write arbitrary block size data,
parameter size in bytes */
.thsafe_client_read_dma = thsafe_zmq_client_read_dma, /* Read arbitrary block size data via DMA,
_ parameter size in bytes */
.thsafe_client_write_dma = thsafe_zmq_client_write_dma /* Write arbitrary block size data via DMA,
parameter size in bytes */
/*.thsafe_client_read_info = thsafe_zmq_client_read_info */ /* Read device information data */
};
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/smio_thsafe_ops/smio_thsafe_zmq_client.h 0000664 0000000 0000000 00000000611 12326537641 0031252 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _SMIO_THSAFE_ZMQ_H_
#define _SMIO_THSAFE_ZMQ_H_
#include "sm_io.h"
#include "sm_io_thsafe_codes.h"
/* For use by smio_t general structure */
extern const smio_thsafe_client_ops_t smio_thsafe_client_zmq_ops;
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/smio_thsafe_ops/smio_thsafe_zmq_server.c 0000664 0000000 0000000 00000042663 12326537641 0031312 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include "smio_thsafe_zmq_server.h"
#include "hal_assert.h"
#include "msg_err.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, MSG, "[smio_thsafe_server:zmq]", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, MSG, "[smio_thsafe_server:zmq]", \
msg_err_str(MSG_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, MSG, "[smio_thsafe_server:zmq]", \
msg_err_str (err_type))
static int _thsafe_zmq_server_send_read (int32_t *llio_ret, uint8_t *data,
uint32_t size, void *reply_to);
static int _thsafe_zmq_server_recv_read (zmsg_t *msg, loff_t *offset);
static int _thsafe_zmq_server_send_write (int32_t *llio_ret, void *reply_to);
static int _thsafe_zmq_server_recv_write (zmsg_t *msg, loff_t *offset,
uint8_t *data, uint32_t size);
/**** Open device ****/
void *thsafe_zmq_server_open (void *owner, void *args)
{
assert (owner);
assert (args);
devio_t *self = (devio_t *) owner;
zmq_server_args_t *server_args = (zmq_server_args_t *) args;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Calling thsafe_open\n");
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Received message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (*server_args->msg);
#endif
/* Message is:
* frame null: OPEN opcode (removed by dev_io)
* frame 0: endpopint struct (FIXME?) */
zframe_t *endpoint = zmsg_pop (*server_args->msg);
ASSERT_ALLOC(endpoint, err_endpoint_alloc);
/* Call llio to actually perform the
* operation */
int32_t ret = llio_open (self->llio,
(llio_endpoint_t *) zframe_data (endpoint));
/* Send reply back to client */
zmsg_t *send_msg = zmsg_new ();
ASSERT_ALLOC(send_msg, err_send_msg_alloc);
THSAFE_REPLY_TYPE reply_code = THSAFE_OK;
if (ret != 0) {
reply_code = THSAFE_ERR;
}
int zerr = zmsg_addmem (send_msg, &reply_code, sizeof (reply_code));
ASSERT_TEST(zerr == 0, "Could not add reply code in message", err_reply_code);
zerr = zmsg_addmem (send_msg, &ret, sizeof (ret));
ASSERT_TEST(zerr == 0, "Could not add return code in message", err_ret_code);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Sending message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (send_msg);
#endif
zerr = zmsg_send (&send_msg, server_args->reply_to);
ASSERT_TEST(zerr == 0, "Could not send message", err_send_msg);
err_send_msg:
err_ret_code:
err_reply_code:
zmsg_destroy (&send_msg);
err_send_msg_alloc:
zframe_destroy (&endpoint);
err_endpoint_alloc:
/* Might not be safe to do this if we fail */
zmsg_destroy (server_args->msg);
return NULL;
}
/**** Release device ****/
void *thsafe_zmq_server_release (void *owner, void *args)
{
assert (owner);
assert (args);
devio_t *self = (devio_t *) owner;
zmq_server_args_t *server_args = (zmq_server_args_t *) args;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Calling thsafe_release\n");
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Received message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (*server_args->msg);
#endif
/* Message is:
* frame null: OPEN opcode (removed by dev_io)
* frame 0: endpopint struct (FIXME?) */
zframe_t *endpoint = zmsg_pop (*server_args->msg);
ASSERT_ALLOC(endpoint, err_endpoint_alloc);
/* Call llio to actually perform the
* operation */
int32_t ret = llio_release (self->llio,
(llio_endpoint_t *) zframe_data (endpoint));
/* Send reply back to client */
zmsg_t *send_msg = zmsg_new ();
ASSERT_ALLOC(send_msg, err_send_msg_alloc);
THSAFE_REPLY_TYPE reply_code = THSAFE_OK;
if (ret != 0) {
reply_code = THSAFE_ERR;
}
int zerr = zmsg_addmem (send_msg, &reply_code, sizeof (reply_code));
ASSERT_TEST(zerr == 0, "Could not add reply code in message", err_reply_code);
zerr = zmsg_addmem (send_msg, &ret, sizeof (ret));
ASSERT_TEST(zerr == 0, "Could not add return code in message", err_ret_code);
zerr = zmsg_send (&send_msg, server_args->reply_to);
ASSERT_TEST(zerr == 0, "Could not send message", err_send_msg);
err_send_msg:
err_ret_code:
err_reply_code:
zmsg_destroy (&send_msg);
err_send_msg_alloc:
zframe_destroy (&endpoint);
err_endpoint_alloc:
/* Might not be safe to do this if we fail */
zmsg_destroy (server_args->msg);
return NULL;
}
/**** Read data from device ****/
void *thsafe_zmq_server_read_16 (void *owner, void *args)
{
assert (owner);
assert (args);
devio_t *self = (devio_t *) owner;
zmq_server_args_t *server_args = (zmq_server_args_t *) args;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Calling thsafe_read_16\n");
loff_t offset = 0;
int zerr = _thsafe_zmq_server_recv_read (*server_args->msg, &offset);
ASSERT_TEST(zerr == 0, "Could receive message", err_recv_msg);
/* Alloc space for the data read */
uint16_t data = 0;
/* Call llio to perform the actual operation */
int32_t llio_ret = llio_read_16 (self->llio, offset, &data);
/* Send reply back to client */
_thsafe_zmq_server_send_read (&llio_ret, (uint8_t *) &data, sizeof (data),
server_args->reply_to);
err_recv_msg:
/* Might not be safe to do this if we fail */
zmsg_destroy (server_args->msg);
return NULL;
}
/* TODO: Reduce code repetition */
/* Changed only the necessary parameters out of laziness */
void *thsafe_zmq_server_read_32 (void *owner, void *args)
{
assert (owner);
assert (args);
devio_t *self = (devio_t *) owner;
zmq_server_args_t *server_args = (zmq_server_args_t *) args;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Calling thsafe_read_32\n");
loff_t offset = 0;
int zerr = _thsafe_zmq_server_recv_read (*server_args->msg, &offset);
ASSERT_TEST(zerr == 0, "Could receive message", err_recv_msg);
/* Alloc space for the data read */
uint32_t data = 0;
/* Call llio to perform the actual operation */
int32_t llio_ret = llio_read_32 (self->llio, offset, &data);
printf ("message read from LLIO is: %u\n", data);
/* Send message back to client */
_thsafe_zmq_server_send_read (&llio_ret, (uint8_t *) &data, sizeof (data),
server_args->reply_to);
err_recv_msg:
/* Might not be safe to do this if we fail */
zmsg_destroy (server_args->msg);
return NULL;
}
/* TODO: Reduce code repetition */
/* Changed only the necessary parameters out of laziness */
void *thsafe_zmq_server_read_64 (void *owner, void *args)
{
assert (owner);
assert (args);
devio_t *self = (devio_t *) owner;
zmq_server_args_t *server_args = (zmq_server_args_t *) args;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Calling thsafe_read_64\n");
loff_t offset = 0;
int zerr = _thsafe_zmq_server_recv_read (*server_args->msg, &offset);
ASSERT_TEST(zerr == 0, "Could receive message", err_recv_msg);
/* Alloc space for the data read */
uint64_t data = 0;
/* Call llio to perform the actual operation */
int32_t llio_ret = llio_read_64 (self->llio, offset, &data);
/* Send message back to client */
_thsafe_zmq_server_send_read (&llio_ret, (uint8_t *) &data, sizeof (data),
server_args->reply_to);
err_recv_msg:
/* Might not be safe to do this if we fail */
zmsg_destroy (server_args->msg);
return NULL;
}
/**** Write data to device ****/
void *thsafe_zmq_server_write_16 (void *owner, void *args)
{
assert (owner);
assert (args);
devio_t *self = (devio_t *) owner;
zmq_server_args_t *server_args = (zmq_server_args_t *) args;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Calling thsafe_write_16\n");
uint16_t data_write = 0;
loff_t offset = 0;
int zerr = _thsafe_zmq_server_recv_write (*server_args->msg, &offset,
(uint8_t *) &data_write, THSAFE_WRITE_16_DSIZE);
ASSERT_TEST(zerr == 0, "Could receive message", err_recv_msg);
/* Call llio to perform the actual operation */
int32_t llio_ret = llio_write_16 (self->llio, offset, &data_write);
/* Send message back to client */
_thsafe_zmq_server_send_write (&llio_ret, server_args->reply_to);
err_recv_msg:
/* Might not be safe to do this if we fail */
zmsg_destroy (server_args->msg);
return NULL;
}
void *thsafe_zmq_server_write_32 (void *owner, void *args)
{
assert (owner);
assert (args);
devio_t *self = (devio_t *) owner;
zmq_server_args_t *server_args = (zmq_server_args_t *) args;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Calling thsafe_write_32\n");
uint32_t data_write = 0;
loff_t offset = 0;
int zerr = _thsafe_zmq_server_recv_write (*server_args->msg, &offset,
(uint8_t *) &data_write, THSAFE_WRITE_32_DSIZE);
ASSERT_TEST(zerr == 0, "Could receive message", err_recv_msg);
/* Call llio to perform the actual operation */
int32_t llio_ret = llio_write_32 (self->llio, offset, &data_write);
/* Send message back to client */
_thsafe_zmq_server_send_write (&llio_ret, server_args->reply_to);
err_recv_msg:
/* Might not be safe to do this if we fail */
zmsg_destroy (server_args->msg);
return NULL;
}
void *thsafe_zmq_server_write_64 (void *owner, void *args)
{
assert (owner);
assert (args);
devio_t *self = (devio_t *) owner;
zmq_server_args_t *server_args = (zmq_server_args_t *) args;
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Calling thsafe_write_64\n");
uint64_t data_write = 0;
loff_t offset = 0;
int zerr = _thsafe_zmq_server_recv_write (*server_args->msg, &offset,
(uint8_t *) &data_write, THSAFE_WRITE_64_DSIZE);
ASSERT_TEST(zerr == 0, "Could receive message", err_recv_msg);
/* Call llio to perform the actual operation */
int32_t llio_ret = llio_write_64 (self->llio, offset, &data_write);
/* Send message back to client */
_thsafe_zmq_server_send_write (&llio_ret, server_args->reply_to);
err_recv_msg:
/* Might not be safe to do this if we fail */
zmsg_destroy (server_args->msg);
return NULL;
}
/**** Read data block from device function pointer, size in bytes ****/
void *thsafe_zmq_server_read_block (void *owner, void *args)
{
(void) owner;
(void) args;
return NULL;
}
/**** Write data block from device function pointer, size in bytes ****/
void *thsafe_zmq_server_write_block (void *owner, void *args)
{
(void) owner;
(void) args;
return NULL;
}
/**** Read data block via DMA from device, size in bytes ****/
void *thsafe_zmq_server_read_dma (void *owner, void *args)
{
(void) owner;
(void) args;
return NULL;
}
/**** Write data block via DMA from device, size in bytes ****/
void *thsafe_zmq_server_write_dma (void *owner, void *args)
{
(void) owner;
(void) args;
return NULL;
}
/**** Read device information function pointer ****/
/* void *thsafe_zmq_server_read_info (void *owner, void *args)
*{
* (void) owner;
* (void) args;
* return NULL;
*} */
/*************** Helper functions **************/
static int _thsafe_zmq_server_send_read (int32_t *llio_ret, uint8_t *data, uint32_t size, void *reply_to)
{
assert (llio_ret);
int ret = 0; /* success */
/* Send reply back to client */
zmsg_t *send_msg = zmsg_new ();
ret = (send_msg == NULL) ? -1 : ret;
ASSERT_ALLOC(send_msg, err_send_msg_alloc);
THSAFE_REPLY_TYPE reply_code = THSAFE_OK;
if (*llio_ret < 0) {
reply_code = THSAFE_ERR;
}
/* Message is:
* frame 0: reply code
* frame 1: return code
* frame 2: data read */
int zerr = zmsg_addmem (send_msg, &reply_code, sizeof (reply_code));
ASSERT_TEST(zerr == 0, "Could not add reply code in message", err_reply_code);
zerr = zmsg_addmem (send_msg, llio_ret, sizeof (*llio_ret));
ASSERT_TEST(zerr == 0, "Could not add number of bytes read in message", err_ret_code);
zerr = zmsg_addmem (send_msg, data, size);
ASSERT_TEST(zerr == 0, "Could not add read data in message", err_data_send);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Sending message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (send_msg);
#endif
zerr = zmsg_send (&send_msg, reply_to);
ASSERT_TEST(zerr == 0, "Could not send message", err_send_msg);
err_send_msg:
err_data_send:
err_ret_code:
err_reply_code:
zmsg_destroy (&send_msg);
err_send_msg_alloc:
return ret;
}
static int _thsafe_zmq_server_recv_read (zmsg_t *msg, loff_t *offset)
{
assert (offset);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq:read] Received message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (msg);
#endif
/* Message is:
* frame null: READ opcode
* frame 0: offset */
zframe_t *offset_frame = zmsg_pop (msg);
ASSERT_ALLOC(offset, err_offset_alloc);
if (zframe_size (offset_frame) != sizeof (loff_t)) {
goto err_wrong_offset_size;
}
*offset = *(loff_t *) zframe_data (offset_frame);
zframe_destroy (&offset_frame);
return 0;
err_wrong_offset_size:
err_offset_alloc:
zframe_destroy (&offset_frame);
return -1;
}
static int _thsafe_zmq_server_send_write (int32_t *llio_ret, void *reply_to)
{
assert (llio_ret);
int ret = 0; /* success */
/* Send reply back to client */
zmsg_t *send_msg = zmsg_new ();
ret = (send_msg == NULL) ? -1 : ret;
ASSERT_ALLOC(send_msg, err_send_msg_alloc);
THSAFE_REPLY_TYPE reply_code = THSAFE_OK;
if (*llio_ret < 0) {
reply_code = THSAFE_ERR;
}
/* Message is:
* frame 0: reply code
* frame 1: return code */
int zerr = zmsg_addmem (send_msg, &reply_code, sizeof (reply_code));
ASSERT_TEST(zerr == 0, "Could not add reply code in message", err_reply_code);
zerr = zmsg_addmem (send_msg, llio_ret, sizeof (*llio_ret));
ASSERT_TEST(zerr == 0, "Could not add number of bytes read in message", err_ret_code);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Sent message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (send_msg);
#endif
zerr = zmsg_send (&send_msg, reply_to);
ASSERT_TEST(zerr == 0, "Could not send message", err_send_msg);
err_send_msg:
err_ret_code:
err_reply_code:
zmsg_destroy (&send_msg);
err_send_msg_alloc:
return ret;
}
static int _thsafe_zmq_server_recv_write (zmsg_t *msg, loff_t *offset,
uint8_t *data, uint32_t size)
{
assert (offset);
assert (data);
DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_server:zmq] Received message:\n");
#ifdef LOCAL_MSG_DBG
zmsg_print (msg);
#endif
/* Message is:
* frame null: WRITE opcode
* frame 0: offset
* frame 1: data to be written */
zframe_t *offset_frame = zmsg_pop (msg);
ASSERT_ALLOC(offset, err_offset_alloc);
zframe_t *data_write_frame = zmsg_pop (msg);
ASSERT_ALLOC(offset, err_data_write_alloc);
if (zframe_size (data_write_frame) != size) {
DBE_DEBUG (DBG_MSG | DBG_LVL_ERR, "[smio_thsafe_server:zmq] Wrong received data size\n");
goto err_wrong_data_write_size;
}
*offset = *(loff_t *) zframe_data (offset_frame);
memcpy (data, zframe_data (data_write_frame), size);
zframe_destroy (&data_write_frame);
zframe_destroy (&offset_frame);
return 0;
err_wrong_data_write_size:
zframe_destroy (&data_write_frame);
err_data_write_alloc:
zframe_destroy (&offset_frame);
err_offset_alloc:
return -1;
}
/*************** Our constant structure **************/
const smio_thsafe_server_ops_t smio_thsafe_zmq_server_ops = {
.thsafe_server_open = thsafe_zmq_server_open, /* Open device */
.thsafe_server_release = thsafe_zmq_server_release, /* Release device */
.thsafe_server_read_16 = thsafe_zmq_server_read_16, /* Read 16-bit data */
.thsafe_server_read_32 = thsafe_zmq_server_read_32, /* Read 32-bit data */
.thsafe_server_read_64 = thsafe_zmq_server_read_64, /* Read 64-bit data */
.thsafe_server_write_16 = thsafe_zmq_server_write_16, /* Write 16-bit data */
.thsafe_server_write_32 = thsafe_zmq_server_write_32, /* Write 32-bit data */
.thsafe_server_write_64 = thsafe_zmq_server_write_64, /* Write 64-bit data */
.thsafe_server_read_block = thsafe_zmq_server_read_block, /* Read arbitrary block size data,
parameter size in bytes */
.thsafe_server_write_block = thsafe_zmq_server_write_block, /* Write arbitrary block size data,
parameter size in bytes */
.thsafe_server_read_dma = thsafe_zmq_server_read_dma, /* Read arbitrary block size data via DMA,
_ parameter size in bytes */
.thsafe_server_write_dma = thsafe_zmq_server_write_dma /* Write arbitrary block size data via DMA,
parameter size in bytes */
/*.thsafe_server_read_info = thsafe_zmq_server_read_info */ /* Read device information data */
};
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/msg/smio_thsafe_ops/smio_thsafe_zmq_server.h 0000664 0000000 0000000 00000001013 12326537641 0031277 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _SMIO_THSAFE_ZMQ_H_
#define _SMIO_THSAFE_ZMQ_H_
#include "dev_io_core.h"
#include "sm_io_thsafe_codes.h"
/* For use by smio_t general structure */
extern const smio_thsafe_server_ops_t smio_thsafe_zmq_server_ops;
struct _zmq_server_args_t {
zmsg_t **msg;
void *reply_to;
};
typedef struct _zmq_server_args_t zmq_server_args_t;
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sdb/ 0000775 0000000 0000000 00000000000 12326537641 0021155 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sdb/sdb.h 0000664 0000000 0000000 00000002750 12326537641 0022102 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*
* This was taken from wrpc-sw reposytory at
* http://www.ohwr.org/projects/wrpc-sw/repository
*/
#ifndef _SDB_H_
#define _SDB_H_
#include
#define SDB_INTERCONNET 0x00
#define SDB_DEVICE 0x01
#define SDB_BRIDGE 0x02
#define SDB_EMPTY 0xFF
typedef struct pair64 {
uint32_t high;
uint32_t low;
} pair64_t;
struct sdb_empty {
int8_t reserved[63];
uint8_t record_type;
};
struct sdb_product {
pair64_t vendor_id;
uint32_t device_id;
uint32_t version;
uint32_t date;
int8_t name[19];
uint8_t record_type;
};
struct sdb_component {
pair64_t addr_first;
pair64_t addr_last;
struct sdb_product product;
};
struct sdb_device {
uint16_t abi_class;
uint8_t abi_ver_major;
uint8_t abi_ver_minor;
uint32_t bus_specific;
struct sdb_component sdb_component;
};
struct sdb_bridge {
pair64_t sdb_child;
struct sdb_component sdb_component;
};
struct sdb_interconnect {
uint32_t sdb_magic;
uint16_t sdb_records;
uint8_t sdb_version;
uint8_t sdb_bus_type;
struct sdb_component sdb_component;
};
typedef union sdb_record {
struct sdb_empty empty;
struct sdb_device device;
struct sdb_bridge bridge;
struct sdb_interconnect interconnect;
} sdb_record_t;
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sdb/sdb.mk 0000664 0000000 0000000 00000000340 12326537641 0022253 0 ustar 00root root 0000000 0000000 sdb_DIR = hal/sdb
# Here we call _core_OBJS as we need to add
# more objects to this target. This is done in the hal.mk
# makefile
#sdb_core_OBJS = $(sdb_DIR)/sdb.o
sdb_INCLUDE_DIRS = $(sdb_DIR)
sdb_OUT = sdb
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/ 0000775 0000000 0000000 00000000000 12326537641 0021513 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/modules/ 0000775 0000000 0000000 00000000000 12326537641 0023163 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/modules/fmc130m_4ch/ 0000775 0000000 0000000 00000000000 12326537641 0025067 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/modules/fmc130m_4ch/fmc130m_4ch.mk 0000664 0000000 0000000 00000000270 12326537641 0027323 0 ustar 00root root 0000000 0000000 sm_io_fmc130m_4ch_DIR = hal/sm_io/modules/fmc130m_4ch
sm_io_fmc130m_4ch_OBJS = $(sm_io_fmc130m_4ch_DIR)/sm_io_fmc130m_4ch.o
sm_io_fmc130m_4ch_INCLUDE_DIRS = $(sm_io_fmc130m_4ch_DIR)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/modules/fmc130m_4ch/sm_io_fmc130m_4ch.c 0000664 0000000 0000000 00000013621 12326537641 0030330 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include "sm_io_fmc130m_4ch.h"
#include "sm_io.h"
#include "dev_io.h"
#include "hal_assert.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, SM_IO, "[sm_io:fmc130m_4ch]",\
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, SM_IO, "[sm_io:fmc130m_4ch]", \
smio_err_str(SMIO_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, SM_IO, "[sm_io:fmc130m_4ch]", \
smio_err_str (err_type))
/************************************************************/
/****************** Specific Operations ********************/
/************************************************************/
/* This does not belong to any public interface. It's meant to
* allow the do_ops() function to route the operations based on
* the opcode */
/* FIXME FIXME! We don't have to know our transport layer! */
#define BAR4_ADDR (4 << 28)
#define FMC1_ADDR 0x00310000
/* #define FMC2_ADDR 0x00310000 + ???? */
#define FMC_MONITOR_REG (0x010)
#define FMC1 1
#define FMC2 2
/************************************************************/
/************* Specific fmc_130m_4ch functions **************/
/************************************************************/
static void *_fmc130m_4ch_leds (void *owner, void *args)
{
assert (owner);
assert (args);
smio_t *self = (smio_t *) owner;
exp_msg_zmq_t *exp_msg = (exp_msg_zmq_t *) args;
assert (zmsg_size (*exp_msg->msg) > 0);
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "[sm_io:fmc130m_4ch] Calling _fmc130m_4ch_leds\n");
uint32_t leds = *(uint32_t *) zframe_data (zmsg_pop (*exp_msg->msg));
smio_thsafe_client_write_32 (self, BAR4_ADDR | FMC1_ADDR | FMC_MONITOR_REG,
&leds);
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "[sm_io:fmc130m_4ch_boot] Led write: 0x%08x\n",
leds);
/* Don't send any response, for now... */
return NULL;
}
/* #define EXP_FUNC_FMC130M_4CH_SIZE 1 */
#define FMC130M_4CH_OPCODE_LEDS 0
#define FMC130M_4CH_NAME_LEDS "leds"
#define FMC130M_4CH_OPCODE_END 1
const smio_exp_ops_t fmc130m_exp_ops [] = {
{.name = FMC130M_4CH_NAME_LEDS, .opcode = FMC130M_4CH_OPCODE_LEDS, .func_fp = _fmc130m_4ch_leds},
{.name = NULL, .opcode = 0, .func_fp = NULL} /* Must end with this NULL pattern */
};
/************************************************************/
/***************** Export methods functions *****************/
/************************************************************/
static smio_err_e _fmc130m_4ch_do_op (void *owner, void *msg);
/* Attach an instance of sm_io to dev_io function pointer */
smio_err_e fmc130m_4ch_attach (smio_t *self, devio_t *parent)
{
(void) self;
(void) parent;
return SMIO_ERR_FUNC_NOT_IMPL;
}
/* Deattach an instance of sm_io to dev_io function pointer */
smio_err_e fmc130m_4ch_deattach (smio_t *self)
{
(void) self;
return SMIO_ERR_FUNC_NOT_IMPL;
}
/* Export (register) sm_io to handle operations function pointer */
smio_err_e fmc130m_4ch_export_ops (smio_t *self,
const smio_exp_ops_t* smio_exp_ops)
{
(void) self;
(void) smio_exp_ops;
return SMIO_ERR_FUNC_NOT_IMPL;
}
/* Unexport (unregister) sm_io to handle operations function pointer */
smio_err_e fmc130m_4ch_unexport_ops (smio_t *self)
{
(void) self;
return SMIO_ERR_FUNC_NOT_IMPL;
}
/* Generic wrapper for receiving opcodes and arguments to specific funtions function pointer */
/* FIXME: Code repetition! _devio_do_smio_op () function does almost the same!!! */
smio_err_e _fmc130m_4ch_do_op (void *owner, void *msg)
{
(void) owner;
(void) msg;
return SMIO_ERR_FUNC_NOT_IMPL;
}
smio_err_e fmc130m_4ch_do_op (void *self, void *msg)
{
return _fmc130m_4ch_do_op (self, msg);
}
const smio_ops_t fmc130m_4ch_ops = {
.attach = fmc130m_4ch_attach, /* Attach sm_io instance to dev_io */
.deattach = fmc130m_4ch_deattach, /* Deattach sm_io instance to dev_io */
.export_ops = fmc130m_4ch_export_ops, /* Export sm_io operations to dev_io */
.unexport_ops = fmc130m_4ch_unexport_ops, /* Unexport sm_io operations to dev_io */
.do_op = fmc130m_4ch_do_op /* Generic wrapper for handling specific operations */
};
/************************************************************/
/****************** Bootstrap Operations ********************/
/************************************************************/
smio_err_e fmc130m_4ch_init (smio_t * self)
{
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "[sm_io:fmc130m_4ch] Initializing fmc130m_4ch\n");
smio_err_e err = SMIO_ERR_ALLOC;
self->id = FMC130M_4CH_SDB_DEVID;
self->name = strdup (FMC130M_4CH_SDB_NAME);
ASSERT_ALLOC(self->name, err_name_alloc);
/* Set SMIO ops pointers */
self->ops = &fmc130m_4ch_ops;
self->thsafe_client_ops = &smio_thsafe_client_zmq_ops;
self->exp_ops = fmc130m_exp_ops;
err = SMIO_SUCCESS;
err_name_alloc:
return err;
}
/* Destroy sm_io instance of fmc130m_4ch */
smio_err_e fmc130m_4ch_shutdown (smio_t *self)
{
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "[sm_io:fmc130m_4ch] Shutting down fmc130m_4ch\n");
self->exp_ops = NULL;
self->thsafe_client_ops = NULL;
self->ops = NULL;
free (self->name);
return SMIO_SUCCESS;
}
const smio_bootstrap_ops_t fmc130m_4ch_bootstrap_ops = {
.init = fmc130m_4ch_init,
.shutdown = fmc130m_4ch_shutdown
};
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/modules/fmc130m_4ch/sm_io_fmc130m_4ch.h 0000664 0000000 0000000 00000001032 12326537641 0030326 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _FMC130M_4CH_H_
#define _FMC130M_4CH_H_
#include "sm_io_bootstrap.h"
#include "smio_thsafe_zmq_client.h"
#include "exp_ops_codes.h"
/* Known modules IDs (from SDB records defined in FPGA) */
#define FMC130M_4CH_SDB_DEVID 0x7085ef15
#define FMC130M_4CH_SDB_NAME "FMC130M_4CH"
extern const smio_bootstrap_ops_t fmc130m_4ch_bootstrap_ops;
#endif
sm_io_fmc130m_4ch_core.c 0000664 0000000 0000000 00000003174 12326537641 0031263 0 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/modules/fmc130m_4ch /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include
#include
#include "sm_io_fmc130m_4ch_core.h"
#include "sm_io_err.h"
#include "hal_assert.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, SM_IO, "[sm_io_fmc130m_4ch_core]", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, SM_IO, "[sm_io_fmc130m_4ch_core]", \
smio_err_str(SMIO_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, SM_IO, "[sm_io_fmc130m_4ch_core]", \
smio_err_str (err_type))
/* Creates a new instance of Device Information */
smio_fmc130m_4ch_t * smio_fmc130m_4ch_new (uint32_t dummy)
{
smio_fmc130m_4ch_t *self = (smio_fmc130m_4ch_t *) zmalloc (sizeof *self);
ASSERT_ALLOC(self, err_self_alloc);
self->dummy = dummy;
return self;
err_self_alloc:
return NULL;
}
/* Destroy an instance of the Device Information */
smio_err_e smio_fmc130m_4ch_destroy (smio_fmc130m_4ch_t **self_p)
{
assert (self_p);
if (*self_p) {
smio_fmc130m_4ch_t *self = *self_p;
free (self);
*self_p = NULL;
}
return SMIO_SUCCESS;
}
sm_io_fmc130m_4ch_core.h 0000664 0000000 0000000 00000001373 12326537641 0031267 0 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/modules/fmc130m_4ch /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _SM_IO_FMC130M_4CH_CORE_H_
#define _SM_IO_FMC130M_4CH_CORE_H_
#include
#include "sm_io_err.h"
struct _smio_fmc130m_4ch_t {
uint32_t dummy; /* Just a dummy value to illustrate the idea */
};
/* Opaque class structure */
typedef struct _smio_fmc130m_4ch_t smio_fmc130m_4ch_t;
/***************** Our methods *****************/
/* Creates a new instance of the smio realizationn */
smio_fmc130m_4ch_t * smio_fmc130m_4ch_new (uint32_t dummy);
/* Destroys the smio realizationn */
smio_err_e smio_fmc130m_4ch_destroy (smio_fmc130m_4ch_t **self_p);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/modules/modules.mk 0000664 0000000 0000000 00000000425 12326537641 0025165 0 ustar 00root root 0000000 0000000 include hal/sm_io/modules/fmc130m_4ch/fmc130m_4ch.mk
sm_io_modules_DIR = hal/sm_io/modules
sm_io_modules_OBJS = $(sm_io_modules_DIR)/sm_io_mod_dispatch.o \
$(sm_io_fmc130m_4ch_OBJS)
sm_io_modules_INCLUDE_DIRS = $(sm_io_modules_DIR) \
$(sm_io_fmc130m_4ch_DIR)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/modules/sm_io_mod_dispatch.c 0000664 0000000 0000000 00000001036 12326537641 0027153 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include "sm_io_mod_dispatch.h"
/* Include all available module we can handle */
#include "sm_io_fmc130m_4ch.h"
/* Table of all known modules we can handle */
const smio_mod_dispatch_t smio_mod_dispatch[MOD_DISPATCH_END] = {
[0] = { .id = FMC130M_4CH_SDB_DEVID,
.name = FMC130M_4CH_SDB_NAME,
.bootstrap_ops = &fmc130m_4ch_bootstrap_ops
}
};
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/modules/sm_io_mod_dispatch.h 0000664 0000000 0000000 00000001227 12326537641 0027162 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _MOD_DISPATCH_H_
#define _MOD_DISPATCH_H_
#include
/* #include "sm_io_bootstrap.h" */
/* Number of known specific modules that we can handle */
#define MOD_DISPATCH_END 1
struct _smio_bootstrap_ops_t;
struct _smio_mod_dispatch_t {
uint32_t id;
const char *name;
const struct _smio_bootstrap_ops_t *bootstrap_ops;
};
typedef struct _smio_mod_dispatch_t smio_mod_dispatch_t;
extern const smio_mod_dispatch_t
smio_mod_dispatch[MOD_DISPATCH_END];
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/sm_io.c 0000664 0000000 0000000 00000020765 12326537641 0022777 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include "sm_io.h"
#include "exp_ops_codes.h"
#include "hal_assert.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, SM_IO, "[sm_io]", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, SM_IO, "[sm_io]", \
smio_err_str(SMIO_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, SM_IO, "[sm_io]", \
smio_err_str (err_type))
#define CHECK_FUNC(func_p) \
do { \
if(func_p == NULL) { \
DBE_DEBUG (DBG_SM_IO | DBG_LVL_ERR, \
"[sm_io] %s\n", \
smio_err_str (SMIO_ERR_FUNC_NOT_IMPL)); \
return -SMIO_ERR_FUNC_NOT_IMPL; \
} \
} while(0)
/* Declare wrapper for all SMIO functions API */
#define SMIO_FUNC_WRAPPER(func_name, ...) \
{ \
assert (self); \
assert (self->thsafe_client_ops); \
CHECK_FUNC (self->thsafe_client_ops->func_name); \
return self->thsafe_client_ops->func_name (self, ##__VA_ARGS__); \
}
#define SMIO_FUNC_OPS_NOFAIL_WRAPPER(err, func_name, ...) \
do { \
if (self->ops && self->ops->func_name) { \
smio_err_e local_err = self->ops->func_name (self, ##__VA_ARGS__); \
err = (local_err != SMIO_ERR_FUNC_NOT_IMPL) ? \
local_err : err; \
} \
} while (0)
/************************************************************/
/**************** SMIO Ops wrapper functions ****************/
/************************************************************/
/* Attach an instance of sm_io to dev_io function pointer */
smio_err_e smio_attach (smio_t *self, struct _devio_t *parent)
{
assert (self);
smio_err_e err = SMIO_SUCCESS;
self->parent = parent;
SMIO_FUNC_OPS_NOFAIL_WRAPPER(err, attach, parent);
return err;
}
/* Deattach an instance of sm_io to dev_io function pointer */
smio_err_e smio_deattach (smio_t *self)
{
assert (self);
smio_err_e err = SMIO_SUCCESS;
self->parent = NULL;
SMIO_FUNC_OPS_NOFAIL_WRAPPER(err, deattach);
return SMIO_SUCCESS;
}
/* Export (Register) sm_io to handle specific operations */
smio_err_e smio_export_ops (smio_t *self, const smio_exp_ops_t* smio_exp_ops)
{
assert (self);
assert (smio_exp_ops);
/* FIXME: Dispatch table disp_table_insert_all implements almost the
* same code! Try to reuse it! */
const smio_exp_ops_t* smio_exp_ops_it = smio_exp_ops;
smio_err_e err = SMIO_SUCCESS;
/* FIXME: Iterator is not very good as it has to check an specific field */
for (smio_exp_ops_it = smio_exp_ops; smio_exp_ops_it->func_fp != NULL;
smio_exp_ops_it++) {
halutils_err_e herr = disp_table_insert (self->exp_ops_dtable,
smio_exp_ops_it->opcode, smio_exp_ops_it->func_fp);
if (herr != HALUTILS_SUCCESS) {
err = SMIO_ERR_EXPORT_OP;
goto err_export_op;
}
}
SMIO_FUNC_OPS_NOFAIL_WRAPPER(err, export_ops, smio_exp_ops);
err_export_op:
return err;
}
/* Unexport (unregister) sm_io to handle specific operations */
smio_err_e smio_unexport_ops (smio_t *self)
{
assert (self);
smio_err_e err = SMIO_SUCCESS;
halutils_err_e herr = disp_table_remove_all (self->exp_ops_dtable);
if (herr != HALUTILS_SUCCESS) {
err = SMIO_ERR_EXPORT_OP;
goto err_unexport_op;
}
SMIO_FUNC_OPS_NOFAIL_WRAPPER(err, unexport_ops);
err_unexport_op:
return err;
}
smio_err_e smio_do_op (void *owner, void *msg)
{
assert (owner);
assert (msg);
smio_t *self = (smio_t *) owner;
exp_msg_zmq_t *exp_msg = (exp_msg_zmq_t *) msg;
smio_err_e err = SMIO_SUCCESS;
/* TODO: The SMIO do_op must not modify the packet! We could pass a copy of the
* message to it, but we this is in the critical path! Evaluate the imapct
* of doing this */
SMIO_FUNC_OPS_NOFAIL_WRAPPER(err, do_op, msg);
ASSERT_TEST (err==SMIO_SUCCESS, "Error executing SMIO do_op ()",
err_do_op);
/* Our simple packet is composed of:
* frame 0: operation
* frame n: arguments*/
zframe_t *opcode = zmsg_pop (*exp_msg->msg);
err = (opcode == NULL) ? SMIO_ERR_WRONG_NARGS : SMIO_SUCCESS;
ASSERT_TEST(opcode != NULL, "Could not receive opcode", err_null_opcode);
if (zframe_size (opcode) != EXP_OPS_OPCODE_SIZE) {
DBE_DEBUG (DBG_SM_IO | DBG_LVL_ERR,
"[sm_io] Invalid opcode size received\n");
err = SMIO_ERR_WRONG_NARGS;
goto err_wrong_opcode_size;
}
uint32_t opcode_data = *(uint32_t *) zframe_data (opcode);
if (opcode_data > SMIO_MAX_OPS-1) {
DBE_DEBUG (DBG_SM_IO | DBG_LVL_ERR,
"[sm_io] Invalid opcode received\n");
err = SMIO_ERR_WRONG_NARGS;
goto err_invalid_opcode;
}
/* Do the actual work... */
disp_table_call (self->exp_ops_dtable, opcode_data, self, exp_msg);
err_invalid_opcode:
err_wrong_opcode_size:
zframe_destroy (&opcode);
err_null_opcode:
err_do_op:
/* Should reply_to field be zframe_t ** type ?*/
zframe_destroy (&exp_msg->reply_to);
zmsg_destroy (exp_msg->msg);
return err;
}
/************************************************************/
/************* SMIO thsafe wrapper functions **************/
/************************************************************/
/**** Open device ****/
int smio_thsafe_client_open (smio_t *self, llio_endpoint_t *endpoint)
SMIO_FUNC_WRAPPER (thsafe_client_open, endpoint)
/**** Release device ****/
int smio_thsafe_client_release (smio_t *self, llio_endpoint_t *endpoint)
SMIO_FUNC_WRAPPER (thsafe_client_release, endpoint)
/**** Read data from device ****/
ssize_t smio_thsafe_client_read_16 (smio_t *self, loff_t offs, uint16_t *data)
SMIO_FUNC_WRAPPER (thsafe_client_read_16, offs, data)
ssize_t smio_thsafe_client_read_32 (smio_t *self, loff_t offs, uint32_t *data)
SMIO_FUNC_WRAPPER (thsafe_client_read_32, offs, data)
ssize_t smio_thsafe_client_read_64 (smio_t *self, loff_t offs, uint64_t *data)
SMIO_FUNC_WRAPPER (thsafe_client_read_64, offs, data)
/**** Write data to device ****/
ssize_t smio_thsafe_client_write_16 (smio_t *self, loff_t offs, const uint16_t *data)
SMIO_FUNC_WRAPPER (thsafe_client_write_16, offs, data)
ssize_t smio_thsafe_client_write_32 (smio_t *self, loff_t offs, const uint32_t *data)
SMIO_FUNC_WRAPPER (thsafe_client_write_32, offs, data)
ssize_t smio_thsafe_client_write_64 (smio_t *self, loff_t offs, const uint64_t *data)
SMIO_FUNC_WRAPPER (thsafe_client_write_64, offs, data)
/**** Read data block from device function pointer, size in bytes ****/
ssize_t smio_thsafe_client_read_block (smio_t *self, loff_t offs, size_t size, uint32_t *data)
SMIO_FUNC_WRAPPER (thsafe_client_read_block, offs, size, data)
/**** Write data block from device function pointer, size in bytes ****/
ssize_t smio_thsafe_client_write_block (smio_t *self, loff_t offs, size_t size, const uint32_t *data)
SMIO_FUNC_WRAPPER (thsafe_client_write_block, offs, size, data)
/**** Read data block via DMA from device, size in bytes ****/
ssize_t smio_thsafe_client_read_dma (smio_t *self, loff_t offs, size_t size, uint32_t *data)
SMIO_FUNC_WRAPPER (thsafe_client_read_dma, offs, size, data)
/**** Write data block via DMA from device, size in bytes ****/
ssize_t smio_thsafe_client_write_dma (smio_t *self, loff_t offs, size_t size, const uint32_t *data)
SMIO_FUNC_WRAPPER (thsafe_client_write_dma, offs, size, data)
/**** Read device information function pointer ****/
/* int smio_thsafe_client_read_info (smio_t *self, llio_dev_info_t *dev_info)
SMIO_FUNC_WRAPPER (thsafe_client_read_info, dev_info) Moved to dev_io */
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/sm_io.h 0000664 0000000 0000000 00000023220 12326537641 0022771 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _SM_IO_H_
#define _SM_IO_H_
#include
#include
#include
/* #include "dev_io_core.h" */
#include "ll_io.h"
#include "sm_io_err.h"
#include "exp_msg_zmq.h"
#include "sm_io_bootstrap.h"
#include "sm_io_mod_dispatch.h"
#include "mdp.h"
#include "dispatch_table.h"
/* Arbitrary number*/
#define SMIO_MAX_OPS 200
struct _devio_t;
struct _smio_ops_t;
struct _smio_thsafe_client_ops_t;
struct _smio_exp_ops_t;
/* Main class object that every sm_io must implement */
struct _smio_t {
uint32_t id; /* Unique identifier for this sm_io type. This must be
the same from the SDB ID */
char *name; /* Identification of this sm_io instance */
/* int verbose; */ /* Print activity to stdout */
mdp_worker_t *worker; /* zeroMQ Majordomo worker */
struct _devio_t *parent; /* Pointer back to parent dev_io */
void *smio_handler; /* Generic pointer to a device handler. This
must be cast to a specific type by the
devices functions */
zctx_t *ctx; /* Our context */
void *pipe; /* Pipe back to parent to exchange messages */
/* Specific SMIO operations dispatch table for exported operations */
disp_table_t *exp_ops_dtable;
/* Specific SMIO instance functions. This will be exported on SMIO startup */
const struct _smio_exp_ops_t *exp_ops;
/* Minimum set of methods that every sm_io instance must implement.
* This is thought as the interface to the world */
const struct _smio_ops_t *ops;
/* These operations must be used to access LLIO methods, as they are
* thread safe. The method's signatures are almost the same as the
* ones available in llio, changing the llio_t self pointer to a void
* pointer (socket to parent thread) */
const struct _smio_thsafe_client_ops_t *thsafe_client_ops;
};
/* Attach an instance of sm_io to dev_io function pointer */
typedef enum _smio_err_e (*attach_fp)(struct _smio_t *self, struct _devio_t *parent);
/* Deattach an instance of sm_io to dev_io function pointer */
typedef enum _smio_err_e (*deattach_fp)(struct _smio_t *self);
/* Export (register) sm_io to handle operations function pointer */
typedef enum _smio_err_e (*export_ops_fp)(struct _smio_t *self,
const struct _smio_exp_ops_t* smio_exp_ops);
/* Unexport (unregister) sm_io to handle operations function pointer */
typedef enum _smio_err_e (*unexport_ops_fp)(struct _smio_t *self);
/* Generic wrapper for receiving opcodes and arguments to specific funtions function pointer */
typedef enum _smio_err_e (*do_op_fp)(void *owner, void *msg);
struct _smio_ops_t {
attach_fp attach; /* Attach sm_io instance to dev_io */
deattach_fp deattach; /* Deattach sm_io instance to dev_io */
export_ops_fp export_ops; /* Export sm_io operations to dev_io */
unexport_ops_fp unexport_ops; /* Unexport sm_io operations to dev_io */
do_op_fp do_op; /* Generic wrapper for handling specific operations */
};
/* Open device */
typedef int (*thsafe_client_open_fp) (struct _smio_t *self, llio_endpoint_t *endpoint);
/* Release device */
typedef int (*thsafe_client_release_fp) (struct _smio_t *self, llio_endpoint_t *endpoint);
/* Read data from device */
typedef ssize_t (*thsafe_client_read_16_fp) (struct _smio_t *self, loff_t offs, uint16_t *data);
typedef ssize_t (*thsafe_client_read_32_fp) (struct _smio_t *self, loff_t offs, uint32_t *data);
typedef ssize_t (*thsafe_client_read_64_fp) (struct _smio_t *self, loff_t offs, uint64_t *data);
/* Write data to device */
typedef ssize_t (*thsafe_client_write_16_fp) (struct _smio_t *self, loff_t offs, const uint16_t *data);
typedef ssize_t (*thsafe_client_write_32_fp) (struct _smio_t *self, loff_t offs, const uint32_t *data);
typedef ssize_t (*thsafe_client_write_64_fp) (struct _smio_t *self, loff_t offs, const uint64_t *data);
/* Read data block from device, size in bytes */
typedef ssize_t (*thsafe_client_read_block_fp) (struct _smio_t *self, loff_t offs, size_t size, uint32_t *data);
/* Write data block from device, size in bytes */
typedef ssize_t (*thsafe_client_write_block_fp) (struct _smio_t *self, loff_t offs, size_t size, const uint32_t *data);
/* Read data block via DMA from device, size in bytes */
typedef ssize_t (*thsafe_client_read_dma_fp) (struct _smio_t *self, loff_t offs, size_t size, uint32_t *data);
/* Write data block via DMA from device, size in bytes */
typedef ssize_t (*thsafe_client_write_dma_fp) (struct _smio_t *self, loff_t offs, size_t size, const uint32_t *data);
/* Read device information */
/* typedef int (*thsafe_client_read_info_fp) (struct _smio_t *self, llio_dev_info_t *dev_info); Moved to dev_io */
struct _smio_thsafe_client_ops_t {
thsafe_client_open_fp thsafe_client_open; /* Open device */
thsafe_client_release_fp thsafe_client_release; /* Release device */
thsafe_client_read_16_fp thsafe_client_read_16; /* Read 16-bit data */
thsafe_client_read_32_fp thsafe_client_read_32; /* Read 32-bit data */
thsafe_client_read_64_fp thsafe_client_read_64; /* Read 64-bit data */
thsafe_client_write_16_fp thsafe_client_write_16; /* Write 16-bit data */
thsafe_client_write_32_fp thsafe_client_write_32; /* Write 32-bit data */
thsafe_client_write_64_fp thsafe_client_write_64; /* Write 64-bit data */
thsafe_client_read_block_fp thsafe_client_read_block; /* Read arbitrary block size data,
parameter size in bytes */
thsafe_client_write_block_fp thsafe_client_write_block; /* Write arbitrary block size data,
parameter size in bytes */
thsafe_client_read_dma_fp thsafe_client_read_dma; /* Read arbitrary block size data via DMA,
parameter size in bytes */
thsafe_client_write_dma_fp thsafe_client_write_dma; /* Write arbitrary block size data via DMA,
parameter size in bytes */
/*thsafe_client_read_info_fp thsafe_client_read_info; Moved to dev_io */ /* Read device information data */
};
struct _smio_exp_ops_t {
const char *name;
uint32_t opcode;
disp_table_func_fp func_fp;
};
/* Opaque class structure */
typedef struct _smio_t smio_t;
/* Opaque smio_ops structure */
typedef struct _smio_ops_t smio_ops_t;
/* Opaque llio_th_safe_ops structure */
typedef struct _smio_thsafe_client_ops_t smio_thsafe_client_ops_t;
/* smio exported interface function strcuture */
typedef struct _smio_exp_ops_t smio_exp_ops_t;
/***************** Our methods *****************/
/* Creates a new instance of the Low-level I/O */
/* smio_t * smio_new (uint32_t id, char *name, devio_t *parent); */
/* Destroy an instance of the Low-level I/O */
/* smio_err_e smio_destroy (smio_t **self_p); */
/************************************************************/
/**************** Smio OPS generic methods API **************/
/************************************************************/
/* Attach an instance of sm_io to dev_io function pointer */
smio_err_e smio_attach (smio_t *self, struct _devio_t *parent);
/* Deattach an instance of sm_io to dev_io function pointer */
smio_err_e smio_deattach (smio_t *self);
/* Export (Register) sm_io to handle specific operations */
smio_err_e smio_export_ops (smio_t *self, const smio_exp_ops_t* smio_exp_ops);
/* Unexport (unregister) sm_io to handle specific operations */
smio_err_e smio_unexport_ops (smio_t *self);
/* Handle the operation */
smio_err_e smio_do_op (void *owner, void *msg);
/************************************************************/
/***************** Thsafe generic methods API ***************/
/************************************************************/
/* Open device */
int smio_thsafe_client_open (smio_t *self, llio_endpoint_t *endpoint);
/* Release device */
int smio_thsafe_client_release (smio_t *self, llio_endpoint_t *endpoint);
/* Read data from device */
ssize_t smio_thsafe_client_read_16 (smio_t *self, loff_t offs, uint16_t *data);
ssize_t smio_thsafe_client_read_32 (smio_t *self, loff_t offs, uint32_t *data);
ssize_t smio_thsafe_client_read_64 (smio_t *self, loff_t offs, uint64_t *data);
/* Write data to device */
ssize_t smio_thsafe_client_write_16 (smio_t *self, loff_t offs, const uint16_t *data);
ssize_t smio_thsafe_client_write_32 (smio_t *self, loff_t offs, const uint32_t *data);
ssize_t smio_thsafe_client_write_64 (smio_t *self, loff_t offs, const uint64_t *data);
/* Read data block from device, size in bytes */
ssize_t smio_thsafe_client_read_block (smio_t *self, loff_t offs, size_t size, uint32_t *data);
/* Write data block from device, size in bytes */
ssize_t smio_thsafe_client_write_block (smio_t *self, loff_t offs, size_t size, const uint32_t *data);
/* Read data block via DMA from device, size in bytes */
ssize_t smio_thsafe_client_read_dma (smio_t *self, loff_t offs, size_t size, uint32_t *data);
/* Write data block via DMA from device, size in bytes */
ssize_t smio_thsafe_client_write_dma (smio_t *self, loff_t offs, size_t size, const uint32_t *data);
/* Read device information */
/* int smio_thsafe_client_read_info (smio_t *self, llio_dev_info_t *dev_info) */
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/sm_io.mk 0000664 0000000 0000000 00000000471 12326537641 0023154 0 ustar 00root root 0000000 0000000 include hal/sm_io/modules/modules.mk
sm_io_DIR = hal/sm_io
sm_io_OBJS = $(sm_io_DIR)/sm_io.o \
$(sm_io_DIR)/sm_io_bootstrap.o \
$(sm_io_DIR)/sm_io_err.o \
$(sm_io_DIR)/sm_io_thsafe_codes.o \
$(sm_io_modules_OBJS)
sm_io_INCLUDE_DIRS = $(sm_io_DIR) \
$(sm_io_modules_INCLUDE_DIRS)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/sm_io_bootstrap.c 0000664 0000000 0000000 00000020650 12326537641 0025065 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
#include "sm_io_bootstrap.h"
#include "sm_io.h"
#include "exp_ops_codes.h"
#include "hal_assert.h"
/* Undef ASSERT_ALLOC to avoid conflicting with other ASSERT_ALLOC */
#ifdef ASSERT_TEST
#undef ASSERT_TEST
#endif
#define ASSERT_TEST(test_boolean, err_str, err_goto_label) \
ASSERT_HAL_TEST(test_boolean, SM_IO, "[sm_io_bootstrap]", \
err_str, err_goto_label)
#ifdef ASSERT_ALLOC
#undef ASSERT_ALLOC
#endif
#define ASSERT_ALLOC(ptr, err_goto_label) \
ASSERT_HAL_ALLOC(ptr, SM_IO, "[sm_io_bootstrap]", \
smio_err_str(SMIO_ERR_ALLOC), \
err_goto_label)
#ifdef CHECK_ERR
#undef CHECK_ERR
#endif
#define CHECK_ERR(err, err_type) \
CHECK_HAL_ERR(err, SM_IO, "[sm_io_bootstrap]", \
smio_err_str (err_type))
#define SMIO_FUNC_OPS_NOFAIL_WRAPPER(err, func_name, ...) \
do { \
if (self->ops && self->ops->func_name) { \
smio_err_e local_err = self->ops->func_name (self, ##__VA_ARGS__); \
err = (local_err != SMIO_ERR_FUNC_NOT_IMPL) ? \
local_err : err; \
} \
} while (0)
#define SMIO_DISPATCH_FUNC_WRAPPER(func_name, ...) \
do { \
if (smio_mod_dispatch[th_args->smio_id].bootstrap_ops && \
smio_mod_dispatch[th_args->smio_id].bootstrap_ops->func_name) { \
smio_mod_dispatch[th_args->smio_id].bootstrap_ops->func_name (self, ##__VA_ARGS__); \
} \
} while (0)
#define SMIO_POLLER_TIMEOUT 100 /* in msec */
/* ':'. We have parent :. So, we need 1
* more byte allocated */
#define EXTRA_SMIO_SERV_BYTES 1
static struct _smio_t *_smio_new (struct _devio_t *parent, struct _zctx_t *ctx,
void *pipe, char *broker, char *service, int verbose);
static smio_err_e _smio_destroy (struct _smio_t **self_p);
static smio_err_e _smio_loop (smio_t *self);
/************************************************************/
/****************** SMIO Thread entry-point ****************/
/************************************************************/
/* FIXME: Do some sanity check before calling functions from smio_mod_dispatch*/
void smio_startup (void *args, zctx_t *ctx, void *pipe)
{
/* FIXME: priv pointer is unused for now! We should use it to differentiate
* between multiple smio instances of the same type controlling multiple
* modules of the same type. Otherwise, we would ended up with two workers
* for the same thing (see Majordomo protocol) */
th_boot_args_t *th_args = (th_boot_args_t *) args;
/* Initialize serice name concatenating the received name with
* the smio service name */
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "[sm_io_bootstrap] Thread starting\n");
/* We must export our service as the combination of the
* devio name (coming from devio parent) and our own name ID
* followed by an optional parameter coming from priv pointer */
char *smio_service = zmalloc (strlen(th_args->service)+
strlen(smio_mod_dispatch[th_args->smio_id].name)+
EXTRA_SMIO_SERV_BYTES+1);
ASSERT_ALLOC(smio_service, err_smio_service_alloc);
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "[sm_io_bootstrap] Thread allocating resources\n");
sprintf (smio_service, "%s:%s", th_args->service, smio_mod_dispatch[th_args->smio_id].name);
smio_t *self = _smio_new (th_args->parent, ctx, pipe, th_args->broker,
smio_service, th_args->verbose);
ASSERT_ALLOC(self, err_self_alloc);
/* We don't need this anymore */
free (smio_service);
smio_service = NULL;
/* Call SMIO init function to finish initializing its internal strucutres */
SMIO_DISPATCH_FUNC_WRAPPER (init);
/* Atach this SMIO instance to its parent */
smio_attach (self, th_args->parent);
/* Export SMIO specific operations */
smio_err_e err = smio_export_ops (self, self->exp_ops);
ASSERT_TEST (err == SMIO_SUCCESS, "Could not export specific SMIO operations",
err_smio_export);
/* Main loop request-action */
_smio_loop (self);
/* Unexport SMIO specific operations */
smio_unexport_ops (self);
/* Deattach this SMIO instance to its parent */
smio_deattach (self);
/* FIXME: Poll PIPE sockets and on receiving any message calls shutdown () */
SMIO_DISPATCH_FUNC_WRAPPER (shutdown);
err_smio_export:
/* FIXME: check for return error */
/* Destroy what we did in _smio_new */
_smio_destroy (&self);
err_self_alloc:
free (smio_service);
err_smio_service_alloc:
DBE_DEBUG (DBG_SM_IO | DBG_LVL_ERR, "[sm_io_bootstrap] Thread exiting\n");
free (args);
return;
}
/************************************************************/
/************ SMIO Bootstrap wrapper functions **************/
/************************************************************/
struct _smio_t *smio_new (struct _devio_t *parent, struct _zctx_t *ctx, void *pipe,
char *broker, char *service, int verbose)
{
return _smio_new (parent, ctx, pipe, broker, service, verbose);
}
smio_err_e smio_destroy (struct _smio_t **self_p)
{
return _smio_destroy (self_p);
}
smio_err_e smio_loop (struct _smio_t *self)
{
return _smio_loop (self);
}
/************************************************************/
/****************** Local helper functions ******************/
/************************************************************/
/* Boot new sm_io instance of fmc130m_4ch */
static struct _smio_t *_smio_new (struct _devio_t *parent, struct _zctx_t *ctx, void *pipe,
char *broker, char *service, int verbose)
{
(void) parent;
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "[sm_io_bootstrap] Initializing SMIO\n");
smio_t *self = (smio_t *) zmalloc (sizeof *self);
ASSERT_ALLOC(self, err_self_alloc);
/* Setup Dispatch table */
self->exp_ops_dtable = disp_table_new ();
ASSERT_ALLOC(self->exp_ops_dtable, err_exp_ops_dtable_alloc);
self->smio_handler = NULL; /* This is set by the device functions */
self->ctx = ctx;
self->pipe = pipe;
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "[sm_io_bootstrap] Creating worker\n");
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "\tbroker = %s, service = %s, verbose = %d\n",
broker, service, verbose);
self->worker = mdp_worker_new (self->ctx, broker, service, verbose);
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "[sm_io_bootstrap] Worker created\n");
ASSERT_ALLOC(self->worker, err_worker_alloc);
return self;
err_worker_alloc:
disp_table_destroy (&self->exp_ops_dtable);
err_exp_ops_dtable_alloc:
free (self);
err_self_alloc:
return NULL;
}
static smio_err_e _smio_destroy (struct _smio_t **self_p)
{
assert (self_p);
if (*self_p) {
struct _smio_t *self = *self_p;
mdp_worker_destroy (&self->worker);
disp_table_destroy (&self->exp_ops_dtable);
self->thsafe_client_ops = NULL;
self->ops = NULL;
self->parent = NULL;
free (self);
*self_p = NULL;
}
return SMIO_SUCCESS;
}
/* FIXME: Poll on PIPE socket as well and in case of any arriving message
* destroy itself */
static smio_err_e _smio_loop (smio_t *self)
{
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE,
"[sm_io_bootstrap] Main loop starting\n");
smio_err_e err = SMIO_SUCCESS;
/* Begin infinite polling on Majordomo socket
* and exit if the parent send a message through
* the pipe socket */
while (!zctx_interrupted) {
zframe_t *reply_to = NULL;
zmsg_t *request = mdp_worker_recv (self->worker, &reply_to);
if (request == NULL)
break; /* Worker has been interrupted */
exp_msg_zmq_t smio_args = {.msg = &request, .reply_to = reply_to};
err = smio_do_op (self, &smio_args);
/* What can I do in case of error ?*/
if (err != SMIO_SUCCESS) {
DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE,
"[sm_io_bootstrap] smio_do_op: %s\n",
smio_err_str (err));
}
}
return err;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/sm_io_bootstrap.h 0000664 0000000 0000000 00000004130 12326537641 0025065 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _SM_IO_BOOTSTRAP_H_
#define _SM_IO_BOOTSTRAP_H_
#include
/* #include "sm_io.h" */
/* #include "dev_io.h" */
#include "sm_io_err.h"
#include "czmq.h"
/* Foward declarations. We don't need to include the associated header files.
* The following should suffice */
struct _smio_t;
struct _devio_t;
/* Create instance of sm_io function pointer. This tells how to create
* such an object */
typedef smio_err_e (*smio_init_fp)(struct _smio_t *self);
/* Destroy instance of sm)io functuion pointer. This tells how to destroy
* such an object */
typedef smio_err_e (*smio_shutdown_fp)(struct _smio_t *self);
/* Main class object that every sm_io must implement */
struct _smio_bootstrap_ops_t {
smio_init_fp init;
smio_shutdown_fp shutdown;
};
typedef struct _smio_bootstrap_ops_t smio_bootstrap_ops_t;
/* Thread boot args structure */
struct _th_boot_args_t {
struct _devio_t *parent; /* Pointer back to devo parent */
uint32_t smio_id; /* ID of the SMIO instance */
char *broker; /* Endpoint to connect to broker */
char *service; /* (part of) the service name to be exported */
int verbose; /* Print trace information to stdout*/
void *priv; /* Pointer to a private strucutre to be passed
untouched by devio to the specific smio instace*/
};
typedef struct _th_boot_args_t th_boot_args_t;
/************************************************************/
/************************ Our methods ***********************/
/************************************************************/
void smio_startup (void *args, zctx_t *ctx, void *pipe);
struct _smio_t *smio_new (struct _devio_t *parent, struct _zctx_t *ctx, void *pipe,
char *broker, char *service, int verbose);
smio_err_e smio_destroy (struct _smio_t **self_p);
smio_err_e smio_loop (struct _smio_t *self);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/sm_io_err.c 0000664 0000000 0000000 00000001757 12326537641 0023647 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#include "sm_io_err.h"
static const char *smio_err [SMIO_ERR_END] =
{
[SMIO_SUCCESS] = "Success",
[SMIO_ERR_ALLOC] = "Could not allocate memory",
[SMIO_ERR_FUNC_NOT_IMPL] = "Function not implemented",
[SMIO_ERR_OPCODE_NOT_SUPP] = "Opcode not supported",
[SMIO_ERR_WRONG_NARGS] = "Wrong number of arguments",
[SMIO_ERR_WRONG_PARAM] = "Wrong parameter value",
[SMIO_ERR_LLIO] = "Low-level I/O could not complete operation",
[SMIO_ERR_EXPORT_OP] = "Could not export function"
};
/* Convert enumeration type to string */
const char * smio_err_str (smio_err_e err)
{
return smio_err [err];
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/sm_io_err.h 0000664 0000000 0000000 00000002134 12326537641 0023642 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
/* Error definitions and output stringification based on the work available
* at the libsllp project repository: https://github.com/brunoseivam/libsllp */
#ifndef _SMIO_ERR_H_
#define _SMIO_ERR_H_
enum _smio_err_e
{
SMIO_SUCCESS = 0, /* No error */
SMIO_ERR_ALLOC, /* Could not allocate memory */
SMIO_ERR_FUNC_NOT_IMPL, /* Function not implemented */
SMIO_ERR_OPCODE_NOT_SUPP, /* Opcode not supported */
SMIO_ERR_WRONG_NARGS, /* Wrong number of arguments */
SMIO_ERR_WRONG_PARAM, /* Wrong parameter value */
SMIO_ERR_LLIO, /* Low-level I/O could not complete operation */
SMIO_ERR_EXPORT_OP, /* Error exporting function */
SMIO_ERR_END /* End of enum marker */
};
typedef enum _smio_err_e smio_err_e;
/* Convert enumeration type to string */
const char * smio_err_str (smio_err_e err);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/sm_io_thsafe_codes.c 0000664 0000000 0000000 00000001327 12326537641 0025477 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#include
const uint32_t thsafe_opcodes [THSAFE_OPCODE_END] = {
[0] = THSAFE_OPEN,
[1] = THSAFE_RELEASE,
[2] = THSAFE_READ_16,
[3] = THSAFE_READ_32,
[4] = THSAFE_READ_64,
[5] = THSAFE_WRITE_16,
[6] = THSAFE_WRITE_32,
[7] = THSAFE_WRITE_64,
[8] = THSAFE_READ_BLOCK,
[9] = THSAFE_WRITE_BLOCK,
[10] = THSAFE_READ_DMA,
[11] = THSAFE_WRITE_DMA
// [12] = THSAFE_READ_INFO
};
const uint32_t thsafe_reply_opcodes [THSAFE_REPLY_END] = {
[0] = THSAFE_OK,
[1] = THSAFE_ERR
};
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/hal/sm_io/sm_io_thsafe_codes.h 0000664 0000000 0000000 00000003440 12326537641 0025502 0 ustar 00root root 0000000 0000000 /*
* Copyright (C) 2014 LNLS (www.lnls.br)
* Author: Lucas Russo
*
* Released according to the GNU LGPL, version 3 or any later version.
*/
#ifndef _SM_IO_THSAFE_CODES_H_
#define _SM_IO_THSAFE_CODES_H_
#include
/* Messaging OPCODES */
#define THSAFE_OPCODE_SIZE (sizeof (uint32_t))
#define THSAFE_READ_16_DSIZE (sizeof (uint16_t))
#define THSAFE_READ_32_DSIZE (sizeof (uint32_t))
#define THSAFE_READ_64_DSIZE (sizeof (uint64_t))
#define THSAFE_WRITE_16_DSIZE THSAFE_READ_16_DSIZE
#define THSAFE_WRITE_32_DSIZE THSAFE_READ_32_DSIZE
#define THSAFE_WRITE_64_DSIZE THSAFE_READ_64_DSIZE
#define THSAFE_OPCODE_TYPE uint32_t
#define THSAFE_OPEN 0
#define THSAFE_RELEASE 1
#define THSAFE_READ_16 2
#define THSAFE_READ_32 3
#define THSAFE_READ_64 4
#define THSAFE_WRITE_16 5
#define THSAFE_WRITE_32 6
#define THSAFE_WRITE_64 7
#define THSAFE_READ_BLOCK 8
#define THSAFE_WRITE_BLOCK 9
#define THSAFE_READ_DMA 10
#define THSAFE_WRITE_DMA 11
//#define THSAFE_READ_INFO 12
#define THSAFE_OPCODE_END 12
//#define THSAFE_OPCODE_END 13
extern const THSAFE_OPCODE_TYPE thsafe_opcodes [THSAFE_OPCODE_END];
/* Messaging Reply OPCODES */
#define THSAFE_REPLY_SIZE (sizeof(uint32_t))
#define THSAFE_REPLY_TYPE uint32_t
#define THSAFE_OK 0
#define THSAFE_ERR 1
#define THSAFE_REPLY_END 2
extern const THSAFE_REPLY_TYPE thsafe_reply_opcodes [THSAFE_REPLY_END];
/* Messaging Return Codes */
#define THSAFE_RETURN_SIZE (sizeof(int32_t))
#define THSAFE_RETURN_TYPE int32_t
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/init.sh 0000775 0000000 0000000 00000000770 12326537641 0021147 0 ustar 00root root 0000000 0000000 #!/bin/bash
# Broker Endpoint
EXPECTED_ARGS=1
if [ "$(id -u)" != "0" ]
then
echo "This must be run as root"
exit 1
fi
if [ $# -ne $EXPECTED_ARGS ]
then
echo "Error: Broker endpoint not set!"
echo "Usage: `basename $0` {broker endpoint}"
exit 1;
fi
broker_endp=$1
# Launch Device Manager
./dev_mngr -v -b "ipc://"$broker_endp &
# Signal dev_mngr of a "new" PCIe device
killall -SIGUSR1 dev_mngr
# FIXME:Wait until worker has been created
sleep 1
# Change IPC permissions
chmod 777 $broker_endp
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/ 0000775 0000000 0000000 00000000000 12326537641 0021121 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/Makefile 0000664 0000000 0000000 00000001517 12326537641 0022565 0 ustar 00root root 0000000 0000000 # Set your cross compile prefix with CROSS_COMPILE variable
CROSS_COMPILE ?=
CMDSEP = ;
CC = $(CROSS_COMPILE)gcc
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
MAKE = make
DRIVER_DIR = drivers/pcie
LIB_DIR = lib/pcie
all: kernel_driver lib_driver
.PHONY: kernel_driver lib_driver install uninstall clean
kernel_driver:
$(MAKE) -C $(DRIVER_DIR) all
# $(MAKE) -C $(DRIVER_DIR) install
lib_driver:
$(MAKE) -C $(LIB_DIR) all
# $(MAKE) -C $(LIB_DIR) install
clean:
$(MAKE) -C $(DRIVER_DIR) clean
$(MAKE) -C $(LIB_DIR) clean
install:
$(MAKE) -C $(DRIVER_DIR) install
$(MAKE) -C $(LIB_DIR) install
uninstall:
$(MAKE) -C $(DRIVER_DIR) uninstall
$(MAKE) -C $(LIB_DIR) uninstall
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/README 0000664 0000000 0000000 00000001644 12326537641 0022006 0 ustar 00root root 0000000 0000000 ==========================================================
Folder containing all of the Beam Position Monitor software.
==========================================================
1. PCIE driver for FPGA device
1.1. Overview
This driver is based on original driver for the PCIe SG DMA project
placed at the opencores.org
As of now, the changes are mostly reworked Makefiles to fit into the
directory structure at the OHWR repo; also, with present makefiles
it's easier to cross-compile code (e.g. using buildroot).
It consists of two parts:
- kernel driver at driver/pcie
- c/c++ library at lib/pcie
All relevant includes are in include/pcie folder.
1.2. INSTALL
To compile and install kernel driver go to driver/pcie and issue 'make && make install'
To install library go to lib/pcie and type 'make && make install'
1.3. TODO
- review and commit original test units
- port to PowerPC
- any changes that will be required
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/ 0000775 0000000 0000000 00000000000 12326537641 0022577 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/ 0000775 0000000 0000000 00000000000 12326537641 0023517 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/Makefile 0000775 0000000 0000000 00000001050 12326537641 0025156 0 ustar 00root root 0000000 0000000
# Main Makefile for the pciDriver
#helpful in case of buildroot crosscompiling
ROOTDIR :=
CURDIR := $(shell pwd)
export SRCDIR := $(CURDIR)/src
all:
$(Q)$(MAKE) -C $(SRCDIR)
install:
$(Q)$(MAKE) -C $(SRCDIR) install
@echo "INSTALL 60-udev_fpga.rules"
-$(Q)install -m 644 etc/udev/rules.d/60-udev_fpga.rules $(ROOTDIR)/etc/udev/rules.d/
uninstall:
$(Q)$(MAKE) -C $(SRCDIR) uninstall
@echo "UNINSTALL 60-udev_fpga.rules"
-$(Q)rm -f $(ROOTDIR)/etc/udev/rules.d/60-udev_fpga.rules
clean:
@echo "Cleaning..."
-$(Q)$(MAKE) -C $(SRCDIR) clean
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/make_with_buildroot.sh 0000775 0000000 0000000 00000001047 12326537641 0030113 0 ustar 00root root 0000000 0000000 #!/bin/bash
#add relevant overrides to make use of buildroot toolchain
BUILDROOT_DIR="/home/adrian/praca/buildroot/buildroot"
KERNELDIR="$BUILDROOT_DIR/output/build/linux-3.6.8"
INSTALLDIR="$BUILDROOT_DIR/output/target"
export ARCH=x86_64
export CROSS_COMPILE=x86_64-linux-
export PATH="$PATH:$BUILDROOT_DIR/output/host/usr/bin"
EXTRA_CFLAGS="-D VERBOSE"
cd src && make KERNELDIR=$KERNELDIR
cd ..
echo "Copying to $INSTALLDIR"
cp src/pciDriver.ko $INSTALLDIR/opt/
cp etc/udev/rules.d/60-udev_fpga.rules $INSTALLDIR/etc/udev/rules.d/
echo "DONE"
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/ 0000775 0000000 0000000 00000000000 12326537641 0024306 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/.gitignore 0000775 0000000 0000000 00000000220 12326537641 0026273 0 ustar 00root root 0000000 0000000 #makefile symbolic link
pciDriver.h
#editor backup files
*~
#Kbuild files
*.o
*.ko
*.mod.c
Module.symvers
modules.order
.tmp_versions/
.*.cmd
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/Makefile 0000775 0000000 0000000 00000001563 12326537641 0025756 0 ustar 00root root 0000000 0000000
obj-m := pciDriver.o
pciDriver-objs := base.o int.o umem.o kmem.o sysfs.o ioctl.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
INSTALLDIR ?= /lib/modules/$(shell uname -r)/extra
INSTALLHDRDIR ?= /usr/include/pciDriver/driver
PWD := $(shell pwd)
default: dolink
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
dolink:
@ln -sf ../../../include/pcie/driver/pciDriver.h
install:
@mkdir -p $(INSTALLDIR)
@echo "INSTALL $(INSTALLDIR)/pciDriver.ko"
@install -m 755 pciDriver.ko $(INSTALLDIR)
@echo "INSTALL $(INSTALLHDRDIR)/pciDriver.h"
@mkdir -p $(INSTALLHDRDIR)
@install -m 644 pciDriver.h $(INSTALLHDRDIR)
uninstall:
@echo "UNINSTALL $(INSTALLDIR)/pciDriver.ko"
@rm -f $(INSTALLDIR)/pciDriver.ko
@echo "UNINSTALL $(INSTALLHDRDIR)/pciDriver.h"
@rm -rf /usr/include/pciDriver/driver
clean:
rm -f *.o *.ko *.mod.c .*.cmd Module.symvers modules.order
rm -rf .tmp_versions
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/base.c 0000775 0000000 0000000 00000043457 12326537641 0025404 0 ustar 00root root 0000000 0000000 /**
*
* @file base.c
* @author Guillermo Marcus
* @date 2009-04-05
* @brief Contains the main code which connects all the different parts and does
* basic driver tasks like initialization.
*
* This is a full rewrite of the pciDriver.
* New default is to support kernel 2.6, using kernel 2.6 APIs.
*
*/
/*
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.13 2008-05-30 11:38:15 marcus
* Added patches for kernel 2.6.24
*
* Revision 1.12 2008-01-24 14:21:36 marcus
* Added a CLEAR_INTERRUPT_QUEUE ioctl.
* Added a sysfs attribute to show the outstanding IRQ queues.
*
* Revision 1.11 2008-01-24 12:53:11 marcus
* Corrected wait_event condition in waiti_ioctl. Improved the loop too.
*
* Revision 1.10 2008-01-14 10:39:39 marcus
* Set some messages as debug instead of normal.
*
* Revision 1.9 2008-01-11 10:18:28 marcus
* Modified interrupt mechanism. Added atomic functions and queues, to address race conditions. Removed unused interrupt code.
*
* Revision 1.8 2007-07-17 13:15:55 marcus
* Removed Tasklets.
* Using newest map for the ABB interrupts.
*
* Revision 1.7 2007-07-06 15:56:04 marcus
* Change default status for OLD_REGISTERS to not defined.
*
* Revision 1.6 2007-07-05 15:29:59 marcus
* Corrected issue with the bar mapping for interrupt handling.
* Added support up to kernel 2.6.20
*
* Revision 1.5 2007-05-29 07:50:18 marcus
* Split code into 2 files. May get merged in the future again....
*
* Revision 1.4 2007/03/01 17:47:34 marcus
* Fixed bug when the kernel memory was less than one page, it was not locked properly, recalling an old mapping issue in this case.
*
* Revision 1.3 2007/03/01 17:01:22 marcus
* comment fix (again).
*
* Revision 1.2 2007/03/01 17:00:25 marcus
* Changed some comment in the log.
*
* Revision 1.1 2007/03/01 16:57:43 marcus
* Divided driver file to ease the interrupt hooks for the user of the driver.
* Modified Makefile accordingly.
*
* From pciDriver.c:
* Revision 1.11 2006/12/11 16:15:43 marcus
* Fixed kernel buffer mmapping, and driver crash when application crashes.
* Buffer memory is now marked reserved during allocation, and mmaped with
* remap_xx_range.
*
* Revision 1.10 2006/11/21 09:50:49 marcus
* Added PROGRAPE4 vendor/device IDs.
*
* Revision 1.9 2006/11/17 18:47:36 marcus
* Removed MERGE_SGENTRIES flag, now it is selected at runtime with 'type'.
* Removed noncached in non-prefetchable areas, to allow the use of MTRRs.
*
* Revision 1.8 2006/11/17 16:41:21 marcus
* Added slot number to the PCI info IOctl.
*
* Revision 1.7 2006/11/13 12:30:34 marcus
* Added a IOctl call, to confiure the interrupt response. (testing pending).
* Basic interrupts are now supported, using a Tasklet and Completions.
*
* Revision 1.6 2006/11/08 21:30:02 marcus
* Added changes after compile tests in kernel 2.6.16
*
* Revision 1.5 2006/10/31 07:57:38 marcus
* Improved the pfn calculation in nopage(), to deal with some possible border
* conditions. It was really no issue, because they are normally page-aligned
* anyway, but to be on the safe side.
*
* Revision 1.4 2006/10/30 19:37:40 marcus
* Solved bug on kernel memory not mapping properly.
*
* Revision 1.3 2006/10/18 11:19:20 marcus
* Added kernel 2.6.8 support based on comments from Joern Adamczewski (GSI).
*
* Revision 1.2 2006/10/18 11:04:15 marcus
* Bus Master is only activated when we detect a specific board.
*
* Revision 1.1 2006/10/10 14:46:51 marcus
* Initial commit of the new pciDriver for kernel 2.6
*
* Revision 1.9 2006/10/05 11:30:46 marcus
* Prerelease. Added bus and devfn to pciInfo for compatibility.
*
* Revision 1.8 2006/09/25 16:51:07 marcus
* Added PCI config IOctls, and implemented basic mmap functions.
*
* Revision 1.7 2006/09/20 11:12:41 marcus
* Added Merge SG entries
*
* Revision 1.6 2006/09/19 17:22:18 marcus
* backup commit.
*
* Revision 1.5 2006/09/18 17:13:11 marcus
* backup commit.
*
* Revision 1.4 2006/09/15 15:44:41 marcus
* backup commit.
*
* Revision 1.3 2006/08/15 11:40:02 marcus
* backup commit.
*
* Revision 1.2 2006/08/12 18:28:42 marcus
* Sync with the laptop
*
* Revision 1.1 2006/08/11 15:30:46 marcus
* Sync with the laptop
*
*/
#include
/* Check macros and kernel version first */
#ifndef KERNEL_VERSION
#error "No KERNEL_VERSION macro! Stopping."
#endif
#ifndef LINUX_VERSION_CODE
#error "No LINUX_VERSION_CODE macro! Stopping."
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
#error "This driver has been tested only for Kernel 2.6.8 or above."
#endif
/* Required includes */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* Configuration for the driver (what should be compiled in, module name, etc...) */
#include "config.h"
/* Compatibility functions/definitions (provides functions which are not available on older kernels) */
#include "compat.h"
/* External interface for the driver */
#include "pciDriver.h"
/* Internal definitions for all parts (prototypes, data, macros) */
#include "common.h"
/* Internal definitions for the base part */
#include "base.h"
/* Internal definitions of the IRQ handling part */
#include "int.h"
/* Internal definitions for kernel memory */
#include "kmem.h"
/* Internal definitions for user space memory */
#include "umem.h"
#include "ioctl.h"
/*************************************************************************/
/* Module device table associated with this driver */
MODULE_DEVICE_TABLE(pci, pcidriver_ids);
/* Module init and exit points */
module_init(pcidriver_init);
module_exit(pcidriver_exit);
/* Module info */
MODULE_AUTHOR("Adrian Byszuk");
MODULE_DESCRIPTION("BPM PCIe board driver");
MODULE_LICENSE("GPL v2");
/* Module class */
static struct class_compat *pcidriver_class;
/**
*
* Called when loading the driver
*
*/
static int __init pcidriver_init(void)
{
int err;
/* Initialize the device count */
atomic_set(&pcidriver_deviceCount, 0);
/* Allocate character device region dynamically */
if ((err = alloc_chrdev_region(&pcidriver_devt, MINORNR, MAXDEVICES, NODENAME)) != 0) {
mod_info("Couldn't allocate chrdev region. Module not loaded.\n");
goto init_alloc_fail;
}
mod_info("Major %d allocated to nodename '%s'\n", MAJOR(pcidriver_devt), NODENAME);
/* Register driver class */
pcidriver_class = class_create(THIS_MODULE, NODENAME);
if (IS_ERR(pcidriver_class)) {
mod_info("No sysfs support. Module not loaded.\n");
goto init_class_fail;
}
/* Register PCI driver. This function returns the number of devices on some
* systems, therefore check for errors as < 0. */
if ((err = pci_register_driver(&pcidriver_driver)) < 0) {
mod_info("Couldn't register PCI driver. Module not loaded.\n");
goto init_pcireg_fail;
}
mod_info("Module loaded\n");
return 0;
init_pcireg_fail:
class_destroy(pcidriver_class);
init_class_fail:
unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
init_alloc_fail:
return err;
}
/**
*
* Called when unloading the driver
*
*/
static void __exit pcidriver_exit(void)
{
pci_unregister_driver(&pcidriver_driver);
unregister_chrdev_region(pcidriver_devt, MAXDEVICES);
if (pcidriver_class != NULL)
class_destroy(pcidriver_class);
mod_info("Module unloaded\n");
}
/*************************************************************************/
/* Driver functions */
/**
*
* This struct defines the PCI entry points.
* Will be registered at module init.
*
*/
static struct pci_driver pcidriver_driver = {
.name = MODNAME,
.id_table = pcidriver_ids,
.probe = pcidriver_probe,
.remove = pcidriver_remove,
};
/**
*
* This function is called when installing the driver for a device
* @param pdev Pointer to the PCI device
*
*/
static int pcidriver_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int err;
int devno;
pcidriver_privdata_t *privdata;
int devid;
/* At the moment there is no difference between these boards here, other than
* printing a different message in the log.
*
* However, there is some difference in the interrupt handling functions.
*/
if ( (id->vendor == PCIE_XILINX_VENDOR_ID) &&
(id->device == PCIE_KC705_DEV_ID))
{
mod_info( "Found KC705 at %s\n", dev_name(&pdev->dev));
}
else if ((id->vendor == PCIE_XILINX_VENDOR_ID) &&
(id->device == PCIE_ML605_DEVICE_ID))
{
/* It is a PCI-E Xilinx ML605 evaluation board */
mod_info("Found ML605 board at %s\n", dev_name(&pdev->dev));
}
else if ((id->vendor == PCIE_XILINX_VENDOR_ID) &&
(id->device == PCIE_AMC_DEV_ID))
{
/* It is a PCI-E Creotech uTCA AMC board */
mod_info("Found uTCA AMC board at %s\n", dev_name(&pdev->dev));
}
else
{
/* It is something else */
mod_info( "Found unknown board (%x:%x) at %s\n", id->vendor, id->device, dev_name(&pdev->dev));
}
/* Enable the device */
if ((err = pci_enable_device(pdev)) != 0) {
mod_info("Couldn't enable device\n");
goto probe_pcien_fail;
}
/* Set bus master */
pci_set_master(pdev);
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
if (err) {
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
}
if (err) {
dev_err(&pdev->dev, "No suitable DMA available");
goto probe_disable_device;
}
/* Get / Increment the device id */
devid = atomic_inc_return(&pcidriver_deviceCount) - 1;
if (devid >= MAXDEVICES) {
mod_info("Maximum number of devices reached! Increase MAXDEVICES.\n");
err = -ENOMSG;
goto probe_disable_device;
}
/* Allocate and initialize the private data for this device */
if ((privdata = kcalloc(1, sizeof(*privdata), GFP_KERNEL)) == NULL) {
err = -ENOMEM;
goto probe_nomem;
}
INIT_LIST_HEAD(&(privdata->kmem_list));
spin_lock_init(&(privdata->kmemlist_lock));
atomic_set(&privdata->kmem_count, 0);
INIT_LIST_HEAD(&(privdata->umem_list));
spin_lock_init(&(privdata->umemlist_lock));
atomic_set(&privdata->umem_count, 0);
pci_set_drvdata( pdev, privdata );
privdata->pdev = pdev;
/* Device add to sysfs */
devno = MKDEV(MAJOR(pcidriver_devt), MINOR(pcidriver_devt) + devid);
privdata->devno = devno;
if (pcidriver_class != NULL) {
/* FIXME: some error checking missing here */
privdata->class_dev = class_device_create(pcidriver_class, NULL, devno, &(pdev->dev), NODENAMEFMT, MINOR(pcidriver_devt) + devid, privdata);
class_set_devdata( privdata->class_dev, privdata );
mod_info("Device /dev/%s%d added\n",NODENAME,MINOR(pcidriver_devt) + devid);
}
/* Setup mmaped BARs into kernel space */
if ((err = pcidriver_probe_irq(privdata)) != 0)
goto probe_irq_probe_fail;
/* Populate sysfs attributes for the class device */
/* TODO: correct errorhandling. ewww. must remove the files in reversed order :-( */
#define sysfs_attr(name) do { \
if (class_device_create_file(sysfs_attr_def_pointer, &sysfs_attr_def_name(name)) != 0) \
goto probe_device_create_fail; \
} while (0)
#ifdef ENABLE_IRQ
sysfs_attr(irq_count);
sysfs_attr(irq_queues);
#endif
sysfs_attr(mmap_mode);
sysfs_attr(mmap_area);
sysfs_attr(kmem_count);
sysfs_attr(kmem_alloc);
sysfs_attr(kmem_free);
sysfs_attr(kbuffers);
sysfs_attr(umappings);
sysfs_attr(umem_unmap);
#undef sysfs_attr
/* Register character device */
cdev_init( &(privdata->cdev), &pcidriver_fops );
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35)
privdata->cdev.owner = THIS_MODULE;
#endif
privdata->cdev.ops = &pcidriver_fops;
err = cdev_add( &privdata->cdev, devno, 1 );
if (err) {
mod_info( "Couldn't add character device.\n" );
goto probe_cdevadd_fail;
}
return 0;
probe_device_create_fail:
probe_cdevadd_fail:
probe_irq_probe_fail:
pcidriver_irq_unmap_bars(privdata);
kfree(privdata);
probe_nomem:
atomic_dec(&pcidriver_deviceCount);
probe_disable_device:
pci_disable_device(pdev);
probe_pcien_fail:
return err;
}
/**
*
* This function is called when disconnecting a device
*
*/
static void pcidriver_remove(struct pci_dev *pdev)
{
pcidriver_privdata_t *privdata;
/* Get private data from the device */
privdata = pci_get_drvdata(pdev);
/* Removing sysfs attributes from class device */
#define sysfs_attr(name) do { \
class_device_remove_file(sysfs_attr_def_pointer, &sysfs_attr_def_name(name)); \
} while (0)
#ifdef ENABLE_IRQ
sysfs_attr(irq_count);
sysfs_attr(irq_queues);
#endif
sysfs_attr(mmap_mode);
sysfs_attr(mmap_area);
sysfs_attr(kmem_count);
sysfs_attr(kmem_alloc);
sysfs_attr(kmem_free);
sysfs_attr(kbuffers);
sysfs_attr(umappings);
sysfs_attr(umem_unmap);
#undef sysfs_attr
/* Free all allocated kmem buffers before leaving */
pcidriver_kmem_free_all( privdata );
#ifdef ENABLE_IRQ
pcidriver_remove_irq(privdata);
#endif
/* Removing Character device */
cdev_del(&(privdata->cdev));
/* Removing the device from sysfs */
class_device_destroy(pcidriver_class, privdata->devno);
/* Releasing privdata */
kfree(privdata);
/* Disabling PCI device */
pci_disable_device(pdev);
mod_info("Device at %s removed\n", dev_name(&pdev->dev));
}
/*************************************************************************/
/* File operations */
/*************************************************************************/
/**
* This struct defines the file operation entry points.
*
* @see pcidriver_ioctl
* @see pcidriver_mmap
* @see pcidriver_open
* @see pcidriver_release
*
*/
static struct file_operations pcidriver_fops = {
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35)
.owner = THIS_MODULE,
#endif
.unlocked_ioctl = pcidriver_ioctl,
.mmap = pcidriver_mmap,
.open = pcidriver_open,
.release = pcidriver_release,
};
/**
*
* Called when an application open()s a /dev/fpga*, attaches the private data
* with the file pointer.
*
*/
int pcidriver_open(struct inode *inode, struct file *filp)
{
pcidriver_privdata_t *privdata;
/* Set the private data area for the file */
privdata = container_of( inode->i_cdev, pcidriver_privdata_t, cdev);
filp->private_data = privdata;
return 0;
}
/**
*
* Called when the application close()s the file descriptor. Does nothing at
* the moment.
*
*/
int pcidriver_release(struct inode *inode, struct file *filp)
{
pcidriver_privdata_t *privdata;
/* Get the private data area */
privdata = filp->private_data;
return 0;
}
/**
*
* This function is the entry point for mmap() and calls either pcidriver_mmap_pci
* or pcidriver_mmap_kmem
*
* @see pcidriver_mmap_pci
* @see pcidriver_mmap_kmem
*
*/
int pcidriver_mmap(struct file *filp, struct vm_area_struct *vma)
{
pcidriver_privdata_t *privdata;
int ret = 0, bar;
mod_info_dbg("Entering mmap\n");
/* Get the private data area */
privdata = filp->private_data;
/* Check the current mmap mode */
switch (privdata->mmap_mode) {
case PCIDRIVER_MMAP_PCI:
/* Mmap a PCI region */
switch (privdata->mmap_area) {
case PCIDRIVER_BAR0: bar = 0; break;
case PCIDRIVER_BAR1: bar = 1; break;
case PCIDRIVER_BAR2: bar = 2; break;
case PCIDRIVER_BAR3: bar = 3; break;
case PCIDRIVER_BAR4: bar = 4; break;
case PCIDRIVER_BAR5: bar = 5; break;
default:
mod_info("Attempted to mmap a PCI area with the wrong mmap_area value: %d\n",privdata->mmap_area);
return -EINVAL; /* invalid parameter */
break;
}
ret = pcidriver_mmap_pci(privdata, vma, bar);
break;
case PCIDRIVER_MMAP_KMEM:
/* mmap a Kernel buffer */
ret = pcidriver_mmap_kmem(privdata, vma);
break;
default:
mod_info( "Invalid mmap_mode value (%d)\n",privdata->mmap_mode );
return -EINVAL; /* Invalid parameter (mode) */
}
return ret;
}
/*************************************************************************/
/* Internal driver functions */
int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vmap, int bar)
{
int ret = 0;
unsigned long bar_addr;
unsigned long bar_length, vma_size;
unsigned long bar_flags;
mod_info_dbg("Entering mmap_pci\n");
/* Get info of the BAR to be mapped */
bar_addr = pci_resource_start(privdata->pdev, bar);
bar_length = pci_resource_len(privdata->pdev, bar);
bar_flags = pci_resource_flags(privdata->pdev, bar);
/* Check sizes */
vma_size = (vmap->vm_end - vmap->vm_start);
if ((vma_size != bar_length) &&
((bar_length < PAGE_SIZE) && (vma_size != PAGE_SIZE))) {
mod_info( "mmap size is not correct! bar: %lu - vma: %lu\n", bar_length, vma_size );
return -EINVAL;
}
if (bar_flags & IORESOURCE_IO) {
/* Unlikely case, we will mmap a IO region */
/* IO regions are never cacheable */
#ifdef pgprot_noncached
vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot);
#endif
/* Map the BAR */
ret = io_remap_pfn_range_compat(
vmap,
vmap->vm_start,
bar_addr,
bar_length,
vmap->vm_page_prot);
} else {
/* Normal case, mmap a memory region */
/* Ensure this VMA is non-cached, if it is not flaged as prefetchable.
* If it is prefetchable, caching is allowed and will give better performance.
* This should be set properly by the BIOS, but we want to be sure. */
/* adapted from drivers/char/mem.c, mmap function. */
#ifdef pgprot_noncached
/* Setting noncached disables MTRR registers, and we want to use them.
* So we take this code out. This can lead to caching problems if and only if
* the System BIOS set something wrong. Check LDDv3, page 425.
*/
// if (!(bar_flags & IORESOURCE_PREFETCH))
// vmap->vm_page_prot = pgprot_noncached(vmap->vm_page_prot);
#endif
/* Map the BAR */
ret = remap_pfn_range_compat(
vmap,
vmap->vm_start,
bar_addr,
bar_length,
vmap->vm_page_prot);
}
if (ret) {
mod_info("remap_pfn_range failed\n");
return -EAGAIN;
}
return 0; /* success */
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/base.h 0000775 0000000 0000000 00000005756 12326537641 0025411 0 ustar 00root root 0000000 0000000 #ifndef _PCIDRIVER_BASE_H
#define _PCIDRIVER_BASE_H
#include "sysfs.h"
/**
*
* This file contains prototypes and data structures for internal use of the pciDriver.
*
*
*/
/* prototypes for file_operations */
static struct file_operations pcidriver_fops;
int pcidriver_mmap( struct file *filp, struct vm_area_struct *vmap );
int pcidriver_open(struct inode *inode, struct file *filp );
int pcidriver_release(struct inode *inode, struct file *filp);
/* prototypes for device operations */
static struct pci_driver pcidriver_driver;
static int pcidriver_probe(struct pci_dev *pdev, const struct pci_device_id *id);
static void pcidriver_remove(struct pci_dev *pdev);
/* prototypes for module operations */
static int __init pcidriver_init(void);
static void pcidriver_exit(void);
/*
* This is the table of PCI devices handled by this driver by default
* If you want to add devices dynamically to this list, do:
*
* echo "vendor device" > /sys/bus/pci/drivers/pciDriver/new_id
* where vendor and device are in hex, without leading '0x'.
*
* The IDs themselves can be found in common.h
*
* For more info, see /Documentation/pci.txt
*
*/
DEFINE_PCI_DEVICE_TABLE(pcidriver_ids) = {
{ PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_ML605_DEVICE_ID ) }, // PCI-E Xilinx ML605
{ PCI_DEVICE(PCIE_XILINX_VENDOR_ID, PCIE_KC705_DEV_ID)}, // PCIe Xilinx KC705
{ PCI_DEVICE(PCIE_XILINX_VENDOR_ID, PCIE_AMC_DEV_ID)}, // PCIe Creotech AMC
{0,0,0,0},
};
/* prototypes for internal driver functions */
int pcidriver_pci_read( pcidriver_privdata_t *privdata, pci_cfg_cmd *pci_cmd );
int pcidriver_pci_write( pcidriver_privdata_t *privdata, pci_cfg_cmd *pci_cmd );
int pcidriver_pci_info( pcidriver_privdata_t *privdata, pci_board_info *pci_info );
int pcidriver_mmap_pci( pcidriver_privdata_t *privdata, struct vm_area_struct *vmap , int bar );
int pcidriver_mmap_kmem( pcidriver_privdata_t *privdata, struct vm_area_struct *vmap );
/*************************************************************************/
/* Static data */
/* Hold the allocated major & minor numbers */
static dev_t pcidriver_devt;
/* Number of devices allocated */
static atomic_t pcidriver_deviceCount;
/* Sysfs attributes */
static DEVICE_ATTR(mmap_mode, (S_IRUGO | S_IWUGO), pcidriver_show_mmap_mode, pcidriver_store_mmap_mode);
static DEVICE_ATTR(mmap_area, (S_IRUGO | S_IWUGO), pcidriver_show_mmap_area, pcidriver_store_mmap_area);
static DEVICE_ATTR(kmem_count, S_IRUGO, pcidriver_show_kmem_count, NULL);
static DEVICE_ATTR(kbuffers, S_IRUGO, pcidriver_show_kbuffers, NULL);
static DEVICE_ATTR(kmem_alloc, S_IWUGO, NULL, pcidriver_store_kmem_alloc);
static DEVICE_ATTR(kmem_free, S_IWUGO, NULL, pcidriver_store_kmem_free);
static DEVICE_ATTR(umappings, S_IRUGO, pcidriver_show_umappings, NULL);
static DEVICE_ATTR(umem_unmap, S_IWUGO, NULL, pcidriver_store_umem_unmap);
#ifdef ENABLE_IRQ
static DEVICE_ATTR(irq_count, S_IRUGO, pcidriver_show_irq_count, NULL);
static DEVICE_ATTR(irq_queues, S_IRUGO, pcidriver_show_irq_queues, NULL);
#endif
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/common.h 0000775 0000000 0000000 00000006526 12326537641 0025763 0 ustar 00root root 0000000 0000000 #ifndef _PCIDRIVER_COMMON_H
#define _PCIDRIVER_COMMON_H
/*************************************************************************/
/* Private data types and structures */
/* Define an entry in the kmem list (this list is per device) */
/* This list keeps references to the allocated kernel buffers */
typedef struct {
int id;
struct list_head list;
dma_addr_t dma_handle;
unsigned long cpua;
unsigned long size;
struct class_device_attribute sysfs_attr; /* initialized when adding the entry */
} pcidriver_kmem_entry_t;
/* Define an entry in the umem list (this list is per device) */
/* This list keeps references to the SG lists for each mapped userspace region */
typedef struct {
int id;
struct list_head list;
unsigned int nr_pages; /* number of pages for this user memeory area */
struct page **pages; /* list of pointers to the pages */
unsigned int nents; /* actual entries in the scatter/gatter list (NOT nents for the map function, but the result) */
struct scatterlist *sg; /* list of sg entries */
struct class_device_attribute sysfs_attr; /* initialized when adding the entry */
} pcidriver_umem_entry_t;
/* Hold the driver private data */
typedef struct {
dev_t devno; /* device number (major and minor) */
struct pci_dev *pdev; /* PCI device */
struct class_device *class_dev; /* Class device */
struct cdev cdev; /* char device struct */
int mmap_mode; /* current mmap mode */
int mmap_area; /* current PCI mmap area */
#ifdef ENABLE_IRQ
int irq_enabled; /* Non-zero if IRQ is enabled */
int irq_count; /* Just an IRQ counter */
wait_queue_head_t irq_queues[ PCIDRIVER_INT_MAXSOURCES ];
/* One queue per interrupt source */
atomic_t irq_outstanding[ PCIDRIVER_INT_MAXSOURCES ];
/* Outstanding interrupts per queue */
volatile unsigned int *bars_kmapped[6]; /* PCI BARs mmapped in kernel space */
#endif
spinlock_t kmemlist_lock; /* Spinlock to lock kmem list operations */
struct list_head kmem_list; /* List of 'kmem_list_entry's associated with this device */
atomic_t kmem_count; /* id for next kmem entry */
spinlock_t umemlist_lock; /* Spinlock to lock umem list operations */
struct list_head umem_list; /* List of 'umem_list_entry's associated with this device */
atomic_t umem_count; /* id for next umem entry */
} pcidriver_privdata_t;
#define PCIE_XILINX_VENDOR_ID 0x10ee
/* Identifies the PCI-E Xilinx ML605 */
#define PCIE_ML605_DEVICE_ID 0x6014
/* Identfifies the PCIe Xilinx KC705 */
#define PCIE_KC705_DEV_ID 0x7021
/* Identfifies the PCIe Xilinx Artix AMC board */
#define PCIE_AMC_DEV_ID 0x7014
/*************************************************************************/
/* Some nice defines that make code more readable */
/* This is to print nice info in the log */
#ifdef DEBUG
#define mod_info( args... ) \
do { printk( KERN_INFO "%s - %s : ", MODNAME , __FUNCTION__ );\
printk( args ); } while(0)
#define mod_info_dbg( args... ) \
do { printk( KERN_INFO "%s - %s : ", MODNAME , __FUNCTION__ );\
printk( args ); } while(0)
#else
#define mod_info( args... ) \
do { printk( KERN_INFO "%s: ", MODNAME );\
printk( args ); } while(0)
#define mod_info_dbg( args... )
#endif
#define mod_crit( args... ) \
do { printk( KERN_CRIT "%s: ", MODNAME );\
printk( args ); } while(0)
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/compat.h 0000775 0000000 0000000 00000016622 12326537641 0025754 0 ustar 00root root 0000000 0000000 /**
*
* @file compat.h
* @author Michael Stapelberg
* @date 2009-04-05
* @brief Contains compatibility definitions for the different linux kernel versions to avoid
* putting ifdefs all over the driver code.
*
*/
#ifndef _COMPAT_H
#define _COMPAT_H
/* dev_name is the wrapper one needs to use to access what was formerly called
* bus_id in struct device. However, before 2.6.26, direct access was necessary,
* so we provide our own version. */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
static inline const char *dev_name(struct device *dev) {
return dev->bus_id;
}
#endif
/* SetPageLocked disappeared in v2.6.27 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
#define compat_lock_page SetPageLocked
#define compat_unlock_page ClearPageLocked
#else
/* in v2.6.28, __set_page_locked and __clear_page_locked was introduced */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
#define compat_lock_page __set_page_locked
#define compat_unlock_page __clear_page_locked
#else
/* However, in v2.6.27 itself, neither of them is there, so
* we need to use our own function fiddling with bits inside
* the page struct :-\ */
static inline void compat_lock_page(struct page *page) {
__set_bit(PG_locked, &page->flags);
}
static inline void compat_unlock_page(struct page *page) {
__clear_bit(PG_locked, &page->flags);
}
#endif
#endif
/* Before 2.6.13, simple_class was the standard interface. Nowadays, it's just called class */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
#define class_compat class_simple
/* These functions are redirected to their old corresponding functions */
#define class_create(module, name) class_simple_create(module, name)
#define class_destroy(type) class_simple_destroy(type)
#define class_device_destroy(unused, devno) class_simple_device_remove(devno)
#define class_device_create(type, unused, devno, devpointer, nameformat, minor, unused) \
class_simple_device_add(type, devno, devpointer, nameformat, minor)
#define class_set_devdata(classdev, privdata) classdev->class_data = privdata
#define DEVICE_ATTR_COMPAT
#define sysfs_attr_def_name(name) class_device_attr_##name
#define sysfs_attr_def_pointer privdata->class_dev
#define SYSFS_GET_FUNCTION(name) ssize_t name(struct class_device *cls, char *buf)
#define SYSFS_SET_FUNCTION(name) ssize_t name(struct class_device *cls, const char *buf, size_t count)
#define SYSFS_GET_PRIVDATA (pcidriver_privdata_t*)cls->class_data
#else
/* In 2.6.26, device.h was changed quite significantly. Luckily, it only affected
type/function names, for the most part. */
//#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
#define class_device_attribute device_attribute
#define CLASS_DEVICE_ATTR DEVICE_ATTR
#define class_device device
#define class_data dev
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
#define class_device_create(type, parent, devno, devpointer, nameformat, minor, privdata) \
device_create(type, parent, devno, privdata, nameformat, minor)
#else
#define class_device_create(type, parent, devno, devpointer, nameformat, minor, unused) \
device_create(type, parent, devno, nameformat, minor)
#endif
#define class_device_create_file device_create_file
#define class_device_remove_file device_remove_file
#define class_device_destroy device_destroy
#define DEVICE_ATTR_COMPAT struct device_attribute *attr,
#define class_set_devdata dev_set_drvdata
#define sysfs_attr_def_name(name) dev_attr_##name
#define sysfs_attr_def_pointer privdata->class_dev
#define SYSFS_GET_FUNCTION(name) ssize_t name(struct device *dev, struct device_attribute *attr, char *buf)
#define SYSFS_SET_FUNCTION(name) ssize_t name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
#define SYSFS_GET_PRIVDATA dev_get_drvdata(dev)
//#endif
#define class_compat class
#endif
/* The arguments of IRQ handlers have been changed in 2.6.19. It's very likely that
int irq will disappear somewhen in the future (current is 2.6.29), too. */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
#define IRQ_HANDLER_FUNC(name) irqreturn_t name(int irq, void *dev_id)
#else
#define IRQ_HANDLER_FUNC(name) irqreturn_t name(int irq, void *dev_id, struct pt_regs *regs)
#endif
/* atomic_inc_return appeared in 2.6.9, at least in CERN scientific linux, provide
compatibility wrapper for older kernels */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
static int atomic_inc_return(atomic_t *variable) {
atomic_inc(variable);
return atomic_read(variable);
}
#endif
/* sg_set_page is available starting at 2.6.24 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
#define sg_set_page(sg, set_page, set_length, set_offset) do { \
(sg)->page = set_page; \
(sg)->length = set_length; \
(sg)->offset = set_offset; \
} while (0)
#endif
/* Before 2.6.20, disable was not an atomic counter, so this check was needed */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
#define pci_disable_device(pdev) do { \
if (pdev->is_enabled) \
pci_disable_device(pdev); \
} while (0)
#endif
/* Before 2.6.24, scatter/gather lists did not need to be initialized */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
#define sg_init_table(sg, nr_pages)
#endif
/* SA_SHIRQ was renamed to IRQF_SHARED in 2.6.24 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
#define request_irq(irq, irq_handler, modname, privdata) request_irq(irq, irq_handler, IRQF_SHARED, modname, privdata)
#else
#define request_irq(irq, irq_handler, modname, privdata) request_irq(irq, irq_handler, SA_SHIRQ, modname, privdata)
#endif
/* In 2.6.13, io_remap_page_range was removed in favor for io_remap_pfn_range which works on
more platforms and allows more memory space */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
#define io_remap_pfn_range_compat(vmap, vm_start, bar_addr, bar_length, vm_page_prot) \
io_remap_pfn_range(vmap, vm_start, (bar_addr >> PAGE_SHIFT), bar_length, vm_page_prot)
#else
#define io_remap_pfn_range_compat(vmap, vm_start, bar_addr, bar_length, vm_page_prot) \
io_remap_page_range(vmap, vm_start, bar_addr, bar_length, vm_page_prot)
#endif
/* In 2.6.10, remap_pfn_range was introduced, see io_remap_pfn_range_compat */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
#define remap_pfn_range_compat(vmap, vm_start, bar_addr, bar_length, vm_page_prot) \
remap_pfn_range(vmap, vm_start, (bar_addr >> PAGE_SHIFT), bar_length, vm_page_prot)
#define remap_pfn_range_cpua_compat(vmap, vm_start, cpua, size, vm_page_prot) \
remap_pfn_range(vmap, vm_start, page_to_pfn(virt_to_page((void*)cpua)), size, vm_page_prot)
#else
#define remap_pfn_range_compat(vmap, vm_start, bar_addr, bar_length, vm_page_prot) \
remap_page_range(vmap, vm_start, bar_addr, bar_length, vm_page_prot)
#define remap_pfn_range_cpua_compat(vmap, vm_start, cpua, size, vm_page_prot) \
remap_page_range(vmap, vm_start, virt_to_phys((void*)cpua), size, vm_page_prot)
#endif
/**
* Go over the pages of the kmem buffer, and mark them as reserved.
* This is needed, otherwise mmaping the kernel memory to user space
* will fail silently (mmaping /dev/null) when using remap_xx_range.
*/
static inline void set_pages_reserved_compat(unsigned long cpua, unsigned long size)
{
/* Starting in 2.6.15, the PG_RESERVED bit was removed.
See also http://lwn.net/Articles/161204/ */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
struct page *page, *last_page;
page = virt_to_page(cpua);
last_page = virt_to_page(cpua + size - 1);
for (; page <= last_page; page++)
SetPageReserved(page);
#endif
}
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/config.h 0000775 0000000 0000000 00000000732 12326537641 0025731 0 ustar 00root root 0000000 0000000 /*******************************/
/* Configuration of the driver */
/*******************************/
/* Debug messages */
#define DEBUG
/* Enable/disable IRQ handling */
#define ENABLE_IRQ
/* The name of the module */
#define MODNAME "pciDriver"
/* Major number is allocated dynamically */
/* Minor number */
#define MINORNR 0
/* Node name of the char device */
#define NODENAME "fpga"
#define NODENAMEFMT "fpga%d"
/* Maximum number of devices*/
#define MAXDEVICES 4
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/int.c 0000775 0000000 0000000 00000017727 12326537641 0025265 0 ustar 00root root 0000000 0000000 /**
*
* @file int.c
* @author Guillermo Marcus
* @date 2009-04-05
* @brief Contains the interrupt handler.
*
*/
/*
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.7 2008-01-11 10:18:28 marcus
* Modified interrupt mechanism. Added atomic functions and queues, to address race conditions. Removed unused interrupt code.
*
* Revision 1.6 2007-11-04 20:58:22 marcus
* Added interrupt generator acknowledge.
* Fixed wrong operator.
*
* Revision 1.5 2007-10-31 15:42:21 marcus
* Added IG ack for testing, may be removed later.
*
* Revision 1.4 2007-07-17 13:15:56 marcus
* Removed Tasklets.
* Using newest map for the ABB interrupts.
*
* Revision 1.3 2007-07-05 15:30:30 marcus
* Added support for both register maps of the ABB.
*
* Revision 1.2 2007-05-29 07:50:18 marcus
* Split code into 2 files. May get merged in the future again....
*
* Revision 1.1 2007/03/01 16:57:43 marcus
* Divided driver file to ease the interrupt hooks for the user of the driver.
* Modified Makefile accordingly.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "config.h"
#include "compat.h"
#include "pciDriver.h"
#include "common.h"
#include "int.h"
/*
* The ID between IRQ_SOURCE in irq_outstanding and the actual source is arbitrary.
* Therefore, be careful when communicating with multiple implementations.
*/
/* IRQ_SOURCES */
#define ABB_IRQ_CH0 0
#define ABB_IRQ_CH1 1
#define ABB_IRQ_IG 2
/* See ABB user’s guide, register definitions (3.1) */
#define ABB_INT_ENABLE (0x0010 >> 2)
#define ABB_INT_STAT (0x0008 >> 2)
#define ABB_INT_CH1_TIMEOUT (1 << 4)
#define ABB_INT_CH0_TIMEOUT (1 << 5)
#define ABB_INT_IG (1 << 2)
#define ABB_INT_CH0 (1 << 1) /* downstream */
#define ABB_INT_CH1 (1) /* upstream */
#define ABB_CH0_CTRL (108 >> 2)
#define ABB_CH1_CTRL (72 >> 2)
#define ABB_CH_RESET (0x0201000A)
#define ABB_IG_CTRL (0x0080 >> 2)
#define ABB_IG_ACK (0x00F0)
/**
*
* If IRQ-handling is enabled, this function will be called from pcidriver_probe
* to initialize the IRQ handling (maps the BARs)
*
*/
int pcidriver_probe_irq(pcidriver_privdata_t *privdata)
{
unsigned char int_pin, int_line;
unsigned long bar_addr, bar_len, bar_flags;
int i;
int err;
for (i = 0; i < 6; i++)
privdata->bars_kmapped[i] = NULL;
for (i = 0; i < 6; i++) {
bar_addr = pci_resource_start(privdata->pdev, i);
bar_len = pci_resource_len(privdata->pdev, i);
bar_flags = pci_resource_flags(privdata->pdev, i);
/* check if it is a valid BAR, skip if not */
if ((bar_addr == 0) || (bar_len == 0))
continue;
/* Skip IO regions (map only mem regions) */
if (bar_flags & IORESOURCE_IO)
continue;
/* Check if the region is available */
if ((err = pci_request_region(privdata->pdev, i, NULL)) != 0) {
mod_info( "Failed to request BAR memory region.\n" );
return err;
}
/* Map it into kernel space. */
/* For x86 this is just a dereference of the pointer, but that is
* not portable. So we need to do the portable way. Thanks Joern!
*/
/* respect the cacheable-bility of the region */
if (bar_flags & IORESOURCE_PREFETCH)
privdata->bars_kmapped[i] = ioremap(bar_addr, bar_len);
else
privdata->bars_kmapped[i] = ioremap_nocache(bar_addr, bar_len);
/* check for error */
if (privdata->bars_kmapped[i] == NULL) {
mod_info( "Failed to remap BAR%d into kernel space.\n", i );
return -EIO;
}
}
/* Initialize the interrupt handler for this device */
/* Initialize the wait queues */
for (i = 0; i < PCIDRIVER_INT_MAXSOURCES; i++) {
init_waitqueue_head(&(privdata->irq_queues[i]));
atomic_set(&(privdata->irq_outstanding[i]), 0);
}
/* Initialize the irq config */
if ((err = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_PIN, &int_pin)) != 0) {
/* continue without interrupts */
int_pin = 0;
mod_info("Error getting the interrupt pin. Disabling interrupts for this device\n");
}
/* Disable interrupts and activate them if everything can be set up properly */
privdata->irq_enabled = 0;
if (int_pin == 0)
return 0;
if ((err = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_LINE, &int_line)) != 0) {
mod_info("Error getting the interrupt line. Disabling interrupts for this device\n");
return 0;
}
/* register interrupt handler */
if ((err = request_irq(privdata->pdev->irq, pcidriver_irq_handler, MODNAME, privdata)) != 0) {
mod_info("Error registering the interrupt handler. Disabling interrupts for this device\n");
return 0;
}
privdata->irq_enabled = 1;
mod_info("Registered Interrupt Handler at pin %i, line %i, IRQ %i\n", int_pin, int_line, privdata->pdev->irq );
return 0;
}
/**
*
* Frees/cleans up the data structures, called from pcidriver_remove()
*
*/
void pcidriver_remove_irq(pcidriver_privdata_t *privdata)
{
/* Release the IRQ handler */
if (privdata->irq_enabled != 0)
free_irq(privdata->pdev->irq, privdata);
pcidriver_irq_unmap_bars(privdata);
}
/**
*
* Unmaps the BARs and releases them
*
*/
void pcidriver_irq_unmap_bars(pcidriver_privdata_t *privdata)
{
int i;
for (i = 0; i < 6; i++) {
if (privdata->bars_kmapped[i] == NULL)
continue;
iounmap((void*)privdata->bars_kmapped[i]);
pci_release_region(privdata->pdev, i);
}
}
/**
*
* Acknowledge the interrupt by ACKing the interrupt generator.
*
* @returns true if the channel was acknowledged and the interrupt handler is done
*
*/
static bool check_acknowlegde_channel(pcidriver_privdata_t *privdata, int interrupt,
int channel, volatile unsigned int *bar)
{
if (!(bar[ABB_INT_STAT] & interrupt))
return false;
bar[ABB_INT_ENABLE] &= !interrupt;
if (interrupt == ABB_INT_IG)
bar[ABB_IG_CTRL] = ABB_IG_ACK;
/* Wake up the waiting loop in ioctl.c:ioctl_wait_interrupt() */
atomic_inc(&(privdata->irq_outstanding[channel]));
wake_up_interruptible(&(privdata->irq_queues[channel]));
return true;
}
/**
*
* Acknowledges the receival of an interrupt to the card.
*
* @returns true if the card was acknowledget
* @returns false if the interrupt was not for one of our cards
*
* @see check_acknowlegde_channel
*
*/
static bool pcidriver_irq_acknowledge(pcidriver_privdata_t *privdata)
{
/* Disable this thing, as it is irrelevant in our case
volatile unsigned int *bar;
*/
/* TODO: add subvendor / subsystem ids */
/* FIXME: guillermo: which ones? all? */
/* Test if we have to handle this interrupt */
/* if ((privdata->pdev->vendor != PCIEABB_VENDOR_ID) ||
(privdata->pdev->device != PCIEABB_DEVICE_ID))
return false;
*/
/* Acknowledge the device */
/* this is for ABB / wenxue DMA engine */
/*
bar = privdata->bars_kmapped[0];
mod_info_dbg("interrupt registers. ISR: %x, IER: %x\n", bar[ABB_INT_STAT], bar[ABB_INT_ENABLE]);
if (check_acknowlegde_channel(privdata, ABB_INT_CH0, ABB_IRQ_CH0, bar))
return true;
if (check_acknowlegde_channel(privdata, ABB_INT_CH1, ABB_IRQ_CH1, bar))
return true;
if (check_acknowlegde_channel(privdata, ABB_INT_IG, ABB_IRQ_IG, bar))
return true;
if (check_acknowlegde_channel(privdata, ABB_INT_CH0_TIMEOUT, ABB_IRQ_CH0, bar))
return true;
if (check_acknowlegde_channel(privdata, ABB_INT_CH1_TIMEOUT, ABB_IRQ_CH1, bar))
return true;
mod_info_dbg("err: interrupt registers. ISR: %x, IER: %x\n", bar[ ABB_INT_STAT ], bar[ ABB_INT_ENABLE ] );
*/
return false;
}
/**
*
* Handles IRQs. At the moment, this acknowledges the card that this IRQ
* was received and then increases the driver's IRQ counter.
*
* @see pcidriver_irq_acknowledge
*
*/
IRQ_HANDLER_FUNC(pcidriver_irq_handler)
{
pcidriver_privdata_t *privdata = (pcidriver_privdata_t *)dev_id;
if (!pcidriver_irq_acknowledge(privdata))
return IRQ_NONE;
privdata->irq_count++;
return IRQ_HANDLED;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/int.h 0000775 0000000 0000000 00000000464 12326537641 0025260 0 ustar 00root root 0000000 0000000 #if !defined(_PCIDRIVER_INT_H) && defined(ENABLE_IRQ)
#define _PCIDRIVER_INT_H
int pcidriver_probe_irq(pcidriver_privdata_t *privdata);
void pcidriver_remove_irq(pcidriver_privdata_t *privdata);
void pcidriver_irq_unmap_bars(pcidriver_privdata_t *privdata);
IRQ_HANDLER_FUNC(pcidriver_irq_handler);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/ioctl.c 0000775 0000000 0000000 00000025724 12326537641 0025601 0 ustar 00root root 0000000 0000000 /**
*
* @file ioctl.c
* @author Guillermo Marcus
* @date 2009-04-05
* @brief Contains the functions handling the different ioctl calls.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "config.h" /* Configuration for the driver */
#include "compat.h" /* Compatibility functions/definitions */
#include "pciDriver.h" /* External interface for the driver */
#include "common.h" /* Internal definitions for all parts */
#include "kmem.h" /* Internal definitions for kernel memory */
#include "umem.h" /* Internal definitions for user space memory */
#include "ioctl.h" /* Internal definitions for the ioctl part */
/** Declares a variable of the given type with the given name and copies it from userspace */
#define READ_FROM_USER(type, name) \
type name; \
if ((ret = copy_from_user(&name, (type*)arg, sizeof(name))) != 0) \
return -EFAULT;
/** Writes back the given variable with the given type to userspace */
#define WRITE_TO_USER(type, name) \
if ((ret = copy_to_user((type*)arg, &name, sizeof(name))) != 0) \
return -EFAULT;
/**
*
* Sets the mmap mode for following mmap() calls.
*
* @param arg Not a pointer, but either PCIDRIVER_MMAP_PCI or PCIDRIVER_MMAP_KMEM
*
*/
static int ioctl_mmap_mode(pcidriver_privdata_t *privdata, unsigned long arg)
{
if ((arg != PCIDRIVER_MMAP_PCI) && (arg != PCIDRIVER_MMAP_KMEM))
return -EINVAL;
/* change the mode */
privdata->mmap_mode = arg;
return 0;
}
/**
*
* Sets the mmap area (BAR) for following mmap() calls.
*
*/
static int ioctl_mmap_area(pcidriver_privdata_t *privdata, unsigned long arg)
{
/* validate input */
if ((arg < PCIDRIVER_BAR0) || (arg > PCIDRIVER_BAR5))
return -EINVAL;
/* change the PCI area to mmap */
privdata->mmap_area = arg;
return 0;
}
/**
*
* Reads/writes a byte/word/dword of the device's PCI config.
*
* @see pcidriver_pci_read
* @see pcidriver_pci_write
*
*/
static int ioctl_pci_config_read_write(pcidriver_privdata_t *privdata, unsigned int cmd, unsigned long arg)
{
int ret;
READ_FROM_USER(pci_cfg_cmd, pci_cmd);
if (cmd == PCIDRIVER_IOC_PCI_CFG_RD) {
switch (pci_cmd.size) {
case PCIDRIVER_PCI_CFG_SZ_BYTE:
ret = pci_read_config_byte( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.byte) );
break;
case PCIDRIVER_PCI_CFG_SZ_WORD:
ret = pci_read_config_word( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.word) );
break;
case PCIDRIVER_PCI_CFG_SZ_DWORD:
ret = pci_read_config_dword( privdata->pdev, pci_cmd.addr, &(pci_cmd.val.dword) );
break;
default:
return -EINVAL; /* Wrong size setting */
}
} else {
switch (pci_cmd.size) {
case PCIDRIVER_PCI_CFG_SZ_BYTE:
ret = pci_write_config_byte( privdata->pdev, pci_cmd.addr, pci_cmd.val.byte );
break;
case PCIDRIVER_PCI_CFG_SZ_WORD:
ret = pci_write_config_word( privdata->pdev, pci_cmd.addr, pci_cmd.val.word );
break;
case PCIDRIVER_PCI_CFG_SZ_DWORD:
ret = pci_write_config_dword( privdata->pdev, pci_cmd.addr, pci_cmd.val.dword );
break;
default:
return -EINVAL; /* Wrong size setting */
break;
}
}
WRITE_TO_USER(pci_cfg_cmd, pci_cmd);
return 0;
}
/**
*
* Gets the PCI information for the device.
*
* @see pcidriver_pci_info
*
*/
static int ioctl_pci_info(pcidriver_privdata_t *privdata, unsigned long arg)
{
int ret;
int bar;
READ_FROM_USER(pci_board_info, pci_info);
pci_info.vendor_id = privdata->pdev->vendor;
pci_info.device_id = privdata->pdev->device;
pci_info.bus = privdata->pdev->bus->number;
pci_info.slot = PCI_SLOT(privdata->pdev->devfn);
pci_info.devfn = privdata->pdev->devfn;
if ((ret = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_PIN, &(pci_info.interrupt_pin))) != 0)
return ret;
if ((ret = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_LINE, &(pci_info.interrupt_line))) != 0)
return ret;
for (bar = 0; bar < 6; bar++) {
pci_info.bar_start[bar] = pci_resource_start(privdata->pdev, bar);
pci_info.bar_length[bar] = pci_resource_len(privdata->pdev, bar);
}
WRITE_TO_USER(pci_board_info, pci_info);
return 0;
}
/**
*
* Allocates kernel memory.
*
* @see pcidriver_kmem_alloc
*
*/
static int ioctl_kmem_alloc(pcidriver_privdata_t *privdata, unsigned long arg)
{
int ret;
READ_FROM_USER(kmem_handle_t, khandle);
if ((ret = pcidriver_kmem_alloc(privdata, &khandle)) != 0)
return ret;
WRITE_TO_USER(kmem_handle_t, khandle);
return 0;
}
/**
*
* Frees kernel memory.
*
* @see pcidriver_kmem_free
*
*/
static int ioctl_kmem_free(pcidriver_privdata_t *privdata, unsigned long arg)
{
int ret;
READ_FROM_USER(kmem_handle_t, khandle);
if ((ret = pcidriver_kmem_free(privdata, &khandle)) != 0)
return ret;
return 0;
}
/**
*
* Syncs kernel memory.
*
* @see pcidriver_kmem_sync
*
*/
static int ioctl_kmem_sync(pcidriver_privdata_t *privdata, unsigned long arg)
{
int ret;
READ_FROM_USER(kmem_sync_t, ksync);
return pcidriver_kmem_sync(privdata, &ksync);
}
/*
*
* Maps the given scatter/gather list from memory to PCI bus addresses.
*
* @see pcidriver_umem_sgmap
*
*/
static int ioctl_umem_sgmap(pcidriver_privdata_t *privdata, unsigned long arg)
{
int ret;
READ_FROM_USER(umem_handle_t, uhandle);
if ((ret = pcidriver_umem_sgmap(privdata, &uhandle)) != 0)
return ret;
WRITE_TO_USER(umem_handle_t, uhandle);
return 0;
}
/**
*
* Unmaps the given scatter/gather list.
*
* @see pcidriver_umem_sgunmap
*
*/
static int ioctl_umem_sgunmap(pcidriver_privdata_t *privdata, unsigned long arg)
{
int ret;
pcidriver_umem_entry_t *umem_entry;
READ_FROM_USER(umem_handle_t, uhandle);
/* Find the associated umem_entry for this buffer,
* return -EINVAL if the specified handle id is invalid */
if ((umem_entry = pcidriver_umem_find_entry_id(privdata, uhandle.handle_id)) == NULL)
return -EINVAL;
if ((ret = pcidriver_umem_sgunmap(privdata, umem_entry)) != 0)
return ret;
return 0;
}
/**
*
* Copies the scatter/gather list from kernelspace to userspace.
*
* @see pcidriver_umem_sgget
*
*/
static int ioctl_umem_sgget(pcidriver_privdata_t *privdata, unsigned long arg)
{
int ret;
READ_FROM_USER(umem_sglist_t, usglist);
/* The umem_sglist_t has a pointer to the scatter/gather list itself which
* needs to be copied separately. The number of elements is stored in ->nents.
* As the list can get very big, we need to use vmalloc. */
if ((usglist.sg = vmalloc(usglist.nents * sizeof(umem_sgentry_t))) == NULL)
return -ENOMEM;
/* copy array to kernel structure */
ret = copy_from_user(usglist.sg, ((umem_sglist_t *)arg)->sg, (usglist.nents)*sizeof(umem_sgentry_t));
if (ret) return -EFAULT;
if ((ret = pcidriver_umem_sgget(privdata, &usglist)) != 0)
return ret;
/* write data to user space */
ret = copy_to_user(((umem_sglist_t *)arg)->sg, usglist.sg, (usglist.nents)*sizeof(umem_sgentry_t));
if (ret) return -EFAULT;
/* free array memory */
vfree(usglist.sg);
/* restore sg pointer to vma address in user space before copying */
usglist.sg = ((umem_sglist_t *)arg)->sg;
WRITE_TO_USER(umem_sglist_t, usglist);
return 0;
}
/**
*
* Syncs user memory.
*
* @see pcidriver_umem_sync
*
*/
static int ioctl_umem_sync(pcidriver_privdata_t *privdata, unsigned long arg)
{
int ret;
READ_FROM_USER(umem_handle_t, uhandle);
return pcidriver_umem_sync( privdata, &uhandle );
}
/**
*
* Waits for an interrupt
*
* @param arg Not a pointer, but the irq source to wait for (unsigned int)
*
*/
static int ioctl_wait_interrupt(pcidriver_privdata_t *privdata, unsigned long arg)
{
#ifdef ENABLE_IRQ
unsigned int irq_source;
int temp;
if (arg >= PCIDRIVER_INT_MAXSOURCES)
return -EFAULT; /* User tried to overrun the IRQ_SOURCES array */
irq_source = arg;
/* Thanks to Joern for the correction and tips! */
/* done this way to avoid wrong behaviour (endless loop) of the compiler in AMD platforms */
temp=1;
while (temp) {
/* We wait here with an interruptible timeout. This will be interrupted
* by int.c:check_acknowledge_channel() as soon as in interrupt for
* the specified source arrives. */
wait_event_interruptible_timeout( (privdata->irq_queues[irq_source]),
(atomic_read(&(privdata->irq_outstanding[irq_source])) > 0),
(10*HZ/1000) );
if (atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source])) )
atomic_inc( &(privdata->irq_outstanding[irq_source]) );
else
temp =0;
}
return 0;
#else
mod_info("Asked to wait for interrupt but interrupts are not enabled in the driver\n");
return -EFAULT;
#endif
}
/**
*
* Clears the interrupt wait queue.
*
* @param arg Not a pointer, but the irq source (unsigned int)
* @returns -EFAULT if the user specified an irq source out of range
*
*/
static int ioctl_clear_ioq(pcidriver_privdata_t *privdata, unsigned long arg)
{
#ifdef ENABLE_IRQ
unsigned int irq_source;
if (arg >= PCIDRIVER_INT_MAXSOURCES)
return -EFAULT;
irq_source = arg;
atomic_set(&(privdata->irq_outstanding[irq_source]), 0);
return 0;
#else
mod_info("Asked to wait for interrupt but interrupts are not enabled in the driver\n");
return -EFAULT;
#endif
}
/**
*
* This function handles all ioctl file operations.
* Generally, the data of the ioctl is copied from userspace to kernelspace, a separate
* function is called to handle the ioctl itself, then the data is copied back to userspace.
*
* @returns -EFAULT when an invalid memory pointer is passed
*
*/
long pcidriver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
pcidriver_privdata_t *privdata = filp->private_data;
/* Select the appropiate command */
switch (cmd) {
case PCIDRIVER_IOC_MMAP_MODE:
return ioctl_mmap_mode(privdata, arg);
case PCIDRIVER_IOC_MMAP_AREA:
return ioctl_mmap_area(privdata, arg);
case PCIDRIVER_IOC_PCI_CFG_RD:
case PCIDRIVER_IOC_PCI_CFG_WR:
return ioctl_pci_config_read_write(privdata, cmd, arg);
case PCIDRIVER_IOC_PCI_INFO:
return ioctl_pci_info(privdata, arg);
case PCIDRIVER_IOC_KMEM_ALLOC:
return ioctl_kmem_alloc(privdata, arg);
case PCIDRIVER_IOC_KMEM_FREE:
return ioctl_kmem_free(privdata, arg);
case PCIDRIVER_IOC_KMEM_SYNC:
return ioctl_kmem_sync(privdata, arg);
case PCIDRIVER_IOC_UMEM_SGMAP:
return ioctl_umem_sgmap(privdata, arg);
case PCIDRIVER_IOC_UMEM_SGUNMAP:
return ioctl_umem_sgunmap(privdata, arg);
case PCIDRIVER_IOC_UMEM_SGGET:
return ioctl_umem_sgget(privdata, arg);
case PCIDRIVER_IOC_UMEM_SYNC:
return ioctl_umem_sync(privdata, arg);
case PCIDRIVER_IOC_WAITI:
return ioctl_wait_interrupt(privdata, arg);
case PCIDRIVER_IOC_CLEAR_IOQ:
return ioctl_clear_ioq(privdata, arg);
default:
return -EINVAL;
}
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/ioctl.h 0000775 0000000 0000000 00000000116 12326537641 0025572 0 ustar 00root root 0000000 0000000 long pcidriver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/kmem.c 0000775 0000000 0000000 00000022766 12326537641 0025423 0 ustar 00root root 0000000 0000000 /**
*
* @file kmem.c
* @brief This file contains all functions dealing with kernel memory.
* @author Guillermo Marcus
* @date 2009-04-05
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "config.h" /* compile-time configuration */
#include "compat.h" /* compatibility definitions for older linux */
#include "pciDriver.h" /* external interface for the driver */
#include "common.h" /* internal definitions for all parts */
#include "kmem.h" /* prototypes for kernel memory */
#include "sysfs.h" /* prototypes for sysfs */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
#define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
#endif
/**
*
* Allocates new kernel memory including the corresponding management structure, makes
* it available via sysfs if possible.
*
*/
int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle)
{
pcidriver_kmem_entry_t *kmem_entry;
void *retptr;
/* First, allocate zeroed memory for the kmem_entry */
if ((kmem_entry = kcalloc(1, sizeof(pcidriver_kmem_entry_t), GFP_KERNEL)) == NULL)
goto kmem_alloc_entry_fail;
/* Initialize the kmem_entry */
kmem_entry->id = atomic_inc_return(&privdata->kmem_count) - 1;
kmem_entry->size = kmem_handle->size;
kmem_handle->handle_id = kmem_entry->id;
/* Initialize sysfs if possible */
if (pcidriver_sysfs_initialize_kmem(privdata, kmem_entry->id, &(kmem_entry->sysfs_attr)) != 0)
goto kmem_alloc_mem_fail;
/* ...and allocate the DMA memory */
/* note this is a memory pair, referencing the same area: the cpu address (cpua)
* and the PCI bus address (pa). The CPU and PCI addresses may not be the same.
* The CPU sees only CPU addresses, while the device sees only PCI addresses.
* CPU address is used for the mmap (internal to the driver), and
* PCI address is the address passed to the DMA Controller in the device.
*/
retptr = pci_alloc_consistent( privdata->pdev, kmem_handle->size, &(kmem_entry->dma_handle) );
if (retptr == NULL)
goto kmem_alloc_mem_fail;
kmem_entry->cpua = (unsigned long)retptr;
kmem_handle->pa = (unsigned long)(kmem_entry->dma_handle);
set_pages_reserved_compat(kmem_entry->cpua, kmem_entry->size);
/* Add the kmem_entry to the list of the device */
spin_lock( &(privdata->kmemlist_lock) );
list_add_tail( &(kmem_entry->list), &(privdata->kmem_list) );
spin_unlock( &(privdata->kmemlist_lock) );
return 0;
kmem_alloc_mem_fail:
kfree(kmem_entry);
kmem_alloc_entry_fail:
return -ENOMEM;
}
/**
*
* Called via sysfs, frees kernel memory and the corresponding management structure
*
*/
int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle )
{
pcidriver_kmem_entry_t *kmem_entry;
/* Find the associated kmem_entry for this buffer */
if ((kmem_entry = pcidriver_kmem_find_entry(privdata, kmem_handle)) == NULL)
return -EINVAL; /* kmem_handle is not valid */
return pcidriver_kmem_free_entry(privdata, kmem_entry);
}
/**
*
* Called when cleaning up, frees all kernel memory and their corresponding management structure
*
*/
int pcidriver_kmem_free_all(pcidriver_privdata_t *privdata)
{
struct list_head *ptr, *next;
pcidriver_kmem_entry_t *kmem_entry;
/* iterate safely over the entries and delete them */
list_for_each_safe(ptr, next, &(privdata->kmem_list)) {
kmem_entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
pcidriver_kmem_free_entry(privdata, kmem_entry); /* spin lock inside! */
}
return 0;
}
/**
*
* Synchronize memory to/from the device (or in both directions).
*
*/
int pcidriver_kmem_sync( pcidriver_privdata_t *privdata, kmem_sync_t *kmem_sync )
{
pcidriver_kmem_entry_t *kmem_entry;
/* Find the associated kmem_entry for this buffer */
if ((kmem_entry = pcidriver_kmem_find_entry(privdata, &(kmem_sync->handle))) == NULL)
return -EINVAL; /* kmem_handle is not valid */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
switch (kmem_sync->dir) {
case PCIDRIVER_DMA_TODEVICE:
pci_dma_sync_single_for_device( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_TODEVICE );
break;
case PCIDRIVER_DMA_FROMDEVICE:
pci_dma_sync_single_for_cpu( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_FROMDEVICE );
break;
case PCIDRIVER_DMA_BIDIRECTIONAL:
pci_dma_sync_single_for_device( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_BIDIRECTIONAL );
pci_dma_sync_single_for_cpu( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_BIDIRECTIONAL );
break;
default:
return -EINVAL; /* wrong direction parameter */
}
#else
switch (kmem_sync->dir) {
case PCIDRIVER_DMA_TODEVICE:
pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_TODEVICE );
break;
case PCIDRIVER_DMA_FROMDEVICE:
pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_FROMDEVICE );
break;
case PCIDRIVER_DMA_BIDIRECTIONAL:
pci_dma_sync_single( privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_BIDIRECTIONAL );
break;
default:
return -EINVAL; /* wrong direction parameter */
}
#endif
return 0; /* success */
}
/**
*
* Free the given kmem_entry and its memory.
*
*/
int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_entry_t *kmem_entry)
{
pcidriver_sysfs_remove(privdata, &(kmem_entry->sysfs_attr));
/* Go over the pages of the kmem buffer, and mark them as not reserved */
#if 0
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
/*
* This code is DISABLED.
* Apparently, it is not needed to unreserve them. Doing so here
* hangs the machine. Why?
*
* Uhm.. see links:
*
* http://lwn.net/Articles/161204/
* http://lists.openfabrics.org/pipermail/general/2007-March/034101.html
*
* I insist, this should be enabled, but doing so hangs the machine.
* Literature supports the point, and there is even a similar problem (see link)
* But this is not the case. It seems right to me. but obviously is not.
*
* Anyway, this goes away in kernel >=2.6.15.
*/
unsigned long start = __pa(kmem_entry->cpua) >> PAGE_SHIFT;
unsigned long end = __pa(kmem_entry->cpua + kmem_entry->size) >> PAGE_SHIFT;
unsigned long i;
for(i=start;ipdev, kmem_entry->size, (void *)(kmem_entry->cpua), kmem_entry->dma_handle );
/* Remove the kmem list entry */
spin_lock( &(privdata->kmemlist_lock) );
list_del( &(kmem_entry->list) );
spin_unlock( &(privdata->kmemlist_lock) );
/* Release kmem_entry memory */
kfree(kmem_entry);
return 0;
}
/**
*
* Find the corresponding kmem_entry for the given kmem_handle.
*
*/
pcidriver_kmem_entry_t *pcidriver_kmem_find_entry(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle)
{
struct list_head *ptr;
pcidriver_kmem_entry_t *entry, *result = NULL;
/* should I implement it better using the handle_id? */
spin_lock(&(privdata->kmemlist_lock));
list_for_each(ptr, &(privdata->kmem_list)) {
entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
if (entry->dma_handle == kmem_handle->pa) {
result = entry;
break;
}
}
spin_unlock(&(privdata->kmemlist_lock));
return result;
}
/**
*
* find the corresponding kmem_entry for the given id.
*
*/
pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_id(pcidriver_privdata_t *privdata, int id)
{
struct list_head *ptr;
pcidriver_kmem_entry_t *entry, *result = NULL;
spin_lock(&(privdata->kmemlist_lock));
list_for_each(ptr, &(privdata->kmem_list)) {
entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
if (entry->id == id) {
result = entry;
break;
}
}
spin_unlock(&(privdata->kmemlist_lock));
return result;
}
/**
*
* mmap() kernel memory to userspace.
*
*/
int pcidriver_mmap_kmem(pcidriver_privdata_t *privdata, struct vm_area_struct *vma)
{
unsigned long vma_size;
pcidriver_kmem_entry_t *kmem_entry;
int ret;
mod_info_dbg("Entering mmap_kmem\n");
/* FIXME: Is this really right? Always just the latest one? Can't we identify one? */
/* Get latest entry on the kmem_list */
spin_lock(&(privdata->kmemlist_lock));
if (list_empty(&(privdata->kmem_list))) {
spin_unlock(&(privdata->kmemlist_lock));
mod_info("Trying to mmap a kernel memory buffer without creating it first!\n");
return -EFAULT;
}
kmem_entry = list_entry(privdata->kmem_list.prev, pcidriver_kmem_entry_t, list);
spin_unlock(&(privdata->kmemlist_lock));
mod_info_dbg("Got kmem_entry with id: %d\n", kmem_entry->id);
/* Check sizes */
vma_size = (vma->vm_end - vma->vm_start);
if ((vma_size != kmem_entry->size) &&
((kmem_entry->size < PAGE_SIZE) && (vma_size != PAGE_SIZE))) {
mod_info("kem_entry size(%lu) and vma size do not match(%lu)\n", kmem_entry->size, vma_size);
return -EINVAL;
}
vma->vm_flags |= (VM_RESERVED);
#ifdef pgprot_noncached
// This is coherent memory, so it must not be cached.
// vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
#endif
mod_info_dbg("Mapping address %08lx / PFN %08lx\n",
(long unsigned int)virt_to_phys((void*)kmem_entry->cpua),
page_to_pfn(virt_to_page((void*)kmem_entry->cpua)));
ret = remap_pfn_range_cpua_compat(
vma,
vma->vm_start,
kmem_entry->cpua,
kmem_entry->size,
vma->vm_page_prot );
if (ret) {
mod_info("kmem remap failed: %d (%lx)\n", ret,kmem_entry->cpua);
return -EAGAIN;
}
return ret;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/kmem.h 0000775 0000000 0000000 00000001172 12326537641 0025414 0 ustar 00root root 0000000 0000000 int pcidriver_kmem_alloc( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle );
int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle );
int pcidriver_kmem_sync( pcidriver_privdata_t *privdata, kmem_sync_t *kmem_sync );
int pcidriver_kmem_free_all( pcidriver_privdata_t *privdata );
pcidriver_kmem_entry_t *pcidriver_kmem_find_entry( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle );
pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_id( pcidriver_privdata_t *privdata, int id );
int pcidriver_kmem_free_entry( pcidriver_privdata_t *privdata, pcidriver_kmem_entry_t *kmem_entry );
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/sysfs.c 0000775 0000000 0000000 00000017770 12326537641 0025640 0 ustar 00root root 0000000 0000000 /**
*
* @file sysfs.c
* @brief This file contains the functions providing the SysFS-interface.
* @author Guillermo Marcus
* @date 2010-03-01
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "compat.h"
#include "config.h"
#include "pciDriver.h"
#include "common.h"
#include "umem.h"
#include "kmem.h"
#include "sysfs.h"
static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry);
static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry);
/**
*
* Initializes the sysfs attributes for an kmem/umem-entry
*
*/
static int _pcidriver_sysfs_initialize(pcidriver_privdata_t *privdata,
int id,
struct class_device_attribute *sysfs_attr,
const char *fmtstring,
SYSFS_GET_FUNCTION((*callback)))
{
/* sysfs attributes for kmem buffers don’t make sense before 2.6.13, as
we have no mmap support before */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
char namebuffer[16];
/* allocate space for the name of the attribute */
snprintf(namebuffer, sizeof(namebuffer), fmtstring, id);
if ((sysfs_attr->attr.name = kstrdup(namebuffer, GFP_KERNEL)) == NULL)
return -ENOMEM;
sysfs_attr->attr.mode = S_IRUGO;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35)
/* owner was removed in 2.6.36 */
sysfs_attr->attr.owner = THIS_MODULE;
#endif
sysfs_attr->show = callback;
sysfs_attr->store = NULL;
/* name and add attribute */
if (class_device_create_file(privdata->class_dev, sysfs_attr) != 0)
return -ENXIO; /* Device not configured. Not the really best choice, but hm. */
#endif
return 0;
}
int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr)
{
return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "kbuf%d", pcidriver_show_kmem_entry);
}
int pcidriver_sysfs_initialize_umem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr)
{
return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "umem%d", pcidriver_show_umem_entry);
}
/**
*
* Removes the file from sysfs and frees the allocated (kstrdup()) memory.
*
*/
void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct class_device_attribute *sysfs_attr)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
class_device_remove_file(privdata->class_dev, sysfs_attr);
kfree(sysfs_attr->attr.name);
#endif
}
static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
// pcidriver_privdata_t *privdata = (pcidriver_privdata_t *)cls->class_data;
/* As we can be sure that attr.name contains a filename which we
* created (see _pcidriver_sysfs_initialize), we do not need to have
* sanity checks but can directly call simple_strtol() */
int id = simple_strtol(attr->attr.name + strlen("kbuf"), NULL, 10);
return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id);
#else
return 0;
#endif
}
static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
#if 0
pcidriver_privdata_t *privdata = (pcidriver_privdata_t *)cls->class_data;
return snprintf(buf, PAGE_SIZE, "I am in the umem_entry show function, class_device_kobj_name: %s\n", cls->kobj.name);
#endif
return 0;
#else
return 0;
#endif
}
#ifdef ENABLE_IRQ
SYSFS_GET_FUNCTION(pcidriver_show_irq_count)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
return snprintf(buf, PAGE_SIZE, "%d\n", privdata->irq_count);
}
SYSFS_GET_FUNCTION(pcidriver_show_irq_queues)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
int i, offset;
/* output will be truncated to PAGE_SIZE */
offset = snprintf(buf, PAGE_SIZE, "Queue\tOutstanding IRQs\n");
for (i = 0; i < PCIDRIVER_INT_MAXSOURCES; i++)
offset += snprintf(buf+offset, PAGE_SIZE-offset, "%d\t%d\n", i, atomic_read(&(privdata->irq_outstanding[i])) );
return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
}
#endif
SYSFS_GET_FUNCTION(pcidriver_show_mmap_mode)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_mode);
}
SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
int mode = -1;
/* Set the mmap-mode if it is either PCIDRIVER_MMAP_PCI or PCIDRIVER_MMAP_KMEM */
if (sscanf(buf, "%d", &mode) == 1 &&
(mode == PCIDRIVER_MMAP_PCI || mode == PCIDRIVER_MMAP_KMEM))
privdata->mmap_mode = mode;
return strlen(buf);
}
SYSFS_GET_FUNCTION(pcidriver_show_mmap_area)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_area);
}
SYSFS_SET_FUNCTION(pcidriver_store_mmap_area)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
int temp = -1;
sscanf(buf, "%d", &temp);
if ((temp >= PCIDRIVER_BAR0) && (temp <= PCIDRIVER_BAR5))
privdata->mmap_area = temp;
return strlen(buf);
}
SYSFS_GET_FUNCTION(pcidriver_show_kmem_count)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&(privdata->kmem_count)));
}
SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
kmem_handle_t kmem_handle;
/* FIXME: guillermo: is validation of parsing an unsigned int enough? */
if (sscanf(buf, "%lu", &kmem_handle.size) == 1)
pcidriver_kmem_alloc(privdata, &kmem_handle);
return strlen(buf);
}
SYSFS_SET_FUNCTION(pcidriver_store_kmem_free)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
unsigned int id;
pcidriver_kmem_entry_t *kmem_entry;
/* Parse the ID of the kernel memory to be freed, check bounds */
if (sscanf(buf, "%u", &id) != 1 ||
(id >= atomic_read(&(privdata->kmem_count))))
goto err;
if ((kmem_entry = pcidriver_kmem_find_entry_id(privdata,id)) == NULL)
goto err;
pcidriver_kmem_free_entry(privdata, kmem_entry );
err:
return strlen(buf);
}
SYSFS_GET_FUNCTION(pcidriver_show_kbuffers)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
int offset = 0;
struct list_head *ptr;
pcidriver_kmem_entry_t *entry;
/* print the header */
offset += snprintf(buf, PAGE_SIZE, "kbuf#\tcpu addr\tsize\n");
spin_lock(&(privdata->kmemlist_lock));
list_for_each(ptr, &(privdata->kmem_list)) {
entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
/* print entry info */
if (offset > PAGE_SIZE) {
spin_unlock( &(privdata->kmemlist_lock) );
return PAGE_SIZE;
}
offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%08lx\t%lu\n", entry->id, (unsigned long)(entry->dma_handle), entry->size );
}
spin_unlock(&(privdata->kmemlist_lock));
/* output will be truncated to PAGE_SIZE */
return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
}
SYSFS_GET_FUNCTION(pcidriver_show_umappings)
{
int offset = 0;
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
struct list_head *ptr;
pcidriver_umem_entry_t *entry;
/* print the header */
offset += snprintf(buf, PAGE_SIZE, "umap#\tn_pages\tsg_ents\n");
spin_lock( &(privdata->umemlist_lock) );
list_for_each( ptr, &(privdata->umem_list) ) {
entry = list_entry(ptr, pcidriver_umem_entry_t, list );
/* print entry info */
if (offset > PAGE_SIZE) {
spin_unlock( &(privdata->umemlist_lock) );
return PAGE_SIZE;
}
offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%lu\t%lu\n", entry->id,
(unsigned long)(entry->nr_pages), (unsigned long)(entry->nents));
}
spin_unlock( &(privdata->umemlist_lock) );
/* output will be truncated to PAGE_SIZE */
return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
}
SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap)
{
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
pcidriver_umem_entry_t *umem_entry;
unsigned int id;
if (sscanf(buf, "%u", &id) != 1 ||
(id >= atomic_read(&(privdata->umem_count))))
goto err;
if ((umem_entry = pcidriver_umem_find_entry_id(privdata, id)) == NULL)
goto err;
pcidriver_umem_sgunmap(privdata, umem_entry);
err:
return strlen(buf);
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/sysfs.h 0000775 0000000 0000000 00000002006 12326537641 0025627 0 ustar 00root root 0000000 0000000 #ifndef _PCIDRIVER_SYSFS_H
#define _PCIDRIVER_SYSFS_H
int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr);
int pcidriver_sysfs_initialize_umem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr);
void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct class_device_attribute *sysfs_attr);
#ifdef ENABLE_IRQ
SYSFS_GET_FUNCTION(pcidriver_show_irq_count);
SYSFS_GET_FUNCTION(pcidriver_show_irq_queues);
#endif
/* prototypes for sysfs operations */
SYSFS_GET_FUNCTION(pcidriver_show_mmap_mode);
SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode);
SYSFS_GET_FUNCTION(pcidriver_show_mmap_area);
SYSFS_SET_FUNCTION(pcidriver_store_mmap_area);
SYSFS_GET_FUNCTION(pcidriver_show_kmem_count);
SYSFS_GET_FUNCTION(pcidriver_show_kbuffers);
SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc);
SYSFS_SET_FUNCTION(pcidriver_store_kmem_free);
SYSFS_GET_FUNCTION(pcidriver_show_umappings);
SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap);
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/umem.c 0000775 0000000 0000000 00000031110 12326537641 0025414 0 ustar 00root root 0000000 0000000 /**
*
* @file umem.c
* @brief This file contains the functions handling user space memory.
* @author Guillermo Marcus
* @date 2009-04-05
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "config.h" /* compile-time configuration */
#include "compat.h" /* compatibility definitions for older linux */
#include "pciDriver.h" /* external interface for the driver */
#include "common.h" /* internal definitions for all parts */
#include "umem.h" /* prototypes for kernel memory */
#include "sysfs.h" /* prototypes for sysfs */
/**
*
* Reserve a new scatter/gather list and map it from memory to PCI bus addresses.
*
*/
int pcidriver_umem_sgmap(pcidriver_privdata_t *privdata, umem_handle_t *umem_handle)
{
int i, res, nr_pages;
struct page **pages;
struct scatterlist *sg = NULL;
pcidriver_umem_entry_t *umem_entry;
unsigned int nents;
unsigned long count,offset,length;
/*
* We do some checks first. Then, the following is necessary to create a
* Scatter/Gather list from a user memory area:
* - Determine the number of pages
* - Get the pages for the memory area
* - Lock them.
* - Create a scatter/gather list of the pages
* - Map the list from memory to PCI bus addresses
*
* Then, we:
* - Create an entry on the umem list of the device, to cache the mapping.
* - Create a sysfs attribute that gives easy access to the SG list
*/
/* zero-size?? */
if (umem_handle->size == 0)
return -EINVAL;
/* Direction is better ignoring during mapping. */
/* We assume bidirectional buffers always, except when sync'ing */
/* calculate the number of pages */
nr_pages = ((umem_handle->vma & ~PAGE_MASK) + umem_handle->size + ~PAGE_MASK) >> PAGE_SHIFT;
mod_info_dbg("nr_pages computed: %u\n", nr_pages);
/* Allocate space for the page information */
/* This can be very big, so we use vmalloc */
if ((pages = vmalloc(nr_pages * sizeof(*pages))) == NULL)
return -ENOMEM;
mod_info_dbg("allocated space for the pages.\n");
/* Allocate space for the scatterlist */
/* We do not know how many entries will be, but the maximum is nr_pages. */
/* This can be very big, so we use vmalloc */
if ((sg = vmalloc(nr_pages * sizeof(*sg))) == NULL)
goto umem_sgmap_pages;
sg_init_table(sg, nr_pages);
mod_info_dbg("allocated space for the SG list.\n");
/* Get the page information */
down_read(¤t->mm->mmap_sem);
res = get_user_pages(
current,
current->mm,
umem_handle->vma,
nr_pages,
1,
0, /* do not force, FIXME: shall I? */
pages,
NULL );
up_read(¤t->mm->mmap_sem);
/* Error, not all pages mapped */
if (res < (int)nr_pages) {
mod_info("Could not map all user pages (%d of %d)\n", res, nr_pages);
/* If only some pages could be mapped, we release those. If a real
* error occured, we set nr_pages to 0 */
nr_pages = (res > 0 ? res : 0);
goto umem_sgmap_unmap;
}
mod_info_dbg("Got the pages (%d).\n", res);
/* Lock the pages, then populate the SG list with the pages */
/* page0 is different */
if ( !PageReserved(pages[0]) )
compat_lock_page(pages[0]);
offset = (umem_handle->vma & ~PAGE_MASK);
length = (umem_handle->size > (PAGE_SIZE-offset) ? (PAGE_SIZE-offset) : umem_handle->size);
sg_set_page(&sg[0], pages[0], length, offset);
count = umem_handle->size - length;
for(i=1;i PAGE_SIZE) ? PAGE_SIZE : count), 0);
count -= sg[i].length;
}
/* Use the page list to populate the SG list */
/* SG entries may be merged, res is the number of used entries */
/* We have originally nr_pages entries in the sg list */
if ((nents = pci_map_sg(privdata->pdev, sg, nr_pages, PCI_DMA_BIDIRECTIONAL)) == 0)
goto umem_sgmap_unmap;
mod_info_dbg("Mapped SG list (%d entries).\n", nents);
/* Add an entry to the umem_list of the device, and update the handle with the id */
/* Allocate space for the new umem entry */
if ((umem_entry = kmalloc(sizeof(*umem_entry), GFP_KERNEL)) == NULL)
goto umem_sgmap_entry;
/* Fill entry to be added to the umem list */
umem_entry->id = atomic_inc_return(&privdata->umem_count) - 1;
umem_entry->nr_pages = nr_pages; /* Will be needed when unmapping */
umem_entry->pages = pages;
umem_entry->nents = nents;
umem_entry->sg = sg;
if (pcidriver_sysfs_initialize_umem(privdata, umem_entry->id, &(umem_entry->sysfs_attr)) != 0)
goto umem_sgmap_name_fail;
/* Add entry to the umem list */
spin_lock( &(privdata->umemlist_lock) );
list_add_tail( &(umem_entry->list), &(privdata->umem_list) );
spin_unlock( &(privdata->umemlist_lock) );
/* Update the Handle with the Handle ID of the entry */
umem_handle->handle_id = umem_entry->id;
return 0;
umem_sgmap_name_fail:
kfree(umem_entry);
umem_sgmap_entry:
pci_unmap_sg( privdata->pdev, sg, nr_pages, PCI_DMA_BIDIRECTIONAL );
umem_sgmap_unmap:
/* release pages */
if (nr_pages > 0) {
for(i=0;isysfs_attr));
/* Unmap user memory */
pci_unmap_sg( privdata->pdev, umem_entry->sg, umem_entry->nr_pages, PCI_DMA_BIDIRECTIONAL );
/* Release the pages */
if (umem_entry->nr_pages > 0) {
for(i=0;i<(umem_entry->nr_pages);i++) {
/* Mark pages as Dirty and unlock it */
if ( !PageReserved( umem_entry->pages[i] )) {
SetPageDirty( umem_entry->pages[i] );
compat_unlock_page(umem_entry->pages[i]);
}
/* and release it from the cache */
page_cache_release( umem_entry->pages[i] );
}
}
/* Remove the umem list entry */
spin_lock( &(privdata->umemlist_lock) );
list_del( &(umem_entry->list) );
spin_unlock( &(privdata->umemlist_lock) );
/* Release SG list and page list memory */
/* These two are in the vm area of the kernel */
vfree(umem_entry->pages);
vfree(umem_entry->sg);
/* Release umem_entry memory */
kfree(umem_entry);
return 0;
}
/**
*
* Unmap all scatter/gather lists.
*
*/
int pcidriver_umem_sgunmap_all(pcidriver_privdata_t *privdata)
{
struct list_head *ptr, *next;
pcidriver_umem_entry_t *umem_entry;
/* iterate safely over the entries and delete them */
list_for_each_safe( ptr, next, &(privdata->umem_list) ) {
umem_entry = list_entry(ptr, pcidriver_umem_entry_t, list );
pcidriver_umem_sgunmap( privdata, umem_entry ); /* spin lock inside! */
}
return 0;
}
/**
*
* Copies the scatter/gather list from kernelspace to userspace.
*
*/
int pcidriver_umem_sgget(pcidriver_privdata_t *privdata, umem_sglist_t *umem_sglist)
{
int i;
pcidriver_umem_entry_t *umem_entry;
struct scatterlist *sg;
int idx = 0;
dma_addr_t cur_addr;
unsigned int cur_size;
/* Find the associated umem_entry for this buffer */
umem_entry = pcidriver_umem_find_entry_id( privdata, umem_sglist->handle_id );
if (umem_entry == NULL)
return -EINVAL; /* umem_handle is not valid */
/* Check if passed SG list is enough */
if (umem_sglist->nents < umem_entry->nents)
return -EINVAL; /* sg has not enough entries */
/* Copy the SG list to the user format */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
if (umem_sglist->type == PCIDRIVER_SG_MERGED) {
for_each_sg(umem_entry->sg, sg, umem_entry->nents, i ) {
if (i==0) {
umem_sglist->sg[0].addr = sg_dma_address( sg );
umem_sglist->sg[0].size = sg_dma_len( sg );
idx = 0;
}
else {
cur_addr = sg_dma_address( sg );
cur_size = sg_dma_len( sg );
/* Check if entry fits after current entry */
if (cur_addr == (umem_sglist->sg[idx].addr + umem_sglist->sg[idx].size)) {
umem_sglist->sg[idx].size += cur_size;
continue;
}
/* Skip if the entry is zero-length (yes, it can happen.... at the end of the list) */
if (cur_size == 0)
continue;
/* None of the above, add new entry */
idx++;
umem_sglist->sg[idx].addr = cur_addr;
umem_sglist->sg[idx].size = cur_size;
}
}
/* Set the used size of the SG list */
umem_sglist->nents = idx+1;
} else {
for_each_sg(umem_entry->sg, sg, umem_entry->nents, i ) {
mod_info("entry: %d\n",i);
umem_sglist->sg[i].addr = sg_dma_address( sg );
umem_sglist->sg[i].size = sg_dma_len( sg );
}
/* Set the used size of the SG list */
/* Check if the last one is zero-length */
if ( umem_sglist->sg[ umem_entry->nents - 1].size == 0)
umem_sglist->nents = umem_entry->nents -1;
else
umem_sglist->nents = umem_entry->nents;
}
#else
if (umem_sglist->type == PCIDRIVER_SG_MERGED) {
/* Merge entries that are contiguous into a single entry */
/* Non-optimal but fast for most cases */
/* First one always true */
sg=umem_entry->sg;
umem_sglist->sg[0].addr = sg_dma_address( sg );
umem_sglist->sg[0].size = sg_dma_len( sg );
sg++;
idx = 0;
/* Iterate over the SG entries */
for(i=1; i< umem_entry->nents; i++, sg++ ) {
cur_addr = sg_dma_address( sg );
cur_size = sg_dma_len( sg );
/* Check if entry fits after current entry */
if (cur_addr == (umem_sglist->sg[idx].addr + umem_sglist->sg[idx].size)) {
umem_sglist->sg[idx].size += cur_size;
continue;
}
/* Skip if the entry is zero-length (yes, it can happen.... at the end of the list) */
if (cur_size == 0)
continue;
/* None of the above, add new entry */
idx++;
umem_sglist->sg[idx].addr = cur_addr;
umem_sglist->sg[idx].size = cur_size;
}
/* Set the used size of the SG list */
umem_sglist->nents = idx+1;
} else {
/* Assume pci_map_sg made a good job (ehem..) and just copy it.
* actually, now I assume it just gives them plainly to me. */
for(i=0, sg=umem_entry->sg ; i< umem_entry->nents; i++, sg++ ) {
umem_sglist->sg[i].addr = sg_dma_address( sg );
umem_sglist->sg[i].size = sg_dma_len( sg );
}
/* Set the used size of the SG list */
/* Check if the last one is zero-length */
if ( umem_sglist->sg[ umem_entry->nents - 1].size == 0)
umem_sglist->nents = umem_entry->nents -1;
else
umem_sglist->nents = umem_entry->nents;
}
#endif
return 0;
}
/**
*
* Sync user space memory from/to device
*
*/
int pcidriver_umem_sync( pcidriver_privdata_t *privdata, umem_handle_t *umem_handle )
{
pcidriver_umem_entry_t *umem_entry;
/* Find the associated umem_entry for this buffer */
umem_entry = pcidriver_umem_find_entry_id( privdata, umem_handle->handle_id );
if (umem_entry == NULL)
return -EINVAL; /* umem_handle is not valid */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
switch (umem_handle->dir) {
case PCIDRIVER_DMA_TODEVICE:
pci_dma_sync_sg_for_device( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_TODEVICE );
break;
case PCIDRIVER_DMA_FROMDEVICE:
pci_dma_sync_sg_for_cpu( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_FROMDEVICE );
break;
case PCIDRIVER_DMA_BIDIRECTIONAL:
pci_dma_sync_sg_for_device( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_BIDIRECTIONAL );
pci_dma_sync_sg_for_cpu( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_BIDIRECTIONAL );
break;
default:
return -EINVAL; /* wrong direction parameter */
}
#else
switch (umem_handle->dir) {
case PCIDRIVER_DMA_TODEVICE:
pci_dma_sync_sg( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_TODEVICE );
break;
case PCIDRIVER_DMA_FROMDEVICE:
pci_dma_sync_sg( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_FROMDEVICE );
break;
case PCIDRIVER_DMA_BIDIRECTIONAL:
pci_dma_sync_sg( privdata->pdev, umem_entry->sg, umem_entry->nents, PCI_DMA_BIDIRECTIONAL );
break;
default:
return -EINVAL; /* wrong direction parameter */
}
#endif
return 0;
}
/*
*
* Get the pcidriver_umem_entry_t structure for the given id.
*
* @param id ID of the umem entry to search for
*
*/
pcidriver_umem_entry_t *pcidriver_umem_find_entry_id(pcidriver_privdata_t *privdata, int id)
{
struct list_head *ptr;
pcidriver_umem_entry_t *entry;
spin_lock(&(privdata->umemlist_lock));
list_for_each(ptr, &(privdata->umem_list)) {
entry = list_entry(ptr, pcidriver_umem_entry_t, list );
if (entry->id == id) {
spin_unlock( &(privdata->umemlist_lock) );
return entry;
}
}
spin_unlock(&(privdata->umemlist_lock));
return NULL;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/drivers/pcie/src/umem.h 0000775 0000000 0000000 00000000711 12326537641 0025424 0 ustar 00root root 0000000 0000000 int pcidriver_umem_sgmap( pcidriver_privdata_t *privdata, umem_handle_t *umem_handle );
int pcidriver_umem_sgunmap( pcidriver_privdata_t *privdata, pcidriver_umem_entry_t *umem_entry );
int pcidriver_umem_sgget( pcidriver_privdata_t *privdata, umem_sglist_t *umem_sglist );
int pcidriver_umem_sync( pcidriver_privdata_t *privdata, umem_handle_t *umem_handle );
pcidriver_umem_entry_t *pcidriver_umem_find_entry_id( pcidriver_privdata_t *privdata, int id );
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/ 0000775 0000000 0000000 00000000000 12326537641 0022544 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/pcie/ 0000775 0000000 0000000 00000000000 12326537641 0023464 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/pcie/driver/ 0000775 0000000 0000000 00000000000 12326537641 0024757 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/pcie/driver/pciDriver.h 0000775 0000000 0000000 00000012050 12326537641 0027060 0 ustar 00root root 0000000 0000000 #ifndef PCIDRIVER_H_
#define PCIDRIVER_H_
/**
* This is a full rewrite of the pciDriver.
* New default is to support kernel 2.6, using kernel 2.6 APIs.
*
* This header defines the interface to the outside world.
*
* $Revision: 1.6 $
* $Date: 2008-01-24 14:21:36 $
*
*/
/*
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.5 2008-01-11 10:15:14 marcus
* Removed unused interrupt code.
* Added intSource to the wait interrupt call.
*
* Revision 1.4 2006/11/17 18:44:42 marcus
* Type of SG list can now be selected at runtime. Added type to sglist.
*
* Revision 1.3 2006/11/17 16:23:02 marcus
* Added slot number to the PCI info IOctl.
*
* Revision 1.2 2006/11/13 12:29:09 marcus
* Added a IOctl call, to confiure the interrupt response. (testing pending).
* Basic interrupts are now supported.
*
* Revision 1.1 2006/10/10 14:46:52 marcus
* Initial commit of the new pciDriver for kernel 2.6
*
* Revision 1.7 2006/10/06 15:18:06 marcus
* Updated PCI info and PCI cmd
*
* Revision 1.6 2006/09/25 16:51:07 marcus
* Added PCI config IOctls, and implemented basic mmap functions.
*
* Revision 1.5 2006/09/18 17:13:12 marcus
* backup commit.
*
* Revision 1.4 2006/09/15 15:44:41 marcus
* backup commit.
*
* Revision 1.3 2006/08/15 11:40:02 marcus
* backup commit.
*
* Revision 1.2 2006/08/12 18:28:42 marcus
* Sync with the laptop
*
* Revision 1.1 2006/08/11 15:30:46 marcus
* Sync with the laptop
*
*/
#include
/* Possible values for ioctl commands */
/* PCI mmap areas */
#define PCIDRIVER_BAR0 0
#define PCIDRIVER_BAR1 1
#define PCIDRIVER_BAR2 2
#define PCIDRIVER_BAR3 3
#define PCIDRIVER_BAR4 4
#define PCIDRIVER_BAR5 5
/* mmap mode of the device */
#define PCIDRIVER_MMAP_PCI 0
#define PCIDRIVER_MMAP_KMEM 1
/* Direction of a DMA operation */
#define PCIDRIVER_DMA_BIDIRECTIONAL 0
#define PCIDRIVER_DMA_TODEVICE 1
#define PCIDRIVER_DMA_FROMDEVICE 2
/* Possible sizes in a PCI command */
#define PCIDRIVER_PCI_CFG_SZ_BYTE 1
#define PCIDRIVER_PCI_CFG_SZ_WORD 2
#define PCIDRIVER_PCI_CFG_SZ_DWORD 3
/* Possible types of SG lists */
#define PCIDRIVER_SG_NONMERGED 0
#define PCIDRIVER_SG_MERGED 1
/* Maximum number of interrupt sources */
#define PCIDRIVER_INT_MAXSOURCES 16
/* Types */
typedef struct {
unsigned long pa;
unsigned long size;
int handle_id;
} kmem_handle_t;
typedef struct {
unsigned long addr;
unsigned long size;
} umem_sgentry_t;
typedef struct {
int handle_id;
int type;
int nents;
umem_sgentry_t *sg;
} umem_sglist_t;
typedef struct {
unsigned long vma;
unsigned long size;
int handle_id;
int dir;
} umem_handle_t;
typedef struct {
kmem_handle_t handle;
int dir;
} kmem_sync_t;
typedef struct {
int size;
int addr;
union {
unsigned char byte;
unsigned short word;
unsigned int dword; /* not strict C, but if not can have problems */
} val;
} pci_cfg_cmd;
typedef struct {
unsigned short vendor_id;
unsigned short device_id;
unsigned short bus;
unsigned short slot;
unsigned short devfn;
unsigned char interrupt_pin;
unsigned char interrupt_line;
unsigned int irq;
unsigned long bar_start[6];
unsigned long bar_length[6];
} pci_board_info;
/* ioctl interface */
/* See documentation for a detailed usage explanation */
/*
* one of the problems of ioctl, is that requires a type definition.
* This type is only 8-bits wide, and half-documented in
* /Documentation/ioctl-number.txt.
* previous SHL -> 'S' definition, conflicts with several devices,
* so I changed it to be pci -> 'p', in the range 0xA0-AF
*/
#define PCIDRIVER_IOC_MAGIC 'p'
#define PCIDRIVER_IOC_BASE 0xB0
#define PCIDRIVER_IOC_MMAP_MODE _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 0 )
#define PCIDRIVER_IOC_MMAP_AREA _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 1 )
#define PCIDRIVER_IOC_KMEM_ALLOC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 2, kmem_handle_t * )
#define PCIDRIVER_IOC_KMEM_FREE _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 3, kmem_handle_t * )
#define PCIDRIVER_IOC_KMEM_SYNC _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 4, kmem_sync_t * )
#define PCIDRIVER_IOC_UMEM_SGMAP _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 5, umem_handle_t * )
#define PCIDRIVER_IOC_UMEM_SGUNMAP _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 6, umem_handle_t * )
#define PCIDRIVER_IOC_UMEM_SGGET _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 7, umem_sglist_t * )
#define PCIDRIVER_IOC_UMEM_SYNC _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 8, umem_handle_t * )
#define PCIDRIVER_IOC_WAITI _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 9 )
/* And now, the methods to access the PCI configuration area */
#define PCIDRIVER_IOC_PCI_CFG_RD _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 10, pci_cfg_cmd * )
#define PCIDRIVER_IOC_PCI_CFG_WR _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 11, pci_cfg_cmd * )
#define PCIDRIVER_IOC_PCI_INFO _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 12, pci_board_info * )
/* Clear interrupt queues */
#define PCIDRIVER_IOC_CLEAR_IOQ _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 13 )
#endif
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/pcie/lib/ 0000775 0000000 0000000 00000000000 12326537641 0024232 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/pcie/lib/Exception.h 0000775 0000000 0000000 00000002531 12326537641 0026345 0 ustar 00root root 0000000 0000000 #ifndef PCIDRIVER_EXCEPTION_H_
#define PCIDRIVER_EXCEPTION_H_
/********************************************************************
*
* October 10th, 2006
* Guillermo Marcus - Universitaet Mannheim
*
* $Revision: 1.3 $
* $Date: 2008-01-11 10:06:09 $
*
*******************************************************************/
/*******************************************************************
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.2 2007-02-09 17:01:28 marcus
* Added Exception as part of the standard exception hierarchy.
* Simplified description handling, now using an array.
*
* Revision 1.1 2006/10/13 17:18:33 marcus
* Implemented and tested most of C++ interface.
*
*******************************************************************/
#include
namespace pciDriver {
class Exception : public std::exception {
protected:
int type;
public:
enum Type {
UNKNOWN,
DEVICE_NOT_FOUND,
INVALID_BAR,
INTERNAL_ERROR,
OPEN_FAILED,
NOT_OPEN,
MMAP_FAILED,
ALLOC_FAILED,
SGMAP_FAILED,
INTERRUPT_FAILED
};
static const char* descriptions[];
Exception(Type t) : type(t) {}
inline int getType() { return type; }
char const *toString() { return descriptions[type]; }
virtual const char* what() const throw() { return descriptions[type]; }
};
}
#endif /*PCIDRIVER_EXCEPTION_H_*/
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/pcie/lib/KernelMemory.h 0000775 0000000 0000000 00000002066 12326537641 0027023 0 ustar 00root root 0000000 0000000 #ifndef KERNELMEMORY_H_
#define KERNELMEMORY_H_
/********************************************************************
*
* October 10th, 2006
* Guillermo Marcus - Universitaet Mannheim
*
* $Revision: 1.1 $
* $Date: 2006-10-13 17:18:34 $
*
*******************************************************************/
#include "PciDevice.h"
namespace pciDriver {
class KernelMemory {
friend class PciDevice;
protected:
unsigned long pa;
unsigned long size;
int handle_id;
void *mem;
PciDevice *device;
KernelMemory(PciDevice& device, unsigned int size);
public:
~KernelMemory();
/**
*
* @returns the physical address of the kernel memory.
*
*/
inline unsigned long getPhysicalAddress() { return pa; }
/**
*
* @returns the size of the kernel memory.
*
*/
inline unsigned long getSize() { return size; }
/**
*
* @returns the pointer to the memory.
*
*/
inline void *getBuffer() { return mem; }
enum sync_dir {
BIDIRECTIONAL = 0,
TO_DEVICE = 1,
FROM_DEVICE = 2
};
void sync(sync_dir dir);
};
}
#endif /*KERNELMEMORY_H_*/
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/pcie/lib/PciDevice.h 0000775 0000000 0000000 00000004523 12326537641 0026245 0 ustar 00root root 0000000 0000000 #ifndef PD_PCIDEVICE_H_
#define PD_PCIDEVICE_H_
/********************************************************************
*
* October 10th, 2006
* Guillermo Marcus - Universitaet Mannheim
*
* $Revision: 1.5 $
* $Date: 2008-01-24 14:21:36 $
*
*******************************************************************/
/*******************************************************************
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.4 2008-01-11 10:14:21 marcus
* Added intSource to the interrupt wait function.
*
* Revision 1.3 2006/11/17 18:51:08 marcus
* Support both types of SG-lists at runtime.
*
* Revision 1.2 2006/11/17 16:51:05 marcus
* Added page info values, and functions to get the bus and slot of a device,
* required for compatibility with the uelib.
*
* Revision 1.1 2006/10/13 17:18:34 marcus
* Implemented and tested most of C++ interface.
*
*******************************************************************/
#include
namespace pciDriver {
// Forward references
class KernelMemory;
class UserMemory;
class PciDevice {
private:
unsigned int pagesize;
unsigned int pageshift;
unsigned int pagemask;
protected:
int handle;
int device;
char name[50];
pthread_mutex_t mmap_mutex;
public:
PciDevice(int number);
~PciDevice();
void open();
void close();
int getHandle();
unsigned short getBus();
unsigned short getSlot();
KernelMemory& allocKernelMemory( unsigned int size );
UserMemory& mapUserMemory( void *mem, unsigned int size, bool merged );
inline UserMemory& mapUserMemory( void *mem, unsigned int size )
{ return mapUserMemory(mem,size,true); }
inline void mmap_lock() { pthread_mutex_lock( &mmap_mutex ); }
inline void mmap_unlock() { pthread_mutex_unlock( &mmap_mutex ); }
void waitForInterrupt(unsigned int int_id);
void clearInterruptQueue(unsigned int int_id);
unsigned int getBARsize(unsigned int bar);
void *mapBAR(unsigned int bar);
void unmapBAR(unsigned int bar, void *ptr);
unsigned char readConfigByte(unsigned int addr);
unsigned short readConfigWord(unsigned int addr);
unsigned int readConfigDWord(unsigned int addr);
void writeConfigByte(unsigned int addr, unsigned char val);
void writeConfigWord(unsigned int addr, unsigned short val);
void writeConfigDWord(unsigned int addr, unsigned int val);
};
}
#endif /*PD_PCIDEVICE_H_*/
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/pcie/lib/UserMemory.h 0000775 0000000 0000000 00000002534 12326537641 0026521 0 ustar 00root root 0000000 0000000 #ifndef USERMEMORY_H_
#define USERMEMORY_H_
/********************************************************************
*
* October 10th, 2006
* Guillermo Marcus - Universitaet Mannheim
*
* $Revision: 1.2 $
* $Date: 2006-11-17 18:50:17 $
*
*******************************************************************/
/*******************************************************************
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.1 2006/10/13 17:18:34 marcus
* Implemented and tested most of C++ interface.
*
*******************************************************************/
#include "PciDevice.h"
namespace pciDriver {
class UserMemory {
friend class PciDevice;
private:
struct sg_entry {
unsigned long addr;
unsigned long size;
};
protected:
unsigned long vma;
unsigned long size;
int handle_id;
PciDevice *device;
int nents;
struct sg_entry *sg;
UserMemory(PciDevice& device, void *mem, unsigned int size, bool merged );
public:
~UserMemory();
enum sync_dir {
BIDIRECTIONAL = 0,
TO_DEVICE = 1,
FROM_DEVICE = 2
};
void sync(sync_dir dir);
inline unsigned int getSGcount() { return nents; }
inline unsigned long getSGentryAddress(unsigned int entry ) { return sg[entry].addr; }
inline unsigned long getSGentrySize(unsigned int entry ) { return sg[entry].size; }
};
}
#endif /*USERMEMORY_H_*/
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/pcie/lib/pciDriver.h 0000775 0000000 0000000 00000007311 12326537641 0026337 0 ustar 00root root 0000000 0000000 #ifndef LIBPCIDRIVER_H_
#define LIBPCIDRIVER_H_
/*******************************************************************
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.6 2008-01-11 10:07:53 marcus
* Removed unused int code.
* Modified int wait call to include the intSource to wait for. (experimental for cocurrent interrupts support).
*
* Revision 1.5 2007/02/09 16:59:52 marcus
* Added interrupt descriptor and related function.
*
* Revision 1.4 2006/11/13 16:44:51 marcus
* Added direction values as define's.
*
* Revision 1.3 2006/10/16 16:57:43 marcus
* Added nice comment at the start.
*
*******************************************************************/
#include
/* Both APIs are in a single header */
/***********************************************************************************
* This is the C API
***********************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/* Data types */
typedef struct {
int handle; /* PCI device handle */
int device; /* Device ID number */
char name[50]; /* Device Name (node) used */
pthread_mutex_t mmap_mutex; /* Mmap mutex used by the device */
} pd_device_t;
/* All Data types are redefined in the C API, even if they match the native driver interface */
typedef struct {
unsigned long pa;
unsigned long size;
void *mem;
int handle_id;
pd_device_t *pci_handle;
} pd_kmem_t;
typedef struct {
unsigned long addr;
unsigned long size;
} pd_umem_sgentry_t;
typedef struct {
unsigned long vma;
unsigned long size;
int handle_id;
int nents;
pd_umem_sgentry_t *sg;
pd_device_t *pci_handle;
} pd_umem_t;
/* Direction of a Sync operation */
#define PD_DIR_BIDIRECTIONAL 0
#define PD_DIR_TODEVICE 1
#define PD_DIR_FROMDEVICE 2
int pd_open( int dev, pd_device_t *pci_handle, char *dev_entry );
int pd_close( pd_device_t *pci_handle );
/* Kernel Memory Functions */
void *pd_allocKernelMemory( pd_device_t *pci_handle, unsigned int size, pd_kmem_t *kmem_handle );
int pd_freeKernelMemory( pd_kmem_t *kmem_handle );
/* User Memory Functions */
int pd_mapUserMemory( pd_device_t *pci_handle, void *mem, unsigned int size, pd_umem_t *umem_handle );
int pd_unmapUserMemory( pd_umem_t *umem_handle );
/* Sync Functions */
int pd_syncKernelMemory( pd_kmem_t *kmem_handle, int dir );
int pd_syncUserMemory( pd_umem_t *umem_handle, int dir );
/* Interrupt Function */
int pd_waitForInterrupt(pd_device_t *pci_handle , unsigned int int_id );
int pd_clearInterruptQueue(pd_device_t *pci_handle , unsigned int int_id );
/* PCI Functions */
int pd_getID( pd_device_t *pci_handle );
int pd_getBARsize( pd_device_t *pci_handle, unsigned int bar );
void *pd_mapBAR( pd_device_t *pci_handle, unsigned int bar );
int pd_unmapBAR( pd_device_t *pci_handle, unsigned int bar, void *ptr );
unsigned char pd_readConfigByte( pd_device_t *pci_handle, unsigned int addr );
unsigned short pd_readConfigWord( pd_device_t *pci_handle, unsigned int addr );
unsigned int pd_readConfigDWord( pd_device_t *pci_handle, unsigned int addr );
int pd_writeConfigByte( pd_device_t *pci_handle, unsigned int addr, unsigned char val );
int pd_writeConfigWord( pd_device_t *pci_handle, unsigned int addr, unsigned short val );
int pd_writeConfigDWord( pd_device_t *pci_handle, unsigned int addr, unsigned int val );
#ifdef __cplusplus
}
#endif
/***********************************************************************************
* This is the C++ API
***********************************************************************************/
#ifdef __cplusplus
#include "Exception.h"
#include "PciDevice.h"
#include "KernelMemory.h"
#include "UserMemory.h"
#include "pciDriver_compat.h"
#endif
#endif /*LIBPCIDRIVER_H_*/
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/include/pcie/lib/pciDriver_compat.h 0000775 0000000 0000000 00000013344 12326537641 0027705 0 ustar 00root root 0000000 0000000 #ifndef PCIDRIVER_COMPAT_H_
#define PCIDRIVER_COMPAT_H_
/***********************************************************************************
* C++ API compatible with older pciDriver interfaces
* Do not use for new designs!
*
* $Revision: 1.3 $
* $Date: 2006-11-17 18:53:23 $
*
***********************************************************************************/
/***********************************************************************************
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.2 2006/11/13 12:29:49 marcus
* Backup commit. Compatibility section still requires testing.
*
* Revision 1.1 2006/10/10 14:46:49 marcus
* Initial commit of the new pciDriver for kernel 2.6
*
***********************************************************************************/
// Some needed forward references
namespace pciDriver {
class KernelMemory;
class UserMemory;
class PciDevice;
}
#ifndef KMEM_H
#define KMEM_H
/** This class is the main interface to allocate kernel memory
* with the driver. It performes ioctl calls to allocate and
* free the memory and mapps it into the user space.
*/
class KMem {
public:
/** The standard constructor.
* Initialises data.
*/
KMem();
/** The standard destructor.
* Ensure data is properly released.
*/
~KMem();
/** Constructor which initialises with allocated kernel memory.
* @param handle The device driver handle
* @param order The memory size in powers of 2
*/
KMem(int handle, int order);
/** Allocate kernel memory.
* @param handle The device driver handle
* @param order The memory size in powers of 2
* @return Integer 1 on success, 0 else.
*/
int Alloc(int handle, int order);
/** Free the kernel memory
* @return Integer 1 on success, 0 else.
*/
int Free(void);
/** Get the physical address of the allocated buffer
* @return The physical address of the buffer
*/
unsigned long GetPhysicalAddress(void);
/** Get the buffer address
* @return The virtual address of the buffer
*/
unsigned int *GetBuffer(void);
void Sync(void);
protected:
pciDriver::KernelMemory *km;
};
#endif /* KMEM_H */
#ifndef MEMORYPAGELIST_H
#define MEMORYPAGELIST_H
class MemoryPageList {
public:
/// The standard constructor
MemoryPageList();
/// The standard destructor
~MemoryPageList();
/** A constructor which builds up the pagelist for a
* given buffer.
* @param handle The device driver handle
* @param buffer Pointer which contains the virtual address of the buffer
* @param size The buffer size in byte
*/
MemoryPageList(int handle, unsigned int *buffer, unsigned int size);
/** Lock AND build up the list of buffer pages.
* @param handle The device driver handle
* @param buffer Pointer which contains the virtual address of the buffer
* @param size The buffer size in byte
* @return True on success, else false
*/
bool LockBuffer(int handle, unsigned int *buffer, unsigned int size);
/** Unlock the buffer
* @return True on success, else false
*/
bool UnlockBuffer(void);
/** Check if this page list is accociated to a buffer.
* @return True if this object contains a page list, else false
*/
bool IsUsed(void);
/** Get the size of the pagelist.
* @return The number of pages, 0 if no pagelist exists
*/
unsigned int GetNumberOfPages(void);
/** returns the physical addresses of the pages.
@param index The number of the buffer page
@return The physical address or 0 if the pagelist is not in use
*/
unsigned int GetPhysicalAddress(unsigned int index);
/// Access to the physical addresses of the pages.
unsigned int operator[] (unsigned int index);
/// Get the offset in the first page
unsigned int GetFirstPageOffset(void);
void Sync(void);
protected:
pciDriver::UserMemory *um;
int pagesize;
int pageshift;
};
#endif /* MEMORYPAGELIST_H */
#ifndef PCIDEVICE_H
#define PCIDEVICE_H
// --------x----------------------------x-----------------------------------x--
/** Class PciDevice
* This class represents a PCI device. It can open and close the device
* driver and get the user memory mapped PCI areas.
*/
class PciDevice {
public:
/** Standard constructor
Initialises data.*/
PciDevice();
/** Standard destructor
Initialises data.*/
~PciDevice();
/** Open the driver to accesss a device. Initialise data.
* @param deviceNr The logical number of the device to open.
* @return Integer 1 on success.
*/
int Open(unsigned int deviceNr);
/** Close the device driver. */
int Close(void);
/** Get access to a PCI memory bar which is mapped in user memory.
@return The virtual pointer to the PCI memory bar.
*/
volatile unsigned int *GetBarAccess(unsigned int barNr);
/** Checks if the driver is open.
* @return True if the driver is open else false.
*/
bool IsOpen(void);
unsigned char ReadConfigByte(unsigned int address);
unsigned short ReadConfigWord(unsigned int address);
unsigned int ReadConfigDWord(unsigned int address);
void WriteConfigByte(unsigned int address, unsigned char val);
void WriteConfigWord(unsigned int address, unsigned short val);
void WriteConfigDWord(unsigned int address, unsigned int val);
unsigned int GetBus(void);
unsigned int GetSlot(void);
unsigned short GetVendorId(void);
unsigned short GetDeviceId(void);
/** Performs a cast operation to an int to get easy access to the
* device handle.
*/
operator int();
static int GetNumberOfDevices(void);
protected:
pciDriver::PciDevice *dev;
int dev_number;
void *bar[6];
};
#endif /* PCIDEVICE_H */
#endif /*PCIDRIVER_COMPAT_H_*/
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/lib/ 0000775 0000000 0000000 00000000000 12326537641 0021667 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/lib/pcie/ 0000775 0000000 0000000 00000000000 12326537641 0022607 5 ustar 00root root 0000000 0000000 bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/lib/pcie/.gitignore 0000775 0000000 0000000 00000000073 12326537641 0024602 0 ustar 00root root 0000000 0000000 #editor backup files
*~
#makefile generated
*.o
*.so
*.a
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/lib/pcie/Exception.cpp 0000775 0000000 0000000 00000001074 12326537641 0025256 0 ustar 00root root 0000000 0000000 /*******************************************************************
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.1 2006/10/13 17:18:32 marcus
* Implemented and tested most of C++ interface.
*
*******************************************************************/
#include "Exception.h"
using namespace pciDriver;
const char* Exception::descriptions[] = {
"Unknown Exception",
"Device Not Found",
"Invalid BAR",
"Internal Error",
"Open failed",
"Not Open",
"Mmap failed",
"Alloc failed",
"SGmap failed",
"Interrupt failed"
};
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/lib/pcie/KernelMemory.cpp 0000775 0000000 0000000 00000005515 12326537641 0025735 0 ustar 00root root 0000000 0000000 /**
*
* @file KernelMemory.cpp
* @author Guillermo Marcus
* @date 2009-04-05
* @brief KernelMemory class implementation.
*
*/
/*******************************************************************
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.3 2007-02-09 17:02:38 marcus
* Modified Exception handling, made simpler and more standard.
*
* Revision 1.2 2006/10/30 19:39:50 marcus
* Renamed variable to avoid confusions.
*
* Revision 1.1 2006/10/13 17:18:32 marcus
* Implemented and tested most of C++ interface.
*
*******************************************************************/
#include "KernelMemory.h"
#include "Exception.h"
#include "driver/pciDriver.h"
#include
#include
using namespace pciDriver;
/**
*
* Constructor of a KernelMemory object, allocates kernel memory of the specified
* size and mmaps it.
*
* @param size How much memory to allocate
*
*/
KernelMemory::KernelMemory(PciDevice& dev, unsigned int size)
{
void *m_ptr;
kmem_handle_t kh;
int dev_handle;
dev_handle = dev.getHandle();
this->device = &dev;
this->size = size;
/* Allocate */
kh.size = size;
if (ioctl(dev_handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh) != 0)
throw Exception(Exception::ALLOC_FAILED);
handle_id = kh.handle_id;
pa = kh.pa;
/* Mmap */
/* This is not fully safe, as a separate process can still open the device independently.
* That will use a separate mutex and the race condition can arise.
* Posible fix: Do not allow the driver for mutliple openings of a device */
device->mmap_lock();
if (ioctl(dev_handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_KMEM) != 0)
goto pd_allockm_err;
m_ptr = mmap( 0, size, PROT_WRITE | PROT_READ, MAP_SHARED, dev_handle, 0 );
if ((m_ptr == MAP_FAILED) || (m_ptr == NULL))
goto pd_allockm_err;
this->mem = m_ptr;
device->mmap_unlock();
/* Success, Object created successfully */
return;
/* On error, unlock, deallocate buffer and throw an exception */
pd_allockm_err:
device->mmap_unlock();
ioctl(dev_handle, PCIDRIVER_IOC_KMEM_FREE, &kh);
throw Exception(Exception::ALLOC_FAILED);
}
/**
*
* Destructor of KernelMemory, unmaps the memory and frees it.
*
*/
KernelMemory::~KernelMemory()
{
kmem_handle_t kh;
/* Unmap */
munmap(this->mem, this->size);
/* Free buffer */
kh.handle_id = handle_id;
kh.size = size;
kh.pa = pa;
if (ioctl(device->getHandle(), PCIDRIVER_IOC_KMEM_FREE, &kh) != 0)
throw Exception(Exception::INTERNAL_ERROR);
}
/**
*
* Syncs the kernel memory to the device.
*
*/
void KernelMemory::sync(sync_dir dir)
{
kmem_sync_t ks;
ks.handle.handle_id = handle_id;
ks.handle.pa = pa;
ks.handle.size = size;
/* We assume (C++ API) dir === (Driver API) dir */
ks.dir = dir;
if (ioctl(device->getHandle(), PCIDRIVER_IOC_KMEM_SYNC, &ks) != 0)
throw Exception(Exception::INTERNAL_ERROR);
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/lib/pcie/Makefile 0000775 0000000 0000000 00000003403 12326537641 0024252 0 ustar 00root root 0000000 0000000 # Makefile for the pciDriver library
CC = gcc
CXX = g++
CFLAGS += -O2 -g -fPIC
CXXFLAGS += -O2 -g -fPIC
# Source files in this directory
SRC = $(wildcard *.cpp)
SRCC = $(wildcard *.c)
# Corresponding object file
OBJ = $(SRC:.cpp=.o)
OBJ += $(SRCC:.c=.o)
LIB ?= libpcidriver.so
LIBSTATIC ?= libpcidriver.a
INCDIR =../../include/pcie
INCDIR +=../../include/pcie/lib
INC = $(INCDIR)/%.h
LDINC += -L $(realpath .)
CFLAGS += $(addprefix -I, $(INCDIR))
CXXFLAGS += $(addprefix -I,i $(INCDIR))
###############################################################
# Target definitions
.PHONY: all clean
all: $(LIB) $(LIBSTATIC)
# Target for dynamic the library
$(LIB): $(OBJ)
@echo "## Creating dynamic library ##"
@echo -e "LD [.so] \t$@"
$(Q)$(CXX) -shared $(LDINC) $(LDFLAGS) $(CXXFLAGS) -o $@ $^
# Target for static the library
$(LIBSTATIC): $(OBJ)
@echo "## Creating static library ##"
@echo -e "LD [.a] \t$@"
$(Q)ar -r $(LIBSTATIC) $^
$(Q)ar -s $(LIBSTATIC)
%.o: %.cpp $(INC)
@echo -e "CC \t$<"
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o: %.c $(INC)
@echo -e "CC \t$<"
$(CC) $(CFLAGS) -c -o $@ $<
install:
@echo "INSTALL libpcidriver.so"
-$(Q)install -m 755 $(LIB) /usr/lib/
@echo "INSTALL libpcidriver.a"
-$(Q)install -m 755 $(LIBSTATIC) /usr/lib/
@echo "INSTALL /usr/include/pciDriver/lib"
-$(Q)mkdir -p /usr/include/pciDriver/lib
-$(Q)install -D -m 644 ../../include/pcie/lib/*.h /usr/include/pciDriver/lib
uninstall:
@echo "UNINSTALL libpcidriver.so"
-$(Q)rm -f /usr/lib/libpcidriver.so
@echo "UNINSTALL libpcidriver.a"
-$(Q)rm -f /usr/lib/libpcidriver.a
@echo "UNINSTALL /usr/include/pciDriver/lib"
-$(Q)rm -rf /usr/include/pciDriver/lib
-$(Q)rmdir /usr/include/pciDriver
clean:
@echo -e "CLEAN \t$(shell pwd)"
-$(Q)rm -f $(LIB) $(LIBSTATIC)
-$(Q)rm -f $(OBJ)
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/lib/pcie/PciDevice.cpp 0000775 0000000 0000000 00000017535 12326537641 0025164 0 ustar 00root root 0000000 0000000 /**
*
* @file PciDevice.cpp
* @author Guillermo Marcus
* @date 2009-04-05
* @brief Represents the PCI device.
*
*/
/*******************************************************************
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.4 2008-01-11 10:15:59 marcus
* Added intSource to the Wait for Interrupt call.
*
* Revision 1.3 2007/02/09 17:02:39 marcus
* Modified Exception handling, made simpler and more standard.
*
* Revision 1.2 2006/11/17 18:59:57 marcus
* Fixed offset when mmaping a BAR with a not page-aligned address.
* Added support for SGlist types at runtime.
*
* Revision 1.1 2006/10/13 17:18:31 marcus
* Implemented and tested most of C++ interface.
*
*******************************************************************/
#include "driver/pciDriver.h"
#include "PciDevice.h"
#include "Exception.h"
#include "KernelMemory.h"
#include "UserMemory.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace pciDriver;
/**
*
* Construtor for the PciDevice. Checks if the specified device exists and initializes
* pagemask, pageshift and the mmap_mutex.
*
* @param number Number of the device, e.g. 0 for /dev/fpga0
*
*/
PciDevice::PciDevice(int number)
{
struct stat tmp_stat;
unsigned int temp;
device = number;
snprintf(name, sizeof(name), "/dev/fpga%d", number);
if (stat(name, &tmp_stat) < 0)
throw Exception( Exception::DEVICE_NOT_FOUND );
pthread_mutex_init(&mmap_mutex, NULL);
handle = -1;
pagesize = getpagesize();
// set pagemask and pageshift
for( pagemask=0, pageshift=0, temp = pagesize; temp != 1; pageshift++ ) {
temp = (temp >> 1);
pagemask = (pagemask << 1)+1;
}
}
/**
*
* Destructor of PciDevice. Closes the device if it is opened and destroys the mmap_mutex.
*
*/
PciDevice::~PciDevice()
{
// Close device if open
if (handle > 0)
this->close();
pthread_mutex_destroy(&mmap_mutex);
}
/**
*
* Gets the file handle.
*
* @returns file handle of the opened PCI device.
*
*/
int PciDevice::getHandle()
{
if (handle == -1)
throw Exception(Exception::NOT_OPEN);
return handle;
}
/**
*
* Opens the PCI device.
*
*/
void PciDevice::open()
{
int ret;
/* Check if the device is already opened and exit if yes */
if (handle != -1)
return;
if ((ret = ::open(name, O_RDWR)) < 0)
throw Exception( Exception::OPEN_FAILED );
handle = ret;
}
/**
*
* Close the PCI device.
*
*/
void PciDevice::close()
{
// do nothing, pass silently if closing a non-opened device.
if (handle != -1)
::close(handle);
handle = -1;
}
/**
*
* Allocates kernel memory of the specified size.
*
* @param size How much memory to allocate
* @returns A KernelMemory object
* @see KernelMemory
*
*/
KernelMemory& PciDevice::allocKernelMemory(unsigned int size)
{
KernelMemory *km = new KernelMemory(*this, size);
return *km;
}
/**
*
* Maps user memory of the specified size.
*
* @returns A UserMemory object
* @see UserMemory
*
*/
UserMemory& PciDevice::mapUserMemory(void *mem, unsigned int size, bool merged)
{
UserMemory *um = new UserMemory(*this, mem, size, merged);
return *um;
}
/**
*
* Waits for an interrupt.
*
*/
void PciDevice::waitForInterrupt(unsigned int int_id)
{
if (handle == -1)
throw Exception(Exception::NOT_OPEN);
if (ioctl(handle, PCIDRIVER_IOC_WAITI, int_id) != 0)
throw Exception(Exception::INTERRUPT_FAILED);
}
/**
*
* Clears the interrupt queue.
*
*/
void PciDevice::clearInterruptQueue(unsigned int int_id)
{
if (handle == -1)
throw Exception( Exception::NOT_OPEN );
if (ioctl(handle, PCIDRIVER_IOC_CLEAR_IOQ, int_id) != 0)
throw Exception(Exception::INTERNAL_ERROR);
}
/**
*
* Gets the size of a BAR.
*
* @returns the size of the given BAR
*
*/
unsigned int PciDevice::getBARsize(unsigned int bar)
{
pci_board_info info;
unsigned int id;
if (handle == -1)
throw Exception( Exception::NOT_OPEN );
if (bar > 5)
throw Exception( Exception::INVALID_BAR );
if (ioctl(handle, PCIDRIVER_IOC_PCI_INFO, &info) != 0)
throw Exception( Exception::INTERNAL_ERROR );
return info.bar_length[ bar ];
}
/**
*
* Gets the bus ID of the PCI device
*
*/
unsigned short PciDevice::getBus()
{
pci_board_info info;
if (handle == -1)
throw Exception(Exception::NOT_OPEN);
if (ioctl(handle, PCIDRIVER_IOC_PCI_INFO, &info) != 0)
throw Exception(Exception::INTERNAL_ERROR);
return info.bus;
}
/**
*
* Gets the slot of the PCI device
*
*/
unsigned short PciDevice::getSlot()
{
pci_board_info info;
if (handle == -1)
throw Exception(Exception::NOT_OPEN);
if (ioctl(handle, PCIDRIVER_IOC_PCI_INFO, &info) != 0)
throw Exception(Exception::INTERNAL_ERROR);
return info.slot;
}
/**
*
* Map the specified BAR.
*
* @param bar Which BAR to map (1-5).
* @returns A pointer to the mapped bar.
*
*/
void *PciDevice::mapBAR(unsigned int bar)
{
void *mem;
pci_board_info info;
if (handle == -1)
throw Exception(Exception::NOT_OPEN);
if (bar > 5)
throw Exception(Exception::INVALID_BAR);
if (ioctl(handle, PCIDRIVER_IOC_PCI_INFO, &info) != 0)
return NULL;
/* Mmap */
/* This is not fully safe, as a separate process can still open the device independently.
* That will use a separate mutex and the race condition can arise.
* Posible fix: Do not allow the driver for mutliple openings of a device */
mmap_lock();
if (ioctl(handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_PCI) != 0)
throw Exception(Exception::INTERNAL_ERROR);
if (ioctl( handle, PCIDRIVER_IOC_MMAP_AREA, PCIDRIVER_BAR0+bar) != 0)
throw Exception(Exception::INTERNAL_ERROR);
mem = mmap(0, info.bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, handle, 0);
mmap_unlock();
if ((mem == MAP_FAILED) || (mem == NULL))
throw Exception(Exception::MMAP_FAILED);
return mem;
}
/**
*
* Unmap the specified bar.
*
*/
void PciDevice::unmapBAR(unsigned int bar, void *ptr)
{
pci_board_info info;
if (handle == -1)
throw Exception(Exception::NOT_OPEN);
if (bar > 5)
throw Exception(Exception::INVALID_BAR);
if (ioctl(handle, PCIDRIVER_IOC_PCI_INFO, &info) != 0)
throw Exception(Exception::INVALID_BAR);
munmap(ptr, info.bar_length[bar]);
}
unsigned char PciDevice::readConfigByte(unsigned int addr)
{
pci_cfg_cmd cmd;
if (handle == -1)
throw Exception( Exception::NOT_OPEN );
cmd.addr = addr;
cmd.size = PCIDRIVER_PCI_CFG_SZ_BYTE;
ioctl( handle, PCIDRIVER_IOC_PCI_CFG_RD, &cmd );
return cmd.val.byte;
}
unsigned short PciDevice::readConfigWord(unsigned int addr)
{
pci_cfg_cmd cmd;
if (handle == -1)
throw Exception( Exception::NOT_OPEN );
cmd.addr = addr;
cmd.size = PCIDRIVER_PCI_CFG_SZ_WORD;
ioctl( handle, PCIDRIVER_IOC_PCI_CFG_RD, &cmd );
return cmd.val.word;
}
unsigned int PciDevice::readConfigDWord(unsigned int addr)
{
pci_cfg_cmd cmd;
if (handle == -1)
throw Exception( Exception::NOT_OPEN );
cmd.addr = addr;
cmd.size = PCIDRIVER_PCI_CFG_SZ_DWORD;
ioctl( handle, PCIDRIVER_IOC_PCI_CFG_RD, &cmd );
return cmd.val.dword;
}
void PciDevice::writeConfigByte(unsigned int addr, unsigned char val)
{
pci_cfg_cmd cmd;
if (handle == -1)
throw Exception( Exception::NOT_OPEN );
cmd.addr = addr;
cmd.size = PCIDRIVER_PCI_CFG_SZ_BYTE;
cmd.val.byte = val;
ioctl( handle, PCIDRIVER_IOC_PCI_CFG_WR, &cmd );
return;
}
void PciDevice::writeConfigWord(unsigned int addr, unsigned short val)
{
pci_cfg_cmd cmd;
if (handle == -1)
throw Exception( Exception::NOT_OPEN );
cmd.addr = addr;
cmd.size = PCIDRIVER_PCI_CFG_SZ_WORD;
cmd.val.word = val;
ioctl( handle, PCIDRIVER_IOC_PCI_CFG_WR, &cmd );
return;
}
void PciDevice::writeConfigDWord(unsigned int addr, unsigned int val)
{
pci_cfg_cmd cmd;
if (handle == -1)
throw Exception( Exception::NOT_OPEN );
cmd.addr = addr;
cmd.size = PCIDRIVER_PCI_CFG_SZ_DWORD;
cmd.val.dword = val;
ioctl( handle, PCIDRIVER_IOC_PCI_CFG_WR, &cmd );
return;
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/lib/pcie/UserMemory.cpp 0000775 0000000 0000000 00000005506 12326537641 0025433 0 ustar 00root root 0000000 0000000 /**
*
* @file UserMemory.cpp
* @author Guillermo Marcus
* @date 2009-04-05
* @brief UserMemory class
*
*/
/*******************************************************************
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.3 2007-02-09 17:02:38 marcus
* Modified Exception handling, made simpler and more standard.
*
* Revision 1.2 2006/11/17 18:57:27 marcus
* Added SGlist type support at runtime.
*
* Revision 1.1 2006/10/13 17:18:33 marcus
* Implemented and tested most of C++ interface.
*
*******************************************************************/
#include "UserMemory.h"
#include "Exception.h"
#include "driver/pciDriver.h"
#include
#include
#include
using namespace pciDriver;
/**
*
* Constructor of UserMemory. Allocates a scatter/gather list and receives it
* from kernel space.
*
*/
UserMemory::UserMemory(PciDevice& dev, void *mem, unsigned int size, bool merged)
{
int i;
umem_handle_t uh;
umem_sglist_t sgl;
int dev_handle;
dev_handle = dev.getHandle();
this->device = &dev;
this->vma = reinterpret_cast(mem);
this->size = size;
uh.vma = reinterpret_cast(mem);
uh.size = size;
/* Lock and Map the memory to their pages */
if (ioctl(dev_handle, PCIDRIVER_IOC_UMEM_SGMAP, &uh) != 0)
throw Exception( Exception::SGMAP_FAILED );
this->handle_id = uh.handle_id;
/* Obtain the scatter/gather list for this memory */
sgl.handle_id = uh.handle_id;
sgl.type = ((merged) ? PCIDRIVER_SG_MERGED : PCIDRIVER_SG_NONMERGED);
sgl.nents = (size / getpagesize()) + 2;
sgl.sg = new umem_sgentry_t[ sgl.nents ];
if (ioctl(dev_handle, PCIDRIVER_IOC_UMEM_SGGET, &sgl) != 0) {
ioctl( dev_handle, PCIDRIVER_IOC_UMEM_SGUNMAP, &uh );
delete [] sgl.sg;
throw Exception( Exception::SGMAP_FAILED );
}
/* Copy the Scatter / Gather list to our structures */
this->nents = sgl.nents;
this->sg = new struct sg_entry[ sgl.nents ];
for(i = 0; i < sgl.nents; i++) {
this->sg[i].addr = sgl.sg[i].addr;
this->sg[i].size = sgl.sg[i].size;
}
/* Temp SG list for the driver is no longer needed */
delete [] sgl.sg;
}
/**
*
* Destructor of UserMemory. Deletes the scatter/gather list and unmaps it
* in kernel.
*
*/
UserMemory::~UserMemory()
{
umem_handle_t uh;
delete [] this->sg;
uh.handle_id = handle_id;
uh.vma = vma;
uh.size = size;
if (ioctl(device->getHandle(), PCIDRIVER_IOC_UMEM_SGUNMAP, &uh) != 0)
throw Exception(Exception::INTERNAL_ERROR);
}
/**
*
* Syncs the user memory from/to the device.
*
*/
void UserMemory::sync(sync_dir dir)
{
umem_handle_t uh;
/* We assume (C++ API) dir === (Driver API) dir */
uh.handle_id = handle_id;
uh.vma = vma;
uh.size = size;
uh.dir = dir;
if (ioctl(device->getHandle(), PCIDRIVER_IOC_UMEM_SYNC, &uh) != 0)
throw Exception( Exception::INTERNAL_ERROR );
}
bpm-sw-b46de62356ed3761c9105d7a1d6d085351c0f0af/kernel/lib/pcie/pciDriver_Capi.c 0000775 0000000 0000000 00000026540 12326537641 0025650 0 ustar 00root root 0000000 0000000 /*******************************************************************
* Change History:
*
* $Log: not supported by cvs2svn $
* Revision 1.8 2008-01-24 14:21:35 marcus
* Added a CLEAR_INTERRUPT_QUEUE ioctl.
* Added a sysfs attribute to show the outstanding IRQ queues.
*
* Revision 1.7 2008-01-11 10:16:53 marcus
* Removed unused interrupt code.
* Added intSource to the WaitFor Interrupt call.
*
* Revision 1.6 2007/02/09 17:02:05 marcus
* Added interrupt descriptor function.
*
* Revision 1.5 2006/12/07 18:43:24 marcus
* Fixed offset when mapping/unmapping a non-aligned BAR.
*
* Revision 1.4 2006/11/17 19:00:41 marcus
* Added default type to the SGlist.
*
* Revision 1.3 2006/10/16 16:54:59 marcus
* Changed malloc to posix_memalign.
* Fixed memory leak in unmapUserMemory.
*
* Revision 1.2 2006/10/13 17:18:33 marcus
* Implemented and tested most of C++ interface.
*
*******************************************************************/
#include
#include