blob: a91a0bc2bc516c4ad8b199a8443711788570dd14 [file] [log] [blame]
#!/bin/bash
#
# PERFTUNE.SH - A Linux performance tuning script for Chelsio 10Gb Ethernet
# adapters and TOE (TCP Offload Engine). Supports all Chelsio
# 10Gb Ethernet adapters (T1, T2, and T3).
#
# Copyright (c) 2004-2006 Chelsio Communications. All rights reserved.
#
# Written by Scott Bardone <sbardone@chelsio.com>
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. This program may be distributed but used
# only with Chelsio Ethernet adapters.
# $Date: 2008-07-07 22:57:18 $ $RCSfile: perftune.sh,v $ $Revision: 1.43 $
# DEFAULT SETTINGS #############################################################
# Modify appropriately. #
# The number indicates the first CPU to use for assignment of the smp_affinity.#
# Each subsequent interfaces will set smp_affinity on the next physical CPU. #
# New smp_affinity values will not take affect until the first interrupt! #
cpu_affinity_index=0 #
################################################################################
# SCRIPT SETTINGS ##############################################################
column_width=60 #
use_colors=1 #
tune_sysctl_enable=1 #
tune_pci_enable=1 #
tune_tom_enable=1 #
tune_iface_enable=1 #
tune_cpumask_enable=1 #
enable_amd_workaround=1 #
enable_pci_latency=1 #
enable_pci_burstsplit=0 #
disable_irqbalance=1 #
write_sysctls=0 #
enable_ht_smp_affinity=1 #
################################################################################
# TOM TUNEABLES ################################################################
# tom_max_tx_pages should be set to 8 if doing a single connection #
# performance test. For multiconnection tests, use a lower value. #
# This is only used on Terminator 2 cards. (default 2) #
tom_max_tx_pages=8 #
# Terminator 2 tom_mss_size should be set to 12272. #
tom_mss_size[2]="12272" #
# Terminator 3 tom_mss_size should use the default, 1048576. #
tom_mss_size[3]="" #
#
# Disable TCP timestamps for TOM. #
tom_tcp_timestamps=0 #
#
# Terminator 3 specific options. #
tom_delayed_ack=2 #
tom_ddp=1 #
# Max number of work requests, default 15. #
tom_max_wr="" #
# #
zcopy_tweak=32768 #
#
################################################################################
# PCI TUNEABLES ################################################################
# Register Addresses. #
PCIX_CMD_ADDR[2]=0x60 #
PCIX_CMD_ADDR[3]=0x74 #
PCIX_LAT_TMR_ADDR[2]=0x0c #
PCIX_LAT_TMR_ADDR[3]=0x0c #
PCIX_CFG_MODE_ADDR[2]=0xfc #
PCI_BAR_REG[3]=0x10 #
PCIX_MODE_OFFSET[3]=0x8c #
PCIE_LINK_STAT[3]=0x68 #
PCIE_LINK_CAP[3]=0x64 #
#
# PCI outstanding transaction and data burst length on most systems is #
# default to 8 transactions, 2k bytes. AMD-8131 (rev 12) chipset has a #
# bug and this should be set to 2 transactions 1k bytes, however this will #
# totally kill performance. It is possible to run with the higher numbers, #
# but we have seen the interface hang at times, depending on the traffic. #
# load and the machine. AMD-8131 chipset rev 13 is supposed to be fixed. #
# This has been taken care of by most BIOS vendors, but there still are #
# a few that have not been updated. #
SAFE_PCIX_SPLIT_TRAN=0x1 # 2 split transactions. #
SAFE_PCIX_BURST_SIZE=0x1 # 1024 byte burst size. #
# The PERF_PCIX values may be overwritten by host-bridge negotatiation. #
PERF_PCIX_SPLIT_TRAN=0x7 # 32 split transactions. #
PERF_PCIX_BURST_SIZE=0x3 # 4096 byte burst size. #
#
# PCI Latency timer value should be set to 0xF8 #
SAFE_PCI_LAT_TMR=0xf8 #
PERF_PCI_LAT_TMR=0xf8 #
################################################################################
# SYSCTL TUNABLES ##############################################################
# Linux core, ipv4, and tcp tuning paramters, #
# Setting any of these values to "" will skip writing of the sysctl. #
#
core_rmem_max=16777216 # Increase maximum read socket buffer size. #
core_wmem_max=16777216 # Increase maximum write socket buffer size. #
tcp_timestamps=0 # Disable timestamps to increase throughput. #
tcp_sack="" # Disable SACK to increase throughput. #
tcp_low_latency="" #
tcp_adv_win_scale="" #
moderate_rcvbuf="" #
#
# TCP read buffer (min/default/max), default 4096 87380 174760. #
ipv4_tcp_rmem="4096 262144 16777216" # overrides net.core.rmem_default. #
# TCP write buffer (min/default/max), default 4096 16384 131072. #
ipv4_tcp_wmem="4096 262144 16777216" # overrides net.core.wmem_default. #
#
# TCP memory allocation (min/pressure/max). #
# default values are calculated by the kernel at boot time and depend #
# on the amount of physical memory. #
ipv4_tcp_mem="" #
#
# max length of iovec or ancilliary data. #
optmem_max=524288 # default 20480. #
#
# log length of network packets. kernel will drop unprocessed packets #
# beyond this. simple algorithm for throughput: #
# <backlog> * 100(HZ) * <avg bytes/packet> = throughput bytes/second. #
netdev_max_backlog=200000 # log length of network packets. #
#
# Allows control over what percentage of the congestion window can be #
# consumed by a single TSO frame. Default is 3 on older kernels, 8 on new. #
tso_win_divisor="" #
#
# TOE SYSCTLS TUNEABLES ########################################################
#
################################################################################
# sysctl config file #
sysctl_conf_file="/etc/sysctl.conf" #
# sysctl_data array, need to include the sysctl name and the data variable. #
# Comma delimited. #
sysctl_data=( #
"net.core.wmem_max,$core_wmem_max" #
"net.core.rmem_max,$core_rmem_max" #
"net.ipv4.tcp_timestamps,$tcp_timestamps" #
"net.ipv4.tcp_sack,$tcp_sack" #
"net.ipv4.tcp_low_latency,$tcp_low_latency" #
"net.ipv4.tcp_adv_win_scale,$tcp_adv_win_scale" #
"net.ipv4.tcp_moderate_rcvbuf,$moderate_rcvbuf" #
"net.ipv4.tcp_rmem,$ipv4_tcp_rmem" #
"net.ipv4.tcp_wmem,$ipv4_tcp_wmem" #
"net.ipv4.tcp_mem,$ipv4_tcp_mem" #
"net.core.optmem_max,$optmem_max" #
"net.core.netdev_max_backlog,$netdev_max_backlog" #
"net.ipv4.tcp_tso_win_divisor,$tso_win_divisor" #
) #
################################################################################
# DO NOT MODIFY BEYOND THIS POINT! #############################################
self='perftune.sh' #
mmapr32cksum="1466576699 5134" #
mmapr64cksum="911177960 5559" #
mmapr32md5="40d20ce1a3f9dd619affe4437d09dc5e" #
mmapr64md5="61a5195259e8b8725c54bb118c6eb852" #
SELFCKSUM="923829129 57779" #
REVISION="$Revision: 1.43 $" #
HARDSTART=$LINENO #
# FILE CHECKSUM STARTS AT THIS LINE ############################################
CHELSIO_PCI_VID='1425' #
AMD_PCI_VID='1022' #
AMD_8131_DEVID='7450' #
AMD_8131_BUG_REV=18 # 0x12 #
T3_LLD_MODULE='cxgb3' #
T3_TOE_MODULE='toecore' #
T3_TOM_MODULE='t3_tom' #
################################################################################
# FUNCTIONS. ###################################################################
# function _set_color(), next print will be in color.
# _set_color pass|fail|warn|norm
_set_color() {
if (( $use_colors )); then
pass="echo -en \\033[1;32m"
fail="echo -en \\033[1;31m"
warn="echo -en \\033[1;33m"
norm="echo -en \\033[0;39m"
eval \$$1
fi
}
# function _set_column(), column width for print status.
# Uses globally defined variable 'column'.
# _set_column <number of columns>
_set_column() {
[ -n "$column_width" ] && echo -en "\\033[${column_width}G"
}
# function _print_stat(), call to print the status.
# _print_stat "<message>"
_print_stat() {
_set_color norm
echo -n "[ "
_set_color $1
echo -n $2
_set_color norm
echo " ]"
}
# function not(). negate value for double parentheses testing.
# (( $(not <value>) ))
not() {
if [ -n "$1" ] && (( $1 )); then
echo 0
else
echo 1
fi
}
# function dbg().
# dbg <var> | @<var> | *<var>[index]
dbg() {
: # stub
}
# function dbg_msg().
# dbg_msg "<message>"
dbg_msg() {
: #stub
}
# function Print(), prints a message.
# Print "<message>"
Print() {
[ -n "$1" ] && prev_print="$1"
(( $quiet )) && return
(( $silent )) && return
[ -n "$1" ] && echo -en " > $1"
}
# function Info(), prints an info message.
# Info "<message>"
Info() {
(( $quiet )) && return
(( $silent )) && return
[ -n "$1" ] && echo -e " [ $1 ]"
}
# function Pass(), prints pass status.
# Pass
Pass() {
[ -n "$1" ] && prev_print=$1
(( $quiet )) && return
(( $silent )) && return
[ -n "$1" ] && echo -n " > $1"
_set_column
_print_stat pass PASS
}
# function Fail(), prints fail status.
# Fail
Fail() {
local out=$1
(( $silent )) && prev_print=$out && return
if (( $quiet )); then
[ -z "$out" ] && [ -n "$prev_print" ] && out=$prev_print
fi
[ -n "$out" ] && echo -n " * $out"
_set_column
_print_stat fail FAIL
prev_print=$out
}
# function Warn(), prints (optional) message and warn status.
# Warn "<message>"
Warn() {
local out=$1
(( $silent )) && prev_print=$out && return
if (( $quiet )); then
[ -z "$out" ] && [ -n "$prev_print" ] && out=$prev_print
fi
[ -n "$out" ] && echo -n " > $out"
_set_column
_print_stat warn WARN
prev_print=$out
}
Say() {
[ -n "$1" ] && prev_print="$1"
(( $quiet )) && return
(( $silent )) && return
[ -n "$1" ] && echo -en "$1"
}
# function restore_if_state().
# restore_if_state <list>
restore_if_state() {
unset IFS
for interface in $@; do
Print "Restore interface $interface state."
$ifconfig $interface down >/dev/null &&
Pass || Fail
done
}
# function Exit(), prints (optional) exit message and runs restore_if_state,
# if needed, then exits. Uses local array 'term_temp_ifup'.
# Exit "<message>"
Exit() {
[ -n "$1" ] && echo -e "$1" >&2
[ ${#term_temp_ifup[@]} -gt 0 ] && restore_if_state ${term_temp_ifup[@]}
exit 1
}
# function Convert_base(), converts data from hex to bin or bin to hex.
# Convert_base [hex2bin|bin2hex] <data>
# returns <converted data>
Convert_base() {
local bintbl
local indata
local indata_len
local cntr
local outdata
local chunk
bintbl=( 0000 0001 0010 0011 \
0100 0101 0110 0111 \
1000 1001 1010 1011 \
1100 1101 1110 1111 )
indata=$(echo $2 | tr '[a-z]' '[A-z]')
indata=${indata#0X}
indata=$(echo $indata | sed 's/^0*//')
[ ${#indata} -lt 1 ] && indata=0
indata_len=${#indata}
cntr=0
unset outdata
while [ $cntr -lt $indata_len ]; do
if [ "$1" == "bin2hex" ]; then
chunk=${indata:$cntr:4}
outdata="$outdata`printf %x $((2#$chunk))`"
let "cntr += 4"
elif [ "$1" == "hex2bin" ]; then
chunk=$(printf %d "0x${indata:$cntr:1}")
outdata="$outdata${bintbl[$chunk]}"
(( cntr++ ))
fi
done
echo $outdata
}
# function Get_bits(), returns bit or bit-range from supplied bitstream.
# Get_bits <bitstream> <upper:lower>|<single bit>
# returns <bits>
Get_bits() {
local data=$1
local start_bit=$(( ${#data} - 1 - ${2%%:*} ))
local stop_bit=$(( ${#data} - 1 - ${2##*:} ))
local length=$(( stop_bit - start_bit + 1 ))
echo ${data:$start_bit:$length}
}
# function Change_bits(), modifies certain bits of a bitstream with hex data.
# Change_bits <bitstream> <upper:lower>|<single bit> <hex data>
# returns <bitstream>
Change_bits() {
local data=$1
local start_bit=$(( ${#data} - 1 - ${2%%:*} ))
local stop_bit=$(( ${#data} - 1 - ${2##*:} ))
local bit_length=$(( stop_bit - start_bit + 1 ))
local stream_hi=${data:0:$start_bit}
local stream_lo=${data:$(( stop_bit + 1 )):$(( ${#data} - 1 ))}
local new_bits=$(Convert_base hex2bin $3)
new_bits=$(printf "%"$bit_length"s" \
$(echo $new_bits | sed 's/^0*//') | sed 's/ /0/g')
echo "$stream_hi$new_bits$stream_lo"
}
# function Check_util(), verifies the specified utility exists, returns the
# path/utility name if the utility is found, if not, returns error.
# var=$(Check_util <utility> [<path>])
Check_util() {
local util=$1
local util_path
shift
util_path=$(builtin type -P $util 2>/dev/null)
if [ -z "$util_path" ]; then
while [ ${#@} -gt 0 ]; do
[ -e "$1" ] && util_path=$1 && break
shift
done
fi
[ -z "$util_path" ] && return 1
echo $util_path
return 0
}
hexdump2bin() {
perl -e 'while ($stream=<>) { chomp $stream; print STDOUT (pack("H" . length($stream), $stream)); }'
}
bin2hexdump() {
perl -e 'while ($stream=<>) { print STDOUT (unpack("H*", $stream)); }'
}
Extract_mmap() {
# mmapr utility is not present on FC5 systems and would assume RHEL5 as well.
# Included my own mmapr (data at end of script).
local arch
local hex_data
local checksum
local cksum_util
Info "The mmapr utility is missing from this system."
# Get tmp file location.
if [ -e "/var/tmp" ]; then
temp_dir="/var/tmp"
else
if [ ! -e "$PWD/.perftune" ]; then
mkdir -p "$PWD/.perftune" || return 1
fi
if [ -d "$PWD/.perftune" ]; then
temp_dir="$PWD/.perftune"
else
return 1
fi
fi
# Get architecture.
arch=$($uname -m | sed 's/i.86/x86/')
case $arch in
x86_64 ) arch=64;;
x86 ) arch=32;;
* ) arch=0
dbg_msg "Unsupported architecture"
return 1;;
esac
Print "Extract internal utility to $temp_dir/mmapr$arch."
if [ -n "$md5sum" ]; then
cksum_util="$md5sum | awk '{print \$1}'"
cksum_value=$(eval echo \$mmapr$arch"md5")
elif [ -n "$cksum" ]; then
cksum_util="$cksum"
cksum_value=$(eval echo \$mmapr$arch"cksum")
else
return 1
fi
checksum=$(cat $0 |\
sed -n '/: <<MMAPR'$arch'/,/MMAPR'$arch'/{/: <<MMAPR'$arch'/b;
/MMAPR'$arch'/b;p}' |\
eval $cksum_util)
if [ "$checksum" != "$cksum_value" ]; then
return 1
fi
# Generate the binary file.
cat $0 |\
sed -n '/: <<MMAPR'$arch'/,/MMAPR'$arch'/{/: <<MMAPR'$arch'/b;
/MMAPR'$arch'/b;p}' |\
hexdump2bin > $temp_dir/mmapr$arch.gz ||
return 1
# Extract the file.
$gzip -d -f "$temp_dir/mmapr$arch.gz" || return 1
# Change file permissions.
chmod +x "$temp_dir/mmapr$arch" || return 1
# Set mmapr_internal command.
mmapr_internal="$temp_dir/mmapr$arch"
Pass
return 0
}
memmapread() {
local address=$1
if [ -n "$mmapr" ]; then
echo $($mmapr /dev/mem $address 1 2>/dev/null | bin2hexdump)
elif [ -n "$mmapr_internal" ]; then
echo $($mmapr_internal $address 1 2>/dev/null | bin2hexdump)
else
echo
fi
}
ShowVersion() {
echo -n "$self version"
echo $REVISION | sed 's/[:$]//g'
exit 0
}
Help() {
echo "usage: $self [options]|-h"
echo "Options:"
echo " -A Disable AMD-8131 Data Corruption bug workaround for PCI-X."
echo " WARNING: Applying the workaround will have a severe impact on"
echo " the performance! Set this option to disable the workaround, but"
echo " be warned, the bus could hang if the bug is encountered. See"
echo " AMD-8131 HT PCI-X Tunnel Revision Guide 26310, section 56, for"
echo " info on the \"133-MHz Mode Split Completion Data Corruption\" bug."
echo " -b Force PCI split transaction/burst tuning parameters."
echo " WARNING: The PCI bridge will auto-negotiate to the best supported"
echo " split/burst parameters. Forcing parameters which have not been"
echo " negotiated by the bridge may not always provide optimal performance."
echo " which would be revealed when setting burst size greater than 512."
echo " -C Disable binding IRQs to CPUs (smp_affinity mask)."
echo " -c <CPU> Set the base CPU for applying the smp_affinity mask."
echo " The affinity_mask will be applied to each interrupt of each"
echo " interface in a round-robin order, starting at the first interface"
echo " encountered. The first interface will be set to the base CPU, the"
echo " second interface will be set to the next CPU (<value> * 2), etc."
echo " -d <value> Enable or disable DDP on Terminator 3 devices. Enable=1, Disable=0."
echo " -D Do not disable IRQ balance daemon."
echo " -H Do not set IRQ smp_affinity to Hyperthreaded (SMT) CPUs."
echo " -I Do not temporarily enable interfaces for tuning."
echo " -L Disable PCI latency tuning parameters."
echo " -m <value> Set the TOM mss_size to <value>."
echo " WARNING: This is not the MSS for the network interface!"
echo " -n Auto load NIC driver module."
echo " The LLD (cxgb3) driver module will be automatically loaded. Only"
echo " applies to Terminator3 devices."
echo " -o Auto load NIC and TOE driver modules."
echo " The LLD (cxgb3), TOE (toecore), and TOM (t3_tom) driver modules"
echo " will automatically be loaded. Do not use this if any additional"
echo " tuning parameters are required to be set prior to enabling offload."
echo " Once offload is enabled, some options cannot be modified."
echo " Only applies to Terminator3 devices."
echo " -P Disable PCI tuning parameters."
echo " -q Be somewhat quiet. Use a second time to be silent."
echo " -S Disable sysctl tuning parameters."
echo " -s Only run sysctl tuning parameters, do not perform other tuning."
echo " -T Disable TOM tuning parameters."
echo " -t <value> Set the TOM max_tx_pages to <value>."
echo " WARNING: Only for Terminator2 devices."
echo " -v Show version."
echo " -w <value> Set the TOM max_wr to <value>."
echo " -W Write sysctls to /etc/sysctl.conf file. This does not write any"
echo " TOE/TOM specific sysctls to the file."
echo " -x Do not use terminal colors."
echo " -Z Enable debugging."
echo " -g Generate self checksum."
echo " -h Help."
Exit
}
[ -e "functions.sh" ] && source "functions.sh"
################################################################################
# This script should only be run by root.
if [ $UID -ne 0 ]; then
Exit "Must be root user (UID 0) to run this script!"
fi
# Command-line options.
Options="AbCc:Dd:HILm:noPqSsTt:vWw:xZgh"
# Get options.
while getopts $Options option; do
case $option in
A ) enable_amd_workaround=0;; # Disable AMD-8131 bug workaround.
b ) enable_pci_burstsplit=1;; # Enable PCI burst/split trans tuning.
C ) tune_cpumask_enable=0;; # Disable CPU mask.
c ) cpu_affinity_index=$OPTARG;;
d ) ddp_state=$OPTARG;; # Set DDP.
D ) disable_irqbalance=0;;
H ) enable_ht_smp_affinity=0;;# Don't set smp_affinity on Hyperthread CPUs.
I ) tune_iface_enable=0;; # Do not temporarily enable interfaces.
L ) enable_pci_latency=0;; # Disable PCI latency tuning.
m ) tom_mss_size=$OPTARG;;
n ) autoload_nic=1;; # Autoload NIC (T3) driver.
o ) autoload_nic=1 # Autoload both NIC and TOE (T3) drivers.
autoload_toe=1;;
P ) tune_pci_enable=0;; # Disable PCI tuning.
q ) (( quiet++ ));; # Be quiet.
S ) tune_sysctl_enable=0;; # Disable sysctl tuning.
s ) tune_sysctl_only=1 # Only perform sysctls, disable others.
disable_irqbalance=0
tune_tom_enable=0
tune_iface_enable=0;;
T ) tune_tom_enable=0;; # Disable TOM tuning.
t ) tom_max_tx_pages=$OPTARG;;
v ) ShowVersion;;
W ) write_sysctls=1;; # Write sysctls to /etc/sysctl.conf file.
w ) tom_max_wr=$OPTARG;;
x ) use_colors=0;; # Do not use terminal colors.
Z ) debug=1;;
g ) generate_self_checksum=1;;
* ) Help;;
esac
done
if (( $tune_sysctl_only )); then
tune_pci_enable=0 # Disable PCI tuning.
tune_tom_enable=0 # Disable TOM tuning.
tune_cpumask_enable=0 # Disable CPU mask.
tune_iface_enable=0 # Don't enable interfaces.
fi
# Option error checking.
# tom_max_tx_pages can only be a decimal value.
tom_max_tx_pages=${tom_max_tx_pages//*[^0-9]*/X}
# cpu_affinity_index input should be an integer
# no larger than the number of CPUs on the system.
cpu_affinity_index=${cpu_affinity_index//*[^0-9]*/X}
# tom_mss_size can only be decimal values.
tom_mss_size=${tom_mss_size//*[^0-9]*/X}
# ddp_state can only be on or off (1 or 0).
ddp_state=${ddp_state//*[^0-1]*/X}
tom_max_tx_pages=${tom_max_tx_pages//*[^0-9]*/X}
if [ -n "$tom_mss_size" ]; then
# This variable will later be copied to the correct element in the
# array after determining the board type.
if [ "$tom_mss_size" == "X" ]; then
echo "-m: tom_mss_size must be an integer value." >&2
(( args_failed++ ))
fi
if [ $tom_mss_size -eq 0 ]; then
echo "-m: tom_mss_size must not be 0 value." >&2
fi
fi
if [ -n "$tom_max_tx_pages" ]; then
if [ "$tom_max_tx_pages" == "X" ] ||
(( tom_max_tx_pages < 2 | tom_max_tx_pages > 16 )); then
echo "-t: tom_max_tx_pages must be an integer between 2 and 16." >&2
(( args_failed++ ))
fi
fi
if [ -n "$tom_max_wr" ]; then
if [ "$tom_max_wr" == "X" ] ||
(( tom_max_wr < 1 | tom_max_wr > 16 )); then
echo "-w: tom_max_wr must be an integer between 1 and 16." >&2
(( args_failed++ ))
fi
fi
if [ -n "$cpu_affinity_index" ]; then
if [ "$cpu_affinity_index" == "X" ]; then
echo "-c: cpu_affinity_index must be an integer." >&2
(( args_failed++ ))
fi
fi
if [ -n "$ddp_state" ]; then
if [ "$ddp_state" == "X" ]; then
echo "-d: ddp must be 1 or 0 (enabled or disabled)." >&2
(( args_failed++ ))
fi
fi
(( $args_failed )) && Exit "ERROR: Failed arguments."
(( $quiet )) && [ $quiet -gt 1 ] && silent=1
# Trap INT signal.
trap 'Exit "Exit on signal INT."' TERM INT
# Make sure the required utilities are available.
lspci=$(Check_util lspi /sbin/lspci /usr/bin/lspci) ||
{ Fail "Can't locate lspci utility!"; (( fail_util++ )); }
setpci=$(Check_util setpci /sbin/setpci /usr/bin/setpci) ||
{ Fail "Can't locate setpci utility!"; (( fail_util++ )); }
uname=$(Check_util uname /bin/uname) ||
{ Fail "Can't locate uname utility!"; (( fail_util++ )); }
sysctl=$(Check_util sysctl /sbin/sysctl) ||
{ Fail "Can't locate sysctl utility!"; (( fail_util++ )); }
ifconfig=$(Check_util ifconfig /sbin/ifconfig) ||
{ Fail "Can't locate ifconfig utility!"; (( fail_util++ )); }
cp=$(Check_util cp /bin/cp) ||
{ Fail "Can't locate cp utility!"; (( fail_util++ )); }
mv=$(Check_util mv /bin/mv) ||
{ Fail "Can't locate mv utility!"; (( fail_util++ )); }
grep=$(Check_util grep /bin/grep /usr/bin/grep) ||
{ Fail "Can't locate grep utility!"; (( fail_util++ )); }
cat=$(Check_util cat /bin/cat) ||
{ Fail "Can't locate cat utility!"; (( fail_util++ )); }
cksum=$(Check_util cksum /usr/bin/cksum) ||
{ Warn "Can't locate cksum utility!"; }
gzip=$(Check_util gzip /bin/gzip) ||
{ Warn "Can't locate gzip utility!"; }
md5sum=$(Check_util md5sum /usr/bin/md5sum) ||
{ Warn "Can't locate md5sum utility!"; }
chkconfig=$(Check_util chkconfig /sbin/chkconfig) ||
{ Warn "Can't locate chkconfig utility!"; }
modprobe=$(Check_util modprobe /sbin/modprobe) ||
{ Print "Can't locate modprobe utility!";
(( $autoload_nic )) && { Fail; (( fail_util++ )); } \
|| Warn; }
lsmod=$(Check_util lsmod /sbin/lsmod) ||
{ Print "Can't locate lsmod utility!";
(( $autoload_nic )) && { Fail; (( fail_util++ )); } \
|| Warn; }
if (( $fail_util )); then
Exit "Cannot proceed with missing system utilities."
fi
if (( $(not tune_sysctl_only) )); then
mmapr=$(Check_util mmapr /usr/X11R6/bin/mmapr) ||
{ Extract_mmap || {
tune_pci_enable=0;
tune_iface_enable=0;
Fail "Problem using memory map utility."; };
}
fi
# Perform self check.
if (( $generate_self_checksum )); then
echo $(tail -n +$HARDSTART $0 | $cksum)
exit 0
fi
checksum=$(tail -n +$HARDSTART $0 | $cksum)
if [ "$checksum" != "$SELFCKSUM" ]; then
Warn "This script has been modified from the original!"
fi
# Set system variables.
[ -d '/proc' ] || Exit "ERROR: No /proc filesystem found!"
term_if_count=0
smp_kernel=$($uname -v | $grep SMP)
num_cpus=$(cat /proc/cpuinfo | $grep -c "^processor")
[ -z "$tom_tcp_timestamps" ] && tom_tcp_timestamps=$tcp_timestamps
[ -n "$ddp_state" ] && tom_ddp=$ddp_state
# Define the name of the userspace IRQ balance daemon.
# This name is different on various distributions.
daemon_check=/etc/init.d/irq*
for irqbalance in $daemon_check; do
echo $irqbalance | $grep "irq" | $grep "balance" >/dev/null && break;
done
if $irqbalance status 1>/dev/null 2>&1; then
if (( $disable_irqbalance )); then
Print "Disabling IRQ balance daemon."
$irqbalance stop 1>/dev/null 2>&1 &&
Pass || { Fail; }
else
Warn "IRQ Balance daemon is running."
fi
else
Print "IRQ Balance daemon is not running." && Pass
fi
# If using a kernel which exports the thread_siblings to sysfs,
# I can determine which CPUs are Hyperthreaded (SMT) and not
# bind those to an interrupt vector, otherwise, I need to assume
# that all CPUs are "real".
[ -e '/sys/devices/system/cpu/cpu0/topology/thread_siblings' ] &&
(( thread_sib++ ))
# Disable setting SMT smp_affinity if commanded to do so.
(( $(not $enable_ht_smp_affinity) )) && thread_sib=0
# Get the number of processors.
if [ -n "$smp_kernel" ] && (( $thread_sib )); then
# Populate the sibling map for each CPU.
for ((i=0; i < $num_cpus; i++)); do
sib_map[$i]="$(cat /sys/devices/system/cpu/cpu$i/topology/thread_siblings)"
done
for ((i=0; i < $num_cpus; i++)); do
for ((j=0; j < $num_cpus; j++)); do
# Skip same CPUs.
if [ $i -ne $j ] && (( $(not ${ht_cpu[$i]}) )); then
# Hyperthreaded CPUs have the same thread_sibling string.
if [ "${sib_map[$i]}" == "${sib_map[$j]}" ]; then
ht_cpu[$j]=1
break
fi
fi
done
done
# Setup the affinity mask.
for ((i=0; i < $num_cpus; i++)); do
if (( $(not ${ht_cpu[$i]}) )); then
affinity_mask[${#affinity_mask[@]}]=$(printf "%x" $(echo $(( 2 ** $i ))))
phys_cpus[${#phys_cpus[@]}]=$i
(( num_phys_cpus++ ))
fi
done
elif [ -n "$smp_kernel" ]; then
# All CPUs will be treated as real.
for ((i=0; i < $num_cpus; i++)); do
affinity_mask[${#affinity_mask[@]}]=$(printf "%x" $(echo $(( 2 ** $i ))))
phys_cpus[${#phys_cpus[@]}]=$i
(( num_phys_cpus++ ))
done
else
# This is a single CPU, affinity does not apply.
num_phys_cpus=1
fi
if [ $cpu_affinity_index -gt $(( num_phys_cpus - 1 )) ]; then
Warn "Invalid CPU index $cpu_affinity_index, using 0 instead."
cpu_affinity_index=0
fi
# Autoload drivers before tuning.
if (( $autoload_nic )); then
# Check if the LLD module is loaded.
if $lsmod | $grep "$T3_LLD_MODULE " 1>/dev/null 2>&1; then
Info "Terminator 3 LLD ($T3_LLD_MODULE) already loaded."
else
# Check if the LLD module is installed.
if $modprobe -n $T3_LLD_MODULE 1>/dev/null 2>&1; then
# Try to load the module since it's installed.
if $modprobe $T3_LLD_MODULE 1>/dev/null 2>&1; then
Pass "Loaded Terminator 3 LLD ($T3_LLD_MODULE)."
else
Fail "Failed to load Terminator 3 LLD ($T3_LLD_MODULE)."
fi
else
Warn "Terminator 3 LLD ($T3_LLD_MODULE) not installed."
(( driver_not_installed++ ))
fi
fi
fi
if (( $autoload_toe )); then
# Check if the TOE module is loaded.
if $lsmod | $grep "$T3_TOE_MODULE " 1>/dev/null 2>&1; then
Info "Chelsio TOE module ($T3_TOE_MODULE) already loaded."
else
# Check if the TOE module is installed.
if $modprobe -n $T3_TOE_MODULE 1>/dev/null 2>&1; then
# Try to load the module since it's installed.
if $modprobe $T3_TOE_MODULE 1>/dev/null 2>&1; then
Pass "Loaded Chelsio TOE module ($T3_TOE_MODULE)."
else
Fail "Failed to load Chelsio TOE module ($T3_TOE_MODULE)."
fi
else
Warn "Chelsio TOE module ($T3_TOE_MODULE) not installed."
# TOECORE could be part of the kernel.
fi
fi
if $lsmod | $grep "$T3_TOM_MODULE " 1>/dev/null 2>&1; then
Info "Terminator 3 TOM ($T3_TOM_MODULE) already loaded."
else
# Check if the TOM module is installed.
if $modprobe -n $T3_TOM_MODULE 1>/dev/null 2>&1; then
# Try to load the module since it's installed.
if $modprobe $T3_TOM_MODULE 1>/dev/null 2>&1; then
Pass "Loaded Terminator 3 TOM ($T3_TOM_MODULE)."
else
Fail "Failed to load Terminator 3 TOM ($T3_TOM_MODULE)."
fi
else
Warn "Terminator 3 TOM ($T3_TOE_MODULE) not installed."
# TOM could be part of the kernel.
fi
fi
fi
# Get the correct TOM devices path.
if [ -e '/proc/net/toe/devices' ]; then
tom_device_path="/proc/net/toe"
elif [ -e '/proc/net/offload/devices' ]; then
tom_device_path="/proc/net/offload"
fi
# Get the PCI slots for the Chelsio card(s).
IFS=$'\n'
term_pci_device=($($lspci -m -n -d $CHELSIO_PCI_VID: | awk '{print $1}'))
unset IFS
# Get architecture.
arch=$($uname -m | sed 's/i.86/x86/')
case $arch in
x86_64 ) arch=64;;
x86 ) arch=32;;
ia64) (( tune_sysctl_only++ ));;
* ) arch=0;;
esac
# Main PCI device loop.
(( $(not $tune_sysctl_only) )) &&
for (( idx=0; idx < ${#term_pci_device[@]}; idx++ )); do
# On some versions of lspci, the domain is printed first [xxxx:].
# Remove it so that everything is standard.
term_pci_bus_pri[$idx]=$(echo ${term_pci_device[$idx]} |
sed 's/\([0-9a-zA-Z]\)\{4\}://' |
sed 's/:.*//')
# Get the data for each slot.
IFS=$'\n'
data=($($lspci -n -vv -s ${term_pci_device[$idx]}))
# Get the interface data for all interfaces, split on paragraphs.
iface_data=($($ifconfig -a | awk 'BEGIN { FS="\n"; RS=""; ORS="" };\
{ x=1;
while ( x<NF ) { print $x " "; x++ }\
print $NF "\n" }'))
unset IFS
# Get the device ID (board ID) of the card(s) and
# remove any leading/trailing whitespace.
term_dev_id[$idx]=$(echo ${data[0]} | \
awk "{split(\$0,a,\"$CHELSIO_PCI_VID:\");\
print a[2]}" |\
sed 's/^[ \t]*//;s/[ \t]*$//')
# Test the board ID's and define the type(s).
# term_dev_id should not contain non-hex characters.
echo ${term_dev_id[$idx]} | $grep -q '[^0-9a-fA-F]' && term_dev_id[$idx]=0
[ $(printf %i 0x${term_dev_id[$idx]}) -ge 32 ] && term_type[$idx]=3
[ $(printf %i 0x${term_dev_id[$idx]}) -lt 32 ] && term_type[$idx]=2
[ $(printf %i 0x${term_dev_id[$idx]}) -eq 0 ] && term_type[$idx]=0
# Set the register address based on board type.
PCIX_CMD_ADDR=${PCIX_CMD_ADDR[${term_type[$idx]}]}
PCIX_CFG_MODE_ADDR=${PCIX_CFG_MODE_ADDR[${term_type[$idx]}]}
PCIX_MODE_OFFSET=${PCIX_MODE_OFFSET[${term_type[$idx]}]}
PCI_BAR_REG=${PCI_BAR_REG[${term_type[$idx]}]}
PCIX_LAT_TMR_ADDR=${PCIX_LAT_TMR_ADDR[${term_type[$idx]}]}
PCIE_LINK_STAT=${PCIE_LINK_STAT[${term_type[$idx]}]}
PCIE_LINK_CAP=${PCIE_LINK_CAP[${term_type[$idx]}]}
if [ ${term_type[$idx]} -eq 2 ]; then
pcix_mode_data=$($setpci -s ${term_pci_device[$idx]} $PCIX_CFG_MODE_ADDR.b)
pcix_mode_data=$(Convert_base hex2bin $pcix_mode_data)
pcix_mode_data=$(Convert_base bin2hex ${pcix_mode_data:3:3})
# All T2's are PCI-X, except for device 15.
term_board_id=$(printf %i 0x${term_dev_id[$idx]})
if [ $term_board_id -ne 15 ]; then
term_pcix[$idx]=1
else
unset term_pcix[$idx]
fi
# Identify multi-port cards.
case $term_board_id in 12 | 13 | 15 | 16 ) term_multiport[$idx]=1;;
* ) term_multiport[$idx]=0;;
esac
fi
if [ ${term_type[$idx]} -eq 3 ]; then
term_pcix[$idx]=$($setpci -s ${term_pci_device[$idx]} $PCIX_CMD_ADDR.b | sed 's/0//g')
if (( ${term_pcix[$idx]} )); then
# PCI/PCI-X
bar_addr="0x$($setpci -s ${term_pci_device[$idx]} $PCI_BAR_REG.l)"
bar_addr=$(printf 0x%x $(echo $(( bar_addr & 0xfffffff0 )) ))
pcix_mode_addr=$(printf 0x%x $(echo $(( bar_addr + PCIX_MODE_OFFSET )) ))
pcix_mode_data=$(memmapread $pcix_mode_addr)
if [ -n "$pcix_mode_data" ]; then
pcix_mode_data=$(Convert_base hex2bin $pcix_mode_data)
pcix_mode_data=$(Convert_base bin2hex ${pcix_mode_data:0:2})
else
Fail "Could not get data at memory address $pcix_mode_addr!"
Warn "Skip PCI-X tuning."
tune_pci_enable=0
fi
else
# PCI-Express.
# Capability.
cap_data="0x$($setpci -s ${term_pci_device[$idx]} $PCIE_LINK_CAP.l)"
cap_width=$(Get_bits $(Convert_base hex2bin $cap_data) 9:4)
pcie_bus_cap=$(Convert_base bin2hex $cap_width)
# Linked.
link_data="0x$($setpci -s ${term_pci_device[$idx]} $PCIE_LINK_STAT.l)"
link_width=$(Get_bits $(Convert_base hex2bin $link_data) 25:20)
pcie_bus_width=$(Convert_base bin2hex $link_width)
fi
fi
# Set speed values based on register settings.
if (( ${term_pcix[$idx]} )); then
case $pcix_mode_data in
3 ) term_pcix_speed[$idx]=133;;
2 ) term_pcix_speed[$idx]=100;;
1 ) term_pcix_speed[$idx]=66;;
0 ) term_pcix_speed[$idx]=33;;
* ) term_pcix_speed[$idx]=0;;
esac
else
case $pcie_bus_width in
1 ) term_pcie_width[$idx]=1;;
2 ) term_pcie_width[$idx]=2;;
4 ) term_pcie_width[$idx]=4;;
8 ) term_pcie_width[$idx]=8;;
16 ) term_pcie_width[$idx]=16;;
32 ) term_pcie_width[$idx]=32;;
esac
case $pcie_bus_cap in
1 ) term_pcie_cap[$idx]=1;;
2 ) term_pcie_cap[$idx]=2;;
4 ) term_pcie_cap[$idx]=4;;
8 ) term_pcie_cap[$idx]=8;;
16 ) term_pcie_cap[$idx]=16;;
32 ) term_pcie_cap[$idx]=32;;
esac
fi
# Get the Terminator card host bridge device.
IFS=$'\n'
lspci_data=($($lspci -v | awk 'BEGIN { FS="\n"; RS=""; ORS="" }; \
{ x=1; while ( x<NF ) { print $x " "; x++ }\
print $NF "\n" }'))
for device in ${lspci_data[@]}; do
unset IFS
if $(echo $device |
$grep "Bus:.*secondary=${term_pci_bus_pri[$idx]}" >/dev/null); then
term_host_bridge[$idx]=$(echo $device |\
awk '{print $1}' |\
sed 's/\([0-9a-zA-Z]\)\{4\}://')
fi
done
unset IFS
# The term devices are given an interrupt from the kernel at bootup.
# Then, the interrupt vector is replaced, but the original interrupt
# is used in ifconfig. If there are two cards in the system, they both
# may get the same interrupt, and this IRQ may not even show up in
# /proc/interrupts! This requires another method of identifying the
# device in the ifconfig list. MAC address cannot be used, since it
# could not be programmed yet (internal use).
# The device base (Region 0) memory address should be sufficient to
# uniquely identify a device in the ifconfig list based on the data from
# lspci.
# Get memory address used by the device.
term_mem_addr[$idx]=$(echo ${data[@]} |
awk '{split($0,a,"Region 0: Memory at "); print a[2]}' |
sed 's/ .*//;/^$/d')
[ -z "${term_mem_addr[$idx]}" ] && term_mem_addr[$idx]='none'
unset data
# Get the card interface (based on memory address).
# Record interface up/down status.
IFS=$'\n'
for data in ${iface_data[@]}; do
unset IFS
if echo $data | $grep "Memory:${term_mem_addr[$idx]}" >/dev/null; then
interface=$(echo $data | awk '{print $1}')
# If the interface is up, assign term_iface_up.
# A card may have more than one interface.
if echo $data | $grep -q 'UP' >/dev/null; then
term_iface_up[$idx]="$(echo ${term_iface_up[$idx]} $interface |
sed 's/^[ \t]*//;s/[ \t]*$//')"
(( term_if_count++ ))
else
# If the interface is down...
if (( $tune_iface_enable )); then
# Bring interface up without configuring it and assign term_iface_up.
# Flag the interfaces which were brought up w/o configuring.
# Need to bring these down later.
term_temp_ifup[$idx]="$(echo ${term_temp_ifup[$idx]} $interface |
sed 's/^[ \t]*//;s/[ \t]*$//')"
Print "Enable interface $interface."
$ifconfig $interface up >/dev/null &&
Pass || { Fail &&
Exit "Failed to enable interface $interface for tuning."; }
(( term_if_count++ ))
term_iface_up[$idx]="$(echo ${term_iface_up[$idx]} $interface |
sed 's/^[ \t]*//;s/[ \t]*$//')"
else
# Skip it and print warning.
Warn "Skip tuning interface $interface, it's not up!"
skip_down_interfaces[$idx]="$(echo ${skip_down_interfaces[$idx]} \
$interface |
sed 's/^[ \t]*//;s/[ \t]*$//')"
unset term_iface_up[$idx]
fi
fi
# These are the interfaces assigned to the Chelsio card(s).
term_iface[$idx]="$(echo ${term_iface[$idx]} $interface |
sed 's/^[ \t]*//;s/[ \t]*$//')"
fi
done
unset iface_data
unset IFS
# Get the interrupt data.
IFS=$'\n'
intr_data=($(cat /proc/interrupts))
unset IFS
# Identify the interrupts (MSI/MSI-X) assigned to the interface.
for interface in ${term_iface[$idx]}; do
IFS=$'\n'
for data in ${intr_data[@]}; do
unset IFS
if [ -z "${term_card_intr[$idx]}" ]; then
term_card_intr[$idx]=$(echo $data |\
$grep $interface |\
$grep -v queue 1>/dev/null 2>&1)
fi
if echo $data | $grep $interface | $grep queue 1>/dev/null 2>&1; then
qset=$(echo $data | $grep $interface | $grep queue |
sed 's/.*(queue //;s/).*//')
# term_qset unused for now.
term_qset[$idx]="$(echo ${term_qset[$idx]} $qset)"
intr="$(echo $data | awk '{print $1}' |
sed 's/://'):$interface"
else
unset intr
fi
if echo $data | $grep $interface 1>/dev/null 2>&1; then
if [ ${term_type[$idx]} == 3 ] && [ -z "$qset" ]; then
:
else
term_intr[$idx]="$(echo ${term_intr[$idx]} \
$(echo $intr | sed 's/^[ \t]*//;s/[ \t]*$//'))"
fi
fi
done
done
# Get TOM module for interface, if this is a TOE card/driver.
if [ -n "$tom_device_path" ]; then
IFS=$'\n'
tom_devices=($(cat $tom_device_path/devices | sed '/Device/d'))
unset IFS
for interface in ${term_iface[$idx]}; do
IFS=$'\n'
for data in ${tom_devices[@]}; do
unset IFS
offload_interfaces=$(echo $data |
awk '{for(field=3; field<=NF; field++) \
print $field}')
if echo $offload_interfaces | $grep $interface >/dev/null; then
term_tom_module[$idx]=$(echo $data | awk '{print $1}')
# Assign TOM name if loaded.
term_tom_loaded[$idx]=$(echo $data | awk '{print $2}' | sed 's/<none>//i')
fi
done
unset data
done
unset IFS
fi
done
# Exit if all interfaces down.
if [ $term_if_count -lt 1 ] && (( $(not $tune_sysctl_only) )); then
Fail "All Chelsio network interfaces are down!"
if (( $tune_iface_enable )); then
if (( $driver_not_installed )); then
Info "The LLD is not installed."
else
Info "Be sure the driver is loaded."
fi
else
Info "Denied access to enable network interfaces."
fi
Exit
fi
# Device loop, perform tuning.
(( $(not $tune_sysctl_only) )) &&
for (( idx=0; idx < ${#term_pci_device[@]}; idx++ )); do
# Warn about PCI-X bus speed.
if (( ${term_pcix[$idx]} )); then
if [ ${term_pcix_speed[$idx]} -lt 133 ]; then
for iface in ${term_iface[$idx]}; do
Warn "$iface: PCI-X speed is ${term_pcix_speed[$idx]}Mhz."
done
else
for iface in ${term_iface[$idx]}; do
Pass "$iface: PCI-X speed is ${term_pcix_speed[$idx]}Mhz."
done
fi
fi
# Warn about PCI-E bus width.
if (( $(not ${term_pcix[$idx]}) )); then
if [ ${term_pcie_width[$idx]} -lt ${term_pcie_cap[$idx]} ]; then
for iface in ${term_iface[$idx]}; do
Print "$iface: PCI-E x${term_pcie_cap[$idx]} device "
Say "running in x${term_pcie_width[$idx]} slot."
Warn
done
else
for iface in ${term_iface[$idx]}; do
Print "$iface: PCI-E x${term_pcie_width[$idx]} device "
Say "using all lanes."
Pass
done
fi
fi
# PCI TUNING ###################################################################
if (( ${term_pcix[$idx]} )) && (( $tune_pci_enable )) &&
[ -n "${term_host_bridge[$idx]}" ]; then
dbg_msg "PCI-X device ${term_dev_id[$idx]} running at ${term_pcix_speed[$idx]}Mhz.\n"
# Check for AMD-8131 PCI-X bridge "133Mhz Mode Split Completion Data Corruption" bug.
host_bridge_venid[$idx]=$($setpci -s ${term_host_bridge[$idx]} 0x00.w \
2>/dev/null)
host_bridge_devid[$idx]=$($setpci -s ${term_host_bridge[$idx]} 0x02.w \
2>/dev/null)
host_bridge_rev[$idx]="0x$($setpci -s ${term_host_bridge[$idx]} 0x08.b \
2>/dev/null)"
host_bridge_rev[$idx]=$(printf %i ${host_bridge_rev[$idx]})
# AMD-8131 running at 133Mhz.
if [ "${host_bridge_venid[$idx]}" == "$AMD_PCI_VID" ] &&
[ "${host_bridge_devid[$idx]}" == "$AMD_8131_DEVID" ] &&
[ ${host_bridge_rev[$idx]} -le $AMD_8131_BUG_REV ] &&
[ ${term_pcix_speed[$idx]} -eq 133 ]; then
dbg_msg "Going to fix AMD PCI-X bug for card ${term_pci_device[$idx]}."
# Found an AMD-8131 bridge and the device is running at 133Mhz,
# there's a chance of hitting 8131 data corruption bug.
# Get PCIX CMD data.
pcix_cmd_data=$(Convert_base hex2bin \
$($setpci -s ${term_pci_device[$idx]} \
$PCIX_CMD_ADDR.l) \
2>/dev/null)
# Get current PCIX Split Transaction.
pcix_current_split_trans="0x$(Convert_base bin2hex \
$(Get_bits $pcix_cmd_data 22:20))"
# Get current PCIX Burst Size.
pcix_current_rd_byte_cnt="0x$(Convert_base bin2hex \
$(Get_bits $pcix_cmd_data 19:18))"
# Conditions in which the AMD-8131 bug would NOT be present:
# max_split_trans = 0x0 (1) max_rd_byte_cnt = 0x2 (2048b)
# max_split_trans = 0x1 (2) max_rd_byte_cnt = 0x1 (1024b)
# max_split_trans = 0x2 (3) max_rd_byte_cnt = 0x0 (512b)
if [ $(echo $(( pcix_current_split_trans + \
pcix_current_rd_byte_cnt )) ) -gt 2 ]; then
# This configuration would cause the data corruption bug!
pcix_cmd_data=$(Change_bits $pcix_cmd_data 22:20 $SAFE_PCIX_SPLIT_TRAN)
pcix_cmd_data=$(Change_bits $pcix_cmd_data 19:18 $SAFE_PCIX_BURST_SIZE)
pcix_cmd_data="0x$(Convert_base bin2hex $pcix_cmd_data)"
iface_bug=$(echo ${term_iface[$idx]} | sed 's/ /, /')
Warn "Found AMD-8131 bug on interface(s) $iface_bug."
if (( $enable_amd_workaround )); then
Print "AMD-8131 bug workaround for interface(s) $iface_bug."
# Apply the workaround values, this will degrade performance a bit.
$setpci -s ${term_pci_device[$idx]} \
"$PCIX_CMD_ADDR.l=$pcix_cmd_data" \
>/dev/null 2>&1 &&
Pass || Fail
else
Warn "Skip workaround for AMD-8131 bug!"
fi
fi
else # not AMD-8131 running at 133Mhz.
if (( $enable_pci_burstsplit )); then
# Tune the PCI burst size and outstanding split transactions reg.
dbg_msg "Going to crank up PCI-X bus settings for dev ${term_pci_device[$idx]}."
pcix_cmd_data=$(Convert_base hex2bin \
$($setpci -s ${term_pci_device[$idx]} \
$PCIX_CMD_ADDR.l) \
2>/dev/null)
pcix_cmd_data=$(Change_bits $pcix_cmd_data 22:20 $PERF_PCIX_SPLIT_TRAN)
pcix_cmd_data=$(Change_bits $pcix_cmd_data 19:18 $PERF_PCIX_BURST_SIZE)
pcix_cmd_data="0x$(Convert_base bin2hex $pcix_cmd_data)"
Print "Set PCI-X split/burst parameters."
$setpci -s ${term_pci_device[$idx]} \
"$PCIX_CMD_ADDR.l=$pcix_cmd_data" \
>/dev/null 2>&1 &&
Pass || Fail
fi
fi
# PCI LATENCY ##################################################################
if (( $enable_pci_latency )); then
# Tune the PCI Latency Timer.
pcix_lat_tmr_data=$(Convert_base hex2bin \
$($setpci -s ${term_pci_device[$idx]} \
$PCIX_LAT_TMR_ADDR.l) \
2>/dev/null)
pcix_lat_tmr_data=$(Change_bits $pcix_lat_tmr_data 15:8 $PERF_PCI_LAT_TMR)
pcix_lat_tmr_data="0x$(Convert_base bin2hex $pcix_lat_tmr_data)"
Print "Set PCI-X latency timer parameters."
$setpci -s ${term_pci_device[$idx]} \
"$PCIX_LAT_TMR_ADDR.l=$pcix_lat_tmr_data" \
>/dev/null 2>&1 &&
Pass || Fail
fi
elif (( ${term_pcix[$idx]} )); then
Warn "Skip PCI-X tuning!"
fi # end PCI-X tuning.
# Tuning for interfaces which are up.
interfaces=${term_iface_up[$idx]}
if [ -n "$interfaces" ]; then
# SMP AFFINITY #################################################################
if ((tune_cpumask_enable)); then
for iface in ${interfaces[@]}; do
for interrupt_data in ${term_intr[$idx]}; do
associated_iface=${interrupt_data##*:}
interrupt=${interrupt_data%:*}
# Only set smp_affinity for SMP systems.
if [ $num_phys_cpus -gt 1 ]; then
if [ "$associated_iface" == "$iface" ]; then
Print "$iface: Set IRQ $(printf "%3d" $interrupt)"
Say " smp_affinity to CPU${phys_cpus[$cpu_affinity_index]}."
echo ${affinity_mask[$cpu_affinity_index]} \
2>/dev/null > /proc/irq/$interrupt/smp_affinity &&
Pass || { Fail && (( failed++ )); }
fi
(( cpu_affinity_index++ ))
if [ $cpu_affinity_index -ge $num_phys_cpus ]; then
cpu_affinity_index=0
fi
fi
done
done
fi
if (( $tune_tom_enable )); then
# TOM TUNING ###################################################################
if [ -n "${term_tom_module[$idx]}" ]; then
if [ -n "${term_tom_loaded[$idx]}" ]; then
# Terminator 2 specific.
if [ ${term_type[$idx]} -eq 2 ] && [ ${term_multiport[$idx]} -ne 1 ]; then
# max_tx_pages
if [ -n "$tom_max_tx_pages" ]; then
Print "TOM(${term_tom_module[$idx]}): Set 'max_tx_pages=$tom_max_tx_pages'."
$sysctl -w \
"toe.${term_tom_module[$idx]}_tom.max_tx_pages=$tom_max_tx_pages"\
>/dev/null 2>&1 &&
Pass || { Fail && (( failed_tom_sysctl++ )); }
fi
fi
# Terminator 3 specific.
if [ ${term_type[$idx]} -eq 3 ]; then
# ddp
if [ -n "$tom_ddp" ]; then
(( $tom_ddp )) && action="Enable" || action="Disable"
Print "TOM(${term_tom_module[$idx]}): $action DDP."
$sysctl -w \
"toe.${term_tom_module[$idx]}_tom.ddp=$tom_ddp" \
>/dev/null 2>&1 &&
Pass || { Fail && (( failed_tom_sysctl++ )); }
fi
# max_wr
if [ -n "$tom_max_wr" ]; then
Print "TOM(${term_tom_module[$idx]}): Set 'max_wr=$tom_max_wr'."
$sysctl -w \
"toe.${term_tom_module[$idx]}_tom.max_wr=$tom_max_wr" \
>/dev/null 2>&1 &&
Pass || { Fail && (( failed_tom_sysctl++ )); }
fi
# delayed_ack
if [ -n "$tom_delayed_ack" ]; then
Print "TOM(${term_tom_module[$idx]}): "
Say "Set 'delayed_ack=$tom_delayed_ack'."
$sysctl -w \
"toe.${term_tom_module[$idx]}_tom.delayed_ack=$tom_delayed_ack" \
>/dev/null 2>&1 &&
Pass || { Fail && (( failed_tom_sysctl++ )); }
fi
# tcp_timestamps
for iface in ${term_iface[$idx]}; do
if [ -e "/sys/class/net/$iface/tcp_timestamps" ]; then
(( $tom_tcp_timestamps )) && action="Enable" || action="Disable"
Print "TOM(${term_tom_module[$idx]})[$iface]: $action TCP timestamps."
echo "$tom_tcp_timestamps" \
1> "/sys/class/net/$iface/tcp_timestamps" 2>/dev/null &&
Pass || { Fail && (( failed_tom_sysctl++ )); }
fi
done
# zcopy
# Increase zcopy_sendmsg_partial_copy if on 32-bit arch and using
# a PCI-X card or PCI-Express x4 or slower.
if [ -n "$zcopy_tweak" ] && [ $arch -le 32 ] &&
( [ -n "${term_pcix[$idx]}" ] ||
( [ -n "${term_pcie_width[$idx]}" ] &&
[ ${term_pcie_width[$idx]} -le 4 ] ) ); then
Print "TOM(${term_tom_module[$idx]}): "
Say "Set 'zcopy_sendmsg_partial_copy=$zcopy_tweak'."
$sysctl -w \
"toe.${term_tom_module[$idx]}_tom.zcopy_sendmsg_partial_copy=$zcopy_tweak" \
>/dev/null 2>&1 &&
Pass || { Fail && (( failed_tom_sysclt++ )); }
fi
fi
# Global or non-Terminator version specific.
if [ -n "$tom_mss_size" ]; then
# Override the in-script tom_mss_size with supplied parameter.
tom_mss_size[${term_type[$idx]}]=$tom_mss_size
fi
if [ -n "${tom_mss_size[${term_type[$idx]}]}" ]; then
Print "TOM(${term_tom_module[$idx]}): Set 'tom.mss' to ${tom_mss_size[${term_type[$idx]}]}."
$sysctl -w \
"toe.${term_tom_module[$idx]}_tom.mss=${tom_mss_size[${term_type[$idx]}]}" \
>/dev/null 2>&1 &&
Pass || { Fail && (( failed_tom_sysclt++ )); }
fi
(( $failed_tom_sysctl )) &&
Warn "Some TOM sysctls failed, system may not be tuned!"
else
Warn "TOM(${term_tom_module[$idx]}): offload disabled, skip tuning!"
fi # end TOM loaded.
else
Warn "TOM driver not loaded, skip tuning!"
fi # end TOM tuning enabled.
else
Warn "Skip TOM tuning!"
fi # end Tuning for TOM.
fi # end Tuning for interfaces which are up.
# Tuning which does not require an interface to be up, loop per device.
if [ ${term_type[$idx]} -eq 2 ]; then
:
fi
if [ ${term_type[$idx]} -eq 3 ]; then
:
fi
done
restore_if_state ${term_temp_ifup[@]}
# SYSCTL TUNING ################################################################
if (( $tune_sysctl_enable )); then
Info "Set sysctls..."
if (( $write_sysctls )); then
Info "Writing sysctl entries to $sysctl_conf_file."
# Create a backup file.
if [ ! -e "$sysctl_conf_file.perftune.bak" ]; then
$cp -fa $sysctl_conf_file "$sysctl_conf_file.perftune.bak"
fi
fi
IFS=$'\n'
for control in ${sysctl_data[@]}; do
unset IFS
sysctl_param=${control%%,*}
sysctl_param=$(echo $sysctl_param | sed 's/^[ \t]*//;s/[ \t]*$//')
data=${control##*,}
data=$(echo $data | sed 's/^[ \t]*//;s/[ \t]*$//')
[ -z "$data" ] && continue
unset failed_sysctl
if $sysctl $sysctl_param >/dev/null 2>&1; then
Print "Set $sysctl_param=\"$data\""
$sysctl -w "$sysctl_param=$data" >/dev/null 2>&1 && Pass ||
{ (( failed_sysctl++ )); Fail; }
if (( $write_sysctls )) && (( $(not $failed_sysctl_file) )); then
if ! $grep $sysctl_param $sysctl_conf_file >/dev/null 2>&1; then
echo "$sysctl_param = $data" >> $sysctl_conf_file ||
(( failed_sysctl_file++ ))
else
# Entry already exists, overwrite it!
$cat $sysctl_conf_file |
sed "s/$sysctl_param.*/$sysctl_param = $data/" \
> "$sysctl_conf_file.tmp" ||
(( failed_sysctl_file++ ))
if (( $(not $failed_sysctl_file) )); then
$mv -f "$sysctl_conf_file.tmp" $sysctl_conf_file
fi
fi
fi
else
Warn "$sysctl_param not valid for this system."
fi
done
unset IFS
(( $failed_sysctl )) && Warn "Some sysctls failed, system may not be tuned!"
(( $failed_sysctl_file )) && Fail "Unable to write to $sysctl_conf_file."
else
unset IFS
Warn "Skip sysctl tuning!"
fi
Info "System tuning is complete."
exit
# MEMMAPREAD DATA ##############################################################
: <<MMAPR32
1f8b080845a0884400036d6d617072333200dd586f6c14c7159f3d9f7d86183813971882d4ab00c9
a6e1b0a99d3a94aa067bf1199df9634c4a046273dcad7de7debfdcedf2a7152af448a2cbc5aaa37e
80484885b6523ea452ab962a55f2c58e29942a8a4e1152aa36486e45a4734d2347a5c48928d7df9b
99bddb5ba052be76ed77b3bf796fde7b33f3e6edccfc500dee541485598f8bd53142fd67dd8d5d28
7b968afa2ee6631ed6c6d6b2d5ac8163d069c88066f14e540f7283ea402d50d272c6dd48f438f0e3
92a748e20fda12f57860c723da33afe0f3ba73e0815a51b11ed420f92e1441f083e011fd1198a841
da206a837c1b6c13f9807d36debe8f8d087bc863b5df1c8f1ddd1c8f6c8ac792e6097f36e5df22ea
bdd2f781dd07e45809aa977d5e066a02c135b6c4a1dbea739d6d9c1a64fb46100df3630ff1e96559
be005a093a28f10589bb25de2a7140e2c312fb417bcfbb1bc95e337b826d93fc75926f4a7c53e27d
12bf2df12868fdcb56fbe54c93fc1945f0ab9123c6f82b0eccb45dc7b4617d2c9635f44c5f3c94cd
ea59a66963895452cb1aa18ca1690cc31da6617e9a658d48ca3458c24c26426936a61be9d0989e8d
7d5f072763a4cc789ca5d27af2e92e9680008ad1e39998a1336d700fb4456249cdccea11e8279552
7f22144bb2703c95d5d9407070479fb6c5df5979eb604cc4bcabf247f1ef9273e662eb9998777a9a
63b165348313b2cecbb18b9d93fc168c73439318ef7a4cf27a941e8a432aa1f2292a11001d546240
bba84410f45089a0d9462582a1974a04c481fcc7b9db8da569a82ed17a2a6d46e3eb33acdcbd1612
e50d3efc92ddf206b214a5d7b9d9329e0d64314abcb922c764394a2ecf4d714c1e445b09ff9a63f2
244ad335779163f228da46789263f22c4a6335779a63f230da43380dd8f9cf23f9bfe56e2dec1d19
8e5e78099c007ef63d1bbd8d1c52fa1504ee4c4ea22ffb4be4e1a133336f20190c1772f7c07971ca
70958b070f5d9f99e432e8efe96f8f50bf8c15f35f9d38c67253ee9f07a9b71f5ca2a2e07df10373
fe6a3d8928d767f277459b4b01a401e85afd7b3281176fee7653942acbc5dc152ff490012edb0347
b9546e6a05fea74beee95977fb956bea22555e53ef89e23605f655f5afca35f5461be2bfa036c195
02cbabc5dca922339baea9ef91c8dc7d5275db3dcec659d92c962ede2f976131af2ee60fdc936ae0
20316f947e6b316773a766d9c98a0e5a6ca56360e6d58f0aea479ffdf9f5fcf4baa1c5fcd042beb8
4ebd9757efa0b6706051799773bf56fcbaba90574b305b36ef94cd85b2393bae8c2b65b334ce4af7
ff43467c79f516c6009cd24d5ee1cd9dba5536974893f3bb0a07160a437726d4c576efea80bba0de
aa53175f613f3b4863dd4d114c1aa3044b4dc26d740316cae6add29b422374d16015d4f7aecf606c
bffbec7e58b426f9dd66f4692b0427723e4cf4c44fe837af2eb4173bef4e2fba9eb99a5d95ff307f
b7dcf29bc2d042fbe73ba73f773df37efe8bcc27b92b4d878e68726ea1d352f802144a5defd06ffb
22d4c0e044ba3c5f3f596e796b77ee7ed9fcac4419cfd221e26ef81dfa8a5ca29ff9a51453f3ee72
b150975bc4e851e8d963f33158d95bcac0efe7c011f99af2c0e6887e6c73424f58b98d9681bd6432
1752bea06fc0859cbb91be076e993b03f80e51de7ffe47c81128278129e75f6222ef7b6db9936cb6
62e0290bf5525ee1b997217b23af432fbd0751ae94ede8db4a8b1dd3945a8b7ab894225f1650ba72
22477cd987beabd6fb9fa0e32fa07f80be002dc5ba5e03da08da7ab62ad74f6d06fafab6fadaf089
6cf77dc3dfe5eff66de9e8e8eedcd2d1e96b1bd623be40c810f59bb6b4b3ff7f617ff664c2081d45
89ef172fa3d65b2c892f629af9932943f76fdf31b8c9088d317f34948d327fe464120d456964987f
2c69fa8fe9996c2c95ac011a78193d4e72e2251d3748730cbf867e02bfa30060a5222123c4fc7a54
1bcd84123af3878d54260b03a2180f67b8b1502216868194c17f8436d1f2681662e15422a1278d2f
13474f32b12e2896f97e5011f16a3dd6fe81f6231e29c7f76d8adc3fc8c72dcb4e26f64f24476b2a
a0883d8fdb2647f44d26d615c9d15a9b845c51b65558753ff71d26d61bc9d1da7cde25d6a4d3bf01
c6d77a8aeff9b0065c68b4c666d7da0b8e30b10ee99dd6e25afade3becd21366628fc8f7b2900bd6
097fecfda08515b7c9d1da3f5c2772825bf6cf9233a57eca2d947b2ed4897ce11cbfb44dee32e42e
436ed22147f4039b1c9d05fa5139e57a50df199b1ccf751e312e4eb99759350e7c90f379444e73ca
fdd826d705b92e4f9567977b5dcad1dcf17382478c8353eea24dae1772bd8f907bc32647fb86c023
ecfe52f695e4f8f9c323ce1ef53639d2ff3b9b3eda17b6343ea88fe86d9b1ce5fc56c83df510b919
9b5c3fe4fa1bc577c6e9df75699fe4e82bbef71172efb3dabd3bc92db75558afcd5297f51c41307e
c81e94b3e6cc7ace2fc799d02dd6ff26565d6f4b1cfa4e20195cb535b4fbe47c287f30de5e48b555
b05010a8606161b28245af697d0b2c66cbfa36d68993255faf027b380e56b08898c3152c4e77172a
581c922f57b038c9f59fb5b098015a1f022fe3d857c1cb39eeaae0151cf79cb3b03881f456b05839
810a5e29fcad6091615bce5bb885e3d60a163b8dfe0a5ec5f1de0ab6670ec2ad0ebcda81d738f093
7c86a2b2ff2ef4bf76ad7f5a5e6beb9f82fe6db4f54f81748fad7f0afaa752ffce5b78151b44c90f
011c3fc1e844feaacddef7504efd0ffbc7516eb3d93fcbe4fe45da7f8d55e743c17cfcd4e1cf9b28
675faaea9f76e8a7f575d0e6df0d569d9f66cccf4d296b9deb3f61221eac73f6bf6de3e3757d5a6e
900bc33af7d39d48408e47b36b15db004c67af1d9cdfc4ba956a7cae447c7e4bb6b7ee098624b6ee
09424aed3d4156f2ad7b8257946a3c93fed7945aff7e41fec0feb0e45f56aaf1e4c5784c01d379f0
b022f87f90faad7b87bf3bf4fd4ba9c6a70ff37d5fa9ae9f95583f6e9933ac7b8a55aedaf61b5db5
f63b5dd5f86f46fc0f001fb6f1838ef69aabf6de2329ed59f71ea75d55ffbcf06fc296c37ca04b0e
7d6f39f82c1c8ac76dd7202c9c31b286393aea0f334deb1bd933ac0507f78f681a507f0ddad55701
697f07c39e2c1dd70d3de2ef043392d2c6e2a9a3a1b8c677765ac83cc1f88e4f8b9889c4494bb5ba
bbbfaad9023b87b70fa9154466acf7aad670452bce4289503aa38722f098f6884799d6ffdceeed43
837de2b6a5b7b77ac9a28da6b5e87168a2eda816ca644227353d1991b7385549de856c4a8b869291
b86edde384b3266fc834beb315b74376f5d6e5506d1d5d25d96b6cd74935be89f1aff1cdaaaa98e7
86350dbb60c9e3b74a0fdc33d5e8e58d6c9da541b234f3ee88abacdade63441dcd349defc0b581e0
9e1ddb83da9e9d3bf7ab23dac8f61d411573c325ec96a481da0b31714d56eb9ddd9d87ded1d5ba62
0d49cdcddd7f010586df723e160000
MMAPR32
: <<MMAPR64
1f8b08080aa0884400036d6d617072363400e5597d6c5b5715bf7e8e53e7a3a95bba35b441f2a8cb
92a2b88969433b567092ba792e5eeba6c9e880edd5b15f12337f613fb7e9a4c024b3a9c6cb642490
fa170bd2248240d07ff8d884dab4699714a429dd102a5f53049de62803a5da24220633e7be77eef3
7bd736adf8837fb8967d7c7eeffcce3df7be7bcfbdefddaffb0247058b85b02290cf12aa391abdaa
ee45dcd1a69b007690d8e1f76364276904dd66b0f312af49cea36b26ed6867856f83562156ec35c9
0e8499b418a48d188bd724ef34119384c8751e8db58478a92968923d18875730f304e4399a116d0e
9a6411032b72ed6bc06f07faeb60ed42e9443ba7c19e96e0db4a84feefc4383b9bbc26e9423b17c7
3b09bc4672ff85c5b92f161debdbbf2f16e98e4513d9a9eea9837ddd7dfbdd99a4dba3faa6bd409b
36747c54b5170c75d242ef632b7c5b88765f3671f508686331f01ab17edac4e67bc4390edf6d06fd
f7284f727810fbff510edf8152e2f043682f72f853280f70f8c3284f73f85e94531c9e42e986ef56
d24eda5bb5f1c2fa9d56ef24d5e5813a38918e9d9586e589684691d383b15026236788244dc49309
29a384d28a2411b895617ae7fa48468924b30a896713f1508a4cc84a2a342167a2cfc87025ad24b3
b11849a6e444df7e12070310e3e7d251450687d4073a8c87a209128e253332190af80706258fdbe3
a6fd22547d2ac5021f3a361da86777469b28e36ba8cfb668fd40c7408b81c7fa878ea126033e8ff6
9b482507d0b264c08df52f1b70ab01bf6dc08de377c5801bf34ac9801be7d5ba01378ef50d036e37
e062ee5d7be94dead003e1979eb452e8ba7da17cc0d3e820e53dfbe1b708a5bc87ea9394b2ba5286
b2672fd56993579755fde354a74d5d9d57f59d54a74d5cbda4eadba84e9bb63aabeacd54a74d5a2d
aaba4075da94d56755fd1f36d069b8ab2950f5787bffeacfdf7a4accff59ccdd590f8ef817e78b76
2f1117aff6a86271091686d27160bc5fa46d130bb627c091f8dcbc229497d5a6158de5d9c3afc065
322ae6df561c6b2ee0ccdbc5bced3b0096df00f20b945c7088cfbd91bdf39a6d0634cbcd85f1f1f1
a2f62d8e8ab9c392153c50070ffe420d11ea6abd628704eccf2fdcec2fffe52654492b8078cee4a7
ff29e6b3ebe2a2afa4da2efa6ed33e7ccd77c502ff2f75401a150bbe75358c0238f5cd89b9e93992
6d5df4bdac76b61d7ec5c2f4dcab947e591d0ab31f96cb605962cee0f225f58a1a4ee9245ccefbae
e7a6af93f3ba9babf4ca907a65bee09bfffb6df1a2b81b5ce47d2ba08292bf265a474becd243cbe2
277d2b707519a25b298c5e170bd9657ffe6a7f7ef915eaef55fa7345adcea345b35498be5eeaa3ff
73d34be56c1356bcf679b130ba22ce40555d0ef05512adbea52d3f23176c7d0db4a737ef06a17abb
acba74c1bc2bfde45fe0062a84862d95ae8102ce685d05dfcb37cdb7b328e6bfec2a05f211d74660
66cff72de0321f734177bedbdefb87d216ea67c6560438d0b5225eddb08a8716325bc4fc8dfef2f6
3f8ae505f1d05afa7db1d0e1120b31973d5088b81c3064daf1866bf77bc616a46e67bafd5474954e
a97e664e97e9705bdb541ef91311cbbf16731f94b3efd1f1f6a527573f07b1627c741c9c121717e8
ba8ee3d3027ed61c5885985bb3c3382d58c5dc46397b577540dba8ced313347e3a8469ae11c8be88
7c765f5c8ed3aeb0ecb27ec685396516ccbc749ec32ca0797f12e4459c3fdb51421e9c72b46eb2b3
7d41077e97705ff545c4fbdb1ccf0b839b1b75de33c39469d9855cc6bb0077fa716a70ec0521d710
6c733e6fd5fdd2356f09ae1fd21d0eb7b5e7ac813667250f95b1d4d359613996ed2f5a519eb16971
6f46dd8efb11964bbd82a6b31c3a67d574963b2fe075b6de7f13255b03da513ec0c5c372f81ce657
96ebe751b27e63b998adf7b30d5e139e429de5e61e946cad61f5433726a90ca27d1975d62feba87b
f0faffaab0fd265f5ec4fbf25d943f467919e5eb28df42f937941fa2ac2aac9ea1c1c1479c9db0ed
eb727ecabddf7dc0e9e9e939d0ebe9e975760ecb11a7185234bcdbd3f57f60ecce9c8f2ba13190b0
7f52e524fb174dc08e2c45dc89a422bbfb07fcdd4a6882b827439949e28e9c4f0051934a9ab82712
59f759399d8926132645826b693916a286f82f1553a8ef28fc2af214fc8e8302d792919012226e79
521a4f87e2b23419495734e20e2bc974062ad4c457c269b5f2503c1a860a938afaa3f9d6fc8c65c0
2c9c8cc7e584f2df8fce4ad945b4b9a2efc9041c67ec3988b3b770fa6e62ded3559e9b34ddc9d937
707a2fd17210e37b91cf9eeb8e703c3ba77f9a683989f159debac0eac7806d183be3b3fc419722ab
81cff2e01c263296f758e1db3f44b49cc3f82ccf781accf5b078054e8e102d87319de5b120129ca4
76fcac84d137e3b3bc99423ecb9b7cffb1b8e21c9fe5e15924cc1bf82d35f8e748e5599d16b6ee9c
b199ed58e1ef7f9ae34f217f0af9c53a7cf6bc32cdf1d97b1007021bc6870d038f951cc767eba41d
179a36ce9e8f3f4fccf3a71df9edc8dfccd9f3fc6f71fccafb034d7771f63cff258e1f447e10f9df
e6ecf9f1f303e4b375bbf29e45d3f9fee2f99738fe06f237ee93ff738e6fc7f5ccde5cdb9ed77f49
b47bc7f895f73d9a5e34cc7f239fc57583ab9f3defceb6fce7fa99fc15c767fb9e39e49fbe07ff4d
8e4ff0b99a6de4f8f9c3c7f33bc4189f3d97b723ff5efdff16a9ce69467e1b7791b7dd4acccfedac
7c0207fe3b1ccef34d6b8fa104716319c40d215d87e8bb193eff34d5a97f1617ae5b9cf35a6dad57
acd45af0d6c0057d9d33e3567dfd32e30dfaba64c66dfa7a63c61b6bee57adb0d2066be2763def9b
f1263d9f9bf1663d4f9bf1163dff9af1563daf9af1cd7abe34e36d7a1e34e35bf4fc66c61d7ade32
e35bf57c64c6b7e979c68c7f44cf1f667c7bcdfdb8159e5ed87c37e30feaf3d88cefa8cc4f135e79
5f68c63f5a8569f8ce3af8ae3a38bf0b63f3a6953ccadd173a1f1bc8ddaae7c40e9553dd9f7b55bc
ba3f0faa78757ffa547c077170edf5ab783b7122cee6d928c679868bf369c467ef33fe7318ff3a17
e737307ec2c5a9adab0eb2c28dab97eab4eb8718cfb2dd6c7fb54e3caf637b5d5c7b7f436abfff7e
8fd47effbdc942db5c3d3e1d803b84bb65fe7e3d64a9fdbefc11ea47d841ecdc7d1952ed5b4911db
7508f12f586abf5f7f5ac5abf3c357d10f9f07a62cb5dfc7bf5827feef596abfa7ff29faefc1381f
47fc06f503fdcfcfaf5b68cfbf9ff96d9d7adfb1d43e07f8c042f7d8d5f3ba51a0f6d5f9ad55a8ed
df29d48ef36181dedfea7c7218ed3b39fb01a1f6b9c4689d7a2755ff957ccbf687e784dae71805b5
deeaf65e146a9f63fca84ebdd7ead893702816331c7390705ac928d9f171779848d2e0c8896129e0
3f352249a01d3169c7067525e5ee21f08c9b8ac98a1c71f7c2c548529a8825c74231497d529642d9
29a23d4f47b2f1f879e6da77fc48c533538e0ef73fe6d3355a0dfb5ff11ad6bdc6657ac492964311
88983e738f559fb278bdc60316ed64c68c49479e38deff987f10b8f43d80144aa743e7253911311e
ee70142992494a93a14424a61fec843359958fe73d1c417ddb80ddccce89789f86da3543ed8c8937
d36bd37c4a63990cb3a7a74a928a1b5aa11d4399bdd0ce429216b424413f72444956df6348438113
03fd01e9c4d1a3a77c23d248ff40c00777845aa827587c7c062f5883ff04fc8b441352362347f000
adaa430d11d53c8e33c78796e643ba7f03b1adade7711f0000
MMAPR64