#!/bin/bash

# ***********************************************************************************************

 # This file is provided under a dual BSD/GPLv2 license.  When using or 
 # redistributing this file, you may do so under either license.

  # GPL LICENSE SUMMARY

  # Copyright(c) 2011 Intel Corporation. All rights reserved.

  # This program is free software; you can redistribute it and/or modify 
  # it under the terms of version 2 of the GNU General Public License as
  # published by the Free Software Foundation.

  # This program is distributed in the hope that it will be useful, but 
  # WITHOUT ANY WARRANTY; without even the implied warranty of 
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
  # General Public License for more details.

  # You should have received a copy of the GNU General Public License 
  # along with this program; if not, write to the Free Software 
  # Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  # The full GNU General Public License is included in this distribution 
  # in the file called LICENSE.GPL.

  # Contact Information:
  # Gautam Upadhyaya <gautam.upadhyaya@intel.com>
  # 1906 Fox Drive, Champaign, IL - 61820, USA

  # BSD LICENSE 

  # Copyright(c) 2011 Intel Corporation. All rights reserved.
  # All rights reserved.

  # Redistribution and use in source and binary forms, with or without 
  # modification, are permitted provided that the following conditions 
  # are met:

  #   * Redistributions of source code must retain the above copyright 
  #     notice, this list of conditions and the following disclaimer.
  #   * Redistributions in binary form must reproduce the above copyright 
  #     notice, this list of conditions and the following disclaimer in 
  #     the documentation and/or other materials provided with the 
  #     distribution.
  #   * Neither the name of Intel Corporation nor the names of its 
  #     contributors may be used to endorse or promote products derived 
  #     from this software without specific prior written permission.

  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  # ***********************************************************************************************

UNAME="uname"
GREP="grep"
AWK="awk"
CAT="cat"
LSMOD="/sbin/lsmod"

BOOT_CONFIG_FILE=/boot/config-`${UNAME} -r`

KERNEL_VERSION_MAJOR=`${UNAME} -r | ${AWK} 'BEGIN{FS="[^0-9]"} {print $1}'`
KERNEL_VERSION_MINOR=`${UNAME} -r | ${AWK} 'BEGIN{FS="[^0-9]"} {print $2}'`
KERNEL_VERSION_SUBLEVEL=`${UNAME} -r | ${AWK} 'BEGIN{FS="[^0-9]"} {print $3}'`

CPUFREQ_DIR="/sys/devices/system/cpu/cpu0/cpufreq"

#KERNEL_VERSION_MAJOR=3
#KERNEL_VERSION_MINOR=0
#KERNEL_VERSION_SUBLEVEL=13

REQUIRED_MIN_MAJOR=2
REQUIRED_MIN_MINOR=6
REQUIRED_MIN_SUBLEVEL=32

# ########################################################
# Following {Family, Model} values taken from
# "sampling/collector/platform_picker/platform_picker.h"
# ########################################################
FAM_P6=6 #0x6

# Core i7 (45nm)
MOD_NEHALEM=26 #0x1A
MOD_LYNFIELD=30 #0x1E
MOD_HAVENDALE=31 #0x1F
MOD_BECKTON=46 #0x2E

# Core i7 (32nm)
MOD_WESTMEREA0=37 #0x25
MOD_WESTMERET0=44 #0x2C
MOD_EAGLETON=47 #0x2F

# Sandybridge (32nm)
MOD_SANDYBRIDGE=42 #0x2A
MOD_JAKETOWN=45 #0x2D

# Ivy Bridge (22nm)
MOD_IVYBRIDGE=58 #0x3A


is_verbose=0

usage()
{
    echo "USAGE: sh ./integ_machine_check.sh <options>";
    echo "  Where options are:";
    echo "  --help | -h: print this message and exit";
    echo "  --verbose | -v: be verbose";
    return 0
}

get_fms()
{
    eval $(${CAT} /proc/cpuinfo | tr -s ' ' | 
            ${AWK} '
            BEGIN{
                fam="";
                mod="";
                step="";
            }
    {
        if (NF >= 3) {
            if ($1 == "cpu" && $2 == "family") {
                fam=$4;
            } else if ($1 == "model" && $2 != "name") {
                mod=$3;
            } else if ($1 == "stepping") {
                step = $3;
                print "FAMILY=" fam "; MODEL=" mod "; STEPPING=" step;
                exit 0
            }
        }
    }
    END{
        if(fam == "" || mod == "" || step == ""){
            print "ERROR: could NOT extract F.M.S from cpuinfo file!";
            exit 255;
        }
    }'
    );
}

is_supported_fam_mod()
{
    family=$1; model=$2;
    if [ $family -ne $FAM_P6 ]; then
        return 255;
    fi
    if [ $model -eq $MOD_NEHALEM ] || [ $model -eq $MOD_LYNFIELD ] || [ $model -eq $MOD_HAVENDALE ] || [ $model -eq $MOD_BECKTON ]; then
        return 0;
    elif [ $model -eq $MOD_WESTMEREA0 ] || [ $model -eq $MOD_WESTMERET0 ] || [ $model -eq $MOD_EAGLETON ]; then
        return 0;
    elif [ $model -eq $MOD_SANDYBRIDGE ] || [ $model -eq $MOD_JAKETOWN ]; then
        return 0;
    elif [ $model -eq $MOD_IVYBRIDGE ]; then
        return 0;
    else
        echo No mod found;
        return 255; #-1
    fi
}

check_fms()
{
    if [ $is_verbose -ne 0 ]; then
        echo "CHECKING underlying processor architecture for compatibility."
    fi

    get_fms
    is_supported_fam_mod $FAMILY $MODEL
    retVal_fam_mod=$?

    if [ $retVal_fam_mod -ne 0 ]; then
        if [ $is_verbose -ne 0 ]; then
            echo "ERROR: underlying architecture $FAMILY.$MODEL.$STEPPING is NOT supported!";
        fi
        return 255; # -1
    else
        if [ $is_verbose -ne 0 ]; then
            echo "OK: underlying architecture $FAMILY.$MODEL.$STEPPING IS supported!";
        fi
        return 0;
    fi
}

check_kernel_ver()
{
    is_valid_kernel=1
    if [ $is_verbose -ne 0 ]; then
        echo "CHECKING KERNEL VERSION for min compatibility";
    fi
    if [ $KERNEL_VERSION_MAJOR -gt $REQUIRED_MIN_MAJOR ]; then
        is_valid_kernel=1;
    else
        if [ $KERNEL_VERSION_MAJOR -lt $REQUIRED_MIN_MAJOR ]; then
            is_valid_kernel=0;
        elif [ $KERNEL_VERSION_MINOR -lt $REQUIRED_MIN_MINOR ]; then
            is_valid_kernel=0;
        elif [ $KERNEL_VERSION_SUBLEVEL -lt $REQUIRED_MIN_SUBLEVEL ]; then
            is_valid_kernel=0;
        fi
    fi
    if [ $is_valid_kernel -ne 1 ]; then
        if [ $is_verbose -ne 0 ]; then
            echo "UNSUPPORTED KERNEL VERSION $KERNEL_VERSION_MAJOR.$KERNEL_VERSION_MINOR.$KERNEL_VERSION_SUBLEVEL detected: Min of $REQUIRED_MIN_MAJOR.$REQUIRED_MIN_MINOR.$REQUIRED_MIN_SUBLEVEL is required!";
        fi
        retVal=255; # -1
    else
        if [ $is_verbose -ne 0 ]; then
            echo "OK: SUPPORTED KERNEL VERSION $KERNEL_VERSION_MAJOR.$KERNEL_VERSION_MINOR.$KERNEL_VERSION_SUBLEVEL detected.";
        fi
        retVal=0;
    fi

    return $retVal
}

check_tracepoints()
{
    if [ $is_verbose -ne 0 ]; then
        echo "CHECKING BOOT CONFIG FILE $BOOT_CONFIG_FILE for tracepoints";
    fi

    HAS_TRACEPOINTS=`${GREP} "CONFIG_TRACEPOINTS=y" $BOOT_CONFIG_FILE`;

    if [ -z "$HAS_TRACEPOINTS" ]; then
        if [ $is_verbose -ne 0 ]; then
            echo "ERROR: KERNEL has NOT been compiled with tracepoints!";
        fi
        retVal=255; # -1
    else
        if [ $is_verbose -ne 0 ]; then
            echo "OK: KERNEL HAS been compiled with tracepoints!";
        fi
        retVal=0;
    fi

    return $retVal
}


check_cpufreq()
{
    if [ $is_verbose -ne 0 ]; then
        echo "CHECKING BOOT CONFIG FILE $BOOT_CONFIG_FILE for cpufreq availability.";
    fi

    HAS_CPUFREQ=`${GREP} "CONFIG_CPU_FREQ=y" $BOOT_CONFIG_FILE`;

    if [ -z "$HAS_CPUFREQ" ]; then
        if [ $is_verbose -ne 0 ]; then
            echo "ERROR: KERNEL has NOT been compiled with cpufreq set!";
        fi
        retVal=255; #-1
    else
        if [ $is_verbose -ne 0 ]; then
            echo "OK: KERNEL HAS been compiled with CONFIG_CPU_FREQ set!";
        fi
        retVal=0;
    fi
    return $retVal
}

check_acpi_cpufreq_old()
{
    if [ $is_verbose -ne 0 ]; then
        echo "CHECKING if module \"acpi_cpufreq\" has been loaded.";
    fi

#HAS_ACPI_CPUFREQ=`${LSMOD} | ${GREP} "acpi_cpufreq"`;
        HAS_ACPI_CPUFREQ=`grep -E "CONFIG_X86_ACPI_CPUFREQ=(y|m)" $BOOT_CONFIG_FILE`;
    if [ -z "$HAS_ACPI_CPUFREQ" ]; then
        if [ $is_verbose -ne 0 ]; then
            echo "ERROR: module acpi_cpufreq NOT loaded!";
        fi
        retVal=255; #-1
    else
        if [ $is_verbose -ne 0 ]; then
            echo "OK: acpi_cpufreq module loaded";
        fi
        retVal=0;
    fi
    return $retVal
}

check_acpi_cpufreq()
{
    if [ $is_verbose -ne 0 ]; then
        echo "CHECKING if module \"acpi_cpufreq\" has been loaded by checking to see if the $CPUFREQ_DIR directory is present."
    fi

    if [ -d "$CPUFREQ_DIR" ]; then
        if [ $is_verbose -ne 0 ]; then
            echo "OK: directory $CPUFREQ_DIR exists";
        fi
        retVal=0;
    else
        if [ $is_verbose -ne 0 ]; then
            echo "ERROR: directory $CPUFREQ_DIR does NOT exist";
            echo "The issue sometimes occurs because the Intel Speedstep option has been disabled in the BIOS."
			echo "Please recheck your BIOS settings.";
        fi
        retVal=255; #-1
    fi
    return $retVal
}

parse_args()
{
    while [ $# -gt 0 ]; do
        case "$1" in
            --help | -h) usage; exit 0;;
            --verbose | -v) is_verbose=1;;
            *) echo "ERROR: unknown option $1"; usage; exit 255;
        esac
        shift
    done
}

do_integ_machine_check()
{
    fms=$1; kernel_ver=$2; tracepoints=$3; cpufreq=$4; acpi_cpufreq=$5;

    if [ $fms -ne 0 ] || [ $kernel_ver -ne 0 ] || [ $tracepoints -ne 0 ] || [ $cpufreq -ne 0 ] || [ $acpi_cpufreq -ne 0 ]; then
        if [ $is_verbose -ne 0 ]; then
            echo "***********************************";
        fi
        echo "ERROR: UNSUPPORTED platform";
        if [ $is_verbose -ne 0 ]; then
            echo "***********************************";
        fi
        exit 255; # -1
    else
        if [ $is_verbose -ne 0 ]; then
            echo "***********************************";
        fi
        echo "OK: SUPPORTED platform";
        if [ $is_verbose -ne 0 ]; then
            echo "***********************************";
        fi
        exit 0;
    fi
}

parse_args $*

check_fms
fms=$?
check_kernel_ver
kernel_ver=$?
check_tracepoints
tracepoints=$?
check_cpufreq
cpufreq=$?
check_acpi_cpufreq
acpi_cpufreq=$?

do_integ_machine_check $fms $kernel_ver $tracepoints $cpufreq $acpi_cpufreq
