void PerformDma_8000( PLX_DEVICE_OBJECT *pDevice ) { U8 *VaBar0 = 0; U8 DmaChannel; U16 UserInput; U32 LoopCount; U32 PollCount; U32 OffsetDmaCmd; U32 ElapsedTime_ms; VOID *BarVa; double Stat_TxTotalCount; double Stat_TxTotalBytes; BOOLEAN bInterrupts; PLX_STATUS status; struct timeb StartTime, EndTime; PLX_DMA_PROP DmaProp; PLX_INTERRUPT PlxInterrupt; PLX_DMA_PARAMS DmaParams; PLX_PHYSICAL_MEM PciBuffer; PLX_NOTIFY_OBJECT NotifyObject; Cons_printf("\n\n"); Cons_printf("Please select a DMA channel (0-3) --> "); Cons_scanf("%hd", &UserInput); if (UserInput >= 4) { Cons_printf("ERROR: Unsupported DMA channel, test aborted\n"); return; } DmaChannel = (U8)UserInput; // Set offset of DMA command register OffsetDmaCmd = 0x200 + (DmaChannel * 0x100) + 0x38; // Determine whether to use interrupts or polling Cons_printf("Use interrupts(i) or poll(p) [i/p]? --> "); UserInput = Cons_getch(); Cons_printf("%c\n\n", UserInput); if (UserInput == 'i' || UserInput == 'I') bInterrupts = TRUE; else bInterrupts = FALSE; /************************************************************** * *************************************************************/ Cons_printf(" Allocate DMA buffer............ "); // Set buffer request size PciBuffer.Size = (8 * 1024 * 1024); // Allocate a buffer status = PlxPci_PhysicalMemoryAllocate( pDevice, &PciBuffer, TRUE // Smaller buffer ok ); if (status != ApiSuccess) { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(status); return; } Cons_printf("Ok (size=%d KB)\n", (PciBuffer.Size >> 10)); /************************************************************** * *************************************************************/ // Open the DMA channel Cons_printf(" Open Channel %i for DMA......... ", DmaChannel); status = PlxPci_DmaChannelOpen( pDevice, DmaChannel, NULL ); if (status == ApiSuccess) { Cons_printf("Ok\n"); } else { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(status); } // Get current DMA properties Cons_printf(" Get DMA propeties.............. "); status = PlxPci_DmaGetProperties( pDevice, DmaChannel, &DmaProp ); if (status != ApiSuccess) { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(status); goto _ExitDmaTest; } Cons_printf("Ok\n"); // Update any DMA properties Cons_printf(" Set DMA propeties.............. "); // Set to support 128B TLP read request size DmaProp.MaxSrcXferSize = PLX_DMA_MAX_SRC_TSIZE_128B; status = PlxPci_DmaSetProperties( pDevice, DmaChannel, &DmaProp ); if (status != ApiSuccess) { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(status); goto _ExitDmaTest; } Cons_printf("Ok\n"); /************************************************************** * *************************************************************/ if (bInterrupts) { Cons_printf(" Register for notification...... "); // Clear interrupt fields memset( &PlxInterrupt, 0, sizeof(PLX_INTERRUPT) ); // Setup to wait for selected DMA channel PlxInterrupt.DmaDone = (1 << DmaChannel); status = PlxPci_NotificationRegisterFor( pDevice, &PlxInterrupt, &NotifyObject ); if (status != ApiSuccess) { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(status); return; } Cons_printf( "Ok\n" ); } else { Cons_printf(" Map BAR 0 for register access.. "); status = PlxPci_PciBarMap( pDevice, 0, &BarVa ); if (status != ApiSuccess) { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(status); return; } Cons_printf("Ok (VA=%p)\n", BarVa); VaBar0 = BarVa; } /***************************************** * * Transfer the Data * *****************************************/ Cons_printf("\n\n"); Cons_printf(" --- Performing DMA transfers (Press ESC to halt) ---\n"); // Clear DMA data memset(&DmaParams, 0, sizeof(PLX_DMA_PARAMS)); DmaParams.AddrSource = PciBuffer.PhysicalAddr; DmaParams.AddrDest = PciBuffer.PhysicalAddr + (PciBuffer.Size / 2); DmaParams.ByteCount = PciBuffer.Size / 2; // If polling, disable DMA interrupt if (bInterrupts == FALSE) DmaParams.bIgnoreBlockInt = TRUE; LoopCount = 0; // Reset stats Stat_TxTotalCount = 0; Stat_TxTotalBytes = 0; // Get initial start time ftime( &StartTime ); do { // Periodically display statistics if ((LoopCount & 0x0000003F) == 0) { // Get end time ftime( &EndTime ); // Calculate elapsed time in milliseconds ElapsedTime_ms = (((U32)EndTime.time * 1000) + EndTime.millitm) - (((U32)StartTime.time * 1000) + StartTime.millitm); if (ElapsedTime_ms >= (UPDATE_DISPLAY_SEC * 1000)) { // Display statistics if (ElapsedTime_ms != 0) { Cons_printf( " Transfers: %0.0lf Bytes: %0.2lf MB Time: %ldms Rate:%6.3lf MB/s\n", Stat_TxTotalCount, Stat_TxTotalBytes / (1 << 20), ElapsedTime_ms, ((Stat_TxTotalBytes * 1000) / (double)ElapsedTime_ms) / (double)(1 << 20) ); } // Reset stats Stat_TxTotalCount = 0; Stat_TxTotalBytes = 0; // Check for user cancel if (Cons_kbhit()) { if (Cons_getch() == 27) goto _ExitDmaTest; } // Get new start time ftime( &StartTime ); } } status = PlxPci_DmaTransferBlock( pDevice, DmaChannel, &DmaParams, 0 // Don't wait for completion ); if (status != ApiSuccess) { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(status); goto _ExitDmaTest; } if (bInterrupts) { status = PlxPci_NotificationWait( pDevice, &NotifyObject, DMA_TIMEOUT_SEC * 1000 ); switch (status) { case ApiSuccess: break; case ApiWaitTimeout: Cons_printf("*ERROR* - Timeout waiting for Int Event\n"); goto _ExitDmaTest; case ApiWaitCanceled: Cons_printf("*ERROR* - Interrupt event cancelled\n"); goto _ExitDmaTest; default: Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(status); goto _ExitDmaTest; } } else { PollCount = 1000000; // Poll for DMA completion do { PollCount--; if ((PlxReg(VaBar0, OffsetDmaCmd) & (1 << 30)) == 0) break; } while (PollCount != 0); // Check if DMA is truly complete if (PollCount == 0) { Cons_printf("*ERROR* - Timeout waiting for DMA to complete\n"); goto _ExitDmaTest; } } // Update statistics Stat_TxTotalCount++; Stat_TxTotalBytes += PciBuffer.Size / 2; LoopCount++; } while (1); _ExitDmaTest: Cons_printf("\n ------------------\n"); // Release the interrupt wait object if (bInterrupts) { Cons_printf(" Cancelling Int Notification.... "); status = PlxPci_NotificationCancel( pDevice, &NotifyObject ); if (status != ApiSuccess) { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(status); } else { Cons_printf("Ok\n"); } } // Close DMA Channel Cons_printf(" Close DMA Channel.............. "); status = PlxPci_DmaChannelClose( pDevice, DmaChannel ); if (status == ApiSuccess) { Cons_printf("Ok\n"); } else { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(status); } // Release DMA buffer PlxPci_PhysicalMemoryFree( pDevice, &PciBuffer ); }
/* * 'Burst' read a block of data */ XIA_EXPORT int XIA_API plx_read_block(HANDLE h, unsigned long addr, unsigned long len, unsigned long n_dead, unsigned long *data) { unsigned long idx; unsigned long *local = NULL; PLX_STATUS status; PLX_STATUS ignored_status; PLX_DMA_PROP dma_prop; PLX_DMA_PARAMS dma_params; ASSERT(len > 0); ASSERT(data != NULL); status = _plx_find_handle_index(h, &idx); if (status != PLX_SUCCESS) { _plx_log_DEBUG("Unable to find HANDLE %p\n", h); return status; } memset(&dma_prop, 0, sizeof(PLX_DMA_PROP)); dma_prop.ReadyInput = 1; dma_prop.Burst = 1; dma_prop.BurstInfinite = 1; dma_prop.ConstAddrLocal = 1; dma_prop.LocalBusWidth = 2; // 32-bit bus status = PlxPci_DmaChannelOpen(&(V_MAP.device[idx]), 0, &dma_prop); if (status != ApiSuccess) { _plx_log_DEBUG("Error opening PCI channel 0 for 'burst' read: HANDLE %p\n", h); _plx_print_more(status); return status; } /* If the handle is not registered as a notifier, then we need to do it. * this only needs to be done once per handle. */ if (!V_MAP.registered[idx]) { memset(&(V_MAP.intrs[idx]), 0, sizeof(PLX_INTERRUPT)); // Setup to wait for DMA channel 0 V_MAP.intrs[idx].DmaDone = 1; status = PlxPci_NotificationRegisterFor(&(V_MAP.device[idx]), &(V_MAP.intrs[idx]), &(V_MAP.events[idx])); if (status != ApiSuccess) { ignored_status = PlxPci_DmaChannelClose(&(V_MAP.device[idx]), 0); _plx_log_DEBUG("Error registering for notification of PCI DMA channel 0: " "HANDLE %p\n", h); _plx_print_more(status); return status; } V_MAP.registered[idx] = TRUE_; } /* Write transfer address to XMAP_REG_TAR */ status = plx_write_long(h, 0x50, addr); if (status != PLX_SUCCESS) { ignored_status = PlxPci_DmaChannelClose(&(V_MAP.device[idx]), 0); _plx_log_DEBUG("Error setting block address %#lx: HANDLE %p\n", addr, h); _plx_print_more(status); return status; } memset(&dma_params, 0, sizeof(PLX_DMA_PARAMS)); /* We include the dead words in the transfer */ local = (unsigned long *)malloc((len + n_dead) * sizeof(unsigned long)); if (!local) { _plx_log_DEBUG("Error allocating %d bytes for 'local'.\n", (len + 2) * sizeof(unsigned long)); return PLX_MEM; } dma_params.UserVa = (U64)local; dma_params.LocalAddr = EXTERNAL_MEMORY_LOCAL_ADDR; dma_params.ByteCount = (len + n_dead) * 4; dma_params.Direction = PLX_DMA_LOC_TO_PCI; status = PlxPci_DmaTransferUserBuffer(&(V_MAP.device[idx]), 0, &dma_params, 0); if (status != ApiSuccess) { free(local); ignored_status = PlxPci_DmaChannelClose(&(V_MAP.device[idx]), 0); _plx_log_DEBUG("Error during 'burst' read: HANDLE %p\n", h); _plx_print_more(status); return status; } /* ASSERT((V_MAP.events[idx]).IsValidTag == PLX_TAG_VALID); */ status = PlxPci_NotificationWait(&(V_MAP.device[idx]), &(V_MAP.events[idx]), 10000); if (status != ApiSuccess) { free(local); ignored_status = PlxPci_DmaChannelClose(&(V_MAP.device[idx]), 0); _plx_log_DEBUG("Error waiting for 'burst' read to complete: HANDLE %p\n", h); _plx_print_more(status); return status; } memcpy(data, local + n_dead, len * sizeof(unsigned long)); free(local); status = PlxPci_DmaChannelClose(&(V_MAP.device[idx]), 0); if (status != ApiSuccess) { _plx_log_DEBUG("Error closing PCI channel 0: HANDLE %p\n", h); _plx_print_more(status); return status; } return PLX_SUCCESS; }