dpdk/drivers/net/qede/qede_regs.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright (c) 2020 Marvell Semiconductor Inc.
   3 * All rights reserved.
   4 * www.marvell.com
   5 */
   6
   7#include <stdio.h>
   8#include <stdlib.h>
   9#include <fcntl.h>
  10#include <time.h>
  11#include <rte_ethdev.h>
  12#include "base/bcm_osal.h"
  13#include "qede_ethdev.h"
  14
  15int
  16qede_get_regs_len(struct qede_dev *qdev)
  17{
  18        struct ecore_dev *edev = &qdev->edev;
  19        int cur_engine, num_of_hwfns, regs_len = 0;
  20        uint8_t org_engine;
  21
  22        if (IS_VF(edev))
  23                return 0;
  24
  25        if (qdev->ops && qdev->ops->common) {
  26                num_of_hwfns = qdev->dev_info.common.num_hwfns;
  27                org_engine = qdev->ops->common->dbg_get_debug_engine(edev);
  28                for (cur_engine = 0; cur_engine < num_of_hwfns; cur_engine++) {
  29                        /* compute required buffer size for idle_chks and
  30                         * grcDump for each hw function
  31                         */
  32                        DP_NOTICE(edev, false,
  33                                "Calculating idle_chk and grcdump register length for current engine\n");
  34                        qdev->ops->common->dbg_set_debug_engine(edev,
  35                                                                cur_engine);
  36                        regs_len += REGDUMP_HEADER_SIZE +
  37                                qdev->ops->common->dbg_idle_chk_size(edev) +
  38                                REGDUMP_HEADER_SIZE +
  39                                qdev->ops->common->dbg_idle_chk_size(edev) +
  40                                REGDUMP_HEADER_SIZE +
  41                                qdev->ops->common->dbg_grc_size(edev) +
  42                                REGDUMP_HEADER_SIZE +
  43                                qdev->ops->common->dbg_reg_fifo_size(edev) +
  44                                REGDUMP_HEADER_SIZE +
  45                                qdev->ops->common->dbg_protection_override_size(edev) +
  46                                REGDUMP_HEADER_SIZE +
  47                                qdev->ops->common->dbg_igu_fifo_size(edev) +
  48                                REGDUMP_HEADER_SIZE +
  49                                qdev->ops->common->dbg_fw_asserts_size(edev);
  50                }
  51                /* compute required buffer size for mcp trace and add it to the
  52                 * total required buffer size
  53                 */
  54                regs_len += REGDUMP_HEADER_SIZE +
  55                            qdev->ops->common->dbg_mcp_trace_size(edev);
  56
  57                qdev->ops->common->dbg_set_debug_engine(edev, org_engine);
  58        }
  59        DP_NOTICE(edev, false, "Total length = %u\n", regs_len);
  60
  61        return regs_len;
  62}
  63
  64static uint32_t
  65qede_calc_regdump_header(enum debug_print_features feature, int engine,
  66                         uint32_t feature_size, uint8_t omit_engine)
  67{
  68        /* insert the engine, feature and mode inside the header and
  69         * combine it with feature size
  70         */
  71        return (feature_size | (feature << REGDUMP_HEADER_FEATURE_SHIFT) |
  72                (omit_engine << REGDUMP_HEADER_OMIT_ENGINE_SHIFT) |
  73                (engine << REGDUMP_HEADER_ENGINE_SHIFT));
  74}
  75
  76int qede_get_regs(struct rte_eth_dev *eth_dev, struct rte_dev_reg_info *regs)
  77{
  78        struct qede_dev *qdev = eth_dev->data->dev_private;
  79        struct ecore_dev *edev = &qdev->edev;
  80        uint32_t *buffer = regs->data;
  81        int cur_engine, num_of_hwfns;
  82        /* '1' tells the parser to omit the engine number in the output files */
  83        uint8_t omit_engine = 0;
  84        uint8_t org_engine;
  85        uint32_t feature_size;
  86        uint32_t offset = 0;
  87
  88        if (IS_VF(edev))
  89                return -ENOTSUP;
  90
  91        if (buffer == NULL) {
  92                regs->length = qede_get_regs_len(qdev);
  93                regs->width =  sizeof(uint32_t);
  94                DP_INFO(edev, "Length %u\n", regs->length);
  95                return 0;
  96        }
  97
  98        memset(buffer, 0, regs->length);
  99        num_of_hwfns = qdev->dev_info.common.num_hwfns;
 100        if (num_of_hwfns == 1)
 101                omit_engine = 1;
 102
 103        OSAL_MUTEX_ACQUIRE(&edev->dbg_lock);
 104
 105        org_engine = qdev->ops->common->dbg_get_debug_engine(edev);
 106        for (cur_engine = 0; cur_engine < num_of_hwfns; cur_engine++) {
 107                /* collect idle_chks and grcDump for each hw function */
 108                DP_NOTICE(edev, false, "obtaining idle_chk and grcdump for current engine\n");
 109                qdev->ops->common->dbg_set_debug_engine(edev, cur_engine);
 110
 111                /* first idle_chk */
 112                qdev->ops->common->dbg_idle_chk(edev, (uint8_t *)buffer +
 113                        offset + REGDUMP_HEADER_SIZE, &feature_size);
 114                *(uint32_t *)((uint8_t *)buffer + offset) =
 115                        qede_calc_regdump_header(IDLE_CHK, cur_engine,
 116                                                 feature_size, omit_engine);
 117                offset += (feature_size + REGDUMP_HEADER_SIZE);
 118                DP_NOTICE(edev, false, "Idle Check1 feature_size %u\n",
 119                          feature_size);
 120
 121                /* second idle_chk */
 122                qdev->ops->common->dbg_idle_chk(edev, (uint8_t *)buffer +
 123                        offset + REGDUMP_HEADER_SIZE, &feature_size);
 124                *(uint32_t *)((uint8_t *)buffer + offset) =
 125                        qede_calc_regdump_header(IDLE_CHK, cur_engine,
 126                                                 feature_size, omit_engine);
 127                offset += (feature_size + REGDUMP_HEADER_SIZE);
 128                DP_NOTICE(edev, false, "Idle Check2 feature_size %u\n",
 129                          feature_size);
 130
 131                /* reg_fifo dump */
 132                qdev->ops->common->dbg_reg_fifo(edev, (uint8_t *)buffer +
 133                        offset + REGDUMP_HEADER_SIZE, &feature_size);
 134                *(uint32_t *)((uint8_t *)buffer + offset) =
 135                        qede_calc_regdump_header(REG_FIFO, cur_engine,
 136                                                 feature_size, omit_engine);
 137                offset += (feature_size + REGDUMP_HEADER_SIZE);
 138                DP_NOTICE(edev, false, "Reg fifo feature_size %u\n",
 139                          feature_size);
 140
 141                /* igu_fifo dump */
 142                qdev->ops->common->dbg_igu_fifo(edev, (uint8_t *)buffer +
 143                        offset + REGDUMP_HEADER_SIZE, &feature_size);
 144                *(uint32_t *)((uint8_t *)buffer + offset) =
 145                        qede_calc_regdump_header(IGU_FIFO, cur_engine,
 146                                                 feature_size, omit_engine);
 147                offset += (feature_size + REGDUMP_HEADER_SIZE);
 148                DP_NOTICE(edev, false, "IGU fifo feature_size %u\n",
 149                          feature_size);
 150
 151                /* protection_override dump */
 152                qdev->ops->common->dbg_protection_override(edev,
 153                                                           (uint8_t *)buffer +
 154                        offset + REGDUMP_HEADER_SIZE, &feature_size);
 155                *(uint32_t *)((uint8_t *)buffer + offset) =
 156                       qede_calc_regdump_header(PROTECTION_OVERRIDE, cur_engine,
 157                                                feature_size, omit_engine);
 158                offset += (feature_size + REGDUMP_HEADER_SIZE);
 159                DP_NOTICE(edev, false, "Protection override feature_size %u\n",
 160                          feature_size);
 161
 162                /* fw_asserts dump */
 163                qdev->ops->common->dbg_fw_asserts(edev, (uint8_t *)buffer +
 164                        offset + REGDUMP_HEADER_SIZE, &feature_size);
 165                *(uint32_t *)((uint8_t *)buffer + offset) =
 166                        qede_calc_regdump_header(FW_ASSERTS, cur_engine,
 167                                                 feature_size, omit_engine);
 168                offset += (feature_size + REGDUMP_HEADER_SIZE);
 169                DP_NOTICE(edev, false, "FW assert feature_size %u\n",
 170                          feature_size);
 171
 172                /* grc dump */
 173                qdev->ops->common->dbg_grc(edev, (uint8_t *)buffer +
 174                        offset + REGDUMP_HEADER_SIZE, &feature_size);
 175                *(uint32_t *)((uint8_t *)buffer + offset) =
 176                        qede_calc_regdump_header(GRC_DUMP, cur_engine,
 177                                                 feature_size, omit_engine);
 178                offset += (feature_size + REGDUMP_HEADER_SIZE);
 179                DP_NOTICE(edev, false, "GRC dump feature_size %u\n",
 180                          feature_size);
 181        }
 182
 183        /* mcp_trace */
 184        qdev->ops->common->dbg_mcp_trace(edev, (uint8_t *)buffer +
 185                offset + REGDUMP_HEADER_SIZE, &feature_size);
 186        *(uint32_t *)((uint8_t *)buffer + offset) =
 187                qede_calc_regdump_header(MCP_TRACE, cur_engine, feature_size,
 188                                         omit_engine);
 189        offset += (feature_size + REGDUMP_HEADER_SIZE);
 190        DP_NOTICE(edev, false, "MCP trace feature_size %u\n", feature_size);
 191
 192        qdev->ops->common->dbg_set_debug_engine(edev, org_engine);
 193
 194        OSAL_MUTEX_RELEASE(&edev->dbg_lock);
 195
 196        return 0;
 197}
 198
 199static void
 200qede_set_fw_dump_file_name(struct qede_dev *qdev)
 201{
 202        time_t ltime;
 203        struct tm *tm;
 204
 205        ltime = time(NULL);
 206        tm = localtime(&ltime);
 207        snprintf(qdev->dump_file, QEDE_FW_DUMP_FILE_SIZE,
 208                 "qede_pmd_dump_%02d-%02d-%02d_%02d-%02d-%02d.bin",
 209                 tm->tm_mon + 1, (int)tm->tm_mday, 1900 + tm->tm_year,
 210                 tm->tm_hour, tm->tm_min, tm->tm_sec);
 211}
 212
 213static int
 214qede_write_fwdump(const char *dump_file, void *dump, size_t len)
 215{
 216        int err = 0;
 217        FILE *f;
 218        size_t bytes;
 219
 220        f = fopen(dump_file, "wb+");
 221
 222        if (!f) {
 223                fprintf(stderr, "Can't open file %s: %s\n",
 224                        dump_file, strerror(errno));
 225                return 1;
 226        }
 227        bytes = fwrite(dump, 1, len, f);
 228        if (bytes != len) {
 229                fprintf(stderr,
 230                        "Can not write all of dump data bytes=%zd len=%zd\n",
 231                        bytes, len);
 232                err = 1;
 233        }
 234
 235        if (fclose(f)) {
 236                fprintf(stderr, "Can't close file %s: %s\n",
 237                        dump_file, strerror(errno));
 238                err = 1;
 239        }
 240
 241        return err;
 242}
 243
 244int
 245qede_save_fw_dump(uint16_t port_id)
 246{
 247        struct rte_eth_dev *eth_dev = &rte_eth_devices[port_id];
 248        struct rte_dev_reg_info regs;
 249        struct qede_dev *qdev = eth_dev->data->dev_private;
 250        struct ecore_dev *edev = &qdev->edev;
 251        int rc = 0;
 252
 253        if (!rte_eth_dev_is_valid_port(port_id)) {
 254                DP_ERR(edev, "port %u invalid port ID", port_id);
 255                return -ENODEV;
 256        }
 257
 258        memset(&regs, 0, sizeof(regs));
 259        regs.length = qede_get_regs_len(qdev);
 260        regs.data = OSAL_ZALLOC(eth_dev, GFP_KERNEL, regs.length);
 261        if (regs.data) {
 262                qede_get_regs(eth_dev, &regs);
 263                qede_set_fw_dump_file_name(qdev);
 264                rc = qede_write_fwdump(qdev->dump_file, regs.data, regs.length);
 265                if (!rc)
 266                        DP_NOTICE(edev, false, "FW dump written to %s file\n",
 267                                  qdev->dump_file);
 268                OSAL_FREE(edev, regs.data);
 269        }
 270
 271        return rc;
 272}
 273