From 1ebc3c0868c74833aabe3775509d65ae29cd4925 Mon Sep 17 00:00:00 2001 From: Greg Still Date: Tue, 14 Apr 2015 08:29:05 -0500 Subject: Add common ppe_compiler.mk and proc_hcd_common.H - ppe_compiler.mk for pointing to the common PPE compiler across platforms - proc_hcd_common.H for things common across PPE HCD procedures Change-Id: Ic8883a655eacfcd860e0036c516555ab12984d08 New PPE getscom routines leveragin upgraded compiler - Pass pointers to data elements to use indexed lvdx/stvdx instructions Change-Id: I7b99393919bc533bac5743001ee2c50b778eb2b2 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/17172 Reviewed-by: Glenn R. Miles Reviewed-by: Brian Silver Reviewed-by: Derk Rembold Tested-by: Derk Rembold --- include/ppe_compiler.mk | 59 ++++++++++++ include/proc_hcd_common.H | 20 ++++ pk/ppe42/ppe42_scom.c | 232 +++++++--------------------------------------- pk/ppe42/ppe42_scom.h | 101 ++++++++++++++------ 4 files changed, 188 insertions(+), 224 deletions(-) create mode 100755 include/ppe_compiler.mk create mode 100644 include/proc_hcd_common.H diff --git a/include/ppe_compiler.mk b/include/ppe_compiler.mk new file mode 100755 index 00000000..7db9a4ca --- /dev/null +++ b/include/ppe_compiler.mk @@ -0,0 +1,59 @@ +# Make header to set up PPE Compiler +# +ifndef CC_VERSION +export CC_VERSION = 4.8.3 +endif + +ifndef CC_TARGET +export CC_TARGET = powerpc-buildroot-linux-gnu +endif + +# GCC libraries +ifndef LIB_GCC_DIR +export LIB_GCC_DIR = $(CC_ROOT)/usr/lib/gcc/$(CC_TARGET)/$(CC_VERSION) +endif +LIB_DIRS += -L$(LIB_GCC_DIR) + +# GCC libraries +ifndef LIB_GCC_BASE +export LIB_GCC_BASE = $(CC_ROOT)/usr/lib/gcc/$(CC_TARGET) +endif +LIB_DIRS += -L$(LIB_GCC_BASE) + +# GCC libraries +ifndef LIB_BASE +export LIB_BASE = $(CC_ROOT)/usr/lib +endif +LIB_DIRS += -L$(LIB_BASE) + +# Shared Object C and C++ libraries +ifndef LIB_TARGET +export LIB_TARGET = $(CC_ROOT)/usr/$(CC_TARGET)/lib +endif +#CLIBS += $(LIB_TARGET)/libstdc++.a +#LIB_DIRS += -L$(LIB_TARGET) + +# Static C and C++ libraries +ifndef LIB_CLIB_DIR +export LIB_CLIB_DIR = $(CC_ROOT)/usr/$(CC_TARGET)/sysroot/lib +endif +LIB_DIRS += -L$(LIB_CLIB_DIR) + +# Runtime Static C and C++ libraries +ifndef LIB_CULIB_DIR +export LIB_CULIB_DIR = $(CC_ROOT)/usr/$(CC_TARGET)/sysroot/usr/lib +endif +LIB_DIRS += -L$(LIB_CULIB_DIR) + +GCCLIBS += $(LIB_CULIB_DIR)/libstdc++.a +GCCLIBS += $(LIB_CULIB_DIR)/libm.a +GCCLIBS += $(LIB_CULIB_DIR)/libc.a + +ifdef ENABLE_UCLIB +GCCLIBS += $(LIB_CULIB_DIR)/uclibc_nonshared.a +GCCLIBS += $(LIB_CULIB_DIR)/crt1.o +GCCLIBS += $(LIB_CULIB_DIR)/crti.o +endif + +GCCLIBS += $(LIB_GCC_DIR)/libgcc.a +GCCLIBS += $(LIB_GCC_DIR)/libgcc_eh.a diff --git a/include/proc_hcd_common.H b/include/proc_hcd_common.H new file mode 100644 index 00000000..51cc1285 --- /dev/null +++ b/include/proc_hcd_common.H @@ -0,0 +1,20 @@ +#ifndef __PROC_HCD_COMMON_H +#define __PROC_HCD_COMMON_H + +/// \file proc_hcd_common.H +/// \brief Standard bit-manipulation macros (C and Assembler) for PORE code + +/// \defgroup be64_bits Bit manipulation for 64-bit Big-Endian values +/// +/// \note These macros only work in the assembler context because we build our +/// assemblers to do 64-bit arithmetic, which is required for PORE assembly. +/// +/// @{ + +/// 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 // __PROC_HCD_COMMON_H diff --git a/pk/ppe42/ppe42_scom.c b/pk/ppe42/ppe42_scom.c index e9fe2e6c..ca0b44c7 100644 --- a/pk/ppe42/ppe42_scom.c +++ b/pk/ppe42/ppe42_scom.c @@ -5,7 +5,7 @@ //----------------------------------------------------------------------------- /// \file ppe42_scom.c -/// \brief Lowest level PK SCOM definitions. +/// \brief Lowest level PK SCOM definitions. /// /// Currently these SCOM functions are only optimized for functionality, not /// speed. Speed optimization will be done when we have full compiler support @@ -21,221 +21,57 @@ #include "pk.h" #include "ppe42_scom.h" +#include "ppe42_msr.h" -uint32_t putscom_abs(uint32_t i_address, uint64_t i_data) +uint32_t putscom_abs(const uint32_t i_address, uint64_t *i_data) { - // CMO-Declaring variables tied to specific registers enables us to protect - // the SCOM data and address variables used in the new stvd and lvd 64-bit - // scom instructions. This protection is needed since the new instructions' - // operands are not yet properly considered by the compiler. - // Note that l_dataH is used to represent the "beginning", i.e. High-order, - // part of the 64-bit data in d8 (i.e., r8+r9). - uint32_t register l_dataH asm("r8")=0; - uint32_t register l_dataL asm("r9")=0; - uint32_t register l_addr_eff asm("r10")=0; - uint32_t register l_scratch asm("r31")=0; + // Perform the Store Virtual Double instruction + PPE_STVD(i_address, &i_data); + + // Get the MSR[SIBRC] as the return code + uint32_t rc = mfmsr(); + rc = ((rc & MSR_SIBRC) >> (32-(MSR_SIBRC_START_BIT + MSR_SIBRC_LEN))); + return (rc); - l_addr_eff = i_address; - l_dataH = (uint32_t)(i_data>>32); - l_dataL = (uint32_t)(i_data); - - // CMO-The following sequence forces usage of l_dataH/L and l_addr_eff - // and thus the population of them as well. - // Further note that unless l_dataH/L are placed right before the following - // sequence, more specifically, if they're placed at the top of putscom(), - // r8, or l_dataH, might be overwritten in the if(chiplet_id) section. - // Secondly, we test l_addr_eff for non-zero through the CR0 register - // (which was populated in the "mr." instruction.) This is to convince the - // compiler that we actually used l_addr_eff for something. - // At present the test result causes no action except to execute the stvd - // instruction in either case. - asm volatile ( \ - "mr. %0, %1 \n" \ - : "=r"(l_scratch) \ - : "r"(l_dataH) ); - asm volatile ( \ - "mr. %0, %1 \n" \ - : "=r"(l_scratch) \ - : "r"(l_dataL) ); - asm volatile ( \ - "mr. %0, %1 \n" \ - : "=r"(l_scratch) \ - : "r"(l_addr_eff) ); - asm volatile ( \ - "beq 0x4 \n" ); - - // CMO-This instruction is not fully supported by the compiler (as of - // 20150108): - // - Works: It is correctly translated into the proper OP code - // format. - // - Works not: The compiler does not seem to recognize the usage - // of the two l_xyz variables in that it doesn't - // know prior to this command that the registers that - // contain the values of l_xyz need to be protected - // up to this point. Thus, we are forced to use those - // two l_xyz variables in some dummy instructions just - // before this point in order to fake protection. - asm volatile ( \ - "stvd %[data], 0(%[effective_address]) \n" \ - : [data]"=r"(l_dataH) \ - : [effective_address]"r"(l_addr_eff) ); - - // CMO-TBD - // Check PIB response code in 0x00001007(17:19) - // Translate PIB rc to PK rc - // Does this rc get reset to zero on success? - // Do we need to check this rc prior to issuing the SCOM? - - return 0; } -uint32_t _putscom( uint32_t i_chiplet_id, uint32_t i_address, uint64_t i_data) +uint32_t _putscom( uint32_t i_chiplet_id, uint32_t i_address, uint64_t *i_data) { - uint32_t l_rc=0; - uint32_t l_cid=0; - uint32_t l_addr_eff=0; - - if (i_chiplet_id) - { - // Accommodate two different ways of supplying the chiplet ID: - // 0xNN000000: Only bits in high-order two nibbles : Valid - // 0x000000NN: Only bits in low-order two nibbles : Valid - // - if ((i_chiplet_id & 0xFF000000) == i_chiplet_id) - { - // Valid: Chiplet ID in high-order two nibbles. - l_cid = i_chiplet_id; - } - else if ((i_chiplet_id & 0x000000FF) == i_chiplet_id) - { - // Valid: Chiplet ID in low-order two nibbles. Convert to high-order. - l_cid = i_chiplet_id << 24; - } - else - { - // Invalid: Invalid type of chiplet ID - PK_TRACE("putscom() : Invalid value of i_chiplet_id (=0x%08X)",i_chiplet_id); - return 1; //CMO-improve Return sensible rc here. - } - - l_addr_eff = (i_address & 0x00FFFFFF) | l_cid; - } - else - { - // Chiplet ID is zero. Accept address as is. - // This is useful for PIB addresses and non-EX chiplets, and even for - // EX chiplets if the fully qualified EX chiplet addr is already known. - l_addr_eff = i_address; - - } - - l_rc = putscom_abs(l_addr_eff, i_data); + // Perform the Store Virtual Double Index instruction + PPE_STVDX(i_chiplet_id, i_address, &i_data); - return l_rc; -} + // Get the MSR[SIBRC] as the return code + uint32_t rc = mfmsr(); + rc = ((rc & MSR_SIBRC) >> (32-(MSR_SIBRC_START_BIT + MSR_SIBRC_LEN))); + return (rc); +} -uint32_t getscom_abs( uint32_t i_address, uint64_t *o_data) +uint32_t getscom_abs( const uint32_t i_address, uint64_t *o_data) { - // CMO-Declaring variables tied to specific registers enables us to protect - // the SCOM data and address variables used in the new stvd and lvd 64-bit - // data instructions. This protection is needed since the new instructions - // are not yet properly considered by the compiler. - // Note that l_dataH is used to represent the "beginning", i.e. High-order, - // part of the 64-bit data in d8 (i.e., r8+r9). - uint32_t register l_dataH asm("r8")=0; - uint32_t register l_dataL asm("r9")=0; - uint32_t register l_addr_eff asm("r10")=0; - uint32_t register l_scratch asm("r31")=0; - - - l_addr_eff = i_address; - - // CMO-The following sequence forces usage of l_addr_eff and thus the - // population of it as well. - // Secondly, we test l_addr_eff for non-zero through the CR0 register - // (which was populated in the "mr." instruction.) This is to convince the - // compiler that we actually used l_addr_eff for something. - // At present the test result causes no action except to execute the lvd - // instruction in either case. - asm volatile ( \ - "mr. %0, %1 \n" \ - : "=r"(l_scratch) \ - : "r"(l_addr_eff) ); - asm volatile ( \ - "beq 0x4 \n" ); - - asm volatile ( \ - "lvd %[data], 0(%[effective_address]) \n" \ - : [data]"=r"(l_dataH) \ - : [effective_address]"r"(l_addr_eff) ); - - // CMO-The following sequence moves the read data, in l_dataH/L, into the - // 64-bit o_data location. - asm volatile ( \ - "stw %0, 0(%1) \n" \ - : "=r"(l_dataH) \ - : "r"(o_data) ); - asm volatile ( \ - "stw %0, 4(%1) \n" \ - : "=r"(l_dataL) \ - : "r"(o_data) ); - - // CMO-TBD - // Check PIB response code in 0x00001007(17:19) - // Translate PIB rc to PK rc + // Perform the Load Virtual Double instruction + PPE_LVD(i_address, &o_data); - return 0; + // Get the MSR[SIBRC] as the return code + uint32_t rc = mfmsr(); + rc = ((rc & MSR_SIBRC) >> (32-(MSR_SIBRC_START_BIT + MSR_SIBRC_LEN))); + return (rc); } -uint32_t _getscom( uint32_t i_chiplet_id, uint32_t i_address, uint64_t *o_data) + +uint32_t _getscom( const uint32_t i_chiplet_id, const uint32_t i_address, uint64_t *o_data) { - uint32_t l_rc=0; - uint32_t l_cid=0; - uint32_t l_addr_eff=0; - - if (i_chiplet_id) - { - // Accommodate two different ways of supplying the chiplet ID: - // 0xNN000000: Only bits in high-order two nibbles : Valid - // 0x000000NN: Only bits in low-order two nibbles : Valid - // - if ((i_chiplet_id & 0xFF000000) == i_chiplet_id) - { - // Valid: Chiplet ID in high-order two nibbles. - l_cid = i_chiplet_id; - } - else if ((i_chiplet_id & 0x000000FF) == i_chiplet_id) - { - // Valid: Chiplet ID in low-order two nibbles. Convert to high-order. - l_cid = i_chiplet_id << 24; - } - else - { - // Invalid: Invalid type of chiplet ID - PK_TRACE("getscom() : Invalid value of i_chiplet_id (=0x%08X)",i_chiplet_id); - return 1; //CMO-improve Return sensible rc here. - } - - l_addr_eff = (i_address & 0x00FFFFFF) | l_cid; - } - else - { - // Chiplet ID is zero. Accept address as is. - // This is useful for PIB addresses and non-EX chiplets, and even for - // EX chiplets if the fully qualified EX chiplet addr is already known. - l_addr_eff = i_address; - } - - l_rc = getscom_abs(l_addr_eff, o_data); - // CMO-TBD - // Check PIB response code in 0x00001007(17:19) - // Translate PIB rc to PK rc + // Perform the Load Virtual Double Index instruction + PPE_LVDX(i_chiplet_id, i_address, &o_data); + + // Get the MSR[SIBRC] as the return code + uint32_t rc = mfmsr(); + rc = ((rc & MSR_SIBRC) >> (32-(MSR_SIBRC_START_BIT + MSR_SIBRC_LEN))); + return (rc); - return l_rc; } diff --git a/pk/ppe42/ppe42_scom.h b/pk/ppe42/ppe42_scom.h index 0d57e5d4..886a44b8 100644 --- a/pk/ppe42/ppe42_scom.h +++ b/pk/ppe42/ppe42_scom.h @@ -25,28 +25,89 @@ #define PCB_ERROR_PACKET_ERROR 6 #define PCB_ERROR_TIMEOUT 7 +#ifdef __cplusplus +extern "C" { +#endif + + +/// PPE Load Virtual Double operation +#define PPE_LVD(_m_address, _m_data) \ +asm volatile \ + ( \ + "lvd %[data], 0(%[address]) \n" \ + : [data]"=&r"(*_m_data) \ + : "[data]"(*_m_data), \ + [address]"r"(_m_address) \ + ); + + +// PPE Store Virtual Double operation +#define PPE_STVD(_m_address, _m_data) \ +asm volatile \ + ( \ + "stvd %[data], 0(%[address]) \n" \ + : [data]"=&r"(*_m_data) \ + : "[data]"(*_m_data), \ + [address]"r"(_m_address) \ + : "memory" \ + ); + +/// PPE Load Virtual Double Indexed operation +#define PPE_LVDX(_m_base, _m_offset, _m_data) \ +asm volatile \ + ( \ + "lvdx %[data], %[base], %[offset] \n" \ + : [data]"=&r"(*_m_data) \ + : "[data]"(*_m_data), \ + [base]"r"(_m_base), \ + [offset]"r"(_m_offset) \ + ); + + +// PPE Store Virtual Double Indexed operation +#define PPE_STVDX(_m_base, _m_offset, _m_data) \ +asm volatile \ + ( \ + "stvdx %[data], %[base], %[offset] \n" \ + : [data]"=&r"(*_m_data) \ + : "[data]"(*_m_data), \ + [base]"r"(_m_base), \ + [offset]"r"(_m_offset) \ + : "memory" \ + ); + +#define PPE_MFMSR(_m_data) \ +asm volatile \ + ( \ + "mfmsr %[data] \n" \ + : [data]"=&r"(*_m_data) \ + : "[data]"(*_m_data) \ + ); + /// @brief putscom with absolute address -/// @param [in] i_address Fully formed SCOM address -/// @param [in] i_data uint64_t data to be written +/// @param [in] i_address Fully formed SCOM address +/// @param [in] i_data Pointer to uint64_t data to be written. A pointer is used +/// to optimize the underlying hardware execution /// /// @retval On PPE42 platform, unmasked errors will take machine check interrupts -uint32_t putscom_abs( uint32_t i_address, uint64_t i_data); +uint32_t putscom_abs(const uint32_t i_address, uint64_t *i_data); /// @brief getscom with absolute address /// @param [in] i_address Fully formed SCOM address /// @param [in] *o_data Pointer to uint64_t data read /// /// @retval On PPE42 platform, unmasked errors will take machine check interrupts -uint32_t getscom_abs( uint32_t i_address, uint64_t *o_data); +uint32_t getscom_abs( const uint32_t i_address, uint64_t *o_data); /// @brief Implementation of PPE putscom functionality /// @param [in] i_chiplet Chiplet ID (@todo Should only be right justified) /// @param [in] i_address Base SCOM address -/// @param [in] i_data uint64_t data to be written +/// @param [in] i_data Pointer to uint64_t data to be written. A pointer is used +/// to optimize the underlying hardware execution /// /// @retval On PPE42 platform, unmasked errors will take machine check interrupts -uint32_t _putscom( uint32_t i_chiplet, uint32_t i_address, uint64_t i_data); +uint32_t _putscom( const uint32_t i_chiplet, const uint32_t i_address, uint64_t *i_data); /// @brief Implementation of PPE getscom functionality @@ -57,31 +118,19 @@ uint32_t _putscom( uint32_t i_chiplet, uint32_t i_address, uint64_t i_data); /// @retval On PPE42 platform, unmasked errors will take machine check interrupts uint32_t _getscom( uint32_t i_chiplet, uint32_t i_address, uint64_t *o_data); - -/// Macro to abstract the underlying putscom function so that it might be replaced -/// later with different implementations. Used directly by low level PPE calls -/// but also used by the FAPI2 API implementation -/* -#define putscom (_m_chiplet, _m_address, _m_data) { \ - _putscom( _m_chiplet, _m_address, _m_data); \ -}; -*/ -extern inline uint32_t putscom(uint32_t i_chiplet, uint32_t i_address, uint64_t i_data) +extern inline uint32_t putscom(const uint32_t i_chiplet, const uint32_t i_address, uint64_t *i_data) { return _putscom(i_chiplet, i_address, i_data); } -/// Macro to abstract the underlying getscom function so that it might be replaced -/// later with different implementations. Used directly by low level PPE calls -/// but also used by the FAPI2 API implementation -/* -#define getscom (i_chiplet, i_address, o_data) { \ - _getscom( i_chiplet, i_address, o_data); \ -}; -*/ -extern inline uint32_t getscom(uint32_t i_chiplet, uint32_t i_address, uint64_t *o_data) -{ + +extern inline uint32_t getscom(const uint32_t i_chiplet, const uint32_t i_address, uint64_t *o_data) +{ return _getscom(i_chiplet, i_address, o_data); } +#ifdef __cplusplus +} // extern C +#endif + #endif // __PK_SCOM_H__ -- cgit v1.2.1