コード例 #1
0
/*******************************************************************************
 *
 * Function   :  PlxChip_MailboxWrite
 *
 * Description:  Writes to a PLX mailbox register
 *
 ******************************************************************************/
PLX_STATUS
PlxChip_MailboxWrite(
    DEVICE_EXTENSION *pdx,
    U16               mailbox,
    U32               value
    )
{
    U16 offset;


    // Verify valid mailbox
    if (((S16)mailbox < 0) || ((S16)mailbox > 7))
    {
        return ApiInvalidIndex;
    }

    // Set mailbox register base
    if ((mailbox == 0) || (mailbox == 1))
        offset = 0x78;
    else
        offset = 0x40;

    // Calculate mailbox offset
    offset = offset + (mailbox * sizeof(U32));

    // Write mailbox
    PLX_9000_REG_WRITE(
        pdx,
        offset,
        value
        );

    return ApiSuccess;
}
コード例 #2
0
/******************************************************************************
 *
 * Function   :  PlxChip_EepromWriteByOffset
 *
 * Description:  Write a 32-bit value to the EEPROM at a specified offset
 *
 ******************************************************************************/
PLX_STATUS
PlxChip_EepromWriteByOffset(
    DEVICE_EXTENSION *pdx,
    U16               offset,
    U32               value
    )
{
    U32 RegisterSave;


    // Verify the offset
    if ((offset & 0x3) || (offset > 0x200))
    {
        DebugPrintf(("ERROR - Invalid EEPROM offset\n"));
        return ApiInvalidOffset;
    }

    // Unprotect the EEPROM for write access
    RegisterSave =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_ENDIAN_DESC
            );

    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_ENDIAN_DESC,
        RegisterSave & ~(0xFF << 16)
        );

    // Write to EEPROM
    Plx9000_EepromWriteByOffset(
        pdx,
        offset,
        value
        );

    // Restore EEPROM Write-Protected Address Boundary
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_ENDIAN_DESC,
        RegisterSave
        );

    return ApiSuccess;
}
コード例 #3
0
ファイル: SuppFunc.c プロジェクト: ayuzer/qpx-gamma
/*******************************************************************************
 *
 * Function   :  PlxSynchronizedRegisterModify
 *
 * Description:  Synchronized function with ISR to modify a PLX register
 *
 ******************************************************************************/
BOOLEAN
PlxSynchronizedRegisterModify(
    PLX_REG_DATA *pRegData
    )
{
    unsigned long flags;
    U32           RegValue;


    /*************************************************
     * This routine sychronizes modification of a
     * register with the ISR.  To do this, it uses
     * a special spinlock routine provided by the
     * kernel, which will temporarily disable interrupts.
     * This code should also work on SMP systems.
     ************************************************/

    // Disable interrupts and acquire lock
    spin_lock_irqsave(
        &(pRegData->pdx->Lock_Isr),
        flags
        );

    RegValue =
        PLX_9000_REG_READ(
            pRegData->pdx,
            pRegData->offset
            );

    RegValue |= pRegData->BitsToSet;
    RegValue &= ~(pRegData->BitsToClear);

    PLX_9000_REG_WRITE(
        pRegData->pdx,
        pRegData->offset,
        RegValue
        );

    // Re-enable interrupts and release lock
    spin_unlock_irqrestore(
        &(pRegData->pdx->Lock_Isr),
        flags
        );

    return TRUE;
}
コード例 #4
0
/*******************************************************************************
 *
 * Function   :  OnInterrupt
 *
 * Description:  The Interrupt Service Routine for the PLX device
 *
 ******************************************************************************/
irqreturn_t
OnInterrupt(
    int   irq,
    void *dev_id
  #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
  , struct pt_regs *regs
  #endif
    )
{
    U32               RegValue;
    U32               RegPciInt;
    U32               InterruptSource;
    DEVICE_EXTENSION *pdx;


    // Get the device extension
    pdx = (DEVICE_EXTENSION *)dev_id;

    // Disable interrupts and acquire lock 
    spin_lock( &(pdx->Lock_Isr) ); 

    // Read interrupt status register
    RegPciInt =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_INT_CTRL_STAT
            );

    /****************************************************
     * If the chip is in a low power state, then local
     * register reads are disabled and will always return
     * 0xFFFFFFFF.  If the PLX chip's interrupt is shared
     * with another PCI device, the PXL ISR may continue
     * to be called.  This case is handled to avoid
     * erroneous reporting of an active interrupt.
     ***************************************************/
    if (RegPciInt == 0xFFFFFFFF)
    {
        spin_unlock( &(pdx->Lock_Isr) );
        return IRQ_RETVAL(IRQ_NONE);
    }

    // Check for master PCI interrupt enable
    if ((RegPciInt & (1 << 8)) == 0)
    {
        spin_unlock( &(pdx->Lock_Isr) );
        return IRQ_RETVAL(IRQ_NONE);
    }

    // Verify that an interrupt is truly active

    // Clear the interrupt type flag
    InterruptSource = INTR_TYPE_NONE;

    // Check if PCI Doorbell Interrupt is active and not masked
    if ((RegPciInt & (1 << 13)) && (RegPciInt & (1 << 9)))
    {
        InterruptSource |= INTR_TYPE_DOORBELL;
    }

    // Check if PCI Abort Interrupt is active and not masked
    if ((RegPciInt & (1 << 14)) && (RegPciInt & (1 << 10)))
    {
        InterruptSource |= INTR_TYPE_PCI_ABORT;
    }

    // Check if Local->PCI Interrupt is active and not masked
    if ((RegPciInt & (1 << 15)) && (RegPciInt & (1 << 11)))
    {
        InterruptSource |= INTR_TYPE_LOCAL_1;
    }

    // Check if DMA Channel 0 Interrupt is active and not masked
    if ((RegPciInt & (1 << 21)) && (RegPciInt & (1 << 18)))
    {
        // Verify the DMA interrupt is routed to PCI
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_DMA0_MODE
                );

        if (RegValue & (1 << 17))
        {
            InterruptSource |= INTR_TYPE_DMA_0;
        }
    }

    // Check if DMA Channel 1 Interrupt is active and not masked
    if ((RegPciInt & (1 << 22)) && (RegPciInt & (1 << 19)))
    {
        // Verify the DMA interrupt is routed to PCI
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_DMA1_MODE
                );

        if (RegValue & (1 << 17))
        {
            InterruptSource |= INTR_TYPE_DMA_1;
        }
    }

    // Check if MU Outbound Post interrupt is active
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_OUTPOST_INT_STAT
            );

    if (RegValue & (1 << 3))
    {
        // Check if MU Outbound Post interrupt is not masked
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_OUTPOST_INT_MASK
                );

        if ((RegValue & (1 << 3)) == 0)
        {
            InterruptSource |= INTR_TYPE_OUTBOUND_POST;
        }
    }

    // Return if no interrupts are active
    if (InterruptSource == INTR_TYPE_NONE)
    {
        spin_unlock( &(pdx->Lock_Isr) );
        return IRQ_RETVAL(IRQ_NONE);
    }

    // At this point, the device interrupt is verified

    // Mask the PCI Interrupt
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_INT_CTRL_STAT,
        RegPciInt & ~(1 << 8)
        );

    // Re-enable interrupts and release lock 
    spin_unlock( &(pdx->Lock_Isr) ); 

    //
    // Schedule deferred procedure (DPC) to complete interrupt processing
    //

    // Provide interrupt source to DPC
    pdx->Source_Ints = InterruptSource;

    // If device is no longer started, do not schedule a DPC
    if (pdx->State != PLX_STATE_STARTED)
        return IRQ_RETVAL(IRQ_HANDLED);

    // Add task to system work queue
    schedule_work(
        &(pdx->Task_DpcForIsr)
        );

    // Flag a DPC is pending
    pdx->bDpcPending = TRUE;

    return IRQ_RETVAL(IRQ_HANDLED);
}
コード例 #5
0
/*******************************************************************************
 *
 * Function   :  DpcForIsr
 *
 * Description:  This routine will be triggered by the ISR to service an interrupt
 *
 ******************************************************************************/
VOID
DpcForIsr(
    PLX_DPC_PARAM *pArg1
    )
{
    U32                 RegValue;
    unsigned long       flags;
    DEVICE_EXTENSION   *pdx;
    PLX_INTERRUPT_DATA  IntData;


    // Get the device extension
    pdx =
        container_of(
            pArg1,
            DEVICE_EXTENSION,
            Task_DpcForIsr
            );

    // Abort DPC if device is being stopped and resources released
    if ((pdx->State != PLX_STATE_STARTED) || (pdx->PciBar[0].pVa == NULL))
    {
        DebugPrintf(("DPC aborted, device is stopping\n"));

        // Flag DPC is no longer pending
        pdx->bDpcPending = FALSE;

        return;
    }

    // Get interrupt source
    IntData.Source_Ints     = pdx->Source_Ints;
    IntData.Source_Doorbell = 0;

    // Local Interrupt 1
    if (IntData.Source_Ints & INTR_TYPE_LOCAL_1)
    {
        // Synchronize access to Interrupt Control/Status Register
        spin_lock_irqsave( &(pdx->Lock_Isr), flags );

        // Mask local interrupt 1 since true source is unknown
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_INT_CTRL_STAT
                );

        RegValue &= ~(1 << 11);

        PLX_9000_REG_WRITE(
            pdx,
            PCI9056_INT_CTRL_STAT,
            RegValue
            );

        spin_unlock_irqrestore( &(pdx->Lock_Isr), flags );
    }

    // Doorbell Interrupt
    if (IntData.Source_Ints & INTR_TYPE_DOORBELL)
    {
        // Get Doorbell register
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_PCI_DOORBELL
                );

        // Clear Doorbell interrupt
        PLX_9000_REG_WRITE(
            pdx,
            PCI9056_PCI_DOORBELL,
            RegValue
            );

        // Save the doorbell value
        IntData.Source_Doorbell = RegValue;
    }

    // PCI Abort interrupt
    if (IntData.Source_Ints & INTR_TYPE_PCI_ABORT)
    {
        // Get the PCI Command register
        PLX_PCI_REG_READ(
            pdx,
            0x04,
            &RegValue
            );

        // Write to back to clear PCI Abort
        PLX_PCI_REG_WRITE(
            pdx,
            0x04,
            RegValue
            );
    }

    // DMA Channel 0 interrupt
    if (IntData.Source_Ints & INTR_TYPE_DMA_0)
    {
        // Get DMA Control/Status
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_DMA_COMMAND_STAT
                );

        // Clear DMA interrupt
        PLX_9000_REG_WRITE(
            pdx,
            PCI9056_DMA_COMMAND_STAT,
            RegValue | (1 << 3)
            );

        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_DMA0_MODE
                );

        // Check if SGL is enabled & cleanup
        if (RegValue & (1 << 9))
        {
            PlxSglDmaTransferComplete(
                pdx,
                0
                );
        }
    }

    // DMA Channel 1 interrupt
    if (IntData.Source_Ints & INTR_TYPE_DMA_1)
    {
        // Get DMA Control/Status
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_DMA_COMMAND_STAT
                );

        // Clear DMA interrupt
        PLX_9000_REG_WRITE(
            pdx,
            PCI9056_DMA_COMMAND_STAT,
            RegValue | (1 << 11)
            );

        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_DMA1_MODE
                );

        // Check if SGL is enabled & cleanup
        if (RegValue & (1 << 9))
        {
            PlxSglDmaTransferComplete(
                pdx,
                1
                );
        }
    }

    // Outbound post FIFO interrupt
    if (IntData.Source_Ints & INTR_TYPE_OUTBOUND_POST)
    {
        // Mask Outbound Post interrupt
        PLX_9000_REG_WRITE(
            pdx,
            PCI9056_OUTPOST_INT_MASK,
            (1 << 3)
            );
    }

    // Signal any objects waiting for notification
    PlxSignalNotifications(
        pdx,
        &IntData
        );

    // Re-enable interrupts
    PlxChipInterruptsEnable(
        pdx
        );

    // Flag a DPC is no longer pending
    pdx->bDpcPending = FALSE;
}
コード例 #6
0
/******************************************************************************
 *
 * Function   :  PlxChip_DmaControl
 *
 * Description:  Control the DMA engine
 *
 ******************************************************************************/
PLX_STATUS
PlxChip_DmaControl(
    DEVICE_EXTENSION *pdx,
    U8                channel,
    PLX_DMA_COMMAND   command,
    VOID             *pOwner
    )
{
    U8  shift;
    U32 RegValue;


    // Verify valid DMA channel
    switch (channel)
    {
        case 0:
        case 1:
            break;

        default:
            DebugPrintf(("ERROR - Invalid DMA channel\n"));
            return ApiDmaChannelInvalid;
    }

    // Verify owner
    if ((pdx->DmaInfo[channel].bOpen) && (pdx->DmaInfo[channel].pOwner != pOwner))
    {
        DebugPrintf(("ERROR - DMA owned by different process\n"));
        return ApiDeviceInUse;
    }

    // Set shift for status register
    shift = (channel * 8);

    switch (command)
    {
        case DmaPause:
            // Pause the DMA Channel
            RegValue =
                PLX_9000_REG_READ(
                    pdx,
                    PCI9056_DMA_COMMAND_STAT
                    );

            PLX_9000_REG_WRITE(
                pdx,
                PCI9056_DMA_COMMAND_STAT,
                RegValue & ~((1 << 0) << shift)
                );

            // Check if the transfer has completed
            RegValue =
                PLX_9000_REG_READ(
                    pdx,
                    PCI9056_DMA_COMMAND_STAT
                    );

            if (RegValue & ((1 << 4) << shift))
                return ApiDmaDone;
            break;

        case DmaResume:
            // Verify that the DMA Channel is paused
            RegValue =
                PLX_9000_REG_READ(
                    pdx,
                    PCI9056_DMA_COMMAND_STAT
                    );

            if ((RegValue & (((1 << 4) | (1 << 0)) << shift)) == 0)
            {
                PLX_9000_REG_WRITE(
                    pdx,
                    PCI9056_DMA_COMMAND_STAT,
                    RegValue | ((1 << 0) << shift)
                    );
            }
            else
            {
                return ApiDmaInProgress;
            }
            break;

        case DmaAbort:
            // Pause the DMA Channel
            RegValue =
                PLX_9000_REG_READ(
                    pdx,
                    PCI9056_DMA_COMMAND_STAT
                    );

            PLX_9000_REG_WRITE(
                pdx,
                PCI9056_DMA_COMMAND_STAT,
                RegValue & ~((1 << 0) << shift)
                );

            // Check if the transfer has completed
            RegValue =
                PLX_9000_REG_READ(
                    pdx,
                    PCI9056_DMA_COMMAND_STAT
                    );

            if (RegValue & ((1 << 4) << shift))
                return ApiDmaDone;

            // Abort the transfer (should cause an interrupt)
            PLX_9000_REG_WRITE(
                pdx,
                PCI9056_DMA_COMMAND_STAT,
                RegValue | ((1 << 2) << shift)
                );
            break;

        default:
            return ApiDmaCommandInvalid;
    }

    return ApiSuccess;
}
コード例 #7
0
/******************************************************************************
 *
 * Function   :  PlxChip_DmaSetProperties
 *
 * Description:  Sets the current DMA properties
 *
 ******************************************************************************/
PLX_STATUS
PlxChip_DmaSetProperties(
    DEVICE_EXTENSION *pdx,
    U8                channel,
    PLX_DMA_PROP     *pProp,
    VOID             *pOwner
    )
{
    U16 OffsetMode;
    U32 RegValue;


    // Verify valid DMA channel
    switch (channel)
    {
        case 0:
            OffsetMode = PCI9056_DMA0_MODE;
            break;

        case 1:
            OffsetMode = PCI9056_DMA1_MODE;
            break;

        default:
            DebugPrintf(("ERROR - Invalid DMA channel\n"));
            return ApiDmaChannelInvalid;
    }

    // Verify owner
    if ((pdx->DmaInfo[channel].bOpen) && (pdx->DmaInfo[channel].pOwner != pOwner))
    {
        DebugPrintf(("ERROR - DMA owned by different process\n"));
        return ApiDeviceInUse;
    }

    // Verify DMA not in progress
    if (PlxChip_DmaStatus(
            pdx,
            channel,
            pOwner
            ) != ApiDmaDone)
    {
        DebugPrintf(("ERROR - DMA transfer in progress\n"));
        return ApiDmaInProgress;
    }

    // Set DMA properties
    RegValue =
        (pProp->LocalBusWidth     <<  0) |
        (pProp->WaitStates        <<  2) |
        (pProp->ReadyInput        <<  6) |
        (pProp->BurstInfinite     <<  7) |
        (pProp->Burst             <<  8) |
        (pProp->SglMode           <<  9) |
        (pProp->DoneInterrupt     << 10) |
        (pProp->ConstAddrLocal    << 11) |
        (pProp->DemandMode        << 12) |
        (pProp->WriteInvalidMode  << 13) |
        (pProp->EnableEOT         << 14) |
        (pProp->FastTerminateMode << 15) |
        (pProp->ClearCountMode    << 16) |
        (pProp->RouteIntToPci     << 17) |
        (pProp->DualAddressMode   << 18) |
        (pProp->EOTEndLink        << 19) |
        (pProp->ValidMode         << 20) |
        (pProp->ValidStopControl  << 21);

    // Update properties
    PLX_9000_REG_WRITE(
        pdx,
        OffsetMode,
        RegValue
        );

    return ApiSuccess;
}
コード例 #8
0
/******************************************************************************
 *
 * Function   :  PlxChip_BoardReset
 *
 * Description:  Resets a device using software reset feature of PLX chip
 *
 ******************************************************************************/
PLX_STATUS
PlxChip_BoardReset(
    DEVICE_EXTENSION *pdx
    )
{
    U8  MU_Enabled;
    U8  EepromPresent;
    U32 RegValue;
    U32 RegInterrupt;
    U32 RegHotSwap;
    U32 RegPowerMgmnt;


    // Clear any PCI errors (04[31:27])
    PLX_PCI_REG_READ(
        pdx,
        0x04,
        &RegValue
        );

    if (RegValue & (0xf8 << 24))
    {
        // Write value back to clear aborts
        PLX_PCI_REG_WRITE(
            pdx,
            0x04,
            RegValue
            );
    }

    // Save state of I2O Decode Enable
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_FIFO_CTRL_STAT
            );

    MU_Enabled = (U8)(RegValue & (1 << 0));

    // Determine if an EEPROM is present
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_EEPROM_CTRL_STAT
            );

    // Make sure S/W Reset & EEPROM reload bits are clear
    RegValue &= ~((1 << 30) | (1 << 29));

    // Remember if EEPROM is present
    EepromPresent = (U8)((RegValue >> 28) & (1 << 0));

    // Save interrupt line
    PLX_PCI_REG_READ(
        pdx,
        0x3C,
        &RegInterrupt
        );

    // Save some registers if EEPROM present
    if (EepromPresent)
    {
        PLX_PCI_REG_READ(
            pdx,
            PCI9056_HS_CAP_ID,
            &RegHotSwap
            );

        PLX_PCI_REG_READ(
            pdx,
            PCI9056_PM_CSR,
            &RegPowerMgmnt
            );
    }

    // Issue Software Reset to hold PLX chip in reset
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_EEPROM_CTRL_STAT,
        RegValue | (1 << 30)
        );

    // Delay for a bit
    Plx_sleep(100);

    // Bring chip out of reset
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_EEPROM_CTRL_STAT,
        RegValue
        );

    // Issue EEPROM reload in case now programmed
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_EEPROM_CTRL_STAT,
        RegValue | (1 << 29)
        );

    // Delay for a bit
    Plx_sleep(10);

    // Clear EEPROM reload
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_EEPROM_CTRL_STAT,
        RegValue
        );

    // Restore I2O Decode Enable state
    if (MU_Enabled)
    {
        // Save state of I2O Decode Enable
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_FIFO_CTRL_STAT
                );

        PLX_9000_REG_WRITE(
            pdx,
            PCI9056_FIFO_CTRL_STAT,
            RegValue | (1 << 0)
            );
    }

    // Restore interrupt line
    PLX_PCI_REG_WRITE(
        pdx,
        0x3C,
        RegInterrupt
        );

    // If EEPROM was present, restore registers
    if (EepromPresent)
    {
        // Mask out HS bits that can be cleared
        RegHotSwap &= ~((1 << 23) | (1 << 22) | (1 << 17));

        PLX_PCI_REG_WRITE(
            pdx,
            PCI9056_HS_CAP_ID,
            RegHotSwap
            );

        // Mask out PM bits that can be cleared
        RegPowerMgmnt &= ~(1 << 15);

        PLX_PCI_REG_READ(
            pdx,
            PCI9056_PM_CSR,
            &RegPowerMgmnt
            );
    }

    return ApiSuccess;
}
コード例 #9
0
/******************************************************************************
 *
 * Function   :  PlxChip_InterruptDisable
 *
 * Description:  Disables specific interrupts of the PLX Chip
 *
 ******************************************************************************/
PLX_STATUS
PlxChip_InterruptDisable(
    DEVICE_EXTENSION *pdx,
    PLX_INTERRUPT    *pPlxIntr
    )
{
    U32          QueueCsr;
    U32          QueueCsr_Original;
    U32          RegValue;
    PLX_REG_DATA RegData;


    // Setup to synchronize access to Interrupt Control/Status Register
    RegData.pdx         = pdx;
    RegData.offset      = PCI9056_INT_CTRL_STAT;
    RegData.BitsToSet   = 0;
    RegData.BitsToClear = 0;

    if (pPlxIntr->PciMain)
        RegData.BitsToClear |= (1 << 8);

    if (pPlxIntr->PciAbort)
        RegData.BitsToClear |= (1 << 10);

    if (pPlxIntr->TargetRetryAbort)
        RegData.BitsToClear |= (1 << 12);

    if (pPlxIntr->LocalToPci & (1 << 0))
        RegData.BitsToClear |= (1 << 11);

    if (pPlxIntr->Doorbell)
        RegData.BitsToClear |= (1 << 9);

    if (pPlxIntr->DmaDone & (1 << 0))
    {
        // Check if DMA interrupt is routed to PCI
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_DMA0_MODE
                );

        if (RegValue & (1 << 17))
        {
            RegData.BitsToClear |= (1 << 18);

            // Disable DMA interrupt enable
            PLX_9000_REG_WRITE(
                pdx,
                PCI9056_DMA0_MODE,
                RegValue & ~(1 << 10)
                );
        }
    }

    if (pPlxIntr->DmaDone & (1 << 1))
    {
        // Check if DMA interrupt is routed to PCI
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                PCI9056_DMA1_MODE
                );

        if (RegValue & (1 << 17))
        {
            RegData.BitsToClear |= (1 << 19);

            // Disable DMA interrupt enable
            PLX_9000_REG_WRITE(
                pdx,
                PCI9056_DMA1_MODE,
                RegValue & ~(1 << 10)
                );
        }
    }

    // Inbound Post Queue Interrupt Control/Status Register
    QueueCsr_Original =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_FIFO_CTRL_STAT
            );

    QueueCsr = QueueCsr_Original;

    if (pPlxIntr->MuOutboundPost)
    {
        PLX_9000_REG_WRITE(
            pdx,
            PCI9056_OUTPOST_INT_MASK,
            (1 << 3)
            );
    }

    if (pPlxIntr->MuInboundPost)
        QueueCsr |= (1 << 4);

    if (pPlxIntr->MuOutboundOverflow)
        QueueCsr |= (1 << 6);

    // Write register values if they have changed
    if (RegData.BitsToClear != 0)
    {
        // Synchronize write of Interrupt Control/Status Register
        PlxSynchronizedRegisterModify(
            &RegData
            );
    }

    if (QueueCsr != QueueCsr_Original)
    {
        PLX_9000_REG_WRITE(
            pdx,
            PCI9056_FIFO_CTRL_STAT,
            QueueCsr
            );
    }

    return ApiSuccess;
}
コード例 #10
0
/******************************************************************************
 *
 * Function   :  PlxChip_DmaTransferUserBuffer
 *
 * Description:  Transfers a user-mode buffer using SGL DMA
 *
 ******************************************************************************/
PLX_STATUS
PlxChip_DmaTransferUserBuffer(
    DEVICE_EXTENSION *pdx,
    U8                channel,
    PLX_DMA_PARAMS   *pParams,
    VOID             *pOwner
    )
{
    U8         shift;
    U16        OffsetMode;
    U32        RegValue;
    U32        SglPciAddress;
    BOOLEAN    bBits64;
    PLX_STATUS rc;


    // Verify DMA channel & setup register offsets
    switch (channel)
    {
        case 0:
            OffsetMode = PCI9056_DMA0_MODE;
            break;

        case 1:
            OffsetMode = PCI9056_DMA1_MODE;
            break;

        default:
            DebugPrintf(("ERROR - Invalid DMA channel\n"));
            return ApiDmaChannelInvalid;
    }

    // Verify owner
    if (pdx->DmaInfo[channel].pOwner != pOwner)
    {
        DebugPrintf(("ERROR - DMA owned by different process\n"));
        return ApiDeviceInUse;
    }

    // Set shift for status register
    shift = (channel * 8);

    // Verify that DMA is not in progress
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_DMA_COMMAND_STAT
            );

    if ((RegValue & ((1 << 4) << shift)) == 0)
    {
        DebugPrintf(("ERROR - DMA channel is currently active\n"));
        return ApiDmaInProgress;
    }

    spin_lock(
        &(pdx->Lock_Dma[channel])
        );

    // Verify DMA channel was opened
    if (pdx->DmaInfo[channel].bOpen == FALSE)
    {
        DebugPrintf(("ERROR - DMA channel has not been opened\n"));

        spin_unlock(
            &(pdx->Lock_Dma[channel])
            );

        return ApiDmaChannelUnavailable;
    }

    // Verify an SGL DMA transfer is not pending
    if (pdx->DmaInfo[channel].bSglPending)
    {
        DebugPrintf(("ERROR - An SGL DMA transfer is currently pending\n"));

        spin_unlock(
            &(pdx->Lock_Dma[channel])
            );

        return ApiDmaInProgress;
    }

    // Set the SGL DMA pending flag
    pdx->DmaInfo[channel].bSglPending = TRUE;

    spin_unlock(
        &(pdx->Lock_Dma[channel])
        );

    // Get DMA mode
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            OffsetMode
            );

    // Keep track if local address should remain constant
    if (RegValue & (1 << 11))
        pdx->DmaInfo[channel].bConstAddrLocal = TRUE;
    else
        pdx->DmaInfo[channel].bConstAddrLocal = FALSE;

    // Page-lock user buffer & build SGL
    rc =
        PlxLockBufferAndBuildSgl(
            pdx,
            channel,
            pParams,
            &SglPciAddress,
            &bBits64
            );

    if (rc != ApiSuccess)
    {
        DebugPrintf(("ERROR - Unable to lock buffer and build SGL list\n"));
        pdx->DmaInfo[channel].bSglPending = FALSE;
        return rc;
    }

    spin_lock(
        &(pdx->Lock_Dma[channel])
        );

    // Disable valid mode
    RegValue &= ~(1 << 20);

    // Enable DMA chaining, interrupt, & route interrupt to PCI
    RegValue |= (1 << 9) | (1 << 10) | (1 << 17);

    // Enable dual-addressing DMA if 64-bit DMA is required
    if (bBits64)
        RegValue |= (1 << 18);
    else
        RegValue &= ~(1 << 18);

    PLX_9000_REG_WRITE(
        pdx,
        OffsetMode,
        RegValue
        );

    // Clear DAC upper 32-bit PCI address in case it contains non-zero value
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_DMA0_PCI_DAC + (channel * sizeof(U32)),
        0
        );

    // Write SGL physical address & set descriptors in PCI space
    PLX_9000_REG_WRITE(
        pdx,
        OffsetMode + 0x10,
        SglPciAddress | (1 << 0)
        );

    // Enable DMA channel
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_DMA_COMMAND_STAT
            );

    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_DMA_COMMAND_STAT,
        RegValue | ((1 << 0) << shift)
        );

    spin_unlock(
        &(pdx->Lock_Dma[channel])
        );

    DebugPrintf(("Starting DMA transfer...\n"));

    // Start DMA
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_DMA_COMMAND_STAT,
        RegValue | (((1 << 0) | (1 << 1)) << shift)
        );

    return ApiSuccess;
}
コード例 #11
0
/******************************************************************************
 *
 * Function   :  PlxChip_DmaTransferBlock
 *
 * Description:  Performs DMA block transfer
 *
 ******************************************************************************/
PLX_STATUS
PlxChip_DmaTransferBlock(
    DEVICE_EXTENSION *pdx,
    U8                channel,
    PLX_DMA_PARAMS   *pParams,
    VOID             *pOwner
    )
{
    U8  shift;
    U16 OffsetMode;
    U32 RegValue;


    // Verify DMA channel & setup register offsets
    switch (channel)
    {
        case 0:
            OffsetMode = PCI9056_DMA0_MODE;
            break;

        case 1:
            OffsetMode = PCI9056_DMA1_MODE;
            break;

        default:
            DebugPrintf(("ERROR - Invalid DMA channel\n"));
            return ApiDmaChannelInvalid;
    }

    // Verify owner
    if (pdx->DmaInfo[channel].pOwner != pOwner)
    {
        DebugPrintf(("ERROR - DMA owned by different process\n"));
        return ApiDeviceInUse;
    }

    // Set shift for status register
    shift = (channel * 8);

    // Verify that DMA is not in progress
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_DMA_COMMAND_STAT
            );

    if ((RegValue & ((1 << 4) << shift)) == 0)
    {
        DebugPrintf(("ERROR - DMA channel is currently active\n"));
        return ApiDmaInProgress;
    }

    spin_lock(
        &(pdx->Lock_Dma[channel])
        );

    // Verify DMA channel was opened
    if (pdx->DmaInfo[channel].bOpen == FALSE)
    {
        DebugPrintf(("ERROR - DMA channel has not been opened\n"));

        spin_unlock(
            &(pdx->Lock_Dma[channel])
            );

        return ApiDmaChannelUnavailable;
    }

    // Get DMA mode
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            OffsetMode
            );

    // Disable DMA chaining & SGL dual-addressing
    RegValue &= ~((1 << 9) | (1 << 18));

    // Route interrupt to PCI
    RegValue |= (1 << 17);

    // Ignore interrupt if requested
    if (pParams->bIgnoreBlockInt)
        RegValue &= ~(1 << 10);
    else
        RegValue |= (1 << 10);

    PLX_9000_REG_WRITE(
        pdx,
        OffsetMode,
        RegValue
        );

    // Write PCI Address
    PLX_9000_REG_WRITE(
        pdx,
        OffsetMode + 0x4,
        PLX_64_LOW_32(pParams->PciAddr)
        );

    // Write Local Address
    PLX_9000_REG_WRITE(
        pdx,
        OffsetMode + 0x8,
        pParams->LocalAddr
        );

    // Write Transfer Count
    PLX_9000_REG_WRITE(
        pdx,
        OffsetMode + 0xc,
        pParams->ByteCount
        );

    // Write Descriptor Pointer
    if (pParams->Direction == PLX_DMA_LOC_TO_PCI)
        RegValue = (1 << 3);
    else
        RegValue = 0;

    PLX_9000_REG_WRITE(
        pdx,
        OffsetMode + 0x10,
        RegValue
        );

    // Write Dual Address cycle with upper 32-bit PCI address
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_DMA0_PCI_DAC + (channel * sizeof(U32)),
        PLX_64_HIGH_32(pParams->PciAddr)
        );

    // Enable DMA channel
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            PCI9056_DMA_COMMAND_STAT
            );

    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_DMA_COMMAND_STAT,
        RegValue | ((1 << 0) << shift)
        );

    spin_unlock(
        &(pdx->Lock_Dma[channel])
        );

    DebugPrintf(("Starting DMA transfer...\n"));

    // Start DMA
    PLX_9000_REG_WRITE(
        pdx,
        PCI9056_DMA_COMMAND_STAT,
        RegValue | (((1 << 0) | (1 << 1)) << shift)
        );

    return ApiSuccess;
}
コード例 #12
0
/*
**===========================================================================
** 8.0			pcidriver_ioctl()
**===========================================================================
** Description: 
**
** Parameters:  cmd and a argument
**              
**
** Returns:     some stuff ...
**
** Globals:     
*/
int plx_drv_ioctl(struct inode *inode, struct file *file,
		    unsigned int cmd, unsigned long arg)
{

driver_t  *dev = file->private_data;

  static unsigned char localbuf[IOC_BUFSIZE];
  /* Define "alias" names for the localbuf */
  void *karg = localbuf;
  Register *reg = karg;
  unsigned long *klong = karg;
  Container *container = karg;
 int size = _IOC_SIZE(cmd); /* the size bitfield in cmd */
  int retval = 0; /* success by default */

#if ZERO
PDEBUG(("function: %s, file: %s line: %d invoked\n", __FUNCTION__, __FILE__, __LINE__));
#endif

 /*
   * Extract the type and number bitfields, and don't decode
   * wrong cmds: return EINVAL before verify_area()
   */
  if (_IOC_TYPE(cmd) != MAG_NUM) return -ENOTTY;
  if (_IOC_NR(cmd) > IOC_MAXNR) return -ENOTTY;

  /*
   * The direction is a bitmask, and VERIFY_WRITE catches R/W
   * transfers. `Dir' is user-oriented, while
   * verify_area is kernel-oriented, so the concept of "read" and
   * "write" is reversed
   */
  if (_IOC_DIR(cmd) & _IOC_READ) {
    if (!access_ok(VERIFY_WRITE, (void *)arg, size))
      return -EFAULT;
  }
  else if (_IOC_DIR(cmd) & _IOC_WRITE) {
    if (!access_ok(VERIFY_READ, (void *)arg, size))
      return -EFAULT;
  }

#if ZERO
  PDEBUG(("ioctl.c: %08x %08lx: nr %i, size %i, dir %i\n",
	 cmd, arg, _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd)));
#endif

  /* First, retrieve data from userspace */
  if ((_IOC_DIR(cmd) & _IOC_WRITE) && (size <= IOC_BUFSIZE))
    if (copy_from_user(karg, (void *)arg, size))
      return -EFAULT;

  /* We are ready to switch ... */
  switch (cmd) {

  case READ_PLX_REG:
   {
     if ((plx_read_plx_reg(dev, reg->addr, &(reg->data)) == 0)) { 
//       PDEBUG(("plx_read_fpga_reg: addr: %x and data %x\n", reg->addr, reg->data));
      }
      else
       return -EIO;
 
   }
   break;
  case WRITE_PLX_REG:
   {
     if((plx_write_plx_reg(dev, reg->addr, reg->data)) == 0) {
//         PDEBUG(("plx_write_fpga_reg: addr: %x and data %x\n", reg->addr, reg->data));
      }
      else
       return -EIO; 
 
   }

  break;


  case FILL_PCI_MEM:
    PDEBUG(("plx_ioctl: Fill PCI memory with test pattern!\n")); 

   memset_io(dev->PciBar[2].pVa, 0x11, DMA_SIZE/4);
   memset_io((dev->PciBar[2].pVa)+0x2000, 0x22, DMA_SIZE/4); 
   memset_io((dev->PciBar[2].pVa)+(0x2000*2), 0x33, DMA_SIZE/4); 
   memset_io((dev->PciBar[2].pVa)+(0x2000*3), 0x44, DMA_SIZE/4); 
  break;


 case READ_FPGA_REG:
      if ((plx_read_fpga_reg(dev, reg->addr, &(reg->data)) == 0)) { 
       PDEBUG(("plx_read_fpga_reg: addr: %x and data %x\n", reg->addr, reg->data));
      }
      else
       return -EIO; // Physical input/output error occured
   break;

case WRITE_FPGA_REG:
     if((plx_write_fpga_reg(dev, reg->addr, reg->data)) == 0) {
         PDEBUG(("plx_write_fpga_reg: addr: %x and data %x\n", reg->addr, reg->data));
      }
      else
       return -EIO; 

   break;

case WRITE_SRAM:
     if((plx_write_sram(dev, reg->addr, reg->data)) == 0) {
         PDEBUG(("plx_write_sram: addr: %x and data %x\n", reg->addr, reg->data));
      }
      else
       return -EIO; 

   break;


 case READ_COMMAND_LINK_REG:
    
      if ((plx_read_reg(dev, reg->addr, &(reg->data)) == 0)) { 
       PDEBUG(("plx_read_reg: addr: %x and data %x\n", reg->addr, reg->data));
      }
      else
       return -EIO; 
   
    break;

  case WRITE_COMMAND_LINK_REG:
    PDEBUG(("ioctl.c: addr: %x and data %x\n", reg->addr, reg->data));
  
      if((plx_write_reg(dev, reg->addr, reg->data)) == 0) {
         PDEBUG(("plx_write_reg: addr: %x and data %x\n", reg->addr, reg->data));
      }
      else
       return -EIO; 
    break;

    case IMMEDIATE_COMMAND:
      switch( *klong) {
 
      case XL_EXEC:
        /* Read the micro sec counter */
        plx_diff_since_read(dev);
      case XL_NOP:
      case XL_INIT:
      case XL_STOP:
        if((plx_immediate_cmd(dev, *klong) == 0)) {
       }
       else {
	retval = -EIO;
        }
       break;
    default :
      retval = -EFAULT;     
   }
   break;


  case ORDER_HW:

     switch (container->order) {
 
     case 0x1:  // Dump PCI memory
       { int i; unsigned int tmp;
       PDEBUG(("ioctl: order_hw, start_addr%x\n", container->start_addr));
       for (i = 0; i <16; i++) { 
         tmp = SRAM_READ(dev, (container->start_addr) +(i*4)); 
         container->array[i] = tmp; 

       } 

       }

       break; 
     case 0x2:   // Reset HW
       plx_board_reset(dev);
       break;
     case 0x3:  // Read and clear device driver counters
      {
       container->array[0] = dev->cntr_circ_empty_rp;
       container->array[1] = dev->cntr_irq_count;
       container->array[2] = dev->cntr_irq_processed;
       container->array[3] = dev->cntr_irq_none;
       container->array[4] = dev->cntr_low_power_state;
       container->array[5] = dev->cntr_pci_master_disabled;
       container->array[6] = dev->cntr_lost_ints;
       container->array[7] = dev->cntr_read;
       container->array[8] = dev->cntr_poll;
       container->array[9] = dev->cntr_failed_dma;
       container->array[10] = dev->cntr_circ_full_wp;
       container->array[11] = dev->cntr_circ_full_ip;
       container->array[12] = dev->cntr_2_user_space;
       container->array[13] = dev->cntr_tmo_rdr;
       container->array[14] = dev->cntr_tmo_tbe;
       container->array[15] = dev->cntr_lost_hw_ints;

       dev->cntr_circ_empty_rp = dev->cntr_irq_count = dev->cntr_irq_processed = dev->cntr_irq_none = 0;
       dev->cntr_low_power_state = dev->cntr_pci_master_disabled =  0;
       dev->cntr_read = dev->cntr_poll = dev->cntr_failed_dma = dev->cntr_2_user_space = 0;
       dev->cntr_tmo_rdr = dev->cntr_tmo_tbe = dev->cntr_circ_full_wp = dev->cntr_lost_ints = 0;
       dev->cntr_lost_hw_ints = dev->cntr_circ_full_ip = 0;
      }
      break;
     case 0x4:

     break;
     case 0x5:
#if ZERO
       PDEBUG(("order_hw: read time:%d\n", plx_diff_since_read(dev)));
#endif
     break;

#if DMA_DEBUG
     case 0x6:

     {
        int r;

        /* Write a test pattern at start address  in kernel mem */

       for(r = 0; r < NO_OF_BUFFERS ; r++) {
        *(unsigned long *)(dev->frames[r]) = 0xcdcdfbfb;

       }
     }
     break;

     case 0x7:

     {
        int r;

        /* Read test pattern at start address  in kernel mem */

       for(r = 0; r < NO_OF_BUFFERS ; r++) {
       PDEBUG(("r:%d:%lx\n", r, *(unsigned long *)(dev->frames[r])));

       }
     }
     break;

     case 0x8:
      {
          U32 RegValue;


   /* Abort a DMA, should generate an interrupt */
    RegValue =
	PLX_9000_REG_READ(
			  dev,
			  PCI8311_DMA_COMMAND_STAT
			  );

     // Abort the transfer (should cause an interrupt)
      PLX_9000_REG_WRITE(
			 dev,
			 PCI8311_DMA_COMMAND_STAT,
			 RegValue | ((1 << 2))
			 );

      }
     break;
#endif
     case 0x9:
        PDEBUG(("order_hw: ip%d, wp%d, rp%d\n", dev->ip , dev->wp, dev->rp));
        dev->wp = dev->rp = dev->ip = 0;
      break;

     /* Disable driver debug */
     case 0xa:
        debug = 0;
      break;

     /* Enable driver debug */
     case 0xb:
        debug = 1;
      break;

     /* Reset sequence counters in hw and driver */
     case 0xc:
        dev->seq_cntr = 0;
        plx_immediate_cmd(dev, XL_INIT);
      break;

     /* Generate a local interrupt */
     case 0xd:
      { u32 RegDetectorInt;

        RegDetectorInt = COMMAND_LINK_REG_READ(dev, PCI_MC_CARD_STATUS);
        RegDetectorInt |= (1<<29);
        COMMAND_LINK_REG_WRITE(dev,PCI_MC_CARD_STATUS,RegDetectorInt); 

      }  
      break;

     default:
       ERROR(("ioctl: no such order: %x\n", container->order));
       retval = -EFAULT;     
       break;
     }

  case DRIVER_VERSION:
   reg->data = DEVICE_DRIVER_VERSION;
   break;	

  case READ_CONFIG_REG:
  {
    PLX_PCI_REG_READ(dev, reg->addr,&reg->data);
   }
   break;

  default:
    ERROR(("ioctl: no such command: %x\n", cmd));
    return -ENOIOCTLCMD; 
}

  /* Finally, copy data to user space and return */
  if (retval < 0) return retval;
  if ((_IOC_DIR(cmd) & _IOC_READ) && (size <= IOC_BUFSIZE))
    if (copy_to_user((void *)arg, karg, size))
      return -EFAULT;
  return retval; /* sometimes, positive is what I want */
}