summaryrefslogtreecommitdiff
path: root/usr/src/uts/intel
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@fingolfin.org>2020-10-07 12:00:39 -0700
committerRobert Mustacchi <rm@fingolfin.org>2020-10-21 14:05:11 -0700
commit549e0fd315406a4a97f9043f44860eed39a715da (patch)
tree7e8177502e3db10815f9c9d7eff2102000a2eb8e /usr/src/uts/intel
parentbecd642c1e97d1674cef9e3dccb159c20c6992ae (diff)
downloadillumos-joyent-549e0fd315406a4a97f9043f44860eed39a715da.tar.gz
13213 Want development driver for accessing AMD DF
Reviewed by: Patrick Mooney <pmooney@pfmooney.com> Approved by: Richard Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src/uts/intel')
-rw-r--r--usr/src/uts/intel/Makefile.files1
-rw-r--r--usr/src/uts/intel/Makefile.intel2
-rw-r--r--usr/src/uts/intel/io/amdzen/amdzen.c70
-rw-r--r--usr/src/uts/intel/io/amdzen/amdzen.h3
-rw-r--r--usr/src/uts/intel/io/amdzen/amdzen_client.h4
-rw-r--r--usr/src/uts/intel/io/amdzen/zen_udf.c286
-rw-r--r--usr/src/uts/intel/io/amdzen/zen_udf.h44
-rw-r--r--usr/src/uts/intel/zen_udf/Makefile41
8 files changed, 445 insertions, 6 deletions
diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files
index f6d2efc34c..336c25d739 100644
--- a/usr/src/uts/intel/Makefile.files
+++ b/usr/src/uts/intel/Makefile.files
@@ -350,3 +350,4 @@ AMDZEN_OBJS = amdzen.o
AMDZEN_STUB_OBJS = amdzen_stub.o
SMNTEMP_OBJS = smntemp.o
USMN_OBJS = usmn.o
+ZEN_UDF_OBJS = zen_udf.o
diff --git a/usr/src/uts/intel/Makefile.intel b/usr/src/uts/intel/Makefile.intel
index f24c591288..64e027fe15 100644
--- a/usr/src/uts/intel/Makefile.intel
+++ b/usr/src/uts/intel/Makefile.intel
@@ -776,4 +776,4 @@ DRV_KMODS += smntemp
#
DRV_KMODS += amdzen
DRV_KMODS += amdzen_stub
-DRV_KMODS += usmn
+DRV_KMODS += usmn zen_udf
diff --git a/usr/src/uts/intel/io/amdzen/amdzen.c b/usr/src/uts/intel/io/amdzen/amdzen.c
index 17a3c69b9a..25e38ee988 100644
--- a/usr/src/uts/intel/io/amdzen/amdzen.c
+++ b/usr/src/uts/intel/io/amdzen/amdzen.c
@@ -157,7 +157,8 @@ typedef struct {
static const amdzen_child_data_t amdzen_children[] = {
{ "smntemp", AMDZEN_C_SMNTEMP },
- { "usmn", AMDZEN_C_USMN }
+ { "usmn", AMDZEN_C_USMN },
+ { "zen_udf", AMDZEN_C_ZEN_UDF }
};
static uint32_t
@@ -166,6 +167,12 @@ amdzen_stub_get32(amdzen_stub_t *stub, off_t reg)
return (pci_config_get32(stub->azns_cfgspace, reg));
}
+static uint64_t
+amdzen_stub_get64(amdzen_stub_t *stub, off_t reg)
+{
+ return (pci_config_get64(stub->azns_cfgspace, reg));
+}
+
static void
amdzen_stub_put32(amdzen_stub_t *stub, off_t reg, uint32_t val)
{
@@ -189,6 +196,24 @@ amdzen_df_read32(amdzen_t *azn, amdzen_df_t *df, uint8_t inst, uint8_t func,
return (amdzen_stub_get32(df->adf_funcs[4], AMDZEN_DF_F4_FICAD_LO));
}
+/*
+ * Perform a targeted 64-bit indirect read to a specific instance and function.
+ */
+static uint64_t
+amdzen_df_read64(amdzen_t *azn, amdzen_df_t *df, uint8_t inst, uint8_t func,
+ uint16_t reg)
+{
+ uint32_t val;
+
+ VERIFY(MUTEX_HELD(&azn->azn_mutex));
+ val = AMDZEN_DF_F4_FICAA_TARG_INST | AMDZEN_DF_F4_FICAA_SET_REG(reg) |
+ AMDZEN_DF_F4_FICAA_SET_FUNC(func) |
+ AMDZEN_DF_F4_FICAA_SET_INST(inst) | AMDZEN_DF_F4_FICAA_SET_64B;
+ amdzen_stub_put32(df->adf_funcs[4], AMDZEN_DF_F4_FICAA, val);
+ return (amdzen_stub_get64(df->adf_funcs[4], AMDZEN_DF_F4_FICAD_LO));
+}
+
+
static uint32_t
amdzen_smn_read32(amdzen_t *azn, amdzen_df_t *df, uint32_t reg)
{
@@ -260,6 +285,45 @@ amdzen_c_df_count(void)
return (ret);
}
+int
+amdzen_c_df_read32(uint_t dfno, uint8_t inst, uint8_t func,
+ uint16_t reg, uint32_t *valp)
+{
+ amdzen_df_t *df;
+ amdzen_t *azn = amdzen_data;
+
+ mutex_enter(&azn->azn_mutex);
+ df = amdzen_df_find(azn, dfno);
+ if (df == NULL) {
+ mutex_exit(&azn->azn_mutex);
+ return (ENOENT);
+ }
+
+ *valp = amdzen_df_read32(azn, df, inst, func, reg);
+ mutex_exit(&azn->azn_mutex);
+
+ return (0);
+}
+
+int
+amdzen_c_df_read64(uint_t dfno, uint8_t inst, uint8_t func,
+ uint16_t reg, uint64_t *valp)
+{
+ amdzen_df_t *df;
+ amdzen_t *azn = amdzen_data;
+
+ mutex_enter(&azn->azn_mutex);
+ df = amdzen_df_find(azn, dfno);
+ if (df == NULL) {
+ mutex_exit(&azn->azn_mutex);
+ return (ENOENT);
+ }
+
+ *valp = amdzen_df_read64(azn, df, inst, func, reg);
+ mutex_exit(&azn->azn_mutex);
+
+ return (0);
+}
static boolean_t
amdzen_create_child(amdzen_t *azn, const amdzen_child_data_t *acd)
@@ -269,14 +333,14 @@ amdzen_create_child(amdzen_t *azn, const amdzen_child_data_t *acd)
if (ndi_devi_alloc(azn->azn_dip, acd->acd_name,
(pnode_t)DEVI_SID_NODEID, &child) != NDI_SUCCESS) {
- dev_err(azn->azn_dip, CE_WARN, "failed to allocate child "
+ dev_err(azn->azn_dip, CE_WARN, "!failed to allocate child "
"dip for %s", acd->acd_name);
return (B_FALSE);
}
ddi_set_parent_data(child, (void *)acd);
if ((ret = ndi_devi_online(child, 0)) != NDI_SUCCESS) {
- dev_err(azn->azn_dip, CE_WARN, "failed to online child "
+ dev_err(azn->azn_dip, CE_WARN, "!failed to online child "
"dip %s: %d", acd->acd_name, ret);
return (B_FALSE);
}
diff --git a/usr/src/uts/intel/io/amdzen/amdzen.h b/usr/src/uts/intel/io/amdzen/amdzen.h
index 79b0bc38f4..8150495911 100644
--- a/usr/src/uts/intel/io/amdzen/amdzen.h
+++ b/usr/src/uts/intel/io/amdzen/amdzen.h
@@ -289,7 +289,8 @@ typedef struct amdzen {
typedef enum {
AMDZEN_C_SMNTEMP = 1,
- AMDZEN_C_USMN
+ AMDZEN_C_USMN,
+ AMDZEN_C_ZEN_UDF
} amdzen_child_t;
/*
diff --git a/usr/src/uts/intel/io/amdzen/amdzen_client.h b/usr/src/uts/intel/io/amdzen/amdzen_client.h
index ebb942c40b..41ca3e8afd 100644
--- a/usr/src/uts/intel/io/amdzen/amdzen_client.h
+++ b/usr/src/uts/intel/io/amdzen/amdzen_client.h
@@ -26,8 +26,10 @@
extern "C" {
#endif
-extern int amdzen_c_smn_read32(uint_t df, uint32_t reg, uint32_t *);
+extern int amdzen_c_smn_read32(uint_t, uint32_t, uint32_t *);
extern uint_t amdzen_c_df_count(void);
+extern int amdzen_c_df_read32(uint_t, uint8_t, uint8_t, uint16_t, uint32_t *);
+extern int amdzen_c_df_read64(uint_t, uint8_t, uint8_t, uint16_t, uint64_t *);
#ifdef __cplusplus
}
diff --git a/usr/src/uts/intel/io/amdzen/zen_udf.c b/usr/src/uts/intel/io/amdzen/zen_udf.c
new file mode 100644
index 0000000000..61d1e79774
--- /dev/null
+++ b/usr/src/uts/intel/io/amdzen/zen_udf.c
@@ -0,0 +1,286 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 Oxide Computer Company
+ */
+
+/*
+ * A companion to zen_udf(7D) that allows user access to read the data fabric
+ * for development purposes.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include <sys/open.h>
+#include <sys/cred.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/stat.h>
+#include <sys/conf.h>
+#include <sys/devops.h>
+#include <sys/cmn_err.h>
+#include <sys/policy.h>
+#include <amdzen_client.h>
+
+#include <zen_udf.h>
+
+typedef struct zen_udf {
+ dev_info_t *zudf_dip;
+ uint_t zudf_ndfs;
+} zen_udf_t;
+
+static zen_udf_t zen_udf_data;
+
+static int
+zen_udf_open(dev_t *devp, int flags, int otype, cred_t *credp)
+{
+ minor_t m;
+ zen_udf_t *zen_udf = &zen_udf_data;
+
+ if (crgetzoneid(credp) != GLOBAL_ZONEID ||
+ secpolicy_hwmanip(credp) != 0) {
+ return (EPERM);
+ }
+
+ if ((flags & (FEXCL | FNDELAY | FNONBLOCK)) != 0) {
+ return (EINVAL);
+ }
+
+ if (otype != OTYP_CHR) {
+ return (EINVAL);
+ }
+
+ m = getminor(*devp);
+ if (m >= zen_udf->zudf_ndfs) {
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+zen_udf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
+ int *rvalp)
+{
+ uint_t dfno;
+ zen_udf_t *zen_udf = &zen_udf_data;
+ zen_udf_io_t zui;
+
+ if (cmd != ZEN_UDF_READ32 && cmd != ZEN_UDF_READ64) {
+ return (ENOTTY);
+ }
+
+ dfno = getminor(dev);
+ if (dfno >= zen_udf->zudf_ndfs) {
+ return (ENXIO);
+ }
+
+ if (crgetzoneid(credp) != GLOBAL_ZONEID ||
+ secpolicy_hwmanip(credp) != 0) {
+ return (EPERM);
+ }
+
+ if (ddi_copyin((void *)arg, &zui, sizeof (zui), mode & FKIOCTL) != 0) {
+ return (EFAULT);
+ }
+
+ if (cmd == ZEN_UDF_READ32) {
+ int ret;
+ uint32_t data;
+
+ ret = amdzen_c_df_read32(dfno, zui.zui_inst, zui.zui_func,
+ zui.zui_reg, &data);
+ if (ret != 0) {
+ return (ret);
+ }
+
+ zui.zui_data = data;
+ } else {
+ int ret;
+
+ ret = amdzen_c_df_read64(dfno, zui.zui_inst, zui.zui_func,
+ zui.zui_reg, &zui.zui_data);
+ if (ret != 0) {
+ return (ret);
+ }
+ }
+
+ if (ddi_copyout(&zui, (void *)arg, sizeof (zui), mode & FKIOCTL) != 0) {
+ return (EFAULT);
+ }
+
+ return (0);
+}
+
+static int
+zen_udf_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+ return (0);
+}
+
+static void
+zen_udf_cleanup(zen_udf_t *zen_udf)
+{
+ ddi_remove_minor_node(zen_udf->zudf_dip, NULL);
+ zen_udf->zudf_ndfs = 0;
+ zen_udf->zudf_dip = NULL;
+}
+
+static int
+zen_udf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ zen_udf_t *zen_udf = &zen_udf_data;
+
+ if (cmd == DDI_RESUME) {
+ return (DDI_SUCCESS);
+ } else if (cmd != DDI_ATTACH) {
+ return (DDI_FAILURE);
+ }
+
+ if (zen_udf->zudf_dip != NULL) {
+ dev_err(dip, CE_WARN, "!zen_udf is already attached to a "
+ "dev_info_t: %p", zen_udf->zudf_dip);
+ return (DDI_FAILURE);
+ }
+
+ zen_udf->zudf_dip = dip;
+ zen_udf->zudf_ndfs = amdzen_c_df_count();
+ for (uint_t i = 0; i < zen_udf->zudf_ndfs; i++) {
+ char buf[32];
+
+ (void) snprintf(buf, sizeof (buf), "zen_udf.%u", i);
+ if (ddi_create_minor_node(dip, buf, S_IFCHR, i, DDI_PSEUDO,
+ 0) != DDI_SUCCESS) {
+ dev_err(dip, CE_WARN, "!failed to create minor %s",
+ buf);
+ goto err;
+ }
+ }
+
+ return (DDI_SUCCESS);
+
+err:
+ zen_udf_cleanup(zen_udf);
+ return (DDI_FAILURE);
+}
+
+static int
+zen_udf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
+{
+ zen_udf_t *zen_udf = &zen_udf_data;
+ minor_t m;
+
+ switch (cmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ m = getminor((dev_t)arg);
+ if (m >= zen_udf->zudf_ndfs) {
+ return (DDI_FAILURE);
+ }
+ *resultp = (void *)zen_udf->zudf_dip;
+ break;
+ case DDI_INFO_DEVT2INSTANCE:
+ m = getminor((dev_t)arg);
+ if (m >= zen_udf->zudf_ndfs) {
+ return (DDI_FAILURE);
+ }
+ *resultp = (void *)(uintptr_t)ddi_get_instance(
+ zen_udf->zudf_dip);
+ break;
+ default:
+ return (DDI_FAILURE);
+ }
+ return (DDI_SUCCESS);
+}
+
+static int
+zen_udf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ zen_udf_t *zen_udf = &zen_udf_data;
+
+ if (cmd == DDI_SUSPEND) {
+ return (DDI_SUCCESS);
+ } else if (cmd != DDI_DETACH) {
+ return (DDI_FAILURE);
+ }
+
+ if (zen_udf->zudf_dip != dip) {
+ dev_err(dip, CE_WARN, "!asked to detach zen_udf, but dip "
+ "doesn't match");
+ return (DDI_FAILURE);
+ }
+
+ zen_udf_cleanup(zen_udf);
+ return (DDI_SUCCESS);
+}
+
+static struct cb_ops zen_udf_cb_ops = {
+ .cb_open = zen_udf_open,
+ .cb_close = zen_udf_close,
+ .cb_strategy = nodev,
+ .cb_print = nodev,
+ .cb_dump = nodev,
+ .cb_read = nodev,
+ .cb_write = nodev,
+ .cb_ioctl = zen_udf_ioctl,
+ .cb_devmap = nodev,
+ .cb_mmap = nodev,
+ .cb_segmap = nodev,
+ .cb_chpoll = nochpoll,
+ .cb_prop_op = ddi_prop_op,
+ .cb_flag = D_MP,
+ .cb_rev = CB_REV,
+ .cb_aread = nodev,
+ .cb_awrite = nodev
+};
+
+static struct dev_ops zen_udf_dev_ops = {
+ .devo_rev = DEVO_REV,
+ .devo_refcnt = 0,
+ .devo_getinfo = zen_udf_getinfo,
+ .devo_identify = nulldev,
+ .devo_probe = nulldev,
+ .devo_attach = zen_udf_attach,
+ .devo_detach = zen_udf_detach,
+ .devo_reset = nodev,
+ .devo_quiesce = ddi_quiesce_not_needed,
+ .devo_cb_ops = &zen_udf_cb_ops
+};
+
+static struct modldrv zen_udf_modldrv = {
+ .drv_modops = &mod_driverops,
+ .drv_linkinfo = "AMD User DF Access",
+ .drv_dev_ops = &zen_udf_dev_ops
+};
+
+static struct modlinkage zen_udf_modlinkage = {
+ .ml_rev = MODREV_1,
+ .ml_linkage = { &zen_udf_modldrv, NULL }
+};
+
+int
+_init(void)
+{
+ return (mod_install(&zen_udf_modlinkage));
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&zen_udf_modlinkage, modinfop));
+}
+
+int
+_fini(void)
+{
+ return (mod_remove(&zen_udf_modlinkage));
+}
diff --git a/usr/src/uts/intel/io/amdzen/zen_udf.h b/usr/src/uts/intel/io/amdzen/zen_udf.h
new file mode 100644
index 0000000000..ef5a3184d5
--- /dev/null
+++ b/usr/src/uts/intel/io/amdzen/zen_udf.h
@@ -0,0 +1,44 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 Oxide Computer Company
+ */
+
+#ifndef _ZEN_UDF_H
+#define _ZEN_UDF_H
+
+/*
+ * Private ioctls for interfacing with the zen_udf driver.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZEN_UDF_IOCTL (('u' << 24) | ('d' << 16) | ('f' << 8))
+
+#define ZEN_UDF_READ32 (ZEN_UDF_IOCTL | 0x01)
+#define ZEN_UDF_READ64 (ZEN_UDF_IOCTL | 0x02)
+
+typedef struct zen_udf_io {
+ uint8_t zui_inst;
+ uint8_t zui_func;
+ uint16_t zui_reg;
+ uint32_t zui_pad;
+ uint64_t zui_data;
+} zen_udf_io_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZEN_UDF_H */
diff --git a/usr/src/uts/intel/zen_udf/Makefile b/usr/src/uts/intel/zen_udf/Makefile
new file mode 100644
index 0000000000..5b312d7013
--- /dev/null
+++ b/usr/src/uts/intel/zen_udf/Makefile
@@ -0,0 +1,41 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2020 Oxide Computer Company
+#
+
+UTSBASE = ../..
+
+MODULE = zen_udf
+OBJECTS = $(ZEN_UDF_OBJS:%=$(OBJS_DIR)/%)
+ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
+
+include $(UTSBASE)/intel/Makefile.intel
+
+ALL_TARGET = $(BINARY)
+INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
+CPPFLAGS += -I$(UTSBASE)/intel/io/amdzen
+LDFLAGS += -dy -Ndrv/amdzen
+
+.KEEP_STATE:
+
+def: $(DEF_DEPS)
+
+all: $(ALL_DEPS)
+
+clean: $(CLEAN_DEPS)
+
+clobber: $(CLOBBER_DEPS)
+
+install: $(INSTALL_DEPS)
+
+include $(UTSBASE)/intel/Makefile.targ