<commit_before>/****************************************************************************
 *
 *   Copyright (C) 2015 Mark Charlebois. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/
/**
 * @file main.cpp
 * Basic shell to execute builtin "apps"
 *
 * @author Mark Charlebois <charlebm@gmail.com>
 * @author Roman Bapst <bapstroman@gmail.com>
 */

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include "apps.h"
#include "px4_middleware.h"
#include "DriverFramework.hpp"
#include <termios.h>

namespace px4
{
void init_once(void);
}

using namespace std;

typedef int (*px4_main_t)(int argc, char *argv[]);

#define CMD_BUFF_SIZE	100

static bool _ExitFlag = false;

static struct termios orig_term;

extern "C" {
	void _SigIntHandler(int sig_num);
	void _SigIntHandler(int sig_num)
	{
		cout.flush();
		cout << endl << "Exiting..." << endl;
		cout.flush();
		_ExitFlag = true;
	}
	void _SigFpeHandler(int sig_num);
	void _SigFpeHandler(int sig_num)
	{
		cout.flush();
		cout << endl << "floating point exception" << endl;
		PX4_BACKTRACE();
		cout.flush();
	}
}

static void print_prompt()
{
	cout.flush();
	cout << "pxh> ";
	cout.flush();
}

static void run_cmd(const vector<string> &appargs, bool exit_on_fail)
{
	// command is appargs[0]
	string command = appargs[0];

	if (apps.find(command) != apps.end()) {
		const char *arg[appargs.size() + 2];

		unsigned int i = 0;

		while (i < appargs.size() && appargs[i] != "") {
			arg[i] = (char *)appargs[i].c_str();
			++i;
		}

		arg[i] = (char *)0;

		cout << endl;

		int retval = apps[command](i, (char **)arg);

		if (retval) {
			cout << "Command '" << command << "' failed, returned " << retval << endl;

			if (exit_on_fail && retval) {
				exit(retval);
			}
		}

	} else if (command.compare("help") == 0) {
		list_builtins();

	} else if (command.length() == 0) {
		// Do nothing

	} else {
		cout << endl << "Invalid command: " << command << "\ntype 'help' for a list of commands" << endl;

	}
}

static void usage()
{

	cout << "./mainapp [-d] [startup_config] -h" << std::endl;
	cout << "   -d            - Optional flag to run the app in daemon mode and does not listen for user input." <<
	     std::endl;
	cout << "                   This is needed if mainapp is intended to be run as a upstart job on linux" << std::endl;
	cout << "<startup_config> - config file for starting/stopping px4 modules" << std::endl;
	cout << "   -h            - help/usage information" << std::endl;
}

static void process_line(string &line, bool exit_on_fail)
{
	if (line.length() == 0) {
		printf("\n");
	}

	vector<string> appargs(10);

	stringstream(line) >> appargs[0] >> appargs[1] >> appargs[2] >> appargs[3] >> appargs[4] >> appargs[5] >> appargs[6] >>
			   appargs[7] >> appargs[8] >> appargs[9];
	run_cmd(appargs, exit_on_fail);
}

static void restore_term(void)
{
	cout << "Restoring terminal\n";
	tcsetattr (0, TCSANOW, &orig_term);
}

int main(int argc, char **argv)
{
	bool daemon_mode = false;
	bool chroot_on = false;

	tcgetattr(0, &orig_term);
	atexit(restore_term);

	struct sigaction sig_int;
	memset(&sig_int, 0, sizeof(struct sigaction));
	sig_int.sa_handler = _SigIntHandler;
	sig_int.sa_flags = 0;// not SA_RESTART!;

	struct sigaction sig_fpe;
	memset(&sig_fpe, 0, sizeof(struct sigaction));
	sig_fpe.sa_handler = _SigFpeHandler;
	sig_fpe.sa_flags = 0;// not SA_RESTART!;

	sigaction(SIGINT, &sig_int, NULL);
	//sigaction(SIGTERM, &sig_int, NULL);
	sigaction(SIGFPE, &sig_fpe, NULL);

	int index = 1;
	char *commands_file = nullptr;

	while (index < argc) {
		if (argv[index][0] == '-') {
			// the arg starts with -
			if (strcmp(argv[index], "-d") == 0) {
				daemon_mode = true;

			} else if (strcmp(argv[index], "-h") == 0) {
				usage();
				return 0;

			} else if (strcmp(argv[index], "-c") == 0) {
				chroot_on = true;

			} else {
				PX4_WARN("Unknown/unhandled parameter: %s", argv[index]);
				return 1;
			}

		} else {
			// this is an argument that does not have '-' prefix; treat it like a file name
			ifstream infile(argv[index]);

			if (infile.good()) {
				infile.close();
				commands_file = argv[index];

			} else {
				PX4_WARN("Error opening file: %s", argv[index]);
				return -1;
			}
		}

		++index;
	}

	DriverFramework::Framework::initialize();
	px4::init_once();

	px4::init(argc, argv, "mainapp");

	// if commandfile is present, process the commands from the file
	if (commands_file != nullptr) {
		ifstream infile(commands_file);

		if (infile.is_open()) {
			for (string line; getline(infile, line, '\n');) {
				// TODO: this should be true but for that we have to check all startup files
				process_line(line, false);
			}

		} else {
			PX4_WARN("Error opening file: %s", commands_file);
		}
	}

	if (chroot_on) {
		// Lock this application in the current working dir
		// this is not an attempt to secure the environment,
		// rather, to replicate a deployed file system.

#ifdef PATH_MAX
		const unsigned path_max_len = PATH_MAX;
#else
		const unsigned path_max_len = 1024;
#endif

		char pwd_path[path_max_len];
		const char *folderpath = "/rootfs/";

		if (nullptr == getcwd(pwd_path, sizeof(pwd_path))) {
			PX4_ERR("Failed acquiring working dir, abort.");
			exit(1);
		}

		if (nullptr == strcat(pwd_path, folderpath)) {
			PX4_ERR("Failed completing path, abort.");
			exit(1);
		}

		if (chroot(pwd_path)) {
			PX4_ERR("Failed chrooting application, path: %s, error: %s.", pwd_path, strerror(errno));
			exit(1);
		}

		if (chdir("/")) {
			PX4_ERR("Failed changing to root dir, path: %s, error: %s.", pwd_path, strerror(errno));
			exit(1);
		}
	}

	if (!daemon_mode) {
		string mystr = "";
		string string_buffer[CMD_BUFF_SIZE];
		int buf_ptr_write = 0;
		int buf_ptr_read = 0;

		print_prompt();

		// change input mode so that we can manage shell
		struct termios term;
		tcgetattr(0, &term);
		term.c_lflag &= ~ICANON;
		term.c_lflag &= ~ECHO;
		tcsetattr(0, TCSANOW, &term);
		setbuf(stdin, NULL);

		while (!_ExitFlag) {

			char c = getchar();

			switch (c) {
			case 127:	// backslash
				if (mystr.length() > 0) {
					mystr.pop_back();
					printf("%c[2K", 27);	// clear line
					cout << (char)13;
					print_prompt();
					cout << mystr;
				}

				break;

			case'\n':	// user hit enter
				if (buf_ptr_write == CMD_BUFF_SIZE) {
					buf_ptr_write = 0;
				}

				if (buf_ptr_write > 0) {
					if (mystr != string_buffer[buf_ptr_write - 1]) {
						string_buffer[buf_ptr_write] = mystr;
						buf_ptr_write++;
					}

				} else {
					if (mystr != string_buffer[CMD_BUFF_SIZE - 1]) {
						string_buffer[buf_ptr_write] = mystr;
						buf_ptr_write++;
					}
				}

				process_line(mystr, false);
				mystr = "";
				buf_ptr_read = buf_ptr_write;

				print_prompt();
				break;

			case '\033': {	// arrow keys
					c = getchar();	// skip first one, does not have the info
					c = getchar();

					// arrow up
					if (c == 'A') {
						buf_ptr_read--;
						// arrow down

					} else if (c == 'B') {
						if (buf_ptr_read < buf_ptr_write) {
							buf_ptr_read++;
						}

					} else {
						// TODO: Support editing current line
					}

					if (buf_ptr_read < 0) {
						buf_ptr_read = 0;
					}

					string saved_cmd = string_buffer[buf_ptr_read];
					printf("%c[2K", 27);
					cout << (char)13;
					mystr = saved_cmd;
					print_prompt();
					cout << mystr;
					break;
				}

			default:	// any other input
				cout << c;
				mystr += c;
				break;
			}
		}

	} else {
		while (!_ExitFlag) {
			usleep(100000);
		}
	}

	// TODO: Always try to stop muorb for QURT because px4_task_is_running doesn't seem to work.
	if (true) {
	//if (px4_task_is_running("muorb")) {
		// sending muorb stop is needed if it is running to exit cleanly
		vector<string> muorb_stop_cmd = { "muorb", "stop" };
		run_cmd(muorb_stop_cmd, !daemon_mode);
	}

	vector<string> shutdown_cmd = { "shutdown" };
	run_cmd(shutdown_cmd, true);
	DriverFramework::Framework::shutdown();

	return OK;
}
<commit_msg>POSIX main: astyle<commit_after>/****************************************************************************
 *
 *   Copyright (C) 2015 Mark Charlebois. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/
/**
 * @file main.cpp
 * Basic shell to execute builtin "apps"
 *
 * @author Mark Charlebois <charlebm@gmail.com>
 * @author Roman Bapst <bapstroman@gmail.com>
 */

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include "apps.h"
#include "px4_middleware.h"
#include "DriverFramework.hpp"
#include <termios.h>

namespace px4
{
void init_once(void);
}

using namespace std;

typedef int (*px4_main_t)(int argc, char *argv[]);

#define CMD_BUFF_SIZE	100

static bool _ExitFlag = false;

static struct termios orig_term;

extern "C" {
	void _SigIntHandler(int sig_num);
	void _SigIntHandler(int sig_num)
	{
		cout.flush();
		cout << endl << "Exiting..." << endl;
		cout.flush();
		_ExitFlag = true;
	}
	void _SigFpeHandler(int sig_num);
	void _SigFpeHandler(int sig_num)
	{
		cout.flush();
		cout << endl << "floating point exception" << endl;
		PX4_BACKTRACE();
		cout.flush();
	}
}

static void print_prompt()
{
	cout.flush();
	cout << "pxh> ";
	cout.flush();
}

static void run_cmd(const vector<string> &appargs, bool exit_on_fail)
{
	// command is appargs[0]
	string command = appargs[0];

	if (apps.find(command) != apps.end()) {
		const char *arg[appargs.size() + 2];

		unsigned int i = 0;

		while (i < appargs.size() && appargs[i] != "") {
			arg[i] = (char *)appargs[i].c_str();
			++i;
		}

		arg[i] = (char *)0;

		cout << endl;

		int retval = apps[command](i, (char **)arg);

		if (retval) {
			cout << "Command '" << command << "' failed, returned " << retval << endl;

			if (exit_on_fail && retval) {
				exit(retval);
			}
		}

	} else if (command.compare("help") == 0) {
		list_builtins();

	} else if (command.length() == 0) {
		// Do nothing

	} else {
		cout << endl << "Invalid command: " << command << "\ntype 'help' for a list of commands" << endl;

	}
}

static void usage()
{

	cout << "./mainapp [-d] [startup_config] -h" << std::endl;
	cout << "   -d            - Optional flag to run the app in daemon mode and does not listen for user input." <<
	     std::endl;
	cout << "                   This is needed if mainapp is intended to be run as a upstart job on linux" << std::endl;
	cout << "<startup_config> - config file for starting/stopping px4 modules" << std::endl;
	cout << "   -h            - help/usage information" << std::endl;
}

static void process_line(string &line, bool exit_on_fail)
{
	if (line.length() == 0) {
		printf("\n");
	}

	vector<string> appargs(10);

	stringstream(line) >> appargs[0] >> appargs[1] >> appargs[2] >> appargs[3] >> appargs[4] >> appargs[5] >> appargs[6] >>
			   appargs[7] >> appargs[8] >> appargs[9];
	run_cmd(appargs, exit_on_fail);
}

static void restore_term(void)
{
	cout << "Restoring terminal\n";
	tcsetattr(0, TCSANOW, &orig_term);
}

int main(int argc, char **argv)
{
	bool daemon_mode = false;
	bool chroot_on = false;

	tcgetattr(0, &orig_term);
	atexit(restore_term);

	struct sigaction sig_int;
	memset(&sig_int, 0, sizeof(struct sigaction));
	sig_int.sa_handler = _SigIntHandler;
	sig_int.sa_flags = 0;// not SA_RESTART!;

	struct sigaction sig_fpe;
	memset(&sig_fpe, 0, sizeof(struct sigaction));
	sig_fpe.sa_handler = _SigFpeHandler;
	sig_fpe.sa_flags = 0;// not SA_RESTART!;

	sigaction(SIGINT, &sig_int, NULL);
	//sigaction(SIGTERM, &sig_int, NULL);
	sigaction(SIGFPE, &sig_fpe, NULL);

	int index = 1;
	char *commands_file = nullptr;

	while (index < argc) {
		if (argv[index][0] == '-') {
			// the arg starts with -
			if (strcmp(argv[index], "-d") == 0) {
				daemon_mode = true;

			} else if (strcmp(argv[index], "-h") == 0) {
				usage();
				return 0;

			} else if (strcmp(argv[index], "-c") == 0) {
				chroot_on = true;

			} else {
				PX4_WARN("Unknown/unhandled parameter: %s", argv[index]);
				return 1;
			}

		} else {
			// this is an argument that does not have '-' prefix; treat it like a file name
			ifstream infile(argv[index]);

			if (infile.good()) {
				infile.close();
				commands_file = argv[index];

			} else {
				PX4_WARN("Error opening file: %s", argv[index]);
				return -1;
			}
		}

		++index;
	}

	DriverFramework::Framework::initialize();
	px4::init_once();

	px4::init(argc, argv, "mainapp");

	// if commandfile is present, process the commands from the file
	if (commands_file != nullptr) {
		ifstream infile(commands_file);

		if (infile.is_open()) {
			for (string line; getline(infile, line, '\n');) {
				// TODO: this should be true but for that we have to check all startup files
				process_line(line, false);
			}

		} else {
			PX4_WARN("Error opening file: %s", commands_file);
		}
	}

	if (chroot_on) {
		// Lock this application in the current working dir
		// this is not an attempt to secure the environment,
		// rather, to replicate a deployed file system.

#ifdef PATH_MAX
		const unsigned path_max_len = PATH_MAX;
#else
		const unsigned path_max_len = 1024;
#endif

		char pwd_path[path_max_len];
		const char *folderpath = "/rootfs/";

		if (nullptr == getcwd(pwd_path, sizeof(pwd_path))) {
			PX4_ERR("Failed acquiring working dir, abort.");
			exit(1);
		}

		if (nullptr == strcat(pwd_path, folderpath)) {
			PX4_ERR("Failed completing path, abort.");
			exit(1);
		}

		if (chroot(pwd_path)) {
			PX4_ERR("Failed chrooting application, path: %s, error: %s.", pwd_path, strerror(errno));
			exit(1);
		}

		if (chdir("/")) {
			PX4_ERR("Failed changing to root dir, path: %s, error: %s.", pwd_path, strerror(errno));
			exit(1);
		}
	}

	if (!daemon_mode) {
		string mystr = "";
		string string_buffer[CMD_BUFF_SIZE];
		int buf_ptr_write = 0;
		int buf_ptr_read = 0;

		print_prompt();

		// change input mode so that we can manage shell
		struct termios term;
		tcgetattr(0, &term);
		term.c_lflag &= ~ICANON;
		term.c_lflag &= ~ECHO;
		tcsetattr(0, TCSANOW, &term);
		setbuf(stdin, NULL);

		while (!_ExitFlag) {

			char c = getchar();

			switch (c) {
			case 127:	// backslash
				if (mystr.length() > 0) {
					mystr.pop_back();
					printf("%c[2K", 27);	// clear line
					cout << (char)13;
					print_prompt();
					cout << mystr;
				}

				break;

			case'\n':	// user hit enter
				if (buf_ptr_write == CMD_BUFF_SIZE) {
					buf_ptr_write = 0;
				}

				if (buf_ptr_write > 0) {
					if (mystr != string_buffer[buf_ptr_write - 1]) {
						string_buffer[buf_ptr_write] = mystr;
						buf_ptr_write++;
					}

				} else {
					if (mystr != string_buffer[CMD_BUFF_SIZE - 1]) {
						string_buffer[buf_ptr_write] = mystr;
						buf_ptr_write++;
					}
				}

				process_line(mystr, false);
				mystr = "";
				buf_ptr_read = buf_ptr_write;

				print_prompt();
				break;

			case '\033': {	// arrow keys
					c = getchar();	// skip first one, does not have the info
					c = getchar();

					// arrow up
					if (c == 'A') {
						buf_ptr_read--;
						// arrow down

					} else if (c == 'B') {
						if (buf_ptr_read < buf_ptr_write) {
							buf_ptr_read++;
						}

					} else {
						// TODO: Support editing current line
					}

					if (buf_ptr_read < 0) {
						buf_ptr_read = 0;
					}

					string saved_cmd = string_buffer[buf_ptr_read];
					printf("%c[2K", 27);
					cout << (char)13;
					mystr = saved_cmd;
					print_prompt();
					cout << mystr;
					break;
				}

			default:	// any other input
				cout << c;
				mystr += c;
				break;
			}
		}

	} else {
		while (!_ExitFlag) {
			usleep(100000);
		}
	}

	// TODO: Always try to stop muorb for QURT because px4_task_is_running doesn't seem to work.
	if (true) {
		//if (px4_task_is_running("muorb")) {
		// sending muorb stop is needed if it is running to exit cleanly
		vector<string> muorb_stop_cmd = { "muorb", "stop" };
		run_cmd(muorb_stop_cmd, !daemon_mode);
	}

	vector<string> shutdown_cmd = { "shutdown" };
	run_cmd(shutdown_cmd, true);
	DriverFramework::Framework::shutdown();

	return OK;
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/cache/p9_hcd_cache_stopclocks.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_hcd_cache_stopclocks.C
/// @brief Quad Clock Stop
///
/// Procedure Summary:

// *HWP HWP Owner          : David Du       <daviddu@us.ibm.com>
// *HWP Backup HWP Owner   : Greg Still     <stillgs@us.ibm.com>
// *HWP FW Owner           : Sangeetha T S  <sangeet2@in.ibm.com>
// *HWP Team               : PM
// *HWP Consumed by        : HB:PERV
// *HWP Level              : 2

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include <p9_misc_scom_addresses.H>
#include <p9_quad_scom_addresses.H>
#include <p9_hcd_common.H>
#include <p9_common_clk_ctrl_state.H>
#include "p9_hcd_l2_stopclocks.H"
#include "p9_hcd_cache_stopclocks.H"

//------------------------------------------------------------------------------
// Constant Definitions
//------------------------------------------------------------------------------

enum P9_HCD_CACHE_STOPCLOCKS_CONSTANTS
{
    CACHE_CLK_STOP_POLLING_HW_NS_DELAY     = 10000,
    CACHE_CLK_STOP_POLLING_SIM_CYCLE_DELAY = 320000,
    PB_PURGE_CACHE_STOP_POLLING_DELAY_HW_MILLISEC = 1000000ULL, // 1msec
    PB_PURGE_CACHE_STOP_POLLING_DELAY_SIM_CYCLES = 10000ULL,
    PB_PURGE_CACHE_STOP_POLLING_TIMEOUT = 10,
};

//------------------------------------------------------------------------------
// Procedure: Quad Clock Stop
//------------------------------------------------------------------------------

fapi2::ReturnCode
p9_hcd_cache_stopclocks(
    const fapi2::Target<fapi2::TARGET_TYPE_EQ>& i_target,
    const p9hcd::P9_HCD_CLK_CTRL_CONSTANTS      i_select_regions,
    const p9hcd::P9_HCD_EX_CTRL_CONSTANTS       i_select_ex)
{
    FAPI_INF(">>p9_hcd_cache_stopclocks: regions[%016llx] ex[%d]",
             i_select_regions, i_select_ex);
    fapi2::ReturnCode                              l_rc;
    fapi2::buffer<uint64_t>                        l_data64;
    fapi2::buffer<uint64_t>                        l_temp64;
    uint64_t                                       l_l3mask_pscom = 0;
    uint32_t                                       l_loops1ms;
    uint8_t                                        l_attr_chip_unit_pos = 0;
    uint8_t                                        l_attr_vdm_enable;
    uint8_t                                        l_is_mpipl = 0x0;
    const fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> l_sys;
    auto l_perv = i_target.getParent<fapi2::TARGET_TYPE_PERV>();
    auto l_chip = i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IS_MPIPL, l_sys, l_is_mpipl));

    if(l_is_mpipl)
    {
        // PB_PURGE related SCOMs should be added to the beginning of
        // p9_hcd_cache_stopclocks, these scoms should only be done if the clock
        // region including PBIEQ clock domain is being stopped, which
        // incidentally should always be the case for MPIPL
        l_data64.flush<0>();
        l_data64.setBit<30>();
        // Set bit 30 in EQ_QPPM_QCCR_SCOM2(100F01BF) Reg, Pulse to the
        // Powerbus logic in the Cache clock domain to request them to purge
        // their async buffers in preparation to power off the Quad
        FAPI_TRY(fapi2::putScom(i_target, EQ_QPPM_QCCR_SCOM2, l_data64));

        l_data64.flush<0>();
        uint32_t l_timeout = PB_PURGE_CACHE_STOP_POLLING_TIMEOUT;

        do
        {
            // Acknowledgement from Powerbus that the buffers are empty
            // and can safely be fenced & clocked off.
            FAPI_TRY(fapi2::getScom(i_target, EQ_QPPM_QCCR_SCOM, l_data64));
            bool l_poll_data = l_data64.getBit<31>();

            if(l_poll_data == 1)
            {
                break;
            }

            FAPI_TRY(fapi2::delay(PB_PURGE_CACHE_STOP_POLLING_DELAY_HW_MILLISEC,
                                  PB_PURGE_CACHE_STOP_POLLING_DELAY_SIM_CYCLES),
                     "Error from delay"); //1msec delay
        }
        while(--l_timeout != 0);

        // Error if Timeout happens
        FAPI_ASSERT((l_timeout != 0),
                    fapi2::QPPM_QCCR_PB_PURGE_DONE_LVL_TIMEOUT()
                    .set_TARGET(i_target)
                    .set_EQPPMQCCR(l_data64),
                    "QPPM_QCCR_PB_PURGE_DONE_LVL Reg bit 31 not set.");

        l_data64.flush<0>();
        l_data64.setBit<30>();
        FAPI_TRY(fapi2::putScom(i_target, EQ_QPPM_QCCR_SCOM1, l_data64));
    }

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_VDM_ENABLE,    l_sys,
                           l_attr_vdm_enable));
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, l_perv,
                           l_attr_chip_unit_pos));
//  l_attr_chip_unit_pos = l_attr_chip_unit_pos - p9hcd::PERV_TO_QUAD_POS_OFFSET;
    l_attr_chip_unit_pos = l_attr_chip_unit_pos - 0x10;

    if (i_select_regions & p9hcd::CLK_REGION_EX0_L3)
    {
        l_l3mask_pscom |= (BIT64(4) | BIT64(6) | BIT64(8));
    }

    if (i_select_regions & p9hcd::CLK_REGION_EX1_L3)
    {
        l_l3mask_pscom |= (BIT64(5) | BIT64(7) | BIT64(9));
    }

    // -----------------------------
    // Prepare to stop cache clocks
    // -----------------------------
    FAPI_DBG("Check PM_RESET_STATE_INDICATOR via GPMMR[15]");
    FAPI_TRY(getScom(i_target, EQ_PPM_GPMMR_SCOM, l_data64));

    if (!l_data64.getBit<15>())
    {
        FAPI_DBG("Gracefully turn off power management, if fail, continue anyways");
        /// @todo RTC158181 suspend_pm()
    }

    FAPI_DBG("Check cache clock controller status");
    l_rc = p9_common_clk_ctrl_state<fapi2::TARGET_TYPE_EQ>(i_target);

    if (l_rc)
    {
        FAPI_INF("Clock controller of this cache chiplet is inaccessible, return");
        goto fapi_try_exit;
    }

    FAPI_DBG("Check PERV clock status for access to CME via CLOCK_STAT[4]");
    FAPI_TRY(getScom(i_target, EQ_CLOCK_STAT_SL, l_data64));

    FAPI_DBG("Check PERV fence status for access to CME via CPLT_CTRL1[4]");
    FAPI_TRY(getScom(i_target, EQ_CPLT_CTRL1, l_temp64));

    if (l_data64.getBit<4>() == 0 && l_temp64.getBit<4>() == 0)
    {
        /// @todo RTC158181 disable l2 snoop? disable lco? assert refresh quiesce?
        FAPI_DBG("Assert L3 pscom masks via RING_FENCE_MASK_LATCH_REG[4-9]");
        FAPI_TRY(putScom(i_target, EQ_RING_FENCE_MASK_LATCH_REG, l_l3mask_pscom));
    }

    FAPI_DBG("Assert chiplet fence via NET_CTRL0[18]");
    FAPI_TRY(putScom(i_target, EQ_NET_CTRL0_WOR, MASK_SET(18)));

    // -------------------------------
    // Stop L2 clocks
    // -------------------------------

    if (i_select_ex)
        FAPI_EXEC_HWP(fapi2::current_err,
                      p9_hcd_l2_stopclocks,
                      i_target, i_select_ex);

    // -------------------------------
    // Stop cache clocks
    // -------------------------------

    FAPI_DBG("Clear all SCAN_REGION_TYPE bits");
    FAPI_TRY(putScom(i_target, EQ_SCAN_REGION_TYPE, MASK_ZERO));

    FAPI_DBG("Stop cache clocks via CLK_REGION");
    l_data64 = (p9hcd::CLK_STOP_CMD  |
                i_select_regions     |
                p9hcd::CLK_THOLD_ALL);
    FAPI_TRY(putScom(i_target, EQ_CLK_REGION, l_data64));

    FAPI_DBG("Poll for cache clocks stopped via CPLT_STAT0[8]");
    l_loops1ms = 1E6 / CACHE_CLK_STOP_POLLING_HW_NS_DELAY;

    do
    {
        fapi2::delay(CACHE_CLK_STOP_POLLING_HW_NS_DELAY,
                     CACHE_CLK_STOP_POLLING_SIM_CYCLE_DELAY);

        FAPI_TRY(getScom(i_target, EQ_CPLT_STAT0, l_data64));
    }
    while((l_data64.getBit<8>() != 1) && ((--l_loops1ms) != 0));

    FAPI_ASSERT((l_loops1ms != 0),
                fapi2::PMPROC_CACHECLKSTOP_TIMEOUT().set_EQCPLTSTAT(l_data64),
                "Cache Clock Stop Timeout");

    FAPI_DBG("Check cache clocks stopped");
    FAPI_TRY(getScom(i_target, EQ_CLOCK_STAT_SL, l_data64));

    FAPI_ASSERT((((~l_data64) & i_select_regions) == 0),
                fapi2::PMPROC_CACHECLKSTOP_FAILED().set_EQCLKSTAT(l_data64),
                "Cache Clock Stop Failed");
    FAPI_DBG("Cache clocks stopped now");

    // -------------------------------
    // Fence up
    // -------------------------------

    FAPI_DBG("Assert vital fence via CPLT_CTRL1[3]");
    FAPI_TRY(putScom(i_target, EQ_CPLT_CTRL1_OR, MASK_SET(3)));

    FAPI_DBG("Assert regional fences via CPLT_CTRL1[4-14]");
    FAPI_TRY(putScom(i_target, EQ_CPLT_CTRL1_OR, i_select_regions));

    // -------------------------------
    // Disable VDM
    // -------------------------------

    if (l_attr_vdm_enable == fapi2::ENUM_ATTR_VDM_ENABLE_ON)
    {
        FAPI_DBG("Drop vdm enable via QPPM_VDMCR[0]");
        FAPI_TRY(putScom(i_target, EQ_PPM_VDMCR_CLEAR, MASK_SET(0)));
    }

    // -------------------------------
    // Shutdown edram
    // -------------------------------
    // QCCR[0/4] EDRAM_ENABLE_DC
    // QCCR[1/5] EDRAM_VWL_ENABLE_DC
    // QCCR[2/6] L3_EX0/1_EDRAM_VROW_VBLH_ENABLE_DC
    // QCCR[3/7] EDRAM_VPP_ENABLE_DC

    if (i_select_regions & p9hcd::CLK_REGION_EX0_REFR)
    {
        FAPI_DBG("Sequence EX0 EDRAM disables via QPPM_QCCR[0-3]");
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(3)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(2)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(1)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(0)));
    }

    if (i_select_regions & p9hcd::CLK_REGION_EX1_REFR)
    {
        FAPI_DBG("Sequence EX1 EDRAM disables via QPPM_QCCR[4-7]");
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(7)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(6)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(5)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(4)));
    }

    // -------------------------------
    // Update QSSR and STOP history
    // -------------------------------

    FAPI_DBG("Set cache as stopped in QSSR");
    FAPI_TRY(putScom(l_chip, PU_OCB_OCI_QSSR_OR,
                     BIT64(l_attr_chip_unit_pos + 14)));

    FAPI_DBG("Set cache as stopped in STOP history register");
    FAPI_TRY(putScom(i_target, EQ_PPM_SSHSRC, BIT64(0)));

fapi_try_exit:

    FAPI_INF("<<p9_hcd_cache_stopclocks");
    return fapi2::current_err;
}
<commit_msg>HW405243/IPL: Assert/drop pcb_mux_disable around quad power off<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/cache/p9_hcd_cache_stopclocks.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_hcd_cache_stopclocks.C
/// @brief Quad Clock Stop
///
/// Procedure Summary:

// *HWP HWP Owner          : David Du       <daviddu@us.ibm.com>
// *HWP Backup HWP Owner   : Greg Still     <stillgs@us.ibm.com>
// *HWP FW Owner           : Sangeetha T S  <sangeet2@in.ibm.com>
// *HWP Team               : PM
// *HWP Consumed by        : HB:PERV
// *HWP Level              : 2

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include <p9_misc_scom_addresses.H>
#include <p9_quad_scom_addresses.H>
#include <p9_hcd_common.H>
#include <p9_common_clk_ctrl_state.H>
#include "p9_hcd_l2_stopclocks.H"
#include "p9_hcd_cache_stopclocks.H"

//------------------------------------------------------------------------------
// Constant Definitions
//------------------------------------------------------------------------------

enum P9_HCD_CACHE_STOPCLOCKS_CONSTANTS
{
    CACHE_CLK_STOP_POLLING_HW_NS_DELAY     = 10000,
    CACHE_CLK_STOP_POLLING_SIM_CYCLE_DELAY = 320000,
    PB_PURGE_CACHE_STOP_POLLING_DELAY_HW_MILLISEC = 1000000ULL, // 1msec
    PB_PURGE_CACHE_STOP_POLLING_DELAY_SIM_CYCLES = 10000ULL,
    PB_PURGE_CACHE_STOP_POLLING_TIMEOUT = 10,
};

//------------------------------------------------------------------------------
// Procedure: Quad Clock Stop
//------------------------------------------------------------------------------

fapi2::ReturnCode
p9_hcd_cache_stopclocks(
    const fapi2::Target<fapi2::TARGET_TYPE_EQ>& i_target,
    const p9hcd::P9_HCD_CLK_CTRL_CONSTANTS      i_select_regions,
    const p9hcd::P9_HCD_EX_CTRL_CONSTANTS       i_select_ex)
{
    FAPI_INF(">>p9_hcd_cache_stopclocks: regions[%016llx] ex[%d]",
             i_select_regions, i_select_ex);
    fapi2::ReturnCode                              l_rc;
    fapi2::buffer<uint64_t>                        l_data64;
    fapi2::buffer<uint64_t>                        l_temp64;
    uint64_t                                       l_l3mask_pscom              = 0;
    uint32_t                                       l_loops1ms                  = 0;
    uint32_t                                       l_scom_addr                 = 0;
    uint8_t                                        l_attr_chip_unit_pos        = 0;
    uint8_t                                        l_attr_vdm_enable           = 0;
    uint8_t                                        l_is_mpipl                  = 0;
    const fapi2::Target<fapi2::TARGET_TYPE_SYSTEM> l_sys;
    auto l_perv = i_target.getParent<fapi2::TARGET_TYPE_PERV>();
    auto l_chip = i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();
    auto l_core_functional_vector =
        i_target.getChildren<fapi2::TARGET_TYPE_CORE>
        (fapi2::TARGET_STATE_FUNCTIONAL);

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_IS_MPIPL, l_sys, l_is_mpipl));

    if(l_is_mpipl)
    {
        // PB_PURGE related SCOMs should be added to the beginning of
        // p9_hcd_cache_stopclocks, these scoms should only be done if the clock
        // region including PBIEQ clock domain is being stopped, which
        // incidentally should always be the case for MPIPL
        l_data64.flush<0>();
        l_data64.setBit<30>();
        // Set bit 30 in EQ_QPPM_QCCR_SCOM2(100F01BF) Reg, Pulse to the
        // Powerbus logic in the Cache clock domain to request them to purge
        // their async buffers in preparation to power off the Quad
        FAPI_TRY(fapi2::putScom(i_target, EQ_QPPM_QCCR_SCOM2, l_data64));

        l_data64.flush<0>();
        uint32_t l_timeout = PB_PURGE_CACHE_STOP_POLLING_TIMEOUT;

        do
        {
            // Acknowledgement from Powerbus that the buffers are empty
            // and can safely be fenced & clocked off.
            FAPI_TRY(fapi2::getScom(i_target, EQ_QPPM_QCCR_SCOM, l_data64));
            bool l_poll_data = l_data64.getBit<31>();

            if(l_poll_data == 1)
            {
                break;
            }

            FAPI_TRY(fapi2::delay(PB_PURGE_CACHE_STOP_POLLING_DELAY_HW_MILLISEC,
                                  PB_PURGE_CACHE_STOP_POLLING_DELAY_SIM_CYCLES),
                     "Error from delay"); //1msec delay
        }
        while(--l_timeout != 0);

        // Error if Timeout happens
        FAPI_ASSERT((l_timeout != 0),
                    fapi2::QPPM_QCCR_PB_PURGE_DONE_LVL_TIMEOUT()
                    .set_TARGET(i_target)
                    .set_EQPPMQCCR(l_data64),
                    "QPPM_QCCR_PB_PURGE_DONE_LVL Reg bit 31 not set.");

        l_data64.flush<0>();
        l_data64.setBit<30>();
        FAPI_TRY(fapi2::putScom(i_target, EQ_QPPM_QCCR_SCOM1, l_data64));
    }

    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_VDM_ENABLE,    l_sys,
                           l_attr_vdm_enable));
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, l_perv,
                           l_attr_chip_unit_pos));
//  l_attr_chip_unit_pos = l_attr_chip_unit_pos - p9hcd::PERV_TO_QUAD_POS_OFFSET;
    l_attr_chip_unit_pos = l_attr_chip_unit_pos - 0x10;

    if (i_select_regions & p9hcd::CLK_REGION_EX0_L3)
    {
        l_l3mask_pscom |= (BIT64(4) | BIT64(6) | BIT64(8));
    }

    if (i_select_regions & p9hcd::CLK_REGION_EX1_L3)
    {
        l_l3mask_pscom |= (BIT64(5) | BIT64(7) | BIT64(9));
    }

    // -----------------------------
    // Prepare to stop cache clocks
    // -----------------------------
    FAPI_DBG("Check PM_RESET_STATE_INDICATOR via GPMMR[15]");
    FAPI_TRY(getScom(i_target, EQ_PPM_GPMMR_SCOM, l_data64));

    if (!l_data64.getBit<15>())
    {
        FAPI_DBG("Gracefully turn off power management, if fail, continue anyways");
        /// @todo RTC158181 suspend_pm()
    }

    FAPI_DBG("Check cache clock controller status");
    l_rc = p9_common_clk_ctrl_state<fapi2::TARGET_TYPE_EQ>(i_target);

    if (l_rc)
    {
        FAPI_INF("Clock controller of this cache chiplet is inaccessible, return");
        goto fapi_try_exit;
    }

    FAPI_DBG("Check PERV clock status for access to CME via CLOCK_STAT[4]");
    FAPI_TRY(getScom(i_target, EQ_CLOCK_STAT_SL, l_data64));

    FAPI_DBG("Check PERV fence status for access to CME via CPLT_CTRL1[4]");
    FAPI_TRY(getScom(i_target, EQ_CPLT_CTRL1, l_temp64));

    if (l_data64.getBit<4>() == 0 && l_temp64.getBit<4>() == 0)
    {
        /// @todo RTC158181 disable l2 snoop? disable lco? assert refresh quiesce?
        FAPI_DBG("Assert L3 pscom masks via RING_FENCE_MASK_LATCH_REG[4-9]");
        FAPI_TRY(putScom(i_target, EQ_RING_FENCE_MASK_LATCH_REG, l_l3mask_pscom));
    }

    FAPI_DBG("Assert chiplet fence via NET_CTRL0[18]");
    FAPI_TRY(putScom(i_target, EQ_NET_CTRL0_WOR, MASK_SET(18)));

    // -------------------------------
    // Stop L2 clocks
    // -------------------------------

    if (i_select_ex)
        FAPI_EXEC_HWP(fapi2::current_err,
                      p9_hcd_l2_stopclocks,
                      i_target, i_select_ex);

    // -------------------------------
    // Stop cache clocks
    // -------------------------------

    FAPI_DBG("Clear all SCAN_REGION_TYPE bits");
    FAPI_TRY(putScom(i_target, EQ_SCAN_REGION_TYPE, MASK_ZERO));

    FAPI_DBG("Stop cache clocks via CLK_REGION");
    l_data64 = (p9hcd::CLK_STOP_CMD  |
                i_select_regions     |
                p9hcd::CLK_THOLD_ALL);
    FAPI_TRY(putScom(i_target, EQ_CLK_REGION, l_data64));

    FAPI_DBG("Poll for cache clocks stopped via CPLT_STAT0[8]");
    l_loops1ms = 1E6 / CACHE_CLK_STOP_POLLING_HW_NS_DELAY;

    do
    {
        fapi2::delay(CACHE_CLK_STOP_POLLING_HW_NS_DELAY,
                     CACHE_CLK_STOP_POLLING_SIM_CYCLE_DELAY);

        FAPI_TRY(getScom(i_target, EQ_CPLT_STAT0, l_data64));
    }
    while((l_data64.getBit<8>() != 1) && ((--l_loops1ms) != 0));

    FAPI_ASSERT((l_loops1ms != 0),
                fapi2::PMPROC_CACHECLKSTOP_TIMEOUT().set_EQCPLTSTAT(l_data64),
                "Cache Clock Stop Timeout");

    FAPI_DBG("Check cache clocks stopped");
    FAPI_TRY(getScom(i_target, EQ_CLOCK_STAT_SL, l_data64));

    FAPI_ASSERT((((~l_data64) & i_select_regions) == 0),
                fapi2::PMPROC_CACHECLKSTOP_FAILED().set_EQCLKSTAT(l_data64),
                "Cache Clock Stop Failed");
    FAPI_DBG("Cache clocks stopped now");

    // -------------------------------
    // Fence up
    // -------------------------------

    FAPI_DBG("Assert vital fence via CPLT_CTRL1[3]");
    FAPI_TRY(putScom(i_target, EQ_CPLT_CTRL1_OR, MASK_SET(3)));

    FAPI_DBG("Assert regional fences via CPLT_CTRL1[4-14]");
    FAPI_TRY(putScom(i_target, EQ_CPLT_CTRL1_OR, i_select_regions));

    // Gate the PCBMux request so scanning doesn't cause random requests
    for(auto& it : l_core_functional_vector)
    {
        FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS,
                               it.getParent<fapi2::TARGET_TYPE_PERV>(),
                               l_attr_chip_unit_pos));
        FAPI_DBG("Assert core[%d] PCB Mux Disable via C_SLAVE_CONFIG[7]",
                 (l_attr_chip_unit_pos - p9hcd::PERV_TO_CORE_POS_OFFSET));
        l_scom_addr = (C_SLAVE_CONFIG_REG + (0x1000000 *
                                             (l_attr_chip_unit_pos - p9hcd::PERV_TO_CORE_POS_OFFSET)));
        FAPI_TRY(getScom(l_chip, l_scom_addr, l_data64));
        FAPI_TRY(putScom(l_chip, l_scom_addr, DATA_SET(7)));
    }

    // -------------------------------
    // Disable VDM
    // -------------------------------

    if (l_attr_vdm_enable == fapi2::ENUM_ATTR_VDM_ENABLE_ON)
    {
        FAPI_DBG("Drop vdm enable via QPPM_VDMCR[0]");
        FAPI_TRY(putScom(i_target, EQ_PPM_VDMCR_CLEAR, MASK_SET(0)));
    }

    // -------------------------------
    // Shutdown edram
    // -------------------------------
    // QCCR[0/4] EDRAM_ENABLE_DC
    // QCCR[1/5] EDRAM_VWL_ENABLE_DC
    // QCCR[2/6] L3_EX0/1_EDRAM_VROW_VBLH_ENABLE_DC
    // QCCR[3/7] EDRAM_VPP_ENABLE_DC

    if (i_select_regions & p9hcd::CLK_REGION_EX0_REFR)
    {
        FAPI_DBG("Sequence EX0 EDRAM disables via QPPM_QCCR[0-3]");
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(3)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(2)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(1)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(0)));
    }

    if (i_select_regions & p9hcd::CLK_REGION_EX1_REFR)
    {
        FAPI_DBG("Sequence EX1 EDRAM disables via QPPM_QCCR[4-7]");
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(7)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(6)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(5)));
        FAPI_TRY(putScom(i_target, EQ_QPPM_QCCR_WCLEAR, MASK_SET(4)));
    }

    // -------------------------------
    // Update QSSR and STOP history
    // -------------------------------

    FAPI_DBG("Set cache as stopped in QSSR");
    FAPI_TRY(putScom(l_chip, PU_OCB_OCI_QSSR_OR,
                     BIT64(l_attr_chip_unit_pos + 14)));

    FAPI_DBG("Set cache as stopped in STOP history register");
    FAPI_TRY(putScom(i_target, EQ_PPM_SSHSRC, BIT64(0)));

fapi_try_exit:

    FAPI_INF("<<p9_hcd_cache_stopclocks");
    return fapi2::current_err;
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_cpu_special_wakeup_core.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_cpu_special_wakeup_core.C
///  @brief         :    HWP to perform special wakeup of a core

// *HWP HW Owner    :    Greg Still <stillgs@us.ibm.com>
// *HWP FW Owner    :    Prem S Jha <premjha2@in.ibm.com>
// *HWP Team        :    PM
// *HWP Level       :    3
// *HWP Consumed by :    OCC:FSP:HOST:CRO

// -----------------------------------------------------------------------------
// Includes
// -----------------------------------------------------------------------------
#include <p9_cpu_special_wakeup.H>
#include <p9_cpu_special_wakeup_lib.H>
#include <p9_ppe_defs.H>
#include <p9_ppe_utils.H>

fapi2::ReturnCode collectCoreTimeoutFailInfo( const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
        ProcessingValues_t i_processing_info );

/// ----------------------------------------------------------------------------
///
/// @brief      Sets a normal core chiplet into special wakeup state.
/// @param[in]  i_target     core target
/// @param[in]  i_operation  Special Wakeup Operation i.e. assert or deassert
/// @param[in]  i_entity     entity to be considered for special wakeup.
/// @return     fapi2 return code.
///
fapi2::ReturnCode p9_cpu_special_wakeup_core(
    const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
    const p9specialWakeup::PROC_SPCWKUP_OPS i_operation,
    const p9specialWakeup::PROC_SPCWKUP_ENTITY i_entity )
{
    FAPI_INF(">> p9_cpu_special_wakeup_core");
    fapi2::ReturnCode l_rc;
    uint8_t l_spWakeUpInProg    =   0;
    uint8_t l_corePos           =   0;
    uint8_t l_autoSpWkUpEn      =   0;

    ProcessingValues_t l_processing_info;
    fapi2::buffer<uint64_t> l_autoSpWkUp;
    fapi2::buffer<uint64_t> l_sgpeActive;
    auto l_exTarget = i_target.getParent<fapi2::TARGET_TYPE_EX>();
    auto l_eqTarget = i_target.getParent<fapi2::TARGET_TYPE_EQ>();
    auto l_procChip = i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();
    FAPI_TRY( getScom( l_procChip, PU_OCB_OCI_OCCFLG_SCOM, l_sgpeActive ) );
    FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS, i_target,  l_corePos );

    FAPI_ATTR_GET( fapi2::ATTR_CORE_INSIDE_SPECIAL_WAKEUP,
                   i_target,
                   l_spWakeUpInProg );

    // A special wakeup is already in progress. In all likelyhood, a special
    // wakeup has timed out and we are in FFDC collection path. During this
    // FFDC collection, we SCOMed a register which itself needs a special
    // wakeup.

    if( l_spWakeUpInProg )
    {
        FAPI_INF("exiting core recurssion");
        return fapi2::FAPI2_RC_SUCCESS;
    }

    p9specialWakeup::blockWakeupRecurssion( l_eqTarget, p9specialWakeup::BLOCK );

    //Special wakeup request can't be serviced if
    //SGPE did not boot and auto-special wakeup is not enabled.
    if( !l_sgpeActive.getBit( SGPE_ACTIVE_BIT ) )
    {
        l_rc = getScom( l_exTarget, EQ_CME_SCOM_LMCR_SCOM,  l_autoSpWkUp );

        if( !l_rc )
        {
            l_autoSpWkUpEn =
                l_autoSpWkUp.getBit(  AUTO_SPWKUP_DIS_POS + ((l_corePos >> 1) & 0x01) ) ? 0 : 1;
        }

        FAPI_ASSERT( (!l_rc && l_autoSpWkUpEn ),
                     fapi2::CORE_SPECIAL_WAKEUP_NOT_FEASIBLE()
                     .set_CORE_POS( l_corePos ),
                     "Special Wakeup Request Cannot Be Serviced on This Core" );
    }

    l_rc = _special_wakeup<fapi2::TARGET_TYPE_CORE> (
               i_target,
               i_operation,
               i_entity,
               l_processing_info );

    if( l_rc == (uint32_t)fapi2::RC_INTERNAL_SPCWKUP_TIMEOUT )
    {
        collectCoreTimeoutFailInfo( i_target, l_processing_info );
    }

fapi_try_exit:
    p9specialWakeup::blockWakeupRecurssion( l_eqTarget, p9specialWakeup::UNBLOCK );
    FAPI_INF("<< p9_cpu_special_wakeup_core" );
    return fapi2::current_err;
}

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

///
/// @brief      Collect FFDC for EQ Special Wakeup timeout
/// @param[in]  i_target     core target
/// @param[in]  i_operation  info pertaining to special wakeup
/// @return     fapi2 return code.
///
fapi2::ReturnCode collectCoreTimeoutFailInfo( const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
        ProcessingValues_t i_processing_info )
{
    FAPI_INF(">> collectCoreTimeoutFailInfo" );
    fapi2::buffer<uint64_t> l_CPMMR;
    fapi2::buffer<uint64_t> l_GPMMR;
    fapi2::buffer<uint64_t> l_spWakeupRegVal;
    fapi2::buffer<uint64_t> l_histRegVal;

    fapi2::getScom( i_target, C_CPPM_CPMMR, l_CPMMR );
    fapi2::getScom( i_target, C_PPM_GPMMR_SCOM, l_GPMMR );
    fapi2::getScom( i_target, i_processing_info.spwkup_address[0], l_spWakeupRegVal );
    fapi2::getScom( i_target, i_processing_info.history_address[0], l_histRegVal );
    fapi2::Target < fapi2::TARGET_TYPE_EX> parentExTgt = i_target.getParent <fapi2::TARGET_TYPE_EX>();
    uint8_t l_exPos = 0;
    FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS, parentExTgt, l_exPos );

    // Collect PPE FFDC for CME, SGPE and PGPE
    std::vector<uint64_t> l_ppeBaseAddresses;
    l_ppeBaseAddresses.push_back( getCmeBaseAddress( l_exPos ) );
    l_ppeBaseAddresses.push_back( SGPE_BASE_ADDRESS );
    l_ppeBaseAddresses.push_back( PGPE_BASE_ADDRESS );

    FAPI_ASSERT( false ,
                 fapi2::SPCWKUP_CORE_TIMEOUT().
                 set_POLLCOUNT( i_processing_info.poll_count ).
                 set_SP_WKUP_REG_VALUE( l_spWakeupRegVal ).
                 set_HISTORY_VALUE( l_histRegVal ).
                 set_ENTITY( i_processing_info.entity ).
                 set_CPMMR( l_CPMMR ).
                 set_GPMMR( l_GPMMR ).
                 set_EQ_TARGET( i_target.getParent <fapi2::TARGET_TYPE_EQ>() ).
                 set_EX_TARGET( parentExTgt ).
                 set_CORE_TARGET( i_target ).
                 set_PROC_CHIP_TARGET( i_processing_info.procTgt ).
                 set_PPE_BASE_ADDRESSES( l_ppeBaseAddresses ).
                 set_PPE_STATE_MODE( XIRS ),
                 "Timed Out In Setting Core Special Wakeup");
fapi_try_exit:
    FAPI_INF("<< collectCoreTimeoutFailInfo" );
    return fapi2::current_err;
}
// -----------------------------------------------------------------------------
/// @param[in]  i_chipletTarget     core target
/// @param[in]  i_processing_info   struct storing processing info
/// @param[in]  i_msgId             Id pertaining to debug message string.
/// @return     fapi2 return code.
fapi2::ReturnCode spwkup_deassert(  const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_chipletTarget,
                                    const ProcessingValues_t i_processing_info,
                                    p9specialWakeup::SpecialWakeUpMsg i_msgId )
{
    FAPI_INF("> spwkup_deassert Core" );

    uint64_t l_address = i_processing_info.spwkup_address[0];
    FAPI_TRY(_spwkup_deassert(i_chipletTarget, l_address, i_msgId));

fapi_try_exit:
    FAPI_INF("< spwkup_deassert Core" );
    return fapi2::current_err;
}

// -----------------------------------------------------------------------------
///
/// @brief Set addresses for a core target type
/// @param[in]  i_target         core target
/// @param[in]  i_structure      struct storing processing info
/// @param[in]  i_entity         entity to be considered for special wakeup.
/// @return fapi2 return code.
///
template<>
fapi2::ReturnCode set_addresses(const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_target,
                                ProcessingValues_t& i_structure,
                                const uint32_t i_entity )
{
    FAPI_INF(">> set_addresses for Core");

    uint8_t l_core_num = 0;

    FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS, i_target, l_core_num),
             "fapiGetAttribute of ATTR_CHIP_UNIT_POS");

    FAPI_DBG("Core %d being procesed.", l_core_num);

    i_structure.spwkup_address[0]  = SPCWKUP_ADDR[i_entity][p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.history_address[0] = SPCWKUP_HIST_ADDR[i_entity][p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.netctrl_address[0] = SPCWKUP_NETCTRL0_ADDR[p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.gpmmr_address[0] = SPCWKUP_GPMMR_ADDR[p9specialWakeup::SPW_CORE]
                                   + 0x01000000 * l_core_num;
    i_structure.num_addresses = 1;

    FAPI_DBG("i_structure.spwkup_address[%d]  = 0x%08llX \n "
             "i_structure.history_address[%d] = 0x%08llX \n "
             "i_structure.netctrl_address[%d] = 0x%08llX \n "
             "i_structure.gpmmr_addresss[%d]  = 0x%08llX \n " ,
             0, i_structure.spwkup_address[0],
             0, i_structure.history_address[0],
             0, i_structure.netctrl_address[0],
             0, i_structure.gpmmr_address[0]);

fapi_try_exit:
    FAPI_INF("<< set_addresses for Core");
    return fapi2::current_err;
}
<commit_msg>SplWkup: Fixed issue in FFDC collection in case of special wakeup timeout.<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_cpu_special_wakeup_core.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_cpu_special_wakeup_core.C
///  @brief         :    HWP to perform special wakeup of a core

// *HWP HW Owner    :    Greg Still <stillgs@us.ibm.com>
// *HWP FW Owner    :    Prem S Jha <premjha2@in.ibm.com>
// *HWP Team        :    PM
// *HWP Level       :    3
// *HWP Consumed by :    OCC:FSP:HOST:CRO

// -----------------------------------------------------------------------------
// Includes
// -----------------------------------------------------------------------------
#include <p9_cpu_special_wakeup.H>
#include <p9_cpu_special_wakeup_lib.H>
#include <p9_ppe_defs.H>
#include <p9_ppe_utils.H>

fapi2::ReturnCode collectCoreTimeoutFailInfo( const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
        ProcessingValues_t i_processing_info );

/// ----------------------------------------------------------------------------
///
/// @brief      Sets a normal core chiplet into special wakeup state.
/// @param[in]  i_target     core target
/// @param[in]  i_operation  Special Wakeup Operation i.e. assert or deassert
/// @param[in]  i_entity     entity to be considered for special wakeup.
/// @return     fapi2 return code.
///
fapi2::ReturnCode p9_cpu_special_wakeup_core(
    const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
    const p9specialWakeup::PROC_SPCWKUP_OPS i_operation,
    const p9specialWakeup::PROC_SPCWKUP_ENTITY i_entity )
{
    FAPI_INF(">> p9_cpu_special_wakeup_core");
    fapi2::ReturnCode l_rc;
    uint8_t l_spWakeUpInProg    =   0;
    uint8_t l_corePos           =   0;
    uint8_t l_autoSpWkUpEn      =   0;

    ProcessingValues_t l_processing_info;
    fapi2::buffer<uint64_t> l_autoSpWkUp;
    fapi2::buffer<uint64_t> l_sgpeActive;
    auto l_exTarget = i_target.getParent<fapi2::TARGET_TYPE_EX>();
    auto l_eqTarget = i_target.getParent<fapi2::TARGET_TYPE_EQ>();
    auto l_procChip = i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();
    FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS, i_target,  l_corePos );

    FAPI_ATTR_GET( fapi2::ATTR_CORE_INSIDE_SPECIAL_WAKEUP,
                   i_target,
                   l_spWakeUpInProg );

    // A special wakeup is already in progress. In all likelyhood, a special
    // wakeup has timed out and we are in FFDC collection path. During this
    // FFDC collection, we SCOMed a register which itself needs a special
    // wakeup.

    if( l_spWakeUpInProg )
    {
        FAPI_INF("exiting core recurssion");
        return fapi2::FAPI2_RC_SUCCESS;
    }

    p9specialWakeup::blockWakeupRecurssion( l_eqTarget, p9specialWakeup::BLOCK );
    l_rc = getScom( l_procChip, PU_OCB_OCI_OCCFLG_SCOM, l_sgpeActive );

    if( l_rc )
    {
        FAPI_ERR( "Failed To Read OCC Flag Register" );
        return l_rc;
    }

    //Special wakeup request can't be serviced if
    //SGPE did not boot and auto-special wakeup is not enabled.
    if( !l_sgpeActive.getBit( SGPE_ACTIVE_BIT ) )
    {
        l_rc = getScom( l_exTarget, EQ_CME_SCOM_LMCR_SCOM,  l_autoSpWkUp );

        if( !l_rc )
        {
            l_autoSpWkUpEn =
                l_autoSpWkUp.getBit(  AUTO_SPWKUP_DIS_POS + ((l_corePos >> 1) & 0x01) ) ? 0 : 1;
        }

        FAPI_ASSERT( (!l_rc && l_autoSpWkUpEn ),
                     fapi2::CORE_SPECIAL_WAKEUP_NOT_FEASIBLE()
                     .set_CORE_POS( l_corePos ),
                     "Special Wakeup Request Cannot Be Serviced on This Core" );
    }

    l_rc = _special_wakeup<fapi2::TARGET_TYPE_CORE> (
               i_target,
               i_operation,
               i_entity,
               l_processing_info );

    if( l_rc == (uint32_t)fapi2::RC_INTERNAL_SPCWKUP_TIMEOUT )
    {
        collectCoreTimeoutFailInfo( i_target, l_processing_info );
    }

fapi_try_exit:
    p9specialWakeup::blockWakeupRecurssion( l_eqTarget, p9specialWakeup::UNBLOCK );
    FAPI_INF("<< p9_cpu_special_wakeup_core" );
    return fapi2::current_err;
}

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

///
/// @brief      Collect FFDC for EQ Special Wakeup timeout
/// @param[in]  i_target     core target
/// @param[in]  i_operation  info pertaining to special wakeup
/// @return     fapi2 return code.
///
fapi2::ReturnCode collectCoreTimeoutFailInfo( const fapi2::Target < fapi2::TARGET_TYPE_CORE>& i_target,
        ProcessingValues_t i_processing_info )
{
    FAPI_INF(">> collectCoreTimeoutFailInfo" );
    fapi2::buffer<uint64_t> l_CPMMR;
    fapi2::buffer<uint64_t> l_GPMMR;
    fapi2::buffer<uint64_t> l_spWakeupRegVal;
    fapi2::buffer<uint64_t> l_histRegVal;

    fapi2::getScom( i_target, C_CPPM_CPMMR, l_CPMMR );
    fapi2::getScom( i_target, C_PPM_GPMMR_SCOM, l_GPMMR );
    fapi2::getScom( i_target, i_processing_info.spwkup_address[0], l_spWakeupRegVal );
    fapi2::getScom( i_target, i_processing_info.history_address[0], l_histRegVal );
    fapi2::Target < fapi2::TARGET_TYPE_EX> parentExTgt = i_target.getParent <fapi2::TARGET_TYPE_EX>();
    uint8_t l_exPos = 0;
    FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS, parentExTgt, l_exPos );

    // Collect PPE FFDC for CME, SGPE and PGPE
    std::vector<uint64_t> l_ppeBaseAddresses;
    l_ppeBaseAddresses.push_back( getCmeBaseAddress( l_exPos ) );
    l_ppeBaseAddresses.push_back( SGPE_BASE_ADDRESS );
    l_ppeBaseAddresses.push_back( PGPE_BASE_ADDRESS );

    FAPI_ASSERT( false ,
                 fapi2::SPCWKUP_CORE_TIMEOUT().
                 set_POLLCOUNT( i_processing_info.poll_count ).
                 set_SP_WKUP_REG_VALUE( l_spWakeupRegVal ).
                 set_HISTORY_VALUE( l_histRegVal ).
                 set_ENTITY( i_processing_info.entity ).
                 set_CPMMR( l_CPMMR ).
                 set_GPMMR( l_GPMMR ).
                 set_EQ_TARGET( i_target.getParent <fapi2::TARGET_TYPE_EQ>() ).
                 set_EX_TARGET( parentExTgt ).
                 set_CORE_TARGET( i_target ).
                 set_PROC_CHIP_TARGET( i_processing_info.procTgt ).
                 set_PPE_BASE_ADDRESSES( l_ppeBaseAddresses ).
                 set_PPE_STATE_MODE( XIRS ),
                 "Timed Out In Setting Core Special Wakeup");
fapi_try_exit:
    FAPI_INF("<< collectCoreTimeoutFailInfo" );
    return fapi2::current_err;
}
// -----------------------------------------------------------------------------
/// @param[in]  i_chipletTarget     core target
/// @param[in]  i_processing_info   struct storing processing info
/// @param[in]  i_msgId             Id pertaining to debug message string.
/// @return     fapi2 return code.
fapi2::ReturnCode spwkup_deassert(  const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_chipletTarget,
                                    const ProcessingValues_t i_processing_info,
                                    p9specialWakeup::SpecialWakeUpMsg i_msgId )
{
    FAPI_INF("> spwkup_deassert Core" );

    uint64_t l_address = i_processing_info.spwkup_address[0];
    FAPI_TRY(_spwkup_deassert(i_chipletTarget, l_address, i_msgId));

fapi_try_exit:
    FAPI_INF("< spwkup_deassert Core" );
    return fapi2::current_err;
}

// -----------------------------------------------------------------------------
///
/// @brief Set addresses for a core target type
/// @param[in]  i_target         core target
/// @param[in]  i_structure      struct storing processing info
/// @param[in]  i_entity         entity to be considered for special wakeup.
/// @return fapi2 return code.
///
template<>
fapi2::ReturnCode set_addresses(const fapi2::Target<fapi2::TARGET_TYPE_CORE>& i_target,
                                ProcessingValues_t& i_structure,
                                const uint32_t i_entity )
{
    FAPI_INF(">> set_addresses for Core");

    uint8_t l_core_num = 0;

    FAPI_TRY(FAPI_ATTR_GET( fapi2::ATTR_CHIP_UNIT_POS, i_target, l_core_num),
             "fapiGetAttribute of ATTR_CHIP_UNIT_POS");

    FAPI_DBG("Core %d being procesed.", l_core_num);

    i_structure.spwkup_address[0]  = SPCWKUP_ADDR[i_entity][p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.history_address[0] = SPCWKUP_HIST_ADDR[i_entity][p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.netctrl_address[0] = SPCWKUP_NETCTRL0_ADDR[p9specialWakeup::SPW_CORE]
                                     + 0x01000000 * l_core_num;
    i_structure.gpmmr_address[0] = SPCWKUP_GPMMR_ADDR[p9specialWakeup::SPW_CORE]
                                   + 0x01000000 * l_core_num;
    i_structure.num_addresses = 1;

    FAPI_DBG("i_structure.spwkup_address[%d]  = 0x%08llX \n "
             "i_structure.history_address[%d] = 0x%08llX \n "
             "i_structure.netctrl_address[%d] = 0x%08llX \n "
             "i_structure.gpmmr_addresss[%d]  = 0x%08llX \n " ,
             0, i_structure.spwkup_address[0],
             0, i_structure.history_address[0],
             0, i_structure.netctrl_address[0],
             0, i_structure.gpmmr_address[0]);

fapi_try_exit:
    FAPI_INF("<< set_addresses for Core");
    return fapi2::current_err;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 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/file_path.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

void SimulateRendererCrash(Browser* browser) {
  browser->OpenURL(GURL(chrome::kAboutCrashURL), GURL(), CURRENT_TAB,
                   PageTransition::TYPED);
  ui_test_utils::WaitForNotification(
      NotificationType::TAB_CONTENTS_DISCONNECTED);
}

}  // namespace

class CrashRecoveryBrowserTest : public InProcessBrowserTest {
};

// http://crbug.com/29331 - Causes an OS crash dialog in release mode, needs to
// be fixed before it can be enabled to not cause the bots issues.
#if defined(OS_MACOSX)
#define MAYBE_Reload DISABLED_Reload
#define MAYBE_LoadInNewTab DISABLED_LoadInNewTab
#elif defined(OS_WIN)
// http://crbug.com/57158 - Times out sometimes on windows.
#define MAYBE_LoadInNewTab DISABLED_LoadInNewTab
#define MAYBE_Reload Reload
#else
#define MAYBE_Reload Reload
#define MAYBE_LoadInNewTab LoadInNewTab
#endif

// Test that reload works after a crash.
IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, MAYBE_Reload) {
  // The title of the active tab should change each time this URL is loaded.
  GURL url(
      "data:text/html,<script>document.title=new Date().valueOf()</script>");
  ui_test_utils::NavigateToURL(browser(), url);

  string16 title_before_crash;
  string16 title_after_crash;

  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
                                                &title_before_crash));
  SimulateRendererCrash(browser());
  browser()->Reload(CURRENT_TAB);
  ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
                                                &title_after_crash));
  EXPECT_NE(title_before_crash, title_after_crash);
}

// Tests that loading a crashed page in a new tab correctly updates the title.
// There was an earlier bug (1270510) in process-per-site in which the max page
// ID of the RenderProcessHost was stale, so the NavigationEntry in the new tab
// was not committed.  This prevents regression of that bug.
IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, MAYBE_LoadInNewTab) {
  const FilePath::CharType* kTitle2File = FILE_PATH_LITERAL("title2.html");

  ui_test_utils::NavigateToURL(browser(),
      ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                FilePath(kTitle2File)));

  string16 title_before_crash;
  string16 title_after_crash;

  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
                                                &title_before_crash));
  SimulateRendererCrash(browser());
  browser()->Reload(CURRENT_TAB);
  ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
                                                &title_after_crash));
  EXPECT_EQ(title_before_crash, title_after_crash);
}
<commit_msg>Disable CrashRecoveryBrowserTest.LoadInNewTab on Linux and ChromeOS<commit_after>// Copyright (c) 2010 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/file_path.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

void SimulateRendererCrash(Browser* browser) {
  browser->OpenURL(GURL(chrome::kAboutCrashURL), GURL(), CURRENT_TAB,
                   PageTransition::TYPED);
  ui_test_utils::WaitForNotification(
      NotificationType::TAB_CONTENTS_DISCONNECTED);
}

}  // namespace

class CrashRecoveryBrowserTest : public InProcessBrowserTest {
};

// http://crbug.com/29331 - Causes an OS crash dialog in release mode, needs to
// be fixed before it can be enabled to not cause the bots issues.
#if defined(OS_MACOSX)
#define MAYBE_Reload DISABLED_Reload
#define MAYBE_LoadInNewTab DISABLED_LoadInNewTab
#elif defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
// http://crbug.com/57158 - Times out sometimes on windows, linux and chrome os.
#define MAYBE_LoadInNewTab DISABLED_LoadInNewTab
#define MAYBE_Reload Reload
#else
#define MAYBE_Reload Reload
#define MAYBE_LoadInNewTab LoadInNewTab
#endif

// Test that reload works after a crash.
IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, MAYBE_Reload) {
  // The title of the active tab should change each time this URL is loaded.
  GURL url(
      "data:text/html,<script>document.title=new Date().valueOf()</script>");
  ui_test_utils::NavigateToURL(browser(), url);

  string16 title_before_crash;
  string16 title_after_crash;

  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
                                                &title_before_crash));
  SimulateRendererCrash(browser());
  browser()->Reload(CURRENT_TAB);
  ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
                                                &title_after_crash));
  EXPECT_NE(title_before_crash, title_after_crash);
}

// Tests that loading a crashed page in a new tab correctly updates the title.
// There was an earlier bug (1270510) in process-per-site in which the max page
// ID of the RenderProcessHost was stale, so the NavigationEntry in the new tab
// was not committed.  This prevents regression of that bug.
IN_PROC_BROWSER_TEST_F(CrashRecoveryBrowserTest, MAYBE_LoadInNewTab) {
  const FilePath::CharType* kTitle2File = FILE_PATH_LITERAL("title2.html");

  ui_test_utils::NavigateToURL(browser(),
      ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                FilePath(kTitle2File)));

  string16 title_before_crash;
  string16 title_after_crash;

  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
                                                &title_before_crash));
  SimulateRendererCrash(browser());
  browser()->Reload(CURRENT_TAB);
  ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser()));
  ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(),
                                                &title_after_crash));
  EXPECT_EQ(title_before_crash, title_after_crash);
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 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 "app/resource_bundle.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/speech/speech_input_bubble.h"
#include "gfx/canvas_skia.h"
#include "gfx/rect.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

SpeechInputBubble::FactoryMethod SpeechInputBubble::factory_ = NULL;
const int SpeechInputBubble::kBubbleTargetOffsetX = 5;

SkBitmap* SpeechInputBubbleBase::mic_empty_ = NULL;
SkBitmap* SpeechInputBubbleBase::mic_full_ = NULL;
SkBitmap* SpeechInputBubbleBase::mic_mask_ = NULL;
SkBitmap* SpeechInputBubbleBase::spinner_ = NULL;
const int SpeechInputBubbleBase::kRecognizingAnimationStepMs = 100;

SpeechInputBubble* SpeechInputBubble::Create(TabContents* tab_contents,
                                             Delegate* delegate,
                                             const gfx::Rect& element_rect) {
  if (factory_)
    return (*factory_)(tab_contents, delegate, element_rect);

  // Has the tab already closed before bubble create request was processed?
  if (!tab_contents)
    return NULL;

  return CreateNativeBubble(tab_contents, delegate, element_rect);
}

SpeechInputBubbleBase::SpeechInputBubbleBase()
    : ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
      display_mode_(DISPLAY_MODE_RECORDING) {
  if (!mic_empty_) {  // Static variables.
    mic_empty_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
        IDR_SPEECH_INPUT_MIC_EMPTY);
    mic_full_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
        IDR_SPEECH_INPUT_MIC_FULL);
    mic_mask_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
        IDR_SPEECH_INPUT_MIC_MASK);
    spinner_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
        IDR_SPEECH_INPUT_SPINNER);
  }

  // Instance variables.
  mic_image_.reset(new SkBitmap());
  mic_image_->setConfig(SkBitmap::kARGB_8888_Config, mic_empty_->width(),
                        mic_empty_->height());
  mic_image_->allocPixels();

  buffer_image_.reset(new SkBitmap());
  buffer_image_->setConfig(SkBitmap::kARGB_8888_Config, mic_empty_->width(),
                           mic_empty_->height());
  buffer_image_->allocPixels();

  // The sprite image consists of all the animation frames put together in one
  // horizontal/wide image. Each animation frame is square in shape within the
  // sprite.
  int frame_size = spinner_->height();
  for (int x = 0; x < spinner_->width(); x += frame_size) {
    SkBitmap frame;
    spinner_->extractSubset(&frame,
                            SkIRect::MakeXYWH(x, 0, frame_size, frame_size));
    animation_frames_.push_back(frame);
  }
}

SpeechInputBubbleBase::~SpeechInputBubbleBase() {
  // This destructor is added to make sure members such as the scoped_ptr
  // get destroyed here and the derived classes don't have to care about such
  // member variables which they don't use.
}

void SpeechInputBubbleBase::SetRecordingMode() {
  task_factory_.RevokeAll();
  display_mode_ = DISPLAY_MODE_RECORDING;
  UpdateLayout();
}

void SpeechInputBubbleBase::SetRecognizingMode() {
  display_mode_ = DISPLAY_MODE_RECOGNIZING;
  UpdateLayout();

  animation_step_ = 0;
  MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      task_factory_.NewRunnableMethod(
          &SpeechInputBubbleBase::DoRecognizingAnimationStep),
      kRecognizingAnimationStepMs);
}

void SpeechInputBubbleBase::DoRecognizingAnimationStep() {
  SetImage(animation_frames_[animation_step_]);
  if (++animation_step_ >= static_cast<int>(animation_frames_.size()))
    animation_step_ = 0;
  MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      task_factory_.NewRunnableMethod(
          &SpeechInputBubbleBase::DoRecognizingAnimationStep),
      kRecognizingAnimationStepMs);
}

void SpeechInputBubbleBase::SetMessage(const string16& text) {
  task_factory_.RevokeAll();
  message_text_ = text;
  display_mode_ = DISPLAY_MODE_MESSAGE;
  UpdateLayout();
}

void SpeechInputBubbleBase::SetInputVolume(float volume) {
  mic_image_->eraseARGB(0, 0, 0, 0);
  buffer_image_->eraseARGB(0, 0, 0, 0);

  int width = mic_image_->width();
  int height = mic_image_->height();
  SkCanvas canvas(*mic_image_);
  SkCanvas buffer_canvas(*buffer_image_);

  // The 'full volume' mic image is drawn clipped to the current volume level,
  // and a gradient mask is applied over it with the 'multiply' compositing
  // operator to show soft edges at the top.
  buffer_canvas.save();
  SkScalar clip_top = ((1.0f - volume) * height * 3) / 2.0f - height / 2.0f;
  buffer_canvas.clipRect(SkRect::MakeLTRB(0, clip_top,
      SkIntToScalar(width), SkIntToScalar(height)));
  buffer_canvas.drawBitmap(*mic_full_, 0, 0);
  buffer_canvas.restore();
  SkPaint multiply_paint;
  multiply_paint.setXfermode(SkXfermode::Create(SkXfermode::kMultiply_Mode));
  buffer_canvas.drawBitmap(*mic_mask_, 0, clip_top, &multiply_paint);

  // Draw the empty volume image first and the current volume image on top.
  canvas.drawBitmap(*mic_empty_, 0, 0);
  canvas.drawBitmap(*buffer_image_.get(), 0, 0);

  SetImage(*mic_image_.get());
}
<commit_msg>Fix the progress animation to get displayed at the original size and not squished.<commit_after>// Copyright (c) 2010 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 "app/resource_bundle.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/speech/speech_input_bubble.h"
#include "gfx/canvas_skia.h"
#include "gfx/rect.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

SpeechInputBubble::FactoryMethod SpeechInputBubble::factory_ = NULL;
const int SpeechInputBubble::kBubbleTargetOffsetX = 5;

SkBitmap* SpeechInputBubbleBase::mic_empty_ = NULL;
SkBitmap* SpeechInputBubbleBase::mic_full_ = NULL;
SkBitmap* SpeechInputBubbleBase::mic_mask_ = NULL;
SkBitmap* SpeechInputBubbleBase::spinner_ = NULL;
const int SpeechInputBubbleBase::kRecognizingAnimationStepMs = 100;

SpeechInputBubble* SpeechInputBubble::Create(TabContents* tab_contents,
                                             Delegate* delegate,
                                             const gfx::Rect& element_rect) {
  if (factory_)
    return (*factory_)(tab_contents, delegate, element_rect);

  // Has the tab already closed before bubble create request was processed?
  if (!tab_contents)
    return NULL;

  return CreateNativeBubble(tab_contents, delegate, element_rect);
}

SpeechInputBubbleBase::SpeechInputBubbleBase()
    : ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)),
      display_mode_(DISPLAY_MODE_RECORDING) {
  if (!mic_empty_) {  // Static variables.
    mic_empty_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
        IDR_SPEECH_INPUT_MIC_EMPTY);
    mic_full_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
        IDR_SPEECH_INPUT_MIC_FULL);
    mic_mask_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
        IDR_SPEECH_INPUT_MIC_MASK);
    spinner_ = ResourceBundle::GetSharedInstance().GetBitmapNamed(
        IDR_SPEECH_INPUT_SPINNER);
  }

  // Instance variables.
  mic_image_.reset(new SkBitmap());
  mic_image_->setConfig(SkBitmap::kARGB_8888_Config, mic_empty_->width(),
                        mic_empty_->height());
  mic_image_->allocPixels();

  buffer_image_.reset(new SkBitmap());
  buffer_image_->setConfig(SkBitmap::kARGB_8888_Config, mic_empty_->width(),
                           mic_empty_->height());
  buffer_image_->allocPixels();

  // The sprite image consists of all the animation frames put together in one
  // horizontal/wide image. Each animation frame is square in shape within the
  // sprite.
  int frame_size = spinner_->height();
  SkRect dst_rect(SkRect::MakeWH(SkIntToScalar(frame_size),
                                 SkIntToScalar(frame_size)));
  for (SkIRect src_rect(SkIRect::MakeWH(frame_size, frame_size));
       src_rect.fLeft < spinner_->width();
       src_rect.offset(frame_size, 0)) {
    SkBitmap frame;
    frame.setConfig(SkBitmap::kARGB_8888_Config, frame_size, frame_size);
    frame.allocPixels();
    SkCanvas canvas(frame);
    canvas.drawBitmapRect(*spinner_, &src_rect, dst_rect);
    animation_frames_.push_back(frame);
  }
}

SpeechInputBubbleBase::~SpeechInputBubbleBase() {
  // This destructor is added to make sure members such as the scoped_ptr
  // get destroyed here and the derived classes don't have to care about such
  // member variables which they don't use.
}

void SpeechInputBubbleBase::SetRecordingMode() {
  task_factory_.RevokeAll();
  display_mode_ = DISPLAY_MODE_RECORDING;
  UpdateLayout();
}

void SpeechInputBubbleBase::SetRecognizingMode() {
  display_mode_ = DISPLAY_MODE_RECOGNIZING;
  UpdateLayout();

  animation_step_ = 0;
  MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      task_factory_.NewRunnableMethod(
          &SpeechInputBubbleBase::DoRecognizingAnimationStep),
      kRecognizingAnimationStepMs);
}

void SpeechInputBubbleBase::DoRecognizingAnimationStep() {
  SetImage(animation_frames_[animation_step_]);
  if (++animation_step_ >= static_cast<int>(animation_frames_.size()))
    animation_step_ = 0;
  MessageLoop::current()->PostDelayedTask(
      FROM_HERE,
      task_factory_.NewRunnableMethod(
          &SpeechInputBubbleBase::DoRecognizingAnimationStep),
      kRecognizingAnimationStepMs);
}

void SpeechInputBubbleBase::SetMessage(const string16& text) {
  task_factory_.RevokeAll();
  message_text_ = text;
  display_mode_ = DISPLAY_MODE_MESSAGE;
  UpdateLayout();
}

void SpeechInputBubbleBase::SetInputVolume(float volume) {
  mic_image_->eraseARGB(0, 0, 0, 0);
  buffer_image_->eraseARGB(0, 0, 0, 0);

  int width = mic_image_->width();
  int height = mic_image_->height();
  SkCanvas canvas(*mic_image_);
  SkCanvas buffer_canvas(*buffer_image_);

  // The 'full volume' mic image is drawn clipped to the current volume level,
  // and a gradient mask is applied over it with the 'multiply' compositing
  // operator to show soft edges at the top.
  buffer_canvas.save();
  SkScalar clip_top = ((1.0f - volume) * height * 3) / 2.0f - height / 2.0f;
  buffer_canvas.clipRect(SkRect::MakeLTRB(0, clip_top,
      SkIntToScalar(width), SkIntToScalar(height)));
  buffer_canvas.drawBitmap(*mic_full_, 0, 0);
  buffer_canvas.restore();
  SkPaint multiply_paint;
  multiply_paint.setXfermode(SkXfermode::Create(SkXfermode::kMultiply_Mode));
  buffer_canvas.drawBitmap(*mic_mask_, 0, clip_top, &multiply_paint);

  // Draw the empty volume image first and the current volume image on top.
  canvas.drawBitmap(*mic_empty_, 0, 0);
  canvas.drawBitmap(*buffer_image_.get(), 0, 0);

  SetImage(*mic_image_.get());
}
<|endoftext|>


<commit_before>// Copyright (c) 2014-2016 Michael J. Sullivan
// Use of this source code is governed by an MIT-style license that can be
// found in the LICENSE file.

#ifndef RMC_MS_QUEUE_C112
#define RMC_MS_QUEUE_C112

#include <atomic>
#include <utility>
#include "util.hpp"
#include "gen_ptr.hpp"
#include "freelist.hpp"
#include "universal.hpp"

// A version of Michael-Scott queues that closely corresponds to the
// original version using generation pointers.

namespace rmclib {

struct MSQueueNode {
    std::gen_atomic<lf_ptr<MSQueueNode>> next_;
    // Traditional MS Queues need to read out the data from nodes
    // that may already be getting reused.
    // To avoid data races copying the elements around,
    // we instead store a pointer to an allocated object.
    universal data_;

    static Freelist<MSQueueNode> freelist;
};

template<typename T>
class MSQueue {
private:
    using NodePtr = gen_ptr<lf_ptr<MSQueueNode>>;

    alignas(kCacheLinePadding)
    std::gen_atomic<lf_ptr<MSQueueNode>> head_;
    alignas(kCacheLinePadding)
    std::gen_atomic<lf_ptr<MSQueueNode>> tail_;

    void enqueueNode(lf_ptr<MSQueueNode> node);

public:
    MSQueue() {
        // Need to create a dummy node!
        auto node = MSQueueNode::freelist.alloc();
        node->next_ = node->next_.load().update(nullptr); // XXX: ok?
        head_ = tail_ = NodePtr(node, 0);
    }

    optional<T> dequeue();

    void enqueue(T &&t) {
        auto node = MSQueueNode::freelist.alloc();
        node->data_ = universal(std::move(t));
        enqueueNode(node);
    }
    void enqueue(const T &t) {
        auto node = MSQueueNode::freelist.alloc();
        node->data_ = universal(t);
        enqueueNode(node);
    }
};

template<typename T>
void MSQueue<T>::enqueueNode(lf_ptr<MSQueueNode> node) {
    node->next_ = node->next_.load().update(nullptr); // XXX: ok?

    NodePtr tail, next;

    for (;;) {
        tail = this->tail_;
        next = tail->next_;
        // Check that tail and next are consistent: In this gen
        // counter version, this is important for correctness: if,
        // after we read the tail, it gets removed from this queue,
        // freed, and added to some other queue, we need to make sure
        // that we don't try to append to that queue instead.
        if (tail != this->tail_) continue;

        // was tail /actually/ the last node?
        if (next == nullptr) {
            // if so, try to write it in. (nb. this overwrites next)
            // XXX: does weak actually help us here?
            if (tail->next_.compare_exchange_weak_gen(next, node)) {
                // we did it! return
                break;
            }
        } else {
            // nope. try to swing the tail further down the list and try again
            this->tail_.compare_exchange_strong_gen(tail, next);
        }
    }

    // Try to swing the tail_ to point to what we inserted
    this->tail_.compare_exchange_strong_gen(tail, node);
}

template<typename T>
optional<T> MSQueue<T>::dequeue() {
    NodePtr head, tail, next;

    universal data;

    for (;;) {
        head = this->head_;
        tail = this->tail_;
        next = head->next_;

        // Consistency check; see note above
        if (head != this->head_) continue;

        // Check if the queue *might* be empty
        // XXX: is it necessary to have the empty check under this
        if (head == tail) {
            // Ok, so, the queue might be empty, but it also might
            // be that the tail pointer has just fallen behind.
            // If the next pointer is null, then it is actually empty
            if (next == nullptr) {
                return optional<T>{};
            } else {
                // not empty: tail falling behind; since it is super
                // not ok for the head to advance past the tail,
                // try advancing the tail
                // XXX weak v strong?
                this->tail_.compare_exchange_strong_gen(tail, next);
            }
        } else {
            // OK, now we try to actually read the thing out.

            // We need to read the data out of the node
            // *before* we try to dequeue it or else it could get
            // reused before we read it out.
            data = next->data_;
            if (this->head_.compare_exchange_weak_gen(head, next)) {
                break;
            }
        }
    }

    // OK, everything set up.
    // head can be freed
    MSQueueNode::freelist.unlinked(head);
    optional<T> ret(data.extract<T>());

    return ret;
}

}

#endif
<commit_msg>Make ms_queue_c112 actually use C11 stuff<commit_after>// Copyright (c) 2014-2016 Michael J. Sullivan
// Use of this source code is governed by an MIT-style license that can be
// found in the LICENSE file.

#ifndef RMC_MS_QUEUE_C112
#define RMC_MS_QUEUE_C112

#include <atomic>
#include <utility>
#include "util.hpp"
#include "gen_ptr.hpp"
#include "freelist.hpp"
#include "universal.hpp"

// A version of Michael-Scott queues that closely corresponds to the
// original version using generation pointers.

namespace rmclib {

struct MSQueueNode {
    std::gen_atomic<lf_ptr<MSQueueNode>> next_;
    // Traditional MS Queues need to read out the data from nodes
    // that may already be getting reused.
    // To avoid data races copying the elements around,
    // we instead store a pointer to an allocated object.
    universal data_;

    static Freelist<MSQueueNode> freelist;
};

template<typename T>
class MSQueue {
private:
    using NodePtr = gen_ptr<lf_ptr<MSQueueNode>>;

    alignas(kCacheLinePadding)
    std::gen_atomic<lf_ptr<MSQueueNode>> head_;
    alignas(kCacheLinePadding)
    std::gen_atomic<lf_ptr<MSQueueNode>> tail_;

    void enqueueNode(lf_ptr<MSQueueNode> node);

public:
    MSQueue() {
        // Need to create a dummy node!
        auto node = MSQueueNode::freelist.alloc();
        node->next_ = node->next_.load().update(nullptr); // XXX: ok?
        head_ = tail_ = NodePtr(node, 0);
    }

    optional<T> dequeue();

    void enqueue(T &&t) {
        auto node = MSQueueNode::freelist.alloc();
        node->data_ = universal(std::move(t));
        enqueueNode(node);
    }
    void enqueue(const T &t) {
        auto node = MSQueueNode::freelist.alloc();
        node->data_ = universal(t);
        enqueueNode(node);
    }
};

template<typename T>
void MSQueue<T>::enqueueNode(lf_ptr<MSQueueNode> node) {
    node->next_ = node->next_.load().update(nullptr); // XXX: ok?

    NodePtr tail, next;

    for (;;) {
        // acquire because we need to see node init
        tail = this->tail_.load(mo_acq);
        // acquire because anything we see through this needs to be
        // re-published if we try to do a catchup swing: **
        next = tail->next_.load(mo_acq);
        // Check that tail and next are consistent: In this gen
        // counter version, this is important for correctness: if,
        // after we read the tail, it gets removed from this queue,
        // freed, and added to some other queue, we need to make sure
        // that we don't try to append to that queue instead.
        // XXX: So I think that means it should be acquire
        if (tail != this->tail_.load(mo_acq)) continue;

        // was tail /actually/ the last node?
        if (next == nullptr) {
            // if so, try to write it in. (nb. this overwrites next)
            // XXX: does weak actually help us here?
            // release because publishing; not acquire since I don't
            // think we care what we see
            if (tail->next_.compare_exchange_weak_gen(next, node,
                                                      mo_rel, mo_rlx)) {
                // we did it! return
                break;
            }
        } else {
            // nope. try to swing the tail further down the list and try again
            // release because we need to keep the node data visible
            // (**) - maybe can put an acq_rel *fence* here instead
            this->tail_.compare_exchange_strong_gen(tail, next,
                                                    mo_rel, mo_rlx);
        }
    }

    // Try to swing the tail_ to point to what we inserted
    // release because publishing
    this->tail_.compare_exchange_strong_gen(tail, node, mo_rel, mo_rlx);
}

template<typename T>
optional<T> MSQueue<T>::dequeue() {
    NodePtr head, tail, next;

    universal data;

    for (;;) {
        head = this->head_.load(mo_acq);
        tail = this->tail_.load(mo_acq);
        // This one could maybe use an acq/rel fence
        next = head->next_.load(mo_acq);

        // Consistency check; see note above
        if (head != this->head_.load(mo_acq)) continue;

        // Check if the queue *might* be empty
        // XXX: is it necessary to have the empty check under this
        if (head == tail) {
            // Ok, so, the queue might be empty, but it also might
            // be that the tail pointer has just fallen behind.
            // If the next pointer is null, then it is actually empty
            if (next == nullptr) {
                return optional<T>{};
            } else {
                // not empty: tail falling behind; since it is super
                // not ok for the head to advance past the tail,
                // try advancing the tail
                // XXX weak v strong?
                // Release because anything we saw needs to be republished
                this->tail_.compare_exchange_strong_gen(tail, next,
                                                        mo_rel, mo_rlx);
            }
        } else {
            // OK, now we try to actually read the thing out.

            // We need to read the data out of the node
            // *before* we try to dequeue it or else it could get
            // reused before we read it out.
            data = next->data_;

            // release because we're republishing; don't care about what we read
            if (this->head_.compare_exchange_weak_gen(head, next,
                                                      mo_rel, mo_rlx)) {
                break;
            }
        }
    }

    // OK, everything set up.
    // head can be freed
    MSQueueNode::freelist.unlinked(head);
    optional<T> ret(data.extract<T>());

    return ret;
}

}

#endif
<|endoftext|>