2024-02-01 09:49:01 +01:00
|
|
|
From 57d5e1c07b40e56f6209e7b806208818464f8e8d Mon Sep 17 00:00:00 2001
|
2024-01-04 17:53:48 +01:00
|
|
|
From: Nathan Lynch <nathanl@linux.ibm.com>
|
|
|
|
Date: Sat, 12 Aug 2023 13:27:39 -0500
|
|
|
|
Subject: [PATCH 5/6] librtas/vpd: prefer /dev/papr-vpd when available
|
|
|
|
|
2024-02-01 09:49:01 +01:00
|
|
|
Change rtas_get_vpd() to prefer the /dev/papr-vpd character device
|
|
|
|
expected in Linux v6.8.
|
2024-01-04 17:53:48 +01:00
|
|
|
|
|
|
|
On the first invocation of rtas_get_vpd(), probe for the new ABI and
|
|
|
|
initialize an internal function pointer according to the result. Use
|
|
|
|
pthread_once() to ensure that this probe step is performed atomically
|
|
|
|
and only once. It would not make sense to re-probe (and potentially
|
|
|
|
update the implementation) on every call, since the implementations
|
|
|
|
differ in the way state for the call sequence is maintained.
|
|
|
|
|
|
|
|
Assuming the new ABI is available: upon first call to rtas_get_vpd(),
|
|
|
|
open /dev/papr-vpd and obtain a file descriptor using the
|
|
|
|
PAPR_VPD_CREATE_HANDLE ioctl() command. This file descriptor is a
|
|
|
|
reference to the VPD returned from a complete ibm,get-vpd call
|
|
|
|
sequence. Subsequent calls sequentially read the VPD from the fd,
|
|
|
|
which is closed once EOF is reached.
|
|
|
|
|
|
|
|
To existing users of rtas_get_vpd(), the new implementation is
|
|
|
|
indistinguishable from the old one, with one exception:
|
|
|
|
|
|
|
|
* When using the rtas() syscall on current systems, RTAS advances the
|
|
|
|
sequence number by a fixed interval on each call in a sequence. This
|
|
|
|
is visible in the values returned in the 'seq_next' out parameter.
|
|
|
|
|
|
|
|
* When using /dev/papr-vpd, the value returned in 'seq_next' does not
|
|
|
|
change between calls; librtas treats it as a "handle" for a sequence
|
|
|
|
in progress.
|
|
|
|
|
|
|
|
In PAPR there is no meaning attached to the value returned in the
|
|
|
|
'seq_next' out parameter, and there is no requirement that it must
|
|
|
|
change or increment on each call. No user should be relying on the
|
|
|
|
behavior of this aspect of the interface to judge the status of a
|
|
|
|
sequence.
|
|
|
|
|
|
|
|
I have verified that an unmodified vpdupdate command from a distro
|
|
|
|
lsvpd package works correctly when linked to a librtas.so with this
|
|
|
|
change. This is the primary (and perhaps only) user of rtas_get_vpd().
|
|
|
|
|
|
|
|
For now, carry a copy of the kernel uapi header.
|
|
|
|
|
|
|
|
Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
|
2024-02-01 09:49:01 +01:00
|
|
|
Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com>
|
2024-01-04 17:53:48 +01:00
|
|
|
---
|
2024-02-01 09:49:01 +01:00
|
|
|
Makefile.am | 5 +-
|
2024-01-04 17:53:48 +01:00
|
|
|
librtas_src/papr-vpd.h | 22 ++++++
|
|
|
|
librtas_src/vpd.c | 155 ++++++++++++++++++++++++++++++++++++-----
|
2024-02-01 09:49:01 +01:00
|
|
|
3 files changed, 162 insertions(+), 20 deletions(-)
|
2024-01-04 17:53:48 +01:00
|
|
|
create mode 100644 librtas_src/papr-vpd.h
|
|
|
|
|
|
|
|
diff --git a/Makefile.am b/Makefile.am
|
2024-02-01 09:49:01 +01:00
|
|
|
index d0cabfb..89a6eaa 100644
|
2024-01-04 17:53:48 +01:00
|
|
|
--- a/Makefile.am
|
|
|
|
+++ b/Makefile.am
|
2024-02-01 09:49:01 +01:00
|
|
|
@@ -26,7 +26,7 @@ LIBRTAS_AGE = 0
|
|
|
|
LIBRTAS_LIBRARY_VERSION = $(LIBRTAS_CURRENT):$(LIBRTAS_REVISION):$(LIBRTAS_AGE)
|
|
|
|
|
|
|
|
lib_LTLIBRARIES += librtas.la
|
|
|
|
-librtas_la_LDFLAGS = -version-info $(LIBRTAS_LIBRARY_VERSION)
|
|
|
|
+librtas_la_LDFLAGS = -version-info $(LIBRTAS_LIBRARY_VERSION) -lpthread
|
|
|
|
librtas_la_SOURCES = \
|
|
|
|
librtas_src/vpd.c \
|
|
|
|
librtas_src/ofdt.c \
|
2024-01-04 17:53:48 +01:00
|
|
|
@@ -37,7 +37,8 @@ librtas_la_SOURCES = \
|
|
|
|
library_include_HEADERS += librtas_src/librtas.h
|
|
|
|
noinst_HEADERS += \
|
|
|
|
librtas_src/internal.h \
|
|
|
|
- librtas_src/papr-miscdev.h
|
|
|
|
+ librtas_src/papr-miscdev.h \
|
|
|
|
+ librtas_src/papr-vpd.h
|
|
|
|
|
|
|
|
# See "Updating library version information" in the libtool manual for
|
|
|
|
# how to maintain these values. They are *not* tied to the release
|
|
|
|
diff --git a/librtas_src/papr-vpd.h b/librtas_src/papr-vpd.h
|
|
|
|
new file mode 100644
|
|
|
|
index 0000000..b57cf30
|
|
|
|
--- /dev/null
|
|
|
|
+++ b/librtas_src/papr-vpd.h
|
|
|
|
@@ -0,0 +1,22 @@
|
|
|
|
+// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
|
|
|
|
+#ifndef _UAPI_PAPR_VPD_H_
|
|
|
|
+#define _UAPI_PAPR_VPD_H_
|
|
|
|
+
|
|
|
|
+#include <asm/ioctl.h>
|
|
|
|
+#include "papr-miscdev.h"
|
|
|
|
+
|
|
|
|
+struct papr_location_code {
|
|
|
|
+ /*
|
|
|
|
+ * PAPR+ 12.3.2.4 Converged Location Code Rules - Length
|
|
|
|
+ * Restrictions. 79 characters plus nul.
|
|
|
|
+ */
|
|
|
|
+ char str[80];
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * ioctl for /dev/papr-vpd. Returns a VPD handle fd corresponding to
|
|
|
|
+ * the location code.
|
|
|
|
+ */
|
|
|
|
+#define PAPR_VPD_IOC_CREATE_HANDLE _IOW(PAPR_MISCDEV_IOC_ID, 0, struct papr_location_code)
|
|
|
|
+
|
|
|
|
+#endif /* _UAPI_PAPR_VPD_H_ */
|
|
|
|
diff --git a/librtas_src/vpd.c b/librtas_src/vpd.c
|
|
|
|
index b2689fb..544560f 100644
|
|
|
|
--- a/librtas_src/vpd.c
|
|
|
|
+++ b/librtas_src/vpd.c
|
|
|
|
@@ -1,33 +1,33 @@
|
|
|
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
|
|
|
|
// Support for accessing IBM Power systems Vital Product Data (VPD)
|
|
|
|
-// via the rtas() syscall.
|
|
|
|
+// via /dev/papr-vpd or the legacy rtas() syscall.
|
|
|
|
|
|
|
|
-#include <endian.h>
|
|
|
|
+#include <errno.h>
|
|
|
|
+#include <fcntl.h>
|
|
|
|
+#include <inttypes.h>
|
|
|
|
+#include <limits.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/unistd.h>
|
|
|
|
-#include <stdint.h>
|
|
|
|
+#include <pthread.h>
|
|
|
|
+#include <search.h>
|
|
|
|
+#include <stdarg.h>
|
|
|
|
+#include <stdbool.h>
|
|
|
|
+#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
+#include <sys/ioctl.h>
|
|
|
|
+#include <sys/stat.h>
|
|
|
|
#include <sys/syscall.h>
|
|
|
|
+#include <unistd.h>
|
|
|
|
|
|
|
|
#include "internal.h"
|
|
|
|
#include "librtas.h"
|
|
|
|
+#include "papr-vpd.h"
|
|
|
|
|
|
|
|
-/**
|
|
|
|
- * rtas_get_vpd
|
|
|
|
- * @brief Interface to the ibm,get-vpd rtas call
|
|
|
|
- *
|
|
|
|
- * @param loc_code location code
|
|
|
|
- * @param workarea additional args to rtas call
|
|
|
|
- * @param size
|
|
|
|
- * @param sequence
|
|
|
|
- * @param seq_next
|
|
|
|
- * @param bytes_ret
|
|
|
|
- * @return 0 on success, !0 otherwise
|
|
|
|
- */
|
|
|
|
-int rtas_get_vpd(char *loc_code, char *workarea, size_t size,
|
|
|
|
- unsigned int sequence, unsigned int *seq_next,
|
|
|
|
- unsigned int *bytes_ret)
|
|
|
|
+static int
|
|
|
|
+get_vpd_syscall_fallback(const char *loc_code, char *workarea, size_t size,
|
|
|
|
+ unsigned int sequence, unsigned int *seq_next,
|
|
|
|
+ unsigned int *bytes_ret)
|
|
|
|
{
|
|
|
|
uint32_t kernbuf_pa;
|
|
|
|
uint32_t loc_pa = 0;
|
|
|
|
@@ -79,3 +79,122 @@ int rtas_get_vpd(char *loc_code, char *workarea, size_t size,
|
|
|
|
workarea, size, sequence, status, *seq_next, *bytes_ret);
|
|
|
|
return rc ? rc : status;
|
|
|
|
}
|
|
|
|
+
|
|
|
|
+static bool get_vpd_can_use_chardev(void)
|
|
|
|
+{
|
|
|
|
+ struct stat statbuf;
|
|
|
|
+
|
|
|
|
+ if (stat("/dev/papr-vpd", &statbuf))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (!S_ISCHR(statbuf.st_mode))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (close(open("/dev/papr-vpd", O_RDONLY)))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#define DEVPATH "/dev/papr-vpd"
|
|
|
|
+
|
|
|
|
+static int vpd_fd_new(const char *loc_code)
|
|
|
|
+{
|
|
|
|
+ const int devfd = open(DEVPATH, O_WRONLY);
|
|
|
|
+ struct papr_location_code lc = {};
|
|
|
|
+ int fd = -1;
|
|
|
|
+
|
|
|
|
+ if (devfd < 0)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ if (!loc_code)
|
|
|
|
+ loc_code = "";
|
|
|
|
+
|
|
|
|
+ if (sizeof(lc.str) < strlen(loc_code))
|
|
|
|
+ goto close_devfd;
|
|
|
|
+
|
|
|
|
+ strncpy(lc.str, loc_code, sizeof(lc.str));
|
|
|
|
+ fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);
|
|
|
|
+close_devfd:
|
|
|
|
+ close(devfd);
|
|
|
|
+ return fd;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+get_vpd_chardev(const char *loc_code, char *workarea, size_t size,
|
|
|
|
+ unsigned int sequence, unsigned int *seq_next,
|
|
|
|
+ unsigned int *bytes_ret)
|
|
|
|
+{
|
|
|
|
+ int fd = (sequence == 1) ? vpd_fd_new(loc_code) : (int)sequence;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Ensure we return a fd > 0 in seq_next.
|
|
|
|
+ */
|
|
|
|
+ if (fd == 1) {
|
|
|
|
+ int newfd = dup(fd);
|
|
|
|
+ close(fd);
|
|
|
|
+ fd = newfd;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (fd < 0)
|
|
|
|
+ return -3; /* Synthesize ibm,get-vpd "parameter error" */
|
|
|
|
+
|
|
|
|
+ int rtas_status = 0;
|
|
|
|
+ ssize_t res = read(fd, workarea, size);
|
|
|
|
+ if (res < 0) {
|
|
|
|
+ rtas_status = -1; /* Synthesize ibm,get-vpd "hardware error" */
|
|
|
|
+ close(fd);
|
|
|
|
+ } else if (res == 0 || res < (ssize_t)size) {
|
|
|
|
+ rtas_status = 0; /* Done with sequence, no more data */
|
|
|
|
+ close(fd);
|
|
|
|
+ if (seq_next)
|
|
|
|
+ *seq_next = 1;
|
|
|
|
+ if (bytes_ret)
|
|
|
|
+ *bytes_ret = res;
|
|
|
|
+ } else {
|
|
|
|
+ rtas_status = 1; /* More data available, call again */
|
|
|
|
+ if (seq_next)
|
|
|
|
+ *seq_next = fd;
|
|
|
|
+ if (bytes_ret)
|
|
|
|
+ *bytes_ret = res;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return rtas_status;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int (*get_vpd_fn)(const char *loc_code,
|
|
|
|
+ char *workarea,
|
|
|
|
+ size_t size,
|
|
|
|
+ unsigned int sequence,
|
|
|
|
+ unsigned int *seq_next,
|
|
|
|
+ unsigned int *bytes_ret);
|
|
|
|
+
|
|
|
|
+static void get_vpd_fn_setup(void)
|
|
|
|
+{
|
|
|
|
+ get_vpd_fn = get_vpd_can_use_chardev() ?
|
|
|
|
+ get_vpd_chardev : get_vpd_syscall_fallback;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * rtas_get_vpd
|
|
|
|
+ * @brief Interface to the ibm,get-vpd rtas call
|
|
|
|
+ *
|
|
|
|
+ * @param loc_code location code
|
|
|
|
+ * @param workarea additional args to rtas call
|
|
|
|
+ * @param size
|
|
|
|
+ * @param sequence
|
|
|
|
+ * @param seq_next
|
|
|
|
+ * @param bytes_ret
|
|
|
|
+ * @return 0 on success, !0 otherwise
|
|
|
|
+ */
|
|
|
|
+int rtas_get_vpd(char *loc_code, char *workarea, size_t size,
|
|
|
|
+ unsigned int sequence, unsigned int *seq_next,
|
|
|
|
+ unsigned int *bytes_ret)
|
|
|
|
+{
|
|
|
|
+ static pthread_once_t get_vpd_fn_once = PTHREAD_ONCE_INIT;
|
|
|
|
+
|
|
|
|
+ pthread_once(&get_vpd_fn_once, get_vpd_fn_setup);
|
|
|
|
+
|
|
|
|
+ return get_vpd_fn(loc_code, workarea, size, sequence,
|
|
|
|
+ seq_next, bytes_ret);
|
|
|
|
+}
|
|
|
|
--
|
2024-02-01 09:49:01 +01:00
|
|
|
2.43.0
|
2024-01-04 17:53:48 +01:00
|
|
|
|