Module Name: src Committed By: martin Date: Wed Aug 5 16:11:56 UTC 2020
Modified Files: src/sys/dev/pci [netbsd-8]: piixpm.c piixpmreg.h Log Message: Pull up the following revisions, requested by msaitoh in ticket #1591: sys/dev/pci/piixpm.c 1.57-1.59, 1.61-1.63 via patch sys/dev/pci/piixpmreg.h 1.9-1.12 - Fix number of port for Hudson rev. 0x1f and newer. - Read SB800_SMB_HOSTC correctly. This register is not in the PCI config space but in the I/O space. - The bit 0 of SB800_SMB_HOSTC is 0 on SMI or 1 on IRQ, so invert the check. - Don't force using SMBUS0SEL register. - Acquire/release host semaphore to share SMBus between the host and the embedded controller (IMC). Without this change, "shutdown -r" does power off and not boot on some machines. - Save/restore port number before selecting port. - Modify comment. - Whitespace fix. To generate a diff of this commit: cvs rdiff -u -r1.52.6.1 -r1.52.6.2 src/sys/dev/pci/piixpm.c cvs rdiff -u -r1.7.22.1 -r1.7.22.2 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.52.6.1 src/sys/dev/pci/piixpm.c:1.52.6.2 --- src/sys/dev/pci/piixpm.c:1.52.6.1 Tue Aug 6 16:02:54 2019 +++ src/sys/dev/pci/piixpm.c Wed Aug 5 16:11:56 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: piixpm.c,v 1.52.6.1 2019/08/06 16:02:54 martin Exp $ */ +/* $NetBSD: piixpm.c,v 1.52.6.2 2020/08/05 16:11:56 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.52.6.1 2019/08/06 16:02:54 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.52.6.2 2020/08/05 16:11:56 martin Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -70,8 +70,11 @@ __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1 #define PIIXPM_IS_FCHGRP(sc) (PIIXPM_IS_HUDSON(sc) || PIIXPM_IS_KERNCZ(sc)) +#define PIIX_SB800_TIMEOUT 500 + struct piixpm_smbus { int sda; + int sda_save; struct piixpm_softc *softc; }; @@ -86,6 +89,7 @@ struct piixpm_softc { bus_space_handle_t sc_smb_ioh; void * sc_smb_ih; int sc_poll; + bool sc_sb800_selen; /* Use SMBUS0SEL */ pci_chipset_tag_t sc_pc; pcitag_t sc_pcitag; @@ -119,8 +123,8 @@ static bool piixpm_resume(device_t, cons static int piixpm_sb800_init(struct piixpm_softc *); static void piixpm_csb5_reset(void *); -static int piixpm_i2c_acquire_bus(void *, int); -static void piixpm_i2c_release_bus(void *, int); +static int piixpm_i2c_sb800_acquire_bus(void *, int); +static void piixpm_i2c_sb800_release_bus(void *, int); static int piixpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, void *, size_t, int); @@ -231,15 +235,10 @@ nopowermanagement: /* SB800 rev 0x40+, AMD HUDSON and newer need special initialization */ if (PIIXPM_IS_FCHGRP(sc) || PIIXPM_IS_SB800GRP(sc)) { if (piixpm_sb800_init(sc) == 0) { - sc->sc_numbusses = 4; - /* Read configuration */ - conf = pci_conf_read(pa->pa_pc, pa->pa_tag, - SB800_SMB_HOSTC); - DPRINTF(("%s: conf 0x%08x\n", device_xname(self), - conf)); - - usesmi = conf & SB800_SMB_HOSTC_SMI; + conf = bus_space_read_1(sc->sc_iot, + sc->sc_smb_ioh, SB800_SMB_HOSTC); + usesmi = ((conf & SB800_SMB_HOSTC_IRQ) == 0); goto setintr; } aprint_normal_dev(self, "SMBus initialization failed\n"); @@ -328,17 +327,24 @@ piixpm_rescan(device_t self, const char /* Attach I2C bus */ for (i = 0; i < sc->sc_numbusses; i++) { + struct i2c_controller *tag = &sc->sc_i2c_tags[i]; + if (sc->sc_i2c_device[i]) continue; sc->sc_busses[i].sda = i; sc->sc_busses[i].softc = sc; - sc->sc_i2c_tags[i].ic_cookie = &sc->sc_busses[i]; - sc->sc_i2c_tags[i].ic_acquire_bus = piixpm_i2c_acquire_bus; - sc->sc_i2c_tags[i].ic_release_bus = piixpm_i2c_release_bus; - sc->sc_i2c_tags[i].ic_exec = piixpm_i2c_exec; + tag->ic_cookie = &sc->sc_busses[i]; + if (PIIXPM_IS_SB800GRP(sc) || PIIXPM_IS_FCHGRP(sc)) { + tag->ic_acquire_bus = piixpm_i2c_sb800_acquire_bus; + tag->ic_release_bus = piixpm_i2c_sb800_release_bus; + } else { + tag->ic_acquire_bus = NULL; + tag->ic_release_bus = NULL; + } + tag->ic_exec = piixpm_i2c_exec; memset(&iba, 0, sizeof(iba)); iba.iba_type = I2C_TYPE_SMBUS; - iba.iba_tag = &sc->sc_i2c_tags[i]; + iba.iba_tag = tag; sc->sc_i2c_device[i] = config_found_ia(self, ifattr, &iba, piixpm_iicbus_print); } @@ -401,6 +407,12 @@ piixpm_sb800_init(struct piixpm_softc *s uint16_t val, base_addr; bool enabled; + if (PIIXPM_IS_KERNCZ(sc) || + (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) + sc->sc_numbusses = 2; + else + sc->sc_numbusses = 4; + /* Fetch SMB base address */ if (bus_space_map(iot, SB800_INDIRECTIO_BASE, SB800_INDIRECTIO_SIZE, 0, &ioh)) { @@ -420,6 +432,8 @@ piixpm_sb800_init(struct piixpm_softc *s val = bus_space_read_1(iot, ioh, SB800_INDIRECTIO_DATA) << 8; base_addr = val; } 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); @@ -434,15 +448,16 @@ piixpm_sb800_init(struct piixpm_softc *s bus_space_write_1(iot, ioh, SB800_INDIRECTIO_INDEX, SB800_PM_SMBUS0SELEN); - bus_space_write_1(iot, ioh, SB800_INDIRECTIO_DATA, - SB800_PM_SMBUS0EN_ENABLE); + data = bus_space_read_1(iot, ioh, 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); if (bus_space_map(iot, PCI_MAPREG_IO_ADDR(base_addr), - PIIX_SMB_SIZE, 0, &sc->sc_smb_ioh)) { + SB800_SMB_SIZE, 0, &sc->sc_smb_ioh)) { aprint_error_dev(sc->sc_dev, "can't map smbus I/O space\n"); return EBUSY; } @@ -472,51 +487,105 @@ piixpm_csb5_reset(void *arg) } static int -piixpm_i2c_acquire_bus(void *cookie, int flags) +piixpm_i2c_sb800_acquire_bus(void *cookie, int flags) { struct piixpm_smbus *smbus = cookie; struct piixpm_softc *sc = smbus->softc; + uint8_t sctl, old_sda, index, mask, reg; + int i; + if (!cold) mutex_enter(&sc->sc_i2c_mutex); - if (PIIXPM_IS_KERNCZ(sc)) { - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_INDEX, AMDFCH41_PM_PORT_INDEX); - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_DATA, smbus->sda << 3); - } else if (PIIXPM_IS_SB800GRP(sc) || PIIXPM_IS_HUDSON(sc)) { - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_INDEX, SB800_PM_SMBUS0SEL); + sctl = bus_space_read_1(sc->sc_smb_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, + sctl | PIIX_SMB_SC_HOSTSEM); + + sctl = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, + PIIX_SMB_SC); + if ((sctl & PIIX_SMB_SC_HOSTSEM) != 0) + break; + + delay(1000); + } + if (i >= PIIX_SB800_TIMEOUT) { + device_printf(sc->sc_dev, + "Failed to acquire the host semaphore\n"); + return -1; + } + + if (PIIXPM_IS_KERNCZ(sc) || + (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) { + index = AMDFCH41_PM_PORT_INDEX; + mask = AMDFCH41_SMBUS_PORTMASK; + } else if (sc->sc_sb800_selen) { + index = SB800_PM_SMBUS0SEL; + mask = SB800_PM_SMBUS0_MASK_E; + } else { + index = SB800_PM_SMBUS0EN_LO; + 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); + + 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, smbus->sda << 1); + SB800_INDIRECTIO_DATA, reg); } + /* Save the old port number */ + smbus->sda_save = old_sda; + return 0; } static void -piixpm_i2c_release_bus(void *cookie, int flags) +piixpm_i2c_sb800_release_bus(void *cookie, int flags) { struct piixpm_smbus *smbus = cookie; struct piixpm_softc *sc = smbus->softc; + uint8_t sctl, index, mask, reg; - if (PIIXPM_IS_KERNCZ(sc)) { - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_INDEX, AMDFCH41_PM_PORT_INDEX); - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_DATA, 0); - } else if (PIIXPM_IS_SB800GRP(sc) || PIIXPM_IS_HUDSON(sc)) { - /* - * HP Microserver hangs after reboot if not set to SDA0. - * Also add shutdown hook? - */ - bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_INDEX, SB800_PM_SMBUS0SEL); + if (PIIXPM_IS_KERNCZ(sc) || + (PIIXPM_IS_HUDSON(sc) && (sc->sc_rev >= 0x1f))) { + index = AMDFCH41_PM_PORT_INDEX; + mask = AMDFCH41_SMBUS_PORTMASK; + } else if (sc->sc_sb800_selen) { + index = SB800_PM_SMBUS0SEL; + mask = SB800_PM_SMBUS0_MASK_E; + } else { + index = SB800_PM_SMBUS0EN_LO; + 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 &= ~mask; + reg |= __SHIFTIN(smbus->sda_save, mask); bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, - SB800_INDIRECTIO_DATA, 0); + SB800_INDIRECTIO_DATA, reg); } + /* Relase the host semaphore */ + sctl = bus_space_read_1(sc->sc_smb_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, + sctl | PIIX_SMB_SC_CLRHOSTSEM); + if (!cold) mutex_exit(&sc->sc_i2c_mutex); } Index: src/sys/dev/pci/piixpmreg.h diff -u src/sys/dev/pci/piixpmreg.h:1.7.22.1 src/sys/dev/pci/piixpmreg.h:1.7.22.2 --- src/sys/dev/pci/piixpmreg.h:1.7.22.1 Tue Aug 6 16:02:54 2019 +++ src/sys/dev/pci/piixpmreg.h Wed Aug 5 16:11:56 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: piixpmreg.h,v 1.7.22.1 2019/08/06 16:02:54 martin Exp $ */ +/* $NetBSD: piixpmreg.h,v 1.7.22.2 2020/08/05 16:11:56 martin Exp $ */ /* $OpenBSD: piixreg.h,v 1.3 2006/01/03 22:39:03 grange Exp $ */ /*- @@ -66,7 +66,7 @@ #define PIIX_SMB_HOSTC 0xd0 /* SMBus host configuration */ #define PIIX_SMB_HOSTC_HSTEN (1 << 16) /* enable host controller */ #define PIIX_SMB_HOSTC_SMI (0 << 17) /* SMI */ -#define PIIX_SMB_HOSTC_IRQ (4 << 17) /* IRQ */ +#define PIIX_SMB_HOSTC_IRQ (4 << 17) /* IRQ 9 */ #define PIIX_SMB_HOSTC_INTMASK (7 << 17) /* SMBus I/O registers */ @@ -95,6 +95,11 @@ #define PIIX_SMB_HBDB 0x07 /* host block data byte */ #define PIIX_SMB_SC 0x08 /* slave control */ #define PIIX_SMB_SC_ALERTEN (1 << 3) /* enable SMBALERT# */ +#define PIIX_SMB_SC_HOSTSEM (1 << 4) /* (W1S) HostSemaphore */ +#define PIIX_SMB_SC_CLRHOSTSEM (1 << 5) /* (W1C) ClrHostSemaphore */ +#define PIIX_SMB_SC_ECSEM (1 << 6) /* (W1S) EcSemaphore */ +#define PIIX_SMB_SC_CLRECSEM (1 << 7) /* (W1C) ClrEcSemaphore */ +#define PIIX_SMB_SC_SEMMASK 0xf0 /* Semaphore bits */ /* Power management I/O registers */ #define PIIX_PM_PMTMR 0x08 /* power management timer */ @@ -113,18 +118,27 @@ #define SB800_INDIRECTIO_SIZE 2 #define SB800_INDIRECTIO_INDEX 0 #define SB800_INDIRECTIO_DATA 1 - + #define SB800_PM_SMBUS0EN_LO 0x2c #define SB800_PM_SMBUS0EN_HI 0x2d -#define SB800_PM_SMBUS0SEL 0x2e -#define SB800_PM_SMBUS0SELEN 0x2f - -#define SB800_PM_SMBUS0EN_ENABLE 0x0001 -#define SB800_PM_SMBUS0EN_BADDR 0xffe0 +#define SB800_PM_SMBUS0EN_ENABLE __BIT(0) /* Function enable */ +#define SB800_PM_SMBUS0_MASK_C __BITS(2, 1) /* Port mask (PMIO2C) */ +#define SB800_PM_SMBUS0EN_BADDR __BITS(15, 5) /* Base address */ + +#define SB800_PM_SMBUS0SEL 0x2e +#define SB800_PM_SMBUS0_MASK_E __BITS(2, 1) /* Port mask (PMIO2E) */ +#define SB800_PM_SMBUS0SELEN 0x2f +#define SB800_PM_USE_SMBUS0SEL __BIT(0) /* + * If the bit is set, SMBUS0SEL is + * used to select the port. + */ -/* In the PCI config space */ +/* In the SMBus I/O space */ #define SB800_SMB_HOSTC 0x10 /* I2C bus configuration */ -#define SB800_SMB_HOSTC_SMI (1 << 0) /* SMI */ +#define SB800_SMB_HOSTC_IRQ (1 << 0) /* 0:SMI 1:IRQ */ + +/* Misc */ +#define SB800_SMB_SIZE 0x11 /* SMBus I/O space size */ /* * Newer FCH registers in the PMIO space. @@ -135,6 +149,7 @@ #define AMDFCH41_WDT_EN 0x80 #define AMDFCH41_PM_DECODE_EN1 0x01 #define AMDFCH41_PM_PORT_INDEX 0x02 +#define AMDFCH41_SMBUS_PORTMASK 0x18 #define AMDFCH41_PM_DECODE_EN3 0x03 #define AMDFCH41_WDT_RES_MASK 0x03 #define AMDFCH41_WDT_RES_32US 0x00