1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2018 Joyent, Inc.
  14  */
  15 
  16 #include <mdb/mdb_ctf.h>
  17 #include <sys/mdb_modapi.h>
  18 #include "i40e_sw.h"
  19 
  20 #define RSRC_MAX        0x13
  21 static const char *i40e_switch_rsrc_names[] = {
  22         "VEBs",
  23         "VSIs",
  24         "Perfect Match MAC Addresses",
  25         "S-Tags",
  26         "Reserved",
  27         "Multicast Hash Entries",
  28         "Reserved",
  29         "VLANs",
  30         "VSI Lists",
  31         "Reserved",
  32         "VLAN Stat pools",
  33         "Mirror rules",
  34         "Queue sets",
  35         "Inner VLAN Forwarding",
  36         "Reserved",
  37         "Inner MACs",
  38         "IPs",
  39         "GRE/VN1 Keys",
  40         "VN2 Keys",
  41         "Tunnelling Ports"
  42 };
  43 
  44 /*
  45  * i40e mdb dcmds
  46  */
  47 /* ARGSUSED */
  48 static int
  49 i40e_switch_rsrcs_dcmd(uintptr_t addr, uint_t flags, int argc,
  50     const mdb_arg_t *argv)
  51 {
  52         i40e_t i40e;
  53         int i;
  54 
  55         if (!(flags & DCMD_ADDRSPEC)) {
  56                 mdb_warn("::i40e_switch_rsrcs does not operate globally\n");
  57                 return (DCMD_USAGE);
  58         }
  59 
  60         if (mdb_vread(&i40e, sizeof (i40e_t), addr) != sizeof (i40e_t)) {
  61                 mdb_warn("failed to read i40e_t at %p", addr);
  62                 return (DCMD_ERR);
  63         }
  64 
  65         mdb_printf("%-28s %-12s %-8s %-8s %s\n", "TYPE", "GUARANTEE",
  66             "TOTAL", "USED", "UNALLOCED");
  67 
  68         for (i = 0; i < i40e.i40e_switch_rsrc_actual; i++) {
  69                 i40e_switch_rsrc_t rsrc;
  70                 uintptr_t raddr = (uintptr_t)i40e.i40e_switch_rsrcs +
  71                     i * sizeof (i40e_switch_rsrc_t);
  72                 const char *name;
  73 
  74                 if (mdb_vread(&rsrc, sizeof (i40e_switch_rsrc_t), raddr) !=
  75                     sizeof (i40e_switch_rsrc_t)) {
  76                         mdb_warn("failed to read i40e_switch_rsrc_t %d at %p",
  77                             i, raddr);
  78                         return (DCMD_ERR);
  79                 }
  80 
  81                 if (rsrc.resource_type <= RSRC_MAX) {
  82                         name = i40e_switch_rsrc_names[rsrc.resource_type];
  83                 } else {
  84                         char *buf;
  85                         size_t s = mdb_snprintf(NULL, 0, "Unknown type (%d)",
  86                             rsrc.resource_type);
  87                         buf = mdb_alloc(s + 1, UM_GC | UM_SLEEP);
  88                         (void) mdb_snprintf(buf, s + 1, "Unknown type (%d)",
  89                             rsrc.resource_type);
  90                         name = buf;
  91                 }
  92 
  93                 mdb_printf("%-28s %-12d %-8d %-8d %d\n", name,
  94                     LE_16(rsrc.guaranteed), LE_16(rsrc.total), LE_16(rsrc.used),
  95                     LE_16(rsrc.total_unalloced));
  96         }
  97 
  98         return (DCMD_OK);
  99 }
 100 
 101 typedef struct mdb_i40e_trqpair {
 102         uint32_t                itrq_tx_ring_size;
 103         uint32_t                itrq_desc_free;
 104         uint32_t                *itrq_desc_wbhead;
 105         uint32_t                itrq_desc_head;
 106         uint32_t                itrq_desc_tail;
 107         i40e_tx_desc_t          *itrq_desc_ring;
 108         i40e_tx_control_block_t **itrq_tcb_work_list;
 109 } mdb_i40e_trqpair_t;
 110 
 111 static void
 112 i40e_tx_ring_help()
 113 {
 114         mdb_printf(
 115             "\t -a dump all ring entries\n"
 116             "\t or\n"
 117             "\t combine -b [start index] with -e [end index] to specify a \n"
 118             "\t range of ring entries to print\n");
 119 }
 120 
 121 static int
 122 i40e_tx_ring_dcmd(uintptr_t addr, uint_t flags, int argc,
 123     const mdb_arg_t *argv)
 124 {
 125         mdb_i40e_trqpair_t trq;
 126         i40e_tx_desc_t *descring;
 127         i40e_tx_control_block_t **wklist;
 128         uint32_t wbhead;
 129         size_t ringsz, wklistsz;
 130         boolean_t opt_a = B_FALSE;
 131         char *opt_b = NULL, *opt_e = NULL;
 132         uint64_t begin = UINT64_MAX, end = UINT64_MAX;
 133 
 134         if (!(flags & DCMD_ADDRSPEC)) {
 135                 mdb_warn("::i40e_tx_ring does not operate globally\n");
 136                 return (DCMD_USAGE);
 137         }
 138 
 139         if (mdb_getopts(argc, argv,
 140             'a', MDB_OPT_SETBITS, B_TRUE, &opt_a,
 141             'b', MDB_OPT_STR, &opt_b,
 142             'e', MDB_OPT_STR, &opt_e, NULL) != argc)
 143                 return (DCMD_USAGE);
 144 
 145         /*
 146          * Verify that a legal combination of -a/-b/-e were used.
 147          */
 148         if (opt_a && (opt_b != NULL || opt_e != NULL)) {
 149                 mdb_warn("-a and -b/-e are mutually exclusive\n");
 150                 return (DCMD_USAGE);
 151         }
 152         if (argc > 0 && ! opt_a && (opt_b == NULL || opt_e == NULL)) {
 153                 mdb_warn("-b/-e must both be specified\n");
 154                 return (DCMD_USAGE);
 155         }
 156 
 157         if (mdb_ctf_vread(&trq, "i40e_trqpair_t", "mdb_i40e_trqpair_t", addr,
 158             0) == -1) {
 159                 mdb_warn("failed to read i40e_trqpair_t at %p", addr);
 160                 return (DCMD_ERR);
 161         }
 162 
 163         if (opt_b != NULL)
 164                 begin = mdb_strtoull(opt_b);
 165         if (opt_e != NULL)
 166                 end = mdb_strtoull(opt_e);
 167         if (opt_a) {
 168                 begin = 0;
 169                 end = trq.itrq_tx_ring_size - 1;
 170         }
 171 
 172         /*
 173          * Verify that the requested range of ring entries makes sense.
 174          */
 175         if (argc > 0 && (end < begin || begin >= trq.itrq_tx_ring_size ||
 176             end >= trq.itrq_tx_ring_size)) {
 177                 mdb_warn("invalid range specified\n");
 178                 return (DCMD_USAGE);
 179         }
 180 
 181         if (mdb_vread(&wbhead, sizeof (uint32_t),
 182             (uintptr_t)trq.itrq_desc_wbhead) != sizeof (uint32_t)) {
 183                 mdb_warn("failed to read trq.itrq_desc_wbhead");
 184                 return (DCMD_ERR);
 185         }
 186         mdb_printf("%-20s%d\n", "Ring Size:", trq.itrq_tx_ring_size);
 187         mdb_printf("%-20s%d\n", "Free Descriptors:", trq.itrq_desc_free);
 188         mdb_printf("%-20s%d\n", "Writeback Head:", wbhead);
 189         mdb_printf("%-20s%d\n", "Head:", trq.itrq_desc_head);
 190         mdb_printf("%-20s%d\n", "Tail:", trq.itrq_desc_tail);
 191 
 192         /*
 193          * No arguments were specified, so we're done.
 194          */
 195         if (argc == 0)
 196                 return (DCMD_OK);
 197 
 198         /*
 199          * Allocate memory and read in the entire TX descriptor ring and
 200          * TCB work list.
 201          */
 202         ringsz = sizeof (i40e_tx_desc_t) * trq.itrq_tx_ring_size;
 203         descring = mdb_alloc(ringsz, UM_SLEEP);
 204         if (mdb_vread(descring, ringsz, (uintptr_t)trq.itrq_desc_ring) !=
 205             ringsz) {
 206                 mdb_warn("Failed to read in TX decriptor ring\n");
 207                 mdb_free(descring, ringsz);
 208                 return (DCMD_ERR);
 209         }
 210         wklistsz = sizeof (i40e_tx_control_block_t *) * trq.itrq_tx_ring_size;
 211         wklist = mdb_alloc(wklistsz, UM_SLEEP);
 212         if (mdb_vread(wklist, wklistsz, (uintptr_t)trq.itrq_tcb_work_list) !=
 213             wklistsz) {
 214                 mdb_warn("Failed to read in TX TCB work list\n");
 215                 mdb_free(descring, ringsz);
 216                 mdb_free(wklist, wklistsz);
 217                 return (DCMD_ERR);
 218         }
 219 
 220         mdb_printf("\n%-10s %-10s %-16s %-16s %-10s\n", "Index", "Desc Type",
 221             "Desc Ptr", "TCB Ptr", "Other");
 222         for (uint64_t i = begin; i <= end; i++) {
 223                 const char *dtype;
 224                 char dother[17];
 225                 i40e_tx_desc_t *dptr;
 226                 i40e_tx_control_block_t *tcbptr;
 227                 uint64_t ctob;
 228 
 229                 dptr = &descring[i];
 230                 tcbptr = wklist[i];
 231                 ctob = LE_64(dptr->cmd_type_offset_bsz);
 232                 if (ctob == 0) {
 233                         dtype = "FREE";
 234                 } else {
 235                         switch (ctob & I40E_TXD_QW1_DTYPE_MASK) {
 236                         case (I40E_TX_DESC_DTYPE_CONTEXT):
 237                                 dtype = "CONTEXT";
 238                                 break;
 239                         case (I40E_TX_DESC_DTYPE_DATA):
 240                                 dtype = "DATA";
 241                                 break;
 242                         case (I40E_TX_DESC_DTYPE_FILTER_PROG):
 243                                 dtype = "FILTER";
 244                                 break;
 245                         default:
 246                                 dtype = "UNKNOWN";
 247                         }
 248                 }
 249                 dother[0] = '\0';
 250                 if (i == wbhead)
 251                         (void) strcat(dother, "WBHEAD");
 252 
 253                 if (i == trq.itrq_desc_head)
 254                         (void) strcat(dother,
 255                             strlen(dother) > 0 ? " HEAD" : "HEAD");
 256 
 257                 if (i == trq.itrq_desc_tail)
 258                         (void) strcat(dother,
 259                             strlen(dother) > 0 ? " TAIL" : "TAIL");
 260 
 261                 mdb_printf("%-10d %-10s %-16p %-16p %-10s\n", i, dtype, dptr,
 262                     tcbptr, dother);
 263         }
 264 
 265         mdb_free(descring, ringsz);
 266         mdb_free(wklist, wklistsz);
 267         return (DCMD_OK);
 268 }
 269 
 270 static const mdb_dcmd_t i40e_dcmds[] = {
 271         { "i40e_switch_rsrcs", NULL, "print switch resources",
 272             i40e_switch_rsrcs_dcmd, NULL },
 273         { "i40e_tx_ring", "[-a] -b [start index] -e [end index]\n",
 274             "dump TX descriptor ring state", i40e_tx_ring_dcmd,
 275             i40e_tx_ring_help },
 276         { NULL }
 277 };
 278 
 279 static const mdb_modinfo_t i40e_modinfo = {
 280         MDB_API_VERSION, i40e_dcmds, NULL
 281 };
 282 
 283 const mdb_modinfo_t *
 284 _mdb_init(void)
 285 {
 286         return (&i40e_modinfo);
 287 }