VirtioNet-solaris.c revision 38b0f04a36431d57eed1de01653dd0a015eae4c3
/* $Id$ */
/** @file
* VirtualBox Guest Additions: Virtio Network Driver for Solaris.
*/
/*
* 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 *
*******************************************************************************/
#include "Virtio-solaris.h"
#include "VirtioPci-solaris.h"
#include <sys/mac_provider.h>
#include <iprt/initterm.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
#define DEVICE_NAME "virtnet"
/** The module descriptions as seen in 'modinfo'. */
#define DEVICE_DESC_DRV "VirtualBox VirtioNet"
/** Copied from "mac_ether.h" - why the heck is this not public?? All Solaris
* mac clients use it... */
#define MAC_PLUGIN_IDENT_ETHER "mac_ether"
/* Copied from our Virtio Device emulation. */
#if defined(DEBUG_ramshankar)
# define LogFlowFunc LogRel
#endif
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static int VirtioNetStart(void *pvArg);
static void VirtioNetStop(void *pvArg);
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Device operations for Virtio Net.
*/
{
};
/**
* virtio_net_t: Private data per Virtio Device.
*/
typedef struct virtio_net_t
{
} virtio_net_t;
/**
* virtio_txbuf_t: Virtio Net TX buffer.
*/
typedef struct virtio_net_txbuf_t
{
/*
*/
typedef struct virtio_net_header_t
{
/**
* MAC layer hooks for VirtioNet.
*/
static mac_callbacks_t g_VirtioNetCallbacks =
{
MC_GETCAPAB, /* Mask of available extra hooks. */
NULL, /* Reserved. */
NULL, /* IOCtl. */
};
/**
*/
static ddi_dma_attr_t g_VirtioNetBufDmaAttr =
{
DMA_ATTR_V0, /* Version. */
0, /* Lowest usable address. */
0xffffffffffffffffULL, /* Highest usable address. */
0x7fffffff, /* Maximum DMAable byte count. */
MMU_PAGESIZE, /* 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). */
};
/**
*/
static struct cb_ops g_VirtioNetCbOps =
{
nulldev, /* cb open */
nulldev, /* cb close */
nodev, /* b strategy */
nodev, /* b dump */
nodev, /* b print */
nodev, /* cb read */
nodev, /* cb write */
nodev, /* cb ioctl */
nodev, /* c devmap */
nodev, /* c mmap */
nodev, /* c segmap */
nochpoll, /* c poll */
ddi_prop_op, /* property ops */
NULL, /* streamtab */
D_MP, /* compat. flag */
CB_REV /* revision */
};
/**
*/
static struct dev_ops g_VirtioNetDevOps =
{
DEVO_REV, /* driver build revision */
0, /* ref count */
NULL, /* get info */
nulldev, /* identify */
nulldev, /* probe */
nodev, /* reset */
(struct bus_ops *)0,
nodev /* power */
};
/**
* modldrv: export driver specifics to kernel
*/
static struct modldrv g_VirtioNetDriver =
{
&mod_driverops, /* extern from kernel */
};
/**
*/
static struct modlinkage g_VirtioNetModLinkage =
{
MODREV_1, /* loadable module system revision */
{
&g_VirtioNetDriver, /* driver framework */
NULL /* terminate array of linkage structures */
}
};
/**
* Kernel entry points
*/
int _init(void)
{
/*
* Prevent module autounloading.
*/
if (pModCtl)
else
/*
* Initialize IPRT.
*/
if (RT_SUCCESS(rc))
{
/*
* Initialize Solaris specific globals here.
*/
if (!rc)
return rc;
RTR0Term();
return rc;
}
else
return RTErrConvertToErrno(rc);
}
int _fini(void)
{
int rc;
if (!rc)
{
RTR0Term();
}
return rc;
}
{
return rc;
}
/**
* Attach entry point, to attach a device to the system or resume it.
*
* @param pDip The module structure instance.
*
* @return corresponding solaris error code.
*/
{
}
/**
* Detach entry point, to detach a device to the system or suspend it.
*
* @param pDip The module structure instance.
*
* @return corresponding solaris error code.
*/
{
}
/**
* Virtio Net TX buffer constructor for kmem_cache_create().
*
* @param pvBuf Pointer to the allocated buffer.
* @param pvArg Opaque private data.
* @param fFlags Propagated KM flag values.
*
* @return 0 on success, or -1 on failure.
*/
{
/* @todo ncookies handles? */
if (rc == DDI_SUCCESS)
return 0;
return -1;
}
/**
* Virtio Net TX buffer destructor for kmem_cache_create().
*
* @param pvBuf Pointer to the allocated buffer.
* @param pvArg
*/
{
}
/**
* Virtio Net private data allocation routine.
*
* @param pDevice Pointer to the Virtio device instance.
*
* @return Allocated private data that must only be freed by calling
* VirtioNetDevFree().
*/
{
{
/*
* Create a kernel memory cache for frequently allocated/deallocated
* buffers.
*/
char szCachename[KSTAT_STRLEN];
RTStrPrintf(szCachename, sizeof(szCachename), "VirtioNet_Cache_%d", ddi_get_instance(pDevice->pDip));
sizeof(virtio_net_txbuf_t), /* Size of buffers in cache */
0, /* Align */
VirtioNetTxBufCreate, /* Buffer constructor */
VirtioNetTxBufDestroy, /* Buffer destructor */
NULL, /* pfnReclaim */
pDevice, /* Private data */
NULL, /* "vmp", MBZ (man page) */
0 /* "cflags", MBZ (man page) */
);
return pNet;
else
}
else
return NULL;
}
/**
* Virtio Net private data free routine.
*
* @param pDevice Pointer to the Virtio device instance.
*/
{
}
/**
* Virtio Net device attach rountine.
*
* @param pDevice Pointer to the Virtio device instance.
*
* @return corresponding solaris error code.
*/
{
if (pMacRegHandle)
{
pMacRegHandle->m_min_sdu = 0;
/* @todo should we set the margin size? */
/*
* Get MAC from the host or generate a random MAC address.
*/
{
LogFlow((VIRTIOLOGNAME ":VirtioNetDevAttach: Obtained MAC address from host: %.6Rhxs\n", pNet->MacAddr.au8));
}
else
{
}
if (rc == DDI_SUCCESS)
{
if (rc == 0)
{
return DDI_SUCCESS;
}
else
}
else
}
else
return DDI_FAILURE;
}
/**
* Virtio Net device detach routine.
*
* @param pDevice Pointer to the Virtio device instance.
*
* @return corresponding solaris error code.
*/
{
if (rc == 0)
{
return DDI_SUCCESS;
}
else
return DDI_FAILURE;
}
/**
* Attach the Virtio Net TX, RX and control queues.
*
* @param pDevice Pointer to the Virtio device instance.
*
* @return corresponding solaris error code.
*/
{
{
{
{
if (pNet->pCtrlQueue)
{
return DDI_SUCCESS;
}
else
}
else
{
return DDI_SUCCESS;
}
}
else
}
else
return DDI_FAILURE;
}
/**
* Detach the Virtio Net TX, RX and control queues.
*
* @param pDevice Pointer to the Virtio device instance.
*/
{
&& pNet->pCtrlQueue)
}
/* -=-=-=-=- Virtio Net MAC layer callbacks -=-=-=-=- */
/**
* Virtio Net statistics.
*
* @param pvArg Pointer to private data.
* @param cmdStat Which statistics to provide.
* @param pu64Val Where to write statistics data.
*
* @return corresponding solaris error code.
*/
{
return ENOTSUP;
}
/**
* Virtio Net Start.
*
* @param pvArg Pointer to private data.
*
* @return corresponding solaris error code.
*/
static int VirtioNetStart(void *pvArg)
{
return 0;
}
/**
* Virtio Net Stop.
*
* @param pvArg Pointer to private data.
*/
static void VirtioNetStop(void *pvArg)
{
/*
* I don't think we should set status here as the host checks the status on every Xmit. This means pending Xmits
* would also be dropped.
* @todo: Not sure what's the best way to signal connect/disconnect of the link to the host. Figure it out.
*/
}
/**
* Virtio Net toggle Promiscuous mode.
*
* @param pvArg Pointer to private data.
*
* @return corresponding solaris error code.
*/
{
return 0;
}
/**
*
* @param pvArg Pointer to private data.
* @param fAdd Whether to add multicast address or not.
*
* @return corresponding solaris error code.
*/
{
return 1;
}
/**
* Virtio Net set unicast address.
*
* @param pvArg Pointer to private data.
* @param pbMac Pointer to the unicast MAC address to set.
*
* @return corresponding solaris error code.
*/
{
return ENOTSUP;
}
/**
* Virtio Net get capabilities hook.
*
* @param pvArg Pointer to private data.
* @param Capab MAC layer capabilities.
* @param pvCapabData Pointer to store capability info.
*
* @return B_TRUE upon success, otherwise B_FALSE.
*/
{
return B_FALSE;
}
/**
* Virtio Net Xmit hook.
*
* @param pvArg Pointer to private data.
* @param pMsg Pointer to the message.
*
* @return Pointer to message not Xmited.
*/
{
bool fNotify = false;
while (pMsg)
{
#if 0
if (RT_UNLIKELY(!pHdr))
break;
#endif
if (!pTxBuf)
break;
int rc = ddi_dma_addr_bind_handle(pTxBuf->hDMA, NULL /* addrspace */, (char *)pMsg->b_rptr, MBLKL(pMsg),
if (rc != DDI_DMA_MAPPED)
{
break;
}
/** @todo get 'cCookies' slots from the ring. */
{
if (i < cCookies - 1)
if (RT_FAILURE(rc))
{
break;
}
}
fNotify = true;
if (RT_FAILURE(rc))
{
break;
}
}
if (fNotify)
return pMsg;
}
/**
* Interrupt Service Routine for Virtio Net.
*
* @param Arg Private data (unused, will be NULL).
* @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
*/
{
return DDI_INTR_UNCLAIMED;
}