VirtualBox

source: vbox/trunk/src/VBox/Devices/Bus/MsixCommon.cpp@ 33278

Last change on this file since 33278 was 33236, checked in by vboxsync, 15 years ago

PCI: MSI-X work

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 4.2 KB
Line 
1/* $Id: MsixCommon.cpp 33236 2010-10-19 15:14:42Z vboxsync $ */
2/** @file
3 * MSI-X support routines
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.215389.xyz. 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#define LOG_GROUP LOG_GROUP_DEV_PCI
18/* Hack to get PCIDEVICEINT declare at the right point - include "PCIInternal.h". */
19#define PCI_INCLUDE_PRIVATE
20#include <VBox/pci.h>
21#include <VBox/msi.h>
22#include <VBox/pdmdev.h>
23#include <VBox/log.h>
24
25#include "MsiCommon.h"
26
27DECLINLINE(uint16_t) msixGetMessageControl(PPCIDEVICE pDev)
28{
29 return PCIDevGetWord(pDev, pDev->Int.s.u8MsixCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL);
30}
31
32DECLINLINE(bool) msixIsEnabled(PPCIDEVICE pDev)
33{
34 return (msixGetMessageControl(pDev) & VBOX_PCI_MSIX_FLAGS_ENABLE) != 0;
35}
36
37
38int MsixInit(PPCIDEVICE pDev, PPDMMSIREG pMsiReg)
39{
40 if (pMsiReg->cMsixVectors == 0)
41 return VINF_SUCCESS;
42
43 uint16_t cVectors = pMsiReg->cMsixVectors;
44 uint8_t iCapOffset = pMsiReg->iMsixCapOffset;
45 uint8_t iNextOffset = pMsiReg->iMsixNextOffset;
46 uint16_t iFlags = pMsiReg->iMsixFlags;
47
48 if (cVectors != 1)
49 /* We cannot handle multiple vectors yet */
50 return VERR_TOO_MUCH_DATA;
51
52 if (cVectors > VBOX_MSIX_MAX_ENTRIES)
53 return VERR_TOO_MUCH_DATA;
54
55 Assert(iCapOffset != 0 && iCapOffset < 0xff && iNextOffset < 0xff);
56
57 pDev->Int.s.u8MsixCapOffset = iCapOffset;
58 pDev->Int.s.u8MsixCapSize = VBOX_MSIX_CAP_SIZE;
59
60 PCIDevSetByte(pDev, iCapOffset + 0, VBOX_PCI_CAP_ID_MSIX);
61 PCIDevSetByte(pDev, iCapOffset + 1, iNextOffset); /* next */
62 PCIDevSetWord(pDev, iCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL, iFlags);
63
64 PCISetMsixCapable(pDev);
65
66 return VINF_SUCCESS;
67}
68
69
70bool MsixIsEnabled(PPCIDEVICE pDev)
71{
72 return PCIIsMsixCapable(pDev) && msixIsEnabled(pDev);
73}
74
75void MsixNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, int iVector, int iLevel)
76{
77 AssertMsg(msixIsEnabled(pDev), ("Must be enabled to use that"));
78
79 Assert(pPciHlp->pfnIoApicSendMsi != NULL);
80}
81
82
83void MsixPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, uint32_t u32Address, uint32_t val, unsigned len)
84{
85 int32_t iOff = u32Address - pDev->Int.s.u8MsixCapOffset;
86 Assert(iOff >= 0 && (PCIIsMsixCapable(pDev) && iOff < pDev->Int.s.u8MsixCapSize));
87
88 Log2(("MsixPciConfigWrite: %d <- %x (%d)\n", iOff, val, len));
89
90 uint32_t uAddr = u32Address;
91
92 for (uint32_t i = 0; i < len; i++)
93 {
94 uint32_t reg = i + iOff;
95 uint8_t u8Val = (uint8_t)val;
96 switch (reg)
97 {
98 case 0: /* Capability ID, ro */
99 case 1: /* Next pointer, ro */
100 break;
101 case VBOX_MSIX_CAP_MESSAGE_CONTROL:
102 /* don't change read-only bits: 0-7 */
103 break;
104 case VBOX_MSIX_CAP_MESSAGE_CONTROL + 1:
105 /* don't change read-only bits 8-13 */
106 pDev->config[uAddr] = (u8Val & UINT8_C(~0x3f)) | (pDev->config[uAddr] & UINT8_C(0x3f));
107 break;
108 default:
109 /* other fields read-only too */
110 break;
111 }
112 uAddr++;
113 val >>= 8;
114 }
115}
116uint32_t MsixPciConfigRead (PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, unsigned len)
117{
118 int32_t iOff = u32Address - pDev->Int.s.u8MsixCapOffset;
119
120 Assert(iOff >= 0 && (PCIIsMsixCapable(pDev) && iOff < pDev->Int.s.u8MsixCapSize));
121 uint32_t rv = 0;
122
123 switch (len)
124 {
125 case 1:
126 rv = PCIDevGetByte(pDev, u32Address);
127 break;
128 case 2:
129 rv = PCIDevGetWord(pDev, u32Address);
130 break;
131 case 4:
132 rv = PCIDevGetDWord(pDev, u32Address);
133 break;
134 default:
135 Assert(false);
136 }
137
138 Log2(("MsixPciConfigRead: %d (%d) -> %x\n", iOff, len, rv));
139
140 return rv;
141}
Note: See TracBrowser for help on using the repository browser.

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