diff options
author | Greg Still <stillgs@us.ibm.com> | 2015-04-06 11:30:30 -0500 |
---|---|---|
committer | Derk Rembold <rembold@de.ibm.com> | 2015-05-21 06:53:54 -0500 |
commit | 8154f8810540dba21865d1566dc5209eef5a3515 (patch) | |
tree | 96090ab85b85cd1dca4a372190e65c1565c79f16 /hwpf/plat/include | |
parent | 1ebc3c0868c74833aabe3775509d65ae29cd4925 (diff) | |
download | talos-sbe-8154f8810540dba21865d1566dc5209eef5a3515.tar.gz talos-sbe-8154f8810540dba21865d1566dc5209eef5a3515.zip |
Initial PPE FAPI2 platform implementation - targets+get/putscom; no Attributes
Change-Id: I805dd3286b1b9d33b585d903d38ba7555bf40c21
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/16869
Reviewed-by: Glenn R. Miles <milesg@us.ibm.com>
Reviewed-by: Derk Rembold <rembold@de.ibm.com>
Tested-by: Derk Rembold <rembold@de.ibm.com>
Diffstat (limited to 'hwpf/plat/include')
-rw-r--r-- | hwpf/plat/include/array.H | 174 | ||||
-rw-r--r-- | hwpf/plat/include/buffer.H | 423 | ||||
-rw-r--r-- | hwpf/plat/include/buffer_base.H | 347 | ||||
-rw-r--r-- | hwpf/plat/include/buffer_parameters.H | 65 | ||||
-rw-r--r-- | hwpf/plat/include/buffer_traits.H | 238 | ||||
-rw-r--r-- | hwpf/plat/include/error_scope.H | 147 | ||||
-rw-r--r-- | hwpf/plat/include/fapi2.H | 44 | ||||
-rw-r--r-- | hwpf/plat/include/fapi2Structs.H | 109 | ||||
-rw-r--r-- | hwpf/plat/include/hw_access.H | 716 | ||||
-rw-r--r-- | hwpf/plat/include/plat_hw_access.H | 78 | ||||
-rw-r--r-- | hwpf/plat/include/plat_includes.H | 40 | ||||
-rw-r--r-- | hwpf/plat/include/plat_target_definitions.H | 112 | ||||
-rw-r--r-- | hwpf/plat/include/plat_target_parms.H | 62 | ||||
-rw-r--r-- | hwpf/plat/include/return_code.H | 187 | ||||
-rw-r--r-- | hwpf/plat/include/target.H | 532 | ||||
-rw-r--r-- | hwpf/plat/include/target_types.H | 132 | ||||
-rw-r--r-- | hwpf/plat/include/utils.H | 56 | ||||
-rw-r--r-- | hwpf/plat/include/variable_buffer.H | 670 |
18 files changed, 4132 insertions, 0 deletions
diff --git a/hwpf/plat/include/array.H b/hwpf/plat/include/array.H new file mode 100644 index 00000000..1b976f2b --- /dev/null +++ b/hwpf/plat/include/array.H @@ -0,0 +1,174 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file array.H + * @brief definitions for fapi2 arrays + */ + +#ifndef __FAPI2_ARRAY__ +#define __FAPI2_ARRAY__ + +#include <stdint.h> +#include <utility> +#include <assert.h> +#include <string.h> + +namespace fapi2 +{ + /// + /// @brief Class representing a FAPI2 array + /// FAPI2 arrays are defined to be very lightweight but support + /// c++ container operations (iterators, bounds checking, assignment, etc.) + /// To avoid the code-bloat associated with std::vector templates, + /// fapi2::array is presently limited to 64-bit elements. + /// + /// To construct an array, you can either pass in an existing chunk + /// of memory, or let the container allocate memory for you: + /// fapi2::array foo(3, &PIB_MEM_BLOCK); + /// creates an array 3 x uit64_t in size, located at &PIB_MEM_BLOCK. + /// The memory pointed to by the address passed in is untouched + /// during creation. This allows for a light-weight overlay on top + /// of existing memory. It also means you need to initialize the space + /// yourself. + /// fapi2_array foo(3); + /// creates an array 3 x uint64_t in size, and that memory will be + /// allocated by the constructor and initiaized to 0's. + /// + /// + class array + { + public: + + typedef uint64_t element_type; + typedef element_type* iterator; + typedef const element_type* const_iterator; + + /// + /// @brief Create an array + /// @param[in] the size of the array + /// @param[in] a pointer to memory of appropriate size + /// defaults to nullptr which causes the platform to + /// allocate memory of size * element_type + /// @warning fapi2::arrays, like arrays, can not be re-sized after + /// creation. + /// + array(const uint32_t i_size, element_type* i_data = nullptr); + + /// + /// @brief Destroy an array + /// + ~array(void); + + /// + /// @brief operator[] + /// @param[in] the index of the element + /// @return a reference to the element in question. + /// @note array[0] = 0 works as well as foo = array[0] + /// + element_type& operator[](const uint32_t i_index); + + /// + /// @brief operator=() + /// @param[in] the other array + /// @return a reference to this, after the assignement + /// + array& operator=(const array& i_other); + + /// + /// @brief move operator=() + /// @note To use: new_array = std::move(old_array). old_array will be + /// destroyed and no copy will be made (moved) + /// + array& operator=(array&& i_other); + + /// + /// @brief operator==() + /// + bool operator==(const array& i_other); + + /// + /// @brief operator!=() + /// + __attribute__ ((always_inline)) + bool operator!=(const array& i_other) + { return ! operator==(i_other); } + + /// + /// @brief Return an iterator the to beginning of the array + /// @return An iterator to the beginning of the array + /// + __attribute__ ((always_inline)) + iterator begin(void) + { return iv_data; } + + /// + /// @brief Return an iterator the to end of the array + /// @return An iterator to the end of the array + /// + __attribute__ ((always_inline)) + iterator end(void) + { return iv_data + size(); } + + /// + /// @brief Return a const_iterator the to beginning of the array + /// @return A const_iterator to the beginning of the array + /// + __attribute__ ((always_inline)) + const_iterator begin(void) const + { return iv_data; } + + /// + /// @brief Return a const_iterator the to end of the array + /// @return A const_iterator to the end the array + /// + __attribute__ ((always_inline)) + const_iterator end(void) const + { return iv_data + size(); } + + private: + + enum + { + // Bit in iv_size representing whether we delete in the dtor + delete_bit = 0x80000000, + + // The resulting size limit + size_limit = 0x7FFFFFFF, + }; + + __attribute__ ((always_inline)) + uint32_t size(void) + { return (iv_size & ~delete_bit); } + + __attribute__ ((always_inline)) + uint32_t size(void) const + { return (iv_size & ~delete_bit); } + + uint32_t iv_size; + element_type* iv_data; + }; +} + +#endif diff --git a/hwpf/plat/include/buffer.H b/hwpf/plat/include/buffer.H new file mode 100644 index 00000000..382b9642 --- /dev/null +++ b/hwpf/plat/include/buffer.H @@ -0,0 +1,423 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file buffer.H + * @brief definitions for fapi2 variable integral buffers + */ + +#ifndef __FAPI2_INTEGRAL_BUFFER__ +#define __FAPI2_INTEGRAL_BUFFER__ + +#include <buffer_base.H> +#include <return_code.H> + +namespace fapi2 +{ + /// @brief Class representing a FAPI buffer<T> + /// @note Buffers support method chaining. So, rather than + /// this + /// @code + /// buffer<T> mask; + /// mask.setBit<B>(); + /// mask.invert(); + /// my_buffer &= mask; + /// @endcode + /// You can do + /// @code + /// my_buffer &= buffer<T>().setBit<B>.invert(); + /// @endcode + template <typename T> + class buffer : public buffer_base<T> + { + public: + /// Shortcut typedef to map to our traits class + typedef typename buffer_base<T, buffer>::bits_type bits_type; + + /// + /// @brief Integral buffer assignment constructor + /// @param[in] i_value initial value of the buffer + /// Meaningless for variable types and thus protected. + /// + inline buffer(T i_value = 0) + { + // Why not an initializer list? That would force buffer_base<T> + // to have a ctor which took a T, and I want to avoid that in + // the generic case: this makes it more clear that the two + // ctor's (integral and container) behave very differently. + // variable_buffers also have a ctor which takes a single + // numerical value, and that represents a bit count, not an + // initial value. + this->iv_data = i_value; + } + + + /// @name Bit/Word Manipulation Functions + ///@{ + + /// + /// @brief Return the length of the buffer in bits + /// @return Length in bits + /// + inline constexpr uint32_t getBitLength(void) const + { return bufferTraits<T>::bit_length(this->iv_data); } + + /// + /// @brief Return the length of the buffer in OT units + /// @return Length in OT units rounded up + /// @tparam OT the type to get the length of. For example, if one + /// wanted the length in double words, OT would be uint64_t + /// (getLength<uint64_t>().) Similarly, to get the length in words, + /// getLength<uin32_t>(). + /// + template< typename OT > + inline constexpr uint32_t getLength(void) const + { + return bufferTraits<T>::template size<OT>(this->iv_data); + } + + /// + /// @brief Templated setBit for integral types + /// @tparam B the bit number to set. + /// @return buffer& Useful for method chaining + /// @note 0 is left-most + /// @note Example: fapi2::buffer<uint64_t>().setBit<3>(); + /// + template <bits_type B> + inline buffer& setBit(void) + { + static_assert((B >= 0) && + (B < bufferTraits<T>::bits_per_unit), "failed range check"); + + // Force iv_data to be dependent on the template type to force + // its look up in the second phase + this->iv_data |= (static_cast<T>(1)) << (bufferTraits<T>::bits_per_unit - B - 1); + return *this; + } + + /// + /// @brief Clear a bit in buffer + /// @tparam B Bit in buffer to clear. + /// @return buffer& Useful for method chaining + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// + template< bits_type B > + inline buffer& clearBit(void) + { + static_assert((B >= 0) && + (B < bufferTraits<T>::bits_per_unit), "failed range check"); + + this->iv_data &= buffer<T>().setBit<B>().invert(); + return *this; + } + + /// + /// @brief Invert bit + /// @tparam B Bit in buffer to invert. + /// @return buffer& Useful for method chaining + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// + template< bits_type B > + inline buffer& flipBit(void) + { + static_assert((B >= 0) && + (B < bufferTraits<T>::bits_per_unit), "failed range check"); + + this->iv_data ^= buffer<T>().setBit<B>(); + return *this; + } + + /// + /// @brief Set a bit in the buffer + /// @param[in] i_bit the bit number to set. + /// @note 0 is left-most + /// @return FAPI2_RC_SUCCESS if OK + /// + inline fapi2::ReturnCode setBit(const bits_type& i_bit) + { + if (i_bit >= bufferTraits<T>::bits_per_unit) + { + return FAPI2_RC_INVALID_PARAMETER; + } + + // Force iv_data to be dependent on the template type to force + // its look up in the second phase + this->iv_data |= + (static_cast<T>(1)) << (bufferTraits<T>::bits_per_unit - i_bit - 1); + return FAPI2_RC_SUCCESS; + } + + /// + /// @brief Get the value of a bit in the buffer + /// @tparam B Bit in buffer to get. + /// @return true if bit is on, false if bit is off + /// + template< bits_type B > + inline bool getBit(void) const + { + return buffer<T>().setBit<B>() & this->iv_data; + } + + ///@} + + /// @name Buffer Manipulation Functions + ///@{ + + // Note: Many (all?) of these are not needed and the compiler complains + // as the cast to T yields a better operator. There are here mainly for + // documenation purposes. + + /// + /// @brief operator>>() + /// +#ifdef DOXYGEN + buffer<T>& operator>>(bits_type i_shiftnum); +#endif + + /// + /// @brief operator<<() + /// +#ifdef DOXYGEN + buffer<T>& operator<<(bits_type i_shiftnum); +#endif + + /// + /// @brief operator+() + /// +#ifdef DOXYGEN + buffer<T>& operator+(const T& rhs); +#endif + + /// + /// @brief operator+=() + /// +#ifdef DOXYGEN + buffer<T>& operator+=(const T& rhs); +#endif + + /// + /// @brief operator|=() + /// +#ifdef DOXYGEN + buffer<T>& operator|=(const T& rhs); +#endif + + /// + /// @brief operator&=() + /// +#ifdef DOXYGEN + buffer<T>& operator&=(const T& rhs); +#endif + + /// + /// @brief operator|() + /// +#ifdef DOXYGEN + buffer<T>& operator|(const T& rhs); +#endif + + /// + /// @brief operator&() + /// +#ifdef DOXYGEN + buffer<T>& operator&(const T& rhs); +#endif + + /// + /// @brief operator^=() + /// +#ifdef DOXYGEN + buffer<T>& operator^=(const T& rhs); +#endif + + /// + /// @brief operator~() + /// +#ifdef DOXYGEN + buffer<T>& operator~(const T& rhs) const; +#endif + + /// + /// @brief operator==() + /// +#ifdef DOXYGEN + bool operator==(const T& rhs) const; +#endif + + /// + /// @brief operator!=() + /// +#ifdef DOXYGEN + bool operator!=(const T& rhs) const; +#endif + + /// + /// @brief Copy part of a OT into the DataBuffer + /// @tparam TS Start bit to insert into (target start) + /// @tparam L Length of bits to insert + /// @tparam SS Start bit in source + /// @tparam OT the type of the incoming (origin) data + /// @param[in] i_datain OT value to copy into DataBuffer + /// - data is taken left aligned + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// + template<bits_type TS, bits_type L, bits_type SS, typename OT> + inline void insert(const OT i_datain) + { + const bits_type target_length = parameterTraits<T>::bit_length; + const bits_type source_length = parameterTraits<OT>::bit_length; + + // Error if input data don't make sense + static_assert((TS + L) <= target_length, + "insert(): (Target Start + Len) is out of bounds"); + static_assert((SS + L) <= source_length, + "insert(): (Source Start + Len) is out of bounds"); + static_assert(TS < target_length, + "insert(): Target Start is out of bounds"); + static_assert(SS < source_length, + "insert(): Source Start is out of bounds"); + + // Get mask value for Target buffer + // Note: Need "& ((T)-1) because bit shift left for Target buffer doesn't roll off + T mask =((T(~0) << (target_length - L)) & T(~0)) >> TS; + + // Calculate the equivalent position of the input Source start for the size of the Target buffer. + + // Assume OT is smaller (sizeof(T) > sizeof(OT)) + uint64_t sourceShift = abs(TS - ((target_length - source_length) + SS)); + uint64_t sourceAlign = T(i_datain) << sourceShift; + + if (sizeof(T) == sizeof(OT)) + { + sourceShift = abs(SS - TS); + sourceAlign = (SS > TS) ? ((T)i_datain) << sourceShift : ((T)i_datain) >> sourceShift; + } + + if (sizeof(T) < sizeof(OT)) + { + sourceShift = source_length - target_length; + if (SS <= sourceShift) + { + sourceShift = sourceShift + TS - SS; + sourceAlign = ((OT)i_datain) >> sourceShift; + } + + // (SS > sourceShift) + else + { + if (sourceShift > TS) + { + sourceShift = SS - sourceShift - TS; + sourceAlign = OT(i_datain) << sourceShift; + } + else + { + sourceShift = SS - sourceShift; + sourceAlign = (sourceShift < TS) ? OT(i_datain) >> sourceShift : OT(i_datain); + } + } + } + + this->iv_data = (this->iv_data & ~mask) | (sourceAlign & mask); + return; + } + + /// + /// @brief Copy in a right aligned value + /// @tparam SB Start bit to insert into + /// @tparam L Length of bits to insert + /// @tparam OT the type of the incoming (origin) data + /// @param[in] i_datain OT value to copy into DataBuffer + /// - data is taken right aligned + /// @note Data is assumed to be aligned on the word boundary of L + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// + template<bits_type TS, bits_type L, typename OT> + inline void insertFromRight(const OT i_datain) + { + // Error if input data don't make sense + static_assert(L <= parameterTraits<OT>::bit_length, + "insertFromRight(): Len >= input buffer"); + static_assert(TS < parameterTraits<T>::bit_length, + "insertFromRight(): Target Start is out of bounds"); + static_assert((TS + L) <= parameterTraits<T>::bit_length, + "InsertFromRight(): (Target Start + Len) is out of bounds"); + + this->insert<TS, L, parameterTraits<OT>::bit_length - L>(i_datain); + return; + } + + /// + /// @brief Copy data from this buffer into an OT + /// @tparam TS Start bit to insert into (target start) + /// @tparam L Length of bits to insert + /// @tparam SS Start bit in source + /// @tparam OT the type of the outgoing (target) + /// @param[out] o_out OT to copy into - data is placed left aligned + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// + template<bits_type TS, bits_type L, bits_type SS, typename OT> + inline void extract(OT& o_out) + { + // Extraction is just an insert into o_out + + buffer<OT> out(o_out); + out.insert<TS, L, SS>(this->iv_data); + o_out = out; + return; + } + +#if 0 + /// + /// @brief Copy data from this buffer into an OT and right justify + /// @tparam OT the type of the outgoing data - defaults to T + /// @tparam SB Start bit to insert into - defaults to 0 + /// @tparam SS Start bit in o_out - default value is zero + /// @tparam L Length of bits to copy - defaults to sizeof(OT) * 8 + /// @param[out] o_out OT to copy into - data is placed right aligned + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// @post Data is copied from specified location to o_out, right + /// aligned. Data is only right aligned if L < sizeof(bits_type) + /// + template< typename OT = T, bits_type L = parameterTraits<OT>::bit_length, + bits_type SB = 0, bits_type SS = 0 > + void extractFromRight(OT& o_out); +#endif + ///@} + }; +}; + +#endif diff --git a/hwpf/plat/include/buffer_base.H b/hwpf/plat/include/buffer_base.H new file mode 100644 index 00000000..45297a06 --- /dev/null +++ b/hwpf/plat/include/buffer_base.H @@ -0,0 +1,347 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file buffer_base.H + * @brief definitions for fapi2 buffer base class + */ + +#ifndef __FAPI2_BUFFER_BASE__ +#define __FAPI2_BUFFER_BASE__ + +#include <stdint.h> +#include <initializer_list> +#include <error_scope.H> +#include <buffer_parameters.H> +#include <buffer_traits.H> +#include <return_code.H> + +namespace fapi2 +{ + /// @brief Base class for buffers and variable buffers + /// @tparam T is the type of iv_data (std::vector, etc) + /// @tparam TT is the template trait, defaults to the trait for T + /// + /// Buffers can be of two styles; buffers made from an integral type and + /// buffers made from a container. Integral type buffers, while limited + /// in size, can be tightly controlled via the compiler by using c++ + /// templates. + /// + /// C++ templates allow for very explicit control, but yield a + /// syntax different than the FAPI 1.x functional interface. For example, + /// a fapi2::buffer is defined as having a type: + /// @code + /// fapi2::buffer<uint64_t> new_buffer; + /// @endcode + /// defines a buffer with exactly 64 bits, and can be manipulated by the + /// compiler as a single intrgral value. These implementations result + /// in concise instruction streams, and a platform may choose to implement + /// all or some or none of the integral buffer types. + /// + /// Buffers which have containers as their underlying implementation + /// are found in the class fapi2::variable_buffer. variable_buffer is little + /// more than + /// @code + /// fapi2::buffer<fapi2::bits_container> + /// @endcode + /// where bits_container is the typedef of the underlying container (a + /// vector of uint32_t, for example) + /// + /// Examples:<br> + /// + /// * Simple uint64_t buffer + /// @code + /// const uint32_t x = 2; + /// + /// // this data buffer will contain data in a uint64_t type + /// fapi2::buffer<uint64_t> data; + /// + /// // Set using the template and a constant + /// data.setBit<x>(); + /// + /// // Set using the template and a value + /// data.setBit<3>(); + /// + /// // Set using the function interface, and a value + /// data.setBit(1); + /// + /// // compiler gets smart. + /// // movabs $0x7000000000000000,%rsi + /// @endcode + /// + /// * variable_buffer, same thing + /// @code + /// + /// const uint32_t x = 2; + /// + /// // Note: only 15 bits long + /// fapi2::variable_buffer data(15); + /// + /// + /// data.setBit(x); + /// data.setBit(3); + /// data.setBit(1); + /// @endcode + /// + /// * method chaining + /// Buffers support method chaining. So, rather than + /// this + /// @code + /// buffer<T> mask; + /// mask.setBit<B>(); + /// mask.invert(); + /// my_buffer &= mask; + /// @endcode + /// You can do + /// @code + /// my_buffer &= buffer<T>().setBit<B>.invert(); + /// @endcode + /// + /// * buffer operations + /// @code + /// + /// // An 8 bit buffer, initialized with a value + /// fapi2::buffer<uint8_t> eight_bits = 0xAA; + /// fapi2::buffer<uint8_t> another_eight; + /// fapi2::buffer<uint16_t> sixteen_bits; + /// + /// // You can't assign an 8 bit buffer to a 16 bit buffer. + /// sixteen_bits = eight_bits; ERROR + /// + /// // But you can assign buffers of the same type + /// another_eight = eight_bits; + /// + /// // You can assign constants (or other known values) directly: + /// sixteen_bits = 0xAABB; + /// @endcode + /// + /// * Variable buffer operations + /// + /// @code + /// fapi2::variable_buffer data(16); + /// + /// // Very large buffers can be initialized rather than set bit by bit. + /// const fapi2::variable_buffer bit_settings_known( + /// {0xFFFF0000, 0xAABBF0F0, + /// 0xFFFF0000, 0xAABBF0F0, + /// 0xFFFF0000, 0xAABBF0F0,}); + /// + /// // Assignment will expand or shrink the size automatically. + /// data = bit_settings_known; + /// + /// // You can assign directly to the buffer: + /// fapi2::variable_buffer other_bits; + /// const fapi2::container_unit x = 0xFF00AA55; + /// other_bits = {x, 0xDEADBEEF}; + /// @endcode + /// + template <typename T, typename TT = bufferTraits<T> > + class buffer_base + { + + public: + + /// Shortcut typedef to get to our traits class + typedef typename TT::bits_type bits_type; + /// Shortcut typedef to get to our traits class + typedef typename TT::unit_type unit_type; + + /// + /// @brief Default constructor + /// @note iv_data will get the "default" construction, which is + /// correct - 0 for integral types, an empty container for the others. + /// + buffer_base(void): + iv_data() + {} + +// @todo doesn't work for PPE +// virtual ~buffer_base(void) + ~buffer_base(void) + {} + +#ifndef DOXYGEN + /// @brief Print the contents of the buffer to stdout + inline void print(void) const + { TT::print(iv_data); } +#endif + /// + /// @brief Get the contents of the buffer + /// @return The contents of the buffer + /// + inline operator T() const { return iv_data; } + + /// + /// @brief Get the contents of the buffer + /// @return The contents of the buffer + /// + inline operator T&() { return iv_data; } + + /// + /// @brief Get the contents of the buffer + /// @return The contents of the buffer + /// + inline T& operator()(void) { return iv_data; } + + /// + /// @brief Get the contents of the buffer + /// @return Reference to the contents of the buffer + /// + inline const T& operator()(void) const { return iv_data; } + + /// + /// @brief Get a pointer to the buffer bits + /// @return Pointer to the buffer itself + /// + inline T* pointer(void) { return &iv_data; } + + /// @name Buffer Manipulation Functions + ///@{ + + /// + /// @brief Set an OT of data in buffer + /// @param[in] i_value sizeof(OT) bits of data + /// @param[in] i_offset Start OT (start word, for example) in buffer + /// - defaults to 0 (will by default write the left most element) + /// @return FAPI2_RC_SUCCESS on success, FAPI2_RC_OVERFLOW otherwise + /// @note This is is only available for integral types. To set a + /// variable_buffer into a variable_buffer, use insert() + /// + template< typename OT> + inline fapi2::ReturnCode set(OT i_value, const bits_type i_offset = 0) + { + // Compile time check to make sure OT isn't a variable buffer + static_assert( !std::is_same<bits_container, OT>::value, + "Can't use a variable_buffer as input to set()" ); + + // + // There's a gotcha in here. size<OT>() returns the size in the buffer + // in OT units *rounded up*. This is the actual size of the buffer, not + // the perceived size of a variable_buffer. This should be OK however, + // as what we're trying to prevent is overflow, which this should do. + // + const uint32_t length = TT:: template size<OT>(iv_data); + static const bits_type bits_in_value = parameterTraits<OT>::bit_length; + const bits_type bit_length = TT::bit_length(iv_data); + + if (i_offset >= length) + { + return FAPI2_RC_OVERFLOW; + } + + // Create mask if part of this byte is not in the valid part of the buffer, + // Shift it left by the amount of unused bits, + // Clear the unused bits + if (((i_offset + 1) == length) && (bit_length % bits_in_value)) { + i_value &= parameterTraits<OT>::mask << ((bits_in_value * length) - bit_length); + } + + parameterTraits<OT>::template write_element<unit_type>(TT::get_address(iv_data), i_value, i_offset); + return FAPI2_RC_SUCCESS; + } + + /// + /// @brief Set and entire buffer to X's + /// @tparam X {0,1} depending if you want to clear (0) + /// or fill (1) a buffer + /// + template< uint8_t X > + inline void flush(void) + { + static_assert( (X == 1) || (X == 0), "bad argument to flush" ); + (0 == X) ? TT::clear(iv_data) : TT::set(iv_data); + } + + /// + /// @brief Invert entire buffer + /// @return buffer_base&, Useful for method chaining + /// + inline buffer_base& invert(void) + { TT::invert(iv_data); return *this; } + + /// + /// @brief Bit reverse entire buffer + /// @return buffer_base&, Useful for method chaining + /// + inline buffer_base& reverse(void) + { TT::reverse(iv_data); return *this; } + + //@} + protected: + + /// + /// @brief Variable buffer constructor + /// @param[in] i_value number of *bits* (sizeof(container_units) * 8) + /// needed. Meaningless for integral types and thus protected. + /// + buffer_base(bits_type i_value); + + /// + /// @brief Variable buffer construct from a list + /// @param[in] i_value an initializer list to initialize the container. + /// Meaningless for integral types and thus protected + /// + buffer_base(std::initializer_list<unit_type> i_value); + + /// + /// @brief Clear the buffer + /// + inline void clear(void) + { TT::clear(iv_data); } + + /// The contents of the buffer + T iv_data; + }; + +// /// +// /// @brief Set and entire buffer to X's +// /// @tparam X {0,1} depending if you want to clear (0) +// /// or fill (1) a buffer +// /// +// template< typename T, typename TT = bufferTraits<T>, uint8_t X > +// inline buffer_base<T, TT>& flush(void) +// { +// static_assert( (X == 1) || (X == 0), "bad argument to flush" ); +// (0 == X) ? TT::clear(iv_data) : TT::set(iv_data); +// return *this; +// } + + + template <typename T, typename TT> + inline buffer_base<T, TT>::buffer_base(bits_type i_value): + iv_data( std::max(bits_type(1), + bits_type(i_value / 8 / sizeof(bits_type)))) + { + } + + template <typename T, typename TT> + inline buffer_base<T, TT>::buffer_base(std::initializer_list<unit_type> i_value): + iv_data(i_value) + { + } +}; + + + +#endif diff --git a/hwpf/plat/include/buffer_parameters.H b/hwpf/plat/include/buffer_parameters.H new file mode 100644 index 00000000..3dc41b26 --- /dev/null +++ b/hwpf/plat/include/buffer_parameters.H @@ -0,0 +1,65 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file buffer_parameters.H + * @brief definitions for fapi2 buffer parameter types + */ + +#ifndef __FAPI2_BUFFER_PARAM__ +#define __FAPI2_BUFFER_PARAM__ + +#include <stdint.h> + +namespace fapi2 +{ + /// @cond + /// @brief Traits of buffer parameters - things passed in + /// @tparam T is the type of i_value (typically an integral type) + template<typename T> + class parameterTraits + { + public: + enum + { + mask = T(~0), + bit_length = sizeof(T) * 8, + byte_length = sizeof(T), + }; + + template<typename U> + inline static void write_element(void* i_data, T i_value, uint32_t i_offset) + { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + T* ptr = (T*)i_data + (i_offset ^ ((sizeof(U) / sizeof(T)) - 1)); +#else + T* ptr = (T*)i_data + i_offset; +#endif + *ptr = i_value; + } + }; + /// @endcond +}; + +#endif diff --git a/hwpf/plat/include/buffer_traits.H b/hwpf/plat/include/buffer_traits.H new file mode 100644 index 00000000..08073fb6 --- /dev/null +++ b/hwpf/plat/include/buffer_traits.H @@ -0,0 +1,238 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file buffer_traits.H + * @brief trait definitions for fapi2 buffer base class + */ + +#ifndef __FAPI2_BUFFER_TRAITS__ +#define __FAPI2_BUFFER_TRAITS__ + +#include <stdint.h> +#include <vector> +#include <algorithm> +#include <buffer_parameters.H> + +#ifdef __FAPI2_DEBUG__ +// for debug printing ... can be removed for flight +#include <iostream> +#endif +#include <iterator> + +namespace fapi2 +{ + /// @cond + /// Types representing a container of bits. Used to create + /// variable_buffer. + typedef uint32_t container_unit; + typedef std::vector<container_unit> bits_container; + + /// @brief Traits of buffers + // In general, we try to give buffers traits reflecting integral types. If + // this fails, the compiler will let someone know. + /// + /// @tparam T is the type of iv_data (std::vector, etc) + /// @tparam B is the type of the bit-specifier, typically uint32_t + template<typename T, typename B = uint32_t> + class bufferTraits + { + public: +#ifndef DOXYGEN +#ifdef __FAPI2_DEBUG__ + /// + /// @brief Print a container of bits + /// @param[in] i_data the container of bits + /// + static inline void print(const T& i_data) + { + // convert to uint64_t to prevent uint8_t from being + // printed as a char. + std::cout << "\tdata is " + << std::hex + << static_cast<uint64_t>(i_data) + << std::dec << std::endl; + } +#endif +#endif + + /// + /// @brief Return the size of the buffer in E units + /// @tparam E, the element size. + /// @param[in] io_buffer the buffer which to size + /// @return The size of the buffer in E's rounded up + /// + template<typename E> + constexpr static B size(const T& i_buffer) + { + return (bit_length(i_buffer) + + (parameterTraits<E>::bit_length - 1)) / + parameterTraits<E>::bit_length; + } + + /// + /// @brief Return the size of the buffer itself + /// @param[in] io_buffer the buffer which to size + /// @return The size of the buffer in bits (not units) + /// + constexpr static B bit_length(const T&) + { return sizeof(T) * 8; } + + /// + /// @brief Clear the buffer + /// @param[in,out] io_buffer the buffer which to clear + /// + static inline void clear(T& io_buffer) + { io_buffer = static_cast<T>(0); } + + /// + /// @brief Set the buffer + /// @param[in,out] io_buffer the buffer which to set + /// + static inline void set(T& io_buffer) + { io_buffer = static_cast<T>(~0); } + + /// + /// @brief Invert the buffer + /// @param[in,out] io_buffer the buffer which to invert + /// + static inline void invert(T& io_buffer) + { io_buffer = ~io_buffer; } + + /// + /// @brief Reverse the buffer + /// @param[in,out] io_buffer the buffer which to reverse + /// + static inline void reverse(T& io_buffer) + { + io_buffer = + ((io_buffer & 0xAAAAAAAAAAAAAAAA) >> 1) | + ((io_buffer & 0x5555555555555555) << 1); + } + + /// + /// @brief Get the address of the buffer as an array + /// @param[in] i_buffer the buffer which to invert + /// @return The address of the first element of the buffer + /// + static inline void* get_address(T& i_buffer) + { return (void*)&i_buffer; } + + typedef B bits_type; + typedef T unit_type; + enum { bits_per_unit = sizeof(unit_type) * 8 }; + }; + + // + // + /// @brief Traits for buffers which are a container of bits + // + // + template<> + class bufferTraits<bits_container, uint32_t> + { + public: +#ifndef DOXYGEN +#ifdef __FAPI2_DEBUG__ + /// + /// @brief Print a container of bits + /// @param[in] i_data the container of bits + /// + static inline void print(const bits_container& i_data) + { + std::cout << "\tdata is " << std::hex; + std::copy(i_data.begin(), i_data.end(), + std::ostream_iterator<container_unit>(std::cout, " ")); + std::cout << std::dec << std::endl; + } +#endif +#endif + + /// + /// @brief Return the size of the buffer in E units + /// @tparam E, the element size. + /// @param[in] io_buffer the buffer which to size + /// @return The size of the buffer in E's rounded up + /// + template<typename E> + constexpr static uint32_t size(const bits_container& i_buffer) + { + return (bit_length(i_buffer) + + (parameterTraits<E>::bit_length - 1)) / + parameterTraits<E>::bit_length; + } + + /// + /// @brief Return the size of the buffer itself + /// @param[in,out] io_buffer the buffer which to size + /// @return The size of the buffer in bits (not units) + /// + static inline uint32_t bit_length(const bits_container& i_buffer) + { return i_buffer.size() * sizeof(container_unit) * 8; } + + /// + /// @brief Clear the buffer + /// @param[in,out] io_buffer the buffer which to clear + /// + static inline void clear(bits_container& io_buffer) + { io_buffer.assign(io_buffer.size(), 0); } + + /// + /// @brief Set the buffer + /// @param[in,out] io_buffer the buffer which to set + /// + static inline void set(bits_container& io_buffer) + { io_buffer.assign(io_buffer.size(), ~0); } + + /// + /// @brief Invert the buffer + /// @param[in,out] io_buffer the buffer which to invert + /// + static inline void invert(bits_container& io_buffer) + { + std::transform(io_buffer.begin(), io_buffer.end(), + io_buffer.begin(), + [](container_unit u) { return ~u; }); + } + + /// + /// @brief Get the address of the buffer as an array + /// @param[in] i_buffer the buffer which to invert + /// @return The address of the first element of the buffer + /// + static inline void* get_address(bits_container& i_buffer) + { + return (void*)&(i_buffer[0]); + } + + typedef uint32_t bits_type; + typedef container_unit unit_type; + enum { bits_per_unit = sizeof(unit_type) * 8 }; + }; + /// @endcond +}; + + + +#endif diff --git a/hwpf/plat/include/error_scope.H b/hwpf/plat/include/error_scope.H new file mode 100644 index 00000000..ccd2f080 --- /dev/null +++ b/hwpf/plat/include/error_scope.H @@ -0,0 +1,147 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file error_scope.H + * @brief definitions which create a scope for automatic error handling + */ + +#ifndef __FAPI2_ERROR_SCOPE__ +#define __FAPI2_ERROR_SCOPE__ + +#include <stdint.h> +#include <thread> +#include <stdio.h> +#include <return_code.H> +#include <plat_includes.H> + + +extern "C" +{ +#ifndef __noRC__ + extern fapi2::ReturnCode G_current_err; +#endif + extern uint64_t G_pib_error_mask; + extern uint64_t G_operational_state; +} + + +/// +/// @brief Place holder until more of the FAPI infrastructure +/// can be compiled with this file +/// @param[in] ... varargs, passed to a platform specific output function +/// @note This is skeleton implementation for prototype purposes. This +/// does not imply "printf" is used on any or all platforms. +/// +#define FAPI_INF( ... ) +#define FAPI_ERR( ... ) PK_TRACE( __VA_ARGS__ ) +//#define FAPI_DBG( ... ) PK_TRACE( __VA_ARGS__ ) +#define FAPI_DBG( ... ) + +/// @cond +#define FAPI_VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N +#define FAPI_VA_NARGS(...) FAPI_VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1) + +//#define FAPI_TRY_IMPL2(...) FAPI_TRY_TRACE (__VA_ARGS__) +#define FAPI_TRY_IMPL2(count, ...) FAPI_TRY ## count (__VA_ARGS__) +#define FAPI_TRY_IMPL(count, ...) FAPI_TRY_IMPL2(count, __VA_ARGS__) + +#ifndef __noRC__ +#define FAPI_TRY_NO_TRACE( __operation__ ) \ + if ((fapi2::current_err = (__operation__)) != fapi2::FAPI2_RC_SUCCESS) \ + { \ + goto clean_up; \ + } +#else +#define FAPI_TRY_NO_TRACE( __operation__ ) \ + (__operation__); +#endif + +// Why debug? Because this isn't a mechanism to gather FFDC +// one should be using FAPI_ASSERT. However, it is nice to +// have a conditional trace in the event of a failure in the +// operation, so that's why this is here. +// if ((fapi2::current_err = (__operation__)) != fapi2::FAPI2_RC_SUCCESS) +#ifndef __noRC__ +#define FAPI_TRY_TRACE( __operation__, ... ) \ + if ((fapi2::current_err = (__operation__)) != fapi2::FAPI2_RC_SUCCESS) \ + { \ + FAPI_DBG(__VA_ARGS__); \ + goto clean_up; \ + } +#define FAPI_CLEANUP() \ +clean_up: +#else +/// @todo: something is wrong needed the goto_cleanup +#define FAPI_TRY_TRACE( __operation__, ... ) \ + FAPI_DBG(__VA_ARGS__); \ + (__operation__) + +#define FAPI_CLEANUP() + +#endif + +#define FAPI_TRY0 FAPI_TRY_NO_TRACE +#define FAPI_TRY1 FAPI_TRY_TRACE +#define FAPI_TRY2 FAPI_TRY_TRACE +#define FAPI_TRY3 FAPI_TRY_TRACE +#define FAPI_TRY4 FAPI_TRY_TRACE +#define FAPI_TRY5 FAPI_TRY_TRACE +/// @endcond + +/// +/// @brief Wrapper to check an operation for an error state +/// and jump to the label cleam_up if there is an error. +/// @param[in] __operation__ an operation which returns a fapi::ReturnCode +/// @param[in] Optional vararg format/agruments for trace output. +/// @note This implementation does not support PIB error masks or +/// FSP operational states. +/// @warning The trace information is only going to be seen during +/// debug, it's not an error or informational trace. This is because +/// traces might not be seen in the field. If you want information +/// you will see on a field error, use FAPI_ASSERT. +/// +#ifdef DOXYGEN +#define FAPI_TRY(__operation__, ...) FAPI_TRY_IMPL +#else +#define FAPI_TRY(...) FAPI_TRY_IMPL(FAPI_VA_NARGS(__VA_ARGS__), __VA_ARGS__) +#endif + +/// +/// @brief Assert a conditional is true. +/// If it is not, the FFDC gathering function is called and the +/// trace is output as a FAPI error trace. +/// @param[in] __conditional__ the condition to assert +/// @param[in] __ffdc__ the FFDC gathering function +/// @param[in] ... varargs, as input to FAPI_ERR +/// +#define FAPI_ASSERT( __conditional__, __ffdc__, ... ) \ + if (! (__conditional__)) \ + { \ + /* __ffdc__; */ \ + FAPI_ERR(__VA_ARGS__); \ + goto clean_up; \ + } + +#endif // __FAPI2_ERROR_SCOPE__ diff --git a/hwpf/plat/include/fapi2.H b/hwpf/plat/include/fapi2.H new file mode 100644 index 00000000..dcf2607b --- /dev/null +++ b/hwpf/plat/include/fapi2.H @@ -0,0 +1,44 @@ +/** + * @file fapi2.H + * + * @brief Includes all the header files necessary for the FAPI2 interface. + */ + + +#ifndef FAPI2_H_ +#define FAPI2_H_ + +// Define which platforms will not have FAPI Return Codes +#undef __noRC__ +#if defined (__CME__) || defined (__SGPE__) || defined (__PGPE__) +#define __noRC__ +#endif + +// Determine if running on a PPE platform +#ifndef __PPE__ +#if defined (__SBE__) || defined (__CME__) || defined (__SGPE__) || defined (__PGPE__) +#define __PPE__ +#endif +#endif + +#include <buffer.H> +#include <buffer_base.H> +#include <buffer_parameters.H> +#include <buffer_traits.H> +#include <error_scope.H> +#include <hw_access.H> +#include <return_code.H> +#include <target.H> +#include <target_types.H> +#include <utils.H> +//#include <variable_buffer.H> +#include <fapi2AttributeService.H> +#include <fapi2AttributeIds.H> // Generated file + + +#endif // FAPI2_H_ + + + + + diff --git a/hwpf/plat/include/fapi2Structs.H b/hwpf/plat/include/fapi2Structs.H new file mode 100644 index 00000000..48d8062e --- /dev/null +++ b/hwpf/plat/include/fapi2Structs.H @@ -0,0 +1,109 @@ +#ifndef fapiStructs_h +#define fapiStructs_h +// Copyright ********************************************************** +// +// File fapiStructs.H +// +// IBM Confidential +// OCO Source Materials +// 9400 Licensed Internal Code +// (C) COPYRIGHT IBM CORP. 1996 +// +// The source code for this program is not published or otherwise +// divested of its trade secrets, irrespective of what has been +// deposited with the U.S. Copyright Office. +// +// End Copyright ****************************************************** + +/** + * @file fapiStructs.H + * @brief fapi eCMD Extension Structures + + * Extension Owner : John Farrugia +*/ + +//-------------------------------------------------------------------- +// Includes +//-------------------------------------------------------------------- +#include <string> + + +//-------------------------------------------------------------------- +// Forward References +//-------------------------------------------------------------------- + +#define ECMD_FAPI_CAPI_VERSION "1.0" ///< eCMD FAPI Extension version + + + +#ifndef ECMD_PERLAPI + +namespace fapi +{ + +/** + * @brief Enumeration of fapi file types + */ +typedef enum { + FAPI_FILE_UNKNOWN, ///< Default for not initialized + FAPI_FILE_HWP +} FileType_t; + + +enum AttributeSource +{ + FAPI_ATTRIBUTE_SOURCE_UNKNOWN = 0x00000000, + FAPI_ATTRIBUTE_SOURCE_PLAT = 0x00000001, + FAPI_ATTRIBUTE_SOURCE_HWP = 0x00000002, +}; + + +#define FAPI_ATTRIBUTE_TYPE_STRING 0x80000000 +#define FAPI_ATTRIBUTE_TYPE_UINT8 0x40000000 +#define FAPI_ATTRIBUTE_TYPE_UINT32 0x20000000 +#define FAPI_ATTRIBUTE_TYPE_UINT64 0x10000000 +#define FAPI_ATTRIBUTE_TYPE_UINT8ARY 0x04000000 +#define FAPI_ATTRIBUTE_TYPE_UINT32ARY 0x02000000 +#define FAPI_ATTRIBUTE_TYPE_UINT64ARY 0x01000000 + +#define FAPI_ATTRIBUTE_MODE_CONST 0x80000000 +/** + @brief Used by the get/set configuration functions to return the data +*/ +template<typename T> +class Attribute +{ +public: + // Constructor + Attribute(); + + // Destructor + ~Attribute(); + + // + /// @brief Assignment Operator. + /// @param[in] i_right Reference to Value to assign from. + /// @return Reference to 'this' Target + /// + Attribute<T>& operator=(const T& i_right) + { + this->value = i_right->value; + } + +private: + T value; + +}; + +inline AttributeData::AttributeData() {} + +inline AttributeData::~AttributeData() {} + +} //namespace +#endif // #ifndef ECMD_PERLAPI +#endif + + + + + diff --git a/hwpf/plat/include/hw_access.H b/hwpf/plat/include/hw_access.H new file mode 100644 index 00000000..90b567d0 --- /dev/null +++ b/hwpf/plat/include/hw_access.H @@ -0,0 +1,716 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file hw_access.H + * + * @brief Defines the hardware access functions for PPE platforms that + * don't leverage FAPI2 return codes. + */ + +#ifndef FAPI2_HWACCESS_H_ +#define FAPI2_HWACCESS_H_ + +#ifdef FAPI_SUPPORT_SPY_AS_ENUM +#include <fapiSpyIds.H> +#endif + +#include <stdint.h> +#include <thread> +#include <buffer.H> +#include <variable_buffer.H> +#include <return_code.H> +#include <target.H> +#include <utils.H> +#include <plat_includes.H> + +//#include <fapi2Util.H> +//#include <fapi2PlatTrace.H> + +#ifdef FAPI_SUPPORT_MULTI_SCOM +#include <fapiMultiScom.H> +#endif + +/// @cond +typedef uint64_t spyId_t; +typedef uint64_t scanRingId_t; +/// @endcond + +namespace fapi2 +{ + + /// + /// @enum fapi2::ChipOpModifyMode + /// @brief Enumeration of modify modes used in HW access modify operations + /// + enum ChipOpModifyMode + { + CHIP_OP_MODIFY_MODE_OR = 1, ///< Modify or mode + CHIP_OP_MODIFY_MODE_AND = 2, ///< Modify and mode + CHIP_OP_MODIFY_MODE_XOR = 3, ///< Modify xor mode + }; + + /// + /// @enum fapi2::RingMode + /// @brief Enumeration of Ring access operation modes + /// This is a bitmap to allow the user to specify multiple modes. + /// + enum RingMode + { + RING_MODE_SET_PULSE = 0x00000001, ///< Set pulse + RING_MODE_NO_HEADER_CHECK = 0x00000002, ///< Dont' check header + // FUTURE_MODE = 0x00000004, + // FUTURE_MODE = 0x00000008, + }; + + //-------------------------------------------------------------------------- + // PIB Error Functions + //-------------------------------------------------------------------------- + + /// @brief Sets the PIB error mask - platform dependant + /// @param[in] i_mask The new error mask + void setPIBErrorMask(uint8_t i_mask) + { + PLAT_SET_PIB_ERROR_MASK(i_mask); + } + + /// @brief Gets the PIB error mask - platform dependant + /// @return uint8_t The current PIB error mask + uint8_t getPIBErrorMask(void) + { + PLAT_GET_PIB_ERROR_MASK(o_pib_mask); + return o_pib_mask; + } + + //-------------------------------------------------------------------------- + // Operational Mode Error Functions + //-------------------------------------------------------------------------- + + /// @enum OpModes operational Mode Error Functions + enum OpModes + { + // These are bit-masks in case they need to be or'd together + NORMAL = 0x00, + IGNORE_HW_ERROR = 0x01, + DO_NOT_DO_WAKEUP = 0x02, + }; + + /// @brief Sets the operational mode + /// @param[in] i_mode The new mode + inline void setOpMode(const OpModes i_mode) + { + // No-op for now. Should set thread-local operational mode + return; + } + + /// @brief Gets the operational mode + /// @return the operational mode + inline OpModes getOpMode(void) + { + // No-op for now. Should read thread-local operational mode + return NORMAL; + } + + //-------------------------------------------------------------------------- + // HW Communication Functions + //-------------------------------------------------------------------------- + + /// @brief Reads a SCOM register from a chip. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target HW target to operate on. + /// @param[in] i_address SCOM register address to read from. + /// @param[out] o_data Buffer that holds data read from HW target. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline void getScom(const Target<K>& i_target, const uint64_t i_address, + buffer<uint64_t>& o_data) + { + // PLAT_GETSCOM(i_target, +// (uint32_t)(i_address & BITS(40,24)), +// &(o_data())); + +// fapi2::ReturnCode l_rc; + PLAT_GETSCOM(current_err, + i_target, + (uint32_t)(i_address & BITS(40,24)), + &(o_data())); + } + + + /// @brief Writes a SCOM register on a chip. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target HW target to operate on. + /// @param[in] i_address SCOM register address to write to. + /// @param[in] i_data Buffer that holds data to write into address. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline void putScom(const Target<K>& i_target, const uint64_t i_address, + buffer<uint64_t>& i_data) + { + + PLAT_PUTSCOM(i_target, + (uint32_t)(i_address & BITS(40,24)), + &(i_data())); + } + + /// @brief Read-modify-write a SCOM register on a chip + /// @tparam K template parameter, passed in target. + /// @param[in] i_target HW target to operate on. + /// @param[in] i_address SCOM register address to write to. + /// @param[in] i_data Buffer that holds data to be modified. + /// @param[in] i_modifyMode The modify mode (or/and/xor). + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline void modifyScom( const Target<K>& i_target, + const uint64_t i_address, + const buffer<uint64_t>& i_data, + const ChipOpModifyMode i_modifyMode) + { + fapi2::buffer<uint64_t> l_modifyDataBuffer; + + PLAT_GETSCOM(i_target, + (uint32_t)(i_address & BITS(40,24)), + &(l_modifyDataBuffer())); + + if ( i_modifyMode == CHIP_OP_MODIFY_MODE_OR) + { + l_modifyDataBuffer |= i_data; + } + + if ( i_modifyMode == CHIP_OP_MODIFY_MODE_AND) + { + l_modifyDataBuffer &= i_data; + } + + if ( i_modifyMode == CHIP_OP_MODIFY_MODE_XOR) + { + l_modifyDataBuffer ^= i_data; + } + + PLAT_PUTSCOM(i_target, + (uint32_t)(i_address & BITS(40,24)), + &(l_modifyDataBuffer())); + return; + } + + /// @brief Writes a SCOM register under mask on a chip + /// @tparam K template parameter, passed in target. + /// @param[in] i_target HW target to operate on. + /// @param[in] i_address SCOM register address to write to. + /// @param[in] i_data Buffer that holds data to write into address. + /// @param[in] i_mask Buffer that holds the mask value. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline void putScomUnderMask(const Target<K>& i_target, + const uint64_t i_address, + buffer<uint64_t>& i_data, + buffer<uint64_t>& i_mask) + { + fapi2::buffer<uint64_t> l_modifyDataBuffer = i_data; + + l_modifyDataBuffer &= i_mask; + + PLAT_PUTSCOM(i_target, + (uint32_t)(i_address & BITS(40,24)), + &(l_modifyDataBuffer())); + return; + } + + + /// @brief Reads a CFAM register from a chip. + /// CFAM register is 32-bit wide. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target HW target to operate on. + /// @param[in] i_address CFAM register address to read from. + /// @param[out] o_data Buffer that holds data read from HW target. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline ReturnCode getCfamRegister(const Target<K>& i_target, + const uint32_t i_address, + buffer<uint32_t>& o_data) + { + PLAT_GETCFAM(i_target.get(), + (uint32_t)(i_address & BITS(40,24)), + &(o_data())); + + return FAPI2_RC_SUCCESS; + } + + /// @brief Writes a CFAM register on a chip. + /// CFAM register is 32-bit wide. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target HW target to operate on. + /// @param[in] i_address CFAM register address to write to. + /// @param[in] i_data Buffer that holds data to write into address. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline ReturnCode putCfamRegister(const Target<K>& i_target, + const uint32_t i_address, + buffer<uint32_t>& i_data) + { + PLAT_PUTCFAM(i_target.get(), + (uint32_t)(i_address & BITS(40,24)), + &(i_data())); + + return FAPI2_RC_SUCCESS; + } + + /// @brief Read-modify-write a CFAM register on a chip. + /// CFAM register is 32-bit wide. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target HW target to operate on. + /// @param[in] i_address CFAM register address to modify. + /// @param[in] i_data Buffer that holds data to be modified. + /// @param[in] i_modifyMode The modify mode (or/and/xor). + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline ReturnCode modifyCfamRegister(const Target<K>& i_target, + const uint32_t i_address, + const buffer<uint32_t>& i_data, + const ChipOpModifyMode i_modifyMode) + { + PLAT_MODCFAM(i_target.get(), + (uint32_t)(i_address & BITS(40,24)), + &(i_data()), + i_modifyMode); + + return FAPI2_RC_SUCCESS; + } + + /// @brief Reads a ring from a chip. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target Target to operate on. + /// @param[in] i_address Ring address to read from. + /// @param[out] o_data Buffer that holds data read from HW target. + /// @param[in] i_ringMode Ring operation mode. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline ReturnCode getRing(const Target<K>& i_target, + const scanRingId_t i_address, + variable_buffer& o_data, + const RingMode i_ringMode = 0) + { + o_data.setBit(0); + o_data.setBit(3); +#ifndef __PPE__ + std::cout << std::hex << " getRing " + << "target: {" << i_target.getType() << "," + << uint64_t(i_target) << "}; " + << "ring address: " << i_address << "; " + << "ring mode: " << i_ringMode << "; " + << "output data:"; + o_data.print(); +#endif + + return FAPI2_RC_SUCCESS; + } + + /// @brief Writes a ring to a chip. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target Target to operate on. + /// @param[in] i_address Ring address to write to. + /// @param[in] i_data Buffer that contains RS4 compressed ring data + /// to write into address + /// @param[in] i_ringMode Ring operation mode. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline ReturnCode putRing(const Target<K>& i_target, + const scanRingId_t i_address, + variable_buffer& i_data, + const RingMode i_ringMode = 0) + { + + return FAPI2_RC_SUCCESS; + } + + + /// @brief Writes a ring to a chip. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target Target to operate on. + /// @param[in] i_address Ring address to write to. + /// @param[in] i_data Pointer to location that contains RS4 compressed + // ring data to write into address + /// @param[in] i_ringMode Ring operation mode. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline ReturnCode putRing(const Target<K>& i_target, + const scanRingId_t i_address, + const void* i_data, + const RingMode i_ringMode = 0) + { + uint64_t* dataPtr = reinterpret_cast<uint64_t*>(const_cast<void*>(i_data)); + + return FAPI2_RC_SUCCESS; + } +#ifndef __PPE__ + /// @brief Read-modify-write a ring on a chip. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target Target to operate on. + /// @param[in] i_address Ring address to modify. + /// @param[in] i_data Buffer that contains RS4 compressed ring data + /// to be modified. + /// @param[in] i_modifyMode The modify mode (or/and/xor) + /// @param[in] i_ringMode Ring operation mode. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + template< TargetType K > + inline ReturnCode modifyRing(const Target<K>& i_target, + const scanRingId_t i_address, + variable_buffer& i_data, + const ChipOpModifyMode i_modifyMode, + const RingMode i_ringMode = 0) + { + + return FAPI2_RC_SUCCESS; + } +#endif + /// @note + /// These spy access interfaces are only used in FSP and cronus + /// HB does not allow spy access + +#if defined(FAPI_SUPPORT_SPY_AS_ENUM) || defined(FAPI_SUPPORT_SPY_AS_STRING) + /// @brief Reads a spy from a chip. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target Target to operate on. + /// @param[in] i_spyId Id of the spy whose data to be read. + /// @param[out] o_data Buffer that holds data read from HW target. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + /// + /// @note: The string version is only supported for cronus. + /// + /// The fapi design to support both FSP and cronus use of get and + /// put spy functions is dependant on the SPY names being expanded + /// to resemble a valid C identifier. This design places some + /// restrictions on the SPY names which can be used. + /// + /// 1. if the spy name contains a # procedure writers should replace + /// it with an __P__ for example - + /// + /// ABUS.RX0.RXPACKS#0.RXPACK.RD.LC.LC.ACT_DIS + /// becomes + /// ABUS.RX0.RXPACKS__P__0.RXPACK.RD.LC.LC.ACT_DIS + /// + /// 2. if the spy name has a number following a "." it must have an + /// underscore prepended to the number. + /// + /// EH.TPCHIP.2KX100_ARY_CLK_EDGES_DLY + /// becomes + /// EH.TPCHIP._2KX100_ARY_CLK_EDGES_DLY + /// + /// Example SPY name: + /// The hardware procedure should call the function like: + /// + /// ABUS.RX0.RXPACKS#0.RXPACK.RD.LC.LC.ACT_DIS + /// + /// fapi::ReturnCode rc = fapiGetSpy( targ, + /// ABUS.RX0.RXPACKS__P__0.RXPACK.RD.LC.LC.ACT_DIS, data ); + /// + /// @note The ID is not in quotes the fapi code will handle adding + /// the quotes for the cronus environment + /// +#endif + +// Set to 1 for fapi2 API test +#define FAPI_SUPPORT_SPY_AS_ENUM 1 + +#ifdef FAPI_SUPPORT_SPY_AS_ENUM + +#ifndef DOCUMENTATION +#define fapiGetSpy(TARGET, ID, DATA) \ + _fapiGetSpy(TARGET, FAPI_SPY_NAMES::ID.value, DATA ) +#endif + +#ifndef __PPE__ + template< TargetType K > + inline ReturnCode _fapiGetSpy(const Target<K>& i_target, + const spyId_t i_spyId, + variable_buffer& o_data) + { + o_data.setBit(1); + o_data.setBit(4); +#ifndef __PPE__ + std::cout << std::hex << " _fapiGetSpy " + << "target: {" << i_target.getType() << "," + << uint64_t(i_target) << "}; " + << "Spy ID: " << i_spyId << "; " + << "output data:"; + o_data.print(); +#endif + return FAPI2_RC_SUCCESS; + } +#endif +#endif + +#ifdef FAPI_SUPPORT_SPY_AS_STRING + +#ifndef DOCUMENTATION +#define fapiGetSpy(TARGET, ID, DATA) _fapiGetSpy(TARGET, #ID, DATA) +#endif +#ifndef __PPE__ + template< TargetType K > + inline ReturnCode _fapiGetSpy(const Target<K>& i_target, + const char * const i_spyId, + variable_buffer& o_data); +#endif +#endif + +#if defined(FAPI_SUPPORT_SPY_AS_ENUM) || defined(FAPI_SUPPORT_SPY_AS_STRING) + /// @brief Writes a spy on a chip. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target Target to operate on. + /// @param[in] i_spyId Id of the spy to write data to. + /// @param[out] i_data Buffer that holds data to write into spy. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + /// + /// @note: The string version is only supported for cronus. + /// + /// The fapi design to support both FSP and cronus use of get and + /// put spy functions is dependent on the SPY names being expanded + /// to resemble a valid C identifier. This design places some + /// restrictions on the SPY names which can be used. + /// + /// 1. if the spy name contains a # procedure writers should replace + /// is with an __P__ for example - + /// + /// ABUS.RX0.RXPACKS#0.RXPACK.RD.LC.LC.ACT_DIS + /// becomes + /// ABUS.RX0.RXPACKS__P__0.RXPACK.RD.LC.LC.ACT_DIS + /// + /// 2. if the spy name has a number following a "." it must have an + /// underscore prepended to the number. + /// + /// EH.TPCHIP.2KX100_ARY_CLK_EDGES_DLY + /// becomes + /// EH.TPCHIP._2KX100_ARY_CLK_EDGES_DLY + /// + /// Example SPY name: + /// The hardware procedure should call the function like: + /// + /// ABUS.RX0.RXPACKS#0.RXPACK.RD.LC.LC.ACT_DIS + /// + /// fapi::ReturnCode rc = fapiPutSpy( targ, + /// ABUS.RX0.RXPACKS__P__0.RXPACK.RD.LC.LC.ACT_DIS, data ); + /// + /// @note The ID is not in quotes the fapi code will handle adding + /// the quotes for the cronus environment + /// +#endif + +#ifdef FAPI_SUPPORT_SPY_AS_ENUM +#ifndef DOCUMENTATION +#define fapiPutSpy(TARGET, ID, DATA) \ + _fapiPutSpy(TARGET, FAPI_SPY_NAMES::ID.value, DATA) +#endif + + template< TargetType K > + inline ReturnCode _fapiPutSpy(const Target<K>& i_target, + const spyId_t i_spyId, + variable_buffer& i_data) + { +#ifndef __PPE__ + std::cout << std::hex << " _fapiPutSpy " + << "target: {" << i_target.getType() << "," + << uint64_t(i_target) << "}; " + << "Spy Id: " << i_spyId << "; " + << "input data:"; + i_data.print(); +#endif + return FAPI2_RC_SUCCESS; + } + +#endif + +#ifdef FAPI_SUPPORT_SPY_AS_STRING +#ifndef DOCUMENTATION +#define fapiPutSpy(TARGET, ID, DATA) _fapiPutSpy(TARGET, #ID, DATA) +#endif + template< TargetType K > + inline ReturnCode _fapiPutSpy(const Target<K>& i_target, + const spyId_t i_spyId, + variable_buffer& i_data) +#endif + +#if defined(FAPI_SUPPORT_SPY_AS_ENUM) || defined(FAPI_SUPPORT_SPY_AS_STRING) + + /// @brief Writes spy data into a buffer holding ring data image + /// This API is used by L2/L3 repair to put column repair data + /// into a ring buffer image. + /// @tparam K template parameter, passed in target. + /// @param[in] i_target Target to operate on. + /// @param[in] i_spyId Id of the spy. + /// @param[in] i_data Buffer that holds spy data to write into ring + /// image. + /// @param[out] o_data Buffer that holds updated ring image. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + /// + /// @note: The string version is only supported for cronus. + /// + /// The fapi design to support both FSP and cronus use of get and + /// put spy functions is dependent on the SPY names being expanded + /// to resemble a valid C identifier. This design places some + /// restrictions on the SPY names which can be used. + /// + /// See fapiPutSpy for details on spy id specifics. + /// +#endif + +#ifdef FAPI_SUPPORT_SPY_AS_ENUM +#ifndef DOCUMENTATION +#define fapiPutSpyImage(TARGET, ID, DATA1, DATA2) \ + _fapiPutSpyImage(TARGET, \ + FAPI_SPY_NAMES::ID.value, \ + DATA1, DATA2) +#endif + template< TargetType K > + inline ReturnCode _fapiPutSpyImage(const Target<K>& i_target, + const spyId_t i_spyId, + variable_buffer& i_data, + variable_buffer& o_imageData) + { +#ifndef __PPE__ + std::cout << std::hex << " _fapiPutSpyImage " + << "target: {" << i_target.getType() << "," + << uint64_t(i_target) << "}; " + << "Spy Id: " << i_spyId << "; " + << "input data: "; + i_data.print(); +#endif + // Set fake output data + o_imageData.invert(); + + return FAPI2_RC_SUCCESS; + } +#endif + +#ifdef FAPI_SUPPORT_SPY_AS_STRING +// fapiPutSpyImage function Cronus version +#ifndef DOCUMENTATION +#define fapiPutSpyImage(TARGET, ID, DATA1, DATA2) \ + _fapiPutSpyImage(TARGET, #ID, \ + DATA1,DATA2) +#endif + + template< TargetType K > + inline ReturnCode _fapiPutSpyImage(const Target<K>& i_target, + const char* const i_spyId, + variable_buffer& i_data, + variable_buffer& o_imageData); +#endif + +#if defined(FAPI_SUPPORT_SPY_AS_ENUM) || defined(FAPI_SUPPORT_SPY_AS_STRING) + /// @brief Reads spy data from a ring image buffer + /// @param[in] i_target Target to operate on + /// @param[in] i_spyId The spy's id + /// @param[out] o_data Buffer that holds data read from ring image. + /// @param[in] i_imageData Buffer that holds ring image to read data + /// from. + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + /// + /// @note: The string version is only supported for cronus. + /// + /// The fapi design to support both FSP and cronus use of get and + /// put spy functions is dependent on the SPY names being expanded + /// to resemble a valid C identifier. This design places some + /// restrictions on the SPY names which can be used. + /// + /// See fapiPutSpy for details on spy id specifics. + /// +#endif + +#ifdef FAPI_SUPPORT_SPY_AS_ENUM +#ifndef DOCUMENTATION +#define fapiGetSpyImage(TARGET, ID, DATA1, DATA2) \ + _fapiGetSpyImage(TARGET, \ + FAPI_SPY_NAMES::ID.value, \ + DATA1, DATA2) +#endif + template< TargetType K > + inline ReturnCode _fapiGetSpyImage(const Target<K>& i_target, + const spyId_t i_spyId, + variable_buffer& o_data, + const variable_buffer& i_imageData); +#endif + +#ifdef FAPI_SUPPORT_SPY_AS_STRING +// fapiGetSpyImage function Cronus version +#ifndef DOCUMENTATION +#define fapiGetSpyImage(TARGET, ID, DATA1, DATA2) \ + _fapiGetSpyImage(TARGET, \ + #ID, DATA1,DATA2) +#endif + + inline fapi::ReturnCode _fapiGetSpyImage( + const fapi::Target& i_target, + const char* const i_spyId, + fapi::buffer<fapi::bits_container> & o_data, + const fapi::buffer<fapi::bits_container> & i_imageData); +#endif + +#ifdef FAPI_SUPPORT_MULTI_SCOM + + /// @brief Performs a multiple SCOM operation + /// This interface performs multiple SCOM operations on a chip in the + /// order specified by the input MultiScom object. + /// See fapiMultiScom.H for details of how to populate the MultiScom + /// object with SCOM operations. + /// + /// @tparam K template parameter, passed in target. + /// @param[in] i_target Target to operate on. + /// @param[in,out] io_multiScomObj Reference to a MultiScom object, + /// pre-populated with SingleScomInfo entries + /// to perform multiple SCOMs on input target + /// @return fapi::ReturnCode. FAPI2_RC_SUCCESS if success, else error code. + /// + /// @note This is a synchronous interface and would return after all the + /// SCOM operations are completed or on the first failed operation + /// + /// @note SCOMs will be performed in the order they were added to the + /// input MultiScom object + /// + /// @note In case of errors, the platform code is responsible to collect + /// and add all the required error info and FFDC into the error data + /// for debugging + /// + /// @note If the SCOM operations added are specific to a processor chip, + /// then the FSI Shift Engine configured in scatter-gather DMA mode + /// extension would be used to execute the SCOM operations in a + /// performance optimize mode. In this mode, the special + /// SCOM_BULK_READ_MODE and SCOM_BULK_WRITE_MODE operations are + /// supported that allow a large bulk of SCOM access (in multiple of + /// 64 bits) for targets that support auto-increment. The + /// SCOM_WRITE_UNDER_MASK operation is not supported in this mode + /// + /// @note If the SCOM operations added are specific to a memory buffer + /// chip, then the regular SCOM engine is used to execute the SCOM + /// operations. SCOM_WRITE_UNDER_MASK operation is supported in + /// this mode, but the special SCOM_BULK_READ_MODE and + /// SCOM_BULK_WRITE_MODE operations are not supported due to + /// hardware limitations. + /// + inline fapi::ReturnCode fapiMultiScom (const Target<K>& i_target, + MultiScom& io_multiScomObj); +#endif // FAPI_SUPPORT_MULTI_SCOM + +}; + +#endif // FAPI2HWACCESS_H_ diff --git a/hwpf/plat/include/plat_hw_access.H b/hwpf/plat/include/plat_hw_access.H new file mode 100644 index 00000000..9bfccfcc --- /dev/null +++ b/hwpf/plat/include/plat_hw_access.H @@ -0,0 +1,78 @@ +/** + * @file plat_hw_access.H + * + * @brief Define platform specific calls for PPE Platforms that use the machine + * check function of the PPE to deal with errors (eg no explicit return codes + * returned) + */ + +#ifndef PLATHWACCESS_H_ +#define PLATHWACCESS_H_ + +#include <plat_includes.H> + +/// PIB Error Mask + +#define PLAT_SET_PIB_ERROR_MASK(_m_mask) \ + { /* Read MSR */ \ + uint32_t msr_data = mfmsr(); \ + /* Set SEM field */ \ + msr_data &= ~(BITS(0,8)); \ + msr_data |= (uint32_t)(i_mask << 24); \ + /* Write MSR */ \ + mtmsr(msr_data); \ + }; + +#define PLAT_GET_PIB_ERROR_MASK(_m_mask) \ + uint8_t _m_mask; \ + uint32_t _sem = mfmsr(); \ + _m_mask = (uint8_t)((_sem & MSR_SEM) >> (32-(MSR_SEM_START_BIT + MSR_SEM_LEN))); + +// Building block PPE instructions +#define PPE_MFMSR(_m_data) \ +asm volatile \ + ( \ + "mfmsr %[data] \n" \ + : [data]"=&r"(*_m_data) \ + : "[data]"(*_m_data) \ + ); + +#define PPE_MTMSR(_m_data) \ +asm volatile \ + ( \ + "mtmsr %[data] \n" \ + : [data]"=&r"(*_m_data) \ + : "[data]"(*_m_data) \ + ); + + +/// GetScom +#define PLAT_GETSCOM(_m_rc, _m_base, _m_offset, _m_data) \ + PPE_LVDX(_m_base.getAddressOverlay(), (uint32_t)(_m_offset & BITS(40,24)), _m_data) + +/// PutScom +#define PLAT_PUTSCOM(_m_base, _m_offset, _m_data) \ + PPE_STVDX(_m_rc, _m_base.getAddressOverlay(), (uint32_t)(_m_offset & BITS(40,24)), _m_data) + +/// ModifyScom +#define PLAT_MODSCOM(_m_base, _m_offset, _m_data, _m_mode) \ + PPE_STVDX(_m_base.getAddressOverlay(), _m_offset, _m_data) + + +/// GetCFAM +#define PLAT_GETCFAM(_m_base, _m_offset, _m_data) \ + static_assert( K == TARGET_TYPE_NONE, \ + "getCfamRegister is not supported by PPE platforms") + +/// PutCFAM +#define PLAT_PUTCFAM(_m_base, _m_offset, _m_data) \ + static_assert( K == TARGET_TYPE_NONE, \ + "putCfamRegister is not supported by PPE platforms") + +/// ModifyCFAM +#define PLAT_MODCFAM(_m_base, _m_offset, _m_data, _m_mode) \ + static_assert( K == TARGET_TYPE_NONE, \ + "modifyCfamRegister is not supported by PPE platforms") + +#endif // PLATHWACCESS_H_ + diff --git a/hwpf/plat/include/plat_includes.H b/hwpf/plat/include/plat_includes.H new file mode 100644 index 00000000..97074b67 --- /dev/null +++ b/hwpf/plat/include/plat_includes.H @@ -0,0 +1,40 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file plat_includes.H + * @brief Platform specific include to implement FAPI2 APIs + */ + +#ifndef __PLAT_INCLUDES_H__ +#define __PLAT_INCLUDES_H__ + +#include <plat_hw_access.H> + +#include <ppe42_scom.h> +#include <ppe42_msr.h> +//#include <pk.h> + + +#endif // __PLAT_INCLUDES_H__ diff --git a/hwpf/plat/include/plat_target_definitions.H b/hwpf/plat/include/plat_target_definitions.H new file mode 100644 index 00000000..c2ec0518 --- /dev/null +++ b/hwpf/plat/include/plat_target_definitions.H @@ -0,0 +1,112 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file plat_ppe_target.H + * @brief Definitions for fapi2 PPE targets + */ + +#ifndef __FAPI2_PPE_TARGET__ +#define __FAPI2_PPE_TARGET__ + +#define TARGET_CHIP(_name, _index) \ + fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP > _name((uint64_t)_index); + +#define TARGET_CHIP_PERV(_name, _index) \ + fapi2::Target<fapi2::TARGET_TYPE_PERV> _name((uint64_t)_index); + +#define TARGET_EQ(_name, _index) \ + fapi2::Target<fapi2::TARGET_TYPE_EQ> _name((uint64_t)_index); + +#define TARGET_CORE(_name, _index) \ + fapi2::Target<fapi2::TARGET_TYPE_CORE> _name((uint64_t)_index); + +#define TARGET_EX(_name, _index) \ + fapi2::Target<fapi2::TARGET_TYPE_EX> _name((uint64_t)_index); + +namespace fapi2 +{ + + TARGET_CHIP (chip_target, 0); + TARGET_CHIP_PERV (perv_target, 1); + TARGET_CHIP_PERV (n0_target, 2); + TARGET_CHIP_PERV (n1_target, 3); + TARGET_CHIP_PERV (n2_target, 4); + TARGET_CHIP_PERV (n3_target, 5); + TARGET_CHIP_PERV (xb_target, 6); + TARGET_CHIP_PERV (mc0_target, 7); + TARGET_CHIP_PERV (mc1_target, 8); + TARGET_CHIP_PERV (ob0_target, 9); + TARGET_CHIP_PERV (ob1_target, 10); + TARGET_CHIP_PERV (ob2_target, 11); + TARGET_CHIP_PERV (ob3_target, 12); + TARGET_CHIP_PERV (pci0_target, 13); + TARGET_CHIP_PERV (pci1_target, 14); + TARGET_CHIP_PERV (pci2_target, 15); + TARGET_EQ (eq0_target, 0); + TARGET_EQ (eq1_target, 1); + TARGET_EQ (eq2_target, 2); + TARGET_EQ (eq3_target, 3); + TARGET_EQ (eq4_target, 4); + TARGET_EQ (eq5_target, 5); + TARGET_EX (ex0_target, 0); + TARGET_EX (ex1_target, 1); + TARGET_EX (ex2_target, 2); + TARGET_EX (ex3_target, 3); + TARGET_EX (ex4_target, 4); + TARGET_EX (ex5_target, 5); + TARGET_EX (ex6_target, 6); + TARGET_EX (ex7_target, 7); + TARGET_EX (ex8_target, 8); + TARGET_EX (ex9_target, 9); + TARGET_EX (ex10_target, 10); + TARGET_EX (ex11_target, 11); + TARGET_CORE (core0_target, 0); + TARGET_CORE (core1_target, 1); + TARGET_CORE (core2_target, 2); + TARGET_CORE (core3_target, 3); + TARGET_CORE (core4_target, 4); + TARGET_CORE (core5_target, 5); + TARGET_CORE (core6_target, 6); + TARGET_CORE (core7_target, 7); + TARGET_CORE (core8_target, 8); + TARGET_CORE (core9_target, 9); + TARGET_CORE (core10_target,10); + TARGET_CORE (core11_target,11); + TARGET_CORE (core12_target,12); + TARGET_CORE (core13_target,13); + TARGET_CORE (core14_target,14); + TARGET_CORE (core15_target,15); + TARGET_CORE (core16_target,16); + TARGET_CORE (core17_target,17); + TARGET_CORE (core18_target,18); + TARGET_CORE (core19_target,19); + TARGET_CORE (core20_target,20); + TARGET_CORE (core21_target,21); + TARGET_CORE (core22_target,22); + TARGET_CORE (core23_target,23); + +}; // fapi2 namespace + +#endif // __FAPI2_PPE_TARGET__ diff --git a/hwpf/plat/include/plat_target_parms.H b/hwpf/plat/include/plat_target_parms.H new file mode 100644 index 00000000..4931f790 --- /dev/null +++ b/hwpf/plat/include/plat_target_parms.H @@ -0,0 +1,62 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file plat_ppe_target.H + * @brief Definitions for fapi2 PPE targets + */ + +#ifndef __FAPI2_PPE_TARGET_PARMS__ +#define __FAPI2_PPE_TARGET_PARMS__ + + +#ifndef __ASSEMBLER__ + +const uint64_t CHIPLET_COUNT = 0x38; + +const uint64_t CHIP_TARGET_COUNT = 1; +const uint64_t CHIP_TARGET_OFFSET = 0; + +const uint64_t PERV_TARGET_OFFSET = CHIP_TARGET_OFFSET + CHIP_TARGET_COUNT; +const uint64_t PERV_CHIPLET_OFFSET = 0x1; +const uint64_t PERV_TARGET_COUNT = 15; + +const uint64_t EQ_TARGET_OFFSET = PERV_TARGET_OFFSET + PERV_TARGET_COUNT; +const uint64_t EQ_CHIPLET_OFFSET = 0x10; +const uint64_t EQ_TARGET_COUNT = 6; + +const uint64_t CORE_TARGET_OFFSET = EQ_TARGET_OFFSET + EQ_TARGET_COUNT; +const uint64_t CORE_CHIPLET_OFFSET = 0x20; +const uint64_t CORE_TARGET_COUNT = 24; + +const uint64_t EX_TARGET_OFFSET = CORE_TARGET_OFFSET + CORE_TARGET_COUNT; +const uint64_t EX_CHIPLET_OFFSET = 0x10; +const uint64_t EX_TARGET_COUNT = 12; + + +const uint64_t TARGET_COUNT = EX_TARGET_OFFSET + EX_TARGET_COUNT; + +#endif + +#endif // __FAPI2_PPE_TARGET_PARMS__ diff --git a/hwpf/plat/include/return_code.H b/hwpf/plat/include/return_code.H new file mode 100644 index 00000000..225f1b0a --- /dev/null +++ b/hwpf/plat/include/return_code.H @@ -0,0 +1,187 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file return_code.H + * @brief definitions for fapi2 return codes + */ + +#ifndef __FAPI2_RETURN_CODE__ +#define __FAPI2_RETURN_CODE__ + +#include <stdint.h> + +// Remove this for platforms which don't support FFDC +//#include <ffdc.H> + +/// +/// @brief Set HWP Error macro +/// +/// This macro should be used by a HWP to create an error. The ReturnCode's +/// internal return code is set and any error information in the Error XML file +/// is added to the ReturnCode +/// +#define FAPI_SET_HWP_ERROR(RC, ERROR) \ + RC._setHwpError(fapi2::ERROR); \ + ERROR##_CALL_FUNCS_TO_COLLECT_FFDC(RC); \ + ERROR##_CALL_FUNCS_TO_COLLECT_REG_FFDC(RC); \ + ERROR##_ADD_ERROR_INFO(RC) + +/// +/// @brief Add info to HWP Error macro +/// +/// This macro should be used by an FFDC HWP to add error information from an +/// Error XML file to an existing error. +/// +#define FAPI_ADD_INFO_TO_HWP_ERROR(RC, ERROR) \ + ERROR##_CALL_FUNCS_TO_COLLECT_FFDC(RC); \ + ERROR##_CALL_FUNCS_TO_COLLECT_REG_FFDC(RC); \ + ERROR##_ADD_ERROR_INFO(RC) + +namespace fapi2 +{ + /// + /// @brief Enumeration of return codes + /// + enum ReturnCodes + { + ///< Success + FAPI2_RC_SUCCESS = 0, + + // Flag bits indicating which code generated the error. + FAPI2_RC_FAPI2_MASK = 0x04000000, ///< FAPI2 mask + FAPI2_RC_PLAT_MASK = 0x02000000, ///< Platform mask + FAPI2_RC_HWP_MASK = 0x00000000, ///< HWP mask + + // + // FAPI generated return codes + // + + FAPI2_RC_INVALID_ATTR_GET = FAPI2_RC_FAPI2_MASK | 0x01, + ///< Initfile requested an attribute with an invalid attribute ID + + FAPI2_RC_INVALID_CHIP_EC_FEATURE_GET = FAPI2_RC_FAPI2_MASK | 0x02, + ///< HWP requested a chip EC feature with an invalid attribute ID + + FAPI2_RC_INVALID_MULTISCOM_LENGTH = FAPI2_RC_FAPI2_MASK | 0x03, + ///< Invalid multiscom parameters + + FAPI2_RC_INVALID_PARAMETER = FAPI2_RC_FAPI2_MASK | 0x04, + ///< Invalid parameters to a FAPI2 function + + FAPI2_RC_OVERFLOW = FAPI2_RC_FAPI2_MASK | 0x05, + ///< Overflow condition, typically a buffer operation + + // + // PLAT generated return codes. Additional details may be contained in + // ReturnCode platData (this can only be looked at by PLAT code) + // + + FAPI2_RC_PLAT_ERR_SEE_DATA = FAPI2_RC_PLAT_MASK | 0x01, + ///< Generic platform error + + FAPI2_RC_PLAT_ERR_ADU_LOCKED = FAPI2_RC_PLAT_MASK | 0x02, + ///< Operation to AlterDisplay unit failed because it is locked + + FAPI2_RC_PLAT_NOT_SUPPORTED_AT_RUNTIME = FAPI2_RC_PLAT_MASK | 0x03, + ///< Operation not supported by HB runtime + }; + + + /// + /// @brief Class representing a FAPI2 ReturnCode + /// + /// @note Remove the inheritance relationship with FirstFailureData if + /// the platform doesn't support FFDC. + class ReturnCode + { + public: + + /// + /// @brief Constructor. + /// @param[in] i_rc the rc to set + /// + ReturnCode(const uint32_t i_rc = FAPI2_RC_SUCCESS): + iv_rc(i_rc) + {}; + + /// + /// @brief integral type conversion function. Returns the error code + /// @return The error code + /// + inline operator uint32_t() const { return iv_rc; } + + /// + /// @brief Returns true iff iv_rc == SUCCESS + /// @return true or false + /// + inline operator bool() const { return iv_rc == FAPI2_RC_SUCCESS; } + + /// + /// @brief Assignement operator + /// + inline ReturnCode& operator=(const uint32_t& rhs) + { + iv_rc = rhs; + return *this; + } + + inline ReturnCode& operator=(const ReturnCodes& rhs) + { + iv_rc = rhs; + return *this; + } + + inline bool operator==(const uint32_t& rhs) const + { return rhs == iv_rc; } + + inline bool operator==(const ReturnCodes& rhs) const + { return rhs == iv_rc; } + + inline bool operator!=(const uint32_t& rhs) const + { return rhs != iv_rc; } + + inline bool operator!=(const ReturnCodes& rhs) const + { return rhs != iv_rc; } + + ReturnCode& insertPIBcode(const uint32_t& pibrc) + { + iv_rc = FAPI2_RC_PLAT_MASK | pibrc; + return *this; + } + + private: + uint32_t iv_rc; + }; + + /// This implementation assumes no exception handling and leverages thread-local + /// storage. For platforms without thread support, a global variable will + /// suffice for the error state. + extern thread_local ReturnCode current_err; /// the current error state + extern thread_local uint32_t pib_error_mask; /// the pib mask + extern thread_local uint32_t operational_state; /// the operational mode + +}; + +#endif diff --git a/hwpf/plat/include/target.H b/hwpf/plat/include/target.H new file mode 100644 index 00000000..1610069d --- /dev/null +++ b/hwpf/plat/include/target.H @@ -0,0 +1,532 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file target.H + * @brief definitions for fapi2 targets + */ + +#ifndef __FAPI2_TARGET__ +#define __FAPI2_TARGET__ + +#include <stdint.h> +//#include <vector> +#include <target_types.H> +#include <utils.H> +#include "plat_target_parms.H" + +#define MC_ENABLE 0x1 << 6 +#define MC_WRITE 5 +#define MC_READ_OR 0 +#define MC_READ_AND 1 + +#define EX_ADDRESS_MASK 0x0000FF00 + + +namespace fapi2 +{ + /// + /// @brief Class representing a FAPI2 Target + /// @tparam K the type (Kind) of target + /// @tparam V the type of the target's Value + /// @remark TargetLite targets are uint64_t, Targets + /// are uintptr_t (void*). + /// + /// Assuming there are representations of a processor, + /// a membuf and a system here are some examples: + /// @code + /// #define PROCESSOR_CHIP_A 0xFFFF0000 + /// #define MEMBUF_CHIP_B 0x0000FFFF + /// #define SYSTEM_C 0x0000AAAA + /// @endcode + /// + /// * To define a target: + /// @code + /// fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> A(PROCESSOR_CHIP_A); + /// fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> C(SYSTEM_C); + /// fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP> B(MEMBUF_CHIP_B); + /// @endcode + /// + /// * Functions which take composite target types + /// @code + /// void takesProcOrMembuf( + /// const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP | + /// fapi2::TARGET_TYPE_MEMBUF_CHIP>& V ); + /// + /// void takesAny(const fapi2::Target<fapi2::TARGET_TYPE_ALL>& V ); + /// + /// @endcode + /// + /// * Traversing the target "tree" + /// @code + /// fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> A(PROCESSOR_CHIP_A); + /// + /// // Get A's parent + /// A.getParent<fapi2::TARGET_TYPE_SYSTEM>(); + /// + /// // Get the 0x53'd core + /// fapi2::getTarget<fapi2::TARGET_TYPE_CORE>(0x53); + /// + /// // Get all *my* present/functional children which are cores + /// A.getChildren<fapi2::TARGET_TYPE_CORE>(); + /// + /// // Get all of the the cores relative to my base target + /// fapi2::getChildren<fapi2::TARGET_TYPE_CORE>(); + /// @endcode + /// + /// * Invalid casts + /// @code + /// // Can't cast to a specialized target + /// fapi2::Target<fapi2::TARGET_TYPE_NONE> D(MEMBUF_CHIP_B); + /// takesProcOrMembuf( D ); + /// + /// // Not one of the shared types + /// fapi2::Target<fapi2::TARGET_TYPE_ABUS_ENDPOINT> E; + /// takesProcOrMembuf( E ); + /// @endcode + template<TargetType K, typename V = uint64_t> + class Target + { + public: + + /// + /// @brief Create a Target, with a value + /// @param[in] V the value (i.e., specific element this + /// target represents, or pointer) + /// @note Platforms can mangle the value and K to get a + /// single uint64_t in value which represents all the information + /// they might need. value( K | V ), for example + /// + + /// Default constructor is basically a TARGET_TYPE_ALL + Target() + { + this->iv_handle.fields.chiplet_num = 0; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + Target( V Value ) + { + static_assert( ((K == TARGET_TYPE_CORE) & + (K == TARGET_TYPE_EQ) ) != true, + "TARGET_TYPE_CORE and TARGET_TYPE_EQ cannot be specified at the same time"); + + if(K & TARGET_TYPE_PROC_CHIP) + { + this->iv_handle.fields.chiplet_num = Value; + this->iv_handle.fields.type = TARGET_TYPE_PROC_CHIP; + this->iv_handle.fields.type_target_num = Value; // TODO: check this +// this->iv_address.fields.chiplet_num = Value; + } + + if(K & TARGET_TYPE_PERV) + { + this->iv_handle.fields.chiplet_num = Value; + this->iv_handle.fields.type = TARGET_TYPE_PERV | TARGET_TYPE_PROC_CHIP; + this->iv_handle.fields.type_target_num = Value; // TODO: check this +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + if(K & TARGET_TYPE_CORE) + { + /* + if (Value > CORE_CHIPLET_COUNT) + { + PK_TRACE("Chiplet number is greater than CORE_CHIPLET_COUNT"); + return -1; + } + */ + this->iv_handle.fields.chiplet_num = Value + CORE_CHIPLET_OFFSET; + this->iv_handle.fields.type = TARGET_TYPE_CORE; + this->iv_handle.fields.type_target_num = Value; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + if(K & TARGET_TYPE_EQ) + { + this->iv_handle.fields.chiplet_num = Value + EQ_CHIPLET_OFFSET; + this->iv_handle.fields.type = TARGET_TYPE_EQ; + this->iv_handle.fields.type_target_num = Value; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + if(K & TARGET_TYPE_EX) + { + + this->iv_handle.fields.chiplet_num = (Value / 2) + EX_CHIPLET_OFFSET; + this->iv_handle.fields.type = TARGET_TYPE_EX; + this->iv_handle.fields.type_target_num = Value; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + if(K & TARGET_TYPE_EQ_MC_WRITE) + { + this->iv_handle.fields.chiplet_num = + (((MC_ENABLE) | + ((MC_WRITE << 3) | (Value & 0x07))) & + BITS(57,7)); + this->iv_handle.fields.type = TARGET_TYPE_EQ_MC_WRITE; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + if(K & TARGET_TYPE_EQ_MC_READOR) + { + this->iv_handle.fields.chiplet_num = + (((MC_ENABLE) | + ((MC_READ_OR << 3) | (Value & 0x07))) & + BITS(57,7)); + this->iv_handle.fields.type = TARGET_TYPE_EQ_MC_READOR; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + if(K & TARGET_TYPE_EQ_MC_READAND) + { + this->iv_handle.fields.chiplet_num = + (((MC_ENABLE) | + ((MC_READ_AND << 3) | (Value & 0x07))) & + BITS(57,7)); + this->iv_handle.fields.type = TARGET_TYPE_EQ_MC_READAND; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + if(K & TARGET_TYPE_CORE_MC_WRITE) + { + this->iv_handle.fields.chiplet_num = + (((MC_ENABLE) | + ((MC_WRITE << 3) | (Value & 0x07))) & + BITS(57,7)); + this->iv_handle.fields.type = TARGET_TYPE_CORE_MC_WRITE; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + if(K & TARGET_TYPE_CORE_MC_READOR) + { + this->iv_handle.fields.chiplet_num = + (((MC_ENABLE) | + ((MC_READ_OR << 3) | (Value & 0x07))) & + BITS(57,7)); + this->iv_handle.fields.type = TARGET_TYPE_CORE_MC_READOR; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + if(K & TARGET_TYPE_CORE_MC_READAND) + { + this->iv_handle.fields.chiplet_num = + (((MC_ENABLE) | + ((MC_READ_AND << 3) | (Value & 0x07))) & + BITS(57,7)); + this->iv_handle.fields.type = TARGET_TYPE_CORE_MC_READAND; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + + if(K == TARGET_TYPE_ALL) + { + this->iv_handle.fields.chiplet_num = Value; + this->iv_handle.fields.type = TARGET_TYPE_ALL; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; + } + +// if(K == TARGET_TYPE_ADDRESS) +// { +// this->iv_handle.fields.chiplet_num = Value; +// this->iv_address.fields.chiplet_num = this->iv_handle.fields.chiplet_num; +// } + } + + /// + /// @brief Assignment Operator. + /// @param[in] i_right Reference to Target to assign from. + /// @return Reference to 'this' Target + /// + Target<K,V>& operator=(const Target<K,V>& i_right) + { + this->iv_handle.value = i_right->iv_handle.value; + this->iv_addresss.value = i_right->iv_address.value; + return *this; + } + + /// + /// @brief Equality Comparison Operator + /// @param[in] i_right Reference to Target to compare. + /// @return bool. True if equal. + /// + bool operator==(const Target<K,V>& i_right) const + { + if (this->iv_handle.value == i_right->iv_handle.value) + return true; + else + return false; + } + /// + /// @brief Inquality Comparison Operator + /// @param[in] i_right Reference to Target to compare. + /// @return bool. True if equal. + /// + bool operator!=(const Target<K,V>& i_right) const + { + if (this->iv_handle.value != i_right->iv_handle.value) + return true; + else + return false; + } + + /// + /// @brief Get the handle. + /// @return V The target's handle, or value + /// + V get(void) const + { + return this->iv_handle.value; + } + + /// + /// @brief Get the handle as a V + /// @return V The target's handle, or value + /// + operator V() const + { + return this->iv_handle.value; + } + + /// + /// @brief Get a target's value + /// @return V The target's handle, or value + /// + V& operator()(void) + { + return *this->iv_handle; + } + + /// + /// @brief Get the target type + /// @return The type of target represented by this target + /// + TargetType getType(void) const + { + return (TargetType)this->iv_handle.fields.type; + } + + /// + /// @brief Get address overlay to reduce runtime processing + /// @return Overlay as a type V + /// + V getAddressOverlay(void) const + { + return this->iv_handle.fields.address_overlay; + } + + +#if 0 + /// + /// @brief Get this target's immediate parent + /// @tparam T The type of the parent + /// @return Target<T> a target representing the parent + /// + template<TargetType T> + Target<T,V> getParent(void) const + { + static_assert((T & ~(TARGET_TYPE_PROC_CHIP | TARGET_TYPE_PERV) != 0), + "Only TARGET_TYPE_PROC_CHIP and TARGET_TYPE_PERV parent types supported"); + + static_assert( ((((T & TARGET_TYPE_PROC_CHIP) == 0) & + (T & TARGET_TYPE_PERV ) == 0) ), + "Either TARGET_TYPE_PROC_CHIP or TARGET_TYPE_PERV parent type must be specified"); + } + + /// + /// @brief Get this target's children + /// @tparam T The type of the parent + /// @return std::vector<Target<T> > a vector of present/functional + /// children + /// + template< TargetType T> + std::vector<Target<T,V> > getChildren(void) const + { + static_assert( ((T & ~TARGET_TYPE_PROC_CHIP) != 0 ) != true, + "Only TARGET_TYPE_CHIP and TARGET_TYPE_EQ child types supported"); + + if(K & TARGET_TYPE_PROC_CHIP) + { + std::vector<Target<T,V> chip_children(CHIPLET_COUNT); + for (int i = 0; i < CHIPLET_COUNT; i++) + { + if (this->iv_handle.fields.type == TARGET_TYPE_PROC_CHIP & + this->iv_handle.fields.present = 1 & + this->iv_handle.fields.functional = 1 ) + { + chip_children.push_back(this->iv_handle) + } + } + return chip_children; + } + + if(K & TARGET_TYPE_PERV) + { + this->iv_handle.fields.chiplet_num = Value; + // this->iv_handle.fields.type_perv = 1; + this->iv_handle.fields.type_target_num = 0; + } + + } + + /// + /// @brief Get the target at the other end of a bus - dimm included + /// @tparam T The type of the parent + /// @return Target<T> a target representing the thing on the other end + /// @note Can be easily changed to a vector if needed + /// + template<TargetType T> + Target<T,K> getOtherEnd(void) const + { + static_assert( false, "getOtherEnd() is not supported on PPE platforms"); + } +#endif + + /// + /// @brief Copy from a Target<O> to a Target<K> + /// @tparam O the target type of the other + /// + template<TargetType O> + Target<K,V>( const Target<O>& Other ): + Target<K,V>(Other.get()) + { + static_assert( (K & O) != 0, + "unable to cast Target, no shared types"); + + static_assert( bitCount<K>::count >= bitCount<O>::count, + "unable to cast to specialized Target"); + } + + private: + +// union { +// V value; +// struct { +// #ifdef _BIG_ENDIAN +// V chiplet_num : 8; +// V _reserved_b24 : 24; +// #else +// V _reserved_b24 : 24; +// V chiplet_num : 8; +// #endif +// } fields; +// +// } iv_address; +// + union { + V value; + struct { +#ifdef _BIG_ENDIAN + V chiplet_num : 8; + V type_target_num : 8; + V type : 8; + V _reserved_b6 : 6; + V present : 1; + V functional : 1; + V address_overlay : 32; +#else + V address_overlay : 32; + V functional : 1; + V present : 1; + V _reserved_b6 : 6; + V type : 8; + V type_target_num : 8; + V chiplet_num : 8; +#endif + } fields; + } iv_handle ; + +// uint64_t iv_present_children; +// uint64_t iv_functional_children; + + }; + + +#if 0 + /// + /// @brief Return the string interpretation of this target + /// @tparam T The type of the target + /// @tparam B The type of the buffer + /// @param[in] The Target<T> + /// @param[in] The buffer + /// @return void + /// @post The contents of the buffer is replaced with the string + /// representation of the target + /// + template<TargetType T, typename B> + void toString(const Target<T>& i_target, B& i_buffer) + { + static_assert( false, "toString is not supported on PPE platforms"); + } + + /// + /// @brief Get an enumerated target of a specific type + /// @tparam T The type of the target + /// @param[in] uint64_t representing the ordinal number of + /// the desired target + /// @return Target<T> the target requested + /// + template<TargetType T> + Target<T> getTarget(uint64_t Ordinal) + { + // For testing + return Target<T>(Ordinal); + } +#endif + // Why has the been removed? For starters, the API name + // is probably wrong as it's already been confused with + // Target::getChildren(). And if I'm going to change it + // I really want to see if we need it. I'm still not + // clear on whether we're alloing this traversal or not. +#if 0 + /// + /// @brief Get the base target's children + /// @tparam T The type of the target + /// @return std::vector<Target<T> > a vector of present/functional + /// children + /// + template<TargetType T> + std::vector<Target<T> > getChildren() + { + // For testing + return {Target<T>(), Target<T>()}; + } +#endif + + /// + /// @brief Check if the target is of a type, or in a type subset. + /// @tparam K the TargetType to check + /// @tparam T TargetType or TargetType composite to check against + /// @return True, iff K is a proper T + /// + template< TargetType K, TargetType T > + constexpr bool is_same(void) + { return (K & T) != 0; } + + + + +}; +//#include "plat_ppe_targets_hold.H" +#endif diff --git a/hwpf/plat/include/target_types.H b/hwpf/plat/include/target_types.H new file mode 100644 index 00000000..a5d9526b --- /dev/null +++ b/hwpf/plat/include/target_types.H @@ -0,0 +1,132 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file target_types.H + * @brief definitions for fapi2 target types + */ + +#ifndef __FAPI2_TARGET_TYPES__ +#define __FAPI2_TARGET_TYPES__ + +#ifndef __ASSEMBLER__ + + +/// FAPI namespace +namespace fapi2 +{ + /// + /// @enum fapi::TargetType + /// @brief Types, kinds, of targets + /// @note TYPE_NONE is used to represent empty/NULL targets in lists + /// or tables. TYPE_ALL is used to pass targets to methods which + /// can act generally on any type of target + /// + /// Target Kind + enum TargetType + { + TARGET_TYPE_NONE = 0x00, ///< No type + TARGET_TYPE_PROC_CHIP = 0x01, ///< Processor type + TARGET_TYPE_EX = 0x02, ///< Ex type + TARGET_TYPE_CORE = 0x04, ///< Core type + TARGET_TYPE_EQ = 0x08, ///< EQ type + TARGET_TYPE_PERV = 0x10, ///< Pervasive type + TARGET_TYPE_EQ_MC_WRITE = 0x20, ///< EQ Multicast Type + TARGET_TYPE_EQ_MC_READAND = 0x21, ///< EQ Multicast Read AND Type + TARGET_TYPE_EQ_MC_READOR = 0x22, ///< EQ Multicast Read OR Type + TARGET_TYPE_CORE_MC_WRITE = 0x23, ///< Core Multicast Type + TARGET_TYPE_CORE_MC_READAND = 0x24, ///< Core Multicast Read AND Type + TARGET_TYPE_CORE_MC_READOR = 0x25, ///< Core Multicast Read OR Type + TARGET_TYPE_CME_CORE0 = 0x40, ///< CME Core0 (CME only) + TARGET_TYPE_CME_CORE1 = 0x41, ///< CME Core1 (CME only) + TARGET_TYPE_ALL = 0xFF, ///< Any/All types + + +// TARGET_TYPE_NONE = 0x00000000, ///< No type +// TARGET_TYPE_SYSTEM = 0x00000001, ///< System type +// TARGET_TYPE_DIMM = 0x00000002, ///< DIMM type +// TARGET_TYPE_PROC_CHIP = 0x00000004, ///< Processor type +// TARGET_TYPE_MEMBUF_CHIP = 0x00000008, ///< Membuf type +// TARGET_TYPE_EX = 0x00000010, ///< Ex type +// TARGET_TYPE_MBA = 0x00000020, ///< MBA type +// TARGET_TYPE_MCS = 0x00000040, ///< MCS type +// TARGET_TYPE_XBUS = 0x00000080, ///< XBUS type +// TARGET_TYPE_ABUS = 0x00000100, ///< ABUS type +// TARGET_TYPE_L4 = 0x00000200, ///< L4 type +// TARGET_TYPE_CORE = 0x00000400, ///< Core type +// TARGET_TYPE_EQ = 0x00000800, ///< EQ type +// TARGET_TYPE_MCA = 0x00001000, ///< MCA type +// TARGET_TYPE_MCBIST = 0x00002000, ///< MCBIST type +// TARGET_TYPE_MIA = 0x00004000, ///< MIA type +// TARGET_TYPE_MIS = 0x00008000, ///< MIS type +// TARGET_TYPE_DMI = 0x00010000, ///< DMI type +// TARGET_TYPE_OBUS = 0x00020000, ///< OBUS type +// TARGET_TYPE_NV = 0x00040000, ///< NV bus type +// TARGET_TYPE_SBE = 0x00080000, ///< SBE type +// TARGET_TYPE_PPE = 0x00100000, ///< PPE type +// TARGET_TYPE_PERV = 0x00200000, ///< Pervasive type +// TARGET_TYPE_PEC = 0x00400000, ///< PEC type +// TARGET_TYPE_PHB = 0x00800000, ///< PHB type +// TARGET_TYPE_EQ_MC_WRITE = 0x01000000, ///< EQ Multicast Type +// TARGET_TYPE_EQ_MC_READAND = 0x02000000, ///< EQ Multicast Read AND Type +// TARGET_TYPE_EQ_MC_READOR = 0x04000000, ///< EQ Multicast Read OR Type +// TARGET_TYPE_CORE_MC_WRITE = 0x08000000, ///< Core Multicast Type +// TARGET_TYPE_CORE_MC_READAND = 0x10000000, ///< Core Multicast Read AND Type +// TARGET_TYPE_CORE_MC_READOR = 0x20000000, ///< Core Multicast Read OR Type +// TARGET_TYPE_CME_CORE0 = 0x40000000, ///< CME Core0 (CME only) +// TARGET_TYPE_CME_CORE1 = 0x80000000, ///< CME Core1 (CME only) +// TARGET_TYPE_ADDRESS = 0xAAAAAAAA, ///< Address Overlay Type +// TARGET_TYPE_ALL = 0xFFFFFFFF, ///< Any/All types + }; + + + /** + * @brief Typedef used when passing multiple TargetType values + */ + typedef uint8_t TargetTypes_t; + + /// @cond + constexpr TargetType operator|(TargetType x, TargetType y) + { + return static_cast<TargetType>(static_cast<int>(x) | + static_cast<int>(y)); + } + + template<uint64_t V> + class bitCount { + public: + // Don't use enums, too hard to compare + static const uint8_t count = bitCount<(V >> 1)>::count + (V & 1); + }; + + template<> + class bitCount<0> { + public: + static const uint8_t count = 0; + }; + /// @endcond +}; + +#endif // __ASSEMBLER__ +#endif // __FAPI2_TARGET_TYPES__ diff --git a/hwpf/plat/include/utils.H b/hwpf/plat/include/utils.H new file mode 100644 index 00000000..8a86e2ed --- /dev/null +++ b/hwpf/plat/include/utils.H @@ -0,0 +1,56 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file utils.H + * + * @brief Defines common utility elements for FAPI2 use. + */ + +#ifndef FAPI2_UTILS_H_ +#define FAPI2_UTILS_H_ + +#ifdef __ASSEMBLER__ + +#ifndef ULL +#define ULL(x) x +#endif + +#else + +#ifndef ULL +#define ULL(x) x##ull + +#endif + +#endif // __ASSEMBLER + +/// Create a multi-bit mask of \a n bits starting at bit \a b +#define BITS(b, n) ((ULL(0xffffffffffffffff) << (64 - (n))) >> (b)) + +/// Create a single bit mask at bit \a b +#define BIT(b) BITS((b), 1) + + +#endif // FAPI2_UTILS_H_ diff --git a/hwpf/plat/include/variable_buffer.H b/hwpf/plat/include/variable_buffer.H new file mode 100644 index 00000000..fa9e4a05 --- /dev/null +++ b/hwpf/plat/include/variable_buffer.H @@ -0,0 +1,670 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file variable_buffer.H + * @brief definitions for fapi2 variable length buffers + */ + +#ifndef __FAPI2_VARIABLE_BUFFER__ +#define __FAPI2_VARIABLE_BUFFER__ + +#include <buffer_base.H> + +namespace fapi2 +{ + /// @brief Get a 32 bit mask quickly + // This is one of the main reasons we static_assert in the ctor's + // to ensure the unit_type is 32 bits. + inline uint32_t fast_mask32(int32_t i_pos, int32_t i_len) + { + // generates an arbitrary 32-bit mask using two operations, not too shabby + + static const uint32_t l_mask32[] = { + 0x00000000, + 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, + 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, + 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, + 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, + 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, + 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, + 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, + 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF, + }; + return l_mask32[i_len] >> i_pos; + } + + // + // General set a series of bits in the buffer. + // + + /// + /// @cond + /// @brief Internal bit inserting method. + /// @tparam unit_type The type of a unit of the arrays + /// @tparam bits_type The type of the bit counting values + /// @param[in] i_source The incoming data + /// @param[in] i_source_length The length in bits of the incoming data + /// @param[in] i_target The outgoing data + /// @param[in] i_target_length The length in bits of the outgoing data + /// @param[in] i_source_start_bit The starting bit location in the + /// incoming data + /// @param[in] i_target_start_bit The starting bit position in this + /// @param[in] i_length The length, in bits, the user wants copied. + /// + template<typename unit_type, typename bits_type> + inline fapi2::ReturnCode _insert(const unit_type* i_source, + bits_type i_source_length, + unit_type* i_target, + bits_type i_target_length, + bits_type i_source_start_bit, + bits_type i_target_start_bit, + bits_type i_length) + { + const bits_type bits_per_unit = fapi2::parameterTraits<unit_type>::bit_length; + + // tartgetStart is defaulted to the sizeof(target) - (sizeof(source) - i_source_start_bit) + // which makes this act like insert from right + if (i_target_start_bit == ~0) + { + i_target_start_bit = (i_target_length - (i_source_length - i_source_start_bit)); + } + + // len defaults to (sizeof(OT) * 8) - i_source_start_bit + if (i_length == ~0) + { + i_length = i_source_length - i_source_start_bit; + } + + // Check for overflow + if ((i_length + i_target_start_bit > i_target_length) || + (i_length + i_source_start_bit > i_source_length)) + { + return fapi2::FAPI2_RC_OVERFLOW; + } + + do + { + const bits_type src_idx = i_source_start_bit / bits_per_unit; + const bits_type trg_idx = i_target_start_bit / bits_per_unit; + + // "slop" = unaligned bits + const bits_type src_slop = i_source_start_bit % bits_per_unit; + const bits_type trg_slop = i_target_start_bit % bits_per_unit; + + // "cnt" = largest number of bits to be moved each pass + bits_type cnt = std::min(i_length, bits_per_unit); + cnt = std::min(cnt, bits_per_unit - src_slop); + cnt = std::min(cnt, bits_per_unit - trg_slop); + + // generate the source mask only once + bits_type mask = fast_mask32(src_slop, cnt); + + // read the source bits only once + bits_type src_bits = i_source[src_idx] & mask; + + // "shift" = amount of shifting needed for target alignment + int32_t shift = trg_slop - src_slop; + + // ideally (i << -1) would yield (i >> 1), but it + // doesn't, so we need an extra branch here + + if (shift < 0) + { + src_bits <<= -shift; + mask <<= -shift; + } + else + { + src_bits >>= shift; + mask >>= shift; + } + + // clear source '0' bits in the target + i_target[trg_idx] &= ~mask; + // set source '1' bits in the target + i_target[trg_idx] |= src_bits; + + i_source_start_bit += cnt; + i_target_start_bit += cnt; + + i_length -= cnt; + } while (0 < i_length); + + return fapi2::FAPI2_RC_SUCCESS; + } + /// @endcond + + /// @brief Class representing a FAPI variable_buffer. + /// @remark Variable buffers are buffers which can be variable in length + /// (and "odd sized.") These best represent the FAPI 1.X ecmdDataBuffer, + /// however they are implemented using the same template techniques + /// as the new fapi::buffer. + /// @note Variable buffers are not (presently) declared as std::bitset + /// as bitsets' size is fixed at runtime. It is not clear if this is + /// acceptable for variable_buffers at this time. + /// @note Variable buffers are not (presently) declared as std::vector<bool> + /// as it would need to be implemented separate from std::vector, and + /// it's not clear it would give us any real advantage. Howevever, its is + /// more likely this will become a std::vector<bool> than a std::bitset. + class variable_buffer : public buffer_base<bits_container> + { + + public: + + /// + /// @brief Variable buffer constructor + /// @param[in] i_value number of *bits* (sizeof(uint_type) * 8) + /// needed. + variable_buffer(bits_type i_value = 0); + + /// + /// @brief Variable buffer list constructor + /// @param[in] i_value an initializer list to initialize the container. + /// + variable_buffer(const std::initializer_list<unit_type>& i_value); + + /// @name Bit/Word Manipulation Functions + ///@{ + + /// + /// @brief Return the length of the buffer in bits + /// @return Length in bits + /// + inline uint32_t getBitLength(void) const + { return iv_perceived_bit_length; } + + /// + /// @brief Return the length of the buffer in OT units + /// @return Length in OT units rounded up + /// @tparam OT the type to get the length of. For example, if one + /// wanted the length in double words, OT would be uint64_t + /// (getLength<uint64_t>().) Similarly, to get the length in words, + /// getLength<uin32_t>(). + /// + template< typename OT > + inline uint32_t getLength(void) const + { + static const uint32_t bits_in_ot = sizeof(OT) * 8; + return (getBitLength() + (bits_in_ot - 1)) / bits_in_ot; + } + + /// + /// @brief Set a bit in the buffer + /// @param[in] i_bit the bit number to set. + /// @note 0 is left-most + /// @return FAPI2_RC_SUCCESS if OK + /// + inline fapi2::ReturnCode setBit(const bits_type& i_bit) + { + const bits_type index = i_bit / bits_per_unit; + + if (index > iv_data.size()) + { + return FAPI2_RC_INVALID_PARAMETER; + } + + +/// @todo: check with Brian no the correct parens + iv_data[index] |= + unit_type(1) << ((bits_per_unit - 1) - + (i_bit - (index * bits_per_unit))); + + return FAPI2_RC_SUCCESS; + } + + /// + /// @brief Clear a bit in buffer + /// @tparam SB Start bit in buffer to clear. + /// @tparam L Number of consecutive bits from start bit to + /// clear + /// @return FAPI2_RC_SUCCESS on success + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// + template< bits_type SB, bits_type L > + fapi2::ReturnCode clearBit(void); + + /// + /// @brief Invert bit + /// @tparam SB Start bit in buffer to invert. + /// @tparam L Number of consecutive bits from start bit to + /// invert, defaults to 1 + /// @return FAPI2_RC_SUCCESS on success + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// + template< bits_type SB, bits_type L = 1 > + fapi2::ReturnCode flipBit(void); + + /// + /// @brief Get the value of a bit in the buffer + /// @tparam B Bit in buffer to get. + /// @return true/1 if bit is on, false/0 if bit is off + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// + template< bits_type B > + inline bool getBit(void) const + { + const bits_type index = B / bits_per_unit; + const unit_type mask = unit_type(1) << (bits_per_unit - 1) - (B - (index * bits_per_unit)); + return iv_data[index] & mask; + } + + /// + /// @brief Test if multiple bits are set + /// @tparam SB Start bit in buffer to test. + /// @tparam L Number of consecutive bits from start bit to + /// test, defaults to 1 + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// @return true if all bits in range are set - false if any + /// bit is clear + /// + template< bits_type SB, bits_type L = 1 > + bool isBitSet(void) const; + + /// + /// @brief Test if multiple bits are clear + /// @tparam SB Start bit in buffer to test. + /// @tparam L Number of consecutive bits from start bit to + /// test, defaults to 1 + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// @return true if bit is clear - false if bit is set + /// + template< bits_type SB, bits_type L = 1 > + bool isBitClear(void) const; + + /// + /// @brief Count number of bits set in a range + /// @tparam SB Start bit in buffer to test. + /// @tparam L Number of consecutive bits from start bit to + /// test, defaults to 1 + /// @note Asserting that all the parameters are known at + /// compile time so this can be templated only. If that is not + /// the case we can add a function parameter version. + /// @return Number of bits set in range + /// + template< bits_type SB, bits_type L = 1 > + bits_type getNumBitsSet(void) const; + + ///@} + + /// @name Buffer Manipulation Functions + ///@{ + + // Note: Many (all?) of these are not needed and the compiler complains + // as the cast to T yields a better operator. There are here mainly for + // documenation purposes. + + /// + /// @brief operator>>() + /// +#ifdef DOXYGEN + variable_buffer<T>& operator>>(bits_type i_shiftnum); +#endif + + /// + /// @brief operator<<() + /// +#ifdef DOXYGEN + variable_buffer<T>& operator<<(bits_type i_shiftnum); +#endif + + /// + /// @brief operator+() + /// +#ifdef DOXYGEN + variable_buffer<T>& operator+(const T& rhs); +#endif + + /// + /// @brief operator+=() + /// +#ifdef DOXYGEN + variable_buffer<T>& operator+=(const T& rhs); +#endif + + /// + /// @brief operator|=() + /// +#ifdef DOXYGEN + variable_buffer<T>& operator|=(const T& rhs); +#endif + + /// + /// @brief operator&=() + /// +#ifdef DOXYGEN + variable_buffer<T>& operator&=(const T& rhs); +#endif + + /// + /// @brief operator|() + /// +#ifdef DOXYGEN + variable_buffer<T>& operator|(const T& rhs); +#endif + + /// + /// @brief operator&() + /// +#ifdef DOXYGEN + variable_buffer<T>& operator&(const T& rhs); +#endif + + /// + /// @brief operator^=() + /// +#ifdef DOXYGEN + variable_buffer<T>& operator^=(const T& rhs); +#endif + + /// + /// @brief operator!=() + /// +#ifdef DOXYGEN + bool operator!=(const T& rhs) const; +#endif + + /// + /// @brief operator==() + /// @return true if and only if lhs == rhs + /// + inline bool operator==(const fapi2::bits_container& rhs) const + { + if (&iv_data == &rhs) + { + return true; + } + + return iv_data == rhs; + } + + /// + /// @brief Copy part of an element into the DataBuffer + /// @param[in] i_data OT value to copy into DataBuffer + /// @param[in] i_targetStart The position in this where the copy starts + /// @param[in] i_len How many bits to copy + /// @param[in] i_sourceStart The start positon in i_data, defaults to 0 + /// @return FAPI2_RC_SUCCESS on success, FAPi2_RC_OVERFLOW otherwise + /// + template<typename OT> + fapi2::ReturnCode insert(const OT& i_data, + bits_type i_targetStart = 0, + bits_type i_len = ~0, + bits_type i_sourceStart = 0); + + /// + /// @brief Copy in a right aligned (decimal) element + /// @param[in] i_data the incoming data + /// - data is taken right aligned + /// @param[in] i_targetStart The starting bit position in this + /// - Defaultst to 0 + /// @param[in] i_len The length, in bits, the user wants copied. + /// - Defaults to all of the bits in the source which fit + /// @return FAPI2_RC_SUCCESS on success, FAPI2_RC_OVERFLOW otherwise + /// + template<typename OT> + fapi2::ReturnCode insertFromRight(const OT& i_data, + bits_type i_targetStart = 0, + bits_type i_len = ~0); + + /// + /// @brief Copy data from this buffer into an OT + /// @tparam OT the type of the outgoing data + /// @param[out] o_out OT to copy into - data is placed left aligned + /// @param[in] i_start Start bit to copy from - defaults to 0 + /// @param[in] i_len Length of bits to copy - defaults to filling o_out + /// @return FAPI2_RC_SUCCESS on success + /// + template< typename OT > + fapi2::ReturnCode extract(OT& o_out, + bits_type i_start = 0, + bits_type i_len = ~0) const; + + /// + /// @brief Copy data from this buffer into an OT and right justify + /// @tparam OT the type of the outgoing data + /// @param[out] o_out OT to copy into - data is placed right aligned + /// @param[in] i_start Start bit to copy from - defaults to 0 + /// @param[in] i_len Length of bits to copy - defaults to filling o_out + /// @return FAPI2_RC_SUCCESS on success + /// + template< typename OT > + fapi2::ReturnCode extractToRight(OT& o_out, + bits_type i_start = 0, + bits_type i_len = ~0) const; + ///@} + + private: + // Just shorthand ... + static const bits_type bits_per_unit = + bufferTraits<bits_container>::bits_per_unit; + + // The number of bits the user asked for. The actual size of the + // container might be larger. + bits_type iv_perceived_bit_length; + + /// + /// @brief Internal bit extraction method. + /// @tparam OT The type of the destination + /// @param[in] i_start The starting bit position in this + /// @param[in] i_count The length, in bits, the user wants copied. + /// @param[out] o_dest Where to put the data + /// + template< typename OT > + fapi2::ReturnCode _extract(bits_type i_start, + bits_type i_count, + OT* o_dest) const; + + /// + /// @brief Internal insertFromRight + /// @param[in] i_data, the incoming data + /// @param[in] i_data_length The length in bits of the incoming data + /// @param[in] i_target_start_bit The starting bit position in this + /// @param[in] i_length The length, in bits, the user wants copied. + /// + template<typename OT> + fapi2::ReturnCode _insertFromRight(const OT& i_data, + bits_type i_data_length, + bits_type i_targetStart, + bits_type i_len); + + }; + + inline variable_buffer:: + variable_buffer(bits_type i_value): + buffer_base(i_value), + iv_perceived_bit_length(i_value) + { + static_assert(std::is_same<unit_type, uint32_t>::value, + "code currently needs unit_type to be a unit32_t"); + } + + inline variable_buffer:: + variable_buffer(const std::initializer_list<unit_type>& i_value): + buffer_base(i_value), + iv_perceived_bit_length(i_value.size() * sizeof(unit_type) * 8) + { + static_assert(std::is_same<unit_type, uint32_t>::value, + "code currently needs unit_type to be a unit32_t"); + } + + + + /// @cond + // + // Generic insert + // + template<typename OT> + inline fapi2::ReturnCode variable_buffer::insert(const OT& i_source, + bits_type i_targetStart, + bits_type i_len, + bits_type i_sourceStart) + { + return _insert((unit_type*)(&i_source), parameterTraits<OT>::bit_length, + &(iv_data[0]), getBitLength(), + i_sourceStart, i_targetStart, i_len); + } + + // + // Insert another variable_bufer + // + template<> + inline fapi2::ReturnCode variable_buffer::insert( + const variable_buffer& i_data, + bits_type i_targetStart, + bits_type i_len, + bits_type i_sourceStart) + { + return _insert((unit_type*)&(i_data()[0]), i_data.getBitLength(), + &(iv_data[0]), getBitLength(), + i_sourceStart, i_targetStart, i_len); + } + + // + // Generic insert from right + // + template<typename OT> + inline fapi2::ReturnCode variable_buffer::insertFromRight( + const OT& i_data, + bits_type i_targetStart, + bits_type i_len) + { + /// @todo check with Brian on additional return + return _insertFromRight(i_data, parameterTraits<OT>::bit_length, i_targetStart, i_len); + } + + // + // variable_buffer insert from right + // + template<> + inline fapi2::ReturnCode variable_buffer::insertFromRight( + const variable_buffer& i_data, + bits_type i_targetStart, + bits_type i_len) + { + const bits_type bit_length_of_source = i_data.getBitLength(); + /// @todo check with Brian on additional return + return _insertFromRight(i_data, bit_length_of_source, i_targetStart, i_len); + } + + + + + // + // Generic extract. Extract is an insert with the arguments reversed. + // + template<typename OT> + inline fapi2::ReturnCode variable_buffer::extract( + OT& i_data, + bits_type i_start, + bits_type i_len) const + { + // Needed to trick the compiler into matching the template below + const bits_type max_length = parameterTraits<OT>::bit_length; + + // If thy didn't pass an i_len, assume they want all the data + // which will fit. + if (i_len == ~0) + { + i_len = max_length; + } + + return _insert((container_unit*)&iv_data[0], getBitLength(), + &i_data, max_length, + i_start, 0U, i_len); + } + + // + // Extract in to another variable_bufer + // + template<> + inline fapi2::ReturnCode variable_buffer::extract( + variable_buffer& i_data, + bits_type i_start, + bits_type i_len) const + { + // If thy didn't pass an i_len, assume they want all the data + // which will fit. + // @todo Needed to add (bits_type) to compile. Not clear why this is + // different than other similar comparisons + // error: comparison between signed and unsigned integer expressions [-Werror=sign-compare] + if ( i_len == ~(bits_type)0 ) + { + i_len = i_data.getBitLength(); + } + return _insert((container_unit*)&iv_data[0], getBitLength(), + &(i_data()[0]), i_data.getBitLength(), + i_start, 0U, i_len); + } + + + + template<typename OT> + inline fapi2::ReturnCode variable_buffer::_insertFromRight( + const OT& i_data, + bits_type i_data_length, + bits_type i_targetStart, + bits_type i_len) + { + // If they didn't pass in a length, assume they want all the i_data + // which will fit. + if( i_len == ~0 ) + { + // The longest the length can be is the length of the data + // This is the miniumum of the length of the data or the + // number of available bits + i_len = std::min(i_data_length, getBitLength() - i_targetStart); + } + + // Source start is the length, counted from the right + return insert(i_data, i_targetStart, i_len, i_data_length - i_len); + } + + // + // Invalid specializations of set + // + /// @cond + // Sepcialize the variable_buffer version to to "undefined" so the + // linker complains loudly if anyone calls it. +#if 0 + template<> + inline fapi2::ReturnCode buffer_base::set( + const variable_buffer& i_value, + bits_type i_offset); +#endif + /// @endcond +}; + + +#endif |