VirtualBox

source: vbox/trunk/src/VBox/Additions/solaris/Virtio/VirtioNet-solaris.c@ 34575

Last change on this file since 34575 was 34143, checked in by vboxsync, 14 years ago

Additions/Solaris/Virtio: export to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.5 KB
Line 
1/* $Id: VirtioNet-solaris.c 34143 2010-11-17 20:05:36Z vboxsync $ */
2/** @file
3 * VirtualBox Guest Additions: Virtio Network Driver for Solaris.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#include "Virtio-solaris.h"
31#include "VirtioPci-solaris.h"
32
33#include <sys/conf.h>
34#include <sys/sunddi.h>
35#include <sys/mac_provider.h>
36#include <sys/strsun.h>
37#include <sys/cmn_err.h>
38
39#include <iprt/assert.h>
40#include <iprt/initterm.h>
41#include <iprt/err.h>
42#include <VBox/log.h>
43#include <iprt/mem.h>
44#include <iprt/rand.h>
45#include <iprt/string.h>
46
47/*******************************************************************************
48* Defined Constants And Macros *
49*******************************************************************************/
50#define DEVICE_NAME "virtnet"
51/** The module descriptions as seen in 'modinfo'. */
52#define DEVICE_DESC_DRV "VirtualBox VirtioNet"
53
54/** Copied from "mac_ether.h" - why the heck is this not public?? All Solaris
55 * mac clients use it... */
56#define MAC_PLUGIN_IDENT_ETHER "mac_ether"
57
58/* Copied from our Virtio Device emulation. */
59#define VIRTIO_NET_CSUM 0x00000001 /* Host handles pkts w/ partial csum */
60#define VIRTIO_NET_GUEST_CSUM 0x00000002 /* Guest handles pkts w/ partial csum */
61#define VIRTIO_NET_MAC 0x00000020 /* Host has given MAC address. */
62#define VIRTIO_NET_GSO 0x00000040 /* Host handles pkts w/ any GSO type */
63#define VIRTIO_NET_GUEST_TSO4 0x00000080 /* Guest can handle TSOv4 in. */
64#define VIRTIO_NET_GUEST_TSO6 0x00000100 /* Guest can handle TSOv6 in. */
65#define VIRTIO_NET_GUEST_ECN 0x00000200 /* Guest can handle TSO[6] w/ ECN in. */
66#define VIRTIO_NET_GUEST_UFO 0x00000400 /* Guest can handle UFO in. */
67#define VIRTIO_NET_HOST_TSO4 0x00000800 /* Host can handle TSOv4 in. */
68#define VIRTIO_NET_HOST_TSO6 0x00001000 /* Host can handle TSOv6 in. */
69#define VIRTIO_NET_HOST_ECN 0x00002000 /* Host can handle TSO[6] w/ ECN in. */
70#define VIRTIO_NET_HOST_UFO 0x00004000 /* Host can handle UFO in. */
71#define VIRTIO_NET_MRG_RXBUF 0x00008000 /* Host can merge receive buffers. */
72#define VIRTIO_NET_STATUS 0x00010000 /* virtio_net_config.status available */
73#define VIRTIO_NET_CTRL_VQ 0x00020000 /* Control channel available */
74#define VIRTIO_NET_CTRL_RX 0x00040000 /* Control channel RX mode support */
75#define VIRTIO_NET_CTRL_VLAN 0x00080000 /* Control channel VLAN filtering */
76
77#if defined(DEBUG_ramshankar)
78# undef LogFlowFunc
79# define LogFlowFunc LogRel
80# undef Log
81# define Log LogRel
82# undef LogFlow
83# define LogFlow LogRel
84#endif
85
86/*******************************************************************************
87* Internal Functions *
88*******************************************************************************/
89static void *VirtioNetDevAlloc(PVIRTIODEVICE pDevice);
90static void VirtioNetDevFree(PVIRTIODEVICE pDevice);
91static int VirtioNetDevAttach(PVIRTIODEVICE pDevice);
92static int VirtioNetDevDetach(PVIRTIODEVICE pDevice);
93
94static int VirtioNetAttach(dev_info_t *pDip, ddi_attach_cmd_t Cmd);
95static int VirtioNetDetach(dev_info_t *pDip, ddi_detach_cmd_t Cmd);
96
97static int VirtioNetStat(void *pvArg, uint_t cmdStat, uint64_t *pu64Val);
98static int VirtioNetStart(void *pvArg);
99static void VirtioNetStop(void *pvArg);
100static int VirtioNetSetPromisc(void *pvArg, boolean_t fPromiscOn);
101static int VirtioNetSetMulticast(void *pvArg, boolean_t fAdd, const uint8_t *pbMac);
102static int VirtioNetSetUnicast(void *pvArg, const uint8_t *pbMac);
103static boolean_t VirtioNetGetCapab(void *pvArg, mac_capab_t Capab, void *pvCapabData);
104static mblk_t *VirtioNetXmit(void *pvArg, mblk_t *pMsg);
105static uint_t VirtioNetISR(caddr_t addrArg);
106
107static int VirtioNetAttachQueues(PVIRTIODEVICE pDevice);
108static void VirtioNetDetachQueues(PVIRTIODEVICE pDevice);
109
110
111/*******************************************************************************
112* Structures and Typedefs *
113*******************************************************************************/
114/**
115 * Device operations for Virtio Net.
116 */
117VIRTIODEVICEOPS g_VirtioDeviceOpsNet =
118{
119 VirtioNetDevAlloc,
120 VirtioNetDevFree,
121 VirtioNetDevAttach,
122 VirtioNetDevDetach
123};
124
125/**
126 * virtio_net_t: Private data per Virtio Device.
127 */
128typedef struct virtio_net_t
129{
130 mac_handle_t hMac; /* Handle to the MAC layer. */
131 RTMAC MacAddr; /* MAC address. */
132 PVIRTIOQUEUE pRxQueue; /* Receive Queue. */
133 PVIRTIOQUEUE pTxQueue; /* Xmit Queue. */
134 PVIRTIOQUEUE pCtrlQueue; /* Control Queue. */
135 kmem_cache_t *pTxCache; /* TX buffer cache. */
136} virtio_net_t;
137
138/**
139 * virtio_txbuf_t: Virtio Net TX buffer.
140 */
141typedef struct virtio_net_txbuf_t
142{
143 ddi_dma_handle_t hDMA; /* DMA TX handle. */
144} virtio_net_txbuf_t;
145
146/*
147 * virtio_net_header_t: Virtio Net TX/RX buffer header.
148 */
149typedef struct virtio_net_header_t
150{
151 uint8_t u8Flags; /* Flags. */
152 uint8_t u8GSOType; /* GSO type. */
153 uint16_t u16HdrLen; /* Length of this header. */
154 uint16_t u16GSOSize; /* GSO length if applicable. */
155 uint16_t u16CSumStart; /* Checksum start.*/
156 uint16_t u16CSumOffset; /* Checksum offset.*/
157} virtio_net_header_t;
158
159/**
160 * MAC layer hooks for VirtioNet.
161 */
162static mac_callbacks_t g_VirtioNetCallbacks =
163{
164 MC_GETCAPAB, /* Mask of available extra hooks. */
165 VirtioNetStat,
166 VirtioNetStart,
167 VirtioNetStop,
168 VirtioNetSetPromisc,
169 VirtioNetSetMulticast,
170 VirtioNetSetUnicast,
171 VirtioNetXmit,
172 NULL, /* Reserved. */
173 NULL, /* IOCtl. */
174 VirtioNetGetCapab,
175};
176
177/**
178 * DMA transfer attributes for Xmit/Recv. buffers.
179 */
180static ddi_dma_attr_t g_VirtioNetBufDmaAttr =
181{
182 DMA_ATTR_V0, /* Version. */
183 0, /* Lowest usable address. */
184 0xffffffffffffffffULL, /* Highest usable address. */
185 0x7fffffff, /* Maximum DMAable byte count. */
186 MMU_PAGESIZE, /* Alignment in bytes. */
187 0x7ff, /* Bitmap of burst sizes */
188 1, /* Minimum transfer. */
189 0xffffffffU, /* Maximum transfer. */
190 0xffffffffffffffffULL, /* Maximum segment length. */
191 1, /* Maximum number of segments. */
192 1, /* Granularity. */
193 0 /* Flags (reserved). */
194};
195
196/**
197 * cb_ops: driver char/block entry points
198 */
199static struct cb_ops g_VirtioNetCbOps =
200{
201 nulldev, /* cb open */
202 nulldev, /* cb close */
203 nodev, /* b strategy */
204 nodev, /* b dump */
205 nodev, /* b print */
206 nodev, /* cb read */
207 nodev, /* cb write */
208 nodev, /* cb ioctl */
209 nodev, /* c devmap */
210 nodev, /* c mmap */
211 nodev, /* c segmap */
212 nochpoll, /* c poll */
213 ddi_prop_op, /* property ops */
214 NULL, /* streamtab */
215 D_MP, /* compat. flag */
216 CB_REV /* revision */
217};
218
219/**
220 * dev_ops: driver entry/exit and other ops.
221 */
222static struct dev_ops g_VirtioNetDevOps =
223{
224 DEVO_REV, /* driver build revision */
225 0, /* ref count */
226 NULL, /* get info */
227 nulldev, /* identify */
228 nulldev, /* probe */
229 VirtioNetAttach,
230 VirtioNetDetach,
231 nodev, /* reset */
232 &g_VirtioNetCbOps,
233 (struct bus_ops *)0,
234 nodev /* power */
235};
236
237/**
238 * modldrv: export driver specifics to kernel
239 */
240static struct modldrv g_VirtioNetDriver =
241{
242 &mod_driverops, /* extern from kernel */
243 DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
244 &g_VirtioNetDevOps
245};
246
247/**
248 * modlinkage: export install/remove/info to the kernel
249 */
250static struct modlinkage g_VirtioNetModLinkage =
251{
252 MODREV_1, /* loadable module system revision */
253 {
254 &g_VirtioNetDriver, /* driver framework */
255 NULL /* terminate array of linkage structures */
256 }
257};
258
259
260/**
261 * Kernel entry points
262 */
263int _init(void)
264{
265 LogFlowFunc((VIRTIOLOGNAME ":_init\n"));
266
267 /*
268 * Prevent module autounloading.
269 */
270 modctl_t *pModCtl = mod_getctl(&g_VirtioNetModLinkage);
271 if (pModCtl)
272 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
273 else
274 LogRel((VIRTIOLOGNAME ":failed to disable autounloading!\n"));
275
276 /*
277 * Initialize IPRT.
278 */
279 int rc = RTR0Init(0);
280 if (RT_SUCCESS(rc))
281 {
282 /*
283 * Initialize Solaris specific globals here.
284 */
285 mac_init_ops(&g_VirtioNetDevOps, DEVICE_NAME);
286 rc = mod_install(&g_VirtioNetModLinkage);
287 if (!rc)
288 return rc;
289
290 LogRel((VIRTIOLOGNAME ":mod_install failed. rc=%d\n", rc));
291 mac_fini_ops(&g_VirtioNetDevOps);
292 RTR0Term();
293 return rc;
294 }
295 else
296 LogRel((VIRTIOLOGNAME ":failed to initialize IPRT (rc=%d)\n", rc));
297
298 return RTErrConvertToErrno(rc);
299}
300
301
302int _fini(void)
303{
304 int rc;
305 LogFlowFunc((VIRTIOLOGNAME ":_fini\n"));
306
307 rc = mod_remove(&g_VirtioNetModLinkage);
308 if (!rc)
309 {
310 mac_fini_ops(&g_VirtioNetDevOps);
311 RTR0Term();
312 }
313 return rc;
314}
315
316
317int _info(struct modinfo *pModInfo)
318{
319 LogFlowFunc((VIRTIOLOGNAME ":_info\n"));
320
321 int rc = mod_info(&g_VirtioNetModLinkage, pModInfo);
322
323 LogFlow((VIRTIOLOGNAME ":_info returns %d\n", rc));
324 return rc;
325}
326
327
328/**
329 * Attach entry point, to attach a device to the system or resume it.
330 *
331 * @param pDip The module structure instance.
332 * @param enmCmd Operation type (attach/resume).
333 *
334 * @return corresponding solaris error code.
335 */
336static int VirtioNetAttach(dev_info_t *pDip, ddi_attach_cmd_t Cmd)
337{
338 return VirtioAttach(pDip, Cmd, &g_VirtioDeviceOpsNet, &g_VirtioHyperOpsPci);
339}
340
341
342/**
343 * Detach entry point, to detach a device to the system or suspend it.
344 *
345 * @param pDip The module structure instance.
346 * @param enmCmd Operation type (detach/suspend).
347 *
348 * @return corresponding solaris error code.
349 */
350static int VirtioNetDetach(dev_info_t *pDip, ddi_detach_cmd_t Cmd)
351{
352 return VirtioDetach(pDip, Cmd);
353}
354
355
356/**
357 * Virtio Net TX buffer constructor for kmem_cache_create().
358 *
359 * @param pvBuf Pointer to the allocated buffer.
360 * @param pvArg Opaque private data.
361 * @param fFlags Propagated KM flag values.
362 *
363 * @return 0 on success, or -1 on failure.
364 */
365static int VirtioNetTxBufCreate(void *pvBuf, void *pvArg, int fFlags)
366{
367 virtio_net_txbuf_t *pTxBuf = pvBuf;
368 PVIRTIODEVICE pDevice = pvArg;
369
370 /* @todo ncookies handles? */
371 int rc = ddi_dma_alloc_handle(pDevice->pDip, &g_VirtioNetBufDmaAttr,
372 fFlags & KM_NOSLEEP ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP,
373 0 /* Arg */, &pTxBuf->hDMA);
374 if (rc == DDI_SUCCESS)
375 return 0;
376 return -1;
377}
378
379
380/**
381 * Virtio Net TX buffer destructor for kmem_cache_create().
382 *
383 * @param pvBuf Pointer to the allocated buffer.
384 * @param pvArg
385 */
386static void VirtioNetTxBufDestroy(void *pvBuf, void *pvArg)
387{
388 NOREF(pvArg);
389 virtio_net_txbuf_t *pTxBuf = pvBuf;
390
391 ddi_dma_free_handle(&pTxBuf->hDMA);
392}
393
394
395/**
396 * Virtio Net private data allocation routine.
397 *
398 * @param pDevice Pointer to the Virtio device instance.
399 *
400 * @return Allocated private data that must only be freed by calling
401 * VirtioNetDevFree().
402 */
403static void *VirtioNetDevAlloc(PVIRTIODEVICE pDevice)
404{
405 LogFlowFunc((VIRTIOLOGNAME ":VirtioNetDevAlloc pDevice=%p\n", pDevice));
406
407 AssertReturn(pDevice, NULL);
408 virtio_net_t *pNet = RTMemAllocZ(sizeof(virtio_net_t));
409 if (RT_LIKELY(pNet))
410 {
411 /*
412 * Create a kernel memory cache for frequently allocated/deallocated
413 * buffers.
414 */
415 char szCachename[KSTAT_STRLEN];
416 RTStrPrintf(szCachename, sizeof(szCachename), "VirtioNet_Cache_%d", ddi_get_instance(pDevice->pDip));
417 pNet->pTxCache = kmem_cache_create(szCachename, /* Cache name */
418 sizeof(virtio_net_txbuf_t), /* Size of buffers in cache */
419 0, /* Align */
420 VirtioNetTxBufCreate, /* Buffer constructor */
421 VirtioNetTxBufDestroy, /* Buffer destructor */
422 NULL, /* pfnReclaim */
423 pDevice, /* Private data */
424 NULL, /* "vmp", MBZ (man page) */
425 0 /* "cflags", MBZ (man page) */
426 );
427 if (RT_LIKELY(pNet->pTxCache))
428 return pNet;
429 else
430 LogRel((VIRTIOLOGNAME ":kmem_cache_create failed.\n"));
431 }
432 else
433 LogRel((VIRTIOLOGNAME ":failed to alloc %u bytes for Net instance.\n", sizeof(virtio_net_t)));
434
435 return NULL;
436}
437
438
439/**
440 * Virtio Net private data free routine.
441 *
442 * @param pDevice Pointer to the Virtio device instance.
443 */
444static void VirtioNetDevFree(PVIRTIODEVICE pDevice)
445{
446 LogFlowFunc((VIRTIOLOGNAME ":VirtioNetDevFree pDevice=%p\n", pDevice));
447 AssertReturnVoid(pDevice);
448
449 virtio_net_t *pNet = pDevice->pvDevice;
450 kmem_cache_destroy(pNet->pTxCache);
451 RTMemFree(pNet);
452 pDevice->pvDevice = NULL;
453}
454
455
456/**
457 * Virtio Net device attach rountine.
458 *
459 * @param pDevice Pointer to the Virtio device instance.
460 *
461 * @return corresponding solaris error code.
462 */
463static int VirtioNetDevAttach(PVIRTIODEVICE pDevice)
464{
465 LogFlowFunc((VIRTIOLOGNAME ":VirtioNetDevAttach pDevice=%p\n", pDevice));
466
467 virtio_net_t *pNet = pDevice->pvDevice;
468 mac_register_t *pMacRegHandle = mac_alloc(MAC_VERSION);
469 if (pMacRegHandle)
470 {
471 pMacRegHandle->m_driver = pDevice;
472 pMacRegHandle->m_dip = pDevice->pDip;
473 pMacRegHandle->m_callbacks = &g_VirtioNetCallbacks;
474 pMacRegHandle->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
475 pMacRegHandle->m_min_sdu = 0;
476 pMacRegHandle->m_max_sdu = 1500; /* @todo verify */
477 /* @todo should we set the margin size? */
478 pMacRegHandle->m_src_addr = pNet->MacAddr.au8;
479
480 /*
481 * Get MAC from the host or generate a random MAC address.
482 */
483 if (pDevice->fHostFeatures & VIRTIO_NET_MAC)
484 {
485 pDevice->pHyperOps->pfnGet(pDevice, 0 /* offset */, &pNet->MacAddr.au8, sizeof(pNet->MacAddr));
486 LogFlow((VIRTIOLOGNAME ":VirtioNetDevAttach: Obtained MAC address from host: %.6Rhxs\n", pNet->MacAddr.au8));
487 }
488 else
489 {
490 pNet->MacAddr.au8[0] = 0x08;
491 pNet->MacAddr.au8[1] = 0x00;
492 pNet->MacAddr.au8[2] = 0x27;
493 RTRandBytes(&pNet->MacAddr.au8[3], 3);
494 LogFlow((VIRTIOLOGNAME ":VirtioNetDevAttach: Generated MAC address %.6Rhxs\n", pNet->MacAddr.au8));
495 }
496
497 int rc = VirtioNetAttachQueues(pDevice);
498 if (rc == DDI_SUCCESS)
499 {
500 rc = mac_register(pMacRegHandle, &pNet->hMac);
501 if (rc == 0)
502 {
503 mac_link_update(pNet->hMac, LINK_STATE_DOWN);
504 mac_free(pMacRegHandle);
505 LogFlow((VIRTIOLOGNAME ":VirtioNetDevAttach: successfully registered mac.\n"));
506 return DDI_SUCCESS;
507 }
508 else
509 LogRel((VIRTIOLOGNAME ":VirtioNetDevAttach: mac_register failed. rc=%d\n", rc));
510
511 VirtioNetDetachQueues(pDevice);
512 }
513 else
514 LogRel((VIRTIOLOGNAME ":VirtioNetDevAttach: VirtioNetAttachQueues failed. rc=%d\n", rc));
515
516 mac_free(pMacRegHandle);
517 }
518 else
519 LogRel((VIRTIOLOGNAME ":VirtioNetDevAttach: mac_alloc failed. Invalid version!?!\n"));
520
521 return DDI_FAILURE;
522}
523
524
525/**
526 * Virtio Net device detach routine.
527 *
528 * @param pDevice Pointer to the Virtio device instance.
529 *
530 * @return corresponding solaris error code.
531 */
532static int VirtioNetDevDetach(PVIRTIODEVICE pDevice)
533{
534 LogFlowFunc((VIRTIOLOGNAME ":VirtioNetDevDetach pDevice=%p\n", pDevice));
535 virtio_net_t *pNet = pDevice->pvDevice;
536
537 int rc = mac_unregister(pNet->hMac);
538 if (rc == 0)
539 {
540 VirtioNetDetachQueues(pDevice);
541 return DDI_SUCCESS;
542 }
543 else
544 LogRel((VIRTIOLOGNAME ":VirtioNetDevDetach: mac_unregister failed. rc=%d\n", rc));
545
546 return DDI_FAILURE;
547}
548
549
550/**
551 * Attach the Virtio Net TX, RX and control queues.
552 *
553 * @param pDevice Pointer to the Virtio device instance.
554 *
555 * @return corresponding solaris error code.
556 */
557static int VirtioNetAttachQueues(PVIRTIODEVICE pDevice)
558{
559 LogFlowFunc((VIRTIOLOGNAME ":VirtioNetAttachQueues pDevice=%p\n", pDevice));
560
561 virtio_net_t *pNet = pDevice->pvDevice;
562
563 pNet->pRxQueue = VirtioGetQueue(pDevice, 0 /* index */ );
564 if (pNet->pRxQueue)
565 {
566 pNet->pTxQueue = VirtioGetQueue(pDevice, 1 /* index */);
567 if (pNet->pTxQueue)
568 {
569 if (pDevice->fHostFeatures & VIRTIO_NET_CTRL_VQ)
570 {
571 pNet->pCtrlQueue = VirtioGetQueue(pDevice, 2 /* index */);
572 if (pNet->pCtrlQueue)
573 {
574 LogFlow((VIRTIOLOGNAME ":VirtioNetAttachQueues successfully obtained 3 queues.\n"));
575 return DDI_SUCCESS;
576 }
577 else
578 LogRel((VIRTIOLOGNAME ":VirtioNetAttachQueues: failed to get Control queue.\n"));
579 }
580 else
581 {
582 LogFlow((VIRTIOLOGNAME ":VirtioNetAttachQueues successfully obtained 2 queues.\n"));
583 return DDI_SUCCESS;
584 }
585
586 VirtioPutQueue(pDevice, pNet->pTxQueue);
587 pNet->pTxQueue = NULL;
588 }
589 else
590 LogRel((VIRTIOLOGNAME ":VirtioNetAttachQueues: failed to get TX queue.\n"));
591
592 VirtioPutQueue(pDevice, pNet->pRxQueue);
593 pNet->pRxQueue = NULL;
594 }
595 else
596 LogRel((VIRTIOLOGNAME ":VirtioNetAttachQueues: failed to get RX queue.\n"));
597
598 return DDI_FAILURE;
599}
600
601
602/**
603 * Detach the Virtio Net TX, RX and control queues.
604 *
605 * @param pDevice Pointer to the Virtio device instance.
606 */
607static void VirtioNetDetachQueues(PVIRTIODEVICE pDevice)
608{
609 LogFlowFunc((VIRTIOLOGNAME ":VirtioNetDetachQueues pDevice=%p\n", pDevice));
610 virtio_net_t *pNet = pDevice->pvDevice;
611
612 if ( pDevice->fHostFeatures & VIRTIO_NET_CTRL_VQ
613 && pNet->pCtrlQueue)
614 VirtioPutQueue(pDevice, pNet->pCtrlQueue);
615
616 if (pNet->pTxCache)
617 VirtioPutQueue(pDevice, pNet->pTxQueue);
618
619 if (pNet->pRxQueue)
620 VirtioPutQueue(pDevice, pNet->pRxQueue);
621}
622
623
624
625/* -=-=-=-=- Virtio Net MAC layer callbacks -=-=-=-=- */
626
627/**
628 * Virtio Net statistics.
629 *
630 * @param pvArg Pointer to private data.
631 * @param cmdStat Which statistics to provide.
632 * @param pu64Val Where to write statistics data.
633 *
634 * @return corresponding solaris error code.
635 */
636static int VirtioNetStat(void *pvArg, uint_t cmdStat, uint64_t *pu64Val)
637{
638 NOREF(pvArg);
639 NOREF(cmdStat);
640 NOREF(pu64Val);
641 return ENOTSUP;
642}
643
644
645/**
646 * Virtio Net Start.
647 *
648 * @param pvArg Pointer to private data.
649 *
650 * @return corresponding solaris error code.
651 */
652static int VirtioNetStart(void *pvArg)
653{
654 PVIRTIODEVICE pDevice = pvArg;
655 virtio_net_t *pNet = pDevice->pvDevice;
656 mac_link_update(pNet->hMac, LINK_STATE_UP);
657
658 pDevice->pHyperOps->pfnSetStatus(pDevice, VIRTIO_PCI_STATUS_DRV_OK);
659 return 0;
660}
661
662
663/**
664 * Virtio Net Stop.
665 *
666 * @param pvArg Pointer to private data.
667 */
668static void VirtioNetStop(void *pvArg)
669{
670 PVIRTIODEVICE pDevice = pvArg;
671 virtio_net_t *pNet = pDevice->pvDevice;
672 mac_link_update(pNet->hMac, LINK_STATE_DOWN);
673
674 /*
675 * I don't think we should set status here as the host checks the status on every Xmit. This means pending Xmits
676 * would also be dropped.
677 * @todo: Not sure what's the best way to signal connect/disconnect of the link to the host. Figure it out.
678 */
679}
680
681
682/**
683 * Virtio Net toggle Promiscuous mode.
684 *
685 * @param pvArg Pointer to private data.
686 * @param fPromiscOn Promiscuous On/Off.
687 *
688 * @return corresponding solaris error code.
689 */
690static int VirtioNetSetPromisc(void *pvArg, boolean_t fPromiscOn)
691{
692 NOREF(pvArg);
693 NOREF(fPromiscOn);
694 return 0;
695}
696
697
698/**
699 * Virtio Net set/add multicast address.
700 *
701 * @param pvArg Pointer to private data.
702 * @param fAdd Whether to add multicast address or not.
703 * @param pbMac Pointer to the multicast MAC address to set/add.
704 *
705 * @return corresponding solaris error code.
706 */
707static int VirtioNetSetMulticast(void *pvArg, boolean_t fAdd, const uint8_t *pbMac)
708{
709 NOREF(pvArg);
710 NOREF(fAdd);
711 NOREF(pbMac);
712 return 1;
713}
714
715
716/**
717 * Virtio Net set unicast address.
718 *
719 * @param pvArg Pointer to private data.
720 * @param pbMac Pointer to the unicast MAC address to set.
721 *
722 * @return corresponding solaris error code.
723 */
724static int VirtioNetSetUnicast(void *pvArg, const uint8_t *pbMac)
725{
726 NOREF(pvArg);
727 NOREF(pbMac);
728 return ENOTSUP;
729}
730
731
732/**
733 * Virtio Net get capabilities hook.
734 *
735 * @param pvArg Pointer to private data.
736 * @param Capab MAC layer capabilities.
737 * @param pvCapabData Pointer to store capability info.
738 *
739 * @return B_TRUE upon success, otherwise B_FALSE.
740 */
741static boolean_t VirtioNetGetCapab(void *pvArg, mac_capab_t Capab, void *pvCapabData)
742{
743 NOREF(pvArg);
744 NOREF(Capab);
745 NOREF(pvCapabData);
746 return B_FALSE;
747}
748
749
750/**
751 * Virtio Net Xmit hook.
752 *
753 * @param pvArg Pointer to private data.
754 * @param pMsg Pointer to the message.
755 *
756 * @return Pointer to message not Xmited.
757 */
758static mblk_t *VirtioNetXmit(void *pvArg, mblk_t *pMsg)
759{
760 LogFlowFunc((VIRTIOLOGNAME ":VirtioNetXmit pMsg=%p\n", pMsg));
761 cmn_err(CE_NOTE, "Xmit pMsg=%p\n", pMsg);
762
763 PVIRTIODEVICE pDevice = pvArg;
764 virtio_net_t *pNet = pDevice->pvDevice;
765 bool fNotify = false;
766
767 while (pMsg)
768 {
769 mblk_t *pNextMsg = pMsg->b_next;
770
771#if 0
772 mblk_t *pHdr = allocb(sizeof(virtio_net_header_t), BPRI_HI);
773 if (RT_UNLIKELY(!pHdr))
774 break;
775
776 virtio_net_header_t *pNetHdr = pHdr->b_rptr;
777 memset(pNetHdr, 0, sizeof(virtio_net_header_t));
778 pNetHdr->u8Flags = VIRTIO_NET_GUEST_CSUM;
779 pNetHdr->u16HdrLen = sizeof(virtio_net_header_t);
780
781 pHdr->b_wptr += sizeof(virtio_net_header_t);
782 pHdr->b_cont = pMsg;
783#endif
784
785 virtio_net_txbuf_t *pTxBuf = kmem_cache_alloc(pNet->pTxCache, KM_SLEEP);
786 if (!pTxBuf)
787 break;
788
789 ddi_dma_cookie_t DmaCookie;
790 uint_t cCookies;
791 int rc = ddi_dma_addr_bind_handle(pTxBuf->hDMA, NULL /* addrspace */, (char *)pMsg->b_rptr, MBLKL(pMsg),
792 DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0 /* addr */,
793 &DmaCookie, &cCookies);
794 cmn_err(CE_NOTE, "VirtioNetXmit: MBLKL pMsg=%u\n", MBLKL(pMsg));
795 if (rc != DDI_DMA_MAPPED)
796 {
797 LogRel((VIRTIOLOGNAME ":VirtioNetXmit failed to map address to DMA handle. rc=%d\n", rc));
798 kmem_cache_free(pNet->pTxCache, pTxBuf);
799 break;
800 }
801
802 /** @todo get 'cCookies' slots from the ring. */
803
804 for (uint_t i = 0; i < cCookies; i++)
805 {
806 uint16_t fFlags = 0;
807 if (i < cCookies - 1)
808 fFlags |= VIRTIO_FLAGS_RING_DESC_NEXT;
809
810 rc = VirtioRingPush(pNet->pTxQueue, DmaCookie.dmac_laddress, DmaCookie.dmac_size, fFlags);
811 if (RT_FAILURE(rc))
812 {
813 LogRel((VIRTIOLOGNAME ":VirtioNetXmit failed. rc=%Rrc\n", rc));
814 break;
815 }
816
817 ddi_dma_nextcookie(pTxBuf->hDMA, &DmaCookie);
818 }
819
820 pMsg = pNextMsg;
821 fNotify = true;
822 if (RT_FAILURE(rc))
823 {
824 ddi_dma_unbind_handle(pTxBuf->hDMA);
825 break;
826 }
827 }
828
829 if (fNotify)
830 pDevice->pHyperOps->pfnNotifyQueue(pDevice, pNet->pTxQueue);
831
832 return pMsg;
833}
834
835
836/**
837 * Interrupt Service Routine for Virtio Net.
838 *
839 * @param Arg Private data (unused, will be NULL).
840 * @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
841 */
842static uint_t VirtioNetISR(caddr_t Arg)
843{
844 cmn_err(CE_NOTE, "VirtioNetISR Arg=%p\n", Arg);
845 NOREF(Arg);
846 return DDI_INTR_UNCLAIMED;
847}
848
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette