Index: arch/amd64/conf/GENERIC =================================================================== RCS file: /cvs/src/sys/arch/amd64/conf/GENERIC,v retrieving revision 1.514 diff -u -p -r1.514 GENERIC --- arch/amd64/conf/GENERIC 11 Nov 2022 15:27:39 -0000 1.514 +++ arch/amd64/conf/GENERIC 27 Feb 2023 04:52:34 -0000 @@ -119,6 +119,7 @@ ksmn* at pci? # AMD K17 temperature se amas* at pci? disable # AMD memory configuration pchtemp* at pci? # Intel C610 temperature sensor ccp* at pci? # AMD Cryptographic Co-processor +iosf* at pci? # Intel OnChip System Fabric # National Semiconductor LM7[89] and compatible hardware monitors lm0 at isa? port 0x290 Index: dev/pci/files.pci =================================================================== RCS file: /cvs/src/sys/dev/pci/files.pci,v retrieving revision 1.359 diff -u -p -r1.359 files.pci --- dev/pci/files.pci 31 Mar 2022 21:41:17 -0000 1.359 +++ dev/pci/files.pci 27 Feb 2023 04:52:34 -0000 @@ -771,6 +771,11 @@ device gcu attach gcu at pci file dev/pci/gcu.c gcu needs-flag +# Intel OnChip System Fabric +device iosf +attach iosf at pci +file dev/pci/iosf.c iosf needs-flag + # AMD Geode CS5536 Audio device auglx: audio, ac97 attach auglx at pci Index: dev/pci/iosf.c =================================================================== RCS file: dev/pci/iosf.c diff -N dev/pci/iosf.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/pci/iosf.c 27 Feb 2023 04:52:34 -0000 @@ -0,0 +1,438 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2023 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define IOSF_R_MBI_MCR 0xd0 +#define IOSF_R_MBI_MDR 0xd4 +#define IOSF_R_MBI_MCRX 0xd8 + +#define IOSF_MBI_MASK_HI 0xffffff00 +#define IOSF_MBI_MASK_LO 0x000000ff +#define IOSF_MBI_ENABLE 0x000000f0 + +#define IOSF_MBI_MCR_OP_SHIFT 24 +#define IOSF_MBI_MCR_PORT_SHIFT 16 +#define IOSF_MBI_MCR_OFFSET_SHIFT 8 + +/* IOSF sideband read/write opcodes */ +#define IOSF_MBI_OP_MMIO_READ 0x00 +#define IOSF_MBI_OP_MMIO_WRITE 0x01 +#define IOSF_MBI_OP_CFG_READ 0x04 +#define IOSF_MBI_OP_CFG_WRITE 0x05 +#define IOSF_MBI_OP_CR_READ 0x06 +#define IOSF_MBI_OP_CR_WRITE 0x07 +#define IOSF_MBI_OP_REG_READ 0x10 +#define IOSF_MBI_OP_REG_WRITE 0x11 +#define IOSF_MBI_OP_ESRAM_READ 0x12 +#define IOSF_MBI_OP_ESRAM_WRITE 0x13 + +/* Baytrail */ +#define IOSF_BT_MBI_UNIT_AUNIT 0x00 +#define IOSF_BT_MBI_UNIT_SMC 0x01 +#define IOSF_BT_MBI_UNIT_CPU 0x02 +#define IOSF_BT_MBI_UNIT_BUNIT 0x03 +#define IOSF_BT_MBI_UNIT_PMC 0x04 +#define IOSF_BT_MBI_UNIT_GFX 0x06 +#define IOSF_BT_MBI_UNIT_SMI 0x0C +#define IOSF_BT_MBI_UNIT_CCK 0x14 +#define IOSF_BT_MBI_UNIT_USB 0x43 +#define IOSF_BT_MBI_UNIT_SATA 0xA3 +#define IOSF_BT_MBI_UNIT_PCIE 0xA6 + +/* semaphore bits */ +#define IOSF_PUNIT_SEM_BIT (1 << 0) +#define IOSF_PUNIT_SEM_ACQUIRE (1 << 1) + +/* + * Intel OnChip System Fabric driver + */ + +struct iosf_softc { + struct device sc_dev; + + pci_chipset_tag_t sc_pc; + pcitag_t sc_pcitag; + + /* serialise mbi read/write/modify pciconf accesses */ + struct mutex sc_mbi_mtx; + + struct rwlock sc_lock; + + int sc_semaddr; + + uint64_t sc_iic_block_count; + uint64_t sc_iic_block_nsec; +}; + +static int iosf_match(struct device *, void *, void *); +static void iosf_attach(struct device *, struct device *, void *); + +const struct cfattach iosf_ca = { + sizeof(struct iosf_softc), iosf_match, iosf_attach +}; + +struct cfdriver iosf_cd = { + NULL, "iosf", DV_DULL +}; + +static struct iosf_softc *iosf_sc; + +struct iosf_device { + struct pci_matchid id_pm; + int id_semaddr; +}; + +static const struct iosf_device iosf_devices[] = { + { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_BAYTRAIL_HB }, 0x7 }, + { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_BSW_HB }, 0x10e }, + /* Quark X1000, -1 */ + /* Tangier, -1 */ +}; + +static const struct iosf_device * +iosf_match_device(struct pci_attach_args *pa) +{ + pci_vendor_id_t vid = PCI_VENDOR(pa->pa_id); + pci_product_id_t pid = PCI_PRODUCT(pa->pa_id); + const struct iosf_device *id; + size_t i; + + for (i = 0; i < nitems(iosf_devices); i++) { + id = &iosf_devices[i]; + if (id->id_pm.pm_vid == vid && id->id_pm.pm_pid == pid) + return (id); + } + + return (NULL); +} + +static int +iosf_match(struct device *parent, void *match, void *aux) +{ + struct pci_attach_args *pa = aux; + + if (iosf_match_device(pa) != NULL) { + /* match higher than pchb(4) */ + return (2); + } + + return (0); +} + +static void +iosf_attach(struct device *parent, struct device *self, void *aux) +{ + struct iosf_softc *sc = (struct iosf_softc *)self; + struct pci_attach_args *pa = aux; + const struct iosf_device *id = iosf_match_device(pa); + + sc->sc_pc = pa->pa_pc; + sc->sc_pcitag = pa->pa_tag; + + sc->sc_semaddr = id->id_semaddr; + + mtx_init(&sc->sc_mbi_mtx, IPL_HIGH); + rw_init(&sc->sc_lock, "iosflk"); + + /* + * this assumes there is only one instance of this device + * in the machine. + */ + iosf_sc = sc; + + printf("\n"); +} + +static inline uint32_t +iosf_mbi_mcr(uint8_t op, uint8_t port, uint32_t offset) +{ + uint32_t rv = IOSF_MBI_ENABLE; + rv |= op << IOSF_MBI_MCR_OP_SHIFT; + rv |= port << IOSF_MBI_MCR_PORT_SHIFT; + rv |= (offset & IOSF_MBI_MASK_LO) << IOSF_MBI_MCR_OFFSET_SHIFT; + return (rv); +} + +static inline uint32_t +iosf_mbi_mcrx(uint32_t offset) +{ + return (offset & IOSF_MBI_MASK_HI); +} + +/* + * mbi mdr pciconf operations + */ + +static uint32_t +iosf_mbi_mdr_rd(struct iosf_softc *sc, uint32_t mcr, uint32_t mcrx) +{ + if (mcrx != 0) { + pci_conf_write(sc->sc_pc, sc->sc_pcitag, + IOSF_R_MBI_MCRX, mcrx); + } + + pci_conf_write(sc->sc_pc, sc->sc_pcitag, IOSF_R_MBI_MCR, mcr); + + return (pci_conf_read(sc->sc_pc, sc->sc_pcitag, IOSF_R_MBI_MDR)); +} + +static void +iosf_mbi_mdr_wr(struct iosf_softc *sc, uint32_t mcr, uint32_t mcrx, + uint32_t mdr) +{ + pci_conf_write(sc->sc_pc, sc->sc_pcitag, IOSF_R_MBI_MDR, mdr); + + if (mcrx != 0) { + pci_conf_write(sc->sc_pc, sc->sc_pcitag, + IOSF_R_MBI_MCRX, mcrx); + } + + pci_conf_write(sc->sc_pc, sc->sc_pcitag, IOSF_R_MBI_MCR, mcr); +} + +/* + * serialised mbi mdr operations + */ + +static uint32_t +iosf_mbi_mdr_read(struct iosf_softc *sc, uint8_t port, uint8_t op, + uint32_t offset) +{ + uint32_t mcr, mcrx, mdr; + + mcr = iosf_mbi_mcr(op, port, offset); + mcrx = iosf_mbi_mcrx(offset); + + mtx_enter(&sc->sc_mbi_mtx); + mdr = iosf_mbi_mdr_rd(sc, mcr, mcrx); + mtx_leave(&sc->sc_mbi_mtx); + + return (mdr); +} + +static void +iosf_mbi_mdr_write(struct iosf_softc *sc, uint8_t port, uint8_t op, + uint32_t offset, uint32_t mdr) +{ + uint32_t mcr, mcrx; + + mcr = iosf_mbi_mcr(op, port, offset); + mcrx = iosf_mbi_mcrx(offset); + + mtx_enter(&sc->sc_mbi_mtx); + iosf_mbi_mdr_wr(sc, mcr, mcrx, mdr); + mtx_leave(&sc->sc_mbi_mtx); + +} + +static void +iosf_mbi_mdr_modify(struct iosf_softc *sc, uint8_t port, uint8_t op, + uint32_t offset, uint32_t bits, uint32_t mask) +{ + uint32_t mcr, mcrx, mdr; + + mcr = iosf_mbi_mcr(op, port, offset); + mcrx = iosf_mbi_mcrx(offset); + + mtx_enter(&sc->sc_mbi_mtx); + mdr = iosf_mbi_mdr_rd(sc, mcr, mcrx); + + CLR(mdr, mask); + SET(mdr, bits & mask); + + iosf_mbi_mdr_wr(sc, mcr, mcrx, mdr); + mtx_leave(&sc->sc_mbi_mtx); +} + +/* + * linux compat api + */ + +int +iosf_mbi_read(uint8_t port, uint8_t opcode, uint32_t offset, uint32_t *mdrp) +{ + struct iosf_softc *sc; + + sc = iosf_sc; + if (sc == NULL) + return (ENODEV); + + /* check port != BT_MBI_UNIT_GFX? */ + + *mdrp = iosf_mbi_mdr_read(sc, port, opcode, offset); + + return (0); +} + +int +iosf_mbi_write(uint8_t port, uint8_t opcode, uint32_t offset, uint32_t mdr) +{ + struct iosf_softc *sc; + + sc = iosf_sc; + if (sc == NULL) + return (ENODEV); + + /* check port != BT_MBI_UNIT_GFX? */ + + iosf_mbi_mdr_write(sc, port, opcode, offset, mdr); + + return (0); +} + +int +iosf_mbi_modify(uint8_t port, uint8_t opcode, uint32_t offset, + uint32_t bits, uint32_t mask) +{ + struct iosf_softc *sc; + + sc = iosf_sc; + if (sc == NULL) + return (ENODEV); + + /* check port != BT_MBI_UNIT_GFX? */ + + iosf_mbi_mdr_modify(sc, port, opcode, offset, bits, mask); + + return (0); +} + +int +iosf_mbi_available(void) +{ + return (iosf_sc != NULL); +} + +static uint32_t +iosf_mbi_sem_get(struct iosf_softc *sc) +{ + uint32_t sem; + + sem = iosf_mbi_mdr_read(sc, IOSF_BT_MBI_UNIT_PMC, IOSF_MBI_OP_REG_READ, + sc->sc_semaddr); + + return (ISSET(sem, IOSF_PUNIT_SEM_BIT)); +} + +static void +iosf_mbi_sem_reset(struct iosf_softc *sc) +{ + iosf_mbi_mdr_modify(sc, IOSF_BT_MBI_UNIT_PMC, IOSF_MBI_OP_REG_READ, + sc->sc_semaddr, 0, IOSF_PUNIT_SEM_BIT); +} + +void +iosf_mbi_punit_acquire(void) +{ + struct iosf_softc *sc; + + sc = iosf_sc; + if (sc == NULL) + return; + + rw_enter_write(&sc->sc_lock); +} + +void +iosf_mbi_punit_release(void) +{ + struct iosf_softc *sc; + + sc = iosf_sc; + if (sc == NULL) + return; + + rw_exit_write(&sc->sc_lock); +} + +static void +iosf_sem_wait(struct iosf_softc *sc, uint64_t usec, int waitok) +{ + if (waitok) + tsleep_nsec(&nowake, PRIBIO, "iosfsem", USEC_TO_NSEC(usec)); + else + delay(usec); +} + +#include + +int +iosf_i2c_acquire(flags) +{ + struct iosf_softc *sc; + unsigned int i; + int waitok = !cold && !ISSET(flags, I2C_F_POLL); + + sc = iosf_sc; + if (sc == NULL) + return (0); + + if (waitok) + rw_enter_write(&sc->sc_lock); + else if (sc->sc_lock.rwl_owner != 0) + panic("%s", __func__); + + /* XXX disable C6 and C7 states */ + + iosf_mbi_mdr_write(sc, IOSF_BT_MBI_UNIT_PMC, IOSF_MBI_OP_REG_WRITE, + sc->sc_semaddr, IOSF_PUNIT_SEM_ACQUIRE); + + for (i = 0; i < 50; i++) { + if (iosf_mbi_sem_get(sc)) { + /* success! */ + //printf("%s: %s!\n", sc->sc_dev.dv_xname, __func__); + return (0); + } + + iosf_sem_wait(sc, 10000, waitok); + } + + iosf_mbi_sem_reset(sc); + + return (EWOULDBLOCK); +} + +void +iosf_i2c_release(flags) +{ + struct iosf_softc *sc; + int waitok = !cold && !ISSET(flags, I2C_F_POLL); + + sc = iosf_sc; + if (sc == NULL) + return; + + //printf("%s: %s!\n", sc->sc_dev.dv_xname, __func__); + + iosf_mbi_sem_reset(sc); + + if (waitok) + rw_exit_write(&sc->sc_lock); + else if (sc->sc_lock.rwl_owner != 0) + panic("%s", __func__); +} Index: dev/pci/iosf_var.h =================================================================== RCS file: dev/pci/iosf_var.h diff -N dev/pci/iosf_var.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/pci/iosf_var.h 27 Feb 2023 04:52:34 -0000 @@ -0,0 +1,17 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2023 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ Index: dev/acpi/dwiic_acpi.c =================================================================== RCS file: /cvs/src/sys/dev/acpi/dwiic_acpi.c,v retrieving revision 1.20 diff -u -p -r1.20 dwiic_acpi.c --- dev/acpi/dwiic_acpi.c 31 Aug 2022 15:14:01 -0000 1.20 +++ dev/acpi/dwiic_acpi.c 27 Feb 2023 04:52:36 -0000 @@ -53,6 +53,9 @@ void dwiic_acpi_power(struct dwiic_soft void dwiic_acpi_bus_scan(struct device *, struct i2cbus_attach_args *, void *); +static int dwiic_acpi_acquire_bus(void *, int); +static void dwiic_acpi_release_bus(void *, int); + const struct cfattach dwiic_acpi_ca = { sizeof(struct dwiic_softc), dwiic_acpi_match, @@ -169,8 +172,8 @@ dwiic_acpi_attach(struct device *parent, /* setup and attach iic bus */ sc->sc_i2c_tag.ic_cookie = sc; - sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus; - sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus; + sc->sc_i2c_tag.ic_acquire_bus = dwiic_acpi_acquire_bus; + sc->sc_i2c_tag.ic_release_bus = dwiic_acpi_release_bus; sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec; sc->sc_i2c_tag.ic_intr_establish = dwiic_i2c_intr_establish; sc->sc_i2c_tag.ic_intr_disestablish = dwiic_i2c_intr_disestablish; @@ -546,4 +549,26 @@ dwiic_acpi_power(struct dwiic_softc *sc, */ dwiic_write(sc, 0x800, 1); } +} + +int iosf_i2c_acquire(int); +void iosf_i2c_release(int); + +static int +dwiic_acpi_acquire_bus(void *cookie, int flags) +{ + int rv; + + rv = dwiic_i2c_acquire_bus(cookie, flags); + if (rv != 0) + return (rv); + + return (iosf_i2c_acquire(flags)); +} + +static void +dwiic_acpi_release_bus(void *cookie, int flags) +{ + iosf_i2c_release(flags); + dwiic_i2c_release_bus(cookie, flags); } Index: dev/acpi/tipmic.c =================================================================== RCS file: /cvs/src/sys/dev/acpi/tipmic.c,v retrieving revision 1.7 diff -u -p -r1.7 tipmic.c --- dev/acpi/tipmic.c 6 Apr 2022 18:59:27 -0000 1.7 +++ dev/acpi/tipmic.c 27 Feb 2023 04:52:36 -0000 @@ -276,6 +276,25 @@ struct tipmic_regmap tipmic_thermal_regm { 0x18, TIPMIC_SYSTEMP_HI, TIPMIC_SYSTEMP_LO } }; +static int +tipmic_wait_adc(struct tipmic_softc *sc) +{ + int i; + + if (!cold) { + return (tsleep_nsec(&sc->sc_stat_adc, PRIBIO, "tipmic", + SEC_TO_NSEC(1))); + } + + for (i = 0; i < 1000; i++) { + delay(1000); + if (tipmic_intr(sc) == 1) + return (0); + } + + return (EWOULDBLOCK); +} + int tipmic_thermal_opreg_handler(void *cookie, int iodir, uint64_t address, int size, uint64_t *value) @@ -333,8 +352,7 @@ tipmic_thermal_opreg_handler(void *cooki splx(s); while (sc->sc_stat_adc == 0) { - if (tsleep_nsec(&sc->sc_stat_adc, PRIBIO, "tipmic", - SEC_TO_NSEC(1))) { + if (tipmic_wait_adc(sc)) { printf("%s: ADC timeout\n", sc->sc_dev.dv_xname); break; }