summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/builtins.h5
-rw-r--r--src/include/usr/devicefw/driverif.H250
-rw-r--r--src/include/usr/devicefw/userif.H108
-rw-r--r--src/lib/stdlib.C2
-rw-r--r--src/makefile4
-rw-r--r--src/usr/devicefw/assoccontain.C52
-rw-r--r--src/usr/devicefw/assoccontain.H93
-rw-r--r--src/usr/devicefw/associator.C205
-rw-r--r--src/usr/devicefw/associator.H72
-rw-r--r--src/usr/devicefw/driverif.C157
-rw-r--r--src/usr/devicefw/makefile8
-rw-r--r--src/usr/devicefw/test/assoccontaintest.H102
-rw-r--r--src/usr/devicefw/test/associatortest.H174
-rw-r--r--src/usr/devicefw/test/makefile6
-rw-r--r--src/usr/devicefw/userif.C46
-rw-r--r--src/usr/makefile2
16 files changed, 1282 insertions, 4 deletions
diff --git a/src/include/builtins.h b/src/include/builtins.h
index 5126b6114..07b185697 100644
--- a/src/include/builtins.h
+++ b/src/include/builtins.h
@@ -40,6 +40,11 @@ extern "C"
#define SYMB_SECTION(x) __attribute__((section(#x)))
/**
+ * Use of this macro will ensure a data structure is not padded
+ */
+#define PACKED __attribute__((packed))
+
+/**
* Get the value of the link register
*
* @return the value of the link register
diff --git a/src/include/usr/devicefw/driverif.H b/src/include/usr/devicefw/driverif.H
new file mode 100644
index 000000000..ceff91c59
--- /dev/null
+++ b/src/include/usr/devicefw/driverif.H
@@ -0,0 +1,250 @@
+/** @file driverif.H
+ * @brief Provides the device driver interfaces for performing device access
+ * and enabling routing registration.
+ *
+ * @note These interfaces should only be used by device drivers. User code
+ * wanting to perform device operations should use userif.H instead.
+ */
+#ifndef __DEVICEFW_DRIVERIF
+#define __DEVICEFW_DRIVERIF
+
+#include <devicefw/userif.H>
+#include <stdarg.h>
+#include <builtins.h>
+
+namespace DeviceFW
+{
+ /** TODO: Update these to real target handle type once that piece of
+ * code is complete */
+ enum TargetType_t
+ {
+ PROCESSOR = 0,
+
+ LAST_TARGET_TYPE
+ };
+
+ /** @enum AccessType_DriverOnly
+ * @brief Access types to be used internally by drivers for routing
+ * requests to other drivers.
+ */
+ enum AccessType_DriverOnly
+ {
+ XSCOM = LAST_ACCESS_TYPE,
+ FSISCOM,
+
+ LAST_DRIVER_ACCESS_TYPE
+ };
+
+ /** @enum OperationType
+ * @brief Set of operations which can be registered for.
+ */
+ enum OperationType
+ {
+ READ = 0,
+ WRITE,
+
+ LAST_OP_TYPE
+
+ };
+
+ /** @enum DriverSpecial
+ * @brief Special Wildcard enum that can be used for drivers to do
+ * routing registrations.
+ */
+ enum DriverSpecial
+ {
+ WILDCARD = -1,
+ };
+
+ /** @class InvalidParameterType
+ * @brief Unused type to cause compiler fails for invalid template types.
+ *
+ * Forward Declaration of type that is never actually used anywhere.
+ *
+ * Assists in making more developer friendly compiler fails when a
+ * template function is called for which there is no specialization and
+ * the default template function should never be used. This is used for
+ * allowing function calls that take multiple enum types but still provide
+ * type-safety above a int-parameter.
+ */
+ class InvalidParameterType;
+
+ /** @typedef deviceOp_t
+ * @brief Function prototype for registered device-driver operations.
+ */
+ typedef ErrorHandle_t(*deviceOp_t)(OperationType,
+ TargetHandle_t,
+ void*, size_t&,
+ int64_t, va_list);
+
+ /**
+ * @brief Register a device driver routing function with the framework.
+ *
+ * @param[in] i_opType - Enumeration specifying the operation this
+ * driver performs. (Read, Write, Wildcard)
+ * @param[in] i_accessType - Enumeration specifying the access type this
+ * driver performs. (SCOM, XSCOM, PNOR, etc.)
+ * @param[in] i_targetType - Enumeration specifying the target type this
+ * driver performs. (Proc, MC, Wildcard, etc.)
+ * @param[in] i_regRoute - The function being registered.
+ *
+ * This function call be called to register a device driver routing
+ * function with the framework. If it is desired to always register a
+ * device driver when the module associated with that driver is loaded,
+ * the DEVICE_REGISTER_ROUTE macro can be used.
+ *
+ * <PRE>
+ * Example usage:
+ * // High-level address manipulation routing function.
+ * deviceRegisterRoute(WILDCARD,
+ * SCOM,
+ * MEMORY_CONTROLLER,
+ * &scomAdjustMCAddresses);
+ *
+ * // Low-level (internal) XSCOM read operation.
+ * deviceRegisterRoute(READ,
+ * XSCOM,
+ * PROCESSOR,
+ * &xscomPerformRead);
+ * </PRE>
+ *
+ * @note Valid OpType are OperatorType enum or WILDCARD.
+ * @note Valid TargType are TargetType enum or WILDCARD.
+ * @note Valid AccType are AccessType or AccessType_DriverOnly; WILDCARD is
+ * not permitted.
+ *
+ * @note Any unsupported enumeration type will result in a compile error
+ * referencing a InvalidParameterType class.
+ */
+ template <typename OpType, typename AccType, typename TargType>
+ void deviceRegisterRoute(OpType i_opType,
+ AccType i_accessType,
+ TargType i_targetType,
+ deviceOp_t i_regRoute)
+ {
+ return InvalidParameterType(); // Cause a compile fail if not one of
+ // the explicit template specializations.
+ }
+
+ /** Assistance macro for stringification. */
+ #define __DEVICE_REGISTER_ROUTE_XY(X,Y) X##Y
+ /** Assistance macro for stringification. */
+ #define __DEVICE_REGISTER_ROUTE_MAKENAME(X,Y) __DEVICE_REGISTER_ROUTE_XY(X,Y)
+
+ /**
+ * @brief Create a static constructed registration of a device driver
+ * function when a module is loaded.
+ *
+ * Parameters are the same as DeviceFW::deviceRegisterRoute, except the
+ * route function should be passed by name as opposed to pointer.
+ *
+ * If the route function is in a namespace, then this definition must
+ * also be placed into that namespace.
+ */
+ #define DEVICE_REGISTER_ROUTE(i_opType, i_accessType, \
+ i_targetType, i_regRoute) \
+ class __DEVICE_REGISTER_ROUTE_MAKENAME(DeviceRouteRegistrator_, \
+ i_regRoute) \
+ { \
+ public: \
+ __DEVICE_REGISTER_ROUTE_MAKENAME(DeviceRouteRegistrator_, \
+ i_regRoute)() \
+ { \
+ DeviceFW::deviceRegisterRoute(i_opType, i_accessType, \
+ i_targetType, &i_regRoute); \
+ } \
+ }; \
+ __DEVICE_REGISTER_ROUTE_MAKENAME(DeviceRouteRegistrator_, i_regRoute) \
+ __DEVICE_REGISTER_ROUTE_MAKENAME(DeviceRouteRegistrator_instance_, \
+ i_regRoute);
+
+ /**
+ * @brief Perform a device operation by routing through the framework and
+ * calling the appropriate registered operation.
+ *
+ * @param[in] i_opType - Operation request (READ vs WRITE).
+ * @param[in] i_target - Target to perform operation on.
+ * @param[in,out] io_buffer - Data buffer for operation.
+ * @param[in,out] io_buflen - Length of buffer / result size.
+ * @param[in] i_accessType - Type of hardware access method to perform.
+ *
+ * This function has similar behavior as the user-visible deviceRead and
+ * deviceWrite functions and is meant as a method for device drivers to
+ * perform accesses which may be only visible to internal drivers.
+ */
+ template <typename AccType>
+ ErrorHandle_t deviceOp(OperationType i_opType,
+ TargetHandle_t i_target,
+ void* io_buffer, size_t& io_buflen,
+ AccType i_accessType, ...)
+ {
+ return InvalidParameterType(); // Cause a compile fail if not one of
+ // the explicit template specializations.
+ }
+
+ // --- Below are template specializations to aid in type-safety. ---
+
+ // deviceRegisterRoute:
+ // OpType - OperationType or WILDCARD
+ // TargType - TargetType or WILDCARD
+ // AccType - AccessType, AccessType_DriverOnly (no WILDCARD).
+
+ template <>
+ void deviceRegisterRoute<>(OperationType i_opType,
+ AccessType i_accessType,
+ TargetType_t i_targetType,
+ deviceOp_t i_regRoute);
+ template <>
+ void deviceRegisterRoute<>(OperationType i_opType,
+ AccessType_DriverOnly i_accessType,
+ TargetType_t i_targetType,
+ deviceOp_t i_regRoute);
+ template <>
+ void deviceRegisterRoute<>(OperationType i_opType,
+ AccessType i_accessType,
+ DriverSpecial i_targetType,
+ deviceOp_t i_regRoute);
+ template <>
+ void deviceRegisterRoute<>(OperationType i_opType,
+ AccessType_DriverOnly i_accessType,
+ DriverSpecial i_targetType,
+ deviceOp_t i_regRoute);
+ template <>
+ void deviceRegisterRoute<>(DriverSpecial i_opType,
+ AccessType i_accessType,
+ TargetType_t i_targetType,
+ deviceOp_t i_regRoute);
+ template <>
+ void deviceRegisterRoute<>(DriverSpecial i_opType,
+ AccessType_DriverOnly i_accessType,
+ TargetType_t i_targetType,
+ deviceOp_t i_regRoute);
+ template <>
+ void deviceRegisterRoute<>(DriverSpecial i_opType,
+ AccessType i_accessType,
+ DriverSpecial i_targetType,
+ deviceOp_t i_regRoute);
+ template <>
+ void deviceRegisterRoute<>(DriverSpecial i_opType,
+ AccessType_DriverOnly i_accessType,
+ DriverSpecial i_targetType,
+ deviceOp_t i_regRoute);
+
+ // deviceOp:
+ // OpType - OperationType only.
+ // TargType - TargetType only.
+ // AccType - AccessType, AccessType_DriverOnly (no WILDCARD).
+ template <>
+ ErrorHandle_t deviceOp<>(OperationType i_opType,
+ TargetHandle_t i_target,
+ void* io_buffer, size_t& io_buflen,
+ AccessType i_accessType, ...);
+ template <>
+ ErrorHandle_t deviceOp<>(OperationType i_opType,
+ TargetHandle_t i_target,
+ void* io_buffer, size_t& io_buflen,
+ AccessType_DriverOnly i_accessType, ...);
+
+};
+
+#endif
diff --git a/src/include/usr/devicefw/userif.H b/src/include/usr/devicefw/userif.H
new file mode 100644
index 000000000..dc4cbd4c7
--- /dev/null
+++ b/src/include/usr/devicefw/userif.H
@@ -0,0 +1,108 @@
+/** @file userif.H
+ * @brief Provides the user application interfaces for performing device
+ * access.
+ *
+ * @note These interfaces should not be used directly by device drivers.
+ * Use driverif.H instead.
+ */
+
+#ifndef __DEVICEFW_USERIF
+#define __DEVICEFW_USERIF
+
+#include <stdint.h>
+
+namespace DeviceFW
+{
+ /* TODO: Update these to real error log / target handle type once those
+ * pieces of code are complete. */
+ typedef void* ErrorHandle_t;
+ typedef int TargetHandle_t;
+
+ /** @enum AccessType
+ * @brief Access types for accessing a hardware device.
+ */
+ enum AccessType
+ {
+ SCOM = 0,
+ PNOR,
+ MAILBOX,
+ PRESENT,
+
+ LAST_ACCESS_TYPE,
+ };
+
+ /** Construct the device addressing parameters for SCOM device ops.
+ * @param[in] i_address - Scom address to operate on.
+ */
+ #define DEVICE_SCOM_ADDRESS(i_address) \
+ DeviceFW::SCOM, static_cast<uint64_t>((i_address))
+
+ /** Construct the device addressing parameters for the PRESENT device ops.
+ */
+ #define DEVICE_PRESENT_ADDRESS() \
+ DeviceFW::PRESENT
+
+ /**
+ * @brief Perform a hardware read operation.
+ *
+ * @param[in] i_target Device target to operate on.
+ * @param[out] o_buffer Buffer to put result data into.
+ * @param[in,out] io_buflen Length of the buffer on input, length of
+ * data on output (in bytes).
+ * @param[in] i_accessType Operation to perform on target.
+ * @param[in] ... Operation specific addressing parameters.
+ *
+ * @return NULL - No error.
+ * @return Non-NULL - An error handle when error has occured, typically
+ * passed directly from device driver but potentially
+ * created by the device framework as in the case of
+ * not finding an installed driver for the desired
+ * operation.
+ *
+ * It is expected that the callers will use operation specific macros to
+ * assist in the AccessType parameter and variable arguments.
+ *
+ * <PRE>
+ * Example usage:
+ * errl = deviceRead(chip, buf, bufsize, DEVICE_SCOM_ADDRESS(0x42));
+ * </PRE>
+ *
+ */
+ ErrorHandle_t deviceRead(TargetHandle_t i_target,
+ void* o_buffer, size_t& io_buflen,
+ AccessType i_accessType, ...);
+
+ /**
+ * @brief Perform a hardware write operation.
+ *
+ * @param[in] i_target Device target to operate on.
+ * @param[in] i_buffer Buffer to get write data from.
+ * @param[in,out] io_buflen Length of the buffer on input, length of
+ * data on output (in bytes).
+ * @param[in] i_accessType Operation to perform on target.
+ * @param[in] ... Operation specific addressing parameters.
+ *
+ * @return NULL - No error.
+ * @return Non-NULL - An error handle when error has occured, typically
+ * passed directly from device driver but potentially
+ * created by the device framework as in the case of
+ * not finding an installed driver for the desired
+ * operation.
+ *
+ * It is expected that the callers will use operation specific macros to
+ * assist in the AccessType parameter and variable arguments.
+ *
+ * <PRE>
+ * Example usage:
+ * errl = deviceWrite(chip, buf, bufsize, DEVICE_SCOM_ADDRESS(0x42));
+ * </PRE>
+ *
+ */
+ ErrorHandle_t deviceWrite(TargetHandle_t i_target,
+ void* i_buffer, size_t& io_buflen,
+ AccessType i_accessType, ...);
+
+};
+
+
+#endif
diff --git a/src/lib/stdlib.C b/src/lib/stdlib.C
index 8aa6b36eb..1614bdd8f 100644
--- a/src/lib/stdlib.C
+++ b/src/lib/stdlib.C
@@ -52,7 +52,7 @@ void* realloc(void* p, size_t s)
cur_size = (1 << (*len + 4)) - 8;
}
- if (s < cur_size)
+ if (s <= cur_size)
return p;
void* new_p = malloc(s);
diff --git a/src/makefile b/src/makefile
index 5f65cb74e..4a1987678 100644
--- a/src/makefile
+++ b/src/makefile
@@ -15,10 +15,10 @@ DIRECT_BOOT_OBJECTS = start.o kernel.o taskmgr.o cpumgr.o syscall.o \
RUNTIME_OBJECTS =
-BASE_MODULES = trace errl
+BASE_MODULES = trace errl devicefw
DIRECT_BOOT_MODULES = example
RUNTIME_MODULES =
-TESTCASE_MODULES = cxxtest testexample testtrace testerrl
+TESTCASE_MODULES = cxxtest testerrl testdevicefw
RELOCATABLE_IMAGE_LDFLAGS = -pie --export-dynamic
diff --git a/src/usr/devicefw/assoccontain.C b/src/usr/devicefw/assoccontain.C
new file mode 100644
index 000000000..d15eec223
--- /dev/null
+++ b/src/usr/devicefw/assoccontain.C
@@ -0,0 +1,52 @@
+#include "assoccontain.H"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace DeviceFW
+{
+
+ AssociationContainer::AssociationContainer()
+ : iv_data(NULL), iv_size(0)
+ {
+ }
+
+ AssociationContainer::~AssociationContainer()
+ {
+ if (NULL != iv_data)
+ {
+ free(iv_data);
+ }
+ }
+
+ AssociationData* AssociationContainer::operator[](size_t i_pos) const
+ {
+ if (i_pos >= iv_size)
+ {
+ return NULL;
+ }
+
+ return &iv_data[i_pos];
+ }
+
+ size_t AssociationContainer::allocate(size_t i_size)
+ {
+ size_t cur_pos = iv_size;
+
+ // Resize buffer to have space for request.
+ iv_size += i_size;
+ iv_data =
+ static_cast<AssociationData*>(
+ realloc(iv_data,
+ sizeof(AssociationData) * (iv_size)
+ )
+ );
+
+ // Clear out newly allocated space.
+ memset(this->operator[](cur_pos), '\0',
+ sizeof(AssociationData) * i_size);
+
+ return cur_pos;
+ }
+};
+
diff --git a/src/usr/devicefw/assoccontain.H b/src/usr/devicefw/assoccontain.H
new file mode 100644
index 000000000..9786168e0
--- /dev/null
+++ b/src/usr/devicefw/assoccontain.H
@@ -0,0 +1,93 @@
+/** @file assoccontain.H
+ * @brief Provides a memory pool container for allocating blocks of
+ * associations for the device driver framework.
+ *
+ * This class exists because storing the information in a normal map or
+ * vector would be exceptionally big for the expected sparseness of the
+ * device driver associations.
+ */
+
+#ifndef __DEVICEFW_ASSOCCONTAIN_H
+#define __DEVICEFW_ASSOCCONTAIN_H
+
+#include <stdint.h>
+#include <builtins.h>
+
+namespace DeviceFW
+{
+ /** @struct AssociationData
+ * @brief Data about a particular association.
+ *
+ * Typically this is a offset (pointer) to another association and an
+ * optional flag for the associatior to use. This allows a user to
+ * construct a light-weight multi-dimensional sparse array.
+ *
+ * The purpose of the flag field is left to the user.
+ */
+ struct AssociationData
+ {
+ bool flag:1;
+ size_t offset:15;
+
+ AssociationData() : flag(false), offset(0) { };
+
+ AssociationData(bool i_flag, size_t i_off)
+ : flag(i_flag), offset(i_off) { };
+
+ } PACKED;
+
+ /** @class AssociationContainer
+ * @brief The memory pool container of AssociationData blocks.
+ *
+ * The typical usage of this will be to create a multi-dimensional sparse
+ * associative array (map). The first block allocated will be the first
+ * dimension of the array. Each AssociationData entry in the block is the
+ * offset of the block containing the AssociationData for the next
+ * dimension. At the lowest level this offset might be used as an offset
+ * into another container, such as an std::vector.
+ */
+ class AssociationContainer
+ {
+ public:
+ /**
+ * @brief Constructor for AssociationContainer.
+ *
+ * Initializes internal members to clean values.
+ */
+ AssociationContainer();
+
+ /**
+ * @brief Destructor for AssociationContainer.
+ *
+ * Releases memory associated with container. After this call
+ * all pointers previously obtained through operator[] are invalid.
+ */
+ ~AssociationContainer();
+
+ /**
+ * @brief Look up a particular association entry by offset.
+ * @return A pointer to the requested association block.
+ *
+ * @note Will return a NULL pointer if an invalid offset is given.
+ */
+ AssociationData* operator[](size_t) const;
+
+ /**
+ * @brief Allocate a new block into the pool.
+ * @return A offset to the newly allocated block.
+ *
+ * The blocks allocated will all be erased to 0's.
+ *
+ * @note This function can change the pointers previously
+ * returned by the operator[]. Treat this function
+ * as though all previous pointers are invalidated.
+ */
+ size_t allocate(size_t);
+
+ private:
+ AssociationData* iv_data;
+ size_t iv_size;
+ };
+};
+
+#endif
diff --git a/src/usr/devicefw/associator.C b/src/usr/devicefw/associator.C
new file mode 100644
index 000000000..95c8ef7a0
--- /dev/null
+++ b/src/usr/devicefw/associator.C
@@ -0,0 +1,205 @@
+#include <algorithm>
+#include "associator.H"
+
+#include <trace/interface.H>
+
+namespace DeviceFW
+{
+ trace_desc_t* g_traceBuffer = NULL;
+ TRAC_INIT(&g_traceBuffer, "DevFW", 4096);
+
+ Associator::Associator() : iv_mutex(mutex_create())
+ {
+ TRACFCOMP(g_traceBuffer, ENTER_MRK "Associator::Associator");
+
+ // Allocate first level of map (access types).
+ iv_routeMap = iv_associations.allocate(LAST_DRIVER_ACCESS_TYPE);
+ }
+
+ Associator::~Associator()
+ {
+ mutex_destroy(iv_mutex);
+
+ TRACFCOMP(g_traceBuffer, EXIT_MRK "Associator::~Associator");
+ }
+
+ void Associator::registerRoute(int64_t i_opType,
+ int64_t i_accType,
+ int64_t i_targetType,
+ deviceOp_t i_regRoute)
+ {
+ TRACFCOMP(g_traceBuffer, "Device route registered for (%d, %d, %d)",
+ i_opType, i_accType, i_targetType);
+
+ // The ranges of the parameters should all be verified by the
+ // compiler due to the template specializations in driverif.H.
+ // No assert-checks will be done here.
+
+ mutex_lock(iv_mutex);
+
+ size_t ops = 0;
+ AssociationData targets = AssociationData();
+
+ // Look up second level of map (op-type) or allocate fresh block.
+ ops = iv_associations[iv_routeMap][i_accType].offset;
+ if (0 == ops)
+ {
+ // space for LAST_OP_TYPE plus WILDCARD(-1).
+ ops = iv_associations.allocate(LAST_OP_TYPE + 1) + 1;
+ iv_associations[iv_routeMap][i_accType].offset = ops;
+ }
+
+ // Look up third level of map (access-type) or allocate fresh block.
+ targets = iv_associations[ops][i_opType];
+ if (0 == targets.offset)
+ {
+ // To conserve space only allocate 1 block for WILDCARD.
+ if (WILDCARD == i_targetType)
+ {
+ targets.offset = iv_associations.allocate(1);
+ targets.flag = true; // True flag indicates WILDCARD.
+ }
+ else
+ {
+ // Allocate full number of spaces.
+ targets.offset = iv_associations.allocate(LAST_TARGET_TYPE);
+ }
+ iv_associations[ops][i_opType] = targets;
+ }
+ // Ensure the right block size was allocated previously for this
+ // target-type (wildcard vs non-wildcard).
+ if(((targets.flag) && (i_targetType != WILDCARD)) ||
+ ((!targets.flag) && (i_targetType == WILDCARD)))
+ {
+ // TODO: Create error log for invalid target type?
+ bool l_invalidTargetType = false;
+ assert(l_invalidTargetType);
+ }
+
+ // Index offset to proper target type. This is now lowest level of map.
+ targets.offset += (i_targetType == WILDCARD ? 0 : i_targetType);
+
+
+ // Search function vector for entry.
+ opVector_t::iterator opLocation = std::find(iv_operations.begin(),
+ iv_operations.end(),
+ i_regRoute);
+ // Insert function into vector if not found.
+ if (iv_operations.end() == opLocation)
+ {
+ iv_operations.push_back(i_regRoute);
+ opLocation = iv_operations.end() - 1;
+ }
+
+ // TODO: Implement std::distance algorithm and change to:
+ // std::distance(iv_operations.begin(), opLocation);
+ size_t opLoc = opLocation - iv_operations.begin();
+
+ // Set function offset into map. True flag indicates valid.
+ (*iv_associations[targets.offset]) = AssociationData(true, opLoc);
+
+ mutex_unlock(iv_mutex);
+ }
+
+ ErrorHandle_t Associator::performOp(OperationType i_opType,
+ TargetHandle_t i_target,
+ void* io_buffer, size_t& io_buflen,
+ int64_t i_accessType, va_list i_addr)
+ const
+ {
+ TRACDCOMP(g_traceBuffer, "Device op requested for (%d, %d, %d)",
+ i_opType, i_accessType, /*TODO: i_target->type*/PROCESSOR);
+
+ // The ranges of the parameters should all be verified by the
+ // compiler due to the template specializations in driverif.H.
+ // No assert-checks will be done here.
+
+ ErrorHandle_t l_errl = NULL;
+
+ mutex_lock(iv_mutex);
+
+ // Function pointer found for this route request.
+ deviceOp_t l_devRoute = NULL;
+ // Pointer to root of the map.
+ const AssociationData* routeMap = iv_associations[iv_routeMap];
+
+ do
+ {
+ // Follow first level (access type), verify.
+ if (0 == routeMap[i_accessType].offset)
+ {
+ break;
+ }
+
+ const AssociationData* ops =
+ iv_associations[routeMap[i_accessType].offset];
+
+ // Check op type = WILDCARD registrations.
+ if (0 != ops[WILDCARD].offset)
+ {
+ // Check access type = WILDCARD registrations.
+ if (ops[WILDCARD].flag)
+ {
+ l_devRoute =
+ iv_operations[
+ iv_associations[ops[WILDCARD].offset]->offset];
+ break;
+ }
+
+ // Check access type = i_target->type registrations.
+ const AssociationData* targets =
+ iv_associations[ops[WILDCARD].offset];
+ if (targets[/*TODO: i_target->type*/PROCESSOR].flag)
+ {
+ l_devRoute =
+ iv_operations[
+ targets[/*TODO: i_target->type*/PROCESSOR].offset];
+ break;
+ }
+ }
+
+ // Check op type = i_opType registrations.
+ if (0 != ops[i_opType].offset)
+ {
+ // Check access type = WILDCARD registrations.
+ if(ops[i_opType].flag)
+ {
+ l_devRoute =
+ iv_operations[
+ iv_associations[ops[i_opType].offset]->offset];
+ break;
+ }
+
+ // Check access type = i_target->type registrations.
+ const AssociationData* targets =
+ iv_associations[ops[i_opType].offset];
+ if (targets[/*TODO: i_target->type*/PROCESSOR].flag)
+ {
+ l_devRoute =
+ iv_operations[
+ targets[/*TODO: i_target->type*/PROCESSOR].offset];
+ break;
+ }
+ }
+ } while(0);
+
+ mutex_unlock(iv_mutex);
+
+ // Call function if one was found, create error otherwise.
+ if (NULL == l_devRoute)
+ {
+ // TODO: create error log.
+ assert(NULL != l_devRoute);
+ }
+ else
+ {
+ l_errl = (*l_devRoute)(i_opType, i_target,
+ io_buffer, io_buflen,
+ i_accessType, i_addr);
+ }
+
+ return l_errl;
+ }
+}
+
+
diff --git a/src/usr/devicefw/associator.H b/src/usr/devicefw/associator.H
new file mode 100644
index 000000000..67b35e31b
--- /dev/null
+++ b/src/usr/devicefw/associator.H
@@ -0,0 +1,72 @@
+/** @file associator.H
+ * Define the internal routing mechanism (DriverAssociator) for the framework.
+ */
+#ifndef __DEVICEFW_ASSOCIATOR_H
+#define __DEVICEFW_ASSOCIATOR_H
+
+#include <devicefw/driverif.H>
+#include <sys/mutex.h>
+#include <vector>
+
+#include "assoccontain.H"
+
+namespace DeviceFW
+{
+ /** @class Associator
+ * @brief Class which performs the routing.
+ *
+ * Acts as a map of {op, access method, target type} -> deviceOp_t.
+ *
+ * This class is not implemented using a stl::map (or similar container)
+ * because space required to store the map, due to the number of pointers
+ * required to iterate to 3 levels of depth, would be much larger than
+ * needed.
+ *
+ * This class instead uses the AssociationContainer as a map on 16bit
+ * offsets to compact the storage requirements. Since we expect the
+ * same driver function may be registered multiple times (for different
+ * op / access method / target types), the class only stores the function
+ * pointers once and keeps an index of the function pointer in multiple
+ * locations in the map.
+ *
+ * The map is stored in the AssociationContainer as:
+ * iv_associations[AccessType][OpType][TargetType].
+ */
+ class Associator
+ {
+ public:
+ /** @brief Default constructor for Associator. */
+ Associator();
+
+ /** @brief Destructor for Associator.
+ * Removes all existing routing registrations.
+ */
+ ~Associator();
+
+ /** Register routing interface. See deviceRegisterRoute. */
+ void registerRoute(int64_t i_opType,
+ int64_t i_accType,
+ int64_t i_targetType,
+ deviceOp_t i_regRoute);
+
+ /** Perform routing. See deviceOp. */
+ ErrorHandle_t performOp(OperationType i_opType,
+ TargetHandle_t i_target,
+ void* io_buffer, size_t& io_buflen,
+ int64_t i_accessType, va_list i_addr) const;
+ private:
+ typedef std::vector<deviceOp_t> opVector_t;
+
+ /** Mutex to provide thread-safety. (could be rw-lock) */
+ mutex_t iv_mutex;
+ /** Vector of deviceOp_t functions registered. */
+ opVector_t iv_operations;
+ /** Compacted offset map. */
+ AssociationContainer iv_associations;
+ /** Index in map of the first level of the associations. */
+ size_t iv_routeMap;
+
+ };
+}
+
+#endif
diff --git a/src/usr/devicefw/driverif.C b/src/usr/devicefw/driverif.C
new file mode 100644
index 000000000..f6a2b9321
--- /dev/null
+++ b/src/usr/devicefw/driverif.C
@@ -0,0 +1,157 @@
+/** @file driverif.C
+ * Implement the template specializations of functions from driverif.H.
+ */
+#include <devicefw/driverif.H>
+#include <util/singleton.H>
+
+#include "associator.H"
+
+namespace DeviceFW
+{
+ template <>
+ void deviceRegisterRoute<>(OperationType i_opType,
+ AccessType i_accessType,
+ TargetType_t i_targetType,
+ deviceOp_t i_regRoute)
+ {
+ Singleton<Associator>::instance().registerRoute(
+ static_cast<int64_t>(i_opType),
+ static_cast<int64_t>(i_accessType),
+ static_cast<int64_t>(i_targetType),
+ i_regRoute);
+ }
+
+ template <>
+ void deviceRegisterRoute<>(OperationType i_opType,
+ AccessType_DriverOnly i_accessType,
+ TargetType_t i_targetType,
+ deviceOp_t i_regRoute)
+ {
+ Singleton<Associator>::instance().registerRoute(
+ static_cast<int64_t>(i_opType),
+ static_cast<int64_t>(i_accessType),
+ static_cast<int64_t>(i_targetType),
+ i_regRoute);
+ }
+
+ template <>
+ void deviceRegisterRoute<>(OperationType i_opType,
+ AccessType i_accessType,
+ DriverSpecial i_targetType,
+ deviceOp_t i_regRoute)
+ {
+ Singleton<Associator>::instance().registerRoute(
+ static_cast<int64_t>(i_opType),
+ static_cast<int64_t>(i_accessType),
+ static_cast<int64_t>(i_targetType),
+ i_regRoute);
+ }
+
+ template <>
+ void deviceRegisterRoute<>(OperationType i_opType,
+ AccessType_DriverOnly i_accessType,
+ DriverSpecial i_targetType,
+ deviceOp_t i_regRoute)
+ {
+ Singleton<Associator>::instance().registerRoute(
+ static_cast<int64_t>(i_opType),
+ static_cast<int64_t>(i_accessType),
+ static_cast<int64_t>(i_targetType),
+ i_regRoute);
+ }
+
+ template <>
+ void deviceRegisterRoute<>(DriverSpecial i_opType,
+ AccessType i_accessType,
+ TargetType_t i_targetType,
+ deviceOp_t i_regRoute)
+ {
+ Singleton<Associator>::instance().registerRoute(
+ static_cast<int64_t>(i_opType),
+ static_cast<int64_t>(i_accessType),
+ static_cast<int64_t>(i_targetType),
+ i_regRoute);
+ }
+
+ template <>
+ void deviceRegisterRoute<>(DriverSpecial i_opType,
+ AccessType_DriverOnly i_accessType,
+ TargetType_t i_targetType,
+ deviceOp_t i_regRoute)
+ {
+ Singleton<Associator>::instance().registerRoute(
+ static_cast<int64_t>(i_opType),
+ static_cast<int64_t>(i_accessType),
+ static_cast<int64_t>(i_targetType),
+ i_regRoute);
+ }
+
+ template <>
+ void deviceRegisterRoute<>(DriverSpecial i_opType,
+ AccessType i_accessType,
+ DriverSpecial i_targetType,
+ deviceOp_t i_regRoute)
+ {
+ Singleton<Associator>::instance().registerRoute(
+ static_cast<int64_t>(i_opType),
+ static_cast<int64_t>(i_accessType),
+ static_cast<int64_t>(i_targetType),
+ i_regRoute);
+ }
+
+ template <>
+ void deviceRegisterRoute<>(DriverSpecial i_opType,
+ AccessType_DriverOnly i_accessType,
+ DriverSpecial i_targetType,
+ deviceOp_t i_regRoute)
+ {
+ Singleton<Associator>::instance().registerRoute(
+ static_cast<int64_t>(i_opType),
+ static_cast<int64_t>(i_accessType),
+ static_cast<int64_t>(i_targetType),
+ i_regRoute);
+ }
+
+ // deviceOp:
+ // OpType - OperationType only.
+ // TargType - TargetType only.
+ // AccType - AccessType, AccessType_DriverOnly (no WILDCARD).
+ template <>
+ ErrorHandle_t deviceOp<>(OperationType i_opType,
+ TargetHandle_t i_target,
+ void* io_buffer, size_t& io_buflen,
+ AccessType i_accessType, ...)
+ {
+ va_list args;
+ ErrorHandle_t errl;
+
+ va_start(args, i_accessType);
+
+ errl = Singleton<Associator>::instance().performOp(
+ i_opType, i_target, io_buffer, io_buflen,
+ i_accessType, args);
+
+ va_end(args);
+ return errl;
+ }
+
+ template <>
+ ErrorHandle_t deviceOp<>(OperationType i_opType,
+ TargetHandle_t i_target,
+ void* io_buffer, size_t& io_buflen,
+ AccessType_DriverOnly i_accessType, ...)
+ {
+ va_list args;
+ ErrorHandle_t errl;
+
+ va_start(args, i_accessType);
+
+ errl = Singleton<Associator>::instance().performOp(
+ i_opType, i_target, io_buffer, io_buflen,
+ i_accessType, args);
+
+ va_end(args);
+ return errl;
+ }
+
+};
diff --git a/src/usr/devicefw/makefile b/src/usr/devicefw/makefile
new file mode 100644
index 000000000..27d73465c
--- /dev/null
+++ b/src/usr/devicefw/makefile
@@ -0,0 +1,8 @@
+ROOTPATH = ../../..
+MODULE = devicefw
+
+OBJS = driverif.o userif.o assoccontain.o associator.o
+
+SUBDIRS = test.d
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/devicefw/test/assoccontaintest.H b/src/usr/devicefw/test/assoccontaintest.H
new file mode 100644
index 000000000..160a8c2f9
--- /dev/null
+++ b/src/usr/devicefw/test/assoccontaintest.H
@@ -0,0 +1,102 @@
+#ifndef __TEST_ASSOCCONTAINTEST_H
+#define __TEST_ASSOCCONTAINTEST_H
+
+#include <cxxtest/TestSuite.H>
+#include "../assoccontain.H"
+
+using namespace DeviceFW;
+
+class AssocContainTest: public CxxTest::TestSuite
+{
+public:
+
+ /**
+ * @test Ensure AssociationContainer can be constructed.
+ */
+ void testConstruct()
+ {
+ AssociationContainer* ac = new AssociationContainer();
+ if (NULL == ac)
+ {
+ TS_FAIL("NULL pointer returned for 'new AssociationContainer'.");
+ }
+ delete ac;
+ }
+
+ /**
+ * @test Verify allocate operation.
+ */
+ void testAllocate()
+ {
+ AssociationContainer ac;
+
+ // Allocation of a single block.
+ size_t root = ac.allocate(5);
+
+ // Index operation on block.
+ AssociationData* root_ptr = ac[root];
+ if (NULL == root_ptr)
+ {
+ TS_FAIL("NULL pointer returned for newly allocated block.");
+ }
+
+ // Freshly allocated block is empty.
+ for(int i = 0; i < 5; i++)
+ {
+ if (root_ptr[i].flag)
+ {
+ TS_FAIL("Wildcard flag set on newly allocated block.");
+ }
+ if (0 != root_ptr[i].offset)
+ {
+ TS_FAIL("Non-zero value set in newly allocated block.");
+ }
+ }
+
+ // Second allocated block is outside original.
+ size_t second_block = ac.allocate(2);
+ if (((second_block + 2) > root) &&
+ (second_block < (root + 5)))
+ {
+ TS_FAIL("Newly allocated block is inside previous block.");
+ }
+ }
+
+ /**
+ * @test Verify operator[].
+ */
+ void testIndex()
+ {
+ AssociationContainer ac;
+
+ AssociationData root;
+ AssociationData second;
+
+ root.offset = ac.allocate(5);
+ second.offset = ac.allocate(2);
+ second.flag = true;
+
+ ac[second.offset][1].offset = 0x42;
+
+ AssociationData* root_ptr = ac[root.offset];
+ root_ptr[2] = second;
+
+ // Check initial level block index.
+ if ((ac[root.offset + 2]->flag != second.flag) ||
+ (ac[root.offset + 2]->offset != second.offset))
+ {
+ TS_FAIL("Index operator points to incorrect block.");
+ }
+
+ // Check second level indirection block index.
+ if (ac[ac[root.offset + 2]->offset + 1]->offset != 0x42)
+ {
+ TS_FAIL("Index operator points to incorrect block.");
+ }
+ }
+
+
+};
+
+#endif
+
diff --git a/src/usr/devicefw/test/associatortest.H b/src/usr/devicefw/test/associatortest.H
new file mode 100644
index 000000000..792b6c3ef
--- /dev/null
+++ b/src/usr/devicefw/test/associatortest.H
@@ -0,0 +1,174 @@
+#ifndef __TEST_ASSOCIATORTEST_H
+#define __TEST_ASSOCIATORTEST_H
+
+#include <cxxtest/TestSuite.H>
+#include "../associator.H"
+
+using namespace DeviceFW;
+
+class AssociatorTest;
+typedef void (AssociatorTest::*test_fn)();
+
+static test_fn g_associatorTest_value;
+static test_fn g_associatorTest_result;
+static OperationType g_associatorTest_opType;
+static int64_t g_associatorTest_accessType;
+
+class AssociatorTest: public CxxTest::TestSuite
+{
+public:
+
+ /**
+ * @test Ensure AssociationContainer can be constructed.
+ */
+ void testConstruct()
+ {
+ Associator* as = new Associator();
+ if (NULL == as)
+ {
+ TS_FAIL("Unable to construct Associator.");
+ }
+ delete as;
+ }
+
+ // Used for registration testing.
+ static
+ ErrorHandle_t performOperation(OperationType i_opType,
+ TargetHandle_t i_target,
+ void* io_buffer, size_t& io_buflen,
+ int64_t i_accessType, va_list i_addr)
+ {
+ g_associatorTest_result = g_associatorTest_value;
+ g_associatorTest_opType = i_opType;
+ g_associatorTest_accessType = i_accessType;
+
+ return NULL;
+ }
+
+ /**
+ * @test Verify simple registration.
+ */
+ void testSimpleRegistration()
+ {
+ void* buf = NULL;
+ size_t bufsize = 0;
+
+ g_associatorTest_value = &AssociatorTest::testSimpleRegistration;
+
+ Associator as;
+ as.registerRoute(READ,
+ SCOM,
+ PROCESSOR,
+ &performOperation);
+
+ ErrorHandle_t l_errl = as.performOp(READ, TargetHandle_t(),
+ buf, bufsize,
+ SCOM, va_list());
+
+ if (l_errl)
+ {
+ TS_FAIL("Error received from performOp.");
+ }
+
+ if (g_associatorTest_result != g_associatorTest_value)
+ {
+ TS_FAIL("PerformOperation does not appear to have been called.");
+ }
+
+ if (g_associatorTest_opType != READ)
+ {
+ TS_FAIL("Invalid operation type.");
+ }
+
+ if (g_associatorTest_accessType != SCOM)
+ {
+ TS_FAIL("Invalid access type.");
+ }
+ }
+
+ /**
+ * @test Verify registration with an operator as a WILDCARD.
+ */
+ void testOpWildcard()
+ {
+ void* buf = NULL;
+ size_t bufsize = 0;
+
+ g_associatorTest_value = &AssociatorTest::testOpWildcard;
+
+ Associator as;
+ as.registerRoute(WILDCARD,
+ SCOM,
+ PROCESSOR,
+ &performOperation);
+
+ ErrorHandle_t l_errl = as.performOp(WRITE, TargetHandle_t(),
+ buf, bufsize,
+ SCOM, va_list());
+
+ if (l_errl)
+ {
+ TS_FAIL("Error received from performOp.");
+ }
+
+ if (g_associatorTest_result != g_associatorTest_value)
+ {
+ TS_FAIL("PerformOperation does not appear to have been called.");
+ }
+
+ if (g_associatorTest_opType != WRITE)
+ {
+ TS_FAIL("Invalid operation type.");
+ }
+
+ if (g_associatorTest_accessType != SCOM)
+ {
+ TS_FAIL("Invalid access type.");
+ }
+ }
+
+ /**
+ * @test Verify registration with a target type as a WILDCARD.
+ */
+ void testTargTypeWildcard()
+ {
+ void* buf = NULL;
+ size_t bufsize = 0;
+
+ g_associatorTest_value = &AssociatorTest::testTargTypeWildcard;
+
+ Associator as;
+ as.registerRoute(READ,
+ SCOM,
+ WILDCARD,
+ &performOperation);
+
+ ErrorHandle_t l_errl = as.performOp(READ, TargetHandle_t(),
+ buf, bufsize,
+ SCOM, va_list());
+
+ if (l_errl)
+ {
+ TS_FAIL("Error received from performOp.");
+ }
+
+ if (g_associatorTest_result != g_associatorTest_value)
+ {
+ TS_FAIL("PerformOperation does not appear to have been called.");
+ }
+
+ if (g_associatorTest_opType != READ)
+ {
+ TS_FAIL("Invalid operation type.");
+ }
+
+ if (g_associatorTest_accessType != SCOM)
+ {
+ TS_FAIL("Invalid access type.");
+ }
+ }
+
+};
+
+#endif
+
diff --git a/src/usr/devicefw/test/makefile b/src/usr/devicefw/test/makefile
new file mode 100644
index 000000000..b3571ae96
--- /dev/null
+++ b/src/usr/devicefw/test/makefile
@@ -0,0 +1,6 @@
+ROOTPATH = ../../../..
+
+MODULE = testdevicefw
+TESTS = *.H
+
+include ${ROOTPATH}/config.mk
diff --git a/src/usr/devicefw/userif.C b/src/usr/devicefw/userif.C
new file mode 100644
index 000000000..3b1f237f8
--- /dev/null
+++ b/src/usr/devicefw/userif.C
@@ -0,0 +1,46 @@
+/** @file driverif.C
+ * Implement the functions from userif.H.
+ */
+
+#include <devicefw/userif.H>
+#include <util/singleton.H>
+
+#include "associator.H"
+
+namespace DeviceFW
+{
+ ErrorHandle_t deviceRead(TargetHandle_t i_target,
+ void* o_buffer, size_t& io_buflen,
+ AccessType i_accessType, ...)
+ {
+ va_list args;
+ ErrorHandle_t errl;
+
+ va_start(args, i_accessType);
+
+ errl = Singleton<Associator>::instance().performOp(
+ READ, i_target, o_buffer, io_buflen,
+ i_accessType, args);
+
+ va_end(args);
+ return errl;
+ }
+
+ ErrorHandle_t deviceWrite(TargetHandle_t i_target,
+ void* i_buffer, size_t& io_buflen,
+ AccessType i_accessType, ...)
+ {
+ va_list args;
+ ErrorHandle_t errl;
+
+ va_start(args, i_accessType);
+
+ errl = Singleton<Associator>::instance().performOp(
+ WRITE, i_target, i_buffer, io_buflen,
+ i_accessType, args);
+
+ va_end(args);
+ return errl;
+ }
+
+};
diff --git a/src/usr/makefile b/src/usr/makefile
index aa24cf6cd..cd0daeba7 100644
--- a/src/usr/makefile
+++ b/src/usr/makefile
@@ -1,6 +1,6 @@
ROOTPATH = ../..
OBJS = module_init.o
-SUBDIRS = example.d trace.d cxxtest.d errl.d
+SUBDIRS = example.d trace.d cxxtest.d errl.d devicefw.d
include ${ROOTPATH}/config.mk
OpenPOWER on IntegriCloud