summaryrefslogtreecommitdiffstats
path: root/src/usr/devicefw
diff options
context:
space:
mode:
authorPatrick Williams <iawillia@us.ibm.com>2011-05-18 11:49:26 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2011-06-02 09:54:48 -0500
commit83e18669b6c2322c8eb5f8632ac823877d765e0d (patch)
tree780c62fbc578e5a3b6c362db40b84e468611dd13 /src/usr/devicefw
parent40d7b75141080adb8b42cc5ea058c91944e7621e (diff)
downloadtalos-hostboot-83e18669b6c2322c8eb5f8632ac823877d765e0d.tar.gz
talos-hostboot-83e18669b6c2322c8eb5f8632ac823877d765e0d.zip
Device Framework support.
Change-Id: I133f58df309c7fc3a7faa261699eba66a6bae4be Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/98 Tested-by: Jenkins Server Reviewed-by: Thi N. Tran <thi@us.ibm.com> Reviewed-by: Andrew J. Geissler <andrewg@us.ibm.com>
Diffstat (limited to 'src/usr/devicefw')
-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
10 files changed, 915 insertions, 0 deletions
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;
+ }
+
+};
OpenPOWER on IntegriCloud