add iosf(4), a driver for the Intel OnChip System Fabric
authordlg <dlg@openbsd.org>
Sun, 23 Apr 2023 00:20:26 +0000 (00:20 +0000)
committerdlg <dlg@openbsd.org>
Sun, 23 Apr 2023 00:20:26 +0000 (00:20 +0000)
The OnChip System Fabric is mostly an implementation detail on a
bunch of Intel SoC platforms we usually don't care about, except
on some of these machines there are devices shared between the
kernel and the platform that need to coordinate. The iosf(4) driver
allows the kernel to talk via a mailbox interface to take and
release a semaphore that the hardware also uses to lock around
accesses to some components.

There are two ways to talk to the mailbox interface, one via mmio
ops on an INT33BD acpi device. The other is via magic pci conf space
operations on the pci host device. This provides a generic iosf
driver with attachment glue for both acpi and pci so either can be
used. According to linux, the pci ops are a lot more reliable and
less buggy, so if both acpi and pci are available we will prefer
the pci ops after they attach.

I found this because I got a Dell Wyse 3040, which is a cherry
trail/braswell system that has an acpitz(4) which talks to a tipmic(4)
device attached to dwiic(4) on acpi. This box almost always locked
up by the time it got to showing the console login prompt, and it
turns out one of the reasons for this is because acpitz was touching
the tipmic device at the same time the powerunit on the platform
was also trying to use it. The tipmic device lists the iosf mailbox
as a dependency, and the dwiic controller has a _SEM property, both
of which indicate we should use an iosf device to coordinate iic
ops when talking to the tipmic.

This adds the code, but doesn't wire it into dwiic or the build yet.

help from patrick@ jsg@ kettenis@
ok kettenis@ patrick@

sys/conf/files
sys/dev/acpi/files.acpi
sys/dev/acpi/iosf_acpi.c [new file with mode: 0644]
sys/dev/ic/iosf.c [new file with mode: 0644]
sys/dev/ic/iosfvar.h [new file with mode: 0644]
sys/dev/pci/files.pci
sys/dev/pci/iosf_pci.c [new file with mode: 0644]

index cc2467a..edff930 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files,v 1.723 2023/04/04 00:38:37 jsg Exp $
+#      $OpenBSD: files,v 1.724 2023/04/23 00:20:26 dlg Exp $
 #      $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
 
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
@@ -424,6 +424,10 @@ file       dev/ic/malo.c                   malo
 device bwi: ether, ifnet, ifmedia, firmload, wlan
 file   dev/ic/bwi.c                    bwi
 
+# Intel OnChip System Fabric
+device iosf
+file   dev/ic/iosf.c                   iosf    needs-flag
+
 # Attributes which machine-independent bus support can be attached to.
 # These should be defined here, because some of these busses can have
 # devices which provide these attributes, and we'd like to avoid hairy
index 9b7bb76..4036d6a 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.acpi,v 1.68 2023/02/04 23:11:59 mglocker Exp $
+#      $OpenBSD: files.acpi,v 1.69 2023/04/23 00:20:26 dlg Exp $
 #
 # Config file and device description for machine-independent ACPI code.
 # Included by ports that need it.
@@ -275,3 +275,7 @@ file        dev/acpi/qciic.c                qciic
 # UFS HC
 attach ufshci at acpi with ufshci_acpi
 file   dev/acpi/ufshci_acpi.c          ufshci_acpi
+
+# Intel OnChip System Fabric
+attach iosf at acpi with iosf_acpi
+file   dev/acpi/iosf_acpi.c            iosf_acpi
diff --git a/sys/dev/acpi/iosf_acpi.c b/sys/dev/acpi/iosf_acpi.c
new file mode 100644 (file)
index 0000000..f394191
--- /dev/null
@@ -0,0 +1,149 @@
+/*     $OpenBSD: iosf_acpi.c,v 1.1 2023/04/23 00:20:26 dlg Exp $ */
+/*
+ * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
+ *
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+
+#include <dev/ic/iosfvar.h>
+
+struct iosf_acpi_softc {
+       struct device            sc_dev;
+       struct acpi_softc       *sc_acpi;
+       struct aml_node         *sc_node;
+
+       bus_space_tag_t          sc_iot;
+       bus_space_handle_t       sc_ioh;
+       bus_size_t               sc_ios;
+
+       struct iosf_mbi          sc_mbi;
+};
+
+static int     iosf_acpi_match(struct device *, void *, void *);
+static void    iosf_acpi_attach(struct device *, struct device *, void *);
+
+static uint32_t        iosf_acpi_mbi_mdr_rd(struct iosf_mbi *, uint32_t, uint32_t);
+static void    iosf_acpi_mbi_mdr_wr(struct iosf_mbi *, uint32_t, uint32_t,
+                   uint32_t);
+
+const struct cfattach iosf_acpi_ca = {
+       sizeof(struct iosf_acpi_softc), iosf_acpi_match, iosf_acpi_attach
+};
+
+static const char *iosf_hids[] = {
+       "INT33BD",
+       NULL
+};
+
+static int
+iosf_acpi_match(struct device *parent, void *match, void *aux)
+{
+       struct acpi_attach_args *aaa = aux;
+       struct cfdata *cf = match;
+
+       if (aaa->aaa_naddr < 1)
+               return 0;
+
+       return (acpi_matchhids(aaa, iosf_hids, cf->cf_driver->cd_name));
+}
+
+static void
+iosf_acpi_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct iosf_acpi_softc *sc = (struct iosf_acpi_softc *)self;
+       struct acpi_attach_args *aaa = aux;
+       struct cpu_info *ci;
+       int semaddr = -1;
+
+       sc->sc_acpi = (struct acpi_softc *)parent;
+       sc->sc_node = aaa->aaa_node;
+       printf(" %s", sc->sc_node->name);
+
+       sc->sc_iot = aaa->aaa_bst[0];
+       sc->sc_ios = aaa->aaa_size[0];
+
+       if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0], 0,
+           &sc->sc_ioh)) {
+               printf(": can't map registers\n");
+               return;
+       }
+
+       ci = curcpu();
+       if (strcmp(cpu_vendor, "GenuineIntel") == 0 &&
+           ci->ci_family == 0x06 && ci->ci_model == 0x4c) {
+               /* cherry trail, braswell */
+               semaddr = 0x10e;
+       }
+
+       if (semaddr != -1) {
+               printf(": mbi");
+
+               sc->sc_mbi.mbi_dev = self;
+               sc->sc_mbi.mbi_prio = 1; /* lower prio than iosf_pci ops */
+               sc->sc_mbi.mbi_semaddr = semaddr;
+               sc->sc_mbi.mbi_mdr_rd = iosf_acpi_mbi_mdr_rd;
+               sc->sc_mbi.mbi_mdr_wr = iosf_acpi_mbi_mdr_wr;
+       }
+
+       printf("\n");
+}
+
+/*
+ * mbi mdr ACPI operations
+ */
+
+#define IOSF_ACPI_MBI_MCR      0x0
+#define IOSF_ACPI_MBI_MDR      0x4
+#define IOSF_ACPI_MBI_MCRX     0x8
+
+static uint32_t
+iosf_acpi_mbi_mdr_rd(struct iosf_mbi *mbi, uint32_t mcr, uint32_t mcrx)
+{
+       struct iosf_acpi_softc *sc = (struct iosf_acpi_softc *)mbi->mbi_dev;
+
+       if (mcrx != 0) {
+               bus_space_write_4(sc->sc_iot, sc->sc_ioh, 
+                   IOSF_ACPI_MBI_MCRX, mcrx);
+       }
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOSF_ACPI_MBI_MCR, mcr);
+
+       return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOSF_ACPI_MBI_MDR));
+}
+
+static void
+iosf_acpi_mbi_mdr_wr(struct iosf_mbi *mbi, uint32_t mcr, uint32_t mcrx,
+    uint32_t mdr)
+{
+       struct iosf_acpi_softc *sc = (struct iosf_acpi_softc *)mbi->mbi_dev;
+
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOSF_ACPI_MBI_MDR, mdr);
+       if (mcrx != 0) {
+               bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+                   IOSF_ACPI_MBI_MCRX, mcrx);
+       }
+
+       bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOSF_ACPI_MBI_MCR, mcr);
+}
diff --git a/sys/dev/ic/iosf.c b/sys/dev/ic/iosf.c
new file mode 100644 (file)
index 0000000..16f4a40
--- /dev/null
@@ -0,0 +1,335 @@
+/*     $OpenBSD: iosf.c,v 1.1 2023/04/23 00:20:26 dlg Exp $ */
+
+/*
+ * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
+ *
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+
+#include <machine/bus.h>
+
+#include <dev/ic/iosfvar.h>
+
+#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)
+
+struct cfdriver iosf_cd = {
+       NULL, "iosf", DV_DULL
+};
+
+/*
+ * serialise register ops
+ */
+static struct mutex iosf_mbi_mtx = MUTEX_INITIALIZER(IPL_HIGH);
+
+/*
+ * rwlock for kernel to coordinate access to the mbi with
+ */
+static struct rwlock iosf_lock = RWLOCK_INITIALIZER("iosf");
+
+/*
+ * drivers provide an iosf_mbi that acts as a backend for the code below.
+ */
+static struct iosf_mbi *iosf_mbi;
+
+void
+iosf_mbi_attach(struct iosf_mbi *mbi)
+{
+       /*
+        * assume this is serialised by autoconf being run sequentially
+        * during boot.
+        */
+
+       if (iosf_mbi == NULL || iosf_mbi->mbi_prio < mbi->mbi_prio)
+               iosf_mbi = mbi;
+}
+
+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);
+}
+
+/*
+ * serialised mbi mdr operations
+ */
+
+static uint32_t
+iosf_mbi_mdr_read(struct iosf_mbi *mbi, 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(&iosf_mbi_mtx);
+       mdr = (*mbi->mbi_mdr_rd)(mbi, mcr, mcrx);
+       mtx_leave(&iosf_mbi_mtx);
+
+       return (mdr);
+}
+
+static void
+iosf_mbi_mdr_write(struct iosf_mbi *mbi, 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(&iosf_mbi_mtx);
+       (*mbi->mbi_mdr_wr)(mbi, mcr, mcrx, mdr);
+       mtx_leave(&iosf_mbi_mtx);
+}
+
+static void
+iosf_mbi_mdr_modify(struct iosf_mbi *mbi, 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(&iosf_mbi_mtx);
+       mdr = (*mbi->mbi_mdr_rd)(mbi, mcr, mcrx);
+
+       CLR(mdr, mask);
+       SET(mdr, bits & mask); 
+
+       (*mbi->mbi_mdr_wr)(mbi, mcr, mcrx, mdr);
+       mtx_leave(&iosf_mbi_mtx);
+}
+
+/*
+ * linux compat api
+ */
+
+int
+iosf_mbi_read(uint8_t port, uint8_t opcode, uint32_t offset, uint32_t *mdrp)
+{
+       struct iosf_mbi *mbi;
+
+       mbi = iosf_mbi;
+       if (mbi == NULL)
+               return (ENODEV);
+
+       /* check port != BT_MBI_UNIT_GFX? */
+
+       *mdrp = iosf_mbi_mdr_read(mbi, port, opcode, offset);
+
+       return (0);
+}
+
+int
+iosf_mbi_write(uint8_t port, uint8_t opcode, uint32_t offset, uint32_t mdr)
+{
+       struct iosf_mbi *mbi;
+
+       mbi = iosf_mbi;
+       if (mbi == NULL)
+               return (ENODEV);
+
+       /* check port != BT_MBI_UNIT_GFX? */
+
+       iosf_mbi_mdr_write(mbi, 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_mbi *mbi;
+
+       mbi = iosf_mbi;
+       if (mbi == NULL)
+               return (ENODEV);
+
+       /* check port != BT_MBI_UNIT_GFX? */
+
+       iosf_mbi_mdr_modify(mbi, port, opcode, offset, bits, mask);
+
+       return (0);
+}
+
+int
+iosf_mbi_available(void)
+{
+       return (iosf_mbi != NULL);
+}
+
+static uint32_t
+iosf_mbi_sem_get(struct iosf_mbi *mbi)
+{
+       uint32_t sem;
+
+       sem = iosf_mbi_mdr_read(mbi,
+           IOSF_BT_MBI_UNIT_PMC, IOSF_MBI_OP_REG_READ, mbi->mbi_semaddr);
+
+       return (ISSET(sem, IOSF_PUNIT_SEM_BIT));
+}
+
+static void
+iosf_mbi_sem_reset(struct iosf_mbi *mbi)
+{
+       iosf_mbi_mdr_modify(mbi,
+           IOSF_BT_MBI_UNIT_PMC, IOSF_MBI_OP_REG_READ, mbi->mbi_semaddr,
+           0, IOSF_PUNIT_SEM_BIT);
+}
+
+void
+iosf_mbi_punit_acquire(void)
+{
+       rw_enter_write(&iosf_lock);
+}
+
+void
+iosf_mbi_punit_release(void)
+{
+       rw_exit_write(&iosf_lock);
+}
+
+void iosf_mbi_assert_punit_acquired(void)
+{
+       int s;
+
+       if (splassert_ctl == 0)
+               return;
+
+       s = rw_status(&iosf_lock);
+       if (s != RW_WRITE)
+               splassert_fail(RW_WRITE, s, __func__);
+}
+
+static void
+iosf_sem_wait(uint64_t usec, int waitok)
+{
+       if (waitok)
+               tsleep_nsec(&nowake, PRIBIO, "iosfsem", USEC_TO_NSEC(usec));
+       else
+               delay(usec);
+}
+
+#include <dev/i2c/i2cvar.h>
+
+int
+iosf_i2c_acquire(int flags)
+{
+       struct iosf_mbi *mbi;
+       int waitok = !cold && !ISSET(flags, I2C_F_POLL);
+       unsigned int i;
+
+       mbi = iosf_mbi;
+       if (mbi == NULL)
+               return (0);
+
+       if (waitok)
+               rw_enter_write(&iosf_lock);
+       else if (iosf_lock.rwl_owner != 0)
+               panic("%s", __func__);
+
+       /* XXX disable C6 and C7 states */
+
+       iosf_mbi_mdr_write(mbi, IOSF_BT_MBI_UNIT_PMC, IOSF_MBI_OP_REG_WRITE,
+           mbi->mbi_semaddr, IOSF_PUNIT_SEM_ACQUIRE);
+
+       for (i = 0; i < 50; i++) {
+               if (iosf_mbi_sem_get(mbi)) {
+                       /* success! */
+                       return (0);
+               }
+
+               iosf_sem_wait(10000, waitok);
+       }
+
+       iosf_mbi_sem_reset(mbi);
+
+       if (waitok)
+               rw_exit_write(&iosf_lock);
+       else if (iosf_lock.rwl_owner != 0)
+               panic("%s", __func__);
+
+       return (EWOULDBLOCK);
+}
+
+void
+iosf_i2c_release(int flags)
+{
+       struct iosf_mbi *mbi;
+       int waitok = !cold && !ISSET(flags, I2C_F_POLL);
+
+       mbi = iosf_mbi;
+       if (mbi == NULL)
+               return;
+
+       iosf_mbi_sem_reset(mbi);
+
+       if (waitok)
+               rw_exit_write(&iosf_lock);
+       else if (iosf_lock.rwl_owner != 0)
+               panic("%s", __func__);
+}
diff --git a/sys/dev/ic/iosfvar.h b/sys/dev/ic/iosfvar.h
new file mode 100644 (file)
index 0000000..a0c2417
--- /dev/null
@@ -0,0 +1,59 @@
+/*     $OpenBSD: iosfvar.h,v 1.1 2023/04/23 00:20:26 dlg Exp $ */
+
+/*
+ * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
+ *
+ * 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.
+ */
+
+#ifndef _DEV_IC_IOSFVAR_H_
+#define _DEV_IC_IOSFVAR_H_
+
+/*
+ * iosf provider api
+ */
+
+struct iosf_mbi {
+       struct device           *mbi_dev;
+       int                      mbi_prio;
+       int                      mbi_semaddr;
+
+       uint32_t        (*mbi_mdr_rd)(struct iosf_mbi *sc, uint32_t, uint32_t);
+       void            (*mbi_mdr_wr)(struct iosf_mbi *sc, uint32_t, uint32_t,
+                             uint32_t);
+};
+
+void   iosf_mbi_attach(struct iosf_mbi *);
+
+/*
+ * iosf consumer apis
+ */
+
+int    iosf_mbi_available(void);
+
+/* for i2c */
+int    iosf_i2c_acquire(int);
+void   iosf_i2c_relese(int);
+
+/* for drm to coordinate with the rest of the kernel */
+void   iosf_mbi_punit_acquire(void);
+void   iosf_mbi_punit_release(void);
+void   iosf_mbi_assert_punit_acquired(void);
+
+#ifdef nyetyet
+int    iosf_mbi_read(uint8_t, uint8_t, uint32_t, uint32_t *);
+int    iosf_mbi_write(uint8_t, uint8_t, uint32_t, uint32_t);
+int    iosf_mbi_modify(uint8_t, uint8_t, uint32_t, uint32_t, uint32_t);
+#endif
+
+#endif /* _DEV_IC_IOSFVAR_H_ */
index 797e07c..101ed50 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files.pci,v 1.360 2023/03/31 08:19:41 kevlo Exp $
+#      $OpenBSD: files.pci,v 1.361 2023/04/23 00:20:26 dlg Exp $
 #      $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
 #
 # Config file and device description for machine-independent PCI code.
@@ -771,6 +771,10 @@ device     gcu
 attach gcu at pci
 file   dev/pci/gcu.c                   gcu             needs-flag
 
+# Intel OnChip System Fabric
+attach iosf at pci with iosf_pci
+file   dev/pci/iosf_pci.c              iosf_pci
+
 # AMD Geode CS5536 Audio
 device auglx: audio, ac97
 attach auglx at pci
diff --git a/sys/dev/pci/iosf_pci.c b/sys/dev/pci/iosf_pci.c
new file mode 100644 (file)
index 0000000..886a39c
--- /dev/null
@@ -0,0 +1,157 @@
+/*     $OpenBSD: iosf_pci.c,v 1.1 2023/04/23 00:20:26 dlg Exp $ */
+
+/*
+ * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
+ *
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/ic/iosfvar.h>
+
+/*
+ * Intel OnChip System Fabric driver
+ */
+
+struct iosf_pci_softc {
+       struct device           sc_dev;
+
+       pci_chipset_tag_t       sc_pc;
+       pcitag_t                sc_pcitag;
+
+       int                     sc_semaddr;
+
+       struct iosf_mbi         sc_mbi;
+};
+
+static int     iosf_pci_match(struct device *, void *, void *);
+static void    iosf_pci_attach(struct device *, struct device *, void *);
+
+static uint32_t        iosf_pci_mbi_mdr_rd(struct iosf_mbi *, uint32_t, uint32_t);
+static void    iosf_pci_mbi_mdr_wr(struct iosf_mbi *, uint32_t, uint32_t,
+                   uint32_t);
+
+const struct cfattach iosf_pci_ca = {
+       sizeof(struct iosf_pci_softc), iosf_pci_match, iosf_pci_attach
+};
+
+struct iosf_pci_device {
+       struct pci_matchid              id_pm;
+       int                             id_semaddr;
+};
+
+static const struct iosf_pci_device iosf_pci_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_pci_device *
+iosf_pci_device_match(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_pci_device *id;
+       size_t i;
+
+       for (i = 0; i < nitems(iosf_pci_devices); i++) {
+               id = &iosf_pci_devices[i];
+               if (id->id_pm.pm_vid == vid && id->id_pm.pm_pid == pid)
+                       return (id);
+       }
+
+       return (NULL);
+}
+
+static int
+iosf_pci_match(struct device *parent, void *match, void *aux)
+{
+       struct pci_attach_args *pa = aux;
+
+       if (iosf_pci_device_match(pa) != NULL) {
+               /* match higher than pchb(4) */
+               return (2);
+       }
+
+       return (0);
+}
+
+static void
+iosf_pci_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct iosf_pci_softc *sc = (struct iosf_pci_softc *)self;
+       struct pci_attach_args *pa = aux;
+       const struct iosf_pci_device *id = iosf_pci_device_match(pa);
+
+       sc->sc_pc = pa->pa_pc;
+       sc->sc_pcitag = pa->pa_tag;
+
+       printf(": mbi\n");
+
+       sc->sc_mbi.mbi_dev = self;
+       sc->sc_mbi.mbi_prio = 2; /* prefer pci over acpi ops */
+       sc->sc_mbi.mbi_semaddr = id->id_semaddr;
+       sc->sc_mbi.mbi_mdr_rd = iosf_pci_mbi_mdr_rd;
+       sc->sc_mbi.mbi_mdr_wr = iosf_pci_mbi_mdr_wr;
+
+       iosf_mbi_attach(&sc->sc_mbi);
+}
+
+/*
+ * mbi mdr pciconf operations
+ */
+
+#define IOSF_PCI_MBI_MCR               0xd0
+#define IOSF_PCI_MBI_MDR               0xd4
+#define IOSF_PCI_MBI_MCRX              0xd8
+
+static uint32_t
+iosf_pci_mbi_mdr_rd(struct iosf_mbi *mbi, uint32_t mcr, uint32_t mcrx)
+{
+       struct iosf_pci_softc *sc = (struct iosf_pci_softc *)mbi->mbi_dev;
+
+       if (mcrx != 0) {
+               pci_conf_write(sc->sc_pc, sc->sc_pcitag,
+                   IOSF_PCI_MBI_MCRX, mcrx);
+       }
+       pci_conf_write(sc->sc_pc, sc->sc_pcitag, IOSF_PCI_MBI_MCR, mcr);
+
+       return (pci_conf_read(sc->sc_pc, sc->sc_pcitag, IOSF_PCI_MBI_MDR));
+}
+
+static void
+iosf_pci_mbi_mdr_wr(struct iosf_mbi *mbi, uint32_t mcr, uint32_t mcrx,
+    uint32_t mdr)
+{
+       struct iosf_pci_softc *sc = (struct iosf_pci_softc *)mbi->mbi_dev;
+
+       pci_conf_write(sc->sc_pc, sc->sc_pcitag, IOSF_PCI_MBI_MDR, mdr);
+
+       if (mcrx != 0) {
+               pci_conf_write(sc->sc_pc, sc->sc_pcitag,
+                   IOSF_PCI_MBI_MCRX, mcrx);
+       }
+
+       pci_conf_write(sc->sc_pc, sc->sc_pcitag, IOSF_PCI_MBI_MCR, mcr);
+}