MsiCommon.cpp revision bca1ab31c0e7c1e9d9ebc4faa4c06925a37f5996
ea0316554d23852601ee840c4a856339501411a4vboxsync * MSI support routines
ea0316554d23852601ee840c4a856339501411a4vboxsync * Copyright (C) 2010 Oracle Corporation
ea0316554d23852601ee840c4a856339501411a4vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
ea0316554d23852601ee840c4a856339501411a4vboxsync * available from http://www.virtualbox.org. This file is free software;
ea0316554d23852601ee840c4a856339501411a4vboxsync * you can redistribute it and/or modify it under the terms of the GNU
ea0316554d23852601ee840c4a856339501411a4vboxsync * General Public License (GPL) as published by the Free Software
ea0316554d23852601ee840c4a856339501411a4vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
ea0316554d23852601ee840c4a856339501411a4vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
ea0316554d23852601ee840c4a856339501411a4vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
ea0316554d23852601ee840c4a856339501411a4vboxsync/* Hack to get PCIDEVICEINT declare at the right point - include "PCIInternal.h". */
ea0316554d23852601ee840c4a856339501411a4vboxsyncDECLINLINE(uint16_t) msiGetMessageControl(PPCIDEVICE pDev)
ea0316554d23852601ee840c4a856339501411a4vboxsync return PCIDevGetWord(pDev, pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL);
82546d3d9144e70a29430532ac0011ab77b2d5bbvboxsync return (msiGetMessageControl(pDev) & VBOX_PCI_MSI_FLAGS_64BIT) != 0;
0eb8851309a7678e8ccee719ee3eead40651b5d4vboxsyncDECLINLINE(uint32_t*) msiGetMaskBits(PPCIDEVICE pDev)
0eb8851309a7678e8ccee719ee3eead40651b5d4vboxsync uint8_t iOff = msiIs64Bit(pDev) ? VBOX_MSI_CAP_MASK_BITS_64 : VBOX_MSI_CAP_MASK_BITS_32;
0eb8851309a7678e8ccee719ee3eead40651b5d4vboxsyncDECLINLINE(uint32_t*) msiGetPendingBits(PPCIDEVICE pDev)
0eb8851309a7678e8ccee719ee3eead40651b5d4vboxsync uint8_t iOff = msiIs64Bit(pDev) ? VBOX_MSI_CAP_PENDING_BITS_64 : VBOX_MSI_CAP_PENDING_BITS_32;
82546d3d9144e70a29430532ac0011ab77b2d5bbvboxsync return (msiGetMessageControl(pDev) & VBOX_PCI_MSI_FLAGS_ENABLE) != 0;
ea0316554d23852601ee840c4a856339501411a4vboxsync return (msiGetMessageControl(pDev) & VBOX_PCI_MSI_FLAGS_QSIZE) != 0;
ea0316554d23852601ee840c4a856339501411a4vboxsyncDECLINLINE(RTGCPHYS) msiGetMsiAddress(PPCIDEVICE pDev)
ea0316554d23852601ee840c4a856339501411a4vboxsync uint32_t lo = PCIDevGetDWord(pDev, pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_ADDRESS_LO);
ea0316554d23852601ee840c4a856339501411a4vboxsync uint32_t hi = PCIDevGetDWord(pDev, pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_ADDRESS_HI);
ea0316554d23852601ee840c4a856339501411a4vboxsync return PCIDevGetDWord(pDev, pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_ADDRESS_32);
ea0316554d23852601ee840c4a856339501411a4vboxsyncDECLINLINE(uint32_t) msiGetMsiData(PPCIDEVICE pDev, int32_t iVector)
ea0316554d23852601ee840c4a856339501411a4vboxsync int16_t iOff = msiIs64Bit(pDev) ? VBOX_MSI_CAP_MESSAGE_DATA_64 : VBOX_MSI_CAP_MESSAGE_DATA_32;
ea0316554d23852601ee840c4a856339501411a4vboxsync uint16_t lo = PCIDevGetWord(pDev, pDev->Int.s.u8MsiCapOffset + iOff);
ea0316554d23852601ee840c4a856339501411a4vboxsync /// @todo: vector encoding into lower bits of message data, for Multiple Message Enable
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsyncDECLINLINE(bool) msiBitJustCleared(uint32_t uOldValue,
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync return (!!(uOldValue & uMask) && !(uNewValue & uMask));
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync return (!(uOldValue & uMask) && !!(uNewValue & uMask));
f1f55b6ac890efaabca0ff940f58aa8df1dc84c8vboxsyncvoid MsiPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, uint32_t u32Address, uint32_t val, unsigned len)
ea0316554d23852601ee840c4a856339501411a4vboxsync int32_t iOff = u32Address - pDev->Int.s.u8MsiCapOffset;
ea0316554d23852601ee840c4a856339501411a4vboxsync Assert(iOff >= 0 && (PCIIsMsiCapable(pDev) && iOff < pDev->Int.s.u8MsiCapSize));
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync Log2(("MsiPciConfigWrite: %d <- %x (%d)\n", iOff, val, len));
ea0316554d23852601ee840c4a856339501411a4vboxsync case 0: /* Capability ID, ro */
ea0316554d23852601ee840c4a856339501411a4vboxsync /* don't change read-only bits: 1-3,7 */
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync pDev->config[uAddr] = u8Val | (pDev->config[uAddr] & UINT8_C(0x8e));
ea0316554d23852601ee840c4a856339501411a4vboxsync /* don't change read-only bit 8, and reserved 9-15 */
0eb8851309a7678e8ccee719ee3eead40651b5d4vboxsync /* If we're enabling masked vector, and have pending messages
0eb8851309a7678e8ccee719ee3eead40651b5d4vboxsync for this vector, we have to send this message now */
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync if (msiBitJustCleared(pDev->config[uAddr], u8Val, iBit))
c9c1b52d5c13d75ba8fc3d86278f2b0c6b3e8c2avboxsync Log(("msi: mask updated bit %d@%x (%d)\n", iBitNum, uAddr, maskUpdated));
0eb8851309a7678e8ccee719ee3eead40651b5d4vboxsync /* To ensure that we're no longer masked */
c9c1b52d5c13d75ba8fc3d86278f2b0c6b3e8c2avboxsync Log(("msi: notify earlier masked pending vector: %d\n", uVector));
c9c1b52d5c13d75ba8fc3d86278f2b0c6b3e8c2avboxsync MsiNotify(pDevIns, pPciHlp, pDev, uVector, PDM_IRQ_LEVEL_HIGH);
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync if (msiBitJustSet(pDev->config[uAddr], u8Val, iBit))
f1f55b6ac890efaabca0ff940f58aa8df1dc84c8vboxsyncuint32_t MsiPciConfigRead (PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, unsigned len)
ea0316554d23852601ee840c4a856339501411a4vboxsync int32_t iOff = u32Address - pDev->Int.s.u8MsiCapOffset;
ea0316554d23852601ee840c4a856339501411a4vboxsync Assert(iOff >= 0 && (PCIIsMsiCapable(pDev) && iOff < pDev->Int.s.u8MsiCapSize));
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync Log2(("MsiPciConfigRead: %d (%d) -> %x\n", iOff, len, rv));
b742a29c8c5a06fb5f362e5e6c09cbcaf8087ff6vboxsync /* We cannot handle multiple vectors yet */
ea0316554d23852601ee840c4a856339501411a4vboxsync Assert(iCapOffset != 0 && iCapOffset < 0xff && iNextOffset < 0xff);
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync bool f64bit = (iFlags & VBOX_PCI_MSI_FLAGS_64BIT) != 0;
0eb8851309a7678e8ccee719ee3eead40651b5d4vboxsync /* We always support per-vector masking */
ea0316554d23852601ee840c4a856339501411a4vboxsync pDev->Int.s.u8MsiCapSize = f64bit ? VBOX_MSI_CAP_SIZE_64 : VBOX_MSI_CAP_SIZE_32;
ea0316554d23852601ee840c4a856339501411a4vboxsync PCIDevSetByte(pDev, iCapOffset + 0, VBOX_PCI_CAP_ID_MSI);
ea0316554d23852601ee840c4a856339501411a4vboxsync PCIDevSetByte(pDev, iCapOffset + 1, iNextOffset); /* next */
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync PCIDevSetWord(pDev, iCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL, iFlags);
ea0316554d23852601ee840c4a856339501411a4vboxsync return PCIIsMsiCapable(pDev) && msiIsEnabled(pDev);
c9c1b52d5c13d75ba8fc3d86278f2b0c6b3e8c2avboxsyncvoid MsiNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, int iVector, int iLevel)
ea0316554d23852601ee840c4a856339501411a4vboxsync AssertMsg(msiIsEnabled(pDev), ("Must be enabled to use that"));
bca1ab31c0e7c1e9d9ebc4faa4c06925a37f5996vboxsync LogFlow(("MsiNotify: %d pending=%x mask=%x\n", iVector, *puPending, uMask));
c9c1b52d5c13d75ba8fc3d86278f2b0c6b3e8c2avboxsync /* We only trigger MSI on level up */
c9c1b52d5c13d75ba8fc3d86278f2b0c6b3e8c2avboxsync /* @todo: maybe clear pending interrupts on level down? */
c9c1b52d5c13d75ba8fc3d86278f2b0c6b3e8c2avboxsync LogFlow(("msi: clear pending %d, now %x\n", iVector, *puPending));
c9c1b52d5c13d75ba8fc3d86278f2b0c6b3e8c2avboxsync LogFlow(("msi: %d is masked, mark pending, now %x\n", iVector, *puPending));