Skip to content

Commit

Permalink
13986 usmn(7D) could support writing
Browse files Browse the repository at this point in the history
Reviewed by: Gergő Mihály Doma <domag02@gmail.com>
Reviewed by: C Fraire <cfraire@me.com>
Reviewed by: Andy Fiddaman <andy@omnios.org>
Approved by: Richard Lowe <richlowe@richlowe.net>
  • Loading branch information
rmustacc committed Aug 2, 2021
1 parent 8efb738 commit f198607
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 30 deletions.
67 changes: 48 additions & 19 deletions usr/src/cmd/amdzen/usmn.c
Expand Up @@ -10,7 +10,7 @@
*/

/*
* Copyright 2020 Oxide Computer Company
* Copyright 2021 Oxide Computer Company
*/

/*
Expand All @@ -28,28 +28,46 @@
#include <usmn.h>

static boolean_t
usmn_read(int fd, const char *addr)
usmn_parse_uint32(const char *str, uint32_t *valp)
{
unsigned long long l;
long long l;
char *eptr;
usmn_reg_t usr;

errno = 0;
l = strtoull(addr, &eptr, 16);
if (errno != 0 || *eptr != '\0' || l > UINT32_MAX) {
warnx("failed to parse %s: invalid string or address", addr);
l = strtoll(str, &eptr, 16);
if (errno != 0 || *eptr != '\0') {
warnx("failed to parse string '%s'", str);
return (B_FALSE);
}

usr.usr_addr = (uint32_t)l;
usr.usr_data = 0;
if (l < 0 || l > UINT32_MAX) {
warnx("value %s is outside the valid range [0, UINT32_MAX]",
str);
return (B_FALSE);
}

*valp = (uint32_t)l;
return (B_TRUE);
}

static boolean_t
usmn_op(boolean_t do_write, int fd, const char *addr, uint32_t value)
{
usmn_reg_t usr;

usr.usr_data = value;
if (!usmn_parse_uint32(addr, &usr.usr_addr)) {
return (B_FALSE);
}

if (ioctl(fd, USMN_READ, &usr) != 0) {
warn("failed to read SMN at 0x%x", usr.usr_addr);
if (ioctl(fd, do_write ? USMN_WRITE : USMN_READ, &usr) != 0) {
warn("SMN ioctl failed at 0x%x", usr.usr_addr);
return (B_FALSE);
}

(void) printf("0x%x: 0x%x\n", usr.usr_addr, usr.usr_data);
if (!do_write) {
(void) printf("0x%x: 0x%x\n", usr.usr_addr, usr.usr_data);
}
return (B_TRUE);
}

Expand All @@ -58,15 +76,23 @@ main(int argc, char *argv[])
{
int i, c, fd, ret;
const char *device = NULL;
boolean_t do_write = B_FALSE;
uint32_t wval = 0;

while ((c = getopt(argc, argv, "d:")) != -1) {
while ((c = getopt(argc, argv, "d:w:")) != -1) {
switch (c) {
case 'd':
device = optarg;
break;
case 'w':
do_write = B_TRUE;
if (!usmn_parse_uint32(optarg, &wval)) {
return (EXIT_FAILURE);
}
break;
default:
(void) fprintf(stderr, "Usage: usmn -d device addr "
"[addr]...\n"
(void) fprintf(stderr, "Usage: usmn -d device "
"[-w value] addr [addr]...\n"
"Note: All addresses are interpreted as hex\n");
return (2);
}
Expand All @@ -80,21 +106,24 @@ main(int argc, char *argv[])
argv += optind;

if (argc == 0) {
errx(EXIT_FAILURE, "missing registers to read");
errx(EXIT_FAILURE, "at least one register must be specified");
}

if (do_write && argc != 1) {
errx(EXIT_FAILURE, "can only write to a single register");
}

if ((fd = open(device, O_RDONLY)) < 0) {
if ((fd = open(device, do_write ? O_RDWR : O_RDONLY)) < 0) {
err(EXIT_FAILURE, "failed to open %s", device);
}

ret = EXIT_SUCCESS;
for (i = 0; i < argc; i++) {
if (!usmn_read(fd, argv[i])) {
if (!usmn_op(do_write, fd, argv[i], wval)) {
ret = EXIT_FAILURE;
}
}

(void) close(fd);

return (ret);
}
17 changes: 11 additions & 6 deletions usr/src/man/man7d/usmn.7d
Expand Up @@ -9,9 +9,9 @@
.\" http://www.illumos.org/license/CDDL.
.\"
.\"
.\" Copyright 2020 Oxide Computer Company
.\" Copyright 2021 Oxide Computer Company
.\"
.Dd September 1, 2020
.Dd July 30, 2021
.Dt USMN 7D
.Os
.Sh NAME
Expand All @@ -22,16 +22,21 @@
.Sh DESCRIPTION
The
.Nm
driver provides the ability to read data from the AMD system management
network
driver provides the ability to read and write data from the AMD System
Management Network
.Pq SMN
on AMD Family 17h
.Pq Zen, Zen+, and Zen 2
and AMD Family 19h
.Pq Zen 3
processors.
.Pp
This driver is intended strictly for facilitating platform development
and is not recommended for systems that aren't doing kernel development
on AMD Zen platforms.
and is not recommended for systems that aren't doing kernel and platform
development on AMD Zen platforms.
Arbitrary writes to the SMN can severely damage and destabilize the system.
If you do not need access to the SMN, then this driver should not be
present on the system.
.Sh SEE ALSO
.Xr amdzen 7D ,
.Xr zen_udf 7D
35 changes: 33 additions & 2 deletions usr/src/uts/intel/io/amdzen/amdzen.c
Expand Up @@ -11,7 +11,7 @@

/*
* Copyright 2019, Joyent, Inc.
* Copyright 2020 Oxide Computer Company
* Copyright 2021 Oxide Computer Company
*/

/*
Expand Down Expand Up @@ -213,7 +213,6 @@ amdzen_df_read64(amdzen_t *azn, amdzen_df_t *df, uint8_t inst, uint8_t func,
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)
{
Expand All @@ -222,6 +221,14 @@ amdzen_smn_read32(amdzen_t *azn, amdzen_df_t *df, uint32_t reg)
return (amdzen_stub_get32(df->adf_nb, AMDZEN_NB_SMN_DATA));
}

static void
amdzen_smn_write32(amdzen_t *azn, amdzen_df_t *df, uint32_t reg, uint32_t val)
{
VERIFY(MUTEX_HELD(&azn->azn_mutex));
amdzen_stub_put32(df->adf_nb, AMDZEN_NB_SMN_ADDR, reg);
amdzen_stub_put32(df->adf_nb, AMDZEN_NB_SMN_DATA, val);
}

static amdzen_df_t *
amdzen_df_find(amdzen_t *azn, uint_t dfno)
{
Expand Down Expand Up @@ -273,6 +280,30 @@ amdzen_c_smn_read32(uint_t dfno, uint32_t reg, uint32_t *valp)
return (0);
}

int
amdzen_c_smn_write32(uint_t dfno, uint32_t reg, uint32_t val)
{
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);
}

if ((df->adf_flags & AMDZEN_DF_F_FOUND_NB) == 0) {
mutex_exit(&azn->azn_mutex);
return (ENXIO);
}

amdzen_smn_write32(azn, df, reg, val);
mutex_exit(&azn->azn_mutex);
return (0);
}


uint_t
amdzen_c_df_count(void)
{
Expand Down
3 changes: 2 additions & 1 deletion usr/src/uts/intel/io/amdzen/amdzen_client.h
Expand Up @@ -10,7 +10,7 @@
*/

/*
* Copyright 2020 Oxide Computer Company
* Copyright 2021 Oxide Computer Company
*/

#ifndef _AMDZEN_CLIENT_H
Expand All @@ -27,6 +27,7 @@ extern "C" {
#endif

extern int amdzen_c_smn_read32(uint_t, uint32_t, uint32_t *);
extern int amdzen_c_smn_write32(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 *);
Expand Down
20 changes: 18 additions & 2 deletions usr/src/uts/intel/io/amdzen/usmn.c
Expand Up @@ -10,7 +10,7 @@
*/

/*
* Copyright 2020 Oxide Computer Company
* Copyright 2021 Oxide Computer Company
*/

/*
Expand Down Expand Up @@ -97,15 +97,31 @@ usmn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
if (cmd == USMN_READ) {
int ret;

if ((mode & FREAD) == 0) {
return (EINVAL);
}

ret = amdzen_c_smn_read32(dfno, usr.usr_addr, &usr.usr_data);
if (ret != 0) {
return (ret);
}
} else if (cmd == USMN_WRITE) {
int ret;

if ((mode & FWRITE) == 0) {
return (EINVAL);
}

ret = amdzen_c_smn_write32(dfno, usr.usr_addr, usr.usr_data);
if (ret != 0) {
return (ret);
}
} else {
return (ENOTSUP);
}

if (ddi_copyout(&usr, (void *)arg, sizeof (usr), mode & FKIOCTL) != 0) {
if (cmd == USMN_READ &&
ddi_copyout(&usr, (void *)arg, sizeof (usr), mode & FKIOCTL) != 0) {
return (EFAULT);
}

Expand Down

0 comments on commit f198607

Please sign in to comment.