VirtualBox

source: vbox/trunk/src/VBox/Additions/solaris/Virtio/VirtioPci-solaris.c@ 47550

Last change on this file since 47550 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.9 KB
Line 
1/* $Id: VirtioPci-solaris.c 44529 2013-02-04 15:54:15Z vboxsync $ */
2/** @file
3 * VirtualBox Guest Additions - Virtio Driver for Solaris, PCI Hypervisor Interface.
4 */
5
6/*
7 * Copyright (C) 2010-2011 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#ifdef DEBUG_ramshankar
31# define LOG_INSTANCE RTLogRelDefaultInstance()
32#endif
33#include "VirtioPci-solaris.h"
34
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/mem.h>
38#include <iprt/param.h>
39#include <VBox/log.h>
40
41#include <sys/pci.h>
42#include <sys/param.h>
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47/*
48 * Pci Register offsets.
49 */
50#define VIRTIO_PCI_HOST_FEATURES 0x00
51#define VIRTIO_PCI_GUEST_FEATURES 0x04
52#define VIRTIO_PCI_QUEUE_PFN 0x08
53#define VIRTIO_PCI_QUEUE_NUM 0x0C
54#define VIRTIO_PCI_QUEUE_SEL 0x0E
55#define VIRTIO_PCI_QUEUE_NOTIFY 0x10
56#define VIRTIO_PCI_STATUS 0x12
57#define VIRTIO_PCI_ISR 0x13
58#define VIRTIO_PCI_CONFIG 0x14
59
60#define VIRTIO_PCI_RING_ALIGN PAGE_SIZE
61#define VIRTIO_PCI_QUEUE_ADDR_SHIFT PAGE_SHIFT
62
63/**
64 * virtio_pci_t: Private data per device instance.
65 */
66typedef struct virtio_pci_t
67{
68 ddi_acc_handle_t hIO; /* IO handle */
69 caddr_t addrIOBase; /* IO base address */
70} virtio_pci_t;
71
72/**
73 * virtio_pci_queue_t: Private data per queue instance.
74 */
75typedef struct virtio_pci_queue_t
76{
77 ddi_dma_handle_t hDMA; /* DMA handle. */
78 ddi_acc_handle_t hIO; /* IO handle. */
79 size_t cbBuf; /* Physical address of buffer. */
80 paddr_t physBuf; /* Size of buffer. */
81 pfn_t pageBuf; /* Page frame number of buffer. */
82} virtio_pci_queue_t;
83
84static ddi_device_acc_attr_t g_VirtioPciAccAttrRegs =
85{
86 DDI_DEVICE_ATTR_V0, /* Version */
87 DDI_STRUCTURE_LE_ACC, /* Structural data access in little endian. */
88 DDI_STRICTORDER_ACC, /* Strict ordering. */
89 DDI_DEFAULT_ACC /* Default access, possible panic on errors*/
90};
91
92static ddi_device_acc_attr_t g_VirtioPciAccAttrRing =
93{
94 DDI_DEVICE_ATTR_V0, /* Version. */
95 DDI_NEVERSWAP_ACC, /* Data access with no byte swapping*/
96 DDI_STRICTORDER_ACC, /* Strict ordering. */
97 DDI_DEFAULT_ACC /* Default access, possible panic on errors*/
98};
99
100static ddi_dma_attr_t g_VirtioPciDmaAttrRing =
101{
102 DMA_ATTR_V0, /* Version. */
103 0, /* Lowest usable address. */
104 0xffffffffffffffffULL, /* Highest usable address. */
105 0x7fffffff, /* Maximum DMAable byte count. */
106 VIRTIO_PCI_RING_ALIGN, /* Alignment in bytes. */
107 0x7ff, /* Bitmap of burst sizes */
108 1, /* Minimum transfer. */
109 0xffffffffU, /* Maximum transfer. */
110 0xffffffffffffffffULL, /* Maximum segment length. */
111 1, /* Maximum number of segments. */
112 1, /* Granularity. */
113 0 /* Flags (reserved). */
114};
115
116/** Pointer to the interrupt handle vector */
117static ddi_intr_handle_t *g_pIntr;
118/** Number of actually allocated interrupt handles */
119static size_t g_cIntrAllocated;
120/** The IRQ Mutex */
121static kmutex_t g_IrqMtx;
122
123
124/*******************************************************************************
125* Internal Functions *
126*******************************************************************************/
127static void *VirtioPciAlloc(PVIRTIODEVICE pDevice);
128static void VirtioPciFree(PVIRTIODEVICE pDevice);
129static int VirtioPciAttach(PVIRTIODEVICE pDevice);
130static int VirtioPciDetach(PVIRTIODEVICE pDevice);
131static uint32_t VirtioPciGetFeatures(PVIRTIODEVICE pDevice);
132static void VirtioPciSetFeatures(PVIRTIODEVICE pDevice, uint32_t fFeatures);
133static int VirtioPciNotifyQueue(PVIRTIODEVICE pDevice, PVIRTIOQUEUE pQueue);
134static void VirtioPciGet(PVIRTIODEVICE pDevice, off_t off, void *pv, size_t cb);
135static void VirtioPciSet(PVIRTIODEVICE pDevice, off_t off, void *pv, size_t cb);
136static void *VirtioPciGetQueue(PVIRTIODEVICE pDevice, PVIRTIOQUEUE pQueue);
137static void VirtioPciPutQueue(PVIRTIODEVICE pDevice, PVIRTIOQUEUE pQueue);
138static void VirtioPciSetStatus(PVIRTIODEVICE pDevice, uint8_t Status);
139
140static uint_t VirtioPciISR(caddr_t Arg);
141static int VirtioPciSetupIRQ(dev_info_t *pDip);
142static void VirtioPciRemoveIRQ(dev_info_t *pDip);
143
144/**
145 * Hypervisor operations for Virtio Pci.
146 */
147VIRTIOHYPEROPS g_VirtioHyperOpsPci =
148{
149 VirtioPciAlloc,
150 VirtioPciFree,
151 VirtioPciAttach,
152 VirtioPciDetach,
153 VirtioPciGetFeatures,
154 VirtioPciSetFeatures,
155 VirtioPciNotifyQueue,
156 VirtioPciGet,
157 VirtioPciSet,
158 VirtioPciGetQueue,
159 VirtioPciPutQueue,
160 VirtioPciSetStatus
161};
162
163
164/**
165 * Virtio Pci private data allocation routine.
166 *
167 * @param pDevice Pointer to the Virtio device instance.
168 * @return Allocated private data structure which must only be freed by calling
169 * VirtioPciFree().
170 */
171static void *VirtioPciAlloc(PVIRTIODEVICE pDevice)
172{
173 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciAlloc pDevice=%p\n", pDevice));
174 virtio_pci_t *pPciData = RTMemAllocZ(sizeof(virtio_pci_t));
175 return pPciData;
176}
177
178
179/**
180 * Virtio Pci private data deallocation routine.
181 *
182 * @param pDevice Pointer to the Virtio device instance.
183 */
184static void VirtioPciFree(PVIRTIODEVICE pDevice)
185{
186 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciFree pDevice=%p\n", pDevice));
187 virtio_pci_t *pPciData = pDevice->pvHyper;
188 if (pPciData)
189 {
190 RTMemFree(pDevice->pvHyper);
191 pDevice->pvHyper = NULL;
192 }
193}
194
195
196/**
197 * Virtio Pci attach routine, called from driver attach.
198 *
199 * @param pDevice Pointer to the Virtio device instance.
200 *
201 * @return Solaris DDI error code. DDI_SUCCESS or DDI_FAILURE.
202 */
203static int VirtioPciAttach(PVIRTIODEVICE pDevice)
204{
205 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciAttach pDevice=%p\n", pDevice));
206 virtio_pci_t *pPciData = pDevice->pvHyper;
207 AssertReturn(pPciData, DDI_FAILURE);
208
209 int rc = ddi_regs_map_setup(pDevice->pDip,
210 1, /* reg. num */
211 &pPciData->addrIOBase,
212 0, /* offset */
213 0, /* length */
214 &g_VirtioPciAccAttrRegs,
215 &pPciData->hIO);
216 if (rc == DDI_SUCCESS)
217 {
218 /*
219 * Reset the device.
220 */
221 VirtioPciSetStatus(pDevice, 0);
222
223 /*
224 * Add interrupt handler.
225 */
226 VirtioPciSetupIRQ(pDevice->pDip);
227
228 LogFlow((VIRTIOLOGNAME ":VirtioPciAttach: successfully mapped registers.\n"));
229 return DDI_SUCCESS;
230 }
231 else
232 LogRel((VIRTIOLOGNAME ":VirtioPciAttach: ddi_regs_map_setup failed. rc=%d\n", rc));
233 return DDI_FAILURE;
234}
235
236
237/**
238 * Virtio Pci detach routine, called from driver detach.
239 *
240 * @param pDevice Pointer to the Virtio device instance.
241 *
242 * @return Solaris DDI error code. DDI_SUCCESS or DDI_FAILURE.
243 */
244static int VirtioPciDetach(PVIRTIODEVICE pDevice)
245{
246 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciDetach pDevice=%p\n", pDevice));
247 virtio_pci_t *pPciData = pDevice->pvHyper;
248 AssertReturn(pPciData, DDI_FAILURE);
249
250 VirtioPciRemoveIRQ(pDevice->pDip);
251 ddi_regs_map_free(&pPciData->hIO);
252 return DDI_SUCCESS;
253}
254
255
256/**
257 * Get host supported features.
258 *
259 * @param pDevice Pointer to the Virtio device instance.
260 *
261 * @return Mask of host features.
262 */
263static uint32_t VirtioPciGetFeatures(PVIRTIODEVICE pDevice)
264{
265 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciGetFeatures pDevice=%p\n", pDevice));
266 virtio_pci_t *pPciData = pDevice->pvHyper;
267 AssertReturn(pPciData, 0);
268
269 return ddi_get32(pPciData->hIO, (uint32_t *)(pPciData->addrIOBase + VIRTIO_PCI_HOST_FEATURES));
270}
271
272
273/**
274 * Set guest supported features.
275 *
276 * @param pDevice Pointer to the Virtio device instance.
277 * @param u32Features Mask of guest supported features.
278 */
279static void VirtioPciSetFeatures(PVIRTIODEVICE pDevice, uint32_t u32Features)
280{
281 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciSetFeatures pDevice=%p\n", pDevice));
282 virtio_pci_t *pPciData = pDevice->pvHyper;
283 AssertReturnVoid(pPciData);
284
285 ddi_put32(pPciData->hIO, (uint32_t *)(pPciData->addrIOBase + VIRTIO_PCI_GUEST_FEATURES), u32Features);
286}
287
288
289/**
290 * Update the queue, notify the host.
291 *
292 * @param pDevice Pointer to the Virtio device instance.
293 * @param pQueue Pointer to the Queue that is doing the notification.
294 *
295 * @return Solaris DDI error code. DDI_SUCCESS or DDI_FAILURE.
296 */
297static int VirtioPciNotifyQueue(PVIRTIODEVICE pDevice, PVIRTIOQUEUE pQueue)
298{
299 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciNotifyQueue pDevice=%p pQueue=%p\n", pDevice, pQueue));
300 virtio_pci_t *pPciData = pDevice->pvHyper;
301 AssertReturn(pPciData, DDI_FAILURE);
302
303 pQueue->Ring.pRingAvail->Index += pQueue->cBufs;
304 pQueue->cBufs = 0;
305
306 ASMCompilerBarrier();
307
308 ddi_put16(pPciData->hIO, (uint16_t *)(pPciData->addrIOBase + VIRTIO_PCI_QUEUE_NOTIFY), pQueue->QueueIndex);
309 cmn_err(CE_NOTE, "VirtioPciNotifyQueue\n");
310}
311
312
313
314/**
315 * Virtio Pci set (write) routine.
316 *
317 * @param pDevice Pointer to the Virtio device instance.
318 * @param off Offset into the PCI config space.
319 * @param pv Pointer to the buffer to write from.
320 * @param cb Size of the buffer in bytes.
321 */
322static void VirtioPciSet(PVIRTIODEVICE pDevice, off_t off, void *pv, size_t cb)
323{
324 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciSet pDevice=%p\n", pDevice));
325 virtio_pci_t *pPciData = pDevice->pvHyper;
326 AssertReturnVoid(pPciData);
327
328 uint8_t *pb = pv;
329 for (size_t i = 0; i < cb; i++, pb++)
330 ddi_put8(pPciData->hIO, (uint8_t *)(pPciData->addrIOBase + VIRTIO_PCI_CONFIG + off + i), *pb);
331}
332
333
334/**
335 * Virtio Pci get (read) routine.
336 *
337 * @param pDevice Pointer to the Virtio device instance.
338 * @param off Offset into the PCI config space.
339 * @param pv Where to store the read data.
340 * @param cb Size of the buffer in bytes.
341 */
342static void VirtioPciGet(PVIRTIODEVICE pDevice, off_t off, void *pv, size_t cb)
343{
344 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciGet pDevice=%p off=%u pv=%p cb=%u\n", pDevice, off, pv, cb));
345 virtio_pci_t *pPciData = pDevice->pvHyper;
346 AssertReturnVoid(pPciData);
347
348 uint8_t *pb = pv;
349 for (size_t i = 0; i < cb; i++, pb++)
350 *pb = ddi_get8(pPciData->hIO, (uint8_t *)(pPciData->addrIOBase + VIRTIO_PCI_CONFIG + off + i));
351}
352
353
354/**
355 * Virtio Pci put queue routine. Places the queue and frees associated queue.
356 *
357 * @param pDevice Pointer to the Virtio device instance.
358 * @param pQueue Pointer to the queue.
359 */
360static void VirtioPciPutQueue(PVIRTIODEVICE pDevice, PVIRTIOQUEUE pQueue)
361{
362 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciPutQueue pDevice=%p pQueue=%p\n", pDevice, pQueue));
363 AssertReturnVoid(pDevice);
364 AssertReturnVoid(pQueue);
365
366 virtio_pci_t *pPci = pDevice->pvHyper;
367 AssertReturnVoid(pPci);
368 virtio_pci_queue_t *pPciQueue = pQueue->pvData;
369 if (RT_UNLIKELY(!pPciQueue))
370 {
371 LogRel((VIRTIOLOGNAME ":VirtioPciPutQueue missing Pci queue.\n"));
372 return;
373 }
374
375 ddi_put16(pPci->hIO, (uint16_t *)(pPci->addrIOBase + VIRTIO_PCI_QUEUE_SEL), pQueue->QueueIndex);
376 ddi_put32(pPci->hIO, (uint32_t *)(pPci->addrIOBase + VIRTIO_PCI_QUEUE_PFN), 0);
377
378 ddi_dma_unbind_handle(pPciQueue->hDMA);
379 ddi_dma_mem_free(&pPciQueue->hIO);
380 ddi_dma_free_handle(&pPciQueue->hDMA);
381 RTMemFree(pPciQueue);
382}
383
384
385/**
386 * Virtio Pci get queue routine. Allocates a PCI queue and DMA resources.
387 *
388 * @param pDevice Pointer to the Virtio device instance.
389 * @param pQueue Where to store the queue.
390 *
391 * @return An allocated Virtio Pci queue, or NULL in case of errors.
392 */
393static void *VirtioPciGetQueue(PVIRTIODEVICE pDevice, PVIRTIOQUEUE pQueue)
394{
395 LogFlowFunc((VIRTIOLOGNAME ":VirtioPciGetQueue pDevice=%p pQueue=%p\n", pDevice, pQueue));
396 AssertReturn(pDevice, NULL);
397
398 virtio_pci_t *pPci = pDevice->pvHyper;
399 AssertReturn(pPci, NULL);
400
401 /*
402 * Select a Queue.
403 */
404 ddi_put16(pPci->hIO, (uint16_t *)(pPci->addrIOBase + VIRTIO_PCI_QUEUE_SEL), pQueue->QueueIndex);
405
406 /*
407 * Get the currently selected Queue's size.
408 */
409 pQueue->Ring.cDesc = ddi_get16(pPci->hIO, (uint16_t *)(pPci->addrIOBase + VIRTIO_PCI_QUEUE_NUM));
410 if (RT_UNLIKELY(!pQueue->Ring.cDesc))
411 {
412 LogRel((VIRTIOLOGNAME ": VirtioPciGetQueue: Queue[%d] has no descriptors.\n", pQueue->QueueIndex));
413 return NULL;
414 }
415
416 /*
417 * Check if it's already active.
418 */
419 uint32_t QueuePFN = ddi_get32(pPci->hIO, (uint32_t *)(pPci->addrIOBase + VIRTIO_PCI_QUEUE_PFN));
420 if (QueuePFN != 0)
421 {
422 LogRel((VIRTIOLOGNAME ":VirtioPciGetQueue: Queue[%d] is already used.\n", pQueue->QueueIndex));
423 return NULL;
424 }
425
426 LogFlow(("Queue[%d] has %d slots.\n", pQueue->QueueIndex, pQueue->Ring.cDesc));
427
428 /*
429 * Allocate and initialize Pci queue data.
430 */
431 virtio_pci_queue_t *pPciQueue = RTMemAllocZ(sizeof(virtio_pci_queue_t));
432 if (pPciQueue)
433 {
434 /*
435 * Setup DMA.
436 */
437 size_t cbQueue = VirtioRingSize(pQueue->Ring.cDesc, VIRTIO_PCI_RING_ALIGN);
438 int rc = ddi_dma_alloc_handle(pDevice->pDip, &g_VirtioPciDmaAttrRing, DDI_DMA_SLEEP, 0 /* addr */, &pPciQueue->hDMA);
439 if (rc == DDI_SUCCESS)
440 {
441 rc = ddi_dma_mem_alloc(pPciQueue->hDMA, cbQueue, &g_VirtioPciAccAttrRing, DDI_DMA_CONSISTENT,
442 DDI_DMA_SLEEP, 0 /* addr */, &pQueue->pQueue, &pPciQueue->cbBuf,
443 &pPciQueue->hIO);
444 if (rc == DDI_SUCCESS)
445 {
446 AssertRelease(pPciQueue->cbBuf >= cbQueue);
447 ddi_dma_cookie_t DmaCookie;
448 uint_t cCookies;
449 rc = ddi_dma_addr_bind_handle(pPciQueue->hDMA, NULL /* addrspace */, pQueue->pQueue, pPciQueue->cbBuf,
450 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
451 0 /* addr */, &DmaCookie, &cCookies);
452 if (rc == DDI_SUCCESS)
453 {
454 pPciQueue->physBuf = DmaCookie.dmac_laddress;
455 pPciQueue->pageBuf = pPciQueue->physBuf >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
456
457 LogFlow((VIRTIOLOGNAME ":VirtioPciGetQueue: Queue[%d]%p physBuf=%x pfn of Buf %#x\n", pQueue->QueueIndex,
458 pQueue->pQueue, pPciQueue->physBuf, pPciQueue->pageBuf));
459 cmn_err(CE_NOTE, ":VirtioPciGetQueue: Queue[%d]%p physBuf=%x pfn of Buf %x\n", pQueue->QueueIndex,
460 pQueue->pQueue, pPciQueue->physBuf, pPciQueue->pageBuf);
461
462 /*
463 * Activate the queue and initialize a ring for the queue.
464 */
465 memset(pQueue->pQueue, 0, pPciQueue->cbBuf);
466 ddi_put32(pPci->hIO, (uint32_t *)(pPci->addrIOBase + VIRTIO_PCI_QUEUE_PFN), pPciQueue->pageBuf);
467 VirtioRingInit(pQueue, pQueue->Ring.cDesc, pQueue->pQueue, VIRTIO_PCI_RING_ALIGN);
468 return pPciQueue;
469 }
470 else
471 LogRel((VIRTIOLOGNAME ":VirtioPciGetQueue: ddi_dma_addr_bind_handle failed. rc=%d\n", rc));
472
473 ddi_dma_mem_free(&pPciQueue->hIO);
474 }
475 else
476 LogRel((VIRTIOLOGNAME ":VirtioPciGetQueue: ddi_dma_mem_alloc failed for %u bytes rc=%d\n", cbQueue, rc));
477
478 ddi_dma_free_handle(&pPciQueue->hDMA);
479 }
480 else
481 LogRel((VIRTIOLOGNAME ":VirtioPciGetQueue: ddi_dma_alloc_handle failed. rc=%d\n", rc));
482
483 RTMemFree(pPciQueue);
484 }
485 else
486 LogRel((VIRTIOLOGNAME ":VirtioPciGetQueue: failed to alloc %u bytes for Pci Queue data.\n", sizeof(virtio_pci_queue_t)));
487
488 return NULL;
489}
490
491
492/**
493 * Set the Virtio PCI status bit.
494 *
495 * @param pDevice Pointer to the Virtio device instance.
496 * @param Status The status to set.
497 */
498static void VirtioPciSetStatus(PVIRTIODEVICE pDevice, uint8_t Status)
499{
500 virtio_pci_t *pPciData = pDevice->pvHyper;
501 ddi_put8(pPciData->hIO, (uint8_t *)(pPciData->addrIOBase + VIRTIO_PCI_STATUS), Status);
502}
503
504
505/**
506 * Sets up IRQ for Virtio PCI.
507 *
508 * @param pDip Pointer to the device info structure.
509 *
510 * @return Solaris error code.
511 */
512static int VirtioPciSetupIRQ(dev_info_t *pDip)
513{
514 LogFlow((VIRTIOLOGNAME ":VirtioPciSetupIRQ: pDip=%p\n", pDip));
515 cmn_err(CE_NOTE, "VirtioPciSetupIRQ\n");
516
517 int IntrType = 0;
518 int rc = ddi_intr_get_supported_types(pDip, &IntrType);
519 if (rc == DDI_SUCCESS)
520 {
521 /* We won't need to bother about MSIs. */
522 if (IntrType & DDI_INTR_TYPE_FIXED)
523 {
524 int IntrCount = 0;
525 rc = ddi_intr_get_nintrs(pDip, IntrType, &IntrCount);
526 if ( rc == DDI_SUCCESS
527 && IntrCount > 0)
528 {
529 int IntrAvail = 0;
530 rc = ddi_intr_get_navail(pDip, IntrType, &IntrAvail);
531 if ( rc == DDI_SUCCESS
532 && IntrAvail > 0)
533 {
534 /* Allocated kernel memory for the interrupt handles. The allocation size is stored internally. */
535 g_pIntr = RTMemAllocZ(IntrCount * sizeof(ddi_intr_handle_t));
536 if (g_pIntr)
537 {
538 int IntrAllocated;
539 rc = ddi_intr_alloc(pDip, g_pIntr, IntrType, 0, IntrCount, &IntrAllocated, DDI_INTR_ALLOC_NORMAL);
540 if ( rc == DDI_SUCCESS
541 && IntrAllocated > 0)
542 {
543 g_cIntrAllocated = IntrAllocated;
544 uint_t uIntrPriority;
545 rc = ddi_intr_get_pri(g_pIntr[0], &uIntrPriority);
546 if (rc == DDI_SUCCESS)
547 {
548 /* Initialize the mutex. */
549 mutex_init(&g_IrqMtx, NULL, MUTEX_DRIVER, DDI_INTR_PRI(uIntrPriority));
550
551 /* Assign interrupt handler functions and enable interrupts. */
552 for (int i = 0; i < IntrAllocated; i++)
553 {
554 rc = ddi_intr_add_handler(g_pIntr[i], (ddi_intr_handler_t *)VirtioPciISR,
555 NULL /* No Private Data */, NULL);
556 if (rc == DDI_SUCCESS)
557 rc = ddi_intr_enable(g_pIntr[i]);
558 if (rc != DDI_SUCCESS)
559 {
560 /* Changing local IntrAllocated to hold so-far allocated handles for freeing. */
561 IntrAllocated = i;
562 break;
563 }
564 }
565 if (rc == DDI_SUCCESS)
566 {
567 cmn_err(CE_NOTE, "VirtioPciSetupIRQ success\n");
568 return rc;
569 }
570
571 /* Remove any assigned handlers */
572 LogRel((VIRTIOLOGNAME ":VirtioPciSetupIRQ failed to assign IRQs allocated=%d\n", IntrAllocated));
573 for (int x = 0; x < IntrAllocated; x++)
574 ddi_intr_remove_handler(g_pIntr[x]);
575 }
576 else
577 LogRel((VIRTIOLOGNAME ":VirtioPciSetupIRQ failed to get priority of interrupt. rc=%d\n", rc));
578
579 /* Remove allocated IRQs, too bad we can free only one handle at a time. */
580 for (int k = 0; k < g_cIntrAllocated; k++)
581 ddi_intr_free(g_pIntr[k]);
582 }
583 else
584 LogRel((VIRTIOLOGNAME ":VirtioPciSetupIRQ: failed to allocated IRQs. count=%d\n", IntrCount));
585 RTMemFree(g_pIntr);
586 }
587 else
588 LogRel((VIRTIOLOGNAME ":VirtioPciSetupIRQ: failed to allocated IRQs. count=%d\n", IntrCount));
589 }
590 else
591 {
592 LogRel((VIRTIOLOGNAME ":VirtioPciSetupIRQ: failed to get or insufficient available IRQs. rc=%d IntrAvail=%d\n",
593 rc, IntrAvail));
594 }
595 }
596 else
597 {
598 LogRel((VIRTIOLOGNAME ":VirtioPciSetupIRQ: failed to get or insufficient number of IRQs. rc=%d IntrCount=%d\n", rc,
599 IntrCount));
600 }
601 }
602 else
603 LogRel((VIRTIOLOGNAME ":VirtioPciSetupIRQ: invalid irq type. IntrType=%#x\n", IntrType));
604 }
605 else
606 LogRel((VIRTIOLOGNAME ":VirtioPciSetupIRQ: failed to get supported interrupt types\n"));
607 return rc;
608}
609
610
611/**
612 * Removes IRQ for Virtio PCI device.
613 *
614 * @param pDip Pointer to the device info structure.
615 */
616static void VirtioPciRemoveIRQ(dev_info_t *pDip)
617{
618 LogFlow((VIRTIOLOGNAME ":VirtioPciRemoveIRQ pDip=%p:\n", pDip));
619
620 for (int i = 0; i < g_cIntrAllocated; i++)
621 {
622 int rc = ddi_intr_disable(g_pIntr[i]);
623 if (rc == DDI_SUCCESS)
624 {
625 rc = ddi_intr_remove_handler(g_pIntr[i]);
626 if (rc == DDI_SUCCESS)
627 ddi_intr_free(g_pIntr[i]);
628 }
629 }
630 RTMemFree(g_pIntr);
631 mutex_destroy(&g_IrqMtx);
632}
633
634
635/**
636 * Interrupt Service Routine for Virtio PCI device.
637 *
638 * @param Arg Private data (unused, will be NULL).
639 * @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
640 */
641static uint_t VirtioPciISR(caddr_t Arg)
642{
643 LogFlow((VIRTIOLOGNAME ":VBoxGuestSolarisISR\n"));
644 cmn_err(CE_NOTE, "VBoxGuestSolarisISRd Arg=%p\n", Arg);
645
646 mutex_enter(&g_IrqMtx);
647 bool fOurIRQ = false;
648 /*
649 * Call the DeviceOps ISR routine somehow which should notify all Virtio queues
650 * on the interrupt.
651 */
652 mutex_exit(&g_IrqMtx);
653
654 return fOurIRQ ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED;
655}
656
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