Module Name: src Committed By: martin Date: Mon Jan 23 16:02:49 UTC 2023
Modified Files: src/sys/dev/pci [netbsd-10]: piixpm.c piixpmreg.h Log Message: Pull up following revision(s) (requested by msaitoh in ticket #55): sys/dev/pci/piixpm.c: revision 1.68 sys/dev/pci/piixpm.c: revision 1.69 sys/dev/pci/piixpmreg.h: revision 1.13 sys/dev/pci/piixpm.c: revision 1.70 sys/dev/pci/piixpm.c: revision 1.71 sys/dev/pci/piixpm.c: revision 1.72 Modify comment. Whitespace. No functional change. Simplify and modify for following MMIO support. No functional change. Modify for following MMIO support. No functional change. Use MMIO for PM register access on newer revision's devices. Newer revision's device only support memory mapped access. At least, X670E's SMBus device that the revision ID is 0x71 doesn't support I/O access. Use MMIO access for newer devices. Linux uses >= 0x51 for the check, so we do the same check. Note that X570's SMBus(rev. 0x61) supports I/O access... Modify error message to match the current behavior. To generate a diff of this commit: cvs rdiff -u -r1.67 -r1.67.4.1 src/sys/dev/pci/piixpm.c cvs rdiff -u -r1.12 -r1.12.24.1 src/sys/dev/pci/piixpmreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/piixpm.c diff -u src/sys/dev/pci/piixpm.c:1.67 src/sys/dev/pci/piixpm.c:1.67.4.1 --- src/sys/dev/pci/piixpm.c:1.67 Fri Apr 1 15:34:34 2022 +++ src/sys/dev/pci/piixpm.c Mon Jan 23 16:02:49 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: piixpm.c,v 1.67 2022/04/01 15:34:34 pgoyette Exp $ */ +/* $NetBSD: piixpm.c,v 1.67.4.1 2023/01/23 16:02:49 martin Exp $ */ /* $OpenBSD: piixpm.c,v 1.39 2013/10/01 20:06:02 sf Exp $ */ /* @@ -22,7 +22,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.67 2022/04/01 15:34:34 pgoyette Exp $"); +__KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.67.4.1 2023/01/23 16:02:49 martin Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -52,7 +52,7 @@ __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1 #define PIIXPM_IS_CSB5(sc) \ (PCI_VENDOR((sc)->sc_id) == PCI_VENDOR_SERVERWORKS && \ - PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_SERVERWORKS_CSB5) + PCI_PRODUCT((sc)->sc_id) == PCI_PRODUCT_SERVERWORKS_CSB5) #define PIIXPM_DELAY 200 #define PIIXPM_TIMEOUT 1 @@ -76,20 +76,20 @@ __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1 struct piixpm_smbus { int sda; int sda_save; - struct piixpm_softc *softc; + struct piixpm_softc *softc; }; struct piixpm_softc { device_t sc_dev; bus_space_tag_t sc_iot; -#define sc_pm_iot sc_iot -#define sc_smb_iot sc_iot + bus_space_tag_t sc_sb800_bt; bus_space_handle_t sc_pm_ioh; - bus_space_handle_t sc_sb800_ioh; + bus_space_handle_t sc_sb800_bh; bus_space_handle_t sc_smb_ioh; void * sc_smb_ih; int sc_poll; + bool sc_sb800_mmio; /* Use MMIO access */ bool sc_sb800_selen; /* Use SMBUS0SEL */ pci_chipset_tag_t sc_pc; @@ -125,6 +125,7 @@ static void piixpm_chdet(device_t, devic static bool piixpm_suspend(device_t, const pmf_qual_t *); static bool piixpm_resume(device_t, const pmf_qual_t *); +static uint8_t piixpm_sb800_pmread(struct piixpm_softc *, bus_size_t); static int piixpm_sb800_init(struct piixpm_softc *); static void piixpm_csb5_reset(void *); static int piixpm_i2c_sb800_acquire_bus(void *, int); @@ -222,7 +223,7 @@ piixpm_attach(device_t parent, device_t /* Map I/O space */ base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PM_BASE); - if (base == 0 || bus_space_map(sc->sc_pm_iot, PCI_MAPREG_IO_ADDR(base), + if (base == 0 || bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base), PIIX_PM_SIZE, 0, &sc->sc_pm_ioh)) { aprint_error_dev(self, "can't map power management I/O space\n"); @@ -234,13 +235,22 @@ piixpm_attach(device_t parent, device_t * PIIX4 and PIIX4E have a bug in the timer latch, see Errata #20 * in the "Specification update" (document #297738). */ - acpipmtimer_attach(self, sc->sc_pm_iot, sc->sc_pm_ioh, PIIX_PM_PMTMR, + acpipmtimer_attach(self, sc->sc_iot, sc->sc_pm_ioh, PIIX_PM_PMTMR, (PCI_REVISION(pa->pa_class) < 3) ? ACPIPMT_BADLATCH : 0); nopowermanagement: /* SB800 rev 0x40+, AMD HUDSON and newer need special initialization */ if (PIIXPM_IS_FCHGRP(sc) || PIIXPM_IS_SB800GRP(sc)) { + /* Newer chips don't support I/O access */ + if (PIIXPM_IS_KERNCZ(sc) && (sc->sc_rev >= 0x51)) { + sc->sc_sb800_mmio = true; + sc->sc_sb800_bt = pa->pa_memt; + } else { + sc->sc_sb800_mmio = false; + sc->sc_sb800_bt = pa->pa_iot; + } + if (piixpm_sb800_init(sc) == 0) { /* Read configuration */ conf = bus_space_read_1(sc->sc_iot, @@ -265,7 +275,7 @@ nopowermanagement: /* Map I/O space */ base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) & 0xffff; if (base == 0 || - bus_space_map(sc->sc_smb_iot, PCI_MAPREG_IO_ADDR(base), + bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base), PIIX_SMB_SIZE, 0, &sc->sc_smb_ioh)) { aprint_error_dev(self, "can't map smbus I/O space\n"); return; @@ -404,18 +414,37 @@ piixpm_resume(device_t dv, const pmf_qua return true; } +static uint8_t +piixpm_sb800_pmread(struct piixpm_softc *sc, bus_size_t offset) +{ + bus_space_tag_t sbt = sc->sc_sb800_bt; + bus_space_handle_t sbh = sc->sc_sb800_bh; + uint8_t val; + + if (sc->sc_sb800_mmio) + val = bus_space_read_1(sbt, sbh, offset); + else { + bus_space_write_1(sbt, sbh, SB800_INDIRECTIO_INDEX, offset); + val = bus_space_read_1(sbt, sbh, SB800_INDIRECTIO_DATA); + } + + return val; +} + /* * Extract SMBus base address from SB800 Power Management (PM) registers. * The PM registers can be accessed either through indirect I/O (CD6/CD7) or - * direct mapping if AcpiMMioDecodeEn is enabled. Since this function is only - * called once it uses indirect I/O for simplicity. + * direct mapping if AcpiMMioDecodeEn is enabled. Newer devices support MMIO + * access only. */ static int piixpm_sb800_init(struct piixpm_softc *sc) { - bus_space_tag_t iot = sc->sc_iot; - bus_space_handle_t ioh; /* indirect I/O handle */ - uint16_t val, base_addr; + bus_space_tag_t sbt = sc->sc_sb800_bt; + bus_space_handle_t sbh; /* indirect memory or I/O handle */ + int rv; + uint16_t base_addr; + uint8_t lo, hi; bool enabled; if (PIIXPM_IS_KERNCZ(sc) || @@ -424,50 +453,48 @@ piixpm_sb800_init(struct piixpm_softc *s else sc->sc_numbusses = 4; - /* Fetch SMB base address */ - if (bus_space_map(iot, - SB800_INDIRECTIO_BASE, SB800_INDIRECTIO_SIZE, 0, &ioh)) { - device_printf(sc->sc_dev, "couldn't map indirect I/O space\n"); + /* Check SMBus enable bit and Fetch SMB base address */ + if (sc->sc_sb800_mmio) + rv = bus_space_map(sbt, SB800_FCH_PM_BASE, + SB800_FCH_PM_SIZE, 0, &sbh); + else + rv = bus_space_map(sbt, SB800_INDIRECTIO_BASE, + SB800_INDIRECTIO_SIZE, 0, &sbh); + if (rv != 0) { + device_printf(sc->sc_dev, "couldn't map indirect space\n"); return EBUSY; } + sc->sc_sb800_bh = sbh; if (PIIXPM_IS_FCHGRP(sc)) { - bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, - AMDFCH41_PM_DECODE_EN0); - val = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA); - enabled = val & AMDFCH41_SMBUS_EN; + lo = piixpm_sb800_pmread(sc, AMDFCH41_PM_DECODE_EN0); + enabled = lo & AMDFCH41_SMBUS_EN; if (!enabled) return ENOENT; - bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, - AMDFCH41_PM_DECODE_EN1); - val = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA) << 8; - base_addr = val; + hi = piixpm_sb800_pmread(sc, AMDFCH41_PM_DECODE_EN1); + base_addr = (uint16_t)hi << 8; } else { uint8_t data; - bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, - SB800_PM_SMBUS0EN_LO); - val = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA); - enabled = val & SB800_PM_SMBUS0EN_ENABLE; + lo = piixpm_sb800_pmread(sc, SB800_PM_SMBUS0EN_LO); + enabled = lo & SB800_PM_SMBUS0EN_ENABLE; if (!enabled) return ENOENT; - bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, - SB800_PM_SMBUS0EN_HI); - val |= bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA) << 8; - base_addr = val & SB800_PM_SMBUS0EN_BADDR; + hi = piixpm_sb800_pmread(sc, SB800_PM_SMBUS0EN_HI); + base_addr = ((uint16_t)hi << 8) & SB800_PM_SMBUS0EN_BADDR; - bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, + bus_space_write_1(sbt, sbh, SB800_INDIRECTIO_INDEX, SB800_PM_SMBUS0SELEN); - data = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA); + data = bus_space_read_1(sbt, sbh, SB800_INDIRECTIO_DATA); if ((data & SB800_PM_USE_SMBUS0SEL) != 0) sc->sc_sb800_selen = true; } - sc->sc_sb800_ioh = ioh; - aprint_debug_dev(sc->sc_dev, "SMBus @ 0x%04x\n", base_addr); + aprint_debug_dev(sc->sc_dev, "SMBus %s access @ 0x%04x\n", + sc->sc_sb800_mmio ? "memory" : "I/O", base_addr); - if (bus_space_map(iot, PCI_MAPREG_IO_ADDR(base_addr), + if (bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base_addr), SB800_SMB_SIZE, 0, &sc->sc_smb_ioh)) { aprint_error_dev(sc->sc_dev, "can't map smbus I/O space\n"); return EBUSY; @@ -505,14 +532,14 @@ piixpm_i2c_sb800_acquire_bus(void *cooki uint8_t sctl, old_sda, index, mask, reg; int i; - sctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_SC); + sctl = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC); for (i = 0; i < PIIX_SB800_TIMEOUT; i++) { /* Try to acquire the host semaphore */ sctl &= ~PIIX_SMB_SC_SEMMASK; - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_SC, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC, sctl | PIIX_SMB_SC_HOSTSEM); - sctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, + sctl = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC); if ((sctl & PIIX_SMB_SC_HOSTSEM) != 0) break; @@ -537,17 +564,18 @@ piixpm_i2c_sb800_acquire_bus(void *cooki mask = SB800_PM_SMBUS0_MASK_C; } - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_INDEX, index); - reg = bus_space_read_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_DATA); + reg = piixpm_sb800_pmread(sc, index); old_sda = __SHIFTOUT(reg, mask); if (smbus->sda != old_sda) { reg &= ~mask; reg |= __SHIFTIN(smbus->sda, mask); - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_DATA, reg); + /* + * SB800_INDIRECTIO_INDEX is already set on I/O access, + * so it's not required to write it again. + */ + bus_space_write_1(sc->sc_sb800_bt, sc->sc_sb800_bh, + sc->sc_sb800_mmio ? index : SB800_INDIRECTIO_DATA, reg); } /* Save the old port number */ @@ -575,22 +603,23 @@ piixpm_i2c_sb800_release_bus(void *cooki mask = SB800_PM_SMBUS0_MASK_C; } - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_INDEX, index); if (smbus->sda != smbus->sda_save) { /* Restore the port number */ - reg = bus_space_read_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_DATA); + reg = piixpm_sb800_pmread(sc, index); reg &= ~mask; reg |= __SHIFTIN(smbus->sda_save, mask); - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_DATA, reg); + /* + * SB800_INDIRECTIO_INDEX is already set on I/O access, + * so it's not required to write it again. + */ + bus_space_write_1(sc->sc_sb800_bt, sc->sc_sb800_bh, + sc->sc_sb800_mmio ? index : SB800_INDIRECTIO_DATA, reg); } /* Release the host semaphore */ - sctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_SC); + sctl = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC); sctl &= ~PIIX_SMB_SC_SEMMASK; - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_SC, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_SC, sctl | PIIX_SMB_SC_CLRHOSTSEM); } @@ -611,15 +640,15 @@ piixpm_i2c_exec(void *cookie, i2c_op_t o mutex_enter(&sc->sc_exec_lock); /* Clear status bits */ - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, PIIX_SMB_HS_INTR | PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | PIIX_SMB_HS_FAILED); - bus_space_barrier(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, 1, + bus_space_barrier(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); /* Wait for bus to be idle */ for (retries = 100; retries > 0; retries--) { - st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, + st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if (!(st & PIIX_SMB_HS_BUSY)) break; @@ -649,27 +678,27 @@ piixpm_i2c_exec(void *cookie, i2c_op_t o sc->sc_i2c_xfer.done = false; /* Set slave address and transfer direction */ - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_TXSLVA, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_TXSLVA, PIIX_SMB_TXSLVA_ADDR(addr) | (I2C_OP_READ_P(op) ? PIIX_SMB_TXSLVA_READ : 0)); b = cmdbuf; if (cmdlen > 0) /* Set command byte */ - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HCMD, b[0]); if (I2C_OP_WRITE_P(op)) { /* Write data */ b = buf; if (cmdlen == 0 && len == 1) - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HCMD, b[0]); else if (len > 0) - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HD0, b[0]); if (len > 1) - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HD1, b[1]); } @@ -691,7 +720,7 @@ piixpm_i2c_exec(void *cookie, i2c_op_t o /* Start transaction */ ctl |= PIIX_SMB_HC_START; - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HC, ctl); + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HC, ctl); if (flags & I2C_F_POLL) { /* Poll for completion */ @@ -700,7 +729,7 @@ piixpm_i2c_exec(void *cookie, i2c_op_t o else DELAY(PIIXPM_DELAY); for (retries = 1000; retries > 0; retries--) { - st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, + st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if ((st & PIIX_SMB_HS_BUSY) == 0) break; @@ -728,14 +757,14 @@ timeout: * Transfer timeout. Kill the transaction and clear status bits. */ aprint_error_dev(sc->sc_dev, "timeout, status 0x%x\n", st); - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HC, + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HC, PIIX_SMB_HC_KILL); DELAY(PIIXPM_DELAY); - st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS); + st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if ((st & PIIX_SMB_HS_FAILED) == 0) aprint_error_dev(sc->sc_dev, "transaction abort failed, status 0x%x\n", st); - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); /* * CSB5 needs hard reset to unlock the smbus after timeout. */ @@ -754,7 +783,7 @@ piixpm_intr(void *arg) size_t len; /* Read status */ - st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS); + st = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS); if ((st & PIIX_SMB_HS_BUSY) != 0 || (st & (PIIX_SMB_HS_INTR | PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | PIIX_SMB_HS_FAILED)) == 0) @@ -767,7 +796,7 @@ piixpm_intr(void *arg) mutex_enter(&sc->sc_exec_lock); /* Clear status bits */ - bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); + bus_space_write_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st); /* Check for errors */ if (st & (PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR | @@ -784,10 +813,10 @@ piixpm_intr(void *arg) b = sc->sc_i2c_xfer.buf; len = sc->sc_i2c_xfer.len; if (len > 0) - b[0] = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, + b[0] = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HD0); if (len > 1) - b[1] = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, + b[1] = bus_space_read_1(sc->sc_iot, sc->sc_smb_ioh, PIIX_SMB_HD1); } Index: src/sys/dev/pci/piixpmreg.h diff -u src/sys/dev/pci/piixpmreg.h:1.12 src/sys/dev/pci/piixpmreg.h:1.12.24.1 --- src/sys/dev/pci/piixpmreg.h:1.12 Tue Jan 14 22:55:27 2020 +++ src/sys/dev/pci/piixpmreg.h Mon Jan 23 16:02:49 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: piixpmreg.h,v 1.12 2020/01/14 22:55:27 msaitoh Exp $ */ +/* $NetBSD: piixpmreg.h,v 1.12.24.1 2023/01/23 16:02:49 martin Exp $ */ /* $OpenBSD: piixreg.h,v 1.3 2006/01/03 22:39:03 grange Exp $ */ /*- @@ -119,6 +119,10 @@ #define SB800_INDIRECTIO_INDEX 0 #define SB800_INDIRECTIO_DATA 1 +/* In the MMIO area */ +#define SB800_FCH_PM_BASE 0xfed80300 +#define SB800_FCH_PM_SIZE 8 + #define SB800_PM_SMBUS0EN_LO 0x2c #define SB800_PM_SMBUS0EN_HI 0x2d #define SB800_PM_SMBUS0EN_ENABLE __BIT(0) /* Function enable */