openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

pktspeed.c (21625B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        pktspeed.c
      8  * Purpose:     Run a TX or RX reload test to check DMA speed
      9  *
     10  * Test Parameters:
     11  *       PORT       - TX port
     12  *       RXPORT     - RX port
     13  *       PKTsize    - What size packets to use
     14  *       ALLOCsize  - What allocation size to use for packets
     15  *       ChainLen   - How many DMA'd packets to set up in loop
     16  *       Seconds    - How many seconds to run
     17  *
     18  *   Test reports speed once per second.
     19  *
     20  * Notes:       Code originally from appl/diag/txrx.c
     21  *              Moved here to address PR SDK/422
     22  */
     23 
     24 #include <sal/core/time.h>
     25 #include <sal/types.h>
     26 #include <sal/appl/io.h>
     27 #include <shared/bsl.h>
     28 #include <soc/types.h>
     29 #include <soc/cm.h>
     30 #include <soc/dma.h>
     31 #include <soc/dcb.h>
     32 #include <soc/drv.h>
     33 
     34 #include <bcm/tx.h>
     35 #include <bcm/pkt.h>
     36 #include <bcm/rx.h>
     37 #include <bcm/port.h>
     38 #include <bcm/cosq.h>
     39 #include <bcm/error.h>
     40 
     41 #ifdef BCM_CMICM_SUPPORT
     42 #include <soc/cmicm.h>
     43 #endif
     44 
     45 #include "testlist.h"
     46 
     47 #if defined (BCM_PETRA_SUPPORT)
     48 #include <soc/dpp/drv.h>
     49 #else
     50 #define SOC_DPP_PP_ENABLE(unit) (0)
     51 #endif
     52 
     53 #if defined (BCM_ESW_SUPPORT) || defined (BCM_PETRA_SUPPORT)
     54 
     55 #define TEST_FAIL -1
     56 #define TEST_OK    0
     57 
     58 typedef struct pktspeed_param_s {
     59         int unit,        /* Which unit to test on */
     60             tx_port,     /* packet TX port (TX/RX test) */
     61             rx_port,     /* packet RX port (RX test) */
     62             tx_packet_count,    /* tx packet count (RX test) */
     63             pkt_size,    /* Size of actual pkt */
     64             alloc_size,  /* Allocation size of packet */
     65             chain_len,   /* Number of pkts to set up per cycle */
     66             seconds,     /* Number of seconds to run */
     67             poll;        /* T=poll F=interrupt */
     68         int p_l_start;   /* first pkt length for iteration*/
     69         int p_l_end;     /* last pkt length for iteration */
     70         int p_l_inc;    /* pkt length increment between iterations */
     71     volatile COMPILER_DOUBLE count; /* Packet count */
     72 } pktspeed_param_t;
     73 
     74 static volatile int desc_intr_count = 0;
     75 static volatile int chain_intr_count = 0;
     76 
     77 static pktspeed_param_t     *pktspeed_param[SOC_MAX_NUM_DEVICES];
     78 
     79 /*
     80  * Function:
     81  *      pktspeed_print_param
     82  *
     83  * Purpose:
     84  *      Print parameter structure
     85  *
     86  * Parameters:
     87  *      psp             - parameter structure
     88  *
     89  * Returns:
     90  *      Allocated structure or NULL if alloc failed.
     91  */
     92 
     93 STATIC void
     94 pktspeed_print_param(pktspeed_param_t *psp)
     95 {
     96     if (psp != NULL) {
     97         cli_out("port=%d ",  psp->tx_port);
     98         cli_out("rx=%d ",    psp->rx_port);
     99         cli_out("pkt=%d ",   psp->pkt_size);
    100         cli_out("alloc=%d ", psp->alloc_size);
    101         cli_out("cl=%d ",    psp->chain_len);
    102         cli_out("sec=%d ",   psp->seconds);
    103         cli_out("\n");
    104     } else {
    105         cli_out("psp(null)\n");
    106     }
    107 }
    108 
    109 /*
    110  * Function:
    111  *      pktspeed_print_report
    112  *
    113  * Purpose:
    114  *      Print speed report 
    115  *
    116  * Parameters:
    117  *      psp             - parameter structure
    118  *      t_diff          - time difference (usec)
    119  *
    120  * Returns:
    121  *      void
    122  */
    123 
    124 STATIC void
    125 pktspeed_print_report(pktspeed_param_t *psp, COMPILER_DOUBLE count, int t_diff)
    126 {
    127     COMPILER_DOUBLE bytes_per_second, pkts_per_second;
    128     COMPILER_DOUBLE t_diff_dbl, pkt_size_dbl;
    129 
    130     if (psp != NULL) {
    131         COMPILER_32_TO_DOUBLE(t_diff_dbl, t_diff);
    132         COMPILER_32_TO_DOUBLE(pkt_size_dbl, psp->pkt_size);
    133         pkts_per_second = count/t_diff_dbl;
    134         bytes_per_second = (count * pkt_size_dbl)/t_diff_dbl;
    135         cli_out("    %15" COMPILER_DOUBLE_FORMAT
    136                 " %15" COMPILER_DOUBLE_FORMAT
    137                 " %15" COMPILER_DOUBLE_FORMAT "\n",
    138                 count, pkts_per_second, bytes_per_second);
    139     } else {
    140         cli_out("psp(null)\n");
    141     }
    142 }
    143 
    144 /*
    145  * Function:
    146  *      pktspeed_done_desc
    147  *
    148  * Purpose:
    149  *      dv_done_desc callout increments packet count in interrupt context
    150  *
    151  * Parameters:
    152  *      u               - unit
    153  *      dv              - dv struct
    154  *      dcb             - dcp struct
    155  *
    156  * Returns:
    157  *      void
    158  */
    159 
    160 STATIC void
    161 pktspeed_done_desc(int u, struct dv_s *dv, dcb_t *dcb)
    162 {
    163     pktspeed_param_t *psp = (pktspeed_param_t *)dv->dv_public1.ptr;
    164 
    165     psp->count += psp->chain_len;
    166 
    167     desc_intr_count += 1;
    168 }
    169 
    170 STATIC void
    171 pktspeed_done_chain(int unit, dv_t *dv_chain)
    172 {
    173     chain_intr_count += 1;
    174 }
    175 
    176 /*
    177  * Function:
    178  *      pktspeed_run_test
    179  *
    180  * Purpose:
    181  *      Run actual pktspeed test
    182  *
    183  * Parameters:
    184  *      tx_test         - TRUE for TX test, FALSE for RX test
    185  *      psp             - test parameters
    186  *
    187  * Returns:
    188  *      TEST_OK
    189  *      TEST_FAIL
    190  *
    191  * Notes:
    192  *      Could possibly use a pause scheme at the end of the while loop.
    193  */
    194 
    195 STATIC int
    196 pktspeed_run_test(int tx_test, pktspeed_param_t *psp)
    197 {
    198     pbmp_t tx_pbm;
    199     static pbmp_t empty_pbm;    /* Initialized to 0 automatically */
    200     char *pkt_data = NULL;
    201     dv_t *dv = NULL;
    202     sal_usecs_t start_time, cur_time;
    203     COMPILER_DOUBLE count;
    204     int t_diff, last_rpt;
    205     int tot_dcb;
    206     int i;
    207     int rv = TEST_OK;
    208     int rv2 = TEST_OK;
    209     dcb_t	*d;
    210     int channel;
    211     bcm_pkt_t *pkt = NULL;
    212     bcm_vlan_t tx_vlan = 0x123;
    213     bcm_pbmp_t pbmp;
    214     bcm_pbmp_t ubmp;
    215     bcm_gport_t sch_gport;
    216     bcm_gport_t egq_gport;
    217     static sal_mac_addr_t mac_dest = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
    218     static sal_mac_addr_t mac_src  = {0x02, 0x11, 0x22, 0x33, 0x44, 0x66};
    219 
    220     if (psp == NULL) {
    221         cli_out("pktspeed test: NULL param struct\n");
    222         return(TEST_FAIL);
    223     }
    224 
    225     COMPILER_32_TO_DOUBLE(count, 0);
    226 
    227     BCM_PBMP_CLEAR(pbmp);
    228     BCM_PBMP_CLEAR(ubmp);
    229 
    230     if (tx_test) {
    231 
    232         rv = bcm_port_enable_set(psp->unit, psp->tx_port, TRUE);
    233         if (rv != TEST_OK ) {
    234             goto done;
    235         }
    236         SOC_PBMP_PORT_SET(tx_pbm, psp->tx_port);
    237         channel = 0;
    238         if (soc_dma_chan_config(psp->unit, channel, DV_TX, SOC_DMA_F_DEFAULT) < 0) {
    239             cli_out("pktspeed test: Could not configure u %d, chan %d\n",
    240                     psp->unit,
    241                     channel);
    242             rv = TEST_FAIL;
    243             goto done;
    244         }
    245     } else {  /* Set ports to loopback and send a broadcast packet */        
    246         rv = bcm_port_loopback_set(psp->unit, psp->tx_port, BCM_PORT_LOOPBACK_MAC);
    247         if (rv != TEST_OK ) {
    248             goto done;
    249         }
    250         rv = bcm_port_loopback_set(psp->unit, psp->rx_port, BCM_PORT_LOOPBACK_MAC);
    251         if (rv != TEST_OK ) {
    252             goto done;
    253         }
    254         rv = bcm_port_enable_set(psp->unit, psp->tx_port, TRUE);
    255         if (rv != TEST_OK ) {
    256             goto done;
    257         }
    258         rv = bcm_port_enable_set(psp->unit, psp->rx_port, TRUE);
    259         if (rv != TEST_OK ) {
    260             goto done;
    261         }
    262         if ((bcm_pkt_alloc(psp->unit,
    263                            psp->pkt_size,
    264                            BCM_TX_CRC_REGEN, &pkt)) !=
    265                 BCM_E_NONE) {
    266             cli_out("Could not allocate packet to tx\n");
    267             return TEST_FAIL;
    268         }
    269         /* Set up broadcast packet */
    270         if (!SOC_IS_ARAD(psp->unit) || !SOC_DPP_PP_ENABLE(psp->unit)) {   
    271             BCM_PKT_HDR_DMAC_SET(pkt, mac_dest);
    272             BCM_PKT_HDR_SMAC_SET(pkt, mac_src);
    273             BCM_PKT_HDR_TPID_SET(pkt, ENET_DEFAULT_TPID);
    274             BCM_PKT_HDR_VTAG_CONTROL_SET(pkt, VLAN_CTRL(0, 0, 1));
    275         } else {
    276             /* Add the rx_port, rx_port and cpu port to the broadcast vlan domain */
    277             rv = bcm_vlan_create(psp->unit, tx_vlan);
    278             if (rv != TEST_OK ) {
    279                 goto done;
    280             }
    281             BCM_PBMP_PORT_ADD(pbmp, psp->tx_port);
    282             BCM_PBMP_PORT_ADD(pbmp, psp->rx_port);
    283             BCM_PBMP_PORT_ADD(pbmp, 0);
    284             rv = bcm_vlan_port_add(psp->unit, tx_vlan, pbmp, ubmp);
    285             if (rv != TEST_OK ) {
    286                 goto done;
    287             }
    288             /* Add the PTCH header */
    289             (pkt)->_pkt_data.data[0] = 0xD0;
    290             (pkt)->_pkt_data.data[1] = psp->tx_port;
    291             /* Add the Ethernet packet */
    292             sal_memcpy((pkt)->_pkt_data.data + 2, mac_dest, 6);
    293             sal_memcpy((pkt)->_pkt_data.data + 8, mac_src, 6);
    294             _BCM_HTONS_CVT_SET(pkt, ENET_DEFAULT_TPID, 14);
    295             _BCM_HTONS_CVT_SET(pkt, VLAN_CTRL(0, 0, tx_vlan), 16);
    296             /* Configure the CPU sch and egq scheduler as the rate of 1G bps */
    297             BCM_COSQ_GPORT_E2E_PORT_SET(sch_gport, 0);
    298             rv = bcm_cosq_gport_bandwidth_set(psp->unit, sch_gport, 0, 0, 10000000, 0);
    299             if (rv != TEST_OK ) {
    300                 goto done;
    301             }
    302             BCM_GPORT_LOCAL_SET(egq_gport, 0);
    303             rv = bcm_cosq_gport_bandwidth_set(psp->unit, egq_gport, 0, 0, 10000000, 0);
    304             if (rv != TEST_OK ) {
    305                 goto done;
    306             }
    307         }
    308         SOC_PBMP_PORT_SET(pkt->tx_pbmp, psp->tx_port);
    309         pkt->opcode = BCM_HG_OPCODE_BC;
    310 
    311         channel = 1;
    312         if (DV_RX != soc_dma_chan_dvt_get(psp->unit, channel)) {
    313             if (soc_dma_chan_config(psp->unit, channel, DV_RX, 0) < 0) {
    314                 cli_out("pktspeed test: Could not configure u %d, chan %d\n",
    315                         psp->unit,
    316                         channel);
    317                 rv = TEST_FAIL;
    318                 goto done;
    319             }
    320         }
    321         bcm_rx_queue_channel_set(psp->unit, -1, 1);
    322 
    323         {
    324             int i;
    325             for (i=0; i< psp->tx_packet_count; i++) {
    326                 /* Send broadcast packet */
    327                 if (bcm_tx(psp->unit, pkt, NULL) != BCM_E_NONE) {
    328                     cli_out("Failed to transmit packet\n");
    329                     return TEST_FAIL;
    330                 }
    331             }
    332         }
    333         
    334     }
    335 
    336     tot_dcb = psp->chain_len + 1;    /* Need one for reload */
    337 
    338     /* Round packet size up to 8 byte boundary */
    339     psp->alloc_size = (psp->alloc_size + 7) & 0xffffff8;
    340 
    341     if ((pkt_data = soc_cm_salloc(psp->unit, psp->alloc_size * psp->chain_len,
    342                                   "reload_data")) == NULL) {
    343         cli_out("Could not allocate packet data\n");
    344         rv = TEST_FAIL;
    345         goto done;
    346     }
    347 
    348     if ((dv = soc_dma_dv_alloc(psp->unit, tx_test ? DV_TX : DV_RX,
    349                                tot_dcb)) == NULL) {
    350         cli_out("Could not allocate DV\n");
    351         rv = TEST_FAIL;
    352         goto done;
    353     }
    354 
    355     /* DCBs MUST start off 0 */
    356     sal_memset(dv->dv_dcb, 0, SOC_DCB_SIZE(psp->unit) * tot_dcb);
    357 
    358     for (i = 0; i < psp->chain_len; i++) {
    359         if (soc_dma_desc_add(dv, (sal_vaddr_t)&pkt_data[i * psp->alloc_size],
    360                              psp->alloc_size, tx_pbm, empty_pbm,
    361                              empty_pbm, 0, NULL) < 0) {
    362             cli_out("Could not setup packet %d\n", i);
    363             rv = TEST_FAIL;
    364             goto done;
    365         }
    366         soc_dma_desc_end_packet(dv);
    367     }
    368 
    369     /* Set reload bit of last descriptor to point to first */
    370     if (soc_dma_rld_desc_add(dv, (sal_vaddr_t)dv->dv_dcb) < 0) {
    371         cli_out("Could not setup reload dcb\n");
    372         rv = TEST_FAIL;
    373         goto done;
    374     }
    375 
    376     d = SOC_DCB_IDX2PTR(psp->unit, dv->dv_dcb, dv->dv_vcnt - 1);
    377     SOC_DCB_CHAIN_SET(psp->unit, d, 1);
    378 
    379     /* Disable DMA interrupts - prevent soc_start_dma() from choking */
    380 #ifdef BCM_CMICM_SUPPORT
    381     if(soc_feature(psp->unit, soc_feature_cmicm)) {
    382         (void)soc_cmicm_intr0_disable(psp->unit,
    383                         IRQ_CMCx_DESC_DONE(channel) | IRQ_CMCx_CHAIN_DONE(channel));
    384     } else
    385 #endif
    386     {
    387         soc_intr_disable(psp->unit,
    388                          IRQ_DESC_DONE(channel) | IRQ_CHAIN_DONE(channel));
    389     }
    390     if (!psp->poll) {
    391         /* Setup callout if interrupt */
    392         dv->dv_done_desc   = pktspeed_done_desc;
    393         dv->dv_done_chain   = pktspeed_done_chain;
    394         dv->dv_public1.ptr = (void *)psp;
    395         dv->dv_flags      |= DV_F_NOTIFY_DSC | DV_F_NOTIFY_CHN;
    396     }
    397 
    398     cur_time = start_time = sal_time_usecs();
    399     t_diff = 0;
    400     last_rpt = 0;
    401     count = psp->count = 0;
    402 
    403     /* Start DMA */
    404     if (soc_dma_start(psp->unit, channel, dv) < 0) {
    405         cli_out("pktspeed test: Could not start dv, u %d, chan %d\n",
    406                 psp->unit, channel);
    407         rv = TEST_FAIL;
    408         goto done;
    409     }
    410 
    411     cli_out("Starting %s reload test:\n",
    412             tx_test ? "TX" : "RX");
    413     pktspeed_print_param(psp);
    414     cli_out("    %15s %15s %15s\n",
    415             "Total Pkts", "Pkts/Second", "Bytes/Second");
    416     while (t_diff <= psp->seconds) {
    417         if (psp->poll) {
    418             /* Monitor done bit in last real dcb */
    419             soc_cm_sinval(psp->unit, d, SOC_DCB_SIZE(psp->unit));
    420             if (SOC_DCB_DONE_GET(psp->unit, d)) {
    421                 psp->count += psp->chain_len;
    422                 count = psp->count;
    423                 SOC_DCB_DONE_SET(psp->unit, d, 0);
    424                 soc_cm_sflush(psp->unit, d, SOC_DCB_SIZE(psp->unit));
    425             }
    426         } else {
    427             sal_sleep(1);
    428             count = psp->count;
    429         }
    430         /* Report every second */
    431         if (t_diff >= last_rpt + 1) {
    432             last_rpt = t_diff;
    433             pktspeed_print_report(psp, count, t_diff);
    434         }  
    435         cur_time = sal_time_usecs();
    436         t_diff = SAL_USECS_SUB(cur_time, start_time)/1000000;
    437     }
    438 
    439 done:     
    440     if (SOC_IS_ARAD(psp->unit) && !tx_test) {
    441         bcm_vlan_port_remove(psp->unit, tx_vlan, pbmp);
    442         bcm_vlan_destroy(psp->unit, tx_vlan);
    443     }
    444     rv2 = bcm_port_loopback_set(psp->unit, psp->tx_port, BCM_PORT_LOOPBACK_NONE);
    445     if (rv2 != TEST_OK ) {
    446         cli_out("Re tx port loopback failed\n");
    447     }
    448     if (!tx_test) {
    449         rv2= bcm_port_loopback_set(psp->unit, psp->rx_port,
    450                               BCM_PORT_LOOPBACK_NONE);
    451         if (rv2 != TEST_OK ) {
    452             cli_out("Disable rx port loopback failed\n");
    453         }
    454     }
    455 	
    456     if (dv) {
    457         soc_dma_abort_dv(psp->unit, dv);
    458         soc_dma_dv_free(psp->unit, dv);
    459     }
    460     if (pkt_data) {
    461         soc_cm_sfree(psp->unit, pkt_data);
    462     }
    463     if (pkt) {
    464         bcm_pkt_free(psp->unit, pkt);
    465     }
    466 	
    467 
    468 
    469     return rv;
    470 }
    471 
    472 /*
    473  * Function:
    474  *      pktspeed_alloc
    475  *
    476  * Purpose:
    477  *      Allocate and initialize test parameter structure
    478  *
    479  * Parameters:
    480  *      unit            - Unit these parameters are for
    481  *
    482  * Returns:
    483  *      Allocated structure or NULL if alloc failed.
    484  */
    485 
    486 STATIC pktspeed_param_t *
    487 pktspeed_alloc(int unit)
    488 {
    489     bcm_port_t port = 0;
    490     pktspeed_param_t *psp =
    491       (pktspeed_param_t *)sal_alloc(sizeof(pktspeed_param_t),
    492                                     "Pktspeed test config");
    493 
    494     if (psp != NULL) {
    495         psp->unit       = unit;
    496         if(SOC_IS_APOLLO(unit) || SOC_IS_VALKYRIE2(unit)) {
    497             psp->tx_port = 30;
    498         } else if(SOC_IS_ENDURO(unit) || SOC_IS_HURRICANE(unit)) {
    499             psp->tx_port = 2;
    500         } else if (SOC_IS_KATANA(unit) || SOC_IS_GREYHOUND(unit)) {
    501             BCM_PBMP_ITER(PBMP_PORT_ALL(unit), port) { 
    502             break;
    503             }
    504             psp->tx_port = port;
    505         } else if (SOC_IS_ARAD(unit)) { 
    506             psp->tx_port = 13;
    507         } else {
    508             psp->tx_port = 1;
    509         }
    510         psp->rx_port    = -1;   /* Select automatically */
    511         if (!SOC_IS_ARAD(psp->unit)) {
    512             psp->tx_packet_count   = 100;
    513         } else {
    514             psp->tx_packet_count   = 1;
    515         }
    516         psp->pkt_size   = 68;
    517         psp->alloc_size = 68;
    518         psp->chain_len  = 1000;
    519         psp->seconds    = 10;
    520         psp->poll       = TRUE;
    521         COMPILER_32_TO_DOUBLE(psp->count, 0);
    522         psp->p_l_start = 0;  /* 0 means no iteration */
    523         psp->p_l_end = 0;
    524         psp->p_l_inc = 64;
    525     }   
    526     return psp;
    527 }
    528 
    529 /*
    530  * Function:
    531  *      pktspeed_free
    532  *
    533  * Purpose:
    534  *      Free test parameter structure
    535  *
    536  * Parameters:
    537  *      psp             - parameter structure pointer
    538  *
    539  * Returns:
    540  *      TEST_OK
    541  *      TEST_FAIL
    542  */
    543 
    544 STATIC int pktspeed_free(pktspeed_param_t *psp)
    545 {
    546     int rv = TEST_FAIL;
    547 
    548     if (!psp) {
    549         return rv;
    550     }
    551     sal_free(psp);
    552 
    553     return TEST_OK;
    554 }
    555 
    556 /*
    557  * Function:
    558  *      pktspeed_test_init
    559  *
    560  * Purpose:
    561  *      Parse test arguments and save parameter structure locally
    562  *
    563  * Parameters:
    564  *      unit            - unit to test
    565  *      args            - test arguments
    566  *      pa              - test cookie (not used)
    567  *
    568  * Returns:
    569  *      TEST_OK
    570  *      TEST_FAIL
    571  */
    572 
    573 int
    574 pktspeed_test_init(int unit, args_t *args, void **pa)
    575 {
    576     parse_table_t	pt;
    577     pktspeed_param_t    *psp = pktspeed_alloc(unit);
    578 
    579     if (psp == NULL) {
    580         cli_out("%s: out of memory\n", ARG_CMD(args));
    581         return(TEST_FAIL);
    582     }
    583 
    584     parse_table_init(unit, &pt);
    585 
    586     parse_table_add(&pt, "PORT", PQ_DFL|PQ_PORT, 0,
    587                     &psp->tx_port, NULL);
    588     parse_table_add(&pt, "RXport", PQ_DFL|PQ_PORT, 0,
    589                     &psp->rx_port, NULL);
    590     parse_table_add(&pt, "TxPktCount", PQ_DFL|PQ_INT, 0,
    591                     &psp->tx_packet_count, NULL);
    592     parse_table_add(&pt, "PKTsize", PQ_DFL|PQ_INT, 0,
    593                     &psp->pkt_size, NULL);
    594     parse_table_add(&pt, "ALLOCsize", PQ_DFL|PQ_INT, 0,
    595                     &psp->alloc_size, NULL);
    596     parse_table_add(&pt, "ChainLen", PQ_DFL|PQ_INT, 0,
    597                     &psp->chain_len, NULL);
    598     parse_table_add(&pt, "SEConds", PQ_DFL|PQ_INT, 0,
    599                     &psp->seconds, NULL);
    600     parse_table_add(&pt, "LengthStart", PQ_DFL|PQ_INT, 0,
    601                     &psp->p_l_start, NULL);
    602     parse_table_add(&pt, "LengthEnd", PQ_DFL|PQ_INT, 0,
    603                     &psp->p_l_end, NULL);
    604     parse_table_add(&pt, "LengthInc", PQ_DFL|PQ_INT, 0,
    605                     &psp->p_l_inc, NULL);
    606 
    607     /* Parse remaining arguments */
    608     if (0 > parse_arg_eq(args, &pt)) {
    609     	test_error(unit,
    610     		   "%s: Invalid option: %s\n",
    611     		   ARG_CMD(args),
    612     		   ARG_CUR(args) ? ARG_CUR(args) : "*");
    613     	parse_arg_eq_done(&pt);
    614     	goto fail;
    615     }
    616     parse_arg_eq_done(&pt);
    617 
    618     if (psp->pkt_size > psp->alloc_size) {
    619     	test_error(unit,
    620                        "%s: Error: packet size > alloc size\n",
    621                        ARG_CMD(args));
    622     	parse_arg_eq_done(&pt);
    623     	goto fail;
    624     }
    625     parse_arg_eq_done(&pt);
    626 
    627     if (psp->rx_port < 0) {     /* Find an unused port */
    628         int p;
    629 
    630         /* Find first available port != tx_port */
    631         PBMP_ITER(PBMP_PORT_ALL(unit), p) {
    632             if (p != psp->tx_port) {
    633                 psp->rx_port = p;
    634                 break;
    635             }
    636         }
    637 
    638         /* Check to see if one was found */
    639         if (psp->rx_port < 0) {
    640             test_error(unit,
    641                        "%s: Could not find an available RX port.\n",
    642                        ARG_CMD(args));
    643             goto fail;
    644         }
    645 
    646     } else {                    /* RX port specified */
    647 
    648         /* Make sure selected RX port is valid */
    649         if (!BCM_PBMP_MEMBER(PBMP_PORT_ALL(unit), psp->rx_port)) {
    650             test_error(unit,
    651                        "%s: Invalid RX port %d.\n",
    652                        ARG_CMD(args), psp->rx_port);
    653             goto fail;
    654         }
    655     }
    656 
    657     /* Make sure TX port is valid, too */
    658     if (!BCM_PBMP_MEMBER(PBMP_PORT_ALL(unit), psp->tx_port)) {
    659         test_error(unit,
    660                    "%s: Invalid TX port %d.\n",
    661                    ARG_CMD(args), psp->tx_port);
    662         goto fail;
    663     }
    664 
    665     pktspeed_param[unit] = psp;
    666     
    667 
    668     return TEST_OK;
    669 fail:
    670     if (psp) {
    671         sal_free(psp);
    672     }
    673     return(TEST_FAIL);
    674 }
    675 
    676 /*
    677  * Function:
    678  *      pktspeed_test_tx
    679  *
    680  * Purpose:
    681  *      Runs TX test
    682  *
    683  * Parameters:
    684  *      unit            - unit to test
    685  *      a               - test arguments (ignored)
    686  *      pa              - test cookie (ignored)
    687  *
    688  * Returns:
    689  *      TEST_OK
    690  *      TEST_FAIL
    691  */
    692 
    693 int
    694 pktspeed_test_tx(int unit, args_t *a, void *pa)
    695 {
    696     pktspeed_param_t *psp = pktspeed_param[unit];
    697     int rv = TEST_OK;
    698     int len;
    699 
    700     if (psp->p_l_start == 0) { /* single length only */
    701         psp->p_l_start = psp->p_l_end = psp->alloc_size;
    702     }
    703 
    704     for (len = psp->p_l_start; len <= psp->p_l_end; len += psp->p_l_inc) {
    705         psp->alloc_size = len;  /* alloc size placed in DCB determines amount
    706                                    of data tx; pkt_size is not used in tx test */
    707         rv = pktspeed_run_test(TRUE, psp);
    708         if (rv != TEST_OK) {
    709             break;
    710         }
    711     }
    712 
    713     return rv;
    714 }
    715 
    716 /*
    717  * Function:
    718  *      pktspeed_test_rx
    719  *
    720  * Purpose:
    721  *      Runs RX test
    722  *
    723  * Parameters:
    724  *      unit            - unit to test
    725  *      a               - test arguments (ignored)
    726  *      pa              - test cookie (ignored)
    727  *
    728  * Returns:
    729  *      TEST_OK
    730  *      TEST_FAIL
    731  */
    732 
    733 int
    734 pktspeed_test_rx(int unit, args_t *a, void *pa)
    735 {
    736     pktspeed_param_t *psp = pktspeed_param[unit];
    737     int rv = TEST_OK;
    738     int len;
    739 
    740     if (psp->p_l_start == 0) { /* single length only */
    741         psp->p_l_start = psp->p_l_end = psp->pkt_size;
    742     }
    743 
    744     for (len = psp->p_l_start; len <= psp->p_l_end; len += psp->p_l_inc) {
    745         psp->pkt_size = len;
    746         rv = pktspeed_run_test(FALSE, psp);
    747         if (rv != TEST_OK) {
    748             break;
    749         }
    750     }
    751 
    752     return rv;
    753 }
    754 
    755 /*
    756  * Function:
    757  *      pktspeed_test_done
    758  *
    759  * Purpose:
    760  *      Cleans up after tx or rx test completes
    761  *
    762  * Parameters:
    763  *      unit            - unit to test
    764  *      pa              - test cookie (ignored)
    765  *
    766  * Returns:
    767  *      TEST_OK
    768  *      TEST_FAIL
    769  */
    770 
    771 int
    772 pktspeed_test_done(int unit, void *pa)
    773 {
    774     return  pktspeed_free(pktspeed_param[unit]);
    775 }
    776 
    777 #endif /* BCM_ESW_SUPPORT */