/* $Id: VBoxPciInternal.h $ */
/** @file
 * VBoxPci - PCI driver (Host), Internal Header.
 */

/*
 * Copyright (C) 2011-2016 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#ifndef ___VBoPciInternal_h___
#define ___VBoxPciInternal_h___

#include <VBox/sup.h>
#include <VBox/rawpci.h>
#include <iprt/semaphore.h>
#include <iprt/assert.h>

#ifdef RT_OS_LINUX

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) && defined(CONFIG_IOMMU_API)
# define VBOX_WITH_IOMMU
#endif

#ifdef VBOX_WITH_IOMMU
#include <linux/errno.h>
#include <linux/iommu.h>
#endif

#endif

RT_C_DECLS_BEGIN

/* Forward declaration. */
typedef struct VBOXRAWPCIGLOBALS *PVBOXRAWPCIGLOBALS;
typedef struct VBOXRAWPCIDRVVM   *PVBOXRAWPCIDRVVM;
typedef struct VBOXRAWPCIINS     *PVBOXRAWPCIINS;

typedef struct VBOXRAWPCIISRDESC
{
    /** Handler function. */
    PFNRAWPCIISR       pfnIrqHandler;
    /** Handler context. */
    void              *pIrqContext;
    /** Host IRQ. */
    int32_t            iHostIrq;
} VBOXRAWPCIISRDESC;
typedef struct VBOXRAWPCIISRDESC     *PVBOXRAWPCIISRDESC;

/**
 * The per-instance data of the VBox raw PCI interface.
 *
 * This is data associated with a host PCI card attached to the VM.
 *
 */
typedef struct VBOXRAWPCIINS
{
    /** Pointer to the globals. */
    PVBOXRAWPCIGLOBALS pGlobals;

     /** Mutex protecting device access. */
    RTSEMFASTMUTEX     hFastMtx;
    /** The spinlock protecting the state variables and device access. */
    RTSPINLOCK         hSpinlock;
    /** Pointer to the next device in the list. */
    PVBOXRAWPCIINS     pNext;
    /** Reference count. */
    uint32_t volatile cRefs;

    /* Host PCI address of this device. */
    uint32_t           HostPciAddress;

#ifdef RT_OS_LINUX
    struct pci_dev  *  pPciDev;
    char               szPrevDriver[64];
#endif
    bool               fMsiUsed;
    bool               fMsixUsed;
    bool               fIommuUsed;
    bool               fPad0;

    /** Port, given to the outside world. */
    RAWPCIDEVPORT      DevPort;

    /** IRQ handler. */
    VBOXRAWPCIISRDESC  IrqHandler;

    /** Pointer to per-VM context in hypervisor data. */
    PRAWPCIPERVM       pVmCtx;

    RTR0PTR            aRegionR0Mapping[/* XXX: magic */ 7];
} VBOXRAWPCIINS;

/**
 * Per-VM data of the VBox PCI driver. Pointed to by pGVM->rawpci.s.pDriverData.
 *
 */
typedef struct VBOXRAWPCIDRVVM
{
    /** Mutex protecting state changes. */
    RTSEMFASTMUTEX hFastMtx;

#ifdef RT_OS_LINUX
# ifdef VBOX_WITH_IOMMU
    /* IOMMU domain. */
    struct iommu_domain* pIommuDomain;
# endif
#endif
    /* Back pointer to pGVM->rawpci.s. */
    PRAWPCIPERVM pPerVmData;
} VBOXRAWPCIDRVVM;

/**
 * The global data of the VBox PCI driver.
 *
 * This contains the bit required for communicating with support driver, VBoxDrv
 * (start out as SupDrv).
 */
typedef struct VBOXRAWPCIGLOBALS
{
    /** Mutex protecting the list of instances and state changes. */
    RTSEMFASTMUTEX hFastMtx;

    /** Pointer to a list of instance data. */
    PVBOXRAWPCIINS pInstanceHead;

    /** The raw PCI interface factory. */
    RAWPCIFACTORY RawPciFactory;
    /** The SUPDRV component factory registration. */
    SUPDRVFACTORY SupDrvFactory;
    /** The number of current factory references. */
    int32_t volatile cFactoryRefs;
    /** Whether the IDC connection is open or not.
     * This is only for cleaning up correctly after the separate IDC init on Windows. */
    bool fIDCOpen;
    /** The SUPDRV IDC handle (opaque struct). */
    SUPDRVIDCHANDLE SupDrvIDC;
#ifdef RT_OS_LINUX
    bool fPciStubModuleAvail;
    struct module    * pciStubModule;
#endif
} VBOXRAWPCIGLOBALS;

DECLHIDDEN(int)  vboxPciInit(PVBOXRAWPCIGLOBALS pGlobals);
DECLHIDDEN(void) vboxPciShutdown(PVBOXRAWPCIGLOBALS pGlobals);

DECLHIDDEN(int)  vboxPciOsInitVm(PVBOXRAWPCIDRVVM pThis,   PVM pVM, PRAWPCIPERVM pVmData);
DECLHIDDEN(void) vboxPciOsDeinitVm(PVBOXRAWPCIDRVVM pThis, PVM pVM);

DECLHIDDEN(int)  vboxPciOsDevInit  (PVBOXRAWPCIINS pIns, uint32_t fFlags);
DECLHIDDEN(int)  vboxPciOsDevDeinit(PVBOXRAWPCIINS pIns, uint32_t fFlags);
DECLHIDDEN(int)  vboxPciOsDevDestroy(PVBOXRAWPCIINS pIns);

DECLHIDDEN(int)  vboxPciOsDevGetRegionInfo(PVBOXRAWPCIINS pIns,
                                           int32_t        iRegion,
                                           RTHCPHYS       *pRegionStart,
                                           uint64_t       *pu64RegionSize,
                                           bool           *pfPresent,
                                           uint32_t       *pfFlags);
DECLHIDDEN(int)  vboxPciOsDevMapRegion(PVBOXRAWPCIINS pIns,
                                       int32_t        iRegion,
                                       RTHCPHYS       pRegionStart,
                                       uint64_t       u64RegionSize,
                                       uint32_t       fFlags,
                                       RTR0PTR        *pRegionBase);
DECLHIDDEN(int)  vboxPciOsDevUnmapRegion(PVBOXRAWPCIINS pIns,
                                         int32_t        iRegion,
                                         RTHCPHYS       RegionStart,
                                         uint64_t       u64RegionSize,
                                         RTR0PTR        RegionBase);

DECLHIDDEN(int)  vboxPciOsDevPciCfgWrite(PVBOXRAWPCIINS pIns, uint32_t Register, PCIRAWMEMLOC *pValue);
DECLHIDDEN(int)  vboxPciOsDevPciCfgRead (PVBOXRAWPCIINS pIns, uint32_t Register, PCIRAWMEMLOC *pValue);

DECLHIDDEN(int)  vboxPciOsDevRegisterIrqHandler  (PVBOXRAWPCIINS pIns, PFNRAWPCIISR pfnHandler, void* pIrqContext, int32_t *piHostIrq);
DECLHIDDEN(int)  vboxPciOsDevUnregisterIrqHandler(PVBOXRAWPCIINS pIns, int32_t iHostIrq);

DECLHIDDEN(int)  vboxPciOsDevPowerStateChange(PVBOXRAWPCIINS pIns, PCIRAWPOWERSTATE  aState);

#define VBOX_DRV_VMDATA(pIns) ((PVBOXRAWPCIDRVVM)(pIns->pVmCtx ? pIns->pVmCtx->pDriverData : NULL))

RT_C_DECLS_END

#endif
