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 }