uboot/drivers/net/pfe_eth/pfe_cmd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2015-2016 Freescale Semiconductor, Inc.
   4 * Copyright 2017 NXP
   5 */
   6
   7/*
   8 * @file
   9 * @brief PFE utility commands
  10 */
  11
  12#include <common.h>
  13#include <command.h>
  14#include <log.h>
  15#include <linux/delay.h>
  16#include <net/pfe_eth/pfe_eth.h>
  17
  18static inline void pfe_command_help(void)
  19{
  20        printf("Usage: pfe [pe | status | expt ] <options>\n");
  21}
  22
  23static void pfe_command_pe(int argc, char *const argv[])
  24{
  25        if (argc >= 3 && strcmp(argv[2], "pmem") == 0) {
  26                if (argc >= 4 && strcmp(argv[3], "read") == 0) {
  27                        int i;
  28                        int num;
  29                        int id;
  30                        u32 addr;
  31                        u32 size;
  32                        u32 val;
  33
  34                        if (argc == 7) {
  35                                num = simple_strtoul(argv[6], NULL, 0);
  36                        } else if (argc == 6) {
  37                                num = 1;
  38                        } else {
  39                                printf("Usage: pfe pe pmem read <id> <addr> [<num>]\n");
  40                                return;
  41                        }
  42
  43                        id = simple_strtoul(argv[4], NULL, 0);
  44                        addr = simple_strtoul(argv[5], NULL, 16);
  45                        size = 4;
  46
  47                        for (i = 0; i < num; i++, addr += 4) {
  48                                val = pe_pmem_read(id, addr, size);
  49                                val = be32_to_cpu(val);
  50                                if (!(i & 3))
  51                                        printf("%08x: ", addr);
  52                                printf("%08x%s", val, i == num - 1 || (i & 3)
  53                                       == 3 ? "\n" : " ");
  54                        }
  55
  56                } else {
  57                        printf("Usage: pfe pe pmem read <parameters>\n");
  58                }
  59        } else if (argc >= 3 && strcmp(argv[2], "dmem") == 0) {
  60                if (argc >= 4 && strcmp(argv[3], "read") == 0) {
  61                        int i;
  62                        int num;
  63                        int id;
  64                        u32 addr;
  65                        u32 size;
  66                        u32 val;
  67
  68                        if (argc == 7) {
  69                                num = simple_strtoul(argv[6], NULL, 0);
  70                        } else if (argc == 6) {
  71                                num = 1;
  72                        } else {
  73                                printf("Usage: pfe pe dmem read <id> <addr> [<num>]\n");
  74                                return;
  75                        }
  76
  77                        id = simple_strtoul(argv[4], NULL, 0);
  78                        addr = simple_strtoul(argv[5], NULL, 16);
  79                        size = 4;
  80
  81                        for (i = 0; i < num; i++, addr += 4) {
  82                                val = pe_dmem_read(id, addr, size);
  83                                val = be32_to_cpu(val);
  84                                if (!(i & 3))
  85                                        printf("%08x: ", addr);
  86                                printf("%08x%s", val, i == num - 1 || (i & 3)
  87                                       == 3 ? "\n" : " ");
  88                        }
  89
  90                } else if (argc >= 4 && strcmp(argv[3], "write") == 0) {
  91                        int id;
  92                        u32 val;
  93                        u32 addr;
  94                        u32 size;
  95
  96                        if (argc != 7) {
  97                                printf("Usage: pfe pe dmem write <id> <val> <addr>\n");
  98                                return;
  99                        }
 100
 101                        id = simple_strtoul(argv[4], NULL, 0);
 102                        val = simple_strtoul(argv[5], NULL, 16);
 103                        val = cpu_to_be32(val);
 104                        addr = simple_strtoul(argv[6], NULL, 16);
 105                        size = 4;
 106                        pe_dmem_write(id, val, addr, size);
 107                } else {
 108                        printf("Usage: pfe pe dmem [read | write] <parameters>\n");
 109                }
 110        } else if (argc >= 3 && strcmp(argv[2], "lmem") == 0) {
 111                if (argc >= 4 && strcmp(argv[3], "read") == 0) {
 112                        int i;
 113                        int num;
 114                        u32 val;
 115                        u32 offset;
 116
 117                        if (argc == 6) {
 118                                num = simple_strtoul(argv[5], NULL, 0);
 119                        } else if (argc == 5) {
 120                                num = 1;
 121                        } else {
 122                                printf("Usage: pfe pe lmem read <offset> [<num>]\n");
 123                                return;
 124                        }
 125
 126                        offset = simple_strtoul(argv[4], NULL, 16);
 127
 128                        for (i = 0; i < num; i++, offset += 4) {
 129                                pe_lmem_read(&val, 4, offset);
 130                                val = be32_to_cpu(val);
 131                                printf("%08x%s", val, i == num - 1 || (i & 7)
 132                                       == 7 ? "\n" : " ");
 133                        }
 134
 135                } else if (argc >= 4 && strcmp(argv[3], "write") == 0)  {
 136                        u32 val;
 137                        u32 offset;
 138
 139                        if (argc != 6) {
 140                                printf("Usage: pfe pe lmem write <val> <offset>\n");
 141                                return;
 142                        }
 143
 144                        val = simple_strtoul(argv[4], NULL, 16);
 145                        val = cpu_to_be32(val);
 146                        offset = simple_strtoul(argv[5], NULL, 16);
 147                        pe_lmem_write(&val, 4, offset);
 148                } else {
 149                        printf("Usage: pfe pe lmem [read | write] <parameters>\n");
 150                }
 151        } else {
 152                if (strcmp(argv[2], "help") != 0)
 153                        printf("Unknown option: %s\n", argv[2]);
 154
 155                printf("Usage: pfe pe <parameters>\n");
 156        }
 157}
 158
 159#define NUM_QUEUES              16
 160
 161/*
 162 * qm_read_drop_stat
 163 * This function is used to read the drop statistics from the TMU
 164 * hw drop counter.  Since the hw counter is always cleared afer
 165 * reading, this function maintains the previous drop count, and
 166 * adds the new value to it.  That value can be retrieved by
 167 * passing a pointer to it with the total_drops arg.
 168 *
 169 * @param tmu           TMU number (0 - 3)
 170 * @param queue         queue number (0 - 15)
 171 * @param total_drops   pointer to location to store total drops (or NULL)
 172 * @param do_reset      if TRUE, clear total drops after updating
 173 *
 174 */
 175u32 qm_read_drop_stat(u32 tmu, u32 queue, u32 *total_drops, int do_reset)
 176{
 177        static u32 qtotal[TMU_MAX_ID + 1][NUM_QUEUES];
 178        u32 val;
 179
 180        writel((tmu << 8) | queue, TMU_TEQ_CTRL);
 181        writel((tmu << 8) | queue, TMU_LLM_CTRL);
 182        val = readl(TMU_TEQ_DROP_STAT);
 183        qtotal[tmu][queue] += val;
 184        if (total_drops)
 185                *total_drops = qtotal[tmu][queue];
 186        if (do_reset)
 187                qtotal[tmu][queue] = 0;
 188        return val;
 189}
 190
 191static ssize_t tmu_queue_stats(char *buf, int tmu, int queue)
 192{
 193        ssize_t len = 0;
 194        u32 drops;
 195
 196        printf("%d-%02d, ", tmu, queue);
 197
 198        drops = qm_read_drop_stat(tmu, queue, NULL, 0);
 199
 200        /* Select queue */
 201        writel((tmu << 8) | queue, TMU_TEQ_CTRL);
 202        writel((tmu << 8) | queue, TMU_LLM_CTRL);
 203
 204        printf("(teq) drop: %10u, tx: %10u (llm) head: %08x, tail: %08x, drop: %10u\n",
 205               drops, readl(TMU_TEQ_TRANS_STAT),
 206               readl(TMU_LLM_QUE_HEADPTR), readl(TMU_LLM_QUE_TAILPTR),
 207               readl(TMU_LLM_QUE_DROPCNT));
 208
 209        return len;
 210}
 211
 212static ssize_t tmu_queues(char *buf, int tmu)
 213{
 214        ssize_t len = 0;
 215        int queue;
 216
 217        for (queue = 0; queue < 16; queue++)
 218                len += tmu_queue_stats(buf + len, tmu, queue);
 219
 220        return len;
 221}
 222
 223static inline void hif_status(void)
 224{
 225        printf("hif:\n");
 226
 227        printf("  tx curr bd:    %x\n", readl(HIF_TX_CURR_BD_ADDR));
 228        printf("  tx status:     %x\n", readl(HIF_TX_STATUS));
 229        printf("  tx dma status: %x\n", readl(HIF_TX_DMA_STATUS));
 230
 231        printf("  rx curr bd:    %x\n", readl(HIF_RX_CURR_BD_ADDR));
 232        printf("  rx status:     %x\n", readl(HIF_RX_STATUS));
 233        printf("  rx dma status: %x\n", readl(HIF_RX_DMA_STATUS));
 234
 235        printf("hif nocopy:\n");
 236
 237        printf("  tx curr bd:    %x\n", readl(HIF_NOCPY_TX_CURR_BD_ADDR));
 238        printf("  tx status:     %x\n", readl(HIF_NOCPY_TX_STATUS));
 239        printf("  tx dma status: %x\n", readl(HIF_NOCPY_TX_DMA_STATUS));
 240
 241        printf("  rx curr bd:    %x\n", readl(HIF_NOCPY_RX_CURR_BD_ADDR));
 242        printf("  rx status:     %x\n", readl(HIF_NOCPY_RX_STATUS));
 243        printf("  rx dma status: %x\n", readl(HIF_NOCPY_RX_DMA_STATUS));
 244}
 245
 246static void gpi(int id, void *base)
 247{
 248        u32 val;
 249
 250        printf("%s%d:\n", __func__, id);
 251
 252        printf("  tx under stick: %x\n", readl(base + GPI_FIFO_STATUS));
 253        val = readl(base + GPI_FIFO_DEBUG);
 254        printf("  tx pkts:        %x\n", (val >> 23) & 0x3f);
 255        printf("  rx pkts:        %x\n", (val >> 18) & 0x3f);
 256        printf("  tx bytes:       %x\n", (val >> 9) & 0x1ff);
 257        printf("  rx bytes:       %x\n", (val >> 0) & 0x1ff);
 258        printf("  overrun:        %x\n", readl(base + GPI_OVERRUN_DROPCNT));
 259}
 260
 261static void  bmu(int id, void *base)
 262{
 263        printf("%s%d:\n", __func__, id);
 264
 265        printf("  buf size:  %x\n", (1 << readl(base + BMU_BUF_SIZE)));
 266        printf("  buf count: %x\n", readl(base + BMU_BUF_CNT));
 267        printf("  buf rem:   %x\n", readl(base + BMU_REM_BUF_CNT));
 268        printf("  buf curr:  %x\n", readl(base + BMU_CURR_BUF_CNT));
 269        printf("  free err:  %x\n", readl(base + BMU_FREE_ERR_ADDR));
 270}
 271
 272#define PESTATUS_ADDR_CLASS     0x800
 273#define PEMBOX_ADDR_CLASS       0x890
 274#define PESTATUS_ADDR_TMU       0x80
 275#define PEMBOX_ADDR_TMU         0x290
 276#define PESTATUS_ADDR_UTIL      0x0
 277
 278static void pfe_pe_status(int argc, char *const argv[])
 279{
 280        int do_clear = 0;
 281        u32 id;
 282        u32 dmem_addr;
 283        u32 cpu_state;
 284        u32 activity_counter;
 285        u32 rx;
 286        u32 tx;
 287        u32 drop;
 288        char statebuf[5];
 289        u32 class_debug_reg = 0;
 290
 291        if (argc == 4 && strcmp(argv[3], "clear") == 0)
 292                do_clear = 1;
 293
 294        for (id = CLASS0_ID; id < MAX_PE; id++) {
 295                if (id >= TMU0_ID) {
 296                        if (id == TMU2_ID)
 297                                continue;
 298                        if (id == TMU0_ID)
 299                                printf("tmu:\n");
 300                        dmem_addr = PESTATUS_ADDR_TMU;
 301                } else {
 302                        if (id == CLASS0_ID)
 303                                printf("class:\n");
 304                        dmem_addr = PESTATUS_ADDR_CLASS;
 305                        class_debug_reg = readl(CLASS_PE0_DEBUG + id * 4);
 306                }
 307
 308                cpu_state = pe_dmem_read(id, dmem_addr, 4);
 309                dmem_addr += 4;
 310                memcpy(statebuf, (char *)&cpu_state, 4);
 311                statebuf[4] = '\0';
 312                activity_counter = pe_dmem_read(id, dmem_addr, 4);
 313                dmem_addr += 4;
 314                rx = pe_dmem_read(id, dmem_addr, 4);
 315                if (do_clear)
 316                        pe_dmem_write(id, 0, dmem_addr, 4);
 317                dmem_addr += 4;
 318                tx = pe_dmem_read(id, dmem_addr, 4);
 319                if (do_clear)
 320                        pe_dmem_write(id, 0, dmem_addr, 4);
 321                dmem_addr += 4;
 322                drop = pe_dmem_read(id, dmem_addr, 4);
 323                if (do_clear)
 324                        pe_dmem_write(id, 0, dmem_addr, 4);
 325                dmem_addr += 4;
 326
 327                if (id >= TMU0_ID) {
 328                        printf("%d: state=%4s ctr=%08x rx=%x qstatus=%x\n",
 329                               id - TMU0_ID, statebuf,
 330                               cpu_to_be32(activity_counter),
 331                               cpu_to_be32(rx), cpu_to_be32(tx));
 332                } else {
 333                        printf("%d: pc=1%04x ldst=%04x state=%4s ctr=%08x rx=%x tx=%x drop=%x\n",
 334                               id - CLASS0_ID, class_debug_reg & 0xFFFF,
 335                               class_debug_reg >> 16,
 336                               statebuf, cpu_to_be32(activity_counter),
 337                               cpu_to_be32(rx), cpu_to_be32(tx),
 338                               cpu_to_be32(drop));
 339                }
 340        }
 341}
 342
 343static void pfe_command_status(int argc, char *const argv[])
 344{
 345        if (argc >= 3 && strcmp(argv[2], "pe") == 0) {
 346                pfe_pe_status(argc, argv);
 347        } else if (argc == 3 && strcmp(argv[2], "bmu") == 0) {
 348                bmu(1, BMU1_BASE_ADDR);
 349                bmu(2, BMU2_BASE_ADDR);
 350        } else if (argc == 3 && strcmp(argv[2], "hif") == 0) {
 351                hif_status();
 352        } else if (argc == 3 && strcmp(argv[2], "gpi") == 0) {
 353                gpi(0, EGPI1_BASE_ADDR);
 354                gpi(1, EGPI2_BASE_ADDR);
 355                gpi(3, HGPI_BASE_ADDR);
 356        } else if (argc == 3 && strcmp(argv[2], "tmu0_queues") == 0) {
 357                tmu_queues(NULL, 0);
 358        } else if (argc == 3 && strcmp(argv[2], "tmu1_queues") == 0) {
 359                tmu_queues(NULL, 1);
 360        } else if (argc == 3 && strcmp(argv[2], "tmu3_queues") == 0) {
 361                tmu_queues(NULL, 3);
 362        } else {
 363                printf("Usage: pfe status [pe <clear> | bmu | gpi | hif | tmuX_queues ]\n");
 364        }
 365}
 366
 367#define EXPT_DUMP_ADDR 0x1fa8
 368#define EXPT_REG_COUNT 20
 369static const char *register_names[EXPT_REG_COUNT] = {
 370                "  pc", "ECAS", " EID", "  ED",
 371                "  sp", "  r1", "  r2", "  r3",
 372                "  r4", "  r5", "  r6", "  r7",
 373                "  r8", "  r9", " r10", " r11",
 374                " r12", " r13", " r14", " r15"
 375};
 376
 377static void pfe_command_expt(int argc, char *const argv[])
 378{
 379        unsigned int id, i, val, addr;
 380
 381        if (argc == 3) {
 382                id = simple_strtoul(argv[2], NULL, 0);
 383                addr = EXPT_DUMP_ADDR;
 384                printf("Exception information for PE %d:\n", id);
 385                for (i = 0; i < EXPT_REG_COUNT; i++) {
 386                        val = pe_dmem_read(id, addr, 4);
 387                        val = be32_to_cpu(val);
 388                        printf("%s:%08x%s", register_names[i], val,
 389                               (i & 3) == 3 ? "\n" : " ");
 390                        addr += 4;
 391                }
 392        } else {
 393                printf("Usage: pfe expt <id>\n");
 394        }
 395}
 396
 397#ifdef PFE_RESET_WA
 398/*This function sends a dummy packet to HIF through TMU3 */
 399static void send_dummy_pkt_to_hif(void)
 400{
 401        u32 buf;
 402        static u32 dummy_pkt[] =  {
 403                0x4200800a, 0x01000003, 0x00018100, 0x00000000,
 404                0x33221100, 0x2b785544, 0xd73093cb, 0x01000608,
 405                0x04060008, 0x2b780200, 0xd73093cb, 0x0a01a8c0,
 406                0x33221100, 0xa8c05544, 0x00000301, 0x00000000,
 407                0x00000000, 0x00000000, 0x00000000, 0xbe86c51f };
 408
 409        /*Allocate BMU2 buffer */
 410        buf = readl(BMU2_BASE_ADDR + BMU_ALLOC_CTRL);
 411
 412        debug("Sending a dummy pkt to HIF %x\n", buf);
 413        buf += 0x80;
 414        memcpy((void *)DDR_PFE_TO_VIRT(buf), dummy_pkt, sizeof(dummy_pkt));
 415
 416        /*Write length and pkt to TMU*/
 417        writel(0x03000042, TMU_PHY_INQ_PKTPTR);
 418        writel(buf, TMU_PHY_INQ_PKTINFO);
 419}
 420
 421static void pfe_command_stop(int argc, char *const argv[])
 422{
 423        int pfe_pe_id, hif_stop_loop = 10;
 424        u32 rx_status;
 425
 426        printf("Stopping PFE...\n");
 427
 428        /*Mark all descriptors as LAST_BD */
 429        hif_rx_desc_disable();
 430
 431        /*If HIF Rx BDP is busy send a dummy packet */
 432        do {
 433                rx_status = readl(HIF_RX_STATUS);
 434                if (rx_status & BDP_CSR_RX_DMA_ACTV)
 435                        send_dummy_pkt_to_hif();
 436                udelay(10);
 437        } while (hif_stop_loop--);
 438
 439        if (readl(HIF_RX_STATUS) & BDP_CSR_RX_DMA_ACTV)
 440                printf("Unable to stop HIF\n");
 441
 442        /*Disable Class PEs */
 443        for (pfe_pe_id = CLASS0_ID; pfe_pe_id <= CLASS_MAX_ID; pfe_pe_id++) {
 444                /*Inform PE to stop */
 445                pe_dmem_write(pfe_pe_id, cpu_to_be32(1), PEMBOX_ADDR_CLASS, 4);
 446                udelay(10);
 447
 448                /*Read status */
 449                if (!pe_dmem_read(pfe_pe_id, PEMBOX_ADDR_CLASS + 4, 4))
 450                        printf("Failed to stop PE%d\n", pfe_pe_id);
 451        }
 452
 453        /*Disable TMU PEs */
 454        for (pfe_pe_id = TMU0_ID; pfe_pe_id <= TMU_MAX_ID; pfe_pe_id++) {
 455                if (pfe_pe_id == TMU2_ID)
 456                        continue;
 457
 458                /*Inform PE to stop */
 459                pe_dmem_write(pfe_pe_id, 1, PEMBOX_ADDR_TMU, 4);
 460                udelay(10);
 461
 462                /*Read status */
 463                if (!pe_dmem_read(pfe_pe_id, PEMBOX_ADDR_TMU + 4, 4))
 464                        printf("Failed to stop PE%d\n", pfe_pe_id);
 465        }
 466}
 467#endif
 468
 469static int pfe_command(struct cmd_tbl *cmdtp, int flag, int argc,
 470                       char *const argv[])
 471{
 472        if (argc == 1 || strcmp(argv[1], "help") == 0) {
 473                pfe_command_help();
 474                return CMD_RET_SUCCESS;
 475        }
 476
 477        if (strcmp(argv[1], "pe") == 0) {
 478                pfe_command_pe(argc, argv);
 479        } else if (strcmp(argv[1], "status") == 0) {
 480                pfe_command_status(argc, argv);
 481        } else if (strcmp(argv[1], "expt") == 0) {
 482                pfe_command_expt(argc, argv);
 483#ifdef PFE_RESET_WA
 484        } else if (strcmp(argv[1], "stop") == 0) {
 485                pfe_command_stop(argc, argv);
 486#endif
 487        } else {
 488                printf("Unknown option: %s\n", argv[1]);
 489                pfe_command_help();
 490                return CMD_RET_FAILURE;
 491        }
 492        return CMD_RET_SUCCESS;
 493}
 494
 495U_BOOT_CMD(
 496        pfe,    7,      1,      pfe_command,
 497        "Performs PFE lib utility functions",
 498        "Usage:\n"
 499        "pfe <options>"
 500);
 501