#!/usr/bin/perl #T6_RW.pm: T6 perl Library of register read/write functions. # package T6_RW; use strict; use warnings; use Exporter (); use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); @ISA = qw(Exporter); $VERSION = 0.01; @EXPORT = qw( find_ext_functionality get_bits get_context get_flit_bits get_BoardInfo get_ints_msg get_reg get_reg_bits get_win_ipconfig_hash_array get_win_mac_data get_sun_kstat_data get_bsd_mac_data grep_read OS_bsd OS_linux OS_solaris OS_windows OS_darwin prs_regfs prs_regdump put_bits rpci read_sge_dbg read_linkstate read_mac_rx_pkts read_mac_tx_pkts read_mtu read_pcieH read_tcam read_tcb read_win_qset_hash rreg rreg_bits rreg_via_ix rreg_fs rreg_mdio rreg_uP_host_acc rmib rmibH set_get_reg_href clear_get_reg_href set_iface sge_r_dbg snap_lin_ifconfig snap_mac_stats spr_comma spr_hash wreg wreg_bits wreg_via_ix wreg_fs wreg_uP_host_acc wreg_pci $cardid @ifaces ); ## exported symbols our $cardid = "enp136s0f4d1"; #default our @ifaces = qw(enp136s0f4d1); our $ifaces_established=0; our @g_pcie_ifaces =("-d 1425:B000"); our $g_pcie_ifaces_established=0; our $ext_readreg ="cxgbtool"; our $ext_writereg ="cxgbtool"; our $ext_readpci ="setpci"; our $ext_linkstate ="ethtool"; our $ext_macpkts ="ifconfig"; #on linux, "lspci -d 1425:* -vvv | Region 0" will display BAR0. That address #can be used to read registers via mmapr command. See rreg_via_bar below. our $bar_readreg = ""; our $bar_readreg_endian = "little"; use FindBin (); use lib "$FindBin::Bin"; use JLIB; ## non exported symbols ##:-------------------------------------------------------------------------- ###: non-export GLOBAL VARIABLES ##:-------------------------------------------------------------------------- my $OStype = "linux"; #default use constant SGE_DEBUG_INDEX => 0x10cc; use constant SGE_DEBUG_DATA_HIGH => 0x10d0; use constant SGE_DEBUG_DATA_LOW => 0x10d4; use constant SGE_DEBUG_DATA_HIGH_INDEX_0 => 0x1280; use constant SGE_DEBUG_DATA_LOW_INDEX_0 => 0x12C0; my $g_sge_dbgA = [ { name=>"uP", type=>"SEOP", addr=>0, half=>1, hi=>23, lo=>16}, { name=>"CIM1", type=>"SEOP", addr=>0, half=>1, hi=>15, lo=> 8}, { name=>"CIM0", type=>"SEOP", addr=>0, half=>1, hi=> 7, lo=> 0}, { name=>"T_Rx1", type=>"SEOP", addr=>1, half=>1, hi=>31, lo=>24}, { name=>"T_Rx0", type=>"SEOP", addr=>1, half=>1, hi=>23, lo=>16}, { name=>"U_Rx1", type=>"SEOP", addr=>1, half=>1, hi=>15, lo=> 8}, { name=>"U_Rx0", type=>"SEOP", addr=>1, half=>1, hi=> 7, lo=> 0}, { name=>"UD_Rx3", type=>"SEOP", addr=>2, half=>1, hi=>31, lo=>24}, { name=>"UD_Rx2", type=>"SEOP", addr=>2, half=>1, hi=>23, lo=>16}, { name=>"UD_Rx1", type=>"SEOP", addr=>2, half=>1, hi=>15, lo=> 8}, { name=>"UD_Rx0", type=>"SEOP", addr=>2, half=>1, hi=> 7, lo=> 0}, # gone from T6. # { name=>"U_Tx3", type=>"SEOP", addr=>3, half=>1, hi=>31, lo=>24}, # { name=>"U_Tx2", type=>"SEOP", addr=>3, half=>1, hi=>23, lo=>16}, # { name=>"U_Tx1", type=>"SEOP", addr=>3, half=>1, hi=>15, lo=> 8}, # { name=>"U_Tx0", type=>"SEOP", addr=>3, half=>1, hi=> 7, lo=> 0}, { name=>"PC_Rsp1", type=>"SEOP", addr=>4, half=>1, hi=>31, lo=>24}, { name=>"PC_Rsp0", type=>"SEOP", addr=>4, half=>1, hi=>23, lo=>16}, { name=>"PC_Req1", type=>"SEOP", addr=>4, half=>1, hi=>15, lo=> 8}, { name=>"PC_Req0", type=>"SEOP", addr=>4, half=>1, hi=> 7, lo=> 0}, #gone from T6 # { name=>"PD_RdReq3", type=>"SEOP", addr=>5, half=>1, hi=>31, lo=>24}, # { name=>"PD_RdReq2", type=>"SEOP", addr=>5, half=>1, hi=>23, lo=>16}, # { name=>"PD_RdReq1", type=>"SEOP", addr=>5, half=>1, hi=>15, lo=> 8}, # { name=>"PD_RdReq0", type=>"SEOP", addr=>5, half=>1, hi=> 7, lo=> 0}, # { name=>"PD_RdRsp3", type=>"SEOP", addr=>6, half=>1, hi=>31, lo=>24}, # { name=>"PD_RdRsp2", type=>"SEOP", addr=>6, half=>1, hi=>23, lo=>16}, # { name=>"PD_RdRsp1", type=>"SEOP", addr=>6, half=>1, hi=>15, lo=> 8}, # { name=>"PD_RdRsp0", type=>"SEOP", addr=>6, half=>1, hi=> 7, lo=> 0}, { name=>"PD_WrReq3", type=>"SEOP", addr=>7, half=>1, hi=>31, lo=>24}, { name=>"PD_WrReq2", type=>"SEOP", addr=>7, half=>1, hi=>23, lo=>16}, { name=>"PD_WrReq1", type=>"SEOP", addr=>7, half=>1, hi=>15, lo=> 8}, { name=>"PD_WrReq0", type=>"SEOP", addr=>7, half=>1, hi=> 7, lo=> 0}, { name=>"PD_WrReq_Int3", type=>"SOP", addr=>8, half=>1, hi=>15, lo=>12}, { name=>"PD_WrReq_Int2", type=>"SOP", addr=>8, half=>1, hi=>11, lo=> 8}, { name=>"PD_WrReq_Int1", type=>"SOP", addr=>8, half=>1, hi=> 7, lo=> 4}, { name=>"PD_WrReq_Int0", type=>"SOP", addr=>8, half=>1, hi=> 3, lo=> 0}, { name=>"CPLSW_TP_Rx1", type=>"SEOP", addr=>9, half=>1, hi=>31, lo=>24}, { name=>"CPLSW_TP_Rx0", type=>"SEOP", addr=>9, half=>1, hi=>23, lo=>16}, { name=>"CPLSW_CIM1", type=>"SEOP", addr=>9, half=>1, hi=>15, lo=> 8}, { name=>"CPLSW_CIM0", type=>"SEOP", addr=>9, half=>1, hi=> 7, lo=> 0}, ]; use constant TP_MIB_INDEX => 0x7e50; use constant TP_MIB_DATA => 0x7e54; my $g_tp_mibH = { TP_MIB_MAC_IN_ERR_0 => {addr => 0x0 }, TP_MIB_MAC_IN_ERR_1 => {addr => 0x1 }, TP_MIB_MAC_IN_ERR_2 => {addr => 0x2 }, TP_MIB_MAC_IN_ERR_3 => {addr => 0x3 }, TP_MIB_HDR_IN_ERR_0 => {addr => 0x4 }, TP_MIB_HDR_IN_ERR_1 => {addr => 0x5 }, TP_MIB_HDR_IN_ERR_2 => {addr => 0x6 }, TP_MIB_HDR_IN_ERR_3 => {addr => 0x7 }, TP_MIB_TCP_IN_ERR_0 => {addr => 0x8 }, TP_MIB_TCP_IN_ERR_1 => {addr => 0x9 }, TP_MIB_TCP_IN_ERR_2 => {addr => 0xa }, TP_MIB_TCP_IN_ERR_3 => {addr => 0xb }, TP_MIB_TCP_OUT_RST => {addr => 0xc }, TP_MIB_TCP_IN_SEG_HI => {addr => 0x10 }, TP_MIB_TCP_IN_SEG_LO => {addr => 0x11 }, TP_MIB_TCP_OUT_SEG_HI => {addr => 0x12 }, TP_MIB_TCP_OUT_SEG_LO => {addr => 0x13 }, TP_MIB_TCP_RXT_SEG_HI => {addr => 0x14 }, TP_MIB_TCP_RXT_SEG_LO => {addr => 0x15 }, TP_MIB_TNL_CNG_DROP_0 => {addr => 0x18 }, TP_MIB_TNL_CNG_DROP_1 => {addr => 0x19 }, TP_MIB_TNL_CNG_DROP_2 => {addr => 0x1a }, TP_MIB_TNL_CNG_DROP_3 => {addr => 0x1b }, TP_MIB_OFD_CHN_DROP_0 => {addr => 0x1c }, TP_MIB_OFD_CHN_DROP_1 => {addr => 0x1d }, TP_MIB_OFD_CHN_DROP_2 => {addr => 0x1e }, TP_MIB_OFD_CHN_DROP_3 => {addr => 0x1f }, TP_MIB_TNL_OUT_PKT_0 => {addr => 0x20 }, TP_MIB_TNL_OUT_PKT_1 => {addr => 0x21 }, TP_MIB_TNL_OUT_PKT_2 => {addr => 0x22 }, TP_MIB_TNL_OUT_PKT_3 => {addr => 0x23 }, TP_MIB_TNL_IN_PKT_0 => {addr => 0x24 }, TP_MIB_TNL_IN_PKT_1 => {addr => 0x25 }, TP_MIB_TNL_IN_PKT_2 => {addr => 0x26 }, TP_MIB_TNL_IN_PKT_3 => {addr => 0x27 }, TP_MIB_TCP_V6IN_ERR_0 => {addr => 0x28 }, TP_MIB_TCP_V6IN_ERR_1 => {addr => 0x29 }, TP_MIB_TCP_V6IN_ERR_2 => {addr => 0x2a }, TP_MIB_TCP_V6IN_ERR_3 => {addr => 0x2b }, TP_MIB_TCP_V6OUT_RST => {addr => 0x2c }, TP_MIB_TCP_V6IN_SEG_HI => {addr => 0x30 }, TP_MIB_TCP_V6IN_SEG_LO => {addr => 0x31 }, TP_MIB_TCP_V6OUT_SEG_HI => {addr => 0x32 }, TP_MIB_TCP_V6OUT_SEG_LO => {addr => 0x33 }, TP_MIB_TCP_V6RXT_SEG_HI => {addr => 0x34 }, TP_MIB_TCP_V6RXT_SEG_LO => {addr => 0x35 }, TP_MIB_OFD_ARP_DROP => {addr => 0x36 }, TP_MIB_OFD_DFR_DROP => {addr => 0x37 }, TP_MIB_CPL_IN_REQ_0 => {addr => 0x38 }, TP_MIB_CPL_IN_REQ_1 => {addr => 0x39 }, TP_MIB_CPL_IN_REQ_2 => {addr => 0x3a }, TP_MIB_CPL_IN_REQ_3 => {addr => 0x3b }, TP_MIB_CPL_OUT_RSP_0 => {addr => 0x3c }, TP_MIB_CPL_OUT_RSP_1 => {addr => 0x3d }, TP_MIB_CPL_OUT_RSP_2 => {addr => 0x3e }, TP_MIB_CPL_OUT_RSP_3 => {addr => 0x3f }, TP_MIB_TNL_LPBK_0 => {addr => 0x40 }, TP_MIB_TNL_LPBK_1 => {addr => 0x41 }, TP_MIB_TNL_LPBK_2 => {addr => 0x42 }, TP_MIB_TNL_LPBK_3 => {addr => 0x43 }, TP_MIB_TNL_DROP_0 => {addr => 0x44 }, TP_MIB_TNL_DROP_1 => {addr => 0x45 }, TP_MIB_TNL_DROP_2 => {addr => 0x46 }, TP_MIB_TNL_DROP_3 => {addr => 0x47 }, TP_MIB_FCOE_DDP_0 => {addr => 0x48 }, TP_MIB_FCOE_DDP_1 => {addr => 0x49 }, TP_MIB_FCOE_DDP_2 => {addr => 0x4a }, TP_MIB_FCOE_DDP_3 => {addr => 0x4b }, TP_MIB_FCOE_DROP_0 => {addr => 0x4c }, TP_MIB_FCOE_DROP_1 => {addr => 0x4d }, TP_MIB_FCOE_DROP_2 => {addr => 0x4e }, TP_MIB_FCOE_DROP_3 => {addr => 0x4f }, TP_MIB_FCOE_BYTE_0_HI => {addr => 0x50 }, TP_MIB_FCOE_BYTE_0_LO => {addr => 0x51 }, TP_MIB_FCOE_BYTE_1_HI => {addr => 0x52 }, TP_MIB_FCOE_BYTE_1_LO => {addr => 0x53 }, TP_MIB_FCOE_BYTE_2_HI => {addr => 0x54 }, TP_MIB_FCOE_BYTE_2_LO => {addr => 0x55 }, TP_MIB_FCOE_BYTE_3_HI => {addr => 0x56 }, TP_MIB_FCOE_BYTE_3_LO => {addr => 0x57 }, TP_MIB_OFD_VLN_DROP_0 => {addr => 0x58 }, TP_MIB_OFD_VLN_DROP_1 => {addr => 0x59 }, TP_MIB_OFD_VLN_DROP_2 => {addr => 0x5a }, TP_MIB_OFD_VLN_DROP_3 => {addr => 0x5b }, TP_MIB_USM_PKTS => {addr => 0x5c }, TP_MIB_USM_DROP => {addr => 0x5d }, TP_MIB_USM_BYTES_HI => {addr => 0x5e }, TP_MIB_USM_BYTES_LO => {addr => 0x5f }, TP_MIB_TID_DEL => {addr => 0x60 }, TP_MIB_TID_INV => {addr => 0x61 }, TP_MIB_TID_ACT => {addr => 0x62 }, TP_MIB_TID_PAS => {addr => 0x63 }, TP_MIB_TID_RQE_DFR_MOD => {addr => 0x64 }, TP_MIB_TID_RQE_DFR_PKT => {addr => 0x65 }, TP_MIB_CPL_OUT_ERR_0 => {addr => 0x68 }, TP_MIB_CPL_OUT_ERR_1 => {addr => 0x69 }, TP_MIB_CPL_OUT_ERR_2 => {addr => 0x6a }, TP_MIB_CPL_OUT_ERR_3 => {addr => 0x6b }, TP_MIB_ENG_LINE_0 => {addr => 0x6c }, TP_MIB_ENG_LINE_1 => {addr => 0x6d }, TP_MIB_ENG_LINE_2 => {addr => 0x6e }, TP_MIB_ENG_LINE_3 => {addr => 0x6f }, }; use constant PORT_ADDR_SPACE_SIZE => 0x4000; use constant A_MPS_PORT_STAT_TX_PORT_BYTES_L => 0x30400; use constant A_MPS_PORT_STAT_TX_PORT_FRAMES_L => 0x30408; use constant A_MPS_PORT_STAT_TX_PORT_PAUSE_L => 0x30470; use constant A_MPS_PORT_STAT_RX_PORT_BYTES_L => 0x30540; use constant A_MPS_PORT_STAT_RX_PORT_FRAMES_L => 0x30548; use constant A_MPS_PORT_STAT_RX_PORT_PAUSE_L => 0x305c8; use constant A_MPS_PORT_STAT_TX_PORT_PPP0_L => 0x30478; use constant A_MPS_PORT_STAT_TX_PORT_PPP1_L => 0x30480; use constant A_MPS_PORT_STAT_TX_PORT_PPP2_L => 0x30488; use constant A_MPS_PORT_STAT_TX_PORT_PPP3_L => 0x30490; use constant A_MPS_PORT_STAT_TX_PORT_PPP4_L => 0x30498; use constant A_MPS_PORT_STAT_TX_PORT_PPP5_L => 0x304a0; use constant A_MPS_PORT_STAT_TX_PORT_PPP6_L => 0x304a8; use constant A_MPS_PORT_STAT_TX_PORT_PPP7_L => 0x304b0; use constant A_MPS_PORT_STAT_RX_PORT_PPP0_L => 0x305d0; use constant A_MPS_PORT_STAT_RX_PORT_PPP1_L => 0x305d8; use constant A_MPS_PORT_STAT_RX_PORT_PPP2_L => 0x305e0; use constant A_MPS_PORT_STAT_RX_PORT_PPP3_L => 0x305e8; use constant A_MPS_PORT_STAT_RX_PORT_PPP4_L => 0x305f0; use constant A_MPS_PORT_STAT_RX_PORT_PPP5_L => 0x305f8; use constant A_MPS_PORT_STAT_RX_PORT_PPP6_L => 0x30600; use constant A_MPS_PORT_STAT_RX_PORT_PPP7_L => 0x30608; use constant A_PL_RST => 0x19428; use constant A_CIM_BOOT_CFG => 0x7b00; use constant A_CIM_HOST_UPACC_INT_CAUSE => 0x7b34; use constant A_CIM_UP_ACC_INT_CAUSE => 0x7b44; use constant A_CIM_HOST_ACC_CTRL => 0x7b50; use constant A_CIM_HOST_ACC_DATA => 0x7b54; use constant A_CIM_BOOT_LEN => 0x7bf0; use constant A_CIM_UP_SPARE_INT => 0x7b24; #: set_iface #: --------- #: initializes the global variables @ifaces, $cardid, #: through a combination of executing ifconfig/ipconfig commands and #: accepting overides (-i and -i2 switches) from command line arguments #: IN: command line argument array from calling program. #: RET: command line argument array, minus any arguments used by this routine. #: OUT: sets global variables associated with being able to read registers, #: etc. sub set_iface { my (@NEWARGV,$i); $OStype=get_OStype(); if (OS_windows()) { $cardid="cxgen0"; @ifaces=qw(cxgen0 cxgen0); $ext_readreg="cxgen_tool -d "; $ext_writereg="cxgen_tool -d "; $ext_readpci="cxgen_tool -d "; $ext_linkstate="cxgen_tool -d "; $ext_macpkts="cxgen_tool -d "; } elsif(OS_solaris()) { $cardid="cxgen0"; @ifaces=qw(cxge0); $ext_readreg="cxgen_tool -d "; $ext_writereg="cxgen_tool -d "; $ext_readpci="cxgen_tool -d "; $ext_linkstate="cxgen_tool -d "; $ext_macpkts="kstat"; } elsif (OS_bsd()) { @ifaces=qw(cxgb0); $ext_macpkts="/usr/bin/netstat"; } #Look for override interfaces and override readreg/writereg commands for($i=0 ; $i<=$#_ ; $i++) { if ($_[$i] eq "-i") { $ifaces_established=1; $ifaces[0]=$_[++$i]; }elsif ($_[$i] eq "-i2") { $ifaces_established=1; $ifaces[1]=$_[++$i]; } elsif ($_[$i] eq "-toerw") { $ext_readreg ="toerw"; $ext_writereg="toerw"; } elsif ($_[$i] eq "-joerw") { $ext_readreg ="joerw"; $ext_writereg="joerw"; } elsif ($_[$i] eq "-t5rw" or $_[$i] eq "-t6rw" or $_[$i] eq "-ndrw") { $ext_readreg ="ndrw"; $ext_writereg="ndrw "; if ($i+2<=$#_ and ($_[$i+1] eq "-d" or $_[$i+1] eq "-s" )) { $ext_readreg .=" ".$_[$i+1]." ".$_[$i+2]; $ext_writereg.=" ".$_[$i+1]." ".$_[$i+2]; $i+=2; } $ifaces_established=1; } elsif ($_[$i] eq "-bar") { $bar_readreg =hex($_[++$i]); } elsif ($_[$i] eq "-barbig") { $bar_readreg =hex($_[++$i]); $bar_readreg_endian ="big"; } elsif ($_[$i] eq "-bsf") { $g_pcie_ifaces_established=1; my $pcie_iface=$_[++$i]; if ($pcie_iface =~ /[\da-f]+:[\da-f]+.[\da-f]+/i) { $g_pcie_ifaces[0]="-s $pcie_iface" } elsif ($pcie_iface =~ /[\da-f]+:[\da-f]+/i) { $g_pcie_ifaces[0]="-d $pcie_iface" } } else { @NEWARGV = (@NEWARGV,$_[$i]); } } #print ('@ifaces: '."@ifaces\n"); if (0==$#ifaces) { $_=$ifaces[0]; if (/[0-9]/) { $ifaces[1]=sprintf("$`%u",$&+1); } } if (OS_linux() || OS_bsd() || OS_darwin()) {$cardid=$ifaces[0]}; return @NEWARGV; } ########################################################################## # O.S. Dependent Section. # # Procedures in this part of the file may need to be modifed based # on O.S. I'd like to make the O.S. configuration dynamic, via # the variable $OStype, as illustrated in the rreg() and wreg() ########################################################################## #: find_ext_x #: ---------- #: Search for an external executable. sub find_ext_x { my $func_type =shift; my $err_msg_ref=shift; my @cmds =shift; my $ret; foreach my $cmd (@cmds) { if (is_executable($cmd)) {$ret=$cmd; last} } if (not $ret) { $$err_msg_ref .= "I was unable to find any command to perform $func_type.\n". "I looked for the following commands in your PATH and could\n". "not find any of them:\n". " @cmds\n"; } return $ret; } #: find_ext_functionality #: ---------------------- #: Find the exteranl commands such as cxgbtool, etc. that we need to run #: the script. #: IN: $_[0]: string consisting of abstract names for functionality the #: caller will need. Currently defined functionality: #: readreg #: writereg #: readpci #: $_[1]: options. Current options: #: -nodie. Return error message, don't die. #: #: OUT: If functionality found, returns a "" string. #: else { #: If "-nodie" option, returns an error message #: else prints error messages and dies. #: sub find_ext_functionality { my $func_str = $_[0]; my $options=""; if ($#_>=1) {$options=$_[1]} my @func_a = split(" ","\L$func_str"); #default value must be first entry in list. my $err_msg=""; if (OS_linux()) { foreach my $func_type (@func_a) { if ($func_type eq "readreg") { if ($ext_readreg ne "cxgbtool") {next;} #override. my $temp=find_ext_x($func_type,\$err_msg,qw(cxgbtool joerw toerw)); if ($temp) {$ext_readreg=$temp;} } elsif ($func_type eq "writereg") { if ($ext_readreg ne "cxgbtool") {next;} #override. my $temp=find_ext_x($func_type,\$err_msg,qw(cxgbtool joerw toerw)); if ($temp) {$ext_writereg=$temp;} } elsif ($func_type eq "readpci") { my $temp=find_ext_x($func_type,\$err_msg,qw(setpci)); if ($temp) {$ext_readpci=$temp;} } elsif ($func_type eq "macpkts") { my $temp=find_ext_x($func_type,\$err_msg,qw(ifconfig /sbin/ifconfig)); if ($temp) {$ext_macpkts=$temp;} } elsif ($func_type eq "linkstate") { my $temp=find_ext_x($func_type,\$err_msg,qw(ethtool)); if ($temp) {$ext_linkstate=$temp;} } } } elsif (OS_bsd()) { foreach my $func_type (@func_a) { if ($func_type eq "readreg") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgbtool)); if ($temp) {$ext_readreg=$temp;} } elsif ($func_type eq "writereg") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgbtool)); if ($temp) {$ext_writereg=$temp;} } elsif ($func_type eq "readpci") { my $temp=find_ext_x($func_type,\$err_msg,qw(pciconf)); if ($temp) {$ext_readpci=$temp;} } elsif ($func_type eq "macpkts") { my $temp=find_ext_x($func_type,\$err_msg,qw(netstat)); if ($temp) {$ext_macpkts=$temp;} } elsif ($func_type eq "linkstate") { my $temp=find_ext_x($func_type,\$err_msg,qw(ifconfig)); if ($temp) {$ext_linkstate=$temp;} } } } elsif (OS_darwin()) { foreach my $func_type (@func_a) { if ($func_type eq "readreg") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgbtool)); if ($temp) {$ext_readreg=$temp;} } elsif ($func_type eq "writereg") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgbtool)); if ($temp) {$ext_writereg=$temp;} } elsif ($func_type eq "readpci") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgbtool)); if ($temp) {$ext_readpci=$temp;} } elsif ($func_type eq "macpkts") { my $temp=find_ext_x($func_type,\$err_msg,qw(netstat)); if ($temp) {$ext_macpkts=$temp;} } elsif ($func_type eq "linkstate") { my $temp=find_ext_x($func_type,\$err_msg,qw(ifconfig)); if ($temp) {$ext_linkstate=$temp;} } } } elsif (OS_solaris()) { foreach my $func_type (@func_a) { if ($func_type eq "readreg") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgen_tool)); if ($temp) {$ext_readreg="$temp -d";} } elsif ($func_type eq "writereg") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgen_tool)); if ($temp) {$ext_writereg="$temp -d";} } elsif ($func_type eq "readpci") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgen_tool)); if ($temp) {$ext_readpci="$temp -d";} } elsif ($func_type eq "macpkts") { my $temp=find_ext_x($func_type,\$err_msg,qw(kstat)); if ($temp) {$ext_macpkts=$temp;} } elsif ($func_type eq "linkstate") { my $temp=find_ext_x($func_type,\$err_msg,qw(ifconfig)); if ($temp) {$ext_linkstate=$temp;} } } } elsif (OS_windows()) { foreach my $func_type (@func_a) { if ($func_type eq "readreg") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgen_tool)); if ($temp) {$ext_readreg="$temp -d";} } elsif ($func_type eq "writereg") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgen_tool)); if ($temp) {$ext_writereg="$temp -d";} } elsif ($func_type eq "readpci") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgen_tool)); if ($temp) {$ext_readpci="$temp -d";} } elsif ($func_type eq "macpkts") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgen_tool)); if ($temp) {$ext_macpkts=$temp;} } elsif ($func_type eq "linkstate") { my $temp=find_ext_x($func_type,\$err_msg,qw(cxgen_tool)); if ($temp) {$ext_linkstate=$temp;} } } } else { #Unimplemented O.S. $err_msg .= "ERROR: Unrecognized OStype. This script has called the T3_PM::find_ext_functionality() subroutine on an Operating System for which we haven't yet implemented this function. "; } if ($err_msg and $options !~ /-nodie/) {die $err_msg;} return $err_msg; } sub rreg_via_bar { my $reg=shift; my $bar=shift; #note: this typcially doesn't work on linux 2.6.9 kernels. # but does on 2.6.18 kernels. my $cmd=sprintf "mmapr -l /dev/mem 0x%x 4 | xxd -g 1",($bar+hex($reg)); open(REGCMD,"$cmd |"); my $out = ; #typical out: 0000000: 00 04 28 23 ..(# close(REGCMD); my @a=split(":",$out); #split off address my @b=split(" ",$a[1]); #get each byte. my $ret; if ($bar_readreg_endian eq "big") { $ret=(hex($b[0])<<24) | (hex($b[1])<<16) | (hex($b[2])<<8) | hex($b[3]); } else { $ret=(hex($b[3])<<24) | (hex($b[2])<<16) | (hex($b[1])<<8) | hex($b[0]); } return $ret; } sub rreg { my $reg = sprintf("0x%x",$_[0]); my $ret; my $cmd=""; my $out=""; my $status=0; ck_ifaces_established(); if (OS_linux() and $bar_readreg) { $ret=rreg_via_bar($reg,$bar_readreg); goto out; } if (OS_linux() || OS_bsd() || OS_darwin()) { if ($ext_readreg eq "cxgbtool") { $cmd="$ext_readreg $cardid reg $reg"; } else { $cmd="$ext_readreg read $reg"; } $out=`$cmd`; #print "CMD: $cmd, OUT: $out\n"; $status=$?; if (0==$status) { ($ret) = split(" ",$out); $ret = hex($ret); } else { $ret=undef; } } elsif (OS_windows() || OS_solaris()) { $cmd="$ext_readreg $cardid -r $reg"; $out=`$cmd`; $status=$?; if (0==$status) { ($ret) = split(" ",$out); $ret = hex($ret); } else { $ret=undef; } } else { print " ERROR: Unrecognized OStype. This script has called the T3_PM::rreg() subroutine on an Operating System for which there is no known register reading utility. "; exit -1; } out: if (DBG_is_on("regcmd")) { print "RREG CMD: $cmd\nRREG CMD OUT: STATUS: $status\n$out\n"; } if (DBG_is_on("reg")) {printf "RREG: $reg : 0x%08x\n",$ret;} if (!defined $ret) { die "Unable to read register using command $cmd. \n". "It returned status $status and displayed:\n$out"; } return $ret; } sub wreg { my ($reg,$val); $reg = sprintf("0x%x",$_[0]); $val = sprintf("0x%x",$_[1]); my $ret; my $cmd=""; my $out=""; my $status=0; ck_ifaces_established(); if (OS_linux() || OS_bsd() || OS_darwin()) { if ($ext_writereg eq "cxgbtool") { $cmd="$ext_writereg $cardid reg $reg=$val"; } else { $cmd="$ext_writereg write $reg $val"; } $out=`$cmd`; $status=$?; if (0==$status) { $ret = $out; } else { $ret=undef; } } elsif (OS_windows() || OS_solaris()) { $cmd="$ext_writereg $cardid -r $reg $val |"; $out=`$cmd`; $status=$?; if (0==$status) { $ret = $out; } else { $ret=undef; } } else { print " ERROR: Unrecognized OStype. This script has called the T3_PM::wreg() subroutine on an Operating System for which there is no known register writing utility. "; exit -1; } if (DBG_is_on("regcmd")) { print "RREG CMD: $cmd\nRREG CMD OUT: STATUS: $status\n$out\n"; } if (DBG_is_on("reg")) {print "WREG: $reg=$val\n";} if (!defined $ret) { die "Unable to write register using command $cmd. \n". "It returned status $status and displayed:\n$out"; } return $ret; } sub rreg_port { my $addr=shift; my $port=shift; $addr+=$port*PORT_ADDR_SPACE_SIZE; my $ret =rreg($addr); return $ret; } sub rreg_port_64 { my $addr=shift; my $port=shift; $addr+=$port*PORT_ADDR_SPACE_SIZE; my $ret =rreg($addr); $ret |=rreg($addr+4)<<32; return $ret; } ##:wreg_uP_host_acc, rreg_uP_host_acc, wait_uP_host_acc_not_busy #: -------------------------------------------------------------------------- # [0x07b50] CIM_HOST_ACC_CTRL 0x120a4 [ 73892] # Description : # This control register allows debug access to other internal address # spaces. * When performing a write operation first load the register # HOST_ACC_DATA with the write data. Next with one register write # operation (**a must**) to this corresponding control register, # HOST_ACC_CTRL, set the HostWrite field and load the HostAddr field # with the desired address. Then read the HOST_ACC_CTRL register and # the HostBusy status will be set. Now continue to poll this register # until the status is cleared by hardware. This signifies the # operation is complete and the register may be used for another # access. * When performing a read operation only the HOST_ACC_CTRL # register need be written, but again it must be written in one # register write operation. During the write to this register, clear # the HostWrite field, and load the HostAddr field with the desired # address. Then read this HOST_ACC_CTRL register and the HostBusy # status will be set. Now continue to poss this register until the # status is cleared by hardware. This signifies the operation is # complete and the read data can be found loaded into the # HOST_ACC_DATA register. # Module: cim, AddrSpace: COMMON BaseAddr: 0x0 + ModuleBaseAddr 0x7b00 + LocalAddr: 0x50 # Fields: # [17:17] HostBusy 0x0 [ 0] RO # Host access is busy # [16:16] HostWrite 0x1 [ 1] RW # 1 = Write, 0 = Read # [15: 0] HostAddr 0x20a4 [ 8356] RW # Host Access Address: 0x0000 - 0x1FFC Queue control # registers; 0x2000-0x27FC CIM Control Registers; # 0x2800-0x2FFC PBT Address Table (Read Only) {Bit[4] - 0 # Dynamic Address Table; Bit[4] - 1 Static Address Table}; # 0x3000-0x37FC PBT LRF Table (Read Only); 0x3800-0x3FFC # PBT Data Table (read only) #ADDR: 0x7b54 # [0x07b54] CIM_HOST_ACC_DATA # Description : See description above for HOST_ACC_CTRL register. # Module: cim, AddrSpace: COMMON BaseAddr: 0x0 + ModuleBaseAddr 0x7b00 + LocalAddr: 0x54 # Fields: # [31: 0] HostData RW Write Data or Read Data ##: wreg_uP_host_acc #: ----------------- #: IN: $addr, $data #: $ctl: "die" will die if write timeout. #: OUT: $busy: 0 if write succeeded, 1 if timeout waiting for busy to clear. #: sub wreg_uP_host_acc { my $addr=shift; my $data=shift; my $ctl= ($#_>=0) ? shift : ""; my $busy; wreg(A_CIM_HOST_ACC_DATA,$data); #load data wreg(A_CIM_HOST_ACC_CTRL, ((1<<16) | $addr) ); #initate write $busy=wait_uP_host_acc_not_busy($ctl); return $busy; } ##: rreg_uP_host_acc #: ----------------- #: IN: $addr, #: $ctl: optional "die" will die if write timeout. # RET: undef if read timed out, else data from register. #: sub rreg_uP_host_acc { my $addr =shift; my $ctl = ($#_>=0) ? shift : ""; my $ret=undef; wreg(A_CIM_HOST_ACC_CTRL, $addr ); #initate read if (0==wait_uP_host_acc_not_busy($ctl)) { #wait not busy. $ret=rreg(A_CIM_HOST_ACC_DATA); #read data } return $ret; #return undef if timeout,else read data. } ##: wait_uP_host_acc_not_busy #: ------------------- #: Poll uP host_acc register until not busy or 5 second timeout. #: IN: optional $ctl: "die" dies on timeout. #: "show" displays reg if delay. sub wait_uP_host_acc_not_busy { my $ctl = ($#_>=0) ? shift : ""; my $busy=1; #assume we will timeout. my $start=time; my $now=$start; my $last_update_time=$now; my $timeout=5; my $update_interval=1; # print "START TIME: $start\n"; my $update_cnt=0; while ($busy and $now-$start<$timeout) { my $raw_busy=rreg(A_CIM_HOST_ACC_CTRL); $busy=(($raw_busy>>17) & 1); if (!$busy and $update_cnt>0) { if ($ctl =~ /\bshow\b/) { printf "BUSY: 0x%x (not busy)\n",$raw_busy; } } else { $now=time; if ($now-$last_update_time>=$update_interval) { if ($ctl =~ /\bshow\b/) { printf "BUSY: 0x%x (still busy)\n",$raw_busy; } $last_update_time=$now; $update_cnt++; } } } if ($busy and $ctl=~ /\bdie\b/) { die("Timeout in wait_uP_host_acc_not_busy: Bbusy bit set for ". "$timeout seconds\n"); } return $busy; } sub lu_lin_ifaces { my @ret; if (open(IN,'/sbin/ifconfig -a |')) { my $line; while ($line = ) { if ($line =~ /(HWaddr 00:07:43)|(HWaddr 00:00:00:00:00:00)/) { my @in = split (" ",$line); if ($in[0] =~ /bond/) { next } else { push @ret,$in[0]} } } close(IN); } if (0==@ret) { print "Cannot find \"HWaddr 00:07:43\", assuming @ifaces\n"; push @ret, @ifaces; } return @ret; } sub lu_sun_ifaces { my @ret; if (open(IN,'/sbin/ifconfig -a |')) { my $line; while ($line = ) { if ($line =~ /(cxge\d+):/) { push @ret,$1; } } close(IN); } if (0==@ret) { print "Cannot find \"cxge\", assuming @ifaces\n"; push @ret,@ifaces; } return @ret; } sub lu_bsd_ifaces { my @ret; if (open(IN,'/sbin/ifconfig -a |')) { my $line; my $cur_iface; while ($line = ) { if ($line =~ /^(\S+?):/) { $cur_iface=$1; } elsif ($line =~ /ether 00:07:43/ and $cur_iface) { push @ret,$cur_iface; $cur_iface=""; } } close(IN); } if (0==@ret) { print "Cannot find \"ether 00:07:43\", assuming @ifaces\n"; push @ret,@ifaces; } return @ret; } sub ck_ifaces_established { if (not $ifaces_established) { #try to read interfaces from O.S. (ifconfig, ipconfig etc.) if (OS_linux()) { if ($ext_readreg ne "t6rw") { @ifaces=lu_lin_ifaces(); $cardid=$ifaces[0] } } elsif (OS_solaris()) { @ifaces=lu_sun_ifaces(); } elsif (OS_bsd()) { @ifaces=lu_bsd_ifaces(); } $ifaces_established=1; } } #: get_win_ipconfig_hash_array #: ---------------------------- #: Calls ipconfig /all and returns an array of hashes #: of the info from the call to ip config. #: IN: none #: OUT: $ret = reference to array of hashes. sub get_win_ipconfig_hash_array { my $ret=[]; my $hr; my $cnt=0; my $cmd="ipconfig /all"; open(IN,$cmd.' |'); my @lines = ; close (IN); $hr = {}; foreach my $line (@lines) { # print ("Line: |$line|\n"); chomprn $line; # print ("1234: |$line|\n"); if ($line =~ /^\S/) { if ($cnt>0) {push (@{$ret},$hr)} $cnt++; $hr={}; $hr->{header}=$line; } elsif ($line =~ /^\s*$/) { #next } else { my $key=""; my $val=""; my $pstate="start"; my @words=split(" ",$line); foreach my $word (@words) { if ($word eq "." or $word eq ":") { $pstate="periods"; next; } elsif ($pstate eq "start") { $key = $word; $pstate = "key" } elsif ($pstate eq "key") { $key .= " ".$word; } elsif ($pstate eq "periods") { $val = $word; $pstate = "val"; } elsif ($pstate eq "val") { $val .= " ".$word; } } #end if inner foreach. if ($pstate ne "val") { next} $hr->{$key}=$val; } } #end of outer foreach. #The last will just end if ($cnt>0) {push (@{$ret},$hr)} $cnt++; return $ret; } #: get_cxgen_field #: ----------------- #: extract the numeric value for a field in the cxgen_tool -u xxx #: display. #: IN: $_[0] : fieldname to read. #: $_[1] : Reference to array read from cxgen_tool -d cxgen0 -u xxx #: OUT: $ret = "" if no match for the field, else the value on the #: other side of the colon from the fieldname. #: windows cxgen_tool displays mac fields in format: #: rx_frames : #: solaris, running same command, displays with hex numbers. #: sub get_cxgen_field { my $fieldname = $_[0]; my $lines_AR = $_[1]; my $ret =""; foreach my $line (@{$lines_AR}) { if ($line =~ /^$fieldname\s/) { my @words=split (" ",$line); dh2n($words[2],\$ret); last; } } return $ret; } #: get_lin_mac_data #: read linux ethtool data into a hash sub get_lin_mac_data { my $port=shift; my $rethash; my ($result,$status); $result=qxw("ethtool -S $ifaces[$port]\n","",\$status); if (not $status) { $rethash=hash_keyval_filestr($result); } return $rethash; } #: get_win_mac_data #: read windows mac data into an array. sub get_win_mac_data { my $port=shift; my $lines=(); #TODO: the interface/mac name needs refinement. my $cur_macname="mac0"; if ($port==1) {$cur_macname="mac1"} my $cmd="cxgen_tool -d $cardid -u $cur_macname"; open(IN,$cmd.' |'); @$lines = ; close (IN); my $rethash=hash_keyval_filearray($lines); return $rethash; } sub get_sun_kstat_data { my $port = shift; my $interface=$ifaces[$port]; my $lines=(); #TODO: the port/kstat name thing needs refinement. my $kstat_name=$interface; #print("pre kstat_name: $kstat_name\n"); $kstat_name =~ s/(\d+)/:$1/; #put a colon between cxge and instance number. #print("kstat_name: $kstat_name\n"); my $cmd="kstat $kstat_name"; open(IN,$cmd.' |'); @$lines = ; close (IN); my $rethash=hash_keyval_filearray($lines); return $rethash; } #: get_bsd_mac_data #: get mac data from BSD O.S. #: TODO: I don't think this comes from MAC, but rather from O.S. sub get_bsd_mac_data { my $port=shift; my $cur_iface=$ifaces[$port]; my ($eth_data, $ip_data); my (@eth_data, @ip_data); my $macdata={}; (undef, $eth_data, $ip_data) = split(/\n/, `/usr/bin/netstat -ibd -I$cur_iface`); push @eth_data, (split(/\s+/, $eth_data)); push @ip_data, (split(/\s+/, $ip_data)); $macdata->{rxpkt} = $ip_data[4]; $macdata->{rxpkt_errors} = $eth_data[5]; $macdata->{rxbytes} = $eth_data[6]; $macdata->{rxpkt_dropped} = $eth_data[11]; $macdata->{txpkt} = $ip_data[7]; $macdata->{txpkt_errors} = $eth_data[8]; $macdata->{txbytes} = $eth_data[9]; return $macdata; } sub snap_lin_ifconfig { my $port=shift; my $ret; my $status; my $raw=qxw("/sbin/ifconfig $ifaces[$port]","",\$status); if (0==$status) { if ($raw=~/^(\S+)\s/) {$ret->{iface} = $1;} if ($raw=~/inet addr:\s*(\S+)\s/) {$ret->{ipv4} = $1;} if ($raw=~/inet6 addr:\s*(\S+)\s/) {$ret->{ipv6} = $1;} if ($raw=~/MTU:\s*(\d+)\s/) {$ret->{mtu} = $1;} if ($raw=~/RX packets:\s*(\d+)\s/) {$ret->{RxFramesOK} = $1;} if ($raw=~/TX packets:\s*(\d+)\s/) {$ret->{TxFramesOK} = $1;} if ($raw=~/RX bytes:\s*(\d+)\s/) {$ret->{RxOctetsOK} = $1;} if ($raw=~/TX bytes:\s*(\d+)\s/) {$ret->{TxOctetsOK} = $1;} } if (DBG_is_on("snap_lin_ifconfig")) { print "snap_lin_ifconfig Hash:\n"; print indent_str(sprintf_hash($ret),5); print "\n"; } return $ret; } # # xlat the different O.S.'s mac stats names to a standard set # based on the linux ethtool names; # sub snap_mac_stats { my $port=$_[0]; my $macdata; $macdata=snap_mps_stats($port); # if (OS_linux()) { # $macdata=get_lin_mac_data($port); # } elsif (OS_bsd()) { # $macdata=get_bsd_mac_data($port); # } elsif (OS_windows()) { # $macdata=get_win_mac_data($port); # } elsif (OS_solaris()) { # $macdata=get_sun_kstat_data($port); # } else { # print " # ERROR: Unrecognized OStype. This script has called the # T3_PM::snap_mac_status() subroutine on an Operating System for which # this is not implemented. #"; # exit -1; # } #print indent_str(sprintf_hash($macdata),5); # #xlation hash: Key is the operating specific name, # value is the general name. # I've chosen to use linux ethtools display # names for the general names, so for linux, # the O.S. name == general name. # # The algorithm only translates variables that # the O.S. returns. O.S.'es other than Linux # don't have one-to-one mapping. When not # available, the O.S. name will match linux name. # # Where other O.S. have other variables, I don't # currently translate them, but they are availble # in the hash under their own name. these duplicate # keys don't seem to create any problems for perl. my $xh = { #group 1: Linux ethtool names TxOctetsOK => "TxOctetsOK" , TxFramesOK => "TxFramesOK" , TxMulticastFramesOK => "TxMulticastFramesOK", TxBroadcastFramesOK => "TxBroadcastFramesOK", TxPauseFrames => "TxPauseFrames" , TxUnderrun => "TxUnderrun" , TxExtUnderrun => "TxExtUnderrun" , TxFrames64 => "TxFrames64" , TxFrames65To127 => "TxFrames65To127" , TxFrames128To255 => "TxFrames128To255" , TxFrames256To511 => "TxFrames256To511" , TxFrames512To1023 => "TxFrames512To1023" , TxFrames1024To1518 => "TxFrames1024To1518" , TxFrames1519ToMax => "TxFrames1519ToMax" , RxOctetsOK => "RxOctetsOK" , RxFramesOK => "RxFramesOK" , RxMulticastFramesOK => "RxMulticastFramesOK", RxBroadcastFramesOK => "RxBroadcastFramesOK", RxPauseFrames => "RxPauseFrames" , RxFCSErrors => "RxFCSErrors" , RxSymbolErrors => "RxSymbolErrors" , RxShortErrors => "RxShortErrors" , RxJabberErrors => "RxJabberErrors" , RxLengthErrors => "RxLengthErrors" , RxFIFOoverflow => "RxFIFOoverflow" , RxFrames64 => "RxFrames64" , RxFrames65To127 => "RxFrames65To127" , RxFrames128To255 => "RxFrames128To255" , RxFrames256To511 => "RxFrames256To511" , RxFrames512To1023 => "RxFrames512To1023" , RxFrames1024To1518 => "RxFrames1024To1518" , RxFrames1519ToMax => "RxFrames1519ToMax" , PhyFIFOErrors => "PhyFIFOErrors" , TSO => "TSO" , VLANextractions => "VLANextractions" , VLANinsertions => "VLANinsertions" , TxCsumOffload => "TxCsumOffload" , TXCoalesceWR => "TXCoalesceWR" , TXCoalescePkt => "TXCoalescePkt" , RxCsumGood => "RxCsumGood" , RxDrops => "RxDrops" , LroQueued => "LroQueued" , LroFlushed => "LroFlushed" , LroExceededSessions => "LroExceededSessions", CheckTXEnToggled => "CheckTXEnToggled" , CheckResets => "CheckResets" , #group 2: Solaris names obytes => "TxOctetsOK" , opackets => "TxFramesOK" , TxMulticastFramesOK => "TxMulticastFramesOK", TxBroadcastFramesOK => "TxBroadcastFramesOK", pause_tx_cnt => "TxPauseFrames" , tx_uflo => "TxUnderrun" , TxExtUnderrun => "TxExtUnderrun" , TxFrames64 => "TxFrames64" , TxFrames65To127 => "TxFrames65To127" , TxFrames128To255 => "TxFrames128To255" , TxFrames256To511 => "TxFrames256To511" , TxFrames512To1023 => "TxFrames512To1023" , TxFrames1024To1518 => "TxFrames1024To1518" , TxFrames1519ToMax => "TxFrames1519ToMax" , rbytes => "RxOctetsOK" , ipackets => "RxFramesOK" , RxMulticastFramesOK => "RxMulticastFramesOK", RxBroadcastFramesOK => "RxBroadcastFramesOK", pause_rx_cnt => "RxPauseFrames" , rc_crc_err => "RxFCSErrors" , RxSymbolErrors => "RxSymbolErrors" , RxShortErrors => "RxShortErrors" , jabber => "RxJabberErrors" , rx_length_err => "RxLengthErrors" , rx_overflow => "RxFIFOoverflow" , RxFrames64 => "RxFrames64" , RxFrames65To127 => "RxFrames65To127" , RxFrames128To255 => "RxFrames128To255" , RxFrames256To511 => "RxFrames256To511" , RxFrames512To1023 => "RxFrames512To1023" , RxFrames1024To1518 => "RxFrames1024To1518" , RxFrames1519ToMax => "RxFrames1519ToMax" , PhyFIFOErrors => "PhyFIFOErrors" , TSO => "TSO" , VLANextractions => "VLANextractions" , VLANinsertions => "VLANinsertions" , TxCsumOffload => "TxCsumOffload" , TXCoalesceWR => "TXCoalesceWR" , TXCoalescePkt => "TXCoalescePkt" , RxCsumGood => "RxCsumGood" , RxDrops => "RxDrops" , LroQueued => "LroQueued" , LroFlushed => "LroFlushed" , LroExceededSessions => "LroExceededSessions", CheckTXEnToggled => "CheckTXEnToggled" , CheckResets => "CheckResets" , #group 3: Windows Names tx_octets => "TxOctetsOK" , tx_frames => "TxFramesOK" , tx_mcast_frames => "TxMulticastFramesOK", tx_bcast_frames => "TxBroadcastFramesOK", tx_pause => "TxPauseFrames" , tx_underrun => "TxUnderrun" , TxExtUnderrun => "TxExtUnderrun" , tx_frames_64 => "TxFrames64" , tx_frames_65_127 => "TxFrames65To127" , tx_frames_128_255 => "TxFrames128To255" , tx_frames_256_511 => "TxFrames256To511" , tx_frames_512_1023 => "TxFrames512To1023" , tx_frames_1024_1518 => "TxFrames1024To1518" , tx_frames_1519_max => "TxFrames1519ToMax" , rx_octets => "RxOctetsOK" , rx_frames => "RxFramesOK" , rx_mcast_frames => "RxMulticastFramesOK", rx_bcast_frames => "RxBroadcastFramesOK", rx_pause => "RxPauseFrames" , rx_fcs_errs => "RxFCSErrors" , RxSymbolErrors => "RxSymbolErrors" , rx_short => "RxShortErrors" , rx_jabber => "RxJabberErrors" , rx_too_long => "RxLengthErrors" , rx_fifo_ovlfl => "RxFIFOoverflow" , rx_frames_64 => "RxFrames64" , rx_frames_65_127 => "RxFrames65To127" , rx_frames_128_255 => "RxFrames128To255" , rx_frames_256_511 => "RxFrames256To511" , rx_frames_512_1023 => "RxFrames512To1023" , rx_frames_1024_1518 => "RxFrames1024To1518" , rx_frames_1519_max => "RxFrames1519ToMax" , PhyFIFOErrors => "PhyFIFOErrors" , TSO => "TSO" , VLANextractions => "VLANextractions" , VLANinsertions => "VLANinsertions" , TxCsumOffload => "TxCsumOffload" , TXCoalesceWR => "TXCoalesceWR" , TXCoalescePkt => "TXCoalescePkt" , RxCsumGood => "RxCsumGood" , RxDrops => "RxDrops" , LroQueued => "LroQueued" , LroFlushed => "LroFlushed" , LroExceededSessions => "LroExceededSessions", CheckTXEnToggled => "CheckTXEnToggled" , CheckResets => "CheckResets" , #group 4: BSD names txbytes => "TxOctetsOK" , txpkt => "TxFramesOK" , TxMulticastFramesOK => "TxMulticastFramesOK", TxBroadcastFramesOK => "TxBroadcastFramesOK", TxPauseFrames => "TxPauseFrames" , TxUnderrun => "TxUnderrun" , TxExtUnderrun => "TxExtUnderrun" , TxFrames64 => "TxFrames64" , TxFrames65To127 => "TxFrames65To127" , TxFrames128To255 => "TxFrames128To255" , TxFrames256To511 => "TxFrames256To511" , TxFrames512To1023 => "TxFrames512To1023" , TxFrames1024To1518 => "TxFrames1024To1518" , TxFrames1519ToMax => "TxFrames1519ToMax" , rxbytes => "RxOctetsOK" , rxpkt => "RxFramesOK" , RxMulticastFramesOK => "RxMulticastFramesOK", RxBroadcastFramesOK => "RxBroadcastFramesOK", RxPauseFrames => "RxPauseFrames" , RxFCSErrors => "RxFCSErrors" , RxSymbolErrors => "RxSymbolErrors" , RxShortErrors => "RxShortErrors" , RxJabberErrors => "RxJabberErrors" , RxLengthErrors => "RxLengthErrors" , RxFIFOoverflow => "RxFIFOoverflow" , RxFrames64 => "RxFrames64" , RxFrames65To127 => "RxFrames65To127" , RxFrames128To255 => "RxFrames128To255" , RxFrames256To511 => "RxFrames256To511" , RxFrames512To1023 => "RxFrames512To1023" , RxFrames1024To1518 => "RxFrames1024To1518" , RxFrames1519ToMax => "RxFrames1519ToMax" , PhyFIFOErrors => "PhyFIFOErrors" , TSO => "TSO" , VLANextractions => "VLANextractions" , VLANinsertions => "VLANinsertions" , TxCsumOffload => "TxCsumOffload" , TXCoalesceWR => "TXCoalesceWR" , TXCoalescePkt => "TXCoalescePkt" , RxCsumGood => "RxCsumGood" , RxDrops => "RxDrops" , LroQueued => "LroQueued" , LroFlushed => "LroFlushed" , LroExceededSessions => "LroExceededSessions", CheckTXEnToggled => "CheckTXEnToggled" , CheckResets => "CheckResets" , }; my $rethash={}; foreach my $key (keys %$macdata) { if (exists $xh->{$key}) { $rethash->{$xh->{$key}} = $macdata->{$key}; } else { $rethash->{$key} = $macdata->{$key}; } } #print indent_str(sprintf_hash($macdata),5); return $rethash; } sub snap_mps_stats { my $port=$_[0]; my $H={}; $H->{TxOctetsOK} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_BYTES_L,$port); $H->{TxFramesOK} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_FRAMES_L,$port); $H->{TxPauseFrames} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_PAUSE_L,$port); $H->{RxOctetsOK} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_BYTES_L,$port); $H->{RxFramesOK} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_FRAMES_L,$port); $H->{RxPauseFrames} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_PAUSE_L,$port); $H->{TxPPP0} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_PPP0_L,$port); $H->{TxPPP1} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_PPP1_L,$port); $H->{TxPPP2} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_PPP2_L,$port); $H->{TxPPP3} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_PPP3_L,$port); $H->{TxPPP4} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_PPP4_L,$port); $H->{TxPPP5} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_PPP5_L,$port); $H->{TxPPP6} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_PPP6_L,$port); $H->{TxPPP7} =rreg_port_64(A_MPS_PORT_STAT_TX_PORT_PPP7_L,$port); $H->{RxPPP0} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_PPP0_L,$port); $H->{RxPPP1} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_PPP1_L,$port); $H->{RxPPP2} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_PPP2_L,$port); $H->{RxPPP3} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_PPP3_L,$port); $H->{RxPPP4} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_PPP4_L,$port); $H->{RxPPP5} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_PPP5_L,$port); $H->{RxPPP6} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_PPP6_L,$port); $H->{RxPPP7} =rreg_port_64(A_MPS_PORT_STAT_RX_PORT_PPP7_L,$port); return $H; } sub read_mac_tx_pkts { my $port=$_[0]; my $ret; if (OS_linux()) { my ($save,$ixb, $ixe, $len); open(IN,"$ext_macpkts -a $ifaces[$port] | grep ".'"TX packets:" |'); $_ = ; close (IN); $ixb = index($_,":"); $ixb++; $ixe = index($_," ",$ixb); $len = ($ixe - $ixb); $ret = substr($_,$ixb,$len); # print "$_\nixb = $ixb, ixe = $ixe, len = $len, ret = $ret\n"; } elsif (OS_bsd()) { my $macdata=get_bsd_mac_data($port); $ret=$macdata->{txpkt}; } elsif (OS_windows()) { my $macdata=get_win_mac_data($port); $ret=$macdata->{tx_frames}; } elsif (OS_solaris()) { my $kstat_data=get_sun_kstat_data($port); $ret=$kstat_data->{opackets}; } else { print " ERROR: Unrecognized OStype. This script has called the T3_PM::read_mac_tx_pkts() subroutine on an Operating System for which this is not implemented. "; exit -1; } return $ret; } sub read_mac_rx_pkts { my $port=$_[0]; my $ret=0; if (OS_linux()) { my ($save,$ixb, $ixe, $len); #TODO: don't depend on grep. open(IN,"$ext_macpkts -a $ifaces[$port] | grep ".'"RX packets:" |'); $_ = ; close (IN); $ixb = index($_,":"); $ixb++; $ixe = index($_," ",$ixb); $len = ($ixe - $ixb); $ret = substr($_,$ixb,$len); # print "$_\nixb = $ixb, ixe = $ixe, len = $len, ret = $ret\n"; } elsif (OS_bsd()) { my $macdata=get_bsd_mac_data($port); $ret=$macdata->{rxpkt}; } elsif (OS_windows()) { my $macdata=get_win_mac_data($port); $ret=$macdata->{rx_frames}; } elsif (OS_solaris()) { my $kstat_data=get_sun_kstat_data($port); $ret=$kstat_data->{ipackets}; } else { print " ERROR: Unrecognized OStype. This script has called the T3_PM::read_mac_tx_pkts() subroutine on an Operating System for which this is not implemented. "; exit -1; } return $ret; } sub read_mtu { my $if=$ifaces[0]; if (0==$#_) { $if = $_[0];} my $ret; if (OS_windows()) {goto out;} my $pat=' mtu[:\s]+(\d+)'; my ($results,$status); $results=qxw("/sbin/ifconfig $if","",\$status); if ((not $status) and $results =~ /$pat/i) { $ret=$1; } out: return $ret; } sub get_ints_msg { my $ports=$_[0]; my $ret=""; if (OS_linux()) { my @ints=""; if ($ports<=1) { @ints=`grep $ifaces[0] /proc/interrupts`; } else { @ints=`grep -E \"$ifaces[0]|$ifaces[1]\" /proc/interrupts`; } $ret = join "",@ints; } elsif (OS_windows() || OS_solaris()) { my @ints =`cxgen_tool -d $cardid -u intr`; $ret=get_cxgen_field("intrs",\@ints); if ($ret) { $ret = "intrs : ".$ret."\n"; } else { $ret="*** Unable to read interrupt info"; } } else { $ret = "Interrupt info for $OStype not yet implemented\n"; } return $ret; } ##:------------------------------------------------------------------------- ###: PCI access subroutines ##:------------------------------------------------------------------------- ##: ck_pcie_ifaces_estabished #:----------------------- #: Determine the bus, slot and function of Chelsio card #: IN: $_[0]: cla, includes {pf} member specifying physical function to find. #: RET: 1 if found, 0 if cannot find card or can't find $cla->{pf} fucntion. #: GLOBALS: $g_bus, $g_slot, $g_function set to bus, slot and function # # We find bus slot and function by issuing lspci command, and looking for # lines like these: bus, slot and function are numbers in left hand column. # # find_bsf #08:00.0 Non-VGA unclassified device: Chelsio Communications Inc: Unknown device a000 #08:00.1 Non-VGA unclassified device: Chelsio Communications Inc: Unknown device a001 # # Note: Can I use the device numbers -d 1425:a000 and -d 1425:a001 to avoid # the need to call this function? # sub ck_pcie_ifaces_established { if ($g_pcie_ifaces_established) {return 1;} my $pf=0; if (not OS_darwin()) { if (not is_executable("lspci")) { die "I cannot find executable version of \"lspci\" in path\n". "I looked in:\n$ENV{PATH}\n"; } if (not is_executable("setpci")) { die "I cannot find executable version of \"setpci\" in path\n". "I looked in:\n$ENV{PATH}\n"; } @g_pcie_ifaces =(); my $out=qxw("lspci"); my @lines=split("\n",$out); foreach my $line (@lines) { if ($line =~ /^([\da-f]{2}):([\da-f]{2})\.([\da-f]).*Chelsio.*/i) { my $bus=$1; my $slot=$2; my $function=$3; push (@g_pcie_ifaces, "-s $bus:$slot.$function"); $g_pcie_ifaces_established=1; # print @g_pcie_ifaces."\n"; } } } return $g_pcie_ifaces_established; } sub rpci { my $reg = sprintf("0x%x",$_[0]); my $ret; ck_pcie_ifaces_established(); if (OS_linux()) { my $cmd="$ext_readpci $g_pcie_ifaces[0] $reg.L"; open(IN,"$cmd |"); $_ = ; close(IN); ($ret) = split; if (DBG_is_on("reg")) {printf "$cmd : $ret\n";} } elsif (OS_windows() || OS_solaris()) { open(IN,"$ext_readpci $cardid -i $reg |"); $_ = ; close(IN); ($ret) = split; } elsif (OS_bsd()) { #TODO: handle two card systems. open(IN,"pciconf -l | grep cxgbc |"); $_ = ; if ($ifaces[0] eq "cxgb2") { $_ = ;} close(IN); my ($selector) = split(" ",$_); open(IN,"pciconf -r $selector $reg |"); $_ = ; close(IN); ($ret) = split; } elsif (OS_darwin()) { ($ret) = "0x0"; } else { print " ERROR: Unrecognized OStype. This script has called the T3_PM::rpci() subroutine on an Operating System for which there is no known pci register reading utility. "; exit -1; } return hex($ret); } sub wreg_pci { my $reg = shift; my $val = shift; my $hi = ($#_>=0) ? shift : 31; my $lo = ($#_>=0) ? shift : 0; my $ret=undef; ck_pcie_ifaces_established(); if (OS_linux()) { if ($hi!=31 or $lo!=0) { my $rval=rpci($reg); $val=put_bits($rval,$val,$hi,$lo); } my $regstr=sprintf("0x%x",$reg); my $valstr=sprintf("0x%x",$val); my $show=""; if (DBG_is_on("reg")) {$show="show showret";} qxw("$ext_readpci $g_pcie_ifaces[0] $regstr.L=$valstr",$show); $ret=$val; } else { print " ERROR: Unrecognized OStype. This script has called the T3_PM::rpci() subroutine on an Operating System for which there is no known pci register reading utility. "; exit -1; } return $ret; } sub read_linkstate { my $port = $_[0]; my $ret="unknown"; if (OS_linux()) { my $status; if ($ext_linkstate eq "ethtool") { my $cmd="$ext_linkstate $ifaces[$port]"; my $cmdoutput = qxw($cmd,"",\$status); if ($cmdoutput =~ /Link detected:.(yes|no)/ ) { $ret="up"; if ($1 eq "no") {$ret="down"} } } } elsif (OS_windows()) { my $har; $har=get_win_ipconfig_hash_array(); foreach my $hr (@{$har}) { if (exists $hr->{Description} and $hr->{Description} =~ /Chelsio/) { if (exists $hr->{"Media State"}) { $ret="down"; } else { $ret="up"; } last; } } } elsif (OS_solaris() or OS_bsd() or OS_darwin()) { my $status; my $cmd="ifconfig $ifaces[$port]"; my $cmdoutput = qxw($cmd,"",\$status); if ($cmdoutput =~ "UP") { $ret="up" } else { $ret="down"; } } else { print " ERROR: Unrecognized OStype: $OStype. This script has called the T3_PM::read_linkstate() subroutine on an Operating System for which this hasn't been implemented "; exit -1; } return $ret; } sub get_context { my $href = shift; my $type = shift; my $id = shift; my (@temp,%ctx); %$href=%ctx; # clear the hash passed in open(IN,"/sbin/cxgbtool $cardid context $type $id |"); while () { chomp; @temp = split(/:\s+/); if ($#temp == 1) { # convert line into a record if its splittable by colon $ctx{"\L$temp[0]"}= $temp[1]; } } close (IN); if ($type eq "egress") { $$href{credits}=$ctx{credits}; $$href{gts}=$ctx{gts}; $$href{index}=$ctx{index}; $$href{size}=$ctx{"queue size"}; $$href{addr}=hex($ctx{"base address"}); $$href{tun}=$ctx{tun}; $$href{tun}=$ctx{toe}; $$href{gen}=$ctx{generation}; $$href{up_token}=$ctx{"up token"}; $$href{valid}=$ctx{valid}; } elsif ($type eq "response") { $$href{index}=$ctx{index}; $$href{size}=$ctx{"size"}; $$href{addr}=hex($ctx{"base address"}); $$href{msirspq}=$ctx{'msi-x/rspq'}; $$href{inten}=$ctx{"intr enable"}; $$href{intarmed}=$ctx{"intr armed"}; $$href{gen}=$ctx{generation}; $$href{cqmode}=$ctx{"cq mode"}; $$href{fl_thresh}=$ctx{"fl threshold"}; } elsif ($type eq "fl") { $$href{index}=$ctx{index}; $$href{size}=$ctx{"queue size"}; $$href{addr}=hex($ctx{"base address"}); $$href{gen}=$ctx{generation}; $$href{entry_size}=$ctx{"entry size"}; $$href{congest_thresh}=$ctx{'congest thr'}; $$href{gts}=$ctx{gts}; } elsif ($type eq "cq") { $$href{index}=$ctx{index}; $$href{size}=$ctx{"size"}; $$href{addr}=hex($ctx{"base address"}); $$href{rspqueuenum}=hex($ctx{"rsp queue #"}); $$href{AN}=hex($ctx{AN}); $$href{armed}=hex($ctx{armed}); $$href{ANS}=hex($ctx{ANS}); $$href{gen}=hex($ctx{generation}); $$href{omode}=hex($ctx{"overflow mode"}); $$href{credits}=$ctx{credits}; $$href{creditthreshold}=$ctx{"credit threshold"}; } } sub read_win_qset_hash { my $qset=$_[0]; my $ret = {}; if (not OS_windows()) {goto out} my $cmd=sprintf "cxgen_tool -d $cardid -u qs%u",$qset; open(IN,$cmd.' |'); my @lines = ; close (IN); pop @lines; #throw away the dbg_cnts my $level0="dummy"; foreach my $line (@lines) { chomprn $line; # print("LINE: |$line|\n"); my @words = split (":",$line); my $key; my $val; if (@words >0) { $key=$words[0]; chomp_outer_space($key); $key =~ s/ /_/; $key = "\L$key"; # print("KEY: |$key|\n"); } if (@words >1) { $val = $words[1]; chomp_outer_space($val); # print("VAL: |$val|\n"); } if (1==@words and $line !~ /^[ ]/) { $level0 = $key; # print("LEVEL0: |$level0|\n"); $ret->{$level0} = {}; } elsif (2==@words) { # print("ASSIGN: |$level0|->|$key|=|$val|\n"); $ret->{$level0}->{$key} = $val; } } out: return $ret; } sub get_tcam { my $tcamix=shift; my $tcam=[]; my $rawlines=""; my $cmd = sprintf("cxgbtool $cardid tcamdump 0x%x 4 |",$tcamix); open(CMD,$cmd); my @lines=; close(CMD); my $ix=0; my $lineix=0; for (my $lineix=0 ; $lineix<= $#lines; ++$lineix) { if ($lineix==1 or $lineix==3) { next; } #every other line is duplicate. my $line=$lines[$lineix]; $rawlines.=$line; chomp; my @vals = split(/:/,$line); shift(@vals); #throw away address if (defined $vals[0]) { @vals = split(" ",$vals[0]); $tcam->[$ix++]=hex($vals[0]); $tcam->[$ix++]=(hex($vals[1])>>24) & 0xFF; $tcam->[$ix++]=(hex($vals[1])>>16) & 0xFF; $tcam->[$ix++]=(hex($vals[1])>> 8) & 0xFF; $tcam->[$ix++]=(hex($vals[1])>> 0) & 0xFF; $tcam->[$ix++]=(hex($vals[2])>>24) & 0xFF; $tcam->[$ix++]=(hex($vals[2])>>16) & 0xFF; $tcam->[$ix++]=(hex($vals[2])>> 8) & 0xFF; $tcam->[$ix++]=(hex($vals[2])>> 0) & 0xFF; } } return ($rawlines,$tcam); } #reads the data and mask from tcam, returning result in #a hash consiting of rawlines from cxgbtool command and #and array references to data and mask. sub read_tcam { my $tcamix=shift; my $href={}; my ($rawlines,$tcamdata,$tcammask); my $dataix = 0x1000000 | ($tcamix*4); my $maskix = 0x2000000 | ($tcamix*4); ($rawlines,$tcamdata)=get_tcam($dataix); $href->{data_rawlines}=$rawlines; $href->{dataAR} =$tcamdata; ($rawlines,$tcamdata)=get_tcam($maskix); $href->{mask_rawlines}=$rawlines; $href->{maskAR} =$tcamdata; return $href; } #read the tcb into byte array. sub read_tcb { my $tid=shift; my $aref=[]; my $rawlines=""; my $cmd = sprintf("cxgbtool $cardid tcb %u |",$tid); open(CMD,$cmd); my @lines=; close(CMD); my $ix=0; my $lineix=0; for (my $lineix=0 ; $lineix<= $#lines; ++$lineix) { my $line=$lines[$lineix]; $rawlines.=$line; chomp; my @vals = split(/:/,$line); shift(@vals); #throw away address if (defined $vals[0]) { @vals = split(" ",$vals[0]); for (my $i=0 ; $i<=$#vals ; ++$i) { #print "$vals[$i]\n"; $aref->[$ix++]=(hex($vals[$i])>> 0) & 0xFF; $aref->[$ix++]=(hex($vals[$i])>> 8) & 0xFF; $aref->[$ix++]=(hex($vals[$i])>>16) & 0xFF; $aref->[$ix++]=(hex($vals[$i])>>24) & 0xFF; } } } return ($rawlines,$aref); } sub get_OStype { my $ret="linux"; #assume linux. if ($^O =~ /linux/i) { $ret="linux"; } elsif ($^O =~ /darwin/i) { $ret="darwin"; } elsif ($^O =~ /win/i) { $ret="windows"; } elsif ($^O =~ /bsd/i) { $ret="bsd"; } elsif ($^O =~ /solaris/i) { $ret="solaris"; } return $ret; } sub OS_linux { return ("linux" eq $OStype);} sub OS_windows { return ("windows" eq $OStype);} sub OS_solaris { return ("solaris" eq $OStype);} sub OS_bsd { return ("bsd" eq $OStype);} sub OS_darwin { return ("darwin" eq $OStype);} ########################################################################### # END of O.S. Dependent subrotines. All subroutines below this line # do not make any invocations of utilities that are unique to a # given O.S. ########################################################################### #grep_read #--------- # IN: $_[0] is grep string to execute. # OUT: $_[1] is column with the value to read. If $_[1]> number # of fields, then the last field is used. sub grep_read { my $grep_cmd = $_[0]; my $grep_ix = $_[1]; my @words; open(IN,"$grep_cmd |"); $_ = ; close (IN); @words = split; if ($grep_ix>$#words) {$grep_ix=$#words;} return $words[$grep_ix]; } sub get_BoardInfo { my $href = shift; my $DevID = shift; my $ret=1; #temp hack: PE9020 is programming as DevID 20. #read bit 1 of register 0xE0. If set, it is really PCI-E. %$href=(); # clear the hash. $$href{devid}=$DevID; #Note we return true $DevID. if (0x20==$DevID && rreg_bits(0xE0,1,1)) {$DevID=0x40;} if (0x20==$DevID) { $$href{name}="PE9010"; $$href{bus} ="PCIX"; $$href{lanes} =4; $$href{coreclock} = 33; } elsif (0x21==$DevID) { $$href{name}="T302e"; $$href{bus} ="PCIE"; $$href{lanes} =4; $$href{coreclock} = 50; } elsif (0x22==$DevID) { $$href{name}="T310e"; $$href{bus} ="PCIE"; $$href{lanes} =8; $$href{coreclock} = 175; } elsif (0x23==$DevID) { $$href{name}="T310x"; $$href{bus} ="PCIX"; $$href{lanes} =1; $$href{coreclock} = 175; } elsif (0x24==$DevID) { $$href{name}="T302x"; $$href{bus} ="PCIX"; $$href{lanes} =1; $$href{coreclock} = 50; } elsif (0x25==$DevID) { $$href{name}="T320E"; $$href{bus} ="PCIE"; $$href{lanes} =8; $$href{coreclock} = 175; } elsif (0x26==$DevID) { $$href{name}="T310x"; $$href{bus} ="PCIX"; $$href{lanes} =1; $$href{coreclock} = 175; } elsif (0x30==$DevID) { if (rreg_bits(0xE0,1,1)) { $$href{name}="T310E"; $$href{bus} ="PCIE"; } else { $$href{name}="T310X"; $$href{bus} ="PCIX"; } $$href{lanes} =8; $$href{coreclock} = 175; } elsif (0x31==$DevID) { if (rreg_bits(0xE0,1,1)) { $$href{name}="T320E"; $$href{bus} ="PCIE"; } else { $$href{name}="T320X"; $$href{bus} ="PCIX"; } $$href{lanes} =8; $$href{coreclock} = 175; } elsif (0x32==$DevID) { if (rreg_bits(0xE0,1,1)) { $$href{name}="T302E"; $$href{bus} ="PCIE"; } else { $$href{name}="T302X"; $$href{bus} ="PCIX"; } $$href{lanes} =4; $$href{coreclock} = 50; } elsif (0x33==$DevID) { $$href{name}="T304E"; $$href{bus} ="PCIE"; $$href{lanes} =4; $$href{coreclock} = 150; } elsif (0x40==$DevID) { $$href{name}="PE9020"; $$href{bus} ="PCIE"; $$href{lanes} =4; $$href{coreclock} = 33; } else { $$href{name}="unknown"; $$href{bus} ="unknown"; $$href{lanes} =0; $$href{coreclock} = 33; $ret=0; } return $ret; } ########################################################################### # Index Register Read/Write Subroutines # Several of our registers, such as TP's MIB registers for example, # are accessed via indirect methods, such as first writing an index # register and then reading or writing a data register. If these # indirect methods can be built up from a series of calls to rreg() and # wreg() and have no O.S. dependencies, then they belong in this section # of the file. ########################################################################### sub rreg_via_ix { my $addr_reg = shift; my $data_reg = shift; my $reg = shift; my $ret; wreg($addr_reg,$reg); $ret = rreg($data_reg); return $ret; } sub wreg_via_ix { my $addr_reg = shift; my $data_reg = shift; my $reg = shift; my $val = shift; my $ret; wreg($addr_reg,$reg); $ret = wreg($data_reg,$val); return $ret; } sub sge_r_dbg { my $lo=rreg(SGE_DEBUG_DATA_LOW_INDEX_0 +$_[0]*4); my $hi=rreg(SGE_DEBUG_DATA_HIGH_INDEX_0+$_[0]*4); return ($lo,$hi); } sub read_sge_dbg { my $sge_dbgA=[]; my $sge_dbgH={}; my $dataA=[]; for (my $i=0 ; $i<=15 ; ++$i) { my ($lo,$hi)=sge_r_dbg($i); push (@$dataA, ($lo,$hi)); } foreach my $H (@$g_sge_dbgA) { my $cH={%$H}; #make a copy. my $ix=$H->{addr}<<1 | $H->{half}; $cH->{val}=get_bits($dataA->[$ix],$H->{hi},$H->{lo}); if ($H->{type} eq "SEOP") { $cH->{sop}=get_bits($cH->{val},7,4); $cH->{eop}=get_bits($cH->{val},3,0); } elsif ($H->{type} eq "SOP") { $cH->{sop}=$cH->{val} } $sge_dbgH->{$H->{name}}=$cH; push (@$sge_dbgA,$cH); } return ($sge_dbgA,$sge_dbgH); } sub rmib { return rreg_via_ix(TP_MIB_INDEX,TP_MIB_DATA,$_[0]);} ##: rmibH #: ----- sub rmibH { my $mibH={}; foreach my $key (sort keys %$g_tp_mibH) { my $H={%{$g_tp_mibH->{$key}}}; #make a copy. $H->{val}=rmib($H->{addr}); $mibH->{$key}=$H; } return $mibH; } ##: read_reg_group #: -------------- sub read_reg_group { my $base_addr=shift; my $size =shift; my $num =shift; my @ret=(); for (my $i = 0 ; $i<$num ; ++$i) { my $val=rreg($base_addr+($i*$size)); push (@ret,$val); } return wantarray ? @ret : \@ret; } ########################################################################### # Read mdio (phy) register ########################################################################### sub rreg_mdio { my $phy=shift; my $mdd=shift; my $reg=shift; my $ret; if (OS_linux() || OS_bsd() || OS_solaris()) { my $cmd="cxgbtool $cardid mdio $phy $mdd $reg"; if (OS_solaris()) { $cmd="cxgbtool $cardid mdio $phy $reg $mdd"; } open(REGCMD,"$cmd |"); $_ = ; close(REGCMD); ($ret) = split; $ret = hex($ret); } elsif (OS_windows()) { print " ERROR: Windoes doesn't support cxgbtool, so cannot read phy. "; exit -1; } else { print " ERROR: Unrecognized OStype. This script has called the T3_PM::rreg() subroutine on an Operating System for which there is no known register reading utility. "; exit -1; } return $ret; } ########################################################################### # Bit field manipulation funtions # These function are used to read and write bit fields within larger # objects. ########################################################################### #:get_bits: extract a range of bits from a 32-bit integer. #: IN: $val to get bits from. #: $hi: hightest bit to extract. #: $lo: lowest bit to extract #: (note: It's okay to reverse $lo and $hi, code will adjust #: OUT: bits $lo to $hi of $val, right shifted. sub get_bits { my ($val,$hi,$lo,$temp,$bitcnt,$mask); $val = $_[0]; $hi = $_[1]; $lo = $_[2]; if ($lo > $hi) { $temp = $lo; $lo = $hi ; $hi = $temp;} $bitcnt = ($hi - $lo) +1; if (32==$bitcnt) { $mask = 0xFFFFFFFF; } else { $mask = (1 << $bitcnt) -1; } return (($val>>$lo) & $mask); } #:put_bits: insert a bit field into a 32-bit integer. #: IN: $val: Existing 32-bit integer to put value into. #: $fval: Field value to be inserted. #: $hi: highest bit to overwrite. #: $lo: lowest bit to overwrite #: (note: It's okay to reverse $lo and $hi, code will adjust #: OUT: bits $lo to $hi of $val, right shifted. sub put_bits { my ($temp,$bitcnt,$mask); my $val = shift; my $fval = shift; my $hi = shift; my $lo = shift; my $ret; if ($lo > $hi) { $temp = $lo; $lo = $hi ; $hi = $temp;} $bitcnt = ($hi - $lo) +1; if (32==$bitcnt) { $mask = 0xFFFFFFFF; } else { $mask = (1 << $bitcnt) -1; } $ret = $val & ~($mask << $lo); # Clear existing field bits. $ret |= ($mask & $fval) << $lo; # OR in new bits. Don't exceed field size. return $ret; } #: rreg_bits. Calls rreg to read a register, then get_bits to extract bit field #: IN: $reg: Register to read. #: $hi: Highest bit position of field to extract. #: $lo: Lowest bit position of field to extract. #: Note: this subroutine will sort $hi and $lo. #: sub rreg_bits { my $reg = shift; my $hi = shift; my $lo = shift; my $ret; $ret = rreg($reg); if ($hi!=31 or $lo!=0) { $ret = get_bits($ret,$hi,$lo); } return $ret; } sub wreg_bits { my $reg = shift; my $fval= shift ; my $lo = shift; my $hi = shift; my $rval; my $ret; if ($lo>$hi) {($lo,$hi)=($hi,$lo)} if (31==$hi and 0==$lo) { $ret=$fval; } else { $rval = rreg($reg); $ret = put_bits($rval,$fval,$hi,$lo); } wreg($reg,$ret); return $ret; } sub rreg_fs { my $regfs = shift; my $ret; my @fs=prs_regfs($regfs); # print ("fs0=$fs[0], fs1=$fs[1], fs2=$fs[2]\n"); $ret = rreg_bits($fs[0],$fs[1],$fs[2]); return $ret; } sub wreg_fs { my $regfs = shift; my $ret; my @fs=prs_regfs($regfs); $ret = wreg_bits($fs[0],$fs[1],$fs[2]); return $ret; } #:get_reg: #:------ #:read register from a hash or from hardware if hash is not defined #:IN: $_[0]: register address #: { my $get_reg_href; sub set_get_reg_href {$get_reg_href=$_[0]; } sub clear_get_reg_href {undef $get_reg_href;} sub get_reg { my $addr = $_[0]; my $ret; my $val; if (defined $get_reg_href) { my $key = sprintf "%3.3x",$addr; $key = "\L$key"; # print "key: $key\n"; $ret = $get_reg_href->{$key}; } else { $ret=rreg($addr); } return $ret; } sub get_reg_bits { my $reg = shift; my $hi = shift; my $lo = shift; my $val; my $ret; $val = get_reg($reg); $ret = get_bits($val,$hi,$lo); return $ret; } } #:get_abit: extract a single bit form an array of 32-bit words #: IN: $aref array reference to array of 32-bits words. #: $bit: bit to extract, interpreting array a a single large integer. #: OUT: $bit from $aref. Examples: #: if $bit=0, then returns bit 0 of $$aref[0], #: If $bit=33, then returns bit 1 of $$aref[1]. sub get_abit { my $aref = shift; my $bit = shift; my $ret=undef; my ($ix, $shift); $ix=int($bit/32); $shift=$bit%32; # printf ("$bit, $ix, $shift, $$aref[0], \n"); $ret=($$aref[$ix] >> $shift) & 1; return $ret; } #:get_abits: extract a range of bits from an array of 32-bit words. #: IN: $aref: array reference to array of 32-bit words. #: $hi: hightest bit to extract. #: $lo: lowest bit to extract #: (note: It's okay to reverse $lo and $hi, code will adjust) #: $lo and $hi can cross 32-bit word boundaries. #: OUT: bits $lo to $hi of $$aref, right shifted. sub get_abits { my $aref = shift; my $lo = shift; my $hi = shift; my $temp; my $ret=0; if ($lo>$hi) {$temp=$lo ; $lo=$hi ; $hi=$temp;} while ($hi>=$lo) { $ret= ($ret<<1) | get_abit($aref,$hi); # printf ("ret = 0x%x\n",$ret); $hi-=1; } return $ret; } #:get_a8bit: extract a single bit form an array of 8-bit little-endian bytes #: IN: $aref array reference to array of 8-bit little-endian bytes. #: $bit: bit to extract, interpreting array a a single large integer. #: OUT: $bit from $aref. Examples: #: if $bit=0, then returns bit 0 of $$aref[0], #: If $bit=9, then returns bit 1 of $$aref[1]. sub get_a8bit { my $aref = shift; my $bit = shift; my $ret=undef; my ($ix, $shift); $ix=int($bit/8); $shift=$bit%8; # printf ("$bit, $ix, $shift, $$aref[0], \n"); $ret=($$aref[$ix] >> $shift) & 1; return $ret; } #:get_a8bits: extract a range of bits from an array of 8-bit bytes. #: IN: $aref: array reference to array of 8-bit words. #: $lo: lowest bit to extract #: $hi: hightest bit to extract. #: (note: It's okay to reverse $lo and $hi, code will adjust) #: $lo and $hi can cross 32-bit word boundaries. #: OUT: bits $lo to $hi of $$aref, right shifted. sub get_a8bits { my $aref = shift; my $lo = shift; my $hi = shift; my $temp; my $ret=0; if ($lo>$hi) {$temp=$lo ; $lo=$hi ; $hi=$temp;} while ($hi>=$lo) { $ret= ($ret<<1) | get_a8bit($aref,$hi); # printf ("ret = 0x%x\n",$ret); $hi-=1; } return $ret; } #:get_flit_bits: extract a range of bits from an array of 8-bit bytes little #: endian bytes using 8-byte flit referencing #: IN: $aref: array reference to array of 8-bit bytes in little endian #: format. #: $flit: 8-byte flit to get bits from. Each flit is in big-endian format. #: $hi: hightest bit to extract. #: $lo: lowest bit to extract #: (note: It's okay to reverse $lo and $hi, code will adjust) #: $lo and $hi can cross 32-bit word boundaries. #: OUT: bits $lo to $hi of $$aref, right shifted. sub get_flit_bits { my $aref = shift; my $flit = shift; my $lo = shift; my $hi = shift; my ($temp,$i); my $ret=0; if ($lo>$hi) {$temp=$lo ; $lo=$hi ; $hi=$temp;} $lo+=64*$flit; $hi+=64*$flit; while ($hi>=$lo) { $temp = $hi & ~0x3F; $i = $hi & 0x3F; $temp += ((63-$i)&~0x7) + ($i%8); #endianess conversion. $ret= ($ret<<1) | get_a8bit($aref,$temp); # printf("hi=$hi, temp = $temp, i=$i, %u, ret = 0x%x\n",$i%8,$ret); $hi-=1; } return $ret; } ########################################################################### # spr_* functions # The spr_* subroutines are routines for converting an input into # a more user-friendly form for display. They all return a string ########################################################################### #:spr_ip_addr #:IN: ip address as 32-bit number. #:OUT: ip address as dotted decimal string. #: sub spr_ip_addr { my $ip = shift; my $ret=""; $ret = sprintf("%u.%u.%u.%u", ($ip >> 24) & 0xFF, ($ip >> 16) & 0xFF, ($ip >> 8) & 0xFF, ($ip >> 0) & 0xFF ); return $ret; } #:spr_hash #:IN: A simple hash in which value is a scalar. #:OUT: A sring displaying the hash keys and values in alphabetically #:sorted order sub spr_hash { my $href = shift; my $ret = ""; my $fmt ="%-20s : %s\n"; $ret.= sprintf ($fmt,"key","value"); $ret.= sprintf ($fmt,"--------------------","--------------------"); foreach my $key (sort keys %$href) { if (defined $href->{$key}) { $ret.=sprintf ($fmt,$key,$href->{$key}); } else { $ret.=sprintf ($fmt,$key,""); } } $ret.="\n"; return $ret; } sub spr_comma { my $num = shift; my $ret = $num; if ($ret =~ /\./) { # must use "$ " and x option to keep autoindenter for breaking. $ret =~ s/(?<=\d)(?=(\d\d\d)+(\.)(\d)*$ )/,/gx; } else { $ret =~ s/(?<=\d)(?=(\d\d\d)+$ )/,/gx; } return $ret; } ########################################################################### # prs_* functions # The prs_* subroutines are parsing routines for converting text # into more useful variables. ########################################################################### #:prs_regfs #:------------ #: Take a "REGister Field String" (regfs), and return a 3-tuple #: consisting of register address, high bit position and low bit position. #: #: A regfs is a string describing a field in a 32-bit register. It has the #: the form: #: #: 0x1A4[15:0] #: #: where first number is register address in hex, and the second two #: numbers are the high and low bit positions in decimal. #: (they can be in any order). #: #: Register field strings can also take the forms: #: 0x1a4 #: 1a4 #: 1ac[5:12] #: #: If bit positions are not specified, 31 and 0 are assumed. #: #: #: sub prs_regfs { my $reg_fstr = shift; my $addr; my $hi=31; my $lo=0; my $temp; my $regfs_regex=qr{ ( #capture the leading hex number in $1 (?:0x)? #allow optional 0x, but don't capture it [\da-f]+) #hex number regex (?:\s*) #allow optional white space, don't capture. (?: #don't capture entire bit field, just hi & lo \[ #need to escape the open brace (\d+) #capture hi in $2 : #separate between hi & lo (\d+) #capture lo in $3 \] #must escape the close brace. )? #make bit field optional. }xi; #squeeze out white space, ignore case. no warnings; #we get a bunch of "use of unitialized values" errors #when $2, $3 etc. are defined. $reg_fstr=~ $regfs_regex; DBG("prs_regfs","1: $1, 2:$2, 3:$3, 4:$4 5: $5\n"); $addr = hex($1); if ($2 ne "") { $hi = $2; $lo = $3; if ($lo > $hi) { $temp = $lo; $lo = $hi ; $hi = $temp;} } return ($addr,$hi,$lo); } #: prs_regdump #: ----------- #: Convert output of regdump into a hash, with register as key #: and and register value as value. #: IN: $_[0] : string containing output of regdump, #: IN: $_[1] : reference to a hash to store into. #: hash can be non-empty. Existing keys will #: be replaced only if a conflict occurs. #: OUT: return count of registers added to hash. sub prs_regdump { my $in = $_[0]; my $href = $_[1]; my $ret = 0; my @list = split ("\n",$in); foreach my $line (@list) { if ($line !~ /^\[/) {next} #ignore field lines, we only want full regs. if (not $line =~ /^\[\s*(?:0x)*([0-9a-fA-F]+)/) {next} my $reg = hex($1); my $key = sprintf "%3.3x",$reg; $key = "\L$key"; my @words = split (" ",$line); my $val = hex($words[-2]); $href->{$key}=$val; # print "$1: $reg : $key : $href->{$key}\n"; $ret++; } return $ret; } 1; #Needed at EOF so use/require/do don't report an error.