<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/string_util.h"
#include "media/base/filters.h"
#include "media/filters/ffmpeg_common.h"
#include "media/filters/ffmpeg_glue.h"

namespace {

// FFmpeg protocol interface.
int OpenContext(URLContext* h, const char* filename, int flags) {
  scoped_refptr<media::DataSource> data_source;
  media::FFmpegGlue::get()->GetDataSource(filename, &data_source);
  if (!data_source)
    return AVERROR_IO;

  data_source->AddRef();
  h->priv_data = data_source;
  h->flags = URL_RDONLY;
  h->is_streamed = !data_source->IsSeekable();
  return 0;
}

int ReadContext(URLContext* h, unsigned char* buf, int size) {
  media::DataSource* data_source =
      reinterpret_cast<media::DataSource*>(h->priv_data);
  int result = data_source->Read(buf, size);
  if (result < 0)
    result = AVERROR_IO;
  return result;
}

int WriteContext(URLContext* h, unsigned char* buf, int size) {
  // We don't support writing.
  return AVERROR_IO;
}

offset_t SeekContext(URLContext* h, offset_t offset, int whence) {
  media::DataSource* data_source =
      reinterpret_cast<media::DataSource*>(h->priv_data);
  offset_t new_offset = AVERROR_IO;
  switch (whence) {
    case SEEK_SET:
      if (data_source->SetPosition(offset))
        data_source->GetPosition(&new_offset);
      break;

    case SEEK_CUR:
      int64 pos;
      if (!data_source->GetPosition(&pos))
        break;
      if (data_source->SetPosition(pos + offset))
        data_source->GetPosition(&new_offset);
      break;

    case SEEK_END:
      int64 size;
      if (!data_source->GetSize(&size))
        break;
      if (data_source->SetPosition(size + offset))
        data_source->GetPosition(&new_offset);
      break;

    case AVSEEK_SIZE:
      data_source->GetSize(&new_offset);
      break;

    default:
      NOTREACHED();
  }
  if (new_offset < 0)
    new_offset = AVERROR_IO;
  return new_offset;
}

int CloseContext(URLContext* h) {
  media::DataSource* data_source =
      reinterpret_cast<media::DataSource*>(h->priv_data);
  data_source->Release();
  h->priv_data = NULL;
  return 0;
}

}  // namespace

//------------------------------------------------------------------------------

namespace media {

// Use the HTTP protocol to avoid any file path separator issues.
static const char kProtocol[] = "http";

// Fill out our FFmpeg protocol definition.
static URLProtocol kFFmpegProtocol = {
  kProtocol,
  &OpenContext,
  &ReadContext,
  &WriteContext,
  &SeekContext,
  &CloseContext,
};

FFmpegGlue::FFmpegGlue() {
  // Register our protocol glue code with FFmpeg.
  avcodec_init();
  register_protocol(&kFFmpegProtocol);

  // Now register the rest of FFmpeg.
  av_register_all();
}

FFmpegGlue::~FFmpegGlue() {
  DataSourceMap::iterator iter = data_sources_.begin();
  while (iter != data_sources_.end()) {
    DataSource* data_source = iter->second;
    iter = data_sources_.erase(iter);
  }
}

std::string FFmpegGlue::AddDataSource(DataSource* data_source) {
  AutoLock auto_lock(lock_);
  std::string key = GetDataSourceKey(data_source);
  if (data_sources_.find(key) == data_sources_.end()) {
    data_sources_[key] = data_source;
  }
  return key;
}

void FFmpegGlue::RemoveDataSource(DataSource* data_source) {
  AutoLock auto_lock(lock_);
  DataSourceMap::iterator iter = data_sources_.begin();
  while (iter != data_sources_.end()) {
    if (iter->second == data_source) {
      iter = data_sources_.erase(iter);
    } else {
      ++iter;
    }
  }
}

void FFmpegGlue::GetDataSource(const std::string& key,
                               scoped_refptr<DataSource>* data_source) {
  AutoLock auto_lock(lock_);
  DataSourceMap::iterator iter = data_sources_.find(key);
  if (iter == data_sources_.end()) {
    *data_source = NULL;
    return;
  }
  *data_source = iter->second;
}

std::string FFmpegGlue::GetDataSourceKey(DataSource* data_source) {
  // Use the DataSource's memory address to generate the unique string.  This
  // also has the nice property that adding the same DataSource reference will
  // not generate duplicate entries.
  return StringPrintf("%s://0x%lx", kProtocol, static_cast<void*>(data_source));
}

}  // namespace media
<commit_msg>Reapply linux build fix patch to ffmepg glue code from r12791 that was lost in r12802. Original CL: http://codereview.chromium.org/62054<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/string_util.h"
#include "media/base/filters.h"
#include "media/filters/ffmpeg_common.h"
#include "media/filters/ffmpeg_glue.h"

namespace {

// FFmpeg protocol interface.
int OpenContext(URLContext* h, const char* filename, int flags) {
  scoped_refptr<media::DataSource> data_source;
  media::FFmpegGlue::get()->GetDataSource(filename, &data_source);
  if (!data_source)
    return AVERROR_IO;

  data_source->AddRef();
  h->priv_data = data_source;
  h->flags = URL_RDONLY;
  h->is_streamed = !data_source->IsSeekable();
  return 0;
}

int ReadContext(URLContext* h, unsigned char* buf, int size) {
  media::DataSource* data_source =
      reinterpret_cast<media::DataSource*>(h->priv_data);
  int result = data_source->Read(buf, size);
  if (result < 0)
    result = AVERROR_IO;
  return result;
}

int WriteContext(URLContext* h, unsigned char* buf, int size) {
  // We don't support writing.
  return AVERROR_IO;
}

offset_t SeekContext(URLContext* h, offset_t offset, int whence) {
  media::DataSource* data_source =
      reinterpret_cast<media::DataSource*>(h->priv_data);
  offset_t new_offset = AVERROR_IO;
  switch (whence) {
    case SEEK_SET:
      if (data_source->SetPosition(offset))
        data_source->GetPosition(&new_offset);
      break;

    case SEEK_CUR:
      int64 pos;
      if (!data_source->GetPosition(&pos))
        break;
      if (data_source->SetPosition(pos + offset))
        data_source->GetPosition(&new_offset);
      break;

    case SEEK_END:
      int64 size;
      if (!data_source->GetSize(&size))
        break;
      if (data_source->SetPosition(size + offset))
        data_source->GetPosition(&new_offset);
      break;

    case AVSEEK_SIZE:
      data_source->GetSize(&new_offset);
      break;

    default:
      NOTREACHED();
  }
  if (new_offset < 0)
    new_offset = AVERROR_IO;
  return new_offset;
}

int CloseContext(URLContext* h) {
  media::DataSource* data_source =
      reinterpret_cast<media::DataSource*>(h->priv_data);
  data_source->Release();
  h->priv_data = NULL;
  return 0;
}

}  // namespace

//------------------------------------------------------------------------------

namespace media {

// Use the HTTP protocol to avoid any file path separator issues.
static const char kProtocol[] = "http";

// Fill out our FFmpeg protocol definition.
static URLProtocol kFFmpegProtocol = {
  kProtocol,
  &OpenContext,
  &ReadContext,
  &WriteContext,
  &SeekContext,
  &CloseContext,
};

FFmpegGlue::FFmpegGlue() {
  // Register our protocol glue code with FFmpeg.
  avcodec_init();
  register_protocol(&kFFmpegProtocol);

  // Now register the rest of FFmpeg.
  av_register_all();
}

FFmpegGlue::~FFmpegGlue() {
}

std::string FFmpegGlue::AddDataSource(DataSource* data_source) {
  AutoLock auto_lock(lock_);
  std::string key = GetDataSourceKey(data_source);
  if (data_sources_.find(key) == data_sources_.end()) {
    data_sources_[key] = data_source;
  }
  return key;
}

void FFmpegGlue::RemoveDataSource(DataSource* data_source) {
  AutoLock auto_lock(lock_);
  for (DataSourceMap::iterator cur, iter = data_sources_.begin();
       iter != data_sources_.end();) {
    cur = iter;
    iter++;

    if (cur->second == data_source)
      data_sources_.erase(cur);
  }
}

void FFmpegGlue::GetDataSource(const std::string& key,
                               scoped_refptr<DataSource>* data_source) {
  AutoLock auto_lock(lock_);
  DataSourceMap::iterator iter = data_sources_.find(key);
  if (iter == data_sources_.end()) {
    *data_source = NULL;
    return;
  }
  *data_source = iter->second;
}

std::string FFmpegGlue::GetDataSourceKey(DataSource* data_source) {
  // Use the DataSource's memory address to generate the unique string.  This
  // also has the nice property that adding the same DataSource reference will
  // not generate duplicate entries.
  return StringPrintf("%s://0x%lx", kProtocol, static_cast<void*>(data_source));
}

}  // namespace media
<|endoftext|>


<commit_before>#include "Session.hpp"

#include "ApiUtils.hpp"
#include "RandomGenerator.hpp"

#include <QDateTime>
#include <QLoggingCategory>

namespace Telegram {

namespace Server {

constexpr quint32 c_sessionRotation = 1 * 60 * 60;
constexpr quint32 c_sessionOverlapping = 300;
constexpr quint32 c_maxServerSalts = 64;

Session::Session(quint64 sessionId) :
    m_sessionId(sessionId)
{
}

quint64 Session::getOldSalt() const
{
    if (m_oldSalt.validUntil < Utils::getCurrentTime()) {
        return 0;
    }
    return m_oldSalt.salt;
}

quint64 Session::getServerSalt() const
{
    Q_ASSERT_X(!m_salts.isEmpty(), "ServerSession", "server salt requested, but initial salt is not set");
    // https://core.telegram.org/api/optimisation#server-salt
    // "At present, a single salt’s lifespan is 1 hour"
    //
    // https://core.telegram.org/mtproto/description#server-salt
    // "<server salt is> a number periodically (say, every 24 hours) changed (separately for each session)"
    //
    // https://core.telegram.org/mtproto/service_messages#request-for-several-future-salts
    // "a server salt is attached to the authorization key rather than being session-specific"

    if (m_salts.at(1).validSince < Utils::getCurrentTime()) {
        m_oldSalt = m_salts.takeFirst();
        if (m_salts.count() < 2) {
            addSalt();
        }
    }
    return m_salts.constFirst().salt;
}

bool Session::checkSalt(quint64 salt) const
{
    return salt && ((getServerSalt() == salt) || (getOldSalt() == salt));
}

bool Session::generateInitialServerSalt()
{
    if (!m_salts.isEmpty()) {
        qCritical() << Q_FUNC_INFO << "a salt is already set";
        return false;
    }
    ServerSalt s = generateSalt(Utils::getCurrentTime());
    m_salts.append(s);
    addSalt();
    return true;
}

void Session::setInitialServerSalt(quint64 salt)
{
    if (!m_salts.isEmpty()) {
        qCritical() << Q_FUNC_INFO << "a salt is already set";
        return;
    }
    ServerSalt s;
    s.salt = salt;
    s.validSince = Utils::getCurrentTime();
    s.validUntil = s.validSince + c_sessionRotation;
    m_salts.append(s);
    addSalt();
}

QVector<ServerSalt> Session::getSalts(quint32 numberLimit) const
{
    const int limit = static_cast<int>(qMin<quint32>(numberLimit, c_maxServerSalts));
    m_salts.reserve(limit);
    while (m_salts.count() < limit) {
        addSalt();
    }
    return m_salts.mid(0, limit);
}

ServerSalt Session::generateSalt(quint32 validSince)
{
    ServerSalt s;
    s.validSince = validSince;
    s.validUntil = s.validSince + c_sessionRotation;
    RandomGenerator::instance()->generate(&s.salt);
    return s;
}

void Session::addSalt() const
{
    // This method is a part of private lazy salts generation mechanism.
    // Externally we're 'const'.
    m_salts.append(generateSalt(m_salts.constLast().validUntil - c_sessionOverlapping));
}

} // Server namespace

} // Telegram namespace
<commit_msg>Server/Session: Fix ambiguous Utils namespace usage<commit_after>#include "Session.hpp"

#include "ApiUtils.hpp"
#include "RandomGenerator.hpp"

#include <QDateTime>
#include <QLoggingCategory>

namespace Telegram {

namespace Server {

constexpr quint32 c_sessionRotation = 1 * 60 * 60;
constexpr quint32 c_sessionOverlapping = 300;
constexpr quint32 c_maxServerSalts = 64;

Session::Session(quint64 sessionId) :
    m_sessionId(sessionId)
{
}

quint64 Session::getOldSalt() const
{
    if (m_oldSalt.validUntil < Telegram::Utils::getCurrentTime()) {
        return 0;
    }
    return m_oldSalt.salt;
}

quint64 Session::getServerSalt() const
{
    Q_ASSERT_X(!m_salts.isEmpty(), "ServerSession", "server salt requested, but initial salt is not set");
    // https://core.telegram.org/api/optimisation#server-salt
    // "At present, a single salt’s lifespan is 1 hour"
    //
    // https://core.telegram.org/mtproto/description#server-salt
    // "<server salt is> a number periodically (say, every 24 hours) changed (separately for each session)"
    //
    // https://core.telegram.org/mtproto/service_messages#request-for-several-future-salts
    // "a server salt is attached to the authorization key rather than being session-specific"

    if (m_salts.at(1).validSince < Telegram::Utils::getCurrentTime()) {
        m_oldSalt = m_salts.takeFirst();
        if (m_salts.count() < 2) {
            addSalt();
        }
    }
    return m_salts.constFirst().salt;
}

bool Session::checkSalt(quint64 salt) const
{
    return salt && ((getServerSalt() == salt) || (getOldSalt() == salt));
}

bool Session::generateInitialServerSalt()
{
    if (!m_salts.isEmpty()) {
        qCritical() << Q_FUNC_INFO << "a salt is already set";
        return false;
    }
    ServerSalt s = generateSalt(Telegram::Utils::getCurrentTime());
    m_salts.append(s);
    addSalt();
    return true;
}

void Session::setInitialServerSalt(quint64 salt)
{
    if (!m_salts.isEmpty()) {
        qCritical() << Q_FUNC_INFO << "a salt is already set";
        return;
    }
    ServerSalt s;
    s.salt = salt;
    s.validSince = Telegram::Utils::getCurrentTime();
    s.validUntil = s.validSince + c_sessionRotation;
    m_salts.append(s);
    addSalt();
}

QVector<ServerSalt> Session::getSalts(quint32 numberLimit) const
{
    const int limit = static_cast<int>(qMin<quint32>(numberLimit, c_maxServerSalts));
    m_salts.reserve(limit);
    while (m_salts.count() < limit) {
        addSalt();
    }
    return m_salts.mid(0, limit);
}

ServerSalt Session::generateSalt(quint32 validSince)
{
    ServerSalt s;
    s.validSince = validSince;
    s.validUntil = s.validSince + c_sessionRotation;
    RandomGenerator::instance()->generate(&s.salt);
    return s;
}

void Session::addSalt() const
{
    // This method is a part of private lazy salts generation mechanism.
    // Externally we're 'const'.
    m_salts.append(generateSalt(m_salts.constLast().validUntil - c_sessionOverlapping));
}

} // Server namespace

} // Telegram namespace
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mc/mc.H $       */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] 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 mc.H
/// @brief Subroutines to manipulate the memory controller
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef _MSS_MC_H_
#define _MSS_MC_H_

#include <fapi2.H>

#include "p9_mc_scom_addresses.H"
#include "p9_mc_scom_addresses_fld.H"
#include "mss_attribute_accessors.H"
#include "../utils/scom.H"

namespace mss
{

// I have a dream that the xlate code can be shared among controllers. So, I drive the
// engine from a set of traits. This might be folly. Allow me to dream. BRS

///
/// @class mcTraits
/// @brief a collection of traits associated with the MC
/// @tparam T, fapi2::TargetType representing the MC
///
template< fapi2::TargetType T >
class mcTraits;

///
/// @class mcTraits
/// @brief a collection of traits associated with the Centaur controller
///
template<>
class mcTraits<fapi2::TARGET_TYPE_MEMBUF_CHIP>
{
};

///
/// @class mcTraits
/// @brief a collection of traits associated with the Nimbus controller
///
template<>
class mcTraits<fapi2::TARGET_TYPE_MCS>
{
    public:
        // Array of registers indexed by MCA position
        static const uint64_t xlate0_reg[2];
        static const uint64_t xlate1_reg[2];
        static const uint64_t xlate2_reg[2];

        enum
        {
            SLOT0_VALID = MCS_PORT02_MCP0XLT0_SLOT0_VALID,
            SLOT0_ROW15_VALID = MCS_PORT02_MCP0XLT0_SLOT0_ROW15_VALID,
            SLOT0_M1_VALID = MCS_PORT02_MCP0XLT0_SLOT0_M1_VALID,
            M1_BIT_MAP = MCS_PORT02_MCP0XLT0_M1_BIT_MAP,
            M1_BIT_MAP_LEN = MCS_PORT02_MCP0XLT0_M1_BIT_MAP_LEN,
            D_BIT_MAP = MCS_PORT02_MCP0XLT0_D_BIT_MAP,
            D_BIT_MAP_LEN = MCS_PORT02_MCP0XLT0_D_BIT_MAP_LEN,
            R15_BIT_MAP = MCS_PORT02_MCP0XLT0_R15_BIT_MAP,
            R15_BIT_MAP_LEN = MCS_PORT02_MCP0XLT0_R15_BIT_MAP_LEN,
            COL4_BIT_MAP = MCS_PORT02_MCP0XLT1_COL4_BIT_MAP,
            COL4_BIT_MAP_LEN = MCS_PORT02_MCP0XLT1_COL4_BIT_MAP_LEN,
            COL5_BIT_MAP = MCS_PORT02_MCP0XLT1_COL5_BIT_MAP,
            COL5_BIT_MAP_LEN = MCS_PORT02_MCP0XLT1_COL5_BIT_MAP_LEN,
            COL6_BIT_MAP = MCS_PORT02_MCP0XLT1_COL6_BIT_MAP,
            COL6_BIT_MAP_LEN = MCS_PORT02_MCP0XLT1_COL6_BIT_MAP_LEN,
            COL7_BIT_MAP = MCS_PORT02_MCP0XLT1_COL7_BIT_MAP,
            COL7_BIT_MAP_LEN = MCS_PORT02_MCP0XLT1_COL7_BIT_MAP_LEN,
            COL8_BIT_MAP = MCS_PORT02_MCP0XLT2_COL8_BIT_MAP,
            COL8_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_COL8_BIT_MAP_LEN,
            COL9_BIT_MAP = MCS_PORT02_MCP0XLT2_COL9_BIT_MAP,
            COL9_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_COL9_BIT_MAP_LEN,
            BANK0_BIT_MAP = MCS_PORT02_MCP0XLT2_BANK0_BIT_MAP,
            BANK0_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_BANK0_BIT_MAP_LEN,
            BANK1_BIT_MAP = MCS_PORT02_MCP0XLT2_BANK1_BIT_MAP,
            BANK1_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_BANK1_BIT_MAP_LEN,
            BANK_GROUP0_BIT_MAP = MCS_PORT02_MCP0XLT2_BANK_GROUP0_BIT_MAP,
            BANK_GROUP0_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_BANK_GROUP0_BIT_MAP_LEN,
            BANK_GROUP1_BIT_MAP = MCS_PORT02_MCP0XLT2_BANK_GROUP1_BIT_MAP,
            BANK_GROUP1_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_BANK_GROUP1_BIT_MAP_LEN,
        };

};

// Why two enums? Two reasons. First, we need these to be contiguous, and
// we can't always guarentee the symbols will be generated as such. Second,
// we want to be 0'based so that we can use a static array as a table and
// it's probably not possible for the symbols to be 0'based.
enum
{
    THIS_ENTRY_VALID = 0,
    VALUE_OF_D_BIT_INDEX = 1,
    GB12_ENABLE_INDEX = 2,
    MASTER_BIT_0_VALID_INDEX = 3,
    MASTER_BIT_1_VALID_INDEX = 4,
    SLAVE_BIT_0_VALID_INDEX = 5,
    SLAVE_BIT_1_VALID_INDEX = 6,
    SLAVE_BIT_2_VALID_INDEX = 7,
    ROW_BIT_15_VALID_INDEX = 8,
    ROW_BIT_16_VALID_INDEX = 9,
    ROW_BIT_17_VALID_INDEX = 10,
    BANK_BIT_2_VALID_INDEX = 11,
    DIMM_BIT_INDEX = 12,
    MASTER_BIT_0_INDEX = 13,
    MASTER_BIT_1_INDEX = 14,
    SLAVE_BIT_0_INDEX = 15,
    SLAVE_BIT_1_INDEX = 16,
    SLAVE_BIT_2_INDEX = 17,
    ROW_17_INDEX = 18,
    ROW_16_INDEX = 19,
    COLUMN_4_INDEX = 20,
    COLUMN_5_INDEX = 21,
    COLUMN_6_INDEX = 22,
    COLUMN_7_INDEX = 23,
    COLUMN_8_INDEX = 24,
    COLUMN_9_INDEX = 25,
    BANK_0_INDEX = 26,
    BANK_1_INDEX = 27,
    BANK_2_INDEX = 28,
    BANK_GROUP_0_BIT_INDEX = 29,
    BANK_GROUP_1_BIT_INDEX = 30,
    MAX_TRANSLATIONS = 31,
};

///
/// @class mss::mc
/// @brief The memory controller class
/// @tparam T the fapi2::TargetType of the controller
///
template< fapi2::TargetType T >
class mc
{

    public:
        ///
        /// @brief Perform initializations for the MC
        /// @tparam T the fapi2::TargetType
        /// @param[in] i_target the target which has the MCs to initialize
        /// @return FAPI2_RC_SUCCESS iff ok
        ///
        fapi2::ReturnCode scominit(const fapi2::Target<T>& i_target);

        ///
        /// @brief Perform initializations of the MC translation
        /// @tparam P the fapi2::TargetType of the port
        /// @tparam TT the typename of the traits
        /// @param[in] i_target the target which has the MCA to map
        /// @return FAPI2_RC_SUCCESS iff ok
        ///
        template< fapi2::TargetType P, typename TT = mcTraits<T> >
        fapi2::ReturnCode setup_xlate_map(const fapi2::Target<P>& i_target);

};

}

#endif
<commit_msg>Change include paths in memory/lib, tests<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mc/mc.H $       */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] 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 mc.H
/// @brief Subroutines to manipulate the memory controller
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef _MSS_MC_H_
#define _MSS_MC_H_

#include <fapi2.H>

#include <p9_mc_scom_addresses.H>
#include <p9_mc_scom_addresses_fld.H>
#include <mss_attribute_accessors.H>
#include <lib/utils/scom.H>

namespace mss
{

// I have a dream that the xlate code can be shared among controllers. So, I drive the
// engine from a set of traits. This might be folly. Allow me to dream. BRS

///
/// @class mcTraits
/// @brief a collection of traits associated with the MC
/// @tparam T, fapi2::TargetType representing the MC
///
template< fapi2::TargetType T >
class mcTraits;

///
/// @class mcTraits
/// @brief a collection of traits associated with the Centaur controller
///
template<>
class mcTraits<fapi2::TARGET_TYPE_MEMBUF_CHIP>
{
};

///
/// @class mcTraits
/// @brief a collection of traits associated with the Nimbus controller
///
template<>
class mcTraits<fapi2::TARGET_TYPE_MCS>
{
    public:
        // Array of registers indexed by MCA position
        static const uint64_t xlate0_reg[2];
        static const uint64_t xlate1_reg[2];
        static const uint64_t xlate2_reg[2];

        enum
        {
            SLOT0_VALID = MCS_PORT02_MCP0XLT0_SLOT0_VALID,
            SLOT0_ROW15_VALID = MCS_PORT02_MCP0XLT0_SLOT0_ROW15_VALID,
            SLOT0_M1_VALID = MCS_PORT02_MCP0XLT0_SLOT0_M1_VALID,
            M1_BIT_MAP = MCS_PORT02_MCP0XLT0_M1_BIT_MAP,
            M1_BIT_MAP_LEN = MCS_PORT02_MCP0XLT0_M1_BIT_MAP_LEN,
            D_BIT_MAP = MCS_PORT02_MCP0XLT0_D_BIT_MAP,
            D_BIT_MAP_LEN = MCS_PORT02_MCP0XLT0_D_BIT_MAP_LEN,
            R15_BIT_MAP = MCS_PORT02_MCP0XLT0_R15_BIT_MAP,
            R15_BIT_MAP_LEN = MCS_PORT02_MCP0XLT0_R15_BIT_MAP_LEN,
            COL4_BIT_MAP = MCS_PORT02_MCP0XLT1_COL4_BIT_MAP,
            COL4_BIT_MAP_LEN = MCS_PORT02_MCP0XLT1_COL4_BIT_MAP_LEN,
            COL5_BIT_MAP = MCS_PORT02_MCP0XLT1_COL5_BIT_MAP,
            COL5_BIT_MAP_LEN = MCS_PORT02_MCP0XLT1_COL5_BIT_MAP_LEN,
            COL6_BIT_MAP = MCS_PORT02_MCP0XLT1_COL6_BIT_MAP,
            COL6_BIT_MAP_LEN = MCS_PORT02_MCP0XLT1_COL6_BIT_MAP_LEN,
            COL7_BIT_MAP = MCS_PORT02_MCP0XLT1_COL7_BIT_MAP,
            COL7_BIT_MAP_LEN = MCS_PORT02_MCP0XLT1_COL7_BIT_MAP_LEN,
            COL8_BIT_MAP = MCS_PORT02_MCP0XLT2_COL8_BIT_MAP,
            COL8_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_COL8_BIT_MAP_LEN,
            COL9_BIT_MAP = MCS_PORT02_MCP0XLT2_COL9_BIT_MAP,
            COL9_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_COL9_BIT_MAP_LEN,
            BANK0_BIT_MAP = MCS_PORT02_MCP0XLT2_BANK0_BIT_MAP,
            BANK0_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_BANK0_BIT_MAP_LEN,
            BANK1_BIT_MAP = MCS_PORT02_MCP0XLT2_BANK1_BIT_MAP,
            BANK1_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_BANK1_BIT_MAP_LEN,
            BANK_GROUP0_BIT_MAP = MCS_PORT02_MCP0XLT2_BANK_GROUP0_BIT_MAP,
            BANK_GROUP0_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_BANK_GROUP0_BIT_MAP_LEN,
            BANK_GROUP1_BIT_MAP = MCS_PORT02_MCP0XLT2_BANK_GROUP1_BIT_MAP,
            BANK_GROUP1_BIT_MAP_LEN = MCS_PORT02_MCP0XLT2_BANK_GROUP1_BIT_MAP_LEN,
        };

};

// Why two enums? Two reasons. First, we need these to be contiguous, and
// we can't always guarentee the symbols will be generated as such. Second,
// we want to be 0'based so that we can use a static array as a table and
// it's probably not possible for the symbols to be 0'based.
enum
{
    THIS_ENTRY_VALID = 0,
    VALUE_OF_D_BIT_INDEX = 1,
    GB12_ENABLE_INDEX = 2,
    MASTER_BIT_0_VALID_INDEX = 3,
    MASTER_BIT_1_VALID_INDEX = 4,
    SLAVE_BIT_0_VALID_INDEX = 5,
    SLAVE_BIT_1_VALID_INDEX = 6,
    SLAVE_BIT_2_VALID_INDEX = 7,
    ROW_BIT_15_VALID_INDEX = 8,
    ROW_BIT_16_VALID_INDEX = 9,
    ROW_BIT_17_VALID_INDEX = 10,
    BANK_BIT_2_VALID_INDEX = 11,
    DIMM_BIT_INDEX = 12,
    MASTER_BIT_0_INDEX = 13,
    MASTER_BIT_1_INDEX = 14,
    SLAVE_BIT_0_INDEX = 15,
    SLAVE_BIT_1_INDEX = 16,
    SLAVE_BIT_2_INDEX = 17,
    ROW_17_INDEX = 18,
    ROW_16_INDEX = 19,
    COLUMN_4_INDEX = 20,
    COLUMN_5_INDEX = 21,
    COLUMN_6_INDEX = 22,
    COLUMN_7_INDEX = 23,
    COLUMN_8_INDEX = 24,
    COLUMN_9_INDEX = 25,
    BANK_0_INDEX = 26,
    BANK_1_INDEX = 27,
    BANK_2_INDEX = 28,
    BANK_GROUP_0_BIT_INDEX = 29,
    BANK_GROUP_1_BIT_INDEX = 30,
    MAX_TRANSLATIONS = 31,
};

///
/// @class mss::mc
/// @brief The memory controller class
/// @tparam T the fapi2::TargetType of the controller
///
template< fapi2::TargetType T >
class mc
{

    public:
        ///
        /// @brief Perform initializations for the MC
        /// @tparam T the fapi2::TargetType
        /// @param[in] i_target the target which has the MCs to initialize
        /// @return FAPI2_RC_SUCCESS iff ok
        ///
        fapi2::ReturnCode scominit(const fapi2::Target<T>& i_target);

        ///
        /// @brief Perform initializations of the MC translation
        /// @tparam P the fapi2::TargetType of the port
        /// @tparam TT the typename of the traits
        /// @param[in] i_target the target which has the MCA to map
        /// @return FAPI2_RC_SUCCESS iff ok
        ///
        template< fapi2::TargetType P, typename TT = mcTraits<T> >
        fapi2::ReturnCode setup_xlate_map(const fapi2::Target<P>& i_target);

};

}

#endif
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/nest/p9_l2_flush.C $       */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] 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 p9_l2_flush.H
/// @brief Flush the P9 L2 cache (FAPI)
///
/// *HWP HWP Owner   : Benjamin Gass <bgass@us.ibm.com>
/// *HWP FW Owner    : Bilicon Patil  <bilpatil@in.ibm.com>
/// *HWP Team        : Quad
/// *HWP Consumed by : FSP
/// *HWP Level       : 2
///

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <p9_quad_scom_addresses.H>
#include <p9_l2_flush.H>

//------------------------------------------------------------------------------
// Constant definitions
//------------------------------------------------------------------------------

// L2 Purge Engine Command Register bit/field definitions
enum
{
    PURGE_CMD_TRIGGER_BIT            = 0,
    PURGE_CMD_REG_BUSY               = 9,
    PURGE_CMD_PRGSM_BUSY_ON_THIS_BIT = 10,
    PURGE_CMD_PRGSM_BUSY_BIT         = 11,
    PURGE_CMD_ERR_BIT                = 29,
    PURGE_CMD_TYPE_BIT               = 1,
    PURGE_CMD_MEM_BIT                = 17,
    PURGE_CMD_BANK_BIT               = 28,
    PURGE_CMD_CGC_BIT                = 20
};

// L2 Purge Engine Command Register bit/field Lengths
enum
{
    PURGE_CMD_TYPE_BIT_LENGTH   = 4,
    PURGE_CMD_MEM_BIT_LENGTH    = 3,
    PURGE_CMD_BANK_BIT_LENGTH   = 1,
    PURGE_CMD_CGC_BIT_LENGTH    = 8
};

// polling constants
enum
{
    P9_L2_FLUSH_HW_NS_DELAY     = 10000, // unit is nano seconds
    P9_L2_FLUSH_SIM_CYCLE_DELAY = 12000, // unit is cycles
    P9_L2_FLUSH_MAX_POLLS       = 200    // unit is cycles
};

//------------------------------------------------------------------------------
// Function definitions
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
///
/// @brief l2_flush_start: Utility subroutine to initiate L2 cache flush
///                        via purge engine
/// @param[in]  i_target Ex target
/// @param[in]  i_regAddr The scom address to use
/// @param[in]  i_purgeData Structure having values for MEM, CGC, BANK
///                         passed by the user
/// @return  FAPI2_RC_SUCCESS if purge operation was started,
///          RC_P9_L2_FLUSH_PURGE_REQ_OUTSTANDING if a prior purge
///          operation has not yet completed
///          else FAPI getscom/putscom return code for failing operation
//------------------------------------------------------------------------------
fapi2::ReturnCode l2_flush_start(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const uint32_t i_regAddr,
    const p9core::purgeData_t& i_purgeData)
{
    fapi2::buffer<uint64_t> l_cmdReg;
    fapi2::buffer<uint64_t> l_purgeCmd;
    char l_targetStr[fapi2::MAX_ECMD_STRING_LEN];

    FAPI_INF("l2_flush_start: Enter");

    // ensure that purge engine is idle before starting flush
    // poll Purge Engine status
    FAPI_DBG("Reading L2 Purge Engine Command Register to check status");
    FAPI_TRY(fapi2::getScom(i_target, i_regAddr, l_cmdReg));

    // check to see if this reg is idle and ready to accept a new command
    fapi2::toString(i_target, l_targetStr, fapi2::MAX_ECMD_STRING_LEN);
    FAPI_ASSERT(!l_cmdReg.getBit<PURGE_CMD_REG_BUSY>(),
                fapi2::P9_L2_FLUSH_PURGE_REQ_OUTSTANDING()
                .set_TARGET(i_target)
                .set_CMD_REG(l_cmdReg)
                .set_CMD_REG_ADDR(i_regAddr),
                "Previous purge request has not completed for target %s",
                l_targetStr);

    // write PURGE_CMD_TRIGGER bit in Purge Engine Command Register
    // ensure PURGE_CMD_TYPE/MEM/CGC/BANK are clear to specify flush
    // of entire cache
    FAPI_DBG("Write L2 Purge Engine Command Register to initiate cache flush");
    l_purgeCmd.insert<PURGE_CMD_TYPE_BIT,
                      PURGE_CMD_TYPE_BIT_LENGTH>(i_purgeData.iv_cmdType);

    l_purgeCmd.insert<PURGE_CMD_MEM_BIT,
                      PURGE_CMD_MEM_BIT_LENGTH>(i_purgeData.iv_cmdMem);

    l_purgeCmd.insert<PURGE_CMD_BANK_BIT,
                      PURGE_CMD_BANK_BIT_LENGTH>(i_purgeData.iv_cmdBank);

    l_purgeCmd.insert<PURGE_CMD_CGC_BIT,
                      PURGE_CMD_CGC_BIT_LENGTH>(i_purgeData.iv_cmdCGC);

    l_purgeCmd.setBit<PURGE_CMD_TRIGGER_BIT>();

    FAPI_TRY(fapi2::putScom(i_target, i_regAddr, l_purgeCmd));

fapi_try_exit:
    return fapi2::current_err;
}

//------------------------------------------------------------------------------
///
/// @brief l2_flush_check_status: Utility subroutine to poll L2 purge
///                                    engine status, looking for clean idle
///                                    state
/// @param[in] i_target EX chiplet target
/// @param[in] i_regAddr Purge engine register SCOM address
/// @return FAPI2_RC_SUCCESS if engine status returns as idle (with no errors)
///         before maximum number of polls has been reached
///         RC_P9_L2_FLUSH_CMD_ERROR
///              if purge command error reported,
///         RC_P9_L2_FLUSH_CMD_TIMEOUT
///              if purge operation did not complete prior to polling limit,
///         else FAPI getscom/putscom return code for failing operation
///
//------------------------------------------------------------------------------
fapi2::ReturnCode l2_flush_check_status(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const uint32_t i_regAddr)
{
    fapi2::buffer<uint64_t> l_cmdReg;
    uint32_t l_polls = 1;

    FAPI_INF("l2_flush_check_status: Enter");

    while(1)
    {
        // poll Purge Engine status
        FAPI_DBG("Reading L2 Purge Engine Command Register to check status");
        FAPI_TRY(fapi2::getScom(i_target, i_regAddr, l_cmdReg));

        // check state of PURGE_CMD_ERR
        FAPI_ASSERT(!l_cmdReg.getBit<PURGE_CMD_ERR_BIT>(),
                    fapi2::P9_L2_FLUSH_CMD_ERROR()
                    .set_TARGET(i_target)
                    .set_CMD_REG(l_cmdReg)
                    .set_CMD_REG_ADDR(i_regAddr),
                    "Purge failed. PURGE_CMD_ERR_BIT set");

        // check to see if this reg is idle and ready to accept a new command
        if (!l_cmdReg.getBit<PURGE_CMD_REG_BUSY>())
        {
            FAPI_DBG("Purge engine idle");
            break;
        }

        // engine busy, dump status
        FAPI_DBG("Purge engine busy (reg_busy = %d, busy_on_this = %d,"
                 " sm_busy = %d)",
                 l_cmdReg.getBit<PURGE_CMD_REG_BUSY>(),
                 l_cmdReg.getBit<PURGE_CMD_PRGSM_BUSY_ON_THIS_BIT>(),
                 l_cmdReg.getBit<PURGE_CMD_PRGSM_BUSY_BIT>());

        // check if loop count has expired
        FAPI_ASSERT((l_polls < P9_L2_FLUSH_MAX_POLLS),
                    fapi2::P9_L2_FLUSH_CMD_TIMEOUT()
                    .set_TARGET(i_target)
                    .set_CMD_REG(l_cmdReg)
                    .set_CMD_REG_ADDR(i_regAddr)
                    .set_NUMBER_OF_ATTEMPTS(l_polls),
                    "Purge engine still busy after %d loops", l_polls);

        // l_polls left, delay prior to next poll
        FAPI_DBG("%d loops done, delaying before next poll", l_polls);

        FAPI_TRY(fapi2::delay(P9_L2_FLUSH_HW_NS_DELAY,
                              P9_L2_FLUSH_SIM_CYCLE_DELAY),
                 "fapi delay Error");

        l_polls++;
    }

fapi_try_exit:
    return fapi2::current_err;
}

//------------------------------------------------------------------------------
// Hardware Procedure
//------------------------------------------------------------------------------
fapi2::ReturnCode p9_l2_flush(const fapi2::Target < fapi2::TARGET_TYPE_EX >
                              & i_target,
                              const p9core::purgeData_t& i_purgeData)
{
    FAPI_DBG("i_purgeData.iv_cmdType: 0x%x", i_purgeData.iv_cmdType);
    FAPI_DBG("i_purgeData.iv_cmdMem : 0x%x", i_purgeData.iv_cmdMem);
    FAPI_DBG("i_purgeData.iv_cmdBank: 0x%x", i_purgeData.iv_cmdBank);
    FAPI_DBG("i_purgeData.iv_cmdCGC : 0x%x", i_purgeData.iv_cmdCGC);

    uint32_t l_regAddr = 0;
    uint8_t l_platform = 0;

    //Get the scom address to use for this platform
    const fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> FAPI_SYSTEM;
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_EXECUTION_PLATFORM,
                           FAPI_SYSTEM,
                           l_platform),
             "Error from FAPI_ATTR_GET for attribute ATTR_EXECUTION_PLATFORM");

    if( l_platform == fapi2::ENUM_ATTR_EXECUTION_PLATFORM_FSP )
    {
        l_regAddr = EX_PRD_PURGE_CMD_REG;
    }
    else
    {
        FAPI_ASSERT(false,
                    fapi2::P9_L2_FLUSH_UNKNOWN_PLATFORM()
                    .set_TARGET(i_target)
                    .set_PLATFORM(l_platform),
                    "Unsupported l_platform %d", l_platform);
    }

    // initiate flush
    FAPI_TRY(l2_flush_start(i_target, l_regAddr, i_purgeData));

    // check that flush completes and the purge engine is idle
    // before exiting
    FAPI_TRY(l2_flush_check_status(i_target, l_regAddr));

fapi_try_exit:
    FAPI_INF("l2_flush, Ex: Exit");
    return fapi2::current_err;
}
<commit_msg>SBE Compile Issues fixed<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/nest/p9_l2_flush.C $       */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] 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 p9_l2_flush.H
/// @brief Flush the P9 L2 cache (FAPI)
///
/// *HWP HWP Owner   : Benjamin Gass <bgass@us.ibm.com>
/// *HWP FW Owner    : Bilicon Patil  <bilpatil@in.ibm.com>
/// *HWP Team        : Quad
/// *HWP Consumed by : FSP
/// *HWP Level       : 2
///

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <p9_quad_scom_addresses.H>
#include <p9_l2_flush.H>

//------------------------------------------------------------------------------
// Constant definitions
//------------------------------------------------------------------------------

// L2 Purge Engine Command Register bit/field definitions
enum
{
    PURGE_CMD_TRIGGER_BIT            = 0,
    PURGE_CMD_REG_BUSY               = 9,
    PURGE_CMD_PRGSM_BUSY_ON_THIS_BIT = 10,
    PURGE_CMD_PRGSM_BUSY_BIT         = 11,
    PURGE_CMD_ERR_BIT                = 29,
    PURGE_CMD_TYPE_BIT               = 1,
    PURGE_CMD_MEM_BIT                = 17,
    PURGE_CMD_BANK_BIT               = 28,
    PURGE_CMD_CGC_BIT                = 20
};

// L2 Purge Engine Command Register bit/field Lengths
enum
{
    PURGE_CMD_TYPE_BIT_LENGTH   = 4,
    PURGE_CMD_MEM_BIT_LENGTH    = 3,
    PURGE_CMD_BANK_BIT_LENGTH   = 1,
    PURGE_CMD_CGC_BIT_LENGTH    = 8
};

// polling constants
enum
{
    P9_L2_FLUSH_HW_NS_DELAY     = 10000, // unit is nano seconds
    P9_L2_FLUSH_SIM_CYCLE_DELAY = 12000, // unit is cycles
    P9_L2_FLUSH_MAX_POLLS       = 200    // unit is cycles
};

//------------------------------------------------------------------------------
// Function definitions
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
///
/// @brief l2_flush_start: Utility subroutine to initiate L2 cache flush
///                        via purge engine
/// @param[in]  i_target Ex target
/// @param[in]  i_regAddr The scom address to use
/// @param[in]  i_purgeData Structure having values for MEM, CGC, BANK
///                         passed by the user
/// @return  FAPI2_RC_SUCCESS if purge operation was started,
///          RC_P9_L2_FLUSH_PURGE_REQ_OUTSTANDING if a prior purge
///          operation has not yet completed
///          else FAPI getscom/putscom return code for failing operation
//------------------------------------------------------------------------------
fapi2::ReturnCode l2_flush_start(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const uint32_t i_regAddr,
    const p9core::purgeData_t& i_purgeData)
{
    fapi2::buffer<uint64_t> l_cmdReg;
    fapi2::buffer<uint64_t> l_purgeCmd;

    FAPI_INF("l2_flush_start: Enter");

    // ensure that purge engine is idle before starting flush
    // poll Purge Engine status
    FAPI_DBG("Reading L2 Purge Engine Command Register to check status");
    FAPI_TRY(fapi2::getScom(i_target, i_regAddr, l_cmdReg));

    // check to see if this reg is idle and ready to accept a new command
    FAPI_ASSERT(!l_cmdReg.getBit<PURGE_CMD_REG_BUSY>(),
                fapi2::P9_L2_FLUSH_PURGE_REQ_OUTSTANDING()
                .set_TARGET(i_target)
                .set_CMD_REG(l_cmdReg)
                .set_CMD_REG_ADDR(i_regAddr),
                "Previous purge request has not completed for target");

    // write PURGE_CMD_TRIGGER bit in Purge Engine Command Register
    // ensure PURGE_CMD_TYPE/MEM/CGC/BANK are clear to specify flush
    // of entire cache
    FAPI_DBG("Write L2 Purge Engine Command Register to initiate cache flush");
    l_purgeCmd.insert<PURGE_CMD_TYPE_BIT,
                      PURGE_CMD_TYPE_BIT_LENGTH>(i_purgeData.iv_cmdType);

    l_purgeCmd.insert<PURGE_CMD_MEM_BIT,
                      PURGE_CMD_MEM_BIT_LENGTH>(i_purgeData.iv_cmdMem);

    l_purgeCmd.insert<PURGE_CMD_BANK_BIT,
                      PURGE_CMD_BANK_BIT_LENGTH>(i_purgeData.iv_cmdBank);

    l_purgeCmd.insert<PURGE_CMD_CGC_BIT,
                      PURGE_CMD_CGC_BIT_LENGTH>(i_purgeData.iv_cmdCGC);

    l_purgeCmd.setBit<PURGE_CMD_TRIGGER_BIT>();

    FAPI_TRY(fapi2::putScom(i_target, i_regAddr, l_purgeCmd));

fapi_try_exit:
    return fapi2::current_err;
}

//------------------------------------------------------------------------------
///
/// @brief l2_flush_check_status: Utility subroutine to poll L2 purge
///                                    engine status, looking for clean idle
///                                    state
/// @param[in] i_target EX chiplet target
/// @param[in] i_regAddr Purge engine register SCOM address
/// @return FAPI2_RC_SUCCESS if engine status returns as idle (with no errors)
///         before maximum number of polls has been reached
///         RC_P9_L2_FLUSH_CMD_ERROR
///              if purge command error reported,
///         RC_P9_L2_FLUSH_CMD_TIMEOUT
///              if purge operation did not complete prior to polling limit,
///         else FAPI getscom/putscom return code for failing operation
///
//------------------------------------------------------------------------------
fapi2::ReturnCode l2_flush_check_status(
    const fapi2::Target<fapi2::TARGET_TYPE_EX>& i_target,
    const uint32_t i_regAddr)
{
    fapi2::buffer<uint64_t> l_cmdReg;
    uint32_t l_polls = 1;

    FAPI_INF("l2_flush_check_status: Enter");

    while(1)
    {
        // poll Purge Engine status
        FAPI_DBG("Reading L2 Purge Engine Command Register to check status");
        FAPI_TRY(fapi2::getScom(i_target, i_regAddr, l_cmdReg));

        // check state of PURGE_CMD_ERR
        FAPI_ASSERT(!l_cmdReg.getBit<PURGE_CMD_ERR_BIT>(),
                    fapi2::P9_L2_FLUSH_CMD_ERROR()
                    .set_TARGET(i_target)
                    .set_CMD_REG(l_cmdReg)
                    .set_CMD_REG_ADDR(i_regAddr),
                    "Purge failed. PURGE_CMD_ERR_BIT set");

        // check to see if this reg is idle and ready to accept a new command
        if (!l_cmdReg.getBit<PURGE_CMD_REG_BUSY>())
        {
            FAPI_DBG("Purge engine idle");
            break;
        }

        // engine busy, dump status
        FAPI_DBG("Purge engine busy (reg_busy = %d, busy_on_this = %d,"
                 " sm_busy = %d)",
                 l_cmdReg.getBit<PURGE_CMD_REG_BUSY>(),
                 l_cmdReg.getBit<PURGE_CMD_PRGSM_BUSY_ON_THIS_BIT>(),
                 l_cmdReg.getBit<PURGE_CMD_PRGSM_BUSY_BIT>());

        // check if loop count has expired
        FAPI_ASSERT((l_polls < P9_L2_FLUSH_MAX_POLLS),
                    fapi2::P9_L2_FLUSH_CMD_TIMEOUT()
                    .set_TARGET(i_target)
                    .set_CMD_REG(l_cmdReg)
                    .set_CMD_REG_ADDR(i_regAddr)
                    .set_NUMBER_OF_ATTEMPTS(l_polls),
                    "Purge engine still busy after %d loops", l_polls);

        // l_polls left, delay prior to next poll
        FAPI_DBG("%d loops done, delaying before next poll", l_polls);

        FAPI_TRY(fapi2::delay(P9_L2_FLUSH_HW_NS_DELAY,
                              P9_L2_FLUSH_SIM_CYCLE_DELAY),
                 "fapi delay Error");

        l_polls++;
    }

fapi_try_exit:
    return fapi2::current_err;
}

//------------------------------------------------------------------------------
// Hardware Procedure
//------------------------------------------------------------------------------
fapi2::ReturnCode p9_l2_flush(const fapi2::Target < fapi2::TARGET_TYPE_EX >
                              & i_target,
                              const p9core::purgeData_t& i_purgeData)
{
    FAPI_DBG("i_purgeData [iv_cmdType: 0x%x] [iv_cmdMem : 0x%x] "
             "[iv_cmdBank: 0x%x] [iv_cmdCGC : 0x%x]", i_purgeData.iv_cmdType,
             i_purgeData.iv_cmdMem, i_purgeData.iv_cmdBank, i_purgeData.iv_cmdCGC);

    uint32_t l_regAddr = EX_PRD_PURGE_CMD_REG;

    // initiate flush
    FAPI_TRY(l2_flush_start(i_target, l_regAddr, i_purgeData));

    // check that flush completes and the purge engine is idle
    // before exiting
    FAPI_TRY(l2_flush_check_status(i_target, l_regAddr));

fapi_try_exit:
    FAPI_INF("l2_flush, Ex: Exit");
    return fapi2::current_err;
}
<|endoftext|>


<commit_before>#include <boost/algorithm/string.hpp>
#include "pqrs/xml_compiler.hpp"

namespace pqrs {
  xml_compiler::preferences_node::preferences_node(void) :
    name_line_count_(0)
  {}

  bool
  xml_compiler::preferences_node::handle_name_and_appendix(const boost::property_tree::ptree::value_type& it)
  {
    if (it.first == "name") {
      name_ += boost::trim_copy(it.second.data());
      name_ += "\n";

      ++name_line_count_;

      return true;

    } else if (it.first == "appendix") {
      name_ += "  ";
      name_ += boost::trim_copy(it.second.data());
      name_ += "\n";

      ++name_line_count_;

      return true;
    }

    return false;
  }

  xml_compiler::preferences_checkbox_node::preferences_checkbox_node(void)
  {}

  xml_compiler::preferences_checkbox_node::preferences_checkbox_node(const preferences_checkbox_node& parent) :
    name_for_filter_(parent.name_for_filter_ + " ")
  {}

  bool
  xml_compiler::preferences_checkbox_node::handle_item_child(const boost::property_tree::ptree::value_type& it)
  {
    if (preferences_node::handle_name_and_appendix(it)) {
      name_for_filter_ += boost::algorithm::to_lower_copy(boost::trim_copy(it.second.data()));
      name_for_filter_ += " ";

      return true;
    }
    if (it.first == "identifier") {
      identifier_ = boost::trim_copy(it.second.data());
      return true;
    }
    return false;
  }

  xml_compiler::preferences_number_node::preferences_number_node(void) :
    default_value_(0),
    step_(1)
  {}

  xml_compiler::preferences_number_node::preferences_number_node(const preferences_number_node& /*parent*/) :
    preferences_number_node()
  {}

  bool
  xml_compiler::preferences_number_node::handle_item_child(const boost::property_tree::ptree::value_type& it)
  {
    if (preferences_node::handle_name_and_appendix(it)) {
      return true;
    }
    if (it.first == "identifier") {
      identifier_ = boost::trim_copy(it.second.data());

      // default
      {
        auto value = it.second.get_optional<std::string>("<xmlattr>.default");
        if (value) {
          auto v = pqrs::string::to_uint32_t(boost::trim_copy(*value));
          if (v) {
            default_value_ = *v;
          }
        }
      }
      // step
      {
        auto value = it.second.get_optional<std::string>("<xmlattr>.step");
        if (value) {
          auto v = pqrs::string::to_uint32_t(boost::trim_copy(*value));
          if (v) {
            step_ = *v;
          }
        }
      }
      // baseunit
      {
        auto value = it.second.get_optional<std::string>("<xmlattr>.baseunit");
        if (value) {
          base_unit_ = boost::trim_copy(*value);
        }
      }

      return true;
    }

    return false;
  }

  template <class T>
  void
  xml_compiler::preferences_node_tree<T>::clear(void)
  {
    if (children_) {
      children_->clear();
    }
  }

  template <class T>
  void
  xml_compiler::preferences_node_tree<T>::traverse_item(const boost::property_tree::ptree& pt)
  {
    for (auto& it : pt) {
      if (it.first != "item") {
        traverse_item(it.second);

      } else {
        preferences_node_tree_ptr ptr(new preferences_node_tree(node_));

        for (auto& child : it.second) {
          if ((ptr->node_).handle_item_child(child)) {
            continue;
          }
          ptr->traverse_item(child.second);
        }

        if (! children_) {
          children_ = preferences_node_tree_ptrs_ptr(new preferences_node_tree_ptrs());
        }
        children_->push_back(ptr);
      }
    }
  }

  void
  xml_compiler::reload_preferences_(void)
  {
    preferences_checkbox_node_tree_.clear();
    preferences_number_node_tree_.clear();

    // checkbox
    {
      std::vector<xml_file_path_ptr> xml_file_path_ptrs;
      xml_file_path_ptrs.push_back(
        xml_file_path_ptr(new xml_file_path(xml_file_path::base_directory::private_xml, "private.xml")));
      xml_file_path_ptrs.push_back(
        xml_file_path_ptr(new xml_file_path(xml_file_path::base_directory::system_xml,  "checkbox.xml")));

      std::vector<ptree_ptr> pt_ptrs;
      read_xmls_(pt_ptrs, xml_file_path_ptrs);

      for (auto& pt_ptr : pt_ptrs) {
        preferences_checkbox_node_tree_.traverse_item(*pt_ptr);
      }
    }

    // number
    {
      std::vector<xml_file_path_ptr> xml_file_path_ptrs;
      xml_file_path_ptrs.push_back(
        xml_file_path_ptr(new xml_file_path(xml_file_path::base_directory::system_xml, "number.xml")));

      std::vector<ptree_ptr> pt_ptrs;
      read_xmls_(pt_ptrs, xml_file_path_ptrs);

      for (auto& pt_ptr : pt_ptrs) {
        preferences_number_node_tree_.traverse_item(*pt_ptr);
      }
    }
  }
}
<commit_msg>adjust name_line_count<commit_after>#include <boost/algorithm/string.hpp>
#include "pqrs/xml_compiler.hpp"

namespace pqrs {
  xml_compiler::preferences_node::preferences_node(void) :
    name_line_count_(1)
  {}

  bool
  xml_compiler::preferences_node::handle_name_and_appendix(const boost::property_tree::ptree::value_type& it)
  {
    if (it.first == "name") {
      if (! name_.empty()) {
        name_ += "\n";
        ++name_line_count_;
      }
      name_ += boost::trim_copy(it.second.data());

      return true;

    } else if (it.first == "appendix") {
      if (! name_.empty()) {
        name_ += "\n";
        ++name_line_count_;
      }
      name_ += "  ";
      name_ += boost::trim_copy(it.second.data());

      return true;
    }

    return false;
  }

  xml_compiler::preferences_checkbox_node::preferences_checkbox_node(void)
  {}

  xml_compiler::preferences_checkbox_node::preferences_checkbox_node(const preferences_checkbox_node& parent) :
    name_for_filter_(parent.name_for_filter_ + " ")
  {}

  bool
  xml_compiler::preferences_checkbox_node::handle_item_child(const boost::property_tree::ptree::value_type& it)
  {
    if (preferences_node::handle_name_and_appendix(it)) {
      name_for_filter_ += boost::algorithm::to_lower_copy(boost::trim_copy(it.second.data()));
      name_for_filter_ += " ";

      return true;
    }
    if (it.first == "identifier") {
      identifier_ = boost::trim_copy(it.second.data());
      return true;
    }
    return false;
  }

  xml_compiler::preferences_number_node::preferences_number_node(void) :
    default_value_(0),
    step_(1)
  {}

  xml_compiler::preferences_number_node::preferences_number_node(const preferences_number_node& /*parent*/) :
    preferences_number_node()
  {}

  bool
  xml_compiler::preferences_number_node::handle_item_child(const boost::property_tree::ptree::value_type& it)
  {
    if (preferences_node::handle_name_and_appendix(it)) {
      return true;
    }
    if (it.first == "identifier") {
      identifier_ = boost::trim_copy(it.second.data());

      // default
      {
        auto value = it.second.get_optional<std::string>("<xmlattr>.default");
        if (value) {
          auto v = pqrs::string::to_uint32_t(boost::trim_copy(*value));
          if (v) {
            default_value_ = *v;
          }
        }
      }
      // step
      {
        auto value = it.second.get_optional<std::string>("<xmlattr>.step");
        if (value) {
          auto v = pqrs::string::to_uint32_t(boost::trim_copy(*value));
          if (v) {
            step_ = *v;
          }
        }
      }
      // baseunit
      {
        auto value = it.second.get_optional<std::string>("<xmlattr>.baseunit");
        if (value) {
          base_unit_ = boost::trim_copy(*value);
        }
      }

      return true;
    }

    return false;
  }

  template <class T>
  void
  xml_compiler::preferences_node_tree<T>::clear(void)
  {
    if (children_) {
      children_->clear();
    }
  }

  template <class T>
  void
  xml_compiler::preferences_node_tree<T>::traverse_item(const boost::property_tree::ptree& pt)
  {
    for (auto& it : pt) {
      if (it.first != "item") {
        traverse_item(it.second);

      } else {
        preferences_node_tree_ptr ptr(new preferences_node_tree(node_));

        for (auto& child : it.second) {
          if ((ptr->node_).handle_item_child(child)) {
            continue;
          }
          ptr->traverse_item(child.second);
        }

        if (! children_) {
          children_ = preferences_node_tree_ptrs_ptr(new preferences_node_tree_ptrs());
        }
        children_->push_back(ptr);
      }
    }
  }

  void
  xml_compiler::reload_preferences_(void)
  {
    preferences_checkbox_node_tree_.clear();
    preferences_number_node_tree_.clear();

    // checkbox
    {
      std::vector<xml_file_path_ptr> xml_file_path_ptrs;
      xml_file_path_ptrs.push_back(
        xml_file_path_ptr(new xml_file_path(xml_file_path::base_directory::private_xml, "private.xml")));
      xml_file_path_ptrs.push_back(
        xml_file_path_ptr(new xml_file_path(xml_file_path::base_directory::system_xml,  "checkbox.xml")));

      std::vector<ptree_ptr> pt_ptrs;
      read_xmls_(pt_ptrs, xml_file_path_ptrs);

      for (auto& pt_ptr : pt_ptrs) {
        preferences_checkbox_node_tree_.traverse_item(*pt_ptr);
      }
    }

    // number
    {
      std::vector<xml_file_path_ptr> xml_file_path_ptrs;
      xml_file_path_ptrs.push_back(
        xml_file_path_ptr(new xml_file_path(xml_file_path::base_directory::system_xml, "number.xml")));

      std::vector<ptree_ptr> pt_ptrs;
      read_xmls_(pt_ptrs, xml_file_path_ptrs);

      for (auto& pt_ptr : pt_ptrs) {
        preferences_number_node_tree_.traverse_item(*pt_ptr);
      }
    }
  }
}
<|endoftext|>


<commit_before>/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserve.

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. */

#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/operators/lrn_op.h"
#include "paddle/fluid/platform/mkldnn_helper.h"

namespace paddle {
namespace operators {

using paddle::framework::Tensor;
using paddle::platform::MKLDNNDeviceContext;

namespace {
template <typename T, typename... Args>
std::shared_ptr<T> insert_to_context(const std::string& key,
                                     const MKLDNNDeviceContext& dev_ctx,
                                     Args&&... args) {
  auto p = std::static_pointer_cast<T, void>(dev_ctx.GetBlob(key));

  if (!p) {
    p = std::make_shared<T>(args...);
    dev_ctx.SetBlob(key, std::static_pointer_cast<void, T>(p));
  }

  return p;
}

template <typename... Args>
void run_primitive(Args&&... args) {
  auto forward_op = mkldnn::lrn_forward{args...};

  std::vector<mkldnn::primitive> pipeline = {forward_op};
  mkldnn::stream(mkldnn::stream::kind::eager).submit(pipeline).wait();
}
}  // namespace

template <typename T>
class LRNMKLDNNOpKernel : public paddle::framework::OpKernel<T> {
 public:
  void Compute(const paddle::framework::ExecutionContext& ctx) const override {
    bool is_float_type = std::is_same<T, float>::value;
    PADDLE_ENFORCE(is_float_type, "MKLDNN LRN must use float data.");
    PADDLE_ENFORCE(paddle::platform::is_cpu_place(ctx.GetPlace()),
                   "MKLDNN LRN must use CPUPlace.");

    auto& dev_ctx = ctx.template device_context<MKLDNNDeviceContext>();
    const auto& mkldnn_engine = dev_ctx.GetEngine();

    auto x = ctx.Input<Tensor>("X");
    auto out = ctx.Output<Tensor>("Out");
    auto mid = ctx.Output<Tensor>("MidOut");

    auto input_data = x->data<T>();
    auto output_data = out->mutable_data<T>(ctx.GetPlace());
    mid->mutable_data<T>(ctx.GetPlace());

    const int n = ctx.Attr<int>("n");
    const float alpha = ctx.Attr<float>("alpha");
    const float beta = ctx.Attr<float>("beta");
    const float k = ctx.Attr<float>("k");
    const bool is_test = ctx.Attr<bool>("is_test");

    auto e_mid = framework::EigenTensor<T, 4>::From(*mid);
    e_mid = e_mid.constant(k);

    auto dims = paddle::framework::vectorize2int(x->dims());

    auto src_md = paddle::platform::MKLDNNMemDesc(
        dims, mkldnn::memory::data_type::f32, mkldnn::memory::format::nchw);

    auto dst_md = paddle::platform::MKLDNNMemDesc(
        dims, mkldnn::memory::data_type::f32, mkldnn::memory::format::nchw);

    auto forward_desc = mkldnn::lrn_forward::desc{mkldnn::prop_kind::forward,
                                                  mkldnn::lrn_across_channels,
                                                  src_md,
                                                  n,
                                                  alpha,
                                                  beta,
                                                  k};

    auto src_memory_pd = mkldnn::memory::primitive_desc{src_md, mkldnn_engine};
    auto dst_memory = mkldnn::memory{{dst_md, mkldnn_engine},
                                     static_cast<void*>(output_data)};

    if (!is_test) {
      const std::string key = ctx.op().Output("Out");
      const std::string key_src_memory = key + "@lrn_src_memory";
      const std::string key_pd = key + "@lrn_pd";
      const std::string key_workspace_memory = key + "@lrn_workspace_memory";

      auto forward_pd = insert_to_context<mkldnn::lrn_forward::primitive_desc>(
          key_pd, dev_ctx, forward_desc, mkldnn_engine);

      auto src_memory = insert_to_context<mkldnn::memory>(
          key_src_memory, dev_ctx, src_memory_pd);

      src_memory->set_data_handle(
          static_cast<void*>(const_cast<T*>(input_data)));

      auto workspace_memory = insert_to_context<mkldnn::memory>(
          key_workspace_memory, dev_ctx,
          forward_pd->workspace_primitive_desc());

      run_primitive(*forward_pd, *src_memory, *workspace_memory, dst_memory);
    } else {
      auto forward_pd =
          mkldnn::lrn_forward::primitive_desc{forward_desc, mkldnn_engine};
      auto src_memory = mkldnn::memory{
          src_memory_pd, static_cast<void*>(const_cast<T*>(input_data))};
      auto workspace_memory =
          mkldnn::memory{forward_pd.workspace_primitive_desc()};

      run_primitive(forward_pd, src_memory, workspace_memory, dst_memory);
    }
  }
};

template <typename T>
class LRNMKLDNNGradOpKernel : public paddle::framework::OpKernel<T> {
 public:
  void Compute(const paddle::framework::ExecutionContext& ctx) const override {
    PADDLE_ENFORCE(std::is_same<T, float>::value,
                   "MKLDNN LRN must use float data.");
    PADDLE_ENFORCE(paddle::platform::is_cpu_place(ctx.GetPlace()),
                   "MKLDNN LRN must use CPUPlace.");
    PADDLE_ENFORCE(
        !ctx.Attr<bool>("is_test"),
        "is_test attribute should be set to False in training phase.");

    auto x = ctx.Input<Tensor>("X");

    auto out_grad = ctx.Input<Tensor>(framework::GradVarName("Out"));
    auto x_grad = ctx.Output<Tensor>(framework::GradVarName("X"));

    const std::string key = ctx.op().Input("Out");
    const std::string key_src_memory = key + "@lrn_src_memory";
    const std::string key_pd = key + "@lrn_pd";
    const std::string key_workspace_memory = key + "@lrn_workspace_memory";

    const int n = ctx.Attr<int>("n");
    const float alpha = ctx.Attr<float>("alpha");
    const float beta = ctx.Attr<float>("beta");
    const float k = ctx.Attr<float>("k");

    auto& dev_ctx = ctx.template device_context<MKLDNNDeviceContext>();
    const auto& mkldnn_engine = dev_ctx.GetEngine();

    auto x_grad_data = x_grad->mutable_data<T>(ctx.GetPlace());
    auto out_grad_data = out_grad->data<T>();

    auto dims = paddle::framework::vectorize2int(x->dims());

    auto src_md = paddle::platform::MKLDNNMemDesc(
        dims, mkldnn::memory::data_type::f32, mkldnn::memory::format::nchw);

    auto diff_src_md = paddle::platform::MKLDNNMemDesc(
        dims, mkldnn::memory::data_type::f32, mkldnn::memory::format::nchw);

    auto diff_dst_md = paddle::platform::MKLDNNMemDesc(
        dims, mkldnn::memory::data_type::f32, mkldnn::memory::format::nchw);

    auto diff_dst_memory =
        mkldnn::memory{{diff_dst_md, mkldnn_engine},
                       static_cast<void*>(const_cast<float*>(out_grad_data))};

    auto diff_src_memory = mkldnn::memory{{diff_src_md, mkldnn_engine},
                                          static_cast<void*>(x_grad_data)};

    auto backward_desc = mkldnn::lrn_backward::desc{
        mkldnn::lrn_across_channels, src_md, diff_src_md, n, alpha, beta, k};

    auto forward_pd = dev_ctx.GetBlob(key_pd);

    auto backward_pd = mkldnn::lrn_backward::primitive_desc{
        backward_desc, mkldnn_engine,
        *static_cast<mkldnn::lrn_forward::primitive_desc*>(forward_pd.get())};

    std::shared_ptr<void> workspace_memory =
        dev_ctx.GetBlob(key_workspace_memory);

    auto src_memory = dev_ctx.GetBlob(key_src_memory);
    auto backward_op = mkldnn::lrn_backward{
        backward_pd, *static_cast<mkldnn::memory*>(src_memory.get()),
        diff_dst_memory, *static_cast<mkldnn::memory*>(workspace_memory.get()),
        diff_src_memory};

    std::vector<mkldnn::primitive> pipeline = {backward_op};
    mkldnn::stream(mkldnn::stream::kind::eager).submit(pipeline).wait();
  }
};
}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;

REGISTER_OP_KERNEL(lrn, MKLDNN, paddle::platform::CPUPlace,
                   ops::LRNMKLDNNOpKernel<float>);
REGISTER_OP_KERNEL(lrn_grad, MKLDNN, paddle::platform::CPUPlace,
                   ops::LRNMKLDNNGradOpKernel<float>);
<commit_msg>Avoid comma in macro<commit_after>/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserve.

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. */

#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/operators/lrn_op.h"
#include "paddle/fluid/platform/mkldnn_helper.h"

namespace paddle {
namespace operators {

using paddle::framework::Tensor;
using paddle::platform::MKLDNNDeviceContext;

namespace {
template <typename T, typename... Args>
std::shared_ptr<T> insert_to_context(const std::string& key,
                                     const MKLDNNDeviceContext& dev_ctx,
                                     Args&&... args) {
  auto p = std::static_pointer_cast<T, void>(dev_ctx.GetBlob(key));

  if (!p) {
    p = std::make_shared<T>(args...);
    dev_ctx.SetBlob(key, std::static_pointer_cast<void, T>(p));
  }

  return p;
}

template <typename... Args>
void run_primitive(Args&&... args) {
  auto forward_op = mkldnn::lrn_forward{args...};

  std::vector<mkldnn::primitive> pipeline = {forward_op};
  mkldnn::stream(mkldnn::stream::kind::eager).submit(pipeline).wait();
}
}  // namespace

template <typename T>
class LRNMKLDNNOpKernel : public paddle::framework::OpKernel<T> {
 public:
  void Compute(const paddle::framework::ExecutionContext& ctx) const override {
    const bool is_float_type = std::is_same<T, float>::value;
    PADDLE_ENFORCE(is_float_type, "MKLDNN LRN must use float data.");
    PADDLE_ENFORCE(paddle::platform::is_cpu_place(ctx.GetPlace()),
                   "MKLDNN LRN must use CPUPlace.");

    auto& dev_ctx = ctx.template device_context<MKLDNNDeviceContext>();
    const auto& mkldnn_engine = dev_ctx.GetEngine();

    auto x = ctx.Input<Tensor>("X");
    auto out = ctx.Output<Tensor>("Out");
    auto mid = ctx.Output<Tensor>("MidOut");

    auto input_data = x->data<T>();
    auto output_data = out->mutable_data<T>(ctx.GetPlace());
    mid->mutable_data<T>(ctx.GetPlace());

    const int n = ctx.Attr<int>("n");
    const float alpha = ctx.Attr<float>("alpha");
    const float beta = ctx.Attr<float>("beta");
    const float k = ctx.Attr<float>("k");
    const bool is_test = ctx.Attr<bool>("is_test");

    auto e_mid = framework::EigenTensor<T, 4>::From(*mid);
    e_mid = e_mid.constant(k);

    auto dims = paddle::framework::vectorize2int(x->dims());

    auto src_md = paddle::platform::MKLDNNMemDesc(
        dims, mkldnn::memory::data_type::f32, mkldnn::memory::format::nchw);

    auto dst_md = paddle::platform::MKLDNNMemDesc(
        dims, mkldnn::memory::data_type::f32, mkldnn::memory::format::nchw);

    auto forward_desc = mkldnn::lrn_forward::desc{mkldnn::prop_kind::forward,
                                                  mkldnn::lrn_across_channels,
                                                  src_md,
                                                  n,
                                                  alpha,
                                                  beta,
                                                  k};

    auto src_memory_pd = mkldnn::memory::primitive_desc{src_md, mkldnn_engine};
    auto dst_memory = mkldnn::memory{{dst_md, mkldnn_engine},
                                     static_cast<void*>(output_data)};

    if (!is_test) {
      const std::string key = ctx.op().Output("Out");
      const std::string key_src_memory = key + "@lrn_src_memory";
      const std::string key_pd = key + "@lrn_pd";
      const std::string key_workspace_memory = key + "@lrn_workspace_memory";

      auto forward_pd = insert_to_context<mkldnn::lrn_forward::primitive_desc>(
          key_pd, dev_ctx, forward_desc, mkldnn_engine);

      auto src_memory = insert_to_context<mkldnn::memory>(
          key_src_memory, dev_ctx, src_memory_pd);

      src_memory->set_data_handle(
          static_cast<void*>(const_cast<T*>(input_data)));

      auto workspace_memory = insert_to_context<mkldnn::memory>(
          key_workspace_memory, dev_ctx,
          forward_pd->workspace_primitive_desc());

      run_primitive(*forward_pd, *src_memory, *workspace_memory, dst_memory);
    } else {
      auto forward_pd =
          mkldnn::lrn_forward::primitive_desc{forward_desc, mkldnn_engine};
      auto src_memory = mkldnn::memory{
          src_memory_pd, static_cast<void*>(const_cast<T*>(input_data))};
      auto workspace_memory =
          mkldnn::memory{forward_pd.workspace_primitive_desc()};

      run_primitive(forward_pd, src_memory, workspace_memory, dst_memory);
    }
  }
};

template <typename T>
class LRNMKLDNNGradOpKernel : public paddle::framework::OpKernel<T> {
 public:
  void Compute(const paddle::framework::ExecutionContext& ctx) const override {
    const bool is_float_type = std::is_same<T, float>::value;
    PADDLE_ENFORCE(is_float_type, "MKLDNN LRN must use float data.");
    PADDLE_ENFORCE(paddle::platform::is_cpu_place(ctx.GetPlace()),
                   "MKLDNN LRN must use CPUPlace.");
    PADDLE_ENFORCE(
        !ctx.Attr<bool>("is_test"),
        "is_test attribute should be set to False in training phase.");

    auto x = ctx.Input<Tensor>("X");

    auto out_grad = ctx.Input<Tensor>(framework::GradVarName("Out"));
    auto x_grad = ctx.Output<Tensor>(framework::GradVarName("X"));

    const std::string key = ctx.op().Input("Out");
    const std::string key_src_memory = key + "@lrn_src_memory";
    const std::string key_pd = key + "@lrn_pd";
    const std::string key_workspace_memory = key + "@lrn_workspace_memory";

    const int n = ctx.Attr<int>("n");
    const float alpha = ctx.Attr<float>("alpha");
    const float beta = ctx.Attr<float>("beta");
    const float k = ctx.Attr<float>("k");

    auto& dev_ctx = ctx.template device_context<MKLDNNDeviceContext>();
    const auto& mkldnn_engine = dev_ctx.GetEngine();

    auto x_grad_data = x_grad->mutable_data<T>(ctx.GetPlace());
    auto out_grad_data = out_grad->data<T>();

    auto dims = paddle::framework::vectorize2int(x->dims());

    auto src_md = paddle::platform::MKLDNNMemDesc(
        dims, mkldnn::memory::data_type::f32, mkldnn::memory::format::nchw);

    auto diff_src_md = paddle::platform::MKLDNNMemDesc(
        dims, mkldnn::memory::data_type::f32, mkldnn::memory::format::nchw);

    auto diff_dst_md = paddle::platform::MKLDNNMemDesc(
        dims, mkldnn::memory::data_type::f32, mkldnn::memory::format::nchw);

    auto diff_dst_memory =
        mkldnn::memory{{diff_dst_md, mkldnn_engine},
                       static_cast<void*>(const_cast<float*>(out_grad_data))};

    auto diff_src_memory = mkldnn::memory{{diff_src_md, mkldnn_engine},
                                          static_cast<void*>(x_grad_data)};

    auto backward_desc = mkldnn::lrn_backward::desc{
        mkldnn::lrn_across_channels, src_md, diff_src_md, n, alpha, beta, k};

    auto forward_pd = dev_ctx.GetBlob(key_pd);

    auto backward_pd = mkldnn::lrn_backward::primitive_desc{
        backward_desc, mkldnn_engine,
        *static_cast<mkldnn::lrn_forward::primitive_desc*>(forward_pd.get())};

    std::shared_ptr<void> workspace_memory =
        dev_ctx.GetBlob(key_workspace_memory);

    auto src_memory = dev_ctx.GetBlob(key_src_memory);
    auto backward_op = mkldnn::lrn_backward{
        backward_pd, *static_cast<mkldnn::memory*>(src_memory.get()),
        diff_dst_memory, *static_cast<mkldnn::memory*>(workspace_memory.get()),
        diff_src_memory};

    std::vector<mkldnn::primitive> pipeline = {backward_op};
    mkldnn::stream(mkldnn::stream::kind::eager).submit(pipeline).wait();
  }
};
}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;

REGISTER_OP_KERNEL(lrn, MKLDNN, paddle::platform::CPUPlace,
                   ops::LRNMKLDNNOpKernel<float>);
REGISTER_OP_KERNEL(lrn_grad, MKLDNN, paddle::platform::CPUPlace,
                   ops::LRNMKLDNNGradOpKernel<float>);
<|endoftext|>


<commit_before>// Filename: config_pstats.cxx
// Created by:  drose (09Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "config_pstats.h"

#include "dconfig.h"

ConfigureDef(config_pstats);
NotifyCategoryDef(pstats, "");

ConfigureFn(config_pstats) {
  init_libpstatclient();
}

ConfigVariableString pstats_name
("pstats-name", "Panda Stats");

ConfigVariableDouble pstats_max_rate
("pstats-max-rate", 30.0);

ConfigVariableBool pstats_threaded_write
("pstats-threaded-write", false);

ConfigVariableDouble pstats_tcp_ratio
("pstats-tcp-ratio", 0.01,
 PRC_DESC("This specifies the ratio of frame update messages that are eligible "
          "for UDP that are sent via TCP instead.  It does not count messages "
          "that are too large for UDP and must be sent via TCP anyway.  1.0 "
          "means all messages are sent TCP; 0.0 means all are sent UDP."));

ConfigVariableString pstats_host
("pstats-host", "localhost");

// The default port for PStats used to be 5180, but that's used by AIM.
ConfigVariableInt pstats_port
("pstats-port", 5185);

ConfigVariableDouble pstats_target_frame_rate
("pstats-target-frame-rate", 30.0);

// The rest are different in that they directly control the server,
// not the client.
ConfigVariableBool pstats_scroll_mode
("pstats-scroll-mode", true);
ConfigVariableDouble pstats_history
("pstats-history", 60.0);
ConfigVariableDouble pstats_average_time
("pstats-average-time", 3.0);

////////////////////////////////////////////////////////////////////
//     Function: init_libpstatclient
//  Description: Initializes the library.  This must be called at
//               least once before any of the functions or classes in
//               this library can be used.  Normally it will be
//               called by the static initializers and need not be
//               called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libpstatclient() {
  static bool initialized = false;
  if (initialized) {
    return;
  }
  initialized = true;
}

<commit_msg>use more net bandwidth<commit_after>// Filename: config_pstats.cxx
// Created by:  drose (09Jul00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "config_pstats.h"

#include "dconfig.h"

ConfigureDef(config_pstats);
NotifyCategoryDef(pstats, "");

ConfigureFn(config_pstats) {
  init_libpstatclient();
}

ConfigVariableString pstats_name
("pstats-name", "Panda Stats");

ConfigVariableDouble pstats_max_rate
("pstats-max-rate", 1000.0);

ConfigVariableBool pstats_threaded_write
("pstats-threaded-write", false);

ConfigVariableDouble pstats_tcp_ratio
("pstats-tcp-ratio", 0.01,
 PRC_DESC("This specifies the ratio of frame update messages that are eligible "
          "for UDP that are sent via TCP instead.  It does not count messages "
          "that are too large for UDP and must be sent via TCP anyway.  1.0 "
          "means all messages are sent TCP; 0.0 means all are sent UDP."));

ConfigVariableString pstats_host
("pstats-host", "localhost");

// The default port for PStats used to be 5180, but that's used by AIM.
ConfigVariableInt pstats_port
("pstats-port", 5185);

ConfigVariableDouble pstats_target_frame_rate
("pstats-target-frame-rate", 30.0);

// The rest are different in that they directly control the server,
// not the client.
ConfigVariableBool pstats_scroll_mode
("pstats-scroll-mode", true);
ConfigVariableDouble pstats_history
("pstats-history", 60.0);
ConfigVariableDouble pstats_average_time
("pstats-average-time", 3.0);

////////////////////////////////////////////////////////////////////
//     Function: init_libpstatclient
//  Description: Initializes the library.  This must be called at
//               least once before any of the functions or classes in
//               this library can be used.  Normally it will be
//               called by the static initializers and need not be
//               called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libpstatclient() {
  static bool initialized = false;
  if (initialized) {
    return;
  }
  initialized = true;
}

<|endoftext|>