VirtualBox

Changeset 62553 in vbox for trunk/src/VBox/Devices/PC


Ignore:
Timestamp:
Jul 26, 2016 8:39:53 AM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
109122
Message:

Devices/ACPI: Implement dummy SMBus controller (to get rid of the annoying error from the i2c-piix4 kernel module which is loaded for the ACPI device on many Linux distros), rewrite the interrupt signalling to be easier to understand and more extensible, more complete/safe reset handling and a general cleanup by using a lot more defines to reduce the number of unexplained hex constants. Needs bumping the saved state version to cover the additional device state.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/DevACPI.cpp

    r62509 r62553  
    6464#define DEBUG_CHR       0x3001
    6565
     66/** PM Base Address PCI config space offset */
     67#define PMBA            0x40
     68/** PM Miscellaneous Power Management PCI config space offset */
     69#define PMREGMISC       0x80
     70
    6671#define PM_TMR_FREQ     3579545
    67 /* Default base for PM PIIX4 device */
     72/** Default base for PM PIIX4 device */
    6873#define PM_PORT_BASE    0x4000
    6974/* Port offsets in PM device */
     
    204209#define STA_BATTERY_PRESENT_MASK                RT_BIT(4) /**< the battery is present */
    205210
     211/** SMBus Base Address PCI config space offset */
     212#define SMBBA           0x90
     213/** SMBus Host Configuration PCI config space offset */
     214#define SMBHSTCFG       0xd2
     215/** SMBus Slave Command PCI config space offset */
     216#define SMBSLVC         0xd3
     217/** SMBus Slave Shadow Port 1 PCI config space offset */
     218#define SMBSHDW1        0xd4
     219/** SMBus Slave Shadow Port 2 PCI config space offset */
     220#define SMBSHDW2        0xd5
     221/** SMBus Revision Identification PCI config space offset */
     222#define SMBREV          0xd6
     223
     224#define SMBHSTCFG_SMB_HST_EN    RT_BIT(0)
     225#define SMBHSTCFG_INTRSEL       (RT_BIT(1) | RT_BIT(2) | RT_BIT(3))
     226#define SMBHSTCFG_INTRSEL_SMI   0
     227#define SMBHSTCFG_INTRSEL_IRQ9  4
     228#define SMBHSTCFG_INTRSEL_SHIFT 1
     229
     230/** Default base for SMBus PIIX4 device */
     231#define SMB_PORT_BASE   0x4100
     232
     233/** SMBus Host Status Register I/O offset */
     234#define SMBHSTSTS_OFF   0x0000
     235/** SMBus Slave Status Register I/O offset */
     236#define SMBSLVSTS_OFF   0x0001
     237/** SMBus Host Count Register I/O offset */
     238#define SMBHSTCNT_OFF   0x0002
     239/** SMBus Host Command Register I/O offset */
     240#define SMBHSTCMD_OFF   0x0003
     241/** SMBus Host Address Register I/O offset */
     242#define SMBHSTADD_OFF   0x0004
     243/** SMBus Host Data 0 Register I/O offset */
     244#define SMBHSTDAT0_OFF  0x0005
     245/** SMBus Host Data 1 Register I/O offset */
     246#define SMBHSTDAT1_OFF  0x0006
     247/** SMBus Block Data Register I/O offset */
     248#define SMBBLKDAT_OFF   0x0007
     249/** SMBus Slave Control Register I/O offset */
     250#define SMBSLVCNT_OFF   0x0008
     251/** SMBus Shadow Command Register I/O offset */
     252#define SMBSHDWCMD_OFF  0x0009
     253/** SMBus Slave Event Register I/O offset */
     254#define SMBSLVEVT_OFF   0x000a
     255/** SMBus Slave Data Register I/O offset */
     256#define SMBSLVDAT_OFF   0x000c
     257
     258#define SMBHSTSTS_HOST_BUSY RT_BIT(0)
     259#define SMBHSTSTS_INTER     RT_BIT(1)
     260#define SMBHSTSTS_DEV_ERR   RT_BIT(2)
     261#define SMBHSTSTS_BUS_ERR   RT_BIT(3)
     262#define SMBHSTSTS_FAILED    RT_BIT(4)
     263#define SMBHSTSTS_INT_MASK  (SMBHSTSTS_INTER | SMBHSTSTS_DEV_ERR | SMBHSTSTS_BUS_ERR | SMBHSTSTS_FAILED)
     264
     265#define SMBSLVSTS_WRITE_MASK 0x3c
     266
     267#define SMBHSTCNT_INTEREN   RT_BIT(0)
     268#define SMBHSTCNT_KILL      RT_BIT(1)
     269#define SMBHSTCNT_CMD_PROT  (RT_BIT(2) | RT_BIT(3) | RT_BIT(4))
     270#define SMBHSTCNT_START     RT_BIT(6)
     271#define SMBHSTCNT_WRITE_MASK (SMBHSTCNT_INTEREN | SMBHSTCNT_KILL | SMBHSTCNT_CMD_PROT)
     272
     273#define SMBSLVCNT_WRITE_MASK (RT_BIT(0) | RT_BIT(1) | RT_BIT(2) | RT_BIT(3))
     274
    206275
    207276/*********************************************************************************************************************************
     
    271340    /** I/O port address of PM device. */
    272341    RTIOPORT            uPmIoPortBase;
     342    /** I/O port address of SMBus device. */
     343    RTIOPORT            uSMBusIoPortBase;
    273344    /** Flag whether the GC part of the device is enabled. */
    274345    bool                fGCEnabled;
     
    305376    /** PCI address of the host bus controller device. */
    306377    uint32_t            u32HbcPciAddress;
     378
     379    uint32_t            Alignment1;
     380
    307381    /* Physical address of PCI config space MMIO region */
    308382    uint64_t            u64PciConfigMMioAddress;
     
    338412    /** @} */
    339413
    340     uint32_t            u32Alignment1;
     414    uint32_t            Alignment2;
    341415
    342416    /** ACPI port base interface. */
     
    349423    PPDMDEVINSRC        pDevInsRC;
    350424
    351     uint32_t            Alignment2;
     425    uint32_t            Alignment3;
    352426    /** Pointer to the driver base interface. */
    353427    R3PTRTYPE(PPDMIBASE) pDrvBase;
     
    372446    /** ACPI custom OEM Rev */
    373447    uint32_t            u32OemRevision;
    374     uint32_t            Alignment3;
     448    uint32_t            Alignment4;
    375449
    376450    /** The custom table binary data. */
     
    378452    /** The size of the custom table binary. */
    379453    uint64_t            cbCustBin;
     454
     455    /** SMBus Host Status Register */
     456    uint8_t             u8SMBusHstSts;
     457    /** SMBus Slave Status Register */
     458    uint8_t             u8SMBusSlvSts;
     459    /** SMBus Host Control Register */
     460    uint8_t             u8SMBusHstCnt;
     461    /** SMBus Host Command Register */
     462    uint8_t             u8SMBusHstCmd;
     463    /** SMBus Host Address Register */
     464    uint8_t             u8SMBusHstAdd;
     465    /** SMBus Host Data 0 Register */
     466    uint8_t             u8SMBusHstDat0;
     467    /** SMBus Host Data 1 Register */
     468    uint8_t             u8SMBusHstDat1;
     469    /** SMBus Slave Control Register */
     470    uint8_t             u8SMBusSlvCnt;
     471    /** SMBus Shadow Command Register */
     472    uint8_t             u8SMBusShdwCmd;
     473    /** SMBus Slave Event Register */
     474    uint16_t            u16SMBusSlvEvt;
     475    /** SMBus Slave Data Register */
     476    uint16_t            u16SMBusSlvDat;
     477    /** SMBus Host Block Data Buffer */
     478    uint8_t             au8SMBusBlkDat[32];
     479    /** SMBus Host Block Index */
     480    uint8_t             u8SMBusBlkIdx;
    380481} ACPIState;
    381482
     
    672773#endif
    673774
    674 /* SCI IRQ */
     775/* SCI, usually IRQ9 */
    675776DECLINLINE(void) acpiSetIrq(ACPIState *pThis, int level)
    676777{
    677     if (pThis->pm1a_ctl & SCI_EN)
    678         PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, level);
    679 }
    680 
    681 DECLINLINE(uint32_t) pm1a_pure_en(uint32_t en)
    682 {
    683     return en & ~(RSR_EN | IGN_EN);
    684 }
    685 
    686 DECLINLINE(uint32_t) pm1a_pure_sts(uint32_t sts)
    687 {
    688     return sts & ~(RSR_STS | IGN_STS);
    689 }
    690 
    691 DECLINLINE(int) pm1a_level(ACPIState *pThis)
    692 {
    693     return (pm1a_pure_en(pThis->pm1a_en) & pm1a_pure_sts(pThis->pm1a_sts)) != 0;
     778    PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, level);
     779}
     780
     781DECLINLINE(bool) pm1a_level(ACPIState *pThis)
     782{
     783    return    (pThis->pm1a_ctl & SCI_EN)
     784           && (pThis->pm1a_en & pThis->pm1a_sts & ~(RSR_EN | IGN_EN));
    694785}
    695786
    696787DECLINLINE(bool) gpe0_level(ACPIState *pThis)
    697788{
    698     return (pThis->gpe0_en & pThis->gpe0_sts) != 0;
     789    return (pThis->gpe0_en & pThis->gpe0_sts);
     790}
     791
     792DECLINLINE(bool) smbus_level(ACPIState *pThis)
     793{
     794    return    (pThis->u8SMBusHstCnt & SMBHSTCNT_INTEREN)
     795           && (pThis->dev.config[SMBHSTCFG] & SMBHSTCFG_SMB_HST_EN)
     796           && (pThis->dev.config[SMBHSTCFG] & SMBHSTCFG_INTRSEL) == SMBHSTCFG_INTRSEL_IRQ9 << SMBHSTCFG_INTRSEL_SHIFT
     797           && (pThis->u8SMBusHstSts & SMBHSTSTS_INT_MASK);
     798}
     799
     800DECLINLINE(bool) acpiSCILevel(ACPIState *pThis)
     801{
     802    return pm1a_level(pThis) || gpe0_level(pThis) || smbus_level(pThis);
    699803}
    700804
     
    715819    Assert(PDMCritSectIsOwner(&pThis->CritSect));
    716820
    717     if (gpe0_level(pThis))
    718         return;
    719 
    720     int const old_level = pm1a_level(pThis);
    721     int const new_level = (pm1a_pure_en(en) & pm1a_pure_sts(sts)) != 0;
    722 
    723     Log(("apicUpdatePm1a() old=%x new=%x\n", old_level, new_level));
    724 
     821    const bool old_level = acpiSCILevel(pThis);
    725822    pThis->pm1a_en = en;
    726823    pThis->pm1a_sts = sts;
     824    const bool new_level = acpiSCILevel(pThis);
     825
     826    LogFunc(("old=%x new=%x\n", old_level, new_level));
    727827
    728828    if (new_level != old_level)
     
    746846    Assert(PDMCritSectIsOwner(&pThis->CritSect));
    747847
    748     if (pm1a_level(pThis))
    749         return;
    750 
    751     int const old_level = gpe0_level(pThis);
    752     int const new_level = (en & sts) != 0;
    753 
     848    const bool old_level = acpiSCILevel(pThis);
    754849    pThis->gpe0_en  = en;
    755850    pThis->gpe0_sts = sts;
     851    const bool new_level = acpiSCILevel(pThis);
     852
     853    LogFunc(("old=%x new=%x\n", old_level, new_level));
    756854
    757855    if (new_level != old_level)
     
    12941392        case SYSTEM_INFO_INDEX_PCI_LENGTH:
    12951393            /** @todo couldn't MCFG be in 64-bit range? */
    1296             Assert(pThis->u64PciConfigMMioLength< 0xffffffff);
     1394            Assert(pThis->u64PciConfigMMioLength < 0xffffffff);
    12971395            *pu32 = (uint32_t)pThis->u64PciConfigMMioLength;
    12981396            break;
     
    18231921
    18241922/**
     1923 * Called by acpiR3Reset and acpiR3Construct to set up the PM PCI config space.
     1924 *
     1925 * @param   pThis               The ACPI instance.
     1926 */
     1927static void acpiR3PmPCIBIOSFake(ACPIState *pThis)
     1928{
     1929    pThis->dev.config[PMBA  ] = pThis->uPmIoPortBase | 1; /* PMBA, PM base address, bit 0 marks it as IO range */
     1930    pThis->dev.config[PMBA+1] = pThis->uPmIoPortBase >> 8;
     1931    pThis->dev.config[PMBA+2] = 0x00;
     1932    pThis->dev.config[PMBA+3] = 0x00;
     1933}
     1934
     1935/**
    18251936 * Used to calculate the value of a PM I/O port.
    18261937 *
     
    18481959static int acpiR3RegisterPmHandlers(ACPIState *pThis)
    18491960{
    1850     int   rc = VINF_SUCCESS;
     1961    if (pThis->uPmIoPortBase == 0)
     1962        return VINF_SUCCESS;
    18511963
    18521964#define R(offset, cnt, writer, reader, description) \
    18531965    do { \
    1854         rc = PDMDevHlpIOPortRegister(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
    1855                                       NULL, NULL, description); \
     1966        int rc = PDMDevHlpIOPortRegister(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, offset), cnt, pThis, writer, reader, \
     1967                                         NULL, NULL, description); \
    18561968        if (RT_FAILURE(rc)) \
    18571969            return rc; \
     
    18711983    if (pThis->fGCEnabled)
    18721984    {
    1873         rc = PDMDevHlpIOPortRegisterRC(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
    1874                                        1, 0, NULL, "acpiPMTmrRead",
    1875                                        NULL, NULL, "ACPI PM Timer");
     1985        int rc = PDMDevHlpIOPortRegisterRC(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
     1986                                           1, 0, NULL, "acpiPMTmrRead",
     1987                                           NULL, NULL, "ACPI PM Timer");
    18761988        AssertRCReturn(rc, rc);
    18771989    }
     
    18801992    if (pThis->fR0Enabled)
    18811993    {
    1882         rc = PDMDevHlpIOPortRegisterR0(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
    1883                                        1, 0, NULL, "acpiPMTmrRead",
    1884                                        NULL, NULL, "ACPI PM Timer");
     1994        int rc = PDMDevHlpIOPortRegisterR0(pThis->pDevInsR3, acpiR3CalcPmPort(pThis, PM_TMR_OFFSET),
     1995                                           1, 0, NULL, "acpiPMTmrRead",
     1996                                           NULL, NULL, "ACPI PM Timer");
    18851997        AssertRCReturn(rc, rc);
    18861998    }
    18871999
    1888     return rc;
     2000    return VINF_SUCCESS;
    18892001}
    18902002
     
    18982010static int acpiR3UnregisterPmHandlers(ACPIState *pThis)
    18992011{
     2012    if (pThis->uPmIoPortBase == 0)
     2013        return VINF_SUCCESS;
     2014
    19002015#define U(offset, cnt) \
    19012016    do { \
     
    19462061        if (RT_FAILURE(rc))
    19472062            return rc;
     2063    }
     2064
     2065    return VINF_SUCCESS;
     2066}
     2067
     2068/**
     2069 * @callback_method_impl{FNIOMIOPORTOUT, SMBus}
     2070 */
     2071PDMBOTHCBDECL(int) acpiR3SMBusWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
     2072{
     2073    ACPIState *pThis = (ACPIState *)pvUser;
     2074    DEVACPI_LOCK_R3(pThis);
     2075
     2076    LogFunc(("Port=%#x u32=%#x cb=%u\n", Port, u32, cb));
     2077    uint8_t off = Port & 0x000f;
     2078    if (   (cb != 1 && off <= SMBSHDWCMD_OFF)
     2079        || (cb != 2 && (off == SMBSLVEVT_OFF || off == SMBSLVDAT_OFF)))
     2080        return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "cb=%d Port=%u u32=%#x\n", cb, Port, u32);
     2081
     2082    switch (off)
     2083    {
     2084        case SMBHSTSTS_OFF:
     2085            /* Bit 0 is readonly, bits 1..4 are write clear, bits 5..7 are reserved */
     2086            pThis->u8SMBusHstSts &= ~(u32 & SMBHSTSTS_INT_MASK);
     2087            break;
     2088        case SMBSLVSTS_OFF:
     2089            /* Bit 0 is readonly, bit 1 is reserved, bits 2..5 are write clear, bits 6..7 are reserved */
     2090            pThis->u8SMBusSlvSts &= ~(u32 & SMBSLVSTS_WRITE_MASK);
     2091            break;
     2092        case SMBHSTCNT_OFF:
     2093        {
     2094            Assert(PDMCritSectIsOwner(&pThis->CritSect));
     2095
     2096            const bool old_level = acpiSCILevel(pThis);
     2097            pThis->u8SMBusHstCnt = u32 & SMBHSTCNT_WRITE_MASK;
     2098            if (u32 & SMBHSTCNT_START)
     2099            {
     2100                /* Start, trigger error as this is a dummy implementation */
     2101                pThis->u8SMBusHstSts |= SMBHSTSTS_DEV_ERR | SMBHSTSTS_INTER;
     2102            }
     2103            if (u32 & SMBHSTCNT_KILL)
     2104            {
     2105                /* Kill */
     2106                pThis->u8SMBusHstSts |= SMBHSTSTS_FAILED | SMBHSTSTS_INTER;
     2107            }
     2108            const bool new_level = acpiSCILevel(pThis);
     2109
     2110            LogFunc(("old=%x new=%x\n", old_level, new_level));
     2111
     2112            /* This handles only SCI/IRQ9. SMI# makes not much sense today and
     2113             * needs to be implemented later if it ever becomes relevant. */
     2114            if (new_level != old_level)
     2115                acpiSetIrq(pThis, new_level);
     2116            break;
     2117        }
     2118        case SMBHSTCMD_OFF:
     2119            pThis->u8SMBusHstCmd = u32;
     2120            break;
     2121        case SMBHSTADD_OFF:
     2122            pThis->u8SMBusHstAdd = u32;
     2123            break;
     2124        case SMBHSTDAT0_OFF:
     2125            pThis->u8SMBusHstDat0 = u32;
     2126            break;
     2127        case SMBHSTDAT1_OFF:
     2128            pThis->u8SMBusHstDat1 = u32;
     2129            break;
     2130        case SMBBLKDAT_OFF:
     2131            pThis->au8SMBusBlkDat[pThis->u8SMBusBlkIdx] = u32;
     2132            pThis->u8SMBusBlkIdx++;
     2133            pThis->u8SMBusBlkIdx &= sizeof(pThis->au8SMBusBlkDat) - 1;
     2134            break;
     2135        case SMBSLVCNT_OFF:
     2136            pThis->u8SMBusSlvCnt = u32 & SMBSLVCNT_WRITE_MASK;
     2137            break;
     2138        case SMBSHDWCMD_OFF:
     2139            /* readonly register */
     2140            break;
     2141        case SMBSLVEVT_OFF:
     2142            pThis->u16SMBusSlvEvt = u32;
     2143            break;
     2144        case SMBSLVDAT_OFF:
     2145            /* readonly register */
     2146            break;
     2147        default:
     2148            /* caught by the sanity check above */
     2149            ;
     2150    }
     2151
     2152    DEVACPI_UNLOCK(pThis);
     2153    return VINF_SUCCESS;
     2154}
     2155
     2156/**
     2157 * @callback_method_impl{FNIOMIOPORTIN, SMBus}
     2158 */
     2159PDMBOTHCBDECL(int) acpiR3SMBusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
     2160{
     2161    ACPIState *pThis = (ACPIState *)pvUser;
     2162    DEVACPI_LOCK_R3(pThis);
     2163
     2164    int rc = VINF_SUCCESS;
     2165    LogFunc(("Port=%#x cb=%u\n", Port, cb));
     2166    uint8_t off = Port & 0x000f;
     2167    if (   (cb != 1 && off <= SMBSHDWCMD_OFF)
     2168        || (cb != 2 && (off == SMBSLVEVT_OFF || off == SMBSLVDAT_OFF)))
     2169        return VERR_IOM_IOPORT_UNUSED;
     2170
     2171    switch (off)
     2172    {
     2173        case SMBHSTSTS_OFF:
     2174            *pu32 = pThis->u8SMBusHstSts;
     2175            break;
     2176        case SMBSLVSTS_OFF:
     2177            *pu32 = pThis->u8SMBusSlvSts;
     2178            break;
     2179        case SMBHSTCNT_OFF:
     2180            pThis->u8SMBusBlkIdx = 0;
     2181            *pu32 = pThis->u8SMBusHstCnt;
     2182            break;
     2183        case SMBHSTCMD_OFF:
     2184            *pu32 = pThis->u8SMBusHstCmd;
     2185            break;
     2186        case SMBHSTADD_OFF:
     2187            *pu32 = pThis->u8SMBusHstAdd;
     2188            break;
     2189        case SMBHSTDAT0_OFF:
     2190            *pu32 = pThis->u8SMBusHstDat0;
     2191            break;
     2192        case SMBHSTDAT1_OFF:
     2193            *pu32 = pThis->u8SMBusHstDat1;
     2194            break;
     2195        case SMBBLKDAT_OFF:
     2196            *pu32 = pThis->au8SMBusBlkDat[pThis->u8SMBusBlkIdx];
     2197            pThis->u8SMBusBlkIdx++;
     2198            pThis->u8SMBusBlkIdx &= sizeof(pThis->au8SMBusBlkDat) - 1;
     2199            break;
     2200        case SMBSLVCNT_OFF:
     2201            *pu32 = pThis->u8SMBusSlvCnt;
     2202            break;
     2203        case SMBSHDWCMD_OFF:
     2204            *pu32 = pThis->u8SMBusShdwCmd;
     2205            break;
     2206        case SMBSLVEVT_OFF:
     2207            *pu32 = pThis->u16SMBusSlvEvt;
     2208            break;
     2209        case SMBSLVDAT_OFF:
     2210            *pu32 = pThis->u16SMBusSlvDat;
     2211            break;
     2212        default:
     2213            /* caught by the sanity check above */
     2214            rc = VERR_IOM_IOPORT_UNUSED;
     2215    }
     2216
     2217    DEVACPI_UNLOCK(pThis);
     2218    LogFunc(("Port=%#x u32=%#x cb=%u rc=%Rrc\n", Port, *pu32, cb, rc));
     2219    return rc;
     2220}
     2221
     2222/**
     2223 * Called by acpiR3Reset and acpiR3Construct to set up the SMBus PCI config space.
     2224 *
     2225 * @param   pThis           The ACPI instance.
     2226 */
     2227static void acpiR3SMBusPCIBIOSFake(ACPIState *pThis)
     2228{
     2229    pThis->dev.config[SMBBA  ] = pThis->uSMBusIoPortBase | 1; /* SMBBA, SMBus base address, bit 0 marks it as IO range */
     2230    pThis->dev.config[SMBBA+1] = pThis->uSMBusIoPortBase >> 8;
     2231    pThis->dev.config[SMBBA+2] = 0x00;
     2232    pThis->dev.config[SMBBA+3] = 0x00;
     2233    pThis->dev.config[SMBHSTCFG] = SMBHSTCFG_INTRSEL_IRQ9 << SMBHSTCFG_INTRSEL_SHIFT | SMBHSTCFG_SMB_HST_EN; /* SMBHSTCFG */
     2234    pThis->dev.config[SMBSLVC] = 0x00; /* SMBSLVC */
     2235    pThis->dev.config[SMBSHDW1] = 0x00; /* SMBSHDW1 */
     2236    pThis->dev.config[SMBSHDW2] = 0x00; /* SMBSHDW2 */
     2237    pThis->dev.config[SMBREV] = 0x00; /* SMBREV */
     2238}
     2239
     2240/**
     2241 * Called by acpiR3LoadState, acpiR3Reset and acpiR3Construct to reset the SMBus device register state.
     2242 *
     2243 * @param   pThis           The ACPI instance.
     2244 */
     2245static void acpiR3SMBusResetDevice(ACPIState *pThis)
     2246{
     2247    pThis->u8SMBusHstSts = 0x00;
     2248    pThis->u8SMBusSlvSts = 0x00;
     2249    pThis->u8SMBusHstCnt = 0x00;
     2250    pThis->u8SMBusHstCmd = 0x00;
     2251    pThis->u8SMBusHstAdd = 0x00;
     2252    pThis->u8SMBusHstDat0 = 0x00;
     2253    pThis->u8SMBusHstDat1 = 0x00;
     2254    pThis->u8SMBusSlvCnt = 0x00;
     2255    pThis->u8SMBusShdwCmd = 0x00;
     2256    pThis->u16SMBusSlvEvt = 0x0000;
     2257    pThis->u16SMBusSlvDat = 0x0000;
     2258    memset(pThis->au8SMBusBlkDat, 0x00, sizeof(pThis->au8SMBusBlkDat));
     2259    pThis->u8SMBusBlkIdx = 0;
     2260}
     2261
     2262/**
     2263 * Called by acpiR3LoadState and acpiR3UpdateSMBusHandlers to register the SMBus ports.
     2264 *
     2265 * @returns VBox status code.
     2266 * @param   pThis           The ACPI instance.
     2267 */
     2268static int acpiR3RegisterSMBusHandlers(ACPIState *pThis)
     2269{
     2270    int   rc = VINF_SUCCESS;
     2271
     2272    if (pThis->uSMBusIoPortBase == 0)
     2273        return VINF_SUCCESS;
     2274
     2275    rc = PDMDevHlpIOPortRegister(pThis->pDevInsR3, pThis->uSMBusIoPortBase, 16, pThis, acpiR3SMBusWrite, acpiR3SMBusRead, NULL, NULL, "SMBus");
     2276    if (RT_FAILURE(rc))
     2277        return rc;
     2278
     2279    return VINF_SUCCESS;
     2280}
     2281
     2282/**
     2283 * Called by acpiR3LoadState and acpiR3UpdateSMBusHandlers to unregister the SMBus ports.
     2284 *
     2285 * @returns VBox status code.
     2286 * @param   pThis           The ACPI instance.
     2287 */
     2288static int acpiR3UnregisterSMBusHandlers(ACPIState *pThis)
     2289{
     2290    if (pThis->uSMBusIoPortBase == 0)
     2291        return VINF_SUCCESS;
     2292
     2293    int rc = PDMDevHlpIOPortDeregister(pThis->pDevInsR3, pThis->uSMBusIoPortBase, 16);
     2294    AssertRCReturn(rc, rc);
     2295
     2296    return VINF_SUCCESS;
     2297}
     2298
     2299/**
     2300 * Called by acpiR3PciConfigWrite and acpiReset to change the location of the
     2301 * SMBus ports.
     2302 *
     2303 * @returns VBox status code.
     2304 *
     2305 * @param   pThis           The ACPI instance.
     2306 * @param   NewIoPortBase   The new base address of the I/O ports.
     2307 */
     2308static int acpiR3UpdateSMBusHandlers(ACPIState *pThis, RTIOPORT NewIoPortBase)
     2309{
     2310    Log(("acpi: rebasing SMBus 0x%x -> 0x%x\n", pThis->uSMBusIoPortBase, NewIoPortBase));
     2311    if (NewIoPortBase != pThis->uSMBusIoPortBase)
     2312    {
     2313        int rc = acpiR3UnregisterSMBusHandlers(pThis);
     2314        if (RT_FAILURE(rc))
     2315            return rc;
     2316
     2317        pThis->uSMBusIoPortBase = NewIoPortBase;
     2318
     2319        rc = acpiR3RegisterSMBusHandlers(pThis);
     2320        if (RT_FAILURE(rc))
     2321            return rc;
     2322
     2323#if 0 /* is there an FADT table entry for the SMBus base? */
     2324        /* We have to update FADT table acccording to the new base */
     2325        rc = acpiR3PlantTables(pThis);
     2326        AssertRC(rc);
     2327        if (RT_FAILURE(rc))
     2328            return rc;
     2329#endif
    19482330    }
    19492331
     
    20332415
    20342416/**
     2417 * Saved state structure description, version 8.
     2418 */
     2419static const SSMFIELD g_AcpiSavedStateFields8[] =
     2420{
     2421    SSMFIELD_ENTRY(ACPIState, pm1a_en),
     2422    SSMFIELD_ENTRY(ACPIState, pm1a_sts),
     2423    SSMFIELD_ENTRY(ACPIState, pm1a_ctl),
     2424    SSMFIELD_ENTRY(ACPIState, u64PmTimerInitial),
     2425    SSMFIELD_ENTRY(ACPIState, uPmTimerVal),
     2426    SSMFIELD_ENTRY(ACPIState, gpe0_en),
     2427    SSMFIELD_ENTRY(ACPIState, gpe0_sts),
     2428    SSMFIELD_ENTRY(ACPIState, uBatteryIndex),
     2429    SSMFIELD_ENTRY(ACPIState, uSystemInfoIndex),
     2430    SSMFIELD_ENTRY(ACPIState, uSleepState),
     2431    SSMFIELD_ENTRY(ACPIState, u8IndexShift),
     2432    SSMFIELD_ENTRY(ACPIState, uPmIoPortBase),
     2433    SSMFIELD_ENTRY(ACPIState, fSuspendToSavedState),
     2434    SSMFIELD_ENTRY(ACPIState, uSMBusIoPortBase),
     2435    SSMFIELD_ENTRY(ACPIState, u8SMBusHstSts),
     2436    SSMFIELD_ENTRY(ACPIState, u8SMBusSlvSts),
     2437    SSMFIELD_ENTRY(ACPIState, u8SMBusHstCnt),
     2438    SSMFIELD_ENTRY(ACPIState, u8SMBusHstCmd),
     2439    SSMFIELD_ENTRY(ACPIState, u8SMBusHstAdd),
     2440    SSMFIELD_ENTRY(ACPIState, u8SMBusHstDat0),
     2441    SSMFIELD_ENTRY(ACPIState, u8SMBusHstDat1),
     2442    SSMFIELD_ENTRY(ACPIState, u8SMBusSlvCnt),
     2443    SSMFIELD_ENTRY(ACPIState, u8SMBusShdwCmd),
     2444    SSMFIELD_ENTRY(ACPIState, u16SMBusSlvEvt),
     2445    SSMFIELD_ENTRY(ACPIState, u16SMBusSlvDat),
     2446    SSMFIELD_ENTRY(ACPIState, au8SMBusBlkDat),
     2447    SSMFIELD_ENTRY(ACPIState, u8SMBusBlkIdx),
     2448    SSMFIELD_ENTRY_TERM()
     2449};
     2450
     2451/**
    20352452 * @callback_method_impl{FNSSMDEVSAVEEXEC}
    20362453 */
     
    20382455{
    20392456    ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
    2040     return SSMR3PutStruct(pSSM, pThis, &g_AcpiSavedStateFields7[0]);
     2457    return SSMR3PutStruct(pSSM, pThis, &g_AcpiSavedStateFields8[0]);
    20412458}
    20422459
     
    20572474        return rc;
    20582475
     2476    /*
     2477     * Unregister SMBus handlers, will register with actual base after state
     2478     * successfully loaded.
     2479     */
     2480    rc = acpiR3UnregisterSMBusHandlers(pThis);
     2481    if (RT_FAILURE(rc))
     2482        return rc;
     2483    acpiR3SMBusResetDevice(pThis);
     2484
    20592485    switch (uVersion)
    20602486    {
     
    20712497            rc = SSMR3GetStruct(pSSM, pThis, &g_AcpiSavedStateFields7[0]);
    20722498            break;
     2499        case 8:
     2500            rc = SSMR3GetStruct(pSSM, pThis, &g_AcpiSavedStateFields8[0]);
     2501            break;
    20732502        default:
    20742503            rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
     
    20782507    {
    20792508        rc = acpiR3RegisterPmHandlers(pThis);
     2509        if (RT_FAILURE(rc))
     2510            return rc;
     2511        rc = acpiR3RegisterSMBusHandlers(pThis);
    20802512        if (RT_FAILURE(rc))
    20812513            return rc;
     
    28613293    pThis->pfnAcpiPciConfigWrite(pPciDev, Address, u32Value, cb);
    28623294
    2863     /* PMREGMISC written */
    2864     if (Address == 0x80)
    2865     {
     3295    /* Assume that the base address is only changed when the corresponding
     3296     * hardware functionality is disabled. The IO region is mapped when the
     3297     * functionality is enabled by the guest. */
     3298
     3299    if (Address == PMREGMISC)
     3300    {
     3301        RTIOPORT NewIoPortBase = 0;
    28663302        /* Check Power Management IO Space Enable (PMIOSE) bit */
    2867         if (pPciDev->config[0x80] & 0x1)
     3303        if (pPciDev->config[PMREGMISC] & 0x01)
    28683304        {
    2869             RTIOPORT NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, 0x40);
     3305            NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, PMBA);
    28703306            NewIoPortBase &= 0xffc0;
    2871 
    2872             int rc = acpiR3UpdatePmHandlers(pThis, NewIoPortBase);
    2873             AssertRC(rc);
    28743307        }
     3308
     3309        int rc = acpiR3UpdatePmHandlers(pThis, NewIoPortBase);
     3310        AssertRC(rc);
     3311    }
     3312
     3313    if (Address == SMBHSTCFG)
     3314    {
     3315        RTIOPORT NewIoPortBase = 0;
     3316        /* Check SMBus Controller Host Interface Enable (SMB_HST_EN) bit */
     3317        if (pPciDev->config[SMBHSTCFG] & SMBHSTCFG_SMB_HST_EN)
     3318        {
     3319            NewIoPortBase = (RTIOPORT)PCIDevGetDWord(pPciDev, SMBBA);
     3320            NewIoPortBase &= 0xfff0;
     3321        }
     3322
     3323        int rc = acpiR3UpdateSMBusHandlers(pThis, NewIoPortBase);
     3324        AssertRC(rc);
    28753325    }
    28763326
     
    29913441{
    29923442    ACPIState *pThis = PDMINS_2_DATA(pDevIns, ACPIState *);
     3443
     3444    /* Play safe: make sure that the IRQ isn't stuck after a reset. */
     3445    acpiSetIrq(pThis, 0);
    29933446
    29943447    TMTimerLock(pThis->pPmTimerR3, VERR_IGNORED);
     
    30063459    TMTimerUnlock(pThis->pPmTimerR3);
    30073460
    3008     /** @todo Should we really reset PM base? */
     3461    /* Real device behavior is resetting only the PM controller state,
     3462     * but we're additionally doing the job of the BIOS. */
    30093463    acpiR3UpdatePmHandlers(pThis, PM_PORT_BASE);
     3464    acpiR3PmPCIBIOSFake(pThis);
     3465
     3466    /* Reset SMBus base and PCI config space in addition to the SMBus controller
     3467     * state. Real device behavior is only the SMBus controller state reset,
     3468     * but we're additionally doing the job of the BIOS. */
     3469    acpiR3UpdateSMBusHandlers(pThis, SMB_PORT_BASE);
     3470    acpiR3SMBusPCIBIOSFake(pThis);
     3471    acpiR3SMBusResetDevice(pThis);
    30103472}
    30113473
     
    34433905    }
    34443906
    3445     /* Set default port base */
     3907    /* Set default PM port base */
    34463908    pThis->uPmIoPortBase = PM_PORT_BASE;
     3909
     3910    /* Set default SMBus port base */
     3911    pThis->uSMBusIoPortBase = SMB_PORT_BASE;
    34473912
    34483913    /*
     
    34773942     */
    34783943    rc = acpiR3RegisterPmHandlers(pThis);
     3944    if (RT_FAILURE(rc))
     3945        return rc;
     3946
     3947    rc = acpiR3RegisterSMBusHandlers(pThis);
    34793948    if (RT_FAILURE(rc))
    34803949        return rc;
     
    35394008    PCIDevSetInterruptPin (&pThis->dev, 0x01);
    35404009
    3541     pThis->dev.config[0x40] = 0x01; /* PM base address, this bit marks it as IO range, not PA */
    3542 
    3543 #if 0
    3544     int smb_io_base = 0xb100;
    3545     dev->config[0x90] = smb_io_base | 1; /* SMBus base address */
    3546     dev->config[0x90] = smb_io_base >> 8;
    3547 #endif
     4010    Assert((pThis->uPmIoPortBase & 0x003f) == 0);
     4011    acpiR3PmPCIBIOSFake(pThis);
     4012
     4013    Assert((pThis->uSMBusIoPortBase & 0x000f) == 0);
     4014    acpiR3SMBusPCIBIOSFake(pThis);
     4015    acpiR3SMBusResetDevice(pThis);
    35484016
    35494017    rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
     
    35584026     * Register the saved state.
    35594027     */
    3560     rc = PDMDevHlpSSMRegister(pDevIns, 7, sizeof(*pThis), acpiR3SaveState, acpiR3LoadState);
     4028    rc = PDMDevHlpSSMRegister(pDevIns, 8, sizeof(*pThis), acpiR3SaveState, acpiR3LoadState);
    35614029    if (RT_FAILURE(rc))
    35624030        return rc;
Note: See TracChangeset for help on using the changeset viewer.

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