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

dma.c (36320B)


      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:
      8  *	dma.c
      9  * Requires:
     10  *	soc_internal_memory_fetch/store
     11  *	soc_internal_send_int
     12  * Provides:
     13  *	pcid_dcb_fetch
     14  *	pcid_dcb_store
     15  *	pcid_dma_tx_start
     16  *	pcid_dma_rx_start
     17  *	pcid_dma_rx_check
     18  *	pcid_dma_start_chan
     19  *	pcid_dma_stat_write
     20  *	pcid_dma_ctrl_write
     21  */
     22 
     23 #include <shared/bsl.h>
     24 
     25 #include <sys/types.h>
     26 #include <soc/dcb.h>
     27 #include <soc/dma.h>
     28 #include <soc/higig.h>
     29 #include <soc/pbsmh.h>
     30 #ifdef BCM_CMICM_SUPPORT
     31 #include <soc/cmicm.h>
     32 #endif
     33 #include "pcid.h"
     34 #include "cmicsim.h"
     35 
     36 #ifdef BCM_CMICM_SUPPORT
     37 void pcid_dma_cmicm_rx_check(pcid_info_t *pcid_info, int chan);
     38 #endif
     39 
     40 uint32
     41 pcid_reg_read(pcid_info_t *pcid_info, uint32 addr)
     42 {
     43    uint32 value;
     44 
     45    if ( (pcid_info->regmem_cb)  && 
     46         (pcid_info->regmem_cb(pcid_info, BCMSIM_PCI_MEM_READ,
     47                               addr, &value,
     48                               BYTES2BITS(sizeof(uint32))) == 0) ) {
     49       return value;
     50    } 
     51 
     52    return PCIM(pcid_info, addr);
     53 }
     54 
     55 void
     56 pcid_reg_write(pcid_info_t *pcid_info, uint32 addr, uint32 value)
     57 {
     58    if ( (pcid_info->regmem_cb) &&
     59         (pcid_info->regmem_cb(pcid_info, BCMSIM_PCI_MEM_WRITE,
     60                                addr, &value,
     61                                BYTES2BITS(sizeof(uint32))) == 0) ){
     62       return;
     63    }
     64 
     65    PCIM(pcid_info, addr) = value;
     66 }
     67 
     68 void
     69 pcid_reg_or_write(pcid_info_t* pcid_info, uint32 addr, uint32 or_value)
     70 {
     71    uint32 v = pcid_reg_read(pcid_info, addr);
     72    v |= or_value;
     73    pcid_reg_write(pcid_info, addr, v);
     74 }
     75 
     76 void
     77 pcid_reg_and_write(pcid_info_t* pcid_info, uint32 addr, uint32 and_value)
     78 {
     79    uint32 v = pcid_reg_read(pcid_info, addr);
     80    v &= ~and_value;
     81    pcid_reg_write(pcid_info, addr, v);
     82 }
     83 
     84 
     85 uint32
     86 pcid_dcb_fetch(pcid_info_t *pcid_info, uint32 addr, dcb_t *dcb)
     87 {
     88     int     size, i;
     89     uint32  *temp;
     90 
     91     LOG_INFO(BSL_LS_SOC_DMA,
     92              (BSL_META("Reading descriptor at 0x%08x\n"), addr));
     93 
     94     size = SOC_DCB_SIZE(pcid_info->unit);
     95     soc_internal_bytes_fetch(pcid_info, addr, (uint8 *)dcb, size);
     96 
     97     /* Convert to chip(same as host for sim mode) endian-ness */
     98     temp = (uint32 *)dcb;
     99     for (i=0; i < (size/sizeof(uint32)); i++) {
    100         *(temp + i) = soc_internal_endian_swap(pcid_info, *(temp + i), 
    101                                                MF_ES_DMA_OTHER);
    102     }
    103 
    104 #ifdef BROADCOM_DEBUG
    105     if (LOG_CHECK(BSL_LS_SOC_DMA | BSL_INFO)) {
    106 	SOC_DCB_DUMP(pcid_info->unit, dcb, "PCID Fetch", 0);
    107     }
    108 #endif /* BROADCOM_DEBUG */
    109 
    110     return addr + size;
    111 }
    112 
    113 uint32
    114 pcid_dcb_store(pcid_info_t *pcid_info, uint32 addr, dcb_t *dcb)
    115 {
    116     int	    size, i;
    117     uint32  *temp;
    118 
    119     size = SOC_DCB_SIZE(pcid_info->unit);
    120     
    121     /* Convert to CPU endian-ness */
    122     temp = (uint32 *)dcb;
    123     for (i=0; i < (size/sizeof(uint32)); i++) {
    124         *(temp + i) = soc_internal_endian_swap(pcid_info, *(temp + i), 
    125                                                MF_ES_DMA_OTHER);
    126     }
    127 
    128     soc_internal_bytes_store(pcid_info, addr, (void *)dcb, size);
    129     
    130     /* Convert back to chip(host) endian-ness */
    131     for (i=0; i < (size/sizeof(uint32)); i++) {
    132         *(temp + i) = soc_internal_endian_swap(pcid_info, *(temp + i), 
    133                                                MF_ES_DMA_OTHER);
    134     }
    135 
    136 #ifdef BROADCOM_DEBUG
    137     if (LOG_CHECK(BSL_LS_SOC_DMA | BSL_INFO)) {
    138 	SOC_DCB_DUMP(pcid_info->unit, dcb, "PCID Store", 1);
    139     }
    140 #endif /* BROADCOM_DEBUG */
    141 
    142     return addr + size;
    143 }
    144 
    145 /*
    146  * Function:
    147  *	_pcid_loop_tx_cb
    148  * Purpose:
    149  *	Loop back packets transmitted from CPU
    150  * Parameters:
    151  *      pcid_info - Pointer to pcid control structure
    152  *      dcb - Pointer to DCB describing packet data
    153  *      chan - Channel on which packet is being transmitted
    154  */
    155 
    156 void
    157 _pcid_loop_tx_cb(pcid_info_t *pcid_info, dcb_t *dcb, int chan)
    158 {
    159     int			cnt;		/* Bytes in this piece of packet */
    160     int			eop;		/* End of packet indicator */
    161     uint8		*buf;		/* alloc'd for this piece of packet */
    162     int			unit;
    163     int                 pkt_pos;
    164     int                 word_count=8; /* FB/ER 3 + 5 words of HG + PBE */
    165     static uint8        pkt_data[4][PKT_SIZE_MAX];
    166     static uint32       dcbd[4][13];
    167 #ifdef BCM_XGS3_SWITCH_SUPPORT
    168     uint32              hgf;
    169     uint32              opcode = 0xff;
    170     uint32              hgh_store[4];
    171     soc_higig_hdr_t     *hgh;
    172 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    173 
    174     /* Accumulate length for each channel */
    175     static int len[N_DMA_CHAN] = {0, 0, 0, 0};
    176     static int tx_pkt_no = 1;
    177     static int tx_dcb_no = 0;
    178 
    179     unit = pcid_info->unit;
    180     eop = !SOC_DCB_SG_GET(unit, dcb);
    181     cnt = SOC_DCB_REQCOUNT_GET(unit, dcb);
    182 
    183     if ((SOC_DCB_TYPE(pcid_info->unit) >= 9) &&
    184         (SOC_DCB_TYPE(pcid_info->unit) <=31)) {
    185         /* Copy module Header */
    186         if (len[chan] == 0) {
    187             uint32      *up;
    188             int         i;
    189             up = (uint32 *)dcb;
    190             up +=2; /* skip 2 words */
    191 
    192 #ifdef BCM_TRX_SUPPORT
    193             if (SOC_IS_TRX(pcid_info->unit)) {
    194                 word_count = 13; /* 4 + 7 words of HG + PBE */
    195             }
    196 #endif /* BCM_TRX_SUPPORT */
    197 
    198             for (i = 0; i < word_count; i++) {
    199                 dcbd[chan][i] = up[i];
    200             }
    201 #ifdef BCM_XGS3_SWITCH_SUPPORT
    202             hgf = CMIC_PORT(unit);
    203             if (SOC_DCB_HG_GET(unit, dcb)) {
    204                 hgh_store[0] = soc_htonl(dcbd[chan][0]);
    205                 hgh_store[1] = soc_htonl(dcbd[chan][1]);
    206                 hgh_store[2] = soc_htonl(dcbd[chan][2]);
    207                 hgh_store[3] = soc_htonl(dcbd[chan][3]);
    208                 hgh =  (soc_higig_hdr_t *)&hgh_store[0];
    209 
    210                 switch (soc_higig_field_get(unit, hgh, HG_start)) {
    211                 case 0xff:
    212                     hgf = soc_pbsmh_field_get(unit,
    213                                               (soc_pbsmh_hdr_t *)hgh,
    214                                               PBSMH_dst_port);
    215                     break;
    216                 case 0xfb:
    217                 case 0xfc:
    218                     hgf = soc_higig_field_get(unit, hgh, HG_dst_port);
    219                     soc_higig_field_set(unit, hgh, HG_src_port, hgf);
    220                     for(i = 0; i < 4; i++) {
    221                         dcbd[chan][i] = soc_ntohl(hgh_store[i]);
    222                     }
    223                     break;
    224                 default:
    225                     break;
    226                 }
    227             }
    228             SOC_DCB_RX_INGPORT_SET(unit, &dcbd[chan][-2], hgf);
    229 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    230         }
    231     }
    232     pkt_pos = len[chan];
    233     len[chan] += cnt;
    234 
    235     buf = &pkt_data[chan][pkt_pos];
    236     if ((len[chan]) >= PKT_SIZE_MAX) {
    237 	return;
    238     }
    239 
    240     soc_internal_bytes_fetch(pcid_info,
    241                              SOC_DCB_PADDR_GET(unit, dcb),
    242                              buf, cnt);
    243     tx_dcb_no++;
    244 
    245     if (eop) {
    246 	tx_pkt_no++;
    247 	tx_dcb_no = 0;
    248 #ifdef BCM_XGS3_SWITCH_SUPPORT
    249         /*
    250          * Not a generic implementation. Intended only for LB test
    251          */
    252         if (SOC_IS_XGS3_SWITCH(unit)) {
    253             buf = &pkt_data[chan][0];
    254             hgh_store[0] = soc_htonl(dcbd[chan][0]);
    255             hgh_store[1] = soc_htonl(dcbd[chan][1]);
    256             hgh_store[2] = soc_htonl(dcbd[chan][2]);
    257             hgh_store[3] = soc_htonl(dcbd[chan][3]);
    258             hgh =  (soc_higig_hdr_t *)&hgh_store[0];
    259 
    260             if ((soc_higig_field_get(unit, hgh, HG_start) == 0xfb) ||
    261                 (soc_higig_field_get(unit, hgh, HG_start) == 0xfc)) {
    262                 opcode = soc_higig_field_get(unit, hgh, HG_opcode);
    263             } else {
    264                 opcode = 0xff;
    265             }
    266             if ((opcode == 0) ||
    267                 ((buf[12] != 0x81) || (buf[13] != 0x00))) {
    268                 uint16 vtag;
    269                 int i;
    270 
    271                 vtag = soc_higig_field_get(pcid_info->unit,
    272                                            hgh,
    273                                            HG_vlan_tag);
    274                 for(i = len[chan] - 1; i >= 12; i--) {
    275                     buf[i + 4] = buf[i];
    276                 }
    277                 buf[12] = 0x81;
    278                 buf[13] = 0x00;
    279                 buf[14] = vtag >> 8;
    280                 buf[15] = vtag & 0xff;
    281                 len[chan] += 4;
    282             }
    283         }
    284 #endif /* BCM_XGS3_SWITCH_SUPPORT */
    285         if (!(SOC_IS_XGS3_SWITCH(unit) &&
    286              SOC_DCB_PURGE_GET(unit, dcb))) {
    287             pcid_add_pkt(pcid_info,
    288                          &pkt_data[chan][0],
    289                          len[chan],
    290                          &dcbd[chan][0]);
    291         }
    292         len[chan] = 0;
    293     }
    294 }
    295 
    296 /*
    297  * Function:
    298  *	_pcid_default_tx_cb
    299  * Purpose:
    300  *	Default function for transmit callback.
    301  * Parameters:
    302  *      pcid_info - Pointer to pcid control structure
    303  *      dcb - Pointer to DCB describing packet data
    304  *      chan - Channel on which packet is being transmitted
    305  */
    306 
    307 static void
    308 _pcid_default_tx_cb(pcid_info_t *pcid_info, dcb_t *dcb, int chan)
    309 {
    310     int			cnt;		/* Bytes in this piece of packet */
    311     int			i, j;
    312     int			eop;		/* End of packet indicator */
    313     uint8		*buf;		/* alloc'd for this piece of packet */
    314     int			unit;
    315     char		prefix[64];
    316 
    317     /* Accumulate length for each channel */
    318     static int len[N_DMA_CHAN] = {0, 0, 0, 0};
    319     static int tx_pkt_no = 1;
    320     static int tx_dcb_no = 0;
    321 
    322     unit = pcid_info->unit;
    323     eop = !SOC_DCB_SG_GET(unit, dcb);
    324     cnt = SOC_DCB_REQCOUNT_GET(unit, dcb);
    325 
    326     len[chan] += cnt;
    327 
    328     if ((buf = sal_alloc(cnt, "txcbb")) == NULL) {
    329 	return;		/* D'oh! */
    330     }
    331 
    332     soc_internal_bytes_fetch(pcid_info,
    333                              SOC_DCB_PADDR_GET(unit, dcb),
    334                              buf, cnt);
    335     /* coverity[secure_coding] */
    336     sprintf(prefix, "TX %d\tDCB[%d]", tx_pkt_no, tx_dcb_no);
    337 #ifdef BROADCOM_DEBUG
    338     SOC_DCB_DUMP(pcid_info->unit, dcb, prefix, 1);
    339 #endif /* BROADCOM_DEBUG */
    340 
    341     tx_dcb_no++;
    342 
    343     for (i = 0; i < cnt; i += 16) {
    344 	LOG_CLI((BSL_META_U(unit,
    345                             "\tdata[%04x]="), i));
    346 
    347 	for (j = 0; j < 16 && i + j < cnt; j++) {
    348 	    LOG_CLI((BSL_META_U(unit,
    349                                 "%02x "), buf[i + j]));
    350 	}
    351 
    352 	LOG_CLI((BSL_META_U(unit,
    353                             "\n")));
    354     }
    355 
    356     if (eop) {
    357         LOG_CLI((BSL_META_U(unit,
    358                             "TX %d\tEnd %d-byte packet\n"
    359                             "---------------------------------"
    360                             "---------------------------------\n"),
    361                  tx_pkt_no, len[chan]));
    362 	tx_pkt_no++;
    363 	tx_dcb_no = 0;
    364         len[chan] = 0;
    365     }
    366 
    367     sal_free(buf);
    368 }
    369 
    370 void
    371 pcid_dma_tx_start(pcid_info_t *pcid_info, int ch)
    372 {
    373     uint32 dcb_addr, dcb_addr_next;
    374     dcb_t *dcb;
    375 
    376     assert(ch >= 0 && ch < N_DMA_CHAN);
    377 
    378 /*    dcb_addr = PCIM(pcid_info, CMIC_DMA_DESC(ch)); */
    379     dcb_addr = pcid_reg_read(pcid_info, CMIC_DMA_DESC(ch));
    380 
    381     LOG_INFO(BSL_LS_SOC_DMA,
    382              (BSL_META("pcid_dma_tx_start: dcb_addr=0x%08x\n"), dcb_addr));
    383 
    384     dcb = sal_alloc(SOC_DCB_SIZE(pcid_info->unit), "txs_dcb");
    385     if (dcb == NULL) {
    386 	return;		/* Yow! */
    387     }
    388     do {
    389 	dcb_addr_next = pcid_dcb_fetch(pcid_info, dcb_addr, dcb);
    390 
    391 	if (SOC_DCB_RELOAD_GET(pcid_info->unit, dcb) &&
    392 	    (pcid_reg_read(pcid_info, CMIC_CONFIG) & CC_RLD_OPN_EN)) {
    393 	    dcb_addr_next = SOC_DCB_PADDR_GET(pcid_info->unit, dcb);
    394 	} else { /* Check for call back function */
    395             if (pcid_info->tx_cb) {
    396                 (pcid_info->tx_cb)(pcid_info, dcb, ch);
    397             } else { /* Call back not defined; use default */
    398                 _pcid_default_tx_cb(pcid_info, dcb, ch);
    399             }
    400         }
    401 
    402 	/* Update descriptor in memory */
    403 
    404 	SOC_DCB_DONE_SET(pcid_info->unit, dcb, 1);
    405         SOC_DCB_XFERCOUNT_SET(pcid_info->unit, dcb,
    406                               SOC_DCB_REQCOUNT_GET(pcid_info->unit, dcb));
    407 	pcid_dcb_store(pcid_info, dcb_addr, dcb);
    408 
    409 	dcb_addr = dcb_addr_next;
    410 
    411 /*	PCIM(pcid_info, CMIC_DMA_STAT) |= DS_DESC_DONE_TST(ch); */
    412         pcid_reg_or_write(pcid_info, CMIC_DMA_STAT, DS_DESC_DONE_TST(ch));
    413 
    414 /*	PCIM(pcid_info, CMIC_IRQ_STAT) |= IRQ_DESC_DONE(ch); */
    415         pcid_reg_or_write(pcid_info, CMIC_IRQ_STAT, IRQ_DESC_DONE(ch));
    416 	/* send_int(); */
    417     } while (SOC_DCB_CHAIN_GET(pcid_info->unit, dcb));
    418 
    419     /* Notify completion */
    420 
    421 /*    PCIM(pcid_info, CMIC_DMA_STAT) |= DS_CHAIN_DONE_TST(ch); */
    422     pcid_reg_or_write(pcid_info, CMIC_DMA_STAT, DS_CHAIN_DONE_TST(ch));
    423 
    424 /*    PCIM(pcid_info, CMIC_DMA_STAT) &= ~DS_DMA_ACTIVE(ch); */
    425     pcid_reg_and_write(pcid_info, CMIC_DMA_STAT, DS_DMA_ACTIVE(ch));
    426 
    427 /*    PCIM(pcid_info, CMIC_IRQ_STAT) |= IRQ_CHAIN_DONE(ch); */
    428     pcid_reg_or_write(pcid_info, CMIC_IRQ_STAT, IRQ_CHAIN_DONE(ch));
    429 
    430     soc_internal_send_int(pcid_info);
    431     sal_free(dcb);
    432 }
    433 
    434 #ifdef BCM_CMICM_SUPPORT
    435 void
    436 pcid_dma_cmicm_tx_start(pcid_info_t *pcid_info, int ch)
    437 {
    438     uint32 dcb_addr, dcb_addr_next;
    439     dcb_t *dcb;
    440 
    441     assert(ch >= 0 && ch < N_DMA_CHAN);
    442 
    443 /*    dcb_addr = PCIM(pcid_info, CMIC_CMCx_DMA_DESCy_OFFSET(CMC0, ch)); */
    444     dcb_addr = pcid_reg_read(pcid_info, CMIC_CMCx_DMA_DESCy_OFFSET(CMC0, ch));
    445 
    446     LOG_INFO(BSL_LS_SOC_DMA,
    447              (BSL_META("pcid_dma_cmicm_tx_start: dcb_addr=0x%08x\n"), dcb_addr));
    448 
    449     dcb = sal_alloc(SOC_DCB_SIZE(pcid_info->unit), "txs_dcb");
    450     if (dcb == NULL) {
    451 	return;		/* Yow! */
    452     }
    453     do {
    454 	dcb_addr_next = pcid_dcb_fetch(pcid_info, dcb_addr, dcb);
    455 
    456 	if (SOC_DCB_RELOAD_GET(pcid_info->unit, dcb)) {
    457 	    dcb_addr_next = SOC_DCB_PADDR_GET(pcid_info->unit, dcb);
    458 	} else { /* Check for call back function */
    459             if (pcid_info->tx_cb) {
    460                 (pcid_info->tx_cb)(pcid_info, dcb, ch);
    461             } else { /* Call back not defined; use default */
    462                 _pcid_default_tx_cb(pcid_info, dcb, ch);
    463             }
    464         }
    465 
    466 	/* Update descriptor in memory */
    467 
    468 	SOC_DCB_DONE_SET(pcid_info->unit, dcb, 1);
    469         SOC_DCB_XFERCOUNT_SET(pcid_info->unit, dcb,
    470                               SOC_DCB_REQCOUNT_GET(pcid_info->unit, dcb));
    471 	pcid_dcb_store(pcid_info, dcb_addr, dcb);
    472 
    473 	dcb_addr = dcb_addr_next;
    474 
    475 /*/ PCIM(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET) |= DS_CMCx_DMA_DESC_DONE(ch); */
    476         pcid_reg_or_write(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET, DS_CMCx_DMA_DESC_DONE(ch));
    477 
    478 /*	PCIM(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET) |= IRQ_CMCx_DESC_DONE(ch); */
    479         pcid_reg_or_write(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET, IRQ_CMCx_DESC_DONE(ch));
    480 
    481 	/* send_int(); */
    482     } while (SOC_DCB_CHAIN_GET(pcid_info->unit, dcb));
    483 
    484     /* Notify completion */
    485 
    486 /*    PCIM(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET) |= DS_CMCx_DMA_CHAIN_DONE(ch); */
    487     pcid_reg_or_write(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET, DS_CMCx_DMA_CHAIN_DONE(ch));
    488 
    489 /*    PCIM(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET) &= ~DS_CMCx_DMA_ACTIVE(ch); */
    490     pcid_reg_and_write(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET, DS_CMCx_DMA_ACTIVE(ch));
    491 
    492 /*    PCIM(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET) |= IRQ_CMCx_CHAIN_DONE(ch); */
    493     pcid_reg_or_write(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET, IRQ_CMCx_CHAIN_DONE(ch));
    494 
    495     soc_internal_cmicm_send_int(pcid_info, CMIC_CMC0_PCIE_IRQ_MASK0_OFFSET);
    496     sal_free(dcb);
    497 }
    498 #endif
    499 
    500 static uint32 		rx_dcb_addr[N_DMA_CHAN];
    501 static dcb_t		*rx_dcb[N_DMA_CHAN];
    502 
    503 
    504 void
    505 pcid_dma_rx_start(pcid_info_t *pcid_info, int ch)
    506 {
    507     /*
    508      * This notifies the pcid_dma_rx_check polling routine that a DCB is
    509      * executing.
    510      */
    511 
    512 /*   rx_dcb_addr[ch] = PCIM(pcid_info, CMIC_DMA_DESC(ch)); */
    513    rx_dcb_addr[ch] = pcid_reg_read(pcid_info, CMIC_DMA_DESC(ch));
    514 
    515     LOG_INFO(BSL_LS_SOC_DMA,
    516              (BSL_META("pcid_dma_rx_start: ch=%d dcb=0x%08x\n"),
    517               ch, rx_dcb_addr[ch]));
    518 }
    519 
    520 #ifdef BCM_CMICM_SUPPORT
    521 void
    522 pcid_dma_cmicm_rx_start(pcid_info_t *pcid_info, int ch)
    523 {
    524     /*
    525      * This notifies the pcid_dma_rx_check polling routine that a DCB is
    526      * executing.
    527      */
    528 
    529 /*    rx_dcb_addr[ch] = PCIM(pcid_info, CMIC_CMCx_DMA_DESCy_OFFSET(CMC0, ch)); */
    530    rx_dcb_addr[ch] = pcid_reg_read(pcid_info, CMIC_CMCx_DMA_DESCy_OFFSET(CMC0, ch));
    531 
    532     LOG_INFO(BSL_LS_SOC_DMA,
    533              (BSL_META("pcid_dma_cmicm_rx_start: ch=%d dcb=0x%08x\n"),
    534               ch, rx_dcb_addr[ch]));
    535 }
    536 #endif
    537 
    538 void
    539 pcid_dma_rx_check(pcid_info_t *pcid_info, int chan)
    540 {
    541     uint32 		rx_dcb_addr_next;
    542     int 		cnt, len, xfer;
    543     int 		eop, drop_pkt = 0;
    544     uint32		dma_ctrl;
    545     int                 word_count=8; /* FB/ER 3 + 5 words of HG + PBE */
    546 
    547     assert(chan >= 0 && chan < N_DMA_CHAN);
    548 #ifdef BCM_CMICM_SUPPORT
    549     if (soc_feature(pcid_info->unit, soc_feature_cmicm)) {
    550         pcid_dma_cmicm_rx_check(pcid_info, chan);
    551         return;
    552     }
    553 #endif
    554 
    555     PCID_MEM_LOCK(pcid_info);
    556 
    557 /*    dma_ctrl = PCIM(pcid_info, CMIC_DMA_CTRL); */
    558     dma_ctrl = pcid_reg_read(pcid_info, CMIC_DMA_CTRL);
    559 
    560     if ((dma_ctrl & DC_DIRECTION_MASK(chan)) != DC_SOC_TO_MEM(chan)) {
    561         PCID_MEM_UNLOCK(pcid_info);
    562         return;		/* Channel not configured for RX */
    563     }
    564 
    565     if ((pcid_reg_read(pcid_info, CMIC_DMA_STAT) & DS_DMA_EN_TST(chan)) == 0) {
    566         PCID_MEM_UNLOCK(pcid_info);
    567         return;		/* Channel not enabled */
    568     }
    569 
    570     if (rx_dcb_addr[chan] == 0) {
    571         PCID_MEM_UNLOCK(pcid_info);
    572         return;		/* Should not happen */
    573     }
    574 
    575     
    576 
    577     LOG_INFO(BSL_LS_SOC_DMA,
    578              (BSL_META("pcid_dma_rx_check: dcb=0x%08x\n"), rx_dcb_addr[chan]));
    579 
    580     if (rx_dcb[chan] == NULL) {
    581 	rx_dcb[chan] = sal_alloc(SOC_DCB_SIZE(pcid_info->unit), "rxc_dcb");
    582 	if (rx_dcb[chan] == NULL) {
    583         PCID_MEM_UNLOCK(pcid_info);
    584         return;	/* Yow! */
    585 	}
    586     }
    587     rx_dcb_addr_next = pcid_dcb_fetch(pcid_info, rx_dcb_addr[chan],
    588                                       rx_dcb[chan]);
    589 
    590     if (SOC_DCB_RELOAD_GET(pcid_info->unit, rx_dcb[chan]) &&
    591         (pcid_reg_read(pcid_info, CMIC_CONFIG) & CC_RLD_OPN_EN)) {
    592 	rx_dcb_addr_next = SOC_DCB_PADDR_GET(pcid_info->unit,
    593 					     rx_dcb[chan]);
    594 
    595 	LOG_INFO(BSL_LS_SOC_DMA,
    596                  (BSL_META("pcid_dma_rx_check: reload to 0x%08x\n"),
    597                   rx_dcb_addr_next));
    598     } else {
    599         sal_mutex_take(pcid_info->pkt_mutex, sal_mutex_FOREVER);
    600         if (pcid_info->pkt_list == 0) {
    601             sal_mutex_give(pcid_info->pkt_mutex);
    602             PCID_MEM_UNLOCK(pcid_info);
    603             return;		/* No pending packets anyway */
    604         }
    605 	eop = !SOC_DCB_SG_GET(pcid_info->unit, rx_dcb[chan]);
    606 	cnt = SOC_DCB_REQCOUNT_GET(pcid_info->unit, rx_dcb[chan]);
    607 
    608 	len = pcid_info->pkt_list->length - pcid_info->pkt_list->consum;
    609 
    610 	LOG_INFO(BSL_LS_SOC_DMA,
    611                  (BSL_META("pcid_dma_rx_check: eop=%d cnt=%d length=%d consum=%d len=%d\n"),
    612                   eop, cnt, pcid_info->pkt_list->length,
    613                   pcid_info->pkt_list->consum, len));
    614 
    615 	/* Clear status */
    616 	SOC_DCB_STATUS_INIT(pcid_info->unit, rx_dcb[chan]);
    617 
    618 	if (len <= cnt) { /* Room to receive whole packet in current DCB */
    619 	    xfer = len;
    620 	    SOC_DCB_RX_END_SET(pcid_info->unit, rx_dcb[chan], 1);
    621 	    drop_pkt = 1;
    622             eop = 1;
    623 	} else {	/* Part of packet is received */
    624 	    xfer = cnt;
    625 	    drop_pkt = eop;
    626 	}
    627 	SOC_DCB_XFERCOUNT_SET(pcid_info->unit, rx_dcb[chan], xfer);
    628 	SOC_DCB_RX_START_SET(pcid_info->unit, rx_dcb[chan],
    629 				    (pcid_info->pkt_list->consum == 0));
    630 	SOC_DCB_RX_ERROR_SET(pcid_info->unit, rx_dcb[chan], 0);
    631 	SOC_DCB_RX_CRC_SET(pcid_info->unit, rx_dcb[chan], 1);
    632         SOC_DCB_RX_END_SET(pcid_info->unit, rx_dcb[chan], eop);
    633         if ((SOC_DCB_TYPE(pcid_info->unit) >= 9) &&
    634             (SOC_DCB_TYPE(pcid_info->unit) <=31)) {
    635             uint32      *up;
    636             int         i;
    637             up = rx_dcb[chan];
    638             up += 2; /* skip 2 words */
    639 
    640 #ifdef BCM_TRX_SUPPORT
    641             if (SOC_IS_TRX(pcid_info->unit)) {
    642                 word_count = 13; /* 4 + 7 words of HG + PBE */
    643             }
    644 #endif /* BCM_TRX_SUPPORT */
    645 
    646             for (i = 0; i < word_count; i++) {
    647                 up[i] = pcid_info->pkt_list->dcbd[i];
    648             }
    649         }
    650 
    651 	soc_internal_memory_store(pcid_info,
    652                       SOC_DCB_PADDR_GET(pcid_info->unit, rx_dcb[chan]),
    653 		      &pcid_info->pkt_list->data[pcid_info->pkt_list->consum],
    654 		      xfer,
    655 		      MF_ES_DMA_PACKET);
    656         /* Now indicate this part of packet is consumed */
    657         pcid_info->pkt_list->consum += xfer;
    658         sal_mutex_give(pcid_info->pkt_mutex);
    659     }
    660 
    661     SOC_DCB_DONE_SET(pcid_info->unit, rx_dcb[chan], 1);
    662 
    663     pcid_dcb_store(pcid_info, rx_dcb_addr[chan], rx_dcb[chan]);
    664 
    665 /*    PCIM(pcid_info, CMIC_DMA_STAT) |= DS_DESC_DONE_TST(chan); */
    666     pcid_reg_or_write(pcid_info, CMIC_DMA_STAT, DS_DESC_DONE_TST(chan));
    667 
    668 /*    PCIM(pcid_info, CMIC_IRQ_STAT) |= IRQ_DESC_DONE(chan); */
    669     pcid_reg_or_write(pcid_info, CMIC_IRQ_STAT, IRQ_DESC_DONE(chan));
    670 
    671     if (SOC_DCB_CHAIN_GET(pcid_info->unit, rx_dcb[chan])) {
    672 	rx_dcb_addr[chan] = rx_dcb_addr_next;
    673     } else {
    674         if (SOC_DCB_RELOAD_GET(pcid_info->unit, rx_dcb[chan])) {
    675             rx_dcb_addr[chan] = rx_dcb_addr_next;
    676         } else {
    677             rx_dcb_addr[chan] = 0;
    678         }
    679 
    680 	/* Notify completion */
    681 
    682 /*	PCIM(pcid_info, CMIC_DMA_STAT) |= DS_CHAIN_DONE_TST(chan); */
    683         pcid_reg_or_write(pcid_info, CMIC_DMA_STAT, DS_CHAIN_DONE_TST(chan));
    684 /*	PCIM(pcid_info, CMIC_DMA_STAT) &= ~DS_DMA_ACTIVE(chan); */
    685         pcid_reg_and_write(pcid_info, CMIC_DMA_STAT, DS_DMA_ACTIVE(chan));
    686 
    687 /*	PCIM(pcid_info, CMIC_IRQ_STAT) |= IRQ_CHAIN_DONE(chan); */
    688         pcid_reg_or_write(pcid_info, CMIC_IRQ_STAT, IRQ_CHAIN_DONE(chan));
    689 /*	PCIM(pcid_info, CMIC_IRQ_STAT) &= ~(IRQ_DESC_DONE(chan)); */
    690         pcid_reg_and_write(pcid_info, CMIC_IRQ_STAT, IRQ_DESC_DONE(chan));
    691     }
    692 
    693     soc_internal_send_int(pcid_info);
    694 
    695     if (drop_pkt) {
    696 	packet_t		*tmp;
    697 
    698         sal_mutex_take(pcid_info->pkt_mutex, sal_mutex_FOREVER);
    699 	tmp = pcid_info->pkt_list;
    700 	pcid_info->pkt_list = pcid_info->pkt_list->next;
    701         pcid_info->pkt_count--;
    702         sal_mutex_give(pcid_info->pkt_mutex);
    703 	sal_free(tmp);
    704     }
    705     PCID_MEM_UNLOCK(pcid_info);
    706 }
    707 
    708 #ifdef BCM_CMICM_SUPPORT
    709 void
    710 pcid_dma_cmicm_rx_check(pcid_info_t *pcid_info, int chan)
    711 {
    712     uint32 		rx_dcb_addr_next;
    713     int 		cnt, len, xfer;
    714     int 		eop, drop_pkt = 0;
    715     uint32		dma_ctrl;
    716     int                 word_count=8; /* FB/ER 3 + 5 words of HG + PBE */
    717 
    718     assert(chan >= 0 && chan < N_DMA_CHAN);
    719 
    720     PCID_MEM_LOCK(pcid_info);
    721 
    722 /*    dma_ctrl = PCIM(pcid_info, CMIC_CMCx_CHy_DMA_CTRL_OFFSET(CMC0, chan)); */
    723     dma_ctrl = pcid_reg_read(pcid_info, CMIC_CMCx_CHy_DMA_CTRL_OFFSET(CMC0, chan));
    724 
    725     if (dma_ctrl & PKTDMA_DIRECTION) {
    726         PCID_MEM_UNLOCK(pcid_info);
    727         return;		/* Channel not configured for RX */
    728     }
    729 
    730     if ((dma_ctrl & PKTDMA_ENABLE) == 0) {
    731         PCID_MEM_UNLOCK(pcid_info);
    732         return;		/* Channel not enabled */
    733     }
    734 
    735     if (rx_dcb_addr[chan] == 0) {
    736         PCID_MEM_UNLOCK(pcid_info);
    737         return;		/* Should not happen */
    738     }
    739 
    740     
    741 
    742     LOG_INFO(BSL_LS_SOC_DMA,
    743              (BSL_META("pcid_dma_cmicm_rx_check: dcb=0x%08x\n"), rx_dcb_addr[chan]));
    744 
    745     if (rx_dcb[chan] == NULL) {
    746 	rx_dcb[chan] = sal_alloc(SOC_DCB_SIZE(pcid_info->unit), "rxc_dcb");
    747 	if (rx_dcb[chan] == NULL) {
    748         PCID_MEM_UNLOCK(pcid_info);
    749         return;	/* Yow! */
    750 	}
    751     }
    752     rx_dcb_addr_next = pcid_dcb_fetch(pcid_info, rx_dcb_addr[chan],
    753                                       rx_dcb[chan]);
    754 
    755     if (SOC_DCB_RELOAD_GET(pcid_info->unit, rx_dcb[chan])) {
    756 	rx_dcb_addr_next = SOC_DCB_PADDR_GET(pcid_info->unit,
    757 					     rx_dcb[chan]);
    758 
    759 	LOG_INFO(BSL_LS_SOC_DMA,
    760                  (BSL_META("pcid_dma_cmicm_rx_check: reload to 0x%08x\n"),
    761                   rx_dcb_addr_next));
    762     } else {
    763         sal_mutex_take(pcid_info->pkt_mutex, sal_mutex_FOREVER);
    764         if (pcid_info->pkt_list == 0) {
    765             sal_mutex_give(pcid_info->pkt_mutex);
    766             PCID_MEM_UNLOCK(pcid_info);
    767             return;		/* No pending packets anyway */
    768         }
    769 	eop = !SOC_DCB_SG_GET(pcid_info->unit, rx_dcb[chan]);
    770 	cnt = SOC_DCB_REQCOUNT_GET(pcid_info->unit, rx_dcb[chan]);
    771 
    772 	len = pcid_info->pkt_list->length - pcid_info->pkt_list->consum;
    773 
    774 	LOG_INFO(BSL_LS_SOC_DMA,
    775                  (BSL_META("pcid_dma_cmicm_rx_check: eop=%d cnt=%d length=%d consum=%d len=%d\n"),
    776                   eop, cnt, pcid_info->pkt_list->length,
    777                   pcid_info->pkt_list->consum, len));
    778 
    779 	/* Clear status */
    780 	SOC_DCB_STATUS_INIT(pcid_info->unit, rx_dcb[chan]);
    781 
    782 	if (len <= cnt) { /* Room to receive whole packet in current DCB */
    783 	    xfer = len;
    784 	    SOC_DCB_RX_END_SET(pcid_info->unit, rx_dcb[chan], 1);
    785 	    drop_pkt = 1;
    786             eop = 1;
    787 	} else {	/* Part of packet is received */
    788 	    xfer = cnt;
    789 	    drop_pkt = eop;
    790 	}
    791 	SOC_DCB_XFERCOUNT_SET(pcid_info->unit, rx_dcb[chan], xfer);
    792 	SOC_DCB_RX_START_SET(pcid_info->unit, rx_dcb[chan],
    793 				    (pcid_info->pkt_list->consum == 0));
    794 	SOC_DCB_RX_ERROR_SET(pcid_info->unit, rx_dcb[chan], 0);
    795 	SOC_DCB_RX_CRC_SET(pcid_info->unit, rx_dcb[chan], 1);
    796         SOC_DCB_RX_END_SET(pcid_info->unit, rx_dcb[chan], eop);
    797         if ((SOC_DCB_TYPE(pcid_info->unit) >= 9) &&
    798             (SOC_DCB_TYPE(pcid_info->unit) <= 31)) {
    799             uint32      *up;
    800             int         i;
    801             up = rx_dcb[chan];
    802             up += 2; /* skip 2 words */
    803 
    804 #ifdef BCM_TRX_SUPPORT
    805             if (SOC_IS_TRX(pcid_info->unit)) {
    806                 word_count = 13; /* 4 + 7 words of HG + PBE */
    807             }
    808 #endif /* BCM_TRX_SUPPORT */
    809 
    810             for (i = 0; i < word_count; i++) {
    811                 up[i] = pcid_info->pkt_list->dcbd[i];
    812             }
    813         }
    814 
    815 	soc_internal_memory_store(pcid_info,
    816                       SOC_DCB_PADDR_GET(pcid_info->unit, rx_dcb[chan]),
    817 		      &pcid_info->pkt_list->data[pcid_info->pkt_list->consum],
    818 		      xfer,
    819 		      MF_ES_DMA_PACKET);
    820         /* Now indicate this part of packet is consumed */
    821         pcid_info->pkt_list->consum += xfer;
    822         sal_mutex_give(pcid_info->pkt_mutex);
    823     }
    824 
    825     SOC_DCB_DONE_SET(pcid_info->unit, rx_dcb[chan], 1);
    826 
    827     pcid_dcb_store(pcid_info, rx_dcb_addr[chan], rx_dcb[chan]);
    828 
    829 /*    PCIM(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET) |= DS_CMCx_DMA_DESC_DONE(chan); */
    830     pcid_reg_or_write(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET, DS_CMCx_DMA_DESC_DONE(chan));
    831 
    832 /*    PCIM(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET) |= IRQ_CMCx_DESC_DONE(chan); */
    833     pcid_reg_or_write(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET, IRQ_CMCx_DESC_DONE(chan));
    834 
    835     if (SOC_DCB_CHAIN_GET(pcid_info->unit, rx_dcb[chan])) {
    836 	rx_dcb_addr[chan] = rx_dcb_addr_next;
    837     } else {
    838         if (SOC_DCB_RELOAD_GET(pcid_info->unit, rx_dcb[chan])) {
    839             rx_dcb_addr[chan] = rx_dcb_addr_next;
    840         } else {
    841             rx_dcb_addr[chan] = 0;
    842         }
    843 
    844 	/* Notify completion */
    845 
    846 /*	PCIM(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET) |= DS_CMCx_DMA_CHAIN_DONE(chan); */
    847         pcid_reg_or_write(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET, DS_CMCx_DMA_CHAIN_DONE(chan));
    848 /*	PCIM(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET) &= ~DS_CMCx_DMA_ACTIVE(chan); */
    849         pcid_reg_and_write(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET, DS_CMCx_DMA_ACTIVE(chan));
    850 
    851 /*	PCIM(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET) |= IRQ_CMCx_CHAIN_DONE(chan); */
    852         pcid_reg_or_write(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET, IRQ_CMCx_CHAIN_DONE(chan));
    853 /*	PCIM(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET) &= ~(IRQ_CMCx_DESC_DONE(chan)); */
    854         pcid_reg_or_write(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET, IRQ_CMCx_DESC_DONE(chan));
    855     }
    856 
    857     soc_internal_cmicm_send_int(pcid_info, CMIC_CMC0_PCIE_IRQ_MASK0_OFFSET);
    858 
    859     if (drop_pkt) {
    860 	packet_t		*tmp;
    861 
    862         sal_mutex_take(pcid_info->pkt_mutex, sal_mutex_FOREVER);
    863 	tmp = pcid_info->pkt_list;
    864 	pcid_info->pkt_list = pcid_info->pkt_list->next;
    865         pcid_info->pkt_count--;
    866         sal_mutex_give(pcid_info->pkt_mutex);
    867 	sal_free(tmp);
    868     }
    869     PCID_MEM_UNLOCK(pcid_info);
    870 }
    871 #endif
    872 
    873 void
    874 pcid_dma_start_chan(pcid_info_t *pcid_info, int ch)
    875 {
    876     uint32 dma_ctrl;
    877     int tx, modbmp, abort, intrdesc, drop_tx;
    878 
    879 /*    PCIM(pcid_info, CMIC_DMA_STAT) |= DS_DMA_ACTIVE(ch); */
    880     pcid_reg_or_write(pcid_info, CMIC_DMA_STAT, DS_DMA_ACTIVE(ch));
    881 
    882 /*    dma_ctrl = PCIM(pcid_info, CMIC_DMA_CTRL); */
    883     dma_ctrl = pcid_reg_read(pcid_info, CMIC_DMA_CTRL);
    884 
    885     tx = ((dma_ctrl & DC_DIRECTION_MASK(ch)) == DC_MEM_TO_SOC(ch));
    886     modbmp = ((dma_ctrl & DC_MOD_BITMAP_MASK(ch)) == DC_MOD_BITMAP(ch));
    887     abort = ((dma_ctrl & DC_ABORT_DMA_MASK(ch)) == DC_ABORT_DMA(ch));
    888     intrdesc = ((dma_ctrl & DC_INTR_ON_MASK(ch)) == DC_INTR_ON_DESC(ch));
    889     drop_tx = ((dma_ctrl & DC_DROP_TX_MASK(ch)) == DC_DROP_TX(ch));
    890 
    891     LOG_INFO(BSL_LS_SOC_DMA,
    892              (BSL_META("Starting DMA on channel %d\n"), ch));
    893 
    894     LOG_INFO(BSL_LS_SOC_DMA,
    895              (BSL_META("Mode: %s %s %s %s %s\n"),
    896               tx ? "TX" : "RX",
    897               modbmp ? "MOD_BMP" : "NO_MOD_BMP",
    898               abort ? "ABORT" : "NO_ABORT",
    899               intrdesc ? "INTR_ON_DESC" : "INTR_ON_PKT",
    900               drop_tx ? "DROP_TX" : "NO_DROP_TX"));
    901 
    902     if (tx) {
    903 	pcid_dma_tx_start(pcid_info, ch);
    904     } else {
    905 	pcid_dma_rx_start(pcid_info, ch);
    906     }
    907 }
    908 
    909 #ifdef BCM_CMICM_SUPPORT
    910 void
    911 pcid_dma_cmicm_start_chan(pcid_info_t *pcid_info, int ch)
    912 {
    913     uint32 dma_ctrl;
    914     int tx, en, abort, intrdesc;
    915 
    916 /*    PCIM(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET) |= DS_CMCx_DMA_ACTIVE(ch); */
    917     pcid_reg_or_write(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET, DS_CMCx_DMA_ACTIVE(ch));
    918 
    919 /*    dma_ctrl = PCIM(pcid_info, CMIC_CMCx_CHy_DMA_CTRL_OFFSET(CMC0, ch)); */
    920     dma_ctrl = pcid_reg_read(pcid_info, CMIC_CMCx_CHy_DMA_CTRL_OFFSET(CMC0, ch));
    921 
    922     tx = (dma_ctrl & PKTDMA_DIRECTION);
    923     en = (dma_ctrl & PKTDMA_ENABLE);
    924     abort = (dma_ctrl & PKTDMA_ABORT);
    925     intrdesc = (dma_ctrl & PKTDMA_SEL_INTR_ON_DESC_OR_PKT);
    926 
    927     LOG_INFO(BSL_LS_SOC_DMA,
    928              (BSL_META("Starting DMA on channel %d\n"), ch));
    929 
    930     LOG_INFO(BSL_LS_SOC_DMA,
    931              (BSL_META("Mode: %s %s %s %s\n"),
    932               tx ? "TX" : "RX",
    933               en ? "ENABLE" : "NO_ENABLE",
    934               abort ? "ABORT" : "NO_ABORT",
    935               intrdesc ? "INTR_ON_DESC" : "INTR_ON_PKT"));
    936 
    937     if (tx) {
    938 	pcid_dma_cmicm_tx_start(pcid_info, ch);
    939     } else {
    940 	pcid_dma_cmicm_rx_start(pcid_info, ch);
    941     }
    942 }
    943 #endif
    944 
    945 void
    946 pcid_dma_stat_write(pcid_info_t *pcid_info, uint32 value)
    947 {
    948     uint32	old_stat = pcid_reg_read(pcid_info, CMIC_DMA_STAT); /* Initial value */
    949     uint32	new_stat;
    950     int		ch;
    951 
    952     /*
    953      * In the hardware, the DMA is triggered by a couple conditions:
    954      *	1) DMA Enable == 1
    955      *	2) Chain_done == 0
    956      *
    957      * DMA must be triggered as soon as all of these conditions are true.
    958      */
    959     if (value & 0x80) {			/* Set a bit */
    960 /*	new_stat = PCIM(pcid_info, CMIC_DMA_STAT) |= 1 << (value & 0x1f); */
    961         pcid_reg_or_write(pcid_info, CMIC_DMA_STAT, 1 << (value & 0x1f));
    962         new_stat = pcid_reg_read(pcid_info, CMIC_DMA_STAT);
    963     } else {
    964 /*	new_stat = PCIM(pcid_info, CMIC_DMA_STAT) &= ~(1 << (value & 0x1f)); */
    965         pcid_reg_and_write(pcid_info, CMIC_DMA_STAT, 1 << (value & 0x1f));
    966         new_stat = pcid_reg_read(pcid_info, CMIC_DMA_STAT);
    967     }
    968 
    969     /*
    970      * Now look at differences and descide what action to take. This
    971      * could be optimized since only one channel changed, but for now take
    972      * the easy approach.
    973      */
    974 
    975     for (ch = 0; ch < N_DMA_CHAN; ch++) {
    976 	int	old_enable, old_chain_done, old_desc_done;
    977 	int	new_enable, new_chain_done, new_desc_done;
    978 
    979 	old_enable = DS_DMA_EN_TST(ch) & old_stat;
    980 	old_chain_done = DS_CHAIN_DONE_TST(ch) & old_stat;
    981 	old_desc_done = DS_DESC_DONE_TST(ch) & old_stat;
    982 
    983 	new_enable = DS_DMA_EN_TST(ch) & new_stat;
    984 	new_chain_done = DS_CHAIN_DONE_TST(ch) & new_stat;
    985 	new_desc_done = DS_DESC_DONE_TST(ch) & new_stat;
    986 
    987 	/*
    988 	 * Check for interrupt changes - this MUST be before the DMA
    989 	 * check below to avoid clearing status from a potentially
    990 	 * started DMA.
    991 	 */
    992 
    993 	if (old_desc_done && !new_desc_done) { /* Clear interrupt */
    994 /*	    PCIM(pcid_info, CMIC_IRQ_STAT) &= ~IRQ_DESC_DONE(ch); */
    995            pcid_reg_and_write(pcid_info, CMIC_IRQ_STAT, IRQ_DESC_DONE(ch));
    996 	}
    997 
    998 	if (old_chain_done && !new_chain_done) { /* Clear interrupt */
    999 /*	    PCIM(pcid_info, CMIC_IRQ_STAT) &= ~IRQ_CHAIN_DONE(ch); */
   1000            pcid_reg_and_write(pcid_info, CMIC_IRQ_STAT, IRQ_CHAIN_DONE(ch));
   1001 	}
   1002 
   1003 	/* Trigger a DMA ? */
   1004 
   1005 	if ((!old_enable || old_chain_done) && /* Not running before */
   1006 	    (new_enable && !new_chain_done)) { /* Should start */
   1007 	    pcid_dma_start_chan(pcid_info, ch);
   1008 	}
   1009     }
   1010 }
   1011 
   1012 void
   1013 pcid_dma_ctrl_write(pcid_info_t *pcid_info, uint32 value)
   1014 {
   1015     int		ch;
   1016 
   1017     pcid_reg_write(pcid_info, CMIC_DMA_CTRL, value);
   1018 
   1019     for (ch = 0; ch < N_DMA_CHAN; ch++) {
   1020 	if (value & DC_ABORT_DMA(ch)) {
   1021 /*           PCIM(pcid_info, CMIC_DMA_STAT) &= ~DS_DMA_ACTIVE(ch); */
   1022            pcid_reg_and_write(pcid_info, CMIC_DMA_STAT, DS_DMA_ACTIVE(ch));
   1023 	}
   1024     }
   1025 }
   1026 
   1027 #ifdef BCM_CMICM_SUPPORT
   1028 void
   1029 pcid_dma_cmicm_ctrl_write(pcid_info_t *pcid_info, uint32 reg, uint32 value)
   1030 {
   1031     int    ch; 
   1032     uint32 old_stat;
   1033     uint32 new_ctrl, old_ctrl;
   1034     int	old_enable, old_chain_done;
   1035     int	new_enable;
   1036     int active = 0;
   1037 
   1038     switch (reg) {
   1039     case CMIC_CMC0_CH0_DMA_CTRL_OFFSET:
   1040         ch = 0;
   1041         break;
   1042     case CMIC_CMC0_CH1_DMA_CTRL_OFFSET:
   1043         ch = 1;
   1044         break;
   1045     case CMIC_CMC0_CH2_DMA_CTRL_OFFSET:
   1046         ch = 2;
   1047         break;
   1048     case CMIC_CMC0_CH3_DMA_CTRL_OFFSET:
   1049         ch = 3;
   1050         break;
   1051     default:
   1052         assert(0);
   1053         return;
   1054     }
   1055 
   1056 /*    old_stat = PCIM(pcid_info, CMIC_CMCx_DMA_STAT_OFFSET(CMC0)); */
   1057     old_stat = pcid_reg_read(pcid_info, CMIC_CMCx_DMA_STAT_OFFSET(CMC0));
   1058 /*    old_ctrl = PCIM(pcid_info, CMIC_CMCx_CHy_DMA_CTRL_OFFSET(CMC0, ch)); */
   1059     old_ctrl = pcid_reg_read(pcid_info, CMIC_CMCx_CHy_DMA_CTRL_OFFSET(CMC0, ch));
   1060 /*    PCIM(pcid_info, CMIC_CMCx_CHy_DMA_CTRL_OFFSET(CMC0, ch)) = value; */
   1061     pcid_reg_write(pcid_info, CMIC_CMCx_CHy_DMA_CTRL_OFFSET(CMC0, ch), value);
   1062 /*    new_ctrl = PCIM(pcid_info, CMIC_CMCx_CHy_DMA_CTRL_OFFSET(CMC0, ch)); */
   1063     new_ctrl = pcid_reg_read(pcid_info, CMIC_CMCx_CHy_DMA_CTRL_OFFSET(CMC0, ch));
   1064 
   1065     /* handle enable and abort */
   1066     active = DS_CMCx_DMA_ACTIVE(ch) & old_stat;
   1067     old_enable = PKTDMA_ENABLE & old_ctrl;
   1068     old_chain_done = DS_CMCx_DMA_CHAIN_DONE(ch) & old_stat;
   1069     new_enable = PKTDMA_ENABLE & new_ctrl;
   1070  
   1071     if (!new_enable) {
   1072 /*        PCIM(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET) &= ~(IRQ_CMCx_DESC_DONE(ch)); */
   1073        pcid_reg_and_write(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET, (IRQ_CMCx_DESC_DONE(ch)));
   1074 /*        PCIM(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET) &= ~(IRQ_CMCx_CHAIN_DONE(ch)); */
   1075        pcid_reg_and_write(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET, IRQ_CMCx_CHAIN_DONE(ch));
   1076     }
   1077 
   1078     /* Trigger a DMA ? */
   1079     if ((!old_enable || old_chain_done) && /* Not running before */
   1080 	 !active && new_enable) { /* Should start */
   1081 	 pcid_dma_cmicm_start_chan(pcid_info, ch);
   1082     } else if (active && (new_ctrl & PKTDMA_ABORT)) { /* or Abort DMA */
   1083 /*         PCIM(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET) &= ~DS_CMCx_DMA_ACTIVE(ch); */
   1084        pcid_reg_and_write(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET, DS_CMCx_DMA_ACTIVE(ch));
   1085          LOG_CLI((BSL_META("Abort on ch: %d !!\n"), ch));
   1086     }
   1087 }
   1088 #endif
   1089 
   1090 void
   1091 pcid_dma_stop_all(pcid_info_t *pcid_info) 
   1092 {
   1093     int ch;
   1094 
   1095     LOG_CLI((BSL_META("Abort and Disable  DMA\n")));
   1096     
   1097     /* 
   1098      * Abort and disable all DMA channels when the client exits so that
   1099      * the PCID does not poll for the old DMA when the client connects again.
   1100      */ 
   1101 #ifdef BCM_CMICM_SUPPORT
   1102     if (pcid_info->cmicm >= CMC0) {
   1103 /*        PCIM(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET) = 0; */
   1104        pcid_reg_write(pcid_info, CMIC_CMC0_DMA_STAT_OFFSET, 0);
   1105     }
   1106 #endif
   1107     for (ch = 0; ch < N_DMA_CHAN; ch++) {
   1108 #ifdef BCM_CMICM_SUPPORT
   1109         if (pcid_info->cmicm >= CMC0) {
   1110             pcid_dma_cmicm_ctrl_write(pcid_info, 
   1111                    CMIC_CMCx_CHy_DMA_CTRL_OFFSET(pcid_info->cmicm, ch), PKTDMA_ABORT);
   1112 /*            PCIM(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET) &= ~(IRQ_CMCx_DESC_DONE(ch)); */
   1113             pcid_reg_and_write(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET, IRQ_CMCx_DESC_DONE(ch));
   1114 /*            PCIM(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET) &= ~(IRQ_CMCx_CHAIN_DONE(ch)); */
   1115             pcid_reg_and_write(pcid_info, CMIC_CMC0_IRQ_STAT0_OFFSET, IRQ_CMCx_CHAIN_DONE(ch));
   1116         } else 
   1117 #endif
   1118         {
   1119             pcid_dma_ctrl_write(pcid_info, DC_ABORT_DMA(ch)); /* Abort current DMA */
   1120             pcid_dma_stat_write(pcid_info, (0x00 | ch));      /* Disable DMA */
   1121         }
   1122         rx_dcb_addr[ch] = 0x0;                           
   1123     }
   1124 }