/** * interrupt_wait() will wait on the PCI interrupt line and determine if GPIO * input or DMA requested the interrupt * * @return 1 if success 0 if failure */ int interrupt_wait(U32 * interrupt) { int rc; /*clear and reset interrupt structure*/ memset(&plx_intr, 0, sizeof (PLX_INTERRUPT)); /*set interrupt structure*/ plx_intr.LocalToPci = 1; //set bit 11 // plx_intr.PciMain = 1; // Bit 8 -- should already been on /*enable interrupt on PLX bridge*/ rc = PlxPci_InterruptEnable(&fpga_dev, &plx_intr); // sets PCI9056_INT_CTRL_STAT if (rc != ApiSuccess) PlxSdkErrorDisplay(rc); /*register for interrupt with kernel*/ rc = PlxPci_NotificationRegisterFor(&fpga_dev, &plx_intr, &plx_event); if (rc != ApiSuccess) PlxSdkErrorDisplay(rc); /*wait for interrupt*/ int waitrc = PlxPci_NotificationWait(&fpga_dev, &plx_event, FPGA_TIMEOUT); /*cancel interrupt notification*/ rc = PlxPci_NotificationCancel(&fpga_dev, &plx_event); if (rc != ApiSuccess) PlxSdkErrorDisplay(rc); /*disable interrupt*/ rc = PlxPci_InterruptDisable(&fpga_dev, &plx_intr); // sets PCI9056_INT_CTRL_STAT if (rc != ApiSuccess) PlxSdkErrorDisplay(rc); /*handle return code of wait function*/ if (waitrc == ApiWaitTimeout) { *interrupt = TIMEOUT_INT; return TRUE; } else if (waitrc == ApiSuccess) { *interrupt = INP_INT; return TRUE; } else if (waitrc == ApiWaitCanceled) { record("Wait canceled\n"); return FALSE; } else { record("Wait returned an unknown value\n"); return FALSE; } }
void InterruptTest( PLX_DEVICE_OBJECT *pDevice ) { PLX_STATUS rc; PLX_INTERRUPT PlxInterrupt; PLX_NOTIFY_OBJECT NotifyObject; Cons_printf( "Description:\n" " This sample demonstrates how to use the PLX API for\n" " notification of the generic Local->PCI interrupts (e.g. LINTi#).\n" " The interrupt trigger must be initiated by the\n" " OEM hardware. PLX software is not able to manually\n" " assert the interrupt since its source is OEM-dependent.\n" "\n" " Press any key to start...\n" "\n" ); Cons_getch(); Cons_printf(" Register for notification...... "); // Clear interrupt fields memset(&PlxInterrupt, 0, sizeof(PLX_INTERRUPT)); // Setup to wait for either generic interrupt PlxInterrupt.LocalToPci = (1 << 0) | (1 << 1); rc = PlxPci_NotificationRegisterFor( pDevice, &PlxInterrupt, &NotifyObject ); if (rc != ApiSuccess) { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(rc); } else { Cons_printf("Ok\n"); } /*********************************************************** * This loop will loop only one time. It is provided here to * demonstrate which code should be placed within the loop * if waiting for the interrupt multiple times. * Note that the generic L->P interrupt must constantly be * re-enabled since the PLX driver will mask it. **********************************************************/ do { Cons_printf(" Enable interrupt(s)............ "); rc = PlxPci_InterruptEnable( pDevice, &PlxInterrupt ); if (rc != ApiSuccess) { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(rc); } else { Cons_printf("Ok\n"); } Cons_printf( "\n" " -- You may now trigger the interrupt --\n" "\n" ); Cons_printf(" Wait for interrupt event....... "); rc = PlxPci_NotificationWait( pDevice, &NotifyObject, 120 * 1000 ); switch (rc) { case ApiSuccess: Cons_printf("Ok (Int received)\n"); /************************************************ * * Custom code to clear the OEM source of the * interrupt should be placed here. Another option * is to modify the PLX driver interrupt handler * to perform the souce clear. In that case, it * will not constantly need to be masked/re-enabled. * ***********************************************/ break; case ApiWaitTimeout: Cons_printf("*ERROR* - Timeout waiting for Int Event\n"); break; case ApiWaitCanceled: Cons_printf("*ERROR* - Interrupt event cancelled\n"); break; default: Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(rc); break; } Cons_printf(" Check notification status...... "); rc = PlxPci_NotificationStatus( pDevice, &NotifyObject, &PlxInterrupt ); if (rc == ApiSuccess) { Cons_printf("Ok (triggered ints:"); if (PlxInterrupt.LocalToPci & (1 << 0)) Cons_printf(" L->P 1"); if (PlxInterrupt.LocalToPci & (1 << 1)) Cons_printf(" L->P 2"); Cons_printf(")\n"); } else { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(rc); } } while (0); // Release the interrupt wait object Cons_printf(" Cancelling Int Notification.... "); rc = PlxPci_NotificationCancel( pDevice, &NotifyObject ); if (rc != ApiSuccess) { Cons_printf("*ERROR* - API failed\n"); PlxSdkErrorDisplay(rc); } else { Cons_printf("Ok\n"); } }
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; }