Beispiel #1
0
/******************************************************************************
 *
 * Function   :  PlxChipInterruptsDisable
 *
 * Description:  Globally disables PLX chip interrupts
 *
 *****************************************************************************/
BOOLEAN
PlxChipInterruptsDisable(
    DEVICE_EXTENSION *pdx
    )
{
    U32 RegValue;


    // Disable doorbell interrupts
    PLX_PCI_REG_READ(
        pdx,
        0xc4,
        &RegValue
        );

    RegValue &= ~0xFFFF;

    PLX_PCI_REG_WRITE(
        pdx,
        0xc4,
        RegValue
        );

    // Disable Message, S_RSTIN, S_PME, & GPIO interrupts
    PLX_PCI_REG_WRITE(
        pdx,
        0xc8,
        0x00000000
        );

    return TRUE;
}
Beispiel #2
0
/*******************************************************************************
 *
 * Function   :  PlxGetExtendedCapabilityOffset
 *
 * Description:  Scans the capability list to search for a specific capability
 *
 ******************************************************************************/
U16
PlxGetExtendedCapabilityOffset(
    DEVICE_EXTENSION *pdx,
    U16               CapabilityId
    )
{
    U16 Offset_Cap;
    U32 RegValue;


    // Get offset of first capability
    PLX_PCI_REG_READ(
        pdx,
        0x34,           // PCI capabilities pointer
        &RegValue
        );

    // If link is down, PCI reg accesses will fail
    if (RegValue == (U32)-1)
        return 0;

    // Set first capability
    Offset_Cap = (U16)RegValue;

    // Traverse capability list searching for desired ID
    while ((Offset_Cap != 0) && (RegValue != (U32)-1))
    {
        // Get next capability
        PLX_PCI_REG_READ(
            pdx,
            Offset_Cap,
            &RegValue
            );

        if ((U8)RegValue == (U8)CapabilityId)
        {
            // Capability found, return base offset
            return Offset_Cap;
        }

        // Jump to next capability
        Offset_Cap = (U16)((RegValue >> 8) & 0xFF);
    }

    // Capability not found
    return 0;
}
Beispiel #3
0
/*******************************************************************************
 *
 * Function   :  PlxChipTypeDetect
 *
 * Description:  Attempts to determine PLX chip type and revision
 *
 ******************************************************************************/
PLX_STATUS
PlxChipTypeDetect(
    DEVICE_EXTENSION *pdx
    )
{
    U32 RegValue;


    // Set default values
    pdx->Key.PlxChip     = PLX_CHIP_TYPE;
    pdx->Key.PlxRevision = pdx->Key.Revision;
    pdx->Key.PlxFamily   = PLX_FAMILY_BRIDGE_P2L;

    // Check hard-coded ID
    RegValue =
        PLX_9000_REG_READ(
            pdx,
            0x70
            );

    if ((RegValue & 0xFFFF) == PLX_VENDOR_ID)
    {
        pdx->Key.PlxChip = (U16)(RegValue >> 16);

        // Get revision
        RegValue =
            PLX_9000_REG_READ(
                pdx,
                0x74           // Revision ID
                );

        // AA & AB versions have same revision ID
        if (RegValue == 0xA)
        {
            PLX_PCI_REG_READ(
                pdx,
                0x08,
                &RegValue
                );

            if ((RegValue & 0xFF) == 0x0B)
                pdx->Key.PlxRevision = 0xAB;
            else
                pdx->Key.PlxRevision = 0xAA;
        }
        else
        {
            // Check for AC revision
            if (RegValue == 0xC)
                pdx->Key.PlxRevision = 0xAC;
            else
                pdx->Key.PlxRevision = (U8)RegValue;
        }
    }
Beispiel #4
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;
}
Beispiel #5
0
/*******************************************************************************
 *
 * Function   :  StartDevice
 *
 * Description:  Start a device
 *
 ******************************************************************************/
int
StartDevice(
    DEVICE_OBJECT *fdo
)
{
    int               rc;
    U8                i;
    U8                ResourceCount;
    U32               RegValue;
    DEVICE_EXTENSION *pdx;


    if (fdo->DeviceExtension->State == PLX_STATE_STARTED)
        return 0;

    DebugPrintf(("Start device...\n"));

    pdx           = fdo->DeviceExtension;
    ResourceCount = 0;

    for (i = 0; i < PCI_NUM_BARS_TYPE_00; ++i)
    {
        // Verify the address is valid
        if (pci_resource_start(
                    pdx->pPciDevice,
                    i
                ) == 0)
        {
            continue;
        }

        DebugPrintf(("   Resource %02d\n", ResourceCount));

        // Increment resource count
        ResourceCount++;

        // Get PCI physical address
        pdx->PciBar[i].Properties.Physical =
            pci_resource_start(
                pdx->pPciDevice,
                i
            );

        // Determine resource type
        if (pci_resource_flags(
                    pdx->pPciDevice,
                    i
                ) & IORESOURCE_IO)
        {
            DebugPrintf(("     Type     : I/O\n"));

            // Make sure flags are cleared properly
            pdx->PciBar[i].Properties.Physical &= ~(0x3);
            pdx->PciBar[i].Properties.Flags     = PLX_BAR_FLAG_IO;
        }
        else
        {
            DebugPrintf(("     Type     : Memory\n"));

            // Make sure flags are cleared properly
            pdx->PciBar[i].Properties.Physical &= ~(0xf);
            pdx->PciBar[i].Properties.Flags     = PLX_BAR_FLAG_MEM;
        }

        // Set BAR as already probed
        pdx->PciBar[i].Properties.Flags |= PLX_BAR_FLAG_PROBED;

        // Get the actual BAR value
        PLX_PCI_REG_READ( pdx, 0x10 + (i * sizeof(U32)), &RegValue );
        pdx->PciBar[i].Properties.BarValue = RegValue;

        // If 64-bit BAR, get upper address
        if (pci_resource_flags(pdx->pPciDevice, i) & IORESOURCE_MEM_64)
        {
            PLX_PCI_REG_READ( pdx, 0x10 + ((i+1) * sizeof(U32)), &RegValue );
            pdx->PciBar[i].Properties.BarValue |= (U64)RegValue << 32;
        }

        DebugPrintf((
                        "     PCI BAR %d: %08llX\n",
                        i, pdx->PciBar[i].Properties.BarValue
                    ));

        DebugPrintf((
                        "     Phys Addr: %08llX\n",
                        pdx->PciBar[i].Properties.Physical
                    ));

        // Get the size
        pdx->PciBar[i].Properties.Size =
            pci_resource_len(
                pdx->pPciDevice,
                i
            );

        DebugPrintf((
                        "     Size     : %8llx (%lld %s)\n",
                        pdx->PciBar[i].Properties.Size,
                        (pdx->PciBar[i].Properties.Size < ((U64)1 << 10)) ?
                        pdx->PciBar[i].Properties.Size :
                        pdx->PciBar[i].Properties.Size >> 10,
                        (pdx->PciBar[i].Properties.Size < ((U64)1 << 10)) ? "bytes" : "KB"
                    ));

        // Set flags
        if (pdx->PciBar[i].Properties.Flags & PLX_BAR_FLAG_MEM)
        {
            if (pci_resource_flags(pdx->pPciDevice, i) & IORESOURCE_MEM_64)
                pdx->PciBar[i].Properties.Flags |= PLX_BAR_FLAG_64_BIT;
            else
                pdx->PciBar[i].Properties.Flags |= PLX_BAR_FLAG_32_BIT;

            if (pci_resource_flags(pdx->pPciDevice, i) & IORESOURCE_PREFETCH)
                pdx->PciBar[i].Properties.Flags |= PLX_BAR_FLAG_PREFETCHABLE;

            DebugPrintf((
                            "     Property : %sPrefetchable %d-bit\n",
                            (pdx->PciBar[i].Properties.Flags & PLX_BAR_FLAG_PREFETCHABLE) ? "" : "Non-",
                            (pdx->PciBar[i].Properties.Flags & PLX_BAR_FLAG_64_BIT) ? 64 : 32
                        ));
        }

        // Claim and map the resource
        rc = PlxPciBarResourceMap( pdx, i );

        if (rc == 0)
        {
            if (pdx->PciBar[i].Properties.Flags & PLX_BAR_FLAG_MEM)
            {
                DebugPrintf((
                                "     Kernel VA: %p\n",
                                pdx->PciBar[i].pVa
                            ));
            }
        }
        else
        {
            if (pdx->PciBar[i].Properties.Flags & PLX_BAR_FLAG_MEM)
            {
                ErrorPrintf(("     Kernel VA: ERROR - Unable to map space to Kernel VA\n"));
            }
        }
    }

    // Make sure BAR 0 exists or the device can't be started
    if (pdx->PciBar[0].pVa == NULL)
    {
        ErrorPrintf(("ERROR - BAR 0 mapping is required for register access\n"));
        return -ENOSYS;
    }

    // Store BAR 0 kernel virtual address for register access
    pdx->pRegVa = pdx->PciBar[0].pVa;

    // Determine & store the PLX chip type
    PlxChipTypeDetect(
        pdx
    );

    // Disable all interrupts
    PlxChipInterruptsDisable(
        pdx
    );

    // Default interrupt to none
    pdx->IrqType = PLX_IRQ_TYPE_NONE;

    // Store PCI IRQ
    pdx->IrqPci = pdx->pPciDevice->irq;

    // Install the ISR if available
    if (pdx->pPciDevice->irq == 0)
    {
        DebugPrintf(("Device not using a PCI interrupt resource\n"));
    }
    else
    {
        // Default to INTx interrupt
        pdx->IrqType = PLX_IRQ_TYPE_INTX;

        // Install the ISR
        rc =
            request_irq(
                pdx->pPciDevice->irq,    // The device IRQ
                OnInterrupt,             // Interrupt handler
                PLX_IRQF_SHARED,         // Flags, support interrupt sharing
                PLX_DRIVER_NAME,         // The driver name
                pdx                      // Parameter to the ISR
            );

        if (rc != 0)
        {
            ErrorPrintf(("ERROR - Unable to install ISR\n"));
            pdx->IrqType = PLX_IRQ_TYPE_NONE;
        }
        else
        {
            DebugPrintf(("Installed ISR for interrupt\n"));

            // Re-enable interrupts
            PlxChipInterruptsEnable(
                pdx
            );
        }
    }

    // Update device state
    pdx->State = PLX_STATE_STARTED;

    return 0;
}
Beispiel #6
0
/*******************************************************************************
 *
 * Function   :  AddDevice
 *
 * Description:  Add a new device object to the driver
 *
 ******************************************************************************/
int
AddDevice(
    DRIVER_OBJECT  *pDriverObject,
    struct pci_dev *pPciDev
)
{
#if defined(PLX_DMA_SUPPORT)
    U8                i;
#endif
    int               status;
    U32               RegValue;
    DEVICE_OBJECT    *fdo;
    DEVICE_OBJECT    *pDevice;
    DEVICE_EXTENSION *pdx;


    // Allocate memory for the device object
    fdo =
        kmalloc(
            sizeof(DEVICE_OBJECT),
            GFP_KERNEL
        );

    if (fdo == NULL)
    {
        ErrorPrintf(("ERROR - memory allocation for device object failed\n"));
        return (-ENOMEM);
    }

    // Initialize device object
    RtlZeroMemory( fdo, sizeof(DEVICE_OBJECT) );

    fdo->DriverObject    = pDriverObject;         // Save parent driver object
    fdo->DeviceExtension = &(fdo->DeviceInfo);

    // Enable the device
    if (pci_enable_device( pPciDev ) == 0)
    {
        DebugPrintf(("Enabled PCI device\n"));
    }
    else
    {
        ErrorPrintf(("WARNING - PCI device enable failed\n"));
    }

    // Enable bus mastering
    pci_set_master( pPciDev );

    //
    // Initialize the device extension
    //

    pdx = fdo->DeviceExtension;

    // Clear device extension
    RtlZeroMemory( pdx, sizeof(DEVICE_EXTENSION) );

    // Store parent device object
    pdx->pDeviceObject = fdo;

    // Save the OS-supplied PCI object
    pdx->pPciDevice = pPciDev;

    // Set initial device device state
    pdx->State = PLX_STATE_STOPPED;

    // Set initial power state
    pdx->PowerState = PowerDeviceD0;

    // Store device location information
    pdx->Key.bus          = pPciDev->bus->number;
    pdx->Key.slot         = PCI_SLOT(pPciDev->devfn);
    pdx->Key.function     = PCI_FUNC(pPciDev->devfn);
    pdx->Key.DeviceId     = pPciDev->device;
    pdx->Key.VendorId     = pPciDev->vendor;
    pdx->Key.SubVendorId  = pPciDev->subsystem_vendor;
    pdx->Key.SubDeviceId  = pPciDev->subsystem_device;
    pdx->Key.DeviceNumber = pDriverObject->DeviceCount;

    // Set API access mode
    pdx->Key.ApiMode = PLX_API_MODE_PCI;

    // Update Revision ID
    PLX_PCI_REG_READ(
        pdx,
        0x08,        // PCI Revision ID
        &RegValue
    );

    pdx->Key.Revision = (U8)(RegValue & 0xFF);

    // Build device name
    sprintf(
        pdx->LinkName,
        PLX_DRIVER_NAME "-%d",
        pDriverObject->DeviceCount
    );

    // Initialize work queue for ISR DPC queueing
    PLX_INIT_WORK(
        &(pdx->Task_DpcForIsr),
        DpcForIsr,                // DPC routine
        &(pdx->Task_DpcForIsr)    // DPC parameter (pre-2.6.20 only)
    );

    // Initialize ISR spinlock
    spin_lock_init(
        &(pdx->Lock_Isr)
    );

    // Initialize interrupt wait list
    INIT_LIST_HEAD(
        &(pdx->List_WaitObjects)
    );

    spin_lock_init(
        &(pdx->Lock_WaitObjectsList)
    );

    // Initialize physical memories list
    INIT_LIST_HEAD(
        &(pdx->List_PhysicalMem)
    );

    spin_lock_init(
        &(pdx->Lock_PhysicalMemList)
    );

#if defined(PLX_DMA_SUPPORT)
    /****************************************************************
     * Set the DMA mask
     *
     * Although PLX devices can handle 64-bit DMA addressing through
     * dual cycles, this driver does not support that feature.  As
     * a result, the OS is notified to keep this device's DMA mask
     * to 32-bit, which is the default anyway.
     ***************************************************************/
    Plx_dma_set_mask( pdx, PLX_DMA_BIT_MASK(32) );

    // Set DMA buffer allocation mask.  PLX DMA requires 32-bit for SGL buffers
    if (Plx_dma_set_coherent_mask( pdx, PLX_DMA_BIT_MASK(32) ) != 0)
    {
        ErrorPrintf(("WARNING - Set DMA coherent mask failed\n"));
    }

    // Initialize DMA spinlocks
    for (i = 0; i < NUM_DMA_CHANNELS; i++)
    {
        spin_lock_init(
            &(pdx->Lock_Dma[i])
        );
    }
#endif  // PLX_DMA_SUPPORT


    //
    // Add to driver device list
    //

    // Acquire Device List lock
    spin_lock(
        &(pDriverObject->Lock_DeviceList)
    );

    // Get device list head
    pDevice = pDriverObject->DeviceObject;

    if (pDevice == NULL)
    {
        // Add device as first in list
        pDriverObject->DeviceObject = fdo;
    }
    else
    {
        // Go to end of list
        while (pDevice->NextDevice != NULL)
            pDevice = pDevice->NextDevice;

        // Add device to end of list
        pDevice->NextDevice = fdo;
    }

    // Increment device count
    pDriverObject->DeviceCount++;

    // Release Device List lock
    spin_unlock(
        &(pDriverObject->Lock_DeviceList)
    );

    DebugPrintf((
                    "Created Device (%s)\n",
                    pdx->LinkName
                ));

    // Start the device
    status = StartDevice( fdo );
    if (status != 0)
    {
        RemoveDevice( fdo );
        return status;
    }

    return 0;
}
Beispiel #7
0
/*******************************************************************************
 *
 * Function   :  PlxInterruptDisable
 *
 * Description:  Disables specific interrupts of the PLX Chip
 *
 ******************************************************************************/
PLX_STATUS
PlxInterruptDisable(
    DEVICE_EXTENSION *pdx,
    PLX_INTERRUPT    *pPlxIntr
    )
{
    U32          RegValue;
    PLX_REG_DATA RegData;


    // Only 16 doorbell interrupts are supported
    pPlxIntr->Doorbell &= 0xFFFF;

    // Disable doorbell interrupts
    if (pPlxIntr->Doorbell)
    {
        PLX_PCI_REG_READ(
            pdx,
            0xc4,
            &RegValue
            );

        // Clear doorbell interrupts that are set
        RegValue &= 0xFFFF0000 | (~pPlxIntr->Doorbell & 0xFFFF);

        PLX_PCI_REG_WRITE(
            pdx,
            0xc4,
            RegValue
            );
    }

    // Setup to synchronize access to interrupt register
    RegData.pdx         = pdx;
    RegData.offset      = 0xc8;
    RegData.BitsToSet   = 0;
    RegData.BitsToClear = 0;

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

    if (pPlxIntr->Message & (1 << 1))
        RegData.BitsToClear |= (1 << 25);

    if (pPlxIntr->Message & (1 << 2))
        RegData.BitsToClear |= (1 << 26);

    if (pPlxIntr->Message & (1 << 3))
        RegData.BitsToClear |= (1 << 27);

    if (pPlxIntr->ResetDeassert)
        RegData.BitsToClear |= (1 << 28);

    if (pPlxIntr->PmeDeassert)
        RegData.BitsToClear |= (1 << 29);

    if (pPlxIntr->GPIO_14_15)
        RegData.BitsToClear |= (1 << 30);

    if (pPlxIntr->GPIO_4_5)
        RegData.BitsToClear |= (1 << 31);

    // Write register values if they have changed
    if (RegData.BitsToClear != 0)
    {
        // Synchronize write to interrupt register
        PlxSynchronizedRegisterModify(
            &RegData
            );
    }

    return ApiSuccess;
}
Beispiel #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;
}
/******************************************************************************
 *
 * Function   :  PlxPciBoardReset
 *
 * Description:  Resets a device using software reset feature of PLX chip
 *
 ******************************************************************************/
VOID
PlxPciBoardReset(
    DEVICE_EXTENSION *pdx
    )
{
    U8  MU_Enabled;
    U8  EepromPresent;
    U32 RegValue;
    U32 RegInterrupt;
    U32 RegMailbox0;
    U32 RegMailbox1;


    // Added to avoid compiler warnings
    RegMailbox0 = 0;
    RegMailbox1 = 0;

    // Clear any PCI errors
    PLX_PCI_REG_READ(
        pdx,
        CFG_COMMAND,
        &RegValue
        );

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

    // Save state of I2O Decode Enable
    RegValue =
        PLX_REG_READ(
            pdx,
            PCI9080_FIFO_CTRL_STAT
            );

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

    // Determine if an EEPROM is present
    RegValue =
        PLX_REG_READ(
            pdx,
            PCI9080_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 some registers if EEPROM present
    if (RegValue & (1 << 28))
    {
        RegMailbox0 =
            PLX_REG_READ(
                pdx,
                PCI9080_MAILBOX0
                );

        RegMailbox1 =
            PLX_REG_READ(
                pdx,
                PCI9080_MAILBOX1
                );

        PLX_PCI_REG_READ(
            pdx,
            CFG_INT_LINE,
            &RegInterrupt
            );
    }

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

    // Delay for a bit
    Plx_sleep(100);

    // Bring chip out of reset
    PLX_REG_WRITE(
        pdx,
        PCI9080_EEPROM_CTRL_STAT,
        RegValue
        );

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

    // Delay for a bit
    Plx_sleep(10);

    // Clear EEPROM reload
    PLX_REG_WRITE(
        pdx,
        PCI9080_EEPROM_CTRL_STAT,
        RegValue
        );

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

        PLX_REG_WRITE(
            pdx,
            PCI9080_FIFO_CTRL_STAT,
            RegValue | (1 << 0)
            );
    }

    // If EEPROM was present, restore registers
    if (EepromPresent)
    {
        // Restore saved registers
        PLX_REG_WRITE(
            pdx,
            PCI9080_MAILBOX0,
            RegMailbox0
            );

        PLX_REG_WRITE(
            pdx,
            PCI9080_MAILBOX1,
            RegMailbox1
            );

        PLX_PCI_REG_WRITE(
            pdx,
            CFG_INT_LINE,
            RegInterrupt
            );
    }
}
Beispiel #10
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 */
}