/*
 * CoreFreq
 * Copyright (C) 2015-2026 CYRIL COURTIAT
 * Licenses: GPL2
 */

#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <stdio.h>
#include <signal.h>
#include <stdarg.h>
#include <errno.h>
#include <pthread.h>
#ifndef __USE_GNU
#include <libgen.h>
#endif

#include "bitasm.h"
#include "amd_reg.h"
#include "intel_reg.h"
#include "coretypes.h"
#include "corefreq.h"
#include "corefreqm.h"
#include "corefreq-api.h"

#define AT( _loc_ )		[ _loc_ ]

#define PAGE_SIZE							\
(									\
	sysconf(_SC_PAGESIZE) > 0 ? sysconf(_SC_PAGESIZE) : 4096	\
)

/*Ch:8.10.6.7 Place Locks and Semaphores in Aligned, 128-Byte Blocks of Memory*/
static BitCC roomSeed	__attribute__ ((aligned (16))) = InitCC(0x0);
static BitCC roomCore	__attribute__ ((aligned (16))) = InitCC(0x0);
static BitCC roomClear	__attribute__ ((aligned (16))) = InitCC(0x0);
static BitCC roomReady	__attribute__ ((aligned (16))) = InitCC(0x0);
static Bit64 Shutdown	__attribute__ ((aligned (8))) = 0x0;
static Bit64 PendingSync __attribute__ ((aligned (8))) = 0x0;
unsigned int Quiet = 0x001, SysGateStartUp = 1;

UBENCH_DECLARE()

typedef struct
{
	int	drv,
		ro,
		rw;
} FD;

typedef struct {
	sigset_t		Signal;
	pid_t			CPID;
	pthread_t		KID;
	int			Started;
	struct {
		SLICE_FUNC	Func;
		unsigned long	arg;
		enum PATTERN	pattern;
	} Slice;
	FD			*fd;
	RO(SHM_STRUCT)		*RO(Shm);
	RW(SHM_STRUCT)		*RW(Shm);
	RO(PROC)		*RO(Proc);
	RW(PROC)		*RW(Proc);
	RO(CORE)		**RO(Core);
	RW(CORE)		**RW(Core);
	RO(SYSGATE)		*RO(SysGate);
} REF;

void Core_ResetSensorLimits(CPU_STRUCT *Cpu)
{
	RESET_SENSOR_LIMIT(THERMAL,	LOWEST, Cpu->PowerThermal.Limit);
	RESET_SENSOR_LIMIT(VOLTAGE,	LOWEST, Cpu->Sensors.Voltage.Limit);
	RESET_SENSOR_LIMIT(ENERGY,	LOWEST, Cpu->Sensors.Energy.Limit);
	RESET_SENSOR_LIMIT(POWER,	LOWEST, Cpu->Sensors.Power.Limit);
	RESET_SENSOR_LIMIT(REL_FREQ,	LOWEST, Cpu->Relative.Freq);
	RESET_SENSOR_LIMIT(ABS_FREQ,	LOWEST, Cpu->Absolute.Freq);

	RESET_SENSOR_LIMIT(THERMAL,	HIGHEST, Cpu->PowerThermal.Limit);
	RESET_SENSOR_LIMIT(VOLTAGE,	HIGHEST, Cpu->Sensors.Voltage.Limit);
	RESET_SENSOR_LIMIT(ENERGY,	HIGHEST, Cpu->Sensors.Energy.Limit);
	RESET_SENSOR_LIMIT(POWER,	HIGHEST, Cpu->Sensors.Power.Limit);
	RESET_SENSOR_LIMIT(REL_FREQ,	HIGHEST, Cpu->Relative.Freq);
	RESET_SENSOR_LIMIT(ABS_FREQ,	HIGHEST, Cpu->Absolute.Freq);
}

void Core_ComputeThermalLimits(CPU_STRUCT *Cpu, struct FLIP_FLOP *CFlip)
{	/* Per Core, computes the Min temperature.			*/
	TEST_AND_SET_SENSOR( THERMAL, LOWEST,	CFlip->Thermal.Temp,
						Cpu->PowerThermal.Limit );
	/* Per Core, computes the Max temperature.			*/
	TEST_AND_SET_SENSOR( THERMAL, HIGHEST,	CFlip->Thermal.Temp,
						Cpu->PowerThermal.Limit );
}

static void ComputeThermal_None( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu )
{
	UNUSED(RO(Shm));
	UNUSED(cpu);
	CFlip->Thermal.Temp = 0;
}

#define ComputeThermal_None_PerSMT	ComputeThermal_None
#define ComputeThermal_None_PerCore	ComputeThermal_None
#define ComputeThermal_None_PerPkg	ComputeThermal_None

static void (*ComputeThermal_None_Matrix[4])( struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeThermal_None,
	[FORMULA_SCOPE_SMT ] = ComputeThermal_None_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeThermal_None_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeThermal_None_PerPkg
};

static void ComputeThermal_Intel( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu )
{
	COMPUTE_THERMAL(INTEL,
			CFlip->Thermal.Temp,
			CFlip->Thermal.Param,
			CFlip->Thermal.Sensor);

	Core_ComputeThermalLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeThermal_Intel_PerSMT	ComputeThermal_Intel

static void ComputeThermal_Intel_PerCore( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeThermal_Intel(CFlip, RO(Shm), cpu);
	}
}

static void ComputeThermal_Intel_PerPkg( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeThermal_Intel(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeThermal_Intel_Matrix[4])(	struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeThermal_None,
	[FORMULA_SCOPE_SMT ] = ComputeThermal_Intel_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeThermal_Intel_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeThermal_Intel_PerPkg
};

static void ComputeThermal_AMD( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu )
{
	COMPUTE_THERMAL(AMD,
			CFlip->Thermal.Temp,
			CFlip->Thermal.Param,
			CFlip->Thermal.Sensor);

	Core_ComputeThermalLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeThermal_AMD_PerSMT	ComputeThermal_AMD

static void ComputeThermal_AMD_PerCore( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeThermal_AMD(CFlip, RO(Shm), cpu);
	}
}

static void ComputeThermal_AMD_PerPkg( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeThermal_AMD(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeThermal_AMD_Matrix[4])( struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeThermal_None,
	[FORMULA_SCOPE_SMT ] = ComputeThermal_AMD_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeThermal_AMD_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeThermal_AMD_PerPkg
};

static void ComputeThermal_AMD_0Fh( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu )
{
	COMPUTE_THERMAL(AMD_0Fh,
			CFlip->Thermal.Temp,
			CFlip->Thermal.Param,
			CFlip->Thermal.Sensor);

	Core_ComputeThermalLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeThermal_AMD_0Fh_PerSMT	ComputeThermal_AMD_0Fh

static void ComputeThermal_AMD_0Fh_PerCore( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeThermal_AMD_0Fh(CFlip, RO(Shm), cpu);
	}
}

static void ComputeThermal_AMD_0Fh_PerPkg( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeThermal_AMD_0Fh(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeThermal_AMD_0Fh_Matrix[4])( struct FLIP_FLOP*,
							RO(SHM_STRUCT)*,
							unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeThermal_None,
	[FORMULA_SCOPE_SMT ] = ComputeThermal_AMD_0Fh_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeThermal_AMD_0Fh_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeThermal_AMD_0Fh_PerPkg
};

static void ComputeThermal_AMD_15h( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu )
{
    if (RO(Shm)->Cpu[cpu].Topology.CoreID == 0)
    {
	COMPUTE_THERMAL(AMD_15h,
			CFlip->Thermal.Temp,
			CFlip->Thermal.Param,
			CFlip->Thermal.Sensor);

	Core_ComputeThermalLimits(&RO(Shm)->Cpu[cpu], CFlip);
    }
}

#define ComputeThermal_AMD_15h_PerSMT	ComputeThermal_AMD_15h

static void ComputeThermal_AMD_15h_PerCore( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (RO(Shm)->Cpu[cpu].Topology.CoreID == 0)	/* Opteron use case */
	{
		ComputeThermal_AMD_15h(CFlip, RO(Shm), cpu);
	}
}

static void ComputeThermal_AMD_15h_PerPkg( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeThermal_AMD_15h(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeThermal_AMD_15h_Matrix[4])( struct FLIP_FLOP*,
							RO(SHM_STRUCT)*,
							unsigned int) = \
{
	[FORMULA_SCOPE_NONE] = ComputeThermal_None,
	[FORMULA_SCOPE_SMT ] = ComputeThermal_AMD_15h_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeThermal_AMD_15h_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeThermal_AMD_15h_PerPkg
};

static void ComputeThermal_AMD_17h( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu )
{
	COMPUTE_THERMAL(AMD_17h,
			CFlip->Thermal.Temp,
			CFlip->Thermal.Param,
			CFlip->Thermal.Sensor);

	Core_ComputeThermalLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeThermal_AMD_17h_PerSMT	ComputeThermal_AMD_17h

static void ComputeThermal_AMD_17h_PerCore( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeThermal_AMD_17h(CFlip, RO(Shm), cpu);
	}
}

static void ComputeThermal_AMD_17h_PerPkg( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeThermal_AMD_17h(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeThermal_AMD_17h_Matrix[4])(struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int) = \
{
	[FORMULA_SCOPE_NONE] = ComputeThermal_None,
	[FORMULA_SCOPE_SMT ] = ComputeThermal_AMD_17h_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeThermal_AMD_17h_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeThermal_AMD_17h_PerPkg
};

void Core_ComputeVoltageLimits(CPU_STRUCT *Cpu, struct FLIP_FLOP *CFlip)
{	/* Per Core, computes the Min CPU voltage.			*/
	TEST_AND_SET_SENSOR( VOLTAGE, LOWEST,	CFlip->Voltage.Vcore,
						Cpu->Sensors.Voltage.Limit );
	/* Per Core, computes the Max CPU voltage.			*/
	TEST_AND_SET_SENSOR( VOLTAGE, HIGHEST,	CFlip->Voltage.Vcore,
						Cpu->Sensors.Voltage.Limit );
}

static void ComputeVoltage_None( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu )
{
	UNUSED(CFlip);
	UNUSED(RO(Shm));
	UNUSED(cpu);
}

#define ComputeVoltage_None_PerSMT	ComputeVoltage_None
#define ComputeVoltage_None_PerCore	ComputeVoltage_None
#define ComputeVoltage_None_PerPkg	ComputeVoltage_None

static void (*ComputeVoltage_None_Matrix[4])(	struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_None_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_None_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_None_PerPkg
};

#define ComputeVoltage_Intel_Matrix	ComputeVoltage_None_Matrix

static void ComputeVoltage_Intel_Core2( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{	/* Intel Core 2 Extreme Datasheet Chap. 3.3-Table 2		*/
	COMPUTE_VOLTAGE(INTEL_CORE2,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_Intel_Core2_PerSMT	ComputeVoltage_Intel_Core2

static void ComputeVoltage_Intel_Core2_PerCore( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_Intel_Core2(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_Intel_Core2_PerPkg( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_Intel_Core2(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_Intel_Core2_Matrix[4])( struct FLIP_FLOP*,
							RO(SHM_STRUCT)*,
							unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_Intel_Core2_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_Intel_Core2_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_Intel_Core2_PerPkg
};

static void ComputeVoltage_Intel_SoC( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{	/* Intel Valleyview-D/M SoC					*/
	COMPUTE_VOLTAGE(INTEL_SOC,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_Intel_SoC_PerSMT	ComputeVoltage_Intel_SoC

static void ComputeVoltage_Intel_SoC_PerCore( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_Intel_SoC(CFlip, RO(Shm), cpu);
	}
}

static  void ComputeVoltage_Intel_SoC_PerPkg( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_Intel_SoC(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_Intel_SoC_Matrix[4])( struct FLIP_FLOP*,
							RO(SHM_STRUCT)*,
							unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_Intel_SoC_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_Intel_SoC_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_Intel_SoC_PerPkg
};

static void ComputeVoltage_Intel_SNB( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	COMPUTE_VOLTAGE(INTEL_SNB,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_Intel_SNB_PerSMT 	ComputeVoltage_Intel_SNB

static void ComputeVoltage_Intel_SNB_PerCore( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_Intel_SNB(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_Intel_SNB_PerPkg( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_Intel_SNB(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_Intel_SNB_Matrix[4])( struct FLIP_FLOP*,
							RO(SHM_STRUCT)*,
							unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_Intel_SNB_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_Intel_SNB_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_Intel_SNB_PerPkg
};

static void ComputeVoltage_Intel_SKL_X( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	COMPUTE_VOLTAGE(INTEL_SKL_X,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_Intel_SKL_X_PerSMT	ComputeVoltage_Intel_SKL_X

static void ComputeVoltage_Intel_SKL_X_PerCore( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_Intel_SKL_X(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_Intel_SKL_X_PerPkg( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_Intel_SKL_X(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_Intel_SKL_X_Matrix[4])( struct FLIP_FLOP*,
							RO(SHM_STRUCT)*,
							unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_Intel_SKL_X_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_Intel_SKL_X_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_Intel_SKL_X_PerPkg
};

static void ComputeVoltage_AMD( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu )
{
	COMPUTE_VOLTAGE(AMD,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_AMD_PerSMT	ComputeVoltage_AMD

static void ComputeVoltage_AMD_PerCore( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_AMD(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_AMD_PerPkg( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_AMD(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_AMD_Matrix[4])( struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_AMD_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_AMD_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_AMD_PerPkg
};

static void ComputeVoltage_AMD_0Fh( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{	/* AMD BKDG Family 0Fh Chap 10.6 Table 70			*/
	COMPUTE_VOLTAGE(AMD_0Fh,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_AMD_0Fh_PerSMT	ComputeVoltage_AMD_0Fh

static void ComputeVoltage_AMD_0Fh_PerCore( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_AMD_0Fh(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_AMD_0Fh_PerPkg( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_AMD_0Fh(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_AMD_0Fh_Matrix[4])(struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_AMD_0Fh_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_AMD_0Fh_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_AMD_0Fh_PerPkg
};

static void ComputeVoltage_AMD_15h( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu )
{
	COMPUTE_VOLTAGE(AMD_15h,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_AMD_15h_PerSMT	ComputeVoltage_AMD_15h

static void ComputeVoltage_AMD_15h_PerCore( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_AMD_15h(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_AMD_15h_PerPkg( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_AMD_15h(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_AMD_15h_Matrix[4])(struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_AMD_15h_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_AMD_15h_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_AMD_15h_PerPkg
};

static void ComputeVoltage_AMD_17h( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	COMPUTE_VOLTAGE(AMD_17h,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_AMD_17h_PerSMT	ComputeVoltage_AMD_17h

static void ComputeVoltage_AMD_17h_PerCore( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_AMD_17h(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_AMD_17h_PerPkg( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_AMD_17h(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_AMD_17h_Matrix[4])(struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_AMD_17h_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_AMD_17h_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_AMD_17h_PerPkg
};

static void ComputeVoltage_AMD_RMB( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	COMPUTE_VOLTAGE(AMD_RMB,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_AMD_RMB_PerSMT	ComputeVoltage_AMD_RMB

static void ComputeVoltage_AMD_RMB_PerCore( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_AMD_RMB(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_AMD_RMB_PerPkg( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_AMD_RMB(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_AMD_RMB_Matrix[4])(struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_AMD_RMB_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_AMD_RMB_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_AMD_RMB_PerPkg
};

static void ComputeVoltage_AMD_VCO( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	COMPUTE_VOLTAGE(AMD_VCO,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_AMD_VCO_PerSMT	ComputeVoltage_AMD_VCO

static void ComputeVoltage_AMD_VCO_PerCore( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_AMD_VCO(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_AMD_VCO_PerPkg( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_AMD_VCO(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_AMD_VCO_Matrix[4])(struct FLIP_FLOP*,
							RO(SHM_STRUCT)*,
							unsigned int) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_AMD_VCO_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_AMD_VCO_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_AMD_VCO_PerPkg
};

static void ComputeVoltage_Winbond_IO( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{	/* Winbond W83627EHF/EF, W83627EHG,EG				*/
	COMPUTE_VOLTAGE(WINBOND_IO,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_Winbond_IO_PerSMT	ComputeVoltage_Winbond_IO

static void ComputeVoltage_Winbond_IO_PerCore( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_Winbond_IO(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_Winbond_IO_PerPkg( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_Winbond_IO(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_Winbond_IO_Matrix[4])( struct FLIP_FLOP*,
							RO(SHM_STRUCT)*,
							unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_Winbond_IO_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_Winbond_IO_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_Winbond_IO_PerPkg
};

static void ComputeVoltage_ITE_Tech_IO( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{	/* ITE Tech IT8720F						*/
	COMPUTE_VOLTAGE(ITETECH_IO,
			CFlip->Voltage.Vcore,
			CFlip->Voltage.VID);

	Core_ComputeVoltageLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputeVoltage_ITE_Tech_IO_PerSMT	ComputeVoltage_ITE_Tech_IO

static void ComputeVoltage_ITE_Tech_IO_PerCore( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputeVoltage_ITE_Tech_IO(CFlip, RO(Shm), cpu);
	}
}

static void ComputeVoltage_ITE_Tech_IO_PerPkg( struct FLIP_FLOP *CFlip,
							RO(SHM_STRUCT) *RO(Shm),
							unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputeVoltage_ITE_Tech_IO(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputeVoltage_ITE_Tech_IO_Matrix[4])(	struct FLIP_FLOP*,
							RO(SHM_STRUCT)*,
							unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputeVoltage_None,
	[FORMULA_SCOPE_SMT ] = ComputeVoltage_ITE_Tech_IO_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputeVoltage_ITE_Tech_IO_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputeVoltage_ITE_Tech_IO_PerPkg
};

void Core_ComputePowerLimits(CPU_STRUCT *Cpu, struct FLIP_FLOP *CFlip)
{	/* Per Core, computes the Min CPU Energy consumed.		*/
	TEST_AND_SET_SENSOR( ENERGY, LOWEST,	CFlip->State.Energy,
						Cpu->Sensors.Energy.Limit );
	/* Per Core, computes the Max CPU Energy consumed.		*/
	TEST_AND_SET_SENSOR( ENERGY, HIGHEST,	CFlip->State.Energy,
						Cpu->Sensors.Energy.Limit );
	/* Per Core, computes the Min CPU Power consumed.		*/
	TEST_AND_SET_SENSOR( POWER, LOWEST,	CFlip->State.Power,
						Cpu->Sensors.Power.Limit);
	/* Per Core, computes the Max CPU Power consumed.		*/
	TEST_AND_SET_SENSOR( POWER, HIGHEST,	CFlip->State.Power,
						Cpu->Sensors.Power.Limit );
}

static void ComputePower_None( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu )
{
	UNUSED(CFlip);
	UNUSED(RO(Shm));
	UNUSED(cpu);
}

#define ComputePower_None_PerSMT	ComputePower_None
#define ComputePower_None_PerCore	ComputePower_None
#define ComputePower_None_PerPkg	ComputePower_None

static void (*ComputePower_None_Matrix[4])(	struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputePower_None,
	[FORMULA_SCOPE_SMT ] = ComputePower_None_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputePower_None_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputePower_None_PerPkg
};

#define ComputePower_Intel_Matrix	ComputePower_None_Matrix

#define ComputePower_Intel_Atom_Matrix	ComputePower_None_Matrix

#define ComputePower_AMD_Matrix 	ComputePower_None_Matrix

static void ComputePower_AMD_17h( struct FLIP_FLOP *CFlip,
					RO(SHM_STRUCT) *RO(Shm),
					unsigned int cpu)
{
	CFlip->State.Energy	= (double)CFlip->Delta.Power.ACCU
				* RO(Shm)->Proc.Power.Unit.Joules;

	CFlip->State.Power	= 1000.0 * CFlip->State.Energy;
	CFlip->State.Power	/= RO(Shm)->Sleep.Interval;

	Core_ComputePowerLimits(&RO(Shm)->Cpu[cpu], CFlip);
}

#define ComputePower_AMD_17h_PerSMT	ComputePower_AMD_17h

static void ComputePower_AMD_17h_PerCore( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if ((RO(Shm)->Cpu[cpu].Topology.ThreadID == 0)
	 || (RO(Shm)->Cpu[cpu].Topology.ThreadID == -1))
	{
		ComputePower_AMD_17h(CFlip, RO(Shm), cpu);
	}
}

static void ComputePower_AMD_17h_PerPkg( struct FLIP_FLOP *CFlip,
						RO(SHM_STRUCT) *RO(Shm),
						unsigned int cpu )
{
	if (cpu == RO(Shm)->Proc.Service.Core)
	{
		ComputePower_AMD_17h(CFlip, RO(Shm), cpu);
	}
}

static void (*ComputePower_AMD_17h_Matrix[4])(	struct FLIP_FLOP*,
						RO(SHM_STRUCT)*,
						unsigned int ) = \
{
	[FORMULA_SCOPE_NONE] = ComputePower_None,
	[FORMULA_SCOPE_SMT ] = ComputePower_AMD_17h_PerSMT,
	[FORMULA_SCOPE_CORE] = ComputePower_AMD_17h_PerCore,
	[FORMULA_SCOPE_PKG ] = ComputePower_AMD_17h_PerPkg
};


typedef struct {
	REF		*Ref;
	unsigned int	Bind;
	pthread_t	TID;
} ARG;

static void *Core_Cycle(void *arg)
{
	ARG		*Arg		= (ARG *) arg;
	unsigned int	cpu		= Arg->Bind;
	RO(SHM_STRUCT)	*RO(Shm)	= Arg->Ref->RO(Shm);
	RO(CORE)	*RO(Core)	= Arg->Ref->RO(Core, AT(cpu));
	RW(CORE)	*RW(Core)	= Arg->Ref->RW(Core, AT(cpu));
	CPU_STRUCT	*Cpu		= &RO(Shm)->Cpu[cpu];

	pthread_t tid = pthread_self();
	cpu_set_t cpuset;
	CPU_ZERO(&cpuset);
	CPU_SET(cpu, &cpuset);
	if (pthread_setaffinity_np(tid, sizeof(cpu_set_t), &cpuset) != 0) {
		goto EXIT;
	}
	char *comm = malloc(TASK_COMM_LEN+10+1);
	if (comm != NULL) {
		snprintf(comm, TASK_COMM_LEN+10+1, "corefreqd/%u", cpu);
		pthread_setname_np(tid, comm);
		free(comm);
	}

	void (**ComputeThermalFormula)( struct FLIP_FLOP*,
					RO(SHM_STRUCT)*,
					unsigned int );

	void (**ComputeVoltageFormula)( struct FLIP_FLOP*,
					RO(SHM_STRUCT)*,
					unsigned int );

	void (**ComputePowerFormula)(	struct FLIP_FLOP*,
					RO(SHM_STRUCT)*,
					unsigned int );

	switch (KIND_OF_FORMULA(RO(Shm)->Proc.thermalFormula)) {
	case THERMAL_KIND_INTEL:
		ComputeThermalFormula = ComputeThermal_Intel_Matrix;
		break;
	case THERMAL_KIND_AMD:
		ComputeThermalFormula = ComputeThermal_AMD_Matrix;
		break;
	case THERMAL_KIND_AMD_0Fh:
		ComputeThermalFormula = ComputeThermal_AMD_0Fh_Matrix;
		break;
	case THERMAL_KIND_AMD_15h:
		ComputeThermalFormula = ComputeThermal_AMD_15h_Matrix;
		break;
	case THERMAL_KIND_AMD_17h:
		ComputeThermalFormula = ComputeThermal_AMD_17h_Matrix;
		break;
	case THERMAL_KIND_NONE:
	default:
		ComputeThermalFormula = ComputeThermal_None_Matrix;
		break;
	}

	switch (KIND_OF_FORMULA(RO(Shm)->Proc.voltageFormula)) {
	case VOLTAGE_KIND_INTEL:
		ComputeVoltageFormula = ComputeVoltage_Intel_Matrix;
		break;
	case VOLTAGE_KIND_INTEL_CORE2:
		ComputeVoltageFormula = ComputeVoltage_Intel_Core2_Matrix;
		break;
	case VOLTAGE_KIND_INTEL_SOC:
		ComputeVoltageFormula = ComputeVoltage_Intel_SoC_Matrix;
		break;
	case VOLTAGE_KIND_INTEL_SNB:
	case VOLTAGE_KIND_INTEL_SAV:
		ComputeVoltageFormula = ComputeVoltage_Intel_SNB_Matrix;
		break;
	case VOLTAGE_KIND_INTEL_SKL_X:
		ComputeVoltageFormula = ComputeVoltage_Intel_SKL_X_Matrix;
		break;
	case VOLTAGE_KIND_AMD:
		ComputeVoltageFormula = ComputeVoltage_AMD_Matrix;
		break;
	case VOLTAGE_KIND_AMD_0Fh:
		ComputeVoltageFormula = ComputeVoltage_AMD_0Fh_Matrix;
		break;
	case VOLTAGE_KIND_AMD_15h:
		ComputeVoltageFormula = ComputeVoltage_AMD_15h_Matrix;
		break;
	case VOLTAGE_KIND_AMD_17h:
		ComputeVoltageFormula = ComputeVoltage_AMD_17h_Matrix;
		break;
	case VOLTAGE_KIND_AMD_RMB:
		ComputeVoltageFormula = ComputeVoltage_AMD_RMB_Matrix;
		break;
	case VOLTAGE_KIND_ZEN3_VCO:
		ComputeVoltageFormula = ComputeVoltage_AMD_VCO_Matrix;
		break;
	case VOLTAGE_KIND_ZEN4_VCO:
		ComputeVoltageFormula = ComputeVoltage_AMD_VCO_Matrix;
		break;
	case VOLTAGE_KIND_ZEN5_VCO:
		ComputeVoltageFormula = ComputeVoltage_AMD_VCO_Matrix;
		break;
	case VOLTAGE_KIND_WINBOND_IO:
		ComputeVoltageFormula = ComputeVoltage_Winbond_IO_Matrix;
		break;
	case VOLTAGE_KIND_ITETECH_IO:
		ComputeVoltageFormula = ComputeVoltage_ITE_Tech_IO_Matrix;
		break;
	case VOLTAGE_KIND_NONE:
	default:
		ComputeVoltageFormula = ComputeVoltage_None_Matrix;
		break;
	}

	switch (KIND_OF_FORMULA(RO(Shm)->Proc.powerFormula)) {
	case POWER_KIND_INTEL:
		ComputePowerFormula = ComputePower_Intel_Matrix;
		break;
	case POWER_KIND_INTEL_ATOM:
		ComputePowerFormula = ComputePower_Intel_Atom_Matrix;
		break;
	case POWER_KIND_AMD:
		ComputePowerFormula = ComputePower_AMD_Matrix;
		break;
	case POWER_KIND_AMD_17h:
		ComputePowerFormula = ComputePower_AMD_17h_Matrix;
		break;
	case POWER_KIND_NONE:
	default:
		ComputePowerFormula = ComputePower_None_Matrix;
		break;
	}

	if (Quiet & 0x100) {
		printf("    Thread [%lx] Init CYCLE %03u\n", (long) tid, cpu);
		fflush(stdout);
	}
	BITSET_CC(BUS_LOCK, roomSeed, cpu);
	BITSET_CC(BUS_LOCK, roomCore, cpu);

  do {
    while (!BITCLR(LOCKLESS, RW(Core)->Sync.V, NTFY)
	&& !BITVAL(Shutdown, SYNC)
	&& !BITVAL(RO(Core)->OffLine, OS)) {
		nanosleep(&RO(Shm)->Sleep.pollingWait, NULL);
    }

    if (!BITVAL(Shutdown, SYNC) && !BITVAL(RO(Core)->OffLine, OS))
    {
	if (BITCLR_CC(BUS_LOCK, roomCore, cpu)) {
		Cpu->Toggle = !Cpu->Toggle;
	}
	struct FLIP_FLOP *CFlip = &Cpu->FlipFlop[Cpu->Toggle];

	/* Refresh this Base Clock.					*/
	CFlip->Clock.Q  = RO(Core)->Clock.Q;
	CFlip->Clock.R  = RO(Core)->Clock.R;
	CFlip->Clock.Hz = RO(Core)->Clock.Hz;

	/* Copy the Performance & C-States Counters.			*/
	CFlip->Delta.INST	= RO(Core)->Delta.INST;
	CFlip->Delta.C0.UCC	= RO(Core)->Delta.C0.UCC;
	CFlip->Delta.C0.URC	= RO(Core)->Delta.C0.URC;
	CFlip->Delta.C3 	= RO(Core)->Delta.C3;
	CFlip->Delta.C6 	= RO(Core)->Delta.C6;
	CFlip->Delta.C7 	= RO(Core)->Delta.C7;
	CFlip->Delta.TSC	= RO(Core)->Delta.TSC;
	CFlip->Delta.C1 	= RO(Core)->Delta.C1;

	/* Update all clock ratios.					*/
	memcpy(Cpu->Boost, RO(Core)->Boost, (BOOST(SIZE))*sizeof(unsigned int));

	CFlip->Absolute.Ratio.Perf = (double)RO(Core)->Ratio.COF.Q;
	CFlip->Absolute.Ratio.Perf +=(double)RO(Core)->Ratio.COF.R /UNIT_KHz(1);

	/* Compute IPS=Instructions per TSC				*/
	CFlip->State.IPS = (double)CFlip->Delta.INST
			 / (double)CFlip->Delta.TSC;

	/* Compute IPC=Instructions per non-halted reference cycle.
	   ( Protect against a division by zero )			*/
	if (CFlip->Delta.C0.URC != 0) {
		CFlip->State.IPC = (double)CFlip->Delta.INST
				 / (double)CFlip->Delta.C0.URC;
	} else {
		CFlip->State.IPC = 0.0f;
	}
	/* Compute CPI=Non-halted reference cycles per instruction.
	   ( Protect against a division by zero )			*/
	if (CFlip->Delta.INST != 0) {
		CFlip->State.CPI = (double)CFlip->Delta.C0.URC
				 / (double)CFlip->Delta.INST;
	} else {
		CFlip->State.CPI = 0.0f;
	}
	/* Compute the Turbo State.					*/
	CFlip->State.Turbo	= (double)CFlip->Delta.C0.UCC
				/ (double)CFlip->Delta.TSC;

	/* Compute the C-States.					*/
	CFlip->State.C0 = (double)CFlip->Delta.C0.URC
			/ (double)CFlip->Delta.TSC;

	CFlip->State.C3 = (double)CFlip->Delta.C3
			/ (double)CFlip->Delta.TSC;

	CFlip->State.C6 = (double)CFlip->Delta.C6
			/ (double)CFlip->Delta.TSC;

	CFlip->State.C7 = (double)CFlip->Delta.C7
			/ (double)CFlip->Delta.TSC;

	CFlip->State.C1 = (double)CFlip->Delta.C1
			/ (double)CFlip->Delta.TSC;

	/* Relative Frequency = Relative Ratio x Bus Clock Frequency	*/
	CFlip->Relative.Ratio	= (double)(CFlip->Delta.C0.UCC
					* Cpu->Boost[BOOST(MAX)])
				/ (double)CFlip->Delta.TSC;

	CFlip->Relative.Freq	= REL_FREQ_MHz( double,
						CFlip->Relative.Ratio,
						CFlip->Clock,
						RO(Shm)->Sleep.Interval );

	/* Per Core, compute the Relative Frequency limits.		*/
	TEST_AND_SET_SENSOR( REL_FREQ, LOWEST,	CFlip->Relative.Freq,
						Cpu->Relative.Freq );

	TEST_AND_SET_SENSOR( REL_FREQ, HIGHEST, CFlip->Relative.Freq,
						Cpu->Relative.Freq );
	/* Per Core, compute the Absolute Frequency limits.		*/
	CFlip->Absolute.Freq = ABS_FREQ_MHz(double, CFlip->Absolute.Ratio.Perf,
						(double)CFlip->Clock);

	TEST_AND_SET_SENSOR( ABS_FREQ, LOWEST,	CFlip->Absolute.Freq,
						Cpu->Absolute.Freq );

	TEST_AND_SET_SENSOR( ABS_FREQ, HIGHEST, CFlip->Absolute.Freq,
						Cpu->Absolute.Freq );
	/* Core Processor events					*/
	memcpy( CFlip->Thermal.Events, RO(Core)->PowerThermal.Events,
		sizeof(CFlip->Thermal.Events) );
	/* Per Core, evaluate thermal properties.			*/
	CFlip->Thermal.Sensor	= RO(Core)->PowerThermal.Sensor;
	CFlip->Thermal.Param	= RO(Core)->PowerThermal.Param;

	ComputeThermalFormula[SCOPE_OF_FORMULA(RO(Shm)->Proc.thermalFormula)](
		CFlip, RO(Shm), cpu
	);

	/* Per Core, evaluate the voltage properties.			*/
	CFlip->Voltage.VID = RO(Core)->PowerThermal.VID;

	ComputeVoltageFormula[SCOPE_OF_FORMULA(RO(Shm)->Proc.voltageFormula)](
		CFlip, RO(Shm), cpu
	);

	/* Per Core, evaluate the Power properties.			*/
	CFlip->Delta.Power.ACCU = RO(Core)->Delta.Power.ACCU;

	ComputePowerFormula[SCOPE_OF_FORMULA(RO(Shm)->Proc.powerFormula)](
		CFlip, RO(Shm), cpu
	);

	/* Copy the Interrupts counters.				*/
	CFlip->Counter.SMI = RO(Core)->Interrupt.SMI;

	/* If driver registered, copy any NMI counter.			*/
	if (BITVAL(RO(Shm)->Registration.NMI, BIT_NMI_LOCAL) == 1) {
		CFlip->Counter.NMI.LOCAL   = RO(Core)->Interrupt.NMI.LOCAL;
	}
	if (BITVAL(RO(Shm)->Registration.NMI, BIT_NMI_UNKNOWN) == 1) {
		CFlip->Counter.NMI.UNKNOWN = RO(Core)->Interrupt.NMI.UNKNOWN;
	}
	if (BITVAL(RO(Shm)->Registration.NMI, BIT_NMI_SERR) == 1) {
		CFlip->Counter.NMI.PCISERR = RO(Core)->Interrupt.NMI.PCISERR;
	}
	if (BITVAL(RO(Shm)->Registration.NMI, BIT_NMI_IO_CHECK) == 1) {
		CFlip->Counter.NMI.IOCHECK = RO(Core)->Interrupt.NMI.IOCHECK;
	}
    }
  } while (!BITVAL(Shutdown, SYNC) && !BITVAL(RO(Core)->OffLine, OS)) ;

	BITCLR_CC(BUS_LOCK, roomCore, cpu);
	BITCLR_CC(BUS_LOCK, roomSeed, cpu);
EXIT:
	if (Quiet & 0x100) {
		printf("    Thread [%lx] %s CYCLE %03u\n", (long) tid,
			BITVAL(RO(Core)->OffLine, OS) ? "Offline" : "Shutdown",
			cpu);
		fflush(stdout);
	}
	return NULL;
}

void SliceScheduling(	RO(SHM_STRUCT) *RO(Shm),
			unsigned int cpu, enum PATTERN pattern )
{
	unsigned int seek = 0;
	switch (pattern) {
	case RESET_CSP:
		for (seek = 0; seek < RO(Shm)->Proc.CPU.Count; seek++) {
			if (seek == RO(Shm)->Proc.Service.Core) {
				BITSET_CC(LOCKLESS, RO(Shm)->roomSched, seek);
			} else {
				BITCLR_CC(LOCKLESS, RO(Shm)->roomSched, seek);
			}
		}
		break;
	case ALL_SMT:
		if (cpu == RO(Shm)->Proc.Service.Core) {
			BITSTOR_CC(LOCKLESS, RO(Shm)->roomSched, roomSeed);
		}
		break;
	case RAND_SMT:
		do {
		  #ifdef __GLIBC__
		    if (random_r(&RO(Shm)->Cpu[cpu].Slice.Random.data,
				&RO(Shm)->Cpu[cpu].Slice.Random.value[0]) == 0)
		  #else
		    RO(Shm)->Cpu[cpu].Slice.Random.value[0] = (int) random();
		  #endif /* __GLIBC__ */
		    {
			seek = RO(Shm)->Cpu[cpu].Slice.Random.value[0]
				% RO(Shm)->Proc.CPU.Count;
		    }
		} while (BITVAL(RO(Shm)->Cpu[seek].OffLine, OS));
		BITCLR_CC(LOCKLESS, RO(Shm)->roomSched, cpu);
		BITSET_CC(LOCKLESS, RO(Shm)->roomSched, seek);
		break;
	case RR_SMT:
		seek = cpu;
		do {
			seek++;
			if (seek >= RO(Shm)->Proc.CPU.Count) {
				seek = 0;
			}
		} while (BITVAL(RO(Shm)->Cpu[seek].OffLine, OS));
		BITCLR_CC(LOCKLESS, RO(Shm)->roomSched, cpu);
		BITSET_CC(LOCKLESS, RO(Shm)->roomSched, seek);
		break;
	case USR_CPU:
		/*	NOP	*/
		break;
	}
}

static void *Child_Thread(void *arg)
{
	ARG *Arg	= (ARG *) arg;
	unsigned int cpu = Arg->Bind;

	RO(SHM_STRUCT) *RO(Shm) = Arg->Ref->RO(Shm);
	RW(SHM_STRUCT) *RW(Shm) = Arg->Ref->RW(Shm);
	CPU_STRUCT *Cpu = &RO(Shm)->Cpu[cpu];

	CALL_FUNC MatrixCallFunc[2][2] = {
		{ CallWith_RDTSC_No_RDPMC,  CallWith_RDTSC_RDPMC  },
		{ CallWith_RDTSCP_No_RDPMC, CallWith_RDTSCP_RDPMC }
	};
	const int withTSCP = ((RO(Shm)->Proc.Features.AdvPower.EDX.Inv_TSC == 1)
			   || (RO(Shm)->Proc.Features.ExtInfo.EDX.RDTSCP == 1)),
		withRDPMC=((RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_INTEL)
			  && (RO(Shm)->Proc.PM_version >= 1)
			  && (BITVAL(Cpu->SystemRegister.CR4, CR4_PCE) == 1));

	CALL_FUNC CallSliceFunc = MatrixCallFunc[withTSCP][withRDPMC];

	pthread_t tid = pthread_self();
	cpu_set_t cpuset;
	CPU_ZERO(&cpuset);
	CPU_SET(cpu, &cpuset);
	if (pthread_setaffinity_np(tid, sizeof(cpu_set_t), &cpuset) != 0) {
		goto EXIT;
	}
	char *comm = malloc(TASK_COMM_LEN+10+1);
	if (comm != NULL) {
		snprintf(comm, TASK_COMM_LEN+10+1, "corefreqd#%u", cpu);
		pthread_setname_np(tid, comm);
		free(comm);
	}
	if (Quiet & 0x100) {
		printf("    Thread [%lx] Init CHILD %03u\n", (long) tid, cpu);
		fflush(stdout);
	}

	BITSET_CC(BUS_LOCK, roomSeed, cpu);

    do {
	while (!BITVAL(RW(Shm)->Proc.Sync, BURN)
	    && !BITVAL(Shutdown, SYNC)
	    && !BITVAL(Cpu->OffLine, OS)) {
		nanosleep(&RO(Shm)->Sleep.sliceWaiting, NULL);
	}

	BITSET_CC(BUS_LOCK, roomCore, cpu);

	RESET_Slice(Cpu->Slice);

	while ( BITVAL(RW(Shm)->Proc.Sync, BURN)
	    && !BITVAL(Shutdown, SYNC) )
	{
	    if (BITVAL_CC(RO(Shm)->roomSched, cpu)) {
		CallSliceFunc(	RO(Shm), RW(Shm), cpu,
				Arg->Ref->Slice.Func,
				Arg->Ref->Slice.arg);

		SliceScheduling(RO(Shm), cpu, Arg->Ref->Slice.pattern);

	      if (BITVAL(Cpu->OffLine, OS)) {	/* ReSchedule to Service */
		SliceScheduling(RO(Shm), RO(Shm)->Proc.Service.Core, RESET_CSP);
		break;
	      }
	    } else {
		nanosleep(&RO(Shm)->Sleep.sliceWaiting, NULL);

		if (BITVAL(Cpu->OffLine, OS)) {
			break;
		}
	    }
	}

	BITCLR_CC(BUS_LOCK, roomCore, cpu);

    } while (!BITVAL(Shutdown, SYNC) && !BITVAL(Cpu->OffLine, OS)) ;

	BITCLR_CC(BUS_LOCK, roomSeed, cpu);

	RESET_Slice(Cpu->Slice);
EXIT:
	if (Quiet & 0x100) {
		printf("    Thread [%lx] %s CHILD %03u\n", (long) tid,
			BITVAL(Cpu->OffLine, OS) ? "Offline" : "Shutdown",cpu);
		fflush(stdout);
	}
	return NULL;
}

void Architecture(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	signed long ix;
	Bit32	fTSC = RO(Proc)->Features.Std.EDX.TSC,
		aTSC = RO(Proc)->Features.AdvPower.EDX.Inv_TSC;

	/*	Copy all initial CPUID features.			*/
	memcpy(&RO(Shm)->Proc.Features, &RO(Proc)->Features, sizeof(FEATURES));
	/*	Copy the fomula identifiers				*/
	RO(Shm)->Proc.thermalFormula = RO(Proc)->thermalFormula;
	RO(Shm)->Proc.voltageFormula = RO(Proc)->voltageFormula;
	RO(Shm)->Proc.powerFormula   = RO(Proc)->powerFormula;
	/*	Copy the numbers of total & online CPU.			*/
	RO(Shm)->Proc.CPU.Count	= RO(Proc)->CPU.Count;
	RO(Shm)->Proc.CPU.OnLine	= RO(Proc)->CPU.OnLine;
	RO(Shm)->Proc.Service.Proc	= RO(Proc)->Service.Proc;
	/*	Architecture and Hypervisor identifiers.		*/
	RO(Shm)->Proc.ArchID = RO(Proc)->ArchID;
	RO(Shm)->Proc.HypervisorID = RO(Proc)->HypervisorID;
	/*	Copy the Architecture name.				*/
	StrCopy(RO(Shm)->Proc.Architecture,RO(Proc)->Architecture,CODENAME_LEN);
	/*	Make the processor's brand string with no trailing spaces */
	ix = BRAND_LENGTH;
	do {
		if ((RO(Proc)->Features.Info.Brand[ix] == 0x20)
		 || (RO(Proc)->Features.Info.Brand[ix] == 0x0)) {
			ix--;
		} else {
			break;
		}
	} while (ix != 0);
	RO(Shm)->Proc.Brand[1 + ix] = '\0';
	for (; ix >= 0; ix--) {
		RO(Shm)->Proc.Brand[ix] = RO(Proc)->Features.Info.Brand[ix];
	}
	/*	Compute the TSC mode: None, Variant, Invariant		*/
	RO(Shm)->Proc.Features.InvariantTSC = fTSC << aTSC;
}

void PerformanceMonitoring(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	RO(Shm)->Proc.PM_version = RO(Proc)->Features.PerfMon.EAX.Version;
}

void HyperThreading(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{	/*	Update the HyperThreading state.			*/
	RO(Shm)->Proc.Features.HyperThreading = RO(Proc)->Features.HTT_Enable;
}

double ComputeTAU(unsigned char Y, unsigned char Z, double TU)
{
	return COMPUTE_TAU(Y, Z, TU);
}

void PowerInterface(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short pwrUnits = 0, pwrVal;
	enum PWR_DOMAIN pw;

    switch (KIND_OF_FORMULA(RO(Proc)->powerFormula)) {
    case POWER_KIND_INTEL:
    case POWER_KIND_AMD:
    case POWER_KIND_AMD_17h:
	RO(Shm)->Proc.Power.Unit.Watts = RO(Proc)->PowerThermal.Unit.PU > 0 ?
		1.0 / (double) (1 << RO(Proc)->PowerThermal.Unit.PU) : 0;

	RO(Shm)->Proc.Power.Unit.Joules= RO(Proc)->PowerThermal.Unit.ESU > 0 ?
		1.0 / (double) (1 << RO(Proc)->PowerThermal.Unit.ESU) :0;
      TIME_UNIT:
	RO(Shm)->Proc.Power.Unit.Times = RO(Proc)->PowerThermal.Unit.TU > 0 ?
			1.0 / (double) (1 << RO(Proc)->PowerThermal.Unit.TU)
			: 1.0 / (double) (1 << 10);

	pwrUnits = 2 << (RO(Proc)->PowerThermal.Unit.PU - 1);
	break;
    case POWER_KIND_INTEL_ATOM:
	RO(Shm)->Proc.Power.Unit.Watts = RO(Proc)->PowerThermal.Unit.PU > 0 ?
		0.001 / (double) (1 << RO(Proc)->PowerThermal.Unit.PU) : 0;

	RO(Shm)->Proc.Power.Unit.Joules= RO(Proc)->PowerThermal.Unit.ESU > 0 ?
		0.001 / (double) (1 << RO(Proc)->PowerThermal.Unit.ESU) : 0;
	goto TIME_UNIT;
	break;
    case POWER_KIND_NONE:
	break;
    }
  if (	(RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_AMD)
  ||	(RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_HYGON) )
  { /* AMD PowerNow */
	if (RO(Proc)->Features.AdvPower.EDX.FID) {
		BITSET(LOCKLESS, RO(Shm)->Proc.PowerNow, 0);
	} else {
		BITCLR(LOCKLESS, RO(Shm)->Proc.PowerNow, 0);
	}
	if (RO(Proc)->Features.AdvPower.EDX.VID) {
		BITSET(LOCKLESS, RO(Shm)->Proc.PowerNow, 1);
	} else {
		BITCLR(LOCKLESS, RO(Shm)->Proc.PowerNow, 1);
	}
	if((RO(Shm)->Proc.Features.ACPI_PCT_CAP && RO(Proc)->Features.ACPI_PCT)
	|| (RO(Shm)->Proc.Features.ACPI_PSS_CAP && RO(Proc)->Features.ACPI_PSS))
	{
		BITSET(LOCKLESS, RO(Shm)->Proc.PowerNow, 0);
		BITSET(LOCKLESS, RO(Shm)->Proc.PowerNow, 1);
	}
	RO(Shm)->Proc.Power.PPT = RO(Proc)->PowerThermal.Zen.PWR.PPT;
	RO(Shm)->Proc.Power.TDP = RO(Proc)->PowerThermal.Zen.TDP.TDP;
	RO(Shm)->Proc.Power.Min = RO(Proc)->PowerThermal.Zen.TDP.TDP2;
	RO(Shm)->Proc.Power.Max = RO(Proc)->PowerThermal.Zen.TDP.TDP3;
	RO(Shm)->Proc.Power.EDC = RO(Proc)->PowerThermal.Zen.EDC.EDC << 2;
	RO(Shm)->Proc.Power.TDC = RO(Proc)->PowerThermal.Zen.EDC.TDC;

      for (pw = PWR_DOMAIN(PKG); pw < PWR_DOMAIN(SIZE); pw++)
      {
	RO(Shm)->Proc.Power.Domain[pw].Feature[PL1].Enable = \
		RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Enable_Limit1;

	RO(Shm)->Proc.Power.Domain[pw].Feature[PL2].Enable = \
		RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Enable_Limit2;

	RO(Shm)->Proc.Power.Domain[pw].Feature[PL1].Clamping = \
			RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Clamping1;

	RO(Shm)->Proc.Power.Domain[pw].Feature[PL2].Clamping = \
			RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Clamping2;

	pwrVal = RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Domain_Limit1;
	RO(Shm)->Proc.Power.Domain[pw].PWL[PL1] = pwrVal;

	pwrVal = RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Domain_Limit2;
	RO(Shm)->Proc.Power.Domain[pw].PWL[PL2] = pwrVal;

	RO(Shm)->Proc.Power.Domain[pw].Feature[PL1].Unlock = \
	RO(Shm)->Proc.Power.Domain[pw].Feature[PL2].Unlock = \
				RO(Proc)->PowerThermal.Domain[pw].Unlock;
      }
  }
  else if (RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_INTEL)
  {
    if (pwrUnits != 0)
    {
      for (pw = PWR_DOMAIN(PKG); pw < PWR_DOMAIN(SIZE); pw++)
      {
	RO(Shm)->Proc.Power.Domain[pw].Feature[PL1].Enable = \
		RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Enable_Limit1;

	RO(Shm)->Proc.Power.Domain[pw].Feature[PL2].Enable = \
		RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Enable_Limit2;

	RO(Shm)->Proc.Power.Domain[pw].Feature[PL1].Clamping = \
		RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Clamping1;

	RO(Shm)->Proc.Power.Domain[pw].Feature[PL2].Clamping = \
		RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Clamping2;

	pwrVal	= RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Domain_Limit1
		/ pwrUnits;
	RO(Shm)->Proc.Power.Domain[pw].PWL[PL1] = pwrVal;

	pwrVal	= RO(Proc)->PowerThermal.Domain[pw].PowerLimit.Domain_Limit2
		/ pwrUnits;
	RO(Shm)->Proc.Power.Domain[pw].PWL[PL2] = pwrVal;
      }
	pwrVal = RO(Proc)->PowerThermal.PowerInfo.ThermalSpecPower / pwrUnits;
	RO(Shm)->Proc.Power.TDP = pwrVal;

	pwrVal = RO(Proc)->PowerThermal.PowerInfo.MinimumPower / pwrUnits;
	RO(Shm)->Proc.Power.Min = pwrVal;

	pwrVal = RO(Proc)->PowerThermal.PowerInfo.MaximumPower / pwrUnits;
	RO(Shm)->Proc.Power.Max = pwrVal;
    }
    for (pw = PWR_DOMAIN(PKG); pw < PWR_DOMAIN(SIZE); pw++)
    {
	RO(Shm)->Proc.Power.Domain[pw].Feature[PL1].TW = \
		RO(Proc)->PowerThermal.Domain[pw].PowerLimit.TimeWindow1;

	RO(Shm)->Proc.Power.Domain[pw].Feature[PL2].TW = \
		RO(Proc)->PowerThermal.Domain[pw].PowerLimit.TimeWindow2;

	RO(Shm)->Proc.Power.Domain[pw].TAU[PL1] = ComputeTAU(
		RO(Shm)->Proc.Power.Domain[pw].Feature[PL1].TW_Y,
		RO(Shm)->Proc.Power.Domain[pw].Feature[PL1].TW_Z,
		RO(Shm)->Proc.Power.Unit.Times
	);

	RO(Shm)->Proc.Power.Domain[pw].TAU[PL2] = ComputeTAU(
		RO(Shm)->Proc.Power.Domain[pw].Feature[PL2].TW_Y,
		RO(Shm)->Proc.Power.Domain[pw].Feature[PL2].TW_Z,
		RO(Shm)->Proc.Power.Unit.Times
	);

	RO(Shm)->Proc.Power.Domain[pw].Feature[PL1].Unlock = \
	RO(Shm)->Proc.Power.Domain[pw].Feature[PL2].Unlock = \
				RO(Proc)->PowerThermal.Domain[pw].Unlock;
    }
	RO(Shm)->Proc.Power.TDC = RO(Proc)->PowerThermal.TDC;
	RO(Shm)->Proc.Power.Feature.TDC=RO(Proc)->PowerThermal.Enable_Limit.TDC;
  } else {
	RO(Shm)->Proc.PowerNow = 0;
  }
}

void ThermalPoint(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	memcpy(&RO(Shm)->Proc.ThermalPoint, &RO(Proc)->ThermalPoint,
		sizeof(THERMAL_POINT));
}

void Technology_Update( RO(SHM_STRUCT) *RO(Shm),
			RO(PROC) *RO(Proc), RW(PROC) *RW(Proc) )
{	/*	Technologies aggregation.				*/
	RO(Shm)->Proc.Technology.PowerNow = (RO(Shm)->Proc.PowerNow == 0b11);

	RO(Shm)->Proc.Technology.ODCM = BITCMP_CC(BUS_LOCK,
						RW(Proc)->ODCM,
						RO(Proc)->ODCM_Mask);

	RO(Shm)->Proc.Technology.L1_HW_Prefetch = BITCMP_CC(BUS_LOCK,
						RW(Proc)->L1_HW_Prefetch,
						RO(Proc)->DCU_Mask);

	RO(Shm)->Proc.Technology.L1_HW_IP_Prefetch = BITCMP_CC(BUS_LOCK,
						RW(Proc)->L1_HW_IP_Prefetch,
						RO(Proc)->DCU_Mask);

	RO(Shm)->Proc.Technology.L1_NPP_Prefetch = BITCMP_CC(BUS_LOCK,
						RW(Proc)->L1_NPP_Prefetch,
						RO(Proc)->DCU_Mask);

	RO(Shm)->Proc.Technology.L1_Scrubbing = BITWISEAND_CC(BUS_LOCK,
						RW(Proc)->L1_Scrubbing,
						RO(Proc)->L1_Scrub_Mask) != 0;

	RO(Shm)->Proc.Technology.L2_HW_Prefetch = BITCMP_CC(BUS_LOCK,
						RW(Proc)->L2_HW_Prefetch,
						RO(Proc)->DCU_Mask);

	RO(Shm)->Proc.Technology.L2_HW_CL_Prefetch = BITCMP_CC(BUS_LOCK,
						RW(Proc)->L2_HW_CL_Prefetch,
						RO(Proc)->DCU_Mask);

	RO(Shm)->Proc.Technology.L2_AMP_Prefetch = BITWISEAND_CC(BUS_LOCK,
						RW(Proc)->L2_AMP_Prefetch,
						RO(Proc)->L2_AMP_Mask) != 0;

	RO(Shm)->Proc.Technology.L2_NLP_Prefetch = BITWISEAND_CC(BUS_LOCK,
						RW(Proc)->L2_NLP_Prefetch,
						RO(Proc)->ECORE_Mask) != 0;

	RO(Shm)->Proc.Technology.L1_Stride_Pf	= BITCMP_CC(BUS_LOCK,
						RW(Proc)->L1_Stride_Pf,
						RO(Proc)->DCU_Mask);

	RO(Shm)->Proc.Technology.L1_Region_Pf	= BITCMP_CC(BUS_LOCK,
						RW(Proc)->L1_Region_Pf,
						RO(Proc)->DCU_Mask);

	RO(Shm)->Proc.Technology.L1_Burst_Pf	= BITCMP_CC(BUS_LOCK,
						RW(Proc)->L1_Burst_Pf,
						RO(Proc)->DCU_Mask);

	RO(Shm)->Proc.Technology.L2_Stream_HW_Pf = BITCMP_CC(BUS_LOCK,
						RW(Proc)->L2_Stream_HW_Pf,
						RO(Proc)->DCU_Mask);

	RO(Shm)->Proc.Technology.L2_UpDown_Pf	= BITCMP_CC(BUS_LOCK,
						RW(Proc)->L2_UpDown_Pf,
						RO(Proc)->DCU_Mask);

	RO(Shm)->Proc.Technology.LLC_Streamer = BITWISEAND_CC(BUS_LOCK,
						RW(Proc)->LLC_Streamer,
						RO(Proc)->ECORE_Mask) != 0;

	RO(Shm)->Proc.Technology.PowerMgmt = BITCMP_CC(BUS_LOCK,
						RW(Proc)->PowerMgmt,
						RO(Proc)->PowerMgmt_Mask);

	RO(Shm)->Proc.Technology.EIST = BITCMP_CC(BUS_LOCK,
						RW(Proc)->SpeedStep,
						RO(Proc)->SpeedStep_Mask);

	RO(Shm)->Proc.Technology.Turbo = BITWISEAND_CC(BUS_LOCK,
						RW(Proc)->TurboBoost,
						RO(Proc)->TurboBoost_Mask) != 0;

	RO(Shm)->Proc.Technology.C1E = BITCMP_CC(BUS_LOCK,
						RW(Proc)->C1E,
						RO(Proc)->C1E_Mask);

	RO(Shm)->Proc.Technology.C3A = BITCMP_CC(BUS_LOCK,
						RW(Proc)->C3A,
						RO(Proc)->C3A_Mask);

	RO(Shm)->Proc.Technology.C1A = BITCMP_CC(BUS_LOCK,
						RW(Proc)->C1A,
						RO(Proc)->C1A_Mask);

	RO(Shm)->Proc.Technology.C3U = BITCMP_CC(BUS_LOCK,
						RW(Proc)->C3U,
						RO(Proc)->C3U_Mask);

	RO(Shm)->Proc.Technology.C1U = BITCMP_CC(BUS_LOCK,
						RW(Proc)->C1U,
						RO(Proc)->C1U_Mask);

	RO(Shm)->Proc.Technology.CC6 = BITCMP_CC(BUS_LOCK,
						RW(Proc)->CC6,
						RO(Proc)->CC6_Mask);

	RO(Shm)->Proc.Technology.PC6 = BITCMP_CC(BUS_LOCK,
						RW(Proc)->PC6,
						RO(Proc)->PC6_Mask);

	RO(Shm)->Proc.Technology.SMM = BITCMP_CC(BUS_LOCK,
						RW(Proc)->SMM,
						RO(Proc)->CR_Mask);

	RO(Shm)->Proc.Technology.VM = BITCMP_CC(BUS_LOCK,
						RW(Proc)->VM,
						RO(Proc)->CR_Mask);

	RO(Shm)->Proc.Technology.WDT = BITCMP_CC(BUS_LOCK,
						RW(Proc)->WDT,
						RO(Proc)->WDT_Mask);

								/* 000v */
	RO(Shm)->Proc.Technology.TM1 = RO(Proc)->Features.Std.EDX.TM1
					| RO(Proc)->Features.AdvPower.EDX.TTP;
								/* 00v0 */
	RO(Shm)->Proc.Technology.TM1 |= BITCMP_CC(BUS_LOCK,
						RW(Proc)->TM1,
						RO(Proc)->TM_Mask) << 1;

								/* 000v */
	RO(Shm)->Proc.Technology.TM2 = RO(Proc)->Features.Std.ECX.TM2
					| RO(Proc)->Features.AdvPower.EDX.TM;
								/* 00v0 */
	RO(Shm)->Proc.Technology.TM2 |= BITCMP_CC(BUS_LOCK,
						RW(Proc)->TM2,
						RO(Proc)->TM_Mask) << 1;
}

void Mitigation_2nd_Stage(	RO(SHM_STRUCT) *RO(Shm),
				RO(PROC) *RO(Proc), RW(PROC) *RW(Proc) )
{
	unsigned short	IBRS = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->IBRS,
						RO(Proc)->SPEC_CTRL_Mask ),

			STIBP = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->STIBP,
						RO(Proc)->SPEC_CTRL_Mask ),

			SSBD = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->SSBD,
						RO(Proc)->SPEC_CTRL_Mask ),

			AMD_LS_CFG_SSBD = BITCMP_CC(BUS_LOCK,
						RW(Proc)->AMD_LS_CFG_SSBD,
						RO(Proc)->SPEC_CTRL_Mask ),

			PSFD = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->PSFD,
						RO(Proc)->SPEC_CTRL_Mask );

	RO(Shm)->Proc.Mechanisms.IBRS  += (2 * IBRS);
	RO(Shm)->Proc.Mechanisms.STIBP += (2 * STIBP);
	RO(Shm)->Proc.Mechanisms.SSBD  += (2 * (SSBD | AMD_LS_CFG_SSBD));
	RO(Shm)->Proc.Mechanisms.PSFD  += (2 * PSFD);
}

void Mitigation_1st_Stage(	RO(SHM_STRUCT) *RO(Shm),
				RO(PROC) *RO(Proc), RW(PROC) *RW(Proc) )
{
    if (RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_INTEL)
    {
	unsigned short	RDCL_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->RDCL_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			IBRS_ALL = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->RDCL_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			RSBA = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->RSBA,
						RO(Proc)->ARCH_CAP_Mask ),

			L1DFL_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->L1DFL_VMENTRY_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			SSB_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->SSB_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			MDS_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->MDS_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			PSCHANGE_MC_NO=BITCMP_CC(BUS_LOCK,
						RW(Proc)->PSCHANGE_MC_NO,
						RO(Proc)->ARCH_CAP_Mask),

			TAA_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->TAA_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			STLB = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->STLB,
						RO(Proc)->ARCH_CAP_Mask ),

			FUSA = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->FUSA,
						RO(Proc)->ARCH_CAP_Mask ),

			RSM_CPL0 = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->RSM_CPL0,
						RO(Proc)->ARCH_CAP_Mask ),

			SPLA = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->SPLA,
						RO(Proc)->ARCH_CAP_Mask ),

			SNOOP_FILTER =BITCMP_CC(BUS_LOCK,
						RW(Proc)->SNOOP_FILTER,
						RO(Proc)->ARCH_CAP_Mask),

			DOITM_MSR = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->DOITM_MSR,
						RO(Proc)->ARCH_CAP_Mask ),

			DOITM_EN = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->DOITM_EN,
						RO(Proc)->ARCH_CAP_Mask ),

			SBDR_SSDP_NO = BITCMP_CC(BUS_LOCK,
						RW(Proc)->SBDR_SSDP_NO,
						RO(Proc)->ARCH_CAP_Mask),

			FBSDP_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->FBSDP_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			PSDP_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->PSDP_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			FB_CLEAR = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->FB_CLEAR,
						RO(Proc)->ARCH_CAP_Mask ),

			XAPIC_MSR = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->XAPIC_MSR,
						RO(Proc)->ARCH_CAP_Mask ),

			XAPIC_DIS = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->XAPIC_DIS,
						RO(Proc)->ARCH_CAP_Mask ),

			RNGDS = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->RNGDS,
						RO(Proc)->ARCH_CAP_Mask ),

			RTM = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->RTM,
						RO(Proc)->ARCH_CAP_Mask ),

			VERW = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->VERW,
						RO(Proc)->ARCH_CAP_Mask ),

			RRSBA = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->RRSBA,
						RO(Proc)->ARCH_CAP_Mask ),

			BHI_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->BHI_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			PBRSB_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->PBRSB_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			OC_UTILIZED = BITCMP_CC(BUS_LOCK,
						RW(Proc)->OC_UTILIZED,
						RO(Proc)->ARCH_CAP_Mask),

			OC_UNDERVOLT = BITCMP_CC(BUS_LOCK,
						RW(Proc)->OC_UNDERVOLT,
						RO(Proc)->ARCH_CAP_Mask),

			OC_UNLOCKED = BITCMP_CC(BUS_LOCK,
						RW(Proc)->OC_UNLOCKED,
						RO(Proc)->ARCH_CAP_Mask),

			GDS_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->GDS_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			RFDS_NO = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->RFDS_NO,
						RO(Proc)->ARCH_CAP_Mask ),

			IPRED_DIS_U = BITCMP_CC(BUS_LOCK,
						RW(Proc)->IPRED_DIS_U,
						RO(Proc)->SPEC_CTRL_Mask),

			IPRED_DIS_S = BITCMP_CC(BUS_LOCK,
						RW(Proc)->IPRED_DIS_S,
						RO(Proc)->SPEC_CTRL_Mask),

			RRSBA_DIS_U = BITCMP_CC(BUS_LOCK,
						RW(Proc)->RRSBA_DIS_U,
						RO(Proc)->SPEC_CTRL_Mask),

			RRSBA_DIS_S = BITCMP_CC(BUS_LOCK,
						RW(Proc)->RRSBA_DIS_S,
						RO(Proc)->SPEC_CTRL_Mask),

			DDPD_U_DIS = BITCMP_CC( BUS_LOCK,
						RW(Proc)->DDPD_U_DIS,
						RO(Proc)->SPEC_CTRL_Mask ),

			BHI_DIS_S = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->BHI_DIS_S,
						RO(Proc)->SPEC_CTRL_Mask );

	RO(Shm)->Proc.Mechanisms.IBRS = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IBRS_IBPB_Cap == 1
	);
	RO(Shm)->Proc.Mechanisms.STIBP = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.STIBP_Cap == 1
	);
	RO(Shm)->Proc.Mechanisms.SSBD = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.SSBD_Cap == 1
	);
	RO(Shm)->Proc.Mechanisms.PSFD = (
	      (RO(Shm)->Proc.Features.ExtFeature.EAX.MaxSubLeaf >= 2)
	   && (RO(Shm)->Proc.Features.ExtFeature_Leaf2_EDX.PSFD_SPEC_CTRL == 1)
	);

	Mitigation_2nd_Stage(RO(Shm), RO(Proc), RW(Proc));

	RO(Shm)->Proc.Mechanisms.RDCL_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * RDCL_NO)
	);
	RO(Shm)->Proc.Mechanisms.IBRS_ALL = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * IBRS_ALL)
	);
	RO(Shm)->Proc.Mechanisms.RSBA = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * RSBA)
	);
	RO(Shm)->Proc.Mechanisms.L1DFL_VMENTRY_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * L1DFL_NO)
	);
	RO(Shm)->Proc.Mechanisms.SSB_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * SSB_NO)
	);
	RO(Shm)->Proc.Mechanisms.MDS_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * MDS_NO)
	);
	RO(Shm)->Proc.Mechanisms.PSCHANGE_MC_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * PSCHANGE_MC_NO)
	);
	RO(Shm)->Proc.Mechanisms.TAA_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * TAA_NO)
	);
	RO(Shm)->Proc.Mechanisms.STLB = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_CORE_CAP
		+ (2 * STLB)
	);
	RO(Shm)->Proc.Mechanisms.FUSA = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_CORE_CAP
		+ (2 * FUSA)
	);
	RO(Shm)->Proc.Mechanisms.RSM_CPL0 = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_CORE_CAP
		+ (2 * RSM_CPL0)
	);
	RO(Shm)->Proc.Mechanisms.SPLA = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_CORE_CAP
		+ (2 * SPLA)
	);
	RO(Shm)->Proc.Mechanisms.SNOOP_FILTER = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_CORE_CAP
		+ (2 * SNOOP_FILTER)
	);

	RO(Shm)->Proc.Mechanisms.DOITM_EN = DOITM_MSR + (2 * DOITM_EN);

	RO(Shm)->Proc.Mechanisms.SBDR_SSDP_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * SBDR_SSDP_NO)
	);
	RO(Shm)->Proc.Mechanisms.FBSDP_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * FBSDP_NO)
	);
	RO(Shm)->Proc.Mechanisms.PSDP_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * PSDP_NO)
	);
	RO(Shm)->Proc.Mechanisms.FB_CLEAR = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * FB_CLEAR)
	);
	RO(Shm)->Proc.Mechanisms.RRSBA = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * RRSBA)
	);
	RO(Shm)->Proc.Mechanisms.BHI_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * BHI_NO)
	);

	RO(Shm)->Proc.Mechanisms.SRBDS = BITCMP_CC(BUS_LOCK,
						RW(Proc)->SRBDS_MSR,
						RO(Proc)->ARCH_CAP_Mask);

	RO(Shm)->Proc.Mechanisms.RNGDS	= RO(Shm)->Proc.Mechanisms.SRBDS
					+ (2 * RNGDS);

	RO(Shm)->Proc.Mechanisms.RTM	= RO(Shm)->Proc.Mechanisms.SRBDS
					+ (2 * RTM);

	RO(Shm)->Proc.Mechanisms.VERW	= RO(Shm)->Proc.Mechanisms.SRBDS
					+ (2 * VERW);

	RO(Shm)->Proc.Mechanisms.XAPIC_DIS = XAPIC_MSR + (2 * XAPIC_DIS);

	RO(Shm)->Proc.Mechanisms.PBRSB_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * PBRSB_NO)
	);

	RO(Shm)->Proc.Mechanisms.OC_UTILIZED = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * OC_UTILIZED)
	);

	RO(Shm)->Proc.Mechanisms.OC_UNDERVOLT = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * OC_UNDERVOLT)
	);

	RO(Shm)->Proc.Mechanisms.OC_UNLOCKED = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * OC_UNLOCKED)
	);

	RO(Shm)->Proc.Mechanisms.GDS_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * GDS_NO)
	);

	RO(Shm)->Proc.Mechanisms.RFDS_NO = (
		RO(Shm)->Proc.Features.ExtFeature.EDX.IA32_ARCH_CAP
		+ (2 * RFDS_NO)
	);

	RO(Shm)->Proc.Mechanisms.IPRED_DIS_U = (
	      (RO(Shm)->Proc.Features.ExtFeature.EAX.MaxSubLeaf >= 2)
	   && (RO(Shm)->Proc.Features.ExtFeature_Leaf2_EDX.IPRED_SPEC_CTRL == 1)
	);
	RO(Shm)->Proc.Mechanisms.IPRED_DIS_U += (2 * IPRED_DIS_U);

	RO(Shm)->Proc.Mechanisms.IPRED_DIS_S = (
	      (RO(Shm)->Proc.Features.ExtFeature.EAX.MaxSubLeaf >= 2)
	   && (RO(Shm)->Proc.Features.ExtFeature_Leaf2_EDX.IPRED_SPEC_CTRL == 1)
	);
	RO(Shm)->Proc.Mechanisms.IPRED_DIS_S += (2 * IPRED_DIS_S);

	RO(Shm)->Proc.Mechanisms.RRSBA_DIS_U = (
	      (RO(Shm)->Proc.Features.ExtFeature.EAX.MaxSubLeaf >= 2)
	   && (RO(Shm)->Proc.Features.ExtFeature_Leaf2_EDX.RRSBA_SPEC_CTRL == 1)
	);
	RO(Shm)->Proc.Mechanisms.RRSBA_DIS_U += (2 * RRSBA_DIS_U);

	RO(Shm)->Proc.Mechanisms.RRSBA_DIS_S = (
	      (RO(Shm)->Proc.Features.ExtFeature.EAX.MaxSubLeaf >= 2)
	   && (RO(Shm)->Proc.Features.ExtFeature_Leaf2_EDX.RRSBA_SPEC_CTRL == 1)
	);
	RO(Shm)->Proc.Mechanisms.RRSBA_DIS_S += (2 * RRSBA_DIS_S);

	RO(Shm)->Proc.Mechanisms.DDPD_U_DIS = (
	      (RO(Shm)->Proc.Features.ExtFeature.EAX.MaxSubLeaf >= 2)
	   && (RO(Shm)->Proc.Features.ExtFeature_Leaf2_EDX.DDPD_U_SPEC_CTRL ==1)
	);
	RO(Shm)->Proc.Mechanisms.DDPD_U_DIS += (2 * DDPD_U_DIS);

	RO(Shm)->Proc.Mechanisms.BHI_DIS_S = (
	      (RO(Shm)->Proc.Features.ExtFeature.EAX.MaxSubLeaf >= 2)
	   && (RO(Shm)->Proc.Features.ExtFeature_Leaf2_EDX.BHI_SPEC_CTRL == 1)
	);
	RO(Shm)->Proc.Mechanisms.BHI_DIS_S += (2 * BHI_DIS_S);

	RO(Shm)->Proc.Mechanisms.MCDT_NO = (
		RO(Shm)->Proc.Features.ExtFeature_Leaf2_EDX.MCDT_NO == 1
	);

	RO(Shm)->Proc.Mechanisms.MONITOR_MITG_NO = (
		RO(Shm)->Proc.Features.ExtFeature_Leaf2_EDX.MONITOR_MITG_NO == 1
	);
    }
    else if (	(RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_AMD)
	||	(RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_HYGON) )
    {
	unsigned short	BTC_NOBR = BITCMP_CC(	BUS_LOCK,
						RW(Proc)->BTC_NOBR,
						RO(Proc)->BTC_NOBR_Mask );
	RO(Shm)->Proc.Mechanisms.IBRS = (
		RO(Shm)->Proc.Features.leaf80000008.EBX.IBRS == 1
	);
	RO(Shm)->Proc.Mechanisms.STIBP = (
		RO(Shm)->Proc.Features.leaf80000008.EBX.STIBP == 1
	);
	RO(Shm)->Proc.Mechanisms.SSBD = (
		RO(Shm)->Proc.Features.leaf80000008.EBX.SSBD == 1
	);
	RO(Shm)->Proc.Mechanisms.PSFD = (
		RO(Shm)->Proc.Features.leaf80000008.EBX.PSFD == 1
	);

	Mitigation_2nd_Stage(RO(Shm), RO(Proc), RW(Proc));

	switch (RO(Shm)->Proc.ArchID) {
	case AMD_EPYC_Rome_CPK:
	case AMD_Zen2_Renoir:
	case AMD_Zen2_LCN:
	case AMD_Zen2_MTS:
	case AMD_Zen2_Ariel:
	case AMD_Zen2_Jupiter:
	case AMD_Zen2_Galileo:
	case AMD_Zen2_MDN:
		RO(Shm)->Proc.Mechanisms.BTC_NOBR = (
			RO(Shm)->Proc.Features.leaf80000008.EBX.STIBP == 1
		);
		RO(Shm)->Proc.Mechanisms.BTC_NOBR += (2 * BTC_NOBR);

		RO(Shm)->Proc.Mechanisms.XPROC_LEAK = \
			BITCMP_CC(BUS_LOCK,
				RW(Proc)->XPROC_LEAK,
				RO(Proc)->XPROC_LEAK_Mask) ? 0b11 : 0b10;

		RO(Shm)->Proc.Mechanisms.AGENPICK = \
			BITCMP_CC(BUS_LOCK,
				RW(Proc)->AGENPICK,
				RO(Proc)->BTC_NOBR_Mask) ? 0b11 : 0b10;
		break;
	default:
		RO(Shm)->Proc.Mechanisms.BTC_NOBR = 0;
		RO(Shm)->Proc.Mechanisms.XPROC_LEAK = 0;
		RO(Shm)->Proc.Mechanisms.AGENPICK = 0;
		break;
	}
    }
}

#define TIMING(_mc, _cha)	RO(Shm)->Uncore.MC[_mc].Channel[_cha].Timing

typedef struct {
	unsigned int	Q,
			R;
} RAM_Ratio;

void P945_MCH(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, slot;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
    RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
    RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	TIMING(mc, cha).tWR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P945.DRT0.tWR;

	TIMING(mc, cha).tRTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P945.DRT1.tRTPr;

	TIMING(mc, cha).tRAS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P945.DRT1.tRAS;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].P945.DRT1.tRRD) {
	case 0b000:
		TIMING(mc, cha).tRRD = 1;
		break;
	case 0b001:
		TIMING(mc, cha).tRRD = 2;
		break;
	}

	TIMING(mc, cha).tRFC = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P945.DRT1.tRFC;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].P945.DRT1.tCL) {
	case 0b00:
		TIMING(mc, cha).tCL = 5;
		break;
	case 0b01:
		TIMING(mc, cha).tCL = 4;
		break;
	case 0b10:
		TIMING(mc, cha).tCL = 3;
		break;
	case 0b11:
		TIMING(mc, cha).tCL = 6;
		break;
	}

	TIMING(mc, cha).tRCD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P945.DRT1.tRCD + 2;

	TIMING(mc, cha).tRP  = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P945.DRT1.tRP + 2;

      for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
      {
	unsigned long long DIMM_Size;
	unsigned short rank, rankCount = (cha == 0) ? 4 : 2;

	for (rank = 0; rank < rankCount; rank++) {
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks += \
		  RO(Proc)->Uncore.MC[mc].Channel[cha].P945.DRB[rank].Boundary;
	}
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].P945.BANK.Rank0)
	{
	case 0b00:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 4;
		break;
	case 0b01:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 8;
		break;
	}
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].P945.WIDTH.Rank0)
	{
	case 0b00:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 16384;
		break;
	case 0b01:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 8192;
		break;
	}
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1024;

	DIMM_Size	= RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
						(unsigned int)(DIMM_Size >> 20);
      }
	TIMING(mc, cha).ECC = 0;

	TIMING(mc, cha).tCKE = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P945.DRT2.tCKE;
    }
  }
}

void P955_MCH(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, slot;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
    RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
    RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	TIMING(mc, cha).tRAS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P955.DRT1.tRAS;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].P955.DRT1.tCL) {
	case 0b00:
		TIMING(mc, cha).tCL = 5;
		break;
	case 0b01:
		TIMING(mc, cha).tCL = 4;
		break;
	case 0b10:
		TIMING(mc, cha).tCL = 3;
		break;
	case 0b11:
		TIMING(mc, cha).tCL = 6;
		break;
	}

	TIMING(mc, cha).tRCD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P955.DRT1.tRCD + 2;

	TIMING(mc, cha).tRP  = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P955.DRT1.tRP + 2;

      for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
      {
	unsigned long long DIMM_Size;
	unsigned short rank;

	for (rank = 0; rank < 4; rank++) {
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks += \
		  RO(Proc)->Uncore.MC[mc].Channel[cha].P955.DRB[rank].Boundary;
	}
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].P955.BANK.Rank0)
	{
	case 0b00:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 4;
		break;
	case 0b01:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 8;
		break;
	}
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].P955.WIDTH.Rank0)
	{
	case 0b00:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 16384;
		break;
	case 0b01:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 8192;
		break;
	}
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1024;

	DIMM_Size	= RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
							(unsigned int)DIMM_Size;
      }
	TIMING(mc, cha).ECC = 0;
    }
  }
}

void P945_CLK(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	RAM_Ratio Ratio = {.Q = 1, .R = 1};

	switch (RO(Proc)->Uncore.Bus.ClkCfg.FSB_Select) {
	case 0b000:
		RO(Shm)->Uncore.Bus.Rate = 400;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		default:
			fallthrough;
		case 0b010:
			Ratio.Q = 1;
			Ratio.R = 1;
			break;
		case 0b011:
			Ratio.Q = 4;
			Ratio.R = 3;
			break;
		case 0b100:
			Ratio.Q = 5;
			Ratio.R = 3;
			break;
		}
		break;
	case 0b001:
		RO(Shm)->Uncore.Bus.Rate = 533;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		default:
			fallthrough;
		case 0b010:
			Ratio.Q = 3;
			Ratio.R = 4;
			break;
		case 0b011:
			Ratio.Q = 1;
			Ratio.R = 1;
			break;
		case 0b001:
			Ratio.Q = 5;
			Ratio.R = 4;
			break;
		}
		break;
	default:
		fallthrough;
	case 0b011:
		RO(Shm)->Uncore.Bus.Rate = 667;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		default:
			fallthrough;
		case 0b010:
			Ratio.Q = 3;
			Ratio.R = 5;
			break;
		case 0b011:
			Ratio.Q = 4;
			Ratio.R = 5;
			break;
		case 0b100:
			Ratio.Q = 1;
			Ratio.R = 1;
			break;
		}
		break;
	}

	RO(Shm)->Uncore.CtrlSpeed = (RO(Core)->Clock.Hz * Ratio.Q * 2)/* DDR2 */
				/ (Ratio.R * 1000000L);

	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MHZ;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Ver  = 2;
	RO(Shm)->Uncore.Unit.DDR_Std  = RAM_STD_UNSPEC;
}

void P965_MCH(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, slot;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
    RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
    RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	TIMING(mc, cha).tCL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT0.tCL;

	TIMING(mc, cha).tCL += 3;

	TIMING(mc, cha).tRAS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT1.tRAS;

	TIMING(mc, cha).tWR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT1.tWR;

	TIMING(mc, cha).tRFC = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT2.tRFC;

	TIMING(mc, cha).tRP = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT2.tRP;

	TIMING(mc, cha).tRRD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT2.tRRD;

	TIMING(mc, cha).tRCD_WR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT3.tRCD_WR;

	TIMING(mc, cha).tRCD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT4.tRCD_RD;

	TIMING(mc, cha).tFAW = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT2.ACT_Count;

	TIMING(mc, cha).tRTPr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT2.ReservedBits;
/* TODO(Timings)
	TIMING(mc, cha).tCWL  = ?
*/
	TIMING(mc, cha).tddRdTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT3.tRD_WR;

	TIMING(mc, cha).tsrRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT4.tRD_RD_SR;

	TIMING(mc, cha).tdrRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT4.tRD_RD_DR;

	TIMING(mc, cha).tsrWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT3.tWR_WR_SR;

	TIMING(mc, cha).tdrWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT3.tWR_WR_DR;

	TIMING(mc, cha).tsrWrTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT4.tWR_RD_SR;

	TIMING(mc, cha).tdrWrTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P965.DRT4.tWR_RD_DR;

	for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
	{
		unsigned long long DIMM_Size;
/* TODO(Geometry):Hardware missing! */
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 0;
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = 0;
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 0;
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 0;

		DIMM_Size = 8LLU
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
						(unsigned int)(DIMM_Size >> 20);
	}
	TIMING(mc, cha).ECC = 0;

	TIMING(mc, cha).tXS = (cha == 0) ?
				  RO(Proc)->Uncore.MC[mc].P965.CKE0.tXSNR
				: RO(Proc)->Uncore.MC[mc].P965.CKE1.tXSNR;

	TIMING(mc, cha).tXP = (cha == 0) ?
				  RO(Proc)->Uncore.MC[mc].P965.CKE0.tXP
				: RO(Proc)->Uncore.MC[mc].P965.CKE1.tXP;

	TIMING(mc, cha).tCKE = (cha == 0) ?
				  RO(Proc)->Uncore.MC[mc].P965.CKE0.tCKE_Low
				: RO(Proc)->Uncore.MC[mc].P965.CKE1.tCKE_Low;
    }
  }
}

void P965_CLK(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	RAM_Ratio Ratio = {.Q = 1, .R = 1};

	switch (RO(Proc)->Uncore.Bus.ClkCfg.FSB_Select) {
	case 0b111:	/* Unknown */
		fallthrough;
	case 0b000:
		RO(Shm)->Uncore.Bus.Rate = 1066;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		case 0b001:
			Ratio.Q = 1;
			Ratio.R = 1;
			break;
		case 0b010:
			Ratio.Q = 5;
			Ratio.R = 4;
			break;
		case 0b011:
			Ratio.Q = 3;
			Ratio.R = 2;
			break;
		case 0b100:
			Ratio.Q = 2;
			Ratio.R = 1;
			break;
		case 0b101:
			Ratio.Q = 5;
			Ratio.R = 2;
			break;
		}
		break;
	case 0b001:
		RO(Shm)->Uncore.Bus.Rate = 533;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		case 0b001:
			Ratio.Q = 2;
			Ratio.R = 1;
			break;
		case 0b010:
			Ratio.Q = 5;
			Ratio.R = 2;
			break;
		case 0b011:
			Ratio.Q = 3;
			Ratio.R = 1;
			break;
		}
		break;
	case 0b011:
		RO(Shm)->Uncore.Bus.Rate = 667;
		break;
	case 0b100:
		RO(Shm)->Uncore.Bus.Rate = 1333;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		case 0b010:
			Ratio.Q = 1;
			Ratio.R = 1;
			break;
		case 0b011:
			Ratio.Q = 6;
			Ratio.R = 5;
			break;
		case 0b100:
			Ratio.Q = 8;
			Ratio.R = 5;
			break;
		case 0b101:
			Ratio.Q = 2;
			Ratio.R = 1;
			break;
		}
		break;
	case 0b110:
		RO(Shm)->Uncore.Bus.Rate = 1600;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		case 0b011:
			Ratio.Q = 1;
			Ratio.R = 1;
			break;
		case 0b100:
			Ratio.Q = 4;
			Ratio.R = 3;
			break;
		case 0b101:
			Ratio.Q = 3;
			Ratio.R = 2;
			break;
		case 0b110:
			Ratio.Q = 2;
			Ratio.R = 1;
			break;
		}
		break;
	default:
		fallthrough;
	case 0b010:
		RO(Shm)->Uncore.Bus.Rate = 800;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		case 0b000:
			Ratio.Q = 1;
			Ratio.R = 1;
			break;
		case 0b001:
			Ratio.Q = 5;
			Ratio.R = 4;
			break;
		case 0b010:
			Ratio.Q = 5;
			Ratio.R = 3;
			break;
		case 0b011:
			Ratio.Q = 2;
			Ratio.R = 1;
			break;
		case 0b100:
			Ratio.Q = 8;
			Ratio.R = 3;
			break;
		case 0b101:
			Ratio.Q = 10;
			Ratio.R = 3;
			break;
		}
		break;
	}

	RO(Shm)->Uncore.CtrlSpeed = (RO(Core)->Clock.Hz * Ratio.Q * 2) /* DDR2 */
				/ (Ratio.R * 1000000L);

	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MTS;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MTS;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Ver  = 2;
	RO(Shm)->Uncore.Unit.DDR_Std  = RAM_STD_UNSPEC;
}

void G965_MCH(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, slot;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
      RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
      RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	TIMING(mc, cha).tWR  = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT0.tWR;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT1.tRCD) {
	case 0b000:
		TIMING(mc, cha).tRCD = 2;
		break;
	case 0b001:
		TIMING(mc, cha).tRCD = 3;
		break;
	case 0b010:
		TIMING(mc, cha).tRCD = 4;
		break;
	case 0b011:
		TIMING(mc, cha).tRCD = 5;
		break;
	case 0b100:
		TIMING(mc, cha).tRCD = 6;
		break;
	case 0b101:
		TIMING(mc, cha).tRCD = 7;
		break;
	case 0b110:
		TIMING(mc, cha).tRCD = 8;
		break;
	}

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT1.tRP) {
	case 0b000:
		TIMING(mc, cha).tRP = 2;
		break;
	case 0b001:
		TIMING(mc, cha).tRP = 3;
		break;
	case 0b010:
		TIMING(mc, cha).tRP = 4;
		break;
	case 0b011:
		TIMING(mc, cha).tRP = 5;
		break;
	case 0b100:
		TIMING(mc, cha).tRP = 6;
		break;
	case 0b101:
		TIMING(mc, cha).tRP = 7;
		break;
	case 0b110:
		TIMING(mc, cha).tRP = 8;
		break;
	}

	TIMING(mc, cha).tRAS  = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT1.tRAS;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT1.tRRD) {
	case 0b000:
		TIMING(mc, cha).tRRD = 2;
		break;
	case 0b001:
		TIMING(mc, cha).tRRD = 3;
		break;
	case 0b010:
		TIMING(mc, cha).tRRD = 4;
		break;
	case 0b011:
		TIMING(mc, cha).tRRD = 5;
		break;
	case 0b100:
		TIMING(mc, cha).tRRD = 6;
		break;
	}

	TIMING(mc, cha).tRTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT1.tRTPr;

	TIMING(mc, cha).tFAW  = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT2.tFAW;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT3.tCL) {
	case 0b000:
		TIMING(mc, cha).tCL = 3;
		break;
	case 0b001:
		TIMING(mc, cha).tCL = 4;
		break;
	case 0b010:
		TIMING(mc, cha).tCL = 5;
		break;
	case 0b011:
		TIMING(mc, cha).tCL = 6;
		break;
	case 0b100:
		TIMING(mc, cha).tCL = 7;
		break;
	}

	TIMING(mc, cha).tRFC  = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT3.tRFC;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT3.tCWL) {
	case 0b000:
		TIMING(mc, cha).tCWL = 2;
		break;
	case 0b001:
		TIMING(mc, cha).tCWL = 3;
		break;
	case 0b010:
		TIMING(mc, cha).tCWL = 4;
		break;
	case 0b011:
		TIMING(mc, cha).tCWL = 5;
		break;
	case 0b100:
		TIMING(mc, cha).tCWL = 6;
		break;
	default:
		TIMING(mc, cha).tCWL = \
			TIMING(mc, cha).tCL - 1;
		break;
	}
      for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
      {
	unsigned long long DIMM_Size;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].DRA.Rank1Bank)
	{
	case 0b00:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 4;
		break;
	case 0b01:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 8;
		break;
	}
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].DRA.Rank0Bank)
	{
	case 0b00:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks += 4;
		break;
	case 0b01:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks += 8;
		break;
	}
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].DRA.OddRank1)
	{
	case 0b10:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = 1;
		break;
	case 0b11:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = 2;
		break;
	}
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].DRA.EvenRank0)
	{
	case 0b10:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks += 1;
		break;
	case 0b11:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks += 2;
		break;
	}

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 4096;
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1024;

	DIMM_Size	= 8LLU
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
						(unsigned int)(DIMM_Size >> 20);
      }
	TIMING(mc, cha).ECC = 0;

	TIMING(mc, cha).tXS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT3.tXS;

	TIMING(mc, cha).tXP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT2.tXP;

	TIMING(mc, cha).tCKE = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].G965.DRT2.tCKE;
    }
  }
}

void G965_CLK(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	RAM_Ratio Ratio = {.Q = 1, .R = 1};

	switch (RO(Proc)->Uncore.Bus.ClkCfg.FSB_Select) {
	case 0b001:
		RO(Shm)->Uncore.Bus.Rate = 533;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		case 0b001:
			Ratio.Q = 5;
			Ratio.R = 4;
			break;
		case 0b010:
			Ratio.Q = 3;
			Ratio.R = 2;
			break;
		case 0b011:
			Ratio.Q = 2;
			Ratio.R = 1;
			break;
		}
		break;
	case 0b011:
		RO(Shm)->Uncore.Bus.Rate = 667;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		case 0b001:
			Ratio.Q = 1;
			Ratio.R = 1;
			break;
		case 0b010:
			Ratio.Q = 6;
			Ratio.R = 5;
			break;
		case 0b011:
			Ratio.Q = 8;
			Ratio.R = 5;
			break;
		case 0b100:
			Ratio.Q = 2;
			Ratio.R = 1;
			break;
		case 0b101:
			Ratio.Q = 12;
			Ratio.R = 5;
			break;
		}
		break;
	case 0b110:
		RO(Shm)->Uncore.Bus.Rate = 1066;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		case 0b101:
			Ratio.Q = 3;
			Ratio.R = 2;
			break;
		case 0b110:
			Ratio.Q = 2;
			Ratio.R = 1;
			break;
		}
		break;
	default:
		fallthrough;
	case 0b010:
		RO(Shm)->Uncore.Bus.Rate = 800;

		switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
		case 0b001:
			Ratio.Q = 5;
			Ratio.R = 6;
			break;
		case 0b010:
			Ratio.Q = 1;
			Ratio.R = 1;
			break;
		case 0b011:
			Ratio.Q = 4;
			Ratio.R = 3;
			break;
		case 0b100:
			Ratio.Q = 5;
			Ratio.R = 3;
			break;
		case 0b101:
			Ratio.Q = 2;
			Ratio.R = 1;
			break;
		}
		break;
	}

	RO(Shm)->Uncore.CtrlSpeed = (RO(Core)->Clock.Hz * Ratio.Q * 2) /* DDR2 */
				/ (Ratio.R * 1000000L);

	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MHZ;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Ver  = 2;
	RO(Shm)->Uncore.Unit.DDR_Std  = RAM_STD_UNSPEC;
}

void P3S_MCH(	RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc),
		unsigned short mc,unsigned short cha )
{
	TIMING(mc, cha).tCL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT0.tCL;

	TIMING(mc, cha).tWR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT1.tWR;

	TIMING(mc, cha).tRFC = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT2.tRFC;

	TIMING(mc, cha).tRP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT2.tRP;

	TIMING(mc, cha).tRRD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT2.tRRD;

	TIMING(mc, cha).tRCD_WR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT3.tRCD_WR;

	TIMING(mc, cha).tRCD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT4.tRCD_RD;

	TIMING(mc, cha).tRAS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT5.tRAS;

	TIMING(mc, cha).tFAW = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT2.ACT_Count;

	TIMING(mc, cha).tRTPr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT2.ReservedBits;
/* TODO(Timings)
	TIMING(mc, cha).tCWL = ?
*/
	TIMING(mc, cha).tddRdTWr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT3.tRD_WR;

	TIMING(mc, cha).tsrRdTRd = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT4.tRD_RD_SR;

	TIMING(mc, cha).tdrRdTRd = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT4.tRD_RD_DR;

	TIMING(mc, cha).tsrWrTWr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT3.tWR_WR_SR;

	TIMING(mc, cha).tdrWrTWr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT3.tWR_WR_DR;

	TIMING(mc, cha).tsrWrTRd = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT4.tWR_RD_SR;

	TIMING(mc, cha).tdrWrTRd = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRT4.tWR_RD_DR;

	TIMING(mc, cha).tXS = (cha == 0) ?
				  RO(Proc)->Uncore.MC[mc].P35.CKE0.tXSNR
				: RO(Proc)->Uncore.MC[mc].P35.CKE1.tXSNR;

	TIMING(mc, cha).tXP = (cha == 0) ?
				  RO(Proc)->Uncore.MC[mc].P35.CKE0.tXP
				: RO(Proc)->Uncore.MC[mc].P35.CKE1.tXP;

	TIMING(mc, cha).tCKE = (cha == 0) ?
				  RO(Proc)->Uncore.MC[mc].P35.CKE0.tCKE_Low
				: RO(Proc)->Uncore.MC[mc].P35.CKE1.tCKE_Low;
}

void P35_MCH(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, slot;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
    RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
    RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	P3S_MCH(RO(Shm), RO(Proc), mc, cha);

	TIMING(mc, cha).tCL -= 9;

      for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
      {
	unsigned long long DIMM_Size;
	unsigned short rank;

	for (rank = 0; rank < 4; rank++) {
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks += \
		  RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRB[rank].Boundary;

	    switch (rank) {
	    case 0:
	    case 2:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = \
		  RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRA[rank >> 1].Rank0;
		break;
	    case 1:
	    case 3:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = \
		  RO(Proc)->Uncore.MC[mc].Channel[cha].P35.DRA[rank >> 1].Rank1;
		break;
	    }
	}
	/*TODO(Geometry registers)*/
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 16384;
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1024;

	DIMM_Size	= RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
							(unsigned int)DIMM_Size;
      }
	TIMING(mc, cha).ECC = 0;
    }
  }
}

void P35_CLK(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	P965_CLK(RO(Shm), RO(Proc), RO(Core));
}

void P4S_MCH(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, slot;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
    RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
    RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	P3S_MCH(RO(Shm), RO(Proc), mc, cha);

	TIMING(mc, cha).tCL -= 6;
/* TODO(Timings) */
      for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
      {
	unsigned long long DIMM_Size;
/* TODO(Geometry):Hardware missing! */
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 0;
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = 0;
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 0;
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 0;

	DIMM_Size	= 8LLU
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
						(unsigned int)(DIMM_Size >> 20);
      }
	TIMING(mc, cha).ECC = 0;
    }
  }
}

void SLM_PTR(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	unsigned short mc, cha, slot;
/* BUS & DRAM frequency */
	RO(Shm)->Uncore.CtrlSpeed = 800LLU + (
			((2134LLU * RO(Proc)->Uncore.MC[0].SLM.DTR0.DFREQ) >> 3)
	);
	RO(Shm)->Uncore.Bus.Rate = 5000;

	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MTS;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MTS;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
    RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
    RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
/* Standard Timings */
	TIMING(mc, cha).tCL  = RO(Proc)->Uncore.MC[mc].SLM.DTR0.tCL + 5;

	TIMING(mc, cha).tRCD = RO(Proc)->Uncore.MC[mc].SLM.DTR0.tRCD + 5;

	TIMING(mc, cha).tRP  = RO(Proc)->Uncore.MC[mc].SLM.DTR0.tRP + 5;

	TIMING(mc, cha).tRAS = RO(Proc)->Uncore.MC[mc].SLM.DTR1.tRAS;

	TIMING(mc, cha).tRRD = RO(Proc)->Uncore.MC[mc].SLM.DTR1.tRRD + 4;

	TIMING(mc, cha).tRFC = \
			RO(Proc)->Uncore.MC[mc].SLM.DTR0.tXS == 0 ? 256 : 384;

	switch (RO(Proc)->Uncore.MC[mc].SLM.DRFC.tREFI) {
	case 0 ... 1:
		TIMING(mc, cha).tREFI = 0;
		break;
	case 2:
		TIMING(mc, cha).tREFI = 39;
		break;
	case 3:
		TIMING(mc, cha).tREFI = 78;
		break;
	}
	TIMING(mc, cha).tREFI *= RO(Shm)->Uncore.CtrlSpeed;
	TIMING(mc, cha).tREFI /= 20;

	TIMING(mc, cha).tCKE  = RO(Proc)->Uncore.MC[mc].SLM.DRMC.CKEVAL;

	TIMING(mc, cha).tRTPr = RO(Proc)->Uncore.MC[mc].SLM.DTR1.tRTP + 4;

	TIMING(mc, cha).tWTPr = RO(Proc)->Uncore.MC[mc].SLM.DTR1.tWTP + 14;

	TIMING(mc, cha).B2B   = RO(Proc)->Uncore.MC[mc].SLM.DTR1.tCCD;

	switch (RO(Proc)->Uncore.MC[mc].SLM.DTR1.tFAW) {
	case 0 ... 1:
		TIMING(mc, cha).tFAW = 0;
		break;
	default:
		TIMING(mc, cha).tFAW = \
		10 + ((unsigned int)RO(Proc)->Uncore.MC[mc].SLM.DTR1.tFAW << 1);
		break;
	}

	TIMING(mc, cha).tCWL = RO(Proc)->Uncore.MC[mc].SLM.DTR1.tWCL + 3;

/*TODO( Read to Read. Same Rank )
	TIMING(mc, cha).tsrRdTRd = RO(Proc)->Uncore.MC[mc].SLM.DTR?.;
*/
	TIMING(mc, cha).tsrRdTWr = 6 + RO(Proc)->Uncore.MC[mc].SLM.DTR3.tRWSR;

	TIMING(mc, cha).tsrWrTRd = 11 + RO(Proc)->Uncore.MC[mc].SLM.DTR3.tWRSR;
/*TODO( Write to Write. Same Rank )
	TIMING(mc, cha).tsrWrTWr = RO(Proc)->Uncore.MC[mc].SLM.DTR?.;
*/
/* Different Rank */
	TIMING(mc, cha).tdrRdTRd = RO(Proc)->Uncore.MC[mc].SLM.DTR2.tRRDR;
	if (TIMING(mc, cha).tdrRdTRd > 0) {
		TIMING(mc, cha).tdrRdTRd += 5;
	}

	TIMING(mc, cha).tdrRdTWr = RO(Proc)->Uncore.MC[mc].SLM.DTR2.tRWDR;
	if (TIMING(mc, cha).tdrRdTWr > 0) {
		TIMING(mc, cha).tdrRdTWr += 5;
	}

	TIMING(mc, cha).tdrWrTRd = RO(Proc)->Uncore.MC[mc].SLM.DTR3.tWRDR;
	if (TIMING(mc, cha).tdrWrTRd > 0) {
		TIMING(mc, cha).tdrWrTRd += 3;
	}

	TIMING(mc, cha).tdrWrTWr = 4 + RO(Proc)->Uncore.MC[mc].SLM.DTR2.tWWDR;
/* Different DIMM */
	TIMING(mc, cha).tddRdTRd = RO(Proc)->Uncore.MC[mc].SLM.DTR2.tRRDD;
	if (TIMING(mc, cha).tddRdTRd > 0) {
		TIMING(mc, cha).tddRdTRd += 5;
	}

	TIMING(mc, cha).tddRdTWr = RO(Proc)->Uncore.MC[mc].SLM.DTR2.tRWDD;
	if (TIMING(mc, cha).tddRdTWr > 0) {
		TIMING(mc, cha).tddRdTWr += 5;
	}

	TIMING(mc, cha).tddWrTRd = 4 + RO(Proc)->Uncore.MC[mc].SLM.DTR3.tWRDD;

	TIMING(mc, cha).tddWrTWr = 4 + RO(Proc)->Uncore.MC[mc].SLM.DTR2.tWWDD;
/* Command Rate */
	TIMING(mc, cha).CMD_Rate = 1 + RO(Proc)->Uncore.MC[mc].SLM.DTR1.tCMD;

	TIMING(mc, cha).tXS = RO(Proc)->Uncore.MC[mc].SLM.DTR0.tXS;

	TIMING(mc, cha).tXP = RO(Proc)->Uncore.MC[mc].SLM.DTR3.tXP;
/* Topology */
	for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
	{
		unsigned long long DIMM_Size;
		const struct {
			unsigned int	Banks,
					Rows,
					Cols;
		} DDR3L[4] = {
			{ .Banks = 8,	.Rows = 1<<14,	.Cols = 1<<10	},
			{ .Banks = 8,	.Rows = 1<<15,	.Cols = 1<<10	},
			{ .Banks = 8,	.Rows = 1<<16,	.Cols = 1<<10	},
			{ .Banks = 8,	.Rows = 1<<14,	.Cols = 1<<10	}
		};
	    if  (cha == 0) {
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = \
					RO(Proc)->Uncore.MC[mc].SLM.DRP.RKEN0
				+	RO(Proc)->Uncore.MC[mc].SLM.DRP.RKEN1;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = \
			DDR3L[RO(Proc)->Uncore.MC[mc].SLM.DRP.DIMMDDEN0].Banks;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = \
			DDR3L[RO(Proc)->Uncore.MC[mc].SLM.DRP.DIMMDDEN0].Rows;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = \
			DDR3L[RO(Proc)->Uncore.MC[mc].SLM.DRP.DIMMDDEN0].Cols;
	    } else {
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = \
					RO(Proc)->Uncore.MC[mc].SLM.DRP.RKEN2
				+	RO(Proc)->Uncore.MC[mc].SLM.DRP.RKEN3;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = \
			DDR3L[RO(Proc)->Uncore.MC[mc].SLM.DRP.DIMMDDEN1].Banks;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = \
			DDR3L[RO(Proc)->Uncore.MC[mc].SLM.DRP.DIMMDDEN1].Rows;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = \
			DDR3L[RO(Proc)->Uncore.MC[mc].SLM.DRP.DIMMDDEN1].Cols;
	    }
		DIMM_Size = 8LLU
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
						(unsigned int)(DIMM_Size >> 20);
	}
/* Error Correcting Code */
	TIMING(mc, cha).ECC = \
			  RO(Proc)->Uncore.MC[mc].SLM.BIOS_CFG.EFF_ECC_EN
			| RO(Proc)->Uncore.MC[mc].SLM.BIOS_CFG.ECC_EN;
    }
    if (RO(Proc)->Uncore.MC[mc].SLM.DRP.DRAMTYPE) {
	RO(Shm)->Uncore.Unit.DDR_Ver = 2;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;
    } else {
	RO(Shm)->Uncore.Unit.DDR_Ver = 3;

	if (RO(Proc)->Uncore.MC[mc].SLM.DRP.ENLPDDR3) {
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;
	} else {
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;
	}
    }
  }
}

void AMT_MCR(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	unsigned short mc, cha, slot;
/* BUS & DRAM frequency */
	switch (RO(Proc)->Uncore.MC[0].SLM.DTR2.AMT.DFREQ) {
	case 0b000:
		RO(Shm)->Uncore.CtrlSpeed = 400LLU;
		RO(Shm)->Uncore.Bus.Rate = 800;
		break;
	case 0b001:
		RO(Shm)->Uncore.CtrlSpeed = 533LLU;
		RO(Shm)->Uncore.Bus.Rate = 1066;
		break;
	case 0b010:
		RO(Shm)->Uncore.CtrlSpeed = 666LLU;
		RO(Shm)->Uncore.Bus.Rate = 1333;
		break;
	case 0b011:
		RO(Shm)->Uncore.CtrlSpeed = 800LLU;
		RO(Shm)->Uncore.Bus.Rate = 1600;
		break;
	case 0b100:
		RO(Shm)->Uncore.CtrlSpeed = 933LLU;
		RO(Shm)->Uncore.Bus.Rate = 1866;
		break;
	case 0b101:
		RO(Shm)->Uncore.CtrlSpeed = 1066LLU;
		RO(Shm)->Uncore.Bus.Rate = 2133;
		break;
	default:
		RO(Shm)->Uncore.CtrlSpeed = 1066LLU;
		RO(Shm)->Uncore.Bus.Rate = 2133;
		break;
	}
	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MTS;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MTS;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
    RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
    RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
/* Standard Timings */
	TIMING(mc, cha).tCL  = RO(Proc)->Uncore.MC[mc].SLM.DTR0.AMT.tCL + 5;

	TIMING(mc, cha).tRCD = RO(Proc)->Uncore.MC[mc].SLM.DTR0.AMT.tRCD + 5;

	TIMING(mc, cha).tRP  = RO(Proc)->Uncore.MC[mc].SLM.DTR0.AMT.tRP + 5;

	TIMING(mc, cha).tRAS = RO(Proc)->Uncore.MC[mc].SLM.DTR1.AMT.tRAS + 14;

	TIMING(mc, cha).tRRD = RO(Proc)->Uncore.MC[mc].SLM.DTR1.AMT.tRRD + 4;

	TIMING(mc, cha).tRFC = \
		RO(Proc)->Uncore.MC[mc].SLM.DTR0.AMT.tXS == 0 ? 256 : 384;

	switch (RO(Proc)->Uncore.MC[mc].SLM.DRFC.AMT.tREFI) {
	case 0 ... 1:
		TIMING(mc, cha).tREFI = 0;
		break;
	case 2:
		TIMING(mc, cha).tREFI = 39;
		break;
	case 3:
		TIMING(mc, cha).tREFI = 78;
		break;
	}
	TIMING(mc, cha).tREFI *= RO(Shm)->Uncore.CtrlSpeed;
	TIMING(mc, cha).tREFI /= 20;

	TIMING(mc, cha).tCKE = RO(Proc)->Uncore.MC[mc].SLM.DRMC.AMT.CKEVAL;

	TIMING(mc, cha).tRTPr= RO(Proc)->Uncore.MC[mc].SLM.DTR1.AMT.tRTP + 4;

	TIMING(mc, cha).tWTPr= RO(Proc)->Uncore.MC[mc].SLM.DTR1.AMT.tWTP + 15;

	switch (RO(Proc)->Uncore.MC[mc].SLM.DTR1.AMT.tCCD) {
	case 0:
		TIMING(mc, cha).B2B = 4;
		break;
	case 1:
		TIMING(mc, cha).B2B = 12;
		break;
	case 2:
		TIMING(mc, cha).B2B = 18;
		break;
	case 3:
	default:
		TIMING(mc, cha).B2B = 0;
		break;
	}

	switch (RO(Proc)->Uncore.MC[mc].SLM.DTR1.AMT.tFAW) {
	case 0 ... 1:
	case 0xd ... 0xf:
		TIMING(mc, cha).tFAW = 0;
		break;
	default:
		TIMING(mc, cha).tFAW = \
		10 + ((unsigned int)RO(Proc)->Uncore.MC[mc].SLM.DTR1.AMT.tFAW << 1);
		break;
	}

	TIMING(mc, cha).tCWL = RO(Proc)->Uncore.MC[mc].SLM.DTR1.AMT.tWCL + 3;

/*TODO( Read to Read. Same Rank )
	TIMING(mc, cha).tsrRdTRd = RO(Proc)->Uncore.MC[mc].SLM.DTR?.;
*/
	TIMING(mc, cha).tsrRdTWr = 6
				 + RO(Proc)->Uncore.MC[mc].SLM.DTR3.AMT.tRWSR;

	TIMING(mc, cha).tsrWrTRd = 11
				 + RO(Proc)->Uncore.MC[mc].SLM.DTR3.AMT.tWRSR;
/*TODO( Write to Write. Same Rank )
	TIMING(mc, cha).tsrWrTWr = RO(Proc)->Uncore.MC[mc].SLM.DTR?.;
*/
/* Different Rank */
	TIMING(mc, cha).tdrRdTRd = RO(Proc)->Uncore.MC[mc].SLM.DTR2.AMT.tRRDR;
	if (TIMING(mc, cha).tdrRdTRd > 0) {
		TIMING(mc, cha).tdrRdTRd += 5;
	}

	TIMING(mc, cha).tdrRdTWr = RO(Proc)->Uncore.MC[mc].SLM.DTR2.AMT.tRWDR;
	if (TIMING(mc, cha).tdrRdTWr > 0) {
		TIMING(mc, cha).tdrRdTWr += 5;
	}

	TIMING(mc, cha).tdrWrTRd = RO(Proc)->Uncore.MC[mc].SLM.DTR3.AMT.tWRDR;
	if (TIMING(mc, cha).tdrWrTRd > 0) {
		TIMING(mc, cha).tdrWrTRd += 3;
	}

	TIMING(mc, cha).tdrWrTWr = RO(Proc)->Uncore.MC[mc].SLM.DTR2.AMT.tWWDR;
	if (TIMING(mc, cha).tdrWrTWr > 1) {
		TIMING(mc, cha).tdrWrTWr += 4;
	}
/*TODO( Different DIMM )
	TIMING(mc, cha).tddRdTRd = RO(Proc)->Uncore.MC[mc].SLM.DTR2.AMT.tRRDD;

	TIMING(mc, cha).tddRdTWr = RO(Proc)->Uncore.MC[mc].SLM.DTR2.AMT.tRWDD;

	TIMING(mc, cha).tddWrTRd = RO(Proc)->Uncore.MC[mc].SLM.DTR3.AMT.tWRDD;

	TIMING(mc, cha).tddWrTWr = RO(Proc)->Uncore.MC[mc].SLM.DTR2.AMT.tWWDD;
*/
/* Command Rate */
	TIMING(mc, cha).CMD_Rate = 1
				 + RO(Proc)->Uncore.MC[mc].SLM.DTR1.AMT.tCMD;

	TIMING(mc, cha).tXS = RO(Proc)->Uncore.MC[mc].SLM.DTR0.AMT.tXS;

	TIMING(mc, cha).tXP = RO(Proc)->Uncore.MC[mc].SLM.DTR3.AMT.tXP;
/* Topology */
	for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
	{
		unsigned long long DIMM_Size;
		const struct {
			unsigned int	Banks,
					Rows,
					Cols;
		} DDR3L[4] = {
			{ .Banks = 8,	.Rows = 1<<14,	.Cols = 1<<10	},
			{ .Banks = 8,	.Rows = 1<<15,	.Cols = 1<<10	},
			{ .Banks = 8,	.Rows = 1<<16,	.Cols = 1<<10	},
			{ .Banks = 8,	.Rows = 1<<14,	.Cols = 1<<10	}
		};

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = \
				RO(Proc)->Uncore.MC[mc].SLM.DRP.AMT.RKEN0
			+	RO(Proc)->Uncore.MC[mc].SLM.DRP.AMT.RKEN1;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = \
		DDR3L[RO(Proc)->Uncore.MC[mc].SLM.DRP.AMT.DIMMDDEN0].Banks;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = \
		DDR3L[RO(Proc)->Uncore.MC[mc].SLM.DRP.AMT.DIMMDDEN0].Rows;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = \
		DDR3L[RO(Proc)->Uncore.MC[mc].SLM.DRP.AMT.DIMMDDEN0].Cols;

		DIMM_Size = 8LLU
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
						(unsigned int)(DIMM_Size >> 20);
	}
/* Error Correcting Code */
	TIMING(mc, cha).ECC = RO(Proc)->Uncore.MC[mc].SLM.BIOS_CFG.ECC_EN;
    }
    if (RO(Proc)->Uncore.MC[mc].SLM.DRP.AMT.DRAMTYPE) {
	RO(Shm)->Uncore.Unit.DDR_Ver = 2;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;
    } else {
	RO(Shm)->Uncore.Unit.DDR_Ver = 3;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;
    }
  }
}

void NHM_IMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, slot;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
    RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
    RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	TIMING(mc, cha).tCL = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.MR0_1.tCL ?
		4 + RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.MR0_1.tCL : 0;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.MR0_1.tWR) {
	case 0b001:
		TIMING(mc, cha).tWR = 5;
		break;
	case 0b010:
		TIMING(mc, cha).tWR = 6;
		break;
	case 0b011:
		TIMING(mc, cha).tWR = 7;
		break;
	case 0b100:
		TIMING(mc, cha).tWR = 8;
		break;
	case 0b101:
		TIMING(mc, cha).tWR = 10;
		break;
	case 0b110:
		TIMING(mc, cha).tWR = 12;
		break;
	}
	TIMING(mc, cha).tRCD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Bank.tRCD;

	TIMING(mc, cha).tRP = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Bank.tRP;

	TIMING(mc, cha).tRAS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Bank.tRAS;

	TIMING(mc, cha).tRRD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_B.tRRD;

	TIMING(mc, cha).tRFC = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Refresh.tRFC;

	TIMING(mc, cha).tREFI = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Refresh.tREFI_8;

	TIMING(mc, cha).tCKE = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.CKE_Timing.tCKE;

	TIMING(mc, cha).tXS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.CKE_Timing.tXS;

	TIMING(mc, cha).tXP = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.CKE_Timing.tXP;

	TIMING(mc, cha).tRTPr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Bank.tRTPr;

	TIMING(mc, cha).tWTPr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Bank.tWTPr;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_A.tsrRdTRd) {
	case 0b0:
		TIMING(mc, cha).tsrRdTRd = 4;
		break;
	case 0b1:
		TIMING(mc, cha).tsrRdTRd = 6;
		break;
	}
	TIMING(mc, cha).tdrRdTRd = 2
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_A.tdrRdTRd;

	TIMING(mc, cha).tddRdTRd = 2
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_A.tddRdTRd;

	TIMING(mc, cha).tsrRdTWr = 2
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_A.tsrRdTWr;

	TIMING(mc, cha).tdrRdTWr = 2
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_A.tdrRdTWr;

	TIMING(mc, cha).tddRdTWr = 2
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_A.tddRdTWr;

	TIMING(mc, cha).tsrWrTRd = 10
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_A.tsrWrTRd;

	TIMING(mc, cha).tdrWrTRd = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_A.tdrWrTRd;

	TIMING(mc, cha).tddWrTRd = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_A.tddWrTRd;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_B.tsrWrTWr) {
	case 0b0:
		TIMING(mc, cha).tsrWrTWr = 4;
		break;
	case 0b1:
		TIMING(mc, cha).tsrWrTWr = 6;
		break;
	}
	TIMING(mc, cha).tdrWrTWr = 2
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_B.tdrWrTWr;

	TIMING(mc, cha).tddWrTWr = 2
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_B.tddWrTWr;

	TIMING(mc, cha).tFAW = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_B.tFAW;

	TIMING(mc, cha).B2B  = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Rank_B.B2B;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.MR2_3.tCWL) {
	case 0b000:
		TIMING(mc, cha).tCWL = 5;
		break;
	case 0b001:
		TIMING(mc, cha).tCWL = 6;
		break;
	case 0b010:
		TIMING(mc, cha).tCWL = 7;
		break;
	case 0b011:
		TIMING(mc, cha).tCWL = 8;
		break;
	}

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.Sched.ENABLE_2N_3N)
	{
	case 0b00:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b01:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	case 0b10:
		TIMING(mc, cha).CMD_Rate = 3;
		break;
	}

	if (RO(Proc)->Uncore.MC[mc].Channel[cha].NHM.DIMM_Init.REGISTERED_DIMM)
	{
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_RDIMM;
	} else {
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;
	}

     for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++) {
      if (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].DOD.DIMMPRESENT)
      {
	unsigned long long DIMM_Size;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].DOD.NUMBANK)
	{
	case 0b00:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 4;
		break;
	case 0b01:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 8;
		break;
	case 0b10:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 16;
		break;
	}
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].DOD.NUMRANK)
	{
	case 0b00:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = 1;
		break;
	case 0b01:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = 2;
		break;
	case 0b10:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = 4;
		break;
	}
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].DOD.NUMROW)
	{
	case 0b000:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 1 << 12;
		break;
	case 0b001:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 1 << 13;
		break;
	case 0b010:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 1 << 14;
		break;
	case 0b011:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 1 << 15;
		break;
	case 0b100:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 1 << 16;
		break;
	}
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].DOD.NUMCOL)
	{
	case 0b000:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1 << 10;
		break;
	case 0b001:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1 << 11;
		break;
	case 0b010:
		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1 << 12;
		break;
	}

	DIMM_Size	= 8LLU
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
						(unsigned int)(DIMM_Size >> 20);
      }
     }
	TIMING(mc, cha).ECC = (unsigned int)\
			( RO(Proc)->Uncore.MC[mc].NHM.STATUS.ECC_ENABLED
			& RO(Proc)->Uncore.MC[mc].NHM.CONTROL.ECC_ENABLED );
    }
  }
}

void QPI_CLK(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	switch (RO(Proc)->Uncore.Bus.DimmClock.QCLK_RATIO) {
	case 0b00110:
		RO(Shm)->Uncore.CtrlSpeed = 800;
		break;
	case 0b01000:
		RO(Shm)->Uncore.CtrlSpeed = 1066;
		break;
	case 0b01010:
		RO(Shm)->Uncore.CtrlSpeed = 1333;
		break;
	case 0b01100:
		RO(Shm)->Uncore.CtrlSpeed = 1600;
		break;
	case 0b01110:
		RO(Shm)->Uncore.CtrlSpeed = 1866;
		break;
	case 0b10000:
		RO(Shm)->Uncore.CtrlSpeed = 2133;
		break;
	case 0b000000:
		fallthrough;
	default:
		RO(Shm)->Uncore.CtrlSpeed = 800;
		break;
	}

	RO(Shm)->Uncore.CtrlSpeed *= RO(Core)->Clock.Hz;
	RO(Shm)->Uncore.CtrlSpeed /= RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Bus.Rate = \
			RO(Proc)->Uncore.Bus.QuickPath.X58.QPIFREQSEL == 0b00 ?
		4800 :	RO(Proc)->Uncore.Bus.QuickPath.X58.QPIFREQSEL == 0b10 ?
		6400 :	RO(Proc)->Uncore.Bus.QuickPath.X58.QPIFREQSEL == 0b01 ?
		5866 : 6400;

	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MTS;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MTS;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Ver  = 3;
}

void X58_VTD(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	UNUSED(RO(Core));

	RO(Shm)->Proc.Technology.IOMMU = \
				!RO(Proc)->Uncore.Bus.QuickPath.X58.VT_d;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Major = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Major;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Minor = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Minor;
}

void DMI_CLK(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	switch (RO(Proc)->Uncore.Bus.DimmClock.QCLK_RATIO) {
	case 0b00010:
		RO(Shm)->Uncore.CtrlSpeed = 266;
		break;
	case 0b00100:
		RO(Shm)->Uncore.CtrlSpeed = 533;
		break;
	case 0b00110:
		RO(Shm)->Uncore.CtrlSpeed = 800;
		break;
	case 0b01000:
		RO(Shm)->Uncore.CtrlSpeed = 1066;
		break;
	case 0b01010:
		RO(Shm)->Uncore.CtrlSpeed = 1333;
		break;
	case 0b000000:
		fallthrough;
	default:
		RO(Shm)->Uncore.CtrlSpeed = 266;
		break;
	}

	RO(Shm)->Uncore.CtrlSpeed *= RO(Core)->Clock.Hz;
	RO(Shm)->Uncore.CtrlSpeed /= RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Bus.Rate = 2500; /* TODO: hardwired to Lynnfield */

	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MTS;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MTS;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Ver  = 3;
}

unsigned int SNB_DimmWidthToRows(unsigned int width)
{
	return 1 << (15 + width);
}

void SNB_IMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, slot;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
	const unsigned short dimmSize[2][2] = {
		{
			RO(Proc)->Uncore.MC[mc].SNB.MAD0.Dimm_A_Size,
			RO(Proc)->Uncore.MC[mc].SNB.MAD0.Dimm_B_Size
		}, {
			RO(Proc)->Uncore.MC[mc].SNB.MAD1.Dimm_A_Size,
			RO(Proc)->Uncore.MC[mc].SNB.MAD1.Dimm_B_Size
		}
	};

     RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
     RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	TIMING(mc, cha).tCL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.DBP.tCL;

	TIMING(mc, cha).tRCD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.DBP.tRCD;

	TIMING(mc, cha).tRP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.DBP.tRP;

	TIMING(mc, cha).tRAS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.DBP.tRAS;

	TIMING(mc, cha).tRRD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RAP.tRRD;

	TIMING(mc, cha).tRFC = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RFTP.tRFC;

	TIMING(mc, cha).tREFI = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RFTP.tREFI;

	TIMING(mc, cha).tWR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RAP.tWR;

	TIMING(mc, cha).tRTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RAP.tRTPr;

	TIMING(mc, cha).tWTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RAP.tWTPr;

	TIMING(mc, cha).tFAW = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RAP.tFAW;

	TIMING(mc, cha).tCKE = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RAP.tCKE;

	TIMING(mc, cha).tCWL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.DBP.tCWL;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RAP.CMD_Stretch) {
	case 0b00:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b10:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	case 0b11:
		TIMING(mc, cha).CMD_Rate = 3;
		break;
	default:
		TIMING(mc, cha).CMD_Rate = 0;
		break;
	}

	TIMING(mc, cha).tddWrTRd = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tWRDD;

	TIMING(mc, cha).tdrWrTRd = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tWRDR;

	TIMING(mc, cha).tsrWrTRd = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.OTP.tWRSR;

	TIMING(mc, cha).tddRdTWr = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tRWDD;

	TIMING(mc, cha).tdrRdTWr = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tRWDR;

	TIMING(mc, cha).tsrRdTWr = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tRWSR;

	TIMING(mc, cha).tddRdTRd = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.OTP.tRRDD;

	TIMING(mc, cha).tdrRdTRd = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tRRDR;

	TIMING(mc, cha).tsrRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tRRSR;

	TIMING(mc, cha).tddWrTWr = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tWWDD;

	TIMING(mc, cha).tdrWrTWr = 1
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tWWDR;

	TIMING(mc, cha).tsrWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tWWSR;

	TIMING(mc, cha).B2B = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.RWP.tCCD;

	TIMING(mc, cha).tXS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.SRFTP.tXS;

	TIMING(mc, cha).PDM_EN = \
		0 != RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.PDWN.PDWN_Mode;

	TIMING(mc, cha).PDM_MODE = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.PDWN.GLPDN;

	TIMING(mc, cha).PDM_AGGR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SNB.PDWN.PDWN_Mode;

     for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
     {
	unsigned long long DIMM_Banks;
	const unsigned short
		Dimm_A_Map = cha & 1	? RO(Proc)->Uncore.MC[mc].SNB.MAD1.DAS
					: RO(Proc)->Uncore.MC[mc].SNB.MAD0.DAS;

      if (slot == Dimm_A_Map)
      {
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = \
			cha & 1 ? RO(Proc)->Uncore.MC[mc].SNB.MAD1.DANOR
				: RO(Proc)->Uncore.MC[mc].SNB.MAD0.DANOR;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = \
	    SNB_DimmWidthToRows(cha & 1 ? RO(Proc)->Uncore.MC[mc].SNB.MAD1.DAW
					: RO(Proc)->Uncore.MC[mc].SNB.MAD0.DAW);
      }
      else
      {
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = \
			cha & 1 ? RO(Proc)->Uncore.MC[mc].SNB.MAD1.DBNOR
				: RO(Proc)->Uncore.MC[mc].SNB.MAD0.DBNOR;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = \
	    SNB_DimmWidthToRows(cha & 1 ? RO(Proc)->Uncore.MC[mc].SNB.MAD1.DBW
					: RO(Proc)->Uncore.MC[mc].SNB.MAD0.DBW);
      }
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks++;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1 << 10;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
				dimmSize[cha][(slot ^ Dimm_A_Map) % 2] * 256;

	DIMM_Banks = RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size;
	DIMM_Banks = DIMM_Banks * 1024LLU * 1024LLU;
	DIMM_Banks = DIMM_Banks
		/ (8LLU * RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols);

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = DIMM_Banks;
     }
	TIMING(mc, cha).ECC = (cha == 0) ?
					  RO(Proc)->Uncore.MC[mc].SNB.MAD0.ECC
					: RO(Proc)->Uncore.MC[mc].SNB.MAD1.ECC;
    }
  }
}

unsigned long long SNB_MCLK_FSB(RO(PROC) *RO(Proc),
				const unsigned long long fallback)
{
	switch (RO(Proc)->Uncore.Bus.ClkCfg.FSB_Select) {
	case 0b111:
		return 1067;
	case 0b110:
		return 1333;
	case 0b101:
		return 1600;
	case 0b100:
		return 1867;
	case 0b011:
		return 2133;
	case 0b010:
		return 2400;
	case 0b001:
		return 2667;
	case 0b000:
		return fallback;
	}
	return fallback;
}

unsigned long long SNB_MCLK_RAM(RO(PROC) *RO(Proc),
				const unsigned long long fallback)
{
	switch (RO(Proc)->Uncore.Bus.ClkCfg.RAM_Select) {
	case 0b111:
		return 1067;
	case 0b110:
		return 1333;
	case 0b101:
		return 1600;
	case 0b100:
		return 1867;
	case 0b011:
		return 2133;
	case 0b010:
		return 2400;
	case 0b001:
		return 2667;
	case 0b000:
		return SNB_MCLK_FSB(RO(Proc), fallback);
	}
	return fallback;
}

unsigned short BIOS_DDR(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc),
			RO(CORE) *RO(Core))
{
	UNUSED(RO(Core));
    if (RO(Proc)->Uncore.Bus.BIOS_DDR.MEMCLK != 0)
    {
	RO(Shm)->Uncore.CtrlSpeed = RO(Proc)->Uncore.Bus.BIOS_DDR.MEMCLK;

	if (RO(Proc)->Uncore.Bus.BIOS_DDR.PLL_REF100 == 1) {
		RO(Shm)->Uncore.CtrlSpeed = 200 * RO(Shm)->Uncore.CtrlSpeed;
	} else {
		RO(Shm)->Uncore.CtrlSpeed = 800 * RO(Shm)->Uncore.CtrlSpeed;
		RO(Shm)->Uncore.CtrlSpeed = RO(Shm)->Uncore.CtrlSpeed / 3;
	}
	return RO(Shm)->Uncore.CtrlSpeed;
    }
	return 0;
}

void SNB_CAP(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
    if (BIOS_DDR(RO(Shm), RO(Proc), RO(Core)) == 0) {
	switch (RO(Proc)->Uncore.Bus.SNB_Cap.DMFC) {
	case 0b111:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 1067);
		break;
	case 0b110:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 1333);
		break;
	case 0b101:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 1600);
		break;
	case 0b100:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 1867);
		break;
	case 0b011:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 2133);
		break;
	case 0b010:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 2400);
		break;
	case 0b001:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 2667);
		break;
	case 0b000:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 2933);
		break;
	}
    }
	RO(Shm)->Uncore.Bus.Rate = RO(Shm)->Uncore.CtrlSpeed;
	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MHZ;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Ver  = 3;
	RO(Shm)->Uncore.Unit.DDR_Std  = RAM_STD_UNSPEC;

	RO(Shm)->Proc.Technology.IOMMU = !RO(Proc)->Uncore.Bus.SNB_Cap.VT_d;
}

void SNB_EP_IMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, slot;

    for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
    {
     RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
     RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

      for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
      {
	TIMING(mc, cha).tCL = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.DBP.EP.tCL;

	TIMING(mc, cha).tRCD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.DBP.EP.tRCD;

	TIMING(mc, cha).tRP = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.DBP.EP.tRP;

	TIMING(mc, cha).tCWL = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.DBP.EP.tCWL;

	TIMING(mc, cha).tRAS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.DBP.EP.tRAS;

	TIMING(mc, cha).tRRD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RAP.EP.tRRD;

	TIMING(mc, cha).tRFC = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RFTP.EP.tRFC;

	TIMING(mc, cha).tREFI = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RFTP.EP.tREFI;

	TIMING(mc, cha).tWR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RAP.EP.tWR;

	TIMING(mc, cha).tRTPr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RAP.EP.tRTPr;

	TIMING(mc, cha).tWTPr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RAP.EP.tWTPr;

	TIMING(mc, cha).tFAW = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RAP.EP.tFAW;

	TIMING(mc, cha).tCKE = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RAP.EP.tCKE;

	TIMING(mc, cha).tddWrTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RWP.EP.tWRDD;

	TIMING(mc, cha).tdrWrTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RWP.EP.tWRDR;
/*TODO
	TIMING(mc, cha).tsrWrTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.???.EP.t????;
*/
	TIMING(mc, cha).tddRdTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.OTP.EP.tRWDD;

	TIMING(mc, cha).tdrRdTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.OTP.EP.tRWDR;

	TIMING(mc, cha).tsrRdTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.OTP.EP.tRWSR;

	TIMING(mc, cha).tddRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RWP.EP.tRRDD;

	TIMING(mc, cha).tdrRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RWP.EP.tRRDR;
/* TODO
	TIMING(mc, cha).tsrRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.???.EP.t????;
*/
	TIMING(mc, cha).tddWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RWP.EP.tWWDD;

	TIMING(mc, cha).tdrWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RWP.EP.tWWDR;
/* TODO
	TIMING(mc, cha).tsrWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.???.EP.t????;
*/
	TIMING(mc, cha).B2B = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RWP.EP.tCCD;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.RAP.EP.CMD_Stretch)
	{
	case 0b00:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b10:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	case 0b11:
		TIMING(mc, cha).CMD_Rate = 3;
		break;
	default:
		TIMING(mc, cha).CMD_Rate = 0;
		break;
	}

	TIMING(mc, cha).tXS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.SRFTP.EP.tXS_DLL;

	TIMING(mc, cha).tXP = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SNB_EP.OTP.EP.tXP;

	for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
	{
	    if (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].MTR.DIMM_POP)
	    {
		unsigned long long DIMM_Size;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 4 << \
		RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].MTR.DDR3_WIDTH;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = 1 << \
		RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].MTR.RANK_CNT;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 1 << ( 13
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].MTR.RA_WIDTH);

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1 << ( 10
		+ RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].MTR.CA_WIDTH);

		DIMM_Size = 8LLU
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
						(unsigned int)(DIMM_Size >> 20);
	    }
	}

	TIMING(mc, cha).ECC = (unsigned int)\
				( RO(Proc)->Uncore.MC[mc].SNB_EP.TECH.ECC_EN
				& !RO(Proc)->Uncore.Bus.SNB_EP_Cap3.ECC_DIS );
      }
    }
}

void SNB_EP_CAP(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	switch (RO(Proc)->Uncore.Bus.SNB_EP_Cap1.DMFC) {
	case 0b111:
		RO(Shm)->Uncore.CtrlSpeed = 1066;
		break;
	case 0b110:
		RO(Shm)->Uncore.CtrlSpeed = 1333;
		break;
	case 0b101:
		RO(Shm)->Uncore.CtrlSpeed = 1600;
		break;
	case 0b100:
		RO(Shm)->Uncore.CtrlSpeed = 1866;
		break;
	case 0b011:
		RO(Shm)->Uncore.CtrlSpeed = 2133;
		break;
	case 0b010:
		RO(Shm)->Uncore.CtrlSpeed = 2400;
		break;
	case 0b001:
		RO(Shm)->Uncore.CtrlSpeed = 2666;
		break;
	case 0b000:
		RO(Shm)->Uncore.CtrlSpeed = 2933;
		break;
	}

	RO(Shm)->Uncore.CtrlSpeed *= RO(Core)->Clock.Hz;
	RO(Shm)->Uncore.CtrlSpeed /= RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Bus.Rate = \
		RO(Proc)->Uncore.Bus.QuickPath.EP.QPIFREQSEL == 0b010 ?
	5600 :	RO(Proc)->Uncore.Bus.QuickPath.EP.QPIFREQSEL == 0b011 ?
	6400 :	RO(Proc)->Uncore.Bus.QuickPath.EP.QPIFREQSEL == 0b100 ?
	7200 :	RO(Proc)->Uncore.Bus.QuickPath.EP.QPIFREQSEL == 0b101 ?
	8000 : 5000;

	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MTS;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MTS;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Ver  = 3;

	if (RO(Proc)->Uncore.Bus.SNB_EP_Cap3.RDIMM_DIS)
	{
		if (RO(Proc)->Uncore.Bus.SNB_EP_Cap3.UDIMM_DIS) {
			RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_UNSPEC;
		} else {
			RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;
		}
	} else {
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_RDIMM;
	}
}

void IVB_CAP(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
    if (BIOS_DDR(RO(Shm), RO(Proc), RO(Core)) == 0) {
	switch (RO(Proc)->Uncore.Bus.IVB_Cap.DMFC) {
	case 0b111:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 1067);
		break;
	case 0b110:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 1333);
		break;
	case 0b101:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 1600);
		break;
	case 0b100:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 1867);
		break;
	case 0b011:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 2133);
		break;
	case 0b010:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 2400);
		break;
	case 0b001:
		RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc), 2667);
		break;
	case 0b000:
		switch (RO(Proc)->ArchID) {
		case IvyBridge:
		case Haswell_ULT:
			RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc),2933);
			break;
		case Haswell_DT:
		case Haswell_EP:
		case Haswell_ULX:
			RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc),2667);
			break;
		case Broadwell:
		case Broadwell_D:
		case Broadwell_H:
		case Broadwell_EP:
			RO(Shm)->Uncore.CtrlSpeed = SNB_MCLK_RAM(RO(Proc),3200);
			break;
		}
		break;
	}
    }
	RO(Shm)->Uncore.Bus.Rate = RO(Shm)->Uncore.CtrlSpeed;
	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MHZ;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Ver  = 3;
	RO(Shm)->Uncore.Unit.DDR_Std  = RAM_STD_UNSPEC;

	RO(Shm)->Proc.Technology.IOMMU = !RO(Proc)->Uncore.Bus.SNB_Cap.IVB.VT_d;
	RO(Shm)->Proc.Technology.OC = RO(Proc)->Uncore.Bus.IVB_Cap.OC_ENABLED;
}

unsigned int DimmWidthToRows(unsigned int width)
{
	unsigned int rows = 0;
	switch (width) {
	case 0b00:
		rows = 8;
		break;
	case 0b01:
		rows = 16;
		break;
	case 0b10:
		rows = 32;
		break;
	}
	return (8 * 1024 * rows);
}

void HSW_IMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, slot;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
	const unsigned short dimmSize[2][2] = {
		{
			RO(Proc)->Uncore.MC[mc].SNB.MAD0.Dimm_A_Size,
			RO(Proc)->Uncore.MC[mc].SNB.MAD0.Dimm_B_Size
		}, {
			RO(Proc)->Uncore.MC[mc].SNB.MAD1.Dimm_A_Size,
			RO(Proc)->Uncore.MC[mc].SNB.MAD1.Dimm_B_Size
		}
	};

      RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
      RO(Shm)->Uncore.MC[mc].ChannelCount=RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	TIMING(mc, cha).tCL   = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank.tCL;

	TIMING(mc, cha).tCWL  = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank.tCWL;
/*TODO(Not Found)
	TIMING(mc, cha).tWR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW._.tWR;

	TIMING(mc, cha).tFAW = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW._.tFAW;
*/
	TIMING(mc, cha).tRP = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.REG4C00.tRP;

	TIMING(mc, cha).tRRD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.REG4C00.tRRD;

	TIMING(mc, cha).tRCD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.REG4C00.tRCD;

	TIMING(mc, cha).tRAS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.REG4C00.tRAS;

	TIMING(mc, cha).tRFC = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Refresh.tRFC;

	TIMING(mc, cha).tREFI = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Refresh.tREFI;

	TIMING(mc, cha).tsrRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Timing.tsrRdTRd;

	TIMING(mc, cha).tdrRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Timing.tdrRdTRd;

	TIMING(mc, cha).tddRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Timing.tddRdTRd;

	TIMING(mc, cha).tsrWrTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank_A.tsrWrTRd;

	TIMING(mc, cha).tdrWrTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank_A.tdrWrTRd;

	TIMING(mc, cha).tddWrTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank_A.tddWrTRd;

	TIMING(mc, cha).tsrWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank_A.tsrWrTWr;

	TIMING(mc, cha).tdrWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank_A.tdrWrTWr;

	TIMING(mc, cha).tddWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank_A.tddWrTWr;

	TIMING(mc, cha).tsrRdTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank_B.tsrRdTWr;

	TIMING(mc, cha).tdrRdTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank_B.tdrRdTWr;

	TIMING(mc, cha).tddRdTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Rank_B.tddRdTWr;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.Timing.CMD_Stretch) {
	case 0b00:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b10:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	case 0b11:
		TIMING(mc, cha).CMD_Rate = 3;
		break;
	default:
		TIMING(mc, cha).CMD_Rate = 0;
		break;
	}
/*
	TIMING(mc, cha).B2B = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW._.B2B;

	TIMING(mc, cha).tXS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW._.tXS;
*/
	TIMING(mc, cha).PDM_EN = \
		0 != RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.PDWN.PDWN_Mode;

	TIMING(mc, cha).PDM_MODE = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.PDWN.PDWN_Mode;

	TIMING(mc, cha).PDM_AGGR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].HSW.PDWN.PDWN_Mode;

     for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
     {
	unsigned long long DIMM_Banks;
	const unsigned short
		Dimm_A_Map = cha & 1	? RO(Proc)->Uncore.MC[mc].SNB.MAD1.DAS
					: RO(Proc)->Uncore.MC[mc].SNB.MAD0.DAS;

      if (slot == Dimm_A_Map)
      {
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = \
			cha & 1 ? RO(Proc)->Uncore.MC[mc].SNB.MAD1.DANOR
				: RO(Proc)->Uncore.MC[mc].SNB.MAD0.DANOR;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = \
		DimmWidthToRows(cha & 1 ? RO(Proc)->Uncore.MC[mc].SNB.MAD1.DAW
					: RO(Proc)->Uncore.MC[mc].SNB.MAD0.DAW);
      }
      else
      {
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = \
			cha & 1 ? RO(Proc)->Uncore.MC[mc].SNB.MAD1.DBNOR
				: RO(Proc)->Uncore.MC[mc].SNB.MAD0.DBNOR;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = \
		DimmWidthToRows(cha & 1 ? RO(Proc)->Uncore.MC[mc].SNB.MAD1.DBW
					: RO(Proc)->Uncore.MC[mc].SNB.MAD0.DBW);
      }
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks++;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1 << 10;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
				dimmSize[cha][(slot ^ Dimm_A_Map) % 2] * 256;

	DIMM_Banks = RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size;
	DIMM_Banks = DIMM_Banks * 1024LLU * 1024LLU;
	DIMM_Banks = DIMM_Banks
		/ (8LLU * RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows
			* RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols);

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = DIMM_Banks;
     }
	TIMING(mc, cha).ECC = (cha == 0) ?
					  RO(Proc)->Uncore.MC[mc].SNB.MAD0.ECC
					: RO(Proc)->Uncore.MC[mc].SNB.MAD1.ECC;
    }
    if (RO(Proc)->Uncore.MC[mc].SNB.MADCH.LPDDR) {
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;
    } else {
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;
    }
  }
}

#define HSW_CAP 	IVB_CAP

#define HSW_EP_IMC	SNB_EP_IMC

void HSW_EP_CAP(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	switch (RO(Proc)->Uncore.Bus.SNB_EP_Cap1.DMFC) {
	case 0b111:
		RO(Shm)->Uncore.CtrlSpeed = 1066;
		break;
	case 0b110:
		RO(Shm)->Uncore.CtrlSpeed = 1333;
		break;
	case 0b101:
		RO(Shm)->Uncore.CtrlSpeed = 1600;
		break;
	case 0b100:
		RO(Shm)->Uncore.CtrlSpeed = 1866;
		break;
	case 0b011:
		RO(Shm)->Uncore.CtrlSpeed = 2133;
		break;
	case 0b010:
		RO(Shm)->Uncore.CtrlSpeed = 2400;
		break;
	case 0b001:
		RO(Shm)->Uncore.CtrlSpeed = 2666;
		break;
	case 0b000:
		RO(Shm)->Uncore.CtrlSpeed = 2933;
		break;
	}

	RO(Shm)->Uncore.CtrlSpeed *= RO(Core)->Clock.Hz;
	RO(Shm)->Uncore.CtrlSpeed /= RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Bus.Rate = \
		RO(Proc)->Uncore.Bus.QuickPath.EP.QPIFREQSEL == 0b010 ?
	5600 :	RO(Proc)->Uncore.Bus.QuickPath.EP.QPIFREQSEL == 0b011 ?
	6400 :	RO(Proc)->Uncore.Bus.QuickPath.EP.QPIFREQSEL == 0b100 ?
	7200 :	RO(Proc)->Uncore.Bus.QuickPath.EP.QPIFREQSEL == 0b101 ?
	8000 :	RO(Proc)->Uncore.Bus.QuickPath.EP.QPIFREQSEL == 0b111 ?
	9600 : 6400;

	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MTS;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MTS;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;

	if (RO(Proc)->Uncore.MC[0].HSW_EP.TECH.DDR4_Mode) {
		RO(Shm)->Uncore.Unit.DDR_Ver = 4;
	} else {
		RO(Shm)->Uncore.Unit.DDR_Ver = 3;
	}
	if (RO(Proc)->Uncore.Bus.SNB_EP_Cap3.RDIMM_DIS)
	{
		if (RO(Proc)->Uncore.Bus.SNB_EP_Cap3.UDIMM_DIS) {
			RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_UNSPEC;
		} else {
			RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;
		}
	} else {
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_RDIMM;
	}
/*TODO(VT-d capability from device 30 in CAPID# registers among offsets 0x80)*/
	RO(Shm)->Proc.Technology.IOMMU = 0;
	RO(Shm)->Proc.Technology.IOMMU_Ver_Major = 0;
	RO(Shm)->Proc.Technology.IOMMU_Ver_Minor = 0;
}

void SKL_IMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
     RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
     RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	TIMING(mc, cha).tCL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.ODT.tCL;

	TIMING(mc, cha).tRCD_RD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Timing.tRP;

	TIMING(mc, cha).tRCD_WR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.ACT.tRCD_WR;

    if (TIMING(mc, cha).tRCD_WR == 0) {
	/* ACT to CAS (RD or WR) same bank minimum delay in DCLK cycles */
	TIMING(mc, cha).tRCD_WR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Timing.tRP;
    }

	TIMING(mc, cha).tRP   = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Timing.tRP;

	TIMING(mc, cha).tRAS  = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Timing.tRAS;

	TIMING(mc, cha).tRRDS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.ACT.tRRD_DG;

	TIMING(mc, cha).tRRDL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.ACT.tRRD_SG;

	TIMING(mc, cha).tRFC  = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Refresh.tRFC;

	TIMING(mc, cha).tREFI = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Refresh.tREFI;

      if (RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Timing.tWRPRE >=
		(RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.ODT.tCWL + 4U))
      {
	TIMING(mc, cha).tWR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Timing.tWRPRE
			- RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.ODT.tCWL -4U;
      }

	TIMING(mc, cha).tRTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Timing.tRDPRE;

	TIMING(mc, cha).tWTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Timing.tWRPRE;

	TIMING(mc, cha).tFAW  = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.ACT.tFAW;

	TIMING(mc, cha).tCWL  = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.ODT.tCWL;

	TIMING(mc, cha).tRDRD_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.RDRD.tRDRD_SG;

	TIMING(mc, cha).tRDRD_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.RDRD.tRDRD_DG;

	TIMING(mc, cha).tRDRD_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.RDRD.tRDRD_DR;

	TIMING(mc, cha).tRDRD_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.RDRD.tRDRD_DD;

	TIMING(mc, cha).tRDWR_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.RDWR.tRDWR_SG;

	TIMING(mc, cha).tRDWR_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.RDWR.tRDWR_DG;

	TIMING(mc, cha).tRDWR_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.RDWR.tRDWR_DR;

	TIMING(mc, cha).tRDWR_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.RDWR.tRDWR_DD;

	TIMING(mc, cha).tWRRD_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.WRRD.tWRRD_SG;

	TIMING(mc, cha).tWRRD_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.WRRD.tWRRD_DG;

	TIMING(mc, cha).tWRRD_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.WRRD.tWRRD_DR;

	TIMING(mc, cha).tWRRD_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.WRRD.tWRRD_DD;

	TIMING(mc, cha).tWRWR_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.WRWR.tWRWR_SG;

	TIMING(mc, cha).tWRWR_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.WRWR.tWRWR_DG;

	TIMING(mc, cha).tWRWR_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.WRWR.tWRWR_DR;

	TIMING(mc, cha).tWRWR_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.WRWR.tWRWR_DD;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Sched.CMD_Stretch) {
	case 0b00:
	case 0b11:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b01:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	case 0b10:
		TIMING(mc, cha).CMD_Rate = 3;
		break;
	}

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[0].Banks = \
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[1].Banks = \
	RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Sched.DRAM_Tech == 0b00 ? 16:8;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[0].Cols = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Sched.x8_device_Dimm0 ?
			1024 : 512;
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[1].Cols = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Sched.x8_device_Dimm1 ?
			1024 : 512;

	TIMING(mc, cha).tCKE = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Sched.tCKE;

	TIMING(mc, cha).tCPDED = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].SKL.Sched.tCPDED;
    }
	RO(Shm)->Uncore.MC[mc].Channel[0].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].SKL.MADC0.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[1].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].SKL.MADC1.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		RO(Proc)->Uncore.MC[mc].SKL.MADC0.Dimm_L_Map
	].Size = 1024 * RO(Proc)->Uncore.MC[mc].SKL.MADD0.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		!RO(Proc)->Uncore.MC[mc].SKL.MADC0.Dimm_L_Map
	].Size = 1024 * RO(Proc)->Uncore.MC[mc].SKL.MADD0.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		RO(Proc)->Uncore.MC[mc].SKL.MADC1.Dimm_L_Map
	].Size = 1024 * RO(Proc)->Uncore.MC[mc].SKL.MADD1.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		!RO(Proc)->Uncore.MC[mc].SKL.MADC1.Dimm_L_Map
	].Size = 1024 * RO(Proc)->Uncore.MC[mc].SKL.MADD1.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		RO(Proc)->Uncore.MC[mc].SKL.MADC0.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].SKL.MADD0.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		!RO(Proc)->Uncore.MC[mc].SKL.MADC0.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].SKL.MADD0.DSNOR;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		RO(Proc)->Uncore.MC[mc].SKL.MADC1.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].SKL.MADD1.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		!RO(Proc)->Uncore.MC[mc].SKL.MADC1.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].SKL.MADD1.DSNOR;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		RO(Proc)->Uncore.MC[mc].SKL.MADC0.Dimm_L_Map
	].Rows = DimmWidthToRows(RO(Proc)->Uncore.MC[mc].SKL.MADD0.DLW);

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		!RO(Proc)->Uncore.MC[mc].SKL.MADC0.Dimm_L_Map
	].Rows = DimmWidthToRows(RO(Proc)->Uncore.MC[mc].SKL.MADD0.DSW);

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		RO(Proc)->Uncore.MC[mc].SKL.MADC1.Dimm_L_Map
	].Rows = DimmWidthToRows(RO(Proc)->Uncore.MC[mc].SKL.MADD1.DLW);

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		!RO(Proc)->Uncore.MC[mc].SKL.MADC1.Dimm_L_Map
	].Rows = DimmWidthToRows(RO(Proc)->Uncore.MC[mc].SKL.MADD1.DSW);

    switch (RO(Proc)->Uncore.MC[mc].SKL.MADCH.DDR_TYPE) {
    case 0b00:
	RO(Shm)->Uncore.Unit.DDR_Ver = 4;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;
	break;
    case 0b01:
	RO(Shm)->Uncore.Unit.DDR_Ver = 3;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;
	break;
    case 0b10:
	RO(Shm)->Uncore.Unit.DDR_Ver = 3;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;
	break;
    default:
	RO(Shm)->Uncore.Unit.DDR_Ver = 4;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_UNSPEC;
	break;
    }
  }
}

void SKL_CAP(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	unsigned int DMFC;

	switch (RO(Proc)->ArchID) {
	case Skylake_UY:
	case Kabylake_UY:
		DMFC = RO(Proc)->Uncore.Bus.SKL_Cap_B.DMFC_DDR3;
		RO(Shm)->Uncore.Bus.Rate = 4000;	/* 4 GT/s QPI */
		break;
	default:
		DMFC = RO(Proc)->Uncore.Bus.SKL_Cap_C.DMFC_DDR4;
		RO(Shm)->Uncore.Bus.Rate = 8000;	/* 8 GT/s DMI3 */
		break;
	}
    if (RO(Proc)->Uncore.Bus.SKL_SA_Pll.QCLK == 0)
    {
	switch (DMFC) {
	case 0b111:
		RO(Shm)->Uncore.CtrlSpeed = 1067;
		break;
	case 0b110:
		RO(Shm)->Uncore.CtrlSpeed = 1333;
		break;
	case 0b101:
		RO(Shm)->Uncore.CtrlSpeed = 1600;
		break;
	case 0b100:
		RO(Shm)->Uncore.CtrlSpeed = 1867;
		break;
	case 0b011:
		RO(Shm)->Uncore.CtrlSpeed = 2133;
		break;
	case 0b010:
		RO(Shm)->Uncore.CtrlSpeed = 2400;
		break;
	case 0b001:
	case 0b000:
		RO(Shm)->Uncore.CtrlSpeed = 2667;
		break;
	}
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
    }
    else
    {
	unsigned long long Freq_Hz;

	if (RO(Proc)->Uncore.Bus.SKL_SA_Pll.QCLK_REF == 0) {
		Freq_Hz = 133333333LLU * RO(Proc)->Uncore.Bus.SKL_SA_Pll.QCLK;
		Freq_Hz = Freq_Hz / 1000000LLU;
	} else {
		Freq_Hz = 100LLU * RO(Proc)->Uncore.Bus.SKL_SA_Pll.QCLK;
	}
	RO(Shm)->Uncore.CtrlSpeed = (unsigned short) Freq_Hz;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
    }
	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MTS;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MTS;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;

	RO(Shm)->Proc.Technology.IOMMU = !RO(Proc)->Uncore.Bus.SKL_Cap_A.VT_d;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Major = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Major;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Minor = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Minor;

	RO(Shm)->Proc.Technology.GNA = !RO(Proc)->Uncore.Bus.SKL_Cap_B.GMM_DIS;
	RO(Shm)->Proc.Technology.IPU = !RO(Proc)->Uncore.Bus.SKL_Cap_B.IMGU_DIS;
	RO(Shm)->Proc.Technology.OC = RO(Proc)->Uncore.Bus.SKL_Cap_B.OC_ENABLED;
}

void RKL_IMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
	unsigned int width = 15;

     RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
     RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	TIMING(mc, cha).tCL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.ODT.tCL;

	TIMING(mc, cha).tRCD_RD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Timing.tRP;

	TIMING(mc, cha).tRCD_WR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.ACT.tRCD_WR;

    if (TIMING(mc, cha).tRCD_WR == 0) {
	TIMING(mc, cha).tRCD_WR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Timing.tRP;
    }

	TIMING(mc, cha).tRP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Timing.tRP;

	TIMING(mc, cha).tRAS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Timing.tRAS;

	TIMING(mc, cha).tRRDS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.ACT.tRRD_DG;

	TIMING(mc, cha).tRRDL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.ACT.tRRD_SG;

	TIMING(mc, cha).tRFC = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Refresh.tRFC;

	TIMING(mc, cha).tREFI = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Refresh.tREFI;

      if (RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Timing.tWRPRE >=
		(RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.ODT.tCWL + 4U))
      {
	TIMING(mc, cha).tWR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Timing.tWRPRE
			- RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.ODT.tCWL -4U;
      }

	TIMING(mc, cha).tRTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Timing.tRDPRE;

	TIMING(mc, cha).tWTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Timing.tWRPRE;

	TIMING(mc, cha).tFAW = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.ACT.tFAW;

	TIMING(mc, cha).tCWL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.ODT.tCWL;

	TIMING(mc, cha).tRDRD_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.RDRD.tRDRD_SG;

	TIMING(mc, cha).tRDRD_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.RDRD.tRDRD_DG;

	TIMING(mc, cha).tRDRD_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.RDRD.tRDRD_DR;

	TIMING(mc, cha).tRDRD_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.RDRD.tRDRD_DD;

	TIMING(mc, cha).tRDWR_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.RDWR.tRDWR_SG;

	TIMING(mc, cha).tRDWR_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.RDWR.tRDWR_DG;

	TIMING(mc, cha).tRDWR_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.RDWR.tRDWR_DR;

	TIMING(mc, cha).tRDWR_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.RDWR.tRDWR_DD;

	TIMING(mc, cha).tWRRD_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.WRRD.tWRRD_SG;

	TIMING(mc, cha).tWRRD_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.WRRD.tWRRD_DG;

	TIMING(mc, cha).tWRRD_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.WRRD.tWRRD_DR;

	TIMING(mc, cha).tWRRD_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.WRRD.tWRRD_DD;

	TIMING(mc, cha).tWRWR_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.WRWR.tWRWR_SG;

	TIMING(mc, cha).tWRWR_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.WRWR.tWRWR_DG;

	TIMING(mc, cha).tWRWR_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.WRWR.tWRWR_DR;

	TIMING(mc, cha).tWRWR_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.WRWR.tWRWR_DD;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Sched.CMD_Stretch) {
	case 0b00:
	case 0b11:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b01:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	case 0b10:
		TIMING(mc, cha).CMD_Rate = 3;
		break;
	}

	TIMING(mc, cha).tXS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.SRExit.tXSR;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[0].Banks = \
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[1].Banks = \
	!RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Sched.ReservedBits1 ? 16 : 8;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[0].Cols = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Sched.x8_device_Dimm0 ?
			1024 : 512;
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[1].Cols = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Sched.x8_device_Dimm1 ?
			1024 : 512;

	TIMING(mc, cha).tCKE = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.PWDEN.tCKE;

	TIMING(mc, cha).tXP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.PWDEN.tXP;

	TIMING(mc, cha).tCPDED = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Sched.tCPDED;

	TIMING(mc, cha).GEAR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].RKL.Sched.GEAR2 ? 2 : 1;
    }
	RO(Shm)->Uncore.MC[mc].Channel[0].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].RKL.MADC0.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[1].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].RKL.MADC1.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		RO(Proc)->Uncore.MC[mc].RKL.MADC0.Dimm_L_Map
	].Size = 512 * RO(Proc)->Uncore.MC[mc].RKL.MADD0.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		!RO(Proc)->Uncore.MC[mc].RKL.MADC0.Dimm_L_Map
	].Size = 512 * RO(Proc)->Uncore.MC[mc].RKL.MADD0.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		RO(Proc)->Uncore.MC[mc].RKL.MADC1.Dimm_L_Map
	].Size = 512 * RO(Proc)->Uncore.MC[mc].RKL.MADD1.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		!RO(Proc)->Uncore.MC[mc].RKL.MADC1.Dimm_L_Map
	].Size = 512 * RO(Proc)->Uncore.MC[mc].RKL.MADD1.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		RO(Proc)->Uncore.MC[mc].RKL.MADC0.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].RKL.MADD0.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		!RO(Proc)->Uncore.MC[mc].RKL.MADC0.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].RKL.MADD0.DSNOR;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		RO(Proc)->Uncore.MC[mc].RKL.MADC1.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].RKL.MADD1.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		!RO(Proc)->Uncore.MC[mc].RKL.MADC1.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].RKL.MADD1.DSNOR;

	width += RO(Proc)->Uncore.MC[mc].RKL.MADCH.CH_WIDTH;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		RO(Proc)->Uncore.MC[mc].RKL.MADC0.Dimm_L_Map
	].Rows = \

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		!RO(Proc)->Uncore.MC[mc].RKL.MADC0.Dimm_L_Map
	].Rows = \

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		RO(Proc)->Uncore.MC[mc].RKL.MADC1.Dimm_L_Map
	].Rows = \

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		!RO(Proc)->Uncore.MC[mc].RKL.MADC1.Dimm_L_Map
	].Rows = 1 << width;
  }
}

void RKL_CAP(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	unsigned int units = 12;
	unsigned int Bus_Rate = RO(Proc)->Uncore.Bus.BIOS_DDR.MC_PLL_RATIO;
	unsigned short mc, clock_done;

  for (mc = 0, clock_done = 0;
	mc < RO(Shm)->Uncore.CtrlCount && !clock_done;
		mc++)
  {
    if (RO(Proc)->Uncore.MC[mc].RKL.MADCH.value) {
	switch (RO(Proc)->Uncore.MC[mc].RKL.MADCH.DDR_TYPE) {
	default:
	case 0b00:	/*	DDR4	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 4;
		RO(Shm)->Uncore.Unit.DDR_Std  = RAM_STD_SDRAM;

		if ((RO(Proc)->Uncore.Bus.RKL_Cap_C.DDR4_EN)
		 && (RO(Proc)->Uncore.Bus.RKL_Cap_A.DDR_OVERCLOCK == 0))
		{
			units = RO(Proc)->Uncore.Bus.RKL_Cap_C.DATA_RATE_DDR4;
			clock_done = 1;
		}
		break;
	case 0b11:	/*	LPDDR4	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 4;
		RO(Shm)->Uncore.Unit.DDR_Std  = RAM_STD_LPDDR;

		if ((RO(Proc)->Uncore.Bus.RKL_Cap_C.LPDDR4_EN)
		 && (RO(Proc)->Uncore.Bus.RKL_Cap_A.DDR_OVERCLOCK == 0))
		{
			units = RO(Proc)->Uncore.Bus.RKL_Cap_C.DATA_RATE_LPDDR4;
			clock_done = 1;
		}
		break;
	case 0b01:	/*	DDR5	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 5;
		RO(Shm)->Uncore.Unit.DDR_Std  = RAM_STD_SDRAM;

		if ((RO(Proc)->Uncore.Bus.TGL_Cap_E.DDR5_EN)
		 && (RO(Proc)->Uncore.Bus.TGL_Cap_A.DDR_OVERCLOCK == 0))
		{
			units = RO(Proc)->Uncore.Bus.TGL_Cap_E.DATA_RATE_DDR5;
			clock_done = 1;
		}
		break;
	case 0b10:	/*	LPDDR5	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 5;
		RO(Shm)->Uncore.Unit.DDR_Std  = RAM_STD_LPDDR;

		if ((RO(Proc)->Uncore.Bus.TGL_Cap_E.LPDDR5_EN)
		 && (RO(Proc)->Uncore.Bus.TGL_Cap_A.DDR_OVERCLOCK == 0))
		{
			units = RO(Proc)->Uncore.Bus.TGL_Cap_E.DATA_RATE_LPDDR5;
			clock_done = 1;
		}
		break;
	}
    }
  }
    if (RO(Proc)->Uncore.Bus.RKL_SA_Pll.QCLK_RATIO == 0)
    {
	RO(Shm)->Uncore.CtrlSpeed = (266 * units) + ((334 * units) / 501);

	Bus_Rate = Bus_Rate * 100U;
    }
    else	/*	Is Memory frequency overclocked ?		*/
    {
	unsigned long long Freq_Hz;

	if (RO(Proc)->Uncore.Bus.RKL_SA_Pll.QCLK_REF == 0) {
		Freq_Hz = RO(Proc)->Uncore.Bus.RKL_SA_Pll.QCLK_RATIO;
		Freq_Hz = Freq_Hz * RO(Core)->Clock.Hz * 800LLU;
		Freq_Hz = Freq_Hz / RO(Shm)->Proc.Features.Factory.Clock.Hz;
		Freq_Hz = Freq_Hz / 3LLU;

		Bus_Rate = Bus_Rate * 400U;
		Bus_Rate = Bus_Rate / 3U;
	} else {
		Freq_Hz = RO(Proc)->Uncore.Bus.RKL_SA_Pll.QCLK_RATIO;
		Freq_Hz = Freq_Hz * RO(Core)->Clock.Hz * 200LLU;
		Freq_Hz = Freq_Hz / RO(Shm)->Proc.Features.Factory.Clock.Hz;

		Bus_Rate = Bus_Rate * 100U;
	}
	RO(Shm)->Uncore.CtrlSpeed = (unsigned short) Freq_Hz;
    }
	RO(Shm)->Uncore.Bus.Rate = Bus_Rate;
	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MHZ;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MTS;

	RO(Shm)->Proc.Technology.IOMMU = !RO(Proc)->Uncore.Bus.RKL_Cap_A.VT_d;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Major = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Major;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Minor = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Minor;

	RO(Shm)->Proc.Technology.VMD = !RO(Proc)->Uncore.Bus.RKL_Cap_B.VMD_DIS;
	RO(Shm)->Proc.Technology.GNA = !RO(Proc)->Uncore.Bus.RKL_Cap_B.GNA_DIS;
	RO(Shm)->Proc.Technology.HDCP= !RO(Proc)->Uncore.Bus.RKL_Cap_B.HDCPD;
	RO(Shm)->Proc.Technology.IPU = !RO(Proc)->Uncore.Bus.RKL_Cap_B.IPU_DIS;
	RO(Shm)->Proc.Technology.OC = RO(Proc)->Uncore.Bus.RKL_Cap_B.OC_ENABLED;
}

void TGL_IMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
	unsigned int width = 15;

     RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
     RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
	TIMING(mc, cha).tCL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.ODT.tCL;

	/*	ACT to CAS (RD or WR) same bank minimum delay in tCK	*/
	TIMING(mc, cha).tRCD_RD = \
	TIMING(mc, cha).tRCD_WR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Timing.tRCD;

	TIMING(mc, cha).tRP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Timing.tRP;

	TIMING(mc, cha).tRAS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Timing.tRAS;

	TIMING(mc, cha).tRRDS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.ACT.tRRD_DG;

	TIMING(mc, cha).tRRDL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.ACT.tRRD_SG;

	TIMING(mc, cha).tRFC = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Refresh.tRFC;

	TIMING(mc, cha).tREFI = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Refresh.tREFI;

      if (RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Timing.tWRPRE >=
		(RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.ODT.tCWL + 4U))
      {
	TIMING(mc, cha).tWR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Timing.tWRPRE
			- RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.ODT.tCWL -4U;
      }

	TIMING(mc, cha).tRTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Timing.tRDPRE;

	TIMING(mc, cha).tWTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Timing.tWRPRE;

	TIMING(mc, cha).tFAW = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.ACT.tFAW;

	TIMING(mc, cha).tCWL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.ODT.tCWL;

	TIMING(mc, cha).tRDRD_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.RDRD.tRDRD_SG;

	TIMING(mc, cha).tRDRD_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.RDRD.tRDRD_DG;

	TIMING(mc, cha).tRDRD_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.RDRD.tRDRD_DR;

	TIMING(mc, cha).tRDRD_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.RDRD.tRDRD_DD;

	TIMING(mc, cha).tRDWR_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.RDWR.tRDWR_SG;

	TIMING(mc, cha).tRDWR_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.RDWR.tRDWR_DG;

	TIMING(mc, cha).tRDWR_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.RDWR.tRDWR_DR;

	TIMING(mc, cha).tRDWR_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.RDWR.tRDWR_DD;

	TIMING(mc, cha).tWRRD_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.WRRD.tWRRD_SG;

	TIMING(mc, cha).tWRRD_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.WRRD.tWRRD_DG;

	TIMING(mc, cha).tWRRD_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.WRRD.tWRRD_DR;

	TIMING(mc, cha).tWRRD_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.WRRD.tWRRD_DD;

	TIMING(mc, cha).tWRWR_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.WRWR.tWRWR_SG;

	TIMING(mc, cha).tWRWR_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.WRWR.tWRWR_DG;

	TIMING(mc, cha).tWRWR_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.WRWR.tWRWR_DR;

	TIMING(mc, cha).tWRWR_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.WRWR.tWRWR_DD;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Sched.CMD_Stretch) {
	case 0b00:
	case 0b11:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b01:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	case 0b10:
		TIMING(mc, cha).CMD_Rate = 3;
		break;
	}

	TIMING(mc, cha).tXS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.SRExit.tXSR;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[0].Banks = \
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[1].Banks = \
	!RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Sched.ReservedBits1 ? 16 : 8;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[0].Cols = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Sched.x8_device_Dimm0 ?
			1024 : 512;
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[1].Cols = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Sched.x8_device_Dimm1 ?
			1024 : 512;

	TIMING(mc, cha).tCKE = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.PWDEN.tCKE;

	TIMING(mc, cha).tXP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.PWDEN.tXP;

	TIMING(mc, cha).tCPDED = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Sched.tCPDED;

	TIMING(mc, cha).GEAR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].TGL.Sched.GEAR2 ? 2 : 1;
    }
	RO(Shm)->Uncore.MC[mc].Channel[0].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].TGL.MADC0.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[1].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].TGL.MADC1.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		RO(Proc)->Uncore.MC[mc].TGL.MADC0.Dimm_L_Map
	].Size = 512 * RO(Proc)->Uncore.MC[mc].TGL.MADD0.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		!RO(Proc)->Uncore.MC[mc].TGL.MADC0.Dimm_L_Map
	].Size = 512 * RO(Proc)->Uncore.MC[mc].TGL.MADD0.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		RO(Proc)->Uncore.MC[mc].TGL.MADC1.Dimm_L_Map
	].Size = 512 * RO(Proc)->Uncore.MC[mc].TGL.MADD1.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		!RO(Proc)->Uncore.MC[mc].TGL.MADC1.Dimm_L_Map
	].Size = 512 * RO(Proc)->Uncore.MC[mc].TGL.MADD1.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		RO(Proc)->Uncore.MC[mc].TGL.MADC0.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].TGL.MADD0.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		!RO(Proc)->Uncore.MC[mc].TGL.MADC0.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].TGL.MADD0.DSNOR;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		RO(Proc)->Uncore.MC[mc].TGL.MADC1.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].TGL.MADD1.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		!RO(Proc)->Uncore.MC[mc].TGL.MADC1.Dimm_L_Map
	].Ranks = 1 + RO(Proc)->Uncore.MC[mc].TGL.MADD1.DSNOR;

	width += RO(Proc)->Uncore.MC[mc].TGL.MADCH.CH_WIDTH;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		RO(Proc)->Uncore.MC[mc].TGL.MADC0.Dimm_L_Map
	].Rows = \

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[
		!RO(Proc)->Uncore.MC[mc].TGL.MADC0.Dimm_L_Map
	].Rows = \

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		RO(Proc)->Uncore.MC[mc].TGL.MADC1.Dimm_L_Map
	].Rows = \

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[
		!RO(Proc)->Uncore.MC[mc].TGL.MADC1.Dimm_L_Map
	].Rows = 1 << width;
  }
}

#define TGL_CAP RKL_CAP

void ADL_IMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, virtualCount;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
     RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
     RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    if (RO(Proc)->Uncore.Bus.ADL_Cap_A.DDPCD == 0) {
	switch (RO(Proc)->Uncore.MC[mc].ADL.MADCH.DDR_TYPE) {
		case 0b00:	/*	DDR4	*/
			virtualCount = 1;
			break;
		case 0b11:	/*	LPDDR4	*/
		case 0b01:	/*	DDR5	*/
		case 0b10:	/*	LPDDR5	*/
		default:
			virtualCount = RO(Shm)->Uncore.MC[mc].ChannelCount;
			break;
	}
    } else {
	virtualCount = RO(Shm)->Uncore.MC[mc].ChannelCount;
    }
    for (cha = 0; cha < virtualCount; cha++)
    {
	unsigned short tWR_quantity;

	TIMING(mc, cha).tCL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.ODT.tCL;

	TIMING(mc, cha).tRCD_RD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Timing.tRCD;

	TIMING(mc, cha).tRCD_WR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Timing.tRCDW;

      if (TIMING(mc, cha).tRCD_WR == 0) {
		TIMING(mc, cha).tRCD_WR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Timing.tRCD;
      }

	TIMING(mc, cha).tRP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Timing.tRP;

	TIMING(mc, cha).tRAS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Timing.tRAS;

	TIMING(mc, cha).tRRDS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.ACT.tRRD_DG;

	TIMING(mc, cha).tRRDL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.ACT.tRRD_SG;

	TIMING(mc, cha).tRFC = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Refresh.tRFC;

	TIMING(mc, cha).tREFI = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Refresh.tREFI;

	switch (RO(Shm)->Uncore.Unit.DDR_Ver) {
	default:
	case 4:
		tWR_quantity = 4U;
		break;
	case 5:
		tWR_quantity = 8U;
		break;
	}
      if (RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Timing.tWRPRE >=
	 (RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.ODT.tCWL + tWR_quantity))
      {
	TIMING(mc, cha).tWR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Timing.tWRPRE
			- RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.ODT.tCWL
			- tWR_quantity;
      }

	TIMING(mc, cha).tRTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Timing.tRDPRE;

	TIMING(mc, cha).tWTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Timing.tWRPRE;

	TIMING(mc, cha).tFAW = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.ACT.tFAW;

	TIMING(mc, cha).tCWL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.ODT.tCWL;

	TIMING(mc, cha).tRDRD_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.RDRD.tRDRD_SG;

	TIMING(mc, cha).tRDRD_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.RDRD.tRDRD_DG;

	TIMING(mc, cha).tRDRD_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.RDRD.tRDRD_DR;

	TIMING(mc, cha).tRDRD_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.RDRD.tRDRD_DD;

	TIMING(mc, cha).tRDWR_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.RDWR.tRDWR_SG;

	TIMING(mc, cha).tRDWR_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.RDWR.tRDWR_DG;

	TIMING(mc, cha).tRDWR_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.RDWR.tRDWR_DR;

	TIMING(mc, cha).tRDWR_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.RDWR.tRDWR_DD;

	TIMING(mc, cha).tWRRD_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.WRRD.tWRRD_SG;

	TIMING(mc, cha).tWRRD_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.WRRD.tWRRD_DG;

	TIMING(mc, cha).tWRRD_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.WRRD.tWRRD_DR;

	TIMING(mc, cha).tWRRD_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.WRRD.tWRRD_DD;

	TIMING(mc, cha).tWRWR_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.WRWR.tWRWR_SG;

	TIMING(mc, cha).tWRWR_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.WRWR.tWRWR_DG;

	TIMING(mc, cha).tWRWR_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.WRWR.tWRWR_DR;

	TIMING(mc, cha).tWRWR_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.WRWR.tWRWR_DD;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Sched.CMD_Stretch) {
	case 0b00:
	case 0b11:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b01:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	case 0b10:
		TIMING(mc, cha).CMD_Rate = 3;
		break;
	}

	TIMING(mc, cha).tXS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.SRExit.tXSR;

	TIMING(mc, cha).tCKE = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.PWDEN.tCKE;

	TIMING(mc, cha).tXP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.PWDEN.tXP;

	TIMING(mc, cha).tCPDED = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Sched.tCPDED;

	TIMING(mc, cha).GEAR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Sched.GEAR4 ? 4 : \
		RO(Proc)->Uncore.MC[mc].Channel[cha].ADL.Sched.GEAR2 ? 2 : 1;
    }
    switch (RO(Shm)->Uncore.Unit.DDR_Ver) {
    case 1 ... 4:
	RO(Shm)->Uncore.MC[mc].Channel[0].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].ADL.MADC0.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Rows = DimmWidthToRows(RO(Proc)->Uncore.MC[mc].ADL.MADD0.DLW);

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Rows = DimmWidthToRows(RO(Proc)->Uncore.MC[mc].ADL.MADD0.DSW);

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Size = 512 * RO(Proc)->Uncore.MC[mc].ADL.MADD0.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Size = 512 * RO(Proc)->Uncore.MC[mc].ADL.MADD0.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].ADL.MADD0.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].ADL.MADD0.DSNOR;
	break;
    case 5:
    default:
	RO(Shm)->Uncore.MC[mc].Channel[0].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].ADL.MADC0.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[1].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].ADL.MADC1.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Rows = 1 << 17;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Rows = 1 << 17;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].ADL.MADC1.Dimm_L_Map
	].DIMM[0].Rows = 1 << 17;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].ADL.MADC1.Dimm_L_Map
	].DIMM[0].Rows = 1 << 17;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Size = 1024 * RO(Proc)->Uncore.MC[mc].ADL.MADD0.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Size = 1024 * RO(Proc)->Uncore.MC[mc].ADL.MADD0.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].ADL.MADC1.Dimm_L_Map
	].DIMM[0].Size = 1024 * RO(Proc)->Uncore.MC[mc].ADL.MADD1.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].ADL.MADC1.Dimm_L_Map
	].DIMM[0].Size = 1024 * RO(Proc)->Uncore.MC[mc].ADL.MADD1.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].ADL.MADD0.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].ADL.MADC0.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].ADL.MADD0.DSNOR;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].ADL.MADC1.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].ADL.MADD1.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].ADL.MADC1.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].ADL.MADD1.DSNOR;
	break;
    }
	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[0].Banks = \
	!RO(Proc)->Uncore.MC[mc].Channel[0].ADL.Sched.ReservedBits1 ? 16 : 8;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[0].Banks = \
	!RO(Proc)->Uncore.MC[mc].Channel[1].ADL.Sched.ReservedBits1 ? 16 : 8;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[0].Cols = \
	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[0].Cols = 1 << 10;
  }
}

void ADL_CAP(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	unsigned int units = 12;
	unsigned int Bus_Rate = RO(Proc)->Uncore.Bus.BIOS_DDR.MC_PLL_RATIO;
	unsigned short mc, clock_done;

  for (mc = 0, clock_done = 0;
	mc < RO(Shm)->Uncore.CtrlCount && !clock_done;
		mc++)
  {
    if (RO(Proc)->Uncore.MC[mc].ADL.MADCH.value) {
	switch (RO(Proc)->Uncore.MC[mc].ADL.MADCH.DDR_TYPE) {
	default:
	case 0b00:	/*	DDR4	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 4;
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;

		if ((RO(Proc)->Uncore.Bus.ADL_Cap_C.DDR4_EN)
		 && (RO(Proc)->Uncore.Bus.ADL_Cap_A.DDR_OVERCLOCK == 0))
		{
			units = RO(Proc)->Uncore.Bus.ADL_Cap_C.DATA_RATE_DDR4;
			clock_done = 1;
		}
		break;
	case 0b11:	/*	LPDDR4	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 4;
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;

		if ((RO(Proc)->Uncore.Bus.ADL_Cap_C.LPDDR4_EN)
		 && (RO(Proc)->Uncore.Bus.ADL_Cap_A.DDR_OVERCLOCK == 0))
		{
			units = RO(Proc)->Uncore.Bus.ADL_Cap_C.DATA_RATE_LPDDR4;
			clock_done = 1;
		}
		break;
	case 0b01:	/*	DDR5	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 5;
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;

		if ((RO(Proc)->Uncore.Bus.ADL_Cap_E.DDR5_EN)
		 && (RO(Proc)->Uncore.Bus.ADL_Cap_A.DDR_OVERCLOCK == 0))
		{
			units = RO(Proc)->Uncore.Bus.ADL_Cap_E.DATA_RATE_DDR5;
			clock_done = 1;
		}
		break;
	case 0b10:	/*	LPDDR5	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 5;
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;

		if ((RO(Proc)->Uncore.Bus.ADL_Cap_E.LPDDR5_EN)
		 && (RO(Proc)->Uncore.Bus.ADL_Cap_A.DDR_OVERCLOCK == 0))
		{
			units = RO(Proc)->Uncore.Bus.ADL_Cap_E.DATA_RATE_LPDDR5;
			clock_done = 1;
		}
		break;
	}
    }
  }
    if (RO(Proc)->Uncore.Bus.ADL_SA_Pll.QCLK_RATIO == 0)
    {
	RO(Shm)->Uncore.CtrlSpeed = (266 * units) + ((334 * units) / 501);

	Bus_Rate = Bus_Rate * 100U;
    }
    else	/*	Is Memory frequency overclocked ?		*/
    {
	unsigned long long Freq_Hz;

	if (RO(Proc)->Uncore.Bus.ADL_SA_Pll.QCLK_REF == 0) {
		Freq_Hz = RO(Proc)->Uncore.Bus.ADL_SA_Pll.QCLK_RATIO;
		Freq_Hz = Freq_Hz * RO(Core)->Clock.Hz * 800LLU;
		Freq_Hz = Freq_Hz / RO(Shm)->Proc.Features.Factory.Clock.Hz;
		Freq_Hz = Freq_Hz / 3LLU;

		Bus_Rate = Bus_Rate * 400U;
		Bus_Rate = Bus_Rate / 3U;
	} else {
		Freq_Hz = RO(Proc)->Uncore.Bus.ADL_SA_Pll.QCLK_RATIO;
		Freq_Hz = Freq_Hz * RO(Core)->Clock.Hz * 200LLU;
		Freq_Hz = Freq_Hz / RO(Shm)->Proc.Features.Factory.Clock.Hz;

		Bus_Rate = Bus_Rate * 100U;
	}
	RO(Shm)->Uncore.CtrlSpeed = (unsigned short) Freq_Hz;
    }
	RO(Shm)->Uncore.Bus.Rate = Bus_Rate;
	RO(Shm)->Uncore.Bus.Speed = (RO(Core)->Clock.Hz
				* RO(Shm)->Uncore.Bus.Rate)
				/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MHZ;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MTS;

	RO(Shm)->Proc.Technology.IOMMU = !RO(Proc)->Uncore.Bus.ADL_Cap_A.VT_d;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Major = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Major;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Minor = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Minor;

	RO(Shm)->Proc.Technology.VMD = !RO(Proc)->Uncore.Bus.ADL_Cap_B.VMD_DIS;
	RO(Shm)->Proc.Technology.GNA = !RO(Proc)->Uncore.Bus.ADL_Cap_B.GNA_DIS;
	RO(Shm)->Proc.Technology.HDCP= !RO(Proc)->Uncore.Bus.ADL_Cap_B.HDCPD;
	RO(Shm)->Proc.Technology.IPU = !RO(Proc)->Uncore.Bus.ADL_Cap_B.IPU_DIS;
	RO(Shm)->Proc.Technology.OC = RO(Proc)->Uncore.Bus.ADL_Cap_B.OC_ENABLED;
}

void GLK_CAP(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	RO(Shm)->Uncore.Bus.Rate = 0;
	RO(Shm)->Uncore.Bus.Speed = 0;
	RO(Shm)->Uncore.CtrlSpeed = 0;
	RO(Shm)->Uncore.Unit.DDR_Ver = 4;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;
	RO(Shm)->Uncore.Unit.Bus_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_NIL;

	RO(Shm)->Proc.Technology.IOMMU = !RO(Proc)->Uncore.Bus.GLK_Cap_A.VT_d;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Major = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Major;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Minor = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Minor;

	RO(Shm)->Proc.Technology.GNA = !RO(Proc)->Uncore.Bus.GLK_Cap_B.GMM_DIS;
	RO(Shm)->Proc.Technology.IPU = !RO(Proc)->Uncore.Bus.GLK_Cap_B.IMGU_DIS;
	RO(Shm)->Proc.Technology.OC = RO(Proc)->Uncore.Bus.GLK_Cap_B.OC_ENABLED;
}

void GLK_IMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
     RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
     RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
    {
    }
  }
}

#define RPL_CAP ADL_CAP
#define RPL_IMC ADL_IMC

void MTL_CAP(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	unsigned short mc, clock_done;

  for (mc = 0, clock_done = 0;
	mc < RO(Shm)->Uncore.CtrlCount && !clock_done;
		mc++)
  {
    if (RO(Proc)->Uncore.MC[mc].MTL.MADCH.value) {
	switch (RO(Proc)->Uncore.MC[mc].MTL.MADCH.DDR_TYPE) {
	default:
	case 0b00:	/*	DDR4	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 4;
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;

		if ((RO(Proc)->Uncore.Bus.MTL_Cap_C.DDR4_EN)
		 && (RO(Proc)->Uncore.Bus.MTL_Cap_A.DDR_OVERCLOCK == 0))
		{
			clock_done = 1;
		}
		break;
	case 0b11:	/*	LPDDR4	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 4;
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;

		if ((RO(Proc)->Uncore.Bus.MTL_Cap_C.LPDDR4_EN)
		 && (RO(Proc)->Uncore.Bus.MTL_Cap_A.DDR_OVERCLOCK == 0))
		{
			clock_done = 1;
		}
		break;
	case 0b01:	/*	DDR5	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 5;
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;

		if ((RO(Proc)->Uncore.Bus.MTL_Cap_E.DDR5_EN)
		 && (RO(Proc)->Uncore.Bus.MTL_Cap_A.DDR_OVERCLOCK == 0))
		{
			clock_done = 1;
		}
		break;
	case 0b10:	/*	LPDDR5	*/
		RO(Shm)->Uncore.Unit.DDR_Ver = 5;
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;

		if ((RO(Proc)->Uncore.Bus.MTL_Cap_E.LPDDR5_EN)
		 && (RO(Proc)->Uncore.Bus.MTL_Cap_A.DDR_OVERCLOCK == 0))
		{
			clock_done = 1;
		}
		break;
	}
    }
  }
	/* Clock Topology: BCLK drives the Memory Controller clock domain.
	 * Qclk ratio with reference of 33.33MHz.			*/
	RO(Shm)->Uncore.Bus.Rate = \
		( RO(Proc)->Uncore.Bus.MTL_CR_BIOS.REQ.QCLK_RATIO
		* RO(Proc)->Uncore.Bus.MTL_BCLK.PCIE_FREQ_KHZ ) / 3000U;

	/* BCLK_FREQ_0_0_0_MCHBAR is used by software to calculate
	 * various clock frequencies that are derived from BCLK
	 * such as Core, Ring, Memory Controller and GT.		*/
	RO(Shm)->Uncore.Bus.Speed = \
		( RO(Proc)->Uncore.Bus.MTL_CR_BIOS.REQ.QCLK_RATIO
		* RO(Proc)->Uncore.Bus.MTL_BCLK.SOC_FREQ_KHZ ) / 3000LLU;

	/* DDR Transfer Rate (MT/s)					*/
	RO(Shm)->Uncore.CtrlSpeed = 2LLU * RO(Shm)->Uncore.Bus.Speed;

	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MHZ;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MTS;

	RO(Shm)->Proc.Technology.IOMMU = !RO(Proc)->Uncore.Bus.MTL_Cap_A.VT_d;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Major = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Major;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Minor = \
					RO(Proc)->Uncore.Bus.IOMMU_Ver.Minor;

	RO(Shm)->Proc.Technology.VMD = !RO(Proc)->Uncore.Bus.MTL_Cap_B.VMD_DIS;
	RO(Shm)->Proc.Technology.GNA = !RO(Proc)->Uncore.Bus.MTL_Cap_B.GNA_DIS;
	RO(Shm)->Proc.Technology.HDCP= !RO(Proc)->Uncore.Bus.MTL_Cap_B.HDCPD;
	RO(Shm)->Proc.Technology.IPU = !RO(Proc)->Uncore.Bus.MTL_Cap_B.IPU_DIS;
	RO(Shm)->Proc.Technology.VPU = !RO(Proc)->Uncore.Bus.MTL_Cap_C.VPU_DIS;
	RO(Shm)->Proc.Technology.OC = RO(Proc)->Uncore.Bus.MTL_Cap_B.OC_ENABLED;
}

void MTL_IMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc, cha, virtualCount;

  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
  {
     RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
     RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

    if (RO(Proc)->Uncore.Bus.MTL_Cap_A.DDPCD == 0) {
	switch (RO(Proc)->Uncore.MC[mc].MTL.MADCH.DDR_TYPE) {
		case 0b00:	/*	DDR4	*/
			virtualCount = 1;
			break;
		case 0b11:	/*	LPDDR4	*/
		case 0b01:	/*	DDR5	*/
		case 0b10:	/*	LPDDR5	*/
		default:
			virtualCount = RO(Shm)->Uncore.MC[mc].ChannelCount;
			break;
	}
    } else {
	virtualCount = RO(Shm)->Uncore.MC[mc].ChannelCount;
    }
    for (cha = 0; cha < virtualCount; cha++)
    {
	unsigned short tWR_quantity;

	TIMING(mc, cha).tCCD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.CAS.tCCD;

	TIMING(mc, cha).tCL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.CAS.tCL;

	TIMING(mc, cha).tRCD_RD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.ACT.tRCD;

	TIMING(mc, cha).tRCD_WR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.ACT.tRCDW;

      if (TIMING(mc, cha).tRCD_WR == 0) {
		TIMING(mc, cha).tRCD_WR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.ACT.tRCD;
      }

	TIMING(mc, cha).tRP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.Timing.tRPpb;

	TIMING(mc, cha).tRAS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.Timing.tRAS;

	TIMING(mc, cha).tRRDS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.ACT.tRRD_DG;

	TIMING(mc, cha).tRRDL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.ACT.tRRD_SG;

	TIMING(mc, cha).tRFC = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.Refresh.tRFC;

	TIMING(mc, cha).tREFI = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.Refresh.tREFI;

	switch (RO(Shm)->Uncore.Unit.DDR_Ver) {
	default:
	case 4:
		tWR_quantity = 4U;
		break;
	case 5:
		tWR_quantity = 10U;
		break;
	}
      if (RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.Timing.tWRPRE >=
	 (RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.CAS.tCWL + tWR_quantity))
      {
	TIMING(mc, cha).tWR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.Timing.tWRPRE
			- RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.CAS.tCWL
			- tWR_quantity;
      }

	TIMING(mc, cha).tRTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.Timing.tRDPRE;

	TIMING(mc, cha).tWTPr = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.Timing.tWRPRE;

	TIMING(mc, cha).tFAW = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.ACT.tFAW;

	TIMING(mc, cha).tCWL = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.CAS.tCWL;

	TIMING(mc, cha).tRDRD_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.RDRD.tRDRD_SG;

	TIMING(mc, cha).tRDRD_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.RDRD.tRDRD_DG;

	TIMING(mc, cha).tRDRD_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.RDRD.tRDRD_DR;

	TIMING(mc, cha).tRDRD_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.RDRD.tRDRD_DD;

	TIMING(mc, cha).tRDWR_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.RDWR.tRDWR_SG;

	TIMING(mc, cha).tRDWR_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.RDWR.tRDWR_DG;

	TIMING(mc, cha).tRDWR_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.RDWR.tRDWR_DR;

	TIMING(mc, cha).tRDWR_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.RDWR.tRDWR_DD;

	TIMING(mc, cha).tWRRD_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.WRRD.tWRRD_SG;

	TIMING(mc, cha).tWRRD_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.WRRD.tWRRD_DG;

	TIMING(mc, cha).tWRRD_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.WRRD.tWRRD_DR;

	TIMING(mc, cha).tWRRD_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.WRRD.tWRRD_DD;

	TIMING(mc, cha).tWRWR_SG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.WRWR.tWRWR_SG;

	TIMING(mc, cha).tWRWR_DG = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.WRWR.tWRWR_DG;

	TIMING(mc, cha).tWRWR_DR = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.WRWR.tWRWR_DR;

	TIMING(mc, cha).tWRWR_DD = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.WRWR.tWRWR_DD;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.Sched.CMD_Stretch) {
	case 0b00:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b01:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	}

	TIMING(mc, cha).tXS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.SRExit.tXSR;

	TIMING(mc, cha).tCKE = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.PWDEN.tCKE;

	TIMING(mc, cha).tXP = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.PWDEN.tXP;

	TIMING(mc, cha).tCPDED = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.PWDEN.tCPDED;

	TIMING(mc, cha).GEAR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].MTL.Sched.GEAR ? 4 : 2;
    }
    switch (RO(Shm)->Uncore.Unit.DDR_Ver) {
    case 1 ... 4:
	RO(Shm)->Uncore.MC[mc].Channel[0].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].MTL.MADC0.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Rows = DimmWidthToRows(RO(Proc)->Uncore.MC[mc].MTL.MADD0.DLW);

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Rows = DimmWidthToRows(RO(Proc)->Uncore.MC[mc].MTL.MADD0.DSW);

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Size = 512 * RO(Proc)->Uncore.MC[mc].MTL.MADD0.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Size = 512 * RO(Proc)->Uncore.MC[mc].MTL.MADD0.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].MTL.MADD0.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].MTL.MADD0.DSNOR;
	break;
    case 5:
    default:
	RO(Shm)->Uncore.MC[mc].Channel[0].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].MTL.MADC0.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[1].Timing.ECC = \
				RO(Proc)->Uncore.MC[mc].MTL.MADC1.ECC;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Rows = 1 << 17;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Rows = 1 << 17;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].MTL.MADC1.Dimm_L_Map
	].DIMM[0].Rows = 1 << 17;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].MTL.MADC1.Dimm_L_Map
	].DIMM[0].Rows = 1 << 17;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Size = 1024 * RO(Proc)->Uncore.MC[mc].MTL.MADD0.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Size = 1024 * RO(Proc)->Uncore.MC[mc].MTL.MADD0.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].MTL.MADC1.Dimm_L_Map
	].DIMM[0].Size = 1024 * RO(Proc)->Uncore.MC[mc].MTL.MADD1.Dimm_L_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].MTL.MADC1.Dimm_L_Map
	].DIMM[0].Size = 1024 * RO(Proc)->Uncore.MC[mc].MTL.MADD1.Dimm_S_Size;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].MTL.MADD0.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].MTL.MADC0.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].MTL.MADD0.DSNOR;

	RO(Shm)->Uncore.MC[mc].Channel[
		RO(Proc)->Uncore.MC[mc].MTL.MADC1.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].MTL.MADD1.DLNOR;

	RO(Shm)->Uncore.MC[mc].Channel[
		!RO(Proc)->Uncore.MC[mc].MTL.MADC1.Dimm_L_Map
	].DIMM[0].Ranks = 1 + RO(Proc)->Uncore.MC[mc].MTL.MADD1.DSNOR;
	break;
    }
	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[0].Banks = \
	!RO(Proc)->Uncore.MC[mc].Channel[0].MTL.Sched.ReservedBits1 ? 16 : 8;

	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[0].Banks = \
	!RO(Proc)->Uncore.MC[mc].Channel[1].MTL.Sched.ReservedBits1 ? 16 : 8;

	RO(Shm)->Uncore.MC[mc].Channel[0].DIMM[0].Cols = \
	RO(Shm)->Uncore.MC[mc].Channel[1].DIMM[0].Cols = 1 << 10;
  }
}

#define ARL_CAP MTL_CAP
#define ARL_IMC MTL_IMC

#define LNL_CAP MTL_CAP
#define LNL_IMC MTL_IMC

void AMD_0Fh_MCH(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
    struct {
	unsigned int size;
    } module[] = {
	{256}, {512}, {1024}, {1024},
	{1024}, {2048}, {2048}, {4096},
	{4096}, {8192}, {8192}, {16384},
	{0}, {0}, {0}, {0}
    };
    unsigned int mask;
    unsigned short mc, cha, slot, shift, index;

    for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
    {
     RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;
     RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;

      for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++) {
	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD0Fh.DTRL.tCL) {
	case 0b010:
		TIMING(mc, cha).tCL = 3;
		break;
	case 0b011:
		TIMING(mc, cha).tCL = 4;
		break;
	case 0b100:
		TIMING(mc, cha).tCL = 5;
		break;
	case 0b101:
		TIMING(mc, cha).tCL = 6;
		break;
	}

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD0Fh.DTRL.tRCD) {
	case 0b00:
		TIMING(mc, cha).tRCD = 3;
		break;
	case 0b01:
		TIMING(mc, cha).tRCD = 4;
		break;
	case 0b10:
		TIMING(mc, cha).tRCD = 5;
		break;
	case 0b11:
		TIMING(mc, cha).tRCD = 6;
		break;
	}

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD0Fh.DTRL.tRP) {
	case 0b00:
		TIMING(mc, cha).tRP = 3;
		break;
	case 0b01:
		TIMING(mc, cha).tRP = 4;
		break;
	case 0b10:
		TIMING(mc, cha).tRP = 5;
		break;
	case 0b11:
		TIMING(mc, cha).tRP = 6;
		break;
	}

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD0Fh.DTRL.tRTPr) {
	case 0b0:
		if (RO(Proc)->Uncore.MC[mc].AMD0Fh.DCRL.BurstLength32 == 0b1) {
			TIMING(mc, cha).tRTPr = 2;
		} else {
			TIMING(mc, cha).tRTPr = 4;
		}
		break;
	case 0b1:
		if (RO(Proc)->Uncore.MC[mc].AMD0Fh.DCRL.BurstLength32 == 0b1) {
			TIMING(mc, cha).tRTPr = 3;
		} else {
			TIMING(mc, cha).tRTPr = 5;
		}
		break;
	}

	if (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD0Fh.DTRL.tRAS >= 0b0010) {
		TIMING(mc, cha).tRAS = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].AMD0Fh.DTRL.tRAS+3;
	}
	TIMING(mc, cha).tRFC = \
			RO(Proc)->Uncore.MC[mc].Channel[cha].AMD0Fh.DTRL.tRC+11;

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD0Fh.DTRL.tWR) {
	case 0b00:
		TIMING(mc, cha).tWR = 3;
		break;
	case 0b01:
		TIMING(mc, cha).tWR = 4;
		break;
	case 0b10:
		TIMING(mc, cha).tWR = 5;
		break;
	case 0b11:
		TIMING(mc, cha).tWR = 6;
		break;
	}

	switch (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD0Fh.DTRL.tRRD) {
	case 0b00:
		TIMING(mc, cha).tRRD = 2;
		break;
	case 0b01:
		TIMING(mc, cha).tRRD = 3;
		break;
	case 0b10:
		TIMING(mc, cha).tRRD = 4;
		break;
	case 0b11:
		TIMING(mc, cha).tRRD = 5;
		break;
	}

	if ((RO(Proc)->Uncore.MC[mc].AMD0Fh.DCRH.tFAW > 0b0000)
	 && (RO(Proc)->Uncore.MC[mc].AMD0Fh.DCRH.tFAW <= 0b1101)) {
		TIMING(mc, cha).tFAW = \
				RO(Proc)->Uncore.MC[mc].AMD0Fh.DCRH.tFAW + 7;
	}

	if (RO(Proc)->Uncore.MC[mc].AMD0Fh.DCRH.SlowAccessMode == 0b1)
		TIMING(mc, cha).CMD_Rate = 2;
	else
		TIMING(mc, cha).CMD_Rate = 1;

	shift = 4 * cha;
	mask  = 0b1111U << shift;

	for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++) {
	  if (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].MBA.CSEnable)
	  {
		index =(RO(Proc)->Uncore.MC[mc].MaxDIMMs.AMD0Fh.CS.value & mask)
			>> shift;

		RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = \
			module[index].size;
	  }
	}
	TIMING(mc, cha).ECC = \
			RO(Proc)->Uncore.MC[mc].AMD0Fh.DCRL.ECC_DIMM_Enable;
      }
    }
}

void AMD_0Fh_HTT(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned int link = 0;
	RAM_Ratio Ratio = {.Q = 0, .R = 0};
	unsigned long long HTT_Clock = 0;

	switch (RO(Proc)->Uncore.MC[0].AMD0Fh.DCRH.MemClkFreq) {
		case 0b000:
			Ratio.Q = 200;
			Ratio.R = 0;
			break;
		case 0b001:
			Ratio.Q = 266;
			Ratio.R = 1;
			break;
		case 0b010:
			Ratio.Q = 333;
			Ratio.R = 1;
			break;
		case 0b011:
			Ratio.Q = 400;
			Ratio.R = 0;
			break;
	}
	RO(Shm)->Uncore.CtrlSpeed = (Ratio.Q * 2) + Ratio.R;	/* DDR2 */

	if ((link = RO(Proc)->Uncore.Bus.UnitID.McUnit) < 0b11) {
		switch (RO(Proc)->Uncore.Bus.LDTi_Freq[link].LinkFreqMax)
		{						/* "MHz" */
		case 0b0000:
			HTT_Clock = 200;
			break;
		case 0b0010:
			HTT_Clock = 400;
			break;
		case 0b0100:
			HTT_Clock = 600;
			break;
		case 0b0101:
			HTT_Clock = 800;
			break;
		case 0b0110:
			HTT_Clock = 1000;
			break;
		case 0b1111:
			HTT_Clock = 100;
			break;
		}
		RO(Shm)->Uncore.Bus.Rate = HTT_Clock * 2;	/* "MT/s" */
		RO(Shm)->Uncore.Bus.Speed = HTT_Clock * 4;	/* "MB/s" */
	}
	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MTS;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MBS;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Ver  = 2;
	RO(Shm)->Uncore.Unit.DDR_Std  = RAM_STD_UNSPEC;
}

void AMD_17h_UMC(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	unsigned short mc;

	RO(Shm)->Proc.Mechanisms.DRAM_Scrambler = 0b11;
	RO(Shm)->Proc.Mechanisms.TSME = 0b11;

 for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount; mc++)
 {
    RO(Shm)->Uncore.MC[mc].ChannelCount = RO(Proc)->Uncore.MC[mc].ChannelCount;
    RO(Shm)->Uncore.MC[mc].SlotCount = RO(Proc)->Uncore.MC[mc].SlotCount;

	unsigned short cha;
  for (cha = 0; cha < RO(Shm)->Uncore.MC[mc].ChannelCount; cha++)
  {
	unsigned long long DIMM_Size;
	unsigned short slot;
    for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
    {
	const unsigned short chipselect_pair = slot << 1;
      if (BITVAL(RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.CHIP[
			chipselect_pair
		][0].Chip.value, 0)
      )
      { /*			CSEnable				*/
	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks = 8 << \
	RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].AMD17h.DAC.NumBanks;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows = 1 << (10
	+ RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].AMD17h.DAC.NumRowLo);

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols = 1 << (5
	+ RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].AMD17h.DAC.NumCol);

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks = \
	RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].AMD17h.Ranks;

	DIMM_Size = 8LLU;
	DIMM_Size *= RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Banks;
	DIMM_Size *= RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Ranks;
	DIMM_Size *= RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Rows;
	DIMM_Size *= RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Cols;

	RO(Shm)->Uncore.MC[mc].Channel[cha].DIMM[slot].Size = DIMM_Size >> 20;
      }
    }

	TIMING(mc, cha).tCL = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR1.tCL;

	TIMING(mc, cha).tRCD_RD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR1.tRCD_RD;

	TIMING(mc, cha).tRCD_WR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR1.tRCD_WR;

	TIMING(mc, cha).tRP = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR2.tRP;

	TIMING(mc, cha).tRAS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR1.tRAS;

	TIMING(mc, cha).tRRDS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR3.tRRDS;

	TIMING(mc, cha).tRRDL = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR3.tRRDL;

	TIMING(mc, cha).Zen.tRRDDLR =
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR3.tRRDDLR;

	TIMING(mc, cha).tRC = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR2.tRC;

	TIMING(mc, cha).tRCPB = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR2.tRCPB;

	TIMING(mc, cha).tRPPB = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR2.tRPPB;

	TIMING(mc, cha).tFAW = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR4.tFAW;

	TIMING(mc, cha).tFAWSLR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR4.tFAWSLR;

	TIMING(mc, cha).tFAWDLR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR4.tFAWDLR;

	TIMING(mc, cha).tWTRS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR5.tWTRS;

	TIMING(mc, cha).tWTRL = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR5.tWTRL;

	TIMING(mc, cha).tWR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR6.tWR;

	TIMING(mc, cha).tRCPage = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR7.tRCPage;

	TIMING(mc, cha).Zen.tRdRdScl = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR8.tRdRdScl;

	TIMING(mc, cha).Zen.tWrWrScl = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR9.tWrWrScl;

	TIMING(mc, cha).Zen.tRdRdBan = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR8.tRdRdBan;

	TIMING(mc, cha).Zen.tWrWrBan = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR9.tWrWrBan;

	TIMING(mc, cha).tCWL = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR5.tCWL;

	TIMING(mc, cha).tRTP = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR3.tRTP;

	TIMING(mc, cha).Zen.tddRdTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR10.tddRdTWr;

	TIMING(mc, cha).Zen.tddWrTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR10.tddWrTRd;

	TIMING(mc, cha).Zen.tscWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR9.tscWrTWr;

	TIMING(mc, cha).Zen.tsdWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR9.tsdWrTWr;

	TIMING(mc, cha).Zen.tddWrTWr = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR9.tddWrTWr;

	TIMING(mc, cha).Zen.tscRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR8.tscRdTRd;

	TIMING(mc, cha).Zen.tsdRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR8.tsdRdTRd;

	TIMING(mc, cha).Zen.tddRdTRd = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR8.tddRdTRd;

	TIMING(mc, cha).Zen.tRdRdScDLR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR8.tRdRdScDLR;

	TIMING(mc, cha).Zen.tWrWrScDLR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR9.tWrWrScDLR;

	TIMING(mc, cha).Zen.tWrRdScDLR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR10.tWrRdScDLR;

	TIMING(mc, cha).tXP = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR21.tXP;

	TIMING(mc, cha).tCKE = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR21.tCKE;

	TIMING(mc, cha).tCPDED = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR21.tCPDED;

	TIMING(mc, cha).tREFI = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR12.tREFI;

    switch(RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.CONFIG.BurstLength) {
    case 0x0:	/* BL2 */
    case 0x1:	/* BL4 */
    case 0x2:	/* BL8 */
	TIMING(mc, cha).tRFC1 = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTRFC.DDR4.tRFC1;

	TIMING(mc, cha).tRFC2 = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTRFC.DDR4.tRFC2;

	TIMING(mc, cha).tRFC4 = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTRFC.DDR4.tRFC4;

	switch(RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.MISC.DDR4.CMD_Rate) {
	case 0b00:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b10:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	default:
		TIMING(mc, cha).CMD_Rate = 0;
		break;
	}

	TIMING(mc, cha).GDM = \
	    RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.MISC.DDR4.GearDownMode;

	break;
    case 0x3:	/* BL16 */
	TIMING(mc, cha).tRFC1 = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTRFC.DDR5.tRFC1;

	TIMING(mc, cha).tRFC2 = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTRFC.DDR5.tRFC2;

	TIMING(mc, cha).tRFCsb = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.RFCSB.DDR5.tRFCsb;

	switch(RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.MISC.DDR5.CMD_Rate) {
	case 0b01:
		TIMING(mc, cha).CMD_Rate = 1;
		break;
	case 0b10:
		TIMING(mc, cha).CMD_Rate = 2;
		break;
	case 0b00:
	default:
		TIMING(mc, cha).CMD_Rate = 0;
		break;
	}

	TIMING(mc, cha).GDM = \
	    RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.MISC.DDR5.GearDownMode;

	break;
    }

	TIMING(mc, cha).ECC = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.ECC.Hi.Enable;

	TIMING(mc, cha).BGS = \
		!((RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.BGS.value
		& AMD_17_UMC_BGS_MASK_OFF) == AMD_17_UMC_BGS_MASK_OFF);

	TIMING(mc, cha).BGS_ALT = \
		(RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.BGS_ALT.value
		& AMD_17_UMC_BGS_ALT_MASK_ON) == AMD_17_UMC_BGS_ALT_MASK_ON;

	TIMING(mc, cha).PDM_EN = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.SPAZ.PwrDownEn;

	TIMING(mc, cha).PDM_MODE = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.SPAZ.PwrDownMode;

	TIMING(mc, cha).PDM_AGGR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.SPAZ.AggrPwrDownEn;

	TIMING(mc, cha).tMRD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR13.tMRD;

	TIMING(mc, cha).tMOD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR13.tMOD;

	TIMING(mc, cha).tMRD_PDA = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR13.tMRD_PDA;

	TIMING(mc, cha).tMOD_PDA = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR13.tMOD_PDA;

	TIMING(mc, cha).tXS = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR14.tXS;

	TIMING(mc, cha).tSTAG = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR20.tSTAG;

	TIMING(mc, cha).tPHYWRD = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR22.tPHY_WRDATA;

	TIMING(mc, cha).tPHYWRL = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR22.tPHY_WRLAT;

	TIMING(mc, cha).tPHYRDL = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR22.tPHY_RDLAT;

	TIMING(mc, cha).tRDDATA = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR22.tRDDATA_EN;

	TIMING(mc, cha).tWRMPR = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.DTR35.tWR_MPR;

    if (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.ENCR.value != 0xffffffff)
    {
	TIMING(mc, cha).Scramble = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.ENCR.DataScrambleEn;

	RO(Shm)->Proc.Mechanisms.DRAM_Scrambler = \
				RO(Shm)->Proc.Mechanisms.DRAM_Scrambler
				& (0b10 | TIMING(mc, cha).Scramble);

	TIMING(mc, cha).TSME = \
	  ((RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.ENCR.DataEncrEn == 1)
	|| (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.ENCR.ForceEncrEn == 1))
	&& (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.ENCR.DisAddrTweak == 0);

	RO(Shm)->Proc.Mechanisms.TSME	= RO(Shm)->Proc.Mechanisms.TSME
					& (0b10 | TIMING(mc, cha).TSME);
    }
  }
 }
}

void AMD_17h_CAP(RO(SHM_STRUCT) *RO(Shm),
		RO(PROC) *RO(Proc), RO(CORE) *RO(Core))
{
	unsigned short mc, clock_done = 0;
  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount && !clock_done; mc++)
  {
	unsigned short cha;
   for (cha = 0;
	cha < RO(Shm)->Uncore.MC[mc].ChannelCount && !clock_done;
		cha++)
   {
	unsigned short slot;

    switch(RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.CONFIG.BurstLength) {
    case 0x0:	/* BL2 */
    case 0x1:	/* BL4 */
    case 0x2:	/* BL8 */
      if (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.MISC.DDR4.MEMCLK)
      {
	RO(Shm)->Uncore.Bus.Rate = \
	RO(Shm)->Uncore.Bus.Speed = \
	RO(Shm)->Uncore.CtrlSpeed = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.MISC.DDR4.MEMCLK;

	RO(Shm)->Uncore.Bus.Rate = \
		( RO(Shm)->Uncore.Bus.Rate
		* RO(Shm)->Proc.Features.Factory.Clock.Q ) / 3;

	RO(Shm)->Uncore.Bus.Speed = \
		( RO(Shm)->Uncore.Bus.Speed
		* RO(Core)->Clock.Hz * 333333333LLU )
		/ ( RO(Shm)->Proc.Features.Factory.Clock.Hz
		  * ( 1000LLU * PRECISION * PRECISION ) );

	RO(Shm)->Uncore.CtrlSpeed = \
		( RO(Shm)->Uncore.CtrlSpeed
		* RO(Core)->Clock.Hz * 666666666LLU )
		/ ( RO(Shm)->Proc.Features.Factory.Clock.Hz
		  * ( 1000LLU * PRECISION * PRECISION ) );

	RO(Shm)->Uncore.Unit.DDR_Ver = 4;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;

	clock_done = 1;
      }
	break;
    case 0x3:	/* BL16 */
      if (RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.MISC.DDR5.MEMCLK)
      {
	RO(Shm)->Uncore.Bus.Rate = \
	RO(Shm)->Uncore.Bus.Speed = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.MISC.DDR5.MEMCLK;

	RO(Shm)->Uncore.Bus.Speed = \
		( RO(Shm)->Uncore.Bus.Speed * RO(Core)->Clock.Hz )
		/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.CtrlSpeed = 2LLU * RO(Shm)->Uncore.Bus.Speed;

	RO(Shm)->Uncore.Unit.DDR_Ver = 5;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_SDRAM;

	clock_done = 1;
      }
	break;
    }
    for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
    {
     if (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].AMD17h\
	.CFG.value != 0xffffffff)
     {
	if (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].AMD17h.CFG.RDIMM
	 || RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].AMD17h.CFG.LRDIMM)
	{
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_RDIMM;
		break;
	}
     }
    }
   }
  }
	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MHZ;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MTS;
}

void AMD_17h_IOMMU(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	RO(Shm)->Proc.Technology.IOMMU = RO(Proc)->Uncore.Bus.IOMMU_CR.IOMMU_En;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Major = \
			(RO(Proc)->Uncore.Bus.IOMMU_HDR.CapRev & 0b10000) >> 5;

	RO(Shm)->Proc.Technology.IOMMU_Ver_Minor = \
			RO(Proc)->Uncore.Bus.IOMMU_HDR.CapRev & 0b01111;
}

void AMD_1Ah_STX_CAP(	RO(SHM_STRUCT) *RO(Shm),
			RO(PROC) *RO(Proc), RO(CORE) *RO(Core) )
{
	unsigned short mc, clock_done = 0;
  for (mc = 0; mc < RO(Shm)->Uncore.CtrlCount && !clock_done; mc++)
  {
	unsigned short cha;
   for (cha = 0;
	cha < RO(Shm)->Uncore.MC[mc].ChannelCount && !clock_done;
		cha++)
   {
	const AMD_ZEN_UMC_CFG_MISC MISC = \
		RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.MISC;

	unsigned short slot;

    if (MISC.DDR5.MEMCLK)
    {
	const unsigned int correction = \
		BITEXTRZ((unsigned long long)MISC.value, 0, 3) == 0 ? 0 : 2;

	RO(Shm)->Uncore.Bus.Rate = 4U * MISC.DDR5.MEMCLK;
	RO(Shm)->Uncore.Bus.Rate = RO(Shm)->Uncore.Bus.Rate + correction;

	RO(Shm)->Uncore.Bus.Speed =(unsigned long long)RO(Shm)->Uncore.Bus.Rate;
	RO(Shm)->Uncore.Bus.Speed = \
		( RO(Shm)->Uncore.Bus.Speed * RO(Core)->Clock.Hz )
		/ RO(Shm)->Proc.Features.Factory.Clock.Hz;

	RO(Shm)->Uncore.CtrlSpeed = 2LLU * RO(Shm)->Uncore.Bus.Rate;

	clock_done = 1;
    }
    switch(RO(Proc)->Uncore.MC[mc].Channel[cha].AMD17h.CONFIG.BurstLength) {
    case 0x0:	/* BL2 */
    case 0x1:	/* BL4 */
    case 0x2:	/* BL8 */
	RO(Shm)->Uncore.Unit.DDR_Ver = 4;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;
	break;
    case 0x3:	/* BL16 */
	RO(Shm)->Uncore.Unit.DDR_Ver = 5;
	RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_LPDDR;
	break;
    }
    for (slot = 0; slot < RO(Shm)->Uncore.MC[mc].SlotCount; slot++)
    {
     if (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].AMD17h\
	.CFG.value != 0xffffffff)
     {
	if (RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].AMD17h.CFG.RDIMM
	 || RO(Proc)->Uncore.MC[mc].Channel[cha].DIMM[slot].AMD17h.CFG.LRDIMM)
	{
		RO(Shm)->Uncore.Unit.DDR_Std = RAM_STD_RDIMM;
		break;
	}
     }
    }
   }
  }
	RO(Shm)->Uncore.Unit.Bus_Rate = MC_MHZ;
	RO(Shm)->Uncore.Unit.BusSpeed = MC_MHZ;
	RO(Shm)->Uncore.Unit.DDR_Rate = MC_NIL;
	RO(Shm)->Uncore.Unit.DDRSpeed = MC_MTS;
}

#undef TIMING

static char *Chipset[CHIPSETS] = {
	[IC_CHIPSET]		= NULL,
	[IC_LAKEPORT]		= "82945/Lakeport",
	[IC_LAKEPORT_P] 	= "82946/Lakeport-P",
	[IC_LAKEPORT_X] 	= "82955/Lakeport-X",
	[IC_CALISTOGA]		= "82945/Calistoga",
	[IC_BROADWATER] 	= "82965/Broadwater",
	[IC_CRESTLINE]		= "82965/Crestline",
	[IC_CANTIGA]		= "G45/Cantiga",
	[IC_BEARLAKE_Q] 	= "Q35/Bearlake-Q",
	[IC_BEARLAKE_P] 	= "G33/Bearlake-PG+",
	[IC_BEARLAKE_QF]	= "Q33/Bearlake-QF",
	[IC_BEARLAKE_X] 	= "X38/Bearlake-X",
	[IC_INTEL_3200] 	= "Intel 3200",
	[IC_EAGLELAKE_Q]	= "Q45/Eaglelake-Q",
	[IC_EAGLELAKE_P]	= "G45/Eaglelake-P",
	[IC_EAGLELAKE_G]	= "G41/Eaglelake-G",
	[IC_PINEVIEW]		= "Pineview",
	[IC_CEDARVIEW]		= "Cedarview",
	[IC_BAYTRAIL]		= "Bay Trail",
	[IC_AIRMONT]		= "Airmont",
	[IC_GOLDMONT_PLUS]	= "Goldmont Plus",
	[IC_TYLERSBURG] 	= "X58/Tylersburg",
	[IC_IBEXPEAK]		= "P55/Ibex Peak",
	[IC_IBEXPEAK_M] 	= "QM57/Ibex Peak-M",
	[IC_COUGARPOINT]	= "P67/Cougar Point",
	[IC_PATSBURG]		= "X79/Patsburg",
	[IC_CAVECREEK]		= "Cave Creek",
	[IC_WELLSBURG]		= "X99/Wellsburg",
	[IC_PANTHERPOINT]	= "Panther Point",
	[IC_PANTHERPOINT_M]	= "Panther Point-M",
	[IC_LYNXPOINT]		= "Lynx Point",
	[IC_LYNXPOINT_M]	= "Lynx Point-M",
	[IC_WILDCATPOINT]	= "Wildcat Point",
	[IC_WILDCATPOINT_M]	= "Wildcat Point-M",
	[IC_SUNRISEPOINT]	= "Sunrise Point",
	[IC_UNIONPOINT] 	= "Union Point",
	[IC_CANNONPOINT]	= "Cannon Point",
	[IC_400_SERIES_P]	= "400 Series-Prem-U",
	[IC_400_SERIES_M]	= "400 Series-Base-U",
	[IC_495]		= "Intel 495",
	[IC_H470]		= "Intel H470",
	[IC_Z490]		= "Intel Z490",
	[IC_Q470]		= "Intel Q470",
	[IC_HM470]		= "Intel HM470",
	[IC_QM480]		= "Intel QM480",
	[IC_WM490]		= "Intel WM490",
	[IC_W480]		= "Intel W480",
	[IC_H510]		= "Intel H510",
	[IC_B560]		= "Intel B560",
	[IC_H570]		= "Intel H570",
	[IC_Q570]		= "Intel Q570",
	[IC_Z590]		= "Intel Z590",
	[IC_W580]		= "Intel W580",
	[IC_H610]		= "Intel H610",
	[IC_B660]		= "Intel B660",
	[IC_H670]		= "Intel H670",
	[IC_Z690]		= "Intel Z690",
	[IC_Q670]		= "Intel Q670",
	[IC_W680]		= "Intel W680",
	[IC_WM690]		= "Intel WM690",
	[IC_HM670]		= "Intel HM670",
	[IC_ADL_PCH_P]		= "Intel ADL PCH-P",
	[IC_ADL_PCH_U]		= "Intel ADL PCH-U",
	[IC_ADL_PCH_N305]	= "Intel ADL N305",
	[IC_ADL_PCH_N95]	= "Intel ADL N95",
	[IC_ADL_PCH_X7000E]	= "Intel X7000E",
	[IC_ADL_PCH_X7000RE]	= "Intel X7000RE",
	[IC_Z790]		= "Intel Z790",
	[IC_H770]		= "Intel H770",
	[IC_B760]		= "Intel B760",
	[IC_WM790]		= "Intel WM790",
	[IC_HM770]		= "Intel HM770",
	[IC_C262]		= "Intel C262",
	[IC_C266]		= "Intel C266",
	[IC_MTL_H]		= "Intel MTL-H",
	[IC_MTL_U]		= "Intel MTL-U",
	[IC_MTL_UT4]		= "Intel MTL-U Type4",
	[IC_ARL_S]		= "Intel ARL-S",
	[IC_LNL_V]		= "Intel LNL-V",
	[IC_K8] 		= "K8/HyperTransport",
	[IC_ZEN]		= "Zen UMC"
};

#define SET_CHIPSET(ic) 						\
({									\
	RO(Shm)->Uncore.ChipID = DID;					\
	RO(Shm)->Uncore.Chipset.ArchID = ic;				\
})

void PCI_Intel(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core),
		unsigned short DID)
{
	switch (DID) {
	case DID_INTEL_82945P_HB:
		P945_CLK(RO(Shm), RO(Proc), RO(Core));
		P945_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_LAKEPORT);
		break;
	case DID_INTEL_82945GM_HB:
	case DID_INTEL_82945GME_HB:
		P945_CLK(RO(Shm), RO(Proc), RO(Core));
		P945_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CALISTOGA);
		break;
	case DID_INTEL_82955_HB:
		P945_CLK(RO(Shm), RO(Proc), RO(Core));
		P955_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_LAKEPORT_X);
		break;
	case DID_INTEL_82946GZ_HB:
		P965_CLK(RO(Shm), RO(Proc), RO(Core));
		P965_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_LAKEPORT_P);
		break;
	case DID_INTEL_82965Q_HB:
	case DID_INTEL_82965G_HB:
		P965_CLK(RO(Shm), RO(Proc), RO(Core));
		P965_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_BROADWATER);
		break;
	case DID_INTEL_82965GM_HB:
	case DID_INTEL_82965GME_HB:
		G965_CLK(RO(Shm), RO(Proc), RO(Core));
		G965_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CRESTLINE);
		break;
	case DID_INTEL_GM45_HB:
		G965_CLK(RO(Shm), RO(Proc), RO(Core));
		G965_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANTIGA);
		break;
	case DID_INTEL_Q35_HB:
		P35_CLK(RO(Shm), RO(Proc), RO(Core));
		P35_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_BEARLAKE_Q);
		break;
	case DID_INTEL_G33_HB:
		P35_CLK(RO(Shm), RO(Proc), RO(Core));
		P35_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_BEARLAKE_P);
		break;
	case DID_INTEL_Q33_HB:
		P35_CLK(RO(Shm), RO(Proc), RO(Core));
		P35_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_BEARLAKE_QF);
		break;
	case DID_INTEL_X38_HB:
		P35_CLK(RO(Shm), RO(Proc), RO(Core));
		P35_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_BEARLAKE_X);
		break;
	case DID_INTEL_3200_HB:
		P35_CLK(RO(Shm), RO(Proc), RO(Core));
		P35_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_INTEL_3200);
		break;
	case DID_INTEL_Q45_HB:
		P35_CLK(RO(Shm), RO(Proc), RO(Core));
		P4S_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_EAGLELAKE_Q);
		break;
	case DID_INTEL_G45_HB:
		P35_CLK(RO(Shm), RO(Proc), RO(Core));
		P4S_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_EAGLELAKE_P);
		break;
	case DID_INTEL_G41_HB:
		P35_CLK(RO(Shm), RO(Proc), RO(Core));
		P4S_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_EAGLELAKE_G);
		break;
	case DID_INTEL_BONNELL_HB:
		P35_CLK(RO(Shm), RO(Proc), RO(Core));
		P35_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_PINEVIEW);
		break;
	case DID_INTEL_SALTWELL_HB:
		SLM_PTR(RO(Shm), RO(Proc), RO(Core));
		SET_CHIPSET(IC_CEDARVIEW);
		break;
	case DID_INTEL_SLM_PTR:
		SLM_PTR(RO(Shm), RO(Proc), RO(Core));
		SET_CHIPSET(IC_BAYTRAIL);
		break;
	case DID_INTEL_AIRMONT_HB:
		AMT_MCR(RO(Shm), RO(Proc), RO(Core));
		SET_CHIPSET(IC_AIRMONT);
		break;
	case DID_INTEL_X58_HUB_CTRL:
		QPI_CLK(RO(Shm), RO(Proc), RO(Core));
		break;
	case DID_INTEL_X58_HUB_CORE:
	case DID_INTEL_IIO_CORE_REG:
	case DID_INTEL_IVB_EP_IIO_VTD:
		X58_VTD(RO(Shm), RO(Proc), RO(Core));
		break;
	case DID_INTEL_I7_MCR:			/*	Bloomfield	*/
	case DID_INTEL_NHM_EP_MCR:		/*	Westmere EP	*/
		NHM_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_TYLERSBURG);
		break;
	case DID_INTEL_I7_MC_TEST:
	case DID_INTEL_LYNNFIELD_MC_TEST:
	case DID_INTEL_NHM_EP_MC_TEST:
	case DID_INTEL_NHM_EC_MC_TEST:
		DMI_CLK(RO(Shm), RO(Proc), RO(Core));
		break;
	case DID_INTEL_LYNNFIELD_MCR:		/*	Lynnfield	*/
	case DID_INTEL_NHM_EC_MCR:		/*	C5500-C3500	*/
		NHM_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_IBEXPEAK);
		break;
	case DID_INTEL_SNB_IMC_HA0:		/*	Sandy Bridge-E	*/
		SNB_EP_CAP(RO(Shm), RO(Proc), RO(Core));
		SNB_EP_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_PATSBURG);
		break;
	case DID_INTEL_SNB_IMC_SA:		/*	SNB Desktop	*/
		SNB_CAP(RO(Shm), RO(Proc), RO(Core));
		SNB_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_COUGARPOINT);
		break;
	case DID_INTEL_SNB_IMC_0104:
		SNB_CAP(RO(Shm), RO(Proc), RO(Core));
		SNB_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_IBEXPEAK_M);
		break;
	case DID_INTEL_SNB_EP_HOST_BRIDGE:	/* Xeon E5-2640		*/
	case DID_INTEL_IVB_EP_HOST_BRIDGE:	/* Xeon E5 & E7 v2	*/
		SNB_EP_CAP(RO(Shm), RO(Proc), RO(Core));
		SNB_EP_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CAVECREEK);
		break;
	case DID_INTEL_IVB_IMC_SA:		/*	IVB Desktop	*/
		IVB_CAP(RO(Shm), RO(Proc), RO(Core));
		SNB_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_PANTHERPOINT);
		break;
	case DID_INTEL_IVB_IMC_0154:		/* IVB Mobile i5-3337U	*/
		IVB_CAP(RO(Shm), RO(Proc), RO(Core));
		SNB_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_PANTHERPOINT_M);
		break;
	case DID_INTEL_HASWELL_IMC_SA:		/* HSW & BDW Desktop	*/
	case DID_INTEL_HASWELL_MH_IMC_HA0:	/* HSW Mobile M/H	*/
		HSW_CAP(RO(Shm), RO(Proc), RO(Core));
		HSW_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_LYNXPOINT_M);
		break;
	case DID_INTEL_HASWELL_UY_IMC_HA0:	/* HSW Mobile U/Y	*/
		HSW_CAP(RO(Shm), RO(Proc), RO(Core));
		HSW_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_LYNXPOINT_M);
		break;
	case DID_INTEL_HASWELL_IMC_HA0: 		/* Haswell	*/
		HSW_CAP(RO(Shm), RO(Proc), RO(Core));
		HSW_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_LYNXPOINT);
		break;
	case DID_INTEL_HSW_EP_HOST_BRIDGE:
		HSW_EP_CAP(RO(Shm), RO(Proc), RO(Core));
		HSW_EP_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_WELLSBURG);
		break;
	case DID_INTEL_BROADWELL_IMC_HA0:	/* Broadwell/Y/U Core m */
		HSW_CAP(RO(Shm), RO(Proc), RO(Core));
		HSW_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_WILDCATPOINT_M);
		break;
	case DID_INTEL_BROADWELL_D_IMC_HA0:	/*	BDW/Desktop	*/
	case DID_INTEL_BROADWELL_H_IMC_HA0:	/*	Broadwell/H	*/
	case DID_INTEL_BROADWELL_U_IMC_HA0:	/*	Broadwell/U	*/
		HSW_CAP(RO(Shm), RO(Proc), RO(Core));
		HSW_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_WELLSBURG);
		break;
	case DID_INTEL_SKYLAKE_U_IMC_HA:	/* Skylake/U Processor */
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_SUNRISEPOINT);
		break;
	case DID_INTEL_SKYLAKE_Y_IMC_HA:	/* Skylake/Y Processor */
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_SUNRISEPOINT);
		break;
	case DID_INTEL_SKYLAKE_S_IMC_HAD:	/* Skylake/S Dual Core */
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_SUNRISEPOINT);
		break;
	case DID_INTEL_SKYLAKE_S_IMC_HAQ:	/* Skylake/S Quad Core	*/
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_SUNRISEPOINT);
		break;
	case DID_INTEL_SKYLAKE_H_IMC_HAD:	/* Skylake/H Dual Core	*/
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_SUNRISEPOINT);
		break;
	case DID_INTEL_SKYLAKE_H_IMC_HAQ:	/* Skylake/H Quad Core	*/
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_SUNRISEPOINT);
		break;
	case DID_INTEL_SKYLAKE_DT_IMC_HA:	/* Skylake/DT Server	*/
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_SUNRISEPOINT);
		break;
	case DID_INTEL_KABYLAKE_U_IMC_HA:	/*	BGA 1356	*/
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_UNIONPOINT);
		break;
	case DID_INTEL_KABYLAKE_Y_IMC_HA:	/*	BGA 1515	*/
	case DID_INTEL_KABYLAKE_Y_IMC_HQ:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_UNIONPOINT);
		break;
	case DID_INTEL_KABYLAKE_H_IMC_HAD:	/* Kaby Lake/H Dual Core */
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_UNIONPOINT);
		break;
	case DID_INTEL_KABYLAKE_S_IMC_HAD:	/* Kaby Lake/S Dual Core */
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_UNIONPOINT);
		break;
	case DID_INTEL_KABYLAKE_H_IMC_HAQ:	/* Kaby Lake/H Quad Core */
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_UNIONPOINT);
		break;
	case DID_INTEL_KABYLAKE_DT_IMC_HA:	/* Kaby Lake/DT Server	*/
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_UNIONPOINT);
		break;
	case DID_INTEL_KABYLAKE_U_IMC_HAQ:	/* U-Quad Core BGA 1356 */
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_UNIONPOINT);
		break;
	case DID_INTEL_KABYLAKE_S_IMC_HAQ:	/* Kaby Lake/S Quad Core */
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_UNIONPOINT);
		break;
	case DID_INTEL_KABYLAKE_X_IMC_HAQ:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_UNIONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_S_IMC_HAQ:	/* Coffee Lake Quad Core */
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_S_IMC_HAS:	/* Coffee Lake Hexa Core */
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_S_IMC_HAD:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_U_IMC_HAD:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_U_IMC_HAQ:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_H_IMC_HAQ:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_H_IMC_HAS:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_H_IMC_HAO:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_W_IMC_HAQ:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_W_IMC_HAS:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_W_IMC_HAO:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_S_IMC_HAQ:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_S_IMC_HAS:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COFFEELAKE_R_S_IMC_HAO:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_WHISKEYLAKE_U_IMC_HAD:	/*	WHL Dual Core	*/
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_WHISKEYLAKE_U_IMC_HAQ:	/*	WHL Quad Core	*/
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_CANNONLAKE_U_IMC_HB:	/*	CNL-U		*/
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_CANNONPOINT);
		break;
	case DID_INTEL_COMETLAKE_S_IMC_6C:
	case DID_INTEL_COMETLAKE_S_IMC_10C:
	case DID_INTEL_COMETLAKE_H_IMC_10C:
	case DID_INTEL_COMETLAKE_W_IMC_10C:
	case DID_INTEL_COMETLAKE_M_IMC_6C:
	case DID_INTEL_COMETLAKE_S1_IMC:
	case DID_INTEL_COMETLAKE_S2_IMC:
	case DID_INTEL_COMETLAKE_S5_IMC:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		break;
	case DID_INTEL_COMETLAKE_U_IMC_HB:
	case DID_INTEL_COMETLAKE_U1_IMC:
	case DID_INTEL_COMETLAKE_U3_IMC:
		RKL_CAP(RO(Shm), RO(Proc), RO(Core));
		RKL_IMC(RO(Shm), RO(Proc));
		break;
	case DID_INTEL_COMETLAKE_PREM_U_PCH:
		SET_CHIPSET(IC_400_SERIES_P);
		break;
	case DID_INTEL_COMETLAKE_BASE_U_PCH:
		SET_CHIPSET(IC_400_SERIES_M);
		break;
	case DID_INTEL_COMETLAKE_U_ES_PCH:
	case DID_INTEL_COMETLAKE_Y_ES_PCH:
	case DID_INTEL_COMETLAKE_Y_PCH:
	case DID_INTEL_ICELAKE_U_PCH:
		SET_CHIPSET(IC_495);
		break;
	case DID_INTEL_COMETLAKE_H470_PCH:
		SET_CHIPSET(IC_H470);
		break;
	case DID_INTEL_COMETLAKE_Z490_PCH:
		SET_CHIPSET(IC_Z490);
		break;
	case DID_INTEL_COMETLAKE_Q470_PCH:
		SET_CHIPSET(IC_Q470);
		break;
	case DID_INTEL_COMETLAKE_HM470_PCH:
		SET_CHIPSET(IC_HM470);
		break;
	case DID_INTEL_COMETLAKE_QM480_PCH:
		SET_CHIPSET(IC_QM480);
		break;
	case DID_INTEL_COMETLAKE_WM490_PCH:
		SET_CHIPSET(IC_WM490);
		break;
	case DID_INTEL_COMETLAKE_W480_PCH:
		SET_CHIPSET(IC_W480);
		break;
	case DID_INTEL_ICELAKE_U_IMC:
	case DID_INTEL_ICELAKE_U_4C:
		SKL_CAP(RO(Shm), RO(Proc), RO(Core));
		SKL_IMC(RO(Shm), RO(Proc));
		break;
	case DID_INTEL_TIGERLAKE_U1_IMC:
	case DID_INTEL_TIGERLAKE_U2_IMC:
	case DID_INTEL_TIGERLAKE_U3_IMC:
	case DID_INTEL_TIGERLAKE_U4_IMC:
	case DID_INTEL_TIGERLAKE_H_IMC:
		TGL_CAP(RO(Shm), RO(Proc), RO(Core));
		TGL_IMC(RO(Shm), RO(Proc));
		break;
	case DID_INTEL_ROCKETLAKE_S_8C_IMC_HB:
	case DID_INTEL_ROCKETLAKE_S_6C_IMC_HB:
		RKL_CAP(RO(Shm), RO(Proc), RO(Core));
		RKL_IMC(RO(Shm), RO(Proc));
		break;
	case DID_INTEL_TIGERLAKE_UP3_IMC:
	case DID_INTEL_TIGERLAKE_UP4_IMC:
		SET_CHIPSET(IC_H510);
		break;
	case DID_INTEL_ROCKETLAKE_H510_PCH:
		SET_CHIPSET(IC_H510);
		break;
	case DID_INTEL_ROCKETLAKE_B560_PCH:
		SET_CHIPSET(IC_B560);
		break;
	case DID_INTEL_ROCKETLAKE_H570_PCH:
		SET_CHIPSET(IC_H570);
		break;
	case DID_INTEL_ROCKETLAKE_Q570_PCH:
		SET_CHIPSET(IC_Q570);
		break;
	case DID_INTEL_ROCKETLAKE_Z590_PCH:
		SET_CHIPSET(IC_Z590);
		break;
	case DID_INTEL_ROCKETLAKE_W580_PCH:
		SET_CHIPSET(IC_W580);
		break;
	case DID_INTEL_ALDERLAKE_S_8P_8E_HB:
	case DID_INTEL_ALDERLAKE_S_8P_4E_HB:
	case DID_INTEL_ALDERLAKE_S_6P_4E_HB:
	case DID_INTEL_ALDERLAKE_S_6P_0E_HB:
	case DID_INTEL_ALDERLAKE_S_4P_0E_HB:
	case DID_INTEL_ALDERLAKE_S_2P_0E_HB:
	case DID_INTEL_ALDERLAKE_H_6P_8E_HB:
	case DID_INTEL_ALDERLAKE_H_6P_4E_HB:
	case DID_INTEL_ALDERLAKE_H_4P_8E_HB:
	case DID_INTEL_ALDERLAKE_H_4P_4E_HB:
	case DID_INTEL_ALDERLAKE_HL_6P_8E_HB:
	case DID_INTEL_ALDERLAKE_U_2P_8E_HB:
	case DID_INTEL_ALDERLAKE_U_2P_4E_HB:
	case DID_INTEL_ALDERLAKE_U_1P_4E_HB:
	case DID_INTEL_ALDERLAKE_N300_8E_HB:
	case DID_INTEL_ALDERLAKE_N200_4E_HB:
	case DID_INTEL_ALDERLAKE_N100_4E_HB:
	case DID_INTEL_ALDERLAKE_X7835RE_8C_HB:
	case DID_INTEL_ALDERLAKE_X7433RE_4C_HB:
	case DID_INTEL_ALDERLAKE_N97_4E_HB:
	case DID_INTEL_ALDERLAKE_X7425E_4C_HB:
	case DID_INTEL_ALDERLAKE_N50_2E_HB:
	case DID_INTEL_ALDERLAKE_X7213RE_2C_HB:
	case DID_INTEL_ALDERLAKE_X7211RE_2C_HB:
	case DID_INTEL_ALDERLAKE_X7213E_2C_HB:
	case DID_INTEL_ALDERLAKE_X7211E_2C_HB:
		ADL_CAP(RO(Shm), RO(Proc), RO(Core));
		ADL_IMC(RO(Shm), RO(Proc));
		break;
	case DID_INTEL_ALDERLAKE_H610_PCH:
		SET_CHIPSET(IC_H610);
		break;
	case DID_INTEL_ALDERLAKE_B660_PCH:
		SET_CHIPSET(IC_B660);
		break;
	case DID_INTEL_ALDERLAKE_H670_PCH:
		SET_CHIPSET(IC_H670);
		break;
	case DID_INTEL_ALDERLAKE_Z690_PCH:
		SET_CHIPSET(IC_Z690);
		break;
	case DID_INTEL_ALDERLAKE_Q670_PCH:
		SET_CHIPSET(IC_Q670);
		break;
	case DID_INTEL_ALDERLAKE_W680_PCH:
		SET_CHIPSET(IC_W680);
		break;
	case DID_INTEL_ALDERLAKE_WM690_PCH:
		SET_CHIPSET(IC_WM690);
		break;
	case DID_INTEL_ALDERLAKE_HM670_PCH:
		SET_CHIPSET(IC_HM670);
		break;
	case DID_INTEL_ALDERLAKE_PCH_P:
		SET_CHIPSET(IC_ADL_PCH_P);
		break;
	case DID_INTEL_ALDERLAKE_PCH_U:
		SET_CHIPSET(IC_ADL_PCH_U);
		break;
	case DID_INTEL_ALDERLAKE_N305_PCH:
		SET_CHIPSET(IC_ADL_PCH_N305);
		break;
	case DID_INTEL_ALDERLAKE_N95_PCH:
		SET_CHIPSET(IC_ADL_PCH_N95);
		break;
	case DID_INTEL_ALDERLAKE_X7000E_PCH:
		SET_CHIPSET(IC_ADL_PCH_X7000E);
		break;
	case DID_INTEL_ALDERLAKE_X7000RE_PCH:
		SET_CHIPSET(IC_ADL_PCH_X7000RE);
		break;
	case DID_INTEL_GEMINILAKE_HB:
		GLK_CAP(RO(Shm), RO(Proc), RO(Core));
		GLK_IMC(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_GOLDMONT_PLUS);
		break;
	case DID_INTEL_RAPTORLAKE_S_8P_16E_HB:
	case DID_INTEL_RAPTORLAKE_S_8P_12E_HB:
	case DID_INTEL_RAPTORLAKE_S_8P_8E_HB:
	case DID_INTEL_RAPTORLAKE_S_6P_8E_HB1:
	case DID_INTEL_RAPTORLAKE_S_6P_4E_HB:
	case DID_INTEL_RAPTORLAKE_S_6P_8E_HB2:
	case DID_INTEL_RAPTORLAKE_S_4P_0E_HB:
	case DID_INTEL_RAPTORLAKE_HX_8P_16E_HB:
	case DID_INTEL_RAPTORLAKE_HX_8P_12E_HB:
	case DID_INTEL_RAPTORLAKE_HX_8P_8E_HB1:
	case DID_INTEL_RAPTORLAKE_HX_6P_8E_HB1:
	case DID_INTEL_RAPTORLAKE_HX_6P_4E_HB1:
	case DID_INTEL_RAPTORLAKE_HX_8P_8E_HB2:
	case DID_INTEL_RAPTORLAKE_HX_6P_8E_HB2:
	case DID_INTEL_RAPTORLAKE_HX_6P_4E_HB2:
	case DID_INTEL_RAPTORLAKE_H_6P_8E_HB:
	case DID_INTEL_RAPTORLAKE_H_4P_8E_HB:
	case DID_INTEL_RAPTORLAKE_H_6P_4E_HB:
	case DID_INTEL_RAPTORLAKE_H_4P_4E_HB:
	case DID_INTEL_RAPTORLAKE_U_2P_8E_HB:
	case DID_INTEL_RAPTORLAKE_U_2P_4E_HB:
	case DID_INTEL_RAPTORLAKE_U_1P_4E_HB:
	case DID_INTEL_RAPTORLAKE_E_8P_0E_HB:
	case DID_INTEL_RAPTORLAKE_E_6P_0E_HB:
	case DID_INTEL_RAPTORLAKE_E_4P_0E_HB:
	case DID_INTEL_RAPTORLAKE_PX_6P_8E_HB:
	case DID_INTEL_RAPTORLAKE_PX_4P_8E_HB:
		RPL_CAP(RO(Shm), RO(Proc), RO(Core));
		RPL_IMC(RO(Shm), RO(Proc));
		break;
	case DID_INTEL_RAPTORLAKE_Z790_PCH:
		SET_CHIPSET(IC_Z790);
		break;
	case DID_INTEL_RAPTORLAKE_H770_PCH:
		SET_CHIPSET(IC_H770);
		break;
	case DID_INTEL_RAPTORLAKE_B760_PCH:
		SET_CHIPSET(IC_B760);
		break;
	case DID_INTEL_RAPTORLAKE_WM790_PCH:
		SET_CHIPSET(IC_WM790);
		break;
	case DID_INTEL_RAPTORLAKE_HM770_PCH:
		SET_CHIPSET(IC_HM770);
		break;
	case DID_INTEL_RAPTORLAKE_C262_PCH:
		SET_CHIPSET(IC_C262);
		break;
	case DID_INTEL_RAPTORLAKE_C266_PCH:
		SET_CHIPSET(IC_C266);
		break;
	case DID_INTEL_METEORLAKE_UT4_2_8_2_HB:
	case DID_INTEL_METEORLAKE_H_6_8_2_HB:
	case DID_INTEL_METEORLAKE_U_2_8_2_HB:
	case DID_INTEL_METEORLAKE_H_4_8_2_HB:
	case DID_INTEL_METEORLAKE_U_2_4_2_HB:
	case DID_INTEL_METEORLAKE_M_6_8_2_HB:
	case DID_INTEL_METEORLAKE_M_4_8_2_HB:
	case DID_INTEL_METEORLAKE_M_2_8_2_HB:
	case DID_INTEL_METEORLAKE_M_4_4_2_HB:
		MTL_CAP(RO(Shm), RO(Proc), RO(Core));
		MTL_IMC(RO(Shm), RO(Proc));
		break;
	case DID_INTEL_METEORLAKE_H_PCH:
		SET_CHIPSET(IC_MTL_H);
		break;
	case DID_INTEL_METEORLAKE_U_PCH:
		SET_CHIPSET(IC_MTL_U);
		break;
	case DID_INTEL_METEORLAKE_UT4_PCH:
		SET_CHIPSET(IC_MTL_UT4);
		break;
	case DID_INTEL_ARROWLAKE_S_8_16_HB:
	case DID_INTEL_ARROWLAKE_S_8_12_HB:
	case DID_INTEL_ARROWLAKE_S_6_8_HB:
		ARL_CAP(RO(Shm), RO(Proc), RO(Core));
		ARL_IMC(RO(Shm), RO(Proc));
		break;
	case DID_INTEL_ARROWLAKE_S_PCH:
		SET_CHIPSET(IC_ARL_S);
		break;
	case DID_INTEL_LUNARLAKE_V_4P_4E:
		LNL_CAP(RO(Shm), RO(Proc), RO(Core));
		LNL_IMC(RO(Shm), RO(Proc));
		break;
	case DID_INTEL_LUNARLAKE_V_PCH:
		SET_CHIPSET(IC_LNL_V);
		break;
	}
}

void PCI_AMD(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) *RO(Core),
		unsigned short DID)
{
	switch (DID) {
	case DID_AMD_K8_NB_MEMCTL:
		AMD_0Fh_HTT(RO(Shm), RO(Proc));
		AMD_0Fh_MCH(RO(Shm), RO(Proc));
		SET_CHIPSET(IC_K8);
		break;
	case DID_AMD_17H_ZEN_PLUS_NB_IOMMU:
	case DID_AMD_17H_ZEPPELIN_NB_IOMMU:
	case DID_AMD_17H_RAVEN_NB_IOMMU:
	case DID_AMD_17H_ZEN2_MTS_NB_IOMMU:
	case DID_AMD_17H_STARSHIP_NB_IOMMU:
	case DID_AMD_17H_RENOIR_NB_IOMMU:
	case DID_AMD_17H_ZEN_APU_NB_IOMMU:
	case DID_AMD_17H_ZEN2_APU_NB_IOMMU:
	case DID_AMD_17H_FIREFLIGHT_NB_IOMMU:
	case DID_AMD_17H_ARDEN_NB_IOMMU:
	case DID_AMD_17H_JUPITER_NB_IOMMU:
	case DID_AMD_19H_ZEN3_RMB_NB_IOMMU:
	case DID_AMD_19H_ZEN4_RPL_NB_IOMMU:
	case DID_AMD_19H_ZEN4_GNA_NB_IOMMU:
	case DID_AMD_19H_ZEN4_PHX_NB_IOMMU:
	case DID_AMD_1AH_ZEN5_TURIN_IOMMU:
	case DID_AMD_1AH_ZEN5_STX_IOMMU:
		AMD_17h_IOMMU(RO(Shm), RO(Proc));
		break;
	case DID_AMD_17H_ZEPPELIN_DF_UMC:
	case DID_AMD_17H_RAVEN_DF_UMC:
	case DID_AMD_17H_MATISSE_DF_UMC:
	case DID_AMD_17H_STARSHIP_DF_UMC:
	case DID_AMD_17H_RENOIR_DF_UMC:
	case DID_AMD_17H_ARIEL_DF_UMC:
	case DID_AMD_17H_RAVEN2_DF_UMC:
	case DID_AMD_17H_FIREFLIGHT_DF_UMC:
	case DID_AMD_17H_ARDEN_DF_UMC:
	case DID_AMD_17H_JUPITER_DF_UMC:
	case DID_AMD_19H_VERMEER_DF_UMC:
	case DID_AMD_19H_CEZANNE_DF_UMC:
	case DID_AMD_19H_REMBRANDT_DF_UMC:
	case DID_AMD_19H_RAPHAEL_DF_UMC:
	case DID_AMD_19H_GENOA_DF_UMC:
	case DID_AMD_19H_PHOENIX_DF_UMC:
	case DID_AMD_1AH_TURIN_DF_UMC:
		AMD_17h_UMC(RO(Shm), RO(Proc));
		AMD_17h_CAP(RO(Shm), RO(Proc), RO(Core));
		SET_CHIPSET(IC_ZEN);
		break;
	case DID_AMD_1AH_STX_DF_UMC:
	case DID_AMD_1AH_STXH_DF_UMC:
		AMD_17h_UMC(RO(Shm), RO(Proc));
		AMD_1Ah_STX_CAP(RO(Shm), RO(Proc), RO(Core));
		SET_CHIPSET(IC_ZEN);
		break;
	}
}

#undef SET_CHIPSET

void Uncore_Update(	RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc),
			RO(CORE) *RO(Core) )
{
	unsigned int idx;
	/*	Copy the # of controllers.				*/
	RO(Shm)->Uncore.CtrlCount = RO(Proc)->Uncore.CtrlCount;
	/*	Decode the Memory Controller for each found vendor:device */
	Chipset[IC_CHIPSET] = RO(Proc)->Features.Info.Vendor.ID;
	RO(Shm)->Uncore.ChipID = 0x0;
	RO(Shm)->Uncore.Chipset.ArchID = IC_CHIPSET;

  for (idx = 0; idx < CHIP_MAX_PCI; idx++) {
    switch (RO(Proc)->Uncore.Chip[idx].VID) {
    case PCI_VENDOR_ID_INTEL:
	PCI_Intel(RO(Shm), RO(Proc), RO(Core), RO(Proc)->Uncore.Chip[idx].DID);
	break;
    case PCI_VENDOR_ID_AMD:
	PCI_AMD(RO(Shm), RO(Proc), RO(Core), RO(Proc)->Uncore.Chip[idx].DID);
	break;
    }
  }
	/*	Copy the chipset codename.				*/
	StrCopy(RO(Shm)->Uncore.Chipset.CodeName,
		Chipset[RO(Shm)->Uncore.Chipset.ArchID],
		CODENAME_LEN);
	/*	Copy the Uncore clock ratios.				*/
	memcpy( RO(Shm)->Uncore.Boost,
		RO(Proc)->Uncore.Boost,
		(UNCORE_BOOST(SIZE)) * sizeof(unsigned int) );
}

void CPUID_Dump(RO(SHM_STRUCT) *RO(Shm), RO(CORE) **RO(Core), unsigned int cpu)
{	/* Copy the Vendor CPUID dump per Core.				*/
	RO(Shm)->Cpu[cpu].Query.StdFunc = RO(Core, AT(cpu))->Query.StdFunc;
	RO(Shm)->Cpu[cpu].Query.ExtFunc = RO(Core, AT(cpu))->Query.ExtFunc;

	enum CPUID_ENUM i;
    for (i = 0; i < CPUID_MAX_FUNC; i++) {
	RO(Shm)->Cpu[cpu].CpuID[i].func   = RO(Core, AT(cpu))->CpuID[i].func;
	RO(Shm)->Cpu[cpu].CpuID[i].sub    = RO(Core, AT(cpu))->CpuID[i].sub;
	RO(Shm)->Cpu[cpu].CpuID[i].reg[0] = RO(Core, AT(cpu))->CpuID[i].reg[0];
	RO(Shm)->Cpu[cpu].CpuID[i].reg[1] = RO(Core, AT(cpu))->CpuID[i].reg[1];
	RO(Shm)->Cpu[cpu].CpuID[i].reg[2] = RO(Core, AT(cpu))->CpuID[i].reg[2];
	RO(Shm)->Cpu[cpu].CpuID[i].reg[3] = RO(Core, AT(cpu))->CpuID[i].reg[3];
    }
}

unsigned int AMD_L2_L3_Way_Associativity(RO(CORE) **RO(Core),
					unsigned int cpu,
					unsigned int level)
{
	switch (RO(Core, AT(cpu))->T.Cache[level].Way) {
	case 0x9:
		return ((RO(Core, AT(cpu))->CpuID[
			CPUID_8000001D_00000000_CACHE_L1D_PROPERTIES + level
			].reg[1] >> 22) + 1);
	case 0x6:
		return 8;
	case 0x8:
		return 16;
	case 0xa:
		return 32;
	case 0xb:
		return 48;
	case 0xc:
		return 64;
	case 0xd:
		return 96;
	case 0xe:
		return 128;
	default:
		return RO(Core, AT(cpu))->T.Cache[level].Way;
	}
}

void Topology(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc), RO(CORE) **RO(Core),
		unsigned int cpu)
{
	unsigned int loop;
	/*	Copy each Core topology.				*/
	RO(Shm)->Cpu[cpu].Topology.MP.BSP= (RO(Core, AT(cpu))->T.Base.BSP)? 1:0;
	RO(Shm)->Cpu[cpu].Topology.ApicID     = RO(Core,AT(cpu))->T.ApicID;
	RO(Shm)->Cpu[cpu].Topology.CoreID     = RO(Core,AT(cpu))->T.CoreID;
	RO(Shm)->Cpu[cpu].Topology.ThreadID   = RO(Core,AT(cpu))->T.ThreadID;
	RO(Shm)->Cpu[cpu].Topology.PackageID  = RO(Core,AT(cpu))->T.PackageID;
	RO(Shm)->Cpu[cpu].Topology.Cluster.ID = RO(Core,AT(cpu))->T.Cluster.ID;
	/*	x2APIC capability.					*/
	RO(Shm)->Cpu[cpu].Topology.MP.x2APIC= RO(Proc)->Features.Std.ECX.x2APIC;

    if ((RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_AMD)
    ||	(RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_HYGON))
    {
	RO(Shm)->Cpu[cpu].Topology.MP.x2APIC |= \
				RO(Proc)->Features.ExtInfo.ECX.ExtApicId;
    }
  else if ((RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_INTEL)
	&& (RO(Shm)->Proc.Features.ExtFeature.EDX.Hybrid == 1))
    {
	switch (RO(Core,AT(cpu))->T.Cluster.Hybrid.CoreType) {
	case Hybrid_Atom:
		RO(Shm)->Cpu[cpu].Topology.MP.Ecore = 1;
		break;
	case Hybrid_Core:
		RO(Shm)->Cpu[cpu].Topology.MP.Pcore = 1;
		break;
	}
	RO(Shm)->Cpu[cpu].Topology.Cluster.Hybrid_ID = \
				RO(Core,AT(cpu))->T.Cluster.Hybrid.Model_ID;
    }
	/*	Is local APIC enabled in xAPIC mode ?			*/
	RO(Shm)->Cpu[cpu].Topology.MP.x2APIC &= \
					RO(Core, AT(cpu))->T.Base.APIC_EN;
	/*	Is xAPIC enabled in x2APIC mode ?			*/
	RO(Shm)->Cpu[cpu].Topology.MP.x2APIC = \
					RO(Shm)->Cpu[cpu].Topology.MP.x2APIC
					<< RO(Core, AT(cpu))->T.Base.x2APIC_EN;
	/*	Aggregate the Caches topology.				*/
    for (loop = 0; loop < CACHE_MAX_LEVEL; loop++)
    {
      if (RO(Core, AT(cpu))->T.Cache[loop].Type > 0)
      {
	unsigned int level = RO(Core, AT(cpu))->T.Cache[loop].Level;
	if (RO(Core, AT(cpu))->T.Cache[loop].Type == 2) {/* Instruction	*/
		level = 0;
	}
	if (RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_INTEL)
	{
		RO(Shm)->Cpu[cpu].Topology.Cache[level].Set = \
				RO(Core, AT(cpu))->T.Cache[loop].Set + 1;

		RO(Shm)->Cpu[cpu].Topology.Cache[level].LineSz = \
				RO(Core, AT(cpu))->T.Cache[loop].LineSz + 1;

		RO(Shm)->Cpu[cpu].Topology.Cache[level].Part = \
				RO(Core, AT(cpu))->T.Cache[loop].Part + 1;

		RO(Shm)->Cpu[cpu].Topology.Cache[level].Way = \
				RO(Core, AT(cpu))->T.Cache[loop].Way + 1;

		RO(Shm)->Cpu[cpu].Topology.Cache[level].Size = \
				  RO(Shm)->Cpu[cpu].Topology.Cache[level].Set
				* RO(Shm)->Cpu[cpu].Topology.Cache[level].LineSz
				* RO(Shm)->Cpu[cpu].Topology.Cache[level].Part
				* RO(Shm)->Cpu[cpu].Topology.Cache[level].Way;
	} else {
	    if ((RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_AMD)
	     || (RO(Shm)->Proc.Features.Info.Vendor.CRC == CRC_HYGON))
	    {
		RO(Shm)->Cpu[cpu].Topology.Cache[level].Way = \
			(loop == 2) || (loop == 3) ?
				AMD_L2_L3_Way_Associativity(RO(Core), cpu, loop)
				: RO(Core, AT(cpu))->T.Cache[loop].Way;

		RO(Shm)->Cpu[cpu].Topology.Cache[level].Size = \
					RO(Core, AT(cpu))->T.Cache[loop].Size;
	    }
	}
	RO(Shm)->Cpu[cpu].Topology.Cache[level].Feature.WriteBack = \
					RO(Core, AT(cpu))->T.Cache[loop].WrBack;

	RO(Shm)->Cpu[cpu].Topology.Cache[level].Feature.Inclusive = \
					RO(Core, AT(cpu))->T.Cache[loop].Inclus;
      }
    }
	/*	Apply various architecture size unit.			*/
    switch (RO(Proc)->ArchID) {
    case AMD_Family_15h:
	/*TODO: do models 60h & 70h need a 512 KB size unit adjustment ? */
	if ((RO(Shm)->Proc.Features.Std.EAX.ExtModel == 0x6)
	 || (RO(Shm)->Proc.Features.Std.EAX.ExtModel == 0x7)) {
		break;
	}
	fallthrough;
    case AMD_Zen:
    case AMD_Zen_APU:
    case AMD_ZenPlus:
    case AMD_ZenPlus_APU:
    case AMD_Zen_Dali:
    case AMD_EPYC_Rome_CPK:
    case AMD_Zen2_Renoir:
    case AMD_Zen2_LCN:
    case AMD_Zen2_MTS:
    case AMD_Zen2_Ariel:
    case AMD_Zen2_Jupiter:
    case AMD_Zen2_Galileo:
    case AMD_Zen2_MDN:
    case AMD_Zen3_VMR:
    case AMD_Zen3_CZN:
    case AMD_EPYC_Milan:
    case AMD_Zen3_Chagall:
    case AMD_Zen3_Badami:
    case AMD_Zen3Plus_RMB:
    case AMD_Zen4_Genoa:
    case AMD_Zen4_RPL:
    case AMD_Zen4_PHX:
    case AMD_Zen4_PHXR:
    case AMD_Zen4_PHX2:
    case AMD_Zen4_HWK:
    case AMD_Zen4_Bergamo:
    case AMD_Zen4_STP:
    case AMD_Zen5_STX:
    case AMD_Zen5_Eldora:
    case AMD_Zen5_Turin:
    case AMD_Zen5_Turin_Dense:
    case AMD_Family_1Ah_01h:
    case AMD_Zen5_KRK:
    case AMD_Zen5_STXH:
    case AMD_Zen5_SHP:
    case AMD_Zen5_GRP:
    case AMD_Family_17h:
    case Hygon_Family_18h:
    case AMD_Family_19h:
    case AMD_Family_1Ah:
    VIRTUALIZED_L3:
	/* CPUID_Fn80000006_EDX: Value in [3FFFh - 0001h] = (<Value> *0.5) MB */
	RO(Shm)->Cpu[cpu].Topology.Cache[3].Size *= 512;
	break;
    default:
	if (RO(Shm)->Proc.Features.Std.ECX.Hyperv) {	/* Virtualized ? */
		goto VIRTUALIZED_L3;
	}
	break;
    }
}

void CStates(RO(SHM_STRUCT) *RO(Shm), RO(CORE) **RO(Core), unsigned int cpu)
{	/*	Copy the C-State Configuration Control			*/
	RO(Shm)->Cpu[cpu].Query.CfgLock = RO(Core, AT(cpu))->Query.CfgLock;

	RO(Shm)->Cpu[cpu].Query.CStateLimit = \
					RO(Core, AT(cpu))->Query.CStateLimit;
	/*	Copy Intel Max C-State Inclusion			*/
	RO(Shm)->Cpu[cpu].Query.IORedir = RO(Core, AT(cpu))->Query.IORedir;

	RO(Shm)->Cpu[cpu].Query.CStateInclude = \
					RO(Core, AT(cpu))->Query.CStateInclude;
	/*	Copy any architectural C-States I/O Base Address	*/
	RO(Shm)->Cpu[cpu].Query.CStateBaseAddr = \
					RO(Core, AT(cpu))->Query.CStateBaseAddr;
}

void PowerThermal(	RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc),
			RO(CORE) **RO(Core), unsigned int cpu )
{
	UNUSED(RO(Proc));

	RO(Shm)->Cpu[cpu].PowerThermal.DutyCycle.Extended = \
		RO(Core, AT(cpu))->PowerThermal.ClockModulation.ECMD;

	RO(Shm)->Cpu[cpu].PowerThermal.DutyCycle.ClockMod = \
		RO(Core, AT(cpu))->PowerThermal.ClockModulation.DutyCycle
			>> !RO(Shm)->Cpu[cpu].PowerThermal.DutyCycle.Extended;

	RO(Shm)->Cpu[cpu].PowerThermal.PowerPolicy = \
		RO(Core, AT(cpu))->PowerThermal.PerfEnergyBias.PowerPolicy;

	RO(Shm)->Cpu[cpu].PowerThermal.HWP.Capabilities.Highest = \
		RO(Core, AT(cpu))->PowerThermal.HWP_Capabilities.Highest;

	RO(Shm)->Cpu[cpu].PowerThermal.HWP.Capabilities.Guaranteed = \
		RO(Core, AT(cpu))->PowerThermal.HWP_Capabilities.Guaranteed;

	RO(Shm)->Cpu[cpu].PowerThermal.HWP.Capabilities.Most_Efficient = \
		RO(Core, AT(cpu))->PowerThermal.HWP_Capabilities.Most_Efficient;

	RO(Shm)->Cpu[cpu].PowerThermal.HWP.Capabilities.Lowest = \
		RO(Core, AT(cpu))->PowerThermal.HWP_Capabilities.Lowest;

	RO(Shm)->Cpu[cpu].PowerThermal.HWP.Request.Minimum_Perf = \
		RO(Core, AT(cpu))->PowerThermal.HWP_Request.Minimum_Perf;

	RO(Shm)->Cpu[cpu].PowerThermal.HWP.Request.Maximum_Perf = \
		RO(Core, AT(cpu))->PowerThermal.HWP_Request.Maximum_Perf;

	RO(Shm)->Cpu[cpu].PowerThermal.HWP.Request.Desired_Perf = \
		RO(Core, AT(cpu))->PowerThermal.HWP_Request.Desired_Perf;

	RO(Shm)->Cpu[cpu].PowerThermal.HWP.Request.Energy_Pref = \
		RO(Core, AT(cpu))->PowerThermal.HWP_Request.Energy_Pref;

	memcpy( &RO(Shm)->Cpu[cpu].ThermalPoint,
		&RO(Core, AT(cpu))->ThermalPoint,
		sizeof(THERMAL_POINT) );
}

void SystemRegisters(	RO(SHM_STRUCT) *RO(Shm), RO(CORE) **RO(Core),
			unsigned int cpu )
{
	RO(Shm)->Cpu[cpu].SystemRegister.RFLAGS = \
				RO(Core, AT(cpu))->SystemRegister.RFLAGS;

	RO(Shm)->Cpu[cpu].SystemRegister.CR0 = \
				RO(Core, AT(cpu))->SystemRegister.CR0;

	RO(Shm)->Cpu[cpu].SystemRegister.CR3 = \
				RO(Core, AT(cpu))->SystemRegister.CR3;

	RO(Shm)->Cpu[cpu].SystemRegister.CR4 = \
				RO(Core, AT(cpu))->SystemRegister.CR4;

	RO(Shm)->Cpu[cpu].SystemRegister.CR8 = \
				RO(Core, AT(cpu))->SystemRegister.CR8;

	RO(Shm)->Cpu[cpu].SystemRegister.EFER = \
				RO(Core, AT(cpu))->SystemRegister.EFER;

	RO(Shm)->Cpu[cpu].SystemRegister.EFCR = \
				RO(Core, AT(cpu))->SystemRegister.EFCR;

	RO(Shm)->Cpu[cpu].SystemRegister.XCR0 = \
				RO(Core, AT(cpu))->SystemRegister.XCR0;

	RO(Shm)->Cpu[cpu].SystemRegister.XSS = \
				RO(Core, AT(cpu))->SystemRegister.XSS;

	RO(Shm)->Cpu[cpu].SystemRegister.SYSCFG = \
				RO(Core, AT(cpu))->SystemRegister.SYSCFG;

	RO(Shm)->Cpu[cpu].SystemRegister.HWCR = \
				RO(Core, AT(cpu))->SystemRegister.HWCR.value;
}

void SysGate_OS_Driver(RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc))
{
	memset(&RO(Shm)->SysGate.OS, 0, sizeof(OS_DRIVER));
    if (strlen(RO(Proc)->OS.IdleDriver.Name) > 0) {
	int idx;

	StrCopy(RO(Shm)->SysGate.OS.IdleDriver.Name,
		RO(Proc)->OS.IdleDriver.Name,
		CPUIDLE_NAME_LEN);

	RO(Shm)->SysGate.OS.IdleDriver.stateCount = \
					RO(Proc)->OS.IdleDriver.stateCount;

	RO(Shm)->SysGate.OS.IdleDriver.stateLimit = \
					RO(Proc)->OS.IdleDriver.stateLimit;

	for (idx = 0; idx < RO(Shm)->SysGate.OS.IdleDriver.stateCount; idx++)
	{
		StrCopy(RO(Shm)->SysGate.OS.IdleDriver.State[idx].Name,
			RO(Proc)->OS.IdleDriver.State[idx].Name,
			CPUIDLE_NAME_LEN);

		StrCopy(RO(Shm)->SysGate.OS.IdleDriver.State[idx].Desc,
			RO(Proc)->OS.IdleDriver.State[idx].Desc,
			CPUIDLE_NAME_LEN);

		RO(Shm)->SysGate.OS.IdleDriver.State[idx].exitLatency = \
			RO(Proc)->OS.IdleDriver.State[idx].exitLatency;

		RO(Shm)->SysGate.OS.IdleDriver.State[idx].powerUsage = \
			RO(Proc)->OS.IdleDriver.State[idx].powerUsage;

		RO(Shm)->SysGate.OS.IdleDriver.State[idx].targetResidency = \
			RO(Proc)->OS.IdleDriver.State[idx].targetResidency;
	}
    }
    if (strlen(RO(Proc)->OS.FreqDriver.Name) > 0) {
	StrCopy(RO(Shm)->SysGate.OS.FreqDriver.Name,
		RO(Proc)->OS.FreqDriver.Name,
		CPUFREQ_NAME_LEN);
    }
    if (strlen(RO(Proc)->OS.FreqDriver.Governor) > 0) {
	StrCopy(RO(Shm)->SysGate.OS.FreqDriver.Governor,
		RO(Proc)->OS.FreqDriver.Governor,
		CPUFREQ_NAME_LEN);
    }
}

void SysGate_Kernel(REF *Ref)
{
	RO(SHM_STRUCT) *RO(Shm) = Ref->RO(Shm);
	RO(SYSGATE) *SysGate = Ref->RO(SysGate);

	RO(Shm)->SysGate.kernel.version = SysGate->kernelVersionNumber >> 16;
	RO(Shm)->SysGate.kernel.major = SysGate->kernelVersionNumber >> 8;
	RO(Shm)->SysGate.kernel.major = RO(Shm)->SysGate.kernel.major & 0xff;
	RO(Shm)->SysGate.kernel.minor = SysGate->kernelVersionNumber & 0xff;

	memcpy(RO(Shm)->SysGate.sysname, SysGate->sysname, MAX_UTS_LEN);
	memcpy(RO(Shm)->SysGate.release, SysGate->release, MAX_UTS_LEN);
	memcpy(RO(Shm)->SysGate.version, SysGate->version, MAX_UTS_LEN);
	memcpy(RO(Shm)->SysGate.machine, SysGate->machine, MAX_UTS_LEN);
}

#define CS_Reset_Array(_CS)						\
({									\
	_CS.index[0] = 0;						\
})

#define CS_Seek_Store(_fd, _ptr, _CS)					\
({									\
	size_t	length; 						\
	if (fscanf(_fd, "%s", _ptr) == 1) {				\
		unsigned char offset;					\
		length = strlen(_ptr);					\
		_ptr += length; 					\
		(*_ptr) = 0x0;						\
		_ptr++; 						\
		length = _ptr - _CS.array;				\
		offset = (unsigned char) length;			\
		_CS.index[0]++; 					\
		_CS.index[_CS.index[0]] = offset;			\
	}								\
})

void ClockSource_Update(RO(SHM_STRUCT) *RO(Shm))
{
	FILE	*fd;

	CS_Reset_Array(RO(Shm)->CS);

    if ((fd = fopen(CLOCKSOURCE_PATH"/current_clocksource", "r")) != NULL)
    {
	char *ptr = RO(Shm)->CS.array;

	CS_Seek_Store(fd, ptr, RO(Shm)->CS);

	fclose(fd);
	if ((fd = fopen(CLOCKSOURCE_PATH"/available_clocksource", "r")) != NULL)
	{
		do {
			CS_Seek_Store(fd, ptr, RO(Shm)->CS);
		} while (!feof(fd) && (RO(Shm)->CS.index[0] < 7));
		fclose(fd);
	}
    }
}

long ClockSource_Submit(RO(SHM_STRUCT) *RO(Shm), unsigned char index)
{
    if (index <= RO(Shm)->CS.index[0])
    {
	FILE	*fd;
	if ((fd = fopen(CLOCKSOURCE_PATH"/current_clocksource", "w")) != NULL)
	{
		char *ptr = &RO(Shm)->CS.array[RO(Shm)->CS.index[index]];
		fprintf(fd, "%s", ptr);
		fclose(fd);
		return 0;
	}
    }
	return -EINVAL;
}

static const int reverseSign[2] = {+1, -1};

static int SortByRuntime(const void *p1, const void *p2, void *arg)
{
	TASK_MCB *task1 = (TASK_MCB*) p1, *task2 = (TASK_MCB*) p2;
	REF *Ref = (REF*) arg;

	int sort = task1->runtime < task2->runtime ? +1 : -1;
	sort *= reverseSign[Ref->RO(Shm)->SysGate.reverseOrder];
	return sort;
}

static int SortByUsertime(const void *p1, const void *p2, void *arg)
{
	TASK_MCB *task1 = (TASK_MCB*) p1, *task2 = (TASK_MCB*) p2;
	REF *Ref = (REF*) arg;

	int sort = task1->usertime < task2->usertime ? +1 : -1;
	sort *= reverseSign[Ref->RO(Shm)->SysGate.reverseOrder];
	return sort;
}

static int SortBySystime(const void *p1, const void *p2, void *arg)
{
	TASK_MCB *task1 = (TASK_MCB*) p1, *task2 = (TASK_MCB*) p2;
	REF *Ref = (REF*) arg;

	int sort = task1->systime < task2->systime ? +1 : -1;
	sort *= reverseSign[Ref->RO(Shm)->SysGate.reverseOrder];
	return sort;
}

static int SortByState(const void *p1, const void *p2, void *arg)
{
	TASK_MCB *task1 = (TASK_MCB*) p1, *task2 = (TASK_MCB*) p2;
	REF *Ref = (REF*) arg;

	int sort = task1->state < task2->state ? -1 : +1;
	sort *= reverseSign[Ref->RO(Shm)->SysGate.reverseOrder];
	return sort;
}

static int SortByPID(const void *p1, const void *p2, void *arg)
{
	TASK_MCB *task1 = (TASK_MCB*) p1, *task2 = (TASK_MCB*) p2;
	REF *Ref = (REF*) arg;

	int sort = task1->pid < task2->pid ? -1 : +1;
	sort *= reverseSign[Ref->RO(Shm)->SysGate.reverseOrder];
	return sort;
}

static int SortByCommand(const void *p1, const void *p2, void *arg)
{
	TASK_MCB *task1 = (TASK_MCB*) p1, *task2 = (TASK_MCB*) p2;
	REF *Ref = (REF*) arg;

	int sort = strncmp(task1->comm, task2->comm, TASK_COMM_LEN);
	sort *= reverseSign[Ref->RO(Shm)->SysGate.reverseOrder];
	return sort;
}

typedef int (*SORTBYFUNC)(const void *, const void *, void *);

static SORTBYFUNC SortByFunc[SORTBYCOUNT] = {
	SortByState,
	SortByRuntime,
	SortByUsertime,
	SortBySystime,
	SortByPID,
	SortByCommand
};

static int SortByTracker(const void *p1, const void *p2, void *arg)
{
	TASK_MCB *task1 = (TASK_MCB*) p1, *task2 = (TASK_MCB*) p2;
	REF *Ref = (REF*) arg;

	int sort = (task1->pid == Ref->RO(Shm)->SysGate.trackTask) ?
		-1 : (task2->pid == Ref->RO(Shm)->SysGate.trackTask) ?
		+1 : SortByFunc[Ref->RO(Shm)->SysGate.sortByField](p1, p2, Ref);
	return sort;
}

void SysGate_Update(REF *Ref)
{
	struct sysinfo info;
	RO(SHM_STRUCT) *RO(Shm) = Ref->RO(Shm);
	RO(SYSGATE) *SysGate = Ref->RO(SysGate);
	RO(PROC) *RO(Proc) = Ref->RO(Proc);

	RO(Shm)->SysGate.taskCount = SysGate->taskCount;

	memcpy( RO(Shm)->SysGate.taskList, SysGate->taskList,
		(size_t) RO(Shm)->SysGate.taskCount * sizeof(TASK_MCB));

	qsort_r(RO(Shm)->SysGate.taskList,
		(size_t) RO(Shm)->SysGate.taskCount, sizeof(TASK_MCB),
		RO(Shm)->SysGate.trackTask ?
			  SortByTracker
			: SortByFunc[RO(Shm)->SysGate.sortByField], Ref);

    if (sysinfo(&info) == 0) {
	RO(Shm)->SysGate.memInfo.totalram  = info.totalram	>> 10;
	RO(Shm)->SysGate.memInfo.sharedram = info.sharedram	>> 10;
	RO(Shm)->SysGate.memInfo.freeram   = info.freeram	>> 10;
	RO(Shm)->SysGate.memInfo.bufferram = info.bufferram	>> 10;
	RO(Shm)->SysGate.memInfo.totalhigh = info.totalhigh	>> 10;
	RO(Shm)->SysGate.memInfo.freehigh  = info.freehigh	>> 10;
	RO(Shm)->SysGate.procCount = info.procs;
    }
	RO(Shm)->SysGate.OS.IdleDriver.stateLimit =
					RO(Proc)->OS.IdleDriver.stateLimit;
}

void Package_Update(	RO(SHM_STRUCT) *RO(Shm),
			RO(PROC) *RO(Proc), RW(PROC) *RW(Proc) )
{	/*	Copy the operational settings.				*/
	RO(Shm)->Registration.AutoClock = RO(Proc)->Registration.AutoClock;
	RO(Shm)->Registration.Experimental= RO(Proc)->Registration.Experimental;
	RO(Shm)->Registration.HotPlug = RO(Proc)->Registration.HotPlug;
	RO(Shm)->Registration.PCI = RO(Proc)->Registration.PCI;
	RO(Shm)->Registration.HSMP= RO(Proc)->Features.HSMP_Enable;
	BITSTOR(LOCKLESS,RO(Shm)->Registration.NMI, RO(Proc)->Registration.NMI);
	RO(Shm)->Registration.Driver = RO(Proc)->Registration.Driver;
	/*	Copy the timer interval delay.				*/
	RO(Shm)->Sleep.Interval = RO(Proc)->SleepInterval;
	/*	Compute the polling wait time based on the timer interval. */
	RO(Shm)->Sleep.pollingWait=TIMESPEC((RO(Shm)->Sleep.Interval * 1000000L)
					/ WAKEUP_RATIO);
	/*	Copy the SysGate tick steps.				*/
	RO(Shm)->SysGate.tickReset = RO(Proc)->tickReset;
	RO(Shm)->SysGate.tickStep  = RO(Proc)->tickStep;

	Architecture(RO(Shm), RO(Proc));

	PerformanceMonitoring(RO(Shm), RO(Proc));

	HyperThreading(RO(Shm), RO(Proc));

	PowerInterface(RO(Shm), RO(Proc));

	ThermalPoint(RO(Shm), RO(Proc));

	Mitigation_1st_Stage(RO(Shm), RO(Proc), RW(Proc));
	/*	Aggregate OS idle driver data and Clock Source		*/
	SysGate_OS_Driver(RO(Shm), RO(Proc));
	ClockSource_Update(RO(Shm));
}

void PerCore_Update(	RO(SHM_STRUCT) *RO(Shm), RO(PROC) *RO(Proc),
			RO(CORE) **RO(Core), unsigned int cpu )
{
	if (BITVAL(RO(Core, AT(cpu))->OffLine, HW)) {
		BITSET(LOCKLESS, RO(Shm)->Cpu[cpu].OffLine, HW);
	} else {
		BITCLR(LOCKLESS, RO(Shm)->Cpu[cpu].OffLine, HW);
	}
	/*	Initialize all clock ratios.				*/
	memcpy( RO(Shm)->Cpu[cpu].Boost, RO(Core, AT(cpu))->Boost,
		(BOOST(SIZE)) * sizeof(unsigned int) );

	RO(Shm)->Cpu[cpu].Query.Microcode = RO(Core, AT(cpu))->Query.Microcode;

	Topology(RO(Shm), RO(Proc), RO(Core), cpu);

	CStates(RO(Shm), RO(Core), cpu);

	PowerThermal(RO(Shm), RO(Proc), RO(Core), cpu);

	SystemRegisters(RO(Shm), RO(Core), cpu);

	CPUID_Dump(RO(Shm), RO(Core), cpu);
}

#define SysOnce(drv)	ioctl(drv, COREFREQ_IOCTL_SYSONCE)

int SysGate_OnDemand(REF *Ref, int operation)
{
	int rc = -1;
	const size_t allocPages = Ref->RO(Proc)->Gate.ReqMem.Size;

	if (operation == 0) {
	    if (Ref->RO(SysGate) != NULL) {
		if ((rc = munmap(Ref->RO(SysGate), allocPages)) == 0) {
			Ref->RO(SysGate) = NULL;
		}
	    } else {
		rc = -1;
	    }
	} else {
	    if (Ref->RO(SysGate) == NULL) {
		const off_t vm_pgoff = ID_RO_VMA_GATE * PAGE_SIZE;
		RO(SYSGATE) *MapGate = mmap(NULL, allocPages,
						PROT_READ,
						MAP_SHARED,
						Ref->fd->drv, vm_pgoff);
		if (MapGate != MAP_FAILED) {
			Ref->RO(SysGate) = MapGate;
			rc = 0;
		}
	    } else {
		rc = 0;
	    }
	}
	return rc;
}

void SysGate_Toggle(REF *Ref, unsigned int state)
{
    if (state == 0) {
	if (BITWISEAND(LOCKLESS, Ref->RO(Shm)->SysGate.Operation, 0x1)) {
		/*		Stop SysGate 				*/
		BITCLR(LOCKLESS, Ref->RO(Shm)->SysGate.Operation, 0);
		/*		Notify					*/
		BITWISESET(LOCKLESS, PendingSync, BIT_MASK_NTFY);
	}
    } else {
	if (!BITWISEAND(LOCKLESS, Ref->RO(Shm)->SysGate.Operation, 0x1)) {
	    if (SysGate_OnDemand(Ref, 1) == 0) {
		/*		Start SysGate				*/
		BITSET(LOCKLESS, Ref->RO(Shm)->SysGate.Operation, 0);
		/*		Notify					*/
		BITWISESET(LOCKLESS, PendingSync,BIT_MASK_NTFY);
	    }
	}
    }
    if (BITWISEAND(LOCKLESS, Ref->RO(Shm)->SysGate.Operation, 0x1))
	if (SysOnce(Ref->fd->drv) == RC_OK_SYSGATE) {
		/*		Copy system information.		*/
		SysGate_Kernel(Ref);
	}
}

void Main_Ring_Handler(REF *Ref, unsigned int rid)
{
    if (!RING_NULL(Ref->RW(Shm)->Ring[rid]))
    {
	RING_CTRL ctrl __attribute__ ((aligned(16)));
	RING_READ(Ref->RW(Shm)->Ring[rid], ctrl);
	int rc = -EPERM, drc = -EPERM;

	if (	(ctrl.cmd >= COREFREQ_IOCTL_SYSUPDT)
	&&	(ctrl.cmd <= COREFREQ_IOCTL_CLEAR_EVENTS) )
	{
		rc = ioctl(Ref->fd->drv, ctrl.cmd, ctrl.arg);
		drc = errno;
	}
	if (Quiet & 0x100) {
		printf("\tRING[%u](%x,%x)(%llx)>(%d,%d)\n",
			rid, ctrl.cmd, ctrl.sub, ctrl.arg, rc, drc);
	}
	switch (rc) {
	case -EPERM:
	    {
		RING_CTRL error __attribute__ ((aligned(16))) = {
			.arg = ctrl.arg,
			.cmd = ctrl.cmd,
			.drc = (unsigned int) drc,
			.tds = ELAPSED(Ref->RO(Shm)->StartedAt)
		};
		RING_WRITE_1xPARAM(	error.sub,
					Ref->RW(Shm)->Error,
					error.cmd,
					error.arg );
	    }
		break;
	case RC_OK_SYSGATE:
		SysGate_OS_Driver(Ref->RO(Shm), Ref->RO(Proc));
		fallthrough;
	case RC_SUCCESS: /* Platform changed -> pending notification.	*/
		BITWISESET(LOCKLESS, PendingSync, BIT_MASK_NTFY);
		break;
	case RC_OK_COMPUTE: /* Compute claimed -> pending notification. */
		BITWISESET(LOCKLESS, PendingSync, BIT_MASK_COMP);
		break;
	}
    }
}

void Child_Ring_Handler(REF *Ref, unsigned int rid)
{
  if (!RING_NULL(Ref->RW(Shm)->Ring[rid]))
  {
	RING_CTRL ctrl __attribute__ ((aligned(16)));
	RING_READ(Ref->RW(Shm)->Ring[rid], ctrl);

   switch (ctrl.cmd) {
   case COREFREQ_KERNEL_MISC:
     switch (ctrl.dl.hi) {
     case MACHINE_CLOCK_SOURCE:
	if (ClockSource_Submit(Ref->RO(Shm), (unsigned char) ctrl.dl.lo) == 0) {
		ClockSource_Update(Ref->RO(Shm));
	}
	break;
     }
     break;
   case COREFREQ_SESSION_APP:
	switch (ctrl.sub) {
	case SESSION_CLI:
		Ref->RO(Shm)->App.Cli = (pid_t) ctrl.arg;
		break;
	case SESSION_GUI:
		Ref->RO(Shm)->App.GUI = (pid_t) ctrl.arg;
		break;
	}
	break;
   case COREFREQ_TASK_MONITORING:
	switch (ctrl.sub) {
	case TASK_TRACKING:
		Ref->RO(Shm)->SysGate.trackTask = (pid_t) ctrl.arg;
		break;
	case TASK_SORTING:
	    {
		enum SORTBYFIELD sortByField = (enum SORTBYFIELD) ctrl.dl.lo;
		Ref->RO(Shm)->SysGate.sortByField = sortByField % SORTBYCOUNT;
	    }
		break;
	case TASK_INVERSING:
	    {
		const int reverseOrder = !!!Ref->RO(Shm)->SysGate.reverseOrder;
		Ref->RO(Shm)->SysGate.reverseOrder = reverseOrder;
	    }
		break;
	}
	BITWISESET(LOCKLESS, Ref->RW(Shm)->Proc.Sync, BIT_MASK_NTFY);
	break;
   case COREFREQ_TOGGLE_SYSGATE:
	switch (ctrl.arg) {
	case COREFREQ_TOGGLE_OFF:
	case COREFREQ_TOGGLE_ON:
		SysGate_Toggle(Ref, ctrl.arg);
		BITWISESET(LOCKLESS, Ref->RW(Shm)->Proc.Sync, BIT_MASK_NTFY);
		break;
	}
	break;
   case COREFREQ_ORDER_MACHINE:
	switch (ctrl.arg) {
	case COREFREQ_TOGGLE_OFF:
	SCHEDULER_STOP:
	    if (BITVAL(Ref->RW(Shm)->Proc.Sync, BURN))
	    {
		BITCLR(BUS_LOCK, Ref->RW(Shm)->Proc.Sync, BURN);

		while (BITWISEAND_CC(BUS_LOCK, roomCore, roomSeed))
		{
			if (BITVAL(Shutdown, SYNC)) {	/* SpinLock */
				break;
			}
		}
		BITSTOR_CC(BUS_LOCK, Ref->RO(Shm)->roomSched, roomClear);

		Ref->Slice.Func = Slice_NOP;
		Ref->Slice.arg = 0;
		Ref->Slice.pattern = RESET_CSP;
		/*	Notify the Slice module has stopped		*/
		BITWISESET(LOCKLESS, Ref->RW(Shm)->Proc.Sync, BIT_MASK_NTFY);
	    }
	    break;
	}
	break;
   default:
    {
	RING_SLICE *porder = order_list;

     while (porder->func != NULL)
     {
      if ((porder->ctrl.cmd == ctrl.cmd) &&  (porder->ctrl.sub == ctrl.sub))
      {
       if ( !BITVAL(Ref->RW(Shm)->Proc.Sync, BURN)
	|| ((Ref->Slice.Func == Slice_Turbo) && (Ref->Slice.pattern == USR_CPU)
		&& (ctrl.cmd == COREFREQ_ORDER_TURBO) && (ctrl.sub == USR_CPU)))
       {
	if (ctrl.sub == USR_CPU) {
	    if (BITVAL_CC(Ref->RO(Shm)->roomSched, ctrl.dl.lo))
	    {
		BITCLR_CC(LOCKLESS, Ref->RO(Shm)->roomSched, ctrl.dl.lo);

		if (!BITWISEAND_CC(BUS_LOCK, Ref->RO(Shm)->roomSched, roomSeed))
		{
			goto SCHEDULER_STOP;
		}
	    } else {
		BITSET_CC(LOCKLESS, Ref->RO(Shm)->roomSched, ctrl.dl.lo);

		goto SCHEDULER_START;
	    }
	} else {
		SliceScheduling(Ref->RO(Shm), ctrl.dl.lo, porder->pattern);

	SCHEDULER_START:
		Ref->Slice.Func = porder->func;
		Ref->Slice.arg  = porder->ctrl.dl.lo;
		Ref->Slice.pattern = porder->pattern;

		BITSET(BUS_LOCK, Ref->RW(Shm)->Proc.Sync, BURN);
	}
	/*	Notify the Slice module is starting up			*/
	BITWISESET(LOCKLESS, Ref->RW(Shm)->Proc.Sync, BIT_MASK_NTFY);
       }
       break;
      }
	porder++;
     }
    }
    break;
   }
    if (Quiet & 0x100) {
	printf("\tRING[%u](%x,%x)(%hx:%hx,%hx:%hx)\n",
		rid, ctrl.cmd, ctrl.sub,
		ctrl.dh.hi, ctrl.dh.lo, ctrl.dl.hi, ctrl.dl.lo);
    }
  }
}

int ServerFollowService(SERVICE_PROC *pPeer,
			SERVICE_PROC *pMain,
			pthread_t tid)
{
	if (pPeer->Proc != pMain->Proc) {
		pPeer->Proc = pMain->Proc;

		cpu_set_t cpuset;
		CPU_ZERO(&cpuset);
		CPU_SET(pPeer->Core, &cpuset);
		if (pPeer->Thread != -1) {
			const signed int cpu = pPeer->Thread;
			CPU_SET(cpu , &cpuset);
		}
		return pthread_setaffinity_np(tid, sizeof(cpu_set_t), &cpuset);
	}
	return -1;
}

static void *Emergency_Handler(void *pRef)
{
	REF *Ref = (REF *) pRef;
	unsigned int rid = (Ref->CPID == 0);
	SERVICE_PROC localService = RESET_SERVICE;
	int caught = 0, leave = 0;
	char handlerName[TASK_COMM_LEN] = {
		'c','o','r','e','f','r','e','q','d','-','r','i','n','g','0',0
	};
	handlerName[14] += (char) rid;

	pthread_t tid = pthread_self();

    if(ServerFollowService(&localService, &Ref->RO(Shm)->Proc.Service,tid) == 0)
    {
	pthread_setname_np(tid, handlerName);
    }
    while (!leave) {
	caught=sigtimedwait(&Ref->Signal,NULL,&Ref->RO(Shm)->Sleep.ringWaiting);
	if (caught != -1) {
		switch (caught) {
		case SIGUSR2:
			if (Ref->CPID) { /* Stop  SysGate */
				SysGate_Toggle(Ref, 0);
			}
			break;
		case SIGUSR1:
			if (Ref->CPID) { /* Start SysGate */
				SysGate_Toggle(Ref, 1);
			}
			break;
		case SIGCHLD: /* Exit Ring Thread  */
			leave = 0x1;
			fallthrough;
		case SIGSTKFLT:
		case SIGXFSZ:
		case SIGXCPU:
		case SIGSEGV:
		case SIGTERM:
		case SIGQUIT:
		case SIGALRM:
		case SIGABRT:
		case SIGPIPE:
		case SIGTRAP:
		case SIGSYS:
		case SIGFPE:
		case SIGBUS:
		case SIGILL:
		case SIGINT:	/* [CTRL] + [C] */
			BITSET(LOCKLESS, Shutdown, SYNC);
			break;
		case SIGVTALRM:
		case SIGWINCH:
		case SIGTTOU:
		case SIGTTIN:
		case SIGTSTP:
		case SIGPROF:
		case SIGHUP:
		case SIGPWR:
		case SIGIO:
		default:	/* RTMIN ... RTMAX */
			break;
		}
	} else if (errno == EAGAIN) {
		if (Ref->CPID) {
			Main_Ring_Handler(Ref, rid);
		} else {
			Child_Ring_Handler(Ref, rid);
		}
	}
	ServerFollowService(&localService, &Ref->RO(Shm)->Proc.Service, tid);
    }
	return NULL;
}

void Emergency_Command(REF *Ref, unsigned int cmd)
{
	switch (cmd) {
	case 0:
		if (Ref->Started) {
			if (!pthread_kill(Ref->KID, SIGCHLD)) {
				if (!pthread_join(Ref->KID, NULL)) {
					Ref->Started = 0;
				}
			}
		}
		break;
	case 1: {
		const int ignored[] = {
			SIGIO, SIGPROF, SIGPWR, SIGHUP, SIGTSTP,
			SIGTTIN, SIGTTOU, SIGVTALRM, SIGWINCH
		}, handled[] = {
			SIGUSR1, SIGUSR2, SIGCHLD, SIGINT, SIGILL, SIGBUS,
			SIGFPE, SIGSYS, SIGTRAP, SIGPIPE, SIGABRT, SIGALRM,
			SIGQUIT, SIGTERM, SIGSEGV, SIGXCPU, SIGXFSZ, SIGSTKFLT
		};
		/* SIGKILL,SIGCONT,SIGSTOP,SIGURG:	Reserved	*/
		const ssize_t	ignoredCount = sizeof(ignored) / sizeof(int),
				handledCount = sizeof(handled) / sizeof(int);
		int signo;

		sigemptyset(&Ref->Signal);
		for (signo = SIGRTMIN; signo <= SIGRTMAX; signo++) {
			sigaddset(&Ref->Signal, signo);
		}
		for (signo = 0; signo < ignoredCount; signo++) {
			sigaddset(&Ref->Signal, ignored[signo]);
		}
		for (signo = 0; signo < handledCount; signo++) {
			sigaddset(&Ref->Signal, handled[signo]);
		}
		if (!pthread_sigmask(SIG_BLOCK, &Ref->Signal, NULL))
		{
		    if(!pthread_create(&Ref->KID, NULL, Emergency_Handler, Ref))
		    {
			Ref->Started = 1;
		    }
		}
	    }
		break;
	}
}

static void Pkg_ComputeThermal_None(	struct PKG_FLIP_FLOP *PFlip,
					struct FLIP_FLOP *SProc )
{
	UNUSED(PFlip);
	UNUSED(SProc);
}

static void Pkg_ComputeThermal_Intel(	struct PKG_FLIP_FLOP *PFlip,
					struct FLIP_FLOP *SProc )
{
	COMPUTE_THERMAL(INTEL,
		PFlip->Thermal.Temp,
		SProc->Thermal.Param,
		PFlip->Thermal.Sensor);
}

static void Pkg_ComputeThermal_AMD(	struct PKG_FLIP_FLOP *PFlip,
					struct FLIP_FLOP *SProc )
{
	COMPUTE_THERMAL(AMD,
		PFlip->Thermal.Temp,
		SProc->Thermal.Param,
		PFlip->Thermal.Sensor);
}

static void Pkg_ComputeThermal_AMD_0Fh( struct PKG_FLIP_FLOP *PFlip,
					struct FLIP_FLOP *SProc )
{
	COMPUTE_THERMAL(AMD_0Fh,
		PFlip->Thermal.Temp,
		SProc->Thermal.Param,
		PFlip->Thermal.Sensor);
}

static void Pkg_ComputeThermal_AMD_15h( struct PKG_FLIP_FLOP *PFlip,
					struct FLIP_FLOP *SProc )
{
	COMPUTE_THERMAL(AMD_15h,
		PFlip->Thermal.Temp,
		SProc->Thermal.Param,
		PFlip->Thermal.Sensor);
}

static void Pkg_ComputeThermal_AMD_17h( struct PKG_FLIP_FLOP *PFlip,
					struct FLIP_FLOP *SProc )
{
	COMPUTE_THERMAL(AMD_17h,
		PFlip->Thermal.Temp,
		SProc->Thermal.Param,
		PFlip->Thermal.Sensor);
}

static void Pkg_ComputeVoltage_None(struct PKG_FLIP_FLOP *PFlip)
{
	UNUSED(PFlip);
}

#define Pkg_ComputeVoltage_Intel	Pkg_ComputeVoltage_None

#define Pkg_ComputeVoltage_Intel_Core2	Pkg_ComputeVoltage_None

static void Pkg_ComputeVoltage_Intel_SoC(struct PKG_FLIP_FLOP *PFlip)
{
	COMPUTE_VOLTAGE(INTEL_SOC,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);
}

static void Pkg_ComputeVoltage_Intel_SNB(struct PKG_FLIP_FLOP *PFlip)
{	/* Intel 2nd Generation Datasheet Vol-1 Chap. 7.4 Table 7-1	*/
	COMPUTE_VOLTAGE(INTEL_SNB,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);
}

static void Pkg_ComputeVoltage_Intel_SKL_X(struct PKG_FLIP_FLOP *PFlip)
{
	COMPUTE_VOLTAGE(INTEL_SKL_X,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);
}

static void Pkg_ComputeVoltage_Intel_SAV(struct PKG_FLIP_FLOP *PFlip)
{
	COMPUTE_VOLTAGE(INTEL_SNB,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);

	COMPUTE_VOLTAGE(INTEL_SAV,
			PFlip->Voltage.SOC,
			PFlip->Voltage.VID.SOC);
}

#define Pkg_ComputeVoltage_AMD		Pkg_ComputeVoltage_None

#define Pkg_ComputeVoltage_AMD_0Fh	Pkg_ComputeVoltage_None

static void Pkg_ComputeVoltage_AMD_15h(struct PKG_FLIP_FLOP *PFlip)
{
	COMPUTE_VOLTAGE(AMD_15h,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);
}

static void Pkg_ComputeVoltage_AMD_17h(struct PKG_FLIP_FLOP *PFlip)
{
	COMPUTE_VOLTAGE(AMD_17h,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);

	COMPUTE_VOLTAGE(AMD_17h,
			PFlip->Voltage.SOC,
			PFlip->Voltage.VID.SOC);
}

static void Pkg_ComputeVoltage_AMD_RMB(struct PKG_FLIP_FLOP *PFlip)
{
	COMPUTE_VOLTAGE(AMD_RMB,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);

	COMPUTE_VOLTAGE(AMD_RMB,
			PFlip->Voltage.SOC,
			PFlip->Voltage.VID.SOC);
}

static void Pkg_ComputeVoltage_ZEN3_VCO(struct PKG_FLIP_FLOP *PFlip)
{
	COMPUTE_VOLTAGE(AMD_VCO,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);

	COMPUTE_VOLTAGE(AMD_17h,
			PFlip->Voltage.SOC,
			PFlip->Voltage.VID.SOC);
}

static void Pkg_ComputeVoltage_ZEN4_VCO(struct PKG_FLIP_FLOP *PFlip)
{
	COMPUTE_VOLTAGE(AMD_VCO,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);

	COMPUTE_VOLTAGE(AMD_RMB,
			PFlip->Voltage.SOC,
			PFlip->Voltage.VID.SOC);
}

static void Pkg_ComputeVoltage_ZEN5_VCO(struct PKG_FLIP_FLOP *PFlip)
{
	COMPUTE_VOLTAGE(AMD_VCO,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);

/*TODO(Unknown SOC voltage register)
	COMPUTE_VOLTAGE(AMD_VCO,
			PFlip->Voltage.SOC,
			PFlip->Voltage.VID.SOC);			*/
}

static void Pkg_ComputeVoltage_Winbond_IO(struct PKG_FLIP_FLOP *PFlip)
{	/* Winbond W83627EHF/EF, W83627EHG,EG				*/
	COMPUTE_VOLTAGE(WINBOND_IO,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);
}

static void Pkg_ComputeVoltage_ITE_Tech_IO(struct PKG_FLIP_FLOP *PFlip)
{
	COMPUTE_VOLTAGE(ITETECH_IO,
			PFlip->Voltage.CPU,
			PFlip->Voltage.VID.CPU);
}

static void Pkg_ComputePower_None(RW(PROC) *RW(Proc), struct FLIP_FLOP *CFlop)
{
	UNUSED(RW(Proc));
	UNUSED(CFlop);
}

#define Pkg_ComputePower_Intel		Pkg_ComputePower_None

#define Pkg_ComputePower_Intel_Atom	Pkg_ComputePower_None

#define Pkg_ComputePower_AMD		Pkg_ComputePower_None

static void Pkg_ComputePower_AMD_17h(	RW(PROC) *RW(Proc),
					struct FLIP_FLOP *CFlop )
{
    RW(Proc)->Delta.Power.ACCU[PWR_DOMAIN(CORES)] += CFlop->Delta.Power.ACCU;
}

static void Pkg_ResetPower_None(PROC_RW *Proc)
{
	UNUSED(Proc);
}

#define Pkg_ResetPower_Intel		Pkg_ResetPower_None

#define Pkg_ResetPower_Intel_Atom	Pkg_ResetPower_None

#define Pkg_ResetPower_AMD		Pkg_ResetPower_None

static void Pkg_ResetPower_AMD_17h(RW(PROC) *RW(Proc))
{
	RW(Proc)->Delta.Power.ACCU[PWR_DOMAIN(CORES)] = 0;
}

void Pkg_ResetSensorLimits(PROC_STRUCT *Pkg)
{
	enum PWR_DOMAIN pw;
      for (pw = PWR_DOMAIN(PKG); pw < PWR_DOMAIN(SIZE); pw++)
      {
	RESET_SENSOR_LIMIT(ENERGY, LOWEST , Pkg->State.Energy[pw].Limit);
	RESET_SENSOR_LIMIT(ENERGY, HIGHEST, Pkg->State.Energy[pw].Limit );
	RESET_SENSOR_LIMIT(POWER , LOWEST , Pkg->State.Power[pw].Limit );
	RESET_SENSOR_LIMIT(POWER , HIGHEST, Pkg->State.Power[pw].Limit );
      }
	RESET_SENSOR_LIMIT(VOLTAGE, LOWEST, Pkg->State.Voltage.Limit );
	RESET_SENSOR_LIMIT(VOLTAGE, HIGHEST,Pkg->State.Voltage.Limit );
}

REASON_CODE Core_Manager(REF *Ref)
{
	RO(SHM_STRUCT)		*RO(Shm) = Ref->RO(Shm);
	RW(SHM_STRUCT)		*RW(Shm) = Ref->RW(Shm);
	RO(PROC)		*RO(Proc) = Ref->RO(Proc);
	RW(PROC)		*RW(Proc) = Ref->RW(Proc);
	RO(CORE)		**RO(Core) = Ref->RO(Core);
	struct PKG_FLIP_FLOP	*PFlip;
	struct FLIP_FLOP	*SProc;
	SERVICE_PROC		localService = RESET_SERVICE;
	struct {
		double		RelFreq,
				AbsFreq;
	} prevTop;
	REASON_INIT		(reason);
	unsigned int		cpu = 0;

	pthread_t tid = pthread_self();
    #ifdef __GLIBC__
	RO(Shm)->App.Svr = tid;
    #else
	RO(Shm)->App.Svr = getpid();
    #endif

  if (ServerFollowService(&localService, &RO(Shm)->Proc.Service, tid) == 0) {
	pthread_setname_np(tid, "corefreqd-pmgr");
  }
	ARG *Arg = calloc(RO(Shm)->Proc.CPU.Count, sizeof(ARG));
  if (Arg != NULL)
  {
	void (*Pkg_ComputeThermalFormula)(	struct PKG_FLIP_FLOP*,
						struct FLIP_FLOP* );

	void (*Pkg_ComputeVoltageFormula)( struct PKG_FLIP_FLOP* );

	void (*Pkg_ComputePowerFormula)( PROC_RW*, struct FLIP_FLOP* );

	void (*Pkg_ResetPowerFormula)(PROC_RW*);

	switch (KIND_OF_FORMULA(RO(Shm)->Proc.thermalFormula)) {
	case THERMAL_KIND_INTEL:
		Pkg_ComputeThermalFormula = Pkg_ComputeThermal_Intel;
		break;
	case THERMAL_KIND_AMD:
		Pkg_ComputeThermalFormula = Pkg_ComputeThermal_AMD;
		break;
	case THERMAL_KIND_AMD_0Fh:
		Pkg_ComputeThermalFormula = Pkg_ComputeThermal_AMD_0Fh;
		break;
	case THERMAL_KIND_AMD_15h:
		Pkg_ComputeThermalFormula = Pkg_ComputeThermal_AMD_15h;
		break;
	case THERMAL_KIND_AMD_17h:
		Pkg_ComputeThermalFormula = Pkg_ComputeThermal_AMD_17h;
		break;
	case THERMAL_KIND_NONE:
	default:
		Pkg_ComputeThermalFormula = Pkg_ComputeThermal_None;
	}

	switch (KIND_OF_FORMULA(RO(Shm)->Proc.voltageFormula)) {
	case VOLTAGE_KIND_INTEL:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_Intel;
		break;
	case VOLTAGE_KIND_INTEL_CORE2:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_Intel_Core2;
		break;
	case VOLTAGE_KIND_INTEL_SOC:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_Intel_SoC;
		break;
	case VOLTAGE_KIND_INTEL_SNB:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_Intel_SNB;
		break;
	case VOLTAGE_KIND_INTEL_SKL_X:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_Intel_SKL_X;
		break;
	case VOLTAGE_KIND_INTEL_SAV:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_Intel_SAV;
		break;
	case VOLTAGE_KIND_AMD:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_AMD;
		break;
	case VOLTAGE_KIND_AMD_0Fh:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_AMD_0Fh;
		break;
	case VOLTAGE_KIND_AMD_15h:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_AMD_15h;
		break;
	case VOLTAGE_KIND_AMD_17h:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_AMD_17h;
		break;
	case VOLTAGE_KIND_AMD_RMB:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_AMD_RMB;
		break;
	case VOLTAGE_KIND_ZEN3_VCO:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_ZEN3_VCO;
		break;
	case VOLTAGE_KIND_ZEN4_VCO:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_ZEN4_VCO;
		break;
	case VOLTAGE_KIND_ZEN5_VCO:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_ZEN5_VCO;
		break;
	case VOLTAGE_KIND_WINBOND_IO:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_Winbond_IO;
		break;
	case VOLTAGE_KIND_ITETECH_IO:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_ITE_Tech_IO;
		break;
	case VOLTAGE_KIND_NONE:
	default:
		Pkg_ComputeVoltageFormula = Pkg_ComputeVoltage_None;
		break;
	}

	switch (KIND_OF_FORMULA(RO(Shm)->Proc.powerFormula)) {
	case POWER_KIND_INTEL:
		Pkg_ComputePowerFormula = Pkg_ComputePower_Intel;
		Pkg_ResetPowerFormula	= Pkg_ResetPower_Intel;
		break;
	case POWER_KIND_INTEL_ATOM:
		Pkg_ComputePowerFormula = Pkg_ComputePower_Intel_Atom;
		Pkg_ResetPowerFormula	= Pkg_ResetPower_Intel_Atom;
		break;
	case POWER_KIND_AMD:
		Pkg_ComputePowerFormula = Pkg_ComputePower_AMD;
		Pkg_ResetPowerFormula	= Pkg_ResetPower_AMD;
		break;
	case POWER_KIND_AMD_17h:
		Pkg_ComputePowerFormula = Pkg_ComputePower_AMD_17h;
		Pkg_ResetPowerFormula	= Pkg_ResetPower_AMD_17h;
		break;
	case POWER_KIND_NONE:
	default:
		Pkg_ComputePowerFormula = Pkg_ComputePower_None;
		Pkg_ResetPowerFormula	= Pkg_ResetPower_None;
		break;
	}

    #if defined(LEGACY) && LEGACY > 0
	#define ROOM_CLEAR(_room_)					\
		BITZERO(BUS_LOCK, _room_##Core[CORE_WORD_TOP(CORE_COUNT)])
    #else
	#define ROOM_CLEAR(_room_)					\
		BITCMP_CC(BUS_LOCK, _room_##Core, _room_##Clear)
    #endif

    #define ROOM_RESET(_room_)						\
	BITSTOR_CC(BUS_LOCK, _room_##Core, _room_##Seed)

    #define ROOM_READY(_room_)						\
	BITCMP_CC(BUS_LOCK, _room_##Ready, _room_##Seed)

    #define CONDITION_RDTSCP()						\
	(  (RO(Proc)->Features.AdvPower.EDX.Inv_TSC == 1)		\
	|| (RO(Proc)->Features.ExtInfo.EDX.RDTSCP == 1) )

    #define CONDITION_RDPMC()						\
	(  (RO(Proc)->Features.Info.Vendor.CRC == CRC_INTEL)		\
	&& (RO(Proc)->Features.PerfMon.EAX.Version >= 1)		\
	&& (BITVAL(RO(Core, AT(RO(Proc)->Service.Core))->SystemRegister.CR4, \
							CR4_PCE) == 1) )

	UBENCH_SETUP(CONDITION_RDTSCP(), CONDITION_RDPMC());
	Print_uBenchmark((Quiet & 0x100));

   while (!BITVAL(Shutdown, SYNC))
   {	/*	Loop while all the cpu room bits are not cleared.	*/
	while (!BITVAL(Shutdown, SYNC) && !ROOM_CLEAR(room))
	{
		nanosleep(&RO(Shm)->Sleep.pollingWait, NULL);
	}

	UBENCH_RDCOUNTER(1);

	RO(Shm)->Proc.Toggle = !RO(Shm)->Proc.Toggle;
	PFlip = &RO(Shm)->Proc.FlipFlop[RO(Shm)->Proc.Toggle];

	SProc = &RO(Shm)->Cpu[RO(Shm)->Proc.Service.Core].FlipFlop[
				!RO(Shm)->Cpu[RO(Shm)->Proc.Service.Core].Toggle
		];

	PFlip->Thermal.Temp = 0;
	/*	Reset the averages & the max frequency			*/
	RO(Shm)->Proc.Avg.Turbo = 0;
	RO(Shm)->Proc.Avg.C0    = 0;
	RO(Shm)->Proc.Avg.C3    = 0;
	RO(Shm)->Proc.Avg.C6    = 0;
	RO(Shm)->Proc.Avg.C7    = 0;
	RO(Shm)->Proc.Avg.C1    = 0;

	prevTop.RelFreq = 0.0;
	prevTop.AbsFreq = 0.0;

	Pkg_ResetPowerFormula(RW(Proc));
	/*	Reset with Package Events				*/
	memcpy( RO(Shm)->ProcessorEvents, PFlip->Thermal.Events,
		sizeof(RO(Shm)->ProcessorEvents) );

    for (cpu=0; !BITVAL(Shutdown, SYNC)&&(cpu < RO(Shm)->Proc.CPU.Count);cpu++)
    {
      if (BITVAL(RO(Core, AT(cpu))->OffLine, OS) == 1)
      {
	if (Arg[cpu].TID)
	{	/*	Remove this cpu.				*/
	  if (pthread_join(Arg[cpu].TID, NULL) == 0)
	  {
		BITCLR_CC(BUS_LOCK, roomReady, cpu);
		Arg[cpu].TID = 0;

		PerCore_Update(RO(Shm), RO(Proc), RO(Core), cpu);

	    if (ServerFollowService(	&localService,
					&RO(Shm)->Proc.Service,
					tid ) == 0)
	    {
		SProc = &RO(Shm)->Cpu[RO(Shm)->Proc.Service.Core].FlipFlop[
				!RO(Shm)->Cpu[RO(Shm)->Proc.Service.Core].Toggle
			];
	    }
		/*	Raise these bits up to notify a platform change. */
		BITWISESET(LOCKLESS, PendingSync, BIT_MASK_NTFY);
	  }
	}
	BITSET(LOCKLESS, RO(Shm)->Cpu[cpu].OffLine, OS);
      } else {
	struct FLIP_FLOP *CFlop = &RO(Shm)->Cpu[cpu].FlipFlop[
					!RO(Shm)->Cpu[cpu].Toggle
				];
	if (!Arg[cpu].TID)
	{	/*	Add this cpu.					*/
		Arg[cpu].Ref  = Ref;
		Arg[cpu].Bind = cpu;
	  if (pthread_create( &Arg[cpu].TID,
				NULL,
				Core_Cycle,
				&Arg[cpu]) == 0)
	  {
		BITSET_CC(BUS_LOCK, roomReady, cpu);

		PerCore_Update(RO(Shm), RO(Proc), RO(Core), cpu);

	    if (ServerFollowService(&localService,
					&RO(Shm)->Proc.Service,
					tid) == 0)
	    {
		SProc = &RO(Shm)->Cpu[RO(Shm)->Proc.Service.Core].FlipFlop[
				!RO(Shm)->Cpu[RO(Shm)->Proc.Service.Core].Toggle
			];
	    }
	    if (Quiet & 0x100) {
		printf( "    CPU #%03u @ %.2f MHz\n", cpu,
		  ABS_FREQ_MHz(double , RO(Shm)->Cpu[cpu].Boost[BOOST(MAX)],
					RO(Core, AT(cpu))->Clock) );
	    }
		/*	Notify a CPU has been brought up		*/
		BITWISESET(LOCKLESS, PendingSync, BIT_MASK_NTFY);
	  }
	}
	BITCLR(LOCKLESS, RO(Shm)->Cpu[cpu].OffLine, OS);

	/*	Index CPU with the highest Rel. and Abs frequencies.	*/
	if (CFlop->Relative.Freq > prevTop.RelFreq) {
		prevTop.RelFreq = CFlop->Relative.Freq;
		RO(Shm)->Proc.Top.Rel = cpu;
	}
	if (CFlop->Absolute.Freq > prevTop.AbsFreq) {
		prevTop.AbsFreq = CFlop->Absolute.Freq;
		RO(Shm)->Proc.Top.Abs = cpu;
	}

	/*	Workaround to Package Thermal Management: the hottest Core */
	if (!RO(Shm)->Proc.Features.Power.EAX.PTM) {
		if (CFlop->Thermal.Temp > PFlip->Thermal.Temp)
			PFlip->Thermal.Temp = CFlop->Thermal.Temp;
	}

	/*	Workaround to RAPL Package counter: sum of all Cores	*/
	Pkg_ComputePowerFormula(RW(Proc), CFlop);

	/*	Sum counters.						*/
	RO(Shm)->Proc.Avg.Turbo += CFlop->State.Turbo;
	RO(Shm)->Proc.Avg.C0    += CFlop->State.C0;
	RO(Shm)->Proc.Avg.C3    += CFlop->State.C3;
	RO(Shm)->Proc.Avg.C6    += CFlop->State.C6;
	RO(Shm)->Proc.Avg.C7    += CFlop->State.C7;
	RO(Shm)->Proc.Avg.C1    += CFlop->State.C1;
	/*	Aggregate all Cores Events.				*/
	RO(Shm)->ProcessorEvents[eLOG] |= CFlop->Thermal.Events[eLOG];
	RO(Shm)->ProcessorEvents[eSTS] |= CFlop->Thermal.Events[eSTS];
      }
    }
    if (!BITVAL(Shutdown, SYNC) && ROOM_READY(room))
    {
	unsigned char fRESET = 0;
	/*	Compute the counters averages.				*/
	RO(Shm)->Proc.Avg.Turbo /= RO(Shm)->Proc.CPU.OnLine;
	RO(Shm)->Proc.Avg.C0    /= RO(Shm)->Proc.CPU.OnLine;
	RO(Shm)->Proc.Avg.C3    /= RO(Shm)->Proc.CPU.OnLine;
	RO(Shm)->Proc.Avg.C6    /= RO(Shm)->Proc.CPU.OnLine;
	RO(Shm)->Proc.Avg.C7    /= RO(Shm)->Proc.CPU.OnLine;
	RO(Shm)->Proc.Avg.C1    /= RO(Shm)->Proc.CPU.OnLine;
	/*	Package scope counters					*/
	PFlip->Delta.PCLK = RO(Proc)->Delta.PCLK;
	PFlip->Delta.PC02 = RO(Proc)->Delta.PC02;
	PFlip->Delta.PC03 = RO(Proc)->Delta.PC03;
	PFlip->Delta.PC04 = RO(Proc)->Delta.PC04;
	PFlip->Delta.PC06 = RO(Proc)->Delta.PC06;
	PFlip->Delta.PC07 = RO(Proc)->Delta.PC07;
	PFlip->Delta.PC08 = RO(Proc)->Delta.PC08;
	PFlip->Delta.PC09 = RO(Proc)->Delta.PC09;
	PFlip->Delta.PC10 = RO(Proc)->Delta.PC10;
	PFlip->Delta.MC6  = RO(Proc)->Delta.MC6;
	/*	Package C-state Residency counters			*/
	RO(Shm)->Proc.State.PC02= (double)PFlip->Delta.PC02
				/ (double)PFlip->Delta.PCLK;

	RO(Shm)->Proc.State.PC03= (double)PFlip->Delta.PC03
				/ (double)PFlip->Delta.PCLK;

	RO(Shm)->Proc.State.PC04= (double)PFlip->Delta.PC04
				/ (double)PFlip->Delta.PCLK;

	RO(Shm)->Proc.State.PC06= (double)PFlip->Delta.PC06
				/ (double)PFlip->Delta.PCLK;

	RO(Shm)->Proc.State.PC07= (double)PFlip->Delta.PC07
				/ (double)PFlip->Delta.PCLK;

	RO(Shm)->Proc.State.PC08= (double)PFlip->Delta.PC08
				/ (double)PFlip->Delta.PCLK;

	RO(Shm)->Proc.State.PC09= (double)PFlip->Delta.PC09
				/ (double)PFlip->Delta.PCLK;

	RO(Shm)->Proc.State.PC10= (double)PFlip->Delta.PC10
				/ (double)PFlip->Delta.PCLK;

	RO(Shm)->Proc.State.MC6 = (double)PFlip->Delta.MC6
				/ (double)PFlip->Delta.PCLK;
	/*	Uncore scope counters				*/
	PFlip->Uncore.FC0 = RO(Proc)->Delta.Uncore.FC0;
	/*	Power & Energy counters 				*/
	enum PWR_DOMAIN pw;
      for (pw = PWR_DOMAIN(PKG); pw < PWR_DOMAIN(SIZE); pw++)
      {
	PFlip->Delta.ACCU[pw] = RW(Proc)->Delta.Power.ACCU[pw];

	RO(Shm)->Proc.State.Energy[pw].Current = PFlip->Delta.ACCU[pw];
	RO(Shm)->Proc.State.Energy[pw].Current *= \
					RO(Shm)->Proc.Power.Unit.Joules;

	RO(Shm)->Proc.State.Power[pw].Current = \
				RO(Shm)->Proc.State.Energy[pw].Current;

	RO(Shm)->Proc.State.Power[pw].Current *= 1000.0;
	RO(Shm)->Proc.State.Power[pw].Current /= RO(Shm)->Sleep.Interval;

	/*	Processor scope: computes Min and Max energy consumed.	*/
	TEST_AND_SET_SENSOR(	ENERGY, LOWEST,
				RO(Shm)->Proc.State.Energy[pw].Current,
				RO(Shm)->Proc.State.Energy[pw].Limit );

	TEST_AND_SET_SENSOR(	ENERGY, HIGHEST,
				RO(Shm)->Proc.State.Energy[pw].Current,
				RO(Shm)->Proc.State.Energy[pw].Limit );
	/*	Processor scope: computes Min and Max power consumed. */
	TEST_AND_SET_SENSOR(	POWER, LOWEST,
				RO(Shm)->Proc.State.Power[pw].Current,
				RO(Shm)->Proc.State.Power[pw].Limit );

	TEST_AND_SET_SENSOR(	POWER, HIGHEST,
				RO(Shm)->Proc.State.Power[pw].Current,
				RO(Shm)->Proc.State.Power[pw].Limit );
      }
	/*	Package Processor & Plaftorm events			*/
	memcpy( PFlip->Thermal.Events, RO(Proc)->PowerThermal.Events,
		sizeof(PFlip->Thermal.Events) );
	/*	Package thermal formulas				*/
      if (RO(Shm)->Proc.Features.Power.EAX.PTM)
      {
	PFlip->Thermal.Sensor = RO(Proc)->PowerThermal.Sensor;
	Pkg_ComputeThermalFormula(PFlip, SProc);
      }
	/*	Package Voltage formulas				*/
	PFlip->Voltage.VID.CPU = RO(Proc)->PowerThermal.VID.CPU;
	PFlip->Voltage.VID.SOC = RO(Proc)->PowerThermal.VID.SOC;

	Pkg_ComputeVoltageFormula(PFlip);
	/*	Computes the Min Processor voltage.			*/
	TEST_AND_SET_SENSOR(	VOLTAGE, LOWEST, PFlip->Voltage.CPU,
				RO(Shm)->Proc.State.Voltage.Limit );
	/* Computes the Max Processor voltage.			*/
	TEST_AND_SET_SENSOR(	VOLTAGE, HIGHEST, PFlip->Voltage.CPU,
				RO(Shm)->Proc.State.Voltage.Limit );
	/*
	The Driver tick is bound to the Service Core:
	1- Tasks collection; Tasks count; and Memory usage.
	2- Processor has resumed from Suspend To RAM.
	*/
	RO(Shm)->SysGate.tickStep = RO(Proc)->tickStep;
     if (RO(Shm)->SysGate.tickStep == RO(Shm)->SysGate.tickReset)
     {
	if (BITWISEAND(LOCKLESS, RO(Shm)->SysGate.Operation, 0x1))
	{
		if (SysGate_OnDemand(Ref, 1) == 0) {
			SysGate_Update(Ref);
		}
	}
	/*	OS notifications: such as Resumed from Suspend		*/
	if ( (fRESET = BITCLR(BUS_LOCK, RW(Proc)->OS.Signal, NTFY )) == 1)
	{
		BITWISESET(LOCKLESS, PendingSync, BIT_MASK_COMP|BIT_MASK_NTFY);
	}
     }
     if (BITWISEAND(LOCKLESS, PendingSync, BIT_MASK_COMP|BIT_MASK_NTFY))
     {
	Package_Update(RO(Shm), RO(Proc), RW(Proc));

	Uncore_Update(RO(Shm), RO(Proc), RO(Core, AT(RO(Proc)->Service.Core)));

      for (cpu = 0; cpu < Ref->RO(Shm)->Proc.CPU.Count; cpu++)
      {
	if (fRESET == 1)
	{
		Core_ResetSensorLimits(&RO(Shm)->Cpu[cpu]);
	}
	if (BITVAL(RO(Ref->Core, AT(cpu))->OffLine, OS) == 0)
	{
		PerCore_Update(Ref->RO(Shm), RO(Ref->Proc), RO(Ref->Core), cpu);
	}
      }
	if (fRESET == 1)
	{
		Pkg_ResetSensorLimits(&RO(Shm)->Proc);
	}
	Technology_Update(RO(Shm), RO(Proc), RW(Proc));

	if (ServerFollowService(&localService,
				&RO(Shm)->Proc.Service,
				tid) == 0)
	{
		SProc = &RO(Shm)->Cpu[RO(Shm)->Proc.Service.Core].FlipFlop[
				!RO(Shm)->Cpu[RO(Shm)->Proc.Service.Core].Toggle
			];
	}
	if (Quiet & 0x100) {
		printf("\t%s || %s\n",
			BITVAL(PendingSync, NTFY0) ? "NTFY":"....",
			BITVAL(PendingSync, COMP0) ? "COMP":"....");
	}
      }
	/*	All aggregations done: Notify Clients.		*/
	BITWISESET(LOCKLESS, PendingSync, BIT_MASK_SYNC);
	BITWISESET(LOCKLESS, RW(Shm)->Proc.Sync, PendingSync);
	BITWISECLR(LOCKLESS, PendingSync);
    }
	/*	Reset the Room mask					*/
	ROOM_RESET(room);

	UBENCH_RDCOUNTER(2);

	UBENCH_COMPUTE();
	Print_uBenchmark((Quiet & 0x100));
   }
	#undef CONDITION_RDPMC
	#undef CONDITION_RDTSCP
	#undef ROOM_RESET
	#undef ROOM_READY
	#undef ROOM_CLEAR
	for (cpu = 0; cpu < RO(Shm)->Proc.CPU.Count; cpu++) {
		if (Arg[cpu].TID) {
			pthread_join(Arg[cpu].TID, NULL);
		}
	}
	free(Arg);
  } else {
	REASON_SET(reason, RC_MEM_ERR, (errno == 0 ? ENOMEM : errno));
  }
	return reason;
}

REASON_CODE Child_Manager(REF *Ref)
{
	RO(SHM_STRUCT) *RO(Shm) = Ref->RO(Shm);
	SERVICE_PROC localService = RESET_SERVICE;
	REASON_INIT(reason);
	unsigned int cpu = 0;

	pthread_t tid = pthread_self();

  if (ServerFollowService(&localService, &RO(Shm)->Proc.Service, tid) == 0) {
	pthread_setname_np(tid, "corefreqd-cmgr");
  }
	ARG *Arg = calloc(RO(Shm)->Proc.CPU.Count, sizeof(ARG));
  if (Arg != NULL)
  {
   do {
    for(cpu=0; !BITVAL(Shutdown, SYNC) && (cpu < RO(Shm)->Proc.CPU.Count);cpu++)
    {
	if (BITVAL(RO(Shm)->Cpu[cpu].OffLine, OS) == 1) {
		if (Arg[cpu].TID) {
			/*	Remove this child thread.		*/
			pthread_join(Arg[cpu].TID, NULL);
			Arg[cpu].TID = 0;
		}
	} else {
		unsigned int seed32;
		__asm__ volatile
		(
			"rdtsc" 		"\n\t"
			"movl	%%eax,	%0"
			: "=m" (seed32)
			:
			: "%rax", "%rcx", "%rdx", "cc", "memory"
		);
	    #ifdef __GLIBC__
		initstate_r(	seed32,
				RO(Shm)->Cpu[cpu].Slice.Random.state,
				sizeof(RO(Shm)->Cpu[cpu].Slice.Random.state),
				&RO(Shm)->Cpu[cpu].Slice.Random.data );
	    #else
		initstate(seed32, RO(Shm)->Cpu[cpu].Slice.Random.state, 128);
	    #endif
		if (!Arg[cpu].TID) {
			/*	Add this child thread.			*/
			Arg[cpu].Ref  = Ref;
			Arg[cpu].Bind = cpu;
			pthread_create( &Arg[cpu].TID,
					NULL,
					Child_Thread,
					&Arg[cpu]);
		}
	}
    }
	ServerFollowService(&localService, &RO(Shm)->Proc.Service, tid);

	nanosleep(&RO(Shm)->Sleep.childWaiting, NULL);
   }
   while (!BITVAL(Shutdown, SYNC)) ;

	for (cpu = 0; cpu < RO(Shm)->Proc.CPU.Count; cpu++) {
		if (Arg[cpu].TID) {
			pthread_join(Arg[cpu].TID, NULL);
		}
	}
	free(Arg);
  } else {
	REASON_SET(reason, RC_MEM_ERR, (errno == 0 ? ENOMEM : errno));
  }
	return reason;
}

REASON_CODE Shm_Manager(FD *fd, RO(PROC) *RO(Proc), RW(PROC) *RW(Proc),
			uid_t uid, uid_t gid, mode_t cmask[2])
{
	unsigned int	cpu = 0;
	RO(CORE)	**RO(Core);
	RW(CORE)	**RW(Core);
	RO(SHM_STRUCT)	*RO(Shm) = NULL;
	RW(SHM_STRUCT)	*RW(Shm) = NULL;
	struct {
		const size_t	RO(Core),
				RW(Core);
	} Size = {
		ROUND_TO_PAGES(sizeof(RO(CORE))),
		ROUND_TO_PAGES(sizeof(RW(CORE)))
	};
	REASON_INIT(reason);

    if ((RO(Core) = calloc(RO(Proc)->CPU.Count, sizeof(RO(Core)))) == NULL) {
	REASON_SET(reason, RC_MEM_ERR, (errno == 0 ? ENOMEM : errno));
    }
    if ((RW(Core) = calloc(RO(Proc)->CPU.Count, sizeof(RW(Core)))) == NULL) {
	REASON_SET(reason, RC_MEM_ERR, (errno == 0 ? ENOMEM : errno));
    }
    for(cpu = 0;(reason.rc == RC_SUCCESS) && (cpu < RO(Proc)->CPU.Count); cpu++)
    {
	const off_t	vm_ro_pgoff = (ID_RO_VMA_CORE + cpu) * PAGE_SIZE,
			vm_rw_pgoff = (ID_RW_VMA_CORE + cpu) * PAGE_SIZE;

	if ((RO(Core, AT(cpu)) = mmap(NULL, Size.RO(Core),
				PROT_READ,
				MAP_SHARED,
				fd->drv, vm_ro_pgoff)) == MAP_FAILED)
	{
		REASON_SET(reason, RC_SHM_MMAP);
	}
	if ((RW(Core, AT(cpu)) = mmap(NULL, Size.RW(Core),
				PROT_READ|PROT_WRITE,
				MAP_SHARED,
				fd->drv, vm_rw_pgoff)) == MAP_FAILED)
	{
		REASON_SET(reason, RC_SHM_MMAP);
	}
    }
    if (reason.rc == RC_SUCCESS) {
	if (gid != 0) {
		if (setregid((gid_t) -1, gid) != 0) {
			REASON_SET(reason, RC_SYS_CALL);
		}
	}
    }
    if (reason.rc == RC_SUCCESS) {
	if (uid != 0) {
		if (setreuid((uid_t) -1, uid) != 0) {
			REASON_SET(reason, RC_SYS_CALL);
		}
	}
    }
    if (reason.rc == RC_SUCCESS)
    {	/* Initialize shared memory.					*/
	const size_t shmCpuSize = sizeof(CPU_STRUCT) * RO(Proc)->CPU.Count,
			roSize = ROUND_TO_PAGES((sizeof(RO(SHM_STRUCT))
				+ shmCpuSize)),
			rwSize = ROUND_TO_PAGES(sizeof(RW(SHM_STRUCT)));

      if ( ((fd->ro = shm_open(RO(SHM_FILENAME), O_CREAT|O_TRUNC|O_RDWR,
					 S_IRUSR|S_IWUSR
					|S_IRGRP|S_IWGRP
					|S_IROTH|S_IWOTH)) != -1)
	&& ((fd->rw = shm_open(RW(SHM_FILENAME), O_CREAT|O_TRUNC|O_RDWR,
					 S_IRUSR|S_IWUSR
					|S_IRGRP|S_IWGRP
					|S_IROTH|S_IWOTH)) != -1) )
      {
	pid_t CPID = -1;

	if ( (ftruncate(fd->ro, (off_t) roSize) != -1)
	  && (ftruncate(fd->rw, (off_t) rwSize) != -1) )
	{
		fchmod(fd->ro, cmask[0]);
		fchmod(fd->rw, cmask[1]);

	    if ( ( ( RO(Shm) = mmap(NULL, roSize,
				PROT_READ|PROT_WRITE, MAP_SHARED,
				fd->ro, 0) ) != MAP_FAILED )
	      && ( ( RW(Shm) = mmap(NULL, rwSize,
				PROT_READ|PROT_WRITE, MAP_SHARED,
				fd->rw, 0) ) != MAP_FAILED ) )
	    {
		__typeof__ (errno) fork_err = 0;
		/*	Clear SHM					*/
		memset(RO(Shm), 0, roSize);
		memset(RW(Shm), 0, rwSize);
		/*	Store version footprint into SHM		*/
		SET_FOOTPRINT(RO(Shm)->FootPrint,MAX_FREQ_HZ,
						CORE_COUNT,
						TASK_ORDER,
						COREFREQ_MAJOR,
						COREFREQ_MINOR,
						COREFREQ_REV	);
		/*	Reference time the Server is starting at.	*/
		time(&RO(Shm)->StartedAt);
		/*	Store the daemon gate name.			*/
		StrCopy(RO(Shm)->ShmName, RO(SHM_FILENAME), TASK_COMM_LEN);
		/*	Initialize the busy wait times.			*/
		RO(Shm)->Sleep.ringWaiting  = TIMESPEC(SIG_RING_MS);
		RO(Shm)->Sleep.childWaiting = TIMESPEC(CHILD_PS_MS);
		RO(Shm)->Sleep.sliceWaiting = TIMESPEC(CHILD_TH_MS);

		REF Ref = {
			.CPID		= -1,
			.KID		= 0,
			.Started	= 0,
			.Slice.Func	= NULL,
			.Slice.arg	= 0,
			.fd		= fd,
			.RO(Shm)	= RO(Shm),
			.RW(Shm)	= RW(Shm),
			.RO(Proc)	= RO(Proc),
			.RW(Proc)	= RW(Proc),
			.RO(Core)	= RO(Core),
			.RW(Core)	= RW(Core),
			.RO(SysGate)	= NULL
		};
		sigemptyset(&Ref.Signal);

		Package_Update(RO(Shm), RO(Proc), RW(Proc));

		memcpy(&RO(Shm)->SMB, &RO(Proc)->SMB, sizeof(SMBIOS_ST));

		/*	Clear notification.				*/
		BITWISECLR(LOCKLESS, RW(Shm)->Proc.Sync);

		SysGate_Toggle(&Ref, SysGateStartUp);

		/*	Welcomes with brand and per CPU base clock.	*/
	      if (Quiet & 0x001) {
		printf( "CoreFreq Daemon %s"				\
			"  Copyright (C) 2015-2026 CYRIL COURTIAT\n",
			COREFREQ_VERSION );
	      }
	      if (Quiet & 0x010) {
		printf( "\n"						\
			"  Processor [%s]\n"				\
			"  Architecture [%s] %u/%u CPU Online.\n",
			RO(Shm)->Proc.Brand,
			RO(Shm)->Proc.Architecture,
			RO(Shm)->Proc.CPU.OnLine,
			RO(Shm)->Proc.CPU.Count );
	      }
	      if (Quiet & 0x100) {
		printf( "  SleepInterval(%u), SysGate(%u), %ld tasks\n\n",
			RO(Shm)->Sleep.Interval,
			!BITVAL(RO(Shm)->SysGate.Operation, 0) ?
			0:RO(Shm)->Sleep.Interval * RO(Shm)->SysGate.tickReset,
			TASK_LIMIT );
		}
	      if (Quiet) {
		fflush(stdout);
	      }
		CPID = Ref.CPID = fork();
	/*-----[ Resources inherited ]----------------------------------*/
		fork_err = errno;

		Emergency_Command(&Ref, 1);

		switch (Ref.CPID) {
		case 0:
			reason = Child_Manager(&Ref);
			break;
		case -1:
			REASON_SET(reason, RC_EXEC_ERR, fork_err);
			break;
		default:
			reason = Core_Manager(&Ref);

			if (gid != 0) {
				if (setregid((gid_t) -1, 0) != 0) {
					REASON_SET(reason, RC_SYS_CALL);
				}
			}
			if (uid != 0) {
				if (setreuid((uid_t) -1, 0) != 0) {
					REASON_SET(reason, RC_SYS_CALL);
				}
			}
			if (RO(Shm)->App.Cli) {
				if (kill(RO(Shm)->App.Cli, SIGTERM) == -1) {
				    if (errno != ESRCH)
					REASON_SET(reason, RC_EXEC_ERR);
				}
			}
			if (RO(Shm)->App.GUI) {
				if (kill(RO(Shm)->App.GUI, SIGTERM) == -1) {
				    if (errno != ESRCH)
					REASON_SET(reason, RC_EXEC_ERR);
				}
			}
			SysGate_OnDemand(&Ref, 0);

			if (kill(Ref.CPID, SIGQUIT) == 0) {
				if (waitpid(Ref.CPID, NULL, 0) == -1) {
					REASON_SET(reason, RC_EXEC_ERR);
				}
			} else {
				REASON_SET(reason, RC_EXEC_ERR);
			}
			break;
		}
		Emergency_Command(&Ref, 0);

		if (munmap(RO(Shm), roSize) == -1) {
			REASON_SET(reason, RC_SHM_MMAP);
		}
		if (munmap(RW(Shm), rwSize) == -1) {
			REASON_SET(reason, RC_SHM_MMAP);
		}
	    } else {
		REASON_SET(reason, RC_SHM_MMAP);
	    }
	} else {
		REASON_SET(reason, RC_SHM_FILE);
	}
	if (close(fd->ro) == -1) {
		REASON_SET(reason, RC_SHM_FILE);
	}
	if (close(fd->rw) == -1) {
		REASON_SET(reason, RC_SHM_FILE);
	}
	if (CPID != 0) {
	    if (shm_unlink(RO(SHM_FILENAME)) == -1) {
		REASON_SET(reason, RC_SHM_FILE);
	    }
	    if (shm_unlink(RW(SHM_FILENAME)) == -1) {
		REASON_SET(reason, RC_SHM_FILE);
	    }
	}
      } else {
		REASON_SET(reason, RC_SHM_FILE);
      }
    }
    for (cpu = 0; cpu < RO(Proc)->CPU.Count; cpu++)
    {
	if (RO(Core, AT(cpu)) != NULL) {
	    if (munmap(RO(Core, AT(cpu)), Size.RO(Core)) == -1) {
		REASON_SET(reason, RC_SHM_MMAP);
	    }
	}
	if (RW(Core, AT(cpu)) != NULL) {
	    if (munmap(RW(Core, AT(cpu)), Size.RW(Core)) == -1) {
		REASON_SET(reason, RC_SHM_MMAP);
	    }
	}
    }
    if (RO(Core) != NULL) {
	free(RO(Core));
    }
    if (RW(Core) != NULL) {
	free(RW(Core));
    }
	return reason;
}

REASON_CODE Help(REASON_CODE reason, ...)
{
	va_list ap;
	va_start(ap, reason);
	switch (reason.rc) {
	case RC_SUCCESS:
	case RC_OK_SYSGATE:
	case RC_OK_COMPUTE:
	case RC_DRIVER_BASE ... RC_DRIVER_LAST:
		break;
	case RC_CMD_SYNTAX: {
		char *appName = va_arg(ap, char *);
		printf( "Usage:\t%s [-option <arguments>]\n"		\
			"\t-q\t\tQuiet\n"				\
			"\t-i\t\tInfo\n"				\
			"\t-d\t\tDebug\n"				\
			"\t-gon\t\tEnable SysGate\n"			\
			"\t-goff\t\tDisable SysGate\n"			\
			"\t-U <decimal>\tSet the effective user ID\n"	\
			"\t-G <decimal>\tSet the effective group ID\n"	\
			"\t-M <oct>,<oct>\tShared Memories permission\n"\
			"\t-h\t\tPrint out this message\n"		\
			"\t-v\t\tPrint the version number\n"		\
			"\nExit status:\n"				\
			"\t%u\tSUCCESS\t\tSuccessful execution\n"	\
			"\t%u\tCMD_SYNTAX\tCommand syntax error\n"	\
			"\t%u\tSHM_FILE\tShared memory file error\n"	\
			"\t%u\tSHM_MMAP\tShared memory mapping error\n"	\
			"\t%u\tPERM_ERR\tExecution not permitted\n"	\
			"\t%u\tMEM_ERR\t\tMemory operation error\n"	\
			"\t%u\tEXEC_ERR\tGeneral execution error\n"	\
			"\t%u\tSYS_CALL\tSystem call error\n"		\
			"\nReport bugs to labs[at]cyring[.]fr\n", appName,
			RC_SUCCESS,
			RC_CMD_SYNTAX,
			RC_SHM_FILE,
			RC_SHM_MMAP,
			RC_PERM_ERR,
			RC_MEM_ERR,
			RC_EXEC_ERR,
			RC_SYS_CALL);
		}
		break;
	case RC_PERM_ERR:
	case RC_MEM_ERR:
	case RC_EXEC_ERR: {
		char *appName = va_arg(ap, char *);
		char *sysMsg = strerror(reason.no);
		fprintf(stderr, "%s execution error code %d\n%s @ line %d\n",
				appName, reason.no, sysMsg, reason.ln);
		}
		break;
	case RC_SHM_FILE:
	case RC_SHM_MMAP: {
		char *shmFileName = va_arg(ap, char *);
		char *sysMsg = strerror(reason.no);
		fprintf(stderr , "Driver connection error code %d\n"	\
				"%s: '%s' @ line %d\n",
				reason.no, shmFileName, sysMsg, reason.ln);
		}
		break;
	case RC_SYS_CALL: {
		char *sysMsg = strerror(reason.no);
		fprintf(stderr, "System error code %d\n%s @ line %d\n",
				reason.no, sysMsg, reason.ln);
		}
		break;
	}
	va_end(ap);
	return reason;
}

int main(int argc, char *argv[])
{
	FD fd = {0, 0, 0};
	RO(PROC) *RO(Proc) = NULL;	/* Kernel module anchor points. */
	RW(PROC) *RW(Proc) = NULL;
	uid_t uid = 0, gid = 0;
	mode_t cmask[2] = {
		S_IRUSR|S_IRGRP|S_IROTH,
		S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
	};
	char *program = strdup(argv[0]),
		*appName = program != NULL ? basename(program) : argv[0];

	REASON_INIT(reason);
	int  i;
    for (i = 1; i < argc; i++)
    {
	if (strlen(argv[i]) > 1) {
		if (argv[i][0] == '-')
		{
			char option = argv[i][1];
			switch (option) {
			case 'q':
				Quiet = 0x000;
				break;
			case 'i':
				Quiet = 0x011;
				break;
			case 'd':
				Quiet = 0x111;
				break;
			case 'g':
					if (argv[i][2]=='o'
					 && argv[i][3]=='f'
					 && argv[i][4]=='f') {
						SysGateStartUp = 0;
				} else if ( argv[i][2]=='o'
					 && argv[i][3]=='n') {
						SysGateStartUp = 1;
				} else {
					REASON_SET(reason, RC_CMD_SYNTAX, 0);
					reason = Help(reason, appName);
				}
				break;
			case 'v':
				printf("%s\n", COREFREQ_VERSION);
				reason.rc = RC_CMD_SYNTAX;
				break;
			case 'U': {
				char trailing =  '\0';
			    if (argv[++i] == NULL) {
					REASON_SET(reason, RC_CMD_SYNTAX, 0);
					reason = Help(reason, appName);
			    } else if (sscanf(argv[i], "%d%c",
							&uid,
							&trailing) != 1) {
					REASON_SET(reason, RC_CMD_SYNTAX);
					reason = Help(reason, appName);
			    }
			}
				break;
			case 'G': {
				char trailing =  '\0';
			    if (argv[++i] == NULL) {
					REASON_SET(reason, RC_CMD_SYNTAX, 0);
					reason = Help(reason, appName);
			    } else if (sscanf(argv[i], "%d%c",
							&gid,
							&trailing) != 1) {
					REASON_SET(reason, RC_CMD_SYNTAX);
					reason = Help(reason, appName);
			    }
			}
				break;
			case 'M': {
				char trailing =  '\0';
			    if (argv[++i] == NULL) {
				REASON_SET(reason, RC_CMD_SYNTAX, 0);
				reason = Help(reason, appName);
			    } else if (sscanf(argv[i] , "%o,%o%c",
							&cmask[0],
							&cmask[1],
							&trailing) > 2) {
					REASON_SET(reason, RC_CMD_SYNTAX);
					reason = Help(reason, appName);
			    }
			}
				break;
			case 'h':
			default: {
				REASON_SET(reason, RC_CMD_SYNTAX, 0);
				reason = Help(reason, appName);
				}
				break;
			}
		} else {
			REASON_SET(reason, RC_CMD_SYNTAX, 0);
			reason = Help(reason, appName);
		}
	} else {
		REASON_SET(reason, RC_CMD_SYNTAX, 0);
		reason = Help(reason, appName);
	}
    }
    if (reason.rc == RC_SUCCESS)
    {
	if (geteuid() == 0)
	{
	    if ((fd.drv = open(DRV_FILENAME, O_RDWR|O_SYNC)) != -1)
	    {
		const size_t packageSize[] = {
			ROUND_TO_PAGES(sizeof(RO(PROC))),
			ROUND_TO_PAGES(sizeof(RW(PROC)))
		};
		const off_t vm_pgoff[] = {
			ID_RO_VMA_PROC * PAGE_SIZE,
			ID_RW_VMA_PROC * PAGE_SIZE
		};
		if ((RO(Proc) = mmap(NULL, packageSize[0],
				PROT_READ, MAP_SHARED,
				fd.drv, vm_pgoff[0])) != MAP_FAILED)
		{
		  if ((RW(Proc) = mmap(NULL, packageSize[1],
				PROT_READ|PROT_WRITE, MAP_SHARED,
				fd.drv, vm_pgoff[1])) != MAP_FAILED)
		  {
		    if (CHK_FOOTPRINT(RO(Proc)->FootPrint,MAX_FREQ_HZ,
							CORE_COUNT,
							TASK_ORDER,
							COREFREQ_MAJOR,
							COREFREQ_MINOR,
							COREFREQ_REV))
		    {
			reason = Shm_Manager(	&fd, RO(Proc), RW(Proc),
						uid, gid, cmask );

			switch (reason.rc) {
			case RC_SUCCESS:
			case RC_OK_SYSGATE:
			case RC_OK_COMPUTE:
			case RC_DRIVER_BASE ... RC_DRIVER_LAST:
				break;
			case RC_CMD_SYNTAX:
			case RC_PERM_ERR:
				break;
			case RC_SHM_FILE:
			case RC_SHM_MMAP:
				reason = Help(reason, RO(SHM_FILENAME));
				break;
			case RC_MEM_ERR:
			case RC_EXEC_ERR:
				reason = Help(reason, appName);
				break;
			case RC_SYS_CALL:
				reason = Help(reason);
				break;
			}
		    } else {
			char *wrongVersion = malloc(10+5+5+5+1);
			REASON_SET(reason, RC_SHM_MMAP, EACCES);
			if (wrongVersion != NULL) {
				snprintf(wrongVersion, 10+5+5+5+1,
					"Version %hu.%hu.%hu",
					RO(Proc)->FootPrint.major,
					RO(Proc)->FootPrint.minor,
					RO(Proc)->FootPrint.rev);
				reason = Help(reason, wrongVersion);
				free(wrongVersion);
			}
		    }
		    if (munmap(RW(Proc), packageSize[1]) == -1) {
			REASON_SET(reason, RC_SHM_MMAP);
			reason = Help(reason, DRV_FILENAME);
		    }
		  }
		  if (munmap(RO(Proc), packageSize[0]) == -1) {
			REASON_SET(reason, RC_SHM_MMAP);
			reason = Help(reason, DRV_FILENAME);
		  }
		} else {
			REASON_SET(reason, RC_SHM_MMAP);
			reason = Help(reason, DRV_FILENAME);
		}
		if (close(fd.drv) == -1) {
			REASON_SET(reason, RC_SHM_FILE);
			reason = Help(reason, DRV_FILENAME);
		}
	    } else {
		REASON_SET(reason, RC_SHM_FILE);
		reason = Help(reason, DRV_FILENAME);
	    }
	} else {
		REASON_SET(reason, RC_PERM_ERR, EACCES);
		reason = Help(reason, appName);
	}
    }
    if (program != NULL) {
	free(program);
    }
	return reason.rc;
}
