VirtioPci-solaris.c revision 87902654924b5893d165c3f31f1d8a50f87205b4
/* $Id$ */
/** @file
* VirtualBox Guest Additions - Virtio Driver for Solaris, PCI Hypervisor Interface.
*/
/*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* 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.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#ifdef DEBUG_ramshankar
# define LOG_INSTANCE RTLogRelDefaultInstance()
#endif
#include "VirtioPci-solaris.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/*
* Pci Register offsets.
*/
#define VIRTIO_PCI_HOST_FEATURES 0x00
#define VIRTIO_PCI_GUEST_FEATURES 0x04
#define VIRTIO_PCI_QUEUE_PFN 0x08
#define VIRTIO_PCI_QUEUE_NUM 0x0C
#define VIRTIO_PCI_QUEUE_SEL 0x0E
#define VIRTIO_PCI_QUEUE_NOTIFY 0x10
#define VIRTIO_PCI_STATUS 0x12
#define VIRTIO_PCI_ISR 0x13
#define VIRTIO_PCI_CONFIG 0x14
#define VIRTIO_PCI_RING_ALIGN PAGE_SIZE
/**
* virtio_pci_t: Private data per device instance.
*/
typedef struct virtio_pci_t
{
} virtio_pci_t;
/**
* virtio_pci_queue_t: Private data per queue instance.
*/
typedef struct virtio_pci_queue_t
{
{
DDI_DEVICE_ATTR_V0, /* Version */
DDI_STRUCTURE_LE_ACC, /* Structural data access in little endian. */
DDI_STRICTORDER_ACC, /* Strict ordering. */
DDI_DEFAULT_ACC /* Default access, possible panic on errors*/
};
{
DDI_DEVICE_ATTR_V0, /* Version. */
DDI_NEVERSWAP_ACC, /* Data access with no byte swapping*/
DDI_STRICTORDER_ACC, /* Strict ordering. */
DDI_DEFAULT_ACC /* Default access, possible panic on errors*/
};
static ddi_dma_attr_t g_VirtioPciDmaAttrRing =
{
DMA_ATTR_V0, /* Version. */
0, /* Lowest usable address. */
0xffffffffffffffffULL, /* Highest usable address. */
0x7fffffff, /* Maximum DMAable byte count. */
VIRTIO_PCI_RING_ALIGN, /* Alignment in bytes. */
0x7ff, /* Bitmap of burst sizes */
1, /* Minimum transfer. */
0xffffffffU, /* Maximum transfer. */
0xffffffffffffffffULL, /* Maximum segment length. */
1, /* Maximum number of segments. */
1, /* Granularity. */
0 /* Flags (reserved). */
};
/** Pointer to the interrupt handle vector */
static ddi_intr_handle_t *g_pIntr;
/** Number of actually allocated interrupt handles */
static size_t g_cIntrAllocated;
/** The IRQ Mutex */
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/**
* Hypervisor operations for Virtio Pci.
*/
{
};
/**
* Virtio Pci private data allocation routine.
*
* @param pDevice Pointer to the Virtio device instance.
* @return Allocated private data structure which must only be freed by calling
* VirtioPciFree().
*/
{
return pPciData;
}
/**
* Virtio Pci private data deallocation routine.
*
* @param pDevice Pointer to the Virtio device instance.
*/
{
if (pPciData)
{
}
}
/**
* Virtio Pci attach routine, called from driver attach.
*
* @param pDevice Pointer to the Virtio device instance.
*
* @return Solaris DDI error code. DDI_SUCCESS or DDI_FAILURE.
*/
{
1, /* reg. num */
0, /* offset */
0, /* length */
if (rc == DDI_SUCCESS)
{
/*
* Reset the device.
*/
/*
* Add interrupt handler.
*/
return DDI_SUCCESS;
}
else
return DDI_FAILURE;
}
/**
* Virtio Pci detach routine, called from driver detach.
*
* @param pDevice Pointer to the Virtio device instance.
*
* @return Solaris DDI error code. DDI_SUCCESS or DDI_FAILURE.
*/
{
return DDI_SUCCESS;
}
/**
* Get host supported features.
*
* @param pDevice Pointer to the Virtio device instance.
*
* @return Mask of host features.
*/
{
AssertReturn(pPciData, 0);
}
/**
* Set guest supported features.
*
* @param pDevice Pointer to the Virtio device instance.
* @param u32Features Mask of guest supported features.
*/
{
ddi_put32(pPciData->hIO, (uint32_t *)(pPciData->addrIOBase + VIRTIO_PCI_GUEST_FEATURES), u32Features);
}
/**
* Update the queue, notify the host.
*
* @param pDevice Pointer to the Virtio device instance.
* @param pQueue Pointer to the Queue that is doing the notification.
*
* @return Solaris DDI error code. DDI_SUCCESS or DDI_FAILURE.
*/
{
ddi_put16(pPciData->hIO, (uint16_t *)(pPciData->addrIOBase + VIRTIO_PCI_QUEUE_NOTIFY), pQueue->QueueIndex);
}
/**
* Virtio Pci set (write) routine.
*
* @param pDevice Pointer to the Virtio device instance.
* @param off Offset into the PCI config space.
* @param pv Pointer to the buffer to write from.
* @param cb Size of the buffer in bytes.
*/
{
}
/**
* Virtio Pci get (read) routine.
*
* @param pDevice Pointer to the Virtio device instance.
* @param off Offset into the PCI config space.
* @param pv Where to store the read data.
* @param cb Size of the buffer in bytes.
*/
{
}
/**
* Virtio Pci put queue routine. Places the queue and frees associated queue.
*
* @param pDevice Pointer to the Virtio device instance.
* @param pQueue Pointer to the queue.
*/
{
if (RT_UNLIKELY(!pPciQueue))
{
return;
}
}
/**
* Virtio Pci get queue routine. Allocates a PCI queue and DMA resources.
*
* @param pDevice Pointer to the Virtio device instance.
* @param pQueue Where to store the queue.
*
* @return An allocated Virtio Pci queue, or NULL in case of errors.
*/
{
/*
* Select a Queue.
*/
/*
* Get the currently selected Queue's size.
*/
{
return NULL;
}
/*
* Check if it's already active.
*/
if (QueuePFN != 0)
{
return NULL;
}
/*
* Allocate and initialize Pci queue data.
*/
if (pPciQueue)
{
/*
* Setup DMA.
*/
int rc = ddi_dma_alloc_handle(pDevice->pDip, &g_VirtioPciDmaAttrRing, DDI_DMA_SLEEP, 0 /* addr */, &pPciQueue->hDMA);
if (rc == DDI_SUCCESS)
{
if (rc == DDI_SUCCESS)
{
rc = ddi_dma_addr_bind_handle(pPciQueue->hDMA, NULL /* addrspace */, pQueue->pQueue, pPciQueue->cbBuf,
if (rc == DDI_SUCCESS)
{
LogFlow((VIRTIOLOGNAME ":VirtioPciGetQueue: Queue[%d]%p physBuf=%x pfn of Buf %#x\n", pQueue->QueueIndex,
/*
* Activate the queue and initialize a ring for the queue.
*/
return pPciQueue;
}
else
}
else
LogRel((VIRTIOLOGNAME ":VirtioPciGetQueue: ddi_dma_mem_alloc failed for %u bytes rc=%d\n", cbQueue, rc));
}
else
}
else
LogRel((VIRTIOLOGNAME ":VirtioPciGetQueue: failed to alloc %u bytes for Pci Queue data.\n", sizeof(virtio_pci_queue_t)));
return NULL;
}
/**
* Set the Virtio PCI status bit.
*
* @param pDevice Pointer to the Virtio device instance.
* @param Status The status to set.
*/
{
}
/**
* Sets up IRQ for Virtio PCI.
*
* @param pDip Pointer to the device info structure.
*
* @return Solaris error code.
*/
{
int IntrType = 0;
if (rc == DDI_SUCCESS)
{
/* We won't need to bother about MSIs. */
if (IntrType & DDI_INTR_TYPE_FIXED)
{
int IntrCount = 0;
if ( rc == DDI_SUCCESS
&& IntrCount > 0)
{
int IntrAvail = 0;
if ( rc == DDI_SUCCESS
&& IntrAvail > 0)
{
/* Allocated kernel memory for the interrupt handles. The allocation size is stored internally. */
if (g_pIntr)
{
int IntrAllocated;
if ( rc == DDI_SUCCESS
&& IntrAllocated > 0)
{
if (rc == DDI_SUCCESS)
{
/* Initialize the mutex. */
/* Assign interrupt handler functions and enable interrupts. */
for (int i = 0; i < IntrAllocated; i++)
{
if (rc == DDI_SUCCESS)
if (rc != DDI_SUCCESS)
{
/* Changing local IntrAllocated to hold so-far allocated handles for freeing. */
IntrAllocated = i;
break;
}
}
if (rc == DDI_SUCCESS)
{
return rc;
}
/* Remove any assigned handlers */
for (int x = 0; x < IntrAllocated; x++)
}
else
/* Remove allocated IRQs, too bad we can free only one handle at a time. */
for (int k = 0; k < g_cIntrAllocated; k++)
ddi_intr_free(g_pIntr[k]);
}
else
}
else
}
else
{
LogRel((VIRTIOLOGNAME ":VirtioPciSetupIRQ: failed to get or insufficient available IRQs. rc=%d IntrAvail=%d\n",
}
}
else
{
LogRel((VIRTIOLOGNAME ":VirtioPciSetupIRQ: failed to get or insufficient number of IRQs. rc=%d IntrCount=%d\n", rc,
IntrCount));
}
}
else
}
else
return rc;
}
/**
* Removes IRQ for Virtio PCI device.
*
* @param pDip Pointer to the device info structure.
*/
{
for (int i = 0; i < g_cIntrAllocated; i++)
{
if (rc == DDI_SUCCESS)
{
if (rc == DDI_SUCCESS)
ddi_intr_free(g_pIntr[i]);
}
}
}
/**
* Interrupt Service Routine for Virtio PCI device.
*
* @param Arg Private data (unused, will be NULL).
* @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
*/
{
bool fOurIRQ = false;
/*
* Call the DeviceOps ISR routine somehow which should notify all Virtio queues
* on the interrupt.
*/
}