@@ -13,10 +13,18 @@
#include <libcflat.h>
#include <interrupt.h>
+#include <alloc.h>
+#include <bitops.h>
#include <ap.h>
#include <asm/time.h>
#include <asm/facility.h>
+static uint8_t num_ap;
+static uint8_t num_queue;
+static uint8_t *array_ap;
+static uint8_t *array_queue;
+static struct ap_config_info qci;
+
int ap_pqap_tapq(uint8_t ap, uint8_t qn, struct ap_queue_status *apqsw,
struct pqap_r2 *r2)
{
@@ -78,15 +86,90 @@ int ap_pqap_qci(struct ap_config_info *info)
return cc;
}
-bool ap_check(void)
+static int get_entry(uint8_t *ptr, int i, size_t len)
{
+ /* Skip over the last entry */
+ if (i)
+ i++;
+
+ for (; i < 8 * len; i++) {
+ /* Do we even need to check the byte? */
+ if (!ptr[i / 8]) {
+ i += 7;
+ continue;
+ }
+
+ /* Check the bit in big-endian order */
+ if (ptr[i / 8] & BIT(7 - (i % 8)))
+ return i;
+ }
+ return -1;
+}
+
+static void setup_info(void)
+{
+ int i, entry = 0;
+
+ ap_pqap_qci(&qci);
+
+ for (i = 0; i < AP_ARRAY_MAX_NUM; i++) {
+ entry = get_entry((uint8_t *)qci.apm, entry, sizeof(qci.apm));
+ if (entry == -1)
+ break;
+
+ if (!num_ap) {
+ /*
+ * We have at least one AP, time to
+ * allocate the queue arrays
+ */
+ array_ap = malloc(AP_ARRAY_MAX_NUM);
+ array_queue = malloc(AP_ARRAY_MAX_NUM);
+ }
+ array_ap[num_ap] = entry;
+ num_ap += 1;
+ }
+
+ /* Without an AP we don't even need to look at the queues */
+ if (!num_ap)
+ return;
+
+ entry = 0;
+ for (i = 0; i < AP_ARRAY_MAX_NUM; i++) {
+ entry = get_entry((uint8_t *)qci.aqm, entry, sizeof(qci.aqm));
+ if (entry == -1)
+ return;
+
+ array_queue[num_queue] = entry;
+ num_queue += 1;
+ }
+
+}
+
+int ap_setup(uint8_t **ap_array, uint8_t **qn_array, uint8_t *naps, uint8_t *nqns)
+{
+ assert(!num_ap);
+
/*
* Base AP support has no STFLE or SCLP feature bit but the
* PQAP QCI support is indicated via stfle bit 12. As this
* library relies on QCI we bail out if it's not available.
*/
if (!test_facility(12))
- return false;
+ return AP_SETUP_NOINSTR;
- return true;
+ /* Setup ap and queue arrays */
+ setup_info();
+
+ if (!num_ap)
+ return AP_SETUP_NOAPQN;
+
+ /* Only provide the data if the caller actually needs it. */
+ if (ap_array && qn_array && naps && nqns) {
+ *ap_array = array_ap;
+ *qn_array = array_queue;
+ *naps = num_ap;
+ *nqns = num_queue;
+ }
+
+ return AP_SETUP_READY;
}
@@ -81,7 +81,22 @@ struct pqap_r2 {
} __attribute__((packed)) __attribute__((aligned(8)));
_Static_assert(sizeof(struct pqap_r2) == sizeof(uint64_t), "pqap_r2 size");
-bool ap_check(void);
+/*
+ * Maximum number of APQNs that we keep track of.
+ *
+ * This value is already way larger than the number of APQNs a AP test
+ * is probably going to use.
+ */
+#define AP_ARRAY_MAX_NUM 16
+
+/* Return values of ap_setup() */
+enum {
+ AP_SETUP_NOINSTR, /* AP instructions not available */
+ AP_SETUP_NOAPQN, /* Instructions available but no APQNs */
+ AP_SETUP_READY /* Full setup complete, at least one APQN */
+};
+
+int ap_setup(uint8_t **ap_array, uint8_t **qn_array, uint8_t *naps, uint8_t *nqns);
int ap_pqap_tapq(uint8_t ap, uint8_t qn, struct ap_queue_status *apqsw,
struct pqap_r2 *r2);
int ap_pqap_qci(struct ap_config_info *info);
@@ -292,8 +292,10 @@ static void test_priv(void)
int main(void)
{
+ int setup_rc = ap_setup(NULL, NULL, NULL, NULL);
+
report_prefix_push("ap");
- if (!ap_check()) {
+ if (setup_rc == AP_SETUP_NOINSTR) {
report_skip("AP instructions not available");
goto done;
}
For the next tests we need a valid queue which means we need to grab the qci info and search the first set bit in the ap and aq masks. Let's move from the ap_check function to a proper setup function that also returns arrays for the aps and qns. Signed-off-by: Janosch Frank <frankja@linux.ibm.com> --- lib/s390x/ap.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++-- lib/s390x/ap.h | 17 +++++++++- s390x/ap.c | 4 ++- 3 files changed, 105 insertions(+), 5 deletions(-)