VirtualBox

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

最後變更 在這個檔案從34143是 34143,由 vboxsync 提交於 14 年 前

Additions/Solaris/Virtio: export to OSE

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

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