Sync from SUSE:SLFO:Main librtas revision 219e53c2fa80d95f7f213c84093ff785

This commit is contained in:
2025-05-28 11:17:28 +02:00
parent d827dc7346
commit 3253ad585c
11 changed files with 19 additions and 1147 deletions

View File

@@ -1,80 +0,0 @@
From 569da8e5f0d5009694dc2def350cb9cd2c1d81a6 Mon Sep 17 00:00:00 2001
From: Nathan Lynch <nathanl@linux.ibm.com>
Date: Sat, 12 Aug 2023 12:41:36 -0500
Subject: [PATCH 1/6] librtas: expose low-level RTAS call APIs internally
Make these functions available outside of syscall_calls.c, marking
them hidden so that they aren't exposed in the library ABI.
The implementations of librtas APIs will move into separate C files as
they gain support for new interfaces offered by the kernel.
Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com>
---
librtas_src/internal.h | 5 +++++
librtas_src/syscall_calls.c | 11 ++++++-----
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/librtas_src/internal.h b/librtas_src/internal.h
index 3b6ba88..97411d3 100644
--- a/librtas_src/internal.h
+++ b/librtas_src/internal.h
@@ -52,6 +52,11 @@ int read_entire_file(int fd, char **buf, size_t *len);
int rtas_token(const char *call_name);
int sanity_check(void);
+#define CALL_AGAIN 1
+unsigned int handle_delay(int status, uint64_t * elapsed);
+int rtas_call_no_delay(const char *name, int ninputs, int nrets, ...);
+int rtas_call(const char *name, int ninputs, int nrets, ...);
+
#define BITS32_LO(_num) (uint32_t) (_num & 0xffffffffll)
#define BITS32_HI(_num) (uint32_t) (_num >> 32)
#define BITS64(_high, _low) (uint64_t) (((uint64_t) _high << 32) | _low)
diff --git a/librtas_src/syscall_calls.c b/librtas_src/syscall_calls.c
index 1e09217..eabc5ea 100644
--- a/librtas_src/syscall_calls.c
+++ b/librtas_src/syscall_calls.c
@@ -32,8 +32,6 @@
#include "internal.h"
#include "librtas.h"
-#define CALL_AGAIN 1
-
int dbg_lvl = 0;
static uint64_t rtas_timeout_ms;
@@ -65,7 +63,8 @@ int sanity_check(void)
* CALL_AGAIN if the status is delay related
* RTAS_TIMEOUT if the requested timeout has been exceeded
*/
-static unsigned int handle_delay(int status, uint64_t * elapsed)
+__attribute__((visibility("hidden")))
+unsigned int handle_delay(int status, uint64_t * elapsed)
{
int order = status - EXTENDED_DELAY_MIN;
unsigned long ms = 0;
@@ -213,7 +212,8 @@ static int _rtas_call(int delay_handling, int token, int ninputs,
return 0;
}
-static int rtas_call_no_delay(const char *name, int ninputs, int nrets, ...)
+__attribute__((visibility("hidden")))
+int rtas_call_no_delay(const char *name, int ninputs, int nrets, ...)
{
va_list ap;
int rc, token;
@@ -229,7 +229,8 @@ static int rtas_call_no_delay(const char *name, int ninputs, int nrets, ...)
return rc;
}
-static int rtas_call(const char *name, int ninputs, int nrets, ...)
+__attribute__((visibility("hidden")))
+int rtas_call(const char *name, int ninputs, int nrets, ...)
{
va_list ap;
int rc, token;
--
2.43.0

View File

@@ -1,198 +0,0 @@
From ee06898b1e7807a6e201b281ffc8ee3fa96136f4 Mon Sep 17 00:00:00 2001
From: Nathan Lynch <nathanl@linux.ibm.com>
Date: Sat, 12 Aug 2023 12:44:38 -0500
Subject: [PATCH 2/6] librtas: move VPD code into separate module
This code will gain the ability to retrieve VPD using a different
interface exposed by newer kernels. This will be a lot of additional
code, so move it out of syscall_calls.c.
Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com>
---
Makefile.am | 1 +
librtas_src/syscall_calls.c | 67 ------------------------------
librtas_src/vpd.c | 81 +++++++++++++++++++++++++++++++++++++
3 files changed, 82 insertions(+), 67 deletions(-)
create mode 100644 librtas_src/vpd.c
diff --git a/Makefile.am b/Makefile.am
index c4bf09d..37df243 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -28,6 +28,7 @@ LIBRTAS_LIBRARY_VERSION = $(LIBRTAS_CURRENT):$(LIBRTAS_REVISION):$(LIBRTAS_AGE)
lib_LTLIBRARIES += librtas.la
librtas_la_LDFLAGS = -version-info $(LIBRTAS_LIBRARY_VERSION)
librtas_la_SOURCES = \
+ librtas_src/vpd.c \
librtas_src/ofdt.c \
librtas_src/syscall_calls.c \
librtas_src/syscall_rmo.c
diff --git a/librtas_src/syscall_calls.c b/librtas_src/syscall_calls.c
index eabc5ea..05f3c7c 100644
--- a/librtas_src/syscall_calls.c
+++ b/librtas_src/syscall_calls.c
@@ -753,73 +753,6 @@ int rtas_get_time(uint32_t *year, uint32_t *month, uint32_t *day,
return rc ? rc : status;
}
-/**
- * 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)
-{
- uint32_t kernbuf_pa;
- uint32_t loc_pa = 0;
- uint32_t rmo_pa = 0;
- uint64_t elapsed = 0;
- void *kernbuf;
- void *rmobuf;
- void *locbuf;
- int rc, status;
-
- rc = sanity_check();
- if (rc)
- return rc;
-
- rc = rtas_get_rmo_buffer(size + WORK_AREA_SIZE, &rmobuf, &rmo_pa);
- if (rc)
- return rc;
-
- kernbuf = rmobuf + WORK_AREA_SIZE;
- kernbuf_pa = rmo_pa + WORK_AREA_SIZE;
- locbuf = rmobuf;
- loc_pa = rmo_pa;
-
- /* If user didn't set loc_code, copy a NULL string */
- strncpy(locbuf, loc_code ? loc_code : "", WORK_AREA_SIZE);
-
- *seq_next = htobe32(sequence);
- do {
- sequence = *seq_next;
- rc = rtas_call_no_delay("ibm,get-vpd", 4, 3, htobe32(loc_pa),
- htobe32(kernbuf_pa), htobe32(size),
- sequence, &status, seq_next,
- bytes_ret);
- if (rc < 0)
- break;
-
- rc = handle_delay(status, &elapsed);
- } while (rc == CALL_AGAIN);
-
- if (rc == 0)
- memcpy(workarea, kernbuf, size);
-
- (void) rtas_free_rmo_buffer(rmobuf, rmo_pa, size + WORK_AREA_SIZE);
-
- *seq_next = be32toh(*seq_next);
- *bytes_ret = be32toh(*bytes_ret);
-
- dbg("(%s, 0x%p, %zu, %u) = %d, %u, %u\n", loc_code ? loc_code : "NULL",
- workarea, size, sequence, status, *seq_next, *bytes_ret);
- return rc ? rc : status;
-}
-
/**
* rtas_lpar_perftools
* @brief Interface to the ibm,lpar-perftools rtas call
diff --git a/librtas_src/vpd.c b/librtas_src/vpd.c
new file mode 100644
index 0000000..b2689fb
--- /dev/null
+++ b/librtas_src/vpd.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+// Support for accessing IBM Power systems Vital Product Data (VPD)
+// via the rtas() syscall.
+
+#include <endian.h>
+#include <linux/types.h>
+#include <linux/unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+
+#include "internal.h"
+#include "librtas.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)
+{
+ uint32_t kernbuf_pa;
+ uint32_t loc_pa = 0;
+ uint32_t rmo_pa = 0;
+ uint64_t elapsed = 0;
+ void *kernbuf;
+ void *rmobuf;
+ void *locbuf;
+ int rc, status;
+
+ rc = sanity_check();
+ if (rc)
+ return rc;
+
+ rc = rtas_get_rmo_buffer(size + WORK_AREA_SIZE, &rmobuf, &rmo_pa);
+ if (rc)
+ return rc;
+
+ kernbuf = rmobuf + WORK_AREA_SIZE;
+ kernbuf_pa = rmo_pa + WORK_AREA_SIZE;
+ locbuf = rmobuf;
+ loc_pa = rmo_pa;
+
+ /* If user didn't set loc_code, copy a NULL string */
+ strncpy(locbuf, loc_code ? loc_code : "", WORK_AREA_SIZE);
+
+ *seq_next = htobe32(sequence);
+ do {
+ sequence = *seq_next;
+ rc = rtas_call_no_delay("ibm,get-vpd", 4, 3, htobe32(loc_pa),
+ htobe32(kernbuf_pa), htobe32(size),
+ sequence, &status, seq_next,
+ bytes_ret);
+ if (rc < 0)
+ break;
+
+ rc = handle_delay(status, &elapsed);
+ } while (rc == CALL_AGAIN);
+
+ if (rc == 0)
+ memcpy(workarea, kernbuf, size);
+
+ (void) rtas_free_rmo_buffer(rmobuf, rmo_pa, size + WORK_AREA_SIZE);
+
+ *seq_next = be32toh(*seq_next);
+ *bytes_ret = be32toh(*bytes_ret);
+
+ dbg("(%s, 0x%p, %zu, %u) = %d, %u, %u\n", loc_code ? loc_code : "NULL",
+ workarea, size, sequence, status, *seq_next, *bytes_ret);
+ return rc ? rc : status;
+}
--
2.43.0

View File

@@ -1,231 +0,0 @@
From c47176a5f1ce7bb16ba02b8c8520e02b285d7e9f Mon Sep 17 00:00:00 2001
From: Nathan Lynch <nathanl@linux.ibm.com>
Date: Mon, 25 Sep 2023 11:32:33 -0500
Subject: [PATCH 3/6] librtas: move system parameter code to separate module
This code will gain the ability to access system parameters using a
different interface exposed by newer kernels. This will involve adding
a nontrivial amount of code, so move it out of syscall_calls.c.
Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com>
---
Makefile.am | 3 +-
librtas_src/syscall_calls.c | 84 -----------------------------------
librtas_src/sysparm.c | 88 +++++++++++++++++++++++++++++++++++++
3 files changed, 90 insertions(+), 85 deletions(-)
create mode 100644 librtas_src/sysparm.c
diff --git a/Makefile.am b/Makefile.am
index 37df243..1385ac7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -31,7 +31,8 @@ librtas_la_SOURCES = \
librtas_src/vpd.c \
librtas_src/ofdt.c \
librtas_src/syscall_calls.c \
- librtas_src/syscall_rmo.c
+ librtas_src/syscall_rmo.c \
+ librtas_src/sysparm.c
library_include_HEADERS += librtas_src/librtas.h
noinst_HEADERS += librtas_src/internal.h
diff --git a/librtas_src/syscall_calls.c b/librtas_src/syscall_calls.c
index 05f3c7c..b28af2d 100644
--- a/librtas_src/syscall_calls.c
+++ b/librtas_src/syscall_calls.c
@@ -674,44 +674,6 @@ int rtas_get_sensor(int sensor, int index, int *state)
return rc ? rc : status;
}
-/**
- * rtas_get_sysparm
- * @brief Interface to the ibm,get-system-parameter rtas call
- *
- * On successful completion the data parameter will contain the system
- * parameter results
- *
- * @param parameter system parameter to retrieve
- * @param length data buffer length
- * @param data reference to buffer to return parameter in
- * @return 0 on success, !0 otherwise
- */
-int rtas_get_sysparm(unsigned int parameter, unsigned int length, char *data)
-{
- uint32_t kernbuf_pa;
- void *kernbuf;
- int rc, status;
-
- rc = sanity_check();
- if (rc)
- return rc;
-
- rc = rtas_get_rmo_buffer(length, &kernbuf, &kernbuf_pa);
- if (rc)
- return rc;
-
- rc = rtas_call("ibm,get-system-parameter", 3, 1, htobe32(parameter),
- htobe32(kernbuf_pa), htobe32(length), &status);
-
- if (rc == 0)
- memcpy(data, kernbuf, length);
-
- (void)rtas_free_rmo_buffer(kernbuf, kernbuf_pa, length);
-
- dbg("(%u, %u, %p) = %d\n", parameter, length, data, rc ? rc : status);
- return rc ? rc : status;
-}
-
/**
* rtas_get_time
* @brief Interface to get-time-of-day rtas call
@@ -1109,52 +1071,6 @@ int rtas_set_poweron_time(uint32_t year, uint32_t month, uint32_t day,
return rc ? rc : status;
}
-/**
- * rtas_set_sysparm
- * @brief Interface to the ibm,set-system-parameter rtas call
- *
- * @param parameter
- * @param data
- * @return 0 on success, !0 otherwise
- */
-int rtas_set_sysparm(unsigned int parameter, char *data)
-{
- uint32_t kernbuf_pa;
- void *kernbuf;
- int rc, status;
- uint16_t size;
-
- rc = sanity_check();
- if (rc)
- return rc;
- /*
- * We have to copy the contents of @data to a RMO buffer. The
- * caller has encoded the data length in the first two bytes
- * of @data in MSB order, and we can't assume any
- * alignment. So interpret @data as:
- *
- * struct {
- * unsigned char len_msb;
- * unsigned char len_lsb;
- * char [(len_msb << 8) + len_lsb];
- * }
- */
- size = 2 + (((unsigned char)data[0] << 8) | (unsigned char)data[1]);
- rc = rtas_get_rmo_buffer(size, &kernbuf, &kernbuf_pa);
- if (rc)
- return rc;
-
- memcpy(kernbuf, data, size);
-
- rc = rtas_call("ibm,set-system-parameter", 2, 1, htobe32(parameter),
- htobe32(kernbuf_pa), &status);
-
- (void)rtas_free_rmo_buffer(kernbuf, kernbuf_pa, size);
-
- dbg("(%u, %p) = %d\n", parameter, data, rc ? rc : status);
- return rc ? rc : status;
-}
-
/**
* rtas_set_time
* @brief Interface to the set-time-of-day rtas call
diff --git a/librtas_src/sysparm.c b/librtas_src/sysparm.c
new file mode 100644
index 0000000..40af55e
--- /dev/null
+++ b/librtas_src/sysparm.c
@@ -0,0 +1,88 @@
+#include <stdint.h>
+#include <string.h>
+#include "internal.h"
+#include "librtas.h"
+
+/**
+ * rtas_get_sysparm
+ * @brief Interface to the ibm,get-system-parameter rtas call
+ *
+ * On successful completion the data parameter will contain the system
+ * parameter results
+ *
+ * @param parameter system parameter to retrieve
+ * @param length data buffer length
+ * @param data reference to buffer to return parameter in
+ * @return 0 on success, !0 otherwise
+ */
+int rtas_get_sysparm(unsigned int parameter, unsigned int length, char *data)
+{
+ uint32_t kernbuf_pa;
+ void *kernbuf;
+ int rc, status;
+
+ rc = sanity_check();
+ if (rc)
+ return rc;
+
+ rc = rtas_get_rmo_buffer(length, &kernbuf, &kernbuf_pa);
+ if (rc)
+ return rc;
+
+ rc = rtas_call("ibm,get-system-parameter", 3, 1, htobe32(parameter),
+ htobe32(kernbuf_pa), htobe32(length), &status);
+
+ if (rc == 0)
+ memcpy(data, kernbuf, length);
+
+ (void)rtas_free_rmo_buffer(kernbuf, kernbuf_pa, length);
+
+ dbg("(%u, %u, %p) = %d\n", parameter, length, data, rc ? rc : status);
+ return rc ? rc : status;
+}
+
+/**
+ * rtas_set_sysparm
+ * @brief Interface to the ibm,set-system-parameter rtas call
+ *
+ * @param parameter
+ * @param data
+ * @return 0 on success, !0 otherwise
+ */
+int rtas_set_sysparm(unsigned int parameter, char *data)
+{
+ uint32_t kernbuf_pa;
+ void *kernbuf;
+ int rc, status;
+ uint16_t size;
+
+ rc = sanity_check();
+ if (rc)
+ return rc;
+ /*
+ * We have to copy the contents of @data to a RMO buffer. The
+ * caller has encoded the data length in the first two bytes
+ * of @data in MSB order, and we can't assume any
+ * alignment. So interpret @data as:
+ *
+ * struct {
+ * unsigned char len_msb;
+ * unsigned char len_lsb;
+ * char [(len_msb << 8) + len_lsb];
+ * }
+ */
+ size = 2 + (((unsigned char)data[0] << 8) | (unsigned char)data[1]);
+ rc = rtas_get_rmo_buffer(size, &kernbuf, &kernbuf_pa);
+ if (rc)
+ return rc;
+
+ memcpy(kernbuf, data, size);
+
+ rc = rtas_call("ibm,set-system-parameter", 2, 1, htobe32(parameter),
+ htobe32(kernbuf_pa), &status);
+
+ (void)rtas_free_rmo_buffer(kernbuf, kernbuf_pa, size);
+
+ dbg("(%u, %p) = %d\n", parameter, data, rc ? rc : status);
+ return rc ? rc : status;
+}
--
2.43.0

View File

@@ -1,49 +0,0 @@
From c914a1a701391c565203b10603ad0fbc52438bf7 Mon Sep 17 00:00:00 2001
From: Nathan Lynch <nathanl@linux.ibm.com>
Date: Mon, 25 Sep 2023 11:41:22 -0500
Subject: [PATCH 4/6] librtas: vendor papr-miscdev.h
This is a common header used by other kernel uapi headers that we will
copy into the source tree.
Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com>
---
Makefile.am | 4 +++-
librtas_src/papr-miscdev.h | 9 +++++++++
2 files changed, 12 insertions(+), 1 deletion(-)
create mode 100644 librtas_src/papr-miscdev.h
diff --git a/Makefile.am b/Makefile.am
index 1385ac7..d0cabfb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,7 +35,9 @@ librtas_la_SOURCES = \
librtas_src/sysparm.c
library_include_HEADERS += librtas_src/librtas.h
-noinst_HEADERS += librtas_src/internal.h
+noinst_HEADERS += \
+ librtas_src/internal.h \
+ librtas_src/papr-miscdev.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-miscdev.h b/librtas_src/papr-miscdev.h
new file mode 100644
index 0000000..c0b1072
--- /dev/null
+++ b/librtas_src/papr-miscdev.h
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#ifndef _UAPI_PAPR_MISCDEV_H_
+#define _UAPI_PAPR_MISCDEV_H_
+
+enum {
+ PAPR_MISCDEV_IOC_ID = 0xb2,
+};
+
+#endif /* _UAPI_PAPR_MISCDEV_H_ */
--
2.43.0

View File

@@ -1,287 +0,0 @@
From 57d5e1c07b40e56f6209e7b806208818464f8e8d Mon Sep 17 00:00:00 2001
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
Change rtas_get_vpd() to prefer the /dev/papr-vpd character device
expected in Linux v6.8.
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>
Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com>
---
Makefile.am | 5 +-
librtas_src/papr-vpd.h | 22 ++++++
librtas_src/vpd.c | 155 ++++++++++++++++++++++++++++++++++++-----
3 files changed, 162 insertions(+), 20 deletions(-)
create mode 100644 librtas_src/papr-vpd.h
diff --git a/Makefile.am b/Makefile.am
index d0cabfb..89a6eaa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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 \
@@ -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);
+}
--
2.43.0

View File

@@ -1,285 +0,0 @@
From d8d4ee6f5052704ac82bb8aa8d8fe8816dac41cd Mon Sep 17 00:00:00 2001
From: Nathan Lynch <nathanl@linux.ibm.com>
Date: Mon, 25 Sep 2023 11:42:26 -0500
Subject: [PATCH 6/6] librtas/sysparm: prefer /dev/papr-sysparm when available
Change rtas_get_sysparm() and rtas_set_sysparm() to prefer the
/dev/papr-sysparm character device expected in Linux v6.8.
On the first invocation of either function, probe for the new ABI and
initialize internal function pointers according to the result. Use
pthread_once() to ensure that this initialization step is performed
atomically and only once.
When /dev/papr-sysparm is available, use its PAPR_SYSPARM_IOC_GET and
PAPR_SYSPARM_IOC_SET ioctl commands to retrieve and update system
parameters. Most of the complexity of calling RTAS is handled
internally to the kernel and the ioctl follows Linux conventions,
returning 0 on success or -1 w/errno on failure. On failure,
back-convert the errno to an RTAS status value that callers will
recognize.
For now, carry a copy of the kernel uapi header.
Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com>
---
Makefile.am | 1 +
librtas_src/papr-sysparm.h | 58 +++++++++++++++
librtas_src/sysparm.c | 144 ++++++++++++++++++++++++++++++++++++-
3 files changed, 201 insertions(+), 2 deletions(-)
create mode 100644 librtas_src/papr-sysparm.h
diff --git a/Makefile.am b/Makefile.am
index 89a6eaa..67257e3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,6 +38,7 @@ library_include_HEADERS += librtas_src/librtas.h
noinst_HEADERS += \
librtas_src/internal.h \
librtas_src/papr-miscdev.h \
+ librtas_src/papr-sysparm.h \
librtas_src/papr-vpd.h
# See "Updating library version information" in the libtool manual for
diff --git a/librtas_src/papr-sysparm.h b/librtas_src/papr-sysparm.h
new file mode 100644
index 0000000..e0c0ebb
--- /dev/null
+++ b/librtas_src/papr-sysparm.h
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#ifndef _UAPI_PAPR_SYSPARM_H_
+#define _UAPI_PAPR_SYSPARM_H_
+
+#include <linux/types.h>
+#include <asm/ioctl.h>
+#include "papr-miscdev.h"
+
+enum {
+ PAPR_SYSPARM_MAX_INPUT = 1024,
+ PAPR_SYSPARM_MAX_OUTPUT = 4000,
+};
+
+struct papr_sysparm_io_block {
+ __u32 parameter;
+ __u16 length;
+ char data[PAPR_SYSPARM_MAX_OUTPUT];
+};
+
+/**
+ * PAPR_SYSPARM_IOC_GET - Retrieve the value of a PAPR system parameter.
+ *
+ * Uses _IOWR because of one corner case: Retrieving the value of the
+ * "OS Service Entitlement Status" parameter (60) requires the caller
+ * to supply input data (a date string) in the buffer passed to
+ * firmware. So the @length and @data of the incoming
+ * papr_sysparm_io_block are always used to initialize the work area
+ * supplied to ibm,get-system-parameter. No other parameters are known
+ * to parameterize the result this way, and callers are encouraged
+ * (but not required) to zero-initialize @length and @data in the
+ * common case.
+ *
+ * On error the contents of the ioblock are indeterminate.
+ *
+ * Return:
+ * 0: Success; @length is the length of valid data in @data, not to exceed @PAPR_SYSPARM_MAX_OUTPUT.
+ * -EIO: Platform error. (-1)
+ * -EINVAL: Incorrect data length or format. (-9999)
+ * -EPERM: The calling partition is not allowed to access this parameter. (-9002)
+ * -EOPNOTSUPP: Parameter not supported on this platform (-3)
+ */
+#define PAPR_SYSPARM_IOC_GET _IOWR(PAPR_MISCDEV_IOC_ID, 1, struct papr_sysparm_io_block)
+
+/**
+ * PAPR_SYSPARM_IOC_SET - Update the value of a PAPR system parameter.
+ *
+ * The contents of the ioblock are unchanged regardless of success.
+ *
+ * Return:
+ * 0: Success; the parameter has been updated.
+ * -EIO: Platform error. (-1)
+ * -EINVAL: Incorrect data length or format. (-9999)
+ * -EPERM: The calling partition is not allowed to access this parameter. (-9002)
+ * -EOPNOTSUPP: Parameter not supported on this platform (-3)
+ */
+#define PAPR_SYSPARM_IOC_SET _IOW(PAPR_MISCDEV_IOC_ID, 2, struct papr_sysparm_io_block)
+
+#endif /* _UAPI_PAPR_SYSPARM_H_ */
diff --git a/librtas_src/sysparm.c b/librtas_src/sysparm.c
index 40af55e..b4d2054 100644
--- a/librtas_src/sysparm.c
+++ b/librtas_src/sysparm.c
@@ -1,7 +1,16 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
#include <stdint.h>
#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
#include "internal.h"
#include "librtas.h"
+#include "papr-sysparm.h"
+
+static const char sysparm_devpath[] = "/dev/papr-sysparm";
/**
* rtas_get_sysparm
@@ -15,7 +24,8 @@
* @param data reference to buffer to return parameter in
* @return 0 on success, !0 otherwise
*/
-int rtas_get_sysparm(unsigned int parameter, unsigned int length, char *data)
+static int
+get_sysparm_syscall_fallback(unsigned int parameter, unsigned int length, char *data)
{
uint32_t kernbuf_pa;
void *kernbuf;
@@ -49,7 +59,8 @@ int rtas_get_sysparm(unsigned int parameter, unsigned int length, char *data)
* @param data
* @return 0 on success, !0 otherwise
*/
-int rtas_set_sysparm(unsigned int parameter, char *data)
+static int
+set_sysparm_syscall_fallback(unsigned int parameter, char *data)
{
uint32_t kernbuf_pa;
void *kernbuf;
@@ -86,3 +97,132 @@ int rtas_set_sysparm(unsigned int parameter, char *data)
dbg("(%u, %p) = %d\n", parameter, data, rc ? rc : status);
return rc ? rc : status;
}
+
+static bool sysparm_can_use_chardev(void)
+{
+ struct stat statbuf;
+
+ if (stat(sysparm_devpath, &statbuf))
+ return false;
+
+ if (!S_ISCHR(statbuf.st_mode))
+ return false;
+
+ if (close(open(sysparm_devpath, O_RDONLY)))
+ return false;
+
+ return true;
+}
+
+/*
+ * Only to be used when converting an actual error from a syscall.
+ */
+static int chardev_backconvert_errno(int saved_errno)
+{
+ const struct {
+ int linux_errno;
+ int rtas_status;
+ } map[] = {
+#define errno_to_status(e, s) { .linux_errno = (e), .rtas_status = (s), }
+ errno_to_status(EINVAL, -9999),
+ errno_to_status(EPERM, -9002),
+ errno_to_status(EOPNOTSUPP, -3),
+ errno_to_status(EIO, -1),
+ errno_to_status(EFAULT, -1),
+#undef errno_to_status
+ };
+
+ for (size_t i = 0; i < sizeof(map) / sizeof(map[0]); ++i)
+ if (map[i].linux_errno == saved_errno)
+ return map[i].rtas_status;
+ return -1;
+}
+
+static int get_sysparm_chardev(unsigned int parameter, unsigned int length, char *data)
+{
+ const int fd = open(sysparm_devpath, O_RDWR);
+ struct papr_sysparm_io_block buf = {
+ .parameter = parameter,
+ };
+
+ if (fd < 0) {
+ /*
+ * Really shouldn't get here without misconfiguration,
+ * e.g. removal of /dev/papr-sysparm. Synthesize a
+ * hardware/platform error.
+ */
+ return -1;
+ }
+
+ /*
+ * It might make sense to have special handling for parameter
+ * 60 (OS Service Entitlement Status), which takes input data,
+ * but librtas has never handled that one correctly. So ignore
+ * it for now and don't copy incoming data into the block we
+ * pass to PAPR_SYSPARM_IOC_GET.
+ */
+
+ const int res = ioctl(fd, PAPR_SYSPARM_IOC_GET, &buf);
+ const int saved_errno = errno;
+ (void)close(fd);
+
+ if (res != 0)
+ return chardev_backconvert_errno(saved_errno);
+
+ const uint16_t result_size_msb = htobe16(buf.length);
+ memcpy(data, &result_size_msb, sizeof(result_size_msb));
+ length -= sizeof(result_size_msb);
+ data += sizeof(result_size_msb);
+
+ /*
+ * Copy no more than min(@length, sizeof(buf.data)).
+ */
+ const size_t copy_size = sizeof(buf.data) < length ?
+ sizeof(buf.data) : length;
+ memcpy(data, buf.data, copy_size);
+ return 0;
+}
+
+static int set_sysparm_chardev(unsigned int parameter, char *data)
+{
+ const int fd = open(sysparm_devpath, O_RDWR);
+ struct papr_sysparm_io_block buf = {
+ .parameter = parameter,
+ .length = (((unsigned char)data[0] << 8) | (unsigned char)data[1]),
+ };
+
+ memcpy(buf.data, data + 2, buf.length);
+
+ const int res = ioctl(fd, PAPR_SYSPARM_IOC_SET, &buf);
+ const int saved_errno = errno;
+ (void)close(fd);
+
+ return res == 0 ? 0 : chardev_backconvert_errno(saved_errno);
+}
+
+static int (*get_sysparm_fn)(unsigned int parameter, unsigned int length, char *data);
+static int (*set_sysparm_fn)(unsigned int parameter, char *data);
+
+static void sysparm_fn_setup(void)
+{
+ const bool use_chardev = sysparm_can_use_chardev();
+
+ get_sysparm_fn = use_chardev ?
+ get_sysparm_chardev : get_sysparm_syscall_fallback;
+ set_sysparm_fn = use_chardev ?
+ set_sysparm_chardev : set_sysparm_syscall_fallback;
+}
+
+static pthread_once_t sysparm_fn_setup_once = PTHREAD_ONCE_INIT;
+
+int rtas_get_sysparm(unsigned int parameter, unsigned int length, char *data)
+{
+ pthread_once(&sysparm_fn_setup_once, sysparm_fn_setup);
+ return get_sysparm_fn(parameter, length, data);
+}
+
+int rtas_set_sysparm(unsigned int parameter, char *data)
+{
+ pthread_once(&sysparm_fn_setup_once, sysparm_fn_setup);
+ return set_sysparm_fn(parameter, data);
+}
--
2.43.0

BIN
librtas-2.0.5.tar.gz (Stored with Git LFS)

Binary file not shown.

BIN
librtas-2.0.6.tar.gz (Stored with Git LFS) Normal file

Binary file not shown.

View File

@@ -17,7 +17,7 @@
Name: librtas-doc
Version: 2.0.5
Version: 2.0.6
Release: 0
Summary: Documents for librtas
License: LGPL-2.1-or-later
@@ -27,12 +27,6 @@ Source0: https://github.com/ibm-power-utilities/librtas/archive/v%{versio
Source2: activate-firmware-regress
Source3: vpdupdate-regress
Patch0: librtas.fix_doc_path.patch
Patch1: 0001-librtas-expose-low-level-RTAS-call-APIs-internally.patch
Patch2: 0002-librtas-move-VPD-code-into-separate-module.patch
Patch3: 0003-librtas-move-system-parameter-code-to-separate-modul.patch
Patch4: 0004-librtas-vendor-papr-miscdev.h.patch
Patch5: 0005-librtas-vpd-prefer-dev-papr-vpd-when-available.patch
Patch6: 0006-librtas-sysparm-prefer-dev-papr-sysparm-when-availab.patch
Patch7: 0001-librtas-Move-platform-dump-rtas-call-code-to-separat.patch
Patch8: 0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch
Patch9: 0003-librtas-move-get-set-indices-RTAS-calls-code-to-sepa.patch

View File

@@ -1,3 +1,17 @@
-------------------------------------------------------------------
Wed May 7 11:53:55 UTC 2025 - Michal Suchanek <msuchanek@suse.de>
- Update to version 2.0.6
* Optimize delay handling
* Add support for new rtas kernel interface for VPD and sysparm
- Drop upstreamed patches
* 0001-librtas-expose-low-level-RTAS-call-APIs-internally.patch
* 0002-librtas-move-VPD-code-into-separate-module.patch
* 0003-librtas-move-system-parameter-code-to-separate-modul.patch
* 0004-librtas-vendor-papr-miscdev.h.patch
* 0005-librtas-vpd-prefer-dev-papr-vpd-when-available.patch
* 0006-librtas-sysparm-prefer-dev-papr-sysparm-when-availab.patch
-------------------------------------------------------------------
Thu Mar 20 14:41:36 UTC 2025 - Michal Suchanek <msuchanek@suse.de>

View File

@@ -18,7 +18,7 @@
%define sover 2
Name: librtas
Version: 2.0.5
Version: 2.0.6
Release: 0
Summary: Libraries to provide access to RTAS calls and RTAS events
License: LGPL-2.1-or-later
@@ -29,12 +29,6 @@ Source1: baselibs.conf
Source2: activate-firmware-regress
Source3: vpdupdate-regress
Patch0: librtas.fix_doc_path.patch
Patch1: 0001-librtas-expose-low-level-RTAS-call-APIs-internally.patch
Patch2: 0002-librtas-move-VPD-code-into-separate-module.patch
Patch3: 0003-librtas-move-system-parameter-code-to-separate-modul.patch
Patch4: 0004-librtas-vendor-papr-miscdev.h.patch
Patch5: 0005-librtas-vpd-prefer-dev-papr-vpd-when-available.patch
Patch6: 0006-librtas-sysparm-prefer-dev-papr-sysparm-when-availab.patch
Patch7: 0001-librtas-Move-platform-dump-rtas-call-code-to-separat.patch
Patch8: 0002-librtas-platform-dump-prefer-dev-papr-platform-dump-.patch
Patch9: 0003-librtas-move-get-set-indices-RTAS-calls-code-to-sepa.patch