80b158ba27
MFC after: 1 week
1595 lines
44 KiB
C
1595 lines
44 KiB
C
/**************************************************************************
|
|
|
|
Copyright (c) 2007-2009, Chelsio Inc.
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
3. Neither the name of the Chelsio Corporation nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
***************************************************************************/
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <sys/param.h>
|
|
#include <sys/time.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include <net/if.h>
|
|
#include <net/if_var.h>
|
|
#include <net/if_types.h>
|
|
#include <sys/endian.h>
|
|
|
|
#define NMTUS 16
|
|
#define TCB_SIZE 128
|
|
#define TCB_WORDS (TCB_SIZE / 4)
|
|
#define PROTO_SRAM_LINES 128
|
|
#define PROTO_SRAM_LINE_BITS 132
|
|
#define PROTO_SRAM_LINE_NIBBLES (132 / 4)
|
|
#define PROTO_SRAM_SIZE (PROTO_SRAM_LINE_NIBBLES * PROTO_SRAM_LINES / 2)
|
|
#define PROTO_SRAM_EEPROM_ADDR 4096
|
|
|
|
#include <cxgb_ioctl.h>
|
|
#include <common/cxgb_regs.h>
|
|
#include "version.h"
|
|
|
|
struct reg_info {
|
|
const char *name;
|
|
uint16_t addr;
|
|
uint16_t len;
|
|
};
|
|
|
|
|
|
#include "reg_defs.c"
|
|
#if defined(CONFIG_T3_REGS)
|
|
# include "reg_defs_t3.c"
|
|
# include "reg_defs_t3b.c"
|
|
# include "reg_defs_t3c.c"
|
|
#endif
|
|
|
|
static const char *progname;
|
|
|
|
static void
|
|
usage(FILE *fp)
|
|
{
|
|
fprintf(fp, "Usage: %s <interface> [operation]\n", progname);
|
|
fprintf(fp,
|
|
"\tclearstats clear MAC statistics\n"
|
|
"\tcontext <type> <id> show an SGE context\n"
|
|
"\tdesc <qset> <queue> <idx> [<cnt>] dump SGE descriptors\n"
|
|
"\tioqs dump uP IOQs\n"
|
|
"\tla dump uP logic analyzer info\n"
|
|
"\tloadboot <boot image> download boot image\n"
|
|
"\tloadfw <FW image> download firmware\n"
|
|
"\tmdio <phy_addr> <mmd_addr>\n"
|
|
"\t <reg_addr> [<val>] read/write MDIO register\n"
|
|
"\tmemdump cm|tx|rx <addr> <len> dump a mem range\n"
|
|
"\tmeminfo show memory info\n"
|
|
"\tmtus [<mtu0>...<mtuN>] read/write MTU table\n"
|
|
"\tpktsched port <idx> <min> <max> set TX port scheduler params\n"
|
|
"\tpktsched tunnelq <idx> <max>\n"
|
|
"\t <binding> set TX tunnelq scheduler params\n"
|
|
"\tpktsched tx <idx>\n"
|
|
"\t [<param> <val>] ... set Tx HW scheduler\n"
|
|
"\tpm [<TX page spec> <RX page spec>] read/write PM config\n"
|
|
"\tproto read proto SRAM\n"
|
|
"\tqset read qset parameters\n"
|
|
"\tqsets read # of qsets\n"
|
|
"\treg <address>[=<val>] read/write register\n"
|
|
"\tregdump [<module>] dump registers\n"
|
|
"\ttcamdump <address> <count> show TCAM contents\n"
|
|
"\ttcb <index> read TCB\n"
|
|
"\ttrace tx|rx|all on|off [not]\n"
|
|
"\t [<param> <val>[:<mask>]] ... write trace parameters\n"
|
|
);
|
|
exit(fp == stderr ? 1 : 0);
|
|
}
|
|
|
|
static int
|
|
doit(const char *iff_name, unsigned long cmd, void *data)
|
|
{
|
|
static int fd = 0;
|
|
|
|
if (fd == 0) {
|
|
char buf[64];
|
|
snprintf(buf, 64, "/dev/%s", iff_name);
|
|
|
|
if ((fd = open(buf, O_RDWR)) < 0)
|
|
return -1;
|
|
}
|
|
|
|
return ioctl(fd, cmd, data) < 0 ? -1 : 0;
|
|
}
|
|
|
|
static int
|
|
get_int_arg(const char *s, uint32_t *valp)
|
|
{
|
|
char *p;
|
|
|
|
*valp = strtoul(s, &p, 0);
|
|
if (*p) {
|
|
warnx("bad parameter \"%s\"", s);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t
|
|
read_reg(const char *iff_name, uint32_t addr)
|
|
{
|
|
struct ch_reg reg;
|
|
|
|
reg.addr = addr;
|
|
|
|
if (doit(iff_name, CHELSIO_GETREG, ®) < 0)
|
|
err(1, "register read");
|
|
return reg.val;
|
|
}
|
|
|
|
static void
|
|
write_reg(const char *iff_name, uint32_t addr, uint32_t val)
|
|
{
|
|
struct ch_reg ch_reg;
|
|
|
|
ch_reg.addr = addr;
|
|
ch_reg.val = val;
|
|
|
|
if (doit(iff_name, CHELSIO_SETREG, &ch_reg) < 0)
|
|
err(1, "register write");
|
|
}
|
|
|
|
static int
|
|
register_io(int argc, char *argv[], int start_arg,
|
|
const char *iff_name)
|
|
{
|
|
char *p;
|
|
uint32_t addr, val = 0, w = 0;
|
|
|
|
if (argc != start_arg + 1) return -1;
|
|
|
|
addr = strtoul(argv[start_arg], &p, 0);
|
|
if (p == argv[start_arg]) return -1;
|
|
if (*p == '=' && p[1]) {
|
|
val = strtoul(p + 1, &p, 0);
|
|
w = 1;
|
|
}
|
|
if (*p) {
|
|
warnx("bad parameter \"%s\"", argv[start_arg]);
|
|
return -1;
|
|
}
|
|
|
|
if (w)
|
|
write_reg(iff_name, addr, val);
|
|
else {
|
|
val = read_reg(iff_name, addr);
|
|
printf("%#x [%u]\n", val, val);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
mdio_io(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
struct ch_mii_data p;
|
|
unsigned int cmd, phy_addr, reg, mmd, val;
|
|
|
|
if (argc == start_arg + 3)
|
|
cmd = CHELSIO_GET_MIIREG;
|
|
else if (argc == start_arg + 4)
|
|
cmd = CHELSIO_SET_MIIREG;
|
|
else
|
|
return -1;
|
|
|
|
if (get_int_arg(argv[start_arg], &phy_addr) ||
|
|
get_int_arg(argv[start_arg + 1], &mmd) ||
|
|
get_int_arg(argv[start_arg + 2], ®) ||
|
|
(cmd == CHELSIO_SET_MIIREG && get_int_arg(argv[start_arg + 3], &val)))
|
|
return -1;
|
|
|
|
p.phy_id = phy_addr | (mmd << 8);
|
|
p.reg_num = reg;
|
|
p.val_in = val;
|
|
|
|
if (doit(iff_name, cmd, &p) < 0)
|
|
err(1, "MDIO %s", cmd == CHELSIO_GET_MIIREG ? "read" : "write");
|
|
if (cmd == CHELSIO_GET_MIIREG)
|
|
printf("%#x [%u]\n", p.val_out, p.val_out);
|
|
return 0;
|
|
}
|
|
|
|
static inline
|
|
uint32_t xtract(uint32_t val, int shift, int len)
|
|
{
|
|
return (val >> shift) & ((1 << len) - 1);
|
|
}
|
|
|
|
static int
|
|
dump_block_regs(const struct reg_info *reg_array, uint32_t *regs)
|
|
{
|
|
uint32_t reg_val = 0; // silence compiler warning
|
|
|
|
for ( ; reg_array->name; ++reg_array)
|
|
if (!reg_array->len) {
|
|
reg_val = regs[reg_array->addr / 4];
|
|
printf("[%#5x] %-40s %#-10x [%u]\n", reg_array->addr,
|
|
reg_array->name, reg_val, reg_val);
|
|
} else {
|
|
uint32_t v = xtract(reg_val, reg_array->addr,
|
|
reg_array->len);
|
|
|
|
printf(" %-40s %#-10x [%u]\n", reg_array->name,
|
|
v, v);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
dump_regs_t2(int argc, char *argv[], int start_arg, uint32_t *regs)
|
|
{
|
|
int match = 0;
|
|
char *block_name = NULL;
|
|
|
|
if (argc == start_arg + 1)
|
|
block_name = argv[start_arg];
|
|
else if (argc != start_arg)
|
|
return -1;
|
|
|
|
if (!block_name || !strcmp(block_name, "sge"))
|
|
match += dump_block_regs(sge_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mc3"))
|
|
match += dump_block_regs(mc3_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mc4"))
|
|
match += dump_block_regs(mc4_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "tpi"))
|
|
match += dump_block_regs(tpi_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "tp"))
|
|
match += dump_block_regs(tp_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "rat"))
|
|
match += dump_block_regs(rat_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "cspi"))
|
|
match += dump_block_regs(cspi_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "espi"))
|
|
match += dump_block_regs(espi_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "ulp"))
|
|
match += dump_block_regs(ulp_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pl"))
|
|
match += dump_block_regs(pl_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mc5"))
|
|
match += dump_block_regs(mc5_regs, regs);
|
|
if (!match)
|
|
errx(1, "unknown block \"%s\"", block_name);
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_T3_REGS)
|
|
static int
|
|
dump_regs_t3(int argc, char *argv[], int start_arg, uint32_t *regs, int is_pcie)
|
|
{
|
|
int match = 0;
|
|
char *block_name = NULL;
|
|
|
|
if (argc == start_arg + 1)
|
|
block_name = argv[start_arg];
|
|
else if (argc != start_arg)
|
|
return -1;
|
|
|
|
if (!block_name || !strcmp(block_name, "sge"))
|
|
match += dump_block_regs(sge3_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pci"))
|
|
match += dump_block_regs(is_pcie ? pcie0_regs : pcix1_regs,
|
|
regs);
|
|
if (!block_name || !strcmp(block_name, "t3dbg"))
|
|
match += dump_block_regs(t3dbg_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmrx"))
|
|
match += dump_block_regs(mc7_pmrx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmtx"))
|
|
match += dump_block_regs(mc7_pmtx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "cm"))
|
|
match += dump_block_regs(mc7_cm_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "cim"))
|
|
match += dump_block_regs(cim_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "tp"))
|
|
match += dump_block_regs(tp1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "ulp_rx"))
|
|
match += dump_block_regs(ulp2_rx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "ulp_tx"))
|
|
match += dump_block_regs(ulp2_tx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmrx"))
|
|
match += dump_block_regs(pm1_rx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmtx"))
|
|
match += dump_block_regs(pm1_tx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mps"))
|
|
match += dump_block_regs(mps0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "cplsw"))
|
|
match += dump_block_regs(cpl_switch_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "smb"))
|
|
match += dump_block_regs(smb0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "i2c"))
|
|
match += dump_block_regs(i2cm0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mi1"))
|
|
match += dump_block_regs(mi1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "sf"))
|
|
match += dump_block_regs(sf1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pl"))
|
|
match += dump_block_regs(pl3_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mc5"))
|
|
match += dump_block_regs(mc5a_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "xgmac0"))
|
|
match += dump_block_regs(xgmac0_0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "xgmac1"))
|
|
match += dump_block_regs(xgmac0_1_regs, regs);
|
|
if (!match)
|
|
errx(1, "unknown block \"%s\"", block_name);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
dump_regs_t3b(int argc, char *argv[], int start_arg, uint32_t *regs,
|
|
int is_pcie)
|
|
{
|
|
int match = 0;
|
|
char *block_name = NULL;
|
|
|
|
if (argc == start_arg + 1)
|
|
block_name = argv[start_arg];
|
|
else if (argc != start_arg)
|
|
return -1;
|
|
|
|
if (!block_name || !strcmp(block_name, "sge"))
|
|
match += dump_block_regs(t3b_sge3_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pci"))
|
|
match += dump_block_regs(is_pcie ? t3b_pcie0_regs :
|
|
t3b_pcix1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "t3dbg"))
|
|
match += dump_block_regs(t3b_t3dbg_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmrx"))
|
|
match += dump_block_regs(t3b_mc7_pmrx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmtx"))
|
|
match += dump_block_regs(t3b_mc7_pmtx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "cm"))
|
|
match += dump_block_regs(t3b_mc7_cm_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "cim"))
|
|
match += dump_block_regs(t3b_cim_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "tp"))
|
|
match += dump_block_regs(t3b_tp1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "ulp_rx"))
|
|
match += dump_block_regs(t3b_ulp2_rx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "ulp_tx"))
|
|
match += dump_block_regs(t3b_ulp2_tx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmrx"))
|
|
match += dump_block_regs(t3b_pm1_rx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmtx"))
|
|
match += dump_block_regs(t3b_pm1_tx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mps"))
|
|
match += dump_block_regs(t3b_mps0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "cplsw"))
|
|
match += dump_block_regs(t3b_cpl_switch_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "smb"))
|
|
match += dump_block_regs(t3b_smb0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "i2c"))
|
|
match += dump_block_regs(t3b_i2cm0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mi1"))
|
|
match += dump_block_regs(t3b_mi1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "sf"))
|
|
match += dump_block_regs(t3b_sf1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pl"))
|
|
match += dump_block_regs(t3b_pl3_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mc5"))
|
|
match += dump_block_regs(t3b_mc5a_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "xgmac0"))
|
|
match += dump_block_regs(t3b_xgmac0_0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "xgmac1"))
|
|
match += dump_block_regs(t3b_xgmac0_1_regs, regs);
|
|
if (!match)
|
|
errx(1, "unknown block \"%s\"", block_name);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
dump_regs_t3c(int argc, char *argv[], int start_arg, uint32_t *regs,
|
|
int is_pcie)
|
|
{
|
|
int match = 0;
|
|
char *block_name = NULL;
|
|
|
|
if (argc == start_arg + 1)
|
|
block_name = argv[start_arg];
|
|
else if (argc != start_arg)
|
|
return -1;
|
|
|
|
if (!block_name || !strcmp(block_name, "sge"))
|
|
match += dump_block_regs(t3c_sge3_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pci"))
|
|
match += dump_block_regs(is_pcie ? t3c_pcie0_regs :
|
|
t3c_pcix1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "t3dbg"))
|
|
match += dump_block_regs(t3c_t3dbg_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmrx"))
|
|
match += dump_block_regs(t3c_mc7_pmrx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmtx"))
|
|
match += dump_block_regs(t3c_mc7_pmtx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "cm"))
|
|
match += dump_block_regs(t3c_mc7_cm_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "cim"))
|
|
match += dump_block_regs(t3c_cim_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "tp"))
|
|
match += dump_block_regs(t3c_tp1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "ulp_rx"))
|
|
match += dump_block_regs(t3c_ulp2_rx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "ulp_tx"))
|
|
match += dump_block_regs(t3c_ulp2_tx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmrx"))
|
|
match += dump_block_regs(t3c_pm1_rx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pmtx"))
|
|
match += dump_block_regs(t3c_pm1_tx_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mps"))
|
|
match += dump_block_regs(t3c_mps0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "cplsw"))
|
|
match += dump_block_regs(t3c_cpl_switch_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "smb"))
|
|
match += dump_block_regs(t3c_smb0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "i2c"))
|
|
match += dump_block_regs(t3c_i2cm0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mi1"))
|
|
match += dump_block_regs(t3c_mi1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "sf"))
|
|
match += dump_block_regs(t3c_sf1_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "pl"))
|
|
match += dump_block_regs(t3c_pl3_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "mc5"))
|
|
match += dump_block_regs(t3c_mc5a_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "xgmac0"))
|
|
match += dump_block_regs(t3c_xgmac0_0_regs, regs);
|
|
if (!block_name || !strcmp(block_name, "xgmac1"))
|
|
match += dump_block_regs(t3c_xgmac0_1_regs, regs);
|
|
if (!match)
|
|
errx(1, "unknown block \"%s\"", block_name);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
dump_regs(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
int vers, revision, is_pcie;
|
|
struct ch_ifconf_regs regs;
|
|
|
|
regs.len = REGDUMP_SIZE;
|
|
|
|
/* XXX: This is never freed. Looks like we don't care. */
|
|
if ((regs.data = malloc(regs.len)) == NULL)
|
|
err(1, "can't malloc");
|
|
|
|
if (doit(iff_name, CHELSIO_IFCONF_GETREGS, ®s))
|
|
err(1, "can't read registers");
|
|
|
|
vers = regs.version & 0x3ff;
|
|
revision = (regs.version >> 10) & 0x3f;
|
|
is_pcie = (regs.version & 0x80000000) != 0;
|
|
|
|
if (vers <= 2)
|
|
return dump_regs_t2(argc, argv, start_arg, (uint32_t *)regs.data);
|
|
#if defined(CONFIG_T3_REGS)
|
|
if (vers == 3) {
|
|
if (revision == 0)
|
|
return dump_regs_t3(argc, argv, start_arg,
|
|
(uint32_t *)regs.data, is_pcie);
|
|
if (revision == 2 || revision == 3)
|
|
return dump_regs_t3b(argc, argv, start_arg,
|
|
(uint32_t *)regs.data, is_pcie);
|
|
if (revision == 4)
|
|
return dump_regs_t3c(argc, argv, start_arg,
|
|
(uint32_t *)regs.data, is_pcie);
|
|
}
|
|
#endif
|
|
errx(1, "unknown card type %d.%d", vers, revision);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
t3_meminfo(const uint32_t *regs)
|
|
{
|
|
enum {
|
|
SG_EGR_CNTX_BADDR = 0x58,
|
|
SG_CQ_CONTEXT_BADDR = 0x6c,
|
|
CIM_SDRAM_BASE_ADDR = 0x28c,
|
|
CIM_SDRAM_ADDR_SIZE = 0x290,
|
|
TP_CMM_MM_BASE = 0x314,
|
|
TP_CMM_TIMER_BASE = 0x318,
|
|
TP_CMM_MM_RX_FLST_BASE = 0x460,
|
|
TP_CMM_MM_TX_FLST_BASE = 0x464,
|
|
TP_CMM_MM_PS_FLST_BASE = 0x468,
|
|
ULPRX_ISCSI_LLIMIT = 0x50c,
|
|
ULPRX_ISCSI_ULIMIT = 0x510,
|
|
ULPRX_TDDP_LLIMIT = 0x51c,
|
|
ULPRX_TDDP_ULIMIT = 0x520,
|
|
ULPRX_STAG_LLIMIT = 0x52c,
|
|
ULPRX_STAG_ULIMIT = 0x530,
|
|
ULPRX_RQ_LLIMIT = 0x534,
|
|
ULPRX_RQ_ULIMIT = 0x538,
|
|
ULPRX_PBL_LLIMIT = 0x53c,
|
|
ULPRX_PBL_ULIMIT = 0x540,
|
|
};
|
|
|
|
unsigned int egr_cntxt = regs[SG_EGR_CNTX_BADDR / 4],
|
|
cq_cntxt = regs[SG_CQ_CONTEXT_BADDR / 4],
|
|
timers = regs[TP_CMM_TIMER_BASE / 4] & 0xfffffff,
|
|
pstructs = regs[TP_CMM_MM_BASE / 4],
|
|
pstruct_fl = regs[TP_CMM_MM_PS_FLST_BASE / 4],
|
|
rx_fl = regs[TP_CMM_MM_RX_FLST_BASE / 4],
|
|
tx_fl = regs[TP_CMM_MM_TX_FLST_BASE / 4],
|
|
cim_base = regs[CIM_SDRAM_BASE_ADDR / 4],
|
|
cim_size = regs[CIM_SDRAM_ADDR_SIZE / 4];
|
|
unsigned int iscsi_ll = regs[ULPRX_ISCSI_LLIMIT / 4],
|
|
iscsi_ul = regs[ULPRX_ISCSI_ULIMIT / 4],
|
|
tddp_ll = regs[ULPRX_TDDP_LLIMIT / 4],
|
|
tddp_ul = regs[ULPRX_TDDP_ULIMIT / 4],
|
|
stag_ll = regs[ULPRX_STAG_LLIMIT / 4],
|
|
stag_ul = regs[ULPRX_STAG_ULIMIT / 4],
|
|
rq_ll = regs[ULPRX_RQ_LLIMIT / 4],
|
|
rq_ul = regs[ULPRX_RQ_ULIMIT / 4],
|
|
pbl_ll = regs[ULPRX_PBL_LLIMIT / 4],
|
|
pbl_ul = regs[ULPRX_PBL_ULIMIT / 4];
|
|
|
|
printf("CM memory map:\n");
|
|
printf(" TCB region: 0x%08x - 0x%08x [%u]\n", 0, egr_cntxt - 1,
|
|
egr_cntxt);
|
|
printf(" Egress contexts: 0x%08x - 0x%08x [%u]\n", egr_cntxt,
|
|
cq_cntxt - 1, cq_cntxt - egr_cntxt);
|
|
printf(" CQ contexts: 0x%08x - 0x%08x [%u]\n", cq_cntxt,
|
|
timers - 1, timers - cq_cntxt);
|
|
printf(" Timers: 0x%08x - 0x%08x [%u]\n", timers,
|
|
pstructs - 1, pstructs - timers);
|
|
printf(" Pstructs: 0x%08x - 0x%08x [%u]\n", pstructs,
|
|
pstruct_fl - 1, pstruct_fl - pstructs);
|
|
printf(" Pstruct FL: 0x%08x - 0x%08x [%u]\n", pstruct_fl,
|
|
rx_fl - 1, rx_fl - pstruct_fl);
|
|
printf(" Rx FL: 0x%08x - 0x%08x [%u]\n", rx_fl, tx_fl - 1,
|
|
tx_fl - rx_fl);
|
|
printf(" Tx FL: 0x%08x - 0x%08x [%u]\n", tx_fl, cim_base - 1,
|
|
cim_base - tx_fl);
|
|
printf(" uP RAM: 0x%08x - 0x%08x [%u]\n", cim_base,
|
|
cim_base + cim_size - 1, cim_size);
|
|
|
|
printf("\nPMRX memory map:\n");
|
|
printf(" iSCSI region: 0x%08x - 0x%08x [%u]\n", iscsi_ll, iscsi_ul,
|
|
iscsi_ul - iscsi_ll + 1);
|
|
printf(" TCP DDP region: 0x%08x - 0x%08x [%u]\n", tddp_ll, tddp_ul,
|
|
tddp_ul - tddp_ll + 1);
|
|
printf(" TPT region: 0x%08x - 0x%08x [%u]\n", stag_ll, stag_ul,
|
|
stag_ul - stag_ll + 1);
|
|
printf(" RQ region: 0x%08x - 0x%08x [%u]\n", rq_ll, rq_ul,
|
|
rq_ul - rq_ll + 1);
|
|
printf(" PBL region: 0x%08x - 0x%08x [%u]\n", pbl_ll, pbl_ul,
|
|
pbl_ul - pbl_ll + 1);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
meminfo(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
int vers;
|
|
struct ch_ifconf_regs regs;
|
|
|
|
(void) argc;
|
|
(void) argv;
|
|
(void) start_arg;
|
|
|
|
regs.len = REGDUMP_SIZE;
|
|
if ((regs.data = malloc(regs.len)) == NULL)
|
|
err(1, "can't malloc");
|
|
|
|
if (doit(iff_name, CHELSIO_IFCONF_GETREGS, ®s))
|
|
err(1, "can't read registers");
|
|
|
|
vers = regs.version & 0x3ff;
|
|
if (vers == 3)
|
|
return t3_meminfo((uint32_t *)regs.data);
|
|
|
|
errx(1, "unknown card type %d", vers);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
mtu_tab_op(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
struct ch_mtus m;
|
|
unsigned int i;
|
|
|
|
if (argc == start_arg) {
|
|
if (doit(iff_name, CHELSIO_GETMTUTAB, &m) < 0)
|
|
err(1, "get MTU table");
|
|
for (i = 0; i < m.nmtus; ++i)
|
|
printf("%u ", m.mtus[i]);
|
|
printf("\n");
|
|
} else if (argc <= start_arg + NMTUS) {
|
|
m.nmtus = argc - start_arg;
|
|
|
|
for (i = 0; i < m.nmtus; ++i) {
|
|
char *p;
|
|
unsigned long mt = strtoul(argv[start_arg + i], &p, 0);
|
|
|
|
if (*p || mt > 9600) {
|
|
warnx("bad parameter \"%s\"",
|
|
argv[start_arg + i]);
|
|
return -1;
|
|
}
|
|
if (i && mt < m.mtus[i - 1])
|
|
errx(1, "MTUs must be in ascending order");
|
|
m.mtus[i] = mt;
|
|
}
|
|
if (doit(iff_name, CHELSIO_SETMTUTAB, &m) < 0)
|
|
err(1, "set MTU table");
|
|
} else
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CHELSIO_INTERNAL
|
|
static void
|
|
show_egress_cntxt(uint32_t data[])
|
|
{
|
|
printf("credits: %u\n", data[0] & 0x7fff);
|
|
printf("GTS: %u\n", (data[0] >> 15) & 1);
|
|
printf("index: %u\n", data[0] >> 16);
|
|
printf("queue size: %u\n", data[1] & 0xffff);
|
|
printf("base address: 0x%" PRIx64 "\n",
|
|
((data[1] >> 16) | ((uint64_t)data[2] << 16) |
|
|
(((uint64_t)data[3] & 0xf) << 48)) << 12);
|
|
printf("rsp queue #: %u\n", (data[3] >> 4) & 7);
|
|
printf("cmd queue #: %u\n", (data[3] >> 7) & 1);
|
|
printf("TUN: %u\n", (data[3] >> 8) & 1);
|
|
printf("TOE: %u\n", (data[3] >> 9) & 1);
|
|
printf("generation: %u\n", (data[3] >> 10) & 1);
|
|
printf("uP token: %u\n", (data[3] >> 11) & 0xfffff);
|
|
printf("valid: %u\n", (data[3] >> 31) & 1);
|
|
}
|
|
|
|
static void
|
|
show_fl_cntxt(uint32_t data[])
|
|
{
|
|
printf("base address: 0x%" PRIx64 "\n",
|
|
((uint64_t)data[0] | ((uint64_t)data[1] & 0xfffff) << 32) << 12);
|
|
printf("index: %u\n", (data[1] >> 20) | ((data[2] & 0xf) << 12));
|
|
printf("queue size: %u\n", (data[2] >> 4) & 0xffff);
|
|
printf("generation: %u\n", (data[2] >> 20) & 1);
|
|
printf("entry size: %u\n",
|
|
(data[2] >> 21) | (data[3] & 0x1fffff) << 11);
|
|
printf("congest thr: %u\n", (data[3] >> 21) & 0x3ff);
|
|
printf("GTS: %u\n", (data[3] >> 31) & 1);
|
|
}
|
|
|
|
static void
|
|
show_response_cntxt(uint32_t data[])
|
|
{
|
|
printf("index: %u\n", data[0] & 0xffff);
|
|
printf("size: %u\n", data[0] >> 16);
|
|
printf("base address: 0x%" PRIx64 "\n",
|
|
((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12);
|
|
printf("MSI-X/RspQ: %u\n", (data[2] >> 20) & 0x3f);
|
|
printf("intr enable: %u\n", (data[2] >> 26) & 1);
|
|
printf("intr armed: %u\n", (data[2] >> 27) & 1);
|
|
printf("generation: %u\n", (data[2] >> 28) & 1);
|
|
printf("CQ mode: %u\n", (data[2] >> 31) & 1);
|
|
printf("FL threshold: %u\n", data[3]);
|
|
}
|
|
|
|
static void
|
|
show_cq_cntxt(uint32_t data[])
|
|
{
|
|
printf("index: %u\n", data[0] & 0xffff);
|
|
printf("size: %u\n", data[0] >> 16);
|
|
printf("base address: 0x%" PRIx64 "\n",
|
|
((uint64_t)data[1] | ((uint64_t)data[2] & 0xfffff) << 32) << 12);
|
|
printf("rsp queue #: %u\n", (data[2] >> 20) & 0x3f);
|
|
printf("AN: %u\n", (data[2] >> 26) & 1);
|
|
printf("armed: %u\n", (data[2] >> 27) & 1);
|
|
printf("ANS: %u\n", (data[2] >> 28) & 1);
|
|
printf("generation: %u\n", (data[2] >> 29) & 1);
|
|
printf("overflow mode: %u\n", (data[2] >> 31) & 1);
|
|
printf("credits: %u\n", data[3] & 0xffff);
|
|
printf("credit threshold: %u\n", data[3] >> 16);
|
|
}
|
|
|
|
static int
|
|
get_sge_context(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
struct ch_cntxt ctx;
|
|
|
|
if (argc != start_arg + 2) return -1;
|
|
|
|
if (!strcmp(argv[start_arg], "egress"))
|
|
ctx.cntxt_type = CNTXT_TYPE_EGRESS;
|
|
else if (!strcmp(argv[start_arg], "fl"))
|
|
ctx.cntxt_type = CNTXT_TYPE_FL;
|
|
else if (!strcmp(argv[start_arg], "response"))
|
|
ctx.cntxt_type = CNTXT_TYPE_RSP;
|
|
else if (!strcmp(argv[start_arg], "cq"))
|
|
ctx.cntxt_type = CNTXT_TYPE_CQ;
|
|
else {
|
|
warnx("unknown context type \"%s\"; known types are egress, "
|
|
"fl, cq, and response", argv[start_arg]);
|
|
return -1;
|
|
}
|
|
|
|
if (get_int_arg(argv[start_arg + 1], &ctx.cntxt_id))
|
|
return -1;
|
|
|
|
if (doit(iff_name, CHELSIO_GET_SGE_CONTEXT, &ctx) < 0)
|
|
err(1, "get SGE context");
|
|
|
|
if (!strcmp(argv[start_arg], "egress"))
|
|
show_egress_cntxt(ctx.data);
|
|
else if (!strcmp(argv[start_arg], "fl"))
|
|
show_fl_cntxt(ctx.data);
|
|
else if (!strcmp(argv[start_arg], "response"))
|
|
show_response_cntxt(ctx.data);
|
|
else if (!strcmp(argv[start_arg], "cq"))
|
|
show_cq_cntxt(ctx.data);
|
|
return 0;
|
|
}
|
|
|
|
#define ntohll(x) be64toh((x))
|
|
|
|
static int
|
|
get_sge_desc(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
uint64_t *p, wr_hdr;
|
|
unsigned int n = 1, qset, qnum;
|
|
struct ch_desc desc;
|
|
|
|
if (argc != start_arg + 3 && argc != start_arg + 4)
|
|
return -1;
|
|
|
|
if (get_int_arg(argv[start_arg], &qset) ||
|
|
get_int_arg(argv[start_arg + 1], &qnum) ||
|
|
get_int_arg(argv[start_arg + 2], &desc.idx))
|
|
return -1;
|
|
|
|
if (argc == start_arg + 4 && get_int_arg(argv[start_arg + 3], &n))
|
|
return -1;
|
|
|
|
if (qnum > 5)
|
|
errx(1, "invalid queue number %d, range is 0..5", qnum);
|
|
|
|
desc.queue_num = qset * 6 + qnum;
|
|
|
|
for (; n--; desc.idx++) {
|
|
if (doit(iff_name, CHELSIO_GET_SGE_DESC, &desc) < 0)
|
|
err(1, "get SGE descriptor");
|
|
|
|
p = (uint64_t *)desc.data;
|
|
wr_hdr = ntohll(*p);
|
|
printf("Descriptor %u: cmd %u, TID %u, %s%s%s%s%u flits\n",
|
|
desc.idx, (unsigned int)(wr_hdr >> 56),
|
|
((unsigned int)wr_hdr >> 8) & 0xfffff,
|
|
((wr_hdr >> 55) & 1) ? "SOP, " : "",
|
|
((wr_hdr >> 54) & 1) ? "EOP, " : "",
|
|
((wr_hdr >> 53) & 1) ? "COMPL, " : "",
|
|
((wr_hdr >> 52) & 1) ? "SGL, " : "",
|
|
(unsigned int)wr_hdr & 0xff);
|
|
|
|
for (; desc.size; p++, desc.size -= sizeof(uint64_t))
|
|
printf("%016" PRIx64 "%c", ntohll(*p),
|
|
desc.size % 32 == 8 ? '\n' : ' ');
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
get_tcb2(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
uint64_t *d;
|
|
unsigned int i;
|
|
unsigned int tcb_idx;
|
|
struct ch_mem_range mr;
|
|
|
|
if (argc != start_arg + 1)
|
|
return -1;
|
|
|
|
if (get_int_arg(argv[start_arg], &tcb_idx))
|
|
return -1;
|
|
|
|
mr.buf = calloc(1, TCB_SIZE);
|
|
if (!mr.buf)
|
|
err(1, "get TCB");
|
|
|
|
mr.mem_id = MEM_CM;
|
|
mr.addr = tcb_idx * TCB_SIZE;
|
|
mr.len = TCB_SIZE;
|
|
|
|
if (doit(iff_name, CHELSIO_GET_MEM, &mr) < 0)
|
|
err(1, "get TCB");
|
|
|
|
for (d = (uint64_t *)mr.buf, i = 0; i < TCB_SIZE / 32; i++) {
|
|
printf("%2u:", i);
|
|
printf(" %08x %08x %08x %08x", (uint32_t)d[1],
|
|
(uint32_t)(d[1] >> 32), (uint32_t)d[0],
|
|
(uint32_t)(d[0] >> 32));
|
|
d += 2;
|
|
printf(" %08x %08x %08x %08x\n", (uint32_t)d[1],
|
|
(uint32_t)(d[1] >> 32), (uint32_t)d[0],
|
|
(uint32_t)(d[0] >> 32));
|
|
d += 2;
|
|
}
|
|
free(mr.buf);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
get_pm_page_spec(const char *s, unsigned int *page_size,
|
|
unsigned int *num_pages)
|
|
{
|
|
char *p;
|
|
unsigned long val;
|
|
|
|
val = strtoul(s, &p, 0);
|
|
if (p == s) return -1;
|
|
if (*p == 'x' && p[1]) {
|
|
*num_pages = val;
|
|
*page_size = strtoul(p + 1, &p, 0);
|
|
} else {
|
|
*num_pages = -1;
|
|
*page_size = val;
|
|
}
|
|
*page_size <<= 10; // KB -> bytes
|
|
return *p;
|
|
}
|
|
|
|
static int
|
|
conf_pm(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
struct ch_pm pm;
|
|
|
|
if (argc == start_arg) {
|
|
if (doit(iff_name, CHELSIO_GET_PM, &pm) < 0)
|
|
err(1, "read pm config");
|
|
printf("%ux%uKB TX pages, %ux%uKB RX pages, %uKB total memory\n",
|
|
pm.tx_num_pg, pm.tx_pg_sz >> 10, pm.rx_num_pg,
|
|
pm.rx_pg_sz >> 10, pm.pm_total >> 10);
|
|
return 0;
|
|
}
|
|
|
|
if (argc != start_arg + 2) return -1;
|
|
|
|
if (get_pm_page_spec(argv[start_arg], &pm.tx_pg_sz, &pm.tx_num_pg)) {
|
|
warnx("bad parameter \"%s\"", argv[start_arg]);
|
|
return -1;
|
|
}
|
|
if (get_pm_page_spec(argv[start_arg + 1], &pm.rx_pg_sz,
|
|
&pm.rx_num_pg)) {
|
|
warnx("bad parameter \"%s\"", argv[start_arg + 1]);
|
|
return -1;
|
|
}
|
|
if (doit(iff_name, CHELSIO_SET_PM, &pm) < 0)
|
|
err(1, "pm config");
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CHELSIO_INTERNAL
|
|
static int
|
|
dump_tcam(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
unsigned int nwords;
|
|
struct ch_tcam_word op;
|
|
|
|
if (argc != start_arg + 2) return -1;
|
|
|
|
if (get_int_arg(argv[start_arg], &op.addr) ||
|
|
get_int_arg(argv[start_arg + 1], &nwords))
|
|
return -1;
|
|
|
|
while (nwords--) {
|
|
if (doit(iff_name, CHELSIO_READ_TCAM_WORD, &op) < 0)
|
|
err(1, "tcam dump");
|
|
|
|
printf("0x%08x: 0x%02x 0x%08x 0x%08x\n", op.addr,
|
|
op.buf[0] & 0xff, op.buf[1], op.buf[2]);
|
|
op.addr++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
hexdump_8b(unsigned int start, uint64_t *data, unsigned int len)
|
|
{
|
|
int i;
|
|
|
|
while (len) {
|
|
printf("0x%08x:", start);
|
|
for (i = 0; i < 4 && len; ++i, --len)
|
|
printf(" %016llx", (unsigned long long)*data++);
|
|
printf("\n");
|
|
start += 32;
|
|
}
|
|
}
|
|
|
|
static int
|
|
dump_mc7(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
struct ch_mem_range mem;
|
|
unsigned int mem_id, addr, len;
|
|
|
|
if (argc != start_arg + 3) return -1;
|
|
|
|
if (!strcmp(argv[start_arg], "cm"))
|
|
mem_id = MEM_CM;
|
|
else if (!strcmp(argv[start_arg], "rx"))
|
|
mem_id = MEM_PMRX;
|
|
else if (!strcmp(argv[start_arg], "tx"))
|
|
mem_id = MEM_PMTX;
|
|
else
|
|
errx(1, "unknown memory \"%s\"; must be one of \"cm\", \"tx\","
|
|
" or \"rx\"", argv[start_arg]);
|
|
|
|
if (get_int_arg(argv[start_arg + 1], &addr) ||
|
|
get_int_arg(argv[start_arg + 2], &len))
|
|
return -1;
|
|
|
|
mem.buf = malloc(len);
|
|
if (!mem.buf)
|
|
err(1, "memory dump");
|
|
|
|
mem.mem_id = mem_id;
|
|
mem.addr = addr;
|
|
mem.len = len;
|
|
|
|
if (doit(iff_name, CHELSIO_GET_MEM, &mem) < 0)
|
|
err(1, "memory dump");
|
|
|
|
hexdump_8b(mem.addr, (uint64_t *)mem.buf, mem.len >> 3);
|
|
free(mem.buf);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/* Max FW size is 64K including version, +4 bytes for the checksum. */
|
|
#define MAX_FW_IMAGE_SIZE (64 * 1024)
|
|
|
|
static int
|
|
load_fw(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
int fd, len;
|
|
struct ch_mem_range op;
|
|
const char *fname = argv[start_arg];
|
|
|
|
if (argc != start_arg + 1) return -1;
|
|
|
|
fd = open(fname, O_RDONLY);
|
|
if (fd < 0)
|
|
err(1, "load firmware");
|
|
|
|
bzero(&op, sizeof(op));
|
|
op.buf = malloc(MAX_FW_IMAGE_SIZE + 1);
|
|
if (!op.buf)
|
|
err(1, "load firmware");
|
|
|
|
len = read(fd, op.buf, MAX_FW_IMAGE_SIZE + 1);
|
|
if (len < 0)
|
|
err(1, "load firmware");
|
|
if (len > MAX_FW_IMAGE_SIZE)
|
|
errx(1, "FW image too large");
|
|
|
|
op.len = len;
|
|
if (doit(iff_name, CHELSIO_LOAD_FW, &op) < 0)
|
|
err(1, "load firmware");
|
|
return 0;
|
|
}
|
|
|
|
/* Max BOOT size is 255*512 bytes including the BIOS boot ROM basic header */
|
|
#define MAX_BOOT_IMAGE_SIZE (0xff * 512)
|
|
|
|
static int
|
|
load_boot(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
int fd, len;
|
|
struct ch_mem_range op;
|
|
const char *fname = argv[start_arg];
|
|
|
|
if (argc != start_arg + 1) return -1;
|
|
|
|
fd = open(fname, O_RDONLY);
|
|
if (fd < 0)
|
|
err(1, "load boot image");
|
|
|
|
op.buf = malloc(MAX_BOOT_IMAGE_SIZE + 1);
|
|
if (!op.buf)
|
|
err(1, "load boot image");
|
|
|
|
len = read(fd, op.buf, MAX_BOOT_IMAGE_SIZE + 1);
|
|
if (len < 0)
|
|
err(1, "load boot image");
|
|
if (len > MAX_BOOT_IMAGE_SIZE)
|
|
errx(1, "boot image too large");
|
|
|
|
op.len = len;
|
|
|
|
if (doit(iff_name, CHELSIO_LOAD_BOOT, &op) < 0)
|
|
err(1, "load boot image");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
dump_proto_sram(const char *iff_name)
|
|
{
|
|
int i, j;
|
|
uint8_t buf[PROTO_SRAM_SIZE];
|
|
struct ch_eeprom ee;
|
|
uint8_t *p = buf;
|
|
|
|
bzero(buf, sizeof(buf));
|
|
ee.offset = PROTO_SRAM_EEPROM_ADDR;
|
|
ee.data = p;
|
|
ee.len = sizeof(buf);
|
|
if (doit(iff_name, CHELSIO_GET_EEPROM, &ee))
|
|
err(1, "show protocol sram");
|
|
|
|
for (i = 0; i < PROTO_SRAM_LINES; i++) {
|
|
for (j = PROTO_SRAM_LINE_NIBBLES - 1; j >= 0; j--) {
|
|
int nibble_idx = i * PROTO_SRAM_LINE_NIBBLES + j;
|
|
uint8_t nibble = p[nibble_idx / 2];
|
|
|
|
if (nibble_idx & 1)
|
|
nibble >>= 4;
|
|
else
|
|
nibble &= 0xf;
|
|
printf("%x", nibble);
|
|
}
|
|
putchar('\n');
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
proto_sram_op(int argc, char *argv[], int start_arg,
|
|
const char *iff_name)
|
|
{
|
|
(void) argv;
|
|
(void) start_arg;
|
|
|
|
if (argc == start_arg)
|
|
return dump_proto_sram(iff_name);
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
dump_qset_params(const char *iff_name)
|
|
{
|
|
struct ch_qset_params qp;
|
|
|
|
qp.qset_idx = 0;
|
|
|
|
while (doit(iff_name, CHELSIO_GET_QSET_PARAMS, &qp) == 0) {
|
|
if (!qp.qset_idx)
|
|
printf("Qset TxQ0 TxQ1 TxQ2 RspQ RxQ0 RxQ1"
|
|
" Cong Lat IRQ\n");
|
|
printf("%4u %6u %6u %6u %6u %6u %6u %5u %4u %5d\n",
|
|
qp.qnum,
|
|
qp.txq_size[0], qp.txq_size[1], qp.txq_size[2],
|
|
qp.rspq_size, qp.fl_size[0], qp.fl_size[1],
|
|
qp.cong_thres, qp.intr_lat, qp.vector);
|
|
qp.qset_idx++;
|
|
}
|
|
if (!qp.qset_idx || (errno && errno != EINVAL))
|
|
err(1, "get qset parameters");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
qset_config(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
(void) argv;
|
|
|
|
if (argc == start_arg)
|
|
return dump_qset_params(iff_name);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
qset_num_config(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
struct ch_reg reg;
|
|
|
|
(void) argv;
|
|
|
|
if (argc == start_arg) {
|
|
if (doit(iff_name, CHELSIO_GET_QSET_NUM, ®) < 0)
|
|
err(1, "get qsets");
|
|
printf("%u\n", reg.val);
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Parse a string containing an IP address with an optional network prefix.
|
|
*/
|
|
static int
|
|
parse_ipaddr(const char *s, uint32_t *addr, uint32_t *mask)
|
|
{
|
|
char *p, *slash;
|
|
struct in_addr ia;
|
|
|
|
*mask = 0xffffffffU;
|
|
slash = strchr(s, '/');
|
|
if (slash)
|
|
*slash = 0;
|
|
if (!inet_aton(s, &ia)) {
|
|
if (slash)
|
|
*slash = '/';
|
|
*addr = 0;
|
|
return -1;
|
|
}
|
|
*addr = ntohl(ia.s_addr);
|
|
if (slash) {
|
|
unsigned int prefix = strtoul(slash + 1, &p, 10);
|
|
|
|
*slash = '/';
|
|
if (p == slash + 1 || *p || prefix > 32)
|
|
return -1;
|
|
*mask <<= (32 - prefix);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Parse a string containing a value and an optional colon separated mask.
|
|
*/
|
|
static int
|
|
parse_val_mask_param(const char *s, uint32_t *val, uint32_t *mask)
|
|
{
|
|
char *p;
|
|
|
|
*mask = 0xffffffffU;
|
|
*val = strtoul(s, &p, 0);
|
|
if (p == s)
|
|
return -1;
|
|
if (*p == ':' && p[1])
|
|
*mask = strtoul(p + 1, &p, 0);
|
|
return *p ? -1 : 0;
|
|
}
|
|
|
|
static int
|
|
parse_trace_param(const char *s, uint32_t *val, uint32_t *mask)
|
|
{
|
|
return strchr(s, '.') ? parse_ipaddr(s, val, mask) :
|
|
parse_val_mask_param(s, val, mask);
|
|
}
|
|
|
|
static int
|
|
trace_config(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
uint32_t val, mask;
|
|
struct ch_trace trace;
|
|
|
|
if (argc == start_arg)
|
|
return -1;
|
|
|
|
memset(&trace, 0, sizeof(trace));
|
|
if (!strcmp(argv[start_arg], "tx"))
|
|
trace.config_tx = 1;
|
|
else if (!strcmp(argv[start_arg], "rx"))
|
|
trace.config_rx = 1;
|
|
else if (!strcmp(argv[start_arg], "all"))
|
|
trace.config_tx = trace.config_rx = 1;
|
|
else
|
|
errx(1, "bad trace filter \"%s\"; must be one of \"rx\", "
|
|
"\"tx\" or \"all\"", argv[start_arg]);
|
|
|
|
if (argc == ++start_arg)
|
|
return -1;
|
|
if (!strcmp(argv[start_arg], "on")) {
|
|
trace.trace_tx = trace.config_tx;
|
|
trace.trace_rx = trace.config_rx;
|
|
} else if (strcmp(argv[start_arg], "off"))
|
|
errx(1, "bad argument \"%s\"; must be \"on\" or \"off\"",
|
|
argv[start_arg]);
|
|
|
|
start_arg++;
|
|
if (start_arg < argc && !strcmp(argv[start_arg], "not")) {
|
|
trace.invert_match = 1;
|
|
start_arg++;
|
|
}
|
|
|
|
while (start_arg + 2 <= argc) {
|
|
int ret = parse_trace_param(argv[start_arg + 1], &val, &mask);
|
|
|
|
if (!strcmp(argv[start_arg], "interface")) {
|
|
trace.intf = val;
|
|
trace.intf_mask = mask;
|
|
} else if (!strcmp(argv[start_arg], "sip")) {
|
|
trace.sip = val;
|
|
trace.sip_mask = mask;
|
|
} else if (!strcmp(argv[start_arg], "dip")) {
|
|
trace.dip = val;
|
|
trace.dip_mask = mask;
|
|
} else if (!strcmp(argv[start_arg], "sport")) {
|
|
trace.sport = val;
|
|
trace.sport_mask = mask;
|
|
} else if (!strcmp(argv[start_arg], "dport")) {
|
|
trace.dport = val;
|
|
trace.dport_mask = mask;
|
|
} else if (!strcmp(argv[start_arg], "vlan")) {
|
|
trace.vlan = val;
|
|
trace.vlan_mask = mask;
|
|
} else if (!strcmp(argv[start_arg], "proto")) {
|
|
trace.proto = val;
|
|
trace.proto_mask = mask;
|
|
} else
|
|
errx(1, "unknown trace parameter \"%s\"\n"
|
|
"known parameters are \"interface\", \"sip\", "
|
|
"\"dip\", \"sport\", \"dport\", \"vlan\", "
|
|
"\"proto\"", argv[start_arg]);
|
|
if (ret < 0)
|
|
errx(1, "bad parameter \"%s\"", argv[start_arg + 1]);
|
|
start_arg += 2;
|
|
}
|
|
if (start_arg != argc)
|
|
errx(1, "unknown parameter \"%s\"", argv[start_arg]);
|
|
|
|
if (doit(iff_name, CHELSIO_SET_TRACE_FILTER, &trace) < 0)
|
|
err(1, "trace");
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
get_sched_param(int argc, char *argv[], int pos, unsigned int *valp)
|
|
{
|
|
if (pos + 1 >= argc)
|
|
errx(1, "missing value for %s", argv[pos]);
|
|
if (get_int_arg(argv[pos + 1], valp))
|
|
exit(1);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
tx_sched(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
struct ch_hw_sched op;
|
|
unsigned int idx, val;
|
|
|
|
if (argc < 5 || get_int_arg(argv[start_arg++], &idx))
|
|
return -1;
|
|
|
|
op.sched = idx;
|
|
op.mode = op.channel = -1;
|
|
op.kbps = op.class_ipg = op.flow_ipg = -1;
|
|
|
|
while (argc > start_arg) {
|
|
if (!strcmp(argv[start_arg], "mode")) {
|
|
if (start_arg + 1 >= argc)
|
|
errx(1, "missing value for mode");
|
|
if (!strcmp(argv[start_arg + 1], "class"))
|
|
op.mode = 0;
|
|
else if (!strcmp(argv[start_arg + 1], "flow"))
|
|
op.mode = 1;
|
|
else
|
|
errx(1, "bad mode \"%s\"", argv[start_arg + 1]);
|
|
} else if (!strcmp(argv[start_arg], "channel") &&
|
|
!get_sched_param(argc, argv, start_arg, &val))
|
|
op.channel = val;
|
|
else if (!strcmp(argv[start_arg], "rate") &&
|
|
!get_sched_param(argc, argv, start_arg, &val))
|
|
op.kbps = val;
|
|
else if (!strcmp(argv[start_arg], "ipg") &&
|
|
!get_sched_param(argc, argv, start_arg, &val))
|
|
op.class_ipg = val;
|
|
else if (!strcmp(argv[start_arg], "flowipg") &&
|
|
!get_sched_param(argc, argv, start_arg, &val))
|
|
op.flow_ipg = val;
|
|
else
|
|
errx(1, "unknown scheduler parameter \"%s\"",
|
|
argv[start_arg]);
|
|
start_arg += 2;
|
|
}
|
|
|
|
if (doit(iff_name, CHELSIO_SET_HW_SCHED, &op) < 0)
|
|
err(1, "pktsched");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
pktsched(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
struct ch_pktsched_params op;
|
|
unsigned int idx, min = -1, max, binding = -1;
|
|
|
|
if (argc < 4)
|
|
errx(1, "no scheduler specified");
|
|
|
|
if (!strcmp(argv[start_arg], "port")) {
|
|
if (argc != start_arg + 4)
|
|
return -1;
|
|
if (get_int_arg(argv[start_arg + 1], &idx) ||
|
|
get_int_arg(argv[start_arg + 2], &min) ||
|
|
get_int_arg(argv[start_arg + 3], &max))
|
|
return -1;
|
|
op.sched = 0;
|
|
} else if (!strcmp(argv[start_arg], "tunnelq")) {
|
|
if (argc != start_arg + 4)
|
|
return -1;
|
|
if (get_int_arg(argv[start_arg + 1], &idx) ||
|
|
get_int_arg(argv[start_arg + 2], &max) ||
|
|
get_int_arg(argv[start_arg + 3], &binding))
|
|
return -1;
|
|
op.sched = 1;
|
|
} else if (!strcmp(argv[start_arg], "tx"))
|
|
return tx_sched(argc, argv, start_arg + 1, iff_name);
|
|
else
|
|
errx(1, "unknown scheduler \"%s\"; must be one of \"port\", "
|
|
"\"tunnelq\" or \"tx\"", argv[start_arg]);
|
|
|
|
op.idx = idx;
|
|
op.min = min;
|
|
op.max = max;
|
|
op.binding = binding;
|
|
if (doit(iff_name, CHELSIO_SET_PKTSCHED, &op) < 0)
|
|
err(1, "pktsched");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
clear_stats(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
(void) argc;
|
|
(void) argv;
|
|
(void) start_arg;
|
|
|
|
if (doit(iff_name, CHELSIO_CLEAR_STATS, NULL) < 0)
|
|
err(1, "clearstats");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
get_up_la(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
struct ch_up_la la;
|
|
int i, idx, max_idx, entries;
|
|
|
|
(void) argc;
|
|
(void) argv;
|
|
(void) start_arg;
|
|
|
|
la.stopped = 0;
|
|
la.idx = -1;
|
|
la.bufsize = LA_BUFSIZE;
|
|
la.data = malloc(la.bufsize);
|
|
if (!la.data)
|
|
err(1, "uP_LA malloc");
|
|
|
|
if (doit(iff_name, CHELSIO_GET_UP_LA, &la) < 0)
|
|
err(1, "uP_LA");
|
|
|
|
if (la.stopped)
|
|
printf("LA is not running\n");
|
|
|
|
entries = la.bufsize / 4;
|
|
idx = (int)la.idx;
|
|
max_idx = (entries / 4) - 1;
|
|
for (i = 0; i < max_idx; i++) {
|
|
printf("%04x %08x %08x\n",
|
|
la.data[idx], la.data[idx+2], la.data[idx+1]);
|
|
idx = (idx + 4) & (entries - 1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
get_up_ioqs(int argc, char *argv[], int start_arg, const char *iff_name)
|
|
{
|
|
struct ch_up_ioqs ioqs;
|
|
int i, entries;
|
|
|
|
(void) argc;
|
|
(void) argv;
|
|
(void) start_arg;
|
|
|
|
bzero(&ioqs, sizeof(ioqs));
|
|
ioqs.bufsize = IOQS_BUFSIZE;
|
|
ioqs.data = malloc(IOQS_BUFSIZE);
|
|
if (!ioqs.data)
|
|
err(1, "uP_IOQs malloc");
|
|
|
|
if (doit(iff_name, CHELSIO_GET_UP_IOQS, &ioqs) < 0)
|
|
err(1, "uP_IOQs");
|
|
|
|
printf("ioq_rx_enable : 0x%08x\n", ioqs.ioq_rx_enable);
|
|
printf("ioq_tx_enable : 0x%08x\n", ioqs.ioq_tx_enable);
|
|
printf("ioq_rx_status : 0x%08x\n", ioqs.ioq_rx_status);
|
|
printf("ioq_tx_status : 0x%08x\n", ioqs.ioq_tx_status);
|
|
|
|
entries = ioqs.bufsize / sizeof(struct t3_ioq_entry);
|
|
for (i = 0; i < entries; i++) {
|
|
printf("\nioq[%d].cp : 0x%08x\n", i,
|
|
ioqs.data[i].ioq_cp);
|
|
printf("ioq[%d].pp : 0x%08x\n", i,
|
|
ioqs.data[i].ioq_pp);
|
|
printf("ioq[%d].alen : 0x%08x\n", i,
|
|
ioqs.data[i].ioq_alen);
|
|
printf("ioq[%d].stats : 0x%08x\n", i,
|
|
ioqs.data[i].ioq_stats);
|
|
printf(" sop %u\n", ioqs.data[i].ioq_stats >> 16);
|
|
printf(" eop %u\n", ioqs.data[i].ioq_stats & 0xFFFF);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
run_cmd(int argc, char *argv[], const char *iff_name)
|
|
{
|
|
int r = -1;
|
|
|
|
if (!strcmp(argv[2], "reg"))
|
|
r = register_io(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "mdio"))
|
|
r = mdio_io(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "mtus"))
|
|
r = mtu_tab_op(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "pm"))
|
|
r = conf_pm(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "regdump"))
|
|
r = dump_regs(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "tcamdump"))
|
|
r = dump_tcam(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "memdump"))
|
|
r = dump_mc7(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "meminfo"))
|
|
r = meminfo(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "context"))
|
|
r = get_sge_context(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "desc"))
|
|
r = get_sge_desc(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "loadfw"))
|
|
r = load_fw(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "loadboot"))
|
|
r = load_boot(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "proto"))
|
|
r = proto_sram_op(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "qset"))
|
|
r = qset_config(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "qsets"))
|
|
r = qset_num_config(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "trace"))
|
|
r = trace_config(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "pktsched"))
|
|
r = pktsched(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "tcb"))
|
|
r = get_tcb2(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "clearstats"))
|
|
r = clear_stats(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "la"))
|
|
r = get_up_la(argc, argv, 3, iff_name);
|
|
else if (!strcmp(argv[2], "ioqs"))
|
|
r = get_up_ioqs(argc, argv, 3, iff_name);
|
|
|
|
if (r == -1)
|
|
usage(stderr);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
run_cmd_loop(int argc, char *argv[], const char *iff_name)
|
|
{
|
|
int n;
|
|
unsigned int i;
|
|
char buf[64];
|
|
char *args[8], *s;
|
|
|
|
(void) argc;
|
|
args[0] = argv[0];
|
|
args[1] = argv[1];
|
|
|
|
/*
|
|
* Fairly simplistic loop. Displays a "> " prompt and processes any
|
|
* input as a cxgbtool command. You're supposed to enter only the part
|
|
* after "cxgbtool cxgbX". Use "quit" or "exit" to exit. Any error in
|
|
* the command will also terminate cxgbtool.
|
|
*/
|
|
for (;;) {
|
|
fprintf(stdout, "> ");
|
|
fflush(stdout);
|
|
n = read(STDIN_FILENO, buf, sizeof(buf) - 1);
|
|
if (n <= 0)
|
|
return (0);
|
|
|
|
if (buf[--n] != '\n')
|
|
continue;
|
|
else
|
|
buf[n] = 0;
|
|
|
|
s = &buf[0];
|
|
for (i = 2; i < sizeof(args)/sizeof(args[0]) - 1; i++) {
|
|
while (s && (*s == ' ' || *s == '\t'))
|
|
s++;
|
|
if ((args[i] = strsep(&s, " \t")) == NULL)
|
|
break;
|
|
}
|
|
args[sizeof(args)/sizeof(args[0]) - 1] = 0;
|
|
|
|
if (!strcmp(args[2], "quit") || !strcmp(args[2], "exit"))
|
|
return (0);
|
|
|
|
(void) run_cmd(i, args, iff_name);
|
|
}
|
|
|
|
/* Can't really get here */
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int r = -1;
|
|
const char *iff_name;
|
|
|
|
progname = argv[0];
|
|
|
|
if (argc == 2) {
|
|
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
|
|
usage(stdout);
|
|
if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) {
|
|
printf("%s version %s\n", PROGNAME, VERSION);
|
|
printf("%s\n", COPYRIGHT);
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
if (argc < 3) usage(stderr);
|
|
|
|
iff_name = argv[1];
|
|
|
|
if (argc == 3 && !strcmp(argv[2], "stdio"))
|
|
r = run_cmd_loop(argc, argv, iff_name);
|
|
else
|
|
r = run_cmd(argc, argv, iff_name);
|
|
|
|
return (r);
|
|
}
|