Skip to content

Commit

Permalink
intpm: use MMIO for AMD EFCH CPUs
Browse files Browse the repository at this point in the history
Recent AMD CPUs (SMBus PCI revision ID >= 0x51) can disable port-mapped
IO and only support memory-mapped IO. In practice this was observed on a
Zen 3 CPU where PMIO reads all returned 0xff. Update the driver to use
MMIO for these processors while continuing to use PMIO by default.
  • Loading branch information
brian90013 committed Oct 7, 2024
1 parent a3d5dec commit bb5606b
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 11 deletions.
2 changes: 2 additions & 0 deletions sys/dev/amdsbwd/amd_chipset.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
*/
#define AMDFCH41_WDT_FIXED_ADDR 0xfeb00000u
#define AMDFCH41_MMIO_ADDR 0xfed80000u
#define AMDFCH41_MMIO_PM_OFF 0x0300
#define AMDFCH41_MMIO_SMBUS_OFF 0x0a00
#define AMDFCH41_MMIO_WDT_OFF 0x0b00

Expand All @@ -143,5 +144,6 @@
#define AMDFCH41_SMBUS_REVID 0x41
#define AMDCZ_SMBUS_DEVID 0x790b1022
#define AMDCZ49_SMBUS_REVID 0x49
#define AMDCZ51_SMBUS_REVID 0x51

#define HYGONCZ_SMBUS_DEVID 0x790b1d94
44 changes: 33 additions & 11 deletions sys/dev/intpm/intpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct intsmb_softc {
int cfg_irq9;
int sb8xx;
int poll;
int type;
struct mtx lock;
};

Expand Down Expand Up @@ -135,28 +136,44 @@ sb8xx_attach(device_t dev)
struct resource *res;
uint32_t devid;
uint8_t revid;
uint16_t addr;
uint32_t addr;
int rid;
int rc;
bool enabled;

sc = device_get_softc(dev);
devid = pci_get_devid(dev);
revid = pci_get_revid(dev);

/*
* Comment from Linux i2c-piix4.c:
*
* cd6h/cd7h port I/O accesses can be disabled on AMD processors
* w/ SMBus PCI revision ID 0x51 or greater. MMIO is supported on
* the same processors and is the recommended access method.
*/
if (devid == AMDCZ_SMBUS_DEVID && revid >= AMDCZ51_SMBUS_REVID) {
sc->type = SYS_RES_MEMORY;
addr = AMDFCH41_MMIO_ADDR + AMDFCH41_MMIO_PM_OFF;
} else {
sc->type = SYS_RES_IOPORT;
addr = AMDSB_PMIO_INDEX;
}

rid = 0;
rc = bus_set_resource(dev, SYS_RES_IOPORT, rid, AMDSB_PMIO_INDEX,
rc = bus_set_resource(dev, sc->type, rid, addr,
AMDSB_PMIO_WIDTH);
if (rc != 0) {
device_printf(dev, "bus_set_resource for PM IO failed\n");
return (ENXIO);
}
res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
res = bus_alloc_resource_any(dev, sc->type, &rid,
RF_ACTIVE);
if (res == NULL) {
device_printf(dev, "bus_alloc_resource for PM IO failed\n");
return (ENXIO);
}

devid = pci_get_devid(dev);
revid = pci_get_revid(dev);
if (devid == AMDSB_SMBUS_DEVID ||
(devid == AMDFCH_SMBUS_DEVID && revid < AMDFCH41_SMBUS_REVID) ||
(devid == AMDCZ_SMBUS_DEVID && revid < AMDCZ49_SMBUS_REVID)) {
Expand All @@ -165,29 +182,33 @@ sb8xx_attach(device_t dev)
addr |= amd_pmio_read(res, AMDSB8_PM_SMBUS_EN);
enabled = (addr & AMDSB8_SMBUS_EN) != 0;
addr &= AMDSB8_SMBUS_ADDR_MASK;
} else if (devid == AMDCZ_SMBUS_DEVID && revid >= AMDCZ51_SMBUS_REVID) {
addr = bus_read_1(res, AMDFCH41_PM_DECODE_EN0);
enabled = (addr & AMDFCH41_SMBUS_EN) != 0;
addr = AMDFCH41_MMIO_ADDR + AMDFCH41_MMIO_SMBUS_OFF;
} else {
addr = amd_pmio_read(res, AMDFCH41_PM_DECODE_EN0);
enabled = (addr & AMDFCH41_SMBUS_EN) != 0;
addr = amd_pmio_read(res, AMDFCH41_PM_DECODE_EN1);
addr <<= 8;
}

bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
bus_delete_resource(dev, SYS_RES_IOPORT, rid);
bus_release_resource(dev, sc->type, rid, res);
bus_delete_resource(dev, sc->type, rid);

if (!enabled) {
device_printf(dev, "SB8xx/SB9xx/FCH SMBus not enabled\n");
return (ENXIO);
}

sc->io_rid = 0;
rc = bus_set_resource(dev, SYS_RES_IOPORT, sc->io_rid, addr,
rc = bus_set_resource(dev, sc->type, sc->io_rid, addr,
AMDSB_SMBIO_WIDTH);
if (rc != 0) {
device_printf(dev, "bus_set_resource for SMBus IO failed\n");
return (ENXIO);
}
sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid,
sc->io_res = bus_alloc_resource_any(dev, sc->type, &sc->io_rid,
RF_ACTIVE);
if (sc->io_res == NULL) {
device_printf(dev, "Could not allocate I/O space\n");
Expand All @@ -209,7 +230,7 @@ intsmb_release_resources(device_t dev)
if (sc->irq_res)
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
if (sc->io_res)
bus_release_resource(dev, SYS_RES_IOPORT, sc->io_rid,
bus_release_resource(dev, sc->type, sc->io_rid,
sc->io_res);
mtx_destroy(&sc->lock);
}
Expand All @@ -227,6 +248,7 @@ intsmb_attach(device_t dev)
mtx_init(&sc->lock, device_get_nameunit(dev), "intsmb", MTX_DEF);

sc->cfg_irq9 = 0;
sc->type = SYS_RES_IOPORT;
switch (pci_get_devid(dev)) {
#ifndef NO_CHANGE_PCICONF
case 0x71138086: /* Intel 82371AB */
Expand Down Expand Up @@ -255,7 +277,7 @@ intsmb_attach(device_t dev)
}

sc->io_rid = PCI_BASE_ADDR_SMB;
sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid,
sc->io_res = bus_alloc_resource_any(dev, sc->type, &sc->io_rid,
RF_ACTIVE);
if (sc->io_res == NULL) {
device_printf(dev, "Could not allocate I/O space\n");
Expand Down

0 comments on commit bb5606b

Please sign in to comment.