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

pcktwatch.c (54600B)


      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  * Packet Watcher
      8  */
      9 
     10 #include <sal/types.h>
     11 #include <shared/bsl.h>
     12 #ifndef __KERNEL__
     13 #include <sys/types.h>
     14 #include <netinet/in.h>
     15 #endif
     16 
     17 #include <soc/debug.h>
     18 #include <soc/cm.h>
     19 #include <soc/dma.h>
     20 
     21 #include <sal/appl/io.h>
     22 #include <sal/appl/sal.h>
     23 #include <sal/core/thread.h>
     24 #include <sal/core/sync.h>
     25 #include <sal/core/spl.h>
     26 #include <sal/core/libc.h>
     27 
     28 #include <appl/diag/shell.h>
     29 #include <appl/diag/parse.h>
     30 #include <appl/diag/system.h>
     31 #include <appl/diag/decode.h>
     32 
     33 #include <bcm/rx.h>
     34 #include <bcm/error.h>
     35 
     36 #ifdef GHS
     37 #define d_packet_format(pfx, decode, pkt, count, p)
     38 #endif
     39 
     40 /*
     41  * Maximum packet size we will read in.
     42  */
     43 #define	PW_PACKET_SIZE		10240
     44 
     45 #define PW_COUNT_DEFAULT	100
     46 
     47 static char pw_name[SOC_MAX_NUM_DEVICES][16];
     48 
     49 /*
     50  * Define 2 of the public fields in the dv structure for our use.
     51  */
     52 #define	dv_pw_pup	dv_public1.ptr
     53 #define	dv_pw_chan	dv_public2.u32
     54 
     55 
     56 /*
     57  * Typedef:	pup_t
     58  * Purpose:	Maps out each packet array entry - pkt_cnt is sort of
     59  * 		useless, but it makes life easier so we use it to track
     60  *		the pack # received.
     61  *
     62  * Notes:	Each entry is either FREE or on a circular/double linked 
     63  *		list used for the LOG. When the LOG is full, there are 3 extra
     64  *		pups used to suppor the up to 3 outstanding DMA operations.
     65  */
     66 typedef struct pup_s {
     67     struct pup_s *pup_next, *pup_prev;	/* Next and previous pointers */
     68     dv_t	    *pup_esw_dv; 	/* DMA descriptor, ESW SOC mode only */
     69     int		pup_seqno; 		/* Packet # */
     70     void	*pup_pkt; 		/* Actual packet pointer, for soc */
     71     bcm_pkt_t   rx_pkt;                 /* Packet data for RX */
     72 } pup_t;
     73 
     74 #define REPORT_COUNT	0x01		/* Report packet count */
     75 #define	REPORT_RAW	0x02		/* Report Raw packet data */
     76 #define REPORT_DECODE	0x04		/* Report Decode */
     77 #define	REPORT_DMA	0x08		/* Report RX Dma */
     78 #define	REPORT_CHANNEL	0x10		/* Report RX channel */
     79 
     80 typedef	struct pwu_s {
     81     volatile uint32 pu_flags;		/* Flags this unit PU_F_XXX */
     82 #   define	PU_F_RUN	0x01
     83 #   define	PU_F_STOP	0x02
     84 #   define	PU_F_SYNC	0x04	/* Wake up request thread */
     85     sal_mutex_t	pu_lock;		/* Syncronize updates */
     86     sal_spinlock_t	pu_spinlock;	/* Protect updates */
     87     int32	pu_channel;		/* RX channel list 1 << ch # */
     88 #   define	PU_CHANNEL(_c)	(1 << (_c))
     89     uint32	pu_report;		/* Reporting level */
     90     uint32	pu_dump_options;	/* Reporting level when dumping logs */
     91     COMPILER_DOUBLE	pu_count_last;	/* Last count displayed */
     92     COMPILER_DOUBLE	pu_count_time;	/* Last time count was displayed */
     93     sal_thread_t pu_pid;		/* pid this unit */
     94     sal_sem_t	pu_sema;		/* Sleep semaphore this unit */
     95     sal_sem_t	pu_sync;		/* Sync command semaphore */
     96 
     97     /*
     98      * pu_pending - a single linked list, where the head's prev pointer
     99      *                 points to the tail.
    100      * pu_ch_active  - pointers to DMA active on the given channel.
    101      */
    102 
    103     VOL pup_t	*pu_pending; 	/* Pending interrupt servicing */
    104     VOL pup_t	*pu_ch_active[MAX_N_DMA_CHAN+1]; /* Active DMA operations */
    105     int		pu_ch_count[MAX_N_DMA_CHAN+1]; /* # received on channel */
    106     pup_t	*pu_log;		/* Last N packets - head is LRU */
    107     pup_t	*pu_log_free;		/* Last N packets - head is LRU */
    108     pup_t	*pup_list;		/* List of all PUPs for free */
    109     int		pu_log_cnt;		/* # packets on LOG list */
    110     int		pu_log_max;		/* Max # packets logged */
    111 #   define	PU_LOG_CNT	64	/* Default # log entries */
    112     uint32	pu_packet_received;	/* total # received packets */
    113     int		pu_interval;		/* usec between pkt rcv & next dma */
    114 
    115     int         mode;                   /* What mode are we in */
    116 #define         PW_MODE_RX              0
    117 #define         PW_MODE_SOC             1
    118 #define         PW_MODE_PMUX            2
    119 #define PW_INIT_STRINGS \
    120     "RX", \
    121     "SOC", \
    122     "PMUX"
    123     int         chan;
    124     int         rx_pri;
    125     uint32      rx_flags;
    126     int         pkt_size;
    127     bcm_rx_cfg_t  rx_cfg;
    128     int         rate;      /* Current global rate, pps */
    129     int         last_pkt_count;   /* How many pkts processed last wake */
    130 
    131     int         init_done;
    132     uint32      hdr_dump;         /* Header dump for cmicx */
    133 } pwu_t;
    134 
    135 char *pw_modes[3] = {PW_INIT_STRINGS};
    136 
    137 STATIC bcm_rx_t         pw_rx_callback(int unit, bcm_pkt_t *pkt,
    138                                        void *cookie);
    139 
    140 STATIC void             pw_cleanup_dma(int unit);
    141 STATIC pup_t *          pw_pup_alloc(int unit);
    142 STATIC void             pw_pup_free(int unit, pup_t *pup);
    143 STATIC void             pw_dump_packet(int unit, pup_t *pup, uint32 report);
    144 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
    145 STATIC void             pw_esw_done_intr(int unit, dv_t *dv);
    146 STATIC int              pw_channel_config(int unit);
    147 #endif /* BCM_ESW_SUPPORT */
    148 STATIC cmd_result_t     pw_start_channel(int unit, dma_chan_t chan);
    149 STATIC void             pw_thread(void *up);
    150 STATIC void             pw_process_pending(int unit);
    151 STATIC cmd_result_t     pw_dump_log(int unit, int n);
    152 
    153 char pw_usage[] =
    154     "Parameters: [report +/-<values>] [stop|start] [count]\n"
    155 #ifndef COMPILER_STRING_CONST_LIMIT
    156     "\tlog # - specifies # packets to remember\n"
    157     "\tdump [# | options] - # > 0 dumps # packets from start of log\n"
    158     "\t                     # < 0 dumps last # packets\n"
    159     "\t                     nothing - dumps all logs\n"
    160     "\t                     options - count   - print packet # only\n"
    161     "\t                               decode  - attempt to decode packet\n"
    162     "\t                               raw     - dump raw byte stream (host order)\n"
    163     "\t                               dma     - dump DMA descriptors (SOC mode only)\n"
    164     "\t                               channel - dump DMA channel\n"
    165     "\t                               Prepend + to set, - to clear, nothing to toggle\n"
    166     "\tinterval # - # us to wait after a packet arrives before next\n"
    167     "\t        DMA starts (SOC mode only)\n"
    168     "\treport- count   - print packet # only\n"
    169     "\t        decode  - attempt to decode packet\n"
    170     "\t        raw     - dump raw byte stream (host order)\n"
    171     "\t        dma     - dump DMA descriptors (SOC mode only)\n"
    172     "\t        channel - dump DMA channel\n"
    173     "\t        Prepend + to set, - to clear, nothing to toggle\n"
    174     "\tquiet - disable all reporting\n"
    175     "\tchannel x [y z] - configure PW to use the specified RX channels\n"
    176     "\trate    n       - Set the globally accepted pps rate\n"
    177     "\tstart - start the PW-daemon\n"
    178     "\tstop  - stop the PW-daemon and deallocate log space\n"
    179     "\tcount - print # packets received.\n"
    180     "\treset - reinitialize configuration from bcm_rx_* API state\n"
    181     "\tmode [soc | rx]  - set packetwatcher mode\n"
    182     "\t        With no parameters, reports current mode\n"
    183     "\t        soc      - Use the soc layer calls directly\n"
    184     "\t        rx       - Use the RX API\n"
    185 #endif
    186     ;
    187 
    188 pwu_t	pw_units[SOC_MAX_NUM_DEVICES];
    189 
    190 STATIC void
    191 pw_init(int unit)
    192 {
    193     pwu_t	*pu = &pw_units[unit];	/* Control this unit */
    194 
    195     if (pu->init_done) {
    196         return;
    197     }
    198 
    199     sal_snprintf(pw_name[unit], sizeof(pw_name[unit]), "bcmPW.%d", unit);
    200 
    201     /* 
    202      * sync and lock semaphores are only created once, the others
    203      * are created and destroyed every time the packet watcher is
    204      * started and stopped.
    205      *
    206      * We need to check if they already exist to support the
    207      * pw reset option.
    208      */
    209     if (!pu->pu_sync) {
    210         pu->pu_sync = sal_sem_create("pw_sync", sal_sem_BINARY, 0);
    211     }
    212     if (!pu->pu_lock) {
    213         pu->pu_lock = sal_mutex_create("pw_lock");
    214     }
    215     if (!pu->pu_spinlock) {
    216         pu->pu_spinlock = sal_spinlock_create("pw_spinlock");
    217     }
    218 
    219     if (!pu->pu_sync || !pu->pu_lock || !pu->pu_spinlock) {
    220         cli_out("%s ERROR:  Could not allocate sync/lock\n", pw_name[unit]);
    221     }
    222     pu->chan = 0;
    223     pu->rx_pri = 100;
    224     pu->rx_flags = BCM_RCO_F_ALL_COS;
    225     pu->pkt_size = 10 * 1024;
    226 
    227     bcm_rx_cfg_get(unit, &pu->rx_cfg);
    228     pu->rate = pu->rx_cfg.global_pps;
    229 
    230     pu->init_done = TRUE;
    231 }
    232 
    233 STATIC int
    234 _pw_set_rate(int unit)
    235 {
    236     pwu_t	*pu = &pw_units[unit];	/* Control this unit */
    237     int          rv = BCM_E_NONE;
    238 
    239     /* Always calculate SOC interval in case modes are switched. */
    240     if (pu->rate <= 0) {
    241 	pu->pu_interval = 1000000;
    242 	pu->rate = 0;
    243     } else {
    244 	pu->pu_interval = 1000000 / pu->rate;
    245     }
    246 
    247     switch (pu->mode) {
    248         case PW_MODE_RX:
    249             if ((rv = bcm_rx_rate_set(unit, pu->rate)) < 0) {
    250                 cli_out("PW RX rate set error: %s.\n", bcm_errmsg(rv));
    251             }
    252             /* Then set the burst size to equal the rate */
    253             if ((rv = bcm_rx_burst_set(unit, pu->rate)) < 0) {
    254                 cli_out("PW RX burst set error: %s.\n", bcm_errmsg(rv));
    255             }
    256             break;
    257         case PW_MODE_SOC:
    258             break;
    259         default:
    260             break;
    261     }
    262 
    263     return rv;
    264 }
    265 
    266 #define	PW_LOCK(_u)	sal_mutex_take(pw_units[_u].pu_lock, \
    267 				       sal_mutex_FOREVER)
    268 #define	PW_UNLOCK(_u)	sal_mutex_give(pw_units[_u].pu_lock)
    269 #define	PW_SPIN_LOCK(_u)    sal_spinlock_lock(pw_units[_u].pu_spinlock)
    270 #define	PW_SPIN_UNLOCK(_u)  sal_spinlock_unlock(pw_units[_u].pu_spinlock)
    271 
    272 int
    273 pw_start(int unit, int sync)
    274 /*
    275  * Function: 	pw_start
    276  * Purpose:	Start the packet watcher
    277  * Parameters:	unit - unit to start.
    278  *		sync - if true, wait for watcher to start.
    279  * Returns:	0 - success, -1 failed.
    280  */
    281 {
    282     pwu_t	*pu = &pw_units[unit];	/* Control this unit */
    283 
    284     pw_init(unit);
    285     if (pu->pu_sync == NULL || pu->pu_lock == NULL || pu->pu_spinlock == NULL) {
    286         return -1;
    287     }
    288 
    289     sal_memset(pu->pu_ch_active, 0, sizeof(pu->pu_ch_active));
    290     sal_memset(pu->pu_ch_count, 0, sizeof(pu->pu_ch_count));
    291 
    292     pu->pu_pending = NULL;
    293     pu->pu_log = NULL;
    294     pu->pu_log_free = NULL;
    295     pu->pu_log_cnt = 0;
    296 #ifdef BCM_PETRA_SUPPORT
    297     if (SOC_IS_ARAD(unit) ) {
    298        if (bcm_rx_active(unit)) {
    299           bcm_rx_stop(unit, NULL);
    300        }
    301     }
    302 #endif /* BCM_PETRA_SUPPORT */
    303 
    304 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
    305     if (SOC_IS_ESW(unit) || SOC_IS_ARAD(unit)) {
    306         if (pw_channel_config(unit) < 0) {
    307 	    return -1;
    308         }
    309     }
    310 #endif
    311 
    312     pu->pu_sema = sal_sem_create("pw_thread", sal_sem_BINARY, 0);
    313     if (pu->pu_sema == 0) {
    314         return -1;
    315     }
    316 
    317     pu->pu_flags |= PU_F_RUN;
    318     if (sync) {
    319 	pu->pu_flags |= PU_F_SYNC;
    320     }
    321 
    322     pu->pu_pid =
    323 	sal_thread_create(pw_name[unit], SAL_THREAD_STKSZ,
    324 			  soc_property_get(unit, spn_DIAG_PW_THREAD_PRI, 100),
    325 			  pw_thread, INT_TO_PTR(unit));
    326 
    327     if (pu->pu_pid == SAL_THREAD_ERROR) {
    328 	cli_out("%s: Unable to start task\n", pw_name[unit]);
    329 	sal_sem_destroy(pu->pu_sema);
    330 	pu->pu_sema = 0;
    331 	pu->pu_flags &= PU_F_RUN|PU_F_SYNC;
    332 	return -1;
    333     }
    334 
    335     pu->pu_count_last = 0;
    336     pu->pu_count_time = SAL_TIME_DOUBLE();
    337 
    338     pu->pu_packet_received = 0;
    339 
    340     if (sync) {
    341 	if (sal_sem_take(pu->pu_sync, sal_sem_FOREVER)) {
    342 	    cli_out("%s: Failed to wait for start\n", pw_name[unit]);
    343 	    return -1;
    344 	}
    345     }
    346 
    347     return 0;
    348 }    
    349 
    350 cmd_result_t 
    351 pw_stop(int unit, int sync)
    352 /*
    353  * Function: 	pw_stop
    354  * Purpose:	Stop the packet watcher
    355  * Parameters:	unit - unit to stop.
    356  *		sync - if true, wait for watcher to finish.
    357  * Returns:	0 - success, -1 failed.
    358  */
    359 {
    360     pwu_t	*pu = &pw_units[unit];	/* Control this unit */	
    361     soc_timeout_t  to;
    362     sal_usecs_t     pw_timeout;
    363 
    364     pw_timeout = soc_property_get(unit, spn_CDMA_TIMEOUT_USEC, 10000000);
    365 
    366     pu->pu_flags |= PU_F_STOP;
    367     if (sync) {
    368 	pu->pu_flags |= PU_F_SYNC;
    369     }
    370     sal_sem_give(pu->pu_sema);
    371     soc_timeout_init(&to, pw_timeout, 0);
    372 
    373     /* Check for pw_thread exit */
    374     while (pu->pu_pid != SAL_THREAD_ERROR) {
    375 	  /* Handle the case of pw_thread not exiting */
    376          if (soc_timeout_check(&to)) {
    377              cli_out("pw_stop: pw_thread did not exit\n");
    378              pu->pu_pid = SAL_THREAD_ERROR;
    379              break;
    380          }
    381 	  
    382          sal_usleep(80000);
    383     }
    384 	
    385     if  (pu->pu_pid == SAL_THREAD_ERROR) {
    386         /* Abnormal thread exit: Free semaphore resource */
    387     /*    coverity[check_after_deref]    */
    388         if (pu->pu_sema) {
    389             /* Must check, because may have been destroyed by pw_exit */
    390             sal_sem_destroy(pu->pu_sema);
    391             pu->pu_sema = 0;
    392         }
    393     }
    394 
    395     if (sync) {
    396 	    (void)sal_sem_take(pu->pu_sync, sal_sem_FOREVER);
    397     } else {
    398 	    cli_out("%s: Termination requested...\n", pw_name[unit]);
    399     }
    400     return CMD_OK;
    401 }
    402 
    403 int
    404 pw_running(int unit)
    405 /*
    406  * Function:	pw_running
    407  * Purpose:	Determine if packet watcher is running for the specified
    408  *		unit.
    409  * Parameters:	unit - unit #
    410  * Returns:	0 - not running, !0 - running
    411  */
    412 {
    413     return pw_units[unit].pu_flags & PU_F_RUN;
    414 }
    415 
    416 STATIC	void
    417 pw_exit(int unit, int stat)
    418 /*
    419  * Function:	pw_exit
    420  * Purpose:	Exit a packetwatcher thread.
    421  * Parameters:	unit - unit #.
    422  * 		stat - exit status (passed to exit).
    423  * Returns:	Does not return.
    424  *
    425  * Notes:	ASSUMES LOCK held on entry, released in this routine
    426  */
    427 {
    428     pwu_t *pu = &pw_units[unit];
    429     int rv;
    430     char thread_name[SAL_THREAD_NAME_MAX_LEN];
    431     sal_thread_t	thread;
    432 #if defined(BCM_PETRA_SUPPORT)
    433     bcm_rx_cfg_t cfg;
    434 #endif
    435 
    436     thread = sal_thread_self();
    437     thread_name[0] = 0;
    438     sal_thread_name(thread, thread_name, sizeof (thread_name));
    439     
    440     switch (pu->mode) {
    441         case PW_MODE_RX:
    442             /* pw_exit() is called holding the lock. Give it up
    443              * momentarily while we stop the RX task.
    444              */
    445             PW_UNLOCK(unit);
    446             if ((rv = bcm_rx_stop(unit, NULL)) < 0) {
    447                 cli_out("PW stop error: Cannot stop RX: %s.\n",
    448                         bcm_errmsg(rv));
    449             }
    450 #if defined(BCM_PETRA_SUPPORT)
    451             /* init rx cfg as no cos */
    452             bcm_rx_cfg_t_init(&cfg);
    453             cfg.pkt_size = 16*1024;
    454             cfg.pkts_per_chain = 15;
    455             cfg.global_pps = 0;
    456             cfg.max_burst = 15;
    457             cfg.rx_alloc = NULL;
    458             cfg.rx_free = NULL;
    459             cfg.flags = 0;
    460             cfg.chan_cfg[1].chains = 4;
    461             cfg.chan_cfg[1].flags = 0;
    462             cfg.chan_cfg[1].cos_bmp = 0xFffffffF;
    463 
    464             if ((rv = bcm_rx_start(unit, &cfg)) < 0) {
    465                 cli_out("PW re-start error: Cannot re-start RX: %s.\n",
    466                         bcm_errmsg(rv));
    467             }
    468 #endif
    469             if ((rv = bcm_rx_queue_unregister(unit, BCM_RX_COS_ALL, 
    470                                               pw_rx_callback, pu->rx_pri))
    471                        < 0) {
    472                 cli_out("PW stop error: Cannot unregister handler: %s.\n",
    473                         bcm_errmsg(rv));
    474             }
    475             PW_LOCK(unit);
    476             
    477             break;
    478 #if defined(BCM_PETRA_SUPPORT)
    479         case PW_MODE_SOC:
    480             PW_UNLOCK(unit);
    481             if (bcm_rx_active(unit)) {
    482                 if ((rv = bcm_rx_stop(unit, NULL)) < 0) {
    483                     cli_out("PW stop error: Cannot stop RX: %s.\n",
    484                             bcm_errmsg(rv));
    485                 }
    486             }
    487             /* init rx cfg as no cos */
    488             bcm_rx_cfg_t_init(&cfg);
    489             cfg.pkt_size = 16*1024;
    490             cfg.pkts_per_chain = 15;
    491             cfg.global_pps = 0;
    492             cfg.max_burst = 15;
    493             cfg.rx_alloc = NULL;
    494             cfg.rx_free = NULL;
    495             cfg.flags = 0;
    496             cfg.chan_cfg[1].chains = 4;
    497             cfg.chan_cfg[1].flags = 0;
    498             cfg.chan_cfg[1].cos_bmp = 0xFffffffF;
    499 
    500             if ((rv = bcm_rx_start(unit, &cfg)) < 0) {
    501                 cli_out("PW re-start error: Cannot re-start RX: %s.\n",
    502                         bcm_errmsg(rv));
    503             }
    504             PW_LOCK(unit);
    505             break;
    506 #endif
    507         default:
    508             break;
    509     }
    510 
    511     if (pu->pu_sema) {
    512 	sal_sem_destroy(pu->pu_sema);
    513 	pu->pu_sema = 0;
    514     }
    515 
    516     pu->pu_pid = SAL_THREAD_ERROR;
    517 
    518     /* Put logs on the free list - not fast but .... oh well */
    519 
    520     if (pu->pu_log != NULL) {
    521 	pu->pu_log->pup_prev->pup_next = NULL; /* NUll list */
    522 	while (pu->pu_log != NULL) {
    523 	    pup_t	*pup = pu->pu_log->pup_next;
    524 	    pw_pup_free(unit, pu->pu_log);
    525 	    pu->pu_log = pup;
    526 	}
    527     }
    528     
    529     /* Now free the free list */
    530 
    531     while (pu->pu_log_free) {
    532 	pup_t	*pup = pu->pu_log_free;
    533 	pu->pu_log_free = pup->pup_next;
    534         if (pu->mode == PW_MODE_SOC) {
    535 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
    536             soc_dma_dv_free(unit, pup->pup_esw_dv);
    537 #endif
    538             soc_cm_sfree(unit, pup->pup_pkt);
    539         }
    540     }
    541     if (pu->pup_list) {
    542         sal_free(pu->pup_list);
    543     }
    544 
    545     if (pu->pu_flags & PU_F_SYNC) {
    546 	sal_sem_give(pu->pu_sync);
    547     } else {
    548         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    549                     (BSL_META_U(unit,
    550                                 "PW-Daemon[%d]: Exiting\n"), unit));
    551     }
    552 
    553     pu->pu_flags = 0;
    554 
    555     PW_UNLOCK(unit);   
    556     if (stat < 0) {
    557         LOG_ERROR(BSL_LS_SOC_PKT,
    558                   (BSL_META_U(unit,
    559                               "AbnormalThreadExit:%s\n"), thread_name));  
    560     }
    561     
    562     sal_thread_exit(stat);
    563 }
    564 
    565 /* Start the packet watcher operation depending on the mode */
    566 STATIC int
    567 _pw_start_op(int unit)
    568 {
    569     pwu_t       *pu = &pw_units[unit];
    570     int pkt_size;
    571     int rv = BCM_E_NONE;
    572 
    573     switch (pu->mode) {
    574     case PW_MODE_RX:
    575         pu->rx_cfg.global_pps = pu->rate;
    576 
    577         /*
    578          * Allow the packet watcher to run in truncating mode
    579          * by allocating smaller Rx buffers and accepting
    580          * oversized packets on all Rx DMA channels.
    581          */
    582         pkt_size = soc_property_get(unit, spn_DIAG_PW_BUFFER_SIZE, -1);
    583 
    584         if (pkt_size >= 68) {
    585             int chan;
    586             dma_chan_t  dma_chan;
    587             pu->rx_cfg.pkt_size = pkt_size;
    588 
    589             if (soc_feature(unit, soc_feature_cmicx)) {
    590                 dma_chan = BCM_CMICX_RX_CHANNELS;
    591             } else {
    592                 dma_chan = BCM_RX_CHANNELS;
    593             }
    594 
    595             for (chan = 0; chan < dma_chan; chan++) {
    596                 pu->rx_cfg.chan_cfg[chan].flags |= BCM_RX_F_OVERSIZED_OK;
    597             }
    598         }
    599 
    600         if ((rv = bcm_rx_start(unit, &pu->rx_cfg)) < 0) {
    601             return rv;
    602         }
    603 
    604         if ((rv = bcm_rx_queue_register(unit, "RX CMD", BCM_RX_COS_ALL, 
    605                       pw_rx_callback, pu->rx_pri, NULL, pu->rx_flags)) < 0) {
    606             return rv;
    607         }
    608         break;
    609     case PW_MODE_SOC:
    610         if (pu->pu_channel == 0) {              /* Use default RX channel */
    611             pw_start_channel(unit, -1);
    612         } else {
    613             dma_chan_t  chan;
    614             dma_chan_t  dma_chan;
    615 
    616             if (soc_feature(unit, soc_feature_cmicx)) {
    617                 dma_chan = CMICX_N_DMA_CHAN;
    618             } else {
    619                 dma_chan = N_DMA_CHAN;
    620             }
    621             for (chan = 0; chan < dma_chan; chan++) {
    622                 if (pu->pu_channel & PU_CHANNEL(chan)) {
    623                     pw_start_channel(unit, chan);
    624                 }
    625             }
    626         }
    627         break;
    628     default:
    629         assert("Unknown pkt watcher mode");
    630         break;
    631     }
    632 
    633     return rv;
    634 }
    635 
    636 STATIC void 
    637 pw_thread(void *up)
    638 /*
    639  * Function:    pw_thread
    640  * Purpose:     Waits for packets to arrive destined for the CPU and
    641  *              saves them in a queue. 
    642  * Parameters:  unit - SOC unit #
    643  * Returns:     Does not return.
    644  */
    645 {
    646     int         unit = PTR_TO_INT(up);
    647     int         i;
    648     pwu_t       *pu = &pw_units[unit];
    649     int         rv;
    650     int         pup_count;
    651     pup_t      *pup;
    652 
    653     PW_LOCK(unit);
    654 
    655     /* Allocate packet pointer array */ 
    656 
    657     if (0 == pu->pu_log_max) {
    658         pu->pu_log_max = PW_COUNT_DEFAULT;
    659     }
    660 
    661     /* Extra for multiple DMA channels */
    662     if (pu->mode == PW_MODE_SOC) {
    663         if (soc_feature(unit, soc_feature_cmicx)) {
    664             pup_count = pu->pu_log_max + CMICX_N_DMA_CHAN;
    665         } else {
    666             pup_count = pu->pu_log_max + N_DMA_CHAN;
    667         }
    668     } else {
    669         pup_count = pu->pu_log_max;
    670     }
    671     
    672     /* Bump up pup_count to be twice the log size so pups will
    673      * be available even when log queue is full.
    674      */
    675     pup_count += pu->pu_log_max;
    676 
    677     pu->pup_list = sal_alloc(sizeof(pup_t) * pup_count, "PW-pup");
    678     if (pu->pup_list == NULL) {
    679         pw_exit(unit, -1);
    680     }
    681     /* No forwaqrding null. If the allocation failed, the call to pw_exit will end the process and we sould never reach here. */
    682     /* coverity[var_deref_model:FALSE] */
    683     sal_memset(pu->pup_list, 0, sizeof(pup_t) * pup_count);
    684 
    685     for (i = 0; i < pup_count; i++) {
    686 
    687         pup = &pu->pup_list[i];
    688 
    689         if (pu->mode == PW_MODE_SOC) {
    690 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
    691             pup->pup_esw_dv = soc_dma_dv_alloc(unit, DV_RX, 1);
    692             if (pup->pup_esw_dv == NULL) {
    693                 pw_exit(unit, -1);
    694             }
    695 #endif                
    696             pup->pup_pkt = soc_cm_salloc(unit, PW_PACKET_SIZE, "pw_thread");
    697             if (pup->pup_pkt == NULL) {
    698 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
    699                 soc_dma_dv_free(unit, pup->pup_esw_dv);
    700 #endif
    701                 pw_exit(unit, -1);
    702             }
    703         }
    704         pw_pup_free(unit, pup);         /* Put on free list */
    705     }
    706 
    707     if (pu->pu_flags & PU_F_SYNC) {
    708         pu->pu_flags &= ~PU_F_SYNC;
    709         sal_sem_give(pu->pu_sync);
    710     } else {
    711         cli_out("PW-daemon[%d] -- Started\n", unit);
    712     }
    713 
    714     /* Kick Start channels */
    715     if ((rv = _pw_start_op(unit)) < 0) {
    716         cli_out("PW rx mode: Cannot start %s: %s.\n", pw_modes[pu->mode],
    717                 bcm_errmsg(rv));
    718         pw_exit(unit, -1);
    719     }
    720 
    721     PW_UNLOCK(unit);
    722 
    723     /*
    724      * Check if there are any actions for us.
    725      */
    726     while (1) {
    727         int     sem_rv;
    728 
    729         sem_rv = sal_sem_take(pw_units[unit].pu_sema, sal_sem_FOREVER);
    730 
    731         if (sem_rv < 0) {
    732             cli_out("Failed sem_take, exiting\n");
    733             pw_exit(unit, -1);
    734         }
    735 
    736         PW_LOCK(unit);                  /* Block log dumps */
    737 
    738         if (pu->pu_flags & PU_F_STOP) { /* Time to exit */
    739             if (pu->mode == PW_MODE_SOC) {
    740                 pw_cleanup_dma(unit);
    741             }
    742             pw_exit(unit, 0);
    743         }
    744 
    745         pw_process_pending(unit);
    746 
    747         PW_UNLOCK(unit);
    748 
    749         /* If limiting using interval, sleep intvl * num pkts processed */
    750         if (pu->mode == PW_MODE_SOC) {
    751             if (pu->pu_interval != 0 && pu->last_pkt_count != 0) {
    752                 sal_usleep(pu->pu_interval * pu->last_pkt_count);
    753             }
    754         }
    755     }
    756 
    757     pw_exit(unit, 0);
    758 }
    759 
    760 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
    761 STATIC int
    762 pw_channel_config(int unit)
    763 /*
    764  * Function:    pw_channel_config
    765  * Purpose:	Configure DMA RX channels for PW.
    766  * Parameters:  unit - unit to configure.
    767  * Returns:	0 - success
    768  *		-1 - failed.
    769  */
    770 {
    771     pwu_t	*pu = &pw_units[unit];	/* Control this unit */	
    772     dma_chan_t	tx, i;
    773     int		rv = SOC_E_NONE;
    774     dma_chan_t  dma_chan;
    775 
    776     if (pu->pu_channel == 0) {		/* Use default */
    777 	return 0;
    778     }
    779 
    780     if (soc_feature(unit, soc_feature_cmicx)) {
    781         dma_chan = CMICX_N_DMA_CHAN;
    782     } else {
    783         dma_chan = N_DMA_CHAN;
    784     }
    785 
    786     /* Pick lowest # free channel for TX default */
    787     tx = -1;
    788     for (i = 0; i < dma_chan; i++) {
    789 	if (pu->pu_channel & (1 << i)) {
    790 	    rv = soc_dma_chan_config(unit, i, DV_RX, SOC_DMA_F_INTR);
    791 	    if (rv < 0) {
    792 		cli_out("%s: DMA channel configuration failed: %s\n", 
    793                         pw_name[unit], soc_errmsg(rv));
    794 	    }
    795 #if defined(BCM_PETRA_SUPPORT)
    796         /* enable all cos on the channel */
    797         soc_dma_chan_cos_ctrl_set(unit, i, 1, 0xffffffff);
    798         soc_dma_chan_cos_ctrl_set(unit, i, 2, 0xffffffff);
    799 #endif
    800 	} else if (tx == -1) {
    801 	    tx = i;
    802 	}
    803     }
    804 
    805     if ((tx == -1) || 
    806 	((rv = soc_dma_chan_config(unit, tx, DV_TX,
    807 				   SOC_DMA_F_INTR |SOC_DMA_F_DEFAULT)) < 0)) {
    808 	cli_out("%s: Unable to configure TX DMA channel: %s\n", 
    809                 pw_name[unit],
    810                 tx == -1 ? "No remaining channels" : soc_errmsg(rv));
    811 
    812 	rv = soc_dma_init(unit);
    813 	cli_out("%s: Unable to re-initialize DMA: %s\n", 
    814                 pw_name[unit],
    815                 soc_errmsg(rv));
    816 
    817 	return -1;
    818     }
    819     return 0;
    820 }
    821 #endif
    822 
    823 static const parse_pm_t pw_report_table[] = {
    824     {"Count", 	REPORT_COUNT},
    825     {"DECode", 	REPORT_DECODE},
    826     {"Raw", 	REPORT_RAW},
    827     {"DMA", 	REPORT_DMA},
    828     {"CHannel",	REPORT_CHANNEL},
    829     {"@ALL",	~0},
    830     {"@*",	~0},
    831     {NULL, 	0}
    832 };
    833 
    834 static const parse_pm_t pw_channel_table[] = {
    835     {"0",	1 << 0},
    836     {"1",	1 << 1},
    837     {"2",	1 << 2},
    838     {"3",	1 << 3},
    839     {"4",	1 << 4},
    840     {"5",	1 << 5},
    841     {"6",	1 << 6},
    842     {"7",	1 << 7},
    843     {NULL,	0}
    844 };
    845 
    846 cmd_result_t
    847 pw_command(int unit, args_t *a)
    848 /*
    849  * Function:	pw_command
    850  * Purpose:	Command interface to the "packet watcher" thread.
    851  * Parameters:
    852  *		"verbose" - print lots of stuff.
    853  *		"start" - start packet watcher thread.
    854  *		"stop" - stop packet watcher thread.
    855  *		"quiet" - print no stuff.
    856  * Returns:	CMD_OK - success
    857  *		CMD_FAIL - failed
    858  *		CMD_USAGE - print usage instructions
    859  */
    860 {
    861     char	*c;
    862     int		n;
    863     uint32	on = 0;			/* flags to turn on */
    864     pwu_t	*pu = &pw_units[unit];	/* Control this unit */
    865 
    866     if (!sh_check_attached(ARG_CMD(a), unit)) {
    867 	return(CMD_FAIL);
    868     }
    869 
    870     if (!pu->init_done) {
    871         pw_init(unit);
    872     }
    873 
    874     if (!ARG_CNT(a)) {			/* Nothing passed */
    875 	cli_out("%s: Status: %s. Mode %s. Buffering up to %d packets.%s\n",
    876                 pw_name[unit],
    877                 (pu->pu_flags & PU_F_RUN) ? "Running" : "Not Running",
    878                 pw_modes[pu->mode], pu->pu_log_max,
    879                 (pu->pu_flags & PU_F_STOP) ? " STOP Requested." : "");
    880 	if (pu->mode == PW_MODE_SOC) {
    881             if (pu->pu_interval != 0) {
    882                 cli_out("Interval %d us", pu->pu_interval);
    883             }
    884         }
    885         if (pu->rate <= 0) {
    886             cli_out("Rate limiting is off.\n");
    887         } else {
    888             cli_out("Rate limit is %d (soc intvl %d).\n", pu->rate,
    889                     pu->pu_interval);
    890         }
    891             
    892 	cli_out("Reporting is enabled for: ");
    893 	parse_mask_format(80, pw_report_table, pu->pu_report);
    894 	cli_out("Reporting is disabled for: ");
    895 	parse_mask_format(80, pw_report_table, pu->pu_report ^ ~0);
    896 
    897         cli_out("Dump options are enabled for: ");
    898 	parse_mask_format(80, pw_report_table, pu->pu_dump_options);
    899 	cli_out("Dump options are disabled for: ");
    900 	parse_mask_format(80, pw_report_table, pu->pu_dump_options ^ ~0);
    901 
    902         cli_out("RX on for channel(s): ");
    903 	if (pu->pu_channel) {
    904 	    parse_mask_format(50, pw_channel_table, pu->pu_channel);
    905 	    cli_out("RX off for channel(s): ");
    906 	    parse_mask_format(50, pw_channel_table, ~pu->pu_channel);
    907 	} else {
    908 	    cli_out(" -- using default --\n");
    909 	}
    910 #ifdef BROADCOM_DEBUG
    911         if (pu->mode == PW_MODE_RX) {
    912             bcm_rx_show(unit);
    913         }
    914 #endif /* BROADCOM_DEBUG */
    915 	return(CMD_OK);
    916     }
    917 
    918     /* Scan args and see what's up */
    919 
    920     while ((c = ARG_GET(a)) != NULL) {
    921 	if (!sal_strcasecmp(c, "start")) {
    922 	    if (pu->pu_flags & PU_F_RUN) {
    923 		cli_out("%s: WARNING: Already running\n", pw_name[unit]);
    924 	    } else {
    925 		on |= PU_F_RUN;
    926 	    }
    927 	} else if (!sal_strcasecmp(c, "stop")) {
    928 	    if (!(pu->pu_flags & PU_F_RUN)) {
    929 		cli_out("%s: WARNING: Not running\n", pw_name[unit]);
    930 		return(CMD_OK);		/* Return OK to avoid rc aborts */
    931 	    }
    932 	    on |= PU_F_STOP;
    933 	} else if (!sal_strcasecmp(c, "reset")) {
    934 	    if (pu->pu_flags & PU_F_RUN) {
    935 		cli_out("%s: Unable to reset configuration "
    936                         "while running\n", pw_name[unit]);
    937 		return(CMD_FAIL);
    938 	    } else {
    939                 pu->init_done = FALSE;
    940                 pw_init(unit);
    941                 return CMD_OK;
    942             }
    943 	} else if (!sal_strcasecmp(c, "channel")) {
    944 	    if (ARG_CNT(a) == 0) {
    945 		cli_out("%s: RX on for channel(s): ", pw_name[unit]);
    946 		if (pu->pu_channel) {
    947 		    parse_mask_format(50, pw_channel_table, pu->pu_channel);
    948 		    cli_out("%s: RX off for channel(s): ", pw_name[unit]);
    949 		    parse_mask_format(50, pw_channel_table, ~pu->pu_channel);
    950 		} else {
    951 		    cli_out(" -- using default --\n");
    952 		}
    953 		return(CMD_OK);
    954 	    } else if (pu->pu_flags & PU_F_RUN) {
    955 		cli_out("%s: Unable to configure DMA channels "
    956                         "while running\n", pw_name[unit]);
    957 		return(CMD_FAIL);
    958 	    }
    959 
    960 	    /* Set channels */
    961 	    while ((c = ARG_CUR(a)) != NULL && 
    962 		   !parse_mask(c, pw_channel_table,
    963 			       (uint32 *)&pu->pu_channel)) {
    964 		ARG_NEXT(a);	/* Bump arg if matched report */
    965 	    }
    966 
    967 	    if (pu->pu_flags & PU_F_RUN) {
    968 		cli_out("%s: Warning channel re-assignment will not take\n"
    969                         "%s: until restarted.\n",
    970                         pw_name[unit], pw_name[unit]);
    971 	    }
    972 	} else if (!sal_strcasecmp(c, "quiet")) {
    973 	    pu->pu_report = 0;
    974 	} else if (!sal_strcasecmp(c, "rate")) {
    975 	    c = ARG_GET(a);
    976             if (c == NULL) {
    977                 if (pu->rate <= 0) {
    978                     cli_out("%s: No rate limiting.\n", pw_name[unit]);
    979                 } else {
    980                     cli_out("%s: Rate limit is currently %d pkts/sec.\n",
    981                             pw_name[unit], pu->rate);
    982                 }
    983                 return CMD_OK;
    984             }
    985             pu->rate = strtoul(c, NULL, 10);
    986             if (_pw_set_rate(unit) < 0) {
    987                 return CMD_FAIL;
    988             }
    989             return CMD_OK;
    990 	} else if (!sal_strcasecmp(c, "report")) {
    991 	    if (ARG_CNT(a)) {
    992 		while ((c = ARG_CUR(a)) != NULL && 
    993 		       !parse_mask(c, pw_report_table, &pu->pu_report)) {
    994 		    ARG_NEXT(a);	/* Bump arg if matched report */
    995 		}
    996 	    } else {			/* Print values */
    997 		cli_out("%s: Reporting on for: ", pw_name[unit]);
    998 		parse_mask_format(50, pw_report_table, pu->pu_report);
    999 		cli_out("%s: Reporting off for: ", pw_name[unit]);
   1000 		parse_mask_format(50, pw_report_table, ~pu->pu_report);
   1001 	    }
   1002 	} else if (!sal_strcasecmp(c, "log")) {
   1003 	    c = ARG_GET(a);
   1004 	    if (c) {			/* We have an option */
   1005 		if (pu->pu_flags & PU_F_RUN) {
   1006 		    cli_out("%s: Can not change \"log\" "
   1007                             "while PW-daemon running\n", pw_name[unit]);
   1008 		    return(CMD_FAIL);
   1009 		}			
   1010 		if (!sal_strcasecmp(c, "on")) {
   1011 		    n = PU_LOG_CNT;
   1012 		} else if (!sal_strcasecmp(c, "off")) {
   1013 		    n = 1;
   1014 		} else if (isint(c)) {	/* Set log size */
   1015 		    n = parse_integer(c);
   1016 		    if (n < 1) {
   1017 			cli_out("%s: What is %s?\n", pw_name[unit], c);
   1018 			n = 1;
   1019 		    }
   1020 		} else {
   1021 		    cli_out("%s: Invalid count \"%s\"\n", pw_name[unit], c);
   1022 		    return(CMD_FAIL);
   1023 		}
   1024 		pu->pu_log_max = n;
   1025 	    }
   1026 	    cli_out("%s: Logging(%d-packets)\n",
   1027                     pw_name[unit], pu->pu_log_max);
   1028 	    if (!c || !*c) {
   1029 		return(CMD_OK);
   1030 	    }
   1031 	} else if (!sal_strcasecmp(c, "dump")) {
   1032 	    c = ARG_GET(a);
   1033 	    if (!c) {			/* no args */
   1034 		n = pu->pu_log_cnt;
   1035 	    } else if (!isint(c)) {
   1036                 if (!sal_strcasecmp(c, "options")) {
   1037                     if (ARG_CNT(a)) {
   1038                         while ((c = ARG_CUR(a)) != NULL && 
   1039                                !parse_mask(c, pw_report_table,
   1040                                            &pu->pu_dump_options)) {
   1041                             ARG_NEXT(a);	/* Bump arg if matched report */
   1042                         }
   1043                     } else {			/* Print values */
   1044                         cli_out("%s: Dump options on for: ", pw_name[unit]);
   1045                         parse_mask_format(50, pw_report_table, pu->pu_dump_options);
   1046                         cli_out("%s: Dump options off for: ", pw_name[unit]);
   1047                         parse_mask_format(50, pw_report_table, ~pu->pu_dump_options);
   1048                     }
   1049                     return(CMD_OK);
   1050                 } else {
   1051                     cli_out("%s: Invalid log count \"%s\"\n", pw_name[unit], c);
   1052                     return(CMD_FAIL);
   1053                 }
   1054             } else {
   1055 		n = parse_integer(c);
   1056 	    }
   1057 	    return(pw_dump_log(unit, n));
   1058 	} else if (!sal_strcasecmp(c, "count")) {
   1059 	    COMPILER_DOUBLE	cur_time, last_time;
   1060 	    int		cur_count, last_count;
   1061 	    int		rate;
   1062 	    
   1063 	    cur_time = SAL_TIME_DOUBLE();
   1064 
   1065 	    last_time = pu->pu_count_time;
   1066 	    last_count = pu->pu_count_last;
   1067 	    cur_count = pu->pu_packet_received;
   1068 
   1069 	    if (cur_time == last_time) {
   1070 		rate = 0;
   1071 	    } else {
   1072 		rate = (int) ((cur_count - last_count) /
   1073 			      (cur_time - last_time));
   1074 	    }
   1075 
   1076 	    cli_out("%s: Received %d packets [(%d),%d,%d,%d,%d] (%d/sec), "
   1077                     "last %d packet(s) logged\n",
   1078                     pw_name[unit],
   1079                     pu->pu_packet_received,
   1080                     pu->pu_ch_count[0], 
   1081                     pu->pu_ch_count[1], 
   1082                     pu->pu_ch_count[2], 
   1083                     pu->pu_ch_count[3], 
   1084                     pu->pu_ch_count[4], 
   1085                     rate,
   1086                     pu->pu_log_cnt);
   1087 
   1088 	    pu->pu_count_last = cur_count;
   1089 	    pu->pu_count_time = cur_time;
   1090 	} else if (!sal_strcasecmp(c, "interval")) {
   1091 	    c = ARG_GET(a);
   1092 	    if (!c || !isint(c)) {
   1093 		return(CMD_USAGE);
   1094 	    }
   1095 	    n = parse_integer(c);
   1096 	    if (n < 0) {
   1097 		cli_out("%s: Invalid interval: %s\n", pw_name[unit], c);
   1098 		return(CMD_FAIL);
   1099 	    }
   1100 	    pu->pu_interval = n;
   1101 	} else if (!sal_strcasecmp(c, "mode")) {
   1102 	    if ((c = ARG_GET(a)) == NULL) {
   1103 		cli_out("Current mode is %s\n", pw_modes[pu->mode]);
   1104 		return CMD_OK;
   1105 	    }
   1106 
   1107 	    if (pw_running(unit)) {
   1108 		cli_out("Can't set modes while running\n");
   1109 		return CMD_FAIL;
   1110 	    }
   1111 
   1112 	    if (!sal_strcasecmp(c, "soc")) {
   1113 		pu->mode = PW_MODE_SOC;
   1114 	    } else if (!sal_strcasecmp(c, "rx")) {
   1115 		pu->mode = PW_MODE_RX;
   1116 	    } else {
   1117 		cli_out("Unknown mode: %s\n", c);
   1118 		return CMD_FAIL;        
   1119 	    }
   1120 
   1121 	    return CMD_OK;
   1122         } else if (!sal_strcasecmp(c, "hdr")) {
   1123             c = ARG_GET(a);
   1124             if (c) {            /* We have an option */
   1125                 if (!sal_strcasecmp(c, "on")) {
   1126                     pu->hdr_dump = 1;
   1127                 } else if (!sal_strcasecmp(c, "off")) {
   1128                     pu->hdr_dump = 0;
   1129                 }
   1130             }
   1131 	} else {
   1132 	    return(CMD_USAGE);
   1133 	}
   1134     }
   1135     
   1136     /* Everything OK, start or stop packet watcher now */
   1137 
   1138     if (on & PU_F_RUN) {		/* start off thread */
   1139 	return(pw_start(unit, TRUE));
   1140     } else if (on & PU_F_STOP) {	/* stop task */
   1141 	return(pw_stop(unit, TRUE));
   1142     }
   1143 
   1144     return(CMD_OK);
   1145 }
   1146 
   1147 /****************************************************************
   1148  *
   1149  * Common packet watcher routines
   1150  */
   1151 
   1152 
   1153 STATIC  pup_t *
   1154 pw_pup_alloc(int unit)
   1155 /*
   1156  * Function:    pw_alloc
   1157  * Purpose:     Alloc a pup off the free list.
   1158  * Parameters:  unit - unit #
   1159  * Returns:     Pointer to pup.
   1160  */
   1161 {
   1162     pwu_t       *pu = &pw_units[unit];
   1163     pup_t       *pup;
   1164 
   1165     PW_LOCK(unit);
   1166     pup = pu->pu_log_free;
   1167     if (pup) {
   1168         pu->pu_log_free = pup->pup_next;
   1169     }
   1170     PW_UNLOCK(unit);
   1171 
   1172     return(pup);
   1173 }
   1174 
   1175 STATIC  void
   1176 pw_pup_free(int unit, pup_t *pup)
   1177 /*
   1178  * Function:    pw_pup_free
   1179  * Purpose:     Put a pup on the free list.
   1180  * Parameters:  unit - unit #
   1181  *              pup - pointer to pup to free.
   1182  * Returns:     Nothing.
   1183  */
   1184 {
   1185     pwu_t       *pu = &pw_units[unit];
   1186 
   1187     pup->pup_next = pu->pu_log_free;
   1188     pu->pu_log_free = pup;
   1189 
   1190     if (pu->mode == PW_MODE_RX) {
   1191         bcm_rx_free(unit, pup->rx_pkt.alloc_ptr);
   1192     }
   1193 }
   1194 
   1195 STATIC void
   1196 pw_dump_start(int unit, char *pfx, pup_t *pup, uint32 report,
   1197               int chan, int count)
   1198 {
   1199     char        *channel;
   1200 
   1201     if (!report) {
   1202         return;
   1203     } 
   1204 
   1205     cli_out("\n");
   1206 
   1207     if (report & REPORT_CHANNEL) {
   1208         switch (chan) {
   1209         case -1:        channel = "";           break;
   1210         case 0:         channel = "-chn0";      break;
   1211         case 1:         channel = "-chn1";      break;
   1212         case 2:         channel = "-chn2";      break;
   1213         case 3:         channel = "-chn3";      break;
   1214         case 4:         channel = "-chn4";      break;
   1215         case 5:         channel = "-chn5";      break;
   1216         case 6:         channel = "-chn6";      break;
   1217         case 7:         channel = "-chn7";      break;
   1218         default:        channel = "-----";      break;
   1219         }
   1220     } else {
   1221         channel = "";
   1222     }
   1223 
   1224     sal_sprintf(pfx, "Packet[%d]%s: ", pup->pup_seqno, channel);
   1225 
   1226     if ((report & REPORT_COUNT) && (count >= 0)) {
   1227         cli_out("%sTotal %d\n", pfx, count);
   1228     }
   1229 
   1230 }
   1231 
   1232 
   1233 STATIC void
   1234 pw_dump_packet_soc(int unit, pup_t *pup, uint32 report)
   1235 /*
   1236  * Function:    pw_dump_packet
   1237  * Purpose:     dumps out a packet based on the flags set in pw_flags.
   1238  * Parameters:  unit - SOC unit #.
   1239  *              pup - packet structure
   1240  *              report - report flags
   1241  * Returns:     d - pointer to dcb containing packet
   1242  */
   1243 {
   1244 
   1245 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1246         dcb_t       *esw_dcb = NULL;
   1247 #endif
   1248 
   1249     char        pfx[64];
   1250 
   1251 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1252     esw_dcb = pup->pup_esw_dv->dv_dcb;
   1253 #endif
   1254 
   1255     
   1256 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1257     pw_dump_start(unit, pfx, pup, report, (int)pup->pup_esw_dv->dv_pw_chan, -1);
   1258 #endif
   1259 
   1260     if (report & REPORT_COUNT) {
   1261         cli_out("%sReceived\n", pfx);
   1262 #ifdef BROADCOM_DEBUG
   1263 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1264         SOC_DCB_REASON_DUMP(unit, esw_dcb, pfx);
   1265 #endif
   1266 #endif /* BROADCOM_DEBUG */
   1267     }
   1268 
   1269     if (report & REPORT_DMA) {
   1270 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1271         soc_dma_dump_dv(unit, pfx, pup->pup_esw_dv);
   1272 #endif
   1273     }
   1274 
   1275     if (report & REPORT_RAW) {
   1276 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1277         soc_dma_dump_pkt(unit, pfx,
   1278                          (uint8 *) SOC_DCB_ADDR_GET(unit, esw_dcb), 
   1279                          SOC_DCB_XFERCOUNT_GET(unit, esw_dcb),
   1280 			 TRUE);
   1281 #endif
   1282     }
   1283 
   1284 #ifndef NO_SAL_APPL
   1285 #ifndef __STRICT_ANSI__
   1286 #ifndef __KERNEL__
   1287     if (report & REPORT_DECODE) {
   1288 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1289         d_packet_format(pfx, DECODE_ETHER, pup->pup_pkt,
   1290 			SOC_DCB_XFERCOUNT_GET(unit, esw_dcb),
   1291 			SOC_IS_ENDURO(unit)?esw_dcb:NULL);
   1292 #endif
   1293     }
   1294 #endif /* __KERNEL__ */
   1295 #endif /* __STRICT_ANSI__ */
   1296 #endif /* NO_SAL_APPL */
   1297 }
   1298 
   1299 STATIC char *_pw_reason_names[bcmRxReasonCount] = BCM_RX_REASON_NAMES_INITIALIZER;
   1300 
   1301 STATIC void
   1302 pw_dump_packet_rx(int unit, pup_t *pup, uint32 report)
   1303 {
   1304     bcm_pkt_t *pkt;
   1305     char        pfx[64];
   1306     char        info_str[256];
   1307     pwu_t       *pu = &pw_units[unit];
   1308     int         i;
   1309 #ifndef NO_SAL_APPL
   1310 #ifndef __STRICT_ANSI__
   1311 #ifndef __KERNEL__
   1312 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1313     dv_t        *pdv;
   1314 #endif
   1315 #endif /* __KERNEL__ */
   1316 #endif /* __STRICT_ANSI__ */
   1317 #endif /* NO_SAL_APPL */
   1318 #ifdef BCM_PETRA_SUPPORT
   1319     int         hdr_len = 0;
   1320 #endif 
   1321 
   1322     pkt = &pup->rx_pkt;
   1323 
   1324 #ifdef BCM_PETRA_SUPPORT
   1325     if (SOC_IS_ARAD(unit)) {
   1326         hdr_len = pkt->tot_len - pkt->pkt_len;
   1327     }
   1328 #endif
   1329 
   1330     pw_dump_start(unit, pfx, pup, report, pkt->dma_channel,
   1331                   pu->pu_packet_received);
   1332 
   1333     if (report & REPORT_DMA) {
   1334         if (pkt->_dv) {
   1335 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1336             soc_dma_dump_dv(unit, pfx, (dv_t *)pkt->_dv);
   1337 #endif
   1338         }
   1339     }
   1340 
   1341     if (report & REPORT_RAW) {
   1342 #ifdef BCM_XGS12_FABRIC_SUPPORT
   1343         if (SOC_IS_XGS12_FABRIC(unit)) {
   1344             soc_dma_higig_dump(unit, pfx, pkt->_higig, 0, pkt->pkt_len, NULL);
   1345         }
   1346 #endif
   1347         if (SOC_IS_ARAD(unit)) {
   1348 #if defined(BCM_PETRA_SUPPORT)
   1349             soc_dma_ether_dump(unit, pfx, pkt->_pkt_data.data + hdr_len, pkt->pkt_len, 0);
   1350 #endif
   1351         }            
   1352         else {
   1353 #if defined(BCM_ESW_SUPPORT)
   1354 #if defined(BCM_CMICX_SUPPORT)
   1355             if (soc_feature(unit, soc_feature_cmicx)) {
   1356                 if (pu->hdr_dump == 1) {
   1357                     soc_dma_ep_to_cpu_hdr_dump(unit, pfx, pkt->_pkt_data.data - pkt->egress_to_cpu_hdr_size,
   1358                             pkt->egress_to_cpu_hdr_size, 0);
   1359                 }
   1360 
   1361                 if (report & REPORT_DMA) {
   1362                     uint8 *c = (uint8 *)pkt->_pkt_data.data;
   1363                     c -= pkt->egress_to_cpu_hdr_size;
   1364 #ifdef  LE_HOST
   1365                 {
   1366                     /* Higig field accessors expect network byte ordering,
   1367                      * so we must reverse the bytes on LE hosts */
   1368                     int word;
   1369                     uint32 *hg_data = (uint32 *)c;
   1370                     for (word = 0; word < BYTES2WORDS(pkt->egress_to_cpu_hdr_size); word++) {
   1371                         hg_data[word] = _shr_swap32(hg_data[word]);
   1372                     }
   1373                     c = (uint8 *)hg_data;
   1374                 }
   1375 #endif
   1376                     soc_dma_higig_dump(unit, pfx, c, 0, 0, NULL);
   1377                     soc_dma_ep_to_cpu_hdr_decoded_dump(unit, pfx, (void *)c, 1, pkt->egress_to_cpu_hdr_size);
   1378                 }
   1379             }
   1380 #endif
   1381             soc_dma_ether_dump(unit, pfx, pkt->_pkt_data.data, pkt->pkt_len, 0);
   1382 #endif
   1383         }
   1384         if (!SOC_IS_ARAD(unit)) {
   1385             cli_out("%slength %d (%d). rx-port %d. cos %d. prio_int %d. vlan %d. "
   1386                     "reason 0x%x. %s.\n", pfx,
   1387                     pkt->pkt_len, pkt->tot_len, pkt->rx_port, 
   1388                     pkt->cos, pkt->prio_int, pkt->vlan,
   1389                     pkt->rx_reason,
   1390                     (pkt->rx_untagged & BCM_PKT_OUTER_UNTAGGED) ?
   1391                     ((pkt->rx_untagged & BCM_PKT_INNER_UNTAGGED) ?
   1392                     "Untagged" : "Inner tagged") :
   1393                     ((pkt->rx_untagged & BCM_PKT_INNER_UNTAGGED) ?
   1394                     "Outer tagged" : "Double tagged"));
   1395         }
   1396         else {
   1397             cli_out("%slength %d (%d). rx-port %d. cos %d. prio_int %d. vlan %d. "
   1398                 "reason 0x%x.\n", pfx,
   1399                     pkt->pkt_len, pkt->tot_len, pkt->rx_port, 
   1400                     pkt->cos, pkt->prio_int, pkt->vlan,
   1401                     pkt->rx_reason);
   1402         }
   1403         if ((pkt->stk_flags & BCM_PKT_STK_F_SRC_PORT) &&
   1404             (pkt->stk_flags & BCM_PKT_STK_F_DST_PORT)) {
   1405 
   1406             sal_sprintf(info_str, 
   1407                 "dest-gport %d. src-gport %d. ",
   1408                 pkt->dst_gport, pkt->src_gport);
   1409         } else if ((pkt->stk_flags & BCM_PKT_STK_F_SRC_PORT)) {
   1410 
   1411             sal_sprintf(info_str,
   1412                 "dest-port %d. dest-mod %d. src-gport %d. ",
   1413                 pkt->dest_port, pkt->dest_mod, pkt->src_gport);
   1414         } else if ((pkt->stk_flags & BCM_PKT_STK_F_DST_PORT)) {
   1415 
   1416             sal_sprintf(info_str,
   1417                 "dest-gport %d. %s %d. src-mod %d. ",
   1418                 pkt->dst_gport, 
   1419                 (pkt->flags & BCM_PKT_F_TRUNK) ? "src-trunk" : "src-port",
   1420                 (pkt->flags & BCM_PKT_F_TRUNK) ? pkt->src_trunk : pkt->src_port, 
   1421                 pkt->src_mod);
   1422         } else {
   1423 
   1424             sal_sprintf(info_str,
   1425                 "dest-port %d. dest-mod %d. %s %d. src-mod %d. ",
   1426                 pkt->dest_port, pkt->dest_mod,
   1427                 (pkt->flags & BCM_PKT_F_TRUNK) ? "src-trunk" : "src-port",
   1428                 (pkt->flags & BCM_PKT_F_TRUNK) ? pkt->src_trunk : pkt->src_port, 
   1429                 pkt->src_mod);
   1430         }
   1431         if (!SOC_IS_ARAD(unit)) {
   1432             cli_out("%s%sopcode %d. %s matched %d. classification-tag %d.\n",
   1433                 pfx, info_str, 
   1434                 pkt->opcode,
   1435                 (pkt->flags & BCM_RX_TRUNCATED) ? "Truncated." : "",
   1436                 pkt->rx_matched, pkt->rx_classification_tag);
   1437         }
   1438         else {
   1439             cli_out("%s%s%s \n",
   1440                 pfx, info_str, 
   1441                 (pkt->flags & BCM_RX_TRUNCATED) ? "Truncated." : "");
   1442         }
   1443         for (i = 0; i < bcmRxReasonCount; i++) {
   1444             if (BCM_RX_REASON_GET(pkt->rx_reasons, i)) {
   1445                 cli_out("%sreasons: %s\n", pfx, _pw_reason_names[i]);
   1446             }
   1447         }
   1448 
   1449         /*
   1450          * Seamless Redundancy(SR) copy to CPU
   1451          * SR custom RX reason code (1~63) for IFP action bcmFieldActionSrCopyToCpu .
   1452          * construct reason code (1~63) from 6-bit binary encoding
   1453          */
   1454         #define SR_CUSTOM_RX_REASON_CODE \
   1455             ((BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit0) << 0)| \
   1456              (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit1) << 1)| \
   1457              (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit2) << 2)| \
   1458              (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit3) << 3)| \
   1459              (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit4) << 4)| \
   1460              (BCM_RX_REASON_GET(pkt->rx_reasons, bcmRxReasonSrCopyToCpuBit5) << 5))
   1461 
   1462         /* no copy to CPU when SR_CUSTOM_RX_REASON_CODE == 0 */
   1463         if(SR_CUSTOM_RX_REASON_CODE != 0) {
   1464             cli_out("%sSR custom RX reason code: %d\n",
   1465                     pfx,
   1466                     SR_CUSTOM_RX_REASON_CODE);
   1467         }
   1468     }
   1469 
   1470 #ifndef NO_SAL_APPL
   1471 #ifndef __STRICT_ANSI__
   1472 #ifndef __KERNEL__
   1473     if (report & REPORT_DECODE) {
   1474         if (pkt->_dv) {
   1475 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1476 	    pdv = (dv_t *)(pkt->_dv);
   1477 #if defined(BCM_PETRA_SUPPORT)
   1478             if (SOC_IS_ARAD(unit)) {
   1479                 d_packet_format(pfx, DECODE_ETHER, pkt->_pkt_data.data + hdr_len,
   1480 			        pkt->pkt_len, SOC_IS_ENDURO(unit)? pdv->dv_dcb:NULL);
   1481             }
   1482             else
   1483 #endif
   1484             {
   1485                 d_packet_format(pfx, DECODE_ETHER, pkt->_pkt_data.data,
   1486 			        pkt->pkt_len, SOC_IS_ENDURO(unit)? pdv->dv_dcb:NULL);
   1487             }
   1488 #endif
   1489 	}
   1490     }
   1491 #endif /* __KERNEL__ */
   1492 #endif /* __STRICT_ANSI__ */
   1493 #endif /* NO_SAL_APPL */
   1494 
   1495 }
   1496 
   1497 STATIC void
   1498 pw_dump_packet(int unit, pup_t *pup, uint32 report)
   1499 {
   1500     pwu_t       *pu = &pw_units[unit];
   1501 
   1502     switch (pu->mode) {
   1503         case PW_MODE_RX:
   1504             pw_dump_packet_rx(unit, pup, report);
   1505             break;
   1506         case PW_MODE_SOC:
   1507             pw_dump_packet_soc(unit, pup, report);
   1508             break;
   1509         default:
   1510             break;
   1511     }
   1512 }
   1513 
   1514 STATIC cmd_result_t
   1515 pw_dump_log(int unit, int n)
   1516 /*
   1517  * Function:	pw_dump_log
   1518  * Purpose:	Dump out currently logged packets
   1519  * Parameters:  unit - unit #
   1520  *		n - number of packets to dump, -n means last "n"
   1521  *			packets.
   1522  * Returns:	CMD_OK - success
   1523  */
   1524 {
   1525     pwu_t	*pu = &pw_units[unit];
   1526     pup_t	*pup;
   1527     int		abs_n;
   1528 
   1529     PW_LOCK(unit);			/* Stop updates */
   1530 
   1531     if ((pu->pu_log == NULL) || (n == 0)) { /* Nothing to show */
   1532 	PW_UNLOCK(unit);
   1533 	cli_out("pw_dump_log[%d]: Warning: no packets logged "
   1534                 "or selected to dump\n", unit);
   1535 	return CMD_OK;			/* Return nothing */
   1536     }
   1537 
   1538     /*
   1539      * Loop through list of packets, stop when we have dumped the correct
   1540      * number - we know there is at least one logged since we checked above.
   1541      * If dumping the last n packets, move backwards, otherwise move forwards.
   1542      * Anything on this list is complete, so the PW_LOCK protects this 
   1543      * operation.
   1544      */
   1545     abs_n = n < 0 ? -n : n;
   1546     abs_n = abs_n > pu->pu_log_cnt ? pu->pu_log_cnt : abs_n;
   1547 
   1548     if (n < 0) {			/* Dump last N packets */
   1549 	for (pup = pu->pu_log; abs_n-- != 0; pup = pup->pup_next) {
   1550 	    pw_dump_packet(unit, pup, pu->pu_dump_options);
   1551 	}
   1552     } else {				/* Dump first N packets */
   1553 	for (pup = pu->pu_log->pup_prev; abs_n-- != 0; pup = pup->pup_prev) {
   1554 	    pw_dump_packet(unit, pup, pu->pu_dump_options);
   1555 	}	    
   1556     }
   1557     PW_UNLOCK(unit);
   1558 	
   1559     return CMD_OK;
   1560 }
   1561 
   1562 STATIC	void
   1563 pw_log_packet(int unit, pup_t *pup)
   1564 /*
   1565  * Function: 	pw_log_packet
   1566  * Purpose:	Commit a recieved packet to the logs.
   1567  * Parameters:	unit - unit #
   1568  * 		pup - pointer to pup to add to log.
   1569  * Returns:	Nothing.
   1570  *
   1571  * Notes:	Assumes PW_LOCK held.
   1572  */
   1573 {
   1574     pwu_t	*pu = &pw_units[unit];
   1575 
   1576     /*
   1577      * There are 2 cases:
   1578      * 1) First entry
   1579      * 2) Log is full so the LRU packet is dropped (common case)
   1580      * 3) Log is not full, no packet is dropped.
   1581      */
   1582 
   1583     if (pu->pu_log_cnt == 0) {		/* 1) First entry */
   1584 	pu->pu_log = pup->pup_next = pup->pup_prev = pup;
   1585 	pu->pu_log_cnt = 1;
   1586     } else if (pu->pu_log_cnt == pu->pu_log_max) { /* 2) Full log, drop one */
   1587 	pup_t	*tp;
   1588 
   1589 	tp = pu->pu_log->pup_prev;	/* Entry to delete */
   1590 	pup->pup_next = pu->pu_log;	/* Link new one in at head */
   1591 	pup->pup_prev = tp->pup_prev;
   1592 	pup->pup_next->pup_prev = pup;
   1593 	pup->pup_prev->pup_next = pup;
   1594 
   1595 	pw_pup_free(unit, tp);
   1596     } else {				/* 3) Just add to chain */
   1597 	/*
   1598 	 * Case 2 - add new entry and increment log count.
   1599 	 */
   1600 	pu->pu_log_cnt++;
   1601 	pup->pup_next = pu->pu_log;
   1602 	pup->pup_prev = pu->pu_log->pup_prev;
   1603 	pup->pup_next->pup_prev = pup;
   1604 	pup->pup_prev->pup_next = pup;
   1605     }
   1606     pu->pu_log = pup;			/* Set new list */
   1607 }
   1608 
   1609 
   1610 STATIC	void
   1611 pw_process_pending(int unit)
   1612 /*
   1613  * Function:	pw_process_pending
   1614  * Purpose:	Process packets queued from interrupt
   1615  * Parameters:	unit - unit #
   1616  * Returns:	Nothing.
   1617  *
   1618  * Notes: 	Can be called only from a non-interrupt context.
   1619  */
   1620 {
   1621     pwu_t	*pu = &pw_units[unit];
   1622     pup_t	*pup;
   1623     int         chan;
   1624     chan = 0;
   1625     /*
   1626      * Pick up current done list and process in order.
   1627      */
   1628     PW_SPIN_LOCK(unit);
   1629     pup = (pup_t *)pu->pu_pending;
   1630     pu->pu_pending = NULL;
   1631     PW_SPIN_UNLOCK(unit);
   1632 
   1633     pu->last_pkt_count = 0;
   1634     while (pup) {
   1635         pup_t	*tp = pup->pup_next;
   1636 
   1637         pup->pup_seqno = ++pu->pu_packet_received;
   1638         pw_log_packet(unit, (pup_t *)pup);
   1639         if (pu->mode == PW_MODE_SOC) {
   1640 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1641             pw_start_channel(unit, (dma_chan_t)pup->pup_esw_dv->dv_pw_chan);
   1642             chan = (int)pup->pup_esw_dv->dv_pw_chan + 1;
   1643 #endif
   1644         } else {
   1645             chan = 0; /* Per-channel counted in Rx call-back */
   1646         }
   1647         pu->pu_ch_count[chan]++;
   1648         pw_dump_packet(unit, (pup_t *)pup, pu->pu_report); /* Dump packet */
   1649         pup = tp;
   1650         pu->last_pkt_count++;
   1651     }
   1652 }
   1653 
   1654 /****************************************************************
   1655  *
   1656  * RX API packet watcher code, non-interrupt
   1657  */
   1658 STATIC bcm_rx_t
   1659 pw_rx_callback(int unit, bcm_pkt_t *pkt, void *cookie)
   1660 {
   1661     pup_t *pup;
   1662     pwu_t	*pu = &pw_units[unit];
   1663     int8        chan;
   1664     dma_chan_t  dma_chan;
   1665 
   1666     chan = pkt->dma_channel;
   1667 
   1668     if (soc_feature(unit, soc_feature_cmicx)) {
   1669         dma_chan = CMICX_N_DMA_CHAN;
   1670     } else {
   1671         dma_chan = N_DMA_CHAN;
   1672     }
   1673 
   1674     if (chan >= 0 && chan < dma_chan) {
   1675         pu->pu_ch_count[chan + 1]++;
   1676     }
   1677     if (pu->pu_report == 0 && pu->pu_log_max == 1) {
   1678         /* No post-processing - just count packet */
   1679         return BCM_RX_HANDLED;
   1680     }
   1681 
   1682     pup = pw_pup_alloc(unit);
   1683     if (!pup) {
   1684         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1685                     (BSL_META_U(unit,
   1686                                 "PW: Failed to allocate pup struct.  Discarding\n")));
   1687         return BCM_RX_NOT_HANDLED;
   1688     }
   1689 
   1690     sal_memcpy(&pup->rx_pkt, pkt, sizeof(bcm_pkt_t));
   1691 
   1692     PW_SPIN_LOCK(unit);
   1693     pup->pup_next = NULL;
   1694     if (pu->pu_pending == NULL) {
   1695         pup->pup_prev = pup;
   1696         pu->pu_pending = pup;
   1697     } else {
   1698         pu->pu_pending->pup_prev->pup_next = pup;
   1699         pu->pu_pending->pup_prev = pup;
   1700     }
   1701     PW_SPIN_UNLOCK(unit);
   1702 
   1703     sal_sem_give(pw_units[unit].pu_sema);
   1704     return BCM_RX_HANDLED_OWNED;
   1705 }
   1706 
   1707 /****************************************************************
   1708  *
   1709  * SOC layer packet watcher code
   1710  */
   1711 
   1712 
   1713 STATIC	cmd_result_t
   1714 pw_start_channel(int unit, dma_chan_t chan)
   1715 /*
   1716  * Function:	pw_start_chanel
   1717  * Purpose:	Re-init dv and start a new DMA read operation.
   1718  * Parameters:	unit - SOC unit #
   1719  *		chan - DMA channel, if -1, uses default RX channel.
   1720  * Returns:	CMD_OK/CMD_FAIL
   1721  */
   1722 {
   1723     pwu_t	*pu = &pw_units[unit];
   1724     pup_t	*pup;
   1725     int		rv = 0;
   1726 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1727     dv_t	*esw_dv;
   1728     pbmp_t	empty;
   1729 #endif
   1730 
   1731     pup = pw_pup_alloc(unit);
   1732 
   1733     assert(pu->pu_ch_active[chan + 1] == NULL);
   1734     assert(pup);
   1735 
   1736 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1737     SOC_PBMP_CLEAR(empty);
   1738 #endif
   1739 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1740     esw_dv = pup->pup_esw_dv;
   1741     soc_dma_dv_reset(DV_RX, esw_dv);
   1742     soc_dma_desc_add(esw_dv, (sal_vaddr_t)pup->pup_pkt, PW_PACKET_SIZE, 
   1743 		     PBMP_ALL(unit), empty, empty, 0, NULL);
   1744     soc_dma_desc_end_packet(esw_dv);
   1745     esw_dv->dv_done_chain = pw_esw_done_intr;
   1746     esw_dv->dv_flags |= DV_F_NOTIFY_CHN;
   1747 
   1748     esw_dv->dv_pw_chan = (uint32)chan;
   1749     esw_dv->dv_pw_pup  = pup;
   1750 
   1751     pu->pu_ch_active[chan + 1] = pup;
   1752 
   1753     rv = soc_dma_start(unit, chan, esw_dv);
   1754     if (rv < 0) {
   1755 	pu->pu_ch_active[chan + 1] = NULL;
   1756 	pw_pup_free(unit, pup);
   1757 	cli_out("Failed to start DMA: %s\n", soc_errmsg(rv));
   1758     }
   1759 #endif
   1760 
   1761 
   1762     return(rv < 0 ? CMD_FAIL : CMD_OK);
   1763 }
   1764 
   1765 STATIC  void
   1766 pw_cleanup_dma(int unit)
   1767 /*
   1768  * Function:    pw_cleanup_dma
   1769  * Purpose:     Clean up outstanding DMA operations.
   1770  * Parameters:  unit - unit #
   1771  * Returns:     Nothing.
   1772  *
   1773  * Notes: Cleans up active DMA operations, and DMA operations that have
   1774  *        completed but have not been processed yet.
   1775  */
   1776 {
   1777     pwu_t       *pu = &pw_units[unit];
   1778     dma_chan_t  chan, dma_chan;
   1779 
   1780     if (soc_feature(unit, soc_feature_cmicx)) {
   1781         dma_chan = CMICX_N_DMA_CHAN;
   1782     } else {
   1783         dma_chan = N_DMA_CHAN;
   1784     }
   1785     for (chan = 0; chan < dma_chan + 1; chan++) {
   1786 
   1787         /* Clean up Active DMA */
   1788 
   1789         if (pu->pu_ch_active[chan]) {
   1790 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1791 	    if (SOC_IS_ESW(unit) || SOC_IS_ARAD(unit)) {
   1792                 (void)soc_dma_abort_dv(unit, pu->pu_ch_active[chan]->pup_esw_dv);
   1793             }
   1794 #endif            
   1795             pw_pup_free(unit, (pup_t *)pu->pu_ch_active[chan]);
   1796             pu->pu_ch_active[chan] = NULL;
   1797         }
   1798 
   1799     }
   1800     
   1801     /* Clean up those that are complete but not processed */
   1802 
   1803     PW_SPIN_LOCK(unit);
   1804     while (pu->pu_pending != NULL) {
   1805         pup_t   *tp = (pup_t *)pu->pu_pending;
   1806         pu->pu_pending = tp->pup_next;
   1807         pw_pup_free(unit, tp);
   1808     }
   1809     PW_SPIN_UNLOCK(unit);
   1810 }
   1811 
   1812 #if defined(BCM_ESW_SUPPORT) || defined(BCM_PETRA_SUPPORT)
   1813 /*
   1814  * Function:	pw_esw_done_intr
   1815  * Purpose:	Process a chain done interrupt.
   1816  * Parameters:	unit - unit #
   1817  *		dv - pointer to dv_chain associated with request.
   1818  * Returns:	Nothing.
   1819  * 
   1820  * Notes:	All this routine does is wake up the packet watcher
   1821  *		thread. 
   1822  */
   1823 STATIC	void
   1824 pw_esw_done_intr(int unit, dv_t *dv)
   1825 {
   1826     pwu_t	*pu  = &pw_units[unit];
   1827     pup_t	*pup = (pup_t *)dv->dv_pw_pup;
   1828 
   1829     pu->pu_ch_active[(int)dv->dv_pw_chan + 1] = NULL;
   1830     pup->pup_next = NULL;
   1831     PW_SPIN_LOCK(unit);
   1832     if (pu->pu_pending == NULL) {
   1833         pup->pup_prev = pup;
   1834         pu->pu_pending = pup;
   1835     } else {
   1836         pu->pu_pending->pup_prev->pup_next = pup;
   1837         pu->pu_pending->pup_prev = pup;
   1838     }
   1839     PW_SPIN_UNLOCK(unit);
   1840 
   1841     sal_sem_give(pw_units[unit].pu_sema);
   1842 }
   1843 #endif /* BCM_ESW_SUPPORT */