#! /usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # $Source: src/usr/targeting/common/processMrw.pl $ # # OpenPOWER HostBoot Project # # Contributors Listed Below - COPYRIGHT 2015,2019 # [+] International Business Machines Corp. # # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # IBM_PROLOG_END_TAG use strict; use XML::Simple; use Data::Dumper; use Targets; use Math::BigInt; use Getopt::Long; use File::Basename; use constant HZ_PER_KHZ=>1000; use constant MAX_MCS_PER_PROC => 4; # 4 MCS per Nimbus my $VERSION = "1.0.0"; my $force = 0; my $serverwiz_file = ""; my $version = 0; my $debug = 0; my $report = 0; my $sdr_file = ""; my $build = "hb"; my $system_config = ""; my $output_filename = ""; # Map the OMI instance to its corresponding OMIC parent my %omi_map = (4 => "omic-0", 5 => "omic-0", 6 => "omic-0", 7 => "omic-1", 2 => "omic-1", 3 => "omic-1", 0 => "omic-2", 1 => "omic-2", 12 => "omic-0", 13 => "omic-0", 14 => "omic-0", 15 => "omic-1", 10 => "omic-1", 11 => "omic-1", 8 => "omic-2", 9 => "omic-2"); # TODO RTC:170860 - Remove this after dimm connector defines VDDR_ID my $num_voltage_rails_per_proc = 1; GetOptions( "build=s" => \$build, "f" => \$force, # numeric "x=s" => \$serverwiz_file, # string "d" => \$debug, "c=s" => \$system_config, #string "o=s" => \$output_filename, #string "v" => \$version, "r" => \$report, ) # flag or printUsage(); if ($version == 1) { die "\nprocessMrw.pl\tversion $VERSION\n"; } if ($serverwiz_file eq "") { printUsage(); } $XML::Simple::PREFERRED_PARSER = 'XML::Parser'; my $targetObj = Targets->new; if ($force == 1) { $targetObj->{force} = 1; } if ($debug == 1) { $targetObj->{debug} = 1; } $targetObj->setVersion($VERSION); my $xmldir = dirname($serverwiz_file); $targetObj->loadXML($serverwiz_file); our %hwsvmrw_plugins; # FSP-specific functions if ($build eq "fsp") { eval ("use processMrw_fsp; return 1;"); processMrw_fsp::return_plugins(); } my $str=sprintf( " %30s | %10s | %6s | %4s | %9s | %4s | %4s | %4s | %10s | %s\n", "Sensor Name","FRU Name","Ent ID","Type","Evt Type","ID","Inst","FRU", "HUID","Target"); $targetObj->writeReport($str); my $str=sprintf( " %30s | %10s | %6s | %4s | %9s | %4s | %4s | %4s | %10s | %s\n", "------------------------------","----------", "------","----","---------","----","----","----","----------", "----------"); $targetObj->writeReport($str); ######################## ## Used to setup GPU sensors on processors my %G_gpu_sensors; # key: obusslot target, # value: (GPU#, Function, Temp, MemTemp IPMI name/ids, my %G_slot_to_proc; # key: obusslot string # value: processor target string ######################### # convert a number string into a bit-position number # example: "0x02" --> 0b0100 = 4 sub numToBitPositionNum { my ($hexStr) = @_; my $num = 0x0001; my $newNum = $num << hex($hexStr); return $newNum; } # Used to populate G_gpu_sensors hash of array references # # Each array reference will be composed of 3 sensors + # board cfg ID which together makes up a GPU. # - each sensor has a sensor type & entity ID + a sensor ID # - board cfg is known as OBUS_CONFIG in mrw # (each GPU can belong to 1 or more cfgs) # sub addSensorToGpuSensors { my ($name, $obusslot_str, $type, $entID, $sensorID) = @_; my $GPU_SENSORS_FUNC_OFFSET = 0; my $GPU_SENSORS_TEMP_OFFSET = 2; my $GPU_SENSORS_MEM_TEMP_OFFSET = 4; my $rSensorArray = $G_gpu_sensors{$obusslot_str}; unless ($rSensorArray) { $rSensorArray = [ "0xFFFF","0xFF","0xFFFF","0xFF", "0xFFFF","0xFF","0x00" ]; } if ($name =~ m/Func/) { $rSensorArray->[$GPU_SENSORS_FUNC_OFFSET] = sprintf("0x%02X%02X", oct($type), oct($entID)); $rSensorArray->[$GPU_SENSORS_FUNC_OFFSET+1] = $sensorID; } elsif($name =~ m/Memory_Temp/) { $rSensorArray->[$GPU_SENSORS_MEM_TEMP_OFFSET] = sprintf("0x%02X%02X", oct($type), oct($entID)); $rSensorArray->[$GPU_SENSORS_MEM_TEMP_OFFSET+1] = $sensorID; } elsif($name =~ m/Temp/) { $rSensorArray->[$GPU_SENSORS_TEMP_OFFSET] = sprintf("0x%02X%02X", oct($type), oct($entID)); $rSensorArray->[$GPU_SENSORS_TEMP_OFFSET+1] = $sensorID; } $G_gpu_sensors{$obusslot_str} = $rSensorArray; } # Populates the G_slot_to_proc hash and updates the cfgID in G_gpu_sensors # This is how we map the obusslot to the GPU sensors sub addObusCfgToGpuSensors { my ($obusslot_str, $proc_target, $cfg) = @_; my $GPU_SENSORS_OBUS_CFG_OFFSET = 6; my $foundSlot = 0; $G_slot_to_proc{$obusslot_str} = $proc_target; foreach my $obusslot (keys %G_gpu_sensors) { if ($obusslot =~ m/$obusslot_str/) { # Add in the cfg number my $rSensorArray = $G_gpu_sensors{$obusslot_str}; $rSensorArray->[$GPU_SENSORS_OBUS_CFG_OFFSET] = sprintf("0x%02X", (oct($rSensorArray->[$GPU_SENSORS_OBUS_CFG_OFFSET]) | oct(numToBitPositionNum($cfg))) ); $foundSlot = 1; last; } } if (!$foundSlot) { print STDOUT sprintf("%s:%d ", __FILE__,__LINE__); print STDOUT "Found obus slot ($obusslot_str - processor $proc_target)". " not in G_gpu_sensors hash\n"; my $cfg_bit_num = numToBitPositionNum($cfg); $G_gpu_sensors{$obusslot_str} = ["0xFFFF","0xFF","0xFFFF","0xFF","0xFFFF", "0xFF", sprintf("0x02X",oct($cfg_bit_num))]; } } # @brief Returns whether system has multiple possible TPMs or not # # @par Detailed Description: # Returns whether system has multiple possible TPMs or not. # The MRW parser activates more complicated I2C master detection logic when # a system blueprint defines more than one TPM, in order to avoid having to # fix other non-compliant workbooks. If every workbook is determined to # model the TPM and its I2C connection properly, this special case can be # removed. # # @param[in] $targetsRef Reference to array of targets in the system # @retval 0 System does not have multiple possible TPMs # @retval 1 System has multiple possible TPMs # # @TODO RTC: 189374 Remove API when all platforms' MRW supports dynamically # determining the processor driving it. sub isMultiTpmSystem { my $targetsRef = shift; my $tpms=0; foreach my $target (@$targetsRef) { my $type = $targetObj->getType($target); if($type eq "TPM") { ++$tpms; if($tpms >1) { last; } } } return ($tpms > 1) ? 1 : 0; } #-------------------------------------------------- ## loop through all targets and do stuff my @targets = sort keys %{ $targetObj->getAllTargets() }; my $isMultiTpmSys = isMultiTpmSystem(\@targets); foreach my $target (@targets) { my $type = $targetObj->getType($target); if ($type eq "SYS") { processSystem($targetObj, $target); #TODO RTC: 178351 Remove depricated Attribute from HB XML #these are obsolete $targetObj->deleteAttribute($target,"FUSED_CORE_MODE"); $targetObj->deleteAttribute($target,"MRW_CDIMM_MASTER_I2C_TEMP_SENSOR_ENABLE"); $targetObj->deleteAttribute($target,"MRW_CDIMM_SPARE_I2C_TEMP_SENSOR_ENABLE"); $targetObj->deleteAttribute($target,"MRW_DRAMINIT_RESET_DISABLE"); $targetObj->deleteAttribute($target,"MRW_SAFEMODE_MEM_THROTTLE_NUMERATOR_PER_MBA"); $targetObj->deleteAttribute($target,"MRW_STRICT_MBA_PLUG_RULE_CHECKING"); $targetObj->deleteAttribute($target,"MSS_DRAMINIT_RESET_DISABLE"); $targetObj->deleteAttribute($target,"MSS_MRW_SAFEMODE_MEM_THROTTLED_N_COMMANDS_PER_SLOT"); $targetObj->deleteAttribute($target,"OPT_MEMMAP_GROUP_POLICY"); $targetObj->deleteAttribute($target,"PFET_POWERDOWN_DELAY_NS"); $targetObj->deleteAttribute($target,"PFET_POWERUP_DELAY_NS"); $targetObj->deleteAttribute($target,"PFET_VCS_VOFF_SEL"); $targetObj->deleteAttribute($target,"PFET_VDD_VOFF_SEL"); $targetObj->deleteAttribute($target,"SYSTEM_IVRMS_ENABLED"); $targetObj->deleteAttribute($target,"SYSTEM_RESCLK_ENABLE"); $targetObj->deleteAttribute($target,"SYSTEM_WOF_ENABLED"); $targetObj->deleteAttribute($target,"VDM_ENABLE"); $targetObj->deleteAttribute($target,"CHIP_HAS_SBE"); my $maxComputeNodes = get_max_compute_nodes($targetObj , $target); $targetObj->setAttribute($target, "MAX_COMPUTE_NODES_PER_SYSTEM", $maxComputeNodes); #handle enumeration changes my $enum_val = $targetObj->getAttribute($target,"PROC_FABRIC_PUMP_MODE"); if ( $enum_val =~ /MODE1/i) { $targetObj->setAttribute($target,"PROC_FABRIC_PUMP_MODE","CHIP_IS_NODE"); } elsif ( $enum_val =~ /MODE2/i) { $targetObj->setAttribute($target,"PROC_FABRIC_PUMP_MODE","CHIP_IS_GROUP"); } } elsif ($type eq "PROC") { processProcessor($targetObj, $target); if ($build eq "fsp") { do_plugin("fsp_proc", $targetObj, $target); } #TODO RTC: 178351 Remove depricated Attribute from HB XML #these are obsolete $targetObj->deleteAttribute($target,"CHIP_HAS_SBE"); $targetObj->deleteAttribute($target,"FSI_GP_REG_SCOM_ACCESS"); $targetObj->deleteAttribute($target,"I2C_SLAVE_ADDRESS"); $targetObj->deleteAttribute($target,"LPC_BASE_ADDR"); $targetObj->deleteAttribute($target,"NPU_MMIO_BAR_BASE_ADDR"); $targetObj->deleteAttribute($target,"NPU_MMIO_BAR_SIZE"); $targetObj->deleteAttribute($target,"PM_PFET_POWERDOWN_CORE_DELAY0"); $targetObj->deleteAttribute($target,"PM_PFET_POWERDOWN_CORE_DELAY1"); $targetObj->deleteAttribute($target,"PM_PFET_POWERDOWN_ECO_DELAY0"); $targetObj->deleteAttribute($target,"PM_PFET_POWERDOWN_ECO_DELAY1"); $targetObj->deleteAttribute($target,"PM_PFET_POWERUP_CORE_DELAY0"); $targetObj->deleteAttribute($target,"PM_PFET_POWERUP_CORE_DELAY1"); $targetObj->deleteAttribute($target,"PM_PFET_POWERUP_ECO_DELAY0"); $targetObj->deleteAttribute($target,"PM_PFET_POWERUP_ECO_DELAY1"); $targetObj->deleteAttribute($target,"PNOR_I2C_ADDRESS_BYTES"); $targetObj->deleteAttribute($target,"PROC_PCIE_NUM_IOP"); $targetObj->deleteAttribute($target,"PROC_PCIE_NUM_LANES"); $targetObj->deleteAttribute($target,"PROC_PCIE_NUM_PEC"); $targetObj->deleteAttribute($target,"PROC_PCIE_NUM_PHB"); $targetObj->deleteAttribute($target,"PROC_SECURITY_SETUP_VECTOR"); $targetObj->deleteAttribute($target,"SBE_SEEPROM_I2C_ADDRESS_BYTES"); } elsif ($type eq "APSS") { processApss($targetObj, $target); } elsif ($type eq "MEMBUF") { processMembuf($targetObj, $target); $targetObj->deleteAttribute($target,"CEN_MSS_VREF_CAL_CNTL"); } elsif ($type eq "PHB") { #TODO RTC: 178351 Remove depricated Attribute from HB XML $targetObj->deleteAttribute($target,"DEVICE_ID"); $targetObj->deleteAttribute($target,"HDDW_ORDER"); $targetObj->deleteAttribute($target,"MAX_POWER"); $targetObj->deleteAttribute($target,"MGC_LOAD_SOURCE"); $targetObj->deleteAttribute($target,"PCIE_32BIT_DMA_SIZE"); $targetObj->deleteAttribute($target,"PCIE_32BIT_MMIO_SIZE"); $targetObj->deleteAttribute($target,"PCIE_64BIT_DMA_SIZE"); $targetObj->deleteAttribute($target,"PCIE_64BIT_MMIO_SIZE"); $targetObj->deleteAttribute($target,"PCIE_CAPABILITES"); $targetObj->deleteAttribute($target,"PROC_PCIE_BAR_BASE_ADDR"); $targetObj->deleteAttribute($target,"PROC_PCIE_NUM_LANES"); $targetObj->deleteAttribute($target,"SLOT_INDEX"); $targetObj->deleteAttribute($target,"SLOT_NAME"); $targetObj->deleteAttribute($target,"VENDOR_ID"); } # @TODO RTC: 189374 Remove multiple TPMs filter when all platforms' MRW # supports dynamically determining the processor driving it. elsif (($type eq "TPM") && $isMultiTpmSys) { processTpm($targetObj, $target); } elsif ($type eq "POWER_SEQUENCER") { my $target_type = $targetObj->getTargetType($target); # Strip off the chip- part of the target type name $target_type =~ s/chip\-//g; # Currently only UCD9090 and UCD90120A on FSP systems are supported. # All other UCD types are skipped. if (($target_type eq "UCD9090") || ($target_type eq "UCD90120A")) { processUcd($targetObj, $target); } } elsif ($type eq "OCMB_CHIP") { processOcmbChip($targetObj, $target); } processIpmiSensors($targetObj,$target); } if ($build eq "fsp") { processMrw_fsp::loadFSP($targetObj); } ## check topology foreach my $n (keys %{$targetObj->{TOPOLOGY}}) { foreach my $p (keys %{$targetObj->{TOPOLOGY}->{$n}}) { if ($targetObj->{TOPOLOGY}->{$n}->{$p} > 1) { print "ERROR: Fabric topology invalid. 2 targets have same ". "FABRIC_GROUP_ID,FABRIC_CHIP_ID ($n,$p)\n"; $targetObj->myExit(3); } } } ## check for errors foreach my $target (keys %{ $targetObj->getAllTargets() }) { errorCheck($targetObj, $target); } #-------------------------------------------------- ## write out final XML my $xml_fh; my $filename; my $config_str = $system_config; #If user did not specify the output filename, then build one up by using #config and build parameters if ($output_filename eq "") { if ($config_str ne "") { $config_str = "_" . $config_str; } $filename = $xmldir . "/" . $targetObj->getSystemName() . $config_str . "_" . $build . ".mrw.xml"; } else { $filename = $output_filename; } print "Creating XML: $filename\n"; open($xml_fh, ">$filename") || die "Unable to create: $filename"; $targetObj->printXML($xml_fh, "top", $build); close $xml_fh; if (!$targetObj->{errorsExist}) { ## optionally print out report if ($report) { print "Writing report to: ".$targetObj->{report_filename}."\n"; $targetObj->writeReportFile(); } print "MRW created successfully!\n"; } #-------------------------------------------------- #-------------------------------------------------- ## Processing subroutines #-------------------------------------------------- #-------------------------------------------------- ## System ## sub processSystem { my $targetObj = shift; my $target = shift; $targetObj->setAttribute($target, "MAX_MCS_PER_SYSTEM", $targetObj->{NUM_PROCS_PER_NODE} * $targetObj->{MAX_MCS}); $targetObj->setAttribute($target, "MAX_PROC_CHIPS_PER_NODE", $targetObj->{NUM_PROCS_PER_NODE}); parseBitwise($targetObj,$target,"CDM_POLICIES"); #Delete this attribute if it is leftover from an old format if (!$targetObj->isBadAttribute($target,"XSCOM_BASE_ADDRESS") ) { $targetObj->deleteAttribute($target,"XSCOM_BASE_ADDRESS"); } # TODO RTC:170860 - Remove this after dimm connector defines VDDR_ID my $system_name = $targetObj->getAttribute($target,"SYSTEM_NAME"); if ($system_name =~ /ZAIUS/i) { $num_voltage_rails_per_proc = 2; } # TODO RTC:182764 -- right now there is no support for CDIMMs. So, # we don't know what to base these attributes off of. But, once # we get CDIMM support in processMrw, then we should base these # attributes on the type of DIMMs if ($system_name =~ /ZEPPELIN/i) { #Zeppelin has ISDIMM with 10K VPD $targetObj->setAttribute($target, "CVPD_SIZE", 0x2800); $targetObj->setAttribute($target, "CVPD_MAX_SECTIONS", 25); } elsif ($system_name =~ /FLEETWOOD/i) { #Fleetwood has CDIMM with 4K VPD $targetObj->setAttribute($target, "CVPD_SIZE", 0x1000); $targetObj->setAttribute($target, "CVPD_MAX_SECTIONS", 64); } } sub processIpmiSensors { my $targetObj=shift; my $target=shift; if ($targetObj->isBadAttribute($target,"IPMI_INSTANCE") || $targetObj->getMrwType($target) eq "IPMI_SENSOR" || $targetObj->getTargetChildren($target) eq "") { return; } my $instance=$targetObj->getAttribute($target,"IPMI_INSTANCE"); my $name=""; if (!$targetObj->isBadAttribute($target,"FRU_NAME")) { $name=$targetObj->getAttribute($target,"FRU_NAME"); } my $fru_id="N/A"; if (!$targetObj->isBadAttribute($target,"FRU_ID")) { $fru_id=$targetObj->getAttribute($target,"FRU_ID"); } my $huid=""; if (!$targetObj->isBadAttribute($target,"HUID")) { $huid=$targetObj->getAttribute($target,"HUID"); } my @sensors; my %sensorIdsCnt; foreach my $child (@{$targetObj->getTargetChildren($target)}) { if ($targetObj->getMrwType($child) eq "IPMI_SENSOR") { my $entity_id=$targetObj-> getAttribute($child,"IPMI_ENTITY_ID"); my $sensor_type=$targetObj-> getAttribute($child,"IPMI_SENSOR_TYPE"); my $name_suffix=$targetObj-> getAttribute($child,"IPMI_SENSOR_NAME_SUFFIX"); my $sensor_id=$targetObj-> getAttribute($child,"IPMI_SENSOR_ID"); my $sensor_evt=$targetObj-> getAttribute($child,"IPMI_SENSOR_READING_TYPE"); $name_suffix=~s/\n//g; $name_suffix=~s/\s+//g; $name_suffix=~s/\t+//g; my $sensor_name=$name_suffix; if ($name ne "") { $sensor_name=$name."_".$name_suffix; } my $attribute_name=""; my $s=sprintf("0x%02X%02X,0x%02X", oct($sensor_type),oct($entity_id),oct($sensor_id)); push(@sensors,$s); my $sensor_id_str = ""; if ($sensor_id ne "") { $sensor_id_str = sprintf("0x%02X",oct($sensor_id)); } my $str=sprintf( " %30s | %10s | 0x%02X | 0x%02X | 0x%02x |" . " %4s | %4d | %4d | %10s | %s\n", $sensor_name,$name,oct($entity_id),oct($sensor_type), oct($sensor_evt), $sensor_id_str,$instance,$fru_id, $huid,$target); # Check that the sensor id hasn't already been used. Don't check # blank sensor ids. if (($sensor_id ne "") && (++$sensorIdsCnt{$sensor_id} >= 2)) { print "ERROR: Duplicate IPMI_SENSOR_ID ($sensor_id_str)" . " found in MRW. Sensor name is $sensor_name.\n"; print "$str"; $targetObj->myExit(3); } $targetObj->writeReport($str); if ($name =~ /^GPU\d$/) { addSensorToGpuSensors($sensor_name, $target, $sensor_type, $entity_id, $sensor_id_str); } } } for (my $i=@sensors;$i<16;$i++) { push(@sensors,"0xFFFF,0xFF"); } my @sensors_sort = sort(@sensors); $targetObj->setAttribute($target, "IPMI_SENSORS",join(',',@sensors_sort)); } sub processApss { my $targetObj=shift; my $target=shift; my $systemTarget = $targetObj->getTargetParent($target); my @sensors; my @channel_ids; my @channel_offsets; my @channel_gains; my @channel_grounds; my @gpios; foreach my $child (@{$targetObj->getTargetChildren($target)}) { if ($targetObj->getMrwType($child) eq "APSS_SENSOR") { my $entity_id=$targetObj-> getAttribute($child,"IPMI_ENTITY_ID"); my $sensor_id=$targetObj-> getAttribute($child,"IPMI_SENSOR_ID"); my $sensor_type=$targetObj-> getAttribute($child,"IPMI_SENSOR_TYPE"); my $sensor_evt=$targetObj-> getAttribute($child,"IPMI_SENSOR_READING_TYPE"); #@fixme-RTC:175309-Remove deprecated support my $name; my $channel; my $channel_id; my $channel_gain; my $channel_offset; my $channel_ground; # Temporarily allow both old and new attribute names until # all of the SW2 xmls get in sync if (!$targetObj->isBadAttribute($child,"IPMI_SENSOR_NAME_SUFFIX") ) { # Using deprecated names $name = $targetObj-> getAttribute($child,"IPMI_SENSOR_NAME_SUFFIX"); $channel = $targetObj-> getAttribute($child,"ADC_CHANNEL_ASSIGNMENT"); $channel_id = $targetObj-> getAttribute($child,"ADC_CHANNEL_ID"); $channel_gain = $targetObj-> getAttribute($child,"ADC_CHANNEL_GAIN"); $channel_offset = $targetObj-> getAttribute($child,"ADC_CHANNEL_OFFSET"); $channel_ground = $targetObj-> getAttribute($child,"ADC_CHANNEL_GROUND"); } else { # Using correct/new names $name = $targetObj-> getAttribute($child,"FUNCTION_NAME"); $channel = $targetObj-> getAttribute($child,"CHANNEL"); $channel_id = $targetObj-> getAttribute($child,"FUNCTION_ID"); $channel_gain = $targetObj-> getAttribute($child,"GAIN"); $channel_offset = $targetObj-> getAttribute($child,"OFFSET"); $channel_ground = $targetObj-> getAttribute($child,"GND"); } $name=~s/\n//g; $name=~s/\s+//g; $name=~s/\t+//g; my $sensor_id_str = ""; if ($sensor_id ne "") { $sensor_id_str = sprintf("0x%02X",oct($sensor_id)); } if ($channel ne "") { $sensors[$channel] = $sensor_id_str; $channel_ids[$channel] = $channel_id; $channel_grounds[$channel] = $channel_ground; $channel_offsets[$channel] = $channel_offset; $channel_gains[$channel] = $channel_gain; } my $str=sprintf( " %30s | %10s | 0x%02X | 0x%02X | 0x%02x |" . " %4s | %4d | %4d | %10s | %s\n", $name,"",oct($entity_id),oct($sensor_type), oct($sensor_evt),$sensor_id_str,$channel,"","", $systemTarget); $targetObj->writeReport($str); } elsif ($targetObj->getMrwType($child) eq "APSS_GPIO") { my $function_id=$targetObj-> getAttribute($child,"FUNCTION_ID"); my $port=$targetObj-> getAttribute($child,"PORT"); if ($port ne "") { $gpios[$port] = $function_id; } } } for (my $i=0;$i<16;$i++) { if ($sensors[$i] eq "") { $sensors[$i]="0x00"; } if ($channel_ids[$i] eq "") { $channel_ids[$i]="0"; } if ($channel_grounds[$i] eq "") { $channel_grounds[$i]="0"; } if ($channel_gains[$i] eq "") { $channel_gains[$i]="0"; } if ($channel_offsets[$i] eq "") { $channel_offsets[$i]="0"; } if ($gpios[$i] eq "") { $gpios[$i]="0"; } } $targetObj->setAttribute($systemTarget, "ADC_CHANNEL_FUNC_IDS",join(',',@channel_ids)); $targetObj->setAttribute($systemTarget, "ADC_CHANNEL_SENSOR_NUMBERS",join(',',@sensors)); $targetObj->setAttribute($systemTarget, "ADC_CHANNEL_GNDS",join(',',@channel_grounds)); $targetObj->setAttribute($systemTarget, "ADC_CHANNEL_GAINS",join(',',@channel_gains)); $targetObj->setAttribute($systemTarget, "ADC_CHANNEL_OFFSETS",join(',',@channel_offsets)); $targetObj->setAttribute($systemTarget, "APSS_GPIO_PORT_PINS",join(',',@gpios)); convertNegativeNumbers($targetObj,$systemTarget,"ADC_CHANNEL_OFFSETS",32); } sub convertNegativeNumbers { my $targetObj=shift; my $target=shift; my $attribute=shift; my $numbits=shift; my @offset = split(/\,/, $targetObj->getAttribute($target,$attribute)); for (my $i=0;$i<@offset;$i++) { if ($offset[$i]<0) { my $neg_offset = 2**$numbits+$offset[$i]; $offset[$i]=sprintf("0x%08X",$neg_offset); } } my $new_offset = join(',',@offset); $targetObj->setAttribute($target,$attribute,$new_offset) } sub parseBitwise { my $targetObj = shift; my $target = shift; my $attribute = shift; my $mask = 0; #if CDM_POLICIES_BITMASK is not a bad attribute, aka if it is defined if (!$targetObj->isBadAttribute($target, $attribute."_BITMASK")) { foreach my $e (keys %{ $targetObj->getEnumHash($attribute)}) { my $field = $targetObj->getAttributeField( $target,$attribute."_BITMASK",$e); my $val=hex($targetObj->getEnumValue($attribute,$e)); if ($field eq "true") { $mask=$mask | $val; } } $targetObj->setAttribute($target,$attribute,$mask); } } # @brief Processes a TPM target # # @par Detailed Description: # Processes a TPM target; notably determines the TPM's I2C master chip and # updates the associated field in the TPM_INFO attribute, especially useful # on multi-node or multi-TPM systems. # # @param[in] $targetObj Object model reference # @param[in] $target Handle of the target to process sub processTpm { my $targetObj = shift; my $target = shift; # Get any connection involving TPM target's child I2C slave targets my $i2cBuses=$targetObj->findDestConnections($target,"I2C",""); if ($i2cBuses ne "") { foreach my $i2cBus (@{$i2cBuses->{CONN}}) { # On the I2C master side of the connection, ascend one level to the # parent chip my $i2cMasterParentTarget=$i2cBus->{SOURCE_PARENT}; my $i2cMasterParentTargetType = $targetObj->getType($i2cMasterParentTarget); # Hostboot code assumes CEC TPMs are only connected to processors. # Unless that assumption changes, this sanity check is required to # catch modeling errors. if($i2cMasterParentTargetType ne "PROC") { die "Model integrity error; CEC TPM I2C connections must " . "originate at a PROC target, not a " . "$i2cMasterParentTargetType target.\n"; } # Get its physical path my $i2cMasterParentTargetPath = $targetObj->getAttribute( $i2cMasterParentTarget,"PHYS_PATH"); # Set the TPM's I2C master path accordingly $targetObj->setAttributeField( $target, "TPM_INFO","i2cMasterPath", $i2cMasterParentTargetPath); # All TPM I2C buses must be driven from the same I2C master, so only # process the first one last; } } } sub processUcd { my $targetObj = shift; my $target = shift; # Get any connection involving UCD target's child I2C slave targets my $i2cBuses=$targetObj->findDestConnections($target,"I2C",""); if ($i2cBuses ne "") { foreach my $i2cBus (@{$i2cBuses->{CONN}}) { # On the I2C master side of the connection, ascend one level to the # parent chip my $i2cMasterParentTarget=$i2cBus->{SOURCE_PARENT}; my $i2cMasterParentTargetType = $targetObj->getType($i2cMasterParentTarget); # Hostboot code assumes UCDs are only connected to processors. if($i2cMasterParentTargetType ne "PROC") { die "Model integrity error; UCD I2C connections must " . "originate at a PROC target, not a " . "$i2cMasterParentTargetType target.\n"; } # Get the processor's physical path my $i2cMasterParentTargetPath = $targetObj->getAttribute( $i2cMasterParentTarget,"PHYS_PATH"); # Set the UCD's I2C master path accordingly $targetObj->setAttributeField( $target, "I2C_CONTROL_INFO","i2cMasterPath", $i2cMasterParentTargetPath); # Set the UCD's I2C port and engine by accessing the # i2cMaster target and getting the data from it. my $i2cMaster = $i2cBus->{SOURCE}; my $i2cPort = $targetObj->getAttribute($i2cMaster, "I2C_PORT"); my $i2cEngine = $targetObj->getAttribute($i2cMaster, "I2C_ENGINE"); $targetObj->setAttributeField($target, "I2C_CONTROL_INFO", "port", $i2cPort); $targetObj->setAttributeField($target, "I2C_CONTROL_INFO", "engine", $i2cEngine); # Set the UCD's device address by accessing the bus my $addr = ""; if ($targetObj->isBusAttributeDefined( $i2cBus->{SOURCE},$i2cBus->{BUS_NUM},"I2C_ADDRESS")) { $addr = $targetObj->getBusAttribute($i2cBus->{SOURCE}, $i2cBus->{BUS_NUM}, "I2C_ADDRESS"); } # If bus doesn't have I2C_ADDRESS or default value is not set, # then get it from i2c-slave, if defined. if ($addr eq "") { if (! $targetObj->isBadAttribute($i2cBus->{DEST},"I2C_ADDRESS")) { $addr = $targetObj->getAttribute($i2cBus->{DEST}, "I2C_ADDRESS"); } } #if the addr is still not defined, then throw an error if ($addr eq "") { print ("ERROR: I2C_ADDRESS is not defined for $i2cBus\n"); $targetObj->myExit(4); } $targetObj->setAttributeField( $target, "I2C_CONTROL_INFO","devAddr",$addr); last; } } } #-------------------------------------------------- ## Processor ## sub processProcessor { my $targetObj = shift; my $target = shift; ######################### ## In serverwiz, processor instances are not unique ## because plugged into socket ## so processor instance unique attributes are socket level. ## The grandparent is guaranteed to be socket. my $socket_target = $targetObj->getTargetParent($targetObj->getTargetParent($target)); $targetObj->copyAttribute($socket_target,$target,"LOCATION_CODE"); ## Module attibutes are inherited into the proc target my $module_target = $targetObj->getTargetParent($target); $targetObj->copyAttribute($module_target,$target,"LOCATION_CODE"); ## Copy PCIE attributes from socket ## Copy Position attribute from socket ## Copy PBAX attributes from socket foreach my $attr (sort (keys %{ $targetObj->getTarget($socket_target)->{TARGET}->{attribute} })) { if ($attr =~ /PROC\_PCIE/) { $targetObj->copyAttribute($socket_target,$target,$attr); } elsif ($attr =~/POSITION/) { $targetObj->copyAttribute($socket_target,$target,$attr); } elsif ($attr =~/PBAX_BRDCST_ID_VECTOR/) { $targetObj->copyAttribute($socket_target,$target,$attr); } elsif ($attr =~/PBAX_CHIPID/) { $targetObj->copyAttribute($socket_target,$target,$attr); } elsif ($attr =~/PBAX_GROUPID/) { $targetObj->copyAttribute($socket_target,$target,$attr); } elsif ($attr =~/PM_PBAX_NODEID/) { $targetObj->copyAttribute($socket_target,$target,$attr); } elsif ($attr =~/NO_APSS_PROC_POWER_VCS_VIO_WATTS/) { $targetObj->copyAttribute($socket_target,$target,$attr); } } # I2C arrays my @engine = (); my @port = (); my @slavePort = (); my @addr = (); my @speed = (); my @type = (); my @purpose = (); my @label = (); $targetObj->log($target, "Processing PROC"); foreach my $child (@{ $targetObj->getTargetChildren($target) }) { my $child_type = $targetObj->getType($child); $targetObj->log($target, "Processing PROC child: $child Type: $child_type"); if ($child_type eq "NA" || $child_type eq "FSI") { $child_type = $targetObj->getMrwType($child); } if ($child_type eq "XBUS") { processXbus($targetObj, $child); } elsif ($child_type eq "OBUS") { processObus($targetObj, $child); #handle enumeration changes my $enum_val = $targetObj->getAttribute($child,"OPTICS_CONFIG_MODE"); if ( $enum_val =~ /NVLINK/i) { $targetObj->setAttribute($child,"OPTICS_CONFIG_MODE","NV"); } } elsif ($child_type eq "FSIM" || $child_type eq "FSICM") { processFsi($targetObj, $child, $target); } elsif ($child_type eq "PEC") { processPec($targetObj, $child, $target); } elsif ($child_type eq "MCBIST") { processMcbist($targetObj, $child, $target); # TODO RTC:170860 - Eventually the dimm connector will # contain this information and this can be removed my $socket_pos = $targetObj->getAttribute($socket_target, "POSITION"); if ($num_voltage_rails_per_proc > 1) { my $mcbist_pos = $targetObj->getAttribute($child, "CHIP_UNIT"); $targetObj->setAttribute($child, "VDDR_ID", $socket_pos*$num_voltage_rails_per_proc + $mcbist_pos); } else { $targetObj->setAttribute($child, "VDDR_ID", $socket_pos); } } elsif ($child_type eq "MC") { processMc($targetObj, $child); } elsif ($child_type eq "EQ") { processEq($targetObj, $child); } elsif ($child_type eq "OCC") { processOcc($targetObj, $child, $target); } # Ideally this should be $child_type eq "I2C", but we need a change # in serverwiz and the witherspoon.xml first elsif (index($child,"i2c-master") != -1) { my ($i2cEngine, $i2cPort, $i2cSlavePort, $i2cAddr, $i2cSpeed, $i2cType, $i2cPurpose, $i2cLabel) = processI2C($targetObj, $child, $target); # Add this I2C device's information to the proc array push(@engine,@$i2cEngine); push(@port,@$i2cPort); push(@slavePort,@$i2cSlavePort); push(@addr,@$i2cAddr); push(@speed,@$i2cSpeed); push(@type,@$i2cType); push(@purpose,@$i2cPurpose); push(@label, @$i2cLabel); } } # Add GPU sensors to processor my @aGpuSensors = (); foreach my $obusslot (sort keys %G_gpu_sensors) { # find matching obusslot to processor my $proc_target = $G_slot_to_proc{$obusslot}; # if a processor target is found and it is the same as this target if ($proc_target && ($target =~ m/$proc_target/)) { # Add this GPU's sensors to the processor's array of GPU sensors push (@aGpuSensors, @{ $G_gpu_sensors{$obusslot} }); } } if (@aGpuSensors) { # add GPU_SENSORS to this processor target $targetObj->setAttribute( $target, "GPU_SENSORS", join(',', @aGpuSensors) ); } # Add final I2C arrays to processor my $size = scalar @engine; my $engine_attr = $engine[0]; my $port_attr = $port[0]; my $slave_attr = $slavePort[0]; my $addr_attr = $addr[0]; my $speed_attr = $speed[0]; my $type_attr = $type[0]; my $purpose_attr = $purpose[0]; my $label_attr = $label[0]; # Parse out array to print as a string foreach my $n (1..($size-1)) { $engine_attr .= ",".$engine[$n]; $port_attr .= ",".$port[$n]; $slave_attr .= ",".$slavePort[$n]; $addr_attr .= ",".$addr[$n]; $speed_attr .= ",".$speed[$n]; $type_attr .= ",".$type[$n]; $purpose_attr .= ",".$purpose[$n]; $label_attr .= ",".$label[$n]; } # Set the arrays to the corresponding attribute on the proc $targetObj->setAttribute($target,"HDAT_I2C_ENGINE",$engine_attr); $targetObj->setAttribute($target,"HDAT_I2C_MASTER_PORT",$port_attr); $targetObj->setAttribute($target,"HDAT_I2C_SLAVE_PORT",$slave_attr); $targetObj->setAttribute($target,"HDAT_I2C_ADDR",$addr_attr); $targetObj->setAttribute($target,"HDAT_I2C_BUS_FREQ",$speed_attr); $targetObj->setAttribute($target,"HDAT_I2C_DEVICE_TYPE",$type_attr); $targetObj->setAttribute($target,"HDAT_I2C_DEVICE_PURPOSE",$purpose_attr); $targetObj->setAttribute($target,"HDAT_I2C_DEVICE_LABEL", $label_attr); $targetObj->setAttribute($target,"HDAT_I2C_ELEMENTS",$size); ## update path for mvpd's and sbe's my $path = $targetObj->getAttribute($target, "PHYS_PATH"); my $model = $targetObj->getAttribute($target, "MODEL"); $targetObj->setAttributeField($target, "EEPROM_VPD_PRIMARY_INFO","i2cMasterPath",$path); $targetObj->setAttributeField($target, "EEPROM_VPD_BACKUP_INFO","i2cMasterPath",$path); $targetObj->setAttributeField($target, "EEPROM_SBE_PRIMARY_INFO","i2cMasterPath",$path); $targetObj->setAttributeField($target, "EEPROM_SBE_BACKUP_INFO","i2cMasterPath",$path); ## need to initialize the master processor's FSI connections here my $proc_type = $targetObj->getAttribute($target, "PROC_MASTER_TYPE"); if ($proc_type eq "ACTING_MASTER" ) { if($targetObj->isBadAttribute($target, "FSI_MASTER_TYPE")) { $targetObj->setAttributeField($target, "FSI_OPTION_FLAGS", "reserved", "0"); $targetObj->setAttribute($target, "FSI_MASTER_CHIP", "physical:sys-0"); $targetObj->setAttribute($target, "FSI_MASTER_PORT", "0xFF"); $targetObj->setAttribute($target, "ALTFSI_MASTER_CHIP", "physical:sys-0"); $targetObj->setAttribute($target, "ALTFSI_MASTER_PORT", "0xFF"); $targetObj->setAttribute($target, "FSI_MASTER_TYPE", "NO_MASTER"); } $targetObj->setAttribute($target, "FSI_SLAVE_CASCADE", "0"); $targetObj->setAttributeField($target, "SCOM_SWITCHES", "useSbeScom", "1"); $targetObj->setAttributeField($target, "SCOM_SWITCHES", "useFsiScom", "0"); } else { if($targetObj->isBadAttribute($target, "ALTFSI_MASTER_CHIP")) { $targetObj->setAttribute($target, "ALTFSI_MASTER_CHIP", "physical:sys-0"); } $targetObj->setAttributeField($target, "SCOM_SWITCHES", "useSbeScom", "0"); $targetObj->setAttributeField($target, "SCOM_SWITCHES", "useFsiScom", "1"); } ## Update bus speeds processI2cSpeeds($targetObj,$target); ## these are hardcoded because code sets them properly $targetObj->setAttributeField($target, "SCOM_SWITCHES", "reserved", "0"); $targetObj->setAttributeField($target, "SCOM_SWITCHES", "useInbandScom", "0"); $targetObj->setAttributeField($target, "SCOM_SWITCHES", "useXscom", "0"); $targetObj->setAttributeField($target, "SCOM_SWITCHES", "useI2cScom","0"); ## default effective fabric ids to match regular fabric ids ## the value will be adjusted based on presence detection later $targetObj->setAttribute($target, "PROC_EFF_FABRIC_GROUP_ID", $targetObj->getAttribute($target, "FABRIC_GROUP_ID")); $targetObj->setAttribute($target, "PROC_EFF_FABRIC_CHIP_ID", $targetObj->getAttribute($target, "FABRIC_CHIP_ID")); processMembufVpdAssociation($targetObj,$target); #TODO RTC: 191762 -- Need a generic way to source FABRIC_GROUP_ID and #FABRIC_CHIP_ID from the MRW and select the right value in processMRW #based on the system configuration we are compiling for. if ($system_config eq "w") { my $huid_str = $targetObj->getAttribute($target, "HUID"); my $huid = hex $huid_str; my $grp_id = $targetObj->getAttribute($target,"FABRIC_GROUP_ID"); my $chip_id = $targetObj->getAttribute($target,"FABRIC_CHIP_ID"); if ($huid eq 0x50000) { $grp_id = 0; $chip_id = 0; } elsif ($huid eq 0x50001) { $grp_id = 1; $chip_id = 1; } elsif ($huid eq 0x50002) { $grp_id = 0; $chip_id = 1; } elsif ($huid eq 0x50003) { $grp_id = 1; $chip_id = 0; } else { #This is super ugly hack to make sure FABRIC_GROUP_ID and #FABRIC_CHIP_ID are unique in the entire system. But, it #doesn't matter what they are for other drawers as for #wrap config we only care about one drawer $grp_id += 1; } $targetObj->setAttribute($target,"FABRIC_GROUP_ID",$grp_id); $targetObj->setAttribute($target,"FABRIC_CHIP_ID",$chip_id); $targetObj->setAttribute($target,"PROC_EFF_FABRIC_GROUP_ID",$grp_id); $targetObj->setAttribute($target,"PROC_EFF_FABRIC_CHIP_ID",$chip_id); } setupBars($targetObj,$target); $targetObj->setAttribute($target, "PROC_MEM_TO_USE", ( $targetObj->getAttribute($target, "FABRIC_GROUP_ID") << 3)); processPowerRails ($targetObj, $target); } sub processPowerRails { my $targetObj = shift; my $target = shift; #Example of how system xml is getting parsed into data structures here #and eventually into the attribute # #System XML has this: # # vrm3-connector-22/vrm-type3-10/35219-3-8/IR35219_special.vout-0 => fcdimm-connector-69/fcdimm-14/membuf-0/MemIO # POWER # no # vrm3-connector-22/vrm-type3-10/35219-3-8/ # IR35219_special.vout-0 # fcdimm-connector-69/fcdimm-14/membuf-0/ # MemIO # # CLASS # BUS # # # #each of the connection comes up like this (this is $rail variable) # 'BUS_NUM' => 0, # 'DEST_PARENT' => '/sys/node-4/calliope-1/fcdimm-connector-69/fcdimm-14/membuf-0', # 'DEST' => '/sys/node-4/calliope-1/fcdimm-connector-69/fcdimm-14/membuf-0/MemIO', # 'SOURCE_PARENT' => '/sys/node-4/calliope-1/vrm3-connector-22/vrm-type3-10/35219-3-8', # 'SOURCE' => '/sys/node-4/calliope-1/vrm3-connector-22/vrm-type3-10/35219-3-8/IR35219_special.vout-0' # #So, for 'SOURCE' target, we walk up the hierarchy till we get to #vrm3-connector-22 as that is the first target in the hierarchy that #is unique per instance of a given volate rail. We get vrm connector's #POSITION and set it as the ID for that rail. # #The 'DEST' target also has an attribute called "RAIL_NAME" that we can use #to figure out which rail we are working with. But, for rails that are #common between proc and centaur have "Cent" or "Mem" as a prefix. # my $rails=$targetObj->findDestConnections($target,"POWER",""); if ($rails ne "") { foreach my $rail (@{$rails->{CONN}}) { my $rail_dest = $rail->{DEST}; my $rail_src = $rail->{SOURCE}; my $rail_name = $targetObj->getAttribute($rail_dest, "RAIL_NAME"); #Need to get the connector's position and set the ID to that #As it is unique for every new connection in the MRW my $rail_connector = $targetObj->getTargetParent( #VRM connector ($targetObj->getTargetParent #VRM type ($targetObj->getTargetParent($rail_src)))); my $position = $targetObj->getAttribute($rail_connector,"POSITION"); my $rail_attr_id = ($targetObj->getAttribute($target, "TYPE") eq "PROC") ? "NEST_" : ""; #The rails that are common between proc and centaur have a "Cent" #prefix in the system xml. We don't care for "Cent" in our attribute #as it is scoped to the right target. But, for VIO, we decided to #use MemIO rather than CentIO. The attribute is named as VIO_ID. $rail_name =~ s/Cent//g; $rail_name =~ s/Mem/V/g; $rail_attr_id .= $rail_name . "_ID"; $targetObj->setAttribute($target, $rail_attr_id, $position); } } } sub processI2cSpeeds { my $targetObj = shift; my $target = shift; my @bus_speeds; my $bus_speed_attr=$targetObj->getAttribute($target,"I2C_BUS_SPEED_ARRAY"); my @bus_speeds2 = split(/,/,$bus_speed_attr); #need to create a 4X13 array my $i = 0; for my $engineIdx (0 .. 3) { for my $portIdx (0 .. 12) { $bus_speeds[$engineIdx][$portIdx] = $bus_speeds2[$i]; $i++; } } my $i2cs=$targetObj->findConnections($target,"I2C",""); if ($i2cs ne "") { foreach my $i2c (@{$i2cs->{CONN}}) { my $dest_type = $targetObj->getTargetType($i2c->{DEST_PARENT}); my $parent_target =$targetObj->getTargetParent($i2c->{DEST_PARENT}); if ($dest_type eq "chip-spd-device") { setEepromAttributes($targetObj, "EEPROM_VPD_PRIMARY_INFO",$parent_target, $i2c); } elsif ($dest_type eq "chip-dimm-thermal-sensor") { setDimmTempAttributes($targetObj, $parent_target, $i2c); } my $port=oct($targetObj->getAttribute($i2c->{SOURCE},"I2C_PORT")); my $engine=oct($targetObj->getAttribute( $i2c->{SOURCE},"I2C_ENGINE")); my $bus_speed=$targetObj->getBusAttribute( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_SPEED"); if ($bus_speed eq "" || $bus_speed==0) { print "ERROR: I2C bus speed not defined for $i2c->{SOURCE}\n"; $targetObj->myExit(3); } ## choose lowest bus speed if ($bus_speeds[$engine][$port] eq "" || $bus_speeds[$engine][$port]==0 || $bus_speed < $bus_speeds[$engine][$port]) { $bus_speeds[$engine][$port] = $bus_speed; } } } #need to flatten 4x13 array $bus_speed_attr = ""; for my $engineIdx (0 .. 3) { for my $portIdx (0 .. 12) { $bus_speed_attr .= $bus_speeds[$engineIdx][$portIdx] . ","; } } #remove last , $bus_speed_attr =~ s/,$//; $targetObj->setAttribute($target,"I2C_BUS_SPEED_ARRAY",$bus_speed_attr); } ################################ ## Setup address map sub setupBars { my $targetObj = shift; my $target = shift; #-------------------------------------------------- ## Setup BARs my $group = $targetObj->getAttribute($target, "FABRIC_GROUP_ID"); my $proc = $targetObj->getAttribute($target, "FABRIC_CHIP_ID"); $targetObj->{TOPOLOGY}->{$group}->{$proc}++; #P9 has a defined memory map for all configurations, #these are the base addresses for group0-chip0. #Each chip in the group has its own 4TB space, #which each group being 32TB of space. my %bars=( "FSP_BASE_ADDR" => 0x0006030100000000, "PSI_BRIDGE_BASE_ADDR" => 0x0006030203000000, "INTP_BASE_ADDR" => 0x0003FFFF80300000, "PSI_HB_ESB_ADDR" => 0x00060302031C0000, "XIVE_CONTROLLER_BAR_ADDR" => 0x0006030203100000); #Note - Not including XSCOM_BASE_ADDRESS and LPC_BUS_ADDR in here # because Hostboot code itself writes those on every boot if (!$targetObj->isBadAttribute($target,"XSCOM_BASE_ADDRESS") ) { $targetObj->deleteAttribute($target,"XSCOM_BASE_ADDRESS"); } if (!$targetObj->isBadAttribute($target,"LPC_BUS_ADDR") ) { $targetObj->deleteAttribute($target,"LPC_BUS_ADDR"); } my $groupOffset = 0x200000000000; my $procOffset = 0x40000000000; foreach my $bar (keys %bars) { my $i_base = Math::BigInt->new($bars{$bar}); my $value=sprintf("0x%016s",substr(( $i_base+$groupOffset*$group+ $procOffset*$proc)->as_hex(),2)); $targetObj->setAttribute($target,$bar,$value); } } #-------------------------------------------------- ## MCS ## sub processMcs { my $targetObj = shift; my $target = shift; my $parentTarget = shift; my $group = shift; my $proc = shift; #@FIXME RTC:168611 To decouple DVPD from PVPD #parentTarget == MCBIST #parent(MCBIST) = Proc #parent(proc) = module #parent(module) = socket #parent(socket) = motherboard #parent(motherboard) = node my $node = $targetObj->getTargetParent( #node $targetObj->getTargetParent( #motherboard $targetObj->getTargetParent #socket ($targetObj->getTargetParent #module ($targetObj->getTargetParent($parentTarget))))); my $name = "EEPROM_VPD_PRIMARY_INFO"; $targetObj->copyAttributeFields($node, $target, "EEPROM_VPD_PRIMARY_INFO"); # MEMVPD_POS is relative to the EEPROM containing the MEMD record # associated with this MCS, since all MCS are sharing the same # VPD record (see VPD_REC_NUM hardcode in Targets.pm) that means all # MCS need a unique position my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); my $proctarg = $targetObj->getTargetParent( $parentTarget ); my $proc_num = $targetObj->getAttribute($proctarg, "POSITION"); $targetObj->setAttribute( $target, "MEMVPD_POS", $chip_unit + ($proc_num * MAX_MCS_PER_PROC) ); foreach my $child (@{ $targetObj->getTargetChildren($target) }) { my $child_type = $targetObj->getType($child); $targetObj->log($target, "Processing MCS child: $child Type: $child_type"); if ($child_type eq "MCA") { processMca($targetObj, $child); } } { use integer; # There are a total of two MCS units on an MCBIST unit. So, to # determine which MCBIST an MCS belongs to, the CHIP_UNIT of the MCS can # be divided by the number of units per MCBIST to arrive at the correct # offset to add to the pervasive MCS parent offset. my $numberOfMcsPerMcbist = 2; my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_MCS_OFFSET + ($chip_unit / $numberOfMcsPerMcbist)); $targetObj->setAttribute( $target, "CHIPLET_ID", $value); } } sub processMca { use integer; my $targetObj = shift; my $target = shift; my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); # There are a total of four MCA units on an MCBIST unit. So, to determine # which MCBIST an MCA belongs to, the CHIP_UNIT of the MCA can be divided by # the number of units per MCBIST to arrive at the correct offset to add to # the pervasive MCA parent offset. my $numberOfMcaPerMcbist = 4; my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_MCA_OFFSET + ($chip_unit / $numberOfMcaPerMcbist)); $targetObj->setAttribute( $target, "CHIPLET_ID", $value); } ## EQ sub processEq { my $targetObj = shift; my $target = shift; my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); foreach my $child (@{ $targetObj->getTargetChildren($target) }) { my $child_type = $targetObj->getType($child); $targetObj->log($target, "Processing EQ child: $child Type: $child_type"); if ($child_type eq "EX") { processEx($targetObj, $child, $chip_unit); } } my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_EQ_OFFSET + $chip_unit); $targetObj->setAttribute( $target, "CHIPLET_ID", $value); } ## EX sub processEx { my $targetObj = shift; my $target = shift; my $parent_chip_unit = shift; foreach my $child (@{ $targetObj->getTargetChildren($target) }) { my $child_type = $targetObj->getType($child); $targetObj->log($target, "Processing EX child: $child Type: $child_type"); if ($child_type eq "CORE") { processCore($targetObj, $child); } } my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_EQ_OFFSET + $parent_chip_unit); $targetObj->setAttribute( $target, "CHIPLET_ID", $value); } ## CORE sub processCore { my $targetObj = shift; my $target = shift; my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_CORE_OFFSET + $chip_unit); $targetObj->setAttribute( $target, "CHIPLET_ID", $value); } ## MCBIST sub processMcbist { my $targetObj = shift; my $target = shift; my $parentTarget = shift; my $group = $targetObj->getAttribute($parentTarget, "FABRIC_GROUP_ID"); my $proc = $targetObj->getAttribute($parentTarget, "FABRIC_CHIP_ID"); foreach my $child (@{ $targetObj->getTargetChildren($target) }) { my $child_type = $targetObj->getType($child); $targetObj->log($target, "Processing MCBIST child: $child Type: $child_type"); if ($child_type eq "NA" || $child_type eq "FSI") { $child_type = $targetObj->getMrwType($child); } if ($child_type eq "MCS") { processMcs($targetObj, $child, $target, $group, $proc); } } { use integer; my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_MCBIST_OFFSET + $chip_unit); $targetObj->setAttribute( $target, "CHIPLET_ID", $value); } } #-------------------------------------------------- ## MC ## ## sub processMc { # NOTE: OMI_INBAND_BAR_BASE_ADDR_OFFSET will be set for the MC # targets via a specific child OMI Target. View the # processOmi function for further details. my $targetObj = shift; my $target = shift; foreach my $child (@{ $targetObj->getTargetChildren($target) }) { my $child_type = $targetObj->getType($child); $targetObj->log($target, "Processing MC child: $child Type: $child_type"); if ($child_type eq "MI") { processMi($targetObj, $child); } elsif ($child_type eq "OMIC") { processOmic($targetObj, $child); } } { use integer; my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_MC_OFFSET + $chip_unit); $targetObj->setAttribute( $target, "CHIPLET_ID", $value); } } #-------------------------------------------------- ## MCC ## ## sub processMcc { my $targetObj = shift; my $target = shift; foreach my $child (@{ $targetObj->getTargetChildren($target) }) { my $child_type = $targetObj->getType($child); $targetObj->log($target, "Processing MCC child: $child Type: $child_type"); if ($child_type eq "OMI") { processOmi($targetObj, $child); } } { use integer; # There are a total of four MCC units on an MC unit. So, to # determine which MC an MCC belongs to, the CHIP_UNIT of the MCC can # be divided by the number of units per MC to arrive at the correct # offset to add to the pervasive MCC parent offset. my $numberOfMccPerMc = 4; my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_MI_OFFSET + ($chip_unit / $numberOfMccPerMc)); $targetObj->setAttribute( $target, "CHIPLET_ID", $value); } } #-------------------------------------------------- ## OMI ## ## sub processOmi { my $mrwObj = shift; my $omitarg = shift; use integer; # There are a total of eight OMI units on an MC unit. So, to # determine which MC an OMI belongs to, the CHIP_UNIT of the OMI can # be divided by the number of units per MC to arrive at the correct # offset to add to the pervasive OMI parent offset. my $numberOfOmiPerMc = 8; my $chip_unit = $mrwObj->getAttribute($omitarg, "CHIP_UNIT"); my $fapi_pos = $mrwObj->getAttribute($omitarg, "FAPI_POS"); my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_MI_OFFSET + ($chip_unit / $numberOfOmiPerMc)); $mrwObj->setAttribute($omitarg, "CHIPLET_ID", $value); # Start with our affinity path "sys-a/node-b/proc-c/mc-d/mi-e/mcc-f/omi-g" # then snip off everything before the mi my $phys_path = $mrwObj->getAttribute($omitarg, "PHYS_PATH"); my $up_to_mi = index($phys_path,"mi-"); my $omic_parent = substr($phys_path,0,$up_to_mi); $omic_parent = $omic_parent.$omi_map{$chip_unit}; $mrwObj->setAttribute($omitarg, "OMIC_PARENT", $omic_parent); my $omi = Math::BigInt->new($mrwObj->getAttribute($omitarg,"FAPI_POS")); # Base omi bar offset # We use this base address in simics_AXONE.system.xml and want our # addresses to match the ones in that xml my $base = 0x30400000000; my $gigabyte = 0x40000000; my $value = 0; # This algorithm is explained in src/usr/mmio/mmio.C if ($omi % 2 eq 0) { $value = $base + $omi * 4 * $gigabyte; } else { $value = $base + (($omi - 1) * 4 + 2) * $gigabyte; } $value = sprintf("0x%016s", substr(($value)->as_hex(),2)); $mrwObj->setAttribute($omitarg, "OMI_INBAND_BAR_BASE_ADDR_OFFSET", $value); # Set the parent MC BAR value to value of first OMI unit if ($omi % 8 eq 0) { my $parent_mcc = $mrwObj->getTargetParent($omitarg); my $parent_mi = $mrwObj->getTargetParent($parent_mcc); my $parent_mc = $mrwObj->getTargetParent($parent_mi); $mrwObj->setAttribute($parent_mc, "OMI_INBAND_BAR_BASE_ADDR_OFFSET", $value); } } #-------------------------------------------------- ## OMIC ## ## sub processOmic { my $targetObj = shift; my $target = shift; use integer; # There are a total of three OMIC units on an MC unit. So, to # determine which MC an OMIC belongs to, the CHIP_UNIT of the OMIC can # be divided by the number of units per MC to arrive at the correct # offset to add to the pervasive OMIC parent offset. my $numberOfOmicPerMc = 3; my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_MI_OFFSET + ($chip_unit / $numberOfOmicPerMc)); $targetObj->setAttribute( $target, "CHIPLET_ID", $value); } #-------------------------------------------------- ## OCMB_CHIP ## ## sub processOcmbChip { my $targetObj = shift; my $target = shift; $targetObj->setEepromAttributesForAxone($targetObj, $target); } #-------------------------------------------------g ## MI ## ## sub processMi { my $targetObj = shift; my $target = shift; foreach my $child (@{ $targetObj->getTargetChildren($target) }) { my $child_type = $targetObj->getType($child); $targetObj->log($target, "Processing MI child: $child Type: $child_type"); if ($child_type eq "DMI") { processDmi($targetObj, $child); } elsif ($child_type eq "MCC") { processMcc($targetObj, $child); } } { use integer; # There are a total of two MI units on an MC unit. So, to # determine which MC an MI belongs to, the CHIP_UNIT of the MI can # be divided by the number of units per MC to arrive at the correct # offset to add to the pervasive MI parent offset. my $numberOfMiPerMc = 2; my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_MI_OFFSET + ($chip_unit / $numberOfMiPerMc)); $targetObj->setAttribute( $target, "CHIPLET_ID", $value); } } #-------------------------------------------------- ## DMI ## ## Sets DMI offset address attribute sub processDmi { my $targetObj = shift; my $target = shift; my $dmi = Math::BigInt->new($targetObj->getAttribute($target,"CHIP_UNIT")); my $ibase = 0x0030220000000; # Base ibscom offset my $dmiOffset = 0x0000004000000; # 64MB my $value = sprintf("0x%016s",substr(( $ibase+ $dmiOffset*$dmi)->as_hex(),2)); $targetObj->setAttribute($target,"DMI_INBAND_BAR_BASE_ADDR_OFFSET",$value); $targetObj->deleteAttribute($target,"DMI_INBAND_BAR_ENABLE"); { use integer; # There are a total of four DMI units on an MC unit. So, to # determine which MC an DMI belongs to, the CHIP_UNIT of the DMI can # be divided by the number of units per MC to arrive at the correct # offset to add to the pervasive DMI parent offset. my $numberOfDmiPerMc = 4; my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_DMI_OFFSET + ($chip_unit / $numberOfDmiPerMc)); $targetObj->setAttribute($target, "CHIPLET_ID", $value); } } #-------------------------------------------------- ## OBUS ## ## Finds OBUS connections and copy the slot position to obus brick target sub processObus { my $targetObj = shift; my $target = shift; my $obus = $targetObj->findConnections($target,"OBUS", ""); if ($obus eq "") { $obus = $targetObj->findConnections($target,"ABUS", ""); if ($obus ne "") { $targetObj->setAttribute($target, "BUS_TYPE", "ABUS"); if ($targetObj->isBadAttribute($target, "PEER_PATH")) { $targetObj->setAttribute($target, "PEER_PATH","physical:na"); } foreach my $obusconn (@{$obus->{CONN}}) { processAbus($targetObj, $target,$obusconn); } } else { #No connections mean, we need to set the OBUS_SLOT_INDEX to -1 #to mark that they are not connected $targetObj->log($target,"no bus connection found"); foreach my $obrick (@{ $targetObj->getTargetChildren($target) }) { $targetObj->setAttribute($obrick, "OBUS_SLOT_INDEX", -1); } } } else { if ($targetObj->isBadAttribute($target, "PEER_PATH")) { $targetObj->setAttribute($target, "PEER_PATH","physical:na"); } foreach my $obusconn (@{$obus->{CONN}}) { #Loop through all the bricks and figure out if it connected to an #obusslot. If it is connected, then store the slot information (position) #in the obus_brick target as OBUS_SLOT_INDEX. If it is not connected, #set the value to -1 to mark that they are not connected my $match = 0; foreach my $obrick (@{ $targetObj->getTargetChildren($target) }) { foreach my $obrick_conn (@{$obus->{CONN}}) { if ($targetObj->isBusAttributeDefined($obrick, $obrick_conn->{BUS_NUM}, "OBUS_CONFIG")) { my $cfg = $targetObj->getBusAttribute($obrick, $obrick_conn->{BUS_NUM}, "OBUS_CONFIG"); my $intarget = $obrick_conn->{SOURCE_PARENT}; while($targetObj->getAttribute($intarget,"CLASS") ne "CONNECTOR") { $intarget = $targetObj->getTargetParent($intarget); } addObusCfgToGpuSensors($obrick_conn->{DEST_PARENT}, $intarget, $cfg); } $match = ($obrick_conn->{SOURCE} eq $obrick); if ($match eq 1) { my $obus_slot = $targetObj->getTargetParent( $obrick_conn->{DEST_PARENT}); my $obus_slot_pos = $targetObj->getAttribute( $obus_slot, "POSITION"); $targetObj->setAttribute($obrick, "OBUS_SLOT_INDEX", $obus_slot_pos); last; } } #This brick is not connected to anything, set the value of OBUS_SLOT_INDEX to -1 #to mark that they are not connected if ($match eq 0) { $targetObj->setAttribute($obrick, "OBUS_SLOT_INDEX", -1); } } } } my $chip_unit = $targetObj->getAttribute($target, "CHIP_UNIT"); my $value = sprintf("0x%x", Targets::PERVASIVE_PARENT_OBUS_OFFSET + $chip_unit); $targetObj->setAttribute($target, "CHIPLET_ID", $value); # Set CHIPLET_ID for OBUS_BRICKs foreach my $child (@{ $targetObj->getTargetChildren($target) }) { my $type = $targetObj->getType($child); if ($type eq "OBUS_BRICK") { # OBUS_BRICK takes on CHIPLET_ID of OBUS parent $targetObj->setAttribute($child, "CHIPLET_ID", $value); } } } #-------------------------------------------------- ## XBUS ## ## Finds XBUS connections and creates PEER TARGET attributes sub processXbus { my $targetObj = shift; my $target = shift; my $found_xbus = 0; my $default_config = "d"; my $wrap_config = "w"; my $xbus_child_conn = $targetObj->getFirstConnectionDestination($target); if ($xbus_child_conn ne "") { # The CONFIG_APPLY bus attribute carries a comma seperated values for each # X-bus connection. It can currently take the following values. # "w" - This connection is applicable only in wrap config # "d" - This connection is applicable in default config (non-wrap mode). my $config = $default_config; if ($targetObj->isBusAttributeDefined($target,0,"CONFIG_APPLY")) { $config = $targetObj->getBusAttribute($target,0,"CONFIG_APPLY"); } # Validate a value was provided, if not use the default value if ($config eq "") { print STDOUT "No value found for CONFIG_APPLY, default to using default value ($default_config)\n"; $config = $default_config; } #If CONFIG_APPLY doesn't match the system configuration we are #running for, then mark the peers null. #For example, in wrap config, CONFIG_APPLY is expected to have "w" #If "w" is not there, then we skip the connection and mark peers #as NULL if (($system_config eq $wrap_config && $config =~ /$wrap_config/) || ($system_config ne $wrap_config && $config =~ /$default_config/)) { ## set attributes for both directions $targetObj->setAttribute($xbus_child_conn, "PEER_TARGET", $targetObj->getAttribute($target, "PHYS_PATH")); $targetObj->setAttribute($target, "PEER_TARGET", $targetObj->getAttribute($xbus_child_conn, "PHYS_PATH")); $targetObj->setAttribute($xbus_child_conn, "PEER_PATH", $targetObj->getAttribute($target, "PHYS_PATH")); $targetObj->setAttribute($target, "PEER_PATH", $targetObj->getAttribute($xbus_child_conn, "PHYS_PATH")); $targetObj->setAttribute($xbus_child_conn, "PEER_HUID", $targetObj->getAttribute($target, "HUID")); $targetObj->setAttribute($target, "PEER_HUID", $targetObj->getAttribute($xbus_child_conn, "HUID")); $found_xbus = 1; } else { $targetObj->setAttribute($xbus_child_conn, "PEER_TARGET", "NULL"); $targetObj->setAttribute($target, "PEER_TARGET","NULL"); $targetObj->setAttribute($xbus_child_conn, "PEER_PATH", "physical:na"); $targetObj->setAttribute($target, "PEER_PATH", "physical:na"); } } } #-------------------------------------------------- ## ABUS ## ## Finds ABUS connections and creates PEER TARGET attributes sub processAbus { my $targetObj = shift; my $target = shift; my $aBus = shift; my $abussource = $aBus->{SOURCE}; my $abusdest = $aBus->{DEST}; my $abus_dest_parent = $aBus->{DEST_PARENT}; my $bustype = $targetObj->getBusType($abussource); my $updatePeerTargets = 0; my $config = $targetObj->getBusAttribute($aBus->{SOURCE},$aBus->{BUS_NUM},"CONFIG_APPLY"); my $twonode = "2"; my $threenode = "3"; my $fournode = "4"; my @configs = split(',',$config); # The CONFIG_APPLY bus attribute carries a comma seperated values for each # A-bus connection. For eg., # "2,3,4" - This connection is applicable in 2,3 and 4 node config # "w" - This connection is applicable only in wrap config # "2" - This connection is applicable only in 2 node config # "4" - This connection is applicable only in 4 node config # The below logic looks for these tokens and decides whether a certain # A-bus connection has to be conisdered or not # If user has passed 2N as argument, then we consider only those # A-bus connections where token "2" is present if($system_config eq "2N" && $config =~ /$twonode/) { #Looking for Abus connections pertaining to 2 node system only $updatePeerTargets = 1; } elsif ($system_config eq "") { #Looking for Abus connections pertaining to 2,3,4 node systems #This will skip any connections specific to ONLY 2 node if($config =~ /$threenode/ || $config =~ /$fournode/) { $updatePeerTargets = 1; } } elsif ($config =~ /$system_config/) { #If system configuration we are building for matches the config #this ABUS connection is for, then update. Ex: wrap config $updatePeerTargets = 1; } else { $updatePeerTargets = 0; } if($updatePeerTargets eq 1) { ## set attributes for both directions my $phys1 = $targetObj->getAttribute($target, "PHYS_PATH"); my $phys2 = $targetObj->getAttribute($abus_dest_parent, "PHYS_PATH"); $targetObj->setAttribute($abus_dest_parent, "PEER_TARGET",$phys1); $targetObj->setAttribute($target, "PEER_TARGET",$phys2); $targetObj->setAttribute($abus_dest_parent, "PEER_PATH", $phys1); $targetObj->setAttribute($target, "PEER_PATH", $phys2); $targetObj->setAttribute($abus_dest_parent, "PEER_HUID", $targetObj->getAttribute($target, "HUID")); $targetObj->setAttribute($target, "PEER_HUID", $targetObj->getAttribute($abus_dest_parent, "HUID")); $targetObj->setAttribute($abussource, "PEER_TARGET", $targetObj->getAttribute($abusdest, "PHYS_PATH")); $targetObj->setAttribute($abusdest, "PEER_TARGET", $targetObj->getAttribute($abussource, "PHYS_PATH")); $targetObj->setAttribute($abussource, "PEER_PATH", $targetObj->getAttribute($abusdest, "PHYS_PATH")); $targetObj->setAttribute($abusdest, "PEER_PATH", $targetObj->getAttribute($abussource, "PHYS_PATH")); $targetObj->setAttribute($abussource, "PEER_HUID", $targetObj->getAttribute($abusdest, "HUID")); $targetObj->setAttribute($abusdest, "PEER_HUID", $targetObj->getAttribute($abussource, "HUID")); # copy Abus attributes from the connection to the chiplet my $abus = $targetObj->getFirstConnectionBus($target); $targetObj->setAttribute($target, "EI_BUS_TX_MSBSWAP", $abus->{bus_attribute}->{SOURCE_TX_MSBSWAP}->{default}); $targetObj->setAttribute($abus_dest_parent, "EI_BUS_TX_MSBSWAP", $abus->{bus_attribute}->{DEST_TX_MSBSWAP}->{default}); # copy attributes for wrap config my $link_set = "SET_NONE"; if ($targetObj->isBusAttributeDefined($aBus->{SOURCE},$aBus->{BUS_NUM},"MFG_WRAP_TEST_ABUS_LINKS_SET")) { $link_set = $targetObj->getBusAttribute($aBus->{SOURCE},$aBus->{BUS_NUM},"MFG_WRAP_TEST_ABUS_LINKS_SET"); } $targetObj->setAttribute($target, "MFG_WRAP_TEST_ABUS_LINKS_SET", $link_set); $targetObj->setAttribute($abus_dest_parent, "MFG_WRAP_TEST_ABUS_LINKS_SET", $link_set); } } #-------------------------------------------------- ## FSI ## ## Finds FSI connections and creates FSI MASTER attributes at endpoint target sub processFsi { my $targetObj = shift; my $target = shift; my $parentTarget = shift; my $type = $targetObj->getBusType($target); ## fsi can only have 1 connection my $fsi_child_conn = $targetObj->getFirstConnectionDestination($target); ## found something on other end if ($fsi_child_conn ne "") { my $fsi_link = $targetObj->getAttribute($target, "FSI_LINK"); my $fsi_port = $targetObj->getAttribute($target, "FSI_PORT"); my $cmfsi = $targetObj->getAttribute($target, "CMFSI"); my $proc_path = $targetObj->getAttribute($parentTarget,"PHYS_PATH"); my $fsi_child_target = $targetObj->getTargetParent($fsi_child_conn); my $flip_port = 0; my $altfsiswitch = 0; # If this is a proc that can be a master, then we need to set flip_port # attribute in FSI_OPTIONS. $flip_port tells us which FSI port to write to. # The default setting ( with flip_port not set) is to send instructions to port A. # In High End systems there are 2 master capable procs per node. # For the alt-master processor we need to set flip_port so that when it is master, # it knows to send instructions to the B port. During processMrw # we cannot determine which proc is master and which is the alt-master. # We will set flipPort on both and the later clear flipPort when we determine # which is actually master during hwsv init. # FSP A is primary FSB B is backup # |--------| |--------| # | FSP A | | FSP B | # | (M) | | (M) | # |--------| |--------| # | # V # |--------| |--------| # | (A)(B)|------->|(B) (A) | # | Master | |Alt Mast| # | (M)| |(M) | # |--------|\ |--------| # | \ # / \ # / \ # |--------| \ |---------| # | (A) (B)| \->|(A) (B) | # | Slave | | Slave | # | | | | # |--------| |---------| # FSP B is primary FSB A is backup # # |--------| |--------| # | FSP A | | FSP B | # | (M) | | (M) | # |--------| |--------| # | # V # |--------| |--------| # | (A)(B)|<-------|(M) (A) | # | Master | /|Alt Mast| # | (M)| /||(B) | # |--------| / ||--------| # / \ # / \__ # / \ # |--------| / |---------| # |(A) (B)| |(A) (B) | # | Slave | | Slave | # | | | | # |--------| |---------| my $source_type = $targetObj->getType($parentTarget); if ( $source_type eq "PROC" ) { my $proc_type = $targetObj->getAttribute($parentTarget, "PROC_MASTER_TYPE"); if ($proc_type eq "ACTING_MASTER" || $proc_type eq "MASTER_CANDIDATE" ) { my $fcid = $targetObj->getAttribute($parentTarget,"FABRIC_CHIP_ID"); if($fcid eq 1) { $altfsiswitch = 1; } } } my $dest_type = $targetObj->getType($fsi_child_target); if ($dest_type eq "PROC" ) { my $proc_type = $targetObj->getAttribute($fsi_child_target, "PROC_MASTER_TYPE"); if ($proc_type eq "ACTING_MASTER" || $proc_type eq "MASTER_CANDIDATE" ) { my $fcid = $targetObj->getAttribute($fsi_child_target,"FABRIC_CHIP_ID"); if($fcid eq 1) { $flip_port = 1; } } } $targetObj->setFsiAttributes($fsi_child_target, $type,$cmfsi,$proc_path,$fsi_link,$flip_port,$altfsiswitch); } } #-------------------------------------------------- ## PEC ## ## Creates attributes from abstract PCI attributes on bus sub processPec { my $targetObj = shift; my $target = shift; # PEC my $parentTarget = shift; # PROC ## process pcie config target ## this is a special target whose children are the different ways ## to configure iop/phb's ## Get config children my @lane_mask; $lane_mask[0][0] = "0x0000"; $lane_mask[1][0] = "0x0000"; $lane_mask[2][0] = "0x0000"; $lane_mask[3][0] = "0x0000"; my $pec_iop_swap = 0; my $bitshift_const = 0; my $pec_num = $targetObj->getAttribute ($target, "CHIP_UNIT"); my $chipletIdValue = sprintf("0x%x", Targets::PERVASIVE_PARENT_PEC_OFFSET + $pec_num); $targetObj->setAttribute( $target, "CHIPLET_ID", $chipletIdValue); foreach my $pec_config_child (@{ $targetObj->getTargetChildren($target) }) { my $phb_counter = 0; foreach my $phb_child (@{ $targetObj->getTargetChildren ($pec_config_child) }) { foreach my $phb_config_child (@{ $targetObj->getTargetChildren ($phb_child) }) { my $num_connections = $targetObj->getNumConnections ($phb_config_child); if ($num_connections > 0) { # We have a PHB connection # We need to create the PEC attributes my $phb_num = $targetObj->getAttribute ($phb_config_child, "PHB_NUM"); # Get lane group and set lane masks my $lane_group = $targetObj->getAttribute ($phb_config_child, "PCIE_LANE_GROUP"); # Set up Lane Swap attribute # Get attribute that says if lane swap is set up for this # bus. Taken as a 1 or 0 (on or off) # Lane Reversal = swapped lanes my $lane_swap = $targetObj->getBusAttribute ($phb_config_child, 0, "LANE_REVERSAL"); # Lane swap comes out as "00" or "01" - so add 0 so it # converts to an integer to evaluate. my $lane_swap_int = $lane_swap + 0; # The PROC_PCIE_IOP_SWAP attribute is PEC specific. The # right most bit represents the highest numbered PHB in # the PEC. e.g. for PEC2, bit 7 represents PHB5 while bit # 5 represents PHB3. A value of 5 (00000101) represents # both PHB3 and 5 having swap set. # Because of the ordering of how we process PHB's and the # different number of PHB's in each PEC we have to bitshift # by a different number for each PHB in each PEC. if ($lane_swap_int) { if ($pec_num eq 0) { # This number is not simply the PEC unit number, # but the number of PHB's in each PEC. $bitshift_const = 0; } elsif ($pec_num eq 1) { $bitshift_const = 1; } elsif ($pec_num eq 2) { $bitshift_const = 2; } else { die "Invalid PEC Chip unit number for target $target"; } # The bitshift number is the absoulte value of the phb # counter subtracted from the bitshift_const for this # pec. For PHB 3, this abs(0-2), giving a bitshift of 2 # and filling in the correct bit in IOP_SWAP (5). my $bitshift = abs($phb_counter - $bitshift_const); $pec_iop_swap |= 1 << $bitshift; } my $pcie_bifurcated = "0"; if ($targetObj->isBusAttributeDefined($phb_config_child, 0, "PCIE_BIFURCATED")) { $pcie_bifurcated = $targetObj->getBusAttribute ($phb_config_child, 0, "PCIE_BIFURCATED"); } # Set the lane swap for the PEC. If we find more swaps as # we process the other PCI busses then we will overwrite # the overall swap value with the newly computed one. if ($pcie_bifurcated eq "1") { $targetObj->setAttribute($target, "PEC_PCIE_IOP_SWAP_BIFURCATED", $pec_iop_swap); } else { $targetObj->setAttribute($target, "PEC_PCIE_IOP_SWAP_NON_BIFURCATED", $pec_iop_swap); $targetObj->setAttribute($target, "PROC_PCIE_IOP_SWAP", $pec_iop_swap); } $lane_mask[$lane_group][0] = $targetObj->getAttribute ($phb_config_child, "PCIE_LANE_MASK"); my $lane_mask_attr = sprintf("%s,%s,%s,%s", $lane_mask[0][0], $lane_mask[1][0], $lane_mask[2][0], $lane_mask[3][0]); if ($pcie_bifurcated eq "1") { $targetObj->setAttribute($target, "PEC_PCIE_LANE_MASK_BIFURCATED", $lane_mask_attr); } else { $targetObj->setAttribute($target, "PROC_PCIE_LANE_MASK", $lane_mask_attr); $targetObj->setAttribute($target, "PEC_PCIE_LANE_MASK_NON_BIFURCATED", $lane_mask_attr); } # Only compute the HDAT attributes if they are available # and have default values if (!($targetObj->isBadAttribute($phb_config_child, "ENABLE_LSI"))) { # Get capabilites, and bit shift them correctly # Set the CAPABILITES attribute for evey PHB my $lsiSupport = $targetObj->getAttribute ($phb_config_child, "ENABLE_LSI"); my $capiSupport = ($targetObj->getAttribute ($phb_config_child, "ENABLE_CAPI")) << 1; my $cableCardSupport = ($targetObj->getAttribute ($phb_config_child, "ENABLE_CABLECARD")) << 2; my $hotPlugSupport = ($targetObj->getAttribute ($phb_config_child, "ENABLE_HOTPLUG")) << 3; my $sriovSupport = ($targetObj->getAttribute ($phb_config_child, "ENABLE_SRIOV")) << 4; my $elLocoSupport = ($targetObj->getAttribute ($phb_config_child, "ENABLE_ELLOCO")) << 5; my $nvLinkSupport = ($targetObj->getAttribute ($phb_config_child, "ENABLE_NVLINK")) << 6; my $capabilites = sprintf("0x%X", ($nvLinkSupport | $elLocoSupport | $sriovSupport | $hotPlugSupport | $cableCardSupport | $capiSupport | $lsiSupport)); $targetObj->setAttribute($phb_child, "PCIE_CAPABILITES", $capabilites); # Set MGC_LOAD_SOURCE for every PHB my $mgc_load_source = $targetObj->getAttribute ($phb_config_child, "MGC_LOAD_SOURCE"); $targetObj->setAttribute($phb_child, "MGC_LOAD_SOURCE", $mgc_load_source); # Find if this PHB has a pcieslot connection my $pcieBusConnection = $targetObj->findConnections($phb_child,"PCIE",""); # Inspect the connection and set appropriate attributes foreach my $pcieBus (@{$pcieBusConnection->{CONN}}) { # Check if destination is a switch(PEX) or built in # device(USB) and set entry type attribute my $destTargetType = $targetObj->getTargetType ($pcieBus->{DEST_PARENT}); if ($destTargetType eq "chip-PEX8725") { # Destination is a switch upleg. Set entry type # that corresponds to switch upleg. $targetObj->setAttribute($phb_child, "ENTRY_TYPE","0x01"); # Set Station ID (only valid for switch upleg) my $stationId = $targetObj->getAttribute ($pcieBus->{DEST}, "STATION"); $targetObj->setAttribute($phb_child, "STATION_ID",$stationId); # Set device and vendor ID from the switch my $vendorId = $targetObj->getAttribute ($pcieBus->{DEST_PARENT}, "VENDOR_ID"); my $deviceId = $targetObj->getAttribute ($pcieBus->{DEST_PARENT}, "DEVICE_ID"); $targetObj->setAttribute($phb_child, "VENDOR_ID",$vendorId); $targetObj->setAttribute($phb_child, "DEVICE_ID",$deviceId); } elsif ($destTargetType eq "chip-TUSB7340") { # Destination is a built in device. Set entry # type that corresponds to built in device $targetObj->setAttribute($phb_child, "ENTRY_TYPE","0x03"); # Set device and vendor ID from the device my $vendorId = $targetObj->getAttribute ($pcieBus->{DEST_PARENT}, "VENDOR_ID"); my $deviceId = $targetObj->getAttribute ($pcieBus->{DEST_PARENT}, "DEVICE_ID"); $targetObj->setAttribute($phb_child, "VENDOR_ID",$vendorId); $targetObj->setAttribute($phb_child, "DEVICE_ID",$deviceId); } # If the source is a PEX chip, its a switch downleg # Set entry type accordingly my $sourceTargetType = $targetObj->getTargetType ($pcieBus->{SOURCE_PARENT}); if ($sourceTargetType eq "chip-PEX8725") { # Destination is a switch downleg. $targetObj->setAttribute($phb_child, "ENTRY_TYPE","0x02"); # Set Ports which this downleg switch connects # to. Only valid for switch downleg my $portId = $targetObj->getAttribute ($pcieBus->{DEST}, "PORT"); $targetObj->setAttribute($phb_child, "PORT_ID", $portId); # Set device and vendor ID from the device my $vendorId = $targetObj->getAttribute ($pcieBus->{SOURCE_PARENT}, "VENDOR_ID"); my $deviceId = $targetObj->getAttribute ($pcieBus->{SOURCE_PARENT}, "DEVICE_ID"); $targetObj->setAttribute($phb_child, "VENDOR_ID",$vendorId); $targetObj->setAttribute($phb_child, "DEVICE_ID",$deviceId); } # Get the parent of the DEST_PARENT, and chek its # instance type my $parent_target = $targetObj->getTargetParent($pcieBus->{DEST_PARENT}); my $parentTargetType = $targetObj->getTargetType($parent_target); if ($parentTargetType eq "slot-pcieslot-generic") { # Set these attributes only if we are in a pcie # slot connection my $hddw_order = $targetObj->getAttribute ($parent_target, "HDDW_ORDER"); my $slot_index = $targetObj->getAttribute ($parent_target, "SLOT_INDEX"); my $slot_name = $targetObj->getAttribute ($parent_target, "SLOT_NAME"); my $mmio_size_32 = $targetObj->getAttribute ($parent_target, "32BIT_MMIO_SIZE"); my $mmio_size_64 = $targetObj->getAttribute ($parent_target, "64BIT_MMIO_SIZE"); my $dma_size_32 = $targetObj->getAttribute ($parent_target, "32BIT_DMA_SIZE"); my $dma_size_64 = $targetObj->getAttribute ($parent_target, "64BIT_DMA_SIZE"); $targetObj->setAttribute($phb_child, "HDDW_ORDER", $hddw_order); $targetObj->setAttribute($phb_child, "SLOT_INDEX", $slot_index); $targetObj->setAttribute($phb_child, "SLOT_NAME", $slot_name); $targetObj->setAttribute($phb_child, "PCIE_32BIT_MMIO_SIZE", $mmio_size_32); $targetObj->setAttribute($phb_child, "PCIE_64BIT_MMIO_SIZE", $mmio_size_64); $targetObj->setAttribute($phb_child, "PCIE_32BIT_DMA_SIZE", $dma_size_32); $targetObj->setAttribute($phb_child, "PCIE_64BIT_DMA_SIZE", $dma_size_64); $targetObj->setAttribute($phb_child, "ENTRY_FEATURES", "0x0001"); # Only set MAX_POWER if it exisits in the system # xml. TODO to remove this check when system xml # is upated: RTC:175319 if (!($targetObj->isBadAttribute ($parent_target,"MAX_POWER"))) { my $maxSlotPower = $targetObj->getAttribute ($parent_target, "MAX_POWER"); $targetObj->setAttribute($phb_child, "MAX_POWER",$maxSlotPower); } } else { # Set these attributes only for non-pcie slot # connections $targetObj->setAttribute($phb_child, "ENTRY_FEATURES", "0x0002"); } } } } # Found connection } # PHB bus loop $phb_counter = $phb_counter + 1; } # PHB loop } # PEC config loop } #-------------------------------------------------- ## OCC ## sub processOcc { my $targetObj = shift; my $target = shift; my $parentTarget = shift; my $master_capable=0; my $proc_type = $targetObj->getAttribute($parentTarget, "PROC_MASTER_TYPE"); if ($proc_type eq "ACTING_MASTER" ) { $master_capable=1; } $targetObj->setAttribute($target,"OCC_MASTER_CAPABLE",$master_capable); } sub processMembufVpdAssociation { my $targetObj = shift; my $target = shift; my $vpds=$targetObj->findConnections($target,"I2C","VPD"); if ($vpds ne "" ) { my $vpd = $vpds->{CONN}->[0]; my $membuf_assocs=$targetObj->findConnections($vpd->{DEST_PARENT}, "LOGICAL_ASSOCIATION","MEMBUF"); if ($membuf_assocs ne "") { foreach my $membuf_assoc (@{$membuf_assocs->{CONN}}) { my $membuf_target = $membuf_assoc->{DEST_PARENT}; setEepromAttributes($targetObj, "EEPROM_VPD_PRIMARY_INFO",$membuf_target,$vpd); my $index = $targetObj->getBusAttribute($membuf_assoc->{SOURCE}, $membuf_assoc->{BUS_NUM}, "ISDIMM_MBVPD_INDEX"); $targetObj->setAttribute( $membuf_target,"ISDIMM_MBVPD_INDEX",$index); $targetObj->setAttribute($membuf_target, "VPD_REC_NUM",$targetObj->{vpd_num}); } } my $group_assocs=$targetObj->findConnections($vpd->{DEST_PARENT}, "LOGICAL_ASSOCIATION","CARD"); if ($group_assocs ne "") { foreach my $group_assoc (@{$group_assocs->{CONN}}) { my $mb_target = $group_assoc->{DEST_PARENT}; my $group_target = $targetObj->getTargetParent($mb_target); $targetObj->setAttribute($group_target, "VPD_REC_NUM",$targetObj->{vpd_num}); } } $targetObj->{vpd_num}++; } } #-------------------------------------------------- ## MEMBUF ## ## Finds I2C connections to DIMM and creates EEPROM attributes ## FYI: I had to handle DMI busses in framework because they ## define affinity path sub processMembuf { my $targetObj = shift; my $membufTarg = shift; if ($targetObj->isBadAttribute($membufTarg, "PHYS_PATH", "")) { ##dmi is probably not connected. will get caught in error checking return; } processMembufVpdAssociation($targetObj,$membufTarg); ## find port mapping my %dimm_portmap; foreach my $child (@{$targetObj->getTargetChildren($membufTarg)}) { if ($targetObj->getType($child) eq "MBA") { # find this MBA's position relative to the membuf my $mba_num = $targetObj->getAttribute($child,"MBA_NUM"); # follow the DDR4 bus connection to find the 'ddr' targets my $ddrs = $targetObj->findConnections($child,"DDR4",""); if($ddrs eq "") { # on multi node system there is a possibility that either # DDR4 or DDR3 dimms are connected under a node my $ddrs = $targetObj->findConnections($child,"DDR3",""); } if ($ddrs ne "") { foreach my $ddr (@{$ddrs->{CONN}}) { my $port_num = $targetObj->getDimmPort($ddr->{SOURCE}); my $dimm_num = $targetObj->getDimmPos($ddr->{SOURCE}); my $map = oct("0b".$mba_num.$port_num.$dimm_num); $dimm_portmap{$ddr->{DEST_PARENT}} = $map; } } } } ## Process MEMBUF to DIMM I2C connections my @addr_map=('0','0','0','0','0','0','0','0'); my $dimms=$targetObj->findConnections($membufTarg,"I2C","SPD"); if ($dimms ne "") { foreach my $dimm (@{$dimms->{CONN}}) { my $dimm_target = $targetObj->getTargetParent($dimm->{DEST_PARENT}); setEepromAttributes($targetObj, "EEPROM_VPD_PRIMARY_INFO",$dimm_target, $dimm); my $field=getI2cMapField($targetObj,$dimm_target,$dimm); my $map = $dimm_portmap{$dimm_target}; if ($map eq "") { print "ERROR: $dimm_target doesn't map to a dimm/port\n"; $targetObj->myExit(3); } $addr_map[$map] = $field; } } $targetObj->setAttribute($membufTarg, "MRW_MEM_SENSOR_CACHE_ADDR_MAP","0x".join("",@addr_map)); ## Update bus speeds processI2cSpeeds($targetObj,$membufTarg); processPowerRails($targetObj, $membufTarg); } sub getI2cMapField { my $targetObj = shift; my $target = shift; my $conn_target = shift; my $port = $targetObj->getAttribute($conn_target->{SOURCE}, "I2C_PORT"); my $engine = $targetObj->getAttribute($conn_target->{SOURCE}, "I2C_ENGINE"); my $addr = ""; # For Open Power systems continue to get the I2C_ADDRESS from # bus target, if defined. if ($targetObj->isBusAttributeDefined( $conn_target->{SOURCE},$conn_target->{BUS_NUM},"I2C_ADDRESS")) { $addr = $targetObj->getBusAttribute($conn_target->{SOURCE}, $conn_target->{BUS_NUM}, "I2C_ADDRESS"); } # If bus doesn't have I2C_ADDRESS or default value is not set, # then get it from i2c-slave, if defined. if ($addr eq "") { if (! $targetObj->isBadAttribute($conn_target->{DEST},"I2C_ADDRESS") ) { $addr = $targetObj->getAttribute($conn_target->{DEST},"I2C_ADDRESS"); } } #if the addr is still not defined, then throw an error if ($addr eq "") { print ("ERROR: I2C_ADDRESS is not defined for $conn_target\n"); $targetObj->myExit(4); } my $bits=sprintf("%08b",hex($addr)); my $field=sprintf("%d%3s",oct($port),substr($bits,4,3)); my $hexfield = sprintf("%X",oct("0b$field")); return $hexfield; } #------------------------------------------------------------------------------ # I2C # sub processI2C { my $targetObj = shift; # Top Hierarchy of targeting structure my $target = shift; # I2C targetInstance my $parentTarget = shift; # Processor target # Initialize output arrays my @i2cEngine = (); my @i2cPort = (); my @i2cSlave = (); my @i2cAddr = (); my @i2cSpeed = (); my @i2cType = (); my @i2cPurpose = (); my @i2cLabel = (); # Step 1: get I2C_ENGINE and PORT from my $engine = $targetObj->getAttribute($target, "I2C_ENGINE"); if($engine eq "") {$engine = "0xFF";} my $port = $targetObj->getAttribute($target, "I2C_PORT"); if($port eq "") {$port = "0xFF";} # Step 2: get I2C_ADDRESS and I2C_SPEED from # This is different for each connection. my $i2cs = $targetObj->findConnections($parentTarget, "I2C",""); if ($i2cs ne "") { # This gives all i2c connections foreach my $i2c (@{$i2cs->{CONN}}) { # Here we are checking that the i2c source matches our target my $source = $i2c->{SOURCE}; if ($source ne $target) { next; } # Most I2C devices will default the slave port, it is only valid # for gpio expanders. my $slavePort = "0xFF"; my $purpose_str = undef; if ($targetObj->isBusAttributeDefined( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_PURPOSE")) { $purpose_str = $targetObj->getBusAttribute( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_PURPOSE"); } if( defined $purpose_str && $purpose_str ne "") { my $parent = $targetObj->getTargetParent($i2c->{DEST}); foreach my $aTarget ( sort keys %{ $targetObj->getAllTargets()}) { if($aTarget =~ m/$parent/) { if ($targetObj->isBadAttribute($aTarget,"PIN_NAME")) { next; } my $pin = $targetObj->getAttribute($aTarget, "PIN_NAME"); if($pin eq $purpose_str) { ($slavePort) = $aTarget =~ m/\-([0-9]+)$/g; last; } } } } my $type_str; my $purpose; my $addr; my $speed; my $type; my $label; # For all these attributes, we need to check if they're defined, # and if not we set them to a default value. if ($targetObj->isBusAttributeDefined( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_ADDRESS")) { $addr = $targetObj->getBusAttribute( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_ADDRESS"); } # If bus doesn't have I2C_ADDRESS or default value is not set, # then get it from i2c-slave, if defined. if ($addr eq "") { if (! $targetObj->isBadAttribute($i2c->{DEST},"I2C_ADDRESS") ) { $addr = $targetObj->getAttribute($i2c->{DEST},"I2C_ADDRESS"); } } if ($addr eq "") {$addr = "0xFF";} if ($targetObj->isBusAttributeDefined( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_SPEED")) { $speed = HZ_PER_KHZ * $targetObj->getBusAttribute( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_SPEED"); } if ($speed eq "") {$speed = "0";} if ($targetObj->isBusAttributeDefined( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_TYPE")) { $type_str = $targetObj->getBusAttribute( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_TYPE"); } if ($type_str eq "") { $type = "0xFF"; } # TPM types can vary by MODEL number elsif ($type_str eq "NUVOTON_TPM") { # Model values can be found in tpmddif.H and are kept in # sync with TPM_MODEL attribute in attribute_types_hb.xml my $tpm_model = $targetObj->getAttribute($i2c->{DEST_PARENT},"TPM_MODEL"); if ($tpm_model eq 1) { $type = $targetObj->getEnumValue("HDAT_I2C_DEVICE_TYPE",$type_str); } if ($tpm_model eq 2) { # @TODO RTC 212201 use proper enum when .xml supports it #$type = $targetObj->getEnumValue("HDAT_I2C_DEVICE_TYPE","TCG_I2C_TPM"); $type = 0x15; } } else { $type = $targetObj->getEnumValue("HDAT_I2C_DEVICE_TYPE",$type_str); } if ($targetObj->isBusAttributeDefined( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_PURPOSE")) { $purpose_str = $targetObj->getBusAttribute( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_PURPOSE"); } if ($purpose_str eq "") { $purpose = "0xFF"; } else { $purpose = $targetObj->getEnumValue("HDAT_I2C_DEVICE_PURPOSE", $purpose_str); } if ($targetObj->isBusAttributeDefined( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_LABEL")) { $label = $targetObj->getBusAttribute( $i2c->{SOURCE},$i2c->{BUS_NUM},"I2C_LABEL"); } if ($label eq "") { # For SEEPROMS: # ,, , if (($type_str eq "SEEPROM") || ($type_str =~ m/SEEPROM_Atmel28c128/i)) { $label = "atmel,28c128,"; } elsif($type_str =~ m/SEEPROM_Atmel28c256/i) { $label = "atmel,28c256,"; } if ($label ne "") { if ($purpose_str =~ m/MODULE_VPD/) { $label .= "vpd,module"; } elsif ($purpose_str =~ m/DIMM_SPD/) { $label .= "spd,dimm"; } elsif ($purpose_str =~ m/PROC_MODULE_VPD/) { $label .= "vpd,module"; } elsif ($purpose_str =~ m/SBE_SEEPROM/) { $label .= "image,sbe"; } elsif ($purpose_str =~ m/PLANAR_VPD/) { $label .= "vpd,planar"; } else { $label .= "unknown,unknown"; } } # For GPIO expanders: # ,,, if ($label eq "") { if ($type_str =~ m/9551/) { $label = "nxp,pca9551,"; } elsif ($type_str =~ m/9552/) { $label = "nxp,pca9552,"; } elsif ($type_str =~ m/9553/) { $label = "nxp,pca9553,"; } elsif ($type_str =~ m/9554/) { $label = "nxp,pca9554,"; } elsif ($type_str =~ m/9555/) { $label = "nxp,pca9555,"; } elsif($type_str =~ m/UCX90XX/) { $label = "ti,ucx90xx,"; } if ($label ne "") { if ($purpose_str =~ m/CABLE_CARD_PRES/) { $label .= "cablecard,presence"; } elsif ($purpose_str =~ m/PCI_HOTPLUG_PGOOD/) { $label .= "pcie-hotplug,pgood"; } elsif ($purpose_str =~ m/PCI_HOTPLUG_CONTROL/) { $label .= "pcie-hotplug,control"; } elsif ($purpose_str =~ m/WINDOW_OPEN/) { $label .= "secure-boot,window-open"; } elsif ($purpose_str =~ m/PHYSICAL_PRESENCE/) { $label .= "secure-boot,physical-presence"; } else { $label .= "unknown,unknown"; } } } # For TPM: # ,,, if ($type_str eq "NUVOTON_TPM") { # Model values can be found in tpmddif.H and are kept in # sync with TPM_MODEL attribute in attribute_types_hb.xml my $tpm_model = $targetObj->getAttribute($i2c->{DEST_PARENT},"TPM_MODEL"); if ($tpm_model eq 1) { $label = "nuvoton,npct601,tpm,host"; } if ($tpm_model eq 2) { $label = "tcg,tpm_i2c_ptp,tpm,host"; } } if ($label eq "") { $label = "unknown,unknown,unknown,unknown" } $label = '"' . $label . '"'; } # end of filling in default label values elsif ($label !~ m/^\".*\"$/) { # add quotes around label $label = '"' . $label . '"'; } # Step 3: For each connection, create an instance in the array # for the DeviceInfo_t struct. push @i2cEngine, $engine; push @i2cPort, $port; push @i2cSlave, $slavePort; push @i2cAddr, $addr; push @i2cSpeed, $speed; push @i2cType, $type; push @i2cPurpose, $purpose; push @i2cLabel, $label; } } # Return this i2c device's information back to the processor return (\@i2cEngine, \@i2cPort, \@i2cSlave, \@i2cAddr, \@i2cSpeed, \@i2cType, \@i2cPurpose, \@i2cLabel); } sub setEepromAttributes { my $targetObj = shift; my $name = shift; my $target = shift; my $conn_target = shift; my $fru = shift; my $port = $targetObj->getAttribute($conn_target->{SOURCE}, "I2C_PORT"); my $engine = $targetObj->getAttribute($conn_target->{SOURCE}, "I2C_ENGINE"); #my $addr = $targetObj->getBusAttribute($conn_target->{SOURCE}, # $conn_target->{BUS_NUM}, "I2C_ADDRESS"); my $addr = $targetObj->getAttribute($conn_target->{DEST},"I2C_ADDRESS"); my $path = $targetObj->getAttribute($conn_target->{SOURCE_PARENT}, "PHYS_PATH"); my $mem = $targetObj->getAttribute($conn_target->{DEST_PARENT}, "MEMORY_SIZE_IN_KB"); my $count = 1; # default for VPD SEEPROMs my $cycle = $targetObj->getAttribute($conn_target->{DEST_PARENT}, "WRITE_CYCLE_TIME"); my $page = $targetObj->getAttribute($conn_target->{DEST_PARENT}, "WRITE_PAGE_SIZE"); my $offset = $targetObj->getAttribute($conn_target->{DEST_PARENT}, "BYTE_ADDRESS_OFFSET"); $targetObj->setAttributeField($target, $name, "i2cMasterPath", $path); $targetObj->setAttributeField($target, $name, "port", $port); $targetObj->setAttributeField($target, $name, "devAddr", $addr); $targetObj->setAttributeField($target, $name, "engine", $engine); $targetObj->setAttributeField($target, $name, "byteAddrOffset", $offset); $targetObj->setAttributeField($target, $name, "maxMemorySizeKB", $mem); $targetObj->setAttributeField($target, $name, "chipCount", $count); $targetObj->setAttributeField($target, $name, "writePageSize", $page); $targetObj->setAttributeField($target, $name, "writeCycleTime", $cycle); if ($fru ne "") { $targetObj->setAttributeField($target, $name, "fruId", $fru); } } sub setDimmTempAttributes { my $targetObj = shift; my $target = shift; my $conn_target = shift; my $fru = shift; my $name = "TEMP_SENSOR_I2C_CONFIG"; my $port = $targetObj->getAttribute($conn_target->{SOURCE}, "I2C_PORT"); my $engine = $targetObj->getAttribute($conn_target->{SOURCE}, "I2C_ENGINE"); my $addr = $targetObj->getAttribute($conn_target->{DEST},"I2C_ADDRESS"); my $path = $targetObj->getAttribute($conn_target->{SOURCE_PARENT}, "PHYS_PATH"); $targetObj->setAttributeField($target, $name, "i2cMasterPath", $path); $targetObj->setAttributeField($target, $name, "port", $port); $targetObj->setAttributeField($target, $name, "devAddr", $addr); $targetObj->setAttributeField($target, $name, "engine", $engine); } sub setGpioAttributes { my $targetObj = shift; my $target = shift; my $conn_target = shift; my $vddrPin = shift; my $port = $targetObj->getAttribute($conn_target->{SOURCE}, "I2C_PORT"); my $engine = $targetObj->getAttribute($conn_target->{SOURCE}, "I2C_ENGINE"); my $addr = $targetObj->getBusAttribute($conn_target->{SOURCE}, $conn_target->{BUS_NUM}, "I2C_ADDRESS"); my $path = $targetObj->getAttribute($conn_target->{SOURCE_PARENT}, "PHYS_PATH"); my $name="GPIO_INFO"; $targetObj->setAttributeField($target, $name, "i2cMasterPath", $path); $targetObj->setAttributeField($target, $name, "port", $port); $targetObj->setAttributeField($target, $name, "devAddr", $addr); $targetObj->setAttributeField($target, $name, "engine", $engine); $targetObj->setAttributeField($target, $name, "vddrPin", $vddrPin); } #-------------------------------------------------- ## Compute max compute node sub get_max_compute_nodes { my $targetObj = shift; my $sysTarget = shift; my $retVal = 0; ## #Proceeed only for sys targets ## #For fabric_node_map, we store the node's position at the node #position's index my @fabric_node_map = (255, 255, 255, 255, 255, 255, 255, 255); if ($targetObj->getType($sysTarget) eq "SYS") { foreach my $child (@{$targetObj->getTargetChildren($sysTarget)}) { if ($targetObj->isBadAttribute($child, "ENC_TYPE") == 0) { my $attrVal = $targetObj->getAttribute($child, "ENC_TYPE"); if ($attrVal eq "CEC") { my $fapi_pos = $targetObj->getAttribute($child, "FAPI_POS"); $fabric_node_map[$fapi_pos] = $fapi_pos; $retVal++; } } } ## #For Open Power systems this attribute #is not populated, we consider default value as 1 # for open power systems. ## if ($retVal == 0 ) { $retVal = 1; } #Convert array into a comma separated string my $node_map = ""; foreach my $i (@fabric_node_map) { $node_map .= "$i,"; } #remove the last comma $node_map =~ s/.$//; $targetObj->setAttribute($sysTarget, "FABRIC_TO_PHYSICAL_NODE_MAP", $node_map); } return $retVal; } #-------------------------------------------------- ## ERROR checking sub errorCheck { my $targetObj = shift; my $target = shift; my $type = $targetObj->getType($target); ## error checking even for connections are done with attribute checks ## since connections simply create attributes at source and/or destination ## ## also error checking after processing is complete vs during ## processing is easier my %attribute_checks = ( SYS => ['SYSTEM_NAME'],#'OPAL_MODEL'], PROC => ['FSI_MASTER_CHIP', 'EEPROM_VPD_PRIMARY_INFO/devAddr'], MEMBUF => [ 'PHYS_PATH', 'EI_BUS_TX_MSBSWAP', 'FSI_MASTER_PORT|0xFF' ], ); my %error_msg = ( 'EEPROM_VPD_PRIMARY_INFO/devAddr' => 'I2C connection to target is not defined', 'FSI_MASTER_PORT' => 'This target is missing a required FSI connection', 'FSI_MASTER_CHIP' => 'This target is missing a required FSI connection', 'EI_BUS_TX_MSBSWAP' => 'DMI connection is missing to this membuf from processor', 'PHYS_PATH' =>'DMI connection is missing to this membuf from processor', ); my @errors; foreach my $attr (@{ $attribute_checks{$type} }) { my ($a, $v) = split(/\|/, $attr); my ($a_complex, $field) = split(/\//, $a); if ($field ne "") { if ($targetObj->isBadComplexAttribute( $target, $a_complex, $field, $v) ) { push(@errors,sprintf( "$a attribute is invalid (Target=%s)\n\t%s\n", $target, $error_msg{$a})); } } else { if ($targetObj->isBadAttribute($target, $a, $v)) { push(@errors,sprintf( "$a attribute is invalid (Target=%s)\n\t%s\n", $target, $error_msg{$a})); } } } if ($type eq "PROC") { ## note: DMI is checked on membuf side so don't need to check that here ## this checks if at least 1 abus is connected my $found_abus = 0; my $abus_error = ""; foreach my $child (@{ $targetObj->getTargetChildren($target) }) { my $child_type = $targetObj->getBusType($child); if ($child_type eq "ABUS" || $child_type eq "XBUS") { my $proc_type = $targetObj->getAttribute($target, "PROC_MASTER_TYPE"); if ($proc_type eq "NOT_MASTER" ) { if (!$targetObj->isBadAttribute($child, "PEER_TARGET")) { $found_abus = 1; } else { $abus_error = sprintf( "proc not connected to proc via Abus or Xbus (Target=%s)",$child); } } } } if ($found_abus) { $abus_error = ""; } else { push(@errors, $abus_error); } } if ($errors[0]) { foreach my $err (@errors) { print "ERROR: $err\n"; } $targetObj->myExit(3); } } sub printUsage { print " processMrwl.pl -x [XML filename] [OPTIONS] Options: -f = force output file creation even when errors -d = debug mode -c = special configurations we want to run for [2N, w] 2N = special 2 node config with extra ABUS links w = Special MST wrap config -o = output filename -s [SDR XML file] = import SDRs -r = create report and save to [system_name].rpt -v = version "; exit(1); } ################################################################################ # utility function used to call plugins. if none exists, call is skipped. ################################################################################ sub do_plugin { my $step = shift; if (exists($hwsvmrw_plugins{$step})) { $hwsvmrw_plugins{$step}(@_); } elsif ($debug && ($build eq "fsp")) { print STDERR "build is $build but no plugin for $step\n"; } }