<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/mmio/mmio.C $                                         */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,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                                                     */
#include <sys/mmio.h>
#include <devicefw/driverif.H>
#include <errl/errlentry.H>
#include <errl/errlmanager.H>
#include <errl/errludtarget.H>
#include <targeting/common/predicates/predicates.H>
#include <targeting/common/utilFilter.H>
#include <targeting/common/targetservice.H>
#include <arch/memorymap.H>
#include <arch/ppc.H>

#include "mmio.H"
#include <mmio/mmio.H>
#include <mmio/mmio_reasoncodes.H>

#include <p9a_mc_scom_addresses.H>
#include <p9a_mc_scom_addresses_fld.H>
#include <error_info_defs.H>

// Trace definition
trace_desc_t* g_trac_mmio = NULL;
TRAC_INIT(&g_trac_mmio, MMIO_COMP_NAME, 2*KILOBYTE, TRACE::BUFFER_SLOW);

#define OMI_PER_MC 8

namespace MMIO
{

// Helper function declarations (definitions at the bottom of this file)
static
TARGETING::TargetHandle_t getParentProc(TARGETING::TargetHandle_t i_target);
static
errlHndl_t getProcScom(TARGETING::TargetHandle_t i_target,
                       uint64_t i_scomAddr,
                       uint64_t &o_scomData);
static
errlHndl_t setProcScom(TARGETING::TargetHandle_t i_target,
                       uint64_t i_scomAddr,
                       uint64_t i_scomData);
static
void *mmio_memcpy(void *vdest, const void *vsrc, size_t len);


errlHndl_t mmioSetup()
{
    errlHndl_t l_err = nullptr;

    TRACFCOMP(g_trac_mmio, ENTER_MRK"mmioSetup");
    // called after OMI bars have been written to HW registers
    do
    {
        // map 8 OCMBs at a time, set MMIO_VM_ADDR on each OCMB
        //
        // loop through all the Memory Channels (MC Targets)
        //     call allocate of 32 GB virtual memory space with mmio_dev_map() for each MC
        TARGETING::TargetHandleList l_mcTargetList;
        getAllChiplets(l_mcTargetList, TARGETING::TYPE_MC);

        for (auto & l_mcTarget: l_mcTargetList)
        {
            uint32_t  l_mcChipUnit =
                              l_mcTarget->getAttr<TARGETING::ATTR_CHIP_UNIT>();

            // Get the base BAR address for OpenCapi Memory Interfaces (OMIs) of the this Memory Channel (MC)
            auto l_omiBaseAddr =
                  l_mcTarget->getAttr<TARGETING::ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET>();

            // Apply the MMIO base offset so we get the real address
            uint64_t  l_realAddr = ( l_omiBaseAddr | MMIO_BASE );

            // Map the device with a kernal call, each device, the MC,  is 32 GB
            uint64_t l_virtAddr = reinterpret_cast<uint64_t>
                         (mmio_dev_map(reinterpret_cast<void *>(l_realAddr),
                                       THIRTYTWO_GB));

            TRACFCOMP ( g_trac_mmio, "MC%.02x (0x%.08X) MMIO BAR PHYSICAL ADDR = 0x%lx     VIRTUAL ADDR = 0x%lx" ,
                        l_mcChipUnit ? 0x23 : 0x01, TARGETING::get_huid(l_mcTarget),
                        l_realAddr, l_virtAddr);

            // set VM_ADDR on each OCMB
            TARGETING::TargetHandleList l_omiTargetList;
            getChildChiplets(l_omiTargetList, l_mcTarget, TARGETING::TYPE_OMI);

            for (auto & l_omiTarget: l_omiTargetList)
            {
                // ATTR_CHIP_UNIT is relative to other OMI under this PROC
                uint32_t l_omiChipUnit =
                              l_omiTarget->getAttr<TARGETING::ATTR_CHIP_UNIT>();

                // Get the OMI position relative to other OMIs under its parent MC chiplet
                uint32_t l_omiPosRelativeToMc = l_omiChipUnit % OMI_PER_MC;

                // Calculate what we think the real address for this OCMB should be. This should
                // match what the ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET attribute is set to.

                // Each Memory Controller Channel (MCC) uses 8 GB of Memory Mapped IO, 4 GB for each of its child OCMBs.
                // Each OCMB has 2 MMIO distinct spaces that get mapped. The CONFIG space, and the MMIO space. The CONFIG
                // Space is always before the MMIO space we will treat that as the BAR for the OCMB target. These
                // paired OCMB spaces get interleaved as follows :
                //       ocmb  |  BAR ATTRIBUTE     | Type | Base reg           - end addr           | size | sub-ch
                //       +-----+--------------------+------+-----------------------------------------+------+-------
                //       ocmb0 | 0x0006030200000000 | cnfg | 0x0006030200000000 - 0x000603027FFFFFFF | 2GB  | 0
                //       ocmb1 | 0x0006030280000000 | cnfg | 0x0006030280000000 - 0x00060302FFFFFFFF | 2GB  | 1
                //       ocmb0 | N/A                | mmio | 0x0006030300000000 - 0x000603037FFFFFFF | 2GB  | 0
                //       ocmb1 | N/A                | mmio | 0x0006030380000000 - 0x00060303FFFFFFFF | 2GB  | 1
                //       +-----+--------------------+------+-----------------------------------------+------+-------

                // Calculate CNFG space BAR to write to OCMB attribute
                uint64_t l_currentOmiOffset = (( l_omiPosRelativeToMc / 2) * 8 * GIGABYTE) +
                                              (( l_omiPosRelativeToMc % 2) * 2 * GIGABYTE);

                // Calculated real address for this OMI is (BAR from MC attribute) + (currentOmiOffset)
                uint64_t l_calulatedRealAddr = l_omiBaseAddr + l_currentOmiOffset;

                // Grab bar value from attribute to verify it matches our calculations
                auto l_omiBarAttrVal = l_omiTarget->getAttr<TARGETING::ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET>();

                if(l_omiBarAttrVal != l_calulatedRealAddr)
                {
                    TRACFCOMP(g_trac_mmio,
                              "Discrepancy found between calculated OMI MMIO bar offset and what we found in ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET");
                    TRACFCOMP(g_trac_mmio, "Calculated Offset: 0x%lx,  Attribute Value : 0x%lx", l_calulatedRealAddr, l_omiBarAttrVal);

                    /*@
                    * @errortype   ERRORLOG::ERRL_SEV_UNRECOVERABLE
                    * @moduleid    MMIO::MOD_MMIO_SETUP
                    * @reasoncode  MMIO::RC_BAR_OFFSET_MISMATCH
                    * @userdata1   Calculated Bar Offset
                    * @userdata2   Bar offset from attribute
                    * @devdesc     mmioSetup> Mismatch between calculated map value
                    *              and what is in attribute xml
                    * @custdesc    Unexpected memory subsystem firmware error.
                    */
                    l_err = new ERRORLOG::ErrlEntry(
                                            ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                            MMIO::MOD_MMIO_SETUP,
                                            MMIO::RC_BAR_OFFSET_MISMATCH,
                                            l_calulatedRealAddr,
                                            l_omiBarAttrVal,
                                            ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
                    l_err->collectTrace( MMIO_COMP_NAME);
                    ERRORLOG::ErrlUserDetailsTarget(l_omiTarget).addToLog(l_err);

                    break;
                }


                uint64_t l_currentOmiVirtAddr = l_virtAddr + l_currentOmiOffset;

                // set VM_ADDR the associated OCMB
                TARGETING::TargetHandleList l_ocmbTargetList;
                getChildAffinityTargets(l_ocmbTargetList, l_omiTarget,
                                  TARGETING::CLASS_CHIP, TARGETING::TYPE_OCMB_CHIP);

                assert(l_ocmbTargetList.size() == 1 , "OCMB chips list found for a given OMI != 1 as expected");

                TRACFCOMP(g_trac_mmio, "Setting HUID 0x%.08X MMIO vm addr to be 0x%lx , real address is 0x%lx", TARGETING::get_huid(l_ocmbTargetList[0]),
                        l_currentOmiVirtAddr, l_calulatedRealAddr | MMIO_BASE );

                l_ocmbTargetList[0]->setAttr<TARGETING::ATTR_MMIO_VM_ADDR>(l_currentOmiVirtAddr);
            }
        }
    } while(0);

    TRACFCOMP(g_trac_mmio, EXIT_MRK"mmioSetup");

    return l_err;
}

// Direct OCMB reads and writes to the device's memory mapped memory.
DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
                      DeviceFW::MMIO,
                      TARGETING::TYPE_OCMB_CHIP,
                      ocmbMmioPerformOp);

errlHndl_t ocmbMmioPerformOp(DeviceFW::OperationType   i_opType,
                             TARGETING::TargetHandle_t i_target,
                             void*   io_buffer,
                             size_t& io_buflen,
                             int64_t i_accessType,
                             va_list i_args)
{
    errlHndl_t l_err         = nullptr;
    uint64_t   l_offset      = va_arg(i_args, uint64_t);
    uint64_t   l_accessLimit = va_arg(i_args, uint64_t);

    TRACDCOMP(g_trac_mmio, ENTER_MRK"ocmbMmioPerformOp");<commit_msg>Clean up traces and comments in MMIO driver<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/mmio/mmio.C $                                         */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,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                                                     */
#include <sys/mmio.h>
#include <devicefw/driverif.H>
#include <errl/errlentry.H>
#include <errl/errlmanager.H>
#include <errl/errludtarget.H>
#include <targeting/common/predicates/predicates.H>
#include <targeting/common/utilFilter.H>
#include <targeting/common/targetservice.H>
#include <arch/memorymap.H>
#include <arch/ppc.H>

#include "mmio.H"
#include <mmio/mmio.H>
#include <mmio/mmio_reasoncodes.H>

#include <p9a_mc_scom_addresses.H>
#include <p9a_mc_scom_addresses_fld.H>
#include <error_info_defs.H>

// Trace definition
trace_desc_t* g_trac_mmio = NULL;
TRAC_INIT(&g_trac_mmio, MMIO_COMP_NAME, 2*KILOBYTE, TRACE::BUFFER_SLOW);

#define OMI_PER_MC 8

namespace MMIO
{

// Helper function declarations (definitions at the bottom of this file)
static
TARGETING::TargetHandle_t getParentProc(TARGETING::TargetHandle_t i_target);
static
errlHndl_t getProcScom(TARGETING::TargetHandle_t i_target,
                       uint64_t i_scomAddr,
                       uint64_t &o_scomData);
static
errlHndl_t setProcScom(TARGETING::TargetHandle_t i_target,
                       uint64_t i_scomAddr,
                       uint64_t i_scomData);
static
void *mmio_memcpy(void *vdest, const void *vsrc, size_t len);


errlHndl_t mmioSetup()
{
    errlHndl_t l_err = nullptr;

    TRACFCOMP(g_trac_mmio, ENTER_MRK"mmioSetup");
    // called after OMI bars have been written to HW registers
    do
    {
        // map 8 OCMBs at a time, set MMIO_VM_ADDR on each OCMB
        //
        // loop through all the Memory Channels (MC Targets)
        //     call allocate of 32 GB virtual memory space with mmio_dev_map() for each MC
        TARGETING::TargetHandleList l_mcTargetList;
        getAllChiplets(l_mcTargetList, TARGETING::TYPE_MC);

        for (auto & l_mcTarget: l_mcTargetList)
        {
            uint32_t  l_mcChipUnit =
                              l_mcTarget->getAttr<TARGETING::ATTR_CHIP_UNIT>();

            // Get the base BAR address for OpenCapi Memory Interfaces (OMIs) of this Memory Controller (MC)
            auto l_omiBaseAddr =
                  l_mcTarget->getAttr<TARGETING::ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET>();

            // Apply the MMIO base offset so we get the real address
            uint64_t  l_realAddr = ( l_omiBaseAddr | MMIO_BASE );

            // Map the device with a kernal call, each device, the MC,  is 32 GB
            uint64_t l_virtAddr = reinterpret_cast<uint64_t>
                         (mmio_dev_map(reinterpret_cast<void *>(l_realAddr),
                                       THIRTYTWO_GB));

            TRACFCOMP ( g_trac_mmio, "MC%.02X (0x%.08X) MMIO BAR PHYSICAL ADDR = 0x%lX     VIRTUAL ADDR = 0x%lX" ,
                        l_mcChipUnit ? 0x23 : 0x01, TARGETING::get_huid(l_mcTarget),
                        l_realAddr, l_virtAddr);

            // set VM_ADDR on each OCMB
            TARGETING::TargetHandleList l_omiTargetList;
            getChildChiplets(l_omiTargetList, l_mcTarget, TARGETING::TYPE_OMI);

            for (auto & l_omiTarget: l_omiTargetList)
            {
                // ATTR_CHIP_UNIT is relative to other OMI under this PROC
                uint32_t l_omiChipUnit =
                              l_omiTarget->getAttr<TARGETING::ATTR_CHIP_UNIT>();

                // Get the OMI position relative to other OMIs under its parent MC chiplet
                uint32_t l_omiPosRelativeToMc = l_omiChipUnit % OMI_PER_MC;

                // Calculate what we think the real address for this OCMB should be. This should
                // match what the ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET attribute is set to.

                // Each Memory Controller Channel (MCC) uses 8 GB of Memory Mapped IO, 4 GB for each of its child OCMBs.
                // Each OCMB has 2 MMIO distinct spaces that get mapped. The CONFIG space, and the MMIO space. The CONFIG
                // Space is always before the MMIO space we will treat that as the BAR for the OCMB target. These
                // paired OCMB spaces get interleaved as follows :
                //       ocmb  |  BAR ATTRIBUTE     | Type | Base reg           - end addr           | size | sub-ch
                //       +-----+--------------------+------+-----------------------------------------+------+-------
                //       ocmb0 | 0x0006030200000000 | cnfg | 0x0006030200000000 - 0x000603027FFFFFFF | 2GB  | 0
                //       ocmb1 | 0x0006030280000000 | cnfg | 0x0006030280000000 - 0x00060302FFFFFFFF | 2GB  | 1
                //       ocmb0 | N/A                | mmio | 0x0006030300000000 - 0x000603037FFFFFFF | 2GB  | 0
                //       ocmb1 | N/A                | mmio | 0x0006030380000000 - 0x00060303FFFFFFFF | 2GB  | 1
                //       +-----+--------------------+------+-----------------------------------------+------+-------

                // Calculate CNFG space BAR to write to OCMB attribute
                uint64_t l_currentOmiOffset = (( l_omiPosRelativeToMc / 2) * 8 * GIGABYTE) +
                                              (( l_omiPosRelativeToMc % 2) * 2 * GIGABYTE);

                // Calculated real address for this OMI is (BAR from MC attribute) + (currentOmiOffset)
                uint64_t l_calulatedRealAddr = l_omiBaseAddr + l_currentOmiOffset;

                // Grab bar value from attribute to verify it matches our calculations
                auto l_omiBarAttrVal = l_omiTarget->getAttr<TARGETING::ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET>();

                if(l_omiBarAttrVal != l_calulatedRealAddr)
                {
                    TRACFCOMP(g_trac_mmio,
                              "Discrepancy found between calculated OMI MMIO bar offset and what we found in ATTR_OMI_INBAND_BAR_BASE_ADDR_OFFSET");
                    TRACFCOMP(g_trac_mmio, "Calculated Offset: 0x%lX,  Attribute Value : 0x%lX", l_calulatedRealAddr, l_omiBarAttrVal);

                    /*@
                    * @errortype   ERRORLOG::ERRL_SEV_UNRECOVERABLE
                    * @moduleid    MMIO::MOD_MMIO_SETUP
                    * @reasoncode  MMIO::RC_BAR_OFFSET_MISMATCH
                    * @userdata1   Calculated Bar Offset
                    * @userdata2   Bar offset from attribute
                    * @devdesc     mmioSetup> Mismatch between calculated map value
                    *              and what is in attribute xml
                    * @custdesc    Unexpected memory subsystem firmware error.
                    */
                    l_err = new ERRORLOG::ErrlEntry(
                                            ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                                            MMIO::MOD_MMIO_SETUP,
                                            MMIO::RC_BAR_OFFSET_MISMATCH,
                                            l_calulatedRealAddr,
                                            l_omiBarAttrVal,
                                            ERRORLOG::ErrlEntry::ADD_SW_CALLOUT);
                    l_err->collectTrace( MMIO_COMP_NAME);
                    ERRORLOG::ErrlUserDetailsTarget(l_omiTarget).addToLog(l_err);

                    break;
                }


                uint64_t l_currentOmiVirtAddr = l_virtAddr + l_currentOmiOffset;

                // set VM_ADDR the associated OCMB
                TARGETING::TargetHandleList l_ocmbTargetList;
                getChildAffinityTargets(l_ocmbTargetList, l_omiTarget,
                                  TARGETING::CLASS_CHIP, TARGETING::TYPE_OCMB_CHIP);

                assert(l_ocmbTargetList.size() == 1 , "OCMB chips list found for a given OMI != 1 as expected");

                TRACFCOMP(g_trac_mmio, "Setting HUID 0x%.08X MMIO vm addr to be 0x%lX , real address is 0x%lX", TARGETING::get_huid(l_ocmbTargetList[0]),
                        l_currentOmiVirtAddr, l_calulatedRealAddr | MMIO_BASE );

                l_ocmbTargetList[0]->setAttr<TARGETING::ATTR_MMIO_VM_ADDR>(l_currentOmiVirtAddr);
            }
        }
    } while(0);

    TRACFCOMP(g_trac_mmio, EXIT_MRK"mmioSetup");

    return l_err;
}

// Direct OCMB reads and writes to the device's memory mapped memory.
DEVICE_REGISTER_ROUTE(DeviceFW::WILDCARD,
                      DeviceFW::MMIO,
                      TARGETING::TYPE_OCMB_CHIP,
                      ocmbMmioPerformOp);

errlHndl_t ocmbMmioPerformOp(DeviceFW::OperationType   i_opType,
                             TARGETING::TargetHandle_t i_target,
                             void*   io_buffer,
                             size_t& io_buflen,
                             int64_t i_accessType,
                             va_list i_args)
{
    errlHndl_t l_err         = nullptr;
    uint64_t   l_offset      = va_arg(i_args, uint64_t);
    uint64_t   l_accessLimit = va_arg(i_args, uint64_t);

    TRACDCOMP(g_trac_mmio, ENTER_MRK"ocmbMmioPerformOp");
{'fraction_non_alphanumeric': 0.08650212289460178, 'fraction_numerical': 0.022675313768487845, 'mean_word_length': 1.4178228990411732, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 20, 'word_list_counts': {'cursed_substrings.json': 102, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4969082', 'n_tokens_mistral': 6439, 'n_tokens_neox': 5820, 'n_words': 1409}